static int nua_subscribe_client_init(nua_client_request_t *cr, msg_t *msg, sip_t *sip, tagi_t const *tags) { nua_handle_t *nh = cr->cr_owner; nua_dialog_usage_t *du; sip_event_t *o = sip->sip_event; du = nua_dialog_usage_get(nh->nh_ds, nua_subscribe_usage, o); if (du == NULL && o == NULL) du = nua_dialog_usage_get(nh->nh_ds, nua_subscribe_usage, NONE); if (du) { if (du->du_event && o == NULL) /* Add Event header */ sip_add_dup(msg, sip, (sip_header_t *)du->du_event); } else if (cr->cr_event == nua_r_subscribe) { /* Create dialog usage */ du = nua_dialog_usage_add(nh, nh->nh_ds, nua_subscribe_usage, o); /* Note that we allow SUBSCRIBE without event */ } cr->cr_usage = du; return 0; }
static int nua_publish_client_init(nua_client_request_t *cr, msg_t *msg, sip_t *sip, tagi_t const *tags) { nua_handle_t *nh = cr->cr_owner; nua_dialog_usage_t *du; struct publish_usage *pu; if (cr->cr_event == nua_r_publish) { du = nua_dialog_usage_add(nh, nh->nh_ds, nua_publish_usage, NULL); if (!du) return -1; pu = nua_dialog_usage_private(du); pu->pu_published = 0; if (sip->sip_if_match) { pu->pu_etag = sip_etag_dup(nh->nh_home, sip->sip_if_match); if (!pu->pu_etag) return -1; sip_header_remove(msg, sip, (sip_header_t *)sip->sip_if_match); } } else du = nua_dialog_usage_get(nh->nh_ds, nua_publish_usage, NULL); cr->cr_usage = du; return 0; }
int nua_subscribe_server_preprocess(nua_server_request_t *sr) { nua_handle_t *nh = sr->sr_owner; nua_dialog_state_t *ds = nh->nh_ds; nua_dialog_usage_t *du; struct notifier_usage *nu; sip_t const *sip = sr->sr_request.sip; sip_event_t *o = sip->sip_event; char const *event = o ? o->o_type : NULL; /* Maximum expiration time */ unsigned long expires = sip->sip_expires ? sip->sip_expires->ex_delta : 3600; sip_time_t now = sip_now(); sip_allow_events_t *appl_event = NH_PGET(nh, appl_event); assert(nh && nh->nh_nua->nua_dhandle != nh); du = nua_dialog_usage_get(ds, nua_notify_usage, o); if (du == NULL) { /* Create a new subscription */ du = nua_dialog_usage_add(nh, ds, nua_notify_usage, o); if (du == NULL) return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); } else if (!msg_header_find_param((void *)appl_event, event)) { unsigned max_expires; /* Refresh existing subscription */ if (su_strmatch(event, "refer")) max_expires = NH_PGET(nh, refer_expires); else max_expires = NH_PGET(nh, sub_expires); if (expires >= max_expires) expires = max_expires; SR_STATUS1(sr, SIP_200_OK); } nu = nua_dialog_usage_private(du); if (now + expires >= now) nu->nu_requested = now + expires; else nu->nu_requested = SIP_TIME_MAX - 1; #if SU_HAVE_EXPERIMENTAL nu->nu_etags = sip_suppress_body_if_match(sip) || sip_suppress_notify_if_match(sip) || sip_has_feature(sr->sr_request.sip->sip_supported, "etags"); #endif sr->sr_usage = du; return sr->sr_status <= 100 ? 0 : sr->sr_status; }
static int nua_publish_client_template(nua_client_request_t *cr, msg_t **return_msg, tagi_t const *tags) { nua_dialog_usage_t *du; if (cr->cr_event == nua_r_publish) return 0; du = nua_dialog_usage_get(cr->cr_owner->nh_ds, nua_publish_usage, NULL); if (du && du->du_cr) { if (nua_client_set_target(cr, du->du_cr->cr_target) < 0) return -1; *return_msg = msg_copy(du->du_cr->cr_msg); return 1; } return 0; }
int nua_subscribe_server_init(nua_server_request_t *sr) { nua_handle_t *nh = sr->sr_owner; nua_dialog_state_t *ds = nh->nh_ds; sip_allow_events_t const *allow_events = NH_PGET(nh, allow_events); sip_t const *sip = sr->sr_request.sip; sip_event_t *o = sip->sip_event; char const *event = o ? o->o_type : NULL; if (sr->sr_initial || !nua_dialog_usage_get(ds, nua_notify_usage, o)) { if (su_strmatch(event, "refer")) /* refer event subscription should be initiated with REFER */ return SR_STATUS1(sr, SIP_403_FORBIDDEN); /* XXX - event is case-sensitive, should use msg_header_find_item() */ if (!event || !msg_header_find_param(allow_events->k_common, event)) return SR_STATUS1(sr, SIP_489_BAD_EVENT); } return 0; }
int nua_notify_server_preprocess(nua_server_request_t *sr) { nua_dialog_state_t *ds = sr->sr_owner->nh_ds; nua_dialog_usage_t *du; struct event_usage *eu; sip_t const *sip = sr->sr_request.sip; sip_event_t *o = sip->sip_event; enum nua_substate substate = nua_substate_terminated; sip_subscription_state_t *subs = sip->sip_subscription_state; char const *what = "", *reason = NULL; int solicited = 1; du = nua_dialog_usage_get(ds, nua_subscribe_usage, o); if (du == NULL) { if (!sip_is_allowed(NH_PGET(sr->sr_owner, appl_method), SIP_METHOD_NOTIFY)) return SR_STATUS(sr, 481, "Subscription Does Not Exist"); solicited = 0; /* Let application to handle unsolicited NOTIFY */ du = nua_dialog_usage_add(sr->sr_owner, ds, nua_subscribe_usage, o); if (!du) return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); } sr->sr_usage = du; eu = nua_dialog_usage_private(du); assert(eu); eu->eu_notified++; if (!o || !o->o_id) eu->eu_no_id = 1; if (subs == NULL) { /* Compatibility */ unsigned long delta = eu->eu_delta; if (sip->sip_expires) delta = sip->sip_expires->ex_delta; if (delta == 0) substate = nua_substate_terminated, what = "terminated"; else substate = nua_substate_active, what = "active"; } else if (su_casematch(subs->ss_substate, what = "terminated")) { substate = nua_substate_terminated; reason = subs->ss_reason; if (su_casematch(reason, "deactivated") || su_casematch(reason, "probation")) substate = nua_substate_embryonic; } else if (su_casematch(subs->ss_substate, what = "pending")) { substate = nua_substate_pending; } else /* if (su_casematch(subs->ss_substate, what = "active")) */ { /* Any extended state is considered as active */ what = subs->ss_substate; substate = nua_substate_active; } eu->eu_substate = substate; if (!solicited) eu->eu_unsolicited = 1; SU_DEBUG_5(("nua(%p): %s: %s (%s)\n", (void *)sr->sr_owner, "nua_notify_server_preprocess", what, reason ? reason : "")); if (solicited) return SR_STATUS1(sr, SIP_200_OK); return 0; }
static int nua_notify_client_init(nua_client_request_t *cr, msg_t *msg, sip_t *sip, tagi_t const *tags) { nua_handle_t *nh = cr->cr_owner; nua_dialog_usage_t *du; struct notifier_usage *nu; sip_event_t const *o = sip->sip_event; sip_subscription_state_t *ss = sip->sip_subscription_state; sip_time_t now = sip_now(); if (o == NULL && nh->nh_ds->ds_has_notifys == 1) o = NONE; du = nua_dialog_usage_get(nh->nh_ds, nua_notify_usage, o); if (!du) { tagi_t const *newsub = tl_find_last(tags, nutag_newsub); if (!newsub || !newsub->t_value) return 0; /* Rejected eventually by nua_notify_client_request() */ /* Create new notifier */ du = nua_dialog_usage_add(nh, nh->nh_ds, nua_notify_usage, o); if (du == NULL) return -1; nu = nua_dialog_usage_private(du); nu->nu_expires = now; } else nu = nua_dialog_usage_private(du); if (nu->nu_substate == nua_substate_terminated) { /*Xyzzy*/; } else if (ss != NULL) { /* SIPTAG_SUBSCRIPTION_STATE() overrides NUTAG_SUBSTATE() */ nu->nu_substate = nua_substate_make(ss->ss_substate); if (ss->ss_expires) { unsigned long expires = strtoul(ss->ss_expires, NULL, 10); if (now + expires < now) expires = SIP_TIME_MAX - now - 1; /* We can change the lifetime of unsolicited subscription at will */ if (nu->nu_requested == 0) nu->nu_expires = nu->nu_requested = now + expires; /* Notifier can only shorten the subscribed time */ else if (nu->nu_requested >= now + expires) nu->nu_expires = nu->nu_requested = now + expires; } else { if (nu->nu_requested >= nu->nu_expires) nu->nu_expires = nu->nu_requested; } } else { enum nua_substate substate = nu->nu_substate; if (nu->nu_requested >= nu->nu_expires) nu->nu_expires = nu->nu_requested; if (nu->nu_expires > now) { tagi_t const *t = tl_find_last(tags, nutag_substate); if (t) substate = (enum nua_substate)t->t_value; } else substate = nua_substate_terminated; switch (substate) { case nua_substate_embryonic: /*FALLTHROUGH*/ case nua_substate_pending: nu->nu_substate = nua_substate_pending; break; case nua_substate_active: default: nu->nu_substate = nua_substate_active; break; case nua_substate_terminated: nu->nu_substate = nua_substate_terminated; break; } } cr->cr_usage = du; return nua_notify_client_init_etag(cr, msg, sip, tags); }