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