153047392SDaniel P. Berrange /*
253047392SDaniel P. Berrange * QEMU network listener
353047392SDaniel P. Berrange *
453047392SDaniel P. Berrange * Copyright (c) 2016-2017 Red Hat, Inc.
553047392SDaniel P. Berrange *
653047392SDaniel P. Berrange * This program is free software; you can redistribute it and/or modify
753047392SDaniel P. Berrange * it under the terms of the GNU General Public License as published by
853047392SDaniel P. Berrange * the Free Software Foundation; either version 2 of the License, or
953047392SDaniel P. Berrange * (at your option) any later version.
1053047392SDaniel P. Berrange *
1153047392SDaniel P. Berrange * This program is distributed in the hope that it will be useful,
1253047392SDaniel P. Berrange * but WITHOUT ANY WARRANTY; without even the implied warranty of
1353047392SDaniel P. Berrange * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1453047392SDaniel P. Berrange * GNU General Public License for more details.
1553047392SDaniel P. Berrange *
1653047392SDaniel P. Berrange * You should have received a copy of the GNU General Public License along
1753047392SDaniel P. Berrange * with this program; if not, see <http://www.gnu.org/licenses/>.
1853047392SDaniel P. Berrange *
1953047392SDaniel P. Berrange */
2053047392SDaniel P. Berrange
2153047392SDaniel P. Berrange #include "qemu/osdep.h"
2253047392SDaniel P. Berrange #include "io/net-listener.h"
2353047392SDaniel P. Berrange #include "io/dns-resolver.h"
2453047392SDaniel P. Berrange #include "qapi/error.h"
250b8fa32fSMarkus Armbruster #include "qemu/module.h"
2653047392SDaniel P. Berrange
qio_net_listener_new(void)2753047392SDaniel P. Berrange QIONetListener *qio_net_listener_new(void)
2853047392SDaniel P. Berrange {
294a4ff4c5SLaurent Vivier return QIO_NET_LISTENER(object_new(TYPE_QIO_NET_LISTENER));
3053047392SDaniel P. Berrange }
3153047392SDaniel P. Berrange
qio_net_listener_set_name(QIONetListener * listener,const char * name)3253047392SDaniel P. Berrange void qio_net_listener_set_name(QIONetListener *listener,
3353047392SDaniel P. Berrange const char *name)
3453047392SDaniel P. Berrange {
3553047392SDaniel P. Berrange g_free(listener->name);
3653047392SDaniel P. Berrange listener->name = g_strdup(name);
3753047392SDaniel P. Berrange }
3853047392SDaniel P. Berrange
3953047392SDaniel P. Berrange
qio_net_listener_channel_func(QIOChannel * ioc,GIOCondition condition,gpointer opaque)4053047392SDaniel P. Berrange static gboolean qio_net_listener_channel_func(QIOChannel *ioc,
4153047392SDaniel P. Berrange GIOCondition condition,
4253047392SDaniel P. Berrange gpointer opaque)
4353047392SDaniel P. Berrange {
4453047392SDaniel P. Berrange QIONetListener *listener = QIO_NET_LISTENER(opaque);
4553047392SDaniel P. Berrange QIOChannelSocket *sioc;
4653047392SDaniel P. Berrange
4753047392SDaniel P. Berrange sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
4853047392SDaniel P. Berrange NULL);
4953047392SDaniel P. Berrange if (!sioc) {
5053047392SDaniel P. Berrange return TRUE;
5153047392SDaniel P. Berrange }
5253047392SDaniel P. Berrange
5353047392SDaniel P. Berrange if (listener->io_func) {
5453047392SDaniel P. Berrange listener->io_func(listener, sioc, listener->io_data);
5553047392SDaniel P. Berrange }
5653047392SDaniel P. Berrange
5753047392SDaniel P. Berrange object_unref(OBJECT(sioc));
5853047392SDaniel P. Berrange
5953047392SDaniel P. Berrange return TRUE;
6053047392SDaniel P. Berrange }
6153047392SDaniel P. Berrange
6253047392SDaniel P. Berrange
qio_net_listener_open_sync(QIONetListener * listener,SocketAddress * addr,int num,Error ** errp)6353047392SDaniel P. Berrange int qio_net_listener_open_sync(QIONetListener *listener,
6453047392SDaniel P. Berrange SocketAddress *addr,
65fc8135c6SJuan Quintela int num,
6653047392SDaniel P. Berrange Error **errp)
6753047392SDaniel P. Berrange {
6853047392SDaniel P. Berrange QIODNSResolver *resolver = qio_dns_resolver_get_instance();
6953047392SDaniel P. Berrange SocketAddress **resaddrs;
7053047392SDaniel P. Berrange size_t nresaddrs;
7153047392SDaniel P. Berrange size_t i;
7253047392SDaniel P. Berrange Error *err = NULL;
7353047392SDaniel P. Berrange bool success = false;
7453047392SDaniel P. Berrange
7553047392SDaniel P. Berrange if (qio_dns_resolver_lookup_sync(resolver,
7653047392SDaniel P. Berrange addr,
7753047392SDaniel P. Berrange &nresaddrs,
7853047392SDaniel P. Berrange &resaddrs,
7953047392SDaniel P. Berrange errp) < 0) {
8053047392SDaniel P. Berrange return -1;
8153047392SDaniel P. Berrange }
8253047392SDaniel P. Berrange
8353047392SDaniel P. Berrange for (i = 0; i < nresaddrs; i++) {
8453047392SDaniel P. Berrange QIOChannelSocket *sioc = qio_channel_socket_new();
8553047392SDaniel P. Berrange
86fc8135c6SJuan Quintela if (qio_channel_socket_listen_sync(sioc, resaddrs[i], num,
8753047392SDaniel P. Berrange err ? NULL : &err) == 0) {
8853047392SDaniel P. Berrange success = true;
8953047392SDaniel P. Berrange
9053047392SDaniel P. Berrange qio_net_listener_add(listener, sioc);
9153047392SDaniel P. Berrange }
9253047392SDaniel P. Berrange
9353047392SDaniel P. Berrange qapi_free_SocketAddress(resaddrs[i]);
9453047392SDaniel P. Berrange object_unref(OBJECT(sioc));
9553047392SDaniel P. Berrange }
9653047392SDaniel P. Berrange g_free(resaddrs);
9753047392SDaniel P. Berrange
9853047392SDaniel P. Berrange if (success) {
9953047392SDaniel P. Berrange error_free(err);
10053047392SDaniel P. Berrange return 0;
10153047392SDaniel P. Berrange } else {
10253047392SDaniel P. Berrange error_propagate(errp, err);
10353047392SDaniel P. Berrange return -1;
10453047392SDaniel P. Berrange }
10553047392SDaniel P. Berrange }
10653047392SDaniel P. Berrange
10753047392SDaniel P. Berrange
qio_net_listener_add(QIONetListener * listener,QIOChannelSocket * sioc)10853047392SDaniel P. Berrange void qio_net_listener_add(QIONetListener *listener,
10953047392SDaniel P. Berrange QIOChannelSocket *sioc)
11053047392SDaniel P. Berrange {
11153047392SDaniel P. Berrange if (listener->name) {
112*9c636e0fSFabiano Rosas qio_channel_set_name(QIO_CHANNEL(sioc), listener->name);
11353047392SDaniel P. Berrange }
11453047392SDaniel P. Berrange
11553047392SDaniel P. Berrange listener->sioc = g_renew(QIOChannelSocket *, listener->sioc,
11653047392SDaniel P. Berrange listener->nsioc + 1);
117938c8b79SPeter Xu listener->io_source = g_renew(typeof(listener->io_source[0]),
118938c8b79SPeter Xu listener->io_source,
119938c8b79SPeter Xu listener->nsioc + 1);
12053047392SDaniel P. Berrange listener->sioc[listener->nsioc] = sioc;
121938c8b79SPeter Xu listener->io_source[listener->nsioc] = NULL;
12253047392SDaniel P. Berrange
12353047392SDaniel P. Berrange object_ref(OBJECT(sioc));
12453047392SDaniel P. Berrange listener->connected = true;
12553047392SDaniel P. Berrange
12653047392SDaniel P. Berrange if (listener->io_func != NULL) {
12753047392SDaniel P. Berrange object_ref(OBJECT(listener));
128938c8b79SPeter Xu listener->io_source[listener->nsioc] = qio_channel_add_watch_source(
12953047392SDaniel P. Berrange QIO_CHANNEL(listener->sioc[listener->nsioc]), G_IO_IN,
13053047392SDaniel P. Berrange qio_net_listener_channel_func,
131938c8b79SPeter Xu listener, (GDestroyNotify)object_unref, NULL);
13253047392SDaniel P. Berrange }
13353047392SDaniel P. Berrange
13453047392SDaniel P. Berrange listener->nsioc++;
13553047392SDaniel P. Berrange }
13653047392SDaniel P. Berrange
13753047392SDaniel P. Berrange
qio_net_listener_set_client_func_full(QIONetListener * listener,QIONetListenerClientFunc func,gpointer data,GDestroyNotify notify,GMainContext * context)138938c8b79SPeter Xu void qio_net_listener_set_client_func_full(QIONetListener *listener,
13953047392SDaniel P. Berrange QIONetListenerClientFunc func,
14053047392SDaniel P. Berrange gpointer data,
141938c8b79SPeter Xu GDestroyNotify notify,
142938c8b79SPeter Xu GMainContext *context)
14353047392SDaniel P. Berrange {
14453047392SDaniel P. Berrange size_t i;
14553047392SDaniel P. Berrange
14653047392SDaniel P. Berrange if (listener->io_notify) {
14753047392SDaniel P. Berrange listener->io_notify(listener->io_data);
14853047392SDaniel P. Berrange }
14953047392SDaniel P. Berrange listener->io_func = func;
15053047392SDaniel P. Berrange listener->io_data = data;
15153047392SDaniel P. Berrange listener->io_notify = notify;
15253047392SDaniel P. Berrange
15353047392SDaniel P. Berrange for (i = 0; i < listener->nsioc; i++) {
154938c8b79SPeter Xu if (listener->io_source[i]) {
155938c8b79SPeter Xu g_source_destroy(listener->io_source[i]);
156938c8b79SPeter Xu g_source_unref(listener->io_source[i]);
157938c8b79SPeter Xu listener->io_source[i] = NULL;
15853047392SDaniel P. Berrange }
15953047392SDaniel P. Berrange }
16053047392SDaniel P. Berrange
16153047392SDaniel P. Berrange if (listener->io_func != NULL) {
16253047392SDaniel P. Berrange for (i = 0; i < listener->nsioc; i++) {
16353047392SDaniel P. Berrange object_ref(OBJECT(listener));
164938c8b79SPeter Xu listener->io_source[i] = qio_channel_add_watch_source(
16553047392SDaniel P. Berrange QIO_CHANNEL(listener->sioc[i]), G_IO_IN,
16653047392SDaniel P. Berrange qio_net_listener_channel_func,
167938c8b79SPeter Xu listener, (GDestroyNotify)object_unref, context);
16853047392SDaniel P. Berrange }
16953047392SDaniel P. Berrange }
17053047392SDaniel P. Berrange }
17153047392SDaniel P. Berrange
qio_net_listener_set_client_func(QIONetListener * listener,QIONetListenerClientFunc func,gpointer data,GDestroyNotify notify)172938c8b79SPeter Xu void qio_net_listener_set_client_func(QIONetListener *listener,
173938c8b79SPeter Xu QIONetListenerClientFunc func,
174938c8b79SPeter Xu gpointer data,
175938c8b79SPeter Xu GDestroyNotify notify)
176938c8b79SPeter Xu {
177938c8b79SPeter Xu qio_net_listener_set_client_func_full(listener, func, data,
178938c8b79SPeter Xu notify, NULL);
179938c8b79SPeter Xu }
18053047392SDaniel P. Berrange
18153047392SDaniel P. Berrange struct QIONetListenerClientWaitData {
18253047392SDaniel P. Berrange QIOChannelSocket *sioc;
18353047392SDaniel P. Berrange GMainLoop *loop;
18453047392SDaniel P. Berrange };
18553047392SDaniel P. Berrange
18653047392SDaniel P. Berrange
qio_net_listener_wait_client_func(QIOChannel * ioc,GIOCondition condition,gpointer opaque)18753047392SDaniel P. Berrange static gboolean qio_net_listener_wait_client_func(QIOChannel *ioc,
18853047392SDaniel P. Berrange GIOCondition condition,
18953047392SDaniel P. Berrange gpointer opaque)
19053047392SDaniel P. Berrange {
19153047392SDaniel P. Berrange struct QIONetListenerClientWaitData *data = opaque;
19253047392SDaniel P. Berrange QIOChannelSocket *sioc;
19353047392SDaniel P. Berrange
19453047392SDaniel P. Berrange sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
19553047392SDaniel P. Berrange NULL);
19653047392SDaniel P. Berrange if (!sioc) {
19753047392SDaniel P. Berrange return TRUE;
19853047392SDaniel P. Berrange }
19953047392SDaniel P. Berrange
20053047392SDaniel P. Berrange if (data->sioc) {
20153047392SDaniel P. Berrange object_unref(OBJECT(sioc));
20253047392SDaniel P. Berrange } else {
20353047392SDaniel P. Berrange data->sioc = sioc;
20453047392SDaniel P. Berrange g_main_loop_quit(data->loop);
20553047392SDaniel P. Berrange }
20653047392SDaniel P. Berrange
20753047392SDaniel P. Berrange return TRUE;
20853047392SDaniel P. Berrange }
20953047392SDaniel P. Berrange
qio_net_listener_wait_client(QIONetListener * listener)21053047392SDaniel P. Berrange QIOChannelSocket *qio_net_listener_wait_client(QIONetListener *listener)
21153047392SDaniel P. Berrange {
21253047392SDaniel P. Berrange GMainContext *ctxt = g_main_context_new();
21353047392SDaniel P. Berrange GMainLoop *loop = g_main_loop_new(ctxt, TRUE);
21453047392SDaniel P. Berrange GSource **sources;
21553047392SDaniel P. Berrange struct QIONetListenerClientWaitData data = {
21653047392SDaniel P. Berrange .sioc = NULL,
21753047392SDaniel P. Berrange .loop = loop
21853047392SDaniel P. Berrange };
21953047392SDaniel P. Berrange size_t i;
22053047392SDaniel P. Berrange
22153047392SDaniel P. Berrange for (i = 0; i < listener->nsioc; i++) {
222938c8b79SPeter Xu if (listener->io_source[i]) {
223938c8b79SPeter Xu g_source_destroy(listener->io_source[i]);
224938c8b79SPeter Xu g_source_unref(listener->io_source[i]);
225938c8b79SPeter Xu listener->io_source[i] = NULL;
22653047392SDaniel P. Berrange }
22753047392SDaniel P. Berrange }
22853047392SDaniel P. Berrange
22953047392SDaniel P. Berrange sources = g_new0(GSource *, listener->nsioc);
23053047392SDaniel P. Berrange for (i = 0; i < listener->nsioc; i++) {
23153047392SDaniel P. Berrange sources[i] = qio_channel_create_watch(QIO_CHANNEL(listener->sioc[i]),
23253047392SDaniel P. Berrange G_IO_IN);
23353047392SDaniel P. Berrange
23453047392SDaniel P. Berrange g_source_set_callback(sources[i],
23553047392SDaniel P. Berrange (GSourceFunc)qio_net_listener_wait_client_func,
23653047392SDaniel P. Berrange &data,
23753047392SDaniel P. Berrange NULL);
23853047392SDaniel P. Berrange g_source_attach(sources[i], ctxt);
23953047392SDaniel P. Berrange }
24053047392SDaniel P. Berrange
24153047392SDaniel P. Berrange g_main_loop_run(loop);
24253047392SDaniel P. Berrange
24353047392SDaniel P. Berrange for (i = 0; i < listener->nsioc; i++) {
24453047392SDaniel P. Berrange g_source_unref(sources[i]);
24553047392SDaniel P. Berrange }
24628bb0a59SPaolo Bonzini g_free(sources);
24753047392SDaniel P. Berrange g_main_loop_unref(loop);
24853047392SDaniel P. Berrange g_main_context_unref(ctxt);
24953047392SDaniel P. Berrange
25053047392SDaniel P. Berrange if (listener->io_func != NULL) {
25153047392SDaniel P. Berrange for (i = 0; i < listener->nsioc; i++) {
25253047392SDaniel P. Berrange object_ref(OBJECT(listener));
253938c8b79SPeter Xu listener->io_source[i] = qio_channel_add_watch_source(
25453047392SDaniel P. Berrange QIO_CHANNEL(listener->sioc[i]), G_IO_IN,
25553047392SDaniel P. Berrange qio_net_listener_channel_func,
256938c8b79SPeter Xu listener, (GDestroyNotify)object_unref, NULL);
25753047392SDaniel P. Berrange }
25853047392SDaniel P. Berrange }
25953047392SDaniel P. Berrange
26053047392SDaniel P. Berrange return data.sioc;
26153047392SDaniel P. Berrange }
26253047392SDaniel P. Berrange
qio_net_listener_disconnect(QIONetListener * listener)26353047392SDaniel P. Berrange void qio_net_listener_disconnect(QIONetListener *listener)
26453047392SDaniel P. Berrange {
26553047392SDaniel P. Berrange size_t i;
26653047392SDaniel P. Berrange
26753047392SDaniel P. Berrange if (!listener->connected) {
26853047392SDaniel P. Berrange return;
26953047392SDaniel P. Berrange }
27053047392SDaniel P. Berrange
27153047392SDaniel P. Berrange for (i = 0; i < listener->nsioc; i++) {
272938c8b79SPeter Xu if (listener->io_source[i]) {
273938c8b79SPeter Xu g_source_destroy(listener->io_source[i]);
274938c8b79SPeter Xu g_source_unref(listener->io_source[i]);
275938c8b79SPeter Xu listener->io_source[i] = NULL;
27653047392SDaniel P. Berrange }
27753047392SDaniel P. Berrange qio_channel_close(QIO_CHANNEL(listener->sioc[i]), NULL);
27853047392SDaniel P. Berrange }
27953047392SDaniel P. Berrange listener->connected = false;
28053047392SDaniel P. Berrange }
28153047392SDaniel P. Berrange
28253047392SDaniel P. Berrange
qio_net_listener_is_connected(QIONetListener * listener)28353047392SDaniel P. Berrange bool qio_net_listener_is_connected(QIONetListener *listener)
28453047392SDaniel P. Berrange {
28553047392SDaniel P. Berrange return listener->connected;
28653047392SDaniel P. Berrange }
28753047392SDaniel P. Berrange
qio_net_listener_finalize(Object * obj)28853047392SDaniel P. Berrange static void qio_net_listener_finalize(Object *obj)
28953047392SDaniel P. Berrange {
29053047392SDaniel P. Berrange QIONetListener *listener = QIO_NET_LISTENER(obj);
29153047392SDaniel P. Berrange size_t i;
29253047392SDaniel P. Berrange
2935b6116d3SDr. David Alan Gilbert if (listener->io_notify) {
2945b6116d3SDr. David Alan Gilbert listener->io_notify(listener->io_data);
2955b6116d3SDr. David Alan Gilbert }
29653047392SDaniel P. Berrange qio_net_listener_disconnect(listener);
29753047392SDaniel P. Berrange
29853047392SDaniel P. Berrange for (i = 0; i < listener->nsioc; i++) {
29953047392SDaniel P. Berrange object_unref(OBJECT(listener->sioc[i]));
30053047392SDaniel P. Berrange }
301938c8b79SPeter Xu g_free(listener->io_source);
30253047392SDaniel P. Berrange g_free(listener->sioc);
30353047392SDaniel P. Berrange g_free(listener->name);
30453047392SDaniel P. Berrange }
30553047392SDaniel P. Berrange
30653047392SDaniel P. Berrange static const TypeInfo qio_net_listener_info = {
30753047392SDaniel P. Berrange .parent = TYPE_OBJECT,
30853047392SDaniel P. Berrange .name = TYPE_QIO_NET_LISTENER,
30953047392SDaniel P. Berrange .instance_size = sizeof(QIONetListener),
31053047392SDaniel P. Berrange .instance_finalize = qio_net_listener_finalize,
31153047392SDaniel P. Berrange };
31253047392SDaniel P. Berrange
31353047392SDaniel P. Berrange
qio_net_listener_register_types(void)31453047392SDaniel P. Berrange static void qio_net_listener_register_types(void)
31553047392SDaniel P. Berrange {
31653047392SDaniel P. Berrange type_register_static(&qio_net_listener_info);
31753047392SDaniel P. Berrange }
31853047392SDaniel P. Berrange
31953047392SDaniel P. Berrange
32053047392SDaniel P. Berrange type_init(qio_net_listener_register_types);
321