diff --git a/Android.mk b/Android.mk index d3fe4a4a..fb3fdd2a 100644 --- a/Android.mk +++ b/Android.mk @@ -16,7 +16,7 @@ SERVALD_LOCAL_CFLAGS = \ -DHAVE_STRING_H=1 -DHAVE_ARPA_INET_H=1 -DHAVE_SYS_SOCKET_H=1 \ -DHAVE_SYS_MMAN_H=1 -DHAVE_SYS_TIME_H=1 -DHAVE_POLL_H=1 -DHAVE_NETDB_H=1 \ -DHAVE_JNI_H=1 -DHAVE_STRUCT_UCRED=1 -DHAVE_CRYPTO_SIGN_NACL_GE25519_H=1 \ - -DBYTE_ORDER=_BYTE_ORDER -DHAVE_LINUX_STRUCT_UCRED \ + -DBYTE_ORDER=_BYTE_ORDER -DHAVE_LINUX_STRUCT_UCRED -DUSE_ABSTRACT_NAMESPACE \ -DHAVE_BCOPY -DHAVE_BZERO \ -I$(NACL_INC) \ -I$(SQLITE3_INC) diff --git a/configure.in b/configure.in index 280b828b..5e868e50 100644 --- a/configure.in +++ b/configure.in @@ -107,6 +107,14 @@ AC_CHECK_HEADER([alsa/asoundlib.h], [have_alsa=1], [have_alsa=0]) AS_IF([test x"$have_alsa" = "x1"], [AC_DEFINE([HAVE_ALSA_ASOUNDLIB_H])]) AS_IF([test x"$have_alsa" = "x1"], [AC_SUBST(HAVE_ALSA,1)], [AC_SUBST(HAVE_ALSA,0)]) +dnl Lazy way of checking for Linux +AC_CHECK_HEADER([sys/socket.h]) +AC_CHECK_HEADER([linux/if.h], [AC_DEFINE([USE_ABSTRACT_NAMESPACE])],, [ +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +]) + AC_CHECK_LIB(m,sqrtf,[LDFLAGS="$LDFLAGS -lm"]) AC_CHECK_LIB(nsl,callrpc,[LDFLAGS="$LDFLAGS -lnsl"]) AC_CHECK_LIB(socket,socket,[LDFLAGS="$LDFLAGS -lsocket"]) diff --git a/instance.c b/instance.c index 8c8b93c0..0d301c8b 100644 --- a/instance.c +++ b/instance.c @@ -49,10 +49,10 @@ int form_serval_instance_path(char *buf, size_t bufsiz, const char *path) strbuf_path_join(b, serval_instancepath(), path, NULL); if (!strbuf_overrun(b)) return 1; - WHYF("Cannot form pathname from %s and %s -- buffer too small (%lu bytes)", - alloca_str_toprint(serval_instancepath()), - alloca_str_toprint(path), - (unsigned long)bufsiz); + WHYF("instance path overflow (strlen %lu, sizeof buffer %lu): %s", + (unsigned long)strbuf_count(b), + (unsigned long)bufsiz, + alloca_str_toprint(buf)); return 0; } diff --git a/monitor-client.c b/monitor-client.c index b6a990f4..3c87dcee 100644 --- a/monitor-client.c +++ b/monitor-client.c @@ -41,6 +41,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "conf.h" #include "log.h" #include "str.h" +#include "strbuf_helpers.h" #include "monitor-client.h" #include @@ -65,54 +66,21 @@ struct monitor_state { int bufferBytes; }; -int monitor_socket_name(struct sockaddr_un *name){ - int len; -#ifdef linux - /* Use abstract namespace as Android has no writable FS which supports sockets. - Abstract namespace is just plain better, anyway, as no dead files end up - hanging around. */ - name->sun_path[0] = '\0'; - /* XXX: 104 comes from OSX sys/un.h - no #define (note Linux has UNIX_PATH_MAX and it's 108(!)) */ - snprintf(&name->sun_path[1],104-2,"%s", config.monitor.socket); - /* Doesn't include trailing nul */ - len = 1+strlen(&name->sun_path[1]) + sizeof(name->sun_family); -#else - snprintf(name->sun_path,104-1,"%s/%s", - serval_instancepath(), - config.monitor.socket - ); - /* Includes trailing nul */ - len = 1+strlen(name->sun_path) + sizeof(name->sun_family); -#endif - return len; -} - /* Open monitor interface abstract domain named socket */ int monitor_client_open(struct monitor_state **res) { int fd; + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) + return WHYF_perror("socket(AF_UNIX, SOCK_STREAM, 0)"); struct sockaddr_un addr; - - if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { - WHYF_perror("socket(AF_UNIX, SOCK_STREAM, 0)"); + socklen_t addrlen; + if (socket_setname(&addr, config.monitor.socket, &addrlen) == -1) return -1; - } - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - int len = monitor_socket_name(&addr); - - INFOF("Attempting to connect to %s %s", - addr.sun_path[0] ? "local" : "abstract", - alloca_str_toprint(addr.sun_path[0] ? &addr.sun_path[0] : &addr.sun_path[1]) - ); - - if (connect(fd, (struct sockaddr*)&addr, len) == -1) { - WHYF_perror("connect(%d, %s)", fd, alloca_toprint(-1, &addr, len)); + INFOF("Attempting to connect to %s", alloca_sockaddr(&addr, addrlen)); + if (socket_connect(fd, (struct sockaddr*)&addr, addrlen) == -1) { close(fd); return -1; } - *res = (struct monitor_state*)malloc(sizeof(struct monitor_state)); memset(*res,0,sizeof(struct monitor_state)); return fd; diff --git a/monitor.c b/monitor.c index d8927a04..c47adc28 100644 --- a/monitor.c +++ b/monitor.c @@ -29,6 +29,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "rhizome.h" #include "cli.h" #include "str.h" +#include "strbuf_helpers.h" #include "overlay_address.h" #include "monitor-client.h" @@ -76,45 +77,24 @@ struct profile_total client_stats; int monitor_setup_sockets() { - struct sockaddr_un name; - int len; - int sock; - - bzero(&name, sizeof(name)); - name.sun_family = AF_UNIX; - - if ((sock = socket(AF_UNIX, SOCK_STREAM, 0))==-1) { + int sock = -1; + if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { WHYF_perror("socket(AF_UNIX, SOCK_STREAM, 0)"); goto error; } - - len = monitor_socket_name(&name); -#ifndef linux - unlink(name.sun_path); -#endif - - if(bind(sock, (struct sockaddr *)&name, len)==-1) { - WHYF_perror("bind(%d, %s)", sock, alloca_toprint(-1, &name, len)); + struct sockaddr_un addr; + socklen_t addrlen; + if (socket_setname(&addr, config.monitor.socket, &addrlen) == -1) goto error; - } - if(listen(sock,MAX_MONITOR_SOCKETS)==-1) { - WHYF_perror("listen(%d, %d)", sock, MAX_MONITOR_SOCKETS); + if (socket_bind(sock, (struct sockaddr*)&addr, addrlen) == -1) goto error; - } - - int reuseP=1; - if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseP, sizeof reuseP) < 0) { - WHYF_perror("setsockopt(%d, SOL_SOCKET, SO_REUSEADDR, &%d, %d)", sock, reuseP, (int)sizeof reuseP); + if (socket_listen(sock, MAX_MONITOR_SOCKETS) == -1) + goto error; + if (socket_set_reuseaddr(sock, 1) == -1) WHY("Could not indicate reuse addresses. Not necessarily a problem (yet)"); - } - - int send_buffer_size=64*1024; - if(setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &send_buffer_size, sizeof send_buffer_size)==-1) - WHYF_perror("setsockopt(%d, SOL_SOCKET, SO_RCVBUF, &%d, %d)", sock, send_buffer_size, (int)sizeof send_buffer_size); - + socket_set_rcvbufsize(sock, 64 * 1024); if (config.debug.io || config.debug.verbose_io) - DEBUGF("Monitor server socket bound to %s", alloca_toprint(-1, &name, len)); - + DEBUGF("Monitor server socket bound to %s", alloca_sockaddr(&addr, addrlen)); named_socket.function=monitor_poll; named_stats.name="monitor_poll"; named_socket.stats=&named_stats; @@ -123,8 +103,8 @@ int monitor_setup_sockets() watch(&named_socket); return 0; - error: - if (sock>=0) +error: + if (sock != -1) close(sock); return -1; } diff --git a/overlay_mdp.c b/overlay_mdp.c index a8749619..0b3a8c4e 100644 --- a/overlay_mdp.c +++ b/overlay_mdp.c @@ -29,17 +29,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "mdp_client.h" #include "crypto.h" -struct profile_total mdp_stats={.name="overlay_mdp_poll"}; - -struct sched_ent mdp_abstract={ - .function = overlay_mdp_poll, - .stats = &mdp_stats, -}; - -struct sched_ent mdp_named={ - .function = overlay_mdp_poll, - .stats = &mdp_stats, -}; +static struct profile_total mdp_stats = { .name="overlay_mdp_poll" }; +static struct sched_ent mdp_sock = STRUCT_SCHED_ENT_UNUSED; static int overlay_saw_mdp_frame(struct overlay_frame *frame, overlay_mdp_frame *mdp, time_ms_t now); @@ -79,83 +70,36 @@ static void overlay_mdp_clean_socket_files() int overlay_mdp_setup_sockets() { - struct sockaddr_un name; - int len; + struct sockaddr_un addr; + socklen_t addrlen; - /* Clean old socket files from instance directory. */ + /* Delete stale socket files from instance directory. */ overlay_mdp_clean_socket_files(); - - name.sun_family = AF_UNIX; - -#ifndef HAVE_LINUX_IF_H - /* Abstrack name space (i.e., non-file represented) unix domain sockets are a - linux-only thing. */ - mdp_abstract.poll.fd = -1; -#else - if (mdp_abstract.poll.fd<=0) { - /* Abstract name space unix sockets is a special Linux thing, which is - convenient for us because Android is Linux, but does not have a shared - writable path that is on a UFS partition, so we cannot use traditional - named unix domain sockets. So the abstract name space gives us a solution. */ - name.sun_path[0]=0; - /* XXX The 100 should be replaced with the actual maximum allowed. - Apparently POSIX requires it to be at least 100, but I would still feel - more comfortable with using the appropriate constant. */ - if (!form_serval_instance_path(&name.sun_path[0], sizeof name.sun_path, "mdp.socket")) - return WHY("Cannot construct name of unix domain socket."); - len = 1+strlen(&name.sun_path[1]) + sizeof(name.sun_family); - - mdp_abstract.poll.fd = socket(AF_UNIX, SOCK_DGRAM, 0); - if (mdp_abstract.poll.fd>-1) { - int reuseP=1; - if (setsockopt( mdp_abstract.poll.fd, SOL_SOCKET, SO_REUSEADDR, &reuseP, sizeof(reuseP)) == -1) { - WARN_perror("setsockopt(SO_REUSEADDR)"); - WARN("Could not set socket reuse addresses"); - } - if (bind(mdp_abstract.poll.fd, (struct sockaddr *)&name, len) == -1) { - WARN_perror("bind"); - close(mdp_abstract.poll.fd); - mdp_abstract.poll.fd = -1; - WARN("bind of abstract name space socket failed (not a problem on non-linux systems)"); - } - int send_buffer_size=64*1024; - if (setsockopt(mdp_abstract.poll.fd, SOL_SOCKET, SO_SNDBUF, &send_buffer_size, sizeof(send_buffer_size)) == -1) - WARN_perror("setsockopt(SO_SNDBUF)"); - mdp_abstract.poll.events = POLLIN; - watch(&mdp_abstract); - } - } -#endif - if (mdp_named.poll.fd<=0) { - if (!form_serval_instance_path(&name.sun_path[0], sizeof name.sun_path, "mdp.socket")) - return WHY("Cannot construct name of unix domain socket."); - unlink(&name.sun_path[0]); - len = 0+strlen(&name.sun_path[0]) + sizeof(name.sun_family)+1; - mdp_named.poll.fd = socket(AF_UNIX, SOCK_DGRAM, 0); - if (mdp_named.poll.fd>-1) { - int reuseP=1; - if(setsockopt( mdp_named.poll.fd, SOL_SOCKET, SO_REUSEADDR, &reuseP, sizeof(reuseP)) == -1) { - WARN_perror("setsockopt(SO_REUSEADDR)"); - WARN("Could not set socket reuse addresses"); - } - if (bind(mdp_named.poll.fd, (struct sockaddr *)&name, len) == -1) { - WARN_perror("bind"); - close(mdp_named.poll.fd); - mdp_named.poll.fd = -1; - WARN("Could not bind named unix domain socket"); - } - int send_buffer_size=64*1024; - if (setsockopt(mdp_named.poll.fd, SOL_SOCKET, SO_RCVBUF, &send_buffer_size, sizeof(send_buffer_size)) == -1) - WARN_perror("setsockopt(SO_RCVBUF)"); - mdp_named.function = overlay_mdp_poll; - mdp_named.stats = &mdp_stats; - mdp_named.poll.events = POLLIN; - watch(&mdp_named); - } - } + if (mdp_sock.poll.fd == -1) { + if (socket_setname(&addr, "mdp.socket", &addrlen) == -1) + return -1; + if ((mdp_sock.poll.fd = esocket(AF_UNIX, SOCK_DGRAM, 0)) == -1) + return -1; + if (socket_set_reuseaddr(mdp_sock.poll.fd, 1) == -1) + WARN("Could not set socket to reuse addresses"); + if (socket_bind(mdp_sock.poll.fd, (struct sockaddr *)&addr, addrlen) == -1) { + close(mdp_sock.poll.fd); + mdp_sock.poll.fd = -1; + return -1; + } + socket_set_rcvbufsize(mdp_sock.poll.fd, 64 * 1024); + /* + int buffer_size = 64 * 1024; + if (setsockopt(mdp_sock.poll.fd, SOL_SOCKET, SO_SNDBUF, &buffer_size, sizeof(buffer_size)) == -1) + WARNF_perror("setsockopt(%d,SOL_SOCKET,SO_SNDBUF,&%d,%d)", mdp_sock.poll.fd, buffer_size, sizeof buffer_size); + */ + mdp_sock.function = overlay_mdp_poll; + mdp_sock.stats = &mdp_stats; + mdp_sock.poll.events = POLLIN; + watch(&mdp_sock); + } return 0; - } #define MDP_MAX_BINDINGS 100 @@ -497,7 +441,7 @@ static int overlay_saw_mdp_frame(struct overlay_frame *frame, overlay_mdp_frame addr.sun_family=AF_UNIX; errno=0; int len=overlay_mdp_relevant_bytes(mdp); - int r=sendto(mdp_named.poll.fd,mdp,len,0,(struct sockaddr*)&addr,sizeof(addr)); + int r=sendto(mdp_sock.poll.fd,mdp,len,0,(struct sockaddr*)&addr,sizeof(addr)); if (r==overlay_mdp_relevant_bytes(mdp)) { RETURN(0); } @@ -754,7 +698,7 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP, if (overlay_mdp_check_binding(source, mdp->out.src.port, userGeneratedFrameP, recvaddr, recvaddrlen)){ RETURN(overlay_mdp_reply_error - (mdp_named.poll.fd, + (mdp_sock.poll.fd, (struct sockaddr_un *)recvaddr, recvaddrlen,8, "Source address is invalid (you must bind to a source address before" @@ -767,7 +711,7 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP, flag is not set. Also, MDP_NOSIGN must also be applied, until NaCl cryptobox keys can be used for signing. */ if (!(mdp->packetTypeAndFlags&MDP_NOCRYPT)) - RETURN(overlay_mdp_reply_error(mdp_named.poll.fd, + RETURN(overlay_mdp_reply_error(mdp_sock.poll.fd, recvaddr,recvaddrlen,5, "Broadcast packets cannot be encrypted ")); }else{ @@ -778,9 +722,7 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP, if (mdp->out.ttl == 0) mdp->out.ttl = PAYLOAD_TTL_DEFAULT; else if (mdp->out.ttl > PAYLOAD_TTL_MAX) { - RETURN(overlay_mdp_reply_error(mdp_named.poll.fd, - recvaddr,recvaddrlen,9, - "TTL out of range")); + RETURN(overlay_mdp_reply_error(mdp_sock.poll.fd, recvaddr,recvaddrlen,9, "TTL out of range")); } if (mdp->out.queue == 0) @@ -929,7 +871,7 @@ static int routing_table(struct subscriber *subscriber, void *context){ strcpy(r->interface_name, subscriber->destination->interface->name); else r->interface_name[0]=0; - overlay_mdp_reply(mdp_named.poll.fd, state->recvaddr_un, state->recvaddrlen, &reply); + overlay_mdp_reply(mdp_sock.poll.fd, state->recvaddr_un, state->recvaddrlen, &reply); return 0; } diff --git a/rhizome_fetch.c b/rhizome_fetch.c index 63f6341d..eb287791 100644 --- a/rhizome_fetch.c +++ b/rhizome_fetch.c @@ -189,7 +189,8 @@ int rhizome_fetch_status_html(struct strbuf *b) } static struct sched_ent sched_activate = STRUCT_SCHED_ENT_UNUSED; -static struct profile_total fetch_stats; +static struct profile_total rsnqf_stats = { .name="rhizome_start_next_queued_fetches" }; +static struct profile_total fetch_stats = { .name="rhizome_fetch_poll" }; /* Find a queue suitable for a fetch of the given number of bytes. If there is no suitable queue, * return NULL. @@ -505,15 +506,12 @@ static int schedule_fetch(struct rhizome_fetch_slot *slot) slot->state = RHIZOME_FETCH_CONNECTING; slot->alarm.function = rhizome_fetch_poll; - fetch_stats.name = "rhizome_fetch_poll"; slot->alarm.stats = &fetch_stats; if (slot->peer_ipandport.sin_family == AF_INET && slot->peer_ipandport.sin_port) { /* Transfer via HTTP over IPv4 */ - if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { - WHY_perror("socket"); + if ((sock = esocket(AF_INET, SOCK_STREAM, 0)) == -1) goto bail_http; - } if (set_nonblock(sock) == -1) goto bail_http; char buf[INET_ADDRSTRLEN]; @@ -628,7 +626,7 @@ rhizome_fetch(struct rhizome_fetch_slot *slot, rhizome_manifest *m, const struct bid, m->version, m->fileLength, - alloca_sockaddr(peerip) + alloca_sockaddr(peerip, sizeof(struct sockaddr_in)) ); // If the payload is empty, no need to fetch, so import now. @@ -823,8 +821,6 @@ int rhizome_fetch_has_queue_space(unsigned char log2_size){ * * @author Andrew Bettison */ -struct profile_total rsnqf_stats={.name="rhizome_start_next_queued_fetches"}; - int rhizome_suggest_queue_manifest_import(rhizome_manifest *m, const struct sockaddr_in *peerip,const unsigned char peersid[SID_SIZE]) { IN(); diff --git a/serval.h b/serval.h index 921f4391..b41dbf3f 100644 --- a/serval.h +++ b/serval.h @@ -168,6 +168,17 @@ int create_serval_instance_dir(); int form_serval_instance_path(char *buf, size_t bufsiz, const char *path); void serval_setinstancepath(const char *instancepath); +/* Create a named socket using abstract socket on Linux or a local socket on + * other platforms. + */ +int esocket(int domain, int type, int protocol); +int socket_setname(struct sockaddr_un *sockname, const char *name, socklen_t *addrlen); +int socket_bind(int sock, const struct sockaddr *addr, socklen_t addrlen); +int socket_connect(int sock, const struct sockaddr *addr, socklen_t addrlen); +int socket_listen(int sock, int backlog); +int socket_set_reuseaddr(int fd, int reuseP); +int socket_set_rcvbufsize(int fd, unsigned buffer_size); + #define SERVER_CONFIG_RELOAD_INTERVAL_MS 1000 struct cli_parsed; @@ -587,9 +598,6 @@ int overlay_mdp_get_fds(struct pollfd *fds,int *fdcount,int fdmax); int overlay_mdp_reply_error(int sock, struct sockaddr_un *recvaddr,int recvaddrlen, int error_number,char *message); -extern struct sched_ent mdp_abstract; -extern struct sched_ent mdp_named; - typedef struct sockaddr_mdp { unsigned char sid[SID_SIZE]; diff --git a/socket.c b/socket.c index faa9100d..370e3a94 100644 --- a/socket.c +++ b/socket.c @@ -1,66 +1,115 @@ /* - Copyright (C) 2012 Daniel O'Connor, Serval Project. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +Serval DNA named sockets +Copyright 2013 Serval Project Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifdef HAVE_NETINET_IN_H -#include -#endif -#include -#include -#include -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#include -#include - +#include "serval.h" #include "conf.h" #include "log.h" -#include "socket.h" +#include "strbuf_helpers.h" -/* Set the socket name in the abstract namespace for linux or - * $SERVALINSTANCE_PATH/name for everything else. +/* Under Linux, create a socket name in the abstract namespace. This permits us to use local + * sockets on Android despite its lack of a shared writeable directory on a UFS partition. + * + * On non-Linux systems, create a conventional named local socket in the $SERVALINSTANCE_PATH + * directory. + * + * @author Andrew Bettison + * @author Daniel O'Connor */ -void -socket_setname(struct sockaddr_un *sockname, const char *name, socklen_t *len) { - bzero(sockname, sizeof(*sockname)); - sockname->sun_family = AF_UNIX; - +int socket_setname(struct sockaddr_un *addr, const char *name, socklen_t *addrlen) +{ + bzero(addr, sizeof(*addr)); + addr->sun_family = AF_UNIX; #ifdef USE_ABSTRACT_NAMESPACE - sockname->sun_path[0] = 0; - /* Note: -2 here not -1 because sprintf will put the trailling nul in */ - *len = snprintf(sockname->sun_path + 1, sizeof(sockname->sun_path) - 2, "%s.%s", - DEFAULT_ABSTRACT_PREFIX, name); - if (*len > sizeof(sockname->sun_path) - 2) - FATALF("Socket path too long (%d > %d)", *len, sizeof(sockname->sun_path) - 2); - - /* Doesn't include trailing nul */ - *len = 1 + strlen(sockname->sun_path + 1) + sizeof(sockname->sun_family); -#else - *len = snprintf(sockname->sun_path, sizeof(sockname->sun_path) - 1, "%s/%s", - serval_instancepath(), name); - if (*len > sizeof(sockname->sun_path) - 1) - FATALF("Socket path too long (%d > %d)", *len, sizeof(sockname->sun_path) - 1); - -#ifdef SUN_LEN - *len = SUN_LEN(sockname); -#else - /* Includes trailing nul */ - *len = 1 + strlen(sockname->sun_path) + sizeof(sockname->sun_family); -#endif -#endif + addr->sun_path[0] = '\0'; // mark as Linux abstract socket + int len = snprintf(addr->sun_path + 1, sizeof addr->sun_path - 1, "%s.%s", DEFAULT_ABSTRACT_PREFIX, name); + if (len > sizeof addr->sun_path - 1) + return WHYF("abstract socket name overflow (%d bytes exceeds maximum %u): %s.%s", DEFAULT_ABSTRACT_PREFIX, name, len, sizeof addr->sun_path - 1); + *addrlen = sizeof(addr->sun_family) + 1 + len; // abstract socket names do not have a trailing nul +#else // !USE_ABSTRACT_NAMESPACE + if (!FORM_SERVAL_INSTANCE_PATH(addr->sun_path, name)) + return WHYF("local socket name overflow: %s", name); + *addrlen = sizeof(addr->sun_family) + strlen(addr->sun_path) + 1; +#endif // !USE_ABSTRACT_NAMESPACE + return 0; +} + +int esocket(int domain, int type, int protocol) +{ + int fd; + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) + return WHYF_perror("socket(%s, %s, 0)", alloca_socket_domain(domain), alloca_socket_type(type)); + if (config.debug.io || config.debug.verbose_io) + DEBUGF("socket(%s, %s, 0) -> %d", alloca_socket_domain(domain), alloca_socket_type(type), fd); + return fd; +} + +int socket_connect(int sock, const struct sockaddr *addr, socklen_t addrlen) +{ + if (connect(sock, (struct sockaddr *)addr, addrlen) == -1) + return WHYF_perror("connect(%d,%s,%lu)", sock, alloca_sockaddr(addr, addrlen), (unsigned long)addrlen); + if (config.debug.io || config.debug.verbose_io) + DEBUGF("connect(%d, %s, %lu)", sock, alloca_sockaddr(addr, addrlen), (unsigned long)addrlen); + return 0; +} + +int socket_bind(int sock, const struct sockaddr *addr, socklen_t addrlen) +{ + if (addr->sa_family == AF_UNIX && ((struct sockaddr_un *)addr)->sun_path[0]) { + if (unlink(((struct sockaddr_un *)addr)->sun_path) == -1 && errno != ENOENT) + WARNF_perror("unlink(%s)", alloca_str_toprint(((struct sockaddr_un *)addr)->sun_path)); + if (config.debug.io || config.debug.verbose_io) + DEBUGF("unlink(%s)", alloca_str_toprint(((struct sockaddr_un *)addr)->sun_path)); + } + if (bind(sock, (struct sockaddr *)addr, addrlen) == -1) + return WHYF_perror("bind(%d,%s,%lu)", sock, alloca_sockaddr(addr, addrlen), (unsigned long)addrlen); + if (config.debug.io || config.debug.verbose_io) + DEBUGF("bind(%d, %s, %lu)", sock, alloca_sockaddr(addr, addrlen), (unsigned long)addrlen); + return 0; +} + +int socket_listen(int sock, int backlog) +{ + if (listen(sock, backlog) == -1) + return WHYF_perror("listen(%d,%d)", sock, backlog); + if (config.debug.io || config.debug.verbose_io) + DEBUGF("listen(%d, %d)", sock, backlog); + return 0; +} + +int socket_set_reuseaddr(int sock, int reuseP) +{ + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseP, sizeof reuseP) == -1) { + WARNF_perror("setsockopt(%d,SOL_SOCKET,SO_REUSEADDR,&%d,%u)", sock, reuseP, (unsigned)sizeof reuseP); + return -1; + } + if (config.debug.io || config.debug.verbose_io) + DEBUGF("setsockopt(%d, SOL_SOCKET, SO_REUSEADDR, &%d, %u)", sock, reuseP, (unsigned)sizeof reuseP); + return 0; +} + +int socket_set_rcvbufsize(int sock, unsigned buffer_size) +{ + if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &buffer_size, sizeof buffer_size) == -1) { + WARNF_perror("setsockopt(%d,SOL_SOCKET,SO_RCVBUF,&%u,%u)", sock, buffer_size, (unsigned)sizeof buffer_size); + return -1; + } + if (config.debug.io || config.debug.verbose_io) + DEBUGF("setsockopt(%d, SOL_SOCKET, SO_RCVBUF, &%u, %u)", sock, buffer_size, (unsigned)sizeof buffer_size); + return 0; } diff --git a/socket.h b/socket.h deleted file mode 100644 index 7d3fdb0d..00000000 --- a/socket.h +++ /dev/null @@ -1,5 +0,0 @@ -int socket_bind(const char *name, int type, int reuse); -void socket_setname(struct sockaddr_un *sockname, const char *name, socklen_t *len); -void socket_done(const char *name); - - diff --git a/sourcefiles.mk b/sourcefiles.mk index eb63a20e..077936cb 100644 --- a/sourcefiles.mk +++ b/sourcefiles.mk @@ -22,6 +22,7 @@ SERVAL_SOURCES = \ $(SERVAL_BASE)os.c \ $(SERVAL_BASE)mem.c \ $(SERVAL_BASE)instance.c \ + $(SERVAL_BASE)socket.c \ $(SERVAL_BASE)monitor.c \ $(SERVAL_BASE)monitor-client.c \ $(SERVAL_BASE)monitor-cli.c \ diff --git a/strbuf_helpers.c b/strbuf_helpers.c index 973bf90f..dc8c737d 100644 --- a/strbuf_helpers.c +++ b/strbuf_helpers.c @@ -238,10 +238,10 @@ strbuf strbuf_append_exit_status(strbuf sb, int status) return sb; } -strbuf strbuf_append_sockaddr(strbuf sb, const struct sockaddr *addr) +strbuf strbuf_append_socket_domain(strbuf sb, int domain) { const char *fam = NULL; - switch (addr->sa_family) { + switch (domain) { case AF_UNSPEC: fam = "AF_UNSPEC"; break; case AF_UNIX: fam = "AF_UNIX"; break; case AF_INET: fam = "AF_INET"; break; @@ -278,18 +278,60 @@ strbuf strbuf_append_sockaddr(strbuf sb, const struct sockaddr *addr) if (fam) strbuf_puts(sb, fam); else - strbuf_sprintf(sb, "[%d]", addr->sa_family); + strbuf_sprintf(sb, "[%d]", domain); + return sb; +} + +strbuf strbuf_append_socket_type(strbuf sb, int type) +{ + const char *typ = NULL; + switch (type) { + case SOCK_STREAM: typ = "SOCK_STREAM"; break; + case SOCK_DGRAM: typ = "SOCK_DGRAM"; break; +#ifdef SOCK_RAW + case SOCK_RAW: typ = "SOCK_RAW"; break; +#endif +#ifdef SOCK_RDM + case SOCK_RDM: typ = "SOCK_RDM"; break; +#endif +#ifdef SOCK_SEQPACKET + case SOCK_SEQPACKET: typ = "SOCK_SEQPACKET"; break; +#endif +#ifdef SOCK_PACKET + case SOCK_PACKET: typ = "SOCK_PACKET"; break; +#endif + } + if (typ) + strbuf_puts(sb, typ); + else + strbuf_sprintf(sb, "[%d]", type); + return sb; +} + +strbuf strbuf_append_sockaddr(strbuf sb, const struct sockaddr *addr, socklen_t addrlen) +{ + strbuf_append_socket_domain(sb, addr->sa_family); switch (addr->sa_family) { - case AF_UNIX: - strbuf_putc(sb, ' '); - if (addr->sa_data[0]) - strbuf_toprint_quoted_len(sb, addr->sa_data, "\"\"", sizeof addr->sa_data); - else { - strbuf_puts(sb, "abstract "); - strbuf_toprint_quoted_len(sb, addr->sa_data, "\"\"", sizeof addr->sa_data); + case AF_UNIX: { + size_t len = addrlen > sizeof addr->sa_family ? addrlen - sizeof addr->sa_family : 0; + strbuf_putc(sb, ' '); + if (addr->sa_data[0]) { + strbuf_toprint_quoted_len(sb, "\"\"", addr->sa_data, len); + if (len < 2) + strbuf_sprintf(sb, " (addrlen=%d too short)", (int)addrlen); + if (len && addr->sa_data[len - 1] != '\0') + strbuf_sprintf(sb, " (addrlen=%d, no nul terminator)", (int)addrlen); + } else { + strbuf_puts(sb, "abstract "); + strbuf_toprint_quoted_len(sb, "\"\"", addr->sa_data, len); + if (len == 0) + strbuf_sprintf(sb, " (addrlen=%d too short)", (int)addrlen); + } } break; case AF_INET: { + if (addrlen != sizeof(struct sockaddr_in)) + strbuf_sprintf(sb, " (addrlen=%d should be %d)", (int)addrlen, sizeof(struct sockaddr_in)); const struct sockaddr_in *addr_in = (const struct sockaddr_in *) addr; strbuf_sprintf(sb, " %u.%u.%u.%u:%u", ((unsigned char *) &addr_in->sin_addr.s_addr)[0], @@ -301,8 +343,9 @@ strbuf strbuf_append_sockaddr(strbuf sb, const struct sockaddr *addr) } break; default: { + size_t len = addrlen > sizeof addr->sa_family ? addrlen - sizeof addr->sa_family : 0; int i; - for (i = 0; i < sizeof addr->sa_data; ++i) + for (i = 0; i < len; ++i) strbuf_sprintf(sb, " %02x", addr->sa_data[i]); } break; diff --git a/strbuf_helpers.h b/strbuf_helpers.h index 8a0fc44c..56261542 100644 --- a/strbuf_helpers.h +++ b/strbuf_helpers.h @@ -20,6 +20,15 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #ifndef __STRBUF_HELPERS_H__ #define __STRBUF_HELPERS_H__ +// For socklen_t +#ifdef WIN32 +# include "win32/win32.h" +#else +# ifdef HAVE_SYS_SOCKET_H +# include +# endif +#endif + #include "strbuf.h" /* Append a representation of the given chars in a given buffer (including nul @@ -95,12 +104,24 @@ strbuf strbuf_append_argv(strbuf sb, int argc, const char *const *argv); */ strbuf strbuf_append_exit_status(strbuf sb, int status); +/* Append a textual description of a socket domain code (AF_...). + * @author Andrew Bettison + */ +strbuf strbuf_append_socket_domain(strbuf sb, int domain); +#define alloca_socket_domain(domain) strbuf_str(strbuf_append_socket_domain(strbuf_alloca(15), domain)) + +/* Append a textual description of a socket type code (SOCK_...). + * @author Andrew Bettison + */ +strbuf strbuf_append_socket_type(strbuf sb, int type); +#define alloca_socket_type(type) strbuf_str(strbuf_append_socket_type(strbuf_alloca(15), type)) + /* Append a textual description of a struct sockaddr_in. * @author Andrew Bettison */ struct sockaddr; -strbuf strbuf_append_sockaddr(strbuf sb, const struct sockaddr *); -#define alloca_sockaddr(addr) strbuf_str(strbuf_append_sockaddr(strbuf_alloca(40), (const struct sockaddr *)(addr))) +strbuf strbuf_append_sockaddr(strbuf sb, const struct sockaddr *addr, socklen_t addrlen); +#define alloca_sockaddr(addr, addrlen) strbuf_str(strbuf_append_sockaddr(strbuf_alloca(200), (const struct sockaddr *)(addr), (addrlen))) /* Append a strftime(3) string. * @author Andrew Bettison