xref: /openbmc/qemu/io/net-listener.c (revision f09744ddc2424bc6a76702e1951a8d24917062d6)
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