Statistics
| Branch: | Revision:

root / net / socket.c @ a5fd2c34

History | View | Annotate | Download (16.1 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)
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
    imr.imr_interface.s_addr = htonl(INADDR_ANY);
187

    
188
    ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
189
                     (const char *)&imr, sizeof(struct ip_mreq));
190
    if (ret < 0) {
191
        perror("setsockopt(IP_ADD_MEMBERSHIP)");
192
        goto fail;
193
    }
194

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

    
204
    socket_set_nonblock(fd);
205
    return fd;
206
fail:
207
    if (fd >= 0)
208
        closesocket(fd);
209
    return -1;
210
}
211

    
212
static void net_socket_cleanup(VLANClientState *nc)
213
{
214
    NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
215
    qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
216
    close(s->fd);
217
}
218

    
219
static NetClientInfo net_dgram_socket_info = {
220
    .type = NET_CLIENT_TYPE_SOCKET,
221
    .size = sizeof(NetSocketState),
222
    .receive = net_socket_receive_dgram,
223
    .cleanup = net_socket_cleanup,
224
};
225

    
226
static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan,
227
                                                const char *model,
228
                                                const char *name,
229
                                                int fd, int is_connected)
230
{
231
    struct sockaddr_in saddr;
232
    int newfd;
233
    socklen_t saddr_len;
234
    VLANClientState *nc;
235
    NetSocketState *s;
236

    
237
    /* fd passed: multicast: "learn" dgram_dst address from bound address and save it
238
     * Because this may be "shared" socket from a "master" process, datagrams would be recv()
239
     * by ONLY ONE process: we must "clone" this dgram socket --jjo
240
     */
241

    
242
    if (is_connected) {
243
        if (getsockname(fd, (struct sockaddr *) &saddr, &saddr_len) == 0) {
244
            /* must be bound */
245
            if (saddr.sin_addr.s_addr==0) {
246
                fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, cannot setup multicast dst addr\n",
247
                        fd);
248
                return NULL;
249
            }
250
            /* clone dgram socket */
251
            newfd = net_socket_mcast_create(&saddr);
252
            if (newfd < 0) {
253
                /* error already reported by net_socket_mcast_create() */
254
                close(fd);
255
                return NULL;
256
            }
257
            /* clone newfd to fd, close newfd */
258
            dup2(newfd, fd);
259
            close(newfd);
260

    
261
        } else {
262
            fprintf(stderr, "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n",
263
                    fd, strerror(errno));
264
            return NULL;
265
        }
266
    }
267

    
268
    nc = qemu_new_net_client(&net_dgram_socket_info, vlan, NULL, model, name);
269

    
270
    snprintf(nc->info_str, sizeof(nc->info_str),
271
            "socket: fd=%d (%s mcast=%s:%d)",
272
            fd, is_connected ? "cloned" : "",
273
            inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
274

    
275
    s = DO_UPCAST(NetSocketState, nc, nc);
276

    
277
    s->fd = fd;
278

    
279
    qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s);
280

    
281
    /* mcast: save bound address as dst */
282
    if (is_connected) s->dgram_dst=saddr;
283

    
284
    return s;
285
}
286

    
287
static void net_socket_connect(void *opaque)
288
{
289
    NetSocketState *s = opaque;
290
    qemu_set_fd_handler(s->fd, net_socket_send, NULL, s);
291
}
292

    
293
static NetClientInfo net_socket_info = {
294
    .type = NET_CLIENT_TYPE_SOCKET,
295
    .size = sizeof(NetSocketState),
296
    .receive = net_socket_receive,
297
    .cleanup = net_socket_cleanup,
298
};
299

    
300
static NetSocketState *net_socket_fd_init_stream(VLANState *vlan,
301
                                                 const char *model,
302
                                                 const char *name,
303
                                                 int fd, int is_connected)
