Statistics
| Branch: | Revision:

root / net / socket.c @ c7eb1f02

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 = recv(s->fd, (void *)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 = recv(s->fd, (void *)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
    if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) {
158
        fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n",
159
                inet_ntoa(mcastaddr->sin_addr),
160
                (int)ntohl(mcastaddr->sin_addr.s_addr));
161
        return -1;
162

    
163
    }
164
    fd = qemu_socket(PF_INET, SOCK_DGRAM, 0);
165
    if (fd < 0) {
166
        perror("socket(PF_INET, SOCK_DGRAM)");
167
        return -1;
168
    }
169

    
170
    val = 1;
171
    ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
172
                   (const char *)&val, sizeof(val));
173
    if (ret < 0) {
174
        perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
175
        goto fail;
176
    }
177

    
178
    ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr));
179
    if (ret < 0) {
180
        perror("bind");
181
        goto fail;
182
    }
183

    
184
    /* Add host to multicast group */
185
    imr.imr_multiaddr = mcastaddr->sin_addr;
186
    if (localaddr) {
187
        imr.imr_interface = *localaddr;
188
    } else {
189
        imr.imr_interface.s_addr = htonl(INADDR_ANY);
190
    }
191

    
192
    ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
193
                     (const char *)&imr, sizeof(struct ip_mreq));
194
    if (ret < 0) {
195
        perror("setsockopt(IP_ADD_MEMBERSHIP)");
196
        goto fail;
197
    }
198

    
199
    /* Force mcast msgs to loopback (eg. several QEMUs in same host */
200
    val = 1;
201
    ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
202
                   (const char *)&val, sizeof(val));
203
    if (ret < 0) {
204
        perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
205
        goto fail;
206
    }
207

    
208
    /* If a bind address is given, only send packets from that address */
209
    if (localaddr != NULL) {
210
        ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
211
                         (const char *)localaddr, sizeof(*localaddr));
212
        if (ret < 0) {
213
            perror("setsockopt(IP_MULTICAST_IF)");
214
            goto fail;
215
        }
216
    }
217

    
218
    socket_set_nonblock(fd);
219
    return fd;
220
fail:
221
    if (fd >= 0)
222
        closesocket(fd);
223
    return -1;
224
}
225

    
226
static void net_socket_cleanup(VLANClientState *nc)
227
{
228
    NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
229
    qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
230
    close(s->fd);
231
}
232

    
233
static NetClientInfo net_dgram_socket_info = {
234
    .type = NET_CLIENT_TYPE_SOCKET,
235
    .size = sizeof(NetSocketState),
236
    .receive = net_socket_receive_dgram,
237
    .cleanup = net_socket_cleanup,
238
};
239

    
240
static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan,
241
                                                const char *model,
242
                                                const char *name,
243
                                                int fd, int is_connected)
244
{
245
    struct sockaddr_in saddr;
246
    int newfd;
247
    socklen_t saddr_len;
248
    VLANClientState *nc;
249
    NetSocketState *s;
250

    
251
    /* fd passed: multicast: "learn" dgram_dst address from bound address and save it
252
     * Because this may be "shared" socket from a "master" process, datagrams would be recv()
253
     * by ONLY ONE process: we must "clone" this dgram socket --jjo
254
     */
255

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

    
275
        } else {
276
            fprintf(stderr, "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n",
277
                    fd, strerror(errno));
278
            return NULL;
279
        }
280
    }
281

    
282
    nc = qemu_new_net_client(&net_dgram_socket_info, vlan, NULL, model, name);
283

    
284
    snprintf(nc->info_str, sizeof(nc->info_str),
285
            "socket: fd=%d (%s mcast=%s:%d)",
286
            fd, is_connected ? "cloned" : "",
287
            inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
288

    
289
    s = DO_UPCAST(NetSocketState, nc, nc);
290

    
291
    s->fd = fd;
292

    
293
    qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s);
294

    
295
    /* mcast: save bound address as dst */
