📄 nua_register.c
字号:
NH_PGET(nh, instance)); if (!ob) goto error; } if (ob) { outbound_set_options(ob, NH_PGET(nh, outbound), NH_PGET(nh, keepalive), NH_PISSET(nh, keepalive_stream) ? NH_PGET(nh, keepalive_stream) : NH_PGET(nh, keepalive)); nua_stack_outbound_features(nh, ob); outbound_stop_keepalive(ob); if (outbound_set_contact(ob, sip->sip_contact, nr->nr_contact, terminating) < 0) goto error; } /* This calls nta_outgoing_mcreate() but adds a few tags */ cr->cr_orq = outbound_register_request(ob, terminating, nr->nr_by_stack ? nr->nr_contact : NULL, nua->nua_nta, process_response_to_register, nh, NULL, msg, SIPTAG_END(), TAG_IF(terminating, NTATAG_SIGCOMP_CLOSE(1)), TAG_IF(!terminating, NTATAG_COMP("sigcomp")), TAG_NEXT(tags)); if (!cr->cr_orq) goto error; cr->cr_usage = du; return cr->cr_event = e; error: msg_destroy(msg); msg_destroy(cr->cr_msg), cr->cr_msg = NULL; nua_dialog_usage_remove(nh, nh->nh_ds, du); return UA_EVENT1(e, NUA_INTERNAL_ERROR);}static voidrestart_register(nua_handle_t *nh, tagi_t *tags){ struct nua_client_request *cr = nh->nh_cr; msg_t *msg; nua_dialog_usage_t *du = cr->cr_usage; nua_registration_t *nr = nua_dialog_usage_private(du); int terminating = du && du->du_terminating; cr->cr_restart = NULL; if (!cr->cr_msg) return; msg = nua_creq_msg(nh->nh_nua, nh, cr, 1, SIP_METHOD_UNKNOWN, TAG_NEXT(tags)); if (!msg) return; /* XXX - Uh-oh */ if (terminating) unregister_expires_contacts(msg, sip_object(msg)); /* This calls nta_outgoing_mcreate() but adds a few tags */ cr->cr_orq = outbound_register_request(nr->nr_ob, terminating, nr->nr_by_stack ? nr->nr_contact : NULL, nh->nh_nua->nua_nta, process_response_to_register, nh, NULL, msg, SIPTAG_END(), TAG_IF(terminating, NTATAG_SIGCOMP_CLOSE(1)), TAG_IF(!terminating, NTATAG_COMP("sigcomp")), TAG_NEXT(tags)); if (!cr->cr_orq) msg_destroy(msg);}voidrefresh_register(nua_handle_t *nh, nua_dialog_usage_t *du, sip_time_t now){ nua_t *nua = nh->nh_nua; nua_client_request_t *cr = nh->nh_cr; nua_registration_t *nr = nua_dialog_usage_private(du); nua_event_t e; msg_t *msg; sip_t *sip; int terminating; if (cr->cr_msg) { /* Delay of 5 .. 15 seconds */ nua_dialog_usage_set_refresh(du, 5 + (unsigned)random() % 11U); du->du_pending = refresh_register; return; } if (now > 0) e = nua_r_register; else e = nua_r_destroy, du->du_terminating = 1; terminating = du->du_terminating; outbound_stop_keepalive(nr->nr_ob); cr->cr_msg = msg_copy(du->du_msg); msg = nua_creq_msg(nua, nh, cr, 1, SIP_METHOD_REGISTER, NUTAG_USE_DIALOG(1), TAG_END()); sip = sip_object(msg); if (!msg || !sip) goto error; if (terminating) unregister_expires_contacts(msg, sip); cr->cr_orq = outbound_register_request(nr->nr_ob, terminating, nr->nr_by_stack ? nr->nr_contact : NULL, nh->nh_nua->nua_nta, process_response_to_register, nh, NULL, msg, SIPTAG_END(), TAG_IF(terminating, NTATAG_SIGCOMP_CLOSE(1)), TAG_IF(!terminating, NTATAG_COMP("sigcomp")), TAG_END()); if (!cr->cr_orq) goto error; cr->cr_usage = du; cr->cr_event = e; return; error: if (terminating) nua_dialog_usage_remove(nh, nh->nh_ds, du); msg_destroy(msg); msg_destroy(cr->cr_msg); UA_EVENT2(e, NUA_INTERNAL_ERROR, TAG_END()); return;}staticint process_response_to_register(nua_handle_t *nh, nta_outgoing_t *orq, sip_t const *sip){ struct nua_client_request *cr = nh->nh_cr; nua_dialog_usage_t *du = cr->cr_usage; nua_registration_t *nr = nua_dialog_usage_private(du); int status, ready, reregister, terminating; char const *phrase; msg_t *_reqmsg = nta_outgoing_getrequest(orq); sip_t *req = sip_object(_reqmsg); msg_destroy(_reqmsg); assert(sip); assert(du && du->du_class == nua_register_usage); status = sip->sip_status->st_status; phrase = sip->sip_status->st_phrase; if (status < 200 || !du) return nua_stack_process_response(nh, cr, orq, sip, TAG_END()); terminating = du->du_terminating; if (!terminating) nua_dialog_store_peer_info(nh, nh->nh_ds, sip); reregister = outbound_register_response(nr->nr_ob, terminating, req, sip); if (reregister < 0) SET_STATUS1(NUA_INTERNAL_ERROR); else if (reregister >= ob_reregister) { /* Save msg otherwise nua_creq_check_restart() will zap it */ msg_t *msg = msg_ref_create(cr->cr_msg); if (nua_creq_check_restart(nh, cr, orq, sip, restart_register)) { msg_destroy(msg); return 0; } assert(cr->cr_msg == NULL); cr->cr_msg = msg; if (reregister >= ob_reregister_now) { /* We can try to reregister immediately */ nua_creq_restart_with(nh, cr, orq, 100, "Updated Contact", restart_register, TAG_END()); } else { /* Outbound will invoke refresh_register() later */ nua_creq_save_restart(nh, cr, orq, 100, "Updated Contact", restart_register); } return 0; } if (status >= 300) if (nua_creq_check_restart(nh, cr, orq, sip, restart_register)) return 0; ready = !terminating && status < 300; du->du_ready = ready; if (status < 300) { sip_time_t mindelta = 0; if (!du->du_terminating) { sip_time_t now = sip_now(), delta, reqdelta; sip_contact_t const *m, *sent; /** Search for lowest delta of SIP contacts we tried to register */ mindelta = SIP_TIME_MAX; reqdelta = req->sip_expires ? req->sip_expires->ex_delta : 0; for (m = sip->sip_contact; m; m = m->m_next) { if (m->m_url->url_type != url_sip && m->m_url->url_type != url_sips) continue; for (sent = req->sip_contact; sent; sent = sent->m_next) if (url_cmp(m->m_url, sent->m_url) == 0) { sip_time_t mdelta = reqdelta; if (sent->m_expires) mdelta = strtoul(sent->m_expires, NULL, 10); if (mdelta == 0) mdelta = 3600; delta = sip_contact_expires(m, sip->sip_expires, sip->sip_date, mdelta, now); if (delta > 0 && delta < mindelta) mindelta = delta; if (url_cmp_all(m->m_url, sent->m_url) == 0) break; } } if (mindelta == SIP_TIME_MAX) mindelta = 3600; } nua_dialog_usage_set_refresh(du, mindelta); if (mindelta) du->du_pending = refresh_register; }#if HAVE_SIGCOMP if (ready) { struct sigcomp_compartment *cc; cc = nta_outgoing_compartment(orq); sigcomp_compartment_unref(nr->nr_compartment); nr->nr_compartment = cc; }#endif /* RFC 3608 Section 6.1 Procedures at the UA The UA performs a registration as usual. The REGISTER response may contain a Service-Route header field. If so, the UA MAY store the value of the Service-Route header field in an association with the address-of-record for which the REGISTER transaction had registered a contact. If the UA supports multiple addresses-of-record, it may be able to store multiple service routes, one per address-of-record. If the UA refreshes the registration, the stored value of the Service- Route is updated according to the Service-Route header field of the latest 200 class response. If there is no Service-Route header field in the response, the UA clears any service route for that address- of-record previously stored by the UA. If the re-registration request is refused or if an existing registration expires and the UA chooses not to re-register, the UA SHOULD discard any stored service route for that address-of-record. */ if (ready) { su_free(nh->nh_home, nr->nr_route); nr->nr_route = sip_route_dup(nh->nh_home, sip->sip_service_route); } else { su_free(nh->nh_home, nr->nr_route); nr->nr_route = NULL; } if (ready) { /* RFC 3327 */ /* Store last URI in Path header */ sip_path_t *path = sip->sip_path; while (path && path->r_next) path = path->r_next; if (!nr->nr_path || !path || url_cmp_all(nr->nr_path->r_url, path->r_url)) { su_free(nh->nh_home, nr->nr_path); nr->nr_path = sip_path_dup(nh->nh_home, path); } } if (ready) if (sip->sip_to->a_url->url_type == url_sips) nr->nr_secure = 1; if (nr->nr_ob) { if (ready) { outbound_gruuize(nr->nr_ob, sip); outbound_start_keepalive(nr->nr_ob, orq); } else outbound_stop_keepalive(nr->nr_ob); } nua_registration_set_ready(nr, ready); return nua_stack_process_response(nh, cr, orq, sip, TAG_END());}/* ---------------------------------------------------------------------- *//* nua_registration_t interface */#if HAVE_SOFIA_STUN#include <sofia-sip/stun.h>#endifstatic void nua_stack_tport_update(nua_t *nua, nta_agent_t *nta);intnua_stack_init_transport(nua_t *nua, tagi_t const *tags){ url_string_t const *contact1 = NULL, *contact2 = NULL; char const *name1 = "sip", *name2 = "sip"; char const *certificate_dir = NULL; tl_gets(tags, NUTAG_URL_REF(contact1), NUTAG_SIPS_URL_REF(contact2), NUTAG_CERTIFICATE_DIR_REF(certificate_dir), TAG_END()); if (!contact1 && contact2) contact1 = contact2, contact2 = NULL; if (contact1 && (url_is_string(contact1) ? strncasecmp(contact1->us_str, "sips:", 5) == 0 : contact1->us_url->url_type == url_sips)) name1 = "sips"; if (contact2 && (url_is_string(contact2) ? strncasecmp(contact2->us_str, "sips:", 5) == 0 : contact2->us_url->url_type == url_sips)) name2 = "sips"; if (!contact1 /* && !contact2 */) { if (nta_agent_add_tport(nua->nua_nta, NULL, TPTAG_IDENT("sip"), TPTAG_CERTIFICATE(certificate_dir), TAG_NEXT(nua->nua_args)) < 0 && nta_agent_add_tport(nua->nua_nta, URL_STRING_MAKE("sip:*:*"), TPTAG_IDENT("sip"), TPTAG_CERTIFICATE(certificate_dir), TAG_NEXT(nua->nua_args)) < 0) return -1;#if HAVE_SOFIA_STUN if (stun_is_requested(TAG_NEXT(nua->nua_args)) && nta_agent_add_tport(nua->nua_nta, URL_STRING_MAKE("sip:0.0.0.0:*"), TPTAG_IDENT("stun"), TPTAG_PUBLIC(tport_type_stun), /* use stun */ TPTAG_CERTIFICATE(certificate_dir), TAG_NEXT(nua->nua_args)) < 0) { SU_DEBUG_0(("nua: error initializing STUN transport\n")); }#endif } else { if (nta_agent_add_tport(nua->nua_nta, contact1, TPTAG_IDENT(name1), TPTAG_CERTIFICATE(certificate_dir), TAG_NEXT(nua->nua_args)) < 0) return -1; if (contact2 && nta_agent_add_tport(nua->nua_nta, contact2, TPTAG_IDENT(name2), TPTAG_CERTIFICATE(certificate_dir), TAG_NEXT(nua->nua_args)) < 0) return -1; } if (nua_stack_init_registrations(nua) < 0) return -1; return 0;}intnua_stack_init_registrations(nua_t *nua){ /* Create initial identities: peer-to-peer, public, sips */ nua_registration_t **list = &nua->nua_registrations; su_home_t *home = nua->nua_dhandle->nh_home; sip_via_t const *v; v = nta_agent_public_via(nua->nua_nta); if (v) { nua_registration_from_via(list, home, v, 1); } v = nta_agent_via(nua->nua_nta); if (v) { nua_registration_from_via(list, home, v, 0); } else { sip_via_t v[2]; sip_via_init(v)->v_next = v + 1; v[0].v_protocol = sip_transport_udp; v[0].v_host = "addr.is.invalid."; sip_via_init(v + 1); v[1].v_protocol = sip_transport_tcp; v[1].v_host = "addr.is.invalid."; nua_registration_from_via(list, home, v, 0); } nta_agent_bind_tport_update(nua->nua_nta, nua, nua_stack_tport_update); return 0;}int nua_registration_from_via(nua_registration_t **list, su_home_t *home, sip_via_t const *via, int public){ sip_via_t *v, *pair, /* v2[2], */ *vias, **vv, **prev; nua_registration_t *nr = NULL, **next; su_home_t autohome[SU_HOME_AUTO_SIZE(1024)]; int nr_items = 0; vias = sip_via_copy(su_home_auto(autohome, sizeof autohome), via); for (; *list; list = &(*list)->nr_next) ++nr_items; next = list; for (vv = &vias; (v = *vv);) { char const *protocol; sip_contact_t *contact; *vv = v->v_next, v->v_next = NULL, pair = NULL; if (v->v_protocol == sip_transport_tcp) protocol = sip_transport_udp; else if (v->v_protocol == sip_transport_udp) protocol = sip_transport_tcp; else protocol = NULL; if (protocol) { /* Try to pair vias if we have both udp and tcp */ for (prev = vv; *prev; prev = &(*prev)->v_next) { if (strcasecmp(protocol, (*prev)->v_protocol)) continue; if (strcasecmp(v->v_host, (*prev)->v_host)) continue; if (str0cmp(v->v_port, (*prev)->v_port)) continue; break; } if (*prev) { pair = *prev; *prev = pair->v_next; pair->v_next = NULL; } } /* if more than one candidate, ignore local entries */ if (v && (*vv || nr_items > 0) && host_is_local(v->v_host)) { SU_DEBUG_9(("nua_register: ignoring contact candidate %s:%s.\n", v->v_host, v->v_port ? v->v_port : "")); continue; } nr = su_zalloc(home, sizeof *nr); if (!nr) break; /* v2[0] = *v; */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -