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:
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
|
||||
|
Reference in New Issue
Block a user