Mercurial > dropbear
comparison common-channel.c @ 416:a01c0c8e543a channel-fix
Improve behaviour when flushing out after a process has exited.
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Fri, 09 Feb 2007 10:43:16 +0000 |
parents | 8b9aba1d5fa4 |
children | b2b67cfcd66e |
comparison
equal
deleted
inserted
replaced
415:8b9aba1d5fa4 | 416:a01c0c8e543a |
---|---|
146 newchan->writefd = FD_UNINIT; | 146 newchan->writefd = FD_UNINIT; |
147 newchan->readfd = FD_UNINIT; | 147 newchan->readfd = FD_UNINIT; |
148 newchan->errfd = FD_CLOSED; /* this isn't always set to start with */ | 148 newchan->errfd = FD_CLOSED; /* this isn't always set to start with */ |
149 newchan->initconn = 0; | 149 newchan->initconn = 0; |
150 newchan->await_open = 0; | 150 newchan->await_open = 0; |
151 newchan->flushing = 0; | |
151 | 152 |
152 newchan->writebuf = cbuf_new(RECV_MAXWINDOW); | 153 newchan->writebuf = cbuf_new(RECV_MAXWINDOW); |
153 newchan->extrabuf = NULL; /* The user code can set it up */ | 154 newchan->extrabuf = NULL; /* The user code can set it up */ |
154 newchan->recvwindow = RECV_MAXWINDOW; | 155 newchan->recvwindow = RECV_MAXWINDOW; |
155 newchan->recvdonelen = 0; | 156 newchan->recvdonelen = 0; |
201 continue; | 202 continue; |
202 } | 203 } |
203 | 204 |
204 /* read data and send it over the wire */ | 205 /* read data and send it over the wire */ |
205 if (channel->readfd >= 0 && FD_ISSET(channel->readfd, readfds)) { | 206 if (channel->readfd >= 0 && FD_ISSET(channel->readfd, readfds)) { |
207 TRACE(("send normal readfd")) | |
206 send_msg_channel_data(channel, 0); | 208 send_msg_channel_data(channel, 0); |
207 } | 209 } |
208 | 210 |
209 /* read stderr data and send it over the wire */ | 211 /* read stderr data and send it over the wire */ |
210 if (ERRFD_IS_READ(channel) && | 212 if (ERRFD_IS_READ(channel) && channel->errfd >= 0 |
211 channel->errfd >= 0 && FD_ISSET(channel->errfd, readfds)) { | 213 && FD_ISSET(channel->errfd, readfds)) { |
214 TRACE(("send normal errfd")) | |
212 send_msg_channel_data(channel, 1); | 215 send_msg_channel_data(channel, 1); |
213 } | 216 } |
214 | 217 |
215 /* write to program/pipe stdin */ | 218 /* write to program/pipe stdin */ |
216 if (channel->writefd >= 0 && FD_ISSET(channel->writefd, writefds)) { | 219 if (channel->writefd >= 0 && FD_ISSET(channel->writefd, writefds)) { |
263 channel->errfd, channel->sent_close, channel->recv_close)) | 266 channel->errfd, channel->sent_close, channel->recv_close)) |
264 TRACE(("writebuf size %d extrabuf size %d", | 267 TRACE(("writebuf size %d extrabuf size %d", |
265 cbuf_getused(channel->writebuf), | 268 cbuf_getused(channel->writebuf), |
266 channel->extrabuf ? cbuf_getused(channel->extrabuf) : 0)) | 269 channel->extrabuf ? cbuf_getused(channel->extrabuf) : 0)) |
267 | 270 |
271 if (!channel->flushing && channel->type->check_close | |
272 && channel->type->check_close(channel)) | |
273 { | |
274 channel->flushing = 1; | |
275 } | |
276 | |
268 if (channel->recv_close && !write_pending(channel)) { | 277 if (channel->recv_close && !write_pending(channel)) { |
269 if (! channel->sent_close) { | 278 if (!channel->sent_close) { |
270 TRACE(("Sending MSG_CHANNEL_CLOSE in response to same.")) | 279 TRACE(("Sending MSG_CHANNEL_CLOSE in response to same.")) |
271 send_msg_channel_close(channel); | 280 send_msg_channel_close(channel); |
272 } | 281 } |
273 remove_channel(channel); | 282 remove_channel(channel); |
274 return; | 283 return; |
275 } | 284 } |
276 | 285 |
277 if (channel->recv_eof && !write_pending(channel)) { | 286 if (channel->recv_eof && !write_pending(channel)) { |
278 close_chan_fd(channel, channel->writefd, SHUT_WR); | 287 close_chan_fd(channel, channel->writefd, SHUT_WR); |
288 } | |
289 | |
290 /* Special handling for flushing read data after an exit. We | |
291 read regardless of whether the select FD was set, | |
292 and if there isn't data available, the channel will get closed. */ | |
293 if (channel->flushing) { | |
294 TRACE(("might send data, flushing")) | |
295 if (channel->readfd >= 0 && channel->transwindow > 0) { | |
296 TRACE(("send data readfd")) | |
297 send_msg_channel_data(channel, 0); | |
298 } | |
299 if (ERRFD_IS_READ(channel) && channel->readfd >= 0 | |
300 && channel->transwindow > 0) { | |
301 TRACE(("send data errfd")) | |
302 send_msg_channel_data(channel, 1); | |
303 } | |
279 } | 304 } |
280 | 305 |
281 /* If we're not going to send any more data, send EOF */ | 306 /* If we're not going to send any more data, send EOF */ |
282 if (!channel->sent_eof | 307 if (!channel->sent_eof |
283 && channel->readfd == FD_CLOSED | 308 && channel->readfd == FD_CLOSED |
285 send_msg_channel_eof(channel); | 310 send_msg_channel_eof(channel); |
286 } | 311 } |
287 | 312 |
288 /* And if we can't receive any more data from them either, close up */ | 313 /* And if we can't receive any more data from them either, close up */ |
289 if (!channel->sent_close | 314 if (!channel->sent_close |
290 && channel->writefd == FD_CLOSED | |
291 && channel->readfd == FD_CLOSED | 315 && channel->readfd == FD_CLOSED |
292 && channel->errfd == FD_CLOSED) { | 316 && !write_pending(channel)) { |
317 TRACE(("sending close, readfd is closed")) | |
293 send_msg_channel_close(channel); | 318 send_msg_channel_close(channel); |
294 } | 319 } |
295 | 320 } |
296 } | |
297 | |
298 | 321 |
299 /* Check whether a deferred (EINPROGRESS) connect() was successful, and | 322 /* Check whether a deferred (EINPROGRESS) connect() was successful, and |
300 * if so, set up the channel properly. Otherwise, the channel is cleaned up, so | 323 * if so, set up the channel properly. Otherwise, the channel is cleaned up, so |
301 * it is important that the channel reference isn't used after a call to this | 324 * it is important that the channel reference isn't used after a call to this |
302 * function */ | 325 * function */ |
339 | 362 |
340 encrypt_packet(); | 363 encrypt_packet(); |
341 | 364 |
342 channel->sent_eof = 1; | 365 channel->sent_eof = 1; |
343 channel->sent_close = 1; | 366 channel->sent_close = 1; |
367 close_chan_fd(channel, channel->readfd, SHUT_RD); | |
368 close_chan_fd(channel, channel->errfd, SHUT_RDWR); | |
369 close_chan_fd(channel, channel->writefd, SHUT_WR); | |
344 TRACE(("leave send_msg_channel_close")) | 370 TRACE(("leave send_msg_channel_close")) |
345 } | 371 } |
346 | 372 |
347 /* call this when trans/eof channels are closed */ | 373 /* call this when trans/eof channels are closed */ |
348 static void send_msg_channel_eof(struct Channel *channel) { | 374 static void send_msg_channel_eof(struct Channel *channel) { |
554 size_t maxlen, size_pos; | 580 size_t maxlen, size_pos; |
555 int fd; | 581 int fd; |
556 | 582 |
557 CHECKCLEARTOWRITE(); | 583 CHECKCLEARTOWRITE(); |
558 | 584 |
585 TRACE(("enter send_msg_channel_data")) | |
559 dropbear_assert(!channel->sent_close); | 586 dropbear_assert(!channel->sent_close); |
560 | 587 |
561 if (isextended) { | 588 if (isextended) { |
562 fd = channel->errfd; | 589 fd = channel->errfd; |
563 } else { | 590 } else { |
589 | 616 |
590 /* read the data */ | 617 /* read the data */ |
591 len = read(fd, buf_getwriteptr(ses.writepayload, maxlen), maxlen); | 618 len = read(fd, buf_getwriteptr(ses.writepayload, maxlen), maxlen); |
592 if (len <= 0) { | 619 if (len <= 0) { |
593 if (len == 0 || errno != EINTR) { | 620 if (len == 0 || errno != EINTR) { |
621 /* This will also get hit in the case of EAGAIN. The only | |
622 time we expect to receive EAGAIN is when we're flushing a FD, | |
623 in which case it can be treated the same as EOF */ | |
594 close_chan_fd(channel, fd, SHUT_RD); | 624 close_chan_fd(channel, fd, SHUT_RD); |
595 } | 625 } |
596 ses.writepayload->len = ses.writepayload->pos = 0; | 626 ses.writepayload->len = ses.writepayload->pos = 0; |
597 TRACE(("leave send_msg_channel_data: len %d read err or EOF for fd %d", | 627 TRACE(("leave send_msg_channel_data: len %d read err or EOF for fd %d", |
598 len, channel->index)); | 628 len, channel->index)); |
604 buf_putint(ses.writepayload, len); | 634 buf_putint(ses.writepayload, len); |
605 | 635 |
606 channel->transwindow -= len; | 636 channel->transwindow -= len; |
607 | 637 |
608 encrypt_packet(); | 638 encrypt_packet(); |
639 | |
640 /* If we receive less data than we requested when flushing, we've | |
641 reached the equivalent of EOF */ | |
642 if (channel->flushing && len < maxlen) | |
643 { | |
644 TRACE(("closing from channel, flushing out.")) | |
645 close_chan_fd(channel, fd, SHUT_RD); | |
646 } | |
609 TRACE(("leave send_msg_channel_data")) | 647 TRACE(("leave send_msg_channel_data")) |
610 } | 648 } |
611 | 649 |
612 /* We receive channel data */ | 650 /* We receive channel data */ |
613 void recv_msg_channel_data() { | 651 void recv_msg_channel_data() { |