Statistics
| Branch: | Revision:

root / net / socket.c @ 54cdaa1b

History | View | Annotate | Download (16.1 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 42281ac9 Mark McLoughlin
#include "qemu-char.h"
30 42281ac9 Mark McLoughlin
#include "qemu-common.h"
31 2f792016 Markus Armbruster
#include "qemu-error.h"
32 42281ac9 Mark McLoughlin
#include "qemu-option.h"
33 42281ac9 Mark McLoughlin
#include "qemu_socket.h"
34 42281ac9 Mark McLoughlin
35 42281ac9 Mark McLoughlin
typedef struct NetSocketState {
36 564f63e3 Mark McLoughlin
    VLANClientState nc;
37 42281ac9 Mark McLoughlin
    int fd;
38 42281ac9 Mark McLoughlin
    int state; /* 0 = getting length, 1 = getting data */
39 42281ac9 Mark McLoughlin
    unsigned int index;
40 42281ac9 Mark McLoughlin
    unsigned int packet_len;
41 42281ac9 Mark McLoughlin
    uint8_t buf[4096];
42 42281ac9 Mark McLoughlin
    struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */
43 42281ac9 Mark McLoughlin
} NetSocketState;
44 42281ac9 Mark McLoughlin
45 42281ac9 Mark McLoughlin
typedef struct NetSocketListenState {
46 42281ac9 Mark McLoughlin
    VLANState *vlan;
47 42281ac9 Mark McLoughlin
    char *model;
48 42281ac9 Mark McLoughlin
    char *name;
49 42281ac9 Mark McLoughlin
    int fd;
50 42281ac9 Mark McLoughlin
} NetSocketListenState;
51 42281ac9 Mark McLoughlin
52 42281ac9 Mark McLoughlin
/* XXX: we consider we can send the whole packet without blocking */
53 564f63e3 Mark McLoughlin
static ssize_t net_socket_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
54 42281ac9 Mark McLoughlin
{
55 564f63e3 Mark McLoughlin
    NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
56 42281ac9 Mark McLoughlin
    uint32_t len;
57 42281ac9 Mark McLoughlin
    len = htonl(size);
58 42281ac9 Mark McLoughlin
59 42281ac9 Mark McLoughlin
    send_all(s->fd, (const uint8_t *)&len, sizeof(len));
60 42281ac9 Mark McLoughlin
    return send_all(s->fd, buf, size);
61 42281ac9 Mark McLoughlin
}
62 42281ac9 Mark McLoughlin
63 564f63e3 Mark McLoughlin
static ssize_t net_socket_receive_dgram(VLANClientState *nc, const uint8_t *buf, size_t size)
64 42281ac9 Mark McLoughlin
{
65 564f63e3 Mark McLoughlin
    NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
66 42281ac9 Mark McLoughlin
67 42281ac9 Mark McLoughlin
    return sendto(s->fd, (const void *)buf, size, 0,
68 42281ac9 Mark McLoughlin
                  (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst));
69 42281ac9 Mark McLoughlin
}
70 42281ac9 Mark McLoughlin
71 42281ac9 Mark McLoughlin
static void net_socket_send(void *opaque)
72 42281ac9 Mark McLoughlin
{
73 42281ac9 Mark McLoughlin
    NetSocketState *s = opaque;
74 42281ac9 Mark McLoughlin
    int size, err;
75 42281ac9 Mark McLoughlin
    unsigned l;
76 42281ac9 Mark McLoughlin
    uint8_t buf1[4096];
77 42281ac9 Mark McLoughlin
    const uint8_t *buf;
78 42281ac9 Mark McLoughlin
79 42281ac9 Mark McLoughlin
    size = recv(s->fd, (void *)buf1, sizeof(buf1), 0);
80 42281ac9 Mark McLoughlin
    if (size < 0) {
81 42281ac9 Mark McLoughlin
        err = socket_error();
82 42281ac9 Mark McLoughlin
        if (err != EWOULDBLOCK)
83 42281ac9 Mark McLoughlin
            goto eoc;
84 42281ac9 Mark McLoughlin
    } else if (size == 0) {
85 42281ac9 Mark McLoughlin
        /* end of connection */
86 42281ac9 Mark McLoughlin
    eoc:
87 42281ac9 Mark McLoughlin
        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
88 42281ac9 Mark McLoughlin
        closesocket(s->fd);
89 42281ac9 Mark McLoughlin
        return;
90 42281ac9 Mark McLoughlin
    }
91 42281ac9 Mark McLoughlin
    buf = buf1;
92 42281ac9 Mark McLoughlin
    while (size > 0) {
93 42281ac9 Mark McLoughlin
        /* reassemble a packet from the network */
94 42281ac9 Mark McLoughlin
        switch(s->state) {
95 42281ac9 Mark McLoughlin
        case 0:
96 42281ac9 Mark McLoughlin
            l = 4 - s->index;
97 42281ac9 Mark McLoughlin
            if (l > size)
98 42281ac9 Mark McLoughlin
                l = size;
99 42281ac9 Mark McLoughlin
            memcpy(s->buf + s->index, buf, l);
100 42281ac9 Mark McLoughlin
            buf += l;
101 42281ac9 Mark McLoughlin
            size -= l;
102 42281ac9 Mark McLoughlin
            s->index += l;
103 42281ac9 Mark McLoughlin
            if (s->index == 4) {
104 42281ac9 Mark McLoughlin
                /* got length */
105 42281ac9 Mark McLoughlin
                s->packet_len = ntohl(*(uint32_t *)s->buf);
106 42281ac9 Mark McLoughlin
                s->index = 0;
107 42281ac9 Mark McLoughlin
                s->state = 1;
108 42281ac9 Mark McLoughlin
            }
109 42281ac9 Mark McLoughlin
            break;
110 42281ac9 Mark McLoughlin
        case 1:
111 42281ac9 Mark McLoughlin
            l = s->packet_len - s->index;
112 42281ac9 Mark McLoughlin
            if (l > size)
113 42281ac9 Mark McLoughlin
                l = size;
114 42281ac9 Mark McLoughlin
            if (s->index + l <= sizeof(s->buf)) {
115 42281ac9 Mark McLoughlin
                memcpy(s->buf + s->index, buf, l);
116 42281ac9 Mark McLoughlin
            } else {
117 42281ac9 Mark McLoughlin
                fprintf(stderr, "serious error: oversized packet received,"
118 42281ac9 Mark McLoughlin
                    "connection terminated.\n");
119 42281ac9 Mark McLoughlin
                s->state = 0;
120 42281ac9 Mark McLoughlin
                goto eoc;
121 42281ac9 Mark McLoughlin
            }
122 42281ac9 Mark McLoughlin
123 42281ac9 Mark McLoughlin
            s->index += l;
124 42281ac9 Mark McLoughlin
            buf += l;
125 42281ac9 Mark McLoughlin
            size -= l;
126 42281ac9 Mark McLoughlin
            if (s->index >= s->packet_len) {
127 564f63e3 Mark McLoughlin
                qemu_send_packet(&s->nc, s->buf, s->packet_len);
128 42281ac9 Mark McLoughlin
                s->index = 0;
129 42281ac9 Mark McLoughlin
                s->state = 0;
130 42281ac9 Mark McLoughlin
            }
131 42281ac9 Mark McLoughlin
            break;
132 42281ac9 Mark McLoughlin
        }
133 42281ac9 Mark McLoughlin
    }
134 42281ac9 Mark McLoughlin
}
135 42281ac9 Mark McLoughlin
136 42281ac9 Mark McLoughlin
static void net_socket_send_dgram(void *opaque)
137 42281ac9 Mark McLoughlin
{
138 42281ac9 Mark McLoughlin
    NetSocketState *s = opaque;
139 42281ac9 Mark McLoughlin
    int size;
140 42281ac9 Mark McLoughlin
141 42281ac9 Mark McLoughlin
    size = recv(s->fd, (void *)s->buf, sizeof(s->buf), 0);
142 42281ac9 Mark McLoughlin
    if (size < 0)
143 42281ac9 Mark McLoughlin
        return;
144 42281ac9 Mark McLoughlin
    if (size == 0) {
145 42281ac9 Mark McLoughlin
        /* end of connection */
146 42281ac9 Mark McLoughlin
        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
147 42281ac9 Mark McLoughlin
        return;
148 42281ac9 Mark McLoughlin
    }
149 564f63e3 Mark McLoughlin
    qemu_send_packet(&s->nc, s->buf, size);
150 42281ac9 Mark McLoughlin
}
151 42281ac9 Mark McLoughlin
152 42281ac9 Mark McLoughlin
static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
153 42281ac9 Mark McLoughlin
{
154 42281ac9 Mark McLoughlin
    struct ip_mreq imr;
155 42281ac9 Mark McLoughlin
    int fd;
156 42281ac9 Mark McLoughlin
    int val, ret;
157 42281ac9 Mark McLoughlin
    if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) {
158 42281ac9 Mark McLoughlin
        fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n",
159 42281ac9 Mark McLoughlin
                inet_ntoa(mcastaddr->sin_addr),
160 42281ac9 Mark McLoughlin
                (int)ntohl(mcastaddr->sin_addr.s_addr));
161 42281ac9 Mark McLoughlin
        return -1;
162 42281ac9 Mark McLoughlin
163 42281ac9 Mark McLoughlin
    }
