master
c 483 lines 14.6 KB
Raw
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 "qemu/main-loop.h"
28 #include "trace.h"
29
30 struct QIONetListenerSource {
31 QIOChannelSocket *sioc;
32 GSource *io_source;
33 QIONetListener *listener;
34 };
35
36 QIONetListener *qio_net_listener_new(void)
37 {
38 QIONetListener *listener;
39
40 listener = QIO_NET_LISTENER(object_new(TYPE_QIO_NET_LISTENER));
41 return listener;
42 }
43
44 void qio_net_listener_set_name(QIONetListener *listener,
45 const char *name)
46 {
47 g_free(listener->name);
48 listener->name = g_strdup(name);
49 }
50
51
52 static gboolean qio_net_listener_channel_func(QIOChannel *ioc,
53 GIOCondition condition,
54 gpointer opaque)
55 {
56 QIONetListener *listener = QIO_NET_LISTENER(opaque);
57 QIOChannelSocket *sioc;
58 QIONetListenerClientFunc io_func;
59 gpointer io_data;
60 GMainContext *context;
61 AioContext *aio_context;
62
63 sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
64 NULL);
65 if (!sioc) {
66 return TRUE;
67 }
68
69 WITH_QEMU_LOCK_GUARD(&listener->lock) {
70 io_func = listener->io_func;
71 io_data = listener->io_data;
72 context = listener->context;
73 aio_context = listener->aio_context;
74 }
75
76 trace_qio_net_listener_callback(listener, io_func, context, aio_context);
77 if (io_func) {
78 io_func(listener, sioc, io_data);
79 }
80
81 object_unref(OBJECT(sioc));
82
83 return TRUE;
84 }
85
86
87 static void qio_net_listener_aio_func(void *opaque)
88 {
89 QIONetListenerSource *data = opaque;
90
91 assert(data->io_source == NULL);
92 assert(data->listener->aio_context != NULL);
93 qio_net_listener_channel_func(QIO_CHANNEL(data->sioc), G_IO_IN,
94 data->listener);
95 }
96
97
98 int qio_net_listener_open_sync(QIONetListener *listener,
99 SocketAddress *addr,
100 int num,
101 Error **errp)
102 {
103 QIODNSResolver *resolver = qio_dns_resolver_get_instance();
104 SocketAddress **resaddrs;
105 size_t nresaddrs;
106 size_t i;
107 Error *err = NULL;
108 bool success = false;
109
110 if (qio_dns_resolver_lookup_sync(resolver,
111 addr,
112 &nresaddrs,
113 &resaddrs,
114 errp) < 0) {
115 return -1;
116 }
117
118 for (i = 0; i < nresaddrs; i++) {
119 QIOChannelSocket *sioc = qio_channel_socket_new();
120
121 if (qio_channel_socket_listen_sync(sioc, resaddrs[i], num,
122 err ? NULL : &err) == 0) {
123 success = true;
124
125 qio_net_listener_add(listener, sioc);
126 }
127
128 qapi_free_SocketAddress(resaddrs[i]);
129 object_unref(OBJECT(sioc));
130 }
131 g_free(resaddrs);
132
133 if (success) {
134 error_free(err);
135 return 0;
136 } else {
137 error_propagate(errp, err);
138 return -1;
139 }
140 }
141
142 /*
143 * i == 0 to set watch on entire array, non-zero to only set watch on
144 * recent additions when earlier entries are already watched.
145 *
146 * listener->lock must be held by caller.
147 */
148 static void
149 qio_net_listener_watch(QIONetListener *listener, size_t i, const char *caller)
150 {
151 if (!listener->io_func) {
152 return;
153 }
154
155 trace_qio_net_listener_watch(listener, listener->io_func,
156 listener->context, listener->aio_context,
157 caller);
158 for ( ; i < listener->nsioc; i++) {
159 if (!listener->aio_context) {
160 /*
161 * The user passed a GMainContext with the async callback;
162 * they plan on running the default or their own g_main_loop.
163 */
164 object_ref(OBJECT(listener));
165 listener->source[i]->io_source = qio_channel_add_watch_source(
166 QIO_CHANNEL(listener->source[i]->sioc), G_IO_IN,
167 qio_net_listener_channel_func,
168 listener, (GDestroyNotify)object_unref, listener->context);
169 } else {
170 /*
171 * The user passed an AioContext. At this point,
172 * AioContext lacks a clean way to call a notify function
173 * to release a final reference after any callback is
174 * complete. But we asserted earlier that the async
175 * callback is changed only from the thread associated
176 * with aio_context, which means no other thread is in the
177 * middle of running the callback when we are changing the
178 * refcount on listener here. Therefore, a single
179 * reference here is sufficient to ensure listener is not
180 * finalized during the callback.
181 */
182 assert(listener->context == NULL);
183 if (i == 0) {
184 object_ref(OBJECT(listener));
185 }
186 qio_channel_set_aio_fd_handler(
187 QIO_CHANNEL(listener->source[i]->sioc),
188 listener->aio_context, qio_net_listener_aio_func,
189 NULL, NULL, listener->source[i]);
190 }
191 }
192 }
193
194 /* listener->lock must be held by caller. */
195 static void
196 qio_net_listener_unwatch(QIONetListener *listener, const char *caller)
197 {
198 size_t i;
199
200 if (!listener->io_func) {
201 return;
202 }
203
204 trace_qio_net_listener_unwatch(listener, listener->io_func,
205 listener->context, listener->aio_context,
206 caller);
207 for (i = 0; i < listener->nsioc; i++) {
208 if (!listener->aio_context) {
209 if (listener->source[i]->io_source) {
210 g_source_destroy(listener->source[i]->io_source);
211 g_source_unref(listener->source[i]->io_source);
212 listener->source[i]->io_source = NULL;
213 }
214 } else {
215 assert(listener->context == NULL);
216 qio_channel_set_aio_fd_handler(
217 QIO_CHANNEL(listener->source[i]->sioc),
218 listener->aio_context, NULL, NULL, NULL, NULL);
219 if (i == listener->nsioc - 1) {
220 object_unref(OBJECT(listener));
221 }
222 }
223 }
224 }
225
226 void qio_net_listener_add(QIONetListener *listener,
227 QIOChannelSocket *sioc)
228 {
229 if (listener->name) {
230 qio_channel_set_name(QIO_CHANNEL(sioc), listener->name);
231 }
232
233 listener->source = g_renew(typeof(listener->source[0]),
234 listener->source,
235 listener->nsioc + 1);
236 listener->source[listener->nsioc] = g_new0(QIONetListenerSource, 1);
237 listener->source[listener->nsioc]->sioc = sioc;
238 listener->source[listener->nsioc]->listener = listener;
239
240 object_ref(OBJECT(sioc));
241 listener->connected = true;
242
243 QEMU_LOCK_GUARD(&listener->lock);
244 listener->nsioc++;
245 qio_net_listener_watch(listener, listener->nsioc - 1, "add");
246 }
247
248
249 static void
250 qio_net_listener_set_client_func_internal(QIONetListener *listener,
251 QIONetListenerClientFunc func,
252 gpointer data,
253 GDestroyNotify notify,
254 GMainContext *context,
255 AioContext *aio_context)
256 {
257 QEMU_LOCK_GUARD(&listener->lock);
258 if (listener->io_func == func && listener->io_data == data &&
259 listener->io_notify == notify && listener->context == context &&
260 listener->aio_context == aio_context) {
261 return;
262 }
263
264 qio_net_listener_unwatch(listener, "set_client_func");
265 if (listener->io_notify) {
266 listener->io_notify(listener->io_data);
267 }
268 listener->io_func = func;
269 listener->io_data = data;
270 listener->io_notify = notify;
271 listener->context = context;
272 listener->aio_context = aio_context;
273
274 qio_net_listener_watch(listener, 0, "set_client_func");
275 }
276
277 void qio_net_listener_set_client_func_full(QIONetListener *listener,
278 QIONetListenerClientFunc func,
279 gpointer data,
280 GDestroyNotify notify,
281 GMainContext *context)
282 {
283 qio_net_listener_set_client_func_internal(listener, func, data,
284 notify, context, NULL);
285 }
286
287 void qio_net_listener_set_client_func(QIONetListener *listener,
288 QIONetListenerClientFunc func,
289 gpointer data,
290 GDestroyNotify notify)
291 {
292 qio_net_listener_set_client_func_internal(listener, func, data,
293 notify, NULL, NULL);
294 }
295
296 void qio_net_listener_set_client_aio_func(QIONetListener *listener,
297 QIONetListenerClientFunc func,
298 void *data,
299 AioContext *context)
300 {
301 if (!context) {
302 assert(qemu_in_main_thread());
303 context = qemu_get_aio_context();
304 } else {
305 /*
306 * TODO: The API was intentionally designed to allow a caller
307 * to pass an alternative AioContext for future expansion;
308 * however, actually implementating that is not possible
309 * without notify callbacks wired into AioContext similar to
310 * how they work in GSource. So for now, this code hard-codes
311 * the knowledge that the only client needing AioContext is
312 * the NBD server, which uses the global context and does not
313 * suffer from cross-thread safety issues.
314 */
315 g_assert_not_reached();
316 }
317 qio_net_listener_set_client_func_internal(listener, func, data,
318 NULL, NULL, context);
319 }
320
321 struct QIONetListenerClientWaitData {
322 QIOChannelSocket *sioc;
323 GMainLoop *loop;
324 };
325
326
327 static gboolean qio_net_listener_wait_client_func(QIOChannel *ioc,
328 GIOCondition condition,
329 gpointer opaque)
330 {
331 struct QIONetListenerClientWaitData *data = opaque;
332 QIOChannelSocket *sioc;
333
334 sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
335 NULL);
336 if (!sioc) {
337 return TRUE;
338 }
339
340 if (data->sioc) {
341 object_unref(OBJECT(sioc));
342 } else {
343 data->sioc = sioc;
344 g_main_loop_quit(data->loop);
345 }
346
347 return TRUE;
348 }
349
350 QIOChannelSocket *qio_net_listener_wait_client(QIONetListener *listener)
351 {
352 GMainContext *ctxt = g_main_context_new();
353 GMainLoop *loop = g_main_loop_new(ctxt, TRUE);
354 GSource **sources;
355 struct QIONetListenerClientWaitData data = {
356 .sioc = NULL,
357 .loop = loop
358 };
359 size_t i;
360
361 WITH_QEMU_LOCK_GUARD(&listener->lock) {
362 qio_net_listener_unwatch(listener, "wait_client");
363 }
364
365 sources = g_new0(GSource *, listener->nsioc);
366 for (i = 0; i < listener->nsioc; i++) {
367 sources[i] = qio_channel_create_watch(
368 QIO_CHANNEL(listener->source[i]->sioc), G_IO_IN);
369
370 g_source_set_callback(sources[i],
371 (GSourceFunc)qio_net_listener_wait_client_func,
372 &data,
373 NULL);
374 g_source_attach(sources[i], ctxt);
375 }
376
377 g_main_loop_run(loop);
378
379 for (i = 0; i < listener->nsioc; i++) {
380 g_source_unref(sources[i]);
381 }
382 g_free(sources);
383 g_main_loop_unref(loop);
384 g_main_context_unref(ctxt);
385
386 WITH_QEMU_LOCK_GUARD(&listener->lock) {
387 qio_net_listener_watch(listener, 0, "wait_client");
388 }
389
390 return data.sioc;
391 }
392
393 void qio_net_listener_disconnect(QIONetListener *listener)
394 {
395 size_t i;
396
397 if (!listener->connected) {
398 return;
399 }
400
401 QEMU_LOCK_GUARD(&listener->lock);
402 qio_net_listener_unwatch(listener, "disconnect");
403 for (i = 0; i < listener->nsioc; i++) {
404 qio_channel_close(QIO_CHANNEL(listener->source[i]->sioc), NULL);
405 }
406 listener->connected = false;
407 }
408
409
410 bool qio_net_listener_is_connected(QIONetListener *listener)
411 {
412 return listener->connected;
413 }
414
415 size_t qio_net_listener_nsioc(QIONetListener *listener)
416 {
417 return listener->nsioc;
418 }
419
420 QIOChannelSocket *qio_net_listener_sioc(QIONetListener *listener, size_t n)
421 {
422 if (n >= listener->nsioc) {
423 return NULL;
424 }
425 return listener->source[n]->sioc;
426 }
427
428 SocketAddress *
429 qio_net_listener_get_local_address(QIONetListener *listener, size_t n,
430 Error **errp)
431 {
432 QIOChannelSocket *sioc = qio_net_listener_sioc(listener, n);
433
434 if (!sioc) {
435 error_setg(errp, "Listener index out of range");
436 return NULL;
437 }
438
439 return qio_channel_socket_get_local_address(sioc, errp);
440 }
441
442 static void qio_net_listener_instance_init(Object *obj)
443 {
444 QIONetListener *listener = QIO_NET_LISTENER(obj);
445
446 qemu_mutex_init(&listener->lock);
447 }
448
449 static void qio_net_listener_finalize(Object *obj)
450 {
451 QIONetListener *listener = QIO_NET_LISTENER(obj);
452 size_t i;
453
454 qio_net_listener_disconnect(listener);
455 if (listener->io_notify) {
456 listener->io_notify(listener->io_data);
457 }
458
459 for (i = 0; i < listener->nsioc; i++) {
460 object_unref(OBJECT(listener->source[i]->sioc));
461 g_free(listener->source[i]);
462 }
463 g_free(listener->source);
464 g_free(listener->name);
465 qemu_mutex_destroy(&listener->lock);
466 }
467
468 static const TypeInfo qio_net_listener_info = {
469 .parent = TYPE_OBJECT,
470 .name = TYPE_QIO_NET_LISTENER,
471 .instance_size = sizeof(QIONetListener),
472 .instance_init = qio_net_listener_instance_init,
473 .instance_finalize = qio_net_listener_finalize,
474 };
475
476
477 static void qio_net_listener_register_types(void)
478 {
479 type_register_static(&qio_net_listener_info);
480 }
481
482
483 type_init(qio_net_listener_register_types);