15d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/*
25d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *  inet and unix socket functions for qemu
35d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
45d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *  (c) 2008 Gerd Hoffmann <kraxel@redhat.com>
55d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
65d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *  This program is free software; you can redistribute it and/or modify
75d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *  it under the terms of the GNU General Public License as published by
85d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *  the Free Software Foundation; under version 2 of the License.
95d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *  This program is distributed in the hope that it will be useful,
115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *  but WITHOUT ANY WARRANTY; without even the implied warranty of
125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *  GNU General Public License for more details.
145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <stdio.h>
165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <stdlib.h>
175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <string.h>
185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <ctype.h>
195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <errno.h>
205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <unistd.h>
215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
22d0edecb426b34ddb9b10b81dea19aee04a61a385David 'Digit' Turner#include "qemu/sockets.h"
235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu-common.h" /* for qemu_isdigit */
245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifndef AI_ADDRCONFIG
265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner# define AI_ADDRCONFIG 0
275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
29ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner#ifndef INET6_ADDRSTRLEN
30ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner# define INET6_ADDRSTRLEN  46
31ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner#endif
32ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner
335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int sockets_debug = 0;
345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic const int on=1, off=0;
355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
36315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner/* used temporarely until all users are converted to QemuOpts */
37315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turnerstatic QemuOptsList dummy_opts = {
38315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    .name = "dummy",
39315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    .head = QTAILQ_HEAD_INITIALIZER(dummy_opts.head),
40315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    .desc = {
41315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        {
42315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner            .name = "path",
43315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner            .type = QEMU_OPT_STRING,
44315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        },{
45315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner            .name = "host",
46315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner            .type = QEMU_OPT_STRING,
47315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        },{
48315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner            .name = "port",
49315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner            .type = QEMU_OPT_STRING,
50315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        },{
51315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner            .name = "to",
52315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner            .type = QEMU_OPT_NUMBER,
53315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        },{
54315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner            .name = "ipv4",
55315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner            .type = QEMU_OPT_BOOL,
56315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        },{
57315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner            .name = "ipv6",
58315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner            .type = QEMU_OPT_BOOL,
598423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner#ifdef CONFIG_ANDROID
608423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner        },{
618423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner            .name = "socket",
628423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner            .type = QEMU_OPT_NUMBER,
638423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner#endif
64315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        },
65315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        { /* end if list */ }
66315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    },
67315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner};
68315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner
69315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner
705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic const char *sock_address_strfamily(SockAddress *s)
715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    switch (sock_address_get_family(s)) {
735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case SOCKET_IN6:   return "ipv6";
745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case SOCKET_INET:  return "ipv4";
755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case SOCKET_UNIX:  return "unix";
765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    default:           return "????";
775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
80315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turnerint inet_listen_opts(QemuOpts *opts, int port_offset)
815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    SockAddress**  list;
835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    SockAddress*   e;
845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    unsigned       flags = SOCKET_LIST_PASSIVE;
85315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    const char *addr;
865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char port[33];
875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char uaddr[256+1];
88315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    char uport[33];
89315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    int slisten,to,try_next,nn;
905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
918423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner#ifdef CONFIG_ANDROID
928423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner    const char* socket_fd = qemu_opt_get(opts, "socket");
938423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner    if (socket_fd) {
948423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner        return atoi(socket_fd);
958423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner    }
968423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner#endif
978423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner
98315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    if ((qemu_opt_get(opts, "host") == NULL) ||
99315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        (qemu_opt_get(opts, "port") == NULL)) {
100315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        fprintf(stderr, "%s: host and/or port not specified\n", __FUNCTION__);
101315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        return -1;
1025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
103315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    pstrcpy(port, sizeof(port), qemu_opt_get(opts, "port"));
104315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    addr = qemu_opt_get(opts, "host");
1055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
106315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    to = qemu_opt_get_number(opts, "to", 0);
107315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    if (qemu_opt_get_bool(opts, "ipv4", 0))
1085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        flags |= SOCKET_LIST_FORCE_INET;
109315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    if (qemu_opt_get_bool(opts, "ipv6", 0))
1105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        flags |= SOCKET_LIST_FORCE_IN6;
1115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* lookup */
1135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (port_offset)
1145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        snprintf(port, sizeof(port), "%d", atoi(port) + port_offset);
1155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    list = sock_address_list_create( strlen(addr) ? addr : NULL,
1175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                       port,
1185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                       flags );
1195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (list == NULL) {
1205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr,"%s: getaddrinfo(%s,%s): %s\n", __FUNCTION__,
1215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                addr, port, errno_str);
1225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
1235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
1245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* create socket + bind */
1265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (nn = 0; list[nn] != NULL; nn++) {
1275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        SocketFamily  family;
1285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        e      = list[nn];
1305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        family = sock_address_get_family(e);
131315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner
132315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        sock_address_get_numeric_info(e, uaddr, sizeof uaddr, uport, sizeof uport);
133315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        slisten = socket_create(family, SOCKET_STREAM);
1345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (slisten < 0) {
1355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
1365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    sock_address_strfamily(e), errno_str);
1375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            continue;
1385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
1395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        socket_set_xreuseaddr(slisten);
1415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef IPV6_V6ONLY
1425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* listen on both ipv4 and ipv6 */
143315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        if (family == SOCKET_IN6) {
1445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            socket_set_ipv6only(slisten);
1455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
1465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
1475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        for (;;) {
1495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (socket_bind(slisten, e) == 0) {
1505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if (sockets_debug)
1515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__,
1525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        sock_address_strfamily(e), uaddr, sock_address_get_port(e));
1535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                goto listen;
1545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
1555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            socket_close(slisten);
1565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            try_next = to && (sock_address_get_port(e) <= to + port_offset);
1575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (!try_next || sockets_debug)
1585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__,
1595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        sock_address_strfamily(e), uaddr, sock_address_get_port(e),
1605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        strerror(errno));
1615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (try_next) {
1625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                sock_address_set_port(e, sock_address_get_port(e) + 1);
1635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                continue;
1645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
1655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
1665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
1675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
1685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sock_address_list_free(list);
1695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    fprintf(stderr, "%s: FAILED\n", __FUNCTION__);
1705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return -1;
1715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerlisten:
1735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (socket_listen(slisten,1) != 0) {
1745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        perror("listen");
1755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        socket_close(slisten);
1765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
1775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
178315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    snprintf(uport, sizeof(uport), "%d", sock_address_get_port(e) - port_offset);
179315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    qemu_opt_set(opts, "host", uaddr);
180315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    qemu_opt_set(opts, "port", uport);
181315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    qemu_opt_set(opts, "ipv6", (e->family == SOCKET_IN6) ? "on" : "off");
182315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    qemu_opt_set(opts, "ipv4", (e->family != SOCKET_IN6) ? "on" : "off");
1835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sock_address_list_free(list);
1845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return slisten;
1855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
187315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turnerint inet_connect_opts(QemuOpts *opts)
1885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    SockAddress**  list;
1905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    SockAddress*   e;
1915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    unsigned       flags = 0;
192315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    const char *addr;
193315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    const char *port;
1945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int sock, nn;
1955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1968423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner#ifdef CONFIG_ANDROID
1978423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner    const char* socket_fd = qemu_opt_get(opts, "socket");
1988423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner    if (socket_fd) {
1998423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner        return atoi(socket_fd);
2008423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner    }
2018423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner#endif
2028423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner
203315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    addr = qemu_opt_get(opts, "host");
204315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    port = qemu_opt_get(opts, "port");
205315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    if (addr == NULL || port == NULL) {
206315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        fprintf(stderr, "inet_connect: host and/or port not specified\n");
207315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        return -1;
2085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
2095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
210315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    if (qemu_opt_get_bool(opts, "ipv4", 0)) {
2115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        flags &= SOCKET_LIST_FORCE_IN6;
2125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        flags |= SOCKET_LIST_FORCE_INET;
2135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
214315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    if (qemu_opt_get_bool(opts, "ipv6", 0)) {
2155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        flags &= SOCKET_LIST_FORCE_INET;
2165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        flags |= SOCKET_LIST_FORCE_IN6;
2175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
2185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* lookup */
2205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    list = sock_address_list_create(addr, port, flags);
2215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (list == NULL) {
2225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr,"getaddrinfo(%s,%s): %s\n",
2235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                addr, port, errno_str);
2245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
2255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
2265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (nn = 0; list[nn] != NULL; nn++) {
2285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        e     = list[nn];
229315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        sock = socket_create(sock_address_get_family(e), SOCKET_STREAM);
2305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (sock < 0) {
2315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
2325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            sock_address_strfamily(e), errno_str);
2335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            continue;
2345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
2355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        socket_set_xreuseaddr(sock);
2365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* connect to peer */
2385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (socket_connect(sock,e) < 0) {
2395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (sockets_debug)
2405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
2415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        sock_address_strfamily(e),
2425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        sock_address_to_string(e), addr, port, strerror(errno));
2435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            socket_close(sock);
2445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            continue;
2455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
2465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (sockets_debug)
2475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            fprintf(stderr, "%s: connect(%s,%s,%s,%s): OK\n", __FUNCTION__,
2485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        sock_address_strfamily(e),
2495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        sock_address_to_string(e), addr, port);
2505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto EXIT;
2525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
2535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sock = -1;
2545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerEXIT:
2555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sock_address_list_free(list);
2565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return sock;
2575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
259ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turnerint inet_dgram_opts(QemuOpts *opts)
260ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner{
261ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    SockAddress**  peer_list = NULL;
262ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    SockAddress**  local_list = NULL;
263ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    SockAddress*   e;
264ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    unsigned       flags = 0;
265ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    const char *addr;
266ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    const char *port;
267ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    char uaddr[INET6_ADDRSTRLEN+1];
268ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    char uport[33];
269ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    int sock = -1;
270ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    int nn;
271ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner
272ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    /* lookup peer addr */
273ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    addr = qemu_opt_get(opts, "host");
274ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    port = qemu_opt_get(opts, "port");
275ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    if (addr == NULL || strlen(addr) == 0) {
276ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        addr = "localhost";
277ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    }
278ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    if (port == NULL || strlen(port) == 0) {
279ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        fprintf(stderr, "inet_dgram: port not specified\n");
280ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        return -1;
281ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    }
282ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner
283ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    flags = SOCKET_LIST_DGRAM;
284ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    if (qemu_opt_get_bool(opts, "ipv4", 0)) {
285ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        flags &= SOCKET_LIST_FORCE_IN6;
286ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        flags |= SOCKET_LIST_FORCE_INET;
287ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    }
288ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    if (qemu_opt_get_bool(opts, "ipv6", 0)) {
289ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        flags &= SOCKET_LIST_FORCE_INET;
290ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        flags |= SOCKET_LIST_FORCE_IN6;
291ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    }
292ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner
293ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    peer_list = sock_address_list_create(addr, port, flags);
294ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    if (peer_list == NULL) {
295ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        fprintf(stderr,"getaddrinfo(%s,%s): %s\n",
296ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner                addr, port, errno_str);
297ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        return -1;
298ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    }
299ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner
300ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    /* lookup local addr */
301ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    addr = qemu_opt_get(opts, "localaddr");
302ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    port = qemu_opt_get(opts, "localport");
303ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    if (addr == NULL || strlen(addr) == 0) {
304ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        addr = NULL;
305ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    }
306ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    if (!port || strlen(port) == 0)
307ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        port = "0";
308ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner
309ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    flags = SOCKET_LIST_DGRAM | SOCKET_LIST_PASSIVE;
310ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    local_list = sock_address_list_create(addr, port, flags);
311ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    if (local_list == NULL) {
312ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        fprintf(stderr,"getaddrinfo(%s,%s): %s\n",
313ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner                addr, port, errno_str);
314ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        goto EXIT;
315ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    }
316ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner
317ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    if (sock_address_get_numeric_info(local_list[0],
318ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner                                       uaddr, INET6_ADDRSTRLEN,
319ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner                                       uport, 32)) {
320ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        fprintf(stderr, "%s: getnameinfo: oops\n", __FUNCTION__);
321ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        goto EXIT;
322ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    }
323ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner
324ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    for (nn = 0; peer_list[nn] != NULL; nn++) {
325ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        SockAddress *local = local_list[0];
326ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        e    = peer_list[nn];
327ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        sock = socket_create(sock_address_get_family(e), SOCKET_DGRAM);
328ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        if (sock < 0) {
329ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner            fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
330ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner            sock_address_strfamily(e), errno_str);
331ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner            continue;
332ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        }
333ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        socket_set_xreuseaddr(sock);
334ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner
335ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        /* bind socket */
336ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        if (socket_bind(sock, local) < 0) {
337ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner            fprintf(stderr,"%s: bind(%s,%s,%s): OK\n", __FUNCTION__,
338ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner                sock_address_strfamily(local), addr, port);
339ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner            socket_close(sock);
340ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner            continue;
341ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        }
342ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner
343ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        /* connect to peer */
344ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        if (socket_connect(sock,e) < 0) {
345ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner            if (sockets_debug)
346ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner                fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
347ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner                        sock_address_strfamily(e),
348ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner                        sock_address_to_string(e), addr, port, strerror(errno));
349ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner            socket_close(sock);
350ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner            continue;
351ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        }
352ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        if (sockets_debug)
353ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner            fprintf(stderr, "%s: connect(%s,%s,%s,%s): OK\n", __FUNCTION__,
354ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner                        sock_address_strfamily(e),
355ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner                        sock_address_to_string(e), addr, port);
356ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner
357ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        goto EXIT;
358ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    }
359ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    sock = -1;
360ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' TurnerEXIT:
361ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    if (local_list)
362ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        sock_address_list_free(local_list);
363ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    if (peer_list)
364ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner        sock_address_list_free(peer_list);
365ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner    return sock;
366ca6a2e034bce665a08d9d748ac11d6a7cfcd7c48David 'Digit' Turner}
3678423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner
368315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner/* compatibility wrapper */
369315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turnerstatic int inet_parse(QemuOpts *opts, const char *str)
370315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner{
371315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    const char *optstr, *h;
372315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    char addr[64];
373315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    char port[33];
374315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    int pos;
375315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner
376315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    /* parse address */
377315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    if (str[0] == ':') {
378315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        /* no host given */
379315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        addr[0] = '\0';
380315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        if (1 != sscanf(str,":%32[^,]%n",port,&pos)) {
381315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner            fprintf(stderr, "%s: portonly parse error (%s)\n",
382315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner                    __FUNCTION__, str);
383315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner            return -1;
384315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        }
385315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    } else if (str[0] == '[') {
386315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        /* IPv6 addr */
387315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) {
388315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner            fprintf(stderr, "%s: ipv6 parse error (%s)\n",
389315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner                    __FUNCTION__, str);
390315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner            return -1;
391315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        }
392315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        qemu_opt_set(opts, "ipv6", "on");
393315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    } else if (qemu_isdigit(str[0])) {
394315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        /* IPv4 addr */
395315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) {
396315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner            fprintf(stderr, "%s: ipv4 parse error (%s)\n",
397315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner                    __FUNCTION__, str);
398315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner            return -1;
399315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        }
400315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        qemu_opt_set(opts, "ipv4", "on");
401315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    } else {
402315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        /* hostname */
403315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) {
404315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner            fprintf(stderr, "%s: hostname parse error (%s)\n",
405315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner                    __FUNCTION__, str);
406315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner            return -1;
407315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        }
408315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    }
409315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    qemu_opt_set(opts, "host", addr);
410315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    qemu_opt_set(opts, "port", port);
411315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner
412315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    /* parse options */
413315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    optstr = str + pos;
414315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    h = strstr(optstr, ",to=");
415315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    if (h)
416315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        qemu_opt_set(opts, "to", h+4);
417315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    if (strstr(optstr, ",ipv4"))
418315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        qemu_opt_set(opts, "ipv4", "on");
419315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    if (strstr(optstr, ",ipv6"))
420315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        qemu_opt_set(opts, "ipv6", "on");
4218423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner#ifdef CONFIG_ANDROID
4228423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner    h = strstr(optstr, ",socket=");
4238423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner    if (h) {
4248423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner        int socket_fd;
4258423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner        char str_fd[12];
4268423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner        if (1 != sscanf(h+7,"%d",&socket_fd)) {
4278423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner            fprintf(stderr,"%s: socket fd parse error (%s)\n",
4288423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner                    __FUNCTION__, h+7);
4298423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner            return -1;
4308423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner        }
4318423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner        if (socket_fd < 0 || socket_fd >= INT_MAX) {
4328423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner            fprintf(stderr,"%s: socket fd range error (%d)\n",
4338423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner                    __FUNCTION__, socket_fd);
4348423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner            return -1;
4358423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner        }
4368423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner        snprintf(str_fd, sizeof str_fd, "%d", socket_fd);
4378423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner        qemu_opt_set(opts, "socket", str_fd);
4388423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner    }
4398423ffa1a8c56e65220e2a354cd62f71f99a7a06David 'Digit' Turner#endif
440315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    return 0;
441315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner}
442315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner
443315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turnerint inet_listen(const char *str, char *ostr, int olen,
444315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner                int socktype, int port_offset)
445315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner{
446315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    QemuOpts *opts;
447315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    char *optstr;
448315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    int sock = -1;
449315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner
450315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    opts = qemu_opts_create(&dummy_opts, NULL, 0);
451315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    if (inet_parse(opts, str) == 0) {
452315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        sock = inet_listen_opts(opts, port_offset);
453315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        if (sock != -1 && ostr) {
454315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner            optstr = strchr(str, ',');
455315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner            if (qemu_opt_get_bool(opts, "ipv6", 0)) {
456315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner                snprintf(ostr, olen, "[%s]:%s%s",
457315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner                         qemu_opt_get(opts, "host"),
458315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner                         qemu_opt_get(opts, "port"),
459315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner                         optstr ? optstr : "");
460315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner            } else {
461315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner                snprintf(ostr, olen, "%s:%s%s",
462315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner                         qemu_opt_get(opts, "host"),
463315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner                         qemu_opt_get(opts, "port"),
464315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner                         optstr ? optstr : "");
465315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner            }
466315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        }
467315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    }
468315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    qemu_opts_del(opts);
469315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    return sock;
470315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner}
471315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner
472315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turnerint inet_connect(const char *str, int socktype)
473315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner{
474315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    QemuOpts *opts;
475315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    int sock = -1;
476315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner
477315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    opts = qemu_opts_create(&dummy_opts, NULL, 0);
478315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    if (inet_parse(opts, str) == 0)
479315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        sock = inet_connect_opts(opts);
480315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    qemu_opts_del(opts);
481315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    return sock;
482315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner}
483315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner
4845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifndef _WIN32
4855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
486315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turnerint unix_listen_opts(QemuOpts *opts)
4875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
488315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    const char *path = qemu_opt_get(opts, "path");
489315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    char        unpath[PATH_MAX];
490315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    const char *upath;
491315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    int sock, fd;
492315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner
493315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    if (path && strlen(path)) {
4945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        upath = path;
4955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
4965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        char *tmpdir = getenv("TMPDIR");
4975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        snprintf(unpath, sizeof(unpath), "%s/qemu-socket-XXXXXX",
4985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                 tmpdir ? tmpdir : "/tmp");
499315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        upath = unpath;
5005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /*
5015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         * This dummy fd usage silences the mktemp() unsecure warning.
5025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         * Using mkstemp() doesn't make things more secure here
5035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         * though.  bind() complains about existing files, so we have
5045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         * to unlink first and thus re-open the race window.  The
5055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         * worst case possible is bind() failing, i.e. a DoS attack.
5065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         */
5075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fd = mkstemp(unpath); close(fd);
508315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        qemu_opt_set(opts, "path", unpath);
5095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
5105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sock = socket_unix_server(upath, SOCKET_STREAM);
5125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (sock < 0) {
5145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "bind(unix:%s): %s\n", upath, errno_str);
5155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto err;
5165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
5175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (sockets_debug)
5195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "bind(unix:%s): OK\n", upath);
5205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return sock;
5225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnererr:
5245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    socket_close(sock);
5255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return -1;
5265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
5275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
528315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turnerint unix_connect_opts(QemuOpts *opts)
5295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
5305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    SockAddress  un;
531315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    const char *path = qemu_opt_get(opts, "path");
5325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int ret, sock;
5335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sock = socket_create_unix(SOCKET_STREAM);
5355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (sock < 0) {
5365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        perror("socket(unix)");
5375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
5385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
5395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sock_address_init_unix(&un, path);
5415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret = socket_connect(sock, &un);
5425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sock_address_done(&un);
5435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ret < 0) {
5445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "connect(unix:%s): %s\n", path, errno_str);
5455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
5465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
5475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (sockets_debug)
5505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "connect(unix:%s): OK\n", path);
5515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return sock;
5525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
5535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
554315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner/* compatibility wrapper */
555315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turnerint unix_listen(const char *str, char *ostr, int olen)
556315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner{
557315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    QemuOpts *opts;
558315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    char *path, *optstr;
559315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    int sock, len;
560315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner
561315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    opts = qemu_opts_create(&dummy_opts, NULL, 0);
562315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner
563315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    optstr = strchr(str, ',');
564315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    if (optstr) {
565315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        len = optstr - str;
566315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        if (len) {
567aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner            path = g_malloc(len+1);
568315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner            snprintf(path, len+1, "%.*s", len, str);
569315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner            qemu_opt_set(opts, "path", path);
570aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner            g_free(path);
571315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        }
572315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    } else {
573315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        qemu_opt_set(opts, "path", str);
574315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    }
575315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner
576315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    sock = unix_listen_opts(opts);
577315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner
578315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    if (sock != -1 && ostr)
579315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        snprintf(ostr, olen, "%s%s", qemu_opt_get(opts, "path"), optstr ? optstr : "");
580315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    qemu_opts_del(opts);
581315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    return sock;
582315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner}
583315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner
584315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turnerint unix_connect(const char *path)
585315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner{
586315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    QemuOpts *opts;
587315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    int sock;
588315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner
589315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    opts = qemu_opts_create(&dummy_opts, NULL, 0);
590315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    qemu_opt_set(opts, "path", path);
591315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    sock = unix_connect_opts(opts);
592315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    qemu_opts_del(opts);
593315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    return sock;
594315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner}
595315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner
5965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else
5975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
598315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turnerint unix_listen_opts(QemuOpts *opts)
599315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner{
600315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    fprintf(stderr, "unix sockets are not available on windows\n");
601315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    return -1;
602315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner}
603315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner
604315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turnerint unix_connect_opts(QemuOpts *opts)
605315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner{
606315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    fprintf(stderr, "unix sockets are not available on windows\n");
607315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    return -1;
608315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner}
609315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner
6105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint unix_listen(const char *path, char *ostr, int olen)
6115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    fprintf(stderr, "unix sockets are not available on windows\n");
6135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return -1;
6145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint unix_connect(const char *path)
6175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    fprintf(stderr, "unix sockets are not available on windows\n");
6195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return -1;
6205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
623315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner
624315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner#ifndef CONFIG_ANDROID /* see sockets.c */
625315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner#ifdef _WIN32
626315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turnerstatic void socket_cleanup(void)
627315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner{
628315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    WSACleanup();
629315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner}
630315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner#endif
631315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner
632315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turnerint socket_init(void)
633315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner{
634315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner#ifdef _WIN32
635315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    WSADATA Data;
636315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    int ret, err;
637315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner
638315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    ret = WSAStartup(MAKEWORD(2,2), &Data);
639315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    if (ret != 0) {
640315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        err = WSAGetLastError();
641315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        fprintf(stderr, "WSAStartup: %d\n", err);
642315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner        return -1;
643315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    }
644315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    atexit(socket_cleanup);
645315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner#endif
646315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner    return 0;
647315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner}
648315ceb8a16eb7a2102fee4946898e7b8a202e86aDavid Turner#endif /* !CONFIG_ANDROID */
649