diff --git a/include/re_sipevent.h b/include/re_sipevent.h index 78de579..c7c0517 100644 --- a/include/re_sipevent.h +++ b/include/re_sipevent.h @@ -5,20 +5,29 @@ */ struct sipevent_sock; -struct sipsub; int sipevent_listen(struct sipevent_sock **sockp, struct sip *sip, uint32_t htsize_not, uint32_t htsize_sub, sip_msg_h *subh, void *arg); + +struct sipsub; + int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, - const char *uri, const char *from_name, + bool retry, const char *uri, const char *from_name, const char *from_uri, const char *event, uint32_t expires, const char *cuser, const char *routev[], uint32_t routec, sip_auth_h *authh, void *aarg, bool aref, sip_resp_h *resph, sip_msg_h *noth, void *arg, const char *fmt, ...); +int sipevent_refer(struct sipsub **subp, struct sipevent_sock *sock, + const char *uri, const char *from_name, + const char *from_uri, const char *cuser, + const char *routev[], uint32_t routec, + sip_auth_h *authh, void *aarg, bool aref, + sip_resp_h *resph, sip_msg_h *noth, void *arg, + const char *fmt, ...); struct sipevent_event { diff --git a/src/sipevent/listen.c b/src/sipevent/listen.c index fbf8cfc..c6e922c 100644 --- a/src/sipevent/listen.c +++ b/src/sipevent/listen.c @@ -84,16 +84,19 @@ static void notify_handler(struct sipevent_sock *sock, const struct sip_hdr *hdr; struct sipevent_event se; struct sipsub *sub; + bool indialog; sub = sipsub_find(sock, msg, true); if (!sub) { sub = sipsub_find(sock, msg, false); - if (!sub || sub->subscribed) { + if (!sub) { (void)sip_reply(sip, msg, 481, "Subsctiption Does Not Exist"); return; } + + indialog = false; } else { if (!sip_dialog_rseq_valid(sub->dlg, msg)) { @@ -102,6 +105,8 @@ static void notify_handler(struct sipevent_sock *sock, } (void)sip_dialog_update(sub->dlg, msg); + + indialog = true; } hdr = sip_msg_hdr(msg, SIP_HDR_EVENT); @@ -114,10 +119,9 @@ static void notify_handler(struct sipevent_sock *sock, hdr = sip_msg_hdr(msg, SIP_HDR_SUBSCRIPTION_STATE); - if (sub->subscribed && hdr && - !sipevent_substate_decode(&ss, &hdr->val)) { + if (indialog && hdr && !sipevent_substate_decode(&ss, &hdr->val)) { - re_printf("substate: %s (%u secs) [%r]\n", + re_printf("dialog substate: %s (%u secs) [%r]\n", sipevent_substate_name(ss.state), ss.expires, &ss.params); @@ -142,7 +146,10 @@ static void notify_handler(struct sipevent_sock *sock, sub->dlg = mem_deref(sub->dlg); hash_unlink(&sub->he); - sipevent_resubscribe(sub, 0); + if (sub->retry) + sipevent_resubscribe(sub, 0); + else + tmr_cancel(&sub->tmr); break; } } diff --git a/src/sipevent/sipevent.h b/src/sipevent/sipevent.h index 537288b..5117618 100644 --- a/src/sipevent/sipevent.h +++ b/src/sipevent/sipevent.h @@ -46,6 +46,8 @@ struct sipsub { uint32_t routec; bool subscribed; bool terminated; + bool refer; + bool retry; }; diff --git a/src/sipevent/subscribe.c b/src/sipevent/subscribe.c index 68c98f9..2ae067e 100644 --- a/src/sipevent/subscribe.c +++ b/src/sipevent/subscribe.c @@ -173,6 +173,7 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) (void)sip_dialog_update(sub->dlg, msg); } + sub->refer = false; sub->failc = 0; if (pl_isset(&msg->expires)) @@ -238,8 +239,10 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) mem_deref(sub); } else { - re_printf("will re-subscribe in %u ms...\n", wait); - tmr_start(&sub->tmr, wait, tmr_handler, sub); + if (sub->retry || sub->subscribed) { + re_printf("will re-subscribe in %u ms...\n", wait); + tmr_start(&sub->tmr, wait, tmr_handler, sub); + } sub->resph(err, msg, sub->arg); } } @@ -264,50 +267,40 @@ static int request(struct sipsub *sub, bool reset_ls) if (reset_ls) sip_loopstate_reset(&sub->ls); - return sip_drequestf(&sub->req, sub->sip, true, "SUBSCRIBE", sub->dlg, - 0, sub->auth, send_handler, response_handler, sub, - "Event: %s\r\n" - "Expires: %u\r\n" - "%s" - "Content-Length: 0\r\n" - "\r\n", - sub->event, - sub->expires, - sub->hdrs); + if (sub->refer) { + + return sip_drequestf(&sub->req, sub->sip, true, "REFER", + sub->dlg, 0, sub->auth, + send_handler, response_handler, sub, + "%s" + "Content-Length: 0\r\n" + "\r\n", + sub->hdrs); + } + else { + return sip_drequestf(&sub->req, sub->sip, true, "SUBSCRIBE", + sub->dlg, 0, sub->auth, + send_handler, response_handler, sub, + "Event: %s\r\n" + "Expires: %u\r\n" + "%s" + "Content-Length: 0\r\n" + "\r\n", + sub->event, + sub->expires, + sub->hdrs); + } } -/** - * Allocate a SIP subscriber client - * - * @param subp Pointer to allocated SIP subscriber client - * @param sock SIP Event socket - * @param uri SIP Request URI - * @param from_name SIP From-header Name (optional) - * @param from_uri SIP From-header URI - * @param event SIP Event to subscribe to - * @param expires Subscription expires value - * @param cuser Contact username - * @param routev Optional route vector - * @param routec Number of routes - * @param authh Authentication handler - * @param aarg Authentication handler argument - * @param aref True to ref argument - * @param resph SUBSCRIBE response handler - * @param noth Notify handler - * @param arg Response handler argument - * @param fmt Formatted strings with extra SIP Headers - * - * @return 0 if success, otherwise errorcode - */ -int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, - const char *uri, const char *from_name, - const char *from_uri, const char *event, - uint32_t expires, const char *cuser, - const char *routev[], uint32_t routec, - sip_auth_h *authh, void *aarg, bool aref, - sip_resp_h *resph, sip_msg_h *noth, void *arg, - const char *fmt, ...) +static int sipsub_alloc(struct sipsub **subp, struct sipevent_sock *sock, + bool refer, bool retry, const char *uri, + const char *from_name, const char *from_uri, + const char *event, uint32_t expires, const char *cuser, + const char *routev[], uint32_t routec, + sip_auth_h *authh, void *aarg, bool aref, + sip_resp_h *resph, sip_msg_h *noth, void *arg, + const char *fmt, va_list ap) { struct sipsub *sub; int err; @@ -377,16 +370,13 @@ int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, /* Custom SIP headers */ if (fmt) { - va_list ap; - - va_start(ap, fmt); err = re_vsdprintf(&sub->hdrs, fmt, ap); - va_end(ap); - if (err) goto out; } + sub->refer = refer; + sub->retry = retry; sub->sock = mem_ref(sock); sub->sip = mem_ref(sock->sip); sub->expires = expires; @@ -406,3 +396,91 @@ int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, return err; } + + +/** + * Allocate a SIP subscriber client + * + * @param subp Pointer to allocated SIP subscriber client + * @param sock SIP Event socket + * @param retry Re-subscribe if subscription terminates + * @param uri SIP Request URI + * @param from_name SIP From-header Name (optional) + * @param from_uri SIP From-header URI + * @param event SIP Event to subscribe to + * @param expires Subscription expires value + * @param cuser Contact username + * @param routev Optional route vector + * @param routec Number of routes + * @param authh Authentication handler + * @param aarg Authentication handler argument + * @param aref True to ref argument + * @param resph SUBSCRIBE response handler + * @param noth Notify handler + * @param arg Response handler argument + * @param fmt Formatted strings with extra SIP Headers + * + * @return 0 if success, otherwise errorcode + */ +int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, + bool retry, const char *uri, const char *from_name, + const char *from_uri, const char *event, + uint32_t expires, const char *cuser, + const char *routev[], uint32_t routec, + sip_auth_h *authh, void *aarg, bool aref, + sip_resp_h *resph, sip_msg_h *noth, void *arg, + const char *fmt, ...) +{ + va_list ap; + int err; + + va_start(ap, fmt); + err = sipsub_alloc(subp, sock, false, retry, uri, from_name, from_uri, + event, expires, cuser, routev, routec, authh, aarg, + aref, resph, noth, arg, fmt, ap); + va_end(ap); + + return err; +} + + +/** + * Allocate a SIP refer client + * + * @param subp Pointer to allocated SIP subscriber client + * @param sock SIP Event socket + * @param uri SIP Request URI + * @param from_name SIP From-header Name (optional) + * @param from_uri SIP From-header URI + * @param cuser Contact username + * @param routev Optional route vector + * @param routec Number of routes + * @param authh Authentication handler + * @param aarg Authentication handler argument + * @param aref True to ref argument + * @param resph SUBSCRIBE response handler + * @param noth Notify handler + * @param arg Response handler argument + * @param fmt Formatted strings with extra SIP Headers + * + * @return 0 if success, otherwise errorcode + */ +int sipevent_refer(struct sipsub **subp, struct sipevent_sock *sock, + const char *uri, const char *from_name, + const char *from_uri, const char *cuser, + const char *routev[], uint32_t routec, + sip_auth_h *authh, void *aarg, bool aref, + sip_resp_h *resph, sip_msg_h *noth, void *arg, + const char *fmt, ...) +{ + va_list ap; + int err; + + va_start(ap, fmt); + err = sipsub_alloc(subp, sock, true, false, uri, from_name, from_uri, + "refer", DEFAULT_EXPIRES, cuser, routev, routec, + authh, aarg, aref, resph, noth, arg, fmt, ap); + va_end(ap); + + return err; +} diff --git a/src/sipsess/listen.c b/src/sipsess/listen.c index 139653f..81820ee 100644 --- a/src/sipsess/listen.c +++ b/src/sipsess/listen.c @@ -266,6 +266,10 @@ static bool request_handler(const struct sip_msg *msg, void *arg) return true; } else if (!pl_strcmp(&msg->met, "REFER")) { + + if (!pl_isset(&msg->to.tag)) + return false; + refer_handler(sock, msg); return true; }