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