Пример #1
0
int libvchan_wait(libvchan_t *ctrl) {
    int ret = -2; /* invalid, so can be distinguished from real
                     libxenvchan_wait return code */
    struct xs_handle *xs;

    if (ctrl->xenvchan->is_server && libxenvchan_is_open(ctrl->xenvchan) == 2) {
        /* In case of vchan server waiting for a client, we'll not receive any
         * notification if the remote domain dies before connecting. Because of
         * that, check periodically if remote domain is still alive while
         * waiting for a connection. Actually this doesn't cover all the cases
         * - if remote domain is still alive, but remote process dies before
         * connecting, we'll also not receive any notification. But this, in
         * most cases, can be solved by application using libvchan.
         *
         * During normal operation this shouldn't be long - in most cases vchan
         * client will connect almost instantly. So this sleep(10) loop will
         * not hurt. Alternativelly it could be implemented with
         * xs_watch("@releaseDomain"), but such approach will slow down most
         * common execution path (xs_open+xs_watch even if client connects
         * right away).
         */
        while (ret == -2 && libxenvchan_is_open(ctrl->xenvchan) == 2) {
            fd_set rd_set;
            struct timeval tv = { 10, 0 };
            int vchan_fd = libxenvchan_fd_for_select(ctrl->xenvchan);
            FD_ZERO(&rd_set);
            FD_SET(vchan_fd, &rd_set);
            switch (select(vchan_fd+1, &rd_set, NULL, NULL, &tv)) {
                case 0:
                    if (!libvchan__check_domain_alive(ctrl->xc_handle, ctrl->remote_domain))
                        return -1;
                    break;
                case 1:
                    /* break the loop */
                    ret = -1;
                    break;
                default:
                    if (errno == EINTR)
                        break;
                    perror("select");
                    return -1;
            }
        }
    }
    ret = libxenvchan_wait(ctrl->xenvchan);
    if (ctrl->xs_path) {
        /* remove xenstore entry at first client connection */
        xs = xs_open(0);
        if (xs) {
            /* if xenstore connection failed just do not remove entries, but do
             * not abort whole function, especially still free the memory
             */
            xs_rm(xs, 0, ctrl->xs_path);
            xs_close(xs);
        }
        free(ctrl->xs_path);
        ctrl->xs_path = NULL;
    }
    return ret;
}
Пример #2
0
int libvchan_is_open(libvchan_t *ctrl) {
    int ret;
    struct evtchn_status evst;

    ret = libxenvchan_is_open(ctrl->xenvchan);
    if (ret == 2) {
        if (!libvchan__check_domain_alive(ctrl->xc_handle, ctrl->remote_domain))
            return VCHAN_DISCONNECTED;
        return VCHAN_WAITING;
    }
    if (!ret)
        return VCHAN_DISCONNECTED;
    /* slow check in case of domain destroy */
    evst.port = ctrl->xenvchan->event_port;
    evst.dom = DOMID_SELF;
    if (xc_evtchn_status(ctrl->xc_handle, &evst)) {
        perror("xc_evtchn_status");
        return VCHAN_DISCONNECTED;
    }
    if (evst.status != EVTCHNSTAT_interdomain) {
        if (!ctrl->xenvchan->is_server)
            ctrl->xenvchan->ring->srv_live = 0;
        return VCHAN_DISCONNECTED;
    }
    return VCHAN_CONNECTED;
}
Пример #3
0
libvchan_t *libvchan_client_init(int domain, int port) {
    char xs_path[255];
    char xs_path_watch[255];
    libvchan_t *ctrl;
    xc_interface *xc_handle;
    struct xs_handle *xs;
    char **vec;
    unsigned int count, len;
    char *dummy = NULL;
    char *own_domid = NULL;

    xc_handle = xc_interface_open(NULL, NULL, 0);
    if (!xc_handle) {
        /* error already logged by xc_interface_open */
        goto err;
    }

    /* wait for server to appear */
    xs = xs_open(0);
    if (!xs) {
        perror("xs_open");
        goto err_xc;
    }

    len = 0;

    if (!xs_watch(xs, "domid", "domid")) {
        fprintf(stderr, "Cannot setup xenstore watch\n");
        goto err_xs;
    }
    if (!xs_watch(xs, "@releaseDomain", "release")) {
        fprintf(stderr, "Cannot setup xenstore watch\n");
        goto err_xs;
    }
    while (!dummy || !len) {
        vec = xs_read_watch(xs, &count);
        if (vec) {
            if (strcmp(vec[XS_WATCH_TOKEN], "domid") == 0) {
                /* domid have changed */
                if (own_domid) {
                    free(own_domid);
                    own_domid = NULL;
                    xs_unwatch(xs, xs_path_watch, xs_path_watch);
                }
            }
            free(vec);
        }
        if (!own_domid) {
            /* construct xenstore path on first iteration and on every domid
             * change detected (save+restore case) */
            own_domid = xs_read(xs, 0, "domid", &len);
            if (!own_domid) {
                fprintf(stderr, "Cannot get own domid\n");
                goto err_xs;
            }
            if (atoi(own_domid) == domain) {
                fprintf(stderr, "Loopback vchan connection not supported\n");
                free(own_domid);
                goto err_xs;
            }

            snprintf(xs_path, sizeof(xs_path), "/local/domain/%d/data/vchan/%s/%d",
                    domain, own_domid, port);
            /* watch on this key as we might not have access to the whole directory */
            snprintf(xs_path_watch, sizeof(xs_path_watch), "%s/event-channel", xs_path);

            if (!xs_watch(xs, xs_path_watch, xs_path_watch)) {
                fprintf(stderr, "Cannot setup watch on %s\n", xs_path_watch);
                free(own_domid);
                goto err_xs;
            }
        }

        dummy = xs_read(xs, 0, xs_path_watch, &len);
        if (dummy)
            free(dummy);
        else {
            if (!libvchan__check_domain_alive(xc_handle, domain)) {
                fprintf(stderr, "domain dead\n");
                goto err_xs;
            }
        }
    }

    if (own_domid)
        free(own_domid);
    xs_close(xs);

    ctrl = malloc(sizeof(*ctrl));
    if (!ctrl)
        return NULL;
    ctrl->xs_path = NULL;
    ctrl->xenvchan = libxenvchan_client_init(NULL, domain, xs_path);
    if (!ctrl->xenvchan) {
        free(ctrl);
        return NULL;
    }
    ctrl->xenvchan->blocking = 1;
    /* notify server */
    xc_evtchn_notify(ctrl->xenvchan->event, ctrl->xenvchan->event_port);
    ctrl->remote_domain = domain;
    ctrl->xc_handle = xc_handle;
    return ctrl;

err_xs:
    xs_close(xs);
err_xc:
    xc_interface_close(xc_handle);
err:
    return NULL;
}