Mercurial > dropbear
comparison common-channel.c @ 376:4f2dbd1c3685 channel-fix
Add some code for testing whether a writefd is closed (by read()ing from it)
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Tue, 05 Dec 2006 15:23:06 +0000 |
parents | 8d149b812669 |
children | a5bca950120d c53a26c430e5 |
comparison
equal
deleted
inserted
replaced
375:8d149b812669 | 376:4f2dbd1c3685 |
---|---|
184 | 184 |
185 struct Channel* getchannel() { | 185 struct Channel* getchannel() { |
186 return getchannel_msg(NULL); | 186 return getchannel_msg(NULL); |
187 } | 187 } |
188 | 188 |
189 /* In order to tell if a writefd is closed, we put it in the readfd FD_SET. | |
190 We then just try reading a single byte from it. It'll give EAGAIN or something | |
191 if the socket is still alive (but the FD probably shouldn't be set anyway?)*/ | |
192 static void check_closed_writefd(struct Channel* channel, int fd) { | |
193 char c; | |
194 int ret; | |
195 TRACE(("enter check_closed_writefd fd %d", fd)) | |
196 if (fd < 0) { | |
197 TRACE(("leave check_closed_writefd.")) | |
198 return; | |
199 } | |
200 | |
201 /* Read something. doing read(fd,x,0) seems to become a NOP on some platforms */ | |
202 ret = read(fd, &c, 1); | |
203 TRACE(("ret %d errno %d", ret, errno)) | |
204 if (ret > 0 || (ret < 0 && (errno == EINTR || errno == EAGAIN))) { | |
205 TRACE(("leave check_closed_writefd")) | |
206 return; | |
207 } | |
208 close_chan_fd(channel, fd, SHUT_WR); | |
209 TRACE(("leave check_closed_writefd after closing %d", fd)) | |
210 } | |
211 | |
189 /* Iterate through the channels, performing IO if available */ | 212 /* Iterate through the channels, performing IO if available */ |
190 void channelio(fd_set *readfds, fd_set *writefds) { | 213 void channelio(fd_set *readfds, fd_set *writefds) { |
191 | 214 |
192 struct Channel *channel; | 215 struct Channel *channel; |
193 unsigned int i; | 216 unsigned int i; |
226 /* stderr for client mode */ | 249 /* stderr for client mode */ |
227 if (ERRFD_IS_WRITE(channel) | 250 if (ERRFD_IS_WRITE(channel) |
228 && channel->errfd >= 0 && FD_ISSET(channel->errfd, writefds)) { | 251 && channel->errfd >= 0 && FD_ISSET(channel->errfd, writefds)) { |
229 writechannel(channel, channel->errfd, channel->extrabuf); | 252 writechannel(channel, channel->errfd, channel->extrabuf); |
230 } | 253 } |
254 | |
255 /* Check writefds for close, even if we don't have anything | |
256 to write into them. */ | |
257 if (channel->writefd >= 0) { | |
258 check_closed_writefd(channel, channel->writefd); | |
259 } | |
260 if (ERRFD_IS_WRITE(channel) && channel->errfd >= 0) { | |
261 check_closed_writefd(channel, channel->errfd); | |
262 } | |
263 | |
231 | 264 |
232 /* handle any channel closing etc */ | 265 /* handle any channel closing etc */ |
233 check_close(channel); | 266 check_close(channel); |
234 | 267 |
235 } | 268 } |
437 if (ERRFD_IS_WRITE(channel) != NULL && channel->errfd >= 0 | 470 if (ERRFD_IS_WRITE(channel) != NULL && channel->errfd >= 0 |
438 && cbuf_getused(channel->extrabuf) > 0 ) { | 471 && cbuf_getused(channel->extrabuf) > 0 ) { |
439 FD_SET(channel->errfd, writefds); | 472 FD_SET(channel->errfd, writefds); |
440 } | 473 } |
441 | 474 |
475 /* We also set the writefds for reading, so that we will be notified of close */ | |
476 if (channel->writefd >= 0) { | |
477 FD_SET(channel->writefd, readfds); | |
478 } | |
479 if (ERRFD_IS_WRITE(channel) && channel->errfd >= 0) { | |
480 FD_SET(channel->errfd, readfds); | |
481 } | |
482 | |
483 | |
484 | |
442 } /* foreach channel */ | 485 } /* foreach channel */ |
443 | 486 |
444 #ifdef USING_LISTENERS | 487 #ifdef USING_LISTENERS |
445 set_listener_fds(readfds); | 488 set_listener_fds(readfds); |
446 #endif | 489 #endif |