1 /* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3 Copyright (C) 2009-2015 Red Hat, Inc.
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /*
20 * This file exports a global variable:
21 *
22 * const SpiceCoreInterfaceInternal event_loop_core;
23 */
24 #include <config.h>
25
26 #include "red-common.h"
27
28 typedef struct SpiceCoreFuncs {
29 void (*timer_start)(SpiceTimer *timer, uint32_t ms);
30 void (*timer_cancel)(SpiceTimer *timer);
31 void (*timer_remove)(SpiceTimer *timer);
32 void (*watch_update_mask)(SpiceWatch *watch, int event_mask);
33 void (*watch_remove)(SpiceWatch *watch);
34 } SpiceCoreFuncs;
35
36 struct SpiceTimer {
37 const SpiceCoreFuncs *funcs;
38 };
39
40 struct SpiceWatch {
41 const SpiceCoreFuncs *funcs;
42 };
43
red_timer_start(SpiceTimer * timer,uint32_t ms)44 void red_timer_start(SpiceTimer *timer, uint32_t ms)
45 {
46 if (timer) {
47 timer->funcs->timer_start(timer, ms);
48 }
49 }
50
red_timer_cancel(SpiceTimer * timer)51 void red_timer_cancel(SpiceTimer *timer)
52 {
53 if (timer) {
54 timer->funcs->timer_cancel(timer);
55 }
56 }
57
red_timer_remove(SpiceTimer * timer)58 void red_timer_remove(SpiceTimer *timer)
59 {
60 if (timer) {
61 timer->funcs->timer_remove(timer);
62 }
63 }
64
red_watch_update_mask(SpiceWatch * watch,int event_mask)65 void red_watch_update_mask(SpiceWatch *watch, int event_mask)
66 {
67 if (watch) {
68 watch->funcs->watch_update_mask(watch, event_mask);
69 }
70 }
71
red_watch_remove(SpiceWatch * watch)72 void red_watch_remove(SpiceWatch *watch)
73 {
74 if (watch) {
75 watch->funcs->watch_remove(watch);
76 }
77 }
78
79 static const SpiceCoreFuncs glib_core_funcs;
80
81 typedef struct SpiceTimerGlib {
82 SpiceTimer base;
83 GMainContext *context;
84 SpiceTimerFunc func;
85 void *opaque;
86 GSource *source;
87 } SpiceTimerGlib;
88
timer_add(const SpiceCoreInterfaceInternal * iface,SpiceTimerFunc func,void * opaque)89 static SpiceTimer* timer_add(const SpiceCoreInterfaceInternal *iface,
90 SpiceTimerFunc func, void *opaque)
91 {
92 SpiceTimerGlib *timer = g_new0(SpiceTimerGlib, 1);
93
94 timer->base.funcs = &glib_core_funcs;
95 timer->context = iface->main_context;
96 timer->func = func;
97 timer->opaque = opaque;
98
99 return &timer->base;
100 }
101
timer_func(gpointer user_data)102 static gboolean timer_func(gpointer user_data)
103 {
104 SpiceTimerGlib *timer = (SpiceTimerGlib*) user_data;
105
106 timer->func(timer->opaque);
107 /* timer might be free after func(), don't touch */
108
109 return FALSE;
110 }
111
timer_cancel(SpiceTimer * timer_base)112 static void timer_cancel(SpiceTimer *timer_base)
113 {
114 SpiceTimerGlib *timer = SPICE_UPCAST(SpiceTimerGlib, timer_base);
115 if (timer->source) {
116 g_source_destroy(timer->source);
117 g_source_unref(timer->source);
118 timer->source = NULL;
119 }
120 }
121
timer_start(SpiceTimer * timer_base,uint32_t ms)122 static void timer_start(SpiceTimer *timer_base, uint32_t ms)
123 {
124 timer_cancel(timer_base);
125
126 SpiceTimerGlib *timer = SPICE_UPCAST(SpiceTimerGlib, timer_base);
127
128 timer->source = g_timeout_source_new(ms);
129 spice_assert(timer->source != NULL);
130
131 g_source_set_callback(timer->source, timer_func, timer, NULL);
132
133 g_source_attach(timer->source, timer->context);
134 }
135
timer_remove(SpiceTimer * timer_base)136 static void timer_remove(SpiceTimer *timer_base)
137 {
138 timer_cancel(timer_base);
139
140 SpiceTimerGlib *timer = SPICE_UPCAST(SpiceTimerGlib, timer_base);
141 spice_assert(timer->source == NULL);
142 g_free(timer);
143 }
144
spice_event_to_giocondition(int event_mask)145 static GIOCondition spice_event_to_giocondition(int event_mask)
146 {
147 int condition = 0;
148
149 if (event_mask & SPICE_WATCH_EVENT_READ)
150 condition |= G_IO_IN;
151 if (event_mask & SPICE_WATCH_EVENT_WRITE)
152 condition |= G_IO_OUT;
153
154 return (GIOCondition) condition;
155 }
156
giocondition_to_spice_event(GIOCondition condition)157 static int giocondition_to_spice_event(GIOCondition condition)
158 {
159 int event = 0;
160
161 if (condition & G_IO_IN)
162 event |= SPICE_WATCH_EVENT_READ;
163 if (condition & G_IO_OUT)
164 event |= SPICE_WATCH_EVENT_WRITE;
165
166 return event;
167 }
168
169 #ifdef _WIN32
170 typedef struct SpiceWatchGlib {
171 SpiceWatch base;
172 GMainContext *context;
173 void *opaque;
174 GSource *source;
175 GIOChannel *channel;
176 SpiceWatchFunc func;
177 } SpiceWatchGlib;
178
watch_func(GIOChannel * source,GIOCondition condition,gpointer data)179 static gboolean watch_func(GIOChannel *source, GIOCondition condition,
180 gpointer data)
181 {
182 SpiceWatchGlib *watch = (SpiceWatchGlib*) data;
183 // this works also under Windows despite the name
184 int fd = g_io_channel_unix_get_fd(source);
185
186 watch->func(fd, giocondition_to_spice_event(condition), watch->opaque);
187
188 return TRUE;
189 }
190
watch_update_mask(SpiceWatch * watch_base,int event_mask)191 static void watch_update_mask(SpiceWatch *watch_base, int event_mask)
192 {
193 SpiceWatchGlib *watch = SPICE_UPCAST(SpiceWatchGlib, watch_base);
194 if (watch->source) {
195 g_source_destroy(watch->source);
196 g_source_unref(watch->source);
197 watch->source = NULL;
198 }
199
200 if (!event_mask)
201 return;
202
203 watch->source = g_io_create_watch(watch->channel, spice_event_to_giocondition(event_mask));
204 /* g_source_set_callback() documentation says:
205 * "The exact type of func depends on the type of source; ie. you should
206 * not count on func being called with data as its first parameter."
207 * In this case it is a GIOFunc. First cast to GIOFunc to make sure it is the right type.
208 * The other casts silence the warning from gcc */
209 g_source_set_callback(watch->source, (GSourceFunc)(void*)(GIOFunc)watch_func, watch, NULL);
210 g_source_attach(watch->source, watch->context);
211 }
212
watch_add(const SpiceCoreInterfaceInternal * iface,int fd,int event_mask,SpiceWatchFunc func,void * opaque)213 static SpiceWatch *watch_add(const SpiceCoreInterfaceInternal *iface,
214 int fd, int event_mask, SpiceWatchFunc func, void *opaque)
215 {
216 SpiceWatchGlib *watch;
217
218 spice_return_val_if_fail(fd != -1, NULL);
219 spice_return_val_if_fail(func != NULL, NULL);
220
221 watch = g_new0(SpiceWatchGlib, 1);
222 watch->base.funcs = &glib_core_funcs;
223 watch->context = iface->main_context;
224 watch->channel = g_io_channel_win32_new_socket(fd);
225 watch->func = func;
226 watch->opaque = opaque;
227
228 watch_update_mask(&watch->base, event_mask);
229
230 return &watch->base;
231 }
232
watch_remove(SpiceWatch * watch_base)233 static void watch_remove(SpiceWatch *watch_base)
234 {
235 SpiceWatchGlib *watch = SPICE_UPCAST(SpiceWatchGlib, watch_base);
236 watch_update_mask(watch_base, 0);
237 spice_assert(watch->source == NULL);
238
239 g_io_channel_unref(watch->channel);
240 g_free(watch);
241 }
242
243 #else
244
245 typedef struct SpiceWatchGlib {
246 GSource source;
247 SpiceWatch spice_base;
248 gpointer unix_fd;
249 int fd;
250 } SpiceWatchGlib;
251
252 static gboolean
spice_watch_check(GSource * source)253 spice_watch_check(GSource *source)
254 {
255 SpiceWatchGlib *watch = SPICE_CONTAINEROF(source, SpiceWatchGlib, source);
256
257 return g_source_query_unix_fd(&watch->source, watch->unix_fd) != 0;
258 }
259
260 static gboolean
spice_watch_dispatch(GSource * source,GSourceFunc callback,gpointer user_data)261 spice_watch_dispatch(GSource *source,
262 GSourceFunc callback,
263 gpointer user_data)
264 {
265 SpiceWatchGlib *watch = SPICE_CONTAINEROF(source, SpiceWatchGlib, source);
266 SpiceWatchFunc func = (SpiceWatchFunc)(void*) callback;
267 GIOCondition condition = g_source_query_unix_fd(&watch->source, watch->unix_fd);
268
269 func(watch->fd, giocondition_to_spice_event(condition), user_data);
270 /* timer might be free after func(), don't touch */
271
272 return G_SOURCE_CONTINUE;
273 }
274
275 static GSourceFuncs spice_watch_funcs = {
276 .check = spice_watch_check,
277 .dispatch = spice_watch_dispatch,
278 };
279
watch_update_mask(SpiceWatch * watch_base,int event_mask)280 static void watch_update_mask(SpiceWatch *watch_base, int event_mask)
281 {
282 SpiceWatchGlib *watch = SPICE_CONTAINEROF(watch_base, SpiceWatchGlib, spice_base);
283 GIOCondition condition = spice_event_to_giocondition(event_mask);
284
285 g_source_modify_unix_fd(&watch->source, watch->unix_fd, condition);
286 }
287
watch_add(const SpiceCoreInterfaceInternal * iface,int fd,int event_mask,SpiceWatchFunc func,void * opaque)288 static SpiceWatch *watch_add(const SpiceCoreInterfaceInternal *iface,
289 int fd, int event_mask, SpiceWatchFunc func, void *opaque)
290 {
291 SPICE_VERIFY(SPICE_OFFSETOF(SpiceWatchGlib, source) == 0);
292 SpiceWatchGlib *watch =
293 (SpiceWatchGlib *) g_source_new(&spice_watch_funcs, sizeof(SpiceWatchGlib));
294
295 spice_return_val_if_fail(fd != -1, NULL);
296 spice_return_val_if_fail(func != NULL, NULL);
297
298 watch->spice_base.funcs = &glib_core_funcs;
299 watch->fd = fd;
300
301 g_source_set_callback(&watch->source, (GSourceFunc)(void*) func, opaque, NULL);
302
303 g_source_attach(&watch->source, iface->main_context);
304
305 GIOCondition condition = spice_event_to_giocondition(event_mask);
306 watch->unix_fd = g_source_add_unix_fd(&watch->source, watch->fd, condition);
307
308 return &watch->spice_base;
309 }
310
watch_remove(SpiceWatch * watch_base)311 static void watch_remove(SpiceWatch *watch_base)
312 {
313 SpiceWatchGlib *watch = SPICE_CONTAINEROF(watch_base, SpiceWatchGlib, spice_base);
314
315 g_source_remove_unix_fd(&watch->source, watch->unix_fd);
316 g_source_destroy(&watch->source);
317 g_source_unref(&watch->source);
318 }
319 #endif
320
321 static const SpiceCoreFuncs glib_core_funcs = {
322 .timer_start = timer_start,
323 .timer_cancel = timer_cancel,
324 .timer_remove = timer_remove,
325
326 .watch_update_mask = watch_update_mask,
327 .watch_remove = watch_remove,
328 };
329
330 const SpiceCoreInterfaceInternal event_loop_core = {
331 .timer_add = timer_add,
332 .watch_add = watch_add,
333 };
334
335 /*
336 * Adapter for SpiceCodeInterface
337 */
338
339 static const SpiceCoreFuncs qemu_core_funcs;
340
341 typedef struct SpiceTimerQemu {
342 SpiceTimer base;
343 SpiceCoreInterface *core;
344 SpiceTimer *qemu_timer;
345 } SpiceTimerQemu;
346
adapter_timer_add(const SpiceCoreInterfaceInternal * iface,SpiceTimerFunc func,void * opaque)347 static SpiceTimer *adapter_timer_add(const SpiceCoreInterfaceInternal *iface, SpiceTimerFunc func, void *opaque)
348 {
349 SpiceTimerQemu *timer = g_new0(SpiceTimerQemu, 1);
350
351 timer->base.funcs = &qemu_core_funcs;
352 timer->core = iface->public_interface;
353 timer->qemu_timer = timer->core->timer_add(func, opaque);
354 return &timer->base;
355 }
356
adapter_timer_start(SpiceTimer * timer_,uint32_t ms)357 static void adapter_timer_start(SpiceTimer *timer_, uint32_t ms)
358 {
359 SpiceTimerQemu *timer = SPICE_UPCAST(SpiceTimerQemu, timer_);
360 timer->core->timer_start(timer->qemu_timer, ms);
361 }
362
adapter_timer_cancel(SpiceTimer * timer_)363 static void adapter_timer_cancel(SpiceTimer *timer_)
364 {
365 SpiceTimerQemu *timer = SPICE_UPCAST(SpiceTimerQemu, timer_);
366 timer->core->timer_cancel(timer->qemu_timer);
367 }
368
adapter_timer_remove(SpiceTimer * timer_)369 static void adapter_timer_remove(SpiceTimer *timer_)
370 {
371 SpiceTimerQemu *timer = SPICE_UPCAST(SpiceTimerQemu, timer_);
372 timer->core->timer_remove(timer->qemu_timer);
373 g_free(timer);
374 }
375
376 typedef struct SpiceWatchQemu {
377 SpiceWatch base;
378 SpiceCoreInterface *core;
379 SpiceWatch *qemu_watch;
380 } SpiceWatchQemu;
381
adapter_watch_add(const SpiceCoreInterfaceInternal * iface,int fd,int event_mask,SpiceWatchFunc func,void * opaque)382 static SpiceWatch *adapter_watch_add(const SpiceCoreInterfaceInternal *iface,
383 int fd, int event_mask, SpiceWatchFunc func, void *opaque)
384 {
385 // note: Qemu API is fine having a SOCKET on Windows
386 SpiceWatchQemu *watch = g_new0(SpiceWatchQemu, 1);
387
388 watch->base.funcs = &qemu_core_funcs;
389 watch->core = iface->public_interface;
390 watch->qemu_watch = watch->core->watch_add(fd, event_mask, func, opaque);
391 return &watch->base;
392 }
393
adapter_watch_update_mask(SpiceWatch * watch_,int event_mask)394 static void adapter_watch_update_mask(SpiceWatch *watch_, int event_mask)
395 {
396 SpiceWatchQemu *watch = SPICE_UPCAST(SpiceWatchQemu, watch_);
397 watch->core->watch_update_mask(watch->qemu_watch, event_mask);
398 }
399
adapter_watch_remove(SpiceWatch * watch_)400 static void adapter_watch_remove(SpiceWatch *watch_)
401 {
402 SpiceWatchQemu *watch = SPICE_UPCAST(SpiceWatchQemu, watch_);
403 watch->core->watch_remove(watch->qemu_watch);
404 g_free(watch);
405 }
406
adapter_channel_event(const SpiceCoreInterfaceInternal * iface,int event,SpiceChannelEventInfo * info)407 static void adapter_channel_event(const SpiceCoreInterfaceInternal *iface, int event, SpiceChannelEventInfo *info)
408 {
409 if (iface->public_interface->base.minor_version >= 3 && iface->public_interface->channel_event != NULL)
410 iface->public_interface->channel_event(event, info);
411 }
412
413 static const SpiceCoreFuncs qemu_core_funcs = {
414 .timer_start = adapter_timer_start,
415 .timer_cancel = adapter_timer_cancel,
416 .timer_remove = adapter_timer_remove,
417
418 .watch_update_mask = adapter_watch_update_mask,
419 .watch_remove = adapter_watch_remove,
420 };
421
422 const SpiceCoreInterfaceInternal core_interface_adapter = {
423 .timer_add = adapter_timer_add,
424 .watch_add = adapter_watch_add,
425 .channel_event = adapter_channel_event,
426 };
427