Statistics
| Branch: | Revision:

root / net / socket.c @ 7267c094

History | View | Annotate | Download (17.2 kB)

1
/*
2
 * QEMU System Emulator
3
 *
4
 * Copyright (c) 2003-2008 Fabrice Bellard
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24
#include "net/socket.h"
25

    
26
#include "config-host.h"
27

    
28
#include "net.h"
29
#include "qemu-char.h"
30
#include "qemu-common.h"
31
#include "qemu-error.h"
32
#include "qemu-option.h"
33
#include "qemu_socket.h"
34

    
35
typedef struct NetSocketState {
36
    VLANClientState nc;
37
    int fd;
38
    int state; /* 0 = getting length, 1 = getting data */
39
    unsigned int index;
40
    unsigned int packet_len;
41
    uint8_t buf[4096];
42
    struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */
43
} NetSocketState;
44

    
45
typedef struct NetSocketListenState {
46
    VLANState *vlan;
47
    char *model;
48
    char *name;
49
    int fd;
50
} NetSocketListenState;
51

    
52
/* XXX: we consider we can send the whole packet without blocking */
53
static ssize_t net_socket_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
54
{
55
    NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
56
    uint32_t len;
57
    len = htonl(size);
58

    
59
    send_all(s->fd, (const uint8_t *)&len, sizeof(len));
60
    return send_all(s->fd, buf, size);
61
}
62

    
63
static ssize_t net_socket_receive_dgram(VLANClientState *nc, const uint8_t *buf, size_t size)
64
{
65
    NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
66

    
67
    return sendto(s->fd, (const void *)buf, size, 0,
68
                  (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst));
69
}
70

    
71
static void net_socket_send(void *opaque)
72
{
73
    NetSocketState *s = opaque;
74
    int size, err;
75
    unsigned l;
76
    uint8_t buf1[4096];
77
    const uint8_t *buf;
78

    
79
    size = qemu_recv(s->fd, buf1, sizeof(buf1), 0);
80
    if (size < 0) {
81
        err = socket_error();
82
        if (err != EWOULDBLOCK)
83
            goto eoc;
84
    } else if (size == 0) {
85
        /* end of connection */
86
    eoc:
87
        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
88
        closesocket(s->fd);
89
        return;
90
    }
91
    buf = buf1;
92
    while (size > 0) {
93
        /* reassemble a packet from the network */
94
        switch(s->state) {
95
        case 0:
96
            l = 4 - s->index;
97
            if (l > size)
98
                l = size;
99
            memcpy(s->buf + s->index, buf, l);
100
            buf += l;
101
            size -= l;
102
            s->index += l;
103
            if (s->index == 4) {
104
                /* got length */
105
                s->packet_len = ntohl(*(uint32_t *)s->buf);
106
                s->index = 0;
107
                s->state = 1;
108
            }
109
            break;
110
        case 1:
111
            l = s->packet_len - s->index;
112
            if (l > size)
113
                l = size;
114
            if (s->index + l <= sizeof(s->buf)) {
115
                memcpy(s->buf + s->index, buf, l);
116
            } else {
117
                fprintf(stderr, "serious error: oversized packet received,"
118
                    "connection terminated.\n");
119
                s->state = 0;
120
                goto eoc;
121
            }
122

    
123
            s->index += l;
124
            buf += l;
125
            size -= l;
126
            if (s->index >= s->packet_len) {
127
                qemu_send_packet(&s->nc, s->buf, s->packet_len);
128
                s->index = 0;
129
                s->state = 0;
130
            }
131
            break;
132
        }
133
    }
134
}
135

    
136
static void net_socket_send_dgram(void *opaque)
137
{
138
    NetSocketState *s = opaque;
139
    int size;
140

    
141
    size = qemu_recv(s->fd, s->buf, sizeof(s->buf), 0);
142
    if (size < 0)
143
        return;
144
    if (size == 0) {
145
        /* end of connection */
146
        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
147
        return;
148
    }
149
    qemu_send_packet(&s->nc, s->buf, size);
150
}
151

    
152
static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr *localaddr)
153
{
154
    struct ip_mreq imr;
155
    int fd;
156
    int val, ret;
157
#ifdef __OpenBSD__
158
    unsigned char loop;
159
#else
160
    int loop;
161
#endif
162

    
163
    if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) {
164
        fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n",
165
                inet_ntoa(mcastaddr->sin_addr),
166
                (int)ntohl(mcastaddr->sin_addr.s_addr));
167
        return -1;
168

    
169
    }
170
    fd = qemu_socket(PF_INET, SOCK_DGRAM, 0);
171
    if (fd < 0) {
172
        perror("socket(PF_INET, SOCK_DGRAM)");
173
        return -1;
174
    }
