Statistics
| Branch: | Revision:

root / net / socket.c @ a96ed02f

History | View | Annotate | Download (18.9 kB)

1 42281ac9 Mark McLoughlin
/*
2 42281ac9 Mark McLoughlin
 * QEMU System Emulator
3 42281ac9 Mark McLoughlin
 *
4 42281ac9 Mark McLoughlin
 * Copyright (c) 2003-2008 Fabrice Bellard
5 42281ac9 Mark McLoughlin
 *
6 42281ac9 Mark McLoughlin
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 42281ac9 Mark McLoughlin
 * of this software and associated documentation files (the "Software"), to deal
8 42281ac9 Mark McLoughlin
 * in the Software without restriction, including without limitation the rights
9 42281ac9 Mark McLoughlin
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 42281ac9 Mark McLoughlin
 * copies of the Software, and to permit persons to whom the Software is
11 42281ac9 Mark McLoughlin
 * furnished to do so, subject to the following conditions:
12 42281ac9 Mark McLoughlin
 *
13 42281ac9 Mark McLoughlin
 * The above copyright notice and this permission notice shall be included in
14 42281ac9 Mark McLoughlin
 * all copies or substantial portions of the Software.
15 42281ac9 Mark McLoughlin
 *
16 42281ac9 Mark McLoughlin
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 42281ac9 Mark McLoughlin
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 42281ac9 Mark McLoughlin
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 42281ac9 Mark McLoughlin
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 42281ac9 Mark McLoughlin
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 42281ac9 Mark McLoughlin
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 42281ac9 Mark McLoughlin
 * THE SOFTWARE.
23 42281ac9 Mark McLoughlin
 */
24 42281ac9 Mark McLoughlin
#include "net/socket.h"
25 42281ac9 Mark McLoughlin
26 42281ac9 Mark McLoughlin
#include "config-host.h"
27 42281ac9 Mark McLoughlin
28 42281ac9 Mark McLoughlin
#include "net.h"
29 42dcc547 Luiz Capitulino
#include "monitor.h"
30 42281ac9 Mark McLoughlin
#include "qemu-char.h"
31 42281ac9 Mark McLoughlin
#include "qemu-common.h"
32 2f792016 Markus Armbruster
#include "qemu-error.h"
33 42281ac9 Mark McLoughlin
#include "qemu-option.h"
34 42281ac9 Mark McLoughlin
#include "qemu_socket.h"
35 42281ac9 Mark McLoughlin
36 42281ac9 Mark McLoughlin
typedef struct NetSocketState {
37 4e68f7a0 Stefan Hajnoczi
    NetClientState nc;
38 011de2b5 Zhi Yong Wu
    int listen_fd;
39 42281ac9 Mark McLoughlin
    int fd;
40 42281ac9 Mark McLoughlin
    int state; /* 0 = getting length, 1 = getting data */
41 42281ac9 Mark McLoughlin
    unsigned int index;
42 42281ac9 Mark McLoughlin
    unsigned int packet_len;
43 42281ac9 Mark McLoughlin
    uint8_t buf[4096];
44 42281ac9 Mark McLoughlin
    struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */
45 42281ac9 Mark McLoughlin
} NetSocketState;
46 42281ac9 Mark McLoughlin
47 011de2b5 Zhi Yong Wu
static void net_socket_accept(void *opaque);
48 42281ac9 Mark McLoughlin
49 42281ac9 Mark McLoughlin
/* XXX: we consider we can send the whole packet without blocking */
50 4e68f7a0 Stefan Hajnoczi
static ssize_t net_socket_receive(NetClientState *nc, const uint8_t *buf, size_t size)
51 42281ac9 Mark McLoughlin
{
52 564f63e3 Mark McLoughlin
    NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
53 42281ac9 Mark McLoughlin
    uint32_t len;
54 42281ac9 Mark McLoughlin
    len = htonl(size);
55 42281ac9 Mark McLoughlin
56 42281ac9 Mark McLoughlin
    send_all(s->fd, (const uint8_t *)&len, sizeof(len));
57 42281ac9 Mark McLoughlin
    return send_all(s->fd, buf, size);
58 42281ac9 Mark McLoughlin
}
59 42281ac9 Mark McLoughlin
60 4e68f7a0 Stefan Hajnoczi
static ssize_t net_socket_receive_dgram(NetClientState *nc, const uint8_t *buf, size_t size)
61 42281ac9 Mark McLoughlin
{
62 564f63e3 Mark McLoughlin
    NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
63 42281ac9 Mark McLoughlin
64 42281ac9 Mark McLoughlin
    return sendto(s->fd, (const void *)buf, size, 0,
65 42281ac9 Mark McLoughlin
                  (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst));
66 42281ac9 Mark McLoughlin
}
67 42281ac9 Mark McLoughlin
68 42281ac9 Mark McLoughlin
static void net_socket_send(void *opaque)
69 42281ac9 Mark McLoughlin
{
70 42281ac9 Mark McLoughlin
    NetSocketState *s = opaque;
71 42281ac9 Mark McLoughlin
    int size, err;
72 42281ac9 Mark McLoughlin
    unsigned l;
73 42281ac9 Mark McLoughlin
    uint8_t buf1[4096];
74 42281ac9 Mark McLoughlin
    const uint8_t *buf;
75 42281ac9 Mark McLoughlin
76 00aa0040 Blue Swirl
    size = qemu_recv(s->fd, buf1, sizeof(buf1), 0);
77 42281ac9 Mark McLoughlin
    if (size < 0) {
78 42281ac9 Mark McLoughlin
        err = socket_error();
79 42281ac9 Mark McLoughlin
        if (err != EWOULDBLOCK)
80 42281ac9 Mark McLoughlin
            goto eoc;
81 42281ac9 Mark McLoughlin
    } else if (size == 0) {
82 42281ac9 Mark McLoughlin
        /* end of connection */
83 42281ac9 Mark McLoughlin
    eoc:
84 42281ac9 Mark McLoughlin
        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
85 011de2b5 Zhi Yong Wu
        if (s->listen_fd != -1) {
86 011de2b5 Zhi Yong Wu
            qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s);
87 011de2b5 Zhi Yong Wu
        }
88 42281ac9 Mark McLoughlin
        closesocket(s->fd);
89 011de2b5 Zhi Yong Wu
90 011de2b5 Zhi Yong Wu
        s->fd = -1;
91 011de2b5 Zhi Yong Wu
        s->state = 0;
92 011de2b5 Zhi Yong Wu
        s->index = 0;
93 011de2b5 Zhi Yong Wu
        s->packet_len = 0;
94 011de2b5 Zhi Yong Wu
        s->nc.link_down = true;
95 011de2b5 Zhi Yong Wu
        memset(s->buf, 0, sizeof(s->buf));
96 011de2b5 Zhi Yong Wu
        memset(s->nc.info_str, 0, sizeof(s->nc.info_str));
97 011de2b5 Zhi Yong Wu
98 42281ac9 Mark McLoughlin
        return;
99 42281ac9 Mark McLoughlin
    }
