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, /**/