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 27 QIONetListener *qio_net_listener_new(void) 28 { 29 return QIO_NET_LISTENER(object_new(TYPE_QIO_NET_LISTENER)); 30 } 31 32 void qio_net_listener_set_name(QIONetListener *listener, 33 const char *name) 34 { 35 g_free(listener->name); 36 listener->name = g_strdup(name); 37 } 38 39 40 static gboolean qio_net_listener_channel_func(QIOChannel *ioc, 41 GIOCondition condition, 42 gpointer opaque) 43 { 44 QIONetListener *listener = QIO_NET_LISTENER(opaque); 45 QIOChannelSocket *sioc; 46 47 sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc), 48 NULL); 49 if (!sioc) { 50 return TRUE; 51 } 52 53 if (listener->io_func) { 54 listener->io_func(listener, sioc, listener->io_data); 55 } 56 57 object_unref(OBJECT(sioc)); 58 59 return TRUE; 60 } 61 62 63 int qio_net_listener_open_sync(QIONetListener *listener, 64 SocketAddress *addr, 65 int num, 66 Error **errp) 67 { 68 QIODNSResolver *resolver = qio_dns_resolver_get_instance(); 69 SocketAddress **resaddrs; 70 size_t nresaddrs; 71 size_t i; 72 Error *err = NULL; 73 bool success = false; 74 75 if (qio_dns_resolver_lookup_sync(resolver, 76 addr, 77 &nresaddrs, 78 &resaddrs, 79 errp) < 0) { 80 return -1; 81 } 82 83 for (i = 0; i < nresaddrs; i++) { 84 QIOChannelSocket *sioc = qio_channel_socket_new(); 85 86 if (qio_channel_socket_listen_sync(sioc, resaddrs[i], num, 87 err ? NULL : &err) == 0) { 88 success = true; 89 90 qio_net_listener_add(listener, sioc); 91 } 92 93 qapi_free_SocketAddress(resaddrs[i]); 94 object_unref(OBJECT(sioc)); 95 } 96 g_free(resaddrs); 97 98 if (success) { 99 error_free(err); 100 return 0; 101 } else { 102 error_propagate(errp, err); 103 return -1; 104 } 105 } 106 107 108 void qio_net_listener_add(QIONetListener *listener, 109 QIOChannelSocket *sioc) 110 { 111 if (listener->name) { 112 qio_channel_set_name(QIO_CHANNEL(sioc), listener->name); 113 } 114 115 listener->sioc = g_renew(QIOChannelSocket *, listener->sioc, 116 listener->nsioc + 1); 117 listener->io_source = g_renew(typeof(listener->io_source[0]), 118 listener->io_source, 119 listener->nsioc + 1); 120 listener->sioc[listener->nsioc] = sioc; 121 listener->io_source[listener->nsioc] = NULL; 122 123 object_ref(OBJECT(sioc)); 124 listener->connected = true; 125 126 if (listener->io_func != NULL) { 127 object_ref(OBJECT(listener)); 128 listener->io_source[listener->nsioc] = qio_channel_add_watch_source( 129 QIO_CHANNEL(listener->sioc[listener->nsioc]), G_IO_IN, 130 qio_net_listener_channel_func, 131 listener, (GDestroyNotify)object_unref, NULL); 132 } 133 134 listener->nsioc++; 135 } 136 137 138 void qio_net_listener_set_client_func_full(QIONetListener *listener, 139 QIONetListenerClientFunc func, 140 gpointer data, 141 GDestroyNotify notify, 142 GMainContext *context) 143 { 144 size_t i; 145 146 if (listener->io_notify) { 147 listener->io_notify(listener->io_data); 148 } 149 listener->io_func = func; 150 listener->io_data = data; 151 listener->io_notify = notify; 152 153 for (i = 0; i < listener->nsioc; i++) { 154 if (listener->io_source[i]) { 155 g_source_destroy(listener->io_source[i]); 156 g_source_unref(listener->io_source[i]); 157 listener->io_source[i] = NULL; 158 } 159 } 160 161 if (listener->io_func != NULL) { 162 for (i = 0; i < listener->nsioc; i++) { 163 object_ref(OBJECT(listener)); 164 listener->io_source[i] = qio_channel_add_watch_source( 165 QIO_CHANNEL(listener->sioc[i]), G_IO_IN, 166 qio_net_listener_channel_func, 167 listener, (GDestroyNotify)object_unref, context); 168 } 169 } 170 } 171 172 void qio_net_listener_set_client_func(QIONetListener *listener, 173 QIONetListenerClientFunc func, 174 gpointer data, 175 GDestroyNotify notify) 176 { 177 qio_net_listener_set_client_func_full(listener, func, data, 178 notify, NULL); 179 } 180 181 struct QIONetListenerClientWaitData { 182 QIOChannelSocket *sioc; 183 GMainLoop *loop; 184 }; 185 186 187 static gboolean qio_net_listener_wait_client_func(QIOChannel *ioc, 188 GIOCondition condition, 189 gpointer opaque) 190 { 191 struct QIONetListenerClientWaitData *data = opaque; 192 QIOChannelSocket *sioc; 193 194 sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc), 195 NULL); 196 if (!sioc) { 197 return TRUE; 198 } 199 200 if (data->sioc) { 201 object_unref(OBJECT(sioc)); 202 } else { 203 data->sioc = sioc; 204 g_main_loop_quit(data->loop); 205 } 206 207 return TRUE; 208 } 209 210 QIOChannelSocket *qio_net_listener_wait_client(QIONetListener *listener) 211 { 212 GMainContext *ctxt = g_main_context_new(); 213 GMainLoop *loop = g_main_loop_new(ctxt, TRUE); 214 GSource **sources; 215 struct QIONetListenerClientWaitData data = { 216 .sioc = NULL, 217 .loop = loop 218 }; 219 size_t i; 220 221 for (i = 0; i < listener->nsioc; i++) { 222 if (listener->io_source[i]) { 223 g_source_destroy(listener->io_source[i]); 224 g_source_unref(listener->io_source[i]); 225 listener->io_source[i] = NULL; 226 } 227 } 228 229 sources = g_new0(GSource *, listener->nsioc); 230 for (i = 0; i < listener->nsioc; i++) { 231 sources[i] = qio_channel_create_watch(QIO_CHANNEL(listener->sioc[i]), 232 G_IO_IN); 233 234 g_source_set_callback(sources[i], 235 (GSourceFunc)qio_net_listener_wait_client_func, 236 &data, 237 NULL); 238 g_source_attach(sources[i], ctxt); 239 } 240 241 g_main_loop_run(loop); 242 243 for (i = 0; i < listener->nsioc; i++) { 244 g_source_unref(sources[i]); 245 } 246 g_free(sources); 247 g_main_loop_unref(loop); 248 g_main_context_unref(ctxt); 249 250 if (listener->io_func != NULL) { 251 for (i = 0; i < listener->nsioc; i++) { 252 object_ref(OBJECT(listener)); 253 listener->io_source[i] = qio_channel_add_watch_source( 254 QIO_CHANNEL(listener->sioc[i]), G_IO_IN, 255 qio_net_listener_channel_func, 256 listener, (GDestroyNotify)object_unref, NULL); 257 } 258 } 259 260 return data.sioc; 261 } 262 263 void qio_net_listener_disconnect(QIONetListener *listener) 264 { 265 size_t i; 266 267 if (!listener->connected) { 268 return; 269 } 270 271 for (i = 0; i < listener->nsioc; i++) { 272 if (listener->io_source[i]) { 273 g_source_destroy(listener->io_source[i]); 274 g_source_unref(listener->io_source[i]); 275 listener->io_source[i] = NULL; 276 } 277 qio_channel_close(QIO_CHANNEL(listener->sioc[i]), NULL); 278 } 279 listener->connected = false; 280 } 281 282 283 bool qio_net_listener_is_connected(QIONetListener *listener) 284 { 285 return listener->connected; 286 } 287 288 static void qio_net_listener_finalize(Object *obj) 289 { 290 QIONetListener *listener = QIO_NET_LISTENER(obj); 291 size_t i; 292 293 if (listener->io_notify) { 294 listener->io_notify(listener->io_data); 295 } 296 qio_net_listener_disconnect(listener); 297 298 for (i = 0; i < listener->nsioc; i++) { 299 object_unref(OBJECT(listener->sioc[i])); 300 } 301 g_free(listener->io_source); 302 g_free(listener->sioc); 303 g_free(listener->name); 304 } 305 306 static const TypeInfo qio_net_listener_info = { 307 .parent = TYPE_OBJECT, 308 .name = TYPE_QIO_NET_LISTENER, 309 .instance_size = sizeof(QIONetListener), 310 .instance_finalize = qio_net_listener_finalize, 311 }; 312 313 314 static void qio_net_listener_register_types(void) 315 { 316 type_register_static(&qio_net_listener_info); 317 } 318 319 320 type_init(qio_net_listener_register_types); 321