Skip to content

Commit 1d786fa

Browse files
iboukrisLekensteyn
authored andcommitted
unix_socket: add support for abstract unix domain socket
In addition to unix domain sockets, Linux also supports an abstract namespace which is independent of the filesystem. In order to support it, add new CURLOPT_ABSTRACT_UNIX_SOCKET option which uses the same storage as CURLOPT_UNIX_SOCKET_PATH internally, along with a flag to specify abstract socket. On non-supporting platforms, the abstract address will be interpreted as an empty string and fail gracefully. Also add new --abstract-unix-socket tool parameter. Signed-off-by: Isaac Boukris <[email protected]> Reported-by: Chungtsun Li (typeless) Reviewed-by: Daniel Stenberg Reviewed-by: Peter Wu Closes curl#1197 Fixes curl#1061
1 parent a7c73ae commit 1d786fa

17 files changed

+139
-19
lines changed

docs/cmdline-opts/Makefile.am

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222

2323
AUTOMAKE_OPTIONS = foreign no-dependencies
2424

25-
DPAGES = anyauth.d append.d basic.d cacert.d capath.d cert.d \
25+
DPAGES = abstract-unix-socket.d anyauth.d \
26+
append.d basic.d cacert.d capath.d cert.d \
2627
cert-status.d cert-type.d ciphers.d compressed.d config.d \
2728
connect-timeout.d connect-to.d continue-at.d cookie.d cookie-jar.d \
2829
create-dirs.d crlf.d crlfile.d data-ascii.d data-binary.d data.d \
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Long: abstract-unix-socket
2+
Arg: <path>
3+
Help: Connect through an abstract Unix domain socket
4+
Added: 7.53.0
5+
Protocols: HTTP
6+
---
7+
Connect through an abstract Unix domain socket, instead of using the network.
8+
Note: netstat shows the path of an abstract socket prefixed with '@', however
9+
the <path> argument should not have this leading character.

docs/curl.1

+4
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,10 @@ but prefix it with "no-". However, in this list we mostly only list and show
139139
the --option version of them. (This concept with --no options was added in
140140
7.19.0. Previously most options were toggled on/off on repeated use of the
141141
same command line option.)
142+
.IP "--abstract-unix-socket <path>"
143+
(HTTP) Connect through an abstract Unix domain socket, instead of using the network.
144+
145+
Added in 7.53.0.
142146
.IP "--anyauth"
143147
(HTTP) Tells curl to figure out authentication method by itself, and use the most
144148
secure one the remote site claims to support. This is done by first doing a

docs/libcurl/curl_easy_setopt.3

+2
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,8 @@ Idle time before sending keep-alive. See \fICURLOPT_TCP_KEEPIDLE(3)\fP
207207
Interval between keep-alive probes. See \fICURLOPT_TCP_KEEPINTVL(3)\fP
208208
.IP CURLOPT_UNIX_SOCKET_PATH
209209
Path to a Unix domain socket. See \fICURLOPT_UNIX_SOCKET_PATH(3)\fP
210+
.IP CURLOPT_ABSTRACT_UNIX_SOCKET
211+
Path to an abstract Unix domain socket. See \fICURLOPT_ABSTRACT_UNIX_SOCKET(3)\fP
210212
.SH NAMES and PASSWORDS OPTIONS (Authentication)
211213
.IP CURLOPT_NETRC
212214
Enable .netrc parsing. See \fICURLOPT_NETRC(3)\fP
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
.\" **************************************************************************
2+
.\" * _ _ ____ _
3+
.\" * Project ___| | | | _ \| |
4+
.\" * / __| | | | |_) | |
5+
.\" * | (__| |_| | _ <| |___
6+
.\" * \___|\___/|_| \_\_____|
7+
.\" *
8+
.\" * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
9+
.\" *
10+
.\" * This software is licensed as described in the file COPYING, which
11+
.\" * you should have received as part of this distribution. The terms
12+
.\" * are also available at https://curl.haxx.se/docs/copyright.html.
13+
.\" *
14+
.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15+
.\" * copies of the Software, and permit persons to whom the Software is
16+
.\" * furnished to do so, under the terms of the COPYING file.
17+
.\" *
18+
.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19+
.\" * KIND, either express or implied.
20+
.\" *
21+
.\" **************************************************************************
22+
.\"
23+
.TH CURLOPT_ABSTRACT_UNIX_SOCKET 3 "08 Jan 2017" "libcurl 7.53.0" "curl_easy_setopt options"
24+
.SH NAME
25+
CURLOPT_ABSTRACT_UNIX_SOCKET \- set an abstract Unix domain socket
26+
.SH SYNOPSIS
27+
#include <curl/curl.h>
28+
29+
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_ABSTRACT_UNIX_SOCKET, char *path);
30+
.SH DESCRIPTION
31+
Enables the use of an abstract Unix domain socket instead of establishing a TCP
32+
connection to a host. The parameter should be a char * to a zero terminated string
33+
holding the path of the socket. The path will be set to \fIpath\fP prefixed by a
34+
NULL byte (this is the convention for abstract sockets, however it should be stressed
35+
that the path passed to this function should not contain a leading NULL).
36+
37+
On non-supporting platforms, the abstract address will be interpreted as an empty
38+
string and fail gracefully, generating a run-time error.
39+
40+
This option shares the same semantics as
41+
.BR CURLOPT_UNIX_SOCKET_PATH "(3)
42+
in which documentation more details can be found. Internally, these two options share
43+
the same storage and therefore only one of them can be set per handle.
44+
45+
.SH DEFAULT
46+
Default is NULL.
47+
.SH EXAMPLE
48+
.nf
49+
curl_easy_setopt(curl_handle, CURLOPT_ABSTRACT_UNIX_SOCKET, "/tmp/foo.sock");
50+
curl_easy_setopt(curl_handle, CURLOPT_URL, "http://localhost/");
51+
.fi
52+
53+
.SH AVAILABILITY
54+
Since 7.53.0.
55+
.SH RETURN VALUE
56+
Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
57+
.SH "SEE ALSO"
58+
.BR CURLOPT_UNIX_SOCKET_PATH "(3), " unix "(7), "

