diff options
-rw-r--r-- | CMakeLists.txt | 8 | ||||
-rw-r--r-- | configure.ac | 38 | ||||
-rw-r--r-- | docs/libcurl/curl_easy_setopt.3 | 2 | ||||
-rw-r--r-- | docs/libcurl/curl_version_info.3 | 3 | ||||
-rw-r--r-- | docs/libcurl/opts/CURLOPT_UNIX_SOCKET_PATH.3 | 76 | ||||
-rw-r--r-- | docs/libcurl/symbols-in-versions | 2 | ||||
-rw-r--r-- | include/curl/curl.h | 4 | ||||
-rw-r--r-- | lib/curl_addrinfo.c | 39 | ||||
-rw-r--r-- | lib/curl_addrinfo.h | 4 | ||||
-rw-r--r-- | lib/curl_config.h.cmake | 3 | ||||
-rw-r--r-- | lib/url.c | 44 | ||||
-rw-r--r-- | lib/urldata.h | 4 | ||||
-rw-r--r-- | lib/version.c | 3 | ||||
-rw-r--r-- | packages/OS400/curl.inc.in | 4 | ||||
-rw-r--r-- | src/tool_help.c | 3 | ||||
-rw-r--r-- | tests/server/sws.c | 2 |
16 files changed, 236 insertions, 3 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 17eacfa79..d6abaab77 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -527,6 +527,14 @@ if(CMAKE_USE_GSSAPI) endif() endif() +option(ENABLE_UNIX_SOCKETS "Define if you want UNIX domain sockets support" ON) +if(ENABLE_UNIX_SOCKETS) + include(CheckStructHasMember) + check_struct_has_member("struct sockaddr_un" sun_path "sys/un.h" USE_UNIX_SOCKETS) +else() + unset(USE_UNIX_SOCKETS CACHE) +endif() + # Check for header files if(NOT UNIX) check_include_file_concat("ws2tcpip.h" HAVE_WS2TCPIP_H) diff --git a/configure.ac b/configure.ac index d2628d132..fb8dfd5b3 100644 --- a/configure.ac +++ b/configure.ac @@ -154,6 +154,7 @@ dnl initialize all the info variables curl_tls_srp_msg="no (--enable-tls-srp)" curl_res_msg="default (--enable-ares / --enable-threaded-resolver)" curl_ipv6_msg="no (--enable-ipv6)" +curl_unix_sockets_msg="no (--enable-unix-sockets)" curl_idn_msg="no (--with-{libidn,winidn})" curl_manual_msg="no (--enable-manual)" curl_libcurl_msg="enabled (--disable-libcurl-option)" @@ -3274,6 +3275,39 @@ if test "$want_tls_srp" = "yes" && ( test "x$HAVE_GNUTLS_SRP" = "x1" || test "x$ fi dnl ************************************************************ +dnl disable UNIX domain sockets support +dnl +AC_MSG_CHECKING([whether to enable UNIX domain sockets]) +AC_ARG_ENABLE(unix-sockets, +AC_HELP_STRING([--enable-unix-sockets],[Enable UNIX domain sockets]) +AC_HELP_STRING([--disable-unix-sockets],[Disable UNIX domain sockets]), +[ case "$enableval" in + no) AC_MSG_RESULT(no) + want_unix_sockets=no + ;; + *) AC_MSG_RESULT(yes) + want_unix_sockets=yes + ;; + esac ], [ + AC_MSG_RESULT(auto) + want_unix_sockets=auto + ] +) +if test "x$want_unix_sockets" != "xno"; then + AC_CHECK_MEMBER([struct sockaddr_un.sun_path], [ + AC_DEFINE(USE_UNIX_SOCKETS, 1, [Use UNIX domain sockets]) + AC_SUBST(USE_UNIX_SOCKETS, [1]) + curl_unix_sockets_msg="enabled" + ], [ + if test "x$want_unix_sockets" = "xyes"; then + AC_MSG_ERROR([--enable-unix-sockets is not available on this platform!]) + fi + ], [ + #include <sys/un.h> + ]) +fi + +dnl ************************************************************ dnl disable cookies support dnl AC_MSG_CHECKING([whether to enable support for cookies]) @@ -3356,6 +3390,9 @@ fi if test "x$IPV6_ENABLED" = "x1"; then SUPPORT_FEATURES="$SUPPORT_FEATURES IPv6" fi +if test "x$USE_UNIX_SOCKETS" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES unix-sockets" +fi if test "x$HAVE_LIBZ" = "x1"; then SUPPORT_FEATURES="$SUPPORT_FEATURES libz" fi @@ -3563,6 +3600,7 @@ AC_MSG_NOTICE([Configured to build curl/libcurl: TLS-SRP support: ${curl_tls_srp_msg} resolver: ${curl_res_msg} ipv6 support: ${curl_ipv6_msg} + UNIX sockets support: ${curl_unix_sockets_msg} IDN support: ${curl_idn_msg} Build libcurl: Shared=${enable_shared}, Static=${enable_static} Built-in manual: ${curl_manual_msg} diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3 index d79a42b04..71f681b70 100644 --- a/docs/libcurl/curl_easy_setopt.3 +++ b/docs/libcurl/curl_easy_setopt.3 @@ -187,6 +187,8 @@ Enable TCP keep-alive. See \fICURLOPT_TCP_KEEPALIVE(3)\fP Idle time before sending keep-alive. See \fICURLOPT_TCP_KEEPIDLE(3)\fP .IP CURLOPT_TCP_KEEPINTVL Interval between keep-alive probes. See \fICURLOPT_TCP_KEEPINTVL(3)\fP +.IP CURLOPT_UNIX_SOCKET_PATH +Path to a UNIX domain socket. See \fICURLOPT_UNIX_SOCKET_PATH(3)\fP .SH NAMES and PASSWORDS OPTIONS (Authentication) .IP CURLOPT_NETRC Enable .netrc parsing. See \fICURLOPT_NETRC(3)\fP diff --git a/docs/libcurl/curl_version_info.3 b/docs/libcurl/curl_version_info.3 index 3acf7851b..6e553463e 100644 --- a/docs/libcurl/curl_version_info.3 +++ b/docs/libcurl/curl_version_info.3 @@ -146,6 +146,9 @@ libcurl was built with support for NTLM delegation to a winbind helper. .IP CURL_VERSION_HTTP2 libcurl was built with support for HTTP2. (Added in 7.33.0) +.IP CURL_VERSION_UNIX_SOCKETS +libcurl was built with support for UNIX domain sockets. +(Added in 7.40.0) .RE \fIssl_version\fP is an ASCII string for the OpenSSL version used. If libcurl has no SSL support, this is NULL. diff --git a/docs/libcurl/opts/CURLOPT_UNIX_SOCKET_PATH.3 b/docs/libcurl/opts/CURLOPT_UNIX_SOCKET_PATH.3 new file mode 100644 index 000000000..880c2f71f --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_UNIX_SOCKET_PATH.3 @@ -0,0 +1,76 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at http://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_UNIX_SOCKET_PATH 3 "09 Oct 2014" "libcurl 7.40.0" "curl_easy_setopt options" +.SH NAME +CURLOPT_UNIX_SOCKET_PATH \- set UNIX domain socket +.SH SYNOPSIS +#include <curl/curl.h> + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_UNIX_SOCKET_PATH, char *path); +.SH DESCRIPTION +Enables the use of UNIX domain sockets as connection end point and sets the path +to \fIpath\fP. If \fIpath\fP is NULL, then UNIX domain sockets are disabled. An +empty string will result in an error at some point. + +When enabled, cURL will connect to the UNIX domain socket instead of +establishing a TCP connection to a host. Since no TCP connection is established, +cURL does not need to resolve the DNS hostname in the URL. + +The maximum path length on Cygwin, Linux and Solaris is 107. On other platforms +might be even less. + +Proxy and TCP options such as +.BR CURLOPT_TCP_NODELAY "(3) +are not supported. Proxy options such as +.BR CURLOPT_PROXY "(3) +have no effect either as these are TCP-oriented, and asking a proxy server to +connect to a certain UNIX domain socket is not possible. +.SH DEFAULT +Default is NULL, meaning that no UNIX domain sockets are used. +.SH PROTOCOLS +All protocols except for file:// and FTP are supported in theory. HTTP, IMAP, +POP3 and SMTP should in particular work (including their SSL/TLS variants). +.SH EXAMPLE +Given that you have an nginx server running, listening on /tmp/nginx.sock, you +can request a HTTP resource with: + + curl_easy_setopt(curl_handle, CURLOPT_UNIX_SOCKET_PATH, "/tmp/nginx.sock"); + curl_easy_setopt(curl_handle, CURLOPT_URL, "http://localhost/"); + +If you are on Linux and somehow have a need for paths larger than 107 bytes, you +could use the proc filesystem to bypass the limitation: + + int dirfd = open(long_directory_path_to_socket, O_DIRECTORY | O_RDONLY); + char path[108]; + snprintf(path, sizeof(path), "/proc/self/fd/%d/nginx.sock", dirfd); + curl_easy_setopt(curl_handle, CURLOPT_UNIX_SOCKET_PATH, path); + /* Be sure to keep dirfd valid until you discard the handle */ + +.SH AVAILABILITY +Since 7.40.0. +.SH RETURN VALUE +Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. +.SH "SEE ALSO" +.BR CURLOPT_OPENSOCKETFUNCTION "(3) +, +.BR unix "(7) diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions index 642cc19f4..b8b0838b0 100644 --- a/docs/libcurl/symbols-in-versions +++ b/docs/libcurl/symbols-in-versions @@ -529,6 +529,7 @@ CURLOPT_TLSAUTH_TYPE 7.21.4 CURLOPT_TLSAUTH_USERNAME 7.21.4 CURLOPT_TRANSFERTEXT 7.1.1 CURLOPT_TRANSFER_ENCODING 7.21.6 +CURLOPT_UNIX_SOCKET_PATH 7.40.0 CURLOPT_UNRESTRICTED_AUTH 7.10.4 CURLOPT_UPLOAD 7.1 CURLOPT_URL 7.1 @@ -749,6 +750,7 @@ CURL_VERSION_SPNEGO 7.10.8 CURL_VERSION_SSL 7.10 CURL_VERSION_SSPI 7.13.2 CURL_VERSION_TLSAUTH_SRP 7.21.4 +CURL_VERSION_UNIX_SOCKETS 7.40.0 CURL_WAIT_POLLIN 7.28.0 CURL_WAIT_POLLOUT 7.28.0 CURL_WAIT_POLLPRI 7.28.0 diff --git a/include/curl/curl.h b/include/curl/curl.h index 5ed4c3ea5..0d2076bd2 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -1619,6 +1619,9 @@ typedef enum { this option is used only if SSL_VERIFYPEER is true */ CINIT(PINNEDPUBLICKEY, OBJECTPOINT, 230), + /* Path to UNIX domain socket */ + CINIT(UNIX_SOCKET_PATH, OBJECTPOINT, 231), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; @@ -2266,6 +2269,7 @@ typedef struct { #define CURL_VERSION_HTTP2 (1<<16) /* HTTP2 support built-in */ #define CURL_VERSION_GSSAPI (1<<17) /* Built against a GSS-API library */ #define CURL_VERSION_KERBEROS5 (1<<18) /* Kerberos V5 auth is supported */ +#define CURL_VERSION_UNIX_SOCKETS (1<<19) /* UNIX domain sockets support */ /* * NAME curl_version_info() diff --git a/lib/curl_addrinfo.c b/lib/curl_addrinfo.c index 94ed63d96..b8032f4df 100644 --- a/lib/curl_addrinfo.c +++ b/lib/curl_addrinfo.c @@ -33,6 +33,9 @@ #ifdef HAVE_ARPA_INET_H # include <arpa/inet.h> #endif +#ifdef HAVE_SYS_UN_H +# include <sys/un.h> +#endif #ifdef __VMS # include <in.h> @@ -477,6 +480,42 @@ Curl_addrinfo *Curl_str2addr(char *address, int port) return NULL; /* bad input format */ } +#ifdef USE_UNIX_SOCKETS +/** + * Given a path to a UNIX domain socket, return a newly allocated Curl_addrinfo + * struct initialized with this path. + */ +Curl_addrinfo *Curl_unix2addr(const char *path) +{ + Curl_addrinfo *ai; + struct sockaddr_un *sun; + size_t path_len; + + ai = calloc(1, sizeof(Curl_addrinfo)); + if(!ai) + return NULL; + if((ai->ai_addr = calloc(1, sizeof(struct sockaddr_un))) == NULL) { + free(ai); + return NULL; + } + /* sun_path must be able to store the NUL-terminated path */ + path_len = strlen(path); + if(path_len >= sizeof(sun->sun_path)) { + free(ai->ai_addr); + free(ai); + return NULL; + } + + ai->ai_family = AF_UNIX; + ai->ai_socktype = SOCK_STREAM; /* assume reliable transport for HTTP */ + ai->ai_addrlen = (curl_socklen_t) sizeof(struct sockaddr_un); + sun = (void *) ai->ai_addr; + sun->sun_family = AF_UNIX; + memcpy(sun->sun_path, path, path_len + 1); /* copy NUL byte */ + return ai; +} +#endif + #if defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) /* * curl_dofreeaddrinfo() diff --git a/lib/curl_addrinfo.h b/lib/curl_addrinfo.h index 6d2b753eb..4ef882703 100644 --- a/lib/curl_addrinfo.h +++ b/lib/curl_addrinfo.h @@ -79,6 +79,10 @@ Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port); Curl_addrinfo *Curl_str2addr(char *dotted, int port); +#ifdef USE_UNIX_SOCKETS +Curl_addrinfo *Curl_unix2addr(const char *path); +#endif + #if defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) void curl_dofreeaddrinfo(struct addrinfo *freethis, diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake index 44014f5dd..bd367c28d 100644 --- a/lib/curl_config.h.cmake +++ b/lib/curl_config.h.cmake @@ -912,6 +912,9 @@ /* if SSL is enabled */ #cmakedefine USE_SSLEAY 1 +/* if UNIX domain sockets are enabled */ +#cmakedefine USE_UNIX_SOCKETS + /* Define to 1 if you are building a Windows target without large file support. */ #cmakedefine USE_WIN32_LARGE_FILES 1 @@ -47,6 +47,10 @@ #include <inet.h> #endif +#ifdef HAVE_SYS_UN_H +#include <sys/un.h> +#endif + #ifndef HAVE_SOCKET #error "We can't compile without socket() support!" #endif @@ -2574,6 +2578,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, data->set.ssl_enable_alpn = (0 != va_arg(param, long))?TRUE:FALSE; break; +#ifdef USE_UNIX_SOCKETS + case CURLOPT_UNIX_SOCKET_PATH: + result = setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH], + va_arg(param, char *)); + break; +#endif + default: /* unknown tag and its companion, just ignore: */ result = CURLE_UNKNOWN_OPTION; @@ -5064,6 +5075,32 @@ static CURLcode resolve_server(struct SessionHandle *data, /* set a pointer to the hostname we display */ fix_hostname(data, conn, &conn->host); +#ifdef USE_UNIX_SOCKETS + if(data->set.str[STRING_UNIX_SOCKET_PATH]) { + /* UNIX domain sockets are local. The host gets ignored, just use the + * specified domain socket address. Do not cache "DNS entries". There is + * no DNS involved and we already have the filesystem path available */ + const char *path = data->set.str[STRING_UNIX_SOCKET_PATH]; + + hostaddr = calloc(1, sizeof(struct Curl_dns_entry)); + if(!hostaddr) + result = CURLE_OUT_OF_MEMORY; + else if((hostaddr->addr = Curl_unix2addr(path)) != NULL) + hostaddr->inuse++; + else { + /* Long paths are not supported for now */ + if(strlen(path) >= sizeof(((struct sockaddr_un *)0)->sun_path)) { + failf(data, "UNIX socket path too long: '%s'", path); + result = CURLE_COULDNT_RESOLVE_HOST; + } + else + result = CURLE_OUT_OF_MEMORY; + free(hostaddr); + hostaddr = NULL; + } + } + else +#endif if(!conn->proxy.name || !*conn->proxy.name) { /* If not connecting via a proxy, extract the port from the URL, if it is * there, thus overriding any defaults that might have been set above. */ @@ -5379,6 +5416,13 @@ static CURLcode create_conn(struct SessionHandle *data, else if(!proxy) proxy = detect_proxy(conn); +#ifdef USE_UNIX_SOCKETS + if(proxy && data->set.str[STRING_UNIX_SOCKET_PATH]) { + free(proxy); /* UNIX domain sockets cannot be proxied, so disable it */ + proxy = NULL; + } +#endif + if(proxy && (!*proxy || (conn->handler->flags & PROTOPT_NONETWORK))) { free(proxy); /* Don't bother with an empty proxy string or if the protocol doesn't work with network */ diff --git a/lib/urldata.h b/lib/urldata.h index 075dca9b2..d61e8cefc 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -1426,8 +1426,10 @@ enum dupstring { STRING_TLSAUTH_USERNAME, /* TLS auth <username> */ STRING_TLSAUTH_PASSWORD, /* TLS auth <password> */ #endif - STRING_BEARER, /* <bearer>, if used */ +#ifdef USE_UNIX_SOCKETS + STRING_UNIX_SOCKET_PATH, /* path to UNIX socket, if used */ +#endif /* -- end of zero-terminated strings -- */ diff --git a/lib/version.c b/lib/version.c index 93317e19b..511562fe1 100644 --- a/lib/version.c +++ b/lib/version.c @@ -295,6 +295,9 @@ static curl_version_info_data version_info = { #if defined(USE_NGHTTP2) | CURL_VERSION_HTTP2 #endif +#if defined(USE_UNIX_SOCKETS) + | CURL_VERSION_UNIX_SOCKETS +#endif , NULL, /* ssl_version */ 0, /* ssl_version_num, this is kept at zero */ diff --git a/packages/OS400/curl.inc.in b/packages/OS400/curl.inc.in index bc4d848f5..fcbf7c7c5 100644 --- a/packages/OS400/curl.inc.in +++ b/packages/OS400/curl.inc.in @@ -121,6 +121,8 @@ d c X'00020000' d CURL_VERSION_KERBEROS5... d c X'00040000' + d CURL_VERSION_UNIX_SOCKETS... + d c X'00080000' * d HTTPPOST_FILENAME... d c X'00000001' @@ -1199,6 +1201,8 @@ d c 00229 d CURLOPT_PINNEDPUBLICKEY... d c 10230 + d CURLOPT_UNIX_SOCKET_PATH... + d c 10231 * /if not defined(CURL_NO_OLDIES) d CURLOPT_FILE c 10001 diff --git a/src/tool_help.c b/src/tool_help.c index 280d33a87..6f8f29263 100644 --- a/src/tool_help.c +++ b/src/tool_help.c @@ -273,7 +273,8 @@ static const struct feat feats[] = { {"libz", CURL_VERSION_LIBZ}, {"CharConv", CURL_VERSION_CONV}, {"TLS-SRP", CURL_VERSION_TLSAUTH_SRP}, - {"HTTP2", CURL_VERSION_HTTP2} + {"HTTP2", CURL_VERSION_HTTP2}, + {"unix-sockets", CURL_VERSION_UNIX_SOCKETS}, }; void tool_help(void) diff --git a/tests/server/sws.c b/tests/server/sws.c index 03e0d0c3d..14153c6da 100644 --- a/tests/server/sws.c +++ b/tests/server/sws.c @@ -71,7 +71,7 @@ static enum { , socket_domain_inet6 = AF_INET6 #endif #ifdef USE_UNIX_SOCKETS - socket_domain_unix = AF_UNIX, + , socket_domain_unix = AF_UNIX #endif } socket_domain = AF_INET; static bool use_gopher = FALSE; |