164 40ff6d7e Kevin Wolf
    fd = qemu_socket(PF_INET, SOCK_DGRAM, 0);
165 42281ac9 Mark McLoughlin
    if (fd < 0) {
166 42281ac9 Mark McLoughlin
        perror("socket(PF_INET, SOCK_DGRAM)");
167 42281ac9 Mark McLoughlin
        return -1;
168 42281ac9 Mark McLoughlin
    }
169 42281ac9 Mark McLoughlin
170 42281ac9 Mark McLoughlin
    val = 1;
171 42281ac9 Mark McLoughlin
    ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
172 42281ac9 Mark McLoughlin
                   (const char *)&val, sizeof(val));
173 42281ac9 Mark McLoughlin
    if (ret < 0) {
174 42281ac9 Mark McLoughlin
        perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
175 42281ac9 Mark McLoughlin
        goto fail;
176 42281ac9 Mark McLoughlin
    }
177 42281ac9 Mark McLoughlin
178 42281ac9 Mark McLoughlin
    ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr));
179 42281ac9 Mark McLoughlin
    if (ret < 0) {
180 42281ac9 Mark McLoughlin
        perror("bind");
181 42281ac9 Mark McLoughlin
        goto fail;
182 42281ac9 Mark McLoughlin
    }
183 42281ac9 Mark McLoughlin
184 42281ac9 Mark McLoughlin
    /* Add host to multicast group */
