qemu-sockets.c 26.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
 *  inet and unix socket functions for qemu
 *
 *  (c) 2008 Gerd Hoffmann <kraxel@redhat.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; under version 2 of the License.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
14 15 16
 *
 * Contributions after 2012-01-13 are licensed under the terms of the
 * GNU GPL, version 2 or (at your option) any later version.
17
 */
18 19 20 21 22 23 24
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <unistd.h>

25
#include "monitor/monitor.h"
26
#include "qemu/sockets.h"
27
#include "qemu-common.h" /* for qemu_isdigit */
28
#include "qemu/main-loop.h"
29 30 31 32 33 34 35

#ifndef AI_ADDRCONFIG
# define AI_ADDRCONFIG 0
#endif

static const int on=1, off=0;

36 37 38 39
/* used temporarily until all users are converted to QemuOpts */
QemuOptsList socket_optslist = {
    .name = "socket",
    .head = QTAILQ_HEAD_INITIALIZER(socket_optslist.head),
G
Gerd Hoffmann 已提交
40 41 42 43
    .desc = {
        {
            .name = "path",
            .type = QEMU_OPT_STRING,
G
Gerd Hoffmann 已提交
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
        },{
            .name = "host",
            .type = QEMU_OPT_STRING,
        },{
            .name = "port",
            .type = QEMU_OPT_STRING,
        },{
            .name = "to",
            .type = QEMU_OPT_NUMBER,
        },{
            .name = "ipv4",
            .type = QEMU_OPT_BOOL,
        },{
            .name = "ipv6",
            .type = QEMU_OPT_BOOL,
G
Gerd Hoffmann 已提交
59 60 61 62 63
        },
        { /* end if list */ }
    },
};

64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
static int inet_getport(struct addrinfo *e)
{
    struct sockaddr_in *i4;
    struct sockaddr_in6 *i6;

    switch (e->ai_family) {
    case PF_INET6:
        i6 = (void*)e->ai_addr;
        return ntohs(i6->sin6_port);
    case PF_INET:
        i4 = (void*)e->ai_addr;
        return ntohs(i4->sin_port);
    default:
        return 0;
    }
}

static void inet_setport(struct addrinfo *e, int port)
{
    struct sockaddr_in *i4;
    struct sockaddr_in6 *i6;

    switch (e->ai_family) {
    case PF_INET6:
        i6 = (void*)e->ai_addr;
        i6->sin6_port = htons(port);
        break;
    case PF_INET:
        i4 = (void*)e->ai_addr;
        i4->sin_port = htons(port);
        break;
    }
}

98
const char *inet_strfamily(int family)
99 100 101 102 103 104
{
    switch (family) {
    case PF_INET6: return "ipv6";
    case PF_INET:  return "ipv4";
    case PF_UNIX:  return "unix";
    }
105
    return "unknown";
106 107
}

108
int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp)
109 110
{
    struct addrinfo ai,*res,*e;
G
Gerd Hoffmann 已提交
111
    const char *addr;
112 113 114
    char port[33];
    char uaddr[INET6_ADDRSTRLEN+1];
    char uport[33];
115
    int slisten, rc, to, port_min, port_max, p;
116 117 118 119

    memset(&ai,0, sizeof(ai));
    ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
    ai.ai_family = PF_UNSPEC;
G
Gerd Hoffmann 已提交
120
    ai.ai_socktype = SOCK_STREAM;
121

122 123
    if ((qemu_opt_get(opts, "host") == NULL) ||
        (qemu_opt_get(opts, "port") == NULL)) {
124
        error_setg(errp, "host and/or port not specified");
G
Gerd Hoffmann 已提交
125
        return -1;
126
    }
G
Gerd Hoffmann 已提交
127 128
    pstrcpy(port, sizeof(port), qemu_opt_get(opts, "port"));
    addr = qemu_opt_get(opts, "host");
129

G
Gerd Hoffmann 已提交
130 131
    to = qemu_opt_get_number(opts, "to", 0);
    if (qemu_opt_get_bool(opts, "ipv4", 0))
132
        ai.ai_family = PF_INET;
G
Gerd Hoffmann 已提交
133
    if (qemu_opt_get_bool(opts, "ipv6", 0))
134 135 136 137 138 139 140
        ai.ai_family = PF_INET6;

    /* lookup */
    if (port_offset)
        snprintf(port, sizeof(port), "%d", atoi(port) + port_offset);
    rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res);
    if (rc != 0) {
141 142
        error_setg(errp, "address resolution failed for %s:%s: %s", addr, port,
                   gai_strerror(rc));
143 144 145 146 147
        return -1;
    }

    /* create socket + bind */
    for (e = res; e != NULL; e = e->ai_next) {
V
vibi 已提交
148 149 150
        getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
		        uaddr,INET6_ADDRSTRLEN,uport,32,
		        NI_NUMERICHOST | NI_NUMERICSERV);
