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" 29da34e65cSMarkus Armbruster #include "qapi/error.h" 301de7afc9SPaolo Bonzini #include "qemu/error-report.h" 311de7afc9SPaolo Bonzini #include "qemu/option.h" 321de7afc9SPaolo Bonzini #include "qemu/sockets.h" 331de7afc9SPaolo Bonzini #include "qemu/iov.h" 346a1751b7SAlex Bligh #include "qemu/main-loop.h" 3542281ac9SMark McLoughlin 3642281ac9SMark McLoughlin typedef struct NetSocketState { 374e68f7a0SStefan Hajnoczi NetClientState nc; 38011de2b5SZhi Yong Wu int listen_fd; 3942281ac9SMark McLoughlin int fd; 4016a3df40SZhang Chen SocketReadState rs; 4145a7f54aSStefan Hajnoczi unsigned int send_index; /* number of bytes sent (only SOCK_STREAM) */ 4242281ac9SMark McLoughlin struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */ 43863f678fSStefan Hajnoczi IOHandler *send_fn; /* differs between SOCK_STREAM/SOCK_DGRAM */ 44863f678fSStefan Hajnoczi bool read_poll; /* waiting to receive data? */ 45863f678fSStefan Hajnoczi bool write_poll; /* waiting to transmit data? */ 4642281ac9SMark McLoughlin } NetSocketState; 4742281ac9SMark McLoughlin 48011de2b5SZhi Yong Wu static void net_socket_accept(void *opaque); 49863f678fSStefan Hajnoczi static void net_socket_writable(void *opaque); 50863f678fSStefan Hajnoczi 51863f678fSStefan Hajnoczi static void net_socket_update_fd_handler(NetSocketState *s) 52863f678fSStefan Hajnoczi { 5382e1cc4bSFam Zheng qemu_set_fd_handler(s->fd, 54863f678fSStefan Hajnoczi s->read_poll ? s->send_fn : NULL, 55863f678fSStefan Hajnoczi s->write_poll ? net_socket_writable : NULL, 56863f678fSStefan Hajnoczi s); 57863f678fSStefan Hajnoczi } 58863f678fSStefan Hajnoczi 59863f678fSStefan Hajnoczi static void net_socket_read_poll(NetSocketState *s, bool enable) 60863f678fSStefan Hajnoczi { 61863f678fSStefan Hajnoczi s->read_poll = enable; 62863f678fSStefan Hajnoczi net_socket_update_fd_handler(s); 63863f678fSStefan Hajnoczi } 64863f678fSStefan Hajnoczi 65863f678fSStefan Hajnoczi static void net_socket_write_poll(NetSocketState *s, bool enable) 66863f678fSStefan Hajnoczi { 67863f678fSStefan Hajnoczi s->write_poll = enable; 68863f678fSStefan Hajnoczi net_socket_update_fd_handler(s); 69863f678fSStefan Hajnoczi } 70863f678fSStefan Hajnoczi 71863f678fSStefan Hajnoczi static void net_socket_writable(void *opaque) 72863f678fSStefan Hajnoczi { 73863f678fSStefan Hajnoczi NetSocketState *s = opaque; 74863f678fSStefan Hajnoczi 75863f678fSStefan Hajnoczi net_socket_write_poll(s, false); 76863f678fSStefan Hajnoczi 77863f678fSStefan Hajnoczi qemu_flush_queued_packets(&s->nc); 78863f678fSStefan Hajnoczi } 7942281ac9SMark McLoughlin 804e68f7a0SStefan Hajnoczi static ssize_t net_socket_receive(NetClientState *nc, const uint8_t *buf, size_t size) 8142281ac9SMark McLoughlin { 82564f63e3SMark McLoughlin NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); 8345a7f54aSStefan Hajnoczi uint32_t len = htonl(size); 8445a7f54aSStefan Hajnoczi struct iovec iov[] = { 8545a7f54aSStefan Hajnoczi { 8645a7f54aSStefan Hajnoczi .iov_base = &len, 8745a7f54aSStefan Hajnoczi .iov_len = sizeof(len), 8845a7f54aSStefan Hajnoczi }, { 8945a7f54aSStefan Hajnoczi .iov_base = (void *)buf, 9045a7f54aSStefan Hajnoczi .iov_len = size, 9145a7f54aSStefan Hajnoczi }, 9245a7f54aSStefan Hajnoczi }; 9345a7f54aSStefan Hajnoczi size_t remaining; 9445a7f54aSStefan Hajnoczi ssize_t ret; 9542281ac9SMark McLoughlin 9645a7f54aSStefan Hajnoczi remaining = iov_size(iov, 2) - s->send_index; 9745a7f54aSStefan Hajnoczi ret = iov_send(s->fd, iov, 2, s->send_index, remaining); 9845a7f54aSStefan Hajnoczi 9945a7f54aSStefan Hajnoczi if (ret == -1 && errno == EAGAIN) { 10045a7f54aSStefan Hajnoczi ret = 0; /* handled further down */ 10145a7f54aSStefan Hajnoczi } 10245a7f54aSStefan Hajnoczi if (ret == -1) { 10345a7f54aSStefan Hajnoczi s->send_index = 0; 10445a7f54aSStefan Hajnoczi return -errno; 10545a7f54aSStefan Hajnoczi } 10645a7f54aSStefan Hajnoczi if (ret < (ssize_t)remaining) { 10745a7f54aSStefan Hajnoczi s->send_index += ret; 10845a7f54aSStefan Hajnoczi net_socket_write_poll(s, true); 10945a7f54aSStefan Hajnoczi return 0; 11045a7f54aSStefan Hajnoczi } 11145a7f54aSStefan Hajnoczi s->send_index = 0; 11245a7f54aSStefan Hajnoczi return size; 11342281ac9SMark McLoughlin } 11442281ac9SMark McLoughlin 1154e68f7a0SStefan Hajnoczi static ssize_t net_socket_receive_dgram(NetClientState *nc, const uint8_t *buf, size_t size) 11642281ac9SMark McLoughlin { 117564f63e3SMark McLoughlin NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); 118213fd508SStefan Hajnoczi ssize_t ret; 11942281ac9SMark McLoughlin 120213fd508SStefan Hajnoczi do { 121fdec16e3SMarc-André Lureau if (s->dgram_dst.sin_family != AF_UNIX) { 122e7b79428SMarc-André Lureau ret = sendto(s->fd, buf, size, 0, 123213fd508SStefan Hajnoczi (struct sockaddr *)&s->dgram_dst, 124213fd508SStefan Hajnoczi sizeof(s->dgram_dst)); 125fdec16e3SMarc-André Lureau } else { 126fdec16e3SMarc-André Lureau ret = send(s->fd, buf, size, 0); 127fdec16e3SMarc-André Lureau } 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 14616a3df40SZhang Chen static void net_socket_rs_finalize(SocketReadState *rs) 14716a3df40SZhang Chen { 14816a3df40SZhang Chen NetSocketState *s = container_of(rs, NetSocketState, rs); 14916a3df40SZhang Chen 15016a3df40SZhang Chen if (qemu_send_packet_async(&s->nc, rs->buf, 15116a3df40SZhang Chen rs->packet_len, 15216a3df40SZhang Chen net_socket_send_completed) == 0) { 15316a3df40SZhang Chen net_socket_read_poll(s, false); 15416a3df40SZhang Chen } 15516a3df40SZhang Chen } 15616a3df40SZhang Chen 15742281ac9SMark McLoughlin static void net_socket_send(void *opaque) 15842281ac9SMark McLoughlin { 15942281ac9SMark McLoughlin NetSocketState *s = opaque; 160b16a44e1SDaniel P. Berrange int size; 16116a3df40SZhang Chen int ret; 162d32fcad3SScott Feldman uint8_t buf1[NET_BUFSIZE]; 16342281ac9SMark McLoughlin const uint8_t *buf; 16442281ac9SMark McLoughlin 165e7b79428SMarc-André Lureau size = recv(s->fd, buf1, sizeof(buf1), 0); 16642281ac9SMark McLoughlin if (size < 0) { 167b16a44e1SDaniel P. Berrange if (errno != EWOULDBLOCK) 16842281ac9SMark McLoughlin goto eoc; 16942281ac9SMark McLoughlin } else if (size == 0) { 17042281ac9SMark McLoughlin /* end of connection */ 17142281ac9SMark McLoughlin eoc: 172863f678fSStefan Hajnoczi net_socket_read_poll(s, false); 173863f678fSStefan Hajnoczi net_socket_write_poll(s, false); 174011de2b5SZhi Yong Wu if (s->listen_fd != -1) { 175011de2b5SZhi Yong Wu qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s); 176011de2b5SZhi Yong Wu } 17742281ac9SMark McLoughlin closesocket(s->fd); 178011de2b5SZhi Yong Wu 179011de2b5SZhi Yong Wu s->fd = -1; 1803cde5ea2SZhang Chen net_socket_rs_init(&s->rs, net_socket_rs_finalize, false); 181011de2b5SZhi Yong Wu s->nc.link_down = true; 18256e6f594SJason Wang memset(s->nc.info_str, 0, sizeof(s->nc.info_str)); 183011de2b5SZhi Yong Wu 18442281ac9SMark McLoughlin return; 18542281ac9SMark McLoughlin } 18642281ac9SMark McLoughlin buf = buf1; 18742281ac9SMark McLoughlin 18816a3df40SZhang Chen ret = net_fill_rstate(&s->rs, buf, size); 18916a3df40SZhang Chen 19016a3df40SZhang Chen if (ret == -1) { 19116a3df40SZhang Chen goto eoc; 19242281ac9SMark McLoughlin } 19342281ac9SMark McLoughlin } 19442281ac9SMark McLoughlin 19542281ac9SMark McLoughlin static void net_socket_send_dgram(void *opaque) 19642281ac9SMark McLoughlin { 19742281ac9SMark McLoughlin NetSocketState *s = opaque; 19842281ac9SMark McLoughlin int size; 19942281ac9SMark McLoughlin 200e7b79428SMarc-André Lureau size = recv(s->fd, s->rs.buf, sizeof(s->rs.buf), 0); 20142281ac9SMark McLoughlin if (size < 0) 20242281ac9SMark McLoughlin return; 20342281ac9SMark McLoughlin if (size == 0) { 20442281ac9SMark McLoughlin /* end of connection */ 205863f678fSStefan Hajnoczi net_socket_read_poll(s, false); 206863f678fSStefan Hajnoczi net_socket_write_poll(s, false); 20742281ac9SMark McLoughlin return; 20842281ac9SMark McLoughlin } 20916a3df40SZhang Chen if (qemu_send_packet_async(&s->nc, s->rs.buf, size, 2106e99c631SFam Zheng net_socket_send_completed) == 0) { 2116e99c631SFam Zheng net_socket_read_poll(s, false); 2126e99c631SFam Zheng } 21342281ac9SMark McLoughlin } 21442281ac9SMark McLoughlin 215c37f0bb1SMao Zhongyi static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, 216c37f0bb1SMao Zhongyi struct in_addr *localaddr, 217c37f0bb1SMao Zhongyi Error **errp) 21842281ac9SMark McLoughlin { 21942281ac9SMark McLoughlin struct ip_mreq imr; 22042281ac9SMark McLoughlin int fd; 22142281ac9SMark McLoughlin int val, ret; 22223ddf2bbSBrad #ifdef __OpenBSD__ 22323ddf2bbSBrad unsigned char loop; 22423ddf2bbSBrad #else 22523ddf2bbSBrad int loop; 22623ddf2bbSBrad #endif 22723ddf2bbSBrad 22842281ac9SMark McLoughlin if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) { 229c37f0bb1SMao Zhongyi error_setg(errp, "specified mcastaddr %s (0x%08x) " 230c37f0bb1SMao Zhongyi "does not contain a multicast address", 23142281ac9SMark McLoughlin inet_ntoa(mcastaddr->sin_addr), 23242281ac9SMark McLoughlin (int)ntohl(mcastaddr->sin_addr.s_addr)); 23342281ac9SMark McLoughlin return -1; 23442281ac9SMark McLoughlin } 235c37f0bb1SMao Zhongyi 23640ff6d7eSKevin Wolf fd = qemu_socket(PF_INET, SOCK_DGRAM, 0); 23742281ac9SMark McLoughlin if (fd < 0) { 238c37f0bb1SMao Zhongyi error_setg_errno(errp, errno, "can't create datagram socket"); 23942281ac9SMark McLoughlin return -1; 24042281ac9SMark McLoughlin } 24142281ac9SMark McLoughlin 242bcbe92fbSSebastian Ottlik /* Allow multiple sockets to bind the same multicast ip and port by setting 243bcbe92fbSSebastian Ottlik * SO_REUSEADDR. This is the only situation where SO_REUSEADDR should be set 244bcbe92fbSSebastian Ottlik * on windows. Use socket_set_fast_reuse otherwise as it sets SO_REUSEADDR 245bcbe92fbSSebastian Ottlik * only on posix systems. 246bcbe92fbSSebastian Ottlik */ 24742281ac9SMark McLoughlin val = 1; 248e7b79428SMarc-André Lureau ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); 24942281ac9SMark McLoughlin if (ret < 0) { 250c37f0bb1SMao Zhongyi error_setg_errno(errp, errno, 251c37f0bb1SMao Zhongyi "can't set socket option SO_REUSEADDR"); 25242281ac9SMark McLoughlin goto fail; 25342281ac9SMark McLoughlin } 25442281ac9SMark McLoughlin 25542281ac9SMark McLoughlin ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr)); 25642281ac9SMark McLoughlin if (ret < 0) { 257c37f0bb1SMao Zhongyi error_setg_errno(errp, errno, "can't bind ip=%s to socket", 258c37f0bb1SMao Zhongyi inet_ntoa(mcastaddr->sin_addr)); 25942281ac9SMark McLoughlin goto fail; 26042281ac9SMark McLoughlin } 26142281ac9SMark McLoughlin 26242281ac9SMark McLoughlin /* Add host to multicast group */ 26342281ac9SMark McLoughlin imr.imr_multiaddr = mcastaddr->sin_addr; 2643a75e74cSMike Ryan if (localaddr) { 2653a75e74cSMike Ryan imr.imr_interface = *localaddr; 2663a75e74cSMike Ryan } else { 26742281ac9SMark McLoughlin imr.imr_interface.s_addr = htonl(INADDR_ANY); 2683a75e74cSMike Ryan } 26942281ac9SMark McLoughlin 270e7b79428SMarc-André Lureau ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, 2719957fc7fSStefan Weil &imr, sizeof(struct ip_mreq)); 27242281ac9SMark McLoughlin if (ret < 0) { 273c37f0bb1SMao Zhongyi error_setg_errno(errp, errno, 274c37f0bb1SMao Zhongyi "can't add socket to multicast group %s", 275c37f0bb1SMao Zhongyi inet_ntoa(imr.imr_multiaddr)); 27642281ac9SMark McLoughlin goto fail; 27742281ac9SMark McLoughlin } 27842281ac9SMark McLoughlin 27942281ac9SMark McLoughlin /* Force mcast msgs to loopback (eg. several QEMUs in same host */ 28023ddf2bbSBrad loop = 1; 281e7b79428SMarc-André Lureau ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, 2829957fc7fSStefan Weil &loop, sizeof(loop)); 28342281ac9SMark McLoughlin if (ret < 0) { 284c37f0bb1SMao Zhongyi error_setg_errno(errp, errno, 285c37f0bb1SMao Zhongyi "can't force multicast message to loopback"); 28642281ac9SMark McLoughlin goto fail; 28742281ac9SMark McLoughlin } 28842281ac9SMark McLoughlin 2893a75e74cSMike Ryan /* If a bind address is given, only send packets from that address */ 2903a75e74cSMike Ryan if (localaddr != NULL) { 291e7b79428SMarc-André Lureau ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, 2929957fc7fSStefan Weil localaddr, sizeof(*localaddr)); 2933a75e74cSMike Ryan if (ret < 0) { 294c37f0bb1SMao Zhongyi error_setg_errno(errp, errno, 295c37f0bb1SMao Zhongyi "can't set the default network send interface"); 2963a75e74cSMike Ryan goto fail; 2973a75e74cSMike Ryan } 2983a75e74cSMike Ryan } 2993a75e74cSMike Ryan 300*ff5927baSMarc-André Lureau qemu_socket_set_nonblock(fd); 30142281ac9SMark McLoughlin return fd; 30242281ac9SMark McLoughlin fail: 30342281ac9SMark McLoughlin if (fd >= 0) 30442281ac9SMark McLoughlin closesocket(fd); 30542281ac9SMark McLoughlin return -1; 30642281ac9SMark McLoughlin } 30742281ac9SMark McLoughlin 3084e68f7a0SStefan Hajnoczi static void net_socket_cleanup(NetClientState *nc) 30942281ac9SMark McLoughlin { 310564f63e3SMark McLoughlin NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); 311011de2b5SZhi Yong Wu if (s->fd != -1) { 312863f678fSStefan Hajnoczi net_socket_read_poll(s, false); 313863f678fSStefan Hajnoczi net_socket_write_poll(s, false); 31442281ac9SMark McLoughlin close(s->fd); 315011de2b5SZhi Yong Wu s->fd = -1; 316011de2b5SZhi Yong Wu } 317011de2b5SZhi Yong Wu if (s->listen_fd != -1) { 318011de2b5SZhi Yong Wu qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL); 319011de2b5SZhi Yong Wu closesocket(s->listen_fd); 320011de2b5SZhi Yong Wu s->listen_fd = -1; 321011de2b5SZhi Yong Wu } 32242281ac9SMark McLoughlin } 32342281ac9SMark McLoughlin 324564f63e3SMark McLoughlin static NetClientInfo net_dgram_socket_info = { 325f394b2e2SEric Blake .type = NET_CLIENT_DRIVER_SOCKET, 326564f63e3SMark McLoughlin .size = sizeof(NetSocketState), 327564f63e3SMark McLoughlin .receive = net_socket_receive_dgram, 328564f63e3SMark McLoughlin .cleanup = net_socket_cleanup, 329564f63e3SMark McLoughlin }; 330564f63e3SMark McLoughlin 3314e68f7a0SStefan Hajnoczi static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer, 33242281ac9SMark McLoughlin const char *model, 33342281ac9SMark McLoughlin const char *name, 3340f8c289aSJens Freimann int fd, int is_connected, 335c37f0bb1SMao Zhongyi const char *mcast, 336c37f0bb1SMao Zhongyi Error **errp) 33742281ac9SMark McLoughlin { 33842281ac9SMark McLoughlin struct sockaddr_in saddr; 33942281ac9SMark McLoughlin int newfd; 3404e68f7a0SStefan Hajnoczi NetClientState *nc; 34142281ac9SMark McLoughlin NetSocketState *s; 342fdec16e3SMarc-André Lureau SocketAddress *sa; 343fdec16e3SMarc-André Lureau SocketAddressType sa_type; 344fdec16e3SMarc-André Lureau 345fdec16e3SMarc-André Lureau sa = socket_local_address(fd, errp); 346fdec16e3SMarc-André Lureau if (!sa) { 347fdec16e3SMarc-André Lureau return NULL; 348fdec16e3SMarc-André Lureau } 349fdec16e3SMarc-André Lureau sa_type = sa->type; 350fdec16e3SMarc-André Lureau qapi_free_SocketAddress(sa); 35142281ac9SMark McLoughlin 35242281ac9SMark McLoughlin /* fd passed: multicast: "learn" dgram_dst address from bound address and save it 35342281ac9SMark McLoughlin * Because this may be "shared" socket from a "master" process, datagrams would be recv() 35442281ac9SMark McLoughlin * by ONLY ONE process: we must "clone" this dgram socket --jjo 35542281ac9SMark McLoughlin */ 35642281ac9SMark McLoughlin 3570f8c289aSJens Freimann if (is_connected && mcast != NULL) { 358bcd4dfd6SMao Zhongyi if (parse_host_port(&saddr, mcast, errp) < 0) { 3590f8c289aSJens Freimann goto err; 3600f8c289aSJens Freimann } 36142281ac9SMark McLoughlin /* must be bound */ 36242281ac9SMark McLoughlin if (saddr.sin_addr.s_addr == 0) { 363c37f0bb1SMao Zhongyi error_setg(errp, "can't setup multicast destination address"); 364e5d1fca0SStefan Hajnoczi goto err; 36542281ac9SMark McLoughlin } 36642281ac9SMark McLoughlin /* clone dgram socket */ 367c37f0bb1SMao Zhongyi newfd = net_socket_mcast_create(&saddr, NULL, errp); 36842281ac9SMark McLoughlin if (newfd < 0) { 369e5d1fca0SStefan Hajnoczi goto err; 37042281ac9SMark McLoughlin } 37142281ac9SMark McLoughlin /* clone newfd to fd, close newfd */ 37242281ac9SMark McLoughlin dup2(newfd, fd); 37342281ac9SMark McLoughlin close(newfd); 37442281ac9SMark McLoughlin 37542281ac9SMark McLoughlin } 37642281ac9SMark McLoughlin 377ab5f3f84SStefan Hajnoczi nc = qemu_new_net_client(&net_dgram_socket_info, peer, model, name); 378564f63e3SMark McLoughlin 379564f63e3SMark McLoughlin s = DO_UPCAST(NetSocketState, nc, nc); 380564f63e3SMark McLoughlin 38142281ac9SMark McLoughlin s->fd = fd; 382011de2b5SZhi Yong Wu s->listen_fd = -1; 383863f678fSStefan Hajnoczi s->send_fn = net_socket_send_dgram; 3843cde5ea2SZhang Chen net_socket_rs_init(&s->rs, net_socket_rs_finalize, false); 385863f678fSStefan Hajnoczi net_socket_read_poll(s, true); 38642281ac9SMark McLoughlin 38742281ac9SMark McLoughlin /* mcast: save bound address as dst */ 388bb160b57SJens Freimann if (is_connected && mcast != NULL) { 389e34cde35SZhi Yong Wu s->dgram_dst = saddr; 39056e6f594SJason Wang snprintf(nc->info_str, sizeof(nc->info_str), 39156e6f594SJason Wang "socket: fd=%d (cloned mcast=%s:%d)", 39256e6f594SJason Wang fd, inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); 3938db804acSGonglei } else { 394fdec16e3SMarc-André Lureau if (sa_type == SOCKET_ADDRESS_TYPE_UNIX) { 395fdec16e3SMarc-André Lureau s->dgram_dst.sin_family = AF_UNIX; 396fdec16e3SMarc-André Lureau } 397d89b4f83SJason Wang 39856e6f594SJason Wang snprintf(nc->info_str, sizeof(nc->info_str), 39956e6f594SJason Wang "socket: fd=%d %s", fd, SocketAddressType_str(sa_type)); 400e34cde35SZhi Yong Wu } 40142281ac9SMark McLoughlin 40242281ac9SMark McLoughlin return s; 403e5d1fca0SStefan Hajnoczi 404e5d1fca0SStefan Hajnoczi err: 405e5d1fca0SStefan Hajnoczi closesocket(fd); 406e5d1fca0SStefan Hajnoczi return NULL; 40742281ac9SMark McLoughlin } 40842281ac9SMark McLoughlin 40942281ac9SMark McLoughlin static void net_socket_connect(void *opaque) 41042281ac9SMark McLoughlin { 41142281ac9SMark McLoughlin NetSocketState *s = opaque; 412863f678fSStefan Hajnoczi s->send_fn = net_socket_send; 413863f678fSStefan Hajnoczi net_socket_read_poll(s, true); 41442281ac9SMark McLoughlin } 41542281ac9SMark McLoughlin 416564f63e3SMark McLoughlin static NetClientInfo net_socket_info = { 417f394b2e2SEric Blake .type = NET_CLIENT_DRIVER_SOCKET, 418564f63e3SMark McLoughlin .size = sizeof(NetSocketState), 419564f63e3SMark McLoughlin .receive = net_socket_receive, 420564f63e3SMark McLoughlin .cleanup = net_socket_cleanup, 421564f63e3SMark McLoughlin }; 422564f63e3SMark McLoughlin 4234e68f7a0SStefan Hajnoczi static NetSocketState *net_socket_fd_init_stream(NetClientState *peer, 42442281ac9SMark McLoughlin const char *model, 42542281ac9SMark McLoughlin const char *name, 42642281ac9SMark McLoughlin int fd, int is_connected) 42742281ac9SMark McLoughlin { 4284e68f7a0SStefan Hajnoczi NetClientState *nc; 42942281ac9SMark McLoughlin NetSocketState *s; 430564f63e3SMark McLoughlin 431ab5f3f84SStefan Hajnoczi nc = qemu_new_net_client(&net_socket_info, peer, model, name); 432564f63e3SMark McLoughlin 43356e6f594SJason Wang snprintf(nc->info_str, sizeof(nc->info_str), "socket: fd=%d", fd); 434d89b4f83SJason Wang 435564f63e3SMark McLoughlin s = DO_UPCAST(NetSocketState, nc, nc); 436564f63e3SMark McLoughlin 43742281ac9SMark McLoughlin s->fd = fd; 438011de2b5SZhi Yong Wu s->listen_fd = -1; 4393cde5ea2SZhang Chen net_socket_rs_init(&s->rs, net_socket_rs_finalize, false); 440564f63e3SMark McLoughlin 44120048d0aSStefan Hajnoczi /* Disable Nagle algorithm on TCP sockets to reduce latency */ 44220048d0aSStefan Hajnoczi socket_set_nodelay(fd); 44320048d0aSStefan Hajnoczi 44442281ac9SMark McLoughlin if (is_connected) { 44542281ac9SMark McLoughlin net_socket_connect(s); 44642281ac9SMark McLoughlin } else { 44742281ac9SMark McLoughlin qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s); 44842281ac9SMark McLoughlin } 44942281ac9SMark McLoughlin return s; 45042281ac9SMark McLoughlin } 45142281ac9SMark McLoughlin 4524e68f7a0SStefan Hajnoczi static NetSocketState *net_socket_fd_init(NetClientState *peer, 45342281ac9SMark McLoughlin const char *model, const char *name, 454c37f0bb1SMao Zhongyi int fd, int is_connected, 455c37f0bb1SMao Zhongyi const char *mc, Error **errp) 45642281ac9SMark McLoughlin { 45742281ac9SMark McLoughlin int so_type = -1, optlen=sizeof(so_type); 45842281ac9SMark McLoughlin 45942281ac9SMark McLoughlin if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type, 46042281ac9SMark McLoughlin (socklen_t *)&optlen)< 0) { 461c37f0bb1SMao Zhongyi error_setg(errp, "can't get socket option SO_TYPE"); 462e5d1fca0SStefan Hajnoczi closesocket(fd); 46342281ac9SMark McLoughlin return NULL; 46442281ac9SMark McLoughlin } 46542281ac9SMark McLoughlin switch(so_type) { 46642281ac9SMark McLoughlin case SOCK_DGRAM: 467c37f0bb1SMao Zhongyi return net_socket_fd_init_dgram(peer, model, name, fd, is_connected, 468c37f0bb1SMao Zhongyi mc, errp); 46942281ac9SMark McLoughlin case SOCK_STREAM: 470d33d93b2SStefan Hajnoczi return net_socket_fd_init_stream(peer, model, name, fd, is_connected); 47142281ac9SMark McLoughlin default: 4728c42dbe3SMarkus Armbruster error_setg(errp, "socket type=%d for fd=%d must be either" 473e1b24b64SMao Zhongyi " SOCK_DGRAM or SOCK_STREAM", so_type, fd); 474e1b24b64SMao Zhongyi closesocket(fd); 47542281ac9SMark McLoughlin } 47642281ac9SMark McLoughlin return NULL; 47742281ac9SMark McLoughlin } 47842281ac9SMark McLoughlin 47942281ac9SMark McLoughlin static void net_socket_accept(void *opaque) 48042281ac9SMark McLoughlin { 481011de2b5SZhi Yong Wu NetSocketState *s = opaque; 48242281ac9SMark McLoughlin struct sockaddr_in saddr; 48342281ac9SMark McLoughlin socklen_t len; 48442281ac9SMark McLoughlin int fd; 48542281ac9SMark McLoughlin 48642281ac9SMark McLoughlin for(;;) { 48742281ac9SMark McLoughlin len = sizeof(saddr); 488011de2b5SZhi Yong Wu fd = qemu_accept(s->listen_fd, (struct sockaddr *)&saddr, &len); 48942281ac9SMark McLoughlin if (fd < 0 && errno != EINTR) { 49042281ac9SMark McLoughlin return; 49142281ac9SMark McLoughlin } else if (fd >= 0) { 492011de2b5SZhi Yong Wu qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL); 49342281ac9SMark McLoughlin break; 49442281ac9SMark McLoughlin } 49542281ac9SMark McLoughlin } 496011de2b5SZhi Yong Wu 497011de2b5SZhi Yong Wu s->fd = fd; 498011de2b5SZhi Yong Wu s->nc.link_down = false; 499011de2b5SZhi Yong Wu net_socket_connect(s); 50056e6f594SJason Wang snprintf(s->nc.info_str, sizeof(s->nc.info_str), 50156e6f594SJason Wang "socket: connection from %s:%d", 50256e6f594SJason Wang inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); 50342281ac9SMark McLoughlin } 50442281ac9SMark McLoughlin 5054e68f7a0SStefan Hajnoczi static int net_socket_listen_init(NetClientState *peer, 50642281ac9SMark McLoughlin const char *model, 50742281ac9SMark McLoughlin const char *name, 5080522a959SMao Zhongyi const char *host_str, 5090522a959SMao Zhongyi Error **errp) 51042281ac9SMark McLoughlin { 511011de2b5SZhi Yong Wu NetClientState *nc; 512011de2b5SZhi Yong Wu NetSocketState *s; 5136701e551SDaniel P. Berrange struct sockaddr_in saddr; 5146701e551SDaniel P. Berrange int fd, ret; 51542281ac9SMark McLoughlin 5160522a959SMao Zhongyi if (parse_host_port(&saddr, host_str, errp) < 0) { 5176701e551SDaniel P. Berrange return -1; 518bcd4dfd6SMao Zhongyi } 5196701e551SDaniel P. Berrange 5206701e551SDaniel P. Berrange fd = qemu_socket(PF_INET, SOCK_STREAM, 0); 5216701e551SDaniel P. Berrange if (fd < 0) { 5220522a959SMao Zhongyi error_setg_errno(errp, errno, "can't create stream socket"); 52342281ac9SMark McLoughlin return -1; 52442281ac9SMark McLoughlin } 525*ff5927baSMarc-André Lureau qemu_socket_set_nonblock(fd); 52642281ac9SMark McLoughlin 5276701e551SDaniel P. Berrange socket_set_fast_reuse(fd); 5286701e551SDaniel P. Berrange 5296701e551SDaniel P. Berrange ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)); 53042281ac9SMark McLoughlin if (ret < 0) { 5310522a959SMao Zhongyi error_setg_errno(errp, errno, "can't bind ip=%s to socket", 5320522a959SMao Zhongyi inet_ntoa(saddr.sin_addr)); 5336701e551SDaniel P. Berrange closesocket(fd); 5346701e551SDaniel P. Berrange return -1; 5356701e551SDaniel P. Berrange } 5366701e551SDaniel P. Berrange ret = listen(fd, 0); 5376701e551SDaniel P. Berrange if (ret < 0) { 5380522a959SMao Zhongyi error_setg_errno(errp, errno, "can't listen on socket"); 5396701e551SDaniel P. Berrange closesocket(fd); 54042281ac9SMark McLoughlin return -1; 54142281ac9SMark McLoughlin } 542011de2b5SZhi Yong Wu 543011de2b5SZhi Yong Wu nc = qemu_new_net_client(&net_socket_info, peer, model, name); 544011de2b5SZhi Yong Wu s = DO_UPCAST(NetSocketState, nc, nc); 545011de2b5SZhi Yong Wu s->fd = -1; 5466701e551SDaniel P. Berrange s->listen_fd = fd; 547011de2b5SZhi Yong Wu s->nc.link_down = true; 5483cde5ea2SZhang Chen net_socket_rs_init(&s->rs, net_socket_rs_finalize, false); 549011de2b5SZhi Yong Wu 550011de2b5SZhi Yong Wu qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s); 55142281ac9SMark McLoughlin return 0; 55242281ac9SMark McLoughlin } 55342281ac9SMark McLoughlin 5544e68f7a0SStefan Hajnoczi static int net_socket_connect_init(NetClientState *peer, 55542281ac9SMark McLoughlin const char *model, 55642281ac9SMark McLoughlin const char *name, 5570522a959SMao Zhongyi const char *host_str, 5580522a959SMao Zhongyi Error **errp) 55942281ac9SMark McLoughlin { 5606701e551SDaniel P. Berrange NetSocketState *s; 5616701e551SDaniel P. Berrange int fd, connected, ret; 5626701e551SDaniel P. Berrange struct sockaddr_in saddr; 56342281ac9SMark McLoughlin 5640522a959SMao Zhongyi if (parse_host_port(&saddr, host_str, errp) < 0) { 565883e4f76SMarc-André Lureau return -1; 566bcd4dfd6SMao Zhongyi } 5676701e551SDaniel P. Berrange 5686701e551SDaniel P. Berrange fd = qemu_socket(PF_INET, SOCK_STREAM, 0); 5696701e551SDaniel P. Berrange if (fd < 0) { 5700522a959SMao Zhongyi error_setg_errno(errp, errno, "can't create stream socket"); 5716701e551SDaniel P. Berrange return -1; 5726701e551SDaniel P. Berrange } 573*ff5927baSMarc-André Lureau qemu_socket_set_nonblock(fd); 5746701e551SDaniel P. Berrange 5756701e551SDaniel P. Berrange connected = 0; 5766701e551SDaniel P. Berrange for(;;) { 5776701e551SDaniel P. Berrange ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)); 5786701e551SDaniel P. Berrange if (ret < 0) { 5796701e551SDaniel P. Berrange if (errno == EINTR || errno == EWOULDBLOCK) { 5806701e551SDaniel P. Berrange /* continue */ 5816701e551SDaniel P. Berrange } else if (errno == EINPROGRESS || 5826701e551SDaniel P. Berrange errno == EALREADY || 5836701e551SDaniel P. Berrange errno == EINVAL) { 5846701e551SDaniel P. Berrange break; 5856701e551SDaniel P. Berrange } else { 5860522a959SMao Zhongyi error_setg_errno(errp, errno, "can't connect socket"); 5876701e551SDaniel P. Berrange closesocket(fd); 5886701e551SDaniel P. Berrange return -1; 5896701e551SDaniel P. Berrange } 5906701e551SDaniel P. Berrange } else { 5916701e551SDaniel P. Berrange connected = 1; 5926701e551SDaniel P. Berrange break; 5936701e551SDaniel P. Berrange } 5946701e551SDaniel P. Berrange } 5950522a959SMao Zhongyi s = net_socket_fd_init(peer, model, name, fd, connected, NULL, errp); 596c37f0bb1SMao Zhongyi if (!s) { 5976701e551SDaniel P. Berrange return -1; 598c37f0bb1SMao Zhongyi } 599c37f0bb1SMao Zhongyi 60056e6f594SJason Wang snprintf(s->nc.info_str, sizeof(s->nc.info_str), 60156e6f594SJason Wang "socket: connect to %s:%d", 60256e6f594SJason Wang inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); 6036701e551SDaniel P. Berrange return 0; 60442281ac9SMark McLoughlin } 60542281ac9SMark McLoughlin 6064e68f7a0SStefan Hajnoczi static int net_socket_mcast_init(NetClientState *peer, 60742281ac9SMark McLoughlin const char *model, 60842281ac9SMark McLoughlin const char *name, 6093a75e74cSMike Ryan const char *host_str, 6100522a959SMao Zhongyi const char *localaddr_str, 6110522a959SMao Zhongyi Error **errp) 61242281ac9SMark McLoughlin { 61342281ac9SMark McLoughlin NetSocketState *s; 61442281ac9SMark McLoughlin int fd; 61542281ac9SMark McLoughlin struct sockaddr_in saddr; 6163a75e74cSMike Ryan struct in_addr localaddr, *param_localaddr; 61742281ac9SMark McLoughlin 6180522a959SMao Zhongyi if (parse_host_port(&saddr, host_str, errp) < 0) { 61942281ac9SMark McLoughlin return -1; 620bcd4dfd6SMao Zhongyi } 62142281ac9SMark McLoughlin 6223a75e74cSMike Ryan if (localaddr_str != NULL) { 6230522a959SMao Zhongyi if (inet_aton(localaddr_str, &localaddr) == 0) { 6240522a959SMao Zhongyi error_setg(errp, "localaddr '%s' is not a valid IPv4 address", 6250522a959SMao Zhongyi localaddr_str); 6263a75e74cSMike Ryan return -1; 6270522a959SMao Zhongyi } 6283a75e74cSMike Ryan param_localaddr = &localaddr; 6293a75e74cSMike Ryan } else { 6303a75e74cSMike Ryan param_localaddr = NULL; 6313a75e74cSMike Ryan } 63242281ac9SMark McLoughlin 6330522a959SMao Zhongyi fd = net_socket_mcast_create(&saddr, param_localaddr, errp); 634c37f0bb1SMao Zhongyi if (fd < 0) { 63542281ac9SMark McLoughlin return -1; 636c37f0bb1SMao Zhongyi } 63742281ac9SMark McLoughlin 6380522a959SMao Zhongyi s = net_socket_fd_init(peer, model, name, fd, 0, NULL, errp); 639c37f0bb1SMao Zhongyi if (!s) { 64042281ac9SMark McLoughlin return -1; 641c37f0bb1SMao Zhongyi } 64242281ac9SMark McLoughlin 64342281ac9SMark McLoughlin s->dgram_dst = saddr; 64442281ac9SMark McLoughlin 64556e6f594SJason Wang snprintf(s->nc.info_str, sizeof(s->nc.info_str), 64656e6f594SJason Wang "socket: mcast=%s:%d", 64756e6f594SJason Wang inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); 64842281ac9SMark McLoughlin return 0; 649d89b4f83SJason Wang 65042281ac9SMark McLoughlin } 65142281ac9SMark McLoughlin 6524e68f7a0SStefan Hajnoczi static int net_socket_udp_init(NetClientState *peer, 6530e0e7facSBenjamin const char *model, 6540e0e7facSBenjamin const char *name, 6550e0e7facSBenjamin const char *rhost, 6560522a959SMao Zhongyi const char *lhost, 6570522a959SMao Zhongyi Error **errp) 6580e0e7facSBenjamin { 6590e0e7facSBenjamin NetSocketState *s; 660bcbe92fbSSebastian Ottlik int fd, ret; 6610e0e7facSBenjamin struct sockaddr_in laddr, raddr; 6620e0e7facSBenjamin 6630522a959SMao Zhongyi if (parse_host_port(&laddr, lhost, errp) < 0) { 6640e0e7facSBenjamin return -1; 6650e0e7facSBenjamin } 6660e0e7facSBenjamin 6670522a959SMao Zhongyi if (parse_host_port(&raddr, rhost, errp) < 0) { 6680e0e7facSBenjamin return -1; 6690e0e7facSBenjamin } 6700e0e7facSBenjamin 6710e0e7facSBenjamin fd = qemu_socket(PF_INET, SOCK_DGRAM, 0); 6720e0e7facSBenjamin if (fd < 0) { 6730522a959SMao Zhongyi error_setg_errno(errp, errno, "can't create datagram socket"); 6740e0e7facSBenjamin return -1; 6750e0e7facSBenjamin } 676bcbe92fbSSebastian Ottlik 677bcbe92fbSSebastian Ottlik ret = socket_set_fast_reuse(fd); 6780e0e7facSBenjamin if (ret < 0) { 6790522a959SMao Zhongyi error_setg_errno(errp, errno, 6800522a959SMao Zhongyi "can't set socket option SO_REUSEADDR"); 6810e0e7facSBenjamin closesocket(fd); 6820e0e7facSBenjamin return -1; 6830e0e7facSBenjamin } 6840e0e7facSBenjamin ret = bind(fd, (struct sockaddr *)&laddr, sizeof(laddr)); 6850e0e7facSBenjamin if (ret < 0) { 6860522a959SMao Zhongyi error_setg_errno(errp, errno, "can't bind ip=%s to socket", 6870522a959SMao Zhongyi inet_ntoa(laddr.sin_addr)); 6880e0e7facSBenjamin closesocket(fd); 6890e0e7facSBenjamin return -1; 6900e0e7facSBenjamin } 691*ff5927baSMarc-André Lureau qemu_socket_set_nonblock(fd); 6920e0e7facSBenjamin 6930522a959SMao Zhongyi s = net_socket_fd_init(peer, model, name, fd, 0, NULL, errp); 6940e0e7facSBenjamin if (!s) { 6950e0e7facSBenjamin return -1; 6960e0e7facSBenjamin } 6970e0e7facSBenjamin 6980e0e7facSBenjamin s->dgram_dst = raddr; 6990e0e7facSBenjamin 70056e6f594SJason Wang snprintf(s->nc.info_str, sizeof(s->nc.info_str), 70156e6f594SJason Wang "socket: udp=%s:%d", 70256e6f594SJason Wang inet_ntoa(raddr.sin_addr), ntohs(raddr.sin_port)); 7030e0e7facSBenjamin return 0; 7040e0e7facSBenjamin } 7050e0e7facSBenjamin 706cebea510SKővágó, Zoltán int net_init_socket(const Netdev *netdev, const char *name, 707a30ecde6SMarkus Armbruster NetClientState *peer, Error **errp) 70842281ac9SMark McLoughlin { 709bef8e8feSLaszlo Ersek const NetdevSocketOptions *sock; 710bef8e8feSLaszlo Ersek 711f394b2e2SEric Blake assert(netdev->type == NET_CLIENT_DRIVER_SOCKET); 712f394b2e2SEric Blake sock = &netdev->u.socket; 713bef8e8feSLaszlo Ersek 714ff86d576SJens Freimann if (sock->has_fd + sock->has_listen + sock->has_connect + sock->has_mcast + 715ff86d576SJens Freimann sock->has_udp != 1) { 7160522a959SMao Zhongyi error_setg(errp, "exactly one of listen=, connect=, mcast= or udp=" 717bef8e8feSLaszlo Ersek " is required"); 718bef8e8feSLaszlo Ersek return -1; 719bef8e8feSLaszlo Ersek } 720bef8e8feSLaszlo Ersek 721bef8e8feSLaszlo Ersek if (sock->has_localaddr && !sock->has_mcast && !sock->has_udp) { 7220522a959SMao Zhongyi error_setg(errp, "localaddr= is only valid with mcast= or udp="); 723bef8e8feSLaszlo Ersek return -1; 724bef8e8feSLaszlo Ersek } 725bef8e8feSLaszlo Ersek 726bef8e8feSLaszlo Ersek if (sock->has_fd) { 727894022e6SLaurent Vivier int fd, ret; 72842281ac9SMark McLoughlin 729947e4744SKevin Wolf fd = monitor_fd_param(monitor_cur(), sock->fd, errp); 730fc13fa00SStefan Hajnoczi if (fd == -1) { 731fc13fa00SStefan Hajnoczi return -1; 732fc13fa00SStefan Hajnoczi } 733*ff5927baSMarc-André Lureau ret = qemu_socket_try_set_nonblock(fd); 734894022e6SLaurent Vivier if (ret < 0) { 735894022e6SLaurent Vivier error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d", 736894022e6SLaurent Vivier name, fd); 737894022e6SLaurent Vivier return -1; 738894022e6SLaurent Vivier } 739c37f0bb1SMao Zhongyi if (!net_socket_fd_init(peer, "socket", name, fd, 1, sock->mcast, 740c37f0bb1SMao Zhongyi errp)) { 74142281ac9SMark McLoughlin return -1; 74242281ac9SMark McLoughlin } 743bef8e8feSLaszlo Ersek return 0; 74442281ac9SMark McLoughlin } 74542281ac9SMark McLoughlin 746bef8e8feSLaszlo Ersek if (sock->has_listen) { 7470522a959SMao Zhongyi if (net_socket_listen_init(peer, "socket", name, sock->listen, errp) 7480522a959SMao Zhongyi < 0) { 74942281ac9SMark McLoughlin return -1; 75042281ac9SMark McLoughlin } 751bef8e8feSLaszlo Ersek return 0; 75242281ac9SMark McLoughlin } 75342281ac9SMark McLoughlin 754bef8e8feSLaszlo Ersek if (sock->has_connect) { 7550522a959SMao Zhongyi if (net_socket_connect_init(peer, "socket", name, sock->connect, errp) 7560522a959SMao Zhongyi < 0) { 75742281ac9SMark McLoughlin return -1; 75842281ac9SMark McLoughlin } 759bef8e8feSLaszlo Ersek return 0; 76042281ac9SMark McLoughlin } 76142281ac9SMark McLoughlin 762bef8e8feSLaszlo Ersek if (sock->has_mcast) { 763bef8e8feSLaszlo Ersek /* if sock->localaddr is missing, it has been initialized to "all bits 764bef8e8feSLaszlo Ersek * zero" */ 765d33d93b2SStefan Hajnoczi if (net_socket_mcast_init(peer, "socket", name, sock->mcast, 7660522a959SMao Zhongyi sock->localaddr, errp) < 0) { 76742281ac9SMark McLoughlin return -1; 76842281ac9SMark McLoughlin } 769bef8e8feSLaszlo Ersek return 0; 77042281ac9SMark McLoughlin } 77142281ac9SMark McLoughlin 772bef8e8feSLaszlo Ersek assert(sock->has_udp); 773bef8e8feSLaszlo Ersek if (!sock->has_localaddr) { 7740522a959SMao Zhongyi error_setg(errp, "localaddr= is mandatory with udp="); 7750e0e7facSBenjamin return -1; 7760e0e7facSBenjamin } 7770522a959SMao Zhongyi if (net_socket_udp_init(peer, "socket", name, sock->udp, sock->localaddr, 7780522a959SMao Zhongyi errp) < 0) { 7790e0e7facSBenjamin return -1; 7800e0e7facSBenjamin } 78142281ac9SMark McLoughlin return 0; 78242281ac9SMark McLoughlin } 783