1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/*
* tclWinSock.c --
*
* This file contains Windows-specific socket related code.
*
* Copyright (c) 1995-1997 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* RCS: @(#) $Id: tclWinSock.c,v 1.44 2004/10/06 14:39:20 dkf Exp $
*/
#include "tclWinInt.h"
/*
* Make sure to remove the redirection defines set in tclWinPort.h
* that is in use in other sections of the core, except for us.
|
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/*
* tclWinSock.c --
*
* This file contains Windows-specific socket related code.
*
* Copyright (c) 1995-1997 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* RCS: @(#) $Id: tclWinSock.c,v 1.44.2.1 2005/02/02 15:54:05 kennykb Exp $
*/
#include "tclWinInt.h"
/*
* Make sure to remove the redirection defines set in tclWinPort.h
* that is in use in other sections of the core, except for us.
|
| ︙ | | | ︙ | |
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
|
static Tcl_DriverOutputProc TcpOutputProc;
static Tcl_DriverWatchProc TcpWatchProc;
static Tcl_DriverGetHandleProc TcpGetHandleProc;
static int WaitForSocketEvent _ANSI_ARGS_((
SocketInfo *infoPtr, int events,
int *errorCodePtr));
static DWORD WINAPI SocketThread _ANSI_ARGS_((LPVOID arg));
/*
* This structure describes the channel type structure for TCP socket
* based IO.
*/
static Tcl_ChannelType tcpChannelType = {
"tcp", /* Type name. */
TCL_CHANNEL_VERSION_2, /* v2 channel */
TcpCloseProc, /* Close proc. */
TcpInputProc, /* Input proc. */
TcpOutputProc, /* Output proc. */
NULL, /* Seek proc. */
TcpSetOptionProc, /* Set option proc. */
TcpGetOptionProc, /* Get option proc. */
TcpWatchProc, /* Set up notifier to watch this channel. */
TcpGetHandleProc, /* Get an OS handle from channel. */
NULL, /* close2proc. */
TcpBlockProc, /* Set socket into (non-)blocking mode. */
NULL, /* flush proc. */
NULL, /* handler proc. */
};
/*
*----------------------------------------------------------------------
*
* InitSockets --
|
>
>
>
>
|
>
>
|
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
|
static Tcl_DriverOutputProc TcpOutputProc;
static Tcl_DriverWatchProc TcpWatchProc;
static Tcl_DriverGetHandleProc TcpGetHandleProc;
static int WaitForSocketEvent _ANSI_ARGS_((
SocketInfo *infoPtr, int events,
int *errorCodePtr));
static DWORD WINAPI SocketThread _ANSI_ARGS_((LPVOID arg));
static void TcpThreadActionProc _ANSI_ARGS_ ((
ClientData instanceData, int action));
/*
* This structure describes the channel type structure for TCP socket
* based IO.
*/
static Tcl_ChannelType tcpChannelType = {
"tcp", /* Type name. */
TCL_CHANNEL_VERSION_4, /* v4 channel */
TcpCloseProc, /* Close proc. */
TcpInputProc, /* Input proc. */
TcpOutputProc, /* Output proc. */
NULL, /* Seek proc. */
TcpSetOptionProc, /* Set option proc. */
TcpGetOptionProc, /* Get option proc. */
TcpWatchProc, /* Set up notifier to watch this channel. */
TcpGetHandleProc, /* Get an OS handle from channel. */
NULL, /* close2proc. */
TcpBlockProc, /* Set socket into (non-)blocking mode. */
NULL, /* flush proc. */
NULL, /* handler proc. */
NULL, /* wide seek proc */
TcpThreadActionProc, /* thread action proc */
};
/*
*----------------------------------------------------------------------
*
* InitSockets --
|
| ︙ | | | ︙ | |
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
|
/* ARGSUSED */
static int
TcpCloseProc(instanceData, interp)
ClientData instanceData; /* The socket to close. */
Tcl_Interp *interp; /* Unused. */
{
SocketInfo *infoPtr = (SocketInfo *) instanceData;
SocketInfo **nextPtrPtr;
int errorCode = 0;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
/*
* Check that WinSock is initialized; do not call it if not, to
* prevent system crashes. This can happen at exit time if the exit
* handler for WinSock ran before other exit handlers that want to
|
|
|
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
|
/* ARGSUSED */
static int
TcpCloseProc(instanceData, interp)
ClientData instanceData; /* The socket to close. */
Tcl_Interp *interp; /* Unused. */
{
SocketInfo *infoPtr = (SocketInfo *) instanceData;
/* TIP #218 */
int errorCode = 0;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
/*
* Check that WinSock is initialized; do not call it if not, to
* prevent system crashes. This can happen at exit time if the exit
* handler for WinSock ran before other exit handlers that want to
|
| ︙ | | | ︙ | |
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
|
if (winSock.closesocket(infoPtr->socket) == SOCKET_ERROR) {
TclWinConvertWSAError((DWORD) winSock.WSAGetLastError());
errorCode = Tcl_GetErrno();
}
}
/*
* Remove the socket from socketList.
*/
WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
for (nextPtrPtr = &(tsdPtr->socketList); (*nextPtrPtr) != NULL;
nextPtrPtr = &((*nextPtrPtr)->nextPtr)) {
if ((*nextPtrPtr) == infoPtr) {
(*nextPtrPtr) = infoPtr->nextPtr;
break;
}
}
SetEvent(tsdPtr->socketListLock);
ckfree((char *) infoPtr);
return errorCode;
}
/*
*----------------------------------------------------------------------
*
* NewSocketInfo --
*
* This function allocates and initializes a new SocketInfo
* structure.
*
* Results:
* Returns a newly allocated SocketInfo.
*
* Side effects:
* Adds the socket to the global socket list.
*
*----------------------------------------------------------------------
*/
static SocketInfo *
NewSocketInfo(socket)
SOCKET socket;
|
|
|
>
>
>
<
<
<
<
<
<
<
<
<
<
<
|
|
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
|
if (winSock.closesocket(infoPtr->socket) == SOCKET_ERROR) {
TclWinConvertWSAError((DWORD) winSock.WSAGetLastError());
errorCode = Tcl_GetErrno();
}
}
/* TIP #218. Removed the code removing the structure
* from the global socket list. This is now done by
* the thread action callbacks, and only there. This
* happens before this code is called. We can free
* without fear of damaging the list.
*/
ckfree((char *) infoPtr);
return errorCode;
}
/*
*----------------------------------------------------------------------
*
* NewSocketInfo --
*
* This function allocates and initializes a new SocketInfo
* structure.
*
* Results:
* Returns a newly allocated SocketInfo.
*
* Side effects:
* None, except for allocation of memory.
*
*----------------------------------------------------------------------
*/
static SocketInfo *
NewSocketInfo(socket)
SOCKET socket;
|
| ︙ | | | ︙ | |
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
|
infoPtr->readyEvents = 0;
infoPtr->selectEvents = 0;
infoPtr->acceptEventCount = 0;
infoPtr->acceptProc = NULL;
infoPtr->acceptProcData = NULL;
infoPtr->lastError = 0;
WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
infoPtr->nextPtr = tsdPtr->socketList;
tsdPtr->socketList = infoPtr;
SetEvent(tsdPtr->socketListLock);
return infoPtr;
}
/*
*----------------------------------------------------------------------
*
* CreateSocket --
*
* This function opens a new socket and initializes the
* SocketInfo structure.
*
* Results:
* Returns a new SocketInfo, or NULL with an error in interp.
*
* Side effects:
* Adds a new socket to the socketList.
*
*----------------------------------------------------------------------
*/
static SocketInfo *
CreateSocket(interp, port, host, server, myaddr, myport, async)
Tcl_Interp *interp; /* For error reporting; can be NULL. */
|
|
>
>
>
|
<
<
|
|
|
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
|
infoPtr->readyEvents = 0;
infoPtr->selectEvents = 0;
infoPtr->acceptEventCount = 0;
infoPtr->acceptProc = NULL;
infoPtr->acceptProcData = NULL;
infoPtr->lastError = 0;
/* TIP #218. Removed the code inserting the new structure
* into the global list. This is now handled in the thread
* action callbacks, and only there.
*/
infoPtr->nextPtr = NULL;
return infoPtr;
}
/*
*----------------------------------------------------------------------
*
* CreateSocket --
*
* This function opens a new socket and initializes the
* SocketInfo structure.
*
* Results:
* Returns a new SocketInfo, or NULL with an error in interp.
*
* Side effects:
* None, except for allocation of memory.
*
*----------------------------------------------------------------------
*/
static SocketInfo *
CreateSocket(interp, port, host, server, myaddr, myport, async)
Tcl_Interp *interp; /* For error reporting; can be NULL. */
|
| ︙ | | | ︙ | |
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
|
*/
if (!SocketsEnabled()) {
return (struct servent *) NULL;
}
return winSock.getservbyname(name, proto);
}
/*
*----------------------------------------------------------------------
*
* TclpCutSockChannel --
*
* Remove any thread local refs to this channel. See
* Tcl_CutChannel for more info.
*
* Results:
* None.
*
* Side effects:
* Changes thread local list of valid channels.
*
*----------------------------------------------------------------------
*/
void
TclpCutSockChannel(chan)
Tcl_Channel chan; /* The channel being removed. Must
* not be referenced in any
* interpreter. */
{
ThreadSpecificData *tsdPtr;
SocketInfo *infoPtr;
SocketInfo **nextPtrPtr;
int removed = 0;
if (Tcl_GetChannelType(chan) != &tcpChannelType) {
return;
}
/*
* The initializtion of tsdPtr _after_ we have determined that we
* are dealing with socket is necessary. Doing it before causes
* the module to access th tdsPtr when it is not initialized yet,
* causing a lockup.
*/
tsdPtr = TCL_TSD_INIT(&dataKey);
infoPtr = (SocketInfo *) Tcl_GetChannelInstanceData (chan);
for (nextPtrPtr = &(tsdPtr->socketList); (*nextPtrPtr) != NULL;
nextPtrPtr = &((*nextPtrPtr)->nextPtr)) {
if ((*nextPtrPtr) == infoPtr) {
(*nextPtrPtr) = infoPtr->nextPtr;
removed = 1;
break;
}
}
/*
* This could happen if the channel was created in one thread
* and then moved to another without updating the thread
* local data in each thread.
*/
if (!removed) {
Tcl_Panic("file info ptr not on thread channel list");
}
/*
* Stop notifications for the socket to occur in this thread.
*/
SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
(WPARAM) UNSELECT, (LPARAM) infoPtr);
}
/*
*----------------------------------------------------------------------
*
* TclpSpliceSockChannel --
*
* Insert thread local ref for this channel.
* Tcl_SpliceChannel for more info.
*
* Results:
* None.
*
* Side effects:
* Changes thread local list of valid channels.
*
*----------------------------------------------------------------------
*/
void
TclpSpliceSockChannel(chan)
Tcl_Channel chan; /* The channel being removed. Must
* not be referenced in any
* interpreter. */
{
ThreadSpecificData *tsdPtr;
SocketInfo *infoPtr;
if (Tcl_GetChannelType(chan) != &tcpChannelType) {
return;
}
/*
* Ensure that socket subsystem is initialized in this thread, or
* else sockets will not work.
*/
Tcl_MutexLock(&socketMutex);
InitSockets();
Tcl_MutexUnlock(&socketMutex);
/*
* The initializtion of tsdPtr _after_ we have determined that we
* are dealing with socket is necessary. Doing it before causes
* the module to access th tdsPtr when it is not initialized yet,
* causing a lockup.
*/
tsdPtr = TCL_TSD_INIT(&dataKey);
infoPtr = (SocketInfo *) Tcl_GetChannelInstanceData (chan);
WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
infoPtr->nextPtr = tsdPtr->socketList;
tsdPtr->socketList = infoPtr;
SetEvent(tsdPtr->socketListLock);
/*
* Ensure that notifications for the socket occur in this thread.
*/
SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
(WPARAM) SELECT, (LPARAM) infoPtr);
}
|
<
<
|
|
<
|
|
<
|
|
|
<
|
>
>
>
>
>
|
>
|
>
|
>
<
>
>
|
|
|
>
>
|
<
>
|
<
>
>
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
|
|
<
<
<
|
<
<
|
|
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
|
|
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
|
*/
if (!SocketsEnabled()) {
return (struct servent *) NULL;
}
return winSock.getservbyname(name, proto);
}
/*
*----------------------------------------------------------------------
*
* TcpThreadActionProc --
*
* Insert or remove any thread local refs to this channel.
*
* Results:
* None.
*
* Side effects:
* Changes thread local list of valid channels.
*
*----------------------------------------------------------------------
*/
static void
TcpThreadActionProc (instanceData, action)
ClientData instanceData;
int action;
{
ThreadSpecificData *tsdPtr;
SocketInfo *infoPtr = (SocketInfo *) instanceData;
int notifyCmd;
if (action == TCL_CHANNEL_THREAD_INSERT) {
/*
* Ensure that socket subsystem is initialized in this thread, or
* else sockets will not work.
*/
Tcl_MutexLock(&socketMutex);
InitSockets();
Tcl_MutexUnlock(&socketMutex);
tsdPtr = TCL_TSD_INIT(&dataKey);
WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
infoPtr->nextPtr = tsdPtr->socketList;
tsdPtr->socketList = infoPtr;
SetEvent(tsdPtr->socketListLock);
notifyCmd = SELECT;
} else {
SocketInfo **nextPtrPtr;
int removed = 0;
tsdPtr = TCL_TSD_INIT(&dataKey);
/* TIP #218, Bugfix: All access to socketList has to be protected by the lock */
WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
for (nextPtrPtr = &(tsdPtr->socketList); (*nextPtrPtr) != NULL;
nextPtrPtr = &((*nextPtrPtr)->nextPtr)) {
if ((*nextPtrPtr) == infoPtr) {
(*nextPtrPtr) = infoPtr->nextPtr;
removed = 1;
break;
}
}
SetEvent(tsdPtr->socketListLock);
/*
* This could happen if the channel was created in one thread
* and then moved to another without updating the thread
* local data in each thread.
*/
if (!removed) {
Tcl_Panic("file info ptr not on thread channel list");
}
notifyCmd = UNSELECT;
}
/*
* Ensure that, or stop, notifications for the socket occur in this thread.
*/
SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
(WPARAM) notifyCmd, (LPARAM) infoPtr);
}
|