qemu-sockets.c 18.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/*
 *  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.
 */
15 16 17 18 19 20 21 22
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <unistd.h>

#include "qemu_socket.h"
23
#include "qemu-common.h" /* for qemu_isdigit */
24 25 26 27 28 29 30 31

#ifndef AI_ADDRCONFIG
# define AI_ADDRCONFIG 0
#endif

static int sockets_debug = 0;
static const int on=1, off=0;

G
Gerd Hoffmann 已提交
32
/* used temporarely until all users are converted to QemuOpts */
B
Blue Swirl 已提交
33
static QemuOptsList dummy_opts = {
G
Gerd Hoffmann 已提交
34
    .name = "dummy",
B
Blue Swirl 已提交
35
    .head = QTAILQ_HEAD_INITIALIZER(dummy_opts.head),
G
Gerd Hoffmann 已提交
36 37 38 39
    .desc = {
        {
            .name = "path",
            .type = QEMU_OPT_STRING,
G
Gerd Hoffmann 已提交
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
        },{
            .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 已提交
55 56 57 58 59
        },
        { /* end if list */ }
    },
};

60 61 62 63 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
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;
    }
}

94
const char *inet_strfamily(int family)
95 96 97 98 99 100
{
    switch (family) {
    case PF_INET6: return "ipv6";
    case PF_INET:  return "ipv4";
    case PF_UNIX:  return "unix";
    }
101
    return "unknown";
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
}

static void inet_print_addrinfo(const char *tag, struct addrinfo *res)
{
    struct addrinfo *e;
    char uaddr[INET6_ADDRSTRLEN+1];
    char uport[33];

    for (e = res; e != NULL; e = e->ai_next) {
        getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
                    uaddr,INET6_ADDRSTRLEN,uport,32,
                    NI_NUMERICHOST | NI_NUMERICSERV);
        fprintf(stderr,"%s: getaddrinfo: family %s, host %s, port %s\n",
                tag, inet_strfamily(e->ai_family), uaddr, uport);
    }
}

G
Gerd Hoffmann 已提交
119
int inet_listen_opts(QemuOpts *opts, int port_offset)
120 121
{
    struct addrinfo ai,*res,*e;
G
Gerd Hoffmann 已提交
122
    const char *addr;
123 124 125
    char port[33];
    char uaddr[INET6_ADDRSTRLEN+1];
    char uport[33];
G
Gerd Hoffmann 已提交
126
    int slisten,rc,to,try_next;
127 128 129 130

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

G
Gerd Hoffmann 已提交
133 134 135
    if (qemu_opt_get(opts, "port") == NULL) {
        fprintf(stderr, "%s: host and/or port not specified\n", __FUNCTION__);
        return -1;
136
    }
G
Gerd Hoffmann 已提交
137 138
    pstrcpy(port, sizeof(port), qemu_opt_get(opts, "port"));
    addr = qemu_opt_get(opts, "host");
139

G
Gerd Hoffmann 已提交
140 141
    to = qemu_opt_get_number(opts, "to", 0);
    if (qemu_opt_get_bool(opts, "ipv4", 0))
142
        ai.ai_family = PF_INET;
G
Gerd Hoffmann 已提交
143
    if (qemu_opt_get_bool(opts, "ipv6", 0))
144 145 146 147 148 149 150
        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) {
G
Gerd Hoffmann 已提交
151 152
        fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
                gai_strerror(rc));
153 154 155 156 157 158 159
        return -1;
    }
    if (sockets_debug)
        inet_print_addrinfo(__FUNCTION__, res);

    /* create socket + bind */
    for (e = res; e != NULL; e = e->ai_next) {
V
vibi 已提交
160 161 162
        getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
		        uaddr,INET6_ADDRSTRLEN,uport,32,
		        NI_NUMERICHOST | NI_NUMERICSERV);
K
Kevin Wolf 已提交
163
        slisten = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol);
V
vibi 已提交
164
        if (slisten < 0) {
165 166
            fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
                    inet_strfamily(e->ai_family), strerror(errno));
V
vibi 已提交
167 168
            continue;
        }
169 170 171 172 173

        setsockopt(slisten,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));
#ifdef IPV6_V6ONLY
        if (e->ai_family == PF_INET6) {
            /* listen on both ipv4 and ipv6 */
V
vibi 已提交
174 175
            setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&off,
                sizeof(off));
