Update Windows code to fix build breakage
[fio.git] / engines / net.c
index b4ed5df9787b46005d364bfe1b5a0382a6c44219..52cc8a7f92c48f15d538f848810d0ad2710c89cd 100644 (file)
@@ -37,6 +37,8 @@ struct netio_options {
        unsigned int listen;
        unsigned int pingpong;
        unsigned int nodelay;
+       unsigned int ttl;
+       char *intfc;
 };
 
 struct udp_close_msg {
@@ -128,6 +130,26 @@ static struct fio_option options[] = {
                .category = FIO_OPT_C_ENGINE,
                .group  = FIO_OPT_G_NETIO,
        },
+       {
+               .name   = "interface",
+               .lname  = "net engine interface",
+               .type   = FIO_OPT_STR_STORE,
+               .off1   = offsetof(struct netio_options, intfc),
+               .help   = "Network interface to use",
+               .category = FIO_OPT_C_ENGINE,
+               .group  = FIO_OPT_G_NETIO,
+       },
+       {
+               .name   = "ttl",
+               .lname  = "net engine multicast ttl",
+               .type   = FIO_OPT_INT,
+               .off1   = offsetof(struct netio_options, ttl),
+               .def    = "1",
+               .minval = 0,
+               .help   = "Time-to-live value for outgoing UDP multicast packets",
+               .category = FIO_OPT_C_ENGINE,
+               .group  = FIO_OPT_G_NETIO,
+       },
        {
                .name   = NULL,
        },
@@ -164,6 +186,20 @@ static int poll_wait(struct thread_data *td, int fd, short events)
        return -1;
 }
 
+static int fio_netio_is_multicast(const char *mcaddr)
+{
+       in_addr_t addr = inet_network(mcaddr);
+       if (addr == -1)
+               return 0;
+
+       if (inet_network("224.0.0.0") <= addr &&
+           inet_network("239.255.255.255") >= addr)
+               return 1;
+
+       return 0;
+}
+
+
 static int fio_netio_prep(struct thread_data *td, struct io_u *io_u)
 {
        struct netio_options *o = td->eo;
@@ -378,11 +414,20 @@ static int fio_netio_recv(struct thread_data *td, struct io_u *io_u)
 
        do {
                if (o->proto == FIO_TYPE_UDP) {
-                       socklen_t len = sizeof(nd->addr);
-                       struct sockaddr *from = (struct sockaddr *) &nd->addr;
+                       socklen_t l;
+                       socklen_t *len = &l;
+                       struct sockaddr *from;
+
+                       if (o->listen) {
+                               from = (struct sockaddr *) &nd->addr;
+                               *len = sizeof(nd->addr);
+                       } else {
+                               from = NULL;
+                               len = NULL;
+                       }
 
                        ret = recvfrom(io_u->file->fd, io_u->xfer_buf,
-                                       io_u->xfer_buflen, flags, from, &len);
+                                       io_u->xfer_buflen, flags, from, len);
                        if (is_udp_close(io_u, ret)) {
                                td->done = 1;
                                return 0;
@@ -508,9 +553,30 @@ static int fio_netio_connect(struct thread_data *td, struct fio_file *f)
        }
 #endif
 
-       if (o->proto == FIO_TYPE_UDP)
+       if (o->proto == FIO_TYPE_UDP) {
+               if (!fio_netio_is_multicast(td->o.filename))
+                       return 0;
+
+               if (o->intfc) {
+                       struct in_addr interface_addr;
+                       if (inet_aton(o->intfc, &interface_addr) == 0) {
+                               log_err("fio: interface not valid interface IP\n");
+                               close(f->fd);
+                               return 1;
+                       }
+                       if (setsockopt(f->fd, IPPROTO_IP, IP_MULTICAST_IF, (const char*)&interface_addr, sizeof(interface_addr)) < 0) {
+                               td_verror(td, errno, "setsockopt IP_MULTICAST_IF");
+                               close(f->fd);
+                               return 1;
+                       }
+               }
+               if (setsockopt(f->fd, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&o->ttl, sizeof(o->ttl)) < 0) {
+                       td_verror(td, errno, "setsockopt IP_MULTICAST_TTL");
+                       close(f->fd);
+                       return 1;
+               }
                return 0;
-       else if (o->proto == FIO_TYPE_TCP) {
+       else if (o->proto == FIO_TYPE_TCP) {
                socklen_t len = sizeof(nd->addr);
 
                if (connect(f->fd, (struct sockaddr *) &nd->addr, len) < 0) {
@@ -777,8 +843,11 @@ static int fio_netio_setup_listen_inet(struct thread_data *td, short port)
 {
        struct netio_data *nd = td->io_ops->data;
        struct netio_options *o = td->eo;
+       struct ip_mreq mr;
+       struct sockaddr_in sin;
        int fd, opt, type;
 
+       memset(&sin, 0, sizeof(sin));
        if (o->proto == FIO_TYPE_TCP)
                type = SOCK_STREAM;
        else
@@ -804,8 +873,35 @@ static int fio_netio_setup_listen_inet(struct thread_data *td, short port)
        }
 #endif
 
+       if (td->o.filename){
+               if(o->proto != FIO_TYPE_UDP ||
+                  !fio_netio_is_multicast(td->o.filename)) {
+                       log_err("fio: hostname not valid for non-multicast inbound network IO\n");
+                       close(fd);
+                       return 1;
+               }
+
+               inet_aton(td->o.filename, &sin.sin_addr);
+
+               mr.imr_multiaddr = sin.sin_addr;
+               if (o->intfc) {
+                       if (inet_aton(o->intfc, &mr.imr_interface) == 0) {
+                               log_err("fio: interface not valid interface IP\n");
+                               close(fd);
+                               return 1;
+                       }
+               } else {
+                       mr.imr_interface.s_addr = htonl(INADDR_ANY);
+               }
+               if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char*)&mr, sizeof(mr)) < 0) {
+                       td_verror(td, errno, "setsockopt IP_ADD_MEMBERSHIP");
+                       close(fd);
+                       return 1;
+               }
+       }
+
        nd->addr.sin_family = AF_INET;
-       nd->addr.sin_addr.s_addr = htonl(INADDR_ANY);
+       nd->addr.sin_addr.s_addr = sin.sin_addr.s_addr ? sin.sin_addr.s_addr : htonl(INADDR_ANY);
        nd->addr.sin_port = htons(port);
 
        if (bind(fd, (struct sockaddr *) &nd->addr, sizeof(nd->addr)) < 0) {
@@ -882,11 +978,6 @@ static int fio_netio_init(struct thread_data *td)
                o->listen = td_read(td);
        }
 
-       if (o->proto != FIO_TYPE_UNIX && o->listen && td->o.filename) {
-               log_err("fio: hostname not valid for inbound network IO\n");
-               return 1;
-       }
-
        if (o->listen)
                ret = fio_netio_setup_listen(td);
        else