]> granicus.if.org Git - vim/commitdiff
patch 8.2.0557: no IPv6 support for channels v8.2.0557
authorBram Moolenaar <Bram@vim.org>
Sun, 12 Apr 2020 15:53:12 +0000 (17:53 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 12 Apr 2020 15:53:12 +0000 (17:53 +0200)
Problem:    No IPv6 support for channels.
Solution:   Add IPv6 support. (Ozaki Kiichi, closes #5893)

21 files changed:
.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 [new file with mode: 0644]
src/testdir/test_escaped_glob.vim
src/testdir/test_getcwd.vim
src/testdir/test_hide.vim
src/version.c

index 356702cdfcfb21d6dfba35770df7030df36faab5..2c5f5ff304492b23817d00ba54414ccc1c99e00f 100644 (file)
@@ -62,9 +62,7 @@ _anchors:
           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 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) '$*'"; }
index 3fa05083cbb2ab044e8ebc786f63e22f4a00deec..42e00c7ae7ef75c6460a25d8813954bd71749a38 100644 (file)
@@ -120,6 +120,9 @@ Use |ch_status()| to see if the channel could be opened.
 
 {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,6 +624,9 @@ ch_open({address} [, {options}])                            *ch_open()*
                {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|.
 
index b6867bcabd77846fdae424024bb7ee5cdf6c1cbb..a88cc81cc16ab4d80e157649f91c34032ec96770 100644 (file)
@@ -375,6 +375,7 @@ m  *+hangul_input*  Hangul input support |hangul|
    *+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'|
index 86986482aebe2e5c8663c59eb46e55d8a8009742..091102e661df4097f79e7101066e0236054636e7 100644 (file)
@@ -850,7 +850,7 @@ endif
 
 ifeq ($(CHANNEL),yes)
 OBJ += $(OUTDIR)/channel.o
-LIB += -lwsock32
+LIB += -lwsock32 -lws2_32
 endif
 
 ifeq ($(DIRECTX),yes)
index 1d7a3ed112a874d9908e75c9b892a1e448528b8c..fa14c9e646649ad3eade4e4663225050da9b8f7a 100644 (file)
@@ -469,7 +469,7 @@ CHANNEL_PRO = proto/channel.pro
 CHANNEL_OBJ    = $(OBJDIR)/channel.obj
 CHANNEL_DEFS   = -DFEAT_JOB_CHANNEL
 
-NETBEANS_LIB   = WSock32.lib
+NETBEANS_LIB   = WSock32.lib Ws2_32.lib
 !endif
 
 # Set which version of the CRT to use
index 0a140eed8be445320f81c2bdb981e3fdf83205c8..33bf663224f81dcca8f0fb6fcb58b7a4e04c401e 100755 (executable)
@@ -7723,8 +7723,7 @@ $as_echo "yes" >&6; }
 fi
 
 if test "$enable_channel" = "yes"; then
-
-  if test "x$HAIKU" = "xyes"; 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,7 +7817,63 @@ fi
 
   fi
 
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5
+  { $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 <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+       /* 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,8 +7918,11 @@ _ACEOF
 
 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; }
+    { $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,15 +7958,17 @@ main ()
 }
 _ACEOF
 if ac_fn_c_try_link "$LINENO"; then :
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+  vim_cv_ipv4_networking="yes"
 else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }; enable_netbeans="no"; enable_channel="no"
+  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
 
index 1dfb28f85468a534d554314dc23979e4642a4565..8f15c659bfcc9398e29a01cd0df6bd2a680e5bc2 100644 (file)
  * 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 <winsock2.h>
+# include <ws2tcpip.h>
+#endif
+
 #include "vim.h"
 
 #if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
@@ -40,7 +47,7 @@
 #else
 # include <netdb.h>
 # include <netinet/in.h>
-
+# include <arpa/inet.h>
 # include <sys/socket.h>
 # ifdef HAVE_LIBGEN_H
 #  include <libgen.h>
@@ -711,90 +718,38 @@ channel_gui_unregister(channel_T *channel)
 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.
+ * For Unix we need to call connect() again after connect() failed.
+ * On Win32 one time is sufficient.
  */
-    channel_T *
-channel_open(
-       char *hostname,
-       int port_in,
-       int waittime,
-       void (*nb_close_cb)(void))
+    static int
+channel_connect(
+       channel_T *channel,
+       const struct sockaddr *server_addr,
+       int server_addrlen,
+       int *waittime)
 {
-    int                        sd = -1;
-    struct sockaddr_in server;
-    struct hostent     *host;
+    int                sd = -1;
 #ifdef MSWIN
-    u_short            port = port_in;
-    u_long             val = 1;
-#else
-    int                        port = port_in;
+    u_long     val = 1;
 #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;
+       int     ret;
 
        if (sd >= 0)
            sock_close(sd);
-       sd = socket(AF_INET, SOCK_STREAM, 0);
+       sd = socket(server_addr->sa_family, 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;
+           ch_error(channel, "in socket() in channel_connect().");
+           PERROR(_("E898: socket() in channel_connect()"));
+           return -1;
        }
 
-       if (waittime >= 0)
+       if (*waittime >= 0)
        {
            // Make connect() non-blocking.
            if (
@@ -807,23 +762,22 @@ channel_open(
            {
                SOCK_ERRNO;
                ch_error(channel,
-                        "channel_open: Connect failed with errno %d", errno);
+                     "channel_connect: Connect failed with errno %d", errno);
                sock_close(sd);
-               channel_free(channel);
-               return NULL;
+               return -1;
            }
        }
 
        // Try connecting to the server.
-       ch_log(channel, "Connecting to %s port %d", hostname, port);
-       ret = connect(sd, (struct sockaddr *)&server, sizeof(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
+       if (*waittime < 0 || (errno != EWOULDBLOCK
                && errno != ECONNREFUSED
 #ifdef EINPROGRESS
                && errno != EINPROGRESS
@@ -831,22 +785,24 @@ channel_open(
                ))
        {
            ch_error(channel,
-                        "channel_open: Connect failed with errno %d", errno);
+                     "channel_connect: Connect failed with errno %d", errno);
            PERROR(_(e_cannot_connect));
            sock_close(sd);
-           channel_free(channel);
-           return NULL;
+           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;
+       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;
@@ -868,18 +824,17 @@ channel_open(
            gettimeofday(&start_tv, NULL);
 #endif
            ch_log(channel,
-                   "Waiting for connection (waiting %d msec)...", waitnow);
-           ret = select((int)sd + 1, &rfds, &wfds, NULL, &tv);
+                     "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);
+                     "channel_connect: Connect failed with errno %d", errno);
                PERROR(_(e_cannot_connect));
                sock_close(sd);
-               channel_free(channel);
-               return NULL;
+               return -1;
            }
 
 #ifdef MSWIN
@@ -888,9 +843,9 @@ channel_open(
            if (FD_ISSET(sd, &wfds))
                break;
            elapsed_msec = waitnow;
-           if (waittime > 1 && elapsed_msec < waittime)
+           if (*waittime > 1 && elapsed_msec < *waittime)
            {
-               waittime -= elapsed_msec;
+               *waittime -= elapsed_msec;
                continue;
            }
 #else
@@ -914,12 +869,17 @@ channel_open(
                        ))
                {
                    ch_error(channel,
-                           "channel_open: Connect failed with errno %d",
+                           "channel_connect: Connect failed with errno %d",
                            so_error);
                    PERROR(_(e_cannot_connect));
                    sock_close(sd);
-                   channel_free(channel);
-                   return NULL;
+                   return -1;
+               }
+               else if (errno == ECONNREFUSED)
+               {
+                   ch_error(channel, "channel_connect: Connection refused");
+                   sock_close(sd);
+                   return -1;
                }
            }
 
@@ -929,30 +889,30 @@ channel_open(
 
            gettimeofday(&end_tv, NULL);
            elapsed_msec = (end_tv.tv_sec - start_tv.tv_sec) * 1000
-                            + (end_tv.tv_usec - start_tv.tv_usec) / 1000;
+                                + (end_tv.tv_usec - start_tv.tv_usec) / 1000;
 #endif
        }
 
 #ifndef MSWIN
-       if (waittime > 1 && elapsed_msec < waittime)
+       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;
+           *waittime -= elapsed_msec;
            if (waitnow > 0)
            {
                mch_delay((long)waitnow, TRUE);
                ui_breakcheck();
-               waittime -= waitnow;
+               *waittime -= waitnow;
            }
            if (!got_int)
            {
-               if (waittime <= 0)
+               if (*waittime <= 0)
                    // give it one more try
-                   waittime = 1;
+                   *waittime = 1;
                continue;
            }
            // we were interrupted, behave as if timed out
@@ -962,13 +922,10 @@ channel_open(
        // We timed out.
        ch_error(channel, "Connection timed out");
        sock_close(sd);
-       channel_free(channel);
-       return NULL;
+       return -1;
     }
 
-    ch_log(channel, "Connection made");
-
-    if (waittime >= 0)
+    if (*waittime >= 0)
     {
 #ifdef MSWIN
        val = 0;
@@ -978,10 +935,151 @@ channel_open(
 #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_in;
+    channel->ch_port = port;
     channel->ch_to_be_closed |= (1U << PART_SOCK);
 
 #ifdef FEAT_GUI
@@ -1222,6 +1320,7 @@ channel_open_func(typval_T *argvars)
     char_u     *p;
     char       *rest;
     int                port;
+    int                is_ipv6 = FALSE;
     jobopt_T    opt;
     channel_T  *channel = NULL;
 
@@ -1234,20 +1333,40 @@ channel_open_func(typval_T *argvars)
     }
 
     // parse address
-    p = vim_strchr(address, ':');
-    if (p == NULL)
+    if (*address == '[')
     {
-       semsg(_(e_invarg2), address);
-       return NULL;
+       // ipv6 address
+       is_ipv6 = TRUE;
+       p = vim_strchr(address + 1, ']');
+       if (p == NULL || *++p != ':')
+       {
+           semsg(_(e_invarg2), address);
+           return NULL;
+       }
     }
-    *p++ = NUL;
-    port = strtol((char *)p, &rest, 10);
-    if (*address == NUL || port <= 0 || *rest != NUL)
+    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)
     {
-       p[-1] = ':';
        semsg(_(e_invarg2), address);
        return NULL;
     }
+    if (is_ipv6)
+    {
+       // strip '[' and ']'
+       ++address;
+       *(p - 1) = NUL;
+    }
+    else
+       *p = NUL;
 
     // parse options
     clear_job_options(&opt);
index deeceb7a94713932233275e249713667514b3a5f..166724c9169f36fb6ef40daea6bd1eb66d971ca7 100644 (file)
 /* 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
 
index 89ae06f739fff9176b5f2f9246661903c5121bea..47502a99c40571309543e61380419529d0998ad2 100644 (file)
@@ -2038,17 +2038,50 @@ else
 fi
 
 if test "$enable_channel" = "yes"; then
-  dnl On Solaris we need the socket and nsl library.
-
+  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_CHECK_LIB(nsl, gethostbyname)
-  AC_MSG_CHECKING(whether compiling with process communication is possible)
-  AC_TRY_LINK([
+  AC_CACHE_CHECK([whether compiling with IPv6 networking is possible], [vim_cv_ipv6_networking],
+    [AC_TRY_LINK([
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+       /* 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 <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
@@ -2072,8 +2105,9 @@ if test "$enable_channel" = "yes"; then
                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")
+       [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)
index 7170c0e1fe676381234df67071f6f04f3362f9f3..8ce8c8751d38bcb2e723d9c895cdab647608e8bd 100644 (file)
@@ -3943,6 +3943,13 @@ f_has(typval_T *argvars, typval_T *rettv)
 #endif
                },
        {"insert_expand", 1},
+       {"ipv6",
+#ifdef FEAT_IPV6
+               1
+#else
+               0
+#endif
+       },
        {"job",
 #ifdef FEAT_JOB_CHANNEL
                1
index a441a484f45dc8c7d87556c8a13e3a69627a8aee..56a0167b823ce9db54d40c446545325d0cb41c28 100644 (file)
@@ -7,7 +7,7 @@ int channel_unref(channel_T *channel);
 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));
+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);
index 34bf5b319d2554d15b6444f3824cfe4856d0d339..efb273b005ddf4a1bff75bfdb252f4e666a4039a 100644 (file)
@@ -142,4 +142,37 @@ func CheckEnglish()
   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') =~? '\<Loopback\>'
+  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') =~? '\<inet6\>'
+            \ || system('ifconfig ' .. dev .. ' 2>/dev/null') =~? '\<inet6\>'
+        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
index 0d603231aa41358cedb433692847963e7d61b7d7..3e7e5115f4bba03b4d83baf626ad3298321a23ce 100644 (file)
@@ -161,8 +161,7 @@ func RunTheTest(test)
     exe 'call ' . a:test
   else
     try
-      let s:test = a:test
-      au VimLeavePre * call EarlyExit(s:test)
+      au VimLeavePre * call EarlyExit(g:testfunc)
       exe 'call ' . a:test
       au! VimLeavePre
     catch /^\cskipped/
@@ -226,11 +225,11 @@ func AfterTheTest(func_name)
   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 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 ' . s:test . ':')
+      call add(s:errors, 'Found errors in ' . g:testfunc . ':')
       call extend(s:errors, v:errors)
     endif
     let v:errors = []
@@ -396,31 +395,31 @@ endif
 
 let s:may_fail_list = []
 if $TEST_MAY_FAIL != ''
-  " Split the list at commas and add () to make it match s:test.
+  " 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 s:test in sort(s:tests)
+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 test_is_flaky to retry running the test.
-  let test_is_flaky = 0
+  " A test can set g:test_is_flaky to retry running the test.
+  let g:test_is_flaky = 0
 
-  call RunTheTest(s:test)
+  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, s:test) >= 0
-        \      || test_is_flaky)
+        \ && (index(s:flaky_tests, g:testfunc) >= 0
+        \      || g:test_is_flaky)
     while 1
-      call add(s:messages, 'Found errors in ' . s:test . ':')
+      call add(s:messages, 'Found errors in ' . g:testfunc . ':')
       call extend(s:messages, v:errors)
 
       call add(total_errors, 'Run ' . g:run_nr . ':')
@@ -443,7 +442,7 @@ for s:test in sort(s:tests)
       let v:errors = []
       let g:run_nr += 1
 
-      call RunTheTest(s:test)
+      call RunTheTest(g:testfunc)
 
       if len(v:errors) == 0
         " Test passed on rerun.
@@ -452,7 +451,7 @@ for s:test in sort(s:tests)
     endwhile
   endif
 
-  call AfterTheTest(s:test)
+  call AfterTheTest(g:testfunc)
 endfor
 
 call FinishTesting()
index 8a6b7467182f21a5f7283f1a00f7c4372a06dbe4..51800a5e6b3be51291f9026a5bb4a915481c766d 100644 (file)
@@ -4,7 +4,7 @@ source check.vim
 CheckFeature quickfix
 
 " Create the files used by the tests
-function SetUp()
+func SetUp()
   call writefile(["Line1", "Line2", "Line3"], 'Xtestfile1')
   call writefile(["Line1", "Line2", "Line3"], 'Xtestfile2')
   call writefile(["Line1", "Line2", "Line3"], 'Xtestfile3')
index bafa9dbf765c6c297a50717853481df7ce9de1e7..6b2947d904a12699c53f85fd20cfcef2e48e9a84 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 #
 # Server that will accept connections from a Vim channel.
 # Used by test_channel.vim.
@@ -235,21 +235,19 @@ def writePortInFile(port):
     f.write("{0}".format(port))
     f.close()
 
-if __name__ == "__main__":
-    HOST, PORT = "localhost", 0
-
+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)
+        port = 13684
+        writePortInFile(port)
 
         print("Wait for it...")
         time.sleep(0.5)
 
-    server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
-    ip, port = server.server_address
+    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,7 +261,10 @@ if __name__ == "__main__":
     # Main thread terminates, but the server continues running
     # until server.shutdown() is called.
     try:
-        while server_thread.isAlive(): 
+        while server_thread.is_alive():
             server_thread.join(1)
     except (KeyboardInterrupt, SystemExit):
         server.shutdown()
+
+if __name__ == "__main__":
+    main("localhost", 0)
index 0cabd5c1aff9cec95f395717dd4b20d24a3338c5..11f33628d8ff415cc9fb65c611050ef8ab56dcf2 100644 (file)
@@ -18,11 +18,21 @@ endif
 " Add ch_log() calls where you want to see what happens.
 " call ch_logfile('channellog', 'w')
 
-let s:chopt = {}
+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('test_channel.py', a:testfunc, a:000)
+  call RunServer(s:testscript, a:testfunc, a:000)
 
   " communicating with a server can be flaky
   let g:test_is_flaky = 1
@@ -54,9 +64,7 @@ func Ch_communicate(port)
   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
+  let handle = ch_open(s:localhost . a:port, s:chopt)
   if ch_status(handle) == "fail"
     call assert_report("Can't open channel")
     return
@@ -224,13 +232,17 @@ func Ch_communicate(port)
 endfunc
 
 func Test_communicate()
-  call ch_log('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('localhost:' . a:port, s:chopt)
+  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,7 +251,7 @@ func Ch_two_channels(port)
 
   call assert_equal('got it', ch_evalexpr(handle, 'hello!'))
 
-  let newhandle = ch_open('localhost:' . a:port, s:chopt)
+  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,9 +271,14 @@ func Test_two_channels()
   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('localhost:' . a:port, s:chopt)
+  let handle = ch_open(s:localhost . a:port, s:chopt)
   if ch_status(handle) == "fail"
     call assert_report("Can't open channel")
     return
@@ -273,10 +290,14 @@ func Ch_server_crash(port)
 endfunc
 
 func Test_server_crash()
-  call ch_log('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,7 +307,7 @@ func Ch_handler(chan, msg)
 endfunc
 
 func Ch_channel_handler(port)
-  let handle = ch_open('localhost:' . a:port, s:chopt)
+  let handle = ch_open(s:localhost . a:port, s:chopt)
   if ch_status(handle) == "fail"
     call assert_report("Can't open channel")
     return
@@ -302,14 +323,17 @@ func Ch_channel_handler(port)
 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
+
+func Test_channel_handler_ipv6()
+  CheckIPv6
+  call Test_channel_handler()
 endfunc
 
 """""""""
@@ -327,7 +351,7 @@ func Ch_oneHandler(chan, msg)
 endfunc
 
 func Ch_channel_zero(port)
-  let handle = ('localhost:' .. a:port)->ch_open(s:chopt)
+  let handle = (s:localhost .. a:port)->ch_open(s:chopt)
   if ch_status(handle) == "fail"
     call assert_report("Can't open channel")
     return
@@ -359,7 +383,6 @@ func Ch_channel_zero(port)
 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'
@@ -371,6 +394,11 @@ func Test_zero_reply()
   call s:run_server('Ch_channel_zero')
 endfunc
 
+func Test_zero_reply_ipv6()
+  CheckIPv6
+  call Test_zero_reply()
+endfunc
+
 """""""""
 
 let g:Ch_reply1 = ""
@@ -392,7 +420,7 @@ func Ch_handleRaw3(chan, msg)
 endfunc
 
 func Ch_raw_one_time_callback(port)
-  let handle = ch_open('localhost:' . a:port, s:chopt)
+  let handle = ch_open(s:localhost . a:port, s:chopt)
   if ch_status(handle) == "fail"
     call assert_report("Can't open channel")
     return
@@ -410,10 +438,14 @@ func Ch_raw_one_time_callback(port)
 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
 
+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,7 +454,6 @@ func Test_connect_waittime()
   " 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"
@@ -752,7 +783,6 @@ func Test_close_output_buffer()
   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
@@ -924,17 +954,14 @@ func Run_pipe_through_sort(all, use_buffer)
 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
 
@@ -1341,16 +1368,20 @@ endfunc
 
 " 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)
+  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 ch_log('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,7 +1392,7 @@ endfunc
 
 " 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)
+  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,6 +1401,23 @@ func Test_close_handle()
   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,6 +1426,7 @@ func Test_open_fail()
   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,6 +1435,9 @@ func Test_open_fail()
         \ '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,8 +1449,7 @@ endfunc
 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
+  let channel = ch_open(s:localhost . a:port, s:chopt)
   if ch_status(channel) == "fail"
     call assert_report("Can't open channel")
     return
@@ -1412,6 +1463,11 @@ func Test_open_delay()
   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,7 +1475,7 @@ function MyFunction(a,b,c)
 endfunc
 
 function Ch_test_call(port)
-  let handle = ch_open('localhost:' . a:port, s:chopt)
+  let handle = ch_open(s:localhost . a:port, s:chopt)
   if ch_status(handle) == "fail"
     call assert_report("Can't open channel")
     return
@@ -1438,6 +1494,11 @@ func Test_call()
   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,7 +1574,7 @@ function MyCloseCb(ch)
 endfunc
 
 function Ch_test_close_callback(port)
-  let handle = ch_open('localhost:' . a:port, s:chopt)
+  let handle = ch_open(s:localhost . a:port, s:chopt)
   if ch_status(handle) == "fail"
     call assert_report("Can't open channel")
     return
@@ -1528,8 +1589,13 @@ func Test_close_callback()
   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('localhost:' . a:port, s:chopt)
+  let handle = ch_open(s:localhost . a:port, s:chopt)
   if ch_status(handle) == "fail"
     call assert_report("Can't open channel")
     return
@@ -1549,6 +1615,11 @@ func Test_close_partial()
   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,7 +1879,7 @@ func Test_cwd()
 endfunc
 
 function Ch_test_close_lambda(port)
-  let handle = ch_open('localhost:' . a:port, s:chopt)
+  let handle = ch_open(s:localhost . a:port, s:chopt)
   if ch_status(handle) == "fail"
     call assert_report("Can't open channel")
     return
@@ -1824,6 +1895,11 @@ func Test_close_lambda()
   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 = ''
diff --git a/src/testdir/test_channel_6.py b/src/testdir/test_channel_6.py
new file mode 100644 (file)
index 0000000..5bd17a3
--- /dev/null
@@ -0,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)
index da5963e7c7da5b54d66d201421569745e52b7f7e..4b580acbb70984a54380dc426ba6cf3e2a498b7b 100644 (file)
@@ -1,7 +1,7 @@
 " Test whether glob()/globpath() return correct results with certain escaped
 " characters.
 
-function SetUp()
+func SetUp()
   " consistent sorting of file names
   set nofileignorecase
 endfunction
index e87f693c2caecaaf32c7ba20f1e8e62e68565f19..78f9df6623c1d5b68e1fb4d98557b0a6e0f4357e 100644 (file)
@@ -24,7 +24,7 @@ endfunc
 
 " Do all test in a separate window to avoid E211 when we recursively
 " delete the Xtopdir directory during cleanup
-function SetUp()
+func SetUp()
   set visualbell
   set nocp viminfo+=nviminfo
 
index 41b1a4ad7c392e85c0c5ee45d9cb807a69c110e1..b3ce39552395a751948831104672ac7df0227107 100644 (file)
@@ -1,6 +1,6 @@
 " Tests for :hide command/modifier and 'hidden' option
 
-function SetUp()
+func SetUp()
   let s:save_hidden = &hidden
   let s:save_bufhidden = &bufhidden
   let s:save_autowrite = &autowrite
index 7095794e1b006b7208d17bc4b9579b3f700891d2..f1e274ba1922227e571555454e8083ec16eab49e 100644 (file)
@@ -738,6 +738,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    557,
 /**/
     556,
 /**/