comparison common-channel.c @ 331:d6b8815a9b5e

progress towards exiting on writefd closure rather than on process exit - dbclient hangs with scp, so requires work.
author Matt Johnston <matt@ucc.asn.au>
date Sun, 11 Jun 2006 16:19:32 +0000
parents 5488db2e9e4e
children 6f90e5fd42cc e7c1a77d2921
comparison
equal deleted inserted replaced
330:5488db2e9e4e 331:d6b8815a9b5e
179 /* Iterate through the channels, performing IO if available */ 179 /* Iterate through the channels, performing IO if available */
180 void channelio(fd_set *readfds, fd_set *writefds) { 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 185
185 /* iterate through all the possible channels */ 186 /* iterate through all the possible channels */
186 for (i = 0; i < ses.chansize; i++) { 187 for (i = 0; i < ses.chansize; i++) {
187 188
188 channel = ses.channels[i]; 189 channel = ses.channels[i];
202 send_msg_channel_data(channel, 1, SSH_EXTENDED_DATA_STDERR); 203 send_msg_channel_data(channel, 1, SSH_EXTENDED_DATA_STDERR);
203 } 204 }
204 205
205 /* if we can read from the writefd, it might be closed, so we try to 206 /* if we can read from the writefd, it might be closed, so we try to
206 * see if it has errors */ 207 * see if it has errors */
207 if (channel->writefd >= 0 && channel->writefd != channel->readfd 208 if (IS_DROPBEAR_SERVER && channel->writefd >= 0
209 && channel->writefd != channel->readfd
208 && FD_ISSET(channel->writefd, readfds)) { 210 && FD_ISSET(channel->writefd, readfds)) {
209 if (channel->initconn) { 211 if (channel->initconn) {
210 /* Handling for "in progress" connection - this is needed 212 /* Handling for "in progress" connection - this is needed
211 * to avoid spinning 100% CPU when we connect to a server 213 * to avoid spinning 100% CPU when we connect to a server
212 * which doesn't send anything (tcpfwding) */ 214 * which doesn't send anything (tcpfwding) */
257 TRACE(("writebuf size %d extrabuf ptr 0x%x extrabuf size %d", 259 TRACE(("writebuf size %d extrabuf ptr 0x%x extrabuf size %d",
258 cbuf_getused(channel->writebuf), 260 cbuf_getused(channel->writebuf),
259 channel->writebuf, 261 channel->writebuf,
260 channel->writebuf ? 0 : cbuf_getused(channel->extrabuf))) 262 channel->writebuf ? 0 : cbuf_getused(channel->extrabuf)))
261 263
262 if (!channel->sentclosed) { 264 /* server chansession channels are special, since readfd mightn't
263 265 * close in the case of "sleep 4 & echo blah" until the sleep is up */
264 /* check for exited - currently only used for server sessions, 266 if (channel->type->checkclose) {
265 * if the shell has exited etc */ 267 if (channel->type->checkclose(channel)) {
266 if (channel->type->checkclose) { 268 closewritefd(channel);
267 if (channel->type->checkclose(channel)) { 269 closereadfd(channel, channel->readfd);
268 closewritefd(channel); 270 closereadfd(channel, channel->errfd);
269 } 271 }
270 } 272 }
271 273
272 if (!channel->senteof 274 if (!channel->senteof
273 && channel->readfd == FD_CLOSED 275 && channel->readfd == FD_CLOSED
274 && (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) { 276 && (channel->extrabuf == NULL || channel->errfd == FD_CLOSED)) {
275 send_msg_channel_eof(channel); 277 send_msg_channel_eof(channel);
276 } 278 }
277 279
278 if (channel->writefd == FD_CLOSED 280 if (!channel->sentclosed
279 && channel->readfd == FD_CLOSED 281 && channel->writefd == FD_CLOSED
280 && (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) { 282 && channel->readfd == FD_CLOSED
281 send_msg_channel_close(channel); 283 && (channel->extrabuf == NULL || channel->errfd == FD_CLOSED)) {
282 } 284 send_msg_channel_close(channel);
283 } 285 }
284 286
285 /* When either party wishes to terminate the channel, it sends 287 /* When either party wishes to terminate the channel, it sends
286 * SSH_MSG_CHANNEL_CLOSE. Upon receiving this message, a party MUST 288 * SSH_MSG_CHANNEL_CLOSE. Upon receiving this message, a party MUST
287 * send back a SSH_MSG_CHANNEL_CLOSE unless it has already sent this 289 * send back a SSH_MSG_CHANNEL_CLOSE unless it has already sent this
442 if (channel->extrabuf == NULL && channel->errfd >= 0) { 444 if (channel->extrabuf == NULL && channel->errfd >= 0) {
443 FD_SET(channel->errfd, readfds); 445 FD_SET(channel->errfd, readfds);
444 } 446 }
445 } 447 }
446 448
447 /* For checking FD status (ie closure etc) - we don't actually
448 * read data from writefd */
449 TRACE(("writefd = %d, readfd %d, errfd %d, bufused %d", 449 TRACE(("writefd = %d, readfd %d, errfd %d, bufused %d",
450 channel->writefd, channel->readfd, 450 channel->writefd, channel->readfd,
451 channel->errfd, 451 channel->errfd,
452 cbuf_getused(channel->writebuf) )) 452 cbuf_getused(channel->writebuf) ))
453 if (channel->writefd >= 0 && channel->writefd != channel->readfd) { 453
454 /* For checking FD status (ie closure etc) - we don't actually
455 * read data from writefd. We don't want to do this for the client,
456 * since redirection to /dev/null will make it spin in the select */
457 if (IS_DROPBEAR_SERVER && channel->writefd >= 0
458 && channel->writefd != channel->readfd) {
454 FD_SET(channel->writefd, readfds); 459 FD_SET(channel->writefd, readfds);
455 } 460 }
456 461
457 /* Stuff from the wire, to local program/shell/user etc */ 462 /* Stuff from the wire */
458 if ((channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0 ) 463 if ((channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0 )
459 || channel->initconn) { 464 || channel->initconn) {
460
461 FD_SET(channel->writefd, writefds); 465 FD_SET(channel->writefd, writefds);
462 } 466 }
463 467
464 if (channel->extrabuf != NULL && channel->errfd >= 0 468 if (channel->extrabuf != NULL && channel->errfd >= 0
465 && cbuf_getused(channel->extrabuf) > 0 ) { 469 && cbuf_getused(channel->extrabuf) > 0 ) {