/** Bind client request to a dialog usage */ int nua_client_bind(nua_client_request_t *cr, nua_dialog_usage_t *du) { assert(cr); if (cr == NULL) return -1; if (du == NULL) { du = cr->cr_usage; cr->cr_usage = NULL; if (du && du->du_cr == cr) { du->du_cr = NULL; nua_client_request_unref(cr); } return 0; } if (du->du_cr && cr == du->du_cr) return 0; if (du->du_cr) { nua_client_bind(du->du_cr, NULL); } du->du_cr = nua_client_request_ref(cr), cr->cr_usage = du; return 0; }
static int nua_publish_client_request(nua_client_request_t *cr, msg_t *msg, sip_t *sip, tagi_t const *tags) { nua_dialog_usage_t *du = cr->cr_usage; int un, done; sip_etag_t const *etag = NULL; un = cr->cr_terminating || cr->cr_event != nua_r_publish || (du && du->du_shutdown) || (sip->sip_expires && sip->sip_expires->ex_delta == 0); nua_client_set_terminating(cr, un); done = un; if (du) { struct publish_usage *pu = nua_dialog_usage_private(du); if (nua_client_bind(cr, du) < 0) return -1; if (pu->pu_published) done = 1; etag = pu->pu_etag; } return nua_base_client_trequest(cr, msg, sip, SIPTAG_IF_MATCH(etag), TAG_IF(done, SIPTAG_PAYLOAD(NONE)), TAG_IF(done, SIPTAG_CONTENT_TYPE(NONE)), TAG_IF(un, SIPTAG_EXPIRES_STR("0")), TAG_NEXT(tags)); }
static int nua_subscribe_client_request(nua_client_request_t *cr, msg_t *msg, sip_t *sip, tagi_t const *tags) { nua_dialog_usage_t *du = cr->cr_usage; sip_time_t expires = 0; if (cr->cr_event == nua_r_destroy || !du || du->du_shutdown) nua_client_set_terminating(cr, 1); if (du) { struct event_usage *eu = nua_dialog_usage_private(du); sip_event_t *o = sip->sip_event; if (nua_client_bind(cr, du) < 0) return -1; if (eu->eu_no_id && o && o->o_id) { /* Notifier does not handle id properly, remove it */ msg_header_remove_param(o->o_common, "id"); } #if 0 if (cr->cr_terminating) { /* Already terminated subscription? */ if (eu->eu_substate == nua_substate_terminated || eu->eu_substate == nua_substate_embryonic) { return nua_client_return(cr, SIP_200_OK, msg); } } #endif nua_dialog_usage_reset_refresh(du); /* during SUBSCRIBE transaction */ if (cr->cr_terminating || cr->cr_event != nua_r_subscribe) expires = eu->eu_delta = 0; else if (sip->sip_expires) /* Use value specified by application or negotiated with Min-Expires */ expires = eu->eu_delta = sip->sip_expires->ex_delta; else /* We just use common default value, but the default is actually package-specific according to the RFC 3265 section 4.4.4: [Event] packages MUST also define a default "Expires" value to be used if none is specified. */ expires = eu->eu_delta = 3600; eu->eu_final_wait = 0; if (eu->eu_substate == nua_substate_terminated) eu->eu_substate = nua_substate_embryonic; } if (!sip->sip_expires || sip->sip_expires->ex_delta != expires) { sip_expires_t ex[1]; sip_expires_init(ex)->ex_delta = expires; sip_add_dup(msg, sip, (sip_header_t *)ex); } return nua_base_client_request(cr, msg, sip, tags); }
/** @internal Remove dialog usage. * * Zap dialog state (leg, tag and route) if no usages remain. */ static void nua_dialog_usage_remove_at(nua_owner_t *own, nua_dialog_state_t *ds, nua_dialog_usage_t **at, nua_client_request_t *cr0, nua_server_request_t *sr0) { if (*at) { nua_dialog_usage_t *du = *at; sip_event_t const *o = NULL; nua_client_request_t *cr, *cr_next; nua_server_request_t *sr, *sr_next; *at = du->du_next; o = du->du_event; SU_DEBUG_5(("nua(%p): removing %s usage%s%s\n", (void *)own, nua_dialog_usage_name(du), o ? " with event " : "", o ? o->o_type :"")); du->du_class->usage_remove(own, ds, du, cr0, sr0); /* Clean reference to saved client request */ if (du->du_cr) nua_client_bind(du->du_cr, NULL); /* Clean references from queued client requests */ for (cr = ds->ds_cr; cr; cr = cr_next) { cr_next = cr->cr_next; if (cr->cr_usage == du) cr->cr_usage = NULL; } /* Clean references from queued server requests */ for (sr = ds->ds_sr; sr; sr = sr_next) { sr_next = sr->sr_next; if (sr->sr_usage == du) { sr->sr_usage = NULL; if (sr != sr0) nua_server_request_destroy(sr); } } su_home_unref(own); su_free(own, du); } /* Zap dialog if there are no more usages */ if (ds->ds_terminating) ; else if (ds->ds_usage == NULL) { nua_dialog_remove(own, ds, NULL); ds->ds_has_events = 0; return; } else { nua_dialog_log_usage(own, ds); } }
static void nua_client_request_destroy(nua_client_request_t *cr) { nua_handle_t *nh; if (cr == NULL) return; /* Possible references: */ assert(cr->cr_prev == NULL); /* queue */ assert(cr->cr_orq == NULL); /* transaction callback */ assert(cr->cr_timer == NULL); /* timer callback */ nh = cr->cr_owner; nua_destroy_signal(cr->cr_signal); nua_client_bind(cr, NULL); #if HAVE_MEMLEAK_LOG SU_DEBUG_0(("%p %s for %s\n", cr, __func__, cr->cr_methods->crm_method_name)); #endif if (cr->cr_msg) msg_destroy(cr->cr_msg); cr->cr_msg = NULL, cr->cr_sip = NULL; if (cr->cr_orq) nta_outgoing_destroy(cr->cr_orq), cr->cr_orq = NULL; if (cr->cr_target) su_free(nh->nh_home, cr->cr_target); su_free(nh->nh_home, cr); nua_handle_unref(nh); }
static int nua_notify_client_request(nua_client_request_t *cr, msg_t *msg, sip_t *sip, tagi_t const *tags) { nua_dialog_usage_t *du = cr->cr_usage; struct notifier_usage *nu = nua_dialog_usage_private(du); su_home_t *home = msg_home(msg); sip_time_t now = sip_now(); sip_subscription_state_t *ss = sip->sip_subscription_state; char const *expires; if (du == NULL) /* Subscription has been terminated */ return nua_client_return(cr, SIP_481_NO_TRANSACTION, msg); assert(du && nu); if (du && nua_client_bind(cr, du) < 0) return -1; if (nu->nu_requested) nu->nu_expires = nu->nu_requested; nu->nu_requested = 0; if (nu->nu_expires <= now || du->du_shutdown) { nu->nu_substate = nua_substate_terminated; expires = "expires=0"; } else { expires = su_sprintf(home, "expires=%lu", nu->nu_expires - now); } if (ss == NULL || nua_substate_make(ss->ss_substate) != nu->nu_substate) { if (nu->nu_substate == nua_substate_terminated) expires = nu->nu_expires > now ? "reason=noresource" : "reason=timeout"; ss = sip_subscription_state_format(home, "%s;%s", nua_substate_name(nu->nu_substate), expires); msg_header_insert(msg, (void *)sip, (void *)ss); } else if (nu->nu_substate != nua_substate_terminated) { msg_header_replace_param(home, ss->ss_common, expires); } #if SU_HAVE_EXPERIMENTAL if (nu->nu_tag && !sip->sip_etag) msg_header_add_make(msg, (void *)sip, sip_etag_class, nu->nu_tag); if (nu->nu_no_body) { nu->nu_no_body = 0; msg_header_remove(msg, (void *)sip, (void *)sip->sip_payload); msg_header_remove(msg, (void *)sip, (void *)sip->sip_content_length); } #endif if (nu->nu_substate == nua_substate_terminated) nua_client_set_terminating(cr, 1); if (cr->cr_terminating) { nua_server_request_t *sr; for (sr = du->du_dialog->ds_sr; sr; sr = sr->sr_next) { if (sr->sr_usage == du) { /* If subscribe has not been responded, don't terminate usage by NOTIFY */ sr->sr_terminating = 1; nua_client_set_terminating(cr, 0); break; } } } if (du->du_event && !sip->sip_event) sip_add_dup(cr->cr_msg, sip, (sip_header_t *)du->du_event); return nua_base_client_request(cr, msg, sip, tags); }