summaryrefslogtreecommitdiffstats
path: root/src/voicecall.c
diff options
context:
space:
mode:
authorDenis Kenzior <denkenz@gmail.com>2011-07-14 17:33:08 -0500
committerDenis Kenzior <denkenz@gmail.com>2011-07-14 18:28:33 -0500
commitb0566f0bb779e3f6c83fc22108f842a469cb4d22 (patch)
tree735aaee14f0a6d8fa597a5509a1e11c6e248f814 /src/voicecall.c
parent2ff685ac5468ddb83497b80dbc27cbde480e2900 (diff)
downloadofono-b0566f0bb779e3f6c83fc22108f842a469cb4d22.tar.bz2
voicecall: Throttle emulators
Make sure that only a single request from (possibly multiple) emulators is ever sent to the voicecall driver. In the beginning it wasn't clear whether this will be necessary, however several command implementations already implemented basic throttling (+CHUP, ATD, CHLD=3, CHLD=2x) and it made sense to make this more formal. The other constraint is the abrupt removal of the emulator atom while an operation is pending. This case must be handled gracefully. See next commit.
Diffstat (limited to 'src/voicecall.c')
-rw-r--r--src/voicecall.c80
1 files changed, 45 insertions, 35 deletions
diff --git a/src/voicecall.c b/src/voicecall.c
index f6d15ff7..241b38ea 100644
--- a/src/voicecall.c
+++ b/src/voicecall.c
@@ -48,15 +48,9 @@
GSList *g_drivers = NULL;
-struct multi_release {
- ofono_voicecall_cb_t cb;
- void *data;
-};
-
struct ofono_voicecall {
GSList *call_list;
GSList *release_list;
- struct multi_release multi_release;
GSList *multiparty_list;
GHashTable *en_list; /* emergency number list */
GSList *sim_en_list; /* Emergency numbers already read from SIM */
@@ -77,6 +71,7 @@ struct ofono_voicecall {
unsigned int hfp_watch;
GKeyFile *settings;
char *imsi;
+ ofono_voicecall_cb_t release_queue_done_cb;
struct ofono_emulator *pending_em;
unsigned int pending_id;
char *em_atd_number;
@@ -1219,7 +1214,8 @@ static void voicecalls_emit_call_added(struct ofono_voicecall *vc,
g_dbus_send_message(ofono_dbus_get_connection(), signal);
}
-static void voicecalls_release_queue(struct ofono_voicecall *vc, GSList *calls)
+static void voicecalls_release_queue(struct ofono_voicecall *vc, GSList *calls,
+ ofono_voicecall_cb_t cb)
{
GSList *l;
struct voicecall *call;
@@ -1235,6 +1231,8 @@ static void voicecalls_release_queue(struct ofono_voicecall *vc, GSList *calls)
vc->release_list = g_slist_prepend(vc->release_list, l->data);
}
+
+ vc->release_queue_done_cb = cb;
}
static void voicecalls_release_next(struct ofono_voicecall *vc)
@@ -1696,9 +1694,8 @@ static DBusMessage *manager_hangup_all(DBusConnection *conn,
vc->pending = dbus_message_ref(msg);
if (vc->driver->hangup_all == NULL) {
- voicecalls_release_queue(vc, vc->call_list);
- vc->multi_release.cb = voicecalls_release_done;
- vc->multi_release.data = vc;
+ voicecalls_release_queue(vc, vc->call_list,
+ voicecalls_release_done);
voicecalls_release_next(vc);
} else
vc->driver->hangup_all(vc, generic_callback, vc);
@@ -1950,9 +1947,8 @@ static DBusMessage *multiparty_hangup(DBusConnection *conn,
}
/* Fall back to the old-fashioned way */
- voicecalls_release_queue(vc, vc->multiparty_list);
- vc->multi_release.cb = voicecalls_release_done;
- vc->multi_release.data = vc;
+ voicecalls_release_queue(vc, vc->multiparty_list,
+ voicecalls_release_done);
voicecalls_release_next(vc);
out:
@@ -2263,7 +2259,7 @@ static void multirelease_callback(const struct ofono_error *error, void *data)
return;
}
- vc->multi_release.cb(error, vc->multi_release.data);
+ vc->release_queue_done_cb(error, vc);
}
static void emit_en_list_changed(struct ofono_voicecall *vc)
@@ -2706,9 +2702,10 @@ static void sim_watch(struct ofono_atom *atom,
static void emulator_generic_cb(const struct ofono_error *error, void *data)
{
- struct ofono_emulator *em = data;
+ struct ofono_voicecall *vc = data;
- ofono_emulator_send_final(em, error);
+ ofono_emulator_send_final(vc->pending_em, error);
+ vc->pending_em = NULL;
}
static void emulator_mpty_join_cb(const struct ofono_error *error, void *data)
@@ -2781,8 +2778,16 @@ static void emulator_mpty_private_chat_cb(const struct ofono_error *error,
g_slist_free(old);
}
+#define CHECK_BUSY(vc, em, result) \
+ if (vc->pending || vc->dial_req || vc->pending_em) { \
+ result.error = 126; \
+ result.type = OFONO_ERROR_TYPE_CME; \
+ ofono_emulator_send_final(em, &result); \
+ } \
+
static void emulator_ata_cb(struct ofono_emulator *em,
- struct ofono_emulator_request *req, void *userdata)
+ struct ofono_emulator_request *req,
+ void *userdata)
{
struct ofono_voicecall *vc = userdata;
struct ofono_error result;
@@ -2791,13 +2796,16 @@ static void emulator_ata_cb(struct ofono_emulator *em,
switch (ofono_emulator_request_get_type(req)) {
case OFONO_EMULATOR_REQUEST_TYPE_COMMAND_ONLY:
+ CHECK_BUSY(vc, em, result)
+
if (!voicecalls_have_incoming(vc))
goto fail;
if (vc->driver->answer == NULL)
goto fail;
- vc->driver->answer(vc, emulator_generic_cb, em);
+ vc->pending_em = em;
+ vc->driver->answer(vc, emulator_generic_cb, vc);
break;
default:
@@ -2819,7 +2827,7 @@ static void emulator_chup_cb(struct ofono_emulator *em,
switch (ofono_emulator_request_get_type(req)) {
case OFONO_EMULATOR_REQUEST_TYPE_COMMAND_ONLY:
- if (vc->release_list)
+ if (vc->pending || vc->pending_em)
goto fail;
if (vc->driver->release_specific == NULL &&
@@ -2827,7 +2835,8 @@ static void emulator_chup_cb(struct ofono_emulator *em,
goto fail;
if (vc->driver->hangup_active) {
- vc->driver->hangup_active(vc, emulator_generic_cb, em);
+ vc->pending_em = em;
+ vc->driver->hangup_active(vc, emulator_generic_cb, vc);
goto done;
}
@@ -2845,8 +2854,8 @@ static void emulator_chup_cb(struct ofono_emulator *em,
if (vc->release_list == NULL)
goto fail;
- vc->multi_release.cb = emulator_generic_cb;
- vc->multi_release.data = em;
+ vc->pending_em = em;
+ vc->release_queue_done_cb = emulator_generic_cb;
voicecalls_release_next(vc);
done:
@@ -2939,6 +2948,8 @@ static void emulator_chld_cb(struct ofono_emulator *em,
if (!ofono_emulator_request_next_number(req, &chld))
goto fail;
+ CHECK_BUSY(vc, em, result)
+
switch (chld) {
case 0:
if (vc->driver->set_udub == NULL)
@@ -2947,42 +2958,42 @@ static void emulator_chld_cb(struct ofono_emulator *em,
if (vc->driver->release_all_held == NULL)
goto fail;
+ vc->pending_em = em;
+
if (voicecalls_have_waiting(vc)) {
vc->driver->set_udub(vc,
- emulator_generic_cb, em);
+ emulator_generic_cb, vc);
return;
}
vc->driver->release_all_held(vc,
- emulator_generic_cb, em);
+ emulator_generic_cb, vc);
return;
case 1:
if (vc->driver->release_all_active == NULL)
goto fail;
+ vc->pending_em = em;
vc->driver->release_all_active(vc,
- emulator_generic_cb, em);
+ emulator_generic_cb, vc);
return;
case 2:
if (vc->driver->hold_all_active == NULL)
goto fail;
+ vc->pending_em = em;
vc->driver->hold_all_active(vc,
- emulator_generic_cb, em);
+ emulator_generic_cb, vc);
return;
case 3:
if (vc->driver->create_multiparty == NULL)
goto fail;
- if (vc->pending_em || vc->pending || vc->dial_req)
- goto fail;
-
if (!voicecalls_have_held(vc) ||
!voicecalls_have_active(vc))
goto fail;
vc->pending_em = em;
-
vc->driver->create_multiparty(vc,
emulator_mpty_join_cb, vc);
return;
@@ -2990,8 +3001,9 @@ static void emulator_chld_cb(struct ofono_emulator *em,
if (vc->driver->transfer == NULL)
goto fail;
+ vc->pending_em = em;
vc->driver->transfer(vc,
- emulator_generic_cb, em);
+ emulator_generic_cb, vc);
return;
default:
break;
@@ -3001,8 +3013,9 @@ static void emulator_chld_cb(struct ofono_emulator *em,
if (vc->driver->release_specific == NULL)
goto fail;
+ vc->pending_em = em;
vc->driver->release_specific(vc, chld - 10,
- emulator_generic_cb, em);
+ emulator_generic_cb, vc);
return;
}
@@ -3013,9 +3026,6 @@ static void emulator_chld_cb(struct ofono_emulator *em,
if (vc->driver->private_chat == NULL)
goto fail;
- if (vc->pending_em || vc->pending || vc->dial_req)
- goto fail;
-
for (l = vc->multiparty_list; l; l = l->next) {
struct voicecall *v = l->data;
if (v->call->id == id)