/* Return Via that looks very natted */ static sip_via_t *natted_via(struct message *m, const char *receive_natted) { su_home_t *h; sip_via_t *via; h = msg_home(m->msg); via = sip_via_dup(h, m->sip->sip_via); msg_header_replace_param(h, via->v_common, receive_natted); if (via->v_protocol == sip_transport_udp) msg_header_replace_param(h, via->v_common, "rport=9"); if (via->v_protocol == sip_transport_tcp && via->v_rport) { tp_name_t const *tpn = tport_name(m->tport); char *rport = su_sprintf(h, "rport=%s", tpn->tpn_port); msg_header_replace_param(h, via->v_common, rport); } return via; }
/**Set new contact. * * @retval 0 when successful * @retval -1 error setting contact */ int outbound_set_contact(outbound_t *ob, sip_contact_t const *application_contact, sip_via_t const *v, int terminating) { su_home_t *home = ob->ob_home; sip_contact_t *rcontact = NULL, *dcontact = NULL, *previous = NULL; sip_contact_t *m1, *m2, *m3; int contact_uri_changed = 0; m1 = ob->ob_rcontact; m2 = ob->ob_dcontact; m3 = ob->ob_previous; if (terminating) { if (ob->ob_by_stack && application_contact == NULL) return 0; if (ob->ob_contacts) previous = ob->ob_rcontact; } else if (application_contact) { rcontact = sip_contact_dup(home, application_contact); if (!ob->ob_rcontact || url_cmp_all(ob->ob_rcontact->m_url, application_contact->m_url)) { contact_uri_changed = 1; previous = ob->ob_contacts ? ob->ob_rcontact : NULL; } } else if (ob->ob_by_stack) { return 0; /* Xyzzy - nothing happens */ } else if (v) { char const *tport = !v->v_next ? v->v_protocol : NULL; char reg_id_param[20]; dcontact = ob->ob_oo->oo_contact(ob->ob_owner, home, 1, v, tport, NULL); if (!dcontact) return -1; if (ob->ob_instance && ob->ob_reg_id != 0) snprintf(reg_id_param, sizeof reg_id_param, ";reg-id=%u", ob->ob_reg_id); rcontact = ob->ob_oo->oo_contact(ob->ob_owner, home, 0, v, v->v_protocol, ob->ob_instance, reg_id_param, NULL); if (!rcontact) return -1; if (!ob->ob_rcontact || url_cmp_all(ob->ob_rcontact->m_url, rcontact->m_url)) { contact_uri_changed = 1; previous = ob->ob_contacts ? ob->ob_rcontact : NULL; } } if (previous) msg_header_replace_param(home, (msg_common_t *)previous, "expires=0"); ob->ob_by_stack = application_contact == NULL; ob->ob_contacts = rcontact != NULL; ob->ob_rcontact = rcontact; ob->ob_dcontact = dcontact; ob->ob_previous = previous; if (contact_uri_changed) { ob->ob_registering = 0; ob->ob_registered = 0; ob->ob_validated = 0; ob->ob_once_validated = 0; } if (m1 != previous) msg_header_free(home, (void *)m1); if (m2 != m1 && m2 != m3) msg_header_free(home, (void *)m2); msg_header_free(home, (void *)m3); return 0; }
/**@internal * Create contacts for outbound. * * There are two contacts: * one suitable for registrations (ob_rcontact) and another that can be used * in dialogs (ob_dcontact). */ int outbound_contacts_from_via(outbound_t *ob, sip_via_t const *via) { su_home_t *home = ob->ob_home; sip_contact_t *rcontact, *dcontact; char reg_id_param[20] = ""; sip_contact_t *previous_previous, *previous_rcontact, *previous_dcontact; sip_via_t *v, v0[1], *previous_via; int contact_uri_changed; if (!via) return -1; v = v0; *v0 = *via; v0->v_next = NULL; dcontact = ob->ob_oo->oo_contact(ob->ob_owner, home, 1, v, v->v_protocol, NULL); if (ob->ob_instance && ob->ob_reg_id != 0) snprintf(reg_id_param, sizeof reg_id_param, ";reg-id=%u", ob->ob_reg_id); rcontact = ob->ob_oo->oo_contact(ob->ob_owner, home, 0, v, v->v_protocol, ob->ob_instance, reg_id_param, NULL); v = sip_via_dup(home, v); if (!rcontact || !dcontact || !v) { msg_header_free(home, (void *)dcontact); if (rcontact != dcontact) msg_header_free(home, (void *)rcontact); msg_header_free(home, (void *)v); return -1; } contact_uri_changed = !ob->ob_rcontact || url_cmp_all(ob->ob_rcontact->m_url, rcontact->m_url); if (contact_uri_changed) { previous_previous = ob->ob_previous; previous_dcontact = ob->ob_dcontact; previous_via = ob->ob_via; if (ob->ob_registered /* && (ob->ob_reg_id == 0 || ob->ob_info.outbound < outbound_feature_supported) * XXX - multiple connections not yet supported */) previous_rcontact = NULL, ob->ob_previous = ob->ob_rcontact; else previous_rcontact = ob->ob_rcontact, ob->ob_previous = NULL; if (ob->ob_previous) msg_header_replace_param(home, (void*)ob->ob_previous, "expires=0"); } else { previous_previous = ob->ob_rcontact; previous_rcontact = NULL; previous_dcontact = ob->ob_dcontact; previous_via = ob->ob_via; } ob->ob_contacts = 1; ob->ob_rcontact = rcontact; ob->ob_dcontact = dcontact; ob->ob_via = v; if (contact_uri_changed) { ob->ob_registering = 0; ob->ob_registered = 0; ob->ob_validated = 0; } msg_header_free(home, (void *)previous_rcontact); msg_header_free(home, (void *)previous_previous); if (previous_dcontact != ob->ob_previous && previous_dcontact != previous_rcontact && previous_dcontact != previous_previous) msg_header_free(home, (void *)previous_dcontact); msg_header_free(home, (void *)previous_via); return 0; }
/**@ingroup sip_caller_prefs * * Add a parameter to a @AcceptContact or @RejectContact header object. * * @note This function does not duplicate @p param. * * @param home memory home * @param cp pointer to #sip_accept_contact_t or #sip_reject_contact_t * @param param parameter string * * @retval 0 when successful * @retval -1 upon an error * * @deprecated Use msg_header_replace_param() instead. */ int sip_caller_prefs_add_param(su_home_t *home, sip_caller_prefs_t *cp, char const *param) { return msg_header_replace_param(home, cp->cp_common, param); }
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); }