/**Create a request belonging to the leg * (stdarg version of nta_outgoing_create()). * * @deprecated * Use nta_outgoing_tcreate() or nta_outgoing_mcreate() instead. */ nta_outgoing_t *nta_outgoing_vcreate(nta_leg_t *leg, nta_response_f *callback, nta_outgoing_magic_t *magic, url_string_t const *route_url, sip_method_t method, char const *name, url_string_t const *request_uri, void const *extra, va_list headers) { nta_agent_t *agent = leg->leg_agent; msg_t *msg = nta_msg_create(agent, 0); sip_t *sip = sip_object(msg); nta_outgoing_t *orq; if (extra && sip_add_headers(msg, sip, extra, headers) < 0) orq = NULL; else if (route_url && leg->leg_route && !sip->sip_route && sip_add_dup(msg, sip, (sip_header_t *)leg->leg_route) < 0) orq = NULL; else if (nta_msg_request_complete(msg, leg, method, name, request_uri) < 0) orq = NULL; else orq = nta_outgoing_mcreate(agent, callback, magic, route_url, msg); if (!orq) msg_destroy(msg); return orq; }
/** @internal Send a keepalive OPTIONS that probes the registration */ static int keepalive_options_with_registration_probe(outbound_t *ob) { msg_t *req; sip_t *sip; void *request_uri; if (ob->ob_keepalive.orq) return 0; req = msg_copy(ob->ob_keepalive.msg); if (!req) return -1; sip = sip_object(req); assert(sip); request_uri = sip->sip_to->a_url; if (nta_msg_request_complete(req, nta_default_leg(ob->ob_nta), SIP_METHOD_OPTIONS, request_uri) < 0) return msg_destroy(req), -1; if (ob->ob_keepalive.auc[0]) auc_authorization(ob->ob_keepalive.auc, req, (void *)sip, "OPTIONS", request_uri, sip->sip_payload); ob->ob_keepalive.orq = nta_outgoing_mcreate(ob->ob_nta, response_to_keepalive_options, ob, NULL, req, TAG_IF(ob->ob_proxy_override, NTATAG_DEFAULT_PROXY(ob->ob_proxy)), SIPTAG_SUBJECT_STR("REGISTRATION PROBE"), /* NONE is used to remove Max-Forwards: 0 found in ordinary keepalives */ SIPTAG_MAX_FORWARDS(SIP_NONE), TAG_END()); if (!ob->ob_keepalive.orq) return msg_destroy(req), -1; ob->ob_keepalive.validating = 1; ob->ob_keepalive.validated = 0; return 0; }
static int keepalive_options(outbound_t *ob) { msg_t *req; sip_t *sip; if (ob->ob_keepalive.orq) return 0; if (ob->ob_prefs.validate && ob->ob_registered && !ob->ob_validated) return keepalive_options_with_registration_probe(ob); req = msg_copy(ob->ob_keepalive.msg); if (!req) return -1; sip = sip_object(req); assert(sip); assert(sip->sip_request); if (nta_msg_request_complete(req, nta_default_leg(ob->ob_nta), SIP_METHOD_UNKNOWN, NULL) < 0) return msg_destroy(req), -1; if (ob->ob_keepalive.auc[0]) auc_authorization(ob->ob_keepalive.auc, req, (void *)sip, "OPTIONS", sip->sip_request->rq_url, sip->sip_payload); ob->ob_keepalive.orq = nta_outgoing_mcreate(ob->ob_nta, response_to_keepalive_options, ob, NULL, req, TAG_IF(ob->ob_proxy_override, NTATAG_DEFAULT_PROXY(ob->ob_proxy)), TAG_END()); if (!ob->ob_keepalive.orq) return msg_destroy(req), -1; return 0; }
/** @internal Create a message template for keepalive. */ static int create_keepalive_message(outbound_t *ob, sip_t const *regsip) { msg_t *msg = nta_msg_create(ob->ob_nta, MSG_FLG_COMPACT), *previous; sip_t *osip = sip_object(msg); sip_contact_t *m = ob->ob_rcontact; unsigned d = ob->ob_keepalive.interval; if (msg == NULL) return -1; assert(regsip); assert(regsip->sip_request); if (m && m->m_params) { sip_accept_contact_t *ac; size_t i; int features = 0; ac = sip_accept_contact_make(msg_home(msg), "*;require;explicit"); for (i = 0; m->m_params[i]; i++) { char const *s = m->m_params[i]; if (!sip_is_callerpref(s)) continue; features++; s = su_strdup(msg_home(msg), s); msg_header_add_param(msg_home(msg), ac->cp_common, s); } if (features) msg_header_insert(msg, NULL, (void *)ac); else msg_header_free(msg_home(msg), (void *)ac); } if (0 > /* Duplicate essential headers from REGISTER request: */ sip_add_tl(msg, osip, SIPTAG_TO(regsip->sip_to), SIPTAG_FROM(regsip->sip_from), /* XXX - we should only use loose routing here */ /* XXX - if we used strict routing, the route header/request_uri must be restored */ SIPTAG_ROUTE(regsip->sip_route), /* Add Max-Forwards 0 */ TAG_IF(d, SIPTAG_MAX_FORWARDS_STR("0")), TAG_IF(d, SIPTAG_SUBJECT_STR("KEEPALIVE")), SIPTAG_CALL_ID_STR(ob->ob_cookie), SIPTAG_ACCEPT_STR(outbound_content_type), TAG_END()) || /* Create request-line, Call-ID, CSeq */ nta_msg_request_complete(msg, nta_default_leg(ob->ob_nta), SIP_METHOD_OPTIONS, (void *)regsip->sip_to->a_url) < 0 || msg_serialize(msg, (void *)osip) < 0 || msg_prepare(msg) < 0) return msg_destroy(msg), -1; previous = ob->ob_keepalive.msg; ob->ob_keepalive.msg = msg; msg_destroy(previous); return 0; }
/**Send a request message. * * @retval 0 if request is pending * @retval >=1 if error event has been sent * @retval < 0 if no error event has been sent */ static int nua_client_request_sendmsg(nua_client_request_t *cr) { nua_handle_t *nh = cr->cr_owner; nua_dialog_state_t *ds = nh->nh_ds; sip_method_t method = cr->cr_method; char const *name = cr->cr_method_name; url_string_t const *url = (url_string_t *)cr->cr_target; nta_leg_t *leg; msg_t *msg; sip_t *sip; int error; assert(cr->cr_orq == NULL); cr->cr_offer_sent = cr->cr_answer_recv = 0; cr->cr_offer_recv = cr->cr_answer_sent = 0; if (!ds->ds_leg && cr->cr_dialog) { ds->ds_leg = nta_leg_tcreate(nh->nh_nua->nua_nta, nua_stack_process_request, nh, SIPTAG_CALL_ID(cr->cr_sip->sip_call_id), SIPTAG_FROM(cr->cr_sip->sip_from), SIPTAG_TO(cr->cr_sip->sip_to), SIPTAG_CSEQ(cr->cr_sip->sip_cseq), TAG_END()); if (!ds->ds_leg) return -1; } if (cr->cr_sip->sip_from && ds->ds_leg) { if (cr->cr_sip->sip_from->a_tag == NULL) { if (sip_from_tag(msg_home(cr->cr_msg), cr->cr_sip->sip_from, nta_leg_tag(ds->ds_leg, NULL)) < 0) { return -1; } } } cr->cr_retry_count++; if (ds->ds_leg) leg = ds->ds_leg; else leg = nh->nh_nua->nua_dhandle->nh_ds->ds_leg; /* Default leg */ msg = msg_copy(cr->cr_msg), sip = sip_object(msg); if (msg == NULL) return -1; if (nua_dialog_is_established(ds)) { while (sip->sip_route) sip_route_remove(msg, sip); } else if (!ds->ds_route) { sip_route_t *initial_route = NH_PGET(nh, initial_route); if (initial_route) { initial_route = sip_route_dup(msg_home(msg), initial_route); if (!initial_route) return -1; msg_header_prepend(msg, (msg_pub_t*)sip, /* This should be (msg_header_t **)&sip->sip_route * but directly casting pointer &sip->sip_route gives * spurious type-punning warning */ (msg_header_t **)((char *)sip + offsetof(sip_t, sip_route)), (msg_header_t *)initial_route); } } /** * For in-dialog requests, the request URI is taken from the @Contact * header received from the remote party during dialog establishment, * and the NUTAG_URL() is ignored. * * Also, the @CallID and @CSeq headers and @From and @To tags are * generated based on the dialog information and added to the request. * If the dialog has a route, it is added to the request, too. */ if (nta_msg_request_complete(msg, leg, method, name, url) < 0) { msg_destroy(msg); return -1; } /**@MaxForwards header (with default value set by NTATAG_MAX_FORWARDS()) is * also added now, if it does not exist. */ if (!ds->ds_remote) ds->ds_remote = sip_to_dup(nh->nh_home, sip->sip_to); if (!ds->ds_local) ds->ds_local = sip_from_dup(nh->nh_home, sip->sip_from); /** * Next, values previously set with nua_set_params() or nua_set_hparams() * are used: @Allow, @Supported, @Organization, @UserAgent and * @AllowEvents headers are added to the request if they are not already * set. */ if (!sip->sip_allow) sip_add_dup(msg, sip, (sip_header_t*)NH_PGET(nh, allow)); if (!sip->sip_supported && NH_PGET(nh, supported)) sip_add_dup(msg, sip, (sip_header_t *)NH_PGET(nh, supported)); if (method == sip_method_register && NH_PGET(nh, path_enable) && !sip_has_feature(sip->sip_supported, "path") && !sip_has_feature(sip->sip_require, "path")) sip_add_make(msg, sip, sip_supported_class, "path"); if (!sip->sip_organization && NH_PGET(nh, organization)) sip_add_make(msg, sip, sip_organization_class, NH_PGET(nh, organization)); if (!sip->sip_user_agent && NH_PGET(nh, user_agent)) sip_add_make(msg, sip, sip_user_agent_class, NH_PGET(nh, user_agent)); /** Any node implementing one or more event packages SHOULD include an * appropriate @AllowEvents header indicating all supported events in * all methods which initiate dialogs and their responses (such as * INVITE) and OPTIONS responses. */ if (!sip->sip_allow_events && NH_PGET(nh, allow_events) && (method == sip_method_notify || /* Always in NOTIFY */ (!ds->ds_remote_tag && /* And in initial requests */ (method == sip_method_subscribe || method == sip_method_refer || method == sip_method_options || method == sip_method_invite)))) sip_add_dup(msg, sip, (void *)NH_PGET(nh, allow_events)); /** * Next, the stack generates a @Contact header for the request (unless * the application already gave a @Contact header or it does not want to * use @Contact and indicates that by including SIPTAG_CONTACT(NULL) or * SIPTAG_CONTACT(SIP_NONE) in the tagged parameters.) If the * application has registered the URI in @From header, the @Contact * header used with registration is used. Otherwise, the @Contact header * is generated from the local IP address and port number. */ /**For the initial requests, @ServiceRoute set that was received from the * registrar is also added to the request message. */ if (cr->cr_method != sip_method_register) { if (cr->cr_contactize && cr->cr_has_contact) { sip_contact_t *ltarget = sip_contact_dup(nh->nh_home, sip->sip_contact); if (ds->ds_ltarget) msg_header_free(nh->nh_home, (msg_header_t *)ds->ds_ltarget); ds->ds_ltarget = ltarget; } if (ds->ds_ltarget && !cr->cr_has_contact) sip_add_dup(msg, sip, (sip_header_t *)ds->ds_ltarget); if (nua_registration_add_contact_to_request(nh, msg, sip, cr->cr_contactize && !cr->cr_has_contact && !ds->ds_ltarget, !ds->ds_route) < 0) { msg_destroy(msg); return -1; } } cr->cr_wait_for_cred = 0; if (cr->cr_methods->crm_send) error = cr->cr_methods->crm_send(cr, msg, sip, NULL); else error = nua_base_client_request(cr, msg, sip, NULL); if (error == -1) msg_destroy(msg); return error; }