142281ac9SMark McLoughlin /* 242281ac9SMark McLoughlin * QEMU System Emulator 342281ac9SMark McLoughlin * 442281ac9SMark McLoughlin * Copyright (c) 2003-2008 Fabrice Bellard 542281ac9SMark McLoughlin * 642281ac9SMark McLoughlin * Permission is hereby granted, free of charge, to any person obtaining a copy 742281ac9SMark McLoughlin * of this software and associated documentation files (the "Software"), to deal 842281ac9SMark McLoughlin * in the Software without restriction, including without limitation the rights 942281ac9SMark McLoughlin * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1042281ac9SMark McLoughlin * copies of the Software, and to permit persons to whom the Software is 1142281ac9SMark McLoughlin * furnished to do so, subject to the following conditions: 1242281ac9SMark McLoughlin * 1342281ac9SMark McLoughlin * The above copyright notice and this permission notice shall be included in 1442281ac9SMark McLoughlin * all copies or substantial portions of the Software. 1542281ac9SMark McLoughlin * 1642281ac9SMark McLoughlin * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1742281ac9SMark McLoughlin * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1842281ac9SMark McLoughlin * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1942281ac9SMark McLoughlin * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2042281ac9SMark McLoughlin * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2142281ac9SMark McLoughlin * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 2242281ac9SMark McLoughlin * THE SOFTWARE. 2342281ac9SMark McLoughlin */ 2442281ac9SMark McLoughlin #include "net/socket.h" 2542281ac9SMark McLoughlin 2642281ac9SMark McLoughlin #include "config-host.h" 2742281ac9SMark McLoughlin 2842281ac9SMark McLoughlin #include "net.h" 2942dcc547SLuiz Capitulino #include "monitor.h" 3042281ac9SMark McLoughlin #include "qemu-char.h" 3142281ac9SMark McLoughlin #include "qemu-common.h" 322f792016SMarkus Armbruster #include "qemu-error.h" 3342281ac9SMark McLoughlin #include "qemu-option.h" 3442281ac9SMark McLoughlin #include "qemu_socket.h" 3542281ac9SMark McLoughlin 3642281ac9SMark McLoughlin typedef struct NetSocketState { 37564f63e3SMark McLoughlin VLANClientState nc; 3842281ac9SMark McLoughlin int fd; 3942281ac9SMark McLoughlin int state; /* 0 = getting length, 1 = getting data */ 4042281ac9SMark McLoughlin unsigned int index; 4142281ac9SMark McLoughlin unsigned int packet_len; 4242281ac9SMark McLoughlin uint8_t buf[4096]; 4342281ac9SMark McLoughlin struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */ 4442281ac9SMark McLoughlin } NetSocketState; 4542281ac9SMark McLoughlin 4642281ac9SMark McLoughlin typedef struct NetSocketListenState { 4742281ac9SMark McLoughlin VLANState *vlan; 4842281ac9SMark McLoughlin char *model; 4942281ac9SMark McLoughlin char *name; 5042281ac9SMark McLoughlin int fd; 5142281ac9SMark McLoughlin } NetSocketListenState; 5242281ac9SMark McLoughlin 5342281ac9SMark McLoughlin /* XXX: we consider we can send the whole packet without blocking */ 54564f63e3SMark McLoughlin static ssize_t net_socket_receive(VLANClientState *nc, const uint8_t *buf, size_t size) 5542281ac9SMark McLoughlin { 56564f63e3SMark McLoughlin NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); 5742281ac9SMark McLoughlin uint32_t len; 5842281ac9SMark McLoughlin len = htonl(size); 5942281ac9SMark McLoughlin 6042281ac9SMark McLoughlin send_all(s->fd, (const uint8_t *)&len, sizeof(len)); 6142281ac9SMark McLoughlin return send_all(s->fd, buf, size); 6242281ac9SMark McLoughlin } 6342281ac9SMark McLoughlin 64564f63e3SMark McLoughlin static ssize_t net_socket_receive_dgram(VLANClientState *nc, const uint8_t *buf, size_t size) 6542281ac9SMark McLoughlin { 66564f63e3SMark McLoughlin NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); 6742281ac9SMark McLoughlin 6842281ac9SMark McLoughlin return sendto(s->fd, (const void *)buf, size, 0, 6942281ac9SMark McLoughlin (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst)); 7042281ac9SMark McLoughlin } 7142281ac9SMark McLoughlin 7242281ac9SMark McLoughlin static void net_socket_send(void *opaque) 7342281ac9SMark McLoughlin { 7442281ac9SMark McLoughlin NetSocketState *s = opaque; 7542281ac9SMark McLoughlin int size, err; 7642281ac9SMark McLoughlin unsigned l; 7742281ac9SMark McLoughlin uint8_t buf1[4096]; 7842281ac9SMark McLoughlin const uint8_t *buf; 7942281ac9SMark McLoughlin 8000aa0040SBlue Swirl size = qemu_recv(s->fd, buf1, sizeof(buf1), 0); 8142281ac9SMark McLoughlin if (size < 0) { 8242281ac9SMark McLoughlin err = socket_error(); 8342281ac9SMark McLoughlin if (err != EWOULDBLOCK) 8442281ac9SMark McLoughlin goto eoc; 8542281ac9SMark McLoughlin } else if (size == 0) { 8642281ac9SMark McLoughlin /* end of connection */ 8742281ac9SMark McLoughlin eoc: 8842281ac9SMark McLoughlin qemu_set_fd_handler(s->fd, NULL, NULL, NULL); 8942281ac9SMark McLoughlin closesocket(s->fd); 9042281ac9SMark McLoughlin return; 9142281ac9SMark McLoughlin } 9242281ac9SMark McLoughlin buf = buf1; 9342281ac9SMark McLoughlin while (size > 0) { 9442281ac9SMark McLoughlin /* reassemble a packet from the network */ 9542281ac9SMark McLoughlin switch(s->state) { 9642281ac9SMark McLoughlin case 0: 9742281ac9SMark McLoughlin l = 4 - s->index; 9842281ac9SMark McLoughlin if (l > size) 9942281ac9SMark McLoughlin l = size; 10042281ac9SMark McLoughlin memcpy(s->buf + s->index, buf, l); 10142281ac9SMark McLoughlin buf += l; 10242281ac9SMark McLoughlin size -= l; 10342281ac9SMark McLoughlin s->index += l; 10442281ac9SMark McLoughlin if (s->index == 4) { 10542281ac9SMark McLoughlin /* got length */ 10642281ac9SMark McLoughlin s->packet_len = ntohl(*(uint32_t *)s->buf); 10742281ac9SMark McLoughlin s->index = 0; 10842281ac9SMark McLoughlin s->state = 1; 10942281ac9SMark McLoughlin } 11042281ac9SMark McLoughlin break; 11142281ac9SMark McLoughlin case 1: 11242281ac9SMark McLoughlin l = s->packet_len - s->index; 11342281ac9SMark McLoughlin if (l > size) 11442281ac9SMark McLoughlin l = size; 11542281ac9SMark McLoughlin if (s->index + l <= sizeof(s->buf)) { 11642281ac9SMark McLoughlin memcpy(s->buf + s->index, buf, l); 11742281ac9SMark McLoughlin } else { 11842281ac9SMark McLoughlin fprintf(stderr, "serious error: oversized packet received," 11942281ac9SMark McLoughlin "connection terminated.\n"); 12042281ac9SMark McLoughlin s->state = 0; 12142281ac9SMark McLoughlin goto eoc; 12242281ac9SMark McLoughlin } 12342281ac9SMark McLoughlin 12442281ac9SMark McLoughlin s->index += l; 12542281ac9SMark McLoughlin buf += l; 12642281ac9SMark McLoughlin size -= l; 12742281ac9SMark McLoughlin if (s->index >= s->packet_len) { 128564f63e3SMark McLoughlin qemu_send_packet(&s->nc, s->buf, s->packet_len); 12942281ac9SMark McLoughlin s->index = 0; 13042281ac9SMark McLoughlin s->state = 0; 13142281ac9SMark McLoughlin } 13242281ac9SMark McLoughlin break; 13342281ac9SMark McLoughlin } 13442281ac9SMark McLoughlin } 13542281ac9SMark McLoughlin } 13642281ac9SMark McLoughlin 13742281ac9SMark McLoughlin static void net_socket_send_dgram(void *opaque) 13842281ac9SMark McLoughlin { 13942281ac9SMark McLoughlin NetSocketState *s = opaque; 14042281ac9SMark McLoughlin int size; 14142281ac9SMark McLoughlin 14200aa0040SBlue Swirl size = qemu_recv(s->fd, s->buf, sizeof(s->buf), 0); 14342281ac9SMark McLoughlin if (size < 0) 14442281ac9SMark McLoughlin return; 14542281ac9SMark McLoughlin if (size == 0) { 14642281ac9SMark McLoughlin /* end of connection */ 14742281ac9SMark McLoughlin qemu_set_fd_handler(s->fd, NULL, NULL, NULL); 14842281ac9SMark McLoughlin return; 14942281ac9SMark McLoughlin } 150564f63e3SMark McLoughlin qemu_send_packet(&s->nc, s->buf, size); 15142281ac9SMark McLoughlin } 15242281ac9SMark McLoughlin 1533a75e74cSMike Ryan static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr *localaddr) 15442281ac9SMark McLoughlin { 15542281ac9SMark McLoughlin struct ip_mreq imr; 15642281ac9SMark McLoughlin int fd; 15742281ac9SMark McLoughlin int val, ret; 15823ddf2bbSBrad #ifdef __OpenBSD__ 15923ddf2bbSBrad unsigned char loop; 16023ddf2bbSBrad #else 16123ddf2bbSBrad int loop; 16223ddf2bbSBrad #endif 16323ddf2bbSBrad 16442281ac9SMark McLoughlin if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) { 165842480d4SStefan Hajnoczi fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) " 166842480d4SStefan Hajnoczi "does not contain a multicast address\n", 16742281ac9SMark McLoughlin inet_ntoa(mcastaddr->sin_addr), 16842281ac9SMark McLoughlin (int)ntohl(mcastaddr->sin_addr.s_addr)); 16942281ac9SMark McLoughlin return -1; 17042281ac9SMark McLoughlin 17142281ac9SMark McLoughlin } 17240ff6d7eSKevin Wolf fd = qemu_socket(PF_INET, SOCK_DGRAM, 0); 17342281ac9SMark McLoughlin if (fd < 0) { 17442281ac9SMark McLoughlin perror("socket(PF_INET, SOCK_DGRAM)"); 17542281ac9SMark McLoughlin return -1; 17642281ac9SMark McLoughlin } 17742281ac9SMark McLoughlin 17842281ac9SMark McLoughlin val = 1; 17942281ac9SMark McLoughlin ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, 18042281ac9SMark McLoughlin (const char *)&val, sizeof(val)); 18142281ac9SMark McLoughlin if (ret < 0) { 18242281ac9SMark McLoughlin perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)"); 18342281ac9SMark McLoughlin goto fail; 18442281ac9SMark McLoughlin } 18542281ac9SMark McLoughlin 18642281ac9SMark McLoughlin ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr)); 18742281ac9SMark McLoughlin if (ret < 0) { 18842281ac9SMark McLoughlin perror("bind"); 18942281ac9SMark McLoughlin goto fail; 19042281ac9SMark McLoughlin } 19142281ac9SMark McLoughlin 19242281ac9SMark McLoughlin /* Add host to multicast group */ 19342281ac9SMark McLoughlin imr.imr_multiaddr = mcastaddr->sin_addr; 1943a75e74cSMike Ryan if (localaddr) { 1953a75e74cSMike Ryan imr.imr_interface = *localaddr; 1963a75e74cSMike Ryan } else { 19742281ac9SMark McLoughlin imr.imr_interface.s_addr = htonl(INADDR_ANY); 1983a75e74cSMike Ryan } 19942281ac9SMark McLoughlin 20042281ac9SMark McLoughlin ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, 20142281ac9SMark McLoughlin (const char *)&imr, sizeof(struct ip_mreq)); 20242281ac9SMark McLoughlin if (ret < 0) { 20342281ac9SMark McLoughlin perror("setsockopt(IP_ADD_MEMBERSHIP)"); 20442281ac9SMark McLoughlin goto fail; 20542281ac9SMark McLoughlin } 20642281ac9SMark McLoughlin 20742281ac9SMark McLoughlin /* Force mcast msgs to loopback (eg. several QEMUs in same host */ 20823ddf2bbSBrad loop = 1; 20942281ac9SMark McLoughlin ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, 21023ddf2bbSBrad (const char *)&loop, sizeof(loop)); 21142281ac9SMark McLoughlin if (ret < 0) { 21242281ac9SMark McLoughlin perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)"); 21342281ac9SMark McLoughlin goto fail; 21442281ac9SMark McLoughlin } 21542281ac9SMark McLoughlin 2163a75e74cSMike Ryan /* If a bind address is given, only send packets from that address */ 2173a75e74cSMike Ryan if (localaddr != NULL) { 2184d22c6c2SBlue Swirl ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, 2194d22c6c2SBlue Swirl (const char *)localaddr, sizeof(*localaddr)); 2203a75e74cSMike Ryan if (ret < 0) { 2213a75e74cSMike Ryan perror("setsockopt(IP_MULTICAST_IF)"); 2223a75e74cSMike Ryan goto fail; 2233a75e74cSMike Ryan } 2243a75e74cSMike Ryan } 2253a75e74cSMike Ryan 22642281ac9SMark McLoughlin socket_set_nonblock(fd); 22742281ac9SMark McLoughlin return fd; 22842281ac9SMark McLoughlin fail: 22942281ac9SMark McLoughlin if (fd >= 0) 23042281ac9SMark McLoughlin closesocket(fd); 23142281ac9SMark McLoughlin return -1; 23242281ac9SMark McLoughlin } 23342281ac9SMark McLoughlin 234564f63e3SMark McLoughlin static void net_socket_cleanup(VLANClientState *nc) 23542281ac9SMark McLoughlin { 236564f63e3SMark McLoughlin NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); 23742281ac9SMark McLoughlin qemu_set_fd_handler(s->fd, NULL, NULL, NULL); 23842281ac9SMark McLoughlin close(s->fd); 23942281ac9SMark McLoughlin } 24042281ac9SMark McLoughlin 241564f63e3SMark McLoughlin static NetClientInfo net_dgram_socket_info = { 2422be64a68SLaszlo Ersek .type = NET_CLIENT_OPTIONS_KIND_SOCKET, 243564f63e3SMark McLoughlin .size = sizeof(NetSocketState), 244564f63e3SMark McLoughlin .receive = net_socket_receive_dgram, 245564f63e3SMark McLoughlin .cleanup = net_socket_cleanup, 246564f63e3SMark McLoughlin }; 247564f63e3SMark McLoughlin 24842281ac9SMark McLoughlin static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, 24942281ac9SMark McLoughlin const char *model, 25042281ac9SMark McLoughlin const char *name, 25142281ac9SMark McLoughlin int fd, int is_connected) 25242281ac9SMark McLoughlin { 25342281ac9SMark McLoughlin struct sockaddr_in saddr; 25442281ac9SMark McLoughlin int newfd; 25542281ac9SMark McLoughlin socklen_t saddr_len; 256564f63e3SMark McLoughlin VLANClientState *nc; 25742281ac9SMark McLoughlin NetSocketState *s; 25842281ac9SMark McLoughlin 25942281ac9SMark McLoughlin /* fd passed: multicast: "learn" dgram_dst address from bound address and save it 26042281ac9SMark McLoughlin * Because this may be "shared" socket from a "master" process, datagrams would be recv() 26142281ac9SMark McLoughlin * by ONLY ONE process: we must "clone" this dgram socket --jjo 26242281ac9SMark McLoughlin */ 26342281ac9SMark McLoughlin 26442281ac9SMark McLoughlin if (is_connected) { 26542281ac9SMark McLoughlin if (getsockname(fd, (struct sockaddr *) &saddr, &saddr_len) == 0) { 26642281ac9SMark McLoughlin /* must be bound */ 26742281ac9SMark McLoughlin if (saddr.sin_addr.s_addr == 0) { 268842480d4SStefan Hajnoczi fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, " 269842480d4SStefan Hajnoczi "cannot setup multicast dst addr\n", fd); 270e5d1fca0SStefan Hajnoczi goto err; 27142281ac9SMark McLoughlin } 27242281ac9SMark McLoughlin /* clone dgram socket */ 2733a75e74cSMike Ryan newfd = net_socket_mcast_create(&saddr, NULL); 27442281ac9SMark McLoughlin if (newfd < 0) { 27542281ac9SMark McLoughlin /* error already reported by net_socket_mcast_create() */ 276e5d1fca0SStefan Hajnoczi goto err; 27742281ac9SMark McLoughlin } 27842281ac9SMark McLoughlin /* clone newfd to fd, close newfd */ 27942281ac9SMark McLoughlin dup2(newfd, fd); 28042281ac9SMark McLoughlin close(newfd); 28142281ac9SMark McLoughlin 28242281ac9SMark McLoughlin } else { 283842480d4SStefan Hajnoczi fprintf(stderr, 284842480d4SStefan Hajnoczi "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n", 28542281ac9SMark McLoughlin fd, strerror(errno)); 286e5d1fca0SStefan Hajnoczi goto err; 28742281ac9SMark McLoughlin } 28842281ac9SMark McLoughlin } 28942281ac9SMark McLoughlin 290564f63e3SMark McLoughlin nc = qemu_new_net_client(&net_dgram_socket_info, vlan, NULL, model, name); 291564f63e3SMark McLoughlin 292564f63e3SMark McLoughlin snprintf(nc->info_str, sizeof(nc->info_str), 293564f63e3SMark McLoughlin "socket: fd=%d (%s mcast=%s:%d)", 294564f63e3SMark McLoughlin fd, is_connected ? "cloned" : "", 295564f63e3SMark McLoughlin inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); 296564f63e3SMark McLoughlin 297564f63e3SMark McLoughlin s = DO_UPCAST(NetSocketState, nc, nc); 298564f63e3SMark McLoughlin 29942281ac9SMark McLoughlin s->fd = fd; 30042281ac9SMark McLoughlin 30142281ac9SMark McLoughlin qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s); 30242281ac9SMark McLoughlin 30342281ac9SMark McLoughlin /* mcast: save bound address as dst */ 30442281ac9SMark McLoughlin if (is_connected) s->dgram_dst=saddr; 30542281ac9SMark McLoughlin 30642281ac9SMark McLoughlin return s; 307e5d1fca0SStefan Hajnoczi 308e5d1fca0SStefan Hajnoczi err: 309e5d1fca0SStefan Hajnoczi closesocket(fd); 310e5d1fca0SStefan Hajnoczi return NULL; 31142281ac9SMark McLoughlin } 31242281ac9SMark McLoughlin 31342281ac9SMark McLoughlin static void net_socket_connect(void *opaque) 31442281ac9SMark McLoughlin { 31542281ac9SMark McLoughlin NetSocketState *s = opaque; 31642281ac9SMark McLoughlin qemu_set_fd_handler(s->fd, net_socket_send, NULL, s); 31742281ac9SMark McLoughlin } 31842281ac9SMark McLoughlin 319564f63e3SMark McLoughlin static NetClientInfo net_socket_info = { 3202be64a68SLaszlo Ersek .type = NET_CLIENT_OPTIONS_KIND_SOCKET, 321564f63e3SMark McLoughlin .size = sizeof(NetSocketState), 322564f63e3SMark McLoughlin .receive = net_socket_receive, 323564f63e3SMark McLoughlin .cleanup = net_socket_cleanup, 324564f63e3SMark McLoughlin }; 325564f63e3SMark McLoughlin 32642281ac9SMark McLoughlin static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, 32742281ac9SMark McLoughlin const char *model, 32842281ac9SMark McLoughlin const char *name, 32942281ac9SMark McLoughlin int fd, int is_connected) 33042281ac9SMark McLoughlin { 331564f63e3SMark McLoughlin VLANClientState *nc; 33242281ac9SMark McLoughlin NetSocketState *s; 333564f63e3SMark McLoughlin 334564f63e3SMark McLoughlin nc = qemu_new_net_client(&net_socket_info, vlan, NULL, model, name); 335564f63e3SMark McLoughlin 336564f63e3SMark McLoughlin snprintf(nc->info_str, sizeof(nc->info_str), "socket: fd=%d", fd); 337564f63e3SMark McLoughlin 338564f63e3SMark McLoughlin s = DO_UPCAST(NetSocketState, nc, nc); 339564f63e3SMark McLoughlin 34042281ac9SMark McLoughlin s->fd = fd; 341564f63e3SMark McLoughlin 34242281ac9SMark McLoughlin if (is_connected) { 34342281ac9SMark McLoughlin net_socket_connect(s); 34442281ac9SMark McLoughlin } else { 34542281ac9SMark McLoughlin qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s); 34642281ac9SMark McLoughlin } 34742281ac9SMark McLoughlin return s; 34842281ac9SMark McLoughlin } 34942281ac9SMark McLoughlin 35042281ac9SMark McLoughlin static NetSocketState *net_socket_fd_init(VLANState *vlan, 35142281ac9SMark McLoughlin const char *model, const char *name, 35242281ac9SMark McLoughlin int fd, int is_connected) 35342281ac9SMark McLoughlin { 35442281ac9SMark McLoughlin int so_type = -1, optlen=sizeof(so_type); 35542281ac9SMark McLoughlin 35642281ac9SMark McLoughlin if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type, 35742281ac9SMark McLoughlin (socklen_t *)&optlen)< 0) { 358842480d4SStefan Hajnoczi fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n", 359842480d4SStefan Hajnoczi fd); 360e5d1fca0SStefan Hajnoczi closesocket(fd); 36142281ac9SMark McLoughlin return NULL; 36242281ac9SMark McLoughlin } 36342281ac9SMark McLoughlin switch(so_type) { 36442281ac9SMark McLoughlin case SOCK_DGRAM: 36542281ac9SMark McLoughlin return net_socket_fd_init_dgram(vlan, model, name, fd, is_connected); 36642281ac9SMark McLoughlin case SOCK_STREAM: 36742281ac9SMark McLoughlin return net_socket_fd_init_stream(vlan, model, name, fd, is_connected); 36842281ac9SMark McLoughlin default: 36942281ac9SMark McLoughlin /* who knows ... this could be a eg. a pty, do warn and continue as stream */ 37042281ac9SMark McLoughlin fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd); 37142281ac9SMark McLoughlin return net_socket_fd_init_stream(vlan, model, name, fd, is_connected); 37242281ac9SMark McLoughlin } 37342281ac9SMark McLoughlin return NULL; 37442281ac9SMark McLoughlin } 37542281ac9SMark McLoughlin 37642281ac9SMark McLoughlin static void net_socket_accept(void *opaque) 37742281ac9SMark McLoughlin { 37842281ac9SMark McLoughlin NetSocketListenState *s = opaque; 37942281ac9SMark McLoughlin NetSocketState *s1; 38042281ac9SMark McLoughlin struct sockaddr_in saddr; 38142281ac9SMark McLoughlin socklen_t len; 38242281ac9SMark McLoughlin int fd; 38342281ac9SMark McLoughlin 38442281ac9SMark McLoughlin for(;;) { 38542281ac9SMark McLoughlin len = sizeof(saddr); 38640ff6d7eSKevin Wolf fd = qemu_accept(s->fd, (struct sockaddr *)&saddr, &len); 38742281ac9SMark McLoughlin if (fd < 0 && errno != EINTR) { 38842281ac9SMark McLoughlin return; 38942281ac9SMark McLoughlin } else if (fd >= 0) { 39042281ac9SMark McLoughlin break; 39142281ac9SMark McLoughlin } 39242281ac9SMark McLoughlin } 39342281ac9SMark McLoughlin s1 = net_socket_fd_init(s->vlan, s->model, s->name, fd, 1); 394e5d1fca0SStefan Hajnoczi if (s1) { 395564f63e3SMark McLoughlin snprintf(s1->nc.info_str, sizeof(s1->nc.info_str), 39642281ac9SMark McLoughlin "socket: connection from %s:%d", 39742281ac9SMark McLoughlin inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); 39842281ac9SMark McLoughlin } 39942281ac9SMark McLoughlin } 40042281ac9SMark McLoughlin 40142281ac9SMark McLoughlin static int net_socket_listen_init(VLANState *vlan, 40242281ac9SMark McLoughlin const char *model, 40342281ac9SMark McLoughlin const char *name, 40442281ac9SMark McLoughlin const char *host_str) 40542281ac9SMark McLoughlin { 40642281ac9SMark McLoughlin NetSocketListenState *s; 40742281ac9SMark McLoughlin int fd, val, ret; 40842281ac9SMark McLoughlin struct sockaddr_in saddr; 40942281ac9SMark McLoughlin 41042281ac9SMark McLoughlin if (parse_host_port(&saddr, host_str) < 0) 41142281ac9SMark McLoughlin return -1; 41242281ac9SMark McLoughlin 4137267c094SAnthony Liguori s = g_malloc0(sizeof(NetSocketListenState)); 41442281ac9SMark McLoughlin 41540ff6d7eSKevin Wolf fd = qemu_socket(PF_INET, SOCK_STREAM, 0); 41642281ac9SMark McLoughlin if (fd < 0) { 41742281ac9SMark McLoughlin perror("socket"); 418c7ee8f68SZhi Hui Li g_free(s); 41942281ac9SMark McLoughlin return -1; 42042281ac9SMark McLoughlin } 42142281ac9SMark McLoughlin socket_set_nonblock(fd); 42242281ac9SMark McLoughlin 42342281ac9SMark McLoughlin /* allow fast reuse */ 42442281ac9SMark McLoughlin val = 1; 42542281ac9SMark McLoughlin setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); 42642281ac9SMark McLoughlin 42742281ac9SMark McLoughlin ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)); 42842281ac9SMark McLoughlin if (ret < 0) { 42942281ac9SMark McLoughlin perror("bind"); 430c7ee8f68SZhi Hui Li g_free(s); 431a46667eaSPeter Maydell closesocket(fd); 43242281ac9SMark McLoughlin return -1; 43342281ac9SMark McLoughlin } 43442281ac9SMark McLoughlin ret = listen(fd, 0); 43542281ac9SMark McLoughlin if (ret < 0) { 43642281ac9SMark McLoughlin perror("listen"); 437c7ee8f68SZhi Hui Li g_free(s); 438a46667eaSPeter Maydell closesocket(fd); 43942281ac9SMark McLoughlin return -1; 44042281ac9SMark McLoughlin } 44142281ac9SMark McLoughlin s->vlan = vlan; 4427267c094SAnthony Liguori s->model = g_strdup(model); 4437267c094SAnthony Liguori s->name = name ? g_strdup(name) : NULL; 44442281ac9SMark McLoughlin s->fd = fd; 44542281ac9SMark McLoughlin qemu_set_fd_handler(fd, net_socket_accept, NULL, s); 44642281ac9SMark McLoughlin return 0; 44742281ac9SMark McLoughlin } 44842281ac9SMark McLoughlin 44942281ac9SMark McLoughlin static int net_socket_connect_init(VLANState *vlan, 45042281ac9SMark McLoughlin const char *model, 45142281ac9SMark McLoughlin const char *name, 45242281ac9SMark McLoughlin const char *host_str) 45342281ac9SMark McLoughlin { 45442281ac9SMark McLoughlin NetSocketState *s; 45542281ac9SMark McLoughlin int fd, connected, ret, err; 45642281ac9SMark McLoughlin struct sockaddr_in saddr; 45742281ac9SMark McLoughlin 45842281ac9SMark McLoughlin if (parse_host_port(&saddr, host_str) < 0) 45942281ac9SMark McLoughlin return -1; 46042281ac9SMark McLoughlin 46140ff6d7eSKevin Wolf fd = qemu_socket(PF_INET, SOCK_STREAM, 0); 46242281ac9SMark McLoughlin if (fd < 0) { 46342281ac9SMark McLoughlin perror("socket"); 46442281ac9SMark McLoughlin return -1; 46542281ac9SMark McLoughlin } 46642281ac9SMark McLoughlin socket_set_nonblock(fd); 46742281ac9SMark McLoughlin 46842281ac9SMark McLoughlin connected = 0; 46942281ac9SMark McLoughlin for(;;) { 47042281ac9SMark McLoughlin ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)); 47142281ac9SMark McLoughlin if (ret < 0) { 47242281ac9SMark McLoughlin err = socket_error(); 47342281ac9SMark McLoughlin if (err == EINTR || err == EWOULDBLOCK) { 47442281ac9SMark McLoughlin } else if (err == EINPROGRESS) { 47542281ac9SMark McLoughlin break; 47642281ac9SMark McLoughlin #ifdef _WIN32 477c7eb1f02SPavel Dovgaluk } else if (err == WSAEALREADY || err == WSAEINVAL) { 47842281ac9SMark McLoughlin break; 47942281ac9SMark McLoughlin #endif 48042281ac9SMark McLoughlin } else { 48142281ac9SMark McLoughlin perror("connect"); 48242281ac9SMark McLoughlin closesocket(fd); 48342281ac9SMark McLoughlin return -1; 48442281ac9SMark McLoughlin } 48542281ac9SMark McLoughlin } else { 48642281ac9SMark McLoughlin connected = 1; 48742281ac9SMark McLoughlin break; 48842281ac9SMark McLoughlin } 48942281ac9SMark McLoughlin } 49042281ac9SMark McLoughlin s = net_socket_fd_init(vlan, model, name, fd, connected); 49142281ac9SMark McLoughlin if (!s) 49242281ac9SMark McLoughlin return -1; 493564f63e3SMark McLoughlin snprintf(s->nc.info_str, sizeof(s->nc.info_str), 49442281ac9SMark McLoughlin "socket: connect to %s:%d", 49542281ac9SMark McLoughlin inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); 49642281ac9SMark McLoughlin return 0; 49742281ac9SMark McLoughlin } 49842281ac9SMark McLoughlin 49942281ac9SMark McLoughlin static int net_socket_mcast_init(VLANState *vlan, 50042281ac9SMark McLoughlin const char *model, 50142281ac9SMark McLoughlin const char *name, 5023a75e74cSMike Ryan const char *host_str, 5033a75e74cSMike Ryan const char *localaddr_str) 50442281ac9SMark McLoughlin { 50542281ac9SMark McLoughlin NetSocketState *s; 50642281ac9SMark McLoughlin int fd; 50742281ac9SMark McLoughlin struct sockaddr_in saddr; 5083a75e74cSMike Ryan struct in_addr localaddr, *param_localaddr; 50942281ac9SMark McLoughlin 51042281ac9SMark McLoughlin if (parse_host_port(&saddr, host_str) < 0) 51142281ac9SMark McLoughlin return -1; 51242281ac9SMark McLoughlin 5133a75e74cSMike Ryan if (localaddr_str != NULL) { 5143a75e74cSMike Ryan if (inet_aton(localaddr_str, &localaddr) == 0) 5153a75e74cSMike Ryan return -1; 5163a75e74cSMike Ryan param_localaddr = &localaddr; 5173a75e74cSMike Ryan } else { 5183a75e74cSMike Ryan param_localaddr = NULL; 5193a75e74cSMike Ryan } 52042281ac9SMark McLoughlin 5213a75e74cSMike Ryan fd = net_socket_mcast_create(&saddr, param_localaddr); 52242281ac9SMark McLoughlin if (fd < 0) 52342281ac9SMark McLoughlin return -1; 52442281ac9SMark McLoughlin 52542281ac9SMark McLoughlin s = net_socket_fd_init(vlan, model, name, fd, 0); 52642281ac9SMark McLoughlin if (!s) 52742281ac9SMark McLoughlin return -1; 52842281ac9SMark McLoughlin 52942281ac9SMark McLoughlin s->dgram_dst = saddr; 53042281ac9SMark McLoughlin 531564f63e3SMark McLoughlin snprintf(s->nc.info_str, sizeof(s->nc.info_str), 53242281ac9SMark McLoughlin "socket: mcast=%s:%d", 53342281ac9SMark McLoughlin inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); 53442281ac9SMark McLoughlin return 0; 53542281ac9SMark McLoughlin 53642281ac9SMark McLoughlin } 53742281ac9SMark McLoughlin 5380e0e7facSBenjamin static int net_socket_udp_init(VLANState *vlan, 5390e0e7facSBenjamin const char *model, 5400e0e7facSBenjamin const char *name, 5410e0e7facSBenjamin const char *rhost, 5420e0e7facSBenjamin const char *lhost) 5430e0e7facSBenjamin { 5440e0e7facSBenjamin NetSocketState *s; 5450e0e7facSBenjamin int fd, val, ret; 5460e0e7facSBenjamin struct sockaddr_in laddr, raddr; 5470e0e7facSBenjamin 5480e0e7facSBenjamin if (parse_host_port(&laddr, lhost) < 0) { 5490e0e7facSBenjamin return -1; 5500e0e7facSBenjamin } 5510e0e7facSBenjamin 5520e0e7facSBenjamin if (parse_host_port(&raddr, rhost) < 0) { 5530e0e7facSBenjamin return -1; 5540e0e7facSBenjamin } 5550e0e7facSBenjamin 5560e0e7facSBenjamin fd = qemu_socket(PF_INET, SOCK_DGRAM, 0); 5570e0e7facSBenjamin if (fd < 0) { 5580e0e7facSBenjamin perror("socket(PF_INET, SOCK_DGRAM)"); 5590e0e7facSBenjamin return -1; 5600e0e7facSBenjamin } 5610e0e7facSBenjamin val = 1; 5620e0e7facSBenjamin ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, 5630e0e7facSBenjamin (const char *)&val, sizeof(val)); 5640e0e7facSBenjamin if (ret < 0) { 5650e0e7facSBenjamin perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)"); 5660e0e7facSBenjamin closesocket(fd); 5670e0e7facSBenjamin return -1; 5680e0e7facSBenjamin } 5690e0e7facSBenjamin ret = bind(fd, (struct sockaddr *)&laddr, sizeof(laddr)); 5700e0e7facSBenjamin if (ret < 0) { 5710e0e7facSBenjamin perror("bind"); 5720e0e7facSBenjamin closesocket(fd); 5730e0e7facSBenjamin return -1; 5740e0e7facSBenjamin } 5750e0e7facSBenjamin 5760e0e7facSBenjamin s = net_socket_fd_init(vlan, model, name, fd, 0); 5770e0e7facSBenjamin if (!s) { 5780e0e7facSBenjamin return -1; 5790e0e7facSBenjamin } 5800e0e7facSBenjamin 5810e0e7facSBenjamin s->dgram_dst = raddr; 5820e0e7facSBenjamin 5830e0e7facSBenjamin snprintf(s->nc.info_str, sizeof(s->nc.info_str), 5840e0e7facSBenjamin "socket: udp=%s:%d", 5850e0e7facSBenjamin inet_ntoa(raddr.sin_addr), ntohs(raddr.sin_port)); 5860e0e7facSBenjamin return 0; 5870e0e7facSBenjamin } 5880e0e7facSBenjamin 589*1a0c0958SLaszlo Ersek int net_init_socket(const NetClientOptions *opts, const char *name, 590*1a0c0958SLaszlo Ersek VLANState *vlan) 59142281ac9SMark McLoughlin { 592bef8e8feSLaszlo Ersek const NetdevSocketOptions *sock; 593bef8e8feSLaszlo Ersek 594bef8e8feSLaszlo Ersek assert(opts->kind == NET_CLIENT_OPTIONS_KIND_SOCKET); 595bef8e8feSLaszlo Ersek sock = opts->socket; 596bef8e8feSLaszlo Ersek 597bef8e8feSLaszlo Ersek if (sock->has_fd + sock->has_listen + sock->has_connect + sock->has_mcast + 598bef8e8feSLaszlo Ersek sock->has_udp != 1) { 599bef8e8feSLaszlo Ersek error_report("exactly one of fd=, listen=, connect=, mcast= or udp=" 600bef8e8feSLaszlo Ersek " is required"); 601bef8e8feSLaszlo Ersek return -1; 602bef8e8feSLaszlo Ersek } 603bef8e8feSLaszlo Ersek 604bef8e8feSLaszlo Ersek if (sock->has_localaddr && !sock->has_mcast && !sock->has_udp) { 605bef8e8feSLaszlo Ersek error_report("localaddr= is only valid with mcast= or udp="); 606bef8e8feSLaszlo Ersek return -1; 607bef8e8feSLaszlo Ersek } 608bef8e8feSLaszlo Ersek 609bef8e8feSLaszlo Ersek if (sock->has_fd) { 61042281ac9SMark McLoughlin int fd; 61142281ac9SMark McLoughlin 612bef8e8feSLaszlo Ersek fd = net_handle_fd_param(cur_mon, sock->fd); 613bef8e8feSLaszlo Ersek if (fd == -1 || !net_socket_fd_init(vlan, "socket", name, fd, 1)) { 61442281ac9SMark McLoughlin return -1; 61542281ac9SMark McLoughlin } 616bef8e8feSLaszlo Ersek return 0; 61742281ac9SMark McLoughlin } 61842281ac9SMark McLoughlin 619bef8e8feSLaszlo Ersek if (sock->has_listen) { 620bef8e8feSLaszlo Ersek if (net_socket_listen_init(vlan, "socket", name, sock->listen) == -1) { 62142281ac9SMark McLoughlin return -1; 62242281ac9SMark McLoughlin } 623bef8e8feSLaszlo Ersek return 0; 62442281ac9SMark McLoughlin } 62542281ac9SMark McLoughlin 626bef8e8feSLaszlo Ersek if (sock->has_connect) { 627bef8e8feSLaszlo Ersek if (net_socket_connect_init(vlan, "socket", name, sock->connect) == 628bef8e8feSLaszlo Ersek -1) { 62942281ac9SMark McLoughlin return -1; 63042281ac9SMark McLoughlin } 631bef8e8feSLaszlo Ersek return 0; 63242281ac9SMark McLoughlin } 63342281ac9SMark McLoughlin 634bef8e8feSLaszlo Ersek if (sock->has_mcast) { 635bef8e8feSLaszlo Ersek /* if sock->localaddr is missing, it has been initialized to "all bits 636bef8e8feSLaszlo Ersek * zero" */ 637bef8e8feSLaszlo Ersek if (net_socket_mcast_init(vlan, "socket", name, sock->mcast, 638bef8e8feSLaszlo Ersek sock->localaddr) == -1) { 63942281ac9SMark McLoughlin return -1; 64042281ac9SMark McLoughlin } 641bef8e8feSLaszlo Ersek return 0; 64242281ac9SMark McLoughlin } 64342281ac9SMark McLoughlin 644bef8e8feSLaszlo Ersek assert(sock->has_udp); 645bef8e8feSLaszlo Ersek if (!sock->has_localaddr) { 6460e0e7facSBenjamin error_report("localaddr= is mandatory with udp="); 6470e0e7facSBenjamin return -1; 6480e0e7facSBenjamin } 649bef8e8feSLaszlo Ersek if (net_socket_udp_init(vlan, "udp", name, sock->udp, sock->localaddr) == 650bef8e8feSLaszlo Ersek -1) { 6510e0e7facSBenjamin return -1; 6520e0e7facSBenjamin } 65342281ac9SMark McLoughlin return 0; 65442281ac9SMark McLoughlin } 655