summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generic/tclIOCmd.c15
-rw-r--r--unix/tclUnixSock.c20
-rw-r--r--win/tclWinSock.c4
3 files changed, 34 insertions, 5 deletions
diff --git a/generic/tclIOCmd.c b/generic/tclIOCmd.c
index de65da5..9dc8f07 100644
--- a/generic/tclIOCmd.c
+++ b/generic/tclIOCmd.c
@@ -1485,12 +1485,12 @@ Tcl_SocketObjCmd(
Tcl_Obj *const objv[]) /* Argument objects. */
{
static const char *const socketOptions[] = {
- "-async", "-myaddr", "-myport", "-server", NULL
+ "-async", "-myaddr", "-myport", "-server", "-reuseport", NULL
};
enum socketOptions {
- SKT_ASYNC, SKT_MYADDR, SKT_MYPORT, SKT_SERVER
+ SKT_ASYNC, SKT_MYADDR, SKT_MYPORT, SKT_SERVER, SKT_REUSEPORT
};
- int optionIndex, a, server = 0, port, myport = 0, async = 0;
+ int optionIndex, a, server = 0, port, myport = 0, async = 0, reuseport = 0;
const char *host, *myaddr = NULL;
Tcl_Obj *script = NULL;
Tcl_Channel chan;
@@ -1557,6 +1557,9 @@ Tcl_SocketObjCmd(
}
script = objv[a];
break;
+ case SKT_REUSEPORT:
+ reuseport = 1;
+ break;
default:
Tcl_Panic("Tcl_SocketObjCmd: bad option index to SocketOptions");
}
@@ -1600,6 +1603,12 @@ Tcl_SocketObjCmd(
Tcl_IncrRefCount(script);
acceptCallbackPtr->script = script;
acceptCallbackPtr->interp = interp;
+
+ /* Hint for Tcl_OpenTcpServer to set socket option REUSEPORT */
+ if(reuseport) {
+ port |= (1 << 16);
+ }
+
chan = Tcl_OpenTcpServer(interp, port, host, AcceptCallbackProc,
acceptCallbackPtr);
if (chan == NULL) {
diff --git a/unix/tclUnixSock.c b/unix/tclUnixSock.c
index 170aea9..d8a33f9 100644
--- a/unix/tclUnixSock.c
+++ b/unix/tclUnixSock.c
@@ -113,6 +113,11 @@ 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 << 16)
+#endif
+
/*
* Static routines for this file:
*/
@@ -1435,6 +1440,10 @@ Tcl_OpenTcpServer(
char channelName[SOCK_CHAN_LENGTH];
const char *errorMsg = NULL;
TcpFdList *fds = NULL, *newfds;
+#ifdef SO_REUSEPORT
+ int reuseport = port & USE_SOCK_REUSEPORT;
+ CLEAR_BITS(port, USE_SOCK_REUSEPORT);
+#endif
/*
* Try to record and return the most meaningful error message, i.e. the
@@ -1512,6 +1521,17 @@ Tcl_OpenTcpServer(
(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(reuseport) {
+ (void) setsockopt(sock, SOL_SOCKET, SO_REUSEPORT,
+ (char *) &reuseport, sizeof(reuseport));
+ }
+#endif
+
/*
* Make sure we use the same port number when opening two server
* sockets for IPv4 and IPv6 on a random port.
diff --git a/win/tclWinSock.c b/win/tclWinSock.c
index ec881d2..af8dda1 100644
--- a/win/tclWinSock.c
+++ b/win/tclWinSock.c
@@ -2111,8 +2111,8 @@ Tcl_OpenTcpServer(
/*
* Bind to the specified port. Note that we must not call
- * setsockopt with SO_REUSEADDR because Microsoft allows addresses
- * to be reused even if they are still in use.
+ * setsockopt with SO_REUSEADDR or SO_REUSEPORT because Microsoft
+ * allows addresses and ports to be reused even if they are still in use.
*
* Bind should not be affected by the socket having already been
* set into nonblocking mode. If there is trouble, this is one