From d7714ac5c51bd3304d1b9622f47157ef6d127c3d Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Mon, 14 Nov 2011 13:41:32 +0000 Subject: [PATCH 01/46] created sipevent branch From e0a4162a77cb44d23008c507ea74747416e29c64 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Mon, 14 Nov 2011 14:03:31 +0000 Subject: [PATCH 02/46] sipevent: initial sipsub framework --- Makefile | 2 +- include/re.h | 1 + include/re_sipevent.h | 15 +++ src/sipevent/mod.mk | 7 + src/sipevent/sub.c | 307 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 331 insertions(+), 1 deletion(-) create mode 100644 include/re_sipevent.h create mode 100644 src/sipevent/mod.mk create mode 100644 src/sipevent/sub.c diff --git a/Makefile b/Makefile index ac52c76..2c7ba73 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ MK := mk/re.mk include $(MK) # List of modules -MODULES += sip sipreg sipsess +MODULES += sip sipevent sipreg sipsess MODULES += uri httpauth MODULES += stun turn ice MODULES += natbd diff --git a/include/re.h b/include/re.h index ffca789..4aa80ef 100644 --- a/include/re.h +++ b/include/re.h @@ -36,6 +36,7 @@ extern "C" { #include "re_sdp.h" #include "re_uri.h" #include "re_sip.h" +#include "re_sipevent.h" #include "re_sipreg.h" #include "re_sipsess.h" #include "re_stun.h" diff --git a/include/re_sipevent.h b/include/re_sipevent.h new file mode 100644 index 0000000..cce9244 --- /dev/null +++ b/include/re_sipevent.h @@ -0,0 +1,15 @@ +/** + * @file re_sipevent.h SIP Event Framework + * + * Copyright (C) 2010 Creytiv.com + */ + +struct sipsub; + +int sipevent_subscribe(struct sipsub **subp, struct sip *sip, 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, void *arg, + const char *fmt, ...); diff --git a/src/sipevent/mod.mk b/src/sipevent/mod.mk new file mode 100644 index 0000000..6291b76 --- /dev/null +++ b/src/sipevent/mod.mk @@ -0,0 +1,7 @@ +# +# mod.mk +# +# Copyright (C) 2010 Creytiv.com +# + +SRCS += sipevent/sub.c diff --git a/src/sipevent/sub.c b/src/sipevent/sub.c new file mode 100644 index 0000000..fdbac85 --- /dev/null +++ b/src/sipevent/sub.c @@ -0,0 +1,307 @@ +/** + * @file sub.c SIP Subscription + * + * Copyright (C) 2010 Creytiv.com + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +enum { + DEFAULT_EXPIRES = 3600, +}; + + +/** Defines a SIP subscriber client */ +struct sipsub { + struct sip_loopstate ls; + struct tmr tmr; + struct sip *sip; + struct sip_request *req; + struct sip_dialog *dlg; + struct sip_auth *auth; + char *event; + char *cuser; + char *hdrs; + sip_resp_h *resph; + void *arg; + uint32_t expires; + uint32_t failc; + bool subscribed; + bool terminated; +}; + + +static int request(struct sipsub *sub, bool reset_ls); + + +static void dummy_handler(int err, const struct sip_msg *msg, void *arg) +{ + (void)err; + (void)msg; + (void)arg; +} + + +static void destructor(void *arg) +{ + struct sipsub *sub = arg; + + tmr_cancel(&sub->tmr); + + if (!sub->terminated) { + + sub->resph = dummy_handler; + sub->terminated = true; + + if (sub->req) { + mem_ref(sub); + return; + } + + if (sub->subscribed && !request(sub, true)) { + mem_ref(sub); + return; + } + } + + mem_deref(sub->dlg); + mem_deref(sub->auth); + mem_deref(sub->event); + mem_deref(sub->cuser); + mem_deref(sub->sip); + mem_deref(sub->hdrs); +} + + +static uint32_t failwait(uint32_t failc) +{ + return min(1800, (30 * (1<tmr, failwait(++sub->failc), tmr_handler, sub); + sub->resph(err, NULL, sub->arg); + } +} + + +static void response_handler(int err, const struct sip_msg *msg, void *arg) +{ + const struct sip_hdr *minexp; + struct sipsub *sub = arg; + uint32_t wait; + + wait = failwait(sub->failc + 1); + + if (err || sip_request_loops(&sub->ls, msg->scode)) { + sub->failc++; + goto out; + } + + if (msg->scode < 200) { + return; + } + else if (msg->scode < 300) { + + sub->subscribed = true; + sub->failc = 0; + + if (pl_isset(&msg->expires)) + wait = pl_u32(&msg->expires); + else + wait = DEFAULT_EXPIRES; + + wait *= 900; + } + else { + if (sub->terminated && !sub->subscribed) + goto out; + + switch (msg->scode) { + + case 401: + case 407: + err = sip_auth_authenticate(sub->auth, msg); + if (err) { + err = (err == EAUTH) ? 0 : err; + break; + } + + err = request(sub, false); + if (err) + break; + + return; + + case 403: + sip_auth_reset(sub->auth); + break; + + case 423: + minexp = sip_msg_hdr(msg, SIP_HDR_MIN_EXPIRES); + if (!minexp || !pl_u32(&minexp->val) || !sub->expires) + break; + + sub->expires = pl_u32(&minexp->val); + + err = request(sub, false); + if (err) + break; + + return; + } + + ++sub->failc; + } + + out: + if (!sub->expires) { + mem_deref(sub); + } + else if (sub->terminated) { + if (!sub->subscribed || request(sub, true)) + mem_deref(sub); + } + else { + tmr_start(&sub->tmr, wait, tmr_handler, sub); + sub->resph(err, msg, sub->arg); + } +} + + +static int send_handler(enum sip_transp tp, const struct sa *src, + const struct sa *dst, struct mbuf *mb, void *arg) +{ + struct sipsub *sub = arg; + (void)dst; + + return mbuf_printf(mb, "Contact: \r\n", + sub->cuser, src, sip_transp_param(tp)); +} + + +static int request(struct sipsub *sub, bool reset_ls) +{ + if (sub->terminated) + sub->expires = 0; + + 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); +} + + +/** + * Allocate a SIP subscriber client + * + * @param subp Pointer to allocated SIP subscriber client + * @param sip SIP Stack instance + * @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 Response 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 sip *sip, 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, void *arg, + const char *fmt, ...) +{ + struct sipsub *sub; + int err; + + if (!subp || !sip || !uri || !from_uri || !event || !expires || !cuser) + return EINVAL; + + sub = mem_zalloc(sizeof(*sub), destructor); + if (!sub) + return ENOMEM; + + err = sip_dialog_alloc(&sub->dlg, uri, uri, from_name, from_uri, + routev, routec); + if (err) + goto out; + + err = sip_auth_alloc(&sub->auth, authh, aarg, aref); + if (err) + goto out; + + err = str_dup(&sub->event, event); + if (err) + goto out; + + err = str_dup(&sub->cuser, cuser); + if (err) + goto out; + + /* 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->sip = mem_ref(sip); + sub->expires = expires; + sub->resph = resph ? resph : dummy_handler; + sub->arg = arg; + + err = request(sub, true); + if (err) + goto out; + + out: + if (err) + mem_deref(sub); + else + *subp = sub; + + return err; +} From bf5657c3a6f8553c029e8d7d0b8268337ee90a3c Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Wed, 30 Nov 2011 08:08:20 +0000 Subject: [PATCH 03/46] sipevent: subscriber work in progress --- include/re_sip.h | 2 + include/re_sipevent.h | 30 ++++- src/sip/dialog.c | 19 ++++ src/sipevent/listen.c | 243 ++++++++++++++++++++++++++++++++++++++++ src/sipevent/mod.mk | 2 + src/sipevent/sipevent.h | 52 +++++++++ src/sipevent/sub.c | 173 ++++++++++++++++++++++------ src/sipevent/substate.c | 54 +++++++++ 8 files changed, 536 insertions(+), 39 deletions(-) create mode 100644 src/sipevent/listen.c create mode 100644 src/sipevent/sipevent.h create mode 100644 src/sipevent/substate.c diff --git a/include/re_sip.h b/include/re_sip.h index e6dd358..2bdde6d 100644 --- a/include/re_sip.h +++ b/include/re_sip.h @@ -301,6 +301,8 @@ int sip_dialog_update(struct sip_dialog *dlg, const struct sip_msg *msg); bool sip_dialog_rseq_valid(struct sip_dialog *dlg, const struct sip_msg *msg); const char *sip_dialog_callid(const struct sip_dialog *dlg); bool sip_dialog_cmp(const struct sip_dialog *dlg, const struct sip_msg *msg); +bool sip_dialog_cmp_half(const struct sip_dialog *dlg, + const struct sip_msg *msg); /* msg */ diff --git a/include/re_sipevent.h b/include/re_sipevent.h index cce9244..e7813cf 100644 --- a/include/re_sipevent.h +++ b/include/re_sipevent.h @@ -4,12 +4,34 @@ * Copyright (C) 2010 Creytiv.com */ +struct sipevent_sock; struct sipsub; -int sipevent_subscribe(struct sipsub **subp, struct sip *sip, const char *uri, - const char *from_name, const char *from_uri, - const char *event, uint32_t expires, const char *cuser, +int sipevent_listen(struct sipevent_sock **sockp, struct sip *sip, + uint32_t htsize_not, uint32_t htsize_sub, + sip_msg_h *subh, void *arg); + +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, void *arg, + sip_resp_h *resph, sip_msg_h *noth, void *arg, const char *fmt, ...); + + +enum sipevent_subst { + SIPEVENT_ACTIVE = 0, + SIPEVENT_TERMINATED, +}; + +struct sipevent_substate { + enum sipevent_subst state; + struct pl params; + uint32_t expires; +}; + +int sipevent_substate_decode(struct sipevent_substate *ss, + const struct pl *pl); +const char *sipevent_substate_name(enum sipevent_subst state); diff --git a/src/sip/dialog.c b/src/sip/dialog.c index b3e706c..a9b11bf 100644 --- a/src/sip/dialog.c +++ b/src/sip/dialog.c @@ -428,3 +428,22 @@ bool sip_dialog_cmp(const struct sip_dialog *dlg, const struct sip_msg *msg) return true; } + + +bool sip_dialog_cmp_half(const struct sip_dialog *dlg, + const struct sip_msg *msg) +{ + if (!dlg || !msg) + return false; + + if (pl_strcmp(&msg->callid, dlg->callid)) + return false; + + if (pl_strcmp(msg->req ? &msg->to.tag : &msg->from.tag, dlg->ltag)) + return false; + + if (dlg->rtag) + return false; + + return true; +} diff --git a/src/sipevent/listen.c b/src/sipevent/listen.c new file mode 100644 index 0000000..3203672 --- /dev/null +++ b/src/sipevent/listen.c @@ -0,0 +1,243 @@ +/** + * @file listen.c SIP Event Listen + * + * Copyright (C) 2010 Creytiv.com + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sipevent.h" + + +static void destructor(void *arg) +{ + struct sipevent_sock *sock = arg; + + mem_deref(sock->lsnr); + hash_flush(sock->ht_not); + hash_flush(sock->ht_sub); + mem_deref(sock->ht_not); + mem_deref(sock->ht_sub); +} + + +static bool not_cmp_handler(struct le *le, void *arg) +{ + const struct sip_msg *msg = arg; + struct sipnot *not = le->data; + + return sip_dialog_cmp(not->dlg, msg); +} + + +static bool sub_cmp_handler(struct le *le, void *arg) +{ + const struct sip_msg *msg = arg; + struct sipsub *sub = le->data; + + return sip_dialog_cmp(sub->dlg, msg); +} + + +static bool sub_cmp_half_handler(struct le *le, void *arg) +{ + const struct sip_msg *msg = arg; + struct sipsub *sub = le->data; + + return sip_dialog_cmp_half(sub->dlg, msg); +} + + +static struct sipnot *sipnot_find(struct sipevent_sock *sock, + const struct sip_msg *msg) +{ + return list_ledata(hash_lookup(sock->ht_not, + hash_joaat_pl(&msg->callid), + not_cmp_handler, (void *)msg)); +} + + +static struct sipsub *sipsub_find(struct sipevent_sock *sock, + const struct sip_msg *msg, bool full) +{ + return list_ledata(hash_lookup(sock->ht_sub, + hash_joaat_pl(&msg->callid), full ? + sub_cmp_handler : sub_cmp_half_handler, + (void *)msg)); +} + + +static void notify_handler(struct sipevent_sock *sock, + const struct sip_msg *msg) +{ + struct sipevent_substate ss; + struct sip *sip = sock->sip; + const struct sip_hdr *hdr; + struct sipsub *sub; + + sub = sipsub_find(sock, msg, true); + if (!sub) { + + sub = sipsub_find(sock, msg, false); + if (!sub || sub->subscribed) { + (void)sip_reply(sip, msg, + 481, "Subsctiption Does Not Exist"); + return; + } + } + else { + if (!sip_dialog_rseq_valid(sub->dlg, msg)) { + (void)sip_reply(sip, msg, 500,"Server Internal Error"); + return; + } + + // todo: check + (void)sip_dialog_update(sub->dlg, msg); + } + + hdr = sip_msg_hdr(msg, SIP_HDR_EVENT); + + // todo: check case sensitiveness, header syntax and status code + if (!hdr || pl_strcmp(&hdr->val, sub->event)) { + (void)sip_reply(sip, msg, 489, "Bad Event"); + return; + } + + hdr = sip_msg_hdr(msg, SIP_HDR_SUBSCRIPTION_STATE); + + if (sub->subscribed && hdr && + !sipevent_substate_decode(&ss, &hdr->val)) { + + re_printf("substate: %s (%u secs) [%r]\n", + sipevent_substate_name(ss.state), + ss.expires, &ss.params); + + switch (ss.state) { + + case SIPEVENT_ACTIVE: + if (sub->req || sub->terminated) + break; + + sipevent_resubscribe(sub, ss.expires * 900); + break; + + case SIPEVENT_TERMINATED: + sub->req = mem_deref(sub->req); /* forget request */ + + if (sub->terminated) { + mem_deref(sub); + goto reply; + } + + sub->subscribed = false; + sub->dlg = mem_deref(sub->dlg); + hash_unlink(&sub->he); + + sipevent_resubscribe(sub, 0); + break; + } + } + + if (sub->noth(msg, sub->arg)) + return; + + reply: + (void)sip_treply(NULL, sip, msg, 200, "OK"); +} + + +static void subscribe_handler(struct sipevent_sock *sock, + const struct sip_msg *msg) +{ + struct sip *sip = sock->sip; + struct sipnot *not; + + not = sipnot_find(sock, msg); + if (!not || not->terminated) { + (void)sip_reply(sip, msg, 481, "Subscription Does Not Exist"); + return; + } + + if (!sip_dialog_rseq_valid(not->dlg, msg)) { + (void)sip_reply(sip, msg, 500, "Server Internal Error"); + return; + } + + // todo: check + (void)sip_dialog_update(not->dlg, msg); + + // ... +} + + +static bool request_handler(const struct sip_msg *msg, void *arg) +{ + struct sipevent_sock *sock = arg; + + if (!pl_strcmp(&msg->met, "SUBSCRIBE")) { + + if (pl_isset(&msg->to.tag)) { + subscribe_handler(sock, msg); + return true; + } + + return sock->subh ? sock->subh(msg, arg) : false; + } + else if (!pl_strcmp(&msg->met, "NOTIFY")) { + + notify_handler(sock, msg); + return true; + } + else { + return false; + } +} + + +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 sipevent_sock *sock; + int err; + + if (!sockp || !sip || !htsize_not || !htsize_sub) + return EINVAL; + + sock = mem_zalloc(sizeof(*sock), destructor); + if (!sock) + return ENOMEM; + + err = sip_listen(&sock->lsnr, sip, true, request_handler, sock); + if (err) + goto out; + + err = hash_alloc(&sock->ht_not, htsize_not); + if (err) + goto out; + + err = hash_alloc(&sock->ht_sub, htsize_sub); + if (err) + goto out; + + sock->sip = sip; + sock->subh = subh; + sock->arg = arg; + + out: + if (err) + mem_deref(sock); + else + *sockp = sock; + + return err; +} diff --git a/src/sipevent/mod.mk b/src/sipevent/mod.mk index 6291b76..cf1c0c6 100644 --- a/src/sipevent/mod.mk +++ b/src/sipevent/mod.mk @@ -4,4 +4,6 @@ # Copyright (C) 2010 Creytiv.com # +SRCS += sipevent/listen.c SRCS += sipevent/sub.c +SRCS += sipevent/substate.c diff --git a/src/sipevent/sipevent.h b/src/sipevent/sipevent.h new file mode 100644 index 0000000..537288b --- /dev/null +++ b/src/sipevent/sipevent.h @@ -0,0 +1,52 @@ +/** + * @file sipevent.h SIP Event Private Interface + * + * Copyright (C) 2010 Creytiv.com + */ + + +struct sipevent_sock { + struct sip_lsnr *lsnr; + struct hash *ht_not; + struct hash *ht_sub; + struct sip *sip; + sip_msg_h *subh; + void *arg; +}; + + +struct sipnot { + struct le he; + struct sip_dialog *dlg; + bool terminated; +}; + + +struct sipsub { + struct le he; + struct sip_loopstate ls; + struct tmr tmr; + struct sipevent_sock *sock; + struct sip_request *req; + struct sip_dialog *dlg; + struct sip_auth *auth; + struct sip *sip; + char *uri; + char *from_name; + char *from_uri; + char **routev; + char *event; + char *cuser; + char *hdrs; + sip_resp_h *resph; + sip_msg_h *noth; + void *arg; + uint32_t expires; + uint32_t failc; + uint32_t routec; + bool subscribed; + bool terminated; +}; + + +void sipevent_resubscribe(struct sipsub *sub, uint32_t wait); diff --git a/src/sipevent/sub.c b/src/sipevent/sub.c index fdbac85..f8d7750 100644 --- a/src/sipevent/sub.c +++ b/src/sipevent/sub.c @@ -1,5 +1,5 @@ /** - * @file sub.c SIP Subscription + * @file sub.c SIP Event Subscriber * * Copyright (C) 2010 Creytiv.com */ @@ -15,6 +15,7 @@ #include #include #include +#include "sipevent.h" enum { @@ -22,30 +23,11 @@ enum { }; -/** Defines a SIP subscriber client */ -struct sipsub { - struct sip_loopstate ls; - struct tmr tmr; - struct sip *sip; - struct sip_request *req; - struct sip_dialog *dlg; - struct sip_auth *auth; - char *event; - char *cuser; - char *hdrs; - sip_resp_h *resph; - void *arg; - uint32_t expires; - uint32_t failc; - bool subscribed; - bool terminated; -}; - - static int request(struct sipsub *sub, bool reset_ls); -static void dummy_handler(int err, const struct sip_msg *msg, void *arg) +static void internal_response_handler(int err, const struct sip_msg *msg, + void *arg) { (void)err; (void)msg; @@ -53,6 +35,15 @@ static void dummy_handler(int err, const struct sip_msg *msg, void *arg) } +static bool internal_notify_handler(const struct sip_msg *msg, void *arg) +{ + (void)msg; + (void)arg; + + return false; +} + + static void destructor(void *arg) { struct sipsub *sub = arg; @@ -61,7 +52,8 @@ static void destructor(void *arg) if (!sub->terminated) { - sub->resph = dummy_handler; + sub->resph = internal_response_handler; + sub->noth = internal_notify_handler; sub->terminated = true; if (sub->req) { @@ -75,12 +67,27 @@ static void destructor(void *arg) } } + if (sub->routev) { + + uint32_t i; + + for (i=0; iroutec; i++) + mem_deref(sub->routev[i]); + + mem_deref(sub->routev); + } + + hash_unlink(&sub->he); mem_deref(sub->dlg); mem_deref(sub->auth); + mem_deref(sub->uri); + mem_deref(sub->from_name); + mem_deref(sub->from_uri); mem_deref(sub->event); mem_deref(sub->cuser); - mem_deref(sub->sip); mem_deref(sub->hdrs); + mem_deref(sub->sock); + mem_deref(sub->sip); } @@ -95,7 +102,25 @@ static void tmr_handler(void *arg) struct sipsub *sub = arg; int err; + if (!sub->dlg) { + + err = sip_dialog_alloc(&sub->dlg, sub->uri, sub->uri, + sub->from_name, sub->from_uri, + (const char **)sub->routev, + sub->routec); + if (err) + goto out; + + hash_append(sub->sock->ht_sub, + hash_joaat_str(sip_dialog_callid(sub->dlg)), + &sub->he, sub); + } + err = request(sub, true); + if (err) + goto out; + + out: if (err) { tmr_start(&sub->tmr, failwait(++sub->failc), tmr_handler, sub); sub->resph(err, NULL, sub->arg); @@ -103,6 +128,17 @@ static void tmr_handler(void *arg) } +void sipevent_resubscribe(struct sipsub *sub, uint32_t wait) +{ + if (!wait) + wait = failwait(++sub->failc); + + re_printf("will re-subscribe in %u ms\n", wait); + + tmr_start(&sub->tmr, wait, tmr_handler, sub); +} + + static void response_handler(int err, const struct sip_msg *msg, void *arg) { const struct sip_hdr *minexp; @@ -121,8 +157,24 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) } else if (msg->scode < 300) { - sub->subscribed = true; - sub->failc = 0; + if (!sub->subscribed) { + + err = sip_dialog_create(sub->dlg, msg); + if (err) { + sub->dlg = mem_deref(sub->dlg); + hash_unlink(&sub->he); + sub->failc++; + goto out; + } + + sub->subscribed = true; + } + else { + // todo: check + (void)sip_dialog_update(sub->dlg, msg); + } + + sub->failc = 0; if (pl_isset(&msg->expires)) wait = pl_u32(&msg->expires); @@ -167,6 +219,13 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) break; return; + + case 481: + // todo: test + sub->subscribed = false; + sub->dlg = mem_deref(sub->dlg); + hash_unlink(&sub->he); + break; } ++sub->failc; @@ -181,6 +240,7 @@ 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); sub->resph(err, msg, sub->arg); } @@ -223,7 +283,7 @@ static int request(struct sipsub *sub, bool reset_ls) * Allocate a SIP subscriber client * * @param subp Pointer to allocated SIP subscriber client - * @param sip SIP Stack instance + * @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 @@ -235,24 +295,26 @@ static int request(struct sipsub *sub, bool reset_ls) * @param authh Authentication handler * @param aarg Authentication handler argument * @param aref True to ref argument - * @param resph Response handler + * @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 sip *sip, const char *uri, - const char *from_name, const char *from_uri, - const char *event, uint32_t expires, const char *cuser, +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, void *arg, + sip_resp_h *resph, sip_msg_h *noth, void *arg, const char *fmt, ...) { struct sipsub *sub; int err; - if (!subp || !sip || !uri || !from_uri || !event || !expires || !cuser) + if (!subp || !sock || !uri || !from_uri || !event || !expires ||!cuser) return EINVAL; sub = mem_zalloc(sizeof(*sub), destructor); @@ -264,10 +326,49 @@ int sipevent_subscribe(struct sipsub **subp, struct sip *sip, const char *uri, if (err) goto out; + hash_append(sock->ht_sub, + hash_joaat_str(sip_dialog_callid(sub->dlg)), + &sub->he, sub); + err = sip_auth_alloc(&sub->auth, authh, aarg, aref); if (err) goto out; + err = str_dup(&sub->uri, uri); + if (err) + goto out; + + err = str_dup(&sub->from_uri, from_uri); + if (err) + goto out; + + if (from_name) { + + err = str_dup(&sub->from_name, from_name); + if (err) + goto out; + } + + sub->routec = routec; + + if (routec > 0) { + + uint32_t i; + + sub->routev = mem_zalloc(sizeof(*sub->routev) * routec, NULL); + if (!sub->routev) { + err = ENOMEM; + goto out; + } + + for (i=0; iroutev[i], routev[i]); + if (err) + goto out; + } + } + err = str_dup(&sub->event, event); if (err) goto out; @@ -288,9 +389,11 @@ int sipevent_subscribe(struct sipsub **subp, struct sip *sip, const char *uri, goto out; } - sub->sip = mem_ref(sip); + sub->sock = mem_ref(sock); + sub->sip = mem_ref(sock->sip); sub->expires = expires; - sub->resph = resph ? resph : dummy_handler; + sub->resph = resph ? resph : internal_response_handler; + sub->noth = noth ? noth : internal_notify_handler; sub->arg = arg; err = request(sub, true); diff --git a/src/sipevent/substate.c b/src/sipevent/substate.c new file mode 100644 index 0000000..dd72bed --- /dev/null +++ b/src/sipevent/substate.c @@ -0,0 +1,54 @@ +/** + * @file substate.c SIP Subscription-State header + * + * Copyright (C) 2010 Creytiv.com + */ +#include +#include +#include +#include +#include +#include +#include +#include + + +int sipevent_substate_decode(struct sipevent_substate *ss, const struct pl *pl) +{ + struct pl state, expires; + int err; + + if (!ss || !pl) + return EINVAL; + + err = re_regex(pl->p, pl->l, "[a-z]+[ \t\r\n]*[^]*", + &state, NULL, &ss->params); + if (err) + return EBADMSG; + + // todo: check case-sensitiveness + if (!pl_strcasecmp(&state, "active")) + ss->state = SIPEVENT_ACTIVE; + else if (!pl_strcasecmp(&state, "terminated")) + ss->state = SIPEVENT_TERMINATED; + else + ss->state = -1; + + if (!sip_param_decode(&ss->params, "expires", &expires)) + ss->expires = pl_u32(&expires); + else + ss->expires = 0; + + return 0; +} + + +const char *sipevent_substate_name(enum sipevent_subst state) +{ + switch (state) { + + case SIPEVENT_ACTIVE: return "active"; + case SIPEVENT_TERMINATED: return "terminated"; + default: return "???"; + } +} From 91f234c2dfce6f6d7a8dc472eac64dd1a403a512 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Wed, 30 Nov 2011 08:10:59 +0000 Subject: [PATCH 04/46] renamed sub.c -> subscribe.c --- src/sipevent/mod.mk | 2 +- src/sipevent/{sub.c => subscribe.c} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/sipevent/{sub.c => subscribe.c} (99%) diff --git a/src/sipevent/mod.mk b/src/sipevent/mod.mk index cf1c0c6..ae2e417 100644 --- a/src/sipevent/mod.mk +++ b/src/sipevent/mod.mk @@ -5,5 +5,5 @@ # SRCS += sipevent/listen.c -SRCS += sipevent/sub.c +SRCS += sipevent/subscribe.c SRCS += sipevent/substate.c diff --git a/src/sipevent/sub.c b/src/sipevent/subscribe.c similarity index 99% rename from src/sipevent/sub.c rename to src/sipevent/subscribe.c index f8d7750..f62acb7 100644 --- a/src/sipevent/sub.c +++ b/src/sipevent/subscribe.c @@ -1,5 +1,5 @@ /** - * @file sub.c SIP Event Subscriber + * @file sub.c SIP Event Subscribe * * Copyright (C) 2010 Creytiv.com */ From b34b1217c011c9c40fcbd5c150c813dd7aea1d26 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Wed, 30 Nov 2011 09:09:24 +0000 Subject: [PATCH 05/46] NOTIFY and SUBSCRIBE are target refresh requests --- src/sipevent/listen.c | 2 -- src/sipevent/subscribe.c | 1 - 2 files changed, 3 deletions(-) diff --git a/src/sipevent/listen.c b/src/sipevent/listen.c index 3203672..b391e41 100644 --- a/src/sipevent/listen.c +++ b/src/sipevent/listen.c @@ -100,7 +100,6 @@ static void notify_handler(struct sipevent_sock *sock, return; } - // todo: check (void)sip_dialog_update(sub->dlg, msg); } @@ -172,7 +171,6 @@ static void subscribe_handler(struct sipevent_sock *sock, return; } - // todo: check (void)sip_dialog_update(not->dlg, msg); // ... diff --git a/src/sipevent/subscribe.c b/src/sipevent/subscribe.c index f62acb7..1536997 100644 --- a/src/sipevent/subscribe.c +++ b/src/sipevent/subscribe.c @@ -170,7 +170,6 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) sub->subscribed = true; } else { - // todo: check (void)sip_dialog_update(sub->dlg, msg); } From ec8dcbfd4752ef738152e6549a19567b122d9f2f Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Wed, 30 Nov 2011 09:23:27 +0000 Subject: [PATCH 06/46] 481 tested --- src/sipevent/subscribe.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sipevent/subscribe.c b/src/sipevent/subscribe.c index 1536997..68c98f9 100644 --- a/src/sipevent/subscribe.c +++ b/src/sipevent/subscribe.c @@ -220,7 +220,6 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) return; case 481: - // todo: test sub->subscribed = false; sub->dlg = mem_deref(sub->dlg); hash_unlink(&sub->he); From b8a5996b67e645ea35a7d84c6a1325dbb1b485b8 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Wed, 30 Nov 2011 09:46:08 +0000 Subject: [PATCH 07/46] fix header parsing --- include/re_sipevent.h | 6 ++++++ src/sipevent/listen.c | 7 ++++--- src/sipevent/mod.mk | 2 +- src/sipevent/{substate.c => msg.c} | 17 ++++++++++++++++- 4 files changed, 27 insertions(+), 5 deletions(-) rename src/sipevent/{substate.c => msg.c} (80%) diff --git a/include/re_sipevent.h b/include/re_sipevent.h index e7813cf..78de579 100644 --- a/include/re_sipevent.h +++ b/include/re_sipevent.h @@ -21,6 +21,11 @@ int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, const char *fmt, ...); +struct sipevent_event { + struct pl event; + struct pl params; +}; + enum sipevent_subst { SIPEVENT_ACTIVE = 0, SIPEVENT_TERMINATED, @@ -32,6 +37,7 @@ struct sipevent_substate { uint32_t expires; }; +int sipevent_event_decode(struct sipevent_event *se, const struct pl *pl); int sipevent_substate_decode(struct sipevent_substate *ss, const struct pl *pl); const char *sipevent_substate_name(enum sipevent_subst state); diff --git a/src/sipevent/listen.c b/src/sipevent/listen.c index b391e41..fbf8cfc 100644 --- a/src/sipevent/listen.c +++ b/src/sipevent/listen.c @@ -82,6 +82,7 @@ static void notify_handler(struct sipevent_sock *sock, struct sipevent_substate ss; struct sip *sip = sock->sip; const struct sip_hdr *hdr; + struct sipevent_event se; struct sipsub *sub; sub = sipsub_find(sock, msg, true); @@ -105,8 +106,8 @@ static void notify_handler(struct sipevent_sock *sock, hdr = sip_msg_hdr(msg, SIP_HDR_EVENT); - // todo: check case sensitiveness, header syntax and status code - if (!hdr || pl_strcmp(&hdr->val, sub->event)) { + if (!hdr || sipevent_event_decode(&se, &hdr->val) || + pl_strcasecmp(&se.event, sub->event)) { (void)sip_reply(sip, msg, 489, "Bad Event"); return; } @@ -173,7 +174,7 @@ static void subscribe_handler(struct sipevent_sock *sock, (void)sip_dialog_update(not->dlg, msg); - // ... + /* todo: implement notifier */ } diff --git a/src/sipevent/mod.mk b/src/sipevent/mod.mk index ae2e417..0dbf7a0 100644 --- a/src/sipevent/mod.mk +++ b/src/sipevent/mod.mk @@ -6,4 +6,4 @@ SRCS += sipevent/listen.c SRCS += sipevent/subscribe.c -SRCS += sipevent/substate.c +SRCS += sipevent/msg.c diff --git a/src/sipevent/substate.c b/src/sipevent/msg.c similarity index 80% rename from src/sipevent/substate.c rename to src/sipevent/msg.c index dd72bed..f49b4a1 100644 --- a/src/sipevent/substate.c +++ b/src/sipevent/msg.c @@ -13,6 +13,22 @@ #include +int sipevent_event_decode(struct sipevent_event *se, const struct pl *pl) +{ + int err; + + if (!se || !pl) + return EINVAL; + + err = re_regex(pl->p, pl->l, "[^; \t\r\n]+[ \t\r\n]*[^]*", + &se->event, NULL, &se->params); + if (err) + return EBADMSG; + + return 0; +} + + int sipevent_substate_decode(struct sipevent_substate *ss, const struct pl *pl) { struct pl state, expires; @@ -26,7 +42,6 @@ int sipevent_substate_decode(struct sipevent_substate *ss, const struct pl *pl) if (err) return EBADMSG; - // todo: check case-sensitiveness if (!pl_strcasecmp(&state, "active")) ss->state = SIPEVENT_ACTIVE; else if (!pl_strcasecmp(&state, "terminated")) From aa42bc518f9d1595ef7bb8def2acf96c7f2a5f34 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Wed, 30 Nov 2011 10:23:44 +0000 Subject: [PATCH 08/46] mod.mk: sort files alphabetically --- src/sipevent/mod.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sipevent/mod.mk b/src/sipevent/mod.mk index 0dbf7a0..c99d43c 100644 --- a/src/sipevent/mod.mk +++ b/src/sipevent/mod.mk @@ -5,5 +5,5 @@ # SRCS += sipevent/listen.c -SRCS += sipevent/subscribe.c SRCS += sipevent/msg.c +SRCS += sipevent/subscribe.c From 12f862d036898d0b94b5ba5b971046cefeb5a673 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Wed, 30 Nov 2011 13:59:29 +0000 Subject: [PATCH 09/46] added sipevent_refer() --- include/re_sipevent.h | 13 ++- src/sipevent/listen.c | 17 ++-- src/sipevent/sipevent.h | 2 + src/sipevent/subscribe.c | 174 ++++++++++++++++++++++++++++----------- src/sipsess/listen.c | 4 + 5 files changed, 155 insertions(+), 55 deletions(-) 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; } From 573e01d5d4b6e50e0bf41752b572ebc324fee4ab Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Wed, 30 Nov 2011 14:05:58 +0000 Subject: [PATCH 10/46] fix typo --- src/sipevent/listen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sipevent/listen.c b/src/sipevent/listen.c index c6e922c..e687e71 100644 --- a/src/sipevent/listen.c +++ b/src/sipevent/listen.c @@ -92,7 +92,7 @@ static void notify_handler(struct sipevent_sock *sock, sub = sipsub_find(sock, msg, false); if (!sub) { (void)sip_reply(sip, msg, - 481, "Subsctiption Does Not Exist"); + 481, "Subscription Does Not Exist"); return; } From bd45000b462382afc372d6214266883981259da9 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Wed, 30 Nov 2011 14:34:59 +0000 Subject: [PATCH 11/46] terminate dialog if: 408, 481 or timeout --- src/sipevent/subscribe.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/sipevent/subscribe.c b/src/sipevent/subscribe.c index 2ae067e..cf0dc92 100644 --- a/src/sipevent/subscribe.c +++ b/src/sipevent/subscribe.c @@ -148,6 +148,13 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) wait = failwait(sub->failc + 1); if (err || sip_request_loops(&sub->ls, msg->scode)) { + + if (err == ETIMEDOUT) { + sub->subscribed = false; + sub->dlg = mem_deref(sub->dlg); + hash_unlink(&sub->he); + } + sub->failc++; goto out; } @@ -207,6 +214,13 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) sip_auth_reset(sub->auth); break; + case 408: + case 481: + sub->subscribed = false; + sub->dlg = mem_deref(sub->dlg); + hash_unlink(&sub->he); + break; + case 423: minexp = sip_msg_hdr(msg, SIP_HDR_MIN_EXPIRES); if (!minexp || !pl_u32(&minexp->val) || !sub->expires) @@ -219,12 +233,6 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) break; return; - - case 481: - sub->subscribed = false; - sub->dlg = mem_deref(sub->dlg); - hash_unlink(&sub->he); - break; } ++sub->failc; From 7d249098077eba92bbb98ff95208e9b3709dc3ca Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Thu, 1 Dec 2011 09:05:06 +0000 Subject: [PATCH 12/46] subscriber: schedule refresh also when request is in progress --- include/re_sip.h | 1 + src/sip/dialog.c | 9 ++++++--- src/sipevent/listen.c | 4 +++- src/sipevent/sipevent.h | 2 +- src/sipevent/subscribe.c | 36 +++++++++++++++++++++--------------- 5 files changed, 32 insertions(+), 20 deletions(-) diff --git a/include/re_sip.h b/include/re_sip.h index 4a45e1c..70f349b 100644 --- a/include/re_sip.h +++ b/include/re_sip.h @@ -304,6 +304,7 @@ int sip_dialog_create(struct sip_dialog *dlg, const struct sip_msg *msg); int sip_dialog_update(struct sip_dialog *dlg, const struct sip_msg *msg); bool sip_dialog_rseq_valid(struct sip_dialog *dlg, const struct sip_msg *msg); const char *sip_dialog_callid(const struct sip_dialog *dlg); +bool sip_dialog_established(const struct sip_dialog *dlg); bool sip_dialog_cmp(const struct sip_dialog *dlg, const struct sip_msg *msg); bool sip_dialog_cmp_half(const struct sip_dialog *dlg, const struct sip_msg *msg); diff --git a/src/sip/dialog.c b/src/sip/dialog.c index a9b11bf..4282aef 100644 --- a/src/sip/dialog.c +++ b/src/sip/dialog.c @@ -412,6 +412,12 @@ const char *sip_dialog_callid(const struct sip_dialog *dlg) } +bool sip_dialog_established(const struct sip_dialog *dlg) +{ + return dlg && dlg->rtag; +} + + bool sip_dialog_cmp(const struct sip_dialog *dlg, const struct sip_msg *msg) { if (!dlg || !msg) @@ -442,8 +448,5 @@ bool sip_dialog_cmp_half(const struct sip_dialog *dlg, if (pl_strcmp(msg->req ? &msg->to.tag : &msg->from.tag, dlg->ltag)) return false; - if (dlg->rtag) - return false; - return true; } diff --git a/src/sipevent/listen.c b/src/sipevent/listen.c index e687e71..90e24e7 100644 --- a/src/sipevent/listen.c +++ b/src/sipevent/listen.c @@ -128,7 +128,9 @@ static void notify_handler(struct sipevent_sock *sock, switch (ss.state) { case SIPEVENT_ACTIVE: - if (sub->req || sub->terminated) + sub->subscribed = true; + + if (sub->terminated) break; sipevent_resubscribe(sub, ss.expires * 900); diff --git a/src/sipevent/sipevent.h b/src/sipevent/sipevent.h index 5117618..f9e3b3b 100644 --- a/src/sipevent/sipevent.h +++ b/src/sipevent/sipevent.h @@ -51,4 +51,4 @@ struct sipsub { }; -void sipevent_resubscribe(struct sipsub *sub, uint32_t wait); +void sipevent_resubscribe(struct sipsub *sub, uint64_t wait); diff --git a/src/sipevent/subscribe.c b/src/sipevent/subscribe.c index cf0dc92..3cd769b 100644 --- a/src/sipevent/subscribe.c +++ b/src/sipevent/subscribe.c @@ -91,7 +91,7 @@ static void destructor(void *arg) } -static uint32_t failwait(uint32_t failc) +static uint64_t failwait(uint32_t failc) { return min(1800, (30 * (1<req) + return; + if (!sub->dlg) { err = sip_dialog_alloc(&sub->dlg, sub->uri, sub->uri, @@ -128,12 +131,12 @@ static void tmr_handler(void *arg) } -void sipevent_resubscribe(struct sipsub *sub, uint32_t wait) +void sipevent_resubscribe(struct sipsub *sub, uint64_t wait) { if (!wait) wait = failwait(++sub->failc); - re_printf("will re-subscribe in %u ms\n", wait); + re_printf("will re-subscribe in %llu ms\n", wait); tmr_start(&sub->tmr, wait, tmr_handler, sub); } @@ -143,7 +146,7 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) { const struct sip_hdr *minexp; struct sipsub *sub = arg; - uint32_t wait; + uint64_t wait; wait = failwait(sub->failc + 1); @@ -164,7 +167,7 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) } else if (msg->scode < 300) { - if (!sub->subscribed) { + if (!sip_dialog_established(sub->dlg)) { err = sip_dialog_create(sub->dlg, msg); if (err) { @@ -173,22 +176,21 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) sub->failc++; goto out; } - - sub->subscribed = true; } else { (void)sip_dialog_update(sub->dlg, msg); } + if (sub->refer && tmr_isrunning(&sub->tmr)) + wait = tmr_get_expire(&sub->tmr); + else if (pl_isset(&msg->expires)) + wait = pl_u32(&msg->expires) * 900; + else + wait = sub->expires * 900; + + sub->subscribed = true; sub->refer = false; sub->failc = 0; - - if (pl_isset(&msg->expires)) - wait = pl_u32(&msg->expires); - else - wait = DEFAULT_EXPIRES; - - wait *= 900; } else { if (sub->terminated && !sub->subscribed) @@ -248,9 +250,13 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) } else { if (sub->retry || sub->subscribed) { - re_printf("will re-subscribe in %u ms...\n", wait); + re_printf("will re-subscribe in %llu ms...\n", wait); tmr_start(&sub->tmr, wait, tmr_handler, sub); } + else { + tmr_cancel(&sub->tmr); + } + sub->resph(err, msg, sub->arg); } } From a8e32ddacead8a253c83a9b04a5c6b2c6f560cf1 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Fri, 2 Dec 2011 14:09:27 +0000 Subject: [PATCH 13/46] added close handler --- include/re_sipevent.h | 25 +++- src/sipevent/listen.c | 101 +++++++-------- src/sipevent/msg.c | 16 ++- src/sipevent/sipevent.h | 20 +-- src/sipevent/subscribe.c | 258 ++++++++++++++++----------------------- 5 files changed, 196 insertions(+), 224 deletions(-) diff --git a/include/re_sipevent.h b/include/re_sipevent.h index c7c0517..9d0a097 100644 --- a/include/re_sipevent.h +++ b/include/re_sipevent.h @@ -4,6 +4,9 @@ * Copyright (C) 2010 Creytiv.com */ + +/* Listener Socket */ + struct sipevent_sock; int sipevent_listen(struct sipevent_sock **sockp, struct sip *sip, @@ -11,25 +14,33 @@ int sipevent_listen(struct sipevent_sock **sockp, struct sip *sip, sip_msg_h *subh, void *arg); +/* Subscriber */ + +typedef void (sipevent_notify_h)(struct sip *sip, const struct sip_msg *msg, + void *arg); +typedef void (sipevent_close_h)(int err, const struct sip_msg *msg, void *arg); + struct sipsub; int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, - bool retry, const char *uri, const char *from_name, + 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, ...); + sipevent_notify_h *notifyh, sipevent_close_h *closeh, + 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, ...); + sipevent_notify_h *notifyh, sipevent_close_h *closeh, + void *arg, const char *fmt, ...); +/* Message Components */ + struct sipevent_event { struct pl event; struct pl params; @@ -37,13 +48,15 @@ struct sipevent_event { enum sipevent_subst { SIPEVENT_ACTIVE = 0, + SIPEVENT_PENDING, SIPEVENT_TERMINATED, }; struct sipevent_substate { enum sipevent_subst state; struct pl params; - uint32_t expires; + struct pl expires; + struct pl reason; }; int sipevent_event_decode(struct sipevent_event *se, const struct pl *pl); diff --git a/src/sipevent/listen.c b/src/sipevent/listen.c index 90e24e7..811cf88 100644 --- a/src/sipevent/listen.c +++ b/src/sipevent/listen.c @@ -79,18 +79,33 @@ static struct sipsub *sipsub_find(struct sipevent_sock *sock, static void notify_handler(struct sipevent_sock *sock, const struct sip_msg *msg) { - struct sipevent_substate ss; + struct sipevent_substate state; + struct sipevent_event event; struct sip *sip = sock->sip; const struct sip_hdr *hdr; - struct sipevent_event se; struct sipsub *sub; + uint32_t nrefs; bool indialog; + hdr = sip_msg_hdr(msg, SIP_HDR_EVENT); + if (!hdr || sipevent_event_decode(&event, &hdr->val)) { + (void)sip_reply(sip, msg, 400, "Bad Event Header"); + return; + } + + hdr = sip_msg_hdr(msg, SIP_HDR_SUBSCRIPTION_STATE); + if (!hdr || sipevent_substate_decode(&state, &hdr->val)) { + (void)sip_reply(sip, msg, 400,"Bad Subscription-State Header"); + return; + } + sub = sipsub_find(sock, msg, true); if (!sub) { + /* hack: while we are waiting for proper fork handling */ + sub = sipsub_find(sock, msg, false); - if (!sub) { + if (!sub || sip_dialog_established(sub->dlg)) { (void)sip_reply(sip, msg, 481, "Subscription Does Not Exist"); return; @@ -100,7 +115,7 @@ static void notify_handler(struct sipevent_sock *sock, } else { if (!sip_dialog_rseq_valid(sub->dlg, msg)) { - (void)sip_reply(sip, msg, 500,"Server Internal Error"); + (void)sip_reply(sip, msg, 500, "Bad Sequence"); return; } @@ -109,58 +124,46 @@ static void notify_handler(struct sipevent_sock *sock, indialog = true; } - hdr = sip_msg_hdr(msg, SIP_HDR_EVENT); - - if (!hdr || sipevent_event_decode(&se, &hdr->val) || - pl_strcasecmp(&se.event, sub->event)) { + if (pl_strcasecmp(&event.event, sub->event)) { (void)sip_reply(sip, msg, 489, "Bad Event"); return; } - hdr = sip_msg_hdr(msg, SIP_HDR_SUBSCRIPTION_STATE); - - if (indialog && hdr && !sipevent_substate_decode(&ss, &hdr->val)) { - - re_printf("dialog substate: %s (%u secs) [%r]\n", - sipevent_substate_name(ss.state), - ss.expires, &ss.params); - - switch (ss.state) { - - case SIPEVENT_ACTIVE: - sub->subscribed = true; - - if (sub->terminated) - break; - - sipevent_resubscribe(sub, ss.expires * 900); - break; - - case SIPEVENT_TERMINATED: - sub->req = mem_deref(sub->req); /* forget request */ - - if (sub->terminated) { - mem_deref(sub); - goto reply; - } - - sub->subscribed = false; - sub->dlg = mem_deref(sub->dlg); - hash_unlink(&sub->he); - - if (sub->retry) - sipevent_resubscribe(sub, 0); - else - tmr_cancel(&sub->tmr); - break; - } + /* hack: while we are waiting for proper fork handling */ + if (!indialog) { + sub->notifyh(sip, msg, sub->arg); + return; } - if (sub->noth(msg, sub->arg)) + re_printf("notify: %s (%r)\n", sipevent_substate_name(state.state), + &state.params); + + switch (state.state) { + + case SIPEVENT_ACTIVE: + case SIPEVENT_PENDING: + sub->subscribed = true; + + if (!sub->terminated && pl_isset(&state.expires)) + sipsub_reschedule(sub, pl_u32(&state.expires) * 900); + break; + + case SIPEVENT_TERMINATED: + sub->subscribed = false; + break; + } + + mem_ref(sub); + sub->notifyh(sip, msg, sub->arg); + nrefs = mem_nrefs(sub); + mem_deref(sub); + + /* check if subscription was deref'd from notify handler */ + if (nrefs == 1) return; - reply: - (void)sip_treply(NULL, sip, msg, 200, "OK"); + if (!sub->terminated && state.state == SIPEVENT_TERMINATED) + sipsub_terminate(sub, 0, msg); } @@ -177,7 +180,7 @@ static void subscribe_handler(struct sipevent_sock *sock, } if (!sip_dialog_rseq_valid(not->dlg, msg)) { - (void)sip_reply(sip, msg, 500, "Server Internal Error"); + (void)sip_reply(sip, msg, 500, "Bad Sequence"); return; } diff --git a/src/sipevent/msg.c b/src/sipevent/msg.c index f49b4a1..38f4124 100644 --- a/src/sipevent/msg.c +++ b/src/sipevent/msg.c @@ -31,7 +31,7 @@ int sipevent_event_decode(struct sipevent_event *se, const struct pl *pl) int sipevent_substate_decode(struct sipevent_substate *ss, const struct pl *pl) { - struct pl state, expires; + struct pl state, param; int err; if (!ss || !pl) @@ -44,15 +44,22 @@ int sipevent_substate_decode(struct sipevent_substate *ss, const struct pl *pl) if (!pl_strcasecmp(&state, "active")) ss->state = SIPEVENT_ACTIVE; + else if (!pl_strcasecmp(&state, "pending")) + ss->state = SIPEVENT_PENDING; else if (!pl_strcasecmp(&state, "terminated")) ss->state = SIPEVENT_TERMINATED; else ss->state = -1; - if (!sip_param_decode(&ss->params, "expires", &expires)) - ss->expires = pl_u32(&expires); + if (!sip_param_decode(&ss->params, "expires", ¶m)) + ss->expires = param; else - ss->expires = 0; + ss->expires = pl_null; + + if (!sip_param_decode(&ss->params, "reason", ¶m)) + ss->reason = param; + else + ss->reason = pl_null; return 0; } @@ -63,6 +70,7 @@ const char *sipevent_substate_name(enum sipevent_subst state) switch (state) { case SIPEVENT_ACTIVE: return "active"; + case SIPEVENT_PENDING: return "pending"; case SIPEVENT_TERMINATED: return "terminated"; default: return "???"; } diff --git a/src/sipevent/sipevent.h b/src/sipevent/sipevent.h index f9e3b3b..87ed81a 100644 --- a/src/sipevent/sipevent.h +++ b/src/sipevent/sipevent.h @@ -5,6 +5,8 @@ */ +/* Listener Socket */ + struct sipevent_sock { struct sip_lsnr *lsnr; struct hash *ht_not; @@ -15,6 +17,8 @@ struct sipevent_sock { }; +/* Notifier */ + struct sipnot { struct le he; struct sip_dialog *dlg; @@ -22,6 +26,8 @@ struct sipnot { }; +/* Subscriber */ + struct sipsub { struct le he; struct sip_loopstate ls; @@ -31,24 +37,18 @@ struct sipsub { struct sip_dialog *dlg; struct sip_auth *auth; struct sip *sip; - char *uri; - char *from_name; - char *from_uri; - char **routev; char *event; char *cuser; char *hdrs; - sip_resp_h *resph; - sip_msg_h *noth; + sipevent_notify_h *notifyh; + sipevent_close_h *closeh; void *arg; uint32_t expires; uint32_t failc; - uint32_t routec; bool subscribed; bool terminated; bool refer; - bool retry; }; - -void sipevent_resubscribe(struct sipsub *sub, uint64_t wait); +void sipsub_reschedule(struct sipsub *sub, uint64_t wait); +void sipsub_terminate(struct sipsub *sub, int err, const struct sip_msg *msg); diff --git a/src/sipevent/subscribe.c b/src/sipevent/subscribe.c index 3cd769b..8c6e3df 100644 --- a/src/sipevent/subscribe.c +++ b/src/sipevent/subscribe.c @@ -3,6 +3,7 @@ * * Copyright (C) 2010 Creytiv.com */ +#include // todo: remove #include #include #include @@ -20,14 +21,25 @@ enum { DEFAULT_EXPIRES = 3600, + RESUB_FAIL_WAIT = 60000, + RESUB_FAILC_MAX = 7, }; static int request(struct sipsub *sub, bool reset_ls); -static void internal_response_handler(int err, const struct sip_msg *msg, - void *arg) +static void internal_notify_handler(struct sip *sip, const struct sip_msg *msg, + void *arg) +{ + (void)arg; + + (void)sip_treply(NULL, sip, msg, 200, "OK"); +} + + +static void internal_close_handler(int err, const struct sip_msg *msg, + void *arg) { (void)err; (void)msg; @@ -35,10 +47,21 @@ static void internal_response_handler(int err, const struct sip_msg *msg, } -static bool internal_notify_handler(const struct sip_msg *msg, void *arg) +static bool terminate(struct sipsub *sub) { - (void)msg; - (void)arg; + sub->terminated = true; + sub->notifyh = internal_notify_handler; + sub->closeh = internal_close_handler; + + if (sub->req) { + mem_ref(sub); + return true; + } + + if (sub->subscribed && !request(sub, true)) { + mem_ref(sub); + return true; + } return false; } @@ -52,37 +75,14 @@ static void destructor(void *arg) if (!sub->terminated) { - sub->resph = internal_response_handler; - sub->noth = internal_notify_handler; - sub->terminated = true; - - if (sub->req) { - mem_ref(sub); + if (terminate(sub)) return; - } - - if (sub->subscribed && !request(sub, true)) { - mem_ref(sub); - return; - } - } - - if (sub->routev) { - - uint32_t i; - - for (i=0; iroutec; i++) - mem_deref(sub->routev[i]); - - mem_deref(sub->routev); } hash_unlink(&sub->he); + mem_deref(sub->req); mem_deref(sub->dlg); mem_deref(sub->auth); - mem_deref(sub->uri); - mem_deref(sub->from_name); - mem_deref(sub->from_uri); mem_deref(sub->event); mem_deref(sub->cuser); mem_deref(sub->hdrs); @@ -91,12 +91,6 @@ static void destructor(void *arg) } -static uint64_t failwait(uint32_t failc) -{ - return min(1800, (30 * (1<req) return; - if (!sub->dlg) { - - err = sip_dialog_alloc(&sub->dlg, sub->uri, sub->uri, - sub->from_name, sub->from_uri, - (const char **)sub->routev, - sub->routec); - if (err) - goto out; - - hash_append(sub->sock->ht_sub, - hash_joaat_str(sip_dialog_callid(sub->dlg)), - &sub->he, sub); - } - err = request(sub, true); - if (err) - goto out; - - out: if (err) { - tmr_start(&sub->tmr, failwait(++sub->failc), tmr_handler, sub); - sub->resph(err, NULL, sub->arg); + if (++sub->failc < RESUB_FAILC_MAX) { + sipsub_reschedule(sub, RESUB_FAIL_WAIT); + } + else { + sipsub_terminate(sub, err, NULL); + } } } -void sipevent_resubscribe(struct sipsub *sub, uint64_t wait) +void sipsub_reschedule(struct sipsub *sub, uint64_t wait) { - if (!wait) - wait = failwait(++sub->failc); - - re_printf("will re-subscribe in %llu ms\n", wait); + re_printf("will re-subscribe in %llu secs\n", wait/1000); tmr_start(&sub->tmr, wait, tmr_handler, sub); } +void sipsub_terminate(struct sipsub *sub, int err, const struct sip_msg *msg) +{ + sipevent_close_h *closeh; + void *arg; + + closeh = sub->closeh; + arg = sub->arg; + + tmr_cancel(&sub->tmr); + (void)terminate(sub); + + closeh(err, msg, arg); +} + + static void response_handler(int err, const struct sip_msg *msg, void *arg) { const struct sip_hdr *minexp; struct sipsub *sub = arg; - uint64_t wait; - wait = failwait(sub->failc + 1); + if (err) + re_printf("reply: %s\n", strerror(err)); + else + re_printf("reply: %u %r\n", msg->scode, &msg->reason); - if (err || sip_request_loops(&sub->ls, msg->scode)) { - - if (err == ETIMEDOUT) { - sub->subscribed = false; - sub->dlg = mem_deref(sub->dlg); - hash_unlink(&sub->he); - } - - sub->failc++; + if (err || sip_request_loops(&sub->ls, msg->scode)) goto out; - } if (msg->scode < 200) { return; } else if (msg->scode < 300) { + uint32_t wait; + if (!sip_dialog_established(sub->dlg)) { err = sip_dialog_create(sub->dlg, msg); if (err) { - sub->dlg = mem_deref(sub->dlg); - hash_unlink(&sub->he); - sub->failc++; + sub->subscribed = false; goto out; } } @@ -181,16 +166,26 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) (void)sip_dialog_update(sub->dlg, msg); } - if (sub->refer && tmr_isrunning(&sub->tmr)) - wait = tmr_get_expire(&sub->tmr); - else if (pl_isset(&msg->expires)) - wait = pl_u32(&msg->expires) * 900; - else - wait = sub->expires * 900; - sub->subscribed = true; - sub->refer = false; sub->failc = 0; + + if (sub->terminated) { + sub->refer = false; + goto out; + } + + if (sub->refer) { + sub->refer = false; + return; + } + + if (pl_isset(&msg->expires)) + wait = pl_u32(&msg->expires); + else + wait = sub->expires; + + sipsub_reschedule(sub, wait * 900); + return; } else { if (sub->terminated && !sub->subscribed) @@ -216,13 +211,6 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) sip_auth_reset(sub->auth); break; - case 408: - case 481: - sub->subscribed = false; - sub->dlg = mem_deref(sub->dlg); - hash_unlink(&sub->he); - break; - case 423: minexp = sip_msg_hdr(msg, SIP_HDR_MIN_EXPIRES); if (!minexp || !pl_u32(&minexp->val) || !sub->expires) @@ -235,9 +223,11 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) break; return; - } - ++sub->failc; + case 481: + sub->subscribed = false; + break; + } } out: @@ -249,15 +239,10 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) mem_deref(sub); } else { - if (sub->retry || sub->subscribed) { - re_printf("will re-subscribe in %llu ms...\n", wait); - tmr_start(&sub->tmr, wait, tmr_handler, sub); - } - else { - tmr_cancel(&sub->tmr); - } - - sub->resph(err, msg, sub->arg); + if (sub->subscribed && ++sub->failc < RESUB_FAILC_MAX) + sipsub_reschedule(sub, RESUB_FAIL_WAIT); + else + sipsub_terminate(sub, err, msg); } } @@ -308,13 +293,13 @@ static int request(struct sipsub *sub, bool reset_ls) static int sipsub_alloc(struct sipsub **subp, struct sipevent_sock *sock, - bool refer, bool retry, const char *uri, + bool refer, 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) + sipevent_notify_h *notifyh, sipevent_close_h *closeh, + void *arg, const char *fmt, va_list ap) { struct sipsub *sub; int err; @@ -339,41 +324,6 @@ static int sipsub_alloc(struct sipsub **subp, struct sipevent_sock *sock, if (err) goto out; - err = str_dup(&sub->uri, uri); - if (err) - goto out; - - err = str_dup(&sub->from_uri, from_uri); - if (err) - goto out; - - if (from_name) { - - err = str_dup(&sub->from_name, from_name); - if (err) - goto out; - } - - sub->routec = routec; - - if (routec > 0) { - - uint32_t i; - - sub->routev = mem_zalloc(sizeof(*sub->routev) * routec, NULL); - if (!sub->routev) { - err = ENOMEM; - goto out; - } - - for (i=0; iroutev[i], routev[i]); - if (err) - goto out; - } - } - err = str_dup(&sub->event, event); if (err) goto out; @@ -390,12 +340,11 @@ static int sipsub_alloc(struct sipsub **subp, struct sipevent_sock *sock, } sub->refer = refer; - sub->retry = retry; sub->sock = mem_ref(sock); sub->sip = mem_ref(sock->sip); sub->expires = expires; - sub->resph = resph ? resph : internal_response_handler; - sub->noth = noth ? noth : internal_notify_handler; + sub->notifyh = notifyh ? notifyh : internal_notify_handler; + sub->closeh = closeh ? closeh : internal_close_handler; sub->arg = arg; err = request(sub, true); @@ -417,7 +366,6 @@ static int sipsub_alloc(struct sipsub **subp, struct sipevent_sock *sock, * * @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 @@ -429,29 +377,29 @@ static int sipsub_alloc(struct sipsub **subp, struct sipevent_sock *sock, * @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 closeh Close 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 *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, ...) + sipevent_notify_h *notifyh, sipevent_close_h *closeh, + 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, + err = sipsub_alloc(subp, sock, false, uri, from_name, from_uri, event, expires, cuser, routev, routec, authh, aarg, - aref, resph, noth, arg, fmt, ap); + aref, notifyh, closeh, arg, fmt, ap); va_end(ap); return err; @@ -472,8 +420,8 @@ int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, * @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 closeh Close handler * @param arg Response handler argument * @param fmt Formatted strings with extra SIP Headers * @@ -484,16 +432,16 @@ int sipevent_refer(struct sipsub **subp, struct sipevent_sock *sock, 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, ...) + sipevent_notify_h *notifyh, sipevent_close_h *closeh, + 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, + err = sipsub_alloc(subp, sock, true, uri, from_name, from_uri, "refer", DEFAULT_EXPIRES, cuser, routev, routec, - authh, aarg, aref, resph, noth, arg, fmt, ap); + authh, aarg, aref, notifyh, closeh, arg, fmt, ap); va_end(ap); return err; From 2f8a580fc3414b869f884a68af475910031387ab Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Tue, 6 Dec 2011 13:44:37 +0000 Subject: [PATCH 14/46] sipevent: subscribe fork handling --- include/re_sip.h | 2 + include/re_sipevent.h | 24 +++++-- src/sip/dialog.c | 141 +++++++++++++++++++++++++++++++++------ src/sipevent/listen.c | 46 ++++++++----- src/sipevent/sipevent.h | 4 ++ src/sipevent/subscribe.c | 130 +++++++++++++++++++++++++++++++----- 6 files changed, 285 insertions(+), 62 deletions(-) diff --git a/include/re_sip.h b/include/re_sip.h index 70f349b..d638ea9 100644 --- a/include/re_sip.h +++ b/include/re_sip.h @@ -301,6 +301,8 @@ int sip_dialog_alloc(struct sip_dialog **dlgp, const char *routev[], uint32_t routec); int sip_dialog_accept(struct sip_dialog **dlgp, const struct sip_msg *msg); int sip_dialog_create(struct sip_dialog *dlg, const struct sip_msg *msg); +int sip_dialog_fork(struct sip_dialog **dlgp, struct sip_dialog *odlg, + const struct sip_msg *msg); int sip_dialog_update(struct sip_dialog *dlg, const struct sip_msg *msg); bool sip_dialog_rseq_valid(struct sip_dialog *dlg, const struct sip_msg *msg); const char *sip_dialog_callid(const struct sip_dialog *dlg); diff --git a/include/re_sipevent.h b/include/re_sipevent.h index 9d0a097..0b17882 100644 --- a/include/re_sipevent.h +++ b/include/re_sipevent.h @@ -16,11 +16,14 @@ int sipevent_listen(struct sipevent_sock **sockp, struct sip *sip, /* Subscriber */ +struct sipsub; + +typedef int (sipevent_fork_h)(struct sipsub **subp, struct sipsub *osub, + const struct sip_msg *msg, void *arg); typedef void (sipevent_notify_h)(struct sip *sip, const struct sip_msg *msg, void *arg); typedef void (sipevent_close_h)(int err, const struct sip_msg *msg, void *arg); -struct sipsub; int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, const char *uri, const char *from_name, @@ -28,15 +31,22 @@ int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, uint32_t expires, const char *cuser, const char *routev[], uint32_t routec, sip_auth_h *authh, void *aarg, bool aref, - sipevent_notify_h *notifyh, sipevent_close_h *closeh, - void *arg, const char *fmt, ...); + sipevent_fork_h *forkh, sipevent_notify_h *notifyh, + sipevent_close_h *closeh, 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, + const char *from_uri, const char *refer_to, + const char *cuser, const char *routev[], uint32_t routec, sip_auth_h *authh, void *aarg, bool aref, - sipevent_notify_h *notifyh, sipevent_close_h *closeh, - void *arg, const char *fmt, ...); + sipevent_fork_h *forkh, sipevent_notify_h *notifyh, + sipevent_close_h *closeh, void *arg, + const char *fmt, ...); +int sipevent_fork(struct sipsub **subp, struct sipsub *osub, + const struct sip_msg *msg, + sip_auth_h *authh, void *aarg, bool aref, + sipevent_notify_h *notifyh, sipevent_close_h *closeh, + void *arg); /* Message Components */ diff --git a/src/sip/dialog.c b/src/sip/dialog.c index 4282aef..45869a5 100644 --- a/src/sip/dialog.c +++ b/src/sip/dialog.c @@ -219,7 +219,6 @@ int sip_dialog_accept(struct sip_dialog **dlgp, const struct sip_msg *msg) err |= sip_msg_hdr_apply(msg, true, SIP_HDR_RECORD_ROUTE, record_route_handler, &renc) ? ENOMEM : 0; - dlg->cpos = dlg->mb->pos; err |= mbuf_printf(dlg->mb, "To: %r\r\n", &msg->from.val); err |= mbuf_printf(dlg->mb, "From: %r;tag=%016llx\r\n", &msg->to.val, msg->tag); @@ -251,13 +250,14 @@ int sip_dialog_accept(struct sip_dialog **dlgp, const struct sip_msg *msg) int sip_dialog_create(struct sip_dialog *dlg, const struct sip_msg *msg) { + char *uri = NULL, *rtag = NULL; const struct sip_hdr *contact; struct route_enc renc; struct sip_addr addr; struct pl pl; int err; - if (!dlg || dlg->rtag || !msg) + if (!dlg || dlg->rtag || !dlg->cpos || !msg) return EINVAL; contact = sip_msg_hdr(msg, SIP_HDR_CONTACT); @@ -268,20 +268,18 @@ int sip_dialog_create(struct sip_dialog *dlg, const struct sip_msg *msg) if (sip_addr_decode(&addr, &contact->val)) return EBADMSG; - dlg->uri = mem_deref(dlg->uri); - - err = pl_strdup(&dlg->uri, &addr.auri); - if (err) - return err; - - err = pl_strdup(&dlg->rtag, msg->req ? &msg->from.tag : &msg->to.tag); - if (err) - return err; - renc.mb = mbuf_alloc(512); if (!renc.mb) return ENOMEM; + err = pl_strdup(&uri, &addr.auri); + if (err) + goto out; + + err = pl_strdup(&rtag, msg->req ? &msg->from.tag : &msg->to.tag); + if (err) + goto out; + renc.end = 0; err |= sip_msg_hdr_apply(msg, msg->req, SIP_HDR_RECORD_ROUTE, @@ -303,6 +301,106 @@ int sip_dialog_create(struct sip_dialog *dlg, const struct sip_msg *msg) pl.p = (const char *)mbuf_buf(renc.mb) + ROUTE_OFFSET; pl.l = renc.end - ROUTE_OFFSET; err = sip_addr_decode(&addr, &pl); + if (err) + goto out; + + dlg->route = addr.uri; + } + else { + struct uri tmp; + + pl_set_str(&pl, uri); + err = uri_decode(&tmp, &pl); + if (err) + goto out; + + dlg->route = tmp; + } + + mem_deref(dlg->mb); + mem_deref(dlg->uri); + + dlg->mb = mem_ref(renc.mb); + dlg->rtag = mem_ref(rtag); + dlg->uri = mem_ref(uri); + dlg->rseq = msg->req ? msg->cseq.num : 0; + dlg->cpos = 0; + + out: + mem_deref(renc.mb); + mem_deref(rtag); + mem_deref(uri); + + return err; +} + + +int sip_dialog_fork(struct sip_dialog **dlgp, struct sip_dialog *odlg, + const struct sip_msg *msg) +{ + const struct sip_hdr *contact; + struct sip_dialog *dlg; + struct route_enc renc; + struct sip_addr addr; + struct pl pl; + int err; + + if (!dlgp || !odlg || !odlg->cpos || !msg) + return EINVAL; + + contact = sip_msg_hdr(msg, SIP_HDR_CONTACT); + + if (!contact || !msg->callid.p) + return EBADMSG; + + if (sip_addr_decode(&addr, &contact->val)) + return EBADMSG; + + dlg = mem_zalloc(sizeof(*dlg), destructor); + if (!dlg) + return ENOMEM; + + dlg->callid = mem_ref(odlg->callid); + dlg->ltag = mem_ref(odlg->ltag); + dlg->lseq = odlg->lseq; + dlg->rseq = msg->req ? msg->cseq.num : 0; + + err = pl_strdup(&dlg->uri, &addr.auri); + if (err) + goto out; + + err = pl_strdup(&dlg->rtag, msg->req ? &msg->from.tag : &msg->to.tag); + if (err) + goto out; + + dlg->mb = mbuf_alloc(512); + if (!dlg->mb) { + err = ENOMEM; + goto out; + } + + renc.mb = dlg->mb; + renc.end = 0; + + err |= sip_msg_hdr_apply(msg, msg->req, SIP_HDR_RECORD_ROUTE, + record_route_handler, &renc) ? ENOMEM : 0; + err |= mbuf_printf(dlg->mb, "To: %r\r\n", + msg->req ? &msg->from.val : &msg->to.val); + + odlg->mb->pos = odlg->cpos; + err |= mbuf_write_mem(dlg->mb, mbuf_buf(odlg->mb), + mbuf_get_left(odlg->mb)); + odlg->mb->pos = 0; + + if (err) + goto out; + + dlg->mb->pos = 0; + + if (renc.end) { + pl.p = (const char *)mbuf_buf(dlg->mb) + ROUTE_OFFSET; + pl.l = renc.end - ROUTE_OFFSET; + err = sip_addr_decode(&addr, &pl); dlg->route = addr.uri; } else { @@ -310,14 +408,11 @@ int sip_dialog_create(struct sip_dialog *dlg, const struct sip_msg *msg) err = uri_decode(&dlg->route, &pl); } - if (err) - goto out; - - mem_deref(dlg->mb); - dlg->mb = mem_ref(renc.mb); - out: - mem_deref(renc.mb); + if (err) + mem_deref(dlg); + else + *dlgp = dlg; return err; } @@ -327,7 +422,6 @@ int sip_dialog_update(struct sip_dialog *dlg, const struct sip_msg *msg) { const struct sip_hdr *contact; struct sip_addr addr; - struct pl pl; char *uri; int err; @@ -347,10 +441,15 @@ int sip_dialog_update(struct sip_dialog *dlg, const struct sip_msg *msg) if (dlg->route.scheme.p == dlg->uri) { + struct uri tmp; + struct pl pl; + pl_set_str(&pl, uri); - err = uri_decode(&dlg->route, &pl); + err = uri_decode(&tmp, &pl); if (err) goto out; + + dlg->route = tmp; } mem_deref(dlg->uri); diff --git a/src/sipevent/listen.c b/src/sipevent/listen.c index 811cf88..b2fa906 100644 --- a/src/sipevent/listen.c +++ b/src/sipevent/listen.c @@ -53,7 +53,8 @@ static bool sub_cmp_half_handler(struct le *le, void *arg) const struct sip_msg *msg = arg; struct sipsub *sub = le->data; - return sip_dialog_cmp_half(sub->dlg, msg); + return sip_dialog_cmp_half(sub->dlg, msg) && + !sip_dialog_established(sub->dlg); } @@ -66,8 +67,8 @@ static struct sipnot *sipnot_find(struct sipevent_sock *sock, } -static struct sipsub *sipsub_find(struct sipevent_sock *sock, - const struct sip_msg *msg, bool full) +struct sipsub *sipsub_find(struct sipevent_sock *sock, + const struct sip_msg *msg, bool full) { return list_ledata(hash_lookup(sock->ht_sub, hash_joaat_pl(&msg->callid), full ? @@ -85,7 +86,7 @@ static void notify_handler(struct sipevent_sock *sock, const struct sip_hdr *hdr; struct sipsub *sub; uint32_t nrefs; - bool indialog; + int err; hdr = sip_msg_hdr(msg, SIP_HDR_EVENT); if (!hdr || sipevent_event_decode(&event, &hdr->val)) { @@ -101,17 +102,36 @@ static void notify_handler(struct sipevent_sock *sock, sub = sipsub_find(sock, msg, true); if (!sub) { - - /* hack: while we are waiting for proper fork handling */ - sub = sipsub_find(sock, msg, false); - if (!sub || sip_dialog_established(sub->dlg)) { + if (!sub) { (void)sip_reply(sip, msg, 481, "Subscription Does Not Exist"); return; } - indialog = false; + if (sub->forkh) { + + struct sipsub *fsub; + + err = sub->forkh(&fsub, sub, msg, sub->arg); + if (err) { + (void)sip_reply(sip, msg, 500, strerror(err)); + return; + } + + re_printf("*** new subscription forked from NOTIFY\n"); + + sub = fsub; + } + else { + err = sip_dialog_create(sub->dlg, msg); + if (err) { + (void)sip_reply(sip, msg, 500, strerror(err)); + return; + } + + re_printf("*** dialog established from NOTIFY\n"); + } } else { if (!sip_dialog_rseq_valid(sub->dlg, msg)) { @@ -120,8 +140,6 @@ static void notify_handler(struct sipevent_sock *sock, } (void)sip_dialog_update(sub->dlg, msg); - - indialog = true; } if (pl_strcasecmp(&event.event, sub->event)) { @@ -129,12 +147,6 @@ static void notify_handler(struct sipevent_sock *sock, return; } - /* hack: while we are waiting for proper fork handling */ - if (!indialog) { - sub->notifyh(sip, msg, sub->arg); - return; - } - re_printf("notify: %s (%r)\n", sipevent_substate_name(state.state), &state.params); diff --git a/src/sipevent/sipevent.h b/src/sipevent/sipevent.h index 87ed81a..9ac1350 100644 --- a/src/sipevent/sipevent.h +++ b/src/sipevent/sipevent.h @@ -38,8 +38,10 @@ struct sipsub { struct sip_auth *auth; struct sip *sip; char *event; + char *refer_to; char *cuser; char *hdrs; + sipevent_fork_h *forkh; sipevent_notify_h *notifyh; sipevent_close_h *closeh; void *arg; @@ -50,5 +52,7 @@ struct sipsub { bool refer; }; +struct sipsub *sipsub_find(struct sipevent_sock *sock, + const struct sip_msg *msg, bool full); void sipsub_reschedule(struct sipsub *sub, uint64_t wait); void sipsub_terminate(struct sipsub *sub, int err, const struct sip_msg *msg); diff --git a/src/sipevent/subscribe.c b/src/sipevent/subscribe.c index 8c6e3df..81e74c8 100644 --- a/src/sipevent/subscribe.c +++ b/src/sipevent/subscribe.c @@ -50,6 +50,7 @@ static void internal_close_handler(int err, const struct sip_msg *msg, static bool terminate(struct sipsub *sub) { sub->terminated = true; + sub->forkh = NULL; sub->notifyh = internal_notify_handler; sub->closeh = internal_close_handler; @@ -84,6 +85,7 @@ static void destructor(void *arg) mem_deref(sub->dlg); mem_deref(sub->auth); mem_deref(sub->event); + mem_deref(sub->refer_to); mem_deref(sub->cuser); mem_deref(sub->hdrs); mem_deref(sub->sock); @@ -154,25 +156,49 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) uint32_t wait; - if (!sip_dialog_established(sub->dlg)) { + if (sub->forkh) { + + struct sipsub *fsub; + + fsub = sipsub_find(sub->sock, msg, true); + if (!fsub) { + + err = sub->forkh(&fsub, sub, msg, sub->arg); + if (err) + return; + + re_printf("*** new subscription forked\n"); + } + else { + (void)sip_dialog_update(fsub->dlg, msg); + } + + sub = fsub; + } + else if (!sip_dialog_established(sub->dlg)) { err = sip_dialog_create(sub->dlg, msg); if (err) { sub->subscribed = false; goto out; } + + re_printf("*** dialog established\n"); } else { + /* Ignore 2xx responses for other dialogs + * if forking is disabled */ + if (!sip_dialog_cmp(sub->dlg, msg)) + return; + (void)sip_dialog_update(sub->dlg, msg); } sub->subscribed = true; sub->failc = 0; - if (sub->terminated) { - sub->refer = false; + if (sub->terminated) goto out; - } if (sub->refer) { sub->refer = false; @@ -231,6 +257,8 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) } out: + sub->refer = false; + if (!sub->expires) { mem_deref(sub); } @@ -271,9 +299,11 @@ static int request(struct sipsub *sub, bool reset_ls) return sip_drequestf(&sub->req, sub->sip, true, "REFER", sub->dlg, 0, sub->auth, send_handler, response_handler, sub, + "Refer-To: %s\r\n" "%s" "Content-Length: 0\r\n" "\r\n", + sub->refer_to, sub->hdrs); } else { @@ -295,11 +325,13 @@ static int request(struct sipsub *sub, bool reset_ls) static int sipsub_alloc(struct sipsub **subp, struct sipevent_sock *sock, bool refer, const char *uri, const char *from_name, const char *from_uri, - const char *event, uint32_t expires, const char *cuser, + const char *event, uint32_t expires, + const char *refer_to, const char *cuser, const char *routev[], uint32_t routec, sip_auth_h *authh, void *aarg, bool aref, - sipevent_notify_h *notifyh, sipevent_close_h *closeh, - void *arg, const char *fmt, va_list ap) + sipevent_fork_h *forkh, sipevent_notify_h *notifyh, + sipevent_close_h *closeh, void *arg, + const char *fmt, va_list ap) { struct sipsub *sub; int err; @@ -307,6 +339,9 @@ static int sipsub_alloc(struct sipsub **subp, struct sipevent_sock *sock, if (!subp || !sock || !uri || !from_uri || !event || !expires ||!cuser) return EINVAL; + if (refer && !refer_to) + return EINVAL; + sub = mem_zalloc(sizeof(*sub), destructor); if (!sub) return ENOMEM; @@ -328,6 +363,12 @@ static int sipsub_alloc(struct sipsub **subp, struct sipevent_sock *sock, if (err) goto out; + if (refer_to) { + err = str_dup(&sub->refer_to, refer_to); + if (err) + goto out; + } + err = str_dup(&sub->cuser, cuser); if (err) goto out; @@ -343,6 +384,7 @@ static int sipsub_alloc(struct sipsub **subp, struct sipevent_sock *sock, sub->sock = mem_ref(sock); sub->sip = mem_ref(sock->sip); sub->expires = expires; + sub->forkh = forkh; sub->notifyh = notifyh ? notifyh : internal_notify_handler; sub->closeh = closeh ? closeh : internal_close_handler; sub->arg = arg; @@ -390,16 +432,18 @@ int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, uint32_t expires, const char *cuser, const char *routev[], uint32_t routec, sip_auth_h *authh, void *aarg, bool aref, - sipevent_notify_h *notifyh, sipevent_close_h *closeh, - void *arg, const char *fmt, ...) + sipevent_fork_h *forkh, sipevent_notify_h *notifyh, + sipevent_close_h *closeh, void *arg, + const char *fmt, ...) { va_list ap; int err; va_start(ap, fmt); err = sipsub_alloc(subp, sock, false, uri, from_name, from_uri, - event, expires, cuser, routev, routec, authh, aarg, - aref, notifyh, closeh, arg, fmt, ap); + event, expires, NULL, cuser, + routev, routec, authh, aarg, aref, forkh, notifyh, + closeh, arg, fmt, ap); va_end(ap); return err; @@ -429,20 +473,72 @@ int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, */ 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, + const char *from_uri, const char *refer_to, + const char *cuser, const char *routev[], uint32_t routec, sip_auth_h *authh, void *aarg, bool aref, - sipevent_notify_h *notifyh, sipevent_close_h *closeh, - void *arg, const char *fmt, ...) + sipevent_fork_h *forkh, sipevent_notify_h *notifyh, + sipevent_close_h *closeh, void *arg, + const char *fmt, ...) { va_list ap; int err; va_start(ap, fmt); err = sipsub_alloc(subp, sock, true, uri, from_name, from_uri, - "refer", DEFAULT_EXPIRES, cuser, routev, routec, - authh, aarg, aref, notifyh, closeh, arg, fmt, ap); + "refer", DEFAULT_EXPIRES, refer_to, cuser, + routev, routec, authh, aarg, aref, forkh, notifyh, + closeh, arg, fmt, ap); va_end(ap); return err; } + + +int sipevent_fork(struct sipsub **subp, struct sipsub *osub, + const struct sip_msg *msg, + sip_auth_h *authh, void *aarg, bool aref, + sipevent_notify_h *notifyh, sipevent_close_h *closeh, + void *arg) +{ + struct sipsub *sub; + int err; + + if (!subp || !osub || !msg) + return EINVAL; + + sub = mem_zalloc(sizeof(*sub), destructor); + if (!sub) + return ENOMEM; + + err = sip_dialog_fork(&sub->dlg, osub->dlg, msg); + if (err) + goto out; + + hash_append(osub->sock->ht_sub, + hash_joaat_str(sip_dialog_callid(sub->dlg)), + &sub->he, sub); + + err = sip_auth_alloc(&sub->auth, authh, aarg, aref); + if (err) + goto out; + + sub->event = mem_ref(osub->event); + sub->cuser = mem_ref(osub->cuser); + sub->hdrs = mem_ref(osub->hdrs); + sub->refer = osub->refer; + sub->sock = mem_ref(osub->sock); + sub->sip = mem_ref(osub->sip); + sub->expires = osub->expires; + sub->forkh = NULL; + sub->notifyh = notifyh ? notifyh : internal_notify_handler; + sub->closeh = closeh ? closeh : internal_close_handler; + sub->arg = arg; + + out: + if (err) + mem_deref(sub); + else + *subp = sub; + + return err; +} From 45b0b0132fb1659dd65d47e99f820f49782c4c9f Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Thu, 8 Dec 2011 11:41:49 +0000 Subject: [PATCH 15/46] event id parameter handling --- include/re_sipevent.h | 3 ++- src/sipevent/listen.c | 56 ++++++++++++++++++++++++++++++---------- src/sipevent/msg.c | 6 +++++ src/sipevent/sipevent.h | 4 ++- src/sipevent/subscribe.c | 32 ++++++++++++++++++----- 5 files changed, 78 insertions(+), 23 deletions(-) diff --git a/include/re_sipevent.h b/include/re_sipevent.h index 0b17882..494bc8c 100644 --- a/include/re_sipevent.h +++ b/include/re_sipevent.h @@ -27,7 +27,7 @@ typedef void (sipevent_close_h)(int err, const struct sip_msg *msg, void *arg); int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, const char *uri, const char *from_name, - const char *from_uri, const char *event, + const char *from_uri, const char *event, const char *id, uint32_t expires, const char *cuser, const char *routev[], uint32_t routec, sip_auth_h *authh, void *aarg, bool aref, @@ -54,6 +54,7 @@ int sipevent_fork(struct sipsub **subp, struct sipsub *osub, struct sipevent_event { struct pl event; struct pl params; + struct pl id; }; enum sipevent_subst { diff --git a/src/sipevent/listen.c b/src/sipevent/listen.c index b2fa906..02254a5 100644 --- a/src/sipevent/listen.c +++ b/src/sipevent/listen.c @@ -18,6 +18,12 @@ #include "sipevent.h" +struct subcmp { + const struct sipevent_event *evt; + const struct sip_msg *msg; +}; + + static void destructor(void *arg) { struct sipevent_sock *sock = arg; @@ -30,6 +36,25 @@ static void destructor(void *arg) } +static bool event_cmp(const struct sipevent_event *evt, + const char *event, const char *id) +{ + if (pl_strcmp(&evt->event, event)) + return false; + + if (!pl_isset(&evt->id) && !id) + return true; + + if (!pl_isset(&evt->id) || !id) + return false; + + if (pl_strcmp(&evt->id, id)) + return false; + + return true; +} + + static bool not_cmp_handler(struct le *le, void *arg) { const struct sip_msg *msg = arg; @@ -41,20 +66,22 @@ static bool not_cmp_handler(struct le *le, void *arg) static bool sub_cmp_handler(struct le *le, void *arg) { - const struct sip_msg *msg = arg; + const struct subcmp *cmp = arg; struct sipsub *sub = le->data; - return sip_dialog_cmp(sub->dlg, msg); + return sip_dialog_cmp(sub->dlg, cmp->msg) && + (!cmp->evt || event_cmp(cmp->evt, sub->event, sub->id)); } static bool sub_cmp_half_handler(struct le *le, void *arg) { - const struct sip_msg *msg = arg; + const struct subcmp *cmp = arg; struct sipsub *sub = le->data; - return sip_dialog_cmp_half(sub->dlg, msg) && - !sip_dialog_established(sub->dlg); + return sip_dialog_cmp_half(sub->dlg, cmp->msg) && + !sip_dialog_established(sub->dlg) && + (!cmp->evt || event_cmp(cmp->evt, sub->event, sub->id)); } @@ -68,12 +95,18 @@ static struct sipnot *sipnot_find(struct sipevent_sock *sock, struct sipsub *sipsub_find(struct sipevent_sock *sock, - const struct sip_msg *msg, bool full) + const struct sip_msg *msg, + const struct sipevent_event *evt, bool full) { + struct subcmp cmp; + + cmp.msg = msg; + cmp.evt = evt; + return list_ledata(hash_lookup(sock->ht_sub, hash_joaat_pl(&msg->callid), full ? sub_cmp_handler : sub_cmp_half_handler, - (void *)msg)); + &cmp)); } @@ -100,9 +133,9 @@ static void notify_handler(struct sipevent_sock *sock, return; } - sub = sipsub_find(sock, msg, true); + sub = sipsub_find(sock, msg, &event, true); if (!sub) { - sub = sipsub_find(sock, msg, false); + sub = sipsub_find(sock, msg, &event, false); if (!sub) { (void)sip_reply(sip, msg, 481, "Subscription Does Not Exist"); @@ -142,11 +175,6 @@ static void notify_handler(struct sipevent_sock *sock, (void)sip_dialog_update(sub->dlg, msg); } - if (pl_strcasecmp(&event.event, sub->event)) { - (void)sip_reply(sip, msg, 489, "Bad Event"); - return; - } - re_printf("notify: %s (%r)\n", sipevent_substate_name(state.state), &state.params); diff --git a/src/sipevent/msg.c b/src/sipevent/msg.c index 38f4124..6a29d72 100644 --- a/src/sipevent/msg.c +++ b/src/sipevent/msg.c @@ -15,6 +15,7 @@ int sipevent_event_decode(struct sipevent_event *se, const struct pl *pl) { + struct pl param; int err; if (!se || !pl) @@ -25,6 +26,11 @@ int sipevent_event_decode(struct sipevent_event *se, const struct pl *pl) if (err) return EBADMSG; + if (!sip_param_decode(&se->params, "id", ¶m)) + se->id = param; + else + se->id = pl_null; + return 0; } diff --git a/src/sipevent/sipevent.h b/src/sipevent/sipevent.h index 9ac1350..1f581ca 100644 --- a/src/sipevent/sipevent.h +++ b/src/sipevent/sipevent.h @@ -38,6 +38,7 @@ struct sipsub { struct sip_auth *auth; struct sip *sip; char *event; + char *id; char *refer_to; char *cuser; char *hdrs; @@ -53,6 +54,7 @@ struct sipsub { }; struct sipsub *sipsub_find(struct sipevent_sock *sock, - const struct sip_msg *msg, bool full); + const struct sip_msg *msg, + const struct sipevent_event *evt, bool full); void sipsub_reschedule(struct sipsub *sub, uint64_t wait); void sipsub_terminate(struct sipsub *sub, int err, const struct sip_msg *msg); diff --git a/src/sipevent/subscribe.c b/src/sipevent/subscribe.c index 81e74c8..7ee472c 100644 --- a/src/sipevent/subscribe.c +++ b/src/sipevent/subscribe.c @@ -85,6 +85,7 @@ static void destructor(void *arg) mem_deref(sub->dlg); mem_deref(sub->auth); mem_deref(sub->event); + mem_deref(sub->id); mem_deref(sub->refer_to); mem_deref(sub->cuser); mem_deref(sub->hdrs); @@ -160,7 +161,7 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) struct sipsub *fsub; - fsub = sipsub_find(sub->sock, msg, true); + fsub = sipsub_find(sub->sock, msg, NULL, true); if (!fsub) { err = sub->forkh(&fsub, sub, msg, sub->arg); @@ -286,6 +287,15 @@ static int send_handler(enum sip_transp tp, const struct sa *src, } +static int print_event(struct re_printf *pf, const struct sipsub *sub) +{ + if (sub->id) + return re_hprintf(pf, "%s;id=%s", sub->event, sub->id); + else + return re_hprintf(pf, "%s", sub->event); +} + + static int request(struct sipsub *sub, bool reset_ls) { if (sub->terminated) @@ -310,12 +320,12 @@ static int request(struct sipsub *sub, bool reset_ls) return sip_drequestf(&sub->req, sub->sip, true, "SUBSCRIBE", sub->dlg, 0, sub->auth, send_handler, response_handler, sub, - "Event: %s\r\n" + "Event: %H\r\n" "Expires: %u\r\n" "%s" "Content-Length: 0\r\n" "\r\n", - sub->event, + print_event, sub, sub->expires, sub->hdrs); } @@ -325,7 +335,7 @@ static int request(struct sipsub *sub, bool reset_ls) static int sipsub_alloc(struct sipsub **subp, struct sipevent_sock *sock, bool refer, const char *uri, const char *from_name, const char *from_uri, - const char *event, uint32_t expires, + const char *event, const char *id, uint32_t expires, const char *refer_to, const char *cuser, const char *routev[], uint32_t routec, sip_auth_h *authh, void *aarg, bool aref, @@ -363,6 +373,12 @@ static int sipsub_alloc(struct sipsub **subp, struct sipevent_sock *sock, if (err) goto out; + if (id) { + err = str_dup(&sub->id, id); + if (err) + goto out; + } + if (refer_to) { err = str_dup(&sub->refer_to, refer_to); if (err) @@ -412,6 +428,7 @@ static int sipsub_alloc(struct sipsub **subp, struct sipevent_sock *sock, * @param from_name SIP From-header Name (optional) * @param from_uri SIP From-header URI * @param event SIP Event to subscribe to + * @param id SIP Event ID * @param expires Subscription expires value * @param cuser Contact username * @param routev Optional route vector @@ -428,7 +445,7 @@ static int sipsub_alloc(struct sipsub **subp, struct sipevent_sock *sock, */ int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, const char *uri, const char *from_name, - const char *from_uri, const char *event, + const char *from_uri, const char *event, const char *id, uint32_t expires, const char *cuser, const char *routev[], uint32_t routec, sip_auth_h *authh, void *aarg, bool aref, @@ -441,7 +458,7 @@ int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, va_start(ap, fmt); err = sipsub_alloc(subp, sock, false, uri, from_name, from_uri, - event, expires, NULL, cuser, + event, id, expires, NULL, cuser, routev, routec, authh, aarg, aref, forkh, notifyh, closeh, arg, fmt, ap); va_end(ap); @@ -485,7 +502,7 @@ int sipevent_refer(struct sipsub **subp, struct sipevent_sock *sock, va_start(ap, fmt); err = sipsub_alloc(subp, sock, true, uri, from_name, from_uri, - "refer", DEFAULT_EXPIRES, refer_to, cuser, + "refer", NULL, DEFAULT_EXPIRES, refer_to, cuser, routev, routec, authh, aarg, aref, forkh, notifyh, closeh, arg, fmt, ap); va_end(ap); @@ -523,6 +540,7 @@ int sipevent_fork(struct sipsub **subp, struct sipsub *osub, goto out; sub->event = mem_ref(osub->event); + sub->id = mem_ref(osub->id); sub->cuser = mem_ref(osub->cuser); sub->hdrs = mem_ref(osub->hdrs); sub->refer = osub->refer; From 3efeafd2079598976a15acb47e84858a0f07b924 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Thu, 8 Dec 2011 13:52:04 +0000 Subject: [PATCH 16/46] event id handlig for REFER --- include/re_sip.h | 1 + src/sip/dialog.c | 6 ++++++ src/sipevent/listen.c | 27 +++++++++++++++++++++++---- src/sipevent/sipevent.h | 1 + src/sipevent/subscribe.c | 3 +++ 5 files changed, 34 insertions(+), 4 deletions(-) diff --git a/include/re_sip.h b/include/re_sip.h index d638ea9..c7db95e 100644 --- a/include/re_sip.h +++ b/include/re_sip.h @@ -306,6 +306,7 @@ int sip_dialog_fork(struct sip_dialog **dlgp, struct sip_dialog *odlg, int sip_dialog_update(struct sip_dialog *dlg, const struct sip_msg *msg); bool sip_dialog_rseq_valid(struct sip_dialog *dlg, const struct sip_msg *msg); const char *sip_dialog_callid(const struct sip_dialog *dlg); +uint32_t sip_dialog_lseq(const struct sip_dialog *dlg); bool sip_dialog_established(const struct sip_dialog *dlg); bool sip_dialog_cmp(const struct sip_dialog *dlg, const struct sip_msg *msg); bool sip_dialog_cmp_half(const struct sip_dialog *dlg, diff --git a/src/sip/dialog.c b/src/sip/dialog.c index 45869a5..1516a8a 100644 --- a/src/sip/dialog.c +++ b/src/sip/dialog.c @@ -511,6 +511,12 @@ const char *sip_dialog_callid(const struct sip_dialog *dlg) } +uint32_t sip_dialog_lseq(const struct sip_dialog *dlg) +{ + return dlg ? dlg->lseq : 0; +} + + bool sip_dialog_established(const struct sip_dialog *dlg) { return dlg && dlg->rtag; diff --git a/src/sipevent/listen.c b/src/sipevent/listen.c index 02254a5..0efae54 100644 --- a/src/sipevent/listen.c +++ b/src/sipevent/listen.c @@ -37,7 +37,8 @@ static void destructor(void *arg) static bool event_cmp(const struct sipevent_event *evt, - const char *event, const char *id) + const char *event, const char *id, + int32_t refer_cseq) { if (pl_strcmp(&evt->event, event)) return false; @@ -45,9 +46,16 @@ static bool event_cmp(const struct sipevent_event *evt, if (!pl_isset(&evt->id) && !id) return true; - if (!pl_isset(&evt->id) || !id) + if (!pl_isset(&evt->id)) return false; + if (!id) { + if (refer_cseq >= 0 && (int32_t)pl_u32(&evt->id) == refer_cseq) + return true; + + return false; + } + if (pl_strcmp(&evt->id, id)) return false; @@ -70,7 +78,8 @@ static bool sub_cmp_handler(struct le *le, void *arg) struct sipsub *sub = le->data; return sip_dialog_cmp(sub->dlg, cmp->msg) && - (!cmp->evt || event_cmp(cmp->evt, sub->event, sub->id)); + (!cmp->evt || event_cmp(cmp->evt, sub->event, sub->id, + sub->refer_cseq)); } @@ -81,7 +90,8 @@ static bool sub_cmp_half_handler(struct le *le, void *arg) return sip_dialog_cmp_half(sub->dlg, cmp->msg) && !sip_dialog_established(sub->dlg) && - (!cmp->evt || event_cmp(cmp->evt, sub->event, sub->id)); + (!cmp->evt || event_cmp(cmp->evt, sub->event, sub->id, + sub->refer_cseq)); } @@ -175,6 +185,15 @@ static void notify_handler(struct sipevent_sock *sock, (void)sip_dialog_update(sub->dlg, msg); } + if (sub->refer_cseq >= 0 && !sub->id && pl_isset(&event.id)) { + + err = pl_strdup(&sub->id, &event.id); + if (err) { + (void)sip_treply(NULL, sip, msg, 500, strerror(err)); + return; + } + } + re_printf("notify: %s (%r)\n", sipevent_substate_name(state.state), &state.params); diff --git a/src/sipevent/sipevent.h b/src/sipevent/sipevent.h index 1f581ca..e171d4b 100644 --- a/src/sipevent/sipevent.h +++ b/src/sipevent/sipevent.h @@ -46,6 +46,7 @@ struct sipsub { sipevent_notify_h *notifyh; sipevent_close_h *closeh; void *arg; + int32_t refer_cseq; uint32_t expires; uint32_t failc; bool subscribed; diff --git a/src/sipevent/subscribe.c b/src/sipevent/subscribe.c index 7ee472c..1ac12d3 100644 --- a/src/sipevent/subscribe.c +++ b/src/sipevent/subscribe.c @@ -306,6 +306,8 @@ static int request(struct sipsub *sub, bool reset_ls) if (sub->refer) { + sub->refer_cseq = sip_dialog_lseq(sub->dlg); + return sip_drequestf(&sub->req, sub->sip, true, "REFER", sub->dlg, 0, sub->auth, send_handler, response_handler, sub, @@ -396,6 +398,7 @@ static int sipsub_alloc(struct sipsub **subp, struct sipevent_sock *sock, goto out; } + sub->refer_cseq = -1; sub->refer = refer; sub->sock = mem_ref(sock); sub->sip = mem_ref(sock->sip); From b9d4878c46eb75505bc131b6a25e3a2fc236c9c2 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Thu, 8 Dec 2011 15:11:31 +0000 Subject: [PATCH 17/46] added sipevent_dsubscribe/refer() --- include/re_sipevent.h | 14 +++++ src/sipevent/subscribe.c | 111 +++++++++++++++++++++++++++++++++++---- 2 files changed, 115 insertions(+), 10 deletions(-) diff --git a/include/re_sipevent.h b/include/re_sipevent.h index 494bc8c..eaeb74c 100644 --- a/include/re_sipevent.h +++ b/include/re_sipevent.h @@ -34,6 +34,13 @@ int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, sipevent_fork_h *forkh, sipevent_notify_h *notifyh, sipevent_close_h *closeh, void *arg, const char *fmt, ...); +int sipevent_dsubscribe(struct sipsub **subp, struct sipevent_sock *sock, + struct sip_dialog *dlg, const char *event, + const char *id, uint32_t expires, const char *cuser, + sip_auth_h *authh, void *aarg, bool aref, + sipevent_notify_h *notifyh, sipevent_close_h *closeh, + 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 *refer_to, @@ -42,6 +49,13 @@ int sipevent_refer(struct sipsub **subp, struct sipevent_sock *sock, sipevent_fork_h *forkh, sipevent_notify_h *notifyh, sipevent_close_h *closeh, void *arg, const char *fmt, ...); +int sipevent_drefer(struct sipsub **subp, struct sipevent_sock *sock, + struct sip_dialog *dlg, const char *refer_to, + const char *cuser, + sip_auth_h *authh, void *aarg, bool aref, + sipevent_notify_h *notifyh, sipevent_close_h *closeh, + void *arg, const char *fmt, ...); + int sipevent_fork(struct sipsub **subp, struct sipsub *osub, const struct sip_msg *msg, sip_auth_h *authh, void *aarg, bool aref, diff --git a/src/sipevent/subscribe.c b/src/sipevent/subscribe.c index 1ac12d3..1d2a87b 100644 --- a/src/sipevent/subscribe.c +++ b/src/sipevent/subscribe.c @@ -335,7 +335,7 @@ static int request(struct sipsub *sub, bool reset_ls) static int sipsub_alloc(struct sipsub **subp, struct sipevent_sock *sock, - bool refer, const char *uri, + bool refer, struct sip_dialog *dlg, const char *uri, const char *from_name, const char *from_uri, const char *event, const char *id, uint32_t expires, const char *refer_to, const char *cuser, @@ -348,7 +348,10 @@ static int sipsub_alloc(struct sipsub **subp, struct sipevent_sock *sock, struct sipsub *sub; int err; - if (!subp || !sock || !uri || !from_uri || !event || !expires ||!cuser) + if (!subp || !sock || !event || !expires ||!cuser) + return EINVAL; + + if (!dlg && (!uri || !from_uri)) return EINVAL; if (refer && !refer_to) @@ -358,10 +361,15 @@ static int sipsub_alloc(struct sipsub **subp, struct sipevent_sock *sock, if (!sub) return ENOMEM; - err = sip_dialog_alloc(&sub->dlg, uri, uri, from_name, from_uri, - routev, routec); - if (err) - goto out; + if (dlg) { + sub->dlg = mem_ref(dlg); + } + else { + err = sip_dialog_alloc(&sub->dlg, uri, uri, from_name, + from_uri, routev, routec); + if (err) + goto out; + } hash_append(sock->ht_sub, hash_joaat_str(sip_dialog_callid(sub->dlg)), @@ -439,7 +447,8 @@ static int sipsub_alloc(struct sipsub **subp, struct sipevent_sock *sock, * @param authh Authentication handler * @param aarg Authentication handler argument * @param aref True to ref argument - * @param noth Notify handler + * @param forkh Fork handler + * @param notifyh Notify handler * @param closeh Close handler * @param arg Response handler argument * @param fmt Formatted strings with extra SIP Headers @@ -460,7 +469,7 @@ int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, int err; va_start(ap, fmt); - err = sipsub_alloc(subp, sock, false, uri, from_name, from_uri, + err = sipsub_alloc(subp, sock, false, NULL, uri, from_name, from_uri, event, id, expires, NULL, cuser, routev, routec, authh, aarg, aref, forkh, notifyh, closeh, arg, fmt, ap); @@ -470,6 +479,47 @@ int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, } +/** + * Allocate a SIP subscriber client using an existing dialog + * + * @param subp Pointer to allocated SIP subscriber client + * @param sock SIP Event socket + * @param dlg Established SIP Dialog + * @param event SIP Event to subscribe to + * @param id SIP Event ID + * @param expires Subscription expires value + * @param cuser Contact username + * @param authh Authentication handler + * @param aarg Authentication handler argument + * @param aref True to ref argument + * @param noth Notify handler + * @param closeh Close handler + * @param arg Response handler argument + * @param fmt Formatted strings with extra SIP Headers + * + * @return 0 if success, otherwise errorcode + */ +int sipevent_dsubscribe(struct sipsub **subp, struct sipevent_sock *sock, + struct sip_dialog *dlg, const char *event, + const char *id, uint32_t expires, const char *cuser, + sip_auth_h *authh, void *aarg, bool aref, + sipevent_notify_h *notifyh, sipevent_close_h *closeh, + void *arg, const char *fmt, ...) +{ + va_list ap; + int err; + + va_start(ap, fmt); + err = sipsub_alloc(subp, sock, false, dlg, NULL, NULL, NULL, + event, id, expires, NULL, cuser, + NULL, 0, authh, aarg, aref, NULL, notifyh, + closeh, arg, fmt, ap); + va_end(ap); + + return err; +} + + /** * Allocate a SIP refer client * @@ -478,13 +528,15 @@ int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, * @param uri SIP Request URI * @param from_name SIP From-header Name (optional) * @param from_uri SIP From-header URI + * @param refer_to Refer-To address * @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 noth Notify handler + * @param forkh Fork handler + * @param notifyh Notify handler * @param closeh Close handler * @param arg Response handler argument * @param fmt Formatted strings with extra SIP Headers @@ -504,7 +556,7 @@ int sipevent_refer(struct sipsub **subp, struct sipevent_sock *sock, int err; va_start(ap, fmt); - err = sipsub_alloc(subp, sock, true, uri, from_name, from_uri, + err = sipsub_alloc(subp, sock, true, NULL, uri, from_name, from_uri, "refer", NULL, DEFAULT_EXPIRES, refer_to, cuser, routev, routec, authh, aarg, aref, forkh, notifyh, closeh, arg, fmt, ap); @@ -514,6 +566,45 @@ int sipevent_refer(struct sipsub **subp, struct sipevent_sock *sock, } +/** + * Allocate a SIP refer client using an existing dialog + * + * @param subp Pointer to allocated SIP subscriber client + * @param sock SIP Event socket + * @param dlg Established SIP Dialog + * @param refer_to Refer-To address + * @param cuser Contact username + * @param authh Authentication handler + * @param aarg Authentication handler argument + * @param aref True to ref argument + * @param notifyh Notify handler + * @param closeh Close handler + * @param arg Response handler argument + * @param fmt Formatted strings with extra SIP Headers + * + * @return 0 if success, otherwise errorcode + */ +int sipevent_drefer(struct sipsub **subp, struct sipevent_sock *sock, + struct sip_dialog *dlg, const char *refer_to, + const char *cuser, + sip_auth_h *authh, void *aarg, bool aref, + sipevent_notify_h *notifyh, sipevent_close_h *closeh, + void *arg, const char *fmt, ...) +{ + va_list ap; + int err; + + va_start(ap, fmt); + err = sipsub_alloc(subp, sock, true, dlg, NULL, NULL, NULL, + "refer", NULL, DEFAULT_EXPIRES, refer_to, cuser, + NULL, 0, authh, aarg, aref, NULL, notifyh, + closeh, arg, fmt, ap); + va_end(ap); + + return err; +} + + int sipevent_fork(struct sipsub **subp, struct sipsub *osub, const struct sip_msg *msg, sip_auth_h *authh, void *aarg, bool aref, From a89b1858ae4145e37311dc27e06f13a72e3f14ea Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Fri, 9 Dec 2011 12:45:40 +0000 Subject: [PATCH 18/46] handle ID strdup errors gracefully --- src/sipevent/listen.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/sipevent/listen.c b/src/sipevent/listen.c index 0efae54..1c498a5 100644 --- a/src/sipevent/listen.c +++ b/src/sipevent/listen.c @@ -187,11 +187,7 @@ static void notify_handler(struct sipevent_sock *sock, if (sub->refer_cseq >= 0 && !sub->id && pl_isset(&event.id)) { - err = pl_strdup(&sub->id, &event.id); - if (err) { - (void)sip_treply(NULL, sip, msg, 500, strerror(err)); - return; - } + (void)pl_strdup(&sub->id, &event.id); } re_printf("notify: %s (%r)\n", sipevent_substate_name(state.state), From 1e09dea0b1dfb6195f7a9c218232bc39d8b708c8 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Fri, 9 Dec 2011 13:22:42 +0000 Subject: [PATCH 19/46] revert previous patch --- src/sipevent/listen.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sipevent/listen.c b/src/sipevent/listen.c index 1c498a5..0efae54 100644 --- a/src/sipevent/listen.c +++ b/src/sipevent/listen.c @@ -187,7 +187,11 @@ static void notify_handler(struct sipevent_sock *sock, if (sub->refer_cseq >= 0 && !sub->id && pl_isset(&event.id)) { - (void)pl_strdup(&sub->id, &event.id); + err = pl_strdup(&sub->id, &event.id); + if (err) { + (void)sip_treply(NULL, sip, msg, 500, strerror(err)); + return; + } } re_printf("notify: %s (%r)\n", sipevent_substate_name(state.state), From e15e4a936d68d3a1f8c5c0155dd7ef9db87b1175 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Wed, 14 Dec 2011 14:49:59 +0000 Subject: [PATCH 20/46] sipevent: added notifier --- include/re_sipevent.h | 79 ++++--- src/sipevent/listen.c | 39 +++- src/sipevent/mod.mk | 1 + src/sipevent/msg.c | 11 + src/sipevent/notify.c | 441 +++++++++++++++++++++++++++++++++++++++ src/sipevent/sipevent.h | 28 +++ src/sipevent/subscribe.c | 3 +- 7 files changed, 565 insertions(+), 37 deletions(-) create mode 100644 src/sipevent/notify.c diff --git a/include/re_sipevent.h b/include/re_sipevent.h index eaeb74c..4b98a37 100644 --- a/include/re_sipevent.h +++ b/include/re_sipevent.h @@ -5,6 +5,39 @@ */ +/* Message Components */ + +struct sipevent_event { + struct pl event; + struct pl params; + struct pl id; +}; + +enum sipevent_subst { + SIPEVENT_ACTIVE = 0, + SIPEVENT_PENDING, + SIPEVENT_TERMINATED, +}; + +enum sipevent_reason { + SIPEVENT_TIMEOUT = 0, + SIPEVENT_NORESOURCE, +}; + +struct sipevent_substate { + enum sipevent_subst state; + struct pl params; + struct pl expires; + struct pl reason; +}; + +int sipevent_event_decode(struct sipevent_event *se, const struct pl *pl); +int sipevent_substate_decode(struct sipevent_substate *ss, + const struct pl *pl); +const char *sipevent_substate_name(enum sipevent_subst state); +const char *sipevent_reason_name(enum sipevent_reason reason); + + /* Listener Socket */ struct sipevent_sock; @@ -14,6 +47,23 @@ int sipevent_listen(struct sipevent_sock **sockp, struct sip *sip, sip_msg_h *subh, void *arg); +/* Notifier */ + +struct sipnot; + +typedef void (sipevent_close_h)(int err, const struct sip_msg *msg, void *arg); + +int sipevent_accept(struct sipnot **notp, struct sipevent_sock *sock, + const struct sip_msg *msg, struct sip_dialog *dlg, + const struct sipevent_event *event, + uint16_t scode, const char *reason, uint32_t expires_max, + const char *cuser, const char *ctype, + sip_auth_h *authh, void *aarg, bool aref, + sipevent_close_h *closeh, void *arg, const char *fmt, ...); +int sipevent_notify(struct sipnot *not, struct mbuf *mb); +int sipevent_notifyf(struct sipnot *not, const char *fmt, ...); + + /* Subscriber */ struct sipsub; @@ -22,8 +72,6 @@ typedef int (sipevent_fork_h)(struct sipsub **subp, struct sipsub *osub, const struct sip_msg *msg, void *arg); typedef void (sipevent_notify_h)(struct sip *sip, const struct sip_msg *msg, void *arg); -typedef void (sipevent_close_h)(int err, const struct sip_msg *msg, void *arg); - int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, const char *uri, const char *from_name, @@ -61,30 +109,3 @@ int sipevent_fork(struct sipsub **subp, struct sipsub *osub, sip_auth_h *authh, void *aarg, bool aref, sipevent_notify_h *notifyh, sipevent_close_h *closeh, void *arg); - - -/* Message Components */ - -struct sipevent_event { - struct pl event; - struct pl params; - struct pl id; -}; - -enum sipevent_subst { - SIPEVENT_ACTIVE = 0, - SIPEVENT_PENDING, - SIPEVENT_TERMINATED, -}; - -struct sipevent_substate { - enum sipevent_subst state; - struct pl params; - struct pl expires; - struct pl reason; -}; - -int sipevent_event_decode(struct sipevent_event *se, const struct pl *pl); -int sipevent_substate_decode(struct sipevent_substate *ss, - const struct pl *pl); -const char *sipevent_substate_name(enum sipevent_subst state); diff --git a/src/sipevent/listen.c b/src/sipevent/listen.c index 0efae54..d7e0145 100644 --- a/src/sipevent/listen.c +++ b/src/sipevent/listen.c @@ -65,10 +65,11 @@ static bool event_cmp(const struct sipevent_event *evt, static bool not_cmp_handler(struct le *le, void *arg) { - const struct sip_msg *msg = arg; + const struct subcmp *cmp = arg; struct sipnot *not = le->data; - return sip_dialog_cmp(not->dlg, msg); + return sip_dialog_cmp(not->dlg, cmp->msg) && + event_cmp(cmp->evt, not->event, not->id, -1); } @@ -96,11 +97,17 @@ static bool sub_cmp_half_handler(struct le *le, void *arg) static struct sipnot *sipnot_find(struct sipevent_sock *sock, - const struct sip_msg *msg) + const struct sip_msg *msg, + const struct sipevent_event *evt) { + struct subcmp cmp; + + cmp.msg = msg; + cmp.evt = evt; + return list_ledata(hash_lookup(sock->ht_not, hash_joaat_pl(&msg->callid), - not_cmp_handler, (void *)msg)); + not_cmp_handler, &cmp)); } @@ -229,10 +236,19 @@ static void notify_handler(struct sipevent_sock *sock, static void subscribe_handler(struct sipevent_sock *sock, const struct sip_msg *msg) { + struct sipevent_event event; struct sip *sip = sock->sip; + const struct sip_hdr *hdr; struct sipnot *not; + uint32_t expires; - not = sipnot_find(sock, msg); + hdr = sip_msg_hdr(msg, SIP_HDR_EVENT); + if (!hdr || sipevent_event_decode(&event, &hdr->val)) { + (void)sip_reply(sip, msg, 400, "Bad Event Header"); + return; + } + + not = sipnot_find(sock, msg, &event); if (!not || not->terminated) { (void)sip_reply(sip, msg, 481, "Subscription Does Not Exist"); return; @@ -245,7 +261,18 @@ static void subscribe_handler(struct sipevent_sock *sock, (void)sip_dialog_update(not->dlg, msg); - /* todo: implement notifier */ + if (pl_isset(&msg->expires)) + expires = pl_u32(&msg->expires); + else + expires = DEFAULT_EXPIRES; + + sipnot_refresh(not, expires); + + (void)sipnot_reply(not, msg, 200, "OK"); + + if (expires > 0) { + (void)sipnot_notify(not); + } } diff --git a/src/sipevent/mod.mk b/src/sipevent/mod.mk index c99d43c..3426b8c 100644 --- a/src/sipevent/mod.mk +++ b/src/sipevent/mod.mk @@ -6,4 +6,5 @@ SRCS += sipevent/listen.c SRCS += sipevent/msg.c +SRCS += sipevent/notify.c SRCS += sipevent/subscribe.c diff --git a/src/sipevent/msg.c b/src/sipevent/msg.c index 6a29d72..d2cc409 100644 --- a/src/sipevent/msg.c +++ b/src/sipevent/msg.c @@ -81,3 +81,14 @@ const char *sipevent_substate_name(enum sipevent_subst state) default: return "???"; } } + + +const char *sipevent_reason_name(enum sipevent_reason reason) +{ + switch (reason) { + + case SIPEVENT_TIMEOUT: return "timeout"; + case SIPEVENT_NORESOURCE: return "noresource"; + default: return "???"; + } +} diff --git a/src/sipevent/notify.c b/src/sipevent/notify.c new file mode 100644 index 0000000..0c9d041 --- /dev/null +++ b/src/sipevent/notify.c @@ -0,0 +1,441 @@ +/** + * @file not.c SIP Event Notify + * + * Copyright (C) 2010 Creytiv.com + */ +#include // todo: remove +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sipevent.h" + + +static int notify_request(struct sipnot *not, bool reset_ls); + + +static void internal_close_handler(int err, const struct sip_msg *msg, + void *arg) +{ + (void)err; + (void)msg; + (void)arg; +} + + +static bool terminate(struct sipnot *not, enum sipevent_reason reason) +{ + not->terminated = true; + not->reason = reason; + not->closeh = internal_close_handler; + + if (not->req) { + mem_ref(not); + return true; + } + + if (not->subscribed && !notify_request(not, true)) { + mem_ref(not); + return true; + } + + return false; +} + + +static void destructor(void *arg) +{ + struct sipnot *not = arg; + + tmr_cancel(¬->tmr); + + if (!not->terminated) { + + if (terminate(not, SIPEVENT_NORESOURCE)) + return; + } + + hash_unlink(¬->he); + mem_deref(not->req); + mem_deref(not->dlg); + mem_deref(not->auth); + mem_deref(not->mb); + mem_deref(not->event); + mem_deref(not->id); + mem_deref(not->cuser); + mem_deref(not->hdrs); + mem_deref(not->ctype); + mem_deref(not->sock); + mem_deref(not->sip); +} + + +static void sipnot_terminate(struct sipnot *not, int err, + const struct sip_msg *msg, + enum sipevent_reason reason) +{ + sipevent_close_h *closeh; + void *arg; + + closeh = not->closeh; + arg = not->arg; + + tmr_cancel(¬->tmr); + (void)terminate(not, reason); + + closeh(err, msg, arg); +} + + +static void tmr_handler(void *arg) +{ + struct sipnot *not = arg; + + re_printf("subscription expired\n"); + + sipnot_terminate(not, ETIMEDOUT, NULL, SIPEVENT_TIMEOUT); +} + + +void sipnot_refresh(struct sipnot *not, uint32_t expires) +{ + expires = min(expires, not->expires_max); + + re_printf("will expire in %u secs\n", expires); + + tmr_start(¬->tmr, expires * 1000, tmr_handler, not); +} + + +static void response_handler(int err, const struct sip_msg *msg, void *arg) +{ + struct sipnot *not = arg; + + if (err) + re_printf("notify reply: %s\n", strerror(err)); + else + re_printf("notify reply: %u %r\n", msg->scode, &msg->reason); + + if (err || sip_request_loops(¬->ls, msg->scode)) + goto out; + + if (msg->scode < 200) { + return; + } + else if (msg->scode < 300) { + + (void)sip_dialog_update(not->dlg, msg); + } + else { + switch (msg->scode) { + + case 401: + case 407: + err = sip_auth_authenticate(not->auth, msg); + if (err) { + err = (err == EAUTH) ? 0 : err; + break; + } + + err = notify_request(not, false); + if (err) + break; + + return; + + case 403: + sip_auth_reset(not->auth); + break; + + case 481: + not->subscribed = false; + break; + } + } + + out: + if (not->termsent) { + mem_deref(not); + } + else if (not->terminated) { + if (!not->subscribed || notify_request(not, true)) + mem_deref(not); + } + else if (!not->subscribed) { + sipnot_terminate(not, err, msg, -1); + } + else if (not->notify_pending) { + (void)notify_request(not, true); + } +} + + +static int send_handler(enum sip_transp tp, const struct sa *src, + const struct sa *dst, struct mbuf *mb, void *arg) +{ + struct sipnot *not = arg; + (void)dst; + + return mbuf_printf(mb, "Contact: \r\n", + not->cuser, src, sip_transp_param(tp)); +} + + +static int print_event(struct re_printf *pf, const struct sipnot *not) +{ + if (not->id) + return re_hprintf(pf, "%s;id=%s", not->event, not->id); + else + return re_hprintf(pf, "%s", not->event); +} + + +static int print_substate(struct re_printf *pf, const struct sipnot *not) +{ + if (not->terminated) { + return re_hprintf(pf, "terminated;reason=%s", + sipevent_reason_name(not->reason)); + } + else { + uint32_t expires; + + expires = (uint32_t)(tmr_get_expire(¬->tmr) / 1000); + + return re_hprintf(pf, "active;expires=%u", expires); + } +} + + +static int print_content(struct re_printf *pf, const struct sipnot *not) +{ + if (!not->mb) + return re_hprintf(pf, + "Content-Length: 0\r\n" + "\r\n"); + else + return re_hprintf(pf, + "Content-Type: %s\r\n" + "Content-Length: %zu\r\n" + "\r\n" + "%b", + not->ctype, + mbuf_get_left(not->mb), + mbuf_buf(not->mb), + mbuf_get_left(not->mb)); +} + + +static int notify_request(struct sipnot *not, bool reset_ls) +{ + if (reset_ls) + sip_loopstate_reset(¬->ls); + + if (not->terminated) + not->termsent = true; + + not->notify_pending = false; + + return sip_drequestf(¬->req, not->sip, true, "NOTIFY", + not->dlg, 0, not->auth, + send_handler, response_handler, not, + "Event: %H\r\n" + "Subscription-State: %H\r\n" + "%s" + "%H", + print_event, not, + print_substate, not, + not->hdrs, + print_content, not); +} + + +int sipnot_notify(struct sipnot *not) +{ + if (not->req) { + not->notify_pending = true; + return 0; + } + + return notify_request(not, true); +} + + +int sipnot_reply(struct sipnot *not, const struct sip_msg *msg, + uint16_t scode, const char *reason) +{ + uint32_t expires; + + expires = (uint32_t)(tmr_get_expire(¬->tmr) / 1000); + + return sip_treplyf(NULL, NULL, not->sip, msg, true, scode, reason, + "Contact: \r\n" + "Expires: %u\r\n" + "Content-Length: 0\r\n" + "\r\n", + not->cuser, &msg->dst, sip_transp_param(msg->tp), + expires); +} + + +int sipevent_accept(struct sipnot **notp, struct sipevent_sock *sock, + const struct sip_msg *msg, struct sip_dialog *dlg, + const struct sipevent_event *event, + uint16_t scode, const char *reason, uint32_t expires_max, + const char *cuser, const char *ctype, + sip_auth_h *authh, void *aarg, bool aref, + sipevent_close_h *closeh, void *arg, const char *fmt, ...) +{ + struct sipnot *not; + uint32_t expires; + int err; + + if (!notp || !sock || !msg || !scode || !reason || !expires_max || + !cuser || !ctype) + return EINVAL; + + not = mem_zalloc(sizeof(*not), destructor); + if (!not) + return ENOMEM; + + if (!pl_strcmp(&msg->met, "REFER")) { + + err = str_dup(¬->event, "refer"); + if (err) + goto out; + + err = re_sdprintf(¬->id, "%u", msg->cseq.num); + if (err) + goto out; + } + else { + if (!event) { + err = EINVAL; + goto out; + } + + err = pl_strdup(¬->event, &event->event); + if (err) + goto out; + + if (pl_isset(&event->id)) { + + err = pl_strdup(¬->id, &event->id); + if (err) + goto out; + } + } + + if (dlg) { + not->dlg = mem_ref(dlg); + } + else { + err = sip_dialog_accept(¬->dlg, msg); + if (err) + goto out; + } + + hash_append(sock->ht_not, + hash_joaat_str(sip_dialog_callid(not->dlg)), + ¬->he, not); + + err = sip_auth_alloc(¬->auth, authh, aarg, aref); + if (err) + goto out; + + err = str_dup(¬->cuser, cuser); + if (err) + goto out; + + err = str_dup(¬->ctype, ctype); + if (err) + goto out; + + if (fmt) { + va_list ap; + + va_start(ap, fmt); + err = re_vsdprintf(¬->hdrs, fmt, ap); + va_end(ap); + if (err) + goto out; + } + + not->expires_max = expires_max; + not->sock = mem_ref(sock); + not->sip = mem_ref(sock->sip); + not->closeh = closeh ? closeh : internal_close_handler; + not->arg = arg; + + if (pl_isset(&msg->expires)) + expires = pl_u32(&msg->expires); + else + expires = DEFAULT_EXPIRES; + + sipnot_refresh(not, expires); + + err = sipnot_reply(not, msg, scode, reason); + if (err) + goto out; + + not->subscribed = true; + + out: + if (err) + mem_deref(not); + else + *notp = not; + + return err; +} + + +int sipevent_notify(struct sipnot *not, struct mbuf *mb) +{ + if (!not || not->terminated) + return EINVAL; + + mem_deref(not->mb); + not->mb = mem_ref(mb); + + return sipnot_notify(not); +} + + +int sipevent_notifyf(struct sipnot *not, const char *fmt, ...) +{ + struct mbuf *mb; + va_list ap; + int err; + + if (!not || not->terminated || !fmt) + return EINVAL; + + mb = mbuf_alloc(1024); + if (!mb) + return ENOMEM; + + va_start(ap, fmt); + err = mbuf_vprintf(mb, fmt, ap); + va_end(ap); + if (err) + goto out; + + mb->pos = 0; + + err = sipevent_notify(not, mb); + if (err) + goto out; + + out: + mem_deref(mb); + + return err; +} diff --git a/src/sipevent/sipevent.h b/src/sipevent/sipevent.h index e171d4b..a2e8214 100644 --- a/src/sipevent/sipevent.h +++ b/src/sipevent/sipevent.h @@ -4,6 +4,10 @@ * Copyright (C) 2010 Creytiv.com */ +enum { + DEFAULT_EXPIRES = 3600, +}; + /* Listener Socket */ @@ -21,10 +25,34 @@ struct sipevent_sock { struct sipnot { struct le he; + struct sip_loopstate ls; + struct tmr tmr; + struct sipevent_sock *sock; + struct sip_request *req; struct sip_dialog *dlg; + struct sip_auth *auth; + struct sip *sip; + struct mbuf *mb; + char *event; + char *id; + char *cuser; + char *hdrs; + char *ctype; + sipevent_close_h *closeh; + void *arg; + uint32_t expires_max; + enum sipevent_reason reason; + bool notify_pending; + bool subscribed; bool terminated; + bool termsent; }; +void sipnot_refresh(struct sipnot *not, uint32_t expires); +int sipnot_notify(struct sipnot *not); +int sipnot_reply(struct sipnot *not, const struct sip_msg *msg, + uint16_t scode, const char *reason); + /* Subscriber */ diff --git a/src/sipevent/subscribe.c b/src/sipevent/subscribe.c index 1d2a87b..84de1e2 100644 --- a/src/sipevent/subscribe.c +++ b/src/sipevent/subscribe.c @@ -20,7 +20,6 @@ enum { - DEFAULT_EXPIRES = 3600, RESUB_FAIL_WAIT = 60000, RESUB_FAILC_MAX = 7, }; @@ -348,7 +347,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 || !expires || !cuser) return EINVAL; if (!dlg && (!uri || !from_uri)) From 068758967cbc5164f68cdda064099e96f0962950 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Thu, 15 Dec 2011 08:34:59 +0000 Subject: [PATCH 21/46] improved sipevent_notifyf() --- src/sipevent/notify.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/sipevent/notify.c b/src/sipevent/notify.c index 0c9d041..c7cd909 100644 --- a/src/sipevent/notify.c +++ b/src/sipevent/notify.c @@ -173,6 +173,7 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) sipnot_terminate(not, err, msg, -1); } else if (not->notify_pending) { + re_printf("sending queued request\n"); (void)notify_request(not, true); } } @@ -260,6 +261,7 @@ static int notify_request(struct sipnot *not, bool reset_ls) int sipnot_notify(struct sipnot *not) { if (not->req) { + re_printf("waiting for previous request to complete\n"); not->notify_pending = true; return 0; } @@ -409,7 +411,8 @@ int sipevent_notify(struct sipnot *not, struct mbuf *mb) } -int sipevent_notifyf(struct sipnot *not, const char *fmt, ...) +int sipevent_notifyf(struct sipnot *not, struct mbuf **mbp, + const char *fmt, ...) { struct mbuf *mb; va_list ap; @@ -418,6 +421,9 @@ int sipevent_notifyf(struct sipnot *not, const char *fmt, ...) if (!not || not->terminated || !fmt) return EINVAL; + if (mbp && *mbp) + return sipevent_notify(not, *mbp); + mb = mbuf_alloc(1024); if (!mb) return ENOMEM; @@ -435,7 +441,10 @@ int sipevent_notifyf(struct sipnot *not, const char *fmt, ...) goto out; out: - mem_deref(mb); + if (err || !mbp) + mem_deref(mb); + else + *mbp = mb; return err; } From 4bfebde51b94733e501a7155836bf0801c28b13b Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Thu, 15 Dec 2011 10:29:02 +0000 Subject: [PATCH 22/46] configurable default expires --- include/re_sipevent.h | 7 ++++--- src/sipevent/listen.c | 2 +- src/sipevent/notify.c | 11 ++++++----- src/sipevent/sipevent.h | 6 +----- src/sipevent/subscribe.c | 1 + 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/include/re_sipevent.h b/include/re_sipevent.h index 4b98a37..b080669 100644 --- a/include/re_sipevent.h +++ b/include/re_sipevent.h @@ -56,12 +56,13 @@ typedef void (sipevent_close_h)(int err, const struct sip_msg *msg, void *arg); int sipevent_accept(struct sipnot **notp, struct sipevent_sock *sock, const struct sip_msg *msg, struct sip_dialog *dlg, const struct sipevent_event *event, - uint16_t scode, const char *reason, uint32_t expires_max, - const char *cuser, const char *ctype, + uint16_t scode, const char *reason, uint32_t expires_dfl, + uint32_t expires_max, const char *cuser, const char *ctype, sip_auth_h *authh, void *aarg, bool aref, sipevent_close_h *closeh, void *arg, const char *fmt, ...); int sipevent_notify(struct sipnot *not, struct mbuf *mb); -int sipevent_notifyf(struct sipnot *not, const char *fmt, ...); +int sipevent_notifyf(struct sipnot *not, struct mbuf **mbp, + const char *fmt, ...); /* Subscriber */ diff --git a/src/sipevent/listen.c b/src/sipevent/listen.c index d7e0145..a4b6434 100644 --- a/src/sipevent/listen.c +++ b/src/sipevent/listen.c @@ -264,7 +264,7 @@ static void subscribe_handler(struct sipevent_sock *sock, if (pl_isset(&msg->expires)) expires = pl_u32(&msg->expires); else - expires = DEFAULT_EXPIRES; + expires = not->expires_dfl; sipnot_refresh(not, expires); diff --git a/src/sipevent/notify.c b/src/sipevent/notify.c index c7cd909..4626775 100644 --- a/src/sipevent/notify.c +++ b/src/sipevent/notify.c @@ -290,8 +290,8 @@ int sipnot_reply(struct sipnot *not, const struct sip_msg *msg, int sipevent_accept(struct sipnot **notp, struct sipevent_sock *sock, const struct sip_msg *msg, struct sip_dialog *dlg, const struct sipevent_event *event, - uint16_t scode, const char *reason, uint32_t expires_max, - const char *cuser, const char *ctype, + uint16_t scode, const char *reason, uint32_t expires_dfl, + uint32_t expires_max, const char *cuser, const char *ctype, sip_auth_h *authh, void *aarg, bool aref, sipevent_close_h *closeh, void *arg, const char *fmt, ...) { @@ -299,8 +299,8 @@ int sipevent_accept(struct sipnot **notp, struct sipevent_sock *sock, uint32_t expires; int err; - if (!notp || !sock || !msg || !scode || !reason || !expires_max || - !cuser || !ctype) + if (!notp || !sock || !msg || !scode || !reason || !expires_dfl || + !expires_max || !cuser || !ctype) return EINVAL; not = mem_zalloc(sizeof(*not), destructor); @@ -370,6 +370,7 @@ int sipevent_accept(struct sipnot **notp, struct sipevent_sock *sock, goto out; } + not->expires_dfl = expires_dfl; not->expires_max = expires_max; not->sock = mem_ref(sock); not->sip = mem_ref(sock->sip); @@ -379,7 +380,7 @@ int sipevent_accept(struct sipnot **notp, struct sipevent_sock *sock, if (pl_isset(&msg->expires)) expires = pl_u32(&msg->expires); else - expires = DEFAULT_EXPIRES; + expires = not->expires_dfl; sipnot_refresh(not, expires); diff --git a/src/sipevent/sipevent.h b/src/sipevent/sipevent.h index a2e8214..7f51a0f 100644 --- a/src/sipevent/sipevent.h +++ b/src/sipevent/sipevent.h @@ -4,11 +4,6 @@ * Copyright (C) 2010 Creytiv.com */ -enum { - DEFAULT_EXPIRES = 3600, -}; - - /* Listener Socket */ struct sipevent_sock { @@ -40,6 +35,7 @@ struct sipnot { char *ctype; sipevent_close_h *closeh; void *arg; + uint32_t expires_dfl; uint32_t expires_max; enum sipevent_reason reason; bool notify_pending; diff --git a/src/sipevent/subscribe.c b/src/sipevent/subscribe.c index 84de1e2..3fa9e2b 100644 --- a/src/sipevent/subscribe.c +++ b/src/sipevent/subscribe.c @@ -20,6 +20,7 @@ enum { + DEFAULT_EXPIRES = 3600, RESUB_FAIL_WAIT = 60000, RESUB_FAILC_MAX = 7, }; From adca48e7eed34f7a472f6d3f304bf9b57f057998 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Thu, 15 Dec 2011 13:00:20 +0000 Subject: [PATCH 23/46] added notify/terminate option --- include/re_sipevent.h | 13 +++++++++---- src/sipevent/msg.c | 12 ++++++++---- src/sipevent/notify.c | 23 ++++++++++++++++------- 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/include/re_sipevent.h b/include/re_sipevent.h index b080669..979fed7 100644 --- a/include/re_sipevent.h +++ b/include/re_sipevent.h @@ -20,7 +20,11 @@ enum sipevent_subst { }; enum sipevent_reason { - SIPEVENT_TIMEOUT = 0, + SIPEVENT_DEACTIVATED = 0, + SIPEVENT_PROBATION, + SIPEVENT_REJECTED, + SIPEVENT_TIMEOUT, + SIPEVENT_GIVEUP, SIPEVENT_NORESOURCE, }; @@ -60,9 +64,10 @@ int sipevent_accept(struct sipnot **notp, struct sipevent_sock *sock, uint32_t expires_max, const char *cuser, const char *ctype, sip_auth_h *authh, void *aarg, bool aref, sipevent_close_h *closeh, void *arg, const char *fmt, ...); -int sipevent_notify(struct sipnot *not, struct mbuf *mb); -int sipevent_notifyf(struct sipnot *not, struct mbuf **mbp, - const char *fmt, ...); +int sipevent_notify(struct sipnot *not, struct mbuf *mb, bool term, + enum sipevent_reason reason); +int sipevent_notifyf(struct sipnot *not, struct mbuf **mbp, bool term, + enum sipevent_reason reason, const char *fmt, ...); /* Subscriber */ diff --git a/src/sipevent/msg.c b/src/sipevent/msg.c index d2cc409..4ee2bb9 100644 --- a/src/sipevent/msg.c +++ b/src/sipevent/msg.c @@ -78,7 +78,7 @@ const char *sipevent_substate_name(enum sipevent_subst state) case SIPEVENT_ACTIVE: return "active"; case SIPEVENT_PENDING: return "pending"; case SIPEVENT_TERMINATED: return "terminated"; - default: return "???"; + default: return "unknown"; } } @@ -87,8 +87,12 @@ const char *sipevent_reason_name(enum sipevent_reason reason) { switch (reason) { - case SIPEVENT_TIMEOUT: return "timeout"; - case SIPEVENT_NORESOURCE: return "noresource"; - default: return "???"; + case SIPEVENT_DEACTIVATED: return "deactivated"; + case SIPEVENT_PROBATION: return "probation"; + case SIPEVENT_REJECTED: return "rejected"; + case SIPEVENT_TIMEOUT: return "timeout"; + case SIPEVENT_GIVEUP: return "giveup"; + case SIPEVENT_NORESOURCE: return "noresource"; + default: return "unknown"; } } diff --git a/src/sipevent/notify.c b/src/sipevent/notify.c index 4626775..790b1dc 100644 --- a/src/sipevent/notify.c +++ b/src/sipevent/notify.c @@ -400,20 +400,29 @@ int sipevent_accept(struct sipnot **notp, struct sipevent_sock *sock, } -int sipevent_notify(struct sipnot *not, struct mbuf *mb) +int sipevent_notify(struct sipnot *not, struct mbuf *mb, bool term, + enum sipevent_reason reason) { if (!not || not->terminated) return EINVAL; - mem_deref(not->mb); - not->mb = mem_ref(mb); + if (mb || !term) { + mem_deref(not->mb); + not->mb = mem_ref(mb); + } + + if (term) { + tmr_cancel(¬->tmr); + (void)terminate(not, reason); + return 0; + } return sipnot_notify(not); } -int sipevent_notifyf(struct sipnot *not, struct mbuf **mbp, - const char *fmt, ...) +int sipevent_notifyf(struct sipnot *not, struct mbuf **mbp, bool term, + enum sipevent_reason reason, const char *fmt, ...) { struct mbuf *mb; va_list ap; @@ -423,7 +432,7 @@ int sipevent_notifyf(struct sipnot *not, struct mbuf **mbp, return EINVAL; if (mbp && *mbp) - return sipevent_notify(not, *mbp); + return sipevent_notify(not, *mbp, term, reason); mb = mbuf_alloc(1024); if (!mb) @@ -437,7 +446,7 @@ int sipevent_notifyf(struct sipnot *not, struct mbuf **mbp, mb->pos = 0; - err = sipevent_notify(not, mb); + err = sipevent_notify(not, mb, term, reason); if (err) goto out; From 338ae8be9e2644102e93f4b13421c9b13a2ac989 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Fri, 16 Dec 2011 10:43:50 +0000 Subject: [PATCH 24/46] added redundant terminated check in tmr_handlers --- src/sipevent/notify.c | 3 +++ src/sipevent/subscribe.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sipevent/notify.c b/src/sipevent/notify.c index 790b1dc..d86dc23 100644 --- a/src/sipevent/notify.c +++ b/src/sipevent/notify.c @@ -99,6 +99,9 @@ static void tmr_handler(void *arg) { struct sipnot *not = arg; + if (not->terminated) + return; + re_printf("subscription expired\n"); sipnot_terminate(not, ETIMEDOUT, NULL, SIPEVENT_TIMEOUT); diff --git a/src/sipevent/subscribe.c b/src/sipevent/subscribe.c index 3fa9e2b..f326dd2 100644 --- a/src/sipevent/subscribe.c +++ b/src/sipevent/subscribe.c @@ -99,7 +99,7 @@ static void tmr_handler(void *arg) struct sipsub *sub = arg; int err; - if (sub->req) + if (sub->req || sub->terminated) return; err = request(sub, true); From f6bdc84b8001c8e2ad5d460cd335e3ebff75c9d5 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Fri, 16 Dec 2011 11:12:04 +0000 Subject: [PATCH 25/46] fixed refer header api --- include/re_sipevent.h | 7 +++---- src/sipevent/sipevent.h | 2 +- src/sipevent/subscribe.c | 38 ++++++++++++-------------------------- 3 files changed, 16 insertions(+), 31 deletions(-) diff --git a/include/re_sipevent.h b/include/re_sipevent.h index 979fed7..0812921 100644 --- a/include/re_sipevent.h +++ b/include/re_sipevent.h @@ -97,15 +97,14 @@ int sipevent_dsubscribe(struct sipsub **subp, struct sipevent_sock *sock, int sipevent_refer(struct sipsub **subp, struct sipevent_sock *sock, const char *uri, const char *from_name, - const char *from_uri, const char *refer_to, - const char *cuser, const char *routev[], uint32_t routec, + const char *from_uri, const char *cuser, + const char *routev[], uint32_t routec, sip_auth_h *authh, void *aarg, bool aref, sipevent_fork_h *forkh, sipevent_notify_h *notifyh, sipevent_close_h *closeh, void *arg, const char *fmt, ...); int sipevent_drefer(struct sipsub **subp, struct sipevent_sock *sock, - struct sip_dialog *dlg, const char *refer_to, - const char *cuser, + struct sip_dialog *dlg, const char *cuser, sip_auth_h *authh, void *aarg, bool aref, sipevent_notify_h *notifyh, sipevent_close_h *closeh, void *arg, const char *fmt, ...); diff --git a/src/sipevent/sipevent.h b/src/sipevent/sipevent.h index 7f51a0f..d3d122b 100644 --- a/src/sipevent/sipevent.h +++ b/src/sipevent/sipevent.h @@ -63,9 +63,9 @@ struct sipsub { struct sip *sip; char *event; char *id; - char *refer_to; char *cuser; char *hdrs; + char *refer_hdrs; sipevent_fork_h *forkh; sipevent_notify_h *notifyh; sipevent_close_h *closeh; diff --git a/src/sipevent/subscribe.c b/src/sipevent/subscribe.c index f326dd2..a871739 100644 --- a/src/sipevent/subscribe.c +++ b/src/sipevent/subscribe.c @@ -86,9 +86,9 @@ static void destructor(void *arg) mem_deref(sub->auth); mem_deref(sub->event); mem_deref(sub->id); - mem_deref(sub->refer_to); mem_deref(sub->cuser); mem_deref(sub->hdrs); + mem_deref(sub->refer_hdrs); mem_deref(sub->sock); mem_deref(sub->sip); } @@ -311,12 +311,10 @@ static int request(struct sipsub *sub, bool reset_ls) return sip_drequestf(&sub->req, sub->sip, true, "REFER", sub->dlg, 0, sub->auth, send_handler, response_handler, sub, - "Refer-To: %s\r\n" "%s" "Content-Length: 0\r\n" "\r\n", - sub->refer_to, - sub->hdrs); + sub->refer_hdrs); } else { return sip_drequestf(&sub->req, sub->sip, true, "SUBSCRIBE", @@ -338,7 +336,7 @@ static int sipsub_alloc(struct sipsub **subp, struct sipevent_sock *sock, bool refer, struct sip_dialog *dlg, const char *uri, const char *from_name, const char *from_uri, const char *event, const char *id, uint32_t expires, - const char *refer_to, const char *cuser, + const char *cuser, const char *routev[], uint32_t routec, sip_auth_h *authh, void *aarg, bool aref, sipevent_fork_h *forkh, sipevent_notify_h *notifyh, @@ -354,9 +352,6 @@ static int sipsub_alloc(struct sipsub **subp, struct sipevent_sock *sock, if (!dlg && (!uri || !from_uri)) return EINVAL; - if (refer && !refer_to) - return EINVAL; - sub = mem_zalloc(sizeof(*sub), destructor); if (!sub) return ENOMEM; @@ -389,19 +384,13 @@ static int sipsub_alloc(struct sipsub **subp, struct sipevent_sock *sock, goto out; } - if (refer_to) { - err = str_dup(&sub->refer_to, refer_to); - if (err) - goto out; - } - err = str_dup(&sub->cuser, cuser); if (err) goto out; - /* Custom SIP headers */ if (fmt) { - err = re_vsdprintf(&sub->hdrs, fmt, ap); + err = re_vsdprintf(refer ? &sub->refer_hdrs : &sub->hdrs, + fmt, ap); if (err) goto out; } @@ -470,7 +459,7 @@ int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, va_start(ap, fmt); err = sipsub_alloc(subp, sock, false, NULL, uri, from_name, from_uri, - event, id, expires, NULL, cuser, + event, id, expires, cuser, routev, routec, authh, aarg, aref, forkh, notifyh, closeh, arg, fmt, ap); va_end(ap); @@ -511,7 +500,7 @@ int sipevent_dsubscribe(struct sipsub **subp, struct sipevent_sock *sock, va_start(ap, fmt); err = sipsub_alloc(subp, sock, false, dlg, NULL, NULL, NULL, - event, id, expires, NULL, cuser, + event, id, expires, cuser, NULL, 0, authh, aarg, aref, NULL, notifyh, closeh, arg, fmt, ap); va_end(ap); @@ -528,7 +517,6 @@ int sipevent_dsubscribe(struct sipsub **subp, struct sipevent_sock *sock, * @param uri SIP Request URI * @param from_name SIP From-header Name (optional) * @param from_uri SIP From-header URI - * @param refer_to Refer-To address * @param cuser Contact username * @param routev Optional route vector * @param routec Number of routes @@ -545,8 +533,8 @@ int sipevent_dsubscribe(struct sipsub **subp, struct sipevent_sock *sock, */ int sipevent_refer(struct sipsub **subp, struct sipevent_sock *sock, const char *uri, const char *from_name, - const char *from_uri, const char *refer_to, - const char *cuser, const char *routev[], uint32_t routec, + const char *from_uri, const char *cuser, + const char *routev[], uint32_t routec, sip_auth_h *authh, void *aarg, bool aref, sipevent_fork_h *forkh, sipevent_notify_h *notifyh, sipevent_close_h *closeh, void *arg, @@ -557,7 +545,7 @@ int sipevent_refer(struct sipsub **subp, struct sipevent_sock *sock, va_start(ap, fmt); err = sipsub_alloc(subp, sock, true, NULL, uri, from_name, from_uri, - "refer", NULL, DEFAULT_EXPIRES, refer_to, cuser, + "refer", NULL, DEFAULT_EXPIRES, cuser, routev, routec, authh, aarg, aref, forkh, notifyh, closeh, arg, fmt, ap); va_end(ap); @@ -572,7 +560,6 @@ int sipevent_refer(struct sipsub **subp, struct sipevent_sock *sock, * @param subp Pointer to allocated SIP subscriber client * @param sock SIP Event socket * @param dlg Established SIP Dialog - * @param refer_to Refer-To address * @param cuser Contact username * @param authh Authentication handler * @param aarg Authentication handler argument @@ -585,8 +572,7 @@ int sipevent_refer(struct sipsub **subp, struct sipevent_sock *sock, * @return 0 if success, otherwise errorcode */ int sipevent_drefer(struct sipsub **subp, struct sipevent_sock *sock, - struct sip_dialog *dlg, const char *refer_to, - const char *cuser, + struct sip_dialog *dlg, const char *cuser, sip_auth_h *authh, void *aarg, bool aref, sipevent_notify_h *notifyh, sipevent_close_h *closeh, void *arg, const char *fmt, ...) @@ -596,7 +582,7 @@ int sipevent_drefer(struct sipsub **subp, struct sipevent_sock *sock, va_start(ap, fmt); err = sipsub_alloc(subp, sock, true, dlg, NULL, NULL, NULL, - "refer", NULL, DEFAULT_EXPIRES, refer_to, cuser, + "refer", NULL, DEFAULT_EXPIRES, cuser, NULL, 0, authh, aarg, aref, NULL, notifyh, closeh, arg, fmt, ap); va_end(ap); From aefada5c8112db5303a0d6f5cd05d870443391cb Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Fri, 16 Dec 2011 11:41:46 +0000 Subject: [PATCH 26/46] expires_min option --- include/re_sipevent.h | 5 +++-- src/sipevent/listen.c | 19 ++++++++++++++----- src/sipevent/notify.c | 8 +++++--- src/sipevent/sipevent.h | 1 + 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/include/re_sipevent.h b/include/re_sipevent.h index 0812921..8f60470 100644 --- a/include/re_sipevent.h +++ b/include/re_sipevent.h @@ -60,8 +60,9 @@ typedef void (sipevent_close_h)(int err, const struct sip_msg *msg, void *arg); int sipevent_accept(struct sipnot **notp, struct sipevent_sock *sock, const struct sip_msg *msg, struct sip_dialog *dlg, const struct sipevent_event *event, - uint16_t scode, const char *reason, uint32_t expires_dfl, - uint32_t expires_max, const char *cuser, const char *ctype, + uint16_t scode, const char *reason, uint32_t expires_min, + uint32_t expires_dfl, uint32_t expires_max, + const char *cuser, const char *ctype, sip_auth_h *authh, void *aarg, bool aref, sipevent_close_h *closeh, void *arg, const char *fmt, ...); int sipevent_notify(struct sipnot *not, struct mbuf *mb, bool term, diff --git a/src/sipevent/listen.c b/src/sipevent/listen.c index a4b6434..2224728 100644 --- a/src/sipevent/listen.c +++ b/src/sipevent/listen.c @@ -254,6 +254,20 @@ static void subscribe_handler(struct sipevent_sock *sock, return; } + if (pl_isset(&msg->expires)) + expires = pl_u32(&msg->expires); + else + expires = not->expires_dfl; + + if (expires > 0 && expires < not->expires_min) { + (void)sip_replyf(sip, msg, 423, "Interval Too Brief", + "Min-Expires: %u\r\n" + "Content-Length: 0\r\n" + "\r\n", + not->expires_min); + return; + } + if (!sip_dialog_rseq_valid(not->dlg, msg)) { (void)sip_reply(sip, msg, 500, "Bad Sequence"); return; @@ -261,11 +275,6 @@ static void subscribe_handler(struct sipevent_sock *sock, (void)sip_dialog_update(not->dlg, msg); - if (pl_isset(&msg->expires)) - expires = pl_u32(&msg->expires); - else - expires = not->expires_dfl; - sipnot_refresh(not, expires); (void)sipnot_reply(not, msg, 200, "OK"); diff --git a/src/sipevent/notify.c b/src/sipevent/notify.c index d86dc23..9fb716a 100644 --- a/src/sipevent/notify.c +++ b/src/sipevent/notify.c @@ -293,8 +293,9 @@ int sipnot_reply(struct sipnot *not, const struct sip_msg *msg, int sipevent_accept(struct sipnot **notp, struct sipevent_sock *sock, const struct sip_msg *msg, struct sip_dialog *dlg, const struct sipevent_event *event, - uint16_t scode, const char *reason, uint32_t expires_dfl, - uint32_t expires_max, const char *cuser, const char *ctype, + uint16_t scode, const char *reason, uint32_t expires_min, + uint32_t expires_dfl, uint32_t expires_max, + const char *cuser, const char *ctype, sip_auth_h *authh, void *aarg, bool aref, sipevent_close_h *closeh, void *arg, const char *fmt, ...) { @@ -303,7 +304,7 @@ int sipevent_accept(struct sipnot **notp, struct sipevent_sock *sock, int err; if (!notp || !sock || !msg || !scode || !reason || !expires_dfl || - !expires_max || !cuser || !ctype) + !expires_max || !cuser || !ctype || expires_dfl < expires_min) return EINVAL; not = mem_zalloc(sizeof(*not), destructor); @@ -373,6 +374,7 @@ int sipevent_accept(struct sipnot **notp, struct sipevent_sock *sock, goto out; } + not->expires_min = expires_min; not->expires_dfl = expires_dfl; not->expires_max = expires_max; not->sock = mem_ref(sock); diff --git a/src/sipevent/sipevent.h b/src/sipevent/sipevent.h index d3d122b..1fdef5f 100644 --- a/src/sipevent/sipevent.h +++ b/src/sipevent/sipevent.h @@ -35,6 +35,7 @@ struct sipnot { char *ctype; sipevent_close_h *closeh; void *arg; + uint32_t expires_min; uint32_t expires_dfl; uint32_t expires_max; enum sipevent_reason reason; From ea52ebc9f46e06a0672d62f2ad24e999e631eebc Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Fri, 16 Dec 2011 12:41:32 +0000 Subject: [PATCH 27/46] timeout and all error responses removes a notifier subscription --- src/sipevent/notify.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/sipevent/notify.c b/src/sipevent/notify.c index 9fb716a..3371155 100644 --- a/src/sipevent/notify.c +++ b/src/sipevent/notify.c @@ -127,8 +127,16 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) else re_printf("notify reply: %u %r\n", msg->scode, &msg->reason); - if (err || sip_request_loops(¬->ls, msg->scode)) + if (err) { + if (err == ETIMEDOUT) + not->subscribed = false; goto out; + } + + if (sip_request_loops(¬->ls, msg->scode)) { + not->subscribed = false; + goto out; + } if (msg->scode < 200) { return; @@ -153,15 +161,9 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) break; return; - - case 403: - sip_auth_reset(not->auth); - break; - - case 481: - not->subscribed = false; - break; } + + not->subscribed = false; } out: From f9a2aa88a4723c701c25390f70d55930a91c6cea Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Fri, 16 Dec 2011 13:26:10 +0000 Subject: [PATCH 28/46] handle notify replies internally --- include/re_sipevent.h | 3 +-- src/sipevent/listen.c | 10 ++++------ src/sipevent/subscribe.c | 6 ++---- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/include/re_sipevent.h b/include/re_sipevent.h index 8f60470..fdd7503 100644 --- a/include/re_sipevent.h +++ b/include/re_sipevent.h @@ -77,8 +77,7 @@ struct sipsub; typedef int (sipevent_fork_h)(struct sipsub **subp, struct sipsub *osub, const struct sip_msg *msg, void *arg); -typedef void (sipevent_notify_h)(struct sip *sip, const struct sip_msg *msg, - void *arg); +typedef void (sipevent_notify_h)(const struct sip_msg *msg, void *arg); int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, const char *uri, const char *from_name, diff --git a/src/sipevent/listen.c b/src/sipevent/listen.c index 2224728..c18a835 100644 --- a/src/sipevent/listen.c +++ b/src/sipevent/listen.c @@ -192,13 +192,11 @@ static void notify_handler(struct sipevent_sock *sock, (void)sip_dialog_update(sub->dlg, msg); } + (void)sip_treply(NULL, sip, msg, 200, "OK"); + if (sub->refer_cseq >= 0 && !sub->id && pl_isset(&event.id)) { - err = pl_strdup(&sub->id, &event.id); - if (err) { - (void)sip_treply(NULL, sip, msg, 500, strerror(err)); - return; - } + (void)pl_strdup(&sub->id, &event.id); } re_printf("notify: %s (%r)\n", sipevent_substate_name(state.state), @@ -220,7 +218,7 @@ static void notify_handler(struct sipevent_sock *sock, } mem_ref(sub); - sub->notifyh(sip, msg, sub->arg); + sub->notifyh(msg, sub->arg); nrefs = mem_nrefs(sub); mem_deref(sub); diff --git a/src/sipevent/subscribe.c b/src/sipevent/subscribe.c index a871739..e650da9 100644 --- a/src/sipevent/subscribe.c +++ b/src/sipevent/subscribe.c @@ -29,12 +29,10 @@ enum { static int request(struct sipsub *sub, bool reset_ls); -static void internal_notify_handler(struct sip *sip, const struct sip_msg *msg, - void *arg) +static void internal_notify_handler(const struct sip_msg *msg, void *arg) { + (void)msg; (void)arg; - - (void)sip_treply(NULL, sip, msg, 200, "OK"); } From a6eaa8c12122886f6ab09a459a0ddbb8d6e925e2 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Fri, 16 Dec 2011 13:37:52 +0000 Subject: [PATCH 29/46] avoid calling notify handler if terminated --- src/sipevent/listen.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sipevent/listen.c b/src/sipevent/listen.c index c18a835..3c93f0e 100644 --- a/src/sipevent/listen.c +++ b/src/sipevent/listen.c @@ -217,6 +217,9 @@ static void notify_handler(struct sipevent_sock *sock, break; } + if (sub->terminated) + return; + mem_ref(sub); sub->notifyh(msg, sub->arg); nrefs = mem_nrefs(sub); @@ -226,7 +229,7 @@ static void notify_handler(struct sipevent_sock *sock, if (nrefs == 1) return; - if (!sub->terminated && state.state == SIPEVENT_TERMINATED) + if (state.state == SIPEVENT_TERMINATED) sipsub_terminate(sub, 0, msg); } From 8d3f5dd257c4db759335f2c939cbfee66de29535 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Fri, 16 Dec 2011 13:44:15 +0000 Subject: [PATCH 30/46] revert previous patch --- src/sipevent/listen.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/sipevent/listen.c b/src/sipevent/listen.c index 3c93f0e..c18a835 100644 --- a/src/sipevent/listen.c +++ b/src/sipevent/listen.c @@ -217,9 +217,6 @@ static void notify_handler(struct sipevent_sock *sock, break; } - if (sub->terminated) - return; - mem_ref(sub); sub->notifyh(msg, sub->arg); nrefs = mem_nrefs(sub); @@ -229,7 +226,7 @@ static void notify_handler(struct sipevent_sock *sock, if (nrefs == 1) return; - if (state.state == SIPEVENT_TERMINATED) + if (!sub->terminated && state.state == SIPEVENT_TERMINATED) sipsub_terminate(sub, 0, msg); } From 1a346cbd6e0d3ae050081923b7c415235bf74e3f Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Fri, 16 Dec 2011 13:56:03 +0000 Subject: [PATCH 31/46] avoid calling notify handler if terminated --- src/sipevent/listen.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sipevent/listen.c b/src/sipevent/listen.c index c18a835..b2d4e78 100644 --- a/src/sipevent/listen.c +++ b/src/sipevent/listen.c @@ -217,6 +217,9 @@ static void notify_handler(struct sipevent_sock *sock, break; } + if (sub->terminated) + return; + mem_ref(sub); sub->notifyh(msg, sub->arg); nrefs = mem_nrefs(sub); From fd6c3251f80f5bfa0609a093ae5d8e45de23f3d7 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Fri, 16 Dec 2011 14:51:28 +0000 Subject: [PATCH 32/46] set substate based on mb --- src/sipevent/notify.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sipevent/notify.c b/src/sipevent/notify.c index 3371155..74b4d8c 100644 --- a/src/sipevent/notify.c +++ b/src/sipevent/notify.c @@ -215,7 +215,9 @@ static int print_substate(struct re_printf *pf, const struct sipnot *not) expires = (uint32_t)(tmr_get_expire(¬->tmr) / 1000); - return re_hprintf(pf, "active;expires=%u", expires); + return re_hprintf(pf, "%s;expires=%u", + not->mb ? "active" : "pending", + expires); } } From 59145608c6e020ea1e623703317b1be230244ea9 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Fri, 16 Dec 2011 16:37:55 +0000 Subject: [PATCH 33/46] revert previous stuff --- include/re_sipevent.h | 3 ++- src/sipevent/listen.c | 13 ++++++------- src/sipevent/subscribe.c | 6 ++++-- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/include/re_sipevent.h b/include/re_sipevent.h index fdd7503..8f60470 100644 --- a/include/re_sipevent.h +++ b/include/re_sipevent.h @@ -77,7 +77,8 @@ struct sipsub; typedef int (sipevent_fork_h)(struct sipsub **subp, struct sipsub *osub, const struct sip_msg *msg, void *arg); -typedef void (sipevent_notify_h)(const struct sip_msg *msg, void *arg); +typedef void (sipevent_notify_h)(struct sip *sip, const struct sip_msg *msg, + void *arg); int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, const char *uri, const char *from_name, diff --git a/src/sipevent/listen.c b/src/sipevent/listen.c index b2d4e78..2224728 100644 --- a/src/sipevent/listen.c +++ b/src/sipevent/listen.c @@ -192,11 +192,13 @@ static void notify_handler(struct sipevent_sock *sock, (void)sip_dialog_update(sub->dlg, msg); } - (void)sip_treply(NULL, sip, msg, 200, "OK"); - if (sub->refer_cseq >= 0 && !sub->id && pl_isset(&event.id)) { - (void)pl_strdup(&sub->id, &event.id); + err = pl_strdup(&sub->id, &event.id); + if (err) { + (void)sip_treply(NULL, sip, msg, 500, strerror(err)); + return; + } } re_printf("notify: %s (%r)\n", sipevent_substate_name(state.state), @@ -217,11 +219,8 @@ static void notify_handler(struct sipevent_sock *sock, break; } - if (sub->terminated) - return; - mem_ref(sub); - sub->notifyh(msg, sub->arg); + sub->notifyh(sip, msg, sub->arg); nrefs = mem_nrefs(sub); mem_deref(sub); diff --git a/src/sipevent/subscribe.c b/src/sipevent/subscribe.c index e650da9..a871739 100644 --- a/src/sipevent/subscribe.c +++ b/src/sipevent/subscribe.c @@ -29,10 +29,12 @@ enum { static int request(struct sipsub *sub, bool reset_ls); -static void internal_notify_handler(const struct sip_msg *msg, void *arg) +static void internal_notify_handler(struct sip *sip, const struct sip_msg *msg, + void *arg) { - (void)msg; (void)arg; + + (void)sip_treply(NULL, sip, msg, 200, "OK"); } From eb955d3d82319f4bf655ca5c70b2874f7dc17e4e Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Fri, 16 Dec 2011 17:33:02 +0000 Subject: [PATCH 34/46] notify: substate and retry-after --- include/re_sipevent.h | 10 +++++---- src/sipevent/notify.c | 50 ++++++++++++++++++++++++++++------------- src/sipevent/sipevent.h | 2 ++ 3 files changed, 43 insertions(+), 19 deletions(-) diff --git a/include/re_sipevent.h b/include/re_sipevent.h index 8f60470..bf6215e 100644 --- a/include/re_sipevent.h +++ b/include/re_sipevent.h @@ -65,10 +65,12 @@ int sipevent_accept(struct sipnot **notp, struct sipevent_sock *sock, const char *cuser, const char *ctype, sip_auth_h *authh, void *aarg, bool aref, sipevent_close_h *closeh, void *arg, const char *fmt, ...); -int sipevent_notify(struct sipnot *not, struct mbuf *mb, bool term, - enum sipevent_reason reason); -int sipevent_notifyf(struct sipnot *not, struct mbuf **mbp, bool term, - enum sipevent_reason reason, const char *fmt, ...); +int sipevent_notify(struct sipnot *not, struct mbuf *mb, + enum sipevent_subst state, enum sipevent_reason reason, + uint32_t retry_after); +int sipevent_notifyf(struct sipnot *not, struct mbuf **mbp, + enum sipevent_subst state, enum sipevent_reason reason, + uint32_t retry_after, const char *fmt, ...); /* Subscriber */ diff --git a/src/sipevent/notify.c b/src/sipevent/notify.c index 74b4d8c..9160355 100644 --- a/src/sipevent/notify.c +++ b/src/sipevent/notify.c @@ -206,19 +206,28 @@ static int print_event(struct re_printf *pf, const struct sipnot *not) static int print_substate(struct re_printf *pf, const struct sipnot *not) { + int err; + if (not->terminated) { - return re_hprintf(pf, "terminated;reason=%s", - sipevent_reason_name(not->reason)); + + err = re_hprintf(pf, "terminated;reason=%s", + sipevent_reason_name(not->reason)); + + if (not->retry_after) + err |= re_hprintf(pf, ";retry-after=%u", + not->retry_after); } else { uint32_t expires; expires = (uint32_t)(tmr_get_expire(¬->tmr) / 1000); - return re_hprintf(pf, "%s;expires=%u", - not->mb ? "active" : "pending", - expires); + err = re_hprintf(pf, "%s;expires=%u", + sipevent_substate_name(not->substate), + expires); } + + return err; } @@ -409,29 +418,40 @@ int sipevent_accept(struct sipnot **notp, struct sipevent_sock *sock, } -int sipevent_notify(struct sipnot *not, struct mbuf *mb, bool term, - enum sipevent_reason reason) +int sipevent_notify(struct sipnot *not, struct mbuf *mb, + enum sipevent_subst state, enum sipevent_reason reason, + uint32_t retry_after) { if (!not || not->terminated) return EINVAL; - if (mb || !term) { + if (mb || state != SIPEVENT_TERMINATED) { mem_deref(not->mb); not->mb = mem_ref(mb); } - if (term) { + switch (state) { + + case SIPEVENT_ACTIVE: + case SIPEVENT_PENDING: + not->substate = state; + return sipnot_notify(not); + + case SIPEVENT_TERMINATED: tmr_cancel(¬->tmr); + not->retry_after = retry_after; (void)terminate(not, reason); return 0; - } - return sipnot_notify(not); + default: + return EINVAL; + } } -int sipevent_notifyf(struct sipnot *not, struct mbuf **mbp, bool term, - enum sipevent_reason reason, const char *fmt, ...) +int sipevent_notifyf(struct sipnot *not, struct mbuf **mbp, + enum sipevent_subst state, enum sipevent_reason reason, + uint32_t retry_after, const char *fmt, ...) { struct mbuf *mb; va_list ap; @@ -441,7 +461,7 @@ int sipevent_notifyf(struct sipnot *not, struct mbuf **mbp, bool term, return EINVAL; if (mbp && *mbp) - return sipevent_notify(not, *mbp, term, reason); + return sipevent_notify(not, *mbp, state, reason, retry_after); mb = mbuf_alloc(1024); if (!mb) @@ -455,7 +475,7 @@ int sipevent_notifyf(struct sipnot *not, struct mbuf **mbp, bool term, mb->pos = 0; - err = sipevent_notify(not, mb, term, reason); + err = sipevent_notify(not, mb, state, reason, retry_after); if (err) goto out; diff --git a/src/sipevent/sipevent.h b/src/sipevent/sipevent.h index 1fdef5f..189590c 100644 --- a/src/sipevent/sipevent.h +++ b/src/sipevent/sipevent.h @@ -38,6 +38,8 @@ struct sipnot { uint32_t expires_min; uint32_t expires_dfl; uint32_t expires_max; + uint32_t retry_after; + enum sipevent_subst substate; enum sipevent_reason reason; bool notify_pending; bool subscribed; From 25dcee759c5d145e9955efeaefcfb2b677b3dbb6 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Fri, 16 Dec 2011 17:37:05 +0000 Subject: [PATCH 35/46] init substate --- src/sipevent/notify.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sipevent/notify.c b/src/sipevent/notify.c index 9160355..8c2fbf1 100644 --- a/src/sipevent/notify.c +++ b/src/sipevent/notify.c @@ -390,6 +390,7 @@ int sipevent_accept(struct sipnot **notp, struct sipevent_sock *sock, not->expires_min = expires_min; not->expires_dfl = expires_dfl; not->expires_max = expires_max; + not->substate = SIPEVENT_PENDING; not->sock = mem_ref(sock); not->sip = mem_ref(sock->sip); not->closeh = closeh ? closeh : internal_close_handler; From 91b33112e9eb08408d12369bc2da543a2483fc42 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Sat, 17 Dec 2011 07:25:24 +0000 Subject: [PATCH 36/46] send notify at timeout only when expires is 0 --- src/sipevent/listen.c | 4 +--- src/sipevent/notify.c | 11 ++++++++--- src/sipevent/sipevent.h | 1 + 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/sipevent/listen.c b/src/sipevent/listen.c index 2224728..6f858b9 100644 --- a/src/sipevent/listen.c +++ b/src/sipevent/listen.c @@ -279,9 +279,7 @@ static void subscribe_handler(struct sipevent_sock *sock, (void)sipnot_reply(not, msg, 200, "OK"); - if (expires > 0) { - (void)sipnot_notify(not); - } + (void)sipnot_notify(not); } diff --git a/src/sipevent/notify.c b/src/sipevent/notify.c index 8c2fbf1..fa3fc0f 100644 --- a/src/sipevent/notify.c +++ b/src/sipevent/notify.c @@ -110,11 +110,11 @@ static void tmr_handler(void *arg) void sipnot_refresh(struct sipnot *not, uint32_t expires) { - expires = min(expires, not->expires_max); + not->expires = min(expires, not->expires_max); - re_printf("will expire in %u secs\n", expires); + re_printf("will expire in %u secs\n", not->expires); - tmr_start(¬->tmr, expires * 1000, tmr_handler, not); + tmr_start(¬->tmr, not->expires * 1000, tmr_handler, not); } @@ -276,6 +276,11 @@ static int notify_request(struct sipnot *not, bool reset_ls) int sipnot_notify(struct sipnot *not) { + if (not->expires == 0) { + re_printf("NOTIFY will be sent at timeout\n"); + return 0; + } + if (not->req) { re_printf("waiting for previous request to complete\n"); not->notify_pending = true; diff --git a/src/sipevent/sipevent.h b/src/sipevent/sipevent.h index 189590c..85a2a97 100644 --- a/src/sipevent/sipevent.h +++ b/src/sipevent/sipevent.h @@ -35,6 +35,7 @@ struct sipnot { char *ctype; sipevent_close_h *closeh; void *arg; + uint32_t expires; uint32_t expires_min; uint32_t expires_dfl; uint32_t expires_max; From c1803bd705cb162dabab227f46b58e4ed0723e7e Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Mon, 19 Dec 2011 07:30:33 +0000 Subject: [PATCH 37/46] propagate terminate substate --- include/re_sipevent.h | 11 ++++++----- src/sipevent/listen.c | 2 +- src/sipevent/msg.c | 24 ++++++++++++++++++++---- src/sipevent/notify.c | 6 +++--- src/sipevent/sipevent.h | 5 +++-- src/sipevent/subscribe.c | 11 +++++++---- 6 files changed, 40 insertions(+), 19 deletions(-) diff --git a/include/re_sipevent.h b/include/re_sipevent.h index bf6215e..1d7da58 100644 --- a/include/re_sipevent.h +++ b/include/re_sipevent.h @@ -30,9 +30,9 @@ enum sipevent_reason { struct sipevent_substate { enum sipevent_subst state; - struct pl params; + enum sipevent_reason reason; struct pl expires; - struct pl reason; + struct pl params; }; int sipevent_event_decode(struct sipevent_event *se, const struct pl *pl); @@ -55,8 +55,6 @@ int sipevent_listen(struct sipevent_sock **sockp, struct sip *sip, struct sipnot; -typedef void (sipevent_close_h)(int err, const struct sip_msg *msg, void *arg); - int sipevent_accept(struct sipnot **notp, struct sipevent_sock *sock, const struct sip_msg *msg, struct sip_dialog *dlg, const struct sipevent_event *event, @@ -64,7 +62,7 @@ int sipevent_accept(struct sipnot **notp, struct sipevent_sock *sock, uint32_t expires_dfl, uint32_t expires_max, const char *cuser, const char *ctype, sip_auth_h *authh, void *aarg, bool aref, - sipevent_close_h *closeh, void *arg, const char *fmt, ...); + sip_resp_h *closeh, void *arg, const char *fmt, ...); int sipevent_notify(struct sipnot *not, struct mbuf *mb, enum sipevent_subst state, enum sipevent_reason reason, uint32_t retry_after); @@ -81,6 +79,9 @@ typedef int (sipevent_fork_h)(struct sipsub **subp, struct sipsub *osub, const struct sip_msg *msg, void *arg); typedef void (sipevent_notify_h)(struct sip *sip, const struct sip_msg *msg, void *arg); +typedef void (sipevent_close_h)(int err, const struct sip_msg *msg, + const struct sipevent_substate *substate, + void *arg); int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, const char *uri, const char *from_name, diff --git a/src/sipevent/listen.c b/src/sipevent/listen.c index 6f858b9..ca66dfc 100644 --- a/src/sipevent/listen.c +++ b/src/sipevent/listen.c @@ -229,7 +229,7 @@ static void notify_handler(struct sipevent_sock *sock, return; if (!sub->terminated && state.state == SIPEVENT_TERMINATED) - sipsub_terminate(sub, 0, msg); + sipsub_terminate(sub, 0, msg, &state); } diff --git a/src/sipevent/msg.c b/src/sipevent/msg.c index 4ee2bb9..b96d53e 100644 --- a/src/sipevent/msg.c +++ b/src/sipevent/msg.c @@ -62,10 +62,26 @@ int sipevent_substate_decode(struct sipevent_substate *ss, const struct pl *pl) else ss->expires = pl_null; - if (!sip_param_decode(&ss->params, "reason", ¶m)) - ss->reason = param; - else - ss->reason = pl_null; + if (!sip_param_decode(&ss->params, "reason", ¶m)) { + + if (!pl_strcasecmp(¶m, "deactivated")) + ss->reason = SIPEVENT_DEACTIVATED; + else if (!pl_strcasecmp(¶m, "probation")) + ss->reason = SIPEVENT_PROBATION; + else if (!pl_strcasecmp(¶m, "rejected")) + ss->reason = SIPEVENT_REJECTED; + else if (!pl_strcasecmp(¶m, "timeout")) + ss->reason = SIPEVENT_TIMEOUT; + else if (!pl_strcasecmp(¶m, "giveup")) + ss->reason = SIPEVENT_GIVEUP; + else if (!pl_strcasecmp(¶m, "noresource")) + ss->reason = SIPEVENT_NORESOURCE; + else + ss->reason = -1; + } + else { + ss->reason = -1; + } return 0; } diff --git a/src/sipevent/notify.c b/src/sipevent/notify.c index fa3fc0f..fef80b2 100644 --- a/src/sipevent/notify.c +++ b/src/sipevent/notify.c @@ -59,7 +59,7 @@ static void destructor(void *arg) if (!not->terminated) { - if (terminate(not, SIPEVENT_NORESOURCE)) + if (terminate(not, SIPEVENT_DEACTIVATED)) return; } @@ -82,7 +82,7 @@ static void sipnot_terminate(struct sipnot *not, int err, const struct sip_msg *msg, enum sipevent_reason reason) { - sipevent_close_h *closeh; + sip_resp_h *closeh; void *arg; closeh = not->closeh; @@ -315,7 +315,7 @@ int sipevent_accept(struct sipnot **notp, struct sipevent_sock *sock, uint32_t expires_dfl, uint32_t expires_max, const char *cuser, const char *ctype, sip_auth_h *authh, void *aarg, bool aref, - sipevent_close_h *closeh, void *arg, const char *fmt, ...) + sip_resp_h *closeh, void *arg, const char *fmt, ...) { struct sipnot *not; uint32_t expires; diff --git a/src/sipevent/sipevent.h b/src/sipevent/sipevent.h index 85a2a97..8a6e848 100644 --- a/src/sipevent/sipevent.h +++ b/src/sipevent/sipevent.h @@ -33,7 +33,7 @@ struct sipnot { char *cuser; char *hdrs; char *ctype; - sipevent_close_h *closeh; + sip_resp_h *closeh; void *arg; uint32_t expires; uint32_t expires_min; @@ -86,4 +86,5 @@ struct sipsub *sipsub_find(struct sipevent_sock *sock, const struct sip_msg *msg, const struct sipevent_event *evt, bool full); void sipsub_reschedule(struct sipsub *sub, uint64_t wait); -void sipsub_terminate(struct sipsub *sub, int err, const struct sip_msg *msg); +void sipsub_terminate(struct sipsub *sub, int err, const struct sip_msg *msg, + const struct sipevent_substate *substate); diff --git a/src/sipevent/subscribe.c b/src/sipevent/subscribe.c index a871739..9b71516 100644 --- a/src/sipevent/subscribe.c +++ b/src/sipevent/subscribe.c @@ -39,10 +39,12 @@ static void internal_notify_handler(struct sip *sip, const struct sip_msg *msg, static void internal_close_handler(int err, const struct sip_msg *msg, + const struct sipevent_substate *substate, void *arg) { (void)err; (void)msg; + (void)substate; (void)arg; } @@ -108,7 +110,7 @@ static void tmr_handler(void *arg) sipsub_reschedule(sub, RESUB_FAIL_WAIT); } else { - sipsub_terminate(sub, err, NULL); + sipsub_terminate(sub, err, NULL, NULL); } } } @@ -122,7 +124,8 @@ void sipsub_reschedule(struct sipsub *sub, uint64_t wait) } -void sipsub_terminate(struct sipsub *sub, int err, const struct sip_msg *msg) +void sipsub_terminate(struct sipsub *sub, int err, const struct sip_msg *msg, + const struct sipevent_substate *substate) { sipevent_close_h *closeh; void *arg; @@ -133,7 +136,7 @@ void sipsub_terminate(struct sipsub *sub, int err, const struct sip_msg *msg) tmr_cancel(&sub->tmr); (void)terminate(sub); - closeh(err, msg, arg); + closeh(err, msg, substate, arg); } @@ -271,7 +274,7 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) if (sub->subscribed && ++sub->failc < RESUB_FAILC_MAX) sipsub_reschedule(sub, RESUB_FAIL_WAIT); else - sipsub_terminate(sub, err, msg); + sipsub_terminate(sub, err, msg, NULL); } } From 0178526e7041cacc6fa71b0f1206a9f054d4bf41 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Mon, 19 Dec 2011 11:50:38 +0000 Subject: [PATCH 38/46] added parsing of substate/retry-after --- include/re_sipevent.h | 1 + src/sipevent/msg.c | 15 ++++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/include/re_sipevent.h b/include/re_sipevent.h index 1d7da58..0fb0528 100644 --- a/include/re_sipevent.h +++ b/include/re_sipevent.h @@ -32,6 +32,7 @@ struct sipevent_substate { enum sipevent_subst state; enum sipevent_reason reason; struct pl expires; + struct pl retry_after; struct pl params; }; diff --git a/src/sipevent/msg.c b/src/sipevent/msg.c index b96d53e..9b61137 100644 --- a/src/sipevent/msg.c +++ b/src/sipevent/msg.c @@ -57,11 +57,6 @@ int sipevent_substate_decode(struct sipevent_substate *ss, const struct pl *pl) else ss->state = -1; - if (!sip_param_decode(&ss->params, "expires", ¶m)) - ss->expires = param; - else - ss->expires = pl_null; - if (!sip_param_decode(&ss->params, "reason", ¶m)) { if (!pl_strcasecmp(¶m, "deactivated")) @@ -83,6 +78,16 @@ int sipevent_substate_decode(struct sipevent_substate *ss, const struct pl *pl) ss->reason = -1; } + if (!sip_param_decode(&ss->params, "expires", ¶m)) + ss->expires = param; + else + ss->expires = pl_null; + + if (!sip_param_decode(&ss->params, "retry-after", ¶m)) + ss->retry_after = param; + else + ss->retry_after = pl_null; + return 0; } From ea664bbf7f8951407c7b5e3a8981ece3804d1b4a Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Mon, 19 Dec 2011 12:28:37 +0000 Subject: [PATCH 39/46] fixed handler naming --- include/re_sipevent.h | 32 +++++++++++++++++--------------- src/sipevent/notify.c | 4 ++-- src/sipevent/sipevent.h | 8 ++++---- src/sipevent/subscribe.c | 20 ++++++++++---------- 4 files changed, 33 insertions(+), 31 deletions(-) diff --git a/include/re_sipevent.h b/include/re_sipevent.h index 0fb0528..6e680ce 100644 --- a/include/re_sipevent.h +++ b/include/re_sipevent.h @@ -56,6 +56,8 @@ int sipevent_listen(struct sipevent_sock **sockp, struct sip *sip, struct sipnot; +typedef void (sipnot_close_h)(int err, const struct sip_msg *msg, void *arg); + int sipevent_accept(struct sipnot **notp, struct sipevent_sock *sock, const struct sip_msg *msg, struct sip_dialog *dlg, const struct sipevent_event *event, @@ -63,7 +65,7 @@ int sipevent_accept(struct sipnot **notp, struct sipevent_sock *sock, uint32_t expires_dfl, uint32_t expires_max, const char *cuser, const char *ctype, sip_auth_h *authh, void *aarg, bool aref, - sip_resp_h *closeh, void *arg, const char *fmt, ...); + sipnot_close_h *closeh, void *arg, const char *fmt, ...); int sipevent_notify(struct sipnot *not, struct mbuf *mb, enum sipevent_subst state, enum sipevent_reason reason, uint32_t retry_after); @@ -76,13 +78,13 @@ int sipevent_notifyf(struct sipnot *not, struct mbuf **mbp, struct sipsub; -typedef int (sipevent_fork_h)(struct sipsub **subp, struct sipsub *osub, - const struct sip_msg *msg, void *arg); -typedef void (sipevent_notify_h)(struct sip *sip, const struct sip_msg *msg, - void *arg); -typedef void (sipevent_close_h)(int err, const struct sip_msg *msg, - const struct sipevent_substate *substate, - void *arg); +typedef int (sipsub_fork_h)(struct sipsub **subp, struct sipsub *osub, + const struct sip_msg *msg, void *arg); +typedef void (sipsub_notify_h)(struct sip *sip, const struct sip_msg *msg, + void *arg); +typedef void (sipsub_close_h)(int err, const struct sip_msg *msg, + const struct sipevent_substate *substate, + void *arg); int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, const char *uri, const char *from_name, @@ -90,14 +92,14 @@ int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, uint32_t expires, const char *cuser, const char *routev[], uint32_t routec, sip_auth_h *authh, void *aarg, bool aref, - sipevent_fork_h *forkh, sipevent_notify_h *notifyh, - sipevent_close_h *closeh, void *arg, + sipsub_fork_h *forkh, sipsub_notify_h *notifyh, + sipsub_close_h *closeh, void *arg, const char *fmt, ...); int sipevent_dsubscribe(struct sipsub **subp, struct sipevent_sock *sock, struct sip_dialog *dlg, const char *event, const char *id, uint32_t expires, const char *cuser, sip_auth_h *authh, void *aarg, bool aref, - sipevent_notify_h *notifyh, sipevent_close_h *closeh, + sipsub_notify_h *notifyh, sipsub_close_h *closeh, void *arg, const char *fmt, ...); int sipevent_refer(struct sipsub **subp, struct sipevent_sock *sock, @@ -105,17 +107,17 @@ int sipevent_refer(struct sipsub **subp, struct sipevent_sock *sock, const char *from_uri, const char *cuser, const char *routev[], uint32_t routec, sip_auth_h *authh, void *aarg, bool aref, - sipevent_fork_h *forkh, sipevent_notify_h *notifyh, - sipevent_close_h *closeh, void *arg, + sipsub_fork_h *forkh, sipsub_notify_h *notifyh, + sipsub_close_h *closeh, void *arg, const char *fmt, ...); int sipevent_drefer(struct sipsub **subp, struct sipevent_sock *sock, struct sip_dialog *dlg, const char *cuser, sip_auth_h *authh, void *aarg, bool aref, - sipevent_notify_h *notifyh, sipevent_close_h *closeh, + sipsub_notify_h *notifyh, sipsub_close_h *closeh, void *arg, const char *fmt, ...); int sipevent_fork(struct sipsub **subp, struct sipsub *osub, const struct sip_msg *msg, sip_auth_h *authh, void *aarg, bool aref, - sipevent_notify_h *notifyh, sipevent_close_h *closeh, + sipsub_notify_h *notifyh, sipsub_close_h *closeh, void *arg); diff --git a/src/sipevent/notify.c b/src/sipevent/notify.c index fef80b2..8650730 100644 --- a/src/sipevent/notify.c +++ b/src/sipevent/notify.c @@ -82,7 +82,7 @@ static void sipnot_terminate(struct sipnot *not, int err, const struct sip_msg *msg, enum sipevent_reason reason) { - sip_resp_h *closeh; + sipnot_close_h *closeh; void *arg; closeh = not->closeh; @@ -315,7 +315,7 @@ int sipevent_accept(struct sipnot **notp, struct sipevent_sock *sock, uint32_t expires_dfl, uint32_t expires_max, const char *cuser, const char *ctype, sip_auth_h *authh, void *aarg, bool aref, - sip_resp_h *closeh, void *arg, const char *fmt, ...) + sipnot_close_h *closeh, void *arg, const char *fmt, ...) { struct sipnot *not; uint32_t expires; diff --git a/src/sipevent/sipevent.h b/src/sipevent/sipevent.h index 8a6e848..906b527 100644 --- a/src/sipevent/sipevent.h +++ b/src/sipevent/sipevent.h @@ -33,7 +33,7 @@ struct sipnot { char *cuser; char *hdrs; char *ctype; - sip_resp_h *closeh; + sipnot_close_h *closeh; void *arg; uint32_t expires; uint32_t expires_min; @@ -70,9 +70,9 @@ struct sipsub { char *cuser; char *hdrs; char *refer_hdrs; - sipevent_fork_h *forkh; - sipevent_notify_h *notifyh; - sipevent_close_h *closeh; + sipsub_fork_h *forkh; + sipsub_notify_h *notifyh; + sipsub_close_h *closeh; void *arg; int32_t refer_cseq; uint32_t expires; diff --git a/src/sipevent/subscribe.c b/src/sipevent/subscribe.c index 9b71516..3415996 100644 --- a/src/sipevent/subscribe.c +++ b/src/sipevent/subscribe.c @@ -127,7 +127,7 @@ void sipsub_reschedule(struct sipsub *sub, uint64_t wait) void sipsub_terminate(struct sipsub *sub, int err, const struct sip_msg *msg, const struct sipevent_substate *substate) { - sipevent_close_h *closeh; + sipsub_close_h *closeh; void *arg; closeh = sub->closeh; @@ -342,8 +342,8 @@ static int sipsub_alloc(struct sipsub **subp, struct sipevent_sock *sock, const char *cuser, const char *routev[], uint32_t routec, sip_auth_h *authh, void *aarg, bool aref, - sipevent_fork_h *forkh, sipevent_notify_h *notifyh, - sipevent_close_h *closeh, void *arg, + sipsub_fork_h *forkh, sipsub_notify_h *notifyh, + sipsub_close_h *closeh, void *arg, const char *fmt, va_list ap) { struct sipsub *sub; @@ -453,8 +453,8 @@ int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, uint32_t expires, const char *cuser, const char *routev[], uint32_t routec, sip_auth_h *authh, void *aarg, bool aref, - sipevent_fork_h *forkh, sipevent_notify_h *notifyh, - sipevent_close_h *closeh, void *arg, + sipsub_fork_h *forkh, sipsub_notify_h *notifyh, + sipsub_close_h *closeh, void *arg, const char *fmt, ...) { va_list ap; @@ -495,7 +495,7 @@ int sipevent_dsubscribe(struct sipsub **subp, struct sipevent_sock *sock, struct sip_dialog *dlg, const char *event, const char *id, uint32_t expires, const char *cuser, sip_auth_h *authh, void *aarg, bool aref, - sipevent_notify_h *notifyh, sipevent_close_h *closeh, + sipsub_notify_h *notifyh, sipsub_close_h *closeh, void *arg, const char *fmt, ...) { va_list ap; @@ -539,8 +539,8 @@ int sipevent_refer(struct sipsub **subp, struct sipevent_sock *sock, const char *from_uri, const char *cuser, const char *routev[], uint32_t routec, sip_auth_h *authh, void *aarg, bool aref, - sipevent_fork_h *forkh, sipevent_notify_h *notifyh, - sipevent_close_h *closeh, void *arg, + sipsub_fork_h *forkh, sipsub_notify_h *notifyh, + sipsub_close_h *closeh, void *arg, const char *fmt, ...) { va_list ap; @@ -577,7 +577,7 @@ int sipevent_refer(struct sipsub **subp, struct sipevent_sock *sock, int sipevent_drefer(struct sipsub **subp, struct sipevent_sock *sock, struct sip_dialog *dlg, const char *cuser, sip_auth_h *authh, void *aarg, bool aref, - sipevent_notify_h *notifyh, sipevent_close_h *closeh, + sipsub_notify_h *notifyh, sipsub_close_h *closeh, void *arg, const char *fmt, ...) { va_list ap; @@ -597,7 +597,7 @@ int sipevent_drefer(struct sipsub **subp, struct sipevent_sock *sock, int sipevent_fork(struct sipsub **subp, struct sipsub *osub, const struct sip_msg *msg, sip_auth_h *authh, void *aarg, bool aref, - sipevent_notify_h *notifyh, sipevent_close_h *closeh, + sipsub_notify_h *notifyh, sipsub_close_h *closeh, void *arg) { struct sipsub *sub; From a36ecce4e057ee755a1129f651451643fec7882c Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Mon, 19 Dec 2011 15:14:30 +0000 Subject: [PATCH 40/46] fix 489 reply --- src/sipevent/listen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sipevent/listen.c b/src/sipevent/listen.c index ca66dfc..9e9187f 100644 --- a/src/sipevent/listen.c +++ b/src/sipevent/listen.c @@ -140,7 +140,7 @@ static void notify_handler(struct sipevent_sock *sock, hdr = sip_msg_hdr(msg, SIP_HDR_EVENT); if (!hdr || sipevent_event_decode(&event, &hdr->val)) { - (void)sip_reply(sip, msg, 400, "Bad Event Header"); + (void)sip_reply(sip, msg, 489, "Bad Event"); return; } From 3ebaf443d361a89538c29a182707f499ee48f59a Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Tue, 20 Dec 2011 11:59:26 +0000 Subject: [PATCH 41/46] handle expires 0 and wait for last NOTIFY --- src/sipevent/listen.c | 18 +++++++++-- src/sipevent/sipevent.h | 2 ++ src/sipevent/subscribe.c | 64 +++++++++++++++++++++++++++++++--------- 3 files changed, 67 insertions(+), 17 deletions(-) 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); From aab54c330e0fa5d115012379b285811c652f20f1 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Tue, 20 Dec 2011 12:12:38 +0000 Subject: [PATCH 42/46] don't set subscribed if termconf --- src/sipevent/listen.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sipevent/listen.c b/src/sipevent/listen.c index 73a52b6..3ea3a5a 100644 --- a/src/sipevent/listen.c +++ b/src/sipevent/listen.c @@ -208,7 +208,8 @@ static void notify_handler(struct sipevent_sock *sock, case SIPEVENT_ACTIVE: case SIPEVENT_PENDING: - sub->subscribed = true; + if (!sub->termconf) + sub->subscribed = true; if (!sub->terminated && !sub->termwait && pl_isset(&state.expires)) From 11ef90532ca1253d6136967cb77636e4beb09947 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Tue, 20 Dec 2011 14:47:37 +0000 Subject: [PATCH 43/46] merge with trunk --- mk/Doxyfile | 1 - 1 file changed, 1 deletion(-) diff --git a/mk/Doxyfile b/mk/Doxyfile index e506c25..06b75e7 100644 --- a/mk/Doxyfile +++ b/mk/Doxyfile @@ -91,7 +91,6 @@ EXCLUDE = test.c \ include/re_bitv.h \ src/md5/md5.h src/md5/md5.c \ src/dns include/re_dns.h \ - src/httpauth include/re_httpauth.h \ src/sdp include/re_sdp.h \ src/sip/ include/re_sip.h \ src/sipsess/ include/re_sipsess.h \ From a6d0f1b9d1c5c75f711306a264ebafda634281d6 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Wed, 21 Dec 2011 14:20:26 +0000 Subject: [PATCH 44/46] sipevent misc fixes --- docs/README | 3 +++ mk/symbian/bld.inf | 2 ++ src/sipevent/msg.c | 2 +- src/sipevent/notify.c | 2 +- src/sipevent/subscribe.c | 6 +++--- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/README b/docs/README index a5cdd93..0688847 100644 --- a/docs/README +++ b/docs/README @@ -46,6 +46,7 @@ Modules: * sdp unstable Session Description Protocol * sha testing Secure Hash Standard, NIST, FIPS PUB 180-1 * sip unstable Core SIP library +* sipevent unstable SIP Event framework * sipreg testing SIP register client * sipsess unstable SIP Sessions * stun unstable Session Traversal Utilities for NAT (STUN) @@ -76,9 +77,11 @@ Features: * RFC 3261 - SIP: Session Initiation Protocol * RFC 3263 - Locating SIP Servers * RFC 3264 - An Offer/Answer Model with SDP +* RFC 3265 - SIP-Specific Event Notification * RFC 3327 - SIP Extension Header Field for Registering Non-Adjacent Contacts * RFC 3428 - SIP Extension for Instant Messaging * RFC 3489 - STUN - Simple Traversal of UDP Through NATs +* RFC 3515 - The SIP Refer Method * RFC 3550 - RTP: A Transport Protocol for Real-Time Applications * RFC 3551 - RTP Profile for Audio and Video Conferences with Minimal Control * RFC 3555 - MIME Type Registration of RTP Payload Formats diff --git a/mk/symbian/bld.inf b/mk/symbian/bld.inf index fcfb8c3..9a428f9 100644 --- a/mk/symbian/bld.inf +++ b/mk/symbian/bld.inf @@ -35,6 +35,7 @@ PRJ_EXPORTS ..\..\include\re_sdp.h \epoc32\include\re\re_sdp.h ..\..\include\re_sha.h \epoc32\include\re\re_sha.h ..\..\include\re_sip.h \epoc32\include\re\re_sip.h +..\..\include\re_sipevent.h \epoc32\include\re\re_sipevent.h ..\..\include\re_sipreg.h \epoc32\include\re\re_sipreg.h ..\..\include\re_sipsess.h \epoc32\include\re\re_sipsess.h ..\..\include\re_stun.h \epoc32\include\re\re_stun.h @@ -56,5 +57,6 @@ rebfcp.mmp redns.mmp resdp.mmp resip.mmp +resipevent.mmp resipsess.mmp restun.mmp diff --git a/src/sipevent/msg.c b/src/sipevent/msg.c index 9b61137..4cfc753 100644 --- a/src/sipevent/msg.c +++ b/src/sipevent/msg.c @@ -1,5 +1,5 @@ /** - * @file substate.c SIP Subscription-State header + * @file msg.c SIP event messages * * Copyright (C) 2010 Creytiv.com */ diff --git a/src/sipevent/notify.c b/src/sipevent/notify.c index 8650730..007815f 100644 --- a/src/sipevent/notify.c +++ b/src/sipevent/notify.c @@ -1,5 +1,5 @@ /** - * @file not.c SIP Event Notify + * @file notify.c SIP Event Notify * * Copyright (C) 2010 Creytiv.com */ diff --git a/src/sipevent/subscribe.c b/src/sipevent/subscribe.c index ecd14c3..58fc0f1 100644 --- a/src/sipevent/subscribe.c +++ b/src/sipevent/subscribe.c @@ -1,5 +1,5 @@ /** - * @file sub.c SIP Event Subscribe + * @file subscribe.c SIP Event Subscribe * * Copyright (C) 2010 Creytiv.com */ @@ -461,7 +461,7 @@ static int sipsub_alloc(struct sipsub **subp, struct sipevent_sock *sock, * @param from_name SIP From-header Name (optional) * @param from_uri SIP From-header URI * @param event SIP Event to subscribe to - * @param id SIP Event ID + * @param id SIP Event ID (optional) * @param expires Subscription expires value * @param cuser Contact username * @param routev Optional route vector @@ -508,7 +508,7 @@ int sipevent_subscribe(struct sipsub **subp, struct sipevent_sock *sock, * @param sock SIP Event socket * @param dlg Established SIP Dialog * @param event SIP Event to subscribe to - * @param id SIP Event ID + * @param id SIP Event ID (optional) * @param expires Subscription expires value * @param cuser Contact username * @param authh Authentication handler From c1ac00011a51203f933826a5153d97591fb1d740 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Wed, 21 Dec 2011 14:22:16 +0000 Subject: [PATCH 45/46] sipevent misc fixes --- mk/symbian/resipevent.mmp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 mk/symbian/resipevent.mmp diff --git a/mk/symbian/resipevent.mmp b/mk/symbian/resipevent.mmp new file mode 100644 index 0000000..c0eb19b --- /dev/null +++ b/mk/symbian/resipevent.mmp @@ -0,0 +1,34 @@ +/** + * @file resipevent.mmp Symbian makefile for libre SIP Event + * + * Copyright (C) 2010 Creytiv.com + */ +TARGET resipevent.lib +TARGETTYPE lib +TARGETPATH system\libs +UID 0x10000fd3 0x20011307 + +#ifdef EKA2 +VENDORID 0 +CAPABILITY NetworkServices +#endif + +SOURCEPATH . +SOURCE dll.cpp + +SOURCEPATH ..\..\src\sipevent +SOURCE listen.c +SOURCE msg.c +SOURCE notify.c +SOURCE subscribe.c + +USERINCLUDE . ..\..\include +SYSTEMINCLUDE \epoc32\include +SYSTEMINCLUDE \epoc32\include\libc +SYSTEMINCLUDE ..\..\include +#ifndef EKA2 +LIBRARY estlib.lib euser.lib +LIBRARY esock.lib insock.lib +#endif + +EXPORTUNFROZEN From 8e696bb9f0ce4ecfd7918bb3cdde6ff057807724 Mon Sep 17 00:00:00 2001 From: Richard Aas Date: Thu, 22 Dec 2011 07:53:40 +0000 Subject: [PATCH 46/46] sipevent: remove printf's --- src/sipevent/listen.c | 7 ------- src/sipevent/notify.c | 13 ------------- src/sipevent/subscribe.c | 15 --------------- 3 files changed, 35 deletions(-) diff --git a/src/sipevent/listen.c b/src/sipevent/listen.c index 3ea3a5a..1ef0d82 100644 --- a/src/sipevent/listen.c +++ b/src/sipevent/listen.c @@ -169,8 +169,6 @@ static void notify_handler(struct sipevent_sock *sock, return; } - re_printf("*** new subscription forked from NOTIFY\n"); - sub = fsub; } else { @@ -179,8 +177,6 @@ static void notify_handler(struct sipevent_sock *sock, (void)sip_reply(sip, msg, 500, strerror(err)); return; } - - re_printf("*** dialog established from NOTIFY\n"); } } else { @@ -201,9 +197,6 @@ static void notify_handler(struct sipevent_sock *sock, } } - re_printf("notify: %s (%r)\n", sipevent_substate_name(state.state), - &state.params); - switch (state.state) { case SIPEVENT_ACTIVE: diff --git a/src/sipevent/notify.c b/src/sipevent/notify.c index 007815f..0e0059e 100644 --- a/src/sipevent/notify.c +++ b/src/sipevent/notify.c @@ -3,7 +3,6 @@ * * Copyright (C) 2010 Creytiv.com */ -#include // todo: remove #include #include #include @@ -102,8 +101,6 @@ static void tmr_handler(void *arg) if (not->terminated) return; - re_printf("subscription expired\n"); - sipnot_terminate(not, ETIMEDOUT, NULL, SIPEVENT_TIMEOUT); } @@ -112,8 +109,6 @@ void sipnot_refresh(struct sipnot *not, uint32_t expires) { not->expires = min(expires, not->expires_max); - re_printf("will expire in %u secs\n", not->expires); - tmr_start(¬->tmr, not->expires * 1000, tmr_handler, not); } @@ -122,11 +117,6 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) { struct sipnot *not = arg; - if (err) - re_printf("notify reply: %s\n", strerror(err)); - else - re_printf("notify reply: %u %r\n", msg->scode, &msg->reason); - if (err) { if (err == ETIMEDOUT) not->subscribed = false; @@ -178,7 +168,6 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) sipnot_terminate(not, err, msg, -1); } else if (not->notify_pending) { - re_printf("sending queued request\n"); (void)notify_request(not, true); } } @@ -277,12 +266,10 @@ static int notify_request(struct sipnot *not, bool reset_ls) int sipnot_notify(struct sipnot *not) { if (not->expires == 0) { - re_printf("NOTIFY will be sent at timeout\n"); return 0; } if (not->req) { - re_printf("waiting for previous request to complete\n"); not->notify_pending = true; return 0; } diff --git a/src/sipevent/subscribe.c b/src/sipevent/subscribe.c index 58fc0f1..3f17a42 100644 --- a/src/sipevent/subscribe.c +++ b/src/sipevent/subscribe.c @@ -3,7 +3,6 @@ * * Copyright (C) 2010 Creytiv.com */ -#include // todo: remove #include #include #include @@ -107,8 +106,6 @@ static void notify_timeout_handler(void *arg) { struct sipsub *sub = arg; - re_printf("timeout waiting for NOTIFY\n"); - sub->termwait = false; if (sub->terminated) @@ -140,8 +137,6 @@ static void tmr_handler(void *arg) void sipsub_reschedule(struct sipsub *sub, uint64_t wait) { - re_printf("will re-subscribe in %llu secs\n", wait/1000); - tmr_start(&sub->tmr, wait, tmr_handler, sub); } @@ -166,11 +161,6 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) const struct sip_hdr *minexp; struct sipsub *sub = arg; - if (err) - re_printf("reply: %s\n", strerror(err)); - else - re_printf("reply: %u %r\n", msg->scode, &msg->reason); - if (err || sip_request_loops(&sub->ls, msg->scode)) goto out; @@ -191,8 +181,6 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) err = sub->forkh(&fsub, sub, msg, sub->arg); if (err) return; - - re_printf("*** new subscription forked\n"); } else { (void)sip_dialog_update(fsub->dlg, msg); @@ -207,8 +195,6 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) sub->subscribed = false; goto out; } - - re_printf("*** dialog established\n"); } else { /* Ignore 2xx responses for other dialogs @@ -226,7 +212,6 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg) 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;