diff options
| author | rmax <rmax> | 2009-06-15 16:24:44 (GMT) | 
|---|---|---|
| committer | rmax <rmax> | 2009-06-15 16:24:44 (GMT) | 
| commit | 0acb18f87feafbdd931076405ca98c3ce30deca5 (patch) | |
| tree | bc0c063c253ee9081f495aaf6923eb1b284bd6a1 /unix/tclUnixChan.c | |
| parent | c664dc994a0c00a615120c01bda0f55ddd4e428f (diff) | |
| download | tcl-0acb18f87feafbdd931076405ca98c3ce30deca5.zip tcl-0acb18f87feafbdd931076405ca98c3ce30deca5.tar.gz tcl-0acb18f87feafbdd931076405ca98c3ce30deca5.tar.bz2 | |
* unix/tclUnixPort.h: Move all socket-related code from tclUnixChan.c
* unix/tclUnixChan.c: to tclUnixSock.c.
* unix/tclUnixSock.c:
Diffstat (limited to 'unix/tclUnixChan.c')
| -rw-r--r-- | unix/tclUnixChan.c | 1143 | 
1 files changed, 3 insertions, 1140 deletions
| diff --git a/unix/tclUnixChan.c b/unix/tclUnixChan.c index 29da9e4..d8eaccc 100644 --- a/unix/tclUnixChan.c +++ b/unix/tclUnixChan.c @@ -10,7 +10,7 @@   * 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.100 2009/04/10 21:40:55 dgp Exp $ + * RCS: @(#) $Id: tclUnixChan.c,v 1.101 2009/06/15 16:24:45 rmax Exp $   */  #include "tclInt.h"	/* Internal definitions for Tcl. */ @@ -144,60 +144,9 @@ typedef struct TtyAttrs {      }  /* - * 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(Tcl_Interp *interp, int port, -			    const char *host, int server, const char *myaddr, -			    int myport, int async); -static int		CreateSocketAddress(struct sockaddr_in *sockaddrPtr, -			    const char *host, int port, int willBind, -			    const char **errorMsgPtr);  static int		FileBlockModeProc(ClientData instanceData, int mode);  static int		FileCloseProc(ClientData instanceData,  			    Tcl_Interp *interp); @@ -214,23 +163,6 @@ static int		FileTruncateProc(ClientData instanceData,  static Tcl_WideInt	FileWideSeekProc(ClientData instanceData,  			    Tcl_WideInt offset, int mode, int *errorCode);  static void		FileWatchProc(ClientData instanceData, int mask); -static void		TcpAccept(ClientData data, int mask); -static int		TcpBlockModeProc(ClientData data, int mode); -static int		TcpCloseProc(ClientData instanceData, -			    Tcl_Interp *interp); -static int		TcpClose2Proc(ClientData instanceData, -				      Tcl_Interp *interp, -				      int flags); -static int		TcpGetHandleProc(ClientData instanceData, -			    int direction, ClientData *handlePtr); -static int		TcpGetOptionProc(ClientData instanceData, -			    Tcl_Interp *interp, const char *optionName, -			    Tcl_DString *dsPtr); -static int		TcpInputProc(ClientData instanceData, char *buf, -			    int toRead, int *errorCode); -static int		TcpOutputProc(ClientData instanceData, -			    const char *buf, int toWrite, int *errorCode); -static void		TcpWatchProc(ClientData instanceData, int mask);  #ifdef SUPPORTS_TTY  static void		TtyGetAttributes(int fd, TtyAttrs *ttyPtr);  static int		TtyGetOptionProc(ClientData instanceData, @@ -250,9 +182,6 @@ static int		TtySetOptionProc(ClientData instanceData,  			    Tcl_Interp *interp, const char *optionName,  			    const char *value);  #endif	/* SUPPORTS_TTY */ -static int		WaitForConnect(TcpState *statePtr, int *errorCodePtr); -static Tcl_Channel	MakeTcpClientChannelMode(ClientData tcpSocket, -			    int mode);  /*   * This structure describes the channel type structure for file based IO: @@ -305,30 +234,6 @@ static Tcl_ChannelType ttyChannelType = {  };  #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_5,	/* v5 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. */ -    TcpClose2Proc,		/* Close2 proc. */ -    TcpBlockModeProc,		/* Set blocking or non-blocking mode.*/ -    NULL,			/* flush proc. */ -    NULL,			/* handler proc. */ -    NULL,			/* wide seek proc. */ -    NULL,			/* thread action proc. */ -    NULL,			/* truncate proc. */ -};  /*   *---------------------------------------------------------------------- @@ -1773,7 +1678,7 @@ Tcl_MakeFileChannel(      if (getsockname(fd, (struct sockaddr *)&sockaddr, &sockaddrLen) == 0  	    && sockaddrLen > 0  	    && sockaddr.sa_family == AF_INET) { -	return MakeTcpClientChannelMode((ClientData) INT2PTR(fd), mode); +	return TclpMakeTcpClientChannelMode((ClientData) INT2PTR(fd), mode);      } else {  	channelTypePtr = &fileChannelType;  	fsPtr = (FileState *) ckalloc((unsigned) sizeof(FileState)); @@ -1791,1048 +1696,6 @@ Tcl_MakeFileChannel(  /*   *----------------------------------------------------------------------   * - * TcpBlockModeProc -- - * - *	This function is invoked by the generic IO level to set blocking and - *	nonblocking mode on a TCP socket based channel. - * - * Results: - *	0 if successful, errno when failed. - * - * Side effects: - *	Sets the device into blocking or nonblocking mode. - * - *---------------------------------------------------------------------- - */ - -	/* ARGSUSED */ -static int -TcpBlockModeProc( -    ClientData instanceData,	/* Socket state. */ -    int mode)			/* The mode to set. Can be one of -				 * TCL_MODE_BLOCKING or -				 * TCL_MODE_NONBLOCKING. */ -{ -    TcpState *statePtr = (TcpState *) instanceData; - -    if (mode == TCL_MODE_BLOCKING) { -	CLEAR_BITS(statePtr->flags, TCP_ASYNC_SOCKET); -    } else { -	SET_BITS(statePtr->flags, TCP_ASYNC_SOCKET); -    } -    if (TclUnixSetBlockingMode(statePtr->fd, mode) < 0) { -	return errno; -    } -    return 0; -} - -/* - *---------------------------------------------------------------------- - * - * WaitForConnect -- - * - *	Wait for a connection on an asynchronously opened socket to be - *	completed.  In nonblocking mode, just test if the connection - *	has completed without blocking. - * - * Results: - * 	0 if the connection has completed, -1 if still in progress - * 	or there is an error. - * - *---------------------------------------------------------------------- - */ - -static int -WaitForConnect( -    TcpState *statePtr,		/* State of the socket. */ -    int *errorCodePtr)		/* Where to store errors? */ -{ -    int timeOut;		/* How long to wait. */ -    int state;			/* Of calling TclWaitForFile. */ - -    /* -     * If an asynchronous connect is in progress, attempt to wait for it to -     * complete before reading. -     */ - -    if (statePtr->flags & TCP_ASYNC_CONNECT) { -	if (statePtr->flags & TCP_ASYNC_SOCKET) { -	    timeOut = 0; -	} else { -	    timeOut = -1; -	} -	errno = 0; -	state = TclUnixWaitForFile(statePtr->fd, -		TCL_WRITABLE | TCL_EXCEPTION, timeOut); -	if (state & TCL_EXCEPTION) { -	    return -1; -	} -	if (state & TCL_WRITABLE) { -	    CLEAR_BITS(statePtr->flags, TCP_ASYNC_CONNECT); -	} else if (timeOut == 0) { -	    *errorCodePtr = errno = EWOULDBLOCK; -	    return -1; -	} -    } -    return 0; -} - -/* - *---------------------------------------------------------------------- - * - * TcpInputProc -- - * - *	This function is invoked by the generic IO level to read input from a - *	TCP socket based channel. - * - *	NOTE: We cannot share code with FilePipeInputProc because here we must - *	use recv to obtain the input from the channel, not read. - * - * Results: - *	The number of bytes read is returned or -1 on error. An output - *	argument contains the POSIX error code on error, or zero if no error - *	occurred. - * - * Side effects: - *	Reads input from the input device of the channel. - * - *---------------------------------------------------------------------- - */ - -	/* ARGSUSED */ -static int -TcpInputProc( -    ClientData instanceData,	/* Socket state. */ -    char *buf,			/* Where to store data read. */ -    int bufSize,		/* How much space is available in the -				 * buffer? */ -    int *errorCodePtr)		/* Where to store error code. */ -{ -    TcpState *statePtr = (TcpState *) instanceData; -    int bytesRead; - -    *errorCodePtr = 0; -    if (WaitForConnect(statePtr, errorCodePtr) != 0) { -	return -1; -    } -    bytesRead = recv(statePtr->fd, buf, (size_t) bufSize, 0); -    if (bytesRead > -1) { -	return bytesRead; -    } -    if (errno == ECONNRESET) { -	/* -	 * Turn ECONNRESET into a soft EOF condition. -	 */ - -	return 0; -    } -    *errorCodePtr = errno; -    return -1; -} - -/* - *---------------------------------------------------------------------- - * - * TcpOutputProc -- - * - *	This function is invoked by the generic IO level to write output to a - *	TCP socket based channel. - * - *	NOTE: We cannot share code with FilePipeOutputProc because here we - *	must use send, not write, to get reliable error reporting. - * - * Results: - *	The number of bytes written is returned. An output argument is set to - *	a POSIX error code if an error occurred, or zero. - * - * Side effects: - *	Writes output on the output device of the channel. - * - *---------------------------------------------------------------------- - */ - -static int -TcpOutputProc( -    ClientData instanceData,	/* Socket state. */ -    const char *buf,		/* The data buffer. */ -    int toWrite,		/* How many bytes to write? */ -    int *errorCodePtr)		/* Where to store error code. */ -{ -    TcpState *statePtr = (TcpState *) instanceData; -    int written; - -    *errorCodePtr = 0; -    if (WaitForConnect(statePtr, errorCodePtr) != 0) { -	return -1; -    } -    written = send(statePtr->fd, buf, (size_t) toWrite, 0); -    if (written > -1) { -	return written; -    } -    *errorCodePtr = errno; -    return -1; -} - -/* - *---------------------------------------------------------------------- - * - * TcpCloseProc -- - * - *	This function is invoked by the generic IO level to perform - *	channel-type-specific cleanup when a TCP socket based channel is - *	closed. - * - * Results: - *	0 if successful, the value of errno if failed. - * - * Side effects: - *	Closes the socket of the channel. - * - *---------------------------------------------------------------------- - */ - -	/* ARGSUSED */ -static int -TcpCloseProc( -    ClientData instanceData,	/* The socket to close. */ -    Tcl_Interp *interp)		/* For error reporting - unused. */ -{ -    TcpState *statePtr = (TcpState *) instanceData; -    int errorCode = 0; - -    /* -     * Delete a file handler that may be active for this socket if this is a -     * server socket - the file handler was created automatically by Tcl as -     * part of the mechanism to accept new client connections. Channel -     * handlers are already deleted in the generic IO channel closing code -     * that called this function, so we do not have to delete them here. -     */ - -    Tcl_DeleteFileHandler(statePtr->fd); - -    if (close(statePtr->fd) < 0) { -	errorCode = errno; -    } -    ckfree((char *) statePtr); - -    return errorCode; -} - -/* - *---------------------------------------------------------------------- - * - * TcpClose2Proc -- - * - *	This function is called by the generic IO level to perform the channel - *	type specific part of a half-close: namely, a shutdown() on a socket. - * - * Results: - *	0 if successful, the value of errno if failed. - * - * Side effects: - *	Shuts down one side of the socket. - * - *---------------------------------------------------------------------- - */ - -static int -TcpClose2Proc( -    ClientData instanceData,	/* The socket to close. */ -    Tcl_Interp *interp,		/* For error reporting. */ -    int flags)			/* Flags that indicate which side to close. */ -{ -    TcpState *statePtr = (TcpState *) instanceData; -    int errorCode = 0; -    int sd; - -    /* -     * Shutdown the OS socket handle. -     */ -    switch(flags) -	{ -	case TCL_CLOSE_READ: -	    sd=SHUT_RD; -	    break; -	case TCL_CLOSE_WRITE: -	    sd=SHUT_WR; -	    break; -	default: -	    if (interp) { -		Tcl_AppendResult(interp, "Socket close2proc called bidirectionally", NULL); -	    } -	    return TCL_ERROR; -	} -    if (shutdown(statePtr->fd,sd)<0) { -	errorCode = errno; -    } - -    return errorCode; -} - -/* - *---------------------------------------------------------------------- - * - * TcpGetOptionProc -- - * - *	Computes an option value for a TCP socket based channel, or a list of - *	all options and their values. - * - *	Note: This code is based on code contributed by John Haxby. - * - * Results: - *	A standard Tcl result. The value of the specified option or a list of - *	all options and their values is returned in the supplied DString. Sets - *	Error message if needed. - * - * Side effects: - *	None. - * - *---------------------------------------------------------------------- - */ - -static int -TcpGetOptionProc( -    ClientData instanceData,	/* Socket state. */ -    Tcl_Interp *interp,		/* For error reporting - can be NULL. */ -    const char *optionName,	/* Name of the option to retrieve the value -				 * for, or NULL to get all options and their -				 * values. */ -    Tcl_DString *dsPtr)		/* Where to store the computed value; -				 * initialized by caller. */ -{ -    TcpState *statePtr = (TcpState *) instanceData; -    struct sockaddr_in sockname; -    struct sockaddr_in peername; -    struct hostent *hostEntPtr; -    socklen_t size = sizeof(struct sockaddr_in); -    size_t len = 0; -    char buf[TCL_INTEGER_SPACE]; - -    if (optionName != NULL) { -	len = strlen(optionName); -    } - -    if ((len > 1) && (optionName[1] == 'e') && -	    (strncmp(optionName, "-error", len) == 0)) { -	socklen_t optlen = sizeof(int); -	int err, ret; - -	ret = getsockopt(statePtr->fd, SOL_SOCKET, SO_ERROR, -		(char *)&err, &optlen); -	if (ret < 0) { -	    err = errno; -	} -	if (err != 0) { -	    Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(err), -1); -	} -	return TCL_OK; -    } - -    if ((len == 0) || -	    ((len > 1) && (optionName[1] == 'p') && -		    (strncmp(optionName, "-peername", len) == 0))) { -	if (getpeername(statePtr->fd, (struct sockaddr *) &peername, -		&size) >= 0) { -	    if (len == 0) { -		Tcl_DStringAppendElement(dsPtr, "-peername"); -		Tcl_DStringStartSublist(dsPtr); -	    } -	    Tcl_DStringAppendElement(dsPtr, inet_ntoa(peername.sin_addr)); -	    hostEntPtr = TclpGetHostByAddr(			/* INTL: Native. */ -		    (char *) &peername.sin_addr, -		    sizeof(peername.sin_addr), AF_INET); -	    if (hostEntPtr != NULL) { -		Tcl_DString ds; - -		Tcl_ExternalToUtfDString(NULL, hostEntPtr->h_name, -1, &ds); -		Tcl_DStringAppendElement(dsPtr, Tcl_DStringValue(&ds)); -		Tcl_DStringFree(&ds); -	    } else { -		Tcl_DStringAppendElement(dsPtr, inet_ntoa(peername.sin_addr)); -	    } -	    TclFormatInt(buf, ntohs(peername.sin_port)); -	    Tcl_DStringAppendElement(dsPtr, buf); -	    if (len == 0) { -		Tcl_DStringEndSublist(dsPtr); -	    } else { -		return TCL_OK; -	    } -	} else { -	    /* -	     * getpeername failed - but if we were asked for all the options -	     * (len==0), don't flag an error at that point because it could be -	     * an fconfigure request on a server socket (which have no peer). -	     * Same must be done on win&mac. -	     */ - -	    if (len) { -		if (interp) { -		    Tcl_AppendResult(interp, "can't get peername: ", -			    Tcl_PosixError(interp), NULL); -		} -		return TCL_ERROR; -	    } -	} -    } - -    if ((len == 0) || -	    ((len > 1) && (optionName[1] == 's') && -	    (strncmp(optionName, "-sockname", len) == 0))) { -	if (getsockname(statePtr->fd, (struct sockaddr *) &sockname, -		&size) >= 0) { -	    if (len == 0) { -		Tcl_DStringAppendElement(dsPtr, "-sockname"); -		Tcl_DStringStartSublist(dsPtr); -	    } -	    Tcl_DStringAppendElement(dsPtr, inet_ntoa(sockname.sin_addr)); -	    hostEntPtr = TclpGetHostByAddr(			/* INTL: Native. */ -		    (char *) &sockname.sin_addr, -		    sizeof(sockname.sin_addr), AF_INET); -	    if (hostEntPtr != NULL) { -		Tcl_DString ds; - -		Tcl_ExternalToUtfDString(NULL, hostEntPtr->h_name, -1, &ds); -		Tcl_DStringAppendElement(dsPtr, Tcl_DStringValue(&ds)); -		Tcl_DStringFree(&ds); -	    } else { -		Tcl_DStringAppendElement(dsPtr, inet_ntoa(sockname.sin_addr)); -	    } -	    TclFormatInt(buf, ntohs(sockname.sin_port)); -	    Tcl_DStringAppendElement(dsPtr, buf); -	    if (len == 0) { -		Tcl_DStringEndSublist(dsPtr); -	    } else { -		return TCL_OK; -	    } -	} else { -	    if (interp) { -		Tcl_AppendResult(interp, "can't get sockname: ", -			Tcl_PosixError(interp), NULL); -	    } -	    return TCL_ERROR; -	} -    } - -    if (len > 0) { -	return Tcl_BadChannelOption(interp, optionName, "peername sockname"); -    } - -    return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * TcpWatchProc -- - * - *	Initialize the notifier to watch the fd from this channel. - * - * Results: - *	None. - * - * Side effects: - *	Sets up the notifier so that a future event on the channel will be - *	seen by Tcl. - * - *---------------------------------------------------------------------- - */ - -static void -TcpWatchProc( -    ClientData instanceData,	/* The socket state. */ -    int mask)			/* Events of interest; an OR-ed combination of -				 * TCL_READABLE, TCL_WRITABLE and -				 * TCL_EXCEPTION. */ -{ -    TcpState *statePtr = (TcpState *) instanceData; - -    /* -     * Make sure we don't mess with server sockets since they will never be -     * readable or writable at the Tcl level. This keeps Tcl scripts from -     * interfering with the -accept behavior. -     */ - -    if (!statePtr->acceptProc) { -	if (mask) { -	    Tcl_CreateFileHandler(statePtr->fd, mask, -		    (Tcl_FileProc *) Tcl_NotifyChannel, -		    (ClientData) statePtr->channel); -	} else { -	    Tcl_DeleteFileHandler(statePtr->fd); -	} -    } -} - -/* - *---------------------------------------------------------------------- - * - * TcpGetHandleProc -- - * - *	Called from Tcl_GetChannelHandle to retrieve OS handles from inside a - *	TCP socket based channel. - * - * Results: - *	Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if there is no - *	handle for the specified direction. - * - * Side effects: - *	None. - * - *---------------------------------------------------------------------- - */ - -	/* ARGSUSED */ -static int -TcpGetHandleProc( -    ClientData instanceData,	/* The socket state. */ -    int direction,		/* Not used. */ -    ClientData *handlePtr)	/* Where to store the handle. */ -{ -    TcpState *statePtr = (TcpState *) instanceData; - -    *handlePtr = (ClientData) INT2PTR(statePtr->fd); -    return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * CreateSocket -- - * - *	This function opens a new socket in client or server mode and - *	initializes the TcpState structure. - * - * Results: - *	Returns a new TcpState, or NULL with an error in the interp's result, - *	if interp is not NULL. - * - * Side effects: - *	Opens a socket. - * - *---------------------------------------------------------------------- - */ - -static TcpState * -CreateSocket( -    Tcl_Interp *interp,		/* For error reporting; can be NULL. */ -    int port,			/* Port number to open. */ -    const char *host,		/* Name of host on which to open port. NULL -				 * implies INADDR_ANY */ -    int server,			/* 1 if socket should be a server socket, else -				 * 0 for a client socket. */ -    const char *myaddr,		/* Optional client-side address */ -    int myport,			/* Optional client-side port */ -    int async)			/* If nonzero and creating a client socket, -				 * attempt to do an async connect. Otherwise -				 * do a synchronous connect or bind. */ -{ -    int status = 0, sock = -1; -    struct sockaddr_in sockaddr;	/* socket address */ -    struct sockaddr_in mysockaddr;	/* Socket address for client */ -    TcpState *statePtr; -    const char *errorMsg = NULL; - -    if (!CreateSocketAddress(&sockaddr, host, port, 0, &errorMsg)) { -	goto error; -    } -    if ((myaddr != NULL || myport != 0) && -	    !CreateSocketAddress(&mysockaddr, myaddr, myport, 1, &errorMsg)) { -	goto error; -    } - -    sock = socket(AF_INET, SOCK_STREAM, 0); -    if (sock < 0) { -	goto error; -    } - -    /* -     * Set the close-on-exec flag so that the socket will not get inherited by -     * child processes. -     */ - -    fcntl(sock, F_SETFD, FD_CLOEXEC); - -    /* -     * Set kernel space buffering -     */ - -    TclSockMinimumBuffers(sock, SOCKET_BUFSIZE); - -    status = 0; -    if (server) { -	/* -	 * Set up to reuse server addresses automatically and bind to the -	 * specified port. -	 */ - -	int reuseaddr = 1; -	(void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,  -		      (char *) &reuseaddr, sizeof(reuseaddr)); -	status = bind(sock, (struct sockaddr *) &sockaddr, -		sizeof(struct sockaddr)); -	if (status != -1) { -	    status = listen(sock, SOMAXCONN); -	} -    } else { -	if (myaddr != NULL || myport != 0) { -	    int reuseaddr = 1; -	    (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, -		    (char *) &reuseaddr, sizeof(reuseaddr)); -	    status = bind(sock, (struct sockaddr *) &mysockaddr, -		    sizeof(struct sockaddr)); -	    if (status < 0) { -		goto error; -	    } -	} - -	/* -	 * 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) { -	    status = TclUnixSetBlockingMode(sock, TCL_MODE_NONBLOCKING); -	    if (status < 0) { -		goto error; -	    } -	} - -	status = connect(sock, (struct sockaddr *) &sockaddr, -		sizeof(sockaddr)); -	if (status < 0) { -	    if (errno == EINPROGRESS) { -		status = 0; -	    } else { -		goto error; -	    } -	}  -	if (async) { -	    /* -	     * Restore blocking mode. -	     */ -	    status = TclUnixSetBlockingMode(sock, TCL_MODE_BLOCKING); -	} -    } - -    if (status < 0) { -error: -	if (interp != NULL) { -	    Tcl_AppendResult(interp, "couldn't open socket: ", -		    Tcl_PosixError(interp), NULL); -	    if (errorMsg != NULL) { -		Tcl_AppendResult(interp, " (", errorMsg, ")", NULL); -	    } -	} -	if (sock != -1) { -	    close(sock); -	} -	return NULL; -    } - -    /* -     * Allocate a new TcpState for this socket. -     */ - -    statePtr = (TcpState *) ckalloc((unsigned) sizeof(TcpState)); -    statePtr->flags = async ? TCP_ASYNC_CONNECT : 0; -    statePtr->fd = sock; - -    return statePtr; -} - -/* - *---------------------------------------------------------------------- - * - * 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 int -CreateSocketAddress( -    struct sockaddr_in *sockaddrPtr,	/* Socket address */ -    const char *host,			/* Host. NULL implies INADDR_ANY */ -    int port,				/* Port number */ -    int willBind,			/* Is this an address to bind() to or -					 * to connect() to? */ -    const char **errorMsgPtr)		/* Place to store the error message -					 * detail, if available. */ -{ -#ifdef HAVE_GETADDRINFO -    struct addrinfo hints, *resPtr = NULL; -    char *native; -    Tcl_DString ds; -    int result; - -    if (host == NULL) { -	sockaddrPtr->sin_family = AF_INET; -	sockaddrPtr->sin_addr.s_addr = INADDR_ANY; -    addPort: -	sockaddrPtr->sin_port = htons((unsigned short) (port & 0xFFFF)); -	return 1; -    } - -    (void) memset(&hints, 0, sizeof(struct addrinfo)); -    hints.ai_family = AF_INET; -    hints.ai_socktype = SOCK_STREAM; -    if (willBind) { -	hints.ai_flags |= AI_PASSIVE; -    } - -    /* -     * Note that getaddrinfo() *is* thread-safe. If a platform doesn't get -     * that right, it shouldn't use this part of the code. -     */ - -    native = Tcl_UtfToExternalDString(NULL, host, -1, &ds); -    result = getaddrinfo(native, NULL, &hints, &resPtr); -    Tcl_DStringFree(&ds); -    if (result == 0) { -	memcpy(sockaddrPtr, resPtr->ai_addr, sizeof(struct sockaddr_in)); -	freeaddrinfo(resPtr); -	goto addPort; -    } - -    /* -     * Ought to use gai_strerror() here... -     */ - -    switch (result) { -    case EAI_NONAME: -    case EAI_SERVICE: -#if defined(EAI_ADDRFAMILY) && EAI_ADDRFAMILY != EAI_NONAME -    case EAI_ADDRFAMILY: -#endif -#if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME -    case EAI_NODATA: -#endif -	*errorMsgPtr = gai_strerror(result); -	errno = EHOSTUNREACH; -	return 0; -    case EAI_SYSTEM: -	return 0; -    default: -	*errorMsgPtr = gai_strerror(result); -	errno = ENXIO; -	return 0; -    } -#else /* !HAVE_GETADDRINFO */ -    struct in_addr addr;		/* For 64/32 bit madness */ - -    (void) memset(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 { -	struct hostent *hostent;	/* Host database entry */ -	Tcl_DString ds; -	const char *native; - -	if (host == NULL) { -	    native = NULL; -	} else { -	    native = Tcl_UtfToExternalDString(NULL, host, -1, &ds); -	} -	addr.s_addr = inet_addr(native);		/* INTL: Native. */ - -	/* -	 * This is 0xFFFFFFFF to ensure that it compares as a 32bit -1 on -	 * either 32 or 64 bits systems. -	 */ - -	if (addr.s_addr == 0xFFFFFFFF) { -	    hostent = TclpGetHostByName(native);	/* INTL: Native. */ -	    if (hostent != NULL) { -		memcpy(&addr, hostent->h_addr_list[0], -			(size_t) hostent->h_length); -	    } else { -#ifdef	EHOSTUNREACH -		errno = EHOSTUNREACH; -#else /* !EHOSTUNREACH */ -#ifdef ENXIO -		errno = ENXIO; -#endif /* ENXIO */ -#endif /* EHOSTUNREACH */ -		if (native != NULL) { -		    Tcl_DStringFree(&ds); -		} -		return 0;	/* Error. */ -	    } -	} -	if (native != NULL) { -	    Tcl_DStringFree(&ds); -	} -    } - -    /* -     * 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. */ -#endif /* HAVE_GETADDRINFO */ -} - -/* - *---------------------------------------------------------------------- - * - * 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_Channel -Tcl_OpenTcpClient( -    Tcl_Interp *interp,		/* For error reporting; can be NULL. */ -    int port,			/* Port number to open. */ -    const char *host,		/* Host on which to open port. */ -    const 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[16 + TCL_INTEGER_SPACE]; - -    /* -     * 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 = 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(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_Channel -Tcl_MakeTcpClientChannel( -    ClientData sock)		/* The socket to wrap up into a channel. */ -{ -    return MakeTcpClientChannelMode(sock, (TCL_READABLE | TCL_WRITABLE)); -} - -/* - *---------------------------------------------------------------------- - * - * MakeTcpClientChannelMode -- - * - *	Creates a Tcl_Channel from an existing client TCP socket - *	with given mode. - * - * Results: - *	The Tcl_Channel wrapped around the preexisting TCP socket. - * - * Side effects: - *	None. - * - *---------------------------------------------------------------------- - */ - -static Tcl_Channel -MakeTcpClientChannelMode( -    ClientData sock,		/* The socket to wrap up into a channel. */ -    int mode)			/* ORed combination of TCL_READABLE and -				 * TCL_WRITABLE to indicate file mode. */ -{ -    TcpState *statePtr; -    char channelName[16 + TCL_INTEGER_SPACE]; - -    statePtr = (TcpState *) ckalloc((unsigned) sizeof(TcpState)); -    statePtr->fd = PTR2INT(sock); -    statePtr->flags = 0; -    statePtr->acceptProc = NULL; -    statePtr->acceptProcData = NULL; - -    sprintf(channelName, "sock%d", statePtr->fd); - -    statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, -	    (ClientData) statePtr, mode); -    if (Tcl_SetChannelOption(NULL, statePtr->channel, "-translation", -	    "auto crlf") == TCL_ERROR) { -	Tcl_Close(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 the interp's result if interp is not NULL. - * - * Side effects: - *	Opens a server socket and creates a new channel. - * - *---------------------------------------------------------------------- - */ - -Tcl_Channel -Tcl_OpenTcpServer( -    Tcl_Interp *interp,		/* For error reporting - may be NULL. */ -    int port,			/* Port number to open. */ -    const 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[16 + TCL_INTEGER_SPACE]; - -    /* -     * 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 void -TcpAccept( -    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 */ -    socklen_t len;		/* For accept interface */ -    char channelName[16 + TCL_INTEGER_SPACE]; - -    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 = NULL; -    newSockState->acceptProcData = NULL; - -    sprintf(channelName, "sock%d", newsock); -    newSockState->channel = Tcl_CreateChannel(&tcpChannelType, channelName, -	    (ClientData) newSockState, (TCL_READABLE | TCL_WRITABLE)); - -    Tcl_SetChannelOption(NULL, newSockState->channel, "-translation", -	    "auto crlf"); - -    if (sockState->acceptProc != NULL) { -	sockState->acceptProc(sockState->acceptProcData, -		newSockState->channel, inet_ntoa(addr.sin_addr), -		ntohs(addr.sin_port)); -    } -} - -/* - *---------------------------------------------------------------------- - *   * TclpGetDefaultStdChannel --   *   *	Creates channels for standard input, standard output or standard error @@ -2983,7 +1846,7 @@ Tcl_GetOpenFile(  #ifdef SUPPORTS_TTY  	    || (chanTypePtr == &ttyChannelType)  #endif /* SUPPORTS_TTY */ -	    || (chanTypePtr == &tcpChannelType) +	    || (strcmp(chanTypePtr->typeName, "tcp") == 0)  	    || (strcmp(chanTypePtr->typeName, "pipe") == 0)) {  	if (Tcl_GetChannelHandle(chan,  		(forWriting ? TCL_WRITABLE : TCL_READABLE), | 