296
    if (is_connected) s->dgram_dst=saddr;
297

    
298
    return s;
299
}
300

    
301
static void net_socket_connect(void *opaque)
302
{
303
    NetSocketState *s = opaque;
304
    qemu_set_fd_handler(s->fd, net_socket_send, NULL, s);
305
}
306

    
307
static NetClientInfo net_socket_info = {
308
    .type = NET_CLIENT_TYPE_SOCKET,
309
    .size = sizeof(NetSocketState),
310
    .receive = net_socket_receive,
311
    .cleanup = net_socket_cleanup,
312
};
313

    
314
static NetSocketState *net_socket_fd_init_stream(VLANState *vlan,
315
                                                 const char *model,
316
                                                 const char *name,
317
                                                 int fd, int is_connected)
318
{
319
    VLANClientState *nc;
320
    NetSocketState *s;
321

    
322
    nc = qemu_new_net_client(&net_socket_info, vlan, NULL, model, name);
323

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

    
326
    s = DO_UPCAST(NetSocketState, nc, nc);
327

    
328
    s->fd = fd;
329

    
330
    if (is_connected) {
331
        net_socket_connect(s);
332
    } else {
333
        qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s);
334
    }
335
    return s;
336
}
337

    
338
static NetSocketState *net_socket_fd_init(VLANState *vlan,
339
                                          const char *model, const char *name,
340
                                          int fd, int is_connected)
