Properly log errors in server
[fio.git] / server.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <limits.h>
5 #include <string.h>
6 #include <getopt.h>
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <sys/poll.h>
10 #include <sys/stat.h>
11 #include <sys/types.h>
12 #include <sys/wait.h>
13 #include <sys/time.h>
14 #include <sys/mman.h>
15 #include <signal.h>
16 #include <netinet/in.h>
17 #include <arpa/inet.h>
18 #include <netdb.h>
19
20 #include "fio.h"
21
22 static int net_port = 8765;
23
24 int exit_backend = 0;
25
26 static int accept_loop(int listen_sk)
27 {
28         struct sockaddr addr;
29         unsigned int len = sizeof(addr);
30         struct pollfd pfd;
31         int ret, sk, flags;
32
33         flags = fcntl(listen_sk, F_GETFL);
34         flags |= O_NONBLOCK;
35         fcntl(listen_sk, F_SETFL, flags);
36 again:
37         pfd.fd = listen_sk;
38         pfd.events = POLLIN;
39         do {
40                 ret = poll(&pfd, 1, 100);
41                 if (ret < 0) {
42                         if (errno == EINTR)
43                                 break;
44                         perror("poll");
45                         goto out;
46                 } else if (!ret)
47                         continue;
48
49                 if (pfd.revents & POLLIN)
50                         break;
51         } while (!exit_backend);
52
53         if (exit_backend)
54                 goto out;
55
56         sk = accept(listen_sk, &addr, &len);
57         if (sk < 0) {
58                 log_err("fio: accept: %s\n", strerror(errno));
59                 return -1;
60         }
61
62         /* read forever */
63         while (!exit_backend) {
64                 char buf[131072];
65
66                 ret = recv(sk, buf, 4096, 0);
67                 if (ret > 0) {
68                         if (!strncmp("FIO_QUIT", buf, 8)) {
69                                 exit_backend = 1;
70                                 break;
71                         }
72                         parse_jobs_ini(buf, 1, 0);
73                         exec_run();
74                         reset_fio_state();
75                         break;
76                 } else if (!ret)
77                         break;
78                 if (errno == EAGAIN || errno == EINTR)
79                         continue;
80                 break;
81         }
82
83         close(sk);
84
85         if (!exit_backend)
86                 goto again;
87
88 out:
89         return 0;
90 }
91
92 int fio_server(void)
93 {
94         struct sockaddr_in saddr_in;
95         struct sockaddr addr;
96         unsigned int len;
97         int sk, opt, ret;
98
99         sk = socket(AF_INET, SOCK_STREAM, 0);
100         if (sk < 0) {
101                 log_err("fio: socket: %s\n", strerror(errno));
102                 return -1;
103         }
104
105         opt = 1;
106         if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
107                 log_err("fio: setsockopt: %s\n", strerror(errno));
108                 return -1;
109         }
110 #ifdef SO_REUSEPORT
111         if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt)) < 0) {
112                 log_err("fio: setsockopt: %s\n", strerror(errno));
113                 return 1;
114         }
115 #endif
116
117         saddr_in.sin_family = AF_INET;
118         saddr_in.sin_addr.s_addr = htonl(INADDR_ANY);
119         saddr_in.sin_port = htons(net_port);
120
121         if (bind(sk, (struct sockaddr *) &saddr_in, sizeof(saddr_in)) < 0) {
122                 log_err("fio: bind: %s\n", strerror(errno));
123                 return -1;
124         }
125
126         if (listen(sk, 1) < 0) {
127                 log_err("fio: listen: %s\n", strerror(errno));
128                 return -1;
129         }
130
131         len = sizeof(addr);
132         if (getsockname(sk, &addr, &len) < 0) {
133                 log_err("fio: getsockname: %s\n", strerror(errno));
134                 return -1;
135         }
136
137         ret = accept_loop(sk);
138         close(sk);
139         return ret;
140 }