tclWinSock.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:74k
源码类别:

通讯编程

开发平台:

Visual C++

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