xref: /qemu/net/socket.c (revision 23455ae3)
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 
12037b0b24eSNikita Ivanov     ret = RETRY_ON_EINTR(
12137b0b24eSNikita Ivanov         s->dgram_dst.sin_family != AF_UNIX ?
12237b0b24eSNikita Ivanov             sendto(s->fd, buf, size, 0,
123213fd508SStefan Hajnoczi                      (struct sockaddr *)&s->dgram_dst,
12437b0b24eSNikita Ivanov                      sizeof(s->dgram_dst)) :
12537b0b24eSNikita Ivanov             send(s->fd, buf, size, 0)
12637b0b24eSNikita Ivanov     );
127213fd508SStefan Hajnoczi 
128213fd508SStefan Hajnoczi     if (ret == -1 && errno == EAGAIN) {
129213fd508SStefan Hajnoczi         net_socket_write_poll(s, true);
130213fd508SStefan Hajnoczi         return 0;
131213fd508SStefan Hajnoczi     }
132213fd508SStefan Hajnoczi     return ret;
13342281ac9SMark McLoughlin }
13442281ac9SMark McLoughlin 
1356e99c631SFam Zheng static void net_socket_send_completed(NetClientState *nc, ssize_t len)
1366e99c631SFam Zheng {
1376e99c631SFam Zheng     NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
1386e99c631SFam Zheng 
1396e99c631SFam Zheng     if (!s->read_poll) {
1406e99c631SFam Zheng         net_socket_read_poll(s, true);
1416e99c631SFam Zheng     }
1426e99c631SFam Zheng }
1436e99c631SFam Zheng 
14416a3df40SZhang Chen static void net_socket_rs_finalize(SocketReadState *rs)
14516a3df40SZhang Chen {
14616a3df40SZhang Chen     NetSocketState *s = container_of(rs, NetSocketState, rs);
14716a3df40SZhang Chen 
14816a3df40SZhang Chen     if (qemu_send_packet_async(&s->nc, rs->buf,
14916a3df40SZhang Chen                                rs->packet_len,
15016a3df40SZhang Chen                                net_socket_send_completed) == 0) {
15116a3df40SZhang Chen         net_socket_read_poll(s, false);
15216a3df40SZhang Chen     }
15316a3df40SZhang Chen }
15416a3df40SZhang Chen 
15542281ac9SMark McLoughlin static void net_socket_send(void *opaque)
15642281ac9SMark McLoughlin {
15742281ac9SMark McLoughlin     NetSocketState *s = opaque;
158b16a44e1SDaniel P. Berrange     int size;
15916a3df40SZhang Chen     int ret;
160d32fcad3SScott Feldman     uint8_t buf1[NET_BUFSIZE];
16142281ac9SMark McLoughlin     const uint8_t *buf;
16242281ac9SMark McLoughlin 
163e7b79428SMarc-André Lureau     size = recv(s->fd, buf1, sizeof(buf1), 0);
16442281ac9SMark McLoughlin     if (size < 0) {
165b16a44e1SDaniel P. Berrange         if (errno != EWOULDBLOCK)
16642281ac9SMark McLoughlin             goto eoc;
16742281ac9SMark McLoughlin     } else if (size == 0) {
16842281ac9SMark McLoughlin         /* end of connection */
16942281ac9SMark McLoughlin     eoc:
170863f678fSStefan Hajnoczi         net_socket_read_poll(s, false);
171863f678fSStefan Hajnoczi         net_socket_write_poll(s, false);
172011de2b5SZhi Yong Wu         if (s->listen_fd != -1) {
173011de2b5SZhi Yong Wu             qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s);
174011de2b5SZhi Yong Wu         }
17525657fc6SMarc-André Lureau         close(s->fd);
176011de2b5SZhi Yong Wu 
177011de2b5SZhi Yong Wu         s->fd = -1;
1783cde5ea2SZhang Chen         net_socket_rs_init(&s->rs, net_socket_rs_finalize, false);
179011de2b5SZhi Yong Wu         s->nc.link_down = true;
180ac149498SStefan Weil via         qemu_set_info_str(&s->nc, "%s", "");
181011de2b5SZhi Yong Wu 
18242281ac9SMark McLoughlin         return;
18342281ac9SMark McLoughlin     }
18442281ac9SMark McLoughlin     buf = buf1;
18542281ac9SMark McLoughlin 
18616a3df40SZhang Chen     ret = net_fill_rstate(&s->rs, buf, size);
18716a3df40SZhang Chen 
18816a3df40SZhang Chen     if (ret == -1) {
18916a3df40SZhang Chen         goto eoc;
19042281ac9SMark McLoughlin     }
19142281ac9SMark McLoughlin }
19242281ac9SMark McLoughlin 
19342281ac9SMark McLoughlin static void net_socket_send_dgram(void *opaque)
19442281ac9SMark McLoughlin {
19542281ac9SMark McLoughlin     NetSocketState *s = opaque;
19642281ac9SMark McLoughlin     int size;
19742281ac9SMark McLoughlin 
198e7b79428SMarc-André Lureau     size = recv(s->fd, s->rs.buf, sizeof(s->rs.buf), 0);
19942281ac9SMark McLoughlin     if (size < 0)
20042281ac9SMark McLoughlin         return;
20142281ac9SMark McLoughlin     if (size == 0) {
20242281ac9SMark McLoughlin         /* end of connection */
203863f678fSStefan Hajnoczi         net_socket_read_poll(s, false);
204863f678fSStefan Hajnoczi         net_socket_write_poll(s, false);
20542281ac9SMark McLoughlin         return;
20642281ac9SMark McLoughlin     }
20716a3df40SZhang Chen     if (qemu_send_packet_async(&s->nc, s->rs.buf, size,
2086e99c631SFam Zheng                                net_socket_send_completed) == 0) {
2096e99c631SFam Zheng         net_socket_read_poll(s, false);
2106e99c631SFam Zheng     }
21142281ac9SMark McLoughlin }
21242281ac9SMark McLoughlin 
213c37f0bb1SMao Zhongyi static int net_socket_mcast_create(struct sockaddr_in *mcastaddr,
214c37f0bb1SMao Zhongyi                                    struct in_addr *localaddr,
215c37f0bb1SMao Zhongyi                                    Error **errp)
21642281ac9SMark McLoughlin {
21742281ac9SMark McLoughlin     struct ip_mreq imr;
21842281ac9SMark McLoughlin     int fd;
21942281ac9SMark McLoughlin     int val, ret;
22023ddf2bbSBrad #ifdef __OpenBSD__
22123ddf2bbSBrad     unsigned char loop;
22223ddf2bbSBrad #else
22323ddf2bbSBrad     int loop;
22423ddf2bbSBrad #endif
22523ddf2bbSBrad 
22642281ac9SMark McLoughlin     if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) {
227c37f0bb1SMao Zhongyi         error_setg(errp, "specified mcastaddr %s (0x%08x) "
228c37f0bb1SMao Zhongyi                    "does not contain a multicast address",
22942281ac9SMark McLoughlin                    inet_ntoa(mcastaddr->sin_addr),
23042281ac9SMark McLoughlin                    (int)ntohl(mcastaddr->sin_addr.s_addr));
23142281ac9SMark McLoughlin         return -1;
23242281ac9SMark McLoughlin     }
233c37f0bb1SMao Zhongyi 
23440ff6d7eSKevin Wolf     fd = qemu_socket(PF_INET, SOCK_DGRAM, 0);
23542281ac9SMark McLoughlin     if (fd < 0) {
236c37f0bb1SMao Zhongyi         error_setg_errno(errp, errno, "can't create datagram socket");
23742281ac9SMark McLoughlin         return -1;
23842281ac9SMark McLoughlin     }
23942281ac9SMark McLoughlin 
240bcbe92fbSSebastian Ottlik     /* Allow multiple sockets to bind the same multicast ip and port by setting
241bcbe92fbSSebastian Ottlik      * SO_REUSEADDR. This is the only situation where SO_REUSEADDR should be set
242bcbe92fbSSebastian Ottlik      * on windows. Use socket_set_fast_reuse otherwise as it sets SO_REUSEADDR
243bcbe92fbSSebastian Ottlik      * only on posix systems.
244bcbe92fbSSebastian Ottlik      */
24542281ac9SMark McLoughlin     val = 1;
246e7b79428SMarc-André Lureau     ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
24742281ac9SMark McLoughlin     if (ret < 0) {
248c37f0bb1SMao Zhongyi         error_setg_errno(errp, errno,
249c37f0bb1SMao Zhongyi                          "can't set socket option SO_REUSEADDR");
25042281ac9SMark McLoughlin         goto fail;
25142281ac9SMark McLoughlin     }
25242281ac9SMark McLoughlin 
25342281ac9SMark McLoughlin     ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr));
25442281ac9SMark McLoughlin     if (ret < 0) {
255c37f0bb1SMao Zhongyi         error_setg_errno(errp, errno, "can't bind ip=%s to socket",
256c37f0bb1SMao Zhongyi                          inet_ntoa(mcastaddr->sin_addr));
25742281ac9SMark McLoughlin         goto fail;
25842281ac9SMark McLoughlin     }
25942281ac9SMark McLoughlin 
26042281ac9SMark McLoughlin     /* Add host to multicast group */
26142281ac9SMark McLoughlin     imr.imr_multiaddr = mcastaddr->sin_addr;
2623a75e74cSMike Ryan     if (localaddr) {
2633a75e74cSMike Ryan         imr.imr_interface = *localaddr;
2643a75e74cSMike Ryan     } else {
26542281ac9SMark McLoughlin         imr.imr_interface.s_addr = htonl(INADDR_ANY);
2663a75e74cSMike Ryan     }
26742281ac9SMark McLoughlin 
268e7b79428SMarc-André Lureau     ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
2699957fc7fSStefan Weil                      &imr, sizeof(struct ip_mreq));
27042281ac9SMark McLoughlin     if (ret < 0) {
271c37f0bb1SMao Zhongyi         error_setg_errno(errp, errno,
272c37f0bb1SMao Zhongyi                          "can't add socket to multicast group %s",
273c37f0bb1SMao Zhongyi                          inet_ntoa(imr.imr_multiaddr));
27442281ac9SMark McLoughlin         goto fail;
27542281ac9SMark McLoughlin     }
27642281ac9SMark McLoughlin 
27742281ac9SMark McLoughlin     /* Force mcast msgs to loopback (eg. several QEMUs in same host */
27823ddf2bbSBrad     loop = 1;
279e7b79428SMarc-André Lureau     ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
2809957fc7fSStefan Weil                      &loop, sizeof(loop));
28142281ac9SMark McLoughlin     if (ret < 0) {
282c37f0bb1SMao Zhongyi         error_setg_errno(errp, errno,
283c37f0bb1SMao Zhongyi                          "can't force multicast message to loopback");
28442281ac9SMark McLoughlin         goto fail;
28542281ac9SMark McLoughlin     }
28642281ac9SMark McLoughlin 
2873a75e74cSMike Ryan     /* If a bind address is given, only send packets from that address */
2883a75e74cSMike Ryan     if (localaddr != NULL) {
289e7b79428SMarc-André Lureau         ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
2909957fc7fSStefan Weil                          localaddr, sizeof(*localaddr));
2913a75e74cSMike Ryan         if (ret < 0) {
292c37f0bb1SMao Zhongyi             error_setg_errno(errp, errno,
293c37f0bb1SMao Zhongyi                              "can't set the default network send interface");
2943a75e74cSMike Ryan             goto fail;
2953a75e74cSMike Ryan         }
2963a75e74cSMike Ryan     }
2973a75e74cSMike Ryan 
298ff5927baSMarc-André Lureau     qemu_socket_set_nonblock(fd);
29942281ac9SMark McLoughlin     return fd;
30042281ac9SMark McLoughlin fail:
30142281ac9SMark McLoughlin     if (fd >= 0)
30225657fc6SMarc-André Lureau         close(fd);
30342281ac9SMark McLoughlin     return -1;
30442281ac9SMark McLoughlin }
30542281ac9SMark McLoughlin 
3064e68f7a0SStefan Hajnoczi static void net_socket_cleanup(NetClientState *nc)
30742281ac9SMark McLoughlin {
308564f63e3SMark McLoughlin     NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
309011de2b5SZhi Yong Wu     if (s->fd != -1) {
310863f678fSStefan Hajnoczi         net_socket_read_poll(s, false);
311863f678fSStefan Hajnoczi         net_socket_write_poll(s, false);
31242281ac9SMark McLoughlin         close(s->fd);
313011de2b5SZhi Yong Wu         s->fd = -1;
314011de2b5SZhi Yong Wu     }
315011de2b5SZhi Yong Wu     if (s->listen_fd != -1) {
316011de2b5SZhi Yong Wu         qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
31725657fc6SMarc-André Lureau         close(s->listen_fd);
318011de2b5SZhi Yong Wu         s->listen_fd = -1;
319011de2b5SZhi Yong Wu     }
32042281ac9SMark McLoughlin }
32142281ac9SMark McLoughlin 
322564f63e3SMark McLoughlin static NetClientInfo net_dgram_socket_info = {
323f394b2e2SEric Blake     .type = NET_CLIENT_DRIVER_SOCKET,
324564f63e3SMark McLoughlin     .size = sizeof(NetSocketState),
325564f63e3SMark McLoughlin     .receive = net_socket_receive_dgram,
326564f63e3SMark McLoughlin     .cleanup = net_socket_cleanup,
327564f63e3SMark McLoughlin };
328564f63e3SMark McLoughlin 
3294e68f7a0SStefan Hajnoczi static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer,
33042281ac9SMark McLoughlin                                                 const char *model,
33142281ac9SMark McLoughlin                                                 const char *name,
3320f8c289aSJens Freimann                                                 int fd, int is_connected,
333c37f0bb1SMao Zhongyi                                                 const char *mcast,
334c37f0bb1SMao Zhongyi                                                 Error **errp)
33542281ac9SMark McLoughlin {
33642281ac9SMark McLoughlin     struct sockaddr_in saddr;
33742281ac9SMark McLoughlin     int newfd;
3384e68f7a0SStefan Hajnoczi     NetClientState *nc;
33942281ac9SMark McLoughlin     NetSocketState *s;
340fdec16e3SMarc-André Lureau     SocketAddress *sa;
341fdec16e3SMarc-André Lureau     SocketAddressType sa_type;
342fdec16e3SMarc-André Lureau 
343fdec16e3SMarc-André Lureau     sa = socket_local_address(fd, errp);
344fdec16e3SMarc-André Lureau     if (!sa) {
345fdec16e3SMarc-André Lureau         return NULL;
346fdec16e3SMarc-André Lureau     }
347fdec16e3SMarc-André Lureau     sa_type = sa->type;
348fdec16e3SMarc-André Lureau     qapi_free_SocketAddress(sa);
34942281ac9SMark McLoughlin 
35042281ac9SMark McLoughlin     /* fd passed: multicast: "learn" dgram_dst address from bound address and save it
35142281ac9SMark McLoughlin      * Because this may be "shared" socket from a "master" process, datagrams would be recv()
35242281ac9SMark McLoughlin      * by ONLY ONE process: we must "clone" this dgram socket --jjo
35342281ac9SMark McLoughlin      */
35442281ac9SMark McLoughlin 
3550f8c289aSJens Freimann     if (is_connected && mcast != NULL) {
356bcd4dfd6SMao Zhongyi             if (parse_host_port(&saddr, mcast, errp) < 0) {
3570f8c289aSJens Freimann                 goto err;
3580f8c289aSJens Freimann             }
35942281ac9SMark McLoughlin             /* must be bound */
36042281ac9SMark McLoughlin             if (saddr.sin_addr.s_addr == 0) {
361c37f0bb1SMao Zhongyi                 error_setg(errp, "can't setup multicast destination address");
362e5d1fca0SStefan Hajnoczi                 goto err;
36342281ac9SMark McLoughlin             }
36442281ac9SMark McLoughlin             /* clone dgram socket */
365c37f0bb1SMao Zhongyi             newfd = net_socket_mcast_create(&saddr, NULL, errp);
36642281ac9SMark McLoughlin             if (newfd < 0) {
367e5d1fca0SStefan Hajnoczi                 goto err;
36842281ac9SMark McLoughlin             }
36942281ac9SMark McLoughlin             /* clone newfd to fd, close newfd */
37042281ac9SMark McLoughlin             dup2(newfd, fd);
37142281ac9SMark McLoughlin             close(newfd);
37242281ac9SMark McLoughlin 
37342281ac9SMark McLoughlin     }
37442281ac9SMark McLoughlin 
375ab5f3f84SStefan Hajnoczi     nc = qemu_new_net_client(&net_dgram_socket_info, peer, model, name);
376564f63e3SMark McLoughlin 
377564f63e3SMark McLoughlin     s = DO_UPCAST(NetSocketState, nc, nc);
378564f63e3SMark McLoughlin 
37942281ac9SMark McLoughlin     s->fd = fd;
380011de2b5SZhi Yong Wu     s->listen_fd = -1;
381863f678fSStefan Hajnoczi     s->send_fn = net_socket_send_dgram;
3823cde5ea2SZhang Chen     net_socket_rs_init(&s->rs, net_socket_rs_finalize, false);
383863f678fSStefan Hajnoczi     net_socket_read_poll(s, true);
38442281ac9SMark McLoughlin 
38542281ac9SMark McLoughlin     /* mcast: save bound address as dst */
386bb160b57SJens Freimann     if (is_connected && mcast != NULL) {
387e34cde35SZhi Yong Wu         s->dgram_dst = saddr;
38853b85d95SLaurent Vivier         qemu_set_info_str(nc, "socket: fd=%d (cloned mcast=%s:%d)", fd,
38953b85d95SLaurent Vivier                           inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
3908db804acSGonglei     } else {
391fdec16e3SMarc-André Lureau         if (sa_type == SOCKET_ADDRESS_TYPE_UNIX) {
392fdec16e3SMarc-André Lureau             s->dgram_dst.sin_family = AF_UNIX;
393fdec16e3SMarc-André Lureau         }
394d89b4f83SJason Wang 
39553b85d95SLaurent Vivier         qemu_set_info_str(nc, "socket: fd=%d %s", fd,
39653b85d95SLaurent Vivier                           SocketAddressType_str(sa_type));
397e34cde35SZhi Yong Wu     }
39842281ac9SMark McLoughlin 
39942281ac9SMark McLoughlin     return s;
400e5d1fca0SStefan Hajnoczi 
401e5d1fca0SStefan Hajnoczi err:
40225657fc6SMarc-André Lureau     close(fd);
403e5d1fca0SStefan Hajnoczi     return NULL;
40442281ac9SMark McLoughlin }
40542281ac9SMark McLoughlin 
40642281ac9SMark McLoughlin static void net_socket_connect(void *opaque)
40742281ac9SMark McLoughlin {
40842281ac9SMark McLoughlin     NetSocketState *s = opaque;
409863f678fSStefan Hajnoczi     s->send_fn = net_socket_send;
410863f678fSStefan Hajnoczi     net_socket_read_poll(s, true);
41142281ac9SMark McLoughlin }
41242281ac9SMark McLoughlin 
413564f63e3SMark McLoughlin static NetClientInfo net_socket_info = {
414f394b2e2SEric Blake     .type = NET_CLIENT_DRIVER_SOCKET,
415564f63e3SMark McLoughlin     .size = sizeof(NetSocketState),
416564f63e3SMark McLoughlin     .receive = net_socket_receive,
417564f63e3SMark McLoughlin     .cleanup = net_socket_cleanup,
418564f63e3SMark McLoughlin };
419564f63e3SMark McLoughlin 
4204e68f7a0SStefan Hajnoczi static NetSocketState *net_socket_fd_init_stream(NetClientState *peer,
42142281ac9SMark McLoughlin                                                  const char *model,
42242281ac9SMark McLoughlin                                                  const char *name,
42342281ac9SMark McLoughlin                                                  int fd, int is_connected)
42442281ac9SMark McLoughlin {
4254e68f7a0SStefan Hajnoczi     NetClientState *nc;
42642281ac9SMark McLoughlin     NetSocketState *s;
427564f63e3SMark McLoughlin 
428ab5f3f84SStefan Hajnoczi     nc = qemu_new_net_client(&net_socket_info, peer, model, name);
429564f63e3SMark McLoughlin 
43053b85d95SLaurent Vivier     qemu_set_info_str(nc, "socket: fd=%d", fd);
431d89b4f83SJason Wang 
432564f63e3SMark McLoughlin     s = DO_UPCAST(NetSocketState, nc, nc);
433564f63e3SMark McLoughlin 
43442281ac9SMark McLoughlin     s->fd = fd;
435011de2b5SZhi Yong Wu     s->listen_fd = -1;
4363cde5ea2SZhang Chen     net_socket_rs_init(&s->rs, net_socket_rs_finalize, false);
437564f63e3SMark McLoughlin 
43820048d0aSStefan Hajnoczi     /* Disable Nagle algorithm on TCP sockets to reduce latency */
43920048d0aSStefan Hajnoczi     socket_set_nodelay(fd);
44020048d0aSStefan Hajnoczi 
44142281ac9SMark McLoughlin     if (is_connected) {
44242281ac9SMark McLoughlin         net_socket_connect(s);
44342281ac9SMark McLoughlin     } else {
44442281ac9SMark McLoughlin         qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s);
44542281ac9SMark McLoughlin     }
44642281ac9SMark McLoughlin     return s;
44742281ac9SMark McLoughlin }
44842281ac9SMark McLoughlin 
44923455ae3SLaurent Vivier static int net_socket_fd_check(int fd, Error **errp)
45023455ae3SLaurent Vivier {
45123455ae3SLaurent Vivier     int so_type, optlen = sizeof(so_type);
45223455ae3SLaurent Vivier 
45323455ae3SLaurent Vivier     if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type,
45423455ae3SLaurent Vivier         (socklen_t *)&optlen) < 0) {
45523455ae3SLaurent Vivier         error_setg(errp, "can't get socket option SO_TYPE");
45623455ae3SLaurent Vivier         return -1;
45723455ae3SLaurent Vivier     }
45823455ae3SLaurent Vivier     if (so_type != SOCK_DGRAM && so_type != SOCK_STREAM) {
45923455ae3SLaurent Vivier         error_setg(errp, "socket type=%d for fd=%d must be either"
46023455ae3SLaurent Vivier                    " SOCK_DGRAM or SOCK_STREAM", so_type, fd);
46123455ae3SLaurent Vivier         return -1;
46223455ae3SLaurent Vivier     }
46323455ae3SLaurent Vivier     return so_type;
46423455ae3SLaurent Vivier }
46523455ae3SLaurent Vivier 
4664e68f7a0SStefan Hajnoczi static NetSocketState *net_socket_fd_init(NetClientState *peer,
46742281ac9SMark McLoughlin                                           const char *model, const char *name,
468c37f0bb1SMao Zhongyi                                           int fd, int is_connected,
469c37f0bb1SMao Zhongyi                                           const char *mc, Error **errp)
47042281ac9SMark McLoughlin {
47123455ae3SLaurent Vivier     int so_type;
47242281ac9SMark McLoughlin 
47323455ae3SLaurent Vivier     so_type = net_socket_fd_check(fd, errp);
47423455ae3SLaurent Vivier     if (so_type < 0) {
47525657fc6SMarc-André Lureau         close(fd);
47642281ac9SMark McLoughlin         return NULL;
47742281ac9SMark McLoughlin     }
47842281ac9SMark McLoughlin     switch(so_type) {
47942281ac9SMark McLoughlin     case SOCK_DGRAM:
480c37f0bb1SMao Zhongyi         return net_socket_fd_init_dgram(peer, model, name, fd, is_connected,
481c37f0bb1SMao Zhongyi                                         mc, errp);
48242281ac9SMark McLoughlin     case SOCK_STREAM:
483d33d93b2SStefan Hajnoczi         return net_socket_fd_init_stream(peer, model, name, fd, is_connected);
48442281ac9SMark McLoughlin     }
48542281ac9SMark McLoughlin     return NULL;
48642281ac9SMark McLoughlin }
48742281ac9SMark McLoughlin 
48842281ac9SMark McLoughlin static void net_socket_accept(void *opaque)
48942281ac9SMark McLoughlin {
490011de2b5SZhi Yong Wu     NetSocketState *s = opaque;
49142281ac9SMark McLoughlin     struct sockaddr_in saddr;
49242281ac9SMark McLoughlin     socklen_t len;
49342281ac9SMark McLoughlin     int fd;
49442281ac9SMark McLoughlin 
49542281ac9SMark McLoughlin     for(;;) {
49642281ac9SMark McLoughlin         len = sizeof(saddr);
497011de2b5SZhi Yong Wu         fd = qemu_accept(s->listen_fd, (struct sockaddr *)&saddr, &len);
49842281ac9SMark McLoughlin         if (fd < 0 && errno != EINTR) {
49942281ac9SMark McLoughlin             return;
50042281ac9SMark McLoughlin         } else if (fd >= 0) {
501011de2b5SZhi Yong Wu             qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
50242281ac9SMark McLoughlin             break;
50342281ac9SMark McLoughlin         }
50442281ac9SMark McLoughlin     }
505011de2b5SZhi Yong Wu 
506011de2b5SZhi Yong Wu     s->fd = fd;
507011de2b5SZhi Yong Wu     s->nc.link_down = false;
508011de2b5SZhi Yong Wu     net_socket_connect(s);
50953b85d95SLaurent Vivier     qemu_set_info_str(&s->nc, "socket: connection from %s:%d",
51056e6f594SJason Wang                       inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
51142281ac9SMark McLoughlin }
51242281ac9SMark McLoughlin 
5134e68f7a0SStefan Hajnoczi static int net_socket_listen_init(NetClientState *peer,
51442281ac9SMark McLoughlin                                   const char *model,
51542281ac9SMark McLoughlin                                   const char *name,
5160522a959SMao Zhongyi                                   const char *host_str,
5170522a959SMao Zhongyi                                   Error **errp)
51842281ac9SMark McLoughlin {
519011de2b5SZhi Yong Wu     NetClientState *nc;
520011de2b5SZhi Yong Wu     NetSocketState *s;
5216701e551SDaniel P. Berrange     struct sockaddr_in saddr;
5226701e551SDaniel P. Berrange     int fd, ret;
52342281ac9SMark McLoughlin 
5240522a959SMao Zhongyi     if (parse_host_port(&saddr, host_str, errp) < 0) {
5256701e551SDaniel P. Berrange         return -1;
526bcd4dfd6SMao Zhongyi     }
5276701e551SDaniel P. Berrange 
5286701e551SDaniel P. Berrange     fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
5296701e551SDaniel P. Berrange     if (fd < 0) {
5300522a959SMao Zhongyi         error_setg_errno(errp, errno, "can't create stream socket");
53142281ac9SMark McLoughlin         return -1;
53242281ac9SMark McLoughlin     }
533ff5927baSMarc-André Lureau     qemu_socket_set_nonblock(fd);
53442281ac9SMark McLoughlin 
5356701e551SDaniel P. Berrange     socket_set_fast_reuse(fd);
5366701e551SDaniel P. Berrange 
5376701e551SDaniel P. Berrange     ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
53842281ac9SMark McLoughlin     if (ret < 0) {
5390522a959SMao Zhongyi         error_setg_errno(errp, errno, "can't bind ip=%s to socket",
5400522a959SMao Zhongyi                          inet_ntoa(saddr.sin_addr));
54125657fc6SMarc-André Lureau         close(fd);
5426701e551SDaniel P. Berrange         return -1;
5436701e551SDaniel P. Berrange     }
5446701e551SDaniel P. Berrange     ret = listen(fd, 0);
5456701e551SDaniel P. Berrange     if (ret < 0) {
5460522a959SMao Zhongyi         error_setg_errno(errp, errno, "can't listen on socket");
54725657fc6SMarc-André Lureau         close(fd);
54842281ac9SMark McLoughlin         return -1;
54942281ac9SMark McLoughlin     }
550011de2b5SZhi Yong Wu 
551011de2b5SZhi Yong Wu     nc = qemu_new_net_client(&net_socket_info, peer, model, name);
552011de2b5SZhi Yong Wu     s = DO_UPCAST(NetSocketState, nc, nc);
553011de2b5SZhi Yong Wu     s->fd = -1;
5546701e551SDaniel P. Berrange     s->listen_fd = fd;
555011de2b5SZhi Yong Wu     s->nc.link_down = true;
5563cde5ea2SZhang Chen     net_socket_rs_init(&s->rs, net_socket_rs_finalize, false);
557011de2b5SZhi Yong Wu 
558011de2b5SZhi Yong Wu     qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s);
55942281ac9SMark McLoughlin     return 0;
56042281ac9SMark McLoughlin }
56142281ac9SMark McLoughlin 
5624e68f7a0SStefan Hajnoczi static int net_socket_connect_init(NetClientState *peer,
56342281ac9SMark McLoughlin                                    const char *model,
56442281ac9SMark McLoughlin                                    const char *name,
5650522a959SMao Zhongyi                                    const char *host_str,
5660522a959SMao Zhongyi                                    Error **errp)
56742281ac9SMark McLoughlin {
5686701e551SDaniel P. Berrange     NetSocketState *s;
5696701e551SDaniel P. Berrange     int fd, connected, ret;
5706701e551SDaniel P. Berrange     struct sockaddr_in saddr;
57142281ac9SMark McLoughlin 
5720522a959SMao Zhongyi     if (parse_host_port(&saddr, host_str, errp) < 0) {
573883e4f76SMarc-André Lureau         return -1;
574bcd4dfd6SMao Zhongyi     }
5756701e551SDaniel P. Berrange 
5766701e551SDaniel P. Berrange     fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
5776701e551SDaniel P. Berrange     if (fd < 0) {
5780522a959SMao Zhongyi         error_setg_errno(errp, errno, "can't create stream socket");
5796701e551SDaniel P. Berrange         return -1;
5806701e551SDaniel P. Berrange     }
581ff5927baSMarc-André Lureau     qemu_socket_set_nonblock(fd);
5826701e551SDaniel P. Berrange 
5836701e551SDaniel P. Berrange     connected = 0;
5846701e551SDaniel P. Berrange     for(;;) {
5856701e551SDaniel P. Berrange         ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
5866701e551SDaniel P. Berrange         if (ret < 0) {
5876701e551SDaniel P. Berrange             if (errno == EINTR || errno == EWOULDBLOCK) {
5886701e551SDaniel P. Berrange                 /* continue */
5896701e551SDaniel P. Berrange             } else if (errno == EINPROGRESS ||
590daf188ffSStefano Brivio                        errno == EALREADY) {
5916701e551SDaniel P. Berrange                 break;
5926701e551SDaniel P. Berrange             } else {
5930522a959SMao Zhongyi                 error_setg_errno(errp, errno, "can't connect socket");
59425657fc6SMarc-André Lureau                 close(fd);
5956701e551SDaniel P. Berrange                 return -1;
5966701e551SDaniel P. Berrange             }
5976701e551SDaniel P. Berrange         } else {
5986701e551SDaniel P. Berrange             connected = 1;
5996701e551SDaniel P. Berrange             break;
6006701e551SDaniel P. Berrange         }
6016701e551SDaniel P. Berrange     }
602006c3fa7SLaurent Vivier     s = net_socket_fd_init_stream(peer, model, name, fd, connected);
603c37f0bb1SMao Zhongyi     if (!s) {
6046701e551SDaniel P. Berrange         return -1;
605c37f0bb1SMao Zhongyi     }
606c37f0bb1SMao Zhongyi 
60753b85d95SLaurent Vivier     qemu_set_info_str(&s->nc, "socket: connect to %s:%d",
60856e6f594SJason Wang                       inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
6096701e551SDaniel P. Berrange     return 0;
61042281ac9SMark McLoughlin }
61142281ac9SMark McLoughlin 
6124e68f7a0SStefan Hajnoczi static int net_socket_mcast_init(NetClientState *peer,
61342281ac9SMark McLoughlin                                  const char *model,
61442281ac9SMark McLoughlin                                  const char *name,
6153a75e74cSMike Ryan                                  const char *host_str,
6160522a959SMao Zhongyi                                  const char *localaddr_str,
6170522a959SMao Zhongyi                                  Error **errp)
61842281ac9SMark McLoughlin {
61942281ac9SMark McLoughlin     NetSocketState *s;
62042281ac9SMark McLoughlin     int fd;
62142281ac9SMark McLoughlin     struct sockaddr_in saddr;
6223a75e74cSMike Ryan     struct in_addr localaddr, *param_localaddr;
62342281ac9SMark McLoughlin 
6240522a959SMao Zhongyi     if (parse_host_port(&saddr, host_str, errp) < 0) {
62542281ac9SMark McLoughlin         return -1;
626bcd4dfd6SMao Zhongyi     }
62742281ac9SMark McLoughlin 
6283a75e74cSMike Ryan     if (localaddr_str != NULL) {
6290522a959SMao Zhongyi         if (inet_aton(localaddr_str, &localaddr) == 0) {
6300522a959SMao Zhongyi             error_setg(errp, "localaddr '%s' is not a valid IPv4 address",
6310522a959SMao Zhongyi                        localaddr_str);
6323a75e74cSMike Ryan             return -1;
6330522a959SMao Zhongyi         }
6343a75e74cSMike Ryan         param_localaddr = &localaddr;
6353a75e74cSMike Ryan     } else {
6363a75e74cSMike Ryan         param_localaddr = NULL;
6373a75e74cSMike Ryan     }
63842281ac9SMark McLoughlin 
6390522a959SMao Zhongyi     fd = net_socket_mcast_create(&saddr, param_localaddr, errp);
640c37f0bb1SMao Zhongyi     if (fd < 0) {
64142281ac9SMark McLoughlin         return -1;
642c37f0bb1SMao Zhongyi     }
64342281ac9SMark McLoughlin 
644006c3fa7SLaurent Vivier     s = net_socket_fd_init_dgram(peer, model, name, fd, 0, NULL, errp);
645c37f0bb1SMao Zhongyi     if (!s) {
64642281ac9SMark McLoughlin         return -1;
647c37f0bb1SMao Zhongyi     }
64842281ac9SMark McLoughlin 
64942281ac9SMark McLoughlin     s->dgram_dst = saddr;
65042281ac9SMark McLoughlin 
65153b85d95SLaurent Vivier     qemu_set_info_str(&s->nc, "socket: mcast=%s:%d",
65256e6f594SJason Wang                       inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
65342281ac9SMark McLoughlin     return 0;
654d89b4f83SJason Wang 
65542281ac9SMark McLoughlin }
65642281ac9SMark McLoughlin 
6574e68f7a0SStefan Hajnoczi static int net_socket_udp_init(NetClientState *peer,
6580e0e7facSBenjamin                                  const char *model,
6590e0e7facSBenjamin                                  const char *name,
6600e0e7facSBenjamin                                  const char *rhost,
6610522a959SMao Zhongyi                                  const char *lhost,
6620522a959SMao Zhongyi                                  Error **errp)
6630e0e7facSBenjamin {
6640e0e7facSBenjamin     NetSocketState *s;
665bcbe92fbSSebastian Ottlik     int fd, ret;
6660e0e7facSBenjamin     struct sockaddr_in laddr, raddr;
6670e0e7facSBenjamin 
6680522a959SMao Zhongyi     if (parse_host_port(&laddr, lhost, errp) < 0) {
6690e0e7facSBenjamin         return -1;
6700e0e7facSBenjamin     }
6710e0e7facSBenjamin 
6720522a959SMao Zhongyi     if (parse_host_port(&raddr, rhost, errp) < 0) {
6730e0e7facSBenjamin         return -1;
6740e0e7facSBenjamin     }
6750e0e7facSBenjamin 
6760e0e7facSBenjamin     fd = qemu_socket(PF_INET, SOCK_DGRAM, 0);
6770e0e7facSBenjamin     if (fd < 0) {
6780522a959SMao Zhongyi         error_setg_errno(errp, errno, "can't create datagram socket");
6790e0e7facSBenjamin         return -1;
6800e0e7facSBenjamin     }
681bcbe92fbSSebastian Ottlik 
682bcbe92fbSSebastian Ottlik     ret = socket_set_fast_reuse(fd);
6830e0e7facSBenjamin     if (ret < 0) {
6840522a959SMao Zhongyi         error_setg_errno(errp, errno,
6850522a959SMao Zhongyi                          "can't set socket option SO_REUSEADDR");
68625657fc6SMarc-André Lureau         close(fd);
6870e0e7facSBenjamin         return -1;
6880e0e7facSBenjamin     }
6890e0e7facSBenjamin     ret = bind(fd, (struct sockaddr *)&laddr, sizeof(laddr));
6900e0e7facSBenjamin     if (ret < 0) {
6910522a959SMao Zhongyi         error_setg_errno(errp, errno, "can't bind ip=%s to socket",
6920522a959SMao Zhongyi                          inet_ntoa(laddr.sin_addr));
69325657fc6SMarc-André Lureau         close(fd);
6940e0e7facSBenjamin         return -1;
6950e0e7facSBenjamin     }
696ff5927baSMarc-André Lureau     qemu_socket_set_nonblock(fd);
6970e0e7facSBenjamin 
698006c3fa7SLaurent Vivier     s = net_socket_fd_init_dgram(peer, model, name, fd, 0, NULL, errp);
6990e0e7facSBenjamin     if (!s) {
7000e0e7facSBenjamin         return -1;
7010e0e7facSBenjamin     }
7020e0e7facSBenjamin 
7030e0e7facSBenjamin     s->dgram_dst = raddr;
7040e0e7facSBenjamin 
70553b85d95SLaurent Vivier     qemu_set_info_str(&s->nc, "socket: udp=%s:%d", inet_ntoa(raddr.sin_addr),
70653b85d95SLaurent Vivier                       ntohs(raddr.sin_port));
7070e0e7facSBenjamin     return 0;
7080e0e7facSBenjamin }
7090e0e7facSBenjamin 
710cebea510SKővágó, Zoltán int net_init_socket(const Netdev *netdev, const char *name,
711a30ecde6SMarkus Armbruster                     NetClientState *peer, Error **errp)
71242281ac9SMark McLoughlin {
713bef8e8feSLaszlo Ersek     const NetdevSocketOptions *sock;
714bef8e8feSLaszlo Ersek 
715f394b2e2SEric Blake     assert(netdev->type == NET_CLIENT_DRIVER_SOCKET);
716f394b2e2SEric Blake     sock = &netdev->u.socket;
717bef8e8feSLaszlo Ersek 
7187480874aSMarkus Armbruster     if (!!sock->fd + !!sock->listen + !!sock->connect + !!sock->mcast +
7197480874aSMarkus Armbruster         !!sock->udp != 1) {
7200522a959SMao Zhongyi         error_setg(errp, "exactly one of listen=, connect=, mcast= or udp="
721bef8e8feSLaszlo Ersek                    " is required");
722bef8e8feSLaszlo Ersek         return -1;
723bef8e8feSLaszlo Ersek     }
724bef8e8feSLaszlo Ersek 
7257480874aSMarkus Armbruster     if (sock->localaddr && !sock->mcast && !sock->udp) {
7260522a959SMao Zhongyi         error_setg(errp, "localaddr= is only valid with mcast= or udp=");
727bef8e8feSLaszlo Ersek         return -1;
728bef8e8feSLaszlo Ersek     }
729bef8e8feSLaszlo Ersek 
7307480874aSMarkus Armbruster     if (sock->fd) {
731894022e6SLaurent Vivier         int fd, ret;
73242281ac9SMark McLoughlin 
733947e4744SKevin Wolf         fd = monitor_fd_param(monitor_cur(), sock->fd, errp);
734fc13fa00SStefan Hajnoczi         if (fd == -1) {
735fc13fa00SStefan Hajnoczi             return -1;
736fc13fa00SStefan Hajnoczi         }
737ff5927baSMarc-André Lureau         ret = qemu_socket_try_set_nonblock(fd);
738894022e6SLaurent Vivier         if (ret < 0) {
739894022e6SLaurent Vivier             error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d",
740894022e6SLaurent Vivier                              name, fd);
741894022e6SLaurent Vivier             return -1;
742894022e6SLaurent Vivier         }
743c37f0bb1SMao Zhongyi         if (!net_socket_fd_init(peer, "socket", name, fd, 1, sock->mcast,
744c37f0bb1SMao Zhongyi                                 errp)) {
74542281ac9SMark McLoughlin             return -1;
74642281ac9SMark McLoughlin         }
747bef8e8feSLaszlo Ersek         return 0;
74842281ac9SMark McLoughlin     }
74942281ac9SMark McLoughlin 
7507480874aSMarkus Armbruster     if (sock->listen) {
7510522a959SMao Zhongyi         if (net_socket_listen_init(peer, "socket", name, sock->listen, errp)
7520522a959SMao Zhongyi             < 0) {
75342281ac9SMark McLoughlin             return -1;
75442281ac9SMark McLoughlin         }
755bef8e8feSLaszlo Ersek         return 0;
75642281ac9SMark McLoughlin     }
75742281ac9SMark McLoughlin 
7587480874aSMarkus Armbruster     if (sock->connect) {
7590522a959SMao Zhongyi         if (net_socket_connect_init(peer, "socket", name, sock->connect, errp)
7600522a959SMao Zhongyi             < 0) {
76142281ac9SMark McLoughlin             return -1;
76242281ac9SMark McLoughlin         }
763bef8e8feSLaszlo Ersek         return 0;
76442281ac9SMark McLoughlin     }
76542281ac9SMark McLoughlin 
7667480874aSMarkus Armbruster     if (sock->mcast) {
767bef8e8feSLaszlo Ersek         /* if sock->localaddr is missing, it has been initialized to "all bits
768bef8e8feSLaszlo Ersek          * zero" */
769d33d93b2SStefan Hajnoczi         if (net_socket_mcast_init(peer, "socket", name, sock->mcast,
7700522a959SMao Zhongyi                                   sock->localaddr, errp) < 0) {
77142281ac9SMark McLoughlin             return -1;
77242281ac9SMark McLoughlin         }
773bef8e8feSLaszlo Ersek         return 0;
77442281ac9SMark McLoughlin     }
77542281ac9SMark McLoughlin 
7767480874aSMarkus Armbruster     assert(sock->udp);
7777480874aSMarkus Armbruster     if (!sock->localaddr) {
7780522a959SMao Zhongyi         error_setg(errp, "localaddr= is mandatory with udp=");
7790e0e7facSBenjamin         return -1;
7800e0e7facSBenjamin     }
7810522a959SMao Zhongyi     if (net_socket_udp_init(peer, "socket", name, sock->udp, sock->localaddr,
7820522a959SMao Zhongyi                             errp) < 0) {
7830e0e7facSBenjamin         return -1;
7840e0e7facSBenjamin     }
78542281ac9SMark McLoughlin     return 0;
78642281ac9SMark McLoughlin }
787