13b4482a2SMarc-André Lureau /* 23b4482a2SMarc-André Lureau * QEMU System Emulator 33b4482a2SMarc-André Lureau * 43b4482a2SMarc-André Lureau * Copyright (c) 2003-2008 Fabrice Bellard 53b4482a2SMarc-André Lureau * 63b4482a2SMarc-André Lureau * Permission is hereby granted, free of charge, to any person obtaining a copy 73b4482a2SMarc-André Lureau * of this software and associated documentation files (the "Software"), to deal 83b4482a2SMarc-André Lureau * in the Software without restriction, including without limitation the rights 93b4482a2SMarc-André Lureau * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 103b4482a2SMarc-André Lureau * copies of the Software, and to permit persons to whom the Software is 113b4482a2SMarc-André Lureau * furnished to do so, subject to the following conditions: 123b4482a2SMarc-André Lureau * 133b4482a2SMarc-André Lureau * The above copyright notice and this permission notice shall be included in 143b4482a2SMarc-André Lureau * all copies or substantial portions of the Software. 153b4482a2SMarc-André Lureau * 163b4482a2SMarc-André Lureau * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 173b4482a2SMarc-André Lureau * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 183b4482a2SMarc-André Lureau * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 193b4482a2SMarc-André Lureau * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 203b4482a2SMarc-André Lureau * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 213b4482a2SMarc-André Lureau * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 223b4482a2SMarc-André Lureau * THE SOFTWARE. 233b4482a2SMarc-André Lureau */ 24*922a01a0SMarkus Armbruster 253b4482a2SMarc-André Lureau #include "qemu/osdep.h" 268228e353SMarc-André Lureau #include "chardev/char.h" 273b4482a2SMarc-André Lureau #include "io/channel-socket.h" 283b4482a2SMarc-André Lureau #include "qapi/error.h" 29*922a01a0SMarkus Armbruster #include "qemu/option.h" 303b4482a2SMarc-André Lureau 318228e353SMarc-André Lureau #include "chardev/char-io.h" 323b4482a2SMarc-André Lureau 333b4482a2SMarc-André Lureau /***********************************************************/ 343b4482a2SMarc-André Lureau /* UDP Net console */ 353b4482a2SMarc-André Lureau 363b4482a2SMarc-André Lureau typedef struct { 373b4482a2SMarc-André Lureau Chardev parent; 383b4482a2SMarc-André Lureau QIOChannel *ioc; 393b4482a2SMarc-André Lureau uint8_t buf[CHR_READ_BUF_LEN]; 403b4482a2SMarc-André Lureau int bufcnt; 413b4482a2SMarc-André Lureau int bufptr; 423b4482a2SMarc-André Lureau int max_size; 433b4482a2SMarc-André Lureau } UdpChardev; 443b4482a2SMarc-André Lureau 453b4482a2SMarc-André Lureau #define UDP_CHARDEV(obj) OBJECT_CHECK(UdpChardev, (obj), TYPE_CHARDEV_UDP) 463b4482a2SMarc-André Lureau 473b4482a2SMarc-André Lureau /* Called with chr_write_lock held. */ 483b4482a2SMarc-André Lureau static int udp_chr_write(Chardev *chr, const uint8_t *buf, int len) 493b4482a2SMarc-André Lureau { 503b4482a2SMarc-André Lureau UdpChardev *s = UDP_CHARDEV(chr); 513b4482a2SMarc-André Lureau 523b4482a2SMarc-André Lureau return qio_channel_write( 533b4482a2SMarc-André Lureau s->ioc, (const char *)buf, len, NULL); 543b4482a2SMarc-André Lureau } 553b4482a2SMarc-André Lureau 56e0b6767bSMarc-André Lureau static void udp_chr_flush_buffer(UdpChardev *s) 57e0b6767bSMarc-André Lureau { 58e0b6767bSMarc-André Lureau Chardev *chr = CHARDEV(s); 59e0b6767bSMarc-André Lureau 60e0b6767bSMarc-André Lureau while (s->max_size > 0 && s->bufptr < s->bufcnt) { 61e0b6767bSMarc-André Lureau int n = MIN(s->max_size, s->bufcnt - s->bufptr); 62e0b6767bSMarc-André Lureau qemu_chr_be_write(chr, &s->buf[s->bufptr], n); 63e0b6767bSMarc-André Lureau s->bufptr += n; 64e0b6767bSMarc-André Lureau s->max_size = qemu_chr_be_can_write(chr); 65e0b6767bSMarc-André Lureau } 66e0b6767bSMarc-André Lureau } 67e0b6767bSMarc-André Lureau 683b4482a2SMarc-André Lureau static int udp_chr_read_poll(void *opaque) 693b4482a2SMarc-André Lureau { 703b4482a2SMarc-André Lureau Chardev *chr = CHARDEV(opaque); 713b4482a2SMarc-André Lureau UdpChardev *s = UDP_CHARDEV(opaque); 723b4482a2SMarc-André Lureau 733b4482a2SMarc-André Lureau s->max_size = qemu_chr_be_can_write(chr); 743b4482a2SMarc-André Lureau 753b4482a2SMarc-André Lureau /* If there were any stray characters in the queue process them 763b4482a2SMarc-André Lureau * first 773b4482a2SMarc-André Lureau */ 78e0b6767bSMarc-André Lureau udp_chr_flush_buffer(s); 79e0b6767bSMarc-André Lureau 803b4482a2SMarc-André Lureau return s->max_size; 813b4482a2SMarc-André Lureau } 823b4482a2SMarc-André Lureau 833b4482a2SMarc-André Lureau static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque) 843b4482a2SMarc-André Lureau { 853b4482a2SMarc-André Lureau Chardev *chr = CHARDEV(opaque); 863b4482a2SMarc-André Lureau UdpChardev *s = UDP_CHARDEV(opaque); 873b4482a2SMarc-André Lureau ssize_t ret; 883b4482a2SMarc-André Lureau 893b4482a2SMarc-André Lureau if (s->max_size == 0) { 903b4482a2SMarc-André Lureau return TRUE; 913b4482a2SMarc-André Lureau } 923b4482a2SMarc-André Lureau ret = qio_channel_read( 933b4482a2SMarc-André Lureau s->ioc, (char *)s->buf, sizeof(s->buf), NULL); 943b4482a2SMarc-André Lureau if (ret <= 0) { 95b19456ddSzhanghailiang remove_fd_in_watch(chr); 963b4482a2SMarc-André Lureau return FALSE; 973b4482a2SMarc-André Lureau } 983b4482a2SMarc-André Lureau s->bufcnt = ret; 993b4482a2SMarc-André Lureau s->bufptr = 0; 100e0b6767bSMarc-André Lureau udp_chr_flush_buffer(s); 1013b4482a2SMarc-André Lureau 1023b4482a2SMarc-André Lureau return TRUE; 1033b4482a2SMarc-André Lureau } 1043b4482a2SMarc-André Lureau 105bb86d05fSPeter Xu static void udp_chr_update_read_handler(Chardev *chr) 1063b4482a2SMarc-André Lureau { 1073b4482a2SMarc-André Lureau UdpChardev *s = UDP_CHARDEV(chr); 1083b4482a2SMarc-André Lureau 109b19456ddSzhanghailiang remove_fd_in_watch(chr); 1103b4482a2SMarc-André Lureau if (s->ioc) { 111b19456ddSzhanghailiang chr->gsource = io_add_watch_poll(chr, s->ioc, 1123b4482a2SMarc-André Lureau udp_chr_read_poll, 1133b4482a2SMarc-André Lureau udp_chr_read, chr, 1146bbb6c06SPeter Xu chr->gcontext); 1153b4482a2SMarc-André Lureau } 1163b4482a2SMarc-André Lureau } 1173b4482a2SMarc-André Lureau 1183b4482a2SMarc-André Lureau static void char_udp_finalize(Object *obj) 1193b4482a2SMarc-André Lureau { 1203b4482a2SMarc-André Lureau Chardev *chr = CHARDEV(obj); 1213b4482a2SMarc-André Lureau UdpChardev *s = UDP_CHARDEV(obj); 1223b4482a2SMarc-André Lureau 123b19456ddSzhanghailiang remove_fd_in_watch(chr); 1243b4482a2SMarc-André Lureau if (s->ioc) { 1253b4482a2SMarc-André Lureau object_unref(OBJECT(s->ioc)); 1263b4482a2SMarc-André Lureau } 1273b4482a2SMarc-André Lureau qemu_chr_be_event(chr, CHR_EVENT_CLOSED); 1283b4482a2SMarc-André Lureau } 1293b4482a2SMarc-André Lureau 1303b4482a2SMarc-André Lureau static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend, 1313b4482a2SMarc-André Lureau Error **errp) 1323b4482a2SMarc-André Lureau { 1333b4482a2SMarc-André Lureau const char *host = qemu_opt_get(opts, "host"); 1343b4482a2SMarc-André Lureau const char *port = qemu_opt_get(opts, "port"); 1353b4482a2SMarc-André Lureau const char *localaddr = qemu_opt_get(opts, "localaddr"); 1363b4482a2SMarc-André Lureau const char *localport = qemu_opt_get(opts, "localport"); 1373b4482a2SMarc-André Lureau bool has_local = false; 138dfd100f2SMarkus Armbruster SocketAddressLegacy *addr; 1393b4482a2SMarc-André Lureau ChardevUdp *udp; 1403b4482a2SMarc-André Lureau 1413b4482a2SMarc-André Lureau backend->type = CHARDEV_BACKEND_KIND_UDP; 1423b4482a2SMarc-André Lureau if (host == NULL || strlen(host) == 0) { 1433b4482a2SMarc-André Lureau host = "localhost"; 1443b4482a2SMarc-André Lureau } 1453b4482a2SMarc-André Lureau if (port == NULL || strlen(port) == 0) { 1463b4482a2SMarc-André Lureau error_setg(errp, "chardev: udp: remote port not specified"); 1473b4482a2SMarc-André Lureau return; 1483b4482a2SMarc-André Lureau } 1493b4482a2SMarc-André Lureau if (localport == NULL || strlen(localport) == 0) { 1503b4482a2SMarc-André Lureau localport = "0"; 1513b4482a2SMarc-André Lureau } else { 1523b4482a2SMarc-André Lureau has_local = true; 1533b4482a2SMarc-André Lureau } 1543b4482a2SMarc-André Lureau if (localaddr == NULL || strlen(localaddr) == 0) { 1553b4482a2SMarc-André Lureau localaddr = ""; 1563b4482a2SMarc-André Lureau } else { 1573b4482a2SMarc-André Lureau has_local = true; 1583b4482a2SMarc-André Lureau } 1593b4482a2SMarc-André Lureau 1603b4482a2SMarc-André Lureau udp = backend->u.udp.data = g_new0(ChardevUdp, 1); 1613b4482a2SMarc-André Lureau qemu_chr_parse_common(opts, qapi_ChardevUdp_base(udp)); 1623b4482a2SMarc-André Lureau 163dfd100f2SMarkus Armbruster addr = g_new0(SocketAddressLegacy, 1); 164dfd100f2SMarkus Armbruster addr->type = SOCKET_ADDRESS_LEGACY_KIND_INET; 1653b4482a2SMarc-André Lureau addr->u.inet.data = g_new(InetSocketAddress, 1); 1663b4482a2SMarc-André Lureau *addr->u.inet.data = (InetSocketAddress) { 1673b4482a2SMarc-André Lureau .host = g_strdup(host), 1683b4482a2SMarc-André Lureau .port = g_strdup(port), 1693b4482a2SMarc-André Lureau .has_ipv4 = qemu_opt_get(opts, "ipv4"), 1703b4482a2SMarc-André Lureau .ipv4 = qemu_opt_get_bool(opts, "ipv4", 0), 1713b4482a2SMarc-André Lureau .has_ipv6 = qemu_opt_get(opts, "ipv6"), 1723b4482a2SMarc-André Lureau .ipv6 = qemu_opt_get_bool(opts, "ipv6", 0), 1733b4482a2SMarc-André Lureau }; 1743b4482a2SMarc-André Lureau udp->remote = addr; 1753b4482a2SMarc-André Lureau 1763b4482a2SMarc-André Lureau if (has_local) { 1773b4482a2SMarc-André Lureau udp->has_local = true; 178dfd100f2SMarkus Armbruster addr = g_new0(SocketAddressLegacy, 1); 179dfd100f2SMarkus Armbruster addr->type = SOCKET_ADDRESS_LEGACY_KIND_INET; 1803b4482a2SMarc-André Lureau addr->u.inet.data = g_new(InetSocketAddress, 1); 1813b4482a2SMarc-André Lureau *addr->u.inet.data = (InetSocketAddress) { 1823b4482a2SMarc-André Lureau .host = g_strdup(localaddr), 1833b4482a2SMarc-André Lureau .port = g_strdup(localport), 1843b4482a2SMarc-André Lureau }; 1853b4482a2SMarc-André Lureau udp->local = addr; 1863b4482a2SMarc-André Lureau } 1873b4482a2SMarc-André Lureau } 1883b4482a2SMarc-André Lureau 1893b4482a2SMarc-André Lureau static void qmp_chardev_open_udp(Chardev *chr, 1903b4482a2SMarc-André Lureau ChardevBackend *backend, 1913b4482a2SMarc-André Lureau bool *be_opened, 1923b4482a2SMarc-André Lureau Error **errp) 1933b4482a2SMarc-André Lureau { 1943b4482a2SMarc-André Lureau ChardevUdp *udp = backend->u.udp.data; 195bd269ebcSMarkus Armbruster SocketAddress *local_addr = socket_address_flatten(udp->local); 196bd269ebcSMarkus Armbruster SocketAddress *remote_addr = socket_address_flatten(udp->remote); 1973b4482a2SMarc-André Lureau QIOChannelSocket *sioc = qio_channel_socket_new(); 1983b4482a2SMarc-André Lureau char *name; 1993b4482a2SMarc-André Lureau UdpChardev *s = UDP_CHARDEV(chr); 200bd269ebcSMarkus Armbruster int ret; 2013b4482a2SMarc-André Lureau 202bd269ebcSMarkus Armbruster ret = qio_channel_socket_dgram_sync(sioc, local_addr, remote_addr, errp); 203bd269ebcSMarkus Armbruster qapi_free_SocketAddress(local_addr); 204bd269ebcSMarkus Armbruster qapi_free_SocketAddress(remote_addr); 205bd269ebcSMarkus Armbruster if (ret < 0) { 2063b4482a2SMarc-André Lureau object_unref(OBJECT(sioc)); 2073b4482a2SMarc-André Lureau return; 2083b4482a2SMarc-André Lureau } 2093b4482a2SMarc-André Lureau 2103b4482a2SMarc-André Lureau name = g_strdup_printf("chardev-udp-%s", chr->label); 2113b4482a2SMarc-André Lureau qio_channel_set_name(QIO_CHANNEL(sioc), name); 2123b4482a2SMarc-André Lureau g_free(name); 2133b4482a2SMarc-André Lureau 2143b4482a2SMarc-André Lureau s->ioc = QIO_CHANNEL(sioc); 2153b4482a2SMarc-André Lureau /* be isn't opened until we get a connection */ 2163b4482a2SMarc-André Lureau *be_opened = false; 2173b4482a2SMarc-André Lureau } 2183b4482a2SMarc-André Lureau 2193b4482a2SMarc-André Lureau static void char_udp_class_init(ObjectClass *oc, void *data) 2203b4482a2SMarc-André Lureau { 2213b4482a2SMarc-André Lureau ChardevClass *cc = CHARDEV_CLASS(oc); 2223b4482a2SMarc-André Lureau 2233b4482a2SMarc-André Lureau cc->parse = qemu_chr_parse_udp; 2243b4482a2SMarc-André Lureau cc->open = qmp_chardev_open_udp; 2253b4482a2SMarc-André Lureau cc->chr_write = udp_chr_write; 2263b4482a2SMarc-André Lureau cc->chr_update_read_handler = udp_chr_update_read_handler; 2273b4482a2SMarc-André Lureau } 2283b4482a2SMarc-André Lureau 2293b4482a2SMarc-André Lureau static const TypeInfo char_udp_type_info = { 2303b4482a2SMarc-André Lureau .name = TYPE_CHARDEV_UDP, 2313b4482a2SMarc-André Lureau .parent = TYPE_CHARDEV, 2323b4482a2SMarc-André Lureau .instance_size = sizeof(UdpChardev), 2333b4482a2SMarc-André Lureau .instance_finalize = char_udp_finalize, 2343b4482a2SMarc-André Lureau .class_init = char_udp_class_init, 2353b4482a2SMarc-André Lureau }; 2363b4482a2SMarc-André Lureau 2373b4482a2SMarc-André Lureau static void register_types(void) 2383b4482a2SMarc-André Lureau { 2393b4482a2SMarc-André Lureau type_register_static(&char_udp_type_info); 2403b4482a2SMarc-André Lureau } 2413b4482a2SMarc-André Lureau 2423b4482a2SMarc-André Lureau type_init(register_types); 243