qemu/contrib/ivshmem-server/main.c
<<
>>
Prefs
   1/*
   2 * Copyright 6WIND S.A., 2014
   3 *
   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 */
   8
   9#include "qemu/osdep.h"
  10#include "qapi/error.h"
  11#include "qemu/cutils.h"
  12#include "qemu/option.h"
  13#include "ivshmem-server.h"
  14
  15#define IVSHMEM_SERVER_DEFAULT_VERBOSE        0
  16#define IVSHMEM_SERVER_DEFAULT_FOREGROUND     0
  17#define IVSHMEM_SERVER_DEFAULT_PID_FILE       "/var/run/ivshmem-server.pid"
  18#define IVSHMEM_SERVER_DEFAULT_UNIX_SOCK_PATH "/tmp/ivshmem_socket"
  19#define IVSHMEM_SERVER_DEFAULT_SHM_PATH       "ivshmem"
  20#define IVSHMEM_SERVER_DEFAULT_SHM_SIZE       (4*1024*1024)
  21#define IVSHMEM_SERVER_DEFAULT_N_VECTORS      1
  22
  23/* used to quit on signal SIGTERM */
  24static int ivshmem_server_quit;
  25
  26/* arguments given by the user */
  27typedef struct IvshmemServerArgs {
  28    bool verbose;
  29    bool foreground;
  30    const char *pid_file;
  31    const char *unix_socket_path;
  32    const char *shm_path;
  33    bool use_shm_open;
  34    uint64_t shm_size;
  35    unsigned n_vectors;
  36} IvshmemServerArgs;
  37
  38static void
  39ivshmem_server_usage(const char *progname)
  40{
  41    printf("Usage: %s [OPTION]...\n"
  42           "  -h: show this help\n"
  43           "  -v: verbose mode\n"
  44           "  -F: foreground mode (default is to daemonize)\n"
  45           "  -p <pid-file>: path to the PID file (used in daemon mode only)\n"
  46           "     default " IVSHMEM_SERVER_DEFAULT_PID_FILE "\n"
  47           "  -S <unix-socket-path>: path to the unix socket to listen to\n"
  48           "     default " IVSHMEM_SERVER_DEFAULT_UNIX_SOCK_PATH "\n"
  49           "  -M <shm-name>: POSIX shared memory object to use\n"
  50           "     default " IVSHMEM_SERVER_DEFAULT_SHM_PATH "\n"
  51           "  -m <dir-name>: where to create shared memory\n"
  52           "  -l <size>: size of shared memory in bytes\n"
  53           "     suffixes K, M and G can be used, e.g. 1K means 1024\n"
  54           "     default %u\n"
  55           "  -n <nvectors>: number of vectors\n"
  56           "     default %u\n",
  57           progname, IVSHMEM_SERVER_DEFAULT_SHM_SIZE,
  58           IVSHMEM_SERVER_DEFAULT_N_VECTORS);
  59}
  60
  61static void
  62ivshmem_server_help(const char *progname)
  63{
  64    fprintf(stderr, "Try '%s -h' for more information.\n", progname);
  65}
  66
  67/* parse the program arguments, exit on error */
  68static void
  69ivshmem_server_parse_args(IvshmemServerArgs *args, int argc, char *argv[])
  70{
  71    int c;
  72    unsigned long long v;
  73    Error *err = NULL;
  74
  75    while ((c = getopt(argc, argv, "hvFp:S:m:M:l:n:")) != -1) {
  76
  77        switch (c) {
  78        case 'h': /* help */
  79            ivshmem_server_usage(argv[0]);
  80            exit(0);
  81            break;
  82
  83        case 'v': /* verbose */
  84            args->verbose = 1;
  85            break;
  86
  87        case 'F': /* foreground */
  88            args->foreground = 1;
  89            break;
  90
  91        case 'p': /* pid file */
  92            args->pid_file = optarg;
  93            break;
  94
  95        case 'S': /* unix socket path */
  96            args->unix_socket_path = optarg;
  97            break;
  98
  99        case 'M': /* shm name */
 100        case 'm': /* dir name */
 101            args->shm_path = optarg;
 102            args->use_shm_open = c == 'M';
 103            break;
 104
 105        case 'l': /* shm size */
 106            parse_option_size("shm_size", optarg, &args->shm_size, &err);
 107            if (err) {
 108                error_report_err(err);
 109                ivshmem_server_help(argv[0]);
 110                exit(1);
 111            }
 112            break;
 113
 114        case 'n': /* number of vectors */
 115            if (parse_uint_full(optarg, &v, 0) < 0) {
 116                fprintf(stderr, "cannot parse n_vectors\n");
 117                ivshmem_server_help(argv[0]);
 118                exit(1);
 119            }
 120            args->n_vectors = v;
 121            break;
 122
 123        default:
 124            ivshmem_server_usage(argv[0]);
 125            exit(1);
 126            break;
 127        }
 128    }
 129
 130    if (args->n_vectors > IVSHMEM_SERVER_MAX_VECTORS) {
 131        fprintf(stderr, "too many requested vectors (max is %d)\n",
 132                IVSHMEM_SERVER_MAX_VECTORS);
 133        ivshmem_server_help(argv[0]);
 134        exit(1);
 135    }
 136
 137    if (args->verbose == 1 && args->foreground == 0) {
 138        fprintf(stderr, "cannot use verbose in daemon mode\n");
 139        ivshmem_server_help(argv[0]);
 140        exit(1);
 141    }
 142}
 143
 144/* wait for events on listening server unix socket and connected client
 145 * sockets */
 146static int
 147ivshmem_server_poll_events(IvshmemServer *server)
 148{
 149    fd_set fds;
 150    int ret = 0, maxfd;
 151
 152    while (!ivshmem_server_quit) {
 153
 154        FD_ZERO(&fds);
 155        maxfd = 0;
 156        ivshmem_server_get_fds(server, &fds, &maxfd);
 157
 158        ret = select(maxfd, &fds, NULL, NULL, NULL);
 159
 160        if (ret < 0) {
 161            if (errno == EINTR) {
 162                continue;
 163            }
 164
 165            fprintf(stderr, "select error: %s\n", strerror(errno));
 166            break;
 167        }
 168        if (ret == 0) {
 169            continue;
 170        }
 171
 172        if (ivshmem_server_handle_fds(server, &fds, maxfd) < 0) {
 173            fprintf(stderr, "ivshmem_server_handle_fds() failed\n");
 174            break;
 175        }
 176    }
 177
 178    return ret;
 179}
 180
 181static void
 182ivshmem_server_quit_cb(int signum)
 183{
 184    ivshmem_server_quit = 1;
 185}
 186
 187int
 188main(int argc, char *argv[])
 189{
 190    IvshmemServer server;
 191    struct sigaction sa, sa_quit;
 192    IvshmemServerArgs args = {
 193        .verbose = IVSHMEM_SERVER_DEFAULT_VERBOSE,
 194        .foreground = IVSHMEM_SERVER_DEFAULT_FOREGROUND,
 195        .pid_file = IVSHMEM_SERVER_DEFAULT_PID_FILE,
 196        .unix_socket_path = IVSHMEM_SERVER_DEFAULT_UNIX_SOCK_PATH,
 197        .shm_path = IVSHMEM_SERVER_DEFAULT_SHM_PATH,
 198        .use_shm_open = true,
 199        .shm_size = IVSHMEM_SERVER_DEFAULT_SHM_SIZE,
 200        .n_vectors = IVSHMEM_SERVER_DEFAULT_N_VECTORS,
 201    };
 202    int ret = 1;
 203
 204    /*
 205     * Do not remove this notice without adding proper error handling!
 206     * Start with handling ivshmem_server_send_one_msg() failure.
 207     */
 208    printf("*** Example code, do not use in production ***\n");
 209
 210    /* parse arguments, will exit on error */
 211    ivshmem_server_parse_args(&args, argc, argv);
 212
 213    /* Ignore SIGPIPE, see this link for more info:
 214     * http://www.mail-archive.com/libevent-users@monkey.org/msg01606.html */
 215    sa.sa_handler = SIG_IGN;
 216    sa.sa_flags = 0;
 217    if (sigemptyset(&sa.sa_mask) == -1 ||
 218        sigaction(SIGPIPE, &sa, 0) == -1) {
 219        perror("failed to ignore SIGPIPE; sigaction");
 220        goto err;
 221    }
 222
 223    sa_quit.sa_handler = ivshmem_server_quit_cb;
 224    sa_quit.sa_flags = 0;
 225    if (sigemptyset(&sa_quit.sa_mask) == -1 ||
 226        sigaction(SIGTERM, &sa_quit, 0) == -1) {
 227        perror("failed to add SIGTERM handler; sigaction");
 228        goto err;
 229    }
 230
 231    /* init the ivshms structure */
 232    if (ivshmem_server_init(&server, args.unix_socket_path,
 233                            args.shm_path, args.use_shm_open,
 234                            args.shm_size, args.n_vectors, args.verbose) < 0) {
 235        fprintf(stderr, "cannot init server\n");
 236        goto err;
 237    }
 238
 239    /* start the ivshmem server (open shm & unix socket) */
 240    if (ivshmem_server_start(&server) < 0) {
 241        fprintf(stderr, "cannot bind\n");
 242        goto err;
 243    }
 244
 245    /* daemonize if asked to */
 246    if (!args.foreground) {
 247        FILE *fp;
 248
 249        if (qemu_daemon(1, 1) < 0) {
 250            fprintf(stderr, "cannot daemonize: %s\n", strerror(errno));
 251            goto err_close;
 252        }
 253
 254        /* write pid file */
 255        fp = fopen(args.pid_file, "w");
 256        if (fp == NULL) {
 257            fprintf(stderr, "cannot write pid file: %s\n", strerror(errno));
 258            goto err_close;
 259        }
 260
 261        fprintf(fp, "%d\n", (int) getpid());
 262        fclose(fp);
 263    }
 264
 265    ivshmem_server_poll_events(&server);
 266    fprintf(stdout, "server disconnected\n");
 267    ret = 0;
 268
 269err_close:
 270    ivshmem_server_close(&server);
 271err:
 272    return ret;
 273}
 274