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() {