diff options
-rw-r--r-- | include/baresip.h | 1 | ||||
-rw-r--r-- | modules/mwi/mwi.c | 70 | ||||
-rw-r--r-- | modules/presence/presence.c | 27 | ||||
-rw-r--r-- | modules/presence/presence.h | 1 | ||||
-rw-r--r-- | modules/presence/subscriber.c | 47 | ||||
-rw-r--r-- | src/ua.c | 37 |
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); + } +} @@ -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 "?"; } } |