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