Mercurial > dropbear
comparison common-channel.c @ 108:10f4d3319780
- added circular buffering for channels
- added stderr support for the client
- cleaned up a bunch of "unused" warnings, duplicated header definitions
- added exit-status support for the client
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Thu, 26 Aug 2004 13:16:40 +0000 |
parents | d3eb1fa8484e |
children | 2e9d1f29c50f |
comparison
equal
deleted
inserted
replaced
107:d3eb1fa8484e | 108:10f4d3319780 |
---|---|
38 static void send_msg_channel_open_failure(unsigned int remotechan, int reason, | 38 static void send_msg_channel_open_failure(unsigned int remotechan, int reason, |
39 const unsigned char *text, const unsigned char *lang); | 39 const unsigned char *text, const unsigned char *lang); |
40 static void send_msg_channel_open_confirmation(struct Channel* channel, | 40 static void send_msg_channel_open_confirmation(struct Channel* channel, |
41 unsigned int recvwindow, | 41 unsigned int recvwindow, |
42 unsigned int recvmaxpacket); | 42 unsigned int recvmaxpacket); |
43 static void writechannel(struct Channel *channel); | 43 static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf); |
44 static void send_msg_channel_window_adjust(struct Channel *channel, | 44 static void send_msg_channel_window_adjust(struct Channel *channel, |
45 unsigned int incr); | 45 unsigned int incr); |
46 static void send_msg_channel_data(struct Channel *channel, int isextended, | 46 static void send_msg_channel_data(struct Channel *channel, int isextended, |
47 unsigned int exttype); | 47 unsigned int exttype); |
48 static void send_msg_channel_eof(struct Channel *channel); | 48 static void send_msg_channel_eof(struct Channel *channel); |
149 newchan->initconn = 0; | 149 newchan->initconn = 0; |
150 | 150 |
151 newchan->writebuf = cbuf_new(RECV_MAXWINDOW); | 151 newchan->writebuf = cbuf_new(RECV_MAXWINDOW); |
152 newchan->extrabuf = NULL; /* The user code can set it up */ | 152 newchan->extrabuf = NULL; /* The user code can set it up */ |
153 newchan->recvwindow = RECV_MAXWINDOW; | 153 newchan->recvwindow = RECV_MAXWINDOW; |
154 newchan->recvdonelen = 0; | |
154 newchan->recvmaxpacket = RECV_MAXPACKET; | 155 newchan->recvmaxpacket = RECV_MAXPACKET; |
155 | 156 |
156 ses.channels[i] = newchan; | 157 ses.channels[i] = newchan; |
157 ses.chancount++; | 158 ses.chancount++; |
158 | 159 |
218 if (channel->initconn) { | 219 if (channel->initconn) { |
219 checkinitdone(channel); | 220 checkinitdone(channel); |
220 continue; /* Important not to use the channel after | 221 continue; /* Important not to use the channel after |
221 checkinitdone(), as it may be NULL */ | 222 checkinitdone(), as it may be NULL */ |
222 } | 223 } |
223 writechannel(channel); | 224 writechannel(channel, channel->infd, channel->writebuf); |
225 } | |
226 | |
227 /* stderr for client mode */ | |
228 if (channel->extrabuf != NULL | |
229 && channel->errfd >= 0 && FD_ISSET(channel->errfd, writefd)) { | |
230 writechannel(channel, channel->errfd, channel->extrabuf); | |
224 } | 231 } |
225 | 232 |
226 /* now handle any of the channel-closing type stuff */ | 233 /* now handle any of the channel-closing type stuff */ |
227 checkclose(channel); | 234 checkclose(channel); |
228 | 235 |
348 } | 355 } |
349 | 356 |
350 /* Called to write data out to the local side of the channel. | 357 /* Called to write data out to the local side of the channel. |
351 * Only called when we know we can write to a channel, writes as much as | 358 * Only called when we know we can write to a channel, writes as much as |
352 * possible */ | 359 * possible */ |
353 static void writechannel(struct Channel* channel) { | 360 static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) { |
354 | 361 |
355 int len, maxlen; | 362 int len, maxlen; |
356 circbuffer *cbuf; | |
357 | 363 |
358 TRACE(("enter writechannel")); | 364 TRACE(("enter writechannel")); |
359 | 365 |
360 cbuf = channel->writebuf; | |
361 maxlen = cbuf_readlen(cbuf); | 366 maxlen = cbuf_readlen(cbuf); |
362 | 367 |
363 TRACE(("maxlen = %d", maxlen)); | |
364 | |
365 /* Write the data out */ | 368 /* Write the data out */ |
366 len = write(channel->infd, cbuf_readptr(cbuf, maxlen), maxlen); | 369 len = write(fd, cbuf_readptr(cbuf, maxlen), maxlen); |
367 if (len <= 0) { | 370 if (len <= 0) { |
368 if (len < 0 && errno != EINTR) { | 371 if (len < 0 && errno != EINTR) { |
369 /* no more to write */ | 372 /* no more to write - we close it even if the fd was stderr, since |
373 * that's a nasty failure too */ | |
370 closeinfd(channel); | 374 closeinfd(channel); |
371 } | 375 } |
372 TRACE(("leave writechannel: len <= 0")); | 376 TRACE(("leave writechannel: len <= 0")); |
373 return; | 377 return; |
374 } | 378 } |
375 | 379 |
376 TRACE(("len = %d", len)); | |
377 cbuf_incrread(cbuf, len); | 380 cbuf_incrread(cbuf, len); |
378 | 381 channel->recvdonelen += len; |
379 if (len == maxlen && channel->recveof) { | 382 |
383 if (fd == channel->infd && len == maxlen && channel->recveof) { | |
380 /* Check if we're closing up */ | 384 /* Check if we're closing up */ |
381 closeinfd(channel); | 385 closeinfd(channel); |
382 return; | 386 return; |
383 TRACE(("leave writechannel: recveof set")); | 387 TRACE(("leave writechannel: recveof set")); |
384 | 388 |
385 } | 389 } |
386 | 390 |
387 /* Window adjust handling */ | 391 /* Window adjust handling */ |
388 if (channel->recvwindow < (RECV_MAXWINDOW - RECV_WINDOWEXTEND)) { | 392 if (channel->recvdonelen >= RECV_WINDOWEXTEND) { |
389 /* Set it back to max window */ | 393 /* Set it back to max window */ |
390 send_msg_channel_window_adjust(channel, RECV_MAXWINDOW - | 394 send_msg_channel_window_adjust(channel, channel->recvdonelen); |
391 channel->recvwindow); | 395 channel->recvwindow += channel->recvdonelen; |
392 channel->recvwindow = RECV_MAXWINDOW; | 396 channel->recvdonelen = 0; |
393 } | 397 } |
398 | |
399 assert(channel->recvwindow <= RECV_MAXWINDOW); | |
400 assert(channel->recvwindow <= cbuf_getavail(channel->writebuf)); | |
401 assert(channel->extrabuf == NULL || | |
402 channel->recvwindow <= cbuf_getavail(channel->extrabuf)); | |
394 | 403 |
395 | 404 |
396 TRACE(("leave writechannel")); | 405 TRACE(("leave writechannel")); |
397 } | 406 } |
398 | 407 |
422 } | 431 } |
423 } | 432 } |
424 | 433 |
425 /* For checking FD status (ie closure etc) - we don't actually | 434 /* For checking FD status (ie closure etc) - we don't actually |
426 * read data from infd */ | 435 * read data from infd */ |
436 TRACE(("infd = %d, outfd %d, bufused %d", channel->infd, channel->outfd, | |
437 cbuf_getused(channel->writebuf) )); | |
427 if (channel->infd >= 0 && channel->infd != channel->outfd) { | 438 if (channel->infd >= 0 && channel->infd != channel->outfd) { |
428 FD_SET(channel->infd, readfd); | 439 FD_SET(channel->infd, readfd); |
429 } | 440 } |
430 | 441 |
431 /* Stuff from the wire, to local program/shell/user etc */ | 442 /* Stuff from the wire, to local program/shell/user etc */ |
433 || channel->initconn) { | 444 || channel->initconn) { |
434 | 445 |
435 FD_SET(channel->infd, writefd); | 446 FD_SET(channel->infd, writefd); |
436 } | 447 } |
437 | 448 |
438 /* | |
439 if (channel->extrabuf != NULL && channel->errfd >= 0 | 449 if (channel->extrabuf != NULL && channel->errfd >= 0 |
440 && cbuf_getavail(channel->extrabuf) > 0 ) { | 450 && cbuf_getused(channel->extrabuf) > 0 ) { |
441 FD_SET(channel->errfd, writefd); | 451 FD_SET(channel->errfd, writefd); |
442 } | 452 } |
443 */ | |
444 | 453 |
445 } /* foreach channel */ | 454 } /* foreach channel */ |
446 | 455 |
447 #ifdef USING_LISTENERS | 456 #ifdef USING_LISTENERS |
448 set_listener_fds(readfd); | 457 set_listener_fds(readfd); |
466 if (channel == NULL) { | 475 if (channel == NULL) { |
467 dropbear_exit("EOF for unknown channel"); | 476 dropbear_exit("EOF for unknown channel"); |
468 } | 477 } |
469 | 478 |
470 channel->recveof = 1; | 479 channel->recveof = 1; |
471 if (cbuf_getused(channel->writebuf) == 0) { | 480 if (cbuf_getused(channel->writebuf) == 0 |
481 && (channel->extrabuf == NULL | |
482 || cbuf_getused(channel->extrabuf) == 0)) { | |
472 closeinfd(channel); | 483 closeinfd(channel); |
473 } | 484 } |
474 | 485 |
475 TRACE(("leave recv_msg_channel_eof")); | 486 TRACE(("leave recv_msg_channel_eof")); |
476 } | 487 } |
676 dropbear_exit("received data with bad infd"); | 687 dropbear_exit("received data with bad infd"); |
677 } | 688 } |
678 | 689 |
679 datalen = buf_getint(ses.payload); | 690 datalen = buf_getint(ses.payload); |
680 | 691 |
681 TRACE(("datalen = %d", datalen)); | 692 |
682 | |
683 /* if the client is going to send us more data than we've allocated, then | |
684 * it has ignored the windowsize, so we "MAY ignore all extra data" */ | |
685 maxdata = cbuf_getavail(cbuf); | 693 maxdata = cbuf_getavail(cbuf); |
686 TRACE(("maxdata = %d", maxdata)); | 694 |
695 /* Whilst the spec says we "MAY ignore data past the end" this could | |
696 * lead to corrupted file transfers etc (chunks missed etc). It's better to | |
697 * just die horribly */ | |
687 if (datalen > maxdata) { | 698 if (datalen > maxdata) { |
688 TRACE(("Warning: recv_msg_channel_data: extra data past window")); | 699 dropbear_exit("Oversized packet"); |
689 datalen = maxdata; | 700 } |
690 } | |
691 | |
692 | 701 |
693 /* We may have to run throught twice, if the buffer wraps around. Can't | 702 /* We may have to run throught twice, if the buffer wraps around. Can't |
694 * just "leave it for next time" like with writechannel, since this | 703 * just "leave it for next time" like with writechannel, since this |
695 * is payload data */ | 704 * is payload data */ |
696 len = datalen; | 705 len = datalen; |
697 while (len > 0) { | 706 while (len > 0) { |
698 buflen = cbuf_writelen(cbuf); | 707 buflen = cbuf_writelen(cbuf); |
699 TRACE(("buflen = %d", buflen)); | |
700 buflen = MIN(buflen, len); | 708 buflen = MIN(buflen, len); |
701 TRACE(("buflenmin = %d", buflen)); | |
702 | 709 |
703 memcpy(cbuf_writeptr(cbuf, buflen), | 710 memcpy(cbuf_writeptr(cbuf, buflen), |
704 buf_getptr(ses.payload, buflen), buflen); | 711 buf_getptr(ses.payload, buflen), buflen); |
705 cbuf_incrwrite(cbuf, buflen); | 712 cbuf_incrwrite(cbuf, buflen); |
713 buf_incrpos(ses.payload, buflen); | |
706 len -= buflen; | 714 len -= buflen; |
707 TRACE(("len = %d", buflen)); | 715 } |
708 } | 716 |
709 | 717 assert(channel->recvwindow > datalen); |
710 channel->recvwindow -= datalen; | 718 channel->recvwindow -= datalen; |
719 assert(channel->recvwindow <= RECV_MAXWINDOW); | |
711 | 720 |
712 TRACE(("leave recv_msg_channel_data")); | 721 TRACE(("leave recv_msg_channel_data")); |
713 } | 722 } |
714 | 723 |
715 /* Increment the outgoing data window for a channel - the remote end limits | 724 /* Increment the outgoing data window for a channel - the remote end limits |