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

📄 tclunixchan.c

📁 linux系统下的音频通信
💻 C
📖 第 1 页 / 共 5 页
字号:
 * *---------------------------------------------------------------------- */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);#endif#ifdef	USE_FIONBIO            flags = 0;            (void) ioctl(statePtr->fd, FIONBIO, &flags);#endif        }        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, 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. */    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, 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. */    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;    int size = sizeof(struct sockaddr_in);    size_t len = 0;    char buf[128];    if (optionName != (char *) NULL) {        len = strlen(optionName);    }    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((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, inet_ntoa(peername.sin_addr));            }            sprintf(buf, "%d", 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((char *) &(sockname.sin_addr),                    sizeof(sockname.sin_addr), AF_INET);            if (hostEntPtr != (struct hostent *) NULL) {                Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name);            } else {                Tcl_DStringAppendElement(dsPtr, inet_ntoa(sockname.sin_addr));            }            sprintf(buf, "%d", 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_GetChannelFile 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. * *---------------------------------------------------------------------- */	/* ARGSUSED */static intTcpGetHandleProc(instanceData, direction, handlePtr)    ClientData instanceData;	/* The socket state. */    int direction;		/* Not used. */    ClientData *handlePtr;	/* Where to store the handle.  */{    TcpState *statePtr = (TcpState *) instanceData;    *handlePtr = (ClientData)statePtr->fd;    return TCL_OK;}/* *---------------------------------------------------------------------- * * CreateSocket -- * *	This function opens a new socket in client or server mode *	and initializes the TcpState structure. * * Results: *	Returns a new TcpState, or NULL with an error in interp->result, *	if interp is not NULL. * * Side effects: *	Opens a socket. * *---------------------------------------------------------------------- */static TcpState *CreateSocket(interp, port, host, server, myaddr, myport, async)    Tcl_Interp *interp;		/* For error reporting; can be NULL. */    int port;			/* Port number to open. */    char *host;			/* Name of host on which to open port.				 * NULL implies INADDR_ANY */    int server;			/* 1 if socket should be a server socket,				 * else 0 for a client socket. */    char *myaddr;		/* Optional client-side address */    int myport;			/* Optional client-side port */    int async;			/* If nonzero and creating a client socket,                                 * attempt to do an async connect. Otherwise                                 * do a synchronous connect or bind. */{    int status, sock, asyncConnect, curState, origState;    struct sockaddr_in sockaddr;	/* socket address */    struct sockaddr_in mysockaddr;	/* Socket address for client */    TcpState *statePtr;    sock = -1;    origState = 0;    if (! CreateSocketAddress(&sockaddr, host, port)) {	goto addressError;    }    if ((myaddr != NULL || myport != 0) &&	    ! CreateSocketAddress(&mysockaddr, myaddr, myport)) {	goto addressError;    }    sock = socket(AF_INET, SOCK_STREAM, 0);    if (sock < 0) {	goto addressError;    }    /*     * Set the close-on-exec flag so that the socket will not get     * inherited by child processes.     */    fcntl(sock, F_SETFD, FD_CLOEXEC);        /*     * Set kernel space buffering     */    TclSockMinimumBuffers(sock, SOCKET_BUFSIZE);    asyncConnect = 0;    status = 0;    if (server) {	/*	 * Set up to reuse server addresses automatically and bind to the	 * specified port.	 */

⌨️ 快捷键说明

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