100 42281ac9 Mark McLoughlin
    buf = buf1;
101 42281ac9 Mark McLoughlin
    while (size > 0) {
102 42281ac9 Mark McLoughlin
        /* reassemble a packet from the network */
103 42281ac9 Mark McLoughlin
        switch(s->state) {
104 42281ac9 Mark McLoughlin
        case 0:
105 42281ac9 Mark McLoughlin
            l = 4 - s->index;
106 42281ac9 Mark McLoughlin
            if (l > size)
107 42281ac9 Mark McLoughlin
                l = size;
108 42281ac9 Mark McLoughlin
            memcpy(s->buf + s->index, buf, l);
109 42281ac9 Mark McLoughlin
            buf += l;
110 42281ac9 Mark McLoughlin
            size -= l;
111 42281ac9 Mark McLoughlin
            s->index += l;
112 42281ac9 Mark McLoughlin
            if (s->index == 4) {
113 42281ac9 Mark McLoughlin
                /* got length */
114 42281ac9 Mark McLoughlin
                s->packet_len = ntohl(*(uint32_t *)s->buf);
115 42281ac9 Mark McLoughlin
                s->index = 0;
116 42281ac9 Mark McLoughlin
                s->state = 1;
117 42281ac9 Mark McLoughlin
            }
118 42281ac9 Mark McLoughlin
            break;
119 42281ac9 Mark McLoughlin
        case 1:
120 42281ac9 Mark McLoughlin
            l = s->packet_len - s->index;
121 42281ac9 Mark McLoughlin
            if (l > size)
122 42281ac9 Mark McLoughlin
                l = size;
123 42281ac9 Mark McLoughlin
            if (s->index + l <= sizeof(s->buf)) {
124 42281ac9 Mark McLoughlin
                memcpy(s->buf + s->index, buf, l);
125 42281ac9 Mark McLoughlin
            } else {
126 42281ac9 Mark McLoughlin
                fprintf(stderr, "serious error: oversized packet received,"
127 42281ac9 Mark McLoughlin
                    "connection terminated.\n");
128 42281ac9 Mark McLoughlin
                s->state = 0;
129 42281ac9 Mark McLoughlin
                goto eoc;
130 42281ac9 Mark McLoughlin
            }
131 42281ac9 Mark McLoughlin
132 42281ac9 Mark McLoughlin
            s->index += l;
133 42281ac9 Mark McLoughlin
            buf += l;
134 42281ac9 Mark McLoughlin
            size -= l;
135 42281ac9 Mark McLoughlin
            if (s->index >= s->packet_len) {
136 564f63e3 Mark McLoughlin
                qemu_send_packet(&s->nc, s->buf, s->packet_len);
137 42281ac9 Mark McLoughlin
                s->index = 0;
138 42281ac9 Mark McLoughlin
                s->state = 0;
139 42281ac9 Mark McLoughlin
            }
140 42281ac9 Mark McLoughlin
            break;
141 42281ac9 Mark McLoughlin
        }
142 42281ac9 Mark McLoughlin
    }
143 42281ac9 Mark McLoughlin
}
144 42281ac9 Mark McLoughlin
145 42281ac9 Mark McLoughlin
static void net_socket_send_dgram(void *opaque)
146 42281ac9 Mark McLoughlin
{
147 42281ac9 Mark McLoughlin
    NetSocketState *s = opaque;
148 42281ac9 Mark McLoughlin
    int size;
149 42281ac9 Mark McLoughlin
150 00aa0040 Blue Swirl
    size = qemu_recv(s->fd, s->buf, sizeof(s->buf), 0);
151 42281ac9 Mark McLoughlin
    if (size < 0)
152 42281ac9 Mark McLoughlin
        return;
153 42281ac9 Mark McLoughlin
    if (size == 0) {
154 42281ac9 Mark McLoughlin
        /* end of connection */
155 42281ac9 Mark McLoughlin
        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
156 42281ac9 Mark McLoughlin
        return;
157 42281ac9 Mark McLoughlin
    }
158 564f63e3 Mark McLoughlin
    qemu_send_packet(&s->nc, s->buf, size);
159 42281ac9 Mark McLoughlin
}
160 42281ac9 Mark McLoughlin
161 3a75e74c Mike Ryan
static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr *localaddr)
162 42281ac9 Mark McLoughlin
{
163 42281ac9 Mark McLoughlin
    struct ip_mreq imr;
164 42281ac9 Mark McLoughlin
    int fd;
165 42281ac9 Mark McLoughlin
    int val, ret;
166 23ddf2bb Brad
#ifdef __OpenBSD__
167 23ddf2bb Brad
    unsigned char loop;
168 23ddf2bb Brad
#else
169 23ddf2bb Brad
    int loop;
170 23ddf2bb Brad
#endif
171 23ddf2bb Brad
172 42281ac9 Mark McLoughlin
    if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) {
173 842480d4 Stefan Hajnoczi
        fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) "
