diff options
Diffstat (limited to 'win/tclWinSock.c')
| -rw-r--r-- | win/tclWinSock.c | 1022 |
1 files changed, 423 insertions, 599 deletions
diff --git a/win/tclWinSock.c b/win/tclWinSock.c index 0c1a270..8f565b9 100644 --- a/win/tclWinSock.c +++ b/win/tclWinSock.c @@ -65,7 +65,6 @@ #undef getservbyname #undef getsockopt -#undef ntohs #undef setsockopt /* @@ -75,7 +74,6 @@ */ static int initialized = 0; -static const TCHAR classname[] = TEXT("TclSocket"); TCL_DECLARE_MUTEX(socketMutex) /* @@ -98,64 +96,43 @@ static ProcessGlobalValue hostName = { #define UNSELECT FALSE /* - * This is needed to comply with the strict aliasing rules of GCC, but it also - * simplifies casting between the different sockaddr types. - */ -typedef union { - struct sockaddr sa; - struct sockaddr_in sa4; - struct sockaddr_in6 sa6; - struct sockaddr_storage sas; -} address; - -#ifndef IN6_ARE_ADDR_EQUAL -#define IN6_ARE_ADDR_EQUAL IN6_ADDR_EQUAL -#endif - -typedef struct SocketInfo SocketInfo; - -typedef struct TcpFdList { - SocketInfo *infoPtr; - SOCKET fd; - struct TcpFdList *next; -} TcpFdList; - -/* * The following structure is used to store the data associated with each * socket. + * All members modified by the notifier thread are defined as volatile. */ -struct SocketInfo { +typedef struct SocketInfo { Tcl_Channel channel; /* Channel associated with this socket. */ - struct TcpFdList *sockets; /* Windows SOCKET handle. */ - int flags; /* Bit field comprised of the flags described + SOCKET socket; /* Windows SOCKET handle. */ + volatile int flags; /* Bit field comprised of the flags described * below. */ int watchEvents; /* OR'ed combination of FD_READ, FD_WRITE, * FD_CLOSE, FD_ACCEPT and FD_CONNECT that * indicate which events are interesting. */ - int readyEvents; /* OR'ed combination of FD_READ, FD_WRITE, + volatile int readyEvents; /* OR'ed combination of FD_READ, FD_WRITE, * FD_CLOSE, FD_ACCEPT and FD_CONNECT that * indicate which events have occurred. */ int selectEvents; /* OR'ed combination of FD_READ, FD_WRITE, * FD_CLOSE, FD_ACCEPT and FD_CONNECT that * indicate which events are currently being * selected. */ - int acceptEventCount; /* Count of the current number of FD_ACCEPTs + volatile int acceptEventCount; + /* Count of the current number of FD_ACCEPTs * that have arrived and not yet processed. */ Tcl_TcpAcceptProc *acceptProc; /* Proc to call on accept. */ ClientData acceptProcData; /* The data for the accept proc. */ - int lastError; /* Error code from last message. */ + volatile int lastError; /* Error code from last message. */ struct SocketInfo *nextPtr; /* The next socket on the per-thread socket * list. */ -}; +} SocketInfo; /* * The following structure is what is added to the Tcl event queue when a * socket event occurs. */ -typedef struct SocketEvent { +typedef struct { Tcl_Event header; /* Information that is standard for all * events. */ SOCKET socket; /* Socket descriptor that is ready. Used to @@ -183,7 +160,7 @@ typedef struct SocketEvent { #define SOCKET_PENDING (1<<3) /* A message has been sent for this * socket */ -typedef struct ThreadSpecificData { +typedef struct { HWND hwnd; /* Handle to window for socket messages. */ HANDLE socketThread; /* Thread handling the window */ Tcl_ThreadId threadId; /* Parent thread. */ @@ -192,6 +169,10 @@ typedef struct ThreadSpecificData { * socketThread has been initialized and has * started. */ HANDLE socketListLock; /* Win32 Event to lock the socketList */ + SocketInfo *pendingSocketInfo; + /* This socket is opened but not jet in the + * list. This value is also checked by + * the event structure. */ SocketInfo *socketList; /* Every open socket in this thread has an * entry on this list. */ } ThreadSpecificData; @@ -206,17 +187,15 @@ static WNDCLASS windowClass; static SocketInfo * CreateSocket(Tcl_Interp *interp, int port, const char *host, int server, const char *myaddr, int myport, int async); -#if 0 static int CreateSocketAddress(LPSOCKADDR_IN sockaddrPtr, const char *host, int port); -#endif static void InitSockets(void); static SocketInfo * NewSocketInfo(SOCKET socket); static void SocketExitHandler(ClientData clientData); static LRESULT CALLBACK SocketProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); static int SocketsEnabled(void); -static void TcpAccept(TcpFdList *fds); +static void TcpAccept(SocketInfo *infoPtr); static int WaitForSocketEvent(SocketInfo *infoPtr, int events, int *errorCodePtr); static DWORD WINAPI SocketThread(LPVOID arg); @@ -228,7 +207,6 @@ static Tcl_EventProc SocketEventProc; static Tcl_EventSetupProc SocketSetupProc; static Tcl_DriverBlockModeProc TcpBlockProc; static Tcl_DriverCloseProc TcpCloseProc; -static Tcl_DriverClose2Proc TcpClose2Proc; static Tcl_DriverSetOptionProc TcpSetOptionProc; static Tcl_DriverGetOptionProc TcpGetOptionProc; static Tcl_DriverInputProc TcpInputProc; @@ -241,7 +219,7 @@ static Tcl_DriverGetHandleProc TcpGetHandleProc; * based IO. */ -static const Tcl_ChannelType tcpChannelType = { +static Tcl_ChannelType tcpChannelType = { "tcp", /* Type name. */ TCL_CHANNEL_VERSION_5, /* v5 channel */ TcpCloseProc, /* Close proc. */ @@ -252,13 +230,13 @@ static const Tcl_ChannelType tcpChannelType = { TcpGetOptionProc, /* Get option proc. */ TcpWatchProc, /* Set up notifier to watch this channel. */ TcpGetHandleProc, /* Get an OS handle from channel. */ - TcpClose2Proc, /* Close2proc. */ + NULL, /* close2proc. */ TcpBlockProc, /* Set socket into (non-)blocking mode. */ NULL, /* flush proc. */ NULL, /* handler proc. */ NULL, /* wide seek proc */ TcpThreadActionProc, /* thread action proc */ - NULL /* truncate */ + NULL, /* truncate */ }; /* @@ -285,13 +263,12 @@ static void InitSockets(void) { DWORD id; - WSADATA wsaData; - DWORD err; - ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + TclThreadDataKeyGet(&dataKey); if (!initialized) { initialized = 1; - TclCreateLateExitHandler(SocketExitHandler, NULL); + TclCreateLateExitHandler(SocketExitHandler, (ClientData) NULL); /* * Create the async notification window with a new class. We must @@ -306,48 +283,16 @@ InitSockets(void) windowClass.hInstance = TclWinGetTclInstance(); windowClass.hbrBackground = NULL; windowClass.lpszMenuName = NULL; - windowClass.lpszClassName = classname; + windowClass.lpszClassName = "TclSocket"; windowClass.lpfnWndProc = SocketProc; windowClass.hIcon = NULL; windowClass.hCursor = NULL; - if (!RegisterClass(&windowClass)) { + if (!RegisterClassA(&windowClass)) { TclWinConvertError(GetLastError()); goto initFailure; } - /* - * Initialize the winsock library and check the interface version - * actually loaded. We only ask for the 1.1 interface and do require - * that it not be less than 1.1. - */ - -#define WSA_VERSION_MAJOR 1 -#define WSA_VERSION_MINOR 1 -#define WSA_VERSION_REQD MAKEWORD(WSA_VERSION_MAJOR, WSA_VERSION_MINOR) - - err = WSAStartup((WORD)WSA_VERSION_REQD, &wsaData); - if (err != 0) { - TclWinConvertWSAError(err); - goto initFailure; - } - - /* - * Note the byte positions are swapped for the comparison, so that - * 0x0002 (2.0, MAKEWORD(2,0)) doesn't look less than 0x0101 (1.1). - * We want the comparison to be 0x0200 < 0x0101. - */ - - if (MAKEWORD(HIBYTE(wsaData.wVersion), LOBYTE(wsaData.wVersion)) - < MAKEWORD(WSA_VERSION_MINOR, WSA_VERSION_MAJOR)) { - TclWinConvertWSAError(WSAVERNOTSUPPORTED); - WSACleanup(); - goto initFailure; - } - -#undef WSA_VERSION_REQD -#undef WSA_VERSION_MAJOR -#undef WSA_VERSION_MINOR } /* @@ -356,6 +301,7 @@ InitSockets(void) if (tsdPtr == NULL) { tsdPtr = TCL_TSD_INIT(&dataKey); + tsdPtr->pendingSocketInfo = NULL; tsdPtr->socketList = NULL; tsdPtr->hwnd = NULL; tsdPtr->threadId = Tcl_GetCurrentThread(); @@ -453,8 +399,7 @@ SocketExitHandler( */ TclpFinalizeSockets(); - UnregisterClass(classname, TclWinGetTclInstance()); - WSACleanup(); + UnregisterClass("TclSocket", TclWinGetTclInstance()); initialized = 0; Tcl_MutexUnlock(&socketMutex); } @@ -481,19 +426,19 @@ SocketExitHandler( void TclpFinalizeSockets(void) { - ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey); + ThreadSpecificData *tsdPtr; + tsdPtr = (ThreadSpecificData *) TclThreadDataKeyGet(&dataKey); if (tsdPtr != NULL) { if (tsdPtr->socketThread != NULL) { if (tsdPtr->hwnd != NULL) { - PostMessage(tsdPtr->hwnd, SOCKET_TERMINATE, 0, 0); - - /* - * Wait for the thread to exit. This ensures that we are - * completely cleaned up before we leave this function. - */ - - WaitForSingleObject(tsdPtr->readyEvent, INFINITE); + if (PostMessage(tsdPtr->hwnd, SOCKET_TERMINATE, 0, 0)) { + /* + * Wait for the thread to exit. This ensures that we are + * completely cleaned up before we leave this function. + */ + WaitForSingleObject(tsdPtr->readyEvent, INFINITE); + } tsdPtr->hwnd = NULL; } CloseHandle(tsdPtr->socketThread); @@ -639,9 +584,9 @@ SocketCheckProc( if ((infoPtr->readyEvents & infoPtr->watchEvents) && !(infoPtr->flags & SOCKET_PENDING)) { infoPtr->flags |= SOCKET_PENDING; - evPtr = ckalloc(sizeof(SocketEvent)); + evPtr = (SocketEvent *) ckalloc(sizeof(SocketEvent)); evPtr->header.proc = SocketEventProc; - evPtr->socket = infoPtr->sockets->fd; + evPtr->socket = infoPtr->socket; Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL); } } @@ -680,7 +625,6 @@ SocketEventProc( int mask = 0; int events; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - TcpFdList *fds; if (!(flags & TCL_FILE_EVENTS)) { return 0; @@ -693,7 +637,7 @@ SocketEventProc( WaitForSingleObject(tsdPtr->socketListLock, INFINITE); for (infoPtr = tsdPtr->socketList; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { - if (infoPtr->sockets->fd == eventPtr->socket) { + if (infoPtr->socket == eventPtr->socket) { break; } } @@ -714,9 +658,7 @@ SocketEventProc( */ if (infoPtr->readyEvents & FD_ACCEPT) { - for (fds = infoPtr->sockets; fds != NULL; fds = fds->next) { - TcpAccept(fds); - } + TcpAccept(infoPtr); return 1; } @@ -742,44 +684,52 @@ SocketEventProc( Tcl_SetMaxBlockTime(&blockTime); mask |= TCL_READABLE|TCL_WRITABLE; } else if (events & FD_READ) { - fd_set readFds; - struct timeval timeout; - /* - * We must check to see if data is really available, since someone - * could have consumed the data in the meantime. Turn off async - * notification so select will work correctly. If the socket is still - * readable, notify the channel driver, otherwise reset the async - * select handler and keep waiting. + * Throw the readable event if an async connect failed. */ - SendMessage(tsdPtr->hwnd, SOCKET_SELECT, - (WPARAM) UNSELECT, (LPARAM) infoPtr); - - FD_ZERO(&readFds); - FD_SET(infoPtr->sockets->fd, &readFds); - timeout.tv_usec = 0; - timeout.tv_sec = 0; + if (infoPtr->lastError) { - if (select(0, &readFds, NULL, NULL, &timeout) != 0) { mask |= TCL_READABLE; + } else { - infoPtr->readyEvents &= ~(FD_READ); - SendMessage(tsdPtr->hwnd, SOCKET_SELECT, - (WPARAM) SELECT, (LPARAM) infoPtr); - } - } - if (events & (FD_WRITE | FD_CONNECT)) { - mask |= TCL_WRITABLE; - if (events & FD_CONNECT && infoPtr->lastError != NO_ERROR) { + fd_set readFds; + struct timeval timeout; + /* - * Connect errors should also fire the readable handler. + * We must check to see if data is really available, since someone + * could have consumed the data in the meantime. Turn off async + * notification so select will work correctly. If the socket is still + * readable, notify the channel driver, otherwise reset the async + * select handler and keep waiting. */ - mask |= TCL_READABLE; + SendMessage(tsdPtr->hwnd, SOCKET_SELECT, + (WPARAM) UNSELECT, (LPARAM) infoPtr); + + FD_ZERO(&readFds); + FD_SET(infoPtr->socket, &readFds); + timeout.tv_usec = 0; + timeout.tv_sec = 0; + + if (select(0, &readFds, NULL, NULL, &timeout) != 0) { + mask |= TCL_READABLE; + } else { + infoPtr->readyEvents &= ~(FD_READ); + SendMessage(tsdPtr->hwnd, SOCKET_SELECT, + (WPARAM) SELECT, (LPARAM) infoPtr); + } } } + /* + * writable event + */ + + if (events & FD_WRITE) { + mask |= TCL_WRITABLE; + } + if (mask) { Tcl_NotifyChannel(infoPtr->channel, mask); } @@ -808,7 +758,7 @@ TcpBlockProc( int mode) /* TCL_MODE_BLOCKING or * TCL_MODE_NONBLOCKING. */ { - SocketInfo *infoPtr = instanceData; + SocketInfo *infoPtr = (SocketInfo *) instanceData; if (mode == TCL_MODE_NONBLOCKING) { infoPtr->flags |= SOCKET_ASYNC; @@ -842,10 +792,10 @@ TcpCloseProc( ClientData instanceData, /* The socket to close. */ Tcl_Interp *interp) /* Unused. */ { - SocketInfo *infoPtr = instanceData; + SocketInfo *infoPtr = (SocketInfo *) instanceData; /* TIP #218 */ int errorCode = 0; - /* ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); */ + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); /* * Check that WinSock is initialized; do not call it if not, to prevent @@ -860,73 +810,37 @@ TcpCloseProc( * background. */ - if (closesocket(infoPtr->sockets->fd) == SOCKET_ERROR) { + if (closesocket(infoPtr->socket) == SOCKET_ERROR) { TclWinConvertWSAError((DWORD) WSAGetLastError()); errorCode = Tcl_GetErrno(); } } /* - * TIP #218. Removed the code removing the structure from the global - * socket list. This is now done by the thread action callbacks, and only - * there. This happens before this code is called. We can free without - * fear of damaging the list. + * Clear an eventual tsd info list pointer. + * This may be called, if an async socket connect fails or is closed + * between connect and thread action callback. */ + if (tsdPtr->pendingSocketInfo != NULL + && tsdPtr->pendingSocketInfo == infoPtr) { - ckfree(infoPtr); - return errorCode; -} - -/* - *---------------------------------------------------------------------- - * - * TcpClose2Proc -- - * - * This function is called by the generic IO level to perform the channel - * type specific part of a half-close: namely, a shutdown() on a socket. - * - * Results: - * 0 if successful, the value of errno if failed. - * - * Side effects: - * Shuts down one side of the socket. - * - *---------------------------------------------------------------------- - */ + /* get infoPtr lock, because this concerns the notifier thread */ + WaitForSingleObject(tsdPtr->socketListLock, INFINITE); -static int -TcpClose2Proc( - ClientData instanceData, /* The socket to close. */ - Tcl_Interp *interp, /* For error reporting. */ - int flags) /* Flags that indicate which side to close. */ -{ - SocketInfo *infoPtr = instanceData; - int errorCode = 0; - int sd; + tsdPtr->pendingSocketInfo = NULL; + + /* Free list lock */ + SetEvent(tsdPtr->socketListLock); + } /* - * Shutdown the OS socket handle. + * TIP #218. Removed the code removing the structure from the global + * socket list. This is now done by the thread action callbacks, and only + * there. This happens before this code is called. We can free without + * fear of damaging the list. */ - switch(flags) - { - case TCL_CLOSE_READ: - sd=SD_RECEIVE; - break; - case TCL_CLOSE_WRITE: - sd=SD_SEND; - break; - default: - if (interp) { - Tcl_AppendResult(interp, - "Socket close2proc called bidirectionally", NULL); - } - return TCL_ERROR; - } - if (shutdown(infoPtr->sockets->fd,sd) == SOCKET_ERROR) { - TclWinConvertWSAError((DWORD) WSAGetLastError()); - errorCode = Tcl_GetErrno(); - } + ckfree((char *) infoPtr); return errorCode; } @@ -950,15 +864,12 @@ static SocketInfo * NewSocketInfo( SOCKET socket) { - SocketInfo *infoPtr = ckalloc(sizeof(SocketInfo)); - TcpFdList *fds = ckalloc(sizeof(TcpFdList)); - - fds->fd = socket; - fds->next = NULL; - fds->infoPtr = infoPtr; + SocketInfo *infoPtr; /* ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); */ + + infoPtr = (SocketInfo *) ckalloc((unsigned) sizeof(SocketInfo)); infoPtr->channel = 0; - infoPtr->sockets = fds; + infoPtr->socket = socket; infoPtr->flags = 0; infoPtr->watchEvents = 0; infoPtr->readyEvents = 0; @@ -1009,15 +920,12 @@ CreateSocket( * asynchronously. */ { u_long flag = 1; /* Indicates nonblocking mode. */ - int asyncConnect = 0; /* Will be 1 if async connect is in - * progress. */ - unsigned short chosenport = 0; - struct addrinfo *addrlist = NULL, *addrPtr; /* socket address */ - struct addrinfo *myaddrlist = NULL, *myaddrPtr; /* Socket address for client */ - const char *errorMsg = NULL; + SOCKADDR_IN sockaddr; /* Socket address */ + SOCKADDR_IN mysockaddr; /* Socket address for client */ SOCKET sock = INVALID_SOCKET; - SocketInfo *infoPtr = NULL; /* The returned value. */ - ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey); + SocketInfo *infoPtr=NULL; /* The returned value. */ + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + TclThreadDataKeyGet(&dataKey); /* * Check that WinSock is initialized; do not call it if not, to prevent @@ -1029,242 +937,200 @@ CreateSocket( return NULL; } - if (!TclCreateSocketAddress(interp, &addrlist, host, port, server, &errorMsg)) { + if (!CreateSocketAddress(&sockaddr, host, port)) { goto error; } - if (!TclCreateSocketAddress(interp, &myaddrlist, myaddr, myport, 1, &errorMsg)) { + if ((myaddr != NULL || myport != 0) && + !CreateSocketAddress(&mysockaddr, myaddr, myport)) { goto error; } - if (server) { - TcpFdList *fds = NULL, *newfds; - for (addrPtr = addrlist; addrPtr != NULL; addrPtr = addrPtr->ai_next) { - sock = socket(addrPtr->ai_family, SOCK_STREAM, 0); - if (sock == INVALID_SOCKET) { - TclWinConvertWSAError((DWORD) WSAGetLastError()); - continue; - } - - /* - * Win-NT has a misfeature that sockets are inherited in child - * processes by default. Turn off the inherit bit. - */ + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock == INVALID_SOCKET) { + goto error; + } - SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0); + /* + * Win-NT has a misfeature that sockets are inherited in child processes + * by default. Turn off the inherit bit. + */ - /* - * Set kernel space buffering - */ + SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0); - TclSockMinimumBuffers((ClientData)sock, TCP_BUFFER_SIZE); + /* + * Set kernel space buffering + */ - /* - * Make sure we use the same port when opening two server sockets - * for IPv4 and IPv6. - * - * As sockaddr_in6 uses the same offset and size for the port - * member as sockaddr_in, we can handle both through the IPv4 API. - */ - if (port == 0 && chosenport != 0) { - ((struct sockaddr_in *) addrPtr->ai_addr)->sin_port = - htons(chosenport); - } + TclSockMinimumBuffers((void *)sock, TCP_BUFFER_SIZE); - /* - * Bind to the specified port. Note that we must not call - * setsockopt with SO_REUSEADDR because Microsoft allows addresses - * to be reused even if they are still in use. - * - * Bind should not be affected by the socket having already been - * set into nonblocking mode. If there is trouble, this is one - * place to look for bugs. - */ + if (server) { + /* + * Bind to the specified port. Note that we must not call setsockopt + * with SO_REUSEADDR because Microsoft allows addresses to be reused + * even if they are still in use. + * + * Bind should not be affected by the socket having already been set + * into nonblocking mode. If there is trouble, this is one place to + * look for bugs. + */ - if (bind(sock, addrPtr->ai_addr, addrPtr->ai_addrlen) + if (bind(sock, (SOCKADDR *) &sockaddr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR) { - TclWinConvertWSAError((DWORD) WSAGetLastError()); - closesocket(sock); - continue; - } - if (port == 0 && chosenport == 0) { - address sockname; - socklen_t namelen = sizeof(sockname); - /* - * Synchronize port numbers when binding to port 0 of multiple - * addresses. - */ - if (getsockname(sock, &sockname.sa, &namelen) >= 0) { - chosenport = ntohs(sockname.sa4.sin_port); - } - } + goto error; + } - /* - * Set the maximum number of pending connect requests to the max value - * allowed on each platform (Win32 and Win32s may be different, and - * there may be differences between TCP/IP stacks). - */ + /* + * Set the maximum number of pending connect requests to the max value + * allowed on each platform (Win32 and Win32s may be different, and + * there may be differences between TCP/IP stacks). + */ - if (listen(sock, SOMAXCONN) == SOCKET_ERROR) { - TclWinConvertWSAError((DWORD) WSAGetLastError()); - closesocket(sock); - continue; - } + if (listen(sock, SOMAXCONN) == SOCKET_ERROR) { + goto error; + } - if (infoPtr == NULL) { - /* - * Add this socket to the global list of sockets. - */ + /* + * Add this socket to the global list of sockets. + */ - infoPtr = NewSocketInfo(sock); - fds = infoPtr->sockets; + infoPtr = NewSocketInfo(sock); - /* - * Set up the select mask for connection request events. - */ + /* + * Set up the select mask for connection request events. + */ - infoPtr->selectEvents = FD_ACCEPT; - infoPtr->watchEvents |= FD_ACCEPT; + infoPtr->selectEvents = FD_ACCEPT; + infoPtr->watchEvents |= FD_ACCEPT; - } else { - newfds = ckalloc(sizeof(TcpFdList)); - memset(newfds, (int) 0, sizeof(TcpFdList)); - newfds->fd = sock; - newfds->infoPtr = infoPtr; - newfds->next = NULL; - fds->next = newfds; - fds = newfds; + /* + * Register for interest in events in the select mask. Note that this + * automatically places the socket into non-blocking mode. + */ + + ioctlsocket(sock, (long) FIONBIO, &flag); + SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, + (LPARAM) infoPtr); + + } else { + /* + * Try to bind to a local port, if specified. + */ + + if (myaddr != NULL || myport != 0) { + if (bind(sock, (SOCKADDR *) &mysockaddr, sizeof(SOCKADDR_IN)) + == SOCKET_ERROR) { + goto error; } } - } else { - for (addrPtr = addrlist; addrPtr != NULL; - addrPtr = addrPtr->ai_next) { - for (myaddrPtr = myaddrlist; myaddrPtr != NULL; - myaddrPtr = myaddrPtr->ai_next) { - /* - * No need to try combinations of local and remote addresses - * of different families. - */ - if (myaddrPtr->ai_family != addrPtr->ai_family) { - continue; - } - sock = socket(myaddrPtr->ai_family, SOCK_STREAM, 0); - if (sock == INVALID_SOCKET) { - TclWinConvertWSAError((DWORD) WSAGetLastError()); - continue; - } + /* + * Allocate socket info structure + */ - /* - * Win-NT has a misfeature that sockets are inherited in child - * processes by default. Turn off the inherit bit. - */ + infoPtr = NewSocketInfo(sock); - SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0); + /* + * Set the socket into nonblocking mode if the connect should be done + * in the background. Activate connect notification. + */ - /* - * Set kernel space buffering - */ + if (async) { - TclSockMinimumBuffers((ClientData)sock, TCP_BUFFER_SIZE); + /* get infoPtr lock */ + WaitForSingleObject(tsdPtr->socketListLock, INFINITE); - /* - * Try to bind to a local port. - */ + /* + * Buffer new infoPtr in the tsd memory as long as it is not in + * the info list. This allows the event procedure to process the + * event. + * Bugfig for 336441ed59 to not ignore notifications until the + * infoPtr is in the list.. + */ - if (bind(sock, myaddrPtr->ai_addr, myaddrPtr->ai_addrlen) - == SOCKET_ERROR) { - TclWinConvertWSAError((DWORD) WSAGetLastError()); - goto looperror; - } - /* - * Set the socket into nonblocking mode if the connect should - * be done in the background. - */ - if (async) { - if (ioctlsocket(sock, (long) FIONBIO, &flag) - == SOCKET_ERROR) { - TclWinConvertWSAError((DWORD) WSAGetLastError()); - goto looperror; - } - } + tsdPtr->pendingSocketInfo = infoPtr; - /* - * Attempt to connect to the remote socket. - */ + /* + * Set connect mask to connect events + * This is activated by a SOCKET_SELECT message to the notifier + * thread. + */ - if (connect(sock, addrPtr->ai_addr, addrPtr->ai_addrlen) - == SOCKET_ERROR) { - TclWinConvertWSAError((DWORD) WSAGetLastError()); - if (Tcl_GetErrno() != EWOULDBLOCK) { - goto looperror; - } + infoPtr->selectEvents |= FD_CONNECT | FD_READ | FD_WRITE | FD_CLOSE; + infoPtr->flags |= SOCKET_ASYNC_CONNECT; + + /* + * Free list lock + */ + SetEvent(tsdPtr->socketListLock); - /* - * The connection is progressing in the background. - */ + /* + * Activate accept notification and put in async mode + * Bug 336441ed59: activate notification before connect + * so we do not miss a notification of a fialed connect. + */ + ioctlsocket(sock, (long) FIONBIO, &flag); + SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, + (LPARAM) infoPtr); - asyncConnect = 1; - goto connected; - } else { - goto connected; - } - looperror: - if (sock != INVALID_SOCKET) { - closesocket(sock); - sock = INVALID_SOCKET; - } - } } - goto error; - connected: /* - * Add this socket to the global list of sockets. + * Attempt to connect to the remote socket. */ - infoPtr = NewSocketInfo(sock); + if (connect(sock, (SOCKADDR *) &sockaddr, + sizeof(SOCKADDR_IN)) == SOCKET_ERROR) { + TclWinConvertWSAError((DWORD) WSAGetLastError()); + if (Tcl_GetErrno() != EWOULDBLOCK) { + goto error; + } - /* - * Set up the select mask for read/write events. If the - * connect attempt has not completed, include connect events. - */ + /* + * The connection is progressing in the background. + */ - infoPtr->selectEvents = FD_READ | FD_WRITE | FD_CLOSE; - if (asyncConnect) { - infoPtr->flags |= SOCKET_ASYNC_CONNECT; - infoPtr->selectEvents |= FD_CONNECT; - } - } + } else { - error: - if (addrlist == NULL) - freeaddrinfo(addrlist); - if (myaddrlist == NULL) - freeaddrinfo(myaddrlist); + /* + * Set up the select mask for read/write events. If the connect + * attempt has not completed, include connect events. + */ - /* - * Register for interest in events in the select mask. Note that this - * automatically places the socket into non-blocking mode. - */ + infoPtr->selectEvents = FD_READ | FD_WRITE | FD_CLOSE; - if (infoPtr != NULL) { - ioctlsocket(sock, (long) FIONBIO, &flag); - SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, (LPARAM) infoPtr); + /* + * Register for interest in events in the select mask. Note that this + * automatically places the socket into non-blocking mode. + */ - return infoPtr; + ioctlsocket(sock, (long) FIONBIO, &flag); + SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, + (LPARAM) infoPtr); + } } + return infoPtr; + + error: + TclWinConvertWSAError((DWORD) WSAGetLastError()); if (interp != NULL) { Tcl_AppendResult(interp, "couldn't open socket: ", Tcl_PosixError(interp), NULL); } - if (sock != INVALID_SOCKET) { + if (infoPtr != NULL) { + /* + * Free the allocated socket info structure and close the socket + */ + TcpCloseProc(infoPtr, interp); + } else if (sock != INVALID_SOCKET) { + /* + * No socket structure jet - just close + */ closesocket(sock); } return NULL; } -#if 0 /* *---------------------------------------------------------------------- * @@ -1304,7 +1170,7 @@ CreateSocketAddress( ZeroMemory(sockaddrPtr, sizeof(SOCKADDR_IN)); sockaddrPtr->sin_family = AF_INET; - sockaddrPtr->sin_port = htons((u_short) (port & 0xFFFF)); + sockaddrPtr->sin_port = htons((unsigned short) (port & 0xFFFF)); if (host == NULL) { addr.s_addr = INADDR_ANY; } else { @@ -1336,7 +1202,6 @@ CreateSocketAddress( sockaddrPtr->sin_addr.s_addr = addr.s_addr; return 1; /* Success. */ } -#endif /* *---------------------------------------------------------------------- @@ -1363,7 +1228,8 @@ WaitForSocketEvent( { int result = 1; int oldMode; - ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + TclThreadDataKeyGet(&dataKey); /* * Be sure to disable event servicing so we are truly modal. @@ -1373,13 +1239,17 @@ WaitForSocketEvent( /* * Reset WSAAsyncSelect so we have a fresh set of events pending. + * Don't do that if we are waiting for a connect as we may miss + * a connect (bug 336441ed59). */ - SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) UNSELECT, - (LPARAM) infoPtr); - - SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, - (LPARAM) infoPtr); + if ( 0 == (events & FD_CONNECT) ) { + SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) UNSELECT, + (LPARAM) infoPtr); + + SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, + (LPARAM) infoPtr); + } while (1) { if (infoPtr->lastError) { @@ -1448,10 +1318,10 @@ Tcl_OpenTcpClient( return NULL; } - sprintf(channelName, "sock%Id", (size_t) infoPtr->sockets->fd); + sprintf(channelName, "sock%" TCL_I_MODIFIER "u", (size_t)infoPtr->socket); infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, - infoPtr, (TCL_READABLE | TCL_WRITABLE)); + (ClientData) infoPtr, (TCL_READABLE | TCL_WRITABLE)); if (Tcl_SetChannelOption(interp, infoPtr->channel, "-translation", "auto crlf") == TCL_ERROR) { Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel); @@ -1495,13 +1365,13 @@ Tcl_MakeTcpClientChannel( return NULL; } - tsdPtr = TclThreadDataKeyGet(&dataKey); + tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); /* * Set kernel space buffering and non-blocking. */ - TclSockMinimumBuffers((ClientData) sock, TCP_BUFFER_SIZE); + TclSockMinimumBuffers(sock, TCP_BUFFER_SIZE); infoPtr = NewSocketInfo((SOCKET) sock); @@ -1513,9 +1383,9 @@ Tcl_MakeTcpClientChannel( SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, (LPARAM) infoPtr); - sprintf(channelName, "sock%Id", (size_t) infoPtr->sockets->fd); + sprintf(channelName, "sock%" TCL_I_MODIFIER "u", (size_t)infoPtr->socket); infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, - infoPtr, (TCL_READABLE | TCL_WRITABLE)); + (ClientData) infoPtr, (TCL_READABLE | TCL_WRITABLE)); Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto crlf"); return infoPtr->channel; } @@ -1566,10 +1436,10 @@ Tcl_OpenTcpServer( infoPtr->acceptProc = acceptProc; infoPtr->acceptProcData = acceptProcData; - sprintf(channelName, "sock%Id", (size_t) infoPtr->sockets->fd); + sprintf(channelName, "sock%" TCL_I_MODIFIER "u", (size_t)infoPtr->socket); infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, - infoPtr, 0); + (ClientData) infoPtr, 0); if (Tcl_SetChannelOption(interp, infoPtr->channel, "-eofchar", "") == TCL_ERROR) { Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel); @@ -1598,15 +1468,15 @@ Tcl_OpenTcpServer( static void TcpAccept( - TcpFdList *fds) /* Socket to accept. */ + SocketInfo *infoPtr) /* Socket to accept. */ { SOCKET newSocket; SocketInfo *newInfoPtr; - SocketInfo *infoPtr = fds->infoPtr; SOCKADDR_IN addr; int len; char channelName[16 + TCL_INTEGER_SPACE]; - ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + TclThreadDataKeyGet(&dataKey); /* * Accept the incoming connection request. @@ -1614,7 +1484,8 @@ TcpAccept( len = sizeof(SOCKADDR_IN); - newSocket = accept(fds->fd, (SOCKADDR *)&addr, &len); + newSocket = accept(infoPtr->socket, (SOCKADDR *)&addr, + &len); /* * Protect access to sockets (acceptEventCount, readyEvents) in socketList @@ -1658,7 +1529,7 @@ TcpAccept( SetHandleInformation((HANDLE) newSocket, HANDLE_FLAG_INHERIT, 0); /* - * Add this socket to the global list of sockets. + * Allocate socket info structure */ newInfoPtr = NewSocketInfo(newSocket); @@ -1671,9 +1542,9 @@ TcpAccept( SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, (LPARAM) newInfoPtr); - sprintf(channelName, "sock%Id", (size_t) newInfoPtr->sockets->fd); + sprintf(channelName, "sock%" TCL_I_MODIFIER "u", (size_t)newInfoPtr->socket); newInfoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, - newInfoPtr, (TCL_READABLE | TCL_WRITABLE)); + (ClientData) newInfoPtr, (TCL_READABLE | TCL_WRITABLE)); if (Tcl_SetChannelOption(NULL, newInfoPtr->channel, "-translation", "auto crlf") == TCL_ERROR) { Tcl_Close((Tcl_Interp *) NULL, newInfoPtr->channel); @@ -1690,7 +1561,7 @@ TcpAccept( */ if (infoPtr->acceptProc != NULL) { - infoPtr->acceptProc(infoPtr->acceptProcData, newInfoPtr->channel, + (infoPtr->acceptProc) (infoPtr->acceptProcData, newInfoPtr->channel, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); } } @@ -1719,10 +1590,11 @@ TcpInputProc( int toRead, /* Maximum number of bytes to read. */ int *errorCodePtr) /* Where to store error codes. */ { - SocketInfo *infoPtr = instanceData; + SocketInfo *infoPtr = (SocketInfo *) instanceData; int bytesRead; DWORD error; - ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + TclThreadDataKeyGet(&dataKey); *errorCodePtr = 0; @@ -1766,7 +1638,7 @@ TcpInputProc( while (1) { SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) UNSELECT, (LPARAM) infoPtr); - bytesRead = recv(infoPtr->sockets->fd, buf, toRead, 0); + bytesRead = recv(infoPtr->socket, buf, toRead, 0); infoPtr->readyEvents &= ~(FD_READ); /* @@ -1856,10 +1728,11 @@ TcpOutputProc( int toWrite, /* Maximum number of bytes to write. */ int *errorCodePtr) /* Where to store error codes. */ { - SocketInfo *infoPtr = instanceData; + SocketInfo *infoPtr = (SocketInfo *) instanceData; int bytesWritten; DWORD error; - ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + TclThreadDataKeyGet(&dataKey); *errorCodePtr = 0; @@ -1887,7 +1760,7 @@ TcpOutputProc( SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) UNSELECT, (LPARAM) infoPtr); - bytesWritten = send(infoPtr->sockets->fd, buf, toWrite, 0); + bytesWritten = send(infoPtr->socket, buf, toWrite, 0); if (bytesWritten != SOCKET_ERROR) { /* * Since Windows won't generate a new write event until we hit an @@ -1965,9 +1838,9 @@ TcpSetOptionProc( const char *value) /* New value for option. */ { #ifdef TCL_FEATURE_KEEPALIVE_NAGLE - SocketInfo *infoPtr = instanceData; + SocketInfo *infoPtr; SOCKET sock; -#endif /*TCL_FEATURE_KEEPALIVE_NAGLE*/ +#endif /* * Check that WinSock is initialized; do not call it if not, to prevent @@ -1983,7 +1856,8 @@ TcpSetOptionProc( } #ifdef TCL_FEATURE_KEEPALIVE_NAGLE - sock = infoPtr->sockets->fd; + infoPtr = (SocketInfo *) instanceData; + sock = infoPtr->socket; if (!strcasecmp(optionName, "-keepalive")) { BOOL val = FALSE; @@ -2065,12 +1939,14 @@ TcpGetOptionProc( Tcl_DString *dsPtr) /* Where to store the computed value; * initialized by caller. */ { - SocketInfo *infoPtr = instanceData; - char host[NI_MAXHOST], port[NI_MAXSERV]; + SocketInfo *infoPtr; + SOCKADDR_IN sockname; + SOCKADDR_IN peername; + struct hostent *hostEntPtr; SOCKET sock; + int size = sizeof(SOCKADDR_IN); size_t len = 0; - int reverseDNS = 0; -#define SUPPRESS_RDNS_VAR "::tcl::unsupported::noReverseDNS" + char buf[TCL_INTEGER_SPACE]; /* * Check that WinSock is initialized; do not call it if not, to prevent @@ -2085,7 +1961,8 @@ TcpGetOptionProc( return TCL_ERROR; } - sock = infoPtr->sockets->fd; + infoPtr = (SocketInfo *) instanceData; + sock = (int) infoPtr->socket; if (optionName != NULL) { len = strlen(optionName); } @@ -2097,7 +1974,7 @@ TcpGetOptionProc( int ret; optlen = sizeof(int); - ret = TclWinGetSockOpt(sock, SOL_SOCKET, SO_ERROR, + ret = TclWinGetSockOpt((int)sock, SOL_SOCKET, SO_ERROR, (char *)&err, &optlen); if (ret == SOCKET_ERROR) { err = WSAGetLastError(); @@ -2109,27 +1986,28 @@ TcpGetOptionProc( return TCL_OK; } - if (interp != NULL && Tcl_GetVar(interp, SUPPRESS_RDNS_VAR, 0) != NULL) { - reverseDNS = NI_NUMERICHOST; - } - if ((len == 0) || ((len > 1) && (optionName[1] == 'p') && (strncmp(optionName, "-peername", len) == 0))) { - address peername; - socklen_t size = sizeof(peername); - if (getpeername(sock, (LPSOCKADDR) &(peername.sa), &size) == 0) { + if (getpeername(sock, (LPSOCKADDR) &peername, &size) == 0) { if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-peername"); Tcl_DStringStartSublist(dsPtr); } + Tcl_DStringAppendElement(dsPtr, inet_ntoa(peername.sin_addr)); - getnameinfo(&(peername.sa), size, host, sizeof(host), - NULL, 0, NI_NUMERICHOST); - Tcl_DStringAppendElement(dsPtr, host); - getnameinfo(&(peername.sa), size, host, sizeof(host), - port, sizeof(port), reverseDNS | NI_NUMERICSERV); - Tcl_DStringAppendElement(dsPtr, host); - Tcl_DStringAppendElement(dsPtr, port); + if (peername.sin_addr.s_addr == 0) { + hostEntPtr = NULL; + } else { + hostEntPtr = gethostbyaddr((char *) &(peername.sin_addr), + sizeof(peername.sin_addr), AF_INET); + } + if (hostEntPtr != NULL) { + Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name); + } else { + Tcl_DStringAppendElement(dsPtr, inet_ntoa(peername.sin_addr)); + } + TclFormatInt(buf, ntohs(peername.sin_port)); + Tcl_DStringAppendElement(dsPtr, buf); if (len == 0) { Tcl_DStringEndSublist(dsPtr); } else { @@ -2156,53 +2034,25 @@ TcpGetOptionProc( if ((len == 0) || ((len > 1) && (optionName[1] == 's') && (strncmp(optionName, "-sockname", len) == 0))) { - TcpFdList *fds; - address sockname; - socklen_t size; - int found = 0; - - if (len == 0) { - Tcl_DStringAppendElement(dsPtr, "-sockname"); - Tcl_DStringStartSublist(dsPtr); - } - for (fds = infoPtr->sockets; fds != NULL; fds = fds->next) { - sock = fds->fd; - size = sizeof(sockname); - if (getsockname(sock, &(sockname.sa), &size) >= 0) { - int flags = reverseDNS; - found = 1; - - getnameinfo(&sockname.sa, size, host, sizeof(host), - NULL, 0, NI_NUMERICHOST); - Tcl_DStringAppendElement(dsPtr, host); - - /* - * We don't want to resolve INADDR_ANY and sin6addr_any; they - * can sometimes cause problems (and never have a name). - */ - flags |= NI_NUMERICSERV; - if (sockname.sa.sa_family == AF_INET) { - if (sockname.sa4.sin_addr.s_addr == INADDR_ANY) { - flags |= NI_NUMERICHOST; - } - } else if (sockname.sa.sa_family == AF_INET6) { - if ((IN6_ARE_ADDR_EQUAL(&sockname.sa6.sin6_addr, - &in6addr_any)) || - (IN6_IS_ADDR_V4MAPPED(&sockname.sa6.sin6_addr) - && sockname.sa6.sin6_addr.s6_addr[12] == 0 - && sockname.sa6.sin6_addr.s6_addr[13] == 0 - && sockname.sa6.sin6_addr.s6_addr[14] == 0 - && sockname.sa6.sin6_addr.s6_addr[15] == 0)) { - flags |= NI_NUMERICHOST; - } - } - getnameinfo(&sockname.sa, size, host, sizeof(host), - port, sizeof(port), flags); - Tcl_DStringAppendElement(dsPtr, host); - Tcl_DStringAppendElement(dsPtr, port); + if (getsockname(sock, (LPSOCKADDR) &sockname, &size) == 0) { + if (len == 0) { + Tcl_DStringAppendElement(dsPtr, "-sockname"); + Tcl_DStringStartSublist(dsPtr); } - } - if (found) { + Tcl_DStringAppendElement(dsPtr, inet_ntoa(sockname.sin_addr)); + if (sockname.sin_addr.s_addr == 0) { + hostEntPtr = NULL; + } else { + hostEntPtr = gethostbyaddr((char *) &(sockname.sin_addr), + sizeof(peername.sin_addr), AF_INET); + } + if (hostEntPtr != NULL) { + Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name); + } else { + Tcl_DStringAppendElement(dsPtr, inet_ntoa(sockname.sin_addr)); + } + TclFormatInt(buf, ntohs(sockname.sin_port)); + Tcl_DStringAppendElement(dsPtr, buf); if (len == 0) { Tcl_DStringEndSublist(dsPtr); } else { @@ -2246,7 +2096,8 @@ TcpGetOptionProc( Tcl_DStringAppendElement(dsPtr, "-nagle"); } optlen = sizeof(BOOL); - getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, &optlen); + getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, + &optlen); if (opt) { Tcl_DStringAppendElement(dsPtr, "0"); } else { @@ -2295,7 +2146,7 @@ TcpWatchProc( * TCL_READABLE, TCL_WRITABLE and * TCL_EXCEPTION. */ { - SocketInfo *infoPtr = instanceData; + SocketInfo *infoPtr = (SocketInfo *) instanceData; /* * Update the watch events mask. Only if the socket is not a server @@ -2346,9 +2197,9 @@ TcpGetHandleProc( int direction, /* Not used. */ ClientData *handlePtr) /* Where to store the handle. */ { - SocketInfo *statePtr = instanceData; + SocketInfo *statePtr = (SocketInfo *) instanceData; - *handlePtr = INT2PTR(statePtr->sockets->fd); + *handlePtr = (ClientData) statePtr->socket; return TCL_OK; } @@ -2373,13 +2224,13 @@ SocketThread( LPVOID arg) { MSG msg; - ThreadSpecificData *tsdPtr = arg; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *)(arg); /* * Create a dummy window receiving socket events. */ - tsdPtr->hwnd = CreateWindow(classname, classname, + tsdPtr->hwnd = CreateWindow("TclSocket", "TclSocket", WS_TILED, 0, 0, 0, 0, NULL, NULL, windowClass.hInstance, arg); /* @@ -2444,6 +2295,7 @@ SocketProc( int event, error; SOCKET socket; SocketInfo *infoPtr; + int info_found = 0; ThreadSpecificData *tsdPtr = (ThreadSpecificData *) #ifdef _WIN64 GetWindowLongPtr(hwnd, GWLP_USERDATA); @@ -2488,59 +2340,72 @@ SocketProc( WaitForSingleObject(tsdPtr->socketListLock, INFINITE); for (infoPtr = tsdPtr->socketList; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { - if (infoPtr->sockets->fd == socket) { - /* - * Update the socket state. - * - * A count of FD_ACCEPTS is stored, so if an FD_CLOSE event - * happens, then clear the FD_ACCEPT count. Otherwise, - * increment the count if the current event is an FD_ACCEPT. - */ + if (infoPtr->socket == socket) { + info_found = 1; + break; + } + } + /* + * Check if there is a pending info structure not jet in the + * list + */ + if ( !info_found + && tsdPtr->pendingSocketInfo != NULL + && tsdPtr->pendingSocketInfo->socket ==socket ) { + infoPtr = tsdPtr->pendingSocketInfo; + info_found = 1; + } + if (info_found) { - if (event & FD_CLOSE) { - infoPtr->acceptEventCount = 0; - infoPtr->readyEvents &= ~(FD_WRITE|FD_ACCEPT); - } else if (event & FD_ACCEPT) { - infoPtr->acceptEventCount++; - } + /* + * Update the socket state. + * + * A count of FD_ACCEPTS is stored, so if an FD_CLOSE event + * happens, then clear the FD_ACCEPT count. Otherwise, + * increment the count if the current event is an FD_ACCEPT. + */ - if (event & FD_CONNECT) { - /* - * The socket is now connected, clear the async connect - * flag. - */ + if (event & FD_CLOSE) { + infoPtr->acceptEventCount = 0; + infoPtr->readyEvents &= ~(FD_WRITE|FD_ACCEPT); + } else if (event & FD_ACCEPT) { + infoPtr->acceptEventCount++; + } - infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT); + if (event & FD_CONNECT) { + /* + * The socket is now connected, clear the async connect + * flag. + */ - /* - * Remember any error that occurred so we can report - * connection failures. - */ + infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT); - if (error != ERROR_SUCCESS) { - TclWinConvertWSAError((DWORD) error); - infoPtr->lastError = Tcl_GetErrno(); - } - } + /* + * Remember any error that occurred so we can report + * connection failures. + */ - if (infoPtr->flags & SOCKET_ASYNC_CONNECT) { - infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT); - if (error != ERROR_SUCCESS) { - TclWinConvertWSAError((DWORD) error); - infoPtr->lastError = Tcl_GetErrno(); - } - infoPtr->readyEvents |= FD_WRITE; + if (error != ERROR_SUCCESS) { + /* Async Connect error */ + TclWinConvertWSAError((DWORD) error); + infoPtr->lastError = Tcl_GetErrno(); + /* Fire also readable event on connect failure */ + infoPtr->readyEvents |= FD_READ; } - infoPtr->readyEvents |= event; - /* - * Wake up the Main Thread. - */ + /* fire writable event on connect */ + infoPtr->readyEvents |= FD_WRITE; - SetEvent(tsdPtr->readyEvent); - Tcl_ThreadAlert(tsdPtr->threadId); - break; } + + infoPtr->readyEvents |= event; + + /* + * Wake up the Main Thread. + */ + + SetEvent(tsdPtr->readyEvent); + Tcl_ThreadAlert(tsdPtr->threadId); } SetEvent(tsdPtr->socketListLock); break; @@ -2548,14 +2413,18 @@ SocketProc( case SOCKET_SELECT: infoPtr = (SocketInfo *) lParam; if (wParam == SELECT) { - WSAAsyncSelect(infoPtr->sockets->fd, hwnd, + /* + * Start notification by windows messages on socket events + */ + + WSAAsyncSelect(infoPtr->socket, hwnd, SOCKET_MESSAGE, infoPtr->selectEvents); } else { /* - * Clear the selection mask + * UNSELECT: Clear the selection mask */ - WSAAsyncSelect(infoPtr->sockets->fd, hwnd, 0, 0); + WSAAsyncSelect(infoPtr->socket, hwnd, 0, 0); } break; @@ -2610,37 +2479,33 @@ InitializeHostName( int *lengthPtr, Tcl_Encoding *encodingPtr) { - TCHAR tbuf[MAX_COMPUTERNAME_LENGTH + 1]; - DWORD length = MAX_COMPUTERNAME_LENGTH + 1; + WCHAR wbuf[MAX_COMPUTERNAME_LENGTH + 1]; + DWORD length = sizeof(wbuf) / sizeof(WCHAR); Tcl_DString ds; - if (GetComputerName(tbuf, &length) != 0) { + if ((*tclWinProcs->getComputerNameProc)(wbuf, &length) != 0) { /* * Convert string from native to UTF then change to lowercase. */ - Tcl_UtfToLower(Tcl_WinTCharToUtf(tbuf, -1, &ds)); + Tcl_UtfToLower(Tcl_WinTCharToUtf((TCHAR *) wbuf, -1, &ds)); } else { Tcl_DStringInit(&ds); if (TclpHasSockets(NULL) == TCL_OK) { /* - * Buffer length of 255 copied slavishly from previous version of - * this routine. Presumably there's a more "correct" macro value - * for a properly sized buffer for a gethostname() call. - * Maintainers are welcome to supply it. + * The buffer size of 256 is recommended by the MSDN page that + * documents gethostname() as being always adequate. */ Tcl_DString inDs; Tcl_DStringInit(&inDs); - Tcl_DStringSetLength(&inDs, 255); + Tcl_DStringSetLength(&inDs, 256); if (gethostname(Tcl_DStringValue(&inDs), - Tcl_DStringLength(&inDs)) == 0) { - Tcl_DStringSetLength(&ds, 0); - } else { - Tcl_ExternalToUtfDString(NULL, - Tcl_DStringValue(&inDs), -1, &ds); + Tcl_DStringLength(&inDs)) == 0) { + Tcl_ExternalToUtfDString(NULL, Tcl_DStringValue(&inDs), -1, + &ds); } Tcl_DStringFree(&inDs); } @@ -2648,7 +2513,7 @@ InitializeHostName( *encodingPtr = Tcl_GetEncoding(NULL, "utf-8"); *lengthPtr = Tcl_DStringLength(&ds); - *valuePtr = ckalloc((*lengthPtr) + 1); + *valuePtr = ckalloc((unsigned int) (*lengthPtr)+1); memcpy(*valuePtr, Tcl_DStringValue(&ds), (size_t)(*lengthPtr)+1); Tcl_DStringFree(&ds); } @@ -2672,80 +2537,34 @@ InitializeHostName( *---------------------------------------------------------------------- */ +#undef TclWinGetSockOpt int -TclWinGetSockOpt( - SOCKET s, - int level, - int optname, - char * optval, - int FAR *optlen) +TclWinGetSockOpt(SOCKET s, int level, int optname, char *optval, + int *optlen) { - /* - * Check that WinSock is initialized; do not call it if not, to prevent - * system crashes. This can happen at exit time if the exit handler for - * WinSock ran before other exit handlers that want to use sockets. - */ - - if (!SocketsEnabled()) { - return SOCKET_ERROR; - } - return getsockopt(s, level, optname, optval, optlen); } +#undef TclWinSetSockOpt int -TclWinSetSockOpt( - SOCKET s, - int level, - int optname, - const char * optval, +TclWinSetSockOpt(SOCKET s, int level, int optname, const char *optval, int optlen) { - /* - * Check that WinSock is initialized; do not call it if not, to prevent - * system crashes. This can happen at exit time if the exit handler for - * WinSock ran before other exit handlers that want to use sockets. - */ - - if (!SocketsEnabled()) { - return SOCKET_ERROR; - } - return setsockopt(s, level, optname, optval, optlen); } -u_short -TclWinNToHS( - u_short netshort) +char * +TclpInetNtoa(struct in_addr addr) { - /* - * Check that WinSock is initialized; do not call it if not, to prevent - * system crashes. This can happen at exit time if the exit handler for - * WinSock ran before other exit handlers that want to use sockets. - */ - - if (!SocketsEnabled()) { - return (u_short) -1; - } - - return ntohs(netshort); + return inet_ntoa(addr); } +#undef TclWinGetServByName struct servent * TclWinGetServByName( const char *name, const char *proto) { - /* - * Check that WinSock is initialized; do not call it if not, to prevent - * system crashes. This can happen at exit time if the exit handler for - * WinSock ran before other exit handlers that want to use sockets. - */ - - if (!SocketsEnabled()) { - return NULL; - } - return getservbyname(name, proto); } @@ -2771,7 +2590,7 @@ TcpThreadActionProc( int action) { ThreadSpecificData *tsdPtr; - SocketInfo *infoPtr = instanceData; + SocketInfo *infoPtr = (SocketInfo *) instanceData; int notifyCmd; if (action == TCL_CHANNEL_THREAD_INSERT) { @@ -2789,6 +2608,11 @@ TcpThreadActionProc( WaitForSingleObject(tsdPtr->socketListLock, INFINITE); infoPtr->nextPtr = tsdPtr->socketList; tsdPtr->socketList = infoPtr; + + if (infoPtr == tsdPtr->pendingSocketInfo) { + tsdPtr->pendingSocketInfo = NULL; + } + SetEvent(tsdPtr->socketListLock); notifyCmd = SELECT; |
