char-udp.c (7263B)
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/module.h" 30#include "qemu/option.h" 31 32#include "chardev/char-io.h" 33#include "qom/object.h" 34 35/***********************************************************/ 36/* UDP Net console */ 37 38struct UdpChardev { 39 Chardev parent; 40 QIOChannel *ioc; 41 uint8_t buf[CHR_READ_BUF_LEN]; 42 int bufcnt; 43 int bufptr; 44 int max_size; 45}; 46typedef struct UdpChardev UdpChardev; 47 48DECLARE_INSTANCE_CHECKER(UdpChardev, UDP_CHARDEV, 49 TYPE_CHARDEV_UDP) 50 51/* Called with chr_write_lock held. */ 52static int udp_chr_write(Chardev *chr, const uint8_t *buf, int len) 53{ 54 UdpChardev *s = UDP_CHARDEV(chr); 55 56 return qio_channel_write( 57 s->ioc, (const char *)buf, len, NULL); 58} 59 60static void udp_chr_flush_buffer(UdpChardev *s) 61{ 62 Chardev *chr = CHARDEV(s); 63 64 while (s->max_size > 0 && s->bufptr < s->bufcnt) { 65 int n = MIN(s->max_size, s->bufcnt - s->bufptr); 66 qemu_chr_be_write(chr, &s->buf[s->bufptr], n); 67 s->bufptr += n; 68 s->max_size = qemu_chr_be_can_write(chr); 69 } 70} 71 72static int udp_chr_read_poll(void *opaque) 73{ 74 Chardev *chr = CHARDEV(opaque); 75 UdpChardev *s = UDP_CHARDEV(opaque); 76 77 s->max_size = qemu_chr_be_can_write(chr); 78 79 /* If there were any stray characters in the queue process them 80 * first 81 */ 82 udp_chr_flush_buffer(s); 83 84 return s->max_size; 85} 86 87static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque) 88{ 89 Chardev *chr = CHARDEV(opaque); 90 UdpChardev *s = UDP_CHARDEV(opaque); 91 ssize_t ret; 92 93 if (s->max_size == 0) { 94 return TRUE; 95 } 96 ret = qio_channel_read( 97 s->ioc, (char *)s->buf, sizeof(s->buf), NULL); 98 if (ret <= 0) { 99 remove_fd_in_watch(chr); 100 return FALSE; 101 } 102 s->bufcnt = ret; 103 s->bufptr = 0; 104 udp_chr_flush_buffer(s); 105 106 return TRUE; 107} 108 109static void udp_chr_update_read_handler(Chardev *chr) 110{ 111 UdpChardev *s = UDP_CHARDEV(chr); 112 113 remove_fd_in_watch(chr); 114 if (s->ioc) { 115 chr->gsource = io_add_watch_poll(chr, s->ioc, 116 udp_chr_read_poll, 117 udp_chr_read, chr, 118 chr->gcontext); 119 } 120} 121 122static void char_udp_finalize(Object *obj) 123{ 124 Chardev *chr = CHARDEV(obj); 125 UdpChardev *s = UDP_CHARDEV(obj); 126 127 remove_fd_in_watch(chr); 128 if (s->ioc) { 129 object_unref(OBJECT(s->ioc)); 130 } 131 qemu_chr_be_event(chr, CHR_EVENT_CLOSED); 132} 133 134static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend, 135 Error **errp) 136{ 137 const char *host = qemu_opt_get(opts, "host"); 138 const char *port = qemu_opt_get(opts, "port"); 139 const char *localaddr = qemu_opt_get(opts, "localaddr"); 140 const char *localport = qemu_opt_get(opts, "localport"); 141 bool has_local = false; 142 SocketAddressLegacy *addr; 143 ChardevUdp *udp; 144 145 backend->type = CHARDEV_BACKEND_KIND_UDP; 146 if (host == NULL || strlen(host) == 0) { 147 host = "localhost"; 148 } 149 if (port == NULL || strlen(port) == 0) { 150 error_setg(errp, "chardev: udp: remote port not specified"); 151 return; 152 } 153 if (localport == NULL || strlen(localport) == 0) { 154 localport = "0"; 155 } else { 156 has_local = true; 157 } 158 if (localaddr == NULL || strlen(localaddr) == 0) { 159 localaddr = ""; 160 } else { 161 has_local = true; 162 } 163 164 udp = backend->u.udp.data = g_new0(ChardevUdp, 1); 165 qemu_chr_parse_common(opts, qapi_ChardevUdp_base(udp)); 166 167 addr = g_new0(SocketAddressLegacy, 1); 168 addr->type = SOCKET_ADDRESS_TYPE_INET; 169 addr->u.inet.data = g_new(InetSocketAddress, 1); 170 *addr->u.inet.data = (InetSocketAddress) { 171 .host = g_strdup(host), 172 .port = g_strdup(port), 173 .has_ipv4 = qemu_opt_get(opts, "ipv4"), 174 .ipv4 = qemu_opt_get_bool(opts, "ipv4", 0), 175 .has_ipv6 = qemu_opt_get(opts, "ipv6"), 176 .ipv6 = qemu_opt_get_bool(opts, "ipv6", 0), 177 }; 178 udp->remote = addr; 179 180 if (has_local) { 181 udp->has_local = true; 182 addr = g_new0(SocketAddressLegacy, 1); 183 addr->type = SOCKET_ADDRESS_TYPE_INET; 184 addr->u.inet.data = g_new(InetSocketAddress, 1); 185 *addr->u.inet.data = (InetSocketAddress) { 186 .host = g_strdup(localaddr), 187 .port = g_strdup(localport), 188 }; 189 udp->local = addr; 190 } 191} 192 193static void qmp_chardev_open_udp(Chardev *chr, 194 ChardevBackend *backend, 195 bool *be_opened, 196 Error **errp) 197{ 198 ChardevUdp *udp = backend->u.udp.data; 199 SocketAddress *local_addr = socket_address_flatten(udp->local); 200 SocketAddress *remote_addr = socket_address_flatten(udp->remote); 201 QIOChannelSocket *sioc = qio_channel_socket_new(); 202 char *name; 203 UdpChardev *s = UDP_CHARDEV(chr); 204 int ret; 205 206 ret = qio_channel_socket_dgram_sync(sioc, local_addr, remote_addr, errp); 207 qapi_free_SocketAddress(local_addr); 208 qapi_free_SocketAddress(remote_addr); 209 if (ret < 0) { 210 object_unref(OBJECT(sioc)); 211 return; 212 } 213 214 name = g_strdup_printf("chardev-udp-%s", chr->label); 215 qio_channel_set_name(QIO_CHANNEL(sioc), name); 216 g_free(name); 217 218 s->ioc = QIO_CHANNEL(sioc); 219 /* be isn't opened until we get a connection */ 220 *be_opened = false; 221} 222 223static void char_udp_class_init(ObjectClass *oc, void *data) 224{ 225 ChardevClass *cc = CHARDEV_CLASS(oc); 226 227 cc->parse = qemu_chr_parse_udp; 228 cc->open = qmp_chardev_open_udp; 229 cc->chr_write = udp_chr_write; 230 cc->chr_update_read_handler = udp_chr_update_read_handler; 231} 232 233static const TypeInfo char_udp_type_info = { 234 .name = TYPE_CHARDEV_UDP, 235 .parent = TYPE_CHARDEV, 236 .instance_size = sizeof(UdpChardev), 237 .instance_finalize = char_udp_finalize, 238 .class_init = char_udp_class_init, 239}; 240 241static void register_types(void) 242{ 243 type_register_static(&char_udp_type_info); 244} 245 246type_init(register_types);