174 842480d4 Stefan Hajnoczi
                "does not contain a multicast address\n",
175 842480d4 Stefan Hajnoczi
                inet_ntoa(mcastaddr->sin_addr),
176 42281ac9 Mark McLoughlin
                (int)ntohl(mcastaddr->sin_addr.s_addr));
177 842480d4 Stefan Hajnoczi
        return -1;
178 42281ac9 Mark McLoughlin
179 42281ac9 Mark McLoughlin
    }
180 40ff6d7e Kevin Wolf
    fd = qemu_socket(PF_INET, SOCK_DGRAM, 0);
181 42281ac9 Mark McLoughlin
    if (fd < 0) {
182 42281ac9 Mark McLoughlin
        perror("socket(PF_INET, SOCK_DGRAM)");
183 42281ac9 Mark McLoughlin
        return -1;
184 42281ac9 Mark McLoughlin
    }
185 42281ac9 Mark McLoughlin
186 42281ac9 Mark McLoughlin
    val = 1;
187 42281ac9 Mark McLoughlin
    ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
188 42281ac9 Mark McLoughlin
                   (const char *)&val, sizeof(val));
189 42281ac9 Mark McLoughlin
    if (ret < 0) {
190 842480d4 Stefan Hajnoczi
        perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
191 842480d4 Stefan Hajnoczi
        goto fail;
192 42281ac9 Mark McLoughlin
    }
193 42281ac9 Mark McLoughlin
194 42281ac9 Mark McLoughlin
    ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr));
195 42281ac9 Mark McLoughlin
    if (ret < 0) {
196 42281ac9 Mark McLoughlin
        perror("bind");
197 42281ac9 Mark McLoughlin
        goto fail;
198 42281ac9 Mark McLoughlin
    }
199 42281ac9 Mark McLoughlin
200 42281ac9 Mark McLoughlin
    /* Add host to multicast group */
201 42281ac9 Mark McLoughlin
    imr.imr_multiaddr = mcastaddr->sin_addr;
202 3a75e74c Mike Ryan
    if (localaddr) {
203 3a75e74c Mike Ryan
        imr.imr_interface = *localaddr;
204 3a75e74c Mike Ryan
    } else {
205 3a75e74c Mike Ryan
        imr.imr_interface.s_addr = htonl(INADDR_ANY);
206 3a75e74c Mike Ryan
    }
207 42281ac9 Mark McLoughlin
208 42281ac9 Mark McLoughlin
    ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
209 42281ac9 Mark McLoughlin
                     (const char *)&imr, sizeof(struct ip_mreq));
210 42281ac9 Mark McLoughlin
    if (ret < 0) {
211 842480d4 Stefan Hajnoczi
        perror("setsockopt(IP_ADD_MEMBERSHIP)");
212 842480d4 Stefan Hajnoczi
        goto fail;
213 42281ac9 Mark McLoughlin
    }
214 42281ac9 Mark McLoughlin
215 42281ac9 Mark McLoughlin
    /* Force mcast msgs to loopback (eg. several QEMUs in same host */
216 23ddf2bb Brad
    loop = 1;
217 42281ac9 Mark McLoughlin
    ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
218 23ddf2bb Brad
                   (const char *)&loop, sizeof(loop));
219 42281ac9 Mark McLoughlin
    if (ret < 0) {
220 842480d4 Stefan Hajnoczi
        perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
221 842480d4 Stefan Hajnoczi
        goto fail;
222 42281ac9 Mark McLoughlin
    }
223 42281ac9 Mark McLoughlin
224 3a75e74c Mike Ryan
    /* If a bind address is given, only send packets from that address */
225 3a75e74c Mike Ryan
    if (localaddr != NULL) {
226 4d22c6c2 Blue Swirl
        ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
227 4d22c6c2 Blue Swirl
                         (const char *)localaddr, sizeof(*localaddr));
228 3a75e74c Mike Ryan
        if (ret < 0) {
229 3a75e74c Mike Ryan
            perror("setsockopt(IP_MULTICAST_IF)");
230 3a75e74c Mike Ryan
            goto fail;
231 3a75e74c Mike Ryan
        }
232 3a75e74c Mike Ryan
    }
233 3a75e74c Mike Ryan
234 42281ac9 Mark McLoughlin
    socket_set_nonblock(fd);
235 42281ac9 Mark McLoughlin
    return fd;
236 42281ac9 Mark McLoughlin
fail:
237 42281ac9 Mark McLoughlin
    if (fd >= 0)
238 42281ac9 Mark McLoughlin
        closesocket(fd);
239 42281ac9 Mark McLoughlin
    return -1;
240 42281ac9 Mark McLoughlin
}
241 42281ac9 Mark McLoughlin
242 4e68f7a0 Stefan Hajnoczi
static void net_socket_cleanup(NetClientState *nc)
243 42281ac9 Mark McLoughlin
{
244 564f63e3 Mark McLoughlin
    NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
245 011de2b5 Zhi Yong Wu
    if (s->fd != -1) {
246 011de2b5 Zhi Yong Wu
        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
247 011de2b5 Zhi Yong Wu
        close(s->fd);
248 011de2b5 Zhi Yong Wu
        s->fd = -1;
249 011de2b5 Zhi Yong Wu
    }
250 011de2b5 Zhi Yong Wu
    if (s->listen_fd != -1) {
251 011de2b5 Zhi Yong Wu
        qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
252 011de2b5 Zhi Yong Wu
        closesocket(s->listen_fd);
253 011de2b5 Zhi Yong Wu
        s->listen_fd = -1;
254 011de2b5 Zhi Yong Wu
    }
255 42281ac9 Mark McLoughlin
}
256 42281ac9 Mark McLoughlin
257 564f63e3 Mark McLoughlin
static NetClientInfo net_dgram_socket_info = {
258 2be64a68 Laszlo Ersek
    .type = NET_CLIENT_OPTIONS_KIND_SOCKET,
259 564f63e3 Mark McLoughlin
    .size = sizeof(NetSocketState),
260 564f63e3 Mark McLoughlin
    .receive = net_socket_receive_dgram,
261 564f63e3 Mark McLoughlin
    .cleanup = net_socket_cleanup,
262 564f63e3 Mark McLoughlin
};
263 564f63e3 Mark McLoughlin
264 4e68f7a0 Stefan Hajnoczi
static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer,
265 42281ac9 Mark McLoughlin
                                                const char *model,
266 42281ac9 Mark McLoughlin
                                                const char *name,
267 42281ac9 Mark McLoughlin
                                                int fd, int is_connected)
268 42281ac9 Mark McLoughlin
{
269 42281ac9 Mark McLoughlin
    struct sockaddr_in saddr;
270 42281ac9 Mark McLoughlin
    int newfd;
271 42281ac9 Mark McLoughlin
    socklen_t saddr_len;
272 4e68f7a0 Stefan Hajnoczi
    NetClientState *nc;
273 42281ac9 Mark McLoughlin
    NetSocketState *s;
274 42281ac9 Mark McLoughlin
275 42281ac9 Mark McLoughlin
    /* fd passed: multicast: "learn" dgram_dst address from bound address and save it
276 42281ac9 Mark McLoughlin
     * Because this may be "shared" socket from a "master" process, datagrams would be recv()
277 42281ac9 Mark McLoughlin
     * by ONLY ONE process: we must "clone" this dgram socket --jjo
278 42281ac9 Mark McLoughlin
     */
279 42281ac9 Mark McLoughlin
280 42281ac9 Mark McLoughlin
    if (is_connected) {
281 842480d4 Stefan Hajnoczi
        if (getsockname(fd, (struct sockaddr *) &saddr, &saddr_len) == 0) {
282 842480d4 Stefan Hajnoczi
            /* must be bound */
283 842480d4 Stefan Hajnoczi
            if (saddr.sin_addr.s_addr == 0) {
284 842480d4 Stefan Hajnoczi
                fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, "
285 842480d4 Stefan Hajnoczi
                        "cannot setup multicast dst addr\n", fd);
286 e5d1fca0 Stefan Hajnoczi
                goto err;
287 842480d4 Stefan Hajnoczi
            }
288 842480d4 Stefan Hajnoczi
            /* clone dgram socket */
289 842480d4 Stefan Hajnoczi
            newfd = net_socket_mcast_create(&saddr, NULL);
290 842480d4 Stefan Hajnoczi
            if (newfd < 0) {
291 842480d4 Stefan Hajnoczi
                /* error already reported by net_socket_mcast_create() */
292 e5d1fca0 Stefan Hajnoczi
                goto err;
293 842480d4 Stefan Hajnoczi
            }
294 842480d4 Stefan Hajnoczi
            /* clone newfd to fd, close newfd */
295 842480d4 Stefan Hajnoczi
            dup2(newfd, fd);
296 842480d4 Stefan Hajnoczi
            close(newfd);
297 842480d4 Stefan Hajnoczi
298 842480d4 Stefan Hajnoczi
        } else {
299 842480d4 Stefan Hajnoczi
            fprintf(stderr,
300 842480d4 Stefan Hajnoczi
                    "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n",
301 842480d4 Stefan Hajnoczi
                    fd, strerror(errno));
302 e5d1fca0 Stefan Hajnoczi
            goto err;
303 842480d4 Stefan Hajnoczi
        }
304 42281ac9 Mark McLoughlin
    }
305 42281ac9 Mark McLoughlin
306 ab5f3f84 Stefan Hajnoczi
    nc = qemu_new_net_client(&net_dgram_socket_info, peer, model, name);
307 564f63e3 Mark McLoughlin
308 564f63e3 Mark McLoughlin
    snprintf(nc->info_str, sizeof(nc->info_str),
309 842480d4 Stefan Hajnoczi
            "socket: fd=%d (%s mcast=%s:%d)",
310 842480d4 Stefan Hajnoczi
            fd, is_connected ? "cloned" : "",
311 842480d4 Stefan Hajnoczi
            inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
312 564f63e3 Mark McLoughlin
313 564f63e3 Mark McLoughlin
    s = DO_UPCAST(NetSocketState, nc, nc);
314 564f63e3 Mark McLoughlin
315 42281ac9 Mark McLoughlin
    s->fd = fd;
316 011de2b5 Zhi Yong Wu
    s->listen_fd = -1;
317 42281ac9 Mark McLoughlin
318 42281ac9 Mark McLoughlin
    qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s);
319 42281ac9 Mark McLoughlin
320 42281ac9 Mark McLoughlin
    /* mcast: save bound address as dst */
321 e34cde35 Zhi Yong Wu
    if (is_connected) {
322 e34cde35 Zhi Yong Wu
        s->dgram_dst = saddr;
323 e34cde35 Zhi Yong Wu
    }
324 42281ac9 Mark McLoughlin
325 42281ac9 Mark McLoughlin
    return s;
326 e5d1fca0 Stefan Hajnoczi
327 e5d1fca0 Stefan Hajnoczi
err:
328 e5d1fca0 Stefan Hajnoczi
    closesocket(fd);
329 e5d1fca0 Stefan Hajnoczi
    return NULL;
