xref: /openbmc/qemu/contrib/ivshmem-client/main.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 
9*a75eb03bSDavid Marchand #include "qemu-common.h"
10*a75eb03bSDavid Marchand 
11*a75eb03bSDavid Marchand #include "ivshmem-client.h"
12*a75eb03bSDavid Marchand 
13*a75eb03bSDavid Marchand #define IVSHMEM_CLIENT_DEFAULT_VERBOSE        0
14*a75eb03bSDavid Marchand #define IVSHMEM_CLIENT_DEFAULT_UNIX_SOCK_PATH "/tmp/ivshmem_socket"
15*a75eb03bSDavid Marchand 
16*a75eb03bSDavid Marchand typedef struct IvshmemClientArgs {
17*a75eb03bSDavid Marchand     bool verbose;
18*a75eb03bSDavid Marchand     const char *unix_sock_path;
19*a75eb03bSDavid Marchand } IvshmemClientArgs;
20*a75eb03bSDavid Marchand 
21*a75eb03bSDavid Marchand /* show ivshmem_client_usage and exit with given error code */
22*a75eb03bSDavid Marchand static void
23*a75eb03bSDavid Marchand ivshmem_client_usage(const char *name, int code)
24*a75eb03bSDavid Marchand {
25*a75eb03bSDavid Marchand     fprintf(stderr, "%s [opts]\n", name);
26*a75eb03bSDavid Marchand     fprintf(stderr, "  -h: show this help\n");
27*a75eb03bSDavid Marchand     fprintf(stderr, "  -v: verbose mode\n");
28*a75eb03bSDavid Marchand     fprintf(stderr, "  -S <unix_sock_path>: path to the unix socket\n"
29*a75eb03bSDavid Marchand                     "     to connect to.\n"
30*a75eb03bSDavid Marchand                     "     default=%s\n", IVSHMEM_CLIENT_DEFAULT_UNIX_SOCK_PATH);
31*a75eb03bSDavid Marchand     exit(code);
32*a75eb03bSDavid Marchand }
33*a75eb03bSDavid Marchand 
34*a75eb03bSDavid Marchand /* parse the program arguments, exit on error */
35*a75eb03bSDavid Marchand static void
36*a75eb03bSDavid Marchand ivshmem_client_parse_args(IvshmemClientArgs *args, int argc, char *argv[])
37*a75eb03bSDavid Marchand {
38*a75eb03bSDavid Marchand     int c;
39*a75eb03bSDavid Marchand 
40*a75eb03bSDavid Marchand     while ((c = getopt(argc, argv,
41*a75eb03bSDavid Marchand                        "h"  /* help */
42*a75eb03bSDavid Marchand                        "v"  /* verbose */
43*a75eb03bSDavid Marchand                        "S:" /* unix_sock_path */
44*a75eb03bSDavid Marchand                       )) != -1) {
45*a75eb03bSDavid Marchand 
46*a75eb03bSDavid Marchand         switch (c) {
47*a75eb03bSDavid Marchand         case 'h': /* help */
48*a75eb03bSDavid Marchand             ivshmem_client_usage(argv[0], 0);
49*a75eb03bSDavid Marchand             break;
50*a75eb03bSDavid Marchand 
51*a75eb03bSDavid Marchand         case 'v': /* verbose */
52*a75eb03bSDavid Marchand             args->verbose = 1;
53*a75eb03bSDavid Marchand             break;
54*a75eb03bSDavid Marchand 
55*a75eb03bSDavid Marchand         case 'S': /* unix_sock_path */
56*a75eb03bSDavid Marchand             args->unix_sock_path = strdup(optarg);
57*a75eb03bSDavid Marchand             break;
58*a75eb03bSDavid Marchand 
59*a75eb03bSDavid Marchand         default:
60*a75eb03bSDavid Marchand             ivshmem_client_usage(argv[0], 1);
61*a75eb03bSDavid Marchand             break;
62*a75eb03bSDavid Marchand         }
63*a75eb03bSDavid Marchand     }
64*a75eb03bSDavid Marchand }
65*a75eb03bSDavid Marchand 
66*a75eb03bSDavid Marchand /* show command line help */
67*a75eb03bSDavid Marchand static void
68*a75eb03bSDavid Marchand ivshmem_client_cmdline_help(void)
69*a75eb03bSDavid Marchand {
70*a75eb03bSDavid Marchand     printf("dump: dump peers (including us)\n"
71*a75eb03bSDavid Marchand            "int <peer> <vector>: notify one vector on a peer\n"
72*a75eb03bSDavid Marchand            "int <peer> all: notify all vectors of a peer\n"
73*a75eb03bSDavid Marchand            "int all: notify all vectors of all peers (excepting us)\n");
74*a75eb03bSDavid Marchand }
75*a75eb03bSDavid Marchand 
76*a75eb03bSDavid Marchand /* read stdin and handle commands */
77*a75eb03bSDavid Marchand static int
78*a75eb03bSDavid Marchand ivshmem_client_handle_stdin_command(IvshmemClient *client)
79*a75eb03bSDavid Marchand {
80*a75eb03bSDavid Marchand     IvshmemClientPeer *peer;
81*a75eb03bSDavid Marchand     char buf[128];
82*a75eb03bSDavid Marchand     char *s, *token;
83*a75eb03bSDavid Marchand     int ret;
84*a75eb03bSDavid Marchand     int peer_id, vector;
85*a75eb03bSDavid Marchand 
86*a75eb03bSDavid Marchand     memset(buf, 0, sizeof(buf));
87*a75eb03bSDavid Marchand     ret = read(0, buf, sizeof(buf) - 1);
88*a75eb03bSDavid Marchand     if (ret < 0) {
89*a75eb03bSDavid Marchand         return -1;
90*a75eb03bSDavid Marchand     }
91*a75eb03bSDavid Marchand 
92*a75eb03bSDavid Marchand     s = buf;
93*a75eb03bSDavid Marchand     while ((token = strsep(&s, "\n\r;")) != NULL) {
94*a75eb03bSDavid Marchand         if (!strcmp(token, "")) {
95*a75eb03bSDavid Marchand             continue;
96*a75eb03bSDavid Marchand         }
97*a75eb03bSDavid Marchand         if (!strcmp(token, "?")) {
98*a75eb03bSDavid Marchand             ivshmem_client_cmdline_help();
99*a75eb03bSDavid Marchand         }
100*a75eb03bSDavid Marchand         if (!strcmp(token, "help")) {
101*a75eb03bSDavid Marchand             ivshmem_client_cmdline_help();
102*a75eb03bSDavid Marchand         } else if (!strcmp(token, "dump")) {
103*a75eb03bSDavid Marchand             ivshmem_client_dump(client);
104*a75eb03bSDavid Marchand         } else if (!strcmp(token, "int all")) {
105*a75eb03bSDavid Marchand             ivshmem_client_notify_broadcast(client);
106*a75eb03bSDavid Marchand         } else if (sscanf(token, "int %d %d", &peer_id, &vector) == 2) {
107*a75eb03bSDavid Marchand             peer = ivshmem_client_search_peer(client, peer_id);
108*a75eb03bSDavid Marchand             if (peer == NULL) {
109*a75eb03bSDavid Marchand                 printf("cannot find peer_id = %d\n", peer_id);
110*a75eb03bSDavid Marchand                 continue;
111*a75eb03bSDavid Marchand             }
112*a75eb03bSDavid Marchand             ivshmem_client_notify(client, peer, vector);
113*a75eb03bSDavid Marchand         } else if (sscanf(token, "int %d all", &peer_id) == 1) {
114*a75eb03bSDavid Marchand             peer = ivshmem_client_search_peer(client, peer_id);
115*a75eb03bSDavid Marchand             if (peer == NULL) {
116*a75eb03bSDavid Marchand                 printf("cannot find peer_id = %d\n", peer_id);
117*a75eb03bSDavid Marchand                 continue;
118*a75eb03bSDavid Marchand             }
119*a75eb03bSDavid Marchand             ivshmem_client_notify_all_vects(client, peer);
120*a75eb03bSDavid Marchand         } else {
121*a75eb03bSDavid Marchand             printf("invalid command, type help\n");
122*a75eb03bSDavid Marchand         }
123*a75eb03bSDavid Marchand     }
124*a75eb03bSDavid Marchand 
125*a75eb03bSDavid Marchand     printf("cmd> ");
126*a75eb03bSDavid Marchand     fflush(stdout);
127*a75eb03bSDavid Marchand     return 0;
128*a75eb03bSDavid Marchand }
129*a75eb03bSDavid Marchand 
130*a75eb03bSDavid Marchand /* listen on stdin (command line), on unix socket (notifications of new
131*a75eb03bSDavid Marchand  * and dead peers), and on eventfd (IRQ request) */
132*a75eb03bSDavid Marchand static int
133*a75eb03bSDavid Marchand ivshmem_client_poll_events(IvshmemClient *client)
134*a75eb03bSDavid Marchand {
135*a75eb03bSDavid Marchand     fd_set fds;
136*a75eb03bSDavid Marchand     int ret, maxfd;
137*a75eb03bSDavid Marchand 
138*a75eb03bSDavid Marchand     while (1) {
139*a75eb03bSDavid Marchand 
140*a75eb03bSDavid Marchand         FD_ZERO(&fds);
141*a75eb03bSDavid Marchand         FD_SET(0, &fds); /* add stdin in fd_set */
142*a75eb03bSDavid Marchand         maxfd = 1;
143*a75eb03bSDavid Marchand 
144*a75eb03bSDavid Marchand         ivshmem_client_get_fds(client, &fds, &maxfd);
145*a75eb03bSDavid Marchand 
146*a75eb03bSDavid Marchand         ret = select(maxfd, &fds, NULL, NULL, NULL);
147*a75eb03bSDavid Marchand         if (ret < 0) {
148*a75eb03bSDavid Marchand             if (errno == EINTR) {
149*a75eb03bSDavid Marchand                 continue;
150*a75eb03bSDavid Marchand             }
151*a75eb03bSDavid Marchand 
152*a75eb03bSDavid Marchand             fprintf(stderr, "select error: %s\n", strerror(errno));
153*a75eb03bSDavid Marchand             break;
154*a75eb03bSDavid Marchand         }
155*a75eb03bSDavid Marchand         if (ret == 0) {
156*a75eb03bSDavid Marchand             continue;
157*a75eb03bSDavid Marchand         }
158*a75eb03bSDavid Marchand 
159*a75eb03bSDavid Marchand         if (FD_ISSET(0, &fds) &&
160*a75eb03bSDavid Marchand             ivshmem_client_handle_stdin_command(client) < 0 && errno != EINTR) {
161*a75eb03bSDavid Marchand             fprintf(stderr, "ivshmem_client_handle_stdin_command() failed\n");
162*a75eb03bSDavid Marchand             break;
163*a75eb03bSDavid Marchand         }
164*a75eb03bSDavid Marchand 
165*a75eb03bSDavid Marchand         if (ivshmem_client_handle_fds(client, &fds, maxfd) < 0) {
166*a75eb03bSDavid Marchand             fprintf(stderr, "ivshmem_client_handle_fds() failed\n");
167*a75eb03bSDavid Marchand             break;
168*a75eb03bSDavid Marchand         }
169*a75eb03bSDavid Marchand     }
170*a75eb03bSDavid Marchand 
171*a75eb03bSDavid Marchand     return ret;
172*a75eb03bSDavid Marchand }
173*a75eb03bSDavid Marchand 
174*a75eb03bSDavid Marchand /* callback when we receive a notification (just display it) */
175*a75eb03bSDavid Marchand static void
176*a75eb03bSDavid Marchand ivshmem_client_notification_cb(const IvshmemClient *client,
177*a75eb03bSDavid Marchand                                const IvshmemClientPeer *peer,
178*a75eb03bSDavid Marchand                                unsigned vect, void *arg)
179*a75eb03bSDavid Marchand {
180*a75eb03bSDavid Marchand     (void)client;
181*a75eb03bSDavid Marchand     (void)arg;
182*a75eb03bSDavid Marchand     printf("receive notification from peer_id=%ld vector=%d\n", peer->id, vect);
183*a75eb03bSDavid Marchand }
184*a75eb03bSDavid Marchand 
185*a75eb03bSDavid Marchand int
186*a75eb03bSDavid Marchand main(int argc, char *argv[])
187*a75eb03bSDavid Marchand {
188*a75eb03bSDavid Marchand     struct sigaction sa;
189*a75eb03bSDavid Marchand     IvshmemClient client;
190*a75eb03bSDavid Marchand     IvshmemClientArgs args = {
191*a75eb03bSDavid Marchand         .verbose = IVSHMEM_CLIENT_DEFAULT_VERBOSE,
192*a75eb03bSDavid Marchand         .unix_sock_path = IVSHMEM_CLIENT_DEFAULT_UNIX_SOCK_PATH,
193*a75eb03bSDavid Marchand     };
194*a75eb03bSDavid Marchand 
195*a75eb03bSDavid Marchand     /* parse arguments, will exit on error */
196*a75eb03bSDavid Marchand     ivshmem_client_parse_args(&args, argc, argv);
197*a75eb03bSDavid Marchand 
198*a75eb03bSDavid Marchand     /* Ignore SIGPIPE, see this link for more info:
199*a75eb03bSDavid Marchand      * http://www.mail-archive.com/libevent-users@monkey.org/msg01606.html */
200*a75eb03bSDavid Marchand     sa.sa_handler = SIG_IGN;
201*a75eb03bSDavid Marchand     sa.sa_flags = 0;
202*a75eb03bSDavid Marchand     if (sigemptyset(&sa.sa_mask) == -1 ||
203*a75eb03bSDavid Marchand         sigaction(SIGPIPE, &sa, 0) == -1) {
204*a75eb03bSDavid Marchand         perror("failed to ignore SIGPIPE; sigaction");
205*a75eb03bSDavid Marchand         return 1;
206*a75eb03bSDavid Marchand     }
207*a75eb03bSDavid Marchand 
208*a75eb03bSDavid Marchand     ivshmem_client_cmdline_help();
209*a75eb03bSDavid Marchand     printf("cmd> ");
210*a75eb03bSDavid Marchand     fflush(stdout);
211*a75eb03bSDavid Marchand 
212*a75eb03bSDavid Marchand     if (ivshmem_client_init(&client, args.unix_sock_path,
213*a75eb03bSDavid Marchand                             ivshmem_client_notification_cb, NULL,
214*a75eb03bSDavid Marchand                             args.verbose) < 0) {
215*a75eb03bSDavid Marchand         fprintf(stderr, "cannot init client\n");
216*a75eb03bSDavid Marchand         return 1;
217*a75eb03bSDavid Marchand     }
218*a75eb03bSDavid Marchand 
219*a75eb03bSDavid Marchand     while (1) {
220*a75eb03bSDavid Marchand         if (ivshmem_client_connect(&client) < 0) {
221*a75eb03bSDavid Marchand             fprintf(stderr, "cannot connect to server, retry in 1 second\n");
222*a75eb03bSDavid Marchand             sleep(1);
223*a75eb03bSDavid Marchand             continue;
224*a75eb03bSDavid Marchand         }
225*a75eb03bSDavid Marchand 
226*a75eb03bSDavid Marchand         fprintf(stdout, "listen on server socket %d\n", client.sock_fd);
227*a75eb03bSDavid Marchand 
228*a75eb03bSDavid Marchand         if (ivshmem_client_poll_events(&client) == 0) {
229*a75eb03bSDavid Marchand             continue;
230*a75eb03bSDavid Marchand         }
231*a75eb03bSDavid Marchand 
232*a75eb03bSDavid Marchand         /* disconnected from server, reset all peers */
233*a75eb03bSDavid Marchand         fprintf(stdout, "disconnected from server\n");
234*a75eb03bSDavid Marchand 
235*a75eb03bSDavid Marchand         ivshmem_client_close(&client);
236*a75eb03bSDavid Marchand     }
237*a75eb03bSDavid Marchand 
238*a75eb03bSDavid Marchand     return 0;
239*a75eb03bSDavid Marchand }
240