📄 tclunixchan.c
字号:
/* * tclUnixChan.c * * Common channel driver for Unix channels based on files, command * pipes and TCP sockets. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * RCS: @(#) $Id: tclUnixChan.c,v 1.42 2003/02/21 02:36:27 hobbs Exp $ */#include "tclInt.h" /* Internal definitions for Tcl. */#include "tclPort.h" /* Portability features for Tcl. */#include "tclIO.h" /* To get Channel type declaration. *//* * sys/ioctl.h has already been included by tclPort.h. Including termios.h * or termio.h causes a bunch of warning messages because some duplicate * (but not contradictory) #defines exist in termios.h and/or termio.h */#undef NL0#undef NL1#undef CR0#undef CR1#undef CR2#undef CR3#undef TAB0#undef TAB1#undef TAB2#undef XTABS#undef BS0#undef BS1#undef FF0#undef FF1#undef ECHO#undef NOFLSH#undef TOSTOP#undef FLUSHO#undef PENDIN#define SUPPORTS_TTY#ifdef USE_TERMIOS# include <termios.h># ifdef HAVE_SYS_IOCTL_H# include <sys/ioctl.h># endif /* HAVE_SYS_IOCTL_H */# ifdef HAVE_SYS_MODEM_H# include <sys/modem.h># endif /* HAVE_SYS_MODEM_H */# define IOSTATE struct termios# define GETIOSTATE(fd, statePtr) tcgetattr((fd), (statePtr))# define SETIOSTATE(fd, statePtr) tcsetattr((fd), TCSADRAIN, (statePtr))# define GETCONTROL(fd, intPtr) ioctl((fd), TIOCMGET, (intPtr))# define SETCONTROL(fd, intPtr) ioctl((fd), TIOCMSET, (intPtr)) /* * TIP #35 introduced a different on exit flush/close behavior that * doesn't work correctly with standard channels on all systems. * The problem is tcflush throws away waiting channel data. This may * be necessary for true serial channels that may block, but isn't * correct in the standard case. This might be replaced with tcdrain * instead, but that can block. For now, we revert to making this do * nothing, and TtyOutputProc being the same old FileOutputProc. * -- hobbs [Bug #525783] */# define BAD_TIP35_FLUSH 0# if BAD_TIP35_FLUSH# define TTYFLUSH(fd) tcflush((fd), TCIOFLUSH);# else# define TTYFLUSH(fd)# endif /* BAD_TIP35_FLUSH */# ifdef FIONREAD# define GETREADQUEUE(fd, int) ioctl((fd), FIONREAD, &(int))# elif defined(FIORDCHK)# define GETREADQUEUE(fd, int) int = ioctl((fd), FIORDCHK, NULL)# endif /* FIONREAD */# ifdef TIOCOUTQ# define GETWRITEQUEUE(fd, int) ioctl((fd), TIOCOUTQ, &(int))# endif /* TIOCOUTQ */# if defined(TIOCSBRK) && defined(TIOCCBRK)/* * Can't use ?: operator below because that messes up types on either * Linux or Solaris (the two are mutually exclusive!) */# define SETBREAK(fd, flag) \ if (flag) { \ ioctl((fd), TIOCSBRK, NULL); \ } else { \ ioctl((fd), TIOCCBRK, NULL); \ }# endif /* TIOCSBRK&TIOCCBRK */# if !defined(CRTSCTS) && defined(CNEW_RTSCTS)# define CRTSCTS CNEW_RTSCTS# endif /* !CRTSCTS&CNEW_RTSCTS */#else /* !USE_TERMIOS */#ifdef USE_TERMIO# include <termio.h># define IOSTATE struct termio# define GETIOSTATE(fd, statePtr) ioctl((fd), TCGETA, (statePtr))# define SETIOSTATE(fd, statePtr) ioctl((fd), TCSETAW, (statePtr))#else /* !USE_TERMIO */#ifdef USE_SGTTY# include <sgtty.h># define IOSTATE struct sgttyb# define GETIOSTATE(fd, statePtr) ioctl((fd), TIOCGETP, (statePtr))# define SETIOSTATE(fd, statePtr) ioctl((fd), TIOCSETP, (statePtr))#else /* !USE_SGTTY */# undef SUPPORTS_TTY#endif /* !USE_SGTTY */#endif /* !USE_TERMIO */#endif /* !USE_TERMIOS *//* * This structure describes per-instance state of a file based channel. */typedef struct FileState { Tcl_Channel channel; /* Channel associated with this file. */ int fd; /* File handle. */ int validMask; /* OR'ed combination of TCL_READABLE, * TCL_WRITABLE, or TCL_EXCEPTION: indicates * which operations are valid on the file. */#ifdef DEPRECATED struct FileState *nextPtr; /* Pointer to next file in list of all * file channels. */#endif /* DEPRECATED */} FileState;#ifdef SUPPORTS_TTY/* * The following structure describes per-instance state of a tty-based * channel. */typedef struct TtyState { FileState fs; /* Per-instance state of the file * descriptor. Must be the first field. */ int stateUpdated; /* Flag to say if the state has been * modified and needs resetting. */ IOSTATE savedState; /* Initial state of device. Used to reset * state when device closed. */} TtyState;/* * The following structure is used to set or get the serial port * attributes in a platform-independant manner. */typedef struct TtyAttrs { int baud; int parity; int data; int stop;} TtyAttrs;#endif /* !SUPPORTS_TTY */#define UNSUPPORTED_OPTION(detail) \ if (interp) { \ Tcl_AppendResult(interp, (detail), \ " not supported for this platform", (char *) NULL); \ }#ifdef DEPRECATEDtypedef struct ThreadSpecificData { /* * List of all file channels currently open. This is per thread and is * used to match up fd's to channels, which rarely occurs. */ FileState *firstFilePtr;} ThreadSpecificData;static Tcl_ThreadDataKey dataKey;#endif /* DEPRECATED *//* * This structure describes per-instance state of a tcp based channel. */typedef struct TcpState { Tcl_Channel channel; /* Channel associated with this file. */ int fd; /* The socket itself. */ int flags; /* ORed combination of the bitfields * defined below. */ Tcl_TcpAcceptProc *acceptProc; /* Proc to call on accept. */ ClientData acceptProcData; /* The data for the accept proc. */} TcpState;/* * These bits may be ORed together into the "flags" field of a TcpState * structure. */#define TCP_ASYNC_SOCKET (1<<0) /* Asynchronous socket. */#define TCP_ASYNC_CONNECT (1<<1) /* Async connect in progress. *//* * The following defines the maximum length of the listen queue. This is * the number of outstanding yet-to-be-serviced requests for a connection * on a server socket, more than this number of outstanding requests and * the connection request will fail. */#ifndef SOMAXCONN# define SOMAXCONN 100#endif /* SOMAXCONN */#if (SOMAXCONN < 100)# undef SOMAXCONN# define SOMAXCONN 100#endif /* SOMAXCONN < 100 *//* * The following defines how much buffer space the kernel should maintain * for a socket. */#define SOCKET_BUFSIZE 4096/* * Static routines for this file: */static TcpState * CreateSocket _ANSI_ARGS_((Tcl_Interp *interp, int port, CONST char *host, int server, CONST char *myaddr, int myport, int async));static int CreateSocketAddress _ANSI_ARGS_( (struct sockaddr_in *sockaddrPtr, CONST char *host, int port));static int FileBlockModeProc _ANSI_ARGS_(( ClientData instanceData, int mode));static int FileCloseProc _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp));static int FileGetHandleProc _ANSI_ARGS_((ClientData instanceData, int direction, ClientData *handlePtr));static int FileInputProc _ANSI_ARGS_((ClientData instanceData, char *buf, int toRead, int *errorCode));static int FileOutputProc _ANSI_ARGS_(( ClientData instanceData, CONST char *buf, int toWrite, int *errorCode));static int FileSeekProc _ANSI_ARGS_((ClientData instanceData, long offset, int mode, int *errorCode));static Tcl_WideInt FileWideSeekProc _ANSI_ARGS_((ClientData instanceData, Tcl_WideInt offset, int mode, int *errorCode));static void FileWatchProc _ANSI_ARGS_((ClientData instanceData, int mask));static void TcpAccept _ANSI_ARGS_((ClientData data, int mask));static int TcpBlockModeProc _ANSI_ARGS_((ClientData data, int mode));static int TcpCloseProc _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp));static int TcpGetHandleProc _ANSI_ARGS_((ClientData instanceData, int direction, ClientData *handlePtr));static int TcpGetOptionProc _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp, CONST char *optionName, Tcl_DString *dsPtr));static int TcpInputProc _ANSI_ARGS_((ClientData instanceData, char *buf, int toRead, int *errorCode));static int TcpOutputProc _ANSI_ARGS_((ClientData instanceData, CONST char *buf, int toWrite, int *errorCode));static void TcpWatchProc _ANSI_ARGS_((ClientData instanceData, int mask));#ifdef SUPPORTS_TTYstatic int TtyCloseProc _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp));static void TtyGetAttributes _ANSI_ARGS_((int fd, TtyAttrs *ttyPtr));static int TtyGetOptionProc _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp, CONST char *optionName, Tcl_DString *dsPtr));static FileState * TtyInit _ANSI_ARGS_((int fd, int initialize));#if BAD_TIP35_FLUSHstatic int TtyOutputProc _ANSI_ARGS_((ClientData instanceData, CONST char *buf, int toWrite, int *errorCode));#endif /* BAD_TIP35_FLUSH */static int TtyParseMode _ANSI_ARGS_((Tcl_Interp *interp, CONST char *mode, int *speedPtr, int *parityPtr, int *dataPtr, int *stopPtr));static void TtySetAttributes _ANSI_ARGS_((int fd, TtyAttrs *ttyPtr));static int TtySetOptionProc _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp, CONST char *optionName, CONST char *value));#endif /* SUPPORTS_TTY */static int WaitForConnect _ANSI_ARGS_((TcpState *statePtr, int *errorCodePtr));static Tcl_Channel MakeTcpClientChannelMode _ANSI_ARGS_( (ClientData tcpSocket, int mode));/* * This structure describes the channel type structure for file based IO: */static Tcl_ChannelType fileChannelType = { "file", /* Type name. */ TCL_CHANNEL_VERSION_3, /* v3 channel */ FileCloseProc, /* Close proc. */ FileInputProc, /* Input proc. */ FileOutputProc, /* Output proc. */ FileSeekProc, /* Seek proc. */ NULL, /* Set option proc. */ NULL, /* Get option proc. */ FileWatchProc, /* Initialize notifier. */ FileGetHandleProc, /* Get OS handles out of channel. */ NULL, /* close2proc. */ FileBlockModeProc, /* Set blocking or non-blocking mode.*/ NULL, /* flush proc. */ NULL, /* handler proc. */ FileWideSeekProc, /* wide seek proc. */};#ifdef SUPPORTS_TTY/* * This structure describes the channel type structure for serial IO. * Note that this type is a subclass of the "file" type. */static Tcl_ChannelType ttyChannelType = { "tty", /* Type name. */ TCL_CHANNEL_VERSION_2, /* v2 channel */ TtyCloseProc, /* Close proc. */ FileInputProc, /* Input proc. */#if BAD_TIP35_FLUSH TtyOutputProc, /* Output proc. */#else /* !BAD_TIP35_FLUSH */ FileOutputProc, /* Output proc. */#endif /* BAD_TIP35_FLUSH */ NULL, /* Seek proc. */ TtySetOptionProc, /* Set option proc. */ TtyGetOptionProc, /* Get option proc. */ FileWatchProc, /* Initialize notifier. */ FileGetHandleProc, /* Get OS handles out of channel. */ NULL, /* close2proc. */ FileBlockModeProc, /* Set blocking or non-blocking mode.*/ NULL, /* flush proc. */ NULL, /* handler proc. */};#endif /* SUPPORTS_TTY *//* * This structure describes the channel type structure for TCP socket * based IO: */static Tcl_ChannelType tcpChannelType = { "tcp", /* Type name. */ TCL_CHANNEL_VERSION_2, /* v2 channel */ TcpCloseProc, /* Close proc. */ TcpInputProc, /* Input proc. */ TcpOutputProc, /* Output proc. */ NULL, /* Seek proc. */ NULL, /* Set option proc. */ TcpGetOptionProc, /* Get option proc. */ TcpWatchProc, /* Initialize notifier. */ TcpGetHandleProc, /* Get OS handles out of channel. */ NULL, /* close2proc. */ TcpBlockModeProc, /* Set blocking or non-blocking mode.*/ NULL, /* flush proc. */ NULL, /* handler proc. */};/* *---------------------------------------------------------------------- * * FileBlockModeProc -- * * Helper procedure to set blocking and nonblocking modes on a * file based channel. Invoked by generic IO level code. * * Results: * 0 if successful, errno when failed. * * Side effects: * Sets the device into blocking or non-blocking mode. * *---------------------------------------------------------------------- */ /* ARGSUSED */static intFileBlockModeProc(instanceData, mode) ClientData instanceData; /* File state. */ int mode; /* The mode to set. Can be one of * TCL_MODE_BLOCKING or * TCL_MODE_NONBLOCKING. */{ FileState *fsPtr = (FileState *) instanceData; int curStatus;#ifndef USE_FIONBIO curStatus = fcntl(fsPtr->fd, F_GETFL); if (mode == TCL_MODE_BLOCKING) { curStatus &= (~(O_NONBLOCK)); } else { curStatus |= O_NONBLOCK; } if (fcntl(fsPtr->fd, F_SETFL, curStatus) < 0) { return errno; } curStatus = fcntl(fsPtr->fd, F_GETFL);#else /* USE_FIONBIO */ if (mode == TCL_MODE_BLOCKING) { curStatus = 0; } else { curStatus = 1; } if (ioctl(fsPtr->fd, (int) FIONBIO, &curStatus) < 0) { return errno; }#endif /* !USE_FIONBIO */ return 0;}/* *---------------------------------------------------------------------- * * FileInputProc -- * * This procedure is invoked from the generic IO level to read * input from a file based channel. * * Results: * The number of bytes read is returned or -1 on error. An output * argument contains a POSIX error code if an error occurs, or zero. * * Side effects: * Reads input from the input device of the channel. * *---------------------------------------------------------------------- */static intFileInputProc(instanceData, buf, toRead, errorCodePtr) ClientData instanceData; /* File state. */ char *buf; /* Where to store data read. */ int toRead; /* How much space is available * in the buffer? */ int *errorCodePtr; /* Where to store error code. */{ FileState *fsPtr = (FileState *) instanceData; int bytesRead; /* How many bytes were actually * read from the input device? */ *errorCodePtr = 0; /* * Assume there is always enough input available. This will block * appropriately, and read will unblock as soon as a short read is * possible, if the channel is in blocking mode. If the channel is * nonblocking, the read will never block. */ bytesRead = read(fsPtr->fd, buf, (size_t) toRead); if (bytesRead > -1) { return bytesRead; } *errorCodePtr = errno; return -1;}/* *---------------------------------------------------------------------- * * FileOutputProc-- * * This procedure is invoked from the generic IO level to write * output to a file channel. * * Results: * The number of bytes written is returned or -1 on error. An * output argument contains a POSIX error code if an error occurred,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -