xref: /qemu/net/socket.c (revision 947e4744)
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"
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;
4116a3df40SZhang Chen     SocketReadState rs;
4245a7f54aSStefan Hajnoczi     unsigned int send_index;      /* number of bytes sent (only SOCK_STREAM) */
4342281ac9SMark McLoughlin     struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */
44863f678fSStefan Hajnoczi     IOHandler *send_fn;           /* differs between SOCK_STREAM/SOCK_DGRAM */
45863f678fSStefan Hajnoczi     bool read_poll;               /* waiting to receive data? */
46863f678fSStefan Hajnoczi     bool write_poll;              /* waiting to transmit data? */
4742281ac9SMark McLoughlin } NetSocketState;
4842281ac9SMark McLoughlin 
49011de2b5SZhi Yong Wu static void net_socket_accept(void *opaque);
50863f678fSStefan Hajnoczi static void net_socket_writable(void *opaque);
51863f678fSStefan Hajnoczi 
52863f678fSStefan Hajnoczi static void net_socket_update_fd_handler(NetSocketState *s)
53863f678fSStefan Hajnoczi {
5482e1cc4bSFam Zheng     qemu_set_fd_handler(s->fd,
55863f678fSStefan Hajnoczi                         s->read_poll ? s->send_fn : NULL,
56863f678fSStefan Hajnoczi                         s->write_poll ? net_socket_writable : NULL,
57863f678fSStefan Hajnoczi                         s);
58863f678fSStefan Hajnoczi }
59863f678fSStefan Hajnoczi 
60863f678fSStefan Hajnoczi static void net_socket_read_poll(NetSocketState *s, bool enable)
61863f678fSStefan Hajnoczi {
62863f678fSStefan Hajnoczi     s->read_poll = enable;
63863f678fSStefan Hajnoczi     net_socket_update_fd_handler(s);
64863f678fSStefan Hajnoczi }
65863f678fSStefan Hajnoczi 
66863f678fSStefan Hajnoczi static void net_socket_write_poll(NetSocketState *s, bool enable)
67863f678fSStefan Hajnoczi {
68863f678fSStefan Hajnoczi     s->write_poll = enable;
69863f678fSStefan Hajnoczi     net_socket_update_fd_handler(s);
70863f678fSStefan Hajnoczi }
71863f678fSStefan Hajnoczi 
72863f678fSStefan Hajnoczi static void net_socket_writable(void *opaque)
73863f678fSStefan Hajnoczi {
74863f678fSStefan Hajnoczi     NetSocketState *s = opaque;
75863f678fSStefan Hajnoczi 
76863f678fSStefan Hajnoczi     net_socket_write_poll(s, false);
77863f678fSStefan Hajnoczi 
78863f678fSStefan Hajnoczi     qemu_flush_queued_packets(&s->nc);
79863f678fSStefan Hajnoczi }
8042281ac9SMark McLoughlin 
814e68f7a0SStefan Hajnoczi static ssize_t net_socket_receive(NetClientState *nc, const uint8_t *buf, size_t size)
8242281ac9SMark McLoughlin {
83564f63e3SMark McLoughlin     NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
8445a7f54aSStefan Hajnoczi     uint32_t len = htonl(size);
8545a7f54aSStefan Hajnoczi     struct iovec iov[] = {
8645a7f54aSStefan Hajnoczi         {
8745a7f54aSStefan Hajnoczi             .iov_base = &len,
8845a7f54aSStefan Hajnoczi             .iov_len  = sizeof(len),
8945a7f54aSStefan Hajnoczi         }, {
9045a7f54aSStefan Hajnoczi             .iov_base = (void *)buf,
9145a7f54aSStefan Hajnoczi             .iov_len  = size,
9245a7f54aSStefan Hajnoczi         },
9345a7f54aSStefan Hajnoczi     };
9445a7f54aSStefan Hajnoczi     size_t remaining;
9545a7f54aSStefan Hajnoczi     ssize_t ret;
9642281ac9SMark McLoughlin 
9745a7f54aSStefan Hajnoczi     remaining = iov_size(iov, 2) - s->send_index;
9845a7f54aSStefan Hajnoczi     ret = iov_send(s->fd, iov, 2, s->send_index, remaining);
9945a7f54aSStefan Hajnoczi 
10045a7f54aSStefan Hajnoczi     if (ret == -1 && errno == EAGAIN) {
10145a7f54aSStefan Hajnoczi         ret = 0; /* handled further down */
10245a7f54aSStefan Hajnoczi     }
10345a7f54aSStefan Hajnoczi     if (ret == -1) {
10445a7f54aSStefan Hajnoczi         s->send_index = 0;
10545a7f54aSStefan Hajnoczi         return -errno;
10645a7f54aSStefan Hajnoczi     }
10745a7f54aSStefan Hajnoczi     if (ret < (ssize_t)remaining) {
10845a7f54aSStefan Hajnoczi         s->send_index += ret;
10945a7f54aSStefan Hajnoczi         net_socket_write_poll(s, true);
11045a7f54aSStefan Hajnoczi         return 0;
11145a7f54aSStefan Hajnoczi     }
11245a7f54aSStefan Hajnoczi     s->send_index = 0;
11345a7f54aSStefan Hajnoczi     return size;
11442281ac9SMark McLoughlin }
11542281ac9SMark McLoughlin 
1164e68f7a0SStefan Hajnoczi static ssize_t net_socket_receive_dgram(NetClientState *nc, const uint8_t *buf, size_t size)
11742281ac9SMark McLoughlin {
118564f63e3SMark McLoughlin     NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
119213fd508SStefan Hajnoczi     ssize_t ret;
12042281ac9SMark McLoughlin 
121213fd508SStefan Hajnoczi     do {
122fdec16e3SMarc-André Lureau         if (s->dgram_dst.sin_family != AF_UNIX) {
12373062dfeSStefan Weil             ret = qemu_sendto(s->fd, buf, size, 0,
124213fd508SStefan Hajnoczi                               (struct sockaddr *)&s->dgram_dst,
125213fd508SStefan Hajnoczi                               sizeof(s->dgram_dst));
126fdec16e3SMarc-André Lureau         } else {
127fdec16e3SMarc-André Lureau             ret = send(s->fd, buf, size, 0);
128fdec16e3SMarc-André Lureau         }
129213fd508SStefan Hajnoczi     } while (ret == -1 && errno == EINTR);
130213fd508SStefan Hajnoczi 
131213fd508SStefan Hajnoczi     if (ret == -1 && errno == EAGAIN) {
132213fd508SStefan Hajnoczi         net_socket_write_poll(s, true);
133213fd508SStefan Hajnoczi         return 0;
134213fd508SStefan Hajnoczi     }
135213fd508SStefan Hajnoczi     return ret;
13642281ac9SMark McLoughlin }
13742281ac9SMark McLoughlin 
1386e99c631SFam Zheng static void net_socket_send_completed(NetClientState *nc, ssize_t len)
1396e99c631SFam Zheng {
1406e99c631SFam Zheng     NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
1416e99c631SFam Zheng 
1426e99c631SFam Zheng     if (!s->read_poll) {
1436e99c631SFam Zheng         net_socket_read_poll(s, true);
1446e99c631SFam Zheng     }
1456e99c631SFam Zheng }
1466e99c631SFam Zheng 
14716a3df40SZhang Chen static void net_socket_rs_finalize(SocketReadState *rs)
14816a3df40SZhang Chen {
14916a3df40SZhang Chen     NetSocketState *s = container_of(rs, NetSocketState, rs);
15016a3df40SZhang Chen 
15116a3df40SZhang Chen     if (qemu_send_packet_async(&s->nc, rs->buf,
15216a3df40SZhang Chen                                rs->packet_len,
15316a3df40SZhang Chen                                net_socket_send_completed) == 0) {
15416a3df40SZhang Chen         net_socket_read_poll(s, false);
15516a3df40SZhang Chen     }
15616a3df40SZhang Chen }
15716a3df40SZhang Chen 
15842281ac9SMark McLoughlin static void net_socket_send(void *opaque)
15942281ac9SMark McLoughlin {
16042281ac9SMark McLoughlin     NetSocketState *s = opaque;
161b16a44e1SDaniel P. Berrange     int size;
16216a3df40SZhang Chen     int ret;
163d32fcad3SScott Feldman     uint8_t buf1[NET_BUFSIZE];
16442281ac9SMark McLoughlin     const uint8_t *buf;
16542281ac9SMark McLoughlin 
16600aa0040SBlue Swirl     size = qemu_recv(s->fd, buf1, sizeof(buf1), 0);
16742281ac9SMark McLoughlin     if (size < 0) {
168b16a44e1SDaniel P. Berrange         if (errno != EWOULDBLOCK)
16942281ac9SMark McLoughlin             goto eoc;
17042281ac9SMark McLoughlin     } else if (size == 0) {
17142281ac9SMark McLoughlin         /* end of connection */
17242281ac9SMark McLoughlin     eoc:
173863f678fSStefan Hajnoczi         net_socket_read_poll(s, false);
174863f678fSStefan Hajnoczi         net_socket_write_poll(s, false);
175011de2b5SZhi Yong Wu         if (s->listen_fd != -1) {
176011de2b5SZhi Yong Wu             qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s);
177011de2b5SZhi Yong Wu         }
17842281ac9SMark McLoughlin         closesocket(s->fd);
179011de2b5SZhi Yong Wu 
180011de2b5SZhi Yong Wu         s->fd = -1;
1813cde5ea2SZhang Chen         net_socket_rs_init(&s->rs, net_socket_rs_finalize, false);
182011de2b5SZhi Yong Wu         s->nc.link_down = true;
183011de2b5SZhi Yong Wu         memset(s->nc.info_str, 0, sizeof(s->nc.info_str));
184011de2b5SZhi Yong Wu 
18542281ac9SMark McLoughlin         return;
18642281ac9SMark McLoughlin     }
18742281ac9SMark McLoughlin     buf = buf1;
18842281ac9SMark McLoughlin 
18916a3df40SZhang Chen     ret = net_fill_rstate(&s->rs, buf, size);
19016a3df40SZhang Chen 
19116a3df40SZhang Chen     if (ret == -1) {
19216a3df40SZhang Chen         goto eoc;
19342281ac9SMark McLoughlin     }
19442281ac9SMark McLoughlin }
19542281ac9SMark McLoughlin 
19642281ac9SMark McLoughlin static void net_socket_send_dgram(void *opaque)
19742281ac9SMark McLoughlin {
19842281ac9SMark McLoughlin     NetSocketState *s = opaque;
19942281ac9SMark McLoughlin     int size;
20042281ac9SMark McLoughlin 
20116a3df40SZhang Chen     size = qemu_recv(s->fd, s->rs.buf, sizeof(s->rs.buf), 0);
20242281ac9SMark McLoughlin     if (size < 0)
20342281ac9SMark McLoughlin         return;
20442281ac9SMark McLoughlin     if (size == 0) {
20542281ac9SMark McLoughlin         /* end of connection */
206863f678fSStefan Hajnoczi         net_socket_read_poll(s, false);
207863f678fSStefan Hajnoczi         net_socket_write_poll(s, false);
20842281ac9SMark McLoughlin         return;
20942281ac9SMark McLoughlin     }
21016a3df40SZhang Chen     if (qemu_send_packet_async(&s->nc, s->rs.buf, size,
2116e99c631SFam Zheng                                net_socket_send_completed) == 0) {
2126e99c631SFam Zheng         net_socket_read_poll(s, false);
2136e99c631SFam Zheng     }
21442281ac9SMark McLoughlin }
21542281ac9SMark McLoughlin 
216c37f0bb1SMao Zhongyi static int net_socket_mcast_create(struct sockaddr_in *mcastaddr,
217c37f0bb1SMao Zhongyi                                    struct in_addr *localaddr,
218c37f0bb1SMao Zhongyi                                    Error **errp)
21942281ac9SMark McLoughlin {
22042281ac9SMark McLoughlin     struct ip_mreq imr;
22142281ac9SMark McLoughlin     int fd;
22242281ac9SMark McLoughlin     int val, ret;
22323ddf2bbSBrad #ifdef __OpenBSD__
22423ddf2bbSBrad     unsigned char loop;
22523ddf2bbSBrad #else
22623ddf2bbSBrad     int loop;
22723ddf2bbSBrad #endif
22823ddf2bbSBrad 
22942281ac9SMark McLoughlin     if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) {
230c37f0bb1SMao Zhongyi         error_setg(errp, "specified mcastaddr %s (0x%08x) "
231c37f0bb1SMao Zhongyi                    "does not contain a multicast address",
23242281ac9SMark McLoughlin                    inet_ntoa(mcastaddr->sin_addr),
23342281ac9SMark McLoughlin                    (int)ntohl(mcastaddr->sin_addr.s_addr));
23442281ac9SMark McLoughlin         return -1;
23542281ac9SMark McLoughlin     }
236c37f0bb1SMao Zhongyi 
23740ff6d7eSKevin Wolf     fd = qemu_socket(PF_INET, SOCK_DGRAM, 0);
23842281ac9SMark McLoughlin     if (fd < 0) {
239c37f0bb1SMao Zhongyi         error_setg_errno(errp, errno, "can't create datagram socket");
24042281ac9SMark McLoughlin         return -1;
24142281ac9SMark McLoughlin     }
24242281ac9SMark McLoughlin 
243bcbe92fbSSebastian Ottlik     /* Allow multiple sockets to bind the same multicast ip and port by setting
244bcbe92fbSSebastian Ottlik      * SO_REUSEADDR. This is the only situation where SO_REUSEADDR should be set
245bcbe92fbSSebastian Ottlik      * on windows. Use socket_set_fast_reuse otherwise as it sets SO_REUSEADDR
246bcbe92fbSSebastian Ottlik      * only on posix systems.
247bcbe92fbSSebastian Ottlik      */
24842281ac9SMark McLoughlin     val = 1;
2499957fc7fSStefan Weil     ret = qemu_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
25042281ac9SMark McLoughlin     if (ret < 0) {
251c37f0bb1SMao Zhongyi         error_setg_errno(errp, errno,
252c37f0bb1SMao Zhongyi                          "can't set socket option SO_REUSEADDR");
25342281ac9SMark McLoughlin         goto fail;
25442281ac9SMark McLoughlin     }
25542281ac9SMark McLoughlin 
25642281ac9SMark McLoughlin     ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr));
25742281ac9SMark McLoughlin     if (ret < 0) {
258c37f0bb1SMao Zhongyi         error_setg_errno(errp, errno, "can't bind ip=%s to socket",
259c37f0bb1SMao Zhongyi                          inet_ntoa(mcastaddr->sin_addr));
26042281ac9SMark McLoughlin         goto fail;
26142281ac9SMark McLoughlin     }
26242281ac9SMark McLoughlin 
26342281ac9SMark McLoughlin     /* Add host to multicast group */
26442281ac9SMark McLoughlin     imr.imr_multiaddr = mcastaddr->sin_addr;
2653a75e74cSMike Ryan     if (localaddr) {
2663a75e74cSMike Ryan         imr.imr_interface = *localaddr;
2673a75e74cSMike Ryan     } else {
26842281ac9SMark McLoughlin         imr.imr_interface.s_addr = htonl(INADDR_ANY);
2693a75e74cSMike Ryan     }
27042281ac9SMark McLoughlin 
2719957fc7fSStefan Weil     ret = qemu_setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
2729957fc7fSStefan Weil                           &imr, sizeof(struct ip_mreq));
27342281ac9SMark McLoughlin     if (ret < 0) {
274c37f0bb1SMao Zhongyi         error_setg_errno(errp, errno,
275c37f0bb1SMao Zhongyi                          "can't add socket to multicast group %s",
276c37f0bb1SMao Zhongyi                          inet_ntoa(imr.imr_multiaddr));
27742281ac9SMark McLoughlin         goto fail;
27842281ac9SMark McLoughlin     }
27942281ac9SMark McLoughlin 
28042281ac9SMark McLoughlin     /* Force mcast msgs to loopback (eg. several QEMUs in same host */
28123ddf2bbSBrad     loop = 1;
2829957fc7fSStefan Weil     ret = qemu_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
2839957fc7fSStefan Weil                           &loop, sizeof(loop));
28442281ac9SMark McLoughlin     if (ret < 0) {
285c37f0bb1SMao Zhongyi         error_setg_errno(errp, errno,
286c37f0bb1SMao Zhongyi                          "can't force multicast message to loopback");
28742281ac9SMark McLoughlin         goto fail;
28842281ac9SMark McLoughlin     }
28942281ac9SMark McLoughlin 
2903a75e74cSMike Ryan     /* If a bind address is given, only send packets from that address */
2913a75e74cSMike Ryan     if (localaddr != NULL) {
2929957fc7fSStefan Weil         ret = qemu_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
2939957fc7fSStefan Weil                               localaddr, sizeof(*localaddr));
2943a75e74cSMike Ryan         if (ret < 0) {
295c37f0bb1SMao Zhongyi             error_setg_errno(errp, errno,
296c37f0bb1SMao Zhongyi                              "can't set the default network send interface");
2973a75e74cSMike Ryan             goto fail;
2983a75e74cSMike Ryan         }
2993a75e74cSMike Ryan     }
3003a75e74cSMike Ryan 
301f9e8caccSStefan Hajnoczi     qemu_set_nonblock(fd);
30242281ac9SMark McLoughlin     return fd;
30342281ac9SMark McLoughlin fail:
30442281ac9SMark McLoughlin     if (fd >= 0)
30542281ac9SMark McLoughlin         closesocket(fd);
30642281ac9SMark McLoughlin     return -1;
30742281ac9SMark McLoughlin }
30842281ac9SMark McLoughlin 
3094e68f7a0SStefan Hajnoczi static void net_socket_cleanup(NetClientState *nc)
31042281ac9SMark McLoughlin {
311564f63e3SMark McLoughlin     NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
312011de2b5SZhi Yong Wu     if (s->fd != -1) {
313863f678fSStefan Hajnoczi         net_socket_read_poll(s, false);
314863f678fSStefan Hajnoczi         net_socket_write_poll(s, false);
31542281ac9SMark McLoughlin         close(s->fd);
316011de2b5SZhi Yong Wu         s->fd = -1;
317011de2b5SZhi Yong Wu     }
318011de2b5SZhi Yong Wu     if (s->listen_fd != -1) {
319011de2b5SZhi Yong Wu         qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
320011de2b5SZhi Yong Wu         closesocket(s->listen_fd);
321011de2b5SZhi Yong Wu         s->listen_fd = -1;
322011de2b5SZhi Yong Wu     }
32342281ac9SMark McLoughlin }
32442281ac9SMark McLoughlin 
325564f63e3SMark McLoughlin static NetClientInfo net_dgram_socket_info = {
326f394b2e2SEric Blake     .type = NET_CLIENT_DRIVER_SOCKET,
327564f63e3SMark McLoughlin     .size = sizeof(NetSocketState),
328564f63e3SMark McLoughlin     .receive = net_socket_receive_dgram,
329564f63e3SMark McLoughlin     .cleanup = net_socket_cleanup,
330564f63e3SMark McLoughlin };
331564f63e3SMark McLoughlin 
3324e68f7a0SStefan Hajnoczi static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer,
33342281ac9SMark McLoughlin                                                 const char *model,
33442281ac9SMark McLoughlin                                                 const char *name,
3350f8c289aSJens Freimann                                                 int fd, int is_connected,
336c37f0bb1SMao Zhongyi                                                 const char *mcast,
337c37f0bb1SMao Zhongyi                                                 Error **errp)
33842281ac9SMark McLoughlin {
33942281ac9SMark McLoughlin     struct sockaddr_in saddr;
34042281ac9SMark McLoughlin     int newfd;
3414e68f7a0SStefan Hajnoczi     NetClientState *nc;
34242281ac9SMark McLoughlin     NetSocketState *s;
343fdec16e3SMarc-André Lureau     SocketAddress *sa;
344fdec16e3SMarc-André Lureau     SocketAddressType sa_type;
345fdec16e3SMarc-André Lureau 
346fdec16e3SMarc-André Lureau     sa = socket_local_address(fd, errp);
347fdec16e3SMarc-André Lureau     if (!sa) {
348fdec16e3SMarc-André Lureau         return NULL;
349fdec16e3SMarc-André Lureau     }
350fdec16e3SMarc-André Lureau     sa_type = sa->type;
351fdec16e3SMarc-André Lureau     qapi_free_SocketAddress(sa);
35242281ac9SMark McLoughlin 
35342281ac9SMark McLoughlin     /* fd passed: multicast: "learn" dgram_dst address from bound address and save it
35442281ac9SMark McLoughlin      * Because this may be "shared" socket from a "master" process, datagrams would be recv()
35542281ac9SMark McLoughlin      * by ONLY ONE process: we must "clone" this dgram socket --jjo
35642281ac9SMark McLoughlin      */
35742281ac9SMark McLoughlin 
3580f8c289aSJens Freimann     if (is_connected && mcast != NULL) {
359bcd4dfd6SMao Zhongyi             if (parse_host_port(&saddr, mcast, errp) < 0) {
3600f8c289aSJens Freimann                 goto err;
3610f8c289aSJens Freimann             }
36242281ac9SMark McLoughlin             /* must be bound */
36342281ac9SMark McLoughlin             if (saddr.sin_addr.s_addr == 0) {
364c37f0bb1SMao Zhongyi                 error_setg(errp, "can't setup multicast destination address");
365e5d1fca0SStefan Hajnoczi                 goto err;
36642281ac9SMark McLoughlin             }
36742281ac9SMark McLoughlin             /* clone dgram socket */
368c37f0bb1SMao Zhongyi             newfd = net_socket_mcast_create(&saddr, NULL, errp);
36942281ac9SMark McLoughlin             if (newfd < 0) {
370e5d1fca0SStefan Hajnoczi                 goto err;
37142281ac9SMark McLoughlin             }
37242281ac9SMark McLoughlin             /* clone newfd to fd, close newfd */
37342281ac9SMark McLoughlin             dup2(newfd, fd);
37442281ac9SMark McLoughlin             close(newfd);
37542281ac9SMark McLoughlin 
37642281ac9SMark McLoughlin     }
37742281ac9SMark McLoughlin 
378ab5f3f84SStefan Hajnoczi     nc = qemu_new_net_client(&net_dgram_socket_info, peer, model, name);
379564f63e3SMark McLoughlin 
380564f63e3SMark McLoughlin     s = DO_UPCAST(NetSocketState, nc, nc);
381564f63e3SMark McLoughlin 
38242281ac9SMark McLoughlin     s->fd = fd;
383011de2b5SZhi Yong Wu     s->listen_fd = -1;
384863f678fSStefan Hajnoczi     s->send_fn = net_socket_send_dgram;
3853cde5ea2SZhang Chen     net_socket_rs_init(&s->rs, net_socket_rs_finalize, false);
386863f678fSStefan Hajnoczi     net_socket_read_poll(s, true);
38742281ac9SMark McLoughlin 
38842281ac9SMark McLoughlin     /* mcast: save bound address as dst */
389bb160b57SJens Freimann     if (is_connected && mcast != NULL) {
390e34cde35SZhi Yong Wu         s->dgram_dst = saddr;
3918db804acSGonglei         snprintf(nc->info_str, sizeof(nc->info_str),
3928db804acSGonglei                  "socket: fd=%d (cloned mcast=%s:%d)",
3938db804acSGonglei                  fd, inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
3948db804acSGonglei     } else {
395fdec16e3SMarc-André Lureau         if (sa_type == SOCKET_ADDRESS_TYPE_UNIX) {
396fdec16e3SMarc-André Lureau             s->dgram_dst.sin_family = AF_UNIX;
397fdec16e3SMarc-André Lureau         }
398fdec16e3SMarc-André Lureau 
3998db804acSGonglei         snprintf(nc->info_str, sizeof(nc->info_str),
400fdec16e3SMarc-André Lureau                  "socket: fd=%d %s", fd, SocketAddressType_str(sa_type));
401e34cde35SZhi Yong Wu     }
40242281ac9SMark McLoughlin 
40342281ac9SMark McLoughlin     return s;
404e5d1fca0SStefan Hajnoczi 
405e5d1fca0SStefan Hajnoczi err:
406e5d1fca0SStefan Hajnoczi     closesocket(fd);
407e5d1fca0SStefan Hajnoczi     return NULL;
40842281ac9SMark McLoughlin }
40942281ac9SMark McLoughlin 
41042281ac9SMark McLoughlin static void net_socket_connect(void *opaque)
41142281ac9SMark McLoughlin {
41242281ac9SMark McLoughlin     NetSocketState *s = opaque;
413863f678fSStefan Hajnoczi     s->send_fn = net_socket_send;
414863f678fSStefan Hajnoczi     net_socket_read_poll(s, true);
41542281ac9SMark McLoughlin }
41642281ac9SMark McLoughlin 
417564f63e3SMark McLoughlin static NetClientInfo net_socket_info = {
418f394b2e2SEric Blake     .type = NET_CLIENT_DRIVER_SOCKET,
419564f63e3SMark McLoughlin     .size = sizeof(NetSocketState),
420564f63e3SMark McLoughlin     .receive = net_socket_receive,
421564f63e3SMark McLoughlin     .cleanup = net_socket_cleanup,
422564f63e3SMark McLoughlin };
423564f63e3SMark McLoughlin 
4244e68f7a0SStefan Hajnoczi static NetSocketState *net_socket_fd_init_stream(NetClientState *peer,
42542281ac9SMark McLoughlin                                                  const char *model,
42642281ac9SMark McLoughlin                                                  const char *name,
42742281ac9SMark McLoughlin                                                  int fd, int is_connected)
42842281ac9SMark McLoughlin {
4294e68f7a0SStefan Hajnoczi     NetClientState *nc;
43042281ac9SMark McLoughlin     NetSocketState *s;
431564f63e3SMark McLoughlin 
432ab5f3f84SStefan Hajnoczi     nc = qemu_new_net_client(&net_socket_info, peer, model, name);
433564f63e3SMark McLoughlin 
434564f63e3SMark McLoughlin     snprintf(nc->info_str, sizeof(nc->info_str), "socket: fd=%d", fd);
435564f63e3SMark McLoughlin 
436564f63e3SMark McLoughlin     s = DO_UPCAST(NetSocketState, nc, nc);
437564f63e3SMark McLoughlin 
43842281ac9SMark McLoughlin     s->fd = fd;
439011de2b5SZhi Yong Wu     s->listen_fd = -1;
4403cde5ea2SZhang Chen     net_socket_rs_init(&s->rs, net_socket_rs_finalize, false);
441564f63e3SMark McLoughlin 
44220048d0aSStefan Hajnoczi     /* Disable Nagle algorithm on TCP sockets to reduce latency */
44320048d0aSStefan Hajnoczi     socket_set_nodelay(fd);
44420048d0aSStefan Hajnoczi 
44542281ac9SMark McLoughlin     if (is_connected) {
44642281ac9SMark McLoughlin         net_socket_connect(s);
44742281ac9SMark McLoughlin     } else {
44842281ac9SMark McLoughlin         qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s);
44942281ac9SMark McLoughlin     }
45042281ac9SMark McLoughlin     return s;
45142281ac9SMark McLoughlin }
45242281ac9SMark McLoughlin 
4534e68f7a0SStefan Hajnoczi static NetSocketState *net_socket_fd_init(NetClientState *peer,
45442281ac9SMark McLoughlin                                           const char *model, const char *name,
455c37f0bb1SMao Zhongyi                                           int fd, int is_connected,
456c37f0bb1SMao Zhongyi                                           const char *mc, Error **errp)
45742281ac9SMark McLoughlin {
45842281ac9SMark McLoughlin     int so_type = -1, optlen=sizeof(so_type);
45942281ac9SMark McLoughlin 
46042281ac9SMark McLoughlin     if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type,
46142281ac9SMark McLoughlin         (socklen_t *)&optlen)< 0) {
462c37f0bb1SMao Zhongyi         error_setg(errp, "can't get socket option SO_TYPE");
463e5d1fca0SStefan Hajnoczi         closesocket(fd);
46442281ac9SMark McLoughlin         return NULL;
46542281ac9SMark McLoughlin     }
46642281ac9SMark McLoughlin     switch(so_type) {
46742281ac9SMark McLoughlin     case SOCK_DGRAM:
468c37f0bb1SMao Zhongyi         return net_socket_fd_init_dgram(peer, model, name, fd, is_connected,
469c37f0bb1SMao Zhongyi                                         mc, errp);
47042281ac9SMark McLoughlin     case SOCK_STREAM:
471d33d93b2SStefan Hajnoczi         return net_socket_fd_init_stream(peer, model, name, fd, is_connected);
47242281ac9SMark McLoughlin     default:
4738c42dbe3SMarkus Armbruster         error_setg(errp, "socket type=%d for fd=%d must be either"
474e1b24b64SMao Zhongyi                    " SOCK_DGRAM or SOCK_STREAM", so_type, fd);
475e1b24b64SMao Zhongyi         closesocket(fd);
47642281ac9SMark McLoughlin     }
47742281ac9SMark McLoughlin     return NULL;
47842281ac9SMark McLoughlin }
47942281ac9SMark McLoughlin 
48042281ac9SMark McLoughlin static void net_socket_accept(void *opaque)
48142281ac9SMark McLoughlin {
482011de2b5SZhi Yong Wu     NetSocketState *s = opaque;
48342281ac9SMark McLoughlin     struct sockaddr_in saddr;
48442281ac9SMark McLoughlin     socklen_t len;
48542281ac9SMark McLoughlin     int fd;
48642281ac9SMark McLoughlin 
48742281ac9SMark McLoughlin     for(;;) {
48842281ac9SMark McLoughlin         len = sizeof(saddr);
489011de2b5SZhi Yong Wu         fd = qemu_accept(s->listen_fd, (struct sockaddr *)&saddr, &len);
49042281ac9SMark McLoughlin         if (fd < 0 && errno != EINTR) {
49142281ac9SMark McLoughlin             return;
49242281ac9SMark McLoughlin         } else if (fd >= 0) {
493011de2b5SZhi Yong Wu             qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
49442281ac9SMark McLoughlin             break;
49542281ac9SMark McLoughlin         }
49642281ac9SMark McLoughlin     }
497011de2b5SZhi Yong Wu 
498011de2b5SZhi Yong Wu     s->fd = fd;
499011de2b5SZhi Yong Wu     s->nc.link_down = false;
500011de2b5SZhi Yong Wu     net_socket_connect(s);
501011de2b5SZhi Yong Wu     snprintf(s->nc.info_str, sizeof(s->nc.info_str),
50242281ac9SMark McLoughlin              "socket: connection from %s:%d",
50342281ac9SMark McLoughlin              inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
50442281ac9SMark McLoughlin }
50542281ac9SMark McLoughlin 
5064e68f7a0SStefan Hajnoczi static int net_socket_listen_init(NetClientState *peer,
50742281ac9SMark McLoughlin                                   const char *model,
50842281ac9SMark McLoughlin                                   const char *name,
5090522a959SMao Zhongyi                                   const char *host_str,
5100522a959SMao Zhongyi                                   Error **errp)
51142281ac9SMark McLoughlin {
512011de2b5SZhi Yong Wu     NetClientState *nc;
513011de2b5SZhi Yong Wu     NetSocketState *s;
5146701e551SDaniel P. Berrange     struct sockaddr_in saddr;
5156701e551SDaniel P. Berrange     int fd, ret;
51642281ac9SMark McLoughlin 
5170522a959SMao Zhongyi     if (parse_host_port(&saddr, host_str, errp) < 0) {
5186701e551SDaniel P. Berrange         return -1;
519bcd4dfd6SMao Zhongyi     }
5206701e551SDaniel P. Berrange 
5216701e551SDaniel P. Berrange     fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
5226701e551SDaniel P. Berrange     if (fd < 0) {
5230522a959SMao Zhongyi         error_setg_errno(errp, errno, "can't create stream socket");
52442281ac9SMark McLoughlin         return -1;
52542281ac9SMark McLoughlin     }
5266701e551SDaniel P. Berrange     qemu_set_nonblock(fd);
52742281ac9SMark McLoughlin 
5286701e551SDaniel P. Berrange     socket_set_fast_reuse(fd);
5296701e551SDaniel P. Berrange 
5306701e551SDaniel P. Berrange     ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
53142281ac9SMark McLoughlin     if (ret < 0) {
5320522a959SMao Zhongyi         error_setg_errno(errp, errno, "can't bind ip=%s to socket",
5330522a959SMao Zhongyi                          inet_ntoa(saddr.sin_addr));
5346701e551SDaniel P. Berrange         closesocket(fd);
5356701e551SDaniel P. Berrange         return -1;
5366701e551SDaniel P. Berrange     }
5376701e551SDaniel P. Berrange     ret = listen(fd, 0);
5386701e551SDaniel P. Berrange     if (ret < 0) {
5390522a959SMao Zhongyi         error_setg_errno(errp, errno, "can't listen on socket");
5406701e551SDaniel P. Berrange         closesocket(fd);
54142281ac9SMark McLoughlin         return -1;
54242281ac9SMark McLoughlin     }
543011de2b5SZhi Yong Wu 
544011de2b5SZhi Yong Wu     nc = qemu_new_net_client(&net_socket_info, peer, model, name);
545011de2b5SZhi Yong Wu     s = DO_UPCAST(NetSocketState, nc, nc);
546011de2b5SZhi Yong Wu     s->fd = -1;
5476701e551SDaniel P. Berrange     s->listen_fd = fd;
548011de2b5SZhi Yong Wu     s->nc.link_down = true;
5493cde5ea2SZhang Chen     net_socket_rs_init(&s->rs, net_socket_rs_finalize, false);
550011de2b5SZhi Yong Wu 
551011de2b5SZhi Yong Wu     qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s);
55242281ac9SMark McLoughlin     return 0;
55342281ac9SMark McLoughlin }
55442281ac9SMark McLoughlin 
5554e68f7a0SStefan Hajnoczi static int net_socket_connect_init(NetClientState *peer,
55642281ac9SMark McLoughlin                                    const char *model,
55742281ac9SMark McLoughlin                                    const char *name,
5580522a959SMao Zhongyi                                    const char *host_str,
5590522a959SMao Zhongyi                                    Error **errp)
56042281ac9SMark McLoughlin {
5616701e551SDaniel P. Berrange     NetSocketState *s;
5626701e551SDaniel P. Berrange     int fd, connected, ret;
5636701e551SDaniel P. Berrange     struct sockaddr_in saddr;
56442281ac9SMark McLoughlin 
5650522a959SMao Zhongyi     if (parse_host_port(&saddr, host_str, errp) < 0) {
566883e4f76SMarc-André Lureau         return -1;
567bcd4dfd6SMao Zhongyi     }
5686701e551SDaniel P. Berrange 
5696701e551SDaniel P. Berrange     fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
5706701e551SDaniel P. Berrange     if (fd < 0) {
5710522a959SMao Zhongyi         error_setg_errno(errp, errno, "can't create stream socket");
5726701e551SDaniel P. Berrange         return -1;
5736701e551SDaniel P. Berrange     }
5746701e551SDaniel P. Berrange     qemu_set_nonblock(fd);
5756701e551SDaniel P. Berrange 
5766701e551SDaniel P. Berrange     connected = 0;
5776701e551SDaniel P. Berrange     for(;;) {
5786701e551SDaniel P. Berrange         ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
5796701e551SDaniel P. Berrange         if (ret < 0) {
5806701e551SDaniel P. Berrange             if (errno == EINTR || errno == EWOULDBLOCK) {
5816701e551SDaniel P. Berrange                 /* continue */
5826701e551SDaniel P. Berrange             } else if (errno == EINPROGRESS ||
5836701e551SDaniel P. Berrange                        errno == EALREADY ||
5846701e551SDaniel P. Berrange                        errno == EINVAL) {
5856701e551SDaniel P. Berrange                 break;
5866701e551SDaniel P. Berrange             } else {
5870522a959SMao Zhongyi                 error_setg_errno(errp, errno, "can't connect socket");
5886701e551SDaniel P. Berrange                 closesocket(fd);
5896701e551SDaniel P. Berrange                 return -1;
5906701e551SDaniel P. Berrange             }
5916701e551SDaniel P. Berrange         } else {
5926701e551SDaniel P. Berrange             connected = 1;
5936701e551SDaniel P. Berrange             break;
5946701e551SDaniel P. Berrange         }
5956701e551SDaniel P. Berrange     }
5960522a959SMao Zhongyi     s = net_socket_fd_init(peer, model, name, fd, connected, NULL, errp);
597c37f0bb1SMao Zhongyi     if (!s) {
5986701e551SDaniel P. Berrange         return -1;
599c37f0bb1SMao Zhongyi     }
600c37f0bb1SMao Zhongyi 
6016701e551SDaniel P. Berrange     snprintf(s->nc.info_str, sizeof(s->nc.info_str),
6026701e551SDaniel P. Berrange              "socket: connect to %s:%d",
6036701e551SDaniel P. Berrange              inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
6046701e551SDaniel P. Berrange     return 0;
60542281ac9SMark McLoughlin }
60642281ac9SMark McLoughlin 
6074e68f7a0SStefan Hajnoczi static int net_socket_mcast_init(NetClientState *peer,
60842281ac9SMark McLoughlin                                  const char *model,
60942281ac9SMark McLoughlin                                  const char *name,
6103a75e74cSMike Ryan                                  const char *host_str,
6110522a959SMao Zhongyi                                  const char *localaddr_str,
6120522a959SMao Zhongyi                                  Error **errp)
61342281ac9SMark McLoughlin {
61442281ac9SMark McLoughlin     NetSocketState *s;
61542281ac9SMark McLoughlin     int fd;
61642281ac9SMark McLoughlin     struct sockaddr_in saddr;
6173a75e74cSMike Ryan     struct in_addr localaddr, *param_localaddr;
61842281ac9SMark McLoughlin 
6190522a959SMao Zhongyi     if (parse_host_port(&saddr, host_str, errp) < 0) {
62042281ac9SMark McLoughlin         return -1;
621bcd4dfd6SMao Zhongyi     }
62242281ac9SMark McLoughlin 
6233a75e74cSMike Ryan     if (localaddr_str != NULL) {
6240522a959SMao Zhongyi         if (inet_aton(localaddr_str, &localaddr) == 0) {
6250522a959SMao Zhongyi             error_setg(errp, "localaddr '%s' is not a valid IPv4 address",
6260522a959SMao Zhongyi                        localaddr_str);
6273a75e74cSMike Ryan             return -1;
6280522a959SMao Zhongyi         }
6293a75e74cSMike Ryan         param_localaddr = &localaddr;
6303a75e74cSMike Ryan     } else {
6313a75e74cSMike Ryan         param_localaddr = NULL;
6323a75e74cSMike Ryan     }
63342281ac9SMark McLoughlin 
6340522a959SMao Zhongyi     fd = net_socket_mcast_create(&saddr, param_localaddr, errp);
635c37f0bb1SMao Zhongyi     if (fd < 0) {
63642281ac9SMark McLoughlin         return -1;
637c37f0bb1SMao Zhongyi     }
63842281ac9SMark McLoughlin 
6390522a959SMao Zhongyi     s = net_socket_fd_init(peer, model, name, fd, 0, NULL, errp);
640c37f0bb1SMao Zhongyi     if (!s) {
64142281ac9SMark McLoughlin         return -1;
642c37f0bb1SMao Zhongyi     }
64342281ac9SMark McLoughlin 
64442281ac9SMark McLoughlin     s->dgram_dst = saddr;
64542281ac9SMark McLoughlin 
646564f63e3SMark McLoughlin     snprintf(s->nc.info_str, sizeof(s->nc.info_str),
64742281ac9SMark McLoughlin              "socket: mcast=%s:%d",
64842281ac9SMark McLoughlin              inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
64942281ac9SMark McLoughlin     return 0;
65042281ac9SMark McLoughlin 
65142281ac9SMark McLoughlin }
65242281ac9SMark McLoughlin 
6534e68f7a0SStefan Hajnoczi static int net_socket_udp_init(NetClientState *peer,
6540e0e7facSBenjamin                                  const char *model,
6550e0e7facSBenjamin                                  const char *name,
6560e0e7facSBenjamin                                  const char *rhost,
6570522a959SMao Zhongyi                                  const char *lhost,
6580522a959SMao Zhongyi                                  Error **errp)
6590e0e7facSBenjamin {
6600e0e7facSBenjamin     NetSocketState *s;
661bcbe92fbSSebastian Ottlik     int fd, ret;
6620e0e7facSBenjamin     struct sockaddr_in laddr, raddr;
6630e0e7facSBenjamin 
6640522a959SMao Zhongyi     if (parse_host_port(&laddr, lhost, errp) < 0) {
6650e0e7facSBenjamin         return -1;
6660e0e7facSBenjamin     }
6670e0e7facSBenjamin 
6680522a959SMao Zhongyi     if (parse_host_port(&raddr, rhost, errp) < 0) {
6690e0e7facSBenjamin         return -1;
6700e0e7facSBenjamin     }
6710e0e7facSBenjamin 
6720e0e7facSBenjamin     fd = qemu_socket(PF_INET, SOCK_DGRAM, 0);
6730e0e7facSBenjamin     if (fd < 0) {
6740522a959SMao Zhongyi         error_setg_errno(errp, errno, "can't create datagram socket");
6750e0e7facSBenjamin         return -1;
6760e0e7facSBenjamin     }
677bcbe92fbSSebastian Ottlik 
678bcbe92fbSSebastian Ottlik     ret = socket_set_fast_reuse(fd);
6790e0e7facSBenjamin     if (ret < 0) {
6800522a959SMao Zhongyi         error_setg_errno(errp, errno,
6810522a959SMao Zhongyi                          "can't set socket option SO_REUSEADDR");
6820e0e7facSBenjamin         closesocket(fd);
6830e0e7facSBenjamin         return -1;
6840e0e7facSBenjamin     }
6850e0e7facSBenjamin     ret = bind(fd, (struct sockaddr *)&laddr, sizeof(laddr));
6860e0e7facSBenjamin     if (ret < 0) {
6870522a959SMao Zhongyi         error_setg_errno(errp, errno, "can't bind ip=%s to socket",
6880522a959SMao Zhongyi                          inet_ntoa(laddr.sin_addr));
6890e0e7facSBenjamin         closesocket(fd);
6900e0e7facSBenjamin         return -1;
6910e0e7facSBenjamin     }
692fc13fa00SStefan Hajnoczi     qemu_set_nonblock(fd);
6930e0e7facSBenjamin 
6940522a959SMao Zhongyi     s = net_socket_fd_init(peer, model, name, fd, 0, NULL, errp);
6950e0e7facSBenjamin     if (!s) {
6960e0e7facSBenjamin         return -1;
6970e0e7facSBenjamin     }
6980e0e7facSBenjamin 
6990e0e7facSBenjamin     s->dgram_dst = raddr;
7000e0e7facSBenjamin 
7010e0e7facSBenjamin     snprintf(s->nc.info_str, sizeof(s->nc.info_str),
7020e0e7facSBenjamin              "socket: udp=%s:%d",
7030e0e7facSBenjamin              inet_ntoa(raddr.sin_addr), ntohs(raddr.sin_port));
7040e0e7facSBenjamin     return 0;
7050e0e7facSBenjamin }
7060e0e7facSBenjamin 
707cebea510SKővágó, Zoltán int net_init_socket(const Netdev *netdev, const char *name,
708a30ecde6SMarkus Armbruster                     NetClientState *peer, Error **errp)
70942281ac9SMark McLoughlin {
710bef8e8feSLaszlo Ersek     const NetdevSocketOptions *sock;
711bef8e8feSLaszlo Ersek 
712f394b2e2SEric Blake     assert(netdev->type == NET_CLIENT_DRIVER_SOCKET);
713f394b2e2SEric Blake     sock = &netdev->u.socket;
714bef8e8feSLaszlo Ersek 
715ff86d576SJens Freimann     if (sock->has_fd + sock->has_listen + sock->has_connect + sock->has_mcast +
716ff86d576SJens Freimann         sock->has_udp != 1) {
7170522a959SMao Zhongyi         error_setg(errp, "exactly one of listen=, connect=, mcast= or udp="
718bef8e8feSLaszlo Ersek                    " is required");
719bef8e8feSLaszlo Ersek         return -1;
720bef8e8feSLaszlo Ersek     }
721bef8e8feSLaszlo Ersek 
722bef8e8feSLaszlo Ersek     if (sock->has_localaddr && !sock->has_mcast && !sock->has_udp) {
7230522a959SMao Zhongyi         error_setg(errp, "localaddr= is only valid with mcast= or udp=");
724bef8e8feSLaszlo Ersek         return -1;
725bef8e8feSLaszlo Ersek     }
726bef8e8feSLaszlo Ersek 
727bef8e8feSLaszlo Ersek     if (sock->has_fd) {
728894022e6SLaurent Vivier         int fd, ret;
72942281ac9SMark McLoughlin 
730*947e4744SKevin Wolf         fd = monitor_fd_param(monitor_cur(), sock->fd, errp);
731fc13fa00SStefan Hajnoczi         if (fd == -1) {
732fc13fa00SStefan Hajnoczi             return -1;
733fc13fa00SStefan Hajnoczi         }
734894022e6SLaurent Vivier         ret = qemu_try_set_nonblock(fd);
735894022e6SLaurent Vivier         if (ret < 0) {
736894022e6SLaurent Vivier             error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d",
737894022e6SLaurent Vivier                              name, fd);
738894022e6SLaurent Vivier             return -1;
739894022e6SLaurent Vivier         }
740c37f0bb1SMao Zhongyi         if (!net_socket_fd_init(peer, "socket", name, fd, 1, sock->mcast,
741c37f0bb1SMao Zhongyi                                 errp)) {
74242281ac9SMark McLoughlin             return -1;
74342281ac9SMark McLoughlin         }
744bef8e8feSLaszlo Ersek         return 0;
74542281ac9SMark McLoughlin     }
74642281ac9SMark McLoughlin 
747bef8e8feSLaszlo Ersek     if (sock->has_listen) {
7480522a959SMao Zhongyi         if (net_socket_listen_init(peer, "socket", name, sock->listen, errp)
7490522a959SMao Zhongyi             < 0) {
75042281ac9SMark McLoughlin             return -1;
75142281ac9SMark McLoughlin         }
752bef8e8feSLaszlo Ersek         return 0;
75342281ac9SMark McLoughlin     }
75442281ac9SMark McLoughlin 
755bef8e8feSLaszlo Ersek     if (sock->has_connect) {
7560522a959SMao Zhongyi         if (net_socket_connect_init(peer, "socket", name, sock->connect, errp)
7570522a959SMao Zhongyi             < 0) {
75842281ac9SMark McLoughlin             return -1;
75942281ac9SMark McLoughlin         }
760bef8e8feSLaszlo Ersek         return 0;
76142281ac9SMark McLoughlin     }
76242281ac9SMark McLoughlin 
763bef8e8feSLaszlo Ersek     if (sock->has_mcast) {
764bef8e8feSLaszlo Ersek         /* if sock->localaddr is missing, it has been initialized to "all bits
765bef8e8feSLaszlo Ersek          * zero" */
766d33d93b2SStefan Hajnoczi         if (net_socket_mcast_init(peer, "socket", name, sock->mcast,
7670522a959SMao Zhongyi                                   sock->localaddr, errp) < 0) {
76842281ac9SMark McLoughlin             return -1;
76942281ac9SMark McLoughlin         }
770bef8e8feSLaszlo Ersek         return 0;
77142281ac9SMark McLoughlin     }
77242281ac9SMark McLoughlin 
773bef8e8feSLaszlo Ersek     assert(sock->has_udp);
774bef8e8feSLaszlo Ersek     if (!sock->has_localaddr) {
7750522a959SMao Zhongyi         error_setg(errp, "localaddr= is mandatory with udp=");
7760e0e7facSBenjamin         return -1;
7770e0e7facSBenjamin     }
7780522a959SMao Zhongyi     if (net_socket_udp_init(peer, "socket", name, sock->udp, sock->localaddr,
7790522a959SMao Zhongyi                             errp) < 0) {
7800e0e7facSBenjamin         return -1;
7810e0e7facSBenjamin     }
78242281ac9SMark McLoughlin     return 0;
78342281ac9SMark McLoughlin }
784