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