diff options
Diffstat (limited to 'win/tclWinSock.c')
-rw-r--r-- | win/tclWinSock.c | 671 |
1 files changed, 395 insertions, 276 deletions
diff --git a/win/tclWinSock.c b/win/tclWinSock.c index 102feb0..bfcc3a6 100644 --- a/win/tclWinSock.c +++ b/win/tclWinSock.c @@ -8,11 +8,10 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclWinSock.c,v 1.7 1999/04/15 22:38:48 stanton Exp $ + * RCS: @(#) $Id: tclWinSock.c,v 1.8 1999/04/16 00:48:09 stanton Exp $ */ -#include "tclInt.h" -#include "tclPort.h" +#include "tclWinInt.h" /* * The following variable is used to tell whether this module has been @@ -24,6 +23,7 @@ static int initialized = 0; static int hostnameInitialized = 0; static char hostname[255]; /* This buffer should be big enough for * hostname plus domain name. */ +TCL_DECLARE_MUTEX(socketMutex) /* * The following structure contains pointers to all of the WinSock API entry @@ -34,7 +34,6 @@ static char hostname[255]; /* This buffer should be big enough for static struct { HINSTANCE hInstance; /* Handle to WinSock library. */ - HWND hwnd; /* Handle to window for socket messages. */ SOCKET (PASCAL FAR *accept)(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen); int (PASCAL FAR *bind)(SOCKET s, const struct sockaddr FAR *addr, @@ -142,11 +141,16 @@ typedef struct SocketEvent { #define SOCKET_PENDING (1<<3) /* A message has been sent * for this socket */ -/* - * Every open socket has an entry on the following list. - */ +typedef struct ThreadSpecificData { + /* + * Every open socket has an entry on the following list. + */ + + HWND hwnd; /* Handle to window for socket messages. */ + SocketInfo *socketList; +} ThreadSpecificData; -static SocketInfo *socketList; +static Tcl_ThreadDataKey dataKey; /* * Static functions defined in this file. @@ -169,6 +173,8 @@ static LRESULT CALLBACK SocketProc _ANSI_ARGS_((HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)); static void SocketSetupProc _ANSI_ARGS_((ClientData clientData, int flags)); +static void SocketThreadExitHandler _ANSI_ARGS_((ClientData clientData)); +static int SocketsEnabled _ANSI_ARGS_((void)); static void TcpAccept _ANSI_ARGS_((SocketInfo *infoPtr)); static int TcpBlockProc _ANSI_ARGS_((ClientData instanceData, int mode)); @@ -221,6 +227,8 @@ static Tcl_ChannelType tcpChannelType = { * library and set up the winSock function table. If successful, * registers the event window for the socket notifier code. * + * Assumes Mutex is held. + * * Results: * None. * @@ -237,186 +245,203 @@ InitSockets() { WSADATA wsaData; OSVERSIONINFO info; - WNDCLASS class; - - initialized = 1; - Tcl_CreateExitHandler(SocketExitHandler, (ClientData) NULL); - - /* - * Find out if we're running on Win32s. - */ - - info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&info); - - /* - * Check to see if Sockets are supported on this system. Since - * win32s panics if we call WSAStartup on a system that doesn't - * have winsock.dll, we need to look for it on the system first. - * If we find winsock, then load the library and initialize the - * stub table. - */ - - if ((info.dwPlatformId != VER_PLATFORM_WIN32s) - || (SearchPath(NULL, "WINSOCK", ".DLL", 0, NULL, NULL) != 0)) { - winSock.hInstance = LoadLibrary("wsock32.dll"); - } else { - winSock.hInstance = NULL; - } + static WNDCLASSA class; + ThreadSpecificData *tsdPtr = + (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); - /* - * Initialize the function table. - */ - - if (winSock.hInstance == NULL) { - return; + if (! initialized) { + initialized = 1; + Tcl_CreateExitHandler(SocketExitHandler, (ClientData) NULL); + + /* + * Find out if we're running on Win32s. + */ + + info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&info); + + /* + * Check to see if Sockets are supported on this system. Since + * win32s panics if we call WSAStartup on a system that doesn't + * have winsock.dll, we need to look for it on the system first. + * If we find winsock, then load the library and initialize the + * stub table. + */ + + if ((info.dwPlatformId != VER_PLATFORM_WIN32s) + || (SearchPathA(NULL, "WINSOCK", ".DLL", 0, NULL, NULL) != 0)) { + winSock.hInstance = LoadLibraryA("wsock32.dll"); + } else { + winSock.hInstance = NULL; + } + + /* + * Initialize the function table. + */ + + if (!SocketsEnabled()) { + return; + } + + winSock.accept = (SOCKET (PASCAL FAR *)(SOCKET s, + struct sockaddr FAR *addr, int FAR *addrlen)) + GetProcAddress(winSock.hInstance, "accept"); + winSock.bind = (int (PASCAL FAR *)(SOCKET s, + const struct sockaddr FAR *addr, int namelen)) + GetProcAddress(winSock.hInstance, "bind"); + winSock.closesocket = (int (PASCAL FAR *)(SOCKET s)) + GetProcAddress(winSock.hInstance, "closesocket"); + winSock.connect = (int (PASCAL FAR *)(SOCKET s, + const struct sockaddr FAR *name, int namelen)) + GetProcAddress(winSock.hInstance, "connect"); + winSock.ioctlsocket = (int (PASCAL FAR *)(SOCKET s, long cmd, + u_long FAR *argp)) + GetProcAddress(winSock.hInstance, "ioctlsocket"); + winSock.getsockopt = (int (PASCAL FAR *)(SOCKET s, + int level, int optname, char FAR * optval, int FAR *optlen)) + GetProcAddress(winSock.hInstance, "getsockopt"); + winSock.htons = (u_short (PASCAL FAR *)(u_short hostshort)) + GetProcAddress(winSock.hInstance, "htons"); + winSock.inet_addr = (unsigned long (PASCAL FAR *)(const char FAR *cp)) + GetProcAddress(winSock.hInstance, "inet_addr"); + winSock.inet_ntoa = (char FAR * (PASCAL FAR *)(struct in_addr in)) + GetProcAddress(winSock.hInstance, "inet_ntoa"); + winSock.listen = (int (PASCAL FAR *)(SOCKET s, int backlog)) + GetProcAddress(winSock.hInstance, "listen"); + winSock.ntohs = (u_short (PASCAL FAR *)(u_short netshort)) + GetProcAddress(winSock.hInstance, "ntohs"); + winSock.recv = (int (PASCAL FAR *)(SOCKET s, char FAR * buf, + int len, int flags)) GetProcAddress(winSock.hInstance, "recv"); + winSock.select = (int (PASCAL FAR *)(int nfds, fd_set FAR * readfds, + fd_set FAR * writefds, fd_set FAR * exceptfds, + const struct timeval FAR * tiemout)) + GetProcAddress(winSock.hInstance, "select"); + winSock.send = (int (PASCAL FAR *)(SOCKET s, const char FAR * buf, + int len, int flags)) GetProcAddress(winSock.hInstance, "send"); + winSock.setsockopt = (int (PASCAL FAR *)(SOCKET s, int level, + int optname, const char FAR * optval, int optlen)) + GetProcAddress(winSock.hInstance, "setsockopt"); + winSock.shutdown = (int (PASCAL FAR *)(SOCKET s, int how)) + GetProcAddress(winSock.hInstance, "shutdown"); + winSock.socket = (SOCKET (PASCAL FAR *)(int af, int type, + int protocol)) GetProcAddress(winSock.hInstance, "socket"); + winSock.gethostbyaddr = (struct hostent FAR * (PASCAL FAR *) + (const char FAR *addr, int addrlen, int addrtype)) + GetProcAddress(winSock.hInstance, "gethostbyaddr"); + winSock.gethostbyname = (struct hostent FAR * (PASCAL FAR *) + (const char FAR *name)) + GetProcAddress(winSock.hInstance, "gethostbyname"); + winSock.gethostname = (int (PASCAL FAR *)(char FAR * name, + int namelen)) GetProcAddress(winSock.hInstance, "gethostname"); + winSock.getpeername = (int (PASCAL FAR *)(SOCKET sock, + struct sockaddr FAR *name, int FAR *namelen)) + GetProcAddress(winSock.hInstance, "getpeername"); + winSock.getservbyname = (struct servent FAR * (PASCAL FAR *) + (const char FAR * name, const char FAR * proto)) + GetProcAddress(winSock.hInstance, "getservbyname"); + winSock.getsockname = (int (PASCAL FAR *)(SOCKET sock, + struct sockaddr FAR *name, int FAR *namelen)) + GetProcAddress(winSock.hInstance, "getsockname"); + winSock.WSAStartup = (int (PASCAL FAR *)(WORD wVersionRequired, + LPWSADATA lpWSAData)) GetProcAddress(winSock.hInstance, "WSAStartup"); + winSock.WSACleanup = (int (PASCAL FAR *)(void)) + GetProcAddress(winSock.hInstance, "WSACleanup"); + winSock.WSAGetLastError = (int (PASCAL FAR *)(void)) + GetProcAddress(winSock.hInstance, "WSAGetLastError"); + winSock.WSAAsyncSelect = (int (PASCAL FAR *)(SOCKET s, HWND hWnd, + u_int wMsg, long lEvent)) + GetProcAddress(winSock.hInstance, "WSAAsyncSelect"); + + /* + * Now check that all fields are properly initialized. If not, return + * zero to indicate that we failed to initialize properly. + */ + + if ((winSock.hInstance == NULL) || + (winSock.accept == NULL) || + (winSock.bind == NULL) || + (winSock.closesocket == NULL) || + (winSock.connect == NULL) || + (winSock.ioctlsocket == NULL) || + (winSock.getsockopt == NULL) || + (winSock.htons == NULL) || + (winSock.inet_addr == NULL) || + (winSock.inet_ntoa == NULL) || + (winSock.listen == NULL) || + (winSock.ntohs == NULL) || + (winSock.recv == NULL) || + (winSock.select == NULL) || + (winSock.send == NULL) || + (winSock.setsockopt == NULL) || + (winSock.socket == NULL) || + (winSock.gethostbyname == NULL) || + (winSock.gethostbyaddr == NULL) || + (winSock.gethostname == NULL) || + (winSock.getpeername == NULL) || + (winSock.getservbyname == NULL) || + (winSock.getsockname == NULL) || + (winSock.WSAStartup == NULL) || + (winSock.WSACleanup == NULL) || + (winSock.WSAGetLastError == NULL) || + (winSock.WSAAsyncSelect == NULL)) { + goto unloadLibrary; + } + + /* + * Create the async notification window with a new class. We + * must create a new class to avoid a Windows 95 bug that causes + * us to get the wrong message number for socket events if the + * message window is a subclass of a static control. + */ + + class.style = 0; + class.cbClsExtra = 0; + class.cbWndExtra = 0; + class.hInstance = TclWinGetTclInstance(); + class.hbrBackground = NULL; + class.lpszMenuName = NULL; + class.lpszClassName = "TclSocket"; + class.lpfnWndProc = SocketProc; + class.hIcon = NULL; + class.hCursor = NULL; + + if (!RegisterClassA(&class)) { + TclWinConvertError(GetLastError()); + (*winSock.WSACleanup)(); + goto unloadLibrary; + } + + /* + * Initialize the winsock library and check the version number. + */ + + if ((*winSock.WSAStartup)(WSA_VERSION_REQD, &wsaData) != 0) { + goto unloadLibrary; + } + if (wsaData.wVersion != WSA_VERSION_REQD) { + (*winSock.WSACleanup)(); + goto unloadLibrary; + } } - winSock.accept = (SOCKET (PASCAL FAR *)(SOCKET s, - struct sockaddr FAR *addr, int FAR *addrlen)) - GetProcAddress(winSock.hInstance, "accept"); - winSock.bind = (int (PASCAL FAR *)(SOCKET s, - const struct sockaddr FAR *addr, int namelen)) - GetProcAddress(winSock.hInstance, "bind"); - winSock.closesocket = (int (PASCAL FAR *)(SOCKET s)) - GetProcAddress(winSock.hInstance, "closesocket"); - winSock.connect = (int (PASCAL FAR *)(SOCKET s, - const struct sockaddr FAR *name, int namelen)) - GetProcAddress(winSock.hInstance, "connect"); - winSock.ioctlsocket = (int (PASCAL FAR *)(SOCKET s, long cmd, - u_long FAR *argp)) GetProcAddress(winSock.hInstance, "ioctlsocket"); - winSock.getsockopt = (int (PASCAL FAR *)(SOCKET s, - int level, int optname, char FAR * optval, int FAR *optlen)) - GetProcAddress(winSock.hInstance, "getsockopt"); - winSock.htons = (u_short (PASCAL FAR *)(u_short hostshort)) - GetProcAddress(winSock.hInstance, "htons"); - winSock.inet_addr = (unsigned long (PASCAL FAR *)(const char FAR *cp)) - GetProcAddress(winSock.hInstance, "inet_addr"); - winSock.inet_ntoa = (char FAR * (PASCAL FAR *)(struct in_addr in)) - GetProcAddress(winSock.hInstance, "inet_ntoa"); - winSock.listen = (int (PASCAL FAR *)(SOCKET s, int backlog)) - GetProcAddress(winSock.hInstance, "listen"); - winSock.ntohs = (u_short (PASCAL FAR *)(u_short netshort)) - GetProcAddress(winSock.hInstance, "ntohs"); - winSock.recv = (int (PASCAL FAR *)(SOCKET s, char FAR * buf, - int len, int flags)) GetProcAddress(winSock.hInstance, "recv"); - winSock.select = (int (PASCAL FAR *)(int nfds, fd_set FAR * readfds, - fd_set FAR * writefds, fd_set FAR * exceptfds, - const struct timeval FAR * tiemout)) - GetProcAddress(winSock.hInstance, "select"); - winSock.send = (int (PASCAL FAR *)(SOCKET s, const char FAR * buf, - int len, int flags)) GetProcAddress(winSock.hInstance, "send"); - winSock.setsockopt = (int (PASCAL FAR *)(SOCKET s, int level, - int optname, const char FAR * optval, int optlen)) - GetProcAddress(winSock.hInstance, "setsockopt"); - winSock.shutdown = (int (PASCAL FAR *)(SOCKET s, int how)) - GetProcAddress(winSock.hInstance, "shutdown"); - winSock.socket = (SOCKET (PASCAL FAR *)(int af, int type, - int protocol)) GetProcAddress(winSock.hInstance, "socket"); - winSock.gethostbyaddr = (struct hostent FAR * (PASCAL FAR *) - (const char FAR *addr, int addrlen, int addrtype)) - GetProcAddress(winSock.hInstance, "gethostbyaddr"); - winSock.gethostbyname = (struct hostent FAR * (PASCAL FAR *) - (const char FAR *name)) - GetProcAddress(winSock.hInstance, "gethostbyname"); - winSock.gethostname = (int (PASCAL FAR *)(char FAR * name, - int namelen)) GetProcAddress(winSock.hInstance, "gethostname"); - winSock.getpeername = (int (PASCAL FAR *)(SOCKET sock, - struct sockaddr FAR *name, int FAR *namelen)) - GetProcAddress(winSock.hInstance, "getpeername"); - winSock.getservbyname = (struct servent FAR * (PASCAL FAR *) - (const char FAR * name, const char FAR * proto)) - GetProcAddress(winSock.hInstance, "getservbyname"); - winSock.getsockname = (int (PASCAL FAR *)(SOCKET sock, - struct sockaddr FAR *name, int FAR *namelen)) - GetProcAddress(winSock.hInstance, "getsockname"); - winSock.WSAStartup = (int (PASCAL FAR *)(WORD wVersionRequired, - LPWSADATA lpWSAData)) GetProcAddress(winSock.hInstance, "WSAStartup"); - winSock.WSACleanup = (int (PASCAL FAR *)(void)) - GetProcAddress(winSock.hInstance, "WSACleanup"); - winSock.WSAGetLastError = (int (PASCAL FAR *)(void)) - GetProcAddress(winSock.hInstance, "WSAGetLastError"); - winSock.WSAAsyncSelect = (int (PASCAL FAR *)(SOCKET s, HWND hWnd, - u_int wMsg, long lEvent)) - GetProcAddress(winSock.hInstance, "WSAAsyncSelect"); - /* - * Now check that all fields are properly initialized. If not, return - * zero to indicate that we failed to initialize properly. + * Check for per-thread initialization. */ - if ((winSock.hInstance == NULL) || - (winSock.accept == NULL) || - (winSock.bind == NULL) || - (winSock.closesocket == NULL) || - (winSock.connect == NULL) || - (winSock.ioctlsocket == NULL) || - (winSock.getsockopt == NULL) || - (winSock.htons == NULL) || - (winSock.inet_addr == NULL) || - (winSock.inet_ntoa == NULL) || - (winSock.listen == NULL) || - (winSock.ntohs == NULL) || - (winSock.recv == NULL) || - (winSock.select == NULL) || - (winSock.send == NULL) || - (winSock.setsockopt == NULL) || - (winSock.socket == NULL) || - (winSock.gethostbyname == NULL) || - (winSock.gethostbyaddr == NULL) || - (winSock.gethostname == NULL) || - (winSock.getpeername == NULL) || - (winSock.getservbyname == NULL) || - (winSock.getsockname == NULL) || - (winSock.WSAStartup == NULL) || - (winSock.WSACleanup == NULL) || - (winSock.WSAGetLastError == NULL) || - (winSock.WSAAsyncSelect == NULL)) { - goto unloadLibrary; - } + if (tsdPtr == NULL) { + tsdPtr = TCL_TSD_INIT(&dataKey); + tsdPtr->socketList = NULL; - /* - * Initialize the winsock library and check the version number. - */ - - if ((*winSock.WSAStartup)(WSA_VERSION_REQD, &wsaData) != 0) { - goto unloadLibrary; - } - if (wsaData.wVersion != WSA_VERSION_REQD) { - (*winSock.WSACleanup)(); - goto unloadLibrary; - } - - /* - * Create the async notification window with a new class. We - * must create a new class to avoid a Windows 95 bug that causes - * us to get the wrong message number for socket events if the - * message window is a subclass of a static control. - */ + tsdPtr->hwnd = CreateWindowA("TclSocket", "TclSocket", + WS_TILED, 0, 0, 0, 0, NULL, NULL, class.hInstance, NULL); - class.style = 0; - class.cbClsExtra = 0; - class.cbWndExtra = 0; - class.hInstance = TclWinGetTclInstance(); - class.hbrBackground = NULL; - class.lpszMenuName = NULL; - class.lpszClassName = "TclSocket"; - class.lpfnWndProc = SocketProc; - class.hIcon = NULL; - class.hCursor = NULL; - - if (RegisterClass(&class)) { - winSock.hwnd = CreateWindow("TclSocket", "TclSocket", WS_TILED, 0, 0, - 0, 0, NULL, NULL, class.hInstance, NULL); - } else { - winSock.hwnd = NULL; - } - if (winSock.hwnd == NULL) { - TclWinConvertError(GetLastError()); - (*winSock.WSACleanup)(); - goto unloadLibrary; + if (tsdPtr->hwnd == NULL) { + goto unloadLibrary; + } + + Tcl_CreateEventSource(SocketSetupProc, SocketCheckProc, NULL); + Tcl_CreateThreadExitHandler(SocketThreadExitHandler, NULL); } - Tcl_CreateEventSource(SocketSetupProc, SocketCheckProc, NULL); return; unloadLibrary: @@ -428,6 +453,34 @@ unloadLibrary: /* *---------------------------------------------------------------------- * + * SocketsEnabled -- + * + * Check that the WinSock DLL is loaded and ready. + * + * Results: + * 1 if it is. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +static int +SocketsEnabled() +{ + int enabled; + Tcl_MutexLock(&socketMutex); + enabled = (winSock.hInstance != NULL); + Tcl_MutexUnlock(&socketMutex); + return enabled; +} + + +/* + *---------------------------------------------------------------------- + * * SocketExitHandler -- * * Callback invoked during exit clean up to delete the socket @@ -447,22 +500,52 @@ static void SocketExitHandler(clientData) ClientData clientData; /* Not used. */ { + Tcl_MutexLock(&socketMutex); if (winSock.hInstance) { - DestroyWindow(winSock.hwnd); - UnregisterClass("TclSocket", TclWinGetTclInstance()); + UnregisterClassA("TclSocket", TclWinGetTclInstance()); (*winSock.WSACleanup)(); FreeLibrary(winSock.hInstance); winSock.hInstance = NULL; } - Tcl_DeleteEventSource(SocketSetupProc, SocketCheckProc, NULL); initialized = 0; hostnameInitialized = 0; + Tcl_MutexUnlock(&socketMutex); +} + +/* + *---------------------------------------------------------------------- + * + * SocketThreadExitHandler -- + * + * Callback invoked during thread clean up to delete the socket + * event source. + * + * Results: + * None. + * + * Side effects: + * Delete the event source. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +static void +SocketThreadExitHandler(clientData) + ClientData clientData; /* Not used. */ +{ + ThreadSpecificData *tsdPtr = + (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); + + DestroyWindow(tsdPtr->hwnd); + + Tcl_DeleteEventSource(SocketSetupProc, SocketCheckProc, NULL); } /* *---------------------------------------------------------------------- * - * TclHasSockets -- + * TclpHasSockets -- * * This function determines whether sockets are available on the * current system and returns an error in interp if they are not. @@ -479,14 +562,14 @@ SocketExitHandler(clientData) */ int -TclHasSockets(interp) +TclpHasSockets(interp) Tcl_Interp *interp; { - if (!initialized) { - InitSockets(); - } - - if (winSock.hInstance != NULL) { + Tcl_MutexLock(&socketMutex); + InitSockets(); + Tcl_MutexUnlock(&socketMutex); + + if (SocketsEnabled()) { return TCL_OK; } if (interp != NULL) { @@ -520,6 +603,7 @@ SocketSetupProc(data, flags) { SocketInfo *infoPtr; Tcl_Time blockTime = { 0, 0 }; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!(flags & TCL_FILE_EVENTS)) { return; @@ -529,7 +613,8 @@ SocketSetupProc(data, flags) * Check to see if there is a ready socket. If so, poll. */ - for (infoPtr = socketList; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { + for (infoPtr = tsdPtr->socketList; infoPtr != NULL; + infoPtr = infoPtr->nextPtr) { if (infoPtr->readyEvents & infoPtr->watchEvents) { Tcl_SetMaxBlockTime(&blockTime); break; @@ -561,6 +646,7 @@ SocketCheckProc(data, flags) { SocketInfo *infoPtr; SocketEvent *evPtr; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!(flags & TCL_FILE_EVENTS)) { return; @@ -572,7 +658,8 @@ SocketCheckProc(data, flags) * events). */ - for (infoPtr = socketList; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { + for (infoPtr = tsdPtr->socketList; infoPtr != NULL; + infoPtr = infoPtr->nextPtr) { if ((infoPtr->readyEvents & infoPtr->watchEvents) && !(infoPtr->flags & SOCKET_PENDING)) { infoPtr->flags |= SOCKET_PENDING; @@ -615,6 +702,7 @@ SocketEventProc(evPtr, flags) SocketEvent *eventPtr = (SocketEvent *) evPtr; int mask = 0; int events; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!(flags & TCL_FILE_EVENTS)) { return 0; @@ -624,7 +712,8 @@ SocketEventProc(evPtr, flags) * Find the specified socket on the socket list. */ - for (infoPtr = socketList; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { + for (infoPtr = tsdPtr->socketList; infoPtr != NULL; + infoPtr = infoPtr->nextPtr) { if (infoPtr->socket == eventPtr->socket) { break; } @@ -678,26 +767,25 @@ SocketEventProc(evPtr, flags) /* * 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 + * 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. */ - (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, winSock.hwnd, 0, 0); + (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, tsdPtr->hwnd, 0, 0); FD_ZERO(&readFds); FD_SET(infoPtr->socket, &readFds); timeout.tv_usec = 0; timeout.tv_sec = 0; - + if ((*winSock.select)(0, &readFds, NULL, NULL, &timeout) != 0) { mask |= TCL_READABLE; } else { - (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, winSock.hwnd, + (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, tsdPtr->hwnd, SOCKET_MESSAGE, infoPtr->selectEvents); infoPtr->readyEvents &= ~(FD_READ); } - } if (events & (FD_WRITE | FD_CONNECT)) { mask |= TCL_WRITABLE; @@ -768,6 +856,7 @@ TcpCloseProc(instanceData, interp) SocketInfo *infoPtr = (SocketInfo *) instanceData; SocketInfo **nextPtrPtr; int errorCode = 0; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); /* * Check that WinSock is initialized; do not call it if not, to @@ -776,7 +865,7 @@ TcpCloseProc(instanceData, interp) * use sockets. */ - if (winSock.hInstance != NULL) { + if (SocketsEnabled()) { /* * Clean up the OS socket handle. The default Windows setting @@ -794,13 +883,14 @@ TcpCloseProc(instanceData, interp) * Remove the socket from socketList. */ - for (nextPtrPtr = &socketList; (*nextPtrPtr) != NULL; + for (nextPtrPtr = &(tsdPtr->socketList); (*nextPtrPtr) != NULL; nextPtrPtr = &((*nextPtrPtr)->nextPtr)) { if ((*nextPtrPtr) == infoPtr) { (*nextPtrPtr) = infoPtr->nextPtr; break; } } + ckfree((char *) infoPtr); return errorCode; } @@ -827,6 +917,7 @@ NewSocketInfo(socket) SOCKET socket; { SocketInfo *infoPtr; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); infoPtr = (SocketInfo *) ckalloc((unsigned) sizeof(SocketInfo)); infoPtr->socket = socket; @@ -836,8 +927,10 @@ NewSocketInfo(socket) infoPtr->selectEvents = 0; infoPtr->acceptProc = NULL; infoPtr->lastError = 0; - infoPtr->nextPtr = socketList; - socketList = infoPtr; + + infoPtr->nextPtr = tsdPtr->socketList; + tsdPtr->socketList = infoPtr; + return infoPtr; } @@ -877,6 +970,8 @@ CreateSocket(interp, port, host, server, myaddr, myport, async) struct sockaddr_in mysockaddr; /* Socket address for client */ SOCKET sock; SocketInfo *infoPtr; /* The returned value. */ + ThreadSpecificData *tsdPtr = + (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); /* * Check that WinSock is initialized; do not call it if not, to @@ -884,11 +979,11 @@ CreateSocket(interp, port, host, server, myaddr, myport, async) * handler for WinSock ran before other exit handlers that want to * use sockets. */ - - if (winSock.hInstance == NULL) { + + if (!SocketsEnabled()) { return NULL; } - + if (! CreateSocketAddress(&sockaddr, host, port)) { goto error; } @@ -1020,7 +1115,7 @@ CreateSocket(interp, port, host, server, myaddr, myport, async) */ (*winSock.ioctlsocket)(sock, FIONBIO, &flag); - (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, winSock.hwnd, + (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, tsdPtr->hwnd, SOCKET_MESSAGE, infoPtr->selectEvents); return infoPtr; @@ -1070,11 +1165,11 @@ CreateSocketAddress(sockaddrPtr, host, port) * use sockets. */ - if (winSock.hInstance == NULL) { + if (!SocketsEnabled()) { Tcl_SetErrno(EFAULT); return 0; } - + (void) memset((char *) sockaddrPtr, '\0', sizeof(struct sockaddr_in)); sockaddrPtr->sin_family = AF_INET; sockaddrPtr->sin_port = (*winSock.htons)((short) (port & 0xFFFF)); @@ -1138,6 +1233,8 @@ WaitForSocketEvent(infoPtr, events, errorCodePtr) MSG msg; int result = 1; int oldMode; + ThreadSpecificData *tsdPtr = + (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); /* * Be sure to disable event servicing so we are truly modal. @@ -1149,8 +1246,8 @@ WaitForSocketEvent(infoPtr, events, errorCodePtr) * Reset WSAAsyncSelect so we have a fresh set of events pending. */ - (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, winSock.hwnd, 0, 0); - (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, winSock.hwnd, + (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, tsdPtr->hwnd, 0, 0); + (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, tsdPtr->hwnd, SOCKET_MESSAGE, infoPtr->selectEvents); while (1) { @@ -1158,7 +1255,7 @@ WaitForSocketEvent(infoPtr, events, errorCodePtr) * Process all outstanding messages on the socket window. */ - while (PeekMessage(&msg, winSock.hwnd, 0, 0, PM_REMOVE)) { + while (PeekMessage(&msg, tsdPtr->hwnd, 0, 0, PM_REMOVE)) { DispatchMessage(&msg); } @@ -1181,6 +1278,7 @@ WaitForSocketEvent(infoPtr, events, errorCodePtr) WaitMessage(); } + (void) Tcl_SetServiceMode(oldMode); return result; } @@ -1213,9 +1311,9 @@ Tcl_OpenTcpClient(interp, port, host, myaddr, myport, async) * client socket asynchronously. */ { SocketInfo *infoPtr; - char channelName[20]; + char channelName[16 + TCL_INTEGER_SPACE]; - if (TclHasSockets(interp) != TCL_OK) { + if (TclpHasSockets(interp) != TCL_OK) { return NULL; } @@ -1228,7 +1326,7 @@ Tcl_OpenTcpClient(interp, port, host, myaddr, myport, async) return NULL; } - sprintf(channelName, "sock%d", infoPtr->socket); + wsprintfA(channelName, "sock%d", infoPtr->socket); infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, (ClientData) infoPtr, (TCL_READABLE | TCL_WRITABLE)); @@ -1268,9 +1366,11 @@ Tcl_MakeTcpClientChannel(sock) ClientData sock; /* The socket to wrap up into a channel. */ { SocketInfo *infoPtr; - char channelName[20]; + char channelName[16 + TCL_INTEGER_SPACE]; + ThreadSpecificData *tsdPtr = + (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); - if (TclHasSockets(NULL) != TCL_OK) { + if (TclpHasSockets(NULL) != TCL_OK) { return NULL; } @@ -1287,10 +1387,10 @@ Tcl_MakeTcpClientChannel(sock) */ infoPtr->selectEvents = FD_READ | FD_CLOSE | FD_WRITE; - (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, winSock.hwnd, + (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, tsdPtr->hwnd, SOCKET_MESSAGE, infoPtr->selectEvents); - sprintf(channelName, "sock%d", infoPtr->socket); + wsprintfA(channelName, "sock%d", infoPtr->socket); infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, (ClientData) infoPtr, (TCL_READABLE | TCL_WRITABLE)); Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto crlf"); @@ -1325,9 +1425,9 @@ Tcl_OpenTcpServer(interp, port, host, acceptProc, acceptProcData) ClientData acceptProcData; /* Data for the callback. */ { SocketInfo *infoPtr; - char channelName[20]; + char channelName[16 + TCL_INTEGER_SPACE]; - if (TclHasSockets(interp) != TCL_OK) { + if (TclpHasSockets(interp) != TCL_OK) { return NULL; } @@ -1343,7 +1443,7 @@ Tcl_OpenTcpServer(interp, port, host, acceptProc, acceptProcData) infoPtr->acceptProc = acceptProc; infoPtr->acceptProcData = acceptProcData; - sprintf(channelName, "sock%d", infoPtr->socket); + wsprintfA(channelName, "sock%d", infoPtr->socket); infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, (ClientData) infoPtr, 0); @@ -1381,7 +1481,9 @@ TcpAccept(infoPtr) SocketInfo *newInfoPtr; struct sockaddr_in addr; int len; - char channelName[20]; + char channelName[16 + TCL_INTEGER_SPACE]; + ThreadSpecificData *tsdPtr = + (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); /* * Accept the incoming connection request. @@ -1421,10 +1523,10 @@ TcpAccept(infoPtr) */ newInfoPtr->selectEvents = (FD_READ | FD_WRITE | FD_CLOSE); - (void) (*winSock.WSAAsyncSelect)(newInfoPtr->socket, winSock.hwnd, + (void) (*winSock.WSAAsyncSelect)(newInfoPtr->socket, tsdPtr->hwnd, SOCKET_MESSAGE, newInfoPtr->selectEvents); - sprintf(channelName, "sock%d", newInfoPtr->socket); + wsprintfA(channelName, "sock%d", newInfoPtr->socket); newInfoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, (ClientData) newInfoPtr, (TCL_READABLE | TCL_WRITABLE)); if (Tcl_SetChannelOption(NULL, newInfoPtr->channel, "-translation", @@ -1476,6 +1578,8 @@ TcpInputProc(instanceData, buf, toRead, errorCodePtr) SocketInfo *infoPtr = (SocketInfo *) instanceData; int bytesRead; int error; + ThreadSpecificData *tsdPtr = + (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); *errorCodePtr = 0; @@ -1486,7 +1590,7 @@ TcpInputProc(instanceData, buf, toRead, errorCodePtr) * use sockets. */ - if (winSock.hInstance == NULL) { + if (!SocketsEnabled()) { *errorCodePtr = EFAULT; return -1; } @@ -1518,37 +1622,37 @@ TcpInputProc(instanceData, buf, toRead, errorCodePtr) */ while (1) { - (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, winSock.hwnd, + (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, tsdPtr->hwnd, 0, 0); bytesRead = (*winSock.recv)(infoPtr->socket, buf, toRead, 0); infoPtr->readyEvents &= ~(FD_READ); - + /* * Check for end-of-file condition or successful read. */ - + if (bytesRead == 0) { infoPtr->flags |= SOCKET_EOF; } if (bytesRead != SOCKET_ERROR) { break; } - + /* * If an error occurs after the FD_CLOSE has arrived, * then ignore the error and report an EOF. */ - + if (infoPtr->readyEvents & FD_CLOSE) { infoPtr->flags |= SOCKET_EOF; bytesRead = 0; break; } - + /* * Check for error condition or underflow in non-blocking case. */ - + error = (*winSock.WSAGetLastError)(); if ((infoPtr->flags & SOCKET_ASYNC) || (error != WSAEWOULDBLOCK)) { TclWinConvertWSAError(error); @@ -1565,11 +1669,11 @@ TcpInputProc(instanceData, buf, toRead, errorCodePtr) if (!WaitForSocketEvent(infoPtr, FD_READ|FD_CLOSE, errorCodePtr)) { bytesRead = -1; break; - } + } } - (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, winSock.hwnd, - SOCKET_MESSAGE, infoPtr->selectEvents); + (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, tsdPtr->hwnd, + SOCKET_MESSAGE, infoPtr->selectEvents); return bytesRead; } @@ -1600,6 +1704,8 @@ TcpOutputProc(instanceData, buf, toWrite, errorCodePtr) SocketInfo *infoPtr = (SocketInfo *) instanceData; int bytesWritten; int error; + ThreadSpecificData *tsdPtr = + (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); *errorCodePtr = 0; @@ -1610,11 +1716,11 @@ TcpOutputProc(instanceData, buf, toWrite, errorCodePtr) * use sockets. */ - if (winSock.hInstance == NULL) { + if (! SocketsEnabled()) { *errorCodePtr = EFAULT; return -1; } - + /* * Check to see if the socket is connected before trying to write. */ @@ -1625,7 +1731,7 @@ TcpOutputProc(instanceData, buf, toWrite, errorCodePtr) } while (1) { - (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, winSock.hwnd, + (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, tsdPtr->hwnd, 0, 0); bytesWritten = (*winSock.send)(infoPtr->socket, buf, toWrite, 0); if (bytesWritten != SOCKET_ERROR) { @@ -1675,7 +1781,7 @@ TcpOutputProc(instanceData, buf, toWrite, errorCodePtr) } } - (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, winSock.hwnd, + (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, tsdPtr->hwnd, SOCKET_MESSAGE, infoPtr->selectEvents); return bytesWritten; } @@ -1719,7 +1825,7 @@ TcpGetOptionProc(instanceData, interp, optionName, dsPtr) SOCKET sock; int size = sizeof(struct sockaddr_in); size_t len = 0; - char buf[128]; + char buf[TCL_INTEGER_SPACE]; /* * Check that WinSock is initialized; do not call it if not, to @@ -1728,7 +1834,7 @@ TcpGetOptionProc(instanceData, interp, optionName, dsPtr) * use sockets. */ - if (winSock.hInstance == NULL) { + if (!SocketsEnabled()) { if (interp) { Tcl_AppendResult(interp, "winsock is not initialized", NULL); } @@ -1742,21 +1848,21 @@ TcpGetOptionProc(instanceData, interp, optionName, dsPtr) } if ((len > 1) && (optionName[1] == 'e') && - (strncmp(optionName, "-error", len) == 0)) { - int optlen; - int err, ret; + (strncmp(optionName, "-error", len) == 0)) { + int optlen; + int err, ret; - optlen = sizeof(int); - ret = TclWinGetSockOpt(sock, SOL_SOCKET, SO_ERROR, - (char *)&err, &optlen); - if (ret == SOCKET_ERROR) { - err = (*winSock.WSAGetLastError)(); - } - if (err) { - TclWinConvertWSAError(err); - Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(Tcl_GetErrno()), -1); - } - return TCL_OK; + optlen = sizeof(int); + ret = TclWinGetSockOpt(sock, SOL_SOCKET, SO_ERROR, + (char *)&err, &optlen); + if (ret == SOCKET_ERROR) { + err = (*winSock.WSAGetLastError)(); + } + if (err) { + TclWinConvertWSAError(err); + Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(Tcl_GetErrno()), -1); + } + return TCL_OK; } if ((len == 0) || @@ -1779,7 +1885,7 @@ TcpGetOptionProc(instanceData, interp, optionName, dsPtr) Tcl_DStringAppendElement(dsPtr, (*winSock.inet_ntoa)(peername.sin_addr)); } - sprintf(buf, "%d", (*winSock.ntohs)(peername.sin_port)); + TclFormatInt(buf, (*winSock.ntohs)(peername.sin_port)); Tcl_DStringAppendElement(dsPtr, buf); if (len == 0) { Tcl_DStringEndSublist(dsPtr); @@ -1825,7 +1931,7 @@ TcpGetOptionProc(instanceData, interp, optionName, dsPtr) Tcl_DStringAppendElement(dsPtr, (*winSock.inet_ntoa)(sockname.sin_addr)); } - sprintf(buf, "%d", (*winSock.ntohs)(sockname.sin_port)); + TclFormatInt(buf, (*winSock.ntohs)(sockname.sin_port)); Tcl_DStringAppendElement(dsPtr, buf); if (len == 0) { Tcl_DStringEndSublist(dsPtr); @@ -1886,7 +1992,7 @@ TcpWatchProc(instanceData, mask) infoPtr->watchEvents |= (FD_READ|FD_CLOSE|FD_ACCEPT); } if (mask & TCL_WRITABLE) { - infoPtr->watchEvents |= (FD_WRITE|FD_CONNECT); + infoPtr->watchEvents |= (FD_WRITE|FD_CONNECT); } /* @@ -1905,7 +2011,7 @@ TcpWatchProc(instanceData, mask) * * TcpGetProc -- * - * Called from Tcl_GetChannelFile to retrieve an OS handle from inside + * Called from Tcl_GetChannelHandle to retrieve an OS handle from inside * a TCP socket based channel. * * Results: @@ -1958,6 +2064,7 @@ SocketProc(hwnd, message, wParam, lParam) int event, error; SOCKET socket; SocketInfo *infoPtr; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (message != SOCKET_MESSAGE) { return DefWindowProc(hwnd, message, wParam, lParam); @@ -1972,7 +2079,8 @@ SocketProc(hwnd, message, wParam, lParam) * eventState flag. */ - for (infoPtr = socketList; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { + for (infoPtr = tsdPtr->socketList; infoPtr != NULL; + infoPtr = infoPtr->nextPtr) { if (infoPtr->socket == socket) { /* * Update the socket state. @@ -2000,7 +2108,7 @@ SocketProc(hwnd, message, wParam, lParam) } } - if (infoPtr->flags & SOCKET_ASYNC_CONNECT) { + if(infoPtr->flags & SOCKET_ASYNC_CONNECT) { infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT); if (error != ERROR_SUCCESS) { TclWinConvertWSAError(error); @@ -2044,29 +2152,42 @@ char * Tcl_GetHostName() { DWORD length; - char *p; + WCHAR wbuf[MAX_COMPUTERNAME_LENGTH + 1]; + Tcl_MutexLock(&socketMutex); if (hostnameInitialized) { + Tcl_MutexUnlock(&socketMutex); return hostname; } - if (TclHasSockets(NULL) == TCL_OK) { + if (TclpHasSockets(NULL) == TCL_OK) { + /* + * INTL: bug + */ + if ((*winSock.gethostname)(hostname, sizeof(hostname)) == 0) { hostnameInitialized = 1; + Tcl_MutexUnlock(&socketMutex); return hostname; } } length = sizeof(hostname); - if (GetComputerName(hostname, &length) != 0) { - for (p = hostname; *p != '\0'; p++) { - if (isupper(*((unsigned char *) p))) { - *p = (char) tolower(*((unsigned char *) p)); - } - } + if ((*tclWinProcs->getComputerNameProc)(wbuf, &length) != 0) { + /* + * Convert string from native to UTF then change to lowercase. + */ + + Tcl_DString ds; + + lstrcpynA(hostname, Tcl_WinTCharToUtf((TCHAR *) wbuf, -1, &ds), + sizeof(hostname)); + Tcl_DStringFree(&ds); + Tcl_UtfToLower(hostname); } else { hostname[0] = '\0'; } hostnameInitialized = 1; + Tcl_MutexUnlock(&socketMutex); return hostname; } @@ -2090,7 +2211,7 @@ Tcl_GetHostName() */ int -TclWinGetSockOpt(SOCKET s, int level, int optname, char FAR * optval, +TclWinGetSockOpt(SOCKET s, int level, int optname, char * optval, int FAR *optlen) { /* @@ -2100,7 +2221,7 @@ TclWinGetSockOpt(SOCKET s, int level, int optname, char FAR * optval, * use sockets. */ - if (winSock.hInstance == NULL) { + if (!SocketsEnabled()) { return SOCKET_ERROR; } @@ -2108,7 +2229,7 @@ TclWinGetSockOpt(SOCKET s, int level, int optname, char FAR * optval, } int -TclWinSetSockOpt(SOCKET s, int level, int optname, const char FAR * optval, +TclWinSetSockOpt(SOCKET s, int level, int optname, const char * optval, int optlen) { /* @@ -2117,8 +2238,7 @@ TclWinSetSockOpt(SOCKET s, int level, int optname, const char FAR * optval, * handler for WinSock ran before other exit handlers that want to * use sockets. */ - - if (winSock.hInstance == NULL) { + if (!SocketsEnabled()) { return SOCKET_ERROR; } @@ -2135,7 +2255,7 @@ TclWinNToHS(u_short netshort) * use sockets. */ - if (winSock.hInstance == NULL) { + if (!SocketsEnabled()) { return (u_short) -1; } @@ -2151,8 +2271,7 @@ TclWinGetServByName(const char * name, const char * proto) * handler for WinSock ran before other exit handlers that want to * use sockets. */ - - if (winSock.hInstance == NULL) { + if (!SocketsEnabled()) { return (struct servent *) NULL; } |