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

Contents of /projs/trunk/shared_source/c_tcl_base_7_5_w_mods/tclwinsock.c

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25