📄 tclwinsock.c
字号:
(WPARAM) UNSELECT, (LPARAM) infoPtr); bytesWritten = winSock.send(infoPtr->socket, buf, toWrite, 0); if (bytesWritten != SOCKET_ERROR) { /* * Since Windows won't generate a new write event until we hit * an overflow condition, we need to force the event loop to * poll until the condition changes. */ if (infoPtr->watchEvents & FD_WRITE) { Tcl_Time blockTime = { 0, 0 }; Tcl_SetMaxBlockTime(&blockTime); } break; } /* * Check for error condition or overflow. In the event of overflow, we * need to clear the FD_WRITE flag so we can detect the next writable * event. Note that Windows only sends a new writable event after a * send fails with WSAEWOULDBLOCK. */ 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;}/* *---------------------------------------------------------------------- * * TcpSetOptionProc -- * * Sets Tcp channel specific options. * * Results: * None, unless an error happens. * * Side effects: * Changes attributes of the socket at the system level. * *---------------------------------------------------------------------- */static intTcpSetOptionProc ( ClientData instanceData, /* Socket state. */ Tcl_Interp *interp, /* For error reporting - can be NULL. */ CONST char *optionName, /* Name of the option to set. */ CONST char *value) /* New value for option. */{ SocketInfo *infoPtr; SOCKET sock;/* BOOL val = FALSE; int boolVar, rtn;*/ /* * 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 = infoPtr->socket;/* if (!stricmp(optionName, "-keepalive")) { if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) { return TCL_ERROR; } if (boolVar) val = TRUE; rtn = winSock.setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (const char *) &val, sizeof(BOOL)); if (rtn != 0) { TclWinConvertWSAError(winSock.WSAGetLastError()); if (interp) { Tcl_AppendResult(interp, "couldn't set socket option: ", Tcl_PosixError(interp), NULL); } return TCL_ERROR; } return TCL_OK; } else if (!stricmp(optionName, "-nagle")) { if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) { return TCL_ERROR; } if (!boolVar) val = TRUE; rtn = winSock.setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (const char *) &val, sizeof(BOOL)); if (rtn != 0) { TclWinConvertWSAError(winSock.WSAGetLastError()); if (interp) { Tcl_AppendResult(interp, "couldn't set socket option: ", Tcl_PosixError(interp), NULL); } return TCL_ERROR; } return TCL_OK; } return Tcl_BadChannelOption(interp, optionName, "keepalive nagle");*/ return Tcl_BadChannelOption(interp, optionName, "");}/* *---------------------------------------------------------------------- * * 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; SOCKADDR_IN sockname; SOCKADDR_IN peername; struct hostent *hostEntPtr; SOCKET sock; int size = sizeof(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; DWORD err; int 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, (LPSOCKADDR) &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((DWORD) 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, (LPSOCKADDR) &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((DWORD) winSock.WSAGetLastError()); Tcl_AppendResult(interp, "can't get sockname: ", Tcl_PosixError(interp), (char *) NULL); } return TCL_ERROR; } }/* if (len == 0 || !strncmp(optionName, "-keepalive", len)) { int optlen; BOOL opt = FALSE; if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-keepalive"); } optlen = sizeof(BOOL); winSock.getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&opt, &optlen); if (opt) { Tcl_DStringAppendElement(dsPtr, "1"); } else { Tcl_DStringAppendElement(dsPtr, "0"); } if (len > 0) return TCL_OK; } if (len == 0 || !strncmp(optionName, "-nagle", len)) { int optlen; BOOL opt = FALSE; if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-nagle"); } optlen = sizeof(BOOL); winSock.getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, &optlen); if (opt) { Tcl_DStringAppendElement(dsPtr, "0"); } else { Tcl_DStringAppendElement(dsPtr, "1"); } if (len > 0) return TCL_OK; }*/ if (len > 0) { /*return Tcl_BadChannelOption(interp, optionName, "peername sockname keepalive nagle");*/ 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){ M
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -