/** * Create a new leg object * * @param agent agent object * @param callback function which is called for each * incoming request belonging to this leg * @param magic call leg context * @param i optional @CallID * (if @c NULL, an ID generated by @b NTA is used) * @param from optional @From (local address) * @param to optional @To (remote address) * @param extra optional extra header * @param headers va_list of optional extra headers * * @deprecated Use nta_leg_tcreate() instead. */ nta_leg_t *nta_leg_vcreate(nta_agent_t *agent, nta_request_f *callback, nta_leg_magic_t *magic, sip_call_id_t const *i, sip_from_t const *from, sip_to_t const *to, void const *extra, va_list headers) { sip_route_t const *route = NULL; sip_cseq_t const *cseq = NULL; for (; extra ; extra = va_arg(headers, void *)) { sip_header_t const *h = (sip_header_t const *)extra; if (h == SIP_NONE) continue; else if (sip_call_id_p(h)) { if (i == NULL) i = h->sh_call_id; } else if (sip_from_p(h)) { if (from == NULL) from = h->sh_from; } else if (sip_to_p(h)) { if (to == NULL) to = h->sh_to; } else if (sip_route_p(h)) { route = h->sh_route; } else if (sip_cseq_p(h)) { cseq = h->sh_cseq; } else { SU_DEBUG_3(("nta_leg_create: extra header %s\n", sip_header_name(h, 0))); } } return nta_leg_tcreate(agent, callback, magic, NTATAG_NO_DIALOG(i == SIP_NONE->sh_call_id), TAG_IF(i != SIP_NONE->sh_call_id, SIPTAG_CALL_ID(i)), TAG_IF(from != SIP_NONE->sh_from, SIPTAG_FROM(from)), TAG_IF(to != SIP_NONE->sh_to, SIPTAG_TO(to)), SIPTAG_ROUTE(route), SIPTAG_CSEQ(cseq), TAG_END()); }
/**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; }
int DrachtioController::processRequestOutsideDialog( nta_leg_t* defaultLeg, nta_incoming_t* irq, sip_t const *sip) { DR_LOG(log_debug) << "processRequestOutsideDialog" << endl ; int rc = validateSipMessage( sip ) ; if( 0 != rc ) { return rc ; } switch (sip->sip_request->rq_method ) { case sip_method_invite: { /* TODO: should support optional config to only allow invites from defined addresses */ /* system-wide minimum session-expires is 90 seconds */ if( sip->sip_session_expires && sip->sip_session_expires->x_delta < 90 ) { nta_incoming_treply( irq, SIP_422_SESSION_TIMER_TOO_SMALL, SIPTAG_MIN_SE_STR("90"), TAG_END() ) ; return 0; } string transactionId ; generateUuid( transactionId ) ; nta_incoming_treply( irq, SIP_100_TRYING, TAG_END() ) ; if( !m_pClientController->route_request_outside_dialog( irq, sip, transactionId ) ) { DR_LOG(log_error) << "No providers available for invite" << endl ; return 503 ; } nta_leg_t* leg = nta_leg_tcreate(m_nta, legCallback, this, SIPTAG_CALL_ID(sip->sip_call_id), SIPTAG_CSEQ(sip->sip_cseq), SIPTAG_TO(sip->sip_from), SIPTAG_FROM(sip->sip_to), TAG_END()); if( NULL == leg ) { DR_LOG(log_error) << "Error creating a leg for origination" << endl ; //TODO: we got a client out there with a dead INVITE now... return 500 ; } boost::shared_ptr<SipDialog> dlg = boost::make_shared<SipDialog>( leg, irq, sip ) ; dlg->setTransactionId( transactionId ) ; string contactStr ; generateOutgoingContact( sip->sip_contact, contactStr ) ; nta_leg_server_route( leg, sip->sip_record_route, sip->sip_contact ) ; m_pDialogController->addIncomingInviteTransaction( leg, irq, sip, transactionId, dlg ) ; } break ; case sip_method_ack: /* success case: call has been established */ nta_incoming_destroy( irq ) ; return 0 ; case sip_method_register: case sip_method_message: case sip_method_options: case sip_method_notify: { string transactionId ; generateUuid( transactionId ) ; if( !m_pClientController->route_request_outside_dialog( irq, sip, transactionId ) ) { DR_LOG(log_error) << "No providers available for register" << endl ; return 503 ; } m_pDialogController->addIncomingRequestTransaction( irq, transactionId ) ; return 0 ; } case sip_method_bye: case sip_method_cancel: DR_LOG(log_error) << "Received BYE or CANCEL for unknown dialog: " << sip->sip_call_id->i_id << endl ; return 481 ; default: DR_LOG(log_error) << "DrachtioController::processRequestOutsideDialog - unsupported method type: " << sip->sip_request->rq_method_name << ": " << sip->sip_call_id->i_id << endl ; return 501 ; break ; } return 0 ; }