/
usb_moded-dbus.c
548 lines (493 loc) · 16.9 KB
1
2
3
4
/**
@file usb_moded-dbus.c
Copyright (C) 2010 Nokia Corporation. All rights reserved.
5
Copyright (C) 2012-2015 Jolla. All rights reserved.
6
7
@author: Philippe De Swert <philippe.de-swert@nokia.com>
8
@author: Philippe De Swert <philippe.deswert@jollamobile.com>
9
10
This program is free software; you can redistribute it and/or
11
12
modify it under the terms of the Lesser GNU General Public License
version 2 as published by the Free Software Foundation.
13
14
15
16
17
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.
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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
*/
#include <stdio.h>
#include <string.h>
#include <dbus/dbus.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
#include "usb_moded-dbus.h"
#include "usb_moded-dbus-private.h"
#include "usb_moded.h"
#include "usb_moded-modes.h"
36
#include "usb_moded-modesetting.h"
37
#include "usb_moded-config.h"
38
#include "usb_moded-config-private.h"
39
#include "usb_moded-network.h"
40
41
#include "usb_moded-log.h"
42
43
44
45
#define INIT_DONE_INTERFACE "com.nokia.startup.signal"
#define INIT_DONE_SIGNAL "init_done"
#define INIT_DONE_MATCH "type='signal',interface='"INIT_DONE_INTERFACE"',member='"INIT_DONE_SIGNAL"'"
46
static DBusConnection *dbus_connection_sys = NULL;
47
extern gboolean rescue_mode;
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/**
* Issues "sig_usb_config_ind" signal.
*/
static void usb_moded_send_config_signal(const char *section, const char *key, const char *value)
{
log_debug(USB_MODE_CONFIG_SIGNAL_NAME ": %s %s %s\n", section, key, value);
if (dbus_connection_sys)
{
DBusMessage* msg = dbus_message_new_signal(USB_MODE_OBJECT, USB_MODE_INTERFACE, USB_MODE_CONFIG_SIGNAL_NAME);
if (msg) {
dbus_message_append_args(msg, DBUS_TYPE_STRING, §ion,
DBUS_TYPE_STRING, &key,
DBUS_TYPE_STRING, &value,
DBUS_TYPE_INVALID);
dbus_connection_send(dbus_connection_sys, msg, NULL);
dbus_message_unref(msg);
}
}
}
69
70
71
72
73
74
75
76
static DBusHandlerResult msg_handler(DBusConnection *const connection, DBusMessage *const msg, gpointer const user_data)
{
DBusHandlerResult status = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
DBusMessage *reply = 0;
const char *interface = dbus_message_get_interface(msg);
const char *member = dbus_message_get_member(msg);
const char *object = dbus_message_get_path(msg);
int type = dbus_message_get_type(msg);
77
const char *xml = "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
"\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
"<node name=\"" USB_MODE_OBJECT "\">\n"
" <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
" <method name=\"Introspect\">\n"
" <arg name=\"xml\" type=\"s\" direction=\"out\"/>\n"
" </method>\n"
" </interface>\n"
" <interface name=\"" USB_MODE_INTERFACE "\">\n"
" <method name=\"" USB_MODE_STATE_REQUEST "\">\n"
" <arg name=\"mode\" type=\"s\" direction=\"out\"/>\n"
" </method>\n"
" <method name=\"" USB_MODE_STATE_SET "\">\n"
" <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n"
" <arg name=\"mode\" type=\"s\" direction=\"out\"/>\n"
" </method>\n"
" <method name=\"" USB_MODE_CONFIG_SET "\">\n"
" <arg name=\"config\" type=\"s\" direction=\"in\"/>\n"
" <arg name=\"config\" type=\"s\" direction=\"out\"/>\n"
" </method>\n"
" <method name=\"" USB_MODE_NETWORK_SET "\">\n"
" <arg name=\"key\" type=\"s\" direction=\"in\"/>\n"
" <arg name=\"value\" type=\"s\" direction=\"in\"/>\n"
" <arg name=\"key\" type=\"s\" direction=\"out\"/>\n"
" <arg name=\"value\" type=\"s\" direction=\"out\"/>\n"
" </method>\n"
" <method name=\"" USB_MODE_NETWORK_GET "\">\n"
" <arg name=\"key\" type=\"s\" direction=\"in\"/>\n"
" <arg name=\"key\" type=\"s\" direction=\"out\"/>\n"
" <arg name=\"value\" type=\"s\" direction=\"out\"/>\n"
" </method>\n"
" <method name=\"" USB_MODE_CONFIG_GET "\">\n"
" <arg name=\"mode\" type=\"s\" direction=\"out\"/>\n"
" </method>\n"
" <method name=\"" USB_MODE_LIST "\">\n"
" <arg name=\"modes\" type=\"s\" direction=\"out\"/>\n"
" </method>\n"
" <method name=\"" USB_MODE_RESCUE_OFF "\"/>\n"
" <signal name=\"" USB_MODE_SIGNAL_NAME "\">\n"
" <arg name=\"mode\" type=\"s\"/>\n"
" </signal>\n"
" <signal name=\"" USB_MODE_ERROR_SIGNAL_NAME "\">\n"
" <arg name=\"error\" type=\"s\"/>\n"
" </signal>\n"
" <signal name=\"" USB_MODE_SUPPORTED_MODES_SIGNAL_NAME "\">\n"
" <arg name=\"modes\" type=\"s\"/>\n"
" </signal>\n"
124
125
126
127
128
" <signal name=\"" USB_MODE_CONFIG_SIGNAL_NAME "\">\n"
" <arg name=\"section\" type=\"s\"/>\n"
" <arg name=\"key\" type=\"s\"/>\n"
" <arg name=\"value\" type=\"s\"/>\n"
" </signal>\n"
129
130
" </interface>\n"
"</node>\n";
131
132
133
134
135
(void)user_data;
if(!interface || !member || !object) goto EXIT;
136
137
138
139
140
141
142
143
144
145
146
147
if( type == DBUS_MESSAGE_TYPE_SIGNAL )
{
if( !strcmp(interface, INIT_DONE_INTERFACE) && !strcmp(member, INIT_DONE_SIGNAL) ) {
/* Auto-disable rescue mode when bootup is finished */
if( rescue_mode ) {
rescue_mode = FALSE;
log_debug("init done reached - rescue mode disabled");
}
}
goto EXIT;
}
148
149
if( type == DBUS_MESSAGE_TYPE_METHOD_CALL && !strcmp(interface, USB_MODE_INTERFACE) && !strcmp(object, USB_MODE_OBJECT))
{
150
151
152
153
status = DBUS_HANDLER_RESULT_HANDLED;
if(!strcmp(member, USB_MODE_STATE_REQUEST))
{
154
const char *mode = get_usb_mode();
155
156
157
/* To the outside we want to keep CHARGING and CHARGING_FALLBACK the same */
if(!strcmp(MODE_CHARGING_FALLBACK, mode))
158
mode = MODE_CHARGING;
159
160
161
162
163
164
165
166
167
168
if((reply = dbus_message_new_method_return(msg)))
dbus_message_append_args (reply, DBUS_TYPE_STRING, &mode, DBUS_TYPE_INVALID);
}
else if(!strcmp(member, USB_MODE_STATE_SET))
{
char *use = 0;
DBusError err = DBUS_ERROR_INIT;
if(!dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &use, DBUS_TYPE_INVALID))
reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member);
169
170
171
172
else
{
/* check if usb is connected, since it makes no sense to change mode if it isn't */
if(!get_usb_connection_state())
173
174
{
log_warning("USB not connected, not changing mode!\n");
175
goto error_reply;
176
}
177
178
179
/* check if the mode exists */
if(valid_mode(use))
goto error_reply;
180
181
/* do not change mode if the mode requested is the one already set */
if(strcmp(use, get_usb_mode()) != 0)
182
183
{
usb_moded_mode_cleanup(get_usb_module());
184
set_usb_mode(use);
185
}
186
187
if((reply = dbus_message_new_method_return(msg)))
dbus_message_append_args (reply, DBUS_TYPE_STRING, &use, DBUS_TYPE_INVALID);
188
else
189
error_reply:
190
reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member);
191
192
193
194
195
}
dbus_error_free(&err);
}
else if(!strcmp(member, USB_MODE_CONFIG_SET))
{
196
197
char *config = 0;
DBusError err = DBUS_ERROR_INIT;
198
199
200
if(!dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &config, DBUS_TYPE_INVALID))
reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member);
201
202
else
{
203
/* error checking is done when setting configuration */
204
205
206
207
int ret = set_mode_setting(config);
if (ret == SET_CONFIG_UPDATED)
usb_moded_send_config_signal(MODE_SETTING_ENTRY, MODE_SETTING_KEY, config);
if (SET_CONFIG_OK(ret))
208
{
209
210
if((reply = dbus_message_new_method_return(msg)))
dbus_message_append_args (reply, DBUS_TYPE_STRING, &config, DBUS_TYPE_INVALID);
211
212
}
else
213
reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, config);
214
}
215
dbus_error_free(&err);
216
217
218
}
else if(!strcmp(member, USB_MODE_HIDE))
{
219
220
char *config = 0;
DBusError err = DBUS_ERROR_INIT;
221
222
223
if(!dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &config, DBUS_TYPE_INVALID))
reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member);
224
225
226
227
228
229
230
231
else
{
/* error checking is done when setting configuration */
int ret = set_hide_mode_setting(config);
if (ret == SET_CONFIG_UPDATED)
usb_moded_send_config_signal(MODE_SETTING_ENTRY, MODE_HIDE_KEY, config);
if (SET_CONFIG_OK(ret))
{
232
233
if((reply = dbus_message_new_method_return(msg)))
dbus_message_append_args (reply, DBUS_TYPE_STRING, &config, DBUS_TYPE_INVALID);
234
235
}
else
236
reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, config);
237
}
238
dbus_error_free(&err);
239
240
241
}
else if(!strcmp(member, USB_MODE_UNHIDE))
{
242
243
char *config = 0;
DBusError err = DBUS_ERROR_INIT;
244
245
246
if(!dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &config, DBUS_TYPE_INVALID))
reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member);
247
248
249
250
251
252
253
else
{
/* error checking is done when setting configuration */
int ret = set_unhide_mode_setting(config);
if (ret == SET_CONFIG_UPDATED)
usb_moded_send_config_signal(MODE_SETTING_ENTRY, MODE_HIDE_KEY, config);
if (SET_CONFIG_OK(ret))
254
{
255
256
if((reply = dbus_message_new_method_return(msg)))
dbus_message_append_args (reply, DBUS_TYPE_STRING, &config, DBUS_TYPE_INVALID);
257
258
}
else
259
reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, config);
260
}
261
dbus_error_free(&err);
262
}
263
264
265
266
else if(!strcmp(member, USB_MODE_HIDDEN_GET))
{
char *config = get_hidden_modes();
if(!config)
267
config = g_strdup("");
268
269
if((reply = dbus_message_new_method_return(msg)))
dbus_message_append_args (reply, DBUS_TYPE_STRING, &config, DBUS_TYPE_INVALID);
270
g_free(config);
271
}
272
273
else if(!strcmp(member, USB_MODE_NETWORK_SET))
{
274
275
char *config = 0, *setting = 0;
DBusError err = DBUS_ERROR_INIT;
276
277
278
if(!dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &config, DBUS_TYPE_STRING, &setting, DBUS_TYPE_INVALID))
reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member);
279
280
else
{
281
/* error checking is done when setting configuration */
282
283
284
285
int ret = set_network_setting(config, setting);
if (ret == SET_CONFIG_UPDATED)
usb_moded_send_config_signal(NETWORK_ENTRY, config, setting);
if (SET_CONFIG_OK(ret))
286
{
287
288
if((reply = dbus_message_new_method_return(msg)))
dbus_message_append_args (reply, DBUS_TYPE_STRING, &config, DBUS_TYPE_STRING, &setting, DBUS_TYPE_INVALID);
289
usb_network_update();
290
291
}
else
292
reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, config);
293
}
294
dbus_error_free(&err);
295
}
296
297
298
else if(!strcmp(member, USB_MODE_NETWORK_GET))
{
char *config = 0;
299
char *setting = 0;
300
301
302
303
304
305
306
307
308
309
310
311
312
DBusError err = DBUS_ERROR_INIT;
if(!dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &config, DBUS_TYPE_INVALID))
{
reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, member);
}
else
{
setting = get_network_setting(config);
if(setting)
{
if((reply = dbus_message_new_method_return(msg)))
dbus_message_append_args (reply, DBUS_TYPE_STRING, &config, DBUS_TYPE_STRING, &setting, DBUS_TYPE_INVALID);
313
free(setting);
314
315
316
317
318
}
else
reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, config);
}
}
319
320
else if(!strcmp(member, USB_MODE_CONFIG_GET))
{
321
char *config = get_mode_setting();
322
323
324
325
326
327
328
329
if(!config)
{
/* Config is corrupted or we do not have a mode
* configured, fallback to undefined. */
config = g_strdup(MODE_UNDEFINED);
}
330
331
if((reply = dbus_message_new_method_return(msg)))
dbus_message_append_args (reply, DBUS_TYPE_STRING, &config, DBUS_TYPE_INVALID);
332
g_free(config);
333
}
334
335
else if(!strcmp(member, USB_MODE_LIST))
{
336
gchar *mode_list = get_mode_list();
337
338
if((reply = dbus_message_new_method_return(msg)))
339
340
dbus_message_append_args (reply, DBUS_TYPE_STRING, (const char *) &mode_list, DBUS_TYPE_INVALID);
g_free(mode_list);
341
}
342
343
344
else if(!strcmp(member, USB_MODE_RESCUE_OFF))
{
rescue_mode = FALSE;
345
log_debug("Rescue mode off\n ");
346
347
reply = dbus_message_new_method_return(msg);
}
348
349
350
351
352
353
354
355
356
357
else
{
/*unknown methods are handled here */
reply = dbus_message_new_error(msg, DBUS_ERROR_UNKNOWN_METHOD, member);
}
if( !reply )
{
reply = dbus_message_new_error(msg, DBUS_ERROR_FAILED, member);
}
358
359
360
361
}
else if( type == DBUS_MESSAGE_TYPE_METHOD_CALL && !strcmp(interface, "org.freedesktop.DBus.Introspectable") &&
!strcmp(object, USB_MODE_OBJECT) && !strcmp(member, "Introspect"))
{
362
status = DBUS_HANDLER_RESULT_HANDLED;
363
364
if((reply = dbus_message_new_method_return(msg)))
365
366
367
368
369
370
371
372
dbus_message_append_args (reply, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID);
}
EXIT:
if(reply)
{
373
374
375
376
377
378
if( !dbus_message_get_no_reply(msg) )
{
if( !dbus_connection_send(connection, reply, 0) )
log_debug("Failed sending reply. Out Of Memory!\n");
}
dbus_message_unref(reply);
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
}
return status;
}
/**
* Init dbus for usb_moded
*
* @return TRUE when everything went ok
*/
gboolean usb_moded_dbus_init(void)
{
gboolean status = FALSE;
DBusError error;
int ret;
dbus_error_init(&error);
/* connect to system bus */
398
if ((dbus_connection_sys = dbus_bus_get(DBUS_BUS_SYSTEM, &error)) == NULL)
399
{
400
log_debug("Failed to open connection to system message bus; %s\n", error.message);
401
402
403
404
goto EXIT;
}
/* Initialise message handlers */
405
406
if (!dbus_connection_add_filter(dbus_connection_sys, msg_handler, NULL, NULL))
goto EXIT;
407
408
409
/* Acquire D-Bus service */
ret = dbus_bus_request_name(dbus_connection_sys, USB_MODE_SERVICE, DBUS_NAME_FLAG_DO_NOT_QUEUE, &error);
410
if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
411
412
413
414
415
416
417
418
419
420
421
{
log_debug("failed claiming dbus name\n");
if( dbus_error_is_set(&error) )
log_debug("DBUS ERROR: %s, %s \n", error.name, error.message);
goto EXIT;
}
/* only match on signals/methods we support (if needed)
dbus_bus_add_match(dbus_connection_sys, USB_MODE_INTERFACE, &error);
*/
422
423
424
/* Listen to init-done signals */
dbus_bus_add_match(dbus_connection_sys, INIT_DONE_MATCH, 0);
425
426
dbus_threads_init_default();
427
428
429
430
431
432
/* Connect D-Bus to the mainloop */
dbus_connection_setup_with_g_main(dbus_connection_sys, NULL);
/* everything went fine */
status = TRUE;
433
EXIT:
434
435
436
437
438
439
440
441
442
443
444
dbus_error_free(&error);
return status;
}
/**
* Clean up the dbus connections on exit
*
*/
void usb_moded_dbus_cleanup(void)
{
/* clean up system bus connection */
445
if (dbus_connection_sys != NULL)
446
{
447
dbus_bus_release_name(dbus_connection_sys, USB_MODE_SERVICE, NULL);
448
449
450
451
452
453
454
dbus_connection_remove_filter(dbus_connection_sys, msg_handler, NULL);
dbus_connection_unref(dbus_connection_sys);
dbus_connection_sys = NULL;
}
}
/**
455
* Helper function for sending the different signals
456
*
457
* @return 0 on success, 1 on failure
458
459
* @param signal_type the type of signal (normal, error, ...)
* @@param content string which can be mode name, error, list of modes, ...
460
*/
461
static int usb_moded_dbus_signal(const char *signal_type, const char *content)
462
463
464
465
{
int result = 1;
DBusMessage* msg = 0;
466
467
468
469
470
if(!dbus_connection_sys)
{
log_err("Dbus system connection broken!\n");
goto EXIT;
}
471
// create a signal and check for errors
472
msg = dbus_message_new_signal(USB_MODE_OBJECT, USB_MODE_INTERFACE, signal_type );
473
474
475
if (NULL == msg)
{
log_debug("Message Null\n");
476
477
478
479
goto EXIT;
}
// append arguments onto signal
480
481
482
if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &content, DBUS_TYPE_INVALID))
{
log_debug("Appending arguments failed. Out Of Memory!\n");
483
484
485
486
goto EXIT;
}
// send the message on the correct bus and flush the connection
487
if (!dbus_connection_send(dbus_connection_sys, msg, 0))
488
{
489
log_debug("Failed sending message. Out Of Memory!\n");
490
491
492
493
goto EXIT;
}
result = 0;
494
495
EXIT:
// free the message
496
497
498
499
500
501
if(msg != 0)
dbus_message_unref(msg);
return result;
}
502
503
504
/**
* Send regular usb_moded state signal
*
505
* @return 0 on success, 1 on failure
506
507
508
509
* @param state_ind the signal name
*
*/
int usb_moded_send_signal(const char *state_ind)
510
{
511
512
return(usb_moded_dbus_signal(USB_MODE_SIGNAL_NAME, state_ind));
}
513
514
515
516
/**
* Send regular usb_moded error signal
*
517
* @return 0 on success, 1 on failure
518
* @param error the error to be signalled
519
520
521
522
523
*
*/
int usb_moded_send_error_signal(const char *error)
{
return(usb_moded_dbus_signal(USB_MODE_ERROR_SIGNAL_NAME, error));
524
}
525
526
527
528
/**
* Send regular usb_moded mode list signal
*
529
* @return 0 on success, 1 on failure
530
* @param supported_modes list of supported modes
531
532
*
*/
533
534
int usb_moded_send_supported_modes_signal(const char *supported_modes)
{
535
return(usb_moded_dbus_signal(USB_MODE_SUPPORTED_MODES_SIGNAL_NAME, supported_modes));
536
}
537
538
539
540
541
542
543
544
545
546
547
548
/**
* Send regular usb_moded hidden mode list signal
*
* @return 0 on success, 1 on failure
* @param hidden_modes list of supported modes
*
*/
int usb_moded_send_hidden_modes_signal(const char *hidden_modes)
{
return(usb_moded_dbus_signal(USB_MODE_HIDDEN_MODES_SIGNAL_NAME, hidden_modes));
}