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 */ 243b4482a2SMarc-André Lureau #include "qemu/osdep.h" 253b4482a2SMarc-André Lureau #include "sysemu/char.h" 263b4482a2SMarc-André Lureau #include "io/channel-socket.h" 273b4482a2SMarc-André Lureau #include "qapi/error.h" 283b4482a2SMarc-André Lureau 293b4482a2SMarc-André Lureau #include "char-io.h" 303b4482a2SMarc-André Lureau 313b4482a2SMarc-André Lureau /***********************************************************/ 323b4482a2SMarc-André Lureau /* UDP Net console */ 333b4482a2SMarc-André Lureau 343b4482a2SMarc-André Lureau typedef struct { 353b4482a2SMarc-André Lureau Chardev parent; 363b4482a2SMarc-André Lureau QIOChannel *ioc; 373b4482a2SMarc-André Lureau uint8_t buf[CHR_READ_BUF_LEN]; 383b4482a2SMarc-André Lureau int bufcnt; 393b4482a2SMarc-André Lureau int bufptr; 403b4482a2SMarc-André Lureau int max_size; 413b4482a2SMarc-André Lureau } UdpChardev; 423b4482a2SMarc-André Lureau 433b4482a2SMarc-André Lureau #define UDP_CHARDEV(obj) OBJECT_CHECK(UdpChardev, (obj), TYPE_CHARDEV_UDP) 443b4482a2SMarc-André Lureau 453b4482a2SMarc-André Lureau /* Called with chr_write_lock held. */ 463b4482a2SMarc-André Lureau static int udp_chr_write(Chardev *chr, const uint8_t *buf, int len) 473b4482a2SMarc-André Lureau { 483b4482a2SMarc-André Lureau UdpChardev *s = UDP_CHARDEV(chr); 493b4482a2SMarc-André Lureau 503b4482a2SMarc-André Lureau return qio_channel_write( 513b4482a2SMarc-André Lureau s->ioc, (const char *)buf, len, NULL); 523b4482a2SMarc-André Lureau } 533b4482a2SMarc-André Lureau 54*e0b6767bSMarc-André Lureau static void udp_chr_flush_buffer(UdpChardev *s) 55*e0b6767bSMarc-André Lureau { 56*e0b6767bSMarc-André Lureau Chardev *chr = CHARDEV(s); 57*e0b6767bSMarc-André Lureau 58*e0b6767bSMarc-André Lureau while (s->max_size > 0 && s->bufptr < s->bufcnt) { 59*e0b6767bSMarc-André Lureau int n = MIN(s->max_size, s->bufcnt - s->bufptr); 60*e0b6767bSMarc-André Lureau qemu_chr_be_write(chr, &s->buf[s->bufptr], n); 61*e0b6767bSMarc-André Lureau s->bufptr += n; 62*e0b6767bSMarc-André Lureau s->max_size = qemu_chr_be_can_write(chr); 63*e0b6767bSMarc-André Lureau } 64*e0b6767bSMarc-André Lureau } 65*e0b6767bSMarc-André Lureau 663b4482a2SMarc-André Lureau static int udp_chr_read_poll(void *opaque) 673b4482a2SMarc-André Lureau { 683b4482a2SMarc-André Lureau Chardev *chr = CHARDEV(opaque); 693b4482a2SMarc-André Lureau UdpChardev *s = UDP_CHARDEV(opaque); 703b4482a2SMarc-André Lureau 713b4482a2SMarc-André Lureau s->max_size = qemu_chr_be_can_write(chr); 723b4482a2SMarc-André Lureau 733b4482a2SMarc-André Lureau /* If there were any stray characters in the queue process them 743b4482a2SMarc-André Lureau * first 753b4482a2SMarc-André Lureau */ 76*e0b6767bSMarc-André Lureau udp_chr_flush_buffer(s); 77*e0b6767bSMarc-André Lureau 783b4482a2SMarc-André Lureau return s->max_size; 793b4482a2SMarc-André Lureau } 803b4482a2SMarc-André Lureau 813b4482a2SMarc-André Lureau static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque) 823b4482a2SMarc-André Lureau { 833b4482a2SMarc-André Lureau Chardev *chr = CHARDEV(opaque); 843b4482a2SMarc-André Lureau UdpChardev *s = UDP_CHARDEV(opaque); 853b4482a2SMarc-André Lureau ssize_t ret; 863b4482a2SMarc-André Lureau 873b4482a2SMarc-André Lureau if (s->max_size == 0) { 883b4482a2SMarc-André Lureau return TRUE; 893b4482a2SMarc-André Lureau } 903b4482a2SMarc-André Lureau ret = qio_channel_read( 913b4482a2SMarc-André Lureau s->ioc, (char *)s->buf, sizeof(s->buf), NULL); 923b4482a2SMarc-André Lureau if (ret <= 0) { 938487ce45Szhanghailiang remove_fd_in_watch(chr, NULL); 943b4482a2SMarc-André Lureau return FALSE; 953b4482a2SMarc-André Lureau } 963b4482a2SMarc-André Lureau s->bufcnt = ret; 973b4482a2SMarc-André Lureau s->bufptr = 0; 98*e0b6767bSMarc-André Lureau udp_chr_flush_buffer(s); 993b4482a2SMarc-André Lureau 1003b4482a2SMarc-André Lureau return TRUE; 1013b4482a2SMarc-André Lureau } 1023b4482a2SMarc-André Lureau 1033b4482a2SMarc-André Lureau static void udp_chr_update_read_handler(Chardev *chr, 1043b4482a2SMarc-André Lureau GMainContext *context) 1053b4482a2SMarc-André Lureau { 1063b4482a2SMarc-André Lureau UdpChardev *s = UDP_CHARDEV(chr); 1073b4482a2SMarc-André Lureau 1088487ce45Szhanghailiang remove_fd_in_watch(chr, NULL); 1093b4482a2SMarc-André Lureau if (s->ioc) { 1103b4482a2SMarc-André Lureau chr->fd_in_tag = io_add_watch_poll(chr, s->ioc, 1113b4482a2SMarc-André Lureau udp_chr_read_poll, 1123b4482a2SMarc-André Lureau udp_chr_read, chr, 1133b4482a2SMarc-André Lureau context); 1143b4482a2SMarc-André Lureau } 1153b4482a2SMarc-André Lureau } 1163b4482a2SMarc-André Lureau 1173b4482a2SMarc-André Lureau static void char_udp_finalize(Object *obj) 1183b4482a2SMarc-André Lureau { 1193b4482a2SMarc-André Lureau Chardev *chr = CHARDEV(obj); 1203b4482a2SMarc-André Lureau UdpChardev *s = UDP_CHARDEV(obj); 1213b4482a2SMarc-André Lureau 1228487ce45Szhanghailiang remove_fd_in_watch(chr, NULL); 1233b4482a2SMarc-André Lureau if (s->ioc) { 1243b4482a2SMarc-André Lureau object_unref(OBJECT(s->ioc)); 1253b4482a2SMarc-André Lureau } 1263b4482a2SMarc-André Lureau qemu_chr_be_event(chr, CHR_EVENT_CLOSED); 1273b4482a2SMarc-André Lureau } 1283b4482a2SMarc-André Lureau 1293b4482a2SMarc-André Lureau static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend, 1303b4482a2SMarc-André Lureau Error **errp) 1313b4482a2SMarc-André Lureau { 1323b4482a2SMarc-André Lureau const char *host = qemu_opt_get(opts, "host"); 1333b4482a2SMarc-André Lureau const char *port = qemu_opt_get(opts, "port"); 1343b4482a2SMarc-André Lureau const char *localaddr = qemu_opt_get(opts, "localaddr"); 1353b4482a2SMarc-André Lureau const char *localport = qemu_opt_get(opts, "localport"); 1363b4482a2SMarc-André Lureau bool has_local = false; 1373b4482a2SMarc-André Lureau SocketAddress *addr; 1383b4482a2SMarc-André Lureau ChardevUdp *udp; 1393b4482a2SMarc-André Lureau 1403b4482a2SMarc-André Lureau backend->type = CHARDEV_BACKEND_KIND_UDP; 1413b4482a2SMarc-André Lureau if (host == NULL || strlen(host) == 0) { 1423b4482a2SMarc-André Lureau host = "localhost"; 1433b4482a2SMarc-André Lureau } 1443b4482a2SMarc-André Lureau if (port == NULL || strlen(port) == 0) { 1453b4482a2SMarc-André Lureau error_setg(errp, "chardev: udp: remote port not specified"); 1463b4482a2SMarc-André Lureau return; 1473b4482a2SMarc-André Lureau } 1483b4482a2SMarc-André Lureau if (localport == NULL || strlen(localport) == 0) { 1493b4482a2SMarc-André Lureau localport = "0"; 1503b4482a2SMarc-André Lureau } else { 1513b4482a2SMarc-André Lureau has_local = true; 1523b4482a2SMarc-André Lureau } 1533b4482a2SMarc-André Lureau if (localaddr == NULL || strlen(localaddr) == 0) { 1543b4482a2SMarc-André Lureau localaddr = ""; 1553b4482a2SMarc-André Lureau } else { 1563b4482a2SMarc-André Lureau has_local = true; 1573b4482a2SMarc-André Lureau } 1583b4482a2SMarc-André Lureau 1593b4482a2SMarc-André Lureau udp = backend->u.udp.data = g_new0(ChardevUdp, 1); 1603b4482a2SMarc-André Lureau qemu_chr_parse_common(opts, qapi_ChardevUdp_base(udp)); 1613b4482a2SMarc-André Lureau 1623b4482a2SMarc-André Lureau addr = g_new0(SocketAddress, 1); 1633b4482a2SMarc-André Lureau addr->type = SOCKET_ADDRESS_KIND_INET; 1643b4482a2SMarc-André Lureau addr->u.inet.data = g_new(InetSocketAddress, 1); 1653b4482a2SMarc-André Lureau *addr->u.inet.data = (InetSocketAddress) { 1663b4482a2SMarc-André Lureau .host = g_strdup(host), 1673b4482a2SMarc-André Lureau .port = g_strdup(port), 1683b4482a2SMarc-André Lureau .has_ipv4 = qemu_opt_get(opts, "ipv4"), 1693b4482a2SMarc-André Lureau .ipv4 = qemu_opt_get_bool(opts, "ipv4", 0), 1703b4482a2SMarc-André Lureau .has_ipv6 = qemu_opt_get(opts, "ipv6"), 1713b4482a2SMarc-André Lureau .ipv6 = qemu_opt_get_bool(opts, "ipv6", 0), 1723b4482a2SMarc-André Lureau }; 1733b4482a2SMarc-André Lureau udp->remote = addr; 1743b4482a2SMarc-André Lureau 1753b4482a2SMarc-André Lureau if (has_local) { 1763b4482a2SMarc-André Lureau udp->has_local = true; 1773b4482a2SMarc-André Lureau addr = g_new0(SocketAddress, 1); 1783b4482a2SMarc-André Lureau addr->type = SOCKET_ADDRESS_KIND_INET; 1793b4482a2SMarc-André Lureau addr->u.inet.data = g_new(InetSocketAddress, 1); 1803b4482a2SMarc-André Lureau *addr->u.inet.data = (InetSocketAddress) { 1813b4482a2SMarc-André Lureau .host = g_strdup(localaddr), 1823b4482a2SMarc-André Lureau .port = g_strdup(localport), 1833b4482a2SMarc-André Lureau }; 1843b4482a2SMarc-André Lureau udp->local = addr; 1853b4482a2SMarc-André Lureau } 1863b4482a2SMarc-André Lureau } 1873b4482a2SMarc-André Lureau 1883b4482a2SMarc-André Lureau static void qmp_chardev_open_udp(Chardev *chr, 1893b4482a2SMarc-André Lureau ChardevBackend *backend, 1903b4482a2SMarc-André Lureau bool *be_opened, 1913b4482a2SMarc-André Lureau Error **errp) 1923b4482a2SMarc-André Lureau { 1933b4482a2SMarc-André Lureau ChardevUdp *udp = backend->u.udp.data; 1943b4482a2SMarc-André Lureau QIOChannelSocket *sioc = qio_channel_socket_new(); 1953b4482a2SMarc-André Lureau char *name; 1963b4482a2SMarc-André Lureau UdpChardev *s = UDP_CHARDEV(chr); 1973b4482a2SMarc-André Lureau 1983b4482a2SMarc-André Lureau if (qio_channel_socket_dgram_sync(sioc, 1993b4482a2SMarc-André Lureau udp->local, udp->remote, 2003b4482a2SMarc-André Lureau errp) < 0) { 2013b4482a2SMarc-André Lureau object_unref(OBJECT(sioc)); 2023b4482a2SMarc-André Lureau return; 2033b4482a2SMarc-André Lureau } 2043b4482a2SMarc-André Lureau 2053b4482a2SMarc-André Lureau name = g_strdup_printf("chardev-udp-%s", chr->label); 2063b4482a2SMarc-André Lureau qio_channel_set_name(QIO_CHANNEL(sioc), name); 2073b4482a2SMarc-André Lureau g_free(name); 2083b4482a2SMarc-André Lureau 2093b4482a2SMarc-André Lureau s->ioc = QIO_CHANNEL(sioc); 2103b4482a2SMarc-André Lureau /* be isn't opened until we get a connection */ 2113b4482a2SMarc-André Lureau *be_opened = false; 2123b4482a2SMarc-André Lureau } 2133b4482a2SMarc-André Lureau 2143b4482a2SMarc-André Lureau static void char_udp_class_init(ObjectClass *oc, void *data) 2153b4482a2SMarc-André Lureau { 2163b4482a2SMarc-André Lureau ChardevClass *cc = CHARDEV_CLASS(oc); 2173b4482a2SMarc-André Lureau 2183b4482a2SMarc-André Lureau cc->parse = qemu_chr_parse_udp; 2193b4482a2SMarc-André Lureau cc->open = qmp_chardev_open_udp; 2203b4482a2SMarc-André Lureau cc->chr_write = udp_chr_write; 2213b4482a2SMarc-André Lureau cc->chr_update_read_handler = udp_chr_update_read_handler; 2223b4482a2SMarc-André Lureau } 2233b4482a2SMarc-André Lureau 2243b4482a2SMarc-André Lureau static const TypeInfo char_udp_type_info = { 2253b4482a2SMarc-André Lureau .name = TYPE_CHARDEV_UDP, 2263b4482a2SMarc-André Lureau .parent = TYPE_CHARDEV, 2273b4482a2SMarc-André Lureau .instance_size = sizeof(UdpChardev), 2283b4482a2SMarc-André Lureau .instance_finalize = char_udp_finalize, 2293b4482a2SMarc-André Lureau .class_init = char_udp_class_init, 2303b4482a2SMarc-André Lureau }; 2313b4482a2SMarc-André Lureau 2323b4482a2SMarc-André Lureau static void register_types(void) 2333b4482a2SMarc-André Lureau { 2343b4482a2SMarc-André Lureau type_register_static(&char_udp_type_info); 2353b4482a2SMarc-André Lureau } 2363b4482a2SMarc-André Lureau 2373b4482a2SMarc-André Lureau type_init(register_types); 238