330 42281ac9 Mark McLoughlin
}
331 42281ac9 Mark McLoughlin
332 42281ac9 Mark McLoughlin
static void net_socket_connect(void *opaque)
333 42281ac9 Mark McLoughlin
{
334 42281ac9 Mark McLoughlin
    NetSocketState *s = opaque;
335 42281ac9 Mark McLoughlin
    qemu_set_fd_handler(s->fd, net_socket_send, NULL, s);
336 42281ac9 Mark McLoughlin
}
337 42281ac9 Mark McLoughlin
338 564f63e3 Mark McLoughlin
static NetClientInfo net_socket_info = {
339 2be64a68 Laszlo Ersek
    .type = NET_CLIENT_OPTIONS_KIND_SOCKET,
340 564f63e3 Mark McLoughlin
    .size = sizeof(NetSocketState),
341 564f63e3 Mark McLoughlin
    .receive = net_socket_receive,
342 564f63e3 Mark McLoughlin
    .cleanup = net_socket_cleanup,
343 564f63e3 Mark McLoughlin
};
344 564f63e3 Mark McLoughlin
345 4e68f7a0 Stefan Hajnoczi
static NetSocketState *net_socket_fd_init_stream(NetClientState *peer,
346 42281ac9 Mark McLoughlin
                                                 const char *model,
347 42281ac9 Mark McLoughlin
                                                 const char *name,
348 42281ac9 Mark McLoughlin
                                                 int fd, int is_connected)
349 42281ac9 Mark McLoughlin
{
350 4e68f7a0 Stefan Hajnoczi
    NetClientState *nc;
351 42281ac9 Mark McLoughlin
    NetSocketState *s;
352 564f63e3 Mark McLoughlin
353 ab5f3f84 Stefan Hajnoczi
    nc = qemu_new_net_client(&net_socket_info, peer, model, name);
354 564f63e3 Mark McLoughlin
355 564f63e3 Mark McLoughlin
    snprintf(nc->info_str, sizeof(nc->info_str), "socket: fd=%d", fd);
356 564f63e3 Mark McLoughlin
357 564f63e3 Mark McLoughlin
    s = DO_UPCAST(NetSocketState, nc, nc);
358 564f63e3 Mark McLoughlin
359 42281ac9 Mark McLoughlin
    s->fd = fd;
360 011de2b5 Zhi Yong Wu
    s->listen_fd = -1;
361 564f63e3 Mark McLoughlin
362 42281ac9 Mark McLoughlin
    if (is_connected) {
363 42281ac9 Mark McLoughlin
        net_socket_connect(s);
364 42281ac9 Mark McLoughlin
    } else {
365 42281ac9 Mark McLoughlin
        qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s);
366 42281ac9 Mark McLoughlin
    }
367 42281ac9 Mark McLoughlin
    return s;
368 42281ac9 Mark McLoughlin
}
369 42281ac9 Mark McLoughlin
370 4e68f7a0 Stefan Hajnoczi
static NetSocketState *net_socket_fd_init(NetClientState *peer,
371 42281ac9 Mark McLoughlin
                                          const char *model, const char *name,
372 42281ac9 Mark McLoughlin
                                          int fd, int is_connected)
373 42281ac9 Mark McLoughlin
{
374 42281ac9 Mark McLoughlin
    int so_type = -1, optlen=sizeof(so_type);
375 42281ac9 Mark McLoughlin
376 42281ac9 Mark McLoughlin
    if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type,
377 42281ac9 Mark McLoughlin
        (socklen_t *)&optlen)< 0) {
378 842480d4 Stefan Hajnoczi
        fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n",
379 842480d4 Stefan Hajnoczi
                fd);
380 e5d1fca0 Stefan Hajnoczi
        closesocket(fd);
381 842480d4 Stefan Hajnoczi
        return NULL;
382 42281ac9 Mark McLoughlin
    }
383 42281ac9 Mark McLoughlin
    switch(so_type) {
384 42281ac9 Mark McLoughlin
    case SOCK_DGRAM:
385 d33d93b2 Stefan Hajnoczi
        return net_socket_fd_init_dgram(peer, model, name, fd, is_connected);
386 42281ac9 Mark McLoughlin
    case SOCK_STREAM:
387 d33d93b2 Stefan Hajnoczi
        return net_socket_fd_init_stream(peer, model, name, fd, is_connected);
388 42281ac9 Mark McLoughlin
    default:
389 42281ac9 Mark McLoughlin
        /* who knows ... this could be a eg. a pty, do warn and continue as stream */
390 42281ac9 Mark McLoughlin
        fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd);
391 d33d93b2 Stefan Hajnoczi
        return net_socket_fd_init_stream(peer, model, name, fd, is_connected);
392 42281ac9 Mark McLoughlin
    }
393 42281ac9 Mark McLoughlin
    return NULL;
