1 /* 2 * QEMU network listener 3 * 4 * Copyright (c) 2016-2017 Red Hat, Inc. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License along 17 * with this program; if not, see <http://www.gnu.org/licenses/>. 18 * 19 */ 20 21 #include "qemu/osdep.h" 22 #include "io/net-listener.h" 23 #include "io/dns-resolver.h" 24 #include "qapi/error.h" 25 #include "qemu/module.h" 26 #include "qemu/lockable.h" 27 #include "trace.h" 28 29 QIONetListener *qio_net_listener_new(void) 30 { 31 QIONetListener *listener; 32 33 listener = QIO_NET_LISTENER(object_new(TYPE_QIO_NET_LISTENER)); 34 qemu_mutex_init(&listener->lock); 35 return listener; 36 } 37 38 void qio_net_listener_set_name(QIONetListener *listener, 39 const char *name) 40 { 41 g_free(listener->name); 42 listener->name = g_strdup(name); 43 } 44 45 46 static gboolean qio_net_listener_channel_func(QIOChannel *ioc, 47 GIOCondition condition, 48 gpointer opaque) 49 { 50 QIONetListener *listener = QIO_NET_LISTENER(opaque); 51 QIOChannelSocket *sioc; 52 QIONetListenerClientFunc io_func; 53 gpointer io_data; 54 GMainContext *context; 55 56 sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc), 57 NULL); 58 if (!sioc) { 59 return TRUE; 60 } 61 62 WITH_QEMU_LOCK_GUARD(&listener->lock) { 63 io_func = listener->io_func; 64 io_data = listener->io_data; 65 context = listener->context; 66 } 67 68 trace_qio_net_listener_callback(listener, io_func, context); 69 if (io_func) { 70 io_func(listener, sioc, io_data); 71 } 72 73 object_unref(OBJECT(sioc)); 74 75 return TRUE; 76 } 77 78 79 int qio_net_listener_open_sync(QIONetListener *listener, 80 SocketAddress *addr, 81 int num, 82 Error **errp) 83 { 84 QIODNSResolver *resolver = qio_dns_resolver_get_instance(); 85 SocketAddress **resaddrs; 86 size_t nresaddrs; 87 size_t i; 88 Error *err = NULL; 89 bool success = false; 90 91 if (qio_dns_resolver_lookup_sync(resolver, 92 addr, 93 &nresaddrs, 94 &resaddrs, 95 errp) < 0) { 96 return -1; 97 } 98 99 for (i = 0; i < nresaddrs; i++) { 100 QIOChannelSocket *sioc = qio_channel_socket_new(); 101 102 if (qio_channel_socket_listen_sync(sioc, resaddrs[i], num, 103 err ? NULL : &err) == 0) { 104 success = true; 105 106 qio_net_listener_add(listener, sioc); 107 } 108 109 qapi_free_SocketAddress(resaddrs[i]); 110 object_unref(OBJECT(sioc)); 111 } 112 g_free(resaddrs); 113 114 if (success) { 115 error_free(err); 116 return 0; 117 } else { 118 error_propagate(errp, err); 119 return -1; 120 } 121 } 122 123 124 void qio_net_listener_add(QIONetListener *listener, 125 QIOChannelSocket *sioc) 126 { 127 QIONetListenerClientFunc io_func; 128 GMainContext *context; 129 130 if (listener->name) { 131 qio_channel_set_name(QIO_CHANNEL(sioc), listener->name); 132 } 133 134 listener->sioc = g_renew(QIOChannelSocket *, listener->sioc, 135 listener->nsioc + 1); 136 listener->io_source = g_renew(typeof(listener->io_source[0]), 137 listener->io_source, 138 listener->nsioc + 1); 139 listener->sioc[listener->nsioc] = sioc; 140 listener->io_source[listener->nsioc] = NULL; 141 142 object_ref(OBJECT(sioc)); 143 listener->connected = true; 144 145 WITH_QEMU_LOCK_GUARD(&listener->lock) { 146 io_func = listener->io_func; 147 context = listener->context; 148 } 149 150 trace_qio_net_listener_watch(listener, io_func, context, "add"); 151 if (io_func) { 152 object_ref(OBJECT(listener)); 153 listener->io_source[listener->nsioc] = qio_channel_add_watch_source( 154 QIO_CHANNEL(listener->sioc[listener->nsioc]), G_IO_IN, 155 qio_net_listener_channel_func, 156 listener, (GDestroyNotify)object_unref, context); 157 } 158 159 listener->nsioc++; 160 } 161 162 163 void qio_net_listener_set_client_func_full(QIONetListener *listener, 164 QIONetListenerClientFunc func, 165 gpointer data, 166 GDestroyNotify notify, 167 GMainContext *context) 168 { 169 size_t i; 170 171 QEMU_LOCK_GUARD(&listener->lock); 172 trace_qio_net_listener_unwatch(listener, listener->io_func, 173 listener->context, "set_client_func"); 174 175 for (i = 0; i < listener->nsioc; i++) { 176 if (listener->io_source[i]) { 177 g_source_destroy(listener->io_source[i]); 178 g_source_unref(listener->io_source[i]); 179 listener->io_source[i] = NULL; 180 } 181 } 182 183 if (listener->io_notify) { 184 listener->io_notify(listener->io_data); 185 } 186 listener->io_func = func; 187 listener->io_data = data; 188 listener->io_notify = notify; 189 listener->context = context; 190 191 trace_qio_net_listener_watch(listener, listener->io_func, 192 listener->context, "set_client_func"); 193 if (listener->io_func != NULL) { 194 for (i = 0; i < listener->nsioc; i++) { 195 object_ref(OBJECT(listener)); 196 listener->io_source[i] = qio_channel_add_watch_source( 197 QIO_CHANNEL(listener->sioc[i]), G_IO_IN, 198 qio_net_listener_channel_func, 199 listener, (GDestroyNotify)object_unref, context); 200 } 201 } 202 } 203 204 void qio_net_listener_set_client_func(QIONetListener *listener, 205 QIONetListenerClientFunc func, 206 gpointer data, 207 GDestroyNotify notify) 208 { 209 qio_net_listener_set_client_func_full(listener, func, data, 210 notify, NULL); 211 } 212 213 struct QIONetListenerClientWaitData { 214 QIOChannelSocket *sioc; 215 GMainLoop *loop; 216 }; 217 218 219 static gboolean qio_net_listener_wait_client_func(QIOChannel *ioc, 220 GIOCondition condition, 221 gpointer opaque) 222 { 223 struct QIONetListenerClientWaitData *data = opaque; 224 QIOChannelSocket *sioc; 225 226 sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc), 227 NULL); 228 if (!sioc) { 229 return TRUE; 230 } 231 232 if (data->sioc) { 233 object_unref(OBJECT(sioc)); 234 } else { 235 data->sioc = sioc; 236 g_main_loop_quit(data->loop); 237 } 238 239 return TRUE; 240 } 241 242 QIOChannelSocket *qio_net_listener_wait_client(QIONetListener *listener) 243 { 244 GMainContext *ctxt = g_main_context_new(); 245 GMainLoop *loop = g_main_loop_new(ctxt, TRUE); 246 GSource **sources; 247 struct QIONetListenerClientWaitData data = { 248 .sioc = NULL, 249 .loop = loop 250 }; 251 size_t i; 252 QIONetListenerClientFunc io_func; 253 GMainContext *context; 254 255 WITH_QEMU_LOCK_GUARD(&listener->lock) { 256 io_func = listener->io_func; 257 context = listener->context; 258 } 259 260 trace_qio_net_listener_unwatch(listener, io_func, context, "wait_client"); 261 for (i = 0; i < listener->nsioc; i++) { 262 if (listener->io_source[i]) { 263 g_source_destroy(listener->io_source[i]); 264 g_source_unref(listener->io_source[i]); 265 listener->io_source[i] = NULL; 266 } 267 } 268 269 sources = g_new0(GSource *, listener->nsioc); 270 for (i = 0; i < listener->nsioc; i++) { 271 sources[i] = qio_channel_create_watch(QIO_CHANNEL(listener->sioc[i]), 272 G_IO_IN); 273 274 g_source_set_callback(sources[i], 275 (GSourceFunc)qio_net_listener_wait_client_func, 276 &data, 277 NULL); 278 g_source_attach(sources[i], ctxt); 279 } 280 281 g_main_loop_run(loop); 282 283 for (i = 0; i < listener->nsioc; i++) { 284 g_source_unref(sources[i]); 285 } 286 g_free(sources); 287 g_main_loop_unref(loop); 288 g_main_context_unref(ctxt); 289 290 trace_qio_net_listener_watch(listener, io_func, context, "wait_client"); 291 if (io_func != NULL) { 292 for (i = 0; i < listener->nsioc; i++) { 293 object_ref(OBJECT(listener)); 294 listener->io_source[i] = qio_channel_add_watch_source( 295 QIO_CHANNEL(listener->sioc[i]), G_IO_IN, 296 qio_net_listener_channel_func, 297 listener, (GDestroyNotify)object_unref, context); 298 } 299 } 300 301 return data.sioc; 302 } 303 304 void qio_net_listener_disconnect(QIONetListener *listener) 305 { 306 size_t i; 307 308 if (!listener->connected) { 309 return; 310 } 311 312 QEMU_LOCK_GUARD(&listener->lock); 313 trace_qio_net_listener_unwatch(listener, listener->io_func, 314 listener->context, "disconnect"); 315 for (i = 0; i < listener->nsioc; i++) { 316 if (listener->io_source[i]) { 317 g_source_destroy(listener->io_source[i]); 318 g_source_unref(listener->io_source[i]); 319 listener->io_source[i] = NULL; 320 } 321 qio_channel_close(QIO_CHANNEL(listener->sioc[i]), NULL); 322 } 323 listener->connected = false; 324 } 325 326 327 bool qio_net_listener_is_connected(QIONetListener *listener) 328 { 329 return listener->connected; 330 } 331 332 static void qio_net_listener_finalize(Object *obj) 333 { 334 QIONetListener *listener = QIO_NET_LISTENER(obj); 335 size_t i; 336 337 qio_net_listener_disconnect(listener); 338 if (listener->io_notify) { 339 listener->io_notify(listener->io_data); 340 } 341 342 for (i = 0; i < listener->nsioc; i++) { 343 object_unref(OBJECT(listener->sioc[i])); 344 } 345 g_free(listener->io_source); 346 g_free(listener->sioc); 347 g_free(listener->name); 348 qemu_mutex_destroy(&listener->lock); 349 } 350 351 static const TypeInfo qio_net_listener_info = { 352 .parent = TYPE_OBJECT, 353 .name = TYPE_QIO_NET_LISTENER, 354 .instance_size = sizeof(QIONetListener), 355 .instance_finalize = qio_net_listener_finalize, 356 }; 357 358 359 static void qio_net_listener_register_types(void) 360 { 361 type_register_static(&qio_net_listener_info); 362 } 363 364 365 type_init(qio_net_listener_register_types); 366