PageRenderTime 56ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/libssh-0.5.2/src/poll.c

#
C | 638 lines | 354 code | 89 blank | 195 comment | 99 complexity | 7a5b101b0cb1eddebee6b9a67891671a MD5 | raw file
Possible License(s): LGPL-2.1
  1. /*
  2. * poll.c - poll wrapper
  3. *
  4. * This file is part of the SSH Library
  5. *
  6. * Copyright (c) 2009-2010 by Andreas Schneider <mail@cynapses.org>
  7. * Copyright (c) 2003-2009 by Aris Adamantiadis
  8. * Copyright (c) 2009 Aleksandar Kanchev
  9. *
  10. * The SSH Library is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU Lesser General Public License as published by
  12. * the Free Software Foundation; either version 2.1 of the License, or (at your
  13. * option) any later version.
  14. *
  15. * The SSH Library is distributed in the hope that it will be useful, but
  16. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  17. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  18. * License for more details.
  19. *
  20. * You should have received a copy of the GNU Lesser General Public License
  21. * along with the SSH Library; see the file COPYING. If not, write to
  22. * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
  23. * MA 02111-1307, USA.
  24. *
  25. * vim: ts=2 sw=2 et cindent
  26. */
  27. #include "config.h"
  28. #include <errno.h>
  29. #include "libssh/priv.h"
  30. #include "libssh/libssh.h"
  31. #include "libssh/poll.h"
  32. #include "libssh/socket.h"
  33. #include "libssh/session.h"
  34. #ifndef SSH_POLL_CTX_CHUNK
  35. #define SSH_POLL_CTX_CHUNK 5
  36. #endif
  37. /**
  38. * @defgroup libssh_poll The SSH poll functions.
  39. * @ingroup libssh
  40. *
  41. * Add a generic way to handle sockets asynchronously.
  42. *
  43. * It's based on poll objects, each of which store a socket, its events and a
  44. * callback, which gets called whenever an event is set. The poll objects are
  45. * attached to a poll context, which should be allocated on per thread basis.
  46. *
  47. * Polling the poll context will poll all the attached poll objects and call
  48. * their callbacks (handlers) if any of the socket events are set. This should
  49. * be done within the main loop of an application.
  50. *
  51. * @{
  52. */
  53. struct ssh_poll_handle_struct {
  54. ssh_poll_ctx ctx;
  55. union {
  56. socket_t fd;
  57. size_t idx;
  58. } x;
  59. short events;
  60. ssh_poll_callback cb;
  61. void *cb_data;
  62. };
  63. struct ssh_poll_ctx_struct {
  64. ssh_poll_handle *pollptrs;
  65. ssh_pollfd_t *pollfds;
  66. size_t polls_allocated;
  67. size_t polls_used;
  68. size_t chunk_size;
  69. };
  70. #ifdef HAVE_POLL
  71. #include <poll.h>
  72. void ssh_poll_init(void) {
  73. return;
  74. }
  75. void ssh_poll_cleanup(void) {
  76. return;
  77. }
  78. int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
  79. return poll((struct pollfd *) fds, nfds, timeout);
  80. }
  81. #else /* HAVE_POLL */
  82. typedef int (*poll_fn)(ssh_pollfd_t *, nfds_t, int);
  83. static poll_fn ssh_poll_emu;
  84. #include <sys/types.h>
  85. #ifdef _WIN32
  86. #ifndef STRICT
  87. #define STRICT
  88. #endif /* STRICT */
  89. #include <time.h>
  90. #include <windows.h>
  91. #include <winsock2.h>
  92. #else /* _WIN32 */
  93. #include <sys/select.h>
  94. #include <sys/socket.h>
  95. #include <unistd.h>
  96. #include <sys/time.h>
  97. #endif /* _WIN32 */
  98. /*
  99. * This is a poll(2)-emulation using select for systems not providing a native
  100. * poll implementation.
  101. *
  102. * Keep in mind that select is terribly inefficient. The interface is simply not
  103. * meant to be used with maximum descriptor value greater, say, 32 or so. With
  104. * a value as high as 1024 on Linux you'll pay dearly in every single call.
  105. * poll() will be orders of magnitude faster.
  106. */
  107. static int bsd_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
  108. fd_set readfds, writefds, exceptfds;
  109. struct timeval tv, *ptv;
  110. socket_t max_fd;
  111. int rc;
  112. nfds_t i;
  113. if (fds == NULL) {
  114. errno = EFAULT;
  115. return -1;
  116. }
  117. FD_ZERO (&readfds);
  118. FD_ZERO (&writefds);
  119. FD_ZERO (&exceptfds);
  120. /* compute fd_sets and find largest descriptor */
  121. for (rc = -1, max_fd = 0, i = 0; i < nfds; i++) {
  122. if (fds[i].fd == SSH_INVALID_SOCKET) {
  123. continue;
  124. }
  125. #ifndef _WIN32
  126. if (fds[i].fd >= FD_SETSIZE) {
  127. rc = -1;
  128. break;
  129. }
  130. #endif
  131. if (fds[i].events & (POLLIN | POLLRDNORM)) {
  132. FD_SET (fds[i].fd, &readfds);
  133. }
  134. if (fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND)) {
  135. FD_SET (fds[i].fd, &writefds);
  136. }
  137. if (fds[i].events & (POLLPRI | POLLRDBAND)) {
  138. FD_SET (fds[i].fd, &exceptfds);
  139. }
  140. if (fds[i].fd > max_fd &&
  141. (fds[i].events & (POLLIN | POLLOUT | POLLPRI |
  142. POLLRDNORM | POLLRDBAND |
  143. POLLWRNORM | POLLWRBAND))) {
  144. max_fd = fds[i].fd;
  145. rc = 0;
  146. }
  147. }
  148. if (max_fd == SSH_INVALID_SOCKET || rc == -1) {
  149. errno = EINVAL;
  150. return -1;
  151. }
  152. if (timeout < 0) {
  153. ptv = NULL;
  154. } else {
  155. ptv = &tv;
  156. if (timeout == 0) {
  157. tv.tv_sec = 0;
  158. tv.tv_usec = 0;
  159. } else {
  160. tv.tv_sec = timeout / 1000;
  161. tv.tv_usec = (timeout % 1000) * 1000;
  162. }
  163. }
  164. rc = select (max_fd + 1, &readfds, &writefds, &exceptfds, ptv);
  165. if (rc < 0) {
  166. return -1;
  167. }
  168. for (rc = 0, i = 0; i < nfds; i++)
  169. if (fds[i].fd >= 0) {
  170. fds[i].revents = 0;
  171. if (FD_ISSET(fds[i].fd, &readfds)) {
  172. int save_errno = errno;
  173. char data[64] = {0};
  174. int ret;
  175. /* support for POLLHUP */
  176. ret = recv(fds[i].fd, data, 64, MSG_PEEK);
  177. #ifdef _WIN32
  178. if ((ret == -1) &&
  179. (errno == WSAESHUTDOWN || errno == WSAECONNRESET ||
  180. errno == WSAECONNABORTED || errno == WSAENETRESET)) {
  181. #else
  182. if ((ret == -1) &&
  183. (errno == ESHUTDOWN || errno == ECONNRESET ||
  184. errno == ECONNABORTED || errno == ENETRESET)) {
  185. #endif
  186. fds[i].revents |= POLLHUP;
  187. } else {
  188. fds[i].revents |= fds[i].events & (POLLIN | POLLRDNORM);
  189. }
  190. errno = save_errno;
  191. }
  192. if (FD_ISSET(fds[i].fd, &writefds)) {
  193. fds[i].revents |= fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND);
  194. }
  195. if (FD_ISSET(fds[i].fd, &exceptfds)) {
  196. fds[i].revents |= fds[i].events & (POLLPRI | POLLRDBAND);
  197. }
  198. if (fds[i].revents & ~POLLHUP) {
  199. rc++;
  200. }
  201. } else {
  202. fds[i].revents = POLLNVAL;
  203. }
  204. return rc;
  205. }
  206. void ssh_poll_init(void) {
  207. ssh_poll_emu = bsd_poll;
  208. }
  209. void ssh_poll_cleanup(void) {
  210. ssh_poll_emu = bsd_poll;
  211. }
  212. int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
  213. return (ssh_poll_emu)(fds, nfds, timeout);
  214. }
  215. #endif /* HAVE_POLL */
  216. /**
  217. * @brief Allocate a new poll object, which could be used within a poll context.
  218. *
  219. * @param fd Socket that will be polled.
  220. * @param events Poll events that will be monitored for the socket. i.e.
  221. * POLLIN, POLLPRI, POLLOUT
  222. * @param cb Function to be called if any of the events are set.
  223. *
  224. * @param userdata Userdata to be passed to the callback function. NULL if
  225. * not needed.
  226. *
  227. * @return A new poll object, NULL on error
  228. */
  229. ssh_poll_handle ssh_poll_new(socket_t fd, short events, ssh_poll_callback cb,
  230. void *userdata) {
  231. ssh_poll_handle p;
  232. p = malloc(sizeof(struct ssh_poll_handle_struct));
  233. if (p == NULL) {
  234. return NULL;
  235. }
  236. ZERO_STRUCTP(p);
  237. p->x.fd = fd;
  238. p->events = events;
  239. if (cb != NULL) {
  240. p->cb = cb;
  241. }
  242. if (userdata != NULL) {
  243. p->cb_data = userdata;
  244. }
  245. return p;
  246. }
  247. /**
  248. * @brief Free a poll object.
  249. *
  250. * @param p Pointer to an already allocated poll object.
  251. */
  252. void ssh_poll_free(ssh_poll_handle p) {
  253. if(p->ctx != NULL){
  254. ssh_poll_ctx_remove(p->ctx,p);
  255. p->ctx=NULL;
  256. }
  257. SAFE_FREE(p);
  258. }
  259. /**
  260. * @brief Get the poll context of a poll object.
  261. *
  262. * @param p Pointer to an already allocated poll object.
  263. *
  264. * @return Poll context or NULL if the poll object isn't attached.
  265. */
  266. ssh_poll_ctx ssh_poll_get_ctx(ssh_poll_handle p) {
  267. return p->ctx;
  268. }
  269. /**
  270. * @brief Get the events of a poll object.
  271. *
  272. * @param p Pointer to an already allocated poll object.
  273. *
  274. * @return Poll events.
  275. */
  276. short ssh_poll_get_events(ssh_poll_handle p) {
  277. return p->events;
  278. }
  279. /**
  280. * @brief Set the events of a poll object. The events will also be propagated
  281. * to an associated poll context.
  282. *
  283. * @param p Pointer to an already allocated poll object.
  284. * @param events Poll events.
  285. */
  286. void ssh_poll_set_events(ssh_poll_handle p, short events) {
  287. p->events = events;
  288. if (p->ctx != NULL) {
  289. p->ctx->pollfds[p->x.idx].events = events;
  290. }
  291. }
  292. /**
  293. * @brief Set the file descriptor of a poll object. The FD will also be propagated
  294. * to an associated poll context.
  295. *
  296. * @param p Pointer to an already allocated poll object.
  297. * @param fd New file descriptor.
  298. */
  299. void ssh_poll_set_fd(ssh_poll_handle p, socket_t fd) {
  300. if (p->ctx != NULL) {
  301. p->ctx->pollfds[p->x.idx].fd = fd;
  302. } else {
  303. p->x.fd = fd;
  304. }
  305. }
  306. /**
  307. * @brief Add extra events to a poll object. Duplicates are ignored.
  308. * The events will also be propagated to an associated poll context.
  309. *
  310. * @param p Pointer to an already allocated poll object.
  311. * @param events Poll events.
  312. */
  313. void ssh_poll_add_events(ssh_poll_handle p, short events) {
  314. ssh_poll_set_events(p, ssh_poll_get_events(p) | events);
  315. }
  316. /**
  317. * @brief Remove events from a poll object. Non-existent are ignored.
  318. * The events will also be propagated to an associated poll context.
  319. *
  320. * @param p Pointer to an already allocated poll object.
  321. * @param events Poll events.
  322. */
  323. void ssh_poll_remove_events(ssh_poll_handle p, short events) {
  324. ssh_poll_set_events(p, ssh_poll_get_events(p) & ~events);
  325. }
  326. /**
  327. * @brief Get the raw socket of a poll object.
  328. *
  329. * @param p Pointer to an already allocated poll object.
  330. *
  331. * @return Raw socket.
  332. */
  333. socket_t ssh_poll_get_fd(ssh_poll_handle p) {
  334. if (p->ctx != NULL) {
  335. return p->ctx->pollfds[p->x.idx].fd;
  336. }
  337. return p->x.fd;
  338. }
  339. /**
  340. * @brief Set the callback of a poll object.
  341. *
  342. * @param p Pointer to an already allocated poll object.
  343. * @param cb Function to be called if any of the events are set.
  344. * @param userdata Userdata to be passed to the callback function. NULL if
  345. * not needed.
  346. */
  347. void ssh_poll_set_callback(ssh_poll_handle p, ssh_poll_callback cb, void *userdata) {
  348. if (cb != NULL) {
  349. p->cb = cb;
  350. p->cb_data = userdata;
  351. }
  352. }
  353. /**
  354. * @brief Create a new poll context. It could be associated with many poll object
  355. * which are going to be polled at the same time as the poll context. You
  356. * would need a single poll context per thread.
  357. *
  358. * @param chunk_size The size of the memory chunk that will be allocated, when
  359. * more memory is needed. This is for efficiency reasons,
  360. * i.e. don't allocate memory for each new poll object, but
  361. * for the next 5. Set it to 0 if you want to use the
  362. * library's default value.
  363. */
  364. ssh_poll_ctx ssh_poll_ctx_new(size_t chunk_size) {
  365. ssh_poll_ctx ctx;
  366. ctx = malloc(sizeof(struct ssh_poll_ctx_struct));
  367. if (ctx == NULL) {
  368. return NULL;
  369. }
  370. ZERO_STRUCTP(ctx);
  371. if (chunk_size == 0) {
  372. chunk_size = SSH_POLL_CTX_CHUNK;
  373. }
  374. ctx->chunk_size = chunk_size;
  375. return ctx;
  376. }
  377. /**
  378. * @brief Free a poll context.
  379. *
  380. * @param ctx Pointer to an already allocated poll context.
  381. */
  382. void ssh_poll_ctx_free(ssh_poll_ctx ctx) {
  383. if (ctx->polls_allocated > 0) {
  384. while (ctx->polls_used > 0){
  385. ssh_poll_handle p = ctx->pollptrs[0];
  386. ssh_poll_ctx_remove(ctx, p);
  387. }
  388. SAFE_FREE(ctx->pollptrs);
  389. SAFE_FREE(ctx->pollfds);
  390. }
  391. SAFE_FREE(ctx);
  392. }
  393. static int ssh_poll_ctx_resize(ssh_poll_ctx ctx, size_t new_size) {
  394. ssh_poll_handle *pollptrs;
  395. ssh_pollfd_t *pollfds;
  396. pollptrs = realloc(ctx->pollptrs, sizeof(ssh_poll_handle *) * new_size);
  397. if (pollptrs == NULL) {
  398. return -1;
  399. }
  400. pollfds = realloc(ctx->pollfds, sizeof(ssh_pollfd_t) * new_size);
  401. if (pollfds == NULL) {
  402. ctx->pollptrs = realloc(pollptrs, sizeof(ssh_poll_handle *) * ctx->polls_allocated);
  403. return -1;
  404. }
  405. ctx->pollptrs = pollptrs;
  406. ctx->pollfds = pollfds;
  407. ctx->polls_allocated = new_size;
  408. return 0;
  409. }
  410. /**
  411. * @brief Add a poll object to a poll context.
  412. *
  413. * @param ctx Pointer to an already allocated poll context.
  414. * @param p Pointer to an already allocated poll object.
  415. *
  416. * @return 0 on success, < 0 on error
  417. */
  418. int ssh_poll_ctx_add(ssh_poll_ctx ctx, ssh_poll_handle p) {
  419. socket_t fd;
  420. if (p->ctx != NULL) {
  421. /* already attached to a context */
  422. return -1;
  423. }
  424. if (ctx->polls_used == ctx->polls_allocated &&
  425. ssh_poll_ctx_resize(ctx, ctx->polls_allocated + ctx->chunk_size) < 0) {
  426. return -1;
  427. }
  428. fd = p->x.fd;
  429. p->x.idx = ctx->polls_used++;
  430. ctx->pollptrs[p->x.idx] = p;
  431. ctx->pollfds[p->x.idx].fd = fd;
  432. ctx->pollfds[p->x.idx].events = p->events;
  433. ctx->pollfds[p->x.idx].revents = 0;
  434. p->ctx = ctx;
  435. return 0;
  436. }
  437. /**
  438. * @brief Add a socket object to a poll context.
  439. *
  440. * @param ctx Pointer to an already allocated poll context.
  441. * @param s A SSH socket handle
  442. *
  443. * @return 0 on success, < 0 on error
  444. */
  445. int ssh_poll_ctx_add_socket (ssh_poll_ctx ctx, ssh_socket s) {
  446. ssh_poll_handle p_in, p_out;
  447. int ret;
  448. p_in=ssh_socket_get_poll_handle_in(s);
  449. if(p_in==NULL)
  450. return -1;
  451. ret = ssh_poll_ctx_add(ctx,p_in);
  452. if(ret != 0)
  453. return ret;
  454. p_out=ssh_socket_get_poll_handle_out(s);
  455. if(p_in != p_out)
  456. ret = ssh_poll_ctx_add(ctx,p_out);
  457. return ret;
  458. }
  459. /**
  460. * @brief Remove a poll object from a poll context.
  461. *
  462. * @param ctx Pointer to an already allocated poll context.
  463. * @param p Pointer to an already allocated poll object.
  464. */
  465. void ssh_poll_ctx_remove(ssh_poll_ctx ctx, ssh_poll_handle p) {
  466. size_t i;
  467. i = p->x.idx;
  468. p->x.fd = ctx->pollfds[i].fd;
  469. p->ctx = NULL;
  470. ctx->polls_used--;
  471. /* fill the empty poll slot with the last one */
  472. if (ctx->polls_used > 0 && ctx->polls_used != i) {
  473. ctx->pollfds[i] = ctx->pollfds[ctx->polls_used];
  474. ctx->pollptrs[i] = ctx->pollptrs[ctx->polls_used];
  475. }
  476. /* this will always leave at least chunk_size polls allocated */
  477. if (ctx->polls_allocated - ctx->polls_used > ctx->chunk_size) {
  478. ssh_poll_ctx_resize(ctx, ctx->polls_allocated - ctx->chunk_size);
  479. }
  480. }
  481. /**
  482. * @brief Poll all the sockets associated through a poll object with a
  483. * poll context. If any of the events are set after the poll, the
  484. * call back function of the socket will be called.
  485. * This function should be called once within the programs main loop.
  486. *
  487. * @param ctx Pointer to an already allocated poll context.
  488. * @param timeout An upper limit on the time for which ssh_poll_ctx() will
  489. * block, in milliseconds. Specifying a negative value
  490. * means an infinite timeout. This parameter is passed to
  491. * the poll() function.
  492. * @returns SSH_OK No error.
  493. * SSH_ERROR Error happened during the poll.
  494. * SSH_AGAIN Timeout occured
  495. */
  496. int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout) {
  497. int rc;
  498. int i, used;
  499. ssh_poll_handle p;
  500. socket_t fd;
  501. int revents;
  502. if (!ctx->polls_used)
  503. return 0;
  504. rc = ssh_poll(ctx->pollfds, ctx->polls_used, timeout);
  505. if(rc < 0)
  506. return SSH_ERROR;
  507. if (rc == 0)
  508. return SSH_AGAIN;
  509. used = ctx->polls_used;
  510. for (i = 0; i < used && rc > 0; ) {
  511. if (!ctx->pollfds[i].revents) {
  512. i++;
  513. } else {
  514. int ret;
  515. p = ctx->pollptrs[i];
  516. fd = ctx->pollfds[i].fd;
  517. revents = ctx->pollfds[i].revents;
  518. if (p->cb && (ret = p->cb(p, fd, revents, p->cb_data)) < 0) {
  519. if (ret == -2) {
  520. return -1;
  521. }
  522. /* the poll was removed, reload the used counter and start again */
  523. used = ctx->polls_used;
  524. i=0;
  525. } else {
  526. ctx->pollfds[i].revents = 0;
  527. i++;
  528. }
  529. rc--;
  530. }
  531. }
  532. return rc;
  533. }
  534. /**
  535. * @internal
  536. * @brief gets the default poll structure for the current session,
  537. * when used in blocking mode.
  538. * @param session SSH session
  539. * @returns the default ssh_poll_ctx
  540. */
  541. ssh_poll_ctx ssh_poll_get_default_ctx(ssh_session session){
  542. if(session->default_poll_ctx != NULL)
  543. return session->default_poll_ctx;
  544. /* 2 is enough for the default one */
  545. session->default_poll_ctx = ssh_poll_ctx_new(2);
  546. return session->default_poll_ctx;
  547. }
  548. /** @} */
  549. /* vim: set ts=4 sw=4 et cindent: */