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