diff options
-rw-r--r-- | ChangeLog | 19 | ||||
-rw-r--r-- | win/tclWinPort.h | 10 | ||||
-rw-r--r-- | win/tclWinSock.c | 982 |
3 files changed, 608 insertions, 403 deletions
@@ -1,5 +1,24 @@ 2002-11-26 David Gravereaux <davygrvy@pobox.com> + * win/tclWinPort.h: + * win/tclWinSock.c: This patch does two things: + + 1) Cleans-up the winsock typedefs by using the typedefs + provided by winsock2.h. This has no effect on how winsock + is initialized; just makes the source code easier to read. + [Patch 561305] + + 2) Revamps how the socket message handler thread is brough up + and down to allows for cleaner exits without the use of + TerminateThread(). TerminateThread is evil. No attempt has + been made to resolve [Bug 593810] which may need a new + channel driver version for adding a registering function + whithin the transfered thread to init the handler thread. + IOW, initialization of the TSD structure was getting bypassed + through the thread extension's [thread::transfer] command. + +2002-11-26 David Gravereaux <davygrvy@pobox.com> + * win/tclWinConsole.c: * win/tclWinPipe.c: * win/tclWinSerial.c: diff --git a/win/tclWinPort.h b/win/tclWinPort.h index 011a061..f0ba460 100644 --- a/win/tclWinPort.h +++ b/win/tclWinPort.h @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclWinPort.h,v 1.34 2002/09/27 00:50:10 hobbs Exp $ + * RCS: @(#) $Id: tclWinPort.h,v 1.35 2002/11/27 00:58:01 davygrvy Exp $ */ #ifndef _TCLWINPORT @@ -69,6 +69,14 @@ #include <windows.h> #undef WIN32_LEAN_AND_MEAN +/* + * Ask for the winsock function typedefs, only. wspiapi.h may be + * included, 1) isn't used, and 2) can't cope with typedefs only. + * This appears to be a bug in wspiapi.h, so make sure it is excluded. + */ +#define _WSPIAPI_H_ +#define INCL_WINSOCK_API_PROTOTYPES 0 +#define INCL_WINSOCK_API_TYPEDEFS 1 #include <winsock2.h> #ifdef BUILD_tcl diff --git a/win/tclWinSock.c b/win/tclWinSock.c index a520380..160ed14 100644 --- a/win/tclWinSock.c +++ b/win/tclWinSock.c @@ -8,12 +8,21 @@ * 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.27 2002/11/26 22:35:20 davygrvy Exp $ + * RCS: @(#) $Id: tclWinSock.c,v 1.28 2002/11/27 00:58:01 davygrvy Exp $ */ #include "tclWinInt.h" /* + * Make sure to remove the redirection defines set in tclWinPort.h + * that is in use in other sections of the core, except for us. + */ +#undef getservbyname +#undef getsockopt +#undef ntohs +#undef setsockopt + +/* * The following variable is used to tell whether this module has been * initialized. */ @@ -27,64 +36,66 @@ static char hostname[255]; /* This buffer should be big enough for TCL_DECLARE_MUTEX(socketMutex) /* - * The following structure contains pointers to all of the WinSock API entry - * points used by Tcl. It is initialized by InitSockets. Since we - * dynamically load Winsock.dll on demand, we must use this function table - * to refer to functions in the socket API. + * The following structure contains pointers to all of the WinSock API + * entry points used by Tcl. It is initialized by InitSockets. Since + * we dynamically load the Winsock DLL on demand, we must use this + * function table to refer to functions in the winsock API. */ static struct { - HINSTANCE hInstance; /* Handle to WinSock library. */ - SOCKET (PASCAL FAR *accept)(SOCKET s, struct sockaddr FAR *addr, - int FAR *addrlen); - int (PASCAL FAR *bind)(SOCKET s, const struct sockaddr FAR *addr, - int namelen); - int (PASCAL FAR *closesocket)(SOCKET s); - int (PASCAL FAR *connect)(SOCKET s, const struct sockaddr FAR *name, - int namelen); - int (PASCAL FAR *ioctlsocket)(SOCKET s, long cmd, u_long FAR *argp); - int (PASCAL FAR *getsockopt)(SOCKET s, int level, int optname, - char FAR * optval, int FAR *optlen); - u_short (PASCAL FAR *htons)(u_short hostshort); - unsigned long (PASCAL FAR *inet_addr)(const char FAR * cp); - char FAR * (PASCAL FAR *inet_ntoa)(struct in_addr in); - int (PASCAL FAR *listen)(SOCKET s, int backlog); - u_short (PASCAL FAR *ntohs)(u_short netshort); - int (PASCAL FAR *recv)(SOCKET s, char FAR * buf, int len, int flags); - int (PASCAL FAR *select)(int nfds, fd_set FAR * readfds, - fd_set FAR * writefds, fd_set FAR * exceptfds, - const struct timeval FAR * tiemout); - int (PASCAL FAR *send)(SOCKET s, const char FAR * buf, int len, int flags); - int (PASCAL FAR *setsockopt)(SOCKET s, int level, int optname, - const char FAR * optval, int optlen); - int (PASCAL FAR *shutdown)(SOCKET s, int how); - SOCKET (PASCAL FAR *socket)(int af, int type, int protocol); - struct hostent FAR * (PASCAL FAR *gethostbyname)(const char FAR * name); - struct hostent FAR * (PASCAL FAR *gethostbyaddr)(const char FAR *addr, - int addrlen, int addrtype); - int (PASCAL FAR *gethostname)(char FAR * name, int namelen); - int (PASCAL FAR *getpeername)(SOCKET sock, struct sockaddr FAR *name, - int FAR *namelen); - struct servent FAR * (PASCAL FAR *getservbyname)(const char FAR * name, - const char FAR * proto); - int (PASCAL FAR *getsockname)(SOCKET sock, struct sockaddr FAR *name, - int FAR *namelen); - int (PASCAL FAR *WSAStartup)(WORD wVersionRequired, LPWSADATA lpWSAData); - int (PASCAL FAR *WSACleanup)(void); - int (PASCAL FAR *WSAGetLastError)(void); - int (PASCAL FAR *WSAAsyncSelect)(SOCKET s, HWND hWnd, u_int wMsg, - long lEvent); + HMODULE hModule; /* Handle to WinSock library. */ + + /* Winsock 1.1 functions */ + LPFN_ACCEPT accept; + LPFN_BIND bind; + LPFN_CLOSESOCKET closesocket; + LPFN_CONNECT connect; + LPFN_GETHOSTBYADDR gethostbyaddr; + LPFN_GETHOSTBYNAME gethostbyname; + LPFN_GETHOSTNAME gethostname; + LPFN_GETPEERNAME getpeername; + LPFN_GETSERVBYNAME getservbyname; + LPFN_GETSOCKNAME getsockname; + LPFN_GETSOCKOPT getsockopt; + LPFN_HTONS htons; + LPFN_INET_ADDR inet_addr; + LPFN_INET_NTOA inet_ntoa; + LPFN_IOCTLSOCKET ioctlsocket; + LPFN_LISTEN listen; + LPFN_NTOHS ntohs; + LPFN_RECV recv; + LPFN_SELECT select; + LPFN_SEND send; + LPFN_SETSOCKOPT setsockopt; + LPFN_SHUTDOWN shutdown; + LPFN_SOCKET socket; + LPFN_WSAASYNCSELECT WSAAsyncSelect; + LPFN_WSACLEANUP WSACleanup; + LPFN_WSAGETLASTERROR WSAGetLastError; + LPFN_WSASTARTUP WSAStartup; + } winSock; /* * The following defines declare the messages used on socket windows. */ -#define SOCKET_MESSAGE WM_USER+1 -#define SOCKET_SELECT WM_USER+2 -#define SOCKET_TERMINATE WM_USER+3 -#define SELECT TRUE -#define UNSELECT FALSE +#define SOCKET_MESSAGE WM_USER+1 +#define SOCKET_SELECT WM_USER+2 +#define SOCKET_TERMINATE WM_USER+3 +#define SELECT TRUE +#define UNSELECT FALSE + +/* + * Accepted sockets done in the message handling thread are stored here + * and appended to the listen sockets SocketInfo struct until they are + * processed. + */ + +typedef struct SocketAcceptInfo { + SOCKET newSock; + SOCKADDR_IN newAddr; +} SocketAcceptInfo; /* * The following structure is used to store the data associated with @@ -92,27 +103,37 @@ static struct { */ typedef struct SocketInfo { - Tcl_Channel channel; /* Channel associated with this socket. */ + Tcl_Channel channel; /* Channel associated with this + * socket. */ SOCKET socket; /* Windows SOCKET handle. */ 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, - * 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 - * that have arrived and not processed. */ + 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, 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 acceptedSocketsCount; /* Count of the current number of + * accepted connections ready and + * not yet processed. */ + SocketAcceptInfo **acceptedSockets; /* The array of accepted + * connections on this listening + * socket. */ + int acceptedSocketsSize; /* The size of the acceptedSockets + * array. */ Tcl_TcpAcceptProc *acceptProc; /* Proc to call on accept. */ ClientData acceptProcData; /* The data for the accept proc. */ int lastError; /* Error code from last message. */ - struct SocketInfo *nextPtr; /* The next socket on the global socket - * list. */ + struct SocketInfo *nextPtr; /* The next socket on the per-thread + * socket list. */ } SocketInfo; /* @@ -141,73 +162,68 @@ typedef struct SocketEvent { * a SocketInfo structure. */ -#define SOCKET_ASYNC (1<<0) /* The socket is in blocking mode. */ +#define SOCKET_ASYNC (1<<0) /* The socket is in blocking + * mode. */ #define SOCKET_EOF (1<<1) /* A zero read happened on * the socket. */ -#define SOCKET_ASYNC_CONNECT (1<<2) /* This socket uses async connect. */ +#define SOCKET_ASYNC_CONNECT (1<<2) /* This socket uses async + * connect. */ #define SOCKET_PENDING (1<<3) /* A message has been sent * for this socket */ typedef struct ThreadSpecificData { - /* - * Every open socket has an entry on the following list. - */ - HWND hwnd; /* Handle to window for socket messages. */ HANDLE socketThread; /* Thread handling the window */ Tcl_ThreadId threadId; /* Parent thread. */ - HANDLE readyEvent; /* Event indicating that a socket event is ready. - * Also used to indicate that the socketThread has - * been initialized and has started. */ + HANDLE readyEvent; /* Event indicating that a socket event is + * ready. Also used to indicate that the + * socketThread has been initialized and has + * started. */ HANDLE socketListLock; /* Win32 Event to lock the socketList */ - SocketInfo *socketList; + SocketInfo *socketList; /* Every open socket has an entry on this + * list. */ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; -static WNDCLASSA windowClass; +static WNDCLASS windowClass; /* * Static functions defined in this file. */ -static SocketInfo * CreateSocket _ANSI_ARGS_((Tcl_Interp *interp, - int port, CONST char *host, int server, - CONST char *myaddr, int myport, int async)); -static int CreateSocketAddress _ANSI_ARGS_( - (struct sockaddr_in *sockaddrPtr, - CONST char *host, int port)); -static void InitSockets _ANSI_ARGS_((void)); -static SocketInfo * NewSocketInfo _ANSI_ARGS_((SOCKET socket)); -static void SocketCheckProc _ANSI_ARGS_((ClientData clientData, - int flags)); -static int SocketEventProc _ANSI_ARGS_((Tcl_Event *evPtr, - int flags)); -static void SocketExitHandler _ANSI_ARGS_((ClientData clientData)); -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)); -static int TcpCloseProc _ANSI_ARGS_((ClientData instanceData, - Tcl_Interp *interp)); -static int TcpGetOptionProc _ANSI_ARGS_((ClientData instanceData, - Tcl_Interp *interp, CONST char *optionName, - Tcl_DString *optionValue)); -static int TcpInputProc _ANSI_ARGS_((ClientData instanceData, - char *buf, int toRead, int *errorCode)); -static int TcpOutputProc _ANSI_ARGS_((ClientData instanceData, - CONST char *buf, int toWrite, int *errorCode)); -static void TcpWatchProc _ANSI_ARGS_((ClientData instanceData, - int mask)); -static int TcpGetHandleProc _ANSI_ARGS_((ClientData instanceData, - int direction, ClientData *handlePtr)); -static int WaitForSocketEvent _ANSI_ARGS_((SocketInfo *infoPtr, - int events, int *errorCodePtr)); -static DWORD WINAPI SocketThread _ANSI_ARGS_((LPVOID arg)); +static SocketInfo * CreateSocket _ANSI_ARGS_((Tcl_Interp *interp, + int port, CONST char *host, + int server, CONST char *myaddr, + int myport, int async)); +static int CreateSocketAddress _ANSI_ARGS_( + (LPSOCKADDR_IN sockaddrPtr, + CONST char *host, int port)); +static void InitSockets _ANSI_ARGS_((void)); +static SocketInfo * NewSocketInfo _ANSI_ARGS_((SOCKET socket)); +static Tcl_EventCheckProc SocketCheckProc; +static Tcl_EventProc SocketEventProc; +static void SocketExitHandler _ANSI_ARGS_(( + ClientData clientData)); +static LRESULT CALLBACK SocketProc _ANSI_ARGS_((HWND hwnd, + UINT message, WPARAM wParam, + LPARAM lParam)); +static Tcl_EventSetupProc SocketSetupProc; +static Tcl_ExitProc SocketThreadExitHandler; +static int SocketsEnabled _ANSI_ARGS_((void)); +static void TcpAccept _ANSI_ARGS_((SocketInfo *infoPtr, + SocketAcceptInfo *saiPtr)); +static Tcl_DriverBlockModeProc TcpBlockProc; +static Tcl_DriverCloseProc TcpCloseProc; +static Tcl_DriverSetOptionProc TcpSetOptionProc; +static Tcl_DriverGetOptionProc TcpGetOptionProc; +static Tcl_DriverInputProc TcpInputProc; +static Tcl_DriverOutputProc TcpOutputProc; +static Tcl_DriverWatchProc TcpWatchProc; +static Tcl_DriverGetHandleProc TcpGetHandleProc; +static int WaitForSocketEvent _ANSI_ARGS_(( + SocketInfo *infoPtr, int events, + int *errorCodePtr)); +static DWORD WINAPI SocketThread _ANSI_ARGS_((LPVOID arg)); /* * This structure describes the channel type structure for TCP socket @@ -215,27 +231,22 @@ static DWORD WINAPI SocketThread _ANSI_ARGS_((LPVOID arg)); */ static Tcl_ChannelType tcpChannelType = { - "tcp", /* Type name. */ - TCL_CHANNEL_VERSION_2, /* v2 channel */ - TcpCloseProc, /* Close proc. */ - TcpInputProc, /* Input proc. */ - TcpOutputProc, /* Output proc. */ - NULL, /* Seek proc. */ - NULL, /* Set option proc. */ - TcpGetOptionProc, /* Get option proc. */ - TcpWatchProc, /* Set up notifier to watch this channel. */ - TcpGetHandleProc, /* Get an OS handle from channel. */ - NULL, /* close2proc. */ - TcpBlockProc, /* Set socket into (non-)blocking mode. */ - NULL, /* flush proc. */ - NULL, /* handler proc. */ + "tcp", /* Type name. */ + TCL_CHANNEL_VERSION_2, /* v2 channel */ + TcpCloseProc, /* Close proc. */ + TcpInputProc, /* Input proc. */ + TcpOutputProc, /* Output proc. */ + NULL, /* Seek proc. */ + TcpSetOptionProc, /* Set option proc. */ + TcpGetOptionProc, /* Get option proc. */ + TcpWatchProc, /* Set up notifier to watch this channel. */ + TcpGetHandleProc, /* Get an OS handle from channel. */ + NULL, /* close2proc. */ + TcpBlockProc, /* Set socket into (non-)blocking mode. */ + NULL, /* flush proc. */ + NULL, /* handler proc. */ }; -/* - * Define version of Winsock required by Tcl. - */ - -#define WSA_VERSION_REQD MAKEWORD(1,1) /* *---------------------------------------------------------------------- @@ -267,104 +278,97 @@ InitSockets() ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); - if (! initialized) { + if (!initialized) { initialized = 1; Tcl_CreateExitHandler(SocketExitHandler, (ClientData) NULL); - winSock.hInstance = LoadLibraryA("wsock32.dll"); + /* Try loading the win32 winsock library. */ + winSock.hModule = LoadLibraryA("wsock32.dll"); /* * Initialize the function table. */ - if (!SocketsEnabled()) { + if (winSock.hModule == NULL) { 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"); + winSock.accept = (LPFN_ACCEPT) + GetProcAddress(winSock.hModule, "accept"); + winSock.bind = (LPFN_BIND) + GetProcAddress(winSock.hModule, "bind"); + winSock.closesocket = (LPFN_CLOSESOCKET) + GetProcAddress(winSock.hModule, "closesocket"); + winSock.connect = (LPFN_CONNECT) + GetProcAddress(winSock.hModule, "connect"); + winSock.gethostbyaddr = (LPFN_GETHOSTBYADDR) + GetProcAddress(winSock.hModule, "gethostbyaddr"); + winSock.gethostbyname = (LPFN_GETHOSTBYNAME) + GetProcAddress(winSock.hModule, "gethostbyname"); + winSock.gethostname = (LPFN_GETHOSTNAME) + GetProcAddress(winSock.hModule, "gethostname"); + winSock.getpeername = (LPFN_GETPEERNAME) + GetProcAddress(winSock.hModule, "getpeername"); + winSock.getservbyname = (LPFN_GETSERVBYNAME) + GetProcAddress(winSock.hModule, "getservbyname"); + winSock.getsockname = (LPFN_GETSOCKNAME) + GetProcAddress(winSock.hModule, "getsockname"); + winSock.getsockopt = (LPFN_GETSOCKOPT) + GetProcAddress(winSock.hModule, "getsockopt"); + winSock.htons = (LPFN_HTONS) + GetProcAddress(winSock.hModule, "htons"); + winSock.inet_addr = (LPFN_INET_ADDR) + GetProcAddress(winSock.hModule, "inet_addr"); + winSock.inet_ntoa = (LPFN_INET_NTOA) + GetProcAddress(winSock.hModule, "inet_ntoa"); + winSock.ioctlsocket = (LPFN_IOCTLSOCKET) + GetProcAddress(winSock.hModule, "ioctlsocket"); + winSock.listen = (LPFN_LISTEN) + GetProcAddress(winSock.hModule, "listen"); + winSock.ntohs = (LPFN_NTOHS) + GetProcAddress(winSock.hModule, "ntohs"); + winSock.recv = (LPFN_RECV) + GetProcAddress(winSock.hModule, "recv"); + winSock.select = (LPFN_SELECT) + GetProcAddress(winSock.hModule, "select"); + winSock.send = (LPFN_SEND) + GetProcAddress(winSock.hModule, "send"); + winSock.setsockopt = (LPFN_SETSOCKOPT) + GetProcAddress(winSock.hModule, "setsockopt"); + winSock.shutdown = (LPFN_SHUTDOWN) + GetProcAddress(winSock.hModule, "shutdown"); + winSock.socket = (LPFN_SOCKET) + GetProcAddress(winSock.hModule, "socket"); + winSock.WSAAsyncSelect = (LPFN_WSAASYNCSELECT) + GetProcAddress(winSock.hModule, "WSAAsyncSelect"); + winSock.WSACleanup = (LPFN_WSACLEANUP) + GetProcAddress(winSock.hModule, "WSACleanup"); + winSock.WSAGetLastError = (LPFN_WSAGETLASTERROR) + GetProcAddress(winSock.hModule, "WSAGetLastError"); + winSock.WSAStartup = (LPFN_WSASTARTUP) + GetProcAddress(winSock.hModule, "WSAStartup"); /* - * Now check that all fields are properly initialized. If not, return - * zero to indicate that we failed to initialize properly. + * 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) || + if ((winSock.accept == NULL) || (winSock.bind == NULL) || (winSock.closesocket == NULL) || (winSock.connect == NULL) || - (winSock.ioctlsocket == NULL) || + (winSock.gethostbyname == NULL) || + (winSock.gethostbyaddr == NULL) || + (winSock.gethostname == NULL) || + (winSock.getpeername == NULL) || + (winSock.getservbyname == NULL) || + (winSock.getsockname == NULL) || (winSock.getsockopt == NULL) || (winSock.htons == NULL) || (winSock.inet_addr == NULL) || (winSock.inet_ntoa == NULL) || + (winSock.ioctlsocket == NULL) || (winSock.listen == NULL) || (winSock.ntohs == NULL) || (winSock.recv == NULL) || @@ -372,16 +376,11 @@ InitSockets() (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.WSAAsyncSelect == NULL) || (winSock.WSACleanup == NULL) || (winSock.WSAGetLastError == NULL) || - (winSock.WSAAsyncSelect == NULL)) { + (winSock.WSAStartup == NULL)) + { goto unloadLibrary; } @@ -405,19 +404,19 @@ InitSockets() if (!RegisterClassA(&windowClass)) { TclWinConvertError(GetLastError()); - (*winSock.WSACleanup)(); goto unloadLibrary; } /* * Initialize the winsock library and check the version number. + * We only ask for the 1.1 interface. */ - if ((*winSock.WSAStartup)(WSA_VERSION_REQD, &wsaData) != 0) { + if (winSock.WSAStartup(MAKEWORD(1,1), &wsaData) != 0) { goto unloadLibrary; } - if (wsaData.wVersion != WSA_VERSION_REQD) { - (*winSock.WSACleanup)(); + if (wsaData.wVersion < MAKEWORD(1,1)) { + winSock.WSACleanup(); goto unloadLibrary; } } @@ -437,7 +436,7 @@ InitSockets() tsdPtr->socketListLock = CreateEvent(NULL, FALSE, TRUE, NULL); tsdPtr->socketThread = CreateThread(NULL, 256, SocketThread, tsdPtr, 0, &id); - SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST); + SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST); if (tsdPtr->socketThread == NULL) { goto unloadLibrary; @@ -450,7 +449,8 @@ InitSockets() * seconds. */ - if (WaitForSingleObject(tsdPtr->readyEvent, 20000) == WAIT_TIMEOUT) { + if (WaitForSingleObject(tsdPtr->readyEvent, 20000) + == WAIT_TIMEOUT) { goto unloadLibrary; } @@ -464,19 +464,11 @@ InitSockets() return; unloadLibrary: - if (tsdPtr != NULL) { - if (tsdPtr->hwnd != NULL) { - DestroyWindow(tsdPtr->hwnd); - } - if (tsdPtr->socketThread != NULL) { - TerminateThread(tsdPtr->socketThread, 0); - tsdPtr->socketThread = NULL; - } - CloseHandle(tsdPtr->readyEvent); - CloseHandle(tsdPtr->socketListLock); + if (tsdPtr != NULL && tsdPtr->hwnd != NULL) { + SocketThreadExitHandler(0); } - FreeLibrary(winSock.hInstance); - winSock.hInstance = NULL; + FreeLibrary(winSock.hModule); + winSock.hModule = NULL; return; } @@ -502,7 +494,7 @@ SocketsEnabled() { int enabled; Tcl_MutexLock(&socketMutex); - enabled = (winSock.hInstance != NULL); + enabled = (winSock.hModule != NULL); Tcl_MutexUnlock(&socketMutex); return enabled; } @@ -531,11 +523,16 @@ SocketExitHandler(clientData) ClientData clientData; /* Not used. */ { Tcl_MutexLock(&socketMutex); - if (winSock.hInstance) { - UnregisterClassA("TclSocket", TclWinGetTclInstance()); - (*winSock.WSACleanup)(); - FreeLibrary(winSock.hInstance); - winSock.hInstance = NULL; + if (winSock.hModule) { + /* + * Make sure the socket event handling window is cleaned-up + * for, at most, this thread. + */ + SocketThreadExitHandler(clientData); + UnregisterClass("TclSocket", TclWinGetTclInstance()); + winSock.WSACleanup(); + FreeLibrary(winSock.hModule); + winSock.hModule = NULL; } initialized = 0; hostnameInitialized = 0; @@ -568,24 +565,26 @@ SocketThreadExitHandler(clientData) (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); if (tsdPtr->socketThread != NULL) { + DWORD exitCode; - PostMessage(tsdPtr->hwnd, SOCKET_TERMINATE, 0, 0); + GetExitCodeThread(tsdPtr->socketThread, &exitCode); + if (exitCode == STILL_ACTIVE) { + PostMessage(tsdPtr->hwnd, SOCKET_TERMINATE, 0, 0); - /* - * Wait for the thread to terminate. This ensures that we are - * completely cleaned up before we leave this function. - */ + /* + * Wait for the thread to close. This ensures that we are + * completely cleaned up before we leave this function. + */ - WaitForSingleObject(tsdPtr->socketThread, INFINITE); + WaitForSingleObject(tsdPtr->socketThread, INFINITE); + } CloseHandle(tsdPtr->socketThread); + tsdPtr->socketThread = NULL; CloseHandle(tsdPtr->readyEvent); CloseHandle(tsdPtr->socketListLock); - - } - if (tsdPtr->hwnd != NULL) { - DestroyWindow(tsdPtr->hwnd); } - + + Tcl_DeleteThreadExitHandler(SocketThreadExitHandler, NULL); Tcl_DeleteEventSource(SocketSetupProc, SocketCheckProc, NULL); } @@ -770,27 +769,50 @@ SocketEventProc(evPtr, flags) break; } } - SetEvent(tsdPtr->socketListLock); /* * Discard events that have gone stale. */ if (!infoPtr) { + SetEvent(tsdPtr->socketListLock); return 1; } infoPtr->flags &= ~SOCKET_PENDING; /* - * Handle connection requests directly. + * Handle all accepted connections directly. */ if (infoPtr->readyEvents & FD_ACCEPT) { - TcpAccept(infoPtr); + int todo, count; + SocketAcceptInfo **saiPtr; + + /* + * First copy and reset the list, so we can remove the lock. + */ + + count = infoPtr->acceptedSocketsCount; + infoPtr->acceptedSocketsCount = 0; + saiPtr = (SocketAcceptInfo **) ckalloc(sizeof(SocketAcceptInfo *) * count); + memcpy(saiPtr, infoPtr->acceptedSockets, sizeof(SocketAcceptInfo *) * count); + infoPtr->readyEvents &= ~(FD_ACCEPT); + SetEvent(tsdPtr->socketListLock); + + for (todo = 0; count > todo; todo++) { + TcpAccept(infoPtr, saiPtr[todo]); + ckfree((char *) saiPtr[todo]); + } + ckfree((char *) saiPtr); return 1; } + /* + * Release the lock here as FD_ACCEPTs are a special case. + */ + + SetEvent(tsdPtr->socketListLock); /* * Mask off unwanted events and compute the read/write mask so @@ -833,7 +855,7 @@ SocketEventProc(evPtr, flags) timeout.tv_usec = 0; timeout.tv_sec = 0; - if ((*winSock.select)(0, &readFds, NULL, NULL, &timeout) != 0) { + if (winSock.select(0, &readFds, NULL, NULL, &timeout) != 0) { mask |= TCL_READABLE; } else { infoPtr->readyEvents &= ~(FD_READ); @@ -927,8 +949,8 @@ TcpCloseProc(instanceData, interp) * in the background. */ - if ((*winSock.closesocket)(infoPtr->socket) == SOCKET_ERROR) { - TclWinConvertWSAError((*winSock.WSAGetLastError)()); + if (winSock.closesocket(infoPtr->socket) == SOCKET_ERROR) { + TclWinConvertWSAError(winSock.WSAGetLastError()); errorCode = Tcl_GetErrno(); } } @@ -945,8 +967,21 @@ TcpCloseProc(instanceData, interp) break; } } - SetEvent(tsdPtr->socketListLock); + /* + * In case any accepted sockets had been queued, close them. + */ + if (infoPtr->acceptedSocketsCount) { + int ready; + + for (ready = 0; infoPtr->acceptedSocketsCount > ready; ready++) { + winSock.closesocket(infoPtr->acceptedSockets[ready]->newSock); + ckfree((char *)infoPtr->acceptedSockets[ready]); + } + } + + SetEvent(tsdPtr->socketListLock); + ckfree((char *) infoPtr->acceptedSockets); ckfree((char *) infoPtr); return errorCode; } @@ -981,7 +1016,10 @@ NewSocketInfo(socket) infoPtr->watchEvents = 0; infoPtr->readyEvents = 0; infoPtr->selectEvents = 0; - infoPtr->acceptEventCount = 0; + infoPtr->acceptedSocketsCount = 0; + infoPtr->acceptedSocketsSize = 1; /* start with 1. */ + infoPtr->acceptedSockets = (SocketAcceptInfo **) + ckalloc(sizeof(SocketAcceptInfo *) * infoPtr->acceptedSocketsSize); infoPtr->acceptProc = NULL; infoPtr->lastError = 0; @@ -1022,13 +1060,13 @@ CreateSocket(interp, port, host, server, myaddr, myport, async) int async; /* If nonzero, connect client socket * asynchronously. */ { - u_long flag = 1; /* Indicates nonblocking mode. */ - int asyncConnect = 0; /* Will be 1 if async connect is - * in progress. */ - struct sockaddr_in sockaddr; /* Socket address */ - struct sockaddr_in mysockaddr; /* Socket address for client */ + u_long flag = 1; /* Indicates nonblocking mode. */ + int asyncConnect = 0; /* Will be 1 if async connect is + * in progress. */ + SOCKADDR_IN sockaddr; /* Socket address */ + SOCKADDR_IN mysockaddr; /* Socket address for client */ SOCKET sock; - SocketInfo *infoPtr; /* The returned value. */ + SocketInfo *infoPtr; /* The returned value. */ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); @@ -1051,7 +1089,7 @@ CreateSocket(interp, port, host, server, myaddr, myport, async) goto error; } - sock = (*winSock.socket)(AF_INET, SOCK_STREAM, 0); + sock = winSock.socket(AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { goto error; } @@ -1080,8 +1118,8 @@ CreateSocket(interp, port, host, server, myaddr, myport, async) * to look for bugs. */ - if ((*winSock.bind)(sock, (struct sockaddr *) &sockaddr, - sizeof(sockaddr)) == SOCKET_ERROR) { + if (winSock.bind(sock, (SOCKADDR *) &sockaddr, + sizeof(SOCKADDR_IN)) == SOCKET_ERROR) { goto error; } @@ -1091,7 +1129,7 @@ CreateSocket(interp, port, host, server, myaddr, myport, async) * different, and there may be differences between TCP/IP stacks). */ - if ((*winSock.listen)(sock, SOMAXCONN) == SOCKET_ERROR) { + if (winSock.listen(sock, SOMAXCONN) == SOCKET_ERROR) { goto error; } @@ -1115,8 +1153,8 @@ CreateSocket(interp, port, host, server, myaddr, myport, async) */ if (myaddr != NULL || myport != 0) { - if ((*winSock.bind)(sock, (struct sockaddr *) &mysockaddr, - sizeof(struct sockaddr)) == SOCKET_ERROR) { + if (winSock.bind(sock, (SOCKADDR *) &mysockaddr, + sizeof(SOCKADDR_IN)) == SOCKET_ERROR) { goto error; } } @@ -1127,7 +1165,7 @@ CreateSocket(interp, port, host, server, myaddr, myport, async) */ if (async) { - if ((*winSock.ioctlsocket)(sock, FIONBIO, &flag) == SOCKET_ERROR) { + if (winSock.ioctlsocket(sock, FIONBIO, &flag) == SOCKET_ERROR) { goto error; } } @@ -1136,9 +1174,9 @@ CreateSocket(interp, port, host, server, myaddr, myport, async) * Attempt to connect to the remote socket. */ - if ((*winSock.connect)(sock, (struct sockaddr *) &sockaddr, - sizeof(sockaddr)) == SOCKET_ERROR) { - TclWinConvertWSAError((*winSock.WSAGetLastError)()); + if (winSock.connect(sock, (SOCKADDR *) &sockaddr, + sizeof(SOCKADDR_IN)) == SOCKET_ERROR) { + TclWinConvertWSAError(winSock.WSAGetLastError()); if (Tcl_GetErrno() != EWOULDBLOCK) { goto error; } @@ -1173,20 +1211,20 @@ CreateSocket(interp, port, host, server, myaddr, myport, async) * automatically places the socket into non-blocking mode. */ - (*winSock.ioctlsocket)(sock, FIONBIO, &flag); + winSock.ioctlsocket(sock, FIONBIO, &flag); SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, (LPARAM) infoPtr); return infoPtr; error: - TclWinConvertWSAError((*winSock.WSAGetLastError)()); + TclWinConvertWSAError(winSock.WSAGetLastError()); if (interp != NULL) { Tcl_AppendResult(interp, "couldn't open socket: ", Tcl_PosixError(interp), (char *) NULL); } if (sock != INVALID_SOCKET) { - (*winSock.closesocket)(sock); + winSock.closesocket(sock); } return NULL; } @@ -1210,7 +1248,7 @@ error: static int CreateSocketAddress(sockaddrPtr, host, port) - struct sockaddr_in *sockaddrPtr; /* Socket address */ + LPSOCKADDR_IN sockaddrPtr; /* Socket address */ CONST char *host; /* Host. NULL implies INADDR_ANY */ int port; /* Port number */ { @@ -1231,13 +1269,13 @@ CreateSocketAddress(sockaddrPtr, host, port) (void) memset((char *) sockaddrPtr, '\0', sizeof(struct sockaddr_in)); sockaddrPtr->sin_family = AF_INET; - sockaddrPtr->sin_port = (*winSock.htons)((short) (port & 0xFFFF)); + sockaddrPtr->sin_port = winSock.htons((u_short) (port & 0xFFFF)); if (host == NULL) { addr.s_addr = INADDR_ANY; } else { - addr.s_addr = (*winSock.inet_addr)(host); + addr.s_addr = winSock.inet_addr(host); if (addr.s_addr == INADDR_NONE) { - hostent = (*winSock.gethostbyname)(host); + hostent = winSock.gethostbyname(host); if (hostent != NULL) { memcpy((char *) &addr, (char *) hostent->h_addr_list[0], @@ -1377,7 +1415,7 @@ Tcl_OpenTcpClient(interp, port, host, myaddr, myport, async) return NULL; } - wsprintfA(channelName, "sock%d", infoPtr->socket); + wsprintf(channelName, "sock%d", infoPtr->socket); infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, (ClientData) infoPtr, (TCL_READABLE | TCL_WRITABLE)); @@ -1442,7 +1480,7 @@ Tcl_MakeTcpClientChannel(sock) SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, (LPARAM) infoPtr); - wsprintfA(channelName, "sock%d", infoPtr->socket); + wsprintf(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"); @@ -1495,7 +1533,7 @@ Tcl_OpenTcpServer(interp, port, host, acceptProc, acceptProcData) infoPtr->acceptProc = acceptProc; infoPtr->acceptProcData = acceptProcData; - wsprintfA(channelName, "sock%d", infoPtr->socket); + wsprintf(channelName, "sock%d", infoPtr->socket); infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, (ClientData) infoPtr, 0); @@ -1512,9 +1550,8 @@ Tcl_OpenTcpServer(interp, port, host, acceptProc, acceptProcData) *---------------------------------------------------------------------- * * TcpAccept -- - * Accept a TCP socket connection. This is called by - * SocketEventProc and it in turns calls the registered accept - * procedure. + * Turns the already accepted socket into a channel and calls + * the registered accept procedure. * * Results: * None. @@ -1526,73 +1563,30 @@ Tcl_OpenTcpServer(interp, port, host, acceptProc, acceptProcData) */ static void -TcpAccept(infoPtr) - SocketInfo *infoPtr; /* Socket to accept. */ +TcpAccept(infoPtr, saiPtr) + SocketInfo *infoPtr; /* Listening socket accepted from. */ + SocketAcceptInfo *saiPtr; /* Accept info pointer. */ { - SOCKET newSocket; SocketInfo *newInfoPtr; - struct sockaddr_in addr; - int len; char channelName[16 + TCL_INTEGER_SPACE]; ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); /* - * Accept the incoming connection request. + * Add this socket to the global list of sockets. */ - len = sizeof(struct sockaddr_in); + newInfoPtr = NewSocketInfo(saiPtr->newSock); - newSocket = (*winSock.accept)(infoPtr->socket, - (struct sockaddr *)&addr, - &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. + * Select on read/write/close events and create the channel. */ - - if (newSocket == INVALID_SOCKET) { - infoPtr->acceptEventCount = 0; - infoPtr->readyEvents &= ~(FD_ACCEPT); - return; - } - /* - * It is possible that more than one FD_ACCEPT has been sent, so an extra - * count must be kept. Decrement the count, and reset the readyEvent bit - * if the count is no longer > 0. - */ - - infoPtr->acceptEventCount--; - - if (infoPtr->acceptEventCount <= 0) { - infoPtr->readyEvents &= ~(FD_ACCEPT); - } - - /* - * Win-NT has a misfeature that sockets are inherited in child - * processes by default. Turn off the inherit bit. - */ - - SetHandleInformation( (HANDLE) newSocket, HANDLE_FLAG_INHERIT, 0 ); - - /* - * Add this socket to the global list of sockets. - */ - - newInfoPtr = NewSocketInfo(newSocket); - - /* - * Select on read/write events and create the channel. - */ - newInfoPtr->selectEvents = (FD_READ | FD_WRITE | FD_CLOSE); SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, (LPARAM) newInfoPtr); - - wsprintfA(channelName, "sock%d", newInfoPtr->socket); + + wsprintf(channelName, "sock%d", newInfoPtr->socket); newInfoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, (ClientData) newInfoPtr, (TCL_READABLE | TCL_WRITABLE)); if (Tcl_SetChannelOption(NULL, newInfoPtr->channel, "-translation", @@ -1605,16 +1599,16 @@ TcpAccept(infoPtr) Tcl_Close((Tcl_Interp *) NULL, newInfoPtr->channel); return; } - + /* * Invoke the accept callback procedure. */ - + if (infoPtr->acceptProc != NULL) { (infoPtr->acceptProc) (infoPtr->acceptProcData, newInfoPtr->channel, - (*winSock.inet_ntoa)(addr.sin_addr), - (*winSock.ntohs)(addr.sin_port)); + winSock.inet_ntoa(saiPtr->newAddr.sin_addr), + winSock.ntohs(saiPtr->newAddr.sin_port)); } } @@ -1691,7 +1685,7 @@ TcpInputProc(instanceData, buf, toRead, errorCodePtr) while (1) { SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) UNSELECT, (LPARAM) infoPtr); - bytesRead = (*winSock.recv)(infoPtr->socket, buf, toRead, 0); + bytesRead = winSock.recv(infoPtr->socket, buf, toRead, 0); infoPtr->readyEvents &= ~(FD_READ); /* @@ -1720,7 +1714,7 @@ TcpInputProc(instanceData, buf, toRead, errorCodePtr) * Check for error condition or underflow in non-blocking case. */ - error = (*winSock.WSAGetLastError)(); + error = winSock.WSAGetLastError(); if ((infoPtr->flags & SOCKET_ASYNC) || (error != WSAEWOULDBLOCK)) { TclWinConvertWSAError(error); *errorCodePtr = Tcl_GetErrno(); @@ -1802,7 +1796,7 @@ TcpOutputProc(instanceData, buf, toWrite, errorCodePtr) SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) UNSELECT, (LPARAM) infoPtr); - bytesWritten = (*winSock.send)(infoPtr->socket, buf, toWrite, 0); + bytesWritten = winSock.send(infoPtr->socket, buf, toWrite, 0); if (bytesWritten != SOCKET_ERROR) { /* * Since Windows won't generate a new write event until we hit @@ -1824,7 +1818,7 @@ TcpOutputProc(instanceData, buf, toWrite, errorCodePtr) * send fails with WSAEWOULDBLOCK. */ - error = (*winSock.WSAGetLastError)(); + error = winSock.WSAGetLastError(); if (error == WSAEWOULDBLOCK) { infoPtr->readyEvents &= ~(FD_WRITE); if (infoPtr->flags & SOCKET_ASYNC) { @@ -1859,6 +1853,92 @@ TcpOutputProc(instanceData, buf, toWrite, errorCodePtr) /* *---------------------------------------------------------------------- * + * TcpSetOptionProc -- + * + * Sets Tcp channel specific options. + * + * Results: + * ... + * + * Side effects: + * ... + * + *---------------------------------------------------------------------- + */ + +static int +TcpSetOptionProc ( + ClientData instanceData, /* Socket state. */ + Tcl_Interp *interp, /* For error reporting - can be NULL. */ + CONST char *optionName, /* Name of the option to set. */ + CONST char *value) /* New value for option. */ +{ + 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 WinSock ran before other exit handlers that want to + * use sockets. + */ + + if (!SocketsEnabled()) { + if (interp) { + Tcl_AppendResult(interp, "winsock is not initialized", NULL); + } + return TCL_ERROR; + } + + infoPtr = (SocketInfo *) instanceData; + sock = infoPtr->socket; + +/* + if (!stricmp(optionName, "-keepalive")) { + if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) { + return TCL_ERROR; + } + if (boolVar) val = TRUE; + rtn = winSock.setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, + (const char *) &val, sizeof(BOOL)); + if (rtn != 0) { + TclWinConvertWSAError(winSock.WSAGetLastError()); + if (interp) { + Tcl_AppendResult(interp, "couldn't set socket option: ", + Tcl_PosixError(interp), NULL); + } + return TCL_ERROR; + } + return TCL_OK; + + } else if (!stricmp(optionName, "-nagle")) { + if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) { + return TCL_ERROR; + } + if (!boolVar) val = TRUE; + rtn = winSock.setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, + (const char *) &val, sizeof(BOOL)); + if (rtn != 0) { + TclWinConvertWSAError(winSock.WSAGetLastError()); + if (interp) { + Tcl_AppendResult(interp, "couldn't set socket option: ", + Tcl_PosixError(interp), NULL); + } + return TCL_ERROR; + } + return TCL_OK; + } + + return Tcl_BadChannelOption(interp, optionName, "keepalive nagle"); +*/ + return Tcl_BadChannelOption(interp, optionName, ""); +} + +/* + *---------------------------------------------------------------------- + * * TcpGetOptionProc -- * * Computes an option value for a TCP socket based channel, or a @@ -1889,11 +1969,11 @@ TcpGetOptionProc(instanceData, interp, optionName, dsPtr) * value; initialized by caller. */ { SocketInfo *infoPtr; - struct sockaddr_in sockname; - struct sockaddr_in peername; + SOCKADDR_IN sockname; + SOCKADDR_IN peername; struct hostent *hostEntPtr; SOCKET sock; - int size = sizeof(struct sockaddr_in); + int size = sizeof(SOCKADDR_IN); size_t len = 0; char buf[TCL_INTEGER_SPACE]; @@ -1926,7 +2006,7 @@ TcpGetOptionProc(instanceData, interp, optionName, dsPtr) ret = TclWinGetSockOpt(sock, SOL_SOCKET, SO_ERROR, (char *)&err, &optlen); if (ret == SOCKET_ERROR) { - err = (*winSock.WSAGetLastError)(); + err = winSock.WSAGetLastError(); } if (err) { TclWinConvertWSAError(err); @@ -1938,19 +2018,19 @@ TcpGetOptionProc(instanceData, interp, optionName, dsPtr) if ((len == 0) || ((len > 1) && (optionName[1] == 'p') && (strncmp(optionName, "-peername", len) == 0))) { - if ((*winSock.getpeername)(sock, (struct sockaddr *) &peername, &size) + if (winSock.getpeername(sock, (LPSOCKADDR) &peername, &size) == 0) { if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-peername"); Tcl_DStringStartSublist(dsPtr); } Tcl_DStringAppendElement(dsPtr, - (*winSock.inet_ntoa)(peername.sin_addr)); + winSock.inet_ntoa(peername.sin_addr)); if (peername.sin_addr.s_addr == 0) { hostEntPtr = (struct hostent *) NULL; } else { - hostEntPtr = (*winSock.gethostbyaddr)( + hostEntPtr = winSock.gethostbyaddr( (char *) &(peername.sin_addr), sizeof(peername.sin_addr), AF_INET); } @@ -1958,9 +2038,9 @@ TcpGetOptionProc(instanceData, interp, optionName, dsPtr) Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name); } else { Tcl_DStringAppendElement(dsPtr, - (*winSock.inet_ntoa)(peername.sin_addr)); + winSock.inet_ntoa(peername.sin_addr)); } - TclFormatInt(buf, (*winSock.ntohs)(peername.sin_port)); + TclFormatInt(buf, winSock.ntohs(peername.sin_port)); Tcl_DStringAppendElement(dsPtr, buf); if (len == 0) { Tcl_DStringEndSublist(dsPtr); @@ -1975,7 +2055,7 @@ TcpGetOptionProc(instanceData, interp, optionName, dsPtr) * no peer). {copied from unix/tclUnixChan.c} */ if (len) { - TclWinConvertWSAError((*winSock.WSAGetLastError)()); + TclWinConvertWSAError(winSock.WSAGetLastError()); if (interp) { Tcl_AppendResult(interp, "can't get peername: ", Tcl_PosixError(interp), @@ -1989,18 +2069,18 @@ TcpGetOptionProc(instanceData, interp, optionName, dsPtr) if ((len == 0) || ((len > 1) && (optionName[1] == 's') && (strncmp(optionName, "-sockname", len) == 0))) { - if ((*winSock.getsockname)(sock, (struct sockaddr *) &sockname, &size) + if (winSock.getsockname(sock, (LPSOCKADDR) &sockname, &size) == 0) { if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-sockname"); Tcl_DStringStartSublist(dsPtr); } Tcl_DStringAppendElement(dsPtr, - (*winSock.inet_ntoa)(sockname.sin_addr)); + winSock.inet_ntoa(sockname.sin_addr)); if (sockname.sin_addr.s_addr == 0) { hostEntPtr = (struct hostent *) NULL; } else { - hostEntPtr = (*winSock.gethostbyaddr)( + hostEntPtr = winSock.gethostbyaddr( (char *) &(sockname.sin_addr), sizeof(peername.sin_addr), AF_INET); } @@ -2008,9 +2088,9 @@ TcpGetOptionProc(instanceData, interp, optionName, dsPtr) Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name); } else { Tcl_DStringAppendElement(dsPtr, - (*winSock.inet_ntoa)(sockname.sin_addr)); + winSock.inet_ntoa(sockname.sin_addr)); } - TclFormatInt(buf, (*winSock.ntohs)(sockname.sin_port)); + TclFormatInt(buf, winSock.ntohs(sockname.sin_port)); Tcl_DStringAppendElement(dsPtr, buf); if (len == 0) { Tcl_DStringEndSublist(dsPtr); @@ -2019,7 +2099,7 @@ TcpGetOptionProc(instanceData, interp, optionName, dsPtr) } } else { if (interp) { - TclWinConvertWSAError((*winSock.WSAGetLastError)()); + TclWinConvertWSAError(winSock.WSAGetLastError()); Tcl_AppendResult(interp, "can't get sockname: ", Tcl_PosixError(interp), (char *) NULL); @@ -2028,7 +2108,46 @@ TcpGetOptionProc(instanceData, interp, optionName, dsPtr) } } +/* + if (len == 0 || !strncmp(optionName, "-keepalive", len)) { + int optlen; + BOOL opt = FALSE; + + if (len == 0) { + Tcl_DStringAppendElement(dsPtr, "-keepalive"); + } + optlen = sizeof(BOOL); + winSock.getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&opt, + &optlen); + if (opt) { + Tcl_DStringAppendElement(dsPtr, "1"); + } else { + Tcl_DStringAppendElement(dsPtr, "0"); + } + if (len > 0) return TCL_OK; + } + + if (len == 0 || !strncmp(optionName, "-nagle", len)) { + int optlen; + BOOL opt = FALSE; + + if (len == 0) { + Tcl_DStringAppendElement(dsPtr, "-nagle"); + } + optlen = sizeof(BOOL); + winSock.getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, + &optlen); + if (opt) { + Tcl_DStringAppendElement(dsPtr, "0"); + } else { + Tcl_DStringAppendElement(dsPtr, "1"); + } + if (len > 0) return TCL_OK; + } +*/ + if (len > 0) { + /*return Tcl_BadChannelOption(interp, optionName, "peername sockname keepalive nagle");*/ return Tcl_BadChannelOption(interp, optionName, "peername sockname"); } @@ -2139,8 +2258,8 @@ SocketThread(LPVOID arg) MSG msg; ThreadSpecificData *tsdPtr = (ThreadSpecificData *)(arg); - tsdPtr->hwnd = CreateWindowA("TclSocket", "TclSocket", - WS_TILED, 0, 0, 0, 0, NULL, NULL, windowClass.hInstance, NULL); + tsdPtr->hwnd = CreateWindow("TclSocket", "TclSocket", + WS_TILED, 0, 0, 0, 0, NULL, NULL, windowClass.hInstance, arg); /* * Signal the main thread that the window has been created @@ -2151,29 +2270,17 @@ SocketThread(LPVOID arg) if (tsdPtr->hwnd == NULL) { return 1; - } else { - /* - * store the tsdPtr, it's from a different thread, so it's - * not directly accessible, but needed. - */ - -#ifdef _WIN64 - SetWindowLongPtr(tsdPtr->hwnd, GWLP_USERDATA, (LONG_PTR) tsdPtr); -#else - SetWindowLong(tsdPtr->hwnd, GWL_USERDATA, (LONG) tsdPtr); -#endif } - while (1) { - /* - * Process all outstanding messages on the socket window. - */ + /* + * Process all messages on the socket window. + */ - while (PeekMessage(&msg, tsdPtr->hwnd, 0, 0, PM_REMOVE)) { - DispatchMessage(&msg); - } - WaitMessage(); + while (GetMessage(&msg, NULL, 0, 0) > 0) { + DispatchMessage(&msg); } + + return msg.wParam; } @@ -2218,7 +2325,26 @@ SocketProc(hwnd, message, wParam, lParam) default: return DefWindowProc(hwnd, message, wParam, lParam); break; - + + case WM_CREATE: + /* + * store the initial tsdPtr, it's from a different thread, so it's + * not directly accessible, but needed. + */ + +#ifdef _WIN64 + SetWindowLongPtr(hwnd, GWLP_USERDATA, + (LONG_PTR) ((LPCREATESTRUCT)lParam)->lpCreateParams); +#else + SetWindowLong(hwnd, GWL_USERDATA, + (LONG) ((LPCREATESTRUCT)lParam)->lpCreateParams); +#endif + break; + + case WM_DESTROY: + PostQuitMessage(0); + break; + case SOCKET_MESSAGE: event = WSAGETSELECTEVENT(lParam); error = WSAGETSELECTERROR(lParam); @@ -2243,12 +2369,62 @@ SocketProc(hwnd, message, wParam, lParam) * increment the count if the current event is and * FD_ACCEPT. */ - + if (event & FD_CLOSE) { - infoPtr->acceptEventCount = 0; infoPtr->readyEvents &= ~(FD_WRITE|FD_ACCEPT); } else if (event & FD_ACCEPT) { - infoPtr->acceptEventCount++; + SocketAcceptInfo *saiPtr; + int len = sizeof(SOCKADDR_IN); + + /* + * Accept the incoming connection request now, + * instead of later. This helps avoid time delays + * and possible threading issues related to the + * underlying TCP/IP stack by keeping the accept() + * in the same thread context as the notification + * for it. + */ + + saiPtr = (SocketAcceptInfo *) + ckalloc(sizeof(SocketAcceptInfo)); + saiPtr->newSock = winSock.accept(infoPtr->socket, + (LPSOCKADDR)&saiPtr->newAddr, &len); + + /* + * Clear the event notification mask, due to + * inheritence from the parent listening socket. + */ + + winSock.WSAAsyncSelect(saiPtr->newSock, hwnd, 0, + 0); + + /* + * Win-NT has a misfeature that sockets are + * inherited in child processes by default. + * Turn off the inherit bit. + */ + + SetHandleInformation((HANDLE)saiPtr->newSock, + HANDLE_FLAG_INHERIT, 0); + /* + * If the array isn't large enough, make it + * bigger. + */ + + if ((infoPtr->acceptedSocketsCount + 1) > + infoPtr->acceptedSocketsSize) { + /* double the size. */ + infoPtr->acceptedSocketsSize *= 2; + infoPtr->acceptedSockets = + (SocketAcceptInfo **) + ckrealloc((char *) + infoPtr->acceptedSockets, + sizeof(SocketAcceptInfo *) * + infoPtr->acceptedSocketsSize); + } + + infoPtr->acceptedSockets[ + infoPtr->acceptedSocketsCount++] = saiPtr; } if (event & FD_CONNECT) { @@ -2256,19 +2432,19 @@ SocketProc(hwnd, message, wParam, lParam) * The socket is now connected, * clear the async connect flag. */ - + infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT); - + /* * Remember any error that occurred so we can report * connection failures. */ - + if (error != ERROR_SUCCESS) { TclWinConvertWSAError(error); infoPtr->lastError = Tcl_GetErrno(); } - + } if(infoPtr->flags & SOCKET_ASYNC_CONNECT) { infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT); @@ -2290,22 +2466,24 @@ SocketProc(hwnd, message, wParam, lParam) } SetEvent(tsdPtr->socketListLock); break; + case SOCKET_SELECT: infoPtr = (SocketInfo *) lParam; if (wParam == SELECT) { - (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, hwnd, + winSock.WSAAsyncSelect(infoPtr->socket, hwnd, SOCKET_MESSAGE, infoPtr->selectEvents); } else { /* * Clear the selection mask */ - - (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, hwnd, 0, 0); + + winSock.WSAAsyncSelect(infoPtr->socket, hwnd, 0, 0); } break; + case SOCKET_TERMINATE: - ExitThread(0); + DestroyWindow(hwnd); break; } @@ -2350,7 +2528,7 @@ Tcl_GetHostName() * INTL: bug */ - if ((*winSock.gethostname)(hostname, sizeof(hostname)) == 0) { + if (winSock.gethostname(hostname, sizeof(hostname)) == 0) { Tcl_MutexLock(&socketMutex); hostnameInitialized = 1; Tcl_MutexUnlock(&socketMutex); @@ -2412,7 +2590,7 @@ TclWinGetSockOpt(SOCKET s, int level, int optname, char * optval, return SOCKET_ERROR; } - return (*winSock.getsockopt)(s, level, optname, optval, optlen); + return winSock.getsockopt(s, level, optname, optval, optlen); } int @@ -2429,7 +2607,7 @@ TclWinSetSockOpt(SOCKET s, int level, int optname, const char * optval, return SOCKET_ERROR; } - return (*winSock.setsockopt)(s, level, optname, optval, optlen); + return winSock.setsockopt(s, level, optname, optval, optlen); } u_short @@ -2446,7 +2624,7 @@ TclWinNToHS(u_short netshort) return (u_short) -1; } - return (*winSock.ntohs)(netshort); + return winSock.ntohs(netshort); } struct servent * @@ -2462,7 +2640,7 @@ TclWinGetServByName(const char * name, const char * proto) return (struct servent *) NULL; } - return (*winSock.getservbyname)(name, proto); + return winSock.getservbyname(name, proto); } |