summaryrefslogtreecommitdiffstats
path: root/win/tclWinSock.c
diff options
context:
space:
mode:
Diffstat (limited to 'win/tclWinSock.c')
-rw-r--r--win/tclWinSock.c189
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);
}
/*