Bug Summary

File:libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c
Location:line 3606, column 46
Description:Access to field 'ss_oa_sent' results in a dereference of a null pointer (loaded from variable 'ss')

Annotated Source Code

1/*
2 * This file is part of the Sofia-SIP package
3 *
4 * Copyright (C) 2006 Nokia Corporation.
5 *
6 * Contact: Pekka Pessi <pekka.pessi@nokia.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 *
23 */
24
25/**@CFILE nua_session.c
26 * @brief SIP session handling
27 *
28 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
29 *
30 * @date Created: Wed Mar 8 16:17:27 EET 2006 ppessi
31 */
32
33#include "config.h"
34
35#include <stddef.h>
36#include <stdlib.h>
37#include <string.h>
38#include <limits.h>
39
40#include <assert.h>
41
42#include <sofia-sip/su_string.h>
43#include <sofia-sip/sip_protos.h>
44#include <sofia-sip/sip_status.h>
45#include <sofia-sip/sip_util.h>
46#include <sofia-sip/su_uniqueid.h>
47#include <sofia-sip/msg_mime_protos.h>
48
49#define NTA_INCOMING_MAGIC_Tstruct nua_server_request struct nua_server_request
50#define NTA_OUTGOING_MAGIC_Tstruct nua_client_request struct nua_client_request
51#define NTA_RELIABLE_MAGIC_Tstruct nua_server_request struct nua_server_request
52
53#include "nua_stack.h"
54#include <sofia-sip/soa.h>
55
56#ifndef SDP_H
57typedef struct sdp_session_s sdp_session_t;
58#endif
59
60/* ---------------------------------------------------------------------- */
61
62/** @enum nua_callstate
63
64The states for SIP session established with INVITE.
65
66Initially the call states follow the state of the INVITE transaction. If the
67initial INVITE transaction fails, the call is terminated. The status codes
68401 and 407 are an exception: if the client (on the left side in the diagram
69below) receives them, it enters in #nua_callstate_authenticating state.
70
71If a re-INVITE transaction fails, the result depends on the status code in
72failure. The call can return to the ready state, be terminated immediately,
73or be terminated gracefully. The proper action to take is determined with
74sip_response_terminates_dialog().
75
76@sa @ref nua_call_model, #nua_i_state, nua_invite(), #nua_i_invite
77
78@par Session State Diagram
79
80@code
81 +----------+
82 | |---------------------+
83 | Init | |
84 | |----------+ |
85 +----------+ | |
86 | | | |
87 --/INVITE| |INVITE/100 | |
88 V V | |
89 +----------+ +----------+ | |
90 +--------| | | | | |
91 | 18X +-| Calling | | Received | |INVITE/ |
92 | /- | | | | | | /18X |
93 | V +----------+ +----------+ V |
94 | +----------+ | | | +----------+ |
95 |---| | |2XX -/ | -/ | | | |
96 | | Proceed- | | /- 2XX| 18X| | Early | |INVITE/
97 | | ing | | | +->| | | /200
98 | +----------+ V V +----------+ |
99 | | +----------+ +----------+ | -/ |
100 | 2XX| | | | |<--+ 2XX |
101 | /-| | Complet- | | Complete |<-----------+
102 | +->| ing | | |------+
103 | +----------+ +----------+ |
104 | | | | |
105 |401,407/ -/ACK| |ACK/- |timeout/ |
106 | /ACK V V | /BYE |
107 | +----------+ | |
108 | | | | |
109 | +--| Ready | | |
110 | | | | | |
111 | | +----------+ | |
112 | | | | |
113 | BYE/ | |-/BYE | |BYE/
114 V /200 | V | |/200
115 +----------+ | +----------+ | |
116 | | | | | | |
117 |Authentic-| | | Terminat-|<----+ |
118 | ating | | | ing | |
119 +----------+ | +----------+ |
120 | | |
121 | |[23456]XX/- |
122 | V |
123 | +----------+ |
124 | | | |
125 +->|Terminated|<--------------+
126 | |
127 +----------+
128 |
129 V
130 +----------+
131 | |
132 | Init |
133 | |
134 +----------+
135@endcode
136*/
137
138/* ---------------------------------------------------------------------- */
139/* Session event usage */
140
141/** @internal @brief Session-related state. */
142typedef struct nua_session_usage
143{
144 enum nua_callstate ss_state; /**< Session status (enum nua_callstate) */
145
146 unsigned ss_100rel:1; /**< Use 100rel, send 183 */
147 unsigned ss_alerting:1; /**< 180 is sent/received */
148
149 unsigned ss_update_needed:2; /**< Send an UPDATE (do O/A if > 1) */
150
151 unsigned ss_precondition:1; /**< Precondition required */
152
153 unsigned ss_reporting:1; /**< True if reporting state */
154 unsigned : 0;
155
156 struct session_timer {
157 unsigned interval; /**< Negotiated expiration time */
158 enum nua_session_refresher refresher; /**< Our Negotiated role */
159
160 struct {
161 unsigned expires, defaults; /**< Value of Session-Expires (delta) */
162 unsigned min_se; /**< Minimum session expires */
163 /** none, local or remote */
164 enum nua_session_refresher refresher;
165 unsigned supported:1, require:1, :0;
166 } local, remote;
167
168 unsigned timer_set:1; /**< We have active session timer. */
169 } ss_timer[1];
170
171 char const *ss_reason; /**< Reason for termination. */
172
173 /* Offer-Answer status */
174 char const *ss_oa_recv, *ss_oa_sent;
175
176 /**< Version of user SDP from latest successful O/A */
177 int ss_sdp_version;
178} nua_session_usage_t;
179
180static char const Offer[] = "offer", Answer[] = "answer";
181
182static char const *nua_session_usage_name(nua_dialog_usage_t const *du);
183static int nua_session_usage_add(nua_handle_t *nh,
184 nua_dialog_state_t *ds,
185 nua_dialog_usage_t *du);
186static void nua_session_usage_remove(nua_handle_t *nh,
187 nua_dialog_state_t *ds,
188 nua_dialog_usage_t *du,
189 nua_client_request_t *cr,
190 nua_server_request_t *sr);
191static void nua_session_usage_refresh(nua_owner_t *,
192 nua_dialog_state_t *,
193 nua_dialog_usage_t *,
194 sip_time_t now);
195static int nua_session_usage_shutdown(nua_owner_t *,
196 nua_dialog_state_t *,
197 nua_dialog_usage_t *);
198
199static void signal_call_state_change(nua_handle_t *nh,
200 nua_session_usage_t *ss,
201 int status, char const *phrase,
202 enum nua_callstate next_state);
203
204static int nua_invite_client_should_ack(nua_client_request_t const *cr);
205static int nua_invite_client_ack(nua_client_request_t *cr, tagi_t const *tags);
206static int nua_invite_client_complete(nua_client_request_t *cr);
207
208static nua_usage_class const nua_session_usage[1] = {
209 {
210 sizeof (nua_session_usage_t),
211 sizeof nua_session_usage,
212 nua_session_usage_add,
213 nua_session_usage_remove,
214 nua_session_usage_name,
215 nua_base_usage_update_params,
216 NULL((void*)0),
217 nua_session_usage_refresh,
218 nua_session_usage_shutdown
219 }};
220
221static char const *nua_session_usage_name(nua_dialog_usage_t const *du)
222{
223 return "session";
224}
225
226static
227int nua_session_usage_add(nua_handle_t *nh,
228 nua_dialog_state_t *ds,
229 nua_dialog_usage_t *du)
230{
231 nua_session_usage_t *ss = NUA_DIALOG_USAGE_PRIVATE(du)((void *)((du) + 1));
232
233 if (ds->ds_has_session)
234 return -1;
235 ds->ds_has_session = 1;
236 ds->ds_got_session = 1;
237
238 ss->ss_timer->local.refresher = nua_any_refresher;
239 ss->ss_timer->remote.refresher = nua_any_refresher;
240
241 return 0;
242}
243
244static
245void nua_session_usage_remove(nua_handle_t *nh,
246 nua_dialog_state_t *ds,
247 nua_dialog_usage_t *du,
248 nua_client_request_t *cr0,
249 nua_server_request_t *sr0)
250{
251 nua_session_usage_t *ss = NUA_DIALOG_USAGE_PRIVATE(du)((void *)((du) + 1));
252 nua_client_request_t *cr, *cr_next;
253 nua_server_request_t *sr;
254
255 /* Destroy queued INVITE transactions */
256 for (cr = ds->ds_cr; cr; cr = cr_next) {
257 cr_next = cr->cr_next;
258
259 if (cr->cr_method != sip_method_invite)
260 continue;
261
262 if (cr == cr0)
263 continue;
264
265 nua_client_request_ref(cr);
266
267 if (nua_invite_client_should_ack(cr)) {
268 ss->ss_reporting = 1;
269 nua_invite_client_ack(cr, NULL((void*)0));
270 ss->ss_reporting = 0;
271 }
272
273 if (cr == du->du_cr && cr->cr_orq) {
274 nua_client_request_unref(cr);
275 continue;
276 }
277
278 if (cr->cr_status < 200) {
279 nua_stack_event(nh->nh_nua, nh,
280 NULL((void*)0),
281 (enum nua_event_e)cr->cr_event,
282 SIP_481_NO_TRANSACTION481, sip_481_No_transaction,
283 NULL((void*)0));
284 }
285
286 nua_client_request_remove(cr);
287
288 nua_client_request_unref(cr);
289
290 cr_next = ds->ds_cr;
291 }
292
293 if (ss->ss_state != nua_callstate_terminated &&
294 ss->ss_state != nua_callstate_init &&
295 !ss->ss_reporting) {
296 int status = 0; char const *phrase = "Terminated";
297
298 if (cr0)
299 status = cr0->cr_status, phrase = cr0->cr_phrase ? cr0->cr_phrase : phrase;
300 else if (sr0)
301 status = sr0->sr_status, phrase = sr0->sr_phrase;
302
303 signal_call_state_change(nh, ss, status, phrase, nua_callstate_terminated);
304 }
305
306 /* Application can respond to BYE after the session usage has terminated */
307 for (sr = ds->ds_sr; sr; sr = sr->sr_next) {
308 if (sr->sr_usage == du && sr->sr_method == sip_method_bye)
309 sr->sr_usage = NULL((void*)0);
310 }
311
312 ds->ds_has_session = 0;
313 nh->nh_has_invite = 0;
314 nh->nh_active_call = 0;
315 nh->nh_hold_remote = 0;
316
317 if (nh->nh_soa)
318 soa_destroy(nh->nh_soa), nh->nh_soa = NULL((void*)0);
319}
320
321static
322nua_dialog_usage_t *nua_dialog_usage_for_session(nua_dialog_state_t const *ds)
323{
324 if (ds == ((nua_handle_t *)NULL((void*)0))->nh_ds)
325 return NULL((void*)0);
326
327 return nua_dialog_usage_get(ds, nua_session_usage, NULL((void*)0));
328}
329
330static
331nua_session_usage_t *nua_session_usage_for_dialog(nua_dialog_state_t const *ds)
332{
333 nua_dialog_usage_t *du;
334
335 if (ds == ((nua_handle_t *)NULL((void*)0))->nh_ds)
336 return NULL((void*)0);
337
338 du = nua_dialog_usage_get(ds, nua_session_usage, NULL((void*)0));
339
340 return (nua_session_usage_t *)nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
341}
342
343/** Zap the session associated with the handle */
344static
345void nua_session_usage_destroy(nua_handle_t *nh,
346 nua_session_usage_t *ss)
347{
348 /* Remove usage */
349 nua_dialog_usage_remove(nh, nh->nh_ds, nua_dialog_usage_public(ss)((ss) ? (nua_dialog_usage_t*)(ss) - 1 : ((void*)0)), NULL((void*)0), NULL((void*)0));
350
351 SU_DEBUG_5(("nua: terminated session %p\n", (void *)nh))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 351, "nua: terminated session %p\n"
, (void *)nh)) : (void)0)
;
352}
353
354/* ======================================================================== */
355/* INVITE and call (session) processing */
356
357static int session_timer_is_supported(struct session_timer const *t);
358
359static void session_timer_preferences(struct session_timer *t,
360 sip_t const *sip,
361 sip_supported_t const *supported,
362 unsigned expires, int isset,
363 enum nua_session_refresher refresher,
364 unsigned min_se);
365
366static void session_timer_store(struct session_timer *t,
367 sip_t const *sip);
368
369static int session_timer_check_min_se(msg_t *msg, sip_t *sip,
370 sip_t const *request,
371 unsigned long min_se);
372
373static int session_timer_add_headers(struct session_timer *t,
374 int initial,
375 msg_t *msg, sip_t *sip,
376 nua_handle_t *nh);
377
378static void session_timer_negotiate(struct session_timer *t, int uas);
379
380static void session_timer_set(nua_session_usage_t *ss, int uas);
381
382static int session_timer_check_restart(nua_client_request_t *cr,
383 int status, char const *phrase,
384 sip_t const *sip);
385
386static int nh_referral_check(nua_handle_t *nh, tagi_t const *tags);
387static void nh_referral_respond(nua_handle_t *,
388 int status, char const *phrase);
389
390static
391int session_get_description(sip_t const *sip,
392 char const **return_sdp,
393 size_t *return_len);
394
395static
396int session_include_description(soa_session_t *soa,
397 int session,
398 msg_t *msg,
399 sip_t *sip);
400
401static
402int session_make_description(su_home_t *home,
403 soa_session_t *soa,
404 int session,
405 sip_content_disposition_t **return_cd,
406 sip_content_type_t **return_ct,
407 sip_payload_t **return_pl);
408
409static
410int nua_server_retry_after(nua_server_request_t *sr,
411 int status, char const *phrase,
412 int min, int max);
413
414/**@fn void nua_invite(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
415 *
416 * Place a call using SIP @b INVITE method.
417 *
418 * The INVITE method is used to initiate a call between two parties. The
419 * call is also known as <i>SIP session</i>.
420 *
421 * At SIP level the session is represented as @e Dialog, which is a
422 * peer-to-peer association between two SIP User-Agents. The dialog is
423 * established by a successful 2XX response to the INVITE. The dialog is
424 * terminated by BYE transaction, which application can initiate with
425 * nua_bye() call.
426 *
427 * An @e early @e dialog is established by an preliminary response
428 * (101..199), such as <i>180 Ringing</i>. An early dialog is terminated
429 * with an error response with response code in range 300...699.
430 *
431 * The media session belonging to the SIP session is usually represented by
432 * SDP, Session Description Protocol. The media session it is usually
433 * established during the call set-up with procedure known as SDP
434 * Offer/Answer exchange, defined by @RFC3264. See <b>Media Session
435 * Handling</b> below for details.
436 *
437 * @param nh Pointer to operation handle
438 * @param tag, value, ... List of tagged parameters
439 *
440 * @return
441 * nothing
442 *
443 * @par Events:
444 * #nua_r_invite \n
445 * #nua_i_state (#nua_i_active, #nua_i_terminated) \n
446 * #nua_i_media_error \n
447 * #nua_i_fork \n
448 *
449 * @par Tags:
450 * NUTAG_AUTH_CACHE() \n
451 * NUTAG_AUTOACK() \n
452 * NUTAG_AUTOANSWER() \n
453 * NUTAG_EARLY_MEDIA() \n
454 * NUTAG_ENABLEINVITE() \n
455 * NUTAG_INITIAL_ROUTE(), NUTAG_INITIAL_ROUTE_STR() \n
456 * NUTAG_INVITE_TIMER() \n
457 * NUTAG_MEDIA_ENABLE() \n
458 * NUTAG_MEDIA_FEATURES() \n
459 * NUTAG_MIN_SE() \n
460 * NUTAG_RETRY_COUNT() \n
461 * NUTAG_SERVICE_ROUTE_ENABLE() \n
462 * NUTAG_SESSION_REFRESHER() \n
463 * NUTAG_SESSION_TIMER() \n
464 * NUTAG_SOA_NAME() \n
465 * NUTAG_UPDATE_REFRESH() \n
466 *
467 * @par Populating SIP Request Message with Tagged Arguments
468 * The tagged arguments can be used to pass values for any SIP headers to
469 * the stack. When the INVITE message (or any other SIP message) is created,
470 * the tagged values saved with nua_handle() are used first, next the tagged
471 * values given with the operation (nua_invite()) are added.
472 *
473 * @par
474 * When multiple tags for the same header are specified, the behaviour
475 * depends on the header type. If only a single header field can be included
476 * in a SIP message, the latest non-NULL value is used, e.g., @Subject.
477 * However, if the SIP header can consist of multiple lines or header fields
478 * separated by comma, e.g., @Accept, all the tagged
479 * values are concatenated.
480 *
481 * @par
482 * However, if a tag value is #SIP_NONE (-1 casted as a void pointer), the
483 * values from previous tags are ignored.
484 *
485 * @par
486 * Next, values previously set with nua_set_params() or nua_set_hparams()
487 * are used: @Allow, @Supported, @Organization, and @UserAgent headers are
488 * added to the request if they are not already set.
489 *
490 * @par
491 * Now, the target URI for the request needs to be determined.
492 *
493 * @par
494 * For initial INVITE requests, values from tags are used. If NUTAG_URL() is
495 * given, it is used as target URI. Otherwise, if SIPTAG_TO() is given, it
496 * is used as target URI. If neither is given, the complete request line
497 * already specified using SIPTAG_REQUEST() or SIPTAG_REQUEST_STR() is used.
498 * If none of the tags above are given, an internal error is returned to the
499 * application. At this point, the target URI is stored in the request line,
500 * together with method name ("INVITE") and protocol version ("SIP/2.0").
501 * The initial dialog information is also created: @CallID, @CSeq headers
502 * are generated, if they do not exist, and an unique tag is added to @From
503 * header.
504 *
505 * @par
506 * For the initial INVITE requests, the @Route headers specified by
507 * SIPTAG_ROUTE()/SIPTAG_ROUTER_STR() tags in nua_handle() and nua_invite()
508 * calls are inserted to the request. Next the initial route set specified
509 * by NUTAG_INITIAL_ROUTE()/NUTAG_INITIAL_ROUTE_STR() tags is prepended to
510 * the route. Finally (unless NUTAG_SERVICE_ROUTE_ENABLE(0) is used) the
511 * @ServiceRoute set received from the registrar is also appended to the
512 * route set of the initial request message.
513 *
514 * @par
515 * Next, the stack generates a @Contact header for the request (Unless the
516 * application already gave a @Contact header or it does not want to use
517 * @Contact and indicates that by including SIPTAG_CONTACT(NULL) or
518 * SIPTAG_CONTACT(SIP_NONE) in the tagged parameters.) If the application
519 * has a registration active, the @Contact header used with registration is
520 * used. Otherwise, the @Contact header is generated from the local IP
521 * address and port number, taking also the values from NUTAG_M_DISPLAY(),
522 * NUTAG_M_FEATURES(), NUTAG_M_PARAMS(), and NUTAG_M_USERNAME().
523 *
524 * @par
525 * For in-dialog INVITE (re-INVITE), the request URI is taken from the
526 * @Contact header received from the remote party during the dialog
527 * establishment. Also, the @CallID and @CSeq headers and @From and @To tags
528 * are generated based on the dialog information and added to the request.
529 * If the dialog has a route (set by @RecordRoute headers), it is added to
530 * the request, too.
531 *
532 * @par
533 * @MaxForwards header (with default value set by NTATAG_MAX_FORWARDS()) is
534 * also added now, if it does not exist.
535 *
536 * @par
537 * The INVITE request message created by nua_invite() operation is saved as
538 * a template for automatic re-INVITE requests sent by the session timer
539 * ("timer") feature (see NUTAG_SESSION_TIMER() for more details). Please
540 * note that the template message is not used when ACK, PRACK, UPDATE or
541 * INFO requests are created (however, these requests will include
542 * dialog-specific headers like @To, @From, and @CallID as well as
543 * preference headers @Allow, @Supported, @UserAgent, @Organization).
544 *
545 * @par Tags Related to SIP Headers and Request-URI
546 * NUTAG_URL(), SIPTAG_REQUEST(), SIPTAG_REQUEST_STR() \n
547 * NUTAG_INITIAL_ROUTE(), NUTAG_INITIAL_ROUTE_STR(),
548 * SIPTAG_ROUTE(), SIPTAG_ROUTE_STR(),
549 * NUTAG_SERVICE_ROUTE_ENABLE() \n
550 * SIPTAG_MAX_FORWARDS(), SIPTAG_MAX_FORWARDS_STR() \n
551 * SIPTAG_PROXY_REQUIRE(), SIPTAG_PROXY_REQUIRE_STR() \n
552 * SIPTAG_FROM(), SIPTAG_FROM_STR() \n
553 * SIPTAG_TO(), SIPTAG_TO_STR() \n
554 * SIPTAG_CALL_ID(), SIPTAG_CALL_ID_STR() \n
555 * SIPTAG_CSEQ(), SIPTAG_CSEQ_STR()
556 * (note that @CSeq value is incremented if request gets retried)\n
557 * SIPTAG_CONTACT(), SIPTAG_CONTACT_STR() \n
558 * SIPTAG_REQUEST_DISPOSITION(), SIPTAG_REQUEST_DISPOSITION_STR() \n
559 * SIPTAG_ACCEPT_CONTACT(), SIPTAG_ACCEPT_CONTACT_STR() \n
560 * SIPTAG_REJECT_CONTACT(), SIPTAG_REJECT_CONTACT_STR() \n
561 * SIPTAG_EXPIRES(), SIPTAG_EXPIRES_STR() \n
562 * SIPTAG_DATE(), SIPTAG_DATE_STR() \n
563 * SIPTAG_TIMESTAMP(), SIPTAG_TIMESTAMP_STR() \n
564 * SIPTAG_SUBJECT(), SIPTAG_SUBJECT_STR() \n
565 * SIPTAG_PRIORITY(), SIPTAG_PRIORITY_STR() \n
566 * SIPTAG_CALL_INFO(), SIPTAG_CALL_INFO_STR() \n
567 * SIPTAG_ORGANIZATION(), SIPTAG_ORGANIZATION_STR() \n
568 * NUTAG_USER_AGENT(), SIPTAG_USER_AGENT() and SIPTAG_USER_AGENT_STR() \n
569 * SIPTAG_IN_REPLY_TO(), SIPTAG_IN_REPLY_TO_STR() \n
570 * SIPTAG_ACCEPT(), SIPTAG_ACCEPT_STR() \n
571 * SIPTAG_ACCEPT_ENCODING(), SIPTAG_ACCEPT_ENCODING_STR() \n
572 * SIPTAG_ACCEPT_LANGUAGE(), SIPTAG_ACCEPT_LANGUAGE_STR() \n
573 * NUTAG_ALLOW(), SIPTAG_ALLOW(), and SIPTAG_ALLOW_STR() \n
574 * NUTAG_EARLY_MEDIA(), SIPTAG_REQUIRE(), and SIPTAG_REQUIRE_STR() \n
575 * NUTAG_SUPPORTED(), SIPTAG_SUPPORTED(), and SIPTAG_SUPPORTED_STR() \n
576 * SIPTAG_ALLOW_EVENTS(), SIPTAG_ALLOW_EVENTS_STR() \n
577 * SIPTAG_PROXY_AUTHORIZATION(), SIPTAG_PROXY_AUTHORIZATION_STR() \n
578 * SIPTAG_AUTHORIZATION(), SIPTAG_AUTHORIZATION_STR() \n
579 * SIPTAG_REFERRED_BY(), SIPTAG_REFERRED_BY_STR() \n
580 * SIPTAG_REPLACES(), SIPTAG_REPLACES_STR() \n
581 * NUTAG_SESSION_TIMER(), NUTAG_SESSION_REFRESHER(),
582 * SIPTAG_SESSION_EXPIRES(), SIPTAG_SESSION_EXPIRES_STR() \n
583 * NUTAG_MIN_SE(), SIPTAG_MIN_SE(), SIPTAG_MIN_SE_STR() \n
584 * SIPTAG_SECURITY_CLIENT(), SIPTAG_SECURITY_CLIENT_STR() \n
585 * SIPTAG_SECURITY_VERIFY(), SIPTAG_SECURITY_VERIFY_STR() \n
586 * SIPTAG_PRIVACY(), SIPTAG_PRIVACY_STR() \n
587 * SIPTAG_MIME_VERSION(), SIPTAG_MIME_VERSION_STR() \n
588 * SIPTAG_CONTENT_TYPE(), SIPTAG_CONTENT_TYPE_STR() \n
589 * SIPTAG_CONTENT_ENCODING(), SIPTAG_CONTENT_ENCODING_STR() \n
590 * SIPTAG_CONTENT_LANGUAGE(), SIPTAG_CONTENT_LANGUAGE_STR() \n
591 * SIPTAG_CONTENT_DISPOSITION(), SIPTAG_CONTENT_DISPOSITION_STR() \n
592 * SIPTAG_HEADER(), SIPTAG_HEADER_STR() \n
593 * SIPTAG_PAYLOAD(), SIPTAG_PAYLOAD_STR() \n
594 *
595 * @par SDP Handling
596 * By default the nua_invite() uses an @ref soa_session_t "SOA media
597 * session" object to take care of the Offer/Answer exchange. The SOA can
598 * be disabled with tag NUTAG_MEDIA_ENABLE(0).
599 *
600 * @par
601 * The SDP description of the
602 * @ref soa_session_t "soa media session" is included in the INVITE request
603 * as a message body.
604 * The SDP in the message body of the 1XX or 2XX response message is
605 * interpreted as an answer, given to the @ref soa_session_t "soa media
606 * session" object for processing.
607 *
608 * @bug If the INVITE request already contains a message body, SDP is not
609 * added. Also, if the response contains a multipart body, it is not parsed.
610 *
611 * @par Tags Related to SDP Management and Offer/Answer Model:
612 * NUTAG_MEDIA_ENABLE(), \n
613 * NUTAG_INCLUDE_EXTRA_SDP(), \n
614 * SOATAG_HOLD(), SOATAG_AF(), SOATAG_ADDRESS(),
615 * SOATAG_ORDERED_USER(), SOATAG_REUSE_REJECTED(),
616 * SOATAG_RTP_SELECT(), SOATAG_RTP_SORT(), SOATAG_RTP_MISMATCH(),
617 * SOATAG_AUDIO_AUX(), \n
618 * SOATAG_USER_SDP() or SOATAG_USER_SDP_STR() \n
619 *
620 * @par Alternative Call Models
621 * In addition to the basic SIP call model described in @RFC3261 and
622 * @RFC3264, the early media model described in @RFC3262 is available. The
623 * use of 100rel and early media can be use can be forced with
624 * NUTAG_EARLY_MEDIA(1).
625 *
626 * Also, the "precondition" call model described in @RFC3312 is supported at
627 * SIP level, that is, the SIP PRACK and UPDATE requests are sent if
628 * "precondition" is added to the @Require header in the INVITE request.
629 *
630 * Optionally
631 * - uses early media if NUTAG_EARLY_MEDIA() tag is used with non zero-value
632 * - media parameters can be set by SOA tags
633 * - nua_invite() can be used to change status of an existing call:
634 * - #SOATAG_HOLD tag can be used to list the media that will be put on hold,
635 * the value "*" sets all the media beloginging to the session on hold
636 *
637 * @par Authentication
638 * The INVITE request may need authentication. Each proxy or server
639 * requiring authentication can respond with 401 or 407 response. The
640 * nua_authenticate() operation stores authentication information (username
641 * and password) to the handle, and stack tries to authenticate all the rest
642 * of the requests (e.g., PRACK, ACK, UPDATE, re-INVITE, BYE) using the
643 * stored username and password.
644 *
645 * @sa @ref nua_call_model, #nua_r_invite, #nua_i_state, \n
646 * nua_handle_has_active_call() \n
647 * nua_handle_has_call_on_hold()\n
648 * nua_handle_has_invite() \n
649 * nua_authenticate() \n
650 * nua_prack() \n
651 * nua_update() \n
652 * nua_info() \n
653 * nua_cancel() \n
654 * nua_bye() \n
655 * #nua_i_invite, nua_respond()
656 */
657
658/* Tags not implemented
659 * NUTAG_REFER_PAUSE() \n
660 */
661
662static int nua_invite_client_init(nua_client_request_t *cr,
663 msg_t *msg, sip_t *sip,
664 tagi_t const *tags);
665static int nua_invite_client_request(nua_client_request_t *cr,
666 msg_t *msg, sip_t *sip,
667 tagi_t const *tags);
668static int nua_invite_client_preliminary(nua_client_request_t *cr,
669 int status, char const *phrase,
670 sip_t const *sip);
671static int nua_invite_client_response(nua_client_request_t *cr,
672 int status, char const *phrase,
673 sip_t const *sip);
674static int nua_session_client_response(nua_client_request_t *cr,
675 int status, char const *phrase,
676 sip_t const *sip);
677static int nua_invite_client_report(nua_client_request_t *cr,
678 int status, char const *phrase,
679 sip_t const *sip,
680 nta_outgoing_t *orq,
681 tagi_t const *tags);
682
683nua_client_methods_t const nua_invite_client_methods = {
684 SIP_METHOD_INVITEsip_method_invite, "INVITE", /* crm_method, crm_method_name */
685 0, /* crm_extra */
686 { /* crm_flags */
687 /* create_dialog */ 1,
688 /* in_dialog */ 1,
689 /* target refresh */ 1
690 },
691 NULL((void*)0), /* crm_template */
692 nua_invite_client_init, /* crm_init */
693 nua_invite_client_request, /* crm_send */
694 session_timer_check_restart, /* crm_check_restart */
695 nua_invite_client_response, /* crm_recv */
696 nua_invite_client_preliminary, /* crm_preliminary */
697 nua_invite_client_report, /* crm_report */
698 nua_invite_client_complete, /* crm_complete */
699};
700
701extern nua_client_methods_t const nua_bye_client_methods;
702extern nua_client_methods_t const nua_cancel_client_methods;
703extern nua_client_methods_t const nua_update_client_methods;
704extern nua_client_methods_t const nua_prack_client_methods;
705
706int nua_stack_invite(nua_t *nua, nua_handle_t *nh, nua_event_t e,
707 tagi_t const *tags)
708{
709 return nua_client_create(nh, e, &nua_invite_client_methods, tags);
710}
711
712static int nua_invite_client_init(nua_client_request_t *cr,
713 msg_t *msg, sip_t *sip,
714 tagi_t const *tags)
715{
716 nua_handle_t *nh = cr->cr_owner;
717 nua_dialog_usage_t *du;
718 nua_session_usage_t *ss;
719
720 cr->cr_usage = du = nua_dialog_usage_for_session(nh->nh_ds);
721 /* Errors returned by nua_invite_client_init()
722 do not change the session state */
723 cr->cr_neutral = 1;
724
725 if (nh_is_special(nh) ||
726 nua_stack_set_handle_special(nh, nh_has_invite, nua_i_error))
727 return nua_client_return(cr, 900, "Invalid handle for INVITE", msg);
728 else if (nh_referral_check(nh, tags) < 0)
729 return nua_client_return(cr, 900, "Invalid referral", msg);
730
731 if (du) {
732 nua_server_request_t *sr;
733 for (sr = nh->nh_ds->ds_sr; sr; sr = sr->sr_next)
734 /* INVITE in progress? */
735 if (sr->sr_usage == du && sr->sr_method == sip_method_invite &&
736 nua_server_request_is_pending(sr))
737 return nua_client_return(cr, SIP_491_REQUEST_PENDING491, sip_491_Request_pending, msg);
738 cr->cr_initial = 0;
739 }
740 else {
741 du = nua_dialog_usage_add(nh, nh->nh_ds, nua_session_usage, NULL((void*)0));
742 cr->cr_initial = 1;
743 }
744
745 if (!du)
746 return -1;
747
748 ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
749
750 if (ss->ss_state >= nua_callstate_terminating)
751 return nua_client_return(cr, 900, "Session is terminating", msg);
752
753 if (nua_client_bind(cr, du) < 0)
754 return nua_client_return(cr, 900, "INVITE already in progress", msg);
755
756 cr->cr_neutral = 0;
757
758 session_timer_preferences(ss->ss_timer,
759 sip,
760 NH_PGET(nh, supported)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_supported ? ((
nh)->nh_prefs)->nhp_supported : ((nh)->nh_nua->nua_handles
->nh_prefs)->nhp_supported)
,
761 NH_PGET(nh, session_timer)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_session_timer ?
((nh)->nh_prefs)->nhp_session_timer : ((nh)->nh_nua
->nua_handles->nh_prefs)->nhp_session_timer)
,
762 NUA_PISSET(nh->nh_nua, nh, session_timer)((((nh->nh_nua)->nua_handles->nh_prefs)->nhp_set_
.set_bits.nhb_session_timer) || ((nh) && (((nh)->nh_prefs
)->nhp_set_.set_bits.nhb_session_timer)))
,
763 NH_PGET(nh, refresher)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_refresher ? ((
nh)->nh_prefs)->nhp_refresher : ((nh)->nh_nua->nua_handles
->nh_prefs)->nhp_refresher)
,
764 NH_PGET(nh, min_se)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_min_se ? ((nh)
->nh_prefs)->nhp_min_se : ((nh)->nh_nua->nua_handles
->nh_prefs)->nhp_min_se)
);
765
766 return 0;
767}
768
769static int nua_invite_client_request(nua_client_request_t *cr,
770 msg_t *msg, sip_t *sip,
771 tagi_t const *tags)
772{
773 nua_handle_t *nh = cr->cr_owner;
774 nua_dialog_usage_t *du = cr->cr_usage;
775 nua_session_usage_t *ss;
776 int offer_sent = 0, retval;
777 sip_time_t invite_timeout;
778
779 if (du == NULL((void*)0)) /* Call terminated */
780 return nua_client_return(cr, SIP_481_NO_TRANSACTION481, sip_481_No_transaction, msg);
781
782 ss = NUA_DIALOG_USAGE_PRIVATE(du)((void *)((du) + 1));
783
784 if (ss->ss_state >= nua_callstate_terminating)
785 return nua_client_return(cr, 900, "Session is terminating", msg);
786
787 invite_timeout = NH_PGET(nh, invite_timeout)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_invite_timeout
? ((nh)->nh_prefs)->nhp_invite_timeout : ((nh)->nh_nua
->nua_handles->nh_prefs)->nhp_invite_timeout)
;
788 if (invite_timeout == 0)
789 invite_timeout = UINT_MAX(2147483647 *2U +1U);
790 /* Send CANCEL if we don't get response within timeout*/
791 /* nua_dialog_usage_set_expires(du, invite_timeout); Xyzzy */
792 nua_dialog_usage_reset_refresh(du);
793
794 /* Add session timer headers */
795 if (session_timer_is_supported(ss->ss_timer))
796 session_timer_add_headers(ss->ss_timer, ss->ss_state == nua_callstate_init,
797 msg, sip, nh);
798
799 ss->ss_100rel = NH_PGET(nh, early_media)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_early_media ? (
(nh)->nh_prefs)->nhp_early_media : ((nh)->nh_nua->
nua_handles->nh_prefs)->nhp_early_media)
;
800 ss->ss_precondition = sip_has_feature(sip->sip_require, "precondition");
801 if (ss->ss_precondition)
802 ss->ss_update_needed = ss->ss_100rel = 1;
803
804 if (nh->nh_soa) {
805 soa_init_offer_answer(nh->nh_soa);
806
807 if (sip->sip_payload)
808 offer_sent = 0; /* XXX - kludge */
809 else if (soa_generate_offer(nh->nh_soa, 0, NULL((void*)0)) < 0)
810 return -1;
811 else
812 offer_sent = 1;
813
814 if (offer_sent > 0 &&
815 session_include_description(nh->nh_soa, 1, msg, sip) < 0)
816 return nua_client_return(cr, 900, "Internal media error", msg);
817
818 if (NH_PGET(nh, media_features)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_media_features
? ((nh)->nh_prefs)->nhp_media_features : ((nh)->nh_nua
->nua_handles->nh_prefs)->nhp_media_features)
&&
819 !nua_dialog_is_established(nh->nh_ds) &&
820 !sip->sip_accept_contact && !sip->sip_reject_contact) {
821 sip_accept_contact_t ac[1];
822 sip_accept_contact_init(ac);
823
824 ac->cp_params = (msg_param_t *)
825 soa_media_features(nh->nh_soa, 1, msg_home(msg)((su_home_t*)(msg)));
826
827 if (ac->cp_params) {
828 msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), ac->cp_common, "explicit");
829 sip_add_dup(msg, sip, (sip_header_t *)ac);
830 }
831 }
832 }
833 else {
834 offer_sent = session_get_description(sip, NULL((void*)0), NULL((void*)0));
835 }
836
837 retval = nua_base_client_trequest(cr, msg, sip,
838 NTATAG_REL100(ss->ss_100rel)ntatag_rel100, tag_bool_v((ss->ss_100rel)),
839 TAG_NEXT(tags)tag_next, (tag_value_t)(tags));
840 if (retval == 0) {
841 if ((cr->cr_offer_sent = offer_sent))
842 ss->ss_oa_sent = Offer;
843
844 if (!cr->cr_restarting) /* Restart logic calls nua_invite_client_report */
845 signal_call_state_change(nh, ss, 0, "INVITE sent",
846 nua_callstate_calling);
847 }
848
849 return retval;
850}
851
852static int nua_invite_client_response(nua_client_request_t *cr,
853 int status, char const *phrase,
854 sip_t const *sip)
855{
856 nua_dialog_usage_t *du = cr->cr_usage;
857 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
858 int uas;
859
860 if (ss == NULL((void*)0) || sip == NULL((void*)0)) {
861 /* Xyzzy */
862 }
863 else if (status < 300) {
864 du->du_ready = 1;
865
866 if (session_timer_is_supported(ss->ss_timer))
867 session_timer_store(ss->ss_timer, sip);
868
869 session_timer_set(ss, uas = 0);
870 }
871
872 return nua_session_client_response(cr, status, phrase, sip);
873}
874
875static int nua_invite_client_preliminary(nua_client_request_t *cr,
876 int status, char const *phrase,
877 sip_t const *sip)
878{
879 nua_handle_t *nh = cr->cr_owner;
880 nua_dialog_usage_t *du = cr->cr_usage;
881 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
882
883 assert(sip)((sip) ? (void) (0) : __assert_fail ("sip", "nua_session.c", 883
, __PRETTY_FUNCTION__))
;
884
885 if (ss && sip && sip->sip_rseq) {
886 /* Handle 100rel responses */
887 sip_rseq_t *rseq = sip->sip_rseq;
888
889 /* Establish early dialog - we should fork here */
890 if (!nua_dialog_is_established(nh->nh_ds)) {
891 nta_outgoing_t *tagged;
892
893 nua_dialog_uac_route(nh, nh->nh_ds, sip, 1, 1);
894 nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
895
896 /* Tag the INVITE request */
897 tagged = nta_outgoing_tagged(cr->cr_orq,
898 nua_client_orq_response, cr,
899 sip->sip_to->a_tag, sip->sip_rseq);
900 if (tagged) {
901 nta_outgoing_destroy(cr->cr_orq), cr->cr_orq = tagged;
902 }
903 else {
904 cr->cr_graceful = 1;
905 ss->ss_reason = "SIP;cause=500;text=\"Cannot Create Early Dialog\"";
906 }
907 }
908
909 if (!rseq) {
910 SU_DEBUG_5(("nua(%p): 100rel missing RSeq\n", (void *)nh))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 910, "nua(%p): 100rel missing RSeq\n"
, (void *)nh)) : (void)0)
;
911 }
912 else if (nta_outgoing_rseq(cr->cr_orq) > rseq->rs_response) {
913 SU_DEBUG_5(("nua(%p): 100rel bad RSeq %u (got %u)\n", (void *)nh,((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 915, "nua(%p): 100rel bad RSeq %u (got %u)\n"
, (void *)nh, (unsigned)rseq->rs_response, nta_outgoing_rseq
(cr->cr_orq))) : (void)0)
914 (unsigned)rseq->rs_response,((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 915, "nua(%p): 100rel bad RSeq %u (got %u)\n"
, (void *)nh, (unsigned)rseq->rs_response, nta_outgoing_rseq
(cr->cr_orq))) : (void)0)
915 nta_outgoing_rseq(cr->cr_orq)))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 915, "nua(%p): 100rel bad RSeq %u (got %u)\n"
, (void *)nh, (unsigned)rseq->rs_response, nta_outgoing_rseq
(cr->cr_orq))) : (void)0)
;
916 return 1; /* Do not send event */
917 }
918 else if (nta_outgoing_setrseq(cr->cr_orq, rseq->rs_response) < 0) {
919 SU_DEBUG_1(("nua(%p): cannot set RSeq %u\n", (void *)nh,((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 1 ? (_su_llog((nua_log), 1, "nua_session.c"
, (const char *)__func__, 920, "nua(%p): cannot set RSeq %u\n"
, (void *)nh, (unsigned)rseq->rs_response)) : (void)0)
920 (unsigned)rseq->rs_response))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 1 ? (_su_llog((nua_log), 1, "nua_session.c"
, (const char *)__func__, 920, "nua(%p): cannot set RSeq %u\n"
, (void *)nh, (unsigned)rseq->rs_response)) : (void)0)
;
921 cr->cr_graceful = 1;
922 ss->ss_reason = "SIP;cause=400;text=\"Bad RSeq\"";
923 }
924 }
925
926 return nua_session_client_response(cr, status, phrase, sip);
927}
928
929/** Process response to a session request (INVITE, PRACK, UPDATE) */
930static int nua_session_client_response(nua_client_request_t *cr,
931 int status, char const *phrase,
932 sip_t const *sip)
933{
934 nua_handle_t *nh = cr->cr_owner;
935 nua_dialog_usage_t *du = cr->cr_usage;
936 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
937
938 char const *sdp = NULL((void*)0);
939 size_t len;
940 char const *received = NULL((void*)0);
941
942#define LOG3(m)((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_session.c"
, (const char *)__func__, 942, "nua(%p): %s: %s %s in %u %s\n"
, (void *)nh, cr->cr_method_name, (m), received ? received
: "SDP", status, phrase)) : (void)0)
\
943 SU_DEBUG_3(("nua(%p): %s: %s %s in %u %s\n", \((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_session.c"
, (const char *)__func__, 945, "nua(%p): %s: %s %s in %u %s\n"
, (void *)nh, cr->cr_method_name, (m), received ? received
: "SDP", status, phrase)) : (void)0)
944 (void *)nh, cr->cr_method_name, (m), \((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_session.c"
, (const char *)__func__, 945, "nua(%p): %s: %s %s in %u %s\n"
, (void *)nh, cr->cr_method_name, (m), received ? received
: "SDP", status, phrase)) : (void)0)
945 received ? received : "SDP", status, phrase))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_session.c"
, (const char *)__func__, 945, "nua(%p): %s: %s %s in %u %s\n"
, (void *)nh, cr->cr_method_name, (m), received ? received
: "SDP", status, phrase)) : (void)0)
946#define LOG5(m)((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 946, "nua(%p): %s: %s %s in %u %s\n"
, (void *)nh, cr->cr_method_name, (m), received, status, phrase
)) : (void)0)
\
947 SU_DEBUG_5(("nua(%p): %s: %s %s in %u %s\n", \((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 948, "nua(%p): %s: %s %s in %u %s\n"
, (void *)nh, cr->cr_method_name, (m), received, status, phrase
)) : (void)0)
948 (void *)nh, cr->cr_method_name, (m), received, status, phrase))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 948, "nua(%p): %s: %s %s in %u %s\n"
, (void *)nh, cr->cr_method_name, (m), received, status, phrase
)) : (void)0)
949
950 retry:
951
952 if (!ss || !sip || 300 <= status)
953 /* Xyzzy */;
954 else if (!session_get_description(sip, &sdp, &len))
955 /* No SDP */;
956 else if (cr->cr_answer_recv) {
957 /* Ignore spurious answers after completing O/A */
958 //LOG3("ignoring duplicate");
959 //sdp = NULL;
960 // we need to make sure its *actually* a dup, so we can't assume for now.
961 cr->cr_answer_recv = 0;
962 goto retry;
963 }
964 else if (cr->cr_offer_sent) {
965 /* case 1: answer to our offer */
966 cr->cr_answer_recv = status;
967 received = Answer;
968
969 if (nh->nh_soa == NULL((void*)0))
970 LOG5("got SDP")((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 970, "nua(%p): %s: %s %s in %u %s\n"
, (void *)nh, cr->cr_method_name, ("got SDP"), received, status
, phrase)) : (void)0)
;
971 else if (soa_set_remote_sdp(nh->nh_soa, NULL((void*)0), sdp, len) < 0) {
972 LOG3("error parsing SDP")((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_session.c"
, (const char *)__func__, 972, "nua(%p): %s: %s %s in %u %s\n"
, (void *)nh, cr->cr_method_name, ("error parsing SDP"), received
? received : "SDP", status, phrase)) : (void)0)
;
973 sdp = NULL((void*)0);
974 cr->cr_graceful = 1;
975 ss->ss_reason = "SIP;cause=400;text=\"Malformed Session Description\"";
976 }
977 else if (soa_process_answer(nh->nh_soa, NULL((void*)0)) < 0) {
978 LOG5("error processing SDP")((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 978, "nua(%p): %s: %s %s in %u %s\n"
, (void *)nh, cr->cr_method_name, ("error processing SDP")
, received, status, phrase)) : (void)0)
;
979 /* XXX */
980 sdp = NULL((void*)0);
981 }
982 else if (soa_activate(nh->nh_soa, NULL((void*)0)) < 0) {
983 /* XXX - what about errors? */
984 LOG3("error activating media after")((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_session.c"
, (const char *)__func__, 984, "nua(%p): %s: %s %s in %u %s\n"
, (void *)nh, cr->cr_method_name, ("error activating media after"
), received ? received : "SDP", status, phrase)) : (void)0)
;
985 }
986 else {
987 ss->ss_sdp_version = soa_get_user_version(nh->nh_soa);
988 LOG5("processed SDP")((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 988, "nua(%p): %s: %s %s in %u %s\n"
, (void *)nh, cr->cr_method_name, ("processed SDP"), received
, status, phrase)) : (void)0)
;
989 }
990 }
991 else if (cr->cr_method != sip_method_invite) {
992 /* If non-invite request did not have offer, ignore SDP in response */
993 LOG3("ignoring extra")((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_session.c"
, (const char *)__func__, 993, "nua(%p): %s: %s %s in %u %s\n"
, (void *)nh, cr->cr_method_name, ("ignoring extra"), received
? received : "SDP", status, phrase)) : (void)0)
;
994 sdp = NULL((void*)0);
995 }
996 else {
997 /* case 2: new offer */
998 cr->cr_offer_recv = 1, cr->cr_answer_sent = 0;
999 received = Offer;
1000
1001 if (nh->nh_soa && soa_set_remote_sdp(nh->nh_soa, NULL((void*)0), sdp, len) < 0) {
1002 LOG3("error parsing SDP")((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_session.c"
, (const char *)__func__, 1002, "nua(%p): %s: %s %s in %u %s\n"
, (void *)nh, cr->cr_method_name, ("error parsing SDP"), received
? received : "SDP", status, phrase)) : (void)0)
;
1003 sdp = NULL((void*)0);
1004 cr->cr_graceful = 1;
1005 ss->ss_reason = "SIP;cause=400;text=\"Malformed Session Description\"";
1006 }
1007 else
1008 LOG5("got SDP")((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 1008, "nua(%p): %s: %s %s in %u %s\n"
, (void *)nh, cr->cr_method_name, ("got SDP"), received, status
, phrase)) : (void)0)
;
1009 }
1010
1011 if (ss && received)
1012 ss->ss_oa_recv = received;
1013
1014 if (sdp && nh->nh_soa)
1015 return nua_base_client_tresponse(cr, status, phrase, sip,
1016 NH_REMOTE_MEDIA_TAGS(1, nh->nh_soa)!((1) && (nh->nh_soa) && soa_is_remote_audio_active
(nh->nh_soa) >= 0) ? tag_skip : soatag_active_audio, tag_int_v
(soa_is_remote_audio_active(nh->nh_soa)), !((1) &&
(nh->nh_soa) && soa_is_remote_video_active(nh->
nh_soa) >= 0) ? tag_skip : soatag_active_video, tag_int_v(
soa_is_remote_video_active(nh->nh_soa)), !((1) && (
nh->nh_soa) && soa_is_remote_image_active(nh->nh_soa
) >= 0) ? tag_skip : soatag_active_image, tag_int_v(soa_is_remote_image_active
(nh->nh_soa)), !((1) && (nh->nh_soa) &&
soa_is_remote_chat_active(nh->nh_soa) >= 0) ? tag_skip
: soatag_active_chat, tag_int_v(soa_is_remote_chat_active(nh
->nh_soa))
,
1017 TAG_END()(tag_type_t)0, (tag_value_t)0);
1018 else
1019 return nua_base_client_response(cr, status, phrase, sip, NULL((void*)0));
1020}
1021
1022static int nua_invite_client_report(nua_client_request_t *cr,
1023 int status, char const *phrase,
1024 sip_t const *sip,
1025 nta_outgoing_t *orq,
1026 tagi_t const *tags)
1027{
1028 nua_handle_t *nh = cr->cr_owner;
1029 nua_dialog_state_t *ds = nh->nh_ds;
1030 nua_dialog_usage_t *du = cr->cr_usage;
1031 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
1032 msg_t *response = nta_outgoing_getresponse(orq);
1033 unsigned next_state;
1034 int error;
1035
1036 nh_referral_respond(nh, status, phrase); /* XXX - restarting after 401/407 */
1037
1038 nua_stack_event(nh->nh_nua, nh,
1039 response,
1040 (enum nua_event_e)cr->cr_event,
1041 status, phrase,
1042 tags);
1043
1044 if (cr->cr_waiting)
1045 /* Do not report call state change if waiting for restart */
1046 return 1;
1047
1048 if (ss == NULL((void*)0)) {
1049 signal_call_state_change(nh, ss, status, phrase, nua_callstate_terminated);
1050 return 1;
1051 }
1052
1053 ss->ss_reporting = 1;
1054
1055 if (cr->cr_neutral) {
1056 signal_call_state_change(nh, ss, status, phrase, ss->ss_state);
1057 ss->ss_reporting = 0;
1058 return 1;
1059 }
1060
1061 response = msg_ref_create(response); /* Keep reference to contents of sip */
1062
1063 if (orq != cr->cr_orq && cr->cr_orq) { /* Being restarted */
1064 next_state = nua_callstate_calling;
1065 }
1066 else if (status == 100) {
1067 next_state = nua_callstate_calling;
1068 }
1069 else if (status < 300 && cr->cr_graceful) {
1070 next_state = nua_callstate_terminating;
1071 if (200 <= status) {
1072 nua_invite_client_ack(cr, NULL((void*)0));
1073 }
1074 }
1075 else if (status < 200) {
1076 next_state = nua_callstate_proceeding;
1077
1078 if (sip && sip->sip_rseq &&
1079 !SIP_IS_ALLOWED(NH_PGET(nh, appl_method), sip_method_prack)(sip_method_unknown < (sip_method_prack) && (sip_method_prack
) < 32 && ((((nh)->nh_prefs)->nhp_set_.set_bits
.nhb_appl_method ? ((nh)->nh_prefs)->nhp_appl_method : (
(nh)->nh_nua->nua_handles->nh_prefs)->nhp_appl_method
)) && (((((nh)->nh_prefs)->nhp_set_.set_bits.nhb_appl_method
? ((nh)->nh_prefs)->nhp_appl_method : ((nh)->nh_nua
->nua_handles->nh_prefs)->nhp_appl_method))->k_bitmap
& (1 << (sip_method_prack))) != 0)
) {
1080 sip_rack_t rack[1];
1081
1082 sip_rack_init(rack);
1083 rack->ra_response = sip->sip_rseq->rs_response;
1084 rack->ra_cseq = sip->sip_cseq->cs_seq;
1085 rack->ra_method = sip->sip_cseq->cs_method;
1086 rack->ra_method_name = sip->sip_cseq->cs_method_name;
1087
1088 error = nua_client_tcreate(nh, nua_r_prack, &nua_prack_client_methods,
1089 SIPTAG_RACK(rack)siptag_rack, siptag_rack_v(rack),
1090 TAG_END()(tag_type_t)0, (tag_value_t)0);
1091 if (error < 0) {
1092 cr->cr_graceful = 1;
1093 next_state = nua_callstate_terminating;
1094 }
1095 }
1096 }
1097 else if (status < 300) {
1098 next_state = nua_callstate_completing;
1099 }
1100 else if (cr->cr_terminated) {
1101 next_state = nua_callstate_terminated;
1102 }
1103 else if (cr->cr_graceful && ss->ss_state >= nua_callstate_completing) {
1104 next_state = nua_callstate_terminating;
1105 }
1106 else {
1107 next_state = nua_callstate_init;
1108 }
1109
1110 if (next_state == nua_callstate_calling) {
1111 if (sip && sip->sip_status && sip->sip_status->st_status == 100) {
1112 ss->ss_reporting = 0;
1113 return 1;
1114 }
1115 }
1116
1117 if (next_state == nua_callstate_completing) {
1118 if (NH_PGET(nh, auto_ack)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_auto_ack ? ((nh
)->nh_prefs)->nhp_auto_ack : ((nh)->nh_nua->nua_handles
->nh_prefs)->nhp_auto_ack)
||
1119 /* Auto-ACK response to re-INVITE when media is enabled
1120 and auto_ack is not set to 0 on handle */
1121 (ss->ss_state == nua_callstate_ready && nh->nh_soa &&
1122 !NH_PISSET(nh, auto_ack)((((nh)->nh_prefs)->nhp_set_.set_bits.nhb_auto_ack) &&
(nh)->nh_nua->nua_handles->nh_prefs != (nh)->nh_prefs
)
)) {
1123 nua_client_request_t *cru;
1124
1125 for (cru = ds->ds_cr; cru; cru = cru->cr_next) {
1126 if (cr != cru && cru->cr_offer_sent && !cru->cr_answer_recv)
1127 break;
1128 }
1129
1130 if (cru)
1131 /* A final response to UPDATE or PRACK with answer on its way? */;
1132 else if (nua_invite_client_ack(cr, NULL((void*)0)) > 0)
1133 next_state = nua_callstate_ready;
1134 else
1135 next_state = nua_callstate_terminating;
1136 }
1137 }
1138
1139 if (next_state == nua_callstate_terminating) {
1140 /* Send BYE or CANCEL */
1141 /* XXX - Forking - send BYE to early dialog?? */
1142 if (ss->ss_state > nua_callstate_proceeding || status >= 200)
1143 error = nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL((void*)0));
1144 else
1145 error = nua_client_create(nh, nua_r_cancel,
1146 &nua_cancel_client_methods, tags);
1147
1148 if (error) {
1149 next_state = nua_callstate_terminated;
1150 cr->cr_terminated = 1;
1151 }
1152 cr->cr_graceful = 0;
1153 }
1154
1155 ss->ss_reporting = 0;
1156
1157 signal_call_state_change(nh, ss, status, phrase, (enum nua_callstate)next_state);
1158
1159 msg_destroy(response);
1160
1161 return 1;
1162}
1163
1164/**@fn void nua_ack(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
1165 *
1166 * Acknowledge a succesful response to INVITE request.
1167 *
1168 * Acknowledge a successful response (200..299) to INVITE request with the
1169 * SIP ACK request message. This function is needed only if NUTAG_AUTOACK()
1170 * parameter has been cleared.
1171 *
1172 * @param nh Pointer to operation handle
1173 * @param tag, value, ... List of tagged parameters
1174 *
1175 * @return
1176 * nothing
1177 *
1178 * @par Related Tags:
1179 * Header tags defined in <sofia-sip/sip_tag.h>
1180 *
1181 * @par Events:
1182 * #nua_i_media_error \n
1183 * #nua_i_state (#nua_i_active, #nua_i_terminated)
1184 *
1185 * @sa NUTAG_AUTOACK(), @ref nua_call_model, #nua_i_state
1186 */
1187
1188int nua_stack_ack(nua_t *nua, nua_handle_t *nh, nua_event_t e,
1189 tagi_t const *tags)
1190{
1191 nua_dialog_usage_t *du = nua_dialog_usage_for_session(nh->nh_ds);
1192 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
1193 nua_client_request_t *cr = du ? du->du_cr : NULL((void*)0);
1194 int error;
1195
1196 if (!cr || cr->cr_orq == NULL((void*)0) || cr->cr_status < 200) {
1197 UA_EVENT2(nua_i_error, 900, "No response to ACK")nua_stack_event(nua, nh, ((void*)0), nua_i_error, 900, "No response to ACK"
, ((void*)0))
;
1198 return 1;
1199 }
1200
1201 if (tags)
1202 nua_stack_set_params(nua, nh, nua_i_error, tags);
1203
1204 nua_client_request_ref(cr);
1205 error = nua_invite_client_ack(cr, tags);
1206
1207 if (error < 0) {
1208 if (ss->ss_reason == NULL((void*)0))
1209 ss->ss_reason = "SIP;cause=500;text=\"Internal Error\"";
1210 ss->ss_reporting = 1; /* We report terminated state here if BYE fails */
1211 error = nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL((void*)0));
1212 ss->ss_reporting = 0;
1213 signal_call_state_change(nh, ss, 500, "Internal Error",
1214 error
1215 ? nua_callstate_terminated
1216 : nua_callstate_terminating);
1217 }
1218 else if (ss)
1219 signal_call_state_change(nh, ss, 200, "ACK sent", nua_callstate_ready);
1220
1221 nua_client_request_unref(cr);
1222
1223 return 0;
1224}
1225
1226/** Send ACK, destroy INVITE transaction.
1227 *
1228 * @retval 1 if successful
1229 * @retval < 0 if an error occurred
1230 */
1231static
1232int nua_invite_client_ack(nua_client_request_t *cr, tagi_t const *tags)
1233{
1234 nua_handle_t *nh = cr->cr_owner;
1235 nua_dialog_state_t *ds = nh->nh_ds;
1236 nua_session_usage_t *ss = nua_dialog_usage_private(cr->cr_usage)((cr->cr_usage) ? (void*)((cr->cr_usage) + 1) : ((void*
)0))
;
1237
1238 msg_t *msg;
1239 sip_t *sip;
1240 int error = -1;
1241 sip_authorization_t *wa;
1242 sip_proxy_authorization_t *pa;
1243 sip_cseq_t *cseq;
1244 int proxy_is_set;
1245 url_string_t *proxy;
1246 nta_outgoing_t *ack;
1247 int status = 200;
1248 char const *phrase = "OK", *reason = NULL((void*)0);
1249 char const *invite_branch;
1250 char const *pl_s = NULL((void*)0);
1251
1252 assert(cr->cr_orq)((cr->cr_orq) ? (void) (0) : __assert_fail ("cr->cr_orq"
, "nua_session.c", 1252, __PRETTY_FUNCTION__))
;
1253 assert(cr->cr_method == sip_method_invite)((cr->cr_method == sip_method_invite) ? (void) (0) : __assert_fail
("cr->cr_method == sip_method_invite", "nua_session.c", 1253
, __PRETTY_FUNCTION__))
;
1254
1255 cr->cr_initial = 0;
1256
1257 if (!ds->ds_leg) {
1258 /* XXX - fix nua_dialog_usage_remove_at() instead! */
1259 goto error;
1260 }
1261
1262 tl_gets(tags,
1263 SIPTAG_PAYLOAD_STR_REF(pl_s)siptag_payload_str_ref, tag_str_vr(&(pl_s)),
1264 TAG_END()(tag_type_t)0, (tag_value_t)0);
1265
1266
1267 assert(ds->ds_leg)((ds->ds_leg) ? (void) (0) : __assert_fail ("ds->ds_leg"
, "nua_session.c", 1267, __PRETTY_FUNCTION__))
;
1268
1269 msg = nta_outgoing_getrequest(cr->cr_orq);
1270 sip = sip_object(msg);
1271 if (!msg)
1272 goto error;
1273 invite_branch = nta_outgoing_branch(cr->cr_orq);
1274
1275 wa = sip_authorization(sip)((sip_authorization_t *)msg_header_access((msg_pub_t*)(sip), sip_authorization_class
))
;
1276 pa = sip_proxy_authorization(sip)((sip_proxy_authorization_t *)msg_header_access((msg_pub_t*)(
sip), sip_proxy_authorization_class))
;
1277
1278 msg_destroy(msg);
1279
1280 msg = nta_msg_create(nh->nh_nua->nua_nta, 0);
1281 sip = sip_object(msg);
1282 if (!msg)
1283 goto error;
1284
1285 cseq = sip_cseq_create(msg_home(msg)((su_home_t*)(msg)), cr->cr_seq, SIP_METHOD_ACKsip_method_ack, "ACK");
1286
1287 if (!cseq)
1288 ;
1289 else if (nh->nh_tags && sip_add_tl(msg, sip, TAG_NEXT(nh->nh_tags)tag_next, (tag_value_t)(nh->nh_tags)) < 0)
1290 ;
1291 else if (tags && sip_add_tl(msg, sip, TAG_NEXT(tags)tag_next, (tag_value_t)(tags)) < 0)
1292 ;
1293 else if (wa && sip_add_dup(msg, sip, (sip_header_t *)wa) < 0)
1294 ;
1295 else if (pa && sip_add_dup(msg, sip, (sip_header_t *)pa) < 0)
1296 ;
1297 else if (sip_header_insert(msg, sip, (sip_header_t *)cseq) < 0)
1298 ;
1299 else if (nta_msg_request_complete(msg, ds->ds_leg, SIP_METHOD_ACKsip_method_ack, "ACK", NULL((void*)0)) < 0)
1300 ;
1301 else {
1302 /* Remove extra headers */
1303 while (sip->sip_allow)
1304 sip_header_remove(msg, sip, (sip_header_t*)sip->sip_allow);
1305 while (sip->sip_priority)
1306 sip_header_remove(msg, sip, (sip_header_t*)sip->sip_priority);
1307 while (sip->sip_proxy_require)
1308 sip_header_remove(msg, sip, (sip_header_t*)sip->sip_proxy_require);
1309 while (sip->sip_require)
1310 sip_header_remove(msg, sip, (sip_header_t*)sip->sip_require);
1311 while (sip->sip_subject)
1312 sip_header_remove(msg, sip, (sip_header_t*)sip->sip_subject);
1313 while (sip->sip_supported)
1314 sip_header_remove(msg, sip, (sip_header_t*)sip->sip_supported);
1315
1316 if (ss == NULL((void*)0) || ss->ss_state > nua_callstate_ready || pl_s)
1317 ;
1318 else if (cr->cr_offer_recv && !cr->cr_answer_sent) {
1319 if (nh->nh_soa == NULL((void*)0)) {
1320 if (session_get_description(sip, NULL((void*)0), NULL((void*)0)))
1321 cr->cr_answer_sent = 1, ss->ss_oa_sent = Answer;
1322 }
1323 else if (soa_generate_answer(nh->nh_soa, NULL((void*)0)) < 0 ||
1324 session_include_description(nh->nh_soa, 1, msg, sip) < 0) {
1325 status = 900, phrase = "Internal media error";
1326 reason = "SIP;cause=500;text=\"Internal media error\"";
1327 /* reason = soa_error_as_sip_reason(nh->nh_soa); */
1328 }
1329 else {
1330 cr->cr_answer_sent = 1, ss->ss_oa_sent = Answer;
1331 }
1332 }
1333
1334 if (ss == NULL((void*)0) || ss->ss_state > nua_callstate_ready || reason)
1335 ;
1336 else if (nh->nh_soa && soa_is_complete(nh->nh_soa)) {
1337 /* signal SOA that O/A round(s) is (are) complete */
1338 if (soa_activate(nh->nh_soa, NULL((void*)0)) >= 0) {
1339 ss->ss_sdp_version = soa_get_user_version(nh->nh_soa);
1340 }
1341 }
1342 else if (nh->nh_soa == NULL((void*)0)
1343 /* NUA does not necessarily know dirty details */
1344 /* && !(cr->cr_offer_sent && !cr->cr_answer_recv) */) {
1345 ;
1346 }
1347 else {
1348 nua_client_request_t *cru;
1349
1350 /* Final response to UPDATE or PRACK may be on its way ... */
1351 for (cru = ds->ds_cr; cru; cru = cru->cr_next) {
1352 if (cr != cru && cru->cr_offer_sent && !cru->cr_answer_recv)
1353 break;
1354 }
1355
1356 if (cru == NULL((void*)0)) {
1357 /* No SDP answer -> terminate call */
1358 status = 988, phrase = "Incomplete offer/answer";
1359 reason = "SIP;cause=488;text=\"Incomplete offer/answer\"";
1360 }
1361 }
1362
1363 proxy_is_set = NH_PISSET(nh, proxy)((((nh)->nh_prefs)->nhp_set_.set_bits.nhb_proxy) &&
(nh)->nh_nua->nua_handles->nh_prefs != (nh)->nh_prefs
)
;
1364 proxy = NH_PGET(nh, proxy)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_proxy ? ((nh)->
nh_prefs)->nhp_proxy : ((nh)->nh_nua->nua_handles->
nh_prefs)->nhp_proxy)
;
1365
1366 if ((ack = nta_outgoing_mcreate(nh->nh_nua->nua_nta, NULL((void*)0), NULL((void*)0), NULL((void*)0),
1367 msg,
1368 NTATAG_ACK_BRANCH(invite_branch)ntatag_ack_branch, tag_str_v((invite_branch)),
1369 TAG_IF(proxy_is_set,!(proxy_is_set) ? tag_skip : ntatag_default_proxy, urltag_url_v
((proxy))
1370 NTATAG_DEFAULT_PROXY(proxy))!(proxy_is_set) ? tag_skip : ntatag_default_proxy, urltag_url_v
((proxy))
,
1371 SIPTAG_END()siptag_end, (tag_value_t)0,
1372 TAG_NEXT(tags)tag_next, (tag_value_t)(tags)))) {
1373 /* TR engine keeps this around for T2 so it catches all 2XX retransmissions */
1374 nta_outgoing_destroy(ack);
1375
1376 if (nh->nh_soa && reason && ss && ss->ss_state <= nua_callstate_ready)
1377 nua_stack_event(nh->nh_nua, nh, NULL((void*)0),
1378 nua_i_media_error, status, phrase,
1379 NULL((void*)0));
1380 }
1381 else if (!reason) {
1382 status = 900, phrase = "Cannot send ACK";
1383 reason = "SIP;cause=500;text=\"Internal Error\"";
1384 }
1385
1386 if (ss && reason)
1387 ss->ss_reason = reason;
1388
1389 if (status < 300)
1390 error = 1;
1391 else
1392 error = -2;
1393 }
1394
1395 if (error == -1)
1396 msg_destroy(msg);
1397
1398 error:
1399 cr->cr_acked = 1; /* ... or we have at least tried */
1400
1401 nua_client_request_remove(cr);
1402 nua_client_request_clean(cr);
1403
1404 return error;
1405}
1406
1407static int
1408nua_invite_client_should_ack(nua_client_request_t const *cr)
1409{
1410 return
1411 cr && cr->cr_orq && !cr->cr_acked &&
1412 200 <= cr->cr_status && cr->cr_status < 300;
1413}
1414
1415/** Complete client request */
1416static int nua_invite_client_complete(nua_client_request_t *cr)
1417{
1418 if (cr->cr_orq == NULL((void*)0))
1419 /* Xyzzy */;
1420 else if (cr->cr_status < 200)
1421 nta_outgoing_cancel(cr->cr_orq);
1422 else if (cr->cr_status < 300 && !cr->cr_acked)
1423 nua_invite_client_ack(cr, NULL((void*)0));
1424
1425 return 0;
1426}
1427
1428/**@fn void nua_cancel(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
1429 *
1430 * Cancel an INVITE operation
1431 *
1432 * @param nh Pointer to operation handle
1433 * @param tag, value, ... List of tagged parameters
1434 *
1435 * @return
1436 * nothing
1437 *
1438 * @par Related Tags:
1439 * Header tags defined in <sofia-sip/sip_tag.h>
1440 *
1441 * @par Events:
1442 * #nua_r_cancel, #nua_i_state (#nua_i_active, #nua_i_terminated)
1443 *
1444 * @sa @ref nua_call_model, nua_invite(), #nua_i_cancel
1445 */
1446
1447static int nua_cancel_client_request(nua_client_request_t *cr,
1448 msg_t *msg, sip_t *sip,
1449 tagi_t const *tags);
1450static int nua_cancel_client_check_restart(nua_client_request_t *cr,
1451 int status,
1452 char const *phrase,
1453 sip_t const *sip);
1454
1455nua_client_methods_t const nua_cancel_client_methods = {
1456 SIP_METHOD_CANCELsip_method_cancel, "CANCEL", /* crm_method, crm_method_name */
1457 0, /* crm_extra */
1458 { /* crm_flags */
1459 /* create_dialog */ 0,
1460 /* in_dialog */ 1,
1461 /* target refresh */ 0
1462 },
1463 NULL((void*)0), /* crm_template */
1464 NULL((void*)0), /* crm_init */
1465 nua_cancel_client_request, /* .. not really crm_send */
1466 nua_cancel_client_check_restart, /* crm_check_restart */
1467 NULL((void*)0), /* crm_recv */
1468 NULL((void*)0), /* crm_preliminary */
1469 NULL((void*)0), /* crm_report */
1470 NULL((void*)0), /* crm_complete */
1471};
1472
1473int nua_stack_cancel(nua_t *nua, nua_handle_t *nh, nua_event_t e,
1474 tagi_t const *tags)
1475{
1476 return nua_client_create(nh, e, &nua_cancel_client_methods, tags);
1477}
1478
1479static int nua_cancel_client_request(nua_client_request_t *cr,
1480 msg_t *msg, sip_t *sip,
1481 tagi_t const *tags)
1482{
1483 nua_handle_t *nh = cr->cr_owner;
1484 nua_dialog_usage_t *du = nua_dialog_usage_for_session(nh->nh_ds);
1485
1486 if (!du || !du->du_cr || !du->du_cr->cr_orq ||
1487 nta_outgoing_status(du->du_cr->cr_orq) >= 200) {
1488 return nua_client_return(cr, 481, "No transaction to CANCEL", msg);
1489 }
1490
1491 assert(cr->cr_orq == NULL)((cr->cr_orq == ((void*)0)) ? (void) (0) : __assert_fail (
"cr->cr_orq == ((void*)0)", "nua_session.c", 1491, __PRETTY_FUNCTION__
))
;
1492
1493 cr->cr_orq = nta_outgoing_tcancel(du->du_cr->cr_orq,
1494 nua_client_orq_response,
1495 nua_client_request_ref(cr),
1496 TAG_NEXT(tags)tag_next, (tag_value_t)(tags));
1497
1498 if (cr->cr_orq == NULL((void*)0)) {
1499 nua_client_request_unref(cr);
1500 return -1;
1501 }
1502
1503 return 0;
1504}
1505
1506static int
1507nua_cancel_client_check_restart(nua_client_request_t *cr,
1508 int status,
1509 char const *phrase,
1510 sip_t const *sip)
1511{
1512 /* We cannot really restart CANCEL */
1513 return 0;
1514}
1515
1516/** @NUA_EVENT nua_r_cancel
1517 *
1518 * Answer to outgoing CANCEL.
1519 *
1520 * The CANCEL may be sent explicitly by nua_cancel() or implicitly by NUA
1521 * state machine.
1522 *
1523 * @param status response status code
1524 * @param phrase a short textual description of @a status code
1525 * @param nh operation handle associated with the call
1526 * @param hmagic application context associated with the call
1527 * @param sip response to CANCEL request or NULL upon an error
1528 * (status code is in @a status and
1529 * descriptive message in @a phrase parameters)
1530 * @param tags empty
1531 *
1532 * @sa nua_cancel(), @ref nua_uac_call_model, #nua_r_invite, nua_invite(),
1533 * #nua_i_state
1534 *
1535 * @END_NUA_EVENT
1536 */
1537
1538static void nua_session_usage_refresh(nua_handle_t *nh,
1539 nua_dialog_state_t *ds,
1540 nua_dialog_usage_t *du,
1541 sip_time_t now)
1542{
1543 nua_session_usage_t *ss = NUA_DIALOG_USAGE_PRIVATE(du)((void *)((du) + 1));
1544 nua_client_request_t const *cr = du->du_cr;
1545 nua_server_request_t const *sr;
1546
1547 if (ss->ss_state >= nua_callstate_terminating ||
1548 /* INVITE is in progress or being authenticated */
1549 nua_client_request_in_progress(cr))
1550 return;
1551
1552 if (ds->ds_cr) return; /* request queued */
1553
1554 /* UPDATE has been queued */
1555 //for (cr = ds->ds_cr; cr; cr = cr->cr_next)
1556 //if (cr->cr_method == sip_method_update)
1557 // return;
1558
1559 /* INVITE or UPDATE in progress on server side */
1560 for (sr = ds->ds_sr; sr; sr = sr->sr_next)
1561 if (sr->sr_usage == du &&
1562 (sr->sr_method == sip_method_invite ||
1563 sr->sr_method == sip_method_update))
1564 return;
1565
1566 if (ss->ss_timer->refresher == nua_remote_refresher) {
1567 SU_DEBUG_3(("nua(%p): session almost expired, sending BYE before timeout.\n", (void *)nh))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_session.c"
, (const char *)__func__, 1567, "nua(%p): session almost expired, sending BYE before timeout.\n"
, (void *)nh)) : (void)0)
;
1568 ss->ss_reason = "SIP;cause=408;text=\"Session timeout\"";
1569 nua_stack_bye(nh->nh_nua, nh, nua_r_bye, NULL((void*)0));
1570 return;
1571 }
1572 else if (NH_PGET(nh, update_refresh)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_update_refresh
? ((nh)->nh_prefs)->nhp_update_refresh : ((nh)->nh_nua
->nua_handles->nh_prefs)->nhp_update_refresh)
) {
1573 nua_stack_update(nh->nh_nua, nh, nua_r_update, NULL((void*)0));
1574 }
1575 else if (du->du_cr) {
1576 nua_client_resend_request(du->du_cr, 0);
1577 }
1578 else {
1579 nua_stack_invite(nh->nh_nua, nh, nua_r_invite, NULL((void*)0));
1580 }
1581}
1582
1583/** @interal Shut down session usage.
1584 *
1585 * @retval >0 shutdown done
1586 * @retval 0 shutdown in progress
1587 * @retval <0 try again later
1588 */
1589static int nua_session_usage_shutdown(nua_handle_t *nh,
1590 nua_dialog_state_t *ds,
1591 nua_dialog_usage_t *du)
1592{
1593 nua_session_usage_t *ss = NUA_DIALOG_USAGE_PRIVATE(du)((void *)((du) + 1));
1594 nua_server_request_t *sr, *sr_next;
1595 nua_client_request_t *cri;
1596
1597 assert(ss == nua_session_usage_for_dialog(nh->nh_ds))((ss == nua_session_usage_for_dialog(nh->nh_ds)) ? (void) (
0) : __assert_fail ("ss == nua_session_usage_for_dialog(nh->nh_ds)"
, "nua_session.c", 1597, __PRETTY_FUNCTION__))
;
1598
1599 /* Zap server-side transactions */
1600 for (sr = ds->ds_sr; sr; sr = sr_next) {
1601 sr_next = sr->sr_next;
1602 if (sr->sr_usage == du) {
1603 assert(sr->sr_usage == du)((sr->sr_usage == du) ? (void) (0) : __assert_fail ("sr->sr_usage == du"
, "nua_session.c", 1603, __PRETTY_FUNCTION__))
;
1604 sr->sr_usage = NULL((void*)0);
1605
1606 if (nua_server_request_is_pending(sr)) {
1607 SR_STATUS1(sr, SIP_480_TEMPORARILY_UNAVAILABLE)sr_status(sr, 480, sip_480_Temporarily_unavailable);
1608 nua_server_respond(sr, NULL((void*)0));
1609 if (nua_server_report(sr) >= 2)
1610 return 480;
1611 }
1612 else
1613 nua_server_request_destroy(sr);
1614 }
1615 }
1616
1617 cri = du->du_cr;
1618
1619 switch (ss->ss_state) {
1620 case nua_callstate_calling:
1621 case nua_callstate_proceeding:
1622 return nua_client_create(nh, nua_r_cancel, &nua_cancel_client_methods, NULL((void*)0));
1623
1624 case nua_callstate_completing:
1625 case nua_callstate_completed:
1626 case nua_callstate_ready:
1627 if (cri && cri->cr_orq) {
1628 if (cri->cr_status < 200) {
1629 nua_client_create(nh, nua_r_cancel, &nua_cancel_client_methods, NULL((void*)0));
1630 }
1631 else if (cri->cr_status < 300 && !cri->cr_acked) {
1632 nua_invite_client_ack(cri, NULL((void*)0));
1633 }
1634 }
1635 if (nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL((void*)0)) != 0)
1636 break;
1637
1638 signal_call_state_change(nh, ss, 487, "BYE sent",
1639 nua_callstate_terminating);
1640 return 0;
1641
1642 case nua_callstate_terminating:
1643 case nua_callstate_terminated: /* XXX */
1644 return 0;
1645
1646 default:
1647 break;
1648 }
1649
1650 nua_dialog_usage_remove(nh, ds, du, NULL((void*)0), NULL((void*)0));
1651
1652 return 200;
1653}
1654
1655/**@fn void nua_prack(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
1656 * Send a PRACK request.
1657 *
1658 * PRACK is used to acknowledge receipt of 100rel responses. See @RFC3262.
1659 *
1660 * @param nh Pointer to operation handle
1661 * @param tag, value, ... List of tagged parameters
1662 *
1663 * @return
1664 * nothing
1665 *
1666 * @par Related Tags:
1667 * Tags in <sofia-sip/soa_tag.h>, <sofia-sip/sip_tag.h>.
1668 *
1669 * @par Events:
1670 * #nua_r_prack
1671 */
1672
1673/** @NUA_EVENT nua_r_prack
1674 *
1675 * Response to an outgoing @b PRACK request. PRACK request is used to
1676 * acknowledge reliable preliminary responses and it is usually sent
1677 * automatically by the nua stack.
1678 *
1679 * @param status response status code
1680 * (if the request is retried, @a status is 100, the @a
1681 * sip->sip_status->st_status contain the real status code
1682 * from the response message, e.g., 302, 401, or 407)
1683 * @param phrase a short textual description of @a status code
1684 * @param nh operation handle associated with the call
1685 * @param hmagic application context associated with the call
1686 * @param sip response to @b PRACK or NULL upon an error
1687 * (status code is in @a status and
1688 * descriptive message in @a phrase parameters)
1689 * @param tags empty
1690 *
1691 * @sa nua_prack(), #nua_i_prack, @RFC3262
1692 *
1693 * @END_NUA_EVENT
1694 */
1695
1696static int nua_prack_client_init(nua_client_request_t *cr,
1697 msg_t *msg, sip_t *sip,
1698 tagi_t const *tags);
1699static int nua_prack_client_request(nua_client_request_t *cr,
1700 msg_t *msg, sip_t *sip,
1701 tagi_t const *tags);
1702static int nua_prack_client_response(nua_client_request_t *cr,
1703 int status, char const *phrase,
1704 sip_t const *sip);
1705static int nua_prack_client_report(nua_client_request_t *cr,
1706 int status, char const *phrase,
1707 sip_t const *sip,
1708 nta_outgoing_t *orq,
1709 tagi_t const *tags);
1710
1711nua_client_methods_t const nua_prack_client_methods = {
1712 SIP_METHOD_PRACKsip_method_prack, "PRACK", /* crm_method, crm_method_name */
1713 0, /* crm_extra */
1714 { /* crm_flags */
1715 /* create_dialog */ 0,
1716 /* in_dialog */ 1,
1717 /* target refresh */ 0
1718 },
1719 NULL((void*)0), /* crm_template */
1720 nua_prack_client_init, /* crm_init */
1721 nua_prack_client_request, /* crm_send */
1722 NULL((void*)0), /* crm_check_restart */
1723 nua_prack_client_response, /* crm_recv */
1724 NULL((void*)0), /* crm_preliminary */
1725 nua_prack_client_report, /* crm_report */
1726 NULL((void*)0), /* crm_complete */
1727};
1728
1729int nua_stack_prack(nua_t *nua, nua_handle_t *nh, nua_event_t e,
1730 tagi_t const *tags)
1731{
1732 return nua_client_create(nh, e, &nua_prack_client_methods, tags);
1733}
1734
1735static int nua_prack_client_init(nua_client_request_t *cr,
1736 msg_t *msg, sip_t *sip,
1737 tagi_t const *tags)
1738{
1739 nua_handle_t *nh = cr->cr_owner;
1740 nua_dialog_usage_t *du = nua_dialog_usage_for_session(nh->nh_ds);
1741
1742 cr->cr_usage = du;
1743
1744 return 0;
1745}
1746
1747static int nua_prack_client_request(nua_client_request_t *cr,
1748 msg_t *msg, sip_t *sip,
1749 tagi_t const *tags)
1750{
1751 nua_handle_t *nh = cr->cr_owner;
1752 nua_dialog_usage_t *du = cr->cr_usage;
1753 nua_session_usage_t *ss;
1754 nua_client_request_t *cri;
1755 int offer_sent = 0, answer_sent = 0, retval;
1756 int status = 0; char const *phrase = "PRACK Sent";
1757 //uint32_t rseq = 0;
1758
1759 if (du == NULL((void*)0)) /* Call terminated */
1760 return nua_client_return(cr, SIP_481_NO_TRANSACTION481, sip_481_No_transaction, msg);
1761
1762 ss = NUA_DIALOG_USAGE_PRIVATE(du)((void *)((du) + 1));
1763 if (ss->ss_state >= nua_callstate_terminating)
1764 return nua_client_return(cr, 900, "Session is terminating", msg);
1765
1766 cri = du->du_cr;
1767
1768// if (sip->sip_rack)
1769// rseq = sip->sip_rack->ra_response;
1770
1771 if (cri->cr_offer_recv && !cri->cr_answer_sent) {
1772 if (nh->nh_soa == NULL((void*)0))
1773 /* It is up to application to handle SDP */
1774 answer_sent = session_get_description(sip, NULL((void*)0), NULL((void*)0));
1775 else if (sip->sip_payload)
1776 /* XXX - we should just do MIME in session_include_description() */;
1777 else if (soa_generate_answer(nh->nh_soa, NULL((void*)0)) < 0 ||
1778 session_include_description(nh->nh_soa, 1, msg, sip) < 0) {
1779 status = soa_error_as_sip_response(nh->nh_soa, &phrase);
1780 SU_DEBUG_3(("nua(%p): local response to PRACK: %d %s\n",((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_session.c"
, (const char *)__func__, 1781, "nua(%p): local response to PRACK: %d %s\n"
, (void *)nh, status, phrase)) : (void)0)
1781 (void *)nh, status, phrase))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_session.c"
, (const char *)__func__, 1781, "nua(%p): local response to PRACK: %d %s\n"
, (void *)nh, status, phrase)) : (void)0)
;
1782 nua_stack_event(nh->nh_nua, nh, NULL((void*)0),
1783 nua_i_media_error, status, phrase,
1784 NULL((void*)0));
1785 return nua_client_return(cr, status, phrase, msg);
1786 }
1787 else {
1788 answer_sent = 1;
1789 if (soa_activate(nh->nh_soa, NULL((void*)0)) >= 0) {
1790 ss->ss_sdp_version = soa_get_user_version(nh->nh_soa);
1791 }
1792 }
1793 }
1794 else if (nh->nh_soa == NULL((void*)0)) {
1795 offer_sent = session_get_description(sip, NULL((void*)0), NULL((void*)0));
1796 }
1797 else {
1798 /* When 100rel response status was 183 do support for preconditions */
1799 int send_offer = ss->ss_precondition &&
1800 cri->cr_status == 183 && cri->cr_offer_sent && cri->cr_answer_recv;
1801
1802 if (!send_offer) {
1803 tagi_t const *t = tl_find_last(tags, nutag_include_extra_sdp);
1804 send_offer = t && t->t_value;
1805 }
1806
1807 if (!send_offer) {
1808 }
1809 else if (soa_generate_offer(nh->nh_soa, 0, NULL((void*)0)) >= 0 &&
1810 session_include_description(nh->nh_soa, 1, msg, sip) >= 0) {
1811 offer_sent = 1;
1812 }
1813 else {
1814 status = soa_error_as_sip_response(nh->nh_soa, &phrase);
1815 SU_DEBUG_3(("nua(%p): PRACK offer: %d %s\n", (void *)nh,((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_session.c"
, (const char *)__func__, 1816, "nua(%p): PRACK offer: %d %s\n"
, (void *)nh, status, phrase)) : (void)0)
1816 status, phrase))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_session.c"
, (const char *)__func__, 1816, "nua(%p): PRACK offer: %d %s\n"
, (void *)nh, status, phrase)) : (void)0)
;
1817 nua_stack_event(nh->nh_nua, nh, NULL((void*)0),
1818 nua_i_media_error, status, phrase, NULL((void*)0));
1819 return nua_client_return(cr, status, phrase, msg);
1820 }
1821 }
1822
1823 retval = nua_base_client_request(cr, msg, sip, NULL((void*)0));
1824
1825 if (retval == 0) {
1826 cr->cr_offer_sent = offer_sent;
1827 cr->cr_answer_sent = answer_sent;
1828
1829 if (offer_sent)
1830 ss->ss_oa_sent = Offer;
1831 else if (answer_sent)
1832 ss->ss_oa_sent = Answer;
1833
1834 if (cr->cr_restarting)
1835 /* Restart logic calls nua_prack_client_report */;
1836 else if (!cr->cr_auto && (!offer_sent || !answer_sent))
1837 /* Suppose application know it called nua_prack() */;
1838 else
1839 signal_call_state_change(nh, ss, status, phrase, ss->ss_state);
1840 }
1841
1842 return retval;
1843}
1844
1845static int nua_prack_client_response(nua_client_request_t *cr,
1846 int status, char const *phrase,
1847 sip_t const *sip)
1848{
1849 /* XXX - fatal error cases? */
1850
1851 return nua_session_client_response(cr, status, phrase, sip);
1852}
1853
1854static int nua_prack_client_report(nua_client_request_t *cr,
1855 int status, char const *phrase,
1856 sip_t const *sip,
1857 nta_outgoing_t *orq,
1858 tagi_t const *tags)
1859{
1860 nua_handle_t *nh = cr->cr_owner;
1861 nua_dialog_usage_t *du = cr->cr_usage;
1862 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
1863 int acked = 0;
1864
1865 nua_stack_event(nh->nh_nua, nh,
1866 nta_outgoing_getresponse(orq),
1867 (enum nua_event_e)cr->cr_event,
1868 status, phrase,
1869 tags);
1870
1871 if (!ss || cr->cr_terminated || cr->cr_graceful || cr->cr_waiting)
1872 return 1;
1873
1874 if (cr->cr_offer_sent || cr->cr_answer_sent) {
1875 unsigned next_state = ss->ss_state;
1876
1877 if (status < 200)
1878 ;
1879 else if (nua_invite_client_should_ack(du->du_cr)) {
1880 /* There is an un-ACK-ed INVITE there */
1881 assert(du->du_cr->cr_method == sip_method_invite)((du->du_cr->cr_method == sip_method_invite) ? (void) (
0) : __assert_fail ("du->du_cr->cr_method == sip_method_invite"
, "nua_session.c", 1881, __PRETTY_FUNCTION__))
;
1882 if (NH_PGET(nh, auto_ack)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_auto_ack ? ((nh
)->nh_prefs)->nhp_auto_ack : ((nh)->nh_nua->nua_handles
->nh_prefs)->nhp_auto_ack)
||
1883 /* Auto-ACK response to re-INVITE when media is enabled
1884 and auto_ack is not set to 0 on handle */
1885 (ss->ss_state == nua_callstate_ready && nh->nh_soa &&
1886 !NH_PISSET(nh, auto_ack)((((nh)->nh_prefs)->nhp_set_.set_bits.nhb_auto_ack) &&
(nh)->nh_nua->nua_handles->nh_prefs != (nh)->nh_prefs
)
)) {
1887 /* There should be no UPDATE with offer/answer
1888 if PRACK with offer/answer was ongoing! */
1889 if (nua_invite_client_ack(du->du_cr, NULL((void*)0)) > 0)
1890 next_state = nua_callstate_ready;
1891 else
1892 next_state = nua_callstate_terminating;
1893
1894 acked = 1;
1895 }
1896 }
1897
1898 signal_call_state_change(nh, ss, status, phrase, (enum nua_callstate)next_state);
1899 }
1900
1901 if (acked &&
1902 nua_client_is_queued(du->du_cr) &&
1903 du->du_cr->cr_method == sip_method_invite) {
1904 /* New INVITE was queued - do not send UPDATE */
1905 }
1906 else if (ss->ss_update_needed && 200 <= status && status < 300 &&
1907 !SIP_IS_ALLOWED(NH_PGET(nh, appl_method), sip_method_update)(sip_method_unknown < (sip_method_update) && (sip_method_update
) < 32 && ((((nh)->nh_prefs)->nhp_set_.set_bits
.nhb_appl_method ? ((nh)->nh_prefs)->nhp_appl_method : (
(nh)->nh_nua->nua_handles->nh_prefs)->nhp_appl_method
)) && (((((nh)->nh_prefs)->nhp_set_.set_bits.nhb_appl_method
? ((nh)->nh_prefs)->nhp_appl_method : ((nh)->nh_nua
->nua_handles->nh_prefs)->nhp_appl_method))->k_bitmap
& (1 << (sip_method_update))) != 0)
)
1908 nua_client_create(nh, nua_r_update, &nua_update_client_methods, NULL((void*)0));
1909
1910 return 1;
1911}
1912
1913/* ---------------------------------------------------------------------- */
1914/* UAS side of INVITE */
1915
1916/** @NUA_EVENT nua_i_invite
1917 *
1918 * Indication of incoming call or re-INVITE request.
1919 *
1920 * @param status statuscode of response sent automatically by stack
1921 * @param phrase a short textual description of @a status code
1922 * @param nh operation handle associated with this call
1923 * (maybe created for this call)
1924 * @param hmagic application context associated with this call
1925 * (maybe NULL if call handle was created for this call)
1926 * @param sip incoming INVITE request
1927 * @param tags SOATAG_ACTIVE_AUDIO(), SOATAG_ACTIVE_VIDEO()
1928 *
1929 * @par
1930 * @par Responding to INVITE with nua_respond()
1931 *
1932 * If @a status in #nua_i_invite event is below 200, the application should
1933 * accept or reject the call with nua_respond(). See the @ref nua_call_model
1934 * for the detailed explanation of various options in call processing at
1935 * server end.
1936 *
1937 * The @b INVITE request takes care of session setup using SDP Offer-Answer
1938 * negotiation as specified in @RFC3264 (updated in @RFC3262 section 5,
1939 * @RFC3311, and @RFC3312). The Offer-Answer can be taken care by
1940 * application (if NUTAG_MEDIA_ENABLE(0) parameter has been set) or by the
1941 * built-in SDP Offer/Answer engine @soa (by default and when
1942 * NUTAG_MEDIA_ENABLE(1) parameter has been set). When @soa is enabled, it
1943 * will take care of parsing the SDP, negotiating the media and codecs, and
1944 * including the SDP in the SIP message bodies as required by the
1945 * Offer-Answer model.
1946 *
1947 * When @soa is enabled, the SDP in the incoming INVITE is parsed and feed
1948 * to a #soa_session_t object. The #nua_i_state event sent to the
1949 * application immediately after #nua_i_invite will contain the parsing
1950 * results in SOATAG_REMOTE_SDP() and SOATAG_REMOTE_SDP_STR() tags.
1951 *
1952 * Note that currently the parser within @nua does not handle MIME
1953 * multipart. The SDP Offer/Answer engine can get confused if the SDP offer
1954 * is included in a MIME multipart, therefore such an @b INVITE is rejected
1955 * with <i>415 Unsupported Media Type</i> error response: the client is
1956 * expected to retry the INVITE without MIME multipart content.
1957 *
1958 * If the call is to be accepted, the application should include the SDP in
1959 * the 2XX response. If @soa is not disabled with NUTAG_MEDIA_ENABLE(0), the
1960 * SDP should be included in the SOATAG_USER_SDP() or SOATAG_USER_SDP_STR()
1961 * parameter given to nua_respond(). If it is disabled, the SDP should be
1962 * included in the response message using SIPTAG_PAYLOAD() or
1963 * SIPTAG_PAYLOAD_STR(). Also, the @ContentType should be set using
1964 * SIPTAG_CONTENT_TYPE() or SIPTAG_CONTENT_TYPE_STR().
1965 *
1966 * @par Preliminary Responses and 100rel
1967 *
1968 * Call progress can be signaled with preliminary responses (with status
1969 * code in the range 101..199). It is possible to conclude the SDP
1970 * Offer-Answer negotiation using preliminary responses, too. If
1971 * NUTAG_EARLY_ANSWER(1), SOATAG_USER_SDP() or SOATAG_USER_SDP_STR()
1972 * parameter is included with in a preliminary nua_response(), the SDP
1973 * answer is generated and sent with the preliminary responses, too.
1974 *
1975 * The preliminary responses are sent reliably if feature tag "100rel" is
1976 * included in the @Require header of the response or if
1977 * NUTAG_EARLY_MEDIA(1) parameter has been given. The reliably delivery of
1978 * preliminary responses mean that a sequence number is included in the
1979 * @RSeq header in the response message and the response message is resent
1980 * until the client responds with a @b PRACK request with matching sequence
1981 * number in @RAck header.
1982 *
1983 * Note that only the "183" response is sent reliably if the
1984 * NUTAG_ONLY183_100REL(1) parameter has been given. The reliable
1985 * preliminary responses are acknowledged with @b PRACK request sent by the
1986 * client.
1987 *
1988 * Note if the SDP offer-answer is completed with the reliable preliminary
1989 * responses, the is no need to include SDP in 200 OK response (or other 2XX
1990 * response). However, it the tag NUTAG_INCLUDE_EXTRA_SDP(1) is included
1991 * with nua_respond(), a copy of the SDP answer generated earlier by @soa is
1992 * included as the message body.
1993 *
1994 * @sa nua_respond(), @ref nua_uas_call_model, #nua_i_state,
1995 * NUTAG_MEDIA_ENABLE(), SOATAG_USER_SDP(), SOATAG_USER_SDP_STR(),
1996 * @RFC3262, NUTAG_EARLY_ANSWER(), NUTAG_EARLY_MEDIA(),
1997 * NUTAG_ONLY183_100REL(),
1998 * NUTAG_INCLUDE_EXTRA_SDP(),
1999 * #nua_i_prack, #nua_i_update, nua_update(),
2000 * nua_invite(), #nua_r_invite
2001 *
2002 * @par
2003 * @par Third Party Call Control
2004 *
2005 * When so called 2rd party call control is used, the initial @b INVITE may
2006 * not contain SDP offer. In that case, the offer is sent by the recipient
2007 * of the @b INVITE request (User-Agent Server, UAS). The SDP sent in 2XX
2008 * response (or in a preliminary reliable response) is considered as an
2009 * offer, and the answer will be included in the @b ACK request sent by the
2010 * UAC (or @b PRACK in case of preliminary reliable response).
2011 *
2012 * @sa @ref nua_3pcc_call_model
2013 *
2014 * @END_NUA_EVENT
2015 */
2016
2017static int nua_invite_server_init(nua_server_request_t *sr);
2018static int nua_session_server_init(nua_server_request_t *sr);
2019static int nua_invite_server_preprocess(nua_server_request_t *sr);
2020static int nua_invite_server_respond(nua_server_request_t *sr, tagi_t const *);
2021static int nua_invite_server_is_100rel(nua_server_request_t *, tagi_t const *);
2022static int nua_invite_server_report(nua_server_request_t *sr, tagi_t const *);
2023
2024static int
2025 process_ack_or_cancel(nua_server_request_t *, nta_incoming_t *,
2026 sip_t const *),
2027 process_ack(nua_server_request_t *, nta_incoming_t *, sip_t const *),
2028 process_ack_error(nua_server_request_t *sr, msg_t *ackmsg,
2029 int status, char const *phrase, char const *reason),
2030 process_cancel(nua_server_request_t *, nta_incoming_t *, sip_t const *),
2031 process_timeout(nua_server_request_t *, nta_incoming_t *),
2032 process_prack(nua_server_request_t *,
2033 nta_reliable_t *rel,
2034 nta_incoming_t *irq,
2035 sip_t const *sip);
2036
2037nua_server_methods_t const nua_invite_server_methods =
2038 {
2039 SIP_METHOD_INVITEsip_method_invite, "INVITE",
2040 nua_i_invite, /* Event */
2041 {
2042 1, /* Create dialog */
2043 0, /* Initial request */
2044 1, /* Target refresh request */
2045 1, /* Add Contact */
2046 },
2047 nua_invite_server_init,
2048 nua_invite_server_preprocess,
2049 nua_base_server_params((void*)0),
2050 nua_invite_server_respond,
2051 nua_invite_server_report,
2052 };
2053
2054
2055/** @internal Preprocess incoming invite - sure we have a valid request.
2056 *
2057 * @return 0 if request is valid, or error statuscode otherwise
2058 */
2059static int
2060nua_invite_server_init(nua_server_request_t *sr)
2061{
2062 nua_handle_t *nh = sr->sr_owner;
2063 nua_t *nua = nh->nh_nua;
2064 nua_session_usage_t *ss;
2065
2066 sr->sr_neutral = 1;
2067
2068 if (!NUA_PGET(nua, nh, invite_enable)(((nh) ? (nh)->nh_prefs : (nua)->nua_handles->nh_prefs
)->nhp_set_.set_bits.nhb_invite_enable ? ((nh) ? (nh)->
nh_prefs : (nua)->nua_handles->nh_prefs)->nhp_invite_enable
: ((nua)->nua_handles->nh_prefs)->nhp_invite_enable
)
)
2069 return SR_STATUS1(sr, SIP_403_FORBIDDEN)sr_status(sr, 403, sip_403_Forbidden);
2070
2071 if (nua_session_server_init(sr))
2072 return sr->sr_status;
2073
2074 if (sr->sr_usage) {
2075 /* Existing session - check for overlap and glare */
2076
2077 nua_server_request_t const *sr0;
2078 nua_client_request_t const *cr;
2079
2080 for (sr0 = nh->nh_ds->ds_sr; sr0; sr0 = sr0->sr_next) {
2081 /* Previous INVITE has not been ACKed */
2082 if (sr0->sr_method == sip_method_invite)
2083 break;
2084 /* Or we have sent offer but have not received an answer */
2085 if (sr->sr_sdp && sr0->sr_offer_sent && !sr0->sr_answer_recv)
2086 break;
2087 /* Or we have received request with offer but not sent an answer */
2088 if (sr->sr_sdp && sr0->sr_offer_recv && !sr0->sr_answer_sent)
2089 break;
2090 }
2091
2092 if (sr0) {
2093 /* Overlapping invites - RFC 3261 14.2 */
2094 return nua_server_retry_after(sr, 500, "Overlapping Requests", 0, 10);
2095 }
2096
2097 for (cr = nh->nh_ds->ds_cr; cr; cr = cr->cr_next) {
2098 if (cr->cr_usage == sr->sr_usage && cr->cr_orq && cr->cr_offer_sent)
2099 /* Glare - RFC 3261 14.2 and RFC 3311 section 5.2 */
2100 return SR_STATUS1(sr, SIP_491_REQUEST_PENDING)sr_status(sr, 491, sip_491_Request_pending);
2101 }
2102
2103 ss = nua_dialog_usage_private(sr->sr_usage)((sr->sr_usage) ? (void*)((sr->sr_usage) + 1) : ((void*
)0))
;
2104
2105 if (ss->ss_state < nua_callstate_ready &&
2106 ss->ss_state != nua_callstate_init) {
2107 return nua_server_retry_after(sr, 500, "Overlapping Requests 2", 0, 10);
2108 }
2109 }
2110
2111 sr->sr_neutral = 0;
2112
2113 return 0;
2114}
2115
2116/** Initialize session server request.
2117 *
2118 * Ensure that the request is valid.
2119 */
2120static int
2121nua_session_server_init(nua_server_request_t *sr)
2122{
2123 nua_handle_t *nh = sr->sr_owner;
2124 nua_t *nua = nh->nh_nua;
2125
2126 msg_t *msg = sr->sr_response.msg;
2127 sip_t *sip = sr->sr_response.sip;
2128
2129 sip_t *request = (sip_t *) sr->sr_request.sip;
2130
2131 if (!sr->sr_initial)
2132 sr->sr_usage = nua_dialog_usage_get(nh->nh_ds, nua_session_usage, NULL((void*)0));
2133
2134 if (sr->sr_method != sip_method_invite && sr->sr_usage == NULL((void*)0)) {
2135 /* UPDATE/PRACK sent within an existing dialog? */
2136 return SR_STATUS(sr, 481, "Call Does Not Exist")((sr)->sr_phrase = ("Call Does Not Exist"), (sr)->sr_status
= (481))
;
2137 }
2138 else if (sr->sr_usage) {
2139 nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage)((sr->sr_usage) ? (void*)((sr->sr_usage) + 1) : ((void*
)0))
;
2140 if (ss->ss_state >= nua_callstate_terminating)
2141 return SR_STATUS(sr, 481, "Call is being terminated")((sr)->sr_phrase = ("Call is being terminated"), (sr)->
sr_status = (481))
;
2142 }
2143
2144 if (nh->nh_soa) {
2145 sip_accept_t *a = nua->nua_invite_accept;
2146
2147 /* XXX - soa should know what it supports */
2148 sip_add_dup(msg, sip, (sip_header_t *)a);
2149
2150 /* if we see there is a multipart content-type,
2151 parse it into the sip structre and find the SDP and replace it
2152 into the request as the requested content */
2153 if (request->sip_content_type &&
2154 su_casenmatch(request->sip_content_type->c_type, "multipart/", 10)) {
2155 msg_multipart_t *mp, *mpp;
2156
2157 if (request->sip_multipart) {
2158 mp = request->sip_multipart;
2159 } else {
2160 mp = msg_multipart_parse(nua_handle_home(nh)((su_home_t *)(nh)),
2161 request->sip_content_type,
2162 (sip_payload_t *)request->sip_payload);
2163 request->sip_multipart = mp;
2164 }
2165
2166 if (mp) {
2167 int sdp = 0;
2168
2169 /* extract the SDP and set the primary content-type and payload to that SDP as if it was the only content so SOA will work */
2170 for(mpp = mp; mpp; mpp = mpp->mp_next) {
2171 if (mpp->mp_content_type && mpp->mp_content_type->c_type &&
2172 mpp->mp_payload && mpp->mp_payload->pl_data &&
2173 su_casenmatch(mpp->mp_content_type->c_type, "application/sdp", 15)) {
2174
2175 request->sip_content_type = msg_content_type_dup(nua_handle_home(nh)((su_home_t *)(nh)), mpp->mp_content_type);
2176
2177 if (request->sip_content_length) {
2178 request->sip_content_length->l_length = mpp->mp_payload->pl_len;
2179 }
2180
2181 request->sip_payload->pl_data = su_strdup(nua_handle_home(nh)((su_home_t *)(nh)), mpp->mp_payload->pl_data);
2182 request->sip_payload->pl_len = mpp->mp_payload->pl_len;
2183
2184 sdp++;
2185
2186 break;
2187 }
2188 }
2189
2190 /* insist on the existance of a SDP in the content or refuse the request */
2191 if (!sdp) {
2192 return SR_STATUS1(sr, SIP_406_NOT_ACCEPTABLE)sr_status(sr, 406, sip_406_Not_acceptable);
2193 }
2194 }
2195 }
2196
2197
2198 /* Make sure caller uses application/sdp without compression */
2199 if (nta_check_session_content(NULL((void*)0), request, a, TAG_END()(tag_type_t)0, (tag_value_t)0)) {
2200 sip_add_make(msg, sip, sip_accept_encoding_class, "");
2201 return SR_STATUS1(sr, SIP_415_UNSUPPORTED_MEDIA)sr_status(sr, 415, sip_415_Unsupported_media);
2202 }
2203
2204 /* Make sure caller accepts application/sdp */
2205 if (nta_check_accept(NULL((void*)0), request, a, NULL((void*)0), TAG_END()(tag_type_t)0, (tag_value_t)0)) {
2206 sip_add_make(msg, sip, sip_accept_encoding_class, "");
2207 return SR_STATUS1(sr, SIP_406_NOT_ACCEPTABLE)sr_status(sr, 406, sip_406_Not_acceptable);
2208 }
2209 }
2210
2211 if (request->sip_session_expires &&
2212 sip_has_feature(NH_PGET(nh, supported)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_supported ? ((
nh)->nh_prefs)->nhp_supported : ((nh)->nh_nua->nua_handles
->nh_prefs)->nhp_supported)
, "timer") &&
2213 session_timer_check_min_se(msg, sip, request, NH_PGET(nh, min_se)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_min_se ? ((nh)
->nh_prefs)->nhp_min_se : ((nh)->nh_nua->nua_handles
->nh_prefs)->nhp_min_se)
)) {
2214 if (sip->sip_min_se)
2215 return SR_STATUS1(sr, SIP_422_SESSION_TIMER_TOO_SMALL)sr_status(sr, 422, sip_422_Session_timer);
2216 else
2217 return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR)sr_status(sr, 500, sip_500_Internal_server_error);
2218 }
2219
2220 session_get_description(request, &sr->sr_sdp, &sr->sr_sdp_len);
2221
2222 return 0;
2223}
2224
2225/** Preprocess INVITE.
2226 *
2227 * This is called after a handle has been created for an incoming INVITE.
2228 */
2229int nua_invite_server_preprocess(nua_server_request_t *sr)
2230{
2231 nua_handle_t *nh = sr->sr_owner;
2232 nua_dialog_state_t *ds = nh->nh_ds;
2233 nua_session_usage_t *ss;
2234
2235 sip_t const *request = sr->sr_request.sip;
2236
2237 assert(sr->sr_status == 100)((sr->sr_status == 100) ? (void) (0) : __assert_fail ("sr->sr_status == 100"
, "nua_session.c", 2237, __PRETTY_FUNCTION__))
;
2238 assert(nh != nh->nh_nua->nua_dhandle)((nh != nh->nh_nua->nua_handles) ? (void) (0) : __assert_fail
("nh != nh->nh_nua->nua_handles", "nua_session.c", 2238
, __PRETTY_FUNCTION__))
;
2239
2240 if (sr->sr_status > 100)
2241 return sr->sr_status;
2242
2243 if (nh->nh_soa)
2244 soa_init_offer_answer(nh->nh_soa);
2245
2246 if (sr->sr_sdp) {
2247 if (nh->nh_soa &&
2248 soa_set_remote_sdp(nh->nh_soa, NULL((void*)0), sr->sr_sdp, sr->sr_sdp_len) < 0) {
2249 SU_DEBUG_5(("nua(%p): %s server: error parsing SDP\n", (void *)nh,((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 2250, "nua(%p): %s server: error parsing SDP\n"
, (void *)nh, "INVITE")) : (void)0)
2250 "INVITE"))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 2250, "nua(%p): %s server: error parsing SDP\n"
, (void *)nh, "INVITE")) : (void)0)
;
2251 return SR_STATUS(sr, 400, "Bad Session Description")((sr)->sr_phrase = ("Bad Session Description"), (sr)->sr_status
= (400))
;
2252 }
2253 else
2254 sr->sr_offer_recv = 1;
2255 }
2256
2257 /* Add the session usage */
2258 if (sr->sr_usage == NULL((void*)0)) {
2259 sr->sr_usage = nua_dialog_usage_add(nh, ds, nua_session_usage, NULL((void*)0));
2260 if (sr->sr_usage == NULL((void*)0))
2261 return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR)sr_status(sr, 500, sip_500_Internal_server_error);
2262 }
2263
2264 ss = nua_dialog_usage_private(sr->sr_usage)((sr->sr_usage) ? (void*)((sr->sr_usage) + 1) : ((void*
)0))
;
2265
2266 if (sr->sr_offer_recv)
2267 ss->ss_oa_recv = Offer;
2268
2269 ss->ss_100rel = NH_PGET(nh, early_media)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_early_media ? (
(nh)->nh_prefs)->nhp_early_media : ((nh)->nh_nua->
nua_handles->nh_prefs)->nhp_early_media)
;
2270 ss->ss_precondition = sip_has_feature(request->sip_require, "precondition");
2271 if (ss->ss_precondition)
2272 ss->ss_100rel = 1;
2273
2274 session_timer_store(ss->ss_timer, request);
2275
2276#if 0 /* The glare and overlap tests should take care of this. */
2277 assert(ss->ss_state >= nua_callstate_completed ||((ss->ss_state >= nua_callstate_completed || ss->ss_state
== nua_callstate_init) ? (void) (0) : __assert_fail ("ss->ss_state >= nua_callstate_completed || ss->ss_state == nua_callstate_init"
, "nua_session.c", 2278, __PRETTY_FUNCTION__))
2278 ss->ss_state == nua_callstate_init)((ss->ss_state >= nua_callstate_completed || ss->ss_state
== nua_callstate_init) ? (void) (0) : __assert_fail ("ss->ss_state >= nua_callstate_completed || ss->ss_state == nua_callstate_init"
, "nua_session.c", 2278, __PRETTY_FUNCTION__))
;
2279#endif
2280
2281 if (NH_PGET(nh, auto_answer)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_auto_answer ? (
(nh)->nh_prefs)->nhp_auto_answer : ((nh)->nh_nua->
nua_handles->nh_prefs)->nhp_auto_answer)
||
2282 /* Auto-answer to re-INVITE unless auto_answer is set to 0 on handle */
2283 (ss->ss_state == nua_callstate_ready &&
2284 /* Auto-answer requires enabled media (soa).
2285 * XXX - if the re-INVITE modifies the media we should not auto-answer.
2286 */
2287 nh->nh_soa &&
2288 !NH_PISSET(nh, auto_answer)((((nh)->nh_prefs)->nhp_set_.set_bits.nhb_auto_answer) &&
(nh)->nh_nua->nua_handles->nh_prefs != (nh)->nh_prefs
)
)) {
2289 SR_STATUS1(sr, SIP_200_OK)sr_status(sr, 200, sip_200_OK);
2290 }
2291 else if (NH_PGET(nh, auto_alert)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_auto_alert ? (
(nh)->nh_prefs)->nhp_auto_alert : ((nh)->nh_nua->
nua_handles->nh_prefs)->nhp_auto_alert)
) {
2292 if (ss->ss_100rel &&
2293 (sip_has_feature(request->sip_supported, "100rel") ||
2294 sip_has_feature(request->sip_require, "100rel"))) {
2295 SR_STATUS1(sr, SIP_183_SESSION_PROGRESS)sr_status(sr, 183, sip_183_Session_progress);
2296 }
2297 else {
2298 SR_STATUS1(sr, SIP_180_RINGING)sr_status(sr, 180, sip_180_Ringing);
2299 }
2300 }
2301
2302 return 0;
2303}
2304
2305
2306/** @internal Respond to an INVITE request.
2307 *
2308 */
2309static
2310int nua_invite_server_respond(nua_server_request_t *sr, tagi_t const *tags)
2311{
2312 nua_handle_t *nh = sr->sr_owner;
2313 nua_dialog_usage_t *du = sr->sr_usage;
2314 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
2315 msg_t *msg = sr->sr_response.msg;
2316 sip_t *sip = sr->sr_response.sip;
2317
2318 int reliable = 0, maybe_answer = 0, offer = 0, answer = 0, extra = 0;
2319
2320 enter(void)((((nua_log) != ((void*)0) && (nua_log)->log_init
) == 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 9 ? (_su_llog((nua_log), 9, "nua_session.c"
, (const char *)__func__, 2320, "nua: %s: entering\n", __func__
)) : (void)0)
;
2321
2322 if (du == NULL((void*)0)) {
2323 if (sr->sr_status < 300)
2324 sr_status(sr, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error);
2325 return nua_base_server_respond(sr, tags);
2326 }
2327
2328 if (200 <= sr->sr_status && sr->sr_status < 300) {
2329 reliable = 1, maybe_answer = 1;
2330 }
2331 else if (nua_invite_server_is_100rel(sr, tags)) {
2332 reliable = 1, maybe_answer = 1;
2333 }
2334 else if (!nh->nh_soa || sr->sr_status >= 300) {
2335 if (sr->sr_neutral)
2336 return nua_base_server_respond(sr, tags);
2337 }
2338 else if (tags && 100 < sr->sr_status && sr->sr_status < 200 &&
2339 !NHP_ISSET(nh->nh_prefs, early_answer)((nh->nh_prefs)->nhp_set_.set_bits.nhb_early_answer)) {
2340 sdp_session_t const *user_sdp = NULL((void*)0);
2341 char const *user_sdp_str = NULL((void*)0);
2342
2343 tl_gets(tags,
2344 SOATAG_USER_SDP_REF(user_sdp)soatag_user_sdp_ref, sdptag_session_vr(&(user_sdp)),
2345 SOATAG_USER_SDP_STR_REF(user_sdp_str)soatag_user_sdp_str_ref, tag_str_vr(&(user_sdp_str)),
2346 TAG_END()(tag_type_t)0, (tag_value_t)0);
2347
2348 maybe_answer = user_sdp || user_sdp_str;
2349 }
2350 else {
2351 maybe_answer = NH_PGET(nh, early_answer)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_early_answer ?
((nh)->nh_prefs)->nhp_early_answer : ((nh)->nh_nua->
nua_handles->nh_prefs)->nhp_early_answer)
;
2352 }
2353
2354 if (!nh->nh_soa) {
2355 if (session_get_description(sip, NULL((void*)0), NULL((void*)0))) {
2356 if (sr->sr_offer_recv)
2357 answer = 1;
2358 else if (sr->sr_offer_sent < 2)
2359 offer = 1;
2360 }
2361 }
2362 else if (sr->sr_status >= 300) {
2363 soa_clear_remote_sdp(nh->nh_soa);
2364 }
2365 else if (sr->sr_offer_sent && !sr->sr_answer_recv)
2366 /* Wait for answer */;
2367 else if (sr->sr_offer_recv && sr->sr_answer_sent > 1) {
2368 /* We have sent answer */
2369 /* ... but we may want to send it again */
2370 tagi_t const *t = tl_find_last(tags, nutag_include_extra_sdp);
2371 extra = t && t->t_value;
2372 }
2373 else if (sr->sr_offer_recv && !sr->sr_answer_sent && maybe_answer) {
2374 /* Generate answer */
2375 if (soa_generate_answer(nh->nh_soa, NULL((void*)0)) >= 0 &&
2376 soa_activate(nh->nh_soa, NULL((void*)0)) >= 0) {
2377 answer = 1; /* signal that O/A answer sent (answer to invite) */
2378 /* ss_sdp_version is updated only after answer is sent reliably */
2379 }
2380 /* We have an error! */
2381 else if (sr->sr_status >= 200) {
2382 sip_warning_t *warning = NULL((void*)0);
2383 int wcode;
2384 char const *text;
2385 char const *host = "invalid.";
2386
2387 sr->sr_status = soa_error_as_sip_response(nh->nh_soa, &sr->sr_phrase);
2388
2389 wcode = soa_get_warning(nh->nh_soa, &text);
2390
2391 if (wcode) {
2392 if (sip->sip_contact)
2393 host = sip->sip_contact->m_url->url_host;
2394 warning = sip_warning_format(msg_home(msg)((su_home_t*)(msg)), "%u %s \"%s\"",
2395 wcode, host, text);
2396 sip_header_insert(msg, sip, (sip_header_t *)warning);
2397 }
2398 }
2399 else {
2400 /* 1xx - we don't have to send answer */
2401 }
2402 }
2403 else if (sr->sr_offer_recv && sr->sr_answer_sent == 1 && maybe_answer) {
2404 /* The answer was sent unreliably, keep sending it */
2405 answer = 1;
2406 }
2407 else if (!sr->sr_offer_recv && !sr->sr_offer_sent && reliable) {
2408 if (200 <= sr->sr_status && nua_callstate_ready <= ss->ss_state &&
2409 NH_PGET(nh, refresh_without_sdp)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_refresh_without_sdp
? ((nh)->nh_prefs)->nhp_refresh_without_sdp : ((nh)->
nh_nua->nua_handles->nh_prefs)->nhp_refresh_without_sdp
)
)
2410 /* This is a re-INVITE without SDP - do not try to send offer in 200 */;
2411 else
2412 /* Generate offer */
2413 if (soa_generate_offer(nh->nh_soa, 0, NULL((void*)0)) < 0)
2414 sr->sr_status = soa_error_as_sip_response(nh->nh_soa, &sr->sr_phrase);
2415 else
2416 offer = 1;
2417 }
2418
2419 if (sr->sr_status < 300 && (offer || answer || extra)) {
2420 if (nh->nh_soa && session_include_description(nh->nh_soa, 1, msg, sip) < 0)
2421 SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR)sr_status(sr, 500, sip_500_Internal_server_error);
2422 else if (offer)
2423 sr->sr_offer_sent = 1 + reliable, ss->ss_oa_sent = Offer;
2424 else if (answer)
2425 sr->sr_answer_sent = 1 + reliable, ss->ss_oa_sent = Answer;
2426
2427 if (answer && reliable && nh->nh_soa) {
2428 ss->ss_sdp_version = soa_get_user_version(nh->nh_soa);
2429 }
2430 }
2431
2432 if (reliable && sr->sr_status < 200) {
2433 sr->sr_response.msg = NULL((void*)0), sr->sr_response.sip = NULL((void*)0);
2434 if (nta_reliable_mreply(sr->sr_irq, process_prack, sr, msg) == NULL((void*)0))
2435 return -1;
2436 sr->sr_100rel = 1;
2437 return 0;
2438 }
2439
2440 if (200 <= sr->sr_status && sr->sr_status < 300) {
2441 session_timer_preferences(ss->ss_timer,
2442 sip,
2443 NH_PGET(nh, supported)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_supported ? ((
nh)->nh_prefs)->nhp_supported : ((nh)->nh_nua->nua_handles
->nh_prefs)->nhp_supported)
,
2444 NH_PGET(nh, session_timer)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_session_timer ?
((nh)->nh_prefs)->nhp_session_timer : ((nh)->nh_nua
->nua_handles->nh_prefs)->nhp_session_timer)
,
2445 NUA_PISSET(nh->nh_nua, nh, session_timer)((((nh->nh_nua)->nua_handles->nh_prefs)->nhp_set_
.set_bits.nhb_session_timer) || ((nh) && (((nh)->nh_prefs
)->nhp_set_.set_bits.nhb_session_timer)))
,
2446 NH_PGET(nh, refresher)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_refresher ? ((
nh)->nh_prefs)->nhp_refresher : ((nh)->nh_nua->nua_handles
->nh_prefs)->nhp_refresher)
,
2447 NH_PGET(nh, min_se)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_min_se ? ((nh)
->nh_prefs)->nhp_min_se : ((nh)->nh_nua->nua_handles
->nh_prefs)->nhp_min_se)
);
2448
2449 if (session_timer_is_supported(ss->ss_timer))
2450 session_timer_add_headers(ss->ss_timer, 0, msg, sip, nh);
2451 }
2452
2453 return nua_base_server_respond(sr, tags);
2454}
2455
2456/** Check if the response should be sent reliably.
2457 * XXX - use tags to indicate when to use reliable responses ???
2458 */
2459static
2460int nua_invite_server_is_100rel(nua_server_request_t *sr, tagi_t const *tags)
2461{
2462 nua_handle_t *nh = sr->sr_owner;
2463 sip_require_t *require = sr->sr_request.sip->sip_require;
2464 sip_supported_t *supported = sr->sr_request.sip->sip_supported;
2465
2466 if (sr->sr_status >= 200)
2467 return 0;
2468 else if (sr->sr_status == 100)
2469 return 0;
2470
2471 if (sip_has_feature(sr->sr_response.sip->sip_require, "100rel"))
2472 return 1;
2473
2474 if (require == NULL((void*)0) && supported == NULL((void*)0))
2475 return 0;
2476
2477 if (!sip_has_feature(NH_PGET(nh, supported)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_supported ? ((
nh)->nh_prefs)->nhp_supported : ((nh)->nh_nua->nua_handles
->nh_prefs)->nhp_supported)
, "100rel"))
2478 return 0;
2479 if (sip_has_feature(require, "100rel"))
2480 return 1;
2481 if (!sip_has_feature(supported, "100rel"))
2482 return 0;
2483 if (sr->sr_status == 183)
2484 return 1;
2485
2486 if (NH_PGET(nh, early_media)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_early_media ? (
(nh)->nh_prefs)->nhp_early_media : ((nh)->nh_nua->
nua_handles->nh_prefs)->nhp_early_media)
&& !NH_PGET(nh, only183_100rel)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_only183_100rel
? ((nh)->nh_prefs)->nhp_only183_100rel : ((nh)->nh_nua
->nua_handles->nh_prefs)->nhp_only183_100rel)
)
2487 return 1;
2488
2489 if (sip_has_feature(require, "precondition")) {
2490 if (!NH_PGET(nh, only183_100rel)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_only183_100rel
? ((nh)->nh_prefs)->nhp_only183_100rel : ((nh)->nh_nua
->nua_handles->nh_prefs)->nhp_only183_100rel)
)
2491 return 1;
2492 if (sr->sr_offer_recv && !sr->sr_answer_sent)
2493 return 1;
2494 }
2495
2496 return 0;
2497}
2498
2499
2500int nua_invite_server_report(nua_server_request_t *sr, tagi_t const *tags)
2501{
2502 nua_handle_t *nh = sr->sr_owner;
2503 nua_dialog_usage_t *du = sr->sr_usage;
2504 nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage)((sr->sr_usage) ? (void*)((sr->sr_usage) + 1) : ((void*
)0))
;
2505 int initial = sr->sr_initial && !sr->sr_event;
2506 int neutral = sr->sr_neutral;
2507 int application = sr->sr_application;
2508 int status = sr->sr_status; char const *phrase = sr->sr_phrase;
2509 int retval;
2510
2511 if (!sr->sr_event && status < 300) { /* Not reported yet */
2512 nta_incoming_bind(sr->sr_irq, process_ack_or_cancel, sr);
2513 }
2514
2515 retval = nua_base_server_report(sr, tags), sr = NULL((void*)0); /* destroys sr */
2516
2517 if (retval >= 2 || ss == NULL((void*)0)) {
2518 /* Session has been terminated. */
2519 if (!initial && !neutral) {
2520#if 0
2521 signal_call_state_change(nh, NULL((void*)0), status, phrase,
2522 nua_callstate_terminated);
2523#endif
2524 }
2525 return retval;
2526 }
2527
2528 /* Update session state */
2529 if (status < 300 || application != 0) {
2530 assert(ss->ss_state != nua_callstate_calling)((ss->ss_state != nua_callstate_calling) ? (void) (0) : __assert_fail
("ss->ss_state != nua_callstate_calling", "nua_session.c"
, 2530, __PRETTY_FUNCTION__))
;
2531 assert(ss->ss_state != nua_callstate_proceeding)((ss->ss_state != nua_callstate_proceeding) ? (void) (0) :
__assert_fail ("ss->ss_state != nua_callstate_proceeding"
, "nua_session.c", 2531, __PRETTY_FUNCTION__))
;
2532 signal_call_state_change(nh, ss, status, phrase,
2533 status >= 300
2534 ? nua_callstate_init
2535 : status >= 200
2536 ? nua_callstate_completed
2537 : status > 100
2538 ? nua_callstate_early
2539 : nua_callstate_received);
2540 }
2541
2542 if (status == 180)
2543 ss->ss_alerting = 1;
2544 else if (status >= 200)
2545 ss->ss_alerting = 0;
2546
2547 if (200 <= status && status < 300) {
2548 du->du_ready = 1;
2549 }
2550 else if (300 <= status && !neutral) {
2551 if (nh->nh_soa)
2552 soa_init_offer_answer(nh->nh_soa);
2553 }
2554
2555 if (ss->ss_state == nua_callstate_init) {
2556 assert(status >= 300)((status >= 300) ? (void) (0) : __assert_fail ("status >= 300"
, "nua_session.c", 2556, __PRETTY_FUNCTION__))
;
2557 nua_session_usage_destroy(nh, ss);
2558 }
2559
2560 return retval;
2561}
2562
2563/** @internal Process ACK or CANCEL or timeout (no ACK) for incoming INVITE */
2564static
2565int process_ack_or_cancel(nua_server_request_t *sr,
2566 nta_incoming_t *irq,
2567 sip_t const *sip)
2568{
2569 enter(void)((((nua_log) != ((void*)0) && (nua_log)->log_init
) == 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 9 ? (_su_llog((nua_log), 9, "nua_session.c"
, (const char *)__func__, 2569, "nua: %s: entering\n", __func__
)) : (void)0)
;
2570
2571 assert(sr->sr_usage)((sr->sr_usage) ? (void) (0) : __assert_fail ("sr->sr_usage"
, "nua_session.c", 2571, __PRETTY_FUNCTION__))
;
2572 assert(sr->sr_usage->du_class == nua_session_usage)((sr->sr_usage->du_class == nua_session_usage) ? (void)
(0) : __assert_fail ("sr->sr_usage->du_class == nua_session_usage"
, "nua_session.c", 2572, __PRETTY_FUNCTION__))
;
2573
2574 if (sip && sip->sip_request->rq_method == sip_method_ack)
2575 return process_ack(sr, irq, sip);
2576 else if (sip && sip->sip_request->rq_method == sip_method_cancel)
2577 return process_cancel(sr, irq, sip);
2578 else
2579 return process_timeout(sr, irq);
2580}
2581
2582/** @NUA_EVENT nua_i_ack
2583 *
2584 * Final response to INVITE has been acknowledged by UAC with ACK.
2585 *
2586 * @note This event is only sent after 2XX response.
2587 *
2588 * @param nh operation handle associated with the call
2589 * @param hmagic application context associated with the call
2590 * @param sip incoming ACK request
2591 * @param tags empty
2592 *
2593 * @sa #nua_i_invite, #nua_i_state, @ref nua_uas_call_model, nua_ack()
2594 *
2595 * @END_NUA_EVENT
2596 */
2597static
2598int process_ack(nua_server_request_t *sr,
2599 nta_incoming_t *irq,
2600 sip_t const *sip)
2601{
2602 nua_handle_t *nh = sr->sr_owner;
2603 nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage)((sr->sr_usage) ? (void*)((sr->sr_usage) + 1) : ((void*
)0))
;
2604 msg_t *msg = nta_incoming_getrequest_ackcancel(irq);
2605 char const *recv = NULL((void*)0);
2606 int uas;
2607
2608 if (ss == NULL((void*)0))
2609 return 0;
2610
2611 if (sr->sr_offer_sent && !sr->sr_answer_recv) {
2612 char const *sdp;
2613 size_t len;
2614
2615 if (session_get_description(sip, &sdp, &len))
2616 recv = Answer;
2617
2618 if (recv) {
2619 assert(ss->ss_oa_recv == NULL)((ss->ss_oa_recv == ((void*)0)) ? (void) (0) : __assert_fail
("ss->ss_oa_recv == ((void*)0)", "nua_session.c", 2619, __PRETTY_FUNCTION__
))
;
2620 ss->ss_oa_recv = recv;
2621 }
2622
2623 if (nh->nh_soa == NULL((void*)0))
2624 ;
2625 else if (recv == NULL((void*)0) ) {
2626 if (ss->ss_state >= nua_callstate_ready &&
2627 soa_get_user_version(nh->nh_soa) == ss->ss_sdp_version &&
2628 soa_process_reject(nh->nh_soa, NULL((void*)0)) >= 0) {
2629 url_t const *m;
2630
2631 /* The re-INVITE was a refresh and re-INVITEr ignored our offer */
2632 ss->ss_oa_sent = NULL((void*)0);
2633
2634 if (sr->sr_request.sip->sip_contact)
2635 m = sr->sr_request.sip->sip_contact->m_url;
2636 else
2637 m = sr->sr_request.sip->sip_from->a_url;
2638
2639 SU_DEBUG_3(("nua(%p): re-INVITEr ignored offer in our %u response "((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_session.c"
, (const char *)__func__, 2641, "nua(%p): re-INVITEr ignored offer in our %u response "
"(Contact: <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">)\n"
, (void *)nh, sr->sr_status, (m)->url_scheme ? (m)->
url_scheme : "", (m)->url_type != url_any && (m)->
url_scheme && (m)->url_scheme[0] ? ":" : "", (m)->
url_root && ((m)->url_host || (m)->url_user) ? "//"
: "", (m)->url_user ? (m)->url_user : "", (m)->url_user
&& (m)->url_password ? ":" : "", (m)->url_user
&& (m)->url_password ? (m)->url_password : "",
(m)->url_user && (m)->url_host ? "@" : "", (m)
->url_host ? (m)->url_host : "", (m)->url_host &&
(m)->url_port ? ":" : "", (m)->url_host && (m)
->url_port ? (m)->url_port : "", (m)->url_root &&
(m)->url_path ? "/" : "", (m)->url_path ? (m)->url_path
: "", (m)->url_params ? ";" : "", (m)->url_params ? (m
)->url_params : "", (m)->url_headers ? "?" : "", (m)->
url_headers ? (m)->url_headers : "", (m)->url_fragment ?
"#" : "", (m)->url_fragment ? (m)->url_fragment : ""))
: (void)0)
2640 "(Contact: <" URL_PRINT_FORMAT ">)\n",((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_session.c"
, (const char *)__func__, 2641, "nua(%p): re-INVITEr ignored offer in our %u response "
"(Contact: <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">)\n"
, (void *)nh, sr->sr_status, (m)->url_scheme ? (m)->
url_scheme : "", (m)->url_type != url_any && (m)->
url_scheme && (m)->url_scheme[0] ? ":" : "", (m)->
url_root && ((m)->url_host || (m)->url_user) ? "//"
: "", (m)->url_user ? (m)->url_user : "", (m)->url_user
&& (m)->url_password ? ":" : "", (m)->url_user
&& (m)->url_password ? (m)->url_password : "",
(m)->url_user && (m)->url_host ? "@" : "", (m)
->url_host ? (m)->url_host : "", (m)->url_host &&
(m)->url_port ? ":" : "", (m)->url_host && (m)
->url_port ? (m)->url_port : "", (m)->url_root &&
(m)->url_path ? "/" : "", (m)->url_path ? (m)->url_path
: "", (m)->url_params ? ";" : "", (m)->url_params ? (m
)->url_params : "", (m)->url_headers ? "?" : "", (m)->
url_headers ? (m)->url_headers : "", (m)->url_fragment ?
"#" : "", (m)->url_fragment ? (m)->url_fragment : ""))
: (void)0)
2641 (void *)nh, sr->sr_status, URL_PRINT_ARGS(m)))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_session.c"
, (const char *)__func__, 2641, "nua(%p): re-INVITEr ignored offer in our %u response "
"(Contact: <" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" ">)\n"
, (void *)nh, sr->sr_status, (m)->url_scheme ? (m)->
url_scheme : "", (m)->url_type != url_any && (m)->
url_scheme && (m)->url_scheme[0] ? ":" : "", (m)->
url_root && ((m)->url_host || (m)->url_user) ? "//"
: "", (m)->url_user ? (m)->url_user : "", (m)->url_user
&& (m)->url_password ? ":" : "", (m)->url_user
&& (m)->url_password ? (m)->url_password : "",
(m)->url_user && (m)->url_host ? "@" : "", (m)
->url_host ? (m)->url_host : "", (m)->url_host &&
(m)->url_port ? ":" : "", (m)->url_host && (m)
->url_port ? (m)->url_port : "", (m)->url_root &&
(m)->url_path ? "/" : "", (m)->url_path ? (m)->url_path
: "", (m)->url_params ? ";" : "", (m)->url_params ? (m
)->url_params : "", (m)->url_headers ? "?" : "", (m)->
url_headers ? (m)->url_headers : "", (m)->url_fragment ?
"#" : "", (m)->url_fragment ? (m)->url_fragment : ""))
: (void)0)
;
2642 if (sr->sr_request.sip->sip_user_agent)
2643 SU_DEBUG_3(("nua(%p): re-INVITE: \"User-Agent: %s\"\n", (void *)nh,((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_session.c"
, (const char *)__func__, 2644, "nua(%p): re-INVITE: \"User-Agent: %s\"\n"
, (void *)nh, sr->sr_request.sip->sip_user_agent->g_string
)) : (void)0)
2644 sr->sr_request.sip->sip_user_agent->g_string))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_session.c"
, (const char *)__func__, 2644, "nua(%p): re-INVITE: \"User-Agent: %s\"\n"
, (void *)nh, sr->sr_request.sip->sip_user_agent->g_string
)) : (void)0)
;
2645 }
2646 else
2647 return process_ack_error(sr, msg, 488, "Offer-Answer error",
2648 "SIP;cause=488;text=\"No answer to offer\"");
2649 }
2650 else if (soa_set_remote_sdp(nh->nh_soa, NULL((void*)0), sdp, len) >= 0 &&
2651 soa_process_answer(nh->nh_soa, NULL((void*)0)) >= 0 &&
2652 soa_activate(nh->nh_soa, NULL((void*)0)) >= 0) {
2653 ss->ss_sdp_version = soa_get_user_version(nh->nh_soa);
2654 }
2655 else {
2656 int status; char const *phrase, *reason;
2657
2658 status = soa_error_as_sip_response(nh->nh_soa, &phrase);
2659 reason = soa_error_as_sip_reason(nh->nh_soa);
2660
2661 return process_ack_error(sr, msg, status, phrase, reason);
2662 }
2663 }
2664
2665 if (nh->nh_soa)
2666 soa_clear_remote_sdp(nh->nh_soa);
2667
2668 nua_stack_event(nh->nh_nua, nh, msg, nua_i_ack, SIP_200_OK200, sip_200_OK, NULL((void*)0));
2669 signal_call_state_change(nh, ss, 200, "OK", nua_callstate_ready);
2670 session_timer_set(ss, uas = 1);
2671
2672 nua_server_request_destroy(sr);
2673
2674 return 0;
2675}
2676
2677static int
2678process_ack_error(nua_server_request_t *sr,
2679 msg_t *ackmsg,
2680 int status,
2681 char const *phrase,
2682 char const *reason)
2683{
2684 nua_handle_t *nh = sr->sr_owner;
2685 nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage)((sr->sr_usage) ? (void*)((sr->sr_usage) + 1) : ((void*
)0))
;
2686 int error;
2687
2688 nua_stack_event(nh->nh_nua, nh, ackmsg,
2689 nua_i_ack, status, phrase, NULL((void*)0));
2690 nua_stack_event(nh->nh_nua, nh, NULL((void*)0),
2691 nua_i_media_error, status, phrase, NULL((void*)0));
2692
2693 if (reason) ss->ss_reason = reason;
2694 ss->ss_reporting = 1;
2695 error = nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL((void*)0));
2696 ss->ss_reporting = 0;
2697
2698 signal_call_state_change(nh, ss,
2699 488, "Offer-Answer Error",
2700 /* We report terminated state if BYE failed */
2701 error
2702 ? nua_callstate_terminated
2703 : nua_callstate_terminating);
2704
2705 return 0;
2706}
2707
2708
2709/** @NUA_EVENT nua_i_cancel
2710 *
2711 * Incoming INVITE has been cancelled by the client.
2712 *
2713 * @param status status code of response to CANCEL sent automatically by stack
2714 * @param phrase a short textual description of @a status code
2715 * @param nh operation handle associated with the call
2716 * @param hmagic application context associated with the call
2717 * @param sip incoming CANCEL request
2718 * @param tags empty
2719 *
2720 * @sa @ref nua_uas_call_model, nua_cancel(), #nua_i_invite, #nua_i_state
2721 *
2722 * @END_NUA_EVENT
2723 */
2724
2725/* CANCEL */
2726static
2727int process_cancel(nua_server_request_t *sr,
2728 nta_incoming_t *irq,
2729 sip_t const *sip)
2730{
2731 nua_handle_t *nh = sr->sr_owner;
2732 nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage)((sr->sr_usage) ? (void*)((sr->sr_usage) + 1) : ((void*
)0))
;
2733 msg_t *cancel = nta_incoming_getrequest_ackcancel(irq);
2734
2735 assert(ss)((ss) ? (void) (0) : __assert_fail ("ss", "nua_session.c", 2735
, __PRETTY_FUNCTION__))
; assert(ss == nua_session_usage_for_dialog(nh->nh_ds))((ss == nua_session_usage_for_dialog(nh->nh_ds)) ? (void) (
0) : __assert_fail ("ss == nua_session_usage_for_dialog(nh->nh_ds)"
, "nua_session.c", 2735, __PRETTY_FUNCTION__))
; (void)ss;
2736
2737 assert(nta_incoming_status(irq) < 200)((nta_incoming_status(irq) < 200) ? (void) (0) : __assert_fail
("nta_incoming_status(irq) < 200", "nua_session.c", 2737,
__PRETTY_FUNCTION__))
;
2738
2739 nua_stack_event(nh->nh_nua, nh, cancel, nua_i_cancel, SIP_200_OK200, sip_200_OK, NULL((void*)0));
2740 sr->sr_application = SR_STATUS1(sr, SIP_487_REQUEST_TERMINATED)sr_status(sr, 487, sip_487_Request_terminated);
2741 nua_server_respond(sr, NULL((void*)0));
2742 nua_server_report(sr);
2743
2744 return 0;
2745}
2746
2747/* Timeout (no ACK or PRACK received) */
2748static
2749int process_timeout(nua_server_request_t *sr,
2750 nta_incoming_t *irq)
2751{
2752 nua_handle_t *nh = sr->sr_owner;
2753 nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage)((sr->sr_usage) ? (void*)((sr->sr_usage) + 1) : ((void*
)0))
;
2754 char const *phrase = "ACK Timeout";
2755 char const *reason = "SIP;cause=408;text=\"ACK Timeout\"";
2756 int error;
2757
2758 assert(ss)((ss) ? (void) (0) : __assert_fail ("ss", "nua_session.c", 2758
, __PRETTY_FUNCTION__))
; assert(ss == nua_session_usage_for_dialog(nh->nh_ds))((ss == nua_session_usage_for_dialog(nh->nh_ds)) ? (void) (
0) : __assert_fail ("ss == nua_session_usage_for_dialog(nh->nh_ds)"
, "nua_session.c", 2758, __PRETTY_FUNCTION__))
;
2759
2760 if (nua_server_request_is_pending(sr)) {
2761 phrase = "PRACK Timeout";
2762 reason = "SIP;cause=504;text=\"PRACK Timeout\"";
2763 }
2764
2765 nua_stack_event(nh->nh_nua, nh, 0, nua_i_error, 408, phrase, NULL((void*)0));
2766
2767 if (nua_server_request_is_pending(sr)) {
2768 /* PRACK timeout */
2769 SR_STATUS1(sr, SIP_504_GATEWAY_TIME_OUT)sr_status(sr, 504, sip_504_Gateway_time_out);
2770 nua_server_trespond(sr,
2771 SIPTAG_REASON_STR(reason)siptag_reason_str, tag_str_v(reason),
2772 TAG_END()(tag_type_t)0, (tag_value_t)0);
2773 if (nua_server_report(sr) >= 2)
2774 return 0; /* Done */
2775 sr = NULL((void*)0);
2776 }
2777
2778 /* send BYE, too, if 200 OK (or 183 to re-INVITE) timeouts */
2779 ss->ss_reason = reason;
2780
2781 ss->ss_reporting = 1; /* We report terminated state here if BYE fails */
2782 error = nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL((void*)0));
2783 ss->ss_reporting = 0;
2784
2785 signal_call_state_change(nh, ss, 0, phrase,
2786 error
2787 ? nua_callstate_terminated
2788 : nua_callstate_terminating);
2789
2790 if (sr)
2791 nua_server_request_destroy(sr);
2792
2793 return 0;
2794}
2795
2796
2797/** @NUA_EVENT nua_i_prack
2798 *
2799 * Incoming PRACK request. PRACK request is used to acknowledge reliable
2800 * preliminary responses and it is usually sent automatically by the nua
2801 * stack.
2802 *
2803 * @param status status code of response sent automatically by stack
2804 * @param phrase a short textual description of @a status code
2805 * @param nh operation handle associated with the call
2806 * @param hmagic application context associated with the call
2807 * @param sip incoming PRACK request
2808 * @param tags empty
2809 *
2810 * @sa nua_prack(), #nua_r_prack, @RFC3262, NUTAG_EARLY_MEDIA()
2811 *
2812 * @END_NUA_EVENT
2813 */
2814
2815int nua_prack_server_init(nua_server_request_t *sr);
2816int nua_prack_server_respond(nua_server_request_t *sr, tagi_t const *tags);
2817int nua_prack_server_report(nua_server_request_t *sr, tagi_t const *tags);
2818
2819nua_server_methods_t const nua_prack_server_methods =
2820 {
2821 SIP_METHOD_PRACKsip_method_prack, "PRACK",
2822 nua_i_prack, /* Event */
2823 {
2824 0, /* Do not create dialog */
2825 1, /* In-dialog request */
2826 1, /* Target refresh request */
2827 1, /* Add Contact */
2828 },
2829 nua_prack_server_init,
2830 nua_base_server_preprocess((void*)0),
2831 nua_base_server_params((void*)0),
2832 nua_prack_server_respond,
2833 nua_prack_server_report,
2834 };
2835
2836/** @internal Process reliable response PRACK or (timeout from 100rel) */
2837static int process_prack(nua_server_request_t *sr,
2838 nta_reliable_t *rel,
2839 nta_incoming_t *irq,
2840 sip_t const *sip)
2841{
2842 nua_handle_t *nh;
2843
2844 nta_reliable_destroy(rel);
2845
2846 if (irq == NULL((void*)0))
2847 /* Final response interrupted 100rel, we did not actually receive PRACK */
2848 return 200;
2849
2850 sr->sr_pracked = 1;
2851
2852 if (!nua_server_request_is_pending(sr)) /* There is no INVITE anymore */
2853 return 481;
2854
2855 nh = sr->sr_owner;
2856
2857 if (nh->nh_ds->ds_leg == NULL((void*)0))
2858 return 500;
2859
2860 if (sip == NULL((void*)0)) {
2861 /* 100rel timeout */
2862 SR_STATUS(sr, 504, "Reliable Response Timeout")((sr)->sr_phrase = ("Reliable Response Timeout"), (sr)->
sr_status = (504))
;
2863 nua_stack_event(nh->nh_nua, nh, NULL((void*)0), nua_i_error,
2864 sr->sr_status, sr->sr_phrase,
2865 NULL((void*)0));
2866 nua_server_trespond(sr,
2867 SIPTAG_REASON_STR("SIP;cause=504;"siptag_reason_str, tag_str_v("SIP;cause=504;" "text=\"PRACK Timeout\""
)
2868 "text=\"PRACK Timeout\"")siptag_reason_str, tag_str_v("SIP;cause=504;" "text=\"PRACK Timeout\""
)
,
2869 TAG_END()(tag_type_t)0, (tag_value_t)0);
2870 nua_server_report(sr);
2871 return 504;
2872 }
2873
2874 nta_incoming_bind(irq, NULL((void*)0), (void *)sr);
2875
2876 return nua_stack_process_request(nh, nh->nh_ds->ds_leg, irq, sip);
2877}
2878
2879
2880int nua_prack_server_init(nua_server_request_t *sr)
2881{
2882 nua_handle_t *nh = sr->sr_owner;
2883 nua_server_request_t *sri = nta_incoming_magic(sr->sr_irq, NULL((void*)0));
2884
2885 if (sri == NULL((void*)0))
2886 return SR_STATUS(sr, 481, "No Such Preliminary Response")((sr)->sr_phrase = ("No Such Preliminary Response"), (sr)->
sr_status = (481))
;
2887
2888 if (nua_session_server_init(sr))
2889 return sr->sr_status;
2890
2891 if (sr->sr_sdp) {
2892 nua_session_usage_t *ss = NUA_DIALOG_USAGE_PRIVATE(sr->sr_usage)((void *)((sr->sr_usage) + 1));
2893 char const *offeranswer;
2894
2895 /* XXX - check for overlap? */
2896
2897 if (sri->sr_offer_sent && !sri->sr_answer_recv)
2898 sr->sr_answer_recv = 1, sri->sr_answer_recv = 1, offeranswer = Answer;
2899 else
2900 sr->sr_offer_recv = 1, offeranswer = Offer;
2901
2902 ss->ss_oa_recv = offeranswer;
2903
2904 if (nh->nh_soa &&
2905 soa_set_remote_sdp(nh->nh_soa, NULL((void*)0), sr->sr_sdp, sr->sr_sdp_len) < 0) {
2906 SU_DEBUG_5(("nua(%p): %s server: error parsing %s\n", (void *)nh,((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 2907, "nua(%p): %s server: error parsing %s\n"
, (void *)nh, "PRACK", offeranswer)) : (void)0)
2907 "PRACK", offeranswer))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 2907, "nua(%p): %s server: error parsing %s\n"
, (void *)nh, "PRACK", offeranswer)) : (void)0)
;
2908 return
2909 sr->sr_status = soa_error_as_sip_response(nh->nh_soa, &sr->sr_phrase);
2910 }
2911 }
2912
2913 return 0;
2914}
2915
2916int nua_prack_server_respond(nua_server_request_t *sr, tagi_t const *tags)
2917{
2918 nua_handle_t *nh = sr->sr_owner;
2919
2920 if (sr->sr_status < 200 || 300 <= sr->sr_status)
2921 return nua_base_server_respond(sr, tags);
2922
2923 if (sr->sr_sdp) {
2924 nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage)((sr->sr_usage) ? (void*)((sr->sr_usage) + 1) : ((void*
)0))
;
2925 msg_t *msg = sr->sr_response.msg;
2926 sip_t *sip = sr->sr_response.sip;
2927
2928 if (nh->nh_soa == NULL((void*)0)) {
2929 if (sr->sr_offer_recv && session_get_description(sip, NULL((void*)0), NULL((void*)0)))
2930 sr->sr_answer_sent = 1, ss ? ss->ss_oa_sent = Answer : Answer;
2931 }
2932 else if ((sr->sr_offer_recv && soa_generate_answer(nh->nh_soa, NULL((void*)0)) < 0) ||
2933 (sr->sr_answer_recv && soa_process_answer(nh->nh_soa, NULL((void*)0)) < 0)) {
2934 SU_DEBUG_5(("nua(%p): %s server: %s %s\n",((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 2937, "nua(%p): %s server: %s %s\n"
, (void *)nh, "PRACK", "error processing", sr->sr_offer_recv
? Offer : Answer)) : (void)0)
2935 (void *)nh, "PRACK",((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 2937, "nua(%p): %s server: %s %s\n"
, (void *)nh, "PRACK", "error processing", sr->sr_offer_recv
? Offer : Answer)) : (void)0)
2936 "error processing",((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 2937, "nua(%p): %s server: %s %s\n"
, (void *)nh, "PRACK", "error processing", sr->sr_offer_recv
? Offer : Answer)) : (void)0)
2937 sr->sr_offer_recv ? Offer : Answer))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 2937, "nua(%p): %s server: %s %s\n"
, (void *)nh, "PRACK", "error processing", sr->sr_offer_recv
? Offer : Answer)) : (void)0)
;
2938 sr->sr_status = soa_error_as_sip_response(nh->nh_soa, &sr->sr_phrase);
2939 }
2940 else if (sr->sr_offer_recv) {
2941 if (session_include_description(nh->nh_soa, 1, msg, sip) < 0)
2942 sr_status(sr, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error);
2943 else
2944 sr->sr_answer_sent = 1, ss ? ss->ss_oa_sent = Answer : Answer;
2945 }
2946 }
2947
2948 return nua_base_server_respond(sr, tags);
2949}
2950
2951int nua_prack_server_report(nua_server_request_t *sr, tagi_t const *tags)
2952{
2953 nua_handle_t *nh = sr->sr_owner;
2954 nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage)((sr->sr_usage) ? (void*)((sr->sr_usage) + 1) : ((void*
)0))
;
2955 nua_server_request_t *sri = nta_incoming_magic(sr->sr_irq, NULL((void*)0));
2956 int status = sr->sr_status; char const *phrase = sr->sr_phrase;
2957 int offer_recv_or_answer_sent = sr->sr_offer_recv || sr->sr_answer_sent || sr->sr_offer_sent || sr->sr_answer_recv;
2958 int retval;
2959
2960 retval = nua_base_server_report(sr, tags), sr = NULL((void*)0); /* destroys sr */
2961
2962 if (retval >= 2 || ss == NULL((void*)0)) {
2963#if 0
2964 signal_call_state_change(nh, NULL((void*)0),
2965 status, phrase,
2966 nua_callstate_terminated);
2967#endif
2968 return retval;
2969 }
2970
2971 if (offer_recv_or_answer_sent) {
2972 /* signal offer received, answer sent */
2973 signal_call_state_change(nh, ss,
2974 status, phrase,
2975 ss->ss_state);
2976 if (nh->nh_soa) {
2977 soa_activate(nh->nh_soa, NULL((void*)0));
2978 ss->ss_sdp_version = soa_get_user_version(nh->nh_soa);
2979 }
2980 }
2981
2982 if (status < 200 || 300 <= status)
2983 return retval;
2984
2985 assert(sri)((sri) ? (void) (0) : __assert_fail ("sri", "nua_session.c", 2985
, __PRETTY_FUNCTION__))
;
2986
2987 if (sri == NULL((void*)0)) {
2988
2989 }
2990 else if (SR_HAS_SAVED_SIGNAL(sri)((sri)->sr_signal[0] != ((void*)0))) {
2991 nua_signal_data_t const *e;
2992
2993 e = nua_signal_data(sri->sr_signal);
2994
2995 sri->sr_application = SR_STATUS(sri, e->e_status, e->e_phrase)((sri)->sr_phrase = (e->e_phrase), (sri)->sr_status =
(e->e_status))
;
2996
2997 nua_server_params(sri, e->e_tags);
2998 nua_server_respond(sri, e->e_tags);
2999 nua_server_report(sri);
3000 }
3001 else if (ss->ss_state < nua_callstate_ready
3002 && !ss->ss_alerting
3003 && !ss->ss_precondition
3004 && NH_PGET(nh, auto_alert)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_auto_alert ? (
(nh)->nh_prefs)->nhp_auto_alert : ((nh)->nh_nua->
nua_handles->nh_prefs)->nhp_auto_alert)
) {
3005 SR_STATUS1(sri, SIP_180_RINGING)sr_status(sri, 180, sip_180_Ringing);
3006 nua_server_respond(sri, NULL((void*)0));
3007 nua_server_report(sri);
3008 }
3009
3010 return retval;
3011}
3012
3013/* ---------------------------------------------------------------------- */
3014/* Automatic notifications from a referral */
3015
3016static int
3017nh_referral_check(nua_handle_t *nh, tagi_t const *tags)
3018{
3019 sip_event_t const *event = NULL((void*)0);
3020 int pause = 1;
3021 struct nua_referral *ref = nh->nh_referral;
3022 nua_handle_t *ref_handle = ref->ref_handle;
3023
3024 if (!ref_handle
3025 &&
3026 tl_gets(tags,
3027 NUTAG_NOTIFY_REFER_REF(ref_handle)nutag_notify_refer_ref, nutag_handle_vr(&(ref_handle)),
3028 NUTAG_REFER_EVENT_REF(event)nutag_refer_event_ref, siptag_event_vr(&(event)),
3029 NUTAG_REFER_PAUSE_REF(pause)nutag_refer_pause_ref, tag_bool_vr(&(pause)),
3030 TAG_END()(tag_type_t)0, (tag_value_t)0) == 0
3031 &&
3032 tl_gets(nh->nh_tags,
3033 NUTAG_NOTIFY_REFER_REF(ref_handle)nutag_notify_refer_ref, nutag_handle_vr(&(ref_handle)),
3034 NUTAG_REFER_EVENT_REF(event)nutag_refer_event_ref, siptag_event_vr(&(event)),
3035 NUTAG_REFER_PAUSE_REF(pause)nutag_refer_pause_ref, tag_bool_vr(&(pause)),
3036 TAG_END()(tag_type_t)0, (tag_value_t)0) == 0)
3037 return 0;
3038
3039 if (!ref_handle)
3040 return 0;
3041
3042 /* Remove nh_referral and nh_notevent */
3043 tl_tremove(nh->nh_tags,
3044 NUTAG_NOTIFY_REFER(ref_handle)nutag_notify_refer, nutag_handle_v(ref_handle),
3045 TAG_IF(event, NUTAG_REFER_EVENT(event))!(event) ? tag_skip : nutag_refer_event, siptag_event_v(event
)
,
3046 TAG_END()(tag_type_t)0, (tag_value_t)0);
3047
3048 if (event)
3049 ref->ref_event = sip_event_dup(nh->nh_home, event);
3050
3051 if (!nh_validate(nh->nh_nua, ref_handle)) {
3052 SU_DEBUG_3(("nua: invalid NOTIFY_REFER handle\n" VA_NONE))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_session.c"
, (const char *)__func__, 3052, "nua: invalid NOTIFY_REFER handle\n"
"%s", "")) : (void)0)
;
3053 return -1;
3054 }
3055 else if (!ref->ref_event) {
3056 SU_DEBUG_3(("nua: NOTIFY event missing\n" VA_NONE))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_session.c"
, (const char *)__func__, 3056, "nua: NOTIFY event missing\n"
"%s", "")) : (void)0)
;
3057 return -1;
3058 }
3059
3060 if (ref_handle != ref->ref_handle) {
3061 if (ref->ref_handle)
3062 nua_handle_unref(ref->ref_handle);
3063 ref->ref_handle = nua_handle_ref(ref_handle);
3064 }
3065
3066#if 0
3067 if (pause) {
3068 /* Pause media on REFER handle */
3069 nmedia_pause(nua, ref_handle->nh_nm, NULL((void*)0));
3070 }
3071#endif
3072
3073 return 0;
3074}
3075
3076static void
3077nh_referral_respond(nua_handle_t *nh, int status, char const *phrase)
3078{
3079 char payload[128];
3080 char const *substate;
3081 struct nua_referral *ref = nh->nh_referral;
3082
3083 if (!nh_validate(nh->nh_nua, ref->ref_handle)) {
3084 if (ref) {
3085 if (ref->ref_handle)
3086 SU_DEBUG_1(("nh_handle_referral: stale referral handle %p\n",((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 1 ? (_su_llog((nua_log), 1, "nua_session.c"
, (const char *)__func__, 3087, "nh_handle_referral: stale referral handle %p\n"
, (void *)ref->ref_handle)) : (void)0)
3087 (void *)ref->ref_handle))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 1 ? (_su_llog((nua_log), 1, "nua_session.c"
, (const char *)__func__, 3087, "nh_handle_referral: stale referral handle %p\n"
, (void *)ref->ref_handle)) : (void)0)
;
3088 ref->ref_handle = NULL((void*)0);
3089 }
3090 return;
3091 }
3092
3093 /* XXX - we should have a policy here whether to send 101..199 */
3094
3095 assert(ref->ref_event)((ref->ref_event) ? (void) (0) : __assert_fail ("ref->ref_event"
, "nua_session.c", 3095, __PRETTY_FUNCTION__))
;
3096
3097 if (status >= 300)
3098 status = 503, phrase = sip_503_Service_unavailable;
3099
3100 snprintf(payload, sizeof(payload), "SIP/2.0 %03u %s\r\n", status, phrase);
3101
3102 if (status < 200)
3103 substate = "active";
3104 else
3105 substate = "terminated ;reason=noresource";
3106
3107 nua_stack_post_signal(ref->ref_handle,
3108 nua_r_notify,
3109 SIPTAG_EVENT(ref->ref_event)siptag_event, siptag_event_v(ref->ref_event),
3110 SIPTAG_SUBSCRIPTION_STATE_STR(substate)siptag_subscription_state_str, tag_str_v(substate),
3111 SIPTAG_CONTENT_TYPE_STR("message/sipfrag")siptag_content_type_str, tag_str_v("message/sipfrag"),
3112 SIPTAG_PAYLOAD_STR(payload)siptag_payload_str, tag_str_v(payload),
3113 TAG_END()(tag_type_t)0, (tag_value_t)0);
3114
3115 if (status < 200)
3116 return;
3117
3118 su_free(nh->nh_home, ref->ref_event), ref->ref_event = NULL((void*)0);
3119
3120 nua_handle_unref(ref->ref_handle), ref->ref_handle = NULL((void*)0);
3121}
3122
3123/* ======================================================================== */
3124/* INFO */
3125
3126/**@fn void nua_info(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
3127 *
3128 * Send an INFO request.
3129 *
3130 * INFO is used to send call related information like DTMF
3131 * digit input events. See @RFC2976.
3132 *
3133 * @param nh Pointer to operation handle
3134 * @param tag, value, ... List of tagged parameters
3135 *
3136 * @return
3137 * nothing
3138 *
3139 * @par Related Tags:
3140 * Header tags defined in <sofia-sip/sip_tag.h>.
3141 *
3142 * @par Events:
3143 * #nua_r_info
3144 *
3145 * @sa #nua_i_info
3146 */
3147
3148nua_client_methods_t const nua_info_client_methods = {
3149 SIP_METHOD_INFOsip_method_info, "INFO", /* crm_method, crm_method_name */
3150 0, /* crm_extra */
3151 { /* crm_flags */
3152 /* create_dialog */ 0,
3153 /* in_dialog */ 1,
3154 /* target refresh */ 0
3155 },
3156 NULL((void*)0), /* crm_template */
3157 NULL((void*)0), /* crm_init */
3158 NULL((void*)0), /* crm_send */
3159 NULL((void*)0), /* crm_check_restart */
3160 NULL((void*)0), /* crm_recv */
3161 NULL((void*)0), /* crm_preliminary */
3162 NULL((void*)0), /* crm_report */
3163 NULL((void*)0), /* crm_complete */
3164};
3165
3166int
3167nua_stack_info(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags)
3168{
3169 return nua_client_create(nh, e, &nua_info_client_methods, tags);
3170}
3171
3172/** @NUA_EVENT nua_r_info
3173 *
3174 * Response to an outgoing @b INFO request.
3175 *
3176 * @param status response status code
3177 * (if the request is retried, @a status is 100, the @a
3178 * sip->sip_status->st_status contain the real status code
3179 * from the response message, e.g., 302, 401, or 407)
3180 * @param phrase a short textual description of @a status code
3181 * @param nh operation handle associated with the call
3182 * @param hmagic application context associated with the call
3183 * @param sip response to @b INFO or NULL upon an error
3184 * (status code is in @a status and
3185 * descriptive message in @a phrase parameters)
3186 * @param tags empty
3187 *
3188 * @sa nua_info(), #nua_i_info, @RFC2976
3189 *
3190 * @END_NUA_EVENT
3191 */
3192
3193/** @NUA_EVENT nua_i_info
3194 *
3195 * Incoming session INFO request.
3196 *
3197 * @param status statuscode of response sent automatically by stack
3198 * @param phrase a short textual description of @a status code
3199 * @param nh operation handle associated with the call
3200 * @param hmagic application context associated with the call
3201 * @param sip incoming INFO request
3202 * @param tags empty
3203 *
3204 * @sa nua_info(), #nua_r_info, @RFC2976
3205 *
3206 * @END_NUA_EVENT
3207 */
3208
3209nua_server_methods_t const nua_info_server_methods =
3210 {
3211 SIP_METHOD_INFOsip_method_info, "INFO",
3212 nua_i_info, /* Event */
3213 {
3214 0, /* Do not create dialog */
3215 0, /* Allow outside dialog, too */
3216 0, /* Not a target refresh request */
3217 0, /* Do not add Contact */
3218 },
3219 nua_base_server_init((void*)0),
3220 nua_base_server_preprocess((void*)0),
3221 nua_base_server_params((void*)0),
3222 nua_base_server_respond,
3223 nua_base_server_report,
3224 };
3225
3226/* ======================================================================== */
3227/* UPDATE */
3228
3229/**@fn void nua_update(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
3230 *
3231 * Update a session.
3232 *
3233 * Update a session using SIP UPDATE method. See @RFC3311.
3234 *
3235 * Update method can be used when the session has been established with
3236 * INVITE. It's mainly used during the session establishment when
3237 * preconditions are used (@RFC3312). It can be also used during the call if
3238 * no user input is needed for offer/answer negotiation.
3239 *
3240 * @param nh Pointer to operation handle
3241 * @param tag, value, ... List of tagged parameters
3242 *
3243 * @return
3244 * nothing
3245 *
3246 * @par Related Tags:
3247 * same as nua_invite()
3248 *
3249 * @par Events:
3250 * #nua_r_update \n
3251 * #nua_i_state (#nua_i_active, #nua_i_terminated)\n
3252 * #nua_i_media_error \n
3253 *
3254 * @sa @ref nua_call_model, @RFC3311, nua_update(), #nua_i_update
3255 */
3256
3257static int nua_update_client_init(nua_client_request_t *cr,
3258 msg_t *msg, sip_t *sip,
3259 tagi_t const *tags);
3260static int nua_update_client_request(nua_client_request_t *cr,
3261 msg_t *msg, sip_t *sip,
3262 tagi_t const *tags);
3263static int nua_update_client_response(nua_client_request_t *cr,
3264 int status, char const *phrase,
3265 sip_t const *sip);
3266static int nua_update_client_report(nua_client_request_t *cr,
3267 int status, char const *phrase,
3268 sip_t const *sip,
3269 nta_outgoing_t *orq,
3270 tagi_t const *tags);
3271
3272nua_client_methods_t const nua_update_client_methods = {
3273 SIP_METHOD_UPDATEsip_method_update, "UPDATE", /* crm_method, crm_method_name */
3274 0, /* crm_extrasize of private data */
3275 { /* crm_flags */
3276 /* create_dialog */ 0,
3277 /* in_dialog */ 1,
3278 /* target refresh */ 1
3279 },
3280 NULL((void*)0), /* crm_template */
3281 nua_update_client_init, /* crm_init */
3282 nua_update_client_request, /* crm_send */
3283 session_timer_check_restart, /* crm_check_restart */
3284 nua_update_client_response, /* crm_recv */
3285 NULL((void*)0), /* crm_preliminary */
3286 nua_update_client_report, /* crm_report */
3287 NULL((void*)0), /* crm_complete */
3288};
3289
3290int nua_stack_update(nua_t *nua, nua_handle_t *nh, nua_event_t e,
3291 tagi_t const *tags)
3292{
3293 return nua_client_create(nh, e, &nua_update_client_methods, tags);
3294}
3295
3296static int nua_update_client_init(nua_client_request_t *cr,
3297 msg_t *msg, sip_t *sip,
3298 tagi_t const *tags)
3299{
3300 nua_handle_t *nh = cr->cr_owner;
3301 nua_dialog_usage_t *du = nua_dialog_usage_for_session(nh->nh_ds);
3302
3303 cr->cr_usage = du;
3304
3305 return 0;
3306}
3307
3308static int nua_update_client_request(nua_client_request_t *cr,
3309 msg_t *msg, sip_t *sip,
3310 tagi_t const *tags)
3311{
3312 nua_handle_t *nh = cr->cr_owner;
3313 nua_dialog_usage_t *du = cr->cr_usage;
3314 nua_session_usage_t *ss;
3315 nua_server_request_t *sr;
3316 nua_client_request_t *cri;
3317 int offer_sent = 0, retval;
3318
3319 if (du == NULL((void*)0)) /* Call terminated */
3320 return nua_client_return(cr, SIP_481_NO_TRANSACTION481, sip_481_No_transaction, msg);
3321
3322 ss = NUA_DIALOG_USAGE_PRIVATE(du)((void *)((du) + 1));
3323 if (ss->ss_state >= nua_callstate_terminating)
3324 return nua_client_return(cr, 900, "Session is terminating", msg);
3325
3326 cri = du->du_cr;
3327
3328 for (sr = nh->nh_ds->ds_sr; sr; sr = sr->sr_next)
3329 if ((sr->sr_offer_sent && !sr->sr_answer_recv) ||
3330 (sr->sr_offer_recv && !sr->sr_answer_sent))
3331 break;
3332
3333 if (nh->nh_soa == NULL((void*)0)) {
3334 offer_sent = session_get_description(sip, NULL((void*)0), NULL((void*)0));
3335 }
3336 else if (sr ||
3337 (cri && cri->cr_offer_sent && !cri->cr_answer_recv) ||
3338 (cri && cri->cr_offer_recv && !cri->cr_answer_sent)) {
3339 if (session_get_description(sip, NULL((void*)0), NULL((void*)0)))
3340 return nua_client_return(cr, 500, "Overlapping Offer/Answer", msg);
3341 }
3342 else if (!sip->sip_payload) {
3343 soa_init_offer_answer(nh->nh_soa);
3344
3345 if (soa_generate_offer(nh->nh_soa, 0, NULL((void*)0)) < 0 ||
3346 session_include_description(nh->nh_soa, 1, msg, sip) < 0) {
3347 if (ss->ss_state < nua_callstate_ready) {
3348 /* XXX - use soa_error_as_sip_reason(nh->nh_soa) */
3349 cr->cr_graceful = 1;
3350 ss->ss_reason = "SIP;cause=400;text=\"Local media failure\"";
3351 }
3352 return nua_client_return(cr, 900, "Local media failed", msg);
3353 }
3354 offer_sent = 1;
3355 }
3356
3357 /* Add session timer headers */
3358 session_timer_preferences(ss->ss_timer,
3359 sip,
3360 NH_PGET(nh, supported)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_supported ? ((
nh)->nh_prefs)->nhp_supported : ((nh)->nh_nua->nua_handles
->nh_prefs)->nhp_supported)
,
3361 NH_PGET(nh, session_timer)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_session_timer ?
((nh)->nh_prefs)->nhp_session_timer : ((nh)->nh_nua
->nua_handles->nh_prefs)->nhp_session_timer)
,
3362 NUA_PISSET(nh->nh_nua, nh, session_timer)((((nh->nh_nua)->nua_handles->nh_prefs)->nhp_set_
.set_bits.nhb_session_timer) || ((nh) && (((nh)->nh_prefs
)->nhp_set_.set_bits.nhb_session_timer)))
,
3363 NH_PGET(nh, refresher)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_refresher ? ((
nh)->nh_prefs)->nhp_refresher : ((nh)->nh_nua->nua_handles
->nh_prefs)->nhp_refresher)
,
3364 NH_PGET(nh, min_se)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_min_se ? ((nh)
->nh_prefs)->nhp_min_se : ((nh)->nh_nua->nua_handles
->nh_prefs)->nhp_min_se)
);
3365
3366 if (session_timer_is_supported(ss->ss_timer))
3367 session_timer_add_headers(ss->ss_timer, ss->ss_state < nua_callstate_ready,
3368 msg, sip, nh);
3369
3370 retval = nua_base_client_request(cr, msg, sip, NULL((void*)0));
3371
3372 if (retval == 0) {
3373 enum nua_callstate state = ss->ss_state;
3374 cr->cr_offer_sent = offer_sent;
3375 ss->ss_update_needed = 0;
3376
3377 if (state == nua_callstate_ready)
3378 state = nua_callstate_calling; /* XXX */
3379
3380 if (offer_sent)
3381 ss->ss_oa_sent = Offer;
3382
3383 if (!cr->cr_restarting) /* Restart logic calls nua_update_client_report */
3384 signal_call_state_change(nh, ss, 0, "UPDATE sent", state);
3385 }
3386
3387 return retval;
3388}
3389
3390static int nua_update_client_response(nua_client_request_t *cr,
3391 int status, char const *phrase,
3392 sip_t const *sip)
3393{
3394 nua_handle_t *nh = cr->cr_owner;
3395 nua_dialog_usage_t *du = cr->cr_usage;
3396 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
3397 int uas;
3398
3399 assert(200 <= status)((200 <= status) ? (void) (0) : __assert_fail ("200 <= status"
, "nua_session.c", 3399, __PRETTY_FUNCTION__))
;
3400
3401 if (ss && sip && status < 300) {
3402 if (session_timer_is_supported(ss->ss_timer)) {
3403 nua_server_request_t *sr;
3404
3405 for (sr = nh->nh_ds->ds_sr; sr; sr = sr->sr_next)
3406 if (sr->sr_method == sip_method_invite ||
3407 sr->sr_method == sip_method_update)
3408 break;
3409
3410 if (!sr && (!du->du_cr || !du->du_cr->cr_orq)) {
3411 session_timer_store(ss->ss_timer, sip);
3412 session_timer_set(ss, uas = 0);
3413 }
3414 }
3415 }
3416
3417 return nua_session_client_response(cr, status, phrase, sip);
3418}
3419
3420/** @NUA_EVENT nua_r_update
3421 *
3422 * Answer to outgoing UPDATE.
3423 *
3424 * The UPDATE may be sent explicitly by nua_update() or
3425 * implicitly by NUA state machine.
3426 *
3427 * @param status response status code
3428 * (if the request is retried, @a status is 100, the @a
3429 * sip->sip_status->st_status contain the real status code
3430 * from the response message, e.g., 302, 401, or 407)
3431 * @param phrase a short textual description of @a status code
3432 * @param nh operation handle associated with the call
3433 * @param hmagic application context associated with the call
3434 * @param sip response to UPDATE request or NULL upon an error
3435 * (status code is in @a status and
3436 * descriptive message in @a phrase parameters)
3437 * @param tags empty
3438 *
3439 * @sa @ref nua_call_model, @RFC3311, nua_update(), #nua_i_update
3440 *
3441 * @END_NUA_EVENT
3442 */
3443
3444static int nua_update_client_report(nua_client_request_t *cr,
3445 int status, char const *phrase,
3446 sip_t const *sip,
3447 nta_outgoing_t *orq,
3448 tagi_t const *tags)
3449{
3450 nua_handle_t *nh = cr->cr_owner;
3451 nua_dialog_usage_t *du = cr->cr_usage;
3452 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
3453
3454 nua_stack_event(nh->nh_nua, nh,
3455 nta_outgoing_getresponse(orq),
3456 (enum nua_event_e)cr->cr_event,
3457 status, phrase,
3458 tags);
3459
3460 if (!ss || cr->cr_terminated || cr->cr_graceful || cr->cr_waiting)
3461 return 1;
3462
3463 if (cr->cr_offer_sent) {
3464 unsigned next_state = ss->ss_state;
3465
3466 if (status < 200)
3467 ;
3468 else if (nua_invite_client_should_ack(du->du_cr)) {
3469 /* There is an un-ACK-ed INVITE there */
3470 assert(du->du_cr->cr_method == sip_method_invite)((du->du_cr->cr_method == sip_method_invite) ? (void) (
0) : __assert_fail ("du->du_cr->cr_method == sip_method_invite"
, "nua_session.c", 3470, __PRETTY_FUNCTION__))
;
3471
3472 if (NH_PGET(nh, auto_ack)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_auto_ack ? ((nh
)->nh_prefs)->nhp_auto_ack : ((nh)->nh_nua->nua_handles
->nh_prefs)->nhp_auto_ack)
||
3473 /* Auto-ACK response to re-INVITE when media is enabled
3474 and auto_ack is not set to 0 on handle */
3475 (ss->ss_state == nua_callstate_ready && nh->nh_soa &&
3476 !NH_PISSET(nh, auto_ack)((((nh)->nh_prefs)->nhp_set_.set_bits.nhb_auto_ack) &&
(nh)->nh_nua->nua_handles->nh_prefs != (nh)->nh_prefs
)
)) {
3477 if (nua_invite_client_ack(du->du_cr, NULL((void*)0)) > 0)
3478 next_state = nua_callstate_ready;
3479 else
3480 next_state = nua_callstate_terminating;
3481 }
3482 }
3483
3484 signal_call_state_change(nh, ss, status, phrase, (enum nua_callstate)next_state);
3485 }
3486
3487 return 1;
3488}
3489
3490/* ---------------------------------------------------------------------- */
3491/* UPDATE server */
3492
3493int nua_update_server_init(nua_server_request_t *sr);
3494int nua_update_server_respond(nua_server_request_t *sr, tagi_t const *tags);
3495int nua_update_server_report(nua_server_request_t *, tagi_t const *);
3496
3497nua_server_methods_t const nua_update_server_methods =
3498 {
3499 SIP_METHOD_UPDATEsip_method_update, "UPDATE",
3500 nua_i_update, /* Event */
3501 {
3502 0, /* Do not create dialog */
3503 1, /* In-dialog request */
3504 1, /* Target refresh request */
3505 1, /* Add Contact */
3506 },
3507 nua_update_server_init,
3508 nua_base_server_preprocess((void*)0),
3509 nua_base_server_params((void*)0),
3510 nua_update_server_respond,
3511 nua_update_server_report,
3512 };
3513
3514int nua_update_server_init(nua_server_request_t *sr)
3515{
3516 nua_handle_t *nh = sr->sr_owner;
3517 nua_session_usage_t *ss;
3518
3519 sip_t const *request = sr->sr_request.sip;
3520
3521 if (nua_session_server_init(sr))
3522 return sr->sr_status;
3523
3524 ss = nua_dialog_usage_private(sr->sr_usage)((sr->sr_usage) ? (void*)((sr->sr_usage) + 1) : ((void*
)0))
;
3525
3526 /* Do session timer negotiation */
3527 if (request->sip_session_expires)
3528 session_timer_store(ss->ss_timer, request);
3529
3530 if (sr->sr_sdp) { /* Check for overlap */
3531 nua_client_request_t *cr;
3532 nua_server_request_t *sr0;
3533 int overlap = 0;
3534
3535 /*
3536 A UAS that receives an UPDATE before it has generated a final
3537 response to a previous UPDATE on the same dialog MUST return a 500
3538 response to the new UPDATE, and MUST include a Retry-After header
3539 field with a randomly chosen value between 0 and 10 seconds.
3540
3541 If an UPDATE is received that contains an offer, and the UAS has
3542 generated an offer (in an UPDATE, PRACK or INVITE) to which it has
3543 not yet received an answer, the UAS MUST reject the UPDATE with a 491
3544 response. Similarly, if an UPDATE is received that contains an
3545 offer, and the UAS has received an offer (in an UPDATE, PRACK, or
3546 INVITE) to which it has not yet generated an answer, the UAS MUST
3547 reject the UPDATE with a 500 response, and MUST include a Retry-After
3548 header field with a randomly chosen value between 0 and 10 seconds.
3549 */
3550 for (cr = nh->nh_ds->ds_cr; cr; cr = cr->cr_next)
3551 if ((overlap = cr->cr_offer_sent && !cr->cr_answer_recv))
3552 break;
3553
3554 if (!overlap)
3555 for (sr0 = nh->nh_ds->ds_sr; sr0; sr0 = sr0->sr_next)
3556 if ((overlap = sr0->sr_offer_recv && !sr0->sr_answer_sent))
3557 break;
3558
3559 if (nh->nh_soa && overlap) {
3560 return nua_server_retry_after(sr, 500, "Overlapping Offer/Answer", 1, 9);
3561 }
3562
3563 if (nh->nh_soa &&
3564 soa_set_remote_sdp(nh->nh_soa, NULL((void*)0), sr->sr_sdp, sr->sr_sdp_len) < 0) {
3565 SU_DEBUG_5(("nua(%p): %s server: error parsing %s\n", (void *)nh,((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 3566, "nua(%p): %s server: error parsing %s\n"
, (void *)nh, "UPDATE", Offer)) : (void)0)
3566 "UPDATE", Offer))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 3566, "nua(%p): %s server: error parsing %s\n"
, (void *)nh, "UPDATE", Offer)) : (void)0)
;
3567 return
3568 sr->sr_status = soa_error_as_sip_response(nh->nh_soa, &sr->sr_phrase);
3569 }
3570
3571 sr->sr_offer_recv = 1;
3572 ss ? ss->ss_oa_recv = Offer : Offer;
3573 }
3574
3575 return 0;
3576}
3577
3578/** @internal Respond to an UPDATE request.
3579 *
3580 */
3581int nua_update_server_respond(nua_server_request_t *sr, tagi_t const *tags)
3582{
3583 nua_handle_t *nh = sr->sr_owner;
3584 nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage)((sr->sr_usage) ? (void*)((sr->sr_usage) + 1) : ((void*
)0))
;
1
'ss' initialized to a null pointer value
3585 msg_t *msg = sr->sr_response.msg;
3586 sip_t *sip = sr->sr_response.sip;
3587
3588 if (200 <= sr->sr_status && sr->sr_status < 300 && sr->sr_sdp) {
2
Taking true branch
3589 if (nh->nh_soa == NULL((void*)0)) {
3
Taking false branch
3590 sr->sr_answer_sent = 1, ss ? ss->ss_oa_sent = Answer : Answer;
3591 }
3592 else if (soa_generate_answer(nh->nh_soa, NULL((void*)0)) < 0) {
4
Taking false branch
3593 SU_DEBUG_5(("nua(%p): %s server: %s %s\n",((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 3594, "nua(%p): %s server: %s %s\n"
, (void *)nh, "UPDATE", "error processing", Offer)) : (void)0
)
3594 (void *)nh, "UPDATE", "error processing", Offer))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 3594, "nua(%p): %s server: %s %s\n"
, (void *)nh, "UPDATE", "error processing", Offer)) : (void)0
)
;
3595 sr->sr_status = soa_error_as_sip_response(nh->nh_soa, &sr->sr_phrase);
3596 }
3597 else if (soa_activate(nh->nh_soa, NULL((void*)0)) < 0) {
5
Taking false branch
3598 SU_DEBUG_5(("nua(%p): %s server: error activating media\n",((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 3599, "nua(%p): %s server: error activating media\n"
, (void *)nh, "UPDATE")) : (void)0)
3599 (void *)nh, "UPDATE"))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 3599, "nua(%p): %s server: error activating media\n"
, (void *)nh, "UPDATE")) : (void)0)
;
3600 /* XXX */
3601 }
3602 else if (session_include_description(nh->nh_soa, 1, msg, sip) < 0) {
6
Taking false branch
3603 sr_status(sr, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error);
3604 }
3605 else {
3606 sr->sr_answer_sent = 1, ss->ss_oa_sent = Answer;
7
Access to field 'ss_oa_sent' results in a dereference of a null pointer (loaded from variable 'ss')
3607 ss->ss_sdp_version = soa_get_user_version(nh->nh_soa);
3608 }
3609 }
3610
3611 if (ss && 200 <= sr->sr_status && sr->sr_status < 300) {
3612 session_timer_preferences(ss->ss_timer,
3613 sip,
3614 NH_PGET(nh, supported)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_supported ? ((
nh)->nh_prefs)->nhp_supported : ((nh)->nh_nua->nua_handles
->nh_prefs)->nhp_supported)
,
3615 NH_PGET(nh, session_timer)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_session_timer ?
((nh)->nh_prefs)->nhp_session_timer : ((nh)->nh_nua
->nua_handles->nh_prefs)->nhp_session_timer)
,
3616 NUA_PISSET(nh->nh_nua, nh, session_timer)((((nh->nh_nua)->nua_handles->nh_prefs)->nhp_set_
.set_bits.nhb_session_timer) || ((nh) && (((nh)->nh_prefs
)->nhp_set_.set_bits.nhb_session_timer)))
,
3617 NH_PGET(nh, refresher)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_refresher ? ((
nh)->nh_prefs)->nhp_refresher : ((nh)->nh_nua->nua_handles
->nh_prefs)->nhp_refresher)
,
3618 NH_PGET(nh, min_se)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_min_se ? ((nh)
->nh_prefs)->nhp_min_se : ((nh)->nh_nua->nua_handles
->nh_prefs)->nhp_min_se)
);
3619
3620 if (session_timer_is_supported(ss->ss_timer)) {
3621 nua_server_request_t *sr0;
3622 int uas;
3623
3624 session_timer_add_headers(ss->ss_timer, 0, msg, sip, nh);
3625
3626 for (sr0 = nh->nh_ds->ds_sr; sr0; sr0 = sr0->sr_next)
3627 if (sr0->sr_method == sip_method_invite)
3628 break;
3629
3630 if (!sr0 && (!sr->sr_usage->du_cr || !sr->sr_usage->du_cr->cr_orq))
3631 session_timer_set(ss, uas = 1);
3632 }
3633 }
3634
3635 return nua_base_server_respond(sr, tags);
3636}
3637
3638/** @NUA_EVENT nua_i_update
3639 *
3640 * @brief Incoming session UPDATE request.
3641 *
3642 * @param status statuscode of response sent automatically by stack
3643 * @param phrase a short textual description of @a status code
3644 * @param nh operation handle associated with the call
3645 * @param hmagic application context associated with the call
3646 * @param sip incoming UPDATE request
3647 * @param tags empty
3648 *
3649 * @sa nua_update(), #nua_r_update, #nua_i_state
3650 *
3651 * @END_NUA_EVENT
3652 */
3653
3654int nua_update_server_report(nua_server_request_t *sr, tagi_t const *tags)
3655{
3656 nua_handle_t *nh = sr->sr_owner;
3657 nua_dialog_usage_t *du = sr->sr_usage;
3658 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
3659 int status = sr->sr_status; char const *phrase = sr->sr_phrase;
3660 int offer_recv_or_answer_sent = sr->sr_offer_recv || sr->sr_answer_sent;
3661 int retval;
3662
3663 retval = nua_base_server_report(sr, tags), sr = NULL((void*)0); /* destroys sr */
3664
3665 if (retval >= 2 || ss == NULL((void*)0)) {
3666#if 0
3667 signal_call_state_change(nh, NULL((void*)0), status, phrase,
3668 nua_callstate_terminated);
3669#endif
3670 return retval;
3671 }
3672
3673 if (offer_recv_or_answer_sent) {
3674 /* signal offer received, answer sent */
3675 enum nua_callstate state = ss->ss_state;
3676
3677 if (state == nua_callstate_ready && status < 200)
3678 state = nua_callstate_received;
3679
3680 signal_call_state_change(nh, ss, status, phrase, state);
3681 }
3682
3683 if (200 <= status && status < 300
3684 && ss->ss_state < nua_callstate_ready
3685 && ss->ss_precondition
3686 && !ss->ss_alerting
3687 && NH_PGET(nh, auto_alert)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_auto_alert ? (
(nh)->nh_prefs)->nhp_auto_alert : ((nh)->nh_nua->
nua_handles->nh_prefs)->nhp_auto_alert)
) {
3688 nua_server_request_t *sri;
3689
3690 for (sri = nh->nh_ds->ds_sr; sri; sri = sri->sr_next)
3691 if (sri->sr_method == sip_method_invite &&
3692 nua_server_request_is_pending(sri))
3693 break;
3694
3695 if (sri) {
3696 SR_STATUS1(sri, SIP_180_RINGING)sr_status(sri, 180, sip_180_Ringing);
3697 nua_server_respond(sri, NULL((void*)0));
3698 nua_server_report(sri);
3699 }
3700 }
3701
3702 return retval;
3703}
3704
3705/* ======================================================================== */
3706/* BYE */
3707
3708/**@fn void nua_bye(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
3709 *
3710 * Hangdown a call.
3711 *
3712 * Hangdown a call using SIP BYE method. Also the media session
3713 * associated with the call is terminated.
3714 *
3715 * @param nh Pointer to operation handle
3716 * @param tag, value, ... List of tagged parameters
3717 *
3718 * @return
3719 * nothing
3720 *
3721 * @par Related Tags:
3722 * none
3723 *
3724 * @par Events:
3725 * #nua_r_bye \n
3726 * #nua_i_media_error
3727 */
3728
3729static int nua_bye_client_init(nua_client_request_t *cr,
3730 msg_t *msg, sip_t *sip,
3731 tagi_t const *tags);
3732static int nua_bye_client_request(nua_client_request_t *cr,
3733 msg_t *msg, sip_t *sip,
3734 tagi_t const *tags);
3735static int nua_bye_client_response(nua_client_request_t *cr,
3736 int status, char const *phrase,
3737 sip_t const *sip);
3738static int nua_bye_client_report(nua_client_request_t *cr,
3739 int status, char const *phrase,
3740 sip_t const *sip,
3741 nta_outgoing_t *orq,
3742 tagi_t const *tags);
3743
3744nua_client_methods_t const nua_bye_client_methods = {
3745 SIP_METHOD_BYEsip_method_bye, "BYE", /* crm_method, crm_method_name */
3746 0, /* crm_extrasize */
3747 { /* crm_flags */
3748 /* create_dialog */ 0,
3749 /* in_dialog */ 1,
3750 /* target refresh */ 0
3751 },
3752 NULL((void*)0), /* crm_template */
3753 nua_bye_client_init, /* crm_init */
3754 nua_bye_client_request, /* crm_send */
3755 NULL((void*)0), /* crm_check_restart */
3756 nua_bye_client_response, /* crm_recv */
3757 NULL((void*)0), /* crm_preliminary */
3758 nua_bye_client_report, /* crm_report */
3759 NULL((void*)0), /* crm_complete */
3760};
3761
3762int
3763nua_stack_bye(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags)
3764{
3765 nua_session_usage_t *ss = nua_session_usage_for_dialog(nh->nh_ds);
3766
3767 if (ss &&
3768 nua_callstate_calling <= ss->ss_state &&
3769 ss->ss_state <= nua_callstate_proceeding)
3770 return nua_client_create(nh, e, &nua_cancel_client_methods, tags);
3771 else
3772 return nua_client_create(nh, e, &nua_bye_client_methods, tags);
3773}
3774
3775static int nua_bye_client_init(nua_client_request_t *cr,
3776 msg_t *msg, sip_t *sip,
3777 tagi_t const *tags)
3778{
3779 nua_handle_t *nh = cr->cr_owner;
3780 nua_dialog_usage_t *du = nua_dialog_usage_for_session(nh->nh_ds);
3781 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
3782
3783 if (!ss || (ss->ss_state >= nua_callstate_terminating && !cr->cr_auto))
3784 return nua_client_return(cr, 900, "Invalid handle for BYE", msg);
3785
3786 if (!cr->cr_auto)
3787 /* Implicit state transition by nua_bye() */
3788 ss->ss_state = nua_callstate_terminating;
3789
3790 if (nh->nh_soa)
3791 soa_terminate(nh->nh_soa, 0);
3792
3793 nua_client_bind(cr, du);
3794
3795 return 0;
3796}
3797
3798static int nua_bye_client_request(nua_client_request_t *cr,
3799 msg_t *msg, sip_t *sip,
3800 tagi_t const *tags)
3801{
3802 nua_dialog_usage_t *du = cr->cr_usage;
3803 nua_session_usage_t *ss;
3804 char const *reason = NULL((void*)0);
3805
3806 int error;
3807 nua_server_request_t *sr;
3808
3809 if (du == NULL((void*)0))
3810 return nua_client_return(cr, SIP_481_NO_TRANSACTION481, sip_481_No_transaction, msg);
3811
3812 ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
3813 reason = ss->ss_reason;
3814
3815 error = nua_base_client_trequest(cr, msg, sip,
3816 SIPTAG_REASON_STR(reason)siptag_reason_str, tag_str_v(reason),
3817 TAG_NEXT(tags)tag_next, (tag_value_t)(tags));
3818
3819 if (error == 0) {
3820 nua_dialog_usage_reset_refresh(du);
3821 ss->ss_timer->timer_set = 0;
3822
3823 /* Terminate server transactions associated with session, too. */
3824 for (sr = du->du_dialog->ds_sr; sr; sr = sr->sr_next) {
3825 if (sr->sr_usage == du && nua_server_request_is_pending(sr) &&
3826 sr->sr_method != sip_method_bye) {
3827 sr_status(sr, SIP_486_BUSY_HERE486, sip_486_Busy_here);
3828 nua_server_respond(sr, 0);
3829 }
3830 }
3831 }
3832
3833 return error;
3834}
3835static int nua_bye_client_response(nua_client_request_t *cr,
3836 int status, char const *phrase,
3837 sip_t const *sip) {
3838
3839 nua_dialog_usage_t *du = cr->cr_usage;
3840 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
3841
3842 if (ss && ss->ss_reporting && status >= 900)
3843 return 1;
3844
3845 return nua_base_client_response(cr, status, phrase, sip, NULL((void*)0));
3846}
3847
3848/** @NUA_EVENT nua_r_bye
3849 *
3850 * Answer to outgoing BYE.
3851 *
3852 * The BYE may be sent explicitly by nua_bye() or implicitly by NUA state
3853 * machine.
3854 *
3855 * @param status response status code
3856 * (if the request is retried, @a status is 100, the @a
3857 * sip->sip_status->st_status contain the real status code
3858 * from the response message, e.g., 302, 401, or 407)
3859 * @param phrase a short textual description of @a status code
3860 * @param nh operation handle associated with the call
3861 * @param hmagic application context associated with the call
3862 * @param sip response to BYE request or NULL upon an error
3863 * (status code is in @a status and
3864 * descriptive message in @a phrase parameters)
3865 * @param tags empty
3866 *
3867 * @sa nua_bye(), @ref nua_call_model, #nua_i_state, #nua_r_invite()
3868 *
3869 * @END_NUA_EVENT
3870 */
3871
3872static int nua_bye_client_report(nua_client_request_t *cr,
3873 int status, char const *phrase,
3874 sip_t const *sip,
3875 nta_outgoing_t *orq,
3876 tagi_t const *tags)
3877{
3878 nua_handle_t *nh = cr->cr_owner;
3879 nua_dialog_usage_t *du = cr->cr_usage;
3880
3881 nua_stack_event(nh->nh_nua, nh,
3882 nta_outgoing_getresponse(orq),
3883 (enum nua_event_e)cr->cr_event,
3884 status, phrase,
3885 tags);
3886
3887 if (du == NULL((void*)0)) {
3888 /* No more session */
3889 }
3890 else if (status < 200) {
3891 /* Preliminary */
3892 }
3893 else {
3894 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
3895 nua_client_request_t *cri;
3896
3897 if (ss->ss_reporting) {
3898 return 1; /* Somebody else's problem */
3899 }
3900 else if (cr->cr_waiting) {
3901 return 1; /* Application problem */
3902 }
3903
3904 nua_client_bind(cr, NULL((void*)0));
3905
3906 signal_call_state_change(nh, ss, status, "to BYE",
3907 nua_callstate_terminated);
3908
3909 for (cri = du->du_dialog->ds_cr; cri; cri = cri->cr_next) {
3910 if (cri->cr_method == sip_method_invite)
3911 break;
3912 }
3913
3914 if (!cri || cri->cr_status >= 200) {
3915 /* INVITE is completed, we can zap the session... */;
3916 nua_session_usage_destroy(nh, ss);
3917 }
3918 }
3919
3920 return 1;
3921}
3922
3923/** @NUA_EVENT nua_i_bye
3924 *
3925 * Incoming BYE request, call hangup.
3926 *
3927 * @param status statuscode of response sent automatically by stack
3928 * @param phrase a short textual description of @a status code
3929 * @param nh operation handle associated with the call
3930 * @param hmagic application context associated with the call
3931 * @param sip pointer to BYE request
3932 * @param tags empty
3933 *
3934 * @sa @ref nua_call_model, #nua_i_state, nua_bye(), nua_bye(), #nua_r_cancel
3935 *
3936 * @END_NUA_EVENT
3937 */
3938
3939int nua_bye_server_init(nua_server_request_t *sr);
3940int nua_bye_server_report(nua_server_request_t *sr, tagi_t const *tags);
3941
3942nua_server_methods_t const nua_bye_server_methods =
3943 {
3944 SIP_METHOD_BYEsip_method_bye, "BYE",
3945 nua_i_bye, /* Event */
3946 {
3947 0, /* Do not create dialog */
3948 1, /* In-dialog request */
3949 0, /* Not a target refresh request */
3950 0, /* Do not add Contact */
3951 },
3952 nua_bye_server_init,
3953 nua_base_server_preprocess((void*)0),
3954 nua_base_server_params((void*)0),
3955 nua_base_server_respond,
3956 nua_bye_server_report,
3957 };
3958
3959
3960int nua_bye_server_init(nua_server_request_t *sr)
3961{
3962 nua_handle_t *nh = sr->sr_owner;
3963 nua_dialog_usage_t *du = nua_dialog_usage_for_session(nh->nh_ds);
3964
3965 sr->sr_terminating = 1;
3966
3967 if (du)
3968 sr->sr_usage = du;
3969 else
3970 return SR_STATUS(sr, 481, "No Such Call")((sr)->sr_phrase = ("No Such Call"), (sr)->sr_status = (
481))
;
3971
3972 return 0;
3973}
3974
3975int nua_bye_server_report(nua_server_request_t *sr, tagi_t const *tags)
3976{
3977 nua_handle_t *nh = sr->sr_owner;
3978 nua_dialog_usage_t *du = sr->sr_usage;
3979 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
3980 int early = 0, retval;
3981
3982 if (sr->sr_status < 200)
3983 return nua_base_server_report(sr, tags);
3984
3985 if (ss) {
3986 nua_server_request_t *sr0 = NULL((void*)0), *sr_next;
3987 char const *phrase;
3988
3989 early = ss->ss_state < nua_callstate_ready;
3990 phrase = early ? "Early Session Terminated" : "Session Terminated";
3991
3992#if 0
3993 sr->sr_usage = NULL((void*)0);
3994#endif
3995
3996 for (sr0 = nh->nh_ds->ds_sr; sr0; sr0 = sr_next) {
3997 sr_next = sr0->sr_next;
3998
3999 if (sr == sr0 || sr0->sr_usage != sr->sr_usage)
4000 continue;
4001
4002 if (nua_server_request_is_pending(sr0)) {
4003 SR_STATUS(sr0, 487, phrase)((sr0)->sr_phrase = (phrase), (sr0)->sr_status = (487));
4004 nua_server_respond(sr0, NULL((void*)0));
4005 }
4006 nua_server_request_destroy(sr0);
4007 }
4008
4009 sr->sr_phrase = phrase;
4010 }
4011
4012 retval = nua_base_server_report(sr, tags);
4013
4014 //assert(2 <= retval && retval < 4);
4015
4016#if 0
4017 if (ss) {
4018 signal_call_state_change(nh, ss, 200,
4019 early ? "Received early BYE" : "Received BYE",
4020 nua_callstate_terminated);
4021 nua_dialog_usage_remove(nh, nh->nh_ds, du);
4022 }
4023#endif
4024
4025 return retval;
4026}
4027
4028/* ---------------------------------------------------------------------- */
4029
4030/** @NUA_EVENT nua_i_state
4031 *
4032 * @brief Call state has changed.
4033 *
4034 * This event will be sent whenever the call state changes.
4035 *
4036 * In addition to basic changes of session status indicated with enum
4037 * ::nua_callstate, the @RFC3264 SDP Offer/Answer negotiation status is also
4038 * included. The tags NUTAG_OFFER_RECV() or NUTAG_ANSWER_RECV() indicate
4039 * whether the remote SDP that was received was considered as an offer or an
4040 * answer. Tags NUTAG_OFFER_SENT() or NUTAG_ANSWER_SENT() indicate whether
4041 * the local SDP which was sent was considered as an offer or answer.
4042 *
4043 * If the @b soa SDP negotiation is enabled (by default or with
4044 * NUTAG_MEDIA_ENABLE(1)), the received remote SDP is included in tags
4045 * SOATAG_REMOTE_SDP() and SOATAG_REMOTE_SDP_STR(). The SDP negotiation
4046 * result from @b soa is included in the tags SOATAG_LOCAL_SDP() and
4047 * SOATAG_LOCAL_SDP_STR().
4048 *
4049 * SOATAG_ACTIVE_AUDIO() and SOATAG_ACTIVE_VIDEO() are informational tags
4050 * used to indicate what is the status of audio or video.
4051 *
4052 * Note that #nua_i_state also covers the information relayed in call
4053 * establisment (#nua_i_active) and termination (#nua_i_terminated) events.
4054 *
4055 * @param status protocol status code \n
4056 * (always present)
4057 * @param phrase short description of status code \n
4058 * (always present)
4059 * @param nh operation handle associated with the call
4060 * @param hmagic application context associated with the call
4061 * @param sip NULL
4062 * @param tags NUTAG_CALLSTATE(),
4063 * SOATAG_LOCAL_SDP(), SOATAG_LOCAL_SDP_STR(),
4064 * NUTAG_OFFER_SENT(), NUTAG_ANSWER_SENT(),
4065 * SOATAG_REMOTE_SDP(), SOATAG_REMOTE_SDP_STR(),
4066 * NUTAG_OFFER_RECV(), NUTAG_ANSWER_RECV(),
4067 * SOATAG_ACTIVE_AUDIO(), SOATAG_ACTIVE_VIDEO(),
4068 * SOATAG_ACTIVE_IMAGE(), SOATAG_ACTIVE_CHAT().
4069 *
4070 * @sa @ref nua_call_model, #nua_i_active, #nua_i_terminated,
4071 * nua_invite(), #nua_r_invite, #nua_i_invite, nua_respond(),
4072 * NUTAG_MEDIA_ENABLE(),
4073 * NUTAG_AUTOALERT(), NUTAG_AUTOANSWER(), NUTAG_EARLY_MEDIA(),
4074 * NUTAG_EARLY_ANSWER(), NUTAG_INCLUDE_EXTRA_SDP(),
4075 * nua_ack(), NUTAG_AUTOACK(), nua_bye(), #nua_r_bye, #nua_i_bye,
4076 * nua_cancel(), #nua_r_cancel, #nua_i_cancel,
4077 * nua_prack(), #nua_r_prack, #nua_i_prack,
4078 * nua_update(), #nua_r_update, #nua_i_update
4079 *
4080 * @par History
4081 * Prior @VERSION_1_12_6 the tags NUTAG_OFFER_RECV(), NUTAG_ANSWER_RECV(),
4082 * NUTAG_ANSWER_SENT(), NUTAG_OFFER_SENT() were not included with
4083 * nua_i_state eventif media was disabled.
4084 *
4085 * @END_NUA_EVENT
4086 */
4087
4088/**
4089 * Delivers call state changed event to the nua client. @internal
4090 *
4091 * @param nh call handle
4092 * @param status status code
4093 * @param tr_event SIP transaction event triggering this change
4094 * @param oa_recv Received SDP
4095 * @param oa_sent Sent SDP
4096 */
4097
4098static void signal_call_state_change(nua_handle_t *nh,
4099 nua_session_usage_t *ss,
4100 int status, char const *phrase,
4101 enum nua_callstate next_state)
4102{
4103 enum nua_callstate ss_state = nua_callstate_init;
4104 enum nua_callstate invite_state = next_state;
4105
4106 char const *oa_recv = NULL((void*)0);
4107 char const *oa_sent = NULL((void*)0);
4108
4109 int offer_recv = 0, answer_recv = 0, offer_sent = 0, answer_sent = 0;
4110
4111 if (ss) {
4112 if (ss->ss_reporting)
4113 return;
4114
4115 ss_state = ss->ss_state;
4116 oa_recv = ss->ss_oa_recv, ss->ss_oa_recv = NULL((void*)0);
4117 oa_sent = ss->ss_oa_sent, ss->ss_oa_sent = NULL((void*)0);
4118
4119 assert(oa_sent == Offer || oa_sent == Answer || oa_sent == NULL)((oa_sent == Offer || oa_sent == Answer || oa_sent == ((void*
)0)) ? (void) (0) : __assert_fail ("oa_sent == Offer || oa_sent == Answer || oa_sent == ((void*)0)"
, "nua_session.c", 4119, __PRETTY_FUNCTION__))
;
4120 assert(oa_recv == Offer || oa_recv == Answer || oa_recv == NULL)((oa_recv == Offer || oa_recv == Answer || oa_recv == ((void*
)0)) ? (void) (0) : __assert_fail ("oa_recv == Offer || oa_recv == Answer || oa_recv == ((void*)0)"
, "nua_session.c", 4120, __PRETTY_FUNCTION__))
;
4121
4122 if (oa_recv) {
4123 offer_recv = oa_recv == Offer;
4124 answer_recv = oa_recv == Answer;
4125 }
4126
4127 if (oa_sent) {
4128 offer_sent = oa_sent == Offer;
4129 answer_sent = oa_sent == Answer;
4130 }
4131 }
4132
4133 if (ss_state < nua_callstate_ready || next_state > nua_callstate_ready)
4134 SU_DEBUG_5(("nua(%p): call state changed: %s -> %s%s%s%s%s\n",((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 4139, "nua(%p): call state changed: %s -> %s%s%s%s%s\n"
, (void *)nh, nua_callstate_name(ss_state), nua_callstate_name
(next_state), oa_recv ? ", received " : "", oa_recv ? oa_recv
: "", oa_sent && oa_recv ? ", and sent " : oa_sent ?
", sent " : "", oa_sent ? oa_sent : "")) : (void)0)
4135 (void *)nh, nua_callstate_name(ss_state),((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 4139, "nua(%p): call state changed: %s -> %s%s%s%s%s\n"
, (void *)nh, nua_callstate_name(ss_state), nua_callstate_name
(next_state), oa_recv ? ", received " : "", oa_recv ? oa_recv
: "", oa_sent && oa_recv ? ", and sent " : oa_sent ?
", sent " : "", oa_sent ? oa_sent : "")) : (void)0)
4136 nua_callstate_name(next_state),((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 4139, "nua(%p): call state changed: %s -> %s%s%s%s%s\n"
, (void *)nh, nua_callstate_name(ss_state), nua_callstate_name
(next_state), oa_recv ? ", received " : "", oa_recv ? oa_recv
: "", oa_sent && oa_recv ? ", and sent " : oa_sent ?
", sent " : "", oa_sent ? oa_sent : "")) : (void)0)
4137 oa_recv ? ", received " : "", oa_recv ? oa_recv : "",((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 4139, "nua(%p): call state changed: %s -> %s%s%s%s%s\n"
, (void *)nh, nua_callstate_name(ss_state), nua_callstate_name
(next_state), oa_recv ? ", received " : "", oa_recv ? oa_recv
: "", oa_sent && oa_recv ? ", and sent " : oa_sent ?
", sent " : "", oa_sent ? oa_sent : "")) : (void)0)
4138 oa_sent && oa_recv ? ", and sent " :((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 4139, "nua(%p): call state changed: %s -> %s%s%s%s%s\n"
, (void *)nh, nua_callstate_name(ss_state), nua_callstate_name
(next_state), oa_recv ? ", received " : "", oa_recv ? oa_recv
: "", oa_sent && oa_recv ? ", and sent " : oa_sent ?
", sent " : "", oa_sent ? oa_sent : "")) : (void)0)
4139 oa_sent ? ", sent " : "", oa_sent ? oa_sent : ""))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 4139, "nua(%p): call state changed: %s -> %s%s%s%s%s\n"
, (void *)nh, nua_callstate_name(ss_state), nua_callstate_name
(next_state), oa_recv ? ", received " : "", oa_recv ? oa_recv
: "", oa_sent && oa_recv ? ", and sent " : oa_sent ?
", sent " : "", oa_sent ? oa_sent : "")) : (void)0)
;
4140 else
4141 SU_DEBUG_5(("nua(%p): ready call updated: %s%s%s%s%s\n",((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 4145, "nua(%p): ready call updated: %s%s%s%s%s\n"
, (void *)nh, nua_callstate_name(next_state), oa_recv ? " received "
: "", oa_recv ? oa_recv : "", oa_sent && oa_recv ? ", sent "
: oa_sent ? " sent " : "", oa_sent ? oa_sent : "")) : (void)
0)
4142 (void *)nh, nua_callstate_name(next_state),((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 4145, "nua(%p): ready call updated: %s%s%s%s%s\n"
, (void *)nh, nua_callstate_name(next_state), oa_recv ? " received "
: "", oa_recv ? oa_recv : "", oa_sent && oa_recv ? ", sent "
: oa_sent ? " sent " : "", oa_sent ? oa_sent : "")) : (void)
0)
4143 oa_recv ? " received " : "", oa_recv ? oa_recv : "",((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 4145, "nua(%p): ready call updated: %s%s%s%s%s\n"
, (void *)nh, nua_callstate_name(next_state), oa_recv ? " received "
: "", oa_recv ? oa_recv : "", oa_sent && oa_recv ? ", sent "
: oa_sent ? " sent " : "", oa_sent ? oa_sent : "")) : (void)
0)
4144 oa_sent && oa_recv ? ", sent " :((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 4145, "nua(%p): ready call updated: %s%s%s%s%s\n"
, (void *)nh, nua_callstate_name(next_state), oa_recv ? " received "
: "", oa_recv ? oa_recv : "", oa_sent && oa_recv ? ", sent "
: oa_sent ? " sent " : "", oa_sent ? oa_sent : "")) : (void)
0)
4145 oa_sent ? " sent " : "", oa_sent ? oa_sent : ""))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 4145, "nua(%p): ready call updated: %s%s%s%s%s\n"
, (void *)nh, nua_callstate_name(next_state), oa_recv ? " received "
: "", oa_recv ? oa_recv : "", oa_sent && oa_recv ? ", sent "
: oa_sent ? " sent " : "", oa_sent ? oa_sent : "")) : (void)
0)
;
4146
4147 if (next_state == nua_callstate_terminating &&
4148 ss_state >= nua_callstate_terminating)
4149 return;
4150
4151 if (ss) {
4152 /* Update state variables */
4153 if (next_state == nua_callstate_init) {
4154 if (ss_state < nua_callstate_ready)
4155 ss->ss_state = next_state;
4156 else if (ss->ss_state == nua_callstate_ready)
4157 next_state = ss->ss_state;
4158 else if (ss->ss_state == nua_callstate_terminating)
4159 return;
4160 else
4161 ss->ss_state = next_state = nua_callstate_terminated;
4162 }
4163 else if (next_state > ss_state)
4164 ss->ss_state = next_state;
4165 }
4166
4167 if (next_state == nua_callstate_init)
4168 next_state = nua_callstate_terminated;
4169
4170 if (ss && ss->ss_state == nua_callstate_ready)
4171 nh->nh_active_call = 1;
4172 else if (next_state == nua_callstate_terminated)
4173 nh->nh_active_call = 0;
4174
4175 /* Send events */
4176 if (phrase == NULL((void*)0))
4177 phrase = "Call state";
4178
4179 {
4180 sdp_session_t const *remote_sdp = NULL((void*)0);
4181 char const *remote_sdp_str = NULL((void*)0);
4182 sdp_session_t const *local_sdp = NULL((void*)0);
4183 char const *local_sdp_str = NULL((void*)0);
4184
4185 if (nh->nh_soa) {
4186 if (oa_recv)
4187 soa_get_remote_sdp(nh->nh_soa, &remote_sdp, &remote_sdp_str, 0);
4188 if (oa_sent)
4189 soa_get_local_sdp(nh->nh_soa, &local_sdp, &local_sdp_str, 0);
4190
4191 if (answer_recv || answer_sent) { /* Update nh_hold_remote */
4192 char const *held = NULL((void*)0);
4193 soa_get_params(nh->nh_soa, SOATAG_HOLD_REF(held)soatag_hold_ref, tag_str_vr(&(held)), TAG_END()(tag_type_t)0, (tag_value_t)0);
4194 nh->nh_hold_remote = held && strlen(held) > 0;
4195 }
4196 }
4197 else
4198 oa_recv = NULL((void*)0), oa_sent = NULL((void*)0);
4199
4200 nua_stack_tevent(nh->nh_nua, nh, NULL((void*)0), nua_i_state,
4201 status, phrase,
4202 NUTAG_CALLSTATE(next_state)nutag_callstate, tag_int_v(next_state),
4203 NH_ACTIVE_MEDIA_TAGS(1, nh->nh_soa)!((1) && (nh->nh_soa) && soa_is_audio_active
(nh->nh_soa) >= 0) ? tag_skip : soatag_active_audio, tag_int_v
(soa_is_audio_active(nh->nh_soa)), !((1) && (nh->
nh_soa) && soa_is_video_active(nh->nh_soa) >= 0
) ? tag_skip : soatag_active_video, tag_int_v(soa_is_video_active
(nh->nh_soa)), !((1) && (nh->nh_soa) &&
soa_is_image_active(nh->nh_soa) >= 0) ? tag_skip : soatag_active_image
, tag_int_v(soa_is_image_active(nh->nh_soa)), !((1) &&
(nh->nh_soa) && soa_is_chat_active(nh->nh_soa)
>= 0) ? tag_skip : soatag_active_chat, tag_int_v(soa_is_chat_active
(nh->nh_soa))
,
4204 /* NUTAG_SOA_SESSION(nh->nh_soa), */
4205 TAG_IF(offer_recv, NUTAG_OFFER_RECV(offer_recv))!(offer_recv) ? tag_skip : nutag_offer_recv, tag_bool_v(offer_recv
)
,
4206 TAG_IF(answer_recv, NUTAG_ANSWER_RECV(answer_recv))!(answer_recv) ? tag_skip : nutag_answer_recv, tag_bool_v(answer_recv
)
,
4207 TAG_IF(offer_sent, NUTAG_OFFER_SENT(offer_sent))!(offer_sent) ? tag_skip : nutag_offer_sent, tag_bool_v(offer_sent
)
,
4208 TAG_IF(answer_sent, NUTAG_ANSWER_SENT(answer_sent))!(answer_sent) ? tag_skip : nutag_answer_sent, tag_bool_v(answer_sent
)
,
4209 TAG_IF(oa_recv, SOATAG_REMOTE_SDP(remote_sdp))!(oa_recv) ? tag_skip : soatag_remote_sdp, sdptag_session_v(remote_sdp
)
,
4210 TAG_IF(oa_recv, SOATAG_REMOTE_SDP_STR(remote_sdp_str))!(oa_recv) ? tag_skip : soatag_remote_sdp_str, tag_str_v(remote_sdp_str
)
,
4211 TAG_IF(oa_sent, SOATAG_LOCAL_SDP(local_sdp))!(oa_sent) ? tag_skip : soatag_local_sdp, sdptag_session_v(local_sdp
)
,
4212 TAG_IF(oa_sent, SOATAG_LOCAL_SDP_STR(local_sdp_str))!(oa_sent) ? tag_skip : soatag_local_sdp_str, tag_str_v(local_sdp_str
)
,
4213 TAG_END()(tag_type_t)0, (tag_value_t)0);
4214 }
4215
4216 if (next_state == nua_callstate_ready && ss_state <= nua_callstate_ready) {
4217 nua_stack_tevent(nh->nh_nua, nh, NULL((void*)0), nua_i_active, status, "Call active",
4218 NH_ACTIVE_MEDIA_TAGS(1, nh->nh_soa)!((1) && (nh->nh_soa) && soa_is_audio_active
(nh->nh_soa) >= 0) ? tag_skip : soatag_active_audio, tag_int_v
(soa_is_audio_active(nh->nh_soa)), !((1) && (nh->
nh_soa) && soa_is_video_active(nh->nh_soa) >= 0
) ? tag_skip : soatag_active_video, tag_int_v(soa_is_video_active
(nh->nh_soa)), !((1) && (nh->nh_soa) &&
soa_is_image_active(nh->nh_soa) >= 0) ? tag_skip : soatag_active_image
, tag_int_v(soa_is_image_active(nh->nh_soa)), !((1) &&
(nh->nh_soa) && soa_is_chat_active(nh->nh_soa)
>= 0) ? tag_skip : soatag_active_chat, tag_int_v(soa_is_chat_active
(nh->nh_soa))
,
4219 /* NUTAG_SOA_SESSION(nh->nh_soa), */
4220 TAG_END()(tag_type_t)0, (tag_value_t)0);
4221 }
4222
4223 else if (next_state == nua_callstate_terminated) {
4224 nua_stack_event(nh->nh_nua, nh, NULL((void*)0),
4225 nua_i_terminated, status, phrase,
4226 NULL((void*)0));
4227 }
4228
4229 if (invite_state == nua_callstate_ready) {
4230 /* Start next INVITE request, if queued */
4231 nua_client_next_request(nh->nh_ds->ds_cr, 1);
4232 }
4233}
4234
4235/** @NUA_EVENT nua_i_active
4236 *
4237 * A call has been activated.
4238 *
4239 * This event will be sent after a succesful response to the initial
4240 * INVITE has been received and the media has been activated.
4241 *
4242 * @param nh operation handle associated with the call
4243 * @param hmagic application context associated with the call
4244 * @param sip NULL
4245 * @param tags SOATAG_ACTIVE_AUDIO(), SOATAG_ACTIVE_VIDEO(),
4246 * SOATAG_ACTIVE_IMAGE(), SOATAG_ACTIVE_CHAT().
4247 *
4248 * @deprecated Use #nua_i_state instead.
4249 *
4250 * @sa @ref nua_call_model, #nua_i_state, #nua_i_terminated,
4251 * #nua_i_invite
4252 *
4253 * @END_NUA_EVENT
4254 */
4255
4256/** @NUA_EVENT nua_i_terminated
4257 *
4258 * A call has been terminated.
4259 *
4260 * This event will be sent after a call has been terminated. A call is
4261 * terminated, when
4262 * 1) an error response (300..599) is sent to an incoming initial INVITE
4263 * 2) a reliable response (200..299 or reliable preliminary response) to
4264 * an incoming initial INVITE is not acknowledged with ACK or PRACK
4265 * 3) BYE is received or sent
4266 *
4267 * @param nh operation handle associated with the call
4268 * @param hmagic application context associated with the call
4269 * @param sip NULL
4270 * @param tags empty
4271 *
4272 * @deprecated Use #nua_i_state instead.
4273 *
4274 * @sa @ref nua_call_model, #nua_i_state, #nua_i_active, #nua_i_bye,
4275 * #nua_i_invite
4276 *
4277 * @END_NUA_EVENT
4278 */
4279
4280
4281/* ======================================================================== */
4282
4283static
4284int nua_server_retry_after(nua_server_request_t *sr,
4285 int status, char const *phrase,
4286 int min, int max)
4287{
4288 sip_retry_after_t af[1];
4289
4290 sip_retry_after_init(af);
4291 af->af_delta = (unsigned)su_randint(min, max);
4292 af->af_comment = phrase;
4293
4294 sip_add_dup(sr->sr_response.msg, sr->sr_response.sip, (sip_header_t *)af);
4295
4296 return sr_status(sr, status, phrase);
4297}
4298
4299/* ======================================================================== */
4300/* Session timer - RFC 4028 */
4301
4302static int session_timer_is_supported(struct session_timer const *t)
4303{
4304 return t->local.supported;
4305}
4306
4307/** Set session timer preferences */
4308static
4309void session_timer_preferences(struct session_timer *t,
4310 sip_t const *sip,
4311 sip_supported_t const *supported,
4312 unsigned expires,
4313 int isset,
4314 enum nua_session_refresher refresher,
4315 unsigned min_se)
4316{
4317 memset(&t->local, 0, sizeof t->local);
4318
4319 t->local.require = sip_has_feature(sip->sip_require, "timer");
4320 t->local.supported =
4321 sip_has_feature(supported, "timer") ||
4322 sip_has_feature(sip->sip_supported, "timer");
4323 if (isset || refresher != nua_no_refresher)
4324 t->local.expires = expires;
4325 else
4326 t->local.defaults = expires;
4327 t->local.min_se = min_se;
4328 t->local.refresher = refresher;
4329}
4330
4331static int session_timer_check_restart(nua_client_request_t *cr,
4332 int status, char const *phrase,
4333 sip_t const *sip)
4334{
4335 if (status == 422) {
4336 nua_session_usage_t *ss = nua_dialog_usage_private(cr->cr_usage)((cr->cr_usage) ? (void*)((cr->cr_usage) + 1) : ((void*
)0))
;
4337
4338 if (ss && session_timer_is_supported(ss->ss_timer)) {
4339 struct session_timer *t = ss->ss_timer;
4340
4341 if (sip->sip_min_se && t->local.min_se < sip->sip_min_se->min_delta)
4342 t->local.min_se = sip->sip_min_se->min_delta;
4343 if (t->local.expires != 0 && t->local.min_se > t->local.expires)
4344 t->local.expires = t->local.min_se;
4345
4346 return nua_client_restart(cr, 100, "Re-Negotiating Session Timer");
4347 }
4348 }
4349
4350 return nua_base_client_check_restart(cr, status, phrase, sip);
4351}
4352
4353/** Check that received Session-Expires is longer than Min-SE */
4354static
4355int session_timer_check_min_se(msg_t *msg,
4356 sip_t *sip,
4357 sip_t const *request,
4358 unsigned long min)
4359{
4360 if (min == 0)
4361 min = 1;
4362
4363 /*
4364 If an incoming request contains a Supported header field with a value
4365 'timer' and a Session Expires header field, the UAS MAY reject the
4366 INVITE request with a 422 (Session Interval Too Small) response if
4367 the session interval in the Session-Expires header field is smaller
4368 than the minimum interval defined by the UAS' local policy. When
4369 sending the 422 response, the UAS MUST include a Min-SE header field
4370 with the value of its minimum interval. This minimum interval MUST
4371 NOT be lower than 90 seconds.
4372 */
4373 if (request->sip_session_expires &&
4374 sip_has_feature(request->sip_supported, "timer") &&
4375 request->sip_session_expires->x_delta < min) {
4376 sip_min_se_t min_se[1];
4377
4378 if (min < 90)
4379 min = 90;
4380
4381 sip_min_se_init(min_se)->min_delta = min;
4382
4383 /* Include extension parameters, if any */
4384 if (request->sip_min_se)
4385 min_se->min_params = request->sip_min_se->min_params;
4386
4387 sip_add_dup(msg, sip, (sip_header_t *)min_se);
4388
4389 return 422;
4390 }
4391
4392 return 0;
4393}
4394
4395/** Store session timer parameters in request from uac / response from uas */
4396static
4397void session_timer_store(struct session_timer *t,
4398 sip_t const *sip)
4399{
4400 sip_require_t const *require = sip->sip_require;
4401 sip_supported_t const *supported = sip->sip_supported;
4402 sip_session_expires_t const *x = sip->sip_session_expires;
4403
4404 t->remote.require = require && sip_has_feature(require, "timer");
4405 t->remote.supported =
4406 t->remote.supported || (supported && sip_has_feature(supported, "timer"));
4407
4408 t->remote.expires = 0;
4409 t->remote.refresher = nua_any_refresher;
4410 t->remote.min_se = 0;
4411
4412 if (x) {
4413 t->remote.expires = x->x_delta;
4414
4415 if (x->x_refresher) {
4416 int uas = sip->sip_request != NULL((void*)0);
4417
4418 if (su_casenmatch(x->x_refresher, "uac", (sizeof "uac")))
4419 t->remote.refresher = uas ? nua_remote_refresher : nua_local_refresher;
4420 else if (su_casenmatch(x->x_refresher, "uas", (sizeof "uas")))
4421 t->remote.refresher = uas ? nua_local_refresher : nua_remote_refresher;
4422 }
4423 else if (t->remote.require) {
4424 /* Require: timer but no refresher parameter in Session-Expires header */
4425 t->remote.refresher = nua_local_refresher;
4426 }
4427 }
4428
4429 if (sip->sip_min_se)
4430 t->remote.min_se = sip->sip_min_se->min_delta;
4431}
4432
4433/** Add timer feature and Session-Expires/Min-SE headers to request/response
4434 *
4435 */
4436static int
4437session_timer_add_headers(struct session_timer *t,
4438 int initial,
4439 msg_t *msg,
4440 sip_t *sip,
4441 nua_handle_t *nh)
4442{
4443 unsigned long expires, min;
4444 sip_min_se_t min_se[1];
4445 sip_session_expires_t x[1];
4446 int uas;
4447 int autorequire = 1;
4448
4449 enum nua_session_refresher refresher = nua_any_refresher;
4450
4451 static sip_param_t const x_params_uac[] = {"refresher=uac", NULL((void*)0)};
4452 static sip_param_t const x_params_uas[] = {"refresher=uas", NULL((void*)0)};
4453
4454 if ( !NH_PGET(nh, timer_autorequire)(((nh)->nh_prefs)->nhp_set_.set_bits.nhb_timer_autorequire
? ((nh)->nh_prefs)->nhp_timer_autorequire : ((nh)->
nh_nua->nua_handles->nh_prefs)->nhp_timer_autorequire
)
&& NH_PISSET(nh, timer_autorequire)((((nh)->nh_prefs)->nhp_set_.set_bits.nhb_timer_autorequire
) && (nh)->nh_nua->nua_handles->nh_prefs != (
nh)->nh_prefs)
) {
4455 autorequire = 0;
4456 }
4457
4458 if (!t->local.supported)
4459 return 0;
4460
4461 uas = sip->sip_status != NULL((void*)0);
4462
4463 min = t->local.min_se;
4464 if (min < t->remote.min_se)
4465 min = t->remote.min_se;
4466
4467 if (uas) {
4468 session_timer_negotiate(t, uas = 1);
4469
4470 refresher = t->refresher;
4471 expires = t->interval;
4472 }
4473 else {
4474 /* RFC 4028:
4475 * The UAC MAY include the refresher parameter with value 'uac' if it
4476 * wants to perform the refreshes. However, it is RECOMMENDED that the
4477 * parameter be omitted so that it can be selected by the negotiation
4478 * mechanisms described below.
4479 */
4480 if (t->local.refresher == nua_local_refresher)
4481 refresher = nua_local_refresher;
4482 else if (!initial)
4483 refresher = t->refresher;
4484
4485 expires = t->local.expires;
4486 if (expires != 0 && expires < min)
4487 expires = min;
4488
4489 if (expires == 0 && !initial && t->interval)
4490 expires = t->interval;
4491 }
4492
4493 sip_min_se_init(min_se)->min_delta = min;
4494
4495 sip_session_expires_init(x)->x_delta = expires;
4496 if (refresher == nua_remote_refresher)
4497 x->x_params = uas ? x_params_uac : x_params_uas;
4498 else if (refresher == nua_local_refresher)
4499 x->x_params = uas ? x_params_uas : x_params_uac;
4500
4501 if (expires == 0 && t->remote.min_se == 0)
4502 /* Session timer is not used, do not add headers */
4503 return 1;
4504
4505 sip_add_tl(msg, sip,
4506 TAG_IF(expires != 0, SIPTAG_SESSION_EXPIRES(x))!(expires != 0) ? tag_skip : siptag_session_expires, siptag_session_expires_v
(x)
,
4507 TAG_IF((!uas || sip->sip_status->st_status == 422) && (min != 0!((!uas || sip->sip_status->st_status == 422) &&
(min != 0 || !initial)) ? tag_skip : siptag_min_se, siptag_min_se_v
(min_se)
4508 /* Min-SE: 0 is optional with initial INVITE */!((!uas || sip->sip_status->st_status == 422) &&
(min != 0 || !initial)) ? tag_skip : siptag_min_se, siptag_min_se_v
(min_se)
4509 || !initial),!((!uas || sip->sip_status->st_status == 422) &&
(min != 0 || !initial)) ? tag_skip : siptag_min_se, siptag_min_se_v
(min_se)
4510 SIPTAG_MIN_SE(min_se))!((!uas || sip->sip_status->st_status == 422) &&
(min != 0 || !initial)) ? tag_skip : siptag_min_se, siptag_min_se_v
(min_se)
,
4511 TAG_IF(autorequire && refresher == nua_remote_refresher && expires != 0, SIPTAG_REQUIRE_STR("timer"))!(autorequire && refresher == nua_remote_refresher &&
expires != 0) ? tag_skip : siptag_require_str, tag_str_v("timer"
)
,
4512 TAG_END()(tag_type_t)0, (tag_value_t)0);
4513
4514 return 1;
4515}
4516
4517static void
4518session_timer_negotiate(struct session_timer *t, int uas)
4519{
4520 if (!t->local.supported)
4521 t->refresher = nua_no_refresher;
4522 else if (!t->remote.supported)
4523 t->refresher = nua_local_refresher;
4524 else if (t->remote.refresher == nua_local_refresher)
4525 t->refresher = nua_local_refresher;
4526 else if (t->remote.refresher == nua_remote_refresher)
4527 t->refresher = nua_remote_refresher;
4528 else if (uas)
4529 /* UAS defaults UAC to refreshing */
4530 t->refresher = nua_remote_refresher;
4531 else
4532 /* UAC refreshes by itself */
4533 t->refresher = nua_local_refresher;
4534
4535 t->interval = t->remote.expires;
4536 if (t->interval == 0)
4537 t->interval = t->local.expires;
4538 if (t->local.expires != 0 && t->interval > t->local.expires)
4539 t->interval = t->local.expires;
4540 if (t->local.defaults != 0 && t->interval > t->local.defaults)
4541 t->interval = t->local.defaults;
4542
4543 if (t->interval != 0) {
4544 if (t->interval < t->local.min_se)
4545 t->interval = t->local.min_se;
4546 if (t->interval < t->remote.min_se)
4547 t->interval = t->remote.min_se;
4548 }
4549
4550 if (t->interval == 0)
4551 t->refresher = nua_no_refresher;
4552}
4553
4554static void
4555session_timer_set(nua_session_usage_t *ss, int uas)
4556{
4557 nua_dialog_usage_t *du = nua_dialog_usage_public(ss)((ss) ? (nua_dialog_usage_t*)(ss) - 1 : ((void*)0));
4558 struct session_timer *t;
4559
4560 if (ss == NULL((void*)0))
4561 return;
4562
4563 t = ss->ss_timer;
4564
4565 session_timer_negotiate(t, uas);
4566
4567 if (t->refresher == nua_local_refresher) {
4568 unsigned low = t->interval / 2, high = t->interval / 2;
4569
4570 if (t->interval >= 90)
4571 low -=5, high += 5;
4572
4573 nua_dialog_usage_set_refresh_range(du, low, high);
4574 t->timer_set = 1;
4575 }
4576 else if (t->refresher == nua_remote_refresher) {
4577 /* RFC 4028 10.3 and 10.4: Send BYE before the session expires.
4578 Increased interval from 2/3 to 9/10 of session expiration delay
4579 because some endpoints won't UPDATE early enough with very short
4580 sessions (e.g. 120). */
4581
4582 unsigned interval = t->interval;
4583
4584 interval -= 32 > interval / 10 ? interval / 10 : 32;
4585
4586 nua_dialog_usage_set_refresh_range(du, interval, interval);
4587 t->timer_set = 1;
4588 }
4589 else {
4590 nua_dialog_usage_reset_refresh(du);
4591 t->timer_set = 0;
4592 }
4593}
4594
4595/* ======================================================================== */
4596
4597/** Get SDP from a SIP message.
4598 *
4599 * @retval 1 if message contains SDP
4600 * @retval 0 if message does not contain valid SDP
4601 */
4602static
4603int session_get_description(sip_t const *sip,
4604 char const **return_sdp,
4605 size_t *return_len)
4606{
4607 sip_payload_t const *pl = sip->sip_payload;
4608 sip_content_type_t const *ct = sip->sip_content_type;
4609 int matching_content_type = 0;
4610
4611 if (pl == NULL((void*)0))
4612 return 0;
4613 else if (pl->pl_len == 0 || pl->pl_data == NULL((void*)0))
4614 return 0;
4615 else if (ct == NULL((void*)0))
4616 /* Be bug-compatible with our old gateways */
4617 SU_DEBUG_3(("nua: no %s, assuming %s\n",((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_session.c"
, (const char *)__func__, 4618, "nua: no %s, assuming %s\n", "Content-Type"
, nua_application_sdp)) : (void)0)
4618 "Content-Type", SDP_MIME_TYPE))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_session.c"
, (const char *)__func__, 4618, "nua: no %s, assuming %s\n", "Content-Type"
, nua_application_sdp)) : (void)0)
;
4619 else if (ct->c_type == NULL((void*)0))
4620 SU_DEBUG_3(("nua: empty %s, assuming %s\n",((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_session.c"
, (const char *)__func__, 4621, "nua: empty %s, assuming %s\n"
, "Content-Type", nua_application_sdp)) : (void)0)
4621 "Content-Type", SDP_MIME_TYPE))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 3 ? (_su_llog((nua_log), 3, "nua_session.c"
, (const char *)__func__, 4621, "nua: empty %s, assuming %s\n"
, "Content-Type", nua_application_sdp)) : (void)0)
;
4622 else if (!su_casematch(ct->c_type, SDP_MIME_TYPEnua_application_sdp)) {
4623 SU_DEBUG_5(("nua: unknown %s: %s\n", "Content-Type", ct->c_type))((((nua_log) != ((void*)0) && (nua_log)->log_init)
== 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)->
log_init > 1) ? (nua_log)->log_level : su_log_default->
log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_session.c"
, (const char *)__func__, 4623, "nua: unknown %s: %s\n", "Content-Type"
, ct->c_type)) : (void)0)
;
4624 return 0;
4625 }
4626 else
4627 matching_content_type = 1;
4628
4629 if (pl == NULL((void*)0))
4630 return 0;
4631
4632 if (!matching_content_type) {
4633 /* Make sure we got SDP */
4634 if (pl->pl_len < 3 || !su_casenmatch(pl->pl_data, "v=0", 3))
4635 return 0;
4636 }
4637
4638 if (return_sdp && return_len) {
4639 *return_sdp = pl->pl_data;
4640 *return_len = pl->pl_len;
4641 }
4642
4643 return 1;
4644}
4645
4646/** Insert SDP into SIP message */
4647static
4648int session_include_description(soa_session_t *soa,
4649 int session,
4650 msg_t *msg,
4651 sip_t *sip)
4652{
4653 su_home_t *home = msg_home(msg)((su_home_t*)(msg));
4654
4655 sip_content_disposition_t *cd = NULL((void*)0);
4656 sip_content_type_t *ct = NULL((void*)0);
4657 sip_payload_t *pl = NULL((void*)0);
4658
4659 int retval;
4660
4661 if (!soa)
4662 return 0;
4663
4664 retval = session_make_description(home, soa, session, &cd, &ct, &pl);
4665
4666 if (retval <= 0)
4667 return retval;
4668
4669 if ((cd && sip_header_insert(msg, sip, (sip_header_t *)cd) < 0) ||
4670 sip_header_insert(msg, sip, (sip_header_t *)ct) < 0 ||
4671 sip_header_insert(msg, sip, (sip_header_t *)pl) < 0)
4672 return -1;
4673
4674 return retval;
4675}
4676
4677/** Generate SDP headers */
4678static
4679int session_make_description(su_home_t *home,
4680 soa_session_t *soa,
4681 int session,
4682 sip_content_disposition_t **return_cd,
4683 sip_content_type_t **return_ct,
4684 sip_payload_t **return_pl)
4685{
4686 char const *sdp;
4687 isize_t len;
4688 int retval;
4689
4690 if (!soa)
4691 return 0;
4692
4693 if (session)
4694 retval = soa_get_local_sdp(soa, 0, &sdp, &len);
4695 else
4696 retval = soa_get_capability_sdp(soa, 0, &sdp, &len);
4697
4698 if (retval > 0) {
4699 *return_pl = sip_payload_create(home, sdp, len);
4700 *return_ct = sip_content_type_make(home, SDP_MIME_TYPEnua_application_sdp);
4701 if (session)
4702 *return_cd = sip_content_disposition_make(home, "session");
4703 else
4704 *return_cd = NULL((void*)0);
4705
4706 if (!*return_pl || !*return_ct)
4707 return -1;
4708
4709 if (session && !*return_cd)
4710 return -1;
4711 }
4712
4713 return retval;
4714}
4715
4716/* ====================================================================== */
4717
4718/** @NUA_EVENT nua_i_options
4719 *
4720 * Incoming OPTIONS request. The user-agent should respond to an OPTIONS
4721 * request with the same statuscode as it would respond to an INVITE
4722 * request.
4723 *
4724 * Stack responds automatically to OPTIONS request unless OPTIONS is
4725 * included in the set of application methods, set by NUTAG_APPL_METHOD().
4726 *
4727 * The OPTIONS request does not create a dialog. Currently the processing
4728 * of incoming OPTIONS creates a new handle for each incoming request which
4729 * is not assiciated with an existing dialog. If the handle @a nh is not
4730 * bound, you should probably destroy it after responding to the OPTIONS
4731 * request.
4732 *
4733 * @param status status code of response sent automatically by stack
4734 * @param phrase a short textual description of @a status code
4735 * @param nh operation handle associated with the OPTIONS request
4736 * @param hmagic application context associated with the call
4737 * (NULL if outside session)
4738 * @param sip incoming OPTIONS request
4739 * @param tags empty
4740 *
4741 * @sa nua_respond(), nua_options(), #nua_r_options, @RFC3261 section 11.2
4742 *
4743 * @END_NUA_EVENT
4744 */
4745
4746int nua_options_server_respond(nua_server_request_t *sr, tagi_t const *tags);
4747
4748nua_server_methods_t const nua_options_server_methods =
4749 {
4750 SIP_METHOD_OPTIONSsip_method_options, "OPTIONS",
4751 nua_i_options, /* Event */
4752 {
4753 0, /* Do not create dialog */
4754 0, /* Initial request */
4755 0, /* Not a target refresh request */
4756 1, /* Add Contact */
4757 },
4758 nua_base_server_init((void*)0),
4759 nua_base_server_preprocess((void*)0),
4760 nua_base_server_params((void*)0),
4761 nua_options_server_respond,
4762 nua_base_server_report,
4763 };
4764
4765/** @internal Respond to an OPTIONS request.
4766 *
4767 */
4768int nua_options_server_respond(nua_server_request_t *sr, tagi_t const *tags)
4769{
4770 nua_handle_t *nh = sr->sr_owner;
4771 nua_t *nua = nh->nh_nua;
4772
4773 if (200 <= sr->sr_status && sr->sr_status < 300) {
4774 msg_t *msg = sr->sr_response.msg;
4775 sip_t *sip = sr->sr_response.sip;
4776
4777 sip_add_tl(msg, sip, SIPTAG_ACCEPT(nua->nua_invite_accept)siptag_accept, siptag_accept_v(nua->nua_invite_accept), TAG_END()(tag_type_t)0, (tag_value_t)0);
4778
4779 if (!sip->sip_payload) { /* XXX - do MIME multipart? */
4780 soa_session_t *soa = nh->nh_soa;
4781
4782 if (soa == NULL((void*)0))
4783 soa = nua->nua_dhandlenua_handles->nh_soa;
4784
4785 session_include_description(soa, 0, msg, sip);
4786 }
4787 }
4788
4789 return nua_base_server_respond(sr, tags);
4790}