176 177 178 179 180 181 182
        }
#endif

        for (;;) {
            if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) {
                if (sockets_debug)
                    fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__,
V
vibi 已提交
183
                        inet_strfamily(e->ai_family), uaddr, inet_getport(e));
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
                goto listen;
            }
            try_next = to && (inet_getport(e) <= to + port_offset);
            if (!try_next || sockets_debug)
                fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__,
                        inet_strfamily(e->ai_family), uaddr, inet_getport(e),
                        strerror(errno));
            if (try_next) {
                inet_setport(e, inet_getport(e) + 1);
                continue;
            }
            break;
        }
        closesocket(slisten);
    }
    fprintf(stderr, "%s: FAILED\n", __FUNCTION__);
    freeaddrinfo(res);
    return -1;

listen:
    if (listen(slisten,1) != 0) {
        perror("listen");
        closesocket(slisten);
V
vibi 已提交
207
        freeaddrinfo(res);
208 209
        return -1;
    }
G
Gerd Hoffmann 已提交
210 211 212 213 214
    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");
215 216 217 218
    freeaddrinfo(res);
    return slisten;
}

G
Gerd Hoffmann 已提交
219
int inet_connect_opts(QemuOpts *opts)
220 221
{
    struct addrinfo ai,*res,*e;
G
Gerd Hoffmann 已提交
222 223
    const char *addr;
    const char *port;
224 225 226 227 228 229 230
    char uaddr[INET6_ADDRSTRLEN+1];
    char uport[33];
    int sock,rc;

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

G
Gerd Hoffmann 已提交
233 234 235 236 237
    addr = qemu_opt_get(opts, "host");
    port = qemu_opt_get(opts, "port");
    if (addr == NULL || port == NULL) {
        fprintf(stderr, "inet_connect: host and/or port not specified\n");
        return -1;
238 239
    }

G
Gerd Hoffmann 已提交
240
    if (qemu_opt_get_bool(opts, "ipv4", 0))
241
        ai.ai_family = PF_INET;
G
Gerd Hoffmann 已提交
242
    if (qemu_opt_get_bool(opts, "ipv6", 0))
243 244 245 246
        ai.ai_family = PF_INET6;

    /* lookup */
    if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) {
G
Gerd Hoffmann 已提交
247 248
        fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
                gai_strerror(rc));
249 250 251 252 253 254
	return -1;
    }
    if (sockets_debug)
        inet_print_addrinfo(__FUNCTION__, res);

    for (e = res; e != NULL; e = e->ai_next) {
V
vibi 已提交
255 256 257
        if (getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
                            uaddr,INET6_ADDRSTRLEN,uport,32,
                            NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
258
            fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__);
V
vibi 已提交
259 260
            continue;
        }
K
Kevin Wolf 已提交
261
        sock = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol);
V
vibi 已提交
262
        if (sock < 0) {
263
            fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
V
vibi 已提交
264 265 266
            inet_strfamily(e->ai_family), strerror(errno));
            continue;
        }
267 268
        setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));

V
vibi 已提交
269 270
        /* connect to peer */
        if (connect(sock,e->ai_addr,e->ai_addrlen) < 0) {
271 272 273 274 275
            if (sockets_debug || NULL == e->ai_next)
                fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
                        inet_strfamily(e->ai_family),
                        e->ai_canonname, uaddr, uport, strerror(errno));
            closesocket(sock);
V
vibi 已提交
276 277
            continue;
        }
278 279 280 281 282
        if (sockets_debug)
            fprintf(stderr, "%s: connect(%s,%s,%s,%s): OK\n", __FUNCTION__,
                    inet_strfamily(e->ai_family),
                    e->ai_canonname, uaddr, uport);
        freeaddrinfo(res);
V
vibi 已提交
283
        return sock;
284 285 286 287 288
    }
    freeaddrinfo(res);
    return -1;
}

G
Gerd Hoffmann 已提交
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
int inet_dgram_opts(QemuOpts *opts)
{
    struct addrinfo ai, *peer = NULL, *local = NULL;
    const char *addr;
    const char *port;
    char uaddr[INET6_ADDRSTRLEN+1];
    char uport[33];
    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) {
        fprintf(stderr, "inet_dgram: port not specified\n");
        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))) {
        fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
                gai_strerror(rc));
	return -1;
    }
    if (sockets_debug) {
        fprintf(stderr, "%s: peer (%s:%s)\n", __FUNCTION__, addr, port);
        inet_print_addrinfo(__FUNCTION__, peer);
    }

    /* 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))) {
        fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
                gai_strerror(rc));
        return -1;
    }
    if (sockets_debug) {
        fprintf(stderr, "%s: local (%s:%s)\n", __FUNCTION__, addr, port);
        inet_print_addrinfo(__FUNCTION__, local);
    }

    /* create socket */
K
Kevin Wolf 已提交
354
    sock = qemu_socket(peer->ai_family, peer->ai_socktype, peer->ai_protocol);
G
Gerd Hoffmann 已提交
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
    if (sock < 0) {
        fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
                inet_strfamily(peer->ai_family), strerror(errno));
        goto err;
    }
    setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));

    /* bind socket */
    if (getnameinfo((struct sockaddr*)local->ai_addr,local->ai_addrlen,
                    uaddr,INET6_ADDRSTRLEN,uport,32,
                    NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
        fprintf(stderr, "%s: getnameinfo: oops\n", __FUNCTION__);
        goto err;
    }
    if (bind(sock, local->ai_addr, local->ai_addrlen) < 0) {
        fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__,
                inet_strfamily(local->ai_family), uaddr, inet_getport(local));
        goto err;
    }

    /* connect to peer */
    if (getnameinfo((struct sockaddr*)peer->ai_addr, peer->ai_addrlen,
                    uaddr, INET6_ADDRSTRLEN, uport, 32,
                    NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
        fprintf(stderr, "%s: getnameinfo: oops\n", __FUNCTION__);
        goto err;
    }
    if (connect(sock,peer->ai_addr,peer->ai_addrlen) < 0) {
        fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
                inet_strfamily(peer->ai_family),
                peer->ai_canonname, uaddr, uport, strerror(errno));
        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 已提交
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
/* compatibility wrapper */
static int inet_parse(QemuOpts *opts, const char *str)
{
    const char *optstr, *h;
    char addr[64];
    char port[33];
    int pos;

    /* parse address */
    if (str[0] == ':') {
        /* no host given */
        addr[0] = '\0';
        if (1 != sscanf(str,":%32[^,]%n",port,&pos)) {
            fprintf(stderr, "%s: portonly parse error (%s)\n",
                    __FUNCTION__, str);
            return -1;
        }
    } else if (str[0] == '[') {
        /* IPv6 addr */
        if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) {
            fprintf(stderr, "%s: ipv6 parse error (%s)\n",
                    __FUNCTION__, str);
            return -1;
        }
M
Marcelo Tosatti 已提交
427
        qemu_opt_set(opts, "ipv6", "on");
G
Gerd Hoffmann 已提交
428 429 430 431 432 433 434
    } else if (qemu_isdigit(str[0])) {
        /* IPv4 addr */
        if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) {
            fprintf(stderr, "%s: ipv4 parse error (%s)\n",
                    __FUNCTION__, str);
            return -1;
        }
M
Marcelo Tosatti 已提交
435
        qemu_opt_set(opts, "ipv4", "on");
G
Gerd Hoffmann 已提交
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
    } else {
        /* hostname */
        if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) {
            fprintf(stderr, "%s: hostname parse error (%s)\n",
                    __FUNCTION__, str);
            return -1;
        }
    }
    qemu_opt_set(opts, "host", addr);
    qemu_opt_set(opts, "port", port);

    /* parse options */
    optstr = str + pos;
    h = strstr(optstr, ",to=");
    if (h)
        qemu_opt_set(opts, "to", h+4);
    if (strstr(optstr, ",ipv4"))
M
Marcelo Tosatti 已提交
453
        qemu_opt_set(opts, "ipv4", "on");
G
Gerd Hoffmann 已提交
454
    if (strstr(optstr, ",ipv6"))
M
Marcelo Tosatti 已提交
455
        qemu_opt_set(opts, "ipv6", "on");
G
Gerd Hoffmann 已提交
456 457 458
    return 0;
}

G
Gerd Hoffmann 已提交
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
int inet_listen(const char *str, char *ostr, int olen,
                int socktype, int port_offset)
{
    QemuOpts *opts;
    char *optstr;
    int sock = -1;

    opts = qemu_opts_create(&dummy_opts, NULL, 0);
    if (inet_parse(opts, str) == 0) {
        sock = inet_listen_opts(opts, port_offset);
        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 : "");
            }
        }
    }
    qemu_opts_del(opts);
    return sock;
}

