📄 tclwinsock.c
字号:
/* * 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.26 2002/05/24 18:57:09 andreas_kupries Exp $ */#include "tclWinInt.h"/* * The following variable is used to tell whether this module has been * initialized. */static int initialized = 0;static int hostnameInitialized = 0;static char hostname[255]; /* This buffer should be big enough for * hostname plus domain name. */TCL_DECLARE_MUTEX(socketMutex)/* * The following structure contains pointers to all of the WinSock API entry * points used by Tcl. It is initialized by InitSockets. Since we * dynamically load Winsock.dll on demand, we must use this function table * to refer to functions in the socket API. */static struct { HINSTANCE hInstance; /* Handle to WinSock library. */ SOCKET (PASCAL FAR *accept)(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen); int (PASCAL FAR *bind)(SOCKET s, const struct sockaddr FAR *addr, int namelen); int (PASCAL FAR *closesocket)(SOCKET s); int (PASCAL FAR *connect)(SOCKET s, const struct sockaddr FAR *name, int namelen); int (PASCAL FAR *ioctlsocket)(SOCKET s, long cmd, u_long FAR *argp); int (PASCAL FAR *getsockopt)(SOCKET s, int level, int optname, char FAR * optval, int FAR *optlen); u_short (PASCAL FAR *htons)(u_short hostshort); unsigned long (PASCAL FAR *inet_addr)(const char FAR * cp); char FAR * (PASCAL FAR *inet_ntoa)(struct in_addr in); int (PASCAL FAR *listen)(SOCKET s, int backlog); u_short (PASCAL FAR *ntohs)(u_short netshort); int (PASCAL FAR *recv)(SOCKET s, char FAR * buf, int len, int flags); int (PASCAL FAR *select)(int nfds, fd_set FAR * readfds, fd_set FAR * writefds, fd_set FAR * exceptfds, const struct timeval FAR * tiemout); int (PASCAL FAR *send)(SOCKET s, const char FAR * buf, int len, int flags); int (PASCAL FAR *setsockopt)(SOCKET s, int level, int optname, const char FAR * optval, int optlen); int (PASCAL FAR *shutdown)(SOCKET s, int how); SOCKET (PASCAL FAR *socket)(int af, int type, int protocol); struct hostent FAR * (PASCAL FAR *gethostbyname)(const char FAR * name); struct hostent FAR * (PASCAL FAR *gethostbyaddr)(const char FAR *addr, int addrlen, int addrtype); int (PASCAL FAR *gethostname)(char FAR * name, int namelen); int (PASCAL FAR *getpeername)(SOCKET sock, struct sockaddr FAR *name, int FAR *namelen); struct servent FAR * (PASCAL FAR *getservbyname)(const char FAR * name, const char FAR * proto); int (PASCAL FAR *getsockname)(SOCKET sock, struct sockaddr FAR *name, int FAR *namelen); int (PASCAL FAR *WSAStartup)(WORD wVersionRequired, LPWSADATA lpWSAData); int (PASCAL FAR *WSACleanup)(void); int (PASCAL FAR *WSAGetLastError)(void); int (PASCAL FAR *WSAAsyncSelect)(SOCKET s, HWND hWnd, u_int wMsg, long lEvent);} winSock;/* * The following defines declare the messages used on socket windows. */#define SOCKET_MESSAGE WM_USER+1#define SOCKET_SELECT WM_USER+2#define SOCKET_TERMINATE WM_USER+3#define SELECT TRUE#define UNSELECT FALSE/* * The following structure is used to store the data associated with * each socket. */typedef struct SocketInfo { Tcl_Channel channel; /* Channel associated with this socket. */ SOCKET socket; /* Windows SOCKET handle. */ int flags; /* Bit field comprised of the flags * described below. */ int watchEvents; /* OR'ed combination of FD_READ, FD_WRITE, * FD_CLOSE, FD_ACCEPT and FD_CONNECT that * indicate which events are interesting. */ int readyEvents; /* OR'ed combination of FD_READ, FD_WRITE, * FD_CLOSE, FD_ACCEPT and FD_CONNECT that * indicate which events have occurred. */ int selectEvents; /* OR'ed combination of FD_READ, FD_WRITE, * FD_CLOSE, FD_ACCEPT and FD_CONNECT that * indicate which events are currently * being selected. */ int acceptEventCount; /* Count of the current number of FD_ACCEPTs * that have arrived and not processed. */ Tcl_TcpAcceptProc *acceptProc; /* Proc to call on accept. */ ClientData acceptProcData; /* The data for the accept proc. */ int lastError; /* Error code from last message. */ struct SocketInfo *nextPtr; /* The next socket on the global socket * list. */} SocketInfo;/* * The following structure is what is added to the Tcl event queue when * a socket event occurs. */typedef struct SocketEvent { Tcl_Event header; /* Information that is standard for * all events. */ SOCKET socket; /* Socket descriptor that is ready. Used * to find the SocketInfo structure for * the file (can't point directly to the * SocketInfo structure because it could * go away while the event is queued). */} SocketEvent;/* * This defines the minimum buffersize maintained by the kernel. */#define TCP_BUFFER_SIZE 4096/* * The following macros may be used to set the flags field of * a SocketInfo structure. */#define SOCKET_ASYNC (1<<0) /* The socket is in blocking mode. */#define SOCKET_EOF (1<<1) /* A zero read happened on * the socket. */#define SOCKET_ASYNC_CONNECT (1<<2) /* This socket uses async connect. */#define SOCKET_PENDING (1<<3) /* A message has been sent * for this socket */typedef struct ThreadSpecificData { /* * Every open socket has an entry on the following list. */ HWND hwnd; /* Handle to window for socket messages. */ HANDLE socketThread; /* Thread handling the window */ Tcl_ThreadId threadId; /* Parent thread. */ HANDLE readyEvent; /* Event indicating that a socket event is ready. * Also used to indicate that the socketThread has * been initialized and has started. */ HANDLE socketListLock; /* Win32 Event to lock the socketList */ SocketInfo *socketList;} ThreadSpecificData;static Tcl_ThreadDataKey dataKey;static WNDCLASSA windowClass;/* * Static functions defined in this file. */static SocketInfo * CreateSocket _ANSI_ARGS_((Tcl_Interp *interp, int port, CONST char *host, int server, CONST char *myaddr, int myport, int async));static int CreateSocketAddress _ANSI_ARGS_( (struct sockaddr_in *sockaddrPtr, CONST char *host, int port));static void InitSockets _ANSI_ARGS_((void));static SocketInfo * NewSocketInfo _ANSI_ARGS_((SOCKET socket));static void SocketCheckProc _ANSI_ARGS_((ClientData clientData, int flags));static int SocketEventProc _ANSI_ARGS_((Tcl_Event *evPtr, int flags));static void SocketExitHandler _ANSI_ARGS_((ClientData clientData));static LRESULT CALLBACK SocketProc _ANSI_ARGS_((HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam));static void SocketSetupProc _ANSI_ARGS_((ClientData clientData, int flags));static void SocketThreadExitHandler _ANSI_ARGS_((ClientData clientData));static int SocketsEnabled _ANSI_ARGS_((void));static void TcpAccept _ANSI_ARGS_((SocketInfo *infoPtr));static int TcpBlockProc _ANSI_ARGS_((ClientData instanceData, int mode));static int TcpCloseProc _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp));static int TcpGetOptionProc _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp, CONST char *optionName, Tcl_DString *optionValue));static int TcpInputProc _ANSI_ARGS_((ClientData instanceData, char *buf, int toRead, int *errorCode));static int TcpOutputProc _ANSI_ARGS_((ClientData instanceData, CONST char *buf, int toWrite, int *errorCode));static void TcpWatchProc _ANSI_ARGS_((ClientData instanceData, int mask));static int TcpGetHandleProc _ANSI_ARGS_((ClientData instanceData, int direction, ClientData *handlePtr));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. */ NULL, /* 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. */};/* * Define version of Winsock required by Tcl. */#define WSA_VERSION_REQD MAKEWORD(1,1)/* *---------------------------------------------------------------------- * * InitSockets -- * * Initialize the socket module. Attempts to load the wsock32.dll * library and set up the winSock function table. If successful, * registers the event window for the socket notifier code. * * Assumes Mutex is held. * * Results: * None. * * Side effects: * Dynamically loads wsock32.dll, and registers a new window * class and creates a window for use in asynchronous socket * notification. * *---------------------------------------------------------------------- */static voidInitSockets(){ DWORD id; WSADATA wsaData; ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); if (! initialized) { initialized = 1; Tcl_CreateExitHandler(SocketExitHandler, (ClientData) NULL); winSock.hInstance = LoadLibraryA("wsock32.dll"); /* * Initialize the function table. */ if (!SocketsEnabled()) { return; } winSock.accept = (SOCKET (PASCAL FAR *)(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen)) GetProcAddress(winSock.hInstance, "accept"); winSock.bind = (int (PASCAL FAR *)(SOCKET s, const struct sockaddr FAR *addr, int namelen)) GetProcAddress(winSock.hInstance, "bind"); winSock.closesocket = (int (PASCAL FAR *)(SOCKET s)) GetProcAddress(winSock.hInstance, "closesocket"); winSock.connect = (int (PASCAL FAR *)(SOCKET s, const struct sockaddr FAR *name, int namelen)) GetProcAddress(winSock.hInstance, "connect"); winSock.ioctlsocket = (int (PASCAL FAR *)(SOCKET s, long cmd, u_long FAR *argp)) GetProcAddress(winSock.hInstance, "ioctlsocket"); winSock.getsockopt = (int (PASCAL FAR *)(SOCKET s, int level, int optname, char FAR * optval, int FAR *optlen)) GetProcAddress(winSock.hInstance, "getsockopt"); winSock.htons = (u_short (PASCAL FAR *)(u_short hostshort)) GetProcAddress(winSock.hInstance, "htons"); winSock.inet_addr = (unsigned long (PASCAL FAR *)(const char FAR *cp)) GetProcAddress(winSock.hInstance, "inet_addr"); winSock.inet_ntoa = (char FAR * (PASCAL FAR *)(struct in_addr in)) GetProcAddress(winSock.hInstance, "inet_ntoa"); winSock.listen = (int (PASCAL FAR *)(SOCKET s, int backlog)) GetProcAddress(winSock.hInstance, "listen"); winSock.ntohs = (u_short (PASCAL FAR *)(u_short netshort)) GetProcAddress(winSock.hInstance, "ntohs"); winSock.recv = (int (PASCAL FAR *)(SOCKET s, char FAR * buf, int len, int flags)) GetProcAddress(winSock.hInstance, "recv"); winSock.select = (int (PASCAL FAR *)(int nfds, fd_set FAR * readfds, fd_set FAR * writefds, fd_set FAR * exceptfds, const struct timeval FAR * tiemout)) GetProcAddress(winSock.hInstance, "select"); winSock.send = (int (PASCAL FAR *)(SOCKET s, const char FAR * buf, int len, int flags)) GetProcAddress(winSock.hInstance, "send"); winSock.setsockopt = (int (PASCAL FAR *)(SOCKET s, int level, int optname, const char FAR * optval, int optlen)) GetProcAddress(winSock.hInstance, "setsockopt"); winSock.shutdown = (int (PASCAL FAR *)(SOCKET s, int how)) GetProcAddress(winSock.hInstance, "shutdown"); winSock.socket = (SOCKET (PASCAL FAR *)(int af, int type, int protocol)) GetProcAddress(winSock.hInstance, "socket"); winSock.gethostbyaddr = (struct hostent FAR * (PASCAL FAR *) (const char FAR *addr, int addrlen, int addrtype)) GetProcAddress(winSock.hInstance, "gethostbyaddr"); winSock.gethostbyname = (struct hostent FAR * (PASCAL FAR *) (const char FAR *name)) GetProcAddress(winSock.hInstance, "gethostbyname"); winSock.gethostname = (int (PASCAL FAR *)(char FAR * name, int namelen)) GetProcAddress(winSock.hInstance, "gethostname"); winSock.getpeername = (int (PASCAL FAR *)(SOCKET sock, struct sockaddr FAR *name, int FAR *namelen)) GetProcAddress(winSock.hInstance, "getpeername"); winSock.getservbyname = (struct servent FAR * (PASCAL FAR *) (const char FAR * name, const char FAR * proto)) GetProcAddress(winSock.hInstance, "getservbyname"); winSock.getsockname = (int (PASCAL FAR *)(SOCKET sock, struct sockaddr FAR *name, int FAR *namelen)) GetProcAddress(winSock.hInstance, "getsockname"); winSock.WSAStartup = (int (PASCAL FAR *)(WORD wVersionRequired, LPWSADATA lpWSAData)) GetProcAddress(winSock.hInstance, "WSAStartup"); winSock.WSACleanup = (int (PASCAL FAR *)(void)) GetProcAddress(winSock.hInstance, "WSACleanup"); winSock.WSAGetLastError = (int (PASCAL FAR *)(void)) GetProcAddress(winSock.hInstance, "WSAGetLastError"); winSock.WSAAsyncSelect = (int (PASCAL FAR *)(SOCKET s, HWND hWnd, u_int wMsg, long lEvent)) GetProcAddress(winSock.hInstance, "WSAAsyncSelect"); /* * Now check that all fields are properly initialized. If not, return * zero to indicate that we failed to initialize properly. */ if ((winSock.hInstance == NULL) || (winSock.accept == NULL) || (winSock.bind == NULL) || (winSock.closesocket == NULL) || (winSock.connect == NULL) || (winSock.ioctlsocket == NULL) || (winSock.getsockopt == NULL) || (winSock.htons == NULL) || (winSock.inet_addr == NULL) || (winSock.inet_ntoa == NULL) || (winSock.listen == NULL) || (winSock.ntohs == NULL) || (winSock.recv == NULL) || (winSock.select == NULL) || (winSock.send == NULL) || (winSock.setsockopt == NULL) || (winSock.socket == NULL) || (winSock.gethostbyname == NULL) || (winSock.gethostbyaddr == NULL) || (winSock.gethostname == NULL) || (winSock.getpeername == NULL) || (winSock.getservbyname == NULL) || (winSock.getsockname == NULL) || (winSock.WSAStartup == NULL) || (winSock.WSACleanup == NULL) || (winSock.WSAGetLastError == NULL) || (winSock.WSAAsyncSelect == NULL)) { goto unloadLibrary; } /* * Create the async notification window with a new class. We * must create a new class to avoid a Windows 95 bug that causes * us to get the wrong message number for socket events if the * message window is a subclass of a static control. */ windowClass.style = 0; windowClass.cbClsExtra = 0; windowClass.cbWndExtra = 0; windowClass.hInstance = TclWinGetTclInstance(); windowClass.hbrBackground = NULL; windowClass.lpszMenuName = NULL; windowClass.lpszClassName = "TclSocket"; windowClass.lpfnWndProc = SocketProc; windowClass.hIcon = NULL; windowClass.hCursor = NULL; if (!RegisterClassA(&windowClass)) { TclWinConvertError(GetLastError()); (*winSock.WSACleanup)(); goto unloadLibrary; } /* * Initialize the winsock library and check the version number. */ if ((*winSock.WSAStartup)(WSA_VERSION_REQD, &wsaData) != 0) { goto unloadLibrary; } if (wsaData.wVersion != WSA_VERSION_REQD) { (*winSock.WSACleanup)(); goto unloadLibrary; } } /* * Check for per-thread initialization. */ if (tsdPtr == NULL) { tsdPtr = TCL_TSD_INIT(&dataKey); tsdPtr->socketList = NULL; tsdPtr->hwnd = NULL; tsdPtr->threadId = Tcl_GetCurrentThread(); tsdPtr->readyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); tsdPtr->socketListLock = CreateEvent(NULL, FALSE, TRUE, NULL); tsdPtr->socketThread = CreateThread(NULL, 8000, SocketThread, tsdPtr, 0, &id); SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST); if (tsdPtr->socketThread == NULL) { goto unloadLibrary; } /* * Wait for the thread to signal that the window has * been created and is ready to go. Timeout after twenty * seconds. */ if (WaitForSingleObject(tsdPtr->readyEvent, 20000) == WAIT_TIMEOUT) { goto unloadLibrary; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -