4444# define sock_write (sd , buf , len ) send((SOCKET)sd, buf, len, 0)
4545# define sock_read (sd , buf , len ) recv((SOCKET)sd, buf, len, 0)
4646# define sock_close (sd ) closesocket((SOCKET)sd)
47+ // Support for Unix-domain sockets was added in Windows SDK 17061.
48+ # define UNIX_PATH_MAX 108
49+ typedef struct sockaddr_un {
50+ ADDRESS_FAMILY sun_family ;
51+ char sun_path [UNIX_PATH_MAX ];
52+ } SOCKADDR_UN , * PSOCKADDR_UN ;
4753#else
4854# include <netdb.h>
4955# include <netinet/in.h>
5056# include <arpa/inet.h>
5157# include <sys/socket.h>
58+ # include <sys/un.h>
5259# ifdef HAVE_LIBGEN_H
5360# include <libgen.h>
5461# endif
@@ -928,6 +935,67 @@ channel_connect(
928935 return sd ;
929936}
930937
938+ /*
939+ * Open a socket channel to the UNIX socket at "path".
940+ * Returns the channel for success.
941+ * Returns NULL for failure.
942+ */
943+ static channel_T *
944+ channel_open_unix (
945+ const char * path ,
946+ void (* nb_close_cb )(void ))
947+ {
948+ channel_T * channel = NULL ;
949+ int sd = -1 ;
950+ size_t path_len = STRLEN (path );
951+ struct sockaddr_un server ;
952+ size_t server_len ;
953+ int waittime = -1 ;
954+
955+ if (* path == NUL || path_len >= sizeof (server .sun_path ))
956+ {
957+ semsg (_ (e_invalid_argument_str ), path );
958+ return NULL ;
959+ }
960+
961+ channel = add_channel ();
962+ if (channel == NULL )
963+ {
964+ ch_error (NULL , "Cannot allocate channel." );
965+ return NULL ;
966+ }
967+
968+ CLEAR_FIELD (server );
969+ server .sun_family = AF_UNIX ;
970+ STRNCPY (server .sun_path , path , sizeof (server .sun_path ) - 1 );
971+
972+ ch_log (channel , "Trying to connect to %s" , path );
973+
974+ server_len = offsetof(struct sockaddr_un , sun_path ) + path_len + 1 ;
975+ sd = channel_connect (channel , (struct sockaddr * )& server , (int )server_len ,
976+ & waittime );
977+
978+ if (sd < 0 )
979+ {
980+ channel_free (channel );
981+ return NULL ;
982+ }
983+
984+ ch_log (channel , "Connection made" );
985+
986+ channel -> CH_SOCK_FD = (sock_T )sd ;
987+ channel -> ch_nb_close_cb = nb_close_cb ;
988+ channel -> ch_hostname = (char * )vim_strsave ((char_u * )path );
989+ channel -> ch_port = 0 ;
990+ channel -> ch_to_be_closed |= (1U << PART_SOCK );
991+
992+ #ifdef FEAT_GUI
993+ channel_gui_register_one (channel , PART_SOCK );
994+ #endif
995+
996+ return channel ;
997+ }
998+
931999/*
9321000 * Open a socket channel to "hostname":"port".
9331001 * "waittime" is the time in msec to wait for the connection.
@@ -1301,8 +1369,9 @@ channel_open_func(typval_T *argvars)
13011369 char_u * address ;
13021370 char_u * p ;
13031371 char * rest ;
1304- int port ;
1372+ int port = 0 ;
13051373 int is_ipv6 = FALSE;
1374+ int is_unix = FALSE;
13061375 jobopt_T opt ;
13071376 channel_T * channel = NULL ;
13081377
@@ -1319,8 +1388,18 @@ channel_open_func(typval_T *argvars)
13191388 return NULL ;
13201389 }
13211390
1322- // parse address
1323- if (* address == '[' )
1391+ if (* address == NUL )
1392+ {
1393+ semsg (_ (e_invalid_argument_str ), address );
1394+ return NULL ;
1395+ }
1396+
1397+ if (!STRNCMP (address , "unix:" , 5 ))
1398+ {
1399+ is_unix = TRUE;
1400+ address += 5 ;
1401+ }
1402+ else if (* address == '[' )
13241403 {
13251404 // ipv6 address
13261405 is_ipv6 = TRUE;
@@ -1333,42 +1412,51 @@ channel_open_func(typval_T *argvars)
13331412 }
13341413 else
13351414 {
1415+ // ipv4 address
13361416 p = vim_strchr (address , ':' );
13371417 if (p == NULL )
13381418 {
13391419 semsg (_ (e_invalid_argument_str ), address );
13401420 return NULL ;
13411421 }
13421422 }
1343- port = strtol ((char * )(p + 1 ), & rest , 10 );
1344- if (* address == NUL || port <= 0 || port >= 65536 || * rest != NUL )
1345- {
1346- semsg (_ (e_invalid_argument_str ), address );
1347- return NULL ;
1348- }
1349- if (is_ipv6 )
1423+
1424+ if (!is_unix )
13501425 {
1351- // strip '[' and ']'
1352- ++ address ;
1353- * (p - 1 ) = NUL ;
1426+ port = strtol ((char * )(p + 1 ), & rest , 10 );
1427+ if (port <= 0 || port >= 65536 || * rest != NUL )
1428+ {
1429+ semsg (_ (e_invalid_argument_str ), address );
1430+ return NULL ;
1431+ }
1432+ if (is_ipv6 )
1433+ {
1434+ // strip '[' and ']'
1435+ ++ address ;
1436+ * (p - 1 ) = NUL ;
1437+ }
1438+ else
1439+ * p = NUL ;
13541440 }
1355- else
1356- * p = NUL ;
13571441
13581442 // parse options
13591443 clear_job_options (& opt );
13601444 opt .jo_mode = MODE_JSON ;
13611445 opt .jo_timeout = 2000 ;
13621446 if (get_job_options (& argvars [1 ], & opt ,
1363- JO_MODE_ALL + JO_CB_ALL + JO_WAITTIME + JO_TIMEOUT_ALL , 0 ) == FAIL )
1447+ JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL
1448+ + (is_unix ? 0 : JO_WAITTIME ), 0 ) == FAIL )
13641449 goto theend ;
13651450 if (opt .jo_timeout < 0 )
13661451 {
13671452 emsg (_ (e_invalid_argument ));
13681453 goto theend ;
13691454 }
13701455
1371- channel = channel_open ((char * )address , port , opt .jo_waittime , NULL );
1456+ if (is_unix )
1457+ channel = channel_open_unix ((char * )address , NULL );
1458+ else
1459+ channel = channel_open ((char * )address , port , opt .jo_waittime , NULL );
13721460 if (channel != NULL )
13731461 {
13741462 opt .jo_set = JO_ALL ;
@@ -3268,8 +3356,14 @@ channel_info(channel_T *channel, dict_T *dict)
32683356
32693357 if (channel -> ch_hostname != NULL )
32703358 {
3271- dict_add_string (dict , "hostname" , (char_u * )channel -> ch_hostname );
3272- dict_add_number (dict , "port" , channel -> ch_port );
3359+ if (channel -> ch_port )
3360+ {
3361+ dict_add_string (dict , "hostname" , (char_u * )channel -> ch_hostname );
3362+ dict_add_number (dict , "port" , channel -> ch_port );
3363+ }
3364+ else
3365+ // Unix-domain socket.
3366+ dict_add_string (dict , "path" , (char_u * )channel -> ch_hostname );
32733367 channel_part_info (channel , dict , "sock" , PART_SOCK );
32743368 }
32753369 else
0 commit comments