comparison common-channel.c @ 1173:d734fe76b72f coverity

merge
author Matt Johnston <matt@ucc.asn.au>
date Mon, 23 Nov 2015 23:04:48 +0800
parents 509cf5df51c6
children b370b4b172d0
comparison
equal deleted inserted replaced
1144:624fc24cfae5 1173:d734fe76b72f
40 static void send_msg_channel_open_failure(unsigned int remotechan, int reason, 40 static void send_msg_channel_open_failure(unsigned int remotechan, int reason,
41 const char *text, const char *lang); 41 const char *text, const char *lang);
42 static void send_msg_channel_open_confirmation(struct Channel* channel, 42 static void send_msg_channel_open_confirmation(struct Channel* channel,
43 unsigned int recvwindow, 43 unsigned int recvwindow,
44 unsigned int recvmaxpacket); 44 unsigned int recvmaxpacket);
45 static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf, 45 static int writechannel(struct Channel* channel, int fd, circbuffer *cbuf,
46 const unsigned char *moredata, unsigned int *morelen); 46 const unsigned char *moredata, unsigned int *morelen);
47 static void send_msg_channel_window_adjust(struct Channel *channel, 47 static void send_msg_channel_window_adjust(struct Channel *channel,
48 unsigned int incr); 48 unsigned int incr);
49 static void send_msg_channel_data(struct Channel *channel, int isextended); 49 static void send_msg_channel_data(struct Channel *channel, int isextended);
50 static void send_msg_channel_eof(struct Channel *channel); 50 static void send_msg_channel_eof(struct Channel *channel);
98 } 98 }
99 m_free(ses.channels); 99 m_free(ses.channels);
100 TRACE(("leave chancleanup")) 100 TRACE(("leave chancleanup"))
101 } 101 }
102 102
103 static void
104 chan_initwritebuf(struct Channel *channel)
105 {
106 dropbear_assert(channel->writebuf->size == 0 && channel->recvwindow == 0);
107 cbuf_free(channel->writebuf);
108 channel->writebuf = cbuf_new(opts.recv_window);
109 channel->recvwindow = opts.recv_window;
110 }
111
112 /* Create a new channel entry, send a reply confirm or failure */ 103 /* Create a new channel entry, send a reply confirm or failure */
113 /* If remotechan, transwindow and transmaxpacket are not know (for a new 104 /* If remotechan, transwindow and transmaxpacket are not know (for a new
114 * outgoing connection, with them to be filled on confirmation), they should 105 * outgoing connection, with them to be filled on confirmation), they should
115 * all be set to 0 */ 106 * all be set to 0 */
116 static struct Channel* newchannel(unsigned int remotechan, 107 static struct Channel* newchannel(unsigned int remotechan,
165 newchan->readfd = FD_UNINIT; 156 newchan->readfd = FD_UNINIT;
166 newchan->errfd = FD_CLOSED; /* this isn't always set to start with */ 157 newchan->errfd = FD_CLOSED; /* this isn't always set to start with */
167 newchan->await_open = 0; 158 newchan->await_open = 0;
168 newchan->flushing = 0; 159 newchan->flushing = 0;
169 160
170 newchan->writebuf = cbuf_new(0); /* resized later by chan_initwritebuf */ 161 newchan->writebuf = cbuf_new(opts.recv_window);
171 newchan->recvwindow = 0; 162 newchan->recvwindow = opts.recv_window;
172 163
173 newchan->extrabuf = NULL; /* The user code can set it up */ 164 newchan->extrabuf = NULL; /* The user code can set it up */
174 newchan->recvdonelen = 0; 165 newchan->recvdonelen = 0;
175 newchan->recvmaxpacket = RECV_MAX_CHANNEL_DATA_LEN; 166 newchan->recvmaxpacket = RECV_MAX_CHANNEL_DATA_LEN;
176 167
254 } 245 }
255 246
256 if (ses.channel_signal_pending) { 247 if (ses.channel_signal_pending) {
257 /* SIGCHLD can change channel state for server sessions */ 248 /* SIGCHLD can change channel state for server sessions */
258 do_check_close = 1; 249 do_check_close = 1;
259 ses.channel_signal_pending = 0;
260 } 250 }
261 251
262 /* handle any channel closing etc */ 252 /* handle any channel closing etc */
263 if (do_check_close) { 253 if (do_check_close) {
264 check_close(channel); 254 check_close(channel);
265 } 255 }
266 } 256 }
257
258 ses.channel_signal_pending = 0;
267 259
268 #ifdef USING_LISTENERS 260 #ifdef USING_LISTENERS
269 handle_listeners(readfds); 261 handle_listeners(readfds);
270 #endif 262 #endif
271 } 263 }
376 368
377 if (result == DROPBEAR_SUCCESS) 369 if (result == DROPBEAR_SUCCESS)
378 { 370 {
379 channel->readfd = channel->writefd = sock; 371 channel->readfd = channel->writefd = sock;
380 channel->conn_pending = NULL; 372 channel->conn_pending = NULL;
381 chan_initwritebuf(channel);
382 send_msg_channel_open_confirmation(channel, channel->recvwindow, 373 send_msg_channel_open_confirmation(channel, channel->recvwindow,
383 channel->recvmaxpacket); 374 channel->recvmaxpacket);
384 TRACE(("leave channel_connect_done: success")) 375 TRACE(("leave channel_connect_done: success"))
385 } 376 }
386 else 377 else
433 424
434 TRACE(("leave send_msg_channel_eof")) 425 TRACE(("leave send_msg_channel_eof"))
435 } 426 }
436 427
437 #ifndef HAVE_WRITEV 428 #ifndef HAVE_WRITEV
438 static void writechannel_fallback(struct Channel* channel, int fd, circbuffer *cbuf, 429 static int writechannel_fallback(struct Channel* channel, int fd, circbuffer *cbuf,
439 const unsigned char *UNUSED(moredata), unsigned int *morelen) { 430 const unsigned char *UNUSED(moredata), unsigned int *morelen) {
440 431
441 unsigned char *circ_p1, *circ_p2; 432 unsigned char *circ_p1, *circ_p2;
442 unsigned int circ_len1, circ_len2; 433 unsigned int circ_len1, circ_len2;
443 ssize_t written; 434 ssize_t written;
452 written = write(fd, circ_p1, circ_len1); 443 written = write(fd, circ_p1, circ_len1);
453 if (written < 0) { 444 if (written < 0) {
454 if (errno != EINTR && errno != EAGAIN) { 445 if (errno != EINTR && errno != EAGAIN) {
455 TRACE(("channel IO write error fd %d %s", fd, strerror(errno))) 446 TRACE(("channel IO write error fd %d %s", fd, strerror(errno)))
456 close_chan_fd(channel, fd, SHUT_WR); 447 close_chan_fd(channel, fd, SHUT_WR);
457 } 448 return DROPBEAR_FAILURE;
458 } else { 449 }
459 cbuf_incrread(cbuf, written); 450 }
460 channel->recvdonelen += written; 451 cbuf_incrread(cbuf, written);
461 } 452 channel->recvdonelen += written;
453 return DROPBEAR_SUCCESS;
462 } 454 }
463 #endif /* !HAVE_WRITEV */ 455 #endif /* !HAVE_WRITEV */
464 456
465 #ifdef HAVE_WRITEV 457 #ifdef HAVE_WRITEV
466 static void writechannel_writev(struct Channel* channel, int fd, circbuffer *cbuf, 458 static int writechannel_writev(struct Channel* channel, int fd, circbuffer *cbuf,
467 const unsigned char *moredata, unsigned int *morelen) { 459 const unsigned char *moredata, unsigned int *morelen) {
468 460
469 struct iovec iov[3]; 461 struct iovec iov[3];
470 unsigned char *circ_p1, *circ_p2; 462 unsigned char *circ_p1, *circ_p2;
471 unsigned int circ_len1, circ_len2; 463 unsigned int circ_len1, circ_len2;
472 int io_count = 0; 464 int io_count = 0;
473 465 int cbuf_written;
474 ssize_t written; 466 ssize_t written;
475 467
476 cbuf_readptrs(cbuf, &circ_p1, &circ_len1, &circ_p2, &circ_len2); 468 cbuf_readptrs(cbuf, &circ_p1, &circ_len1, &circ_p2, &circ_len2);
477 469
478 if (circ_len1 > 0) { 470 if (circ_len1 > 0) {
500 if (io_count == 0) { 492 if (io_count == 0) {
501 /* writechannel may sometimes be called twice in a main loop iteration. 493 /* writechannel may sometimes be called twice in a main loop iteration.
502 From common_recv_msg_channel_data() then channelio(). 494 From common_recv_msg_channel_data() then channelio().
503 The second call may not have any data to write, so we just return. */ 495 The second call may not have any data to write, so we just return. */
504 TRACE(("leave writechannel, no data")) 496 TRACE(("leave writechannel, no data"))
505 return; 497 return DROPBEAR_SUCCESS;
506 } 498 }
507 499
508 if (morelen) { 500 if (morelen) {
509 /* Default return value, none consumed */ 501 /* Default return value, none consumed */
510 *morelen = 0; 502 *morelen = 0;
514 506
515 if (written < 0) { 507 if (written < 0) {
516 if (errno != EINTR && errno != EAGAIN) { 508 if (errno != EINTR && errno != EAGAIN) {
517 TRACE(("channel IO write error fd %d %s", fd, strerror(errno))) 509 TRACE(("channel IO write error fd %d %s", fd, strerror(errno)))
518 close_chan_fd(channel, fd, SHUT_WR); 510 close_chan_fd(channel, fd, SHUT_WR);
519 } 511 return DROPBEAR_FAILURE;
520 } else { 512 }
521 int cbuf_written = MIN(circ_len1+circ_len2, (unsigned int)written); 513 }
522 cbuf_incrread(cbuf, cbuf_written); 514
523 if (morelen) { 515 cbuf_written = MIN(circ_len1+circ_len2, (unsigned int)written);
524 *morelen = written - cbuf_written; 516 cbuf_incrread(cbuf, cbuf_written);
525 } 517 if (morelen) {
526 channel->recvdonelen += written; 518 *morelen = written - cbuf_written;
527 } 519 }
528 520 channel->recvdonelen += written;
521 return DROPBEAR_SUCCESS;
529 } 522 }
530 #endif /* HAVE_WRITEV */ 523 #endif /* HAVE_WRITEV */
531 524
532 /* Called to write data out to the local side of the channel. 525 /* Called to write data out to the local side of the channel.
533 Writes the circular buffer contents and also the "moredata" buffer 526 Writes the circular buffer contents and also the "moredata" buffer
534 if not null. Will ignore EAGAIN */ 527 if not null. Will ignore EAGAIN.
535 static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf, 528 Returns DROPBEAR_FAILURE if writing to fd had an error and the channel is being closed, DROPBEAR_SUCCESS otherwise */
529 static int writechannel(struct Channel* channel, int fd, circbuffer *cbuf,
536 const unsigned char *moredata, unsigned int *morelen) { 530 const unsigned char *moredata, unsigned int *morelen) {
531 int ret = DROPBEAR_SUCCESS;
537 TRACE(("enter writechannel fd %d", fd)) 532 TRACE(("enter writechannel fd %d", fd))
538 #ifdef HAVE_WRITEV 533 #ifdef HAVE_WRITEV
539 writechannel_writev(channel, fd, cbuf, moredata, morelen); 534 ret = writechannel_writev(channel, fd, cbuf, moredata, morelen);
540 #else 535 #else
541 writechannel_fallback(channel, fd, cbuf, moredata, morelen); 536 ret = writechannel_fallback(channel, fd, cbuf, moredata, morelen);
542 #endif 537 #endif
543 538
544 /* Window adjust handling */ 539 /* Window adjust handling */
545 if (channel->recvdonelen >= RECV_WINDOWEXTEND) { 540 if (channel->recvdonelen >= RECV_WINDOWEXTEND) {
546 send_msg_channel_window_adjust(channel, channel->recvdonelen); 541 send_msg_channel_window_adjust(channel, channel->recvdonelen);
552 dropbear_assert(channel->recvwindow <= cbuf_getavail(channel->writebuf)); 547 dropbear_assert(channel->recvwindow <= cbuf_getavail(channel->writebuf));
553 dropbear_assert(channel->extrabuf == NULL || 548 dropbear_assert(channel->extrabuf == NULL ||
554 channel->recvwindow <= cbuf_getavail(channel->extrabuf)); 549 channel->recvwindow <= cbuf_getavail(channel->extrabuf));
555 550
556 TRACE(("leave writechannel")) 551 TRACE(("leave writechannel"))
552 return ret;
557 } 553 }
558 554
559 555
560 /* Set the file descriptors for the main select in session.c 556 /* Set the file descriptors for the main select in session.c
561 * This avoid channels which don't have any window available, are closed, etc*/ 557 * This avoid channels which don't have any window available, are closed, etc*/
826 unsigned int datalen; 822 unsigned int datalen;
827 unsigned int maxdata; 823 unsigned int maxdata;
828 unsigned int buflen; 824 unsigned int buflen;
829 unsigned int len; 825 unsigned int len;
830 unsigned int consumed; 826 unsigned int consumed;
827 int res;
831 828
832 TRACE(("enter recv_msg_channel_data")) 829 TRACE(("enter recv_msg_channel_data"))
833 830
834 if (channel->recv_eof) { 831 if (channel->recv_eof) {
835 dropbear_exit("Received data after eof"); 832 dropbear_exit("Received data after eof");
858 channel->recvwindow -= datalen; 855 channel->recvwindow -= datalen;
859 dropbear_assert(channel->recvwindow <= opts.recv_window); 856 dropbear_assert(channel->recvwindow <= opts.recv_window);
860 857
861 /* Attempt to write the data immediately without having to put it in the circular buffer */ 858 /* Attempt to write the data immediately without having to put it in the circular buffer */
862 consumed = datalen; 859 consumed = datalen;
863 writechannel(channel, fd, cbuf, buf_getptr(ses.payload, datalen), &consumed); 860 res = writechannel(channel, fd, cbuf, buf_getptr(ses.payload, datalen), &consumed);
864 861
865 datalen -= consumed; 862 datalen -= consumed;
866 buf_incrpos(ses.payload, consumed); 863 buf_incrpos(ses.payload, consumed);
867 864
868 865
869 /* We may have to run throught twice, if the buffer wraps around. Can't 866 /* We may have to run throught twice, if the buffer wraps around. Can't
870 * just "leave it for next time" like with writechannel, since this 867 * just "leave it for next time" like with writechannel, since this
871 * is payload data */ 868 * is payload data.
872 len = datalen; 869 * If the writechannel() failed then remaining data is discarded */
873 while (len > 0) { 870 if (res == DROPBEAR_SUCCESS) {
874 buflen = cbuf_writelen(cbuf); 871 len = datalen;
875 buflen = MIN(buflen, len); 872 while (len > 0) {
876 873 buflen = cbuf_writelen(cbuf);
877 memcpy(cbuf_writeptr(cbuf, buflen), 874 buflen = MIN(buflen, len);
878 buf_getptr(ses.payload, buflen), buflen); 875
879 cbuf_incrwrite(cbuf, buflen); 876 memcpy(cbuf_writeptr(cbuf, buflen),
880 buf_incrpos(ses.payload, buflen); 877 buf_getptr(ses.payload, buflen), buflen);
881 len -= buflen; 878 cbuf_incrwrite(cbuf, buflen);
879 buf_incrpos(ses.payload, buflen);
880 len -= buflen;
881 }
882 } 882 }
883 883
884 TRACE(("leave recv_msg_channel_data")) 884 TRACE(("leave recv_msg_channel_data"))
885 } 885 }
886 886
968 /* create the channel */ 968 /* create the channel */
969 channel = newchannel(remotechan, chantype, transwindow, transmaxpacket); 969 channel = newchannel(remotechan, chantype, transwindow, transmaxpacket);
970 970
971 if (channel == NULL) { 971 if (channel == NULL) {
972 TRACE(("newchannel returned NULL")) 972 TRACE(("newchannel returned NULL"))
973 errtype = SSH_OPEN_RESOURCE_SHORTAGE;
973 goto failure; 974 goto failure;
974 } 975 }
975 976
976 if (channel->type->inithandler) { 977 if (channel->type->inithandler) {
977 ret = channel->type->inithandler(channel); 978 ret = channel->type->inithandler(channel);
988 } 989 }
989 990
990 if (channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) { 991 if (channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) {
991 channel->prio = DROPBEAR_CHANNEL_PRIO_BULK; 992 channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
992 } 993 }
993
994 chan_initwritebuf(channel);
995 994
996 /* success */ 995 /* success */
997 send_msg_channel_open_confirmation(channel, channel->recvwindow, 996 send_msg_channel_open_confirmation(channel, channel->recvwindow,
998 channel->recvmaxpacket); 997 channel->recvmaxpacket);
999 goto cleanup; 998 goto cleanup;
1133 return DROPBEAR_FAILURE; 1132 return DROPBEAR_FAILURE;
1134 } 1133 }
1135 1134
1136 /* Outbound opened channels don't make use of in-progress connections, 1135 /* Outbound opened channels don't make use of in-progress connections,
1137 * we can set it up straight away */ 1136 * we can set it up straight away */
1138 chan_initwritebuf(chan);
1139 1137
1140 /* set fd non-blocking */ 1138 /* set fd non-blocking */
1141 setnonblocking(fd); 1139 setnonblocking(fd);
1142 1140
1143 chan->writefd = chan->readfd = fd; 1141 chan->writefd = chan->readfd = fd;