304
{
305
    VLANClientState *nc;
306
    NetSocketState *s;
307

    
308
    nc = qemu_new_net_client(&net_socket_info, vlan, NULL, model, name);
309

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

    
312
    s = DO_UPCAST(NetSocketState, nc, nc);
313

    
314
    s->fd = fd;
315

    
316
    if (is_connected) {
317
        net_socket_connect(s);
318
    } else {
319
        qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s);
320
    }
321
    return s;
322
}
323

    
324
static NetSocketState *net_socket_fd_init(VLANState *vlan,
325
                                          const char *model, const char *name,
326
                                          int fd, int is_connected)
327
{
328
    int so_type = -1, optlen=sizeof(so_type);
329

    
330
    if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type,
331
        (socklen_t *)&optlen)< 0) {
332
        fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n", fd);
333
        return NULL;
334
    }
335
    switch(so_type) {
336
    case SOCK_DGRAM:
337
        return net_socket_fd_init_dgram(vlan, model, name, fd, is_connected);
338
    case SOCK_STREAM:
339
        return net_socket_fd_init_stream(vlan, model, name, fd, is_connected);
340
    default:
341
        /* who knows ... this could be a eg. a pty, do warn and continue as stream */
342
        fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd);
343
        return net_socket_fd_init_stream(vlan, model, name, fd, is_connected);
344
    }
345
    return NULL;
