From 87aa8f1901e26bc377f3035a485d35c417d0255a Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 6 Oct 2011 21:24:13 +0200 Subject: [PATCH] Add support for client/server connection over unix domain sockets Signed-off-by: Jens Axboe --- client.c | 65 +++++++++++++++++++++++---- init.c | 4 +- server.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++----- server.h | 1 + 4 files changed, 180 insertions(+), 21 deletions(-) diff --git a/client.c b/client.c index 9806b41c..88da9a1e 100644 --- a/client.c +++ b/client.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -24,11 +25,13 @@ struct fio_client { struct flist_head fd_hash_list; struct flist_head name_hash_list; struct sockaddr_in addr; + struct sockaddr_un addr_un; char *hostname; int fd; int state; int skip_newline; + int is_sock; uint16_t argc; char **argv; @@ -184,7 +187,12 @@ void fio_client_add(const char *hostname) INIT_FLIST_HEAD(&client->fd_hash_list); INIT_FLIST_HEAD(&client->name_hash_list); - client->hostname = strdup(hostname); + if (!strncmp(hostname, "sock:", 5)) { + client->hostname = strdup(hostname + 5); + client->is_sock = 1; + } else + client->hostname = strdup(hostname); + client->fd = -1; fio_client_add_name_hash(client); @@ -195,13 +203,10 @@ void fio_client_add(const char *hostname) nr_clients++; } -static int fio_client_connect(struct fio_client *client) +static int fio_client_connect_ip(struct fio_client *client) { int fd; - dprint(FD_NET, "client: connect to host %s\n", client->hostname); - - memset(&client->addr, 0, sizeof(client->addr)); client->addr.sin_family = AF_INET; client->addr.sin_port = htons(fio_net_port); @@ -213,7 +218,7 @@ static int fio_client_connect(struct fio_client *client) log_err("fio: gethostbyname: %s\n", strerror(errno)); log_err("fio: failed looking up hostname %s\n", client->hostname); - return 1; + return -1; } memcpy(&client->addr.sin_addr, hent->h_addr, 4); @@ -222,15 +227,59 @@ static int fio_client_connect(struct fio_client *client) fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { log_err("fio: socket: %s\n", strerror(errno)); - return 1; + return -1; } if (connect(fd, (struct sockaddr *) &client->addr, sizeof(client->addr)) < 0) { log_err("fio: connect: %s\n", strerror(errno)); log_err("fio: failed to connect to %s\n", client->hostname); - return 1; + return -1; + } + + return fd; +} + +static int fio_client_connect_sock(struct fio_client *client) +{ + struct sockaddr_un *addr = &client->addr_un; + fio_socklen_t len; + int fd; + + memset(addr, 0, sizeof(*addr)); + addr->sun_family = AF_UNIX; + strcpy(addr->sun_path, client->hostname); + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + log_err("fio: socket: %s\n", strerror(errno)); + return -1; + } + + len = sizeof(addr->sun_family) + strlen(addr->sun_path) + 1; + if (connect(fd, (struct sockaddr *) addr, len) < 0) { + log_err("fio: connect; %s\n", strerror(errno)); + return -1; } + return fd; +} + +static int fio_client_connect(struct fio_client *client) +{ + int fd; + + dprint(FD_NET, "client: connect to host %s\n", client->hostname); + + memset(&client->addr, 0, sizeof(client->addr)); + + if (client->is_sock) + fd = fio_client_connect_sock(client); + else + fd = fio_client_connect_ip(client); + + if (fd < 0) + return 1; + client->fd = fd; fio_client_add_fd_hash(client); client->state = Client_connected; diff --git a/init.c b/init.c index 1cf8e598..486b7435 100644 --- a/init.c +++ b/init.c @@ -188,7 +188,7 @@ static struct option l_opts[FIO_NR_OPTIONS] = { }, { .name = (char *) "server", - .has_arg = no_argument, + .has_arg = optional_argument, .val = 'S', }, { .name = (char *) "daemonize", @@ -1410,6 +1410,8 @@ int parse_cmd_line(int argc, char *argv[]) exit_val = 1; break; } + if (optarg) + fio_server_add_arg(optarg); is_backend = 1; backend = 1; break; diff --git a/server.c b/server.c index c4a0b7ef..ba9558ce 100644 --- a/server.c +++ b/server.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include #include @@ -25,6 +27,9 @@ int fio_net_port = 8765; int exit_backend = 0; static int server_fd = -1; +static char *fio_server_arg; +static char *bind_sock; +static struct sockaddr_in saddr_in; int fio_send_data(int sk, const void *p, unsigned int len) { @@ -636,14 +641,9 @@ int fio_server_log(const char *format, ...) return fio_server_text_output(buffer, len); } -static int fio_server(void) +static int fio_init_server_ip(void) { - struct sockaddr_in saddr_in; - struct sockaddr addr; - fio_socklen_t len; - int sk, opt, ret; - - dprint(FD_NET, "starting server\n"); + int sk, opt; sk = socket(AF_INET, SOCK_STREAM, 0); if (sk < 0) { @@ -664,7 +664,6 @@ static int fio_server(void) #endif saddr_in.sin_family = AF_INET; - saddr_in.sin_addr.s_addr = htonl(INADDR_ANY); saddr_in.sin_port = htons(fio_net_port); if (bind(sk, (struct sockaddr *) &saddr_in, sizeof(saddr_in)) < 0) { @@ -672,19 +671,122 @@ static int fio_server(void) return -1; } + return sk; +} + +static int fio_init_server_sock(void) +{ + struct sockaddr_un addr; + fio_socklen_t len; + mode_t mode; + int sk; + + sk = socket(AF_UNIX, SOCK_STREAM, 0); + if (sk < 0) { + log_err("fio: socket: %s\n", strerror(errno)); + return -1; + } + + mode = umask(000); + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, bind_sock); + unlink(bind_sock); + + len = sizeof(addr.sun_family) + strlen(bind_sock) + 1; + + if (bind(sk, (struct sockaddr *) &addr, len) < 0) { + log_err("fio: bind: %s\n", strerror(errno)); + return -1; + } + + umask(mode); + return sk; +} + +static int fio_init_server_connection(void) +{ + int sk; + + dprint(FD_NET, "starting server\n"); + + if (!bind_sock) + sk = fio_init_server_ip(); + else + sk = fio_init_server_sock(); + + if (sk < 0) + return sk; + if (listen(sk, 1) < 0) { log_err("fio: listen: %s\n", strerror(errno)); return -1; } - len = sizeof(addr); - if (getsockname(sk, &addr, &len) < 0) { - log_err("fio: getsockname: %s\n", strerror(errno)); - return -1; + return sk; +} + +/* + * Server arg should be one of: + * + * sock:/path/to/socket + * ip:1.2.3.4 + * 1.2.3.4 + * + * Where sock uses unix domain sockets, and ip binds the server to + * a specific interface. If no arguments are given to the server, it + * uses IP and binds to 0.0.0.0. + * + */ +static int fio_handle_server_arg(void) +{ + saddr_in.sin_addr.s_addr = htonl(INADDR_ANY); + + if (!fio_server_arg) + return 0; + if (!strncmp(fio_server_arg, "sock:", 5)) { + bind_sock = fio_server_arg += 5; + return 0; + } else { + char *host = fio_server_arg; + + if (!strncmp(host, "ip:", 3)) + host += 3; + + if (inet_aton(host, &saddr_in.sin_addr) != 1) { + struct hostent *hent; + + hent = gethostbyname(host); + if (hent) + memcpy(&saddr_in.sin_addr, hent->h_addr, 4); + } + return 0; } +} + +static int fio_server(void) +{ + int sk, ret; + + dprint(FD_NET, "starting server\n"); + + if (fio_handle_server_arg()) + return -1; + + sk = fio_init_server_connection(); + if (sk < 0) + return -1; ret = accept_loop(sk); + close(sk); + + if (fio_server_arg) { + free(fio_server_arg); + fio_server_arg = NULL; + } + return ret; } @@ -735,3 +837,8 @@ int fio_start_server(int daemonize) log_syslog = 1; return fio_server(); } + +void fio_server_add_arg(const char *arg) +{ + fio_server_arg = strdup(arg); +} diff --git a/server.h b/server.h index b895dc31..0e35fde1 100644 --- a/server.h +++ b/server.h @@ -76,6 +76,7 @@ extern int fio_server_text_output(const char *, unsigned int len); extern int fio_server_log(const char *format, ...); extern int fio_net_send_cmd(int, uint16_t, const void *, off_t); extern int fio_net_send_simple_cmd(int sk, uint16_t opcode, uint64_t serial); +extern void fio_server_add_arg(const char *); struct thread_stat; struct group_run_stats; -- 2.25.1