8ef781103462ce4af9dcf2e9644ddc1e937550e6
[fio.git] / engines / net.c
1 /*
2  * Transfer data over the net. Pretty basic setup, will only support
3  * 1 file per thread/job.
4  */
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <errno.h>
9 #include <assert.h>
10 #include <netinet/in.h>
11 #include <arpa/inet.h>
12 #include <netdb.h>
13
14 #include "../fio.h"
15 #include "../os.h"
16
17 struct net_data {
18         int send_to_net;
19         struct io_u *last_io_u;
20 };
21
22 static int fio_netio_getevents(struct thread_data *td, int fio_unused min,
23                                 int max, struct timespec fio_unused *t)
24 {
25         assert(max <= 1);
26
27         /*
28          * we can only have one finished io_u for sync io, since the depth
29          * is always 1
30          */
31         if (list_empty(&td->io_u_busylist))
32                 return 0;
33
34         return 1;
35 }
36
37 static struct io_u *fio_netio_event(struct thread_data *td, int event)
38 {
39         struct net_data *nd = td->io_ops->data;
40
41         assert(event == 0);
42
43         return nd->last_io_u;
44 }
45
46 static int fio_netio_prep(struct thread_data *td, struct io_u *io_u)
47 {
48         struct net_data *nd = td->io_ops->data;
49         struct fio_file *f = io_u->file;
50
51         if (nd->send_to_net) {
52                 if (io_u->ddir == DDIR_READ) {
53                         td_verror(td, EINVAL);
54                         return 1;
55                 }
56         } else {
57                 if (io_u->ddir == DDIR_WRITE) {
58                         td_verror(td, EINVAL);
59                         return 1;
60                 }
61         }
62
63         if (io_u->ddir == DDIR_SYNC)
64                 return 0;
65         if (io_u->offset == f->last_completed_pos)
66                 return 0;
67
68         td_verror(td, EINVAL);
69         return 1;
70 }
71
72 static int fio_netio_queue(struct thread_data *td, struct io_u *io_u)
73 {
74         struct net_data *nd = td->io_ops->data;
75         struct fio_file *f = io_u->file;
76         unsigned int ret = 0;
77
78         if (io_u->ddir == DDIR_WRITE)
79                 ret = write(f->fd, io_u->buf, io_u->buflen);
80         else if (io_u->ddir == DDIR_READ)
81                 ret = read(f->fd, io_u->buf, io_u->buflen);
82
83         if (ret != io_u->buflen) {
84                 if (ret > 0) {
85                         io_u->resid = io_u->buflen - ret;
86                         io_u->error = EIO;
87                 } else
88                         io_u->error = errno;
89         }
90
91         if (!io_u->error)
92                 nd->last_io_u = io_u;
93
94         return io_u->error;
95 }
96
97 static int fio_netio_setup_connect(struct thread_data *td, const char *host,
98                                    const char *port)
99 {
100         struct sockaddr_in addr;
101         struct fio_file *f;
102
103         memset(&addr, 0, sizeof(addr));
104         addr.sin_family = AF_INET;
105         addr.sin_port = htons(atoi(port));
106
107         if (inet_aton(host, &addr.sin_addr) != 1) {
108                 struct hostent *hent = gethostbyname(host);
109
110                 if (!hent) {
111                         td_vmsg(td, errno, "gethostbyname");
112                         return 1;
113                 }
114
115                 memcpy(&addr.sin_addr, hent->h_addr, 4);
116         }
117
118         f = &td->files[0];
119
120         f->fd = socket(AF_INET, SOCK_STREAM, 0);
121         if (f->fd < 0) {
122                 td_vmsg(td, errno, "socket");
123                 return 1;
124         }
125
126         if (connect(f->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
127                 td_vmsg(td, errno, "connect");
128                 return 1;
129         }
130
131         return 0;
132
133 }
134
135 static int fio_netio_setup_listen(struct thread_data *td, const char *port)
136 {
137         struct sockaddr_in addr;
138         socklen_t socklen;
139         int fd, opt;
140
141         fd = socket(AF_INET, SOCK_STREAM, 0);
142         if (fd < 0) {
143                 td_vmsg(td, errno, "socket");
144                 return 1;
145         }
146
147         opt = 1;
148         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
149                 td_vmsg(td, errno, "setsockopt");
150                 return 1;
151         }
152
153         memset(&addr, 0, sizeof(addr));
154         addr.sin_family = AF_INET;
155         addr.sin_addr.s_addr = htonl(INADDR_ANY);
156         addr.sin_port = htons(atoi(port));
157
158         if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
159                 td_vmsg(td, errno, "bind");
160                 return 1;
161         }
162         if (listen(fd, 1) < 0) {
163                 td_vmsg(td, errno, "listen");
164                 return 1;
165         }
166
167         socklen = sizeof(addr);
168         td->files[0].fd = accept(fd, (struct sockaddr *) &addr, &socklen);
169         if (td->files[0].fd < 0) {
170                 td_vmsg(td, errno, "accept");
171                 return 1;
172         }
173
174         return 0;
175 }
176
177 static int fio_netio_setup(struct thread_data *td)
178 {
179         char host[64], port[64], buf[128];
180         struct net_data *nd;
181         char *sep;
182         int ret;
183
184         /*
185          * work around for late init call
186          */
187         if (td->io_ops->init(td))
188                 return 1;
189
190         nd = td->io_ops->data;
191
192         if (td->iomix) {
193                 log_err("fio: network connections must be read OR write\n");
194                 return 1;
195         }
196         if (td->nr_files > 1) {
197                 log_err("fio: only one file supported for network\n");
198                 return 1;
199         }
200
201         strcpy(buf, td->filename);
202
203         sep = strchr(buf, ':');
204         if (!sep) {
205                 log_err("fio: bad network host:port <<%s>>\n", td->filename);
206                 return 1;
207         }
208
209         *sep = '\0';
210         sep++;
211         strcpy(host, buf);
212         strcpy(port, sep);
213
214         if (td->ddir == READ) {
215                 nd->send_to_net = 0;
216                 ret = fio_netio_setup_listen(td, port);
217         } else {
218                 nd->send_to_net = 1;
219                 ret = fio_netio_setup_connect(td, host, port);
220         }
221
222         if (!ret) {
223                 td->io_size = td->total_file_size;
224                 td->total_io_size = td->io_size;
225                 td->files[0].real_file_size = td->io_size;
226         }
227
228         return ret;
229 }
230
231 static void fio_netio_cleanup(struct thread_data *td)
232 {
233         if (td->io_ops->data) {
234                 free(td->io_ops->data);
235                 td->io_ops->data = NULL;
236         }
237 }
238
239 static int fio_netio_init(struct thread_data *td)
240 {
241         struct net_data *nd;
242
243         if (td->io_ops->data)
244                 return 0;
245
246         nd  = malloc(sizeof(*nd));
247         nd->last_io_u = NULL;
248         td->io_ops->data = nd;
249         return 0;
250 }
251
252 static struct ioengine_ops ioengine = {
253         .name           = "net",
254         .version        = FIO_IOOPS_VERSION,
255         .init           = fio_netio_init,
256         .prep           = fio_netio_prep,
257         .queue          = fio_netio_queue,
258         .getevents      = fio_netio_getevents,
259         .event          = fio_netio_event,
260         .cleanup        = fio_netio_cleanup,
261         .setup          = fio_netio_setup,
262         .flags          = FIO_SYNCIO | FIO_NETIO,
263 };
264
265 static void fio_init fio_netio_register(void)
266 {
267         register_ioengine(&ioengine);
268 }
269
270 static void fio_exit fio_netio_unregister(void)
271 {
272         unregister_ioengine(&ioengine);
273 }