forked from aniani/vim
patch 8.2.4684: cannot open a channel on a Unix domain socket
Problem: Cannot open a channel on a Unix domain socket. Solution: Add Unix domain socket support. (closes #10062)
This commit is contained in:
@@ -119,10 +119,13 @@ To open a channel: >
|
||||
|
||||
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".
|
||||
*channel-address*
|
||||
{address} can be a domain name or an IP address, followed by a port number, or
|
||||
a Unix-domain socket path prefixed by "unix:". E.g. >
|
||||
www.example.com:80 " domain + port
|
||||
127.0.0.1:1234 " IPv4 + port
|
||||
[2001:db8::1]:8765 " IPv6 + port
|
||||
unix:/tmp/my-socket " Unix-domain socket path
|
||||
|
||||
{options} is a dictionary with optional entries: *channel-open-options*
|
||||
|
||||
@@ -579,10 +582,15 @@ ch_info({handle}) *ch_info()*
|
||||
When opened with ch_open():
|
||||
"hostname" the hostname of the address
|
||||
"port" the port of the address
|
||||
"path" the path of the Unix-domain socket
|
||||
"sock_status" "open" or "closed"
|
||||
"sock_mode" "NL", "RAW", "JSON" or "JS"
|
||||
"sock_io" "socket"
|
||||
"sock_timeout" timeout in msec
|
||||
|
||||
Note that "pair" is only present for Unix-domain sockets, for
|
||||
regular ones "hostname" and "port" are present instead.
|
||||
|
||||
When opened with job_start():
|
||||
"out_status" "open", "buffered" or "closed"
|
||||
"out_mode" "NL", "RAW", "JSON" or "JS"
|
||||
@@ -641,11 +649,8 @@ ch_open({address} [, {options}]) *ch_open()*
|
||||
Open a channel to {address}. See |channel|.
|
||||
Returns a Channel. Use |ch_status()| to check for failure.
|
||||
|
||||
{address} is a String and 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".
|
||||
{address} is a String, see |channel-address| for the possible
|
||||
accepted forms.
|
||||
|
||||
If {options} is given it must be a |Dictionary|.
|
||||
See |channel-open-options|.
|
||||
|
132
src/channel.c
132
src/channel.c
@@ -44,11 +44,18 @@
|
||||
# define sock_write(sd, buf, len) send((SOCKET)sd, buf, len, 0)
|
||||
# define sock_read(sd, buf, len) recv((SOCKET)sd, buf, len, 0)
|
||||
# define sock_close(sd) closesocket((SOCKET)sd)
|
||||
// Support for Unix-domain sockets was added in Windows SDK 17061.
|
||||
# define UNIX_PATH_MAX 108
|
||||
typedef struct sockaddr_un {
|
||||
ADDRESS_FAMILY sun_family;
|
||||
char sun_path[UNIX_PATH_MAX];
|
||||
} SOCKADDR_UN, *PSOCKADDR_UN;
|
||||
#else
|
||||
# include <netdb.h>
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/inet.h>
|
||||
# include <sys/socket.h>
|
||||
# include <sys/un.h>
|
||||
# ifdef HAVE_LIBGEN_H
|
||||
# include <libgen.h>
|
||||
# endif
|
||||
@@ -928,6 +935,67 @@ channel_connect(
|
||||
return sd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open a socket channel to the UNIX socket at "path".
|
||||
* Returns the channel for success.
|
||||
* Returns NULL for failure.
|
||||
*/
|
||||
static channel_T *
|
||||
channel_open_unix(
|
||||
const char *path,
|
||||
void (*nb_close_cb)(void))
|
||||
{
|
||||
channel_T *channel = NULL;
|
||||
int sd = -1;
|
||||
size_t path_len = STRLEN(path);
|
||||
struct sockaddr_un server;
|
||||
size_t server_len;
|
||||
int waittime = -1;
|
||||
|
||||
if (*path == NUL || path_len >= sizeof(server.sun_path))
|
||||
{
|
||||
semsg(_(e_invalid_argument_str), path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
channel = add_channel();
|
||||
if (channel == NULL)
|
||||
{
|
||||
ch_error(NULL, "Cannot allocate channel.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CLEAR_FIELD(server);
|
||||
server.sun_family = AF_UNIX;
|
||||
STRNCPY(server.sun_path, path, sizeof(server.sun_path) - 1);
|
||||
|
||||
ch_log(channel, "Trying to connect to %s", path);
|
||||
|
||||
server_len = offsetof(struct sockaddr_un, sun_path) + path_len + 1;
|
||||
sd = channel_connect(channel, (struct sockaddr *)&server, (int)server_len,
|
||||
&waittime);
|
||||
|
||||
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 *)path);
|
||||
channel->ch_port = 0;
|
||||
channel->ch_to_be_closed |= (1U << PART_SOCK);
|
||||
|
||||
#ifdef FEAT_GUI
|
||||
channel_gui_register_one(channel, PART_SOCK);
|
||||
#endif
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open a socket channel to "hostname":"port".
|
||||
* "waittime" is the time in msec to wait for the connection.
|
||||
@@ -1301,8 +1369,9 @@ channel_open_func(typval_T *argvars)
|
||||
char_u *address;
|
||||
char_u *p;
|
||||
char *rest;
|
||||
int port;
|
||||
int port = 0;
|
||||
int is_ipv6 = FALSE;
|
||||
int is_unix = FALSE;
|
||||
jobopt_T opt;
|
||||
channel_T *channel = NULL;
|
||||
|
||||
@@ -1319,8 +1388,18 @@ channel_open_func(typval_T *argvars)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// parse address
|
||||
if (*address == '[')
|
||||
if (*address == NUL)
|
||||
{
|
||||
semsg(_(e_invalid_argument_str), address);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!STRNCMP(address, "unix:", 5))
|
||||
{
|
||||
is_unix = TRUE;
|
||||
address += 5;
|
||||
}
|
||||
else if (*address == '[')
|
||||
{
|
||||
// ipv6 address
|
||||
is_ipv6 = TRUE;
|
||||
@@ -1333,6 +1412,7 @@ channel_open_func(typval_T *argvars)
|
||||
}
|
||||
else
|
||||
{
|
||||
// ipv4 address
|
||||
p = vim_strchr(address, ':');
|
||||
if (p == NULL)
|
||||
{
|
||||
@@ -1340,27 +1420,32 @@ channel_open_func(typval_T *argvars)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
port = strtol((char *)(p + 1), &rest, 10);
|
||||
if (*address == NUL || port <= 0 || port >= 65536 || *rest != NUL)
|
||||
|
||||
if (!is_unix)
|
||||
{
|
||||
semsg(_(e_invalid_argument_str), address);
|
||||
return NULL;
|
||||
port = strtol((char *)(p + 1), &rest, 10);
|
||||
if (port <= 0 || port >= 65536 || *rest != NUL)
|
||||
{
|
||||
semsg(_(e_invalid_argument_str), address);
|
||||
return NULL;
|
||||
}
|
||||
if (is_ipv6)
|
||||
{
|
||||
// strip '[' and ']'
|
||||
++address;
|
||||
*(p - 1) = NUL;
|
||||
}
|
||||
else
|
||||
*p = NUL;
|
||||
}
|
||||
if (is_ipv6)
|
||||
{
|
||||
// strip '[' and ']'
|
||||
++address;
|
||||
*(p - 1) = NUL;
|
||||
}
|
||||
else
|
||||
*p = NUL;
|
||||
|
||||
// parse options
|
||||
clear_job_options(&opt);
|
||||
opt.jo_mode = MODE_JSON;
|
||||
opt.jo_timeout = 2000;
|
||||
if (get_job_options(&argvars[1], &opt,
|
||||
JO_MODE_ALL + JO_CB_ALL + JO_WAITTIME + JO_TIMEOUT_ALL, 0) == FAIL)
|
||||
JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL
|
||||
+ (is_unix? 0 : JO_WAITTIME), 0) == FAIL)
|
||||
goto theend;
|
||||
if (opt.jo_timeout < 0)
|
||||
{
|
||||
@@ -1368,7 +1453,10 @@ channel_open_func(typval_T *argvars)
|
||||
goto theend;
|
||||
}
|
||||
|
||||
channel = channel_open((char *)address, port, opt.jo_waittime, NULL);
|
||||
if (is_unix)
|
||||
channel = channel_open_unix((char *)address, NULL);
|
||||
else
|
||||
channel = channel_open((char *)address, port, opt.jo_waittime, NULL);
|
||||
if (channel != NULL)
|
||||
{
|
||||
opt.jo_set = JO_ALL;
|
||||
@@ -3268,8 +3356,14 @@ channel_info(channel_T *channel, dict_T *dict)
|
||||
|
||||
if (channel->ch_hostname != NULL)
|
||||
{
|
||||
dict_add_string(dict, "hostname", (char_u *)channel->ch_hostname);
|
||||
dict_add_number(dict, "port", channel->ch_port);
|
||||
if (channel->ch_port)
|
||||
{
|
||||
dict_add_string(dict, "hostname", (char_u *)channel->ch_hostname);
|
||||
dict_add_number(dict, "port", channel->ch_port);
|
||||
}
|
||||
else
|
||||
// Unix-domain socket.
|
||||
dict_add_string(dict, "path", (char_u *)channel->ch_hostname);
|
||||
channel_part_info(channel, dict, "sock", PART_SOCK);
|
||||
}
|
||||
else
|
||||
|
@@ -95,7 +95,7 @@ func CheckUnix()
|
||||
endif
|
||||
endfunc
|
||||
|
||||
" Command to check for running on Linix
|
||||
" Command to check for running on Linux
|
||||
command CheckLinux call CheckLinux()
|
||||
func CheckLinux()
|
||||
if !has('linux')
|
||||
|
@@ -15,10 +15,16 @@ func PythonProg()
|
||||
if has('unix')
|
||||
" We also need the job feature or the pkill command to make sure the server
|
||||
" can be stopped.
|
||||
if !(executable('python') && (has('job') || executable('pkill')))
|
||||
if !(has('job') || executable('pkill'))
|
||||
return ''
|
||||
endif
|
||||
let s:python = 'python'
|
||||
if executable('python')
|
||||
let s:python = 'python'
|
||||
elseif executable('python3')
|
||||
let s:python = 'python3'
|
||||
else
|
||||
return ''
|
||||
end
|
||||
elseif has('win32')
|
||||
" Use Python Launcher for Windows (py.exe) if available.
|
||||
" NOTE: if you get a "Python was not found" error, disable the Python
|
||||
|
@@ -22,7 +22,8 @@ except ImportError:
|
||||
class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
|
||||
|
||||
def setup(self):
|
||||
self.request.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
||||
if self.server.address_family != socket.AF_UNIX:
|
||||
self.request.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
||||
|
||||
def handle(self):
|
||||
print("=== socket opened ===")
|
||||
|
@@ -23,6 +23,9 @@ func SetUp()
|
||||
if g:testfunc =~ '_ipv6()$'
|
||||
let s:localhost = '[::1]:'
|
||||
let s:testscript = 'test_channel_6.py'
|
||||
elseif g:testfunc =~ '_unix()$'
|
||||
let s:localhost = 'unix:Xtestsocket'
|
||||
let s:testscript = 'test_channel_unix.py'
|
||||
else
|
||||
let s:localhost = 'localhost:'
|
||||
let s:testscript = 'test_channel.py'
|
||||
@@ -39,6 +42,15 @@ func s:run_server(testfunc, ...)
|
||||
call RunServer(s:testscript, a:testfunc, a:000)
|
||||
endfunc
|
||||
|
||||
" Returns the address of the test server.
|
||||
func s:address(port)
|
||||
if s:localhost =~ '^unix:'
|
||||
return s:localhost
|
||||
else
|
||||
return s:localhost . a:port
|
||||
end
|
||||
endfunc
|
||||
|
||||
" Return a list of open files.
|
||||
" Can be used to make sure no resources leaked.
|
||||
" Returns an empty list on systems where this is not supported.
|
||||
@@ -65,7 +77,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(s:localhost . a:port, s:chopt)
|
||||
let handle = ch_open(s:address(a:port), s:chopt)
|
||||
if ch_status(handle) == "fail"
|
||||
call assert_report("Can't open channel")
|
||||
return
|
||||
@@ -77,7 +89,10 @@ func Ch_communicate(port)
|
||||
let dict = handle->ch_info()
|
||||
call assert_true(dict.id != 0)
|
||||
call assert_equal('open', dict.status)
|
||||
call assert_equal(a:port, string(dict.port))
|
||||
if has_key(dict, 'port')
|
||||
" Channels using Unix sockets have no 'port' entry.
|
||||
call assert_equal(a:port, string(dict.port))
|
||||
end
|
||||
call assert_equal('open', dict.sock_status)
|
||||
call assert_equal('socket', dict.sock_io)
|
||||
|
||||
@@ -252,13 +267,19 @@ endfunc
|
||||
|
||||
func Test_communicate_ipv6()
|
||||
CheckIPv6
|
||||
|
||||
call Test_communicate()
|
||||
endfunc
|
||||
|
||||
func Test_communicate_unix()
|
||||
CheckUnix
|
||||
call Test_communicate()
|
||||
call delete('Xtestsocket')
|
||||
endfunc
|
||||
|
||||
|
||||
" Test that we can open two channels.
|
||||
func Ch_two_channels(port)
|
||||
let handle = ch_open(s:localhost . a:port, s:chopt)
|
||||
let handle = ch_open(s:address(a:port), s:chopt)
|
||||
call assert_equal(v:t_channel, type(handle))
|
||||
if handle->ch_status() == "fail"
|
||||
call assert_report("Can't open channel")
|
||||
@@ -267,7 +288,7 @@ func Ch_two_channels(port)
|
||||
|
||||
call assert_equal('got it', ch_evalexpr(handle, 'hello!'))
|
||||
|
||||
let newhandle = ch_open(s:localhost . a:port, s:chopt)
|
||||
let newhandle = ch_open(s:address(a:port), s:chopt)
|
||||
if ch_status(newhandle) == "fail"
|
||||
call assert_report("Can't open second channel")
|
||||
return
|
||||
@@ -292,9 +313,15 @@ func Test_two_channels_ipv6()
|
||||
call Test_two_channels()
|
||||
endfunc
|
||||
|
||||
func Test_two_channels_unix()
|
||||
CheckUnix
|
||||
call Test_two_channels()
|
||||
call delete('Xtestsocket')
|
||||
endfunc
|
||||
|
||||
" Test that a server crash is handled gracefully.
|
||||
func Ch_server_crash(port)
|
||||
let handle = ch_open(s:localhost . a:port, s:chopt)
|
||||
let handle = ch_open(s:address(a:port), s:chopt)
|
||||
if ch_status(handle) == "fail"
|
||||
call assert_report("Can't open channel")
|
||||
return
|
||||
@@ -314,6 +341,12 @@ func Test_server_crash_ipv6()
|
||||
call Test_server_crash()
|
||||
endfunc
|
||||
|
||||
func Test_server_crash_unix()
|
||||
CheckUnix
|
||||
call Test_server_crash()
|
||||
call delete('Xtestsocket')
|
||||
endfunc
|
||||
|
||||
"""""""""
|
||||
|
||||
func Ch_handler(chan, msg)
|
||||
@@ -323,7 +356,7 @@ func Ch_handler(chan, msg)
|
||||
endfunc
|
||||
|
||||
func Ch_channel_handler(port)
|
||||
let handle = ch_open(s:localhost . a:port, s:chopt)
|
||||
let handle = ch_open(s:address(a:port), s:chopt)
|
||||
if ch_status(handle) == "fail"
|
||||
call assert_report("Can't open channel")
|
||||
return
|
||||
@@ -352,6 +385,12 @@ func Test_channel_handler_ipv6()
|
||||
call Test_channel_handler()
|
||||
endfunc
|
||||
|
||||
func Test_channel_handler_unix()
|
||||
CheckUnix
|
||||
call Test_channel_handler()
|
||||
call delete('Xtestsocket')
|
||||
endfunc
|
||||
|
||||
"""""""""
|
||||
|
||||
let g:Ch_reply = ''
|
||||
@@ -367,7 +406,7 @@ func Ch_oneHandler(chan, msg)
|
||||
endfunc
|
||||
|
||||
func Ch_channel_zero(port)
|
||||
let handle = (s:localhost .. a:port)->ch_open(s:chopt)
|
||||
let handle = (s:address(a:port))->ch_open(s:chopt)
|
||||
if ch_status(handle) == "fail"
|
||||
call assert_report("Can't open channel")
|
||||
return
|
||||
@@ -415,6 +454,13 @@ func Test_zero_reply_ipv6()
|
||||
call Test_zero_reply()
|
||||
endfunc
|
||||
|
||||
func Test_zero_reply_unix()
|
||||
CheckUnix
|
||||
call Test_zero_reply()
|
||||
call delete('Xtestsocket')
|
||||
endfunc
|
||||
|
||||
|
||||
"""""""""
|
||||
|
||||
let g:Ch_reply1 = ""
|
||||
@@ -436,7 +482,7 @@ func Ch_handleRaw3(chan, msg)
|
||||
endfunc
|
||||
|
||||
func Ch_raw_one_time_callback(port)
|
||||
let handle = ch_open(s:localhost . a:port, s:chopt)
|
||||
let handle = ch_open(s:address(a:port), s:chopt)
|
||||
if ch_status(handle) == "fail"
|
||||
call assert_report("Can't open channel")
|
||||
return
|
||||
@@ -462,6 +508,12 @@ func Test_raw_one_time_callback_ipv6()
|
||||
call Test_raw_one_time_callback()
|
||||
endfunc
|
||||
|
||||
func Test_raw_one_time_callback_unix()
|
||||
CheckUnix
|
||||
call Test_raw_one_time_callback()
|
||||
call delete('Xtestsocket')
|
||||
endfunc
|
||||
|
||||
"""""""""
|
||||
|
||||
" Test that trying to connect to a non-existing port fails quickly.
|
||||
@@ -1398,7 +1450,7 @@ endfunc
|
||||
|
||||
" 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)
|
||||
let s:channelfd = ch_open(s:address(a:port), s:chopt)
|
||||
eval s:channelfd->ch_sendexpr("test", {'callback': function('s:UnletHandler')})
|
||||
call WaitForAssert({-> assert_equal('what?', g:Ch_unletResponse)})
|
||||
endfunc
|
||||
@@ -1422,7 +1474,7 @@ endfunc
|
||||
|
||||
" 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)
|
||||
let s:channelfd = ch_open(s:address(a:port), s:chopt)
|
||||
call ch_sendexpr(s:channelfd, "test", {'callback': function('Ch_CloseHandler')})
|
||||
call WaitForAssert({-> assert_equal('what?', g:Ch_unletResponse)})
|
||||
endfunc
|
||||
@@ -1439,7 +1491,7 @@ endfunc
|
||||
""""""""""
|
||||
|
||||
func Ch_open_ipv6(port)
|
||||
let handle = ch_open('[::1]:' .. a:port, s:chopt)
|
||||
let handle = ch_open(s:address(a:port), s:chopt)
|
||||
call assert_notequal('fail', ch_status(handle))
|
||||
endfunc
|
||||
|
||||
@@ -1479,7 +1531,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(s:localhost . a:port, s:chopt)
|
||||
let channel = ch_open(s:address(a:port), s:chopt)
|
||||
if ch_status(channel) == "fail"
|
||||
call assert_report("Can't open channel")
|
||||
return
|
||||
@@ -1505,7 +1557,7 @@ function MyFunction(a,b,c)
|
||||
endfunc
|
||||
|
||||
function Ch_test_call(port)
|
||||
let handle = ch_open(s:localhost . a:port, s:chopt)
|
||||
let handle = ch_open(s:address(a:port), s:chopt)
|
||||
if ch_status(handle) == "fail"
|
||||
call assert_report("Can't open channel")
|
||||
return
|
||||
@@ -1529,6 +1581,12 @@ func Test_call_ipv6()
|
||||
call Test_call()
|
||||
endfunc
|
||||
|
||||
func Test_call_unix()
|
||||
CheckUnix
|
||||
call Test_call()
|
||||
call delete('Xtestsocket')
|
||||
endfunc
|
||||
|
||||
"""""""""
|
||||
|
||||
let g:Ch_job_exit_ret = 'not yet'
|
||||
@@ -1605,7 +1663,7 @@ function MyCloseCb(ch)
|
||||
endfunc
|
||||
|
||||
function Ch_test_close_callback(port)
|
||||
let handle = ch_open(s:localhost . a:port, s:chopt)
|
||||
let handle = ch_open(s:address(a:port), s:chopt)
|
||||
if ch_status(handle) == "fail"
|
||||
call assert_report("Can't open channel")
|
||||
return
|
||||
@@ -1625,8 +1683,14 @@ func Test_close_callback_ipv6()
|
||||
call Test_close_callback()
|
||||
endfunc
|
||||
|
||||
func Test_close_callback_unix()
|
||||
CheckUnix
|
||||
call Test_close_callback()
|
||||
call delete('Xtestsocket')
|
||||
endfunc
|
||||
|
||||
function Ch_test_close_partial(port)
|
||||
let handle = ch_open(s:localhost . a:port, s:chopt)
|
||||
let handle = ch_open(s:address(a:port), s:chopt)
|
||||
if ch_status(handle) == "fail"
|
||||
call assert_report("Can't open channel")
|
||||
return
|
||||
@@ -1651,6 +1715,12 @@ func Test_close_partial_ipv6()
|
||||
call Test_close_partial()
|
||||
endfunc
|
||||
|
||||
func Test_close_partial_unix()
|
||||
CheckUnix
|
||||
call Test_close_partial()
|
||||
call delete('Xtestsocket')
|
||||
endfunc
|
||||
|
||||
func Test_job_start_fails()
|
||||
" this was leaking memory
|
||||
call assert_fails("call job_start([''])", "E474:")
|
||||
@@ -1920,7 +1990,7 @@ func Test_cwd()
|
||||
endfunc
|
||||
|
||||
function Ch_test_close_lambda(port)
|
||||
let handle = ch_open(s:localhost . a:port, s:chopt)
|
||||
let handle = ch_open(s:address(a:port), s:chopt)
|
||||
if ch_status(handle) == "fail"
|
||||
call assert_report("Can't open channel")
|
||||
return
|
||||
@@ -1942,6 +2012,12 @@ func Test_close_lambda_ipv6()
|
||||
call Test_close_lambda()
|
||||
endfunc
|
||||
|
||||
func Test_close_lambda_unix()
|
||||
CheckUnix
|
||||
call Test_close_lambda()
|
||||
call delete('Xtestsocket')
|
||||
endfunc
|
||||
|
||||
func s:test_list_args(cmd, out, remove_lf)
|
||||
try
|
||||
let g:out = ''
|
||||
@@ -2243,6 +2319,8 @@ func Test_job_trailing_space_unix()
|
||||
let job = job_start("cat ", #{in_io: 'null'})
|
||||
call WaitForAssert({-> assert_equal("dead", job_status(job))})
|
||||
call assert_equal(0, job_info(job).exitval)
|
||||
|
||||
call delete('Xtestsocket')
|
||||
endfunc
|
||||
|
||||
func Test_ch_getbufnr()
|
||||
|
50
src/testdir/test_channel_unix.py
Normal file
50
src/testdir/test_channel_unix.py
Normal file
@@ -0,0 +1,50 @@
|
||||
#!/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 __future__ import print_function
|
||||
from test_channel import ThreadedTCPServer, ThreadedTCPRequestHandler, \
|
||||
writePortInFile
|
||||
import socket
|
||||
import threading
|
||||
import os
|
||||
|
||||
try:
|
||||
FileNotFoundError
|
||||
except NameError:
|
||||
# Python 2
|
||||
FileNotFoundError = (IOError, OSError)
|
||||
|
||||
class ThreadedUnixServer(ThreadedTCPServer):
|
||||
address_family = socket.AF_UNIX
|
||||
|
||||
def main(path):
|
||||
server = ThreadedUnixServer(path, ThreadedTCPRequestHandler)
|
||||
|
||||
# Start a thread with the server. That thread will then start a new thread
|
||||
# for each connection.
|
||||
server_thread = threading.Thread(target=server.serve_forever)
|
||||
server_thread.start()
|
||||
|
||||
# Signal the test harness we're ready, the port value has no meaning.
|
||||
writePortInFile(1234)
|
||||
|
||||
print("Listening on {0}".format(server.server_address))
|
||||
|
||||
# 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__":
|
||||
try:
|
||||
os.remove("Xtestsocket")
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
main("Xtestsocket")
|
@@ -620,8 +620,8 @@ func Test_fullcommand()
|
||||
\ ':5s': 'substitute',
|
||||
\ "'<,'>s": 'substitute',
|
||||
\ ":'<,'>s": 'substitute',
|
||||
\ 'CheckUni': 'CheckUnix',
|
||||
\ 'CheckUnix': 'CheckUnix',
|
||||
\ 'CheckLin': 'CheckLinux',
|
||||
\ 'CheckLinux': 'CheckLinux',
|
||||
\ }
|
||||
|
||||
for [in, want] in items(tests)
|
||||
|
@@ -750,6 +750,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
4684,
|
||||
/**/
|
||||
4683,
|
||||
/**/
|
||||
|
Reference in New Issue
Block a user