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