1*3b4482a2SMarc-André Lureau /* 2*3b4482a2SMarc-André Lureau * QEMU System Emulator 3*3b4482a2SMarc-André Lureau * 4*3b4482a2SMarc-André Lureau * Copyright (c) 2003-2008 Fabrice Bellard 5*3b4482a2SMarc-André Lureau * 6*3b4482a2SMarc-André Lureau * Permission is hereby granted, free of charge, to any person obtaining a copy 7*3b4482a2SMarc-André Lureau * of this software and associated documentation files (the "Software"), to deal 8*3b4482a2SMarc-André Lureau * in the Software without restriction, including without limitation the rights 9*3b4482a2SMarc-André Lureau * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10*3b4482a2SMarc-André Lureau * copies of the Software, and to permit persons to whom the Software is 11*3b4482a2SMarc-André Lureau * furnished to do so, subject to the following conditions: 12*3b4482a2SMarc-André Lureau * 13*3b4482a2SMarc-André Lureau * The above copyright notice and this permission notice shall be included in 14*3b4482a2SMarc-André Lureau * all copies or substantial portions of the Software. 15*3b4482a2SMarc-André Lureau * 16*3b4482a2SMarc-André Lureau * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17*3b4482a2SMarc-André Lureau * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18*3b4482a2SMarc-André Lureau * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19*3b4482a2SMarc-André Lureau * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20*3b4482a2SMarc-André Lureau * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21*3b4482a2SMarc-André Lureau * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22*3b4482a2SMarc-André Lureau * THE SOFTWARE. 23*3b4482a2SMarc-André Lureau */ 24*3b4482a2SMarc-André Lureau #include "qemu/osdep.h" 25*3b4482a2SMarc-André Lureau #include "sysemu/char.h" 26*3b4482a2SMarc-André Lureau #include "io/channel-socket.h" 27*3b4482a2SMarc-André Lureau #include "qapi/error.h" 28*3b4482a2SMarc-André Lureau 29*3b4482a2SMarc-André Lureau #include "char-io.h" 30*3b4482a2SMarc-André Lureau 31*3b4482a2SMarc-André Lureau /***********************************************************/ 32*3b4482a2SMarc-André Lureau /* UDP Net console */ 33*3b4482a2SMarc-André Lureau 34*3b4482a2SMarc-André Lureau typedef struct { 35*3b4482a2SMarc-André Lureau Chardev parent; 36*3b4482a2SMarc-André Lureau QIOChannel *ioc; 37*3b4482a2SMarc-André Lureau uint8_t buf[CHR_READ_BUF_LEN]; 38*3b4482a2SMarc-André Lureau int bufcnt; 39*3b4482a2SMarc-André Lureau int bufptr; 40*3b4482a2SMarc-André Lureau int max_size; 41*3b4482a2SMarc-André Lureau } UdpChardev; 42*3b4482a2SMarc-André Lureau 43*3b4482a2SMarc-André Lureau #define UDP_CHARDEV(obj) OBJECT_CHECK(UdpChardev, (obj), TYPE_CHARDEV_UDP) 44*3b4482a2SMarc-André Lureau 45*3b4482a2SMarc-André Lureau /* Called with chr_write_lock held. */ 46*3b4482a2SMarc-André Lureau static int udp_chr_write(Chardev *chr, const uint8_t *buf, int len) 47*3b4482a2SMarc-André Lureau { 48*3b4482a2SMarc-André Lureau UdpChardev *s = UDP_CHARDEV(chr); 49*3b4482a2SMarc-André Lureau 50*3b4482a2SMarc-André Lureau return qio_channel_write( 51*3b4482a2SMarc-André Lureau s->ioc, (const char *)buf, len, NULL); 52*3b4482a2SMarc-André Lureau } 53*3b4482a2SMarc-André Lureau 54*3b4482a2SMarc-André Lureau static int udp_chr_read_poll(void *opaque) 55*3b4482a2SMarc-André Lureau { 56*3b4482a2SMarc-André Lureau Chardev *chr = CHARDEV(opaque); 57*3b4482a2SMarc-André Lureau UdpChardev *s = UDP_CHARDEV(opaque); 58*3b4482a2SMarc-André Lureau 59*3b4482a2SMarc-André Lureau s->max_size = qemu_chr_be_can_write(chr); 60*3b4482a2SMarc-André Lureau 61*3b4482a2SMarc-André Lureau /* If there were any stray characters in the queue process them 62*3b4482a2SMarc-André Lureau * first 63*3b4482a2SMarc-André Lureau */ 64*3b4482a2SMarc-André Lureau while (s->max_size > 0 && s->bufptr < s->bufcnt) { 65*3b4482a2SMarc-André Lureau qemu_chr_be_write(chr, &s->buf[s->bufptr], 1); 66*3b4482a2SMarc-André Lureau s->bufptr++; 67*3b4482a2SMarc-André Lureau s->max_size = qemu_chr_be_can_write(chr); 68*3b4482a2SMarc-André Lureau } 69*3b4482a2SMarc-André Lureau return s->max_size; 70*3b4482a2SMarc-André Lureau } 71*3b4482a2SMarc-André Lureau 72*3b4482a2SMarc-André Lureau static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque) 73*3b4482a2SMarc-André Lureau { 74*3b4482a2SMarc-André Lureau Chardev *chr = CHARDEV(opaque); 75*3b4482a2SMarc-André Lureau UdpChardev *s = UDP_CHARDEV(opaque); 76*3b4482a2SMarc-André Lureau ssize_t ret; 77*3b4482a2SMarc-André Lureau 78*3b4482a2SMarc-André Lureau if (s->max_size == 0) { 79*3b4482a2SMarc-André Lureau return TRUE; 80*3b4482a2SMarc-André Lureau } 81*3b4482a2SMarc-André Lureau ret = qio_channel_read( 82*3b4482a2SMarc-André Lureau s->ioc, (char *)s->buf, sizeof(s->buf), NULL); 83*3b4482a2SMarc-André Lureau if (ret <= 0) { 84*3b4482a2SMarc-André Lureau remove_fd_in_watch(chr); 85*3b4482a2SMarc-André Lureau return FALSE; 86*3b4482a2SMarc-André Lureau } 87*3b4482a2SMarc-André Lureau s->bufcnt = ret; 88*3b4482a2SMarc-André Lureau 89*3b4482a2SMarc-André Lureau s->bufptr = 0; 90*3b4482a2SMarc-André Lureau while (s->max_size > 0 && s->bufptr < s->bufcnt) { 91*3b4482a2SMarc-André Lureau qemu_chr_be_write(chr, &s->buf[s->bufptr], 1); 92*3b4482a2SMarc-André Lureau s->bufptr++; 93*3b4482a2SMarc-André Lureau s->max_size = qemu_chr_be_can_write(chr); 94*3b4482a2SMarc-André Lureau } 95*3b4482a2SMarc-André Lureau 96*3b4482a2SMarc-André Lureau return TRUE; 97*3b4482a2SMarc-André Lureau } 98*3b4482a2SMarc-André Lureau 99*3b4482a2SMarc-André Lureau static void udp_chr_update_read_handler(Chardev *chr, 100*3b4482a2SMarc-André Lureau GMainContext *context) 101*3b4482a2SMarc-André Lureau { 102*3b4482a2SMarc-André Lureau UdpChardev *s = UDP_CHARDEV(chr); 103*3b4482a2SMarc-André Lureau 104*3b4482a2SMarc-André Lureau remove_fd_in_watch(chr); 105*3b4482a2SMarc-André Lureau if (s->ioc) { 106*3b4482a2SMarc-André Lureau chr->fd_in_tag = io_add_watch_poll(chr, s->ioc, 107*3b4482a2SMarc-André Lureau udp_chr_read_poll, 108*3b4482a2SMarc-André Lureau udp_chr_read, chr, 109*3b4482a2SMarc-André Lureau context); 110*3b4482a2SMarc-André Lureau } 111*3b4482a2SMarc-André Lureau } 112*3b4482a2SMarc-André Lureau 113*3b4482a2SMarc-André Lureau static void char_udp_finalize(Object *obj) 114*3b4482a2SMarc-André Lureau { 115*3b4482a2SMarc-André Lureau Chardev *chr = CHARDEV(obj); 116*3b4482a2SMarc-André Lureau UdpChardev *s = UDP_CHARDEV(obj); 117*3b4482a2SMarc-André Lureau 118*3b4482a2SMarc-André Lureau remove_fd_in_watch(chr); 119*3b4482a2SMarc-André Lureau if (s->ioc) { 120*3b4482a2SMarc-André Lureau object_unref(OBJECT(s->ioc)); 121*3b4482a2SMarc-André Lureau } 122*3b4482a2SMarc-André Lureau qemu_chr_be_event(chr, CHR_EVENT_CLOSED); 123*3b4482a2SMarc-André Lureau } 124*3b4482a2SMarc-André Lureau 125*3b4482a2SMarc-André Lureau static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend, 126*3b4482a2SMarc-André Lureau Error **errp) 127*3b4482a2SMarc-André Lureau { 128*3b4482a2SMarc-André Lureau const char *host = qemu_opt_get(opts, "host"); 129*3b4482a2SMarc-André Lureau const char *port = qemu_opt_get(opts, "port"); 130*3b4482a2SMarc-André Lureau const char *localaddr = qemu_opt_get(opts, "localaddr"); 131*3b4482a2SMarc-André Lureau const char *localport = qemu_opt_get(opts, "localport"); 132*3b4482a2SMarc-André Lureau bool has_local = false; 133*3b4482a2SMarc-André Lureau SocketAddress *addr; 134*3b4482a2SMarc-André Lureau ChardevUdp *udp; 135*3b4482a2SMarc-André Lureau 136*3b4482a2SMarc-André Lureau backend->type = CHARDEV_BACKEND_KIND_UDP; 137*3b4482a2SMarc-André Lureau if (host == NULL || strlen(host) == 0) { 138*3b4482a2SMarc-André Lureau host = "localhost"; 139*3b4482a2SMarc-André Lureau } 140*3b4482a2SMarc-André Lureau if (port == NULL || strlen(port) == 0) { 141*3b4482a2SMarc-André Lureau error_setg(errp, "chardev: udp: remote port not specified"); 142*3b4482a2SMarc-André Lureau return; 143*3b4482a2SMarc-André Lureau } 144*3b4482a2SMarc-André Lureau if (localport == NULL || strlen(localport) == 0) { 145*3b4482a2SMarc-André Lureau localport = "0"; 146*3b4482a2SMarc-André Lureau } else { 147*3b4482a2SMarc-André Lureau has_local = true; 148*3b4482a2SMarc-André Lureau } 149*3b4482a2SMarc-André Lureau if (localaddr == NULL || strlen(localaddr) == 0) { 150*3b4482a2SMarc-André Lureau localaddr = ""; 151*3b4482a2SMarc-André Lureau } else { 152*3b4482a2SMarc-André Lureau has_local = true; 153*3b4482a2SMarc-André Lureau } 154*3b4482a2SMarc-André Lureau 155*3b4482a2SMarc-André Lureau udp = backend->u.udp.data = g_new0(ChardevUdp, 1); 156*3b4482a2SMarc-André Lureau qemu_chr_parse_common(opts, qapi_ChardevUdp_base(udp)); 157*3b4482a2SMarc-André Lureau 158*3b4482a2SMarc-André Lureau addr = g_new0(SocketAddress, 1); 159*3b4482a2SMarc-André Lureau addr->type = SOCKET_ADDRESS_KIND_INET; 160*3b4482a2SMarc-André Lureau addr->u.inet.data = g_new(InetSocketAddress, 1); 161*3b4482a2SMarc-André Lureau *addr->u.inet.data = (InetSocketAddress) { 162*3b4482a2SMarc-André Lureau .host = g_strdup(host), 163*3b4482a2SMarc-André Lureau .port = g_strdup(port), 164*3b4482a2SMarc-André Lureau .has_ipv4 = qemu_opt_get(opts, "ipv4"), 165*3b4482a2SMarc-André Lureau .ipv4 = qemu_opt_get_bool(opts, "ipv4", 0), 166*3b4482a2SMarc-André Lureau .has_ipv6 = qemu_opt_get(opts, "ipv6"), 167*3b4482a2SMarc-André Lureau .ipv6 = qemu_opt_get_bool(opts, "ipv6", 0), 168*3b4482a2SMarc-André Lureau }; 169*3b4482a2SMarc-André Lureau udp->remote = addr; 170*3b4482a2SMarc-André Lureau 171*3b4482a2SMarc-André Lureau if (has_local) { 172*3b4482a2SMarc-André Lureau udp->has_local = true; 173*3b4482a2SMarc-André Lureau addr = g_new0(SocketAddress, 1); 174*3b4482a2SMarc-André Lureau addr->type = SOCKET_ADDRESS_KIND_INET; 175*3b4482a2SMarc-André Lureau addr->u.inet.data = g_new(InetSocketAddress, 1); 176*3b4482a2SMarc-André Lureau *addr->u.inet.data = (InetSocketAddress) { 177*3b4482a2SMarc-André Lureau .host = g_strdup(localaddr), 178*3b4482a2SMarc-André Lureau .port = g_strdup(localport), 179*3b4482a2SMarc-André Lureau }; 180*3b4482a2SMarc-André Lureau udp->local = addr; 181*3b4482a2SMarc-André Lureau } 182*3b4482a2SMarc-André Lureau } 183*3b4482a2SMarc-André Lureau 184*3b4482a2SMarc-André Lureau static void qmp_chardev_open_udp(Chardev *chr, 185*3b4482a2SMarc-André Lureau ChardevBackend *backend, 186*3b4482a2SMarc-André Lureau bool *be_opened, 187*3b4482a2SMarc-André Lureau Error **errp) 188*3b4482a2SMarc-André Lureau { 189*3b4482a2SMarc-André Lureau ChardevUdp *udp = backend->u.udp.data; 190*3b4482a2SMarc-André Lureau QIOChannelSocket *sioc = qio_channel_socket_new(); 191*3b4482a2SMarc-André Lureau char *name; 192*3b4482a2SMarc-André Lureau UdpChardev *s = UDP_CHARDEV(chr); 193*3b4482a2SMarc-André Lureau 194*3b4482a2SMarc-André Lureau if (qio_channel_socket_dgram_sync(sioc, 195*3b4482a2SMarc-André Lureau udp->local, udp->remote, 196*3b4482a2SMarc-André Lureau errp) < 0) { 197*3b4482a2SMarc-André Lureau object_unref(OBJECT(sioc)); 198*3b4482a2SMarc-André Lureau return; 199*3b4482a2SMarc-André Lureau } 200*3b4482a2SMarc-André Lureau 201*3b4482a2SMarc-André Lureau name = g_strdup_printf("chardev-udp-%s", chr->label); 202*3b4482a2SMarc-André Lureau qio_channel_set_name(QIO_CHANNEL(sioc), name); 203*3b4482a2SMarc-André Lureau g_free(name); 204*3b4482a2SMarc-André Lureau 205*3b4482a2SMarc-André Lureau s->ioc = QIO_CHANNEL(sioc); 206*3b4482a2SMarc-André Lureau /* be isn't opened until we get a connection */ 207*3b4482a2SMarc-André Lureau *be_opened = false; 208*3b4482a2SMarc-André Lureau } 209*3b4482a2SMarc-André Lureau 210*3b4482a2SMarc-André Lureau static void char_udp_class_init(ObjectClass *oc, void *data) 211*3b4482a2SMarc-André Lureau { 212*3b4482a2SMarc-André Lureau ChardevClass *cc = CHARDEV_CLASS(oc); 213*3b4482a2SMarc-André Lureau 214*3b4482a2SMarc-André Lureau cc->parse = qemu_chr_parse_udp; 215*3b4482a2SMarc-André Lureau cc->open = qmp_chardev_open_udp; 216*3b4482a2SMarc-André Lureau cc->chr_write = udp_chr_write; 217*3b4482a2SMarc-André Lureau cc->chr_update_read_handler = udp_chr_update_read_handler; 218*3b4482a2SMarc-André Lureau } 219*3b4482a2SMarc-André Lureau 220*3b4482a2SMarc-André Lureau static const TypeInfo char_udp_type_info = { 221*3b4482a2SMarc-André Lureau .name = TYPE_CHARDEV_UDP, 222*3b4482a2SMarc-André Lureau .parent = TYPE_CHARDEV, 223*3b4482a2SMarc-André Lureau .instance_size = sizeof(UdpChardev), 224*3b4482a2SMarc-André Lureau .instance_finalize = char_udp_finalize, 225*3b4482a2SMarc-André Lureau .class_init = char_udp_class_init, 226*3b4482a2SMarc-André Lureau }; 227*3b4482a2SMarc-André Lureau 228*3b4482a2SMarc-André Lureau static void register_types(void) 229*3b4482a2SMarc-André Lureau { 230*3b4482a2SMarc-André Lureau type_register_static(&char_udp_type_info); 231*3b4482a2SMarc-André Lureau } 232*3b4482a2SMarc-André Lureau 233*3b4482a2SMarc-André Lureau type_init(register_types); 234