xref: /qemu/net/socket.c (revision cebea510)
142281ac9SMark McLoughlin /*
242281ac9SMark McLoughlin  * QEMU System Emulator
342281ac9SMark McLoughlin  *
442281ac9SMark McLoughlin  * Copyright (c) 2003-2008 Fabrice Bellard
542281ac9SMark McLoughlin  *
642281ac9SMark McLoughlin  * Permission is hereby granted, free of charge, to any person obtaining a copy
742281ac9SMark McLoughlin  * of this software and associated documentation files (the "Software"), to deal
842281ac9SMark McLoughlin  * in the Software without restriction, including without limitation the rights
942281ac9SMark McLoughlin  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1042281ac9SMark McLoughlin  * copies of the Software, and to permit persons to whom the Software is
1142281ac9SMark McLoughlin  * furnished to do so, subject to the following conditions:
1242281ac9SMark McLoughlin  *
1342281ac9SMark McLoughlin  * The above copyright notice and this permission notice shall be included in
1442281ac9SMark McLoughlin  * all copies or substantial portions of the Software.
1542281ac9SMark McLoughlin  *
1642281ac9SMark McLoughlin  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1742281ac9SMark McLoughlin  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1842281ac9SMark McLoughlin  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1942281ac9SMark McLoughlin  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2042281ac9SMark McLoughlin  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2142281ac9SMark McLoughlin  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2242281ac9SMark McLoughlin  * THE SOFTWARE.
2342281ac9SMark McLoughlin  */
242744d920SPeter Maydell #include "qemu/osdep.h"
2542281ac9SMark McLoughlin 
261422e32dSPaolo Bonzini #include "net/net.h"
27a245fc18SPaolo Bonzini #include "clients.h"
2883c9089eSPaolo Bonzini #include "monitor/monitor.h"
29da34e65cSMarkus Armbruster #include "qapi/error.h"
3042281ac9SMark McLoughlin #include "qemu-common.h"
311de7afc9SPaolo Bonzini #include "qemu/error-report.h"
321de7afc9SPaolo Bonzini #include "qemu/option.h"
331de7afc9SPaolo Bonzini #include "qemu/sockets.h"
341de7afc9SPaolo Bonzini #include "qemu/iov.h"
356a1751b7SAlex Bligh #include "qemu/main-loop.h"
3642281ac9SMark McLoughlin 
3742281ac9SMark McLoughlin typedef struct NetSocketState {
384e68f7a0SStefan Hajnoczi     NetClientState nc;
39011de2b5SZhi Yong Wu     int listen_fd;
4042281ac9SMark McLoughlin     int fd;
4116a3df40SZhang Chen     SocketReadState rs;
4245a7f54aSStefan Hajnoczi     unsigned int send_index;      /* number of bytes sent (only SOCK_STREAM) */
4342281ac9SMark McLoughlin     struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */
44863f678fSStefan Hajnoczi     IOHandler *send_fn;           /* differs between SOCK_STREAM/SOCK_DGRAM */
45863f678fSStefan Hajnoczi     bool read_poll;               /* waiting to receive data? */
46863f678fSStefan Hajnoczi     bool write_poll;              /* waiting to transmit data? */
4742281ac9SMark McLoughlin } NetSocketState;
4842281ac9SMark McLoughlin 
49011de2b5SZhi Yong Wu static void net_socket_accept(void *opaque);
50863f678fSStefan Hajnoczi static void net_socket_writable(void *opaque);
51863f678fSStefan Hajnoczi 
52863f678fSStefan Hajnoczi static void net_socket_update_fd_handler(NetSocketState *s)
53863f678fSStefan Hajnoczi {
5482e1cc4bSFam Zheng     qemu_set_fd_handler(s->fd,
55863f678fSStefan Hajnoczi                         s->read_poll ? s->send_fn : NULL,
56863f678fSStefan Hajnoczi                         s->write_poll ? net_socket_writable : NULL,
57863f678fSStefan Hajnoczi                         s);
58863f678fSStefan Hajnoczi }
59863f678fSStefan Hajnoczi 
60863f678fSStefan Hajnoczi static void net_socket_read_poll(NetSocketState *s, bool enable)
61863f678fSStefan Hajnoczi {
62863f678fSStefan Hajnoczi     s->read_poll = enable;
63863f678fSStefan Hajnoczi     net_socket_update_fd_handler(s);
64863f678fSStefan Hajnoczi }
65863f678fSStefan Hajnoczi 
66863f678fSStefan Hajnoczi static void net_socket_write_poll(NetSocketState *s, bool enable)
67863f678fSStefan Hajnoczi {
68863f678fSStefan Hajnoczi     s->write_poll = enable;
69863f678fSStefan Hajnoczi     net_socket_update_fd_handler(s);
70863f678fSStefan Hajnoczi }
71863f678fSStefan Hajnoczi 
72863f678fSStefan Hajnoczi static void net_socket_writable(void *opaque)
73863f678fSStefan Hajnoczi {
74863f678fSStefan Hajnoczi     NetSocketState *s = opaque;
75863f678fSStefan Hajnoczi 
76863f678fSStefan Hajnoczi     net_socket_write_poll(s, false);
77863f678fSStefan Hajnoczi 
78863f678fSStefan Hajnoczi     qemu_flush_queued_packets(&s->nc);
79863f678fSStefan Hajnoczi }
8042281ac9SMark McLoughlin 
814e68f7a0SStefan Hajnoczi static ssize_t net_socket_receive(NetClientState *nc, const uint8_t *buf, size_t size)
8242281ac9SMark McLoughlin {
83564f63e3SMark McLoughlin     NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
8445a7f54aSStefan Hajnoczi     uint32_t len = htonl(size);
8545a7f54aSStefan Hajnoczi     struct iovec iov[] = {
8645a7f54aSStefan Hajnoczi         {
8745a7f54aSStefan Hajnoczi             .iov_base = &len,
8845a7f54aSStefan Hajnoczi             .iov_len  = sizeof(len),
8945a7f54aSStefan Hajnoczi         }, {
9045a7f54aSStefan Hajnoczi             .iov_base = (void *)buf,
9145a7f54aSStefan Hajnoczi             .iov_len  = size,
9245a7f54aSStefan Hajnoczi         },
9345a7f54aSStefan Hajnoczi     };
9445a7f54aSStefan Hajnoczi     size_t remaining;
9545a7f54aSStefan Hajnoczi     ssize_t ret;
9642281ac9SMark McLoughlin 
9745a7f54aSStefan Hajnoczi     remaining = iov_size(iov, 2) - s->send_index;
9845a7f54aSStefan Hajnoczi     ret = iov_send(s->fd, iov, 2, s->send_index, remaining);
9945a7f54aSStefan Hajnoczi 
10045a7f54aSStefan Hajnoczi     if (ret == -1 && errno == EAGAIN) {
10145a7f54aSStefan Hajnoczi         ret = 0; /* handled further down */
10245a7f54aSStefan Hajnoczi     }
10345a7f54aSStefan Hajnoczi     if (ret == -1) {
10445a7f54aSStefan Hajnoczi         s->send_index = 0;
10545a7f54aSStefan Hajnoczi         return -errno;
10645a7f54aSStefan Hajnoczi     }
10745a7f54aSStefan Hajnoczi     if (ret < (ssize_t)remaining) {
10845a7f54aSStefan Hajnoczi         s->send_index += ret;
10945a7f54aSStefan Hajnoczi         net_socket_write_poll(s, true);
11045a7f54aSStefan Hajnoczi         return 0;
11145a7f54aSStefan Hajnoczi     }
11245a7f54aSStefan Hajnoczi     s->send_index = 0;
11345a7f54aSStefan Hajnoczi     return size;
11442281ac9SMark McLoughlin }
11542281ac9SMark McLoughlin 
1164e68f7a0SStefan Hajnoczi static ssize_t net_socket_receive_dgram(NetClientState *nc, const uint8_t *buf, size_t size)
11742281ac9SMark McLoughlin {
118564f63e3SMark McLoughlin     NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
119213fd508SStefan Hajnoczi     ssize_t ret;
12042281ac9SMark McLoughlin 
121213fd508SStefan Hajnoczi     do {
12273062dfeSStefan Weil         ret = qemu_sendto(s->fd, buf, size, 0,
123213fd508SStefan Hajnoczi                           (struct sockaddr *)&s->dgram_dst,
124213fd508SStefan Hajnoczi                           sizeof(s->dgram_dst));
125213fd508SStefan Hajnoczi     } while (ret == -1 && errno == EINTR);
126213fd508SStefan Hajnoczi 
127213fd508SStefan Hajnoczi     if (ret == -1 && errno == EAGAIN) {
128213fd508SStefan Hajnoczi         net_socket_write_poll(s, true);
129213fd508SStefan Hajnoczi         return 0;
130213fd508SStefan Hajnoczi     }
131213fd508SStefan Hajnoczi     return ret;
13242281ac9SMark McLoughlin }
13342281ac9SMark McLoughlin 
1346e99c631SFam Zheng static void net_socket_send_completed(NetClientState *nc, ssize_t len)
1356e99c631SFam Zheng {
1366e99c631SFam Zheng     NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
1376e99c631SFam Zheng 
1386e99c631SFam Zheng     if (!s->read_poll) {
1396e99c631SFam Zheng         net_socket_read_poll(s, true);
1406e99c631SFam Zheng     }
1416e99c631SFam Zheng }
1426e99c631SFam Zheng 
14316a3df40SZhang Chen static void net_socket_rs_finalize(SocketReadState *rs)
14416a3df40SZhang Chen {
14516a3df40SZhang Chen     NetSocketState *s = container_of(rs, NetSocketState, rs);
14616a3df40SZhang Chen 
14716a3df40SZhang Chen     if (qemu_send_packet_async(&s->nc, rs->buf,
14816a3df40SZhang Chen                                rs->packet_len,
14916a3df40SZhang Chen                                net_socket_send_completed) == 0) {
15016a3df40SZhang Chen         net_socket_read_poll(s, false);
15116a3df40SZhang Chen     }
15216a3df40SZhang Chen }
15316a3df40SZhang Chen 
15442281ac9SMark McLoughlin static void net_socket_send(void *opaque)
15542281ac9SMark McLoughlin {
15642281ac9SMark McLoughlin     NetSocketState *s = opaque;
157b16a44e1SDaniel P. Berrange     int size;
15816a3df40SZhang Chen     int ret;
159d32fcad3SScott Feldman     uint8_t buf1[NET_BUFSIZE];
16042281ac9SMark McLoughlin     const uint8_t *buf;
16142281ac9SMark McLoughlin 
16200aa0040SBlue Swirl     size = qemu_recv(s->fd, buf1, sizeof(buf1), 0);
16342281ac9SMark McLoughlin     if (size < 0) {
164b16a44e1SDaniel P. Berrange         if (errno != EWOULDBLOCK)
16542281ac9SMark McLoughlin             goto eoc;
16642281ac9SMark McLoughlin     } else if (size == 0) {
16742281ac9SMark McLoughlin         /* end of connection */
16842281ac9SMark McLoughlin     eoc:
169863f678fSStefan Hajnoczi         net_socket_read_poll(s, false);
170863f678fSStefan Hajnoczi         net_socket_write_poll(s, false);
171011de2b5SZhi Yong Wu         if (s->listen_fd != -1) {
172011de2b5SZhi Yong Wu             qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s);
173011de2b5SZhi Yong Wu         }
17442281ac9SMark McLoughlin         closesocket(s->fd);
175011de2b5SZhi Yong Wu 
176011de2b5SZhi Yong Wu         s->fd = -1;
17716a3df40SZhang Chen         net_socket_rs_init(&s->rs, net_socket_rs_finalize);
178011de2b5SZhi Yong Wu         s->nc.link_down = true;
179011de2b5SZhi Yong Wu         memset(s->nc.info_str, 0, sizeof(s->nc.info_str));
180011de2b5SZhi Yong Wu 
18142281ac9SMark McLoughlin         return;
18242281ac9SMark McLoughlin     }
18342281ac9SMark McLoughlin     buf = buf1;
18442281ac9SMark McLoughlin 
18516a3df40SZhang Chen     ret = net_fill_rstate(&s->rs, buf, size);
18616a3df40SZhang Chen 
18716a3df40SZhang Chen     if (ret == -1) {
18816a3df40SZhang Chen         goto eoc;
18942281ac9SMark McLoughlin     }
19042281ac9SMark McLoughlin }
19142281ac9SMark McLoughlin 
19242281ac9SMark McLoughlin static void net_socket_send_dgram(void *opaque)
19342281ac9SMark McLoughlin {
19442281ac9SMark McLoughlin     NetSocketState *s = opaque;
19542281ac9SMark McLoughlin     int size;
19642281ac9SMark McLoughlin 
19716a3df40SZhang Chen     size = qemu_recv(s->fd, s->rs.buf, sizeof(s->rs.buf), 0);
19842281ac9SMark McLoughlin     if (size < 0)
19942281ac9SMark McLoughlin         return;
20042281ac9SMark McLoughlin     if (size == 0) {
20142281ac9SMark McLoughlin         /* end of connection */
202863f678fSStefan Hajnoczi         net_socket_read_poll(s, false);
203863f678fSStefan Hajnoczi         net_socket_write_poll(s, false);
20442281ac9SMark McLoughlin         return;
20542281ac9SMark McLoughlin     }
20616a3df40SZhang Chen     if (qemu_send_packet_async(&s->nc, s->rs.buf, size,
2076e99c631SFam Zheng                                net_socket_send_completed) == 0) {
2086e99c631SFam Zheng         net_socket_read_poll(s, false);
2096e99c631SFam Zheng     }
21042281ac9SMark McLoughlin }
21142281ac9SMark McLoughlin 
2123a75e74cSMike Ryan static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr *localaddr)
21342281ac9SMark McLoughlin {
21442281ac9SMark McLoughlin     struct ip_mreq imr;
21542281ac9SMark McLoughlin     int fd;
21642281ac9SMark McLoughlin     int val, ret;
21723ddf2bbSBrad #ifdef __OpenBSD__
21823ddf2bbSBrad     unsigned char loop;
21923ddf2bbSBrad #else
22023ddf2bbSBrad     int loop;
22123ddf2bbSBrad #endif
22223ddf2bbSBrad 
22342281ac9SMark McLoughlin     if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) {
224842480d4SStefan Hajnoczi         fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) "
225842480d4SStefan Hajnoczi                 "does not contain a multicast address\n",
22642281ac9SMark McLoughlin                 inet_ntoa(mcastaddr->sin_addr),
22742281ac9SMark McLoughlin                 (int)ntohl(mcastaddr->sin_addr.s_addr));
22842281ac9SMark McLoughlin         return -1;
22942281ac9SMark McLoughlin 
23042281ac9SMark McLoughlin     }
23140ff6d7eSKevin Wolf     fd = qemu_socket(PF_INET, SOCK_DGRAM, 0);
23242281ac9SMark McLoughlin     if (fd < 0) {
23342281ac9SMark McLoughlin         perror("socket(PF_INET, SOCK_DGRAM)");
23442281ac9SMark McLoughlin         return -1;
23542281ac9SMark McLoughlin     }
23642281ac9SMark McLoughlin 
237bcbe92fbSSebastian Ottlik     /* Allow multiple sockets to bind the same multicast ip and port by setting
238bcbe92fbSSebastian Ottlik      * SO_REUSEADDR. This is the only situation where SO_REUSEADDR should be set
239bcbe92fbSSebastian Ottlik      * on windows. Use socket_set_fast_reuse otherwise as it sets SO_REUSEADDR
240bcbe92fbSSebastian Ottlik      * only on posix systems.
241bcbe92fbSSebastian Ottlik      */
24242281ac9SMark McLoughlin     val = 1;
2439957fc7fSStefan Weil     ret = qemu_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
24442281ac9SMark McLoughlin     if (ret < 0) {
24542281ac9SMark McLoughlin         perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
24642281ac9SMark McLoughlin         goto fail;
24742281ac9SMark McLoughlin     }
24842281ac9SMark McLoughlin 
24942281ac9SMark McLoughlin     ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr));
25042281ac9SMark McLoughlin     if (ret < 0) {
25142281ac9SMark McLoughlin         perror("bind");
25242281ac9SMark McLoughlin         goto fail;
25342281ac9SMark McLoughlin     }
25442281ac9SMark McLoughlin 
25542281ac9SMark McLoughlin     /* Add host to multicast group */
25642281ac9SMark McLoughlin     imr.imr_multiaddr = mcastaddr->sin_addr;
2573a75e74cSMike Ryan     if (localaddr) {
2583a75e74cSMike Ryan         imr.imr_interface = *localaddr;
2593a75e74cSMike Ryan     } else {
26042281ac9SMark McLoughlin         imr.imr_interface.s_addr = htonl(INADDR_ANY);
2613a75e74cSMike Ryan     }
26242281ac9SMark McLoughlin 
2639957fc7fSStefan Weil     ret = qemu_setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
2649957fc7fSStefan Weil                           &imr, sizeof(struct ip_mreq));
26542281ac9SMark McLoughlin     if (ret < 0) {
26642281ac9SMark McLoughlin         perror("setsockopt(IP_ADD_MEMBERSHIP)");
26742281ac9SMark McLoughlin         goto fail;
26842281ac9SMark McLoughlin     }
26942281ac9SMark McLoughlin 
27042281ac9SMark McLoughlin     /* Force mcast msgs to loopback (eg. several QEMUs in same host */
27123ddf2bbSBrad     loop = 1;
2729957fc7fSStefan Weil     ret = qemu_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
2739957fc7fSStefan Weil                           &loop, sizeof(loop));
27442281ac9SMark McLoughlin     if (ret < 0) {
27542281ac9SMark McLoughlin         perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
27642281ac9SMark McLoughlin         goto fail;
27742281ac9SMark McLoughlin     }
27842281ac9SMark McLoughlin 
2793a75e74cSMike Ryan     /* If a bind address is given, only send packets from that address */
2803a75e74cSMike Ryan     if (localaddr != NULL) {
2819957fc7fSStefan Weil         ret = qemu_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
2829957fc7fSStefan Weil                               localaddr, sizeof(*localaddr));
2833a75e74cSMike Ryan         if (ret < 0) {
2843a75e74cSMike Ryan             perror("setsockopt(IP_MULTICAST_IF)");
2853a75e74cSMike Ryan             goto fail;
2863a75e74cSMike Ryan         }
2873a75e74cSMike Ryan     }
2883a75e74cSMike Ryan 
289f9e8caccSStefan Hajnoczi     qemu_set_nonblock(fd);
29042281ac9SMark McLoughlin     return fd;
29142281ac9SMark McLoughlin fail:
29242281ac9SMark McLoughlin     if (fd >= 0)
29342281ac9SMark McLoughlin         closesocket(fd);
29442281ac9SMark McLoughlin     return -1;
29542281ac9SMark McLoughlin }
29642281ac9SMark McLoughlin 
2974e68f7a0SStefan Hajnoczi static void net_socket_cleanup(NetClientState *nc)
29842281ac9SMark McLoughlin {
299564f63e3SMark McLoughlin     NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
300011de2b5SZhi Yong Wu     if (s->fd != -1) {
301863f678fSStefan Hajnoczi         net_socket_read_poll(s, false);
302863f678fSStefan Hajnoczi         net_socket_write_poll(s, false);
30342281ac9SMark McLoughlin         close(s->fd);
304011de2b5SZhi Yong Wu         s->fd = -1;
305011de2b5SZhi Yong Wu     }
306011de2b5SZhi Yong Wu     if (s->listen_fd != -1) {
307011de2b5SZhi Yong Wu         qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
308011de2b5SZhi Yong Wu         closesocket(s->listen_fd);
309011de2b5SZhi Yong Wu         s->listen_fd = -1;
310011de2b5SZhi Yong Wu     }
31142281ac9SMark McLoughlin }
31242281ac9SMark McLoughlin 
313564f63e3SMark McLoughlin static NetClientInfo net_dgram_socket_info = {
3142be64a68SLaszlo Ersek     .type = NET_CLIENT_OPTIONS_KIND_SOCKET,
315564f63e3SMark McLoughlin     .size = sizeof(NetSocketState),
316564f63e3SMark McLoughlin     .receive = net_socket_receive_dgram,
317564f63e3SMark McLoughlin     .cleanup = net_socket_cleanup,
318564f63e3SMark McLoughlin };
319564f63e3SMark McLoughlin 
3204e68f7a0SStefan Hajnoczi static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer,
32142281ac9SMark McLoughlin                                                 const char *model,
32242281ac9SMark McLoughlin                                                 const char *name,
32342281ac9SMark McLoughlin                                                 int fd, int is_connected)
32442281ac9SMark McLoughlin {
32542281ac9SMark McLoughlin     struct sockaddr_in saddr;
32642281ac9SMark McLoughlin     int newfd;
327ed6273e2Szhanghailiang     socklen_t saddr_len = sizeof(saddr);
3284e68f7a0SStefan Hajnoczi     NetClientState *nc;
32942281ac9SMark McLoughlin     NetSocketState *s;
33042281ac9SMark McLoughlin 
33142281ac9SMark McLoughlin     /* fd passed: multicast: "learn" dgram_dst address from bound address and save it
33242281ac9SMark McLoughlin      * Because this may be "shared" socket from a "master" process, datagrams would be recv()
33342281ac9SMark McLoughlin      * by ONLY ONE process: we must "clone" this dgram socket --jjo
33442281ac9SMark McLoughlin      */
33542281ac9SMark McLoughlin 
33642281ac9SMark McLoughlin     if (is_connected) {
33742281ac9SMark McLoughlin         if (getsockname(fd, (struct sockaddr *) &saddr, &saddr_len) == 0) {
33842281ac9SMark McLoughlin             /* must be bound */
33942281ac9SMark McLoughlin             if (saddr.sin_addr.s_addr == 0) {
340842480d4SStefan Hajnoczi                 fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, "
341842480d4SStefan Hajnoczi                         "cannot setup multicast dst addr\n", fd);
342e5d1fca0SStefan Hajnoczi                 goto err;
34342281ac9SMark McLoughlin             }
34442281ac9SMark McLoughlin             /* clone dgram socket */
3453a75e74cSMike Ryan             newfd = net_socket_mcast_create(&saddr, NULL);
34642281ac9SMark McLoughlin             if (newfd < 0) {
34742281ac9SMark McLoughlin                 /* error already reported by net_socket_mcast_create() */
348e5d1fca0SStefan Hajnoczi                 goto err;
34942281ac9SMark McLoughlin             }
35042281ac9SMark McLoughlin             /* clone newfd to fd, close newfd */
35142281ac9SMark McLoughlin             dup2(newfd, fd);
35242281ac9SMark McLoughlin             close(newfd);
35342281ac9SMark McLoughlin 
35442281ac9SMark McLoughlin         } else {
355842480d4SStefan Hajnoczi             fprintf(stderr,
356842480d4SStefan Hajnoczi                     "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n",
35742281ac9SMark McLoughlin                     fd, strerror(errno));
358e5d1fca0SStefan Hajnoczi             goto err;
35942281ac9SMark McLoughlin         }
36042281ac9SMark McLoughlin     }
36142281ac9SMark McLoughlin 
362ab5f3f84SStefan Hajnoczi     nc = qemu_new_net_client(&net_dgram_socket_info, peer, model, name);
363564f63e3SMark McLoughlin 
364564f63e3SMark McLoughlin     s = DO_UPCAST(NetSocketState, nc, nc);
365564f63e3SMark McLoughlin 
36642281ac9SMark McLoughlin     s->fd = fd;
367011de2b5SZhi Yong Wu     s->listen_fd = -1;
368863f678fSStefan Hajnoczi     s->send_fn = net_socket_send_dgram;
36916a3df40SZhang Chen     net_socket_rs_init(&s->rs, net_socket_rs_finalize);
370863f678fSStefan Hajnoczi     net_socket_read_poll(s, true);
37142281ac9SMark McLoughlin 
37242281ac9SMark McLoughlin     /* mcast: save bound address as dst */
373e34cde35SZhi Yong Wu     if (is_connected) {
374e34cde35SZhi Yong Wu         s->dgram_dst = saddr;
3758db804acSGonglei         snprintf(nc->info_str, sizeof(nc->info_str),
3768db804acSGonglei                  "socket: fd=%d (cloned mcast=%s:%d)",
3778db804acSGonglei                  fd, inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
3788db804acSGonglei     } else {
3798db804acSGonglei         snprintf(nc->info_str, sizeof(nc->info_str),
3808db804acSGonglei                  "socket: fd=%d", fd);
381e34cde35SZhi Yong Wu     }
38242281ac9SMark McLoughlin 
38342281ac9SMark McLoughlin     return s;
384e5d1fca0SStefan Hajnoczi 
385e5d1fca0SStefan Hajnoczi err:
386e5d1fca0SStefan Hajnoczi     closesocket(fd);
387e5d1fca0SStefan Hajnoczi     return NULL;
38842281ac9SMark McLoughlin }
38942281ac9SMark McLoughlin 
39042281ac9SMark McLoughlin static void net_socket_connect(void *opaque)
39142281ac9SMark McLoughlin {
39242281ac9SMark McLoughlin     NetSocketState *s = opaque;
393863f678fSStefan Hajnoczi     s->send_fn = net_socket_send;
394863f678fSStefan Hajnoczi     net_socket_read_poll(s, true);
39542281ac9SMark McLoughlin }
39642281ac9SMark McLoughlin 
397564f63e3SMark McLoughlin static NetClientInfo net_socket_info = {
3982be64a68SLaszlo Ersek     .type = NET_CLIENT_OPTIONS_KIND_SOCKET,
399564f63e3SMark McLoughlin     .size = sizeof(NetSocketState),
400564f63e3SMark McLoughlin     .receive = net_socket_receive,
401564f63e3SMark McLoughlin     .cleanup = net_socket_cleanup,
402564f63e3SMark McLoughlin };
403564f63e3SMark McLoughlin 
4044e68f7a0SStefan Hajnoczi static NetSocketState *net_socket_fd_init_stream(NetClientState *peer,
40542281ac9SMark McLoughlin                                                  const char *model,
40642281ac9SMark McLoughlin                                                  const char *name,
40742281ac9SMark McLoughlin                                                  int fd, int is_connected)
40842281ac9SMark McLoughlin {
4094e68f7a0SStefan Hajnoczi     NetClientState *nc;
41042281ac9SMark McLoughlin     NetSocketState *s;
411564f63e3SMark McLoughlin 
412ab5f3f84SStefan Hajnoczi     nc = qemu_new_net_client(&net_socket_info, peer, model, name);
413564f63e3SMark McLoughlin 
414564f63e3SMark McLoughlin     snprintf(nc->info_str, sizeof(nc->info_str), "socket: fd=%d", fd);
415564f63e3SMark McLoughlin 
416564f63e3SMark McLoughlin     s = DO_UPCAST(NetSocketState, nc, nc);
417564f63e3SMark McLoughlin 
41842281ac9SMark McLoughlin     s->fd = fd;
419011de2b5SZhi Yong Wu     s->listen_fd = -1;
42016a3df40SZhang Chen     net_socket_rs_init(&s->rs, net_socket_rs_finalize);
421564f63e3SMark McLoughlin 
42220048d0aSStefan Hajnoczi     /* Disable Nagle algorithm on TCP sockets to reduce latency */
42320048d0aSStefan Hajnoczi     socket_set_nodelay(fd);
42420048d0aSStefan Hajnoczi 
42542281ac9SMark McLoughlin     if (is_connected) {
42642281ac9SMark McLoughlin         net_socket_connect(s);
42742281ac9SMark McLoughlin     } else {
42842281ac9SMark McLoughlin         qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s);
42942281ac9SMark McLoughlin     }
43042281ac9SMark McLoughlin     return s;
43142281ac9SMark McLoughlin }
43242281ac9SMark McLoughlin 
4334e68f7a0SStefan Hajnoczi static NetSocketState *net_socket_fd_init(NetClientState *peer,
43442281ac9SMark McLoughlin                                           const char *model, const char *name,
43542281ac9SMark McLoughlin                                           int fd, int is_connected)
43642281ac9SMark McLoughlin {
43742281ac9SMark McLoughlin     int so_type = -1, optlen=sizeof(so_type);
43842281ac9SMark McLoughlin 
43942281ac9SMark McLoughlin     if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type,
44042281ac9SMark McLoughlin         (socklen_t *)&optlen)< 0) {
441842480d4SStefan Hajnoczi         fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n",
442842480d4SStefan Hajnoczi                 fd);
443e5d1fca0SStefan Hajnoczi         closesocket(fd);
44442281ac9SMark McLoughlin         return NULL;
44542281ac9SMark McLoughlin     }
44642281ac9SMark McLoughlin     switch(so_type) {
44742281ac9SMark McLoughlin     case SOCK_DGRAM:
448d33d93b2SStefan Hajnoczi         return net_socket_fd_init_dgram(peer, model, name, fd, is_connected);
44942281ac9SMark McLoughlin     case SOCK_STREAM:
450d33d93b2SStefan Hajnoczi         return net_socket_fd_init_stream(peer, model, name, fd, is_connected);
45142281ac9SMark McLoughlin     default:
45242281ac9SMark McLoughlin         /* who knows ... this could be a eg. a pty, do warn and continue as stream */
45342281ac9SMark McLoughlin         fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd);
454d33d93b2SStefan Hajnoczi         return net_socket_fd_init_stream(peer, model, name, fd, is_connected);
45542281ac9SMark McLoughlin     }
45642281ac9SMark McLoughlin     return NULL;
45742281ac9SMark McLoughlin }
45842281ac9SMark McLoughlin 
45942281ac9SMark McLoughlin static void net_socket_accept(void *opaque)
46042281ac9SMark McLoughlin {
461011de2b5SZhi Yong Wu     NetSocketState *s = opaque;
46242281ac9SMark McLoughlin     struct sockaddr_in saddr;
46342281ac9SMark McLoughlin     socklen_t len;
46442281ac9SMark McLoughlin     int fd;
46542281ac9SMark McLoughlin 
46642281ac9SMark McLoughlin     for(;;) {
46742281ac9SMark McLoughlin         len = sizeof(saddr);
468011de2b5SZhi Yong Wu         fd = qemu_accept(s->listen_fd, (struct sockaddr *)&saddr, &len);
46942281ac9SMark McLoughlin         if (fd < 0 && errno != EINTR) {
47042281ac9SMark McLoughlin             return;
47142281ac9SMark McLoughlin         } else if (fd >= 0) {
472011de2b5SZhi Yong Wu             qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
47342281ac9SMark McLoughlin             break;
47442281ac9SMark McLoughlin         }
47542281ac9SMark McLoughlin     }
476011de2b5SZhi Yong Wu 
477011de2b5SZhi Yong Wu     s->fd = fd;
478011de2b5SZhi Yong Wu     s->nc.link_down = false;
479011de2b5SZhi Yong Wu     net_socket_connect(s);
480011de2b5SZhi Yong Wu     snprintf(s->nc.info_str, sizeof(s->nc.info_str),
48142281ac9SMark McLoughlin              "socket: connection from %s:%d",
48242281ac9SMark McLoughlin              inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
48342281ac9SMark McLoughlin }
48442281ac9SMark McLoughlin 
4854e68f7a0SStefan Hajnoczi static int net_socket_listen_init(NetClientState *peer,
48642281ac9SMark McLoughlin                                   const char *model,
48742281ac9SMark McLoughlin                                   const char *name,
48842281ac9SMark McLoughlin                                   const char *host_str)
48942281ac9SMark McLoughlin {
490011de2b5SZhi Yong Wu     NetClientState *nc;
491011de2b5SZhi Yong Wu     NetSocketState *s;
4927e844959SAshijeet Acharya     SocketAddress *saddr;
4937e844959SAshijeet Acharya     int ret;
4947e844959SAshijeet Acharya     Error *local_error = NULL;
49542281ac9SMark McLoughlin 
4967e844959SAshijeet Acharya     saddr = socket_parse(host_str, &local_error);
4977e844959SAshijeet Acharya     if (saddr == NULL) {
4987e844959SAshijeet Acharya         error_report_err(local_error);
49942281ac9SMark McLoughlin         return -1;
50042281ac9SMark McLoughlin     }
50142281ac9SMark McLoughlin 
5027e844959SAshijeet Acharya     ret = socket_listen(saddr, &local_error);
50342281ac9SMark McLoughlin     if (ret < 0) {
5047e844959SAshijeet Acharya         error_report_err(local_error);
50542281ac9SMark McLoughlin         return -1;
50642281ac9SMark McLoughlin     }
507011de2b5SZhi Yong Wu 
508011de2b5SZhi Yong Wu     nc = qemu_new_net_client(&net_socket_info, peer, model, name);
509011de2b5SZhi Yong Wu     s = DO_UPCAST(NetSocketState, nc, nc);
510011de2b5SZhi Yong Wu     s->fd = -1;
5117e844959SAshijeet Acharya     s->listen_fd = ret;
512011de2b5SZhi Yong Wu     s->nc.link_down = true;
513011de2b5SZhi Yong Wu 
514011de2b5SZhi Yong Wu     qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s);
5157e844959SAshijeet Acharya     qapi_free_SocketAddress(saddr);
51642281ac9SMark McLoughlin     return 0;
51742281ac9SMark McLoughlin }
51842281ac9SMark McLoughlin 
5194e68f7a0SStefan Hajnoczi static int net_socket_connect_init(NetClientState *peer,
52042281ac9SMark McLoughlin                                    const char *model,
52142281ac9SMark McLoughlin                                    const char *name,
52242281ac9SMark McLoughlin                                    const char *host_str)
52342281ac9SMark McLoughlin {
52442281ac9SMark McLoughlin     NetSocketState *s;
525b16a44e1SDaniel P. Berrange     int fd, connected, ret;
5267e844959SAshijeet Acharya     char *addr_str;
5277e844959SAshijeet Acharya     SocketAddress *saddr;
5287e844959SAshijeet Acharya     Error *local_error = NULL;
52942281ac9SMark McLoughlin 
5307e844959SAshijeet Acharya     saddr = socket_parse(host_str, &local_error);
5317e844959SAshijeet Acharya     if (saddr == NULL) {
5327e844959SAshijeet Acharya         error_report_err(local_error);
53342281ac9SMark McLoughlin         return -1;
5347e844959SAshijeet Acharya     }
53542281ac9SMark McLoughlin 
53640ff6d7eSKevin Wolf     fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
53742281ac9SMark McLoughlin     if (fd < 0) {
53842281ac9SMark McLoughlin         perror("socket");
53942281ac9SMark McLoughlin         return -1;
54042281ac9SMark McLoughlin     }
541f9e8caccSStefan Hajnoczi     qemu_set_nonblock(fd);
54242281ac9SMark McLoughlin     connected = 0;
54342281ac9SMark McLoughlin     for(;;) {
5447e844959SAshijeet Acharya         ret = socket_connect(saddr, &local_error, NULL, NULL);
54542281ac9SMark McLoughlin         if (ret < 0) {
546b16a44e1SDaniel P. Berrange             if (errno == EINTR || errno == EWOULDBLOCK) {
547b16a44e1SDaniel P. Berrange                 /* continue */
548b16a44e1SDaniel P. Berrange             } else if (errno == EINPROGRESS ||
549b16a44e1SDaniel P. Berrange                        errno == EALREADY ||
550b16a44e1SDaniel P. Berrange                        errno == EINVAL) {
55142281ac9SMark McLoughlin                 break;
55242281ac9SMark McLoughlin             } else {
5537e844959SAshijeet Acharya                 error_report_err(local_error);
55442281ac9SMark McLoughlin                 closesocket(fd);
55542281ac9SMark McLoughlin                 return -1;
55642281ac9SMark McLoughlin             }
55742281ac9SMark McLoughlin         } else {
55842281ac9SMark McLoughlin             connected = 1;
55942281ac9SMark McLoughlin             break;
56042281ac9SMark McLoughlin         }
56142281ac9SMark McLoughlin     }
562d33d93b2SStefan Hajnoczi     s = net_socket_fd_init(peer, model, name, fd, connected);
56342281ac9SMark McLoughlin     if (!s)
56442281ac9SMark McLoughlin         return -1;
5657e844959SAshijeet Acharya 
5667e844959SAshijeet Acharya     addr_str = socket_address_to_string(saddr, &local_error);
5677e844959SAshijeet Acharya     if (addr_str == NULL)
5687e844959SAshijeet Acharya         return -1;
5697e844959SAshijeet Acharya 
570564f63e3SMark McLoughlin     snprintf(s->nc.info_str, sizeof(s->nc.info_str),
5717e844959SAshijeet Acharya              "socket: connect to %s", addr_str);
5727e844959SAshijeet Acharya     qapi_free_SocketAddress(saddr);
5737e844959SAshijeet Acharya     g_free(addr_str);
57442281ac9SMark McLoughlin     return 0;
57542281ac9SMark McLoughlin }
57642281ac9SMark McLoughlin 
5774e68f7a0SStefan Hajnoczi static int net_socket_mcast_init(NetClientState *peer,
57842281ac9SMark McLoughlin                                  const char *model,
57942281ac9SMark McLoughlin                                  const char *name,
5803a75e74cSMike Ryan                                  const char *host_str,
5813a75e74cSMike Ryan                                  const char *localaddr_str)
58242281ac9SMark McLoughlin {
58342281ac9SMark McLoughlin     NetSocketState *s;
58442281ac9SMark McLoughlin     int fd;
58542281ac9SMark McLoughlin     struct sockaddr_in saddr;
5863a75e74cSMike Ryan     struct in_addr localaddr, *param_localaddr;
58742281ac9SMark McLoughlin 
58842281ac9SMark McLoughlin     if (parse_host_port(&saddr, host_str) < 0)
58942281ac9SMark McLoughlin         return -1;
59042281ac9SMark McLoughlin 
5913a75e74cSMike Ryan     if (localaddr_str != NULL) {
5923a75e74cSMike Ryan         if (inet_aton(localaddr_str, &localaddr) == 0)
5933a75e74cSMike Ryan             return -1;
5943a75e74cSMike Ryan         param_localaddr = &localaddr;
5953a75e74cSMike Ryan     } else {
5963a75e74cSMike Ryan         param_localaddr = NULL;
5973a75e74cSMike Ryan     }
59842281ac9SMark McLoughlin 
5993a75e74cSMike Ryan     fd = net_socket_mcast_create(&saddr, param_localaddr);
60042281ac9SMark McLoughlin     if (fd < 0)
60142281ac9SMark McLoughlin         return -1;
60242281ac9SMark McLoughlin 
603d33d93b2SStefan Hajnoczi     s = net_socket_fd_init(peer, model, name, fd, 0);
60442281ac9SMark McLoughlin     if (!s)
60542281ac9SMark McLoughlin         return -1;
60642281ac9SMark McLoughlin 
60742281ac9SMark McLoughlin     s->dgram_dst = saddr;
60842281ac9SMark McLoughlin 
609564f63e3SMark McLoughlin     snprintf(s->nc.info_str, sizeof(s->nc.info_str),
61042281ac9SMark McLoughlin              "socket: mcast=%s:%d",
61142281ac9SMark McLoughlin              inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
61242281ac9SMark McLoughlin     return 0;
61342281ac9SMark McLoughlin 
61442281ac9SMark McLoughlin }
61542281ac9SMark McLoughlin 
6164e68f7a0SStefan Hajnoczi static int net_socket_udp_init(NetClientState *peer,
6170e0e7facSBenjamin                                  const char *model,
6180e0e7facSBenjamin                                  const char *name,
6190e0e7facSBenjamin                                  const char *rhost,
6200e0e7facSBenjamin                                  const char *lhost)
6210e0e7facSBenjamin {
6220e0e7facSBenjamin     NetSocketState *s;
623bcbe92fbSSebastian Ottlik     int fd, ret;
6240e0e7facSBenjamin     struct sockaddr_in laddr, raddr;
6250e0e7facSBenjamin 
6260e0e7facSBenjamin     if (parse_host_port(&laddr, lhost) < 0) {
6270e0e7facSBenjamin         return -1;
6280e0e7facSBenjamin     }
6290e0e7facSBenjamin 
6300e0e7facSBenjamin     if (parse_host_port(&raddr, rhost) < 0) {
6310e0e7facSBenjamin         return -1;
6320e0e7facSBenjamin     }
6330e0e7facSBenjamin 
6340e0e7facSBenjamin     fd = qemu_socket(PF_INET, SOCK_DGRAM, 0);
6350e0e7facSBenjamin     if (fd < 0) {
6360e0e7facSBenjamin         perror("socket(PF_INET, SOCK_DGRAM)");
6370e0e7facSBenjamin         return -1;
6380e0e7facSBenjamin     }
639bcbe92fbSSebastian Ottlik 
640bcbe92fbSSebastian Ottlik     ret = socket_set_fast_reuse(fd);
6410e0e7facSBenjamin     if (ret < 0) {
6420e0e7facSBenjamin         closesocket(fd);
6430e0e7facSBenjamin         return -1;
6440e0e7facSBenjamin     }
6450e0e7facSBenjamin     ret = bind(fd, (struct sockaddr *)&laddr, sizeof(laddr));
6460e0e7facSBenjamin     if (ret < 0) {
6470e0e7facSBenjamin         perror("bind");
6480e0e7facSBenjamin         closesocket(fd);
6490e0e7facSBenjamin         return -1;
6500e0e7facSBenjamin     }
651fc13fa00SStefan Hajnoczi     qemu_set_nonblock(fd);
6520e0e7facSBenjamin 
653d33d93b2SStefan Hajnoczi     s = net_socket_fd_init(peer, model, name, fd, 0);
6540e0e7facSBenjamin     if (!s) {
6550e0e7facSBenjamin         return -1;
6560e0e7facSBenjamin     }
6570e0e7facSBenjamin 
6580e0e7facSBenjamin     s->dgram_dst = raddr;
6590e0e7facSBenjamin 
6600e0e7facSBenjamin     snprintf(s->nc.info_str, sizeof(s->nc.info_str),
6610e0e7facSBenjamin              "socket: udp=%s:%d",
6620e0e7facSBenjamin              inet_ntoa(raddr.sin_addr), ntohs(raddr.sin_port));
6630e0e7facSBenjamin     return 0;
6640e0e7facSBenjamin }
6650e0e7facSBenjamin 
666*cebea510SKővágó, Zoltán int net_init_socket(const Netdev *netdev, const char *name,
667a30ecde6SMarkus Armbruster                     NetClientState *peer, Error **errp)
66842281ac9SMark McLoughlin {
669a30ecde6SMarkus Armbruster     /* FIXME error_setg(errp, ...) on failure */
6701677f4c6SMarkus Armbruster     Error *err = NULL;
671bef8e8feSLaszlo Ersek     const NetdevSocketOptions *sock;
672bef8e8feSLaszlo Ersek 
673*cebea510SKővágó, Zoltán     assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_SOCKET);
674*cebea510SKővágó, Zoltán     sock = netdev->opts->u.socket.data;
675bef8e8feSLaszlo Ersek 
676bef8e8feSLaszlo Ersek     if (sock->has_fd + sock->has_listen + sock->has_connect + sock->has_mcast +
677bef8e8feSLaszlo Ersek         sock->has_udp != 1) {
678bef8e8feSLaszlo Ersek         error_report("exactly one of fd=, listen=, connect=, mcast= or udp="
679bef8e8feSLaszlo Ersek                      " is required");
680bef8e8feSLaszlo Ersek         return -1;
681bef8e8feSLaszlo Ersek     }
682bef8e8feSLaszlo Ersek 
683bef8e8feSLaszlo Ersek     if (sock->has_localaddr && !sock->has_mcast && !sock->has_udp) {
684bef8e8feSLaszlo Ersek         error_report("localaddr= is only valid with mcast= or udp=");
685bef8e8feSLaszlo Ersek         return -1;
686bef8e8feSLaszlo Ersek     }
687bef8e8feSLaszlo Ersek 
688bef8e8feSLaszlo Ersek     if (sock->has_fd) {
68942281ac9SMark McLoughlin         int fd;
69042281ac9SMark McLoughlin 
6911677f4c6SMarkus Armbruster         fd = monitor_fd_param(cur_mon, sock->fd, &err);
692fc13fa00SStefan Hajnoczi         if (fd == -1) {
6931677f4c6SMarkus Armbruster             error_report_err(err);
694fc13fa00SStefan Hajnoczi             return -1;
695fc13fa00SStefan Hajnoczi         }
696fc13fa00SStefan Hajnoczi         qemu_set_nonblock(fd);
697fc13fa00SStefan Hajnoczi         if (!net_socket_fd_init(peer, "socket", name, fd, 1)) {
69842281ac9SMark McLoughlin             return -1;
69942281ac9SMark McLoughlin         }
700bef8e8feSLaszlo Ersek         return 0;
70142281ac9SMark McLoughlin     }
70242281ac9SMark McLoughlin 
703bef8e8feSLaszlo Ersek     if (sock->has_listen) {
704d33d93b2SStefan Hajnoczi         if (net_socket_listen_init(peer, "socket", name, sock->listen) == -1) {
70542281ac9SMark McLoughlin             return -1;
70642281ac9SMark McLoughlin         }
707bef8e8feSLaszlo Ersek         return 0;
70842281ac9SMark McLoughlin     }
70942281ac9SMark McLoughlin 
710bef8e8feSLaszlo Ersek     if (sock->has_connect) {
711d33d93b2SStefan Hajnoczi         if (net_socket_connect_init(peer, "socket", name, sock->connect) ==
712bef8e8feSLaszlo Ersek             -1) {
71342281ac9SMark McLoughlin             return -1;
71442281ac9SMark McLoughlin         }
715bef8e8feSLaszlo Ersek         return 0;
71642281ac9SMark McLoughlin     }
71742281ac9SMark McLoughlin 
718bef8e8feSLaszlo Ersek     if (sock->has_mcast) {
719bef8e8feSLaszlo Ersek         /* if sock->localaddr is missing, it has been initialized to "all bits
720bef8e8feSLaszlo Ersek          * zero" */
721d33d93b2SStefan Hajnoczi         if (net_socket_mcast_init(peer, "socket", name, sock->mcast,
722bef8e8feSLaszlo Ersek             sock->localaddr) == -1) {
72342281ac9SMark McLoughlin             return -1;
72442281ac9SMark McLoughlin         }
725bef8e8feSLaszlo Ersek         return 0;
72642281ac9SMark McLoughlin     }
72742281ac9SMark McLoughlin 
728bef8e8feSLaszlo Ersek     assert(sock->has_udp);
729bef8e8feSLaszlo Ersek     if (!sock->has_localaddr) {
7300e0e7facSBenjamin         error_report("localaddr= is mandatory with udp=");
7310e0e7facSBenjamin         return -1;
7320e0e7facSBenjamin     }
733f0e3ac70SLei Li     if (net_socket_udp_init(peer, "socket", name, sock->udp, sock->localaddr) ==
734bef8e8feSLaszlo Ersek         -1) {
7350e0e7facSBenjamin         return -1;
7360e0e7facSBenjamin     }
73742281ac9SMark McLoughlin     return 0;
73842281ac9SMark McLoughlin }
739