From 499e2f2e988839d3ba2bfe014b707023a93b16ff Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 8 Oct 2019 20:49:34 +0100 Subject: [PATCH] Add support for unix sockets to broker, lib, and clients. --- CMakeLists.txt | 6 ++ ChangeLog.txt | 4 ++ buildtest.py | 1 + client/client_shared.c | 15 ++++- client/client_shared.h | 3 + client/pub_client.c | 4 +- client/rr_client.c | 4 +- client/sub_client.c | 4 +- config.mk | 9 +++ lib/connect.c | 4 +- lib/net_mosq.c | 57 +++++++++++++++++- lib/tls_mosq.c | 6 +- man/mosquitto.conf.5.xml | 6 +- man/mosquitto_pub.1.xml | 16 +++++ man/mosquitto_rr.1.xml | 16 +++++ man/mosquitto_sub.1.xml | 16 +++++ mosquitto.conf | 19 ++++++ src/conf.c | 18 ++++++ src/mosquitto.c | 9 ++- src/mosquitto_broker_internal.h | 3 + src/net.c | 102 +++++++++++++++++++++++++++++--- 21 files changed, 299 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0cde4539..6c37be2e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,12 @@ else (WITH_TLS) set (OPENSSL_INCLUDE_DIR "") endif (WITH_TLS) + +option(WITH_UNIX_SOCKETS "Include Unix Domain Socket support?" ON) +if (WITH_UNIX_SOCKETS AND NOT WIN32) + add_definitions("-DWITH_UNIX_SOCKETS") +endif (WITH_UNIX_SOCKETS AND NOT WIN32) + option(WITH_SOCKS "Include SOCKS5 support?" ON) if (WITH_SOCKS) add_definitions("-DWITH_SOCKS") diff --git a/ChangeLog.txt b/ChangeLog.txt index b8445d19..3819a644 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -2,15 +2,19 @@ Broker: - When running as root, if dropping privileges to the "mosquitto" user fails, then try "nobody" instead. This reduces the burden on users installing Mosquitto themselves. +- Add support for Unix domain socket listeners. Client library: - Client no longer generates random client ids for v3.1.1 clients, these are now expected to be generated on the broker. This matches the behaviour for v5 clients. Closes #291. +- Add support for connecting to brokers through Unix domain sockets. Clients: - Add timeout return code (27) for `mosquitto_sub -W ` and `mosquitto_rr -W `. Closes #275. +- Add support for connecting to brokers through Unix domain sockets with the + `--unix` argument. 1.6.7 - 20190925 diff --git a/buildtest.py b/buildtest.py index b0772cbc..f8e751a3 100755 --- a/buildtest.py +++ b/buildtest.py @@ -18,6 +18,7 @@ build_variants = [ 'WITH_THREADING', 'WITH_TLS', 'WITH_TLS_PSK', + 'WITH_UNIX_SOCKETS', 'WITH_WEBSOCKETS', 'WITH_WRAP', ] diff --git a/client/client_shared.c b/client/client_shared.c index 205245a2..b7d7dedb 100644 --- a/client/client_shared.c +++ b/client/client_shared.c @@ -125,7 +125,7 @@ static int check_format(const char *str) void init_config(struct mosq_config *cfg, int pub_or_sub) { memset(cfg, 0, sizeof(*cfg)); - cfg->port = -1; + cfg->port = PORT_UNDEFINED; cfg->max_inflight = 20; cfg->keepalive = 60; cfg->clean_session = true; @@ -742,7 +742,7 @@ int client_config_line_proc(struct mosq_config *cfg, int pub_or_sub, int argc, c return 1; }else{ cfg->port = atoi(argv[i+1]); - if(cfg->port<1 || cfg->port>65535){ + if(cfg->port<0 || cfg->port>65535){ fprintf(stderr, "Error: Invalid port given: %d\n", cfg->port); return 1; } @@ -974,6 +974,15 @@ int client_config_line_proc(struct mosq_config *cfg, int pub_or_sub, int argc, c cfg->username = strdup(argv[i+1]); } i++; + }else if(!strcmp(argv[i], "--unix")){ + if(i==argc-1){ + fprintf(stderr, "Error: --unix argument given but no socket path specified.\n\n"); + return 1; + }else{ + cfg->host = strdup(argv[i+1]); + cfg->port = 0; + } + i++; }else if(!strcmp(argv[i], "-V") || !strcmp(argv[i], "--protocol-version")){ if(i==argc-1){ fprintf(stderr, "Error: --protocol-version argument given but no version specified.\n\n"); @@ -1174,7 +1183,7 @@ int client_connect(struct mosquitto *mosq, struct mosq_config *cfg) int rc; int port; - if(cfg->port < 0){ + if(cfg->port == PORT_UNDEFINED){ #ifdef WITH_TLS if(cfg->cafile || cfg->capath # ifdef FINAL_WITH_TLS_PSK diff --git a/client/client_shared.h b/client/client_shared.h index 232fa909..4c7edd93 100644 --- a/client/client_shared.h +++ b/client/client_shared.h @@ -38,6 +38,9 @@ Contributors: #define CLIENT_RR 3 #define CLIENT_RESPONSE_TOPIC 4 +#define PORT_UNDEFINED -1 +#define PORT_UNIX 0 + struct mosq_config { char *id; char *id_prefix; diff --git a/client/pub_client.c b/client/pub_client.c index 0debcaee..6ffab6ed 100644 --- a/client/pub_client.c +++ b/client/pub_client.c @@ -345,7 +345,7 @@ void print_usage(void) mosquitto_lib_version(&major, &minor, &revision); printf("mosquitto_pub is a simple mqtt client that will publish a message on a single topic and exit.\n"); printf("mosquitto_pub version %s running on libmosquitto %d.%d.%d.\n\n", VERSION, major, minor, revision); - printf("Usage: mosquitto_pub {[-h host] [-p port] [-u username] [-P password] -t topic | -L URL}\n"); + printf("Usage: mosquitto_pub {[-h host] [--unix path] [-p port] [-u username] [-P password] -t topic | -L URL}\n"); printf(" {-f file | -l | -n | -m message}\n"); printf(" [-c] [-k keepalive] [-q qos] [-r] [--repeat N] [--repeat-delay time]\n"); #ifdef WITH_SRV @@ -405,6 +405,8 @@ void print_usage(void) printf(" --repeat : if publish mode is -f, -m, or -s, then repeat the publish N times.\n"); printf(" --repeat-delay : if using --repeat, wait time seconds between publishes. Defaults to 0.\n"); printf(" --quiet : don't print error messages.\n"); + printf(" --unix : connect to a broker through a unix domain socket instead of a TCP socket,\n"); + printf(" e.g. /tmp/mosquitto.sock\n"); printf(" --will-payload : payload for the client Will, which is sent by the broker in case of\n"); printf(" unexpected disconnection. If not given and will-topic is set, a zero\n"); printf(" length message will be sent.\n"); diff --git a/client/rr_client.c b/client/rr_client.c index e1a8596a..aa8ef5e6 100644 --- a/client/rr_client.c +++ b/client/rr_client.c @@ -162,7 +162,7 @@ void print_usage(void) printf(" Defaults to MQTT v5, where the Request-Response feature will be used, but v3.1.1 can also be used\n"); printf(" with v3.1.1 brokers.\n"); printf("mosquitto_rr version %s running on libmosquitto %d.%d.%d.\n\n", VERSION, major, minor, revision); - printf("Usage: mosquitto_rr {[-h host] [-p port] [-u username] [-P password] -t topic | -L URL} -e response-topic\n"); + printf("Usage: mosquitto_rr {[-h host] [--unix path] [-p port] [-u username] [-P password] -t topic | -L URL} -e response-topic\n"); printf(" [-c] [-k keepalive] [-q qos] [-R]\n"); printf(" [-F format]\n"); #ifndef WIN32 @@ -219,6 +219,8 @@ void print_usage(void) #endif printf(" --help : display this message.\n"); printf(" --quiet : don't print error messages.\n"); + printf(" --unix : connect to a broker through a unix domain socket instead of a TCP socket,\n"); + printf(" e.g. /tmp/mosquitto.sock\n"); printf(" --will-payload : payload for the client Will, which is sent by the broker in case of\n"); printf(" unexpected disconnection. If not given and will-topic is set, a zero\n"); printf(" length message will be sent.\n"); diff --git a/client/sub_client.c b/client/sub_client.c index 86a4476e..6b2f9bd4 100644 --- a/client/sub_client.c +++ b/client/sub_client.c @@ -176,7 +176,7 @@ void print_usage(void) mosquitto_lib_version(&major, &minor, &revision); printf("mosquitto_sub is a simple mqtt client that will subscribe to a set of topics and print all messages it receives.\n"); printf("mosquitto_sub version %s running on libmosquitto %d.%d.%d.\n\n", VERSION, major, minor, revision); - printf("Usage: mosquitto_sub {[-h host] [-p port] [-u username] [-P password] -t topic | -L URL [-t topic]}\n"); + printf("Usage: mosquitto_sub {[-h host] [--unix path] [-p port] [-u username] [-P password] -t topic | -L URL [-t topic]}\n"); printf(" [-c] [-k keepalive] [-q qos]\n"); printf(" [-C msg_count] [-E] [-R] [--retained-only] [--remove-retained] [-T filter_out] [-U topic ...]\n"); printf(" [-F format]\n"); @@ -244,6 +244,8 @@ void print_usage(void) printf(" first non-retained message is received.\n"); printf(" --remove-retained : send a message to the server to clear any received retained messages\n"); printf(" Use -T to filter out messages you do not want to be cleared.\n"); + printf(" --unix : connect to a broker through a unix domain socket instead of a TCP socket,\n"); + printf(" e.g. /tmp/mosquitto.sock\n"); printf(" --will-payload : payload for the client Will, which is sent by the broker in case of\n"); printf(" unexpected disconnection. If not given and will-topic is set, a zero\n"); printf(" length message will be sent.\n"); diff --git a/config.mk b/config.mk index 4b869e6b..11b29bae 100644 --- a/config.mk +++ b/config.mk @@ -97,6 +97,9 @@ WITH_BUNDLED_DEPS:=yes # Build with coverage options WITH_COVERAGE:=no +# Build with unix domain socket support +WITH_UNIX_SOCKETS:=yes + # ============================================================================= # End of user configuration # ============================================================================= @@ -272,6 +275,12 @@ ifeq ($(WITH_DOCS),yes) MAKE_ALL:=$(MAKE_ALL) docs endif +ifeq ($(WITH_UNIX_SOCKETS),yes) + BROKER_CPPFLAGS:=$(BROKER_CPPFLAGS) -DWITH_UNIX_SOCKETS + LIB_CPPFLAGS:=$(LIB_CPPFLAGS) -DWITH_UNIX_SOCKETS + CLIENT_CPPFLAGS:=$(CLIENT_CPPFLAGS) -DWITH_UNIX_SOCKETS +endif + ifeq ($(WITH_WEBSOCKETS),yes) BROKER_CPPFLAGS:=$(BROKER_CPPFLAGS) -DWITH_WEBSOCKETS BROKER_LDADD:=$(BROKER_LDADD) -lwebsockets diff --git a/lib/connect.c b/lib/connect.c index b143321b..f32c2c53 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -42,7 +42,7 @@ static int mosquitto__connect_init(struct mosquitto *mosq, const char *host, int int rc; if(!mosq) return MOSQ_ERR_INVAL; - if(!host || port <= 0) return MOSQ_ERR_INVAL; + if(!host || port < 0) return MOSQ_ERR_INVAL; /* Only MQTT v3.1 requires a client id to be sent */ if(mosq->id == NULL && (mosq->protocol == mosq_p_mqtt31)){ @@ -160,7 +160,7 @@ static int mosquitto__reconnect(struct mosquitto *mosq, bool blocking, const mos int rc; if(!mosq) return MOSQ_ERR_INVAL; - if(!mosq->host || mosq->port <= 0) return MOSQ_ERR_INVAL; + if(!mosq->host || mosq->port < 0) return MOSQ_ERR_INVAL; if(mosq->protocol != mosq_p_mqtt5 && properties) return MOSQ_ERR_NOT_SUPPORTED; if(properties){ diff --git a/lib/net_mosq.c b/lib/net_mosq.c index c2907452..e51196ff 100644 --- a/lib/net_mosq.c +++ b/lib/net_mosq.c @@ -42,6 +42,10 @@ Contributors: # include #endif +#ifdef WITH_UNIX_SOCKETS +# include +#endif + #ifdef __QNX__ #include #endif @@ -364,7 +368,7 @@ int net__try_connect_step2(struct mosquitto *mosq, uint16_t port, mosq_sock_t *s #endif -int net__try_connect(const char *host, uint16_t port, mosq_sock_t *sock, const char *bind_address, bool blocking) +static int net__try_connect_tcp(const char *host, uint16_t port, mosq_sock_t *sock, const char *bind_address, bool blocking) { struct addrinfo hints; struct addrinfo *ainfo, *rp; @@ -461,6 +465,55 @@ int net__try_connect(const char *host, uint16_t port, mosq_sock_t *sock, const c } +#ifdef WITH_UNIX_SOCKETS +static int net__try_connect_unix(const char *host, mosq_sock_t *sock) +{ + struct sockaddr_un addr; + int s; + int rc; + + if(host == NULL || strlen(host) == 0 || strlen(host) > sizeof(addr.sun_path)-1){ + return MOSQ_ERR_INVAL; + } + + memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, host, sizeof(addr.sun_path)-1); + + s = socket(AF_UNIX, SOCK_STREAM, 0); + if(s < 0){ + return MOSQ_ERR_ERRNO; + } + rc = net__socket_nonblock(&s); + if(rc) return rc; + + rc = connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)); + if(rc < 0){ + close(s); + return MOSQ_ERR_ERRNO; + } + + *sock = s; + + return 0; +} +#endif + + +int net__try_connect(const char *host, uint16_t port, mosq_sock_t *sock, const char *bind_address, bool blocking) +{ + if(port == 0){ +#ifdef WITH_UNIX_SOCKETS + return net__try_connect_unix(host, sock); +#else + return MOSQ_ERR_NOT_SUPPORTED; +#endif + }else{ + return net__try_connect_tcp(host, port, sock, bind_address, blocking); + } +} + + #ifdef WITH_TLS void net__print_ssl_error(struct mosquitto *mosq) { @@ -827,7 +880,7 @@ int net__socket_connect(struct mosquitto *mosq, const char *host, uint16_t port, mosq_sock_t sock = INVALID_SOCKET; int rc, rc2; - if(!mosq || !host || !port) return MOSQ_ERR_INVAL; + if(!mosq || !host || port < 0) return MOSQ_ERR_INVAL; rc = net__try_connect(host, port, &sock, bind_address, blocking); if(rc > 0) return rc; diff --git a/lib/tls_mosq.c b/lib/tls_mosq.c index c2f1204f..9b627dea 100644 --- a/lib/tls_mosq.c +++ b/lib/tls_mosq.c @@ -56,7 +56,11 @@ int mosquitto__server_certificate_verify(int preverify_ok, X509_STORE_CTX *ctx) mosq = SSL_get_ex_data(ssl, tls_ex_index_mosq); if(!mosq) return 0; - if(mosq->tls_insecure == false){ + if(mosq->tls_insecure == false +#ifndef WITH_BROKER + && mosq->port != 0 /* no hostname checking for unix sockets */ +#endif + ){ if(X509_STORE_CTX_get_error_depth(ctx) == 0){ /* FIXME - use X509_check_host() etc. for sufficiently new openssl (>=1.1.x) */ cert = X509_STORE_CTX_get_current_cert(ctx); diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml index baed328e..387ff36c 100644 --- a/man/mosquitto.conf.5.xml +++ b/man/mosquitto.conf.5.xml @@ -1159,7 +1159,7 @@ log_timestamp_format %Y-%m-%dT%H:%M:%S - [ ipv4 | ipv6 ] + [ ipv4 | ipv6 | unix ] [path to unix socket] By default, a listener will attempt to listen on all supported IP protocol versions. If you do not @@ -1176,6 +1176,10 @@ log_timestamp_format %Y-%m-%dT%H:%M:%S use IPv6. If you want support for both IPv4 and IPv6, then do not use the option. + On systems that support Unix Domain Sockets, this + option can also be used to create a Unix socket rather + than opening a TCP socket. In this case, the option + should be in the form: . For example: Not reloaded on reload signal. diff --git a/man/mosquitto_pub.1.xml b/man/mosquitto_pub.1.xml index 88cd3041..a386653a 100644 --- a/man/mosquitto_pub.1.xml +++ b/man/mosquitto_pub.1.xml @@ -20,6 +20,7 @@ hostname + socket path port-number username password @@ -537,6 +538,21 @@ argument. + + + + Connect to a broker through a local unix domain socket + instead of a TCP socket. This is a replacement for + and . For example: + + + See the option in + + mosquitto.conf + 5 + to configure Mosquitto to listen on a unix socket. + + diff --git a/man/mosquitto_rr.1.xml b/man/mosquitto_rr.1.xml index e204b5ad..3a783486 100644 --- a/man/mosquitto_rr.1.xml +++ b/man/mosquitto_rr.1.xml @@ -20,6 +20,7 @@ hostname + socket path port-number username password @@ -545,6 +546,21 @@ argument. + + + + Connect to a broker through a local unix domain socket + instead of a TCP socket. This is a replacement for + and . For example: + + + See the option in + + mosquitto.conf + 5 + to configure Mosquitto to listen on a unix socket. + + diff --git a/man/mosquitto_sub.1.xml b/man/mosquitto_sub.1.xml index 01b55398..d80afed1 100644 --- a/man/mosquitto_sub.1.xml +++ b/man/mosquitto_sub.1.xml @@ -20,6 +20,7 @@ hostname + socket path port-number username password @@ -618,6 +619,21 @@ mosquitto_sub -t 'bbc/#' -T bbc/bbc1 --remove-retained argument. + + + + Connect to a broker through a local unix domain socket + instead of a TCP socket. This is a replacement for + and . For example: + + + See the option in + + mosquitto.conf + 5 + to configure Mosquitto to listen on a unix socket. + + diff --git a/mosquitto.conf b/mosquitto.conf index 486895e9..2117d9e8 100644 --- a/mosquitto.conf +++ b/mosquitto.conf @@ -375,6 +375,25 @@ # listener port-number [ip address/host name] #listener +# By default, a listener will attempt to listen on all supported IP protocol +# versions. If you do not have an IPv4 or IPv6 interface you may wish to +# disable support for either of those protocol versions. In particular, note +# that due to the limitations of the websockets library, it will only ever +# attempt to open IPv6 sockets if IPv6 support is compiled in, and so will fail +# if IPv6 is not available. +# +# Set to `ipv4` to force the listener to only use IPv4, or set to `ipv6` to +# force the listener to only use IPv6. If you want support for both IPv4 and +# IPv6, then do not use the socket_domain option. +# +# On systems that support Unix Domain Sockets, this option can also be used to +# create a Unix socket rather than opening a TCP socket. In this case, the +# option should be in the form: +# socket_domain unix +# e.g. `socket_domain unix /tmp/mosquitto.sock` +# +#socket_domain + # Bind the listener to a specific interface. This is similar to # the [ip address/host name] part of the listener definition, but is useful # when an interface has multiple addresses or the address may change. It is diff --git a/src/conf.c b/src/conf.c index ace524c5..544694bb 100644 --- a/src/conf.c +++ b/src/conf.c @@ -322,6 +322,9 @@ void config__cleanup(struct mosquitto__config *config) #endif #ifdef WITH_WEBSOCKETS mosquitto__free(config->listeners[i].http_dir); +#endif +#ifdef WITH_UNIX_SOCKETS + mosquitto__free(config->listeners[i].unix_socket_path); #endif } mosquitto__free(config->listeners); @@ -1894,6 +1897,21 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct cur_listener->socket_domain = AF_INET; }else if(!strcmp(token, "ipv6")){ cur_listener->socket_domain = AF_INET6; +#ifdef WITH_UNIX_SOCKETS + }else if(!strcmp(token, "unix")){ + cur_listener->socket_domain = AF_UNIX; + token = strtok_r(NULL, " ", &saveptr); + if(token){ + cur_listener->unix_socket_path = mosquitto__strdup(token); + if(cur_listener->unix_socket_path == NULL){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); + return MOSQ_ERR_NOMEM; + } + }else{ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Empty socket_domain unix socket path in configuration."); + return MOSQ_ERR_INVAL; + } +#endif }else{ log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid socket_domain value \"%s\" in configuration.", token); return MOSQ_ERR_INVAL; diff --git a/src/mosquitto.c b/src/mosquitto.c index 71919410..f35f58e0 100644 --- a/src/mosquitto.c +++ b/src/mosquitto.c @@ -377,14 +377,19 @@ int main(int argc, char *argv[]) log__printf(NULL, MOSQ_LOG_INFO, "mosquitto version %s terminating", VERSION); -#ifdef WITH_WEBSOCKETS for(i=0; ilistener_count; i++){ +#ifdef WITH_WEBSOCKETS if(int_db.config->listeners[i].ws_context){ libwebsocket_context_destroy(int_db.config->listeners[i].ws_context); } mosquitto__free(int_db.config->listeners[i].ws_protocol); - } #endif +#ifdef WITH_UNIX_SOCKETS + if(int_db.config->listeners[i].unix_socket_path != NULL){ + unlink(int_db.config->listeners[i].unix_socket_path); + } +#endif + } /* FIXME - this isn't quite right, all wills with will delay zero should be * sent now, but those with positive will delay should be persisted and diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index ea2ecbf8..ac75cd93 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -272,6 +272,9 @@ struct mosquitto__listener { struct mosquitto__security_options security_options; struct mosquitto__unpwd *unpwd; struct mosquitto__unpwd *psk_id; +#ifdef WITH_UNIX_SOCKETS + char *unix_socket_path; +#endif }; struct mosquitto__config { diff --git a/src/net.c b/src/net.c index 392972f8..b01aaeb6 100644 --- a/src/net.c +++ b/src/net.c @@ -41,6 +41,10 @@ Contributors: # include #endif +#ifdef WITH_UNIX_SOCKETS +# include "sys/un.h" +#endif + #ifdef __QNX__ #include #endif @@ -551,11 +555,7 @@ int net__tls_load_verify(struct mosquitto__listener *listener) } -/* Creates a socket and listens on port 'port'. - * Returns 1 on failure - * Returns 0 on success. - */ -int net__socket_listen(struct mosquitto__listener *listener) +static int net__socket_listen_tcp(struct mosquitto__listener *listener) { mosq_sock_t sock = INVALID_SOCKET; struct addrinfo hints; @@ -655,17 +655,92 @@ int net__socket_listen(struct mosquitto__listener *listener) } freeaddrinfo(ainfo); + return 0; +} + + +#ifdef WITH_UNIX_SOCKETS +static int net__socket_listen_unix(struct mosquitto__listener *listener) +{ + struct sockaddr_un addr; + int sock; + + if(listener->unix_socket_path == NULL){ + return MOSQ_ERR_INVAL; + } + if(strlen(listener->unix_socket_path) > sizeof(addr.sun_path)-1){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Path to unix socket is too long \"%s\".", listener->unix_socket_path); + return MOSQ_ERR_INVAL; + } + + unlink(listener->unix_socket_path); + log__printf(NULL, MOSQ_LOG_INFO, "Opening unix listen socket on path %s.", listener->unix_socket_path); + memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, listener->unix_socket_path, sizeof(addr.sun_path)-1); + + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if(sock == INVALID_SOCKET){ + net__print_error(MOSQ_LOG_ERR, "Error creating unix socket: %s"); + return 1; + } + listener->sock_count++; + listener->socks = mosquitto__realloc(listener->socks, sizeof(mosq_sock_t)*listener->sock_count); + if(!listener->socks){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); + return MOSQ_ERR_NOMEM; + } + listener->socks[listener->sock_count-1] = sock; + + + if(bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) == -1){ + net__print_error(MOSQ_LOG_ERR, "Error binding unix socket: %s"); + return 1; + } + + if(listen(sock, 10) == -1){ + net__print_error(MOSQ_LOG_ERR, "Error listening to unix socket: %s"); + return 1; + } + + if(net__socket_nonblock(&sock)){ + return 1; + } + + return 0; +} +#endif + + +/* Creates a socket and listens on port 'port'. + * Returns 1 on failure + * Returns 0 on success. + */ +int net__socket_listen(struct mosquitto__listener *listener) +{ + int rc; + + if(!listener) return MOSQ_ERR_INVAL; + +#ifdef WITH_UNIX_SOCKETS + if(listener->socket_domain == AF_UNIX){ + rc = net__socket_listen_unix(listener); + }else +#endif + { + rc = net__socket_listen_tcp(listener); + } + if(rc) return rc; + /* We need to have at least one working socket. */ if(listener->sock_count > 0){ #ifdef WITH_TLS if((listener->cafile || listener->capath) && listener->certfile && listener->keyfile){ if(net__tls_server_ctx(listener)){ - COMPAT_CLOSE(sock); return 1; } if(net__tls_load_verify(listener)){ - COMPAT_CLOSE(sock); return 1; } # ifdef FINAL_WITH_TLS_PSK @@ -678,7 +753,6 @@ int net__socket_listen(struct mosquitto__listener *listener) } if(net__tls_server_ctx(listener)){ - COMPAT_CLOSE(sock); return 1; } SSL_CTX_set_psk_server_callback(listener->ssl_ctx, psk_server_callback); @@ -687,7 +761,6 @@ int net__socket_listen(struct mosquitto__listener *listener) if(rc == 0){ log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to set TLS PSK hint."); net__print_error(MOSQ_LOG_ERR, "Error: %s"); - COMPAT_CLOSE(sock); return 1; } } @@ -716,6 +789,17 @@ int net__socket_get_address(mosq_sock_t sock, char *buf, int len) if(inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&addr)->sin6_addr.s6_addr, buf, len)){ return 0; } +#ifdef WITH_UNIX_SOCKETS + }else if(addr.ss_family == AF_UNIX){ + struct sockaddr_un un; + addrlen = sizeof(struct sockaddr_un); + if(!getsockname(sock, (struct sockaddr *)&un, &addrlen)){ + snprintf(buf, len, "%s", un.sun_path); + }else{ + snprintf(buf, len, "unix-socket"); + } + return 0; +#endif } } return 1;