185 42281ac9 Mark McLoughlin
    imr.imr_multiaddr = mcastaddr->sin_addr;
186 42281ac9 Mark McLoughlin
    imr.imr_interface.s_addr = htonl(INADDR_ANY);
187 42281ac9 Mark McLoughlin
188 42281ac9 Mark McLoughlin
    ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
189 42281ac9 Mark McLoughlin
                     (const char *)&imr, sizeof(struct ip_mreq));
190 42281ac9 Mark McLoughlin
    if (ret < 0) {
191 42281ac9 Mark McLoughlin
        perror("setsockopt(IP_ADD_MEMBERSHIP)");
192 42281ac9 Mark McLoughlin
        goto fail;
193 42281ac9 Mark McLoughlin
    }
194 42281ac9 Mark McLoughlin
195 42281ac9 Mark McLoughlin
    /* Force mcast msgs to loopback (eg. several QEMUs in same host */
196 42281ac9 Mark McLoughlin
    val = 1;
197 42281ac9 Mark McLoughlin
    ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
198 42281ac9 Mark McLoughlin
                   (const char *)&val, sizeof(val));
199 42281ac9 Mark McLoughlin
    if (ret < 0) {
200 42281ac9 Mark McLoughlin
        perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
201 42281ac9 Mark McLoughlin
        goto fail;
202 42281ac9 Mark McLoughlin
    }
203 42281ac9 Mark McLoughlin
204 42281ac9 Mark McLoughlin
    socket_set_nonblock(fd);
205 42281ac9 Mark McLoughlin
    return fd;
206 42281ac9 Mark McLoughlin
fail:
207 42281ac9 Mark McLoughlin
    if (fd >= 0)
208 42281ac9 Mark McLoughlin
        closesocket(fd);
209 42281ac9 Mark McLoughlin
    return -1;
210 42281ac9 Mark McLoughlin
}
211 42281ac9 Mark McLoughlin
212 564f63e3 Mark McLoughlin
static void net_socket_cleanup(VLANClientState *nc)
213 42281ac9 Mark McLoughlin
{
214 564f63e3 Mark McLoughlin
    NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
215 42281ac9 Mark McLoughlin
    qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
216 42281ac9 Mark McLoughlin
    close(s->fd);
217 42281ac9 Mark McLoughlin
}
218 42281ac9 Mark McLoughlin
219 564f63e3 Mark McLoughlin
static NetClientInfo net_dgram_socket_info = {
220 564f63e3 Mark McLoughlin
    .type = NET_CLIENT_TYPE_SOCKET,
221 564f63e3 Mark McLoughlin
    .size = sizeof(NetSocketState),
222 564f63e3 Mark McLoughlin
    .receive = net_socket_receive_dgram,
223 564f63e3 Mark McLoughlin
    .cleanup = net_socket_cleanup,
224 564f63e3 Mark McLoughlin
};
225 564f63e3 Mark McLoughlin
226 42281ac9 Mark McLoughlin
static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan,
227 42281ac9 Mark McLoughlin
                                                const char *model,
228 42281ac9 Mark McLoughlin
                                                const char *name,
229 42281ac9 Mark McLoughlin
                                                int fd, int is_connected)
