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