175

    
176
    val = 1;
177
    ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
178
                   (const char *)&val, sizeof(val));
179
    if (ret < 0) {
180
        perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
181
        goto fail;
182
    }
183

    
184
    ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr));
185
    if (ret < 0) {
186
        perror("bind");
187
        goto fail;
188
    }
189

    
190
    /* Add host to multicast group */
191
    imr.imr_multiaddr = mcastaddr->sin_addr;
192
    if (localaddr) {
193
        imr.imr_interface = *localaddr;
194
    } else {
195
        imr.imr_interface.s_addr = htonl(INADDR_ANY);
196
    }
197

    
198
    ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
199
                     (const char *)&imr, sizeof(struct ip_mreq));
200
    if (ret < 0) {
201
        perror("setsockopt(IP_ADD_MEMBERSHIP)");
202
        goto fail;
203
    }
204

    
205
    /* Force mcast msgs to loopback (eg. several QEMUs in same host */
206
    loop = 1;
207
    ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
208
                   (const char *)&loop, sizeof(loop));
209
    if (ret < 0) {
210
        perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
211
        goto fail;
212
    }
213

    
214
    /* If a bind address is given, only send packets from that address */
215
    if (localaddr != NULL) {
216
        ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
217
                         (const char *)localaddr, sizeof(*localaddr));
218
        if (ret < 0) {
219
            perror("setsockopt(IP_MULTICAST_IF)");
220
            goto fail;
221
        }
222
    }
223

    
224
    socket_set_nonblock(fd);
225
    return fd;
226
fail:
227
    if (fd >= 0)
228
        closesocket(fd);
229
    return -1;
230
}
231

    
232
static void net_socket_cleanup(VLANClientState *nc)
233
{
234
    NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
235
    qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
236
    close(s->fd);
237
}
238

    
239
static NetClientInfo net_dgram_socket_info = {
240
    .type = NET_CLIENT_TYPE_SOCKET,
241
    .size = sizeof(NetSocketState),
242
    .receive = net_socket_receive_dgram,
243
    .cleanup = net_socket_cleanup,
244
};
245

    
246
static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan,
247
                                                const char *model,
248
                                                const char *name,
249
                                                int fd, int is_connected)
250
{
251
    struct sockaddr_in saddr;
252
    int newfd;
253
    socklen_t saddr_len;
254
    VLANClientState *nc;
255
    NetSocketState *s;
256

    
257
    /* fd passed: multicast: "learn" dgram_dst address from bound address and save it
258
     * Because this may be "shared" socket from a "master" process, datagrams would be recv()
259
     * by ONLY ONE process: we must "clone" this dgram socket --jjo
260
     */
261

    
262
    if (is_connected) {
263
        if (getsockname(fd, (struct sockaddr *) &saddr, &saddr_len) == 0) {
264
            /* must be bound */
265
            if (saddr.sin_addr.s_addr==0) {
266
                fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, cannot setup multicast dst addr\n",
267
                        fd);
268
                return NULL;
269
            }
270
            /* clone dgram socket */
271
            newfd = net_socket_mcast_create(&saddr, NULL);
272
            if (newfd < 0) {
273
                /* error already reported by net_socket_mcast_create() */
274
                close(fd);
275
                return NULL;
276
            }
277
            /* clone newfd to fd, close newfd */
278
            dup2(newfd, fd);
279
            close(newfd);
280

    
281
        } else {
282
            fprintf(stderr, "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n",
283
                    fd, strerror(errno));
284
            return NULL;
285
        }
286
    }
287

    
288
    nc = qemu_new_net_client(&net_dgram_socket_info, vlan, NULL, model, name);
289

    
290
    snprintf(nc->info_str, sizeof(nc->info_str),
291
            "socket: fd=%d (%s mcast=%s:%d)",
292
            fd, is_connected ? "cloned" : "",
293
            inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
294

    
295
    s = DO_UPCAST(NetSocketState, nc, nc);
296

    
297
    s->fd = fd;
298

    
299
    qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s);
300

    
301
    /* mcast: save bound address as dst */
302
    if (is_connected) s->dgram_dst=saddr;
303

    
304
    return s;
305
}
306

    
307
static void net_socket_connect(void *opaque)
308
{
309
    NetSocketState *s = opaque;
310
    qemu_set_fd_handler(s->fd, net_socket_send, NULL, s);
311
}
312

    
313
static NetClientInfo net_socket_info = {
314
    .type = NET_CLIENT_TYPE_SOCKET,
315
    .size = sizeof(NetSocketState),
316
    .receive = net_socket_receive,
317
    .cleanup = net_socket_cleanup,
318
};
319

    
320
static NetSocketState *net_socket_fd_init_stream(VLANState *vlan,
321
                                                 const char *model,
322
                                                 const char *name,
323
                                                 int fd, int is_connected)