K
Kevin Wolf 已提交
151
        slisten = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol);
V
vibi 已提交
152
        if (slisten < 0) {
153
            if (!e->ai_next) {
154
                error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED);
155
            }
V
vibi 已提交
156 157
            continue;
        }
158

159
        qemu_setsockopt(slisten, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
160 161 162
#ifdef IPV6_V6ONLY
        if (e->ai_family == PF_INET6) {
            /* listen on both ipv4 and ipv6 */
163 164
            qemu_setsockopt(slisten, IPPROTO_IPV6, IPV6_V6ONLY, &off,
                            sizeof(off));
165 166 167
        }
#endif

168 169 170 171
        port_min = inet_getport(e);
        port_max = to ? to + port_offset : port_min;
        for (p = port_min; p <= port_max; p++) {
            inet_setport(e, p);
172 173 174
            if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) {
                goto listen;
            }
175
            if (p == port_max) {
176
                if (!e->ai_next) {
177
                    error_set_errno(errp, errno, QERR_SOCKET_BIND_FAILED);
178
                }
179 180 181 182 183 184 185 186 187
            }
        }
        closesocket(slisten);
    }
    freeaddrinfo(res);
    return -1;

listen:
    if (listen(slisten,1) != 0) {
188
        error_set_errno(errp, errno, QERR_SOCKET_LISTEN_FAILED);
189
        closesocket(slisten);
V
vibi 已提交
190
        freeaddrinfo(res);
191 192
        return -1;
    }
G
Gerd Hoffmann 已提交
193 194 195 196 197
    snprintf(uport, sizeof(uport), "%d", inet_getport(e) - port_offset);
    qemu_opt_set(opts, "host", uaddr);
    qemu_opt_set(opts, "port", uport);
    qemu_opt_set(opts, "ipv6", (e->ai_family == PF_INET6) ? "on" : "off");
    qemu_opt_set(opts, "ipv4", (e->ai_family != PF_INET6) ? "on" : "off");
198 199 200 201
    freeaddrinfo(res);
    return slisten;
}

202 203 204 205 206 207 208 209
#ifdef _WIN32
#define QEMU_SOCKET_RC_INPROGRESS(rc) \
    ((rc) == -EINPROGRESS || (rc) == -EWOULDBLOCK || (rc) == -WSAEALREADY)
#else
#define QEMU_SOCKET_RC_INPROGRESS(rc) \
    ((rc) == -EINPROGRESS)
#endif

210 211 212 213 214 215 216 217 218 219
/* Struct to store connect state for non blocking connect */
typedef struct ConnectState {
    int fd;
    struct addrinfo *addr_list;
    struct addrinfo *current_addr;
    NonBlockingConnectHandler *callback;
    void *opaque;
} ConnectState;

static int inet_connect_addr(struct addrinfo *addr, bool *in_progress,
220
                             ConnectState *connect_state, Error **errp);
221 222

static void wait_for_connect(void *opaque)
223
{
224 225 226 227 228 229 230 231
    ConnectState *s = opaque;
    int val = 0, rc = 0;
    socklen_t valsize = sizeof(val);
    bool in_progress;

    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);

    do {
232
        rc = qemu_getsockopt(s->fd, SOL_SOCKET, SO_ERROR, &val, &valsize);
233 234 235 236 237 238 239 240 241 242 243 244 245 246
    } while (rc == -1 && socket_error() == EINTR);

    /* update rc to contain error */
    if (!rc && val) {
        rc = -1;
    }

    /* connect error */
    if (rc < 0) {
        closesocket(s->fd);
        s->fd = rc;
    }

    /* try to connect to the next address on the list */
247 248 249
    if (s->current_addr) {
        while (s->current_addr->ai_next != NULL && s->fd < 0) {
            s->current_addr = s->current_addr->ai_next;
250
            s->fd = inet_connect_addr(s->current_addr, &in_progress, s, NULL);
251 252 253 254
            /* connect in progress */
            if (in_progress) {
                return;
            }
255
        }
256 257

        freeaddrinfo(s->addr_list);
258
    }
259

260 261
    if (s->callback) {
        s->callback(s->fd, s->opaque);
262
    }
263 264 265 266
    g_free(s);
}

static int inet_connect_addr(struct addrinfo *addr, bool *in_progress,
267
                             ConnectState *connect_state, Error **errp)
268 269 270 271
{
    int sock, rc;

    *in_progress = false;
272 273 274

    sock = qemu_socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
    if (sock < 0) {
275
        error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED);
276 277
        return -1;
    }
278
    qemu_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
279
    if (connect_state != NULL) {
280
        qemu_set_nonblock(sock);
281 282 283 284 285 286 287 288 289
    }
    /* connect to peer */
    do {
        rc = 0;
        if (connect(sock, addr->ai_addr, addr->ai_addrlen) < 0) {
            rc = -socket_error();
        }
    } while (rc == -EINTR);

290 291 292 293 294
    if (connect_state != NULL && QEMU_SOCKET_RC_INPROGRESS(rc)) {
        connect_state->fd = sock;
        qemu_set_fd_handler2(sock, NULL, NULL, wait_for_connect,
                             connect_state);
        *in_progress = true;
295
    } else if (rc < 0) {
296
        error_set_errno(errp, errno, QERR_SOCKET_CONNECT_FAILED);
297 298 299 300 301 302 303 304 305 306
        closesocket(sock);
        return -1;
    }
    return sock;
}

static struct addrinfo *inet_parse_connect_opts(QemuOpts *opts, Error **errp)
{
    struct addrinfo ai, *res;
    int rc;
G
Gerd Hoffmann 已提交
307 308
    const char *addr;
    const char *port;
309

310
    memset(&ai, 0, sizeof(ai));
311

312 313
    ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
    ai.ai_family = PF_UNSPEC;
G
Gerd Hoffmann 已提交
314
    ai.ai_socktype = SOCK_STREAM;
315

G
Gerd Hoffmann 已提交
316 317 318
    addr = qemu_opt_get(opts, "host");
    port = qemu_opt_get(opts, "port");
    if (addr == NULL || port == NULL) {
319
        error_setg(errp, "host and/or port not specified");
320
        return NULL;
321 322
    }

323
    if (qemu_opt_get_bool(opts, "ipv4", 0)) {
324
        ai.ai_family = PF_INET;
325 326
    }
    if (qemu_opt_get_bool(opts, "ipv6", 0)) {
327
        ai.ai_family = PF_INET6;
328
    }
329 330

    /* lookup */
331 332
    rc = getaddrinfo(addr, port, &ai, &res);
    if (rc != 0) {
333 334
        error_setg(errp, "address resolution failed for %s:%s: %s", addr, port,
                   gai_strerror(rc));
335 336 337 338 339
        return NULL;
    }
    return res;
}

340 341 342 343 344 345
/**
 * Create a socket and connect it to an address.
 *
 * @opts: QEMU options, recognized parameters strings "host" and "port",
 *        bools "ipv4" and "ipv6".
 * @errp: set on error
346 347
 * @callback: callback function for non-blocking connect
 * @opaque: opaque for callback function
348 349
 *
 * Returns: -1 on error, file descriptor on success.
350 351 352 353
 *
 * If @callback is non-null, the connect is non-blocking.  If this
 * function succeeds, callback will be called when the connection
 * completes, with the file descriptor on success, or -1 on error.
354
 */
355 356
int inet_connect_opts(QemuOpts *opts, Error **errp,
                      NonBlockingConnectHandler *callback, void *opaque)
357 358 359
{
    struct addrinfo *res, *e;
    int sock = -1;
360 361
    bool in_progress;
    ConnectState *connect_state = NULL;
362 363 364 365 366 367

    res = inet_parse_connect_opts(opts, errp);
    if (!res) {
        return -1;
    }

368 369 370 371 372
    if (callback != NULL) {
        connect_state = g_malloc0(sizeof(*connect_state));
        connect_state->addr_list = res;
        connect_state->callback = callback;
        connect_state->opaque = opaque;
373 374 375
    }

    for (e = res; e != NULL; e = e->ai_next) {
376 377 378 379
        if (error_is_set(errp)) {
            error_free(*errp);
            *errp = NULL;
        }
380 381 382
        if (connect_state != NULL) {
            connect_state->current_addr = e;
        }
383
        sock = inet_connect_addr(e, &in_progress, connect_state, errp);
384 385 386 387 388 389 390
        if (in_progress) {
            return sock;
        } else if (sock >= 0) {
            /* non blocking socket immediate success, call callback */
            if (callback != NULL) {
                callback(sock, opaque);
            }
391
            break;
392
        }
393
    }
394
    g_free(connect_state);
395
    freeaddrinfo(res);
396
    return sock;
397 398
}

