Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: |
|
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | rmax-ipv6-branch |
Files: | files | file ages | folders |
SHA1: |
6d66913621071f11838281041e14db16 |
User & Date: | max 2011-05-30 18:04:42 |
Original Comment: | - Fix setting up of [fileevent] while an async socket is still in progress - Cache async socket errors for later use by [fconfigure -error] - Add tests for the above |
Context
2011-06-01
| ||
15:30 |
| |
2011-05-30
| ||
18:04 |
| |
2011-05-27
| ||
18:36 | Fix [socket -async] for DNS names with more than one address check-in: a1abfd5e94 user: max tags: rmax-ipv6-branch | |
Changes
Changes to tests/socket.test.
︙ | ︙ | |||
1696 1697 1698 1699 1700 1701 1702 | if {$remoteProcChan ne ""} { catch {sendCommand exit} } catch {close $commandSocket} catch {close $remoteProcChan} } unset ::tcl::unsupported::socketAF | | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 | if {$remoteProcChan ne ""} { catch {sendCommand exit} } catch {close $commandSocket} catch {close $remoteProcChan} } unset ::tcl::unsupported::socketAF test socket-14.0 {[socket -async] when server only listens on one address family} \ -constraints [list socket supported_any] \ -setup { proc accept {s a p} { global x puts $s bye close $s set x ok } set server [socket -server accept -myaddr 127.0.0.1 0] set port [lindex [fconfigure $server -sockname] 2] } -body { set client [socket -async localhost $port] after 1000 {set x [fconfigure $client -error]} vwait x set x } -cleanup { close $server close $client } -result ok test socket-14.1 {[socket -async] fileevent while still connecting} \ -constraints [list socket supported_any] \ -setup { proc accept {s a p} { global x puts $s bye close $s set x ok } set server [socket -server accept -myaddr 127.0.0.1 2222] set port [lindex [fconfigure $server -sockname] 2] } -body { set client [socket -async localhost $port] fileevent $client readable {lappend x [fconfigure $client -error]} set after [after 1000 {set x timeout}] vwait x vwait x set x } -cleanup { after cancel $after close $server close $client } -result {ok {}} test socket-14.2 {[socket -async] fileevent connection refused} \ -constraints [list socket supported_any] \ -body { set client [socket -async localhost 0] fileevent $client readable {set x [fconfigure $client -error]} set after [after 1000 {set x timeout}] vwait x set x } -cleanup { after cancel $after close $client } -result "connection refused" ::tcltest::cleanupTests flush stdout return # Local Variables: # mode: tcl # fill-column: 78 |
︙ | ︙ |
Changes to unix/tclUnixSock.c.
︙ | ︙ | |||
54 55 56 57 58 59 60 | /* Only needed for server sockets */ Tcl_TcpAcceptProc *acceptProc; /* Proc to call on accept. */ ClientData acceptProcData; /* The data for the accept proc. */ }; struct { | > | > | | | | > > > | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | /* Only needed for server sockets */ Tcl_TcpAcceptProc *acceptProc; /* Proc to call on accept. */ ClientData acceptProcData; /* The data for the accept proc. */ }; struct { /* * Only needed for client sockets */ 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 status; /* Cache status of async socket */ }; }; }; /* * These bits may be ORed together into the "flags" field of a TcpState * structure. |
︙ | ︙ | |||
640 641 642 643 644 645 646 | } if ((len > 1) && (optionName[1] == 'e') && (strncmp(optionName, "-error", len) == 0)) { socklen_t optlen = sizeof(int); int err, ret; | > | | | | | > > > > | 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 | } if ((len > 1) && (optionName[1] == 'e') && (strncmp(optionName, "-error", len) == 0)) { socklen_t optlen = sizeof(int); int err, ret; if (statePtr->status == 0) { ret = getsockopt(statePtr->fds->fd, SOL_SOCKET, SO_ERROR, (char *)&err, &optlen); if (ret < 0) { err = errno; } } else { err = statePtr->status; statePtr->status = 0; } if (err != 0) { Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(err), -1); } return TCL_OK; } if (interp != NULL && Tcl_GetVar(interp, SUPPRESS_RDNS_VAR, 0) != NULL) { |
︙ | ︙ | |||
793 794 795 796 797 798 799 | TcpWatchProc( ClientData instanceData, /* The socket state. */ int mask) /* Events of interest; an OR-ed combination of * TCL_READABLE, TCL_WRITABLE and * TCL_EXCEPTION. */ { TcpState *statePtr = (TcpState *) instanceData; | < | > > > | | | | | | | < | 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 | TcpWatchProc( ClientData instanceData, /* The socket state. */ int mask) /* Events of interest; an OR-ed combination of * TCL_READABLE, TCL_WRITABLE and * TCL_EXCEPTION. */ { TcpState *statePtr = (TcpState *) instanceData; if (statePtr->flags & TCP_ASYNC_CONNECT) { /* Async sockets use a FileHandler internally while connecting, so we * need to cache this request until the connection has succeeded. */ statePtr->filehandlers = mask; } else if (mask) { Tcl_CreateFileHandler(statePtr->fds->fd, mask, (Tcl_FileProc *) Tcl_NotifyChannel, (ClientData) statePtr->channel); } else { Tcl_DeleteFileHandler(statePtr->fds->fd); } } /* *---------------------------------------------------------------------- * * TcpGetHandleProc -- |
︙ | ︙ | |||
870 871 872 873 874 875 876 | */ static int CreateClientSocket( Tcl_Interp *interp, /* For error reporting; can be NULL. */ TcpState *state) { | | > > > > > > > > > > > > | 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 | */ static int CreateClientSocket( Tcl_Interp *interp, /* For error reporting; can be NULL. */ TcpState *state) { int status, connected = 0; int async = state->flags & TCP_ASYNC_CONNECT; if (state->addr != NULL) { goto coro_continue; } for (state->addr = state->addrlist; state->addr != NULL; state->addr = state->addr->ai_next) { status = -1; for (state->myaddr = state->myaddrlist; state->myaddr != NULL; state->myaddr = state->myaddr->ai_next) { int reuseaddr; /* * No need to try combinations of local and remote addresses of * different families. */ if (state->myaddr->ai_family != state->addr->ai_family) { continue; } /* * Close the socket if it is still open from the last unsuccessful * iteration. */ if (state->fds->fd >= 0) { close(state->fds->fd); state->fds->fd = -1; } state->fds->fd = socket(state->addr->ai_family, SOCK_STREAM, 0); if (state->fds->fd < 0) { continue; } /* |
︙ | ︙ | |||
913 914 915 916 917 918 919 | */ TclSockMinimumBuffers(INT2PTR(state->fds->fd), SOCKET_BUFSIZE); if (async) { status = TclUnixSetBlockingMode(state->fds->fd, TCL_MODE_NONBLOCKING); if (status < 0) { | | | < | | < < < < < < < < < < > > > > > > > | | 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 | */ TclSockMinimumBuffers(INT2PTR(state->fds->fd), SOCKET_BUFSIZE); if (async) { status = TclUnixSetBlockingMode(state->fds->fd, TCL_MODE_NONBLOCKING); if (status < 0) { continue; } } reuseaddr = 1; (void) setsockopt(state->fds->fd, SOL_SOCKET, SO_REUSEADDR, (char *) &reuseaddr, sizeof(reuseaddr)); status = bind(state->fds->fd, state->myaddr->ai_addr, state->myaddr->ai_addrlen); if (status < 0) { 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. */ status = connect(state->fds->fd, state->addr->ai_addr, state->addr->ai_addrlen); if (status < 0 && errno == EINPROGRESS) { Tcl_CreateFileHandler(state->fds->fd, TCL_WRITABLE, TcpAsyncCallback, state); return TCL_OK; coro_continue: do { socklen_t optlen = sizeof(int); Tcl_DeleteFileHandler(state->fds->fd); getsockopt(state->fds->fd, SOL_SOCKET, SO_ERROR, (char *)&status, &optlen); state->status = status; } while (0); } if (status == 0) { connected = 1; break; } } if (connected) { break; } } if (async) { /* * Restore blocking mode. */ status = TclUnixSetBlockingMode(state->fds->fd, TCL_MODE_BLOCKING); } freeaddrinfo(state->addrlist); freeaddrinfo(state->myaddrlist); if (async) { CLEAR_BITS(state->flags, TCP_ASYNC_CONNECT); if (state->filehandlers != 0) { TcpWatchProc(state, state->filehandlers); } return TCL_OK; } if (status < 0) { if (interp != NULL) { Tcl_AppendResult(interp, "couldn't open socket: ", Tcl_PosixError(interp), NULL); } if (state->fds->fd != -1) { close(state->fds->fd); } |
︙ | ︙ | |||
1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 | int mode) /* ORed combination of TCL_READABLE and * TCL_WRITABLE to indicate file mode. */ { TcpState *statePtr; char channelName[16 + TCL_INTEGER_SPACE]; statePtr = ckalloc(sizeof(TcpState)); statePtr->fds = ckalloc(sizeof(TcpFdList)); memset(statePtr->fds, (int) 0, sizeof(TcpFdList)); statePtr->fds->fd = PTR2INT(sock); statePtr->flags = 0; | > < < | 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 | int mode) /* ORed combination of TCL_READABLE and * TCL_WRITABLE to indicate file mode. */ { TcpState *statePtr; char channelName[16 + TCL_INTEGER_SPACE]; statePtr = ckalloc(sizeof(TcpState)); memset(statePtr, 0, sizeof(TcpState)); statePtr->fds = ckalloc(sizeof(TcpFdList)); memset(statePtr->fds, (int) 0, sizeof(TcpFdList)); statePtr->fds->fd = PTR2INT(sock); statePtr->flags = 0; sprintf(channelName, "sock%d", statePtr->fds->fd); statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, statePtr, mode); if (Tcl_SetChannelOption(NULL, statePtr->channel, "-translation", "auto crlf") == TCL_ERROR) { |
︙ | ︙ | |||
1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 | memset(newfds, (int) 0, sizeof(TcpFdList)); if (statePtr == NULL) { /* * Allocate a new TcpState for this socket. */ statePtr = ckalloc(sizeof(TcpState)); statePtr->fds = newfds; statePtr->acceptProc = acceptProc; statePtr->acceptProcData = acceptProcData; sprintf(channelName, "sock%d", sock); } else { fds->next = newfds; } | > | 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 | memset(newfds, (int) 0, sizeof(TcpFdList)); if (statePtr == NULL) { /* * Allocate a new TcpState for this socket. */ statePtr = ckalloc(sizeof(TcpState)); memset(statePtr, 0, sizeof(TcpState)); statePtr->fds = newfds; statePtr->acceptProc = acceptProc; statePtr->acceptProcData = acceptProcData; sprintf(channelName, "sock%d", sock); } else { fds->next = newfds; } |
︙ | ︙ | |||
1354 1355 1356 1357 1358 1359 1360 | * 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)); | | < < | 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 | * 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 = ckalloc(sizeof(TcpFdList)); memset(newSockState->fds, (int) 0, sizeof(TcpFdList)); newSockState->fds->fd = newsock; sprintf(channelName, "sock%d", newsock); newSockState->channel = Tcl_CreateChannel(&tcpChannelType, channelName, newSockState, (TCL_READABLE | TCL_WRITABLE)); Tcl_SetChannelOption(NULL, newSockState->channel, "-translation", "auto crlf"); |
︙ | ︙ |