230 42281ac9 Mark McLoughlin
{
231 42281ac9 Mark McLoughlin
    struct sockaddr_in saddr;
232 42281ac9 Mark McLoughlin
    int newfd;
233 42281ac9 Mark McLoughlin
    socklen_t saddr_len;
234 564f63e3 Mark McLoughlin
    VLANClientState *nc;
235 42281ac9 Mark McLoughlin
    NetSocketState *s;
236 42281ac9 Mark McLoughlin
237 42281ac9 Mark McLoughlin
    /* fd passed: multicast: "learn" dgram_dst address from bound address and save it
238 42281ac9 Mark McLoughlin
     * Because this may be "shared" socket from a "master" process, datagrams would be recv()
239 42281ac9 Mark McLoughlin
     * by ONLY ONE process: we must "clone" this dgram socket --jjo
240 42281ac9 Mark McLoughlin
     */
241 42281ac9 Mark McLoughlin
242 42281ac9 Mark McLoughlin
    if (is_connected) {
243 42281ac9 Mark McLoughlin
        if (getsockname(fd, (struct sockaddr *) &saddr, &saddr_len) == 0) {
244 42281ac9 Mark McLoughlin
            /* must be bound */
245 42281ac9 Mark McLoughlin
            if (saddr.sin_addr.s_addr==0) {
246 42281ac9 Mark McLoughlin
                fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, cannot setup multicast dst addr\n",
247 42281ac9 Mark McLoughlin
                        fd);
248 42281ac9 Mark McLoughlin
                return NULL;
249 42281ac9 Mark McLoughlin
            }
250 42281ac9 Mark McLoughlin
            /* clone dgram socket */
251 42281ac9 Mark McLoughlin
            newfd = net_socket_mcast_create(&saddr);
252 42281ac9 Mark McLoughlin
            if (newfd < 0) {
253 42281ac9 Mark McLoughlin
                /* error already reported by net_socket_mcast_create() */
254 42281ac9 Mark McLoughlin
                close(fd);
255 42281ac9 Mark McLoughlin
                return NULL;
256 42281ac9 Mark McLoughlin
            }
257 42281ac9 Mark McLoughlin
            /* clone newfd to fd, close newfd */
258 42281ac9 Mark McLoughlin
            dup2(newfd, fd);
259 42281ac9 Mark McLoughlin
            close(newfd);
260 42281ac9 Mark McLoughlin
261 42281ac9 Mark McLoughlin
        } else {
262 42281ac9 Mark McLoughlin
            fprintf(stderr, "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n",
263 42281ac9 Mark McLoughlin
                    fd, strerror(errno));
264 42281ac9 Mark McLoughlin
            return NULL;
265 42281ac9 Mark McLoughlin
        }
266 42281ac9 Mark McLoughlin
    }
267 42281ac9 Mark McLoughlin
268 564f63e3 Mark McLoughlin
    nc = qemu_new_net_client(&net_dgram_socket_info, vlan, NULL, model, name);
269 564f63e3 Mark McLoughlin
270 564f63e3 Mark McLoughlin
    snprintf(nc->info_str, sizeof(nc->info_str),
271 564f63e3 Mark McLoughlin
            "socket: fd=%d (%s mcast=%s:%d)",
272 564f63e3 Mark McLoughlin
            fd, is_connected ? "cloned" : "",
273 564f63e3 Mark McLoughlin
            inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
274 564f63e3 Mark McLoughlin
275 564f63e3 Mark McLoughlin
    s = DO_UPCAST(NetSocketState, nc, nc);
276 564f63e3 Mark McLoughlin
277 42281ac9 Mark McLoughlin
    s->fd = fd;
278 42281ac9 Mark McLoughlin
279 42281ac9 Mark McLoughlin
    qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s);
280 42281ac9 Mark McLoughlin
281 42281ac9 Mark McLoughlin
    /* mcast: save bound address as dst */
282 42281ac9 Mark McLoughlin
    if (is_connected) s->dgram_dst=saddr;
283 42281ac9 Mark McLoughlin
284 42281ac9 Mark McLoughlin
    return s;
285 42281ac9 Mark McLoughlin
}
286 42281ac9 Mark McLoughlin
287 42281ac9 Mark McLoughlin
static void net_socket_connect(void *opaque)
288 42281ac9 Mark McLoughlin
{
289 42281ac9 Mark McLoughlin
    NetSocketState *s = opaque;
290 42281ac9 Mark McLoughlin
    qemu_set_fd_handler(s->fd, net_socket_send, NULL, s);
291 42281ac9 Mark McLoughlin
}
292 42281ac9 Mark McLoughlin
293 564f63e3 Mark McLoughlin
static NetClientInfo net_socket_info = {
294 564f63e3 Mark McLoughlin
    .type = NET_CLIENT_TYPE_SOCKET,
295 564f63e3 Mark McLoughlin
    .size = sizeof(NetSocketState),
296 564f63e3 Mark McLoughlin
    .receive = net_socket_receive,
297 564f63e3 Mark McLoughlin
    .cleanup = net_socket_cleanup,
298 564f63e3 Mark McLoughlin
};
299 564f63e3 Mark McLoughlin
300 42281ac9 Mark McLoughlin
static NetSocketState *net_socket_fd_init_stream(VLANState *vlan,
301 42281ac9 Mark McLoughlin
                                                 const char *model,
302 42281ac9 Mark McLoughlin
                                                 const char *name,
303 42281ac9 Mark McLoughlin
                                                 int fd, int is_connected)
