📄 tclunixchan.c
字号:
status = 1; (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &status, sizeof(status)); status = bind(sock, (struct sockaddr *) &sockaddr, sizeof(struct sockaddr)); if (status != -1) { status = listen(sock, SOMAXCONN); } } else { if (myaddr != NULL || myport != 0) { curState = 1; (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &curState, sizeof(curState)); status = bind(sock, (struct sockaddr *) &mysockaddr, sizeof(struct sockaddr)); if (status < 0) { goto bindError; } } /* * 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. */ if (async) {#ifndef USE_FIONBIO origState = fcntl(sock, F_GETFL); curState = origState | O_NONBLOCK; status = fcntl(sock, F_SETFL, curState);#endif#ifdef USE_FIONBIO curState = 1; status = ioctl(sock, FIONBIO, &curState);#endif } else { status = 0; } if (status > -1) { status = connect(sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr)); if (status < 0) { if (errno == EINPROGRESS) { asyncConnect = 1; status = 0; } } } }bindError: if (status < 0) { if (interp != NULL) { Tcl_AppendResult(interp, "couldn't open socket: ", Tcl_PosixError(interp), (char *) NULL); } if (sock != -1) { close(sock); } return NULL; } /* * Allocate a new TcpState for this socket. */ statePtr = (TcpState *) ckalloc((unsigned) sizeof(TcpState)); statePtr->flags = 0; if (asyncConnect) { statePtr->flags = TCP_ASYNC_CONNECT; } statePtr->fd = sock; return statePtr;addressError: if (sock != -1) { close(sock); } if (interp != NULL) { Tcl_AppendResult(interp, "couldn't open socket: ", Tcl_PosixError(interp), (char *) NULL); } return NULL;}/* *---------------------------------------------------------------------- * * CreateSocketAddress -- * * This function initializes a sockaddr structure for a host and port. * * Results: * 1 if the host was valid, 0 if the host could not be converted to * an IP address. * * Side effects: * Fills in the *sockaddrPtr structure. * *---------------------------------------------------------------------- */static intCreateSocketAddress(sockaddrPtr, host, port) struct sockaddr_in *sockaddrPtr; /* Socket address */ char *host; /* Host. NULL implies INADDR_ANY */ int port; /* Port number */{ struct hostent *hostent; /* Host database entry */ struct in_addr addr; /* For 64/32 bit madness */ (void) memset((VOID *) sockaddrPtr, '\0', sizeof(struct sockaddr_in)); sockaddrPtr->sin_family = AF_INET; sockaddrPtr->sin_port = htons((unsigned short) (port & 0xFFFF)); if (host == NULL) { addr.s_addr = INADDR_ANY; } else { addr.s_addr = inet_addr(host); if (addr.s_addr == -1) { hostent = gethostbyname(host); if (hostent != NULL) { memcpy((VOID *) &addr, (VOID *) hostent->h_addr_list[0], (size_t) hostent->h_length); } else {#ifdef EHOSTUNREACH errno = EHOSTUNREACH;#else#ifdef ENXIO errno = ENXIO;#endif#endif return 0; /* error */ } } } /* * NOTE: On 64 bit machines the assignment below is rumored to not * do the right thing. Please report errors related to this if you * observe incorrect behavior on 64 bit machines such as DEC Alphas. * Should we modify this code to do an explicit memcpy? */ sockaddrPtr->sin_addr.s_addr = addr.s_addr; return 1; /* Success. */}/* *---------------------------------------------------------------------- * * Tcl_OpenTcpClient -- * * Opens a TCP client socket and creates a channel around it. * * Results: * The channel or NULL if failed. An error message is returned * in the interpreter on failure. * * Side effects: * Opens a client socket and creates a new channel. * *---------------------------------------------------------------------- */Tcl_ChannelTcl_OpenTcpClient(interp, port, host, myaddr, myport, async) 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. */{ TcpState *statePtr; char channelName[20]; /* * Create a new client socket and wrap it in a channel. */ statePtr = CreateSocket(interp, port, host, 0, myaddr, myport, async); if (statePtr == NULL) { return NULL; } statePtr->acceptProc = NULL; statePtr->acceptProcData = (ClientData) NULL; sprintf(channelName, "sock%d", statePtr->fd); statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, (ClientData) statePtr, (TCL_READABLE | TCL_WRITABLE)); if (Tcl_SetChannelOption(interp, statePtr->channel, "-translation", "auto crlf") == TCL_ERROR) { Tcl_Close((Tcl_Interp *) NULL, statePtr->channel); return NULL; } return statePtr->channel;}/* *---------------------------------------------------------------------- * * 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(sock) ClientData sock; /* The socket to wrap up into a channel. */{ TcpState *statePtr; char channelName[20]; statePtr = (TcpState *) ckalloc((unsigned) sizeof(TcpState)); statePtr->fd = (int) sock; statePtr->acceptProc = NULL; statePtr->acceptProcData = (ClientData) NULL; sprintf(channelName, "sock%d", statePtr->fd); statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, (ClientData) statePtr, (TCL_READABLE | TCL_WRITABLE)); if (Tcl_SetChannelOption((Tcl_Interp *) NULL, statePtr->channel, "-translation", "auto crlf") == TCL_ERROR) { Tcl_Close((Tcl_Interp *) NULL, statePtr->channel); return NULL; } return statePtr->channel;}/* *---------------------------------------------------------------------- * * Tcl_OpenTcpServer -- * * Opens a TCP server socket and creates a channel around it. * * Results: * The channel or NULL if failed. If an error occurred, an * error message is left in interp->result if interp is * not NULL. * * Side effects: * Opens a server socket and creates a new channel. * *---------------------------------------------------------------------- */Tcl_ChannelTcl_OpenTcpServer(interp, port, myHost, acceptProc, acceptProcData) Tcl_Interp *interp; /* For error reporting - may be * NULL. */ int port; /* Port number to open. */ char *myHost; /* 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]; /* * Create a new client socket and wrap it in a channel. */ statePtr = CreateSocket(interp, port, myHost, 1, NULL, 0, 0); if (statePtr == NULL) { return NULL; } statePtr->acceptProc = acceptProc; statePtr->acceptProcData = acceptProcData; /* * Set up the callback mechanism for accepting connections * from new clients. */ Tcl_CreateFileHandler(statePtr->fd, TCL_READABLE, TcpAccept, (ClientData) statePtr); sprintf(channelName, "sock%d", statePtr->fd); statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, (ClientData) statePtr, 0); return statePtr->channel;}/* *---------------------------------------------------------------------- * * TcpAccept -- * Accept a TCP socket connection. This is called by the event loop. * * Results: * None. * * Side effects: * Creates a new connection socket. Calls the registered callback * for the connection acceptance mechanism. * *---------------------------------------------------------------------- */ /* ARGSUSED */static voidTcpAccept(data, mask) ClientData data; /* Callback token. */ int mask; /* Not used. */{ TcpState *sockState; /* Client data of server socket. */ int newsock; /* The new client socket */ TcpState *newSockState; /* State for new socket. */ struct sockaddr_in addr; /* The remote address */ int len; /* For accept interface */ char channelName[20]; sockState = (TcpState *) data; len = sizeof(struct sockaddr_in); newsock = accept(sockState->fd, (struct sockaddr *)&addr, &len); if (newsock < 0) { return; } /* * Set close-on-exec flag to prevent the newly accepted socket from * being inherited by child processes. */ (void) fcntl(newsock, F_SETFD, FD_CLOEXEC); newSockState = (TcpState *) ckalloc((unsigned) sizeof(TcpState)); newSockState->flags = 0; newSockState->fd = newsock; newSockState->acceptProc = (Tcl_TcpAcceptProc *) NULL; newSockState->acceptProcData = (ClientData) NULL; sprintf(channelName, "sock%d", newsock); newSockState->channel = Tcl_CreateChannel(&tcpChannelType, channelName, (ClientData) newSockState, (TCL_READABLE | TCL_WRITABLE)); Tcl_SetChannelOption((Tcl_Interp *) NULL, newSockState->channel, "-translation", "auto crlf"); if (sockState->acceptProc != (Tcl_TcpAcceptProc *) NULL) { (sockState->acceptProc) (sockState->acceptProcData, newSockState->channel, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); }}/* *---------------------------------------------------------------------- * * TclGetDefaultStdChannel -- * * Creates channels for standard input, standard output or standard * error output if they do not already exist. * * Results: * Returns the specified default standard channel, or NULL. * * Side effects: * May cause the creation of a standard channel and the underlying * file. * *---------------------------------------------------------------------- */Tcl_ChannelTclGetDefaultStdChannel(type) int type; /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR. */{ Tcl_Channel channel = NULL; int fd = 0; /* Initializations needed to prevent */ int mode = 0; /* compiler warning (used before set). */ char *bufMode = NULL; switch (type) { case TCL_STDIN: if ((lseek(0, (off_t) 0, SEEK_CUR) == -1) && (errno == EBADF)) { return (Tcl_Channel) NULL; } fd = 0; mode = TCL_READABLE; bufMode = "line"; break; case TCL_STDOUT: if ((lseek(1, (off_t) 0, SEEK_CUR) == -1) && (errno == EBADF)) { return (Tcl_Channel) NULL; } fd = 1; mode = TCL_WRITABLE; bufMode = "line"; break; case TCL_STDERR: if ((lseek(2, (off_t) 0, SEEK_CUR) == -1) && (errno == EBADF)) { return (Tcl_Channel) NULL; } fd = 2; mode = TCL_WRITABLE; bufMode = "none"; break; default: panic("TclGetDefaultStdChannel: Unexpected channel type"); break; } channel = Tcl_MakeFileChannel((ClientData) fd, mode); /* * Set up the normal channel options for stdio handles. */ Tcl_SetChannelOption(NULL, channel, "-translation", "auto"); Tcl_SetChannelOption(NULL, channel, "-buffering", bufMode); return channel;}/* *---------------------------------------------------------------------- * * Tcl_GetOpenFile -- * * Given a name of a channel registered in the given interpreter, * returns a FILE * for it. * * Results: * A standard Tcl result. If the channel is registered in the given * interpreter and it is managed by the "file" channel driver, and * it is open for the requested mode, then the output parameter * filePtr is set to a FILE * for the underlying file. On error, the * filePtr is not set, TCL_ERROR is returned and an error message is * left in interp->result. * * Side effects: * May invoke fdopen to create the FILE * for the requested file. * *---------------------------------------------------------------------- */intTcl_GetOpenFile(interp, string, forWriting, checkUsage, filePtr) Tcl_Interp *interp; /* Interpreter in which to find file. */ char *string; /* String that identifies file. */ int forWriting; /* 1 means the file is going to be used * for writing, 0 means for reading. */ int checkUsage; /* 1 means verify that the file was opened
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -