diff --git a/src/sipevent/listen.c b/src/sipevent/listen.c index 9e9187f..73a52b6 100644 --- a/src/sipevent/listen.c +++ b/src/sipevent/listen.c @@ -210,12 +210,14 @@ static void notify_handler(struct sipevent_sock *sock, case SIPEVENT_PENDING: sub->subscribed = true; - if (!sub->terminated && pl_isset(&state.expires)) + if (!sub->terminated && !sub->termwait && + pl_isset(&state.expires)) sipsub_reschedule(sub, pl_u32(&state.expires) * 900); break; case SIPEVENT_TERMINATED: sub->subscribed = false; + sub->termconf = true; break; } @@ -228,8 +230,18 @@ static void notify_handler(struct sipevent_sock *sock, if (nrefs == 1) return; - if (!sub->terminated && state.state == SIPEVENT_TERMINATED) - sipsub_terminate(sub, 0, msg, &state); + if (state.state == SIPEVENT_TERMINATED) { + + if (!sub->terminated) { + sub->termwait = false; + sipsub_terminate(sub, 0, msg, &state); + } + else if (sub->termwait) { + sub->termwait = false; + tmr_cancel(&sub->tmr); + mem_deref(sub); + } + } } diff --git a/src/sipevent/sipevent.h b/src/sipevent/sipevent.h index 906b527..e186efb 100644 --- a/src/sipevent/sipevent.h +++ b/src/sipevent/sipevent.h @@ -79,6 +79,8 @@ struct sipsub { uint32_t failc; bool subscribed; bool terminated; + bool termconf; + bool termwait; bool refer; }; diff --git a/src/sipevent/subscribe.c b/src/sipevent/subscribe.c index 3415996..ecd14c3 100644 --- a/src/sipevent/subscribe.c +++ b/src/sipevent/subscribe.c @@ -23,6 +23,7 @@ enum { DEFAULT_EXPIRES = 3600, RESUB_FAIL_WAIT = 60000, RESUB_FAILC_MAX = 7, + NOTIFY_TIMEOUT = 10000, }; @@ -56,12 +57,19 @@ static bool terminate(struct sipsub *sub) sub->notifyh = internal_notify_handler; sub->closeh = internal_close_handler; + if (sub->termwait) { + mem_ref(sub); + return true; + } + + tmr_cancel(&sub->tmr); + if (sub->req) { mem_ref(sub); return true; } - if (sub->subscribed && !request(sub, true)) { + if (sub->expires && sub->subscribed && !request(sub, true)) { mem_ref(sub); return true; } @@ -74,14 +82,13 @@ static void destructor(void *arg) { struct sipsub *sub = arg; - tmr_cancel(&sub->tmr); - if (!sub->terminated) { if (terminate(sub)) return; } + tmr_cancel(&sub->tmr); hash_unlink(&sub->he); mem_deref(sub->req); mem_deref(sub->dlg); @@ -96,6 +103,21 @@ static void destructor(void *arg) } +static void notify_timeout_handler(void *arg) +{ + struct sipsub *sub = arg; + + re_printf("timeout waiting for NOTIFY\n"); + + sub->termwait = false; + + if (sub->terminated) + mem_deref(sub); + else + sipsub_terminate(sub, ETIMEDOUT, NULL, NULL); +} + + static void tmr_handler(void *arg) { struct sipsub *sub = arg; @@ -133,7 +155,6 @@ void sipsub_terminate(struct sipsub *sub, int err, const struct sip_msg *msg, closeh = sub->closeh; arg = sub->arg; - tmr_cancel(&sub->tmr); (void)terminate(sub); closeh(err, msg, substate, arg); @@ -198,9 +219,20 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) (void)sip_dialog_update(sub->dlg, msg); } - sub->subscribed = true; + if (!sub->termconf) + sub->subscribed = true; + sub->failc = 0; + if (!sub->expires && !sub->termconf) { + + re_printf("waiting for last NOTIFY\n"); + tmr_start(&sub->tmr, NOTIFY_TIMEOUT, + notify_timeout_handler, sub); + sub->termwait = true; + return; + } + if (sub->terminated) goto out; @@ -263,11 +295,9 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) out: sub->refer = false; - if (!sub->expires) { - mem_deref(sub); - } - else if (sub->terminated) { - if (!sub->subscribed || request(sub, true)) + if (sub->terminated) { + + if (!sub->expires || !sub->subscribed || request(sub, true)) mem_deref(sub); } else { @@ -301,9 +331,6 @@ static int print_event(struct re_printf *pf, const struct sipsub *sub) static int request(struct sipsub *sub, bool reset_ls) { - if (sub->terminated) - sub->expires = 0; - if (reset_ls) sip_loopstate_reset(&sub->ls); @@ -320,6 +347,9 @@ static int request(struct sipsub *sub, bool reset_ls) sub->refer_hdrs); } else { + if (sub->terminated) + sub->expires = 0; + return sip_drequestf(&sub->req, sub->sip, true, "SUBSCRIBE", sub->dlg, 0, sub->auth, send_handler, response_handler, sub, @@ -349,7 +379,7 @@ static int sipsub_alloc(struct sipsub **subp, struct sipevent_sock *sock, struct sipsub *sub; int err; - if (!subp || !sock || !event || !expires || !cuser) + if (!subp || !sock || !event || !cuser) return EINVAL; if (!dlg && (!uri || !from_uri)) @@ -635,6 +665,12 @@ int sipevent_fork(struct sipsub **subp, struct sipsub *osub, sub->closeh = closeh ? closeh : internal_close_handler; sub->arg = arg; + if (!sub->expires) { + tmr_start(&sub->tmr, NOTIFY_TIMEOUT, + notify_timeout_handler, sub); + sub->termwait = true; + } + out: if (err) mem_deref(sub);