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