Issue #20: merge branch 'sockets' into 'development'

Daniel's improvements to the local file/abstract socket code, with many
improvements to bring it up to date.
This commit is contained in:
Andrew Bettison 2013-09-18 16:36:28 +09:30
commit 2b3119b49b
13 changed files with 266 additions and 255 deletions

View File

@ -16,7 +16,7 @@ SERVALD_LOCAL_CFLAGS = \
-DHAVE_STRING_H=1 -DHAVE_ARPA_INET_H=1 -DHAVE_SYS_SOCKET_H=1 \ -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_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 \ -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 \ -DHAVE_BCOPY -DHAVE_BZERO \
-I$(NACL_INC) \ -I$(NACL_INC) \
-I$(SQLITE3_INC) -I$(SQLITE3_INC)

View File

@ -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_DEFINE([HAVE_ALSA_ASOUNDLIB_H])])
AS_IF([test x"$have_alsa" = "x1"], [AC_SUBST(HAVE_ALSA,1)], [AC_SUBST(HAVE_ALSA,0)]) 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 <sys/socket.h>
#endif
])
AC_CHECK_LIB(m,sqrtf,[LDFLAGS="$LDFLAGS -lm"]) AC_CHECK_LIB(m,sqrtf,[LDFLAGS="$LDFLAGS -lm"])
AC_CHECK_LIB(nsl,callrpc,[LDFLAGS="$LDFLAGS -lnsl"]) AC_CHECK_LIB(nsl,callrpc,[LDFLAGS="$LDFLAGS -lnsl"])
AC_CHECK_LIB(socket,socket,[LDFLAGS="$LDFLAGS -lsocket"]) AC_CHECK_LIB(socket,socket,[LDFLAGS="$LDFLAGS -lsocket"])

View File

@ -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); strbuf_path_join(b, serval_instancepath(), path, NULL);
if (!strbuf_overrun(b)) if (!strbuf_overrun(b))
return 1; return 1;
WHYF("Cannot form pathname from %s and %s -- buffer too small (%lu bytes)", WHYF("instance path overflow (strlen %lu, sizeof buffer %lu): %s",
alloca_str_toprint(serval_instancepath()), (unsigned long)strbuf_count(b),
alloca_str_toprint(path), (unsigned long)bufsiz,
(unsigned long)bufsiz); alloca_str_toprint(buf));
return 0; return 0;
} }

View File

@ -41,6 +41,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "conf.h" #include "conf.h"
#include "log.h" #include "log.h"
#include "str.h" #include "str.h"
#include "strbuf_helpers.h"
#include "monitor-client.h" #include "monitor-client.h"
#include <ctype.h> #include <ctype.h>
@ -65,54 +66,21 @@ struct monitor_state {
int bufferBytes; 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 */ /* Open monitor interface abstract domain named socket */
int monitor_client_open(struct monitor_state **res) int monitor_client_open(struct monitor_state **res)
{ {
int fd; int fd;
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
return WHYF_perror("socket(AF_UNIX, SOCK_STREAM, 0)");
struct sockaddr_un addr; struct sockaddr_un addr;
socklen_t addrlen;
if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { if (socket_setname(&addr, config.monitor.socket, &addrlen) == -1)
WHYF_perror("socket(AF_UNIX, SOCK_STREAM, 0)");
return -1; return -1;
} INFOF("Attempting to connect to %s", alloca_sockaddr(&addr, addrlen));
if (socket_connect(fd, (struct sockaddr*)&addr, addrlen) == -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));
close(fd); close(fd);
return -1; return -1;
} }
*res = (struct monitor_state*)malloc(sizeof(struct monitor_state)); *res = (struct monitor_state*)malloc(sizeof(struct monitor_state));
memset(*res,0,sizeof(struct monitor_state)); memset(*res,0,sizeof(struct monitor_state));
return fd; return fd;

View File

