/[dtapublic]/projs/trunk/shared_source/c_tcl_base_7_5_w_mods/tclwinsock.c
ViewVC logotype

Diff of /projs/trunk/shared_source/c_tcl_base_7_5_w_mods/tclwinsock.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 44 by dashley, Fri Oct 14 02:09:58 2016 UTC revision 71 by dashley, Sat Nov 5 11:07:06 2016 UTC
# Line 1  Line 1 
 /* $Header: /cvsroot/esrg/sfesrg/esrgpcpj/shared/tcl_base/tclwinsock.c,v 1.1.1.1 2001/06/13 04:50:36 dtashley Exp $ */  
   
 /*  
  * tclWinSock.c --  
  *  
  *      This file contains Windows-specific socket related code.  
  *  
  * Copyright (c) 1995-1997 Sun Microsystems, Inc.  
  *  
  * 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.1.1.1 2001/06/13 04:50:36 dtashley Exp $  
  */  
   
 #include "tclWinInt.h"  
   
 /*  
  * The following variable is used to tell whether this module has been  
  * initialized.  
  */  
   
 static int initialized = 0;  
   
 static int  hostnameInitialized = 0;  
 static char hostname[255];      /* This buffer should be big enough for  
                                  * hostname plus domain name. */  
   
 TCL_DECLARE_MUTEX(socketMutex)  
   
 /*  
  * The following structure contains pointers to all of the WinSock API entry  
  * 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.  
  */  
   
 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);  
 } 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  
   
 /*  
  * The following structure is used to store the data associated with  
  * each socket.  
  */  
   
 typedef struct SocketInfo {  
     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. */  
     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. */  
 } SocketInfo;  
   
 /*  
  * The following structure is what is added to the Tcl event queue when  
  * a socket event occurs.  
  */  
   
 typedef struct SocketEvent {  
     Tcl_Event header;           /* Information that is standard for  
                                  * all events. */  
     SOCKET socket;              /* Socket descriptor that is ready.  Used  
                                  * to find the SocketInfo structure for  
                                  * the file (can't point directly to the  
                                  * SocketInfo structure because it could  
                                  * go away while the event is queued). */  
 } SocketEvent;  
   
 /*  
  * This defines the minimum buffersize maintained by the kernel.  
  */  
   
 #define TCP_BUFFER_SIZE 4096  
   
 /*  
  * The following macros may be used to set the flags field of  
  * a SocketInfo structure.  
  */  
   
 #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_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 socketListLock;  /* Win32 Event to lock the socketList */  
     SocketInfo *socketList;  
 } ThreadSpecificData;  
   
 static Tcl_ThreadDataKey dataKey;  
 static WNDCLASSA windowClass;  
   
 /*  
  * Static functions defined in this file.  
  */  
   
 static SocketInfo *     CreateSocket _ANSI_ARGS_((Tcl_Interp *interp,  
                             int port, char *host, int server, char *myaddr,  
                             int myport, int async));  
 static int              CreateSocketAddress _ANSI_ARGS_(  
                             (struct sockaddr_in *sockaddrPtr,  
                             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, 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,  
                             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));  
   
 /*  
  * This structure describes the channel type structure for TCP socket  
  * based IO.  
  */  
   
 static Tcl_ChannelType tcpChannelType = {  
     "tcp",              /* Type name. */  
     TcpBlockProc,       /* Set socket into blocking/non-blocking mode. */  
     TcpCloseProc,       /* Close proc. */  
     TcpInputProc,       /* Input proc. */  
     TcpOutputProc,      /* Output proc. */  
     NULL,               /* Seek proc. */  
     NULL,               /* Set option proc. */  
     TcpGetOptionProc,   /* Get option proc. */  
     TcpWatchProc,       /* Initialize notifier to watch this channel. */  
     TcpGetHandleProc,   /* Get an OS handle from channel. */  
 };  
   
 /*  
  * Define version of Winsock required by Tcl.  
  */  
   
 #define WSA_VERSION_REQD MAKEWORD(1,1)  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * InitSockets --  
  *  
  *      Initialize the socket module.  Attempts to load the wsock32.dll  
  *      library and set up the winSock function table.  If successful,  
  *      registers the event window for the socket notifier code.  
  *  
  *      Assumes Mutex is held.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      Dynamically loads wsock32.dll, and registers a new window  
  *      class and creates a window for use in asynchronous socket  
  *      notification.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static void  
 InitSockets()  
 {  
     DWORD id;  
     WSADATA wsaData;  
     ThreadSpecificData *tsdPtr =  
         (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);  
   
     if (! initialized) {  
         initialized = 1;  
         Tcl_CreateExitHandler(SocketExitHandler, (ClientData) NULL);  
   
         winSock.hInstance = LoadLibraryA("wsock32.dll");  
   
         /*  
          * Initialize the function table.  
          */  
   
         if (!SocketsEnabled()) {  
             return;  
         }  
       
         winSock.accept = (SOCKET (PASCAL FAR *)(SOCKET s,  
                 struct sockaddr FAR *addr, int FAR *addrlen))  
             GetProcAddress(winSock.hInstance, "accept");  
         winSock.bind = (int (PASCAL FAR *)(SOCKET s,  
                 const struct sockaddr FAR *addr, int namelen))  
             GetProcAddress(winSock.hInstance, "bind");  
         winSock.closesocket = (int (PASCAL FAR *)(SOCKET s))  
             GetProcAddress(winSock.hInstance, "closesocket");  
         winSock.connect = (int (PASCAL FAR *)(SOCKET s,  
                 const struct sockaddr FAR *name, int namelen))  
             GetProcAddress(winSock.hInstance, "connect");  
         winSock.ioctlsocket = (int (PASCAL FAR *)(SOCKET s, long cmd,  
                 u_long FAR *argp))  
             GetProcAddress(winSock.hInstance, "ioctlsocket");  
         winSock.getsockopt = (int (PASCAL FAR *)(SOCKET s,  
                 int level, int optname, char FAR * optval, int FAR *optlen))  
             GetProcAddress(winSock.hInstance, "getsockopt");  
         winSock.htons = (u_short (PASCAL FAR *)(u_short hostshort))  
             GetProcAddress(winSock.hInstance, "htons");  
         winSock.inet_addr = (unsigned long (PASCAL FAR *)(const char FAR *cp))  
             GetProcAddress(winSock.hInstance, "inet_addr");  
         winSock.inet_ntoa = (char FAR * (PASCAL FAR *)(struct in_addr in))  
             GetProcAddress(winSock.hInstance, "inet_ntoa");  
         winSock.listen = (int (PASCAL FAR *)(SOCKET s, int backlog))  
             GetProcAddress(winSock.hInstance, "listen");  
         winSock.ntohs = (u_short (PASCAL FAR *)(u_short netshort))  
             GetProcAddress(winSock.hInstance, "ntohs");  
         winSock.recv = (int (PASCAL FAR *)(SOCKET s, char FAR * buf,  
                 int len, int flags)) GetProcAddress(winSock.hInstance, "recv");  
         winSock.select = (int (PASCAL FAR *)(int nfds, fd_set FAR * readfds,  
                 fd_set FAR * writefds, fd_set FAR * exceptfds,  
                 const struct timeval FAR * tiemout))  
             GetProcAddress(winSock.hInstance, "select");  
         winSock.send = (int (PASCAL FAR *)(SOCKET s, const char FAR * buf,  
                 int len, int flags)) GetProcAddress(winSock.hInstance, "send");  
         winSock.setsockopt = (int (PASCAL FAR *)(SOCKET s, int level,  
                 int optname, const char FAR * optval, int optlen))  
             GetProcAddress(winSock.hInstance, "setsockopt");  
         winSock.shutdown = (int (PASCAL FAR *)(SOCKET s, int how))  
             GetProcAddress(winSock.hInstance, "shutdown");  
         winSock.socket = (SOCKET (PASCAL FAR *)(int af, int type,  
                 int protocol)) GetProcAddress(winSock.hInstance, "socket");  
         winSock.gethostbyaddr = (struct hostent FAR * (PASCAL FAR *)  
                 (const char FAR *addr, int addrlen, int addrtype))  
             GetProcAddress(winSock.hInstance, "gethostbyaddr");  
         winSock.gethostbyname = (struct hostent FAR * (PASCAL FAR *)  
                 (const char FAR *name))  
             GetProcAddress(winSock.hInstance, "gethostbyname");  
         winSock.gethostname = (int (PASCAL FAR *)(char FAR * name,  
                 int namelen)) GetProcAddress(winSock.hInstance, "gethostname");  
         winSock.getpeername = (int (PASCAL FAR *)(SOCKET sock,  
                 struct sockaddr FAR *name, int FAR *namelen))  
             GetProcAddress(winSock.hInstance, "getpeername");  
         winSock.getservbyname = (struct servent FAR * (PASCAL FAR *)  
                 (const char FAR * name, const char FAR * proto))  
             GetProcAddress(winSock.hInstance, "getservbyname");  
         winSock.getsockname = (int (PASCAL FAR *)(SOCKET sock,  
                 struct sockaddr FAR *name, int FAR *namelen))  
             GetProcAddress(winSock.hInstance, "getsockname");  
         winSock.WSAStartup = (int (PASCAL FAR *)(WORD wVersionRequired,  
                 LPWSADATA lpWSAData)) GetProcAddress(winSock.hInstance, "WSAStartup");  
         winSock.WSACleanup = (int (PASCAL FAR *)(void))  
             GetProcAddress(winSock.hInstance, "WSACleanup");  
         winSock.WSAGetLastError = (int (PASCAL FAR *)(void))  
             GetProcAddress(winSock.hInstance, "WSAGetLastError");  
         winSock.WSAAsyncSelect = (int (PASCAL FAR *)(SOCKET s, HWND hWnd,  
                 u_int wMsg, long lEvent))  
             GetProcAddress(winSock.hInstance, "WSAAsyncSelect");  
       
         /*  
          * Now check that all fields are properly initialized. If not, return  
          * zero to indicate that we failed to initialize properly.  
          */  
       
         if ((winSock.hInstance == NULL) ||  
                 (winSock.accept == NULL) ||  
                 (winSock.bind == NULL) ||  
                 (winSock.closesocket == NULL) ||  
                 (winSock.connect == NULL) ||  
                 (winSock.ioctlsocket == NULL) ||  
                 (winSock.getsockopt == NULL) ||  
                 (winSock.htons == NULL) ||  
                 (winSock.inet_addr == NULL) ||  
                 (winSock.inet_ntoa == NULL) ||  
                 (winSock.listen == NULL) ||  
                 (winSock.ntohs == NULL) ||  
                 (winSock.recv == NULL) ||  
                 (winSock.select == NULL) ||  
                 (winSock.send == NULL) ||  
                 (winSock.setsockopt == NULL) ||  
                 (winSock.socket == NULL) ||  
                 (winSock.gethostbyname == NULL) ||  
                 (winSock.gethostbyaddr == NULL) ||  
                 (winSock.gethostname == NULL) ||  
                 (winSock.getpeername == NULL) ||  
                 (winSock.getservbyname == NULL) ||  
                 (winSock.getsockname == NULL) ||  
                 (winSock.WSAStartup == NULL) ||  
                 (winSock.WSACleanup == NULL) ||  
                 (winSock.WSAGetLastError == NULL) ||  
                 (winSock.WSAAsyncSelect == NULL)) {  
             goto unloadLibrary;  
         }  
           
         /*  
          * Create the async notification window with a new class.  We  
          * must create a new class to avoid a Windows 95 bug that causes  
          * us to get the wrong message number for socket events if the  
          * message window is a subclass of a static control.  
          */  
       
         windowClass.style = 0;  
         windowClass.cbClsExtra = 0;  
         windowClass.cbWndExtra = 0;  
         windowClass.hInstance = TclWinGetTclInstance();  
         windowClass.hbrBackground = NULL;  
         windowClass.lpszMenuName = NULL;  
         windowClass.lpszClassName = "TclSocket";  
         windowClass.lpfnWndProc = SocketProc;  
         windowClass.hIcon = NULL;  
         windowClass.hCursor = NULL;  
   
         if (!RegisterClassA(&windowClass)) {  
             TclWinConvertError(GetLastError());  
             (*winSock.WSACleanup)();  
             goto unloadLibrary;  
         }  
           
         /*  
          * Initialize the winsock library and check the version number.  
          */  
       
         if ((*winSock.WSAStartup)(WSA_VERSION_REQD, &wsaData) != 0) {  
             goto unloadLibrary;  
         }  
         if (wsaData.wVersion != WSA_VERSION_REQD) {  
             (*winSock.WSACleanup)();  
             goto unloadLibrary;  
         }  
     }  
   
     /*  
      * Check for per-thread initialization.  
      */  
   
     if (tsdPtr == NULL) {  
         tsdPtr = TCL_TSD_INIT(&dataKey);  
         tsdPtr->socketList = NULL;  
         tsdPtr->hwnd = NULL;  
   
         tsdPtr->threadId = Tcl_GetCurrentThread();  
           
         tsdPtr->readyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);  
         tsdPtr->socketListLock = CreateEvent(NULL, FALSE, TRUE, NULL);  
         tsdPtr->socketThread = CreateThread(NULL, 8000, SocketThread,  
                 tsdPtr, 0, &id);  
         SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST);  
   
         if (tsdPtr->socketThread == NULL) {  
             goto unloadLibrary;  
         }  
           
   
         /*  
          * Wait for the thread to signal that the window has  
          * been created and is ready to go.  Timeout after twenty  
          * seconds.  
          */  
           
         if (WaitForSingleObject(tsdPtr->readyEvent, 20000) == WAIT_TIMEOUT) {  
             goto unloadLibrary;  
         }  
   
         if (tsdPtr->hwnd == NULL) {  
             goto unloadLibrary;  
         }  
           
         Tcl_CreateEventSource(SocketSetupProc, SocketCheckProc, NULL);  
         Tcl_CreateThreadExitHandler(SocketThreadExitHandler, NULL);  
     }  
     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);  
     }  
     FreeLibrary(winSock.hInstance);  
     winSock.hInstance = NULL;  
     return;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * SocketsEnabled --  
  *  
  *      Check that the WinSock DLL is loaded and ready.  
  *  
  * Results:  
  *      1 if it is.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
     /* ARGSUSED */  
 static int  
 SocketsEnabled()  
 {  
     int enabled;  
     Tcl_MutexLock(&socketMutex);  
     enabled = (winSock.hInstance != NULL);  
     Tcl_MutexUnlock(&socketMutex);  
     return enabled;  
 }  
   
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * SocketExitHandler --  
  *  
  *      Callback invoked during exit clean up to delete the socket  
  *      communication window and to release the WinSock DLL.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
     /* ARGSUSED */  
 static void  
 SocketExitHandler(clientData)  
     ClientData clientData;              /* Not used. */  
 {  
     Tcl_MutexLock(&socketMutex);  
     if (winSock.hInstance) {  
         UnregisterClassA("TclSocket", TclWinGetTclInstance());  
         (*winSock.WSACleanup)();  
         FreeLibrary(winSock.hInstance);  
         winSock.hInstance = NULL;  
     }  
     initialized = 0;  
     hostnameInitialized = 0;  
     Tcl_MutexUnlock(&socketMutex);  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * SocketThreadExitHandler --  
  *  
  *      Callback invoked during thread clean up to delete the socket  
  *      event source.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      Delete the event source.  
  *  
  *----------------------------------------------------------------------  
  */  
   
     /* ARGSUSED */  
 static void  
 SocketThreadExitHandler(clientData)  
     ClientData clientData;              /* Not used. */  
 {  
     ThreadSpecificData *tsdPtr =  
         (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);  
   
     if (tsdPtr->socketThread != NULL) {  
   
         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.  
          */  
   
         WaitForSingleObject(tsdPtr->socketThread, INFINITE);  
         CloseHandle(tsdPtr->socketThread);  
         CloseHandle(tsdPtr->readyEvent);  
         CloseHandle(tsdPtr->socketListLock);  
   
     }  
     if (tsdPtr->hwnd != NULL) {  
         DestroyWindow(tsdPtr->hwnd);  
     }  
       
     Tcl_DeleteEventSource(SocketSetupProc, SocketCheckProc, NULL);  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * TclpHasSockets --  
  *  
  *      This function determines whether sockets are available on the  
  *      current system and returns an error in interp if they are not.  
  *      Note that interp may be NULL.  
  *  
  * Results:  
  *      Returns TCL_OK if the system supports sockets, or TCL_ERROR with  
  *      an error in interp.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 int  
 TclpHasSockets(interp)  
     Tcl_Interp *interp;  
 {  
     Tcl_MutexLock(&socketMutex);  
     InitSockets();  
     Tcl_MutexUnlock(&socketMutex);  
   
     if (SocketsEnabled()) {  
         return TCL_OK;  
     }  
     if (interp != NULL) {  
         Tcl_AppendResult(interp, "sockets are not available on this system",  
                 NULL);  
     }  
     return TCL_ERROR;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * SocketSetupProc --  
  *  
  *      This procedure is invoked before Tcl_DoOneEvent blocks waiting  
  *      for an event.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      Adjusts the block time if needed.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 void  
 SocketSetupProc(data, flags)  
     ClientData data;            /* Not used. */  
     int flags;                  /* Event flags as passed to Tcl_DoOneEvent. */  
 {  
     SocketInfo *infoPtr;  
     Tcl_Time blockTime = { 0, 0 };  
     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);  
   
     if (!(flags & TCL_FILE_EVENTS)) {  
         return;  
     }  
       
     /*  
      * Check to see if there is a ready socket.  If so, poll.  
      */  
   
     WaitForSingleObject(tsdPtr->socketListLock, INFINITE);  
     for (infoPtr = tsdPtr->socketList; infoPtr != NULL;  
             infoPtr = infoPtr->nextPtr) {  
         if (infoPtr->readyEvents & infoPtr->watchEvents) {  
             Tcl_SetMaxBlockTime(&blockTime);  
             break;  
         }  
     }  
     SetEvent(tsdPtr->socketListLock);  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * SocketCheckProc --  
  *  
  *      This procedure is called by Tcl_DoOneEvent to check the socket  
  *      event source for events.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      May queue an event.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static void  
 SocketCheckProc(data, flags)  
     ClientData data;            /* Not used. */  
     int flags;                  /* Event flags as passed to Tcl_DoOneEvent. */  
 {  
     SocketInfo *infoPtr;  
     SocketEvent *evPtr;  
     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);  
   
     if (!(flags & TCL_FILE_EVENTS)) {  
         return;  
     }  
       
     /*  
      * Queue events for any ready sockets that don't already have events  
      * queued (caused by persistent states that won't generate WinSock  
      * events).  
      */  
   
     WaitForSingleObject(tsdPtr->socketListLock, INFINITE);  
     for (infoPtr = tsdPtr->socketList; infoPtr != NULL;  
             infoPtr = infoPtr->nextPtr) {  
         if ((infoPtr->readyEvents & infoPtr->watchEvents)  
                 && !(infoPtr->flags & SOCKET_PENDING)) {  
             infoPtr->flags |= SOCKET_PENDING;  
             evPtr = (SocketEvent *) ckalloc(sizeof(SocketEvent));  
             evPtr->header.proc = SocketEventProc;  
             evPtr->socket = infoPtr->socket;  
             Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);  
         }  
     }  
     SetEvent(tsdPtr->socketListLock);  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * SocketEventProc --  
  *  
  *      This procedure is called by Tcl_ServiceEvent when a socket event  
  *      reaches the front of the event queue.  This procedure is  
  *      responsible for notifying the generic channel code.  
  *  
  * Results:  
  *      Returns 1 if the event was handled, meaning it should be removed  
  *      from the queue.  Returns 0 if the event was not handled, meaning  
  *      it should stay on the queue.  The only time the event isn't  
  *      handled is if the TCL_FILE_EVENTS flag bit isn't set.  
  *  
  * Side effects:  
  *      Whatever the channel callback procedures do.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static int  
 SocketEventProc(evPtr, flags)  
     Tcl_Event *evPtr;           /* Event to service. */  
     int flags;                  /* Flags that indicate what events to  
                                  * handle, such as TCL_FILE_EVENTS. */  
 {  
     SocketInfo *infoPtr;  
     SocketEvent *eventPtr = (SocketEvent *) evPtr;  
     int mask = 0;  
     int events;  
     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);  
   
     if (!(flags & TCL_FILE_EVENTS)) {  
         return 0;  
     }  
   
     /*  
      * Find the specified socket on the socket list.  
      */  
   
     WaitForSingleObject(tsdPtr->socketListLock, INFINITE);  
     for (infoPtr = tsdPtr->socketList; infoPtr != NULL;  
             infoPtr = infoPtr->nextPtr) {  
         if (infoPtr->socket == eventPtr->socket) {  
             break;  
         }  
     }  
     SetEvent(tsdPtr->socketListLock);  
       
     /*  
      * Discard events that have gone stale.  
      */  
   
     if (!infoPtr) {  
         return 1;  
     }  
   
     infoPtr->flags &= ~SOCKET_PENDING;  
   
     /*  
      * Handle connection requests directly.  
      */  
   
     if (infoPtr->readyEvents & FD_ACCEPT) {  
         TcpAccept(infoPtr);  
         return 1;  
     }  
   
   
     /*  
      * Mask off unwanted events and compute the read/write mask so  
      * we can notify the channel.  
      */  
   
     events = infoPtr->readyEvents & infoPtr->watchEvents;  
   
     if (events & FD_CLOSE) {  
         /*  
          * If the socket was closed and the channel is still interested  
          * in read events, then we need to ensure that we keep polling  
          * for this event until someone does something with the channel.  
          * Note that we do this before calling Tcl_NotifyChannel so we don't  
          * have to watch out for the channel being deleted out from under  
          * us.  This may cause a redundant trip through the event loop, but  
          * it's simpler than trying to do unwind protection.  
          */  
   
         Tcl_Time blockTime = { 0, 0 };  
         Tcl_SetMaxBlockTime(&blockTime);  
         mask |= TCL_READABLE;  
     } else if (events & FD_READ) {  
         fd_set readFds;  
         struct timeval timeout;  
   
         /*  
          * We must check to see if data is really available, since someone  
          * could have consumed the data in the meantime.  Turn off async  
          * notification so select will work correctly.  If the socket is  
          * still readable, notify the channel driver, otherwise reset the  
          * async select handler and keep waiting.  
          */  
   
         SendMessage(tsdPtr->hwnd, SOCKET_SELECT,  
                 (WPARAM) UNSELECT, (LPARAM) infoPtr);  
   
         FD_ZERO(&readFds);  
         FD_SET(infoPtr->socket, &readFds);  
         timeout.tv_usec = 0;  
         timeout.tv_sec = 0;  
   
         if ((*winSock.select)(0, &readFds, NULL, NULL, &timeout) != 0) {  
             mask |= TCL_READABLE;  
         } else {  
             SendMessage(tsdPtr->hwnd, SOCKET_SELECT,  
                     (WPARAM) SELECT, (LPARAM) infoPtr);  
             infoPtr->readyEvents &= ~(FD_READ);  
         }  
     }  
     if (events & (FD_WRITE | FD_CONNECT)) {  
         mask |= TCL_WRITABLE;  
     }  
   
     if (mask) {  
         Tcl_NotifyChannel(infoPtr->channel, mask);  
     }  
     return 1;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * TcpBlockProc --  
  *  
  *      Sets a socket into blocking or non-blocking mode.  
  *  
  * Results:  
  *      0 if successful, errno if there was an error.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static int  
 TcpBlockProc(instanceData, mode)  
     ClientData  instanceData;   /* The socket to block/un-block. */  
     int mode;                   /* TCL_MODE_BLOCKING or  
                                  * TCL_MODE_NONBLOCKING. */  
 {  
     SocketInfo *infoPtr = (SocketInfo *) instanceData;  
   
     if (mode == TCL_MODE_NONBLOCKING) {  
         infoPtr->flags |= SOCKET_ASYNC;  
     } else {  
         infoPtr->flags &= ~(SOCKET_ASYNC);  
     }  
     return 0;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * TcpCloseProc --  
  *  
  *      This procedure is called by the generic IO level to perform  
  *      channel type specific cleanup on a socket based channel  
  *      when the channel is closed.  
  *  
  * Results:  
  *      0 if successful, the value of errno if failed.  
  *  
  * Side effects:  
  *      Closes the socket.  
  *  
  *----------------------------------------------------------------------  
  */  
   
     /* ARGSUSED */  
 static int  
 TcpCloseProc(instanceData, interp)  
     ClientData instanceData;    /* The socket to close. */  
     Tcl_Interp *interp;         /* Unused. */  
 {  
     SocketInfo *infoPtr = (SocketInfo *) instanceData;  
     SocketInfo **nextPtrPtr;  
     int errorCode = 0;  
     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);  
   
     /*  
      * Check that WinSock is initialized; do not call it if not, to  
      * 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()) {  
           
         /*  
          * Clean up the OS socket handle.  The default Windows setting  
          * for a socket is SO_DONTLINGER, which does a graceful shutdown  
          * in the background.  
          */  
       
         if ((*winSock.closesocket)(infoPtr->socket) == SOCKET_ERROR) {  
             TclWinConvertWSAError((*winSock.WSAGetLastError)());  
             errorCode = Tcl_GetErrno();  
         }  
     }  
   
     /*  
      * Remove the socket from socketList.  
      */  
   
     WaitForSingleObject(tsdPtr->socketListLock, INFINITE);  
     for (nextPtrPtr = &(tsdPtr->socketList); (*nextPtrPtr) != NULL;  
          nextPtrPtr = &((*nextPtrPtr)->nextPtr)) {  
         if ((*nextPtrPtr) == infoPtr) {  
             (*nextPtrPtr) = infoPtr->nextPtr;  
             break;  
         }  
     }  
     SetEvent(tsdPtr->socketListLock);  
       
     ckfree((char *) infoPtr);  
     return errorCode;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * NewSocketInfo --  
  *  
  *      This function allocates and initializes a new SocketInfo  
  *      structure.  
  *  
  * Results:  
  *      Returns a newly allocated SocketInfo.  
  *  
  * Side effects:  
  *      Adds the socket to the global socket list.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static SocketInfo *  
 NewSocketInfo(socket)  
     SOCKET socket;  
 {  
     SocketInfo *infoPtr;  
     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);  
   
     infoPtr = (SocketInfo *) ckalloc((unsigned) sizeof(SocketInfo));  
     infoPtr->socket = socket;  
     infoPtr->flags = 0;  
     infoPtr->watchEvents = 0;  
     infoPtr->readyEvents = 0;  
     infoPtr->selectEvents = 0;  
     infoPtr->acceptEventCount = 0;  
     infoPtr->acceptProc = NULL;  
     infoPtr->lastError = 0;  
   
     WaitForSingleObject(tsdPtr->socketListLock, INFINITE);  
     infoPtr->nextPtr = tsdPtr->socketList;  
     tsdPtr->socketList = infoPtr;  
     SetEvent(tsdPtr->socketListLock);  
       
     return infoPtr;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * CreateSocket --  
  *  
  *      This function opens a new socket and initializes the  
  *      SocketInfo structure.  
  *  
  * Results:  
  *      Returns a new SocketInfo, or NULL with an error in interp.  
  *  
  * Side effects:  
  *      Adds a new socket to the socketList.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static SocketInfo *  
 CreateSocket(interp, port, host, server, myaddr, myport, async)  
     Tcl_Interp *interp;         /* For error reporting; can be NULL. */  
     int port;                   /* Port number to open. */  
     char *host;                 /* Name of host on which to open port. */  
     int server;                 /* 1 if socket should be a server socket,  
                                  * else 0 for a client socket. */  
     char *myaddr;               /* Optional client-side address */  
     int myport;                 /* Optional client-side port */  
     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 */  
     SOCKET sock;  
     SocketInfo *infoPtr;                /* The returned value. */  
     ThreadSpecificData *tsdPtr =  
         (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);  
   
     /*  
      * Check that WinSock is initialized; do not call it if not, to  
      * prevent system crashes. This can happen at exit time if the exit  
      * handler for WinSock ran before other exit handlers that want to  
      * use sockets.  
      */  
   
     if (!SocketsEnabled()) {  
         return NULL;  
     }  
   
     if (! CreateSocketAddress(&sockaddr, host, port)) {  
         goto error;  
     }  
     if ((myaddr != NULL || myport != 0) &&  
             ! CreateSocketAddress(&mysockaddr, myaddr, myport)) {  
         goto error;  
     }  
   
     sock = (*winSock.socket)(AF_INET, SOCK_STREAM, 0);  
     if (sock == INVALID_SOCKET) {  
         goto error;  
     }  
   
     /*  
      * Win-NT has a misfeature that sockets are inherited in child  
      * processes by default.  Turn off the inherit bit.  
      */  
   
     SetHandleInformation( (HANDLE) sock, HANDLE_FLAG_INHERIT, 0 );  
           
     /*  
      * Set kernel space buffering  
      */  
   
     TclSockMinimumBuffers(sock, TCP_BUFFER_SIZE);  
   
     if (server) {  
         /*  
          * Bind to the specified port.  Note that we must not call setsockopt  
          * with SO_REUSEADDR because Microsoft allows addresses to be reused  
          * even if they are still in use.  
          *  
          * Bind should not be affected by the socket having already been  
          * set into nonblocking mode. If there is trouble, this is one place  
          * to look for bugs.  
          */  
       
         if ((*winSock.bind)(sock, (struct sockaddr *) &sockaddr,  
                 sizeof(sockaddr)) == SOCKET_ERROR) {  
             goto error;  
         }  
   
         /*  
          * Set the maximum number of pending connect requests to the  
          * max value allowed on each platform (Win32 and Win32s may be  
          * different, and there may be differences between TCP/IP stacks).  
          */  
           
         if ((*winSock.listen)(sock, SOMAXCONN) == SOCKET_ERROR) {  
             goto error;  
         }  
   
         /*  
          * Add this socket to the global list of sockets.  
          */  
   
         infoPtr = NewSocketInfo(sock);  
   
         /*  
          * Set up the select mask for connection request events.  
          */  
   
         infoPtr->selectEvents = FD_ACCEPT;  
         infoPtr->watchEvents |= FD_ACCEPT;  
   
     } else {  
   
         /*  
          * Try to bind to a local port, if specified.  
          */  
           
         if (myaddr != NULL || myport != 0) {  
             if ((*winSock.bind)(sock, (struct sockaddr *) &mysockaddr,  
                     sizeof(struct sockaddr)) == SOCKET_ERROR) {  
                 goto error;  
             }  
         }              
       
         /*  
          * Set the socket into nonblocking mode if the connect should be  
          * done in the background.  
          */  
       
         if (async) {  
             if ((*winSock.ioctlsocket)(sock, FIONBIO, &flag) == SOCKET_ERROR) {  
                 goto error;  
             }  
         }  
   
         /*  
          * Attempt to connect to the remote socket.  
          */  
   
         if ((*winSock.connect)(sock, (struct sockaddr *) &sockaddr,  
                 sizeof(sockaddr)) == SOCKET_ERROR) {  
             TclWinConvertWSAError((*winSock.WSAGetLastError)());  
             if (Tcl_GetErrno() != EWOULDBLOCK) {  
                 goto error;  
             }  
   
             /*  
              * The connection is progressing in the background.  
              */  
   
             asyncConnect = 1;  
         }  
   
         /*  
          * Add this socket to the global list of sockets.  
          */  
   
         infoPtr = NewSocketInfo(sock);  
   
         /*  
          * Set up the select mask for read/write events.  If the connect  
          * attempt has not completed, include connect events.  
          */  
   
         infoPtr->selectEvents = FD_READ | FD_WRITE | FD_CLOSE;  
         if (asyncConnect) {  
             infoPtr->flags |= SOCKET_ASYNC_CONNECT;  
             infoPtr->selectEvents |= FD_CONNECT;  
         }  
     }  
   
     /*  
      * Register for interest in events in the select mask.  Note that this  
      * automatically places the socket into non-blocking mode.  
      */  
   
     (*winSock.ioctlsocket)(sock, FIONBIO, &flag);  
     SendMessage(tsdPtr->hwnd, SOCKET_SELECT,  
             (WPARAM) SELECT, (LPARAM) infoPtr);  
   
     return infoPtr;  
   
 error:  
     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);  
     }  
     return NULL;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * CreateSocketAddress --  
  *  
  *      This function initializes a sockaddr structure for a host and port.  
  *  
  * Results:  
  *      1 if the host was valid, 0 if the host could not be converted to  
  *      an IP address.  
  *  
  * Side effects:  
  *      Fills in the *sockaddrPtr structure.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static int  
 CreateSocketAddress(sockaddrPtr, host, port)  
     struct sockaddr_in *sockaddrPtr;    /* Socket address */  
     char *host;                         /* Host.  NULL implies INADDR_ANY */  
     int port;                           /* Port number */  
 {  
     struct hostent *hostent;            /* Host database entry */  
     struct in_addr addr;                /* For 64/32 bit madness */  
   
     /*  
      * 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()) {  
         Tcl_SetErrno(EFAULT);  
         return 0;  
     }  
   
     (void) memset((char *) sockaddrPtr, '\0', sizeof(struct sockaddr_in));  
     sockaddrPtr->sin_family = AF_INET;  
     sockaddrPtr->sin_port = (*winSock.htons)((short) (port & 0xFFFF));  
     if (host == NULL) {  
         addr.s_addr = INADDR_ANY;  
     } else {  
         addr.s_addr = (*winSock.inet_addr)(host);  
         if (addr.s_addr == INADDR_NONE) {  
             hostent = (*winSock.gethostbyname)(host);  
             if (hostent != NULL) {  
                 memcpy((char *) &addr,  
                         (char *) hostent->h_addr_list[0],  
                         (size_t) hostent->h_length);  
             } else {  
 #ifdef  EHOSTUNREACH  
                 Tcl_SetErrno(EHOSTUNREACH);  
 #else  
 #ifdef ENXIO  
                 Tcl_SetErrno(ENXIO);  
 #endif  
 #endif  
                 return 0;       /* Error. */  
             }  
         }  
     }  
   
     /*  
      * NOTE: On 64 bit machines the assignment below is rumored to not  
      * do the right thing. Please report errors related to this if you  
      * observe incorrect behavior on 64 bit machines such as DEC Alphas.  
      * Should we modify this code to do an explicit memcpy?  
      */  
   
     sockaddrPtr->sin_addr.s_addr = addr.s_addr;  
     return 1;   /* Success. */  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * WaitForSocketEvent --  
  *  
  *      Waits until one of the specified events occurs on a socket.  
  *  
  * Results:  
  *      Returns 1 on success or 0 on failure, with an error code in  
  *      errorCodePtr.  
  *  
  * Side effects:  
  *      Processes socket events off the system queue.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static int  
 WaitForSocketEvent(infoPtr, events, errorCodePtr)  
     SocketInfo *infoPtr;        /* Information about this socket. */  
     int events;                 /* Events to look for. */  
     int *errorCodePtr;          /* Where to store errors? */  
 {  
     int result = 1;  
     int oldMode;  
     ThreadSpecificData *tsdPtr =  
         (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);  
   
     /*  
      * Be sure to disable event servicing so we are truly modal.  
      */  
   
     oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE);  
       
     /*  
      * Reset WSAAsyncSelect so we have a fresh set of events pending.  
      */  
   
     SendMessage(tsdPtr->hwnd, SOCKET_SELECT,  
             (WPARAM) UNSELECT, (LPARAM) infoPtr);  
   
     SendMessage(tsdPtr->hwnd, SOCKET_SELECT,  
             (WPARAM) SELECT, (LPARAM) infoPtr);  
   
     while (1) {  
   
         if (infoPtr->lastError) {  
             *errorCodePtr = infoPtr->lastError;  
             result = 0;  
             break;  
         } else if (infoPtr->readyEvents & events) {  
             break;  
         } else if (infoPtr->flags & SOCKET_ASYNC) {  
             *errorCodePtr = EWOULDBLOCK;  
             result = 0;  
             break;  
         }  
   
         /*  
          * Wait until something happens.  
          */  
         WaitForSingleObject(tsdPtr->readyEvent, INFINITE);  
     }  
       
     (void) Tcl_SetServiceMode(oldMode);  
     return result;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_OpenTcpClient --  
  *  
  *      Opens a TCP client socket and creates a channel around it.  
  *  
  * Results:  
  *      The channel or NULL if failed.  An error message is returned  
  *      in the interpreter on failure.  
  *  
  * Side effects:  
  *      Opens a client socket and creates a new channel.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 Tcl_Channel  
 Tcl_OpenTcpClient(interp, port, host, myaddr, myport, async)  
     Tcl_Interp *interp;                 /* For error reporting; can be NULL. */  
     int port;                           /* Port number to open. */  
     char *host;                         /* Host on which to open port. */  
     char *myaddr;                       /* Client-side address */  
     int myport;                         /* Client-side port */  
     int async;                          /* If nonzero, should connect  
                                          * client socket asynchronously. */  
 {  
     SocketInfo *infoPtr;  
     char channelName[16 + TCL_INTEGER_SPACE];  
   
     if (TclpHasSockets(interp) != TCL_OK) {  
         return NULL;  
     }  
   
     /*  
      * Create a new client socket and wrap it in a channel.  
      */  
   
     infoPtr = CreateSocket(interp, port, host, 0, myaddr, myport, async);  
     if (infoPtr == NULL) {  
         return NULL;  
     }  
   
     wsprintfA(channelName, "sock%d", infoPtr->socket);  
   
     infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,  
             (ClientData) infoPtr, (TCL_READABLE | TCL_WRITABLE));  
     if (Tcl_SetChannelOption(interp, infoPtr->channel, "-translation",  
             "auto crlf") == TCL_ERROR) {  
         Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel);  
         return (Tcl_Channel) NULL;  
     }  
     if (Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "")  
             == TCL_ERROR) {  
         Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel);  
         return (Tcl_Channel) NULL;  
     }  
     return infoPtr->channel;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_MakeTcpClientChannel --  
  *  
  *      Creates a Tcl_Channel from an existing client TCP socket.  
  *  
  * Results:  
  *      The Tcl_Channel wrapped around the preexisting TCP socket.  
  *  
  * Side effects:  
  *      None.  
  *  
  * NOTE: Code contributed by Mark Diekhans (markd@grizzly.com)  
  *  
  *----------------------------------------------------------------------  
  */  
   
 Tcl_Channel  
 Tcl_MakeTcpClientChannel(sock)  
     ClientData sock;            /* The socket to wrap up into a channel. */  
 {  
     SocketInfo *infoPtr;  
     char channelName[16 + TCL_INTEGER_SPACE];  
     ThreadSpecificData *tsdPtr;  
   
     if (TclpHasSockets(NULL) != TCL_OK) {  
         return NULL;  
     }  
   
     tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);  
   
     /*  
      * Set kernel space buffering and non-blocking.  
      */  
   
     TclSockMinimumBuffers((SOCKET) sock, TCP_BUFFER_SIZE);  
   
     infoPtr = NewSocketInfo((SOCKET) sock);  
   
     /*  
      * Start watching for read/write events on the socket.  
      */  
   
     infoPtr->selectEvents = FD_READ | FD_CLOSE | FD_WRITE;  
     SendMessage(tsdPtr->hwnd, SOCKET_SELECT,  
             (WPARAM) SELECT, (LPARAM) infoPtr);  
   
     wsprintfA(channelName, "sock%d", infoPtr->socket);  
     infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,  
             (ClientData) infoPtr, (TCL_READABLE | TCL_WRITABLE));  
     Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto crlf");  
     return infoPtr->channel;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_OpenTcpServer --  
  *  
  *      Opens a TCP server socket and creates a channel around it.  
  *  
  * Results:  
  *      The channel or NULL if failed.  An error message is returned  
  *      in the interpreter on failure.  
  *  
  * Side effects:  
  *      Opens a server socket and creates a new channel.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 Tcl_Channel  
 Tcl_OpenTcpServer(interp, port, host, acceptProc, acceptProcData)  
     Tcl_Interp *interp;                 /* For error reporting - may be  
                                          * NULL. */  
     int port;                           /* Port number to open. */  
     char *host;                         /* Name of local host. */  
     Tcl_TcpAcceptProc *acceptProc;      /* Callback for accepting connections  
                                          * from new clients. */  
     ClientData acceptProcData;          /* Data for the callback. */  
 {  
     SocketInfo *infoPtr;  
     char channelName[16 + TCL_INTEGER_SPACE];  
   
     if (TclpHasSockets(interp) != TCL_OK) {  
         return NULL;  
     }  
   
     /*  
      * Create a new client socket and wrap it in a channel.  
      */  
   
     infoPtr = CreateSocket(interp, port, host, 1, NULL, 0, 0);  
     if (infoPtr == NULL) {  
         return NULL;  
     }  
   
     infoPtr->acceptProc = acceptProc;  
     infoPtr->acceptProcData = acceptProcData;  
   
     wsprintfA(channelName, "sock%d", infoPtr->socket);  
   
     infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,  
             (ClientData) infoPtr, 0);  
     if (Tcl_SetChannelOption(interp, infoPtr->channel, "-eofchar", "")  
             == TCL_ERROR) {  
         Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel);  
         return (Tcl_Channel) NULL;  
     }  
   
     return infoPtr->channel;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * TcpAccept --  
  *      Accept a TCP socket connection.  This is called by  
  *      SocketEventProc and it in turns calls the registered accept  
  *      procedure.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      Invokes the accept proc which may invoke arbitrary Tcl code.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static void  
 TcpAccept(infoPtr)  
     SocketInfo *infoPtr;        /* Socket to accept. */  
 {  
     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.  
      */  
   
     len = sizeof(struct sockaddr_in);  
   
     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.  
      */  
       
     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);  
     newInfoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,  
             (ClientData) newInfoPtr, (TCL_READABLE | TCL_WRITABLE));  
     if (Tcl_SetChannelOption(NULL, newInfoPtr->channel, "-translation",  
             "auto crlf") == TCL_ERROR) {  
         Tcl_Close((Tcl_Interp *) NULL, newInfoPtr->channel);  
         return;  
     }  
     if (Tcl_SetChannelOption(NULL, newInfoPtr->channel, "-eofchar", "")  
             == TCL_ERROR) {  
         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));  
     }  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * TcpInputProc --  
  *  
  *      This procedure is called by the generic IO level to read data from  
  *      a socket based channel.  
  *  
  * Results:  
  *      The number of bytes read or -1 on error.  
  *  
  * Side effects:  
  *      Consumes input from the socket.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static int  
 TcpInputProc(instanceData, buf, toRead, errorCodePtr)  
     ClientData instanceData;            /* The socket state. */  
     char *buf;                          /* Where to store data. */  
     int toRead;                         /* Maximum number of bytes to read. */  
     int *errorCodePtr;                  /* Where to store error codes. */  
 {  
     SocketInfo *infoPtr = (SocketInfo *) instanceData;  
     int bytesRead;  
     int error;  
     ThreadSpecificData *tsdPtr =  
         (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);  
       
     *errorCodePtr = 0;  
   
     /*  
      * 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()) {  
         *errorCodePtr = EFAULT;  
         return -1;  
     }  
   
     /*  
      * First check to see if EOF was already detected, to prevent  
      * calling the socket stack after the first time EOF is detected.  
      */  
   
     if (infoPtr->flags & SOCKET_EOF) {  
         return 0;  
     }  
   
     /*  
      * Check to see if the socket is connected before trying to read.  
      */  
   
     if ((infoPtr->flags & SOCKET_ASYNC_CONNECT)  
             && ! WaitForSocketEvent(infoPtr,  FD_CONNECT, errorCodePtr)) {  
         return -1;  
     }  
       
     /*  
      * No EOF, and it is connected, so try to read more from the socket.  
      * Note that we clear the FD_READ bit because read events are level  
      * triggered so a new event will be generated if there is still data  
      * available to be read.  We have to simulate blocking behavior here  
      * since we are always using non-blocking sockets.  
      */  
   
     while (1) {  
         SendMessage(tsdPtr->hwnd, SOCKET_SELECT,  
                 (WPARAM) UNSELECT, (LPARAM) infoPtr);  
         bytesRead = (*winSock.recv)(infoPtr->socket, buf, toRead, 0);  
         infoPtr->readyEvents &= ~(FD_READ);  
     
         /*  
          * Check for end-of-file condition or successful read.  
          */  
     
         if (bytesRead == 0) {  
             infoPtr->flags |= SOCKET_EOF;  
         }  
         if (bytesRead != SOCKET_ERROR) {  
             break;  
         }  
     
         /*  
          * If an error occurs after the FD_CLOSE has arrived,  
          * then ignore the error and report an EOF.  
          */  
     
         if (infoPtr->readyEvents & FD_CLOSE) {  
             infoPtr->flags |= SOCKET_EOF;  
             bytesRead = 0;  
             break;  
         }  
     
         /*  
          * Check for error condition or underflow in non-blocking case.  
          */  
     
         error = (*winSock.WSAGetLastError)();  
         if ((infoPtr->flags & SOCKET_ASYNC) || (error != WSAEWOULDBLOCK)) {  
             TclWinConvertWSAError(error);  
             *errorCodePtr = Tcl_GetErrno();  
             bytesRead = -1;  
             break;  
         }  
   
         /*  
          * In the blocking case, wait until the file becomes readable  
          * or closed and try again.  
          */  
   
         if (!WaitForSocketEvent(infoPtr, FD_READ|FD_CLOSE, errorCodePtr)) {  
             bytesRead = -1;  
             break;  
         }  
     }  
       
     SendMessage(tsdPtr->hwnd, SOCKET_SELECT,  
             (WPARAM) SELECT, (LPARAM) infoPtr);  
       
     return bytesRead;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * TcpOutputProc --  
  *  
  *      This procedure is called by the generic IO level to write data  
  *      to a socket based channel.  
  *  
  * Results:  
  *      The number of bytes written or -1 on failure.  
  *  
  * Side effects:  
  *      Produces output on the socket.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static int  
 TcpOutputProc(instanceData, buf, toWrite, errorCodePtr)  
     ClientData instanceData;            /* The socket state. */  
     char *buf;                          /* Where to get data. */  
     int toWrite;                        /* Maximum number of bytes to write. */  
     int *errorCodePtr;                  /* Where to store error codes. */  
 {  
     SocketInfo *infoPtr = (SocketInfo *) instanceData;  
     int bytesWritten;  
     int error;  
     ThreadSpecificData *tsdPtr =  
         (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);  
   
     *errorCodePtr = 0;  
   
     /*  
      * 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()) {  
         *errorCodePtr = EFAULT;  
         return -1;  
     }  
   
     /*  
      * Check to see if the socket is connected before trying to write.  
      */  
       
     if ((infoPtr->flags & SOCKET_ASYNC_CONNECT)  
             && ! WaitForSocketEvent(infoPtr,  FD_CONNECT, errorCodePtr)) {  
         return -1;  
     }  
   
     while (1) {  
         SendMessage(tsdPtr->hwnd, SOCKET_SELECT,  
                 (WPARAM) UNSELECT, (LPARAM) infoPtr);  
   
         bytesWritten = (*winSock.send)(infoPtr->socket, buf, toWrite, 0);  
         if (bytesWritten != SOCKET_ERROR) {  
             /*  
              * Since Windows won't generate a new write event until we hit  
              * an overflow condition, we need to force the event loop to  
              * poll until the condition changes.  
              */  
   
             if (infoPtr->watchEvents & FD_WRITE) {  
                 Tcl_Time blockTime = { 0, 0 };  
                 Tcl_SetMaxBlockTime(&blockTime);  
             }            
             break;  
         }  
           
         /*  
          * Check for error condition or overflow.  In the event of overflow, we  
          * need to clear the FD_WRITE flag so we can detect the next writable  
          * event.  Note that Windows only sends a new writable event after a  
          * send fails with WSAEWOULDBLOCK.  
          */  
   
         error = (*winSock.WSAGetLastError)();  
         if (error == WSAEWOULDBLOCK) {  
             infoPtr->readyEvents &= ~(FD_WRITE);  
             if (infoPtr->flags & SOCKET_ASYNC) {  
                 *errorCodePtr = EWOULDBLOCK;  
                 bytesWritten = -1;  
                 break;  
             }  
         } else {  
             TclWinConvertWSAError(error);  
             *errorCodePtr = Tcl_GetErrno();  
             bytesWritten = -1;  
             break;  
         }  
   
         /*  
          * In the blocking case, wait until the file becomes writable  
          * or closed and try again.  
          */  
   
         if (!WaitForSocketEvent(infoPtr, FD_WRITE|FD_CLOSE, errorCodePtr)) {  
             bytesWritten = -1;  
             break;  
         }  
     }  
   
     SendMessage(tsdPtr->hwnd, SOCKET_SELECT,  
             (WPARAM) SELECT, (LPARAM) infoPtr);  
       
     return bytesWritten;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * TcpGetOptionProc --  
  *  
  *      Computes an option value for a TCP socket based channel, or a  
  *      list of all options and their values.  
  *  
  *      Note: This code is based on code contributed by John Haxby.  
  *  
  * Results:  
  *      A standard Tcl result. The value of the specified option or a  
  *      list of all options and their values is returned in the  
  *      supplied DString.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static int  
 TcpGetOptionProc(instanceData, interp, optionName, dsPtr)  
     ClientData instanceData;            /* Socket state. */  
     Tcl_Interp *interp;                 /* For error reporting - can be NULL */  
     char *optionName;                   /* Name of the option to  
                                          * retrieve the value for, or  
                                          * NULL to get all options and  
                                          * their values. */  
     Tcl_DString *dsPtr;                 /* Where to store the computed  
                                          * value; initialized by caller. */  
 {  
     SocketInfo *infoPtr;  
     struct sockaddr_in sockname;  
     struct sockaddr_in peername;  
     struct hostent *hostEntPtr;  
     SOCKET sock;  
     int size = sizeof(struct sockaddr_in);  
     size_t len = 0;  
     char buf[TCL_INTEGER_SPACE];  
   
     /*  
      * 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 = (int) infoPtr->socket;  
     if (optionName != (char *) NULL) {  
         len = strlen(optionName);  
     }  
   
     if ((len > 1) && (optionName[1] == 'e') &&  
             (strncmp(optionName, "-error", len) == 0)) {  
         int optlen;  
         int err, ret;  
       
         optlen = sizeof(int);  
         ret = TclWinGetSockOpt(sock, SOL_SOCKET, SO_ERROR,  
                 (char *)&err, &optlen);  
         if (ret == SOCKET_ERROR) {  
             err = (*winSock.WSAGetLastError)();  
         }  
         if (err) {  
             TclWinConvertWSAError(err);  
             Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(Tcl_GetErrno()), -1);  
         }  
         return TCL_OK;  
     }  
   
     if ((len == 0) ||  
             ((len > 1) && (optionName[1] == 'p') &&  
                     (strncmp(optionName, "-peername", len) == 0))) {  
         if ((*winSock.getpeername)(sock, (struct sockaddr *) &peername, &size)  
                 == 0) {  
             if (len == 0) {  
                 Tcl_DStringAppendElement(dsPtr, "-peername");  
                 Tcl_DStringStartSublist(dsPtr);  
             }  
             Tcl_DStringAppendElement(dsPtr,  
                     (*winSock.inet_ntoa)(peername.sin_addr));  
             hostEntPtr = (*winSock.gethostbyaddr)(  
                 (char *) &(peername.sin_addr), sizeof(peername.sin_addr),  
                 AF_INET);  
             if (hostEntPtr != (struct hostent *) NULL) {  
                 Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name);  
             } else {  
                 Tcl_DStringAppendElement(dsPtr,  
                         (*winSock.inet_ntoa)(peername.sin_addr));  
             }  
             TclFormatInt(buf, (*winSock.ntohs)(peername.sin_port));  
             Tcl_DStringAppendElement(dsPtr, buf);  
             if (len == 0) {  
                 Tcl_DStringEndSublist(dsPtr);  
             } else {  
                 return TCL_OK;  
             }  
         } else {  
             /*  
              * getpeername failed - but if we were asked for all the options  
              * (len==0), don't flag an error at that point because it could  
              * be an fconfigure request on a server socket. (which have  
              * no peer). {copied from unix/tclUnixChan.c}  
              */  
             if (len) {  
                 TclWinConvertWSAError((*winSock.WSAGetLastError)());  
                 if (interp) {  
                     Tcl_AppendResult(interp, "can't get peername: ",  
                                      Tcl_PosixError(interp),  
                                      (char *) NULL);  
                 }  
                 return TCL_ERROR;  
             }  
         }  
     }  
   
     if ((len == 0) ||  
             ((len > 1) && (optionName[1] == 's') &&  
                     (strncmp(optionName, "-sockname", len) == 0))) {  
         if ((*winSock.getsockname)(sock, (struct sockaddr *) &sockname, &size)  
                 == 0) {  
             if (len == 0) {  
                 Tcl_DStringAppendElement(dsPtr, "-sockname");  
                 Tcl_DStringStartSublist(dsPtr);  
             }  
             Tcl_DStringAppendElement(dsPtr,  
                     (*winSock.inet_ntoa)(sockname.sin_addr));  
             hostEntPtr = (*winSock.gethostbyaddr)(  
                 (char *) &(sockname.sin_addr), sizeof(peername.sin_addr),  
                 AF_INET);  
             if (hostEntPtr != (struct hostent *) NULL) {  
                 Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name);  
             } else {  
                 Tcl_DStringAppendElement(dsPtr,  
                         (*winSock.inet_ntoa)(sockname.sin_addr));  
             }  
             TclFormatInt(buf, (*winSock.ntohs)(sockname.sin_port));  
             Tcl_DStringAppendElement(dsPtr, buf);  
             if (len == 0) {  
                 Tcl_DStringEndSublist(dsPtr);  
             } else {  
                 return TCL_OK;  
             }  
         } else {  
             if (interp) {  
                 TclWinConvertWSAError((*winSock.WSAGetLastError)());  
                 Tcl_AppendResult(interp, "can't get sockname: ",  
                                  Tcl_PosixError(interp),  
                                  (char *) NULL);  
             }  
             return TCL_ERROR;  
         }  
     }  
   
     if (len > 0) {  
         return Tcl_BadChannelOption(interp, optionName, "peername sockname");  
     }  
   
     return TCL_OK;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * TcpWatchProc --  
  *  
  *      Informs the channel driver of the events that the generic  
  *      channel code wishes to receive on this socket.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      May cause the notifier to poll if any of the specified  
  *      conditions are already true.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static void  
 TcpWatchProc(instanceData, mask)  
     ClientData instanceData;            /* The socket state. */  
     int mask;                           /* Events of interest; an OR-ed  
                                          * combination of TCL_READABLE,  
                                          * TCL_WRITABLE and TCL_EXCEPTION. */  
 {  
     SocketInfo *infoPtr = (SocketInfo *) instanceData;  
       
     /*  
      * Update the watch events mask.  
      */  
       
     infoPtr->watchEvents = 0;  
     if (mask & TCL_READABLE) {  
         infoPtr->watchEvents |= (FD_READ|FD_CLOSE|FD_ACCEPT);  
     }  
     if (mask & TCL_WRITABLE) {  
         infoPtr->watchEvents |= (FD_WRITE|FD_CONNECT);  
     }  
   
     /*  
      * If there are any conditions already set, then tell the notifier to poll  
      * rather than block.  
      */  
   
     if (infoPtr->readyEvents & infoPtr->watchEvents) {  
         Tcl_Time blockTime = { 0, 0 };  
         Tcl_SetMaxBlockTime(&blockTime);  
     }            
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * TcpGetProc --  
  *  
  *      Called from Tcl_GetChannelHandle to retrieve an OS handle from inside  
  *      a TCP socket based channel.  
  *  
  * Results:  
  *      Returns TCL_OK with the socket in handlePtr.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static int  
 TcpGetHandleProc(instanceData, direction, handlePtr)  
     ClientData instanceData;    /* The socket state. */  
     int direction;              /* Not used. */  
     ClientData *handlePtr;      /* Where to store the handle.  */  
 {  
     SocketInfo *statePtr = (SocketInfo *) instanceData;  
   
     *handlePtr = (ClientData) statePtr->socket;  
     return TCL_OK;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * SocketThread --  
  *  
  *      Helper thread used to manage the socket event handling window.  
  *  
  * Results:  
  *      1 if unable to create socket event window, 0 otherwise.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static DWORD WINAPI  
 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);  
   
     /*  
      * Signal the main thread that the window has been created  
      * and that the socket thread is ready to go.  
      */  
       
     SetEvent(tsdPtr->readyEvent);  
       
     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) tsdPtr);  
 #else  
         SetWindowLong(tsdPtr->hwnd, GWL_USERDATA, (LONG) tsdPtr);  
 #endif  
     }  
   
     while (1) {  
         /*  
          * Process all outstanding messages on the socket window.  
          */  
   
         while (PeekMessage(&msg, tsdPtr->hwnd, 0, 0, PM_REMOVE)) {  
             DispatchMessage(&msg);  
         }  
         WaitMessage();  
     }  
 }  
   
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * SocketProc --  
  *  
  *      This function is called when WSAAsyncSelect has been used  
  *      to register interest in a socket event, and the event has  
  *      occurred.  
  *  
  * Results:  
  *      0 on success.  
  *  
  * Side effects:  
  *      The flags for the given socket are updated to reflect the  
  *      event that occured.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static LRESULT CALLBACK  
 SocketProc(hwnd, message, wParam, lParam)  
     HWND hwnd;  
     UINT message;  
     WPARAM wParam;  
     LPARAM lParam;  
 {  
     int event, error;  
     SOCKET socket;  
     SocketInfo *infoPtr;  
     ThreadSpecificData *tsdPtr =  
 #ifdef _WIN64  
         (ThreadSpecificData *) GetWindowLongPtr(hwnd, GWLP_USERDATA);  
 #else  
         (ThreadSpecificData *) GetWindowLong(hwnd, GWL_USERDATA);  
 #endif  
   
     switch (message) {  
   
         default:  
             return DefWindowProc(hwnd, message, wParam, lParam);  
             break;  
               
         case SOCKET_MESSAGE:  
             event = WSAGETSELECTEVENT(lParam);  
             error = WSAGETSELECTERROR(lParam);  
             socket = (SOCKET) wParam;  
   
             /*  
              * Find the specified socket on the socket list and update its  
              * eventState flag.  
              */  
   
             WaitForSingleObject(tsdPtr->socketListLock, INFINITE);  
             for (infoPtr = tsdPtr->socketList; infoPtr != NULL;  
                  infoPtr = infoPtr->nextPtr) {  
                 if (infoPtr->socket == socket) {  
                     /*  
                      * Update the socket state.  
                      */  
   
                     /*  
                      * A count of FD_ACCEPTS is stored, so if an FD_CLOSE event  
                      * happens, then clear the FD_ACCEPT count.  Otherwise,  
                      * increment the count if the current event is and  
                      * FD_ACCEPT.  
                      */  
                       
                     if (event & FD_CLOSE) {  
                         infoPtr->acceptEventCount = 0;  
                         infoPtr->readyEvents &= ~(FD_WRITE|FD_ACCEPT);  
                     } else if (event & FD_ACCEPT) {  
                         infoPtr->acceptEventCount++;  
                     }  
   
                     if (event & FD_CONNECT) {  
                         /*  
                          * 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);  
                         if (error != ERROR_SUCCESS) {  
                             TclWinConvertWSAError(error);  
                             infoPtr->lastError = Tcl_GetErrno();  
                         }  
                         infoPtr->readyEvents |= FD_WRITE;  
                     }  
                     infoPtr->readyEvents |= event;  
   
                     /*  
                      * Wake up the Main Thread.  
                      */  
                     SetEvent(tsdPtr->readyEvent);  
                     Tcl_ThreadAlert(tsdPtr->threadId);  
                     break;  
                 }  
             }  
             SetEvent(tsdPtr->socketListLock);  
             break;  
         case SOCKET_SELECT:  
             infoPtr = (SocketInfo *) lParam;  
             if (wParam == SELECT) {  
   
                 (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, hwnd,  
                         SOCKET_MESSAGE, infoPtr->selectEvents);  
             } else {  
                 /*  
                  * Clear the selection mask  
                  */  
                   
                 (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, hwnd, 0, 0);  
             }  
             break;  
         case SOCKET_TERMINATE:  
             ExitThread(0);  
             break;  
     }  
   
     return 0;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * Tcl_GetHostName --  
  *  
  *      Returns the name of the local host.  
  *  
  * Results:  
  *      A string containing the network name for this machine, or  
  *      an empty string if we can't figure out the name.  The caller  
  *      must not modify or free this string.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 char *  
 Tcl_GetHostName()  
 {  
     DWORD length;  
     WCHAR wbuf[MAX_COMPUTERNAME_LENGTH + 1];  
   
     Tcl_MutexLock(&socketMutex);  
     InitSockets();  
   
     if (hostnameInitialized) {  
         Tcl_MutexUnlock(&socketMutex);  
         return hostname;  
     }  
     Tcl_MutexUnlock(&socketMutex);  
           
     if (TclpHasSockets(NULL) == TCL_OK) {  
         /*  
          * INTL: bug  
          */  
   
         if ((*winSock.gethostname)(hostname, sizeof(hostname)) == 0) {  
             Tcl_MutexLock(&socketMutex);  
             hostnameInitialized = 1;  
             Tcl_MutexUnlock(&socketMutex);  
             return hostname;  
         }  
     }  
     Tcl_MutexLock(&socketMutex);  
     length = sizeof(hostname);  
     if ((*tclWinProcs->getComputerNameProc)(wbuf, &length) != 0) {  
         /*  
          * Convert string from native to UTF then change to lowercase.  
          */  
   
         Tcl_DString ds;  
   
         lstrcpynA(hostname, Tcl_WinTCharToUtf((TCHAR *) wbuf, -1, &ds),  
                 sizeof(hostname));  
         Tcl_DStringFree(&ds);  
         Tcl_UtfToLower(hostname);  
     } else {  
         hostname[0] = '\0';  
     }  
     hostnameInitialized = 1;  
     Tcl_MutexUnlock(&socketMutex);  
     return hostname;  
 }  
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * TclWinGetSockOpt, et al. --  
  *  
  *      These functions are wrappers that let us bind the WinSock  
  *      API dynamically so we can run on systems that don't have  
  *      the wsock32.dll.  We need wrappers for these interfaces  
  *      because they are called from the generic Tcl code.  
  *  
  * Results:  
  *      As defined for each function.  
  *  
  * Side effects:  
  *      As defined for each function.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 int  
 TclWinGetSockOpt(SOCKET s, int level, int optname, char * optval,  
         int FAR *optlen)  
 {  
     /*  
      * Check that WinSock is initialized; do not call it if not, to  
      * prevent system crashes. This can happen at exit time if the exit  
      * handler for WinSock ran before other exit handlers that want to  
      * use sockets.  
      */  
   
     if (!SocketsEnabled()) {  
         return SOCKET_ERROR;  
     }  
       
     return (*winSock.getsockopt)(s, level, optname, optval, optlen);  
 }  
   
 int  
 TclWinSetSockOpt(SOCKET s, int level, int optname, const char * optval,  
         int optlen)  
 {  
     /*  
      * Check that WinSock is initialized; do not call it if not, to  
      * prevent system crashes. This can happen at exit time if the exit  
      * handler for WinSock ran before other exit handlers that want to  
      * use sockets.  
      */  
     if (!SocketsEnabled()) {  
         return SOCKET_ERROR;  
     }  
   
     return (*winSock.setsockopt)(s, level, optname, optval, optlen);  
 }  
   
 u_short  
 TclWinNToHS(u_short netshort)  
 {  
     /*  
      * Check that WinSock is initialized; do not call it if not, to  
      * prevent system crashes. This can happen at exit time if the exit  
      * handler for WinSock ran before other exit handlers that want to  
      * use sockets.  
      */  
   
     if (!SocketsEnabled()) {  
         return (u_short) -1;  
     }  
   
     return (*winSock.ntohs)(netshort);  
 }  
   
 struct servent *  
 TclWinGetServByName(const char * name, const char * proto)  
 {  
     /*  
      * Check that WinSock is initialized; do not call it if not, to  
      * prevent system crashes. This can happen at exit time if the exit  
      * handler for WinSock ran before other exit handlers that want to  
      * use sockets.  
      */  
     if (!SocketsEnabled()) {  
         return (struct servent *) NULL;  
     }  
   
     return (*winSock.getservbyname)(name, proto);  
 }  
   
 /* $History: tclwinsock.c $  
  *  
  * *****************  Version 1  *****************  
  * User: Dtashley     Date: 1/02/01    Time: 12:26a  
  * Created in $/IjuScripter, IjuConsole/Source/Tcl Base  
  * Initial check-in.  
  */  
   
 /* End of TCLWINSOCK.C */  
1    /* $Header$ */
2    /*
3     * tclWinSock.c --
4     *
5     *      This file contains Windows-specific socket related code.
6     *
7     * Copyright (c) 1995-1997 Sun Microsystems, Inc.
8     *
9     * See the file "license.terms" for information on usage and redistribution
10     * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11     *
12     * RCS: @(#) $Id: tclwinsock.c,v 1.1.1.1 2001/06/13 04:50:36 dtashley Exp $
13     */
14    
15    #include "tclWinInt.h"
16    
17    /*
18     * The following variable is used to tell whether this module has been
19     * initialized.
20     */
21    
22    static int initialized = 0;
23    
24    static int  hostnameInitialized = 0;
25    static char hostname[255];      /* This buffer should be big enough for
26                                     * hostname plus domain name. */
27    
28    TCL_DECLARE_MUTEX(socketMutex)
29    
30    /*
31     * The following structure contains pointers to all of the WinSock API entry
32     * points used by Tcl.  It is initialized by InitSockets.  Since we
33     * dynamically load Winsock.dll on demand, we must use this function table
34     * to refer to functions in the socket API.
35     */
36    
37    static struct {
38        HINSTANCE hInstance;        /* Handle to WinSock library. */
39        SOCKET (PASCAL FAR *accept)(SOCKET s, struct sockaddr FAR *addr,
40                int FAR *addrlen);
41        int (PASCAL FAR *bind)(SOCKET s, const struct sockaddr FAR *addr,
42                int namelen);
43        int (PASCAL FAR *closesocket)(SOCKET s);
44        int (PASCAL FAR *connect)(SOCKET s, const struct sockaddr FAR *name,
45                int namelen);
46        int (PASCAL FAR *ioctlsocket)(SOCKET s, long cmd, u_long FAR *argp);
47        int (PASCAL FAR *getsockopt)(SOCKET s, int level, int optname,
48                char FAR * optval, int FAR *optlen);
49        u_short (PASCAL FAR *htons)(u_short hostshort);
50        unsigned long (PASCAL FAR *inet_addr)(const char FAR * cp);
51        char FAR * (PASCAL FAR *inet_ntoa)(struct in_addr in);
52        int (PASCAL FAR *listen)(SOCKET s, int backlog);
53        u_short (PASCAL FAR *ntohs)(u_short netshort);
54        int (PASCAL FAR *recv)(SOCKET s, char FAR * buf, int len, int flags);
55        int (PASCAL FAR *select)(int nfds, fd_set FAR * readfds,
56                fd_set FAR * writefds, fd_set FAR * exceptfds,
57                const struct timeval FAR * tiemout);
58        int (PASCAL FAR *send)(SOCKET s, const char FAR * buf, int len, int flags);
59        int (PASCAL FAR *setsockopt)(SOCKET s, int level, int optname,
60                const char FAR * optval, int optlen);
61        int (PASCAL FAR *shutdown)(SOCKET s, int how);
62        SOCKET (PASCAL FAR *socket)(int af, int type, int protocol);
63        struct hostent FAR * (PASCAL FAR *gethostbyname)(const char FAR * name);
64        struct hostent FAR * (PASCAL FAR *gethostbyaddr)(const char FAR *addr,
65                int addrlen, int addrtype);
66        int (PASCAL FAR *gethostname)(char FAR * name, int namelen);
67        int (PASCAL FAR *getpeername)(SOCKET sock, struct sockaddr FAR *name,
68                int FAR *namelen);
69        struct servent FAR * (PASCAL FAR *getservbyname)(const char FAR * name,
70                const char FAR * proto);
71        int (PASCAL FAR *getsockname)(SOCKET sock, struct sockaddr FAR *name,
72                int FAR *namelen);
73        int (PASCAL FAR *WSAStartup)(WORD wVersionRequired, LPWSADATA lpWSAData);
74        int (PASCAL FAR *WSACleanup)(void);
75        int (PASCAL FAR *WSAGetLastError)(void);
76        int (PASCAL FAR *WSAAsyncSelect)(SOCKET s, HWND hWnd, u_int wMsg,
77                long lEvent);
78    } winSock;
79    
80    /*
81     * The following defines declare the messages used on socket windows.
82     */
83    
84    #define SOCKET_MESSAGE  WM_USER+1
85    #define SOCKET_SELECT   WM_USER+2
86    #define SOCKET_TERMINATE WM_USER+3
87    #define SELECT          TRUE
88    #define UNSELECT        FALSE
89    
90    /*
91     * The following structure is used to store the data associated with
92     * each socket.
93     */
94    
95    typedef struct SocketInfo {
96        Tcl_Channel channel;           /* Channel associated with this socket. */
97        SOCKET socket;                 /* Windows SOCKET handle. */
98        int flags;                     /* Bit field comprised of the flags
99                                        * described below.  */
100        int watchEvents;               /* OR'ed combination of FD_READ, FD_WRITE,
101                                        * FD_CLOSE, FD_ACCEPT and FD_CONNECT that
102                                        * indicate which events are interesting. */
103        int readyEvents;               /* OR'ed combination of FD_READ, FD_WRITE,
104                                        * FD_CLOSE, FD_ACCEPT and FD_CONNECT that
105                                        * indicate which events have occurred. */
106        int selectEvents;              /* OR'ed combination of FD_READ, FD_WRITE,
107                                        * FD_CLOSE, FD_ACCEPT and FD_CONNECT that
108                                        * indicate which events are currently
109                                        * being selected. */
110        int acceptEventCount;          /* Count of the current number of FD_ACCEPTs
111                                        * that have arrived and not processed. */
112        Tcl_TcpAcceptProc *acceptProc; /* Proc to call on accept. */
113        ClientData acceptProcData;     /* The data for the accept proc. */
114        int lastError;                 /* Error code from last message. */
115        struct SocketInfo *nextPtr;    /* The next socket on the global socket
116                                        * list. */
117    } SocketInfo;
118    
119    /*
120     * The following structure is what is added to the Tcl event queue when
121     * a socket event occurs.
122     */
123    
124    typedef struct SocketEvent {
125        Tcl_Event header;           /* Information that is standard for
126                                     * all events. */
127        SOCKET socket;              /* Socket descriptor that is ready.  Used
128                                     * to find the SocketInfo structure for
129                                     * the file (can't point directly to the
130                                     * SocketInfo structure because it could
131                                     * go away while the event is queued). */
132    } SocketEvent;
133    
134    /*
135     * This defines the minimum buffersize maintained by the kernel.
136     */
137    
138    #define TCP_BUFFER_SIZE 4096
139    
140    /*
141     * The following macros may be used to set the flags field of
142     * a SocketInfo structure.
143     */
144    
145    #define SOCKET_ASYNC            (1<<0)  /* The socket is in blocking mode. */
146    #define SOCKET_EOF              (1<<1)  /* A zero read happened on
147                                             * the socket. */
148    #define SOCKET_ASYNC_CONNECT    (1<<2)  /* This socket uses async connect. */
149    #define SOCKET_PENDING          (1<<3)  /* A message has been sent
150                                             * for this socket */
151    
152    typedef struct ThreadSpecificData {
153        /*
154         * Every open socket has an entry on the following list.
155         */
156        
157        HWND hwnd;              /* Handle to window for socket messages. */
158        HANDLE socketThread;    /* Thread handling the window */
159        Tcl_ThreadId threadId;  /* Parent thread. */
160        HANDLE readyEvent;      /* Event indicating that a socket event is ready.
161                                 * Also used to indicate that the socketThread has
162                                 * been initialized and has started. */
163        HANDLE socketListLock;  /* Win32 Event to lock the socketList */
164        SocketInfo *socketList;
165    } ThreadSpecificData;
166    
167    static Tcl_ThreadDataKey dataKey;
168    static WNDCLASSA windowClass;
169    
170    /*
171     * Static functions defined in this file.
172     */
173    
174    static SocketInfo *     CreateSocket _ANSI_ARGS_((Tcl_Interp *interp,
175                                int port, char *host, int server, char *myaddr,
176                                int myport, int async));
177    static int              CreateSocketAddress _ANSI_ARGS_(
178                                (struct sockaddr_in *sockaddrPtr,
179                                char *host, int port));
180    static void             InitSockets _ANSI_ARGS_((void));
181    static SocketInfo *     NewSocketInfo _ANSI_ARGS_((SOCKET socket));
182    static void             SocketCheckProc _ANSI_ARGS_((ClientData clientData,
183                                int flags));
184    static int              SocketEventProc _ANSI_ARGS_((Tcl_Event *evPtr,
185                                int flags));
186    static void             SocketExitHandler _ANSI_ARGS_((ClientData clientData));
187    static LRESULT CALLBACK SocketProc _ANSI_ARGS_((HWND hwnd, UINT message,
188                                WPARAM wParam, LPARAM lParam));
189    static void             SocketSetupProc _ANSI_ARGS_((ClientData clientData,
190                                int flags));
191    static void             SocketThreadExitHandler _ANSI_ARGS_((ClientData clientData));
192    static int              SocketsEnabled _ANSI_ARGS_((void));
193    static void             TcpAccept _ANSI_ARGS_((SocketInfo *infoPtr));
194    static int              TcpBlockProc _ANSI_ARGS_((ClientData instanceData,
195                                int mode));
196    static int              TcpCloseProc _ANSI_ARGS_((ClientData instanceData,
197                                Tcl_Interp *interp));
198    static int              TcpGetOptionProc _ANSI_ARGS_((ClientData instanceData,
199                                Tcl_Interp *interp, char *optionName,
200                                Tcl_DString *optionValue));
201    static int              TcpInputProc _ANSI_ARGS_((ClientData instanceData,
202                                char *buf, int toRead, int *errorCode));
203    static int              TcpOutputProc _ANSI_ARGS_((ClientData instanceData,
204                                char *buf, int toWrite, int *errorCode));
205    static void             TcpWatchProc _ANSI_ARGS_((ClientData instanceData,
206                                int mask));
207    static int              TcpGetHandleProc _ANSI_ARGS_((ClientData instanceData,
208                                int direction, ClientData *handlePtr));
209    static int              WaitForSocketEvent _ANSI_ARGS_((SocketInfo *infoPtr,
210                                int events, int *errorCodePtr));
211    static DWORD WINAPI     SocketThread _ANSI_ARGS_((LPVOID arg));
212    
213    /*
214     * This structure describes the channel type structure for TCP socket
215     * based IO.
216     */
217    
218    static Tcl_ChannelType tcpChannelType = {
219        "tcp",              /* Type name. */
220        TcpBlockProc,       /* Set socket into blocking/non-blocking mode. */
221        TcpCloseProc,       /* Close proc. */
222        TcpInputProc,       /* Input proc. */
223        TcpOutputProc,      /* Output proc. */
224        NULL,               /* Seek proc. */
225        NULL,               /* Set option proc. */
226        TcpGetOptionProc,   /* Get option proc. */
227        TcpWatchProc,       /* Initialize notifier to watch this channel. */
228        TcpGetHandleProc,   /* Get an OS handle from channel. */
229    };
230    
231    /*
232     * Define version of Winsock required by Tcl.
233     */
234    
235    #define WSA_VERSION_REQD MAKEWORD(1,1)
236    
237    /*
238     *----------------------------------------------------------------------
239     *
240     * InitSockets --
241     *
242     *      Initialize the socket module.  Attempts to load the wsock32.dll
243     *      library and set up the winSock function table.  If successful,
244     *      registers the event window for the socket notifier code.
245     *
246     *      Assumes Mutex is held.
247     *
248     * Results:
249     *      None.
250     *
251     * Side effects:
252     *      Dynamically loads wsock32.dll, and registers a new window
253     *      class and creates a window for use in asynchronous socket
254     *      notification.
255     *
256     *----------------------------------------------------------------------
257     */
258    
259    static void
260    InitSockets()
261    {
262        DWORD id;
263        WSADATA wsaData;
264        ThreadSpecificData *tsdPtr =
265            (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
266    
267        if (! initialized) {
268            initialized = 1;
269            Tcl_CreateExitHandler(SocketExitHandler, (ClientData) NULL);
270    
271            winSock.hInstance = LoadLibraryA("wsock32.dll");
272    
273            /*
274             * Initialize the function table.
275             */
276    
277            if (!SocketsEnabled()) {
278                return;
279            }
280        
281            winSock.accept = (SOCKET (PASCAL FAR *)(SOCKET s,
282                    struct sockaddr FAR *addr, int FAR *addrlen))
283                GetProcAddress(winSock.hInstance, "accept");
284            winSock.bind = (int (PASCAL FAR *)(SOCKET s,
285                    const struct sockaddr FAR *addr, int namelen))
286                GetProcAddress(winSock.hInstance, "bind");
287            winSock.closesocket = (int (PASCAL FAR *)(SOCKET s))
288                GetProcAddress(winSock.hInstance, "closesocket");
289            winSock.connect = (int (PASCAL FAR *)(SOCKET s,
290                    const struct sockaddr FAR *name, int namelen))
291                GetProcAddress(winSock.hInstance, "connect");
292            winSock.ioctlsocket = (int (PASCAL FAR *)(SOCKET s, long cmd,
293                    u_long FAR *argp))
294                GetProcAddress(winSock.hInstance, "ioctlsocket");
295            winSock.getsockopt = (int (PASCAL FAR *)(SOCKET s,
296                    int level, int optname, char FAR * optval, int FAR *optlen))
297                GetProcAddress(winSock.hInstance, "getsockopt");
298            winSock.htons = (u_short (PASCAL FAR *)(u_short hostshort))
299                GetProcAddress(winSock.hInstance, "htons");
300            winSock.inet_addr = (unsigned long (PASCAL FAR *)(const char FAR *cp))
301                GetProcAddress(winSock.hInstance, "inet_addr");
302            winSock.inet_ntoa = (char FAR * (PASCAL FAR *)(struct in_addr in))
303                GetProcAddress(winSock.hInstance, "inet_ntoa");
304            winSock.listen = (int (PASCAL FAR *)(SOCKET s, int backlog))
305                GetProcAddress(winSock.hInstance, "listen");
306            winSock.ntohs = (u_short (PASCAL FAR *)(u_short netshort))
307                GetProcAddress(winSock.hInstance, "ntohs");
308            winSock.recv = (int (PASCAL FAR *)(SOCKET s, char FAR * buf,
309                    int len, int flags)) GetProcAddress(winSock.hInstance, "recv");
310            winSock.select = (int (PASCAL FAR *)(int nfds, fd_set FAR * readfds,
311                    fd_set FAR * writefds, fd_set FAR * exceptfds,
312                    const struct timeval FAR * tiemout))
313                GetProcAddress(winSock.hInstance, "select");
314            winSock.send = (int (PASCAL FAR *)(SOCKET s, const char FAR * buf,
315                    int len, int flags)) GetProcAddress(winSock.hInstance, "send");
316            winSock.setsockopt = (int (PASCAL FAR *)(SOCKET s, int level,
317                    int optname, const char FAR * optval, int optlen))
318                GetProcAddress(winSock.hInstance, "setsockopt");
319            winSock.shutdown = (int (PASCAL FAR *)(SOCKET s, int how))
320                GetProcAddress(winSock.hInstance, "shutdown");
321            winSock.socket = (SOCKET (PASCAL FAR *)(int af, int type,
322                    int protocol)) GetProcAddress(winSock.hInstance, "socket");
323            winSock.gethostbyaddr = (struct hostent FAR * (PASCAL FAR *)
324                    (const char FAR *addr, int addrlen, int addrtype))
325                GetProcAddress(winSock.hInstance, "gethostbyaddr");
326            winSock.gethostbyname = (struct hostent FAR * (PASCAL FAR *)
327                    (const char FAR *name))
328                GetProcAddress(winSock.hInstance, "gethostbyname");
329            winSock.gethostname = (int (PASCAL FAR *)(char FAR * name,
330                    int namelen)) GetProcAddress(winSock.hInstance, "gethostname");
331            winSock.getpeername = (int (PASCAL FAR *)(SOCKET sock,
332                    struct sockaddr FAR *name, int FAR *namelen))
333                GetProcAddress(winSock.hInstance, "getpeername");
334            winSock.getservbyname = (struct servent FAR * (PASCAL FAR *)
335                    (const char FAR * name, const char FAR * proto))
336                GetProcAddress(winSock.hInstance, "getservbyname");
337            winSock.getsockname = (int (PASCAL FAR *)(SOCKET sock,
338                    struct sockaddr FAR *name, int FAR *namelen))
339                GetProcAddress(winSock.hInstance, "getsockname");
340            winSock.WSAStartup = (int (PASCAL FAR *)(WORD wVersionRequired,
341                    LPWSADATA lpWSAData)) GetProcAddress(winSock.hInstance, "WSAStartup");
342            winSock.WSACleanup = (int (PASCAL FAR *)(void))
343                GetProcAddress(winSock.hInstance, "WSACleanup");
344            winSock.WSAGetLastError = (int (PASCAL FAR *)(void))
345                GetProcAddress(winSock.hInstance, "WSAGetLastError");
346            winSock.WSAAsyncSelect = (int (PASCAL FAR *)(SOCKET s, HWND hWnd,
347                    u_int wMsg, long lEvent))
348                GetProcAddress(winSock.hInstance, "WSAAsyncSelect");
349        
350            /*
351             * Now check that all fields are properly initialized. If not, return
352             * zero to indicate that we failed to initialize properly.
353             */
354        
355            if ((winSock.hInstance == NULL) ||
356                    (winSock.accept == NULL) ||
357                    (winSock.bind == NULL) ||
358                    (winSock.closesocket == NULL) ||
359                    (winSock.connect == NULL) ||
360                    (winSock.ioctlsocket == NULL) ||
361                    (winSock.getsockopt == NULL) ||
362                    (winSock.htons == NULL) ||
363                    (winSock.inet_addr == NULL) ||
364                    (winSock.inet_ntoa == NULL) ||
365                    (winSock.listen == NULL) ||
366                    (winSock.ntohs == NULL) ||
367                    (winSock.recv == NULL) ||
368                    (winSock.select == NULL) ||
369                    (winSock.send == NULL) ||
370                    (winSock.setsockopt == NULL) ||
371                    (winSock.socket == NULL) ||
372                    (winSock.gethostbyname == NULL) ||
373                    (winSock.gethostbyaddr == NULL) ||
374                    (winSock.gethostname == NULL) ||
375                    (winSock.getpeername == NULL) ||
376                    (winSock.getservbyname == NULL) ||
377                    (winSock.getsockname == NULL) ||
378                    (winSock.WSAStartup == NULL) ||
379                    (winSock.WSACleanup == NULL) ||
380                    (winSock.WSAGetLastError == NULL) ||
381                    (winSock.WSAAsyncSelect == NULL)) {
382                goto unloadLibrary;
383            }
384            
385            /*
386             * Create the async notification window with a new class.  We
387             * must create a new class to avoid a Windows 95 bug that causes
388             * us to get the wrong message number for socket events if the
389             * message window is a subclass of a static control.
390             */
391        
392            windowClass.style = 0;
393            windowClass.cbClsExtra = 0;
394            windowClass.cbWndExtra = 0;
395            windowClass.hInstance = TclWinGetTclInstance();
396            windowClass.hbrBackground = NULL;
397            windowClass.lpszMenuName = NULL;
398            windowClass.lpszClassName = "TclSocket";
399            windowClass.lpfnWndProc = SocketProc;
400            windowClass.hIcon = NULL;
401            windowClass.hCursor = NULL;
402    
403            if (!RegisterClassA(&windowClass)) {
404                TclWinConvertError(GetLastError());
405                (*winSock.WSACleanup)();
406                goto unloadLibrary;
407            }
408            
409            /*
410             * Initialize the winsock library and check the version number.
411             */
412        
413            if ((*winSock.WSAStartup)(WSA_VERSION_REQD, &wsaData) != 0) {
414                goto unloadLibrary;
415            }
416            if (wsaData.wVersion != WSA_VERSION_REQD) {
417                (*winSock.WSACleanup)();
418                goto unloadLibrary;
419            }
420        }
421    
422        /*
423         * Check for per-thread initialization.
424         */
425    
426        if (tsdPtr == NULL) {
427            tsdPtr = TCL_TSD_INIT(&dataKey);
428            tsdPtr->socketList = NULL;
429            tsdPtr->hwnd = NULL;
430    
431            tsdPtr->threadId = Tcl_GetCurrentThread();
432            
433            tsdPtr->readyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
434            tsdPtr->socketListLock = CreateEvent(NULL, FALSE, TRUE, NULL);
435            tsdPtr->socketThread = CreateThread(NULL, 8000, SocketThread,
436                    tsdPtr, 0, &id);
437            SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST);
438    
439            if (tsdPtr->socketThread == NULL) {
440                goto unloadLibrary;
441            }
442            
443    
444            /*
445             * Wait for the thread to signal that the window has
446             * been created and is ready to go.  Timeout after twenty
447             * seconds.
448             */
449            
450            if (WaitForSingleObject(tsdPtr->readyEvent, 20000) == WAIT_TIMEOUT) {
451                goto unloadLibrary;
452            }
453    
454            if (tsdPtr->hwnd == NULL) {
455                goto unloadLibrary;
456            }
457            
458            Tcl_CreateEventSource(SocketSetupProc, SocketCheckProc, NULL);
459            Tcl_CreateThreadExitHandler(SocketThreadExitHandler, NULL);
460        }
461        return;
462    
463    unloadLibrary:
464        if (tsdPtr != NULL) {
465            if (tsdPtr->hwnd != NULL) {
466                DestroyWindow(tsdPtr->hwnd);
467            }
468            if (tsdPtr->socketThread != NULL) {
469                TerminateThread(tsdPtr->socketThread, 0);
470                tsdPtr->socketThread = NULL;
471            }
472            CloseHandle(tsdPtr->readyEvent);
473            CloseHandle(tsdPtr->socketListLock);
474        }
475        FreeLibrary(winSock.hInstance);
476        winSock.hInstance = NULL;
477        return;
478    }
479    
480    /*
481     *----------------------------------------------------------------------
482     *
483     * SocketsEnabled --
484     *
485     *      Check that the WinSock DLL is loaded and ready.
486     *
487     * Results:
488     *      1 if it is.
489     *
490     * Side effects:
491     *      None.
492     *
493     *----------------------------------------------------------------------
494     */
495    
496        /* ARGSUSED */
497    static int
498    SocketsEnabled()
499    {
500        int enabled;
501        Tcl_MutexLock(&socketMutex);
502        enabled = (winSock.hInstance != NULL);
503        Tcl_MutexUnlock(&socketMutex);
504        return enabled;
505    }
506    
507    
508    /*
509     *----------------------------------------------------------------------
510     *
511     * SocketExitHandler --
512     *
513     *      Callback invoked during exit clean up to delete the socket
514     *      communication window and to release the WinSock DLL.
515     *
516     * Results:
517     *      None.
518     *
519     * Side effects:
520     *      None.
521     *
522     *----------------------------------------------------------------------
523     */
524    
525        /* ARGSUSED */
526    static void
527    SocketExitHandler(clientData)
528        ClientData clientData;              /* Not used. */
529    {
530        Tcl_MutexLock(&socketMutex);
531        if (winSock.hInstance) {
532            UnregisterClassA("TclSocket", TclWinGetTclInstance());
533            (*winSock.WSACleanup)();
534            FreeLibrary(winSock.hInstance);
535            winSock.hInstance = NULL;
536        }
537        initialized = 0;
538        hostnameInitialized = 0;
539        Tcl_MutexUnlock(&socketMutex);
540    }
541    
542    /*
543     *----------------------------------------------------------------------
544     *
545     * SocketThreadExitHandler --
546     *
547     *      Callback invoked during thread clean up to delete the socket
548     *      event source.
549     *
550     * Results:
551     *      None.
552     *
553     * Side effects:
554     *      Delete the event source.
555     *
556     *----------------------------------------------------------------------
557     */
558    
559        /* ARGSUSED */
560    static void
561    SocketThreadExitHandler(clientData)
562        ClientData clientData;              /* Not used. */
563    {
564        ThreadSpecificData *tsdPtr =
565            (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
566    
567        if (tsdPtr->socketThread != NULL) {
568    
569            PostMessage(tsdPtr->hwnd, SOCKET_TERMINATE, 0, 0);
570    
571            /*
572             * Wait for the thread to terminate.  This ensures that we are
573             * completely cleaned up before we leave this function.
574             */
575    
576            WaitForSingleObject(tsdPtr->socketThread, INFINITE);
577            CloseHandle(tsdPtr->socketThread);
578            CloseHandle(tsdPtr->readyEvent);
579            CloseHandle(tsdPtr->socketListLock);
580    
581        }
582        if (tsdPtr->hwnd != NULL) {
583            DestroyWindow(tsdPtr->hwnd);
584        }
585        
586        Tcl_DeleteEventSource(SocketSetupProc, SocketCheckProc, NULL);
587    }
588    
589    /*
590     *----------------------------------------------------------------------
591     *
592     * TclpHasSockets --
593     *
594     *      This function determines whether sockets are available on the
595     *      current system and returns an error in interp if they are not.
596     *      Note that interp may be NULL.
597     *
598     * Results:
599     *      Returns TCL_OK if the system supports sockets, or TCL_ERROR with
600     *      an error in interp.
601     *
602     * Side effects:
603     *      None.
604     *
605     *----------------------------------------------------------------------
606     */
607    
608    int
609    TclpHasSockets(interp)
610        Tcl_Interp *interp;
611    {
612        Tcl_MutexLock(&socketMutex);
613        InitSockets();
614        Tcl_MutexUnlock(&socketMutex);
615    
616        if (SocketsEnabled()) {
617            return TCL_OK;
618        }
619        if (interp != NULL) {
620            Tcl_AppendResult(interp, "sockets are not available on this system",
621                    NULL);
622        }
623        return TCL_ERROR;
624    }
625    
626    /*
627     *----------------------------------------------------------------------
628     *
629     * SocketSetupProc --
630     *
631     *      This procedure is invoked before Tcl_DoOneEvent blocks waiting
632     *      for an event.
633     *
634     * Results:
635     *      None.
636     *
637     * Side effects:
638     *      Adjusts the block time if needed.
639     *
640     *----------------------------------------------------------------------
641     */
642    
643    void
644    SocketSetupProc(data, flags)
645        ClientData data;            /* Not used. */
646        int flags;                  /* Event flags as passed to Tcl_DoOneEvent. */
647    {
648        SocketInfo *infoPtr;
649        Tcl_Time blockTime = { 0, 0 };
650        ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
651    
652        if (!(flags & TCL_FILE_EVENTS)) {
653            return;
654        }
655        
656        /*
657         * Check to see if there is a ready socket.  If so, poll.
658         */
659    
660        WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
661        for (infoPtr = tsdPtr->socketList; infoPtr != NULL;
662                infoPtr = infoPtr->nextPtr) {
663            if (infoPtr->readyEvents & infoPtr->watchEvents) {
664                Tcl_SetMaxBlockTime(&blockTime);
665                break;
666            }
667        }
668        SetEvent(tsdPtr->socketListLock);
669    }
670    
671    /*
672     *----------------------------------------------------------------------
673     *
674     * SocketCheckProc --
675     *
676     *      This procedure is called by Tcl_DoOneEvent to check the socket
677     *      event source for events.
678     *
679     * Results:
680     *      None.
681     *
682     * Side effects:
683     *      May queue an event.
684     *
685     *----------------------------------------------------------------------
686     */
687    
688    static void
689    SocketCheckProc(data, flags)
690        ClientData data;            /* Not used. */
691        int flags;                  /* Event flags as passed to Tcl_DoOneEvent. */
692    {
693        SocketInfo *infoPtr;
694        SocketEvent *evPtr;
695        ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
696    
697        if (!(flags & TCL_FILE_EVENTS)) {
698            return;
699        }
700        
701        /*
702         * Queue events for any ready sockets that don't already have events
703         * queued (caused by persistent states that won't generate WinSock
704         * events).
705         */
706    
707        WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
708        for (infoPtr = tsdPtr->socketList; infoPtr != NULL;
709                infoPtr = infoPtr->nextPtr) {
710            if ((infoPtr->readyEvents & infoPtr->watchEvents)
711                    && !(infoPtr->flags & SOCKET_PENDING)) {
712                infoPtr->flags |= SOCKET_PENDING;
713                evPtr = (SocketEvent *) ckalloc(sizeof(SocketEvent));
714                evPtr->header.proc = SocketEventProc;
715                evPtr->socket = infoPtr->socket;
716                Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
717            }
718        }
719        SetEvent(tsdPtr->socketListLock);
720    }
721    
722    /*
723     *----------------------------------------------------------------------
724     *
725     * SocketEventProc --
726     *
727     *      This procedure is called by Tcl_ServiceEvent when a socket event
728     *      reaches the front of the event queue.  This procedure is
729     *      responsible for notifying the generic channel code.
730     *
731     * Results:
732     *      Returns 1 if the event was handled, meaning it should be removed
733     *      from the queue.  Returns 0 if the event was not handled, meaning
734     *      it should stay on the queue.  The only time the event isn't
735     *      handled is if the TCL_FILE_EVENTS flag bit isn't set.
736     *
737     * Side effects:
738     *      Whatever the channel callback procedures do.
739     *
740     *----------------------------------------------------------------------
741     */
742    
743    static int
744    SocketEventProc(evPtr, flags)
745        Tcl_Event *evPtr;           /* Event to service. */
746        int flags;                  /* Flags that indicate what events to
747                                     * handle, such as TCL_FILE_EVENTS. */
748    {
749        SocketInfo *infoPtr;
750        SocketEvent *eventPtr = (SocketEvent *) evPtr;
751        int mask = 0;
752        int events;
753        ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
754    
755        if (!(flags & TCL_FILE_EVENTS)) {
756            return 0;
757        }
758    
759        /*
760         * Find the specified socket on the socket list.
761         */
762    
763        WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
764        for (infoPtr = tsdPtr->socketList; infoPtr != NULL;
765                infoPtr = infoPtr->nextPtr) {
766            if (infoPtr->socket == eventPtr->socket) {
767                break;
768            }
769        }
770        SetEvent(tsdPtr->socketListLock);
771        
772        /*
773         * Discard events that have gone stale.
774         */
775    
776        if (!infoPtr) {
777            return 1;
778        }
779    
780        infoPtr->flags &= ~SOCKET_PENDING;
781    
782        /*
783         * Handle connection requests directly.
784         */
785    
786        if (infoPtr->readyEvents & FD_ACCEPT) {
787            TcpAccept(infoPtr);
788            return 1;
789        }
790    
791    
792        /*
793         * Mask off unwanted events and compute the read/write mask so
794         * we can notify the channel.
795         */
796    
797        events = infoPtr->readyEvents & infoPtr->watchEvents;
798    
799        if (events & FD_CLOSE) {
800            /*
801             * If the socket was closed and the channel is still interested
802             * in read events, then we need to ensure that we keep polling
803             * for this event until someone does something with the channel.
804             * Note that we do this before calling Tcl_NotifyChannel so we don't
805             * have to watch out for the channel being deleted out from under
806             * us.  This may cause a redundant trip through the event loop, but
807             * it's simpler than trying to do unwind protection.
808             */
809    
810            Tcl_Time blockTime = { 0, 0 };
811            Tcl_SetMaxBlockTime(&blockTime);
812            mask |= TCL_READABLE;
813        } else if (events & FD_READ) {
814            fd_set readFds;
815            struct timeval timeout;
816    
817            /*
818             * We must check to see if data is really available, since someone
819             * could have consumed the data in the meantime.  Turn off async
820             * notification so select will work correctly.  If the socket is
821             * still readable, notify the channel driver, otherwise reset the
822             * async select handler and keep waiting.
823             */
824    
825            SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
826                    (WPARAM) UNSELECT, (LPARAM) infoPtr);
827    
828            FD_ZERO(&readFds);
829            FD_SET(infoPtr->socket, &readFds);
830            timeout.tv_usec = 0;
831            timeout.tv_sec = 0;
832    
833            if ((*winSock.select)(0, &readFds, NULL, NULL, &timeout) != 0) {
834                mask |= TCL_READABLE;
835            } else {
836                SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
837                        (WPARAM) SELECT, (LPARAM) infoPtr);
838                infoPtr->readyEvents &= ~(FD_READ);
839            }
840        }
841        if (events & (FD_WRITE | FD_CONNECT)) {
842            mask |= TCL_WRITABLE;
843        }
844    
845        if (mask) {
846            Tcl_NotifyChannel(infoPtr->channel, mask);
847        }
848        return 1;
849    }
850    
851    /*
852     *----------------------------------------------------------------------
853     *
854     * TcpBlockProc --
855     *
856     *      Sets a socket into blocking or non-blocking mode.
857     *
858     * Results:
859     *      0 if successful, errno if there was an error.
860     *
861     * Side effects:
862     *      None.
863     *
864     *----------------------------------------------------------------------
865     */
866    
867    static int
868    TcpBlockProc(instanceData, mode)
869        ClientData  instanceData;   /* The socket to block/un-block. */
870        int mode;                   /* TCL_MODE_BLOCKING or
871                                     * TCL_MODE_NONBLOCKING. */
872    {
873        SocketInfo *infoPtr = (SocketInfo *) instanceData;
874    
875        if (mode == TCL_MODE_NONBLOCKING) {
876            infoPtr->flags |= SOCKET_ASYNC;
877        } else {
878            infoPtr->flags &= ~(SOCKET_ASYNC);
879        }
880        return 0;
881    }
882    
883    /*
884     *----------------------------------------------------------------------
885     *
886     * TcpCloseProc --
887     *
888     *      This procedure is called by the generic IO level to perform
889     *      channel type specific cleanup on a socket based channel
890     *      when the channel is closed.
891     *
892     * Results:
893     *      0 if successful, the value of errno if failed.
894     *
895     * Side effects:
896     *      Closes the socket.
897     *
898     *----------------------------------------------------------------------
899     */
900    
901        /* ARGSUSED */
902    static int
903    TcpCloseProc(instanceData, interp)
904        ClientData instanceData;    /* The socket to close. */
905        Tcl_Interp *interp;         /* Unused. */
906    {
907        SocketInfo *infoPtr = (SocketInfo *) instanceData;
908        SocketInfo **nextPtrPtr;
909        int errorCode = 0;
910        ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
911    
912        /*
913         * Check that WinSock is initialized; do not call it if not, to
914         * prevent system crashes. This can happen at exit time if the exit
915         * handler for WinSock ran before other exit handlers that want to
916         * use sockets.
917         */
918    
919        if (SocketsEnabled()) {
920            
921            /*
922             * Clean up the OS socket handle.  The default Windows setting
923             * for a socket is SO_DONTLINGER, which does a graceful shutdown
924             * in the background.
925             */
926        
927            if ((*winSock.closesocket)(infoPtr->socket) == SOCKET_ERROR) {
928                TclWinConvertWSAError((*winSock.WSAGetLastError)());
929                errorCode = Tcl_GetErrno();
930            }
931        }
932    
933        /*
934         * Remove the socket from socketList.
935         */
936    
937        WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
938        for (nextPtrPtr = &(tsdPtr->socketList); (*nextPtrPtr) != NULL;
939             nextPtrPtr = &((*nextPtrPtr)->nextPtr)) {
940            if ((*nextPtrPtr) == infoPtr) {
941                (*nextPtrPtr) = infoPtr->nextPtr;
942                break;
943            }
944        }
945        SetEvent(tsdPtr->socketListLock);
946        
947        ckfree((char *) infoPtr);
948        return errorCode;
949    }
950    
951    /*
952     *----------------------------------------------------------------------
953     *
954     * NewSocketInfo --
955     *
956     *      This function allocates and initializes a new SocketInfo
957     *      structure.
958     *
959     * Results:
960     *      Returns a newly allocated SocketInfo.
961     *
962     * Side effects:
963     *      Adds the socket to the global socket list.
964     *
965     *----------------------------------------------------------------------
966     */
967    
968    static SocketInfo *
969    NewSocketInfo(socket)
970        SOCKET socket;
971    {
972        SocketInfo *infoPtr;
973        ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
974    
975        infoPtr = (SocketInfo *) ckalloc((unsigned) sizeof(SocketInfo));
976        infoPtr->socket = socket;
977        infoPtr->flags = 0;
978        infoPtr->watchEvents = 0;
979        infoPtr->readyEvents = 0;
980        infoPtr->selectEvents = 0;
981        infoPtr->acceptEventCount = 0;
982        infoPtr->acceptProc = NULL;
983        infoPtr->lastError = 0;
984    
985        WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
986        infoPtr->nextPtr = tsdPtr->socketList;
987        tsdPtr->socketList = infoPtr;
988        SetEvent(tsdPtr->socketListLock);
989        
990        return infoPtr;
991    }
992    
993    /*
994     *----------------------------------------------------------------------
995     *
996     * CreateSocket --
997     *
998     *      This function opens a new socket and initializes the
999     *      SocketInfo structure.
1000     *
1001     * Results:
1002     *      Returns a new SocketInfo, or NULL with an error in interp.
1003     *
1004     * Side effects:
1005     *      Adds a new socket to the socketList.
1006     *
1007     *----------------------------------------------------------------------
1008     */
1009    
1010    static SocketInfo *
1011    CreateSocket(interp, port, host, server, myaddr, myport, async)
1012        Tcl_Interp *interp;         /* For error reporting; can be NULL. */
1013        int port;                   /* Port number to open. */
1014        char *host;                 /* Name of host on which to open port. */
1015        int server;                 /* 1 if socket should be a server socket,
1016                                     * else 0 for a client socket. */
1017        char *myaddr;               /* Optional client-side address */
1018        int myport;                 /* Optional client-side port */
1019        int async;                  /* If nonzero, connect client socket
1020                                     * asynchronously. */
1021    {
1022        u_long flag = 1;                    /* Indicates nonblocking mode. */
1023        int asyncConnect = 0;               /* Will be 1 if async connect is
1024                                             * in progress. */
1025        struct sockaddr_in sockaddr;        /* Socket address */
1026        struct sockaddr_in mysockaddr;      /* Socket address for client */
1027        SOCKET sock;
1028        SocketInfo *infoPtr;                /* The returned value. */
1029        ThreadSpecificData *tsdPtr =
1030            (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
1031    
1032        /*
1033         * Check that WinSock is initialized; do not call it if not, to
1034         * prevent system crashes. This can happen at exit time if the exit
1035         * handler for WinSock ran before other exit handlers that want to
1036         * use sockets.
1037         */
1038    
1039        if (!SocketsEnabled()) {
1040            return NULL;
1041        }
1042    
1043        if (! CreateSocketAddress(&sockaddr, host, port)) {
1044            goto error;
1045        }
1046        if ((myaddr != NULL || myport != 0) &&
1047                ! CreateSocketAddress(&mysockaddr, myaddr, myport)) {
1048            goto error;
1049        }
1050    
1051        sock = (*winSock.socket)(AF_INET, SOCK_STREAM, 0);
1052        if (sock == INVALID_SOCKET) {
1053            goto error;
1054        }
1055    
1056        /*
1057         * Win-NT has a misfeature that sockets are inherited in child
1058         * processes by default.  Turn off the inherit bit.
1059         */
1060    
1061        SetHandleInformation( (HANDLE) sock, HANDLE_FLAG_INHERIT, 0 );
1062            
1063        /*
1064         * Set kernel space buffering
1065         */
1066    
1067        TclSockMinimumBuffers(sock, TCP_BUFFER_SIZE);
1068    
1069        if (server) {
1070            /*
1071             * Bind to the specified port.  Note that we must not call setsockopt
1072             * with SO_REUSEADDR because Microsoft allows addresses to be reused
1073             * even if they are still in use.
1074             *
1075             * Bind should not be affected by the socket having already been
1076             * set into nonblocking mode. If there is trouble, this is one place
1077             * to look for bugs.
1078             */
1079        
1080            if ((*winSock.bind)(sock, (struct sockaddr *) &sockaddr,
1081                    sizeof(sockaddr)) == SOCKET_ERROR) {
1082                goto error;
1083            }
1084    
1085            /*
1086             * Set the maximum number of pending connect requests to the
1087             * max value allowed on each platform (Win32 and Win32s may be
1088             * different, and there may be differences between TCP/IP stacks).
1089             */
1090            
1091            if ((*winSock.listen)(sock, SOMAXCONN) == SOCKET_ERROR) {
1092                goto error;
1093            }
1094    
1095            /*
1096             * Add this socket to the global list of sockets.
1097             */
1098    
1099            infoPtr = NewSocketInfo(sock);
1100    
1101            /*
1102             * Set up the select mask for connection request events.
1103             */
1104    
1105            infoPtr->selectEvents = FD_ACCEPT;
1106            infoPtr->watchEvents |= FD_ACCEPT;
1107    
1108        } else {
1109    
1110            /*
1111             * Try to bind to a local port, if specified.
1112             */
1113            
1114            if (myaddr != NULL || myport != 0) {
1115                if ((*winSock.bind)(sock, (struct sockaddr *) &mysockaddr,
1116                        sizeof(struct sockaddr)) == SOCKET_ERROR) {
1117                    goto error;
1118                }
1119            }            
1120        
1121            /*
1122             * Set the socket into nonblocking mode if the connect should be
1123             * done in the background.
1124             */
1125        
1126            if (async) {
1127                if ((*winSock.ioctlsocket)(sock, FIONBIO, &flag) == SOCKET_ERROR) {
1128                    goto error;
1129                }
1130            }
1131    
1132            /*
1133             * Attempt to connect to the remote socket.
1134             */
1135    
1136            if ((*winSock.connect)(sock, (struct sockaddr *) &sockaddr,
1137                    sizeof(sockaddr)) == SOCKET_ERROR) {
1138                TclWinConvertWSAError((*winSock.WSAGetLastError)());
1139                if (Tcl_GetErrno() != EWOULDBLOCK) {
1140                    goto error;
1141                }
1142    
1143                /*
1144                 * The connection is progressing in the background.
1145                 */
1146    
1147                asyncConnect = 1;
1148            }
1149    
1150            /*
1151             * Add this socket to the global list of sockets.
1152             */
1153    
1154            infoPtr = NewSocketInfo(sock);
1155    
1156            /*
1157             * Set up the select mask for read/write events.  If the connect
1158             * attempt has not completed, include connect events.
1159             */
1160    
1161            infoPtr->selectEvents = FD_READ | FD_WRITE | FD_CLOSE;
1162            if (asyncConnect) {
1163                infoPtr->flags |= SOCKET_ASYNC_CONNECT;
1164                infoPtr->selectEvents |= FD_CONNECT;
1165            }
1166        }
1167    
1168        /*
1169         * Register for interest in events in the select mask.  Note that this
1170         * automatically places the socket into non-blocking mode.
1171         */
1172    
1173        (*winSock.ioctlsocket)(sock, FIONBIO, &flag);
1174        SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
1175                (WPARAM) SELECT, (LPARAM) infoPtr);
1176    
1177        return infoPtr;
1178    
1179    error:
1180        TclWinConvertWSAError((*winSock.WSAGetLastError)());
1181        if (interp != NULL) {
1182            Tcl_AppendResult(interp, "couldn't open socket: ",
1183                    Tcl_PosixError(interp), (char *) NULL);
1184        }
1185        if (sock != INVALID_SOCKET) {
1186            (*winSock.closesocket)(sock);
1187        }
1188        return NULL;
1189    }
1190    
1191    /*
1192     *----------------------------------------------------------------------
1193     *
1194     * CreateSocketAddress --
1195     *
1196     *      This function initializes a sockaddr structure for a host and port.
1197     *
1198     * Results:
1199     *      1 if the host was valid, 0 if the host could not be converted to
1200     *      an IP address.
1201     *
1202     * Side effects:
1203     *      Fills in the *sockaddrPtr structure.
1204     *
1205     *----------------------------------------------------------------------
1206     */
1207    
1208    static int
1209    CreateSocketAddress(sockaddrPtr, host, port)
1210        struct sockaddr_in *sockaddrPtr;    /* Socket address */
1211        char *host;                         /* Host.  NULL implies INADDR_ANY */
1212        int port;                           /* Port number */
1213    {
1214        struct hostent *hostent;            /* Host database entry */
1215        struct in_addr addr;                /* For 64/32 bit madness */
1216    
1217        /*
1218         * Check that WinSock is initialized; do not call it if not, to
1219         * prevent system crashes. This can happen at exit time if the exit
1220         * handler for WinSock ran before other exit handlers that want to
1221         * use sockets.
1222         */
1223    
1224        if (!SocketsEnabled()) {
1225            Tcl_SetErrno(EFAULT);
1226            return 0;
1227        }
1228    
1229        (void) memset((char *) sockaddrPtr, '\0', sizeof(struct sockaddr_in));
1230        sockaddrPtr->sin_family = AF_INET;
1231        sockaddrPtr->sin_port = (*winSock.htons)((short) (port & 0xFFFF));
1232        if (host == NULL) {
1233            addr.s_addr = INADDR_ANY;
1234        } else {
1235            addr.s_addr = (*winSock.inet_addr)(host);
1236            if (addr.s_addr == INADDR_NONE) {
1237                hostent = (*winSock.gethostbyname)(host);
1238                if (hostent != NULL) {
1239                    memcpy((char *) &addr,
1240                            (char *) hostent->h_addr_list[0],
1241                            (size_t) hostent->h_length);
1242                } else {
1243    #ifdef  EHOSTUNREACH
1244                    Tcl_SetErrno(EHOSTUNREACH);
1245    #else
1246    #ifdef ENXIO
1247                    Tcl_SetErrno(ENXIO);
1248    #endif
1249    #endif
1250                    return 0;       /* Error. */
1251                }
1252            }
1253        }
1254    
1255        /*
1256         * NOTE: On 64 bit machines the assignment below is rumored to not
1257         * do the right thing. Please report errors related to this if you
1258         * observe incorrect behavior on 64 bit machines such as DEC Alphas.
1259         * Should we modify this code to do an explicit memcpy?
1260         */
1261    
1262        sockaddrPtr->sin_addr.s_addr = addr.s_addr;
1263        return 1;   /* Success. */
1264    }
1265    
1266    /*
1267     *----------------------------------------------------------------------
1268     *
1269     * WaitForSocketEvent --
1270     *
1271     *      Waits until one of the specified events occurs on a socket.
1272     *
1273     * Results:
1274     *      Returns 1 on success or 0 on failure, with an error code in
1275     *      errorCodePtr.
1276     *
1277     * Side effects:
1278     *      Processes socket events off the system queue.
1279     *
1280     *----------------------------------------------------------------------
1281     */
1282    
1283    static int
1284    WaitForSocketEvent(infoPtr, events, errorCodePtr)
1285        SocketInfo *infoPtr;        /* Information about this socket. */
1286        int events;                 /* Events to look for. */
1287        int *errorCodePtr;          /* Where to store errors? */
1288    {
1289        int result = 1;
1290        int oldMode;
1291        ThreadSpecificData *tsdPtr =
1292            (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
1293    
1294        /*
1295         * Be sure to disable event servicing so we are truly modal.
1296         */
1297    
1298        oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE);
1299        
1300        /*
1301         * Reset WSAAsyncSelect so we have a fresh set of events pending.
1302         */
1303    
1304        SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
1305                (WPARAM) UNSELECT, (LPARAM) infoPtr);
1306    
1307        SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
1308                (WPARAM) SELECT, (LPARAM) infoPtr);
1309    
1310        while (1) {
1311    
1312            if (infoPtr->lastError) {
1313                *errorCodePtr = infoPtr->lastError;
1314                result = 0;
1315                break;
1316            } else if (infoPtr->readyEvents & events) {
1317                break;
1318            } else if (infoPtr->flags & SOCKET_ASYNC) {
1319                *errorCodePtr = EWOULDBLOCK;
1320                result = 0;
1321                break;
1322            }
1323    
1324            /*
1325             * Wait until something happens.
1326             */
1327            WaitForSingleObject(tsdPtr->readyEvent, INFINITE);
1328        }
1329        
1330        (void) Tcl_SetServiceMode(oldMode);
1331        return result;
1332    }
1333    
1334    /*
1335     *----------------------------------------------------------------------
1336     *
1337     * Tcl_OpenTcpClient --
1338     *
1339     *      Opens a TCP client socket and creates a channel around it.
1340     *
1341     * Results:
1342     *      The channel or NULL if failed.  An error message is returned
1343     *      in the interpreter on failure.
1344     *
1345     * Side effects:
1346     *      Opens a client socket and creates a new channel.
1347     *
1348     *----------------------------------------------------------------------
1349     */
1350    
1351    Tcl_Channel
1352    Tcl_OpenTcpClient(interp, port, host, myaddr, myport, async)
1353        Tcl_Interp *interp;                 /* For error reporting; can be NULL. */
1354        int port;                           /* Port number to open. */
1355        char *host;                         /* Host on which to open port. */
1356        char *myaddr;                       /* Client-side address */
1357        int myport;                         /* Client-side port */
1358        int async;                          /* If nonzero, should connect
1359                                             * client socket asynchronously. */
1360    {
1361        SocketInfo *infoPtr;
1362        char channelName[16 + TCL_INTEGER_SPACE];
1363    
1364        if (TclpHasSockets(interp) != TCL_OK) {
1365            return NULL;
1366        }
1367    
1368        /*
1369         * Create a new client socket and wrap it in a channel.
1370         */
1371    
1372        infoPtr = CreateSocket(interp, port, host, 0, myaddr, myport, async);
1373        if (infoPtr == NULL) {
1374            return NULL;
1375        }
1376    
1377        wsprintfA(channelName, "sock%d", infoPtr->socket);
1378    
1379        infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
1380                (ClientData) infoPtr, (TCL_READABLE | TCL_WRITABLE));
1381        if (Tcl_SetChannelOption(interp, infoPtr->channel, "-translation",
1382                "auto crlf") == TCL_ERROR) {
1383            Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel);
1384            return (Tcl_Channel) NULL;
1385        }
1386        if (Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "")
1387                == TCL_ERROR) {
1388            Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel);
1389            return (Tcl_Channel) NULL;
1390        }
1391        return infoPtr->channel;
1392    }
1393    
1394    /*
1395     *----------------------------------------------------------------------
1396     *
1397     * Tcl_MakeTcpClientChannel --
1398     *
1399     *      Creates a Tcl_Channel from an existing client TCP socket.
1400     *
1401     * Results:
1402     *      The Tcl_Channel wrapped around the preexisting TCP socket.
1403     *
1404     * Side effects:
1405     *      None.
1406     *
1407     * NOTE: Code contributed by Mark Diekhans (markd@grizzly.com)
1408     *
1409     *----------------------------------------------------------------------
1410     */
1411    
1412    Tcl_Channel
1413    Tcl_MakeTcpClientChannel(sock)
1414        ClientData sock;            /* The socket to wrap up into a channel. */
1415    {
1416        SocketInfo *infoPtr;
1417        char channelName[16 + TCL_INTEGER_SPACE];
1418        ThreadSpecificData *tsdPtr;
1419    
1420        if (TclpHasSockets(NULL) != TCL_OK) {
1421            return NULL;
1422        }
1423    
1424        tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
1425    
1426        /*
1427         * Set kernel space buffering and non-blocking.
1428         */
1429    
1430        TclSockMinimumBuffers((SOCKET) sock, TCP_BUFFER_SIZE);
1431    
1432        infoPtr = NewSocketInfo((SOCKET) sock);
1433    
1434        /*
1435         * Start watching for read/write events on the socket.
1436         */
1437    
1438        infoPtr->selectEvents = FD_READ | FD_CLOSE | FD_WRITE;
1439        SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
1440                (WPARAM) SELECT, (LPARAM) infoPtr);
1441    
1442        wsprintfA(channelName, "sock%d", infoPtr->socket);
1443        infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
1444                (ClientData) infoPtr, (TCL_READABLE | TCL_WRITABLE));
1445        Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto crlf");
1446        return infoPtr->channel;
1447    }
1448    
1449    /*
1450     *----------------------------------------------------------------------
1451     *
1452     * Tcl_OpenTcpServer --
1453     *
1454     *      Opens a TCP server socket and creates a channel around it.
1455     *
1456     * Results:
1457     *      The channel or NULL if failed.  An error message is returned
1458     *      in the interpreter on failure.
1459     *
1460     * Side effects:
1461     *      Opens a server socket and creates a new channel.
1462     *
1463     *----------------------------------------------------------------------
1464     */
1465    
1466    Tcl_Channel
1467    Tcl_OpenTcpServer(interp, port, host, acceptProc, acceptProcData)
1468        Tcl_Interp *interp;                 /* For error reporting - may be
1469                                             * NULL. */
1470        int port;                           /* Port number to open. */
1471        char *host;                         /* Name of local host. */
1472        Tcl_TcpAcceptProc *acceptProc;      /* Callback for accepting connections
1473                                             * from new clients. */
1474        ClientData acceptProcData;          /* Data for the callback. */
1475    {
1476        SocketInfo *infoPtr;
1477        char channelName[16 + TCL_INTEGER_SPACE];
1478    
1479        if (TclpHasSockets(interp) != TCL_OK) {
1480            return NULL;
1481        }
1482    
1483        /*
1484         * Create a new client socket and wrap it in a channel.
1485         */
1486    
1487        infoPtr = CreateSocket(interp, port, host, 1, NULL, 0, 0);
1488        if (infoPtr == NULL) {
1489            return NULL;
1490        }
1491    
1492        infoPtr->acceptProc = acceptProc;
1493        infoPtr->acceptProcData = acceptProcData;
1494    
1495        wsprintfA(channelName, "sock%d", infoPtr->socket);
1496    
1497        infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
1498                (ClientData) infoPtr, 0);
1499        if (Tcl_SetChannelOption(interp, infoPtr->channel, "-eofchar", "")
1500                == TCL_ERROR) {
1501            Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel);
1502            return (Tcl_Channel) NULL;
1503        }
1504    
1505        return infoPtr->channel;
1506    }
1507    
1508    /*
1509     *----------------------------------------------------------------------
1510     *
1511     * TcpAccept --
1512     *      Accept a TCP socket connection.  This is called by
1513     *      SocketEventProc and it in turns calls the registered accept
1514     *      procedure.
1515     *
1516     * Results:
1517     *      None.
1518     *
1519     * Side effects:
1520     *      Invokes the accept proc which may invoke arbitrary Tcl code.
1521     *
1522     *----------------------------------------------------------------------
1523     */
1524    
1525    static void
1526    TcpAccept(infoPtr)
1527        SocketInfo *infoPtr;        /* Socket to accept. */
1528    {
1529        SOCKET newSocket;
1530        SocketInfo *newInfoPtr;
1531        struct sockaddr_in addr;
1532        int len;
1533        char channelName[16 + TCL_INTEGER_SPACE];
1534        ThreadSpecificData *tsdPtr =
1535            (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
1536    
1537        /*
1538         * Accept the incoming connection request.
1539         */
1540    
1541        len = sizeof(struct sockaddr_in);
1542    
1543        newSocket = (*winSock.accept)(infoPtr->socket,
1544                (struct sockaddr *)&addr,
1545                &len);
1546        
1547        /*
1548         * Clear the ready mask so we can detect the next connection request.
1549         * Note that connection requests are level triggered, so if there is
1550         * a request already pending, a new event will be generated.
1551         */
1552        
1553        if (newSocket == INVALID_SOCKET) {
1554            infoPtr->acceptEventCount = 0;
1555            infoPtr->readyEvents &= ~(FD_ACCEPT);
1556            return;
1557        }
1558    
1559        /*
1560         * It is possible that more than one FD_ACCEPT has been sent, so an extra
1561         * count must be kept.  Decrement the count, and reset the readyEvent bit
1562         * if the count is no longer > 0.
1563         */
1564        
1565        infoPtr->acceptEventCount--;
1566    
1567        if (infoPtr->acceptEventCount <= 0) {
1568            infoPtr->readyEvents &= ~(FD_ACCEPT);
1569        }
1570    
1571        /*
1572         * Win-NT has a misfeature that sockets are inherited in child
1573         * processes by default.  Turn off the inherit bit.
1574         */
1575        
1576        SetHandleInformation( (HANDLE) newSocket, HANDLE_FLAG_INHERIT, 0 );
1577        
1578        /*
1579         * Add this socket to the global list of sockets.
1580         */
1581        
1582        newInfoPtr = NewSocketInfo(newSocket);
1583        
1584        /*
1585         * Select on read/write events and create the channel.
1586         */
1587        
1588        newInfoPtr->selectEvents = (FD_READ | FD_WRITE | FD_CLOSE);
1589        SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
1590                (WPARAM) SELECT, (LPARAM) newInfoPtr);
1591        
1592        wsprintfA(channelName, "sock%d", newInfoPtr->socket);
1593        newInfoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
1594                (ClientData) newInfoPtr, (TCL_READABLE | TCL_WRITABLE));
1595        if (Tcl_SetChannelOption(NULL, newInfoPtr->channel, "-translation",
1596                "auto crlf") == TCL_ERROR) {
1597            Tcl_Close((Tcl_Interp *) NULL, newInfoPtr->channel);
1598            return;
1599        }
1600        if (Tcl_SetChannelOption(NULL, newInfoPtr->channel, "-eofchar", "")
1601                == TCL_ERROR) {
1602            Tcl_Close((Tcl_Interp *) NULL, newInfoPtr->channel);
1603            return;
1604        }
1605        
1606        /*
1607         * Invoke the accept callback procedure.
1608         */
1609        
1610        if (infoPtr->acceptProc != NULL) {
1611            (infoPtr->acceptProc) (infoPtr->acceptProcData,
1612                    newInfoPtr->channel,
1613                    (*winSock.inet_ntoa)(addr.sin_addr),
1614                    (*winSock.ntohs)(addr.sin_port));
1615        }
1616    }
1617    
1618    /*
1619     *----------------------------------------------------------------------
1620     *
1621     * TcpInputProc --
1622     *
1623     *      This procedure is called by the generic IO level to read data from
1624     *      a socket based channel.
1625     *
1626     * Results:
1627     *      The number of bytes read or -1 on error.
1628     *
1629     * Side effects:
1630     *      Consumes input from the socket.
1631     *
1632     *----------------------------------------------------------------------
1633     */
1634    
1635    static int
1636    TcpInputProc(instanceData, buf, toRead, errorCodePtr)
1637        ClientData instanceData;            /* The socket state. */
1638        char *buf;                          /* Where to store data. */
1639        int toRead;                         /* Maximum number of bytes to read. */
1640        int *errorCodePtr;                  /* Where to store error codes. */
1641    {
1642        SocketInfo *infoPtr = (SocketInfo *) instanceData;
1643        int bytesRead;
1644        int error;
1645        ThreadSpecificData *tsdPtr =
1646            (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
1647        
1648        *errorCodePtr = 0;
1649    
1650        /*
1651         * Check that WinSock is initialized; do not call it if not, to
1652         * prevent system crashes. This can happen at exit time if the exit
1653         * handler for WinSock ran before other exit handlers that want to
1654         * use sockets.
1655         */
1656    
1657        if (!SocketsEnabled()) {
1658            *errorCodePtr = EFAULT;
1659            return -1;
1660        }
1661    
1662        /*
1663         * First check to see if EOF was already detected, to prevent
1664         * calling the socket stack after the first time EOF is detected.
1665         */
1666    
1667        if (infoPtr->flags & SOCKET_EOF) {
1668            return 0;
1669        }
1670    
1671        /*
1672         * Check to see if the socket is connected before trying to read.
1673         */
1674    
1675        if ((infoPtr->flags & SOCKET_ASYNC_CONNECT)
1676                && ! WaitForSocketEvent(infoPtr,  FD_CONNECT, errorCodePtr)) {
1677            return -1;
1678        }
1679        
1680        /*
1681         * No EOF, and it is connected, so try to read more from the socket.
1682         * Note that we clear the FD_READ bit because read events are level
1683         * triggered so a new event will be generated if there is still data
1684         * available to be read.  We have to simulate blocking behavior here
1685         * since we are always using non-blocking sockets.
1686         */
1687    
1688        while (1) {
1689            SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
1690                    (WPARAM) UNSELECT, (LPARAM) infoPtr);
1691            bytesRead = (*winSock.recv)(infoPtr->socket, buf, toRead, 0);
1692            infoPtr->readyEvents &= ~(FD_READ);
1693      
1694            /*
1695             * Check for end-of-file condition or successful read.
1696             */
1697      
1698            if (bytesRead == 0) {
1699                infoPtr->flags |= SOCKET_EOF;
1700            }
1701            if (bytesRead != SOCKET_ERROR) {
1702                break;
1703            }
1704      
1705            /*
1706             * If an error occurs after the FD_CLOSE has arrived,
1707             * then ignore the error and report an EOF.
1708             */
1709      
1710            if (infoPtr->readyEvents & FD_CLOSE) {
1711                infoPtr->flags |= SOCKET_EOF;
1712                bytesRead = 0;
1713                break;
1714            }
1715      
1716            /*
1717             * Check for error condition or underflow in non-blocking case.
1718             */
1719      
1720            error = (*winSock.WSAGetLastError)();
1721            if ((infoPtr->flags & SOCKET_ASYNC) || (error != WSAEWOULDBLOCK)) {
1722                TclWinConvertWSAError(error);
1723                *errorCodePtr = Tcl_GetErrno();
1724                bytesRead = -1;
1725                break;
1726            }
1727    
1728            /*
1729             * In the blocking case, wait until the file becomes readable
1730             * or closed and try again.
1731             */
1732    
1733            if (!WaitForSocketEvent(infoPtr, FD_READ|FD_CLOSE, errorCodePtr)) {
1734                bytesRead = -1;
1735                break;
1736            }
1737        }
1738        
1739        SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
1740                (WPARAM) SELECT, (LPARAM) infoPtr);
1741        
1742        return bytesRead;
1743    }
1744    
1745    /*
1746     *----------------------------------------------------------------------
1747     *
1748     * TcpOutputProc --
1749     *
1750     *      This procedure is called by the generic IO level to write data
1751     *      to a socket based channel.
1752     *
1753     * Results:
1754     *      The number of bytes written or -1 on failure.
1755     *
1756     * Side effects:
1757     *      Produces output on the socket.
1758     *
1759     *----------------------------------------------------------------------
1760     */
1761    
1762    static int
1763    TcpOutputProc(instanceData, buf, toWrite, errorCodePtr)
1764        ClientData instanceData;            /* The socket state. */
1765        char *buf;                          /* Where to get data. */
1766        int toWrite;                        /* Maximum number of bytes to write. */
1767        int *errorCodePtr;                  /* Where to store error codes. */
1768    {
1769        SocketInfo *infoPtr = (SocketInfo *) instanceData;
1770        int bytesWritten;
1771        int error;
1772        ThreadSpecificData *tsdPtr =
1773            (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
1774    
1775        *errorCodePtr = 0;
1776    
1777        /*
1778         * Check that WinSock is initialized; do not call it if not, to
1779         * prevent system crashes. This can happen at exit time if the exit
1780         * handler for WinSock ran before other exit handlers that want to
1781         * use sockets.
1782         */
1783    
1784        if (!SocketsEnabled()) {
1785            *errorCodePtr = EFAULT;
1786            return -1;
1787        }
1788    
1789        /*
1790         * Check to see if the socket is connected before trying to write.
1791         */
1792        
1793        if ((infoPtr->flags & SOCKET_ASYNC_CONNECT)
1794                && ! WaitForSocketEvent(infoPtr,  FD_CONNECT, errorCodePtr)) {
1795            return -1;
1796        }
1797    
1798        while (1) {
1799            SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
1800                    (WPARAM) UNSELECT, (LPARAM) infoPtr);
1801    
1802            bytesWritten = (*winSock.send)(infoPtr->socket, buf, toWrite, 0);
1803            if (bytesWritten != SOCKET_ERROR) {
1804                /*
1805                 * Since Windows won't generate a new write event until we hit
1806                 * an overflow condition, we need to force the event loop to
1807                 * poll until the condition changes.
1808                 */
1809    
1810                if (infoPtr->watchEvents & FD_WRITE) {
1811                    Tcl_Time blockTime = { 0, 0 };
1812                    Tcl_SetMaxBlockTime(&blockTime);
1813                }          
1814                break;
1815            }
1816            
1817            /*
1818             * Check for error condition or overflow.  In the event of overflow, we
1819             * need to clear the FD_WRITE flag so we can detect the next writable
1820             * event.  Note that Windows only sends a new writable event after a
1821             * send fails with WSAEWOULDBLOCK.
1822             */
1823    
1824            error = (*winSock.WSAGetLastError)();
1825            if (error == WSAEWOULDBLOCK) {
1826                infoPtr->readyEvents &= ~(FD_WRITE);
1827                if (infoPtr->flags & SOCKET_ASYNC) {
1828                    *errorCodePtr = EWOULDBLOCK;
1829                    bytesWritten = -1;
1830                    break;
1831                }
1832            } else {
1833                TclWinConvertWSAError(error);
1834                *errorCodePtr = Tcl_GetErrno();
1835                bytesWritten = -1;
1836                break;
1837            }
1838    
1839            /*
1840             * In the blocking case, wait until the file becomes writable
1841             * or closed and try again.
1842             */
1843    
1844            if (!WaitForSocketEvent(infoPtr, FD_WRITE|FD_CLOSE, errorCodePtr)) {
1845                bytesWritten = -1;
1846                break;
1847            }
1848        }
1849    
1850        SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
1851                (WPARAM) SELECT, (LPARAM) infoPtr);
1852        
1853        return bytesWritten;
1854    }
1855    
1856    /*
1857     *----------------------------------------------------------------------
1858     *
1859     * TcpGetOptionProc --
1860     *
1861     *      Computes an option value for a TCP socket based channel, or a
1862     *      list of all options and their values.
1863     *
1864     *      Note: This code is based on code contributed by John Haxby.
1865     *
1866     * Results:
1867     *      A standard Tcl result. The value of the specified option or a
1868     *      list of all options and their values is returned in the
1869     *      supplied DString.
1870     *
1871     * Side effects:
1872     *      None.
1873     *
1874     *----------------------------------------------------------------------
1875     */
1876    
1877    static int
1878    TcpGetOptionProc(instanceData, interp, optionName, dsPtr)
1879        ClientData instanceData;            /* Socket state. */
1880        Tcl_Interp *interp;                 /* For error reporting - can be NULL */
1881        char *optionName;                   /* Name of the option to
1882                                             * retrieve the value for, or
1883                                             * NULL to get all options and
1884                                             * their values. */
1885        Tcl_DString *dsPtr;                 /* Where to store the computed
1886                                             * value; initialized by caller. */
1887    {
1888        SocketInfo *infoPtr;
1889        struct sockaddr_in sockname;
1890        struct sockaddr_in peername;
1891        struct hostent *hostEntPtr;
1892        SOCKET sock;
1893        int size = sizeof(struct sockaddr_in);
1894        size_t len = 0;
1895        char buf[TCL_INTEGER_SPACE];
1896    
1897        /*
1898         * Check that WinSock is initialized; do not call it if not, to
1899         * prevent system crashes. This can happen at exit time if the exit
1900         * handler for WinSock ran before other exit handlers that want to
1901         * use sockets.
1902         */
1903    
1904        if (!SocketsEnabled()) {
1905            if (interp) {
1906                Tcl_AppendResult(interp, "winsock is not initialized", NULL);
1907            }
1908            return TCL_ERROR;
1909        }
1910        
1911        infoPtr = (SocketInfo *) instanceData;
1912        sock = (int) infoPtr->socket;
1913        if (optionName != (char *) NULL) {
1914            len = strlen(optionName);
1915        }
1916    
1917        if ((len > 1) && (optionName[1] == 'e') &&
1918                (strncmp(optionName, "-error", len) == 0)) {
1919            int optlen;
1920            int err, ret;
1921        
1922            optlen = sizeof(int);
1923            ret = TclWinGetSockOpt(sock, SOL_SOCKET, SO_ERROR,
1924                    (char *)&err, &optlen);
1925            if (ret == SOCKET_ERROR) {
1926                err = (*winSock.WSAGetLastError)();
1927            }
1928            if (err) {
1929                TclWinConvertWSAError(err);
1930                Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(Tcl_GetErrno()), -1);
1931            }
1932            return TCL_OK;
1933        }
1934    
1935        if ((len == 0) ||
1936                ((len > 1) && (optionName[1] == 'p') &&
1937                        (strncmp(optionName, "-peername", len) == 0))) {
1938            if ((*winSock.getpeername)(sock, (struct sockaddr *) &peername, &size)
1939                    == 0) {
1940                if (len == 0) {
1941                    Tcl_DStringAppendElement(dsPtr, "-peername");
1942                    Tcl_DStringStartSublist(dsPtr);
1943                }
1944                Tcl_DStringAppendElement(dsPtr,
1945                        (*winSock.inet_ntoa)(peername.sin_addr));
1946                hostEntPtr = (*winSock.gethostbyaddr)(
1947                    (char *) &(peername.sin_addr), sizeof(peername.sin_addr),
1948                    AF_INET);
1949                if (hostEntPtr != (struct hostent *) NULL) {
1950                    Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name);
1951                } else {
1952                    Tcl_DStringAppendElement(dsPtr,
1953                            (*winSock.inet_ntoa)(peername.sin_addr));
1954                }
1955                TclFormatInt(buf, (*winSock.ntohs)(peername.sin_port));
1956                Tcl_DStringAppendElement(dsPtr, buf);
1957                if (len == 0) {
1958                    Tcl_DStringEndSublist(dsPtr);
1959                } else {
1960                    return TCL_OK;
1961                }
1962            } else {
1963                /*
1964                 * getpeername failed - but if we were asked for all the options
1965                 * (len==0), don't flag an error at that point because it could
1966                 * be an fconfigure request on a server socket. (which have
1967                 * no peer). {copied from unix/tclUnixChan.c}
1968                 */
1969                if (len) {
1970                    TclWinConvertWSAError((*winSock.WSAGetLastError)());
1971                    if (interp) {
1972                        Tcl_AppendResult(interp, "can't get peername: ",
1973                                         Tcl_PosixError(interp),
1974                                         (char *) NULL);
1975                    }
1976                    return TCL_ERROR;
1977                }
1978            }
1979        }
1980    
1981        if ((len == 0) ||
1982                ((len > 1) && (optionName[1] == 's') &&
1983                        (strncmp(optionName, "-sockname", len) == 0))) {
1984            if ((*winSock.getsockname)(sock, (struct sockaddr *) &sockname, &size)
1985                    == 0) {
1986                if (len == 0) {
1987                    Tcl_DStringAppendElement(dsPtr, "-sockname");
1988                    Tcl_DStringStartSublist(dsPtr);
1989                }
1990                Tcl_DStringAppendElement(dsPtr,
1991                        (*winSock.inet_ntoa)(sockname.sin_addr));
1992                hostEntPtr = (*winSock.gethostbyaddr)(
1993                    (char *) &(sockname.sin_addr), sizeof(peername.sin_addr),
1994                    AF_INET);
1995                if (hostEntPtr != (struct hostent *) NULL) {
1996                    Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name);
1997                } else {
1998                    Tcl_DStringAppendElement(dsPtr,
1999                            (*winSock.inet_ntoa)(sockname.sin_addr));
2000                }
2001                TclFormatInt(buf, (*winSock.ntohs)(sockname.sin_port));
2002                Tcl_DStringAppendElement(dsPtr, buf);
2003                if (len == 0) {
2004                    Tcl_DStringEndSublist(dsPtr);
2005                } else {
2006                    return TCL_OK;
2007                }
2008            } else {
2009                if (interp) {
2010                    TclWinConvertWSAError((*winSock.WSAGetLastError)());
2011                    Tcl_AppendResult(interp, "can't get sockname: ",
2012                                     Tcl_PosixError(interp),
2013                                     (char *) NULL);
2014                }
2015                return TCL_ERROR;
2016            }
2017        }
2018    
2019        if (len > 0) {
2020            return Tcl_BadChannelOption(interp, optionName, "peername sockname");
2021        }
2022    
2023        return TCL_OK;
2024    }
2025    
2026    /*
2027     *----------------------------------------------------------------------
2028     *
2029     * TcpWatchProc --
2030     *
2031     *      Informs the channel driver of the events that the generic
2032     *      channel code wishes to receive on this socket.
2033     *
2034     * Results:
2035     *      None.
2036     *
2037     * Side effects:
2038     *      May cause the notifier to poll if any of the specified
2039     *      conditions are already true.
2040     *
2041     *----------------------------------------------------------------------
2042     */
2043    
2044    static void
2045    TcpWatchProc(instanceData, mask)
2046        ClientData instanceData;            /* The socket state. */
2047        int mask;                           /* Events of interest; an OR-ed
2048                                             * combination of TCL_READABLE,
2049                                             * TCL_WRITABLE and TCL_EXCEPTION. */
2050    {
2051        SocketInfo *infoPtr = (SocketInfo *) instanceData;
2052        
2053        /*
2054         * Update the watch events mask.
2055         */
2056        
2057        infoPtr->watchEvents = 0;
2058        if (mask & TCL_READABLE) {
2059            infoPtr->watchEvents |= (FD_READ|FD_CLOSE|FD_ACCEPT);
2060        }
2061        if (mask & TCL_WRITABLE) {
2062            infoPtr->watchEvents |= (FD_WRITE|FD_CONNECT);
2063        }
2064    
2065        /*
2066         * If there are any conditions already set, then tell the notifier to poll
2067         * rather than block.
2068         */
2069    
2070        if (infoPtr->readyEvents & infoPtr->watchEvents) {
2071            Tcl_Time blockTime = { 0, 0 };
2072            Tcl_SetMaxBlockTime(&blockTime);
2073        }          
2074    }
2075    
2076    /*
2077     *----------------------------------------------------------------------
2078     *
2079     * TcpGetProc --
2080     *
2081     *      Called from Tcl_GetChannelHandle to retrieve an OS handle from inside
2082     *      a TCP socket based channel.
2083     *
2084     * Results:
2085     *      Returns TCL_OK with the socket in handlePtr.
2086     *
2087     * Side effects:
2088     *      None.
2089     *
2090     *----------------------------------------------------------------------
2091     */
2092    
2093    static int
2094    TcpGetHandleProc(instanceData, direction, handlePtr)
2095        ClientData instanceData;    /* The socket state. */
2096        int direction;              /* Not used. */
2097        ClientData *handlePtr;      /* Where to store the handle.  */
2098    {
2099        SocketInfo *statePtr = (SocketInfo *) instanceData;
2100    
2101        *handlePtr = (ClientData) statePtr->socket;
2102        return TCL_OK;
2103    }
2104    
2105    /*
2106     *----------------------------------------------------------------------
2107     *
2108     * SocketThread --
2109     *
2110     *      Helper thread used to manage the socket event handling window.
2111     *
2112     * Results:
2113     *      1 if unable to create socket event window, 0 otherwise.
2114     *
2115     * Side effects:
2116     *      None.
2117     *
2118     *----------------------------------------------------------------------
2119     */
2120    
2121    static DWORD WINAPI
2122    SocketThread(LPVOID arg)
2123    {
2124        MSG msg;
2125        ThreadSpecificData *tsdPtr = (ThreadSpecificData *)(arg);
2126    
2127        tsdPtr->hwnd = CreateWindowA("TclSocket", "TclSocket",
2128                WS_TILED, 0, 0, 0, 0, NULL, NULL, windowClass.hInstance, NULL);
2129    
2130        /*
2131         * Signal the main thread that the window has been created
2132         * and that the socket thread is ready to go.
2133         */
2134        
2135        SetEvent(tsdPtr->readyEvent);
2136        
2137        if (tsdPtr->hwnd == NULL) {
2138            return 1;
2139        } else {
2140            /*
2141             * store the tsdPtr, it's from a different thread, so it's
2142             * not directly accessible, but needed.
2143             */
2144    
2145    #ifdef _WIN64
2146            SetWindowLongPtr(tsdPtr->hwnd, GWLP_USERDATA, (LONG) tsdPtr);
2147    #else
2148            SetWindowLong(tsdPtr->hwnd, GWL_USERDATA, (LONG) tsdPtr);
2149    #endif
2150        }
2151    
2152        while (1) {
2153            /*
2154             * Process all outstanding messages on the socket window.
2155             */
2156    
2157            while (PeekMessage(&msg, tsdPtr->hwnd, 0, 0, PM_REMOVE)) {
2158                DispatchMessage(&msg);
2159            }
2160            WaitMessage();
2161        }
2162    }
2163    
2164    
2165    /*
2166     *----------------------------------------------------------------------
2167     *
2168     * SocketProc --
2169     *
2170     *      This function is called when WSAAsyncSelect has been used
2171     *      to register interest in a socket event, and the event has
2172     *      occurred.
2173     *
2174     * Results:
2175     *      0 on success.
2176     *
2177     * Side effects:
2178     *      The flags for the given socket are updated to reflect the
2179     *      event that occured.
2180     *
2181     *----------------------------------------------------------------------
2182     */
2183    
2184    static LRESULT CALLBACK
2185    SocketProc(hwnd, message, wParam, lParam)
2186        HWND hwnd;
2187        UINT message;
2188        WPARAM wParam;
2189        LPARAM lParam;
2190    {
2191        int event, error;
2192        SOCKET socket;
2193        SocketInfo *infoPtr;
2194        ThreadSpecificData *tsdPtr =
2195    #ifdef _WIN64
2196            (ThreadSpecificData *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
2197    #else
2198            (ThreadSpecificData *) GetWindowLong(hwnd, GWL_USERDATA);
2199    #endif
2200    
2201        switch (message) {
2202    
2203            default:
2204                return DefWindowProc(hwnd, message, wParam, lParam);
2205                break;
2206                
2207            case SOCKET_MESSAGE:
2208                event = WSAGETSELECTEVENT(lParam);
2209                error = WSAGETSELECTERROR(lParam);
2210                socket = (SOCKET) wParam;
2211    
2212                /*
2213                 * Find the specified socket on the socket list and update its
2214                 * eventState flag.
2215                 */
2216    
2217                WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
2218                for (infoPtr = tsdPtr->socketList; infoPtr != NULL;
2219                     infoPtr = infoPtr->nextPtr) {
2220                    if (infoPtr->socket == socket) {
2221                        /*
2222                         * Update the socket state.
2223                         */
2224    
2225                        /*
2226                         * A count of FD_ACCEPTS is stored, so if an FD_CLOSE event
2227                         * happens, then clear the FD_ACCEPT count.  Otherwise,
2228                         * increment the count if the current event is and
2229                         * FD_ACCEPT.
2230                         */
2231                        
2232                        if (event & FD_CLOSE) {
2233                            infoPtr->acceptEventCount = 0;
2234                            infoPtr->readyEvents &= ~(FD_WRITE|FD_ACCEPT);
2235                        } else if (event & FD_ACCEPT) {
2236                            infoPtr->acceptEventCount++;
2237                        }
2238    
2239                        if (event & FD_CONNECT) {
2240                            /*
2241                             * The socket is now connected,
2242                             * clear the async connect flag.
2243                             */
2244                            
2245                            infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT);
2246                            
2247                            /*
2248                             * Remember any error that occurred so we can report
2249                             * connection failures.
2250                             */
2251                            
2252                            if (error != ERROR_SUCCESS) {
2253                                TclWinConvertWSAError(error);
2254                                infoPtr->lastError = Tcl_GetErrno();
2255                            }
2256                            
2257                        }
2258                        if(infoPtr->flags & SOCKET_ASYNC_CONNECT) {
2259                            infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT);
2260                            if (error != ERROR_SUCCESS) {
2261                                TclWinConvertWSAError(error);
2262                                infoPtr->lastError = Tcl_GetErrno();
2263                            }
2264                            infoPtr->readyEvents |= FD_WRITE;
2265                        }
2266                        infoPtr->readyEvents |= event;
2267    
2268                        /*
2269                         * Wake up the Main Thread.
2270                         */
2271                        SetEvent(tsdPtr->readyEvent);
2272                        Tcl_ThreadAlert(tsdPtr->threadId);
2273                        break;
2274                    }
2275                }
2276                SetEvent(tsdPtr->socketListLock);
2277                break;
2278            case SOCKET_SELECT:
2279                infoPtr = (SocketInfo *) lParam;
2280                if (wParam == SELECT) {
2281    
2282                    (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, hwnd,
2283                            SOCKET_MESSAGE, infoPtr->selectEvents);
2284                } else {
2285                    /*
2286                     * Clear the selection mask
2287                     */
2288                    
2289                    (void) (*winSock.WSAAsyncSelect)(infoPtr->socket, hwnd, 0, 0);
2290                }
2291                break;
2292            case SOCKET_TERMINATE:
2293                ExitThread(0);
2294                break;
2295        }
2296    
2297        return 0;
2298    }
2299    
2300    /*
2301     *----------------------------------------------------------------------
2302     *
2303     * Tcl_GetHostName --
2304     *
2305     *      Returns the name of the local host.
2306     *
2307     * Results:
2308     *      A string containing the network name for this machine, or
2309     *      an empty string if we can't figure out the name.  The caller
2310     *      must not modify or free this string.
2311     *
2312     * Side effects:
2313     *      None.
2314     *
2315     *----------------------------------------------------------------------
2316     */
2317    
2318    char *
2319    Tcl_GetHostName()
2320    {
2321        DWORD length;
2322        WCHAR wbuf[MAX_COMPUTERNAME_LENGTH + 1];
2323    
2324        Tcl_MutexLock(&socketMutex);
2325        InitSockets();
2326    
2327        if (hostnameInitialized) {
2328            Tcl_MutexUnlock(&socketMutex);
2329            return hostname;
2330        }
2331        Tcl_MutexUnlock(&socketMutex);
2332            
2333        if (TclpHasSockets(NULL) == TCL_OK) {
2334            /*
2335             * INTL: bug
2336             */
2337    
2338            if ((*winSock.gethostname)(hostname, sizeof(hostname)) == 0) {
2339                Tcl_MutexLock(&socketMutex);
2340                hostnameInitialized = 1;
2341                Tcl_MutexUnlock(&socketMutex);
2342                return hostname;
2343            }
2344        }
2345        Tcl_MutexLock(&socketMutex);
2346        length = sizeof(hostname);
2347        if ((*tclWinProcs->getComputerNameProc)(wbuf, &length) != 0) {
2348            /*
2349             * Convert string from native to UTF then change to lowercase.
2350             */
2351    
2352            Tcl_DString ds;
2353    
2354            lstrcpynA(hostname, Tcl_WinTCharToUtf((TCHAR *) wbuf, -1, &ds),
2355                    sizeof(hostname));
2356            Tcl_DStringFree(&ds);
2357            Tcl_UtfToLower(hostname);
2358        } else {
2359            hostname[0] = '\0';
2360        }
2361        hostnameInitialized = 1;
2362        Tcl_MutexUnlock(&socketMutex);
2363        return hostname;
2364    }
2365    
2366    /*
2367     *----------------------------------------------------------------------
2368     *
2369     * TclWinGetSockOpt, et al. --
2370     *
2371     *      These functions are wrappers that let us bind the WinSock
2372     *      API dynamically so we can run on systems that don't have
2373     *      the wsock32.dll.  We need wrappers for these interfaces
2374     *      because they are called from the generic Tcl code.
2375     *
2376     * Results:
2377     *      As defined for each function.
2378     *
2379     * Side effects:
2380     *      As defined for each function.
2381     *
2382     *----------------------------------------------------------------------
2383     */
2384    
2385    int
2386    TclWinGetSockOpt(SOCKET s, int level, int optname, char * optval,
2387            int FAR *optlen)
2388    {
2389        /*
2390         * Check that WinSock is initialized; do not call it if not, to
2391         * prevent system crashes. This can happen at exit time if the exit
2392         * handler for WinSock ran before other exit handlers that want to
2393         * use sockets.
2394         */
2395    
2396        if (!SocketsEnabled()) {
2397            return SOCKET_ERROR;
2398        }
2399        
2400        return (*winSock.getsockopt)(s, level, optname, optval, optlen);
2401    }
2402    
2403    int
2404    TclWinSetSockOpt(SOCKET s, int level, int optname, const char * optval,
2405            int optlen)
2406    {
2407        /*
2408         * Check that WinSock is initialized; do not call it if not, to
2409         * prevent system crashes. This can happen at exit time if the exit
2410         * handler for WinSock ran before other exit handlers that want to
2411         * use sockets.
2412         */
2413        if (!SocketsEnabled()) {
2414            return SOCKET_ERROR;
2415        }
2416    
2417        return (*winSock.setsockopt)(s, level, optname, optval, optlen);
2418    }
2419    
2420    u_short
2421    TclWinNToHS(u_short netshort)
2422    {
2423        /*
2424         * Check that WinSock is initialized; do not call it if not, to
2425         * prevent system crashes. This can happen at exit time if the exit
2426         * handler for WinSock ran before other exit handlers that want to
2427         * use sockets.
2428         */
2429    
2430        if (!SocketsEnabled()) {
2431            return (u_short) -1;
2432        }
2433    
2434        return (*winSock.ntohs)(netshort);
2435    }
2436    
2437    struct servent *
2438    TclWinGetServByName(const char * name, const char * proto)
2439    {
2440        /*
2441         * Check that WinSock is initialized; do not call it if not, to
2442         * prevent system crashes. This can happen at exit time if the exit
2443         * handler for WinSock ran before other exit handlers that want to
2444         * use sockets.
2445         */
2446        if (!SocketsEnabled()) {
2447            return (struct servent *) NULL;
2448        }
2449    
2450        return (*winSock.getservbyname)(name, proto);
2451    }
2452    
2453    /* End of tclwinsock.c */

Legend:
Removed from v.44  
changed lines
  Added in v.71

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25