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

Properties

Name Value
svn:eol-style native
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25