@ -29,6 +29,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "rhizome.h" #include "rhizome.h"
#include "cli.h" #include "cli.h"
#include "str.h" #include "str.h"
#include "strbuf_helpers.h"
#include "overlay_address.h" #include "overlay_address.h"
#include "monitor-client.h" #include "monitor-client.h"
@ -76,45 +77,24 @@ struct profile_total client_stats;
int monitor_setup_sockets() int monitor_setup_sockets()
{ {
struct sockaddr_un name; int sock = -1;
int len; if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
int sock;
bzero(&name, sizeof(name));
name.sun_family = AF_UNIX;
if ((sock = socket(AF_UNIX, SOCK_STREAM, 0))==-1) {
WHYF_perror("socket(AF_UNIX, SOCK_STREAM, 0)"); WHYF_perror("socket(AF_UNIX, SOCK_STREAM, 0)");
goto error; goto error;
} }
struct sockaddr_un addr;
len = monitor_socket_name(&name); socklen_t addrlen;
#ifndef linux if (socket_setname(&addr, config.monitor.socket, &addrlen) == -1)
unlink(name.sun_path);
#endif
if(bind(sock, (struct sockaddr *)&name, len)==-1) {
WHYF_perror("bind(%d, %s)", sock, alloca_toprint(-1, &name, len));
goto error; goto error;
} if (socket_bind(sock, (struct sockaddr*)&addr, addrlen) == -1)
if(listen(sock,MAX_MONITOR_SOCKETS)==-1) {
WHYF_perror("listen(%d, %d)", sock, MAX_MONITOR_SOCKETS);
goto error; goto error;
} if (socket_listen(sock, MAX_MONITOR_SOCKETS) == -1)
goto error;
int reuseP=1; if (socket_set_reuseaddr(sock, 1) == -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);
WHY("Could not indicate reuse addresses. Not necessarily a problem (yet)"); WHY("Could not indicate reuse addresses. Not necessarily a problem (yet)");
} socket_set_rcvbufsize(sock, 64 * 1024);
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);
if (config.debug.io || config.debug.verbose_io) 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_socket.function=monitor_poll;
named_stats.name="monitor_poll"; named_stats.name="monitor_poll";
named_socket.stats=&named_stats; named_socket.stats=&named_stats;
@ -123,8 +103,8 @@ int monitor_setup_sockets()
watch(&named_socket); watch(&named_socket);
return 0; return 0;
error: error:
if (sock>=0) if (sock != -1)
close(sock); close(sock);
return -1; return -1;
} }

View File

@ -29,17 +29,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "mdp_client.h" #include "mdp_client.h"
#include "crypto.h" #include "crypto.h"
struct profile_total mdp_stats={.name="overlay_mdp_poll"}; static struct profile_total mdp_stats = { .name="overlay_mdp_poll" };
static struct sched_ent mdp_sock = STRUCT_SCHED_ENT_UNUSED;
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 int overlay_saw_mdp_frame(struct overlay_frame *frame, overlay_mdp_frame *mdp, time_ms_t now); 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() int overlay_mdp_setup_sockets()
{ {
struct sockaddr_un name; struct sockaddr_un addr;
int len; socklen_t addrlen;
/* Clean old socket files from instance directory. */ /* Delete stale socket files from instance directory. */
overlay_mdp_clean_socket_files(); overlay_mdp_clean_socket_files();
name.sun_family = AF_UNIX; if (mdp_sock.poll.fd == -1) {
if (socket_setname(&addr, "mdp.socket", &addrlen) == -1)
#ifndef HAVE_LINUX_IF_H return -1;
/* Abstrack name space (i.e., non-file represented) unix domain sockets are a if ((mdp_sock.poll.fd = esocket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
linux-only thing. */ return -1;
mdp_abstract.poll.fd = -1; if (socket_set_reuseaddr(mdp_sock.poll.fd, 1) == -1)
#else WARN("Could not set socket to reuse addresses");
if (mdp_abstract.poll.fd<=0) { if (socket_bind(mdp_sock.poll.fd, (struct sockaddr *)&addr, addrlen) == -1) {
/* Abstract name space unix sockets is a special Linux thing, which is close(mdp_sock.poll.fd);
convenient for us because Android is Linux, but does not have a shared mdp_sock.poll.fd = -1;
writable path that is on a UFS partition, so we cannot use traditional return -1;
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) { socket_set_rcvbufsize(mdp_sock.poll.fd, 64 * 1024);
WARN_perror("bind"); /*
close(mdp_abstract.poll.fd); int buffer_size = 64 * 1024;
mdp_abstract.poll.fd = -1; if (setsockopt(mdp_sock.poll.fd, SOL_SOCKET, SO_SNDBUF, &buffer_size, sizeof(buffer_size)) == -1)
WARN("bind of abstract name space socket failed (not a problem on non-linux systems)"); 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);
} }
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);
}
}
return 0; return 0;
} }
#define MDP_MAX_BINDINGS 100 #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; addr.sun_family=AF_UNIX;
errno=0; errno=0;
int len=overlay_mdp_relevant_bytes(mdp); 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)) { if (r==overlay_mdp_relevant_bytes(mdp)) {
RETURN(0); 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, if (overlay_mdp_check_binding(source, mdp->out.src.port, userGeneratedFrameP,
recvaddr, recvaddrlen)){ recvaddr, recvaddrlen)){
RETURN(overlay_mdp_reply_error RETURN(overlay_mdp_reply_error
(mdp_named.poll.fd, (mdp_sock.poll.fd,
(struct sockaddr_un *)recvaddr, (struct sockaddr_un *)recvaddr,
recvaddrlen,8, recvaddrlen,8,
"Source address is invalid (you must bind to a source address before" "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 flag is not set. Also, MDP_NOSIGN must also be applied, until
NaCl cryptobox keys can be used for signing. */ NaCl cryptobox keys can be used for signing. */
if (!(mdp->packetTypeAndFlags&MDP_NOCRYPT)) 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, recvaddr,recvaddrlen,5,
"Broadcast packets cannot be encrypted ")); "Broadcast packets cannot be encrypted "));
}else{ }else{
@ -778,9 +722,7 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
if (mdp->out.ttl == 0) if (mdp->out.ttl == 0)
mdp->out.ttl = PAYLOAD_TTL_DEFAULT; mdp->out.ttl = PAYLOAD_TTL_DEFAULT;
else if (mdp->out.ttl > PAYLOAD_TTL_MAX) { else if (mdp->out.ttl > PAYLOAD_TTL_MAX) {
RETURN(overlay_mdp_reply_error(mdp_named.poll.fd, RETURN(overlay_mdp_reply_error(mdp_sock.poll.fd, recvaddr,recvaddrlen,9, "TTL out of range"));
recvaddr,recvaddrlen,9,
"TTL out of range"));
} }
if (mdp->out.queue == 0) 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); strcpy(r->interface_name, subscriber->destination->interface->name);
else else
r->interface_name[0]=0; 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; return 0;
} }

