Compare commits

...

15 Commits

Author SHA1 Message Date
Juho Hämäläinen
1c0f5094a6 Merge pull request #3 from jusa/jb55276
Be less pedantic about ordering of speech codecs.
2021-08-25 17:00:06 +03:00
Juho Hämäläinen
4208b6d9ea [bluetooth] Be less pedantic about ordering of speech codecs. Fixes JB#55276
HFP spec 1.7.1 (4.34.1) says:

The Codec ID for the mandatory narrow band codec (CVSD) shall
always be included.

If wide band speech is supported, then the mandatory codec (mSBC)
shall be included unless it is temporarily unavailable.

Any other optional wide band speech codecs may also be included
in this list as long as the mandatory codec is included first.

---

The wording in spec is slightly vague on what the ordering of
mandatory narrow band codec (CVSD) and - IF wide band speech
is supported - mandatory wide band coded (mSBC) should be.
oFono's take is that the mandatory narrow band codec should
be listed first, and when mSBC is there oFono will abort the
connection.

To fix this we can be less pedantic about the ordering of
codecs - as long as the mandatory ones are there.
2021-08-25 16:32:55 +03:00
Frajo
59e304d474 Merge pull request #2 from krnlyng/jb55233
[packaging] Use transfiletriggerin to restart ofono when a plugin is installed. JB#55233
2021-08-25 16:02:24 +03:00
Frajo Haider
30a2424507 [packaging] Use transfiletriggerin to restart ofono when a plugin is installed. JB#55233 2021-08-24 13:29:18 +03:00
Slava Monich
e4f3ec6322 Merge pull request #1 from monich/start_block
Fix SIM I/O mess
2021-07-30 15:12:59 +03:00
Slava Monich
95fd4efc37 [simfs] Fix SIM I/O mess. JB#54380
Apparently all simfs reads from any blocks other than the very first one
were badly broken and could even cause a crash :|
2021-07-30 01:50:07 +03:00
Slava Monich
ef5ee98508 [ofono] Set destination for Unsubscribed signal. JB#50816 2021-06-10 18:00:39 +03:00
Slava Monich
4220e7d5e8 Merge branch 'dbus-clients-fixes' into 'master'
Resolve a few issues with cell info notifications

See merge request mer-core/ofono!286
2021-06-10 13:54:42 +00:00
Slava Monich
33c067a75f [ofono] Resolved a few issues with cell info notifications. JB#50816
1. Disable notifications from modem on unsibscribe
2. Made all signals unicast
3. Fixed a memory leak
2021-06-10 16:23:52 +03:00
Slava Monich
29616c04d0 [ofono] Fixed signal emission, reworked D-Bus client list. JB#50816
1. Exposed D-Bus clients list to plugin as ofono_dbus_clients
2. Signal has to be properly declared, otherwise it's not emitted
3. Added missing unit tests
2021-06-10 05:10:16 +03:00
Slava Monich
beb997d914 Merge branch 'jb50608-ondemand' into 'master'
Disable cell info updates when no one listens for them

See merge request mer-core/ofono!274
2021-06-10 01:58:05 +00:00
Denis Grigorev
3d147843c4 [ril] Make cell info updates unicast. JB#50608 2021-05-28 16:25:42 +03:00
Denis Grigorev
c01dc63cbc [ril] Cell info consumer can unsubscribe from updates. JB#50608
Add a new org.nemomobile.ofono.CellInfo.Unsubscribe method. If it is called
ofono excludes the client from cell info consumers. The updates will be
disabled if no one client left.
2021-05-28 16:25:42 +03:00
Denis Grigorev
297926ed24 [ril] Enable cell info updates only when requested. JB#50608 2021-05-28 16:25:42 +03:00
Denis Grigorev
6ef1174ea8 [ril] Cell info updates can be disabled. JB#50608 2021-05-28 16:25:42 +03:00
18 changed files with 942 additions and 115 deletions

1
ofono/.gitignore vendored
View File

@@ -45,6 +45,7 @@ unit/test-caif
unit/test-stkutil
unit/test-cdmasms
unit/test-dbus-access
unit/test-dbus-clients
unit/test-dbus-queue
unit/test-gprs-filter
unit/test-ril_config

View File

@@ -26,7 +26,7 @@ pkginclude_HEADERS = include/log.h include/plugin.h include/history.h \
include/sms-filter.h include/gprs-filter.h \
include/voicecall-filter.h include/dbus-access.h \
include/ril-constants.h include/ril-transport.h \
include/watch.h gdbus/gdbus.h \
include/watch.h gdbus/gdbus.h include/dbus-clients.h \
include/netmon.h include/lte.h include/ims.h \
include/storage.h
@@ -775,7 +775,8 @@ src_ofonod_SOURCES = $(builtin_sources) $(gatchat_sources) src/ofono.ver \
src/handsfree-audio.c src/bluetooth.h \
src/sim-mnclength.c src/voicecallagent.c \
src/sms-filter.c src/gprs-filter.c \
src/dbus-queue.c src/dbus-access.c src/config.c \
src/dbus-clients.c src/dbus-queue.c \
src/dbus-access.c src/config.c \
src/voicecall-filter.c src/ril-transport.c \
src/hfp.h src/siri.c src/watchlist.c \
src/netmon.c src/lte.c src/ims.c \
@@ -981,7 +982,7 @@ unit_test_sailfish_cell_info_dbus_SOURCES = unit/test-dbus.c \
unit/fake_sailfish_cell_info.c \
plugins/sailfish_manager/sailfish_cell_info.c \
plugins/sailfish_manager/sailfish_cell_info_dbus.c \
gdbus/object.c \
gdbus/object.c src/dbus-clients.c \
src/dbus.c src/log.c
unit_test_sailfish_cell_info_dbus_CFLAGS = $(AM_CFLAGS) $(COVERAGE_OPT) \
@DBUS_GLIB_CFLAGS@
@@ -1164,6 +1165,14 @@ unit_test_caif_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_caif_LDADD = @GLIB_LIBS@
unit_objects += $(unit_test_caif_OBJECTS)
unit_test_dbus_clients_SOURCES = unit/test-dbus-clients.c unit/test-dbus.c \
src/dbus-clients.c gdbus/object.c \
src/dbus.c src/log.c
unit_test_dbus_clients_CFLAGS = @DBUS_GLIB_CFLAGS@ $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_dbus_clients_LDADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ -ldl
unit_objects += $(unit_test_dbus_clients_OBJECTS)
unit_tests += unit/test-dbus-clients
unit_test_dbus_queue_SOURCES = unit/test-dbus-queue.c unit/test-dbus.c \
src/dbus-queue.c gdbus/object.c \
src/dbus.c src/log.c

View File

@@ -47,6 +47,7 @@ struct ril_cell_info {
gulong event_id;
guint query_id;
guint set_rate_id;
gboolean enabled;
};
enum ril_cell_info_signal {
@@ -331,7 +332,8 @@ static void ril_cell_info_list_cb(GRilIoChannel *io, int status,
DBG_(self, "");
GASSERT(self->query_id);
self->query_id = 0;
ril_cell_info_update_cells(self, (status == RIL_E_SUCCESS) ?
ril_cell_info_update_cells(self,
(status == RIL_E_SUCCESS && self->enabled) ?
ril_cell_info_parse_list(io->ril_version, data, len) : NULL);
}
@@ -348,12 +350,14 @@ static void ril_cell_info_set_rate_cb(GRilIoChannel *io, int status,
static gboolean ril_cell_info_retry(GRilIoRequest* request, int ril_status,
const void* response_data, guint response_len, void* user_data)
{
struct ril_cell_info *self = RIL_CELL_INFO(user_data);
switch (ril_status) {
case RIL_E_SUCCESS:
case RIL_E_RADIO_NOT_AVAILABLE:
return FALSE;
default:
return TRUE;
return self->enabled;
}
}
@@ -373,7 +377,8 @@ static void ril_cell_info_query(struct ril_cell_info *self)
static void ril_cell_info_set_rate(struct ril_cell_info *self)
{
GRilIoRequest *req = grilio_request_array_int32_new(1,
(self->update_rate_ms >= 0) ? self->update_rate_ms : INT_MAX);
(self->update_rate_ms >= 0 && self->enabled) ?
self->update_rate_ms : INT_MAX);
grilio_request_set_retry(req, RIL_RETRY_MS, MAX_RETRIES);
grilio_request_set_retry_func(req, ril_cell_info_retry);
@@ -387,7 +392,8 @@ static void ril_cell_info_set_rate(struct ril_cell_info *self)
static void ril_cell_info_refresh(struct ril_cell_info *self)
{
/* RIL_REQUEST_GET_CELL_INFO_LIST fails without SIM card */
if (self->radio->state == RADIO_STATE_ON && self->sim_card_ready) {
if (self->enabled && self->radio->state == RADIO_STATE_ON &&
self->sim_card_ready) {
ril_cell_info_query(self);
} else {
ril_cell_info_update_cells(self, NULL);
@@ -482,6 +488,21 @@ static void ril_cell_info_set_update_interval_proc
if (self->update_rate_ms != ms) {
self->update_rate_ms = ms;
DBG_(self, "%d ms", ms);
if (self->enabled && self->sim_card_ready) {
ril_cell_info_set_rate(self);
}
}
}
void ril_cell_info_set_enabled_proc(struct sailfish_cell_info *info,
gboolean enabled)
{
struct ril_cell_info *self = ril_cell_info_cast(info);
if (self->enabled != enabled) {
self->enabled = enabled;
DBG_(self, "%d", enabled);
ril_cell_info_refresh(self);
if (self->sim_card_ready) {
ril_cell_info_set_rate(self);
}
@@ -497,7 +518,8 @@ struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
ril_cell_info_unref_proc,
ril_cell_info_add_cells_changed_handler_proc,
ril_cell_info_remove_handler_proc,
ril_cell_info_set_update_interval_proc
ril_cell_info_set_update_interval_proc,
ril_cell_info_set_enabled_proc
};
struct ril_cell_info *self = g_object_new(RIL_CELL_INFO_TYPE, 0);
@@ -519,6 +541,9 @@ struct sailfish_cell_info *ril_cell_info_new(GRilIoChannel *io,
ril_cell_info_sim_status_cb, self);
self->sim_card_ready = ril_sim_card_ready(sim_card);
ril_cell_info_refresh(self);
/* Disable updates by default */
self->enabled = FALSE;
if (self->sim_card_ready) {
ril_cell_info_set_rate(self);
}

View File

@@ -0,0 +1,55 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2021 Jolla Ltd.
* Copyright (C) 2021 Open Mobile Platform LLC.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the 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.
*/
#ifndef OFONO_DBUS_CLIENTS_H
#define OFONO_DBUS_CLIENTS_H
#include <ofono/types.h>
#include <ofono/dbus.h>
/* Since mer/1.23+git31 */
struct ofono_dbus_clients;
typedef void (*ofono_dbus_clients_notify_func)(const char *name,
void *user_data);
struct ofono_dbus_clients *ofono_dbus_clients_new(DBusConnection *conn,
ofono_dbus_clients_notify_func notify, void *user_data);
void ofono_dbus_clients_free(struct ofono_dbus_clients *clients);
unsigned int ofono_dbus_clients_count(struct ofono_dbus_clients *clients);
ofono_bool_t ofono_dbus_clients_add(struct ofono_dbus_clients *clients,
const char *name);
ofono_bool_t ofono_dbus_clients_remove(struct ofono_dbus_clients *clients,
const char *name);
void ofono_dbus_clients_signal(struct ofono_dbus_clients *clients,
DBusMessage *signal);
void ofono_dbus_clients_signal_property_changed(struct ofono_dbus_clients *dc,
const char *path, const char *interface, const char *name,
int type, const void *value);
#endif /* OFONO_DBUS_CLIENTS_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -3,7 +3,7 @@
* oFono - Open Telephony stack for Linux
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2013-2016 Jolla Ltd.
* Copyright (C) 2013-2021 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -14,10 +14,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the 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
*
*/
#ifndef __OFONO_DBUS_H
@@ -83,6 +79,8 @@ extern "C" {
DBUS_TYPE_VARIANT_AS_STRING \
DBUS_DICT_ENTRY_END_CHAR_AS_STRING
#define OFONO_ERROR_INTERFACE "org.ofono.Error"
DBusConnection *ofono_dbus_get_connection(void);
void ofono_dbus_dict_append(DBusMessageIter *dict, const char *key, int type,
@@ -110,6 +108,11 @@ int ofono_dbus_signal_dict_property_changed(DBusConnection *conn,
const char *name, int type,
const void *value);
/* Since mer/1.23+git31 */
DBusMessage *ofono_dbus_signal_new_property_changed(const char *path,
const char *interface,
const char *name,
int type, const void *value);
#ifdef __cplusplus
}
#endif

View File

@@ -128,6 +128,14 @@ void sailfish_cell_info_set_update_interval(struct sailfish_cell_info *info,
}
}
void sailfish_cell_info_set_enabled(struct sailfish_cell_info *info,
gboolean enabled)
{
if (info && info->proc->set_enabled) {
info->proc->set_enabled(info, enabled);
}
}
/*
* Local Variables:
* mode: C

View File

@@ -89,6 +89,7 @@ struct sailfish_cell_info_proc {
sailfish_cell_info_cb_t cb, void *arg);
void (*remove_handler)(struct sailfish_cell_info *info, gulong id);
void (*set_update_interval)(struct sailfish_cell_info *info, int ms);
void (*set_enabled)(struct sailfish_cell_info *info, gboolean enabled);
};
/* Utilities */
@@ -107,6 +108,8 @@ void sailfish_cell_info_remove_handler(struct sailfish_cell_info *info,
gulong id);
void sailfish_cell_info_set_update_interval(struct sailfish_cell_info *info,
int ms);
void sailfish_cell_info_set_enabled(struct sailfish_cell_info *info,
gboolean enabled);
#endif /* SAILFISH_CELINFO_H */

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
* Copyright (C) 2016-2018 Jolla Ltd.
* Copyright (C) 2016-2021 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -18,6 +18,7 @@
#include <ofono/modem.h>
#include <ofono/dbus.h>
#include <ofono/dbus-clients.h>
#include <ofono/log.h>
#include <gdbus.h>
@@ -35,11 +36,13 @@ struct sailfish_cell_info_dbus {
gulong handler_id;
guint next_cell_id;
GSList *entries;
struct ofono_dbus_clients *clients;
};
#define CELL_INFO_DBUS_INTERFACE "org.nemomobile.ofono.CellInfo"
#define CELL_INFO_DBUS_CELLS_ADDED_SIGNAL "CellsAdded"
#define CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL "CellsRemoved"
#define CELL_INFO_DBUS_UNSUBSCRIBED_SIGNAL "Unsubscribed"
#define CELL_DBUS_INTERFACE_VERSION (1)
#define CELL_DBUS_INTERFACE "org.nemomobile.ofono.Cell"
@@ -322,21 +325,24 @@ static void sailfish_cell_info_dbus_emit_path_list
(struct sailfish_cell_info_dbus *dbus, const char *name,
GPtrArray *list)
{
guint i;
DBusMessageIter it, array;
DBusMessage *signal = dbus_message_new_signal(dbus->path,
if (ofono_dbus_clients_count(dbus->clients)) {
guint i;
DBusMessageIter it, a;
DBusMessage *signal = dbus_message_new_signal(dbus->path,
CELL_INFO_DBUS_INTERFACE, name);
dbus_message_iter_init_append(signal, &it);
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &array);
for (i = 0; i < list->len; i++) {
const char* path = list->pdata[i];
dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
&path);
}
dbus_message_iter_close_container(&it, &array);
dbus_message_iter_init_append(signal, &it);
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &a);
for (i = 0; i < list->len; i++) {
const char* path = list->pdata[i];
g_dbus_send_message(dbus->conn, signal);
dbus_message_iter_append_basic(&a,
DBUS_TYPE_OBJECT_PATH, &path);
}
dbus_message_iter_close_container(&it, &a);
ofono_dbus_clients_signal(dbus->clients, signal);
dbus_message_unref(signal);
}
}
static int sailfish_cell_info_dbus_compare(const struct sailfish_cell *c1,
@@ -366,6 +372,23 @@ static int sailfish_cell_info_dbus_compare(const struct sailfish_cell *c1,
}
}
static void sailfish_cell_info_dbus_emit_signal
(struct sailfish_cell_info_dbus *dbus,
const char *path, const char *intf,
const char *name, int type, ...)
{
if (ofono_dbus_clients_count(dbus->clients)) {
va_list args;
DBusMessage *signal = dbus_message_new_signal(path, intf, name);
va_start(args, type);
dbus_message_append_args_valist(signal, type, args);
ofono_dbus_clients_signal(dbus->clients, signal);
dbus_message_unref(signal);
va_end(args);
}
}
static void sailfish_cell_info_dbus_property_changed
(struct sailfish_cell_info_dbus *dbus,
const struct sailfish_cell_entry *entry, int mask)
@@ -377,7 +400,8 @@ static void sailfish_cell_info_dbus_property_changed
if (mask & SAILFISH_CELL_PROPERTY_REGISTERED) {
const dbus_bool_t registered = (cell->registered != FALSE);
g_dbus_emit_signal(dbus->conn, entry->path,
sailfish_cell_info_dbus_emit_signal(dbus, entry->path,
CELL_DBUS_INTERFACE,
CELL_DBUS_REGISTERED_CHANGED_SIGNAL,
DBUS_TYPE_BOOLEAN, &registered, DBUS_TYPE_INVALID);
@@ -386,9 +410,10 @@ static void sailfish_cell_info_dbus_property_changed
for (i = 0; i < n && mask; i++) {
if (mask & prop[i].flag) {
ofono_dbus_signal_property_changed(dbus->conn,
entry->path, CELL_DBUS_INTERFACE,
prop[i].name, DBUS_TYPE_INT32,
ofono_dbus_clients_signal_property_changed(
dbus->clients, entry->path,
CELL_DBUS_INTERFACE, prop[i].name,
DBUS_TYPE_INT32,
G_STRUCT_MEMBER_P(&cell->info, prop[i].off));
mask &= ~prop[i].flag;
}
@@ -411,7 +436,7 @@ static void sailfish_cell_info_dbus_update_entries
sailfish_cell_compare_func)) {
DBG("%s removed", entry->path);
dbus->entries = g_slist_delete_link(dbus->entries, l);
g_dbus_emit_signal(dbus->conn, entry->path,
sailfish_cell_info_dbus_emit_signal(dbus, entry->path,
CELL_DBUS_INTERFACE,
CELL_DBUS_REMOVED_SIGNAL,
DBUS_TYPE_INVALID);
@@ -492,29 +517,67 @@ static void sailfish_cell_info_dbus_cells_changed_cb
((struct sailfish_cell_info_dbus *)arg, TRUE);
}
static DBusMessage *sailfish_cell_info_dbus_error_failed(DBusMessage *msg,
const char *explanation)
{
return g_dbus_create_error(msg, OFONO_ERROR_INTERFACE ".Failed", "%s",
explanation);
}
static DBusMessage *sailfish_cell_info_dbus_get_cells(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct sailfish_cell_info_dbus *dbus = data;
DBusMessage *reply = dbus_message_new_method_return(msg);
DBusMessageIter it, array;
GSList *l;
const char *sender = dbus_message_get_sender(msg);
dbus_message_iter_init_append(reply, &it);
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &array);
for (l = dbus->entries; l; l = l->next) {
const struct sailfish_cell_entry *entry = l->data;
dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
&entry->path);
if (ofono_dbus_clients_add(dbus->clients, sender)) {
DBusMessage *reply = dbus_message_new_method_return(msg);
DBusMessageIter it, a;
GSList *l;
sailfish_cell_info_set_enabled(dbus->info, TRUE);
dbus_message_iter_init_append(reply, &it);
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "o", &a);
for (l = dbus->entries; l; l = l->next) {
const struct sailfish_cell_entry *entry = l->data;
dbus_message_iter_append_basic(&a,
DBUS_TYPE_OBJECT_PATH, &entry->path);
}
dbus_message_iter_close_container(&it, &a);
return reply;
}
dbus_message_iter_close_container(&it, &array);
return reply;
return sailfish_cell_info_dbus_error_failed(msg, "Operation failed");
}
static DBusMessage *sailfish_cell_info_dbus_unsubscribe(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct sailfish_cell_info_dbus *dbus = data;
const char *sender = dbus_message_get_sender(msg);
DBG("%s", sender);
if (ofono_dbus_clients_remove(dbus->clients, sender)) {
DBusMessage *signal = dbus_message_new_signal(dbus->path,
CELL_INFO_DBUS_INTERFACE,
CELL_INFO_DBUS_UNSUBSCRIBED_SIGNAL);
if (!ofono_dbus_clients_count(dbus->clients)) {
sailfish_cell_info_set_enabled(dbus->info, FALSE);
}
dbus_message_set_destination(signal, sender);
g_dbus_send_message(dbus->conn, signal);
return dbus_message_new_method_return(msg);
}
return sailfish_cell_info_dbus_error_failed(msg, "Not subscribed");
}
static const GDBusMethodTable sailfish_cell_info_dbus_methods[] = {
{ GDBUS_METHOD("GetCells", NULL,
GDBUS_ARGS({ "paths", "ao" }),
sailfish_cell_info_dbus_get_cells) },
{ GDBUS_METHOD("Unsubscribe", NULL, NULL,
sailfish_cell_info_dbus_unsubscribe) },
{ }
};
@@ -523,9 +586,20 @@ static const GDBusSignalTable sailfish_cell_info_dbus_signals[] = {
GDBUS_ARGS({ "paths", "ao" })) },
{ GDBUS_SIGNAL(CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL,
GDBUS_ARGS({ "paths", "ao" })) },
{ GDBUS_SIGNAL(CELL_INFO_DBUS_UNSUBSCRIBED_SIGNAL,
GDBUS_ARGS({})) },
{ }
};
static void sailfish_cell_info_dbus_disconnect_cb(const char *name, void *data)
{
struct sailfish_cell_info_dbus *dbus = data;
if (!ofono_dbus_clients_count(dbus->clients)) {
sailfish_cell_info_set_enabled(dbus->info, FALSE);
}
}
struct sailfish_cell_info_dbus *sailfish_cell_info_dbus_new
(struct ofono_modem *modem, struct sailfish_cell_info *info)
{
@@ -550,6 +624,8 @@ struct sailfish_cell_info_dbus *sailfish_cell_info_dbus_new
ofono_modem_add_interface(modem,
CELL_INFO_DBUS_INTERFACE);
sailfish_cell_info_dbus_update_entries(dbus, FALSE);
dbus->clients = ofono_dbus_clients_new(dbus->conn,
sailfish_cell_info_dbus_disconnect_cb, dbus);
return dbus;
} else {
ofono_error("CellInfo D-Bus register failed");
@@ -565,6 +641,7 @@ void sailfish_cell_info_dbus_free(struct sailfish_cell_info_dbus *dbus)
GSList *l;
DBG("%s", dbus->path);
ofono_dbus_clients_free(dbus->clients);
g_dbus_unregister_interface(dbus->conn, dbus->path,
CELL_INFO_DBUS_INTERFACE);

182
ofono/src/dbus-clients.c Normal file
View File

@@ -0,0 +1,182 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2017-2018 Jolla Ltd.
* Copyright (C) 2020 Open Mobile Platform LLC.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the 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.
*/
#include <ofono/dbus-clients.h>
#include <ofono/gdbus.h>
#include <ofono/log.h>
struct ofono_dbus_client {
struct ofono_dbus_clients *clients;
char *name;
unsigned int watch_id;
};
struct ofono_dbus_clients {
DBusConnection* conn;
GHashTable* table;
ofono_dbus_clients_notify_func notify;
void *user_data;
};
/* Compatible with GDestroyNotify */
static void ofono_dbus_client_free(struct ofono_dbus_client *client)
{
struct ofono_dbus_clients *clients = client->clients;
/* Callers make sure that client parameter is not NULL */
if (client->watch_id) {
g_dbus_remove_watch(clients->conn, client->watch_id);
}
g_free(client->name);
g_slice_free(struct ofono_dbus_client, client);
}
static void ofono_dbus_clients_disconnect_notify(DBusConnection *connection,
void *user_data)
{
struct ofono_dbus_client *client = user_data;
struct ofono_dbus_clients *self = client->clients;
char *name = client->name;
/*
* Steal the name so that it doesn't get freed by
* ofono_dbus_client_free(). We want to pass it to
* the callback but first we need to delete client's
* entry from the hashtable.
*/
client->name = NULL;
DBG("%s is gone", name);
g_hash_table_remove(self->table, name);
if (self->notify) {
self->notify(name, self->user_data);
}
g_free(name);
}
struct ofono_dbus_clients *ofono_dbus_clients_new(DBusConnection *conn,
ofono_dbus_clients_notify_func notify, void *user_data)
{
if (conn) {
struct ofono_dbus_clients *self =
g_slice_new0(struct ofono_dbus_clients);
self->conn = dbus_connection_ref(conn);
self->table = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, (GDestroyNotify) ofono_dbus_client_free);
self->notify = notify;
self->user_data = user_data;
return self;
}
return NULL;
}
void ofono_dbus_clients_free(struct ofono_dbus_clients *self)
{
if (self) {
g_hash_table_destroy(self->table);
dbus_connection_unref(self->conn);
g_slice_free(struct ofono_dbus_clients, self);
}
}
unsigned int ofono_dbus_clients_count(struct ofono_dbus_clients *self)
{
return self ? g_hash_table_size(self->table) : 0;
}
ofono_bool_t ofono_dbus_clients_add(struct ofono_dbus_clients *self,
const char *name)
{
if (self && name) {
struct ofono_dbus_client *client =
g_slice_new0(struct ofono_dbus_client);
client->clients = self;
client->name = g_strdup(name);
client->watch_id = g_dbus_add_disconnect_watch(self->conn,
client->name, ofono_dbus_clients_disconnect_notify,
client, NULL);
if (client->watch_id) {
DBG("%s is registered", client->name);
g_hash_table_replace(self->table, (gpointer)
client->name, client);
return TRUE;
} else {
DBG("failed to register %s", client->name);
ofono_dbus_client_free(client);
}
}
return FALSE;
}
ofono_bool_t ofono_dbus_clients_remove(struct ofono_dbus_clients *self,
const char *name)
{
return self && name && g_hash_table_remove(self->table, name);
}
void ofono_dbus_clients_signal(struct ofono_dbus_clients *self,
DBusMessage *signal)
{
if (self && signal && g_hash_table_size(self->table)) {
GHashTableIter it;
gpointer key;
const char *last_name = NULL;
g_hash_table_iter_init(&it, self->table);
g_hash_table_iter_next(&it, &key, NULL);
last_name = key;
while (g_hash_table_iter_next(&it, &key, NULL)) {
DBusMessage *copy = dbus_message_copy(signal);
dbus_message_set_destination(copy, key);
g_dbus_send_message(self->conn, copy);
}
/*
* The last one. Note that g_dbus_send_message() unrefs
* the message, we need compensate for that by adding a
* reference. The caller still owns the message when this
* function returns.
*/
dbus_message_ref(signal);
dbus_message_set_destination(signal, last_name);
g_dbus_send_message(self->conn, signal);
}
}
void ofono_dbus_clients_signal_property_changed(struct ofono_dbus_clients *self,
const char *path, const char *interface, const char *name,
int type, const void *value)
{
if (self && g_hash_table_size(self->table)) {
DBusMessage *sig = ofono_dbus_signal_new_property_changed(path,
interface, name, type, value);
ofono_dbus_clients_signal(self, sig);
dbus_message_unref(sig);
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -3,6 +3,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
* Copyright (C) 2013-2021 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -13,10 +14,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the 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
*
*/
#ifdef HAVE_CONFIG_H
@@ -29,8 +26,6 @@
#include "ofono.h"
#define OFONO_ERROR_INTERFACE "org.ofono.Error"
static DBusConnection *g_connection;
struct error_mapping_entry {
@@ -209,8 +204,8 @@ void ofono_dbus_dict_append_dict(DBusMessageIter *dict, const char *key,
dbus_message_iter_close_container(dict, &entry);
}
int ofono_dbus_signal_property_changed(DBusConnection *conn,
const char *path,
/* Since mer/1.23+git31 */
DBusMessage *ofono_dbus_signal_new_property_changed(const char *path,
const char *interface,
const char *name,
int type, const void *value)
@@ -219,11 +214,8 @@ int ofono_dbus_signal_property_changed(DBusConnection *conn,
DBusMessageIter iter;
signal = dbus_message_new_signal(path, interface, "PropertyChanged");
if (signal == NULL) {
ofono_error("Unable to allocate new %s.PropertyChanged signal",
interface);
return -1;
}
if (signal == NULL)
return NULL;
dbus_message_iter_init_append(signal, &iter);
@@ -231,6 +223,24 @@ int ofono_dbus_signal_property_changed(DBusConnection *conn,
append_variant(&iter, type, value);
return signal;
}
int ofono_dbus_signal_property_changed(DBusConnection *conn,
const char *path,
const char *interface,
const char *name,
int type, const void *value)
{
DBusMessage *signal = ofono_dbus_signal_new_property_changed(path,
interface, name, type, value);
if (signal == NULL) {
ofono_error("Unable to allocate new %s.PropertyChanged signal",
interface);
return -1;
}
return g_dbus_send_message(conn, signal);
}

View File

@@ -994,18 +994,17 @@ static void bac_cb(GAtServer *server, GAtServerRequestType type,
/*
* CVSD codec is mandatory and must come first.
* See HFP v1.6 4.34.1
* However, some headsets send the list in wrong order,
* but function fine otherwise, so to get those working
* let's not be pedantic about the codec order.
*/
if (g_at_result_iter_next_number(&iter, &val) == FALSE ||
val != HFP_CODEC_CVSD)
goto fail;
em->bac_received = TRUE;
em->negotiated_codec = 0;
em->r_codecs[CVSD_OFFSET].supported = TRUE;
while (g_at_result_iter_next_number(&iter, &val)) {
switch (val) {
case HFP_CODEC_CVSD:
em->bac_received = TRUE;
em->negotiated_codec = 0;
em->r_codecs[CVSD_OFFSET].supported = TRUE;
break;
case HFP_CODEC_MSBC:
em->r_codecs[MSBC_OFFSET].supported = TRUE;
break;
@@ -1015,6 +1014,11 @@ static void bac_cb(GAtServer *server, GAtServerRequestType type,
}
}
if (!em->bac_received) {
DBG("Mandatory codec %d not received.", HFP_CODEC_CVSD);
goto fail;
}
g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
/*

View File

@@ -405,18 +405,18 @@ static void sim_fs_op_read_block_cb(const struct ofono_error *error,
}
start_block = op->offset / 256;
end_block = (op->offset + (op->num_bytes - 1)) / 256;
end_block = op->num_bytes ? (op->offset + op->num_bytes - 1) / 256 :
start_block;
if (op->current == start_block) {
bufoff = 0;
dataoff = op->offset % 256;
tocopy = MIN(256 - op->offset % 256,
op->num_bytes - op->current * 256);
tocopy = MIN(256 - dataoff, op->num_bytes);
} else {
bufoff = (op->current - start_block - 1) * 256 +
bufoff = (op->current - start_block) * 256 -
op->offset % 256;
dataoff = 0;
tocopy = MIN(256, op->num_bytes - op->current * 256);
tocopy = MIN(256, op->num_bytes - bufoff);
}
DBG("bufoff: %d, dataoff: %d, tocopy: %d",
@@ -485,13 +485,12 @@ static gboolean sim_fs_op_read_block(gpointer user_data)
bufoff = 0;
seekoff = SIM_CACHE_HEADER_SIZE + op->current * 256 +
op->offset % 256;
toread = MIN(256 - op->offset % 256,
op->num_bytes - op->current * 256);
toread = MIN(256 - op->offset % 256, op->num_bytes);
} else {
bufoff = (op->current - start_block - 1) * 256 +
bufoff = (op->current - start_block) * 256 -
op->offset % 256;
seekoff = SIM_CACHE_HEADER_SIZE + op->current * 256;
toread = MIN(256, op->num_bytes - op->current * 256);
toread = MIN(256, op->num_bytes - bufoff);
}
DBG("bufoff: %d, seekoff: %d, toread: %d",

View File

@@ -18,6 +18,7 @@ TESTS="\
test-caif \
test-dbus-queue \
test-dbus-access \
test-dbus-clients \
test-gprs-filter \
test-provision \
test-config \

View File

@@ -0,0 +1,280 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2021 Jolla Ltd. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the 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.
*/
#include "test-dbus.h"
#include <ofono/dbus-clients.h>
#include <ofono/dbus.h>
#include <ofono/log.h>
#include "ofono.h"
#include <gutil_log.h>
#include <gutil_macros.h>
#include <errno.h>
#define TEST_TIMEOUT (10) /* seconds */
#define TEST_SENDER ":1.0"
#define TEST_SENDER_1 ":1.1"
#define TEST_DBUS_PATH "/test"
#define TEST_DBUS_INTERFACE "test.interface"
#define TEST_PROPERTY_CHANGED_SIGNAL "PropertyChanged"
#define TEST_PROPERTY_NAME "Test"
#define TEST_PROPERTY_VALUE "test"
struct test_data {
struct test_dbus_context dbus;
struct ofono_dbus_clients *clients;
int count;
};
static gboolean test_debug;
/* ==== dummy interface ==== */
#define test_register_interface(methods,signals,data) \
g_assert(g_dbus_register_interface(ofono_dbus_get_connection(), \
TEST_DBUS_PATH, TEST_DBUS_INTERFACE, \
methods, signals, NULL, data, NULL))
#define test_register_dummy_interface() \
test_register_interface(test_dummy_methods, \
test_property_change_signal, NULL)
static DBusMessage *test_dummy_handler(DBusConnection *conn,
DBusMessage *msg, void *data)
{
g_assert_not_reached();
return NULL;
}
static const GDBusMethodTable test_dummy_methods[] = {
{ GDBUS_ASYNC_METHOD("Dummy", NULL, NULL, test_dummy_handler) },
{ }
};
static const GDBusSignalTable test_property_change_signal[] = {
{ GDBUS_SIGNAL("PropertyChanged",
GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
{ }
};
/* ==== common ==== */
static gboolean test_timeout(gpointer param)
{
g_assert(!"TIMEOUT");
return G_SOURCE_REMOVE;
}
static guint test_setup_timeout(void)
{
if (test_debug) {
return 0;
} else {
return g_timeout_add_seconds(TEST_TIMEOUT, test_timeout, NULL);
}
}
static gboolean test_loop_quit(gpointer data)
{
g_main_loop_quit(data);
return G_SOURCE_REMOVE;
}
static void test_loop_quit_later(GMainLoop *loop)
{
g_idle_add(test_loop_quit, loop);
}
/* ==== null ==== */
static void test_null(void)
{
/* We are NULL tolerant: */
ofono_dbus_clients_free(NULL);
ofono_dbus_clients_signal(NULL, NULL);
ofono_dbus_clients_signal_property_changed(NULL,NULL,NULL,NULL,0,NULL);
g_assert(!ofono_dbus_clients_new(NULL, NULL, NULL));
g_assert(!ofono_dbus_clients_count(NULL));
g_assert(!ofono_dbus_clients_add(NULL, NULL));
g_assert(!ofono_dbus_clients_remove(NULL, NULL));
}
/* ==== basic ==== */
static void test_basic_notify_func(const char *name, void *loop)
{
g_assert_cmpstr(name, == ,TEST_SENDER);
g_main_loop_quit(loop);
}
static void test_basic_start(struct test_dbus_context *dbus)
{
struct test_data *test = G_CAST(dbus, struct test_data, dbus);
const char *value = TEST_PROPERTY_VALUE;
DBusMessage *signal =
ofono_dbus_signal_new_property_changed(TEST_DBUS_PATH,
TEST_DBUS_INTERFACE, TEST_PROPERTY_NAME,
DBUS_TYPE_STRING, &value);
test->clients = ofono_dbus_clients_new(ofono_dbus_get_connection(),
test_basic_notify_func, test->dbus.loop);
g_assert(!ofono_dbus_clients_add(test->clients, NULL));
g_assert(ofono_dbus_clients_add(test->clients, TEST_SENDER));
g_assert(ofono_dbus_clients_remove(test->clients, TEST_SENDER));
g_assert(!ofono_dbus_clients_remove(test->clients, TEST_SENDER));
/* OK to add the same thing twice */
g_assert(ofono_dbus_clients_add(test->clients, TEST_SENDER));
g_assert(ofono_dbus_clients_add(test->clients, TEST_SENDER));
g_assert_cmpuint(ofono_dbus_clients_count(test->clients), == ,1);
test_dbus_watch_disconnect_all();
g_assert_cmpuint(ofono_dbus_clients_count(test->clients), == ,0);
/* There's nothing to remove */
g_assert(!ofono_dbus_clients_remove(test->clients, TEST_SENDER));
g_assert(!ofono_dbus_clients_remove(test->clients, NULL));
/* These have no effect because client list is empty: */
ofono_dbus_clients_signal(test->clients, NULL);
ofono_dbus_clients_signal(test->clients, signal);
ofono_dbus_clients_signal_property_changed(test->clients, NULL, NULL,
NULL, 0, NULL);
ofono_dbus_clients_signal_property_changed(test->clients,
TEST_DBUS_PATH, TEST_DBUS_INTERFACE,
TEST_PROPERTY_NAME, DBUS_TYPE_STRING, &value);
/* test_basic_notify_func() has called test_loop_quit_later() */
dbus_message_unref(signal);
}
static void test_basic(void)
{
struct test_data test;
guint timeout = test_setup_timeout();
memset(&test, 0, sizeof(test));
test_dbus_setup(&test.dbus);
test.dbus.start = test_basic_start;
g_main_loop_run(test.dbus.loop);
g_assert(test.clients);
ofono_dbus_clients_free(test.clients);
test_dbus_shutdown(&test.dbus);
if (timeout) {
g_source_remove(timeout);
}
}
/* ==== signal ==== */
static void test_signal_handle(struct test_dbus_context *dbus, DBusMessage *msg)
{
struct test_data *test = G_CAST(dbus, struct test_data, dbus);
g_assert_cmpstr(dbus_message_get_path(msg), == ,TEST_DBUS_PATH);
g_assert_cmpstr(dbus_message_get_interface(msg), == ,
TEST_DBUS_INTERFACE);
g_assert_cmpstr(dbus_message_get_member(msg), == ,
TEST_PROPERTY_CHANGED_SIGNAL);
test->count++;
if (test->count == 2) {
test_loop_quit_later(dbus->loop);
}
}
static void test_signal_start(struct test_dbus_context *dbus)
{
struct test_data *test = G_CAST(dbus, struct test_data, dbus);
const char *value = TEST_PROPERTY_VALUE;
test_register_dummy_interface();
test->clients = ofono_dbus_clients_new(ofono_dbus_get_connection(),
NULL, NULL);
g_assert(ofono_dbus_clients_add(test->clients, TEST_SENDER));
g_assert(ofono_dbus_clients_add(test->clients, TEST_SENDER_1));
g_assert_cmpuint(ofono_dbus_clients_count(test->clients), == ,2);
ofono_dbus_clients_signal_property_changed(test->clients,
TEST_DBUS_PATH, TEST_DBUS_INTERFACE,
TEST_PROPERTY_NAME, DBUS_TYPE_STRING, &value);
/* And wait for 2 signals to arrive */
}
static void test_signal(void)
{
struct test_data test;
guint timeout = test_setup_timeout();
memset(&test, 0, sizeof(test));
test_dbus_setup(&test.dbus);
test.dbus.start = test_signal_start;
test.dbus.handle_signal = test_signal_handle;
g_main_loop_run(test.dbus.loop);
g_assert_cmpuint(ofono_dbus_clients_count(test.clients), == ,2);
test_dbus_watch_disconnect_all();
g_assert_cmpuint(ofono_dbus_clients_count(test.clients), == ,0);
ofono_dbus_clients_free(test.clients);
test_dbus_shutdown(&test.dbus);
if (timeout) {
g_source_remove(timeout);
}
}
#define TEST_(name) "/dbus-clients/" name
int main(int argc, char *argv[])
{
int i;
g_test_init(&argc, &argv, NULL);
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if (!strcmp(arg, "-d") || !strcmp(arg, "--debug")) {
test_debug = TRUE;
} else {
GWARN("Unsupported command line option %s", arg);
}
}
gutil_log_timestamp = FALSE;
gutil_log_default.level = g_test_verbose() ?
GLOG_LEVEL_VERBOSE : GLOG_LEVEL_NONE;
__ofono_log_init("test-dbus-clients",
g_test_verbose() ? "*" : NULL,
FALSE, FALSE);
g_test_add_func(TEST_("null"), test_null);
g_test_add_func(TEST_("basic"), test_basic);
g_test_add_func(TEST_("signal"), test_signal);
return g_test_run();
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2021 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -133,6 +133,13 @@ guint g_dbus_add_signal_watch(DBusConnection *connection, const char *sender,
return test_dbus_add_watch(connection, NULL, destroy, user_data);
}
guint g_dbus_add_disconnect_watch(DBusConnection *connection, const char *name,
GDBusWatchFunction func, void *user_data,
GDBusDestroyFunction destroy)
{
return test_dbus_add_watch(connection, func, destroy, user_data);
}
gboolean g_dbus_remove_watch(DBusConnection *connection, guint id)
{
struct test_dbus_watch *prev = NULL;
@@ -303,6 +310,9 @@ static DBusHandlerResult test_dbus_client_message_cb(DBusConnection *conn,
dbus_message_get_path(msg));
test->client_signals = g_slist_append(test->client_signals,
dbus_message_ref(msg));
if (test->handle_signal) {
test->handle_signal(test, msg);
}
return DBUS_HANDLER_RESULT_HANDLED;
} else {
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018-2021 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -25,6 +25,7 @@ struct test_dbus_context {
DBusConnection *client_connection;
GSList* client_signals;
void (*start)(struct test_dbus_context *test);
void (*handle_signal)(struct test_dbus_context *test, DBusMessage *msg);
guint timeout_id;
};

View File

@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony
*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018-2021 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -31,6 +31,7 @@
#define CELL_INFO_DBUS_INTERFACE "org.nemomobile.ofono.CellInfo"
#define CELL_INFO_DBUS_CELLS_ADDED_SIGNAL "CellsAdded"
#define CELL_INFO_DBUS_CELLS_REMOVED_SIGNAL "CellsRemoved"
#define CELL_INFO_DBUS_UNSUBSCRIBED_SIGNAL "Unsubscribed"
#define CELL_DBUS_INTERFACE_VERSION (1)
#define CELL_DBUS_INTERFACE "org.nemomobile.ofono.Cell"
@@ -66,7 +67,7 @@ static gboolean test_timeout(gpointer param)
static guint test_setup_timeout(void)
{
if (!test_debug) {
if (test_debug) {
return 0;
} else {
return g_timeout_add_seconds(TEST_TIMEOUT, test_timeout, NULL);
@@ -102,6 +103,19 @@ static DBusMessage *test_new_cell_call(const char *path, const char *method)
return msg;
}
static void test_submit_cell_info_call(DBusConnection* connection,
const char *method, DBusPendingCallNotifyFunction notify,
void *data)
{
DBusMessage *msg = test_new_cell_info_call(method);
DBusPendingCall* call;
g_assert(dbus_connection_send_with_reply(connection, msg, &call,
DBUS_TIMEOUT_INFINITE));
dbus_pending_call_set_notify(call, notify, data, NULL);
dbus_message_unref(msg);
}
static void test_submit_get_all_call(DBusConnection* connection,
const char *cell_path, DBusPendingCallNotifyFunction notify,
void *data)
@@ -186,6 +200,26 @@ static void test_check_get_all_reply(DBusPendingCall *call,
dbus_message_unref(reply);
}
static void test_check_empty_reply(DBusPendingCall *call)
{
DBusMessage *reply = dbus_pending_call_steal_reply(call);
DBusMessageIter it;
g_assert(dbus_message_get_type(reply) ==
DBUS_MESSAGE_TYPE_METHOD_RETURN);
dbus_message_iter_init(reply, &it);
g_assert(dbus_message_iter_get_arg_type(&it) == DBUS_TYPE_INVALID);
dbus_message_unref(reply);
}
static void test_check_error(DBusPendingCall *call, const char* name)
{
DBusMessage *reply = dbus_pending_call_steal_reply(call);
g_assert(dbus_message_is_error(reply, name));
dbus_message_unref(reply);
}
static struct sailfish_cell *test_cell_init_gsm1(struct sailfish_cell *cell)
{
struct sailfish_cell_info_gsm *gsm = &cell->info.gsm;
@@ -311,19 +345,13 @@ struct test_get_cells_data {
static void test_get_cells_call(struct test_get_cells_data *test,
DBusPendingCallNotifyFunction notify)
{
DBusPendingCall *call;
DBusConnection *connection = test->context.client_connection;
DBusMessage *msg = test_new_cell_info_call("GetCells");
g_assert(dbus_connection_send_with_reply(connection, msg, &call,
DBUS_TIMEOUT_INFINITE));
dbus_pending_call_set_notify(call, notify, test, NULL);
dbus_message_unref(msg);
test_submit_cell_info_call(test->context.client_connection, "GetCells",
notify, test);
}
static void test_get_cells_start_reply3(DBusPendingCall *call, void *data)
{
struct test_get_cells_data *test = data;
struct test_get_cells_data *test = data;
DBusMessageIter it;
DBusMessage *signal = test_dbus_take_signal(&test->context,
test->modem.path, CELL_INFO_DBUS_INTERFACE,
@@ -344,7 +372,7 @@ static void test_get_cells_start_reply3(DBusPendingCall *call, void *data)
static void test_get_cells_start_reply2(DBusPendingCall *call, void *data)
{
struct test_get_cells_data *test = data;
struct test_get_cells_data *test = data;
const char *cell_added = "/test/cell_1";
struct sailfish_cell cell;
DBusMessageIter it;
@@ -371,7 +399,7 @@ static void test_get_cells_start_reply2(DBusPendingCall *call, void *data)
static void test_get_cells_start_reply1(DBusPendingCall *call, void *data)
{
struct test_get_cells_data *test = data;
struct test_get_cells_data *test = data;
struct sailfish_cell cell;
DBG("");
@@ -432,7 +460,7 @@ struct test_get_all_data {
static void test_get_all_reply(DBusPendingCall *call, void *data)
{
struct test_get_all_data *test = data;
struct test_get_all_data *test = data;
DBG("");
test_check_get_all_reply(call, &test->cell, test->type);
@@ -519,7 +547,7 @@ struct test_get_version_data {
static void test_get_version_reply(DBusPendingCall *call, void *data)
{
struct test_get_version_data *test = data;
struct test_get_version_data *test = data;
DBusMessage *reply = dbus_pending_call_steal_reply(call);
dbus_int32_t version;
@@ -588,7 +616,7 @@ struct test_get_type_data {
static void test_get_type_reply(DBusPendingCall *call, void *data)
{
struct test_get_type_data *test = data;
struct test_get_type_data *test = data;
DBusMessage *reply = dbus_pending_call_steal_reply(call);
DBusMessageIter it;
@@ -656,7 +684,7 @@ struct test_get_registered_data {
static void test_get_registered_reply(DBusPendingCall *call, void *data)
{
struct test_get_registered_data *test = data;
struct test_get_registered_data *test = data;
DBusMessage *reply = dbus_pending_call_steal_reply(call);
DBusMessageIter it;
@@ -725,7 +753,7 @@ struct test_get_properties_data {
static void test_get_properties_reply(DBusPendingCall *call, void *data)
{
struct test_get_properties_data *test = data;
struct test_get_properties_data *test = data;
DBusMessage *reply = dbus_pending_call_steal_reply(call);
DBusMessageIter it, array;
@@ -799,9 +827,9 @@ struct test_registered_changed_data {
const char *cell_path;
};
static void test_registered_changed_reply(DBusPendingCall *call, void *data)
static void test_registered_changed_reply2(DBusPendingCall *call, void *data)
{
struct test_registered_changed_data *test = data;
struct test_registered_changed_data *test = data;
DBG("");
test_check_get_all_reply(call, &test->cell, test->type);
@@ -810,17 +838,14 @@ static void test_registered_changed_reply(DBusPendingCall *call, void *data)
test_loop_quit_later(test->context.loop);
}
static void test_registered_changed_start(struct test_dbus_context *context)
static void test_registered_changed_reply1(DBusPendingCall *call, void *data)
{
struct test_registered_changed_data *test =
G_CAST(context, struct test_registered_changed_data, context);
struct test_registered_changed_data *test = data;
struct sailfish_cell *first_cell;
DBG("");
test->info = fake_cell_info_new();
fake_cell_info_add_cell(test->info, &test->cell);
test->dbus = sailfish_cell_info_dbus_new(&test->modem, test->info);
g_assert(test->dbus);
test_check_get_cells_reply(call, test->cell_path, NULL);
dbus_pending_call_unref(call);
/* Trigger "RegisteredChanged" signal */
first_cell = test->info->cells->data;
@@ -828,8 +853,24 @@ static void test_registered_changed_start(struct test_dbus_context *context)
first_cell->registered = !first_cell->registered;
fake_cell_info_cells_changed(test->info);
test_submit_get_all_call(context->client_connection, test->cell_path,
test_registered_changed_reply, test);
test_submit_get_all_call(test->context.client_connection,
test->cell_path, test_registered_changed_reply2, test);
}
static void test_registered_changed_start(struct test_dbus_context *context)
{
struct test_registered_changed_data *test =
G_CAST(context, struct test_registered_changed_data, context);
DBG("");
test->info = fake_cell_info_new();
fake_cell_info_add_cell(test->info, &test->cell);
test->dbus = sailfish_cell_info_dbus_new(&test->modem, test->info);
g_assert(test->dbus);
/* Submit GetCells to enable "RegisteredChanged" signals */
test_submit_cell_info_call(test->context.client_connection, "GetCells",
test_registered_changed_reply1, test);
}
static void test_registered_changed(void)
@@ -871,28 +912,26 @@ struct test_property_changed_data {
const char *cell_path;
};
static void test_property_changed_reply1(DBusPendingCall *call, void *data)
static void test_property_changed_reply2(DBusPendingCall *call, void *data)
{
struct test_property_changed_data *test = data;
struct test_property_changed_data *test = data;
DBG("");
test_check_get_all_reply(call, &test->cell, test->type);
dbus_pending_call_unref(call);
test_loop_quit_later(test->context.loop);
test_dbus_watch_disconnect_all();
}
static void test_property_changed_start(struct test_dbus_context *context)
static void test_property_changed_reply1(DBusPendingCall *call, void *data)
{
struct test_property_changed_data *test =
G_CAST(context, struct test_property_changed_data, context);
struct test_property_changed_data *test = data;
struct sailfish_cell *first_cell;
DBG("");
test->info = fake_cell_info_new();
fake_cell_info_add_cell(test->info, &test->cell);
test->dbus = sailfish_cell_info_dbus_new(&test->modem, test->info);
g_assert(test->dbus);
test_check_get_cells_reply(call, test->cell_path, NULL);
dbus_pending_call_unref(call);
/* Trigger "PropertyChanged" signal */
first_cell = test->info->cells->data;
@@ -900,8 +939,24 @@ static void test_property_changed_start(struct test_dbus_context *context)
(++(first_cell->info.gsm.signalStrength));
fake_cell_info_cells_changed(test->info);
test_submit_get_all_call(context->client_connection, test->cell_path,
test_property_changed_reply1, test);
test_submit_get_all_call(test->context.client_connection,
test->cell_path, test_property_changed_reply2, test);
}
static void test_property_changed_start(struct test_dbus_context *context)
{
struct test_property_changed_data *test =
G_CAST(context, struct test_property_changed_data, context);
DBG("");
test->info = fake_cell_info_new();
fake_cell_info_add_cell(test->info, &test->cell);
test->dbus = sailfish_cell_info_dbus_new(&test->modem, test->info);
g_assert(test->dbus);
/* Submit GetCells to enable "PropertyChanged" signals */
test_submit_cell_info_call(test->context.client_connection, "GetCells",
test_property_changed_reply1, test);
}
static void test_property_changed(void)
@@ -931,6 +986,106 @@ static void test_property_changed(void)
}
}
/* ==== Unsubscribe ==== */
struct test_unsubscribe_data {
struct ofono_modem modem;
struct test_dbus_context context;
struct sailfish_cell_info *info;
struct sailfish_cell_info_dbus *dbus;
struct sailfish_cell cell;
const char *type;
const char *cell_path;
};
static void test_unsubscribe_reply3(DBusPendingCall *call, void *data)
{
struct test_unsubscribe_data *test = data;
DBG("");
test_check_error(call, OFONO_ERROR_INTERFACE ".Failed");
dbus_pending_call_unref(call);
test_loop_quit_later(test->context.loop);
test_dbus_watch_disconnect_all();
}
static void test_unsubscribe_reply2(DBusPendingCall *call, void *data)
{
struct test_unsubscribe_data *test = data;
struct sailfish_cell *first_cell;
DBG("");
test_check_empty_reply(call);
dbus_pending_call_unref(call);
/* No "PropertyChanged" signal is expected because it's disabled */
first_cell = test->info->cells->data;
test->cell.info.gsm.signalStrength =
(++(first_cell->info.gsm.signalStrength));
fake_cell_info_cells_changed(test->info);
/* Submit Unsubscribe and expect and error */
test_submit_cell_info_call(test->context.client_connection,
"Unsubscribe", test_unsubscribe_reply3, test);
}
static void test_unsubscribe_reply1(DBusPendingCall *call, void *data)
{
struct test_unsubscribe_data *test = data;
DBG("");
test_check_get_cells_reply(call, test->cell_path, NULL);
dbus_pending_call_unref(call);
/* Submit Unsubscribe to disable "PropertyChanged" signals */
test_submit_cell_info_call(test->context.client_connection,
"Unsubscribe", test_unsubscribe_reply2, test);
}
static void test_unsubscribe_start(struct test_dbus_context *context)
{
struct test_unsubscribe_data *test =
G_CAST(context, struct test_unsubscribe_data, context);
DBG("");
test->info = fake_cell_info_new();
fake_cell_info_add_cell(test->info, &test->cell);
test->dbus = sailfish_cell_info_dbus_new(&test->modem, test->info);
g_assert(test->dbus);
/* Submit GetCells to enable "PropertyChanged" signals */
test_submit_cell_info_call(test->context.client_connection, "GetCells",
test_unsubscribe_reply1, test);
}
static void test_unsubscribe(void)
{
struct test_unsubscribe_data test;
guint timeout = test_setup_timeout();
memset(&test, 0, sizeof(test));
test.modem.path = TEST_MODEM_PATH;
test.context.start = test_unsubscribe_start;
test_cell_init_gsm1(&test.cell);
test.type = "gsm";
test.cell_path = "/test/cell_0";
test_dbus_setup(&test.context);
g_main_loop_run(test.context.loop);
/* We must have received "Unsubscribed" signal */
g_assert(test_dbus_find_signal(&test.context, test.modem.path,
CELL_INFO_DBUS_INTERFACE, CELL_INFO_DBUS_UNSUBSCRIBED_SIGNAL));
sailfish_cell_info_unref(test.info);
sailfish_cell_info_dbus_free(test.dbus);
test_dbus_shutdown(&test.context);
if (timeout) {
g_source_remove(timeout);
}
}
#define TEST_(name) "/sailfish_cell_info_dbus/" name
int main(int argc, char *argv[])
@@ -966,6 +1121,7 @@ int main(int argc, char *argv[])
g_test_add_func(TEST_("GetProperties"), test_get_properties);
g_test_add_func(TEST_("RegisteredChanged"), test_registered_changed);
g_test_add_func(TEST_("PropertyChanged"), test_property_changed);
g_test_add_func(TEST_("Unsubscribe"), test_unsubscribe);
return g_test_run();
}

View File

@@ -130,6 +130,9 @@ systemctl daemon-reload ||:
%postun
systemctl daemon-reload ||:
%transfiletriggerin -- %{_libdir}/ofono/plugins
systemctl try-restart ofono.service ||:
%files
%defattr(-,root,root,-)
%license COPYING