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

📄 tclmacsock.c

📁 linux系统下的音频通信
💻 C
📖 第 1 页 / 共 5 页
字号:
    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;    StreamPtr tcpStream;    OSErr err;    TCPiopb statusPB;    int toRead, dataAvail;    *errorCodePtr = 0;    errno = 0;    tcpStream = statePtr->tcpStream;    if (bufSize == 0) {        return 0;    }    toRead = bufSize;    /*     * First check to see if EOF was already detected, to prevent     * calling the socket stack after the first time EOF is detected.     */    if (statePtr->flags & TCP_REMOTE_CLOSED) {	return 0;    }    /*     * If an asynchronous connect is in progress, attempt to wait for it     * to complete before reading.     */        if ((statePtr->flags & TCP_ASYNC_CONNECT)	    && ! WaitForSocketEvent(statePtr, TCL_READABLE, errorCodePtr)) {	return -1;    }    /*     * No EOF, and it is connected, so try to read more from the socket.     * If the socket is blocking, we keep trying until there is data     * available or the socket is closed.     */    while (1) {	statusPB.ioCRefNum = driverRefNum;	statusPB.tcpStream = tcpStream;	statusPB.csCode = TCPStatus;	err = PBControlSync((ParmBlkPtr) &statusPB);	if (err != noErr) {	    Debugger();	    statePtr->flags |= TCP_REMOTE_CLOSED;	    return 0;	/* EOF */	}	dataAvail = statusPB.csParam.status.amtUnreadData;	if (dataAvail < bufSize) {	    toRead = dataAvail;	} else {	    toRead = bufSize;	}	if (toRead != 0) {	    /*	     * Try to read the data.	     */	    	    InitMacTCPParamBlock(&statusPB, TCPRcv);	    statusPB.tcpStream = tcpStream;	    statusPB.csParam.receive.rcvBuff = buf;	    statusPB.csParam.receive.rcvBuffLen = toRead;	    err = PBControlSync((ParmBlkPtr) &statusPB);	    statePtr->checkMask &= ~TCL_READABLE;	    switch (err) {		case noErr:		    /*		     * The channel remains readable only if this read succeds		     * and we had more data then the size of the buffer we were		     * trying to fill.  Use the info from the call to status to		     * determine this.		     */		    if (dataAvail > bufSize) {			statePtr->checkMask |= TCL_READABLE;		    }		    return statusPB.csParam.receive.rcvBuffLen;		case connectionClosing:		    *errorCodePtr = errno = ESHUTDOWN;		    statePtr->flags |= TCP_REMOTE_CLOSED;		    return 0;		case connectionDoesntExist:		case connectionTerminated:		    *errorCodePtr = errno = ENOTCONN;		    statePtr->flags |= TCP_REMOTE_CLOSED;		    return 0;		case invalidStreamPtr:		default:		    *errorCodePtr = EINVAL;		    return -1;	    }	}	/*	 * No data is available, so check the connection state to	 * see why this is the case.  	 */	if (statusPB.csParam.status.connectionState == 14) {	    statePtr->flags |= TCP_REMOTE_CLOSED;	    return 0;	}	if (statusPB.csParam.status.connectionState != 8) {	    Debugger();	}	statePtr->checkMask &= ~TCL_READABLE;	if (statePtr->flags & TCP_ASYNC_SOCKET) {	    *errorCodePtr = EWOULDBLOCK;	    return -1;	}	/*	 * In the blocking case, wait until the file becomes readable	 * or closed and try again.	 */	if (!WaitForSocketEvent(statePtr, TCL_READABLE, errorCodePtr)) {	    return -1;	}    }}/* *---------------------------------------------------------------------- * * TcpGetHandle -- * *	Called from Tcl_GetChannelFile to retrieve handles from inside *	a file based channel. * * Results: *	The appropriate handle or NULL if not present.  * * Side effects: *	None. * *---------------------------------------------------------------------- */static intTcpGetHandle(    ClientData instanceData,		/* The file state. */    int direction,			/* Which handle to retrieve? */    ClientData *handlePtr){    TcpState *statePtr = (TcpState *) instanceData;    *handlePtr = (ClientData) statePtr->tcpStream;    return TCL_OK;}/* *---------------------------------------------------------------------- * * TcpOutput-- * *	Writes the given output on the IO channel. Returns count of how *	many characters were actually written, and an error indication. * * Results: *	A count of how many characters were written is returned and an *	error indication is returned in an output argument. * * Side effects: *	Writes output on the actual channel. * *---------------------------------------------------------------------- */static intTcpOutput(    ClientData instanceData, 		/* Channel state. */    char *buf, 				/* The data buffer. */    int toWrite, 			/* How many bytes to write? */    int *errorCodePtr)			/* Where to store error code. */{    TcpState *statePtr = (TcpState *) instanceData;    StreamPtr tcpStream;    OSErr err;    int amount;    TCPiopb statusPB;    *errorCodePtr = 0;    tcpStream = statePtr->tcpStream;    /*     * If an asynchronous connect is in progress, attempt to wait for it     * to complete before writing.     */        if ((statePtr->flags & TCP_ASYNC_CONNECT)	    && ! WaitForSocketEvent(statePtr, TCL_WRITABLE, errorCodePtr)) {	return -1;    }    /*     * Loop until we have written some data, or an error occurs.     */    while (1) {	statusPB.ioCRefNum = driverRefNum;	statusPB.tcpStream = tcpStream;	statusPB.csCode = TCPStatus;	err = PBControlSync((ParmBlkPtr) &statusPB);	if ((err == connectionDoesntExist) || ((err == noErr) && 		(statusPB.csParam.status.connectionState == 14))) {	    /*	     * The remote connection is gone away.  Report an error	     * and don't write anything.	     */	    *errorCodePtr = errno = EPIPE;	    return -1;	} else if (err != noErr) {	    return -1;	}	amount = statusPB.csParam.status.sendWindow	    - statusPB.csParam.status.amtUnackedData;	/*	 * Attempt to write the data to the socket if a background	 * write isn't in progress and there is room in the output buffers.	 */	if (!(statePtr->flags & TCP_WRITING) && amount > 0) {	    if (toWrite < amount) {		amount = toWrite;	    }	    statePtr->dataSegment[0].length = amount;	    statePtr->dataSegment[0].ptr = buf;	    statePtr->dataSegment[1].length = 0;	    InitMacTCPParamBlock(&statePtr->pb, TCPSend);	    statePtr->pb.ioCompletion = completeUPP;	    statePtr->pb.tcpStream = tcpStream;	    statePtr->pb.csParam.send.wdsPtr = (Ptr) statePtr->dataSegment;	    statePtr->pb.csParam.send.pushFlag = 1;	    statePtr->pb.csParam.send.userDataPtr = (Ptr) statePtr;	    statePtr->flags |= TCP_WRITING;	    err = PBControlAsync((ParmBlkPtr) &(statePtr->pb));	    switch (err) {		case noErr:		    return amount;		case connectionClosing:		    *errorCodePtr = errno = ESHUTDOWN;		    statePtr->flags |= TCP_REMOTE_CLOSED;		    return -1;		case connectionDoesntExist:		case connectionTerminated:		    *errorCodePtr = errno = ENOTCONN;		    statePtr->flags |= TCP_REMOTE_CLOSED;		    return -1;		case invalidStreamPtr:		default:		    return -1;	    }	}	/*	 * The socket wasn't writable.  In the non-blocking case, return	 * immediately, otherwise wait  until the file becomes writable	 * or closed and try again.	 */	if (statePtr->flags & TCP_ASYNC_SOCKET) {	    statePtr->checkMask &= ~TCL_WRITABLE;	    *errorCodePtr = EWOULDBLOCK;	    return -1;	} else if (!WaitForSocketEvent(statePtr, TCL_WRITABLE, errorCodePtr)) {	    return -1;	}    }}/* *---------------------------------------------------------------------- * * 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(    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;    int doPeerName = false, doSockName = false, doAll = false;    ip_addr tcpAddress;    char buffer[128];    OSErr err;    Tcl_DString dString;    TCPiopb statusPB;    int errorCode;    /*     * If an asynchronous connect is in progress, attempt to wait for it     * to complete before accessing the socket state.     */        if ((statePtr->flags & TCP_ASYNC_CONNECT)	    && ! WaitForSocketEvent(statePtr, TCL_WRITABLE, &errorCode)) {	if (interp) {	    /*	     * fix the error message.	     */	    Tcl_AppendResult(interp, "connect is in progress and can't wait",	    		NULL);	}	return TCL_ERROR;    }                /*     * Determine which options we need to do.  Do all of them     * if optionName is NULL.     */    if (optionName == (char *) NULL || optionName[0] == '\0') {        doAll = true;    } else {	if (!strcmp(optionName, "-peername")) {	    doPeerName = true;	} else if (!strcmp(optionName, "-sockname")) {	    doSockName = true;	} else {	    return Tcl_BadChannelOption(interp, optionName, 	    		"peername sockname");	}    }    /*     * Get status on the stream.  Make sure to use a new pb struct because     * the struct in the statePtr may be part of an asyncronous call.     */    statusPB.ioCRefNum = driverRefNum;    statusPB.tcpStream = statePtr->tcpStream;    statusPB.csCode = TCPStatus;    err = PBControlSync((ParmBlkPtr) &statusPB);    if ((err == connectionDoesntExist) ||	((err == noErr) && (statusPB.csParam.status.connectionState == 14))) {	/*	 * The socket was probably closed on the other side of the connection.	 */	if (interp) {	    Tcl_AppendResult(interp, "can't access socket info: ",			     "connection reset by peer", NULL);	}	return TCL_ERROR;    } else if (err != noErr) {	if (interp) { 	    Tcl_AppendResult(interp, "unknown socket error", NULL);	}	Debugger();	return TCL_ERROR;    }    /*     * Get the sockname for the socket.     */    Tcl_DStringInit(&dString);    if (doAll || doSockName) {	if (doAll) {	    Tcl_DStringAppendElement(dsPtr, "-sockname");	    Tcl_DStringStartSublist(dsPtr);	}	tcpAddress = statusPB.csParam.status.localHost;	sprintf(buffer, "%d.%d.%d.%d", tcpAddress>>24,		tcpAddress>>16 & 0xff, tcpAddress>>8 & 0xff,		tcpAddress & 0xff);	Tcl_DStringAppendElement(dsPtr, buffer);	if (ResolveAddress(tcpAddress, &dString) == noErr) {	    Tcl_DStringAppendElement(dsPtr, dString.string);	} else {	    Tcl_DStringAppendElement(dsPtr, "<unknown>");	}	sprintf(buffer, "%d", statusPB.csParam.status.localPort);	Tcl_DStringAppendElement(dsPtr, buffer);	if (doAll) {	    Tcl_DStringEndSublist(dsPtr);	}    }    /*     * Get the peername for the socket.     */    if ((doAll || doPeerName) && (statePtr->flags & TCP_CONNECTED)) {	if (doAll) {	    Tcl_DStringAppendElement(dsPtr, "-peername");	    Tcl_DStringStartSublist(dsPtr);	}	tcpAddress = statusPB.csParam.status.remoteHost;	sprintf(buffer, "%d.%d.%d.%d", tcpAddress>>24,		tcpAddress>>16 & 0xff, tcpAddress>>8 & 0xff,		tcpAddress & 0xff);	Tcl_DStringAppendElement(dsPtr, buffer);	Tcl_DStringSetLength(&dString, 0);	if (ResolveAddress(tcpAddress, &dString) == noErr) {	    Tcl_DStringAppendElement(dsPtr, dString.string);	} else {	    Tcl_DStringAppendElement(dsPtr, "<unknown>");	}	sprintf(buffer, "%d", statusPB.csParam.status.remotePort);	Tcl_DStringAppendElement(dsPtr, buffer);	if (doAll) {	    Tcl_DStringEndSublist(dsPtr);	}    }    Tcl_DStringFree(&dString);    return TCL_OK;}/* *---------------------------------------------------------------------- * * TcpWatch -- * *	Initialize the notifier to watch this channel. * * Results: *	None. * * Side effects: *	Sets the watchMask for the channel. * *---------------------------------------------------------------------- */static voidTcpWatch(instanceData, mask)    ClientData instanceData;		/* The file state. */    int mask;				/* Events of interest; an OR-ed                                         * combination of TCL_READABLE,                                         * TCL_WRITABLE and TCL_EXCEPTION. */{    TcpState *statePtr = (TcpState *) instanceData;    statePtr->watchMask = mask;}/* *---------------------------------------------------------------------- * * NewSocketInfo -- * *	This function allocates and initializes a new SocketInfo *	structure. * * Results: *	Returns a newly allocated SocketInfo. *

⌨️ 快捷键说明

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