View File

@ -189,7 +189,8 @@ int rhizome_fetch_status_html(struct strbuf *b)
} }
static struct sched_ent sched_activate = STRUCT_SCHED_ENT_UNUSED; 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, /* Find a queue suitable for a fetch of the given number of bytes. If there is no suitable queue,
* return NULL. * return NULL.
@ -505,15 +506,12 @@ static int schedule_fetch(struct rhizome_fetch_slot *slot)
slot->state = RHIZOME_FETCH_CONNECTING; slot->state = RHIZOME_FETCH_CONNECTING;
slot->alarm.function = rhizome_fetch_poll; slot->alarm.function = rhizome_fetch_poll;
fetch_stats.name = "rhizome_fetch_poll";
slot->alarm.stats = &fetch_stats; slot->alarm.stats = &fetch_stats;
if (slot->peer_ipandport.sin_family == AF_INET && slot->peer_ipandport.sin_port) { if (slot->peer_ipandport.sin_family == AF_INET && slot->peer_ipandport.sin_port) {
/* Transfer via HTTP over IPv4 */ /* Transfer via HTTP over IPv4 */
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { if ((sock = esocket(AF_INET, SOCK_STREAM, 0)) == -1)
WHY_perror("socket");
goto bail_http; goto bail_http;
}
if (set_nonblock(sock) == -1) if (set_nonblock(sock) == -1)
goto bail_http; goto bail_http;
char buf[INET_ADDRSTRLEN]; char buf[INET_ADDRSTRLEN];
@ -628,7 +626,7 @@ rhizome_fetch(struct rhizome_fetch_slot *slot, rhizome_manifest *m, const struct
bid, bid,
m->version, m->version,
m->fileLength, m->fileLength,
alloca_sockaddr(peerip) alloca_sockaddr(peerip, sizeof(struct sockaddr_in))
); );
// If the payload is empty, no need to fetch, so import now. // 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 <andrew@servalproject.com> * @author Andrew Bettison <andrew@servalproject.com>
*/ */
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]) int rhizome_suggest_queue_manifest_import(rhizome_manifest *m, const struct sockaddr_in *peerip,const unsigned char peersid[SID_SIZE])
{ {
IN(); IN();

View File

@ -168,6 +168,17 @@ int create_serval_instance_dir();
int form_serval_instance_path(char *buf, size_t bufsiz, const char *path); int form_serval_instance_path(char *buf, size_t bufsiz, const char *path);
void serval_setinstancepath(const char *instancepath); 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 #define SERVER_CONFIG_RELOAD_INTERVAL_MS 1000
struct cli_parsed; 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, int overlay_mdp_reply_error(int sock,
struct sockaddr_un *recvaddr,int recvaddrlen, struct sockaddr_un *recvaddr,int recvaddrlen,
int error_number,char *message); int error_number,char *message);
extern struct sched_ent mdp_abstract;
extern struct sched_ent mdp_named;
typedef struct sockaddr_mdp { typedef struct sockaddr_mdp {
unsigned char sid[SID_SIZE]; unsigned char sid[SID_SIZE];

157
socket.c
View File

@ -1,66 +1,115 @@
/* /*
Copyright (C) 2012 Daniel O'Connor, Serval Project. Serval DNA named sockets
Copyright 2013 Serval Project Inc.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2 as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version. of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
#ifdef HAVE_NETINET_IN_H #include "serval.h"
#include <netinet/in.h>
#endif
#include <stdio.h>
#include <strings.h>
#include <sys/errno.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#include <sys/un.h>
#include <unistd.h>
#include "conf.h" #include "conf.h"
#include "log.h" #include "log.h"
#include "socket.h" #include "strbuf_helpers.h"
/* Set the socket name in the abstract namespace for linux or /* Under Linux, create a socket name in the abstract namespace. This permits us to use local
* $SERVALINSTANCE_PATH/name for everything else. * 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 <andrew@servalproject.com>
* @author Daniel O'Connor <daniel@servalproject.com>
*/ */
void int socket_setname(struct sockaddr_un *addr, const char *name, socklen_t *addrlen)
socket_setname(struct sockaddr_un *sockname, const char *name, socklen_t *len) { {
bzero(sockname, sizeof(*sockname)); bzero(addr, sizeof(*addr));
sockname->sun_family = AF_UNIX; addr->sun_family = AF_UNIX;
#ifdef USE_ABSTRACT_NAMESPACE #ifdef USE_ABSTRACT_NAMESPACE
sockname->sun_path[0] = 0; addr->sun_path[0] = '\0'; // mark as Linux abstract socket
/* Note: -2 here not -1 because sprintf will put the trailling nul in */ int len = snprintf(addr->sun_path + 1, sizeof addr->sun_path - 1, "%s.%s", DEFAULT_ABSTRACT_PREFIX, name);
*len = snprintf(sockname->sun_path + 1, sizeof(sockname->sun_path) - 2, "%s.%s", if (len > sizeof addr->sun_path - 1)
DEFAULT_ABSTRACT_PREFIX, name); return WHYF("abstract socket name overflow (%d bytes exceeds maximum %u): %s.%s", DEFAULT_ABSTRACT_PREFIX, name, len, sizeof addr->sun_path - 1);
if (*len > sizeof(sockname->sun_path) - 2) *addrlen = sizeof(addr->sun_family) + 1 + len; // abstract socket names do not have a trailing nul
FATALF("Socket path too long (%d > %d)", *len, sizeof(sockname->sun_path) - 2); #else // !USE_ABSTRACT_NAMESPACE
if (!FORM_SERVAL_INSTANCE_PATH(addr->sun_path, name))
/* Doesn't include trailing nul */ return WHYF("local socket name overflow: %s", name);
*len = 1 + strlen(sockname->sun_path + 1) + sizeof(sockname->sun_family); *addrlen = sizeof(addr->sun_family) + strlen(addr->sun_path) + 1;
#else #endif // !USE_ABSTRACT_NAMESPACE
*len = snprintf(sockname->sun_path, sizeof(sockname->sun_path) - 1, "%s/%s", return 0;
serval_instancepath(), name); }
if (*len > sizeof(sockname->sun_path) - 1)
FATALF("Socket path too long (%d > %d)", *len, sizeof(sockname->sun_path) - 1); int esocket(int domain, int type, int protocol)
{
#ifdef SUN_LEN int fd;
*len = SUN_LEN(sockname); if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
#else return WHYF_perror("socket(%s, %s, 0)", alloca_socket_domain(domain), alloca_socket_type(type));
/* Includes trailing nul */ if (config.debug.io || config.debug.verbose_io)
*len = 1 + strlen(sockname->sun_path) + sizeof(sockname->sun_family); DEBUGF("socket(%s, %s, 0) -> %d", alloca_socket_domain(domain), alloca_socket_type(type), fd);
#endif return fd;
#endif }
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;
} }

View File

@ -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);

View File

@ -22,6 +22,7 @@ SERVAL_SOURCES = \
$(SERVAL_BASE)os.c \ $(SERVAL_BASE)os.c \
$(SERVAL_BASE)mem.c \ $(SERVAL_BASE)mem.c \
$(SERVAL_BASE)instance.c \ $(SERVAL_BASE)instance.c \
$(SERVAL_BASE)socket.c \
$(SERVAL_BASE)monitor.c \ $(SERVAL_BASE)monitor.c \
$(SERVAL_BASE)monitor-client.c \ $(SERVAL_BASE)monitor-client.c \
$(SERVAL_BASE)monitor-cli.c \ $(SERVAL_BASE)monitor-cli.c \

View File

@ -238,10 +238,10 @@ strbuf strbuf_append_exit_status(strbuf sb, int status)
return sb; 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; const char *fam = NULL;
switch (addr->sa_family) { switch (domain) {
case AF_UNSPEC: fam = "AF_UNSPEC"; break; case AF_UNSPEC: fam = "AF_UNSPEC"; break;
case AF_UNIX: fam = "AF_UNIX"; break; case AF_UNIX: fam = "AF_UNIX"; break;
case AF_INET: fam = "AF_INET"; break; case AF_INET: fam = "AF_INET"; break;
@ -278,18 +278,60 @@ strbuf strbuf_append_sockaddr(strbuf sb, const struct sockaddr *addr)
if (fam) if (fam)
strbuf_puts(sb, fam); strbuf_puts(sb, fam);
else 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) { switch (addr->sa_family) {
case AF_UNIX: case AF_UNIX: {
size_t len = addrlen > sizeof addr->sa_family ? addrlen - sizeof addr->sa_family : 0;
strbuf_putc(sb, ' '); strbuf_putc(sb, ' ');
if (addr->sa_data[0]) if (addr->sa_data[0]) {
strbuf_toprint_quoted_len(sb, addr->sa_data, "\"\"", sizeof addr->sa_data); strbuf_toprint_quoted_len(sb, "\"\"", addr->sa_data, len);
else { 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_puts(sb, "abstract ");
strbuf_toprint_quoted_len(sb, addr->sa_data, "\"\"", sizeof addr->sa_data); strbuf_toprint_quoted_len(sb, "\"\"", addr->sa_data, len);
if (len == 0)
strbuf_sprintf(sb, " (addrlen=%d too short)", (int)addrlen);
}
} }
break; break;
case AF_INET: { 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; const struct sockaddr_in *addr_in = (const struct sockaddr_in *) addr;
strbuf_sprintf(sb, " %u.%u.%u.%u:%u", strbuf_sprintf(sb, " %u.%u.%u.%u:%u",
((unsigned char *) &addr_in->sin_addr.s_addr)[0], ((unsigned char *) &addr_in->sin_addr.s_addr)[0],
@ -301,8 +343,9 @@ strbuf strbuf_append_sockaddr(strbuf sb, const struct sockaddr *addr)
} }
break; break;
default: { default: {
size_t len = addrlen > sizeof addr->sa_family ? addrlen - sizeof addr->sa_family : 0;
int i; 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]); strbuf_sprintf(sb, " %02x", addr->sa_data[i]);
} }
break; break;

View File

@ -20,6 +20,15 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifndef __STRBUF_HELPERS_H__ #ifndef __STRBUF_HELPERS_H__
#define __STRBUF_HELPERS_H__ #define __STRBUF_HELPERS_H__
// For socklen_t
#ifdef WIN32
# include "win32/win32.h"
#else
# ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
# endif
#endif
#include "strbuf.h" #include "strbuf.h"
/* Append a representation of the given chars in a given buffer (including nul /* 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); strbuf strbuf_append_exit_status(strbuf sb, int status);
/* Append a textual description of a socket domain code (AF_...).
* @author Andrew Bettison <andrew@servalproject.com>
*/
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 <andrew@servalproject.com>
*/
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. /* Append a textual description of a struct sockaddr_in.
* @author Andrew Bettison <andrew@servalproject.com> * @author Andrew Bettison <andrew@servalproject.com>
*/ */
struct sockaddr; struct sockaddr;
strbuf strbuf_append_sockaddr(strbuf sb, const struct sockaddr *); strbuf strbuf_append_sockaddr(strbuf sb, const struct sockaddr *addr, socklen_t addrlen);
#define alloca_sockaddr(addr) strbuf_str(strbuf_append_sockaddr(strbuf_alloca(40), (const struct sockaddr *)(addr))) #define alloca_sockaddr(addr, addrlen) strbuf_str(strbuf_append_sockaddr(strbuf_alloca(200), (const struct sockaddr *)(addr), (addrlen)))
/* Append a strftime(3) string. /* Append a strftime(3) string.
* @author Andrew Bettison <andrew@servalproject.com> * @author Andrew Bettison <andrew@servalproject.com>