399
int inet_dgram_opts(QemuOpts *opts, Error **errp)
G
Gerd Hoffmann 已提交
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
{
    struct addrinfo ai, *peer = NULL, *local = NULL;
    const char *addr;
    const char *port;
    int sock = -1, rc;

    /* lookup peer addr */
    memset(&ai,0, sizeof(ai));
    ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
    ai.ai_family = PF_UNSPEC;
    ai.ai_socktype = SOCK_DGRAM;

    addr = qemu_opt_get(opts, "host");
    port = qemu_opt_get(opts, "port");
    if (addr == NULL || strlen(addr) == 0) {
        addr = "localhost";
    }
    if (port == NULL || strlen(port) == 0) {
418
        error_setg(errp, "remote port not specified");
G
Gerd Hoffmann 已提交
419 420 421 422 423 424 425 426 427
        return -1;
    }

    if (qemu_opt_get_bool(opts, "ipv4", 0))
        ai.ai_family = PF_INET;
    if (qemu_opt_get_bool(opts, "ipv6", 0))
        ai.ai_family = PF_INET6;

    if (0 != (rc = getaddrinfo(addr, port, &ai, &peer))) {
428 429
        error_setg(errp, "address resolution failed for %s:%s: %s", addr, port,
                   gai_strerror(rc));
G
Gerd Hoffmann 已提交
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447
	return -1;
    }

    /* lookup local addr */
    memset(&ai,0, sizeof(ai));
    ai.ai_flags = AI_PASSIVE;
    ai.ai_family = peer->ai_family;
    ai.ai_socktype = SOCK_DGRAM;

    addr = qemu_opt_get(opts, "localaddr");
    port = qemu_opt_get(opts, "localport");
    if (addr == NULL || strlen(addr) == 0) {
        addr = NULL;
    }
    if (!port || strlen(port) == 0)
        port = "0";

    if (0 != (rc = getaddrinfo(addr, port, &ai, &local))) {
448 449
        error_setg(errp, "address resolution failed for %s:%s: %s", addr, port,
                   gai_strerror(rc));
450
        goto err;
G
Gerd Hoffmann 已提交
451 452 453
    }

    /* create socket */
K
Kevin Wolf 已提交
454
    sock = qemu_socket(peer->ai_family, peer->ai_socktype, peer->ai_protocol);
G
Gerd Hoffmann 已提交
455
    if (sock < 0) {
456
        error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED);
G
Gerd Hoffmann 已提交
457 458
        goto err;
    }
459
    qemu_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
G
Gerd Hoffmann 已提交
460 461 462

    /* bind socket */
    if (bind(sock, local->ai_addr, local->ai_addrlen) < 0) {
463
        error_set_errno(errp, errno, QERR_SOCKET_BIND_FAILED);
G
Gerd Hoffmann 已提交
464 465 466 467 468
        goto err;
    }

    /* connect to peer */
    if (connect(sock,peer->ai_addr,peer->ai_addrlen) < 0) {
469
        error_set_errno(errp, errno, QERR_SOCKET_CONNECT_FAILED);
G
Gerd Hoffmann 已提交
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
        goto err;
    }

    freeaddrinfo(local);
    freeaddrinfo(peer);
    return sock;

err:
    if (-1 != sock)
        closesocket(sock);
    if (local)
        freeaddrinfo(local);
    if (peer)
        freeaddrinfo(peer);
    return -1;
}

