We now build libssh2 in Xcode and it's a much better UB/10.4 citizen
[printdrop.git] / Vendor / libssh2 / Source / channel.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 #ifdef HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42 #include <fcntl.h>
43 #ifdef HAVE_INTTYPES_H
44 #include <inttypes.h>
45 #endif
46
47
48 /* {{{ libssh2_channel_nextid
49 * Determine the next channel ID we can use at our end
50 */
51 unsigned long
52 libssh2_channel_nextid(LIBSSH2_SESSION * session)
53 {
54 unsigned long id = session->next_channel;
55 LIBSSH2_CHANNEL *channel;
56
57 channel = session->channels.head;
58
59 while (channel) {
60 if (channel->local.id > id) {
61 id = channel->local.id;
62 }
63 channel = channel->next;
64 }
65
66 /* This is a shortcut to avoid waiting for close packets on channels we've forgotten about,
67 * This *could* be a problem if we request and close 4 billion or so channels in too rapid succession
68 * for the remote end to respond, but the worst case scenario is that some data meant for another channel
69 * Gets picked up by the new one.... Pretty unlikely all told...
70 */
71 session->next_channel = id + 1;
72 _libssh2_debug(session, LIBSSH2_DBG_CONN, "Allocated new channel ID#%lu",
73 id);
74 return id;
75 }
76
77 /* }}} */
78
79 /* {{{ libssh2_channel_locate
80 * Locate a channel pointer by number
81 */
82 LIBSSH2_CHANNEL *
83 libssh2_channel_locate(LIBSSH2_SESSION * session, unsigned long channel_id)
84 {
85 LIBSSH2_CHANNEL *channel = session->channels.head;
86 while (channel) {
87 if (channel->local.id == channel_id) {
88 return channel;
89 }
90 channel = channel->next;
91 }
92
93 return NULL;
94 }
95
96 /* }}} */
97
98 #define libssh2_channel_add(session, channel) \
99 { \
100 if ((session)->channels.tail) { \
101 (session)->channels.tail->next = (channel); \
102 (channel)->prev = (session)->channels.tail; \
103 } else { \
104 (session)->channels.head = (channel); \
105 (channel)->prev = NULL; \
106 } \
107 (channel)->next = NULL; \
108 (session)->channels.tail = (channel); \
109 (channel)->session = (session); \
110 }
111
112 /* {{{ libssh2_channel_open_ex
113 * Establish a generic session channel
114 */
115 LIBSSH2_API LIBSSH2_CHANNEL *
116 libssh2_channel_open_ex(LIBSSH2_SESSION * session, const char *channel_type,
117 unsigned int channel_type_len,
118 unsigned int window_size, unsigned int packet_size,
119 const char *message, unsigned int message_len)
120 {
121 static const unsigned char reply_codes[3] = {
122 SSH_MSG_CHANNEL_OPEN_CONFIRMATION,
123 SSH_MSG_CHANNEL_OPEN_FAILURE,
124 0
125 };
126 unsigned char *s;
127 int rc;
128
129 if (session->open_state == libssh2_NB_state_idle) {
130 session->open_channel = NULL;
131 session->open_packet = NULL;
132 session->open_data = NULL;
133 /* 17 = packet_type(1) + channel_type_len(4) + sender_channel(4) + window_size(4) + packet_size(4) */
134 session->open_packet_len = channel_type_len + message_len + 17;
135 session->open_local_channel = libssh2_channel_nextid(session);
136
137 /* Zero the whole thing out */
138 memset(&session->open_packet_requirev_state, 0,
139 sizeof(session->open_packet_requirev_state));
140
141 _libssh2_debug(session, LIBSSH2_DBG_CONN,
142 "Opening Channel - win %d pack %d", window_size,
143 packet_size);
144 session->open_channel =
145 LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
146 if (!session->open_channel) {
147 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
148 "Unable to allocate space for channel data", 0);
149 return NULL;
150 }
151 memset(session->open_channel, 0, sizeof(LIBSSH2_CHANNEL));
152
153 session->open_channel->channel_type_len = channel_type_len;
154 session->open_channel->channel_type =
155 LIBSSH2_ALLOC(session, channel_type_len);
156 if (!session->open_channel->channel_type) {
157 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
158 "Failed allocating memory for channel type name", 0);
159 LIBSSH2_FREE(session, session->open_channel);
160 session->open_channel = NULL;
161 return NULL;
162 }
163 memcpy(session->open_channel->channel_type, channel_type,
164 channel_type_len);
165
166 /* REMEMBER: local as in locally sourced */
167 session->open_channel->local.id = session->open_local_channel;
168 session->open_channel->remote.window_size = window_size;
169 session->open_channel->remote.window_size_initial = window_size;
170 session->open_channel->remote.packet_size = packet_size;
171
172 libssh2_channel_add(session, session->open_channel);
173
174 s = session->open_packet =
175 LIBSSH2_ALLOC(session, session->open_packet_len);
176 if (!session->open_packet) {
177 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
178 "Unable to allocate temporary space for packet", 0);
179 goto channel_error;
180 }
181 *(s++) = SSH_MSG_CHANNEL_OPEN;
182 libssh2_htonu32(s, channel_type_len);
183 s += 4;
184
185 memcpy(s, channel_type, channel_type_len);
186 s += channel_type_len;
187
188 libssh2_htonu32(s, session->open_local_channel);
189 s += 4;
190
191 libssh2_htonu32(s, window_size);
192 s += 4;
193
194 libssh2_htonu32(s, packet_size);
195 s += 4;
196
197 if (message && message_len) {
198 memcpy(s, message, message_len);
199 s += message_len;
200 }
201
202 session->open_state = libssh2_NB_state_created;
203 }
204
205 if (session->open_state == libssh2_NB_state_created) {
206 rc = libssh2_packet_write(session, session->open_packet,
207 session->open_packet_len);
208 if (rc == PACKET_EAGAIN) {
209 libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
210 "Would block sending channel-open request", 0);
211 return NULL;
212 } else if (rc) {
213 libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
214 "Unable to send channel-open request", 0);
215 goto channel_error;
216 }
217
218 session->open_state = libssh2_NB_state_sent;
219 }
220
221 if (session->open_state == libssh2_NB_state_sent) {
222 rc = libssh2_packet_requirev_ex(session, reply_codes,
223 &session->open_data,
224 &session->open_data_len, 1,
225 session->open_packet + 5 +
226 channel_type_len, 4,
227 &session->open_packet_requirev_state);
228 if (rc == PACKET_EAGAIN) {
229 libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block", 0);
230 return NULL;
231 } else if (rc) {
232 goto channel_error;
233 }
234
235 if (session->open_data[0] == SSH_MSG_CHANNEL_OPEN_CONFIRMATION) {
236 session->open_channel->remote.id =
237 libssh2_ntohu32(session->open_data + 5);
238 session->open_channel->local.window_size =
239 libssh2_ntohu32(session->open_data + 9);
240 session->open_channel->local.window_size_initial =
241 libssh2_ntohu32(session->open_data + 9);
242 session->open_channel->local.packet_size =
243 libssh2_ntohu32(session->open_data + 13);
244 _libssh2_debug(session, LIBSSH2_DBG_CONN,
245 "Connection Established - ID: %lu/%lu win: %lu/%lu pack: %lu/%lu",
246 session->open_channel->local.id,
247 session->open_channel->remote.id,
248 session->open_channel->local.window_size,
249 session->open_channel->remote.window_size,
250 session->open_channel->local.packet_size,
251 session->open_channel->remote.packet_size);
252 LIBSSH2_FREE(session, session->open_packet);
253 session->open_packet = NULL;
254 LIBSSH2_FREE(session, session->open_data);
255 session->open_data = NULL;
256
257 session->open_state = libssh2_NB_state_idle;
258 return session->open_channel;
259 }
260
261 if (session->open_data[0] == SSH_MSG_CHANNEL_OPEN_FAILURE) {
262 libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
263 "Channel open failure", 0);
264 }
265 }
266
267 channel_error:
268
269 if (session->open_data) {
270 LIBSSH2_FREE(session, session->open_data);
271 session->open_data = NULL;
272 }
273 if (session->open_packet) {
274 LIBSSH2_FREE(session, session->open_packet);
275 session->open_packet = NULL;
276 }
277 if (session->open_channel) {
278 unsigned char channel_id[4];
279 LIBSSH2_FREE(session, session->open_channel->channel_type);
280
281 if (session->open_channel->next) {
282 session->open_channel->next->prev = session->open_channel->prev;
283 }
284 if (session->open_channel->prev) {
285 session->open_channel->prev->next = session->open_channel->next;
286 }
287 if (session->channels.head == session->open_channel) {
288 session->channels.head = session->open_channel->next;
289 }
290 if (session->channels.tail == session->open_channel) {
291 session->channels.tail = session->open_channel->prev;
292 }
293
294 /* Clear out packets meant for this channel */
295 libssh2_htonu32(channel_id, session->open_channel->local.id);
296 while ((libssh2_packet_ask_ex
297 (session, SSH_MSG_CHANNEL_DATA, &session->open_data,
298 &session->open_data_len, 1, channel_id, 4, 0) >= 0)
299 ||
300 (libssh2_packet_ask_ex
301 (session, SSH_MSG_CHANNEL_EXTENDED_DATA, &session->open_data,
302 &session->open_data_len, 1, channel_id, 4, 0) >= 0)) {
303 LIBSSH2_FREE(session, session->open_data);
304 session->open_data = NULL;
305 }
306
307 /* Free any state variables still holding data */
308 if (session->open_channel->write_packet) {
309 LIBSSH2_FREE(session, session->open_channel->write_packet);
310 session->open_channel->write_packet = NULL;
311 }
312
313 LIBSSH2_FREE(session, session->open_channel);
314 session->open_channel = NULL;
315 }
316
317 session->open_state = libssh2_NB_state_idle;
318 return NULL;
319 }
320
321 /* }}} */
322
323 /* {{{ libssh2_channel_direct_tcpip_ex
324 * Tunnel TCP/IP connect through the SSH session to direct host/port
325 */
326 LIBSSH2_API LIBSSH2_CHANNEL *
327 libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION * session, const char *host,
328 int port, const char *shost, int sport)
329 {
330 LIBSSH2_CHANNEL *channel;
331 unsigned char *s;
332
333 if (session->direct_state == libssh2_NB_state_idle) {
334 session->direct_host_len = strlen(host);
335 session->direct_shost_len = strlen(shost);
336 /* host_len(4) + port(4) + shost_len(4) + sport(4) */
337 session->direct_message_len =
338 session->direct_host_len + session->direct_shost_len + 16;
339
340 _libssh2_debug(session, LIBSSH2_DBG_CONN,
341 "Requesting direct-tcpip session to from %s:%d to %s:%d",
342 shost, sport, host, port);
343
344 s = session->direct_message =
345 LIBSSH2_ALLOC(session, session->direct_message_len);
346 if (!session->direct_message) {
347 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
348 "Unable to allocate memory for direct-tcpip connection",
349 0);
350 return NULL;
351 }
352 libssh2_htonu32(s, session->direct_host_len);
353 s += 4;
354 memcpy(s, host, session->direct_host_len);
355 s += session->direct_host_len;
356 libssh2_htonu32(s, port);
357 s += 4;
358
359 libssh2_htonu32(s, session->direct_shost_len);
360 s += 4;
361 memcpy(s, shost, session->direct_shost_len);
362 s += session->direct_shost_len;
363 libssh2_htonu32(s, sport);
364 s += 4;
365
366 session->direct_state = libssh2_NB_state_created;
367 }
368
369 channel =
370 libssh2_channel_open_ex(session, "direct-tcpip",
371 sizeof("direct-tcpip") - 1,
372 LIBSSH2_CHANNEL_WINDOW_DEFAULT,
373 LIBSSH2_CHANNEL_PACKET_DEFAULT,
374 (char *) session->direct_message,
375 session->direct_message_len);
376 if (!channel) {
377 if (libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) {
378 /* The error code is still set to LIBSSH2_ERROR_EAGAIN */
379 return NULL;
380 } else {
381 LIBSSH2_FREE(session, session->direct_message);
382 session->direct_message = NULL;
383 return NULL;
384 }
385 }
386
387 LIBSSH2_FREE(session, session->direct_message);
388 session->direct_message = NULL;
389
390 return channel;
391 }
392
393 /* }}} */
394
395 /* {{{ libssh2_channel_forward_listen_ex
396 * Bind a port on the remote host and listen for connections
397 */
398 LIBSSH2_API LIBSSH2_LISTENER *
399 libssh2_channel_forward_listen_ex(LIBSSH2_SESSION * session, const char *host,
400 int port, int *bound_port, int queue_maxsize)
401 {
402 unsigned char *s, *data;
403 static const unsigned char reply_codes[3] =
404 { SSH_MSG_REQUEST_SUCCESS, SSH_MSG_REQUEST_FAILURE, 0 };
405 unsigned long data_len;
406 int rc;
407
408 if (session->fwdLstn_state == libssh2_NB_state_idle) {
409 session->fwdLstn_host_len =
410 (host ? strlen(host) : (sizeof("0.0.0.0") - 1));
411 /* 14 = packet_type(1) + request_len(4) + want_replay(1) + host_len(4) + port(4) */
412 session->fwdLstn_packet_len =
413 session->fwdLstn_host_len + (sizeof("tcpip-forward") - 1) + 14;
414
415 /* Zero the whole thing out */
416 memset(&session->fwdLstn_packet_requirev_state, 0,
417 sizeof(session->fwdLstn_packet_requirev_state));
418
419 _libssh2_debug(session, LIBSSH2_DBG_CONN,
420 "Requesting tcpip-forward session for %s:%d", host,
421 port);
422
423 s = session->fwdLstn_packet =
424 LIBSSH2_ALLOC(session, session->fwdLstn_packet_len);
425 if (!session->fwdLstn_packet) {
426 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
427 "Unable to allocate memeory for setenv packet", 0);
428 return NULL;
429 }
430
431 *(s++) = SSH_MSG_GLOBAL_REQUEST;
432 libssh2_htonu32(s, sizeof("tcpip-forward") - 1);
433 s += 4;
434 memcpy(s, "tcpip-forward", sizeof("tcpip-forward") - 1);
435 s += sizeof("tcpip-forward") - 1;
436 *(s++) = 0x01; /* want_reply */
437
438 libssh2_htonu32(s, session->fwdLstn_host_len);
439 s += 4;
440 memcpy(s, host ? host : "0.0.0.0", session->fwdLstn_host_len);
441 s += session->fwdLstn_host_len;
442 libssh2_htonu32(s, port);
443 s += 4;
444
445 session->fwdLstn_state = libssh2_NB_state_created;
446 }
447
448 if (session->fwdLstn_state == libssh2_NB_state_created) {
449 rc = libssh2_packet_write(session, session->fwdLstn_packet,
450 session->fwdLstn_packet_len);
451 if (rc == PACKET_EAGAIN) {
452 libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
453 "Would block sending global-request packet for forward listen request",
454 0);
455 return NULL;
456 } else if (rc) {
457 libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
458 "Unable to send global-request packet for forward listen request",
459 0);
460 LIBSSH2_FREE(session, session->fwdLstn_packet);
461 session->fwdLstn_packet = NULL;
462 session->fwdLstn_state = libssh2_NB_state_idle;
463 return NULL;
464 }
465 LIBSSH2_FREE(session, session->fwdLstn_packet);
466 session->fwdLstn_packet = NULL;
467
468 session->fwdLstn_state = libssh2_NB_state_sent;
469 }
470
471 if (session->fwdLstn_state == libssh2_NB_state_sent) {
472 rc = libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len,
473 0, NULL, 0,
474 &session->
475 fwdLstn_packet_requirev_state);
476 if (rc == PACKET_EAGAIN) {
477 libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block", 0);
478 return NULL;
479 } else if (rc) {
480 libssh2_error(session, LIBSSH2_ERROR_PROTO, "Unknown", 0);
481 session->fwdLstn_state = libssh2_NB_state_idle;
482 return NULL;
483 }
484
485 if (data[0] == SSH_MSG_REQUEST_SUCCESS) {
486 LIBSSH2_LISTENER *listener;
487
488 listener = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_LISTENER));
489 if (!listener) {
490 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
491 "Unable to allocate memory for listener queue",
492 0);
493 LIBSSH2_FREE(session, data);
494 session->fwdLstn_state = libssh2_NB_state_idle;
495 return NULL;
496 }
497 memset(listener, 0, sizeof(LIBSSH2_LISTENER));
498 listener->session = session;
499 listener->host =
500 LIBSSH2_ALLOC(session, session->fwdLstn_host_len + 1);
501 if (!listener->host) {
502 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
503 "Unable to allocate memory for listener queue",
504 0);
505 LIBSSH2_FREE(session, listener);
506 LIBSSH2_FREE(session, data);
507 session->fwdLstn_state = libssh2_NB_state_idle;
508 return NULL;
509 }
510 memcpy(listener->host, host ? host : "0.0.0.0",
511 session->fwdLstn_host_len);
512 listener->host[session->fwdLstn_host_len] = 0;
513 if (data_len >= 5 && !port) {
514 listener->port = libssh2_ntohu32(data + 1);
515 _libssh2_debug(session, LIBSSH2_DBG_CONN,
516 "Dynamic tcpip-forward port allocated: %d",
517 listener->port);
518 } else {
519 listener->port = port;
520 }
521
522 listener->queue_size = 0;
523 listener->queue_maxsize = queue_maxsize;
524
525 listener->next = session->listeners;
526 listener->prev = NULL;
527 if (session->listeners) {
528 session->listeners->prev = listener;
529 }
530 session->listeners = listener;
531
532 if (bound_port) {
533 *bound_port = listener->port;
534 }
535
536 LIBSSH2_FREE(session, data);
537 session->fwdLstn_state = libssh2_NB_state_idle;
538 return listener;
539 }
540
541 if (data[0] == SSH_MSG_REQUEST_FAILURE) {
542 LIBSSH2_FREE(session, data);
543 libssh2_error(session, LIBSSH2_ERROR_REQUEST_DENIED,
544 "Unable to complete request for forward-listen", 0);
545 session->fwdLstn_state = libssh2_NB_state_idle;
546 return NULL;
547 }
548 }
549
550 session->fwdLstn_state = libssh2_NB_state_idle;
551
552 return NULL;
553 }
554
555 /* }}} */
556
557 /* {{{ libssh2_channel_forward_cancel
558 * Stop listening on a remote port and free the listener
559 * Toss out any pending (un-accept()ed) connections
560 *
561 * Return 0 on success, PACKET_EAGAIN if would block, -1 on error
562 */
563 LIBSSH2_API int
564 libssh2_channel_forward_cancel(LIBSSH2_LISTENER * listener)
565 {
566 LIBSSH2_SESSION *session = listener->session;
567 LIBSSH2_CHANNEL *queued = listener->queue;
568 unsigned char *packet, *s;
569 unsigned long host_len = strlen(listener->host);
570 /* 14 = packet_type(1) + request_len(4) + want_replay(1) + host_len(4) + port(4) */
571 unsigned long packet_len =
572 host_len + 14 + sizeof("cancel-tcpip-forward") - 1;
573 int rc;
574
575 if (listener->chanFwdCncl_state == libssh2_NB_state_idle) {
576 _libssh2_debug(session, LIBSSH2_DBG_CONN,
577 "Cancelling tcpip-forward session for %s:%d",
578 listener->host, listener->port);
579
580 s = packet = LIBSSH2_ALLOC(session, packet_len);
581 if (!packet) {
582 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
583 "Unable to allocate memeory for setenv packet", 0);
584 return -1;
585 }
586
587 *(s++) = SSH_MSG_GLOBAL_REQUEST;
588 libssh2_htonu32(s, sizeof("cancel-tcpip-forward") - 1);
589 s += 4;
590 memcpy(s, "cancel-tcpip-forward", sizeof("cancel-tcpip-forward") - 1);
591 s += sizeof("cancel-tcpip-forward") - 1;
592 *(s++) = 0x00; /* want_reply */
593
594 libssh2_htonu32(s, host_len);
595 s += 4;
596 memcpy(s, listener->host, host_len);
597 s += host_len;
598 libssh2_htonu32(s, listener->port);
599 s += 4;
600
601 listener->chanFwdCncl_state = libssh2_NB_state_created;
602 } else {
603 packet = listener->chanFwdCncl_data;
604 }
605
606 if (listener->chanFwdCncl_state == libssh2_NB_state_created) {
607 rc = libssh2_packet_write(session, packet, packet_len);
608 if (rc == PACKET_EAGAIN) {
609 listener->chanFwdCncl_data = packet;
610 } else if (rc) {
611 libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
612 "Unable to send global-request packet for forward listen request",
613 0);
614 LIBSSH2_FREE(session, packet);
615 listener->chanFwdCncl_state = libssh2_NB_state_idle;
616 return -1;
617 }
618 LIBSSH2_FREE(session, packet);
619
620 listener->chanFwdCncl_state = libssh2_NB_state_sent;
621 }
622
623 while (queued) {
624 LIBSSH2_CHANNEL *next = queued->next;
625
626 rc = libssh2_channel_free(queued);
627 if (rc == PACKET_EAGAIN) {
628 return PACKET_EAGAIN;
629 }
630 queued = next;
631 }
632 LIBSSH2_FREE(session, listener->host);
633
634 if (listener->next) {
635 listener->next->prev = listener->prev;
636 }
637 if (listener->prev) {
638 listener->prev->next = listener->next;
639 } else {
640 session->listeners = listener->next;
641 }
642
643 LIBSSH2_FREE(session, listener);
644
645 listener->chanFwdCncl_state = libssh2_NB_state_idle;
646
647 return 0;
648 }
649
650 /* }}} */
651
652 /* {{{ libssh2_channel_forward_accept
653 * Accept a connection
654 */
655 LIBSSH2_API LIBSSH2_CHANNEL *
656 libssh2_channel_forward_accept(LIBSSH2_LISTENER * listener)
657 {
658 libssh2pack_t rc;
659
660 do {
661 rc = libssh2_packet_read(listener->session);
662 if (rc == PACKET_EAGAIN) {
663 libssh2_error(listener->session, LIBSSH2_ERROR_EAGAIN,
664 "Would block waiting for packet", 0);
665 return NULL;
666 }
667 } while (rc > 0);
668
669 if (listener->queue) {
670 LIBSSH2_SESSION *session = listener->session;
671 LIBSSH2_CHANNEL *channel;
672
673 channel = listener->queue;
674
675 listener->queue = listener->queue->next;
676 if (listener->queue) {
677 listener->queue->prev = NULL;
678 }
679
680 channel->prev = NULL;
681 channel->next = session->channels.head;
682 session->channels.head = channel;
683
684 if (channel->next) {
685 channel->next->prev = channel;
686 } else {
687 session->channels.tail = channel;
688 }
689 listener->queue_size--;
690
691 return channel;
692 }
693
694 return NULL;
695 }
696
697 /* }}} */
698
699 /* {{{ libssh2_channel_setenv_ex
700 * Set an environment variable prior to requesting a shell/program/subsystem
701 */
702 LIBSSH2_API int
703 libssh2_channel_setenv_ex(LIBSSH2_CHANNEL * channel, const char *varname,
704 unsigned int varname_len, const char *value,
705 unsigned int value_len)
706 {
707 LIBSSH2_SESSION *session = channel->session;
708 unsigned char *s, *data;
709 static const unsigned char reply_codes[3] =
710 { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 };
711 unsigned long data_len;
712 int rc;
713
714 if (channel->setenv_state == libssh2_NB_state_idle) {
715 /* 21 = packet_type(1) + channel_id(4) + request_len(4) +
716 * request(3)"env" + want_reply(1) + varname_len(4) + value_len(4) */
717 channel->setenv_packet_len = varname_len + value_len + 21;
718
719 /* Zero the whole thing out */
720 memset(&channel->setenv_packet_requirev_state, 0,
721 sizeof(channel->setenv_packet_requirev_state));
722
723 _libssh2_debug(session, LIBSSH2_DBG_CONN,
724 "Setting remote environment variable: %s=%s on channel %lu/%lu",
725 varname, value, channel->local.id, channel->remote.id);
726
727 s = channel->setenv_packet =
728 LIBSSH2_ALLOC(session, channel->setenv_packet_len);
729 if (!channel->setenv_packet) {
730 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
731 "Unable to allocate memeory for setenv packet", 0);
732 return -1;
733 }
734
735 *(s++) = SSH_MSG_CHANNEL_REQUEST;
736 libssh2_htonu32(s, channel->remote.id);
737 s += 4;
738 libssh2_htonu32(s, sizeof("env") - 1);
739 s += 4;
740 memcpy(s, "env", sizeof("env") - 1);
741 s += sizeof("env") - 1;
742
743 *(s++) = 0x01;
744
745 libssh2_htonu32(s, varname_len);
746 s += 4;
747 memcpy(s, varname, varname_len);
748 s += varname_len;
749
750 libssh2_htonu32(s, value_len);
751 s += 4;
752 memcpy(s, value, value_len);
753 s += value_len;
754
755 channel->setenv_state = libssh2_NB_state_created;
756 }
757
758 if (channel->setenv_state == libssh2_NB_state_created) {
759 rc = libssh2_packet_write(session, channel->setenv_packet,
760 channel->setenv_packet_len);
761 if (rc == PACKET_EAGAIN) {
762 return PACKET_EAGAIN;
763 } else if (rc) {
764 libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
765 "Unable to send channel-request packet for setenv request",
766 0);
767 LIBSSH2_FREE(session, channel->setenv_packet);
768 channel->setenv_packet = NULL;
769 channel->setenv_state = libssh2_NB_state_idle;
770 return -1;
771 }
772 LIBSSH2_FREE(session, channel->setenv_packet);
773 channel->setenv_packet = NULL;
774
775 libssh2_htonu32(channel->setenv_local_channel, channel->local.id);
776
777 channel->setenv_state = libssh2_NB_state_sent;
778 }
779
780 if (channel->setenv_state == libssh2_NB_state_sent) {
781 rc = libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len,
782 1, channel->setenv_local_channel, 4,
783 &channel->
784 setenv_packet_requirev_state);
785 if (rc == PACKET_EAGAIN) {
786 return PACKET_EAGAIN;
787 }
788 if (rc) {
789 channel->setenv_state = libssh2_NB_state_idle;
790 return -1;
791 }
792
793 if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
794 LIBSSH2_FREE(session, data);
795 channel->setenv_state = libssh2_NB_state_idle;
796 return 0;
797 }
798
799 LIBSSH2_FREE(session, data);
800 }
801
802 libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED,
803 "Unable to complete request for channel-setenv", 0);
804 channel->setenv_state = libssh2_NB_state_idle;
805 return -1;
806 }
807
808 /* }}} */
809
810 /* {{{ libssh2_channel_request_pty_ex
811 * Duh... Request a PTY
812 */
813 LIBSSH2_API int
814 libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL * channel, const char *term,
815 unsigned int term_len, const char *modes,
816 unsigned int modes_len, int width, int height,
817 int width_px, int height_px)
818 {
819 LIBSSH2_SESSION *session = channel->session;
820 unsigned char *s, *data;
821 static const unsigned char reply_codes[3] =
822 { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 };
823 unsigned long data_len;
824 int rc;
825
826 if (channel->reqPTY_state == libssh2_NB_state_idle) {
827 /* 41 = packet_type(1) + channel(4) + pty_req_len(4) + "pty_req"(7) +
828 * want_reply(1) + term_len(4) + width(4) + height(4) + width_px(4) +
829 * height_px(4) + modes_len(4) */
830 channel->reqPTY_packet_len = term_len + modes_len + 41;
831
832 /* Zero the whole thing out */
833 memset(&channel->reqPTY_packet_requirev_state, 0,
834 sizeof(channel->reqPTY_packet_requirev_state));
835
836 _libssh2_debug(session, LIBSSH2_DBG_CONN,
837 "Allocating tty on channel %lu/%lu", channel->local.id,
838 channel->remote.id);
839
840 s = channel->reqPTY_packet =
841 LIBSSH2_ALLOC(session, channel->reqPTY_packet_len);
842 if (!channel->reqPTY_packet) {
843 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
844 "Unable to allocate memory for pty-request", 0);
845 return -1;
846 }
847
848 *(s++) = SSH_MSG_CHANNEL_REQUEST;
849 libssh2_htonu32(s, channel->remote.id);
850 s += 4;
851 libssh2_htonu32(s, sizeof("pty-req") - 1);
852 s += 4;
853 memcpy(s, "pty-req", sizeof("pty-req") - 1);
854 s += sizeof("pty-req") - 1;
855
856 *(s++) = 0x01;
857
858 libssh2_htonu32(s, term_len);
859 s += 4;
860 if (term) {
861 memcpy(s, term, term_len);
862 s += term_len;
863 }
864
865 libssh2_htonu32(s, width);
866 s += 4;
867 libssh2_htonu32(s, height);
868 s += 4;
869 libssh2_htonu32(s, width_px);
870 s += 4;
871 libssh2_htonu32(s, height_px);
872 s += 4;
873
874 libssh2_htonu32(s, modes_len);
875 s += 4;
876 if (modes) {
877 memcpy(s, modes, modes_len);
878 s += modes_len;
879 }
880
881 channel->reqPTY_state = libssh2_NB_state_created;
882 }
883
884 if (channel->reqPTY_state == libssh2_NB_state_created) {
885 rc = libssh2_packet_write(session, channel->reqPTY_packet,
886 channel->reqPTY_packet_len);
887 if (rc == PACKET_EAGAIN) {
888 return PACKET_EAGAIN;
889 } else if (rc) {
890 libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
891 "Unable to send pty-request packet", 0);
892 LIBSSH2_FREE(session, channel->reqPTY_packet);
893 channel->reqPTY_packet = NULL;
894 channel->reqPTY_state = libssh2_NB_state_idle;
895 return -1;
896 }
897 LIBSSH2_FREE(session, channel->reqPTY_packet);
898 channel->reqPTY_packet = NULL;
899
900 libssh2_htonu32(channel->reqPTY_local_channel, channel->local.id);
901
902 channel->reqPTY_state = libssh2_NB_state_sent;
903 }
904
905 if (channel->reqPTY_state == libssh2_NB_state_sent) {
906 rc = libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len,
907 1, channel->reqPTY_local_channel, 4,
908 &channel->
909 reqPTY_packet_requirev_state);
910 if (rc == PACKET_EAGAIN) {
911 return PACKET_EAGAIN;
912 } else if (rc) {
913 channel->reqPTY_state = libssh2_NB_state_idle;
914 return -1;
915 }
916
917 if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
918 LIBSSH2_FREE(session, data);
919 channel->reqPTY_state = libssh2_NB_state_idle;
920 return 0;
921 }
922 }
923
924 LIBSSH2_FREE(session, data);
925 libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED,
926 "Unable to complete request for channel request-pty", 0);
927 channel->reqPTY_state = libssh2_NB_state_idle;
928 return -1;
929 }
930
931 /* }}} */
932
933 /* Keep this an even number */
934 #define LIBSSH2_X11_RANDOM_COOKIE_LEN 32
935
936 /* {{{ libssh2_channel_x11_req_ex
937 * Request X11 forwarding
938 */
939 LIBSSH2_API int
940 libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL * channel, int single_connection,
941 const char *auth_proto, const char *auth_cookie,
942 int screen_number)
943 {
944 LIBSSH2_SESSION *session = channel->session;
945 unsigned char *s, *data;
946 static const unsigned char reply_codes[3] =
947 { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 };
948 unsigned long data_len;
949 unsigned long proto_len =
950 auth_proto ? strlen(auth_proto) : (sizeof("MIT-MAGIC-COOKIE-1") - 1);
951 unsigned long cookie_len =
952 auth_cookie ? strlen(auth_cookie) : LIBSSH2_X11_RANDOM_COOKIE_LEN;
953 int rc;
954
955 if (channel->reqX11_state == libssh2_NB_state_idle) {
956 /* 30 = packet_type(1) + channel(4) + x11_req_len(4) + "x11-req"(7) +
957 * want_reply(1) + single_cnx(1) + proto_len(4) + cookie_len(4) +
958 * screen_num(4) */
959 channel->reqX11_packet_len = proto_len + cookie_len + 30;
960
961 /* Zero the whole thing out */
962 memset(&channel->reqX11_packet_requirev_state, 0,
963 sizeof(channel->reqX11_packet_requirev_state));
964
965 _libssh2_debug(session, LIBSSH2_DBG_CONN,
966 "Requesting x11-req for channel %lu/%lu: single=%d proto=%s cookie=%s screen=%d",
967 channel->local.id, channel->remote.id,
968 single_connection,
969 auth_proto ? auth_proto : "MIT-MAGIC-COOKIE-1",
970 auth_cookie ? auth_cookie : "<random>", screen_number);
971
972 s = channel->reqX11_packet =
973 LIBSSH2_ALLOC(session, channel->reqX11_packet_len);
974 if (!channel->reqX11_packet) {
975 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
976 "Unable to allocate memory for pty-request", 0);
977 return -1;
978 }
979
980 *(s++) = SSH_MSG_CHANNEL_REQUEST;
981 libssh2_htonu32(s, channel->remote.id);
982 s += 4;
983 libssh2_htonu32(s, sizeof("x11-req") - 1);
984 s += 4;
985 memcpy(s, "x11-req", sizeof("x11-req") - 1);
986 s += sizeof("x11-req") - 1;
987
988 *(s++) = 0x01; /* want_reply */
989 *(s++) = single_connection ? 0x01 : 0x00;
990
991 libssh2_htonu32(s, proto_len);
992 s += 4;
993 memcpy(s, auth_proto ? auth_proto : "MIT-MAGIC-COOKIE-1", proto_len);
994 s += proto_len;
995
996 libssh2_htonu32(s, cookie_len);
997 s += 4;
998 if (auth_cookie) {
999 memcpy(s, auth_cookie, cookie_len);
1000 } else {
1001 int i;
1002 unsigned char buffer[LIBSSH2_X11_RANDOM_COOKIE_LEN / 2];
1003
1004 libssh2_random(buffer, LIBSSH2_X11_RANDOM_COOKIE_LEN / 2);
1005 for(i = 0; i < (LIBSSH2_X11_RANDOM_COOKIE_LEN / 2); i++) {
1006 snprintf((char *) s + (i * 2), 2, "%02X", buffer[i]);
1007 }
1008 }
1009 s += cookie_len;
1010
1011 libssh2_htonu32(s, screen_number);
1012 s += 4;
1013
1014 channel->reqX11_state = libssh2_NB_state_created;
1015 }
1016
1017 if (channel->reqX11_state == libssh2_NB_state_created) {
1018 rc = libssh2_packet_write(session, channel->reqX11_packet,
1019 channel->reqX11_packet_len);
1020 if (rc == PACKET_EAGAIN) {
1021 return PACKET_EAGAIN;
1022 }
1023 if (rc) {
1024 libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
1025 "Unable to send x11-req packet", 0);
1026 LIBSSH2_FREE(session, channel->reqX11_packet);
1027 channel->reqX11_packet = NULL;
1028 channel->reqX11_state = libssh2_NB_state_idle;
1029 return -1;
1030 }
1031 LIBSSH2_FREE(session, channel->reqX11_packet);
1032 channel->reqX11_packet = NULL;
1033
1034 libssh2_htonu32(channel->reqX11_local_channel, channel->local.id);
1035
1036 channel->reqX11_state = libssh2_NB_state_sent;
1037 }
1038
1039 if (channel->reqX11_state == libssh2_NB_state_sent) {
1040 rc = libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len,
1041 1, channel->reqX11_local_channel, 4,
1042 &channel->
1043 reqX11_packet_requirev_state);
1044 if (rc == PACKET_EAGAIN) {
1045 return PACKET_EAGAIN;
1046 } else if (rc) {
1047 channel->reqX11_state = libssh2_NB_state_idle;
1048 return -1;
1049 }
1050
1051 if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
1052 LIBSSH2_FREE(session, data);
1053 channel->reqX11_state = libssh2_NB_state_idle;
1054 return 0;
1055 }
1056 }
1057
1058 LIBSSH2_FREE(session, data);
1059 libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED,
1060 "Unable to complete request for channel x11-req", 0);
1061 return -1;
1062 }
1063
1064 /* }}} */
1065
1066 /* {{{ libssh2_channel_process_startup
1067 * Primitive for libssh2_channel_(shell|exec|subsystem)
1068 */
1069 LIBSSH2_API int
1070 libssh2_channel_process_startup(LIBSSH2_CHANNEL * channel, const char *request,
1071 unsigned int request_len, const char *message,
1072 unsigned int message_len)
1073 {
1074 LIBSSH2_SESSION *session = channel->session;
1075 unsigned char *s, *data;
1076 static const unsigned char reply_codes[3] =
1077 { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 };
1078 unsigned long data_len;
1079 libssh2pack_t rc;
1080
1081 if (channel->process_state == libssh2_NB_state_idle) {
1082 /* 10 = packet_type(1) + channel(4) + request_len(4) + want_reply(1) */
1083 channel->process_packet_len = request_len + 10;
1084
1085 /* Zero the whole thing out */
1086 memset(&channel->process_packet_requirev_state, 0,
1087 sizeof(channel->process_packet_requirev_state));
1088
1089 if (message) {
1090 channel->process_packet_len += message_len + 4;
1091 }
1092
1093 _libssh2_debug(session, LIBSSH2_DBG_CONN,
1094 "starting request(%s) on channel %lu/%lu, message=%s",
1095 request, channel->local.id, channel->remote.id,
1096 message);
1097 s = channel->process_packet =
1098 LIBSSH2_ALLOC(session, channel->process_packet_len);
1099 if (!channel->process_packet) {
1100 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1101 "Unable to allocate memory for channel-process request",
1102 0);
1103 return -1;
1104 }
1105
1106 *(s++) = SSH_MSG_CHANNEL_REQUEST;
1107 libssh2_htonu32(s, channel->remote.id);
1108 s += 4;
1109 libssh2_htonu32(s, request_len);
1110 s += 4;
1111 memcpy(s, request, request_len);
1112 s += request_len;
1113
1114 *(s++) = 0x01;
1115
1116 if (message) {
1117 libssh2_htonu32(s, message_len);
1118 s += 4;
1119 memcpy(s, message, message_len);
1120 s += message_len;
1121 }
1122
1123 channel->process_state = libssh2_NB_state_created;
1124 }
1125
1126 if (channel->process_state == libssh2_NB_state_created) {
1127 rc = libssh2_packet_write(session, channel->process_packet,
1128 channel->process_packet_len);
1129 if (rc == PACKET_EAGAIN) {
1130 return PACKET_EAGAIN;
1131 } else if (rc) {
1132 libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
1133 "Unable to send channel request", 0);
1134 LIBSSH2_FREE(session, channel->process_packet);
1135 channel->process_packet = NULL;
1136 channel->process_state = libssh2_NB_state_idle;
1137 return -1;
1138 }
1139 LIBSSH2_FREE(session, channel->process_packet);
1140 channel->process_packet = NULL;
1141
1142 libssh2_htonu32(channel->process_local_channel, channel->local.id);
1143
1144 channel->process_state = libssh2_NB_state_sent;
1145 }
1146
1147 if (channel->process_state == libssh2_NB_state_sent) {
1148 rc = libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len,
1149 1, channel->process_local_channel, 4,
1150 &channel->
1151 process_packet_requirev_state);
1152 if (rc == PACKET_EAGAIN) {
1153 return PACKET_EAGAIN;
1154 } else if (rc) {
1155 channel->process_state = libssh2_NB_state_idle;
1156 return -1;
1157 }
1158
1159 if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
1160 LIBSSH2_FREE(session, data);
1161 channel->process_state = libssh2_NB_state_idle;
1162 return 0;
1163 }
1164 }
1165
1166 LIBSSH2_FREE(session, data);
1167 libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED,
1168 "Unable to complete request for channel-process-startup", 0);
1169 channel->process_state = libssh2_NB_state_idle;
1170 return -1;
1171 }
1172
1173 /* }}} */
1174
1175 /* {{{ libssh2_channel_set_blocking
1176 * Set a channel's blocking mode on or off, similar to a socket's
1177 * fcntl(fd, F_SETFL, O_NONBLOCK); type command
1178 */
1179 LIBSSH2_API void
1180 libssh2_channel_set_blocking(LIBSSH2_CHANNEL * channel, int blocking)
1181 {
1182 (void) _libssh2_session_set_blocking(channel->session, blocking);
1183 }
1184
1185 /* }}} */
1186
1187 /* {{{ libssh2_channel_flush_ex
1188 * Flush data from one (or all) stream
1189 * Returns number of bytes flushed, or -1 on failure
1190 */
1191 LIBSSH2_API int
1192 libssh2_channel_flush_ex(LIBSSH2_CHANNEL * channel, int streamid)
1193 {
1194 LIBSSH2_PACKET *packet = channel->session->packets.head;
1195
1196 if (channel->flush_state == libssh2_NB_state_idle) {
1197 channel->flush_refund_bytes = 0;
1198 channel->flush_flush_bytes = 0;
1199
1200 while (packet) {
1201 LIBSSH2_PACKET *next = packet->next;
1202 unsigned char packet_type = packet->data[0];
1203
1204 if (((packet_type == SSH_MSG_CHANNEL_DATA)
1205 || (packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA))
1206 && (libssh2_ntohu32(packet->data + 1) == channel->local.id)) {
1207 /* It's our channel at least */
1208 long packet_stream_id =
1209 (packet_type ==
1210 SSH_MSG_CHANNEL_DATA) ? 0 : libssh2_ntohu32(packet->data +
1211 5);
1212 if ((streamid == LIBSSH2_CHANNEL_FLUSH_ALL)
1213 || ((packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA)
1214 && ((streamid == LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA)
1215 || (streamid == packet_stream_id)))
1216 || ((packet_type == SSH_MSG_CHANNEL_DATA)
1217 && (streamid == 0))) {
1218 int bytes_to_flush = packet->data_len - packet->data_head;
1219
1220 _libssh2_debug(channel->session, LIBSSH2_DBG_CONN,
1221 "Flushing %d bytes of data from stream %lu on channel %lu/%lu",
1222 bytes_to_flush, packet_stream_id,
1223 channel->local.id, channel->remote.id);
1224
1225 /* It's one of the streams we wanted to flush */
1226 channel->flush_refund_bytes += packet->data_len - 13;
1227 channel->flush_flush_bytes += bytes_to_flush;
1228
1229 LIBSSH2_FREE(channel->session, packet->data);
1230 if (packet->prev) {
1231 packet->prev->next = packet->next;
1232 } else {
1233 channel->session->packets.head = packet->next;
1234 }
1235 if (packet->next) {
1236 packet->next->prev = packet->prev;
1237 } else {
1238 channel->session->packets.tail = packet->prev;
1239 }
1240 LIBSSH2_FREE(channel->session, packet);
1241 }
1242 }
1243 packet = next;
1244 }
1245
1246 channel->flush_state = libssh2_NB_state_created;
1247 }
1248
1249 if (channel->flush_refund_bytes) {
1250 int rc;
1251
1252 rc = libssh2_channel_receive_window_adjust(channel,
1253 channel->flush_refund_bytes,
1254 0);
1255 if (rc == PACKET_EAGAIN) {
1256 return PACKET_EAGAIN;
1257 }
1258 }
1259
1260 channel->flush_state = libssh2_NB_state_idle;
1261
1262 return channel->flush_flush_bytes;
1263 }
1264
1265 /* }}} */
1266
1267 /* {{{ libssh2_channel_get_exit_status
1268 * Return the channel's program exit status
1269 */
1270 LIBSSH2_API int
1271 libssh2_channel_get_exit_status(LIBSSH2_CHANNEL * channel)
1272 {
1273 return channel->exit_status;
1274 }
1275
1276 /* }}} */
1277
1278 /* {{{ libssh2_channel_receive_window_adjust
1279 * Adjust the receive window for a channel by adjustment bytes
1280 * If the amount to be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and
1281 * force is 0 the adjustment amount will be queued for a later packet
1282 *
1283 * Returns the new size of the receive window (as understood by remote end)
1284 */
1285 LIBSSH2_API unsigned long
1286 libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel,
1287 unsigned long adjustment,
1288 unsigned char force)
1289 {
1290 int rc;
1291
1292 if (channel->adjust_state == libssh2_NB_state_idle) {
1293 if (!force
1294 && (adjustment + channel->adjust_queue <
1295 LIBSSH2_CHANNEL_MINADJUST)) {
1296 _libssh2_debug(channel->session, LIBSSH2_DBG_CONN,
1297 "Queueing %lu bytes for receive window adjustment for channel %lu/%lu",
1298 adjustment, channel->local.id, channel->remote.id);
1299 channel->adjust_queue += adjustment;
1300 return channel->remote.window_size;
1301 }
1302
1303 if (!adjustment && !channel->adjust_queue) {
1304 return channel->remote.window_size;
1305 }
1306
1307 adjustment += channel->adjust_queue;
1308 channel->adjust_queue = 0;
1309
1310
1311 /* Adjust the window based on the block we just freed */
1312 channel->adjust_adjust[0] = SSH_MSG_CHANNEL_WINDOW_ADJUST;
1313 libssh2_htonu32(channel->adjust_adjust + 1, channel->remote.id);
1314 libssh2_htonu32(channel->adjust_adjust + 5, adjustment);
1315 _libssh2_debug(channel->session, LIBSSH2_DBG_CONN,
1316 "Adjusting window %lu bytes for data flushed from channel %lu/%lu",
1317 adjustment, channel->local.id, channel->remote.id);
1318
1319 channel->adjust_state = libssh2_NB_state_created;
1320 }
1321
1322 rc = libssh2_packet_write(channel->session, channel->adjust_adjust, 9);
1323 if (rc == PACKET_EAGAIN) {
1324 return PACKET_EAGAIN;
1325 } else if (rc) {
1326 libssh2_error(channel->session, LIBSSH2_ERROR_SOCKET_SEND,
1327 "Unable to send transfer-window adjustment packet, deferring",
1328 0);
1329 channel->adjust_queue = adjustment;
1330 channel->adjust_state = libssh2_NB_state_idle;
1331 } else {
1332 channel->adjust_state = libssh2_NB_state_idle;
1333 channel->remote.window_size += adjustment;
1334 }
1335
1336 return channel->remote.window_size;
1337 }
1338
1339 /* }}} */
1340
1341 /* {{{ libssh2_channel_handle_extended_data
1342 * How should extended data look to the calling app?
1343 * Keep it in separate channels[_read() _read_stdder()]? (NORMAL)
1344 * Merge the extended data to the standard data? [everything via _read()]? (MERGE)
1345 * Ignore it entirely [toss out packets as they come in]? (IGNORE)
1346 */
1347 LIBSSH2_API void
1348 libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL * channel,
1349 int ignore_mode)
1350 {
1351 while (libssh2_channel_handle_extended_data2(channel, ignore_mode) ==
1352 PACKET_EAGAIN);
1353 }
1354
1355 LIBSSH2_API int
1356 libssh2_channel_handle_extended_data2(LIBSSH2_CHANNEL * channel,
1357 int ignore_mode)
1358 {
1359 if (channel->extData2_state == libssh2_NB_state_idle) {
1360 _libssh2_debug(channel->session, LIBSSH2_DBG_CONN,
1361 "Setting channel %lu/%lu handle_extended_data mode to %d",
1362 channel->local.id, channel->remote.id, ignore_mode);
1363 channel->remote.extended_data_ignore_mode = ignore_mode;
1364
1365 channel->extData2_state = libssh2_NB_state_created;
1366 }
1367
1368 if (channel->extData2_state == libssh2_NB_state_idle) {
1369 if (ignore_mode == LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE) {
1370 if (libssh2_channel_flush_ex
1371 (channel,
1372 LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA) == PACKET_EAGAIN) {
1373 return PACKET_EAGAIN;
1374 }
1375 }
1376 }
1377
1378 channel->extData2_state = libssh2_NB_state_idle;
1379 return 0;
1380 }
1381
1382 /* }}} */
1383
1384 /*
1385 * {{{ libssh2_channel_read_ex
1386 * Read data from a channel blocking or non-blocking depending on set state
1387 *
1388 * When this is done non-blocking, it is important to not return 0 until the
1389 * currently read channel is complete. If we read stuff from the wire but it
1390 * was no payload data to fill in the buffer with, we MUST make sure to return
1391 * PACKET_EAGAIN.
1392 */
1393 LIBSSH2_API ssize_t
1394 libssh2_channel_read_ex(LIBSSH2_CHANNEL * channel, int stream_id, char *buf,
1395 size_t buflen)
1396 {
1397 LIBSSH2_SESSION *session = channel->session;
1398 libssh2pack_t rc = 0;
1399
1400 if (channel->read_state == libssh2_NB_state_idle) {
1401 _libssh2_debug(session, LIBSSH2_DBG_CONN,
1402 "Attempting to read %d bytes from channel %lu/%lu stream #%d",
1403 (int) buflen, channel->local.id, channel->remote.id,
1404 stream_id);
1405
1406 /* process all incoming packets */
1407 do {
1408 if (libssh2_waitsocket(session, 0) > 0) {
1409 rc = libssh2_packet_read(session);
1410 } else {
1411 /* Set for PACKET_EAGAIN so we continue */
1412 rc = PACKET_EAGAIN;
1413 }
1414 } while (rc > 0);
1415
1416 if ((rc < 0) && (rc != PACKET_EAGAIN)) {
1417 fprintf(stderr, "return rc = %d\n", rc);
1418 return rc;
1419 }
1420 channel->read_bytes_read = 0;
1421 channel->read_block = 0;
1422
1423 channel->read_packet = session->packets.head;
1424
1425 channel->read_state = libssh2_NB_state_created;
1426 }
1427
1428 /*
1429 * =============================== NOTE ===============================
1430 * I know this is very ugly and not a really good use of "goto", but
1431 * this case statement would be even uglier to do it any other way
1432 */
1433 if (channel->read_state == libssh2_NB_state_jump1) {
1434 goto channel_read_ex_point1;
1435 }
1436
1437 rc = 0;
1438
1439 do {
1440 if (channel->read_block) {
1441 /* in the second lap and onwards, do this */
1442 rc = libssh2_packet_read(session);
1443 channel->read_packet = session->packets.head;
1444 }
1445
1446 if (rc < 0) {
1447 if (rc != PACKET_EAGAIN) {
1448 channel->read_state = libssh2_NB_state_idle;
1449 }
1450 /* no packets available */
1451 return rc;
1452 }
1453
1454 while (channel->read_packet
1455 && (channel->read_bytes_read < (int) buflen)) {
1456 /* In case packet gets destroyed during this iteration */
1457 channel->read_next = channel->read_packet->next;
1458
1459 channel->read_local_id =
1460 libssh2_ntohu32(channel->read_packet->data + 1);
1461
1462 /*
1463 * Either we asked for a specific extended data stream
1464 * (and data was available),
1465 * or the standard stream (and data was available),
1466 * or the standard stream with extended_data_merge
1467 * enabled and data was available
1468 */
1469 if ((stream_id
1470 && (channel->read_packet->data[0] ==
1471 SSH_MSG_CHANNEL_EXTENDED_DATA)
1472 && (channel->local.id == channel->read_local_id)
1473 && (stream_id ==
1474 (int) libssh2_ntohu32(channel->read_packet->data + 5)))
1475 || (!stream_id
1476 && (channel->read_packet->data[0] == SSH_MSG_CHANNEL_DATA)
1477 && (channel->local.id == channel->read_local_id))
1478 || (!stream_id
1479 && (channel->read_packet->data[0] ==
1480 SSH_MSG_CHANNEL_EXTENDED_DATA)
1481 && (channel->local.id == channel->read_local_id)
1482 && (channel->remote.extended_data_ignore_mode ==
1483 LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE))) {
1484
1485 channel->read_want = buflen - channel->read_bytes_read;
1486 channel->read_unlink_packet = 0;
1487
1488 if (channel->read_want >=
1489 (int) (channel->read_packet->data_len -
1490 channel->read_packet->data_head)) {
1491 channel->read_want =
1492 channel->read_packet->data_len -
1493 channel->read_packet->data_head;
1494 channel->read_unlink_packet = 1;
1495 }
1496
1497 _libssh2_debug(session, LIBSSH2_DBG_CONN,
1498 "Reading %d of buffered data from %lu/%lu/%d",
1499 channel->read_want, channel->local.id,
1500 channel->remote.id, stream_id);
1501 memcpy(buf + channel->read_bytes_read,
1502 channel->read_packet->data +
1503 channel->read_packet->data_head, channel->read_want);
1504 channel->read_packet->data_head += channel->read_want;
1505 channel->read_bytes_read += channel->read_want;
1506
1507 if (channel->read_unlink_packet) {
1508 if (channel->read_packet->prev) {
1509 channel->read_packet->prev->next =
1510 channel->read_packet->next;
1511 } else {
1512 session->packets.head = channel->read_packet->next;
1513 }
1514 if (channel->read_packet->next) {
1515 channel->read_packet->next->prev =
1516 channel->read_packet->prev;
1517 } else {
1518 session->packets.tail = channel->read_packet->prev;
1519 }
1520 LIBSSH2_FREE(session, channel->read_packet->data);
1521
1522
1523 _libssh2_debug(session, LIBSSH2_DBG_CONN,
1524 "Unlinking empty packet buffer from channel %lu/%lu",
1525 channel->local.id, channel->remote.id);
1526 channel_read_ex_point1:
1527 channel->read_state = libssh2_NB_state_jump1;
1528 rc = libssh2_channel_receive_window_adjust(channel,
1529 channel->
1530 read_packet->
1531 data_len -
1532 (stream_id ? 13
1533 : 9), 0);
1534 if (rc == PACKET_EAGAIN) {
1535 return PACKET_EAGAIN;
1536 }
1537 channel->read_state = libssh2_NB_state_created;
1538 LIBSSH2_FREE(session, channel->read_packet);
1539 channel->read_packet = NULL;
1540 }
1541 }
1542 channel->read_packet = channel->read_next;
1543 }
1544 channel->read_block = 1;
1545 } while ((channel->read_bytes_read == 0) && !channel->remote.close);
1546
1547 channel->read_state = libssh2_NB_state_idle;
1548 if (channel->read_bytes_read == 0) {
1549 if (channel->session->socket_block) {
1550 libssh2_error(session, LIBSSH2_ERROR_CHANNEL_CLOSED,
1551 "Remote end has closed this channel", 0);
1552 } else {
1553 /*
1554 * when non-blocking, we must return PACKET_EAGAIN if we haven't
1555 * completed reading the channel
1556 */
1557 if (!libssh2_channel_eof(channel)) {
1558 return PACKET_EAGAIN;
1559 }
1560 }
1561 }
1562
1563 channel->read_state = libssh2_NB_state_idle;
1564 return channel->read_bytes_read;
1565 }
1566
1567 /* }}} */
1568
1569 /*
1570 * {{{ libssh2_channel_packet_data_len
1571 * Return the size of the data block of the current packet, or 0 if there
1572 * isn't a packet.
1573 */
1574 unsigned long
1575 libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id)
1576 {
1577 LIBSSH2_SESSION *session = channel->session;
1578 LIBSSH2_PACKET *read_packet;
1579 uint32_t read_local_id;
1580
1581 if ((read_packet = session->packets.head) == NULL) {
1582 return 0;
1583 }
1584
1585 while (read_packet) {
1586 read_local_id = libssh2_ntohu32(read_packet->data + 1);
1587
1588 /*
1589 * Either we asked for a specific extended data stream
1590 * (and data was available),
1591 * or the standard stream (and data was available),
1592 * or the standard stream with extended_data_merge
1593 * enabled and data was available
1594 */
1595 if ((stream_id
1596 && (read_packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)
1597 && (channel->local.id == read_local_id)
1598 && (stream_id == (int) libssh2_ntohu32(read_packet->data + 5)))
1599 || (!stream_id && (read_packet->data[0] == SSH_MSG_CHANNEL_DATA)
1600 && (channel->local.id == read_local_id)) || (!stream_id
1601 && (read_packet->
1602 data[0] ==
1603 SSH_MSG_CHANNEL_EXTENDED_DATA)
1604 && (channel->
1605 local.id ==
1606 read_local_id)
1607 && (channel->
1608 remote.
1609 extended_data_ignore_mode
1610 ==
1611 LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE)))
1612 {
1613
1614 return (read_packet->data_len - read_packet->data_head);
1615 }
1616 read_packet = read_packet->next;
1617 }
1618
1619 return 0;
1620 }
1621
1622 /* }}} */
1623
1624 /* {{{ libssh2_channel_write_ex
1625 * Send data to a channel
1626 */
1627 LIBSSH2_API ssize_t
1628 libssh2_channel_write_ex(LIBSSH2_CHANNEL * channel, int stream_id,
1629 const char *buf, size_t buflen)
1630 {
1631 LIBSSH2_SESSION *session = channel->session;
1632 libssh2pack_t rc;
1633
1634 if (channel->write_state == libssh2_NB_state_idle) {
1635 channel->write_bufwrote = 0;
1636
1637 _libssh2_debug(session, LIBSSH2_DBG_CONN,
1638 "Writing %d bytes on channel %lu/%lu, stream #%d",
1639 (int) buflen, channel->local.id, channel->remote.id,
1640 stream_id);
1641
1642 if (channel->local.close) {
1643 libssh2_error(session, LIBSSH2_ERROR_CHANNEL_CLOSED,
1644 "We've already closed this channel", 0);
1645 return -1;
1646 }
1647
1648 if (channel->local.eof) {
1649 libssh2_error(session, LIBSSH2_ERROR_CHANNEL_EOF_SENT,
1650 "EOF has already been sight, data might be ignored",
1651 0);
1652 }
1653
1654 #if 0
1655 /*
1656 The following chunk of code is #ifdef'ed out, since I wanted it to
1657 remain here with the given explanation why having the code in here
1658 is not a good idea. The text is taken from the email Gavrie
1659 Philipson wrote to libssh2-devel on Nov 8 2007.
1660
1661 The logic behind this is that in nonblocking mode, if the local
1662 window size has shrunk to zero, there's no point in trying to send
1663 anything more. However, exiting the function at that point does not
1664 allow any adjusts from the remote side to be received, since
1665 libssh2_packet_read (that is called further on in this function) is
1666 never called in this case.
1667
1668 Removing this bit of code fixes the problem. This should not cause
1669 busy waiting, since after the libssh2_packet_read, the function
1670 correctly returns PACKET_EAGAIN if the window size was not adjusted.
1671 */
1672 if (!channel->session->socket_block &&
1673 (channel->local.window_size <= 0)) {
1674 /* Can't write anything */
1675 return 0;
1676 }
1677 #endif
1678
1679 /* [13] 9 = packet_type(1) + channelno(4) [ + streamid(4) ] + buflen(4) */
1680 channel->write_packet_len = buflen + (stream_id ? 13 : 9);
1681 channel->write_packet =
1682 LIBSSH2_ALLOC(session, channel->write_packet_len);
1683 if (!channel->write_packet) {
1684 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1685 "Unable to allocte space for data transmission packet",
1686 0);
1687 return -1;
1688 }
1689
1690 channel->write_state = libssh2_NB_state_allocated;
1691 }
1692
1693 while (buflen > 0) {
1694 if (channel->write_state == libssh2_NB_state_allocated) {
1695 channel->write_bufwrite = buflen;
1696 channel->write_s = channel->write_packet;
1697
1698 *(channel->write_s++) =
1699 stream_id ? SSH_MSG_CHANNEL_EXTENDED_DATA :
1700 SSH_MSG_CHANNEL_DATA;
1701 libssh2_htonu32(channel->write_s, channel->remote.id);
1702 channel->write_s += 4;
1703 if (stream_id) {
1704 libssh2_htonu32(channel->write_s, stream_id);
1705 channel->write_s += 4;
1706 }
1707
1708 /* twiddle our thumbs until there's window space available */
1709 while (channel->local.window_size <= 0) {
1710 /* Don't worry -- This is never hit unless it's a
1711 blocking channel anyway */
1712 rc = libssh2_packet_read(session);
1713
1714 if (rc < 0) {
1715 /* Error or EAGAIN occurred, disconnect? */
1716 if (rc != PACKET_EAGAIN) {
1717 channel->write_state = libssh2_NB_state_idle;
1718 }
1719 return rc;
1720 }
1721
1722 if ((rc == 0) && (session->socket_block == 0)) {
1723 /*
1724 * if rc == 0 and in non-blocking, then fake EAGAIN
1725 * to prevent busyloops until data arriaves on the network
1726 * which seemed like a very bad idea
1727 */
1728 return PACKET_EAGAIN;
1729 }
1730 }
1731
1732 /* Don't exceed the remote end's limits */
1733 /* REMEMBER local means local as the SOURCE of the data */
1734 if (channel->write_bufwrite > channel->local.window_size) {
1735 _libssh2_debug(session, LIBSSH2_DBG_CONN,
1736 "Splitting write block due to %lu byte window_size on %lu/%lu/%d",
1737 channel->local.window_size, channel->local.id,
1738 channel->remote.id, stream_id);
1739 channel->write_bufwrite = channel->local.window_size;
1740 }
1741 if (channel->write_bufwrite > channel->local.packet_size) {
1742 _libssh2_debug(session, LIBSSH2_DBG_CONN,
1743 "Splitting write block due to %lu byte packet_size on %lu/%lu/%d",
1744 channel->local.packet_size, channel->local.id,
1745 channel->remote.id, stream_id);
1746 channel->write_bufwrite = channel->local.packet_size;
1747 }
1748 libssh2_htonu32(channel->write_s, channel->write_bufwrite);
1749 channel->write_s += 4;
1750 memcpy(channel->write_s, buf, channel->write_bufwrite);
1751 channel->write_s += channel->write_bufwrite;
1752
1753 _libssh2_debug(session, LIBSSH2_DBG_CONN,
1754 "Sending %d bytes on channel %lu/%lu, stream_id=%d",
1755 (int) channel->write_bufwrite, channel->local.id,
1756 channel->remote.id, stream_id);
1757
1758 channel->write_state = libssh2_NB_state_created;
1759 }
1760
1761 if (channel->write_state == libssh2_NB_state_created) {
1762 rc = libssh2_packet_write(session, channel->write_packet,
1763 channel->write_s -
1764 channel->write_packet);
1765 if (rc == PACKET_EAGAIN) {
1766 return PACKET_EAGAIN;
1767 } else if (rc) {
1768 libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
1769 "Unable to send channel data", 0);
1770 LIBSSH2_FREE(session, channel->write_packet);
1771 channel->write_packet = NULL;
1772 channel->write_state = libssh2_NB_state_idle;
1773 return -1;
1774 }
1775 /* Shrink local window size */
1776 channel->local.window_size -= channel->write_bufwrite;
1777
1778 /* Adjust buf for next iteration */
1779 buflen -= channel->write_bufwrite;
1780 buf += channel->write_bufwrite;
1781 channel->write_bufwrote += channel->write_bufwrite;
1782
1783 channel->write_state = libssh2_NB_state_allocated;
1784
1785 /*
1786 * Not sure this is still wanted
1787 if (!channel->session->socket_block) {
1788 break;
1789 }
1790 */
1791 }
1792 }
1793
1794 LIBSSH2_FREE(session, channel->write_packet);
1795 channel->write_packet = NULL;
1796
1797 channel->write_state = libssh2_NB_state_idle;
1798
1799 return channel->write_bufwrote;
1800 }
1801
1802 /* }}} */
1803
1804 /* {{{ libssh2_channel_send_eof
1805 * Send EOF on channel
1806 */
1807 LIBSSH2_API int
1808 libssh2_channel_send_eof(LIBSSH2_CHANNEL * channel)
1809 {
1810 LIBSSH2_SESSION *session = channel->session;
1811 unsigned char packet[5]; /* packet_type(1) + channelno(4) */
1812 int rc;
1813
1814 _libssh2_debug(session, LIBSSH2_DBG_CONN, "Sending EOF on channel %lu/%lu",
1815 channel->local.id, channel->remote.id);
1816 packet[0] = SSH_MSG_CHANNEL_EOF;
1817 libssh2_htonu32(packet + 1, channel->remote.id);
1818 rc = libssh2_packet_write(session, packet, 5);
1819 if (rc == PACKET_EAGAIN) {
1820 return PACKET_EAGAIN;
1821 } else if (rc) {
1822 libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
1823 "Unable to send EOF on channel", 0);
1824 return -1;
1825 }
1826 channel->local.eof = 1;
1827
1828 return 0;
1829 }
1830
1831 /* }}} */
1832
1833 /* {{{ libssh2_channel_eof
1834 * Read channel's eof status
1835 */
1836 LIBSSH2_API int
1837 libssh2_channel_eof(LIBSSH2_CHANNEL * channel)
1838 {
1839 LIBSSH2_SESSION *session = channel->session;
1840 LIBSSH2_PACKET *packet = session->packets.head;
1841
1842 while (packet) {
1843 if (((packet->data[0] == SSH_MSG_CHANNEL_DATA)
1844 || (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA))
1845 && (channel->local.id == libssh2_ntohu32(packet->data + 1))) {
1846 /* There's data waiting to be read yet, mask the EOF status */
1847 return 0;
1848 }
1849 packet = packet->next;
1850 }
1851
1852 return channel->remote.eof;
1853 }
1854
1855 /* }}} */
1856
1857 /* {{{ libssh2_channel_wait_closed
1858 * Awaiting channel EOF
1859 */
1860 LIBSSH2_API int
1861 libssh2_channel_wait_eof(LIBSSH2_CHANNEL * channel)
1862 {
1863 LIBSSH2_SESSION *session = channel->session;
1864 int rc;
1865
1866 if (channel->wait_eof_state == libssh2_NB_state_idle) {
1867 _libssh2_debug(session, LIBSSH2_DBG_CONN,
1868 "Awaiting close of channel %lu/%lu", channel->local.id,
1869 channel->remote.id);
1870
1871 channel->wait_eof_state = libssh2_NB_state_created;
1872 }
1873
1874 /*
1875 * While channel is not eof, read more packets from the network.
1876 * Either the EOF will be set or network timeout will occur.
1877 */
1878 do {
1879 if (channel->remote.eof) {
1880 break;
1881 }
1882 rc = libssh2_packet_read(session);
1883 if (rc == PACKET_EAGAIN) {
1884 return PACKET_EAGAIN;
1885 } else if (rc < 0) {
1886 channel->wait_eof_state = libssh2_NB_state_idle;
1887 return -1;
1888 }
1889 } while (1);
1890
1891 channel->wait_eof_state = libssh2_NB_state_idle;
1892
1893 return 0;
1894 }
1895
1896 /* }}} */
1897
1898
1899 /* {{{ libssh2_channel_close
1900 * Close a channel
1901 */
1902 LIBSSH2_API int
1903 libssh2_channel_close(LIBSSH2_CHANNEL * channel)
1904 {
1905 LIBSSH2_SESSION *session = channel->session;
1906 int rc = 0;
1907 int retcode;
1908
1909 if (channel->local.close) {
1910 /* Already closed, act like we sent another close,
1911 * even though we didn't... shhhhhh */
1912 channel->close_state = libssh2_NB_state_idle;
1913 return 0;
1914 }
1915
1916 if (channel->close_state == libssh2_NB_state_idle) {
1917 _libssh2_debug(session, LIBSSH2_DBG_CONN, "Closing channel %lu/%lu",
1918 channel->local.id, channel->remote.id);
1919
1920 if (channel->close_cb) {
1921 LIBSSH2_CHANNEL_CLOSE(session, channel);
1922 }
1923 channel->local.close = 1;
1924
1925 channel->close_packet[0] = SSH_MSG_CHANNEL_CLOSE;
1926 libssh2_htonu32(channel->close_packet + 1, channel->remote.id);
1927
1928 channel->close_state = libssh2_NB_state_created;
1929 }
1930
1931 if (channel->close_state == libssh2_NB_state_created) {
1932 retcode = libssh2_packet_write(session, channel->close_packet, 5);
1933 if (retcode == PACKET_EAGAIN) {
1934 return PACKET_EAGAIN;
1935 } else if (retcode) {
1936 libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
1937 "Unable to send close-channel request", 0);
1938 channel->close_state = libssh2_NB_state_idle;
1939 return -1;
1940 }
1941
1942 channel->close_state = libssh2_NB_state_sent;
1943 }
1944
1945 if (channel->close_state == libssh2_NB_state_sent) {
1946 /* We must wait for the remote SSH_MSG_CHANNEL_CLOSE message */
1947 if (!channel->remote.close) {
1948 libssh2pack_t ret;
1949
1950 do {
1951 ret = libssh2_packet_read(session);
1952 if (ret == PACKET_EAGAIN) {
1953 return PACKET_EAGAIN;
1954 } else if (ret < 0) {
1955 rc = -1;
1956 }
1957 } while ((ret != SSH_MSG_CHANNEL_CLOSE) && (rc == 0));
1958 }
1959 }
1960
1961 channel->close_state = libssh2_NB_state_idle;
1962
1963 return rc;
1964 }
1965
1966 /* }}} */
1967
1968 /* {{{ libssh2_channel_wait_closed
1969 * Awaiting channel close after EOF
1970 */
1971 LIBSSH2_API int
1972 libssh2_channel_wait_closed(LIBSSH2_CHANNEL * channel)
1973 {
1974 LIBSSH2_SESSION *session = channel->session;
1975 int rc;
1976
1977 if (!libssh2_channel_eof(channel)) {
1978 libssh2_error(session, LIBSSH2_ERROR_INVAL,
1979 "libssh2_channel_wait_closed() invoked when channel is not in EOF state",
1980 0);
1981 return -1;
1982 }
1983
1984 if (channel->wait_closed_state == libssh2_NB_state_idle) {
1985 _libssh2_debug(session, LIBSSH2_DBG_CONN,
1986 "Awaiting close of channel %lu/%lu", channel->local.id,
1987 channel->remote.id);
1988
1989 channel->wait_closed_state = libssh2_NB_state_created;
1990 }
1991
1992 /*
1993 * While channel is not closed, read more packets from the network.
1994 * Either the channel will be closed or network timeout will occur.
1995 */
1996 do {
1997 if (!channel->remote.close) {
1998 break;
1999 }
2000 rc = libssh2_packet_read(session);
2001 if (rc == PACKET_EAGAIN) {
2002 return PACKET_EAGAIN;
2003 } else if (rc <= 0) {
2004 break;
2005 }
2006 } while (1);
2007
2008 channel->wait_closed_state = libssh2_NB_state_idle;
2009
2010 return 1;
2011 }
2012
2013 /* }}} */
2014
2015
2016 /* {{{ libssh2_channel_free
2017 * Make sure a channel is closed, then remove the channel from the session
2018 * and free its resource(s)
2019 *
2020 * Returns 0 on success, -1 on failure
2021 */
2022 LIBSSH2_API int
2023 libssh2_channel_free(LIBSSH2_CHANNEL * channel)
2024 {
2025 LIBSSH2_SESSION *session = channel->session;
2026 unsigned char channel_id[4];
2027 unsigned char *data;
2028 unsigned long data_len;
2029 int rc;
2030
2031 if (channel->free_state == libssh2_NB_state_idle) {
2032 _libssh2_debug(session, LIBSSH2_DBG_CONN,
2033 "Freeing channel %lu/%lu resources", channel->local.id,
2034 channel->remote.id);
2035
2036 channel->free_state = libssh2_NB_state_created;
2037 }
2038
2039 /* Allow channel freeing even when the socket has lost its connection */
2040 if (!channel->local.close
2041 && (session->socket_state == LIBSSH2_SOCKET_CONNECTED)) {
2042 while ((rc = libssh2_channel_close(channel)) == PACKET_EAGAIN);
2043 if (rc) {
2044 channel->free_state = libssh2_NB_state_idle;
2045 return -1;
2046 }
2047 }
2048
2049 channel->free_state = libssh2_NB_state_idle;
2050
2051 /*
2052 * channel->remote.close *might* not be set yet, Well...
2053 * We've sent the close packet, what more do you want?
2054 * Just let packet_add ignore it when it finally arrives
2055 */
2056
2057 /* Clear out packets meant for this channel */
2058 libssh2_htonu32(channel_id, channel->local.id);
2059 while ((libssh2_packet_ask_ex
2060 (session, SSH_MSG_CHANNEL_DATA, &data, &data_len, 1, channel_id, 4,
2061 0) >= 0)
2062 ||
2063 (libssh2_packet_ask_ex
2064 (session, SSH_MSG_CHANNEL_EXTENDED_DATA, &data, &data_len, 1,
2065 channel_id, 4, 0) >= 0)) {
2066 LIBSSH2_FREE(session, data);
2067 }
2068
2069 /* free "channel_type" */
2070 if (channel->channel_type) {
2071 LIBSSH2_FREE(session, channel->channel_type);
2072 }
2073
2074 /* Unlink from channel brigade */
2075 if (channel->prev) {
2076 channel->prev->next = channel->next;
2077 } else {
2078 session->channels.head = channel->next;
2079 }
2080 if (channel->next) {
2081 channel->next->prev = channel->prev;
2082 } else {
2083 session->channels.tail = channel->prev;
2084 }
2085
2086 /*
2087 * Make sure all memory used in the state variables are free
2088 */
2089 if (channel->setenv_packet) {
2090 LIBSSH2_FREE(session, channel->setenv_packet);
2091 }
2092 if (channel->reqPTY_packet) {
2093 LIBSSH2_FREE(session, channel->reqPTY_packet);
2094 }
2095 if (channel->reqX11_packet) {
2096 LIBSSH2_FREE(session, channel->reqX11_packet);
2097 }
2098 if (channel->process_packet) {
2099 LIBSSH2_FREE(session, channel->process_packet);
2100 }
2101 if (channel->write_packet) {
2102 LIBSSH2_FREE(session, channel->write_packet);
2103 }
2104
2105 LIBSSH2_FREE(session, channel);
2106
2107 return 0;
2108 }
2109
2110 /* }}} */
2111
2112 /* {{{ libssh2_channel_window_read_ex
2113 * Check the status of the read window
2114 * Returns the number of bytes which the remote end may send without overflowing the window limit
2115 * read_avail (if passed) will be populated with the number of bytes actually available to be read
2116 * window_size_initial (if passed) will be populated with the window_size_initial as defined by the channel_open request
2117 */
2118 LIBSSH2_API unsigned long
2119 libssh2_channel_window_read_ex(LIBSSH2_CHANNEL * channel,
2120 unsigned long *read_avail,
2121 unsigned long *window_size_initial)
2122 {
2123 if (window_size_initial) {
2124 *window_size_initial = channel->remote.window_size_initial;
2125 }
2126
2127 if (read_avail) {
2128 unsigned long bytes_queued = 0;
2129 LIBSSH2_PACKET *packet = channel->session->packets.head;
2130
2131 while (packet) {
2132 unsigned char packet_type = packet->data[0];
2133
2134 if (((packet_type == SSH_MSG_CHANNEL_DATA)
2135 || (packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA))
2136 && (libssh2_ntohu32(packet->data + 1) == channel->local.id)) {
2137 bytes_queued += packet->data_len - packet->data_head;
2138 }
2139
2140 packet = packet->next;
2141 }
2142
2143 *read_avail = bytes_queued;
2144 }
2145
2146 return channel->remote.window_size;
2147 }
2148
2149 /* }}} */
2150
2151 /* {{{ libssh2_channel_window_write_ex
2152 * Check the status of the write window
2153 * Returns the number of bytes which may be safely writen on the channel without blocking
2154 * window_size_initial (if passed) will be populated with the size of the initial window as defined by the channel_open request
2155 */
2156 LIBSSH2_API unsigned long
2157 libssh2_channel_window_write_ex(LIBSSH2_CHANNEL * channel,
2158 unsigned long *window_size_initial)
2159 {
2160 if (window_size_initial) {
2161 /* For locally initiated channels this is very often 0, so it's not *that* useful as information goes */
2162 *window_size_initial = channel->local.window_size_initial;
2163 }
2164
2165 return channel->local.window_size;
2166 }
2167
2168 /* }}} */