We now build libssh2 in Xcode and it's a much better UB/10.4 citizen
[printdrop.git] / Vendor / libssh2 / Source / session.c
1 /* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms,
5 * with or without modification, are permitted provided
6 * that the following conditions are met:
7 *
8 * Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the
10 * following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials
15 * provided with the distribution.
16 *
17 * Neither the name of the copyright holder nor the names
18 * of any other contributors may be used to endorse or
19 * promote products derived from this software without
20 * specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
23 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
34 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
35 * OF SUCH DAMAGE.
36 */
37
38 #include "libssh2_priv.h"
39 #include <errno.h>
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43 #include <stdlib.h>
44 #include <fcntl.h>
45
46 #ifdef HAVE_GETTIMEOFDAY
47 #include <sys/time.h>
48 #endif
49 #ifdef HAVE_ALLOCA_H
50 #include <alloca.h>
51 #endif
52
53 /* {{{ libssh2_default_alloc
54 */
55 static
56 LIBSSH2_ALLOC_FUNC(libssh2_default_alloc)
57 {
58 (void) abstract;
59 return malloc(count);
60 }
61
62 /* }}} */
63
64 /* {{{ libssh2_default_free
65 */
66 static
67 LIBSSH2_FREE_FUNC(libssh2_default_free)
68 {
69 (void) abstract;
70 free(ptr);
71 }
72
73 /* }}} */
74
75 /* {{{ libssh2_default_realloc
76 */
77 static
78 LIBSSH2_REALLOC_FUNC(libssh2_default_realloc)
79 {
80 (void) abstract;
81 return realloc(ptr, count);
82 }
83
84 /* }}} */
85
86 /* {{{ libssh2_banner_receive
87 * Wait for a hello from the remote host
88 * Allocate a buffer and store the banner in session->remote.banner
89 * Returns: 0 on success, PACKET_EAGAIN if read would block, 1 on failure
90 */
91 static int
92 libssh2_banner_receive(LIBSSH2_SESSION * session)
93 {
94 int ret;
95 int banner_len;
96
97 if (session->banner_TxRx_state == libssh2_NB_state_idle) {
98 banner_len = 0;
99
100 session->banner_TxRx_state = libssh2_NB_state_created;
101 } else {
102 banner_len = session->banner_TxRx_total_send;
103 }
104
105 while ((banner_len < (int) sizeof(session->banner_TxRx_banner)) &&
106 ((banner_len == 0)
107 || (session->banner_TxRx_banner[banner_len - 1] != '\n'))) {
108 char c = '\0';
109
110 ret =
111 recv(session->socket_fd, &c, 1,
112 LIBSSH2_SOCKET_RECV_FLAGS(session));
113
114 if (ret < 0) {
115 #ifdef WIN32
116 switch (WSAGetLastError()) {
117 case WSAEWOULDBLOCK:
118 errno = EAGAIN;
119 break;
120
121 case WSAENOTSOCK:
122 errno = EBADF;
123 break;
124
125 case WSAENOTCONN:
126 case WSAECONNABORTED:
127 errno = WSAENOTCONN;
128 break;
129
130 case WSAEINTR:
131 errno = EINTR;
132 break;
133 }
134 #endif /* WIN32 */
135 if (errno == EAGAIN) {
136 session->banner_TxRx_total_send = banner_len;
137 return PACKET_EAGAIN;
138 }
139
140 /* Some kinda error */
141 session->banner_TxRx_state = libssh2_NB_state_idle;
142 session->banner_TxRx_total_send = 0;
143 return 1;
144 }
145
146 if (ret == 0) {
147 session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
148 return PACKET_FAIL;
149 }
150
151 if (c == '\0') {
152 /* NULLs are not allowed in SSH banners */
153 session->banner_TxRx_state = libssh2_NB_state_idle;
154 session->banner_TxRx_total_send = 0;
155 return 1;
156 }
157
158 session->banner_TxRx_banner[banner_len++] = c;
159 }
160
161 while (banner_len &&
162 ((session->banner_TxRx_banner[banner_len - 1] == '\n') ||
163 (session->banner_TxRx_banner[banner_len - 1] == '\r'))) {
164 banner_len--;
165 }
166
167 /* From this point on, we are done here */
168 session->banner_TxRx_state = libssh2_NB_state_idle;
169 session->banner_TxRx_total_send = 0;
170
171 if (!banner_len)
172 return 1;
173
174 session->remote.banner = LIBSSH2_ALLOC(session, banner_len + 1);
175 if (!session->remote.banner) {
176 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
177 "Error allocating space for remote banner", 0);
178 return 1;
179 }
180 memcpy(session->remote.banner, session->banner_TxRx_banner, banner_len);
181 session->remote.banner[banner_len] = '\0';
182 _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Received Banner: %s",
183 session->remote.banner);
184 return 0;
185 }
186
187 /* }}} */
188
189 /* {{{ libssh2_banner_send
190 * Send the default banner, or the one set via libssh2_setopt_string
191 *
192 * Returns PACKET_EAGAIN if it would block - and if it does so, you should
193 * call this function again as soon as it is likely that more data can be
194 * sent, and this function should then be called with the same argument set
195 * (same data pointer and same data_len) until zero or failure is returned.
196 */
197 static int
198 libssh2_banner_send(LIBSSH2_SESSION * session)
199 {
200 char *banner = (char *) LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF;
201 int banner_len = sizeof(LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF) - 1;
202 ssize_t ret;
203 #ifdef LIBSSH2DEBUG
204 char banner_dup[256];
205 #endif
206
207 if (session->banner_TxRx_state == libssh2_NB_state_idle) {
208 if (session->local.banner) {
209 /* setopt_string will have given us our \r\n characters */
210 banner_len = strlen((char *) session->local.banner);
211 banner = (char *) session->local.banner;
212 }
213 #ifdef LIBSSH2DEBUG
214 /* Hack and slash to avoid sending CRLF in debug output */
215 if (banner_len < 256) {
216 memcpy(banner_dup, banner, banner_len - 2);
217 banner_dup[banner_len - 2] = '\0';
218 } else {
219 memcpy(banner_dup, banner, 255);
220 banner[255] = '\0';
221 }
222
223 _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Sending Banner: %s",
224 banner_dup);
225 #endif
226
227 session->banner_TxRx_state = libssh2_NB_state_created;
228 }
229
230 ret =
231 send(session->socket_fd, banner + session->banner_TxRx_total_send,
232 banner_len - session->banner_TxRx_total_send,
233 LIBSSH2_SOCKET_SEND_FLAGS(session));
234
235 if (ret != (banner_len - session->banner_TxRx_total_send)) {
236 if ((ret > 0) || ((ret == -1) && (errno == EAGAIN))) {
237 /* the whole packet could not be sent, save the what was */
238 session->banner_TxRx_total_send += ret;
239 return PACKET_EAGAIN;
240 }
241 session->banner_TxRx_state = libssh2_NB_state_idle;
242 session->banner_TxRx_total_send = 0;
243 return PACKET_FAIL;
244 }
245
246 /* Set the state back to idle */
247 session->banner_TxRx_state = libssh2_NB_state_idle;
248 session->banner_TxRx_total_send = 0;
249
250 return 0;
251 }
252
253 /* }}} */
254
255 /*
256 * _libssh2_nonblock() sets the given socket to either blocking or
257 * non-blocking mode based on the 'nonblock' boolean argument. This function
258 * is copied from the libcurl sources with permission.
259 */
260 static int
261 _libssh2_nonblock(int sockfd, /* operate on this */
262 int nonblock /* TRUE or FALSE */ )
263 {
264 #undef SETBLOCK
265 #define SETBLOCK 0
266 #ifdef HAVE_O_NONBLOCK
267 /* most recent unix versions */
268 int flags;
269
270 flags = fcntl(sockfd, F_GETFL, 0);
271 if (nonblock)
272 return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
273 else
274 return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));
275 #undef SETBLOCK
276 #define SETBLOCK 1
277 #endif
278
279 #if defined(HAVE_FIONBIO) && (SETBLOCK == 0)
280 /* older unix versions */
281 int flags;
282
283 flags = nonblock;
284 return ioctl(sockfd, FIONBIO, &flags);
285 #undef SETBLOCK
286 #define SETBLOCK 2
287 #endif
288
289 #if defined(HAVE_IOCTLSOCKET) && (SETBLOCK == 0)
290 /* Windows? */
291 unsigned long flags;
292 flags = nonblock;
293
294 return ioctlsocket(sockfd, FIONBIO, &flags);
295 #undef SETBLOCK
296 #define SETBLOCK 3
297 #endif
298
299 #if defined(HAVE_IOCTLSOCKET_CASE) && (SETBLOCK == 0)
300 /* presumably for Amiga */
301 return IoctlSocket(sockfd, FIONBIO, (long) nonblock);
302 #undef SETBLOCK
303 #define SETBLOCK 4
304 #endif
305
306 #if defined(HAVE_SO_NONBLOCK) && (SETBLOCK == 0)
307 /* BeOS */
308 long b = nonblock ? 1 : 0;
309 return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
310 #undef SETBLOCK
311 #define SETBLOCK 5
312 #endif
313
314 #ifdef HAVE_DISABLED_NONBLOCKING
315 return 0; /* returns success */
316 #undef SETBLOCK
317 #define SETBLOCK 6
318 #endif
319
320 #if (SETBLOCK == 0)
321 #error "no non-blocking method was found/used/set"
322 #endif
323 }
324
325 /*
326 * _libssh2_get_socket_nonblocking() gets the given blocking or non-blocking
327 * state of the socket.
328 */
329 static int
330 _libssh2_get_socket_nonblocking(int sockfd)
331 { /* operate on this */
332 #undef GETBLOCK
333 #define GETBLOCK 0
334 #ifdef HAVE_O_NONBLOCK
335 /* most recent unix versions */
336 int flags;
337
338 if ((flags = fcntl(sockfd, F_GETFL, 0)) == -1) {
339 /* Assume blocking on error */
340 return 1;
341 }
342 return (flags & O_NONBLOCK);
343 #undef GETBLOCK
344 #define GETBLOCK 1
345 #endif
346
347 #if defined(WSAEWOULDBLOCK) && (GETBLOCK == 0)
348 /* Windows? */
349 unsigned int option_value;
350 socklen_t option_len = sizeof(option_value);
351
352 if (getsockopt
353 (sockfd, SOL_SOCKET, SO_ERROR, (void *) &option_value, &option_len)) {
354 /* Assume blocking on error */
355 return 1;
356 }
357 return (int) option_value;
358 #undef GETBLOCK
359 #define GETBLOCK 2
360 #endif
361
362 #if defined(HAVE_SO_NONBLOCK) && (GETBLOCK == 0)
363 /* BeOS */
364 long b;
365 if (getsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b))) {
366 /* Assume blocking on error */
367 return 1;
368 }
369 return (int) b;
370 #undef GETBLOCK
371 #define GETBLOCK 5
372 #endif
373
374 #ifdef HAVE_DISABLED_NONBLOCKING
375 return 1; /* returns blocking */
376 #undef GETBLOCK
377 #define GETBLOCK 6
378 #endif
379
380 #if (GETBLOCK == 0)
381 #error "no non-blocking method was found/used/get"
382 #endif
383 }
384
385 /* {{{ libssh2_banner_set
386 * Set the local banner
387 */
388 LIBSSH2_API int
389 libssh2_banner_set(LIBSSH2_SESSION * session, const char *banner)
390 {
391 int banner_len = banner ? strlen(banner) : 0;
392
393 if (session->local.banner) {
394 LIBSSH2_FREE(session, session->local.banner);
395 session->local.banner = NULL;
396 }
397
398 if (!banner_len) {
399 return 0;
400 }
401
402 session->local.banner = LIBSSH2_ALLOC(session, banner_len + 3);
403 if (!session->local.banner) {
404 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
405 "Unable to allocate memory for local banner", 0);
406 return -1;
407 }
408
409 memcpy(session->local.banner, banner, banner_len);
410 session->local.banner[banner_len] = '\0';
411 _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Setting local Banner: %s",
412 session->local.banner);
413 session->local.banner[banner_len++] = '\r';
414 session->local.banner[banner_len++] = '\n';
415 session->local.banner[banner_len++] = '\0';
416
417 return 0;
418 }
419
420 /* }}} */
421
422 /* {{{ proto libssh2_session_init
423 * Allocate and initialize a libssh2 session structure
424 * Allows for malloc callbacks in case the calling program has its own memory manager
425 * It's allowable (but unadvisable) to define some but not all of the malloc callbacks
426 * An additional pointer value may be optionally passed to be sent to the callbacks (so they know who's asking)
427 */
428 LIBSSH2_API LIBSSH2_SESSION *
429 libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)),
430 LIBSSH2_FREE_FUNC((*my_free)),
431 LIBSSH2_REALLOC_FUNC((*my_realloc)), void *abstract)
432 {
433 LIBSSH2_ALLOC_FUNC((*local_alloc)) = libssh2_default_alloc;
434 LIBSSH2_FREE_FUNC((*local_free)) = libssh2_default_free;
435 LIBSSH2_REALLOC_FUNC((*local_realloc)) = libssh2_default_realloc;
436 LIBSSH2_SESSION *session;
437
438 if (my_alloc) {
439 local_alloc = my_alloc;
440 }
441 if (my_free) {
442 local_free = my_free;
443 }
444 if (my_realloc) {
445 local_realloc = my_realloc;
446 }
447
448 session = local_alloc(sizeof(LIBSSH2_SESSION), abstract);
449 if (session) {
450 memset(session, 0, sizeof(LIBSSH2_SESSION));
451 session->alloc = local_alloc;
452 session->free = local_free;
453 session->realloc = local_realloc;
454 session->abstract = abstract;
455 _libssh2_debug(session, LIBSSH2_DBG_TRANS,
456 "New session resource allocated");
457 libssh2_crypto_init();
458 }
459 return session;
460 }
461
462 /* }}} */
463
464 /* {{{ libssh2_session_callback_set
465 * Set (or reset) a callback function
466 * Returns the prior address
467 *
468 * FIXME: this function relies on that we can typecast function pointers
469 * to void pointers, which isn't allowed in ISO C!
470 */
471 LIBSSH2_API void *
472 libssh2_session_callback_set(LIBSSH2_SESSION * session,
473 int cbtype, void *callback)
474 {
475 void *oldcb;
476
477 switch (cbtype) {
478 case LIBSSH2_CALLBACK_IGNORE:
479 oldcb = session->ssh_msg_ignore;
480 session->ssh_msg_ignore = callback;
481 return oldcb;
482
483 case LIBSSH2_CALLBACK_DEBUG:
484 oldcb = session->ssh_msg_debug;
485 session->ssh_msg_debug = callback;
486 return oldcb;
487
488 case LIBSSH2_CALLBACK_DISCONNECT:
489 oldcb = session->ssh_msg_disconnect;
490 session->ssh_msg_disconnect = callback;
491 return oldcb;
492
493 case LIBSSH2_CALLBACK_MACERROR:
494 oldcb = session->macerror;
495 session->macerror = callback;
496 return oldcb;
497
498 case LIBSSH2_CALLBACK_X11:
499 oldcb = session->x11;
500 session->x11 = callback;
501 return oldcb;
502
503 }
504 _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Setting Callback %d", cbtype);
505
506 return NULL;
507 }
508
509 /* }}} */
510
511 /* {{{ proto libssh2_session_startup
512 * session: LIBSSH2_SESSION struct allocated and owned by the calling program
513 * Returns: 0 on success, or non-zero on failure
514 * Any memory allocated by libssh2 will use alloc/realloc/free
515 * callbacks in session
516 * socket *must* be populated with an opened and connected socket.
517 */
518 LIBSSH2_API int
519 libssh2_session_startup(LIBSSH2_SESSION * session, int sock)
520 {
521 int rc;
522
523 if (session->startup_state == libssh2_NB_state_idle) {
524 _libssh2_debug(session, LIBSSH2_DBG_TRANS,
525 "session_startup for socket %d", sock);
526 /* FIXME: on some platforms (like win32) sockets are unsigned */
527 if (sock < 0) {
528 /* Did we forget something? */
529 libssh2_error(session, LIBSSH2_ERROR_SOCKET_NONE,
530 "Bad socket provided", 0);
531 return LIBSSH2_ERROR_SOCKET_NONE;
532 }
533 session->socket_fd = sock;
534
535 session->socket_block =
536 !_libssh2_get_socket_nonblocking(session->socket_fd);
537 if (session->socket_block) {
538 /*
539 * Since we can't be sure that we are in blocking or there
540 * was an error detecting the state, so set to blocking to
541 * be sure
542 */
543 _libssh2_nonblock(session->socket_fd, 0);
544 }
545
546 session->startup_state = libssh2_NB_state_created;
547 }
548
549 /* TODO: Liveness check */
550
551 if (session->startup_state == libssh2_NB_state_created) {
552 rc = libssh2_banner_send(session);
553 if (rc == PACKET_EAGAIN) {
554 libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
555 "Would block sending banner to remote host", 0);
556 return LIBSSH2_ERROR_EAGAIN;
557 } else if (rc) {
558 /* Unable to send banner? */
559 libssh2_error(session, LIBSSH2_ERROR_BANNER_SEND,
560 "Error sending banner to remote host", 0);
561 return LIBSSH2_ERROR_BANNER_SEND;
562 }
563
564 session->startup_state = libssh2_NB_state_sent;
565 }
566
567 if (session->startup_state == libssh2_NB_state_sent) {
568 rc = libssh2_banner_receive(session);
569 if (rc == PACKET_EAGAIN) {
570 libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
571 "Would block waiting for banner", 0);
572 return LIBSSH2_ERROR_EAGAIN;
573 } else if (rc) {
574 /* Unable to receive banner from remote */
575 libssh2_error(session, LIBSSH2_ERROR_BANNER_NONE,
576 "Timeout waiting for banner", 0);
577 return LIBSSH2_ERROR_BANNER_NONE;
578 }
579
580 session->startup_state = libssh2_NB_state_sent1;
581 }
582
583 if (session->startup_state == libssh2_NB_state_sent1) {
584 rc = libssh2_kex_exchange(session, 0, &session->startup_key_state);
585 if (rc == PACKET_EAGAIN) {
586 libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
587 "Would block exchanging encryption keys", 0);
588 return LIBSSH2_ERROR_EAGAIN;
589 } else if (rc) {
590 libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE,
591 "Unable to exchange encryption keys", 0);
592 return LIBSSH2_ERROR_KEX_FAILURE;
593 }
594
595 session->startup_state = libssh2_NB_state_sent2;
596 }
597
598 if (session->startup_state == libssh2_NB_state_sent2) {
599 _libssh2_debug(session, LIBSSH2_DBG_TRANS,
600 "Requesting userauth service");
601
602 /* Request the userauth service */
603 session->startup_service[0] = SSH_MSG_SERVICE_REQUEST;
604 libssh2_htonu32(session->startup_service + 1,
605 sizeof("ssh-userauth") - 1);
606 memcpy(session->startup_service + 5, "ssh-userauth",
607 sizeof("ssh-userauth") - 1);
608
609 session->startup_state = libssh2_NB_state_sent3;
610 }
611
612 if (session->startup_state == libssh2_NB_state_sent3) {
613 rc = libssh2_packet_write(session, session->startup_service,
614 sizeof("ssh-userauth") + 5 - 1);
615 if (rc == PACKET_EAGAIN) {
616 libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
617 "Would block asking for ssh-userauth service", 0);
618 return LIBSSH2_ERROR_EAGAIN;
619 } else if (rc) {
620 libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
621 "Unable to ask for ssh-userauth service", 0);
622 return LIBSSH2_ERROR_SOCKET_SEND;
623 }
624
625 session->startup_state = libssh2_NB_state_sent4;
626 }
627
628 if (session->startup_state == libssh2_NB_state_sent4) {
629 rc = libssh2_packet_require_ex(session, SSH_MSG_SERVICE_ACCEPT,
630 &session->startup_data,
631 &session->startup_data_len, 0, NULL, 0,
632 &session->startup_req_state);
633 if (rc == PACKET_EAGAIN) {
634 return LIBSSH2_ERROR_EAGAIN;
635 } else if (rc) {
636 return LIBSSH2_ERROR_SOCKET_DISCONNECT;
637 }
638 session->startup_service_length =
639 libssh2_ntohu32(session->startup_data + 1);
640
641 if ((session->startup_service_length != (sizeof("ssh-userauth") - 1))
642 || strncmp("ssh-userauth", (char *) session->startup_data + 5,
643 session->startup_service_length)) {
644 LIBSSH2_FREE(session, session->startup_data);
645 session->startup_data = NULL;
646 libssh2_error(session, LIBSSH2_ERROR_PROTO,
647 "Invalid response received from server", 0);
648 return LIBSSH2_ERROR_PROTO;
649 }
650 LIBSSH2_FREE(session, session->startup_data);
651 session->startup_data = NULL;
652
653 session->startup_state = libssh2_NB_state_idle;
654
655 return 0;
656 }
657
658 /* just for safety return some error */
659 return LIBSSH2_ERROR_INVAL;
660 }
661
662 /* }}} */
663
664 /* {{{ proto libssh2_session_free
665 * Frees the memory allocated to the session
666 * Also closes and frees any channels attached to this session
667 */
668 LIBSSH2_API int
669 libssh2_session_free(LIBSSH2_SESSION * session)
670 {
671 int rc;
672
673 if (session->free_state == libssh2_NB_state_idle) {
674 _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Freeing session resource",
675 session->remote.banner);
676
677 session->state = libssh2_NB_state_created;
678 }
679
680 if (session->free_state == libssh2_NB_state_created) {
681 while (session->channels.head) {
682 LIBSSH2_CHANNEL *tmp = session->channels.head;
683
684 rc = libssh2_channel_free(session->channels.head);
685 if (rc == PACKET_EAGAIN) {
686 return PACKET_EAGAIN;
687 }
688 if (tmp == session->channels.head) {
689 /* channel_free couldn't do it's job, perform a messy cleanup */
690 tmp = session->channels.head;
691
692 /* unlink */
693 session->channels.head = tmp->next;
694
695 /* free */
696 LIBSSH2_FREE(session, tmp);
697
698 /* reverse linking isn't important here, we're killing the structure */
699 }
700 }
701
702 session->state = libssh2_NB_state_sent;
703 }
704
705 if (session->state == libssh2_NB_state_sent) {
706 while (session->listeners) {
707 rc = libssh2_channel_forward_cancel(session->listeners);
708 if (rc == PACKET_EAGAIN) {
709 return PACKET_EAGAIN;
710 }
711 }
712
713 session->state = libssh2_NB_state_sent1;
714 }
715
716 if (session->state & LIBSSH2_STATE_NEWKEYS) {
717 /* hostkey */
718 if (session->hostkey && session->hostkey->dtor) {
719 session->hostkey->dtor(session, &session->server_hostkey_abstract);
720 }
721
722 /* Client to Server */
723 /* crypt */
724 if (session->local.crypt && session->local.crypt->dtor) {
725 session->local.crypt->dtor(session,
726 &session->local.crypt_abstract);
727 }
728 /* comp */
729 if (session->local.comp && session->local.comp->dtor) {
730 session->local.comp->dtor(session, 1,
731 &session->local.comp_abstract);
732 }
733 /* mac */
734 if (session->local.mac && session->local.mac->dtor) {
735 session->local.mac->dtor(session, &session->local.mac_abstract);
736 }
737
738 /* Server to Client */
739 /* crypt */
740 if (session->remote.crypt && session->remote.crypt->dtor) {
741 session->remote.crypt->dtor(session,
742 &session->remote.crypt_abstract);
743 }
744 /* comp */
745 if (session->remote.comp && session->remote.comp->dtor) {
746 session->remote.comp->dtor(session, 0,
747 &session->remote.comp_abstract);
748 }
749 /* mac */
750 if (session->remote.mac && session->remote.mac->dtor) {
751 session->remote.mac->dtor(session, &session->remote.mac_abstract);
752 }
753
754 /* session_id */
755 if (session->session_id) {
756 LIBSSH2_FREE(session, session->session_id);
757 }
758 }
759
760 /* Free banner(s) */
761 if (session->remote.banner) {
762 LIBSSH2_FREE(session, session->remote.banner);
763 }
764 if (session->local.banner) {
765 LIBSSH2_FREE(session, session->local.banner);
766 }
767
768 /* Free preference(s) */
769 if (session->kex_prefs) {
770 LIBSSH2_FREE(session, session->kex_prefs);
771 }
772 if (session->hostkey_prefs) {
773 LIBSSH2_FREE(session, session->hostkey_prefs);
774 }
775
776 if (session->local.crypt_prefs) {
777 LIBSSH2_FREE(session, session->local.crypt_prefs);
778 }
779 if (session->local.mac_prefs) {
780 LIBSSH2_FREE(session, session->local.mac_prefs);
781 }
782 if (session->local.comp_prefs) {
783 LIBSSH2_FREE(session, session->local.comp_prefs);
784 }
785 if (session->local.lang_prefs) {
786 LIBSSH2_FREE(session, session->local.lang_prefs);
787 }
788
789 if (session->remote.crypt_prefs) {
790 LIBSSH2_FREE(session, session->remote.crypt_prefs);
791 }
792 if (session->remote.mac_prefs) {
793 LIBSSH2_FREE(session, session->remote.mac_prefs);
794 }
795 if (session->remote.comp_prefs) {
796 LIBSSH2_FREE(session, session->remote.comp_prefs);
797 }
798 if (session->remote.lang_prefs) {
799 LIBSSH2_FREE(session, session->remote.lang_prefs);
800 }
801
802 /*
803 * Make sure all memory used in the state variables are free
804 */
805 if (session->startup_data) {
806 LIBSSH2_FREE(session, session->startup_data);
807 }
808 if (session->disconnect_data) {
809 LIBSSH2_FREE(session, session->disconnect_data);
810 }
811 if (session->userauth_list_data) {
812 LIBSSH2_FREE(session, session->userauth_list_data);
813 }
814 if (session->userauth_pswd_data) {
815 LIBSSH2_FREE(session, session->userauth_pswd_data);
816 }
817 if (session->userauth_pswd_newpw) {
818 LIBSSH2_FREE(session, session->userauth_pswd_newpw);
819 }
820 if (session->userauth_host_packet) {
821 LIBSSH2_FREE(session, session->userauth_host_packet);
822 }
823 if (session->userauth_host_method) {
824 LIBSSH2_FREE(session, session->userauth_host_method);
825 }
826 if (session->userauth_host_data) {
827 LIBSSH2_FREE(session, session->userauth_host_data);
828 }
829 if (session->userauth_pblc_data) {
830 LIBSSH2_FREE(session, session->userauth_pblc_data);
831 }
832 if (session->userauth_pblc_packet) {
833 LIBSSH2_FREE(session, session->userauth_pblc_packet);
834 }
835 if (session->userauth_pblc_method) {
836 LIBSSH2_FREE(session, session->userauth_pblc_method);
837 }
838 if (session->userauth_kybd_data) {
839 LIBSSH2_FREE(session, session->userauth_kybd_data);
840 }
841 if (session->userauth_kybd_packet) {
842 LIBSSH2_FREE(session, session->userauth_kybd_packet);
843 }
844 if (session->userauth_kybd_auth_instruction) {
845 LIBSSH2_FREE(session, session->userauth_kybd_auth_instruction);
846 }
847 if (session->open_packet) {
848 LIBSSH2_FREE(session, session->open_packet);
849 }
850 if (session->open_data) {
851 LIBSSH2_FREE(session, session->open_data);
852 }
853 if (session->direct_message) {
854 LIBSSH2_FREE(session, session->direct_message);
855 }
856 if (session->fwdLstn_packet) {
857 LIBSSH2_FREE(session, session->fwdLstn_packet);
858 }
859 if (session->pkeyInit_data) {
860 LIBSSH2_FREE(session, session->pkeyInit_data);
861 }
862 if (session->scpRecv_command) {
863 LIBSSH2_FREE(session, session->scpRecv_command);
864 }
865 if (session->scpSend_command) {
866 LIBSSH2_FREE(session, session->scpSend_command);
867 }
868 if (session->scpRecv_err_msg) {
869 LIBSSH2_FREE(session, session->scpRecv_err_msg);
870 }
871 if (session->scpSend_err_msg) {
872 LIBSSH2_FREE(session, session->scpSend_err_msg);
873 }
874
875 /* Free the error message, if we ar supposed to */
876 if (session->err_msg && session->err_should_free) {
877 LIBSSH2_FREE(session, session->err_msg);
878 }
879
880 /* Cleanup any remaining packets */
881 while (session->packets.head) {
882 LIBSSH2_PACKET *tmp = session->packets.head;
883
884 /* unlink */
885 session->packets.head = tmp->next;
886
887 /* free */
888 LIBSSH2_FREE(session, tmp->data);
889 LIBSSH2_FREE(session, tmp);
890 }
891
892 LIBSSH2_FREE(session, session);
893
894 return 0;
895 }
896
897 /* }}} */
898
899 /* {{{ libssh2_session_disconnect_ex
900 */
901 LIBSSH2_API int
902 libssh2_session_disconnect_ex(LIBSSH2_SESSION * session, int reason,
903 const char *description, const char *lang)
904 {
905 unsigned char *s;
906 unsigned long descr_len = 0, lang_len = 0;
907 int rc;
908
909 if (session->disconnect_state == libssh2_NB_state_idle) {
910 _libssh2_debug(session, LIBSSH2_DBG_TRANS,
911 "Disconnecting: reason=%d, desc=%s, lang=%s", reason,
912 description, lang);
913 if (description) {
914 descr_len = strlen(description);
915 }
916 if (lang) {
917 lang_len = strlen(lang);
918 }
919 /* 13 = packet_type(1) + reason code(4) + descr_len(4) + lang_len(4) */
920 session->disconnect_data_len = descr_len + lang_len + 13;
921
922 s = session->disconnect_data =
923 LIBSSH2_ALLOC(session, session->disconnect_data_len);
924 if (!session->disconnect_data) {
925 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
926 "Unable to allocate memory for disconnect packet",
927 0);
928 session->disconnect_state = libssh2_NB_state_idle;
929 return -1;
930 }
931
932 *(s++) = SSH_MSG_DISCONNECT;
933 libssh2_htonu32(s, reason);
934 s += 4;
935
936 libssh2_htonu32(s, descr_len);
937 s += 4;
938 if (description) {
939 memcpy(s, description, descr_len);
940 s += descr_len;
941 }
942
943 libssh2_htonu32(s, lang_len);
944 s += 4;
945 if (lang) {
946 memcpy(s, lang, lang_len);
947 s += lang_len;
948 }
949
950 session->disconnect_state = libssh2_NB_state_created;
951 }
952
953 rc = libssh2_packet_write(session, session->disconnect_data,
954 session->disconnect_data_len);
955 if (rc == PACKET_EAGAIN) {
956 return PACKET_EAGAIN;
957 }
958
959 LIBSSH2_FREE(session, session->disconnect_data);
960 session->disconnect_data = NULL;
961 session->disconnect_state = libssh2_NB_state_idle;
962
963 return 0;
964 }
965
966 /* }}} */
967
968 /* {{{ libssh2_session_methods
969 * Return the currently active methods for method_type
970 * NOTE: Currently lang_cs and lang_sc are ALWAYS set to empty string regardless of actual negotiation
971 * Strings should NOT be freed
972 */
973 LIBSSH2_API const char *
974 libssh2_session_methods(LIBSSH2_SESSION * session, int method_type)
975 {
976 /* All methods have char *name as their first element */
977 const LIBSSH2_KEX_METHOD *method = NULL;
978
979 switch (method_type) {
980 case LIBSSH2_METHOD_KEX:
981 method = session->kex;
982 break;
983
984 case LIBSSH2_METHOD_HOSTKEY:
985 method = (LIBSSH2_KEX_METHOD *) session->hostkey;
986 break;
987
988 case LIBSSH2_METHOD_CRYPT_CS:
989 method = (LIBSSH2_KEX_METHOD *) session->local.crypt;
990 break;
991
992 case LIBSSH2_METHOD_CRYPT_SC:
993 method = (LIBSSH2_KEX_METHOD *) session->remote.crypt;
994 break;
995
996 case LIBSSH2_METHOD_MAC_CS:
997 method = (LIBSSH2_KEX_METHOD *) session->local.mac;
998 break;
999
1000 case LIBSSH2_METHOD_MAC_SC:
1001 method = (LIBSSH2_KEX_METHOD *) session->remote.mac;
1002 break;
1003
1004 case LIBSSH2_METHOD_COMP_CS:
1005 method = (LIBSSH2_KEX_METHOD *) session->local.comp;
1006 break;
1007
1008 case LIBSSH2_METHOD_COMP_SC:
1009 method = (LIBSSH2_KEX_METHOD *) session->remote.comp;
1010 break;
1011
1012 case LIBSSH2_METHOD_LANG_CS:
1013 return "";
1014 break;
1015
1016 case LIBSSH2_METHOD_LANG_SC:
1017 return "";
1018 break;
1019
1020 default:
1021 libssh2_error(session, LIBSSH2_ERROR_INVAL,
1022 "Invalid parameter specified for method_type", 0);
1023 return NULL;
1024 break;
1025 }
1026
1027 if (!method) {
1028 libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE,
1029 "No method negotiated", 0);
1030 return NULL;
1031 }
1032
1033 return method->name;
1034 }
1035
1036 /* }}} */
1037
1038 /* {{{ libssh2_session_abstract
1039 * Retrieve a pointer to the abstract property
1040 */
1041 LIBSSH2_API void **
1042 libssh2_session_abstract(LIBSSH2_SESSION * session)
1043 {
1044 return &session->abstract;
1045 }
1046
1047 /* }}} */
1048
1049 /* {{{ libssh2_session_last_error
1050 * Returns error code and populates an error string into errmsg
1051 * If want_buf is non-zero then the string placed into errmsg must be freed by the calling program
1052 * Otherwise it is assumed to be owned by libssh2
1053 */
1054 LIBSSH2_API int
1055 libssh2_session_last_error(LIBSSH2_SESSION * session, char **errmsg,
1056 int *errmsg_len, int want_buf)
1057 {
1058 /* No error to report */
1059 if (!session->err_code) {
1060 if (errmsg) {
1061 if (want_buf) {
1062 *errmsg = LIBSSH2_ALLOC(session, 1);
1063 if (*errmsg) {
1064 **errmsg = 0;
1065 }
1066 } else {
1067 *errmsg = (char *) "";
1068 }
1069 }
1070 if (errmsg_len) {
1071 *errmsg_len = 0;
1072 }
1073 return 0;
1074 }
1075
1076 if (errmsg) {
1077 char *serrmsg = session->err_msg ? session->err_msg : (char *) "";
1078 int ownbuf = session->err_msg ? session->err_should_free : 0;
1079
1080 if (want_buf) {
1081 if (ownbuf) {
1082 /* Just give the calling program the buffer */
1083 *errmsg = serrmsg;
1084 session->err_should_free = 0;
1085 } else {
1086 /* Make a copy so the calling program can own it */
1087 *errmsg = LIBSSH2_ALLOC(session, session->err_msglen + 1);
1088 if (*errmsg) {
1089 memcpy(*errmsg, session->err_msg, session->err_msglen);
1090 (*errmsg)[session->err_msglen] = 0;
1091 }
1092 }
1093 } else {
1094 *errmsg = serrmsg;
1095 }
1096 }
1097
1098 if (errmsg_len) {
1099 *errmsg_len = session->err_msglen;
1100 }
1101
1102 return session->err_code;
1103 }
1104
1105 /* }}} */
1106
1107 /* {{{ libssh2_session_last_error
1108 * Returns error code
1109 */
1110 LIBSSH2_API int
1111 libssh2_session_last_errno(LIBSSH2_SESSION * session)
1112 {
1113 return session->err_code;
1114 }
1115
1116 /* }}} */
1117
1118 /* {{{ libssh2_session_flag
1119 * Set/Get session flags
1120 * Passing flag==0 will avoid changing session->flags while still returning its current value
1121 */
1122 LIBSSH2_API int
1123 libssh2_session_flag(LIBSSH2_SESSION * session, int flag, int value)
1124 {
1125 if (value) {
1126 session->flags |= flag;
1127 } else {
1128 session->flags &= ~flag;
1129 }
1130
1131 return session->flags;
1132 }
1133
1134 /* }}} */
1135
1136 /* {{{ _libssh2_session_set_blocking
1137 * Set a session's blocking mode on or off, return the previous status
1138 * when this function is called.
1139 */
1140 int
1141 _libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking)
1142 {
1143 int bl = session->socket_block;
1144 _libssh2_debug(session, LIBSSH2_DBG_CONN,
1145 "Setting blocking mode on session %d", blocking);
1146 if (blocking == session->socket_block) {
1147 /* avoid if already correct */
1148 return bl;
1149 }
1150 session->socket_block = blocking;
1151
1152 _libssh2_nonblock(session->socket_fd, !blocking);
1153
1154 return bl;
1155 }
1156
1157 /* }}} */
1158
1159 /* {{{ libssh2_session_set_blocking
1160 * Set a channel's blocking mode on or off, similar to a socket's
1161 * fcntl(fd, F_SETFL, O_NONBLOCK); type command
1162 */
1163 LIBSSH2_API void
1164 libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking)
1165 {
1166 (void) _libssh2_session_set_blocking(session, blocking);
1167 }
1168
1169 /* }}} */
1170
1171 /* {{{ libssh2_session_get_blocking
1172 * Returns a session's blocking mode on or off
1173 */
1174 LIBSSH2_API int
1175 libssh2_session_get_blocking(LIBSSH2_SESSION * session)
1176 {
1177 return session->socket_block;
1178 }
1179
1180 /* }}} */
1181
1182 /* {{{ libssh2_poll_channel_read
1183 * Returns 0 if no data is waiting on channel,
1184 * non-0 if data is available
1185 */
1186 LIBSSH2_API int
1187 libssh2_poll_channel_read(LIBSSH2_CHANNEL * channel, int extended)
1188 {
1189 LIBSSH2_SESSION *session = channel->session;
1190 LIBSSH2_PACKET *packet = session->packets.head;
1191
1192 while (packet) {
1193 if (((packet->data[0] == SSH_MSG_CHANNEL_DATA) && (extended == 0) &&
1194 (channel->local.id == libssh2_ntohu32(packet->data + 1))) ||
1195 ((packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)
1196 && (extended != 0)
1197 && (channel->local.id == libssh2_ntohu32(packet->data + 1)))) {
1198 /* Found data waiting to be read */
1199 return 1;
1200 }
1201 packet = packet->next;
1202 }
1203
1204 return 0;
1205 }
1206
1207 /* }}} */
1208
1209 /* {{{ libssh2_poll_channel_write
1210 * Returns 0 if writing to channel would block,
1211 * non-0 if data can be written without blocking
1212 */
1213 static inline int
1214 libssh2_poll_channel_write(LIBSSH2_CHANNEL * channel)
1215 {
1216 return channel->local.window_size ? 1 : 0;
1217 }
1218
1219 /* }}} */
1220
1221 /* {{{ libssh2_poll_listener_queued
1222 * Returns 0 if no connections are waiting to be accepted
1223 * non-0 if one or more connections are available
1224 */
1225 static inline int
1226 libssh2_poll_listener_queued(LIBSSH2_LISTENER * listener)
1227 {
1228 return listener->queue ? 1 : 0;
1229 }
1230
1231 /* }}} */
1232
1233 /* {{{ libssh2_poll
1234 * Poll sockets, channels, and listeners for activity
1235 */
1236 LIBSSH2_API int
1237 libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout)
1238 {
1239 long timeout_remaining;
1240 unsigned int i, active_fds;
1241 #ifdef HAVE_POLL
1242 LIBSSH2_SESSION *session = NULL;
1243 #ifdef HAVE_ALLOCA
1244 struct pollfd *sockets = alloca(sizeof(struct pollfd) * nfds);
1245 #else
1246 struct pollfd sockets[256];
1247
1248 if (nfds > 256)
1249 /* systems without alloca use a fixed-size array, this can be fixed
1250 if we really want to, at least if the compiler is a C99 capable one */
1251 return -1;
1252 #endif
1253 /* Setup sockets for polling */
1254 for(i = 0; i < nfds; i++) {
1255 fds[i].revents = 0;
1256 switch (fds[i].type) {
1257 case LIBSSH2_POLLFD_SOCKET:
1258 sockets[i].fd = fds[i].fd.socket;
1259 sockets[i].events = fds[i].events;
1260 sockets[i].revents = 0;
1261 break;
1262
1263 case LIBSSH2_POLLFD_CHANNEL:
1264 sockets[i].fd = fds[i].fd.channel->session->socket_fd;
1265 sockets[i].events = POLLIN;
1266 sockets[i].revents = 0;
1267 if (!session)
1268 session = fds[i].fd.channel->session;
1269 break;
1270
1271 case LIBSSH2_POLLFD_LISTENER:
1272 sockets[i].fd = fds[i].fd.listener->session->socket_fd;
1273 sockets[i].events = POLLIN;
1274 sockets[i].revents = 0;
1275 if (!session)
1276 session = fds[i].fd.listener->session;
1277 break;
1278
1279 default:
1280 if (session)
1281 libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE,
1282 "Invalid descriptor passed to libssh2_poll()",
1283 0);
1284 return -1;
1285 }
1286 }
1287 #elif defined(HAVE_SELECT)
1288 LIBSSH2_SESSION *session = NULL;
1289 int maxfd = 0;
1290 fd_set rfds, wfds;
1291 struct timeval tv;
1292
1293 FD_ZERO(&rfds);
1294 FD_ZERO(&wfds);
1295 for(i = 0; i < nfds; i++) {
1296 fds[i].revents = 0;
1297 switch (fds[i].type) {
1298 case LIBSSH2_POLLFD_SOCKET:
1299 if (fds[i].events & LIBSSH2_POLLFD_POLLIN) {
1300 FD_SET(fds[i].fd.socket, &rfds);
1301 if (fds[i].fd.socket > maxfd)
1302 maxfd = fds[i].fd.socket;
1303 }
1304 if (fds[i].events & LIBSSH2_POLLFD_POLLOUT) {
1305 FD_SET(fds[i].fd.socket, &wfds);
1306 if (fds[i].fd.socket > maxfd)
1307 maxfd = fds[i].fd.socket;
1308 }
1309 break;
1310
1311 case LIBSSH2_POLLFD_CHANNEL:
1312 FD_SET(fds[i].fd.channel->session->socket_fd, &rfds);
1313 if (fds[i].fd.channel->session->socket_fd > maxfd)
1314 maxfd = fds[i].fd.channel->session->socket_fd;
1315 if (!session)
1316 session = fds[i].fd.channel->session;
1317 break;
1318
1319 case LIBSSH2_POLLFD_LISTENER:
1320 FD_SET(fds[i].fd.listener->session->socket_fd, &rfds);
1321 if (fds[i].fd.listener->session->socket_fd > maxfd)
1322 maxfd = fds[i].fd.listener->session->socket_fd;
1323 if (!session)
1324 session = fds[i].fd.listener->session;
1325 break;
1326
1327 default:
1328 if (session)
1329 libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE,
1330 "Invalid descriptor passed to libssh2_poll()",
1331 0);
1332 return -1;
1333 }
1334 }
1335 #else
1336 /* No select() or poll()
1337 * no sockets sturcture to setup
1338 */
1339
1340 timeout = 0;
1341 #endif /* HAVE_POLL or HAVE_SELECT */
1342
1343 timeout_remaining = timeout;
1344 do {
1345 #if defined(HAVE_POLL) || defined(HAVE_SELECT)
1346 int sysret;
1347 #endif
1348
1349 active_fds = 0;
1350
1351 for(i = 0; i < nfds; i++) {
1352 if (fds[i].events != fds[i].revents) {
1353 switch (fds[i].type) {
1354 case LIBSSH2_POLLFD_CHANNEL:
1355 if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) && /* Want to be ready for read */
1356 ((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) { /* Not yet known to be ready for read */
1357 fds[i].revents |=
1358 libssh2_poll_channel_read(fds[i].fd.channel,
1359 0) ?
1360 LIBSSH2_POLLFD_POLLIN : 0;
1361 }
1362 if ((fds[i].events & LIBSSH2_POLLFD_POLLEXT) && /* Want to be ready for extended read */
1363 ((fds[i].revents & LIBSSH2_POLLFD_POLLEXT) == 0)) { /* Not yet known to be ready for extended read */
1364 fds[i].revents |=
1365 libssh2_poll_channel_read(fds[i].fd.channel,
1366 1) ?
1367 LIBSSH2_POLLFD_POLLEXT : 0;
1368 }
1369 if ((fds[i].events & LIBSSH2_POLLFD_POLLOUT) && /* Want to be ready for write */
1370 ((fds[i].revents & LIBSSH2_POLLFD_POLLOUT) == 0)) { /* Not yet known to be ready for write */
1371 fds[i].revents |=
1372 libssh2_poll_channel_write(fds[i].fd.
1373 channel) ?
1374 LIBSSH2_POLLFD_POLLOUT : 0;
1375 }
1376 if (fds[i].fd.channel->remote.close
1377 || fds[i].fd.channel->local.close) {
1378 fds[i].revents |= LIBSSH2_POLLFD_CHANNEL_CLOSED;
1379 }
1380 if (fds[i].fd.channel->session->socket_state ==
1381 LIBSSH2_SOCKET_DISCONNECTED) {
1382 fds[i].revents |=
1383 LIBSSH2_POLLFD_CHANNEL_CLOSED |
1384 LIBSSH2_POLLFD_SESSION_CLOSED;
1385 }
1386 break;
1387
1388 case LIBSSH2_POLLFD_LISTENER:
1389 if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) && /* Want a connection */
1390 ((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) { /* No connections known of yet */
1391 fds[i].revents |=
1392 libssh2_poll_listener_queued(fds[i].fd.
1393 listener) ?
1394 LIBSSH2_POLLFD_POLLIN : 0;
1395 }
1396 if (fds[i].fd.listener->session->socket_state ==
1397 LIBSSH2_SOCKET_DISCONNECTED) {
1398 fds[i].revents |=
1399 LIBSSH2_POLLFD_LISTENER_CLOSED |
1400 LIBSSH2_POLLFD_SESSION_CLOSED;
1401 }
1402 break;
1403 }
1404 }
1405 if (fds[i].revents) {
1406 active_fds++;
1407 }
1408 }
1409
1410 if (active_fds) {
1411 /* Don't block on the sockets if we have channels/listeners which are ready */
1412 timeout_remaining = 0;
1413 }
1414 #ifdef HAVE_POLL
1415
1416 #ifdef HAVE_GETTIMEOFDAY
1417 {
1418 struct timeval tv_begin, tv_end;
1419
1420 gettimeofday((struct timeval *) &tv_begin, NULL);
1421 sysret = poll(sockets, nfds, timeout_remaining);
1422 gettimeofday((struct timeval *) &tv_end, NULL);
1423 timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000;
1424 timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000;
1425 }
1426 #else
1427 /* If the platform doesn't support gettimeofday,
1428 * then just make the call non-blocking and walk away
1429 */
1430 sysret = poll(sockets, nfds, timeout_remaining);
1431 timeout_remaining = 0;
1432 #endif /* HAVE_GETTIMEOFDAY */
1433
1434 if (sysret > 0) {
1435 for(i = 0; i < nfds; i++) {
1436 switch (fds[i].type) {
1437 case LIBSSH2_POLLFD_SOCKET:
1438 fds[i].revents = sockets[i].revents;
1439 sockets[i].revents = 0; /* In case we loop again, be nice */
1440 if (fds[i].revents) {
1441 active_fds++;
1442 }
1443 break;
1444 case LIBSSH2_POLLFD_CHANNEL:
1445 if (sockets[i].events & POLLIN) {
1446 /* Spin session until no data available */
1447 while (libssh2_packet_read(fds[i].fd.channel->session)
1448 > 0);
1449 }
1450 if (sockets[i].revents & POLLHUP) {
1451 fds[i].revents |=
1452 LIBSSH2_POLLFD_CHANNEL_CLOSED |
1453 LIBSSH2_POLLFD_SESSION_CLOSED;
1454 }
1455 sockets[i].revents = 0;
1456 break;
1457 case LIBSSH2_POLLFD_LISTENER:
1458 if (sockets[i].events & POLLIN) {
1459 /* Spin session until no data available */
1460 while (libssh2_packet_read(fds[i].fd.listener->session)
1461 > 0);
1462 }
1463 if (sockets[i].revents & POLLHUP) {
1464 fds[i].revents |=
1465 LIBSSH2_POLLFD_LISTENER_CLOSED |
1466 LIBSSH2_POLLFD_SESSION_CLOSED;
1467 }
1468 sockets[i].revents = 0;
1469 break;
1470 }
1471 }
1472 }
1473 #elif defined(HAVE_SELECT)
1474 tv.tv_sec = timeout_remaining / 1000;
1475 tv.tv_usec = (timeout_remaining % 1000) * 1000;
1476 #ifdef HAVE_GETTIMEOFDAY
1477 {
1478 struct timeval tv_begin, tv_end;
1479
1480 gettimeofday((struct timeval *) &tv_begin, NULL);
1481 sysret = select(maxfd, &rfds, &wfds, NULL, &tv);
1482 gettimeofday((struct timeval *) &tv_end, NULL);
1483
1484 timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000;
1485 timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000;
1486 }
1487 #else
1488 /* If the platform doesn't support gettimeofday,
1489 * then just make the call non-blocking and walk away
1490 */
1491 sysret = select(maxfd, &rfds, &wfds, NULL, &tv);
1492 timeout_remaining = 0;
1493 #endif
1494
1495 if (sysret > 0) {
1496 for(i = 0; i < nfds; i++) {
1497 switch (fds[i].type) {
1498 case LIBSSH2_POLLFD_SOCKET:
1499 if (FD_ISSET(fds[i].fd.socket, &rfds)) {
1500 fds[i].revents |= LIBSSH2_POLLFD_POLLIN;
1501 }
1502 if (FD_ISSET(fds[i].fd.socket, &wfds)) {
1503 fds[i].revents |= LIBSSH2_POLLFD_POLLOUT;
1504 }
1505 if (fds[i].revents) {
1506 active_fds++;
1507 }
1508 break;
1509
1510 case LIBSSH2_POLLFD_CHANNEL:
1511 if (FD_ISSET(fds[i].fd.channel->session->socket_fd, &rfds)) {
1512 /* Spin session until no data available */
1513 while (libssh2_packet_read(fds[i].fd.channel->session)
1514 > 0);
1515 }
1516 break;
1517
1518 case LIBSSH2_POLLFD_LISTENER:
1519 if (FD_ISSET
1520 (fds[i].fd.listener->session->socket_fd, &rfds)) {
1521 /* Spin session until no data available */
1522 while (libssh2_packet_read(fds[i].fd.listener->session)
1523 > 0);
1524 }
1525 break;
1526 }
1527 }
1528 }
1529 #endif /* else no select() or poll() -- timeout (and by extension timeout_remaining) will be equal to 0 */
1530 } while ((timeout_remaining > 0) && !active_fds);
1531
1532 return active_fds;
1533 }
1534
1535 /* }}} */