summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlimeboy <that.lemon+tcl@gmai.com>2016-11-24 12:47:21 (GMT)
committerlimeboy <that.lemon+tcl@gmai.com>2016-11-24 12:47:21 (GMT)
commit5b33616e5080b53d8b1e8b8608a98d824a952ee9 (patch)
treeff124e26492a522aa6a4f97ce86dcbb4625938bd
parent33ded984ff02df26e0faf1d254abd2ea6acc0070 (diff)
downloadtcl-5b33616e5080b53d8b1e8b8608a98d824a952ee9.zip
tcl-5b33616e5080b53d8b1e8b8608a98d824a952ee9.tar.gz
tcl-5b33616e5080b53d8b1e8b8608a98d824a952ee9.tar.bz2
Implement the whole TIP 456 specification.
Also introduces the `-reuseaddr' and `-reuseport' options for the `socket' command.
-rw-r--r--generic/tcl.decls2
-rw-r--r--generic/tcl.h7
-rw-r--r--generic/tclDecls.h4
-rw-r--r--generic/tclIOCmd.c23
-rw-r--r--generic/tclIOSock.c6
-rw-r--r--unix/tclUnixSock.c41
-rw-r--r--win/tclWinSock.c2
7 files changed, 52 insertions, 33 deletions
diff --git a/generic/tcl.decls b/generic/tcl.decls
index 20c3f3e..af496b3 100644
--- a/generic/tcl.decls
+++ b/generic/tcl.decls
@@ -2329,7 +2329,7 @@ declare 630 {
# TIP #456
declare 631 {
Tcl_Channel Tcl_OpenTcpServerEx(Tcl_Interp *interp, int port,
- const char *host, int flags, Tcl_TcpAcceptProc *acceptProc,
+ const char *host, unsigned int flags, Tcl_TcpAcceptProc *acceptProc,
ClientData callbackData)
}
diff --git a/generic/tcl.h b/generic/tcl.h
index eb53c70..75a947a 100644
--- a/generic/tcl.h
+++ b/generic/tcl.h
@@ -2371,6 +2371,13 @@ typedef int (Tcl_ArgvGenFuncProc)(ClientData clientData, Tcl_Interp *interp,
/*
*----------------------------------------------------------------------------
+ * Definitions needed for the Tcl_OpenTcpServerEx function. [TIP #456]
+ */
+#define TCL_TCPSERVER_REUSEADDR (1<<0)
+#define TCL_TCPSERVER_REUSEPORT (1<<1)
+
+/*
+ *----------------------------------------------------------------------------
* Single public declaration for NRE.
*/
diff --git a/generic/tclDecls.h b/generic/tclDecls.h
index d1c1170..4810c51 100644
--- a/generic/tclDecls.h
+++ b/generic/tclDecls.h
@@ -1818,7 +1818,7 @@ EXTERN void Tcl_ZlibStreamSetCompressionDictionary(
Tcl_Obj *compressionDictionaryObj);
/* 631 */
EXTERN Tcl_Channel Tcl_OpenTcpServerEx(Tcl_Interp *interp, int port,
- const char *host, int flags,
+ const char *host, unsigned int flags,
Tcl_TcpAcceptProc *acceptProc,
ClientData callbackData);
@@ -2487,7 +2487,7 @@ typedef struct TclStubs {
void * (*tcl_FindSymbol) (Tcl_Interp *interp, Tcl_LoadHandle handle, const char *symbol); /* 628 */
int (*tcl_FSUnloadFile) (Tcl_Interp *interp, Tcl_LoadHandle handlePtr); /* 629 */
void (*tcl_ZlibStreamSetCompressionDictionary) (Tcl_ZlibStream zhandle, Tcl_Obj *compressionDictionaryObj); /* 630 */
- Tcl_Channel (*tcl_OpenTcpServerEx) (Tcl_Interp *interp, int port, const char *host, int flags, Tcl_TcpAcceptProc *acceptProc, ClientData callbackData); /* 631 */
+ Tcl_Channel (*tcl_OpenTcpServerEx) (Tcl_Interp *interp, int port, const char *host, unsigned int flags, Tcl_TcpAcceptProc *acceptProc, ClientData callbackData); /* 631 */
} TclStubs;
extern const TclStubs *tclStubsPtr;
diff --git a/generic/tclIOCmd.c b/generic/tclIOCmd.c
index 883c6b7..b4696fd 100644
--- a/generic/tclIOCmd.c
+++ b/generic/tclIOCmd.c
@@ -1485,12 +1485,15 @@ Tcl_SocketObjCmd(
Tcl_Obj *const objv[]) /* Argument objects. */
{
static const char *const socketOptions[] = {
- "-async", "-myaddr", "-myport", "-server", "-reuseport", NULL
+ "-async", "-myaddr", "-myport", "-server", "-reuseaddr", "-reuseport",
+ NULL
};
enum socketOptions {
- SKT_ASYNC, SKT_MYADDR, SKT_MYPORT, SKT_SERVER, SKT_REUSEPORT
+ SKT_ASYNC, SKT_MYADDR, SKT_MYPORT, SKT_SERVER, SKT_REUSEADDR,
+ SKT_REUSEPORT
};
- int optionIndex, a, server = 0, port, myport = 0, async = 0, flags = 0;
+ int optionIndex, a, server = 0, port, myport = 0, async = 0;
+ unsigned int flags = 0;
const char *host, *myaddr = NULL;
Tcl_Obj *script = NULL;
Tcl_Channel chan;
@@ -1557,8 +1560,11 @@ Tcl_SocketObjCmd(
}
script = objv[a];
break;
+ case SKT_REUSEADDR:
+ flags |= TCL_TCPSERVER_REUSEADDR;
+ break;
case SKT_REUSEPORT:
- flags |= 1;
+ flags |= TCL_TCPSERVER_REUSEPORT;
break;
default:
Tcl_Panic("Tcl_SocketObjCmd: bad option index to SocketOptions");
@@ -1583,7 +1589,14 @@ Tcl_SocketObjCmd(
"?-myaddr addr? ?-myport myport? ?-async? host port");
iPtr->flags |= INTERP_ALTERNATE_WRONG_ARGS;
Tcl_WrongNumArgs(interp, 1, objv,
- "-server command ?-myaddr addr? port");
+ "-server command ?-reuseaddr? ?-reuseport? ?-myaddr addr? port");
+ return TCL_ERROR;
+ }
+
+ if (!server && flags != 0) {
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(
+ "options -reuseaddr and -reuseport are only valid for servers",
+ -1));
return TCL_ERROR;
}
diff --git a/generic/tclIOSock.c b/generic/tclIOSock.c
index 72a0b5a..b6e99ba 100644
--- a/generic/tclIOSock.c
+++ b/generic/tclIOSock.c
@@ -283,7 +283,7 @@ TclCreateSocketAddress(
}
return 1;
}
-
+
/*
*----------------------------------------------------------------------
*
@@ -304,9 +304,9 @@ Tcl_Channel Tcl_OpenTcpServer(Tcl_Interp *interp, int port,
const char *host, Tcl_TcpAcceptProc *acceptProc,
ClientData callbackData)
{
- return Tcl_OpenTcpServerEx(interp, port, host, 0, acceptProc, callbackData);
+ return Tcl_OpenTcpServerEx(interp, port, host, TCL_TCPSERVER_REUSEADDR,
+ acceptProc, callbackData);
}
-
/*
* Local Variables:
diff --git a/unix/tclUnixSock.c b/unix/tclUnixSock.c
index 4767522..bb75ed3 100644
--- a/unix/tclUnixSock.c
+++ b/unix/tclUnixSock.c
@@ -113,11 +113,6 @@ struct TcpState {
#define SOCKET_BUFSIZE 4096
-#ifdef SO_REUSEPORT
-/* Bitmask to check if the setting of SO_REUSEPORT was requested by the caller. */
-#define USE_SOCK_REUSEPORT 1
-#endif
-
/*
* Static routines for this file:
*/
@@ -1429,13 +1424,13 @@ Tcl_OpenTcpServerEx(
Tcl_Interp *interp, /* For error reporting - may be NULL. */
int port, /* Port number to open. */
const char *myHost, /* Name of local host. */
- int flags, /* Flags. */
+ unsigned int flags, /* Flags. */
Tcl_TcpAcceptProc *acceptProc,
/* Callback for accepting connections from new
* clients. */
ClientData acceptProcData) /* Data for the callback. */
{
- int status = 0, sock = -1, reuseaddr = 1, chosenport;
+ int status = 0, sock = -1, optvalue, chosenport;
struct addrinfo *addrlist = NULL, *addrPtr; /* socket address */
TcpState *statePtr = NULL;
char channelName[SOCK_CHAN_LENGTH];
@@ -1511,24 +1506,28 @@ Tcl_OpenTcpServerEx(
TclSockMinimumBuffers(INT2PTR(sock), SOCKET_BUFSIZE);
/*
- * Set up to reuse server addresses automatically and bind to the
- * specified port.
+ * Set up to reuse server addresses and/or ports if requested.
*/
- (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
- (char *) &reuseaddr, sizeof(reuseaddr));
-
-#ifdef SO_REUSEPORT
- /*
- * Set up to allows multiple sockets on the same host to bind to the same port.
- * The flag can be switched on by setting the lowest bit above the valid maximum port (0xffff).
- */
- if (flags & USE_SOCK_REUSEPORT) {
- int reuseport = 1;
- (void) setsockopt(sock, SOL_SOCKET, SO_REUSEPORT,
- (char *) &reuseport, sizeof(reuseport));
+ if (flags & TCL_TCPSERVER_REUSEADDR) {
+ optvalue = 1;
+ (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+ (char *) &optvalue, sizeof(optvalue));
}
+
+ if (flags & TCL_TCPSERVER_REUSEPORT) {
+#ifndef SO_REUSEPORT
+ /*
+ * If the platform doesn't support the SO_REUSEPORT flag we can't do
+ * much beside erroring out.
+ */
+ errorMsg = "SO_REUSEPORT isn't supported by this platform";
+ goto error;
#endif
+ optvalue = 1;
+ (void) setsockopt(sock, SOL_SOCKET, SO_REUSEPORT,
+ (char *) &optvalue, sizeof(optvalue));
+ }
/*
* Make sure we use the same port number when opening two server
diff --git a/win/tclWinSock.c b/win/tclWinSock.c
index a389d45..b228730 100644
--- a/win/tclWinSock.c
+++ b/win/tclWinSock.c
@@ -2039,7 +2039,7 @@ Tcl_OpenTcpServerEx(
Tcl_Interp *interp, /* For error reporting - may be NULL. */
int port, /* Port number to open. */
const char *myHost, /* Name of local host. */
- int flags, /* Flags (not used) */
+ unsigned int flags, /* Flags (not used) */
Tcl_TcpAcceptProc *acceptProc,
/* Callback for accepting connections from new
* clients. */