G
Gerd Hoffmann 已提交
487
/* compatibility wrapper */
488
InetSocketAddress *inet_parse(const char *str, Error **errp)
G
Gerd Hoffmann 已提交
489
{
490
    InetSocketAddress *addr;
G
Gerd Hoffmann 已提交
491
    const char *optstr, *h;
492
    char host[64];
G
Gerd Hoffmann 已提交
493
    char port[33];
494
    int to;
G
Gerd Hoffmann 已提交
495 496
    int pos;

497 498
    addr = g_new0(InetSocketAddress, 1);

G
Gerd Hoffmann 已提交
499 500 501
    /* parse address */
    if (str[0] == ':') {
        /* no host given */
502 503
        host[0] = '\0';
        if (1 != sscanf(str, ":%32[^,]%n", port, &pos)) {
504
            error_setg(errp, "error parsing port in address '%s'", str);
505
            goto fail;
G
Gerd Hoffmann 已提交
506 507 508
        }
    } else if (str[0] == '[') {
        /* IPv6 addr */
509
        if (2 != sscanf(str, "[%64[^]]]:%32[^,]%n", host, port, &pos)) {
510
            error_setg(errp, "error parsing IPv6 address '%s'", str);
511
            goto fail;
G
Gerd Hoffmann 已提交
512
        }
513
        addr->ipv6 = addr->has_ipv6 = true;
G
Gerd Hoffmann 已提交
514 515
    } else if (qemu_isdigit(str[0])) {
        /* IPv4 addr */
516
        if (2 != sscanf(str, "%64[0-9.]:%32[^,]%n", host, port, &pos)) {
517
            error_setg(errp, "error parsing IPv4 address '%s'", str);
518
            goto fail;
G
Gerd Hoffmann 已提交
519
        }
520
        addr->ipv4 = addr->has_ipv4 = true;
G
Gerd Hoffmann 已提交
521 522
    } else {
        /* hostname */
523
        if (2 != sscanf(str, "%64[^:]:%32[^,]%n", host, port, &pos)) {
524
            error_setg(errp, "error parsing address '%s'", str);
525
            goto fail;
G
Gerd Hoffmann 已提交
526 527
        }
    }
528 529 530

    addr->host = g_strdup(host);
    addr->port = g_strdup(port);
G
Gerd Hoffmann 已提交
531 532 533 534

    /* parse options */
    optstr = str + pos;
    h = strstr(optstr, ",to=");
535
    if (h) {
536 537 538
        h += 4;
        if (sscanf(h, "%d%n", &to, &pos) != 1 ||
            (h[pos] != '\0' && h[pos] != ',')) {
539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
            error_setg(errp, "error parsing to= argument");
            goto fail;
        }
        addr->has_to = true;
        addr->to = to;
    }
    if (strstr(optstr, ",ipv4")) {
        addr->ipv4 = addr->has_ipv4 = true;
    }
    if (strstr(optstr, ",ipv6")) {
        addr->ipv6 = addr->has_ipv6 = true;
    }
    return addr;

fail:
    qapi_free_InetSocketAddress(addr);
    return NULL;
}

558
static void inet_addr_to_opts(QemuOpts *opts, const InetSocketAddress *addr)
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573
{
    bool ipv4 = addr->ipv4 || !addr->has_ipv4;
    bool ipv6 = addr->ipv6 || !addr->has_ipv6;

    if (!ipv4 || !ipv6) {
        qemu_opt_set_bool(opts, "ipv4", ipv4);
        qemu_opt_set_bool(opts, "ipv6", ipv6);
    }
    if (addr->has_to) {
        char to[20];
        snprintf(to, sizeof(to), "%d", addr->to);
        qemu_opt_set(opts, "to", to);
    }
    qemu_opt_set(opts, "host", addr->host);
    qemu_opt_set(opts, "port", addr->port);
G
Gerd Hoffmann 已提交
574 575
}

G
Gerd Hoffmann 已提交
576
int inet_listen(const char *str, char *ostr, int olen,
577
                int socktype, int port_offset, Error **errp)
G
Gerd Hoffmann 已提交
578 579 580 581
{
    QemuOpts *opts;
    char *optstr;
    int sock = -1;
582
    InetSocketAddress *addr;
G
Gerd Hoffmann 已提交
583

584 585
    addr = inet_parse(str, errp);
    if (addr != NULL) {
586
        opts = qemu_opts_create_nofail(&socket_optslist);
587 588
        inet_addr_to_opts(opts, addr);
        qapi_free_InetSocketAddress(addr);
589
        sock = inet_listen_opts(opts, port_offset, errp);
G
Gerd Hoffmann 已提交
590 591 592 593 594 595 596 597 598 599 600 601 602 603
        if (sock != -1 && ostr) {
            optstr = strchr(str, ',');
            if (qemu_opt_get_bool(opts, "ipv6", 0)) {
                snprintf(ostr, olen, "[%s]:%s%s",
                         qemu_opt_get(opts, "host"),
                         qemu_opt_get(opts, "port"),
                         optstr ? optstr : "");
            } else {
                snprintf(ostr, olen, "%s:%s%s",
                         qemu_opt_get(opts, "host"),
                         qemu_opt_get(opts, "port"),
                         optstr ? optstr : "");
            }
        }
604
        qemu_opts_del(opts);
G
Gerd Hoffmann 已提交
605 606 607 608
    }
    return sock;
}