docs/libcurl/opts/Makefile.am

+3
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ man_MANS = \
8787
CURLMOPT_SOCKETFUNCTION.3 \
8888
CURLMOPT_TIMERDATA.3 \
8989
CURLMOPT_TIMERFUNCTION.3 \
90+
CURLOPT_ABSTRACT_UNIX_SOCKET.3 \
9091
CURLOPT_ACCEPTTIMEOUT_MS.3 \
9192
CURLOPT_ACCEPT_ENCODING.3 \
9293
CURLOPT_ADDRESS_SCOPE.3 \
@@ -397,6 +398,7 @@ HTMLPAGES = \
397398
CURLMOPT_SOCKETFUNCTION.html \
398399
CURLMOPT_TIMERDATA.html \
399400
CURLMOPT_TIMERFUNCTION.html \
401+
CURLOPT_ABSTRACT_UNIX_SOCKET.html \
400402
CURLOPT_ACCEPTTIMEOUT_MS.html \
401403
CURLOPT_ACCEPT_ENCODING.html \
402404
CURLOPT_ADDRESS_SCOPE.html \
@@ -707,6 +709,7 @@ PDFPAGES = \
707709
CURLMOPT_SOCKETFUNCTION.pdf \
708710
CURLMOPT_TIMERDATA.pdf \
709711
CURLMOPT_TIMERFUNCTION.pdf \
712+
CURLOPT_ABSTRACT_UNIX_SOCKET.pdf \
710713
CURLOPT_ACCEPTTIMEOUT_MS.pdf \
711714
CURLOPT_ACCEPT_ENCODING.pdf \
712715
CURLOPT_ADDRESS_SCOPE.pdf \

docs/libcurl/symbols-in-versions

+1
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@ CURLOPTTYPE_LONG 7.1
317317
CURLOPTTYPE_OBJECTPOINT 7.1
318318
CURLOPTTYPE_OFF_T 7.11.0
319319
CURLOPTTYPE_STRINGPOINT 7.46.0
320+
CURLOPT_ABSTRACT_UNIX_SOCKET 7.53.0
320321
CURLOPT_ACCEPTTIMEOUT_MS 7.24.0
321322
CURLOPT_ACCEPT_ENCODING 7.21.6
322323
CURLOPT_ADDRESS_SCOPE 7.19.0

include/curl/curl.h

+3
Original file line numberDiff line numberDiff line change
@@ -1770,6 +1770,9 @@ typedef enum {
17701770
this option is used only if PROXY_SSL_VERIFYPEER is true */
17711771
CINIT(PROXY_PINNEDPUBLICKEY, STRINGPOINT, 263),
17721772

1773+
/* Path to an abstract Unix domain socket */
1774+
CINIT(ABSTRACT_UNIX_SOCKET, STRINGPOINT, 264),
1775+
17731776
CURLOPT_LASTENTRY /* the last unused */
17741777
} CURLoption;
17751778

include/curl/typecheck-gcc.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,8 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist,
219219