324
{
325
    VLANClientState *nc;
326
    NetSocketState *s;
327

    
328
    nc = qemu_new_net_client(&net_socket_info, vlan, NULL, model, name);
329

    
330
    snprintf(nc->info_str, sizeof(nc->info_str), "socket: fd=%d", fd);
331

    
332
    s = DO_UPCAST(NetSocketState, nc, nc);
333

    
334
    s->fd = fd;
335

    
336
    if (is_connected) {
337
        net_socket_connect(s);
338
    } else {
339
        qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s);
340
    }
341
    return s;
342
}
343

    
344
static NetSocketState *net_socket_fd_init(VLANState *vlan,
345
                                          const char *model, const char *name,
346
                                          int fd, int is_connected)
347
{
348
    int so_type = -1, optlen=sizeof(so_type);
349

    
350
    if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type,
351
        (socklen_t *)&optlen)< 0) {
352
        fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n", fd);
353
        return NULL;
354
    }
355
    switch(so_type) {
356
    case SOCK_DGRAM:
357
        return net_socket_fd_init_dgram(vlan, model, name, fd, is_connected);
358
    case SOCK_STREAM:
359
        return net_socket_fd_init_stream(vlan, model, name, fd, is_connected);
360
    default:
361
        /* who knows ... this could be a eg. a pty, do warn and continue as stream */
362
        fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd);
363
        return net_socket_fd_init_stream(vlan, model, name, fd, is_connected);
364
    }
365
    return NULL;
