123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658 |
- #include "rl_subscription.h"
- #include "rls_mod.h"
- #include <cds/dstring.h>
- #include <cds/list.h>
- #include <cds/logger.h>
- #include "result_codes.h"
- #include "rlmi_doc.h"
- #include <xcap/resource_list.h>
- #include <presence/pres_doc.h>
- #include "../../str.h"
- #include "../../id.h"
- #include "../../dprint.h"
- #include "../../mem/mem.h"
- #include "../../mem/shm_mem.h"
- #include "../../lock_alloc.h"
- #include "../../ut.h"
- #include "../../parser/hf.h"
- #include "../../parser/parse_from.h"
- #include "../../data_lump_rpl.h"
- typedef struct {
- dlg_id_t id;
- char buf[1];
- } rls_notify_cb_param_t;
- subscription_manager_t *rls_manager = NULL;
- #define METHOD_NOTIFY "NOTIFY"
- /************* Helper functions for TM callback ************/
- static rls_notify_cb_param_t *create_notify_cb_param(rl_subscription_t *s)
- {
- rls_notify_cb_param_t *cbd;
- int size;
- dlg_t *dlg;
- if (!s) return NULL;
- if (s->type != rls_external_subscription) return NULL;
- dlg = s->u.external.dialog;
- if (!dlg) return NULL;
- size = sizeof(*cbd) +
- dlg->id.call_id.len +
- dlg->id.rem_tag.len +
- dlg->id.loc_tag.len;
-
- cbd = (rls_notify_cb_param_t*)mem_alloc(size);
- if (!cbd) {
- ERR("can't allocate memory (%d bytes)\n", size);
- return NULL;
- }
- cbd->id.call_id.s = cbd->buf;
- cbd->id.call_id.len = dlg->id.call_id.len;
-
- cbd->id.rem_tag.s = cbd->id.call_id.s + cbd->id.call_id.len;
- cbd->id.rem_tag.len = dlg->id.rem_tag.len;
-
- cbd->id.loc_tag.s = cbd->id.rem_tag.s + cbd->id.rem_tag.len;
- cbd->id.loc_tag.len = dlg->id.loc_tag.len;
-
- /* copy data */
- if (dlg->id.call_id.s) memcpy(cbd->id.call_id.s,
- dlg->id.call_id.s, dlg->id.call_id.len);
- if (dlg->id.rem_tag.s) memcpy(cbd->id.rem_tag.s,
- dlg->id.rem_tag.s, dlg->id.rem_tag.len);
- if (dlg->id.loc_tag.s) memcpy(cbd->id.loc_tag.s,
- dlg->id.loc_tag.s, dlg->id.loc_tag.len);
-
- return cbd;
- }
- static void destroy_subscription(rls_notify_cb_param_t *cbd)
- {
- int res;
- rl_subscription_t *s = NULL;
-
- rls_lock();
-
- res = rls_find_subscription(&cbd->id.rem_tag, &cbd->id.loc_tag,
- &cbd->id.call_id, &s);
- if ((res != RES_OK) || (!s)) {
- /* subscription NOT found */
- rls_unlock();
- return;
- }
- rls_remove(s);
- rls_unlock();
- }
- /************* Helper functions for RL subscription manipulation ************/
- str_t * rls_get_uri(rl_subscription_t *s)
- {
- if (!s) return NULL;
-
- if (s->type == rls_external_subscription) {
- return &((s)->u.external.record_id);
- }
- else {
- return s->u.internal.record_id;
- }
- return NULL;
- }
- str_t * rls_get_package(rl_subscription_t *s)
- {
- static str presence = STR_STATIC_INIT("presence");
- str_t *package = NULL;
-
- if (!s) return NULL;
-
- if (s->type == rls_external_subscription)
- package = &((s)->u.external.package);
- else package = s->u.internal.package;
- if (!package) package = &presence;
- return package;
- }
- str_t * rls_get_subscriber(rl_subscription_t *subscription)
- {
- if (!subscription) return NULL;
-
- switch (subscription->type) {
- case rls_external_subscription:
- return &subscription->u.external.subscriber;
- case rls_internal_subscription:
- return subscription->u.internal.subscriber_id;
- }
- return NULL;
- }
- int add_virtual_subscriptions(rl_subscription_t *ss,
- flat_list_t *flat,
- int nesting_level)
- {
- flat_list_t *e;
- /* xcap_query_t xcap; */
- virtual_subscription_t *vs;
- int res = 0;
- str s;
-
- /* TODO: create virtual subscriptions using Accept headers
- * ... (for remote subscriptions) */
- /* go through flat list and find/create virtual subscriptions */
- e = flat;
- while (e) {
- s.s = e->uri;
- if (s.s) s.len = strlen(s.s);
- else s.len = 0;
- res = vs_create(&s, &vs, e->names, ss, nesting_level);
-
- if (res != RES_OK) {
- /* FIXME: remove already added members? */
- return res;
- }
- ptr_vector_add(&ss->vs, vs);
- e = e->next;
- }
- return RES_OK;
- }
- int create_virtual_subscriptions(rl_subscription_t *ss, int nesting_level)
- {
- flat_list_t *flat = NULL;
- int res = 0;
- str_t *ss_uri = NULL;
- str_t *ss_package = NULL;
-
- ss_uri = rls_get_uri(ss);
- ss_package = rls_get_package(ss);
- res = xcap_query_rls_services(&ss->xcap_params,
- ss_uri, ss_package, &flat);
-
- if (res != RES_OK) return res;
-
- /* go through flat list and find/create virtual subscriptions */
- res = add_virtual_subscriptions(ss, flat, nesting_level);
- DEBUG_LOG("rli_create_content(): freeing flat list\n");
- free_flat_list(flat);
- return RES_OK;
- }
- static void clear_change_flags(rl_subscription_t *s)
- {
- int i, cnt;
- virtual_subscription_t *vs;
- cnt = ptr_vector_size(&s->vs);
- for (i = 0; i < cnt; i++) {
- vs = ptr_vector_get(&s->vs, i);
- if (!vs) continue;
- vs->changed = 0;
- }
- s->changed = 0;
- }
- /************* RL subscription manipulation function ************/
- rl_subscription_t *rls_alloc_subscription(rls_subscription_type_t type)
- {
- rl_subscription_t *s;
-
- s = (rl_subscription_t*)mem_alloc(sizeof(rl_subscription_t));
- if (!s) {
- LOG(L_ERR, "rls_alloc_subscription(): can't allocate memory\n");
- return NULL;
- }
- memset(s, 0, sizeof(*s));
-
- s->u.external.status = subscription_uninitialized;
- s->u.external.usr_data = s;
- s->doc_version = 0;
- s->changed = 0;
- s->type = type;
- s->dbid[0] = 0;
- /* s->first_vs = NULL;
- s->last_vs = NULL; */
- str_clear(&s->from_uid);
- ptr_vector_init(&s->vs, 4);
-
- return s;
- }
- int rls_create_subscription(struct sip_msg *m,
- rl_subscription_t **dst,
- flat_list_t *flat,
- xcap_query_params_t *params)
- {
- rl_subscription_t *s;
- str from_uid = STR_NULL;
- int res;
- if (!dst) return RES_INTERNAL_ERR;
- *dst = NULL;
- s = rls_alloc_subscription(rls_external_subscription);
- if (!s) {
- LOG(L_ERR, "rls_create_new(): can't allocate memory\n");
- return RES_MEMORY_ERR;
- }
- generate_db_id(&s->dbid, s);
- res = sm_init_subscription_nolock(rls_manager, &s->u.external, m);
- if (res != RES_OK) {
- rls_free(s);
- return res;
- }
-
- if (params) {
- if (dup_xcap_params(&s->xcap_params, params) < 0) {
- ERR("can't duplicate xcap_params\n");
- rls_free(s);
- return -1;
- }
- }
- /* store pointer to this RL subscription as user data
- * of (low level) subscription */
- s->u.external.usr_data = s;
- if (get_from_uid(&from_uid, m) < 0) str_clear(&s->from_uid);
- else str_dup(&s->from_uid, &from_uid);
-
- /* res = set_rls_info(m, s, xcap_root);
- if (res != 0) {
- rls_free(s);
- return res;
- }*/
-
- res = add_virtual_subscriptions(s, flat, max_list_nesting_level);
- if (res != 0) {
- rls_free(s);
- return res;
- }
- if (use_db) {
- if (rls_db_add(s) != 0) {
- rls_free(s);
- return RES_INTERNAL_ERR; /* FIXME RES_DB_ERR */
- }
- }
- *dst = s;
- return RES_OK;
- }
- int rls_find_subscription(str *from_tag, str *to_tag, str *call_id, rl_subscription_t **dst)
- {
- subscription_data_t *s;
- int res;
- *dst = NULL;
- res = sm_find_subscription(rls_manager, from_tag, to_tag, call_id, &s);
- if ((res == RES_OK) && (s)) {
- if (!s->usr_data) {
- LOG(L_ERR, "found subscription without filled usr_data\n");
- return RES_INTERNAL_ERR;
- }
- else {
- *dst = (rl_subscription_t*)s->usr_data;
- return RES_OK;
- }
- }
- return RES_NOT_FOUND;
- }
- int rls_refresh_subscription(struct sip_msg *m, rl_subscription_t *s)
- {
- int res;
- if (!s) return RES_INTERNAL_ERR;
- if (s->type != rls_external_subscription) return RES_INTERNAL_ERR;
- res = sm_refresh_subscription_nolock(rls_manager, &s->u.external, m);
- if (use_db) rls_db_update(s);
- return res;
- }
- void rls_remove(rl_subscription_t *s)
- {
- if (!s) return;
-
- if (use_db) rls_db_remove(s);
- rls_free(s);
- }
- void rls_free(rl_subscription_t *s)
- {
- int i, cnt;
- virtual_subscription_t *vs;
-
- if (!s) return;
- if (use_db) rls_db_remove(s);
-
- cnt = ptr_vector_size(&s->vs);
- for (i = 0; i < cnt; i++) {
- vs = ptr_vector_get(&s->vs, i);
- if (!vs) continue;
- vs_free(vs);
- }
- if (s->type == rls_external_subscription) {
- sm_release_subscription_nolock(rls_manager, &s->u.external);
-
- /* free ONLY for external subscriptions */
- free_xcap_params_content(&s->xcap_params);
- }
- else {
- /* release_internal_subscription(s); */
- /* don't free xcap_params */
- }
- ptr_vector_destroy(&s->vs);
- str_free_content(&s->from_uid);
- mem_free(s);
- }
- /* void rls_notify_cb(struct cell* t, struct sip_msg* msg, int code, void *param) */
- static void rls_notify_cb(struct cell* t, int type, struct tmcb_params* params)
- {
- rls_notify_cb_param_t *cbd = NULL;
- if (!params) return;
- if (params->param) cbd = (rls_notify_cb_param_t *)*(params->param);
- if (!cbd) {
- ERR("BUG empty cbd parameter given to callback function\n");
- return;
- }
- if (params->code >= 300) { /* what else can we do with 3xx ? */
- int ignore = 0;
-
- switch (params->code) {
- case 408:
- if (rls_ignore_408_on_notify) ignore = 1;
- /* due to eyeBeam's problems with processing more NOTIFY
- * requests sent consequently without big delay */
- break;
- }
-
- if (!ignore) {
- WARN("destroying subscription from callback due to %d response on NOTIFY\n", params->code);
- destroy_subscription(cbd);
- TRACE("subscription destroyed!!!\n");
- }
- }
- mem_free(cbd);
- }
- static int rls_generate_notify_ext(rl_subscription_t *s, int full_info)
- {
- /* !!! the main mutex must be locked here !!! */
- int res;
- str doc;
- dstring_t dstr;
- str headers, content_type;
- static str method = STR_STATIC_INIT(METHOD_NOTIFY);
- dlg_t *dlg;
- int exp_time = 0;
- char expiration[32];
- str body = STR_STATIC_INIT("");
- int removed = 0;
- dlg = s->u.external.dialog;
- if (!dlg) return -1;
- DEBUG("generating external notify\n");
-
- str_clear(&doc);
- str_clear(&content_type);
- if (sm_subscription_pending(&s->u.external) != 0) {
- /* create the document only for non-pending subscriptions */
- if (create_rlmi_document(&doc, &content_type, s, full_info) != 0) {
- return -1;
- }
- }
-
- exp_time = sm_subscription_expires_in(rls_manager, &s->u.external);
- sprintf(expiration, ";expires=%d\r\n", exp_time);
-
- dstr_init(&dstr, 256);
- dstr_append_zt(&dstr, "Subscription-State: ");
- switch (s->u.external.status) {
- case subscription_active:
- dstr_append_zt(&dstr, "active");
- dstr_append_zt(&dstr, expiration);
- break;
- case subscription_pending:
- dstr_append_zt(&dstr, "pending");
- dstr_append_zt(&dstr, expiration);
- break;
- case subscription_terminated_pending:
- case subscription_terminated:
- dstr_append_zt(&dstr, "terminated\r\n");
- break;
- case subscription_terminated_pending_to:
- case subscription_terminated_to:
- dstr_append_zt(&dstr,
- "terminated;reason=timeout\r\n");
- break;
- case subscription_uninitialized:
- dstr_append_zt(&dstr, "pending\r\n");
- /* this is an error ! */
- LOG(L_ERR, "sending NOTIFY for an unitialized subscription!\n");
- break;
- }
- dstr_append_str(&dstr, &s->u.external.contact);
-
- /* required by RFC 3261 */
- dstr_append_zt(&dstr, "Max-Forwards: 70\r\n");
- dstr_append_zt(&dstr, "Event: ");
- dstr_append_str(&dstr, rls_get_package(s));
- dstr_append_zt(&dstr, "\r\n");
- dstr_append_zt(&dstr, "Require: eventlist\r\nContent-Type: ");
- dstr_append_str(&dstr, &content_type);
- dstr_append_zt(&dstr, "\r\n");
- res = dstr_get_str(&dstr, &headers);
- dstr_destroy(&dstr);
- if (res >= 0) {
- /* DEBUG("sending NOTIFY message to %.*s (subscription %p)\n",
- dlg->rem_uri.len,
- ZSW(dlg->rem_uri.s), s); */
-
- if (!is_str_empty(&doc)) body = doc;
-
- if (sm_subscription_terminated(&s->u.external) == 0) {
- /* doesn't matter if delivered or not, it will be freed otherwise !!! */
- res = tmb.t_request_within(&method, &headers, &body, dlg, 0, 0);
- if (res >= 0) clear_change_flags(s);
- }
- else {
- rls_notify_cb_param_t *cbd = create_notify_cb_param(s);
- if (!cbd) {
- ERR("Can't create notify cb data! Freeing RL subscription.\n");
- rls_remove(s); /* ?????? */
- removed = 1;
- res = -13;
- }
- else {
- /* the subscritpion will be destroyed if NOTIFY delivery problems */
- /* rls_unlock(); the callback locks this mutex ! */
-
- /* !!!! FIXME: callbacks can't be safely used (may be called or not,
- * may free memory automaticaly or not) !!! */
- res = tmb.t_request_within(&method, &headers, &body, dlg, rls_notify_cb, cbd);
-
- /* res = tmb.t_request_within(&method, &headers, &body, dlg, rls_notify_cb, s); */
- /* rls_lock(); the callback locks this mutex ! */
- if (res < 0) {
- /* does this mean, that the callback was not called ??? */
- ERR("t_request_within FAILED: %d! Freeing RL subscription.\n", res);
- rls_remove(s); /* ?????? */
- removed = 1;
- }
- else clear_change_flags(s);
- }
- }
- }
-
- if (doc.s) cds_free(doc.s);
- if (content_type.s) cds_free(content_type.s);
- if (headers.s) cds_free(headers.s);
-
- if ((!removed) && use_db) rls_db_update(s);
-
- if (res < 0) DEBUG("external notify NOT generated\n");
- else DEBUG("external notify generated\n");
-
- return res;
- }
- /* static raw_presence_info_t* rls2raw_presence_info(rl_subscription_t *s)
- {
- raw_presence_info_t *info;
- info = create_raw_presence_info(s->u.internal.record_id);
- if (!info) return info;
- str_clear(&info->pres_doc);
- str_clear(&info->content_type);
- DEBUG_LOG(" ... create RLMI document\n");
- create_rlmi_document(&info->pres_doc, &info->content_type, s, 1);
- return info;
- } */
-
- static int rls_generate_notify_int(rl_subscription_t *s, int full_info)
- {
- /* generate internal notification */
- str_t doc, content_type;
-
- /* TRACE("generating internal list notify\n"); */
- if (!s->u.internal.vs) return 1;
-
- DBG("generating internal rls notification\n");
- /* raw = rls2raw_presence_info(s); */
- if (create_rlmi_document(&doc, &content_type, s, full_info) < 0) {
- ERR("can't generate internal notification document\n");
- return -1;
- }
- clear_change_flags(s);
-
- /* documents are given to VS (we don't care about them
- * more - no free, ... */
- process_internal_notify(s->u.internal.vs,
- &doc, &content_type);
- return 0;
- }
- int rls_generate_notify(rl_subscription_t *s, int full_info)
- {
- /* !!! the main mutex must be locked here !!! */
- DBG("generating rls notification\n");
- if (!s) {
- ERR("called with <null> subscription\n");
- return -1;
- }
-
- switch (s->type) {
- case rls_external_subscription:
- return rls_generate_notify_ext(s, full_info);
- case rls_internal_subscription:
- return rls_generate_notify_int(s, full_info);
- }
-
- return -1;
- }
- int rls_prepare_subscription_response(rl_subscription_t *s, struct sip_msg *m) {
- /* char *hdr = "Supported: eventlist\r\n"; */
- char *hdr = "Require: eventlist\r\n";
- if (s->type != rls_external_subscription) return -1;
-
- if (!add_lump_rpl(m, hdr, strlen(hdr), LUMP_RPL_HDR)) return -1;
-
- return sm_prepare_subscription_response(rls_manager, &s->u.external, m);
- }
- /** returns the count of seconds remaining to subscription expiration */
- int rls_subscription_expires_in(rl_subscription_t *s)
- {
- if (s->type == rls_external_subscription)
- return sm_subscription_expires_in(rls_manager, &s->u.external);
- else return -1;
- }
- /* static str_t notifier_name = { s: "rls", len: 3 }; */
- /* static str_t pres_list_package = { s: "presence.list", len: 13 };
- int is_presence_list_package(const str_t *package)
- {
- return (str_case_equals(package, &pres_list_package) == 0);
- }*/
- int rls_create_internal_subscription(virtual_subscription_t *vs,
- rl_subscription_t **dst,
- flat_list_t *flat,
- int nesting_level)
- {
- rl_subscription_t *rls;
-
- /* try to make subscription and release it if internal subscription
- * not created */
- if (dst) *dst = NULL;
- rls = rls_alloc_subscription(rls_internal_subscription);
- if (!rls) {
- ERR("processing INTERNAL RLS subscription - memory allocation error\n");
- return -1;
- }
- rls->u.internal.record_id = &vs->uri; /* !!! NEVER !!! free this */
- rls->u.internal.package = rls_get_package(vs->subscription); /* !!! NEVER !!! free this */
- rls->u.internal.subscriber_id = rls_get_subscriber(vs->subscription); /* !!! NEVER !!! free this */
- rls->xcap_params = vs->subscription->xcap_params; /* !!! NEVER free this !!! */
- rls->u.internal.vs = vs;
- if (dst) *dst = rls;
- DBG("creating internal subscription to %.*s (VS %p)\n",
- FMT_STR(*rls->u.internal.record_id),
- rls->u.internal.vs);
- if (add_virtual_subscriptions(rls, flat, nesting_level) != 0) {
- rls_free(rls);
- if (dst) *dst = NULL;
- return -1;
- }
- rls_generate_notify(rls, 1);
- return 0;
- }
|