394 42281ac9 Mark McLoughlin
}
395 42281ac9 Mark McLoughlin
396 42281ac9 Mark McLoughlin
static void net_socket_accept(void *opaque)
397 42281ac9 Mark McLoughlin
{
398 011de2b5 Zhi Yong Wu
    NetSocketState *s = opaque;
399 42281ac9 Mark McLoughlin
    struct sockaddr_in saddr;
400 42281ac9 Mark McLoughlin
    socklen_t len;
401 42281ac9 Mark McLoughlin
    int fd;
402 42281ac9 Mark McLoughlin
403 42281ac9 Mark McLoughlin
    for(;;) {
404 42281ac9 Mark McLoughlin
        len = sizeof(saddr);
405 011de2b5 Zhi Yong Wu
        fd = qemu_accept(s->listen_fd, (struct sockaddr *)&saddr, &len);
406 42281ac9 Mark McLoughlin
        if (fd < 0 && errno != EINTR) {
407 42281ac9 Mark McLoughlin
            return;
408 42281ac9 Mark McLoughlin
        } else if (fd >= 0) {
409 011de2b5 Zhi Yong Wu
            qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
410 42281ac9 Mark McLoughlin
            break;
411 42281ac9 Mark McLoughlin
        }
412 42281ac9 Mark McLoughlin
    }
413 011de2b5 Zhi Yong Wu
414 011de2b5 Zhi Yong Wu
    s->fd = fd;
415 011de2b5 Zhi Yong Wu
    s->nc.link_down = false;
416 011de2b5 Zhi Yong Wu
    net_socket_connect(s);
417 011de2b5 Zhi Yong Wu
    snprintf(s->nc.info_str, sizeof(s->nc.info_str),
418 011de2b5 Zhi Yong Wu
             "socket: connection from %s:%d",
419 011de2b5 Zhi Yong Wu
             inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
420 42281ac9 Mark McLoughlin
}
421 42281ac9 Mark McLoughlin
422 4e68f7a0 Stefan Hajnoczi
static int net_socket_listen_init(NetClientState *peer,
423 42281ac9 Mark McLoughlin
                                  const char *model,
424 42281ac9 Mark McLoughlin
                                  const char *name,
425 42281ac9 Mark McLoughlin
                                  const char *host_str)
426 42281ac9 Mark McLoughlin
{
427 011de2b5 Zhi Yong Wu
    NetClientState *nc;
428 011de2b5 Zhi Yong Wu
    NetSocketState *s;
429 42281ac9 Mark McLoughlin
    struct sockaddr_in saddr;
430 011de2b5 Zhi Yong Wu
    int fd, val, ret;
431 42281ac9 Mark McLoughlin
432 42281ac9 Mark McLoughlin
    if (parse_host_port(&saddr, host_str) < 0)
433 42281ac9 Mark McLoughlin
        return -1;
434 42281ac9 Mark McLoughlin
435 40ff6d7e Kevin Wolf
    fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
436 42281ac9 Mark McLoughlin
    if (fd < 0) {
437 42281ac9 Mark McLoughlin
        perror("socket");
438 42281ac9 Mark McLoughlin
        return -1;
439 42281ac9 Mark McLoughlin
    }
440 42281ac9 Mark McLoughlin
    socket_set_nonblock(fd);
441 42281ac9 Mark McLoughlin
442 42281ac9 Mark McLoughlin
    /* allow fast reuse */
443 42281ac9 Mark McLoughlin
    val = 1;
444 42281ac9 Mark McLoughlin
    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
445 42281ac9 Mark McLoughlin
446 42281ac9 Mark McLoughlin
    ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
447 42281ac9 Mark McLoughlin
    if (ret < 0) {
448 42281ac9 Mark McLoughlin
        perror("bind");
449 a46667ea Peter Maydell
        closesocket(fd);
450 42281ac9 Mark McLoughlin
        return -1;
451 42281ac9 Mark McLoughlin
    }
452 42281ac9 Mark McLoughlin
    ret = listen(fd, 0);
453 42281ac9 Mark McLoughlin
    if (ret < 0) {
454 42281ac9 Mark McLoughlin
        perror("listen");
455 a46667ea Peter Maydell
        closesocket(fd);
456 42281ac9 Mark McLoughlin
        return -1;
457 42281ac9 Mark McLoughlin
    }
458 011de2b5 Zhi Yong Wu
459 011de2b5 Zhi Yong Wu
    nc = qemu_new_net_client(&net_socket_info, peer, model, name);
460 011de2b5 Zhi Yong Wu
    s = DO_UPCAST(NetSocketState, nc, nc);
461 011de2b5 Zhi Yong Wu
    s->fd = -1;
462 011de2b5 Zhi Yong Wu
    s->listen_fd = fd;
463 011de2b5 Zhi Yong Wu
    s->nc.link_down = true;
464 011de2b5 Zhi Yong Wu
465 011de2b5 Zhi Yong Wu
    qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s);
466 42281ac9 Mark McLoughlin
    return 0;
467 42281ac9 Mark McLoughlin
}
468 42281ac9 Mark McLoughlin
469 4e68f7a0 Stefan Hajnoczi
static int net_socket_connect_init(NetClientState *peer,
470 42281ac9 Mark McLoughlin
                                   const char *model,
471 42281ac9 Mark McLoughlin
                                   const char *name,
472 42281ac9 Mark McLoughlin
                                   const char *host_str)
