📄 nua_session.c
字号:
sip_content_disposition_t **return_cd, sip_content_type_t **return_ct, sip_payload_t **return_pl);staticint nua_server_retry_after(nua_server_request_t *sr, int status, char const *phrase, int min, int max);/**@fn void nua_invite(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...); * * Place a call using SIP @b INVITE method. * * The INVITE method is used to initiate a call between two parties. The * call is also known as <i>SIP session</i>. * * At SIP level the session is represented as @e Dialog, which is a * peer-to-peer association between two SIP User-Agents. The dialog is * established by a successful 2XX response to the INVITE. The dialog is * terminated by BYE transaction, which application can initiate with * nua_bye() call. * * An @e early @e dialog is established by an preliminary response * (101..199), such as <i>180 Ringing</i>. An early dialog is terminated * with an error response with response code in range 300...699. * * The media session belonging to the SIP session is usually represented by * SDP, Session Description Protocol. The media session it is usually * established during the call set-up with procedure known as SDP * Offer/Answer exchange, defined by @RFC3264. See <b>Media Session * Handling</b> below for details. * * @param nh Pointer to operation handle * @param tag, value, ... List of tagged parameters * * @return * nothing * * @par Events: * #nua_r_invite \n * #nua_i_state (#nua_i_active, #nua_i_terminated) \n * #nua_i_media_error \n * #nua_i_fork \n * * @par Tags: * NUTAG_AUTH_CACHE() \n * NUTAG_AUTOACK() \n * NUTAG_AUTOANSWER() \n * NUTAG_EARLY_MEDIA() \n * NUTAG_ENABLEINVITE() \n * NUTAG_INITIAL_ROUTE(), NUTAG_INITIAL_ROUTE_STR() \n * NUTAG_INVITE_TIMER() \n * NUTAG_MEDIA_ENABLE() \n * NUTAG_MEDIA_FEATURES() \n * NUTAG_MIN_SE() \n * NUTAG_RETRY_COUNT() \n * NUTAG_SERVICE_ROUTE_ENABLE() \n * NUTAG_SESSION_REFRESHER() \n * NUTAG_SESSION_TIMER() \n * NUTAG_SOA_NAME() \n * NUTAG_UPDATE_REFRESH() \n * * @par Populating SIP Request Message with Tagged Arguments * The tagged arguments can be used to pass values for any SIP headers to * the stack. When the INVITE message (or any other SIP message) is created, * the tagged values saved with nua_handle() are used first, next the tagged * values given with the operation (nua_invite()) are added. * * @par * When multiple tags for the same header are specified, the behaviour * depends on the header type. If only a single header field can be included * in a SIP message, the latest non-NULL value is used, e.g., @Subject. * However, if the SIP header can consist of multiple lines or header fields * separated by comma, e.g., @Accept, all the tagged * values are concatenated. * * @par * However, if a tag value is #SIP_NONE (-1 casted as a void pointer), the * values from previous tags are ignored. * * @par * Next, values previously set with nua_set_params() or nua_set_hparams() * are used: @Allow, @Supported, @Organization, and @UserAgent headers are * added to the request if they are not already set. * * @par * Now, the target URI for the request needs to be determined. * * @par * For initial INVITE requests, values from tags are used. If NUTAG_URL() is * given, it is used as target URI. Otherwise, if SIPTAG_TO() is given, it * is used as target URI. If neither is given, the complete request line * already specified using SIPTAG_REQUEST() or SIPTAG_REQUEST_STR() is used. * If none of the tags above are given, an internal error is returned to the * application. At this point, the target URI is stored in the request line, * together with method name ("INVITE") and protocol version ("SIP/2.0"). * The initial dialog information is also created: @CallID, @CSeq headers * are generated, if they do not exist, and an unique tag is added to @From * header. * * @par * For the initial INVITE requests, the @Route headers specified by * SIPTAG_ROUTE()/SIPTAG_ROUTER_STR() tags in nua_handle() and nua_invite() * calls are inserted to the request. Next the initial route set specified * by NUTAG_INITIAL_ROUTE()/NUTAG_INITIAL_ROUTE_STR() tags is prepended to * the route. Finally (unless NUTAG_SERVICE_ROUTE_ENABLE(0) is used) the * @ServiceRoute set received from the registrar is also appended to the * route set of the initial request message. * * @par * 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 a registration active, the @Contact header used with registration is * used. Otherwise, the @Contact header is generated from the local IP * address and port number, taking also the values from NUTAG_M_DISPLAY(), * NUTAG_M_FEATURES(), NUTAG_M_PARAMS(), and NUTAG_M_USERNAME(). * * @par * For in-dialog INVITE (re-INVITE), the request URI is taken from the * @Contact header received from the remote party during the dialog * establishment. 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 (set by @RecordRoute headers), it is added to * the request, too. * * @par * @MaxForwards header (with default value set by NTATAG_MAX_FORWARDS()) is * also added now, if it does not exist. * * @par * The INVITE request message created by nua_invite() operation is saved as * a template for automatic re-INVITE requests sent by the session timer * ("timer") feature (see NUTAG_SESSION_TIMER() for more details). Please * note that the template message is not used when ACK, PRACK, UPDATE or * INFO requests are created (however, these requests will include * dialog-specific headers like @To, @From, and @CallID as well as * preference headers @Allow, @Supported, @UserAgent, @Organization). * * @par Tags Related to SIP Headers and Request-URI * NUTAG_URL(), SIPTAG_REQUEST(), SIPTAG_REQUEST_STR() \n * NUTAG_INITIAL_ROUTE(), NUTAG_INITIAL_ROUTE_STR(), * SIPTAG_ROUTE(), SIPTAG_ROUTE_STR(), * NUTAG_SERVICE_ROUTE_ENABLE() \n * SIPTAG_MAX_FORWARDS(), SIPTAG_MAX_FORWARDS_STR() \n * SIPTAG_PROXY_REQUIRE(), SIPTAG_PROXY_REQUIRE_STR() \n * SIPTAG_FROM(), SIPTAG_FROM_STR() \n * SIPTAG_TO(), SIPTAG_TO_STR() \n * SIPTAG_CALL_ID(), SIPTAG_CALL_ID_STR() \n * SIPTAG_CSEQ(), SIPTAG_CSEQ_STR() * (note that @CSeq value is incremented if request gets retried)\n * SIPTAG_CONTACT(), SIPTAG_CONTACT_STR() \n * SIPTAG_REQUEST_DISPOSITION(), SIPTAG_REQUEST_DISPOSITION_STR() \n * SIPTAG_ACCEPT_CONTACT(), SIPTAG_ACCEPT_CONTACT_STR() \n * SIPTAG_REJECT_CONTACT(), SIPTAG_REJECT_CONTACT_STR() \n * SIPTAG_EXPIRES(), SIPTAG_EXPIRES_STR() \n * SIPTAG_DATE(), SIPTAG_DATE_STR() \n * SIPTAG_TIMESTAMP(), SIPTAG_TIMESTAMP_STR() \n * SIPTAG_SUBJECT(), SIPTAG_SUBJECT_STR() \n * SIPTAG_PRIORITY(), SIPTAG_PRIORITY_STR() \n * SIPTAG_CALL_INFO(), SIPTAG_CALL_INFO_STR() \n * SIPTAG_ORGANIZATION(), SIPTAG_ORGANIZATION_STR() \n * NUTAG_USER_AGENT(), SIPTAG_USER_AGENT() and SIPTAG_USER_AGENT_STR() \n * SIPTAG_IN_REPLY_TO(), SIPTAG_IN_REPLY_TO_STR() \n * SIPTAG_ACCEPT(), SIPTAG_ACCEPT_STR() \n * SIPTAG_ACCEPT_ENCODING(), SIPTAG_ACCEPT_ENCODING_STR() \n * SIPTAG_ACCEPT_LANGUAGE(), SIPTAG_ACCEPT_LANGUAGE_STR() \n * NUTAG_ALLOW(), SIPTAG_ALLOW(), and SIPTAG_ALLOW_STR() \n * NUTAG_EARLY_MEDIA(), SIPTAG_REQUIRE(), and SIPTAG_REQUIRE_STR() \n * NUTAG_SUPPORTED(), SIPTAG_SUPPORTED(), and SIPTAG_SUPPORTED_STR() \n * SIPTAG_ALLOW_EVENTS(), SIPTAG_ALLOW_EVENTS_STR() \n * SIPTAG_PROXY_AUTHORIZATION(), SIPTAG_PROXY_AUTHORIZATION_STR() \n * SIPTAG_AUTHORIZATION(), SIPTAG_AUTHORIZATION_STR() \n * SIPTAG_REFERRED_BY(), SIPTAG_REFERRED_BY_STR() \n * SIPTAG_REPLACES(), SIPTAG_REPLACES_STR() \n * NUTAG_SESSION_TIMER(), NUTAG_SESSION_REFRESHER(), * SIPTAG_SESSION_EXPIRES(), SIPTAG_SESSION_EXPIRES_STR() \n * NUTAG_MIN_SE(), SIPTAG_MIN_SE(), SIPTAG_MIN_SE_STR() \n * SIPTAG_SECURITY_CLIENT(), SIPTAG_SECURITY_CLIENT_STR() \n * SIPTAG_SECURITY_VERIFY(), SIPTAG_SECURITY_VERIFY_STR() \n * SIPTAG_PRIVACY(), SIPTAG_PRIVACY_STR() \n * SIPTAG_MIME_VERSION(), SIPTAG_MIME_VERSION_STR() \n * SIPTAG_CONTENT_TYPE(), SIPTAG_CONTENT_TYPE_STR() \n * SIPTAG_CONTENT_ENCODING(), SIPTAG_CONTENT_ENCODING_STR() \n * SIPTAG_CONTENT_LANGUAGE(), SIPTAG_CONTENT_LANGUAGE_STR() \n * SIPTAG_CONTENT_DISPOSITION(), SIPTAG_CONTENT_DISPOSITION_STR() \n * SIPTAG_HEADER(), SIPTAG_HEADER_STR() \n * SIPTAG_PAYLOAD(), SIPTAG_PAYLOAD_STR() \n * * @par SDP Handling * By default the nua_invite() uses an @ref soa_session_t "SOA media * session" object to take care of the Offer/Answer exchange. The SOA can * be disabled with tag NUTAG_MEDIA_ENABLE(0). * * @par * The SDP description of the * @ref soa_session_t "soa media session" is included in the INVITE request * as a message body. * The SDP in the message body of the 1XX or 2XX response message is * interpreted as an answer, given to the @ref soa_session_t "soa media * session" object for processing. * * @bug If the INVITE request already contains a message body, SDP is not * added. Also, if the response contains a multipart body, it is not parsed. * * @par Tags Related to SDP Management and Offer/Answer Model: * NUTAG_MEDIA_ENABLE(), \n * NUTAG_INCLUDE_EXTRA_SDP(), \n * SOATAG_HOLD(), SOATAG_AF(), SOATAG_ADDRESS(), * SOATAG_ORDERED_USER(), SOATAG_REUSE_REJECTED(), * SOATAG_RTP_SELECT(), SOATAG_RTP_SORT(), SOATAG_RTP_MISMATCH(), * SOATAG_AUDIO_AUX(), \n * SOATAG_USER_SDP() or SOATAG_USER_SDP_STR() \n * * @par Alternative Call Models * In addition to the basic SIP call model described in @RFC3261 and * @RFC3264, the early media model described in @RFC3262 is available. The * use of 100rel and early media can be use can be forced with * NUTAG_EARLY_MEDIA(1). * * Also, the "precondition" call model described in @RFC3312 is supported at * SIP level, that is, the SIP PRACK and UPDATE requests are sent if * "precondition" is added to the @Require header in the INVITE request. * * Optionally * - uses early media if NUTAG_EARLY_MEDIA() tag is used with non zero-value * - media parameters can be set by SOA tags * - nua_invite() can be used to change status of an existing call: * - #SOATAG_HOLD tag can be used to list the media that will be put on hold, * the value "*" sets all the media beloginging to the session on hold * * @par Authentication * The INVITE request may need authentication. Each proxy or server * requiring authentication can respond with 401 or 407 response. The * nua_authenticate() operation stores authentication information (username * and password) to the handle, and stack tries to authenticate all the rest * of the requests (e.g., PRACK, ACK, UPDATE, re-INVITE, BYE) using the * stored username and password. * * @sa @ref nua_call_model, #nua_r_invite, #nua_i_state, \n * nua_handle_has_active_call() \n * nua_handle_has_call_on_hold()\n * nua_handle_has_invite() \n * nua_authenticate() \n * nua_prack() \n * nua_update() \n * nua_info() \n * nua_cancel() \n * nua_bye() \n * #nua_i_invite, nua_respond() *//* Tags not implemented * NUTAG_REFER_PAUSE() \n */static int nua_invite_client_init(nua_client_request_t *cr, msg_t *msg, sip_t *sip, tagi_t const *tags);static int nua_invite_client_request(nua_client_request_t *cr, msg_t *msg, sip_t *sip, tagi_t const *tags);static int nua_invite_client_preliminary(nua_client_request_t *cr, int status, char const *phrase, sip_t const *sip);static int nua_invite_client_response(nua_client_request_t *cr, int status, char const *phrase, sip_t const *sip);static int nua_session_client_response(nua_client_request_t *cr, int status, char const *phrase, sip_t const *sip);static int nua_invite_client_report(nua_client_request_t *cr, int status, char const *phrase, sip_t const *sip, nta_outgoing_t *orq, tagi_t const *tags);nua_client_methods_t const nua_invite_client_methods = { SIP_METHOD_INVITE, /* crm_method, crm_method_name */ 0, /* crm_extra */ { /* crm_flags */ /* create_dialog */ 1, /* in_dialog */ 1, /* target refresh */ 1 }, NULL, /* crm_template */ nua_invite_client_init, /* crm_init */ nua_invite_client_request, /* crm_send */ session_timer_check_restart, /* crm_check_restart */ nua_invite_client_response, /* crm_recv */ nua_invite_client_preliminary, /* crm_preliminary */ nua_invite_client_report, /* crm_report */ nua_invite_client_complete, /* crm_complete */};extern nua_client_methods_t const nua_bye_client_methods;extern nua_client_methods_t const nua_cancel_client_methods;extern nua_client_methods_t const nua_info_client_methods;extern nua_client_methods_t const nua_update_client_methods;extern nua_client_methods_t const nua_prack_client_methods;int nua_stack_invite(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags){ return nua_client_create(nh, e, &nua_invite_client_methods, tags);}static int nua_invite_client_init(nua_client_request_t *cr, msg_t *msg, sip_t *sip, tagi_t const *tags){ nua_handle_t *nh = cr->cr_owner; nua_dialog_usage_t *du; nua_session_usage_t *ss; cr->cr_usage = du = nua_dialog_usage_for_session(nh->nh_ds); /* Errors returned by nua_invite_client_init() do not change the session state */ cr->cr_neutral = 1; if (nh_is_special(nh) || nua_stack_set_handle_special(nh, nh_has_invite, nua_i_error)) return nua_client_return(cr, 900, "Invalid handle for INVITE", msg); else if (nh_referral_check(nh, tags) < 0) return nua_client_return(cr, 900, "Invalid referral", msg); if (du) { nua_server_request_t *sr; for (sr = nh->nh_ds->ds_sr; sr; sr = sr->sr_next) /* INVITE in progress? */ if (sr->sr_usage == du && sr->sr_method == sip_method_invite && nua_server_request_is_pending(sr)) return nua_client_return(cr, SIP_491_REQUEST_PENDING, msg); } else du = nua_dialog_usage_add(nh, nh->nh_ds, nua_session_usage, NULL); if (!du) return -1; ss = nua_dialog_usage_private(du); if (ss->ss_state >= nua_callstate_terminating) return nua_client_return(cr, 900, "Session is terminating", msg); if (nua_client_bind(cr, du) < 0) return nua_client_return(cr, 900, "INVITE already in progress", msg); cr->cr_neutral = 0; session_timer_preferences(ss->ss_timer, sip, NH_PGET(nh, supported), NH_PGET(nh, session_timer), NUA_PISSET(nh->nh_nua, nh, session_timer), NH_PGET(nh, refresher), NH_PGET(nh, min_se)); return 0;}static int nua_invite_client_request(nua_client_request_t *cr, msg_t *msg, sip_t *sip, tagi_t const *tags){ nua_handle_t *nh = cr->cr_owner; nua_dialog_usage_t *du = cr->cr_usage; nua_session_usage_t *ss; int offer_sent = 0, retval; sip_time_t invite_timeout; if (du == NULL) /* Call terminated */ return nua_client_return(cr, SIP_481_NO_TRANSACTION, msg); ss = NUA_DIALOG_USAGE_PRIVATE(du); if (ss->ss_state >= nua_callstate_terminating) return nua_client_return(cr, 900, "Session is terminating", msg); invite_timeout = NH_PGET(nh, invite_timeout); if (invite_timeout == 0) invite_timeout = UINT_MAX; /* Send CANCEL if we don't get response within timeout*/ /* nua_dialog_usage_set_expires(du, invite_timeout); Xyzzy */ nua_dialog_usage_reset_refresh(du); /* Add session timer headers */ if (session_timer_is_supported(ss->ss_timer)) session_timer_add_headers(ss->ss_timer, ss->ss_state == nua_callstate_init, msg, sip); ss->ss_100rel = NH_PGET(nh, early_media); ss->ss_precondition = sip_has_feature(sip->sip_require, "precondition"); if (ss->ss_precondition)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -