To: vim_dev@googlegroups.com Subject: Patch 8.2.0557 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.0557 Problem: No IPv6 support for channels. Solution: Add IPv6 support. (Ozaki Kiichi, closes #5893) Files: .travis.yml, runtime/doc/channel.txt, runtime/doc/various.txt, src/Make_cyg_ming.mak, src/Make_mvc.mak, src/auto/configure, src/channel.c, src/config.h.in, src/configure.ac, src/evalfunc.c, src/proto/channel.pro, src/testdir/check.vim, src/testdir/runtest.vim, src/testdir/test_cdo.vim, src/testdir/test_channel.py, src/testdir/test_channel.vim, src/testdir/test_channel_6.py, src/testdir/test_escaped_glob.vim, src/testdir/test_getcwd.vim, src/testdir/test_hide.vim *** ../vim-8.2.0556/.travis.yml 2020-04-11 18:01:10.929802359 +0200 --- .travis.yml 2020-04-12 17:32:54.427547851 +0200 *************** *** 62,70 **** sudo update-alternatives --install /usr/bin/lua lua /usr/bin/lua5.3 10 fi before_script: ! # On travis bionic-amd64 gethostbyname() resolves "localhost" to 127.0.1.1 ! # so that makes various channel tests fail. ! - sudo sed -i '/^127\.0\.1\.1\s/s/\blocalhost\b//g' /etc/hosts - sudo bash ci/load-snd-dummy.sh || true - sudo usermod -a -G audio $USER - do_test() { sg audio "sg $(id -gn) '$*'"; } --- 62,68 ---- sudo update-alternatives --install /usr/bin/lua lua /usr/bin/lua5.3 10 fi before_script: ! - sudo sysctl -w net.ipv6.conf.lo.disable_ipv6=0 - sudo bash ci/load-snd-dummy.sh || true - sudo usermod -a -G audio $USER - do_test() { sg audio "sg $(id -gn) '$*'"; } *** ../vim-8.2.0556/runtime/doc/channel.txt 2019-12-12 12:49:05.000000000 +0100 --- runtime/doc/channel.txt 2020-04-12 17:32:54.427547851 +0200 *************** *** 120,125 **** --- 120,128 ---- {address} has the form "hostname:port". E.g., "localhost:8765". + When using an IPv6 address, enclose it within square brackets. E.g., + "[2001:db8::1]:8765". + {options} is a dictionary with optional entries: *channel-open-options* "mode" can be: *channel-mode* *************** *** 621,626 **** --- 624,632 ---- {address} has the form "hostname:port", e.g., "localhost:8765". + When using an IPv6 address, enclose it within square brackets. + E.g., "[2001:db8::1]:8765". + If {options} is given it must be a |Dictionary|. See |channel-open-options|. *** ../vim-8.2.0556/runtime/doc/various.txt 2020-02-22 14:26:39.248757828 +0100 --- runtime/doc/various.txt 2020-04-12 17:32:54.427547851 +0200 *************** *** 374,379 **** --- 375,381 ---- *+iconv* Compiled with the |iconv()| function *+iconv/dyn* Likewise |iconv-dynamic| |/dyn| T *+insert_expand* |insert_expand| Insert mode completion + m *+ipv6* Support for IPv6 networking |channel| m *+job* starting and stopping jobs |job| S *+jumplist* |jumplist| B *+keymap* |'keymap'| *** ../vim-8.2.0556/src/Make_cyg_ming.mak 2020-04-05 20:20:40.100596581 +0200 --- src/Make_cyg_ming.mak 2020-04-12 17:32:54.427547851 +0200 *************** *** 850,856 **** ifeq ($(CHANNEL),yes) OBJ += $(OUTDIR)/channel.o ! LIB += -lwsock32 endif ifeq ($(DIRECTX),yes) --- 850,856 ---- ifeq ($(CHANNEL),yes) OBJ += $(OUTDIR)/channel.o ! LIB += -lwsock32 -lws2_32 endif ifeq ($(DIRECTX),yes) *** ../vim-8.2.0556/src/Make_mvc.mak 2020-04-05 20:20:40.100596581 +0200 --- src/Make_mvc.mak 2020-04-12 17:32:54.427547851 +0200 *************** *** 469,475 **** CHANNEL_OBJ = $(OBJDIR)/channel.obj CHANNEL_DEFS = -DFEAT_JOB_CHANNEL ! NETBEANS_LIB = WSock32.lib !endif # Set which version of the CRT to use --- 469,475 ---- CHANNEL_OBJ = $(OBJDIR)/channel.obj CHANNEL_DEFS = -DFEAT_JOB_CHANNEL ! NETBEANS_LIB = WSock32.lib Ws2_32.lib !endif # Set which version of the CRT to use *** ../vim-8.2.0556/src/auto/configure 2020-02-26 16:15:31.068386966 +0100 --- src/auto/configure 2020-04-12 17:34:25.626859274 +0200 *************** *** 7723,7730 **** fi if test "$enable_channel" = "yes"; then ! ! if test "x$HAIKU" = "xyes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lnetwork" >&5 $as_echo_n "checking for socket in -lnetwork... " >&6; } if ${ac_cv_lib_network_socket+:} false; then : --- 7723,7729 ---- fi if test "$enable_channel" = "yes"; then ! if test "x$HAIKU" = "xyes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lnetwork" >&5 $as_echo_n "checking for socket in -lnetwork... " >&6; } if ${ac_cv_lib_network_socket+:} false; then : *************** *** 7818,7824 **** fi ! { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 $as_echo_n "checking for gethostbyname in -lnsl... " >&6; } if ${ac_cv_lib_nsl_gethostbyname+:} false; then : $as_echo_n "(cached) " >&6 --- 7817,7879 ---- fi ! { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiling with IPv6 networking is possible" >&5 ! $as_echo_n "checking whether compiling with IPv6 networking is possible... " >&6; } ! if ${vim_cv_ipv6_networking+:} false; then : ! $as_echo_n "(cached) " >&6 ! else ! cat confdefs.h - <<_ACEOF >conftest.$ac_ext ! /* end confdefs.h. */ ! ! #include ! #include ! #include ! #include ! #include ! #include ! #include ! #include ! #include ! /* Check bitfields */ ! struct nbbuf { ! unsigned int initDone:1; ! unsigned short signmaplen; ! }; ! ! int ! main () ! { ! ! /* Check creating a socket. */ ! struct sockaddr_in server; ! struct addrinfo *res; ! (void)socket(AF_INET, SOCK_STREAM, 0); ! (void)htons(100); ! (void)getaddrinfo("microsoft.com", NULL, NULL, &res); ! if (errno == ECONNREFUSED) ! (void)connect(1, (struct sockaddr *)&server, sizeof(server)); ! (void)freeaddrinfo(res); ! ! ; ! return 0; ! } ! _ACEOF ! if ac_fn_c_try_link "$LINENO"; then : ! vim_cv_ipv6_networking="yes" ! else ! vim_cv_ipv6_networking="no" ! fi ! rm -f core conftest.err conftest.$ac_objext \ ! conftest$ac_exeext conftest.$ac_ext ! fi ! { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_ipv6_networking" >&5 ! $as_echo "$vim_cv_ipv6_networking" >&6; } ! ! if test "x$vim_cv_ipv6_networking" = "xyes"; then ! $as_echo "#define FEAT_IPV6 1" >>confdefs.h ! ! else ! { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 $as_echo_n "checking for gethostbyname in -lnsl... " >&6; } if ${ac_cv_lib_nsl_gethostbyname+:} false; then : $as_echo_n "(cached) " >&6 *************** *** 7863,7870 **** fi ! { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiling with process communication is possible" >&5 ! $as_echo_n "checking whether compiling with process communication is possible... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ --- 7918,7928 ---- fi ! { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiling with IPv4 networking is possible" >&5 ! $as_echo_n "checking whether compiling with IPv4 networking is possible... " >&6; } ! if ${vim_cv_ipv4_networking+:} false; then : ! $as_echo_n "(cached) " >&6 ! else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ *************** *** 7900,7914 **** } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ! { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 ! $as_echo "yes" >&6; } else ! { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ! $as_echo "no" >&6; }; enable_netbeans="no"; enable_channel="no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi if test "$enable_netbeans" = "yes"; then $as_echo "#define FEAT_NETBEANS_INTG 1" >>confdefs.h --- 7958,7974 ---- } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ! vim_cv_ipv4_networking="yes" else ! vim_cv_ipv4_networking="no"; enable_netbeans="no"; enable_channel="no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_ipv4_networking" >&5 + $as_echo "$vim_cv_ipv4_networking" >&6; } + fi + fi if test "$enable_netbeans" = "yes"; then $as_echo "#define FEAT_NETBEANS_INTG 1" >>confdefs.h *** ../vim-8.2.0556/src/channel.c 2020-04-02 18:50:42.415773144 +0200 --- src/channel.c 2020-04-12 17:32:54.427547851 +0200 *************** *** 10,15 **** --- 10,22 ---- * Implements communication through a socket or any file handle. */ + #ifdef WIN32 + // Must include winsock2.h before windows.h since it conflicts with winsock.h + // (included in windows.h). + # include + # include + #endif + #include "vim.h" #if defined(FEAT_JOB_CHANNEL) || defined(PROTO) *************** *** 40,46 **** #else # include # include ! # include # ifdef HAVE_LIBGEN_H # include --- 47,53 ---- #else # include # include ! # include # include # ifdef HAVE_LIBGEN_H # include *************** *** 711,800 **** static char *e_cannot_connect = N_("E902: Cannot connect to port"); /* ! * Open a socket channel to "hostname":"port". ! * "waittime" is the time in msec to wait for the connection. ! * When negative wait forever. ! * Returns the channel for success. ! * Returns NULL for failure. */ ! channel_T * ! channel_open( ! char *hostname, ! int port_in, ! int waittime, ! void (*nb_close_cb)(void)) { ! int sd = -1; ! struct sockaddr_in server; ! struct hostent *host; ! #ifdef MSWIN ! u_short port = port_in; ! u_long val = 1; ! #else ! int port = port_in; ! #endif ! channel_T *channel; ! int ret; ! #ifdef MSWIN ! channel_init_winsock(); #endif - channel = add_channel(); - if (channel == NULL) - { - ch_error(NULL, "Cannot allocate channel."); - return NULL; - } - - // Get the server internet address and put into addr structure - // fill in the socket address structure and connect to server - vim_memset((char *)&server, 0, sizeof(server)); - server.sin_family = AF_INET; - server.sin_port = htons(port); - if ((host = gethostbyname(hostname)) == NULL) - { - ch_error(channel, "in gethostbyname() in channel_open()"); - PERROR(_("E901: gethostbyname() in channel_open()")); - channel_free(channel); - return NULL; - } - { - char *p; - - // When using host->h_addr_list[0] directly ubsan warns for it to not - // be aligned. First copy the pointer to avoid that. - memcpy(&p, &host->h_addr_list[0], sizeof(p)); - memcpy((char *)&server.sin_addr, p, host->h_length); - } - - // On Mac and Solaris a zero timeout almost never works. At least wait - // one millisecond. Let's do it for all systems, because we don't know why - // this is needed. - if (waittime == 0) - waittime = 1; - - /* - * For Unix we need to call connect() again after connect() failed. - * On Win32 one time is sufficient. - */ while (TRUE) { long elapsed_msec = 0; int waitnow; if (sd >= 0) sock_close(sd); ! sd = socket(AF_INET, SOCK_STREAM, 0); if (sd == -1) { ! ch_error(channel, "in socket() in channel_open()."); ! PERROR(_("E898: socket() in channel_open()")); ! channel_free(channel); ! return NULL; } ! if (waittime >= 0) { // Make connect() non-blocking. if ( --- 718,755 ---- static char *e_cannot_connect = N_("E902: Cannot connect to port"); /* ! * For Unix we need to call connect() again after connect() failed. ! * On Win32 one time is sufficient. */ ! static int ! channel_connect( ! channel_T *channel, ! const struct sockaddr *server_addr, ! int server_addrlen, ! int *waittime) { ! int sd = -1; #ifdef MSWIN ! u_long val = 1; #endif while (TRUE) { long elapsed_msec = 0; int waitnow; + int ret; if (sd >= 0) sock_close(sd); ! sd = socket(server_addr->sa_family, SOCK_STREAM, 0); if (sd == -1) { ! ch_error(channel, "in socket() in channel_connect()."); ! PERROR(_("E898: socket() in channel_connect()")); ! return -1; } ! if (*waittime >= 0) { // Make connect() non-blocking. if ( *************** *** 807,829 **** { SOCK_ERRNO; ch_error(channel, ! "channel_open: Connect failed with errno %d", errno); sock_close(sd); ! channel_free(channel); ! return NULL; } } // Try connecting to the server. ! ch_log(channel, "Connecting to %s port %d", hostname, port); ! ret = connect(sd, (struct sockaddr *)&server, sizeof(server)); if (ret == 0) // The connection could be established. break; SOCK_ERRNO; ! if (waittime < 0 || (errno != EWOULDBLOCK && errno != ECONNREFUSED #ifdef EINPROGRESS && errno != EINPROGRESS --- 762,783 ---- { SOCK_ERRNO; ch_error(channel, ! "channel_connect: Connect failed with errno %d", errno); sock_close(sd); ! return -1; } } // Try connecting to the server. ! ch_log(channel, "Connecting..."); + ret = connect(sd, server_addr, server_addrlen); if (ret == 0) // The connection could be established. break; SOCK_ERRNO; ! if (*waittime < 0 || (errno != EWOULDBLOCK && errno != ECONNREFUSED #ifdef EINPROGRESS && errno != EINPROGRESS *************** *** 831,852 **** )) { ch_error(channel, ! "channel_open: Connect failed with errno %d", errno); PERROR(_(e_cannot_connect)); sock_close(sd); ! channel_free(channel); ! return NULL; } // Limit the waittime to 50 msec. If it doesn't work within this // time we close the socket and try creating it again. ! waitnow = waittime > 50 ? 50 : waittime; // If connect() didn't finish then try using select() to wait for the // connection to be made. For Win32 always use select() to wait. - #ifndef MSWIN - if (errno != ECONNREFUSED) - #endif { struct timeval tv; fd_set rfds; --- 785,808 ---- )) { ch_error(channel, ! "channel_connect: Connect failed with errno %d", errno); PERROR(_(e_cannot_connect)); sock_close(sd); ! return -1; ! } ! else if (errno == ECONNREFUSED) ! { ! ch_error(channel, "channel_connect: Connection refused"); ! sock_close(sd); ! return -1; } // Limit the waittime to 50 msec. If it doesn't work within this // time we close the socket and try creating it again. ! waitnow = *waittime > 50 ? 50 : *waittime; // If connect() didn't finish then try using select() to wait for the // connection to be made. For Win32 always use select() to wait. { struct timeval tv; fd_set rfds; *************** *** 868,885 **** gettimeofday(&start_tv, NULL); #endif ch_log(channel, ! "Waiting for connection (waiting %d msec)...", waitnow); ! ret = select((int)sd + 1, &rfds, &wfds, NULL, &tv); if (ret < 0) { SOCK_ERRNO; ch_error(channel, ! "channel_open: Connect failed with errno %d", errno); PERROR(_(e_cannot_connect)); sock_close(sd); ! channel_free(channel); ! return NULL; } #ifdef MSWIN --- 824,840 ---- gettimeofday(&start_tv, NULL); #endif ch_log(channel, ! "Waiting for connection (waiting %d msec)...", waitnow); + ret = select((int)sd + 1, &rfds, &wfds, NULL, &tv); if (ret < 0) { SOCK_ERRNO; ch_error(channel, ! "channel_connect: Connect failed with errno %d", errno); PERROR(_(e_cannot_connect)); sock_close(sd); ! return -1; } #ifdef MSWIN *************** *** 888,896 **** if (FD_ISSET(sd, &wfds)) break; elapsed_msec = waitnow; ! if (waittime > 1 && elapsed_msec < waittime) { ! waittime -= elapsed_msec; continue; } #else --- 843,851 ---- if (FD_ISSET(sd, &wfds)) break; elapsed_msec = waitnow; ! if (*waittime > 1 && elapsed_msec < *waittime) { ! *waittime -= elapsed_msec; continue; } #else *************** *** 914,925 **** )) { ch_error(channel, ! "channel_open: Connect failed with errno %d", so_error); PERROR(_(e_cannot_connect)); sock_close(sd); ! channel_free(channel); ! return NULL; } } --- 869,885 ---- )) { ch_error(channel, ! "channel_connect: Connect failed with errno %d", so_error); PERROR(_(e_cannot_connect)); sock_close(sd); ! return -1; ! } ! else if (errno == ECONNREFUSED) ! { ! ch_error(channel, "channel_connect: Connection refused"); ! sock_close(sd); ! return -1; } } *************** *** 929,958 **** gettimeofday(&end_tv, NULL); elapsed_msec = (end_tv.tv_sec - start_tv.tv_sec) * 1000 ! + (end_tv.tv_usec - start_tv.tv_usec) / 1000; #endif } #ifndef MSWIN ! if (waittime > 1 && elapsed_msec < waittime) { // The port isn't ready but we also didn't get an error. // This happens when the server didn't open the socket // yet. Select() may return early, wait until the remaining // "waitnow" and try again. waitnow -= elapsed_msec; ! waittime -= elapsed_msec; if (waitnow > 0) { mch_delay((long)waitnow, TRUE); ui_breakcheck(); ! waittime -= waitnow; } if (!got_int) { ! if (waittime <= 0) // give it one more try ! waittime = 1; continue; } // we were interrupted, behave as if timed out --- 889,918 ---- gettimeofday(&end_tv, NULL); elapsed_msec = (end_tv.tv_sec - start_tv.tv_sec) * 1000 ! + (end_tv.tv_usec - start_tv.tv_usec) / 1000; #endif } #ifndef MSWIN ! if (*waittime > 1 && elapsed_msec < *waittime) { // The port isn't ready but we also didn't get an error. // This happens when the server didn't open the socket // yet. Select() may return early, wait until the remaining // "waitnow" and try again. waitnow -= elapsed_msec; ! *waittime -= elapsed_msec; if (waitnow > 0) { mch_delay((long)waitnow, TRUE); ui_breakcheck(); ! *waittime -= waitnow; } if (!got_int) { ! if (*waittime <= 0) // give it one more try ! *waittime = 1; continue; } // we were interrupted, behave as if timed out *************** *** 962,974 **** // We timed out. ch_error(channel, "Connection timed out"); sock_close(sd); ! channel_free(channel); ! return NULL; } ! ch_log(channel, "Connection made"); ! ! if (waittime >= 0) { #ifdef MSWIN val = 0; --- 922,931 ---- // We timed out. ch_error(channel, "Connection timed out"); sock_close(sd); ! return -1; } ! if (*waittime >= 0) { #ifdef MSWIN val = 0; *************** *** 978,987 **** #endif } channel->CH_SOCK_FD = (sock_T)sd; channel->ch_nb_close_cb = nb_close_cb; channel->ch_hostname = (char *)vim_strsave((char_u *)hostname); ! channel->ch_port = port_in; channel->ch_to_be_closed |= (1U << PART_SOCK); #ifdef FEAT_GUI --- 935,1085 ---- #endif } + return sd; + } + + /* + * Open a socket channel to "hostname":"port". + * "waittime" is the time in msec to wait for the connection. + * When negative wait forever. + * Returns the channel for success. + * Returns NULL for failure. + */ + channel_T * + channel_open( + const char *hostname, + int port, + int waittime, + void (*nb_close_cb)(void)) + { + int sd = -1; + channel_T *channel = NULL; + #ifdef FEAT_IPV6 + struct addrinfo hints; + struct addrinfo *res = NULL; + struct addrinfo *addr = NULL; + #else + struct sockaddr_in server; + struct hostent *host = NULL; + #endif + + #ifdef MSWIN + channel_init_winsock(); + #endif + + channel = add_channel(); + if (channel == NULL) + { + ch_error(NULL, "Cannot allocate channel."); + return NULL; + } + + // Get the server internet address and put into addr structure fill in the + // socket address structure and connect to server. + #ifdef FEAT_IPV6 + vim_memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + # ifdef AI_ADDRCONFIG + hints.ai_flags = AI_ADDRCONFIG; + # endif + // Set port number manually in order to prevent name resolution services + // from being invoked in the environment where AI_NUMERICSERV is not + // defined. + if (getaddrinfo(hostname, NULL, &hints, &res) != 0) + { + ch_error(channel, "in getaddrinfo() in channel_open()"); + PERROR(_("E901: getaddrinfo() in channel_open()")); + channel_free(channel); + return NULL; + } + + for (addr = res; addr != NULL; addr = addr->ai_next) + { + const char *dst = hostname; + const void *src = NULL; + char buf[NUMBUFLEN]; + + if (addr->ai_family == AF_INET6) + { + struct sockaddr_in6 *sai = (struct sockaddr_in6 *)addr->ai_addr; + + sai->sin6_port = htons(port); + src = &sai->sin6_addr; + } + else if (addr->ai_family == AF_INET) + { + struct sockaddr_in *sai = (struct sockaddr_in *)addr->ai_addr; + + sai->sin_port = htons(port); + src = &sai->sin_addr; + } + if (src != NULL) + { + dst = inet_ntop(addr->ai_family, src, buf, sizeof(buf)); + if (dst != NULL && STRCMP(hostname, dst) != 0) + ch_log(channel, "Resolved %s to %s", hostname, dst); + } + + ch_log(channel, "Trying to connect to %s port %d", dst, port); + + // On Mac and Solaris a zero timeout almost never works. At least wait + // one millisecond. Let's do it for all systems, because we don't know + // why this is needed. + if (waittime == 0) + waittime = 1; + + sd = channel_connect(channel, addr->ai_addr, addr->ai_addrlen, + &waittime); + if (sd >= 0) + break; + } + + freeaddrinfo(res); + #else + vim_memset((char *)&server, 0, sizeof(server)); + server.sin_family = AF_INET; + server.sin_port = htons(port); + if ((host = gethostbyname(hostname)) == NULL) + { + ch_error(channel, "in gethostbyname() in channel_open()"); + PERROR(_("E901: gethostbyname() in channel_open()")); + channel_free(channel); + return NULL; + } + { + char *p; + + // When using host->h_addr_list[0] directly ubsan warns for it to not + // be aligned. First copy the pointer to avoid that. + memcpy(&p, &host->h_addr_list[0], sizeof(p)); + memcpy((char *)&server.sin_addr, p, host->h_length); + } + + ch_log(channel, "Trying to connect to %s port %d", hostname, port); + + // On Mac and Solaris a zero timeout almost never works. At least wait one + // millisecond. Let's do it for all systems, because we don't know why + // this is needed. + if (waittime == 0) + waittime = 1; + + sd = channel_connect(channel, (struct sockaddr *)&server, sizeof(server), + &waittime); + #endif + + if (sd < 0) + { + channel_free(channel); + return NULL; + } + + ch_log(channel, "Connection made"); + channel->CH_SOCK_FD = (sock_T)sd; channel->ch_nb_close_cb = nb_close_cb; channel->ch_hostname = (char *)vim_strsave((char_u *)hostname); ! channel->ch_port = port; channel->ch_to_be_closed |= (1U << PART_SOCK); #ifdef FEAT_GUI *************** *** 1222,1227 **** --- 1320,1326 ---- char_u *p; char *rest; int port; + int is_ipv6 = FALSE; jobopt_T opt; channel_T *channel = NULL; *************** *** 1234,1253 **** } // parse address ! p = vim_strchr(address, ':'); ! if (p == NULL) { ! semsg(_(e_invarg2), address); ! return NULL; } ! *p++ = NUL; ! port = strtol((char *)p, &rest, 10); ! if (*address == NUL || port <= 0 || *rest != NUL) { - p[-1] = ':'; semsg(_(e_invarg2), address); return NULL; } // parse options clear_job_options(&opt); --- 1333,1372 ---- } // parse address ! if (*address == '[') { ! // ipv6 address ! is_ipv6 = TRUE; ! p = vim_strchr(address + 1, ']'); ! if (p == NULL || *++p != ':') ! { ! semsg(_(e_invarg2), address); ! return NULL; ! } ! } ! else ! { ! p = vim_strchr(address, ':'); ! if (p == NULL) ! { ! semsg(_(e_invarg2), address); ! return NULL; ! } } ! port = strtol((char *)(p + 1), &rest, 10); ! if (*address == NUL || port <= 0 || port >= 65536 || *rest != NUL) { semsg(_(e_invarg2), address); return NULL; } + if (is_ipv6) + { + // strip '[' and ']' + ++address; + *(p - 1) = NUL; + } + else + *p = NUL; // parse options clear_job_options(&opt); *** ../vim-8.2.0556/src/config.h.in 2019-11-21 17:03:13.000000000 +0100 --- src/config.h.in 2020-04-12 17:32:54.431547820 +0200 *************** *** 438,443 **** --- 438,446 ---- /* Define if we have shl_load() */ #undef HAVE_SHL_LOAD + /* Define if we can use IPv6 networking. */ + #undef FEAT_IPV6 + /* Define if you want to include NetBeans integration. */ #undef FEAT_NETBEANS_INTG *** ../vim-8.2.0556/src/configure.ac 2020-02-26 16:15:31.068386966 +0100 --- src/configure.ac 2020-04-12 17:32:54.431547820 +0200 *************** *** 2038,2054 **** fi if test "$enable_channel" = "yes"; then ! dnl On Solaris we need the socket and nsl library. ! if test "x$HAIKU" = "xyes"; then AC_CHECK_LIB(network, socket) else AC_CHECK_LIB(socket, socket) fi ! AC_CHECK_LIB(nsl, gethostbyname) ! AC_MSG_CHECKING(whether compiling with process communication is possible) ! AC_TRY_LINK([ #include #include #include --- 2038,2087 ---- fi if test "$enable_channel" = "yes"; then ! dnl On Solaris we need the socket library, or on Haiku the network library. if test "x$HAIKU" = "xyes"; then AC_CHECK_LIB(network, socket) else AC_CHECK_LIB(socket, socket) fi ! AC_CACHE_CHECK([whether compiling with IPv6 networking is possible], [vim_cv_ipv6_networking], ! [AC_TRY_LINK([ ! #include ! #include ! #include ! #include ! #include ! #include ! #include ! #include ! #include ! /* Check bitfields */ ! struct nbbuf { ! unsigned int initDone:1; ! unsigned short signmaplen; ! }; ! ], [ ! /* Check creating a socket. */ ! struct sockaddr_in server; ! struct addrinfo *res; ! (void)socket(AF_INET, SOCK_STREAM, 0); ! (void)htons(100); ! (void)getaddrinfo("microsoft.com", NULL, NULL, &res); ! if (errno == ECONNREFUSED) ! (void)connect(1, (struct sockaddr *)&server, sizeof(server)); ! (void)freeaddrinfo(res); ! ], ! [vim_cv_ipv6_networking="yes"], ! [vim_cv_ipv6_networking="no"])]) ! ! if test "x$vim_cv_ipv6_networking" = "xyes"; then ! AC_DEFINE(FEAT_IPV6) ! else ! dnl On Solaris we need the nsl library. ! AC_CHECK_LIB(nsl, gethostbyname) ! AC_CACHE_CHECK([whether compiling with IPv4 networking is possible], [vim_cv_ipv4_networking], ! [AC_TRY_LINK([ #include #include #include *************** *** 2072,2079 **** if (errno == ECONNREFUSED) (void)connect(1, (struct sockaddr *)&server, sizeof(server)); ], ! AC_MSG_RESULT(yes), ! AC_MSG_RESULT(no); enable_netbeans="no"; enable_channel="no") fi if test "$enable_netbeans" = "yes"; then AC_DEFINE(FEAT_NETBEANS_INTG) --- 2105,2113 ---- if (errno == ECONNREFUSED) (void)connect(1, (struct sockaddr *)&server, sizeof(server)); ], ! [vim_cv_ipv4_networking="yes"], ! [vim_cv_ipv4_networking="no"; enable_netbeans="no"; enable_channel="no"])]) ! fi fi if test "$enable_netbeans" = "yes"; then AC_DEFINE(FEAT_NETBEANS_INTG) *** ../vim-8.2.0556/src/evalfunc.c 2020-04-08 20:03:48.184622981 +0200 --- src/evalfunc.c 2020-04-12 17:32:54.431547820 +0200 *************** *** 3943,3948 **** --- 3943,3955 ---- #endif }, {"insert_expand", 1}, + {"ipv6", + #ifdef FEAT_IPV6 + 1 + #else + 0 + #endif + }, {"job", #ifdef FEAT_JOB_CHANNEL 1 *** ../vim-8.2.0556/src/proto/channel.pro 2020-01-30 16:27:02.068562909 +0100 --- src/proto/channel.pro 2020-04-12 17:32:54.431547820 +0200 *************** *** 7,13 **** int free_unused_channels_contents(int copyID, int mask); void free_unused_channels(int copyID, int mask); void channel_gui_register_all(void); ! channel_T *channel_open(char *hostname, int port_in, int waittime, void (*nb_close_cb)(void)); void channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err); void channel_set_job(channel_T *channel, job_T *job, jobopt_T *options); void channel_buffer_free(buf_T *buf); --- 7,13 ---- int free_unused_channels_contents(int copyID, int mask); void free_unused_channels(int copyID, int mask); void channel_gui_register_all(void); ! channel_T *channel_open(const char *hostname, int port, int waittime, void (*nb_close_cb)(void)); void channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err); void channel_set_job(channel_T *channel, job_T *job, jobopt_T *options); void channel_buffer_free(buf_T *buf); *** ../vim-8.2.0556/src/testdir/check.vim 2020-04-04 14:00:34.193098268 +0200 --- src/testdir/check.vim 2020-04-12 17:32:54.431547820 +0200 *************** *** 142,145 **** --- 142,178 ---- endif endfunc + " Command to check that loopback device has IPv6 address + command CheckIPv6 call CheckIPv6() + func CheckIPv6() + if !has('ipv6') + throw 'Skipped: cannot use IPv6 networking' + endif + if !exists('s:ipv6_loopback') + let s:ipv6_loopback = s:CheckIPv6Loopback() + endif + if !s:ipv6_loopback + throw 'Skipped: no IPv6 address for loopback device' + endif + endfunc + + func s:CheckIPv6Loopback() + if has('win32') + return system('netsh interface ipv6 show interface') =~? '\' + elseif filereadable('/proc/net/if_inet6') + return (match(readfile('/proc/net/if_inet6'), '\slo$') >= 0) + elseif executable('ifconfig') + for dev in ['lo0', 'lo', 'loop'] + " NOTE: On SunOS, need specify address family 'inet6' to get IPv6 info. + if system('ifconfig ' .. dev .. ' inet6 2>/dev/null') =~? '\' + \ || system('ifconfig ' .. dev .. ' 2>/dev/null') =~? '\' + return v:true + endif + endfor + else + " TODO: How to check it in other platforms? + endif + return v:false + endfunc + " vim: shiftwidth=2 sts=2 expandtab *** ../vim-8.2.0556/src/testdir/runtest.vim 2020-03-26 16:50:53.413148743 +0100 --- src/testdir/runtest.vim 2020-04-12 17:32:54.431547820 +0200 *************** *** 161,168 **** exe 'call ' . a:test else try ! let s:test = a:test ! au VimLeavePre * call EarlyExit(s:test) exe 'call ' . a:test au! VimLeavePre catch /^\cskipped/ --- 161,167 ---- exe 'call ' . a:test else try ! au VimLeavePre * call EarlyExit(g:testfunc) exe 'call ' . a:test au! VimLeavePre catch /^\cskipped/ *************** *** 226,236 **** if len(v:errors) > 0 if match(s:may_fail_list, '^' .. a:func_name) >= 0 let s:fail_expected += 1 ! call add(s:errors_expected, 'Found errors in ' . s:test . ':') call extend(s:errors_expected, v:errors) else let s:fail += 1 ! call add(s:errors, 'Found errors in ' . s:test . ':') call extend(s:errors, v:errors) endif let v:errors = [] --- 225,235 ---- if len(v:errors) > 0 if match(s:may_fail_list, '^' .. a:func_name) >= 0 let s:fail_expected += 1 ! call add(s:errors_expected, 'Found errors in ' . g:testfunc . ':') call extend(s:errors_expected, v:errors) else let s:fail += 1 ! call add(s:errors, 'Found errors in ' . g:testfunc . ':') call extend(s:errors, v:errors) endif let v:errors = [] *************** *** 396,426 **** let s:may_fail_list = [] if $TEST_MAY_FAIL != '' ! " Split the list at commas and add () to make it match s:test. let s:may_fail_list = split($TEST_MAY_FAIL, ',')->map({i, v -> v .. '()'}) endif " Execute the tests in alphabetical order. ! for s:test in sort(s:tests) " Silence, please! set belloff=all let prev_error = '' let total_errors = [] let g:run_nr = 1 ! " A test can set test_is_flaky to retry running the test. ! let test_is_flaky = 0 ! call RunTheTest(s:test) " Repeat a flaky test. Give up when: " - it fails again with the same message " - it fails five times (with a different message) if len(v:errors) > 0 ! \ && (index(s:flaky_tests, s:test) >= 0 ! \ || test_is_flaky) while 1 ! call add(s:messages, 'Found errors in ' . s:test . ':') call extend(s:messages, v:errors) call add(total_errors, 'Run ' . g:run_nr . ':') --- 395,425 ---- let s:may_fail_list = [] if $TEST_MAY_FAIL != '' ! " Split the list at commas and add () to make it match g:testfunc. let s:may_fail_list = split($TEST_MAY_FAIL, ',')->map({i, v -> v .. '()'}) endif " Execute the tests in alphabetical order. ! for g:testfunc in sort(s:tests) " Silence, please! set belloff=all let prev_error = '' let total_errors = [] let g:run_nr = 1 ! " A test can set g:test_is_flaky to retry running the test. ! let g:test_is_flaky = 0 ! call RunTheTest(g:testfunc) " Repeat a flaky test. Give up when: " - it fails again with the same message " - it fails five times (with a different message) if len(v:errors) > 0 ! \ && (index(s:flaky_tests, g:testfunc) >= 0 ! \ || g:test_is_flaky) while 1 ! call add(s:messages, 'Found errors in ' . g:testfunc . ':') call extend(s:messages, v:errors) call add(total_errors, 'Run ' . g:run_nr . ':') *************** *** 443,449 **** let v:errors = [] let g:run_nr += 1 ! call RunTheTest(s:test) if len(v:errors) == 0 " Test passed on rerun. --- 442,448 ---- let v:errors = [] let g:run_nr += 1 ! call RunTheTest(g:testfunc) if len(v:errors) == 0 " Test passed on rerun. *************** *** 452,458 **** endwhile endif ! call AfterTheTest(s:test) endfor call FinishTesting() --- 451,457 ---- endwhile endif ! call AfterTheTest(g:testfunc) endfor call FinishTesting() *** ../vim-8.2.0556/src/testdir/test_cdo.vim 2019-08-07 22:27:45.000000000 +0200 --- src/testdir/test_cdo.vim 2020-04-12 17:32:54.431547820 +0200 *************** *** 4,10 **** CheckFeature quickfix " Create the files used by the tests ! function SetUp() call writefile(["Line1", "Line2", "Line3"], 'Xtestfile1') call writefile(["Line1", "Line2", "Line3"], 'Xtestfile2') call writefile(["Line1", "Line2", "Line3"], 'Xtestfile3') --- 4,10 ---- CheckFeature quickfix " Create the files used by the tests ! func SetUp() call writefile(["Line1", "Line2", "Line3"], 'Xtestfile1') call writefile(["Line1", "Line2", "Line3"], 'Xtestfile2') call writefile(["Line1", "Line2", "Line3"], 'Xtestfile3') *** ../vim-8.2.0556/src/testdir/test_channel.py 2017-02-06 20:31:27.000000000 +0100 --- src/testdir/test_channel.py 2020-04-12 17:32:54.431547820 +0200 *************** *** 1,4 **** ! #!/usr/bin/python # # Server that will accept connections from a Vim channel. # Used by test_channel.vim. --- 1,4 ---- ! #!/usr/bin/env python # # Server that will accept connections from a Vim channel. # Used by test_channel.vim. *************** *** 235,255 **** f.write("{0}".format(port)) f.close() ! if __name__ == "__main__": ! HOST, PORT = "localhost", 0 ! # Wait half a second before opening the port to test waittime in ch_open(). # We do want to get the port number, get that first. We cannot open the # socket, guess a port is free. if len(sys.argv) >= 2 and sys.argv[1] == 'delay': ! PORT = 13684 ! writePortInFile(PORT) print("Wait for it...") time.sleep(0.5) ! server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler) ! ip, port = server.server_address # Start a thread with the server. That thread will then start a new thread # for each connection. --- 235,253 ---- f.write("{0}".format(port)) f.close() ! def main(host, port, server_class=ThreadedTCPServer): # Wait half a second before opening the port to test waittime in ch_open(). # We do want to get the port number, get that first. We cannot open the # socket, guess a port is free. if len(sys.argv) >= 2 and sys.argv[1] == 'delay': ! port = 13684 ! writePortInFile(port) print("Wait for it...") time.sleep(0.5) ! server = server_class((host, port), ThreadedTCPRequestHandler) ! ip, port = server.server_address[0:2] # Start a thread with the server. That thread will then start a new thread # for each connection. *************** *** 263,269 **** # Main thread terminates, but the server continues running # until server.shutdown() is called. try: ! while server_thread.isAlive(): server_thread.join(1) except (KeyboardInterrupt, SystemExit): server.shutdown() --- 261,270 ---- # Main thread terminates, but the server continues running # until server.shutdown() is called. try: ! while server_thread.is_alive(): server_thread.join(1) except (KeyboardInterrupt, SystemExit): server.shutdown() + + if __name__ == "__main__": + main("localhost", 0) *** ../vim-8.2.0556/src/testdir/test_channel.vim 2020-04-08 21:50:18.872619665 +0200 --- src/testdir/test_channel.vim 2020-04-12 17:32:54.431547820 +0200 *************** *** 18,28 **** " Add ch_log() calls where you want to see what happens. " call ch_logfile('channellog', 'w') ! let s:chopt = {} " Run "testfunc" after starting the server and stop the server afterwards. func s:run_server(testfunc, ...) ! call RunServer('test_channel.py', a:testfunc, a:000) " communicating with a server can be flaky let g:test_is_flaky = 1 --- 18,38 ---- " Add ch_log() calls where you want to see what happens. " call ch_logfile('channellog', 'w') ! func SetUp() ! if g:testfunc =~ '_ipv6()$' ! let s:localhost = '[::1]:' ! let s:testscript = 'test_channel_6.py' ! else ! let s:localhost = 'localhost:' ! let s:testscript = 'test_channel.py' ! endif ! let s:chopt = {} ! call ch_log(g:testfunc) ! endfunc " Run "testfunc" after starting the server and stop the server afterwards. func s:run_server(testfunc, ...) ! call RunServer(s:testscript, a:testfunc, a:000) " communicating with a server can be flaky let g:test_is_flaky = 1 *************** *** 54,62 **** let s:chopt.drop = 'never' " Also add the noblock flag to try it out. let s:chopt.noblock = 1 ! let handle = ch_open('localhost:' . a:port, s:chopt) ! unlet s:chopt.drop ! unlet s:chopt.noblock if ch_status(handle) == "fail" call assert_report("Can't open channel") return --- 64,70 ---- let s:chopt.drop = 'never' " Also add the noblock flag to try it out. let s:chopt.noblock = 1 ! let handle = ch_open(s:localhost . a:port, s:chopt) if ch_status(handle) == "fail" call assert_report("Can't open channel") return *************** *** 224,236 **** endfunc func Test_communicate() - call ch_log('Test_communicate()') call s:run_server('Ch_communicate') endfunc " Test that we can open two channels. func Ch_two_channels(port) ! let handle = ch_open('localhost:' . a:port, s:chopt) call assert_equal(v:t_channel, type(handle)) if handle->ch_status() == "fail" call assert_report("Can't open channel") --- 232,248 ---- endfunc func Test_communicate() call s:run_server('Ch_communicate') endfunc + func Test_communicate_ipv6() + CheckIPv6 + call Test_communicate() + endfunc + " Test that we can open two channels. func Ch_two_channels(port) ! let handle = ch_open(s:localhost . a:port, s:chopt) call assert_equal(v:t_channel, type(handle)) if handle->ch_status() == "fail" call assert_report("Can't open channel") *************** *** 239,245 **** call assert_equal('got it', ch_evalexpr(handle, 'hello!')) ! let newhandle = ch_open('localhost:' . a:port, s:chopt) if ch_status(newhandle) == "fail" call assert_report("Can't open second channel") return --- 251,257 ---- call assert_equal('got it', ch_evalexpr(handle, 'hello!')) ! let newhandle = ch_open(s:localhost . a:port, s:chopt) if ch_status(newhandle) == "fail" call assert_report("Can't open second channel") return *************** *** 259,267 **** call s:run_server('Ch_two_channels') endfunc " Test that a server crash is handled gracefully. func Ch_server_crash(port) ! let handle = ch_open('localhost:' . a:port, s:chopt) if ch_status(handle) == "fail" call assert_report("Can't open channel") return --- 271,284 ---- call s:run_server('Ch_two_channels') endfunc + func Test_two_channels_ipv6() + CheckIPv6 + call Test_two_channels() + endfunc + " Test that a server crash is handled gracefully. func Ch_server_crash(port) ! let handle = ch_open(s:localhost . a:port, s:chopt) if ch_status(handle) == "fail" call assert_report("Can't open channel") return *************** *** 273,282 **** endfunc func Test_server_crash() - call ch_log('Test_server_crash()') call s:run_server('Ch_server_crash') endfunc """"""""" func Ch_handler(chan, msg) --- 290,303 ---- endfunc func Test_server_crash() call s:run_server('Ch_server_crash') endfunc + func Test_server_crash_ipv6() + CheckIPv6 + call Test_server_crash() + endfunc + """"""""" func Ch_handler(chan, msg) *************** *** 286,292 **** endfunc func Ch_channel_handler(port) ! let handle = ch_open('localhost:' . a:port, s:chopt) if ch_status(handle) == "fail" call assert_report("Can't open channel") return --- 307,313 ---- endfunc func Ch_channel_handler(port) ! let handle = ch_open(s:localhost . a:port, s:chopt) if ch_status(handle) == "fail" call assert_report("Can't open channel") return *************** *** 302,315 **** endfunc func Test_channel_handler() - call ch_log('Test_channel_handler()') let g:Ch_reply = "" let s:chopt.callback = 'Ch_handler' call s:run_server('Ch_channel_handler') let g:Ch_reply = "" let s:chopt.callback = function('Ch_handler') call s:run_server('Ch_channel_handler') ! unlet s:chopt.callback endfunc """"""""" --- 323,339 ---- endfunc func Test_channel_handler() let g:Ch_reply = "" let s:chopt.callback = 'Ch_handler' call s:run_server('Ch_channel_handler') let g:Ch_reply = "" let s:chopt.callback = function('Ch_handler') call s:run_server('Ch_channel_handler') ! endfunc ! ! func Test_channel_handler_ipv6() ! CheckIPv6 ! call Test_channel_handler() endfunc """"""""" *************** *** 327,333 **** endfunc func Ch_channel_zero(port) ! let handle = ('localhost:' .. a:port)->ch_open(s:chopt) if ch_status(handle) == "fail" call assert_report("Can't open channel") return --- 351,357 ---- endfunc func Ch_channel_zero(port) ! let handle = (s:localhost .. a:port)->ch_open(s:chopt) if ch_status(handle) == "fail" call assert_report("Can't open channel") return *************** *** 359,365 **** endfunc func Test_zero_reply() - call ch_log('Test_zero_reply()') " Run with channel handler let s:has_handler = 1 let s:chopt.callback = 'Ch_zeroHandler' --- 383,388 ---- *************** *** 371,376 **** --- 394,404 ---- call s:run_server('Ch_channel_zero') endfunc + func Test_zero_reply_ipv6() + CheckIPv6 + call Test_zero_reply() + endfunc + """"""""" let g:Ch_reply1 = "" *************** *** 392,398 **** endfunc func Ch_raw_one_time_callback(port) ! let handle = ch_open('localhost:' . a:port, s:chopt) if ch_status(handle) == "fail" call assert_report("Can't open channel") return --- 420,426 ---- endfunc func Ch_raw_one_time_callback(port) ! let handle = ch_open(s:localhost . a:port, s:chopt) if ch_status(handle) == "fail" call assert_report("Can't open channel") return *************** *** 410,419 **** endfunc func Test_raw_one_time_callback() - call ch_log('Test_raw_one_time_callback()') call s:run_server('Ch_raw_one_time_callback') endfunc """"""""" " Test that trying to connect to a non-existing port fails quickly. --- 438,451 ---- endfunc func Test_raw_one_time_callback() call s:run_server('Ch_raw_one_time_callback') endfunc + func Test_raw_one_time_callback_ipv6() + CheckIPv6 + call Test_raw_one_time_callback() + endfunc + """"""""" " Test that trying to connect to a non-existing port fails quickly. *************** *** 422,428 **** " this is timing sensitive let g:test_is_flaky = 1 - call ch_log('Test_connect_waittime()') let start = reltime() let handle = ch_open('localhost:9876', s:chopt) if ch_status(handle) != "fail" --- 454,459 ---- *************** *** 752,758 **** enew! let test_lines = ['one', 'two'] call setline(1, test_lines) - call ch_log('Test_close_output_buffer()') let options = {'out_io': 'buffer'} let options['out_name'] = 'buffer-output' let options['out_msg'] = 0 --- 783,788 ---- *************** *** 924,940 **** endfunc func Test_pipe_through_sort_all() - call ch_log('Test_pipe_through_sort_all()') call Run_pipe_through_sort(1, 1) endfunc func Test_pipe_through_sort_some() - call ch_log('Test_pipe_through_sort_some()') call Run_pipe_through_sort(0, 1) endfunc func Test_pipe_through_sort_feed() - call ch_log('Test_pipe_through_sort_feed()') call Run_pipe_through_sort(1, 0) endfunc --- 954,967 ---- *************** *** 1341,1356 **** " Test that "unlet handle" in a handler doesn't crash Vim. func Ch_unlet_handle(port) ! let s:channelfd = ch_open('localhost:' . a:port, s:chopt) eval s:channelfd->ch_sendexpr("test", {'callback': function('s:UnletHandler')}) call WaitForAssert({-> assert_equal('what?', g:Ch_unletResponse)}) endfunc func Test_unlet_handle() - call ch_log('Test_unlet_handle()') call s:run_server('Ch_unlet_handle') endfunc """""""""" let g:Ch_unletResponse = '' --- 1368,1387 ---- " Test that "unlet handle" in a handler doesn't crash Vim. func Ch_unlet_handle(port) ! let s:channelfd = ch_open(s:localhost . a:port, s:chopt) eval s:channelfd->ch_sendexpr("test", {'callback': function('s:UnletHandler')}) call WaitForAssert({-> assert_equal('what?', g:Ch_unletResponse)}) endfunc func Test_unlet_handle() call s:run_server('Ch_unlet_handle') endfunc + func Test_unlet_handle_ipv6() + CheckIPv6 + call Test_unlet_handle() + endfunc + """""""""" let g:Ch_unletResponse = '' *************** *** 1361,1367 **** " Test that "unlet handle" in a handler doesn't crash Vim. func Ch_close_handle(port) ! let s:channelfd = ch_open('localhost:' . a:port, s:chopt) call ch_sendexpr(s:channelfd, "test", {'callback': function('Ch_CloseHandler')}) call WaitForAssert({-> assert_equal('what?', g:Ch_unletResponse)}) endfunc --- 1392,1398 ---- " Test that "unlet handle" in a handler doesn't crash Vim. func Ch_close_handle(port) ! let s:channelfd = ch_open(s:localhost . a:port, s:chopt) call ch_sendexpr(s:channelfd, "test", {'callback': function('Ch_CloseHandler')}) call WaitForAssert({-> assert_equal('what?', g:Ch_unletResponse)}) endfunc *************** *** 1370,1375 **** --- 1401,1423 ---- call s:run_server('Ch_close_handle') endfunc + func Test_close_handle_ipv6() + CheckIPv6 + call Test_close_handle() + endfunc + + """""""""" + + func Ch_open_ipv6(port) + let handle = ch_open('[::1]:' .. a:port, s:chopt) + call assert_notequal('fail', ch_status(handle)) + endfunc + + func Test_open_ipv6() + CheckIPv6 + call s:run_server('Ch_open_ipv6') + endfunc + """""""""" func Test_open_fail() *************** *** 1378,1383 **** --- 1426,1432 ---- let d = ch call assert_fails("let ch = ch_open('noserver', 10)", 'E474:') call assert_fails("let ch = ch_open('localhost:-1')", 'E475:') + call assert_fails("let ch = ch_open('localhost:65537')", 'E475:') call assert_fails("let ch = ch_open('localhost:8765', {'timeout' : -1})", \ 'E474:') call assert_fails("let ch = ch_open('localhost:8765', {'axby' : 1})", *************** *** 1386,1391 **** --- 1435,1443 ---- \ 'E475:') call assert_fails("let ch = ch_open('localhost:8765', {'part' : 'out'})", \ 'E475:') + call assert_fails("let ch = ch_open('[::]')", 'E475:') + call assert_fails("let ch = ch_open('[::.80')", 'E475:') + call assert_fails("let ch = ch_open('[::]8080')", 'E475:') endfunc func Test_ch_info_fail() *************** *** 1397,1404 **** func Ch_open_delay(port) " Wait up to a second for the port to open. let s:chopt.waittime = 1000 ! let channel = ch_open('localhost:' . a:port, s:chopt) ! unlet s:chopt.waittime if ch_status(channel) == "fail" call assert_report("Can't open channel") return --- 1449,1455 ---- func Ch_open_delay(port) " Wait up to a second for the port to open. let s:chopt.waittime = 1000 ! let channel = ch_open(s:localhost . a:port, s:chopt) if ch_status(channel) == "fail" call assert_report("Can't open channel") return *************** *** 1412,1417 **** --- 1463,1473 ---- call s:run_server('Ch_open_delay', 'delay') endfunc + func Test_open_delay_ipv6() + CheckIPv6 + call Test_open_delay() + endfunc + """"""""" function MyFunction(a,b,c) *************** *** 1419,1425 **** endfunc function Ch_test_call(port) ! let handle = ch_open('localhost:' . a:port, s:chopt) if ch_status(handle) == "fail" call assert_report("Can't open channel") return --- 1475,1481 ---- endfunc function Ch_test_call(port) ! let handle = ch_open(s:localhost . a:port, s:chopt) if ch_status(handle) == "fail" call assert_report("Can't open channel") return *************** *** 1438,1443 **** --- 1494,1504 ---- call s:run_server('Ch_test_call') endfunc + func Test_call_ipv6() + CheckIPv6 + call Test_call() + endfunc + """"""""" let g:Ch_job_exit_ret = 'not yet' *************** *** 1513,1519 **** endfunc function Ch_test_close_callback(port) ! let handle = ch_open('localhost:' . a:port, s:chopt) if ch_status(handle) == "fail" call assert_report("Can't open channel") return --- 1574,1580 ---- endfunc function Ch_test_close_callback(port) ! let handle = ch_open(s:localhost . a:port, s:chopt) if ch_status(handle) == "fail" call assert_report("Can't open channel") return *************** *** 1528,1535 **** call s:run_server('Ch_test_close_callback') endfunc function Ch_test_close_partial(port) ! let handle = ch_open('localhost:' . a:port, s:chopt) if ch_status(handle) == "fail" call assert_report("Can't open channel") return --- 1589,1601 ---- call s:run_server('Ch_test_close_callback') endfunc + func Test_close_callback_ipv6() + CheckIPv6 + call Test_close_callback() + endfunc + function Ch_test_close_partial(port) ! let handle = ch_open(s:localhost . a:port, s:chopt) if ch_status(handle) == "fail" call assert_report("Can't open channel") return *************** *** 1549,1554 **** --- 1615,1625 ---- call s:run_server('Ch_test_close_partial') endfunc + func Test_close_partial_ipv6() + CheckIPv6 + call Test_close_partial() + endfunc + func Test_job_start_fails() " this was leaking memory call assert_fails("call job_start([''])", "E474:") *************** *** 1808,1814 **** endfunc function Ch_test_close_lambda(port) ! let handle = ch_open('localhost:' . a:port, s:chopt) if ch_status(handle) == "fail" call assert_report("Can't open channel") return --- 1879,1885 ---- endfunc function Ch_test_close_lambda(port) ! let handle = ch_open(s:localhost . a:port, s:chopt) if ch_status(handle) == "fail" call assert_report("Can't open channel") return *************** *** 1824,1829 **** --- 1895,1905 ---- call s:run_server('Ch_test_close_lambda') endfunc + func Test_close_lambda_ipv6() + CheckIPv6 + call Test_close_lambda() + endfunc + func s:test_list_args(cmd, out, remove_lf) try let g:out = '' *** ../vim-8.2.0556/src/testdir/test_channel_6.py 2020-04-12 17:51:56.593689566 +0200 --- src/testdir/test_channel_6.py 2020-04-12 17:32:54.431547820 +0200 *************** *** 0 **** --- 1,15 ---- + #!/usr/bin/env python + # + # Server that will accept connections from a Vim channel. + # Used by test_channel.vim. + # + # This requires Python 2.6 or later. + + from test_channel import main, ThreadedTCPServer + import socket + + class ThreadedTCP6Server(ThreadedTCPServer): + address_family = socket.AF_INET6 + + if __name__ == "__main__": + main("::", 0, ThreadedTCP6Server) *** ../vim-8.2.0556/src/testdir/test_escaped_glob.vim 2019-08-31 19:11:06.000000000 +0200 --- src/testdir/test_escaped_glob.vim 2020-04-12 17:32:54.431547820 +0200 *************** *** 1,7 **** " Test whether glob()/globpath() return correct results with certain escaped " characters. ! function SetUp() " consistent sorting of file names set nofileignorecase endfunction --- 1,7 ---- " Test whether glob()/globpath() return correct results with certain escaped " characters. ! func SetUp() " consistent sorting of file names set nofileignorecase endfunction *** ../vim-8.2.0556/src/testdir/test_getcwd.vim 2019-11-09 18:02:07.000000000 +0100 --- src/testdir/test_getcwd.vim 2020-04-12 17:32:54.431547820 +0200 *************** *** 24,30 **** " Do all test in a separate window to avoid E211 when we recursively " delete the Xtopdir directory during cleanup ! function SetUp() set visualbell set nocp viminfo+=nviminfo --- 24,30 ---- " Do all test in a separate window to avoid E211 when we recursively " delete the Xtopdir directory during cleanup ! func SetUp() set visualbell set nocp viminfo+=nviminfo *** ../vim-8.2.0556/src/testdir/test_hide.vim 2019-08-18 22:52:24.000000000 +0200 --- src/testdir/test_hide.vim 2020-04-12 17:32:54.431547820 +0200 *************** *** 1,6 **** " Tests for :hide command/modifier and 'hidden' option ! function SetUp() let s:save_hidden = &hidden let s:save_bufhidden = &bufhidden let s:save_autowrite = &autowrite --- 1,6 ---- " Tests for :hide command/modifier and 'hidden' option ! func SetUp() let s:save_hidden = &hidden let s:save_bufhidden = &bufhidden let s:save_autowrite = &autowrite *** ../vim-8.2.0556/src/version.c 2020-04-12 17:11:24.091578044 +0200 --- src/version.c 2020-04-12 17:34:08.898980478 +0200 *************** *** 740,741 **** --- 740,743 ---- { /* Add new patch number below this line */ + /**/ + 557, /**/ -- I am always surprised in the Linux world how quickly solutions can be obtained. (Imagine sending an email to Bill Gates, asking why Windows crashed, and how to fix it... and then getting an answer that fixed the problem... <0>_<0> !) -- Mark Langdon /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///