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