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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25