OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [insight/] [tcl/] [win/] [tclWinSock.c] - Blame information for rev 1782

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.