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