From 32cdcfd0d04a0fd21367cceb1a39d4732bf27837 Mon Sep 17 00:00:00 2001 From: davygrvy Date: Wed, 27 Nov 2002 00:58:00 +0000 Subject: * 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. --- ChangeLog | 19 ++ win/tclWinPort.h | 10 +- win/tclWinSock.c | 982 ++++++++++++++++++++++++++++++++----------------------- 3 files changed, 608 insertions(+), 403 deletions(-) diff --git a/ChangeLog b/ChangeLog index 57a3b20..16e5fc4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,24 @@ 2002-11-26 David Gravereaux + * 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 + * 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 #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 #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); } -- cgit v0.12