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 */ 24922a01a0SMarkus 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" 290b8fa32fSMarkus Armbruster #include "qemu/module.h" 30922a01a0SMarkus Armbruster #include "qemu/option.h" 313b4482a2SMarc-André Lureau 328228e353SMarc-André Lureau #include "chardev/char-io.h" 33db1015e9SEduardo Habkost #include "qom/object.h" 343b4482a2SMarc-André Lureau 353b4482a2SMarc-André Lureau /***********************************************************/ 363b4482a2SMarc-André Lureau /* UDP Net console */ 373b4482a2SMarc-André Lureau 38db1015e9SEduardo Habkost struct UdpChardev { 393b4482a2SMarc-André Lureau Chardev parent; 403b4482a2SMarc-André Lureau QIOChannel *ioc; 413b4482a2SMarc-André Lureau uint8_t buf[CHR_READ_BUF_LEN]; 423b4482a2SMarc-André Lureau int bufcnt; 433b4482a2SMarc-André Lureau int bufptr; 443b4482a2SMarc-André Lureau int max_size; 45db1015e9SEduardo Habkost }; 46db1015e9SEduardo Habkost typedef struct UdpChardev UdpChardev; 473b4482a2SMarc-André Lureau 488110fa1dSEduardo Habkost DECLARE_INSTANCE_CHECKER(UdpChardev, UDP_CHARDEV, 498110fa1dSEduardo Habkost TYPE_CHARDEV_UDP) 503b4482a2SMarc-André Lureau 513b4482a2SMarc-André Lureau /* Called with chr_write_lock held. */ 523b4482a2SMarc-André Lureau static int udp_chr_write(Chardev *chr, const uint8_t *buf, int len) 533b4482a2SMarc-André Lureau { 543b4482a2SMarc-André Lureau UdpChardev *s = UDP_CHARDEV(chr); 553b4482a2SMarc-André Lureau 563b4482a2SMarc-André Lureau return qio_channel_write( 573b4482a2SMarc-André Lureau s->ioc, (const char *)buf, len, NULL); 583b4482a2SMarc-André Lureau } 593b4482a2SMarc-André Lureau 60e0b6767bSMarc-André Lureau static void udp_chr_flush_buffer(UdpChardev *s) 61e0b6767bSMarc-André Lureau { 62e0b6767bSMarc-André Lureau Chardev *chr = CHARDEV(s); 63e0b6767bSMarc-André Lureau 64e0b6767bSMarc-André Lureau while (s->max_size > 0 && s->bufptr < s->bufcnt) { 65e0b6767bSMarc-André Lureau int n = MIN(s->max_size, s->bufcnt - s->bufptr); 66e0b6767bSMarc-André Lureau qemu_chr_be_write(chr, &s->buf[s->bufptr], n); 67e0b6767bSMarc-André Lureau s->bufptr += n; 68e0b6767bSMarc-André Lureau s->max_size = qemu_chr_be_can_write(chr); 69e0b6767bSMarc-André Lureau } 70e0b6767bSMarc-André Lureau } 71e0b6767bSMarc-André Lureau 723b4482a2SMarc-André Lureau static int udp_chr_read_poll(void *opaque) 733b4482a2SMarc-André Lureau { 743b4482a2SMarc-André Lureau Chardev *chr = CHARDEV(opaque); 753b4482a2SMarc-André Lureau UdpChardev *s = UDP_CHARDEV(opaque); 763b4482a2SMarc-André Lureau 773b4482a2SMarc-André Lureau s->max_size = qemu_chr_be_can_write(chr); 783b4482a2SMarc-André Lureau 793b4482a2SMarc-André Lureau /* If there were any stray characters in the queue process them 803b4482a2SMarc-André Lureau * first 813b4482a2SMarc-André Lureau */ 82e0b6767bSMarc-André Lureau udp_chr_flush_buffer(s); 83e0b6767bSMarc-André Lureau 843b4482a2SMarc-André Lureau return s->max_size; 853b4482a2SMarc-André Lureau } 863b4482a2SMarc-André Lureau 873b4482a2SMarc-André Lureau static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque) 883b4482a2SMarc-André Lureau { 893b4482a2SMarc-André Lureau Chardev *chr = CHARDEV(opaque); 903b4482a2SMarc-André Lureau UdpChardev *s = UDP_CHARDEV(opaque); 913b4482a2SMarc-André Lureau ssize_t ret; 923b4482a2SMarc-André Lureau 933b4482a2SMarc-André Lureau if (s->max_size == 0) { 943b4482a2SMarc-André Lureau return TRUE; 953b4482a2SMarc-André Lureau } 963b4482a2SMarc-André Lureau ret = qio_channel_read( 973b4482a2SMarc-André Lureau s->ioc, (char *)s->buf, sizeof(s->buf), NULL); 983b4482a2SMarc-André Lureau if (ret <= 0) { 99b19456ddSzhanghailiang remove_fd_in_watch(chr); 1003b4482a2SMarc-André Lureau return FALSE; 1013b4482a2SMarc-André Lureau } 1023b4482a2SMarc-André Lureau s->bufcnt = ret; 1033b4482a2SMarc-André Lureau s->bufptr = 0; 104e0b6767bSMarc-André Lureau udp_chr_flush_buffer(s); 1053b4482a2SMarc-André Lureau 1063b4482a2SMarc-André Lureau return TRUE; 1073b4482a2SMarc-André Lureau } 1083b4482a2SMarc-André Lureau 109bb86d05fSPeter Xu static void udp_chr_update_read_handler(Chardev *chr) 1103b4482a2SMarc-André Lureau { 1113b4482a2SMarc-André Lureau UdpChardev *s = UDP_CHARDEV(chr); 1123b4482a2SMarc-André Lureau 113b19456ddSzhanghailiang remove_fd_in_watch(chr); 1143b4482a2SMarc-André Lureau if (s->ioc) { 115b19456ddSzhanghailiang chr->gsource = io_add_watch_poll(chr, s->ioc, 1163b4482a2SMarc-André Lureau udp_chr_read_poll, 1173b4482a2SMarc-André Lureau udp_chr_read, chr, 1186bbb6c06SPeter Xu chr->gcontext); 1193b4482a2SMarc-André Lureau } 1203b4482a2SMarc-André Lureau } 1213b4482a2SMarc-André Lureau 1223b4482a2SMarc-André Lureau static void char_udp_finalize(Object *obj) 1233b4482a2SMarc-André Lureau { 1243b4482a2SMarc-André Lureau Chardev *chr = CHARDEV(obj); 1253b4482a2SMarc-André Lureau UdpChardev *s = UDP_CHARDEV(obj); 1263b4482a2SMarc-André Lureau 127b19456ddSzhanghailiang remove_fd_in_watch(chr); 1283b4482a2SMarc-André Lureau if (s->ioc) { 1293b4482a2SMarc-André Lureau object_unref(OBJECT(s->ioc)); 1303b4482a2SMarc-André Lureau } 1313b4482a2SMarc-André Lureau qemu_chr_be_event(chr, CHR_EVENT_CLOSED); 1323b4482a2SMarc-André Lureau } 1333b4482a2SMarc-André Lureau 1343b4482a2SMarc-André Lureau static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend, 1353b4482a2SMarc-André Lureau Error **errp) 1363b4482a2SMarc-André Lureau { 1373b4482a2SMarc-André Lureau const char *host = qemu_opt_get(opts, "host"); 1383b4482a2SMarc-André Lureau const char *port = qemu_opt_get(opts, "port"); 1393b4482a2SMarc-André Lureau const char *localaddr = qemu_opt_get(opts, "localaddr"); 1403b4482a2SMarc-André Lureau const char *localport = qemu_opt_get(opts, "localport"); 1413b4482a2SMarc-André Lureau bool has_local = false; 142dfd100f2SMarkus Armbruster SocketAddressLegacy *addr; 1433b4482a2SMarc-André Lureau ChardevUdp *udp; 1443b4482a2SMarc-André Lureau 1453b4482a2SMarc-André Lureau backend->type = CHARDEV_BACKEND_KIND_UDP; 1463b4482a2SMarc-André Lureau if (host == NULL || strlen(host) == 0) { 1473b4482a2SMarc-André Lureau host = "localhost"; 1483b4482a2SMarc-André Lureau } 1493b4482a2SMarc-André Lureau if (port == NULL || strlen(port) == 0) { 1503b4482a2SMarc-André Lureau error_setg(errp, "chardev: udp: remote port not specified"); 1513b4482a2SMarc-André Lureau return; 1523b4482a2SMarc-André Lureau } 1533b4482a2SMarc-André Lureau if (localport == NULL || strlen(localport) == 0) { 1543b4482a2SMarc-André Lureau localport = "0"; 1553b4482a2SMarc-André Lureau } else { 1563b4482a2SMarc-André Lureau has_local = true; 1573b4482a2SMarc-André Lureau } 1583b4482a2SMarc-André Lureau if (localaddr == NULL || strlen(localaddr) == 0) { 1593b4482a2SMarc-André Lureau localaddr = ""; 1603b4482a2SMarc-André Lureau } else { 1613b4482a2SMarc-André Lureau has_local = true; 1623b4482a2SMarc-André Lureau } 1633b4482a2SMarc-André Lureau 1643b4482a2SMarc-André Lureau udp = backend->u.udp.data = g_new0(ChardevUdp, 1); 1653b4482a2SMarc-André Lureau qemu_chr_parse_common(opts, qapi_ChardevUdp_base(udp)); 1663b4482a2SMarc-André Lureau 167dfd100f2SMarkus Armbruster addr = g_new0(SocketAddressLegacy, 1); 168935a867cSMarkus Armbruster addr->type = SOCKET_ADDRESS_TYPE_INET; 1693b4482a2SMarc-André Lureau addr->u.inet.data = g_new(InetSocketAddress, 1); 1703b4482a2SMarc-André Lureau *addr->u.inet.data = (InetSocketAddress) { 1713b4482a2SMarc-André Lureau .host = g_strdup(host), 1723b4482a2SMarc-André Lureau .port = g_strdup(port), 1733b4482a2SMarc-André Lureau .has_ipv4 = qemu_opt_get(opts, "ipv4"), 1743b4482a2SMarc-André Lureau .ipv4 = qemu_opt_get_bool(opts, "ipv4", 0), 1753b4482a2SMarc-André Lureau .has_ipv6 = qemu_opt_get(opts, "ipv6"), 1763b4482a2SMarc-André Lureau .ipv6 = qemu_opt_get_bool(opts, "ipv6", 0), 1773b4482a2SMarc-André Lureau }; 1783b4482a2SMarc-André Lureau udp->remote = addr; 1793b4482a2SMarc-André Lureau 1803b4482a2SMarc-André Lureau if (has_local) { 181dfd100f2SMarkus Armbruster addr = g_new0(SocketAddressLegacy, 1); 182935a867cSMarkus Armbruster addr->type = SOCKET_ADDRESS_TYPE_INET; 1833b4482a2SMarc-André Lureau addr->u.inet.data = g_new(InetSocketAddress, 1); 1843b4482a2SMarc-André Lureau *addr->u.inet.data = (InetSocketAddress) { 1853b4482a2SMarc-André Lureau .host = g_strdup(localaddr), 1863b4482a2SMarc-André Lureau .port = g_strdup(localport), 1873b4482a2SMarc-André Lureau }; 1883b4482a2SMarc-André Lureau udp->local = addr; 1893b4482a2SMarc-André Lureau } 1903b4482a2SMarc-André Lureau } 1913b4482a2SMarc-André Lureau 1923b4482a2SMarc-André Lureau static void qmp_chardev_open_udp(Chardev *chr, 1933b4482a2SMarc-André Lureau ChardevBackend *backend, 1943b4482a2SMarc-André Lureau bool *be_opened, 1953b4482a2SMarc-André Lureau Error **errp) 1963b4482a2SMarc-André Lureau { 1973b4482a2SMarc-André Lureau ChardevUdp *udp = backend->u.udp.data; 198bd269ebcSMarkus Armbruster SocketAddress *local_addr = socket_address_flatten(udp->local); 199bd269ebcSMarkus Armbruster SocketAddress *remote_addr = socket_address_flatten(udp->remote); 2003b4482a2SMarc-André Lureau QIOChannelSocket *sioc = qio_channel_socket_new(); 2013b4482a2SMarc-André Lureau char *name; 2023b4482a2SMarc-André Lureau UdpChardev *s = UDP_CHARDEV(chr); 203bd269ebcSMarkus Armbruster int ret; 2043b4482a2SMarc-André Lureau 205bd269ebcSMarkus Armbruster ret = qio_channel_socket_dgram_sync(sioc, local_addr, remote_addr, errp); 206bd269ebcSMarkus Armbruster qapi_free_SocketAddress(local_addr); 207bd269ebcSMarkus Armbruster qapi_free_SocketAddress(remote_addr); 208bd269ebcSMarkus Armbruster if (ret < 0) { 2093b4482a2SMarc-André Lureau object_unref(OBJECT(sioc)); 2103b4482a2SMarc-André Lureau return; 2113b4482a2SMarc-André Lureau } 2123b4482a2SMarc-André Lureau 2133b4482a2SMarc-André Lureau name = g_strdup_printf("chardev-udp-%s", chr->label); 2143b4482a2SMarc-André Lureau qio_channel_set_name(QIO_CHANNEL(sioc), name); 2153b4482a2SMarc-André Lureau g_free(name); 2163b4482a2SMarc-André Lureau 2173b4482a2SMarc-André Lureau s->ioc = QIO_CHANNEL(sioc); 2183b4482a2SMarc-André Lureau /* be isn't opened until we get a connection */ 2193b4482a2SMarc-André Lureau *be_opened = false; 2203b4482a2SMarc-André Lureau } 2213b4482a2SMarc-André Lureau 222*12d1a768SPhilippe Mathieu-Daudé static void char_udp_class_init(ObjectClass *oc, const void *data) 2233b4482a2SMarc-André Lureau { 2243b4482a2SMarc-André Lureau ChardevClass *cc = CHARDEV_CLASS(oc); 2253b4482a2SMarc-André Lureau 2263b4482a2SMarc-André Lureau cc->parse = qemu_chr_parse_udp; 2273b4482a2SMarc-André Lureau cc->open = qmp_chardev_open_udp; 2283b4482a2SMarc-André Lureau cc->chr_write = udp_chr_write; 2293b4482a2SMarc-André Lureau cc->chr_update_read_handler = udp_chr_update_read_handler; 2303b4482a2SMarc-André Lureau } 2313b4482a2SMarc-André Lureau 2323b4482a2SMarc-André Lureau static const TypeInfo char_udp_type_info = { 2333b4482a2SMarc-André Lureau .name = TYPE_CHARDEV_UDP, 2343b4482a2SMarc-André Lureau .parent = TYPE_CHARDEV, 2353b4482a2SMarc-André Lureau .instance_size = sizeof(UdpChardev), 2363b4482a2SMarc-André Lureau .instance_finalize = char_udp_finalize, 2373b4482a2SMarc-André Lureau .class_init = char_udp_class_init, 2383b4482a2SMarc-André Lureau }; 2393b4482a2SMarc-André Lureau 2403b4482a2SMarc-André Lureau static void register_types(void) 2413b4482a2SMarc-André Lureau { 2423b4482a2SMarc-André Lureau type_register_static(&char_udp_type_info); 2433b4482a2SMarc-André Lureau } 2443b4482a2SMarc-André Lureau 2453b4482a2SMarc-André Lureau type_init(register_types); 246