diff options
-rw-r--r-- | win/tclWinSock.c | 226 |
1 files changed, 120 insertions, 106 deletions
diff --git a/win/tclWinSock.c b/win/tclWinSock.c index 717b42a..9b609a2 100644 --- a/win/tclWinSock.c +++ b/win/tclWinSock.c @@ -8,12 +8,19 @@ * 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.55 2006/07/24 13:43:14 dgp Exp $ + * RCS: @(#) $Id: tclWinSock.c,v 1.56 2007/01/02 18:43:51 dkf Exp $ */ #include "tclWinInt.h" /* + * Support for control over sockets' KEEPALIVE and NODELAY behavior is + * currently disabled. + */ + +#undef TCL_FEATURE_KEEPALIVE_NAGLE + +/* * Make sure to remove the redirection defines set in tclWinPort.h that is in * use in other sections of the core, except for us. */ @@ -35,67 +42,61 @@ TCL_DECLARE_MUTEX(socketMutex) * The following variable holds the network name of this host. */ -static TclInitProcessGlobalValueProc InitializeHostName; -static ProcessGlobalValue hostName = - {0, 0, NULL, NULL, InitializeHostName, NULL, NULL}; +static TclInitProcessGlobalValueProc InitializeHostName; +static ProcessGlobalValue hostName = { + 0, 0, NULL, NULL, InitializeHostName, NULL, NULL +}; /* * Mingw, Cygwin and OpenWatcom may not have LPFN_* typedefs. */ #ifdef HAVE_NO_LPFN_DECLS - typedef SOCKET (PASCAL FAR *LPFN_ACCEPT)(SOCKET s, - struct sockaddr FAR * addr, int FAR * addrlen); - typedef int (PASCAL FAR *LPFN_BIND)(SOCKET s, - const struct sockaddr FAR *addr, int namelen); - typedef int (PASCAL FAR *LPFN_CLOSESOCKET)(SOCKET s); - typedef int (PASCAL FAR *LPFN_CONNECT)(SOCKET s, +typedef SOCKET (PASCAL FAR *LPFN_ACCEPT)(SOCKET s, struct sockaddr FAR *addr, + int FAR *addrlen); +typedef int (PASCAL FAR *LPFN_BIND)(SOCKET s, const struct sockaddr FAR *addr, + int namelen); +typedef int (PASCAL FAR *LPFN_CLOSESOCKET)(SOCKET s); +typedef int (PASCAL FAR *LPFN_CONNECT)(SOCKET s, const struct sockaddr FAR *name, int namelen); - typedef struct hostent FAR * (PASCAL FAR *LPFN_GETHOSTBYADDR) +typedef struct hostent FAR *(PASCAL FAR *LPFN_GETHOSTBYADDR) (const char FAR *addr, int addrlen, int addrtype); - typedef struct hostent FAR * (PASCAL FAR *LPFN_GETHOSTBYNAME) - (const char FAR * name); - typedef int (PASCAL FAR *LPFN_GETHOSTNAME)(char FAR * name, - int namelen); - typedef int (PASCAL FAR *LPFN_GETPEERNAME)(SOCKET sock, +typedef struct hostent FAR *(PASCAL FAR *LPFN_GETHOSTBYNAME) + (const char FAR *name); +typedef int (PASCAL FAR *LPFN_GETHOSTNAME)(char FAR *name, int namelen); +typedef int (PASCAL FAR *LPFN_GETPEERNAME)(SOCKET sock, struct sockaddr FAR *name, int FAR *namelen); - typedef struct servent FAR * (PASCAL FAR *LPFN_GETSERVBYNAME) - (const char FAR * name, const char FAR * proto); - typedef int (PASCAL FAR *LPFN_GETSOCKNAME)(SOCKET sock, +typedef struct servent FAR *(PASCAL FAR *LPFN_GETSERVBYNAME) + (const char FAR *name, const char FAR *proto); +typedef int (PASCAL FAR *LPFN_GETSOCKNAME)(SOCKET sock, struct sockaddr FAR *name, int FAR *namelen); - typedef int (PASCAL FAR *LPFN_GETSOCKOPT)(SOCKET s, int level, - int optname, char FAR * optval, int FAR *optlen); - typedef u_short (PASCAL FAR *LPFN_HTONS)(u_short hostshort); - typedef unsigned long (PASCAL FAR *LPFN_INET_ADDR) - (const char FAR * cp); - typedef char FAR * (PASCAL FAR *LPFN_INET_NTOA) - (struct in_addr in); - typedef int (PASCAL FAR *LPFN_IOCTLSOCKET)(SOCKET s, - long cmd, u_long FAR *argp); - typedef int (PASCAL FAR *LPFN_LISTEN)(SOCKET s, int backlog); - typedef u_short (PASCAL FAR *LPFN_NTOHS)(u_short netshort); - typedef int (PASCAL FAR *LPFN_RECV)(SOCKET s, char FAR * buf, - int len, int flags); - typedef int (PASCAL FAR *LPFN_SELECT)(int nfds, - fd_set FAR * readfds, fd_set FAR * writefds, - fd_set FAR * exceptfds, - const struct timeval FAR * timeout); - typedef int (PASCAL FAR *LPFN_SEND)(SOCKET s, - const char FAR * buf, int len, int flags); - typedef int (PASCAL FAR *LPFN_SETSOCKOPT)(SOCKET s, - int level, int optname, const char FAR * optval, - int optlen); - typedef SOCKET (PASCAL FAR *LPFN_SOCKET)(int af, - int type, int protocol); - typedef int (PASCAL FAR *LPFN_WSAASYNCSELECT)(SOCKET s, - HWND hWnd, u_int wMsg, long lEvent); - typedef int (PASCAL FAR *LPFN_WSACLEANUP)(void); - typedef int (PASCAL FAR *LPFN_WSAGETLASTERROR)(void); - typedef int (PASCAL FAR *LPFN_WSASTARTUP)(WORD wVersionRequired, +typedef int (PASCAL FAR *LPFN_GETSOCKOPT)(SOCKET s, int level, int optname, + char FAR *optval, int FAR *optlen); +typedef u_short (PASCAL FAR *LPFN_HTONS)(u_short hostshort); +typedef unsigned long (PASCAL FAR *LPFN_INET_ADDR)(const char FAR *cp); +typedef char FAR *(PASCAL FAR *LPFN_INET_NTOA)(struct in_addr in); +typedef int (PASCAL FAR *LPFN_IOCTLSOCKET)(SOCKET s, long cmd, + u_long FAR *argp); +typedef int (PASCAL FAR *LPFN_LISTEN)(SOCKET s, int backlog); +typedef u_short (PASCAL FAR *LPFN_NTOHS)(u_short netshort); +typedef int (PASCAL FAR *LPFN_RECV)(SOCKET s, char FAR *buf, int len, + int flags); +typedef int (PASCAL FAR *LPFN_SELECT)(int nfds, fd_set FAR *readfds, + fd_set FAR *writefds, fd_set FAR *exceptfds, + const struct timeval FAR *timeout); +typedef int (PASCAL FAR *LPFN_SEND)(SOCKET s, + const char FAR *buf, int len, int flags); +typedef int (PASCAL FAR *LPFN_SETSOCKOPT)(SOCKET s, int level, int optname, + const char FAR *optval, int optlen); +typedef SOCKET (PASCAL FAR *LPFN_SOCKET)(int af, int type, int protocol); +typedef int (PASCAL FAR *LPFN_WSAASYNCSELECT)(SOCKET s, HWND hWnd, u_int wMsg, + long lEvent); +typedef int (PASCAL FAR *LPFN_WSACLEANUP)(void); +typedef int (PASCAL FAR *LPFN_WSAGETLASTERROR)(void); +typedef int (PASCAL FAR *LPFN_WSASTARTUP)(WORD wVersionRequired, LPWSADATA lpWSAData); #endif - /* * The following structure contains pointers to all of the WinSock API entry * points used by Tcl. It is initialized by InitSockets. Since we dynamically @@ -105,7 +106,6 @@ static ProcessGlobalValue hostName = static struct { HMODULE hModule; /* Handle to WinSock library. */ - /* Winsock 1.1 functions */ LPFN_ACCEPT accept; LPFN_BIND bind; @@ -280,7 +280,7 @@ static Tcl_ChannelType tcpChannelType = { NULL, /* handler proc. */ NULL, /* wide seek proc */ TcpThreadActionProc, /* thread action proc */ - NULL, /* truncate */ + NULL, /* truncate */ }; /* @@ -447,7 +447,8 @@ InitSockets(void) #define WSA_VERSION_MINOR 1 #define WSA_VERSION_REQD MAKEWORD(WSA_VERSION_MAJOR, WSA_VERSION_MINOR) - if ((err = winSock.WSAStartup((WORD)WSA_VERSION_REQD, &wsaData)) != 0) { + err = winSock.WSAStartup((WORD)WSA_VERSION_REQD, &wsaData); + if (err != 0) { TclWinConvertWSAError(err); goto unloadLibrary; } @@ -487,8 +488,8 @@ InitSockets(void) if (tsdPtr->socketListLock == NULL) { goto unloadLibrary; } - tsdPtr->socketThread = CreateThread(NULL, 256, SocketThread, - tsdPtr, 0, &id); + tsdPtr->socketThread = CreateThread(NULL, 256, SocketThread, tsdPtr, + 0, &id); if (tsdPtr->socketThread == NULL) { goto unloadLibrary; } @@ -496,8 +497,8 @@ InitSockets(void) SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST); /* - * Wait for the thread to signal when the window has - * been created and if it is ready to go. + * Wait for the thread to signal when the window has been created and + * if it is ready to go. */ WaitForSingleObject(tsdPtr->readyEvent, INFINITE); @@ -590,10 +591,10 @@ SocketExitHandler( * * TclpFinalizeSockets -- * - * This function is called from Tcl_FinalizeThread to finalize - * the platform specific socket subsystem. - * Also, it may be called from within this module to cleanup - * the state if unable to initialize the sockets subsystem. + * This function is called from Tcl_FinalizeThread to finalize the + * platform specific socket subsystem. Also, it may be called from within + * this module to cleanup the state if unable to initialize the sockets + * subsystem. * * Results: * None. @@ -605,19 +606,21 @@ SocketExitHandler( */ void -TclpFinalizeSockets() +TclpFinalizeSockets(void) { ThreadSpecificData *tsdPtr; - tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); + 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); tsdPtr->hwnd = NULL; } @@ -659,7 +662,9 @@ TclpFinalizeSockets() int TclpHasSockets( - Tcl_Interp *interp) + Tcl_Interp *interp) /* Where to write an error message if sockets + * are not present, or NULL if no such message + * is to be written. */ { Tcl_MutexLock(&socketMutex); InitSockets(); @@ -1350,11 +1355,11 @@ WaitForSocketEvent( * Reset WSAAsyncSelect so we have a fresh set of events pending. */ - SendMessage(tsdPtr->hwnd, SOCKET_SELECT, - (WPARAM) UNSELECT, (LPARAM) infoPtr); + SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) UNSELECT, + (LPARAM) infoPtr); - SendMessage(tsdPtr->hwnd, SOCKET_SELECT, - (WPARAM) SELECT, (LPARAM) infoPtr); + SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, + (LPARAM) infoPtr); while (1) { if (infoPtr->lastError) { @@ -1593,9 +1598,9 @@ TcpAccept( &len); /* - * Clear the ready mask so we can detect the next connection request. - * Note that connection requests are level triggered, so if there is a - * request already pending, a new event will be generated. + * Clear the ready mask so we can detect the next connection request. Note + * that connection requests are level triggered, so if there is a request + * already pending, a new event will be generated. */ if (newSocket == INVALID_SOCKET) { @@ -1689,8 +1694,8 @@ TcpInputProc( SocketInfo *infoPtr = (SocketInfo *) instanceData; int bytesRead; DWORD error; - ThreadSpecificData *tsdPtr = - (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + TclThreadDataKeyGet(&dataKey); *errorCodePtr = 0; @@ -1719,7 +1724,7 @@ TcpInputProc( */ if ((infoPtr->flags & SOCKET_ASYNC_CONNECT) - && ! WaitForSocketEvent(infoPtr, FD_CONNECT, errorCodePtr)) { + && !WaitForSocketEvent(infoPtr, FD_CONNECT, errorCodePtr)) { return -1; } @@ -1815,8 +1820,8 @@ TcpOutputProc( SocketInfo *infoPtr = (SocketInfo *) instanceData; int bytesWritten; DWORD error; - ThreadSpecificData *tsdPtr = - (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) + TclThreadDataKeyGet(&dataKey); *errorCodePtr = 0; @@ -1836,7 +1841,7 @@ TcpOutputProc( */ if ((infoPtr->flags & SOCKET_ASYNC_CONNECT) - && ! WaitForSocketEvent(infoPtr, FD_CONNECT, errorCodePtr)) { + && !WaitForSocketEvent(infoPtr, FD_CONNECT, errorCodePtr)) { return -1; } @@ -1923,10 +1928,7 @@ TcpSetOptionProc( { SocketInfo *infoPtr; SOCKET sock; -/* - BOOL val = FALSE; - int boolVar, rtn; -*/ + /* * 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 @@ -1943,12 +1945,17 @@ TcpSetOptionProc( infoPtr = (SocketInfo *) instanceData; sock = infoPtr->socket; -/* +#ifdef TCL_FEATURE_KEEPALIVE_NAGLE if (!stricmp(optionName, "-keepalive")) { + BOOL val = FALSE; + int boolVar, rtn; + if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) { return TCL_ERROR; } - if (boolVar) val = TRUE; + if (boolVar) { + val = TRUE; + } rtn = winSock.setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (const char *) &val, sizeof(BOOL)); if (rtn != 0) { @@ -1960,12 +1967,16 @@ TcpSetOptionProc( return TCL_ERROR; } return TCL_OK; - } else if (!stricmp(optionName, "-nagle")) { + BOOL val = FALSE; + int boolVar, rtn; + if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) { return TCL_ERROR; } - if (!boolVar) val = TRUE; + if (!boolVar) { + val = TRUE; + } rtn = winSock.setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (const char *) &val, sizeof(BOOL)); if (rtn != 0) { @@ -1980,8 +1991,9 @@ TcpSetOptionProc( } return Tcl_BadChannelOption(interp, optionName, "keepalive nagle"); -*/ +#else return Tcl_BadChannelOption(interp, optionName, ""); +#endif /*TCL_FEATURE_KEEPALIVE_NAGLE*/ } /* @@ -2095,8 +2107,8 @@ TcpGetOptionProc( /* * getpeername failed - but if we were asked for all the options * (len==0), don't flag an error at that point because it could be - * an fconfigure request on a server socket (which have no peer). - * {Copied from unix/tclUnixChan.c} + * an fconfigure request on a server socket (such sockets have no + * peer). {Copied from unix/tclUnixChan.c} */ if (len) { @@ -2149,7 +2161,7 @@ TcpGetOptionProc( } } -/* +#ifdef TCL_FEATURE_KEEPALIVE_NAGLE if (len == 0 || !strncmp(optionName, "-keepalive", len)) { int optlen; BOOL opt = FALSE; @@ -2189,11 +2201,15 @@ TcpGetOptionProc( return TCL_OK; } } -*/ +#endif /*TCL_FEATURE_KEEPALIVE_NAGLE*/ if (len > 0) { - /*return Tcl_BadChannelOption(interp, optionName, "peername sockname keepalive nagle");*/ +#ifdef TCL_FEATURE_KEEPALIVE_NAGLE + return Tcl_BadChannelOption(interp, optionName, + "peername sockname keepalive nagle"); +#else return Tcl_BadChannelOption(interp, optionName, "peername sockname"); +#endif /*TCL_FEATURE_KEEPALIVE_NAGLE*/ } return TCL_OK; @@ -2273,7 +2289,7 @@ static int TcpGetHandleProc( ClientData instanceData, /* The socket state. */ int direction, /* Not used. */ - ClientData *handlePtr) /* Where to store the handle. */ + ClientData *handlePtr) /* Where to store the handle. */ { SocketInfo *statePtr = (SocketInfo *) instanceData; @@ -2326,9 +2342,9 @@ SocketThread( } /* - * Process all messages on the socket window until WM_QUIT. - * This threads exits only when instructed to do so by the - * call to PostMessage(SOCKET_TERMINATE) in TclpFinalizeSockets(). + * Process all messages on the socket window until WM_QUIT. This threads + * exits only when instructed to do so by the call to + * PostMessage(SOCKET_TERMINATE) in TclpFinalizeSockets(). */ while (GetMessage(&msg, NULL, 0, 0) > 0) { @@ -2373,11 +2389,11 @@ SocketProc( int event, error; SOCKET socket; SocketInfo *infoPtr; - ThreadSpecificData *tsdPtr = + ThreadSpecificData *tsdPtr = (ThreadSpecificData *) #ifdef _WIN64 - (ThreadSpecificData *) GetWindowLongPtr(hwnd, GWLP_USERDATA); + GetWindowLongPtr(hwnd, GWLP_USERDATA); #else - (ThreadSpecificData *) GetWindowLong(hwnd, GWL_USERDATA); + GetWindowLong(hwnd, GWL_USERDATA); #endif switch (message) { @@ -2387,7 +2403,7 @@ SocketProc( case WM_CREATE: /* - * store the initial tsdPtr, it's from a different thread, so it's not + * Store the initial tsdPtr, it's from a different thread, so it's not * directly accessible, but needed. */ @@ -2420,9 +2436,7 @@ SocketProc( if (infoPtr->socket == 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. @@ -2467,6 +2481,7 @@ SocketProc( /* * Wake up the Main Thread. */ + SetEvent(tsdPtr->readyEvent); Tcl_ThreadAlert(tsdPtr->threadId); break; @@ -2555,9 +2570,9 @@ InitializeHostName( 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. + * 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. */ @@ -2574,8 +2589,7 @@ InitializeHostName( *encodingPtr = Tcl_GetEncoding(NULL, "utf-8"); *lengthPtr = Tcl_DStringLength(&ds); *valuePtr = ckalloc((unsigned int) (*lengthPtr)+1); - memcpy((VOID *) *valuePtr, (VOID *) Tcl_DStringValue(&ds), - (size_t)(*lengthPtr)+1); + memcpy(*valuePtr, Tcl_DStringValue(&ds), (size_t)(*lengthPtr)+1); Tcl_DStringFree(&ds); } |