From: Yasuhiro Matsumoto Date: Sun, 15 Mar 2026 09:22:29 +0000 (+0000) Subject: patch 9.2.0170: channel: some issues in ch_listen() X-Git-Tag: v9.2.0170^0 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e05d897258a6c3d0463fb6d76aaeb4f0534cd13f;p=thirdparty%2Fvim.git patch 9.2.0170: channel: some issues in ch_listen() Problem: channel: some issues in ch_listen() (char101, after v9.2.0153) Solution: On MS-Windows, initialize using channel_init_winsock() and use SO_EXCLUSIVEADDRUSE instead of SO_REUSEADDR, allow to use port 0 to have the OS assign a port (Yasuhiro Matsumoto). related: #19231 closes: #19690 Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Yasuhiro Matsumoto Signed-off-by: Christian Brabandt --- diff --git a/src/channel.c b/src/channel.c index f35cbf8ead..6f06517fd7 100644 --- a/src/channel.c +++ b/src/channel.c @@ -1440,7 +1440,7 @@ channel_listen_func(typval_T *argvars) return NULL; } port = strtol((char *)(p + 1), &rest, 10); - if (port <= 0 || port >= 65536 || *rest != NUL) + if (port < 0 || port >= 65536 || *rest != NUL) { semsg(_(e_invalid_argument_str), address); return NULL; @@ -1459,7 +1459,7 @@ channel_listen_func(typval_T *argvars) return NULL; } port = strtol((char *)(p + 1), &rest, 10); - if (port <= 0 || port >= 65536 || *rest != NUL) + if (port < 0 || port >= 65536 || *rest != NUL) { semsg(_(e_invalid_argument_str), address); return NULL; @@ -1511,6 +1511,10 @@ channel_listen( int val = 1; channel_T *channel; +#ifdef MSWIN + channel_init_winsock(); +#endif + channel = add_channel(); if (channel == NULL) { @@ -1555,7 +1559,7 @@ channel_listen( } #ifdef MSWIN - if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, + if (setsockopt(sd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char *)&val, sizeof(val)) < 0) #else if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, @@ -1591,6 +1595,16 @@ channel_listen( return NULL; } + // When port 0 was specified, retrieve the actual port assigned by the OS. + if (port_in == 0) + { + struct sockaddr_in addr; + socklen_t addr_len = sizeof(addr); + + if (getsockname(sd, (struct sockaddr *)&addr, &addr_len) == 0) + port_in = ntohs(addr.sin_port); + } + channel->ch_listen = TRUE; channel->CH_SOCK_FD = (sock_T)sd; channel->ch_nb_close_cb = nb_close_cb; diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim index 431eaab261..94dec0d973 100644 --- a/src/testdir/test_channel.vim +++ b/src/testdir/test_channel.vim @@ -2798,8 +2798,11 @@ func Test_listen_invalid_address() " port number too large call assert_fails("call ch_listen('localhost:99999')", 'E475:') - " port number zero - call assert_fails("call ch_listen('localhost:0')", 'E475:') + " port number zero should let the OS assign an available port + let ch = ch_listen('localhost:0') + call assert_equal('open', ch_status(ch)) + call assert_notequal(0, ch_info(ch).port) + call ch_close(ch) " port number negative call assert_fails("call ch_listen('localhost:-1')", 'E475:') diff --git a/src/version.c b/src/version.c index 4f9c944a62..38e48f4a11 100644 --- a/src/version.c +++ b/src/version.c @@ -734,6 +734,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 170, /**/ 169, /**/