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