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