📄 nua_subnotref.c
字号:
SET_STATUS1(SIP_200_OK); if (status < 300) { nr = nua_registration_by_aor(nua->nua_registrations, sip->sip_to, sip->sip_request->rq_url, 0); m = nua_registration_contact(nr); if (m == NULL) { SET_STATUS1(SIP_500_INTERNAL_SERVER_ERROR); eu->eu_substate = nua_substate_terminated; } } nta_incoming_treply(irq, status, phrase, SIPTAG_CONTACT(m), NULL); nua_stack_event(nua, nh, nta_incoming_getrequest(irq), nua_i_subscribe, status, phrase, NUTAG_SUBSTATE(eu->eu_substate), TAG_END()); nta_incoming_destroy(irq), irq = NULL; /* Immediate notify */ if (status < 300) nua_stack_post_signal(nh, nua_r_notify, SIPTAG_EVENT(du->du_event), TAG_END()); return 0;}/* ======================================================================== *//* NOTIFY */static int process_response_to_notify(nua_handle_t *nh, nta_outgoing_t *orq, sip_t const *sip);intnua_stack_notify(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags){ struct nua_client_request *cr = nh->nh_cr; nua_dialog_usage_t *du = NULL; struct event_usage *eu; msg_t *msg; sip_t *sip; if (cr->cr_orq) { return UA_EVENT2(e, 500, "Request already in progress"); } nua_stack_init_handle(nua, nh, nh_has_nothing, NULL, TAG_NEXT(tags)); msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count, SIP_METHOD_NOTIFY, NUTAG_ADD_CONTACT(1), TAG_NEXT(tags)); sip = sip_object(msg); if (!sip) return UA_EVENT1(e, NUA_INTERNAL_ERROR); du = nua_dialog_usage_get(nh->nh_ds, nua_notify_usage, sip->sip_event); eu = nua_dialog_usage_private(du); if (du && du->du_event && !sip->sip_event) sip_add_dup(msg, sip, (sip_header_t *)du->du_event); if (!du) ; else if (sip->sip_subscription_state) { char const *ss_substate = sip->sip_subscription_state->ss_substate; sip_time_t now = sip_now(); if (strcasecmp(ss_substate, "terminated") == 0) eu->eu_substate = nua_substate_terminated; else if (strcasecmp(ss_substate, "pending") == 0) eu->eu_substate = nua_substate_pending; else /* if (strcasecmp(subs->ss_substate, "active") == 0) */ eu->eu_substate = nua_substate_active; if (sip->sip_subscription_state->ss_expires) { unsigned long expires; expires = strtoul(sip->sip_subscription_state->ss_expires, NULL, 10); if (expires > 3600) expires = 3600; du->du_refresh = now + expires; } else if (eu->eu_substate != nua_substate_terminated) { sip_subscription_state_t *ss = sip->sip_subscription_state; char *param; if (now < du->du_refresh) param = su_sprintf(msg_home(msg), "expires=%lu", du->du_refresh - now); else param = "expires=0"; msg_header_add_param(msg_home(msg), ss->ss_common, param); } } else { sip_subscription_state_t *ss; char const *substate; sip_time_t now = sip_now(); unsigned long expires = 3600; switch (eu->eu_substate) { case nua_substate_embryonic: eu->eu_substate = nua_substate_pending; /*FALLTHROUGH*/ case nua_substate_pending: substate = "pending"; break; case nua_substate_active: default: substate = "active"; break; case nua_substate_terminated: substate = "terminated"; break; } if (du->du_refresh <= now) eu->eu_substate = nua_substate_terminated; if (eu->eu_substate != nua_substate_terminated) { if (du->du_refresh) expires = du->du_refresh - now; else du->du_refresh = now + expires; ss = sip_subscription_state_format(msg_home(msg), "%s;expires=%lu", substate, expires); } else { du->du_refresh = now; ss = sip_subscription_state_make(msg_home(msg), "terminated; " "reason=noresource"); } msg_header_insert(msg, (void *)sip, (void *)ss); } if (du) { if (eu->eu_substate == nua_substate_terminated) du->du_terminating = 1; cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta, process_response_to_notify, nh, NULL, msg, SIPTAG_END(), TAG_NEXT(tags)); } if (!cr->cr_orq) { msg_destroy(msg); return UA_EVENT1(e, NUA_INTERNAL_ERROR); } cr->cr_usage = du; return cr->cr_event = e;}staticvoid restart_notify(nua_handle_t *nh, tagi_t *tags){ nua_creq_restart(nh, nh->nh_cr, process_response_to_notify, tags);}static int process_response_to_notify(nua_handle_t *nh, nta_outgoing_t *orq, sip_t const *sip){ if (nua_creq_check_restart(nh, nh->nh_cr, orq, sip, restart_notify)) return 0; return nua_stack_process_response(nh, nh->nh_cr, orq, sip, TAG_END());}/** @internal Process incoming NOTIFY. */int nua_stack_process_notify(nua_t *nua, nua_handle_t *nh, nta_incoming_t *irq, sip_t const *sip){ nua_dialog_state_t *ds = nh->nh_ds; nua_dialog_usage_t *du; struct event_usage *eu; sip_subscription_state_t *subs = sip ? sip->sip_subscription_state : NULL; sip_subscription_state_t ss0[1]; msg_t *response; char expires[32]; int retry = -1; char const *what = NULL, *why = NULL; enter; if (nh == NULL) { nta_incoming_treply(irq, 481, "Subscription Does Not Exist", TAG_END()); return 481; } assert(nh); if (/* XXX - support forking of subscriptions?... */ ds->ds_remote_tag && sip && sip->sip_from->a_tag && strcmp(ds->ds_remote_tag, sip->sip_from->a_tag)) { sip_contact_t const *m = NULL; sip_warning_t *w = NULL, w0[1]; m = nua_stack_get_contact(nua->nua_registrations); if (m) { w = sip_warning_init(w0); w->w_code = 399; w->w_host = m->m_url->url_host; w->w_port = m->m_url->url_port; w->w_text = "Forking SUBSCRIBEs are not supported"; } nta_incoming_treply(irq, 481, "Subscription Does Not Exist", SIPTAG_WARNING(w), TAG_END()); return 481; } du = nua_dialog_usage_get(nh->nh_ds, nua_subscribe_usage, sip->sip_event); if (du == NULL) { nta_incoming_treply(irq, 481, "Subscription Does Not Exist", TAG_END()); return 481; } eu = nua_dialog_usage_private(du); assert(eu); if (subs == NULL) { /* Do some compatibility stuff here */ unsigned long delta = 3600; sip_subscription_state_init(subs = ss0); if (sip->sip_expires) delta = sip->sip_expires->ex_delta; else delta = eu->eu_expires; if (delta == 0) subs->ss_substate = "terminated"; else subs->ss_substate = "active"; if (delta > 0) { snprintf(expires, sizeof expires, "%lu", delta); subs->ss_expires = expires; } } nua_dialog_store_peer_info(nh, nh->nh_ds, sip); nua_dialog_uas_route(nh, nh->nh_ds, sip, 1); if (strcasecmp(subs->ss_substate, what = "terminated") == 0) { eu->eu_substate = nua_substate_terminated; if (str0casecmp(subs->ss_reason, why = "deactivated") == 0) { eu->eu_substate = nua_substate_embryonic; retry = 0; } else if (str0casecmp(subs->ss_reason, why = "probation") == 0) { eu->eu_substate = nua_substate_embryonic; retry = 30; if (subs->ss_retry_after) retry = strtoul(subs->ss_retry_after, NULL, 10); } else why = subs->ss_reason; } else if (strcasecmp(subs->ss_substate, what = "pending") == 0) eu->eu_substate = nua_substate_pending; else /* if (strcasecmp(subs->ss_substate, "active") == 0) */ { what = subs->ss_substate ? subs->ss_substate : "active"; /* XXX - any extended state is considered as active */ eu->eu_substate = nua_substate_active; } response = nh_make_response(nua, nh, irq, SIP_200_OK, SIPTAG_ALLOW(NH_PGET(nh, allow)), SIPTAG_SUPPORTED(NH_PGET(nh, supported)), TAG_END()); if (response && nua_registration_add_contact(nh, response, NULL, 1, 0) >= 0) nta_incoming_mreply(irq, response); else nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR, TAG_END()); nua_stack_event(nh->nh_nua, nh, nta_incoming_getrequest(irq), nua_i_notify, SIP_200_OK, NUTAG_SUBSTATE(eu->eu_substate), TAG_END()); nta_incoming_destroy(irq), irq = NULL; SU_DEBUG_5(("nua(%p): nua_stack_process_notify: %s (%s)\n", nh, what, why ? why : "")); if (eu->eu_substate == nua_substate_terminated) { du->du_refresh = 0, du->du_pending = NULL; if (du != nh->nh_cr->cr_usage) nua_dialog_usage_remove(nh, nh->nh_ds, du); } else if (eu->eu_substate == nua_substate_embryonic) { if (retry != -1 && !du->du_terminating) { /* Try to subscribe again */ /* XXX - how to handle dialog ?? */ nua_dialog_usage_set_refresh(du, retry); du->du_pending = refresh_subscribe; } else if (du != nh->nh_cr->cr_usage) nua_dialog_usage_remove(nh, nh->nh_ds, du); } else if (subs->ss_expires) { sip_time_t delta = strtoul(subs->ss_expires, NULL, 10); if (!du->du_terminating) { nua_dialog_usage_set_refresh(du, delta); du->du_pending = refresh_subscribe; } } return 0;}/* ======================================================================== *//* REFER */static int process_response_to_refer(nua_handle_t *nh, nta_outgoing_t *orq, sip_t const *sip);intnua_stack_refer(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags){ nua_dialog_usage_t *du = NULL; struct nua_client_request *cr = nh->nh_cr; msg_t *msg; sip_t *sip; sip_referred_by_t by[1]; sip_event_t *event = NULL; if (nh_is_special(nh) && !nua_handle_has_subscribe(nh)) { return UA_EVENT2(e, 500, "Invalid handle for REFER"); } else if (cr->cr_orq) { return UA_EVENT2(e, 500, "Request already in progress"); } nua_stack_init_handle(nua, nh, nh_has_subscribe, "NOTIFY", TAG_NEXT(tags)); if (nh->nh_has_subscribe) nh->nh_special = nua_r_subscribe; sip_referred_by_init(by); by->b_display = nua->nua_from->a_display; *by->b_url = *nua->nua_from->a_url; /* Now we create a REFER request message */ msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count, SIP_METHOD_REFER, NUTAG_USE_DIALOG(1), SIPTAG_EVENT(SIP_NONE), /* remove event */ SIPTAG_REFERRED_BY(by), /* Overriden by user tags */ NUTAG_ADD_CONTACT(1), TAG_NEXT(tags)); sip = sip_object(msg); if (sip && sip->sip_cseq) event = sip_event_format(nh->nh_home, "refer;id=%u", sip->sip_cseq->cs_seq); if (event) du = nua_dialog_usage_add(nh, nh->nh_ds, nua_subscribe_usage, event); if (du) cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta, process_response_to_refer, nh, NULL, msg, SIPTAG_END(), TAG_NEXT(tags)); if (!cr->cr_orq) { if (du) nua_dialog_usage_remove(nh, nh->nh_ds, du); su_free(nh->nh_home, event); msg_destroy(msg); return UA_EVENT1(e, NUA_INTERNAL_ERROR); } /* * We send a 100 trying event so that application gets a event * it can use to match NOTIFYs with its REFER */ nua_stack_event(nua, nh, NULL, e, SIP_100_TRYING, NUTAG_REFER_EVENT(event), TAG_END()); su_free(nh->nh_home, event); cr->cr_usage = du; return cr->cr_event = e;}void restart_refer(nua_handle_t *nh, tagi_t *tags){ nua_stack_refer(nh->nh_nua, nh, nh->nh_cr->cr_event, tags);}static int process_response_to_refer(nua_handle_t *nh, nta_outgoing_t *orq, sip_t const *sip){ struct nua_client_request *cr = nh->nh_cr; int status = sip ? sip->sip_status->st_status : 408; if (status < 200) ; else if (status < 300) { if (cr->cr_usage) cr->cr_usage->du_ready = 1; nua_dialog_uac_route(nh, nh->nh_ds, sip, 1); nua_dialog_store_peer_info(nh, nh->nh_ds, sip); } else /* if (status >= 300) */ { if (cr->cr_usage) nua_dialog_usage_remove(nh, nh->nh_ds, cr->cr_usage), cr->cr_usage = NULL; if (nua_creq_check_restart(nh, cr, orq, sip, restart_refer)) return 0; } return nua_stack_process_response(nh, cr, orq, sip, TAG_END());}/** @internal Process incoming REFER. */int nua_stack_process_refer(nua_t *nua, nua_handle_t *nh, nta_incoming_t *irq, sip_t const *sip){ nua_dialog_usage_t *du = NULL; sip_event_t *event; sip_referred_by_t *by = NULL, default_by[1]; msg_t *response; int created = 0; if (nh == NULL) { if (!(nh = nua_stack_incoming_handle(nua, irq, sip, nh_has_notify, 1))) return 500; created = 1; } event = sip_event_format(nh->nh_home, "refer;id=%u", sip->sip_cseq->cs_seq); if (event) du = nua_dialog_usage_add(nh, nh->nh_ds, nua_notify_usage, event); if (!du || du->du_ready) { if (du->du_ready) { SU_DEBUG_1(("nua(%p): REFER with existing refer;id=%u\n", nh, sip->sip_cseq->cs_seq)); } if (created) nh_destroy(nua, nh); return 500; } du->du_ready = 1; nua_dialog_uas_route(nh, nh->nh_ds, sip, 1); /* Set route and tags */ if (!sip->sip_referred_by) { sip_from_t *a = sip->sip_from; sip_referred_by_init(by = default_by); *by->b_url = *a->a_url; by->b_display = a->a_display; } response = nh_make_response(nua, nh, irq, SIP_202_ACCEPTED, NUTAG_ADD_CONTACT(1), TAG_END()); nta_incoming_mreply(irq, response); du->du_refresh = sip_now() + NH_PGET(nh, refer_expires); /* Immediate notify */ nua_stack_post_signal(nh, nua_r_notify, SIPTAG_EVENT(event), SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), SIPTAG_PAYLOAD_STR("SIP/2.0 100 Trying\r\n"), TAG_END()); nua_stack_event(nh->nh_nua, nh, nta_incoming_getrequest(irq), nua_i_refer, SIP_202_ACCEPTED, NUTAG_REFER_EVENT(event), TAG_IF(by, SIPTAG_REFERRED_BY(by)), TAG_END()); su_free(nh->nh_home, event); return 500; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -