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

📄 tclmacsock.c

📁 tcl是工具命令语言
💻 C
📖 第 1 页 / 共 5 页
字号:
    }    statusPB.ioCRefNum = driverRefNum;    statusPB.tcpStream = statePtr->tcpStream;    statusPB.csCode = TCPStatus;    err = PBControlSync((ParmBlkPtr) &statusPB);    if ((statusPB.csParam.status.connectionState == 0) ||	(statusPB.csParam.status.connectionState == 2)) {	/*	 * If the conection state is 0 then this was a client	 * connection and it's closed.  If it is 2 then this a	 * server client and we may release it.  If it isn't	 * one of those values then we return and we'll try to	 * clean up later.	 */    } else {	return;    }        /*     * The Close request is made async.  We know it's     * OK to release the socket when the TCP_RELEASE flag     * gets set.     */    InitMacTCPParamBlock(&statePtr->pb, TCPRelease);    statePtr->pb.tcpStream = statePtr->tcpStream;    err = PBControlSync((ParmBlkPtr) &statePtr->pb);    if (err != noErr) {        Debugger(); /* Ignoreing leaves stranded stream.  Is there an		       alternative?  */    }    /*     * Free the buffer space used by the socket and the      * actual socket state data structure.     */    ckfree((char *) statePtr->pb.csParam.create.rcvBuff);    FreeSocketInfo(statePtr);}/* *---------------------------------------------------------------------- * * TcpInput -- * *	Reads input from the IO channel into the buffer given. Returns *	count of how many bytes were actually read, and an error  *	indication. * * Results: *	A count of how many bytes were read is returned.  A value of -1 *	implies an error occured.  A value of zero means we have reached *	the end of data (EOF). * * Side effects: *	Reads input from the actual channel. * *---------------------------------------------------------------------- */intTcpInput(    ClientData instanceData,		/* Channel 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;    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_GetChannelHandle 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. */    CONST 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;	    }            /* We need to copy the data, otherwise the caller may overwrite             * the buffer in the middle of our asynchronous call             */                         if (amount > statePtr->writeBufferSize) {                /*                  * need to grow write buffer                  */                                 if (statePtr->writeBuffer != (void *) NULL) {                    ckfree(statePtr->writeBuffer);                }                statePtr->writeBuffer = (void *) ckalloc(amount);                statePtr->writeBufferSize = amount;            }            memcpy(statePtr->writeBuffer, buf, amount);            statePtr->dataSegment[0].ptr = statePtr->writeBuffer;	    statePtr->dataSegment[0].length = amount;	    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.*/    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;    int doPeerName = false, doSockName = false, doError = false, doAll = false;    ip_addr tcpAddress;    char buffer[128];    OSErr err;    Tcl_DString dString;    TCPiopb statusPB;    int errorCode;    size_t len = 0;    /*     * 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 == (CONST char *) NULL || optionName[0] == '\0') {        doAll = true;    } else {	len = strlen(optionName);	if (!strncmp(optionName, "-peername", len)) {	    doPeerName = true;	} else if (!strncmp(optionName, "-sockname", len)) {	    doSockName = true;	} else if (!strncmp(optionName, "-error", len)) {	    /* SF Bug #483575 */	    doError = true;	} else {	    return Tcl_BadChannelOption(interp, optionName, 		        "error peername sockname");	}    }    /*     * SF Bug #483575     *     * Return error information. Currently we ignore     * this option. IOW, we always return the empty     * string, signaling 'no error'.     *     * FIXME: Get a mac/socket expert to write a correct     * FIXME: implementation.     */    if (doAll || doError) {	if (doAll) {	    Tcl_DStringAppendElement(dsPtr, "-error");	    Tcl_DStringAppendElement(dsPtr, "");	} else {	    Tcl_DStringAppend (dsPtr, "", -1);	    return TCL_OK;	}    }    /*     * 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;

⌨️ 快捷键说明

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