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