/
usb_moded-appsync-dbus.c
388 lines (319 loc) · 11 KB
1
/**
2
3
4
* @file usb_moded-dbus.c
*
* Copyright (C) 2010 Nokia Corporation. All rights reserved.
5
* Copyright (C) 2013-2019 Jolla Ltd.
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
*
* @author: Philippe De Swert <philippe.de-swert@nokia.com>
* @author: Philippe De Swert <phdeswer@lumi.maa>
* @author: Philippe De Swert <philippedeswert@gmail.com>
* @author: Philippe De Swert <philippe.deswert@jollamobile.com>
* @author: Simo Piiroinen <simo.piiroinen@jollamobile.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the Lesser GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
27
28
29
30
31
32
#include "usb_moded-appsync-dbus-private.h"
#include "usb_moded-appsync.h"
#include "usb_moded-log.h"
33
34
35
36
#include <string.h>
#include <dbus/dbus.h>
37
38
39
40
/* ========================================================================= *
* Prototypes
* ========================================================================= */
41
42
43
/* ------------------------------------------------------------------------- *
* DBUSAPPSYNC
* ------------------------------------------------------------------------- */
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
static void dbusappsync_release_name (void);
static gboolean dbusappsync_obtain_name (void);
static DBusHandlerResult dbusappsync_msg_handler (DBusConnection *const connection, DBusMessage *const msg, gpointer const user_data);
static DBusHandlerResult dbusappsync_handle_disconnect (DBusConnection *conn, DBusMessage *msg, void *user_data);
static void dbusappsync_cleanup_connection(void);
gboolean dbusappsync_init_connection (void);
gboolean dbusappsync_init (void);
void dbusappsync_cleanup (void);
int dbusappsync_launch_app (char *launch);
/* ========================================================================= *
* Data
* ========================================================================= */
59
60
61
62
static DBusConnection *dbus_connection_ses = NULL; // connection
static gboolean dbus_connection_name = FALSE; // have name
static gboolean dbus_connection_disc = FALSE; // got disconnected
63
64
65
/* ========================================================================= *
* Functions
* ========================================================================= */
66
67
static void dbusappsync_release_name(void)
68
{
69
70
LOG_REGISTER_CONTEXT;
71
72
/* Drop the service name - if we have it */
if( dbus_connection_ses && dbus_connection_name )
73
{
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
DBusError error = DBUS_ERROR_INIT;
int ret = dbus_bus_release_name(dbus_connection_ses, USB_MODE_SERVICE, &error);
switch( ret )
{
case DBUS_RELEASE_NAME_REPLY_RELEASED:
// as expected
log_debug("released name: %s", USB_MODE_SERVICE);
break;
case DBUS_RELEASE_NAME_REPLY_NON_EXISTENT:
// weird, but since nobody owns the name ...
log_debug("nonexisting name: %s", USB_MODE_SERVICE);
break;
case DBUS_RELEASE_NAME_REPLY_NOT_OWNER:
log_warning("somebody else owns: %s", USB_MODE_SERVICE);
}
if( dbus_error_is_set(&error) )
{
log_debug("DBUS ERROR: %s, %s \n", error.name, error.message);
dbus_error_free(&error);
}
96
97
}
98
dbus_connection_name = FALSE;
99
100
}
101
static gboolean dbusappsync_obtain_name(void)
102
{
103
104
LOG_REGISTER_CONTEXT;
105
DBusError error = DBUS_ERROR_INIT;
106
107
int ret;
108
109
110
111
112
if( dbus_connection_name )
{
goto EXIT;
}
113
114
115
116
117
if( dbus_connection_ses == 0 )
{
goto EXIT;
}
118
119
120
/* Acquire D-Bus service name */
ret = dbus_bus_request_name(dbus_connection_ses, USB_MODE_SERVICE, DBUS_NAME_FLAG_DO_NOT_QUEUE , &error);
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
switch( ret )
{
case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
// expected result
log_debug("primary owner of: %s", USB_MODE_SERVICE);
break;
case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
// functionally ok, but we do have a logic error somewhere
log_warning("already owner of: %s", USB_MODE_SERVICE);
break;
default:
// something odd
log_err("failed to claim: %s", USB_MODE_SERVICE);
goto EXIT;
}
139
140
dbus_connection_name = TRUE;
141
142
143
EXIT:
144
145
146
147
148
if( dbus_error_is_set(&error) )
{
log_debug("DBUS ERROR: %s, %s \n", error.name, error.message);
dbus_error_free(&error);
}
149
150
return dbus_connection_name;
151
152
}
153
154
155
/**
* Handle USB_MODE_INTERFACE method calls
*/
156
157
static DBusHandlerResult dbusappsync_msg_handler(DBusConnection *const connection, DBusMessage *const msg, gpointer const user_data)
158
{
159
160
LOG_REGISTER_CONTEXT;
161
162
163
164
165
DBusHandlerResult status = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
int type = dbus_message_get_type(msg);
const char *interface = dbus_message_get_interface(msg);
const char *member = dbus_message_get_member(msg);
const char *object = dbus_message_get_path(msg);
166
167
if(!interface || !member || !object) goto IGNORE;
168
169
170
171
if( type == DBUS_MESSAGE_TYPE_METHOD_CALL &&
!strcmp(interface, USB_MODE_INTERFACE) &&
!strcmp(object, USB_MODE_OBJECT) )
172
173
{
174
175
176
177
178
179
180
181
182
183
184
185
186
187
DBusMessage *reply = 0;
status = DBUS_HANDLER_RESULT_HANDLED;
if(!strcmp(member, USB_MODE_APP_STATE))
{
char *use = 0;
DBusError err = DBUS_ERROR_INIT;
if(!dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &use, DBUS_TYPE_INVALID))
{
// could not parse method call args
reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member);
}
188
else if( appsync_mark_active(use, 1) < 0 )
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
{
// name could not be marked active
reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member);
}
else if((reply = dbus_message_new_method_return(msg)))
{
// generate normal reply
dbus_message_append_args (reply, DBUS_TYPE_STRING, &use, DBUS_TYPE_INVALID);
}
dbus_error_free(&err);
}
else
{
/*unknown methods are handled here */
reply = dbus_message_new_error(msg, DBUS_ERROR_UNKNOWN_METHOD, member);
}
if( !dbus_message_get_no_reply(msg) )
{
if( !reply )
{
// we failed to generate reply above -> generate one
reply = dbus_message_new_error(msg, DBUS_ERROR_FAILED, member);
}
if( !reply || !dbus_connection_send(connection, reply, 0) )
{
log_debug("Failed sending reply. Out Of Memory!\n");
}
}
if( reply ) dbus_message_unref(reply);
220
221
222
223
}
IGNORE:
224
return status;
225
226
227
228
229
}
/**
* Handle disconnect signals
*/
230
static DBusHandlerResult dbusappsync_handle_disconnect(DBusConnection *conn, DBusMessage *msg, void *user_data)
231
{
232
233
LOG_REGISTER_CONTEXT;
234
235
236
237
238
239
240
if( dbus_message_is_signal(msg, DBUS_INTERFACE_LOCAL, "Disconnected") )
{
log_warning("disconnected from session bus - expecting restart/stop soon\n");
dbus_connection_disc = TRUE;
dbusappsync_cleanup_connection();
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
241
}
242
243
244
245
/**
* Detach from session bus
*/
246
static void dbusappsync_cleanup_connection(void)
247
{
248
249
LOG_REGISTER_CONTEXT;
250
if( dbus_connection_ses != 0 )
251
{
252
253
254
255
256
257
258
259
260
261
262
263
264
/* Remove message filters */
dbus_connection_remove_filter(dbus_connection_ses, dbusappsync_msg_handler, 0);
dbus_connection_remove_filter(dbus_connection_ses, dbusappsync_handle_disconnect, 0);
/* Release name, but only if we can still talk to dbus daemon */
if( !dbus_connection_disc )
{
dbusappsync_release_name();
}
dbus_connection_unref(dbus_connection_ses);
dbus_connection_ses = NULL;
//dbus_connection_disc = FALSE;
265
}
266
log_debug("succesfully cleaned up appsync dbus\n");
267
}
268
269
270
271
/**
* Attach to session bus
*/
272
gboolean dbusappsync_init_connection(void)
273
{
274
275
LOG_REGISTER_CONTEXT;
276
277
gboolean result = FALSE;
DBusError error = DBUS_ERROR_INIT;
278
279
280
281
282
283
if( dbus_connection_ses != 0 )
{
result = TRUE;
goto EXIT;
}
284
285
286
287
288
289
if( dbus_connection_disc )
{
// we've already observed death of session
goto EXIT;
}
290
291
292
293
294
295
296
/* Connect to session bus */
if ((dbus_connection_ses = dbus_bus_get(DBUS_BUS_SESSION, &error)) == NULL)
{
log_err("Failed to open connection to session message bus; %s\n", error.message);
goto EXIT;
}
297
298
299
/* Add disconnect handler */
dbus_connection_add_filter(dbus_connection_ses, dbusappsync_handle_disconnect, 0, 0);
300
301
302
/* Add method call handler */
dbus_connection_add_filter(dbus_connection_ses, dbusappsync_msg_handler, 0, 0);
303
304
305
/* Make sure we do not get forced to exit if dbus session dies or stops */
dbus_connection_set_exit_on_disconnect(dbus_connection_ses, FALSE);
306
307
/* Connect D-Bus to the mainloop (Seems it is only needed once and is done at the main
308
309
* D-Bus init
* dbus_connection_setup_with_g_main(dbus_connection_ses, NULL);
310
*/
311
312
313
314
315
316
/* Request service name */
if( !dbusappsync_obtain_name() )
{
goto EXIT;
}
317
318
319
/* everything went fine */
result = TRUE;
320
321
EXIT:
322
323
dbus_error_free(&error);
return result;
324
325
326
327
328
329
330
}
/**
* Init dbus for usb_moded application synchronisation
*
* @return TRUE when everything went ok
*/
331
gboolean dbusappsync_init(void)
332
{
333
334
LOG_REGISTER_CONTEXT;
335
gboolean status = FALSE;
336
337
338
339
340
if( !dbusappsync_init_connection() )
{
goto EXIT;
}
341
342
343
/* everything went fine */
status = TRUE;
344
345
EXIT:
346
return status;
347
348
349
}
/**
350
* Clean up the dbus connections for the application
351
352
* synchronisation after sync is done
*/
353
void dbusappsync_cleanup(void)
354
{
355
356
LOG_REGISTER_CONTEXT;
357
358
dbusappsync_cleanup_connection();
// NOP
359
360
}
361
362
363
/**
* Launch applications over dbus that need to be synchronized
*/
364
int dbusappsync_launch_app(char *launch)
365
{
366
367
LOG_REGISTER_CONTEXT;
368
369
370
int ret = -1; // assume failure
if( dbus_connection_ses == 0 )
371
{
372
log_err("could not start '%s': no session bus connection", launch);
373
374
375
}
else
{
376
377
378
379
380
381
382
383
384
385
DBusError error = DBUS_ERROR_INIT;
if( !dbus_bus_start_service_by_name(dbus_connection_ses, launch, 0, NULL, &error) )
{
log_err("could not start '%s': %s: %s", launch, error.name, error.message);
dbus_error_free(&error);
}
else
{
ret = 0; // success
}
386
}
387
return ret;
388
}