⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tclunixchan.c

📁 tcl是工具命令语言
💻 C
📖 第 1 页 / 共 5 页
字号:
    fsPtr->validMask = mode | TCL_EXCEPTION;    fsPtr->channel = Tcl_CreateChannel(channelTypePtr, channelName,	    (ClientData) fsPtr, mode);    return fsPtr->channel;}/* *---------------------------------------------------------------------- * * TcpBlockModeProc -- * *	This procedure is invoked by the generic IO level to set blocking *	and nonblocking mode on a TCP socket based channel. * * Results: *	0 if successful, errno when failed. * * Side effects: *	Sets the device into blocking or nonblocking mode. * *---------------------------------------------------------------------- */	/* ARGSUSED */static intTcpBlockModeProc(instanceData, mode)    ClientData instanceData;		/* Socket state. */    int mode;				/* The mode to set. Can be one of					 * TCL_MODE_BLOCKING or					 * TCL_MODE_NONBLOCKING. */{    TcpState *statePtr = (TcpState *) instanceData;    int setting;#ifndef USE_FIONBIO    setting = fcntl(statePtr->fd, F_GETFL);    if (mode == TCL_MODE_BLOCKING) {	statePtr->flags &= (~(TCP_ASYNC_SOCKET));	setting &= (~(O_NONBLOCK));    } else {	statePtr->flags |= TCP_ASYNC_SOCKET;	setting |= O_NONBLOCK;    }    if (fcntl(statePtr->fd, F_SETFL, setting) < 0) {	return errno;    }#else /* USE_FIONBIO */    if (mode == TCL_MODE_BLOCKING) {	statePtr->flags &= (~(TCP_ASYNC_SOCKET));	setting = 0;	if (ioctl(statePtr->fd, (int) FIONBIO, &setting) == -1) {	    return errno;	}    } else {	statePtr->flags |= TCP_ASYNC_SOCKET;	setting = 1;	if (ioctl(statePtr->fd, (int) FIONBIO, &setting) == -1) {	    return errno;	}    }#endif /* !USE_FIONBIO */    return 0;}/* *---------------------------------------------------------------------- * * WaitForConnect -- * *	Waits for a connection on an asynchronously opened socket to *	be completed. * * Results: *	None. * * Side effects: *	The socket is connected after this function returns. * *---------------------------------------------------------------------- */static intWaitForConnect(statePtr, errorCodePtr)    TcpState *statePtr;		/* State of the socket. */    int *errorCodePtr;		/* Where to store errors? */{    int timeOut;		/* How long to wait. */    int state;			/* Of calling TclWaitForFile. */    int flags;			/* fcntl flags for the socket. */    /*     * If an asynchronous connect is in progress, attempt to wait for it     * to complete before reading.     */    if (statePtr->flags & TCP_ASYNC_CONNECT) {	if (statePtr->flags & TCP_ASYNC_SOCKET) {	    timeOut = 0;	} else {	    timeOut = -1;	}	errno = 0;	state = TclUnixWaitForFile(statePtr->fd,		TCL_WRITABLE | TCL_EXCEPTION, timeOut);	if (!(statePtr->flags & TCP_ASYNC_SOCKET)) {#ifndef USE_FIONBIO	    flags = fcntl(statePtr->fd, F_GETFL);	    flags &= (~(O_NONBLOCK));	    (void) fcntl(statePtr->fd, F_SETFL, flags);#else /* USE_FIONBIO */	    flags = 0;	    (void) ioctl(statePtr->fd, FIONBIO, &flags);#endif /* !USE_FIONBIO */	}	if (state & TCL_EXCEPTION) {	    return -1;	}	if (state & TCL_WRITABLE) {	    statePtr->flags &= (~(TCP_ASYNC_CONNECT));	} else if (timeOut == 0) {	    *errorCodePtr = errno = EWOULDBLOCK;	    return -1;	}    }    return 0;}/* *---------------------------------------------------------------------- * * TcpInputProc -- * *	This procedure is invoked by the generic IO level to read input *	from a TCP socket based channel. * *	NOTE: We cannot share code with FilePipeInputProc because here *	we must use recv to obtain the input from the channel, not read. * * Results: *	The number of bytes read is returned or -1 on error. An output *	argument contains the POSIX error code on error, or zero if no *	error occurred. * * Side effects: *	Reads input from the input device of the channel. * *---------------------------------------------------------------------- */	/* ARGSUSED */static intTcpInputProc(instanceData, buf, bufSize, errorCodePtr)    ClientData instanceData;		/* Socket state. */    char *buf;				/* Where to store data read. */    int bufSize;			/* How much space is available					 * in the buffer? */    int *errorCodePtr;			/* Where to store error code. */{    TcpState *statePtr = (TcpState *) instanceData;    int bytesRead, state;    *errorCodePtr = 0;    state = WaitForConnect(statePtr, errorCodePtr);    if (state != 0) {	return -1;    }    bytesRead = recv(statePtr->fd, buf, (size_t) bufSize, 0);    if (bytesRead > -1) {	return bytesRead;    }    if (errno == ECONNRESET) {	/*	 * Turn ECONNRESET into a soft EOF condition.	 */	return 0;    }    *errorCodePtr = errno;    return -1;}/* *---------------------------------------------------------------------- * * TcpOutputProc -- * *	This procedure is invoked by the generic IO level to write output *	to a TCP socket based channel. * *	NOTE: We cannot share code with FilePipeOutputProc because here *	we must use send, not write, to get reliable error reporting. * * Results: *	The number of bytes written is returned. An output argument is *	set to a POSIX error code if an error occurred, or zero. * * Side effects: *	Writes output on the output device of the channel. * *---------------------------------------------------------------------- */static intTcpOutputProc(instanceData, buf, toWrite, errorCodePtr)    ClientData instanceData;		/* Socket state. */    CONST char *buf;			/* The data buffer. */    int toWrite;			/* How many bytes to write? */    int *errorCodePtr;			/* Where to store error code. */{    TcpState *statePtr = (TcpState *) instanceData;    int written;    int state;				/* Of waiting for connection. */    *errorCodePtr = 0;    state = WaitForConnect(statePtr, errorCodePtr);    if (state != 0) {	return -1;    }    written = send(statePtr->fd, buf, (size_t) toWrite, 0);    if (written > -1) {	return written;    }    *errorCodePtr = errno;    return -1;}/* *---------------------------------------------------------------------- * * TcpCloseProc -- * *	This procedure is invoked by the generic IO level to perform *	channel-type-specific cleanup when a TCP socket based channel *	is closed. * * Results: *	0 if successful, the value of errno if failed. * * Side effects: *	Closes the socket of the channel. * *---------------------------------------------------------------------- */	/* ARGSUSED */static intTcpCloseProc(instanceData, interp)    ClientData instanceData;	/* The socket to close. */    Tcl_Interp *interp;		/* For error reporting - unused. */{    TcpState *statePtr = (TcpState *) instanceData;    int errorCode = 0;    /*     * Delete a file handler that may be active for this socket if this     * is a server socket - the file handler was created automatically     * by Tcl as part of the mechanism to accept new client connections.     * Channel handlers are already deleted in the generic IO channel     * closing code that called this function, so we do not have to     * delete them here.     */    Tcl_DeleteFileHandler(statePtr->fd);    if (close(statePtr->fd) < 0) {	errorCode = errno;    }    ckfree((char *) statePtr);    return errorCode;}/* *---------------------------------------------------------------------- * * 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. Sets Error message if needed. * * 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. */{    TcpState *statePtr = (TcpState *) instanceData;    struct sockaddr_in sockname;    struct sockaddr_in peername;    struct hostent *hostEntPtr;    socklen_t size = sizeof(struct sockaddr_in);    size_t len = 0;    char buf[TCL_INTEGER_SPACE];    if (optionName != (char *) NULL) {	len = strlen(optionName);    }    if ((len > 1) && (optionName[1] == 'e') &&	    (strncmp(optionName, "-error", len) == 0)) {	socklen_t optlen = sizeof(int);	int err, ret;	ret = getsockopt(statePtr->fd, SOL_SOCKET, SO_ERROR,		(char *)&err, &optlen);	if (ret < 0) {	    err = errno;	}	if (err != 0) {	    Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(err), -1);	}	return TCL_OK;    }    if ((len == 0) ||	    ((len > 1) && (optionName[1] == 'p') &&		    (strncmp(optionName, "-peername", len) == 0))) {	if (getpeername(statePtr->fd, (struct sockaddr *) &peername,		&size) >= 0) {	    if (len == 0) {		Tcl_DStringAppendElement(dsPtr, "-peername");		Tcl_DStringStartSublist(dsPtr);	    }	    Tcl_DStringAppendElement(dsPtr, inet_ntoa(peername.sin_addr));	    hostEntPtr = gethostbyaddr(			/* INTL: Native. */		    (char *) &peername.sin_addr,		    sizeof(peername.sin_addr), AF_INET);	    if (hostEntPtr != NULL) {		Tcl_DString ds;		Tcl_ExternalToUtfDString(NULL, hostEntPtr->h_name, -1, &ds);		Tcl_DStringAppendElement(dsPtr, Tcl_DStringValue(&ds));	    } else {		Tcl_DStringAppendElement(dsPtr, inet_ntoa(peername.sin_addr));	    }	    TclFormatInt(buf, 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). same must be done on win&mac.	     */	    if (len) {		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 (getsockname(statePtr->fd, (struct sockaddr *) &sockname,		&size) >= 0) {	    if (len == 0) {		Tcl_DStringAppendElement(dsPtr, "-sockname");		Tcl_DStringStartSublist(dsPtr);	    }	    Tcl_DStringAppendElement(dsPtr, inet_ntoa(sockname.sin_addr));	    hostEntPtr = gethostbyaddr(			/* INTL: Native. */		    (char *) &sockname.sin_addr,		    sizeof(sockname.sin_addr), AF_INET);	    if (hostEntPtr != (struct hostent *) NULL) {		Tcl_DString ds;		Tcl_ExternalToUtfDString(NULL, hostEntPtr->h_name, -1, &ds);		Tcl_DStringAppendElement(dsPtr, Tcl_DStringValue(&ds));	    } else {		Tcl_DStringAppendElement(dsPtr, inet_ntoa(sockname.sin_addr));	    }	    TclFormatInt(buf, ntohs(sockname.sin_port));	    Tcl_DStringAppendElement(dsPtr, buf);	    if (len == 0) {		Tcl_DStringEndSublist(dsPtr);	    } else {		return TCL_OK;	    }	} else {	    if (interp) {		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 -- * *	Initialize the notifier to watch the fd from this channel. * * Results: *	None. * * Side effects: *	Sets up the notifier so that a future event on the channel will *	be seen by Tcl. * *---------------------------------------------------------------------- */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. */{    TcpState *statePtr = (TcpState *) instanceData;    /*     * Make sure we don't mess with server sockets since they will never     * be readable or writable at the Tcl level.  This keeps Tcl scripts     * from interfering with the -accept behavior.     */    if (!statePtr->acceptProc) {	if (mask) {	    Tcl_CreateFileHandler(statePtr->fd, mask,		    (Tcl_FileProc *) Tcl_NotifyChannel,		    (ClientData) statePtr->channel);	} else {	    Tcl_DeleteFileHandler(statePtr->fd);	}    }}/* *---------------------------------------------------------------------- * * TcpGetHandleProc -- * *	Called from Tcl_GetChannelHandle to retrieve OS handles from inside *	a TCP socket based channel. * * Results: *	Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if *	there is no handle for the specified direction.  * * Side effects: *	None. * *----------------------------------------------------------------------

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -