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 */ 242744d920SPeter Maydell #include "qemu/osdep.h" 2542281ac9SMark McLoughlin 261422e32dSPaolo Bonzini #include "net/net.h" 27a245fc18SPaolo Bonzini #include "clients.h" 2883c9089eSPaolo Bonzini #include "monitor/monitor.h" 29*da34e65cSMarkus Armbruster #include "qapi/error.h" 3042281ac9SMark McLoughlin #include "qemu-common.h" 311de7afc9SPaolo Bonzini #include "qemu/error-report.h" 321de7afc9SPaolo Bonzini #include "qemu/option.h" 331de7afc9SPaolo Bonzini #include "qemu/sockets.h" 341de7afc9SPaolo Bonzini #include "qemu/iov.h" 356a1751b7SAlex Bligh #include "qemu/main-loop.h" 3642281ac9SMark McLoughlin 3742281ac9SMark McLoughlin typedef struct NetSocketState { 384e68f7a0SStefan Hajnoczi NetClientState nc; 39011de2b5SZhi Yong Wu int listen_fd; 4042281ac9SMark McLoughlin int fd; 4142281ac9SMark McLoughlin int state; /* 0 = getting length, 1 = getting data */ 4242281ac9SMark McLoughlin unsigned int index; 4342281ac9SMark McLoughlin unsigned int packet_len; 4445a7f54aSStefan Hajnoczi unsigned int send_index; /* number of bytes sent (only SOCK_STREAM) */ 45d32fcad3SScott Feldman uint8_t buf[NET_BUFSIZE]; 4642281ac9SMark McLoughlin struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */ 47863f678fSStefan Hajnoczi IOHandler *send_fn; /* differs between SOCK_STREAM/SOCK_DGRAM */ 48863f678fSStefan Hajnoczi bool read_poll; /* waiting to receive data? */ 49863f678fSStefan Hajnoczi bool write_poll; /* waiting to transmit data? */ 5042281ac9SMark McLoughlin } NetSocketState; 5142281ac9SMark McLoughlin 52011de2b5SZhi Yong Wu static void net_socket_accept(void *opaque); 53863f678fSStefan Hajnoczi static void net_socket_writable(void *opaque); 54863f678fSStefan Hajnoczi 55863f678fSStefan Hajnoczi static void net_socket_update_fd_handler(NetSocketState *s) 56863f678fSStefan Hajnoczi { 5782e1cc4bSFam Zheng qemu_set_fd_handler(s->fd, 58863f678fSStefan Hajnoczi s->read_poll ? s->send_fn : NULL, 59863f678fSStefan Hajnoczi s->write_poll ? net_socket_writable : NULL, 60863f678fSStefan Hajnoczi s); 61863f678fSStefan Hajnoczi } 62863f678fSStefan Hajnoczi 63863f678fSStefan Hajnoczi static void net_socket_read_poll(NetSocketState *s, bool enable) 64863f678fSStefan Hajnoczi { 65863f678fSStefan Hajnoczi s->read_poll = enable; 66863f678fSStefan Hajnoczi net_socket_update_fd_handler(s); 67863f678fSStefan Hajnoczi } 68863f678fSStefan Hajnoczi 69863f678fSStefan Hajnoczi static void net_socket_write_poll(NetSocketState *s, bool enable) 70863f678fSStefan Hajnoczi { 71863f678fSStefan Hajnoczi s->write_poll = enable; 72863f678fSStefan Hajnoczi net_socket_update_fd_handler(s); 73863f678fSStefan Hajnoczi } 74863f678fSStefan Hajnoczi 75863f678fSStefan Hajnoczi static void net_socket_writable(void *opaque) 76863f678fSStefan Hajnoczi { 77863f678fSStefan Hajnoczi NetSocketState *s = opaque; 78863f678fSStefan Hajnoczi 79863f678fSStefan Hajnoczi net_socket_write_poll(s, false); 80863f678fSStefan Hajnoczi 81863f678fSStefan Hajnoczi qemu_flush_queued_packets(&s->nc); 82863f678fSStefan Hajnoczi } 8342281ac9SMark McLoughlin 844e68f7a0SStefan Hajnoczi static ssize_t net_socket_receive(NetClientState *nc, const uint8_t *buf, size_t size) 8542281ac9SMark McLoughlin { 86564f63e3SMark McLoughlin NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); 8745a7f54aSStefan Hajnoczi uint32_t len = htonl(size); 8845a7f54aSStefan Hajnoczi struct iovec iov[] = { 8945a7f54aSStefan Hajnoczi { 9045a7f54aSStefan Hajnoczi .iov_base = &len, 9145a7f54aSStefan Hajnoczi .iov_len = sizeof(len), 9245a7f54aSStefan Hajnoczi }, { 9345a7f54aSStefan Hajnoczi .iov_base = (void *)buf, 9445a7f54aSStefan Hajnoczi .iov_len = size, 9545a7f54aSStefan Hajnoczi }, 9645a7f54aSStefan Hajnoczi }; 9745a7f54aSStefan Hajnoczi size_t remaining; 9845a7f54aSStefan Hajnoczi ssize_t ret; 9942281ac9SMark McLoughlin 10045a7f54aSStefan Hajnoczi remaining = iov_size(iov, 2) - s->send_index; 10145a7f54aSStefan Hajnoczi ret = iov_send(s->fd, iov, 2, s->send_index, remaining); 10245a7f54aSStefan Hajnoczi 10345a7f54aSStefan Hajnoczi if (ret == -1 && errno == EAGAIN) { 10445a7f54aSStefan Hajnoczi ret = 0; /* handled further down */ 10545a7f54aSStefan Hajnoczi } 10645a7f54aSStefan Hajnoczi if (ret == -1) { 10745a7f54aSStefan Hajnoczi s->send_index = 0; 10845a7f54aSStefan Hajnoczi return -errno; 10945a7f54aSStefan Hajnoczi } 11045a7f54aSStefan Hajnoczi if (ret < (ssize_t)remaining) { 11145a7f54aSStefan Hajnoczi s->send_index += ret; 11245a7f54aSStefan Hajnoczi net_socket_write_poll(s, true); 11345a7f54aSStefan Hajnoczi return 0; 11445a7f54aSStefan Hajnoczi } 11545a7f54aSStefan Hajnoczi s->send_index = 0; 11645a7f54aSStefan Hajnoczi return size; 11742281ac9SMark McLoughlin } 11842281ac9SMark McLoughlin 1194e68f7a0SStefan Hajnoczi static ssize_t net_socket_receive_dgram(NetClientState *nc, const uint8_t *buf, size_t size) 12042281ac9SMark McLoughlin { 121564f63e3SMark McLoughlin NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); 122213fd508SStefan Hajnoczi ssize_t ret; 12342281ac9SMark McLoughlin 124213fd508SStefan Hajnoczi do { 12573062dfeSStefan Weil ret = qemu_sendto(s->fd, buf, size, 0, 126213fd508SStefan Hajnoczi (struct sockaddr *)&s->dgram_dst, 127213fd508SStefan Hajnoczi sizeof(s->dgram_dst)); 128213fd508SStefan Hajnoczi } while (ret == -1 && errno == EINTR); 129213fd508SStefan Hajnoczi 130213fd508SStefan Hajnoczi if (ret == -1 && errno == EAGAIN) { 131213fd508SStefan Hajnoczi net_socket_write_poll(s, true); 132213fd508SStefan Hajnoczi return 0; 133213fd508SStefan Hajnoczi } 134213fd508SStefan Hajnoczi return ret; 13542281ac9SMark McLoughlin } 13642281ac9SMark McLoughlin 1376e99c631SFam Zheng static void net_socket_send_completed(NetClientState *nc, ssize_t len) 1386e99c631SFam Zheng { 1396e99c631SFam Zheng NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); 1406e99c631SFam Zheng 1416e99c631SFam Zheng if (!s->read_poll) { 1426e99c631SFam Zheng net_socket_read_poll(s, true); 1436e99c631SFam Zheng } 1446e99c631SFam Zheng } 1456e99c631SFam Zheng 14642281ac9SMark McLoughlin static void net_socket_send(void *opaque) 14742281ac9SMark McLoughlin { 14842281ac9SMark McLoughlin NetSocketState *s = opaque; 149b16a44e1SDaniel P. Berrange int size; 15042281ac9SMark McLoughlin unsigned l; 151d32fcad3SScott Feldman uint8_t buf1[NET_BUFSIZE]; 15242281ac9SMark McLoughlin const uint8_t *buf; 15342281ac9SMark McLoughlin 15400aa0040SBlue Swirl size = qemu_recv(s->fd, buf1, sizeof(buf1), 0); 15542281ac9SMark McLoughlin if (size < 0) { 156b16a44e1SDaniel P. Berrange if (errno != EWOULDBLOCK) 15742281ac9SMark McLoughlin goto eoc; 15842281ac9SMark McLoughlin } else if (size == 0) { 15942281ac9SMark McLoughlin /* end of connection */ 16042281ac9SMark McLoughlin eoc: 161863f678fSStefan Hajnoczi net_socket_read_poll(s, false); 162863f678fSStefan Hajnoczi net_socket_write_poll(s, false); 163011de2b5SZhi Yong Wu if (s->listen_fd != -1) { 164011de2b5SZhi Yong Wu qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s); 165011de2b5SZhi Yong Wu } 16642281ac9SMark McLoughlin closesocket(s->fd); 167011de2b5SZhi Yong Wu 168011de2b5SZhi Yong Wu s->fd = -1; 169011de2b5SZhi Yong Wu s->state = 0; 170011de2b5SZhi Yong Wu s->index = 0; 171011de2b5SZhi Yong Wu s->packet_len = 0; 172011de2b5SZhi Yong Wu s->nc.link_down = true; 173011de2b5SZhi Yong Wu memset(s->buf, 0, sizeof(s->buf)); 174011de2b5SZhi Yong Wu memset(s->nc.info_str, 0, sizeof(s->nc.info_str)); 175011de2b5SZhi Yong Wu 17642281ac9SMark McLoughlin return; 17742281ac9SMark McLoughlin } 17842281ac9SMark McLoughlin buf = buf1; 17942281ac9SMark McLoughlin while (size > 0) { 18042281ac9SMark McLoughlin /* reassemble a packet from the network */ 18142281ac9SMark McLoughlin switch(s->state) { 18242281ac9SMark McLoughlin case 0: 18342281ac9SMark McLoughlin l = 4 - s->index; 18442281ac9SMark McLoughlin if (l > size) 18542281ac9SMark McLoughlin l = size; 18642281ac9SMark McLoughlin memcpy(s->buf + s->index, buf, l); 18742281ac9SMark McLoughlin buf += l; 18842281ac9SMark McLoughlin size -= l; 18942281ac9SMark McLoughlin s->index += l; 19042281ac9SMark McLoughlin if (s->index == 4) { 19142281ac9SMark McLoughlin /* got length */ 19242281ac9SMark McLoughlin s->packet_len = ntohl(*(uint32_t *)s->buf); 19342281ac9SMark McLoughlin s->index = 0; 19442281ac9SMark McLoughlin s->state = 1; 19542281ac9SMark McLoughlin } 19642281ac9SMark McLoughlin break; 19742281ac9SMark McLoughlin case 1: 19842281ac9SMark McLoughlin l = s->packet_len - s->index; 19942281ac9SMark McLoughlin if (l > size) 20042281ac9SMark McLoughlin l = size; 20142281ac9SMark McLoughlin if (s->index + l <= sizeof(s->buf)) { 20242281ac9SMark McLoughlin memcpy(s->buf + s->index, buf, l); 20342281ac9SMark McLoughlin } else { 20442281ac9SMark McLoughlin fprintf(stderr, "serious error: oversized packet received," 20542281ac9SMark McLoughlin "connection terminated.\n"); 20642281ac9SMark McLoughlin s->state = 0; 20742281ac9SMark McLoughlin goto eoc; 20842281ac9SMark McLoughlin } 20942281ac9SMark McLoughlin 21042281ac9SMark McLoughlin s->index += l; 21142281ac9SMark McLoughlin buf += l; 21242281ac9SMark McLoughlin size -= l; 21342281ac9SMark McLoughlin if (s->index >= s->packet_len) { 21442281ac9SMark McLoughlin s->index = 0; 21542281ac9SMark McLoughlin s->state = 0; 216091f1f52SJason Wang if (qemu_send_packet_async(&s->nc, s->buf, s->packet_len, 2176e99c631SFam Zheng net_socket_send_completed) == 0) { 2186e99c631SFam Zheng net_socket_read_poll(s, false); 2196e99c631SFam Zheng break; 2206e99c631SFam Zheng } 22142281ac9SMark McLoughlin } 22242281ac9SMark McLoughlin break; 22342281ac9SMark McLoughlin } 22442281ac9SMark McLoughlin } 22542281ac9SMark McLoughlin } 22642281ac9SMark McLoughlin 22742281ac9SMark McLoughlin static void net_socket_send_dgram(void *opaque) 22842281ac9SMark McLoughlin { 22942281ac9SMark McLoughlin NetSocketState *s = opaque; 23042281ac9SMark McLoughlin int size; 23142281ac9SMark McLoughlin 23200aa0040SBlue Swirl size = qemu_recv(s->fd, s->buf, sizeof(s->buf), 0); 23342281ac9SMark McLoughlin if (size < 0) 23442281ac9SMark McLoughlin return; 23542281ac9SMark McLoughlin if (size == 0) { 23642281ac9SMark McLoughlin /* end of connection */ 237863f678fSStefan Hajnoczi net_socket_read_poll(s, false); 238863f678fSStefan Hajnoczi net_socket_write_poll(s, false); 23942281ac9SMark McLoughlin return; 24042281ac9SMark McLoughlin } 2416e99c631SFam Zheng if (qemu_send_packet_async(&s->nc, s->buf, size, 2426e99c631SFam Zheng net_socket_send_completed) == 0) { 2436e99c631SFam Zheng net_socket_read_poll(s, false); 2446e99c631SFam Zheng } 24542281ac9SMark McLoughlin } 24642281ac9SMark McLoughlin 2473a75e74cSMike Ryan static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr *localaddr) 24842281ac9SMark McLoughlin { 24942281ac9SMark McLoughlin struct ip_mreq imr; 25042281ac9SMark McLoughlin int fd; 25142281ac9SMark McLoughlin int val, ret; 25223ddf2bbSBrad #ifdef __OpenBSD__ 25323ddf2bbSBrad unsigned char loop; 25423ddf2bbSBrad #else 25523ddf2bbSBrad int loop; 25623ddf2bbSBrad #endif 25723ddf2bbSBrad 25842281ac9SMark McLoughlin if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) { 259842480d4SStefan Hajnoczi fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) " 260842480d4SStefan Hajnoczi "does not contain a multicast address\n", 26142281ac9SMark McLoughlin inet_ntoa(mcastaddr->sin_addr), 26242281ac9SMark McLoughlin (int)ntohl(mcastaddr->sin_addr.s_addr)); 26342281ac9SMark McLoughlin return -1; 26442281ac9SMark McLoughlin 26542281ac9SMark McLoughlin } 26640ff6d7eSKevin Wolf fd = qemu_socket(PF_INET, SOCK_DGRAM, 0); 26742281ac9SMark McLoughlin if (fd < 0) { 26842281ac9SMark McLoughlin perror("socket(PF_INET, SOCK_DGRAM)"); 26942281ac9SMark McLoughlin return -1; 27042281ac9SMark McLoughlin } 27142281ac9SMark McLoughlin 272bcbe92fbSSebastian Ottlik /* Allow multiple sockets to bind the same multicast ip and port by setting 273bcbe92fbSSebastian Ottlik * SO_REUSEADDR. This is the only situation where SO_REUSEADDR should be set 274bcbe92fbSSebastian Ottlik * on windows. Use socket_set_fast_reuse otherwise as it sets SO_REUSEADDR 275bcbe92fbSSebastian Ottlik * only on posix systems. 276bcbe92fbSSebastian Ottlik */ 27742281ac9SMark McLoughlin val = 1; 2789957fc7fSStefan Weil ret = qemu_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); 27942281ac9SMark McLoughlin if (ret < 0) { 28042281ac9SMark McLoughlin perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)"); 28142281ac9SMark McLoughlin goto fail; 28242281ac9SMark McLoughlin } 28342281ac9SMark McLoughlin 28442281ac9SMark McLoughlin ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr)); 28542281ac9SMark McLoughlin if (ret < 0) { 28642281ac9SMark McLoughlin perror("bind"); 28742281ac9SMark McLoughlin goto fail; 28842281ac9SMark McLoughlin } 28942281ac9SMark McLoughlin 29042281ac9SMark McLoughlin /* Add host to multicast group */ 29142281ac9SMark McLoughlin imr.imr_multiaddr = mcastaddr->sin_addr; 2923a75e74cSMike Ryan if (localaddr) { 2933a75e74cSMike Ryan imr.imr_interface = *localaddr; 2943a75e74cSMike Ryan } else { 29542281ac9SMark McLoughlin imr.imr_interface.s_addr = htonl(INADDR_ANY); 2963a75e74cSMike Ryan } 29742281ac9SMark McLoughlin 2989957fc7fSStefan Weil ret = qemu_setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, 2999957fc7fSStefan Weil &imr, sizeof(struct ip_mreq)); 30042281ac9SMark McLoughlin if (ret < 0) { 30142281ac9SMark McLoughlin perror("setsockopt(IP_ADD_MEMBERSHIP)"); 30242281ac9SMark McLoughlin goto fail; 30342281ac9SMark McLoughlin } 30442281ac9SMark McLoughlin 30542281ac9SMark McLoughlin /* Force mcast msgs to loopback (eg. several QEMUs in same host */ 30623ddf2bbSBrad loop = 1; 3079957fc7fSStefan Weil ret = qemu_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, 3089957fc7fSStefan Weil &loop, sizeof(loop)); 30942281ac9SMark McLoughlin if (ret < 0) { 31042281ac9SMark McLoughlin perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)"); 31142281ac9SMark McLoughlin goto fail; 31242281ac9SMark McLoughlin } 31342281ac9SMark McLoughlin 3143a75e74cSMike Ryan /* If a bind address is given, only send packets from that address */ 3153a75e74cSMike Ryan if (localaddr != NULL) { 3169957fc7fSStefan Weil ret = qemu_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, 3179957fc7fSStefan Weil localaddr, sizeof(*localaddr)); 3183a75e74cSMike Ryan if (ret < 0) { 3193a75e74cSMike Ryan perror("setsockopt(IP_MULTICAST_IF)"); 3203a75e74cSMike Ryan goto fail; 3213a75e74cSMike Ryan } 3223a75e74cSMike Ryan } 3233a75e74cSMike Ryan 324f9e8caccSStefan Hajnoczi qemu_set_nonblock(fd); 32542281ac9SMark McLoughlin return fd; 32642281ac9SMark McLoughlin fail: 32742281ac9SMark McLoughlin if (fd >= 0) 32842281ac9SMark McLoughlin closesocket(fd); 32942281ac9SMark McLoughlin return -1; 33042281ac9SMark McLoughlin } 33142281ac9SMark McLoughlin 3324e68f7a0SStefan Hajnoczi static void net_socket_cleanup(NetClientState *nc) 33342281ac9SMark McLoughlin { 334564f63e3SMark McLoughlin NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); 335011de2b5SZhi Yong Wu if (s->fd != -1) { 336863f678fSStefan Hajnoczi net_socket_read_poll(s, false); 337863f678fSStefan Hajnoczi net_socket_write_poll(s, false); 33842281ac9SMark McLoughlin close(s->fd); 339011de2b5SZhi Yong Wu s->fd = -1; 340011de2b5SZhi Yong Wu } 341011de2b5SZhi Yong Wu if (s->listen_fd != -1) { 342011de2b5SZhi Yong Wu qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL); 343011de2b5SZhi Yong Wu closesocket(s->listen_fd); 344011de2b5SZhi Yong Wu s->listen_fd = -1; 345011de2b5SZhi Yong Wu } 34642281ac9SMark McLoughlin } 34742281ac9SMark McLoughlin 348564f63e3SMark McLoughlin static NetClientInfo net_dgram_socket_info = { 3492be64a68SLaszlo Ersek .type = NET_CLIENT_OPTIONS_KIND_SOCKET, 350564f63e3SMark McLoughlin .size = sizeof(NetSocketState), 351564f63e3SMark McLoughlin .receive = net_socket_receive_dgram, 352564f63e3SMark McLoughlin .cleanup = net_socket_cleanup, 353564f63e3SMark McLoughlin }; 354564f63e3SMark McLoughlin 3554e68f7a0SStefan Hajnoczi static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer, 35642281ac9SMark McLoughlin const char *model, 35742281ac9SMark McLoughlin const char *name, 35842281ac9SMark McLoughlin int fd, int is_connected) 35942281ac9SMark McLoughlin { 36042281ac9SMark McLoughlin struct sockaddr_in saddr; 36142281ac9SMark McLoughlin int newfd; 362ed6273e2Szhanghailiang socklen_t saddr_len = sizeof(saddr); 3634e68f7a0SStefan Hajnoczi NetClientState *nc; 36442281ac9SMark McLoughlin NetSocketState *s; 36542281ac9SMark McLoughlin 36642281ac9SMark McLoughlin /* fd passed: multicast: "learn" dgram_dst address from bound address and save it 36742281ac9SMark McLoughlin * Because this may be "shared" socket from a "master" process, datagrams would be recv() 36842281ac9SMark McLoughlin * by ONLY ONE process: we must "clone" this dgram socket --jjo 36942281ac9SMark McLoughlin */ 37042281ac9SMark McLoughlin 37142281ac9SMark McLoughlin if (is_connected) { 37242281ac9SMark McLoughlin if (getsockname(fd, (struct sockaddr *) &saddr, &saddr_len) == 0) { 37342281ac9SMark McLoughlin /* must be bound */ 37442281ac9SMark McLoughlin if (saddr.sin_addr.s_addr == 0) { 375842480d4SStefan Hajnoczi fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, " 376842480d4SStefan Hajnoczi "cannot setup multicast dst addr\n", fd); 377e5d1fca0SStefan Hajnoczi goto err; 37842281ac9SMark McLoughlin } 37942281ac9SMark McLoughlin /* clone dgram socket */ 3803a75e74cSMike Ryan newfd = net_socket_mcast_create(&saddr, NULL); 38142281ac9SMark McLoughlin if (newfd < 0) { 38242281ac9SMark McLoughlin /* error already reported by net_socket_mcast_create() */ 383e5d1fca0SStefan Hajnoczi goto err; 38442281ac9SMark McLoughlin } 38542281ac9SMark McLoughlin /* clone newfd to fd, close newfd */ 38642281ac9SMark McLoughlin dup2(newfd, fd); 38742281ac9SMark McLoughlin close(newfd); 38842281ac9SMark McLoughlin 38942281ac9SMark McLoughlin } else { 390842480d4SStefan Hajnoczi fprintf(stderr, 391842480d4SStefan Hajnoczi "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n", 39242281ac9SMark McLoughlin fd, strerror(errno)); 393e5d1fca0SStefan Hajnoczi goto err; 39442281ac9SMark McLoughlin } 39542281ac9SMark McLoughlin } 39642281ac9SMark McLoughlin 397ab5f3f84SStefan Hajnoczi nc = qemu_new_net_client(&net_dgram_socket_info, peer, model, name); 398564f63e3SMark McLoughlin 399564f63e3SMark McLoughlin s = DO_UPCAST(NetSocketState, nc, nc); 400564f63e3SMark McLoughlin 40142281ac9SMark McLoughlin s->fd = fd; 402011de2b5SZhi Yong Wu s->listen_fd = -1; 403863f678fSStefan Hajnoczi s->send_fn = net_socket_send_dgram; 404863f678fSStefan Hajnoczi net_socket_read_poll(s, true); 40542281ac9SMark McLoughlin 40642281ac9SMark McLoughlin /* mcast: save bound address as dst */ 407e34cde35SZhi Yong Wu if (is_connected) { 408e34cde35SZhi Yong Wu s->dgram_dst = saddr; 4098db804acSGonglei snprintf(nc->info_str, sizeof(nc->info_str), 4108db804acSGonglei "socket: fd=%d (cloned mcast=%s:%d)", 4118db804acSGonglei fd, inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); 4128db804acSGonglei } else { 4138db804acSGonglei snprintf(nc->info_str, sizeof(nc->info_str), 4148db804acSGonglei "socket: fd=%d", fd); 415e34cde35SZhi Yong Wu } 41642281ac9SMark McLoughlin 41742281ac9SMark McLoughlin return s; 418e5d1fca0SStefan Hajnoczi 419e5d1fca0SStefan Hajnoczi err: 420e5d1fca0SStefan Hajnoczi closesocket(fd); 421e5d1fca0SStefan Hajnoczi return NULL; 42242281ac9SMark McLoughlin } 42342281ac9SMark McLoughlin 42442281ac9SMark McLoughlin static void net_socket_connect(void *opaque) 42542281ac9SMark McLoughlin { 42642281ac9SMark McLoughlin NetSocketState *s = opaque; 427863f678fSStefan Hajnoczi s->send_fn = net_socket_send; 428863f678fSStefan Hajnoczi net_socket_read_poll(s, true); 42942281ac9SMark McLoughlin } 43042281ac9SMark McLoughlin 431564f63e3SMark McLoughlin static NetClientInfo net_socket_info = { 4322be64a68SLaszlo Ersek .type = NET_CLIENT_OPTIONS_KIND_SOCKET, 433564f63e3SMark McLoughlin .size = sizeof(NetSocketState), 434564f63e3SMark McLoughlin .receive = net_socket_receive, 435564f63e3SMark McLoughlin .cleanup = net_socket_cleanup, 436564f63e3SMark McLoughlin }; 437564f63e3SMark McLoughlin 4384e68f7a0SStefan Hajnoczi static NetSocketState *net_socket_fd_init_stream(NetClientState *peer, 43942281ac9SMark McLoughlin const char *model, 44042281ac9SMark McLoughlin const char *name, 44142281ac9SMark McLoughlin int fd, int is_connected) 44242281ac9SMark McLoughlin { 4434e68f7a0SStefan Hajnoczi NetClientState *nc; 44442281ac9SMark McLoughlin NetSocketState *s; 445564f63e3SMark McLoughlin 446ab5f3f84SStefan Hajnoczi nc = qemu_new_net_client(&net_socket_info, peer, model, name); 447564f63e3SMark McLoughlin 448564f63e3SMark McLoughlin snprintf(nc->info_str, sizeof(nc->info_str), "socket: fd=%d", fd); 449564f63e3SMark McLoughlin 450564f63e3SMark McLoughlin s = DO_UPCAST(NetSocketState, nc, nc); 451564f63e3SMark McLoughlin 45242281ac9SMark McLoughlin s->fd = fd; 453011de2b5SZhi Yong Wu s->listen_fd = -1; 454564f63e3SMark McLoughlin 45520048d0aSStefan Hajnoczi /* Disable Nagle algorithm on TCP sockets to reduce latency */ 45620048d0aSStefan Hajnoczi socket_set_nodelay(fd); 45720048d0aSStefan Hajnoczi 45842281ac9SMark McLoughlin if (is_connected) { 45942281ac9SMark McLoughlin net_socket_connect(s); 46042281ac9SMark McLoughlin } else { 46142281ac9SMark McLoughlin qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s); 46242281ac9SMark McLoughlin } 46342281ac9SMark McLoughlin return s; 46442281ac9SMark McLoughlin } 46542281ac9SMark McLoughlin 4664e68f7a0SStefan Hajnoczi static NetSocketState *net_socket_fd_init(NetClientState *peer, 46742281ac9SMark McLoughlin const char *model, const char *name, 46842281ac9SMark McLoughlin int fd, int is_connected) 46942281ac9SMark McLoughlin { 47042281ac9SMark McLoughlin int so_type = -1, optlen=sizeof(so_type); 47142281ac9SMark McLoughlin 47242281ac9SMark McLoughlin if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type, 47342281ac9SMark McLoughlin (socklen_t *)&optlen)< 0) { 474842480d4SStefan Hajnoczi fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n", 475842480d4SStefan Hajnoczi fd); 476e5d1fca0SStefan Hajnoczi closesocket(fd); 47742281ac9SMark McLoughlin return NULL; 47842281ac9SMark McLoughlin } 47942281ac9SMark McLoughlin switch(so_type) { 48042281ac9SMark McLoughlin case SOCK_DGRAM: 481d33d93b2SStefan Hajnoczi return net_socket_fd_init_dgram(peer, model, name, fd, is_connected); 48242281ac9SMark McLoughlin case SOCK_STREAM: 483d33d93b2SStefan Hajnoczi return net_socket_fd_init_stream(peer, model, name, fd, is_connected); 48442281ac9SMark McLoughlin default: 48542281ac9SMark McLoughlin /* who knows ... this could be a eg. a pty, do warn and continue as stream */ 48642281ac9SMark McLoughlin fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd); 487d33d93b2SStefan Hajnoczi return net_socket_fd_init_stream(peer, model, name, fd, is_connected); 48842281ac9SMark McLoughlin } 48942281ac9SMark McLoughlin return NULL; 49042281ac9SMark McLoughlin } 49142281ac9SMark McLoughlin 49242281ac9SMark McLoughlin static void net_socket_accept(void *opaque) 49342281ac9SMark McLoughlin { 494011de2b5SZhi Yong Wu NetSocketState *s = opaque; 49542281ac9SMark McLoughlin struct sockaddr_in saddr; 49642281ac9SMark McLoughlin socklen_t len; 49742281ac9SMark McLoughlin int fd; 49842281ac9SMark McLoughlin 49942281ac9SMark McLoughlin for(;;) { 50042281ac9SMark McLoughlin len = sizeof(saddr); 501011de2b5SZhi Yong Wu fd = qemu_accept(s->listen_fd, (struct sockaddr *)&saddr, &len); 50242281ac9SMark McLoughlin if (fd < 0 && errno != EINTR) { 50342281ac9SMark McLoughlin return; 50442281ac9SMark McLoughlin } else if (fd >= 0) { 505011de2b5SZhi Yong Wu qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL); 50642281ac9SMark McLoughlin break; 50742281ac9SMark McLoughlin } 50842281ac9SMark McLoughlin } 509011de2b5SZhi Yong Wu 510011de2b5SZhi Yong Wu s->fd = fd; 511011de2b5SZhi Yong Wu s->nc.link_down = false; 512011de2b5SZhi Yong Wu net_socket_connect(s); 513011de2b5SZhi Yong Wu snprintf(s->nc.info_str, sizeof(s->nc.info_str), 51442281ac9SMark McLoughlin "socket: connection from %s:%d", 51542281ac9SMark McLoughlin inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); 51642281ac9SMark McLoughlin } 51742281ac9SMark McLoughlin 5184e68f7a0SStefan Hajnoczi static int net_socket_listen_init(NetClientState *peer, 51942281ac9SMark McLoughlin const char *model, 52042281ac9SMark McLoughlin const char *name, 52142281ac9SMark McLoughlin const char *host_str) 52242281ac9SMark McLoughlin { 523011de2b5SZhi Yong Wu NetClientState *nc; 524011de2b5SZhi Yong Wu NetSocketState *s; 52542281ac9SMark McLoughlin struct sockaddr_in saddr; 526bcbe92fbSSebastian Ottlik int fd, ret; 52742281ac9SMark McLoughlin 52842281ac9SMark McLoughlin if (parse_host_port(&saddr, host_str) < 0) 52942281ac9SMark McLoughlin return -1; 53042281ac9SMark McLoughlin 53140ff6d7eSKevin Wolf fd = qemu_socket(PF_INET, SOCK_STREAM, 0); 53242281ac9SMark McLoughlin if (fd < 0) { 53342281ac9SMark McLoughlin perror("socket"); 53442281ac9SMark McLoughlin return -1; 53542281ac9SMark McLoughlin } 536f9e8caccSStefan Hajnoczi qemu_set_nonblock(fd); 53742281ac9SMark McLoughlin 538bcbe92fbSSebastian Ottlik socket_set_fast_reuse(fd); 53942281ac9SMark McLoughlin 54042281ac9SMark McLoughlin ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)); 54142281ac9SMark McLoughlin if (ret < 0) { 54242281ac9SMark McLoughlin perror("bind"); 543a46667eaSPeter Maydell closesocket(fd); 54442281ac9SMark McLoughlin return -1; 54542281ac9SMark McLoughlin } 54642281ac9SMark McLoughlin ret = listen(fd, 0); 54742281ac9SMark McLoughlin if (ret < 0) { 54842281ac9SMark McLoughlin perror("listen"); 549a46667eaSPeter Maydell closesocket(fd); 55042281ac9SMark McLoughlin return -1; 55142281ac9SMark McLoughlin } 552011de2b5SZhi Yong Wu 553011de2b5SZhi Yong Wu nc = qemu_new_net_client(&net_socket_info, peer, model, name); 554011de2b5SZhi Yong Wu s = DO_UPCAST(NetSocketState, nc, nc); 555011de2b5SZhi Yong Wu s->fd = -1; 556011de2b5SZhi Yong Wu s->listen_fd = fd; 557011de2b5SZhi Yong Wu s->nc.link_down = true; 558011de2b5SZhi Yong Wu 559011de2b5SZhi Yong Wu qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s); 56042281ac9SMark McLoughlin return 0; 56142281ac9SMark McLoughlin } 56242281ac9SMark McLoughlin 5634e68f7a0SStefan Hajnoczi static int net_socket_connect_init(NetClientState *peer, 56442281ac9SMark McLoughlin const char *model, 56542281ac9SMark McLoughlin const char *name, 56642281ac9SMark McLoughlin const char *host_str) 56742281ac9SMark McLoughlin { 56842281ac9SMark McLoughlin NetSocketState *s; 569b16a44e1SDaniel P. Berrange int fd, connected, ret; 57042281ac9SMark McLoughlin struct sockaddr_in saddr; 57142281ac9SMark McLoughlin 57242281ac9SMark McLoughlin if (parse_host_port(&saddr, host_str) < 0) 57342281ac9SMark McLoughlin return -1; 57442281ac9SMark McLoughlin 57540ff6d7eSKevin Wolf fd = qemu_socket(PF_INET, SOCK_STREAM, 0); 57642281ac9SMark McLoughlin if (fd < 0) { 57742281ac9SMark McLoughlin perror("socket"); 57842281ac9SMark McLoughlin return -1; 57942281ac9SMark McLoughlin } 580f9e8caccSStefan Hajnoczi qemu_set_nonblock(fd); 58142281ac9SMark McLoughlin 58242281ac9SMark McLoughlin connected = 0; 58342281ac9SMark McLoughlin for(;;) { 58442281ac9SMark McLoughlin ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)); 58542281ac9SMark McLoughlin if (ret < 0) { 586b16a44e1SDaniel P. Berrange if (errno == EINTR || errno == EWOULDBLOCK) { 587b16a44e1SDaniel P. Berrange /* continue */ 588b16a44e1SDaniel P. Berrange } else if (errno == EINPROGRESS || 589b16a44e1SDaniel P. Berrange errno == EALREADY || 590b16a44e1SDaniel P. Berrange errno == EINVAL) { 59142281ac9SMark McLoughlin break; 59242281ac9SMark McLoughlin } else { 59342281ac9SMark McLoughlin perror("connect"); 59442281ac9SMark McLoughlin closesocket(fd); 59542281ac9SMark McLoughlin return -1; 59642281ac9SMark McLoughlin } 59742281ac9SMark McLoughlin } else { 59842281ac9SMark McLoughlin connected = 1; 59942281ac9SMark McLoughlin break; 60042281ac9SMark McLoughlin } 60142281ac9SMark McLoughlin } 602d33d93b2SStefan Hajnoczi s = net_socket_fd_init(peer, model, name, fd, connected); 60342281ac9SMark McLoughlin if (!s) 60442281ac9SMark McLoughlin return -1; 605564f63e3SMark McLoughlin snprintf(s->nc.info_str, sizeof(s->nc.info_str), 60642281ac9SMark McLoughlin "socket: connect to %s:%d", 60742281ac9SMark McLoughlin inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); 60842281ac9SMark McLoughlin return 0; 60942281ac9SMark McLoughlin } 61042281ac9SMark McLoughlin 6114e68f7a0SStefan Hajnoczi static int net_socket_mcast_init(NetClientState *peer, 61242281ac9SMark McLoughlin const char *model, 61342281ac9SMark McLoughlin const char *name, 6143a75e74cSMike Ryan const char *host_str, 6153a75e74cSMike Ryan const char *localaddr_str) 61642281ac9SMark McLoughlin { 61742281ac9SMark McLoughlin NetSocketState *s; 61842281ac9SMark McLoughlin int fd; 61942281ac9SMark McLoughlin struct sockaddr_in saddr; 6203a75e74cSMike Ryan struct in_addr localaddr, *param_localaddr; 62142281ac9SMark McLoughlin 62242281ac9SMark McLoughlin if (parse_host_port(&saddr, host_str) < 0) 62342281ac9SMark McLoughlin return -1; 62442281ac9SMark McLoughlin 6253a75e74cSMike Ryan if (localaddr_str != NULL) { 6263a75e74cSMike Ryan if (inet_aton(localaddr_str, &localaddr) == 0) 6273a75e74cSMike Ryan return -1; 6283a75e74cSMike Ryan param_localaddr = &localaddr; 6293a75e74cSMike Ryan } else { 6303a75e74cSMike Ryan param_localaddr = NULL; 6313a75e74cSMike Ryan } 63242281ac9SMark McLoughlin 6333a75e74cSMike Ryan fd = net_socket_mcast_create(&saddr, param_localaddr); 63442281ac9SMark McLoughlin if (fd < 0) 63542281ac9SMark McLoughlin return -1; 63642281ac9SMark McLoughlin 637d33d93b2SStefan Hajnoczi s = net_socket_fd_init(peer, model, name, fd, 0); 63842281ac9SMark McLoughlin if (!s) 63942281ac9SMark McLoughlin return -1; 64042281ac9SMark McLoughlin 64142281ac9SMark McLoughlin s->dgram_dst = saddr; 64242281ac9SMark McLoughlin 643564f63e3SMark McLoughlin snprintf(s->nc.info_str, sizeof(s->nc.info_str), 64442281ac9SMark McLoughlin "socket: mcast=%s:%d", 64542281ac9SMark McLoughlin inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); 64642281ac9SMark McLoughlin return 0; 64742281ac9SMark McLoughlin 64842281ac9SMark McLoughlin } 64942281ac9SMark McLoughlin 6504e68f7a0SStefan Hajnoczi static int net_socket_udp_init(NetClientState *peer, 6510e0e7facSBenjamin const char *model, 6520e0e7facSBenjamin const char *name, 6530e0e7facSBenjamin const char *rhost, 6540e0e7facSBenjamin const char *lhost) 6550e0e7facSBenjamin { 6560e0e7facSBenjamin NetSocketState *s; 657bcbe92fbSSebastian Ottlik int fd, ret; 6580e0e7facSBenjamin struct sockaddr_in laddr, raddr; 6590e0e7facSBenjamin 6600e0e7facSBenjamin if (parse_host_port(&laddr, lhost) < 0) { 6610e0e7facSBenjamin return -1; 6620e0e7facSBenjamin } 6630e0e7facSBenjamin 6640e0e7facSBenjamin if (parse_host_port(&raddr, rhost) < 0) { 6650e0e7facSBenjamin return -1; 6660e0e7facSBenjamin } 6670e0e7facSBenjamin 6680e0e7facSBenjamin fd = qemu_socket(PF_INET, SOCK_DGRAM, 0); 6690e0e7facSBenjamin if (fd < 0) { 6700e0e7facSBenjamin perror("socket(PF_INET, SOCK_DGRAM)"); 6710e0e7facSBenjamin return -1; 6720e0e7facSBenjamin } 673bcbe92fbSSebastian Ottlik 674bcbe92fbSSebastian Ottlik ret = socket_set_fast_reuse(fd); 6750e0e7facSBenjamin if (ret < 0) { 6760e0e7facSBenjamin closesocket(fd); 6770e0e7facSBenjamin return -1; 6780e0e7facSBenjamin } 6790e0e7facSBenjamin ret = bind(fd, (struct sockaddr *)&laddr, sizeof(laddr)); 6800e0e7facSBenjamin if (ret < 0) { 6810e0e7facSBenjamin perror("bind"); 6820e0e7facSBenjamin closesocket(fd); 6830e0e7facSBenjamin return -1; 6840e0e7facSBenjamin } 685fc13fa00SStefan Hajnoczi qemu_set_nonblock(fd); 6860e0e7facSBenjamin 687d33d93b2SStefan Hajnoczi s = net_socket_fd_init(peer, model, name, fd, 0); 6880e0e7facSBenjamin if (!s) { 6890e0e7facSBenjamin return -1; 6900e0e7facSBenjamin } 6910e0e7facSBenjamin 6920e0e7facSBenjamin s->dgram_dst = raddr; 6930e0e7facSBenjamin 6940e0e7facSBenjamin snprintf(s->nc.info_str, sizeof(s->nc.info_str), 6950e0e7facSBenjamin "socket: udp=%s:%d", 6960e0e7facSBenjamin inet_ntoa(raddr.sin_addr), ntohs(raddr.sin_port)); 6970e0e7facSBenjamin return 0; 6980e0e7facSBenjamin } 6990e0e7facSBenjamin 7001a0c0958SLaszlo Ersek int net_init_socket(const NetClientOptions *opts, const char *name, 701a30ecde6SMarkus Armbruster NetClientState *peer, Error **errp) 70242281ac9SMark McLoughlin { 703a30ecde6SMarkus Armbruster /* FIXME error_setg(errp, ...) on failure */ 7041677f4c6SMarkus Armbruster Error *err = NULL; 705bef8e8feSLaszlo Ersek const NetdevSocketOptions *sock; 706bef8e8feSLaszlo Ersek 7078d0bcba8SEric Blake assert(opts->type == NET_CLIENT_OPTIONS_KIND_SOCKET); 70832bafa8fSEric Blake sock = opts->u.socket.data; 709bef8e8feSLaszlo Ersek 710bef8e8feSLaszlo Ersek if (sock->has_fd + sock->has_listen + sock->has_connect + sock->has_mcast + 711bef8e8feSLaszlo Ersek sock->has_udp != 1) { 712bef8e8feSLaszlo Ersek error_report("exactly one of fd=, listen=, connect=, mcast= or udp=" 713bef8e8feSLaszlo Ersek " is required"); 714bef8e8feSLaszlo Ersek return -1; 715bef8e8feSLaszlo Ersek } 716bef8e8feSLaszlo Ersek 717bef8e8feSLaszlo Ersek if (sock->has_localaddr && !sock->has_mcast && !sock->has_udp) { 718bef8e8feSLaszlo Ersek error_report("localaddr= is only valid with mcast= or udp="); 719bef8e8feSLaszlo Ersek return -1; 720bef8e8feSLaszlo Ersek } 721bef8e8feSLaszlo Ersek 722bef8e8feSLaszlo Ersek if (sock->has_fd) { 72342281ac9SMark McLoughlin int fd; 72442281ac9SMark McLoughlin 7251677f4c6SMarkus Armbruster fd = monitor_fd_param(cur_mon, sock->fd, &err); 726fc13fa00SStefan Hajnoczi if (fd == -1) { 7271677f4c6SMarkus Armbruster error_report_err(err); 728fc13fa00SStefan Hajnoczi return -1; 729fc13fa00SStefan Hajnoczi } 730fc13fa00SStefan Hajnoczi qemu_set_nonblock(fd); 731fc13fa00SStefan Hajnoczi if (!net_socket_fd_init(peer, "socket", name, fd, 1)) { 73242281ac9SMark McLoughlin return -1; 73342281ac9SMark McLoughlin } 734bef8e8feSLaszlo Ersek return 0; 73542281ac9SMark McLoughlin } 73642281ac9SMark McLoughlin 737bef8e8feSLaszlo Ersek if (sock->has_listen) { 738d33d93b2SStefan Hajnoczi if (net_socket_listen_init(peer, "socket", name, sock->listen) == -1) { 73942281ac9SMark McLoughlin return -1; 74042281ac9SMark McLoughlin } 741bef8e8feSLaszlo Ersek return 0; 74242281ac9SMark McLoughlin } 74342281ac9SMark McLoughlin 744bef8e8feSLaszlo Ersek if (sock->has_connect) { 745d33d93b2SStefan Hajnoczi if (net_socket_connect_init(peer, "socket", name, sock->connect) == 746bef8e8feSLaszlo Ersek -1) { 74742281ac9SMark McLoughlin return -1; 74842281ac9SMark McLoughlin } 749bef8e8feSLaszlo Ersek return 0; 75042281ac9SMark McLoughlin } 75142281ac9SMark McLoughlin 752bef8e8feSLaszlo Ersek if (sock->has_mcast) { 753bef8e8feSLaszlo Ersek /* if sock->localaddr is missing, it has been initialized to "all bits 754bef8e8feSLaszlo Ersek * zero" */ 755d33d93b2SStefan Hajnoczi if (net_socket_mcast_init(peer, "socket", name, sock->mcast, 756bef8e8feSLaszlo Ersek sock->localaddr) == -1) { 75742281ac9SMark McLoughlin return -1; 75842281ac9SMark McLoughlin } 759bef8e8feSLaszlo Ersek return 0; 76042281ac9SMark McLoughlin } 76142281ac9SMark McLoughlin 762bef8e8feSLaszlo Ersek assert(sock->has_udp); 763bef8e8feSLaszlo Ersek if (!sock->has_localaddr) { 7640e0e7facSBenjamin error_report("localaddr= is mandatory with udp="); 7650e0e7facSBenjamin return -1; 7660e0e7facSBenjamin } 767f0e3ac70SLei Li if (net_socket_udp_init(peer, "socket", name, sock->udp, sock->localaddr) == 768bef8e8feSLaszlo Ersek -1) { 7690e0e7facSBenjamin return -1; 7700e0e7facSBenjamin } 77142281ac9SMark McLoughlin return 0; 77242281ac9SMark McLoughlin } 773