xref: /qemu/contrib/ivshmem-server/ivshmem-server.c (revision a75eb03b9fca3af291ec2c433ddda06121ae927d)
1*a75eb03bSDavid Marchand /*
2*a75eb03bSDavid Marchand  * Copyright 6WIND S.A., 2014
3*a75eb03bSDavid Marchand  *
4*a75eb03bSDavid Marchand  * This work is licensed under the terms of the GNU GPL, version 2 or
5*a75eb03bSDavid Marchand  * (at your option) any later version.  See the COPYING file in the
6*a75eb03bSDavid Marchand  * top-level directory.
7*a75eb03bSDavid Marchand  */
8*a75eb03bSDavid Marchand #include "qemu-common.h"
9*a75eb03bSDavid Marchand #include "qemu/sockets.h"
10*a75eb03bSDavid Marchand 
11*a75eb03bSDavid Marchand #include <sys/mman.h>
12*a75eb03bSDavid Marchand #include <sys/types.h>
13*a75eb03bSDavid Marchand #include <sys/socket.h>
14*a75eb03bSDavid Marchand #include <sys/un.h>
15*a75eb03bSDavid Marchand 
16*a75eb03bSDavid Marchand #include "ivshmem-server.h"
17*a75eb03bSDavid Marchand 
18*a75eb03bSDavid Marchand /* log a message on stdout if verbose=1 */
19*a75eb03bSDavid Marchand #define IVSHMEM_SERVER_DEBUG(server, fmt, ...) do { \
20*a75eb03bSDavid Marchand         if ((server)->verbose) {         \
21*a75eb03bSDavid Marchand             printf(fmt, ## __VA_ARGS__); \
22*a75eb03bSDavid Marchand         }                                \
23*a75eb03bSDavid Marchand     } while (0)
24*a75eb03bSDavid Marchand 
25*a75eb03bSDavid Marchand /** maximum size of a huge page, used by ivshmem_server_ftruncate() */
26*a75eb03bSDavid Marchand #define IVSHMEM_SERVER_MAX_HUGEPAGE_SIZE (1024 * 1024 * 1024)
27*a75eb03bSDavid Marchand 
28*a75eb03bSDavid Marchand /** default listen backlog (number of sockets not accepted) */
29*a75eb03bSDavid Marchand #define IVSHMEM_SERVER_LISTEN_BACKLOG 10
30*a75eb03bSDavid Marchand 
31*a75eb03bSDavid Marchand /* send message to a client unix socket */
32*a75eb03bSDavid Marchand static int
33*a75eb03bSDavid Marchand ivshmem_server_send_one_msg(int sock_fd, long peer_id, int fd)
34*a75eb03bSDavid Marchand {
35*a75eb03bSDavid Marchand     int ret;
36*a75eb03bSDavid Marchand     struct msghdr msg;
37*a75eb03bSDavid Marchand     struct iovec iov[1];
38*a75eb03bSDavid Marchand     union {
39*a75eb03bSDavid Marchand         struct cmsghdr cmsg;
40*a75eb03bSDavid Marchand         char control[CMSG_SPACE(sizeof(int))];
41*a75eb03bSDavid Marchand     } msg_control;
42*a75eb03bSDavid Marchand     struct cmsghdr *cmsg;
43*a75eb03bSDavid Marchand 
44*a75eb03bSDavid Marchand     iov[0].iov_base = &peer_id;
45*a75eb03bSDavid Marchand     iov[0].iov_len = sizeof(peer_id);
46*a75eb03bSDavid Marchand 
47*a75eb03bSDavid Marchand     memset(&msg, 0, sizeof(msg));
48*a75eb03bSDavid Marchand     msg.msg_iov = iov;
49*a75eb03bSDavid Marchand     msg.msg_iovlen = 1;
50*a75eb03bSDavid Marchand 
51*a75eb03bSDavid Marchand     /* if fd is specified, add it in a cmsg */
52*a75eb03bSDavid Marchand     if (fd >= 0) {
53*a75eb03bSDavid Marchand         memset(&msg_control, 0, sizeof(msg_control));
54*a75eb03bSDavid Marchand         msg.msg_control = &msg_control;
55*a75eb03bSDavid Marchand         msg.msg_controllen = sizeof(msg_control);
56*a75eb03bSDavid Marchand         cmsg = CMSG_FIRSTHDR(&msg);
57*a75eb03bSDavid Marchand         cmsg->cmsg_level = SOL_SOCKET;
58*a75eb03bSDavid Marchand         cmsg->cmsg_type = SCM_RIGHTS;
59*a75eb03bSDavid Marchand         cmsg->cmsg_len = CMSG_LEN(sizeof(int));
60*a75eb03bSDavid Marchand         memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
61*a75eb03bSDavid Marchand     }
62*a75eb03bSDavid Marchand 
63*a75eb03bSDavid Marchand     ret = sendmsg(sock_fd, &msg, 0);
64*a75eb03bSDavid Marchand     if (ret <= 0) {
65*a75eb03bSDavid Marchand         return -1;
66*a75eb03bSDavid Marchand     }
67*a75eb03bSDavid Marchand 
68*a75eb03bSDavid Marchand     return 0;
69*a75eb03bSDavid Marchand }
70*a75eb03bSDavid Marchand 
71*a75eb03bSDavid Marchand /* free a peer when the server advertises a disconnection or when the
72*a75eb03bSDavid Marchand  * server is freed */
73*a75eb03bSDavid Marchand static void
74*a75eb03bSDavid Marchand ivshmem_server_free_peer(IvshmemServer *server, IvshmemServerPeer *peer)
75*a75eb03bSDavid Marchand {
76*a75eb03bSDavid Marchand     unsigned vector;
77*a75eb03bSDavid Marchand     IvshmemServerPeer *other_peer;
78*a75eb03bSDavid Marchand 
79*a75eb03bSDavid Marchand     IVSHMEM_SERVER_DEBUG(server, "free peer %ld\n", peer->id);
80*a75eb03bSDavid Marchand     close(peer->sock_fd);
81*a75eb03bSDavid Marchand     QTAILQ_REMOVE(&server->peer_list, peer, next);
82*a75eb03bSDavid Marchand 
83*a75eb03bSDavid Marchand     /* advertise the deletion to other peers */
84*a75eb03bSDavid Marchand     QTAILQ_FOREACH(other_peer, &server->peer_list, next) {
85*a75eb03bSDavid Marchand         ivshmem_server_send_one_msg(other_peer->sock_fd, peer->id, -1);
86*a75eb03bSDavid Marchand     }
87*a75eb03bSDavid Marchand 
88*a75eb03bSDavid Marchand     for (vector = 0; vector < peer->vectors_count; vector++) {
89*a75eb03bSDavid Marchand         event_notifier_cleanup(&peer->vectors[vector]);
90*a75eb03bSDavid Marchand     }
91*a75eb03bSDavid Marchand 
92*a75eb03bSDavid Marchand     g_free(peer);
93*a75eb03bSDavid Marchand }
94*a75eb03bSDavid Marchand 
95*a75eb03bSDavid Marchand /* send the peer id and the shm_fd just after a new client connection */
96*a75eb03bSDavid Marchand static int
97*a75eb03bSDavid Marchand ivshmem_server_send_initial_info(IvshmemServer *server, IvshmemServerPeer *peer)
98*a75eb03bSDavid Marchand {
99*a75eb03bSDavid Marchand     int ret;
100*a75eb03bSDavid Marchand 
101*a75eb03bSDavid Marchand     /* send the peer id to the client */
102*a75eb03bSDavid Marchand     ret = ivshmem_server_send_one_msg(peer->sock_fd, peer->id, -1);
103*a75eb03bSDavid Marchand     if (ret < 0) {
104*a75eb03bSDavid Marchand         IVSHMEM_SERVER_DEBUG(server, "cannot send peer id: %s\n",
105*a75eb03bSDavid Marchand                              strerror(errno));
106*a75eb03bSDavid Marchand         return -1;
107*a75eb03bSDavid Marchand     }
108*a75eb03bSDavid Marchand 
109*a75eb03bSDavid Marchand     /* send the shm_fd */
110*a75eb03bSDavid Marchand     ret = ivshmem_server_send_one_msg(peer->sock_fd, -1, server->shm_fd);
111*a75eb03bSDavid Marchand     if (ret < 0) {
112*a75eb03bSDavid Marchand         IVSHMEM_SERVER_DEBUG(server, "cannot send shm fd: %s\n",
113*a75eb03bSDavid Marchand                              strerror(errno));
114*a75eb03bSDavid Marchand         return -1;
115*a75eb03bSDavid Marchand     }
116*a75eb03bSDavid Marchand 
117*a75eb03bSDavid Marchand     return 0;
118*a75eb03bSDavid Marchand }
119*a75eb03bSDavid Marchand 
120*a75eb03bSDavid Marchand /* handle message on listening unix socket (new client connection) */
121*a75eb03bSDavid Marchand static int
122*a75eb03bSDavid Marchand ivshmem_server_handle_new_conn(IvshmemServer *server)
123*a75eb03bSDavid Marchand {
124*a75eb03bSDavid Marchand     IvshmemServerPeer *peer, *other_peer;
125*a75eb03bSDavid Marchand     struct sockaddr_un unaddr;
126*a75eb03bSDavid Marchand     socklen_t unaddr_len;
127*a75eb03bSDavid Marchand     int newfd;
128*a75eb03bSDavid Marchand     unsigned i;
129*a75eb03bSDavid Marchand 
130*a75eb03bSDavid Marchand     /* accept the incoming connection */
131*a75eb03bSDavid Marchand     unaddr_len = sizeof(unaddr);
132*a75eb03bSDavid Marchand     newfd = qemu_accept(server->sock_fd,
133*a75eb03bSDavid Marchand                         (struct sockaddr *)&unaddr, &unaddr_len);
134*a75eb03bSDavid Marchand 
135*a75eb03bSDavid Marchand     if (newfd < 0) {
136*a75eb03bSDavid Marchand         IVSHMEM_SERVER_DEBUG(server, "cannot accept() %s\n", strerror(errno));
137*a75eb03bSDavid Marchand         return -1;
138*a75eb03bSDavid Marchand     }
139*a75eb03bSDavid Marchand 
140*a75eb03bSDavid Marchand     qemu_set_nonblock(newfd);
141*a75eb03bSDavid Marchand     IVSHMEM_SERVER_DEBUG(server, "accept()=%d\n", newfd);
142*a75eb03bSDavid Marchand 
143*a75eb03bSDavid Marchand     /* allocate new structure for this peer */
144*a75eb03bSDavid Marchand     peer = g_malloc0(sizeof(*peer));
145*a75eb03bSDavid Marchand     peer->sock_fd = newfd;
146*a75eb03bSDavid Marchand 
147*a75eb03bSDavid Marchand     /* get an unused peer id */
148*a75eb03bSDavid Marchand     while (ivshmem_server_search_peer(server, server->cur_id) != NULL) {
149*a75eb03bSDavid Marchand         server->cur_id++;
150*a75eb03bSDavid Marchand     }
151*a75eb03bSDavid Marchand     peer->id = server->cur_id++;
152*a75eb03bSDavid Marchand 
153*a75eb03bSDavid Marchand     /* create eventfd, one per vector */
154*a75eb03bSDavid Marchand     peer->vectors_count = server->n_vectors;
155*a75eb03bSDavid Marchand     for (i = 0; i < peer->vectors_count; i++) {
156*a75eb03bSDavid Marchand         if (event_notifier_init(&peer->vectors[i], FALSE) < 0) {
157*a75eb03bSDavid Marchand             IVSHMEM_SERVER_DEBUG(server, "cannot create eventfd\n");
158*a75eb03bSDavid Marchand             goto fail;
159*a75eb03bSDavid Marchand         }
160*a75eb03bSDavid Marchand     }
161*a75eb03bSDavid Marchand 
162*a75eb03bSDavid Marchand     /* send peer id and shm fd */
163*a75eb03bSDavid Marchand     if (ivshmem_server_send_initial_info(server, peer) < 0) {
164*a75eb03bSDavid Marchand         IVSHMEM_SERVER_DEBUG(server, "cannot send initial info\n");
165*a75eb03bSDavid Marchand         goto fail;
166*a75eb03bSDavid Marchand     }
167*a75eb03bSDavid Marchand 
168*a75eb03bSDavid Marchand     /* advertise the new peer to others */
169*a75eb03bSDavid Marchand     QTAILQ_FOREACH(other_peer, &server->peer_list, next) {
170*a75eb03bSDavid Marchand         for (i = 0; i < peer->vectors_count; i++) {
171*a75eb03bSDavid Marchand             ivshmem_server_send_one_msg(other_peer->sock_fd, peer->id,
172*a75eb03bSDavid Marchand                                         peer->vectors[i].wfd);
173*a75eb03bSDavid Marchand         }
174*a75eb03bSDavid Marchand     }
175*a75eb03bSDavid Marchand 
176*a75eb03bSDavid Marchand     /* advertise the other peers to the new one */
177*a75eb03bSDavid Marchand     QTAILQ_FOREACH(other_peer, &server->peer_list, next) {
178*a75eb03bSDavid Marchand         for (i = 0; i < peer->vectors_count; i++) {
179*a75eb03bSDavid Marchand             ivshmem_server_send_one_msg(peer->sock_fd, other_peer->id,
180*a75eb03bSDavid Marchand                                         other_peer->vectors[i].wfd);
181*a75eb03bSDavid Marchand         }
182*a75eb03bSDavid Marchand     }
183*a75eb03bSDavid Marchand 
184*a75eb03bSDavid Marchand     /* advertise the new peer to itself */
185*a75eb03bSDavid Marchand     for (i = 0; i < peer->vectors_count; i++) {
186*a75eb03bSDavid Marchand         ivshmem_server_send_one_msg(peer->sock_fd, peer->id,
187*a75eb03bSDavid Marchand                                     event_notifier_get_fd(&peer->vectors[i]));
188*a75eb03bSDavid Marchand     }
189*a75eb03bSDavid Marchand 
190*a75eb03bSDavid Marchand     QTAILQ_INSERT_TAIL(&server->peer_list, peer, next);
191*a75eb03bSDavid Marchand     IVSHMEM_SERVER_DEBUG(server, "new peer id = %ld\n",
192*a75eb03bSDavid Marchand                          peer->id);
193*a75eb03bSDavid Marchand     return 0;
194*a75eb03bSDavid Marchand 
195*a75eb03bSDavid Marchand fail:
196*a75eb03bSDavid Marchand     while (i--) {
197*a75eb03bSDavid Marchand         event_notifier_cleanup(&peer->vectors[i]);
198*a75eb03bSDavid Marchand     }
199*a75eb03bSDavid Marchand     close(newfd);
200*a75eb03bSDavid Marchand     g_free(peer);
201*a75eb03bSDavid Marchand     return -1;
202*a75eb03bSDavid Marchand }
203*a75eb03bSDavid Marchand 
204*a75eb03bSDavid Marchand /* Try to ftruncate a file to next power of 2 of shmsize.
205*a75eb03bSDavid Marchand  * If it fails; all power of 2 above shmsize are tested until
206*a75eb03bSDavid Marchand  * we reach the maximum huge page size. This is useful
207*a75eb03bSDavid Marchand  * if the shm file is in a hugetlbfs that cannot be truncated to the
208*a75eb03bSDavid Marchand  * shm_size value. */
209*a75eb03bSDavid Marchand static int
210*a75eb03bSDavid Marchand ivshmem_server_ftruncate(int fd, unsigned shmsize)
211*a75eb03bSDavid Marchand {
212*a75eb03bSDavid Marchand     int ret;
213*a75eb03bSDavid Marchand     struct stat mapstat;
214*a75eb03bSDavid Marchand 
215*a75eb03bSDavid Marchand     /* align shmsize to next power of 2 */
216*a75eb03bSDavid Marchand     shmsize = pow2ceil(shmsize);
217*a75eb03bSDavid Marchand 
218*a75eb03bSDavid Marchand     if (fstat(fd, &mapstat) != -1 && mapstat.st_size == shmsize) {
219*a75eb03bSDavid Marchand         return 0;
220*a75eb03bSDavid Marchand     }
221*a75eb03bSDavid Marchand 
222*a75eb03bSDavid Marchand     while (shmsize <= IVSHMEM_SERVER_MAX_HUGEPAGE_SIZE) {
223*a75eb03bSDavid Marchand         ret = ftruncate(fd, shmsize);
224*a75eb03bSDavid Marchand         if (ret == 0) {
225*a75eb03bSDavid Marchand             return ret;
226*a75eb03bSDavid Marchand         }
227*a75eb03bSDavid Marchand         shmsize *= 2;
228*a75eb03bSDavid Marchand     }
229*a75eb03bSDavid Marchand 
230*a75eb03bSDavid Marchand     return -1;
231*a75eb03bSDavid Marchand }
232*a75eb03bSDavid Marchand 
233*a75eb03bSDavid Marchand /* Init a new ivshmem server */
234*a75eb03bSDavid Marchand int
235*a75eb03bSDavid Marchand ivshmem_server_init(IvshmemServer *server, const char *unix_sock_path,
236*a75eb03bSDavid Marchand                     const char *shm_path, size_t shm_size, unsigned n_vectors,
237*a75eb03bSDavid Marchand                     bool verbose)
238*a75eb03bSDavid Marchand {
239*a75eb03bSDavid Marchand     int ret;
240*a75eb03bSDavid Marchand 
241*a75eb03bSDavid Marchand     memset(server, 0, sizeof(*server));
242*a75eb03bSDavid Marchand     server->verbose = verbose;
243*a75eb03bSDavid Marchand 
244*a75eb03bSDavid Marchand     ret = snprintf(server->unix_sock_path, sizeof(server->unix_sock_path),
245*a75eb03bSDavid Marchand                    "%s", unix_sock_path);
246*a75eb03bSDavid Marchand     if (ret < 0 || ret >= sizeof(server->unix_sock_path)) {
247*a75eb03bSDavid Marchand         IVSHMEM_SERVER_DEBUG(server, "could not copy unix socket path\n");
248*a75eb03bSDavid Marchand         return -1;
249*a75eb03bSDavid Marchand     }
250*a75eb03bSDavid Marchand     ret = snprintf(server->shm_path, sizeof(server->shm_path),
251*a75eb03bSDavid Marchand                    "%s", shm_path);
252*a75eb03bSDavid Marchand     if (ret < 0 || ret >= sizeof(server->shm_path)) {
253*a75eb03bSDavid Marchand         IVSHMEM_SERVER_DEBUG(server, "could not copy shm path\n");
254*a75eb03bSDavid Marchand         return -1;
255*a75eb03bSDavid Marchand     }
256*a75eb03bSDavid Marchand 
257*a75eb03bSDavid Marchand     server->shm_size = shm_size;
258*a75eb03bSDavid Marchand     server->n_vectors = n_vectors;
259*a75eb03bSDavid Marchand 
260*a75eb03bSDavid Marchand     QTAILQ_INIT(&server->peer_list);
261*a75eb03bSDavid Marchand 
262*a75eb03bSDavid Marchand     return 0;
263*a75eb03bSDavid Marchand }
264*a75eb03bSDavid Marchand 
265*a75eb03bSDavid Marchand /* open shm, create and bind to the unix socket */
266*a75eb03bSDavid Marchand int
267*a75eb03bSDavid Marchand ivshmem_server_start(IvshmemServer *server)
268*a75eb03bSDavid Marchand {
269*a75eb03bSDavid Marchand     struct sockaddr_un sun;
270*a75eb03bSDavid Marchand     int shm_fd, sock_fd, ret;
271*a75eb03bSDavid Marchand 
272*a75eb03bSDavid Marchand     /* open shm file */
273*a75eb03bSDavid Marchand     shm_fd = shm_open(server->shm_path, O_CREAT|O_RDWR, S_IRWXU);
274*a75eb03bSDavid Marchand     if (shm_fd < 0) {
275*a75eb03bSDavid Marchand         fprintf(stderr, "cannot open shm file %s: %s\n", server->shm_path,
276*a75eb03bSDavid Marchand                 strerror(errno));
277*a75eb03bSDavid Marchand         return -1;
278*a75eb03bSDavid Marchand     }
279*a75eb03bSDavid Marchand     if (ivshmem_server_ftruncate(shm_fd, server->shm_size) < 0) {
280*a75eb03bSDavid Marchand         fprintf(stderr, "ftruncate(%s) failed: %s\n", server->shm_path,
281*a75eb03bSDavid Marchand                 strerror(errno));
282*a75eb03bSDavid Marchand         goto err_close_shm;
283*a75eb03bSDavid Marchand     }
284*a75eb03bSDavid Marchand 
285*a75eb03bSDavid Marchand     IVSHMEM_SERVER_DEBUG(server, "create & bind socket %s\n",
286*a75eb03bSDavid Marchand                          server->unix_sock_path);
287*a75eb03bSDavid Marchand 
288*a75eb03bSDavid Marchand     /* create the unix listening socket */
289*a75eb03bSDavid Marchand     sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
290*a75eb03bSDavid Marchand     if (sock_fd < 0) {
291*a75eb03bSDavid Marchand         IVSHMEM_SERVER_DEBUG(server, "cannot create socket: %s\n",
292*a75eb03bSDavid Marchand                              strerror(errno));
293*a75eb03bSDavid Marchand         goto err_close_shm;
294*a75eb03bSDavid Marchand     }
295*a75eb03bSDavid Marchand 
296*a75eb03bSDavid Marchand     sun.sun_family = AF_UNIX;
297*a75eb03bSDavid Marchand     ret = snprintf(sun.sun_path, sizeof(sun.sun_path), "%s",
298*a75eb03bSDavid Marchand                    server->unix_sock_path);
299*a75eb03bSDavid Marchand     if (ret < 0 || ret >= sizeof(sun.sun_path)) {
300*a75eb03bSDavid Marchand         IVSHMEM_SERVER_DEBUG(server, "could not copy unix socket path\n");
301*a75eb03bSDavid Marchand         goto err_close_sock;
302*a75eb03bSDavid Marchand     }
303*a75eb03bSDavid Marchand     if (bind(sock_fd, (struct sockaddr *)&sun, sizeof(sun)) < 0) {
304*a75eb03bSDavid Marchand         IVSHMEM_SERVER_DEBUG(server, "cannot connect to %s: %s\n", sun.sun_path,
305*a75eb03bSDavid Marchand                              strerror(errno));
306*a75eb03bSDavid Marchand         goto err_close_sock;
307*a75eb03bSDavid Marchand     }
308*a75eb03bSDavid Marchand 
309*a75eb03bSDavid Marchand     if (listen(sock_fd, IVSHMEM_SERVER_LISTEN_BACKLOG) < 0) {
310*a75eb03bSDavid Marchand         IVSHMEM_SERVER_DEBUG(server, "listen() failed: %s\n", strerror(errno));
311*a75eb03bSDavid Marchand         goto err_close_sock;
312*a75eb03bSDavid Marchand     }
313*a75eb03bSDavid Marchand 
314*a75eb03bSDavid Marchand     server->sock_fd = sock_fd;
315*a75eb03bSDavid Marchand     server->shm_fd = shm_fd;
316*a75eb03bSDavid Marchand 
317*a75eb03bSDavid Marchand     return 0;
318*a75eb03bSDavid Marchand 
319*a75eb03bSDavid Marchand err_close_sock:
320*a75eb03bSDavid Marchand     close(sock_fd);
321*a75eb03bSDavid Marchand err_close_shm:
322*a75eb03bSDavid Marchand     close(shm_fd);
323*a75eb03bSDavid Marchand     return -1;
324*a75eb03bSDavid Marchand }
325*a75eb03bSDavid Marchand 
326*a75eb03bSDavid Marchand /* close connections to clients, the unix socket and the shm fd */
327*a75eb03bSDavid Marchand void
328*a75eb03bSDavid Marchand ivshmem_server_close(IvshmemServer *server)
329*a75eb03bSDavid Marchand {
330*a75eb03bSDavid Marchand     IvshmemServerPeer *peer, *npeer;
331*a75eb03bSDavid Marchand 
332*a75eb03bSDavid Marchand     IVSHMEM_SERVER_DEBUG(server, "close server\n");
333*a75eb03bSDavid Marchand 
334*a75eb03bSDavid Marchand     QTAILQ_FOREACH_SAFE(peer, &server->peer_list, next, npeer) {
335*a75eb03bSDavid Marchand         ivshmem_server_free_peer(server, peer);
336*a75eb03bSDavid Marchand     }
337*a75eb03bSDavid Marchand 
338*a75eb03bSDavid Marchand     unlink(server->unix_sock_path);
339*a75eb03bSDavid Marchand     close(server->sock_fd);
340*a75eb03bSDavid Marchand     close(server->shm_fd);
341*a75eb03bSDavid Marchand     server->sock_fd = -1;
342*a75eb03bSDavid Marchand     server->shm_fd = -1;
343*a75eb03bSDavid Marchand }
344*a75eb03bSDavid Marchand 
345*a75eb03bSDavid Marchand /* get the fd_set according to the unix socket and the peer list */
346*a75eb03bSDavid Marchand void
347*a75eb03bSDavid Marchand ivshmem_server_get_fds(const IvshmemServer *server, fd_set *fds, int *maxfd)
348*a75eb03bSDavid Marchand {
349*a75eb03bSDavid Marchand     IvshmemServerPeer *peer;
350*a75eb03bSDavid Marchand 
351*a75eb03bSDavid Marchand     if (server->sock_fd == -1) {
352*a75eb03bSDavid Marchand         return;
353*a75eb03bSDavid Marchand     }
354*a75eb03bSDavid Marchand 
355*a75eb03bSDavid Marchand     FD_SET(server->sock_fd, fds);
356*a75eb03bSDavid Marchand     if (server->sock_fd >= *maxfd) {
357*a75eb03bSDavid Marchand         *maxfd = server->sock_fd + 1;
358*a75eb03bSDavid Marchand     }
359*a75eb03bSDavid Marchand 
360*a75eb03bSDavid Marchand     QTAILQ_FOREACH(peer, &server->peer_list, next) {
361*a75eb03bSDavid Marchand         FD_SET(peer->sock_fd, fds);
362*a75eb03bSDavid Marchand         if (peer->sock_fd >= *maxfd) {
363*a75eb03bSDavid Marchand             *maxfd = peer->sock_fd + 1;
364*a75eb03bSDavid Marchand         }
365*a75eb03bSDavid Marchand     }
366*a75eb03bSDavid Marchand }
367*a75eb03bSDavid Marchand 
368*a75eb03bSDavid Marchand /* process incoming messages on the sockets in fd_set */
369*a75eb03bSDavid Marchand int
370*a75eb03bSDavid Marchand ivshmem_server_handle_fds(IvshmemServer *server, fd_set *fds, int maxfd)
371*a75eb03bSDavid Marchand {
372*a75eb03bSDavid Marchand     IvshmemServerPeer *peer, *peer_next;
373*a75eb03bSDavid Marchand 
374*a75eb03bSDavid Marchand     if (server->sock_fd < maxfd && FD_ISSET(server->sock_fd, fds) &&
375*a75eb03bSDavid Marchand         ivshmem_server_handle_new_conn(server) < 0 && errno != EINTR) {
376*a75eb03bSDavid Marchand         IVSHMEM_SERVER_DEBUG(server, "ivshmem_server_handle_new_conn() "
377*a75eb03bSDavid Marchand                              "failed\n");
378*a75eb03bSDavid Marchand         return -1;
379*a75eb03bSDavid Marchand     }
380*a75eb03bSDavid Marchand 
381*a75eb03bSDavid Marchand     QTAILQ_FOREACH_SAFE(peer, &server->peer_list, next, peer_next) {
382*a75eb03bSDavid Marchand         /* any message from a peer socket result in a close() */
383*a75eb03bSDavid Marchand         IVSHMEM_SERVER_DEBUG(server, "peer->sock_fd=%d\n", peer->sock_fd);
384*a75eb03bSDavid Marchand         if (peer->sock_fd < maxfd && FD_ISSET(peer->sock_fd, fds)) {
385*a75eb03bSDavid Marchand             ivshmem_server_free_peer(server, peer);
386*a75eb03bSDavid Marchand         }
387*a75eb03bSDavid Marchand     }
388*a75eb03bSDavid Marchand 
389*a75eb03bSDavid Marchand     return 0;
390*a75eb03bSDavid Marchand }
391*a75eb03bSDavid Marchand 
392*a75eb03bSDavid Marchand /* lookup peer from its id */
393*a75eb03bSDavid Marchand IvshmemServerPeer *
394*a75eb03bSDavid Marchand ivshmem_server_search_peer(IvshmemServer *server, long peer_id)
395*a75eb03bSDavid Marchand {
396*a75eb03bSDavid Marchand     IvshmemServerPeer *peer;
397*a75eb03bSDavid Marchand 
398*a75eb03bSDavid Marchand     QTAILQ_FOREACH(peer, &server->peer_list, next) {
399*a75eb03bSDavid Marchand         if (peer->id == peer_id) {
400*a75eb03bSDavid Marchand             return peer;
401*a75eb03bSDavid Marchand         }
402*a75eb03bSDavid Marchand     }
403*a75eb03bSDavid Marchand     return NULL;
404*a75eb03bSDavid Marchand }
405*a75eb03bSDavid Marchand 
406*a75eb03bSDavid Marchand /* dump our info, the list of peers their vectors on stdout */
407*a75eb03bSDavid Marchand void
408*a75eb03bSDavid Marchand ivshmem_server_dump(const IvshmemServer *server)
409*a75eb03bSDavid Marchand {
410*a75eb03bSDavid Marchand     const IvshmemServerPeer *peer;
411*a75eb03bSDavid Marchand     unsigned vector;
412*a75eb03bSDavid Marchand 
413*a75eb03bSDavid Marchand     /* dump peers */
414*a75eb03bSDavid Marchand     QTAILQ_FOREACH(peer, &server->peer_list, next) {
415*a75eb03bSDavid Marchand         printf("peer_id = %ld\n", peer->id);
416*a75eb03bSDavid Marchand 
417*a75eb03bSDavid Marchand         for (vector = 0; vector < peer->vectors_count; vector++) {
418*a75eb03bSDavid Marchand             printf("  vector %d is enabled (fd=%d)\n", vector,
419*a75eb03bSDavid Marchand                    event_notifier_get_fd(&peer->vectors[vector]));
420*a75eb03bSDavid Marchand         }
421*a75eb03bSDavid Marchand     }
422*a75eb03bSDavid Marchand }
423