patch 8.2.0557: no IPv6 support for channels

Problem:    No IPv6 support for channels.
Solution:   Add IPv6 support. (Ozaki Kiichi, closes #5893)
diff --git a/src/testdir/check.vim b/src/testdir/check.vim
index 34bf5b3..efb273b 100644
--- a/src/testdir/check.vim
+++ b/src/testdir/check.vim
@@ -142,4 +142,37 @@
   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
diff --git a/src/testdir/runtest.vim b/src/testdir/runtest.vim
index 0d60323..3e7e511 100644
--- a/src/testdir/runtest.vim
+++ b/src/testdir/runtest.vim
@@ -161,8 +161,7 @@
     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 @@
   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 @@
 
 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 @@
       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 @@
     endwhile
   endif
 
-  call AfterTheTest(s:test)
+  call AfterTheTest(g:testfunc)
 endfor
 
 call FinishTesting()
diff --git a/src/testdir/test_cdo.vim b/src/testdir/test_cdo.vim
index 8a6b746..51800a5 100644
--- a/src/testdir/test_cdo.vim
+++ b/src/testdir/test_cdo.vim
@@ -4,7 +4,7 @@
 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')
diff --git a/src/testdir/test_channel.py b/src/testdir/test_channel.py
index bafa9db..6b2947d 100644
--- a/src/testdir/test_channel.py
+++ b/src/testdir/test_channel.py
@@ -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 @@
     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 @@
     # 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)
diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim
index 0cabd5c..11f3362 100644
--- a/src/testdir/test_channel.vim
+++ b/src/testdir/test_channel.vim
@@ -18,11 +18,21 @@
 " 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 @@
   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 @@
 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 @@
 
   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 @@
   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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
   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 @@
 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 @@
 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 @@
   " 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 @@
   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 @@
 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 @@
 
 " 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 @@
 
 " 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 @@
   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 @@
   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 @@
         \ '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 @@
 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 @@
   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 @@
 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 @@
   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 @@
 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 @@
   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 @@
   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 @@
 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 @@
   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
index 0000000..5bd17a3
--- /dev/null
+++ b/src/testdir/test_channel_6.py
@@ -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)
diff --git a/src/testdir/test_escaped_glob.vim b/src/testdir/test_escaped_glob.vim
index da5963e..4b580ac 100644
--- a/src/testdir/test_escaped_glob.vim
+++ b/src/testdir/test_escaped_glob.vim
@@ -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
diff --git a/src/testdir/test_getcwd.vim b/src/testdir/test_getcwd.vim
index e87f693..78f9df6 100644
--- a/src/testdir/test_getcwd.vim
+++ b/src/testdir/test_getcwd.vim
@@ -24,7 +24,7 @@
 
 " 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
 
diff --git a/src/testdir/test_hide.vim b/src/testdir/test_hide.vim
index 41b1a4a..b3ce395 100644
--- a/src/testdir/test_hide.vim
+++ b/src/testdir/test_hide.vim
@@ -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