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