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

📄 tclmacsock.c

📁 tcl是工具命令语言
💻 C
📖 第 1 页 / 共 5 页
字号:
 * 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. */    CONST 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 (TclpHasSockets(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;    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);    if (!(flags & TCL_FILE_EVENTS)) {	return 0;    }    /*     * Find the specified socket on the socket list.     */    for (statePtr = tsdPtr->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 intWaitForSocketEvent(    TcpState *statePtr,		/* Information about this socket. */    int mask,			/* Events to look for. */    int *errorCodePtr)		/* Where to store errors? */{    OSErr err;    TCPiopb statusPB;    EventRecord dummy;    /*     * Loop until we get the specified condition, unless the socket is     * asynchronous.     */        do {	statusPB.ioCRefNum = driverRefNum;	statusPB.tcpStream = statePtr->tcpStream;	statusPB.csCode = TCPStatus;	err = PBControlSync((ParmBlkPtr) &statusPB);	if (err != noErr) {            /*             * I am not sure why it is right to return 1 - indicating success             * for synchronous sockets when an attempt to get status on the             * driver yeilds an error.   But it is CERTAINLY wrong for async             * sockect which have not yet connected.             */             	    if (statePtr->flags & TCP_ASYNC_CONNECT) {	        *errorCodePtr = EWOULDBLOCK;	        return 0;	    } else {	        statePtr->checkMask |= (TCL_READABLE | TCL_WRITABLE);	        return 1;	    }	}	statePtr->checkMask = 0;		/*	 * The "6" below is the "connection being established" flag.  I couldn't	 * find a define for this in MacTCP.h, but that's what the programmer's	 * guide says.	 */	 	if ((statusPB.csParam.status.connectionState != 0)	        && (statusPB.csParam.status.connectionState != 4)	        && (statusPB.csParam.status.connectionState != 6)) {	    if (statusPB.csParam.status.amtUnreadData > 0) {	        statePtr->checkMask |= TCL_READABLE;	    }	    if (!(statePtr->flags & TCP_WRITING)		    && (statusPB.csParam.status.sendWindow - 			    statusPB.csParam.status.amtUnackedData) > 0) {	        statePtr->flags &= ~(TCP_ASYNC_CONNECT);	        statePtr->checkMask |= TCL_WRITABLE;	    }	    if (mask & statePtr->checkMask) {	        return 1;	    }        } else {            break;        }        	/*	 * Call the system to let other applications run while we	 * are waiting for this event to occur.	 */		WaitNextEvent(0, &dummy, 1, NULL);    } while (!(statePtr->flags & TCP_ASYNC_SOCKET));    *errorCodePtr = EWOULDBLOCK;    return 0;} /* *---------------------------------------------------------------------- * * TcpAccept -- *	Accept a TCP socket connection.  This is called by the event  *	loop, and it in turns calls any registered callbacks for this *	channel. * * Results: *	None. * * Side effects: *	Evals the Tcl script associated with the server socket. * *---------------------------------------------------------------------- */static voidTcpAccept(    TcpState *statePtr){    TcpState *newStatePtr;    StreamPtr tcpStream;    char remoteHostname[255];    OSErr err;    ip_addr remoteAddress;    long remotePort;    char channelName[20];        statePtr->flags &= ~TCP_LISTEN_CONNECT;    statePtr->checkMask &= ~TCL_READABLE;    /*     * Transfer sever stream to new connection.     */    tcpStream = statePtr->tcpStream;    newStatePtr = NewSocketInfo(tcpStream);    newStatePtr->tcpStream = tcpStream;    sprintf(channelName, "sock%d", socketNumber++);    newStatePtr->flags |= TCP_CONNECTED;    newStatePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,            (ClientData) newStatePtr, (TCL_READABLE | TCL_WRITABLE));    Tcl_SetChannelBufferSize(newStatePtr->channel, socketBufferSize);    Tcl_SetChannelOption(NULL, newStatePtr->channel, "-translation",	    "auto crlf");    remoteAddress = statePtr->pb.csParam.open.remoteHost;    remotePort = statePtr->pb.csParam.open.remotePort;    /*     * Reopen passive connect.  Make new tcpStream the server.     */    ClearZombieSockets();    InitMacTCPParamBlock(&statePtr->pb, TCPCreate);    statePtr->pb.csParam.create.rcvBuff = ckalloc(socketBufferSize);    statePtr->pb.csParam.create.rcvBuffLen = socketBufferSize;    err = PBControlSync((ParmBlkPtr) &statePtr->pb);    if (err != noErr) {	/* 	 * Hmmm...  We can't reopen the server.  We'll go ahead	 * an continue - but we are kind of broken now...	 */	 Debugger();	 statePtr->tcpStream = -1;	 statePtr->flags |= TCP_SERVER_ZOMBIE;    }    tcpStream = statePtr->tcpStream = statePtr->pb.tcpStream;        InitMacTCPParamBlock(&statePtr->pb, TCPPassiveOpen);    statePtr->pb.tcpStream = tcpStream;    statePtr->pb.csParam.open.localHost = 0;    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));    /*     * TODO: deal with case where we can't recreate server socket...     */    /*     * Finally we run the accept procedure.  We must do this last to make     * sure we are in a nice clean state.  This Tcl code can do anything     * including closing the server or client sockets we've just delt with.     */    if (statePtr->acceptProc != NULL) {	sprintf(remoteHostname, "%d.%d.%d.%d", remoteAddress>>24,		remoteAddress>>16 & 0xff, remoteAddress>>8 & 0xff,		remoteAddress & 0xff);			(statePtr->acceptProc)(statePtr->acceptProcData, newStatePtr->channel, 	    remoteHostname, remotePort);    }}/* *---------------------------------------------------------------------- * * Tcl_GetHostName -- * *	Returns the name of the local host. * * Results: *	A string containing the network name for this machine, or *	an empty string if we can't figure out the name.  The caller  *	must not modify or free this string. * * Side effects: *	None. * *---------------------------------------------------------------------- */CONST char *Tcl_GetHostName(){    static int  hostnameInited = 0;    static char hostname[255];    ip_addr ourAddress;    Tcl_DString dString;    OSErr err;        if (hostnameInited) {        return hostname;    }        if (TclpHasSockets(NULL) == TCL_OK) {	err = GetLocalAddress(&ourAddress);	if (err == noErr) {	    /*	     * Search for the doman name and return it if found.  Otherwise, 	     * just print the IP number to a string and return that.	     */	    Tcl_DStringInit(&dString);	    err = ResolveAddress(ourAddress, &dString);	    if (err == noErr) {		strcpy(hostname, dString.string);	    } else {		sprintf(hostname, "%d.%d.%d.%d", ourAddress>>24, ourAddress>>16 & 0xff,		    ourAddress>>8 & 0xff, ourAddress & 0xff);	    }	    Tcl_DStringFree(&dString);	    	    hostnameInited = 1;	    return hostname;	}    }    hostname[0] = '\0';    hostnameInited = 1;    return hostname;}/* *---------------------------------------------------------------------- * * ResolveAddress -- * *	This function is used to resolve an ip address to it's full  *	domain name address. * * Results: *	An os err value. * * Side effects: *	Treats client data as int we set to true. * *---------------------------------------------------------------------- */static OSErr ResolveAddress(    ip_addr tcpAddress, 	/* Address to resolve. */    Tcl_DString *dsPtr)		/* Returned address in string. */{    int i;    EventRecord dummy;    DNRState dnrState;    OSErr err;    /*     * Call AddrToName to resolve our ip address to our domain name.     * The call is async, so we must wait for a callback to tell us     * when to continue.     */     for (i = 0; i < NUM_ALT_ADDRS; i++) {	dnrState.hostInfo.addr[i] = 0;     }    dnrState.done = 0;    GetCurrentProcess(&(dnrState.psn));    err = AddrToName(tcpAddress, &dnrState.hostInfo, resultUPP, (Ptr) &dnrState);    if (err == cacheFault) {	while (!dnrState.done) {	    WaitNextEvent(0, &dummy, 1, NULL);	}    }        /*     * If there is no error in finding the domain name we set the     * result into the dynamic string.  We also work around a bug in     * MacTcp where an extranious '.' may be found at the end of the name.     */    if (dnrState.hostInfo.rtnCode == noErr) {	i = strlen(dnrState.hostInfo.cname) - 1;	if (dnrState.hostInfo.cname[i] == '.') {	    dnrState.hostInfo.cname[i] = '\0';	}	Tcl_DStringAppend(dsPtr, dnrState.hostInfo.cname, -1);    }        return dnrState.hostInfo.rtnCode;}/* *---------------------------------------------------------------------- * * DNRCompletionRoutine -- * *	This function is called when the Domain Name Server is done *	seviceing our request.  It just sets a flag that we can poll *	in functions like Tcl_GetHostName to let them know to continue. * * Results: *	None. * * Side effects: *	Treats client data as int we set to true. * *---------------------------------------------------------------------- */static pascal void DNRCompletionRoutine(    struct hostInfo *hostinfoPtr, 	/* Host infor struct. */    DNRState *dnrStatePtr)		/* Completetion state. */{    dnrStatePtr->done = true;    WakeUpProcess(&(dnrStatePtr->psn));}/* *---------------------------------------------------------------------- * * CleanUpExitProc -- * *	This procedure is invoked as an exi

⌨️ 快捷键说明

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