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