xref: /qemu/net/socket.c (revision b6aeee02)
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 
net_socket_update_fd_handler(NetSocketState * s)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 
net_socket_read_poll(NetSocketState * s,bool enable)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 
net_socket_write_poll(NetSocketState * s,bool enable)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 
net_socket_writable(void * opaque)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 
net_socket_receive(NetClientState * nc,const uint8_t * buf,size_t size)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 
net_socket_receive_dgram(NetClientState * nc,const uint8_t * buf,size_t size)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 
net_socket_send_completed(NetClientState * nc,ssize_t len)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 
net_socket_rs_finalize(SocketReadState * rs)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 
net_socket_send(void * opaque)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 
net_socket_send_dgram(void * opaque)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 
net_socket_mcast_create(struct sockaddr_in * mcastaddr,struct in_addr * localaddr,Error ** errp)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 
net_socket_cleanup(NetClientState * nc)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 
net_socket_fd_init_dgram(NetClientState * peer,const char * model,const char * name,int fd,int is_connected,const char * mcast,Error ** errp)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 
net_socket_connect(void * opaque)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 
net_socket_fd_init_stream(NetClientState * peer,const char * model,const char * name,int fd,int is_connected)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 
net_socket_fd_check(int fd,Error ** errp)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 
net_socket_accept(void * opaque)46642281ac9SMark McLoughlin static void net_socket_accept(void *opaque)
46742281ac9SMark McLoughlin {
468011de2b5SZhi Yong Wu     NetSocketState *s = opaque;
46942281ac9SMark McLoughlin     struct sockaddr_in saddr;
47042281ac9SMark McLoughlin     socklen_t len;
47142281ac9SMark McLoughlin     int fd;
47242281ac9SMark McLoughlin 
47342281ac9SMark McLoughlin     for(;;) {
47442281ac9SMark McLoughlin         len = sizeof(saddr);
475011de2b5SZhi Yong Wu         fd = qemu_accept(s->listen_fd, (struct sockaddr *)&saddr, &len);
47642281ac9SMark McLoughlin         if (fd < 0 && errno != EINTR) {
47742281ac9SMark McLoughlin             return;
47842281ac9SMark McLoughlin         } else if (fd >= 0) {
479011de2b5SZhi Yong Wu             qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
48042281ac9SMark McLoughlin             break;
48142281ac9SMark McLoughlin         }
48242281ac9SMark McLoughlin     }
483011de2b5SZhi Yong Wu 
484011de2b5SZhi Yong Wu     s->fd = fd;
485011de2b5SZhi Yong Wu     s->nc.link_down = false;
486011de2b5SZhi Yong Wu     net_socket_connect(s);
48753b85d95SLaurent Vivier     qemu_set_info_str(&s->nc, "socket: connection from %s:%d",
48856e6f594SJason Wang                       inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
48942281ac9SMark McLoughlin }
49042281ac9SMark McLoughlin 
net_socket_listen_init(NetClientState * peer,const char * model,const char * name,const char * host_str,Error ** errp)4914e68f7a0SStefan Hajnoczi static int net_socket_listen_init(NetClientState *peer,
49242281ac9SMark McLoughlin                                   const char *model,
49342281ac9SMark McLoughlin                                   const char *name,
4940522a959SMao Zhongyi                                   const char *host_str,
4950522a959SMao Zhongyi                                   Error **errp)
49642281ac9SMark McLoughlin {
497011de2b5SZhi Yong Wu     NetClientState *nc;
498011de2b5SZhi Yong Wu     NetSocketState *s;
4996701e551SDaniel P. Berrange     struct sockaddr_in saddr;
5006701e551SDaniel P. Berrange     int fd, ret;
50142281ac9SMark McLoughlin 
5020522a959SMao Zhongyi     if (parse_host_port(&saddr, host_str, errp) < 0) {
5036701e551SDaniel P. Berrange         return -1;
504bcd4dfd6SMao Zhongyi     }
5056701e551SDaniel P. Berrange 
5066701e551SDaniel P. Berrange     fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
5076701e551SDaniel P. Berrange     if (fd < 0) {
5080522a959SMao Zhongyi         error_setg_errno(errp, errno, "can't create stream socket");
50942281ac9SMark McLoughlin         return -1;
51042281ac9SMark McLoughlin     }
511ff5927baSMarc-André Lureau     qemu_socket_set_nonblock(fd);
51242281ac9SMark McLoughlin 
5136701e551SDaniel P. Berrange     socket_set_fast_reuse(fd);
5146701e551SDaniel P. Berrange 
5156701e551SDaniel P. Berrange     ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
51642281ac9SMark McLoughlin     if (ret < 0) {
5170522a959SMao Zhongyi         error_setg_errno(errp, errno, "can't bind ip=%s to socket",
5180522a959SMao Zhongyi                          inet_ntoa(saddr.sin_addr));
51925657fc6SMarc-André Lureau         close(fd);
5206701e551SDaniel P. Berrange         return -1;
5216701e551SDaniel P. Berrange     }
5226701e551SDaniel P. Berrange     ret = listen(fd, 0);
5236701e551SDaniel P. Berrange     if (ret < 0) {
5240522a959SMao Zhongyi         error_setg_errno(errp, errno, "can't listen on socket");
52525657fc6SMarc-André Lureau         close(fd);
52642281ac9SMark McLoughlin         return -1;
52742281ac9SMark McLoughlin     }
528011de2b5SZhi Yong Wu 
529011de2b5SZhi Yong Wu     nc = qemu_new_net_client(&net_socket_info, peer, model, name);
530011de2b5SZhi Yong Wu     s = DO_UPCAST(NetSocketState, nc, nc);
531011de2b5SZhi Yong Wu     s->fd = -1;
5326701e551SDaniel P. Berrange     s->listen_fd = fd;
533011de2b5SZhi Yong Wu     s->nc.link_down = true;
5343cde5ea2SZhang Chen     net_socket_rs_init(&s->rs, net_socket_rs_finalize, false);
535011de2b5SZhi Yong Wu 
536011de2b5SZhi Yong Wu     qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s);
53742281ac9SMark McLoughlin     return 0;
53842281ac9SMark McLoughlin }
53942281ac9SMark McLoughlin 
net_socket_connect_init(NetClientState * peer,const char * model,const char * name,const char * host_str,Error ** errp)5404e68f7a0SStefan Hajnoczi static int net_socket_connect_init(NetClientState *peer,
54142281ac9SMark McLoughlin                                    const char *model,
54242281ac9SMark McLoughlin                                    const char *name,
5430522a959SMao Zhongyi                                    const char *host_str,
5440522a959SMao Zhongyi                                    Error **errp)
54542281ac9SMark McLoughlin {
5466701e551SDaniel P. Berrange     NetSocketState *s;
5476701e551SDaniel P. Berrange     int fd, connected, ret;
5486701e551SDaniel P. Berrange     struct sockaddr_in saddr;
54942281ac9SMark McLoughlin 
5500522a959SMao Zhongyi     if (parse_host_port(&saddr, host_str, errp) < 0) {
551883e4f76SMarc-André Lureau         return -1;
552bcd4dfd6SMao Zhongyi     }
5536701e551SDaniel P. Berrange 
5546701e551SDaniel P. Berrange     fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
5556701e551SDaniel P. Berrange     if (fd < 0) {
5560522a959SMao Zhongyi         error_setg_errno(errp, errno, "can't create stream socket");
5576701e551SDaniel P. Berrange         return -1;
5586701e551SDaniel P. Berrange     }
559ff5927baSMarc-André Lureau     qemu_socket_set_nonblock(fd);
5606701e551SDaniel P. Berrange 
5616701e551SDaniel P. Berrange     connected = 0;
5626701e551SDaniel P. Berrange     for(;;) {
5636701e551SDaniel P. Berrange         ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
5646701e551SDaniel P. Berrange         if (ret < 0) {
5656701e551SDaniel P. Berrange             if (errno == EINTR || errno == EWOULDBLOCK) {
5666701e551SDaniel P. Berrange                 /* continue */
5676701e551SDaniel P. Berrange             } else if (errno == EINPROGRESS ||
568daf188ffSStefano Brivio                        errno == EALREADY) {
5696701e551SDaniel P. Berrange                 break;
5706701e551SDaniel P. Berrange             } else {
5710522a959SMao Zhongyi                 error_setg_errno(errp, errno, "can't connect socket");
57225657fc6SMarc-André Lureau                 close(fd);
5736701e551SDaniel P. Berrange                 return -1;
5746701e551SDaniel P. Berrange             }
5756701e551SDaniel P. Berrange         } else {
5766701e551SDaniel P. Berrange             connected = 1;
5776701e551SDaniel P. Berrange             break;
5786701e551SDaniel P. Berrange         }
5796701e551SDaniel P. Berrange     }
580006c3fa7SLaurent Vivier     s = net_socket_fd_init_stream(peer, model, name, fd, connected);
581c37f0bb1SMao Zhongyi     if (!s) {
5826701e551SDaniel P. Berrange         return -1;
583c37f0bb1SMao Zhongyi     }
584c37f0bb1SMao Zhongyi 
58553b85d95SLaurent Vivier     qemu_set_info_str(&s->nc, "socket: connect to %s:%d",
58656e6f594SJason Wang                       inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
5876701e551SDaniel P. Berrange     return 0;
58842281ac9SMark McLoughlin }
58942281ac9SMark McLoughlin 
net_socket_mcast_init(NetClientState * peer,const char * model,const char * name,const char * host_str,const char * localaddr_str,Error ** errp)5904e68f7a0SStefan Hajnoczi static int net_socket_mcast_init(NetClientState *peer,
59142281ac9SMark McLoughlin                                  const char *model,
59242281ac9SMark McLoughlin                                  const char *name,
5933a75e74cSMike Ryan                                  const char *host_str,
5940522a959SMao Zhongyi                                  const char *localaddr_str,
5950522a959SMao Zhongyi                                  Error **errp)
59642281ac9SMark McLoughlin {
59742281ac9SMark McLoughlin     NetSocketState *s;
59842281ac9SMark McLoughlin     int fd;
59942281ac9SMark McLoughlin     struct sockaddr_in saddr;
6003a75e74cSMike Ryan     struct in_addr localaddr, *param_localaddr;
60142281ac9SMark McLoughlin 
6020522a959SMao Zhongyi     if (parse_host_port(&saddr, host_str, errp) < 0) {
60342281ac9SMark McLoughlin         return -1;
604bcd4dfd6SMao Zhongyi     }
60542281ac9SMark McLoughlin 
6063a75e74cSMike Ryan     if (localaddr_str != NULL) {
6070522a959SMao Zhongyi         if (inet_aton(localaddr_str, &localaddr) == 0) {
6080522a959SMao Zhongyi             error_setg(errp, "localaddr '%s' is not a valid IPv4 address",
6090522a959SMao Zhongyi                        localaddr_str);
6103a75e74cSMike Ryan             return -1;
6110522a959SMao Zhongyi         }
6123a75e74cSMike Ryan         param_localaddr = &localaddr;
6133a75e74cSMike Ryan     } else {
6143a75e74cSMike Ryan         param_localaddr = NULL;
6153a75e74cSMike Ryan     }
61642281ac9SMark McLoughlin 
6170522a959SMao Zhongyi     fd = net_socket_mcast_create(&saddr, param_localaddr, errp);
618c37f0bb1SMao Zhongyi     if (fd < 0) {
61942281ac9SMark McLoughlin         return -1;
620c37f0bb1SMao Zhongyi     }
62142281ac9SMark McLoughlin 
622006c3fa7SLaurent Vivier     s = net_socket_fd_init_dgram(peer, model, name, fd, 0, NULL, errp);
623c37f0bb1SMao Zhongyi     if (!s) {
62442281ac9SMark McLoughlin         return -1;
625c37f0bb1SMao Zhongyi     }
62642281ac9SMark McLoughlin 
62742281ac9SMark McLoughlin     s->dgram_dst = saddr;
62842281ac9SMark McLoughlin 
62953b85d95SLaurent Vivier     qemu_set_info_str(&s->nc, "socket: mcast=%s:%d",
63056e6f594SJason Wang                       inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
63142281ac9SMark McLoughlin     return 0;
632d89b4f83SJason Wang 
63342281ac9SMark McLoughlin }
63442281ac9SMark McLoughlin 
net_socket_udp_init(NetClientState * peer,const char * model,const char * name,const char * rhost,const char * lhost,Error ** errp)6354e68f7a0SStefan Hajnoczi static int net_socket_udp_init(NetClientState *peer,
6360e0e7facSBenjamin                                  const char *model,
6370e0e7facSBenjamin                                  const char *name,
6380e0e7facSBenjamin                                  const char *rhost,
6390522a959SMao Zhongyi                                  const char *lhost,
6400522a959SMao Zhongyi                                  Error **errp)
6410e0e7facSBenjamin {
6420e0e7facSBenjamin     NetSocketState *s;
643bcbe92fbSSebastian Ottlik     int fd, ret;
6440e0e7facSBenjamin     struct sockaddr_in laddr, raddr;
6450e0e7facSBenjamin 
6460522a959SMao Zhongyi     if (parse_host_port(&laddr, lhost, errp) < 0) {
6470e0e7facSBenjamin         return -1;
6480e0e7facSBenjamin     }
6490e0e7facSBenjamin 
6500522a959SMao Zhongyi     if (parse_host_port(&raddr, rhost, errp) < 0) {
6510e0e7facSBenjamin         return -1;
6520e0e7facSBenjamin     }
6530e0e7facSBenjamin 
6540e0e7facSBenjamin     fd = qemu_socket(PF_INET, SOCK_DGRAM, 0);
6550e0e7facSBenjamin     if (fd < 0) {
6560522a959SMao Zhongyi         error_setg_errno(errp, errno, "can't create datagram socket");
6570e0e7facSBenjamin         return -1;
6580e0e7facSBenjamin     }
659bcbe92fbSSebastian Ottlik 
660bcbe92fbSSebastian Ottlik     ret = socket_set_fast_reuse(fd);
6610e0e7facSBenjamin     if (ret < 0) {
6620522a959SMao Zhongyi         error_setg_errno(errp, errno,
6630522a959SMao Zhongyi                          "can't set socket option SO_REUSEADDR");
66425657fc6SMarc-André Lureau         close(fd);
6650e0e7facSBenjamin         return -1;
6660e0e7facSBenjamin     }
6670e0e7facSBenjamin     ret = bind(fd, (struct sockaddr *)&laddr, sizeof(laddr));
6680e0e7facSBenjamin     if (ret < 0) {
6690522a959SMao Zhongyi         error_setg_errno(errp, errno, "can't bind ip=%s to socket",
6700522a959SMao Zhongyi                          inet_ntoa(laddr.sin_addr));
67125657fc6SMarc-André Lureau         close(fd);
6720e0e7facSBenjamin         return -1;
6730e0e7facSBenjamin     }
674ff5927baSMarc-André Lureau     qemu_socket_set_nonblock(fd);
6750e0e7facSBenjamin 
676006c3fa7SLaurent Vivier     s = net_socket_fd_init_dgram(peer, model, name, fd, 0, NULL, errp);
6770e0e7facSBenjamin     if (!s) {
6780e0e7facSBenjamin         return -1;
6790e0e7facSBenjamin     }
6800e0e7facSBenjamin 
6810e0e7facSBenjamin     s->dgram_dst = raddr;
6820e0e7facSBenjamin 
68353b85d95SLaurent Vivier     qemu_set_info_str(&s->nc, "socket: udp=%s:%d", inet_ntoa(raddr.sin_addr),
68453b85d95SLaurent Vivier                       ntohs(raddr.sin_port));
6850e0e7facSBenjamin     return 0;
6860e0e7facSBenjamin }
6870e0e7facSBenjamin 
net_init_socket(const Netdev * netdev,const char * name,NetClientState * peer,Error ** errp)688cebea510SKővágó, Zoltán int net_init_socket(const Netdev *netdev, const char *name,
689a30ecde6SMarkus Armbruster                     NetClientState *peer, Error **errp)
69042281ac9SMark McLoughlin {
691bef8e8feSLaszlo Ersek     const NetdevSocketOptions *sock;
692bef8e8feSLaszlo Ersek 
693f394b2e2SEric Blake     assert(netdev->type == NET_CLIENT_DRIVER_SOCKET);
694f394b2e2SEric Blake     sock = &netdev->u.socket;
695bef8e8feSLaszlo Ersek 
6967480874aSMarkus Armbruster     if (!!sock->fd + !!sock->listen + !!sock->connect + !!sock->mcast +
6977480874aSMarkus Armbruster         !!sock->udp != 1) {
6980522a959SMao Zhongyi         error_setg(errp, "exactly one of listen=, connect=, mcast= or udp="
699bef8e8feSLaszlo Ersek                    " is required");
700bef8e8feSLaszlo Ersek         return -1;
701bef8e8feSLaszlo Ersek     }
702bef8e8feSLaszlo Ersek 
7037480874aSMarkus Armbruster     if (sock->localaddr && !sock->mcast && !sock->udp) {
7040522a959SMao Zhongyi         error_setg(errp, "localaddr= is only valid with mcast= or udp=");
705bef8e8feSLaszlo Ersek         return -1;
706bef8e8feSLaszlo Ersek     }
707bef8e8feSLaszlo Ersek 
7087480874aSMarkus Armbruster     if (sock->fd) {
709b6aeee02SLaurent Vivier         int fd, ret, so_type;
71042281ac9SMark McLoughlin 
711947e4744SKevin Wolf         fd = monitor_fd_param(monitor_cur(), sock->fd, errp);
712fc13fa00SStefan Hajnoczi         if (fd == -1) {
713fc13fa00SStefan Hajnoczi             return -1;
714fc13fa00SStefan Hajnoczi         }
715b6aeee02SLaurent Vivier         so_type = net_socket_fd_check(fd, errp);
716b6aeee02SLaurent Vivier         if (so_type < 0) {
717b6aeee02SLaurent Vivier             return -1;
718b6aeee02SLaurent Vivier         }
719ff5927baSMarc-André Lureau         ret = qemu_socket_try_set_nonblock(fd);
720894022e6SLaurent Vivier         if (ret < 0) {
721894022e6SLaurent Vivier             error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d",
722894022e6SLaurent Vivier                              name, fd);
723894022e6SLaurent Vivier             return -1;
724894022e6SLaurent Vivier         }
725b6aeee02SLaurent Vivier         switch (so_type) {
726b6aeee02SLaurent Vivier         case SOCK_DGRAM:
727b6aeee02SLaurent Vivier             if (!net_socket_fd_init_dgram(peer, "socket", name, fd, 1,
728b6aeee02SLaurent Vivier                                           sock->mcast, errp)) {
72942281ac9SMark McLoughlin                 return -1;
73042281ac9SMark McLoughlin             }
731b6aeee02SLaurent Vivier             break;
732b6aeee02SLaurent Vivier         case SOCK_STREAM:
733b6aeee02SLaurent Vivier             if (!net_socket_fd_init_stream(peer, "socket", name, fd, 1)) {
734b6aeee02SLaurent Vivier                 return -1;
735b6aeee02SLaurent Vivier             }
736b6aeee02SLaurent Vivier             break;
737b6aeee02SLaurent Vivier         }
738bef8e8feSLaszlo Ersek         return 0;
73942281ac9SMark McLoughlin     }
74042281ac9SMark McLoughlin 
7417480874aSMarkus Armbruster     if (sock->listen) {
7420522a959SMao Zhongyi         if (net_socket_listen_init(peer, "socket", name, sock->listen, errp)
7430522a959SMao Zhongyi             < 0) {
74442281ac9SMark McLoughlin             return -1;
74542281ac9SMark McLoughlin         }
746bef8e8feSLaszlo Ersek         return 0;
74742281ac9SMark McLoughlin     }
74842281ac9SMark McLoughlin 
7497480874aSMarkus Armbruster     if (sock->connect) {
7500522a959SMao Zhongyi         if (net_socket_connect_init(peer, "socket", name, sock->connect, errp)
7510522a959SMao Zhongyi             < 0) {
75242281ac9SMark McLoughlin             return -1;
75342281ac9SMark McLoughlin         }
754bef8e8feSLaszlo Ersek         return 0;
75542281ac9SMark McLoughlin     }
75642281ac9SMark McLoughlin 
7577480874aSMarkus Armbruster     if (sock->mcast) {
758bef8e8feSLaszlo Ersek         /* if sock->localaddr is missing, it has been initialized to "all bits
759bef8e8feSLaszlo Ersek          * zero" */
760d33d93b2SStefan Hajnoczi         if (net_socket_mcast_init(peer, "socket", name, sock->mcast,
7610522a959SMao Zhongyi                                   sock->localaddr, errp) < 0) {
76242281ac9SMark McLoughlin             return -1;
76342281ac9SMark McLoughlin         }
764bef8e8feSLaszlo Ersek         return 0;
76542281ac9SMark McLoughlin     }
76642281ac9SMark McLoughlin 
7677480874aSMarkus Armbruster     assert(sock->udp);
7687480874aSMarkus Armbruster     if (!sock->localaddr) {
7690522a959SMao Zhongyi         error_setg(errp, "localaddr= is mandatory with udp=");
7700e0e7facSBenjamin         return -1;
7710e0e7facSBenjamin     }
7720522a959SMao Zhongyi     if (net_socket_udp_init(peer, "socket", name, sock->udp, sock->localaddr,
7730522a959SMao Zhongyi                             errp) < 0) {
7740e0e7facSBenjamin         return -1;
7750e0e7facSBenjamin     }
77642281ac9SMark McLoughlin     return 0;
77742281ac9SMark McLoughlin }
778