diff --git a/debian/usb_moded.conf b/debian/usb_moded.conf index 714e50b..555fd89 100644 --- a/debian/usb_moded.conf +++ b/debian/usb_moded.conf @@ -25,6 +25,8 @@ send_interface="com.meego.usb_moded" send_member="get_net_config"/> + + + + + + + diff --git a/src/usb_moded-dbus.c b/src/usb_moded-dbus.c index 63856e8..2bf66ba 100644 --- a/src/usb_moded-dbus.c +++ b/src/usb_moded-dbus.c @@ -64,9 +64,15 @@ gboolean umdbus_init_connection (void); gboolean umdbus_init_service (void); static void umdbus_cleanup_service (void); void umdbus_cleanup (void); -static int umdbus_send_signal_ex (const char *signal_type, const char *content); +static DBusMessage *umdbus_new_signal (const char *signal_name); +static int umdbus_send_signal_ex (const char *signal_name, const char *content); static void umdbus_send_legacy_signal (const char *state_ind); void umdbus_send_current_state_signal (const char *state_ind); +static bool umsdbus_append_basic_entry (DBusMessageIter *iter, const char *key, int type, const void *val); +static bool umsdbus_append_int32_entry (DBusMessageIter *iter, const char *key, int val); +static bool umsdbus_append_string_entry (DBusMessageIter *iter, const char *key, const char *val); +static bool umdbus_append_mode_details (DBusMessage *msg, const char *mode_name); +static void umdbus_send_mode_details_signal (const char *mode_name); void umdbus_send_target_state_signal (const char *state_ind); void umdbus_send_event_signal (const char *state_ind); int umdbus_send_error_signal (const char *error); @@ -207,6 +213,12 @@ static const char umdbus_introspect_usbmoded[] = " \n" " \n" " \n" +" " +" " +" " +" " +" " +" " " \n" "\n"; @@ -307,6 +319,12 @@ static DBusHandlerResult umdbus_msg_handler(DBusConnection *const connection, DB 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_TARGET_CONFIG_GET)) + { + const char *mode = control_get_target_mode(); + if((reply = dbus_message_new_method_return(msg))) + umdbus_append_mode_details(reply, mode); + } else if(!strcmp(member, USB_MODE_TARGET_STATE_GET)) { const char *mode = control_get_target_mode(); @@ -789,14 +807,52 @@ void umdbus_cleanup(void) } } +/** Helper for allocating usb-moded D-Bus signal + * + * @param signal_name Name of the signal to allocate + * + * @return dbus message object, or NULL in case of errors + */ +static DBusMessage* +umdbus_new_signal(const char *signal_name) +{ + LOG_REGISTER_CONTEXT; + + DBusMessage *msg = 0; + + if( !umdbus_connection ) + { + log_err("sending signal %s without dbus connection", signal_name); + goto EXIT; + } + if( !umdbus_service_name_acquired ) + { + log_err("sending signal %s before acquiring name", signal_name); + goto EXIT; + } + // create a signal and check for errors + msg = dbus_message_new_signal(USB_MODE_OBJECT, USB_MODE_INTERFACE, + signal_name ); + if( !msg ) + { + log_err("allocating signal %s failed", signal_name); + goto EXIT; + } + +EXIT: + return msg; +} + /** * Helper function for sending the different signals * + * @param signal_name the type of signal (normal, error, ...) + * @param content string which can be mode name, error, list of modes, ... + * * @return 0 on success, 1 on failure - * @param signal_type the type of signal (normal, error, ...) - * @@param content string which can be mode name, error, list of modes, ... -*/ -static int umdbus_send_signal_ex(const char *signal_type, const char *content) + */ +static int +umdbus_send_signal_ex(const char *signal_name, const char *content) { LOG_REGISTER_CONTEXT; @@ -808,38 +864,24 @@ static int umdbus_send_signal_ex(const char *signal_type, const char *content) if( !content ) content = ""; - log_debug("broadcast signal %s(%s)\n", signal_type, content); + log_debug("broadcast signal %s(%s)", signal_name, content); - if( !umdbus_service_name_acquired ) - { - log_err("sending signal without service: %s(%s)", - signal_type, content); - goto EXIT; - } - if(!umdbus_connection) - { - log_err("Dbus system connection broken!\n"); - goto EXIT; - } - // create a signal and check for errors - msg = dbus_message_new_signal(USB_MODE_OBJECT, USB_MODE_INTERFACE, signal_type ); - if (NULL == msg) - { - log_debug("Message Null\n"); + if( !(msg = umdbus_new_signal(signal_name)) ) goto EXIT; - } // append arguments onto signal - if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &content, DBUS_TYPE_INVALID)) + if( !dbus_message_append_args(msg, + DBUS_TYPE_STRING, &content, + DBUS_TYPE_INVALID) ) { - log_debug("Appending arguments failed. Out Of Memory!\n"); + log_err("appending arguments to signal %s failed", signal_name); goto EXIT; } - // send the message on the correct bus and flush the connection - if (!dbus_connection_send(umdbus_connection, msg, 0)) + // send the message on the correct bus + if( !dbus_connection_send(umdbus_connection, msg, 0) ) { - log_debug("Failed sending message. Out Of Memory!\n"); + log_err("sending signal %s failed", signal_name); goto EXIT; } result = 0; @@ -879,6 +921,222 @@ void umdbus_send_current_state_signal(const char *state_ind) umdbus_send_legacy_signal(state_ind); } +/** Append string key, variant value dict entry to dbus iterator + * + * @param iter Iterator to append data to + * @param key Entry name string + * @param type Entry value data tupe + * @param val Pointer to basic data (as void pointer) + * + * @return true on success, false on failure + */ +static bool +umsdbus_append_basic_entry(DBusMessageIter *iter, const char *key, + int type, const void *val) +{ + LOG_REGISTER_CONTEXT; + + /* Signature must be provided for variant containers */ + const char *signature = 0; + switch( type ) { + case DBUS_TYPE_INT32: signature = DBUS_TYPE_INT32_AS_STRING; break; + case DBUS_TYPE_STRING: signature = DBUS_TYPE_STRING_AS_STRING; break; + default: break; + } + if( !signature ) { + log_err("unhandled D-Bus type: %d", type); + goto bailout_message; + } + + DBusMessageIter entry, variant; + + if( !dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, + 0, &entry) ) + goto bailout_message; + + if( !dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key) ) + goto bailout_entry; + + if( !dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, + signature, &variant) ) + goto bailout_entry; + + if( !dbus_message_iter_append_basic(&variant, type, val) ) + goto bailout_variant; + + if( !dbus_message_iter_close_container(&entry, &variant) ) + goto bailout_variant; + + if( !dbus_message_iter_close_container(iter, &entry) ) + goto bailout_entry; + + return true; + +bailout_variant: + dbus_message_iter_abandon_container(&entry, &variant); + +bailout_entry: + dbus_message_iter_abandon_container(iter, &entry); + +bailout_message: + return false; +} + +/** Append string key, variant:int32 value dict entry to dbus iterator + * + * @param iter Iterator to append data to + * @param key Entry name string + * @param val Entry value + * + * @return true on success, false on failure + */ +static bool +umsdbus_append_int32_entry(DBusMessageIter *iter, const char *key, int val) +{ + LOG_REGISTER_CONTEXT; + + dbus_int32_t arg = val; + return umsdbus_append_basic_entry(iter, key, DBUS_TYPE_INT32, &arg); +} + +/** Append string key, variant:string value dict entry to dbus iterator + * + * @param iter Iterator to append data to + * @param key Entry name string + * @param val Entry value + * + * @return true on success, false on failure + */ +static bool +umsdbus_append_string_entry(DBusMessageIter *iter, const char *key, + const char *val) +{ + LOG_REGISTER_CONTEXT; + + if( !val ) + val = ""; + return umsdbus_append_basic_entry(iter, key, DBUS_TYPE_STRING, &val); +} + +/** Append dynamic mode configuration to dbus message + * + * @param msg D-Bus message object + * @param mode_name Name of the mode to use + * + * @return true on success, false on failure + */ +static bool +umdbus_append_mode_details(DBusMessage *msg, const char *mode_name) +{ + LOG_REGISTER_CONTEXT; + + const mode_list_elem_t *data = 0; + + for( GList *iter = usbmoded_get_modelist(); iter; iter = g_list_next(iter) ) + { + const mode_list_elem_t *iter_data = iter->data; + if( g_strcmp0(iter_data->mode_name, mode_name) ) + continue; + data = iter_data; + break; + } + + DBusMessageIter body, dict; + + dbus_message_iter_init_append(msg, &body); + + if( !dbus_message_iter_open_container(&body, + DBUS_TYPE_ARRAY, + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + &dict) ) + goto bailout_message; + + /* Note: mode_name is special case: It needs to be valid even + * if the mode does not have dynamic configuration. + */ + if( !umsdbus_append_string_entry(&dict, "mode_name", mode_name) ) + goto bailout_dict; + + /* For the rest of the mode attrs we use fallback data if there + * is no dynamic config / dynamic config does not define some value. + */ + +#define ADD_STR(name) \ + if( !umsdbus_append_string_entry(&dict, #name, data ? data->name : 0) )\ + goto bailout_dict; +#define ADD_INT(name) \ + if( !umsdbus_append_int32_entry(&dict, #name, data ? data->name : 0) )\ + goto bailout_dict; + + /* Attributes that we presume to be needed */ + ADD_INT(appsync); + ADD_INT(network); + ADD_STR(network_interface); + ADD_INT(nat); + ADD_INT(dhcp_server); +#ifdef CONNMAN + ADD_STR(connman_tethering); +#endif + + /* Attributes that are not exposed for now */ +#if 0 + ADD_INT(mass_storage); + ADD_STR(mode_module); + ADD_STR(sysfs_path); + ADD_STR(sysfs_value); + ADD_STR(sysfs_reset_value); + ADD_STR(android_extra_sysfs_path); + ADD_STR(android_extra_sysfs_value); + ADD_STR(android_extra_sysfs_path2); + ADD_STR(android_extra_sysfs_value2); + ADD_STR(android_extra_sysfs_path3); + ADD_STR(android_extra_sysfs_value3); + ADD_STR(android_extra_sysfs_path4); + ADD_STR(android_extra_sysfs_value4); + ADD_STR(idProduct); + ADD_STR(idVendorOverride); +#endif + +#undef ADD_STR +#undef ADD_INT + + if( !dbus_message_iter_close_container(&body, &dict) ) + goto bailout_dict; + + return true; + +bailout_dict: + dbus_message_iter_abandon_container(&body, &dict); + +bailout_message: + return false; +} + +/** Send usb_moded target state configuration signal + * + * @param mode_name mode name + */ +static void +umdbus_send_mode_details_signal(const char *mode_name) +{ + DBusMessage* msg = 0; + + if( !(msg = umdbus_new_signal(USB_MODE_TARGET_CONFIG_SIGNAL_NAME)) ) + goto EXIT; + + if( !umdbus_append_mode_details(msg, mode_name) ) + goto EXIT; + + dbus_connection_send(umdbus_connection, msg, 0); + +EXIT: + if(msg != 0) + dbus_message_unref(msg); +} + /** Send usb_moded target state signal * * @param state_ind mode name @@ -887,6 +1145,17 @@ void umdbus_send_target_state_signal(const char *state_ind) { LOG_REGISTER_CONTEXT; + /* Send target mode details before claiming intent to + * do mode transition. This way the clients tracking + * configuration changes can assume they have valid + * details immediately when transition begins. + * + * If clients for any reason need to pay closer attention + * to signal timing, the mode_name contained in this broadcast + * can be checked against current / target mode. + */ + umdbus_send_mode_details_signal(state_ind); + umdbus_send_signal_ex(USB_MODE_TARGET_STATE_SIGNAL_NAME, state_ind); } diff --git a/src/usb_moded-dbus.h b/src/usb_moded-dbus.h index 278f7a6..d03e37e 100644 --- a/src/usb_moded-dbus.h +++ b/src/usb_moded-dbus.h @@ -56,6 +56,7 @@ # define USB_MODE_HIDDEN_MODES_SIGNAL_NAME "sig_usb_hidden_modes_ind" # define USB_MODE_WHITELISTED_MODES_SIGNAL_NAME "sig_usb_whitelisted_modes_ind" # define USB_MODE_AVAILABLE_MODES_SIGNAL_NAME "sig_usb_available_modes_ind" +# define USB_MODE_TARGET_CONFIG_SIGNAL_NAME "sig_usb_taget_mode_config_ind" /* supported methods */ # define USB_MODE_STATE_REQUEST "mode_request" /* returns the current mode */ @@ -74,6 +75,7 @@ # define USB_MODE_WHITELISTED_MODES_SET "set_whitelisted_modes" /* set the list of whitelisted modes */ # define USB_MODE_WHITELISTED_SET "set_whitelisted" /* sets whether an specific mode is in the whitelist */ # define USB_MODE_AVAILABLE_MODES_GET "get_available_modes" /* returns a comma separated list of modes which are currently available for selection */ +# define USB_MODE_TARGET_CONFIG_GET "get_target_mode_config" /* returns current target mode configuration */ /** * (Transient) states reported by "sig_usb_state_ind" that are not modes.