client/server: IPv6 support
[fio.git] / server.c
index c1ced42dd351c9e25666cb495fbff7c884ee35cb..6a5bc6ce937fcc24e0d6d135be6ac73335acb437 100644 (file)
--- a/server.c
+++ b/server.c
@@ -32,7 +32,9 @@ static int server_fd = -1;
 static char *fio_server_arg;
 static char *bind_sock;
 static struct sockaddr_in saddr_in;
+static struct sockaddr_in6 saddr_in6;
 static int first_cmd_check;
+static int use_ipv6;
 
 static const char *fio_server_ops[FIO_NET_CMD_NR] = {
        "",
@@ -183,8 +185,12 @@ struct fio_net_cmd *fio_net_recv_cmd(int sk)
 
                if (first)
                        memcpy(cmdret, &cmd, sizeof(cmd));
-               else
-                       assert(cmdret->opcode == cmd.opcode);
+               else if (cmdret->opcode != cmd.opcode) {
+                       log_err("fio: fragment opcode mismatch (%d != %d)\n",
+                                       cmdret->opcode, cmd.opcode);
+                       ret = 1;
+                       break;
+               }
 
                if (!cmd.pdu_len)
                        break;
@@ -328,6 +334,8 @@ static int fio_server_send_quit_cmd(void)
 static int handle_job_cmd(struct fio_net_cmd *cmd)
 {
        char *buf = (char *) cmd->payload;
+       struct cmd_start_pdu spdu;
+       struct cmd_end_pdu epdu;
        int ret;
 
        if (parse_jobs_ini(buf, 1, 0)) {
@@ -335,9 +343,14 @@ static int handle_job_cmd(struct fio_net_cmd *cmd)
                return -1;
        }
 
-       fio_net_send_simple_cmd(server_fd, FIO_NET_CMD_START, 0, NULL);
+       spdu.jobs = cpu_to_le32(thread_number);
+       fio_net_send_cmd(server_fd, FIO_NET_CMD_START, &spdu, sizeof(spdu), 0);
 
        ret = exec_run();
+
+       epdu.error = ret;
+       fio_net_send_cmd(server_fd, FIO_NET_CMD_STOP, &epdu, sizeof(epdu), 0);
+
        fio_server_send_quit_cmd();
        reset_fio_state();
        return ret;
@@ -803,9 +816,15 @@ int fio_server_log(const char *format, ...)
 
 static int fio_init_server_ip(void)
 {
+       struct sockaddr *addr;
+       fio_socklen_t socklen;
        int sk, opt;
 
-       sk = socket(AF_INET, SOCK_STREAM, 0);
+       if (use_ipv6)
+               sk = socket(AF_INET6, SOCK_STREAM, 0);
+       else
+               sk = socket(AF_INET, SOCK_STREAM, 0);
+
        if (sk < 0) {
                log_err("fio: socket: %s\n", strerror(errno));
                return -1;
@@ -825,9 +844,17 @@ static int fio_init_server_ip(void)
        }
 #endif
 
-       saddr_in.sin_family = AF_INET;
+       if (use_ipv6) {
+               addr = (struct sockaddr *) &saddr_in6;
+               socklen = sizeof(saddr_in6);
+               saddr_in6.sin6_family = AF_INET6;
+       } else {
+               addr = (struct sockaddr *) &saddr_in;
+               socklen = sizeof(saddr_in);
+               saddr_in.sin_family = AF_INET;
+       }
 
-       if (bind(sk, (struct sockaddr *) &saddr_in, sizeof(saddr_in)) < 0) {
+       if (bind(sk, addr, socklen) < 0) {
                log_err("fio: bind: %s\n", strerror(errno));
                close(sk);
                return -1;
@@ -883,9 +910,27 @@ static int fio_init_server_connection(void)
        if (sk < 0)
                return sk;
 
-       if (!bind_sock)
-               sprintf(bind_str, "%s:%u", inet_ntoa(saddr_in.sin_addr), fio_net_port);
-       else
+       if (!bind_sock) {
+               char *p, port[16];
+               const void *src;
+               int af;
+
+               if (use_ipv6) {
+                       af = AF_INET6;
+                       src = &saddr_in6.sin6_addr;
+               } else {
+                       af = AF_INET;
+                       src = &saddr_in.sin_addr;
+               }
+
+               p = (char *) inet_ntop(af, src, bind_str, sizeof(bind_str));
+
+               sprintf(port, ",%u", fio_net_port);
+               if (p)
+                       strcat(p, port);
+               else
+                       strcpy(bind_str, port);
+       } else
                strcpy(bind_str, bind_sock);
 
        log_info("fio: server listening on %s\n", bind_str);
@@ -899,11 +944,13 @@ static int fio_init_server_connection(void)
 }
 
 int fio_server_parse_string(const char *str, char **ptr, int *is_sock,
-                           int *port, struct in_addr *inp)
+                           int *port, struct in_addr *inp,
+                           struct in6_addr *inp6, int *ipv6)
 {
        *ptr = NULL;
        *is_sock = 0;
        *port = fio_net_port;
+       *ipv6 = 0;
 
        if (!strncmp(str, "sock:", 5)) {
                *ptr = strdup(str + 5);
@@ -911,14 +958,19 @@ int fio_server_parse_string(const char *str, char **ptr, int *is_sock,
        } else {
                const char *host = str;
                char *portp;
-               int lport = 0;
+               int ret, lport = 0;
 
                /*
                 * Is it ip:<ip or host>:port
                 */
                if (!strncmp(host, "ip:", 3))
                        host += 3;
-               else if (host[0] == ':') {
+               else if (!strncmp(host, "ip4:", 4))
+                       host += 4;
+               else if (!strncmp(host, "ip6:", 4)) {
+                       host += 4;
+                       *ipv6 = 1;
+               } else if (host[0] == ':') {
                        /* String is :port */
                        host++;
                        lport = atoi(host);
@@ -935,7 +987,7 @@ int fio_server_parse_string(const char *str, char **ptr, int *is_sock,
                 * If no port seen yet, check if there's a last ':' at the end
                 */
                if (!lport) {
-                       portp = strchr(host, ':');
+                       portp = strchr(host, ',');
                        if (portp) {
                                *portp = '\0';
                                portp++;
@@ -950,22 +1002,46 @@ int fio_server_parse_string(const char *str, char **ptr, int *is_sock,
                if (lport)
                        *port = lport;
 
+               if (!strlen(host))
+                       goto done;
+
                *ptr = strdup(host);
 
-               if (inet_aton(host, inp) != 1) {
+               if (*ipv6)
+                       ret = inet_pton(AF_INET6, host, inp6);
+               else
+                       ret = inet_pton(AF_INET, host, inp);
+
+               if (ret != 1) {
                        struct hostent *hent;
 
                        hent = gethostbyname(host);
                        if (!hent) {
+                               log_err("fio: failed to resolve <%s>\n", host);
+err:
                                free(*ptr);
                                *ptr = NULL;
                                return 1;
                        }
 
-                       memcpy(inp, hent->h_addr, 4);
+                       if (*ipv6) {
+                               if (hent->h_addrtype != AF_INET6) {
+                                       log_info("fio: falling back to IPv4\n");
+                                       *ipv6 = 0;
+                               } else
+                                       memcpy(inp6, hent->h_addr_list[0], 16);
+                       }
+                       if (!*ipv6) {
+                               if (hent->h_addrtype != AF_INET) {
+                                       log_err("fio: lookup type mismatch\n");
+                                       goto err;
+                               }
+                               memcpy(inp, hent->h_addr_list[0], 4);
+                       }
                }
        }
 
+done:
        if (*port == 0)
                *port = fio_net_port;
 
@@ -995,7 +1071,8 @@ static int fio_handle_server_arg(void)
                goto out;
 
        ret = fio_server_parse_string(fio_server_arg, &bind_sock, &is_sock,
-                                       &port, &saddr_in.sin_addr);
+                                       &port, &saddr_in.sin_addr,
+                                       &saddr_in6.sin6_addr, &use_ipv6);
 
        if (!is_sock && bind_sock) {
                free(bind_sock);
@@ -1005,6 +1082,7 @@ static int fio_handle_server_arg(void)
 out:
        fio_net_port = port;
        saddr_in.sin_port = htons(port);
+       saddr_in6.sin6_port = htons(port);
        return ret;
 }