usb_moded 0.86.0+mer64
usb_moded-appsync-dbus.c
Go to the documentation of this file.
1
28
30
31#include "usb_moded-appsync.h"
32#include "usb_moded-log.h"
33
34#include <dbus/dbus.h>
35
36/* ========================================================================= *
37 * Prototypes
38 * ========================================================================= */
39
40/* ------------------------------------------------------------------------- *
41 * DBUSAPPSYNC
42 * ------------------------------------------------------------------------- */
43
44static void dbusappsync_release_name (void);
45static gboolean dbusappsync_obtain_name (void);
46static DBusHandlerResult dbusappsync_msg_handler (DBusConnection *const connection, DBusMessage *const msg, gpointer const user_data);
47static DBusHandlerResult dbusappsync_handle_disconnect (DBusConnection *conn, DBusMessage *msg, void *user_data);
48static void dbusappsync_cleanup_connection(void);
49gboolean dbusappsync_init_connection (void);
50gboolean dbusappsync_init (void);
51void dbusappsync_cleanup (void);
52int dbusappsync_launch_app (char *launch);
53
54/* ========================================================================= *
55 * Data
56 * ========================================================================= */
57
58static DBusConnection *dbus_connection_ses = NULL; // connection
59static gboolean dbus_connection_name = FALSE; // have name
60static gboolean dbus_connection_disc = FALSE; // got disconnected
61
62/* ========================================================================= *
63 * Functions
64 * ========================================================================= */
65
66static void dbusappsync_release_name(void)
67{
68 LOG_REGISTER_CONTEXT;
69
70 /* Drop the service name - if we have it */
71 if( dbus_connection_ses && dbus_connection_name )
72 {
73 DBusError error = DBUS_ERROR_INIT;
74 int ret = dbus_bus_release_name(dbus_connection_ses, USB_MODE_SERVICE, &error);
75
76 switch( ret )
77 {
78 case DBUS_RELEASE_NAME_REPLY_RELEASED:
79 // as expected
80 log_debug("released name: %s", USB_MODE_SERVICE);
81 break;
82 case DBUS_RELEASE_NAME_REPLY_NON_EXISTENT:
83 // weird, but since nobody owns the name ...
84 log_debug("nonexisting name: %s", USB_MODE_SERVICE);
85 break;
86 case DBUS_RELEASE_NAME_REPLY_NOT_OWNER:
87 log_warning("somebody else owns: %s", USB_MODE_SERVICE);
88 }
89
90 if( dbus_error_is_set(&error) )
91 {
92 log_debug("DBUS ERROR: %s, %s", error.name, error.message);
93 dbus_error_free(&error);
94 }
95 }
96
97 dbus_connection_name = FALSE;
98}
99
100static gboolean dbusappsync_obtain_name(void)
101{
102 LOG_REGISTER_CONTEXT;
103
104 DBusError error = DBUS_ERROR_INIT;
105
106 int ret;
107
108 if( dbus_connection_name )
109 {
110 goto EXIT;
111 }
112
113 if( dbus_connection_ses == 0 )
114 {
115 goto EXIT;
116 }
117
118 /* Acquire D-Bus service name */
119 ret = dbus_bus_request_name(dbus_connection_ses, USB_MODE_SERVICE, DBUS_NAME_FLAG_DO_NOT_QUEUE , &error);
120
121 switch( ret )
122 {
123 case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
124 // expected result
125 log_debug("primary owner of: %s", USB_MODE_SERVICE);
126 break;
127
128 case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
129 // functionally ok, but we do have a logic error somewhere
130 log_warning("already owner of: %s", USB_MODE_SERVICE);
131 break;
132
133 default:
134 // something odd
135 log_err("failed to claim: %s", USB_MODE_SERVICE);
136 goto EXIT;
137 }
138
139 dbus_connection_name = TRUE;
140
141EXIT:
142
143 if( dbus_error_is_set(&error) )
144 {
145 log_debug("DBUS ERROR: %s, %s", error.name, error.message);
146 dbus_error_free(&error);
147 }
148
149 return dbus_connection_name;
150}
151
155
156static DBusHandlerResult dbusappsync_msg_handler(DBusConnection *const connection, DBusMessage *const msg, gpointer const user_data)
157{
158 LOG_REGISTER_CONTEXT;
159
160 DBusHandlerResult status = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
161 int type = dbus_message_get_type(msg);
162 const char *interface = dbus_message_get_interface(msg);
163 const char *member = dbus_message_get_member(msg);
164 const char *object = dbus_message_get_path(msg);
165
166 if(!interface || !member || !object) goto IGNORE;
167
168 if( type == DBUS_MESSAGE_TYPE_METHOD_CALL &&
169 !strcmp(interface, USB_MODE_INTERFACE) &&
170 !strcmp(object, USB_MODE_OBJECT) )
171
172 {
173 DBusMessage *reply = 0;
174
175 status = DBUS_HANDLER_RESULT_HANDLED;
176
177 if(!strcmp(member, USB_MODE_APP_STATE))
178 {
179 char *use = 0;
180 DBusError err = DBUS_ERROR_INIT;
181
182 if(!dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &use, DBUS_TYPE_INVALID))
183 {
184 // could not parse method call args
185 reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member);
186 }
187 else if( appsync_mark_active(use, 1) < 0 )
188 {
189 // name could not be marked active
190 reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member);
191 }
192 else if((reply = dbus_message_new_method_return(msg)))
193 {
194 // generate normal reply
195 dbus_message_append_args (reply, DBUS_TYPE_STRING, &use, DBUS_TYPE_INVALID);
196 }
197 dbus_error_free(&err);
198 }
199 else
200 {
201 /*unknown methods are handled here */
202 reply = dbus_message_new_error(msg, DBUS_ERROR_UNKNOWN_METHOD, member);
203 }
204
205 if( !dbus_message_get_no_reply(msg) )
206 {
207 if( !reply )
208 {
209 // we failed to generate reply above -> generate one
210 reply = dbus_message_new_error(msg, DBUS_ERROR_FAILED, member);
211 }
212 if( !reply || !dbus_connection_send(connection, reply, 0) )
213 {
214 log_debug("Failed sending reply. Out Of Memory!\n");
215 }
216 }
217
218 if( reply ) dbus_message_unref(reply);
219 }
220
221IGNORE:
222
223 return status;
224}
225
229static DBusHandlerResult dbusappsync_handle_disconnect(DBusConnection *conn, DBusMessage *msg, void *user_data)
230{
231 LOG_REGISTER_CONTEXT;
232
233 if( dbus_message_is_signal(msg, DBUS_INTERFACE_LOCAL, "Disconnected") )
234 {
235 log_warning("disconnected from session bus - expecting restart/stop soon\n");
236 dbus_connection_disc = TRUE;
237 dbusappsync_cleanup_connection();
238 }
239 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
240}
241
245static void dbusappsync_cleanup_connection(void)
246{
247 LOG_REGISTER_CONTEXT;
248
249 if( dbus_connection_ses != 0 )
250 {
251 /* Remove message filters */
252 dbus_connection_remove_filter(dbus_connection_ses, dbusappsync_msg_handler, 0);
253 dbus_connection_remove_filter(dbus_connection_ses, dbusappsync_handle_disconnect, 0);
254
255 /* Release name, but only if we can still talk to dbus daemon */
256 if( !dbus_connection_disc )
257 {
258 dbusappsync_release_name();
259 }
260
261 dbus_connection_unref(dbus_connection_ses);
262 dbus_connection_ses = NULL;
263 //dbus_connection_disc = FALSE;
264 }
265 log_debug("succesfully cleaned up appsync dbus\n");
266}
267
272{
273 LOG_REGISTER_CONTEXT;
274
275 gboolean result = FALSE;
276 DBusError error = DBUS_ERROR_INIT;
277
278 if( dbus_connection_ses != 0 )
279 {
280 result = TRUE;
281 goto EXIT;
282 }
283
284 if( dbus_connection_disc )
285 {
286 // we've already observed death of session
287 goto EXIT;
288 }
289
290 /* Connect to session bus */
291 if ((dbus_connection_ses = dbus_bus_get(DBUS_BUS_SESSION, &error)) == NULL)
292 {
293 log_err("Failed to open connection to session message bus; %s\n", error.message);
294 goto EXIT;
295 }
296
297 /* Add disconnect handler */
298 dbus_connection_add_filter(dbus_connection_ses, dbusappsync_handle_disconnect, 0, 0);
299
300 /* Add method call handler */
301 dbus_connection_add_filter(dbus_connection_ses, dbusappsync_msg_handler, 0, 0);
302
303 /* Make sure we do not get forced to exit if dbus session dies or stops */
304 dbus_connection_set_exit_on_disconnect(dbus_connection_ses, FALSE);
305
306 /* Connect D-Bus to the mainloop (Seems it is only needed once and is done at the main
307 * D-Bus init
308 * dbus_connection_setup_with_g_main(dbus_connection_ses, NULL);
309 */
310
311 /* Request service name */
312 if( !dbusappsync_obtain_name() )
313 {
314 goto EXIT;
315 }
316
317 /* everything went fine */
318 result = TRUE;
319
320EXIT:
321 dbus_error_free(&error);
322 return result;
323}
324
330gboolean dbusappsync_init(void)
331{
332 LOG_REGISTER_CONTEXT;
333
334 gboolean status = FALSE;
335
337 {
338 goto EXIT;
339 }
340
341 /* everything went fine */
342 status = TRUE;
343
344EXIT:
345 return status;
346}
347
353{
354 LOG_REGISTER_CONTEXT;
355
356 dbusappsync_cleanup_connection();
357 // NOP
358}
359
363int dbusappsync_launch_app(char *launch)
364{
365 LOG_REGISTER_CONTEXT;
366
367 int ret = -1; // assume failure
368
369 if( dbus_connection_ses == 0 )
370 {
371 log_err("could not start '%s': no session bus connection", launch);
372 }
373 else
374 {
375 DBusError error = DBUS_ERROR_INIT;
376 if( !dbus_bus_start_service_by_name(dbus_connection_ses, launch, 0, NULL, &error) )
377 {
378 log_err("could not start '%s': %s: %s", launch, error.name, error.message);
379 dbus_error_free(&error);
380 }
381 else
382 {
383 ret = 0; // success
384 }
385 }
386 return ret;
387}
gboolean dbusappsync_init_connection(void)
void dbusappsync_cleanup(void)
gboolean dbusappsync_init(void)
int dbusappsync_launch_app(char *launch)
int appsync_mark_active(const char *name, int post)