473 42281ac9 Mark McLoughlin
{
474 42281ac9 Mark McLoughlin
    NetSocketState *s;
475 42281ac9 Mark McLoughlin
    int fd, connected, ret, err;
476 42281ac9 Mark McLoughlin
    struct sockaddr_in saddr;
477 42281ac9 Mark McLoughlin
478 42281ac9 Mark McLoughlin
    if (parse_host_port(&saddr, host_str) < 0)
479 42281ac9 Mark McLoughlin
        return -1;
480 42281ac9 Mark McLoughlin
481 40ff6d7e Kevin Wolf
    fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
482 42281ac9 Mark McLoughlin
    if (fd < 0) {
483 42281ac9 Mark McLoughlin
        perror("socket");
484 42281ac9 Mark McLoughlin
        return -1;
485 42281ac9 Mark McLoughlin
    }
486 42281ac9 Mark McLoughlin
    socket_set_nonblock(fd);
487 42281ac9 Mark McLoughlin
488 42281ac9 Mark McLoughlin
    connected = 0;
489 42281ac9 Mark McLoughlin
    for(;;) {
490 42281ac9 Mark McLoughlin
        ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
491 42281ac9 Mark McLoughlin
        if (ret < 0) {
492 42281ac9 Mark McLoughlin
            err = socket_error();
493 42281ac9 Mark McLoughlin
            if (err == EINTR || err == EWOULDBLOCK) {
494 42281ac9 Mark McLoughlin
            } else if (err == EINPROGRESS) {
495 42281ac9 Mark McLoughlin
                break;
496 42281ac9 Mark McLoughlin
#ifdef _WIN32
497 c7eb1f02 Pavel Dovgaluk
            } else if (err == WSAEALREADY || err == WSAEINVAL) {
498 42281ac9 Mark McLoughlin
                break;
499 42281ac9 Mark McLoughlin
#endif
500 42281ac9 Mark McLoughlin
            } else {
501 42281ac9 Mark McLoughlin
                perror("connect");
502 42281ac9 Mark McLoughlin
                closesocket(fd);
503 42281ac9 Mark McLoughlin
                return -1;
504 42281ac9 Mark McLoughlin
            }
505 42281ac9 Mark McLoughlin
        } else {
506 42281ac9 Mark McLoughlin
            connected = 1;
507 42281ac9 Mark McLoughlin
            break;
508 42281ac9 Mark McLoughlin
        }
509 42281ac9 Mark McLoughlin
    }
510 d33d93b2 Stefan Hajnoczi
    s = net_socket_fd_init(peer, model, name, fd, connected);
511 42281ac9 Mark McLoughlin
    if (!s)
512 42281ac9 Mark McLoughlin
        return -1;
513 564f63e3 Mark McLoughlin
    snprintf(s->nc.info_str, sizeof(s->nc.info_str),
514 42281ac9 Mark McLoughlin
             "socket: connect to %s:%d",
515 42281ac9 Mark McLoughlin
             inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
516 42281ac9 Mark McLoughlin
    return 0;
517 42281ac9 Mark McLoughlin
}
518 42281ac9 Mark McLoughlin
519 4e68f7a0 Stefan Hajnoczi
static int net_socket_mcast_init(NetClientState *peer,
520 42281ac9 Mark McLoughlin
                                 const char *model,
521 42281ac9 Mark McLoughlin
                                 const char *name,
522 3a75e74c Mike Ryan
                                 const char *host_str,
523 3a75e74c Mike Ryan
                                 const char *localaddr_str)
524 42281ac9 Mark McLoughlin
{
525 42281ac9 Mark McLoughlin
    NetSocketState *s;
526 42281ac9 Mark McLoughlin
    int fd;
527 42281ac9 Mark McLoughlin
    struct sockaddr_in saddr;
528 3a75e74c Mike Ryan
    struct in_addr localaddr, *param_localaddr;
529 42281ac9 Mark McLoughlin
530 42281ac9 Mark McLoughlin
    if (parse_host_port(&saddr, host_str) < 0)
531 42281ac9 Mark McLoughlin
        return -1;
532 42281ac9 Mark McLoughlin
533 3a75e74c Mike Ryan
    if (localaddr_str != NULL) {
534 3a75e74c Mike Ryan
        if (inet_aton(localaddr_str, &localaddr) == 0)
535 3a75e74c Mike Ryan
            return -1;
536 3a75e74c Mike Ryan
        param_localaddr = &localaddr;
537 3a75e74c Mike Ryan
    } else {
538 3a75e74c Mike Ryan
        param_localaddr = NULL;
539 3a75e74c Mike Ryan
    }
540 42281ac9 Mark McLoughlin
541 3a75e74c Mike Ryan
    fd = net_socket_mcast_create(&saddr, param_localaddr);
542 42281ac9 Mark McLoughlin
    if (fd < 0)
543 842480d4 Stefan Hajnoczi
        return -1;
544 42281ac9 Mark McLoughlin
545 d33d93b2 Stefan Hajnoczi
    s = net_socket_fd_init(peer, model, name, fd, 0);
546 42281ac9 Mark McLoughlin
    if (!s)
547 42281ac9 Mark McLoughlin
        return -1;
548 42281ac9 Mark McLoughlin
549 42281ac9 Mark McLoughlin
    s->dgram_dst = saddr;
550 42281ac9 Mark McLoughlin
551 564f63e3 Mark McLoughlin
    snprintf(s->nc.info_str, sizeof(s->nc.info_str),
552 42281ac9 Mark McLoughlin
             "socket: mcast=%s:%d",
553 42281ac9 Mark McLoughlin
             inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
554 42281ac9 Mark McLoughlin
    return 0;
555 42281ac9 Mark McLoughlin
556 42281ac9 Mark McLoughlin
}
557 42281ac9 Mark McLoughlin
558 4e68f7a0 Stefan Hajnoczi
static int net_socket_udp_init(NetClientState *peer,
559 0e0e7fac Benjamin
                                 const char *model,
560 0e0e7fac Benjamin
                                 const char *name,
561 0e0e7fac Benjamin
                                 const char *rhost,
562 0e0e7fac Benjamin
                                 const char *lhost)
563 0e0e7fac Benjamin
{
564 0e0e7fac Benjamin
    NetSocketState *s;
565 0e0e7fac Benjamin
    int fd, val, ret;
566 0e0e7fac Benjamin
    struct sockaddr_in laddr, raddr;
567 0e0e7fac Benjamin
568 0e0e7fac Benjamin
    if (parse_host_port(&laddr, lhost) < 0) {
569 0e0e7fac Benjamin
        return -1;
570 0e0e7fac Benjamin
    }
571 0e0e7fac Benjamin
572 0e0e7fac Benjamin
    if (parse_host_port(&raddr, rhost) < 0) {
573 0e0e7fac Benjamin
        return -1;
574 0e0e7fac Benjamin
    }
575 0e0e7fac Benjamin
576 0e0e7fac Benjamin
    fd = qemu_socket(PF_INET, SOCK_DGRAM, 0);
577 0e0e7fac Benjamin
    if (fd < 0) {
578 0e0e7fac Benjamin
        perror("socket(PF_INET, SOCK_DGRAM)");
579 0e0e7fac Benjamin
        return -1;
580 0e0e7fac Benjamin
    }
581 0e0e7fac Benjamin
    val = 1;
582 0e0e7fac Benjamin
    ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
583 0e0e7fac Benjamin
                   (const char *)&val, sizeof(val));
584 0e0e7fac Benjamin
    if (ret < 0) {
585 0e0e7fac Benjamin
        perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
586 0e0e7fac Benjamin
        closesocket(fd);
587 0e0e7fac Benjamin
        return -1;
588 0e0e7fac Benjamin
    }
589 0e0e7fac Benjamin
    ret = bind(fd, (struct sockaddr *)&laddr, sizeof(laddr));
590 0e0e7fac Benjamin
    if (ret < 0) {
591 0e0e7fac Benjamin
        perror("bind");
592 0e0e7fac Benjamin
        closesocket(fd);
593 0e0e7fac Benjamin
        return -1;
594 0e0e7fac Benjamin
    }
595 0e0e7fac Benjamin
596 d33d93b2 Stefan Hajnoczi
    s = net_socket_fd_init(peer, model, name, fd, 0);
597 0e0e7fac Benjamin
    if (!s) {
598 0e0e7fac Benjamin
        return -1;
599 0e0e7fac Benjamin
    }
600 0e0e7fac Benjamin
601 0e0e7fac Benjamin
    s->dgram_dst = raddr;
602 0e0e7fac Benjamin
603 0e0e7fac Benjamin
    snprintf(s->nc.info_str, sizeof(s->nc.info_str),
604 0e0e7fac Benjamin
             "socket: udp=%s:%d",
605 0e0e7fac Benjamin
             inet_ntoa(raddr.sin_addr), ntohs(raddr.sin_port));
606 0e0e7fac Benjamin
    return 0;
607 0e0e7fac Benjamin
}
608 0e0e7fac Benjamin
609 1a0c0958 Laszlo Ersek
int net_init_socket(const NetClientOptions *opts, const char *name,
610 4e68f7a0 Stefan Hajnoczi
                    NetClientState *peer)
611 42281ac9 Mark McLoughlin
{
612 bef8e8fe Laszlo Ersek
    const NetdevSocketOptions *sock;
613 42281ac9 Mark McLoughlin
614 bef8e8fe Laszlo Ersek
    assert(opts->kind == NET_CLIENT_OPTIONS_KIND_SOCKET);
615 bef8e8fe Laszlo Ersek
    sock = opts->socket;
616 42281ac9 Mark McLoughlin
617 bef8e8fe Laszlo Ersek
    if (sock->has_fd + sock->has_listen + sock->has_connect + sock->has_mcast +
618 bef8e8fe Laszlo Ersek
        sock->has_udp != 1) {
619 bef8e8fe Laszlo Ersek
        error_report("exactly one of fd=, listen=, connect=, mcast= or udp="
620 bef8e8fe Laszlo Ersek
                     " is required");
621 bef8e8fe Laszlo Ersek
        return -1;
622 bef8e8fe Laszlo Ersek
    }
623 42281ac9 Mark McLoughlin
624 bef8e8fe Laszlo Ersek
    if (sock->has_localaddr && !sock->has_mcast && !sock->has_udp) {
625 bef8e8fe Laszlo Ersek
        error_report("localaddr= is only valid with mcast= or udp=");
626 bef8e8fe Laszlo Ersek
        return -1;
627 bef8e8fe Laszlo Ersek
    }
628 42281ac9 Mark McLoughlin
629 bef8e8fe Laszlo Ersek
    if (sock->has_fd) {
630 bef8e8fe Laszlo Ersek
        int fd;
631 42281ac9 Mark McLoughlin
632 a96ed02f Nicholas Bellinger
        fd = monitor_handle_fd_param(cur_mon, sock->fd);
633 d33d93b2 Stefan Hajnoczi
        if (fd == -1 || !net_socket_fd_init(peer, "socket", name, fd, 1)) {
634 42281ac9 Mark McLoughlin
            return -1;
635 42281ac9 Mark McLoughlin
        }
636 bef8e8fe Laszlo Ersek
        return 0;
637 bef8e8fe Laszlo Ersek
    }
638 42281ac9 Mark McLoughlin
639 bef8e8fe Laszlo Ersek
    if (sock->has_listen) {
640 d33d93b2 Stefan Hajnoczi
        if (net_socket_listen_init(peer, "socket", name, sock->listen) == -1) {
641 42281ac9 Mark McLoughlin
            return -1;
642 42281ac9 Mark McLoughlin
        }
643 bef8e8fe Laszlo Ersek
        return 0;
644 bef8e8fe Laszlo Ersek
    }
645 42281ac9 Mark McLoughlin
646 bef8e8fe Laszlo Ersek
    if (sock->has_connect) {
647 d33d93b2 Stefan Hajnoczi
        if (net_socket_connect_init(peer, "socket", name, sock->connect) ==
648 bef8e8fe Laszlo Ersek
            -1) {
649 42281ac9 Mark McLoughlin
            return -1;
650 42281ac9 Mark McLoughlin
        }
651 bef8e8fe Laszlo Ersek
        return 0;
652 bef8e8fe Laszlo Ersek
    }
653 42281ac9 Mark McLoughlin
654 bef8e8fe Laszlo Ersek
    if (sock->has_mcast) {
655 bef8e8fe Laszlo Ersek
        /* if sock->localaddr is missing, it has been initialized to "all bits
656 bef8e8fe Laszlo Ersek
         * zero" */
657 d33d93b2 Stefan Hajnoczi
        if (net_socket_mcast_init(peer, "socket", name, sock->mcast,
658 bef8e8fe Laszlo Ersek
            sock->localaddr) == -1) {
659 0e0e7fac Benjamin
            return -1;
660 0e0e7fac Benjamin
        }
661 bef8e8fe Laszlo Ersek
        return 0;
662 bef8e8fe Laszlo Ersek
    }
663 0e0e7fac Benjamin
664 bef8e8fe Laszlo Ersek
    assert(sock->has_udp);
665 bef8e8fe Laszlo Ersek
    if (!sock->has_localaddr) {
666 bef8e8fe Laszlo Ersek
        error_report("localaddr= is mandatory with udp=");
667 bef8e8fe Laszlo Ersek
        return -1;
668 bef8e8fe Laszlo Ersek
    }
669 d33d93b2 Stefan Hajnoczi
    if (net_socket_udp_init(peer, "udp", name, sock->udp, sock->localaddr) ==
670 bef8e8fe Laszlo Ersek
        -1) {
671 42281ac9 Mark McLoughlin
        return -1;
672 42281ac9 Mark McLoughlin
    }
673 42281ac9 Mark McLoughlin
    return 0;
674 42281ac9 Mark McLoughlin
}