diff options
author | jan.nijtmans <nijtmans@users.sourceforge.net> | 2018-10-28 19:26:49 (GMT) |
---|---|---|
committer | jan.nijtmans <nijtmans@users.sourceforge.net> | 2018-10-28 19:26:49 (GMT) |
commit | ccb97d88ffefe602e7eb5a9610bd356d66bc2f20 (patch) | |
tree | 417cc58c53b8773c08262c85128c46225c4d2ea0 /win/tclWinSock.c | |
parent | 3c4cc0a0013a0552c90518a995ae654571c18a5b (diff) | |
parent | fd548863930daf0e1bc3d01286f542844b1cc69c (diff) | |
download | tcl-ccb97d88ffefe602e7eb5a9610bd356d66bc2f20.zip tcl-ccb97d88ffefe602e7eb5a9610bd356d66bc2f20.tar.gz tcl-ccb97d88ffefe602e7eb5a9610bd356d66bc2f20.tar.bz2 |
Merge 8.7
Diffstat (limited to 'win/tclWinSock.c')
-rw-r--r-- | win/tclWinSock.c | 189 |
1 files changed, 107 insertions, 82 deletions
diff --git a/win/tclWinSock.c b/win/tclWinSock.c index e42cafd..80588ef 100644 --- a/win/tclWinSock.c +++ b/win/tclWinSock.c @@ -69,6 +69,7 @@ #define SET_BITS(var, bits) ((var) |= (bits)) #define CLEAR_BITS(var, bits) ((var) &= ~(bits)) +#define GOT_BITS(var, bits) (((var) & (bits)) != 0) /* "sock" + a pointer in hex + \0 */ #define SOCK_CHAN_LENGTH (4 + sizeof(void *) * 2 + 1) @@ -124,6 +125,8 @@ typedef struct TcpFdList { struct TcpState { Tcl_Channel channel; /* Channel associated with this socket. */ + int testFlags; /* bit field for tests. Is set by testsocket + * test procedure */ struct TcpFdList *sockets; /* Windows SOCKET handle. */ int flags; /* Bit field comprised of the flags described * below. */ @@ -184,6 +187,15 @@ struct TcpState { #define TCP_ASYNC_FAILED (1<<5) /* An async connect finally failed */ /* + * These bits may be ORed together into the "testFlags" field of a TcpState + * structure. + */ + +#define TCP_ASYNC_TEST_MODE (1<<0) /* Async testing activated. Do not + * automatically continue connection + * process */ + +/* * The following structure is what is added to the Tcl event queue when a * socket event occurs. */ @@ -292,6 +304,15 @@ static const Tcl_ChannelType tcpChannelType = { static TclInitProcessGlobalValueProc InitializeHostName; static ProcessGlobalValue hostName = {0, 0, NULL, NULL, InitializeHostName, NULL, NULL}; + +/* + * Simple wrapper round the SendMessage syscall. + */ + +#define SendSelectMessage(tsdPtr, message, payload) \ + SendMessage((tsdPtr)->hwnd, SOCKET_SELECT, \ + (WPARAM) (message), (LPARAM) (payload)) + /* * Address print debug functions @@ -339,7 +360,7 @@ printaddrinfolist( void InitializeHostName( char **valuePtr, - size_t *lengthPtr, + unsigned int *lengthPtr, Tcl_Encoding *encodingPtr) { TCHAR tbuf[MAX_COMPUTERNAME_LENGTH + 1]; @@ -585,7 +606,7 @@ WaitForConnect( * demanded, return the error ENOTCONN. */ - if (errorCodePtr != NULL && (statePtr->flags & TCP_ASYNC_FAILED)) { + if (errorCodePtr != NULL && GOT_BITS(statePtr->flags, TCP_ASYNC_FAILED)) { *errorCodePtr = ENOTCONN; return -1; } @@ -594,11 +615,26 @@ WaitForConnect( * Check if an async connect is running. If not return ok */ - if (!(statePtr->flags & TCP_ASYNC_CONNECT)) { + if (!GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT)) { return 0; } /* + * In socket test mode do not continue with the connect + * Exceptions are: + * - Call by recv/send and blocking socket + * (errorCodePtr != NULL && !GOT_BITS(flags, TCP_NONBLOCKING)) + * - Call by the event queue (errorCodePtr == NULL) + */ + + if (GOT_BITS(statePtr->testFlags, TCP_ASYNC_TEST_MODE) + && errorCodePtr != NULL + && GOT_BITS(statePtr->flags, TCP_NONBLOCKING)) { + *errorCodePtr = EWOULDBLOCK; + return -1; + } + + /* * Be sure to disable event servicing so we are truly modal. */ @@ -620,7 +656,7 @@ WaitForConnect( * Check for connect event. */ - if (statePtr->readyEvents & FD_CONNECT) { + if (GOT_BITS(statePtr->readyEvents, FD_CONNECT)) { /* * Consume the connect event. */ @@ -633,7 +669,7 @@ WaitForConnect( */ if (errorCodePtr != NULL && - !(statePtr->flags & TCP_NONBLOCKING)) { + !GOT_BITS(statePtr->flags, TCP_NONBLOCKING)) { CLEAR_BITS(statePtr->flags, TCP_ASYNC_CONNECT); } @@ -666,7 +702,7 @@ WaitForConnect( * foreground blocking operation) */ - if (statePtr->flags & TCP_ASYNC_PENDING) { + if (GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) { if (errorCodePtr != NULL) { *errorCodePtr = EWOULDBLOCK; } @@ -702,11 +738,11 @@ WaitForConnect( } /* - * A non blocking socket waiting for an asyncronous connect returns - * directly the error EWOULDBLOCK. + * A non blocking socket waiting for an asynchronous connect + * returns directly the error EWOULDBLOCK */ - if (statePtr->flags & TCP_NONBLOCKING) { + if (GOT_BITS(statePtr->flags, TCP_NONBLOCKING)) { *errorCodePtr = EWOULDBLOCK; return -1; } @@ -770,7 +806,7 @@ TcpInputProc( * socket stack after the first time EOF is detected. */ - if (statePtr->flags & SOCKET_EOF) { + if (GOT_BITS(statePtr->flags, SOCKET_EOF)) { return 0; } @@ -793,8 +829,8 @@ TcpInputProc( */ while (1) { - SendMessage(tsdPtr->hwnd, SOCKET_SELECT, - (WPARAM) UNSELECT, (LPARAM) statePtr); + SendSelectMessage(tsdPtr, UNSELECT, statePtr); + /* * Single fd operation: this proc is only called for a connected * socket. @@ -819,7 +855,7 @@ TcpInputProc( * error and report an EOF. */ - if (statePtr->readyEvents & FD_CLOSE) { + if (GOT_BITS(statePtr->readyEvents, FD_CLOSE)) { SET_BITS(statePtr->flags, SOCKET_EOF); bytesRead = 0; break; @@ -842,7 +878,8 @@ TcpInputProc( * Check for error condition or underflow in non-blocking case. */ - if ((statePtr->flags & TCP_NONBLOCKING) || (error != WSAEWOULDBLOCK)) { + if (GOT_BITS(statePtr->flags, TCP_NONBLOCKING) + || (error != WSAEWOULDBLOCK)) { TclWinConvertError(error); *errorCodePtr = Tcl_GetErrno(); bytesRead = -1; @@ -860,7 +897,7 @@ TcpInputProc( } } - SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM)SELECT, (LPARAM)statePtr); + SendSelectMessage(tsdPtr, SELECT, statePtr); return bytesRead; } @@ -918,8 +955,7 @@ TcpOutputProc( } while (1) { - SendMessage(tsdPtr->hwnd, SOCKET_SELECT, - (WPARAM) UNSELECT, (LPARAM) statePtr); + SendSelectMessage(tsdPtr, UNSELECT, statePtr); /* * Single fd operation: this proc is only called for a connected @@ -934,8 +970,9 @@ TcpOutputProc( * until the condition changes. */ - if (statePtr->watchEvents & FD_WRITE) { + if (GOT_BITS(statePtr->watchEvents, FD_WRITE)) { Tcl_Time blockTime = { 0, 0 }; + Tcl_SetMaxBlockTime(&blockTime); } break; @@ -951,7 +988,7 @@ TcpOutputProc( error = WSAGetLastError(); if (error == WSAEWOULDBLOCK) { CLEAR_BITS(statePtr->readyEvents, FD_WRITE); - if (statePtr->flags & TCP_NONBLOCKING) { + if (GOT_BITS(statePtr->flags, TCP_NONBLOCKING)) { *errorCodePtr = EWOULDBLOCK; written = -1; break; @@ -974,8 +1011,7 @@ TcpOutputProc( } } - SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM)SELECT, - (LPARAM)statePtr); + SendSelectMessage(tsdPtr, SELECT, statePtr); return written; } @@ -1292,7 +1328,9 @@ TcpGetOptionProc( * below. */ - WaitForConnect(statePtr, NULL); + if (!GOT_BITS(statePtr->testFlags, TCP_ASYNC_TEST_MODE)) { + WaitForConnect(statePtr, NULL); + } sock = statePtr->sockets->fd; if (optionName != NULL) { @@ -1305,8 +1343,8 @@ TcpGetOptionProc( * Do not return any errors if async connect is running. */ - if (!(statePtr->flags & TCP_ASYNC_PENDING)) { - if (statePtr->flags & TCP_ASYNC_FAILED) { + if (!GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) { + if (GOT_BITS(statePtr->flags, TCP_ASYNC_FAILED)) { /* * In case of a failed async connect, eventually report the * connect error only once. Do not report the system error, @@ -1361,7 +1399,7 @@ TcpGetOptionProc( if ((len > 1) && (optionName[1] == 'c') && (strncmp(optionName, "-connecting", len) == 0)) { Tcl_DStringAppend(dsPtr, - (statePtr->flags & TCP_ASYNC_PENDING) + GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING) ? "1" : "0", -1); return TCL_OK; } @@ -1376,7 +1414,7 @@ TcpGetOptionProc( address peername; socklen_t size = sizeof(peername); - if (statePtr->flags & TCP_ASYNC_PENDING) { + if (GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) { /* * In async connect output an empty string */ @@ -1441,7 +1479,7 @@ TcpGetOptionProc( Tcl_DStringAppendElement(dsPtr, "-sockname"); Tcl_DStringStartSublist(dsPtr); } - if (statePtr->flags & TCP_ASYNC_PENDING) { + if (GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) { /* * In async connect output an empty string */ @@ -1590,10 +1628,10 @@ TcpWatchProc( if (!statePtr->acceptProc) { statePtr->watchEvents = 0; - if (mask & TCL_READABLE) { + if (GOT_BITS(mask, TCL_READABLE)) { SET_BITS(statePtr->watchEvents, FD_READ | FD_CLOSE); } - if (mask & TCL_WRITABLE) { + if (GOT_BITS(mask, TCL_WRITABLE)) { SET_BITS(statePtr->watchEvents, FD_WRITE | FD_CLOSE); } @@ -1652,9 +1690,9 @@ TcpGetHandleProc( * * This might be called in 3 circumstances: * - By a regular socket command - * - By the event handler to continue an asynchroneous connect + * - By the event handler to continue an asynchronously connect * - By a blocking socket function (gets/puts) to terminate the - * connect synchroneously + * connect synchronously * * Results: * TCL_OK, if the socket was successfully connected or an asynchronous @@ -1666,7 +1704,7 @@ TcpGetHandleProc( * * Remarks: * A single host name may resolve to more than one IP address, e.g. for - * an IPv4/IPv6 dual stack host. For handling asyncronously connecting + * an IPv4/IPv6 dual stack host. For handling asynchronously connecting * sockets in the background for such hosts, this function can act as a * coroutine. On the first call, it sets up the control variables for the * two nested loops over the local and remote addresses. Once the first @@ -1674,7 +1712,7 @@ TcpGetHandleProc( * event handler for that socket, and returns. When the callback occurs, * control is transferred to the "reenter" label, right after the initial * return and the loops resume as if they had never been interrupted. - * For syncronously connecting sockets, the loops work the usual way. + * For synchronously connecting sockets, the loops work the usual way. * *---------------------------------------------------------------------- */ @@ -1685,11 +1723,11 @@ TcpConnect( TcpState *statePtr) { DWORD error; - int async_connect = statePtr->flags & TCP_ASYNC_CONNECT; + int async_connect = GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT); /* We are started with async connect and the * connect notification was not yet * received. */ - int async_callback = statePtr->flags & TCP_ASYNC_PENDING; + int async_callback = GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING); /* We were called by the event procedure and * continue our loop. */ ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey); @@ -1778,7 +1816,7 @@ TcpConnect( } /* - * For asyncroneous connect set the socket in nonblocking mode + * For asynchroneous connect set the socket in nonblocking mode * and activate connect notification */ @@ -1833,8 +1871,7 @@ TcpConnect( * Activate accept notification. */ - SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, - (LPARAM) statePtr); + SendSelectMessage(tsdPtr, SELECT, statePtr); } /* @@ -1893,8 +1930,8 @@ TcpConnect( } /* - * Clear the tsd socket list pointer if we did not wait for the - * FD_CONNECT asynchronously. + * Clear the tsd socket list pointer if we did not wait for + * the FD_CONNECT asynchroneously */ tsdPtr->pendingTcpState = NULL; @@ -1930,8 +1967,7 @@ TcpConnect( * automatically places the socket into non-blocking mode. */ - SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, - (LPARAM) statePtr); + SendSelectMessage(tsdPtr, SELECT, statePtr); } else { /* * Connect failed @@ -1978,7 +2014,7 @@ TcpConnect( } /* - * Error message on syncroneous connect + * Error message on synchroneous connect */ if (interp != NULL) { @@ -2128,8 +2164,7 @@ Tcl_MakeTcpClientChannel( */ statePtr->selectEvents = FD_READ | FD_CLOSE | FD_WRITE; - SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM)SELECT, - (LPARAM)statePtr); + SendSelectMessage(tsdPtr, SELECT, statePtr); sprintf(channelName, SOCK_TEMPLATE, statePtr); statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, @@ -2245,7 +2280,7 @@ Tcl_OpenTcpServerEx( * unix systems. */ - if (flags & TCL_TCPSERVER_REUSEPORT) { + if (GOT_BITS(flags, TCL_TCPSERVER_REUSEPORT)) { optvalue = 1; (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &optvalue, sizeof(optvalue)); @@ -2330,8 +2365,7 @@ Tcl_OpenTcpServerEx( */ ioctlsocket(sock, (long) FIONBIO, &flag); - SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, - (LPARAM) statePtr); + SendSelectMessage(tsdPtr, SELECT, statePtr); if (Tcl_SetChannelOption(interp, statePtr->channel, "-eofchar", "") == TCL_ERROR) { Tcl_Close(NULL, statePtr->channel); @@ -2400,8 +2434,7 @@ TcpAccept( */ newInfoPtr->selectEvents = (FD_READ | FD_WRITE | FD_CLOSE); - SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, - (LPARAM) newInfoPtr); + SendSelectMessage(tsdPtr, SELECT, newInfoPtr); sprintf(channelName, SOCK_TEMPLATE, newInfoPtr); newInfoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, @@ -2632,7 +2665,7 @@ SocketSetupProc( Tcl_Time blockTime = { 0, 0 }; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - if (!(flags & TCL_FILE_EVENTS)) { + if (!GOT_BITS(flags, TCL_FILE_EVENTS)) { return; } @@ -2642,9 +2675,8 @@ SocketSetupProc( WaitForSingleObject(tsdPtr->socketListLock, INFINITE); for (statePtr = tsdPtr->socketList; statePtr != NULL; statePtr = statePtr->nextPtr) { - if (statePtr->readyEvents & - (statePtr->watchEvents | FD_CONNECT | FD_ACCEPT) - ) { + if (GOT_BITS(statePtr->readyEvents, + statePtr->watchEvents | FD_CONNECT | FD_ACCEPT)) { Tcl_SetMaxBlockTime(&blockTime); break; } @@ -2678,7 +2710,7 @@ SocketCheckProc( SocketEvent *evPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - if (!(flags & TCL_FILE_EVENTS)) { + if (!GOT_BITS(flags, TCL_FILE_EVENTS)) { return; } @@ -2691,9 +2723,9 @@ SocketCheckProc( WaitForSingleObject(tsdPtr->socketListLock, INFINITE); for (statePtr = tsdPtr->socketList; statePtr != NULL; statePtr = statePtr->nextPtr) { - if ((statePtr->readyEvents & - (statePtr->watchEvents | FD_CONNECT | FD_ACCEPT)) - && !(statePtr->flags & SOCKET_PENDING)) { + if (GOT_BITS(statePtr->readyEvents, + statePtr->watchEvents | FD_CONNECT | FD_ACCEPT) + && !GOT_BITS(statePtr->flags, SOCKET_PENDING)) { SET_BITS(statePtr->flags, SOCKET_PENDING); evPtr = ckalloc(sizeof(SocketEvent)); evPtr->header.proc = SocketEventProc; @@ -2740,7 +2772,7 @@ SocketEventProc( address addr; int len; - if (!(flags & TCL_FILE_EVENTS)) { + if (!GOT_BITS(flags, TCL_FILE_EVENTS)) { return 0; } @@ -2775,8 +2807,8 @@ SocketEventProc( * Continue async connect if pending and ready */ - if (statePtr->readyEvents & FD_CONNECT) { - if (statePtr->flags & TCP_ASYNC_PENDING) { + if (GOT_BITS(statePtr->readyEvents, FD_CONNECT)) { + if (GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) { /* * Do one step and save eventual connect error */ @@ -2798,7 +2830,7 @@ SocketEventProc( * Handle connection requests directly. */ - if (statePtr->readyEvents & FD_ACCEPT) { + if (GOT_BITS(statePtr->readyEvents, FD_ACCEPT)) { for (fds = statePtr->sockets; fds != NULL; fds = fds->next) { /* * Accept the incoming connection request. @@ -2873,7 +2905,7 @@ SocketEventProc( events = statePtr->readyEvents & statePtr->watchEvents; - if (events & FD_CLOSE) { + if (GOT_BITS(events, FD_CLOSE)) { /* * If the socket was closed and the channel is still interested in * read events, then we need to ensure that we keep polling for this @@ -2888,15 +2920,13 @@ SocketEventProc( Tcl_SetMaxBlockTime(&blockTime); SET_BITS(mask, TCL_READABLE | TCL_WRITABLE); - } else if (events & FD_READ) { - + } else if (GOT_BITS(events, FD_READ)) { /* * Throw the readable event if an async connect failed. */ - if (statePtr->flags & TCP_ASYNC_FAILED) { + if (GOT_BITS(statePtr->flags, TCP_ASYNC_FAILED)) { SET_BITS(mask, TCL_READABLE); - } else { fd_set readFds; struct timeval timeout; @@ -2909,8 +2939,7 @@ SocketEventProc( * async select handler and keep waiting. */ - SendMessage(tsdPtr->hwnd, SOCKET_SELECT, - (WPARAM) UNSELECT, (LPARAM) statePtr); + SendSelectMessage(tsdPtr, UNSELECT, statePtr); FD_ZERO(&readFds); FD_SET(statePtr->sockets->fd, &readFds); @@ -2921,8 +2950,7 @@ SocketEventProc( SET_BITS(mask, TCL_READABLE); } else { CLEAR_BITS(statePtr->readyEvents, FD_READ); - SendMessage(tsdPtr->hwnd, SOCKET_SELECT, - (WPARAM) SELECT, (LPARAM) statePtr); + SendSelectMessage(tsdPtr, SELECT, statePtr); } } } @@ -2931,7 +2959,7 @@ SocketEventProc( * writable event */ - if (events & FD_WRITE) { + if (GOT_BITS(events, FD_WRITE)) { SET_BITS(mask, TCL_WRITABLE); } @@ -3073,10 +3101,8 @@ WaitForSocketEvent( * Reset WSAAsyncSelect so we have a fresh set of events pending. */ - SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) UNSELECT, - (LPARAM) statePtr); - SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, - (LPARAM) statePtr); + SendSelectMessage(tsdPtr, UNSELECT, statePtr); + SendSelectMessage(tsdPtr, SELECT, statePtr); while (1) { int event_found; @@ -3091,7 +3117,7 @@ WaitForSocketEvent( * Check if event occured. */ - event_found = (statePtr->readyEvents & events); + event_found = GOT_BITS(statePtr->readyEvents, events); /* * Free list lock. @@ -3292,14 +3318,14 @@ SocketProc( * the count if the current event is an FD_ACCEPT. */ - if (event & FD_CLOSE) { + if (GOT_BITS(event, FD_CLOSE)) { statePtr->acceptEventCount = 0; CLEAR_BITS(statePtr->readyEvents, FD_WRITE | FD_ACCEPT); - } else if (event & FD_ACCEPT) { + } else if (GOT_BITS(event, FD_ACCEPT)) { statePtr->acceptEventCount++; } - if (event & FD_CONNECT) { + if (GOT_BITS(event, FD_CONNECT)) { /* * Remember any error that occurred so we can report * connection failures. @@ -3530,8 +3556,7 @@ TcpThreadActionProc( * thread. */ - SendMessage(tsdPtr->hwnd, SOCKET_SELECT, - (WPARAM) notifyCmd, (LPARAM) statePtr); + SendSelectMessage(tsdPtr, notifyCmd, statePtr); } /* |