Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch bug-c6897e6e6a Excluding Merge-Ins
This is equivalent to a diff from c8aa0d5bbe to 8f266c55ff
2019-11-07
| ||
12:05 | EBADFD may be undeclared on some systems (use EMFILE as fallback) Leaf check-in: 8f266c55ff user: sebres tags: bug-c6897e6e6a | |
2019-11-06
| ||
23:08 | merge 8.5 check-in: 76450daf3e user: sebres tags: core-8-6-branch | |
17:12 | small amend: adds new define CHECK_FD_SETSIZE_LIMIT to control prevention against violation of FD_SE... check-in: c2d030bb31 user: sebres tags: bug-c6897e6e6a | |
13:25 | Fix tclScan.c, not generating a string representation any more with unsigned wideints and unsigned l... check-in: 4c57a08f2e user: jan.nijtmans tags: fix-scan-no-stringrep | |
2019-11-05
| ||
14:03 | try to fix [c6897e6e6a]: unix/TcpAccept seems to ignore accepting errors silently, so it entering bu... check-in: 56620b4bd5 user: sebres tags: bug-c6897e6e6a | |
2019-11-02
| ||
17:38 | merge 8,6 check-in: 4336cf7305 user: dgp tags: core-8-6-10-rc | |
2019-11-01
| ||
10:11 | Merge 8.6 check-in: f9cf5c9a97 user: jan.nijtmans tags: core-8-branch | |
10:10 | Make ioapi.c and minizip.c build on Windows (for someone who would want to) check-in: c8aa0d5bbe user: jan.nijtmans tags: core-8-6-branch | |
2019-10-31
| ||
11:14 | Merge 8.5 check-in: b87aa25811 user: jan.nijtmans tags: core-8-6-branch | |
Changes to tests/socket.test.
︙ | ︙ | |||
66 67 68 69 70 71 72 73 74 75 76 77 78 79 | if {[expr {[info exists ::env(TRAVIS_OSX_IMAGE)] && [string match xcode* $::env(TRAVIS_OSX_IMAGE)]}]} { return } # Some tests require the Thread package or exec command testConstraint thread [expr {0 == [catch {package require Thread 2.7-}]}] testConstraint exec [llength [info commands exec]] # Produce a random port number in the Dynamic/Private range # from 49152 through 65535. proc randport {} { # firstly try dynamic port via server-socket(0): set port 0x7fffffff catch { | > | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | if {[expr {[info exists ::env(TRAVIS_OSX_IMAGE)] && [string match xcode* $::env(TRAVIS_OSX_IMAGE)]}]} { return } # Some tests require the Thread package or exec command testConstraint thread [expr {0 == [catch {package require Thread 2.7-}]}] testConstraint exec [llength [info commands exec]] testConstraint prlimit [expr {![catch { exec prlimit -n }]}] # Produce a random port number in the Dynamic/Private range # from 49152 through 65535. proc randport {} { # firstly try dynamic port via server-socket(0): set port 0x7fffffff catch { |
︙ | ︙ | |||
738 739 740 741 742 743 744 745 746 747 748 749 750 751 | set done [gets $pipe] } variable done vwait [namespace which -variable done] close $pipe set done } write test socket_$af-3.1 {socket conflict} -constraints [list socket supported_$af stdio] -setup { file delete $path(script) set f [open $path(script) w] puts $f [list set localhost $localhost] puts $f { set f [socket -server accept -myaddr $localhost 0] | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 | set done [gets $pipe] } variable done vwait [namespace which -variable done] close $pipe set done } write proc testSockOnFDExhaustion {{limitn {}}} { upvar localhost localhost set code { lassign $argv localhost wait if {$localhost eq ""} { set localhost 127.0.0.1 } if {$wait ne {} && $wait} { # wait for go signal: gets stdin } proc accept {sock addr port} { incr ::accept } # # flood sockets to cause descriptors exhaustion: set i 0 catch { while 1 { set bs([incr i]) [socket -server accept -myaddr $localhost 0] } } # now we'll free 4 of them: time { close $bs([incr i -1]) } 4 # # test connects shuld cause an error, no busy-wait: set ::accept 0 set tout [after 2500 {set ::accept "TIMEOUT"}] set listener [socket -server accept -myaddr $localhost 0] set port [lindex [chan configure $listener -sockname] 2] puts [list [catch { while {$::accept ne "TIMEOUT"} { set client [socket -async $localhost $port] vwait ::accept } set ::accept "UNEXPECTED: $::accept" } msg] $msg] # # free the descriptors to let "accept" working again: while {$i > 1} { close $bs([incr i -1]) } # # let check 10 connection are successful now: puts [list [catch { set i 0 while {$::accept ne "TIMEOUT" && [incr i] < 10} { set client [socket -async $localhost $port] vwait ::accept } set ::accept "READY: $i" } msg] $msg] # clean up: after cancel $tout # exit. } if {[singleProcess]} { # evaluate test in same process: set orglimitn {} if {$limitn ne {} && $limitn} { if {[catch { set orglimitn [exec prlimit -n -o SOFT --noheadings] exec prlimit -p [pid] --nofile=${limitn}: } msg]} { puts "set of limit ($limitn) is impossible: $msg" } } interp create i i eval [list set argv [list $localhost]] i eval { proc gets args {} proc puts l {lappend ::done {*}$l} } i eval $code set done [i eval {set ::done}] interp delete i if {$orglimitn ne {}} { exec prlimit -p [pid] --nofile=${orglimitn}: } } else { # evaluate test in child process: upvar path path set f [open $path(script) w] puts $f $code close $f set pipe [open |[list [interpreter] $path(script) $localhost $limitn] r+] chan configure $pipe -buffering line if {$limitn ne {} && $limitn} { if {[catch { exec prlimit -p [pid $pipe] --nofile=$limitn } msg]} { puts "set of limit ($limitn) is impossible: $msg" } puts $pipe "go" } set done {} while {[gets $pipe line] >= 0} {lappend done {*}$line} close $pipe file delete $path(script) } set done } test socket_$af-2.14 {accept on descriptors exhaustion (ENOBUFS/EMFILE), bug [c6897e6e6a]} \ -constraints {socket stdio macOrUnix} -body { testSockOnFDExhaustion } -match regexp \ -result {1 \{couldn't open socket: (too many open|host is unreachable)[^\}]*\} 0 \{READY: 10\}} test socket_$af-2.15 {accept on descriptors exhaustion (ENOBUFS/EMFILE), bug [c6897e6e6a]} \ -constraints {socket stdio macOrUnix prlimit} -body { # same as 2.14, but in state where limit of open files exceeds FD_SETSIZE, # so set limit for process larger as FD_SETSIZE (default 1024): testSockOnFDExhaustion [expr {2*1024}] } -match regexp \ -result {1 \{couldn't open socket: (too many open|host is unreachable)[^\}]*\} 0 \{READY: 10\}} test socket_$af-3.1 {socket conflict} -constraints [list socket supported_$af stdio] -setup { file delete $path(script) set f [open $path(script) w] puts $f [list set localhost $localhost] puts $f { set f [socket -server accept -myaddr $localhost 0] |
︙ | ︙ |
Changes to unix/tclUnixSock.c.
︙ | ︙ | |||
54 55 56 57 58 59 60 | struct TcpState { Tcl_Channel channel; /* Channel associated with this file. */ TcpFdList fds; /* The file descriptors of the sockets. */ int flags; /* ORed combination of the bitfields defined * below. */ int interest; /* Event types of interest */ | > | | | | | | | > > > | | | | | | | | | | | | > > > | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | struct TcpState { Tcl_Channel channel; /* Channel associated with this file. */ TcpFdList fds; /* The file descriptors of the sockets. */ int flags; /* ORed combination of the bitfields defined * below. */ int interest; /* Event types of interest */ union { /* * Only needed for server sockets */ struct { Tcl_TcpAcceptProc *acceptProc; /* Proc to call on accept. */ ClientData acceptProcData; /* The data for the accept proc. */ Tcl_TimerToken timer; /* Handle to retard accept event. */ } s; /* * Only needed for client sockets */ struct { struct addrinfo *addrlist; /* Addresses to connect to. */ struct addrinfo *addr; /* Iterator over addrlist. */ struct addrinfo *myaddrlist;/* Local address. */ struct addrinfo *myaddr; /* Iterator over myaddrlist. */ int filehandlers; /* Caches FileHandlers that get set up while * an async socket is not yet connected. */ int connectError; /* Cache SO_ERROR of async socket. */ int cachedBlocking; /* Cache blocking mode of async socket. */ } c; } u; }; /* * These bits may be ORed together into the "flags" field of a TcpState * structure. */ #define TCP_NONBLOCKING (1<<0) /* Socket with non-blocking I/O */ #define TCP_ASYNC_CONNECT (1<<1) /* Async connect in progress. */ #define TCP_SERVER_STATE (1<<2) /* Marks state of server socket. */ #define TCP_ASYNC_PENDING (1<<4) /* TcpConnect was called to * process an async connect. This * flag indicates that reentry is * still pending */ #define TCP_ASYNC_FAILED (1<<5) /* An async connect finally failed */ /* |
︙ | ︙ | |||
166 167 168 169 170 171 172 173 174 175 176 177 178 179 | /* * The following variable holds the network name of this host. */ static TclInitProcessGlobalValueProc InitializeHostName; static ProcessGlobalValue hostName = {0, 0, NULL, NULL, InitializeHostName, NULL, NULL}; #if 0 /* printf debugging */ void printaddrinfo( struct addrinfo *addrlist, char *prefix) | > > > > > > > > | 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | /* * The following variable holds the network name of this host. */ static TclInitProcessGlobalValueProc InitializeHostName; static ProcessGlobalValue hostName = {0, 0, NULL, NULL, InitializeHostName, NULL, NULL}; #define CHECK_FD_SETSIZE_LIMIT #if defined(CHECK_FD_SETSIZE_LIMIT) && !defined(EBADFD) # define EBADFD EMFILE #endif const char * fdSetSizeViolationMsg = "too many open descriptors, violation of the set-size limit"; #if 0 /* printf debugging */ void printaddrinfo( struct addrinfo *addrlist, char *prefix) |
︙ | ︙ | |||
376 377 378 379 380 381 382 | if (mode == TCL_MODE_BLOCKING) { CLEAR_BITS(statePtr->flags, TCP_NONBLOCKING); } else { SET_BITS(statePtr->flags, TCP_NONBLOCKING); } if (GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT)) { | | | | 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 | if (mode == TCL_MODE_BLOCKING) { CLEAR_BITS(statePtr->flags, TCP_NONBLOCKING); } else { SET_BITS(statePtr->flags, TCP_NONBLOCKING); } if (GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT)) { statePtr->u.c.cachedBlocking = mode; return 0; } if (TclUnixSetBlockingMode(statePtr->fds.fd, mode) < 0) { return errno; } return 0; } /* * ---------------------------------------------------------------------- * * WaitForConnect -- * * Check the state of an async connect process. If a connection attempt * terminated, process it, which may finalize it or may start the next * attempt. If a connect error occures, it is saved in * statePtr->u.c.connectError to be reported by 'fconfigure -error'. * * There are two modes of operation, defined by errorCodePtr: * * non-NULL: Called by explicite read/write command. Blocks if the * socket is blocking. * May return two error codes: * * EWOULDBLOCK: if connect is still in progress * * ENOTCONN: if connect failed. This would be the error message |
︙ | ︙ | |||
462 463 464 465 466 467 468 | */ } while (timeout == -1 && GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT)); if (errorCodePtr != NULL) { if (GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) { *errorCodePtr = EAGAIN; return -1; | | | 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 | */ } while (timeout == -1 && GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT)); if (errorCodePtr != NULL) { if (GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) { *errorCodePtr = EAGAIN; return -1; } else if (statePtr->u.c.connectError != 0) { *errorCodePtr = ENOTCONN; return -1; } } return 0; } |
︙ | ︙ | |||
620 621 622 623 624 625 626 | fds = statePtr->fds.next; while (fds != NULL) { TcpFdList *next = fds->next; ckfree(fds); fds = next; } | > > | > > > > > > | | | | | > > | 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 | fds = statePtr->fds.next; while (fds != NULL) { TcpFdList *next = fds->next; ckfree(fds); fds = next; } if (statePtr->flags & TCP_SERVER_STATE) { /* state of server socket (listener) */ if (statePtr->u.s.timer) { Tcl_DeleteTimerHandler(statePtr->u.s.timer); statePtr->u.s.timer = NULL; } } else { /* state of client socket */ if (statePtr->u.c.addrlist != NULL) { freeaddrinfo(statePtr->u.c.addrlist); } if (statePtr->u.c.myaddrlist != NULL) { freeaddrinfo(statePtr->u.c.myaddrlist); } } ckfree(statePtr); return errorCode; } /* *---------------------------------------------------------------------- * |
︙ | ︙ | |||
837 838 839 840 841 842 843 | if (GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT)) { /* * Suppress errors as long as we are not done. */ errno = 0; | | | | | 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 | if (GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT)) { /* * Suppress errors as long as we are not done. */ errno = 0; } else if (statePtr->u.c.connectError != 0) { errno = statePtr->u.c.connectError; statePtr->u.c.connectError = 0; } else { int err; getsockopt(statePtr->fds.fd, SOL_SOCKET, SO_ERROR, (char *) &err, &optlen); errno = err; } |
︙ | ︙ | |||
1012 1013 1014 1015 1016 1017 1018 | ClientData instanceData, /* The socket state. */ int mask) /* Events of interest; an OR-ed combination of * TCL_READABLE, TCL_WRITABLE and * TCL_EXCEPTION. */ { TcpState *statePtr = instanceData; | | | | 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 | ClientData instanceData, /* The socket state. */ int mask) /* Events of interest; an OR-ed combination of * TCL_READABLE, TCL_WRITABLE and * TCL_EXCEPTION. */ { TcpState *statePtr = instanceData; if (statePtr->flags & TCP_SERVER_STATE) { /* * Make sure we don't mess with server sockets since they will never * be readable or writable at the Tcl level. This keeps Tcl scripts * from interfering with the -accept behavior (bug #3394732). */ return; } if (GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) { /* * Async sockets use a FileHandler internally while connecting, so we * need to cache this request until the connection has succeeded. */ statePtr->u.c.filehandlers = mask; } else if (mask) { /* * Whether it is a bug or feature or otherwise, it is a fact of life * that on at least some Linux kernels select() fails to report that a * socket file descriptor is writable when the other end of the socket * is closed. This is in contrast to the guarantees Tcl makes that |
︙ | ︙ | |||
1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 | Tcl_Interp *interp, /* For error reporting; can be NULL. */ TcpState *statePtr) { socklen_t optlen; int async_callback = GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING); int ret = -1, error = EHOSTUNREACH; int async = GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT); if (async_callback) { goto reenter; } | > > | > | > | | | > | | | | | > > > | > > | > > > > > > > | | | < | | | | | | | | | | | | > > > > > | | 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 | Tcl_Interp *interp, /* For error reporting; can be NULL. */ TcpState *statePtr) { socklen_t optlen; int async_callback = GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING); int ret = -1, error = EHOSTUNREACH; int async = GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT); const char *errorMsg = NULL; int fd = statePtr->fds.fd; if (async_callback) { goto reenter; } for (statePtr->u.c.addr = statePtr->u.c.addrlist; statePtr->u.c.addr != NULL; statePtr->u.c.addr = statePtr->u.c.addr->ai_next ) { for (statePtr->u.c.myaddr = statePtr->u.c.myaddrlist; statePtr->u.c.myaddr != NULL; statePtr->u.c.myaddr = statePtr->u.c.myaddr->ai_next ) { int reuseaddr = 1; /* * No need to try combinations of local and remote addresses of * different families. */ if (statePtr->u.c.myaddr->ai_family != statePtr->u.c.addr->ai_family) { continue; } /* * Close the socket if it is still open from the last unsuccessful * iteration. */ if (fd >= 0) { close(fd); fd = -1; errno = 0; } statePtr->fds.fd = fd = socket( statePtr->u.c.addr->ai_family, SOCK_STREAM, 0); #ifdef CHECK_FD_SETSIZE_LIMIT if (fd >= FD_SETSIZE) { close(fd); error = EBADFD; errorMsg = fdSetSizeViolationMsg; statePtr->fds.fd = fd = -1; goto out; } #endif if (fd < 0) { if (errno == EMFILE) { goto out; } continue; } /* * Set the close-on-exec flag so that the socket will not get * inherited by child processes. */ fcntl(fd, F_SETFD, FD_CLOEXEC); /* * Set kernel space buffering */ TclSockMinimumBuffers(INT2PTR(fd), SOCKET_BUFSIZE); if (async) { ret = TclUnixSetBlockingMode(fd, TCL_MODE_NONBLOCKING); if (ret < 0) { continue; } } /* * Must reset the error variable here, before we use it for the * first time in this iteration. */ error = 0; (void) setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &reuseaddr, sizeof(reuseaddr)); ret = bind(fd, statePtr->u.c.myaddr->ai_addr, statePtr->u.c.myaddr->ai_addrlen); if (ret < 0) { error = errno; continue; } /* * Attempt to connect. The connect may fail at present with an * EINPROGRESS but at a later time it will complete. The caller * will set up a file handler on the socket if she is interested * in being informed when the connect completes. */ ret = connect(fd, statePtr->u.c.addr->ai_addr, statePtr->u.c.addr->ai_addrlen); if (ret < 0) { error = errno; } if (ret < 0 && errno == EINPROGRESS) { Tcl_CreateFileHandler(fd, TCL_WRITABLE | TCL_EXCEPTION, TcpAsyncCallback, statePtr); errno = EWOULDBLOCK; SET_BITS(statePtr->flags, TCP_ASYNC_PENDING); return TCL_OK; reenter: CLEAR_BITS(statePtr->flags, TCP_ASYNC_PENDING); Tcl_DeleteFileHandler(fd); /* * Read the error state from the socket to see if the async * connection has succeeded or failed. As this clears the * error condition, we cache the status in the socket state * struct for later retrieval by [fconfigure -error]. */ optlen = sizeof(int); getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *) &error, &optlen); errno = error; } if (error == 0) { goto out; } } } out: statePtr->u.c.connectError = error; CLEAR_BITS(statePtr->flags, TCP_ASYNC_CONNECT); if (async_callback) { /* * An asynchonous connection has finally succeeded or failed. */ TcpWatchProc(statePtr, statePtr->u.c.filehandlers); TclUnixSetBlockingMode(statePtr->fds.fd, statePtr->u.c.cachedBlocking); if (error != 0) { SET_BITS(statePtr->flags, TCP_ASYNC_FAILED); } /* * We need to forward the writable event that brought us here, bcasue * upon reading of getsockopt(SO_ERROR), at least some OSes clear the * writable state from the socket, and so a subsequent select() on * behalf of a script level [fileevent] would not fire. It doesn't * hurt that this is also called in the successful case and will save * the event mechanism one roundtrip through select(). */ if (statePtr->u.c.cachedBlocking == TCL_MODE_NONBLOCKING) { Tcl_NotifyChannel(statePtr->channel, TCL_WRITABLE); } } if (error != 0) { /* * Failure for either a synchronous connection, or an async one that * failed before it could enter background mode, e.g. because an * invalid -myaddr was given. */ if (interp != NULL) { errno = error; if (errorMsg) { Tcl_SetErrorCode(interp, "POSIX", Tcl_ErrnoId(), errorMsg, NULL); } else { errorMsg = Tcl_PosixError(interp); } Tcl_SetObjResult(interp, Tcl_ObjPrintf( "couldn't open socket: %s", errorMsg)); } return TCL_ERROR; } return TCL_OK; } /* |
︙ | ︙ | |||
1370 1371 1372 1373 1374 1375 1376 | /* * Allocate a new TcpState for this socket. */ statePtr = ckalloc(sizeof(TcpState)); memset(statePtr, 0, sizeof(TcpState)); statePtr->flags = async ? TCP_ASYNC_CONNECT : 0; | | | | | 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 | /* * Allocate a new TcpState for this socket. */ statePtr = ckalloc(sizeof(TcpState)); memset(statePtr, 0, sizeof(TcpState)); statePtr->flags = async ? TCP_ASYNC_CONNECT : 0; statePtr->u.c.cachedBlocking = TCL_MODE_BLOCKING; statePtr->u.c.addrlist = addrlist; statePtr->u.c.myaddrlist = myaddrlist; statePtr->fds.fd = -1; /* * Create a new client socket and wrap it in a channel. */ if (TcpConnect(interp, statePtr) != TCL_OK) { |
︙ | ︙ | |||
1507 1508 1509 1510 1511 1512 1513 | */ enum { LOOKUP, SOCKET, BIND, LISTEN } howfar = LOOKUP; int my_errno = 0; if (!TclCreateSocketAddress(interp, &addrlist, myHost, port, 1, &errorMsg)) { my_errno = errno; | | > > > > > > > | 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 | */ enum { LOOKUP, SOCKET, BIND, LISTEN } howfar = LOOKUP; int my_errno = 0; if (!TclCreateSocketAddress(interp, &addrlist, myHost, port, 1, &errorMsg)) { my_errno = errno; goto done; } for (addrPtr = addrlist; addrPtr != NULL; addrPtr = addrPtr->ai_next) { sock = socket(addrPtr->ai_family, addrPtr->ai_socktype, addrPtr->ai_protocol); #ifdef CHECK_FD_SETSIZE_LIMIT if (sock >= FD_SETSIZE) { my_errno = EBADFD; errorMsg = fdSetSizeViolationMsg; goto done; } #endif if (sock == -1) { if (howfar < SOCKET) { howfar = SOCKET; my_errno = errno; } continue; } |
︙ | ︙ | |||
1608 1609 1610 1611 1612 1613 1614 | if (statePtr == NULL) { /* * Allocate a new TcpState for this socket. */ statePtr = ckalloc(sizeof(TcpState)); memset(statePtr, 0, sizeof(TcpState)); | > | | | < | | < | | | | > > > > > > > > > > | 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 | if (statePtr == NULL) { /* * Allocate a new TcpState for this socket. */ statePtr = ckalloc(sizeof(TcpState)); memset(statePtr, 0, sizeof(TcpState)); statePtr->flags = TCP_SERVER_STATE; statePtr->u.s.acceptProc = acceptProc; statePtr->u.s.acceptProcData = acceptProcData; sprintf(channelName, SOCK_TEMPLATE, (long) statePtr); newfds = &statePtr->fds; } else { newfds = ckalloc(sizeof(TcpFdList)); memset(newfds, (int) 0, sizeof(TcpFdList)); fds->next = newfds; } newfds->fd = sock; newfds->statePtr = statePtr; fds = newfds; /* * Set up the callback mechanism for accepting connections from new * clients. */ Tcl_CreateFileHandler(sock, TCL_READABLE, TcpAccept, fds); } done: if (addrlist != NULL) { freeaddrinfo(addrlist); } if (statePtr != NULL) { statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, statePtr, 0); return statePtr->channel; } if (interp != NULL) { errno = my_errno; if (errorMsg) { Tcl_SetErrorCode(interp, "POSIX", Tcl_ErrnoId(), errorMsg, NULL); } else { errorMsg = Tcl_PosixError(interp); } Tcl_SetObjResult(interp, Tcl_ObjPrintf( "couldn't open socket: %s", errorMsg)); } if (sock != -1) { close(sock); } return NULL; } static void RetardAccept( ClientData clientData) { TcpFdList *fds = clientData; fds->statePtr->u.s.timer = NULL; Tcl_CreateFileHandler(fds->fd, TCL_READABLE, TcpAccept, fds); } /* *---------------------------------------------------------------------- * * TcpAccept -- * Accept a TCP socket connection. This is called by the event loop. * * Results: |
︙ | ︙ | |||
1687 1688 1689 1690 1691 1692 1693 | address addr; /* The remote address */ socklen_t len; /* For accept interface */ char channelName[SOCK_CHAN_LENGTH]; char host[NI_MAXHOST], port[NI_MAXSERV]; len = sizeof(addr); newsock = accept(fds->fd, &addr.sa, &len); | > | > > | | > > > > > > > | | | | < | > > > > > > | | | > > > > > | | 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 | address addr; /* The remote address */ socklen_t len; /* For accept interface */ char channelName[SOCK_CHAN_LENGTH]; char host[NI_MAXHOST], port[NI_MAXSERV]; len = sizeof(addr); newsock = accept(fds->fd, &addr.sa, &len); #ifdef CHECK_FD_SETSIZE_LIMIT if (newsock >= FD_SETSIZE) { close(newsock); /* errorMsg = fdSetSizeViolationMsg; */ newsock = -1; } #endif if (newsock < 0) { /* avoid busy wait: retard accept event */ len = 0; Tcl_DeleteFileHandler(fds->fd); fds->statePtr->u.s.timer = Tcl_CreateTimerHandler(1 /* SYNTHETIC_EVENT_TIME */, RetardAccept, fds); } else { /* * Set close-on-exec flag to prevent the newly accepted socket from * being inherited by child processes. */ (void) fcntl(newsock, F_SETFD, FD_CLOEXEC); } newSockState = ckalloc(sizeof(TcpState)); memset(newSockState, 0, sizeof(TcpState)); newSockState->flags = 0; newSockState->fds.fd = newsock; sprintf(channelName, SOCK_TEMPLATE, (long) newSockState); newSockState->channel = Tcl_CreateChannel(&tcpChannelType, channelName, newSockState, TCL_READABLE | TCL_WRITABLE); Tcl_SetChannelOption(NULL, newSockState->channel, "-translation", "auto crlf"); if (newsock < 0) { SET_BITS(newSockState->flags, TCP_ASYNC_FAILED); newSockState->u.c.connectError = errno; } if (fds->statePtr->u.s.acceptProc != NULL) { if (!len || getnameinfo(&addr.sa, len, host, sizeof(host), port, sizeof(port), NI_NUMERICHOST|NI_NUMERICSERV) != 0 ) { /* be sure in error case (e. g. no file descriptors) we'll still * have a host arg. */ memcpy(host, "{}", 3); } fds->statePtr->u.s.acceptProc(fds->statePtr->u.s.acceptProcData, newSockState->channel, host, atoi(port)); } } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * tab-width: 8 * indent-tabs-mode: nil * End: */ |