Merge remote-tracking branch 'remotes/vivier2/tags/linux-user-for-2.12-pull-request...
[qemu/ar7.git] / io / net-listener.c
blob555e8acaa4742d5a29a28b1a1db10f3ec6c026b2
1 /*
2 * QEMU network listener
4 * Copyright (c) 2016-2017 Red Hat, Inc.
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.
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.
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/>.
21 #include "qemu/osdep.h"
22 #include "io/net-listener.h"
23 #include "io/dns-resolver.h"
24 #include "qapi/error.h"
26 QIONetListener *qio_net_listener_new(void)
28 QIONetListener *ret;
30 ret = QIO_NET_LISTENER(object_new(TYPE_QIO_NET_LISTENER));
32 return ret;
35 void qio_net_listener_set_name(QIONetListener *listener,
36 const char *name)
38 g_free(listener->name);
39 listener->name = g_strdup(name);
43 static gboolean qio_net_listener_channel_func(QIOChannel *ioc,
44 GIOCondition condition,
45 gpointer opaque)
47 QIONetListener *listener = QIO_NET_LISTENER(opaque);
48 QIOChannelSocket *sioc;
50 sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
51 NULL);
52 if (!sioc) {
53 return TRUE;
56 if (listener->io_func) {
57 listener->io_func(listener, sioc, listener->io_data);
60 object_unref(OBJECT(sioc));
62 return TRUE;
66 int qio_net_listener_open_sync(QIONetListener *listener,
67 SocketAddress *addr,
68 Error **errp)
70 QIODNSResolver *resolver = qio_dns_resolver_get_instance();
71 SocketAddress **resaddrs;
72 size_t nresaddrs;
73 size_t i;
74 Error *err = NULL;
75 bool success = false;
77 if (qio_dns_resolver_lookup_sync(resolver,
78 addr,
79 &nresaddrs,
80 &resaddrs,
81 errp) < 0) {
82 return -1;
85 for (i = 0; i < nresaddrs; i++) {
86 QIOChannelSocket *sioc = qio_channel_socket_new();
88 if (qio_channel_socket_listen_sync(sioc, resaddrs[i],
89 err ? NULL : &err) == 0) {
90 success = true;
92 qio_net_listener_add(listener, sioc);
95 qapi_free_SocketAddress(resaddrs[i]);
96 object_unref(OBJECT(sioc));
98 g_free(resaddrs);
100 if (success) {
101 error_free(err);
102 return 0;
103 } else {
104 error_propagate(errp, err);
105 return -1;
110 void qio_net_listener_add(QIONetListener *listener,
111 QIOChannelSocket *sioc)
113 if (listener->name) {
114 char *name = g_strdup_printf("%s-listen", listener->name);
115 qio_channel_set_name(QIO_CHANNEL(sioc), name);
116 g_free(name);
119 listener->sioc = g_renew(QIOChannelSocket *, listener->sioc,
120 listener->nsioc + 1);
121 listener->io_source = g_renew(typeof(listener->io_source[0]),
122 listener->io_source,
123 listener->nsioc + 1);
124 listener->sioc[listener->nsioc] = sioc;
125 listener->io_source[listener->nsioc] = NULL;
127 object_ref(OBJECT(sioc));
128 listener->connected = true;
130 if (listener->io_func != NULL) {
131 object_ref(OBJECT(listener));
132 listener->io_source[listener->nsioc] = qio_channel_add_watch_source(
133 QIO_CHANNEL(listener->sioc[listener->nsioc]), G_IO_IN,
134 qio_net_listener_channel_func,
135 listener, (GDestroyNotify)object_unref, NULL);
138 listener->nsioc++;
142 void qio_net_listener_set_client_func_full(QIONetListener *listener,
143 QIONetListenerClientFunc func,
144 gpointer data,
145 GDestroyNotify notify,
146 GMainContext *context)
148 size_t i;
150 if (listener->io_notify) {
151 listener->io_notify(listener->io_data);
153 listener->io_func = func;
154 listener->io_data = data;
155 listener->io_notify = notify;
157 for (i = 0; i < listener->nsioc; i++) {
158 if (listener->io_source[i]) {
159 g_source_destroy(listener->io_source[i]);
160 g_source_unref(listener->io_source[i]);
161 listener->io_source[i] = NULL;
165 if (listener->io_func != NULL) {
166 for (i = 0; i < listener->nsioc; i++) {
167 object_ref(OBJECT(listener));
168 listener->io_source[i] = qio_channel_add_watch_source(
169 QIO_CHANNEL(listener->sioc[i]), G_IO_IN,
170 qio_net_listener_channel_func,
171 listener, (GDestroyNotify)object_unref, context);
176 void qio_net_listener_set_client_func(QIONetListener *listener,
177 QIONetListenerClientFunc func,
178 gpointer data,
179 GDestroyNotify notify)
181 qio_net_listener_set_client_func_full(listener, func, data,
182 notify, NULL);
185 struct QIONetListenerClientWaitData {
186 QIOChannelSocket *sioc;
187 GMainLoop *loop;
191 static gboolean qio_net_listener_wait_client_func(QIOChannel *ioc,
192 GIOCondition condition,
193 gpointer opaque)
195 struct QIONetListenerClientWaitData *data = opaque;
196 QIOChannelSocket *sioc;
198 sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
199 NULL);
200 if (!sioc) {
201 return TRUE;
204 if (data->sioc) {
205 object_unref(OBJECT(sioc));
206 } else {
207 data->sioc = sioc;
208 g_main_loop_quit(data->loop);
211 return TRUE;
214 QIOChannelSocket *qio_net_listener_wait_client(QIONetListener *listener)
216 GMainContext *ctxt = g_main_context_new();
217 GMainLoop *loop = g_main_loop_new(ctxt, TRUE);
218 GSource **sources;
219 struct QIONetListenerClientWaitData data = {
220 .sioc = NULL,
221 .loop = loop
223 size_t i;
225 for (i = 0; i < listener->nsioc; i++) {
226 if (listener->io_source[i]) {
227 g_source_destroy(listener->io_source[i]);
228 g_source_unref(listener->io_source[i]);
229 listener->io_source[i] = NULL;
233 sources = g_new0(GSource *, listener->nsioc);
234 for (i = 0; i < listener->nsioc; i++) {
235 sources[i] = qio_channel_create_watch(QIO_CHANNEL(listener->sioc[i]),
236 G_IO_IN);
238 g_source_set_callback(sources[i],
239 (GSourceFunc)qio_net_listener_wait_client_func,
240 &data,
241 NULL);
242 g_source_attach(sources[i], ctxt);
245 g_main_loop_run(loop);
247 for (i = 0; i < listener->nsioc; i++) {
248 g_source_unref(sources[i]);
250 g_free(sources);
251 g_main_loop_unref(loop);
252 g_main_context_unref(ctxt);
254 if (listener->io_func != NULL) {
255 for (i = 0; i < listener->nsioc; i++) {
256 object_ref(OBJECT(listener));
257 listener->io_source[i] = qio_channel_add_watch_source(
258 QIO_CHANNEL(listener->sioc[i]), G_IO_IN,
259 qio_net_listener_channel_func,
260 listener, (GDestroyNotify)object_unref, NULL);
264 return data.sioc;
267 void qio_net_listener_disconnect(QIONetListener *listener)
269 size_t i;
271 if (!listener->connected) {
272 return;
275 for (i = 0; i < listener->nsioc; i++) {
276 if (listener->io_source[i]) {
277 g_source_destroy(listener->io_source[i]);
278 g_source_unref(listener->io_source[i]);
279 listener->io_source[i] = NULL;
281 qio_channel_close(QIO_CHANNEL(listener->sioc[i]), NULL);
283 listener->connected = false;
287 bool qio_net_listener_is_connected(QIONetListener *listener)
289 return listener->connected;
292 static void qio_net_listener_finalize(Object *obj)
294 QIONetListener *listener = QIO_NET_LISTENER(obj);
295 size_t i;
297 qio_net_listener_disconnect(listener);
299 for (i = 0; i < listener->nsioc; i++) {
300 object_unref(OBJECT(listener->sioc[i]));
302 g_free(listener->io_source);
303 g_free(listener->sioc);
304 g_free(listener->name);
307 static const TypeInfo qio_net_listener_info = {
308 .parent = TYPE_OBJECT,
309 .name = TYPE_QIO_NET_LISTENER,
310 .instance_size = sizeof(QIONetListener),
311 .instance_finalize = qio_net_listener_finalize,
312 .class_size = sizeof(QIONetListenerClass),
316 static void qio_net_listener_register_types(void)
318 type_register_static(&qio_net_listener_info);
322 type_init(qio_net_listener_register_types);