📄 tclmacsock.c
字号:
/* * Queue events for any ready sockets that don't already have events * queued (caused by persistent states that won't generate WinSock * events). */ for (statePtr = socketList; statePtr != NULL; statePtr = statePtr->nextPtr) { /* * Check to see if this socket is dead and needs to be cleaned * up. We use a dummy statePtr whose only valid field is the * nextPtr to allow the loop to continue even if the element * is deleted. */ if (statePtr->flags & TCP_RELEASE) { if (!(statePtr->flags & TCP_PENDING)) { dummyState.nextPtr = statePtr->nextPtr; SocketFreeProc(statePtr); statePtr = &dummyState; } continue; } if (!(statePtr->flags & TCP_PENDING) && SocketReady(statePtr)) { statePtr->flags |= TCP_PENDING; evPtr = (SocketEvent *) ckalloc(sizeof(SocketEvent)); evPtr->header.proc = SocketEventProc; evPtr->statePtr = statePtr; evPtr->tcpStream = statePtr->tcpStream; Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL); } }}/* *---------------------------------------------------------------------- * * SocketReady -- * * This function checks the current state of a socket to see * if any interesting conditions are present. * * Results: * Returns 1 if an event that someone is watching is present, else * returns 0. * * Side effects: * Updates the checkMask for the socket to reflect any newly * detected events. * *---------------------------------------------------------------------- */static intSocketReady( TcpState *statePtr){ TCPiopb statusPB; int foundSomething = 0; int didStatus = 0; int amount; OSErr err; if (statePtr->flags & TCP_LISTEN_CONNECT) { foundSomething = 1; statePtr->checkMask |= TCL_READABLE; } if (statePtr->watchMask & TCL_READABLE) { if (statePtr->checkMask & TCL_READABLE) { foundSomething = 1; } else if (statePtr->flags & TCP_CONNECTED) { statusPB.ioCRefNum = driverRefNum; statusPB.tcpStream = statePtr->tcpStream; statusPB.csCode = TCPStatus; err = PBControlSync((ParmBlkPtr) &statusPB); didStatus = 1; /* * We make the fchannel readable if 1) we get an error, * 2) there is more data available, or 3) we detect * that a close from the remote connection has arrived. */ if ((err != noErr) || (statusPB.csParam.status.amtUnreadData > 0) || (statusPB.csParam.status.connectionState == 14)) { statePtr->checkMask |= TCL_READABLE; foundSomething = 1; } } } if (statePtr->watchMask & TCL_WRITABLE) { if (statePtr->checkMask & TCL_WRITABLE) { foundSomething = 1; } else if (statePtr->flags & TCP_CONNECTED) { if (!didStatus) { statusPB.ioCRefNum = driverRefNum; statusPB.tcpStream = statePtr->tcpStream; statusPB.csCode = TCPStatus; err = PBControlSync((ParmBlkPtr) &statusPB); } /* * If there is an error or there if there is room to * send more data we make the channel writeable. */ amount = statusPB.csParam.status.sendWindow - statusPB.csParam.status.amtUnackedData; if ((err != noErr) || (amount > 0)) { statePtr->checkMask |= TCL_WRITABLE; foundSomething = 1; } } } return foundSomething;}/* *---------------------------------------------------------------------- * * InitMacTCPParamBlock-- * * Initialize a MacTCP parameter block. * * Results: * None. * * Side effects: * Initializes the parameter block. * *---------------------------------------------------------------------- */static voidInitMacTCPParamBlock( TCPiopb *pBlock, /* Tcp parmeter block. */ int csCode) /* Tcp operation code. */{ memset(pBlock, 0, sizeof(TCPiopb)); pBlock->ioResult = 1; pBlock->ioCRefNum = driverRefNum; pBlock->csCode = (short) csCode;}/* *---------------------------------------------------------------------- * * TcpBlockMode -- * * Set blocking or non-blocking mode on channel. * * Results: * 0 if successful, errno when failed. * * Side effects: * Sets the device into blocking or non-blocking mode. * *---------------------------------------------------------------------- */static intTcpBlockMode( ClientData instanceData, /* Channel state. */ int mode) /* The mode to set. */{ TcpState *statePtr = (TcpState *) instanceData; if (mode == TCL_MODE_BLOCKING) { statePtr->flags &= ~TCP_ASYNC_SOCKET; } else { statePtr->flags |= TCP_ASYNC_SOCKET; } return 0;}/* *---------------------------------------------------------------------- * * TcpClose -- * * Close the socket. * * Results: * 0 if successful, the value of errno if failed. * * Side effects: * Closes the socket. * *---------------------------------------------------------------------- */static intTcpClose( ClientData instanceData, /* The socket to close. */ Tcl_Interp *interp) /* Interp for error messages. */{ TcpState *statePtr = (TcpState *) instanceData; StreamPtr tcpStream; TCPiopb closePB; OSErr err; tcpStream = statePtr->tcpStream; statePtr->flags &= ~TCP_CONNECTED; /* * If this is a server socket we can't use the statePtr * param block because it is in use. However, we can * close syncronously. */ if ((statePtr->flags & TCP_LISTENING) || (statePtr->flags & TCP_LISTEN_CONNECT)) { InitMacTCPParamBlock(&closePB, TCPClose); closePB.tcpStream = tcpStream; closePB.ioCompletion = NULL; err = PBControlSync((ParmBlkPtr) &closePB); if (err != noErr) { Debugger(); panic("error closing server socket"); } statePtr->flags |= TCP_RELEASE; /* * Server sockets are closed sync. Therefor, we know it is OK to * release the socket now. */ InitMacTCPParamBlock(&statePtr->pb, TCPRelease); statePtr->pb.tcpStream = statePtr->tcpStream; err = PBControlSync((ParmBlkPtr) &statePtr->pb); if (err != noErr) { panic("error releasing server socket"); } /* * Free the buffer space used by the socket and the * actual socket state data structure. */ ckfree((char *) statePtr->pb.csParam.create.rcvBuff); FreeSocketInfo(statePtr); return 0; } /* * If this socket is in the midddle on async connect we can just * abort the connect and release the stream right now. */ if (statePtr->flags & TCP_ASYNC_CONNECT) { InitMacTCPParamBlock(&closePB, TCPClose); closePB.tcpStream = tcpStream; closePB.ioCompletion = NULL; err = PBControlSync((ParmBlkPtr) &closePB); if (err != noErr) { panic("error closing async connect socket"); } statePtr->flags |= TCP_RELEASE; InitMacTCPParamBlock(&statePtr->pb, TCPRelease); statePtr->pb.tcpStream = statePtr->tcpStream; err = PBControlSync((ParmBlkPtr) &statePtr->pb); if (err != noErr) { panic("error releasing async connect socket"); } /* * Free the buffer space used by the socket and the * actual socket state data structure. */ ckfree((char *) statePtr->pb.csParam.create.rcvBuff); FreeSocketInfo(statePtr); return 0; } /* * Client sockets: * If a background write is in progress, don't close * the socket yet. The completion routine for the * write will take care of it. */ if (!(statePtr->flags & TCP_WRITING)) { InitMacTCPParamBlock(&statePtr->pb, TCPClose); statePtr->pb.tcpStream = tcpStream; statePtr->pb.ioCompletion = closeUPP; statePtr->pb.csParam.close.userDataPtr = (Ptr) statePtr; err = PBControlAsync((ParmBlkPtr) &statePtr->pb); if (err != noErr) { Debugger(); statePtr->flags |= TCP_RELEASE; /* return 0; */ } } SocketFreeProc(instanceData); return 0;}/* *---------------------------------------------------------------------- * * CloseCompletionRoutine -- * * Handles the close protocol for a Tcp socket. This will do * a series of calls to release all data currently buffered for * the socket. This is important to do to as it allows the remote * connection to recieve and issue it's own close on the socket. * Note that this function is running at interupt time and can't * allocate memory or do much else except set state. * * Results: * None. * * Side effects: * The buffers for the socket are flushed. * *---------------------------------------------------------------------- */static voidCloseCompletionRoutine( TCPiopb *pbPtr) /* Tcp parameter block. */{ TcpState *statePtr; OSErr err; if (pbPtr->csCode == TCPClose) { statePtr = (TcpState *) (pbPtr->csParam.close.userDataPtr); } else { statePtr = (TcpState *) (pbPtr->csParam.receive.userDataPtr); } /* * It's very bad if the statePtr is nNULL - we should probably panic... */ if (statePtr == NULL) { Debugger(); return; } WakeUpProcess(&statePtr->psn); /* * If there is an error we assume the remote side has already * close. We are done closing as soon as we decide that the * remote connection has closed. */ if (pbPtr->ioResult != noErr) { statePtr->flags |= TCP_RELEASE; return; } if (statePtr->flags & TCP_REMOTE_CLOSED) { statePtr->flags |= TCP_RELEASE; return; } /* * If we just did a recieve we need to return the buffers. * Otherwise, attempt to recieve more data until we recieve an * error (usually because we have no more data). */ if (statePtr->pb.csCode == TCPNoCopyRcv) { InitMacTCPParamBlock(&statePtr->pb, TCPRcvBfrReturn); statePtr->pb.tcpStream = statePtr->tcpStream; statePtr->pb.ioCompletion = closeUPP; statePtr->pb.csParam.receive.rdsPtr = (Ptr) statePtr->rdsarray; statePtr->pb.csParam.receive.userDataPtr = (Ptr) statePtr; err = PBControlAsync((ParmBlkPtr) &statePtr->pb); } else { InitMacTCPParamBlock(&statePtr->pb, TCPNoCopyRcv); statePtr->pb.tcpStream = statePtr->tcpStream; statePtr->pb.ioCompletion = closeUPP; statePtr->pb.csParam.receive.commandTimeoutValue = 1; statePtr->pb.csParam.receive.rdsPtr = (Ptr) statePtr->rdsarray; statePtr->pb.csParam.receive.rdsLength = 5; statePtr->pb.csParam.receive.userDataPtr = (Ptr) statePtr; err = PBControlAsync((ParmBlkPtr) &statePtr->pb); } if (err != noErr) { statePtr->flags |= TCP_RELEASE; }}/* *---------------------------------------------------------------------- * * SocketFreeProc -- * * This callback is invoked in order to delete * the notifier data associated with a file handle. * * Results: * None. * * Side effects: * Removes the SocketInfo from the global socket list. * *---------------------------------------------------------------------- */static voidSocketFreeProc( ClientData clientData) /* Channel state. */{ TcpState *statePtr = (TcpState *) clientData; OSErr err; TCPiopb statusPB; /* * Get the status of this connection. We need to do a * few tests to see if it's OK to release the stream now. */ if (!(statePtr->flags & TCP_RELEASE)) { return; } 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. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -