os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/win/tclWinSock.c
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/win/tclWinSock.c	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,2752 @@
     1.4 +/* 
     1.5 + * tclWinSock.c --
     1.6 + *
     1.7 + *	This file contains Windows-specific socket related code.
     1.8 + *
     1.9 + * Copyright (c) 1995-1997 Sun Microsystems, Inc.
    1.10 + *
    1.11 + * See the file "license.terms" for information on usage and redistribution
    1.12 + * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
    1.13 + *
    1.14 + * RCS: @(#) $Id: tclWinSock.c,v 1.36.2.6 2006/09/26 21:40:37 patthoyts Exp $
    1.15 + */
    1.16 +
    1.17 +#include "tclWinInt.h"
    1.18 +
    1.19 +/*
    1.20 + * Make sure to remove the redirection defines set in tclWinPort.h
    1.21 + * that is in use in other sections of the core, except for us.
    1.22 + */
    1.23 +#undef getservbyname
    1.24 +#undef getsockopt
    1.25 +#undef ntohs
    1.26 +#undef setsockopt
    1.27 +
    1.28 +/*
    1.29 + * The following variable is used to tell whether this module has been
    1.30 + * initialized.
    1.31 + */
    1.32 +
    1.33 +static int initialized = 0;
    1.34 +
    1.35 +static int  hostnameInitialized = 0;
    1.36 +static char hostname[255];	/* This buffer should be big enough for
    1.37 +                                 * hostname plus domain name. */
    1.38 +
    1.39 +TCL_DECLARE_MUTEX(socketMutex)
    1.40 +
    1.41 +
    1.42 +/*
    1.43 + * Mingw and Cygwin may not have LPFN_* typedefs.
    1.44 + */
    1.45 +
    1.46 +#ifdef HAVE_NO_LPFN_DECLS
    1.47 +    typedef SOCKET (PASCAL FAR *LPFN_ACCEPT)(SOCKET s,
    1.48 +            struct sockaddr FAR * addr, int FAR * addrlen);
    1.49 +    typedef int (PASCAL FAR *LPFN_BIND)(SOCKET s,
    1.50 +            const struct sockaddr FAR *addr, int namelen);
    1.51 +    typedef int (PASCAL FAR *LPFN_CLOSESOCKET)(SOCKET s);
    1.52 +    typedef int (PASCAL FAR *LPFN_CONNECT)(SOCKET s,
    1.53 +            const struct sockaddr FAR *name, int namelen);
    1.54 +    typedef struct hostent FAR * (PASCAL FAR *LPFN_GETHOSTBYADDR)
    1.55 +            (const char FAR *addr, int addrlen, int addrtype);
    1.56 +    typedef struct hostent FAR * (PASCAL FAR *LPFN_GETHOSTBYNAME)
    1.57 +            (const char FAR * name);
    1.58 +    typedef int (PASCAL FAR *LPFN_GETHOSTNAME)(char FAR * name,
    1.59 +            int namelen);
    1.60 +    typedef int (PASCAL FAR *LPFN_GETPEERNAME)(SOCKET sock,
    1.61 +            struct sockaddr FAR *name, int FAR *namelen);
    1.62 +    typedef struct servent FAR * (PASCAL FAR *LPFN_GETSERVBYNAME)
    1.63 +            (const char FAR * name, const char FAR * proto);
    1.64 +    typedef int (PASCAL FAR *LPFN_GETSOCKNAME)(SOCKET sock,
    1.65 +            struct sockaddr FAR *name, int FAR *namelen);
    1.66 +    typedef int (PASCAL FAR *LPFN_GETSOCKOPT)(SOCKET s, int level,
    1.67 +            int optname, char FAR * optval, int FAR *optlen);
    1.68 +    typedef u_short (PASCAL FAR *LPFN_HTONS)(u_short hostshort);
    1.69 +    typedef unsigned long (PASCAL FAR *LPFN_INET_ADDR)
    1.70 +            (const char FAR * cp);
    1.71 +    typedef char FAR * (PASCAL FAR *LPFN_INET_NTOA)
    1.72 +            (struct in_addr in);
    1.73 +    typedef int (PASCAL FAR *LPFN_IOCTLSOCKET)(SOCKET s,
    1.74 +            long cmd, u_long FAR *argp);
    1.75 +    typedef int (PASCAL FAR *LPFN_LISTEN)(SOCKET s, int backlog);
    1.76 +    typedef u_short (PASCAL FAR *LPFN_NTOHS)(u_short netshort);
    1.77 +    typedef int (PASCAL FAR *LPFN_RECV)(SOCKET s, char FAR * buf,
    1.78 +            int len, int flags);
    1.79 +    typedef int (PASCAL FAR *LPFN_SELECT)(int nfds,
    1.80 +            fd_set FAR * readfds, fd_set FAR * writefds,
    1.81 +            fd_set FAR * exceptfds,
    1.82 +            const struct timeval FAR * timeout);
    1.83 +    typedef int (PASCAL FAR *LPFN_SEND)(SOCKET s,
    1.84 +            const char FAR * buf, int len, int flags);
    1.85 +    typedef int (PASCAL FAR *LPFN_SETSOCKOPT)(SOCKET s,
    1.86 +            int level, int optname, const char FAR * optval,
    1.87 +            int optlen);
    1.88 +    typedef SOCKET (PASCAL FAR *LPFN_SOCKET)(int af,
    1.89 +            int type, int protocol);
    1.90 +    typedef int (PASCAL FAR *LPFN_WSAASYNCSELECT)(SOCKET s,
    1.91 +            HWND hWnd, u_int wMsg, long lEvent);
    1.92 +    typedef int (PASCAL FAR *LPFN_WSACLEANUP)(void);
    1.93 +    typedef int (PASCAL FAR *LPFN_WSAGETLASTERROR)(void);
    1.94 +    typedef int (PASCAL FAR *LPFN_WSASTARTUP)(WORD wVersionRequired,
    1.95 +            LPWSADATA lpWSAData);
    1.96 +#endif
    1.97 +
    1.98 +
    1.99 +/*
   1.100 + * The following structure contains pointers to all of the WinSock API
   1.101 + * entry points used by Tcl.  It is initialized by InitSockets.  Since
   1.102 + * we dynamically load the Winsock DLL on demand, we must use this
   1.103 + * function table to refer to functions in the winsock API.
   1.104 + */
   1.105 +
   1.106 +static struct {
   1.107 +    HMODULE		    hModule;	/* Handle to WinSock library. */
   1.108 +
   1.109 +    /* Winsock 1.1 functions */
   1.110 +    LPFN_ACCEPT		    accept;
   1.111 +    LPFN_BIND		    bind;
   1.112 +    LPFN_CLOSESOCKET	    closesocket;
   1.113 +    LPFN_CONNECT	    connect;
   1.114 +    LPFN_GETHOSTBYADDR	    gethostbyaddr;
   1.115 +    LPFN_GETHOSTBYNAME	    gethostbyname;
   1.116 +    LPFN_GETHOSTNAME	    gethostname;
   1.117 +    LPFN_GETPEERNAME	    getpeername;
   1.118 +    LPFN_GETSERVBYNAME	    getservbyname;
   1.119 +    LPFN_GETSOCKNAME	    getsockname;
   1.120 +    LPFN_GETSOCKOPT	    getsockopt;
   1.121 +    LPFN_HTONS		    htons;
   1.122 +    LPFN_INET_ADDR	    inet_addr;
   1.123 +    LPFN_INET_NTOA	    inet_ntoa;
   1.124 +    LPFN_IOCTLSOCKET	    ioctlsocket;
   1.125 +    LPFN_LISTEN		    listen;
   1.126 +    LPFN_NTOHS		    ntohs;
   1.127 +    LPFN_RECV		    recv;
   1.128 +    LPFN_SELECT		    select;
   1.129 +    LPFN_SEND		    send;
   1.130 +    LPFN_SETSOCKOPT	    setsockopt;
   1.131 +    LPFN_SOCKET		    socket;
   1.132 +    LPFN_WSAASYNCSELECT	    WSAAsyncSelect;
   1.133 +    LPFN_WSACLEANUP	    WSACleanup;
   1.134 +    LPFN_WSAGETLASTERROR    WSAGetLastError;
   1.135 +    LPFN_WSASTARTUP	    WSAStartup;
   1.136 +
   1.137 +} winSock;
   1.138 +
   1.139 +/*
   1.140 + * The following defines declare the messages used on socket windows.
   1.141 + */
   1.142 +
   1.143 +#define SOCKET_MESSAGE	    WM_USER+1
   1.144 +#define SOCKET_SELECT	    WM_USER+2
   1.145 +#define SOCKET_TERMINATE    WM_USER+3
   1.146 +#define SELECT		    TRUE
   1.147 +#define UNSELECT	    FALSE
   1.148 +
   1.149 +/*
   1.150 + * The following structure is used to store the data associated with
   1.151 + * each socket.
   1.152 + */
   1.153 +
   1.154 +typedef struct SocketInfo {
   1.155 +    Tcl_Channel channel;	   /* Channel associated with this
   1.156 +				    * socket. */
   1.157 +    SOCKET socket;		   /* Windows SOCKET handle. */
   1.158 +    int flags;			   /* Bit field comprised of the flags
   1.159 +				    * described below.  */
   1.160 +    int watchEvents;		   /* OR'ed combination of FD_READ,
   1.161 +				    * FD_WRITE, FD_CLOSE, FD_ACCEPT and
   1.162 +				    * FD_CONNECT that indicate which
   1.163 +				    * events are interesting. */
   1.164 +    int readyEvents;		   /* OR'ed combination of FD_READ,
   1.165 +				    * FD_WRITE, FD_CLOSE, FD_ACCEPT and
   1.166 +				    * FD_CONNECT that indicate which
   1.167 +				    * events have occurred. */
   1.168 +    int selectEvents;		   /* OR'ed combination of FD_READ,
   1.169 +				    * FD_WRITE, FD_CLOSE, FD_ACCEPT and
   1.170 +				    * FD_CONNECT that indicate which
   1.171 +				    * events are currently being
   1.172 +				    * selected. */
   1.173 +    int acceptEventCount;          /* Count of the current number of
   1.174 +				    * FD_ACCEPTs that have arrived and
   1.175 +				    * not yet processed. */
   1.176 +    Tcl_TcpAcceptProc *acceptProc; /* Proc to call on accept. */
   1.177 +    ClientData acceptProcData;	   /* The data for the accept proc. */
   1.178 +    int lastError;		   /* Error code from last message. */
   1.179 +    struct SocketInfo *nextPtr;	   /* The next socket on the per-thread
   1.180 +				    * socket list. */
   1.181 +} SocketInfo;
   1.182 +
   1.183 +/*
   1.184 + * The following structure is what is added to the Tcl event queue when
   1.185 + * a socket event occurs.
   1.186 + */
   1.187 +
   1.188 +typedef struct SocketEvent {
   1.189 +    Tcl_Event header;		/* Information that is standard for
   1.190 +				 * all events. */
   1.191 +    SOCKET socket;		/* Socket descriptor that is ready.  Used
   1.192 +				 * to find the SocketInfo structure for
   1.193 +				 * the file (can't point directly to the
   1.194 +				 * SocketInfo structure because it could
   1.195 +				 * go away while the event is queued). */
   1.196 +} SocketEvent;
   1.197 +
   1.198 +/*
   1.199 + * This defines the minimum buffersize maintained by the kernel.
   1.200 + */
   1.201 +
   1.202 +#define TCP_BUFFER_SIZE 4096
   1.203 +
   1.204 +/*
   1.205 + * The following macros may be used to set the flags field of
   1.206 + * a SocketInfo structure.
   1.207 + */
   1.208 +
   1.209 +#define SOCKET_ASYNC		(1<<0)	/* The socket is in blocking
   1.210 +					 * mode. */
   1.211 +#define SOCKET_EOF		(1<<1)	/* A zero read happened on
   1.212 +					 * the socket. */
   1.213 +#define SOCKET_ASYNC_CONNECT	(1<<2)	/* This socket uses async
   1.214 +					 * connect. */
   1.215 +#define SOCKET_PENDING		(1<<3)	/* A message has been sent
   1.216 +					 * for this socket */
   1.217 +
   1.218 +typedef struct ThreadSpecificData {
   1.219 +    HWND hwnd;		    /* Handle to window for socket messages. */
   1.220 +    HANDLE socketThread;    /* Thread handling the window */
   1.221 +    Tcl_ThreadId threadId;  /* Parent thread. */
   1.222 +    HANDLE readyEvent;      /* Event indicating that a socket event is
   1.223 +			     * ready.  Also used to indicate that the
   1.224 +			     * socketThread has been initialized and has
   1.225 +			     * started. */
   1.226 +    HANDLE socketListLock;  /* Win32 Event to lock the socketList */
   1.227 +    SocketInfo *socketList; /* Every open socket in this thread has an
   1.228 +			     * entry on this list. */
   1.229 +} ThreadSpecificData;
   1.230 +
   1.231 +static Tcl_ThreadDataKey dataKey;
   1.232 +static WNDCLASS windowClass;
   1.233 +
   1.234 +/*
   1.235 + * Static functions defined in this file.
   1.236 + */
   1.237 +
   1.238 +static SocketInfo *	    CreateSocket _ANSI_ARGS_((Tcl_Interp *interp,
   1.239 +				    int port, CONST char *host,
   1.240 +				    int server, CONST char *myaddr,
   1.241 +				    int myport, int async));
   1.242 +static int		    CreateSocketAddress _ANSI_ARGS_(
   1.243 +				    (LPSOCKADDR_IN sockaddrPtr,
   1.244 +				    CONST char *host, int port));
   1.245 +static void		    InitSockets _ANSI_ARGS_((void));
   1.246 +static SocketInfo *	    NewSocketInfo _ANSI_ARGS_((SOCKET socket));
   1.247 +static Tcl_EventCheckProc   SocketCheckProc;
   1.248 +static Tcl_EventProc	    SocketEventProc;
   1.249 +static void		    SocketExitHandler _ANSI_ARGS_((
   1.250 +				    ClientData clientData));
   1.251 +static LRESULT CALLBACK	    SocketProc _ANSI_ARGS_((HWND hwnd,
   1.252 +				    UINT message, WPARAM wParam,
   1.253 +				    LPARAM lParam));
   1.254 +static Tcl_EventSetupProc   SocketSetupProc;
   1.255 +static int		    SocketsEnabled _ANSI_ARGS_((void));
   1.256 +static void		    TcpAccept _ANSI_ARGS_((SocketInfo *infoPtr));
   1.257 +static Tcl_DriverBlockModeProc	TcpBlockProc;
   1.258 +static Tcl_DriverCloseProc	TcpCloseProc;
   1.259 +static Tcl_DriverSetOptionProc	TcpSetOptionProc;
   1.260 +static Tcl_DriverGetOptionProc	TcpGetOptionProc;
   1.261 +static Tcl_DriverInputProc	TcpInputProc;
   1.262 +static Tcl_DriverOutputProc	TcpOutputProc;
   1.263 +static Tcl_DriverWatchProc	TcpWatchProc;
   1.264 +static Tcl_DriverGetHandleProc	TcpGetHandleProc;
   1.265 +static int		    WaitForSocketEvent _ANSI_ARGS_((
   1.266 +				SocketInfo *infoPtr, int events,
   1.267 +				int *errorCodePtr));
   1.268 +static DWORD WINAPI	    SocketThread _ANSI_ARGS_((LPVOID arg));
   1.269 +
   1.270 +static void             TcpThreadActionProc _ANSI_ARGS_ ((
   1.271 +			   ClientData instanceData, int action));
   1.272 +
   1.273 +
   1.274 +/*
   1.275 + * This structure describes the channel type structure for TCP socket
   1.276 + * based IO.
   1.277 + */
   1.278 +
   1.279 +static Tcl_ChannelType tcpChannelType = {
   1.280 +    "tcp",		    /* Type name. */
   1.281 +    TCL_CHANNEL_VERSION_4,  /* v4 channel */
   1.282 +    TcpCloseProc,	    /* Close proc. */
   1.283 +    TcpInputProc,	    /* Input proc. */
   1.284 +    TcpOutputProc,	    /* Output proc. */
   1.285 +    NULL,		    /* Seek proc. */
   1.286 +    TcpSetOptionProc,	    /* Set option proc. */
   1.287 +    TcpGetOptionProc,	    /* Get option proc. */
   1.288 +    TcpWatchProc,	    /* Set up notifier to watch this channel. */
   1.289 +    TcpGetHandleProc,	    /* Get an OS handle from channel. */
   1.290 +    NULL,		    /* close2proc. */
   1.291 +    TcpBlockProc,	    /* Set socket into (non-)blocking mode. */
   1.292 +    NULL,		    /* flush proc. */
   1.293 +    NULL,		    /* handler proc. */
   1.294 +    NULL,                   /* wide seek proc */
   1.295 +    TcpThreadActionProc,    /* thread action proc */
   1.296 +};
   1.297 +
   1.298 +
   1.299 +/*
   1.300 + *----------------------------------------------------------------------
   1.301 + *
   1.302 + * InitSockets --
   1.303 + *
   1.304 + *	Initialize the socket module.  Attempts to load the wsock32.dll
   1.305 + *	library and set up the winSock function table.  If successful,
   1.306 + *	registers the event window for the socket notifier code.
   1.307 + *
   1.308 + *	Assumes socketMutex is held.
   1.309 + *
   1.310 + * Results:
   1.311 + *	None.
   1.312 + *
   1.313 + * Side effects:
   1.314 + *	Dynamically loads wsock32.dll, and registers a new window
   1.315 + *	class and creates a window for use in asynchronous socket
   1.316 + *	notification.
   1.317 + *
   1.318 + *----------------------------------------------------------------------
   1.319 + */
   1.320 +
   1.321 +static void
   1.322 +InitSockets()
   1.323 +{
   1.324 +    DWORD id;
   1.325 +    WSADATA wsaData;
   1.326 +    DWORD err;
   1.327 +    ThreadSpecificData *tsdPtr = 
   1.328 +	(ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
   1.329 +
   1.330 +    if (!initialized) {
   1.331 +	initialized = 1;
   1.332 +	Tcl_CreateExitHandler(SocketExitHandler, (ClientData) NULL);
   1.333 +
   1.334 +	winSock.hModule = LoadLibraryA("wsock32.dll");
   1.335 +
   1.336 +	if (winSock.hModule == NULL) {
   1.337 +	    return;
   1.338 +	}
   1.339 +    
   1.340 +	/*
   1.341 +	 * Initialize the function table.
   1.342 +	 */
   1.343 +
   1.344 +	winSock.accept = (LPFN_ACCEPT)
   1.345 +		GetProcAddress(winSock.hModule, "accept");
   1.346 +	winSock.bind = (LPFN_BIND)
   1.347 +		GetProcAddress(winSock.hModule, "bind");
   1.348 +	winSock.closesocket = (LPFN_CLOSESOCKET)
   1.349 +		GetProcAddress(winSock.hModule, "closesocket");
   1.350 +	winSock.connect = (LPFN_CONNECT)
   1.351 +		GetProcAddress(winSock.hModule, "connect");
   1.352 +	winSock.gethostbyaddr = (LPFN_GETHOSTBYADDR)
   1.353 +		GetProcAddress(winSock.hModule, "gethostbyaddr");
   1.354 +	winSock.gethostbyname = (LPFN_GETHOSTBYNAME)
   1.355 +		GetProcAddress(winSock.hModule, "gethostbyname");
   1.356 +	winSock.gethostname = (LPFN_GETHOSTNAME)
   1.357 +		GetProcAddress(winSock.hModule, "gethostname");
   1.358 +	winSock.getpeername = (LPFN_GETPEERNAME)
   1.359 +		GetProcAddress(winSock.hModule, "getpeername");
   1.360 +	winSock.getservbyname = (LPFN_GETSERVBYNAME)
   1.361 +		GetProcAddress(winSock.hModule, "getservbyname");
   1.362 +	winSock.getsockname = (LPFN_GETSOCKNAME)
   1.363 +		GetProcAddress(winSock.hModule, "getsockname");
   1.364 +	winSock.getsockopt = (LPFN_GETSOCKOPT)
   1.365 +		GetProcAddress(winSock.hModule, "getsockopt");
   1.366 +	winSock.htons = (LPFN_HTONS)
   1.367 +		GetProcAddress(winSock.hModule, "htons");
   1.368 +	winSock.inet_addr = (LPFN_INET_ADDR)
   1.369 +		GetProcAddress(winSock.hModule, "inet_addr");
   1.370 +	winSock.inet_ntoa = (LPFN_INET_NTOA)
   1.371 +		GetProcAddress(winSock.hModule, "inet_ntoa");
   1.372 +	winSock.ioctlsocket = (LPFN_IOCTLSOCKET)
   1.373 +		GetProcAddress(winSock.hModule, "ioctlsocket");
   1.374 +	winSock.listen = (LPFN_LISTEN)
   1.375 +		GetProcAddress(winSock.hModule, "listen");
   1.376 +	winSock.ntohs = (LPFN_NTOHS)
   1.377 +		GetProcAddress(winSock.hModule, "ntohs");
   1.378 +	winSock.recv = (LPFN_RECV)
   1.379 +		GetProcAddress(winSock.hModule, "recv");
   1.380 +	winSock.select = (LPFN_SELECT)
   1.381 +		GetProcAddress(winSock.hModule, "select");
   1.382 +	winSock.send = (LPFN_SEND)
   1.383 +		GetProcAddress(winSock.hModule, "send");
   1.384 +	winSock.setsockopt = (LPFN_SETSOCKOPT)
   1.385 +		GetProcAddress(winSock.hModule, "setsockopt");
   1.386 +	winSock.socket = (LPFN_SOCKET)
   1.387 +		GetProcAddress(winSock.hModule, "socket");
   1.388 +	winSock.WSAAsyncSelect = (LPFN_WSAASYNCSELECT)
   1.389 +		GetProcAddress(winSock.hModule, "WSAAsyncSelect");
   1.390 +	winSock.WSACleanup = (LPFN_WSACLEANUP)
   1.391 +		GetProcAddress(winSock.hModule, "WSACleanup");
   1.392 +	winSock.WSAGetLastError = (LPFN_WSAGETLASTERROR)
   1.393 +		GetProcAddress(winSock.hModule, "WSAGetLastError");
   1.394 +	winSock.WSAStartup = (LPFN_WSASTARTUP)
   1.395 +		GetProcAddress(winSock.hModule, "WSAStartup");
   1.396 +    
   1.397 +	/*
   1.398 +	 * Now check that all fields are properly initialized. If not,
   1.399 +	 * return zero to indicate that we failed to initialize
   1.400 +	 * properly.
   1.401 +	 */
   1.402 +    
   1.403 +	if ((winSock.accept == NULL) ||
   1.404 +		(winSock.bind == NULL) ||
   1.405 +		(winSock.closesocket == NULL) ||
   1.406 +		(winSock.connect == NULL) ||
   1.407 +		(winSock.gethostbyname == NULL) ||
   1.408 +		(winSock.gethostbyaddr == NULL) ||
   1.409 +		(winSock.gethostname == NULL) ||
   1.410 +		(winSock.getpeername == NULL) ||
   1.411 +		(winSock.getservbyname == NULL) ||
   1.412 +		(winSock.getsockname == NULL) ||
   1.413 +		(winSock.getsockopt == NULL) ||
   1.414 +		(winSock.htons == NULL) ||
   1.415 +		(winSock.inet_addr == NULL) ||
   1.416 +		(winSock.inet_ntoa == NULL) ||
   1.417 +		(winSock.ioctlsocket == NULL) ||
   1.418 +		(winSock.listen == NULL) ||
   1.419 +		(winSock.ntohs == NULL) ||
   1.420 +		(winSock.recv == NULL) ||
   1.421 +		(winSock.select == NULL) ||
   1.422 +		(winSock.send == NULL) ||
   1.423 +		(winSock.setsockopt == NULL) ||
   1.424 +		(winSock.socket == NULL) ||
   1.425 +		(winSock.WSAAsyncSelect == NULL) ||
   1.426 +		(winSock.WSACleanup == NULL) ||
   1.427 +		(winSock.WSAGetLastError == NULL) ||
   1.428 +		(winSock.WSAStartup == NULL))
   1.429 +	{
   1.430 +	    goto unloadLibrary;
   1.431 +	}
   1.432 +	
   1.433 +	/*
   1.434 +	 * Create the async notification window with a new class.  We
   1.435 +	 * must create a new class to avoid a Windows 95 bug that causes
   1.436 +	 * us to get the wrong message number for socket events if the
   1.437 +	 * message window is a subclass of a static control.
   1.438 +	 */
   1.439 +    
   1.440 +	windowClass.style = 0;
   1.441 +	windowClass.cbClsExtra = 0;
   1.442 +	windowClass.cbWndExtra = 0;
   1.443 +	windowClass.hInstance = TclWinGetTclInstance();
   1.444 +	windowClass.hbrBackground = NULL;
   1.445 +	windowClass.lpszMenuName = NULL;
   1.446 +	windowClass.lpszClassName = "TclSocket";
   1.447 +	windowClass.lpfnWndProc = SocketProc;
   1.448 +	windowClass.hIcon = NULL;
   1.449 +	windowClass.hCursor = NULL;
   1.450 +
   1.451 +	if (!RegisterClassA(&windowClass)) {
   1.452 +	    TclWinConvertError(GetLastError());
   1.453 +	    goto unloadLibrary;
   1.454 +	}
   1.455 +
   1.456 +	/*
   1.457 +	 * Initialize the winsock library and check the interface
   1.458 +	 * version actually loaded. We only ask for the 1.1 interface
   1.459 +	 * and do require that it not be less than 1.1.
   1.460 +	 */
   1.461 +
   1.462 +#define WSA_VERSION_MAJOR   1
   1.463 +#define WSA_VERSION_MINOR   1
   1.464 +#define WSA_VERSION_REQD    MAKEWORD(WSA_VERSION_MAJOR, WSA_VERSION_MINOR)
   1.465 +
   1.466 +	if ((err = winSock.WSAStartup(WSA_VERSION_REQD, &wsaData)) != 0) {
   1.467 +	    TclWinConvertWSAError(err);
   1.468 +	    goto unloadLibrary;
   1.469 +	}
   1.470 +
   1.471 +	/*
   1.472 +	 * Note the byte positions are swapped for the comparison, so
   1.473 +	 * that 0x0002 (2.0, MAKEWORD(2,0)) doesn't look less than 0x0101
   1.474 +	 * (1.1).  We want the comparison to be 0x0200 < 0x0101.
   1.475 +	 */
   1.476 +
   1.477 +	if (MAKEWORD(HIBYTE(wsaData.wVersion), LOBYTE(wsaData.wVersion))
   1.478 +		< MAKEWORD(WSA_VERSION_MINOR, WSA_VERSION_MAJOR)) {
   1.479 +	    TclWinConvertWSAError(WSAVERNOTSUPPORTED);
   1.480 +	    winSock.WSACleanup();
   1.481 +	    goto unloadLibrary;
   1.482 +	}
   1.483 +
   1.484 +#undef WSA_VERSION_REQD
   1.485 +#undef WSA_VERSION_MAJOR
   1.486 +#undef WSA_VERSION_MINOR
   1.487 +    }
   1.488 +
   1.489 +    /*
   1.490 +     * Check for per-thread initialization.
   1.491 +     */
   1.492 +
   1.493 +    if (tsdPtr == NULL) {
   1.494 +	tsdPtr = TCL_TSD_INIT(&dataKey);
   1.495 +	tsdPtr->socketList = NULL;
   1.496 +	tsdPtr->hwnd       = NULL;
   1.497 +	tsdPtr->threadId   = Tcl_GetCurrentThread();
   1.498 +	tsdPtr->readyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
   1.499 +	if (tsdPtr->readyEvent == NULL) {
   1.500 +	    goto unloadLibrary;
   1.501 +	}
   1.502 +	tsdPtr->socketListLock = CreateEvent(NULL, FALSE, TRUE, NULL);
   1.503 +	if (tsdPtr->socketListLock == NULL) {
   1.504 +	    goto unloadLibrary;
   1.505 +	}
   1.506 +	tsdPtr->socketThread = CreateThread(NULL, 256, SocketThread,
   1.507 +		tsdPtr, 0, &id);
   1.508 +	if (tsdPtr->socketThread == NULL) {
   1.509 +	    goto unloadLibrary;
   1.510 +	}
   1.511 +
   1.512 +	SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST);
   1.513 +
   1.514 +	/*
   1.515 +	 * Wait for the thread to signal when the window has
   1.516 +	 * been created and if it is ready to go.
   1.517 +	 */
   1.518 +
   1.519 +	WaitForSingleObject(tsdPtr->readyEvent, INFINITE);
   1.520 +
   1.521 +	if (tsdPtr->hwnd == NULL) {
   1.522 +	    goto unloadLibrary; /* Trouble creating the window */
   1.523 +	}
   1.524 +
   1.525 +	Tcl_CreateEventSource(SocketSetupProc, SocketCheckProc, NULL);
   1.526 +    }
   1.527 +    return;
   1.528 +
   1.529 +unloadLibrary:
   1.530 +    TclpFinalizeSockets();
   1.531 +    FreeLibrary(winSock.hModule);
   1.532 +    winSock.hModule = NULL;
   1.533 +    return;
   1.534 +}
   1.535 +
   1.536 +/*
   1.537 + *----------------------------------------------------------------------
   1.538 + *
   1.539 + * SocketsEnabled --
   1.540 + *
   1.541 + *	Check that the WinSock DLL is loaded and ready.
   1.542 + *
   1.543 + * Results:
   1.544 + *	1 if it is.
   1.545 + *
   1.546 + * Side effects:
   1.547 + *	None.
   1.548 + *
   1.549 + *----------------------------------------------------------------------
   1.550 + */
   1.551 +
   1.552 +    /* ARGSUSED */
   1.553 +static int
   1.554 +SocketsEnabled()
   1.555 +{
   1.556 +    int enabled;
   1.557 +    Tcl_MutexLock(&socketMutex);
   1.558 +    enabled = (winSock.hModule != NULL);
   1.559 +    Tcl_MutexUnlock(&socketMutex);
   1.560 +    return enabled;
   1.561 +}
   1.562 +
   1.563 +
   1.564 +/*
   1.565 + *----------------------------------------------------------------------
   1.566 + *
   1.567 + * SocketExitHandler --
   1.568 + *
   1.569 + *	Callback invoked during app exit clean up to delete the socket
   1.570 + *	communication window and to release the WinSock DLL.
   1.571 + *
   1.572 + * Results:
   1.573 + *	None.
   1.574 + *
   1.575 + * Side effects:
   1.576 + *	None.
   1.577 + *
   1.578 + *----------------------------------------------------------------------
   1.579 + */
   1.580 +
   1.581 +    /* ARGSUSED */
   1.582 +static void
   1.583 +SocketExitHandler(clientData)
   1.584 +    ClientData clientData;              /* Not used. */
   1.585 +{
   1.586 +    Tcl_MutexLock(&socketMutex);
   1.587 +    if (winSock.hModule) {
   1.588 +	/*
   1.589 +	 * Make sure the socket event handling window is cleaned-up
   1.590 +	 * for, at most, this thread.
   1.591 +	 */
   1.592 +	TclpFinalizeSockets();
   1.593 +	UnregisterClass("TclSocket", TclWinGetTclInstance());
   1.594 +	winSock.WSACleanup();
   1.595 +	FreeLibrary(winSock.hModule);
   1.596 +	winSock.hModule = NULL;
   1.597 +    }
   1.598 +    initialized = 0;
   1.599 +    hostnameInitialized = 0;
   1.600 +    Tcl_MutexUnlock(&socketMutex);
   1.601 +}
   1.602 +
   1.603 +/*
   1.604 + *----------------------------------------------------------------------
   1.605 + *
   1.606 + * TclpFinalizeSockets --
   1.607 + *
   1.608 + *	This function is called from Tcl_FinalizeThread to finalize
   1.609 + *	the platform specific socket subsystem.
   1.610 + *	Also, it may be called from within this module to cleanup
   1.611 + *	the state if unable to initialize the sockets subsystem.
   1.612 + *
   1.613 + * Results:
   1.614 + *	None.
   1.615 + *
   1.616 + * Side effects:
   1.617 + *	Deletes the event source and destroys the socket thread.
   1.618 + *
   1.619 + *----------------------------------------------------------------------
   1.620 + */
   1.621 +
   1.622 +void
   1.623 +TclpFinalizeSockets()
   1.624 +{
   1.625 +    ThreadSpecificData *tsdPtr;
   1.626 +
   1.627 +    tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
   1.628 +    if (tsdPtr != NULL) {
   1.629 +	if (tsdPtr->socketThread != NULL) {
   1.630 +	    if (tsdPtr->hwnd != NULL) {
   1.631 +		PostMessage(tsdPtr->hwnd, SOCKET_TERMINATE, 0, 0);
   1.632 +		/*
   1.633 +		 * Wait for the thread to exit. This ensures that we are
   1.634 +		 * completely cleaned up before we leave this function.
   1.635 +		 */
   1.636 +		WaitForSingleObject(tsdPtr->readyEvent, INFINITE);
   1.637 +		tsdPtr->hwnd = NULL;
   1.638 +	    }
   1.639 +	    CloseHandle(tsdPtr->socketThread);
   1.640 +	    tsdPtr->socketThread = NULL;
   1.641 +	}
   1.642 +	if (tsdPtr->readyEvent != NULL) {
   1.643 +	    CloseHandle(tsdPtr->readyEvent);
   1.644 +	    tsdPtr->readyEvent = NULL;
   1.645 +	}
   1.646 +	if (tsdPtr->socketListLock != NULL) {
   1.647 +	    CloseHandle(tsdPtr->socketListLock);
   1.648 +	    tsdPtr->socketListLock = NULL;
   1.649 +	}
   1.650 +	Tcl_DeleteEventSource(SocketSetupProc, SocketCheckProc, NULL);
   1.651 +    }
   1.652 +}
   1.653 +
   1.654 +/*
   1.655 + *----------------------------------------------------------------------
   1.656 + *
   1.657 + * TclpHasSockets --
   1.658 + *
   1.659 + *	This function determines whether sockets are available on the
   1.660 + *	current system and returns an error in interp if they are not.
   1.661 + *	Note that interp may be NULL.
   1.662 + *
   1.663 + * Results:
   1.664 + *	Returns TCL_OK if the system supports sockets, or TCL_ERROR with
   1.665 + *	an error in interp.
   1.666 + *
   1.667 + * Side effects:
   1.668 + *	If not already prepared, initializes the TSD structure and
   1.669 + *	socket message handling thread associated to the calling thread
   1.670 + *	for the subsystem of the driver.
   1.671 + *
   1.672 + *----------------------------------------------------------------------
   1.673 + */
   1.674 +
   1.675 +int
   1.676 +TclpHasSockets(interp)
   1.677 +    Tcl_Interp *interp;
   1.678 +{
   1.679 +    Tcl_MutexLock(&socketMutex);
   1.680 +    InitSockets();
   1.681 +    Tcl_MutexUnlock(&socketMutex);
   1.682 +
   1.683 +    if (SocketsEnabled()) {
   1.684 +	return TCL_OK;
   1.685 +    }
   1.686 +    if (interp != NULL) {
   1.687 +	Tcl_AppendResult(interp, "sockets are not available on this system",
   1.688 +		NULL);
   1.689 +    }
   1.690 +    return TCL_ERROR;
   1.691 +}
   1.692 +
   1.693 +/*
   1.694 + *----------------------------------------------------------------------
   1.695 + *
   1.696 + * SocketSetupProc --
   1.697 + *
   1.698 + *	This procedure is invoked before Tcl_DoOneEvent blocks waiting
   1.699 + *	for an event.
   1.700 + *
   1.701 + * Results:
   1.702 + *	None.
   1.703 + *
   1.704 + * Side effects:
   1.705 + *	Adjusts the block time if needed.
   1.706 + *
   1.707 + *----------------------------------------------------------------------
   1.708 + */
   1.709 +
   1.710 +void
   1.711 +SocketSetupProc(data, flags)
   1.712 +    ClientData data;		/* Not used. */
   1.713 +    int flags;			/* Event flags as passed to Tcl_DoOneEvent. */
   1.714 +{
   1.715 +    SocketInfo *infoPtr;
   1.716 +    Tcl_Time blockTime = { 0, 0 };
   1.717 +    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
   1.718 +
   1.719 +    if (!(flags & TCL_FILE_EVENTS)) {
   1.720 +	return;
   1.721 +    }
   1.722 +    
   1.723 +    /*
   1.724 +     * Check to see if there is a ready socket.  If so, poll.
   1.725 +     */
   1.726 +
   1.727 +    WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
   1.728 +    for (infoPtr = tsdPtr->socketList; infoPtr != NULL; 
   1.729 +	    infoPtr = infoPtr->nextPtr) {
   1.730 +	if (infoPtr->readyEvents & infoPtr->watchEvents) {
   1.731 +	    Tcl_SetMaxBlockTime(&blockTime);
   1.732 +	    break;
   1.733 +	}
   1.734 +    }
   1.735 +    SetEvent(tsdPtr->socketListLock);
   1.736 +}
   1.737 +
   1.738 +/*
   1.739 + *----------------------------------------------------------------------
   1.740 + *
   1.741 + * SocketCheckProc --
   1.742 + *
   1.743 + *	This procedure is called by Tcl_DoOneEvent to check the socket
   1.744 + *	event source for events. 
   1.745 + *
   1.746 + * Results:
   1.747 + *	None.
   1.748 + *
   1.749 + * Side effects:
   1.750 + *	May queue an event.
   1.751 + *
   1.752 + *----------------------------------------------------------------------
   1.753 + */
   1.754 +
   1.755 +static void
   1.756 +SocketCheckProc(data, flags)
   1.757 +    ClientData data;		/* Not used. */
   1.758 +    int flags;			/* Event flags as passed to Tcl_DoOneEvent. */
   1.759 +{
   1.760 +    SocketInfo *infoPtr;
   1.761 +    SocketEvent *evPtr;
   1.762 +    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
   1.763 +
   1.764 +    if (!(flags & TCL_FILE_EVENTS)) {
   1.765 +	return;
   1.766 +    }
   1.767 +    
   1.768 +    /*
   1.769 +     * Queue events for any ready sockets that don't already have events
   1.770 +     * queued (caused by persistent states that won't generate WinSock
   1.771 +     * events).
   1.772 +     */
   1.773 +
   1.774 +    WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
   1.775 +    for (infoPtr = tsdPtr->socketList; infoPtr != NULL; 
   1.776 +	    infoPtr = infoPtr->nextPtr) {
   1.777 +	if ((infoPtr->readyEvents & infoPtr->watchEvents)
   1.778 +		&& !(infoPtr->flags & SOCKET_PENDING)) {
   1.779 +	    infoPtr->flags |= SOCKET_PENDING;
   1.780 +	    evPtr = (SocketEvent *) ckalloc(sizeof(SocketEvent));
   1.781 +	    evPtr->header.proc = SocketEventProc;
   1.782 +	    evPtr->socket = infoPtr->socket;
   1.783 +	    Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
   1.784 +	}
   1.785 +    }
   1.786 +    SetEvent(tsdPtr->socketListLock);
   1.787 +}
   1.788 +
   1.789 +/*
   1.790 + *----------------------------------------------------------------------
   1.791 + *
   1.792 + * SocketEventProc --
   1.793 + *
   1.794 + *	This procedure is called by Tcl_ServiceEvent when a socket event
   1.795 + *	reaches the front of the event queue.  This procedure is
   1.796 + *	responsible for notifying the generic channel code.
   1.797 + *
   1.798 + * Results:
   1.799 + *	Returns 1 if the event was handled, meaning it should be removed
   1.800 + *	from the queue.  Returns 0 if the event was not handled, meaning
   1.801 + *	it should stay on the queue.  The only time the event isn't
   1.802 + *	handled is if the TCL_FILE_EVENTS flag bit isn't set.
   1.803 + *
   1.804 + * Side effects:
   1.805 + *	Whatever the channel callback procedures do.
   1.806 + *
   1.807 + *----------------------------------------------------------------------
   1.808 + */
   1.809 +
   1.810 +static int
   1.811 +SocketEventProc(evPtr, flags)
   1.812 +    Tcl_Event *evPtr;		/* Event to service. */
   1.813 +    int flags;			/* Flags that indicate what events to
   1.814 +				 * handle, such as TCL_FILE_EVENTS. */
   1.815 +{
   1.816 +    SocketInfo *infoPtr;
   1.817 +    SocketEvent *eventPtr = (SocketEvent *) evPtr;
   1.818 +    int mask = 0;
   1.819 +    int events;
   1.820 +    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
   1.821 +
   1.822 +    if (!(flags & TCL_FILE_EVENTS)) {
   1.823 +	return 0;
   1.824 +    }
   1.825 +
   1.826 +    /*
   1.827 +     * Find the specified socket on the socket list.
   1.828 +     */
   1.829 +
   1.830 +    WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
   1.831 +    for (infoPtr = tsdPtr->socketList; infoPtr != NULL; 
   1.832 +	    infoPtr = infoPtr->nextPtr) {
   1.833 +	if (infoPtr->socket == eventPtr->socket) {
   1.834 +	    break;
   1.835 +	}
   1.836 +    }
   1.837 +    SetEvent(tsdPtr->socketListLock);
   1.838 +
   1.839 +    /*
   1.840 +     * Discard events that have gone stale.
   1.841 +     */
   1.842 +
   1.843 +    if (!infoPtr) {
   1.844 +	return 1;
   1.845 +    }
   1.846 +
   1.847 +    infoPtr->flags &= ~SOCKET_PENDING;
   1.848 +
   1.849 +    /*
   1.850 +     * Handle connection requests directly.
   1.851 +     */
   1.852 +
   1.853 +    if (infoPtr->readyEvents & FD_ACCEPT) {
   1.854 +	TcpAccept(infoPtr);
   1.855 +	return 1;
   1.856 +    }
   1.857 +
   1.858 +    /*
   1.859 +     * Mask off unwanted events and compute the read/write mask so 
   1.860 +     * we can notify the channel.
   1.861 +     */
   1.862 +
   1.863 +    events = infoPtr->readyEvents & infoPtr->watchEvents;
   1.864 +
   1.865 +    if (events & FD_CLOSE) {
   1.866 +	/*
   1.867 +	 * If the socket was closed and the channel is still interested
   1.868 +	 * in read events, then we need to ensure that we keep polling
   1.869 +	 * for this event until someone does something with the channel.
   1.870 +	 * Note that we do this before calling Tcl_NotifyChannel so we don't
   1.871 +	 * have to watch out for the channel being deleted out from under
   1.872 +	 * us.  This may cause a redundant trip through the event loop, but
   1.873 +	 * it's simpler than trying to do unwind protection.
   1.874 +	 */
   1.875 +
   1.876 +	Tcl_Time blockTime = { 0, 0 };
   1.877 +	Tcl_SetMaxBlockTime(&blockTime);
   1.878 +	mask |= TCL_READABLE|TCL_WRITABLE;
   1.879 +    } else if (events & FD_READ) {
   1.880 +	fd_set readFds;
   1.881 +	struct timeval timeout;
   1.882 +
   1.883 +	/*
   1.884 +	 * We must check to see if data is really available, since someone
   1.885 +	 * could have consumed the data in the meantime.  Turn off async
   1.886 +	 * notification so select will work correctly.	If the socket is
   1.887 +	 * still readable, notify the channel driver, otherwise reset the
   1.888 +	 * async select handler and keep waiting.
   1.889 +	 */
   1.890 +
   1.891 +	SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
   1.892 +		(WPARAM) UNSELECT, (LPARAM) infoPtr);
   1.893 +
   1.894 +	FD_ZERO(&readFds);
   1.895 +	FD_SET(infoPtr->socket, &readFds);
   1.896 +	timeout.tv_usec = 0;
   1.897 +	timeout.tv_sec = 0;
   1.898 + 
   1.899 +	if (winSock.select(0, &readFds, NULL, NULL, &timeout) != 0) {
   1.900 +	    mask |= TCL_READABLE;
   1.901 +	} else {
   1.902 +	    infoPtr->readyEvents &= ~(FD_READ);
   1.903 +	    SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
   1.904 +		    (WPARAM) SELECT, (LPARAM) infoPtr);
   1.905 +	}
   1.906 +    }
   1.907 +    if (events & (FD_WRITE | FD_CONNECT)) {
   1.908 +	mask |= TCL_WRITABLE;
   1.909 +	if (events & FD_CONNECT && infoPtr->lastError != NO_ERROR) {
   1.910 +	    /* connect errors should also fire the readable handler. */
   1.911 +	    mask |= TCL_READABLE;
   1.912 +	}
   1.913 +    }
   1.914 +
   1.915 +    if (mask) {
   1.916 +	Tcl_NotifyChannel(infoPtr->channel, mask);
   1.917 +    }
   1.918 +    return 1;
   1.919 +}
   1.920 +
   1.921 +/*
   1.922 + *----------------------------------------------------------------------
   1.923 + *
   1.924 + * TcpBlockProc --
   1.925 + *
   1.926 + *	Sets a socket into blocking or non-blocking mode.
   1.927 + *
   1.928 + * Results:
   1.929 + *	0 if successful, errno if there was an error.
   1.930 + *
   1.931 + * Side effects:
   1.932 + *	None.
   1.933 + *
   1.934 + *----------------------------------------------------------------------
   1.935 + */
   1.936 +
   1.937 +static int
   1.938 +TcpBlockProc(instanceData, mode)
   1.939 +    ClientData	instanceData;	/* The socket to block/un-block. */
   1.940 +    int mode;			/* TCL_MODE_BLOCKING or
   1.941 +                                 * TCL_MODE_NONBLOCKING. */
   1.942 +{
   1.943 +    SocketInfo *infoPtr = (SocketInfo *) instanceData;
   1.944 +
   1.945 +    if (mode == TCL_MODE_NONBLOCKING) {
   1.946 +	infoPtr->flags |= SOCKET_ASYNC;
   1.947 +    } else {
   1.948 +	infoPtr->flags &= ~(SOCKET_ASYNC);
   1.949 +    }
   1.950 +    return 0;
   1.951 +}
   1.952 +
   1.953 +/*
   1.954 + *----------------------------------------------------------------------
   1.955 + *
   1.956 + * TcpCloseProc --
   1.957 + *
   1.958 + *	This procedure is called by the generic IO level to perform
   1.959 + *	channel type specific cleanup on a socket based channel
   1.960 + *	when the channel is closed.
   1.961 + *
   1.962 + * Results:
   1.963 + *	0 if successful, the value of errno if failed.
   1.964 + *
   1.965 + * Side effects:
   1.966 + *	Closes the socket.
   1.967 + *
   1.968 + *----------------------------------------------------------------------
   1.969 + */
   1.970 +
   1.971 +    /* ARGSUSED */
   1.972 +static int
   1.973 +TcpCloseProc(instanceData, interp)
   1.974 +    ClientData instanceData;	/* The socket to close. */
   1.975 +    Tcl_Interp *interp;		/* Unused. */
   1.976 +{
   1.977 +    SocketInfo *infoPtr = (SocketInfo *) instanceData;
   1.978 +    /* TIP #218 */
   1.979 +    int errorCode = 0;
   1.980 +    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
   1.981 +
   1.982 +    /*
   1.983 +     * Check that WinSock is initialized; do not call it if not, to
   1.984 +     * prevent system crashes. This can happen at exit time if the exit
   1.985 +     * handler for WinSock ran before other exit handlers that want to
   1.986 +     * use sockets.
   1.987 +     */
   1.988 +
   1.989 +    if (SocketsEnabled()) {
   1.990 +        
   1.991 +	/*
   1.992 +         * Clean up the OS socket handle.  The default Windows setting
   1.993 +	 * for a socket is SO_DONTLINGER, which does a graceful shutdown
   1.994 +	 * in the background.
   1.995 +         */
   1.996 +    
   1.997 +        if (winSock.closesocket(infoPtr->socket) == SOCKET_ERROR) {
   1.998 +            TclWinConvertWSAError((DWORD) winSock.WSAGetLastError());
   1.999 +            errorCode = Tcl_GetErrno();
  1.1000 +        }
  1.1001 +    }
  1.1002 +
  1.1003 +    /* TIP #218. Removed the code removing the structure
  1.1004 +     * from the global socket list. This is now done by
  1.1005 +     * the thread action callbacks, and only there. This
  1.1006 +     * happens before this code is called. We can free
  1.1007 +     * without fear of damanging the list.
  1.1008 +     */
  1.1009 +    ckfree((char *) infoPtr);
  1.1010 +    return errorCode;
  1.1011 +}
  1.1012 +
  1.1013 +/*
  1.1014 + *----------------------------------------------------------------------
  1.1015 + *
  1.1016 + * NewSocketInfo --
  1.1017 + *
  1.1018 + *	This function allocates and initializes a new SocketInfo
  1.1019 + *	structure.
  1.1020 + *
  1.1021 + * Results:
  1.1022 + *	Returns a newly allocated SocketInfo.
  1.1023 + *
  1.1024 + * Side effects:
  1.1025 + *	None, except for allocation of memory.
  1.1026 + *
  1.1027 + *----------------------------------------------------------------------
  1.1028 + */
  1.1029 +
  1.1030 +static SocketInfo *
  1.1031 +NewSocketInfo(socket)
  1.1032 +    SOCKET socket;
  1.1033 +{
  1.1034 +    SocketInfo *infoPtr;
  1.1035 +
  1.1036 +    infoPtr = (SocketInfo *) ckalloc((unsigned) sizeof(SocketInfo));
  1.1037 +    infoPtr->socket = socket;
  1.1038 +    infoPtr->flags = 0;
  1.1039 +    infoPtr->watchEvents = 0;
  1.1040 +    infoPtr->readyEvents = 0;
  1.1041 +    infoPtr->selectEvents = 0;
  1.1042 +    infoPtr->acceptEventCount = 0;
  1.1043 +    infoPtr->acceptProc = NULL;
  1.1044 +    infoPtr->lastError = 0;
  1.1045 +
  1.1046 +    /* TIP #218. Removed the code inserting the new structure
  1.1047 +     * into the global list. This is now handled in the thread
  1.1048 +     * action callbacks, and only there.
  1.1049 +     */
  1.1050 +    infoPtr->nextPtr = NULL;
  1.1051 +    
  1.1052 +    return infoPtr;
  1.1053 +}
  1.1054 +
  1.1055 +/*
  1.1056 + *----------------------------------------------------------------------
  1.1057 + *
  1.1058 + * CreateSocket --
  1.1059 + *
  1.1060 + *	This function opens a new socket and initializes the
  1.1061 + *	SocketInfo structure.
  1.1062 + *
  1.1063 + * Results:
  1.1064 + *	Returns a new SocketInfo, or NULL with an error in interp.
  1.1065 + *
  1.1066 + * Side effects:
  1.1067 + *	None, except for allocation of memory.
  1.1068 + *
  1.1069 + *----------------------------------------------------------------------
  1.1070 + */
  1.1071 +
  1.1072 +static SocketInfo *
  1.1073 +CreateSocket(interp, port, host, server, myaddr, myport, async)
  1.1074 +    Tcl_Interp *interp;		/* For error reporting; can be NULL. */
  1.1075 +    int port;			/* Port number to open. */
  1.1076 +    CONST char *host;		/* Name of host on which to open port. */
  1.1077 +    int server;			/* 1 if socket should be a server socket,
  1.1078 +				 * else 0 for a client socket. */
  1.1079 +    CONST char *myaddr;		/* Optional client-side address */
  1.1080 +    int myport;			/* Optional client-side port */
  1.1081 +    int async;			/* If nonzero, connect client socket
  1.1082 +				 * asynchronously. */
  1.1083 +{
  1.1084 +    u_long flag = 1;		/* Indicates nonblocking mode. */
  1.1085 +    int asyncConnect = 0;	/* Will be 1 if async connect is
  1.1086 +				 * in progress. */
  1.1087 +    SOCKADDR_IN sockaddr;	/* Socket address */
  1.1088 +    SOCKADDR_IN mysockaddr;	/* Socket address for client */
  1.1089 +    SOCKET sock = INVALID_SOCKET;
  1.1090 +    SocketInfo *infoPtr;	/* The returned value. */
  1.1091 +    ThreadSpecificData *tsdPtr = 
  1.1092 +	(ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
  1.1093 +
  1.1094 +    /*
  1.1095 +     * Check that WinSock is initialized; do not call it if not, to
  1.1096 +     * prevent system crashes. This can happen at exit time if the exit
  1.1097 +     * handler for WinSock ran before other exit handlers that want to
  1.1098 +     * use sockets.
  1.1099 +     */
  1.1100 +
  1.1101 +    if (!SocketsEnabled()) {
  1.1102 +        return NULL;
  1.1103 +    }
  1.1104 +
  1.1105 +    if (! CreateSocketAddress(&sockaddr, host, port)) {
  1.1106 +	goto error;
  1.1107 +    }
  1.1108 +    if ((myaddr != NULL || myport != 0) &&
  1.1109 +	    ! CreateSocketAddress(&mysockaddr, myaddr, myport)) {
  1.1110 +	goto error;
  1.1111 +    }
  1.1112 +
  1.1113 +    sock = winSock.socket(AF_INET, SOCK_STREAM, 0);
  1.1114 +    if (sock == INVALID_SOCKET) {
  1.1115 +	goto error;
  1.1116 +    }
  1.1117 +
  1.1118 +    /*
  1.1119 +     * Win-NT has a misfeature that sockets are inherited in child
  1.1120 +     * processes by default.  Turn off the inherit bit.
  1.1121 +     */
  1.1122 +
  1.1123 +    SetHandleInformation( (HANDLE) sock, HANDLE_FLAG_INHERIT, 0 );
  1.1124 +	
  1.1125 +    /*
  1.1126 +     * Set kernel space buffering
  1.1127 +     */
  1.1128 +
  1.1129 +    TclSockMinimumBuffers((int) sock, TCP_BUFFER_SIZE);
  1.1130 +
  1.1131 +    if (server) {
  1.1132 +	/*
  1.1133 +	 * Bind to the specified port.  Note that we must not call setsockopt
  1.1134 +	 * with SO_REUSEADDR because Microsoft allows addresses to be reused
  1.1135 +	 * even if they are still in use.
  1.1136 +         *
  1.1137 +         * Bind should not be affected by the socket having already been
  1.1138 +         * set into nonblocking mode. If there is trouble, this is one place
  1.1139 +         * to look for bugs.
  1.1140 +	 */
  1.1141 +    
  1.1142 +	if (winSock.bind(sock, (SOCKADDR *) &sockaddr,
  1.1143 +		sizeof(SOCKADDR_IN)) == SOCKET_ERROR) {
  1.1144 +            goto error;
  1.1145 +        }
  1.1146 +
  1.1147 +        /*
  1.1148 +         * Set the maximum number of pending connect requests to the
  1.1149 +         * max value allowed on each platform (Win32 and Win32s may be
  1.1150 +         * different, and there may be differences between TCP/IP stacks).
  1.1151 +         */
  1.1152 +        
  1.1153 +	if (winSock.listen(sock, SOMAXCONN) == SOCKET_ERROR) {
  1.1154 +	    goto error;
  1.1155 +	}
  1.1156 +
  1.1157 +	/*
  1.1158 +	 * Add this socket to the global list of sockets.
  1.1159 +	 */
  1.1160 +
  1.1161 +	infoPtr = NewSocketInfo(sock);
  1.1162 +
  1.1163 +	/*
  1.1164 +	 * Set up the select mask for connection request events.
  1.1165 +	 */
  1.1166 +
  1.1167 +	infoPtr->selectEvents = FD_ACCEPT;
  1.1168 +	infoPtr->watchEvents |= FD_ACCEPT;
  1.1169 +
  1.1170 +    } else {
  1.1171 +
  1.1172 +        /*
  1.1173 +         * Try to bind to a local port, if specified.
  1.1174 +         */
  1.1175 +        
  1.1176 +	if (myaddr != NULL || myport != 0) { 
  1.1177 +	    if (winSock.bind(sock, (SOCKADDR *) &mysockaddr,
  1.1178 +		    sizeof(SOCKADDR_IN)) == SOCKET_ERROR) {
  1.1179 +		goto error;
  1.1180 +	    }
  1.1181 +	}            
  1.1182 +    
  1.1183 +	/*
  1.1184 +	 * Set the socket into nonblocking mode if the connect should be
  1.1185 +	 * done in the background.
  1.1186 +	 */
  1.1187 +    
  1.1188 +	if (async) {
  1.1189 +	    if (winSock.ioctlsocket(sock, (long) FIONBIO, &flag) == SOCKET_ERROR) {
  1.1190 +		goto error;
  1.1191 +	    }
  1.1192 +	}
  1.1193 +
  1.1194 +	/*
  1.1195 +	 * Attempt to connect to the remote socket.
  1.1196 +	 */
  1.1197 +
  1.1198 +	if (winSock.connect(sock, (SOCKADDR *) &sockaddr,
  1.1199 +		sizeof(SOCKADDR_IN)) == SOCKET_ERROR) {
  1.1200 +            TclWinConvertWSAError((DWORD) winSock.WSAGetLastError());
  1.1201 +	    if (Tcl_GetErrno() != EWOULDBLOCK) {
  1.1202 +		goto error;
  1.1203 +	    }
  1.1204 +
  1.1205 +	    /*
  1.1206 +	     * The connection is progressing in the background.
  1.1207 +	     */
  1.1208 +
  1.1209 +	    asyncConnect = 1;
  1.1210 +        }
  1.1211 +
  1.1212 +	/*
  1.1213 +	 * Add this socket to the global list of sockets.
  1.1214 +	 */
  1.1215 +
  1.1216 +	infoPtr = NewSocketInfo(sock);
  1.1217 +
  1.1218 +	/*
  1.1219 +	 * Set up the select mask for read/write events.  If the connect
  1.1220 +	 * attempt has not completed, include connect events.
  1.1221 +	 */
  1.1222 +
  1.1223 +	infoPtr->selectEvents = FD_READ | FD_WRITE | FD_CLOSE;
  1.1224 +	if (asyncConnect) {
  1.1225 +	    infoPtr->flags |= SOCKET_ASYNC_CONNECT;
  1.1226 +	    infoPtr->selectEvents |= FD_CONNECT;
  1.1227 +	}
  1.1228 +    }
  1.1229 +
  1.1230 +    /*
  1.1231 +     * Register for interest in events in the select mask.  Note that this
  1.1232 +     * automatically places the socket into non-blocking mode.
  1.1233 +     */
  1.1234 +
  1.1235 +    winSock.ioctlsocket(sock, (long) FIONBIO, &flag);
  1.1236 +    SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
  1.1237 +	    (WPARAM) SELECT, (LPARAM) infoPtr);
  1.1238 +
  1.1239 +    return infoPtr;
  1.1240 +
  1.1241 +error:
  1.1242 +    TclWinConvertWSAError((DWORD) winSock.WSAGetLastError());
  1.1243 +    if (interp != NULL) {
  1.1244 +	Tcl_AppendResult(interp, "couldn't open socket: ",
  1.1245 +		Tcl_PosixError(interp), (char *) NULL);
  1.1246 +    }
  1.1247 +    if (sock != INVALID_SOCKET) {
  1.1248 +	winSock.closesocket(sock);
  1.1249 +    }
  1.1250 +    return NULL;
  1.1251 +}
  1.1252 +
  1.1253 +/*
  1.1254 + *----------------------------------------------------------------------
  1.1255 + *
  1.1256 + * CreateSocketAddress --
  1.1257 + *
  1.1258 + *	This function initializes a sockaddr structure for a host and port.
  1.1259 + *
  1.1260 + * Results:
  1.1261 + *	1 if the host was valid, 0 if the host could not be converted to
  1.1262 + *	an IP address.
  1.1263 + *
  1.1264 + * Side effects:
  1.1265 + *	Fills in the *sockaddrPtr structure.
  1.1266 + *
  1.1267 + *----------------------------------------------------------------------
  1.1268 + */
  1.1269 +
  1.1270 +static int
  1.1271 +CreateSocketAddress(sockaddrPtr, host, port)
  1.1272 +    LPSOCKADDR_IN sockaddrPtr;		/* Socket address */
  1.1273 +    CONST char *host;			/* Host.  NULL implies INADDR_ANY */
  1.1274 +    int port;				/* Port number */
  1.1275 +{
  1.1276 +    struct hostent *hostent;		/* Host database entry */
  1.1277 +    struct in_addr addr;		/* For 64/32 bit madness */
  1.1278 +
  1.1279 +    /*
  1.1280 +     * Check that WinSock is initialized; do not call it if not, to
  1.1281 +     * prevent system crashes. This can happen at exit time if the exit
  1.1282 +     * handler for WinSock ran before other exit handlers that want to
  1.1283 +     * use sockets.
  1.1284 +     */
  1.1285 +
  1.1286 +    if (!SocketsEnabled()) {
  1.1287 +        Tcl_SetErrno(EFAULT);
  1.1288 +        return 0;
  1.1289 +    }
  1.1290 +
  1.1291 +    ZeroMemory(sockaddrPtr, sizeof(SOCKADDR_IN));
  1.1292 +    sockaddrPtr->sin_family = AF_INET;
  1.1293 +    sockaddrPtr->sin_port = winSock.htons((u_short) (port & 0xFFFF));
  1.1294 +    if (host == NULL) {
  1.1295 +	addr.s_addr = INADDR_ANY;
  1.1296 +    } else {
  1.1297 +        addr.s_addr = winSock.inet_addr(host);
  1.1298 +        if (addr.s_addr == INADDR_NONE) {
  1.1299 +            hostent = winSock.gethostbyname(host);
  1.1300 +            if (hostent != NULL) {
  1.1301 +                memcpy(&addr, hostent->h_addr, (size_t) hostent->h_length);
  1.1302 +            } else {
  1.1303 +#ifdef	EHOSTUNREACH
  1.1304 +                Tcl_SetErrno(EHOSTUNREACH);
  1.1305 +#else
  1.1306 +#ifdef ENXIO
  1.1307 +                Tcl_SetErrno(ENXIO);
  1.1308 +#endif
  1.1309 +#endif
  1.1310 +		return 0;	/* Error. */
  1.1311 +	    }
  1.1312 +	}
  1.1313 +    }
  1.1314 +
  1.1315 +    /*
  1.1316 +     * NOTE: On 64 bit machines the assignment below is rumored to not
  1.1317 +     * do the right thing. Please report errors related to this if you
  1.1318 +     * observe incorrect behavior on 64 bit machines such as DEC Alphas.
  1.1319 +     * Should we modify this code to do an explicit memcpy?
  1.1320 +     */
  1.1321 +
  1.1322 +    sockaddrPtr->sin_addr.s_addr = addr.s_addr;
  1.1323 +    return 1;	/* Success. */
  1.1324 +}
  1.1325 +
  1.1326 +/*
  1.1327 + *----------------------------------------------------------------------
  1.1328 + *
  1.1329 + * WaitForSocketEvent --
  1.1330 + *
  1.1331 + *	Waits until one of the specified events occurs on a socket.
  1.1332 + *
  1.1333 + * Results:
  1.1334 + *	Returns 1 on success or 0 on failure, with an error code in
  1.1335 + *	errorCodePtr.
  1.1336 + *
  1.1337 + * Side effects:
  1.1338 + *	Processes socket events off the system queue.
  1.1339 + *
  1.1340 + *----------------------------------------------------------------------
  1.1341 + */
  1.1342 +
  1.1343 +static int
  1.1344 +WaitForSocketEvent(infoPtr, events, errorCodePtr)
  1.1345 +    SocketInfo *infoPtr;	/* Information about this socket. */
  1.1346 +    int events;			/* Events to look for. */
  1.1347 +    int *errorCodePtr;		/* Where to store errors? */
  1.1348 +{
  1.1349 +    int result = 1;
  1.1350 +    int oldMode;
  1.1351 +    ThreadSpecificData *tsdPtr = 
  1.1352 +	(ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
  1.1353 +
  1.1354 +    /*
  1.1355 +     * Be sure to disable event servicing so we are truly modal.
  1.1356 +     */
  1.1357 +
  1.1358 +    oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE);
  1.1359 +    
  1.1360 +    /*
  1.1361 +     * Reset WSAAsyncSelect so we have a fresh set of events pending.
  1.1362 +     */
  1.1363 +
  1.1364 +    SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
  1.1365 +	    (WPARAM) UNSELECT, (LPARAM) infoPtr);
  1.1366 +
  1.1367 +    SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
  1.1368 +	    (WPARAM) SELECT, (LPARAM) infoPtr);
  1.1369 +
  1.1370 +    while (1) {
  1.1371 +
  1.1372 +	if (infoPtr->lastError) {
  1.1373 +	    *errorCodePtr = infoPtr->lastError;
  1.1374 +	    result = 0;
  1.1375 +	    break;
  1.1376 +	} else if (infoPtr->readyEvents & events) {
  1.1377 +	    break;
  1.1378 +	} else if (infoPtr->flags & SOCKET_ASYNC) {
  1.1379 +	    *errorCodePtr = EWOULDBLOCK;
  1.1380 +	    result = 0;
  1.1381 +	    break;
  1.1382 +	}
  1.1383 +
  1.1384 +	/*
  1.1385 +	 * Wait until something happens.
  1.1386 +	 */
  1.1387 +	WaitForSingleObject(tsdPtr->readyEvent, INFINITE);
  1.1388 +    }
  1.1389 +    
  1.1390 +    (void) Tcl_SetServiceMode(oldMode);
  1.1391 +    return result;
  1.1392 +}
  1.1393 +
  1.1394 +/*
  1.1395 + *----------------------------------------------------------------------
  1.1396 + *
  1.1397 + * Tcl_OpenTcpClient --
  1.1398 + *
  1.1399 + *	Opens a TCP client socket and creates a channel around it.
  1.1400 + *
  1.1401 + * Results:
  1.1402 + *	The channel or NULL if failed.  An error message is returned
  1.1403 + *	in the interpreter on failure.
  1.1404 + *
  1.1405 + * Side effects:
  1.1406 + *	Opens a client socket and creates a new channel.
  1.1407 + *
  1.1408 + *----------------------------------------------------------------------
  1.1409 + */
  1.1410 +
  1.1411 +Tcl_Channel
  1.1412 +Tcl_OpenTcpClient(interp, port, host, myaddr, myport, async)
  1.1413 +    Tcl_Interp *interp;			/* For error reporting; can be NULL. */
  1.1414 +    int port;				/* Port number to open. */
  1.1415 +    CONST char *host;			/* Host on which to open port. */
  1.1416 +    CONST char *myaddr;			/* Client-side address */
  1.1417 +    int myport;				/* Client-side port */
  1.1418 +    int async;				/* If nonzero, should connect
  1.1419 +                                         * client socket asynchronously. */
  1.1420 +{
  1.1421 +    SocketInfo *infoPtr;
  1.1422 +    char channelName[16 + TCL_INTEGER_SPACE];
  1.1423 +
  1.1424 +    if (TclpHasSockets(interp) != TCL_OK) {
  1.1425 +	return NULL;
  1.1426 +    }
  1.1427 +
  1.1428 +    /*
  1.1429 +     * Create a new client socket and wrap it in a channel.
  1.1430 +     */
  1.1431 +
  1.1432 +    infoPtr = CreateSocket(interp, port, host, 0, myaddr, myport, async);
  1.1433 +    if (infoPtr == NULL) {
  1.1434 +	return NULL;
  1.1435 +    }
  1.1436 +
  1.1437 +    wsprintfA(channelName, "sock%d", infoPtr->socket);
  1.1438 +
  1.1439 +    infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
  1.1440 +	    (ClientData) infoPtr, (TCL_READABLE | TCL_WRITABLE));
  1.1441 +    if (Tcl_SetChannelOption(interp, infoPtr->channel, "-translation",
  1.1442 +	    "auto crlf") == TCL_ERROR) {
  1.1443 +        Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel);
  1.1444 +        return (Tcl_Channel) NULL;
  1.1445 +    }
  1.1446 +    if (Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "")
  1.1447 +	    == TCL_ERROR) {
  1.1448 +        Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel);
  1.1449 +        return (Tcl_Channel) NULL;
  1.1450 +    }
  1.1451 +    return infoPtr->channel;
  1.1452 +}
  1.1453 +
  1.1454 +/*
  1.1455 + *----------------------------------------------------------------------
  1.1456 + *
  1.1457 + * Tcl_MakeTcpClientChannel --
  1.1458 + *
  1.1459 + *	Creates a Tcl_Channel from an existing client TCP socket.
  1.1460 + *
  1.1461 + * Results:
  1.1462 + *	The Tcl_Channel wrapped around the preexisting TCP socket.
  1.1463 + *
  1.1464 + * Side effects:
  1.1465 + *	None.
  1.1466 + *
  1.1467 + * NOTE: Code contributed by Mark Diekhans (markd@grizzly.com)
  1.1468 + *
  1.1469 + *----------------------------------------------------------------------
  1.1470 + */
  1.1471 +
  1.1472 +Tcl_Channel
  1.1473 +Tcl_MakeTcpClientChannel(sock)
  1.1474 +    ClientData sock;		/* The socket to wrap up into a channel. */
  1.1475 +{
  1.1476 +    SocketInfo *infoPtr;
  1.1477 +    char channelName[16 + TCL_INTEGER_SPACE];
  1.1478 +    ThreadSpecificData *tsdPtr;
  1.1479 +
  1.1480 +    if (TclpHasSockets(NULL) != TCL_OK) {
  1.1481 +	return NULL;
  1.1482 +    }
  1.1483 +
  1.1484 +    tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
  1.1485 +
  1.1486 +    /*
  1.1487 +     * Set kernel space buffering and non-blocking.
  1.1488 +     */
  1.1489 +
  1.1490 +    TclSockMinimumBuffers((int) sock, TCP_BUFFER_SIZE);
  1.1491 +
  1.1492 +    infoPtr = NewSocketInfo((SOCKET) sock);
  1.1493 +
  1.1494 +    /*
  1.1495 +     * Start watching for read/write events on the socket.
  1.1496 +     */
  1.1497 +
  1.1498 +    infoPtr->selectEvents = FD_READ | FD_CLOSE | FD_WRITE;
  1.1499 +    SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
  1.1500 +	    (WPARAM) SELECT, (LPARAM) infoPtr);
  1.1501 +
  1.1502 +    wsprintfA(channelName, "sock%d", infoPtr->socket);
  1.1503 +    infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
  1.1504 +	    (ClientData) infoPtr, (TCL_READABLE | TCL_WRITABLE));
  1.1505 +    Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto crlf");
  1.1506 +    return infoPtr->channel;
  1.1507 +}
  1.1508 +
  1.1509 +/*
  1.1510 + *----------------------------------------------------------------------
  1.1511 + *
  1.1512 + * Tcl_OpenTcpServer --
  1.1513 + *
  1.1514 + *	Opens a TCP server socket and creates a channel around it.
  1.1515 + *
  1.1516 + * Results:
  1.1517 + *	The channel or NULL if failed.  An error message is returned
  1.1518 + *	in the interpreter on failure.
  1.1519 + *
  1.1520 + * Side effects:
  1.1521 + *	Opens a server socket and creates a new channel.
  1.1522 + *
  1.1523 + *----------------------------------------------------------------------
  1.1524 + */
  1.1525 +
  1.1526 +Tcl_Channel
  1.1527 +Tcl_OpenTcpServer(interp, port, host, acceptProc, acceptProcData)
  1.1528 +    Tcl_Interp *interp;			/* For error reporting - may be
  1.1529 +                                         * NULL. */
  1.1530 +    int port;				/* Port number to open. */
  1.1531 +    CONST char *host;			/* Name of local host. */
  1.1532 +    Tcl_TcpAcceptProc *acceptProc;	/* Callback for accepting connections
  1.1533 +                                         * from new clients. */
  1.1534 +    ClientData acceptProcData;		/* Data for the callback. */
  1.1535 +{
  1.1536 +    SocketInfo *infoPtr;
  1.1537 +    char channelName[16 + TCL_INTEGER_SPACE];
  1.1538 +
  1.1539 +    if (TclpHasSockets(interp) != TCL_OK) {
  1.1540 +	return NULL;
  1.1541 +    }
  1.1542 +
  1.1543 +    /*
  1.1544 +     * Create a new client socket and wrap it in a channel.
  1.1545 +     */
  1.1546 +
  1.1547 +    infoPtr = CreateSocket(interp, port, host, 1, NULL, 0, 0);
  1.1548 +    if (infoPtr == NULL) {
  1.1549 +	return NULL;
  1.1550 +    }
  1.1551 +
  1.1552 +    infoPtr->acceptProc = acceptProc;
  1.1553 +    infoPtr->acceptProcData = acceptProcData;
  1.1554 +
  1.1555 +    wsprintfA(channelName, "sock%d", infoPtr->socket);
  1.1556 +
  1.1557 +    infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
  1.1558 +	    (ClientData) infoPtr, 0);
  1.1559 +    if (Tcl_SetChannelOption(interp, infoPtr->channel, "-eofchar", "")
  1.1560 +	    == TCL_ERROR) {
  1.1561 +        Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel);
  1.1562 +        return (Tcl_Channel) NULL;
  1.1563 +    }
  1.1564 +
  1.1565 +    return infoPtr->channel;
  1.1566 +}
  1.1567 +
  1.1568 +/*
  1.1569 + *----------------------------------------------------------------------
  1.1570 + *
  1.1571 + * TcpAccept --
  1.1572 + *	Accept a TCP socket connection.  This is called by
  1.1573 + *	SocketEventProc and it in turns calls the registered accept
  1.1574 + *	procedure.
  1.1575 + *
  1.1576 + * Results:
  1.1577 + *	None.
  1.1578 + *
  1.1579 + * Side effects:
  1.1580 + *	Invokes the accept proc which may invoke arbitrary Tcl code.
  1.1581 + *
  1.1582 + *----------------------------------------------------------------------
  1.1583 + */
  1.1584 +
  1.1585 +static void
  1.1586 +TcpAccept(infoPtr)
  1.1587 +    SocketInfo *infoPtr;	/* Socket to accept. */
  1.1588 +{
  1.1589 +    SOCKET newSocket;
  1.1590 +    SocketInfo *newInfoPtr;
  1.1591 +    SOCKADDR_IN addr;
  1.1592 +    int len;
  1.1593 +    char channelName[16 + TCL_INTEGER_SPACE];
  1.1594 +    ThreadSpecificData *tsdPtr = 
  1.1595 +	(ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
  1.1596 +
  1.1597 +    /*
  1.1598 +     * Accept the incoming connection request.
  1.1599 +     */
  1.1600 +
  1.1601 +    len = sizeof(SOCKADDR_IN);
  1.1602 +
  1.1603 +    newSocket = winSock.accept(infoPtr->socket, (SOCKADDR *)&addr,
  1.1604 +	    &len);
  1.1605 +
  1.1606 +    /*
  1.1607 +     * Clear the ready mask so we can detect the next connection request.
  1.1608 +     * Note that connection requests are level triggered, so if there is
  1.1609 +     * a request already pending, a new event will be generated.
  1.1610 +     */
  1.1611 +
  1.1612 +    if (newSocket == INVALID_SOCKET) {
  1.1613 +	infoPtr->acceptEventCount = 0;
  1.1614 +	infoPtr->readyEvents &= ~(FD_ACCEPT);
  1.1615 +	return;
  1.1616 +    }
  1.1617 +
  1.1618 +    /*
  1.1619 +     * It is possible that more than one FD_ACCEPT has been sent, so an extra
  1.1620 +     * count must be kept.  Decrement the count, and reset the readyEvent bit
  1.1621 +     * if the count is no longer > 0.
  1.1622 +     */
  1.1623 +
  1.1624 +    infoPtr->acceptEventCount--;
  1.1625 +
  1.1626 +    if (infoPtr->acceptEventCount <= 0) {
  1.1627 +	infoPtr->readyEvents &= ~(FD_ACCEPT);
  1.1628 +    }
  1.1629 +
  1.1630 +    /*
  1.1631 +     * Win-NT has a misfeature that sockets are inherited in child
  1.1632 +     * processes by default.  Turn off the inherit bit.
  1.1633 +     */
  1.1634 +
  1.1635 +    SetHandleInformation( (HANDLE) newSocket, HANDLE_FLAG_INHERIT, 0 );
  1.1636 +
  1.1637 +    /*
  1.1638 +     * Add this socket to the global list of sockets.
  1.1639 +     */
  1.1640 +
  1.1641 +    newInfoPtr = NewSocketInfo(newSocket);
  1.1642 +
  1.1643 +    /*
  1.1644 +     * Select on read/write events and create the channel.
  1.1645 +     */
  1.1646 +
  1.1647 +    newInfoPtr->selectEvents = (FD_READ | FD_WRITE | FD_CLOSE);
  1.1648 +    SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
  1.1649 +	    (WPARAM) SELECT, (LPARAM) newInfoPtr);
  1.1650 +
  1.1651 +    wsprintfA(channelName, "sock%d", newInfoPtr->socket);
  1.1652 +    newInfoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
  1.1653 +	    (ClientData) newInfoPtr, (TCL_READABLE | TCL_WRITABLE));
  1.1654 +    if (Tcl_SetChannelOption(NULL, newInfoPtr->channel, "-translation",
  1.1655 +	    "auto crlf") == TCL_ERROR) {
  1.1656 +	Tcl_Close((Tcl_Interp *) NULL, newInfoPtr->channel);
  1.1657 +	return;
  1.1658 +    }
  1.1659 +    if (Tcl_SetChannelOption(NULL, newInfoPtr->channel, "-eofchar", "")
  1.1660 +	    == TCL_ERROR) {
  1.1661 +	Tcl_Close((Tcl_Interp *) NULL, newInfoPtr->channel);
  1.1662 +	return;
  1.1663 +    }
  1.1664 +
  1.1665 +    /*
  1.1666 +     * Invoke the accept callback procedure.
  1.1667 +     */
  1.1668 +
  1.1669 +    if (infoPtr->acceptProc != NULL) {
  1.1670 +	(infoPtr->acceptProc) (infoPtr->acceptProcData,
  1.1671 +		newInfoPtr->channel,
  1.1672 +		winSock.inet_ntoa(addr.sin_addr),
  1.1673 +		winSock.ntohs(addr.sin_port));
  1.1674 +    }
  1.1675 +}
  1.1676 +
  1.1677 +/*
  1.1678 + *----------------------------------------------------------------------
  1.1679 + *
  1.1680 + * TcpInputProc --
  1.1681 + *
  1.1682 + *	This procedure is called by the generic IO level to read data from
  1.1683 + *	a socket based channel.
  1.1684 + *
  1.1685 + * Results:
  1.1686 + *	The number of bytes read or -1 on error.
  1.1687 + *
  1.1688 + * Side effects:
  1.1689 + *	Consumes input from the socket.
  1.1690 + *
  1.1691 + *----------------------------------------------------------------------
  1.1692 + */
  1.1693 +
  1.1694 +static int
  1.1695 +TcpInputProc(instanceData, buf, toRead, errorCodePtr)
  1.1696 +    ClientData instanceData;		/* The socket state. */
  1.1697 +    char *buf;				/* Where to store data. */
  1.1698 +    int toRead;				/* Maximum number of bytes to read. */
  1.1699 +    int *errorCodePtr;			/* Where to store error codes. */
  1.1700 +{
  1.1701 +    SocketInfo *infoPtr = (SocketInfo *) instanceData;
  1.1702 +    int bytesRead;
  1.1703 +    DWORD error;
  1.1704 +    ThreadSpecificData *tsdPtr = 
  1.1705 +	(ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
  1.1706 +    
  1.1707 +    *errorCodePtr = 0;
  1.1708 +
  1.1709 +    /*
  1.1710 +     * Check that WinSock is initialized; do not call it if not, to
  1.1711 +     * prevent system crashes. This can happen at exit time if the exit
  1.1712 +     * handler for WinSock ran before other exit handlers that want to
  1.1713 +     * use sockets.
  1.1714 +     */
  1.1715 +
  1.1716 +    if (!SocketsEnabled()) {
  1.1717 +        *errorCodePtr = EFAULT;
  1.1718 +        return -1;
  1.1719 +    }
  1.1720 +
  1.1721 +    /*
  1.1722 +     * First check to see if EOF was already detected, to prevent
  1.1723 +     * calling the socket stack after the first time EOF is detected.
  1.1724 +     */
  1.1725 +
  1.1726 +    if (infoPtr->flags & SOCKET_EOF) {
  1.1727 +	return 0;
  1.1728 +    }
  1.1729 +
  1.1730 +    /*
  1.1731 +     * Check to see if the socket is connected before trying to read.
  1.1732 +     */
  1.1733 +
  1.1734 +    if ((infoPtr->flags & SOCKET_ASYNC_CONNECT)
  1.1735 +	    && ! WaitForSocketEvent(infoPtr,  FD_CONNECT, errorCodePtr)) {
  1.1736 +	return -1;
  1.1737 +    }
  1.1738 +    
  1.1739 +    /*
  1.1740 +     * No EOF, and it is connected, so try to read more from the socket.
  1.1741 +     * Note that we clear the FD_READ bit because read events are level
  1.1742 +     * triggered so a new event will be generated if there is still data
  1.1743 +     * available to be read.  We have to simulate blocking behavior here
  1.1744 +     * since we are always using non-blocking sockets.
  1.1745 +     */
  1.1746 +
  1.1747 +    while (1) {
  1.1748 +	SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
  1.1749 +		(WPARAM) UNSELECT, (LPARAM) infoPtr);
  1.1750 +	bytesRead = winSock.recv(infoPtr->socket, buf, toRead, 0);
  1.1751 +	infoPtr->readyEvents &= ~(FD_READ);
  1.1752 +  
  1.1753 +	/*
  1.1754 +	 * Check for end-of-file condition or successful read.
  1.1755 +	 */
  1.1756 +  
  1.1757 +	if (bytesRead == 0) {
  1.1758 +	    infoPtr->flags |= SOCKET_EOF;
  1.1759 +	}
  1.1760 +	if (bytesRead != SOCKET_ERROR) {
  1.1761 +	    break;
  1.1762 +	}
  1.1763 +  
  1.1764 +	/*
  1.1765 +	 * If an error occurs after the FD_CLOSE has arrived,
  1.1766 +	 * then ignore the error and report an EOF.
  1.1767 +	 */
  1.1768 +  
  1.1769 +	if (infoPtr->readyEvents & FD_CLOSE) {
  1.1770 +	    infoPtr->flags |= SOCKET_EOF;
  1.1771 +	    bytesRead = 0;
  1.1772 +	    break;
  1.1773 +	}
  1.1774 +  
  1.1775 +	/*
  1.1776 +	 * Check for error condition or underflow in non-blocking case.
  1.1777 +	 */
  1.1778 +  
  1.1779 +	error = winSock.WSAGetLastError();
  1.1780 +	if ((infoPtr->flags & SOCKET_ASYNC) || (error != WSAEWOULDBLOCK)) {
  1.1781 +	    TclWinConvertWSAError(error);
  1.1782 +	    *errorCodePtr = Tcl_GetErrno();
  1.1783 +	    bytesRead = -1;
  1.1784 +	    break;
  1.1785 +	}
  1.1786 +
  1.1787 +	/*
  1.1788 +	 * In the blocking case, wait until the file becomes readable
  1.1789 +	 * or closed and try again.
  1.1790 +	 */
  1.1791 +
  1.1792 +	if (!WaitForSocketEvent(infoPtr, FD_READ|FD_CLOSE, errorCodePtr)) {
  1.1793 +	    bytesRead = -1;
  1.1794 +	    break;
  1.1795 +  	}
  1.1796 +    }
  1.1797 +    
  1.1798 +    SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
  1.1799 +	    (WPARAM) SELECT, (LPARAM) infoPtr);
  1.1800 +    
  1.1801 +    return bytesRead;
  1.1802 +}
  1.1803 +
  1.1804 +/*
  1.1805 + *----------------------------------------------------------------------
  1.1806 + *
  1.1807 + * TcpOutputProc --
  1.1808 + *
  1.1809 + *	This procedure is called by the generic IO level to write data
  1.1810 + *	to a socket based channel.
  1.1811 + *
  1.1812 + * Results:
  1.1813 + *	The number of bytes written or -1 on failure.
  1.1814 + *
  1.1815 + * Side effects:
  1.1816 + *	Produces output on the socket.
  1.1817 + *
  1.1818 + *----------------------------------------------------------------------
  1.1819 + */
  1.1820 +
  1.1821 +static int
  1.1822 +TcpOutputProc(instanceData, buf, toWrite, errorCodePtr)
  1.1823 +    ClientData instanceData;		/* The socket state. */
  1.1824 +    CONST char *buf;			/* Where to get data. */
  1.1825 +    int toWrite;			/* Maximum number of bytes to write. */
  1.1826 +    int *errorCodePtr;			/* Where to store error codes. */
  1.1827 +{
  1.1828 +    SocketInfo *infoPtr = (SocketInfo *) instanceData;
  1.1829 +    int bytesWritten;
  1.1830 +    DWORD error;
  1.1831 +    ThreadSpecificData *tsdPtr = 
  1.1832 +	(ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
  1.1833 +
  1.1834 +    *errorCodePtr = 0;
  1.1835 +
  1.1836 +    /*
  1.1837 +     * Check that WinSock is initialized; do not call it if not, to
  1.1838 +     * prevent system crashes. This can happen at exit time if the exit
  1.1839 +     * handler for WinSock ran before other exit handlers that want to
  1.1840 +     * use sockets.
  1.1841 +     */
  1.1842 +
  1.1843 +    if (!SocketsEnabled()) {
  1.1844 +        *errorCodePtr = EFAULT;
  1.1845 +        return -1;
  1.1846 +    }
  1.1847 +
  1.1848 +    /*
  1.1849 +     * Check to see if the socket is connected before trying to write.
  1.1850 +     */
  1.1851 +    
  1.1852 +    if ((infoPtr->flags & SOCKET_ASYNC_CONNECT)
  1.1853 +	    && ! WaitForSocketEvent(infoPtr,  FD_CONNECT, errorCodePtr)) {
  1.1854 +	return -1;
  1.1855 +    }
  1.1856 +
  1.1857 +    while (1) {
  1.1858 +	SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
  1.1859 +		(WPARAM) UNSELECT, (LPARAM) infoPtr);
  1.1860 +
  1.1861 +	bytesWritten = winSock.send(infoPtr->socket, buf, toWrite, 0);
  1.1862 +	if (bytesWritten != SOCKET_ERROR) {
  1.1863 +	    /*
  1.1864 +	     * Since Windows won't generate a new write event until we hit
  1.1865 +	     * an overflow condition, we need to force the event loop to
  1.1866 +	     * poll until the condition changes.
  1.1867 +	     */
  1.1868 +
  1.1869 +	    if (infoPtr->watchEvents & FD_WRITE) {
  1.1870 +		Tcl_Time blockTime = { 0, 0 };
  1.1871 +		Tcl_SetMaxBlockTime(&blockTime);
  1.1872 +	    }		
  1.1873 +	    break;
  1.1874 +	}
  1.1875 +	
  1.1876 +	/*
  1.1877 +	 * Check for error condition or overflow.  In the event of overflow, we
  1.1878 +	 * need to clear the FD_WRITE flag so we can detect the next writable
  1.1879 +	 * event.  Note that Windows only sends a new writable event after a
  1.1880 +	 * send fails with WSAEWOULDBLOCK.
  1.1881 +	 */
  1.1882 +
  1.1883 +	error = winSock.WSAGetLastError();
  1.1884 +	if (error == WSAEWOULDBLOCK) {
  1.1885 +	    infoPtr->readyEvents &= ~(FD_WRITE);
  1.1886 +	    if (infoPtr->flags & SOCKET_ASYNC) {
  1.1887 +		*errorCodePtr = EWOULDBLOCK;
  1.1888 +		bytesWritten = -1;
  1.1889 +		break;
  1.1890 +	    } 
  1.1891 +	} else {
  1.1892 +	    TclWinConvertWSAError(error);
  1.1893 +	    *errorCodePtr = Tcl_GetErrno();
  1.1894 +	    bytesWritten = -1;
  1.1895 +	    break;
  1.1896 +	}
  1.1897 +
  1.1898 +	/*
  1.1899 +	 * In the blocking case, wait until the file becomes writable
  1.1900 +	 * or closed and try again.
  1.1901 +	 */
  1.1902 +
  1.1903 +	if (!WaitForSocketEvent(infoPtr, FD_WRITE|FD_CLOSE, errorCodePtr)) {
  1.1904 +	    bytesWritten = -1;
  1.1905 +	    break;
  1.1906 +	}
  1.1907 +    }
  1.1908 +
  1.1909 +    SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
  1.1910 +	    (WPARAM) SELECT, (LPARAM) infoPtr);
  1.1911 +    
  1.1912 +    return bytesWritten;
  1.1913 +}
  1.1914 +
  1.1915 +/*
  1.1916 + *----------------------------------------------------------------------
  1.1917 + *
  1.1918 + * TcpSetOptionProc --
  1.1919 + *
  1.1920 + *	Sets Tcp channel specific options.
  1.1921 + *
  1.1922 + * Results:
  1.1923 + *	None, unless an error happens.
  1.1924 + *
  1.1925 + * Side effects:
  1.1926 + *	Changes attributes of the socket at the system level.
  1.1927 + *
  1.1928 + *----------------------------------------------------------------------
  1.1929 + */
  1.1930 +
  1.1931 +static int
  1.1932 +TcpSetOptionProc (
  1.1933 +    ClientData instanceData,	/* Socket state. */
  1.1934 +    Tcl_Interp *interp,		/* For error reporting - can be NULL. */
  1.1935 +    CONST char *optionName,	/* Name of the option to set. */
  1.1936 +    CONST char *value)		/* New value for option. */
  1.1937 +{
  1.1938 +    SocketInfo *infoPtr;
  1.1939 +    SOCKET sock;
  1.1940 +/*
  1.1941 +    BOOL val = FALSE;
  1.1942 +    int boolVar, rtn;
  1.1943 +*/
  1.1944 +    /*
  1.1945 +     * Check that WinSock is initialized; do not call it if not, to
  1.1946 +     * prevent system crashes. This can happen at exit time if the exit
  1.1947 +     * handler for WinSock ran before other exit handlers that want to
  1.1948 +     * use sockets.
  1.1949 +     */
  1.1950 +
  1.1951 +    if (!SocketsEnabled()) {
  1.1952 +	if (interp) {
  1.1953 +	    Tcl_AppendResult(interp, "winsock is not initialized", NULL);
  1.1954 +	}
  1.1955 +        return TCL_ERROR;
  1.1956 +    }
  1.1957 +
  1.1958 +    infoPtr = (SocketInfo *) instanceData;
  1.1959 +    sock = infoPtr->socket;
  1.1960 +
  1.1961 +/*
  1.1962 +    if (!stricmp(optionName, "-keepalive")) {
  1.1963 +	if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) {
  1.1964 +	    return TCL_ERROR;
  1.1965 +	}
  1.1966 +	if (boolVar) val = TRUE;
  1.1967 +	rtn = winSock.setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
  1.1968 +		(const char *) &val, sizeof(BOOL));
  1.1969 +	if (rtn != 0) {
  1.1970 +	    TclWinConvertWSAError(winSock.WSAGetLastError());
  1.1971 +	    if (interp) {
  1.1972 +		Tcl_AppendResult(interp, "couldn't set socket option: ",
  1.1973 +			Tcl_PosixError(interp), NULL);
  1.1974 +	    }
  1.1975 +	    return TCL_ERROR;
  1.1976 +	}
  1.1977 +	return TCL_OK;
  1.1978 +
  1.1979 +    } else if (!stricmp(optionName, "-nagle")) {
  1.1980 +	if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) {
  1.1981 +	    return TCL_ERROR;
  1.1982 +	}
  1.1983 +	if (!boolVar) val = TRUE;
  1.1984 +	rtn = winSock.setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
  1.1985 +		(const char *) &val, sizeof(BOOL));
  1.1986 +	if (rtn != 0) {
  1.1987 +	    TclWinConvertWSAError(winSock.WSAGetLastError());
  1.1988 +	    if (interp) {
  1.1989 +		Tcl_AppendResult(interp, "couldn't set socket option: ",
  1.1990 +			Tcl_PosixError(interp), NULL);
  1.1991 +	    }
  1.1992 +	    return TCL_ERROR;
  1.1993 +	}
  1.1994 +	return TCL_OK;
  1.1995 +    }
  1.1996 +
  1.1997 +    return Tcl_BadChannelOption(interp, optionName, "keepalive nagle");
  1.1998 +*/
  1.1999 +    return Tcl_BadChannelOption(interp, optionName, "");
  1.2000 +}
  1.2001 +
  1.2002 +/*
  1.2003 + *----------------------------------------------------------------------
  1.2004 + *
  1.2005 + * TcpGetOptionProc --
  1.2006 + *
  1.2007 + *	Computes an option value for a TCP socket based channel, or a
  1.2008 + *	list of all options and their values.
  1.2009 + *
  1.2010 + *	Note: This code is based on code contributed by John Haxby.
  1.2011 + *
  1.2012 + * Results:
  1.2013 + *	A standard Tcl result. The value of the specified option or a
  1.2014 + *	list of all options and	their values is returned in the
  1.2015 + *	supplied DString.
  1.2016 + *
  1.2017 + * Side effects:
  1.2018 + *	None.
  1.2019 + *
  1.2020 + *----------------------------------------------------------------------
  1.2021 + */
  1.2022 +
  1.2023 +static int
  1.2024 +TcpGetOptionProc(instanceData, interp, optionName, dsPtr)
  1.2025 +    ClientData instanceData;		/* Socket state. */
  1.2026 +    Tcl_Interp *interp;                 /* For error reporting - can be NULL */
  1.2027 +    CONST char *optionName;		/* Name of the option to
  1.2028 +                                         * retrieve the value for, or
  1.2029 +                                         * NULL to get all options and
  1.2030 +                                         * their values. */
  1.2031 +    Tcl_DString *dsPtr;			/* Where to store the computed
  1.2032 +                                         * value; initialized by caller. */
  1.2033 +{
  1.2034 +    SocketInfo *infoPtr;
  1.2035 +    SOCKADDR_IN sockname;
  1.2036 +    SOCKADDR_IN peername;
  1.2037 +    struct hostent *hostEntPtr;
  1.2038 +    SOCKET sock;
  1.2039 +    int size = sizeof(SOCKADDR_IN);
  1.2040 +    size_t len = 0;
  1.2041 +    char buf[TCL_INTEGER_SPACE];
  1.2042 +
  1.2043 +    /*
  1.2044 +     * Check that WinSock is initialized; do not call it if not, to
  1.2045 +     * prevent system crashes. This can happen at exit time if the exit
  1.2046 +     * handler for WinSock ran before other exit handlers that want to
  1.2047 +     * use sockets.
  1.2048 +     */
  1.2049 +
  1.2050 +    if (!SocketsEnabled()) {
  1.2051 +	if (interp) {
  1.2052 +	    Tcl_AppendResult(interp, "winsock is not initialized", NULL);
  1.2053 +	}
  1.2054 +        return TCL_ERROR;
  1.2055 +    }
  1.2056 +    
  1.2057 +    infoPtr = (SocketInfo *) instanceData;
  1.2058 +    sock = (int) infoPtr->socket;
  1.2059 +    if (optionName != (char *) NULL) {
  1.2060 +        len = strlen(optionName);
  1.2061 +    }
  1.2062 +
  1.2063 +    if ((len > 1) && (optionName[1] == 'e') &&
  1.2064 +	    (strncmp(optionName, "-error", len) == 0)) {
  1.2065 +	int optlen;
  1.2066 +	DWORD err;
  1.2067 +	int ret;
  1.2068 +    
  1.2069 +	optlen = sizeof(int);
  1.2070 +	ret = TclWinGetSockOpt(sock, SOL_SOCKET, SO_ERROR,
  1.2071 +		(char *)&err, &optlen);
  1.2072 +	if (ret == SOCKET_ERROR) {
  1.2073 +	    err = winSock.WSAGetLastError();
  1.2074 +	}
  1.2075 +	if (err) {
  1.2076 +	    TclWinConvertWSAError(err);
  1.2077 +	    Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(Tcl_GetErrno()), -1);
  1.2078 +	}
  1.2079 +	return TCL_OK;
  1.2080 +    }
  1.2081 +
  1.2082 +    if ((len == 0) ||
  1.2083 +            ((len > 1) && (optionName[1] == 'p') &&
  1.2084 +                    (strncmp(optionName, "-peername", len) == 0))) {
  1.2085 +        if (winSock.getpeername(sock, (LPSOCKADDR) &peername, &size)
  1.2086 +                == 0) {
  1.2087 +            if (len == 0) {
  1.2088 +                Tcl_DStringAppendElement(dsPtr, "-peername");
  1.2089 +                Tcl_DStringStartSublist(dsPtr);
  1.2090 +            }
  1.2091 +            Tcl_DStringAppendElement(dsPtr,
  1.2092 +                    winSock.inet_ntoa(peername.sin_addr));
  1.2093 +
  1.2094 +	    if (peername.sin_addr.s_addr == 0) {
  1.2095 +	        hostEntPtr = (struct hostent *) NULL;
  1.2096 +	    } else {
  1.2097 +	        hostEntPtr = winSock.gethostbyaddr(
  1.2098 +                    (char *) &(peername.sin_addr), sizeof(peername.sin_addr),
  1.2099 +		    AF_INET);
  1.2100 +	    }
  1.2101 +            if (hostEntPtr != (struct hostent *) NULL) {
  1.2102 +                Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name);
  1.2103 +            } else {
  1.2104 +                Tcl_DStringAppendElement(dsPtr,
  1.2105 +                        winSock.inet_ntoa(peername.sin_addr));
  1.2106 +            }
  1.2107 +	    TclFormatInt(buf, winSock.ntohs(peername.sin_port));
  1.2108 +            Tcl_DStringAppendElement(dsPtr, buf);
  1.2109 +            if (len == 0) {
  1.2110 +                Tcl_DStringEndSublist(dsPtr);
  1.2111 +            } else {
  1.2112 +                return TCL_OK;
  1.2113 +            }
  1.2114 +        } else {
  1.2115 +            /*
  1.2116 +             * getpeername failed - but if we were asked for all the options
  1.2117 +             * (len==0), don't flag an error at that point because it could
  1.2118 +             * be an fconfigure request on a server socket. (which have
  1.2119 +             * no peer). {copied from unix/tclUnixChan.c}
  1.2120 +             */
  1.2121 +            if (len) {
  1.2122 +		TclWinConvertWSAError((DWORD) winSock.WSAGetLastError());
  1.2123 +                if (interp) {
  1.2124 +                    Tcl_AppendResult(interp, "can't get peername: ",
  1.2125 +                                     Tcl_PosixError(interp),
  1.2126 +                                     (char *) NULL);
  1.2127 +                }
  1.2128 +                return TCL_ERROR;
  1.2129 +            }
  1.2130 +        }
  1.2131 +    }
  1.2132 +
  1.2133 +    if ((len == 0) ||
  1.2134 +            ((len > 1) && (optionName[1] == 's') &&
  1.2135 +                    (strncmp(optionName, "-sockname", len) == 0))) {
  1.2136 +        if (winSock.getsockname(sock, (LPSOCKADDR) &sockname, &size)
  1.2137 +                == 0) {
  1.2138 +            if (len == 0) {
  1.2139 +                Tcl_DStringAppendElement(dsPtr, "-sockname");
  1.2140 +                Tcl_DStringStartSublist(dsPtr);
  1.2141 +            }
  1.2142 +            Tcl_DStringAppendElement(dsPtr,
  1.2143 +                    winSock.inet_ntoa(sockname.sin_addr));
  1.2144 +	    if (sockname.sin_addr.s_addr == 0) {
  1.2145 +	        hostEntPtr = (struct hostent *) NULL;
  1.2146 +	    } else {
  1.2147 +	        hostEntPtr = winSock.gethostbyaddr(
  1.2148 +                    (char *) &(sockname.sin_addr), sizeof(peername.sin_addr),
  1.2149 +		    AF_INET);
  1.2150 +	    }
  1.2151 +            if (hostEntPtr != (struct hostent *) NULL) {
  1.2152 +                Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name);
  1.2153 +            } else {
  1.2154 +                Tcl_DStringAppendElement(dsPtr,
  1.2155 +                        winSock.inet_ntoa(sockname.sin_addr));
  1.2156 +            }
  1.2157 +            TclFormatInt(buf, winSock.ntohs(sockname.sin_port));
  1.2158 +            Tcl_DStringAppendElement(dsPtr, buf);
  1.2159 +            if (len == 0) {
  1.2160 +                Tcl_DStringEndSublist(dsPtr);
  1.2161 +            } else {
  1.2162 +                return TCL_OK;
  1.2163 +            }
  1.2164 +        } else {
  1.2165 +	    if (interp) {
  1.2166 +		TclWinConvertWSAError((DWORD) winSock.WSAGetLastError());
  1.2167 +		Tcl_AppendResult(interp, "can't get sockname: ",
  1.2168 +				 Tcl_PosixError(interp),
  1.2169 +				 (char *) NULL);
  1.2170 +	    }
  1.2171 +	    return TCL_ERROR;
  1.2172 +	}
  1.2173 +    }
  1.2174 +
  1.2175 +/*
  1.2176 +    if (len == 0 || !strncmp(optionName, "-keepalive", len)) {
  1.2177 +	int optlen;
  1.2178 +	BOOL opt = FALSE;
  1.2179 +    
  1.2180 +        if (len == 0) {
  1.2181 +            Tcl_DStringAppendElement(dsPtr, "-keepalive");
  1.2182 +        }
  1.2183 +	optlen = sizeof(BOOL);
  1.2184 +	winSock.getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&opt,
  1.2185 +		&optlen);
  1.2186 +	if (opt) {
  1.2187 +	    Tcl_DStringAppendElement(dsPtr, "1");
  1.2188 +	} else {
  1.2189 +	    Tcl_DStringAppendElement(dsPtr, "0");
  1.2190 +	}
  1.2191 +	if (len > 0) return TCL_OK;
  1.2192 +    }
  1.2193 +
  1.2194 +    if (len == 0 || !strncmp(optionName, "-nagle", len)) {
  1.2195 +	int optlen;
  1.2196 +	BOOL opt = FALSE;
  1.2197 +    
  1.2198 +        if (len == 0) {
  1.2199 +            Tcl_DStringAppendElement(dsPtr, "-nagle");
  1.2200 +        }
  1.2201 +	optlen = sizeof(BOOL);
  1.2202 +	winSock.getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&opt,
  1.2203 +		&optlen);
  1.2204 +	if (opt) {
  1.2205 +	    Tcl_DStringAppendElement(dsPtr, "0");
  1.2206 +	} else {
  1.2207 +	    Tcl_DStringAppendElement(dsPtr, "1");
  1.2208 +	}
  1.2209 +	if (len > 0) return TCL_OK;
  1.2210 +    }
  1.2211 +*/
  1.2212 +
  1.2213 +    if (len > 0) {
  1.2214 +        /*return Tcl_BadChannelOption(interp, optionName, "peername sockname keepalive nagle");*/
  1.2215 +        return Tcl_BadChannelOption(interp, optionName, "peername sockname");
  1.2216 +    }
  1.2217 +
  1.2218 +    return TCL_OK;
  1.2219 +}
  1.2220 +
  1.2221 +/*
  1.2222 + *----------------------------------------------------------------------
  1.2223 + *
  1.2224 + * TcpWatchProc --
  1.2225 + *
  1.2226 + *	Informs the channel driver of the events that the generic
  1.2227 + *	channel code wishes to receive on this socket.
  1.2228 + *
  1.2229 + * Results:
  1.2230 + *	None.
  1.2231 + *
  1.2232 + * Side effects:
  1.2233 + *	May cause the notifier to poll if any of the specified 
  1.2234 + *	conditions are already true.
  1.2235 + *
  1.2236 + *----------------------------------------------------------------------
  1.2237 + */
  1.2238 +
  1.2239 +static void
  1.2240 +TcpWatchProc(instanceData, mask)
  1.2241 +    ClientData instanceData;		/* The socket state. */
  1.2242 +    int mask;				/* Events of interest; an OR-ed
  1.2243 +                                         * combination of TCL_READABLE,
  1.2244 +                                         * TCL_WRITABLE and TCL_EXCEPTION. */
  1.2245 +{
  1.2246 +    SocketInfo *infoPtr = (SocketInfo *) instanceData;
  1.2247 +    
  1.2248 +    /*
  1.2249 +     * Update the watch events mask. Only if the socket is not a
  1.2250 +     * server socket. Fix for SF Tcl Bug #557878.
  1.2251 +     */
  1.2252 +
  1.2253 +    if (!infoPtr->acceptProc) {    
  1.2254 +        infoPtr->watchEvents = 0;
  1.2255 +	if (mask & TCL_READABLE) {
  1.2256 +	    infoPtr->watchEvents |= (FD_READ|FD_CLOSE|FD_ACCEPT);
  1.2257 +	}
  1.2258 +	if (mask & TCL_WRITABLE) {
  1.2259 +	    infoPtr->watchEvents |= (FD_WRITE|FD_CLOSE|FD_CONNECT);
  1.2260 +	}
  1.2261 +      
  1.2262 +	/*
  1.2263 +	 * If there are any conditions already set, then tell the notifier to poll
  1.2264 +	 * rather than block.
  1.2265 +	 */
  1.2266 +
  1.2267 +	if (infoPtr->readyEvents & infoPtr->watchEvents) {
  1.2268 +	    Tcl_Time blockTime = { 0, 0 };
  1.2269 +	    Tcl_SetMaxBlockTime(&blockTime);
  1.2270 +	}
  1.2271 +    }
  1.2272 +}
  1.2273 +
  1.2274 +/*
  1.2275 + *----------------------------------------------------------------------
  1.2276 + *
  1.2277 + * TcpGetProc --
  1.2278 + *
  1.2279 + *	Called from Tcl_GetChannelHandle to retrieve an OS handle from inside
  1.2280 + *	a TCP socket based channel.
  1.2281 + *
  1.2282 + * Results:
  1.2283 + *	Returns TCL_OK with the socket in handlePtr.
  1.2284 + *
  1.2285 + * Side effects:
  1.2286 + *	None.
  1.2287 + *
  1.2288 + *----------------------------------------------------------------------
  1.2289 + */
  1.2290 +
  1.2291 +static int
  1.2292 +TcpGetHandleProc(instanceData, direction, handlePtr)
  1.2293 +    ClientData instanceData;	/* The socket state. */
  1.2294 +    int direction;		/* Not used. */
  1.2295 +    ClientData *handlePtr;	/* Where to store the handle.  */
  1.2296 +{
  1.2297 +    SocketInfo *statePtr = (SocketInfo *) instanceData;
  1.2298 +
  1.2299 +    *handlePtr = (ClientData) statePtr->socket;
  1.2300 +    return TCL_OK;
  1.2301 +}
  1.2302 +
  1.2303 +/*
  1.2304 + *----------------------------------------------------------------------
  1.2305 + *
  1.2306 + * SocketThread --
  1.2307 + *
  1.2308 + *	Helper thread used to manage the socket event handling window.
  1.2309 + *
  1.2310 + * Results:
  1.2311 + *	1 if unable to create socket event window, 0 otherwise.
  1.2312 + *
  1.2313 + * Side effects:
  1.2314 + *	None.
  1.2315 + *
  1.2316 + *----------------------------------------------------------------------
  1.2317 + */
  1.2318 +
  1.2319 +static DWORD WINAPI
  1.2320 +SocketThread(LPVOID arg)
  1.2321 +{
  1.2322 +    MSG msg;
  1.2323 +    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)(arg);
  1.2324 +
  1.2325 +    /*
  1.2326 +     * Create a dummy window receiving socket events.
  1.2327 +     */
  1.2328 +
  1.2329 +    tsdPtr->hwnd = CreateWindow("TclSocket", "TclSocket", 
  1.2330 +	    WS_TILED, 0, 0, 0, 0, NULL, NULL, windowClass.hInstance, arg);
  1.2331 +
  1.2332 +    /*
  1.2333 +     * Signalize thread creator that we are done creating the window.
  1.2334 +     */
  1.2335 +
  1.2336 +    SetEvent(tsdPtr->readyEvent);
  1.2337 +
  1.2338 +    /*
  1.2339 +     * If unable to create the window, exit this thread immediately.
  1.2340 +     */
  1.2341 +
  1.2342 +    if (tsdPtr->hwnd == NULL) {
  1.2343 +	return 1;
  1.2344 +    }
  1.2345 +
  1.2346 +    /*
  1.2347 +     * Process all messages on the socket window until WM_QUIT.
  1.2348 +     * This threads exits only when instructed to do so by the
  1.2349 +     * call to PostMessage(SOCKET_TERMINATE) in TclpFinalizeSockets().
  1.2350 +     */
  1.2351 +
  1.2352 +    while (GetMessage(&msg, NULL, 0, 0) > 0) {
  1.2353 +	DispatchMessage(&msg);
  1.2354 +    }
  1.2355 +
  1.2356 +    /*
  1.2357 +     * This releases waiters on thread exit in TclpFinalizeSockets()
  1.2358 +     */
  1.2359 +
  1.2360 +    SetEvent(tsdPtr->readyEvent);
  1.2361 +
  1.2362 +    return (DWORD)msg.wParam;
  1.2363 +}
  1.2364 +
  1.2365 +
  1.2366 +/*
  1.2367 + *----------------------------------------------------------------------
  1.2368 + *
  1.2369 + * SocketProc --
  1.2370 + *
  1.2371 + *	This function is called when WSAAsyncSelect has been used
  1.2372 + *	to register interest in a socket event, and the event has
  1.2373 + *	occurred.
  1.2374 + *
  1.2375 + * Results:
  1.2376 + *	0 on success.
  1.2377 + *
  1.2378 + * Side effects:
  1.2379 + *	The flags for the given socket are updated to reflect the
  1.2380 + *	event that occured.
  1.2381 + *
  1.2382 + *----------------------------------------------------------------------
  1.2383 + */
  1.2384 +
  1.2385 +static LRESULT CALLBACK
  1.2386 +SocketProc(hwnd, message, wParam, lParam)
  1.2387 +    HWND hwnd;
  1.2388 +    UINT message;
  1.2389 +    WPARAM wParam;
  1.2390 +    LPARAM lParam;
  1.2391 +{
  1.2392 +    int event, error;
  1.2393 +    SOCKET socket;
  1.2394 +    SocketInfo *infoPtr;
  1.2395 +    ThreadSpecificData *tsdPtr =
  1.2396 +#ifdef _WIN64
  1.2397 +	(ThreadSpecificData *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1.2398 +#else
  1.2399 +	(ThreadSpecificData *) GetWindowLong(hwnd, GWL_USERDATA);
  1.2400 +#endif
  1.2401 +
  1.2402 +    switch (message) {
  1.2403 +
  1.2404 +	default:
  1.2405 +	    return DefWindowProc(hwnd, message, wParam, lParam);
  1.2406 +	    break;
  1.2407 +
  1.2408 +	case WM_CREATE:
  1.2409 +	    /*
  1.2410 +	     * store the initial tsdPtr, it's from a different thread, so it's
  1.2411 +	     * not directly accessible, but needed.
  1.2412 +	     */
  1.2413 +
  1.2414 +#ifdef _WIN64
  1.2415 +	    SetWindowLongPtr(hwnd, GWLP_USERDATA,
  1.2416 +		    (LONG_PTR) ((LPCREATESTRUCT)lParam)->lpCreateParams);
  1.2417 +#else
  1.2418 +	    SetWindowLong(hwnd, GWL_USERDATA,
  1.2419 +		    (LONG) ((LPCREATESTRUCT)lParam)->lpCreateParams);
  1.2420 +#endif
  1.2421 +	    break;
  1.2422 +
  1.2423 +	case WM_DESTROY:
  1.2424 +	    PostQuitMessage(0);
  1.2425 +	    break;
  1.2426 +
  1.2427 +	case SOCKET_MESSAGE:
  1.2428 +	    event = WSAGETSELECTEVENT(lParam);
  1.2429 +	    error = WSAGETSELECTERROR(lParam);
  1.2430 +	    socket = (SOCKET) wParam;
  1.2431 +
  1.2432 +	    /*
  1.2433 +	     * Find the specified socket on the socket list and update its
  1.2434 +	     * eventState flag.
  1.2435 +	     */
  1.2436 +
  1.2437 +	    WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
  1.2438 +	    for (infoPtr = tsdPtr->socketList; infoPtr != NULL; 
  1.2439 +		 infoPtr = infoPtr->nextPtr) {
  1.2440 +		if (infoPtr->socket == socket) {
  1.2441 +		    /*
  1.2442 +		     * Update the socket state.
  1.2443 +		     */
  1.2444 +
  1.2445 +		    /*
  1.2446 +		     * A count of FD_ACCEPTS is stored, so if an FD_CLOSE
  1.2447 +		     * event happens, then clear the FD_ACCEPT count.
  1.2448 +		     * Otherwise, increment the count if the current
  1.2449 +		     * event is an FD_ACCEPT.
  1.2450 +		     */
  1.2451 +
  1.2452 +		    if (event & FD_CLOSE) {
  1.2453 +			infoPtr->acceptEventCount = 0;
  1.2454 +			infoPtr->readyEvents &= ~(FD_WRITE|FD_ACCEPT);
  1.2455 +		    } else if (event & FD_ACCEPT) {
  1.2456 +			infoPtr->acceptEventCount++;
  1.2457 +		    }
  1.2458 +
  1.2459 +		    if (event & FD_CONNECT) {
  1.2460 +			/*
  1.2461 +			 * The socket is now connected,
  1.2462 +			 * clear the async connect flag.
  1.2463 +			 */
  1.2464 +
  1.2465 +			infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT);
  1.2466 +
  1.2467 +			/*
  1.2468 +			 * Remember any error that occurred so we can report
  1.2469 +			 * connection failures.
  1.2470 +			 */
  1.2471 +
  1.2472 +			if (error != ERROR_SUCCESS) {
  1.2473 +			    TclWinConvertWSAError((DWORD) error);
  1.2474 +			    infoPtr->lastError = Tcl_GetErrno();
  1.2475 +			}
  1.2476 +
  1.2477 +		    } 
  1.2478 +		    if(infoPtr->flags & SOCKET_ASYNC_CONNECT) {
  1.2479 +			infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT);
  1.2480 +			if (error != ERROR_SUCCESS) {
  1.2481 +			    TclWinConvertWSAError((DWORD) error);
  1.2482 +			    infoPtr->lastError = Tcl_GetErrno();
  1.2483 +			}
  1.2484 +			infoPtr->readyEvents |= FD_WRITE;
  1.2485 +		    }
  1.2486 +		    infoPtr->readyEvents |= event;
  1.2487 +
  1.2488 +		    /*
  1.2489 +		     * Wake up the Main Thread.
  1.2490 +		     */
  1.2491 +		    SetEvent(tsdPtr->readyEvent);
  1.2492 +		    Tcl_ThreadAlert(tsdPtr->threadId);
  1.2493 +		    break;
  1.2494 +		}
  1.2495 +	    }
  1.2496 +	    SetEvent(tsdPtr->socketListLock);
  1.2497 +	    break;
  1.2498 +
  1.2499 +	case SOCKET_SELECT:
  1.2500 +	    infoPtr = (SocketInfo *) lParam;
  1.2501 +	    if (wParam == SELECT) {
  1.2502 +
  1.2503 +		winSock.WSAAsyncSelect(infoPtr->socket, hwnd,
  1.2504 +			SOCKET_MESSAGE, infoPtr->selectEvents);
  1.2505 +	    } else {
  1.2506 +		/*
  1.2507 +		 * Clear the selection mask
  1.2508 +		 */
  1.2509 +
  1.2510 +		winSock.WSAAsyncSelect(infoPtr->socket, hwnd, 0, 0);
  1.2511 +	    }
  1.2512 +	    break;
  1.2513 +
  1.2514 +	case SOCKET_TERMINATE:
  1.2515 +	    DestroyWindow(hwnd);
  1.2516 +	    break;
  1.2517 +    }
  1.2518 +
  1.2519 +    return 0;
  1.2520 +}
  1.2521 +
  1.2522 +/*
  1.2523 + *----------------------------------------------------------------------
  1.2524 + *
  1.2525 + * Tcl_GetHostName --
  1.2526 + *
  1.2527 + *	Returns the name of the local host.
  1.2528 + *
  1.2529 + * Results:
  1.2530 + *	A string containing the network name for this machine, or
  1.2531 + *	an empty string if we can't figure out the name.  The caller 
  1.2532 + *	must not modify or free this string.
  1.2533 + *
  1.2534 + * Side effects:
  1.2535 + *	None.
  1.2536 + *
  1.2537 + *----------------------------------------------------------------------
  1.2538 + */
  1.2539 +
  1.2540 +CONST char *
  1.2541 +Tcl_GetHostName()
  1.2542 +{
  1.2543 +    DWORD length;
  1.2544 +    WCHAR wbuf[MAX_COMPUTERNAME_LENGTH + 1];
  1.2545 +
  1.2546 +    Tcl_MutexLock(&socketMutex);
  1.2547 +    InitSockets();
  1.2548 +
  1.2549 +    if (hostnameInitialized) {
  1.2550 +	Tcl_MutexUnlock(&socketMutex);
  1.2551 +        return hostname;
  1.2552 +    }
  1.2553 +    Tcl_MutexUnlock(&socketMutex);
  1.2554 +	
  1.2555 +    if (TclpHasSockets(NULL) == TCL_OK) {
  1.2556 +	/*
  1.2557 +	 * INTL: bug
  1.2558 +	 */
  1.2559 +
  1.2560 +	if (winSock.gethostname(hostname, sizeof(hostname)) == 0) {
  1.2561 +	    Tcl_MutexLock(&socketMutex);
  1.2562 +	    hostnameInitialized = 1;
  1.2563 +	    Tcl_MutexUnlock(&socketMutex);
  1.2564 +	    return hostname;
  1.2565 +	}
  1.2566 +    }
  1.2567 +    Tcl_MutexLock(&socketMutex);
  1.2568 +    length = sizeof(hostname);
  1.2569 +    if ((*tclWinProcs->getComputerNameProc)(wbuf, &length) != 0) {
  1.2570 +	/*
  1.2571 +	 * Convert string from native to UTF then change to lowercase.
  1.2572 +	 */
  1.2573 +
  1.2574 +	Tcl_DString ds;
  1.2575 +
  1.2576 +	lstrcpynA(hostname, Tcl_WinTCharToUtf((TCHAR *) wbuf, -1, &ds),
  1.2577 +		sizeof(hostname));
  1.2578 +	Tcl_DStringFree(&ds);
  1.2579 +	Tcl_UtfToLower(hostname);
  1.2580 +    } else {
  1.2581 +	hostname[0] = '\0';
  1.2582 +    }
  1.2583 +    hostnameInitialized = 1;
  1.2584 +    Tcl_MutexUnlock(&socketMutex);
  1.2585 +    return hostname;
  1.2586 +}
  1.2587 +
  1.2588 +/*
  1.2589 + *----------------------------------------------------------------------
  1.2590 + *
  1.2591 + * TclWinGetSockOpt, et al. --
  1.2592 + *
  1.2593 + *	These functions are wrappers that let us bind the WinSock
  1.2594 + *	API dynamically so we can run on systems that don't have
  1.2595 + *	the wsock32.dll.  We need wrappers for these interfaces
  1.2596 + *	because they are called from the generic Tcl code.
  1.2597 + *
  1.2598 + * Results:
  1.2599 + *	As defined for each function.
  1.2600 + *
  1.2601 + * Side effects:
  1.2602 + *	As defined for each function.
  1.2603 + *
  1.2604 + *----------------------------------------------------------------------
  1.2605 + */
  1.2606 +
  1.2607 +int
  1.2608 +TclWinGetSockOpt(SOCKET s, int level, int optname, char * optval,
  1.2609 +	int FAR *optlen)
  1.2610 +{
  1.2611 +    /*
  1.2612 +     * Check that WinSock is initialized; do not call it if not, to
  1.2613 +     * prevent system crashes. This can happen at exit time if the exit
  1.2614 +     * handler for WinSock ran before other exit handlers that want to
  1.2615 +     * use sockets.
  1.2616 +     */
  1.2617 +
  1.2618 +    if (!SocketsEnabled()) {
  1.2619 +        return SOCKET_ERROR;
  1.2620 +    }
  1.2621 +    
  1.2622 +    return winSock.getsockopt(s, level, optname, optval, optlen);
  1.2623 +}
  1.2624 +
  1.2625 +int
  1.2626 +TclWinSetSockOpt(SOCKET s, int level, int optname, const char * optval,
  1.2627 +	int optlen)
  1.2628 +{
  1.2629 +    /*
  1.2630 +     * Check that WinSock is initialized; do not call it if not, to
  1.2631 +     * prevent system crashes. This can happen at exit time if the exit
  1.2632 +     * handler for WinSock ran before other exit handlers that want to
  1.2633 +     * use sockets.
  1.2634 +     */
  1.2635 +    if (!SocketsEnabled()) {
  1.2636 +        return SOCKET_ERROR;
  1.2637 +    }
  1.2638 +
  1.2639 +    return winSock.setsockopt(s, level, optname, optval, optlen);
  1.2640 +}
  1.2641 +
  1.2642 +u_short
  1.2643 +TclWinNToHS(u_short netshort)
  1.2644 +{
  1.2645 +    /*
  1.2646 +     * Check that WinSock is initialized; do not call it if not, to
  1.2647 +     * prevent system crashes. This can happen at exit time if the exit
  1.2648 +     * handler for WinSock ran before other exit handlers that want to
  1.2649 +     * use sockets.
  1.2650 +     */
  1.2651 +
  1.2652 +    if (!SocketsEnabled()) {
  1.2653 +        return (u_short) -1;
  1.2654 +    }
  1.2655 +
  1.2656 +    return winSock.ntohs(netshort);
  1.2657 +}
  1.2658 +
  1.2659 +struct servent *
  1.2660 +TclWinGetServByName(const char * name, const char * proto)
  1.2661 +{
  1.2662 +    /*
  1.2663 +     * Check that WinSock is initialized; do not call it if not, to
  1.2664 +     * prevent system crashes. This can happen at exit time if the exit
  1.2665 +     * handler for WinSock ran before other exit handlers that want to
  1.2666 +     * use sockets.
  1.2667 +     */
  1.2668 +    if (!SocketsEnabled()) {
  1.2669 +        return (struct servent *) NULL;
  1.2670 +    }
  1.2671 +
  1.2672 +    return winSock.getservbyname(name, proto);
  1.2673 +}
  1.2674 +
  1.2675 +/*
  1.2676 + *----------------------------------------------------------------------
  1.2677 + *
  1.2678 + * TcpThreadActionProc --
  1.2679 + *
  1.2680 + *	Insert or remove any thread local refs to this channel.
  1.2681 + *
  1.2682 + * Results:
  1.2683 + *	None.
  1.2684 + *
  1.2685 + * Side effects:
  1.2686 + *	Changes thread local list of valid channels.
  1.2687 + *
  1.2688 + *----------------------------------------------------------------------
  1.2689 + */
  1.2690 +
  1.2691 +static void
  1.2692 +TcpThreadActionProc (instanceData, action)
  1.2693 +     ClientData instanceData;
  1.2694 +     int action;
  1.2695 +{
  1.2696 +    ThreadSpecificData *tsdPtr;
  1.2697 +    SocketInfo *infoPtr = (SocketInfo *) instanceData;
  1.2698 +    int      notifyCmd;
  1.2699 +
  1.2700 +    if (action == TCL_CHANNEL_THREAD_INSERT) {
  1.2701 +        /*
  1.2702 +	 * Ensure that socket subsystem is initialized in this thread, or
  1.2703 +	 * else sockets will not work.
  1.2704 +	 */
  1.2705 +
  1.2706 +        Tcl_MutexLock(&socketMutex);
  1.2707 +	InitSockets();
  1.2708 +	Tcl_MutexUnlock(&socketMutex);
  1.2709 +
  1.2710 +	tsdPtr = TCL_TSD_INIT(&dataKey);
  1.2711 +
  1.2712 +	WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
  1.2713 +	infoPtr->nextPtr = tsdPtr->socketList;
  1.2714 +	tsdPtr->socketList = infoPtr;
  1.2715 +	SetEvent(tsdPtr->socketListLock);
  1.2716 +
  1.2717 +	notifyCmd = SELECT;
  1.2718 +    } else {
  1.2719 +	SocketInfo **nextPtrPtr;
  1.2720 +	int removed = 0;
  1.2721 +
  1.2722 +	tsdPtr  = TCL_TSD_INIT(&dataKey);
  1.2723 +
  1.2724 +	/* TIP #218, Bugfix: All access to socketList has to be protected by the lock */
  1.2725 +	WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
  1.2726 +	for (nextPtrPtr = &(tsdPtr->socketList); (*nextPtrPtr) != NULL;
  1.2727 +	     nextPtrPtr = &((*nextPtrPtr)->nextPtr)) {
  1.2728 +	    if ((*nextPtrPtr) == infoPtr) {
  1.2729 +	        (*nextPtrPtr) = infoPtr->nextPtr;
  1.2730 +		removed = 1;
  1.2731 +		break;
  1.2732 +	    }
  1.2733 +	}
  1.2734 +	SetEvent(tsdPtr->socketListLock);
  1.2735 +
  1.2736 +	/*
  1.2737 +	 * This could happen if the channel was created in one thread
  1.2738 +	 * and then moved to another without updating the thread
  1.2739 +	 * local data in each thread.
  1.2740 +	 */
  1.2741 +
  1.2742 +	if (!removed) {
  1.2743 +	    Tcl_Panic("file info ptr not on thread channel list");
  1.2744 +	}
  1.2745 +
  1.2746 +	notifyCmd = UNSELECT;
  1.2747 +    }
  1.2748 +
  1.2749 +    /*
  1.2750 +     * Ensure that, or stop, notifications for the socket occur in this thread.
  1.2751 +     */
  1.2752 +
  1.2753 +    SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
  1.2754 +		(WPARAM) notifyCmd, (LPARAM) infoPtr);
  1.2755 +}