configure: check for v2 of libnuma
[fio.git] / engines / net.c
1 /*
2  * net engine
3  *
4  * IO engine that reads/writes to/from sockets.
5  *
6  */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <signal.h>
11 #include <errno.h>
12 #include <assert.h>
13 #include <netinet/in.h>
14 #include <netinet/tcp.h>
15 #include <arpa/inet.h>
16 #include <netdb.h>
17 #include <sys/poll.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <sys/socket.h>
21 #include <sys/un.h>
22
23 #include "../fio.h"
24
25 struct netio_data {
26         int listenfd;
27         int use_splice;
28         int pipes[2];
29         struct sockaddr_in addr;
30         struct sockaddr_un addr_un;
31 };
32
33 struct netio_options {
34         struct thread_data *td;
35         unsigned int port;
36         unsigned int proto;
37         unsigned int listen;
38         unsigned int pingpong;
39         unsigned int nodelay;
40 };
41
42 struct udp_close_msg {
43         uint32_t magic;
44         uint32_t cmd;
45 };
46
47 enum {
48         FIO_LINK_CLOSE = 0x89,
49         FIO_LINK_OPEN_CLOSE_MAGIC = 0x6c696e6b,
50         FIO_LINK_OPEN = 0x98,
51
52         FIO_TYPE_TCP    = 1,
53         FIO_TYPE_UDP    = 2,
54         FIO_TYPE_UNIX   = 3,
55 };
56
57 static int str_hostname_cb(void *data, const char *input);
58 static struct fio_option options[] = {
59         {
60                 .name   = "hostname",
61                 .type   = FIO_OPT_STR_STORE,
62                 .cb     = str_hostname_cb,
63                 .help   = "Hostname for net IO engine",
64         },
65         {
66                 .name   = "port",
67                 .type   = FIO_OPT_INT,
68                 .off1   = offsetof(struct netio_options, port),
69                 .minval = 1,
70                 .maxval = 65535,
71                 .help   = "Port to use for TCP or UDP net connections",
72         },
73         {
74                 .name   = "protocol",
75                 .alias  = "proto",
76                 .type   = FIO_OPT_STR,
77                 .off1   = offsetof(struct netio_options, proto),
78                 .help   = "Network protocol to use",
79                 .def    = "tcp",
80                 .posval = {
81                           { .ival = "tcp",
82                             .oval = FIO_TYPE_TCP,
83                             .help = "Transmission Control Protocol",
84                           },
85                           { .ival = "udp",
86                             .oval = FIO_TYPE_UDP,
87                             .help = "User Datagram Protocol",
88                           },
89                           { .ival = "unix",
90                             .oval = FIO_TYPE_UNIX,
91                             .help = "UNIX domain socket",
92                           },
93                 },
94         },
95 #ifdef CONFIG_TCP_NODELAY
96         {
97                 .name   = "nodelay",
98                 .type   = FIO_OPT_BOOL,
99                 .off1   = offsetof(struct netio_options, nodelay),
100                 .help   = "Use TCP_NODELAY on TCP connections",
101         },
102 #endif
103         {
104                 .name   = "listen",
105                 .type   = FIO_OPT_STR_SET,
106                 .off1   = offsetof(struct netio_options, listen),
107                 .help   = "Listen for incoming TCP connections",
108         },
109         {
110                 .name   = "pingpong",
111                 .type   = FIO_OPT_STR_SET,
112                 .off1   = offsetof(struct netio_options, pingpong),
113                 .help   = "Ping-pong IO requests",
114         },
115         {
116                 .name   = NULL,
117         },
118 };
119
120 /*
121  * Return -1 for error and 'nr events' for a positive number
122  * of events
123  */
124 static int poll_wait(struct thread_data *td, int fd, short events)
125 {
126         struct pollfd pfd;
127         int ret;
128
129         while (!td->terminate) {
130                 pfd.fd = fd;
131                 pfd.events = events;
132                 ret = poll(&pfd, 1, -1);
133                 if (ret < 0) {
134                         if (errno == EINTR)
135                                 break;
136
137                         td_verror(td, errno, "poll");
138                         return -1;
139                 } else if (!ret)
140                         continue;
141
142                 break;
143         }
144
145         if (pfd.revents & events)
146                 return 1;
147
148         return -1;
149 }
150
151 static int fio_netio_prep(struct thread_data *td, struct io_u *io_u)
152 {
153         struct netio_options *o = td->eo;
154
155         /*
156          * Make sure we don't see spurious reads to a receiver, and vice versa
157          */
158         if (o->proto == FIO_TYPE_TCP)
159                 return 0;
160
161         if ((o->listen && io_u->ddir == DDIR_WRITE) ||
162             (!o->listen && io_u->ddir == DDIR_READ)) {
163                 td_verror(td, EINVAL, "bad direction");
164                 return 1;
165         }
166
167         return 0;
168 }
169
170 #ifdef CONFIG_LINUX_SPLICE
171 static int splice_io_u(int fdin, int fdout, unsigned int len)
172 {
173         int bytes = 0;
174
175         while (len) {
176                 int ret = splice(fdin, NULL, fdout, NULL, len, 0);
177
178                 if (ret < 0) {
179                         if (!bytes)
180                                 bytes = ret;
181
182                         break;
183                 } else if (!ret)
184                         break;
185
186                 bytes += ret;
187                 len -= ret;
188         }
189
190         return bytes;
191 }
192
193 /*
194  * Receive bytes from a socket and fill them into the internal pipe
195  */
196 static int splice_in(struct thread_data *td, struct io_u *io_u)
197 {
198         struct netio_data *nd = td->io_ops->data;
199
200         return splice_io_u(io_u->file->fd, nd->pipes[1], io_u->xfer_buflen);
201 }
202
203 /*
204  * Transmit 'len' bytes from the internal pipe
205  */
206 static int splice_out(struct thread_data *td, struct io_u *io_u,
207                       unsigned int len)
208 {
209         struct netio_data *nd = td->io_ops->data;
210
211         return splice_io_u(nd->pipes[0], io_u->file->fd, len);
212 }
213
214 static int vmsplice_io_u(struct io_u *io_u, int fd, unsigned int len)
215 {
216         struct iovec iov = {
217                 .iov_base = io_u->xfer_buf,
218                 .iov_len = len,
219         };
220         int bytes = 0;
221
222         while (iov.iov_len) {
223                 int ret = vmsplice(fd, &iov, 1, SPLICE_F_MOVE);
224
225                 if (ret < 0) {
226                         if (!bytes)
227                                 bytes = ret;
228                         break;
229                 } else if (!ret)
230                         break;
231
232                 iov.iov_len -= ret;
233                 iov.iov_base += ret;
234                 bytes += ret;
235         }
236
237         return bytes;
238
239 }
240
241 /*
242  * vmsplice() pipe to io_u buffer
243  */
244 static int vmsplice_io_u_out(struct thread_data *td, struct io_u *io_u,
245                              unsigned int len)
246 {
247         struct netio_data *nd = td->io_ops->data;
248
249         return vmsplice_io_u(io_u, nd->pipes[0], len);
250 }
251
252 /*
253  * vmsplice() io_u to pipe
254  */
255 static int vmsplice_io_u_in(struct thread_data *td, struct io_u *io_u)
256 {
257         struct netio_data *nd = td->io_ops->data;
258
259         return vmsplice_io_u(io_u, nd->pipes[1], io_u->xfer_buflen);
260 }
261
262 /*
263  * splice receive - transfer socket data into a pipe using splice, then map
264  * that pipe data into the io_u using vmsplice.
265  */
266 static int fio_netio_splice_in(struct thread_data *td, struct io_u *io_u)
267 {
268         int ret;
269
270         ret = splice_in(td, io_u);
271         if (ret > 0)
272                 return vmsplice_io_u_out(td, io_u, ret);
273
274         return ret;
275 }
276
277 /*
278  * splice transmit - map data from the io_u into a pipe by using vmsplice,
279  * then transfer that pipe to a socket using splice.
280  */
281 static int fio_netio_splice_out(struct thread_data *td, struct io_u *io_u)
282 {
283         int ret;
284
285         ret = vmsplice_io_u_in(td, io_u);
286         if (ret > 0)
287                 return splice_out(td, io_u, ret);
288
289         return ret;
290 }
291 #else
292 static int fio_netio_splice_in(struct thread_data *td, struct io_u *io_u)
293 {
294         errno = EOPNOTSUPP;
295         return -1;
296 }
297
298 static int fio_netio_splice_out(struct thread_data *td, struct io_u *io_u)
299 {
300         errno = EOPNOTSUPP;
301         return -1;
302 }
303 #endif
304
305 static int fio_netio_send(struct thread_data *td, struct io_u *io_u)
306 {
307         struct netio_data *nd = td->io_ops->data;
308         struct netio_options *o = td->eo;
309         int ret, flags = 0;
310
311         do {
312                 if (o->proto == FIO_TYPE_UDP) {
313                         struct sockaddr *to = (struct sockaddr *) &nd->addr;
314
315                         ret = sendto(io_u->file->fd, io_u->xfer_buf,
316                                         io_u->xfer_buflen, flags, to,
317                                         sizeof(*to));
318                 } else {
319                         /*
320                          * if we are going to write more, set MSG_MORE
321                          */
322 #ifdef MSG_MORE
323                         if ((td->this_io_bytes[DDIR_WRITE] + io_u->xfer_buflen <
324                             td->o.size) && !o->pingpong)
325                                 flags |= MSG_MORE;
326 #endif
327                         ret = send(io_u->file->fd, io_u->xfer_buf,
328                                         io_u->xfer_buflen, flags);
329                 }
330                 if (ret > 0)
331                         break;
332
333                 ret = poll_wait(td, io_u->file->fd, POLLOUT);
334                 if (ret <= 0)
335                         break;
336         } while (1);
337
338         return ret;
339 }
340
341 static int is_udp_close(struct io_u *io_u, int len)
342 {
343         struct udp_close_msg *msg;
344
345         if (len != sizeof(struct udp_close_msg))
346                 return 0;
347
348         msg = io_u->xfer_buf;
349         if (ntohl(msg->magic) != FIO_LINK_OPEN_CLOSE_MAGIC)
350                 return 0;
351         if (ntohl(msg->cmd) != FIO_LINK_CLOSE)
352                 return 0;
353
354         return 1;
355 }
356
357 static int fio_netio_recv(struct thread_data *td, struct io_u *io_u)
358 {
359         struct netio_data *nd = td->io_ops->data;
360         struct netio_options *o = td->eo;
361         int ret, flags = 0;
362
363         do {
364                 if (o->proto == FIO_TYPE_UDP) {
365                         socklen_t len = sizeof(nd->addr);
366                         struct sockaddr *from = (struct sockaddr *) &nd->addr;
367
368                         ret = recvfrom(io_u->file->fd, io_u->xfer_buf,
369                                         io_u->xfer_buflen, flags, from, &len);
370                         if (is_udp_close(io_u, ret)) {
371                                 td->done = 1;
372                                 return 0;
373                         }
374                 } else {
375                         ret = recv(io_u->file->fd, io_u->xfer_buf,
376                                         io_u->xfer_buflen, flags);
377                 }
378                 if (ret > 0)
379                         break;
380                 else if (!ret && (flags & MSG_WAITALL))
381                         break;
382
383                 ret = poll_wait(td, io_u->file->fd, POLLIN);
384                 if (ret <= 0)
385                         break;
386                 flags |= MSG_WAITALL;
387         } while (1);
388
389         return ret;
390 }
391
392 static int __fio_netio_queue(struct thread_data *td, struct io_u *io_u,
393                              enum fio_ddir ddir)
394 {
395         struct netio_data *nd = td->io_ops->data;
396         struct netio_options *o = td->eo;
397         int ret;
398
399         if (ddir == DDIR_WRITE) {
400                 if (!nd->use_splice || o->proto == FIO_TYPE_UDP ||
401                     o->proto == FIO_TYPE_UNIX)
402                         ret = fio_netio_send(td, io_u);
403                 else
404                         ret = fio_netio_splice_out(td, io_u);
405         } else if (ddir == DDIR_READ) {
406                 if (!nd->use_splice || o->proto == FIO_TYPE_UDP ||
407                     o->proto == FIO_TYPE_UNIX)
408                         ret = fio_netio_recv(td, io_u);
409                 else
410                         ret = fio_netio_splice_in(td, io_u);
411         } else
412                 ret = 0;        /* must be a SYNC */
413
414         if (ret != (int) io_u->xfer_buflen) {
415                 if (ret >= 0) {
416                         io_u->resid = io_u->xfer_buflen - ret;
417                         io_u->error = 0;
418                         return FIO_Q_COMPLETED;
419                 } else {
420                         int err = errno;
421
422                         if (ddir == DDIR_WRITE && err == EMSGSIZE)
423                                 return FIO_Q_BUSY;
424
425                         io_u->error = err;
426                 }
427         }
428
429         if (io_u->error)
430                 td_verror(td, io_u->error, "xfer");
431
432         return FIO_Q_COMPLETED;
433 }
434
435 static int fio_netio_queue(struct thread_data *td, struct io_u *io_u)
436 {
437         struct netio_options *o = td->eo;
438         int ret;
439
440         fio_ro_check(td, io_u);
441
442         ret = __fio_netio_queue(td, io_u, io_u->ddir);
443         if (!o->pingpong || ret != FIO_Q_COMPLETED)
444                 return ret;
445
446         /*
447          * For ping-pong mode, receive or send reply as needed
448          */
449         if (td_read(td) && io_u->ddir == DDIR_READ)
450                 ret = __fio_netio_queue(td, io_u, DDIR_WRITE);
451         else if (td_write(td) && io_u->ddir == DDIR_WRITE)
452                 ret = __fio_netio_queue(td, io_u, DDIR_READ);
453
454         return ret;
455 }
456
457 static int fio_netio_connect(struct thread_data *td, struct fio_file *f)
458 {
459         struct netio_data *nd = td->io_ops->data;
460         struct netio_options *o = td->eo;
461         int type, domain;
462
463         if (o->proto == FIO_TYPE_TCP) {
464                 domain = AF_INET;
465                 type = SOCK_STREAM;
466         } else if (o->proto == FIO_TYPE_UDP) {
467                 domain = AF_INET;
468                 type = SOCK_DGRAM;
469         } else if (o->proto == FIO_TYPE_UNIX) {
470                 domain = AF_UNIX;
471                 type = SOCK_STREAM;
472         } else {
473                 log_err("fio: bad network type %d\n", o->proto);
474                 f->fd = -1;
475                 return 1;
476         }
477
478         f->fd = socket(domain, type, 0);
479         if (f->fd < 0) {
480                 td_verror(td, errno, "socket");
481                 return 1;
482         }
483
484 #ifdef CONFIG_TCP_NODELAY
485         if (o->nodelay && o->proto == FIO_TYPE_TCP) {
486                 int optval = 1;
487
488                 if (setsockopt(f->fd, IPPROTO_TCP, TCP_NODELAY, (void *) &optval, sizeof(int)) < 0) {
489                         log_err("fio: cannot set TCP_NODELAY option on socket (%s), disable with 'nodelay=0'\n", strerror(errno));
490                         return 1;
491                 }
492         }
493 #endif
494
495         if (o->proto == FIO_TYPE_UDP)
496                 return 0;
497         else if (o->proto == FIO_TYPE_TCP) {
498                 socklen_t len = sizeof(nd->addr);
499
500                 if (connect(f->fd, (struct sockaddr *) &nd->addr, len) < 0) {
501                         td_verror(td, errno, "connect");
502                         close(f->fd);
503                         return 1;
504                 }
505         } else {
506                 struct sockaddr_un *addr = &nd->addr_un;
507                 socklen_t len;
508
509                 len = sizeof(addr->sun_family) + strlen(addr->sun_path) + 1;
510
511                 if (connect(f->fd, (struct sockaddr *) addr, len) < 0) {
512                         td_verror(td, errno, "connect");
513                         close(f->fd);
514                         return 1;
515                 }
516         }
517
518         return 0;
519 }
520
521 static int fio_netio_accept(struct thread_data *td, struct fio_file *f)
522 {
523         struct netio_data *nd = td->io_ops->data;
524         struct netio_options *o = td->eo;
525         socklen_t socklen = sizeof(nd->addr);
526         int state;
527
528         if (o->proto == FIO_TYPE_UDP) {
529                 f->fd = nd->listenfd;
530                 return 0;
531         }
532
533         state = td->runstate;
534         td_set_runstate(td, TD_SETTING_UP);
535
536         log_info("fio: waiting for connection\n");
537
538         if (poll_wait(td, nd->listenfd, POLLIN) < 0)
539                 goto err;
540
541         f->fd = accept(nd->listenfd, (struct sockaddr *) &nd->addr, &socklen);
542         if (f->fd < 0) {
543                 td_verror(td, errno, "accept");
544                 goto err;
545         }
546
547 #ifdef CONFIG_TCP_NODELAY
548         if (o->nodelay && o->proto == FIO_TYPE_TCP) {
549                 int optval = 1;
550
551                 if (setsockopt(f->fd, IPPROTO_TCP, TCP_NODELAY, (void *) &optval, sizeof(int)) < 0) {
552                         log_err("fio: cannot set TCP_NODELAY option on socket (%s), disable with 'nodelay=0'\n", strerror(errno));
553                         return 1;
554                 }
555         }
556 #endif
557
558         reset_all_stats(td);
559         td_set_runstate(td, state);
560         return 0;
561 err:
562         td_set_runstate(td, state);
563         return 1;
564 }
565
566 static void fio_netio_udp_close(struct thread_data *td, struct fio_file *f)
567 {
568         struct netio_data *nd = td->io_ops->data;
569         struct udp_close_msg msg;
570         struct sockaddr *to = (struct sockaddr *) &nd->addr;
571         int ret;
572
573         msg.magic = htonl(FIO_LINK_OPEN_CLOSE_MAGIC);
574         msg.cmd = htonl(FIO_LINK_CLOSE);
575
576         ret = sendto(f->fd, (void *) &msg, sizeof(msg), MSG_WAITALL, to,
577                         sizeof(nd->addr));
578         if (ret < 0)
579                 td_verror(td, errno, "sendto udp link close");
580 }
581
582 static int fio_netio_close_file(struct thread_data *td, struct fio_file *f)
583 {
584         struct netio_options *o = td->eo;
585
586         /*
587          * If this is an UDP connection, notify the receiver that we are
588          * closing down the link
589          */
590         if (o->proto == FIO_TYPE_UDP)
591                 fio_netio_udp_close(td, f);
592
593         return generic_close_file(td, f);
594 }
595
596 static int fio_netio_udp_recv_open(struct thread_data *td, struct fio_file *f)
597 {
598         struct netio_data *nd = td->io_ops->data;
599         struct udp_close_msg msg;
600         struct sockaddr *to = (struct sockaddr *) &nd->addr;
601         socklen_t len = sizeof(nd->addr);
602         int ret;
603
604         ret = recvfrom(f->fd, (void *) &msg, sizeof(msg), MSG_WAITALL, to, &len);
605         if (ret < 0) {
606                 td_verror(td, errno, "sendto udp link open");
607                 return ret;
608         }
609
610         if (ntohl(msg.magic) != FIO_LINK_OPEN_CLOSE_MAGIC ||
611             ntohl(msg.cmd) != FIO_LINK_OPEN) {
612                 log_err("fio: bad udp open magic %x/%x\n", ntohl(msg.magic),
613                                                                 ntohl(msg.cmd));
614                 return -1;
615         }
616
617         return 0;
618 }
619
620 static int fio_netio_udp_send_open(struct thread_data *td, struct fio_file *f)
621 {
622         struct netio_data *nd = td->io_ops->data;
623         struct udp_close_msg msg;
624         struct sockaddr *to = (struct sockaddr *) &nd->addr;
625         int ret;
626
627         msg.magic = htonl(FIO_LINK_OPEN_CLOSE_MAGIC);
628         msg.cmd = htonl(FIO_LINK_OPEN);
629
630         ret = sendto(f->fd, (void *) &msg, sizeof(msg), MSG_WAITALL, to,
631                         sizeof(nd->addr));
632         if (ret < 0) {
633                 td_verror(td, errno, "sendto udp link open");
634                 return ret;
635         }
636
637         return 0;
638 }
639
640 static int fio_netio_open_file(struct thread_data *td, struct fio_file *f)
641 {
642         int ret;
643         struct netio_options *o = td->eo;
644
645         if (o->listen)
646                 ret = fio_netio_accept(td, f);
647         else
648                 ret = fio_netio_connect(td, f);
649
650         if (ret) {
651                 f->fd = -1;
652                 return ret;
653         }
654
655         if (o->proto == FIO_TYPE_UDP) {
656                 if (td_write(td))
657                         ret = fio_netio_udp_send_open(td, f);
658                 else {
659                         int state;
660
661                         state = td->runstate;
662                         td_set_runstate(td, TD_SETTING_UP);
663                         ret = fio_netio_udp_recv_open(td, f);
664                         td_set_runstate(td, state);
665                 }
666         }
667
668         if (ret)
669                 fio_netio_close_file(td, f);
670
671         return ret;
672 }
673
674 static int fio_netio_setup_connect_inet(struct thread_data *td,
675                                         const char *host, unsigned short port)
676 {
677         struct netio_data *nd = td->io_ops->data;
678
679         if (!host) {
680                 log_err("fio: connect with no host to connect to.\n");
681                 if (td_read(td))
682                         log_err("fio: did you forget to set 'listen'?\n");
683
684                 td_verror(td, EINVAL, "no hostname= set");
685                 return 1;
686         }
687
688         nd->addr.sin_family = AF_INET;
689         nd->addr.sin_port = htons(port);
690
691         if (inet_aton(host, &nd->addr.sin_addr) != 1) {
692                 struct hostent *hent;
693
694                 hent = gethostbyname(host);
695                 if (!hent) {
696                         td_verror(td, errno, "gethostbyname");
697                         return 1;
698                 }
699
700                 memcpy(&nd->addr.sin_addr, hent->h_addr, 4);
701         }
702
703         return 0;
704 }
705
706 static int fio_netio_setup_connect_unix(struct thread_data *td,
707                                         const char *path)
708 {
709         struct netio_data *nd = td->io_ops->data;
710         struct sockaddr_un *soun = &nd->addr_un;
711
712         soun->sun_family = AF_UNIX;
713         strcpy(soun->sun_path, path);
714         return 0;
715 }
716
717 static int fio_netio_setup_connect(struct thread_data *td)
718 {
719         struct netio_options *o = td->eo;
720
721         if (o->proto == FIO_TYPE_UDP || o->proto == FIO_TYPE_TCP)
722                 return fio_netio_setup_connect_inet(td, td->o.filename,o->port);
723         else
724                 return fio_netio_setup_connect_unix(td, td->o.filename);
725 }
726
727 static int fio_netio_setup_listen_unix(struct thread_data *td, const char *path)
728 {
729         struct netio_data *nd = td->io_ops->data;
730         struct sockaddr_un *addr = &nd->addr_un;
731         mode_t mode;
732         int len, fd;
733
734         fd = socket(AF_UNIX, SOCK_STREAM, 0);
735         if (fd < 0) {
736                 log_err("fio: socket: %s\n", strerror(errno));
737                 return -1;
738         }
739
740         mode = umask(000);
741
742         memset(addr, 0, sizeof(*addr));
743         addr->sun_family = AF_UNIX;
744         strcpy(addr->sun_path, path);
745         unlink(path);
746
747         len = sizeof(addr->sun_family) + strlen(path) + 1;
748
749         if (bind(fd, (struct sockaddr *) addr, len) < 0) {
750                 log_err("fio: bind: %s\n", strerror(errno));
751                 close(fd);
752                 return -1;
753         }
754
755         umask(mode);
756         nd->listenfd = fd;
757         return 0;
758 }
759
760 static int fio_netio_setup_listen_inet(struct thread_data *td, short port)
761 {
762         struct netio_data *nd = td->io_ops->data;
763         struct netio_options *o = td->eo;
764         int fd, opt, type;
765
766         if (o->proto == FIO_TYPE_TCP)
767                 type = SOCK_STREAM;
768         else
769                 type = SOCK_DGRAM;
770
771         fd = socket(AF_INET, type, 0);
772         if (fd < 0) {
773                 td_verror(td, errno, "socket");
774                 return 1;
775         }
776
777         opt = 1;
778         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &opt, sizeof(opt)) < 0) {
779                 td_verror(td, errno, "setsockopt");
780                 return 1;
781         }
782 #ifdef SO_REUSEPORT
783         if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (void *) &opt, sizeof(opt)) < 0) {
784                 td_verror(td, errno, "setsockopt");
785                 return 1;
786         }
787 #endif
788
789         nd->addr.sin_family = AF_INET;
790         nd->addr.sin_addr.s_addr = htonl(INADDR_ANY);
791         nd->addr.sin_port = htons(port);
792
793         if (bind(fd, (struct sockaddr *) &nd->addr, sizeof(nd->addr)) < 0) {
794                 td_verror(td, errno, "bind");
795                 return 1;
796         }
797
798         nd->listenfd = fd;
799         return 0;
800 }
801
802 static int fio_netio_setup_listen(struct thread_data *td)
803 {
804         struct netio_data *nd = td->io_ops->data;
805         struct netio_options *o = td->eo;
806         int ret;
807
808         if (o->proto == FIO_TYPE_UDP || o->proto == FIO_TYPE_TCP)
809                 ret = fio_netio_setup_listen_inet(td, o->port);
810         else
811                 ret = fio_netio_setup_listen_unix(td, td->o.filename);
812
813         if (ret)
814                 return ret;
815         if (o->proto == FIO_TYPE_UDP)
816                 return 0;
817
818         if (listen(nd->listenfd, 10) < 0) {
819                 td_verror(td, errno, "listen");
820                 nd->listenfd = -1;
821                 return 1;
822         }
823
824         return 0;
825 }
826
827 static int fio_netio_init(struct thread_data *td)
828 {
829         struct netio_options *o = td->eo;
830         int ret;
831
832 #ifdef WIN32
833         WSADATA wsd;
834         WSAStartup(MAKEWORD(2,2), &wsd);
835 #endif
836
837         if (td_random(td)) {
838                 log_err("fio: network IO can't be random\n");
839                 return 1;
840         }
841
842         if (o->proto == FIO_TYPE_UNIX && o->port) {
843                 log_err("fio: network IO port not valid with unix socket\n");
844                 return 1;
845         } else if (o->proto != FIO_TYPE_UNIX && !o->port) {
846                 log_err("fio: network IO requires port for tcp or udp\n");
847                 return 1;
848         }
849
850         if (o->proto != FIO_TYPE_TCP) {
851                 if (o->listen) {
852                         log_err("fio: listen only valid for TCP proto IO\n");
853                         return 1;
854                 }
855                 if (td_rw(td)) {
856                         log_err("fio: datagram network connections must be"
857                                    " read OR write\n");
858                         return 1;
859                 }
860                 if (o->proto == FIO_TYPE_UNIX && !td->o.filename) {
861                         log_err("fio: UNIX sockets need host/filename\n");
862                         return 1;
863                 }
864                 o->listen = td_read(td);
865         }
866
867         if (o->proto != FIO_TYPE_UNIX && o->listen && td->o.filename) {
868                 log_err("fio: hostname not valid for inbound network IO\n");
869                 return 1;
870         }
871
872         if (o->listen)
873                 ret = fio_netio_setup_listen(td);
874         else
875                 ret = fio_netio_setup_connect(td);
876
877         return ret;
878 }
879
880 static void fio_netio_cleanup(struct thread_data *td)
881 {
882         struct netio_data *nd = td->io_ops->data;
883
884         if (nd) {
885                 if (nd->listenfd != -1)
886                         close(nd->listenfd);
887                 if (nd->pipes[0] != -1)
888                         close(nd->pipes[0]);
889                 if (nd->pipes[1] != -1)
890                         close(nd->pipes[1]);
891
892                 free(nd);
893         }
894 }
895
896 static int fio_netio_setup(struct thread_data *td)
897 {
898         struct netio_data *nd;
899
900         if (!td->files_index) {
901                 add_file(td, td->o.filename ?: "net");
902                 td->o.nr_files = td->o.nr_files ?: 1;
903         }
904
905         if (!td->io_ops->data) {
906                 nd = malloc(sizeof(*nd));;
907
908                 memset(nd, 0, sizeof(*nd));
909                 nd->listenfd = -1;
910                 nd->pipes[0] = nd->pipes[1] = -1;
911                 td->io_ops->data = nd;
912         }
913
914         return 0;
915 }
916
917 static void fio_netio_terminate(struct thread_data *td)
918 {
919         kill(td->pid, SIGUSR2);
920 }
921
922 #ifdef CONFIG_LINUX_SPLICE
923 static int fio_netio_setup_splice(struct thread_data *td)
924 {
925         struct netio_data *nd;
926
927         fio_netio_setup(td);
928
929         nd = td->io_ops->data;
930         if (nd) {
931                 if (pipe(nd->pipes) < 0)
932                         return 1;
933
934                 nd->use_splice = 1;
935                 return 0;
936         }
937
938         return 1;
939 }
940
941 static struct ioengine_ops ioengine_splice = {
942         .name                   = "netsplice",
943         .version                = FIO_IOOPS_VERSION,
944         .prep                   = fio_netio_prep,
945         .queue                  = fio_netio_queue,
946         .setup                  = fio_netio_setup_splice,
947         .init                   = fio_netio_init,
948         .cleanup                = fio_netio_cleanup,
949         .open_file              = fio_netio_open_file,
950         .close_file             = fio_netio_close_file,
951         .terminate              = fio_netio_terminate,
952         .options                = options,
953         .option_struct_size     = sizeof(struct netio_options),
954         .flags                  = FIO_SYNCIO | FIO_DISKLESSIO | FIO_UNIDIR |
955                                   FIO_PIPEIO,
956 };
957 #endif
958
959 static struct ioengine_ops ioengine_rw = {
960         .name                   = "net",
961         .version                = FIO_IOOPS_VERSION,
962         .prep                   = fio_netio_prep,
963         .queue                  = fio_netio_queue,
964         .setup                  = fio_netio_setup,
965         .init                   = fio_netio_init,
966         .cleanup                = fio_netio_cleanup,
967         .open_file              = fio_netio_open_file,
968         .close_file             = fio_netio_close_file,
969         .terminate              = fio_netio_terminate,
970         .options                = options,
971         .option_struct_size     = sizeof(struct netio_options),
972         .flags                  = FIO_SYNCIO | FIO_DISKLESSIO | FIO_UNIDIR |
973                                   FIO_PIPEIO,
974 };
975
976 static int str_hostname_cb(void *data, const char *input)
977 {
978         struct netio_options *o = data;
979
980         if (o->td->o.filename)
981                 free(o->td->o.filename);
982         o->td->o.filename = strdup(input);
983         return 0;
984 }
985
986 static void fio_init fio_netio_register(void)
987 {
988         register_ioengine(&ioengine_rw);
989 #ifdef CONFIG_LINUX_SPLICE
990         register_ioengine(&ioengine_splice);
991 #endif
992 }
993
994 static void fio_exit fio_netio_unregister(void)
995 {
996         unregister_ioengine(&ioengine_rw);
997 #ifdef CONFIG_LINUX_SPLICE
998         unregister_ioengine(&ioengine_splice);
999 #endif
1000 }