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

Annotation of /projs/dtats/trunk/shared_source/c_tcl_base_7_5_w_mods/tclwinsock.c

Parent Directory Parent Directory | Revision Log Revision Log


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

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25