304 42281ac9 Mark McLoughlin
{
305 564f63e3 Mark McLoughlin
    VLANClientState *nc;
306 42281ac9 Mark McLoughlin
    NetSocketState *s;
307 564f63e3 Mark McLoughlin
308 564f63e3 Mark McLoughlin
    nc = qemu_new_net_client(&net_socket_info, vlan, NULL, model, name);
309 564f63e3 Mark McLoughlin
310 564f63e3 Mark McLoughlin
    snprintf(nc->info_str, sizeof(nc->info_str), "socket: fd=%d", fd);
311 564f63e3 Mark McLoughlin
312 564f63e3 Mark McLoughlin
    s = DO_UPCAST(NetSocketState, nc, nc);
313 564f63e3 Mark McLoughlin
314 42281ac9 Mark McLoughlin
    s->fd = fd;
315 564f63e3 Mark McLoughlin
316 42281ac9 Mark McLoughlin
    if (is_connected) {
317 42281ac9 Mark McLoughlin
        net_socket_connect(s);
318 42281ac9 Mark McLoughlin
    } else {
319 42281ac9 Mark McLoughlin
        qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s);
320 42281ac9 Mark McLoughlin
    }
321 42281ac9 Mark McLoughlin
    return s;
322 42281ac9 Mark McLoughlin
}
323 42281ac9 Mark McLoughlin
324 42281ac9 Mark McLoughlin
static NetSocketState *net_socket_fd_init(VLANState *vlan,
325 42281ac9 Mark McLoughlin
                                          const char *model, const char *name,
326 42281ac9 Mark McLoughlin
                                          int fd, int is_connected)
327 42281ac9 Mark McLoughlin
{
328 42281ac9 Mark McLoughlin
    int so_type = -1, optlen=sizeof(so_type);
329 42281ac9 Mark McLoughlin
330 42281ac9 Mark McLoughlin
    if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type,
331 42281ac9 Mark McLoughlin
        (socklen_t *)&optlen)< 0) {
332 42281ac9 Mark McLoughlin
        fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n", fd);
333 42281ac9 Mark McLoughlin
        return NULL;
334 42281ac9 Mark McLoughlin
    }
335 42281ac9 Mark McLoughlin
    switch(so_type) {
336 42281ac9 Mark McLoughlin
    case SOCK_DGRAM:
337 42281ac9 Mark McLoughlin
        return net_socket_fd_init_dgram(vlan, model, name, fd, is_connected);
338 42281ac9 Mark McLoughlin
    case SOCK_STREAM:
339 42281ac9 Mark McLoughlin
        return net_socket_fd_init_stream(vlan, model, name, fd, is_connected);
340 42281ac9 Mark McLoughlin
    default:
341 42281ac9 Mark McLoughlin
        /* who knows ... this could be a eg. a pty, do warn and continue as stream */
342 42281ac9 Mark McLoughlin
        fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd);
343 42281ac9 Mark McLoughlin
        return net_socket_fd_init_stream(vlan, model, name, fd, is_connected);
344 42281ac9 Mark McLoughlin
    }
345 42281ac9 Mark McLoughlin
    return NULL;
