usb_moded  0.86.0+mer57
usb_moded-appsync-dbus.c
Go to the documentation of this file.
1 
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 
44 static void dbusappsync_release_name (void);
45 static gboolean dbusappsync_obtain_name (void);
46 static DBusHandlerResult dbusappsync_msg_handler (DBusConnection *const connection, DBusMessage *const msg, gpointer const user_data);
47 static DBusHandlerResult dbusappsync_handle_disconnect (DBusConnection *conn, DBusMessage *msg, void *user_data);
48 static void dbusappsync_cleanup_connection(void);
49 gboolean dbusappsync_init_connection (void);
50 gboolean dbusappsync_init (void);
51 void dbusappsync_cleanup (void);
52 int dbusappsync_launch_app (char *launch);
53 
54 /* ========================================================================= *
55  * Data
56  * ========================================================================= */
57 
58 static DBusConnection *dbus_connection_ses = NULL; // connection
59 static gboolean dbus_connection_name = FALSE; // have name
60 static gboolean dbus_connection_disc = FALSE; // got disconnected
61 
62 /* ========================================================================= *
63  * Functions
64  * ========================================================================= */
65 
66 static 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 
100 static 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 
141 EXIT:
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 
156 static 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 
221 IGNORE:
222 
223  return status;
224 }
225 
229 static 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 
245 static 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 
320 EXIT:
321  dbus_error_free(&error);
322  return result;
323 }
324 
330 gboolean 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 
344 EXIT:
345  return status;
346 }
347 
353 {
354  LOG_REGISTER_CONTEXT;
355 
356  dbusappsync_cleanup_connection();
357  // NOP
358 }
359 
363 int 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 }
USB_MODE_SERVICE
#define USB_MODE_SERVICE
Definition: usb_moded-dbus.h:42
dbusappsync_init
gboolean dbusappsync_init(void)
Definition: usb_moded-appsync-dbus.c:330
dbusappsync_cleanup
void dbusappsync_cleanup(void)
Definition: usb_moded-appsync-dbus.c:352
dbusappsync_init_connection
gboolean dbusappsync_init_connection(void)
Definition: usb_moded-appsync-dbus.c:271
appsync_mark_active
int appsync_mark_active(const char *name, int post)
Definition: usb_moded-appsync.c:708
usb_moded-appsync-dbus-private.h
dbusappsync_launch_app
int dbusappsync_launch_app(char *launch)
Definition: usb_moded-appsync-dbus.c:363
usb_moded-appsync.h
usb_moded-log.h