Index: generic/tclIOCmd.c ================================================================== --- generic/tclIOCmd.c +++ generic/tclIOCmd.c @@ -1490,14 +1490,14 @@ }; enum socketOptions { SKT_ASYNC, SKT_MYADDR, SKT_MYPORT, SKT_REUSEADDR, SKT_REUSEPORT, SKT_SERVER }; - int optionIndex, a, server = 0, myport = 0, async = 0, reusep = -1, + int optionIndex, a, server = 0, async = 0, reusep = -1, reusea = -1; unsigned int flags = 0; - const char *host, *port, *myaddr = NULL; + const char *host, *port, *myaddr = NULL, *myport = NULL; Tcl_Obj *script = NULL; Tcl_Channel chan; if (TclpHasSockets(interp) != TCL_OK) { return TCL_ERROR; @@ -1530,22 +1530,17 @@ return TCL_ERROR; } myaddr = TclGetString(objv[a]); break; case SKT_MYPORT: { - const char *myPortName; - a++; if (a >= objc) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "no argument given for -myport option", -1)); return TCL_ERROR; } - myPortName = TclGetString(objv[a]); - if (TclSockGetPort(interp, myPortName, "tcp", &myport) != TCL_OK) { - return TCL_ERROR; - } + myport = TclGetString(objv[a]); break; } case SKT_SERVER: if (async == 1) { Tcl_SetObjResult(interp, Tcl_NewStringObj( @@ -1668,17 +1663,11 @@ * be informed when the interpreter is deleted. */ Tcl_CreateCloseHandler(chan, TcpServerCloseProc, acceptCallbackPtr); } else { - int portNum; - - if (TclSockGetPort(interp, port, "tcp", &portNum) != TCL_OK) { - return TCL_ERROR; - } - - chan = Tcl_OpenTcpClient(interp, portNum, host, myaddr, myport, async); + chan = TclOpenTcpClientEx(interp, port, host, myaddr, myport, async); if (chan == NULL) { return TCL_ERROR; } } Index: generic/tclIOSock.c ================================================================== --- generic/tclIOSock.c +++ generic/tclIOSock.c @@ -156,21 +156,21 @@ TclCreateSocketAddress( Tcl_Interp *interp, /* Interpreter for querying the desired socket * family */ struct addrinfo **addrlist, /* Socket address list */ const char *host, /* Host. NULL implies INADDR_ANY */ - int port, /* Port number */ + const char *service, /* Service */ 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. */ { struct addrinfo hints; struct addrinfo *p; struct addrinfo *v4head = NULL, *v4ptr = NULL; struct addrinfo *v6head = NULL, *v6ptr = NULL; - char *native = NULL, portbuf[TCL_INTEGER_SPACE], *portstring; + char *native = NULL; const char *family = NULL; Tcl_DString ds; int result; if (host != NULL) { @@ -180,15 +180,12 @@ /* * Workaround for OSX's apparent inability to resolve "localhost", "0" * when the loopback device is the only available network interface. */ - if (host != NULL && port == 0) { - portstring = NULL; - } else { - TclFormatInt(portbuf, port); - portstring = portbuf; + if (host != NULL && service != NULL && !strcmp(service, "0")) { + service = NULL; } (void) memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; @@ -229,11 +226,11 @@ if (willBind) { hints.ai_flags |= AI_PASSIVE; } - result = getaddrinfo(native, portstring, &hints, addrlist); + result = getaddrinfo(native, service, &hints, addrlist); if (host != NULL) { Tcl_DStringFree(&ds); } Index: generic/tclInt.h ================================================================== --- generic/tclInt.h +++ generic/tclInt.h @@ -3066,12 +3066,16 @@ MODULE_SCOPE void TclpFinalizeMutex(Tcl_Mutex *mutexPtr); MODULE_SCOPE void TclpFinalizePipes(void); MODULE_SCOPE void TclpFinalizeSockets(void); MODULE_SCOPE int TclCreateSocketAddress(Tcl_Interp *interp, struct addrinfo **addrlist, - const char *host, int port, int willBind, + const char *host, const char *service, int willBind, const char **errorMsgPtr); +Tcl_Channel TclOpenTcpClientEx(Tcl_Interp *interp, + const char *service, const char *host, + const char *myaddr, const char *myservice, + unsigned int flags); MODULE_SCOPE int TclpThreadCreate(Tcl_ThreadId *idPtr, Tcl_ThreadCreateProc *proc, ClientData clientData, int stackSize, int flags); MODULE_SCOPE int TclpFindVariable(const char *name, int *lengthPtr); MODULE_SCOPE void TclpInitLibraryPath(char **valuePtr, Index: unix/tclUnixSock.c ================================================================== --- unix/tclUnixSock.c +++ unix/tclUnixSock.c @@ -1280,22 +1280,37 @@ 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. */ +{ + char service[TCL_INTEGER_SPACE], myservice[TCL_INTEGER_SPACE]; + + TclFormatInt(service, port); + TclFormatInt(myservice, myport); + + return TclOpenTcpClientEx(interp, service, host, myaddr, myservice, async!=0); +} + +Tcl_Channel +TclOpenTcpClientEx( + Tcl_Interp *interp, /* For error reporting; can be NULL. */ + const char *service, /* Port number to open. */ + const char *host, /* Host on which to open port. */ + const char *myaddr, /* Client-side address */ + const char *myservice, /* Client-side port */ + unsigned int flags) /* If nonzero, attempt to do an asynchronous + * connect. Otherwise we do a blocking + * connect. */ { TcpState *statePtr; const char *errorMsg = NULL; struct addrinfo *addrlist = NULL, *myaddrlist = NULL; char channelName[SOCK_CHAN_LENGTH]; - /* - * Do the name lookups for the local and remote addresses. - */ - - if (!TclCreateSocketAddress(interp, &addrlist, host, port, 0, &errorMsg) - || !TclCreateSocketAddress(interp, &myaddrlist, myaddr, myport, 1, + if (!TclCreateSocketAddress(interp, &addrlist, host, service, 0, &errorMsg) + || !TclCreateSocketAddress(interp, &myaddrlist, myaddr, myservice, 1, &errorMsg)) { if (addrlist != NULL) { freeaddrinfo(addrlist); } if (interp != NULL) { @@ -1308,11 +1323,11 @@ /* * Allocate a new TcpState for this socket. */ statePtr = ckalloc(sizeof(TcpState)); memset(statePtr, 0, sizeof(TcpState)); - statePtr->flags = async ? TCP_ASYNC_CONNECT : 0; + statePtr->flags = (flags&1) ? TCP_ASYNC_CONNECT : 0; statePtr->cachedBlocking = TCL_MODE_BLOCKING; statePtr->addrlist = addrlist; statePtr->myaddrlist = myaddrlist; statePtr->fds.fd = -1; @@ -1479,11 +1494,11 @@ if (TclSockGetPort(interp, service, "tcp", &port) != TCL_OK) { errorMsg = "invalid port number"; goto error; } - if (!TclCreateSocketAddress(interp, &addrlist, myHost, port, 1, &errorMsg)) { + if (!TclCreateSocketAddress(interp, &addrlist, myHost, service, 1, &errorMsg)) { my_errno = errno; goto error; } for (addrPtr = addrlist; addrPtr != NULL; addrPtr = addrPtr->ai_next) { Index: win/tclWinSock.c ================================================================== --- win/tclWinSock.c +++ win/tclWinSock.c @@ -1871,11 +1871,11 @@ } /* *---------------------------------------------------------------------- * - * Tcl_OpenTcpClient -- + * Tcl_OpenTcpClient, TclOpenTcpClientEx -- * * 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 @@ -1895,10 +1895,29 @@ 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. */ +{ + char service[TCL_INTEGER_SPACE], myservice[TCL_INTEGER_SPACE]; + + TclFormatInt(service, port); + TclFormatInt(myservice, myport); + + return TclOpenTcpClientEx(interp, service, host, myaddr, myservice, async!=0); +} + +Tcl_Channel +TclOpenTcpClientEx( + Tcl_Interp *interp, /* For error reporting; can be NULL. */ + const char *service, /* Port number to open. */ + const char *host, /* Host on which to open port. */ + const char *myaddr, /* Client-side address */ + const char *myservice, /* Client-side port */ + unsigned int flags) /* If nonzero, attempt to do an asynchronous + * connect. Otherwise we do a blocking + * connect. */ { TcpState *statePtr; const char *errorMsg = NULL; struct addrinfo *addrlist = NULL, *myaddrlist = NULL; char channelName[SOCK_CHAN_LENGTH]; @@ -1919,12 +1938,12 @@ /* * Do the name lookups for the local and remote addresses. */ - if (!TclCreateSocketAddress(interp, &addrlist, host, port, 0, &errorMsg) - || !TclCreateSocketAddress(interp, &myaddrlist, myaddr, myport, 1, + if (!TclCreateSocketAddress(interp, &addrlist, host, service, 0, &errorMsg) + || !TclCreateSocketAddress(interp, &myaddrlist, myaddr, myservice, 1, &errorMsg)) { if (addrlist != NULL) { freeaddrinfo(addrlist); } if (interp != NULL) { @@ -1935,11 +1954,11 @@ } statePtr = NewSocketInfo(INVALID_SOCKET); statePtr->addrlist = addrlist; statePtr->myaddrlist = myaddrlist; - if (async) { + if (flags&1) { statePtr->flags |= TCP_ASYNC_CONNECT; } /* * Create a new client socket and wrap it in a channel. @@ -2076,11 +2095,11 @@ if (TclSockGetPort(interp, service, "tcp", &port) != TCL_OK) { errorMsg = "invalid port number"; goto error; } - if (!TclCreateSocketAddress(interp, &addrlist, myHost, port, 1, &errorMsg)) { + if (!TclCreateSocketAddress(interp, &addrlist, myHost, service, 1, &errorMsg)) { goto error; } for (addrPtr = addrlist; addrPtr != NULL; addrPtr = addrPtr->ai_next) { sock = socket(addrPtr->ai_family, addrPtr->ai_socktype,