15166fe0aSLaurent Vivier /*
25166fe0aSLaurent Vivier * QEMU System Emulator
35166fe0aSLaurent Vivier *
45166fe0aSLaurent Vivier * Copyright (c) 2003-2008 Fabrice Bellard
55166fe0aSLaurent Vivier * Copyright (c) 2022 Red Hat, Inc.
65166fe0aSLaurent Vivier *
75166fe0aSLaurent Vivier * Permission is hereby granted, free of charge, to any person obtaining a copy
85166fe0aSLaurent Vivier * of this software and associated documentation files (the "Software"), to deal
95166fe0aSLaurent Vivier * in the Software without restriction, including without limitation the rights
105166fe0aSLaurent Vivier * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
115166fe0aSLaurent Vivier * copies of the Software, and to permit persons to whom the Software is
125166fe0aSLaurent Vivier * furnished to do so, subject to the following conditions:
135166fe0aSLaurent Vivier *
145166fe0aSLaurent Vivier * The above copyright notice and this permission notice shall be included in
155166fe0aSLaurent Vivier * all copies or substantial portions of the Software.
165166fe0aSLaurent Vivier *
175166fe0aSLaurent Vivier * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
185166fe0aSLaurent Vivier * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
195166fe0aSLaurent Vivier * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
205166fe0aSLaurent Vivier * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
215166fe0aSLaurent Vivier * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
225166fe0aSLaurent Vivier * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
235166fe0aSLaurent Vivier * THE SOFTWARE.
245166fe0aSLaurent Vivier */
255166fe0aSLaurent Vivier
265166fe0aSLaurent Vivier #include "qemu/osdep.h"
275166fe0aSLaurent Vivier
285166fe0aSLaurent Vivier #include "net/net.h"
295166fe0aSLaurent Vivier #include "clients.h"
305166fe0aSLaurent Vivier #include "monitor/monitor.h"
315166fe0aSLaurent Vivier #include "qapi/error.h"
325166fe0aSLaurent Vivier #include "qemu/error-report.h"
335166fe0aSLaurent Vivier #include "qemu/option.h"
345166fe0aSLaurent Vivier #include "qemu/sockets.h"
355166fe0aSLaurent Vivier #include "qemu/iov.h"
365166fe0aSLaurent Vivier #include "qemu/main-loop.h"
375166fe0aSLaurent Vivier #include "qemu/cutils.h"
385166fe0aSLaurent Vivier
395166fe0aSLaurent Vivier typedef struct NetDgramState {
405166fe0aSLaurent Vivier NetClientState nc;
415166fe0aSLaurent Vivier int fd;
425166fe0aSLaurent Vivier SocketReadState rs;
435166fe0aSLaurent Vivier bool read_poll; /* waiting to receive data? */
445166fe0aSLaurent Vivier bool write_poll; /* waiting to transmit data? */
457c1f0c33SLaurent Vivier /* contains destination iff connectionless */
467c1f0c33SLaurent Vivier struct sockaddr *dest_addr;
477c1f0c33SLaurent Vivier socklen_t dest_len;
485166fe0aSLaurent Vivier } NetDgramState;
495166fe0aSLaurent Vivier
505166fe0aSLaurent Vivier static void net_dgram_send(void *opaque);
515166fe0aSLaurent Vivier static void net_dgram_writable(void *opaque);
525166fe0aSLaurent Vivier
net_dgram_update_fd_handler(NetDgramState * s)535166fe0aSLaurent Vivier static void net_dgram_update_fd_handler(NetDgramState *s)
545166fe0aSLaurent Vivier {
555166fe0aSLaurent Vivier qemu_set_fd_handler(s->fd,
565166fe0aSLaurent Vivier s->read_poll ? net_dgram_send : NULL,
575166fe0aSLaurent Vivier s->write_poll ? net_dgram_writable : NULL,
585166fe0aSLaurent Vivier s);
595166fe0aSLaurent Vivier }
605166fe0aSLaurent Vivier
net_dgram_read_poll(NetDgramState * s,bool enable)615166fe0aSLaurent Vivier static void net_dgram_read_poll(NetDgramState *s, bool enable)
625166fe0aSLaurent Vivier {
635166fe0aSLaurent Vivier s->read_poll = enable;
645166fe0aSLaurent Vivier net_dgram_update_fd_handler(s);
655166fe0aSLaurent Vivier }
665166fe0aSLaurent Vivier
net_dgram_write_poll(NetDgramState * s,bool enable)675166fe0aSLaurent Vivier static void net_dgram_write_poll(NetDgramState *s, bool enable)
685166fe0aSLaurent Vivier {
695166fe0aSLaurent Vivier s->write_poll = enable;
705166fe0aSLaurent Vivier net_dgram_update_fd_handler(s);
715166fe0aSLaurent Vivier }
725166fe0aSLaurent Vivier
net_dgram_writable(void * opaque)735166fe0aSLaurent Vivier static void net_dgram_writable(void *opaque)
745166fe0aSLaurent Vivier {
755166fe0aSLaurent Vivier NetDgramState *s = opaque;
765166fe0aSLaurent Vivier
775166fe0aSLaurent Vivier net_dgram_write_poll(s, false);
785166fe0aSLaurent Vivier
795166fe0aSLaurent Vivier qemu_flush_queued_packets(&s->nc);
805166fe0aSLaurent Vivier }
815166fe0aSLaurent Vivier
net_dgram_receive(NetClientState * nc,const uint8_t * buf,size_t size)825166fe0aSLaurent Vivier static ssize_t net_dgram_receive(NetClientState *nc,
835166fe0aSLaurent Vivier const uint8_t *buf, size_t size)
845166fe0aSLaurent Vivier {
855166fe0aSLaurent Vivier NetDgramState *s = DO_UPCAST(NetDgramState, nc, nc);
865166fe0aSLaurent Vivier ssize_t ret;
875166fe0aSLaurent Vivier
885166fe0aSLaurent Vivier do {
897c1f0c33SLaurent Vivier if (s->dest_addr) {
907c1f0c33SLaurent Vivier ret = sendto(s->fd, buf, size, 0, s->dest_addr, s->dest_len);
915166fe0aSLaurent Vivier } else {
925166fe0aSLaurent Vivier ret = send(s->fd, buf, size, 0);
935166fe0aSLaurent Vivier }
945166fe0aSLaurent Vivier } while (ret == -1 && errno == EINTR);
955166fe0aSLaurent Vivier
965166fe0aSLaurent Vivier if (ret == -1 && errno == EAGAIN) {
975166fe0aSLaurent Vivier net_dgram_write_poll(s, true);
985166fe0aSLaurent Vivier return 0;
995166fe0aSLaurent Vivier }
1005166fe0aSLaurent Vivier return ret;
1015166fe0aSLaurent Vivier }
1025166fe0aSLaurent Vivier
net_dgram_send_completed(NetClientState * nc,ssize_t len)1035166fe0aSLaurent Vivier static void net_dgram_send_completed(NetClientState *nc, ssize_t len)
1045166fe0aSLaurent Vivier {
1055166fe0aSLaurent Vivier NetDgramState *s = DO_UPCAST(NetDgramState, nc, nc);
1065166fe0aSLaurent Vivier
1075166fe0aSLaurent Vivier if (!s->read_poll) {
1085166fe0aSLaurent Vivier net_dgram_read_poll(s, true);
1095166fe0aSLaurent Vivier }
1105166fe0aSLaurent Vivier }
1115166fe0aSLaurent Vivier
net_dgram_rs_finalize(SocketReadState * rs)1125166fe0aSLaurent Vivier static void net_dgram_rs_finalize(SocketReadState *rs)
1135166fe0aSLaurent Vivier {
1145166fe0aSLaurent Vivier NetDgramState *s = container_of(rs, NetDgramState, rs);
1155166fe0aSLaurent Vivier
1165166fe0aSLaurent Vivier if (qemu_send_packet_async(&s->nc, rs->buf,
1175166fe0aSLaurent Vivier rs->packet_len,
1185166fe0aSLaurent Vivier net_dgram_send_completed) == 0) {
1195166fe0aSLaurent Vivier net_dgram_read_poll(s, false);
1205166fe0aSLaurent Vivier }
1215166fe0aSLaurent Vivier }
1225166fe0aSLaurent Vivier
net_dgram_send(void * opaque)1235166fe0aSLaurent Vivier static void net_dgram_send(void *opaque)
1245166fe0aSLaurent Vivier {
1255166fe0aSLaurent Vivier NetDgramState *s = opaque;
1265166fe0aSLaurent Vivier int size;
1275166fe0aSLaurent Vivier
1285166fe0aSLaurent Vivier size = recv(s->fd, s->rs.buf, sizeof(s->rs.buf), 0);
1295166fe0aSLaurent Vivier if (size < 0) {
1305166fe0aSLaurent Vivier return;
1315166fe0aSLaurent Vivier }
1325166fe0aSLaurent Vivier if (size == 0) {
1335166fe0aSLaurent Vivier /* end of connection */
1345166fe0aSLaurent Vivier net_dgram_read_poll(s, false);
1355166fe0aSLaurent Vivier net_dgram_write_poll(s, false);
1365166fe0aSLaurent Vivier return;
1375166fe0aSLaurent Vivier }
1385166fe0aSLaurent Vivier if (qemu_send_packet_async(&s->nc, s->rs.buf, size,
1395166fe0aSLaurent Vivier net_dgram_send_completed) == 0) {
1405166fe0aSLaurent Vivier net_dgram_read_poll(s, false);
1415166fe0aSLaurent Vivier }
1425166fe0aSLaurent Vivier }
1435166fe0aSLaurent Vivier
net_dgram_mcast_create(struct sockaddr_in * mcastaddr,struct in_addr * localaddr,Error ** errp)1445166fe0aSLaurent Vivier static int net_dgram_mcast_create(struct sockaddr_in *mcastaddr,
1455166fe0aSLaurent Vivier struct in_addr *localaddr,
1465166fe0aSLaurent Vivier Error **errp)
1475166fe0aSLaurent Vivier {
1485166fe0aSLaurent Vivier struct ip_mreq imr;
1495166fe0aSLaurent Vivier int fd;
1505166fe0aSLaurent Vivier int val, ret;
1515166fe0aSLaurent Vivier #ifdef __OpenBSD__
1525166fe0aSLaurent Vivier unsigned char loop;
1535166fe0aSLaurent Vivier #else
1545166fe0aSLaurent Vivier int loop;
1555166fe0aSLaurent Vivier #endif
1565166fe0aSLaurent Vivier
1575166fe0aSLaurent Vivier if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) {
1585166fe0aSLaurent Vivier error_setg(errp, "specified mcastaddr %s (0x%08x) "
1595166fe0aSLaurent Vivier "does not contain a multicast address",
1605166fe0aSLaurent Vivier inet_ntoa(mcastaddr->sin_addr),
1615166fe0aSLaurent Vivier (int)ntohl(mcastaddr->sin_addr.s_addr));
1625166fe0aSLaurent Vivier return -1;
1635166fe0aSLaurent Vivier }
1645166fe0aSLaurent Vivier
1655166fe0aSLaurent Vivier fd = qemu_socket(PF_INET, SOCK_DGRAM, 0);
1665166fe0aSLaurent Vivier if (fd < 0) {
1675166fe0aSLaurent Vivier error_setg_errno(errp, errno, "can't create datagram socket");
1685166fe0aSLaurent Vivier return -1;
1695166fe0aSLaurent Vivier }
1705166fe0aSLaurent Vivier
1715166fe0aSLaurent Vivier /*
1725166fe0aSLaurent Vivier * Allow multiple sockets to bind the same multicast ip and port by setting
1735166fe0aSLaurent Vivier * SO_REUSEADDR. This is the only situation where SO_REUSEADDR should be set
1745166fe0aSLaurent Vivier * on windows. Use socket_set_fast_reuse otherwise as it sets SO_REUSEADDR
1755166fe0aSLaurent Vivier * only on posix systems.
1765166fe0aSLaurent Vivier */
1775166fe0aSLaurent Vivier val = 1;
1785166fe0aSLaurent Vivier ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
1795166fe0aSLaurent Vivier if (ret < 0) {
1805166fe0aSLaurent Vivier error_setg_errno(errp, errno, "can't set socket option SO_REUSEADDR");
1815166fe0aSLaurent Vivier goto fail;
1825166fe0aSLaurent Vivier }
1835166fe0aSLaurent Vivier
1845166fe0aSLaurent Vivier ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr));
1855166fe0aSLaurent Vivier if (ret < 0) {
1865166fe0aSLaurent Vivier error_setg_errno(errp, errno, "can't bind ip=%s to socket",
1875166fe0aSLaurent Vivier inet_ntoa(mcastaddr->sin_addr));
1885166fe0aSLaurent Vivier goto fail;
1895166fe0aSLaurent Vivier }
1905166fe0aSLaurent Vivier
1915166fe0aSLaurent Vivier /* Add host to multicast group */
1925166fe0aSLaurent Vivier imr.imr_multiaddr = mcastaddr->sin_addr;
1935166fe0aSLaurent Vivier if (localaddr) {
1945166fe0aSLaurent Vivier imr.imr_interface = *localaddr;
1955166fe0aSLaurent Vivier } else {
1965166fe0aSLaurent Vivier imr.imr_interface.s_addr = htonl(INADDR_ANY);
1975166fe0aSLaurent Vivier }
1985166fe0aSLaurent Vivier
1995166fe0aSLaurent Vivier ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
2005166fe0aSLaurent Vivier &imr, sizeof(struct ip_mreq));
2015166fe0aSLaurent Vivier if (ret < 0) {
2025166fe0aSLaurent Vivier error_setg_errno(errp, errno,
2035166fe0aSLaurent Vivier "can't add socket to multicast group %s",
2045166fe0aSLaurent Vivier inet_ntoa(imr.imr_multiaddr));
2055166fe0aSLaurent Vivier goto fail;
2065166fe0aSLaurent Vivier }
2075166fe0aSLaurent Vivier
2085166fe0aSLaurent Vivier /* Force mcast msgs to loopback (eg. several QEMUs in same host */
2095166fe0aSLaurent Vivier loop = 1;
2105166fe0aSLaurent Vivier ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
2115166fe0aSLaurent Vivier &loop, sizeof(loop));
2125166fe0aSLaurent Vivier if (ret < 0) {
2135166fe0aSLaurent Vivier error_setg_errno(errp, errno,
2145166fe0aSLaurent Vivier "can't force multicast message to loopback");
2155166fe0aSLaurent Vivier goto fail;
2165166fe0aSLaurent Vivier }
2175166fe0aSLaurent Vivier
2185166fe0aSLaurent Vivier /* If a bind address is given, only send packets from that address */
2195166fe0aSLaurent Vivier if (localaddr != NULL) {
2205166fe0aSLaurent Vivier ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
2215166fe0aSLaurent Vivier localaddr, sizeof(*localaddr));
2225166fe0aSLaurent Vivier if (ret < 0) {
2235166fe0aSLaurent Vivier error_setg_errno(errp, errno,
2245166fe0aSLaurent Vivier "can't set the default network send interface");
2255166fe0aSLaurent Vivier goto fail;
2265166fe0aSLaurent Vivier }
2275166fe0aSLaurent Vivier }
2285166fe0aSLaurent Vivier
2295166fe0aSLaurent Vivier qemu_socket_set_nonblock(fd);
2305166fe0aSLaurent Vivier return fd;
2315166fe0aSLaurent Vivier fail:
2325166fe0aSLaurent Vivier if (fd >= 0) {
233*25657fc6SMarc-André Lureau close(fd);
2345166fe0aSLaurent Vivier }
2355166fe0aSLaurent Vivier return -1;
2365166fe0aSLaurent Vivier }
2375166fe0aSLaurent Vivier
net_dgram_cleanup(NetClientState * nc)2385166fe0aSLaurent Vivier static void net_dgram_cleanup(NetClientState *nc)
2395166fe0aSLaurent Vivier {
2405166fe0aSLaurent Vivier NetDgramState *s = DO_UPCAST(NetDgramState, nc, nc);
2415166fe0aSLaurent Vivier if (s->fd != -1) {
2425166fe0aSLaurent Vivier net_dgram_read_poll(s, false);
2435166fe0aSLaurent Vivier net_dgram_write_poll(s, false);
2445166fe0aSLaurent Vivier close(s->fd);
2455166fe0aSLaurent Vivier s->fd = -1;
2465166fe0aSLaurent Vivier }
2477c1f0c33SLaurent Vivier g_free(s->dest_addr);
2487c1f0c33SLaurent Vivier s->dest_addr = NULL;
2497c1f0c33SLaurent Vivier s->dest_len = 0;
2505166fe0aSLaurent Vivier }
2515166fe0aSLaurent Vivier
2525166fe0aSLaurent Vivier static NetClientInfo net_dgram_socket_info = {
2535166fe0aSLaurent Vivier .type = NET_CLIENT_DRIVER_DGRAM,
2545166fe0aSLaurent Vivier .size = sizeof(NetDgramState),
2555166fe0aSLaurent Vivier .receive = net_dgram_receive,
2565166fe0aSLaurent Vivier .cleanup = net_dgram_cleanup,
2575166fe0aSLaurent Vivier };
2585166fe0aSLaurent Vivier
net_dgram_fd_init(NetClientState * peer,const char * model,const char * name,int fd,Error ** errp)2595166fe0aSLaurent Vivier static NetDgramState *net_dgram_fd_init(NetClientState *peer,
2605166fe0aSLaurent Vivier const char *model,
2615166fe0aSLaurent Vivier const char *name,
2628ecc7f40SLaurent Vivier int fd,
2635166fe0aSLaurent Vivier Error **errp)
2645166fe0aSLaurent Vivier {
2655166fe0aSLaurent Vivier NetClientState *nc;
2665166fe0aSLaurent Vivier NetDgramState *s;
2675166fe0aSLaurent Vivier
2685166fe0aSLaurent Vivier nc = qemu_new_net_client(&net_dgram_socket_info, peer, model, name);
2695166fe0aSLaurent Vivier
2705166fe0aSLaurent Vivier s = DO_UPCAST(NetDgramState, nc, nc);
2715166fe0aSLaurent Vivier
2725166fe0aSLaurent Vivier s->fd = fd;
2735166fe0aSLaurent Vivier net_socket_rs_init(&s->rs, net_dgram_rs_finalize, false);
2745166fe0aSLaurent Vivier net_dgram_read_poll(s, true);
2755166fe0aSLaurent Vivier
2765166fe0aSLaurent Vivier return s;
2775166fe0aSLaurent Vivier }
2785166fe0aSLaurent Vivier
net_dgram_mcast_init(NetClientState * peer,const char * model,const char * name,SocketAddress * remote,SocketAddress * local,Error ** errp)2795166fe0aSLaurent Vivier static int net_dgram_mcast_init(NetClientState *peer,
2805166fe0aSLaurent Vivier const char *model,
2815166fe0aSLaurent Vivier const char *name,
2825166fe0aSLaurent Vivier SocketAddress *remote,
2835166fe0aSLaurent Vivier SocketAddress *local,
2845166fe0aSLaurent Vivier Error **errp)
2855166fe0aSLaurent Vivier {
2865166fe0aSLaurent Vivier NetDgramState *s;
2875166fe0aSLaurent Vivier int fd, ret;
2887c1f0c33SLaurent Vivier struct sockaddr_in *saddr;
2895166fe0aSLaurent Vivier
2905166fe0aSLaurent Vivier if (remote->type != SOCKET_ADDRESS_TYPE_INET) {
2915166fe0aSLaurent Vivier error_setg(errp, "multicast only support inet type");
2925166fe0aSLaurent Vivier return -1;
2935166fe0aSLaurent Vivier }
2945166fe0aSLaurent Vivier
2957c1f0c33SLaurent Vivier saddr = g_new(struct sockaddr_in, 1);
2967c1f0c33SLaurent Vivier if (convert_host_port(saddr, remote->u.inet.host, remote->u.inet.port,
2975166fe0aSLaurent Vivier errp) < 0) {
2987c1f0c33SLaurent Vivier g_free(saddr);
2995166fe0aSLaurent Vivier return -1;
3005166fe0aSLaurent Vivier }
3015166fe0aSLaurent Vivier
3025166fe0aSLaurent Vivier if (!local) {
3037c1f0c33SLaurent Vivier fd = net_dgram_mcast_create(saddr, NULL, errp);
3045166fe0aSLaurent Vivier if (fd < 0) {
3057c1f0c33SLaurent Vivier g_free(saddr);
3065166fe0aSLaurent Vivier return -1;
3075166fe0aSLaurent Vivier }
3085166fe0aSLaurent Vivier } else {
3095166fe0aSLaurent Vivier switch (local->type) {
3105166fe0aSLaurent Vivier case SOCKET_ADDRESS_TYPE_INET: {
3115166fe0aSLaurent Vivier struct in_addr localaddr;
3125166fe0aSLaurent Vivier
3135166fe0aSLaurent Vivier if (inet_aton(local->u.inet.host, &localaddr) == 0) {
3147c1f0c33SLaurent Vivier g_free(saddr);
3155166fe0aSLaurent Vivier error_setg(errp, "localaddr '%s' is not a valid IPv4 address",
3165166fe0aSLaurent Vivier local->u.inet.host);
3175166fe0aSLaurent Vivier return -1;
3185166fe0aSLaurent Vivier }
3195166fe0aSLaurent Vivier
3207c1f0c33SLaurent Vivier fd = net_dgram_mcast_create(saddr, &localaddr, errp);
3215166fe0aSLaurent Vivier if (fd < 0) {
3227c1f0c33SLaurent Vivier g_free(saddr);
3235166fe0aSLaurent Vivier return -1;
3245166fe0aSLaurent Vivier }
3255166fe0aSLaurent Vivier break;
3265166fe0aSLaurent Vivier }
3278ecc7f40SLaurent Vivier case SOCKET_ADDRESS_TYPE_FD: {
3288ecc7f40SLaurent Vivier int newfd;
3298ecc7f40SLaurent Vivier
3305166fe0aSLaurent Vivier fd = monitor_fd_param(monitor_cur(), local->u.fd.str, errp);
3315166fe0aSLaurent Vivier if (fd == -1) {
3327c1f0c33SLaurent Vivier g_free(saddr);
3335166fe0aSLaurent Vivier return -1;
3345166fe0aSLaurent Vivier }
3355166fe0aSLaurent Vivier ret = qemu_socket_try_set_nonblock(fd);
3365166fe0aSLaurent Vivier if (ret < 0) {
3377c1f0c33SLaurent Vivier g_free(saddr);
3385166fe0aSLaurent Vivier error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d",
3395166fe0aSLaurent Vivier name, fd);
3405166fe0aSLaurent Vivier return -1;
3415166fe0aSLaurent Vivier }
3428ecc7f40SLaurent Vivier
3438ecc7f40SLaurent Vivier /*
3448ecc7f40SLaurent Vivier * fd passed: multicast: "learn" dest_addr address from bound
3458ecc7f40SLaurent Vivier * address and save it. Because this may be "shared" socket from a
3468ecc7f40SLaurent Vivier * "master" process, datagrams would be recv() by ONLY ONE process:
3478ecc7f40SLaurent Vivier * we must "clone" this dgram socket --jjo
3488ecc7f40SLaurent Vivier */
3498ecc7f40SLaurent Vivier
3508ecc7f40SLaurent Vivier saddr = g_new(struct sockaddr_in, 1);
3518ecc7f40SLaurent Vivier
3528ecc7f40SLaurent Vivier if (convert_host_port(saddr, local->u.inet.host, local->u.inet.port,
3538ecc7f40SLaurent Vivier errp) < 0) {
3548ecc7f40SLaurent Vivier g_free(saddr);
355*25657fc6SMarc-André Lureau close(fd);
3568ecc7f40SLaurent Vivier return -1;
3578ecc7f40SLaurent Vivier }
3588ecc7f40SLaurent Vivier
3598ecc7f40SLaurent Vivier /* must be bound */
3608ecc7f40SLaurent Vivier if (saddr->sin_addr.s_addr == 0) {
3618ecc7f40SLaurent Vivier error_setg(errp, "can't setup multicast destination address");
3628ecc7f40SLaurent Vivier g_free(saddr);
363*25657fc6SMarc-André Lureau close(fd);
3648ecc7f40SLaurent Vivier return -1;
3658ecc7f40SLaurent Vivier }
3668ecc7f40SLaurent Vivier /* clone dgram socket */
3678ecc7f40SLaurent Vivier newfd = net_dgram_mcast_create(saddr, NULL, errp);
3688ecc7f40SLaurent Vivier if (newfd < 0) {
3698ecc7f40SLaurent Vivier g_free(saddr);
370*25657fc6SMarc-André Lureau close(fd);
3718ecc7f40SLaurent Vivier return -1;
3728ecc7f40SLaurent Vivier }
3738ecc7f40SLaurent Vivier /* clone newfd to fd, close newfd */
3748ecc7f40SLaurent Vivier dup2(newfd, fd);
3758ecc7f40SLaurent Vivier close(newfd);
3765166fe0aSLaurent Vivier break;
3778ecc7f40SLaurent Vivier }
3785166fe0aSLaurent Vivier default:
3797c1f0c33SLaurent Vivier g_free(saddr);
3805166fe0aSLaurent Vivier error_setg(errp, "only support inet or fd type for local");
3815166fe0aSLaurent Vivier return -1;
3825166fe0aSLaurent Vivier }
3835166fe0aSLaurent Vivier }
3845166fe0aSLaurent Vivier
3858ecc7f40SLaurent Vivier s = net_dgram_fd_init(peer, model, name, fd, errp);
3865166fe0aSLaurent Vivier if (!s) {
3877c1f0c33SLaurent Vivier g_free(saddr);
3885166fe0aSLaurent Vivier return -1;
3895166fe0aSLaurent Vivier }
3905166fe0aSLaurent Vivier
3917c1f0c33SLaurent Vivier g_assert(s->dest_addr == NULL);
3927c1f0c33SLaurent Vivier s->dest_addr = (struct sockaddr *)saddr;
3937c1f0c33SLaurent Vivier s->dest_len = sizeof(*saddr);
3945166fe0aSLaurent Vivier
3958ecc7f40SLaurent Vivier if (!local) {
3968ecc7f40SLaurent Vivier qemu_set_info_str(&s->nc, "mcast=%s:%d",
3978ecc7f40SLaurent Vivier inet_ntoa(saddr->sin_addr),
3987c1f0c33SLaurent Vivier ntohs(saddr->sin_port));
3998ecc7f40SLaurent Vivier } else {
4008ecc7f40SLaurent Vivier switch (local->type) {
4018ecc7f40SLaurent Vivier case SOCKET_ADDRESS_TYPE_INET:
4028ecc7f40SLaurent Vivier qemu_set_info_str(&s->nc, "mcast=%s:%d",
4038ecc7f40SLaurent Vivier inet_ntoa(saddr->sin_addr),
4048ecc7f40SLaurent Vivier ntohs(saddr->sin_port));
4058ecc7f40SLaurent Vivier break;
4068ecc7f40SLaurent Vivier case SOCKET_ADDRESS_TYPE_FD:
4078ecc7f40SLaurent Vivier qemu_set_info_str(&s->nc, "fd=%d (cloned mcast=%s:%d)",
4088ecc7f40SLaurent Vivier fd, inet_ntoa(saddr->sin_addr),
4098ecc7f40SLaurent Vivier ntohs(saddr->sin_port));
4108ecc7f40SLaurent Vivier break;
4118ecc7f40SLaurent Vivier default:
4128ecc7f40SLaurent Vivier g_assert_not_reached();
4138ecc7f40SLaurent Vivier }
4148ecc7f40SLaurent Vivier }
4157c1f0c33SLaurent Vivier
4165166fe0aSLaurent Vivier return 0;
4175166fe0aSLaurent Vivier
4185166fe0aSLaurent Vivier }
4195166fe0aSLaurent Vivier
4205166fe0aSLaurent Vivier
net_init_dgram(const Netdev * netdev,const char * name,NetClientState * peer,Error ** errp)4215166fe0aSLaurent Vivier int net_init_dgram(const Netdev *netdev, const char *name,
4225166fe0aSLaurent Vivier NetClientState *peer, Error **errp)
4235166fe0aSLaurent Vivier {
4245166fe0aSLaurent Vivier NetDgramState *s;
4255166fe0aSLaurent Vivier int fd, ret;
4265166fe0aSLaurent Vivier SocketAddress *remote, *local;
4277c1f0c33SLaurent Vivier struct sockaddr *dest_addr;
4287c1f0c33SLaurent Vivier struct sockaddr_in laddr_in, raddr_in;
429784e7a25SLaurent Vivier struct sockaddr_un laddr_un, raddr_un;
4307c1f0c33SLaurent Vivier socklen_t dest_len;
4315166fe0aSLaurent Vivier
4325166fe0aSLaurent Vivier assert(netdev->type == NET_CLIENT_DRIVER_DGRAM);
4335166fe0aSLaurent Vivier
4345166fe0aSLaurent Vivier remote = netdev->u.dgram.remote;
4355166fe0aSLaurent Vivier local = netdev->u.dgram.local;
4365166fe0aSLaurent Vivier
4375166fe0aSLaurent Vivier /* detect multicast address */
4385166fe0aSLaurent Vivier if (remote && remote->type == SOCKET_ADDRESS_TYPE_INET) {
4395166fe0aSLaurent Vivier struct sockaddr_in mcastaddr;
4405166fe0aSLaurent Vivier
4415166fe0aSLaurent Vivier if (convert_host_port(&mcastaddr, remote->u.inet.host,
4425166fe0aSLaurent Vivier remote->u.inet.port, errp) < 0) {
4435166fe0aSLaurent Vivier return -1;
4445166fe0aSLaurent Vivier }
4455166fe0aSLaurent Vivier
4465166fe0aSLaurent Vivier if (IN_MULTICAST(ntohl(mcastaddr.sin_addr.s_addr))) {
4475166fe0aSLaurent Vivier return net_dgram_mcast_init(peer, "dram", name, remote, local,
4485166fe0aSLaurent Vivier errp);
4495166fe0aSLaurent Vivier }
4505166fe0aSLaurent Vivier }
4515166fe0aSLaurent Vivier
4525166fe0aSLaurent Vivier /* unicast address */
4535166fe0aSLaurent Vivier if (!local) {
4545166fe0aSLaurent Vivier error_setg(errp, "dgram requires local= parameter");
4555166fe0aSLaurent Vivier return -1;
4565166fe0aSLaurent Vivier }
4575166fe0aSLaurent Vivier
4585166fe0aSLaurent Vivier if (remote) {
4595166fe0aSLaurent Vivier if (local->type == SOCKET_ADDRESS_TYPE_FD) {
4605166fe0aSLaurent Vivier error_setg(errp, "don't set remote with local.fd");
4615166fe0aSLaurent Vivier return -1;
4625166fe0aSLaurent Vivier }
4635166fe0aSLaurent Vivier if (remote->type != local->type) {
4645166fe0aSLaurent Vivier error_setg(errp, "remote and local types must be the same");
4655166fe0aSLaurent Vivier return -1;
4665166fe0aSLaurent Vivier }
4675166fe0aSLaurent Vivier } else {
4685166fe0aSLaurent Vivier if (local->type != SOCKET_ADDRESS_TYPE_FD) {
469784e7a25SLaurent Vivier error_setg(errp,
470784e7a25SLaurent Vivier "type=inet or type=unix requires remote parameter");
4715166fe0aSLaurent Vivier return -1;
4725166fe0aSLaurent Vivier }
4735166fe0aSLaurent Vivier }
4745166fe0aSLaurent Vivier
4755166fe0aSLaurent Vivier switch (local->type) {
4765166fe0aSLaurent Vivier case SOCKET_ADDRESS_TYPE_INET:
4775166fe0aSLaurent Vivier if (convert_host_port(&laddr_in, local->u.inet.host, local->u.inet.port,
4785166fe0aSLaurent Vivier errp) < 0) {
4795166fe0aSLaurent Vivier return -1;
4805166fe0aSLaurent Vivier }
4815166fe0aSLaurent Vivier
4825166fe0aSLaurent Vivier if (convert_host_port(&raddr_in, remote->u.inet.host,
4835166fe0aSLaurent Vivier remote->u.inet.port, errp) < 0) {
4845166fe0aSLaurent Vivier return -1;
4855166fe0aSLaurent Vivier }
4865166fe0aSLaurent Vivier
4875166fe0aSLaurent Vivier fd = qemu_socket(PF_INET, SOCK_DGRAM, 0);
4885166fe0aSLaurent Vivier if (fd < 0) {
4895166fe0aSLaurent Vivier error_setg_errno(errp, errno, "can't create datagram socket");
4905166fe0aSLaurent Vivier return -1;
4915166fe0aSLaurent Vivier }
4925166fe0aSLaurent Vivier
4935166fe0aSLaurent Vivier ret = socket_set_fast_reuse(fd);
4945166fe0aSLaurent Vivier if (ret < 0) {
4955166fe0aSLaurent Vivier error_setg_errno(errp, errno,
4965166fe0aSLaurent Vivier "can't set socket option SO_REUSEADDR");
497*25657fc6SMarc-André Lureau close(fd);
4985166fe0aSLaurent Vivier return -1;
4995166fe0aSLaurent Vivier }
5005166fe0aSLaurent Vivier ret = bind(fd, (struct sockaddr *)&laddr_in, sizeof(laddr_in));
5015166fe0aSLaurent Vivier if (ret < 0) {
5025166fe0aSLaurent Vivier error_setg_errno(errp, errno, "can't bind ip=%s to socket",
5035166fe0aSLaurent Vivier inet_ntoa(laddr_in.sin_addr));
504*25657fc6SMarc-André Lureau close(fd);
5055166fe0aSLaurent Vivier return -1;
5065166fe0aSLaurent Vivier }
5075166fe0aSLaurent Vivier qemu_socket_set_nonblock(fd);
5087c1f0c33SLaurent Vivier
5097c1f0c33SLaurent Vivier dest_len = sizeof(raddr_in);
5107c1f0c33SLaurent Vivier dest_addr = g_malloc(dest_len);
5117c1f0c33SLaurent Vivier memcpy(dest_addr, &raddr_in, dest_len);
5125166fe0aSLaurent Vivier break;
513784e7a25SLaurent Vivier case SOCKET_ADDRESS_TYPE_UNIX:
514784e7a25SLaurent Vivier ret = unlink(local->u.q_unix.path);
515784e7a25SLaurent Vivier if (ret < 0 && errno != ENOENT) {
516784e7a25SLaurent Vivier error_setg_errno(errp, errno, "failed to unlink socket %s",
517784e7a25SLaurent Vivier local->u.q_unix.path);
518784e7a25SLaurent Vivier return -1;
519784e7a25SLaurent Vivier }
520784e7a25SLaurent Vivier
521784e7a25SLaurent Vivier laddr_un.sun_family = PF_UNIX;
522784e7a25SLaurent Vivier ret = snprintf(laddr_un.sun_path, sizeof(laddr_un.sun_path), "%s",
523784e7a25SLaurent Vivier local->u.q_unix.path);
524784e7a25SLaurent Vivier if (ret < 0 || ret >= sizeof(laddr_un.sun_path)) {
525784e7a25SLaurent Vivier error_setg(errp, "UNIX socket path '%s' is too long",
526784e7a25SLaurent Vivier local->u.q_unix.path);
527784e7a25SLaurent Vivier error_append_hint(errp, "Path must be less than %zu bytes\n",
528784e7a25SLaurent Vivier sizeof(laddr_un.sun_path));
529784e7a25SLaurent Vivier }
530784e7a25SLaurent Vivier
531784e7a25SLaurent Vivier raddr_un.sun_family = PF_UNIX;
532784e7a25SLaurent Vivier ret = snprintf(raddr_un.sun_path, sizeof(raddr_un.sun_path), "%s",
533784e7a25SLaurent Vivier remote->u.q_unix.path);
534784e7a25SLaurent Vivier if (ret < 0 || ret >= sizeof(raddr_un.sun_path)) {
535784e7a25SLaurent Vivier error_setg(errp, "UNIX socket path '%s' is too long",
536784e7a25SLaurent Vivier remote->u.q_unix.path);
537784e7a25SLaurent Vivier error_append_hint(errp, "Path must be less than %zu bytes\n",
538784e7a25SLaurent Vivier sizeof(raddr_un.sun_path));
539784e7a25SLaurent Vivier }
540784e7a25SLaurent Vivier
541784e7a25SLaurent Vivier fd = qemu_socket(PF_UNIX, SOCK_DGRAM, 0);
542784e7a25SLaurent Vivier if (fd < 0) {
543784e7a25SLaurent Vivier error_setg_errno(errp, errno, "can't create datagram socket");
544784e7a25SLaurent Vivier return -1;
545784e7a25SLaurent Vivier }
546784e7a25SLaurent Vivier
547784e7a25SLaurent Vivier ret = bind(fd, (struct sockaddr *)&laddr_un, sizeof(laddr_un));
548784e7a25SLaurent Vivier if (ret < 0) {
549784e7a25SLaurent Vivier error_setg_errno(errp, errno, "can't bind unix=%s to socket",
550784e7a25SLaurent Vivier laddr_un.sun_path);
551*25657fc6SMarc-André Lureau close(fd);
552784e7a25SLaurent Vivier return -1;
553784e7a25SLaurent Vivier }
554784e7a25SLaurent Vivier qemu_socket_set_nonblock(fd);
555784e7a25SLaurent Vivier
556784e7a25SLaurent Vivier dest_len = sizeof(raddr_un);
557784e7a25SLaurent Vivier dest_addr = g_malloc(dest_len);
558784e7a25SLaurent Vivier memcpy(dest_addr, &raddr_un, dest_len);
559784e7a25SLaurent Vivier break;
5605166fe0aSLaurent Vivier case SOCKET_ADDRESS_TYPE_FD:
5615166fe0aSLaurent Vivier fd = monitor_fd_param(monitor_cur(), local->u.fd.str, errp);
5625166fe0aSLaurent Vivier if (fd == -1) {
5635166fe0aSLaurent Vivier return -1;
5645166fe0aSLaurent Vivier }
5655166fe0aSLaurent Vivier ret = qemu_socket_try_set_nonblock(fd);
5665166fe0aSLaurent Vivier if (ret < 0) {
5675166fe0aSLaurent Vivier error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d",
5685166fe0aSLaurent Vivier name, fd);
5695166fe0aSLaurent Vivier return -1;
5705166fe0aSLaurent Vivier }
5717c1f0c33SLaurent Vivier dest_addr = NULL;
5727c1f0c33SLaurent Vivier dest_len = 0;
5735166fe0aSLaurent Vivier break;
5745166fe0aSLaurent Vivier default:
5755166fe0aSLaurent Vivier error_setg(errp, "only support inet or fd type for local");
5765166fe0aSLaurent Vivier return -1;
5775166fe0aSLaurent Vivier }
5785166fe0aSLaurent Vivier
5798ecc7f40SLaurent Vivier s = net_dgram_fd_init(peer, "dgram", name, fd, errp);
5805166fe0aSLaurent Vivier if (!s) {
5815166fe0aSLaurent Vivier return -1;
5825166fe0aSLaurent Vivier }
5835166fe0aSLaurent Vivier
5845166fe0aSLaurent Vivier if (remote) {
5857c1f0c33SLaurent Vivier g_assert(s->dest_addr == NULL);
5867c1f0c33SLaurent Vivier s->dest_addr = dest_addr;
5877c1f0c33SLaurent Vivier s->dest_len = dest_len;
5885166fe0aSLaurent Vivier }
5895166fe0aSLaurent Vivier
5905166fe0aSLaurent Vivier switch (local->type) {
5915166fe0aSLaurent Vivier case SOCKET_ADDRESS_TYPE_INET:
5925166fe0aSLaurent Vivier qemu_set_info_str(&s->nc, "udp=%s:%d/%s:%d",
5935166fe0aSLaurent Vivier inet_ntoa(laddr_in.sin_addr),
5945166fe0aSLaurent Vivier ntohs(laddr_in.sin_port),
5955166fe0aSLaurent Vivier inet_ntoa(raddr_in.sin_addr),
5965166fe0aSLaurent Vivier ntohs(raddr_in.sin_port));
5975166fe0aSLaurent Vivier break;
598784e7a25SLaurent Vivier case SOCKET_ADDRESS_TYPE_UNIX:
599784e7a25SLaurent Vivier qemu_set_info_str(&s->nc, "udp=%s:%s",
600784e7a25SLaurent Vivier laddr_un.sun_path, raddr_un.sun_path);
601784e7a25SLaurent Vivier break;
6028ecc7f40SLaurent Vivier case SOCKET_ADDRESS_TYPE_FD: {
6038ecc7f40SLaurent Vivier SocketAddress *sa;
6048ecc7f40SLaurent Vivier SocketAddressType sa_type;
6058ecc7f40SLaurent Vivier
6068ecc7f40SLaurent Vivier sa = socket_local_address(fd, errp);
6078ecc7f40SLaurent Vivier if (sa) {
6088ecc7f40SLaurent Vivier sa_type = sa->type;
6098ecc7f40SLaurent Vivier qapi_free_SocketAddress(sa);
6108ecc7f40SLaurent Vivier
6118ecc7f40SLaurent Vivier qemu_set_info_str(&s->nc, "fd=%d %s", fd,
6128ecc7f40SLaurent Vivier SocketAddressType_str(sa_type));
6138ecc7f40SLaurent Vivier } else {
6145166fe0aSLaurent Vivier qemu_set_info_str(&s->nc, "fd=%d", fd);
6158ecc7f40SLaurent Vivier }
6165166fe0aSLaurent Vivier break;
6178ecc7f40SLaurent Vivier }
6185166fe0aSLaurent Vivier default:
6195166fe0aSLaurent Vivier g_assert_not_reached();
6205166fe0aSLaurent Vivier }
6215166fe0aSLaurent Vivier
6225166fe0aSLaurent Vivier return 0;
6235166fe0aSLaurent Vivier }
624