609 610 611 612 613 614 615 616 617
/**
 * Create a blocking socket and connect it to an address.
 *
 * @str: address string
 * @errp: set in case of an error
 *
 * Returns -1 in case of error, file descriptor on success
 **/
int inet_connect(const char *str, Error **errp)
G
Gerd Hoffmann 已提交
618 619 620
{
    QemuOpts *opts;
    int sock = -1;
621
    InetSocketAddress *addr;
G
Gerd Hoffmann 已提交
622

623 624
    addr = inet_parse(str, errp);
    if (addr != NULL) {
625
        opts = qemu_opts_create_nofail(&socket_optslist);
626 627
        inet_addr_to_opts(opts, addr);
        qapi_free_InetSocketAddress(addr);
628
        sock = inet_connect_opts(opts, errp, NULL, NULL);
629
        qemu_opts_del(opts);
630 631 632 633 634 635
    }
    return sock;
}

/**
 * Create a non-blocking socket and connect it to an address.
636 637
 * Calls the callback function with fd in case of success or -1 in case of
 * error.
638 639
 *
 * @str: address string
640 641 642
 * @callback: callback function that is called when connect completes,
 *            cannot be NULL.
 * @opaque: opaque for callback function
643 644
 * @errp: set in case of an error
 *
645
 * Returns: -1 on immediate error, file descriptor on success.
646
 **/
647 648 649
int inet_nonblocking_connect(const char *str,
                             NonBlockingConnectHandler *callback,
                             void *opaque, Error **errp)
650 651 652
{
    QemuOpts *opts;
    int sock = -1;
653
    InetSocketAddress *addr;
654

655 656
    g_assert(callback != NULL);

657 658
    addr = inet_parse(str, errp);
    if (addr != NULL) {
659
        opts = qemu_opts_create_nofail(&socket_optslist);
660 661
        inet_addr_to_opts(opts, addr);
        qapi_free_InetSocketAddress(addr);
662
        sock = inet_connect_opts(opts, errp, callback, opaque);
663
        qemu_opts_del(opts);
664
    }
G
Gerd Hoffmann 已提交
665 666 667
    return sock;
}

668 669
#ifndef _WIN32

670
int unix_listen_opts(QemuOpts *opts, Error **errp)
671 672
{
    struct sockaddr_un un;
G
Gerd Hoffmann 已提交
673 674
    const char *path = qemu_opt_get(opts, "path");
    int sock, fd;
675

K
Kevin Wolf 已提交
676
    sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
677
    if (sock < 0) {
678
        error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED);
V
vibi 已提交
679
        return -1;
680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697
    }

    memset(&un, 0, sizeof(un));
    un.sun_family = AF_UNIX;
    if (path && strlen(path)) {
        snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
    } else {
        char *tmpdir = getenv("TMPDIR");
        snprintf(un.sun_path, sizeof(un.sun_path), "%s/qemu-socket-XXXXXX",
                 tmpdir ? tmpdir : "/tmp");
        /*
         * This dummy fd usage silences the mktemp() unsecure warning.
         * Using mkstemp() doesn't make things more secure here
         * though.  bind() complains about existing files, so we have
         * to unlink first and thus re-open the race window.  The
         * worst case possible is bind() failing, i.e. a DoS attack.
         */
        fd = mkstemp(un.sun_path); close(fd);
G
Gerd Hoffmann 已提交
698
        qemu_opt_set(opts, "path", un.sun_path);
699 700 701 702
    }

    unlink(un.sun_path);
    if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
703
        error_set_errno(errp, errno, QERR_SOCKET_BIND_FAILED);
704 705 706
        goto err;
    }
    if (listen(sock, 1) < 0) {
707
        error_set_errno(errp, errno, QERR_SOCKET_LISTEN_FAILED);
708 709 710 711 712 713 714 715 716 717
        goto err;
    }

    return sock;

err:
    closesocket(sock);
    return -1;
}

718 719
int unix_connect_opts(QemuOpts *opts, Error **errp,
                      NonBlockingConnectHandler *callback, void *opaque)