220220
/* evaluates to true if option takes a char* argument */
221221
#define _curl_is_string_option(option) \
222-
((option) == CURLOPT_ACCEPT_ENCODING || \
222+
((option) == CURLOPT_ABSTRACT_UNIX_SOCKET || \
223+
(option) == CURLOPT_ACCEPT_ENCODING || \
223224
(option) == CURLOPT_CAINFO || \
224225
(option) == CURLOPT_CAPATH || \
225226
(option) == CURLOPT_COOKIE || \

lib/curl_addrinfo.c

+19-8
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
# define in_addr_t unsigned long
4848
#endif
4949

50+
#include <stddef.h>
51+
5052
#include "curl_addrinfo.h"
5153
#include "inet_pton.h"
5254
#include "warnless.h"
@@ -483,24 +485,29 @@ Curl_addrinfo *Curl_str2addr(char *address, int port)
483485
* struct initialized with this path.
484486
* Set '*longpath' to TRUE if the error is a too long path.
485487
*/
486-
Curl_addrinfo *Curl_unix2addr(const char *path, int *longpath)
488+
Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, bool abstract)
487489
{
488490
Curl_addrinfo *ai;
489491
struct sockaddr_un *sa_un;
490492
size_t path_len;
491493

494+
*longpath = FALSE;
495+
492496
ai = calloc(1, sizeof(Curl_addrinfo));
493497
if(!ai)
494498
return NULL;
495499
ai->ai_addr = calloc(1, sizeof(struct sockaddr_un));
496500
if(!ai->ai_addr) {
497501
free(ai);
498-
*longpath = FALSE;
499502
return NULL;
500503
}
504+
505+
sa_un = (void *) ai->ai_addr;
506+
sa_un->sun_family = AF_UNIX;
507+
501508
/* sun_path must be able to store the NUL-terminated path */
502-
path_len = strlen(path);
503-
if(path_len >= sizeof(sa_un->sun_path)) {
509+
path_len = strlen(path) + 1;
510+
if(path_len > sizeof(sa_un->sun_path)) {
504511
free(ai->ai_addr);
505512
free(ai);
506513
*longpath = TRUE;
@@ -509,10 +516,14 @@ Curl_addrinfo *Curl_unix2addr(const char *path, int *longpath)
509516

510517
ai->ai_family = AF_UNIX;
511518
ai->ai_socktype = SOCK_STREAM; /* assume reliable transport for HTTP */
512-
ai->ai_addrlen = (curl_socklen_t) sizeof(struct sockaddr_un);
513-
sa_un = (void *) ai->ai_addr;
514-
sa_un->sun_family = AF_UNIX;
515-
memcpy(sa_un->sun_path, path, path_len + 1); /* copy NUL byte */
519+
ai->ai_addrlen = offsetof(struct sockaddr_un, sun_path) + path_len;
520+
521+
/* Abstract Unix domain socket have NULL prefix instead of suffix */
522+
if(abstract)
523+
memcpy(sa_un->sun_path + 1, path, path_len - 1);
524+
else
525+
memcpy(sa_un->sun_path, path, path_len); /* copy NUL byte */
526+
516527
return ai;
517528
}
518529
#endif

lib/curl_addrinfo.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port);
8080
Curl_addrinfo *Curl_str2addr(char *dotted, int port);
8181

8282
#ifdef USE_UNIX_SOCKETS
83-
Curl_addrinfo *Curl_unix2addr(const char *path, int *longpath);
83+
Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, bool abstract);
8484
#endif
8585

8686
#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) && \

lib/url.c

+12-2
Original file line numberDiff line numberDiff line change
@@ -2814,6 +2814,12 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option,
28142814

28152815
#ifdef USE_UNIX_SOCKETS
28162816
case CURLOPT_UNIX_SOCKET_PATH:
2817+
data->set.abstract_unix_socket = FALSE;
2818+
result = setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH],
2819+
va_arg(param, char *));
2820+
break;
2821+
case CURLOPT_ABSTRACT_UNIX_SOCKET:
2822+
data->set.abstract_unix_socket = TRUE;
28172823
result = setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH],
28182824
va_arg(param, char *));
28192825
break;
@@ -3523,6 +3529,8 @@ ConnectionExists(struct Curl_easy *data,
35233529
continue;
35243530
if(strcmp(needle->unix_domain_socket, check->unix_domain_socket))
35253531
continue;
3532+
if(needle->abstract_unix_socket != check->abstract_unix_socket)
3533+
continue;
35263534
}
35273535
else if(check->unix_domain_socket)
35283536
continue;
@@ -5863,8 +5871,9 @@ static CURLcode resolve_server(struct Curl_easy *data,
58635871
if(!hostaddr)
58645872
result = CURLE_OUT_OF_MEMORY;
58655873
else {
5866-
int longpath=0;
5867-
hostaddr->addr = Curl_unix2addr(path, &longpath);
5874+
bool longpath = FALSE;
5875+
hostaddr->addr = Curl_unix2addr(path, &longpath,
5876+
conn->abstract_unix_socket);
58685877
if(hostaddr->addr)
58695878
hostaddr->inuse++;
58705879
else {
@@ -6273,6 +6282,7 @@ static CURLcode create_conn(struct Curl_easy *data,
62736282
result = CURLE_OUT_OF_MEMORY;
62746283
goto out;
62756284
}
6285+
conn->abstract_unix_socket = data->set.abstract_unix_socket;
62766286
}
62776287
#endif
62786288

lib/urldata.h

+3
Original file line numberDiff line numberDiff line change
@@ -1133,6 +1133,7 @@ struct connectdata {
11331133

11341134
#ifdef USE_UNIX_SOCKETS
11351135
char *unix_domain_socket;
1136+
bool abstract_unix_socket;
11361137
#endif
11371138
};
11381139

@@ -1754,6 +1755,8 @@ struct UserDefined {
17541755
int stream_weight;
17551756

17561757
struct Curl_http2_dep *stream_dependents;
1758+
1759+
bool abstract_unix_socket;
17571760
};
17581761

17591762
struct Names {

src/tool_cfgable.h

+1
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ struct OperationConfig {
230230
bool nonpn; /* enable/disable TLS NPN extension */
231231
bool noalpn; /* enable/disable TLS ALPN extension */
232232
char *unix_socket_path; /* path to Unix domain socket */
233+
bool abstract_unix_socket; /* path to an abstract Unix domain socket */
233234
bool falsestart;
234235
bool path_as_is;
235236
double expect100timeout;

src/tool_getparam.c

+6
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ static const struct LongShort aliases[]= {
183183
{"$R", "expect100-timeout", TRUE},
184184
{"$S", "tftp-no-options", FALSE},
185185
{"$U", "connect-to", TRUE},
186+
{"$W", "abstract-unix-socket", TRUE},
186187
{"0", "http1.0", FALSE},
187188
{"01", "http1.1", FALSE},
188189
{"02", "http2", FALSE},
@@ -1024,6 +1025,7 @@ ParameterError getparameter(char *flag, /* f or -long-flag */
10241025
#endif
10251026
break;
10261027
case 'M': /* --unix-socket */
1028+
config->abstract_unix_socket = FALSE;
10271029
GetStr(&config->unix_socket_path, nextarg);
10281030
break;
10291031
case 'N': /* --path-as-is */
@@ -1054,6 +1056,10 @@ ParameterError getparameter(char *flag, /* f or -long-flag */
10541056
if(err)
10551057
return err;
10561058
break;
1059+
case 'W': /* --abstract-unix-socket */
1060+
config->abstract_unix_socket = TRUE;
1061+
GetStr(&config->unix_socket_path, nextarg);
1062+
break;
10571063
}
10581064
break;
10591065
case '#': /* --progress-bar */

src/tool_help.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,8 @@ static const char *const helptext[] = {
271271
" --tlsuser USER TLS username",
272272
" --tlspassword STRING TLS password",
273273
" --tlsauthtype STRING TLS authentication type (default: SRP)",
274-
" --unix-socket FILE Connect through this Unix domain socket",
274+
" --unix-socket PATH Connect through this Unix domain socket",
275+
" --abstract-unix-socket PATH Connect to an abstract Unix domain socket",
275276
" -A, --user-agent STRING Send User-Agent STRING to server (H)",
276277
" -v, --verbose Make the operation more talkative",
277278
" -V, --version Show version number and quit",

src/tool_operate.c

+11-5
Original file line numberDiff line numberDiff line change
@@ -1393,11 +1393,17 @@ static CURLcode operate_do(struct GlobalConfig *global,
13931393
my_setopt(curl, CURLOPT_SSL_ENABLE_ALPN, 0L);
13941394
}
13951395

1396-
/* new in 7.40.0 */
1397-
if(config->unix_socket_path)
1398-
my_setopt_str(curl, CURLOPT_UNIX_SOCKET_PATH,
1399-
config->unix_socket_path);
1400-
1396+
/* new in 7.40.0, abstract support added in 7.53.0 */
1397+
if(config->unix_socket_path) {
1398+
if(config->abstract_unix_socket) {
1399+
my_setopt_str(curl, CURLOPT_ABSTRACT_UNIX_SOCKET,
1400+
config->unix_socket_path);
1401+
}
1402+
else {
1403+
my_setopt_str(curl, CURLOPT_UNIX_SOCKET_PATH,
1404+
config->unix_socket_path);
1405+
}
1406+
}
14011407
/* new in 7.45.0 */
14021408
if(config->proto_default)
14031409
my_setopt_str(curl, CURLOPT_DEFAULT_PROTOCOL, config->proto_default);

0 commit comments

Comments
 (0)