341
{
342
    int so_type = -1, optlen=sizeof(so_type);
343

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

    
362
static void net_socket_accept(void *opaque)
363
{
364
    NetSocketListenState *s = opaque;
365
    NetSocketState *s1;
366
    struct sockaddr_in saddr;
367
    socklen_t len;
368
    int fd;
369

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

    
389
static int net_socket_listen_init(VLANState *vlan,
390
                                  const char *model,
391
                                  const char *name,
392
                                  const char *host_str)
393
{
394
    NetSocketListenState *s;
395
    int fd, val, ret;
396
    struct sockaddr_in saddr;
397

    
398
    if (parse_host_port(&saddr, host_str) < 0)
399
        return -1;
400

    
401
    s = qemu_mallocz(sizeof(NetSocketListenState));
402

    
403
    fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
404
    if (fd < 0) {
405
        perror("socket");
406
        return -1;
407
    }
408
    socket_set_nonblock(fd);
409

    
410
    /* allow fast reuse */
411
    val = 1;
412
    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
413

    
414
    ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
415
    if (ret < 0) {
416
        perror("bind");
417
        return -1;
418
    }
419
    ret = listen(fd, 0);
420
    if (ret < 0) {
421
        perror("listen");
422
        return -1;
423
    }
424
    s->vlan = vlan;
425
    s->model = qemu_strdup(model);
426
    s->name = name ? qemu_strdup(name) : NULL;
427
    s->fd = fd;
428
    qemu_set_fd_handler(fd, net_socket_accept, NULL, s);
429
    return 0;
430
}
431

    
432
static int net_socket_connect_init(VLANState *vlan,
433
                                   const char *model,
434
                                   const char *name,
435
                                   const char *host_str)
436
{
437
    NetSocketState *s;
438
    int fd, connected, ret, err;
439
    struct sockaddr_in saddr;
440

    
441
    if (parse_host_port(&saddr, host_str) < 0)
442
        return -1;
443

    
444
    fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
445
    if (fd < 0) {
446
        perror("socket");
447
        return -1;
448
    }
449
    socket_set_nonblock(fd);
450

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

    
482
static int net_socket_mcast_init(VLANState *vlan,
483
                                 const char *model,
484
                                 const char *name,
485
                                 const char *host_str,
486
                                 const char *localaddr_str)
487
{
488
    NetSocketState *s;
489
    int fd;
490
    struct sockaddr_in saddr;
491
    struct in_addr localaddr, *param_localaddr;
492

    
493
    if (parse_host_port(&saddr, host_str) < 0)
494
        return -1;
495

    
496
    if (localaddr_str != NULL) {
497
        if (inet_aton(localaddr_str, &localaddr) == 0)
498
            return -1;
499
        param_localaddr = &localaddr;
500
    } else {
501
        param_localaddr = NULL;
502
    }
503

    
504
    fd = net_socket_mcast_create(&saddr, param_localaddr);
505
    if (fd < 0)
506
        return -1;
507

    
508
    s = net_socket_fd_init(vlan, model, name, fd, 0);
509
    if (!s)
510
        return -1;
511

    
512
    s->dgram_dst = saddr;
513

    
514
    snprintf(s->nc.info_str, sizeof(s->nc.info_str),
515
             "socket: mcast=%s:%d",
516
             inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
517
    return 0;
518

    
519
}
520

    
521
int net_init_socket(QemuOpts *opts,
522
                    Monitor *mon,
523
                    const char *name,
524
                    VLANState *vlan)
525
{
526
    if (qemu_opt_get(opts, "fd")) {
527
        int fd;
528

    
529
        if (qemu_opt_get(opts, "listen") ||
530
            qemu_opt_get(opts, "connect") ||
531
            qemu_opt_get(opts, "mcast") ||
532
            qemu_opt_get(opts, "localaddr")) {
533
            error_report("listen=, connect=, mcast= and localaddr= is invalid with fd=\n");
534
            return -1;
535
        }
536

    
537
        fd = net_handle_fd_param(mon, qemu_opt_get(opts, "fd"));
538
        if (fd == -1) {
539
            return -1;
540
        }
541

    
542
        if (!net_socket_fd_init(vlan, "socket", name, fd, 1)) {
543
            close(fd);
544
            return -1;
545
        }
546
    } else if (qemu_opt_get(opts, "listen")) {
547
        const char *listen;
548

    
549
        if (qemu_opt_get(opts, "fd") ||
550
            qemu_opt_get(opts, "connect") ||
551
            qemu_opt_get(opts, "mcast") ||
552
            qemu_opt_get(opts, "localaddr")) {
553
            error_report("fd=, connect=, mcast= and localaddr= is invalid with listen=\n");
554
            return -1;
555
        }
556

    
557
        listen = qemu_opt_get(opts, "listen");
558

    
559
        if (net_socket_listen_init(vlan, "socket", name, listen) == -1) {
560
            return -1;
561
        }
562
    } else if (qemu_opt_get(opts, "connect")) {
563
        const char *connect;
564

    
565
        if (qemu_opt_get(opts, "fd") ||
566
            qemu_opt_get(opts, "listen") ||
567
            qemu_opt_get(opts, "mcast") ||
568
            qemu_opt_get(opts, "localaddr")) {
569
            error_report("fd=, listen=, mcast= and localaddr= is invalid with connect=\n");
570
            return -1;
571
        }
572

    
573
        connect = qemu_opt_get(opts, "connect");
574

    
575
        if (net_socket_connect_init(vlan, "socket", name, connect) == -1) {
576
            return -1;
577
        }
578
    } else if (qemu_opt_get(opts, "mcast")) {
579
        const char *mcast, *localaddr;
580

    
581
        if (qemu_opt_get(opts, "fd") ||
582
            qemu_opt_get(opts, "connect") ||
583
            qemu_opt_get(opts, "listen")) {
584
            error_report("fd=, connect= and listen= is invalid with mcast=");
585
            return -1;
586
        }
587

    
588
        mcast = qemu_opt_get(opts, "mcast");
589
        localaddr = qemu_opt_get(opts, "localaddr");
590

    
591
        if (net_socket_mcast_init(vlan, "socket", name, mcast, localaddr) == -1) {
592
            return -1;
593
        }
594
    } else {
595
        error_report("-socket requires fd=, listen=, connect= or mcast=");
596
        return -1;
597
    }
598

    
599
    return 0;
600
}