720 721
{
    struct sockaddr_un un;
G
Gerd Hoffmann 已提交
722
    const char *path = qemu_opt_get(opts, "path");
723 724
    ConnectState *connect_state = NULL;
    int sock, rc;
725

G
Gerd Hoffmann 已提交
726
    if (NULL == path) {
727
        error_setg(errp, "unix connect: no path specified");
G
Gerd Hoffmann 已提交
728 729 730
        return -1;
    }

K
Kevin Wolf 已提交
731
    sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
732
    if (sock < 0) {
733
        error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED);
V
vibi 已提交
734
        return -1;
735
    }
736 737 738 739
    if (callback != NULL) {
        connect_state = g_malloc0(sizeof(*connect_state));
        connect_state->callback = callback;
        connect_state->opaque = opaque;
740
        qemu_set_nonblock(sock);
741
    }
742 743 744 745

    memset(&un, 0, sizeof(un));
    un.sun_family = AF_UNIX;
    snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767

    /* connect to peer */
    do {
        rc = 0;
        if (connect(sock, (struct sockaddr *) &un, sizeof(un)) < 0) {
            rc = -socket_error();
        }
    } while (rc == -EINTR);

    if (connect_state != NULL && QEMU_SOCKET_RC_INPROGRESS(rc)) {
        connect_state->fd = sock;
        qemu_set_fd_handler2(sock, NULL, NULL, wait_for_connect,
                             connect_state);
        return sock;
    } else if (rc >= 0) {
        /* non blocking socket immediate success, call callback */
        if (callback != NULL) {
            callback(sock, opaque);
        }
    }

    if (rc < 0) {
768
        error_set_errno(errp, -rc, QERR_SOCKET_CONNECT_FAILED);
769
        close(sock);
770
        sock = -1;
771 772
    }

773
    g_free(connect_state);
774 775 776
    return sock;
}

777 778 779 780
#else

int unix_listen_opts(QemuOpts *opts, Error **errp)
{
781
    error_setg(errp, "unix sockets are not available on windows");
782 783 784 785
    errno = ENOTSUP;
    return -1;
}

786 787
int unix_connect_opts(QemuOpts *opts, Error **errp,
                      NonBlockingConnectHandler *callback, void *opaque)
788
{
789
    error_setg(errp, "unix sockets are not available on windows");
790 791 792 793 794
    errno = ENOTSUP;
    return -1;
}
#endif

G
Gerd Hoffmann 已提交
795
/* compatibility wrapper */
796
int unix_listen(const char *str, char *ostr, int olen, Error **errp)
G
Gerd Hoffmann 已提交
797 798 799 800 801
{
    QemuOpts *opts;
    char *path, *optstr;
    int sock, len;

802
    opts = qemu_opts_create_nofail(&socket_optslist);
G
Gerd Hoffmann 已提交
803 804 805 806 807

    optstr = strchr(str, ',');
    if (optstr) {
        len = optstr - str;
        if (len) {
808
            path = g_malloc(len+1);
G
Gerd Hoffmann 已提交
809 810
            snprintf(path, len+1, "%.*s", len, str);
            qemu_opt_set(opts, "path", path);
811
            g_free(path);
G
Gerd Hoffmann 已提交
812 813 814 815 816
        }
    } else {
        qemu_opt_set(opts, "path", str);
    }

817
    sock = unix_listen_opts(opts, errp);
G
Gerd Hoffmann 已提交
818 819 820 821 822 823 824

    if (sock != -1 && ostr)
        snprintf(ostr, olen, "%s%s", qemu_opt_get(opts, "path"), optstr ? optstr : "");
    qemu_opts_del(opts);
    return sock;
}

825
int unix_connect(const char *path, Error **errp)
G
Gerd Hoffmann 已提交
826 827 828 829
{
    QemuOpts *opts;
    int sock;

830
    opts = qemu_opts_create_nofail(&socket_optslist);
G
Gerd Hoffmann 已提交
831
    qemu_opt_set(opts, "path", path);
832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
    sock = unix_connect_opts(opts, errp, NULL, NULL);
    qemu_opts_del(opts);
    return sock;
}


int unix_nonblocking_connect(const char *path,
                             NonBlockingConnectHandler *callback,
                             void *opaque, Error **errp)
{
    QemuOpts *opts;
    int sock = -1;

    g_assert(callback != NULL);

847
    opts = qemu_opts_create_nofail(&socket_optslist);
848 849
    qemu_opt_set(opts, "path", path);
    sock = unix_connect_opts(opts, errp, callback, opaque);
G
Gerd Hoffmann 已提交
850 851 852 853
    qemu_opts_del(opts);
    return sock;
}

