qemu/net/socket.c
<<
>>
Prefs
   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
  35typedef 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
  45typedef 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 */
  53static 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
  63static 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
  71static 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
 136static 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
 152static 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;
 206fail:
 207    if (fd >= 0)
 208        closesocket(fd);
 209    return -1;
 210}
 211
 212static 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
 219static 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
 226static 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
 287static 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
 293static 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
 300static 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
 324static 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
 348static 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
 375static 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
 418static 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
 468static 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
 498int 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}
 574