G
Gerd Hoffmann 已提交
488 489 490 491 492 493 494 495 496 497 498 499
int inet_connect(const char *str, int socktype)
{
    QemuOpts *opts;
    int sock = -1;

    opts = qemu_opts_create(&dummy_opts, NULL, 0);
    if (inet_parse(opts, str) == 0)
        sock = inet_connect_opts(opts);
    qemu_opts_del(opts);
    return sock;
}

500 501
#ifndef _WIN32

G
Gerd Hoffmann 已提交
502
int unix_listen_opts(QemuOpts *opts)
503 504
{
    struct sockaddr_un un;
G
Gerd Hoffmann 已提交
505 506
    const char *path = qemu_opt_get(opts, "path");
    int sock, fd;
507

K
Kevin Wolf 已提交
508
    sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
509
    if (sock < 0) {
V
vibi 已提交
510 511
        perror("socket(unix)");
        return -1;
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529
    }

    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 已提交
530
        qemu_opt_set(opts, "path", un.sun_path);
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551
    }

    unlink(un.sun_path);
    if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
        fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno));
        goto err;
    }
    if (listen(sock, 1) < 0) {
        fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path, strerror(errno));
        goto err;
    }

    if (sockets_debug)
        fprintf(stderr, "bind(unix:%s): OK\n", un.sun_path);
    return sock;

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

G
Gerd Hoffmann 已提交
552
int unix_connect_opts(QemuOpts *opts)
553 554
{
    struct sockaddr_un un;
G
Gerd Hoffmann 已提交
555
    const char *path = qemu_opt_get(opts, "path");
556 557
    int sock;

G
Gerd Hoffmann 已提交
558 559 560 561 562
    if (NULL == path) {
        fprintf(stderr, "unix connect: no path specified\n");
        return -1;
    }

K
Kevin Wolf 已提交
563
    sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
564
    if (sock < 0) {
V
vibi 已提交
565 566
        perror("socket(unix)");
        return -1;
567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
    }

    memset(&un, 0, sizeof(un));
    un.sun_family = AF_UNIX;
    snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
    if (connect(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
        fprintf(stderr, "connect(unix:%s): %s\n", path, strerror(errno));
	return -1;
    }

    if (sockets_debug)
        fprintf(stderr, "connect(unix:%s): OK\n", path);
    return sock;
}

G
Gerd Hoffmann 已提交
582
/* compatibility wrapper */
G
Gerd Hoffmann 已提交
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
int unix_listen(const char *str, char *ostr, int olen)
{
    QemuOpts *opts;
    char *path, *optstr;
    int sock, len;

    opts = qemu_opts_create(&dummy_opts, NULL, 0);

    optstr = strchr(str, ',');
    if (optstr) {
        len = optstr - str;
        if (len) {
            path = qemu_malloc(len+1);
            snprintf(path, len+1, "%.*s", len, str);
            qemu_opt_set(opts, "path", path);
            qemu_free(path);
        }
    } else {
        qemu_opt_set(opts, "path", str);
    }

    sock = unix_listen_opts(opts);

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

G
Gerd Hoffmann 已提交
612 613 614 615 616 617 618 619 620 621 622 623
int unix_connect(const char *path)
{
    QemuOpts *opts;
    int sock;

    opts = qemu_opts_create(&dummy_opts, NULL, 0);
    qemu_opt_set(opts, "path", path);
    sock = unix_connect_opts(opts);
    qemu_opts_del(opts);
    return sock;
}

624 625
#else

626 627 628 629 630 631 632 633 634 635 636 637
int unix_listen_opts(QemuOpts *opts)
{
    fprintf(stderr, "unix sockets are not available on windows\n");
    return -1;
}

int unix_connect_opts(QemuOpts *opts)
{
    fprintf(stderr, "unix sockets are not available on windows\n");
    return -1;
}

638 639 640 641 642 643 644 645 646 647 648 649 650
int unix_listen(const char *path, char *ostr, int olen)
{
    fprintf(stderr, "unix sockets are not available on windows\n");
    return -1;
}

int unix_connect(const char *path)
{
    fprintf(stderr, "unix sockets are not available on windows\n");
    return -1;
}

#endif