📄 tclwinsock.c
字号:
*/ error = (*winSock.WSAGetLastError)(); if (error == WSAEWOULDBLOCK) { infoPtr->readyEvents &= ~(FD_WRITE); if (infoPtr->flags & SOCKET_ASYNC) { *errorCodePtr = EWOULDBLOCK; bytesWritten = -1; break; } } else { TclWinConvertWSAError(error); *errorCodePtr = Tcl_GetErrno(); bytesWritten = -1; break; } /* * In the blocking case, wait until the file becomes writable * or closed and try again. */ if (!WaitForSocketEvent(infoPtr, FD_WRITE|FD_CLOSE, errorCodePtr)) { bytesWritten = -1; break; } } SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, (LPARAM) infoPtr); return bytesWritten;}/* *---------------------------------------------------------------------- * * TcpGetOptionProc -- * * Computes an option value for a TCP socket based channel, or a * list of all options and their values. * * Note: This code is based on code contributed by John Haxby. * * Results: * A standard Tcl result. The value of the specified option or a * list of all options and their values is returned in the * supplied DString. * * Side effects: * None. * *---------------------------------------------------------------------- */static intTcpGetOptionProc(instanceData, interp, optionName, dsPtr) ClientData instanceData; /* Socket state. */ Tcl_Interp *interp; /* For error reporting - can be NULL */ CONST char *optionName; /* Name of the option to * retrieve the value for, or * NULL to get all options and * their values. */ Tcl_DString *dsPtr; /* Where to store the computed * value; initialized by caller. */{ SocketInfo *infoPtr; struct sockaddr_in sockname; struct sockaddr_in peername; struct hostent *hostEntPtr; SOCKET sock; int size = sizeof(struct sockaddr_in); size_t len = 0; char buf[TCL_INTEGER_SPACE]; /* * 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 * use sockets. */ if (!SocketsEnabled()) { if (interp) { Tcl_AppendResult(interp, "winsock is not initialized", NULL); } return TCL_ERROR; } infoPtr = (SocketInfo *) instanceData; sock = (int) infoPtr->socket; if (optionName != (char *) NULL) { len = strlen(optionName); } if ((len > 1) && (optionName[1] == 'e') && (strncmp(optionName, "-error", len) == 0)) { int optlen; int err, ret; optlen = sizeof(int); ret = TclWinGetSockOpt(sock, SOL_SOCKET, SO_ERROR, (char *)&err, &optlen); if (ret == SOCKET_ERROR) { err = (*winSock.WSAGetLastError)(); } if (err) { TclWinConvertWSAError(err); Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(Tcl_GetErrno()), -1); } return TCL_OK; } if ((len == 0) || ((len > 1) && (optionName[1] == 'p') && (strncmp(optionName, "-peername", len) == 0))) { if ((*winSock.getpeername)(sock, (struct sockaddr *) &peername, &size) == 0) { if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-peername"); Tcl_DStringStartSublist(dsPtr); } Tcl_DStringAppendElement(dsPtr, (*winSock.inet_ntoa)(peername.sin_addr)); if (peername.sin_addr.s_addr == 0) { hostEntPtr = (struct hostent *) NULL; } else { hostEntPtr = (*winSock.gethostbyaddr)( (char *) &(peername.sin_addr), sizeof(peername.sin_addr), AF_INET); } if (hostEntPtr != (struct hostent *) NULL) { Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name); } else { Tcl_DStringAppendElement(dsPtr, (*winSock.inet_ntoa)(peername.sin_addr)); } TclFormatInt(buf, (*winSock.ntohs)(peername.sin_port)); Tcl_DStringAppendElement(dsPtr, buf); if (len == 0) { Tcl_DStringEndSublist(dsPtr); } else { return TCL_OK; } } else { /* * getpeername failed - but if we were asked for all the options * (len==0), don't flag an error at that point because it could * be an fconfigure request on a server socket. (which have * no peer). {copied from unix/tclUnixChan.c} */ if (len) { TclWinConvertWSAError((*winSock.WSAGetLastError)()); if (interp) { Tcl_AppendResult(interp, "can't get peername: ", Tcl_PosixError(interp), (char *) NULL); } return TCL_ERROR; } } } if ((len == 0) || ((len > 1) && (optionName[1] == 's') && (strncmp(optionName, "-sockname", len) == 0))) { if ((*winSock.getsockname)(sock, (struct sockaddr *) &sockname, &size) == 0) { if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-sockname"); Tcl_DStringStartSublist(dsPtr); } Tcl_DStringAppendElement(dsPtr, (*winSock.inet_ntoa)(sockname.sin_addr)); if (sockname.sin_addr.s_addr == 0) { hostEntPtr = (struct hostent *) NULL; } else { hostEntPtr = (*winSock.gethostbyaddr)( (char *) &(sockname.sin_addr), sizeof(peername.sin_addr), AF_INET); } if (hostEntPtr != (struct hostent *) NULL) { Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name); } else { Tcl_DStringAppendElement(dsPtr, (*winSock.inet_ntoa)(sockname.sin_addr)); } TclFormatInt(buf, (*winSock.ntohs)(sockname.sin_port)); Tcl_DStringAppendElement(dsPtr, buf); if (len == 0) { Tcl_DStringEndSublist(dsPtr); } else { return TCL_OK; } } else { if (interp) { TclWinConvertWSAError((*winSock.WSAGetLastError)()); Tcl_AppendResult(interp, "can't get sockname: ", Tcl_PosixError(interp), (char *) NULL); } return TCL_ERROR; } } if (len > 0) { return Tcl_BadChannelOption(interp, optionName, "peername sockname"); } return TCL_OK;}/* *---------------------------------------------------------------------- * * TcpWatchProc -- * * Informs the channel driver of the events that the generic * channel code wishes to receive on this socket. * * Results: * None. * * Side effects: * May cause the notifier to poll if any of the specified * conditions are already true. * *---------------------------------------------------------------------- */static voidTcpWatchProc(instanceData, mask) ClientData instanceData; /* The socket state. */ int mask; /* Events of interest; an OR-ed * combination of TCL_READABLE, * TCL_WRITABLE and TCL_EXCEPTION. */{ SocketInfo *infoPtr = (SocketInfo *) instanceData; /* * Update the watch events mask. Only if the socket is not a * server socket. Fix for SF Tcl Bug #557878. */ if (!infoPtr->acceptProc) { infoPtr->watchEvents = 0; if (mask & TCL_READABLE) { infoPtr->watchEvents |= (FD_READ|FD_CLOSE|FD_ACCEPT); } if (mask & TCL_WRITABLE) { infoPtr->watchEvents |= (FD_WRITE|FD_CONNECT); } /* * If there are any conditions already set, then tell the notifier to poll * rather than block. */ if (infoPtr->readyEvents & infoPtr->watchEvents) { Tcl_Time blockTime = { 0, 0 }; Tcl_SetMaxBlockTime(&blockTime); } }}/* *---------------------------------------------------------------------- * * TcpGetProc -- * * Called from Tcl_GetChannelHandle to retrieve an OS handle from inside * a TCP socket based channel. * * Results: * Returns TCL_OK with the socket in handlePtr. * * Side effects: * None. * *---------------------------------------------------------------------- */static intTcpGetHandleProc(instanceData, direction, handlePtr) ClientData instanceData; /* The socket state. */ int direction; /* Not used. */ ClientData *handlePtr; /* Where to store the handle. */{ SocketInfo *statePtr = (SocketInfo *) instanceData; *handlePtr = (ClientData) statePtr->socket; return TCL_OK;}/* *---------------------------------------------------------------------- * * SocketThread -- * * Helper thread used to manage the socket event handling window. * * Results: * 1 if unable to create socket event window, 0 otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */static DWORD WINAPISocketThread(LPVOID arg){ MSG msg; ThreadSpecificData *tsdPtr = (ThreadSpecificData *)(arg); tsdPtr->hwnd = CreateWindowA("TclSocket", "TclSocket", WS_TILED, 0, 0, 0, 0, NULL, NULL, windowClass.hInstance, NULL); /* * Signal the main thread that the window has been created * and that the socket thread is ready to go. */ SetEvent(tsdPtr->readyEvent); if (tsdPtr->hwnd == NULL) { return 1; } else { /* * store the tsdPtr, it's from a different thread, so it's * not directly accessible, but needed. */#ifdef _WIN64 SetWindowLongPtr(tsdPtr->hwnd, GWLP_USERDATA, (LONG_PTR) tsdPtr);#else SetWindowLong(tsdPtr->hwnd, GWL_USERDATA, (LONG) tsdPtr);#endif } while (1) { /* * Process all outstanding messages on the socket window. */ while (PeekMessage(&msg, tsdPtr->hwnd, 0, 0, PM_REMOVE)) { DispatchMessage(&msg); } WaitMessage(); }}/* *---------------------------------------------------------------------- * * SocketProc -- * * This function is called when WSAAsyncSelect has been used * to register interest in a socket event, and the event has * occurred. * * Results: * 0 on success. * * Side effects: * The flags for the given socket are updated to reflect the * event that occured. * *---------------------------------------------------------------------- */static LRESULT CALLBACKSocketProc(hwnd, message, wParam, lParam) HWND hwnd; UINT message; WPARAM wParam; LPARAM lParam;{ int event, error; SOCKET socket; SocketInfo *infoPtr; ThreadSpecificData *tsdPtr =#ifdef _WIN64 (ThreadSpecificData *) GetWindowLongPtr(hwnd, GWLP_USERDATA);#else (ThreadSpecificData *) GetWindowLong(hwnd, GWL_USERDATA);#endif switch (message) { default: return DefWindowProc(hwnd, message, wParam, lParam); break; case SOCKET_MESSAGE: event = WSAGETSELECTEVENT(lParam); error = WSAGETSELECTERROR(lParam); socket = (SOCKET) wParam; /* * Find the specified socket on the socket list and update its * eventState flag. */ WaitForSingleObject(tsdPtr->socketListLock, INFINITE); for (infoPtr = tsdPtr->socketList; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->socket == socket) { /* * Update the socket state. */ /* * A count of FD_ACCEPTS is stored, so if an FD_CLOSE event * happens, then clear the FD_ACCEPT count. Otherwise, * increment the count if the current event is and * FD_ACCEPT. */ if (event & FD_CLOSE) { infoPtr->acceptEventCount = 0; infoPtr->readyEvents &= ~(FD_WRITE|FD_ACCEPT); } else if (event & FD_ACCEPT) { infoPtr->acceptEventCount++; } if (event & FD_CONNECT) { /* * The socket is now connected, * clear the async connect flag. */ infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT); /* * Remember any error that occurred so we can report * connection failures. */ if (error != ERROR_SUCCESS) { TclWinConvertWSAError(error); infoPtr->lastError = Tcl_GetErrno(); } } if(infoPtr->flags & SOCKET_ASYNC_CONNECT) { infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT); if (error != ERROR_SUCCESS) { TclWinConvertWSAError(error); infoPtr->lastError = Tcl_GetErrno(); } infoPtr->readyEvents
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -