summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/baresip.h1
-rw-r--r--modules/mwi/mwi.c70
-rw-r--r--modules/presence/presence.c27
-rw-r--r--modules/presence/presence.h1
-rw-r--r--modules/presence/subscriber.c47
-rw-r--r--src/ua.c37
6 files changed, 172 insertions, 11 deletions
diff --git a/include/baresip.h b/include/baresip.h
index 74cef89..76da052 100644
--- a/include/baresip.h
+++ b/include/baresip.h
@@ -489,6 +489,7 @@ enum ua_event {
UA_EVENT_CALL_TRANSFER_FAILED,
UA_EVENT_CALL_DTMF_START,
UA_EVENT_CALL_DTMF_END,
+ UA_EVENT_SHUTDOWN,
UA_EVENT_MAX,
};
diff --git a/modules/mwi/mwi.c b/modules/mwi/mwi.c
index c1670a0..8ce6fe4 100644
--- a/modules/mwi/mwi.c
+++ b/modules/mwi/mwi.c
@@ -20,6 +20,8 @@ struct mwi {
struct le le;
struct sipsub *sub;
struct ua *ua;
+ struct tmr tmr;
+ bool shutdown;
};
static struct tmr tmr;
@@ -30,8 +32,17 @@ static void destructor(void *arg)
{
struct mwi *mwi = arg;
+ tmr_cancel(&mwi->tmr);
list_unlink(&mwi->le);
mem_deref(mwi->sub);
+ mem_deref(mwi->ua);
+}
+
+
+static void deref_handler(void *arg)
+{
+ struct mwi *mwi = arg;
+ mem_deref(mwi);
}
@@ -54,6 +65,9 @@ static void notify_handler(struct sip *sip, const struct sip_msg *msg,
}
(void)sip_treply(NULL, sip, msg, 200, "OK");
+
+ if (mwi->shutdown)
+ mem_deref(mwi);
}
@@ -85,7 +99,7 @@ static int mwi_subscribe(struct ua *ua)
return ENOMEM;
list_append(&mwil, &mwi->le, mwi);
- mwi->ua = ua;
+ mwi->ua = mem_ref(ua);
routev[0] = ua_outbound(ua);
@@ -110,6 +124,22 @@ static int mwi_subscribe(struct ua *ua)
}
+static struct mwi *mwi_find(const struct ua *ua)
+{
+ struct le *le;
+
+ for (le = mwil.head; le; le = le->next) {
+
+ struct mwi *mwi = le->data;
+
+ if (mwi->ua == ua)
+ return mwi;
+ }
+
+ return NULL;
+}
+
+
static void ua_event_handler(struct ua *ua,
enum ua_event ev,
struct call *call,
@@ -119,12 +149,33 @@ static void ua_event_handler(struct ua *ua,
(void)call;
(void)prm;
- if (ua != (struct ua *)arg)
- return;
+ info("mwi: got event %d (%s)\n", ev, uag_event_str(ev));
if (ev == UA_EVENT_REGISTER_OK) {
- uag_event_unregister(ua_event_handler);
- mwi_subscribe(ua);
+
+ if (!mwi_find(ua))
+ mwi_subscribe(ua);
+ }
+ else if (ev == UA_EVENT_SHUTDOWN) {
+
+ struct le *le;
+
+ info("mwi: shutdown\n");
+
+ le = list_head(&mwil);
+ while (le) {
+ struct mwi *mwi = le->data;
+ le = le->next;
+
+ mwi->shutdown = true;
+
+ if (mwi->sub) {
+ mwi->sub = mem_deref(mwi->sub);
+ tmr_start(&mwi->tmr, 500, deref_handler, mwi);
+ }
+ else
+ mem_deref(mwi);
+ }
}
}
@@ -138,10 +189,10 @@ static void tmr_handler(void *arg)
for (le = list_head(uag_list()); le; le = le->next) {
struct ua *ua = le->data;
struct account *acc = ua_account(ua);
- if (account_regint(acc) > 0)
- uag_event_register(ua_event_handler, ua);
- else
+
+ if (account_regint(acc) == 0) {
mwi_subscribe(ua);
+ }
}
}
@@ -151,12 +202,13 @@ static int module_init(void)
list_init(&mwil);
tmr_start(&tmr, 1, tmr_handler, 0);
- return 0;
+ return uag_event_register(ua_event_handler, NULL);
}
static int module_close(void)
{
+ uag_event_unregister(ua_event_handler);
tmr_cancel(&tmr);
list_flush(&mwil);
diff --git a/modules/presence/presence.c b/modules/presence/presence.c
index 8b706dc..fd31790 100644
--- a/modules/presence/presence.c
+++ b/modules/presence/presence.c
@@ -52,6 +52,21 @@ static const struct cmd cmdv[] = {
};
+static void event_handler(struct ua *ua, enum ua_event ev,
+ struct call *call, const char *prm, void *arg)
+{
+ debug("presence: ua=%p got event %d (%s)\n", ua, ev,
+ uag_event_str(ev));
+
+ if (ev == UA_EVENT_SHUTDOWN) {
+
+ publisher_close();
+ notifier_close();
+ subscriber_close_all();
+ }
+}
+
+
static int module_init(void)
{
int err;
@@ -68,12 +83,22 @@ static int module_init(void)
if (err)
return err;
- return cmd_register(cmdv, ARRAY_SIZE(cmdv));
+ err = cmd_register(cmdv, ARRAY_SIZE(cmdv));
+ if (err)
+ return err;
+
+ err = uag_event_register(event_handler, NULL);
+ if (err)
+ return err;
+
+ return err;
}
static int module_close(void)
{
+ uag_event_unregister(event_handler);
+
cmd_unregister(cmdv);
publisher_close();
diff --git a/modules/presence/presence.h b/modules/presence/presence.h
index 54fcaac..75d8e48 100644
--- a/modules/presence/presence.h
+++ b/modules/presence/presence.h
@@ -6,6 +6,7 @@
int subscriber_init(void);
void subscriber_close(void);
+void subscriber_close_all(void);
int notifier_init(void);
diff --git a/modules/presence/subscriber.c b/modules/presence/subscriber.c
index 66c15a2..9cc84b1 100644
--- a/modules/presence/subscriber.c
+++ b/modules/presence/subscriber.c
@@ -24,6 +24,8 @@ struct presence {
enum presence_status status;
unsigned failc;
struct contact *contact;
+ struct ua *ua;
+ bool shutdown;
};
static struct list presencel;
@@ -81,6 +83,9 @@ static void notify_handler(struct sip *sip, const struct sip_msg *msg,
const struct sip_hdr *type_hdr, *length_hdr;
struct pl pl;
+ if (pres->shutdown)
+ goto done;
+
pres->failc = 0;
type_hdr = sip_msg_hdr(msg, SIP_HDR_CONTENT_TYPE);
@@ -138,6 +143,9 @@ done:
(void)sip_treply(NULL, sip, msg, 200, "OK");
contact_set_presence(pres->contact, status);
+
+ if (pres->shutdown)
+ pres = mem_deref(pres);
}
@@ -177,10 +185,20 @@ static void destructor(void *arg)
{
struct presence *pres = arg;
+ debug("presence: subscriber destroyed\n");
+
list_unlink(&pres->le);
tmr_cancel(&pres->tmr);
mem_deref(pres->contact);
mem_deref(pres->sub);
+ mem_deref(pres->ua);
+}
+
+
+static void deref_handler(void *arg)
+{
+ struct mwi *mwi = arg;
+ mem_deref(mwi);
}
@@ -205,6 +223,9 @@ static int subscribe(struct presence *pres)
return ENOENT;
}
+ mem_deref(pres->ua);
+ pres->ua = mem_ref(ua);
+
pl_strcpy(&contact_addr(pres->contact)->auri, uri, sizeof(uri));
routev[0] = ua_outbound(ua);
@@ -282,3 +303,29 @@ void subscriber_close(void)
{
list_flush(&presencel);
}
+
+
+void subscriber_close_all(void)
+{
+ struct le *le;
+
+ info("presence: subscriber: closing %u subs\n",
+ list_count(&presencel));
+
+ le = presencel.head;
+ while (le) {
+
+ struct presence *pres = le->data;
+ le = le->next;
+
+ debug("presence: shutdown: sub=%p\n", pres->sub);
+
+ pres->shutdown = true;
+ if (pres->sub) {
+ pres->sub = mem_deref(pres->sub);
+ tmr_start(&pres->tmr, 500, deref_handler, pres);
+ }
+ else
+ mem_deref(pres);
+ }
+}
diff --git a/src/ua.c b/src/ua.c
index 7997a88..01dd48e 100644
--- a/src/ua.c
+++ b/src/ua.c
@@ -533,6 +533,10 @@ static void ua_destructor(void *arg)
mem_deref(ua->cuser);
mem_deref(ua->pub_gruu);
mem_deref(ua->acc);
+
+ if (list_isempty(&uag.ual)) {
+ sip_close(uag.sip, false);
+ }
}
@@ -1425,7 +1429,37 @@ void ua_close(void)
*/
void ua_stop_all(bool forced)
{
- module_app_unload();
+ struct le *le;
+ bool ext_ref = false;
+
+ info("ua: stop all (forced=%d)\n", forced);
+
+ /* check if someone else has grabbed a ref to ua */
+ le = uag.ual.head;
+ while (le) {
+
+ struct ua *ua = le->data;
+ le = le->next;
+
+ if (mem_nrefs(ua) > 1) {
+
+ list_unlink(&ua->le);
+ list_flush(&ua->calls);
+ mem_deref(ua);
+
+ ext_ref = true;
+ }
+
+ ua_event(ua, UA_EVENT_SHUTDOWN, NULL, NULL);
+ }
+
+ if (ext_ref) {
+ info("ua: ext_ref -> cannot unload mods\n");
+ return;
+ }
+ else {
+ module_app_unload();
+ }
if (!list_isempty(&uag.ual)) {
const uint32_t n = list_count(&uag.ual);
@@ -1596,6 +1630,7 @@ const char *uag_event_str(enum ua_event ev)
case UA_EVENT_CALL_TRANSFER_FAILED: return "TRANSFER_FAILED";
case UA_EVENT_CALL_DTMF_START: return "CALL_DTMF_START";
case UA_EVENT_CALL_DTMF_END: return "CALL_DTMF_END";
+ case UA_EVENT_SHUTDOWN: return "SHUTDOWN";
default: return "?";
}
}