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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.67  
changed lines
  Added in v.98

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25