854 855 856 857 858 859 860
SocketAddress *socket_parse(const char *str, Error **errp)
{
    SocketAddress *addr = NULL;

    addr = g_new(SocketAddress, 1);
    if (strstart(str, "unix:", NULL)) {
        if (str[5] == '\0') {
861
            error_setg(errp, "invalid Unix socket address");
862 863 864 865 866 867 868 869
            goto fail;
        } else {
            addr->kind = SOCKET_ADDRESS_KIND_UNIX;
            addr->q_unix = g_new(UnixSocketAddress, 1);
            addr->q_unix->path = g_strdup(str + 5);
        }
    } else if (strstart(str, "fd:", NULL)) {
        if (str[3] == '\0') {
870
            error_setg(errp, "invalid file descriptor address");
871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897
            goto fail;
        } else {
            addr->kind = SOCKET_ADDRESS_KIND_FD;
            addr->fd = g_new(String, 1);
            addr->fd->str = g_strdup(str + 3);
        }
    } else {
        addr->kind = SOCKET_ADDRESS_KIND_INET;
        addr->inet = g_new(InetSocketAddress, 1);
        addr->inet = inet_parse(str, errp);
        if (addr->inet == NULL) {
            goto fail;
        }
    }
    return addr;

fail:
    qapi_free_SocketAddress(addr);
    return NULL;
}

int socket_connect(SocketAddress *addr, Error **errp,
                   NonBlockingConnectHandler *callback, void *opaque)
{
    QemuOpts *opts;
    int fd;

898
    opts = qemu_opts_create_nofail(&socket_optslist);
899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928
    switch (addr->kind) {
    case SOCKET_ADDRESS_KIND_INET:
        inet_addr_to_opts(opts, addr->inet);
        fd = inet_connect_opts(opts, errp, callback, opaque);
        break;

    case SOCKET_ADDRESS_KIND_UNIX:
        qemu_opt_set(opts, "path", addr->q_unix->path);
        fd = unix_connect_opts(opts, errp, callback, opaque);
        break;

    case SOCKET_ADDRESS_KIND_FD:
        fd = monitor_get_fd(cur_mon, addr->fd->str, errp);
        if (callback) {
            callback(fd, opaque);
        }
        break;

    default:
        abort();
    }
    qemu_opts_del(opts);
    return fd;
}

int socket_listen(SocketAddress *addr, Error **errp)
{
    QemuOpts *opts;
    int fd;

929
    opts = qemu_opts_create_nofail(&socket_optslist);
930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951
    switch (addr->kind) {
    case SOCKET_ADDRESS_KIND_INET:
        inet_addr_to_opts(opts, addr->inet);
        fd = inet_listen_opts(opts, 0, errp);
        break;

    case SOCKET_ADDRESS_KIND_UNIX:
        qemu_opt_set(opts, "path", addr->q_unix->path);
        fd = unix_listen_opts(opts, errp);
        break;

    case SOCKET_ADDRESS_KIND_FD:
        fd = monitor_get_fd(cur_mon, addr->fd->str, errp);
        break;

    default:
        abort();
    }
    qemu_opts_del(opts);
    return fd;
}

G
Gerd Hoffmann 已提交
952 953 954 955 956
int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp)
{
    QemuOpts *opts;
    int fd;

957
    opts = qemu_opts_create_nofail(&socket_optslist);
G
Gerd Hoffmann 已提交
958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976
    switch (remote->kind) {
    case SOCKET_ADDRESS_KIND_INET:
        qemu_opt_set(opts, "host", remote->inet->host);
        qemu_opt_set(opts, "port", remote->inet->port);
        if (local) {
            qemu_opt_set(opts, "localaddr", local->inet->host);
            qemu_opt_set(opts, "localport", local->inet->port);
        }
        fd = inet_dgram_opts(opts, errp);
        break;

    default:
        error_setg(errp, "socket type unsupported for datagram");
        return -1;
    }
    qemu_opts_del(opts);
    return fd;
}

977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999
#ifdef _WIN32
static void socket_cleanup(void)
{
    WSACleanup();
}
#endif

int socket_init(void)
{
#ifdef _WIN32
    WSADATA Data;
    int ret, err;

    ret = WSAStartup(MAKEWORD(2,2), &Data);
    if (ret != 0) {
        err = WSAGetLastError();
        fprintf(stderr, "WSAStartup: %d\n", err);
        return -1;
    }
    atexit(socket_cleanup);
#endif
    return 0;
}