346
}
347

    
348
static void net_socket_accept(void *opaque)
349
{
350
    NetSocketListenState *s = opaque;
351
    NetSocketState *s1;
352
    struct sockaddr_in saddr;
353
    socklen_t len;
354
    int fd;
355

    
356
    for(;;) {
357
        len = sizeof(saddr);
358
        fd = qemu_accept(s->fd, (struct sockaddr *)&saddr, &len);
359
        if (fd < 0 && errno != EINTR) {
360
            return;
361
        } else if (fd >= 0) {
362
            break;
363
        }
364
    }
365
    s1 = net_socket_fd_init(s->vlan, s->model, s->name, fd, 1);
366
    if (!s1) {
367
        closesocket(fd);
368
    } else {
369
        snprintf(s1->nc.info_str, sizeof(s1->nc.info_str),
370
                 "socket: connection from %s:%d",
371
                 inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
372
    }
373
}
374

    
375
static int net_socket_listen_init(VLANState *vlan,
376
                                  const char *model,
377
                                  const char *name,
378
                                  const char *host_str)
379
{
380
    NetSocketListenState *s;
381
    int fd, val, ret;
382
    struct sockaddr_in saddr;
383

    
384
    if (parse_host_port(&saddr, host_str) < 0)
385
        return -1;
386

    
387
    s = qemu_mallocz(sizeof(NetSocketListenState));
388

    
389
    fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
390
    if (fd < 0) {
391
        perror("socket");
392
        return -1;
393
    }
394
    socket_set_nonblock(fd);
395

    
396
    /* allow fast reuse */
397
    val = 1;
398
    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
399

    
400
    ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
401
    if (ret < 0) {
402
        perror("bind");
403
        return -1;
404
    }
405
    ret = listen(fd, 0);
406
    if (ret < 0) {
407
        perror("listen");
408
        return -1;
409
    }
410
    s->vlan = vlan;
411
    s->model = qemu_strdup(model);
412
    s->name = name ? qemu_strdup(name) : NULL;
413
    s->fd = fd;
414
    qemu_set_fd_handler(fd, net_socket_accept, NULL, s);
415
    return 0;
416
}
417

    
418
static int net_socket_connect_init(VLANState *vlan,
419
                                   const char *model,
420
                                   const char *name,
421
                                   const char *host_str)
422
{
423
    NetSocketState *s;
424
    int fd, connected, ret, err;
425
    struct sockaddr_in saddr;
426

    
427
    if (parse_host_port(&saddr, host_str) < 0)
428
        return -1;
429

    
430
    fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
431
    if (fd < 0) {
432
        perror("socket");
433
        return -1;
434
    }
435
    socket_set_nonblock(fd);
436

    
437
    connected = 0;
438
    for(;;) {
439
        ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
440
        if (ret < 0) {
441
            err = socket_error();
442
            if (err == EINTR || err == EWOULDBLOCK) {
443
            } else if (err == EINPROGRESS) {
444
                break;
445
#ifdef _WIN32
446
            } else if (err == WSAEALREADY) {
447
                break;
448
#endif
449
            } else {
450
                perror("connect");
451
                closesocket(fd);
452
                return -1;
453
            }
454
        } else {
455
            connected = 1;
456
            break;
457
        }
458
    }
459
    s = net_socket_fd_init(vlan, model, name, fd, connected);
460
    if (!s)
461
        return -1;
462
    snprintf(s->nc.info_str, sizeof(s->nc.info_str),
463
             "socket: connect to %s:%d",
464
             inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
465
    return 0;
466
}
467

    
468
static int net_socket_mcast_init(VLANState *vlan,
469
                                 const char *model,
470
                                 const char *name,
471
                                 const char *host_str)
472
{
473
    NetSocketState *s;
474
    int fd;
475
    struct sockaddr_in saddr;
476

    
477
    if (parse_host_port(&saddr, host_str) < 0)
478
        return -1;
479

    
480

    
481
    fd = net_socket_mcast_create(&saddr);
482
    if (fd < 0)
483
        return -1;
484

    
485
    s = net_socket_fd_init(vlan, model, name, fd, 0);
486
    if (!s)
487
        return -1;
488

    
489
    s->dgram_dst = saddr;
490

    
491
    snprintf(s->nc.info_str, sizeof(s->nc.info_str),
492
             "socket: mcast=%s:%d",
493
             inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
494
    return 0;
495

    
496
}
497

    
498
int net_init_socket(QemuOpts *opts,
499
                    Monitor *mon,
500
                    const char *name,
501
                    VLANState *vlan)
502
{
503
    if (qemu_opt_get(opts, "fd")) {
504
        int fd;
505

    
506
        if (qemu_opt_get(opts, "listen") ||
507
            qemu_opt_get(opts, "connect") ||
508
            qemu_opt_get(opts, "mcast")) {
509
            error_report("listen=, connect= and mcast= is invalid with fd=");
510
            return -1;
511
        }
512

    
513
        fd = net_handle_fd_param(mon, qemu_opt_get(opts, "fd"));
514
        if (fd == -1) {
515
            return -1;
516
        }
517

    
518
        if (!net_socket_fd_init(vlan, "socket", name, fd, 1)) {
519
            close(fd);
520
            return -1;
521
        }
522
    } else if (qemu_opt_get(opts, "listen")) {
523
        const char *listen;
524

    
525
        if (qemu_opt_get(opts, "fd") ||
526
            qemu_opt_get(opts, "connect") ||
527
            qemu_opt_get(opts, "mcast")) {
528
            error_report("fd=, connect= and mcast= is invalid with listen=");
529
            return -1;
530
        }
531

    
532
        listen = qemu_opt_get(opts, "listen");
533

    
534
        if (net_socket_listen_init(vlan, "socket", name, listen) == -1) {
535
            return -1;
536
        }
537
    } else if (qemu_opt_get(opts, "connect")) {
538
        const char *connect;
539

    
540
        if (qemu_opt_get(opts, "fd") ||
541
            qemu_opt_get(opts, "listen") ||
542
            qemu_opt_get(opts, "mcast")) {
543
            error_report("fd=, listen= and mcast= is invalid with connect=");
544
            return -1;
545
        }
546

    
547
        connect = qemu_opt_get(opts, "connect");
548

    
549
        if (net_socket_connect_init(vlan, "socket", name, connect) == -1) {
550
            return -1;
551
        }
552
    } else if (qemu_opt_get(opts, "mcast")) {
553
        const char *mcast;
554

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

    
562
        mcast = qemu_opt_get(opts, "mcast");
563

    
564
        if (net_socket_mcast_init(vlan, "socket", name, mcast) == -1) {
565
            return -1;
566
        }
567
    } else {
568
        error_report("-socket requires fd=, listen=, connect= or mcast=");
569
        return -1;
570
    }
571

    
572
    return 0;
573
}