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

📄 tclmacsock.c

📁 linux系统下的音频通信
💻 C
📖 第 1 页 / 共 5 页
字号:
 * Side effects: *	Adds the socket to the global socket list, allocates memory. * *---------------------------------------------------------------------- */static TcpState *NewSocketInfo(    StreamPtr tcpStream){    TcpState *statePtr;    statePtr = (TcpState *) ckalloc((unsigned) sizeof(TcpState));    statePtr->tcpStream = tcpStream;    statePtr->psn = applicationPSN;    statePtr->flags = 0;    statePtr->checkMask = 0;    statePtr->watchMask = 0;    statePtr->acceptProc = (Tcl_TcpAcceptProc *) NULL;    statePtr->acceptProcData = (ClientData) NULL;    statePtr->nextPtr = socketList;    socketList = statePtr;    return statePtr;}/* *---------------------------------------------------------------------- * * FreeSocketInfo -- * *	This function deallocates a SocketInfo structure that is no *	longer needed. * * Results: *	None. * * Side effects: *	Removes the socket from the global socket list, frees memory. * *---------------------------------------------------------------------- */static voidFreeSocketInfo(    TcpState *statePtr)		/* The state pointer to free. */{    if (statePtr == socketList) {	socketList = statePtr->nextPtr;    } else {	TcpState *p;	for (p = socketList; p != NULL; p = p->nextPtr) {	    if (p->nextPtr == statePtr) {		p->nextPtr = statePtr->nextPtr;		break;	    }	}    }    ckfree((char *) statePtr);}/* *---------------------------------------------------------------------- * * Tcl_MakeTcpClientChannel -- * *	Creates a Tcl_Channel from an existing client TCP socket. * * Results: *	The Tcl_Channel wrapped around the preexisting TCP socket. * * Side effects: *	None. * *---------------------------------------------------------------------- */Tcl_ChannelTcl_MakeTcpClientChannel(    ClientData sock)	/* The socket to wrap up into a channel. */{    TcpState *statePtr;    char channelName[20];    if (TclHasSockets(NULL) != TCL_OK) {	return NULL;    }	    statePtr = NewSocketInfo((StreamPtr) sock);    /* TODO: do we need to set the port??? */        sprintf(channelName, "sock%d", socketNumber++);        statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,            (ClientData) statePtr, (TCL_READABLE | TCL_WRITABLE));    Tcl_SetChannelBufferSize(statePtr->channel, socketBufferSize);    Tcl_SetChannelOption(NULL, statePtr->channel, "-translation", "auto crlf");    return statePtr->channel;}/* *---------------------------------------------------------------------- * * CreateSocket -- * *	This function opens a new socket and initializes the *	SocketInfo structure. * * Results: *	Returns a new SocketInfo, or NULL with an error in interp. * * Side effects: *	Adds a new socket to the socketList. * *---------------------------------------------------------------------- */static TcpState *CreateSocket(    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. */    char *myaddr,		/* Optional client-side address */    int myport,			/* Optional client-side port */    int server,			/* 1 if socket should be a server socket,				 * else 0 for a client socket. */    int async)			/* 1 create async, 0 do sync. */{    ip_addr macAddr;    OSErr err;    TCPiopb pb;    StreamPtr tcpStream;    TcpState *statePtr;    char * buffer;        /*     * Figure out the ip address from the host string.     */    if (host == NULL) {	err = GetLocalAddress(&macAddr);    } else {	err = GetHostFromString(host, &macAddr);    }    if (err != noErr) {	Tcl_SetErrno(EHOSTUNREACH);	if (interp != (Tcl_Interp *) NULL) {	    Tcl_AppendResult(interp, "couldn't open socket: ",                        Tcl_PosixError(interp), (char *) NULL);	}	return (TcpState *) NULL;    }        /*     * Create a MacTCP stream and create the state used for socket     * transactions from here on out.     */    ClearZombieSockets();    buffer = ckalloc(socketBufferSize);    InitMacTCPParamBlock(&pb, TCPCreate);    pb.csParam.create.rcvBuff = buffer;    pb.csParam.create.rcvBuffLen = socketBufferSize;    err = PBControlSync((ParmBlkPtr) &pb);    if (err != noErr) {        Tcl_SetErrno(0); /* TODO: set to ENOSR - maybe?*/        if (interp != (Tcl_Interp *) NULL) {	    Tcl_AppendResult(interp, "couldn't open socket: ",		Tcl_PosixError(interp), (char *) NULL);        }	return (TcpState *) NULL;    }    tcpStream = pb.tcpStream;    statePtr = NewSocketInfo(tcpStream);    statePtr->port = port;        if (server) {        /*          * Set up server connection.         */	InitMacTCPParamBlock(&statePtr->pb, TCPPassiveOpen);	statePtr->pb.tcpStream = tcpStream;	statePtr->pb.csParam.open.localPort = statePtr->port;	statePtr->pb.ioCompletion = completeUPP; 	statePtr->pb.csParam.open.userDataPtr = (Ptr) statePtr;	statePtr->flags |= TCP_LISTENING;	err = PBControlAsync((ParmBlkPtr) &(statePtr->pb));	/*	 * If this is a server on port 0 then we need to wait until	 * the dynamic port allocation is made by the MacTcp driver.	 */	if (statePtr->port == 0) {	    EventRecord dummy;	    while (statePtr->pb.csParam.open.localPort == 0) {		WaitNextEvent(0, &dummy, 1, NULL);		if (statePtr->pb.ioResult != 0) {		    break;		}	    }	    statePtr->port = statePtr->pb.csParam.open.localPort;	}	Tcl_SetErrno(EINPROGRESS);    } else {	/*	 * Attempt to connect. The connect may fail at present with an	 * EINPROGRESS but at a later time it will complete. The caller	 * will set up a file handler on the socket if she is interested in	 * being informed when the connect completes.	 */	InitMacTCPParamBlock(&statePtr->pb, TCPActiveOpen);	statePtr->pb.tcpStream = tcpStream;	statePtr->pb.csParam.open.remoteHost = macAddr;	statePtr->pb.csParam.open.remotePort = port;	statePtr->pb.csParam.open.localHost = 0;	statePtr->pb.csParam.open.localPort = myport;	statePtr->pb.csParam.open.userDataPtr = (Ptr) statePtr;	statePtr->pb.ioCompletion = completeUPP;	if (async) {	    statePtr->flags |= TCP_ASYNC_CONNECT;	    err = PBControlAsync((ParmBlkPtr) &(statePtr->pb));	    Tcl_SetErrno(EINPROGRESS);	} else {	    err = PBControlSync((ParmBlkPtr) &(statePtr->pb));	}    }        switch (err) {	case noErr:	    if (!async) {		statePtr->flags |= TCP_CONNECTED;	    }	    return statePtr;	case duplicateSocket:	    Tcl_SetErrno(EADDRINUSE);	    break;	case openFailed:	case connectionTerminated:	    Tcl_SetErrno(ECONNREFUSED);	    break;	case invalidStreamPtr:	case connectionExists:	default:	    /*	     * These cases should never occur.  However, we will fail	     * gracefully and hope Tcl can resume.  The alternative is to panic	     * which is probably a bit drastic.	     */	    Debugger();	    Tcl_SetErrno(err);    }    /*     * We had error during the connection.  Release the stream     * and file handle.  Also report to the interp.     */    pb.ioCRefNum = driverRefNum;    pb.csCode = TCPRelease;    pb.tcpStream = tcpStream;    pb.ioCompletion = NULL;     err = PBControlSync((ParmBlkPtr) &pb);    if (interp != (Tcl_Interp *) NULL) {	Tcl_AppendResult(interp, "couldn't open socket: ",	    Tcl_PosixError(interp), (char *) NULL);    }    ckfree(buffer);    FreeSocketInfo(statePtr);    return (TcpState *) NULL;}/* *---------------------------------------------------------------------- * * Tcl_OpenTcpClient -- * *	Opens a TCP client socket and creates a channel around it. * * Results: *	The channel or NULL if failed. On failure, the routine also *	sets the output argument errorCodePtr to the error code. * * Side effects: *	Opens a client socket and creates a new channel. * *---------------------------------------------------------------------- */Tcl_ChannelTcl_OpenTcpClient(    Tcl_Interp *interp, 		/* For error reporting; can be NULL. */    int port, 				/* Port number to open. */    char *host, 			/* Host on which to open port. */    char *myaddr, 			/* Client-side address */    int myport, 			/* Client-side port */    int async)				/* If nonzero, attempt to do an                                         * asynchronous connect. Otherwise                                         * we do a blocking connect.                                          * - currently ignored */{    TcpState *statePtr;    char channelName[20];    if (TclHasSockets(interp) != TCL_OK) {	return NULL;    }	    /*     * Create a new client socket and wrap it in a channel.     */    statePtr = CreateSocket(interp, port, host, myaddr, myport, 0, async);    if (statePtr == NULL) {	return NULL;    }        sprintf(channelName, "sock%d", socketNumber++);    statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,            (ClientData) statePtr, (TCL_READABLE | TCL_WRITABLE));    Tcl_SetChannelBufferSize(statePtr->channel, socketBufferSize);    Tcl_SetChannelOption(NULL, statePtr->channel, "-translation", "auto crlf");    return statePtr->channel;}/* *---------------------------------------------------------------------- * * Tcl_OpenTcpServer -- * *	Opens a TCP server socket and creates a channel around it. * * Results: *	The channel or NULL if failed. * * Side effects: *	Opens a server socket and creates a new channel. * *---------------------------------------------------------------------- */Tcl_ChannelTcl_OpenTcpServer(    Tcl_Interp *interp,			/* For error reporting - may be                                         * NULL. */    int port,				/* Port number to open. */    char *host,				/* Name of local host. */    Tcl_TcpAcceptProc *acceptProc,	/* Callback for accepting connections                                         * from new clients. */    ClientData acceptProcData)		/* Data for the callback. */{    TcpState *statePtr;    char channelName[20];    if (TclHasSockets(interp) != TCL_OK) {	return NULL;    }    /*     * Create a new client socket and wrap it in a channel.     */    statePtr = CreateSocket(interp, port, host, NULL, 0, 1, 1);    if (statePtr == NULL) {	return NULL;    }    statePtr->acceptProc = acceptProc;    statePtr->acceptProcData = acceptProcData;    sprintf(channelName, "sock%d", socketNumber++);    statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,            (ClientData) statePtr, 0);    Tcl_SetChannelBufferSize(statePtr->channel, socketBufferSize);    Tcl_SetChannelOption(NULL, statePtr->channel, "-translation", "auto crlf");    return statePtr->channel;}/* *---------------------------------------------------------------------- * * SocketEventProc -- * *	This procedure is called by Tcl_ServiceEvent when a socket event *	reaches the front of the event queue.  This procedure is *	responsible for notifying the generic channel code. * * Results: *	Returns 1 if the event was handled, meaning it should be removed *	from the queue.  Returns 0 if the event was not handled, meaning *	it should stay on the queue.  The only time the event isn't *	handled is if the TCL_FILE_EVENTS flag bit isn't set. * * Side effects: *	Whatever the channel callback procedures do. * *---------------------------------------------------------------------- */static intSocketEventProc(    Tcl_Event *evPtr,		/* Event to service. */    int flags)			/* Flags that indicate what events to				 * handle, such as TCL_FILE_EVENTS. */{    TcpState *statePtr;    SocketEvent *eventPtr = (SocketEvent *) evPtr;    int mask = 0;    if (!(flags & TCL_FILE_EVENTS)) {	return 0;    }    /*     * Find the specified socket on the socket list.     */    for (statePtr = socketList; statePtr != NULL;	    statePtr = statePtr->nextPtr) {	if ((statePtr == eventPtr->statePtr) && 		(statePtr->tcpStream == eventPtr->tcpStream)) {	    break;	}    }    /*     * Discard events that have gone stale.     */    if (!statePtr) {	return 1;    }    statePtr->flags &= ~(TCP_PENDING);    if (statePtr->flags & TCP_RELEASE) {	SocketFreeProc(statePtr);	return 1;    }    /*     * Handle connection requests directly.     */    if (statePtr->flags & TCP_LISTEN_CONNECT) {	if (statePtr->checkMask & TCL_READABLE) {	    TcpAccept(statePtr);	}	return 1;    }    /*     * Mask off unwanted events then notify the channel.     */    mask = statePtr->checkMask & statePtr->watchMask;    if (mask) {	Tcl_NotifyChannel(statePtr->channel, mask);    }    return 1;}/* *---------------------------------------------------------------------- * * WaitForSocketEvent -- * *	Waits until one of the specified events occurs on a socket. * * Results: *	Returns 1 on success or 0 on failure, with an error code in *	errorCodePtr. * * Side effects: *	Processes socket events off the system queue. * *---------------------------------------------------------------------- */static int

⌨️ 快捷键说明

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