366
}
367

    
368
static void net_socket_accept(void *opaque)
369
{
370
    NetSocketListenState *s = opaque;
371
    NetSocketState *s1;
372
    struct sockaddr_in saddr;
373
    socklen_t len;
374
    int fd;
375

    
376
    for(;;) {
377
        len = sizeof(saddr);
378
        fd = qemu_accept(s->fd, (struct sockaddr *)&saddr, &len);
379
        if (fd < 0 && errno != EINTR) {
380
            return;
381
        } else if (fd >= 0) {
382
            break;
383
        }
384
    }
385
    s1 = net_socket_fd_init(s->vlan, s->model, s->name, fd, 1);
386
    if (!s1) {
387
        closesocket(fd);
388
    } else {
389
        snprintf(s1->nc.info_str, sizeof(s1->nc.info_str),
390
                 "socket: connection from %s:%d",
391
                 inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
392
    }
393
}
394

    
395
static int net_socket_listen_init(VLANState *vlan,
396
                                  const char *model,
397
                                  const char *name,
398
                                  const char *host_str)
399
{
400
    NetSocketListenState *s;
401
    int fd, val, ret;
402
    struct sockaddr_in saddr;
403

    
404
    if (parse_host_port(&saddr, host_str) < 0)
405
        return -1;
406

    
407
    s = g_malloc0(sizeof(NetSocketListenState));
408

    
409
    fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
410
    if (fd < 0) {
411
        perror("socket");
412
        return -1;
413
    }
414
    socket_set_nonblock(fd);
415

    
416
    /* allow fast reuse */
417
    val = 1;
418
    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
419

    
420
    ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
421
    if (ret < 0) {
422
        perror("bind");
423
        return -1;
424
    }
425
    ret = listen(fd, 0);
426
    if (ret < 0) {
427
        perror("listen");
428
        return -1;
429
    }
430
    s->vlan = vlan;
431
    s->model = g_strdup(model);
432
    s->name = name ? g_strdup(name) : NULL;
433
    s->fd = fd;
434
    qemu_set_fd_handler(fd, net_socket_accept, NULL, s);
435
    return 0;
436
}
437

    
438
static int net_socket_connect_init(VLANState *vlan,
439
                                   const char *model,
440
                                   const char *name,
441
                                   const char *host_str)
442
{
443
    NetSocketState *s;
444
    int fd, connected, ret, err;
445
    struct sockaddr_in saddr;
446

    
447
    if (parse_host_port(&saddr, host_str) < 0)
448
        return -1;
449

    
450
    fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
451
    if (fd < 0) {
452
        perror("socket");
453
        return -1;
454
    }
455
    socket_set_nonblock(fd);
456

    
457
    connected = 0;
458
    for(;;) {
459
        ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
460
        if (ret < 0) {
461
            err = socket_error();
462
            if (err == EINTR || err == EWOULDBLOCK) {
463
            } else if (err == EINPROGRESS) {
464
                break;
465
#ifdef _WIN32
466
            } else if (err == WSAEALREADY || err == WSAEINVAL) {
467
                break;
468
#endif
469
            } else {
470
                perror("connect");
471
                closesocket(fd);
472
                return -1;
473
            }
474
        } else {
475
            connected = 1;
476
            break;
477
        }
478
    }
479
    s = net_socket_fd_init(vlan, model, name, fd, connected);
480
    if (!s)
481
        return -1;
482
    snprintf(s->nc.info_str, sizeof(s->nc.info_str),
483
             "socket: connect to %s:%d",
484
             inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
485
    return 0;
486
}
487

    
488
static int net_socket_mcast_init(VLANState *vlan,
489
                                 const char *model,
490
                                 const char *name,
491
                                 const char *host_str,
492
                                 const char *localaddr_str)
493
{
494
    NetSocketState *s;
495
    int fd;
496
    struct sockaddr_in saddr;
497
    struct in_addr localaddr, *param_localaddr;
498

    
499
    if (parse_host_port(&saddr, host_str) < 0)
500
        return -1;
501

    
502
    if (localaddr_str != NULL) {
503
        if (inet_aton(localaddr_str, &localaddr) == 0)
504
            return -1;
505
        param_localaddr = &localaddr;
506
    } else {
507
        param_localaddr = NULL;
508
    }
509

    
510
    fd = net_socket_mcast_create(&saddr, param_localaddr);
511
    if (fd < 0)
512
        return -1;
513

    
514
    s = net_socket_fd_init(vlan, model, name, fd, 0);
515
    if (!s)
516
        return -1;
517

    
518
    s->dgram_dst = saddr;
519

    
520
    snprintf(s->nc.info_str, sizeof(s->nc.info_str),
521
             "socket: mcast=%s:%d",
522
             inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
523
    return 0;
524

    
525
}
526

    
527
int net_init_socket(QemuOpts *opts,
528
                    Monitor *mon,
529
                    const char *name,
530
                    VLANState *vlan)
531
{
532
    if (qemu_opt_get(opts, "fd")) {
533
        int fd;
534

    
535
        if (qemu_opt_get(opts, "listen") ||
536
            qemu_opt_get(opts, "connect") ||
537
            qemu_opt_get(opts, "mcast") ||
538
            qemu_opt_get(opts, "localaddr")) {
539
            error_report("listen=, connect=, mcast= and localaddr= is invalid with fd=");
540
            return -1;
541
        }
542

    
543
        fd = net_handle_fd_param(mon, qemu_opt_get(opts, "fd"));
544
        if (fd == -1) {
545
            return -1;
546
        }
547

    
548
        if (!net_socket_fd_init(vlan, "socket", name, fd, 1)) {
549
            close(fd);
550
            return -1;
551
        }
552
    } else if (qemu_opt_get(opts, "listen")) {
553
        const char *listen;
554

    
555
        if (qemu_opt_get(opts, "fd") ||
556
            qemu_opt_get(opts, "connect") ||
557
            qemu_opt_get(opts, "mcast") ||
558
            qemu_opt_get(opts, "localaddr")) {
559
            error_report("fd=, connect=, mcast= and localaddr= is invalid with listen=");
560
            return -1;
561
        }
562

    
563
        listen = qemu_opt_get(opts, "listen");
564

    
565
        if (net_socket_listen_init(vlan, "socket", name, listen) == -1) {
566
            return -1;
567
        }
568
    } else if (qemu_opt_get(opts, "connect")) {
569
        const char *connect;
570

    
571
        if (qemu_opt_get(opts, "fd") ||
572
            qemu_opt_get(opts, "listen") ||
573
            qemu_opt_get(opts, "mcast") ||
574
            qemu_opt_get(opts, "localaddr")) {
575
            error_report("fd=, listen=, mcast= and localaddr= is invalid with connect=");
576
            return -1;
577
        }
578

    
579
        connect = qemu_opt_get(opts, "connect");
580

    
581
        if (net_socket_connect_init(vlan, "socket", name, connect) == -1) {
582
            return -1;
583
        }
584
    } else if (qemu_opt_get(opts, "mcast")) {
585
        const char *mcast, *localaddr;
586

    
587
        if (qemu_opt_get(opts, "fd") ||
588
            qemu_opt_get(opts, "connect") ||
589
            qemu_opt_get(opts, "listen")) {
590
            error_report("fd=, connect= and listen= is invalid with mcast=");
591
            return -1;
592
        }
593

    
594
        mcast = qemu_opt_get(opts, "mcast");
595
        localaddr = qemu_opt_get(opts, "localaddr");
596

    
597
        if (net_socket_mcast_init(vlan, "socket", name, mcast, localaddr) == -1) {
598
            return -1;
599
        }
600
    } else {
601
        error_report("-socket requires fd=, listen=, connect= or mcast=");
602
        return -1;
603
    }
604

    
605
    return 0;
606
}