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) {
709*b6aeee02SLaurent 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 }
715*b6aeee02SLaurent Vivier so_type = net_socket_fd_check(fd, errp);
716*b6aeee02SLaurent Vivier if (so_type < 0) {
717*b6aeee02SLaurent Vivier return -1;
718*b6aeee02SLaurent 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 }
725*b6aeee02SLaurent Vivier switch (so_type) {
726*b6aeee02SLaurent Vivier case SOCK_DGRAM:
727*b6aeee02SLaurent Vivier if (!net_socket_fd_init_dgram(peer, "socket", name, fd, 1,
728*b6aeee02SLaurent Vivier sock->mcast, errp)) {
72942281ac9SMark McLoughlin return -1;
73042281ac9SMark McLoughlin }
731*b6aeee02SLaurent Vivier break;
732*b6aeee02SLaurent Vivier case SOCK_STREAM:
733*b6aeee02SLaurent Vivier if (!net_socket_fd_init_stream(peer, "socket", name, fd, 1)) {
734*b6aeee02SLaurent Vivier return -1;
735*b6aeee02SLaurent Vivier }
736*b6aeee02SLaurent Vivier break;
737*b6aeee02SLaurent 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