346 42281ac9 Mark McLoughlin
}
347 42281ac9 Mark McLoughlin
348 42281ac9 Mark McLoughlin
static void net_socket_accept(void *opaque)
349 42281ac9 Mark McLoughlin
{
350 42281ac9 Mark McLoughlin
    NetSocketListenState *s = opaque;
351 42281ac9 Mark McLoughlin
    NetSocketState *s1;
352 42281ac9 Mark McLoughlin
    struct sockaddr_in saddr;
353 42281ac9 Mark McLoughlin
    socklen_t len;
354 42281ac9 Mark McLoughlin
    int fd;
355 42281ac9 Mark McLoughlin
356 42281ac9 Mark McLoughlin
    for(;;) {
357 42281ac9 Mark McLoughlin
        len = sizeof(saddr);
358 40ff6d7e Kevin Wolf
        fd = qemu_accept(s->fd, (struct sockaddr *)&saddr, &len);
359 42281ac9 Mark McLoughlin
        if (fd < 0 && errno != EINTR) {
360 42281ac9 Mark McLoughlin
            return;
361 42281ac9 Mark McLoughlin
        } else if (fd >= 0) {
362 42281ac9 Mark McLoughlin
            break;
363 42281ac9 Mark McLoughlin
        }
364 42281ac9 Mark McLoughlin
    }
365 42281ac9 Mark McLoughlin
    s1 = net_socket_fd_init(s->vlan, s->model, s->name, fd, 1);
366 42281ac9 Mark McLoughlin
    if (!s1) {
367 42281ac9 Mark McLoughlin
        closesocket(fd);
368 42281ac9 Mark McLoughlin
    } else {
369 564f63e3 Mark McLoughlin
        snprintf(s1->nc.info_str, sizeof(s1->nc.info_str),
370 42281ac9 Mark McLoughlin
                 "socket: connection from %s:%d",
371 42281ac9 Mark McLoughlin
                 inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
372 42281ac9 Mark McLoughlin
    }
373 42281ac9 Mark McLoughlin
}
374 42281ac9 Mark McLoughlin
375 42281ac9 Mark McLoughlin
static int net_socket_listen_init(VLANState *vlan,
376 42281ac9 Mark McLoughlin
                                  const char *model,
377 42281ac9 Mark McLoughlin
                                  const char *name,
378 42281ac9 Mark McLoughlin
                                  const char *host_str)
379 42281ac9 Mark McLoughlin
{
380 42281ac9 Mark McLoughlin
    NetSocketListenState *s;
381 42281ac9 Mark McLoughlin
    int fd, val, ret;
382 42281ac9 Mark McLoughlin
    struct sockaddr_in saddr;
383 42281ac9 Mark McLoughlin
384 42281ac9 Mark McLoughlin
    if (parse_host_port(&saddr, host_str) < 0)
385 42281ac9 Mark McLoughlin
        return -1;
386 42281ac9 Mark McLoughlin
387 42281ac9 Mark McLoughlin
    s = qemu_mallocz(sizeof(NetSocketListenState));
388 42281ac9 Mark McLoughlin
389 40ff6d7e Kevin Wolf
    fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
390 42281ac9 Mark McLoughlin
    if (fd < 0) {
391 42281ac9 Mark McLoughlin
        perror("socket");
392 42281ac9 Mark McLoughlin
        return -1;
393 42281ac9 Mark McLoughlin
    }
394 42281ac9 Mark McLoughlin
    socket_set_nonblock(fd);
395 42281ac9 Mark McLoughlin
396 42281ac9 Mark McLoughlin
    /* allow fast reuse */
397 42281ac9 Mark McLoughlin
    val = 1;
398 42281ac9 Mark McLoughlin
    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
399 42281ac9 Mark McLoughlin
400 42281ac9 Mark McLoughlin
    ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
401 42281ac9 Mark McLoughlin
    if (ret < 0) {
402 42281ac9 Mark McLoughlin
        perror("bind");
403 42281ac9 Mark McLoughlin
        return -1;
404 42281ac9 Mark McLoughlin
    }
405 42281ac9 Mark McLoughlin
    ret = listen(fd, 0);
406 42281ac9 Mark McLoughlin
    if (ret < 0) {
407 42281ac9 Mark McLoughlin
        perror("listen");
408 42281ac9 Mark McLoughlin
        return -1;
409 42281ac9 Mark McLoughlin
    }
410 42281ac9 Mark McLoughlin
    s->vlan = vlan;
411 42281ac9 Mark McLoughlin
    s->model = qemu_strdup(model);
412 42281ac9 Mark McLoughlin
    s->name = name ? qemu_strdup(name) : NULL;
413 42281ac9 Mark McLoughlin
    s->fd = fd;
414 42281ac9 Mark McLoughlin
    qemu_set_fd_handler(fd, net_socket_accept, NULL, s);
415 42281ac9 Mark McLoughlin
    return 0;
416 42281ac9 Mark McLoughlin
}
417 42281ac9 Mark McLoughlin
418 42281ac9 Mark McLoughlin
static int net_socket_connect_init(VLANState *vlan,
419 42281ac9 Mark McLoughlin
                                   const char *model,
420 42281ac9 Mark McLoughlin
                                   const char *name,
421 42281ac9 Mark McLoughlin
                                   const char *host_str)
422 42281ac9 Mark McLoughlin
{
423 42281ac9 Mark McLoughlin
    NetSocketState *s;
424 42281ac9 Mark McLoughlin
    int fd, connected, ret, err;
425 42281ac9 Mark McLoughlin
    struct sockaddr_in saddr;
426 42281ac9 Mark McLoughlin
427 42281ac9 Mark McLoughlin
    if (parse_host_port(&saddr, host_str) < 0)
428 42281ac9 Mark McLoughlin
        return -1;
429 42281ac9 Mark McLoughlin
430 40ff6d7e Kevin Wolf
    fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
431 42281ac9 Mark McLoughlin
    if (fd < 0) {
432 42281ac9 Mark McLoughlin
        perror("socket");
433 42281ac9 Mark McLoughlin
        return -1;
434 42281ac9 Mark McLoughlin
    }
435 42281ac9 Mark McLoughlin
    socket_set_nonblock(fd);
436 42281ac9 Mark McLoughlin
437 42281ac9 Mark McLoughlin
    connected = 0;
438 42281ac9 Mark McLoughlin
    for(;;) {
439 42281ac9 Mark McLoughlin
        ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
440 42281ac9 Mark McLoughlin
        if (ret < 0) {
441 42281ac9 Mark McLoughlin
            err = socket_error();
442 42281ac9 Mark McLoughlin
            if (err == EINTR || err == EWOULDBLOCK) {
443 42281ac9 Mark McLoughlin
            } else if (err == EINPROGRESS) {
444 42281ac9 Mark McLoughlin
                break;
445 42281ac9 Mark McLoughlin
#ifdef _WIN32
446 42281ac9 Mark McLoughlin
            } else if (err == WSAEALREADY) {
447 42281ac9 Mark McLoughlin
                break;
448 42281ac9 Mark McLoughlin
#endif
449 42281ac9 Mark McLoughlin
            } else {
450 42281ac9 Mark McLoughlin
                perror("connect");
451 42281ac9 Mark McLoughlin
                closesocket(fd);
452 42281ac9 Mark McLoughlin
                return -1;
453 42281ac9 Mark McLoughlin
            }
454 42281ac9 Mark McLoughlin
        } else {
455 42281ac9 Mark McLoughlin
            connected = 1;
456 42281ac9 Mark McLoughlin
            break;
457 42281ac9 Mark McLoughlin
        }
458 42281ac9 Mark McLoughlin
    }
459 42281ac9 Mark McLoughlin
    s = net_socket_fd_init(vlan, model, name, fd, connected);
460 42281ac9 Mark McLoughlin
    if (!s)
461 42281ac9 Mark McLoughlin
        return -1;
462 564f63e3 Mark McLoughlin
    snprintf(s->nc.info_str, sizeof(s->nc.info_str),
463 42281ac9 Mark McLoughlin
             "socket: connect to %s:%d",
464 42281ac9 Mark McLoughlin
             inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
465 42281ac9 Mark McLoughlin
    return 0;
466 42281ac9 Mark McLoughlin
}
467 42281ac9 Mark McLoughlin
468 42281ac9 Mark McLoughlin
static int net_socket_mcast_init(VLANState *vlan,
469 42281ac9 Mark McLoughlin
                                 const char *model,
470 42281ac9 Mark McLoughlin
                                 const char *name,
471 42281ac9 Mark McLoughlin
                                 const char *host_str)
472 42281ac9 Mark McLoughlin
{
473 42281ac9 Mark McLoughlin
    NetSocketState *s;
474 42281ac9 Mark McLoughlin
    int fd;
475 42281ac9 Mark McLoughlin
    struct sockaddr_in saddr;
476 42281ac9 Mark McLoughlin
477 42281ac9 Mark McLoughlin
    if (parse_host_port(&saddr, host_str) < 0)
478 42281ac9 Mark McLoughlin
        return -1;
479 42281ac9 Mark McLoughlin
480 42281ac9 Mark McLoughlin
481 42281ac9 Mark McLoughlin
    fd = net_socket_mcast_create(&saddr);
482 42281ac9 Mark McLoughlin
    if (fd < 0)
483 42281ac9 Mark McLoughlin
        return -1;
484 42281ac9 Mark McLoughlin
485 42281ac9 Mark McLoughlin
    s = net_socket_fd_init(vlan, model, name, fd, 0);
486 42281ac9 Mark McLoughlin
    if (!s)
487 42281ac9 Mark McLoughlin
        return -1;
488 42281ac9 Mark McLoughlin
489 42281ac9 Mark McLoughlin
    s->dgram_dst = saddr;
490 42281ac9 Mark McLoughlin
491 564f63e3 Mark McLoughlin
    snprintf(s->nc.info_str, sizeof(s->nc.info_str),
492 42281ac9 Mark McLoughlin
             "socket: mcast=%s:%d",
493 42281ac9 Mark McLoughlin
             inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
494 42281ac9 Mark McLoughlin
    return 0;
495 42281ac9 Mark McLoughlin
496 42281ac9 Mark McLoughlin
}
497 42281ac9 Mark McLoughlin
498 42281ac9 Mark McLoughlin
int net_init_socket(QemuOpts *opts,
499 42281ac9 Mark McLoughlin
                    Monitor *mon,
500 42281ac9 Mark McLoughlin
                    const char *name,
501 42281ac9 Mark McLoughlin
                    VLANState *vlan)
502 42281ac9 Mark McLoughlin
{
503 42281ac9 Mark McLoughlin
    if (qemu_opt_get(opts, "fd")) {
504 42281ac9 Mark McLoughlin
        int fd;
505 42281ac9 Mark McLoughlin
506 42281ac9 Mark McLoughlin
        if (qemu_opt_get(opts, "listen") ||
507 42281ac9 Mark McLoughlin
            qemu_opt_get(opts, "connect") ||
508 42281ac9 Mark McLoughlin
            qemu_opt_get(opts, "mcast")) {
509 1ecda02b Markus Armbruster
            error_report("listen=, connect= and mcast= is invalid with fd=");
510 42281ac9 Mark McLoughlin
            return -1;
511 42281ac9 Mark McLoughlin
        }
512 42281ac9 Mark McLoughlin
513 42281ac9 Mark McLoughlin
        fd = net_handle_fd_param(mon, qemu_opt_get(opts, "fd"));
514 42281ac9 Mark McLoughlin
        if (fd == -1) {
515 42281ac9 Mark McLoughlin
            return -1;
516 42281ac9 Mark McLoughlin
        }
517 42281ac9 Mark McLoughlin
518 42281ac9 Mark McLoughlin
        if (!net_socket_fd_init(vlan, "socket", name, fd, 1)) {
519 42281ac9 Mark McLoughlin
            close(fd);
520 42281ac9 Mark McLoughlin
            return -1;
521 42281ac9 Mark McLoughlin
        }
522 42281ac9 Mark McLoughlin
    } else if (qemu_opt_get(opts, "listen")) {
523 42281ac9 Mark McLoughlin
        const char *listen;
524 42281ac9 Mark McLoughlin
525 42281ac9 Mark McLoughlin
        if (qemu_opt_get(opts, "fd") ||
526 42281ac9 Mark McLoughlin
            qemu_opt_get(opts, "connect") ||
527 42281ac9 Mark McLoughlin
            qemu_opt_get(opts, "mcast")) {
528 1ecda02b Markus Armbruster
            error_report("fd=, connect= and mcast= is invalid with listen=");
529 42281ac9 Mark McLoughlin
            return -1;
530 42281ac9 Mark McLoughlin
        }
531 42281ac9 Mark McLoughlin
532 42281ac9 Mark McLoughlin
        listen = qemu_opt_get(opts, "listen");
533 42281ac9 Mark McLoughlin
534 42281ac9 Mark McLoughlin
        if (net_socket_listen_init(vlan, "socket", name, listen) == -1) {
535 42281ac9 Mark McLoughlin
            return -1;
536 42281ac9 Mark McLoughlin
        }
537 42281ac9 Mark McLoughlin
    } else if (qemu_opt_get(opts, "connect")) {
538 42281ac9 Mark McLoughlin
        const char *connect;
539 42281ac9 Mark McLoughlin
540 42281ac9 Mark McLoughlin
        if (qemu_opt_get(opts, "fd") ||
541 42281ac9 Mark McLoughlin
            qemu_opt_get(opts, "listen") ||
542 42281ac9 Mark McLoughlin
            qemu_opt_get(opts, "mcast")) {
543 1ecda02b Markus Armbruster
            error_report("fd=, listen= and mcast= is invalid with connect=");
544 42281ac9 Mark McLoughlin
            return -1;
545 42281ac9 Mark McLoughlin
        }
546 42281ac9 Mark McLoughlin
547 42281ac9 Mark McLoughlin
        connect = qemu_opt_get(opts, "connect");
548 42281ac9 Mark McLoughlin
549 42281ac9 Mark McLoughlin
        if (net_socket_connect_init(vlan, "socket", name, connect) == -1) {
550 42281ac9 Mark McLoughlin
            return -1;
551 42281ac9 Mark McLoughlin
        }
552 42281ac9 Mark McLoughlin
    } else if (qemu_opt_get(opts, "mcast")) {
553 42281ac9 Mark McLoughlin
        const char *mcast;
554 42281ac9 Mark McLoughlin
555 42281ac9 Mark McLoughlin
        if (qemu_opt_get(opts, "fd") ||
556 42281ac9 Mark McLoughlin
            qemu_opt_get(opts, "connect") ||
557 42281ac9 Mark McLoughlin
            qemu_opt_get(opts, "listen")) {
558 1ecda02b Markus Armbruster
            error_report("fd=, connect= and listen= is invalid with mcast=");
559 42281ac9 Mark McLoughlin
            return -1;
560 42281ac9 Mark McLoughlin
        }
561 42281ac9 Mark McLoughlin
562 42281ac9 Mark McLoughlin
        mcast = qemu_opt_get(opts, "mcast");
563 42281ac9 Mark McLoughlin
564 42281ac9 Mark McLoughlin
        if (net_socket_mcast_init(vlan, "socket", name, mcast) == -1) {
565 42281ac9 Mark McLoughlin
            return -1;
566 42281ac9 Mark McLoughlin
        }
567 42281ac9 Mark McLoughlin
    } else {
568 1ecda02b Markus Armbruster
        error_report("-socket requires fd=, listen=, connect= or mcast=");
569 42281ac9 Mark McLoughlin
        return -1;
570 42281ac9 Mark McLoughlin
    }
571 42281ac9 Mark McLoughlin
572 42281ac9 Mark McLoughlin
    return 0;
573 42281ac9 Mark McLoughlin
}