comparison common-channel.c @ 253:84925eceeb13

* rename infd/outfd to writefd/readfd, to avoid confusion
author Matt Johnston <matt@ucc.asn.au>
date Thu, 20 Oct 2005 16:53:12 +0000
parents 0056419cf0f4
children 82393badfa24
comparison
equal deleted inserted replaced
251:b02e8eef3c3a 253:84925eceeb13
50 static void removechannel(struct Channel *channel); 50 static void removechannel(struct Channel *channel);
51 static void deletechannel(struct Channel *channel); 51 static void deletechannel(struct Channel *channel);
52 static void checkinitdone(struct Channel *channel); 52 static void checkinitdone(struct Channel *channel);
53 static void checkclose(struct Channel *channel); 53 static void checkclose(struct Channel *channel);
54 54
55 static void closeinfd(struct Channel * channel); 55 static void closewritefd(struct Channel * channel);
56 static void closeoutfd(struct Channel * channel, int fd); 56 static void closereadfd(struct Channel * channel, int fd);
57 static void closechanfd(struct Channel *channel, int fd, int how); 57 static void closechanfd(struct Channel *channel, int fd, int how);
58 58
59 #define FD_UNINIT (-2) 59 #define FD_UNINIT (-2)
60 #define FD_CLOSED (-1) 60 #define FD_CLOSED (-1)
61 61
141 newchan->remotechan = remotechan; 141 newchan->remotechan = remotechan;
142 newchan->transwindow = transwindow; 142 newchan->transwindow = transwindow;
143 newchan->transmaxpacket = transmaxpacket; 143 newchan->transmaxpacket = transmaxpacket;
144 144
145 newchan->typedata = NULL; 145 newchan->typedata = NULL;
146 newchan->infd = FD_UNINIT; 146 newchan->writefd = FD_UNINIT;
147 newchan->outfd = 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 151
152 newchan->writebuf = cbuf_new(RECV_MAXWINDOW); 152 newchan->writebuf = cbuf_new(RECV_MAXWINDOW);
175 } 175 }
176 return ses.channels[chan]; 176 return ses.channels[chan];
177 } 177 }
178 178
179 /* Iterate through the channels, performing IO if available */ 179 /* Iterate through the channels, performing IO if available */
180 void channelio(fd_set *readfd, fd_set *writefd) { 180 void channelio(fd_set *readfds, fd_set *writefds) {
181 181
182 struct Channel *channel; 182 struct Channel *channel;
183 unsigned int i; 183 unsigned int i;
184 int ret; 184 int ret;
185 185
190 if (channel == NULL) { 190 if (channel == NULL) {
191 /* only process in-use channels */ 191 /* only process in-use channels */
192 continue; 192 continue;
193 } 193 }
194 194
195 /* read from program/pipe stdout */ 195 /* read data and send it over the wire */
196 if (channel->outfd >= 0 && FD_ISSET(channel->outfd, readfd)) { 196 if (channel->readfd >= 0 && FD_ISSET(channel->readfd, readfds)) {
197 send_msg_channel_data(channel, 0, 0); 197 send_msg_channel_data(channel, 0, 0);
198 } 198 }
199 199
200 /* read from program/pipe stderr */ 200 /* read stderr data and send it over the wire */
201 if (channel->extrabuf == NULL && 201 if (channel->extrabuf == NULL &&
202 channel->errfd >= 0 && FD_ISSET(channel->errfd, readfd)) { 202 channel->errfd >= 0 && FD_ISSET(channel->errfd, readfds)) {
203 send_msg_channel_data(channel, 1, SSH_EXTENDED_DATA_STDERR); 203 send_msg_channel_data(channel, 1, SSH_EXTENDED_DATA_STDERR);
204 } 204 }
205 205
206 /* if we can read from the infd, it might be closed, so we try to 206 /* if we can read from the writefd, it might be closed, so we try to
207 * see if it has errors */ 207 * see if it has errors */
208 if (channel->infd >= 0 && channel->infd != channel->outfd 208 if (channel->writefd >= 0 && channel->writefd != channel->readfd
209 && FD_ISSET(channel->infd, readfd)) { 209 && FD_ISSET(channel->writefd, readfds)) {
210 if (channel->initconn) { 210 if (channel->initconn) {
211 /* Handling for "in progress" connection - this is needed 211 /* Handling for "in progress" connection - this is needed
212 * to avoid spinning 100% CPU when we connect to a server 212 * to avoid spinning 100% CPU when we connect to a server
213 * which doesn't send anything (tcpfwding) */ 213 * which doesn't send anything (tcpfwding) */
214 checkinitdone(channel); 214 checkinitdone(channel);
215 continue; /* Important not to use the channel after 215 continue; /* Important not to use the channel after
216 checkinitdone(), as it may be NULL */ 216 checkinitdone(), as it may be NULL */
217 } 217 }
218 ret = write(channel->infd, NULL, 0); /* Fake write */ 218 ret = write(channel->writefd, NULL, 0); /* Fake write */
219 if (ret < 0 && errno != EINTR && errno != EAGAIN) { 219 if (ret < 0 && errno != EINTR && errno != EAGAIN) {
220 closeinfd(channel); 220 closewritefd(channel);
221 } 221 }
222 } 222 }
223 223
224 /* write to program/pipe stdin */ 224 /* write to program/pipe stdin */
225 if (channel->infd >= 0 && FD_ISSET(channel->infd, writefd)) { 225 if (channel->writefd >= 0 && FD_ISSET(channel->writefd, writefds)) {
226 if (channel->initconn) { 226 if (channel->initconn) {
227 checkinitdone(channel); 227 checkinitdone(channel);
228 continue; /* Important not to use the channel after 228 continue; /* Important not to use the channel after
229 checkinitdone(), as it may be NULL */ 229 checkinitdone(), as it may be NULL */
230 } 230 }
231 writechannel(channel, channel->infd, channel->writebuf); 231 writechannel(channel, channel->writefd, channel->writebuf);
232 } 232 }
233 233
234 /* stderr for client mode */ 234 /* stderr for client mode */
235 if (channel->extrabuf != NULL 235 if (channel->extrabuf != NULL
236 && channel->errfd >= 0 && FD_ISSET(channel->errfd, writefd)) { 236 && channel->errfd >= 0 && FD_ISSET(channel->errfd, writefds)) {
237 writechannel(channel, channel->errfd, channel->extrabuf); 237 writechannel(channel, channel->errfd, channel->extrabuf);
238 } 238 }
239 239
240 /* now handle any of the channel-closing type stuff */ 240 /* now handle any of the channel-closing type stuff */
241 checkclose(channel); 241 checkclose(channel);
242 242
243 } /* foreach channel */ 243 } /* foreach channel */
244 244
245 /* Listeners such as TCP, X11, agent-auth */ 245 /* Listeners such as TCP, X11, agent-auth */
246 #ifdef USING_LISTENERS 246 #ifdef USING_LISTENERS
247 handle_listeners(readfd); 247 handle_listeners(readfds);
248 #endif 248 #endif
249 } 249 }
250 250
251 251
252 /* do all the EOF/close type stuff checking for a channel */ 252 /* do all the EOF/close type stuff checking for a channel */
253 static void checkclose(struct Channel *channel) { 253 static void checkclose(struct Channel *channel) {
254 254
255 TRACE(("checkclose: infd %d, outfd %d, errfd %d, sentclosed %d, recvclosed %d", 255 TRACE(("checkclose: writefd %d, readfd %d, errfd %d, sentclosed %d, recvclosed %d",
256 channel->infd, channel->outfd, 256 channel->writefd, channel->readfd,
257 channel->errfd, channel->sentclosed, channel->recvclosed)) 257 channel->errfd, channel->sentclosed, channel->recvclosed))
258 TRACE(("writebuf %d extrabuf %s extrabuf %d", 258 TRACE(("writebuf %d extrabuf %s extrabuf %d",
259 cbuf_getused(channel->writebuf), 259 cbuf_getused(channel->writebuf),
260 channel->writebuf, 260 channel->writebuf,
261 channel->writebuf ? 0 : cbuf_getused(channel->extrabuf))) 261 channel->writebuf ? 0 : cbuf_getused(channel->extrabuf)))
264 264
265 /* check for exited - currently only used for server sessions, 265 /* check for exited - currently only used for server sessions,
266 * if the shell has exited etc */ 266 * if the shell has exited etc */
267 if (channel->type->checkclose) { 267 if (channel->type->checkclose) {
268 if (channel->type->checkclose(channel)) { 268 if (channel->type->checkclose(channel)) {
269 closeinfd(channel); 269 closewritefd(channel);
270 } 270 }
271 } 271 }
272 272
273 if (!channel->senteof 273 if (!channel->senteof
274 && channel->outfd == FD_CLOSED 274 && channel->readfd == FD_CLOSED
275 && (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) { 275 && (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) {
276 send_msg_channel_eof(channel); 276 send_msg_channel_eof(channel);
277 } 277 }
278 278
279 if (channel->infd == FD_CLOSED 279 if (channel->writefd == FD_CLOSED
280 && channel->outfd == FD_CLOSED 280 && channel->readfd == FD_CLOSED
281 && (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) { 281 && (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) {
282 send_msg_channel_close(channel); 282 send_msg_channel_close(channel);
283 } 283 }
284 } 284 }
285 285
312 int val; 312 int val;
313 socklen_t vallen = sizeof(val); 313 socklen_t vallen = sizeof(val);
314 314
315 TRACE(("enter checkinitdone")) 315 TRACE(("enter checkinitdone"))
316 316
317 if (getsockopt(channel->infd, SOL_SOCKET, SO_ERROR, &val, &vallen) 317 if (getsockopt(channel->writefd, SOL_SOCKET, SO_ERROR, &val, &vallen)
318 || val != 0) { 318 || val != 0) {
319 send_msg_channel_open_failure(channel->remotechan, 319 send_msg_channel_open_failure(channel->remotechan,
320 SSH_OPEN_CONNECT_FAILED, "", ""); 320 SSH_OPEN_CONNECT_FAILED, "", "");
321 close(channel->infd); 321 close(channel->writefd);
322 deletechannel(channel); 322 deletechannel(channel);
323 TRACE(("leave checkinitdone: fail")) 323 TRACE(("leave checkinitdone: fail"))
324 } else { 324 } else {
325 send_msg_channel_open_confirmation(channel, channel->recvwindow, 325 send_msg_channel_open_confirmation(channel, channel->recvwindow,
326 channel->recvmaxpacket); 326 channel->recvmaxpacket);
327 channel->outfd = channel->infd; 327 channel->readfd = channel->writefd;
328 channel->initconn = 0; 328 channel->initconn = 0;
329 TRACE(("leave checkinitdone: success")) 329 TRACE(("leave checkinitdone: success"))
330 } 330 }
331 } 331 }
332 332
384 len = write(fd, cbuf_readptr(cbuf, maxlen), maxlen); 384 len = write(fd, cbuf_readptr(cbuf, maxlen), maxlen);
385 if (len <= 0) { 385 if (len <= 0) {
386 if (len < 0 && errno != EINTR) { 386 if (len < 0 && errno != EINTR) {
387 /* no more to write - we close it even if the fd was stderr, since 387 /* no more to write - we close it even if the fd was stderr, since
388 * that's a nasty failure too */ 388 * that's a nasty failure too */
389 closeinfd(channel); 389 closewritefd(channel);
390 } 390 }
391 TRACE(("leave writechannel: len <= 0")) 391 TRACE(("leave writechannel: len <= 0"))
392 return; 392 return;
393 } 393 }
394 394
395 cbuf_incrread(cbuf, len); 395 cbuf_incrread(cbuf, len);
396 channel->recvdonelen += len; 396 channel->recvdonelen += len;
397 397
398 if (fd == channel->infd && len == maxlen && channel->recveof) { 398 if (fd == channel->writefd && len == maxlen && channel->recveof) {
399 /* Check if we're closing up */ 399 /* Check if we're closing up */
400 closeinfd(channel); 400 closewritefd(channel);
401 TRACE(("leave writechannel: recveof set")) 401 TRACE(("leave writechannel: recveof set"))
402 return; 402 return;
403 } 403 }
404 404
405 /* Window adjust handling */ 405 /* Window adjust handling */
419 TRACE(("leave writechannel")) 419 TRACE(("leave writechannel"))
420 } 420 }
421 421
422 /* Set the file descriptors for the main select in session.c 422 /* Set the file descriptors for the main select in session.c
423 * This avoid channels which don't have any window available, are closed, etc*/ 423 * This avoid channels which don't have any window available, are closed, etc*/
424 void setchannelfds(fd_set *readfd, fd_set *writefd) { 424 void setchannelfds(fd_set *readfds, fd_set *writefds) {
425 425
426 unsigned int i; 426 unsigned int i;
427 struct Channel * channel; 427 struct Channel * channel;
428 428
429 for (i = 0; i < ses.chansize; i++) { 429 for (i = 0; i < ses.chansize; i++) {
434 } 434 }
435 435
436 /* Stuff to put over the wire */ 436 /* Stuff to put over the wire */
437 if (channel->transwindow > 0) { 437 if (channel->transwindow > 0) {
438 438
439 if (channel->outfd >= 0) { 439 if (channel->readfd >= 0) {
440 FD_SET(channel->outfd, readfd); 440 FD_SET(channel->readfd, readfds);
441 } 441 }
442 442
443 if (channel->extrabuf == NULL && channel->errfd >= 0) { 443 if (channel->extrabuf == NULL && channel->errfd >= 0) {
444 FD_SET(channel->errfd, readfd); 444 FD_SET(channel->errfd, readfds);
445 } 445 }
446 } 446 }
447 447
448 /* For checking FD status (ie closure etc) - we don't actually 448 /* For checking FD status (ie closure etc) - we don't actually
449 * read data from infd */ 449 * read data from writefd */
450 TRACE(("infd = %d, outfd %d, errfd %d, bufused %d", 450 TRACE(("writefd = %d, readfd %d, errfd %d, bufused %d",
451 channel->infd, channel->outfd, 451 channel->writefd, channel->readfd,
452 channel->errfd, 452 channel->errfd,
453 cbuf_getused(channel->writebuf) )) 453 cbuf_getused(channel->writebuf) ))
454 if (channel->infd >= 0 && channel->infd != channel->outfd) { 454 if (channel->writefd >= 0 && channel->writefd != channel->readfd) {
455 FD_SET(channel->infd, readfd); 455 FD_SET(channel->writefd, readfds);
456 } 456 }
457 457
458 /* Stuff from the wire, to local program/shell/user etc */ 458 /* Stuff from the wire, to local program/shell/user etc */
459 if ((channel->infd >= 0 && cbuf_getused(channel->writebuf) > 0 ) 459 if ((channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0 )
460 || channel->initconn) { 460 || channel->initconn) {
461 461
462 FD_SET(channel->infd, writefd); 462 FD_SET(channel->writefd, writefds);
463 } 463 }
464 464
465 if (channel->extrabuf != NULL && channel->errfd >= 0 465 if (channel->extrabuf != NULL && channel->errfd >= 0
466 && cbuf_getused(channel->extrabuf) > 0 ) { 466 && cbuf_getused(channel->extrabuf) > 0 ) {
467 FD_SET(channel->errfd, writefd); 467 FD_SET(channel->errfd, writefds);
468 } 468 }
469 469
470 } /* foreach channel */ 470 } /* foreach channel */
471 471
472 #ifdef USING_LISTENERS 472 #ifdef USING_LISTENERS
473 set_listener_fds(readfd); 473 set_listener_fds(readfds);
474 #endif 474 #endif
475 475
476 } 476 }
477 477
478 /* handle the channel EOF event, by closing the channel filedescriptor. The 478 /* handle the channel EOF event, by closing the channel filedescriptor. The
491 491
492 channel->recveof = 1; 492 channel->recveof = 1;
493 if (cbuf_getused(channel->writebuf) == 0 493 if (cbuf_getused(channel->writebuf) == 0
494 && (channel->extrabuf == NULL 494 && (channel->extrabuf == NULL
495 || cbuf_getused(channel->extrabuf) == 0)) { 495 || cbuf_getused(channel->extrabuf) == 0)) {
496 closeinfd(channel); 496 closewritefd(channel);
497 } 497 }
498 498
499 TRACE(("leave recv_msg_channel_eof")) 499 TRACE(("leave recv_msg_channel_eof"))
500 } 500 }
501 501
539 } 539 }
540 540
541 541
542 /* close the FDs in case they haven't been done 542 /* close the FDs in case they haven't been done
543 * yet (ie they were shutdown etc */ 543 * yet (ie they were shutdown etc */
544 close(channel->infd); 544 close(channel->writefd);
545 close(channel->outfd); 545 close(channel->readfd);
546 close(channel->errfd); 546 close(channel->errfd);
547 547
548 channel->typedata = NULL; 548 channel->typedata = NULL;
549 549
550 deletechannel(channel); 550 deletechannel(channel);
607 dropbear_assert(!channel->sentclosed); 607 dropbear_assert(!channel->sentclosed);
608 608
609 if (isextended) { 609 if (isextended) {
610 fd = channel->errfd; 610 fd = channel->errfd;
611 } else { 611 } else {
612 fd = channel->outfd; 612 fd = channel->readfd;
613 } 613 }
614 dropbear_assert(fd >= 0); 614 dropbear_assert(fd >= 0);
615 615
616 maxlen = MIN(channel->transwindow, channel->transmaxpacket); 616 maxlen = MIN(channel->transwindow, channel->transmaxpacket);
617 /* -(1+4+4) is SSH_MSG_CHANNEL_DATA, channel number, string length, and 617 /* -(1+4+4) is SSH_MSG_CHANNEL_DATA, channel number, string length, and
629 TRACE(("buf pos %d data %x", buf->pos, buf->data)) 629 TRACE(("buf pos %d data %x", buf->pos, buf->data))
630 len = read(fd, buf_getwriteptr(buf, maxlen), maxlen); 630 len = read(fd, buf_getwriteptr(buf, maxlen), maxlen);
631 if (len <= 0) { 631 if (len <= 0) {
632 /* on error/eof, send eof */ 632 /* on error/eof, send eof */
633 if (len == 0 || errno != EINTR) { 633 if (len == 0 || errno != EINTR) {
634 closeoutfd(channel, fd); 634 closereadfd(channel, fd);
635 } 635 }
636 buf_free(buf); 636 buf_free(buf);
637 buf = NULL; 637 buf = NULL;
638 TRACE(("leave send_msg_channel_data: read err or EOF for fd %d", 638 TRACE(("leave send_msg_channel_data: read err or EOF for fd %d",
639 channel->index)); 639 channel->index));
667 channel = getchannel(); 667 channel = getchannel();
668 if (channel == NULL) { 668 if (channel == NULL) {
669 dropbear_exit("Unknown channel"); 669 dropbear_exit("Unknown channel");
670 } 670 }
671 671
672 common_recv_msg_channel_data(channel, channel->infd, channel->writebuf); 672 common_recv_msg_channel_data(channel, channel->writefd, channel->writebuf);
673 } 673 }
674 674
675 /* Shared for data and stderr data - when we receive data, put it in a buffer 675 /* Shared for data and stderr data - when we receive data, put it in a buffer
676 * for writing to the local file descriptor */ 676 * for writing to the local file descriptor */
677 void common_recv_msg_channel_data(struct Channel *channel, int fd, 677 void common_recv_msg_channel_data(struct Channel *channel, int fd,
687 if (channel->recveof) { 687 if (channel->recveof) {
688 dropbear_exit("received data after eof"); 688 dropbear_exit("received data after eof");
689 } 689 }
690 690
691 if (fd < 0) { 691 if (fd < 0) {
692 dropbear_exit("received data with bad infd"); 692 dropbear_exit("received data with bad writefd");
693 } 693 }
694 694
695 datalen = buf_getint(ses.payload); 695 datalen = buf_getint(ses.payload);
696 696
697 697
929 } 929 }
930 930
931 /* set fd non-blocking */ 931 /* set fd non-blocking */
932 setnonblocking(fd); 932 setnonblocking(fd);
933 933
934 chan->infd = chan->outfd = fd; 934 chan->writefd = chan->readfd = fd;
935 ses.maxfd = MAX(ses.maxfd, fd); 935 ses.maxfd = MAX(ses.maxfd, fd);
936 936
937 chan->await_open = 1; 937 chan->await_open = 1;
938 938
939 /* now open the channel connection */ 939 /* now open the channel connection */
1006 removechannel(channel); 1006 removechannel(channel);
1007 } 1007 }
1008 #endif /* USING_LISTENERS */ 1008 #endif /* USING_LISTENERS */
1009 1009
1010 /* close a stdout/stderr fd */ 1010 /* close a stdout/stderr fd */
1011 static void closeoutfd(struct Channel * channel, int fd) { 1011 static void closereadfd(struct Channel * channel, int fd) {
1012 1012
1013 /* don't close it if it is the same as infd, 1013 /* don't close it if it is the same as writefd,
1014 * unless infd is already set -1 */ 1014 * unless writefd is already set -1 */
1015 TRACE(("enter closeoutfd")) 1015 TRACE(("enter closereadfd"))
1016 closechanfd(channel, fd, 0); 1016 closechanfd(channel, fd, 0);
1017 TRACE(("leave closeoutfd")) 1017 TRACE(("leave closereadfd"))
1018 } 1018 }
1019 1019
1020 /* close a stdin fd */ 1020 /* close a stdin fd */
1021 static void closeinfd(struct Channel * channel) { 1021 static void closewritefd(struct Channel * channel) {
1022 1022
1023 TRACE(("enter closeinfd")) 1023 TRACE(("enter closewritefd"))
1024 closechanfd(channel, channel->infd, 1); 1024 closechanfd(channel, channel->writefd, 1);
1025 TRACE(("leave closeinfd")) 1025 TRACE(("leave closewritefd"))
1026 } 1026 }
1027 1027
1028 /* close a fd, how is 0 for stdout/stderr, 1 for stdin */ 1028 /* close a fd, how is 0 for stdout/stderr, 1 for stdin */
1029 static void closechanfd(struct Channel *channel, int fd, int how) { 1029 static void closechanfd(struct Channel *channel, int fd, int how) {
1030 1030
1042 } else { 1042 } else {
1043 close(fd); 1043 close(fd);
1044 closein = closeout = 1; 1044 closein = closeout = 1;
1045 } 1045 }
1046 1046
1047 if (closeout && fd == channel->outfd) { 1047 if (closeout && fd == channel->readfd) {
1048 channel->outfd = FD_CLOSED; 1048 channel->readfd = FD_CLOSED;
1049 } 1049 }
1050 if (closeout && (channel->extrabuf == NULL) && (fd == channel->errfd)) { 1050 if (closeout && (channel->extrabuf == NULL) && (fd == channel->errfd)) {
1051 channel->errfd = FD_CLOSED; 1051 channel->errfd = FD_CLOSED;
1052 } 1052 }
1053 1053
1054 if (closein && fd == channel->infd) { 1054 if (closein && fd == channel->writefd) {
1055 channel->infd = FD_CLOSED; 1055 channel->writefd = FD_CLOSED;
1056 } 1056 }
1057 if (closein && (channel->extrabuf != NULL) && (fd == channel->errfd)) { 1057 if (closein && (channel->extrabuf != NULL) && (fd == channel->errfd)) {
1058 channel->errfd = FD_CLOSED; 1058 channel->errfd = FD_CLOSED;
1059 } 1059 }
1060 1060
1061 /* if we called shutdown on it and all references are gone, then we 1061 /* if we called shutdown on it and all references are gone, then we
1062 * need to close() it to stop it lingering */ 1062 * need to close() it to stop it lingering */
1063 if (channel->type->sepfds && channel->outfd == FD_CLOSED 1063 if (channel->type->sepfds && channel->readfd == FD_CLOSED
1064 && channel->infd == FD_CLOSED && channel->errfd == FD_CLOSED) { 1064 && channel->writefd == FD_CLOSED && channel->errfd == FD_CLOSED) {
1065 close(fd); 1065 close(fd);
1066 } 1066 }
1067 } 1067 }