Bug Summary

File:nua/nua_session.c
Warning:line 4405, column 21
Dereference of null pointer

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name nua_session.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-eagerly-assume -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -resource-dir /usr/lib/llvm-7/lib/clang/7.0.1 -D HAVE_CONFIG_H -I . -I ../.. -I ../../libsofia-sip-ua/su/sofia-sip -I ../../libsofia-sip-ua/features -I ../../libsofia-sip-ua/features -I ../../libsofia-sip-ua/ipt -I ../../libsofia-sip-ua/ipt -I ../../libsofia-sip-ua/iptsec -I ../../libsofia-sip-ua/iptsec -I ../../libsofia-sip-ua/bnf -I ../../libsofia-sip-ua/bnf -I ../../libsofia-sip-ua/http -I ../../libsofia-sip-ua/http -I ../../libsofia-sip-ua/msg -I ../../libsofia-sip-ua/msg -I ../../libsofia-sip-ua/nth -I ../../libsofia-sip-ua/nth -I ../../libsofia-sip-ua/nta -I ../../libsofia-sip-ua/nta -I ../../libsofia-sip-ua/nea -I ../../libsofia-sip-ua/nea -I ../../libsofia-sip-ua/nua -I ../../libsofia-sip-ua/nua -I ../../libsofia-sip-ua/soa -I ../../libsofia-sip-ua/soa -I ../../libsofia-sip-ua/sdp -I ../../libsofia-sip-ua/sdp -I ../../libsofia-sip-ua/sip -I ../../libsofia-sip-ua/sip -I ../../libsofia-sip-ua/soa -I ../../libsofia-sip-ua/soa -I ../../libsofia-sip-ua/sresolv -I ../../libsofia-sip-ua/sresolv -I ../../libsofia-sip-ua/tport -I ../../libsofia-sip-ua/tport -I ../../libsofia-sip-ua/stun -I ../../libsofia-sip-ua/stun -I ../../libsofia-sip-ua/url -I ../../libsofia-sip-ua/url -I ../../libsofia-sip-ua/su -I ../../libsofia-sip-ua/su -I ../../s2check -D SU_DEBUG=0 -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-7/lib/clang/7.0.1/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir /drone/src/libsofia-sip-ua/nua -ferror-limit 19 -fmessage-length 0 -fobjc-runtime=gcc -fdiagnostics-show-option -analyzer-output=html -o /drone/src/scan-build/2021-08-31-190657-363-1 -x c nua_session.c -faddrsig
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
778 if (du == NULL((void*)0)) /* Call terminated */
779 return nua_client_return(cr, SIP_481_NO_TRANSACTION481, sip_481_No_transaction, msg);
780
781 ss = NUA_DIALOG_USAGE_PRIVATE(du)((void *)((du) + 1));
782
783 if (ss->ss_state >= nua_callstate_terminating)
784 return nua_client_return(cr, 900, "Session is terminating", msg);
785
786 nua_dialog_usage_reset_refresh(du);
787
788 /* Add session timer headers */
789 if (session_timer_is_supported(ss->ss_timer))
790 session_timer_add_headers(ss->ss_timer, ss->ss_state == nua_callstate_init,
791 msg, sip, nh);
792
793 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)
;
794 ss->ss_precondition = sip_has_feature(sip->sip_require, "precondition");
795 if (ss->ss_precondition)
796 ss->ss_update_needed = ss->ss_100rel = 1;
797
798 if (nh->nh_soa) {
799 soa_init_offer_answer(nh->nh_soa);
800
801 if (sip->sip_payload)
802 offer_sent = 0; /* XXX - kludge */
803 else if (soa_generate_offer(nh->nh_soa, 0, NULL((void*)0)) < 0)
804 return -1;
805 else
806 offer_sent = 1;
807
808 if (offer_sent > 0 &&
809 session_include_description(nh->nh_soa, 1, msg, sip) < 0)
810 return nua_client_return(cr, 900, "Internal media error", msg);
811
812 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)
&&
813 !nua_dialog_is_established(nh->nh_ds) &&
814 !sip->sip_accept_contact && !sip->sip_reject_contact) {
815 sip_accept_contact_t ac[1];
816 sip_accept_contact_init(ac);
817
818 ac->cp_params = (msg_param_t *)
819 soa_media_features(nh->nh_soa, 1, msg_home(msg)((su_home_t*)(msg)));
820
821 if (ac->cp_params) {
822 msg_header_replace_param(msg_home(msg)((su_home_t*)(msg)), ac->cp_common, "explicit");
823 sip_add_dup(msg, sip, (sip_header_t *)ac);
824 }
825 }
826 }
827 else {
828 offer_sent = session_get_description(sip, NULL((void*)0), NULL((void*)0));
829 }
830
831 retval = nua_base_client_trequest(cr, msg, sip,
832 NTATAG_REL100(ss->ss_100rel)ntatag_rel100, tag_bool_v((ss->ss_100rel)),
833 TAG_NEXT(tags)tag_next, (tag_value_t)(tags));
834 if (retval == 0) {
835 if ((cr->cr_offer_sent = offer_sent))
836 ss->ss_oa_sent = Offer;
837
838 if (!cr->cr_restarting) /* Restart logic calls nua_invite_client_report */
839 signal_call_state_change(nh, ss, 0, "INVITE sent",
840 nua_callstate_calling);
841 }
842
843 return retval;
844}
845
846static int nua_invite_client_response(nua_client_request_t *cr,
847 int status, char const *phrase,
848 sip_t const *sip)
849{
850 nua_dialog_usage_t *du = cr->cr_usage;
851 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
852 int uas;
853
854 if (ss == NULL((void*)0) || sip == NULL((void*)0)) {
855 /* Xyzzy */
856 }
857 else if (status < 300) {
858 du->du_ready = 1;
859
860 if (session_timer_is_supported(ss->ss_timer))
861 session_timer_store(ss->ss_timer, sip);
862
863 session_timer_set(ss, uas = 0);
864 }
865
866 return nua_session_client_response(cr, status, phrase, sip);
867}
868
869static int nua_invite_client_preliminary(nua_client_request_t *cr,
870 int status, char const *phrase,
871 sip_t const *sip)
872{
873 nua_handle_t *nh = cr->cr_owner;
874 nua_dialog_usage_t *du = cr->cr_usage;
875 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
876
877 assert(sip)((void) sizeof ((sip) ? 1 : 0), __extension__ ({ if (sip) ; else
__assert_fail ("sip", "nua_session.c", 877, __extension__ __PRETTY_FUNCTION__
); }))
;
878
879 if (ss && sip && sip->sip_rseq) {
880 /* Handle 100rel responses */
881 sip_rseq_t *rseq = sip->sip_rseq;
882
883 /* Establish early dialog - we should fork here */
884 if (!nua_dialog_is_established(nh->nh_ds)) {
885 nta_outgoing_t *tagged;
886
887 nua_dialog_uac_route(nh, nh->nh_ds, sip, 1, 1);
888 nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
889
890 /* Tag the INVITE request */
891 tagged = nta_outgoing_tagged(cr->cr_orq,
892 nua_client_orq_response, cr,
893 sip->sip_to->a_tag, sip->sip_rseq);
894 if (tagged) {
895 nta_outgoing_destroy(cr->cr_orq), cr->cr_orq = tagged;
896 }
897 else {
898 cr->cr_graceful = 1;
899 ss->ss_reason = "SIP;cause=500;text=\"Cannot Create Early Dialog\"";
900 }
901 }
902
903 if (!rseq) {
904 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__, 904, "nua(%p): 100rel missing RSeq\n"
, (void *)nh)) : (void)0)
;
905 }
906 else if (nta_outgoing_rseq(cr->cr_orq) > rseq->rs_response) {
907 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__, 909, "nua(%p): 100rel bad RSeq %u (got %u)\n"
, (void *)nh, (unsigned)rseq->rs_response, nta_outgoing_rseq
(cr->cr_orq))) : (void)0)
908 (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__, 909, "nua(%p): 100rel bad RSeq %u (got %u)\n"
, (void *)nh, (unsigned)rseq->rs_response, nta_outgoing_rseq
(cr->cr_orq))) : (void)0)
909 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__, 909, "nua(%p): 100rel bad RSeq %u (got %u)\n"
, (void *)nh, (unsigned)rseq->rs_response, nta_outgoing_rseq
(cr->cr_orq))) : (void)0)
;
910 return 1; /* Do not send event */
911 }
912 else if (nta_outgoing_setrseq(cr->cr_orq, rseq->rs_response) < 0) {
913 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__, 914, "nua(%p): cannot set RSeq %u\n"
, (void *)nh, (unsigned)rseq->rs_response)) : (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)) >= 1 ? (_su_llog((nua_log), 1, "nua_session.c"
, (const char *)__func__, 914, "nua(%p): cannot set RSeq %u\n"
, (void *)nh, (unsigned)rseq->rs_response)) : (void)0)
;
915 cr->cr_graceful = 1;
916 ss->ss_reason = "SIP;cause=400;text=\"Bad RSeq\"";
917 }
918 }
919
920 return nua_session_client_response(cr, status, phrase, sip);
921}
922
923/** Process response to a session request (INVITE, PRACK, UPDATE) */
924static int nua_session_client_response(nua_client_request_t *cr,
925 int status, char const *phrase,
926 sip_t const *sip)
927{
928 nua_handle_t *nh = cr->cr_owner;
929 nua_dialog_usage_t *du = cr->cr_usage;
930 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
931
932 char const *sdp = NULL((void*)0);
933 size_t len;
934 char const *received = NULL((void*)0);
935
936#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__, 936, "nua(%p): %s: %s %s in %u %s (%u)\n"
, (void *)nh, cr->cr_method_name, (m), received ? received
: "SDP", status, phrase, cr->cr_answer_recv)) : (void)0)
\
937 SU_DEBUG_3(("nua(%p): %s: %s %s in %u %s (%u)\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__, 939, "nua(%p): %s: %s %s in %u %s (%u)\n"
, (void *)nh, cr->cr_method_name, (m), received ? received
: "SDP", status, phrase, cr->cr_answer_recv)) : (void)0)
938 (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__, 939, "nua(%p): %s: %s %s in %u %s (%u)\n"
, (void *)nh, cr->cr_method_name, (m), received ? received
: "SDP", status, phrase, cr->cr_answer_recv)) : (void)0)
939 received ? received : "SDP", status, phrase, cr->cr_answer_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)) >= 3 ? (_su_llog((nua_log), 3, "nua_session.c"
, (const char *)__func__, 939, "nua(%p): %s: %s %s in %u %s (%u)\n"
, (void *)nh, cr->cr_method_name, (m), received ? received
: "SDP", status, phrase, cr->cr_answer_recv)) : (void)0)
940#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__, 940, "nua(%p): %s: %s %s in %u %s (%u)\n"
, (void *)nh, cr->cr_method_name, (m), received, status, phrase
, cr->cr_answer_recv)) : (void)0)
\
941 SU_DEBUG_5(("nua(%p): %s: %s %s in %u %s (%u)\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__, 942, "nua(%p): %s: %s %s in %u %s (%u)\n"
, (void *)nh, cr->cr_method_name, (m), received, status, phrase
, cr->cr_answer_recv)) : (void)0)
942 (void *)nh, cr->cr_method_name, (m), received, status, phrase, cr->cr_answer_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__, 942, "nua(%p): %s: %s %s in %u %s (%u)\n"
, (void *)nh, cr->cr_method_name, (m), received, status, phrase
, cr->cr_answer_recv)) : (void)0)
943
944 retry:
945
946 if (!ss || !sip || 300 <= status)
947 /* Xyzzy */;
948 else if (!session_get_description(sip, &sdp, &len))
949 /* No SDP */;
950 else if (cr->cr_answer_recv) {
951 if (cr->cr_answer_recv > status) {
952 LOG3("status is older than previous answer, ignoring")((((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__, 952, "nua(%p): %s: %s %s in %u %s (%u)\n"
, (void *)nh, cr->cr_method_name, ("status is older than previous answer, ignoring"
), received ? received : "SDP", status, phrase, cr->cr_answer_recv
)) : (void)0)
;
953 sdp = NULL((void*)0);
954 return 0;
955 } else {
956 // we need to make sure its *actually* a dup, so we can't assume for now.
957 LOG3("multiple answers received, 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)) >= 3 ? (_su_llog((nua_log), 3, "nua_session.c"
, (const char *)__func__, 957, "nua(%p): %s: %s %s in %u %s (%u)\n"
, (void *)nh, cr->cr_method_name, ("multiple answers received, processing"
), received ? received : "SDP", status, phrase, cr->cr_answer_recv
)) : (void)0)
;
958 cr->cr_answer_recv = 0;
959 goto retry;
960 }
961 }
962 else if (cr->cr_offer_sent) {
963 /* case 1: answer to our offer */
964 cr->cr_answer_recv = status;
965 received = Answer;
966
967 if (nh->nh_soa == NULL((void*)0))
968 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__, 968, "nua(%p): %s: %s %s in %u %s (%u)\n"
, (void *)nh, cr->cr_method_name, ("got SDP"), received, status
, phrase, cr->cr_answer_recv)) : (void)0)
;
969 else if (soa_set_remote_sdp(nh->nh_soa, NULL((void*)0), sdp, len) < 0) {
970 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__, 970, "nua(%p): %s: %s %s in %u %s (%u)\n"
, (void *)nh, cr->cr_method_name, ("error parsing SDP"), received
? received : "SDP", status, phrase, cr->cr_answer_recv)) :
(void)0)
;
971 sdp = NULL((void*)0);
972 cr->cr_graceful = 1;
973 ss->ss_reason = "SIP;cause=400;text=\"Malformed Session Description\"";
974 }
975 else if (soa_process_answer(nh->nh_soa, NULL((void*)0)) < 0) {
976 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__, 976, "nua(%p): %s: %s %s in %u %s (%u)\n"
, (void *)nh, cr->cr_method_name, ("error processing SDP")
, received, status, phrase, cr->cr_answer_recv)) : (void)0
)
;
977 /* XXX */
978 sdp = NULL((void*)0);
979 }
980 else if (soa_activate(nh->nh_soa, NULL((void*)0)) < 0) {
981 /* XXX - what about errors? */
982 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__, 982, "nua(%p): %s: %s %s in %u %s (%u)\n"
, (void *)nh, cr->cr_method_name, ("error activating media after"
), received ? received : "SDP", status, phrase, cr->cr_answer_recv
)) : (void)0)
;
983 }
984 else {
985 ss->ss_sdp_version = soa_get_user_version(nh->nh_soa);
986 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__, 986, "nua(%p): %s: %s %s in %u %s (%u)\n"
, (void *)nh, cr->cr_method_name, ("processed SDP"), received
, status, phrase, cr->cr_answer_recv)) : (void)0)
;
987 }
988 }
989 else if (cr->cr_method != sip_method_invite) {
990 /* If non-invite request did not have offer, ignore SDP in response */
991 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__, 991, "nua(%p): %s: %s %s in %u %s (%u)\n"
, (void *)nh, cr->cr_method_name, ("ignoring extra"), received
? received : "SDP", status, phrase, cr->cr_answer_recv)) :
(void)0)
;
992 sdp = NULL((void*)0);
993 }
994 else {
995 /* case 2: new offer */
996 cr->cr_offer_recv = 1, cr->cr_answer_sent = 0;
997 received = Offer;
998
999 if (nh->nh_soa && soa_set_remote_sdp(nh->nh_soa, NULL((void*)0), sdp, len) < 0) {
1000 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__, 1000, "nua(%p): %s: %s %s in %u %s (%u)\n"
, (void *)nh, cr->cr_method_name, ("error parsing SDP"), received
? received : "SDP", status, phrase, cr->cr_answer_recv)) :
(void)0)
;
1001 sdp = NULL((void*)0);
1002 cr->cr_graceful = 1;
1003 ss->ss_reason = "SIP;cause=400;text=\"Malformed Session Description\"";
1004 }
1005 else
1006 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__, 1006, "nua(%p): %s: %s %s in %u %s (%u)\n"
, (void *)nh, cr->cr_method_name, ("got SDP"), received, status
, phrase, cr->cr_answer_recv)) : (void)0)
;
1007 }
1008
1009 if (ss && received)
1010 ss->ss_oa_recv = received;
1011
1012 if (sdp && nh->nh_soa)
1013 return nua_base_client_tresponse(cr, status, phrase, sip,
1014 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))
,
1015 TAG_END()(tag_type_t)0, (tag_value_t)0);
1016 else
1017 return nua_base_client_response(cr, status, phrase, sip, NULL((void*)0));
1018}
1019
1020static int nua_invite_client_report(nua_client_request_t *cr,
1021 int status, char const *phrase,
1022 sip_t const *sip,
1023 nta_outgoing_t *orq,
1024 tagi_t const *tags)
1025{
1026 nua_handle_t *nh = cr->cr_owner;
1027 nua_dialog_state_t *ds = nh->nh_ds;
1028 nua_dialog_usage_t *du = cr->cr_usage;
1029 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
1030 msg_t *response = nta_outgoing_getresponse(orq);
1031 unsigned next_state;
1032 int error;
1033
1034 nh_referral_respond(nh, status, phrase); /* XXX - restarting after 401/407 */
1035
1036 nua_stack_event(nh->nh_nua, nh,
1037 response,
1038 (enum nua_event_e)cr->cr_event,
1039 status, phrase,
1040 tags);
1041
1042 if (cr->cr_waiting)
1043 /* Do not report call state change if waiting for restart */
1044 return 1;
1045
1046 if (ss == NULL((void*)0)) {
1047 signal_call_state_change(nh, ss, status, phrase, nua_callstate_terminated);
1048 return 1;
1049 }
1050
1051 ss->ss_reporting = 1;
1052
1053 if (cr->cr_neutral) {
1054 signal_call_state_change(nh, ss, status, phrase, ss->ss_state);
1055 ss->ss_reporting = 0;
1056 return 1;
1057 }
1058
1059 response = msg_ref_create(response); /* Keep reference to contents of sip */
1060
1061 if (orq != cr->cr_orq && cr->cr_orq) { /* Being restarted */
1062 next_state = nua_callstate_calling;
1063 }
1064 else if (status == 100) {
1065 next_state = nua_callstate_calling;
1066 }
1067 else if (status < 300 && cr->cr_graceful) {
1068 next_state = nua_callstate_terminating;
1069 if (200 <= status) {
1070 nua_invite_client_ack(cr, NULL((void*)0));
1071 }
1072 }
1073 else if (status < 200) {
1074 next_state = nua_callstate_proceeding;
1075
1076 if (sip && sip->sip_rseq &&
1077 !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)
) {
1078 sip_rack_t rack[1];
1079
1080 sip_rack_init(rack);
1081 rack->ra_response = sip->sip_rseq->rs_response;
1082 rack->ra_cseq = sip->sip_cseq->cs_seq;
1083 rack->ra_method = sip->sip_cseq->cs_method;
1084 rack->ra_method_name = sip->sip_cseq->cs_method_name;
1085
1086 error = nua_client_tcreate(nh, nua_r_prack, &nua_prack_client_methods,
1087 SIPTAG_RACK(rack)siptag_rack, siptag_rack_v(rack),
1088 TAG_END()(tag_type_t)0, (tag_value_t)0);
1089 if (error < 0) {
1090 cr->cr_graceful = 1;
1091 next_state = nua_callstate_terminating;
1092 }
1093 }
1094 }
1095 else if (status < 300) {
1096 next_state = nua_callstate_completing;
1097 }
1098 else if (cr->cr_terminated) {
1099 next_state = nua_callstate_terminated;
1100 }
1101 else if (cr->cr_graceful && ss->ss_state >= nua_callstate_completing) {
1102 next_state = nua_callstate_terminating;
1103 }
1104 else {
1105 next_state = nua_callstate_init;
1106 }
1107
1108 if (next_state == nua_callstate_calling) {
1109 if (sip && sip->sip_status && sip->sip_status->st_status == 100) {
1110 ss->ss_reporting = 0;
1111 return 1;
1112 }
1113 }
1114
1115 if (next_state == nua_callstate_completing) {
1116 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)
||
1117 /* Auto-ACK response to re-INVITE when media is enabled
1118 and auto_ack is not set to 0 on handle */
1119 (ss->ss_state == nua_callstate_ready && nh->nh_soa &&
1120 !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
)
)) {
1121 nua_client_request_t *cru;
1122
1123 for (cru = ds->ds_cr; cru; cru = cru->cr_next) {
1124 if (cr != cru && cru->cr_offer_sent && !cru->cr_answer_recv)
1125 break;
1126 }
1127
1128 if (cru)
1129 /* A final response to UPDATE or PRACK with answer on its way? */;
1130 else if (nua_invite_client_ack(cr, NULL((void*)0)) > 0)
1131 next_state = nua_callstate_ready;
1132 else
1133 next_state = nua_callstate_terminating;
1134 }
1135 }
1136
1137 if (next_state == nua_callstate_terminating) {
1138 /* Send BYE or CANCEL */
1139 /* XXX - Forking - send BYE to early dialog?? */
1140 if (ss->ss_state > nua_callstate_proceeding || status >= 200)
1141 error = nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL((void*)0));
1142 else
1143 error = nua_client_create(nh, nua_r_cancel,
1144 &nua_cancel_client_methods, tags);
1145
1146 if (error) {
1147 next_state = nua_callstate_terminated;
1148 cr->cr_terminated = 1;
1149 }
1150 cr->cr_graceful = 0;
1151 }
1152
1153 ss->ss_reporting = 0;
1154
1155 signal_call_state_change(nh, ss, status, phrase, (enum nua_callstate)next_state);
1156
1157 msg_destroy(response);
1158
1159 return 1;
1160}
1161
1162/**@fn void nua_ack(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
1163 *
1164 * Acknowledge a succesful response to INVITE request.
1165 *
1166 * Acknowledge a successful response (200..299) to INVITE request with the
1167 * SIP ACK request message. This function is needed only if NUTAG_AUTOACK()
1168 * parameter has been cleared.
1169 *
1170 * @param nh Pointer to operation handle
1171 * @param tag, value, ... List of tagged parameters
1172 *
1173 * @return
1174 * nothing
1175 *
1176 * @par Related Tags:
1177 * Header tags defined in <sofia-sip/sip_tag.h>
1178 *
1179 * @par Events:
1180 * #nua_i_media_error \n
1181 * #nua_i_state (#nua_i_active, #nua_i_terminated)
1182 *
1183 * @sa NUTAG_AUTOACK(), @ref nua_call_model, #nua_i_state
1184 */
1185
1186int nua_stack_ack(nua_t *nua, nua_handle_t *nh, nua_event_t e,
1187 tagi_t const *tags)
1188{
1189 nua_dialog_usage_t *du = nua_dialog_usage_for_session(nh->nh_ds);
1190 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
1191 nua_client_request_t *cr = du ? du->du_cr : NULL((void*)0);
1192 int error;
1193
1194 if (!cr || cr->cr_orq == NULL((void*)0) || cr->cr_status < 200) {
1195 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))
;
1196 return 1;
1197 }
1198
1199 if (tags)
1200 nua_stack_set_params(nua, nh, nua_i_error, tags);
1201
1202 nua_client_request_ref(cr);
1203 error = nua_invite_client_ack(cr, tags);
1204
1205 if (error < 0) {
1206 if (ss->ss_reason == NULL((void*)0))
1207 ss->ss_reason = "SIP;cause=500;text=\"Internal Error\"";
1208 ss->ss_reporting = 1; /* We report terminated state here if BYE fails */
1209 error = nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL((void*)0));
1210 ss->ss_reporting = 0;
1211 signal_call_state_change(nh, ss, 500, "Internal Error",
1212 error
1213 ? nua_callstate_terminated
1214 : nua_callstate_terminating);
1215 }
1216 else if (ss)
1217 signal_call_state_change(nh, ss, 200, "ACK sent", nua_callstate_ready);
1218
1219 nua_client_request_unref(cr);
1220
1221 return 0;
1222}
1223
1224/** Send ACK, destroy INVITE transaction.
1225 *
1226 * @retval 1 if successful
1227 * @retval < 0 if an error occurred
1228 */
1229static
1230int nua_invite_client_ack(nua_client_request_t *cr, tagi_t const *tags)
1231{
1232 nua_handle_t *nh = cr->cr_owner;
1233 nua_dialog_state_t *ds = nh->nh_ds;
1234 nua_session_usage_t *ss = nua_dialog_usage_private(cr->cr_usage)((cr->cr_usage) ? (void*)((cr->cr_usage) + 1) : ((void*
)0))
;
1235
1236 msg_t *msg;
1237 sip_t *sip;
1238 int error = -1;
1239 sip_authorization_t *wa;
1240 sip_proxy_authorization_t *pa;
1241 sip_cseq_t *cseq;
1242 int proxy_is_set;
1243 url_string_t *proxy;
1244 nta_outgoing_t *ack;
1245 int status = 200;
1246 char const *phrase = "OK", *reason = NULL((void*)0);
1247 char const *invite_branch;
1248 char const *pl_s = NULL((void*)0);
1249
1250 assert(cr->cr_orq)((void) sizeof ((cr->cr_orq) ? 1 : 0), __extension__ ({ if
(cr->cr_orq) ; else __assert_fail ("cr->cr_orq", "nua_session.c"
, 1250, __extension__ __PRETTY_FUNCTION__); }))
;
1251 assert(cr->cr_method == sip_method_invite)((void) sizeof ((cr->cr_method == sip_method_invite) ? 1 :
0), __extension__ ({ if (cr->cr_method == sip_method_invite
) ; else __assert_fail ("cr->cr_method == sip_method_invite"
, "nua_session.c", 1251, __extension__ __PRETTY_FUNCTION__); }
))
;
1252
1253 cr->cr_initial = 0;
1254
1255 if (!ds->ds_leg) {
1256 /* XXX - fix nua_dialog_usage_remove_at() instead! */
1257 goto error;
1258 }
1259
1260 tl_gets(tags,
1261 SIPTAG_PAYLOAD_STR_REF(pl_s)siptag_payload_str_ref, tag_str_vr(&(pl_s)),
1262 TAG_END()(tag_type_t)0, (tag_value_t)0);
1263
1264
1265 assert(ds->ds_leg)((void) sizeof ((ds->ds_leg) ? 1 : 0), __extension__ ({ if
(ds->ds_leg) ; else __assert_fail ("ds->ds_leg", "nua_session.c"
, 1265, __extension__ __PRETTY_FUNCTION__); }))
;
1266
1267 msg = nta_outgoing_getrequest(cr->cr_orq);
1268 sip = sip_object(msg);
1269 if (!msg)
1270 goto error;
1271 invite_branch = nta_outgoing_branch(cr->cr_orq);
1272
1273 wa = sip_authorization(sip)((sip_authorization_t *)msg_header_access((msg_pub_t*)(sip), sip_authorization_class
))
;
1274 pa = sip_proxy_authorization(sip)((sip_proxy_authorization_t *)msg_header_access((msg_pub_t*)(
sip), sip_proxy_authorization_class))
;
1275
1276 msg_destroy(msg);
1277
1278 msg = nta_msg_create(nh->nh_nua->nua_nta, 0);
1279 sip = sip_object(msg);
1280 if (!msg)
1281 goto error;
1282
1283 cseq = sip_cseq_create(msg_home(msg)((su_home_t*)(msg)), cr->cr_seq, SIP_METHOD_ACKsip_method_ack, "ACK");
1284
1285 if (!cseq)
1286 ;
1287 else if (nh->nh_tags && sip_add_tl(msg, sip, TAG_NEXT(nh->nh_tags)tag_next, (tag_value_t)(nh->nh_tags)) < 0)
1288 ;
1289 else if (tags && sip_add_tl(msg, sip, TAG_NEXT(tags)tag_next, (tag_value_t)(tags)) < 0)
1290 ;
1291 else if (wa && sip_add_dup(msg, sip, (sip_header_t *)wa) < 0)
1292 ;
1293 else if (pa && sip_add_dup(msg, sip, (sip_header_t *)pa) < 0)
1294 ;
1295 else if (sip_header_insert(msg, sip, (sip_header_t *)cseq) < 0)
1296 ;
1297 else if (nta_msg_request_complete(msg, ds->ds_leg, SIP_METHOD_ACKsip_method_ack, "ACK", NULL((void*)0)) < 0)
1298 ;
1299 else {
1300 /* Remove extra headers */
1301 while (sip->sip_allow)
1302 sip_header_remove(msg, sip, (sip_header_t*)sip->sip_allow);
1303 while (sip->sip_priority)
1304 sip_header_remove(msg, sip, (sip_header_t*)sip->sip_priority);
1305 while (sip->sip_proxy_require)
1306 sip_header_remove(msg, sip, (sip_header_t*)sip->sip_proxy_require);
1307 while (sip->sip_require)
1308 sip_header_remove(msg, sip, (sip_header_t*)sip->sip_require);
1309 while (sip->sip_subject)
1310 sip_header_remove(msg, sip, (sip_header_t*)sip->sip_subject);
1311 while (sip->sip_supported)
1312 sip_header_remove(msg, sip, (sip_header_t*)sip->sip_supported);
1313
1314 if (ss == NULL((void*)0) || ss->ss_state > nua_callstate_ready || pl_s)
1315 ;
1316 else if (cr->cr_offer_recv && !cr->cr_answer_sent) {
1317 if (nh->nh_soa == NULL((void*)0)) {
1318 if (session_get_description(sip, NULL((void*)0), NULL((void*)0)))
1319 cr->cr_answer_sent = 1, ss->ss_oa_sent = Answer;
1320 }
1321 else if (soa_generate_answer(nh->nh_soa, NULL((void*)0)) < 0 ||
1322 session_include_description(nh->nh_soa, 1, msg, sip) < 0) {
1323 status = 900, phrase = "Internal media error";
1324 reason = "SIP;cause=500;text=\"Internal media error\"";
1325 /* reason = soa_error_as_sip_reason(nh->nh_soa); */
1326 }
1327 else {
1328 cr->cr_answer_sent = 1, ss->ss_oa_sent = Answer;
1329 }
1330 }
1331
1332 if (ss == NULL((void*)0) || ss->ss_state > nua_callstate_ready || reason)
1333 ;
1334 else if (nh->nh_soa && soa_is_complete(nh->nh_soa)) {
1335 /* signal SOA that O/A round(s) is (are) complete */
1336 if (soa_activate(nh->nh_soa, NULL((void*)0)) >= 0) {
1337 ss->ss_sdp_version = soa_get_user_version(nh->nh_soa);
1338 }
1339 }
1340 else if (nh->nh_soa == NULL((void*)0)
1341 /* NUA does not necessarily know dirty details */
1342 /* && !(cr->cr_offer_sent && !cr->cr_answer_recv) */) {
1343 ;
1344 }
1345 else {
1346 nua_client_request_t *cru;
1347
1348 /* Final response to UPDATE or PRACK may be on its way ... */
1349 for (cru = ds->ds_cr; cru; cru = cru->cr_next) {
1350 if (cr != cru && cru->cr_offer_sent && !cru->cr_answer_recv)
1351 break;
1352 }
1353
1354 if (cru == NULL((void*)0)) {
1355 /* No SDP answer -> terminate call */
1356 status = 988, phrase = "Incomplete offer/answer";
1357 reason = "SIP;cause=488;text=\"Incomplete offer/answer\"";
1358 }
1359 }
1360
1361 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
)
;
1362 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)
;
1363
1364 if ((ack = nta_outgoing_mcreate(nh->nh_nua->nua_nta, NULL((void*)0), NULL((void*)0), NULL((void*)0),
1365 msg,
1366 NTATAG_ACK_BRANCH(invite_branch)ntatag_ack_branch, tag_str_v((invite_branch)),
1367 TAG_IF(proxy_is_set,!(proxy_is_set) ? tag_skip : ntatag_default_proxy, urltag_url_v
((proxy))
1368 NTATAG_DEFAULT_PROXY(proxy))!(proxy_is_set) ? tag_skip : ntatag_default_proxy, urltag_url_v
((proxy))
,
1369 SIPTAG_END()siptag_end, (tag_value_t)0,
1370 TAG_NEXT(tags)tag_next, (tag_value_t)(tags)))) {
1371 /* TR engine keeps this around for T2 so it catches all 2XX retransmissions */
1372 nta_outgoing_destroy(ack);
1373
1374 if (nh->nh_soa && reason && ss && ss->ss_state <= nua_callstate_ready)
1375 nua_stack_event(nh->nh_nua, nh, NULL((void*)0),
1376 nua_i_media_error, status, phrase,
1377 NULL((void*)0));
1378 }
1379 else if (!reason) {
1380 status = 900, phrase = "Cannot send ACK";
1381 reason = "SIP;cause=500;text=\"Internal Error\"";
1382 }
1383
1384 if (ss && reason)
1385 ss->ss_reason = reason;
1386
1387 if (status < 300)
1388 error = 1;
1389 else
1390 error = -2;
1391 }
1392
1393 if (error == -1)
1394 msg_destroy(msg);
1395
1396 error:
1397 cr->cr_acked = 1; /* ... or we have at least tried */
1398
1399 nua_client_request_remove(cr);
1400 nua_client_request_clean(cr);
1401
1402 return error;
1403}
1404
1405static int
1406nua_invite_client_should_ack(nua_client_request_t const *cr)
1407{
1408 return
1409 cr && cr->cr_orq && !cr->cr_acked &&
1410 200 <= cr->cr_status && cr->cr_status < 300;
1411}
1412
1413/** Complete client request */
1414static int nua_invite_client_complete(nua_client_request_t *cr)
1415{
1416 if (cr->cr_orq == NULL((void*)0))
1417 /* Xyzzy */;
1418 else if (cr->cr_status < 200)
1419 nta_outgoing_cancel(cr->cr_orq);
1420 else if (cr->cr_status < 300 && !cr->cr_acked)
1421 nua_invite_client_ack(cr, NULL((void*)0));
1422
1423 return 0;
1424}
1425
1426/**@fn void nua_cancel(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
1427 *
1428 * Cancel an INVITE operation
1429 *
1430 * @param nh Pointer to operation handle
1431 * @param tag, value, ... List of tagged parameters
1432 *
1433 * @return
1434 * nothing
1435 *
1436 * @par Related Tags:
1437 * Header tags defined in <sofia-sip/sip_tag.h>
1438 *
1439 * @par Events:
1440 * #nua_r_cancel, #nua_i_state (#nua_i_active, #nua_i_terminated)
1441 *
1442 * @sa @ref nua_call_model, nua_invite(), #nua_i_cancel
1443 */
1444
1445static int nua_cancel_client_request(nua_client_request_t *cr,
1446 msg_t *msg, sip_t *sip,
1447 tagi_t const *tags);
1448static int nua_cancel_client_check_restart(nua_client_request_t *cr,
1449 int status,
1450 char const *phrase,
1451 sip_t const *sip);
1452
1453nua_client_methods_t const nua_cancel_client_methods = {
1454 SIP_METHOD_CANCELsip_method_cancel, "CANCEL", /* crm_method, crm_method_name */
1455 0, /* crm_extra */
1456 { /* crm_flags */
1457 /* create_dialog */ 0,
1458 /* in_dialog */ 1,
1459 /* target refresh */ 0
1460 },
1461 NULL((void*)0), /* crm_template */
1462 NULL((void*)0), /* crm_init */
1463 nua_cancel_client_request, /* .. not really crm_send */
1464 nua_cancel_client_check_restart, /* crm_check_restart */
1465 NULL((void*)0), /* crm_recv */
1466 NULL((void*)0), /* crm_preliminary */
1467 NULL((void*)0), /* crm_report */
1468 NULL((void*)0), /* crm_complete */
1469};
1470
1471int nua_stack_cancel(nua_t *nua, nua_handle_t *nh, nua_event_t e,
1472 tagi_t const *tags)
1473{
1474 return nua_client_create(nh, e, &nua_cancel_client_methods, tags);
1475}
1476
1477static int nua_cancel_client_request(nua_client_request_t *cr,
1478 msg_t *msg, sip_t *sip,
1479 tagi_t const *tags)
1480{
1481 nua_handle_t *nh = cr->cr_owner;
1482 nua_dialog_usage_t *du = nua_dialog_usage_for_session(nh->nh_ds);
1483
1484 if (!du || !du->du_cr || !du->du_cr->cr_orq ||
1485 nta_outgoing_status(du->du_cr->cr_orq) >= 200) {
1486 return nua_client_return(cr, 481, "No transaction to CANCEL", msg);
1487 }
1488
1489 assert(cr->cr_orq == NULL)((void) sizeof ((cr->cr_orq == ((void*)0)) ? 1 : 0), __extension__
({ if (cr->cr_orq == ((void*)0)) ; else __assert_fail ("cr->cr_orq == NULL"
, "nua_session.c", 1489, __extension__ __PRETTY_FUNCTION__); }
))
;
1490
1491 cr->cr_orq = nta_outgoing_tcancel(du->du_cr->cr_orq,
1492 nua_client_orq_response,
1493 nua_client_request_ref(cr),
1494 TAG_NEXT(tags)tag_next, (tag_value_t)(tags));
1495
1496 if (cr->cr_orq == NULL((void*)0)) {
1497 nua_client_request_unref(cr);
1498 return -1;
1499 }
1500
1501 return 0;
1502}
1503
1504static int
1505nua_cancel_client_check_restart(nua_client_request_t *cr,
1506 int status,
1507 char const *phrase,
1508 sip_t const *sip)
1509{
1510 /* We cannot really restart CANCEL */
1511 return 0;
1512}
1513
1514/** @NUA_EVENT nua_r_cancel
1515 *
1516 * Answer to outgoing CANCEL.
1517 *
1518 * The CANCEL may be sent explicitly by nua_cancel() or implicitly by NUA
1519 * state machine.
1520 *
1521 * @param status response status code
1522 * @param phrase a short textual description of @a status code
1523 * @param nh operation handle associated with the call
1524 * @param hmagic application context associated with the call
1525 * @param sip response to CANCEL request or NULL upon an error
1526 * (status code is in @a status and
1527 * descriptive message in @a phrase parameters)
1528 * @param tags empty
1529 *
1530 * @sa nua_cancel(), @ref nua_uac_call_model, #nua_r_invite, nua_invite(),
1531 * #nua_i_state
1532 *
1533 * @END_NUA_EVENT
1534 */
1535
1536static void nua_session_usage_refresh(nua_handle_t *nh,
1537 nua_dialog_state_t *ds,
1538 nua_dialog_usage_t *du,
1539 sip_time_t now)
1540{
1541 nua_session_usage_t *ss = NUA_DIALOG_USAGE_PRIVATE(du)((void *)((du) + 1));
1542 nua_client_request_t const *cr = du->du_cr;
1543 nua_server_request_t const *sr;
1544
1545 if (ss->ss_state >= nua_callstate_terminating ||
1546 /* INVITE is in progress or being authenticated */
1547 nua_client_request_in_progress(cr))
1548 return;
1549
1550 if (ds->ds_cr) return; /* request queued */
1551
1552 /* UPDATE has been queued */
1553 //for (cr = ds->ds_cr; cr; cr = cr->cr_next)
1554 //if (cr->cr_method == sip_method_update)
1555 // return;
1556
1557 /* INVITE or UPDATE in progress on server side */
1558 for (sr = ds->ds_sr; sr; sr = sr->sr_next)
1559 if (sr->sr_usage == du &&
1560 (sr->sr_method == sip_method_invite ||
1561 sr->sr_method == sip_method_update))
1562 return;
1563
1564 if (ss->ss_timer->refresher == nua_remote_refresher) {
1565 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__, 1565, "nua(%p): session almost expired, sending BYE before timeout.\n"
, (void *)nh)) : (void)0)
;
1566 ss->ss_reason = "SIP;cause=408;text=\"Session timeout\"";
1567 nua_stack_bye(nh->nh_nua, nh, nua_r_bye, NULL((void*)0));
1568 return;
1569 }
1570 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)
) {
1571 nua_stack_update(nh->nh_nua, nh, nua_r_update, NULL((void*)0));
1572 }
1573 else if (du->du_cr) {
1574 nua_client_resend_request(du->du_cr, 0);
1575 }
1576 else {
1577 nua_stack_invite(nh->nh_nua, nh, nua_r_invite, NULL((void*)0));
1578 }
1579}
1580
1581/** @interal Shut down session usage.
1582 *
1583 * @retval >0 shutdown done
1584 * @retval 0 shutdown in progress
1585 * @retval <0 try again later
1586 */
1587static int nua_session_usage_shutdown(nua_handle_t *nh,
1588 nua_dialog_state_t *ds,
1589 nua_dialog_usage_t *du)
1590{
1591 nua_session_usage_t *ss = NUA_DIALOG_USAGE_PRIVATE(du)((void *)((du) + 1));
1592 nua_server_request_t *sr, *sr_next;
1593 nua_client_request_t *cri;
1594
1595 assert(ss == nua_session_usage_for_dialog(nh->nh_ds))((void) sizeof ((ss == nua_session_usage_for_dialog(nh->nh_ds
)) ? 1 : 0), __extension__ ({ if (ss == nua_session_usage_for_dialog
(nh->nh_ds)) ; else __assert_fail ("ss == nua_session_usage_for_dialog(nh->nh_ds)"
, "nua_session.c", 1595, __extension__ __PRETTY_FUNCTION__); }
))
;
1596
1597 /* Zap server-side transactions */
1598 for (sr = ds->ds_sr; sr; sr = sr_next) {
1599 sr_next = sr->sr_next;
1600 if (sr->sr_usage == du) {
1601 assert(sr->sr_usage == du)((void) sizeof ((sr->sr_usage == du) ? 1 : 0), __extension__
({ if (sr->sr_usage == du) ; else __assert_fail ("sr->sr_usage == du"
, "nua_session.c", 1601, __extension__ __PRETTY_FUNCTION__); }
))
;
1602 sr->sr_usage = NULL((void*)0);
1603
1604 if (nua_server_request_is_pending(sr)) {
1605 SR_STATUS1(sr, SIP_480_TEMPORARILY_UNAVAILABLE)sr_status(sr, 480, sip_480_Temporarily_unavailable);
1606 nua_server_respond(sr, NULL((void*)0));
1607 if (nua_server_report(sr) >= 2)
1608 return 480;
1609 }
1610 else
1611 nua_server_request_destroy(sr);
1612 }
1613 }
1614
1615 cri = du->du_cr;
1616
1617 switch (ss->ss_state) {
1618 case nua_callstate_calling:
1619 case nua_callstate_proceeding:
1620 return nua_client_create(nh, nua_r_cancel, &nua_cancel_client_methods, NULL((void*)0));
1621
1622 case nua_callstate_completing:
1623 case nua_callstate_completed:
1624 case nua_callstate_ready:
1625 if (cri && cri->cr_orq) {
1626 if (cri->cr_status < 200) {
1627 nua_client_create(nh, nua_r_cancel, &nua_cancel_client_methods, NULL((void*)0));
1628 }
1629 else if (cri->cr_status < 300 && !cri->cr_acked) {
1630 nua_invite_client_ack(cri, NULL((void*)0));
1631 }
1632 }
1633 if (nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL((void*)0)) != 0)
1634 break;
1635
1636 signal_call_state_change(nh, ss, 487, "BYE sent",
1637 nua_callstate_terminating);
1638 return 0;
1639
1640 case nua_callstate_terminating:
1641 case nua_callstate_terminated: /* XXX */
1642 return 0;
1643
1644 default:
1645 break;
1646 }
1647
1648 nua_dialog_usage_remove(nh, ds, du, NULL((void*)0), NULL((void*)0));
1649
1650 return 200;
1651}
1652
1653/**@fn void nua_prack(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
1654 * Send a PRACK request.
1655 *
1656 * PRACK is used to acknowledge receipt of 100rel responses. See @RFC3262.
1657 *
1658 * @param nh Pointer to operation handle
1659 * @param tag, value, ... List of tagged parameters
1660 *
1661 * @return
1662 * nothing
1663 *
1664 * @par Related Tags:
1665 * Tags in <sofia-sip/soa_tag.h>, <sofia-sip/sip_tag.h>.
1666 *
1667 * @par Events:
1668 * #nua_r_prack
1669 */
1670
1671/** @NUA_EVENT nua_r_prack
1672 *
1673 * Response to an outgoing @b PRACK request. PRACK request is used to
1674 * acknowledge reliable preliminary responses and it is usually sent
1675 * automatically by the nua stack.
1676 *
1677 * @param status response status code
1678 * (if the request is retried, @a status is 100, the @a
1679 * sip->sip_status->st_status contain the real status code
1680 * from the response message, e.g., 302, 401, or 407)
1681 * @param phrase a short textual description of @a status code
1682 * @param nh operation handle associated with the call
1683 * @param hmagic application context associated with the call
1684 * @param sip response to @b PRACK or NULL upon an error
1685 * (status code is in @a status and
1686 * descriptive message in @a phrase parameters)
1687 * @param tags empty
1688 *
1689 * @sa nua_prack(), #nua_i_prack, @RFC3262
1690 *
1691 * @END_NUA_EVENT
1692 */
1693
1694static int nua_prack_client_init(nua_client_request_t *cr,
1695 msg_t *msg, sip_t *sip,
1696 tagi_t const *tags);
1697static int nua_prack_client_request(nua_client_request_t *cr,
1698 msg_t *msg, sip_t *sip,
1699 tagi_t const *tags);
1700static int nua_prack_client_response(nua_client_request_t *cr,
1701 int status, char const *phrase,
1702 sip_t const *sip);
1703static int nua_prack_client_report(nua_client_request_t *cr,
1704 int status, char const *phrase,
1705 sip_t const *sip,
1706 nta_outgoing_t *orq,
1707 tagi_t const *tags);
1708
1709nua_client_methods_t const nua_prack_client_methods = {
1710 SIP_METHOD_PRACKsip_method_prack, "PRACK", /* crm_method, crm_method_name */
1711 0, /* crm_extra */
1712 { /* crm_flags */
1713 /* create_dialog */ 0,
1714 /* in_dialog */ 1,
1715 /* target refresh */ 0
1716 },
1717 NULL((void*)0), /* crm_template */
1718 nua_prack_client_init, /* crm_init */
1719 nua_prack_client_request, /* crm_send */
1720 NULL((void*)0), /* crm_check_restart */
1721 nua_prack_client_response, /* crm_recv */
1722 NULL((void*)0), /* crm_preliminary */
1723 nua_prack_client_report, /* crm_report */
1724 NULL((void*)0), /* crm_complete */
1725};
1726
1727int nua_stack_prack(nua_t *nua, nua_handle_t *nh, nua_event_t e,
1728 tagi_t const *tags)
1729{
1730 return nua_client_create(nh, e, &nua_prack_client_methods, tags);
1731}
1732
1733static int nua_prack_client_init(nua_client_request_t *cr,
1734 msg_t *msg, sip_t *sip,
1735 tagi_t const *tags)
1736{
1737 nua_handle_t *nh = cr->cr_owner;
1738 nua_dialog_usage_t *du = nua_dialog_usage_for_session(nh->nh_ds);
1739
1740 cr->cr_usage = du;
1741
1742 return 0;
1743}
1744
1745static int nua_prack_client_request(nua_client_request_t *cr,
1746 msg_t *msg, sip_t *sip,
1747 tagi_t const *tags)
1748{
1749 nua_handle_t *nh = cr->cr_owner;
1750 nua_dialog_usage_t *du = cr->cr_usage;
1751 nua_session_usage_t *ss;
1752 nua_client_request_t *cri;
1753 int offer_sent = 0, answer_sent = 0, retval;
1754 int status = 0; char const *phrase = "PRACK Sent";
1755 //uint32_t rseq = 0;
1756
1757 if (du == NULL((void*)0)) /* Call terminated */
1758 return nua_client_return(cr, SIP_481_NO_TRANSACTION481, sip_481_No_transaction, msg);
1759
1760 ss = NUA_DIALOG_USAGE_PRIVATE(du)((void *)((du) + 1));
1761 if (ss->ss_state >= nua_callstate_terminating)
1762 return nua_client_return(cr, 900, "Session is terminating", msg);
1763
1764 cri = du->du_cr;
1765
1766// if (sip->sip_rack)
1767// rseq = sip->sip_rack->ra_response;
1768
1769 if (cri->cr_offer_recv && !cri->cr_answer_sent) {
1770 if (nh->nh_soa == NULL((void*)0))
1771 /* It is up to application to handle SDP */
1772 answer_sent = session_get_description(sip, NULL((void*)0), NULL((void*)0));
1773 else if (sip->sip_payload)
1774 /* XXX - we should just do MIME in session_include_description() */;
1775 else if (soa_generate_answer(nh->nh_soa, NULL((void*)0)) < 0 ||
1776 session_include_description(nh->nh_soa, 1, msg, sip) < 0) {
1777 status = soa_error_as_sip_response(nh->nh_soa, &phrase);
1778 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__, 1779, "nua(%p): local response to PRACK: %d %s\n"
, (void *)nh, status, phrase)) : (void)0)
1779 (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__, 1779, "nua(%p): local response to PRACK: %d %s\n"
, (void *)nh, status, phrase)) : (void)0)
;
1780 nua_stack_event(nh->nh_nua, nh, NULL((void*)0),
1781 nua_i_media_error, status, phrase,
1782 NULL((void*)0));
1783 return nua_client_return(cr, status, phrase, msg);
1784 }
1785 else {
1786 answer_sent = 1;
1787 if (soa_activate(nh->nh_soa, NULL((void*)0)) >= 0) {
1788 ss->ss_sdp_version = soa_get_user_version(nh->nh_soa);
1789 }
1790 }
1791 }
1792 else if (nh->nh_soa == NULL((void*)0)) {
1793 offer_sent = session_get_description(sip, NULL((void*)0), NULL((void*)0));
1794 }
1795 else {
1796 /* When 100rel response status was 183 do support for preconditions */
1797 int send_offer = ss->ss_precondition &&
1798 cri->cr_status == 183 && cri->cr_offer_sent && cri->cr_answer_recv;
1799
1800 if (!send_offer) {
1801 tagi_t const *t = tl_find_last(tags, nutag_include_extra_sdp);
1802 send_offer = t && t->t_value;
1803 }
1804
1805 if (!send_offer) {
1806 }
1807 else if (soa_generate_offer(nh->nh_soa, 0, NULL((void*)0)) >= 0 &&
1808 session_include_description(nh->nh_soa, 1, msg, sip) >= 0) {
1809 offer_sent = 1;
1810 }
1811 else {
1812 status = soa_error_as_sip_response(nh->nh_soa, &phrase);
1813 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__, 1814, "nua(%p): PRACK offer: %d %s\n"
, (void *)nh, status, phrase)) : (void)0)
1814 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__, 1814, "nua(%p): PRACK offer: %d %s\n"
, (void *)nh, status, phrase)) : (void)0)
;
1815 nua_stack_event(nh->nh_nua, nh, NULL((void*)0),
1816 nua_i_media_error, status, phrase, NULL((void*)0));
1817 return nua_client_return(cr, status, phrase, msg);
1818 }
1819 }
1820
1821 retval = nua_base_client_request(cr, msg, sip, NULL((void*)0));
1822
1823 if (retval == 0) {
1824 cr->cr_offer_sent = offer_sent;
1825 cr->cr_answer_sent = answer_sent;
1826
1827 if (offer_sent)
1828 ss->ss_oa_sent = Offer;
1829 else if (answer_sent)
1830 ss->ss_oa_sent = Answer;
1831
1832 if (cr->cr_restarting)
1833 /* Restart logic calls nua_prack_client_report */;
1834 else if (!cr->cr_auto && (!offer_sent || !answer_sent))
1835 /* Suppose application know it called nua_prack() */;
1836 else
1837 signal_call_state_change(nh, ss, status, phrase, ss->ss_state);
1838 }
1839
1840 return retval;
1841}
1842
1843static int nua_prack_client_response(nua_client_request_t *cr,
1844 int status, char const *phrase,
1845 sip_t const *sip)
1846{
1847 /* XXX - fatal error cases? */
1848
1849 return nua_session_client_response(cr, status, phrase, sip);
1850}
1851
1852static int nua_prack_client_report(nua_client_request_t *cr,
1853 int status, char const *phrase,
1854 sip_t const *sip,
1855 nta_outgoing_t *orq,
1856 tagi_t const *tags)
1857{
1858 nua_handle_t *nh = cr->cr_owner;
1859 nua_dialog_usage_t *du = cr->cr_usage;
1860 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
1861 int acked = 0;
1862
1863 nua_stack_event(nh->nh_nua, nh,
1864 nta_outgoing_getresponse(orq),
1865 (enum nua_event_e)cr->cr_event,
1866 status, phrase,
1867 tags);
1868
1869 if (!ss || cr->cr_terminated || cr->cr_graceful || cr->cr_waiting)
1870 return 1;
1871
1872 if (cr->cr_offer_sent || cr->cr_answer_sent) {
1873 unsigned next_state = ss->ss_state;
1874
1875 if (status < 200)
1876 ;
1877 else if (nua_invite_client_should_ack(du->du_cr)) {
1878 /* There is an un-ACK-ed INVITE there */
1879 assert(du->du_cr->cr_method == sip_method_invite)((void) sizeof ((du->du_cr->cr_method == sip_method_invite
) ? 1 : 0), __extension__ ({ if (du->du_cr->cr_method ==
sip_method_invite) ; else __assert_fail ("du->du_cr->cr_method == sip_method_invite"
, "nua_session.c", 1879, __extension__ __PRETTY_FUNCTION__); }
))
;
1880 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)
||
1881 /* Auto-ACK response to re-INVITE when media is enabled
1882 and auto_ack is not set to 0 on handle */
1883 (ss->ss_state == nua_callstate_ready && nh->nh_soa &&
1884 !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
)
)) {
1885 /* There should be no UPDATE with offer/answer
1886 if PRACK with offer/answer was ongoing! */
1887 if (nua_invite_client_ack(du->du_cr, NULL((void*)0)) > 0)
1888 next_state = nua_callstate_ready;
1889 else
1890 next_state = nua_callstate_terminating;
1891
1892 acked = 1;
1893 }
1894 }
1895
1896 signal_call_state_change(nh, ss, status, phrase, (enum nua_callstate)next_state);
1897 }
1898
1899 if (acked &&
1900 nua_client_is_queued(du->du_cr) &&
1901 du->du_cr->cr_method == sip_method_invite) {
1902 /* New INVITE was queued - do not send UPDATE */
1903 }
1904 else if (ss->ss_update_needed && 200 <= status && status < 300 &&
1905 !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)
)
1906 nua_client_create(nh, nua_r_update, &nua_update_client_methods, NULL((void*)0));
1907
1908 return 1;
1909}
1910
1911/* ---------------------------------------------------------------------- */
1912/* UAS side of INVITE */
1913
1914/** @NUA_EVENT nua_i_invite
1915 *
1916 * Indication of incoming call or re-INVITE request.
1917 *
1918 * @param status statuscode of response sent automatically by stack
1919 * @param phrase a short textual description of @a status code
1920 * @param nh operation handle associated with this call
1921 * (maybe created for this call)
1922 * @param hmagic application context associated with this call
1923 * (maybe NULL if call handle was created for this call)
1924 * @param sip incoming INVITE request
1925 * @param tags SOATAG_ACTIVE_AUDIO(), SOATAG_ACTIVE_VIDEO()
1926 *
1927 * @par
1928 * @par Responding to INVITE with nua_respond()
1929 *
1930 * If @a status in #nua_i_invite event is below 200, the application should
1931 * accept or reject the call with nua_respond(). See the @ref nua_call_model
1932 * for the detailed explanation of various options in call processing at
1933 * server end.
1934 *
1935 * The @b INVITE request takes care of session setup using SDP Offer-Answer
1936 * negotiation as specified in @RFC3264 (updated in @RFC3262 section 5,
1937 * @RFC3311, and @RFC3312). The Offer-Answer can be taken care by
1938 * application (if NUTAG_MEDIA_ENABLE(0) parameter has been set) or by the
1939 * built-in SDP Offer/Answer engine @soa (by default and when
1940 * NUTAG_MEDIA_ENABLE(1) parameter has been set). When @soa is enabled, it
1941 * will take care of parsing the SDP, negotiating the media and codecs, and
1942 * including the SDP in the SIP message bodies as required by the
1943 * Offer-Answer model.
1944 *
1945 * When @soa is enabled, the SDP in the incoming INVITE is parsed and feed
1946 * to a #soa_session_t object. The #nua_i_state event sent to the
1947 * application immediately after #nua_i_invite will contain the parsing
1948 * results in SOATAG_REMOTE_SDP() and SOATAG_REMOTE_SDP_STR() tags.
1949 *
1950 * Note that currently the parser within @nua does not handle MIME
1951 * multipart. The SDP Offer/Answer engine can get confused if the SDP offer
1952 * is included in a MIME multipart, therefore such an @b INVITE is rejected
1953 * with <i>415 Unsupported Media Type</i> error response: the client is
1954 * expected to retry the INVITE without MIME multipart content.
1955 *
1956 * If the call is to be accepted, the application should include the SDP in
1957 * the 2XX response. If @soa is not disabled with NUTAG_MEDIA_ENABLE(0), the
1958 * SDP should be included in the SOATAG_USER_SDP() or SOATAG_USER_SDP_STR()
1959 * parameter given to nua_respond(). If it is disabled, the SDP should be
1960 * included in the response message using SIPTAG_PAYLOAD() or
1961 * SIPTAG_PAYLOAD_STR(). Also, the @ContentType should be set using
1962 * SIPTAG_CONTENT_TYPE() or SIPTAG_CONTENT_TYPE_STR().
1963 *
1964 * @par Preliminary Responses and 100rel
1965 *
1966 * Call progress can be signaled with preliminary responses (with status
1967 * code in the range 101..199). It is possible to conclude the SDP
1968 * Offer-Answer negotiation using preliminary responses, too. If
1969 * NUTAG_EARLY_ANSWER(1), SOATAG_USER_SDP() or SOATAG_USER_SDP_STR()
1970 * parameter is included with in a preliminary nua_response(), the SDP
1971 * answer is generated and sent with the preliminary responses, too.
1972 *
1973 * The preliminary responses are sent reliably if feature tag "100rel" is
1974 * included in the @Require header of the response or if
1975 * NUTAG_EARLY_MEDIA(1) parameter has been given. The reliably delivery of
1976 * preliminary responses mean that a sequence number is included in the
1977 * @RSeq header in the response message and the response message is resent
1978 * until the client responds with a @b PRACK request with matching sequence
1979 * number in @RAck header.
1980 *
1981 * Note that only the "183" response is sent reliably if the
1982 * NUTAG_ONLY183_100REL(1) parameter has been given. The reliable
1983 * preliminary responses are acknowledged with @b PRACK request sent by the
1984 * client.
1985 *
1986 * Note if the SDP offer-answer is completed with the reliable preliminary
1987 * responses, the is no need to include SDP in 200 OK response (or other 2XX
1988 * response). However, it the tag NUTAG_INCLUDE_EXTRA_SDP(1) is included
1989 * with nua_respond(), a copy of the SDP answer generated earlier by @soa is
1990 * included as the message body.
1991 *
1992 * @sa nua_respond(), @ref nua_uas_call_model, #nua_i_state,
1993 * NUTAG_MEDIA_ENABLE(), SOATAG_USER_SDP(), SOATAG_USER_SDP_STR(),
1994 * @RFC3262, NUTAG_EARLY_ANSWER(), NUTAG_EARLY_MEDIA(),
1995 * NUTAG_ONLY183_100REL(),
1996 * NUTAG_INCLUDE_EXTRA_SDP(),
1997 * #nua_i_prack, #nua_i_update, nua_update(),
1998 * nua_invite(), #nua_r_invite
1999 *
2000 * @par
2001 * @par Third Party Call Control
2002 *
2003 * When so called 2rd party call control is used, the initial @b INVITE may
2004 * not contain SDP offer. In that case, the offer is sent by the recipient
2005 * of the @b INVITE request (User-Agent Server, UAS). The SDP sent in 2XX
2006 * response (or in a preliminary reliable response) is considered as an
2007 * offer, and the answer will be included in the @b ACK request sent by the
2008 * UAC (or @b PRACK in case of preliminary reliable response).
2009 *
2010 * @sa @ref nua_3pcc_call_model
2011 *
2012 * @END_NUA_EVENT
2013 */
2014
2015static int nua_invite_server_init(nua_server_request_t *sr);
2016static int nua_session_server_init(nua_server_request_t *sr);
2017static int nua_invite_server_preprocess(nua_server_request_t *sr);
2018static int nua_invite_server_respond(nua_server_request_t *sr, tagi_t const *);
2019static int nua_invite_server_is_100rel(nua_server_request_t *, tagi_t const *);
2020static int nua_invite_server_report(nua_server_request_t *sr, tagi_t const *);
2021
2022static int
2023 process_ack_or_cancel(nua_server_request_t *, nta_incoming_t *,
2024 sip_t const *),
2025 process_ack(nua_server_request_t *, nta_incoming_t *, sip_t const *),
2026 process_ack_error(nua_server_request_t *sr, msg_t *ackmsg,
2027 int status, char const *phrase, char const *reason),
2028 process_cancel(nua_server_request_t *, nta_incoming_t *, sip_t const *),
2029 process_timeout(nua_server_request_t *, nta_incoming_t *),
2030 process_prack(nua_server_request_t *,
2031 nta_reliable_t *rel,
2032 nta_incoming_t *irq,
2033 sip_t const *sip);
2034
2035nua_server_methods_t const nua_invite_server_methods =
2036 {
2037 SIP_METHOD_INVITEsip_method_invite, "INVITE",
2038 nua_i_invite, /* Event */
2039 {
2040 1, /* Create dialog */
2041 0, /* Initial request */
2042 1, /* Target refresh request */
2043 1, /* Add Contact */
2044 },
2045 nua_invite_server_init,
2046 nua_invite_server_preprocess,
2047 nua_base_server_params((void*)0),
2048 nua_invite_server_respond,
2049 nua_invite_server_report,
2050 };
2051
2052
2053/** @internal Preprocess incoming invite - sure we have a valid request.
2054 *
2055 * @return 0 if request is valid, or error statuscode otherwise
2056 */
2057static int
2058nua_invite_server_init(nua_server_request_t *sr)
2059{
2060 nua_handle_t *nh = sr->sr_owner;
2061 nua_t *nua = nh->nh_nua;
2062 nua_session_usage_t *ss;
2063
2064 sr->sr_neutral = 1;
2065
2066 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
)
)
2067 return SR_STATUS1(sr, SIP_403_FORBIDDEN)sr_status(sr, 403, sip_403_Forbidden);
2068
2069 if (nua_session_server_init(sr))
2070 return sr->sr_status;
2071
2072 if (sr->sr_usage) {
2073 /* Existing session - check for overlap and glare */
2074
2075 nua_server_request_t const *sr0;
2076 nua_client_request_t const *cr;
2077
2078 for (sr0 = nh->nh_ds->ds_sr; sr0; sr0 = sr0->sr_next) {
2079 /* Previous INVITE has not been ACKed */
2080 if (sr0->sr_method == sip_method_invite)
2081 break;
2082 /* Or we have sent offer but have not received an answer */
2083 if (sr->sr_sdp && sr0->sr_offer_sent && !sr0->sr_answer_recv)
2084 break;
2085 /* Or we have received request with offer but not sent an answer */
2086 if (sr->sr_sdp && sr0->sr_offer_recv && !sr0->sr_answer_sent)
2087 break;
2088 }
2089
2090 if (sr0) {
2091 /* Overlapping invites - RFC 3261 14.2 */
2092 return nua_server_retry_after(sr, 500, "Overlapping Requests", 0, 10);
2093 }
2094
2095 for (cr = nh->nh_ds->ds_cr; cr; cr = cr->cr_next) {
2096 if (cr->cr_usage == sr->sr_usage && cr->cr_orq && cr->cr_offer_sent)
2097 /* Glare - RFC 3261 14.2 and RFC 3311 section 5.2 */
2098 return SR_STATUS1(sr, SIP_491_REQUEST_PENDING)sr_status(sr, 491, sip_491_Request_pending);
2099 }
2100
2101 ss = nua_dialog_usage_private(sr->sr_usage)((sr->sr_usage) ? (void*)((sr->sr_usage) + 1) : ((void*
)0))
;
2102
2103 if (ss->ss_state < nua_callstate_ready &&
2104 ss->ss_state != nua_callstate_init) {
2105 return nua_server_retry_after(sr, 500, "Overlapping Requests 2", 0, 10);
2106 }
2107 }
2108
2109 sr->sr_neutral = 0;
2110
2111 return 0;
2112}
2113
2114/** Initialize session server request.
2115 *
2116 * Ensure that the request is valid.
2117 */
2118static int
2119nua_session_server_init(nua_server_request_t *sr)
2120{
2121 nua_handle_t *nh = sr->sr_owner;
2122 nua_t *nua = nh->nh_nua;
2123
2124 msg_t *msg = sr->sr_response.msg;
2125 sip_t *sip = sr->sr_response.sip;
2126
2127 sip_t *request = (sip_t *) sr->sr_request.sip;
2128
2129 if (!sr->sr_initial)
2130 sr->sr_usage = nua_dialog_usage_get(nh->nh_ds, nua_session_usage, NULL((void*)0));
2131
2132 if (sr->sr_method != sip_method_invite && sr->sr_usage == NULL((void*)0)) {
2133 /* UPDATE/PRACK sent within an existing dialog? */
2134 return SR_STATUS(sr, 481, "Call Does Not Exist")((sr)->sr_phrase = ("Call Does Not Exist"), (sr)->sr_status
= (481))
;
2135 }
2136 else if (sr->sr_usage) {
2137 nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage)((sr->sr_usage) ? (void*)((sr->sr_usage) + 1) : ((void*
)0))
;
2138 if (ss->ss_state >= nua_callstate_terminating)
2139 return SR_STATUS(sr, 481, "Call is being terminated")((sr)->sr_phrase = ("Call is being terminated"), (sr)->
sr_status = (481))
;
2140 }
2141
2142 if (nh->nh_soa) {
2143 sip_accept_t *a = nua->nua_invite_accept;
2144
2145 /* XXX - soa should know what it supports */
2146 sip_add_dup(msg, sip, (sip_header_t *)a);
2147
2148 /* if we see there is a multipart content-type,
2149 parse it into the sip structre and find the SDP and replace it
2150 into the request as the requested content */
2151 if (request->sip_content_type &&
2152 su_casenmatch(request->sip_content_type->c_type, "multipart/", 10)) {
2153 msg_multipart_t *mp, *mpp;
2154
2155 if (request->sip_multipart) {
2156 mp = request->sip_multipart;
2157 } else {
2158 mp = msg_multipart_parse(nua_handle_home(nh)((su_home_t *)(nh)),
2159 request->sip_content_type,
2160 (sip_payload_t *)request->sip_payload);
2161 request->sip_multipart = mp;
2162 }
2163
2164 if (mp) {
2165 int sdp = 0;
2166
2167 /* 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 */
2168 for(mpp = mp; mpp; mpp = mpp->mp_next) {
2169 if (mpp->mp_content_type && mpp->mp_content_type->c_type &&
2170 mpp->mp_payload && mpp->mp_payload->pl_data &&
2171 su_casenmatch(mpp->mp_content_type->c_type, "application/sdp", 15)) {
2172
2173 request->sip_content_type = msg_content_type_dup(nua_handle_home(nh)((su_home_t *)(nh)), mpp->mp_content_type);
2174
2175 if (request->sip_content_length) {
2176 request->sip_content_length->l_length = mpp->mp_payload->pl_len;
2177 }
2178
2179 request->sip_payload->pl_data = su_strdup(nua_handle_home(nh)((su_home_t *)(nh)), mpp->mp_payload->pl_data);
2180 request->sip_payload->pl_len = mpp->mp_payload->pl_len;
2181
2182 sdp++;
2183
2184 break;
2185 }
2186 }
2187
2188 /* insist on the existance of a SDP in the content or refuse the request */
2189 if (!sdp) {
2190 return SR_STATUS1(sr, SIP_406_NOT_ACCEPTABLE)sr_status(sr, 406, sip_406_Not_acceptable);
2191 }
2192 }
2193 }
2194
2195
2196 /* Make sure caller uses application/sdp without compression */
2197 if (nta_check_session_content(NULL((void*)0), request, a, TAG_END()(tag_type_t)0, (tag_value_t)0)) {
2198 sip_add_make(msg, sip, sip_accept_encoding_class, "");
2199 return SR_STATUS1(sr, SIP_415_UNSUPPORTED_MEDIA)sr_status(sr, 415, sip_415_Unsupported_media);
2200 }
2201
2202 /* Make sure caller accepts application/sdp */
2203 if (nta_check_accept(NULL((void*)0), request, a, NULL((void*)0), TAG_END()(tag_type_t)0, (tag_value_t)0)) {
2204 sip_add_make(msg, sip, sip_accept_encoding_class, "");
2205 return SR_STATUS1(sr, SIP_406_NOT_ACCEPTABLE)sr_status(sr, 406, sip_406_Not_acceptable);
2206 }
2207 }
2208
2209 if (request->sip_session_expires &&
2210 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") &&
2211 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)
)) {
2212 if (sip->sip_min_se)
2213 return SR_STATUS1(sr, SIP_422_SESSION_TIMER_TOO_SMALL)sr_status(sr, 422, sip_422_Session_timer);
2214 else
2215 return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR)sr_status(sr, 500, sip_500_Internal_server_error);
2216 }
2217
2218 session_get_description(request, &sr->sr_sdp, &sr->sr_sdp_len);
2219
2220 return 0;
2221}
2222
2223/** Preprocess INVITE.
2224 *
2225 * This is called after a handle has been created for an incoming INVITE.
2226 */
2227int nua_invite_server_preprocess(nua_server_request_t *sr)
2228{
2229 nua_handle_t *nh = sr->sr_owner;
2230 nua_dialog_state_t *ds = nh->nh_ds;
2231 nua_session_usage_t *ss;
2232
2233 sip_t const *request = sr->sr_request.sip;
2234
2235 assert(sr->sr_status == 100)((void) sizeof ((sr->sr_status == 100) ? 1 : 0), __extension__
({ if (sr->sr_status == 100) ; else __assert_fail ("sr->sr_status == 100"
, "nua_session.c", 2235, __extension__ __PRETTY_FUNCTION__); }
))
;
2236 assert(nh != nh->nh_nua->nua_dhandle)((void) sizeof ((nh != nh->nh_nua->nua_handles) ? 1 : 0
), __extension__ ({ if (nh != nh->nh_nua->nua_handles) ;
else __assert_fail ("nh != nh->nh_nua->nua_dhandle", "nua_session.c"
, 2236, __extension__ __PRETTY_FUNCTION__); }))
;
2237
2238 if (sr->sr_status > 100)
2239 return sr->sr_status;
2240
2241 if (nh->nh_soa)
2242 soa_init_offer_answer(nh->nh_soa);
2243
2244 if (sr->sr_sdp) {
2245 if (nh->nh_soa &&
2246 soa_set_remote_sdp(nh->nh_soa, NULL((void*)0), sr->sr_sdp, sr->sr_sdp_len) < 0) {
2247 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__, 2248, "nua(%p): %s server: error parsing SDP\n"
, (void *)nh, "INVITE")) : (void)0)
2248 "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__, 2248, "nua(%p): %s server: error parsing SDP\n"
, (void *)nh, "INVITE")) : (void)0)
;
2249 return SR_STATUS(sr, 400, "Bad Session Description")((sr)->sr_phrase = ("Bad Session Description"), (sr)->sr_status
= (400))
;
2250 }
2251 else
2252 sr->sr_offer_recv = 1;
2253 }
2254
2255 /* Add the session usage */
2256 if (sr->sr_usage == NULL((void*)0)) {
2257 sr->sr_usage = nua_dialog_usage_add(nh, ds, nua_session_usage, NULL((void*)0));
2258 if (sr->sr_usage == NULL((void*)0))
2259 return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR)sr_status(sr, 500, sip_500_Internal_server_error);
2260 }
2261
2262 ss = nua_dialog_usage_private(sr->sr_usage)((sr->sr_usage) ? (void*)((sr->sr_usage) + 1) : ((void*
)0))
;
2263
2264 if (sr->sr_offer_recv)
2265 ss->ss_oa_recv = Offer;
2266
2267 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)
;
2268 ss->ss_precondition = sip_has_feature(request->sip_require, "precondition");
2269 if (ss->ss_precondition)
2270 ss->ss_100rel = 1;
2271
2272 session_timer_store(ss->ss_timer, request);
2273
2274#if 0 /* The glare and overlap tests should take care of this. */
2275 assert(ss->ss_state >= nua_callstate_completed ||((void) sizeof ((ss->ss_state >= nua_callstate_completed
|| ss->ss_state == nua_callstate_init) ? 1 : 0), __extension__
({ if (ss->ss_state >= nua_callstate_completed || ss->
ss_state == nua_callstate_init) ; else __assert_fail ("ss->ss_state >= nua_callstate_completed || ss->ss_state == nua_callstate_init"
, "nua_session.c", 2276, __extension__ __PRETTY_FUNCTION__); }
))
2276 ss->ss_state == nua_callstate_init)((void) sizeof ((ss->ss_state >= nua_callstate_completed
|| ss->ss_state == nua_callstate_init) ? 1 : 0), __extension__
({ if (ss->ss_state >= nua_callstate_completed || ss->
ss_state == nua_callstate_init) ; else __assert_fail ("ss->ss_state >= nua_callstate_completed || ss->ss_state == nua_callstate_init"
, "nua_session.c", 2276, __extension__ __PRETTY_FUNCTION__); }
))
;
2277#endif
2278
2279 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)
||
2280 /* Auto-answer to re-INVITE unless auto_answer is set to 0 on handle */
2281 (ss->ss_state == nua_callstate_ready &&
2282 /* Auto-answer requires enabled media (soa).
2283 * XXX - if the re-INVITE modifies the media we should not auto-answer.
2284 */
2285 nh->nh_soa &&
2286 !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
)
)) {
2287 SR_STATUS1(sr, SIP_200_OK)sr_status(sr, 200, sip_200_OK);
2288 }
2289 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)
) {
2290 if (ss->ss_100rel &&
2291 (sip_has_feature(request->sip_supported, "100rel") ||
2292 sip_has_feature(request->sip_require, "100rel"))) {
2293 SR_STATUS1(sr, SIP_183_SESSION_PROGRESS)sr_status(sr, 183, sip_183_Session_progress);
2294 }
2295 else {
2296 SR_STATUS1(sr, SIP_180_RINGING)sr_status(sr, 180, sip_180_Ringing);
2297 }
2298 }
2299
2300 return 0;
2301}
2302
2303
2304/** @internal Respond to an INVITE request.
2305 *
2306 */
2307static
2308int nua_invite_server_respond(nua_server_request_t *sr, tagi_t const *tags)
2309{
2310 nua_handle_t *nh = sr->sr_owner;
2311 nua_dialog_usage_t *du = sr->sr_usage;
2312 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
2313 msg_t *msg = sr->sr_response.msg;
2314 sip_t *sip = sr->sr_response.sip;
2315
2316 int reliable = 0, maybe_answer = 0, offer = 0, answer = 0, extra = 0;
2317
2318 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__, 2318, "nua: %s: entering\n", __func__
)) : (void)0)
;
2319
2320 if (du == NULL((void*)0)) {
2321 if (sr->sr_status < 300)
2322 sr_status(sr, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error);
2323 return nua_base_server_respond(sr, tags);
2324 }
2325
2326 if (200 <= sr->sr_status && sr->sr_status < 300) {
2327 reliable = 1, maybe_answer = 1;
2328 }
2329 else if (nua_invite_server_is_100rel(sr, tags)) {
2330 reliable = 1, maybe_answer = 1;
2331 }
2332 else if (!nh->nh_soa || sr->sr_status >= 300) {
2333 if (sr->sr_neutral)
2334 return nua_base_server_respond(sr, tags);
2335 }
2336 else if (tags && 100 < sr->sr_status && sr->sr_status < 200 &&
2337 !NHP_ISSET(nh->nh_prefs, early_answer)((nh->nh_prefs)->nhp_set_.set_bits.nhb_early_answer)) {
2338 sdp_session_t const *user_sdp = NULL((void*)0);
2339 char const *user_sdp_str = NULL((void*)0);
2340
2341 tl_gets(tags,
2342 SOATAG_USER_SDP_REF(user_sdp)soatag_user_sdp_ref, sdptag_session_vr(&(user_sdp)),
2343 SOATAG_USER_SDP_STR_REF(user_sdp_str)soatag_user_sdp_str_ref, tag_str_vr(&(user_sdp_str)),
2344 TAG_END()(tag_type_t)0, (tag_value_t)0);
2345
2346 maybe_answer = user_sdp || user_sdp_str;
2347 }
2348 else {
2349 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)
;
2350 }
2351
2352 if (!nh->nh_soa) {
2353 if (session_get_description(sip, NULL((void*)0), NULL((void*)0))) {
2354 if (sr->sr_offer_recv)
2355 answer = 1;
2356 else if (sr->sr_offer_sent < 2)
2357 offer = 1;
2358 }
2359 }
2360 else if (sr->sr_status >= 300) {
2361 soa_clear_remote_sdp(nh->nh_soa);
2362 }
2363 else if (sr->sr_offer_sent && !sr->sr_answer_recv)
2364 /* Wait for answer */;
2365 else if (sr->sr_offer_recv && sr->sr_answer_sent > 1) {
2366 /* We have sent answer */
2367 /* ... but we may want to send it again */
2368 tagi_t const *t = tl_find_last(tags, nutag_include_extra_sdp);
2369 extra = t && t->t_value;
2370 }
2371 else if (sr->sr_offer_recv && !sr->sr_answer_sent && maybe_answer) {
2372 /* Generate answer */
2373 if (soa_generate_answer(nh->nh_soa, NULL((void*)0)) >= 0 &&
2374 soa_activate(nh->nh_soa, NULL((void*)0)) >= 0) {
2375 answer = 1; /* signal that O/A answer sent (answer to invite) */
2376 /* ss_sdp_version is updated only after answer is sent reliably */
2377 }
2378 /* We have an error! */
2379 else if (sr->sr_status >= 200) {
2380 sip_warning_t *warning = NULL((void*)0);
2381 int wcode;
2382 char const *text;
2383 char const *host = "invalid.";
2384
2385 sr->sr_status = soa_error_as_sip_response(nh->nh_soa, &sr->sr_phrase);
2386
2387 wcode = soa_get_warning(nh->nh_soa, &text);
2388
2389 if (wcode) {
2390 if (sip->sip_contact)
2391 host = sip->sip_contact->m_url->url_host;
2392 warning = sip_warning_format(msg_home(msg)((su_home_t*)(msg)), "%u %s \"%s\"",
2393 wcode, host, text);
2394 sip_header_insert(msg, sip, (sip_header_t *)warning);
2395 }
2396 }
2397 else {
2398 /* 1xx - we don't have to send answer */
2399 }
2400 }
2401 else if (sr->sr_offer_recv && sr->sr_answer_sent == 1 && maybe_answer) {
2402 /* The answer was sent unreliably, keep sending it */
2403 answer = 1;
2404 }
2405 else if (!sr->sr_offer_recv && !sr->sr_offer_sent && reliable) {
2406 if (200 <= sr->sr_status && nua_callstate_ready <= ss->ss_state &&
2407 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
)
)
2408 /* This is a re-INVITE without SDP - do not try to send offer in 200 */;
2409 else
2410 /* Generate offer */
2411 if (soa_generate_offer(nh->nh_soa, 0, NULL((void*)0)) < 0)
2412 sr->sr_status = soa_error_as_sip_response(nh->nh_soa, &sr->sr_phrase);
2413 else
2414 offer = 1;
2415 }
2416
2417 if (sr->sr_status < 300 && (offer || answer || extra)) {
2418 if (nh->nh_soa && session_include_description(nh->nh_soa, 1, msg, sip) < 0)
2419 SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR)sr_status(sr, 500, sip_500_Internal_server_error);
2420 else if (offer)
2421 sr->sr_offer_sent = 1 + reliable, ss->ss_oa_sent = Offer;
2422 else if (answer)
2423 sr->sr_answer_sent = 1 + reliable, ss->ss_oa_sent = Answer;
2424
2425 if (answer && reliable && nh->nh_soa) {
2426 ss->ss_sdp_version = soa_get_user_version(nh->nh_soa);
2427 }
2428 }
2429
2430 if (reliable && sr->sr_status < 200) {
2431 sr->sr_response.msg = NULL((void*)0), sr->sr_response.sip = NULL((void*)0);
2432 if (nta_reliable_mreply(sr->sr_irq, process_prack, sr, msg) == NULL((void*)0))
2433 return -1;
2434 sr->sr_100rel = 1;
2435 return 0;
2436 }
2437
2438 if (200 <= sr->sr_status && sr->sr_status < 300) {
2439 session_timer_preferences(ss->ss_timer,
2440 sip,
2441 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)
,
2442 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)
,
2443 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)))
,
2444 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)
,
2445 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)
);
2446
2447 if (session_timer_is_supported(ss->ss_timer))
2448 session_timer_add_headers(ss->ss_timer, 0, msg, sip, nh);
2449 }
2450
2451 return nua_base_server_respond(sr, tags);
2452}
2453
2454/** Check if the response should be sent reliably.
2455 * XXX - use tags to indicate when to use reliable responses ???
2456 */
2457static
2458int nua_invite_server_is_100rel(nua_server_request_t *sr, tagi_t const *tags)
2459{
2460 nua_handle_t *nh = sr->sr_owner;
2461 sip_require_t *require = sr->sr_request.sip->sip_require;
2462 sip_supported_t *supported = sr->sr_request.sip->sip_supported;
2463
2464 if (sr->sr_status >= 200)
2465 return 0;
2466 else if (sr->sr_status == 100)
2467 return 0;
2468
2469 if (sip_has_feature(sr->sr_response.sip->sip_require, "100rel"))
2470 return 1;
2471
2472 if (require == NULL((void*)0) && supported == NULL((void*)0))
2473 return 0;
2474
2475 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"))
2476 return 0;
2477 if (sip_has_feature(require, "100rel"))
2478 return 1;
2479 if (!sip_has_feature(supported, "100rel"))
2480 return 0;
2481 if (sr->sr_status == 183)
2482 return 1;
2483
2484 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)
)
2485 return 1;
2486
2487 if (sip_has_feature(require, "precondition")) {
2488 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)
)
2489 return 1;
2490 if (sr->sr_offer_recv && !sr->sr_answer_sent)
2491 return 1;
2492 }
2493
2494 return 0;
2495}
2496
2497
2498int nua_invite_server_report(nua_server_request_t *sr, tagi_t const *tags)
2499{
2500 nua_handle_t *nh = sr->sr_owner;
2501 nua_dialog_usage_t *du = sr->sr_usage;
2502 nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage)((sr->sr_usage) ? (void*)((sr->sr_usage) + 1) : ((void*
)0))
;
2503 int initial = sr->sr_initial && !sr->sr_event;
2504 int neutral = sr->sr_neutral;
2505 int application = sr->sr_application;
2506 int status = sr->sr_status; char const *phrase = sr->sr_phrase;
2507 int retval;
2508
2509 if (!sr->sr_event && status < 300) { /* Not reported yet */
2510 nta_incoming_bind(sr->sr_irq, process_ack_or_cancel, sr);
2511 }
2512
2513 retval = nua_base_server_report(sr, tags), sr = NULL((void*)0); /* destroys sr */
2514
2515 if (retval >= 2 || ss == NULL((void*)0)) {
2516 /* Session has been terminated. */
2517 if (!initial && !neutral) {
2518#if 0
2519 signal_call_state_change(nh, NULL((void*)0), status, phrase,
2520 nua_callstate_terminated);
2521#endif
2522 }
2523 return retval;
2524 }
2525
2526 /* Update session state */
2527 if (status < 300 || application != 0) {
2528 assert(ss->ss_state != nua_callstate_calling)((void) sizeof ((ss->ss_state != nua_callstate_calling) ? 1
: 0), __extension__ ({ if (ss->ss_state != nua_callstate_calling
) ; else __assert_fail ("ss->ss_state != nua_callstate_calling"
, "nua_session.c", 2528, __extension__ __PRETTY_FUNCTION__); }
))
;
2529 assert(ss->ss_state != nua_callstate_proceeding)((void) sizeof ((ss->ss_state != nua_callstate_proceeding)
? 1 : 0), __extension__ ({ if (ss->ss_state != nua_callstate_proceeding
) ; else __assert_fail ("ss->ss_state != nua_callstate_proceeding"
, "nua_session.c", 2529, __extension__ __PRETTY_FUNCTION__); }
))
;
2530 signal_call_state_change(nh, ss, status, phrase,
2531 status >= 300
2532 ? nua_callstate_init
2533 : status >= 200
2534 ? nua_callstate_completed
2535 : status > 100
2536 ? nua_callstate_early
2537 : nua_callstate_received);
2538 }
2539
2540 if (status == 180)
2541 ss->ss_alerting = 1;
2542 else if (status >= 200)
2543 ss->ss_alerting = 0;
2544
2545 if (200 <= status && status < 300) {
2546 du->du_ready = 1;
2547 }
2548 else if (300 <= status && !neutral) {
2549 if (nh->nh_soa)
2550 soa_init_offer_answer(nh->nh_soa);
2551 }
2552
2553 if (ss->ss_state == nua_callstate_init) {
2554 assert(status >= 300)((void) sizeof ((status >= 300) ? 1 : 0), __extension__ ({
if (status >= 300) ; else __assert_fail ("status >= 300"
, "nua_session.c", 2554, __extension__ __PRETTY_FUNCTION__); }
))
;
2555 nua_session_usage_destroy(nh, ss);
2556 }
2557
2558 return retval;
2559}
2560
2561/** @internal Process ACK or CANCEL or timeout (no ACK) for incoming INVITE */
2562static
2563int process_ack_or_cancel(nua_server_request_t *sr,
2564 nta_incoming_t *irq,
2565 sip_t const *sip)
2566{
2567 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__, 2567, "nua: %s: entering\n", __func__
)) : (void)0)
;
2568
2569 assert(sr->sr_usage)((void) sizeof ((sr->sr_usage) ? 1 : 0), __extension__ ({ if
(sr->sr_usage) ; else __assert_fail ("sr->sr_usage", "nua_session.c"
, 2569, __extension__ __PRETTY_FUNCTION__); }))
;
2570 assert(sr->sr_usage->du_class == nua_session_usage)((void) sizeof ((sr->sr_usage->du_class == nua_session_usage
) ? 1 : 0), __extension__ ({ if (sr->sr_usage->du_class
== nua_session_usage) ; else __assert_fail ("sr->sr_usage->du_class == nua_session_usage"
, "nua_session.c", 2570, __extension__ __PRETTY_FUNCTION__); }
))
;
2571
2572 if (sip && sip->sip_request->rq_method == sip_method_ack)
2573 return process_ack(sr, irq, sip);
2574 else if (sip && sip->sip_request->rq_method == sip_method_cancel)
2575 return process_cancel(sr, irq, sip);
2576 else
2577 return process_timeout(sr, irq);
2578}
2579
2580/** @NUA_EVENT nua_i_ack
2581 *
2582 * Final response to INVITE has been acknowledged by UAC with ACK.
2583 *
2584 * @note This event is only sent after 2XX response.
2585 *
2586 * @param nh operation handle associated with the call
2587 * @param hmagic application context associated with the call
2588 * @param sip incoming ACK request
2589 * @param tags empty
2590 *
2591 * @sa #nua_i_invite, #nua_i_state, @ref nua_uas_call_model, nua_ack()
2592 *
2593 * @END_NUA_EVENT
2594 */
2595static
2596int process_ack(nua_server_request_t *sr,
2597 nta_incoming_t *irq,
2598 sip_t const *sip)
2599{
2600 nua_handle_t *nh = sr->sr_owner;
2601 nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage)((sr->sr_usage) ? (void*)((sr->sr_usage) + 1) : ((void*
)0))
;
2602 msg_t *msg = nta_incoming_getrequest_ackcancel(irq);
2603 char const *recv = NULL((void*)0);
2604 int uas;
2605
2606 if (ss == NULL((void*)0))
2607 return 0;
2608
2609 if (sr->sr_offer_sent && !sr->sr_answer_recv) {
2610 char const *sdp;
2611 size_t len;
2612
2613 if (session_get_description(sip, &sdp, &len))
2614 recv = Answer;
2615
2616 if (recv) {
2617 assert(ss->ss_oa_recv == NULL)((void) sizeof ((ss->ss_oa_recv == ((void*)0)) ? 1 : 0), __extension__
({ if (ss->ss_oa_recv == ((void*)0)) ; else __assert_fail
("ss->ss_oa_recv == NULL", "nua_session.c", 2617, __extension__
__PRETTY_FUNCTION__); }))
;
2618 ss->ss_oa_recv = recv;
2619 }
2620
2621 if (nh->nh_soa == NULL((void*)0))
2622 ;
2623 else if (recv == NULL((void*)0) ) {
2624 if (ss->ss_state >= nua_callstate_ready &&
2625 soa_get_user_version(nh->nh_soa) == ss->ss_sdp_version &&
2626 soa_process_reject(nh->nh_soa, NULL((void*)0)) >= 0) {
2627 url_t const *m;
2628
2629 /* The re-INVITE was a refresh and re-INVITEr ignored our offer */
2630 ss->ss_oa_sent = NULL((void*)0);
2631
2632 if (sr->sr_request.sip->sip_contact)
2633 m = sr->sr_request.sip->sip_contact->m_url;
2634 else
2635 m = sr->sr_request.sip->sip_from->a_url;
2636
2637 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__, 2639, "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)
2638 "(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__, 2639, "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)
2639 (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__, 2639, "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 if (sr->sr_request.sip->sip_user_agent)
2641 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__, 2642, "nua(%p): re-INVITE: \"User-Agent: %s\"\n"
, (void *)nh, sr->sr_request.sip->sip_user_agent->g_string
)) : (void)0)
2642 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__, 2642, "nua(%p): re-INVITE: \"User-Agent: %s\"\n"
, (void *)nh, sr->sr_request.sip->sip_user_agent->g_string
)) : (void)0)
;
2643 }
2644 else
2645 return process_ack_error(sr, msg, 488, "Offer-Answer error",
2646 "SIP;cause=488;text=\"No answer to offer\"");
2647 }
2648 else if (soa_set_remote_sdp(nh->nh_soa, NULL((void*)0), sdp, len) >= 0 &&
2649 soa_process_answer(nh->nh_soa, NULL((void*)0)) >= 0 &&
2650 soa_activate(nh->nh_soa, NULL((void*)0)) >= 0) {
2651 ss->ss_sdp_version = soa_get_user_version(nh->nh_soa);
2652 }
2653 else {
2654 int status; char const *phrase, *reason;
2655
2656 status = soa_error_as_sip_response(nh->nh_soa, &phrase);
2657 reason = soa_error_as_sip_reason(nh->nh_soa);
2658
2659 return process_ack_error(sr, msg, status, phrase, reason);
2660 }
2661 }
2662
2663 if (nh->nh_soa)
2664 soa_clear_remote_sdp(nh->nh_soa);
2665
2666 nua_stack_event(nh->nh_nua, nh, msg, nua_i_ack, SIP_200_OK200, sip_200_OK, NULL((void*)0));
2667 signal_call_state_change(nh, ss, 200, "OK", nua_callstate_ready);
2668 session_timer_set(ss, uas = 1);
2669
2670 nua_server_request_destroy(sr);
2671
2672 return 0;
2673}
2674
2675static int
2676process_ack_error(nua_server_request_t *sr,
2677 msg_t *ackmsg,
2678 int status,
2679 char const *phrase,
2680 char const *reason)
2681{
2682 nua_handle_t *nh = sr->sr_owner;
2683 nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage)((sr->sr_usage) ? (void*)((sr->sr_usage) + 1) : ((void*
)0))
;
2684 int error;
2685
2686 nua_stack_event(nh->nh_nua, nh, ackmsg,
2687 nua_i_ack, status, phrase, NULL((void*)0));
2688 nua_stack_event(nh->nh_nua, nh, NULL((void*)0),
2689 nua_i_media_error, status, phrase, NULL((void*)0));
2690
2691 if (reason) ss->ss_reason = reason;
2692 ss->ss_reporting = 1;
2693 error = nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL((void*)0));
2694 ss->ss_reporting = 0;
2695
2696 signal_call_state_change(nh, ss,
2697 488, "Offer-Answer Error",
2698 /* We report terminated state if BYE failed */
2699 error
2700 ? nua_callstate_terminated
2701 : nua_callstate_terminating);
2702
2703 return 0;
2704}
2705
2706
2707/** @NUA_EVENT nua_i_cancel
2708 *
2709 * Incoming INVITE has been cancelled by the client.
2710 *
2711 * @param status status code of response to CANCEL sent automatically by stack
2712 * @param phrase a short textual description of @a status code
2713 * @param nh operation handle associated with the call
2714 * @param hmagic application context associated with the call
2715 * @param sip incoming CANCEL request
2716 * @param tags empty
2717 *
2718 * @sa @ref nua_uas_call_model, nua_cancel(), #nua_i_invite, #nua_i_state
2719 *
2720 * @END_NUA_EVENT
2721 */
2722
2723/* CANCEL */
2724static
2725int process_cancel(nua_server_request_t *sr,
2726 nta_incoming_t *irq,
2727 sip_t const *sip)
2728{
2729 nua_handle_t *nh = sr->sr_owner;
2730 nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage)((sr->sr_usage) ? (void*)((sr->sr_usage) + 1) : ((void*
)0))
;
2731 msg_t *cancel = nta_incoming_getrequest_ackcancel(irq);
2732
2733 assert(ss)((void) sizeof ((ss) ? 1 : 0), __extension__ ({ if (ss) ; else
__assert_fail ("ss", "nua_session.c", 2733, __extension__ __PRETTY_FUNCTION__
); }))
; assert(ss == nua_session_usage_for_dialog(nh->nh_ds))((void) sizeof ((ss == nua_session_usage_for_dialog(nh->nh_ds
)) ? 1 : 0), __extension__ ({ if (ss == nua_session_usage_for_dialog
(nh->nh_ds)) ; else __assert_fail ("ss == nua_session_usage_for_dialog(nh->nh_ds)"
, "nua_session.c", 2733, __extension__ __PRETTY_FUNCTION__); }
))
; (void)ss;
2734
2735 assert(nta_incoming_status(irq) < 200)((void) sizeof ((nta_incoming_status(irq) < 200) ? 1 : 0),
__extension__ ({ if (nta_incoming_status(irq) < 200) ; else
__assert_fail ("nta_incoming_status(irq) < 200", "nua_session.c"
, 2735, __extension__ __PRETTY_FUNCTION__); }))
;
2736
2737 nua_stack_event(nh->nh_nua, nh, cancel, nua_i_cancel, SIP_200_OK200, sip_200_OK, NULL((void*)0));
2738 sr->sr_application = SR_STATUS1(sr, SIP_487_REQUEST_TERMINATED)sr_status(sr, 487, sip_487_Request_terminated);
2739 nua_server_respond(sr, NULL((void*)0));
2740 nua_server_report(sr);
2741
2742 return 0;
2743}
2744
2745/* Timeout (no ACK or PRACK received) */
2746static
2747int process_timeout(nua_server_request_t *sr,
2748 nta_incoming_t *irq)
2749{
2750 nua_handle_t *nh = sr->sr_owner;
2751 nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage)((sr->sr_usage) ? (void*)((sr->sr_usage) + 1) : ((void*
)0))
;
2752 char const *phrase = "ACK Timeout";
2753 char const *reason = "SIP;cause=408;text=\"ACK Timeout\"";
2754 int error;
2755
2756 assert(ss)((void) sizeof ((ss) ? 1 : 0), __extension__ ({ if (ss) ; else
__assert_fail ("ss", "nua_session.c", 2756, __extension__ __PRETTY_FUNCTION__
); }))
; assert(ss == nua_session_usage_for_dialog(nh->nh_ds))((void) sizeof ((ss == nua_session_usage_for_dialog(nh->nh_ds
)) ? 1 : 0), __extension__ ({ if (ss == nua_session_usage_for_dialog
(nh->nh_ds)) ; else __assert_fail ("ss == nua_session_usage_for_dialog(nh->nh_ds)"
, "nua_session.c", 2756, __extension__ __PRETTY_FUNCTION__); }
))
;
2757
2758 if (nua_server_request_is_pending(sr)) {
2759 phrase = "PRACK Timeout";
2760 reason = "SIP;cause=504;text=\"PRACK Timeout\"";
2761 }
2762
2763 nua_stack_event(nh->nh_nua, nh, 0, nua_i_error, 408, phrase, NULL((void*)0));
2764
2765 if (nua_server_request_is_pending(sr)) {
2766 /* PRACK timeout */
2767 SR_STATUS1(sr, SIP_504_GATEWAY_TIME_OUT)sr_status(sr, 504, sip_504_Gateway_time_out);
2768 nua_server_trespond(sr,
2769 SIPTAG_REASON_STR(reason)siptag_reason_str, tag_str_v(reason),
2770 TAG_END()(tag_type_t)0, (tag_value_t)0);
2771 if (nua_server_report(sr) >= 2)
2772 return 0; /* Done */
2773 sr = NULL((void*)0);
2774 }
2775
2776 /* send BYE, too, if 200 OK (or 183 to re-INVITE) timeouts */
2777 ss->ss_reason = reason;
2778
2779 ss->ss_reporting = 1; /* We report terminated state here if BYE fails */
2780 error = nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL((void*)0));
2781 ss->ss_reporting = 0;
2782
2783 signal_call_state_change(nh, ss, 0, phrase,
2784 error
2785 ? nua_callstate_terminated
2786 : nua_callstate_terminating);
2787
2788 if (sr)
2789 nua_server_request_destroy(sr);
2790
2791 return 0;
2792}
2793
2794
2795/** @NUA_EVENT nua_i_prack
2796 *
2797 * Incoming PRACK request. PRACK request is used to acknowledge reliable
2798 * preliminary responses and it is usually sent automatically by the nua
2799 * stack.
2800 *
2801 * @param status status code of response sent automatically by stack
2802 * @param phrase a short textual description of @a status code
2803 * @param nh operation handle associated with the call
2804 * @param hmagic application context associated with the call
2805 * @param sip incoming PRACK request
2806 * @param tags empty
2807 *
2808 * @sa nua_prack(), #nua_r_prack, @RFC3262, NUTAG_EARLY_MEDIA()
2809 *
2810 * @END_NUA_EVENT
2811 */
2812
2813int nua_prack_server_init(nua_server_request_t *sr);
2814int nua_prack_server_respond(nua_server_request_t *sr, tagi_t const *tags);
2815int nua_prack_server_report(nua_server_request_t *sr, tagi_t const *tags);
2816
2817nua_server_methods_t const nua_prack_server_methods =
2818 {
2819 SIP_METHOD_PRACKsip_method_prack, "PRACK",
2820 nua_i_prack, /* Event */
2821 {
2822 0, /* Do not create dialog */
2823 1, /* In-dialog request */
2824 1, /* Target refresh request */
2825 1, /* Add Contact */
2826 },
2827 nua_prack_server_init,
2828 nua_base_server_preprocess((void*)0),
2829 nua_base_server_params((void*)0),
2830 nua_prack_server_respond,
2831 nua_prack_server_report,
2832 };
2833
2834/** @internal Process reliable response PRACK or (timeout from 100rel) */
2835static int process_prack(nua_server_request_t *sr,
2836 nta_reliable_t *rel,
2837 nta_incoming_t *irq,
2838 sip_t const *sip)
2839{
2840 nua_handle_t *nh;
2841
2842 nta_reliable_destroy(rel);
2843
2844 if (irq == NULL((void*)0))
2845 /* Final response interrupted 100rel, we did not actually receive PRACK */
2846 return 200;
2847
2848 sr->sr_pracked = 1;
2849
2850 if (!nua_server_request_is_pending(sr)) /* There is no INVITE anymore */
2851 return 481;
2852
2853 nh = sr->sr_owner;
2854
2855 if (nh->nh_ds->ds_leg == NULL((void*)0))
2856 return 500;
2857
2858 if (sip == NULL((void*)0)) {
2859 /* 100rel timeout */
2860 SR_STATUS(sr, 504, "Reliable Response Timeout")((sr)->sr_phrase = ("Reliable Response Timeout"), (sr)->
sr_status = (504))
;
2861 nua_stack_event(nh->nh_nua, nh, NULL((void*)0), nua_i_error,
2862 sr->sr_status, sr->sr_phrase,
2863 NULL((void*)0));
2864 nua_server_trespond(sr,
2865 SIPTAG_REASON_STR("SIP;cause=504;"siptag_reason_str, tag_str_v("SIP;cause=504;" "text=\"PRACK Timeout\""
)
2866 "text=\"PRACK Timeout\"")siptag_reason_str, tag_str_v("SIP;cause=504;" "text=\"PRACK Timeout\""
)
,
2867 TAG_END()(tag_type_t)0, (tag_value_t)0);
2868 nua_server_report(sr);
2869 return 504;
2870 }
2871
2872 nta_incoming_bind(irq, NULL((void*)0), (void *)sr);
2873
2874 return nua_stack_process_request(nh, nh->nh_ds->ds_leg, irq, sip);
2875}
2876
2877
2878int nua_prack_server_init(nua_server_request_t *sr)
2879{
2880 nua_handle_t *nh = sr->sr_owner;
2881 nua_server_request_t *sri = nta_incoming_magic(sr->sr_irq, NULL((void*)0));
2882
2883 if (sri == NULL((void*)0))
2884 return SR_STATUS(sr, 481, "No Such Preliminary Response")((sr)->sr_phrase = ("No Such Preliminary Response"), (sr)->
sr_status = (481))
;
2885
2886 if (nua_session_server_init(sr))
2887 return sr->sr_status;
2888
2889 if (sr->sr_sdp) {
2890 nua_session_usage_t *ss = NUA_DIALOG_USAGE_PRIVATE(sr->sr_usage)((void *)((sr->sr_usage) + 1));
2891 char const *offeranswer;
2892
2893 /* XXX - check for overlap? */
2894
2895 if (sri->sr_offer_sent && !sri->sr_answer_recv)
2896 sr->sr_answer_recv = 1, sri->sr_answer_recv = 1, offeranswer = Answer;
2897 else
2898 sr->sr_offer_recv = 1, offeranswer = Offer;
2899
2900 ss->ss_oa_recv = offeranswer;
2901
2902 if (nh->nh_soa &&
2903 soa_set_remote_sdp(nh->nh_soa, NULL((void*)0), sr->sr_sdp, sr->sr_sdp_len) < 0) {
2904 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__, 2905, "nua(%p): %s server: error parsing %s\n"
, (void *)nh, "PRACK", offeranswer)) : (void)0)
2905 "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__, 2905, "nua(%p): %s server: error parsing %s\n"
, (void *)nh, "PRACK", offeranswer)) : (void)0)
;
2906 return
2907 sr->sr_status = soa_error_as_sip_response(nh->nh_soa, &sr->sr_phrase);
2908 }
2909 }
2910
2911 return 0;
2912}
2913
2914int nua_prack_server_respond(nua_server_request_t *sr, tagi_t const *tags)
2915{
2916 nua_handle_t *nh = sr->sr_owner;
2917
2918 if (sr->sr_status < 200 || 300 <= sr->sr_status)
2919 return nua_base_server_respond(sr, tags);
2920
2921 if (sr->sr_sdp) {
2922 nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage)((sr->sr_usage) ? (void*)((sr->sr_usage) + 1) : ((void*
)0))
;
2923 msg_t *msg = sr->sr_response.msg;
2924 sip_t *sip = sr->sr_response.sip;
2925
2926 if (nh->nh_soa == NULL((void*)0)) {
2927 if (sr->sr_offer_recv && session_get_description(sip, NULL((void*)0), NULL((void*)0)))
2928 sr->sr_answer_sent = 1, ss ? ss->ss_oa_sent = Answer : Answer;
2929 }
2930 else if ((sr->sr_offer_recv && soa_generate_answer(nh->nh_soa, NULL((void*)0)) < 0) ||
2931 (sr->sr_answer_recv && soa_process_answer(nh->nh_soa, NULL((void*)0)) < 0)) {
2932 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__, 2935, "nua(%p): %s server: %s %s\n"
, (void *)nh, "PRACK", "error processing", sr->sr_offer_recv
? Offer : Answer)) : (void)0)
2933 (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__, 2935, "nua(%p): %s server: %s %s\n"
, (void *)nh, "PRACK", "error processing", sr->sr_offer_recv
? Offer : Answer)) : (void)0)
2934 "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__, 2935, "nua(%p): %s server: %s %s\n"
, (void *)nh, "PRACK", "error processing", sr->sr_offer_recv
? Offer : Answer)) : (void)0)
2935 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__, 2935, "nua(%p): %s server: %s %s\n"
, (void *)nh, "PRACK", "error processing", sr->sr_offer_recv
? Offer : Answer)) : (void)0)
;
2936 sr->sr_status = soa_error_as_sip_response(nh->nh_soa, &sr->sr_phrase);
2937 }
2938 else if (sr->sr_offer_recv) {
2939 if (session_include_description(nh->nh_soa, 1, msg, sip) < 0)
2940 sr_status(sr, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error);
2941 else
2942 sr->sr_answer_sent = 1, ss ? ss->ss_oa_sent = Answer : Answer;
2943 }
2944 }
2945
2946 return nua_base_server_respond(sr, tags);
2947}
2948
2949int nua_prack_server_report(nua_server_request_t *sr, tagi_t const *tags)
2950{
2951 nua_handle_t *nh = sr->sr_owner;
2952 nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage)((sr->sr_usage) ? (void*)((sr->sr_usage) + 1) : ((void*
)0))
;
2953 nua_server_request_t *sri = nta_incoming_magic(sr->sr_irq, NULL((void*)0));
2954 int status = sr->sr_status; char const *phrase = sr->sr_phrase;
2955 int offer_recv_or_answer_sent = sr->sr_offer_recv || sr->sr_answer_sent || sr->sr_offer_sent || sr->sr_answer_recv;
2956 int retval;
2957
2958 retval = nua_base_server_report(sr, tags), sr = NULL((void*)0); /* destroys sr */
2959
2960 if (retval >= 2 || ss == NULL((void*)0)) {
2961#if 0
2962 signal_call_state_change(nh, NULL((void*)0),
2963 status, phrase,
2964 nua_callstate_terminated);
2965#endif
2966 return retval;
2967 }
2968
2969 if (offer_recv_or_answer_sent) {
2970 /* signal offer received, answer sent */
2971 signal_call_state_change(nh, ss,
2972 status, phrase,
2973 ss->ss_state);
2974 if (nh->nh_soa) {
2975 soa_activate(nh->nh_soa, NULL((void*)0));
2976 ss->ss_sdp_version = soa_get_user_version(nh->nh_soa);
2977 }
2978 }
2979
2980 if (status < 200 || 300 <= status)
2981 return retval;
2982
2983 assert(sri)((void) sizeof ((sri) ? 1 : 0), __extension__ ({ if (sri) ; else
__assert_fail ("sri", "nua_session.c", 2983, __extension__ __PRETTY_FUNCTION__
); }))
;
2984
2985 if (sri == NULL((void*)0)) {
2986
2987 }
2988 else if (SR_HAS_SAVED_SIGNAL(sri)((sri)->sr_signal[0] != ((void*)0))) {
2989 nua_signal_data_t const *e;
2990
2991 e = nua_signal_data(sri->sr_signal);
2992
2993 sri->sr_application = SR_STATUS(sri, e->e_status, e->e_phrase)((sri)->sr_phrase = (e->e_phrase), (sri)->sr_status =
(e->e_status))
;
2994
2995 nua_server_params(sri, e->e_tags);
2996 nua_server_respond(sri, e->e_tags);
2997 nua_server_report(sri);
2998 }
2999 else if (ss->ss_state < nua_callstate_ready
3000 && !ss->ss_alerting
3001 && !ss->ss_precondition
3002 && 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)
) {
3003 SR_STATUS1(sri, SIP_180_RINGING)sr_status(sri, 180, sip_180_Ringing);
3004 nua_server_respond(sri, NULL((void*)0));
3005 nua_server_report(sri);
3006 }
3007
3008 return retval;
3009}
3010
3011/* ---------------------------------------------------------------------- */
3012/* Automatic notifications from a referral */
3013
3014static int
3015nh_referral_check(nua_handle_t *nh, tagi_t const *tags)
3016{
3017 sip_event_t const *event = NULL((void*)0);
3018 int pause = 1;
3019 struct nua_referral *ref = nh->nh_referral;
3020 nua_handle_t *ref_handle = ref->ref_handle;
3021
3022 if (!ref_handle
3023 &&
3024 tl_gets(tags,
3025 NUTAG_NOTIFY_REFER_REF(ref_handle)nutag_notify_refer_ref, nutag_handle_vr(&(ref_handle)),
3026 NUTAG_REFER_EVENT_REF(event)nutag_refer_event_ref, siptag_event_vr(&(event)),
3027 NUTAG_REFER_PAUSE_REF(pause)nutag_refer_pause_ref, tag_bool_vr(&(pause)),
3028 TAG_END()(tag_type_t)0, (tag_value_t)0) == 0
3029 &&
3030 tl_gets(nh->nh_tags,
3031 NUTAG_NOTIFY_REFER_REF(ref_handle)nutag_notify_refer_ref, nutag_handle_vr(&(ref_handle)),
3032 NUTAG_REFER_EVENT_REF(event)nutag_refer_event_ref, siptag_event_vr(&(event)),
3033 NUTAG_REFER_PAUSE_REF(pause)nutag_refer_pause_ref, tag_bool_vr(&(pause)),
3034 TAG_END()(tag_type_t)0, (tag_value_t)0) == 0)
3035 return 0;
3036
3037 if (!ref_handle)
3038 return 0;
3039
3040 /* Remove nh_referral and nh_notevent */
3041 tl_tremove(nh->nh_tags,
3042 NUTAG_NOTIFY_REFER(ref_handle)nutag_notify_refer, nutag_handle_v(ref_handle),
3043 TAG_IF(event, NUTAG_REFER_EVENT(event))!(event) ? tag_skip : nutag_refer_event, siptag_event_v(event
)
,
3044 TAG_END()(tag_type_t)0, (tag_value_t)0);
3045
3046 if (event)
3047 ref->ref_event = sip_event_dup(nh->nh_home, event);
3048
3049 if (!nh_validate(nh->nh_nua, ref_handle)) {
3050 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__, 3050, "nua: invalid NOTIFY_REFER handle\n"
"%s", "")) : (void)0)
;
3051 return -1;
3052 }
3053 else if (!ref->ref_event) {
3054 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__, 3054, "nua: NOTIFY event missing\n"
"%s", "")) : (void)0)
;
3055 return -1;
3056 }
3057
3058 if (ref_handle != ref->ref_handle) {
3059 if (ref->ref_handle)
3060 nua_handle_unref(ref->ref_handle);
3061 ref->ref_handle = nua_handle_ref(ref_handle);
3062 }
3063
3064#if 0
3065 if (pause) {
3066 /* Pause media on REFER handle */
3067 nmedia_pause(nua, ref_handle->nh_nm, NULL((void*)0));
3068 }
3069#endif
3070
3071 return 0;
3072}
3073
3074static void
3075nh_referral_respond(nua_handle_t *nh, int status, char const *phrase)
3076{
3077 char payload[128];
3078 char const *substate;
3079 struct nua_referral *ref = nh->nh_referral;
3080
3081 if (!nh_validate(nh->nh_nua, ref->ref_handle)) {
3082 if (ref) {
3083 if (ref->ref_handle)
3084 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__, 3085, "nh_handle_referral: stale referral handle %p\n"
, (void *)ref->ref_handle)) : (void)0)
3085 (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__, 3085, "nh_handle_referral: stale referral handle %p\n"
, (void *)ref->ref_handle)) : (void)0)
;
3086 ref->ref_handle = NULL((void*)0);
3087 }
3088 return;
3089 }
3090
3091 /* XXX - we should have a policy here whether to send 101..199 */
3092
3093 assert(ref->ref_event)((void) sizeof ((ref->ref_event) ? 1 : 0), __extension__ (
{ if (ref->ref_event) ; else __assert_fail ("ref->ref_event"
, "nua_session.c", 3093, __extension__ __PRETTY_FUNCTION__); }
))
;
3094
3095 if (status >= 300)
3096 status = 503, phrase = sip_503_Service_unavailable;
3097
3098 snprintf(payload, sizeof(payload), "SIP/2.0 %03u %s\r\n", status, phrase);
3099
3100 if (status < 200)
3101 substate = "active";
3102 else
3103 substate = "terminated ;reason=noresource";
3104
3105 nua_stack_post_signal(ref->ref_handle,
3106 nua_r_notify,
3107 SIPTAG_EVENT(ref->ref_event)siptag_event, siptag_event_v(ref->ref_event),
3108 SIPTAG_SUBSCRIPTION_STATE_STR(substate)siptag_subscription_state_str, tag_str_v(substate),
3109 SIPTAG_CONTENT_TYPE_STR("message/sipfrag")siptag_content_type_str, tag_str_v("message/sipfrag"),
3110 SIPTAG_PAYLOAD_STR(payload)siptag_payload_str, tag_str_v(payload),
3111 TAG_END()(tag_type_t)0, (tag_value_t)0);
3112
3113 if (status < 200)
3114 return;
3115
3116 su_free(nh->nh_home, ref->ref_event), ref->ref_event = NULL((void*)0);
3117
3118 nua_handle_unref(ref->ref_handle), ref->ref_handle = NULL((void*)0);
3119}
3120
3121/* ======================================================================== */
3122/* INFO */
3123
3124/**@fn void nua_info(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
3125 *
3126 * Send an INFO request.
3127 *
3128 * INFO is used to send call related information like DTMF
3129 * digit input events. See @RFC2976.
3130 *
3131 * @param nh Pointer to operation handle
3132 * @param tag, value, ... List of tagged parameters
3133 *
3134 * @return
3135 * nothing
3136 *
3137 * @par Related Tags:
3138 * Header tags defined in <sofia-sip/sip_tag.h>.
3139 *
3140 * @par Events:
3141 * #nua_r_info
3142 *
3143 * @sa #nua_i_info
3144 */
3145
3146nua_client_methods_t const nua_info_client_methods = {
3147 SIP_METHOD_INFOsip_method_info, "INFO", /* crm_method, crm_method_name */
3148 0, /* crm_extra */
3149 { /* crm_flags */
3150 /* create_dialog */ 0,
3151 /* in_dialog */ 1,
3152 /* target refresh */ 0
3153 },
3154 NULL((void*)0), /* crm_template */
3155 NULL((void*)0), /* crm_init */
3156 NULL((void*)0), /* crm_send */
3157 NULL((void*)0), /* crm_check_restart */
3158 NULL((void*)0), /* crm_recv */
3159 NULL((void*)0), /* crm_preliminary */
3160 NULL((void*)0), /* crm_report */
3161 NULL((void*)0), /* crm_complete */
3162};
3163
3164int
3165nua_stack_info(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags)
3166{
3167 return nua_client_create(nh, e, &nua_info_client_methods, tags);
3168}
3169
3170/** @NUA_EVENT nua_r_info
3171 *
3172 * Response to an outgoing @b INFO request.
3173 *
3174 * @param status response status code
3175 * (if the request is retried, @a status is 100, the @a
3176 * sip->sip_status->st_status contain the real status code
3177 * from the response message, e.g., 302, 401, or 407)
3178 * @param phrase a short textual description of @a status code
3179 * @param nh operation handle associated with the call
3180 * @param hmagic application context associated with the call
3181 * @param sip response to @b INFO or NULL upon an error
3182 * (status code is in @a status and
3183 * descriptive message in @a phrase parameters)
3184 * @param tags empty
3185 *
3186 * @sa nua_info(), #nua_i_info, @RFC2976
3187 *
3188 * @END_NUA_EVENT
3189 */
3190
3191/** @NUA_EVENT nua_i_info
3192 *
3193 * Incoming session INFO request.
3194 *
3195 * @param status statuscode of response sent automatically by stack
3196 * @param phrase a short textual description of @a status code
3197 * @param nh operation handle associated with the call
3198 * @param hmagic application context associated with the call
3199 * @param sip incoming INFO request
3200 * @param tags empty
3201 *
3202 * @sa nua_info(), #nua_r_info, @RFC2976
3203 *
3204 * @END_NUA_EVENT
3205 */
3206
3207nua_server_methods_t const nua_info_server_methods =
3208 {
3209 SIP_METHOD_INFOsip_method_info, "INFO",
3210 nua_i_info, /* Event */
3211 {
3212 0, /* Do not create dialog */
3213 0, /* Allow outside dialog, too */
3214 0, /* Not a target refresh request */
3215 0, /* Do not add Contact */
3216 },
3217 nua_base_server_init((void*)0),
3218 nua_base_server_preprocess((void*)0),
3219 nua_base_server_params((void*)0),
3220 nua_base_server_respond,
3221 nua_base_server_report,
3222 };
3223
3224/* ======================================================================== */
3225/* UPDATE */
3226
3227/**@fn void nua_update(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
3228 *
3229 * Update a session.
3230 *
3231 * Update a session using SIP UPDATE method. See @RFC3311.
3232 *
3233 * Update method can be used when the session has been established with
3234 * INVITE. It's mainly used during the session establishment when
3235 * preconditions are used (@RFC3312). It can be also used during the call if
3236 * no user input is needed for offer/answer negotiation.
3237 *
3238 * @param nh Pointer to operation handle
3239 * @param tag, value, ... List of tagged parameters
3240 *
3241 * @return
3242 * nothing
3243 *
3244 * @par Related Tags:
3245 * same as nua_invite()
3246 *
3247 * @par Events:
3248 * #nua_r_update \n
3249 * #nua_i_state (#nua_i_active, #nua_i_terminated)\n
3250 * #nua_i_media_error \n
3251 *
3252 * @sa @ref nua_call_model, @RFC3311, nua_update(), #nua_i_update
3253 */
3254
3255static int nua_update_client_init(nua_client_request_t *cr,
3256 msg_t *msg, sip_t *sip,
3257 tagi_t const *tags);
3258static int nua_update_client_request(nua_client_request_t *cr,
3259 msg_t *msg, sip_t *sip,
3260 tagi_t const *tags);
3261static int nua_update_client_response(nua_client_request_t *cr,
3262 int status, char const *phrase,
3263 sip_t const *sip);
3264static int nua_update_client_report(nua_client_request_t *cr,
3265 int status, char const *phrase,
3266 sip_t const *sip,
3267 nta_outgoing_t *orq,
3268 tagi_t const *tags);
3269
3270nua_client_methods_t const nua_update_client_methods = {
3271 SIP_METHOD_UPDATEsip_method_update, "UPDATE", /* crm_method, crm_method_name */
3272 0, /* crm_extrasize of private data */
3273 { /* crm_flags */
3274 /* create_dialog */ 0,
3275 /* in_dialog */ 1,
3276 /* target refresh */ 1
3277 },
3278 NULL((void*)0), /* crm_template */
3279 nua_update_client_init, /* crm_init */
3280 nua_update_client_request, /* crm_send */
3281 session_timer_check_restart, /* crm_check_restart */
3282 nua_update_client_response, /* crm_recv */
3283 NULL((void*)0), /* crm_preliminary */
3284 nua_update_client_report, /* crm_report */
3285 NULL((void*)0), /* crm_complete */
3286};
3287
3288int nua_stack_update(nua_t *nua, nua_handle_t *nh, nua_event_t e,
3289 tagi_t const *tags)
3290{
3291 return nua_client_create(nh, e, &nua_update_client_methods, tags);
3292}
3293
3294static int nua_update_client_init(nua_client_request_t *cr,
3295 msg_t *msg, sip_t *sip,
3296 tagi_t const *tags)
3297{
3298 nua_handle_t *nh = cr->cr_owner;
3299 nua_dialog_usage_t *du = nua_dialog_usage_for_session(nh->nh_ds);
3300
3301 cr->cr_usage = du;
3302
3303 return 0;
3304}
3305
3306static int nua_update_client_request(nua_client_request_t *cr,
3307 msg_t *msg, sip_t *sip,
3308 tagi_t const *tags)
3309{
3310 nua_handle_t *nh = cr->cr_owner;
3311 nua_dialog_usage_t *du = cr->cr_usage;
3312 nua_session_usage_t *ss;
3313 nua_server_request_t *sr;
3314 nua_client_request_t *cri;
3315 int offer_sent = 0, retval;
3316
3317 if (du == NULL((void*)0)) /* Call terminated */
3318 return nua_client_return(cr, SIP_481_NO_TRANSACTION481, sip_481_No_transaction, msg);
3319
3320 ss = NUA_DIALOG_USAGE_PRIVATE(du)((void *)((du) + 1));
3321 if (ss->ss_state >= nua_callstate_terminating)
3322 return nua_client_return(cr, 900, "Session is terminating", msg);
3323
3324 cri = du->du_cr;
3325
3326 for (sr = nh->nh_ds->ds_sr; sr; sr = sr->sr_next)
3327 if ((sr->sr_offer_sent && !sr->sr_answer_recv) ||
3328 (sr->sr_offer_recv && !sr->sr_answer_sent))
3329 break;
3330
3331 if (nh->nh_soa == NULL((void*)0)) {
3332 offer_sent = session_get_description(sip, NULL((void*)0), NULL((void*)0));
3333 }
3334 else if (sr ||
3335 (cri && cri->cr_offer_sent && !cri->cr_answer_recv) ||
3336 (cri && cri->cr_offer_recv && !cri->cr_answer_sent)) {
3337 if (session_get_description(sip, NULL((void*)0), NULL((void*)0)))
3338 return nua_client_return(cr, 500, "Overlapping Offer/Answer", msg);
3339 }
3340 else if (!sip->sip_payload) {
3341 soa_init_offer_answer(nh->nh_soa);
3342
3343 if (soa_generate_offer(nh->nh_soa, 0, NULL((void*)0)) < 0 ||
3344 session_include_description(nh->nh_soa, 1, msg, sip) < 0) {
3345 if (ss->ss_state < nua_callstate_ready) {
3346 /* XXX - use soa_error_as_sip_reason(nh->nh_soa) */
3347 cr->cr_graceful = 1;
3348 ss->ss_reason = "SIP;cause=400;text=\"Local media failure\"";
3349 }
3350 return nua_client_return(cr, 900, "Local media failed", msg);
3351 }
3352 offer_sent = 1;
3353 }
3354
3355 /* Add session timer headers */
3356 session_timer_preferences(ss->ss_timer,
3357 sip,
3358 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)
,
3359 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)
,
3360 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)))
,
3361 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)
,
3362 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)
);
3363
3364 if (session_timer_is_supported(ss->ss_timer))
3365 session_timer_add_headers(ss->ss_timer, ss->ss_state < nua_callstate_ready,
3366 msg, sip, nh);
3367
3368 retval = nua_base_client_request(cr, msg, sip, NULL((void*)0));
3369
3370 if (retval == 0) {
3371 enum nua_callstate state = ss->ss_state;
3372 cr->cr_offer_sent = offer_sent;
3373 ss->ss_update_needed = 0;
3374
3375 if (state == nua_callstate_ready)
3376 state = nua_callstate_calling; /* XXX */
3377
3378 if (offer_sent)
3379 ss->ss_oa_sent = Offer;
3380
3381 if (!cr->cr_restarting) /* Restart logic calls nua_update_client_report */
3382 signal_call_state_change(nh, ss, 0, "UPDATE sent", state);
3383 }
3384
3385 return retval;
3386}
3387
3388static int nua_update_client_response(nua_client_request_t *cr,
3389 int status, char const *phrase,
3390 sip_t const *sip)
3391{
3392 nua_handle_t *nh = cr->cr_owner;
3393 nua_dialog_usage_t *du = cr->cr_usage;
3394 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
3395 int uas;
3396
3397 assert(200 <= status)((void) sizeof ((200 <= status) ? 1 : 0), __extension__ ({
if (200 <= status) ; else __assert_fail ("200 <= status"
, "nua_session.c", 3397, __extension__ __PRETTY_FUNCTION__); }
))
;
3398
3399 if (ss && sip && status < 300) {
3400 if (session_timer_is_supported(ss->ss_timer)) {
3401 nua_server_request_t *sr;
3402
3403 for (sr = nh->nh_ds->ds_sr; sr; sr = sr->sr_next)
3404 if (sr->sr_method == sip_method_invite ||
3405 sr->sr_method == sip_method_update)
3406 break;
3407
3408 if (!sr && (!du->du_cr || !du->du_cr->cr_orq)) {
3409 session_timer_store(ss->ss_timer, sip);
3410 session_timer_set(ss, uas = 0);
3411 }
3412 }
3413 }
3414
3415 return nua_session_client_response(cr, status, phrase, sip);
3416}
3417
3418/** @NUA_EVENT nua_r_update
3419 *
3420 * Answer to outgoing UPDATE.
3421 *
3422 * The UPDATE may be sent explicitly by nua_update() or
3423 * implicitly by NUA state machine.
3424 *
3425 * @param status response status code
3426 * (if the request is retried, @a status is 100, the @a
3427 * sip->sip_status->st_status contain the real status code
3428 * from the response message, e.g., 302, 401, or 407)
3429 * @param phrase a short textual description of @a status code
3430 * @param nh operation handle associated with the call
3431 * @param hmagic application context associated with the call
3432 * @param sip response to UPDATE request or NULL upon an error
3433 * (status code is in @a status and
3434 * descriptive message in @a phrase parameters)
3435 * @param tags empty
3436 *
3437 * @sa @ref nua_call_model, @RFC3311, nua_update(), #nua_i_update
3438 *
3439 * @END_NUA_EVENT
3440 */
3441
3442static int nua_update_client_report(nua_client_request_t *cr,
3443 int status, char const *phrase,
3444 sip_t const *sip,
3445 nta_outgoing_t *orq,
3446 tagi_t const *tags)
3447{
3448 nua_handle_t *nh = cr->cr_owner;
3449 nua_dialog_usage_t *du = cr->cr_usage;
3450 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
3451
3452 nua_stack_event(nh->nh_nua, nh,
3453 nta_outgoing_getresponse(orq),
3454 (enum nua_event_e)cr->cr_event,
3455 status, phrase,
3456 tags);
3457
3458 if (!ss || cr->cr_terminated || cr->cr_graceful || cr->cr_waiting)
3459 return 1;
3460
3461 if (cr->cr_offer_sent) {
3462 unsigned next_state = ss->ss_state;
3463
3464 if (status < 200)
3465 ;
3466 else if (nua_invite_client_should_ack(du->du_cr)) {
3467 /* There is an un-ACK-ed INVITE there */
3468 assert(du->du_cr->cr_method == sip_method_invite)((void) sizeof ((du->du_cr->cr_method == sip_method_invite
) ? 1 : 0), __extension__ ({ if (du->du_cr->cr_method ==
sip_method_invite) ; else __assert_fail ("du->du_cr->cr_method == sip_method_invite"
, "nua_session.c", 3468, __extension__ __PRETTY_FUNCTION__); }
))
;
3469
3470 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)
||
3471 /* Auto-ACK response to re-INVITE when media is enabled
3472 and auto_ack is not set to 0 on handle */
3473 (ss->ss_state == nua_callstate_ready && nh->nh_soa &&
3474 !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
)
)) {
3475 if (nua_invite_client_ack(du->du_cr, NULL((void*)0)) > 0)
3476 next_state = nua_callstate_ready;
3477 else
3478 next_state = nua_callstate_terminating;
3479 }
3480 }
3481
3482 signal_call_state_change(nh, ss, status, phrase, (enum nua_callstate)next_state);
3483 }
3484
3485 return 1;
3486}
3487
3488/* ---------------------------------------------------------------------- */
3489/* UPDATE server */
3490
3491int nua_update_server_init(nua_server_request_t *sr);
3492int nua_update_server_respond(nua_server_request_t *sr, tagi_t const *tags);
3493int nua_update_server_report(nua_server_request_t *, tagi_t const *);
3494
3495nua_server_methods_t const nua_update_server_methods =
3496 {
3497 SIP_METHOD_UPDATEsip_method_update, "UPDATE",
3498 nua_i_update, /* Event */
3499 {
3500 0, /* Do not create dialog */
3501 1, /* In-dialog request */
3502 1, /* Target refresh request */
3503 1, /* Add Contact */
3504 },
3505 nua_update_server_init,
3506 nua_base_server_preprocess((void*)0),
3507 nua_base_server_params((void*)0),
3508 nua_update_server_respond,
3509 nua_update_server_report,
3510 };
3511
3512int nua_update_server_init(nua_server_request_t *sr)
3513{
3514 nua_handle_t *nh = sr->sr_owner;
3515 nua_session_usage_t *ss;
3516
3517 sip_t const *request = sr->sr_request.sip;
3518
3519 if (nua_session_server_init(sr))
1
Taking false branch
3520 return sr->sr_status;
3521
3522 ss = nua_dialog_usage_private(sr->sr_usage)((sr->sr_usage) ? (void*)((sr->sr_usage) + 1) : ((void*
)0))
;
3523
3524 /* Do session timer negotiation */
3525 if (request->sip_session_expires)
2
Assuming the condition is true
3
Taking true branch
3526 session_timer_store(ss->ss_timer, request);
4
Passing null pointer value via 1st parameter 't'
5
Calling 'session_timer_store'
3527
3528 if (sr->sr_sdp) { /* Check for overlap */
3529 nua_client_request_t *cr;
3530 nua_server_request_t *sr0;
3531 int overlap = 0;
3532
3533 /*
3534 A UAS that receives an UPDATE before it has generated a final
3535 response to a previous UPDATE on the same dialog MUST return a 500
3536 response to the new UPDATE, and MUST include a Retry-After header
3537 field with a randomly chosen value between 0 and 10 seconds.
3538
3539 If an UPDATE is received that contains an offer, and the UAS has
3540 generated an offer (in an UPDATE, PRACK or INVITE) to which it has
3541 not yet received an answer, the UAS MUST reject the UPDATE with a 491
3542 response. Similarly, if an UPDATE is received that contains an
3543 offer, and the UAS has received an offer (in an UPDATE, PRACK, or
3544 INVITE) to which it has not yet generated an answer, the UAS MUST
3545 reject the UPDATE with a 500 response, and MUST include a Retry-After
3546 header field with a randomly chosen value between 0 and 10 seconds.
3547 */
3548 for (cr = nh->nh_ds->ds_cr; cr; cr = cr->cr_next)
3549 if ((overlap = cr->cr_offer_sent && !cr->cr_answer_recv))
3550 break;
3551
3552 if (!overlap)
3553 for (sr0 = nh->nh_ds->ds_sr; sr0; sr0 = sr0->sr_next)
3554 if ((overlap = sr0->sr_offer_recv && !sr0->sr_answer_sent))
3555 break;
3556
3557 if (nh->nh_soa && overlap) {
3558 return nua_server_retry_after(sr, 500, "Overlapping Offer/Answer", 1, 9);
3559 }
3560
3561 if (nh->nh_soa &&
3562 soa_set_remote_sdp(nh->nh_soa, NULL((void*)0), sr->sr_sdp, sr->sr_sdp_len) < 0) {
3563 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__, 3564, "nua(%p): %s server: error parsing %s\n"
, (void *)nh, "UPDATE", Offer)) : (void)0)
3564 "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__, 3564, "nua(%p): %s server: error parsing %s\n"
, (void *)nh, "UPDATE", Offer)) : (void)0)
;
3565 return
3566 sr->sr_status = soa_error_as_sip_response(nh->nh_soa, &sr->sr_phrase);
3567 }
3568
3569 sr->sr_offer_recv = 1;
3570 ss ? ss->ss_oa_recv = Offer : Offer;
3571 }
3572
3573 return 0;
3574}
3575
3576/** @internal Respond to an UPDATE request.
3577 *
3578 */
3579int nua_update_server_respond(nua_server_request_t *sr, tagi_t const *tags)
3580{
3581 nua_handle_t *nh = sr->sr_owner;
3582 nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage)((sr->sr_usage) ? (void*)((sr->sr_usage) + 1) : ((void*
)0))
;
3583 msg_t *msg = sr->sr_response.msg;
3584 sip_t *sip = sr->sr_response.sip;
3585
3586 if (200 <= sr->sr_status && sr->sr_status < 300 && sr->sr_sdp) {
3587 if (nh->nh_soa == NULL((void*)0)) {
3588 sr->sr_answer_sent = 1, ss ? ss->ss_oa_sent = Answer : Answer;
3589 }
3590 else if (soa_generate_answer(nh->nh_soa, NULL((void*)0)) < 0) {
3591 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__, 3592, "nua(%p): %s server: %s %s\n"
, (void *)nh, "UPDATE", "error processing", Offer)) : (void)0
)
3592 (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__, 3592, "nua(%p): %s server: %s %s\n"
, (void *)nh, "UPDATE", "error processing", Offer)) : (void)0
)
;
3593 sr->sr_status = soa_error_as_sip_response(nh->nh_soa, &sr->sr_phrase);
3594 }
3595 else if (soa_activate(nh->nh_soa, NULL((void*)0)) < 0) {
3596 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__, 3597, "nua(%p): %s server: error activating media\n"
, (void *)nh, "UPDATE")) : (void)0)
3597 (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__, 3597, "nua(%p): %s server: error activating media\n"
, (void *)nh, "UPDATE")) : (void)0)
;
3598 /* XXX */
3599 }
3600 else if (session_include_description(nh->nh_soa, 1, msg, sip) < 0) {
3601 sr_status(sr, SIP_500_INTERNAL_SERVER_ERROR500, sip_500_Internal_server_error);
3602 }
3603 else {
3604 sr->sr_answer_sent = 1;
3605 if (ss) {
3606 ss->ss_oa_sent = Answer;
3607 ss->ss_sdp_version = soa_get_user_version(nh->nh_soa);
3608 }
3609 }
3610 }
3611
3612 if (ss && 200 <= sr->sr_status && sr->sr_status < 300) {
3613 session_timer_preferences(ss->ss_timer,
3614 sip,
3615 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)
,
3616 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)
,
3617 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)))
,
3618 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)
,
3619 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)
);
3620
3621 if (session_timer_is_supported(ss->ss_timer)) {
3622 nua_server_request_t *sr0;
3623 int uas;
3624
3625 session_timer_add_headers(ss->ss_timer, 0, msg, sip, nh);
3626
3627 for (sr0 = nh->nh_ds->ds_sr; sr0; sr0 = sr0->sr_next)
3628 if (sr0->sr_method == sip_method_invite)
3629 break;
3630
3631 if (!sr0 && (!sr->sr_usage->du_cr || !sr->sr_usage->du_cr->cr_orq))
3632 session_timer_set(ss, uas = 1);
3633 }
3634 }
3635
3636 return nua_base_server_respond(sr, tags);
3637}
3638
3639/** @NUA_EVENT nua_i_update
3640 *
3641 * @brief Incoming session UPDATE request.
3642 *
3643 * @param status statuscode of response sent automatically by stack
3644 * @param phrase a short textual description of @a status code
3645 * @param nh operation handle associated with the call
3646 * @param hmagic application context associated with the call
3647 * @param sip incoming UPDATE request
3648 * @param tags empty
3649 *
3650 * @sa nua_update(), #nua_r_update, #nua_i_state
3651 *
3652 * @END_NUA_EVENT
3653 */
3654
3655int nua_update_server_report(nua_server_request_t *sr, tagi_t const *tags)
3656{
3657 nua_handle_t *nh = sr->sr_owner;
3658 nua_dialog_usage_t *du = sr->sr_usage;
3659 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
3660 int status = sr->sr_status; char const *phrase = sr->sr_phrase;
3661 int offer_recv_or_answer_sent = sr->sr_offer_recv || sr->sr_answer_sent;
3662 int retval;
3663
3664 retval = nua_base_server_report(sr, tags), sr = NULL((void*)0); /* destroys sr */
3665
3666 if (retval >= 2 || ss == NULL((void*)0)) {
3667#if 0
3668 signal_call_state_change(nh, NULL((void*)0), status, phrase,
3669 nua_callstate_terminated);
3670#endif
3671 return retval;
3672 }
3673
3674 if (offer_recv_or_answer_sent) {
3675 /* signal offer received, answer sent */
3676 enum nua_callstate state = ss->ss_state;
3677
3678 if (state == nua_callstate_ready && status < 200)
3679 state = nua_callstate_received;
3680
3681 signal_call_state_change(nh, ss, status, phrase, state);
3682 }
3683
3684 if (200 <= status && status < 300
3685 && ss->ss_state < nua_callstate_ready
3686 && ss->ss_precondition
3687 && !ss->ss_alerting
3688 && 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)
) {
3689 nua_server_request_t *sri;
3690
3691 for (sri = nh->nh_ds->ds_sr; sri; sri = sri->sr_next)
3692 if (sri->sr_method == sip_method_invite &&
3693 nua_server_request_is_pending(sri))
3694 break;
3695
3696 if (sri) {
3697 SR_STATUS1(sri, SIP_180_RINGING)sr_status(sri, 180, sip_180_Ringing);
3698 nua_server_respond(sri, NULL((void*)0));
3699 nua_server_report(sri);
3700 }
3701 }
3702
3703 return retval;
3704}
3705
3706/* ======================================================================== */
3707/* BYE */
3708
3709/**@fn void nua_bye(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
3710 *
3711 * Hangdown a call.
3712 *
3713 * Hangdown a call using SIP BYE method. Also the media session
3714 * associated with the call is terminated.
3715 *
3716 * @param nh Pointer to operation handle
3717 * @param tag, value, ... List of tagged parameters
3718 *
3719 * @return
3720 * nothing
3721 *
3722 * @par Related Tags:
3723 * none
3724 *
3725 * @par Events:
3726 * #nua_r_bye \n
3727 * #nua_i_media_error
3728 */
3729
3730static int nua_bye_client_init(nua_client_request_t *cr,
3731 msg_t *msg, sip_t *sip,
3732 tagi_t const *tags);
3733static int nua_bye_client_request(nua_client_request_t *cr,
3734 msg_t *msg, sip_t *sip,
3735 tagi_t const *tags);
3736static int nua_bye_client_response(nua_client_request_t *cr,
3737 int status, char const *phrase,
3738 sip_t const *sip);
3739static int nua_bye_client_report(nua_client_request_t *cr,
3740 int status, char const *phrase,
3741 sip_t const *sip,
3742 nta_outgoing_t *orq,
3743 tagi_t const *tags);
3744
3745nua_client_methods_t const nua_bye_client_methods = {
3746 SIP_METHOD_BYEsip_method_bye, "BYE", /* crm_method, crm_method_name */
3747 0, /* crm_extrasize */
3748 { /* crm_flags */
3749 /* create_dialog */ 0,
3750 /* in_dialog */ 1,
3751 /* target refresh */ 0
3752 },
3753 NULL((void*)0), /* crm_template */
3754 nua_bye_client_init, /* crm_init */
3755 nua_bye_client_request, /* crm_send */
3756 NULL((void*)0), /* crm_check_restart */
3757 nua_bye_client_response, /* crm_recv */
3758 NULL((void*)0), /* crm_preliminary */
3759 nua_bye_client_report, /* crm_report */
3760 NULL((void*)0), /* crm_complete */
3761};
3762
3763int
3764nua_stack_bye(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags)
3765{
3766 nua_session_usage_t *ss = nua_session_usage_for_dialog(nh->nh_ds);
3767
3768 if (ss &&
3769 nua_callstate_calling <= ss->ss_state &&
3770 ss->ss_state <= nua_callstate_proceeding)
3771 return nua_client_create(nh, e, &nua_cancel_client_methods, tags);
3772 else
3773 return nua_client_create(nh, e, &nua_bye_client_methods, tags);
3774}
3775
3776static int nua_bye_client_init(nua_client_request_t *cr,
3777 msg_t *msg, sip_t *sip,
3778 tagi_t const *tags)
3779{
3780 nua_handle_t *nh = cr->cr_owner;
3781 nua_dialog_usage_t *du = nua_dialog_usage_for_session(nh->nh_ds);
3782 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
3783
3784 if (!ss || (ss->ss_state >= nua_callstate_terminating && !cr->cr_auto))
3785 return nua_client_return(cr, 900, "Invalid handle for BYE", msg);
3786
3787 if (!cr->cr_auto)
3788 /* Implicit state transition by nua_bye() */
3789 ss->ss_state = nua_callstate_terminating;
3790
3791 if (nh->nh_soa)
3792 soa_terminate(nh->nh_soa, 0);
3793
3794 nua_client_bind(cr, du);
3795
3796 return 0;
3797}
3798
3799static int nua_bye_client_request(nua_client_request_t *cr,
3800 msg_t *msg, sip_t *sip,
3801 tagi_t const *tags)
3802{
3803 nua_dialog_usage_t *du = cr->cr_usage;
3804 nua_session_usage_t *ss;
3805 char const *reason = NULL((void*)0);
3806
3807 int error;
3808 nua_server_request_t *sr;
3809
3810 if (du == NULL((void*)0))
3811 return nua_client_return(cr, SIP_481_NO_TRANSACTION481, sip_481_No_transaction, msg);
3812
3813 ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
3814 reason = ss->ss_reason;
3815
3816 error = nua_base_client_trequest(cr, msg, sip,
3817 SIPTAG_REASON_STR(reason)siptag_reason_str, tag_str_v(reason),
3818 TAG_NEXT(tags)tag_next, (tag_value_t)(tags));
3819
3820 if (error == 0) {
3821 nua_dialog_usage_reset_refresh(du);
3822 ss->ss_timer->timer_set = 0;
3823
3824 /* Terminate server transactions associated with session, too. */
3825 for (sr = du->du_dialog->ds_sr; sr; sr = sr->sr_next) {
3826 if (sr->sr_usage == du && nua_server_request_is_pending(sr) &&
3827 sr->sr_method != sip_method_bye) {
3828 sr_status(sr, SIP_486_BUSY_HERE486, sip_486_Busy_here);
3829 nua_server_respond(sr, 0);
3830 }
3831 }
3832 }
3833
3834 return error;
3835}
3836static int nua_bye_client_response(nua_client_request_t *cr,
3837 int status, char const *phrase,
3838 sip_t const *sip) {
3839
3840 nua_dialog_usage_t *du = cr->cr_usage;
3841 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
3842
3843 if (ss && ss->ss_reporting && status >= 900)
3844 return 1;
3845
3846 return nua_base_client_response(cr, status, phrase, sip, NULL((void*)0));
3847}
3848
3849/** @NUA_EVENT nua_r_bye
3850 *
3851 * Answer to outgoing BYE.
3852 *
3853 * The BYE may be sent explicitly by nua_bye() or implicitly by NUA state
3854 * machine.
3855 *
3856 * @param status response status code
3857 * (if the request is retried, @a status is 100, the @a
3858 * sip->sip_status->st_status contain the real status code
3859 * from the response message, e.g., 302, 401, or 407)
3860 * @param phrase a short textual description of @a status code
3861 * @param nh operation handle associated with the call
3862 * @param hmagic application context associated with the call
3863 * @param sip response to BYE request or NULL upon an error
3864 * (status code is in @a status and
3865 * descriptive message in @a phrase parameters)
3866 * @param tags empty
3867 *
3868 * @sa nua_bye(), @ref nua_call_model, #nua_i_state, #nua_r_invite()
3869 *
3870 * @END_NUA_EVENT
3871 */
3872
3873static int nua_bye_client_report(nua_client_request_t *cr,
3874 int status, char const *phrase,
3875 sip_t const *sip,
3876 nta_outgoing_t *orq,
3877 tagi_t const *tags)
3878{
3879 nua_handle_t *nh = cr->cr_owner;
3880 nua_dialog_usage_t *du = cr->cr_usage;
3881
3882 nua_stack_event(nh->nh_nua, nh,
3883 nta_outgoing_getresponse(orq),
3884 (enum nua_event_e)cr->cr_event,
3885 status, phrase,
3886 tags);
3887
3888 if (du == NULL((void*)0)) {
3889 /* No more session */
3890 }
3891 else if (status < 200) {
3892 /* Preliminary */
3893 }
3894 else {
3895 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
3896 nua_client_request_t *cri;
3897
3898 if (ss->ss_reporting) {
3899 return 1; /* Somebody else's problem */
3900 }
3901 else if (cr->cr_waiting) {
3902 return 1; /* Application problem */
3903 }
3904
3905 nua_client_bind(cr, NULL((void*)0));
3906
3907 signal_call_state_change(nh, ss, status, "to BYE",
3908 nua_callstate_terminated);
3909
3910 for (cri = du->du_dialog->ds_cr; cri; cri = cri->cr_next) {
3911 if (cri->cr_method == sip_method_invite)
3912 break;
3913 }
3914
3915 if (!cri || cri->cr_status >= 200) {
3916 /* INVITE is completed, we can zap the session... */;
3917 nua_session_usage_destroy(nh, ss);
3918 }
3919 }
3920
3921 return 1;
3922}
3923
3924/** @NUA_EVENT nua_i_bye
3925 *
3926 * Incoming BYE request, call hangup.
3927 *
3928 * @param status statuscode of response sent automatically by stack
3929 * @param phrase a short textual description of @a status code
3930 * @param nh operation handle associated with the call
3931 * @param hmagic application context associated with the call
3932 * @param sip pointer to BYE request
3933 * @param tags empty
3934 *
3935 * @sa @ref nua_call_model, #nua_i_state, nua_bye(), nua_bye(), #nua_r_cancel
3936 *
3937 * @END_NUA_EVENT
3938 */
3939
3940int nua_bye_server_init(nua_server_request_t *sr);
3941int nua_bye_server_report(nua_server_request_t *sr, tagi_t const *tags);
3942
3943nua_server_methods_t const nua_bye_server_methods =
3944 {
3945 SIP_METHOD_BYEsip_method_bye, "BYE",
3946 nua_i_bye, /* Event */
3947 {
3948 0, /* Do not create dialog */
3949 1, /* In-dialog request */
3950 0, /* Not a target refresh request */
3951 0, /* Do not add Contact */
3952 },
3953 nua_bye_server_init,
3954 nua_base_server_preprocess((void*)0),
3955 nua_base_server_params((void*)0),
3956 nua_base_server_respond,
3957 nua_bye_server_report,
3958 };
3959
3960
3961int nua_bye_server_init(nua_server_request_t *sr)
3962{
3963 nua_handle_t *nh = sr->sr_owner;
3964 nua_dialog_usage_t *du = nua_dialog_usage_for_session(nh->nh_ds);
3965
3966 sr->sr_terminating = 1;
3967
3968 if (du)
3969 sr->sr_usage = du;
3970 else
3971 return SR_STATUS(sr, 481, "No Such Call")((sr)->sr_phrase = ("No Such Call"), (sr)->sr_status = (
481))
;
3972
3973 return 0;
3974}
3975
3976int nua_bye_server_report(nua_server_request_t *sr, tagi_t const *tags)
3977{
3978 nua_handle_t *nh = sr->sr_owner;
3979 nua_dialog_usage_t *du = sr->sr_usage;
3980 nua_session_usage_t *ss = nua_dialog_usage_private(du)((du) ? (void*)((du) + 1) : ((void*)0));
3981 int early = 0, retval;
3982
3983 if (sr->sr_status < 200)
3984 return nua_base_server_report(sr, tags);
3985
3986 if (ss) {
3987 nua_server_request_t *sr0 = NULL((void*)0), *sr_next;
3988 char const *phrase;
3989
3990 early = ss->ss_state < nua_callstate_ready;
3991 phrase = early ? "Early Session Terminated" : "Session Terminated";
3992
3993#if 0
3994 sr->sr_usage = NULL((void*)0);
3995#endif
3996
3997 for (sr0 = nh->nh_ds->ds_sr; sr0; sr0 = sr_next) {
3998 sr_next = sr0->sr_next;
3999
4000 if (sr == sr0 || sr0->sr_usage != sr->sr_usage)
4001 continue;
4002
4003 if (nua_server_request_is_pending(sr0)) {
4004 SR_STATUS(sr0, 487, phrase)((sr0)->sr_phrase = (phrase), (sr0)->sr_status = (487));
4005 nua_server_respond(sr0, NULL((void*)0));
4006 }
4007 nua_server_request_destroy(sr0);
4008 }
4009
4010 sr->sr_phrase = phrase;
4011 }
4012
4013 retval = nua_base_server_report(sr, tags);
4014
4015 //assert(2 <= retval && retval < 4);
4016
4017#if 0
4018 if (ss) {
4019 signal_call_state_change(nh, ss, 200,
4020 early ? "Received early BYE" : "Received BYE",
4021 nua_callstate_terminated);
4022 nua_dialog_usage_remove(nh, nh->nh_ds, du);
4023 }
4024#endif
4025
4026 return retval;
4027}
4028
4029/* ---------------------------------------------------------------------- */
4030
4031/** @NUA_EVENT nua_i_state
4032 *
4033 * @brief Call state has changed.
4034 *
4035 * This event will be sent whenever the call state changes.
4036 *
4037 * In addition to basic changes of session status indicated with enum
4038 * ::nua_callstate, the @RFC3264 SDP Offer/Answer negotiation status is also
4039 * included. The tags NUTAG_OFFER_RECV() or NUTAG_ANSWER_RECV() indicate
4040 * whether the remote SDP that was received was considered as an offer or an
4041 * answer. Tags NUTAG_OFFER_SENT() or NUTAG_ANSWER_SENT() indicate whether
4042 * the local SDP which was sent was considered as an offer or answer.
4043 *
4044 * If the @b soa SDP negotiation is enabled (by default or with
4045 * NUTAG_MEDIA_ENABLE(1)), the received remote SDP is included in tags
4046 * SOATAG_REMOTE_SDP() and SOATAG_REMOTE_SDP_STR(). The SDP negotiation
4047 * result from @b soa is included in the tags SOATAG_LOCAL_SDP() and
4048 * SOATAG_LOCAL_SDP_STR().
4049 *
4050 * SOATAG_ACTIVE_AUDIO() and SOATAG_ACTIVE_VIDEO() are informational tags
4051 * used to indicate what is the status of audio or video.
4052 *
4053 * Note that #nua_i_state also covers the information relayed in call
4054 * establisment (#nua_i_active) and termination (#nua_i_terminated) events.
4055 *
4056 * @param status protocol status code \n
4057 * (always present)
4058 * @param phrase short description of status code \n
4059 * (always present)
4060 * @param nh operation handle associated with the call
4061 * @param hmagic application context associated with the call
4062 * @param sip NULL
4063 * @param tags NUTAG_CALLSTATE(),
4064 * SOATAG_LOCAL_SDP(), SOATAG_LOCAL_SDP_STR(),
4065 * NUTAG_OFFER_SENT(), NUTAG_ANSWER_SENT(),
4066 * SOATAG_REMOTE_SDP(), SOATAG_REMOTE_SDP_STR(),
4067 * NUTAG_OFFER_RECV(), NUTAG_ANSWER_RECV(),
4068 * SOATAG_ACTIVE_AUDIO(), SOATAG_ACTIVE_VIDEO(),
4069 * SOATAG_ACTIVE_IMAGE(), SOATAG_ACTIVE_CHAT().
4070 *
4071 * @sa @ref nua_call_model, #nua_i_active, #nua_i_terminated,
4072 * nua_invite(), #nua_r_invite, #nua_i_invite, nua_respond(),
4073 * NUTAG_MEDIA_ENABLE(),
4074 * NUTAG_AUTOALERT(), NUTAG_AUTOANSWER(), NUTAG_EARLY_MEDIA(),
4075 * NUTAG_EARLY_ANSWER(), NUTAG_INCLUDE_EXTRA_SDP(),
4076 * nua_ack(), NUTAG_AUTOACK(), nua_bye(), #nua_r_bye, #nua_i_bye,
4077 * nua_cancel(), #nua_r_cancel, #nua_i_cancel,
4078 * nua_prack(), #nua_r_prack, #nua_i_prack,
4079 * nua_update(), #nua_r_update, #nua_i_update
4080 *
4081 * @par History
4082 * Prior @VERSION_1_12_6 the tags NUTAG_OFFER_RECV(), NUTAG_ANSWER_RECV(),
4083 * NUTAG_ANSWER_SENT(), NUTAG_OFFER_SENT() were not included with
4084 * nua_i_state eventif media was disabled.
4085 *
4086 * @END_NUA_EVENT
4087 */
4088
4089/**
4090 * Delivers call state changed event to the nua client. @internal
4091 *
4092 * @param nh call handle
4093 * @param status status code
4094 * @param tr_event SIP transaction event triggering this change
4095 * @param oa_recv Received SDP
4096 * @param oa_sent Sent SDP
4097 */
4098
4099static void signal_call_state_change(nua_handle_t *nh,
4100 nua_session_usage_t *ss,
4101 int status, char const *phrase,
4102 enum nua_callstate next_state)
4103{
4104 enum nua_callstate ss_state = nua_callstate_init;
4105 enum nua_callstate invite_state = next_state;
4106
4107 char const *oa_recv = NULL((void*)0);
4108 char const *oa_sent = NULL((void*)0);
4109
4110 int offer_recv = 0, answer_recv = 0, offer_sent = 0, answer_sent = 0;
4111
4112 if (ss) {
4113 if (ss->ss_reporting)
4114 return;
4115
4116 ss_state = ss->ss_state;
4117 oa_recv = ss->ss_oa_recv, ss->ss_oa_recv = NULL((void*)0);
4118 oa_sent = ss->ss_oa_sent, ss->ss_oa_sent = NULL((void*)0);
4119
4120 assert(oa_sent == Offer || oa_sent == Answer || oa_sent == NULL)((void) sizeof ((oa_sent == Offer || oa_sent == Answer || oa_sent
== ((void*)0)) ? 1 : 0), __extension__ ({ if (oa_sent == Offer
|| oa_sent == Answer || oa_sent == ((void*)0)) ; else __assert_fail
("oa_sent == Offer || oa_sent == Answer || oa_sent == NULL",
"nua_session.c", 4120, __extension__ __PRETTY_FUNCTION__); }
))
;
4121 assert(oa_recv == Offer || oa_recv == Answer || oa_recv == NULL)((void) sizeof ((oa_recv == Offer || oa_recv == Answer || oa_recv
== ((void*)0)) ? 1 : 0), __extension__ ({ if (oa_recv == Offer
|| oa_recv == Answer || oa_recv == ((void*)0)) ; else __assert_fail
("oa_recv == Offer || oa_recv == Answer || oa_recv == NULL",
"nua_session.c", 4121, __extension__ __PRETTY_FUNCTION__); }
))
;
4122
4123 if (oa_recv) {
4124 offer_recv = oa_recv == Offer;
4125 answer_recv = oa_recv == Answer;
4126 }
4127
4128 if (oa_sent) {
4129 offer_sent = oa_sent == Offer;
4130 answer_sent = oa_sent == Answer;
4131 }
4132 }
4133
4134 if (ss_state < nua_callstate_ready || next_state > nua_callstate_ready)
4135 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__, 4140, "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 (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__, 4140, "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 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__, 4140, "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_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__, 4140, "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 && 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__, 4140, "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 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__, 4140, "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)
;
4141 else
4142 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__, 4146, "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 (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__, 4146, "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_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__, 4146, "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 && 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__, 4146, "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 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__, 4146, "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)
;
4147
4148 if (next_state == nua_callstate_terminating &&
4149 ss_state >= nua_callstate_terminating)
4150 return;
4151
4152 if (ss) {
4153 /* Update state variables */
4154 if (next_state == nua_callstate_init) {
4155 if (ss_state < nua_callstate_ready)
4156 ss->ss_state = next_state;
4157 else if (ss->ss_state == nua_callstate_ready)
4158 next_state = ss->ss_state;
4159 else if (ss->ss_state == nua_callstate_terminating)
4160 return;
4161 else
4162 ss->ss_state = next_state = nua_callstate_terminated;
4163 }
4164 else if (next_state > ss_state)
4165 ss->ss_state = next_state;
4166 }
4167
4168 if (next_state == nua_callstate_init)
4169 next_state = nua_callstate_terminated;
4170
4171 if (ss && ss->ss_state == nua_callstate_ready)
4172 nh->nh_active_call = 1;
4173 else if (next_state == nua_callstate_terminated)
4174 nh->nh_active_call = 0;
4175
4176 /* Send events */
4177 if (phrase == NULL((void*)0))
4178 phrase = "Call state";
4179
4180 {
4181 sdp_session_t const *remote_sdp = NULL((void*)0);
4182 char const *remote_sdp_str = NULL((void*)0);
4183 sdp_session_t const *local_sdp = NULL((void*)0);
4184 char const *local_sdp_str = NULL((void*)0);
4185
4186 if (nh->nh_soa) {
4187 if (oa_recv)
4188 soa_get_remote_sdp(nh->nh_soa, &remote_sdp, &remote_sdp_str, 0);
4189 if (oa_sent)
4190 soa_get_local_sdp(nh->nh_soa, &local_sdp, &local_sdp_str, 0);
4191
4192 if (answer_recv || answer_sent) { /* Update nh_hold_remote */
4193 char const *held = NULL((void*)0);
4194 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);
4195 nh->nh_hold_remote = held && strlen(held) > 0;
4196 }
4197 }
4198 else
4199 oa_recv = NULL((void*)0), oa_sent = NULL((void*)0);
4200
4201 nua_stack_tevent(nh->nh_nua, nh, NULL((void*)0), nua_i_state,
4202 status, phrase,
4203 NUTAG_CALLSTATE(next_state)nutag_callstate, tag_int_v(next_state),
4204 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))
,
4205 /* NUTAG_SOA_SESSION(nh->nh_soa), */
4206 TAG_IF(offer_recv, NUTAG_OFFER_RECV(offer_recv))!(offer_recv) ? tag_skip : nutag_offer_recv, tag_bool_v(offer_recv
)
,
4207 TAG_IF(answer_recv, NUTAG_ANSWER_RECV(answer_recv))!(answer_recv) ? tag_skip : nutag_answer_recv, tag_bool_v(answer_recv
)
,
4208 TAG_IF(offer_sent, NUTAG_OFFER_SENT(offer_sent))!(offer_sent) ? tag_skip : nutag_offer_sent, tag_bool_v(offer_sent
)
,
4209 TAG_IF(answer_sent, NUTAG_ANSWER_SENT(answer_sent))!(answer_sent) ? tag_skip : nutag_answer_sent, tag_bool_v(answer_sent
)
,
4210 TAG_IF(oa_recv, SOATAG_REMOTE_SDP(remote_sdp))!(oa_recv) ? tag_skip : soatag_remote_sdp, sdptag_session_v(remote_sdp
)
,
4211 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
)
,
4212 TAG_IF(oa_sent, SOATAG_LOCAL_SDP(local_sdp))!(oa_sent) ? tag_skip : soatag_local_sdp, sdptag_session_v(local_sdp
)
,
4213 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
)
,
4214 TAG_END()(tag_type_t)0, (tag_value_t)0);
4215 }
4216
4217 if (next_state == nua_callstate_ready && ss_state <= nua_callstate_ready) {
4218 nua_stack_tevent(nh->nh_nua, nh, NULL((void*)0), nua_i_active, status, "Call active",
4219 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))
,
4220 /* NUTAG_SOA_SESSION(nh->nh_soa), */
4221 TAG_END()(tag_type_t)0, (tag_value_t)0);
4222 }
4223
4224 else if (next_state == nua_callstate_terminated) {
4225 nua_stack_event(nh->nh_nua, nh, NULL((void*)0),
4226 nua_i_terminated, status, phrase,
4227 NULL((void*)0));
4228 }
4229
4230 if (invite_state == nua_callstate_ready) {
4231 /* Start next INVITE request, if queued */
4232 nua_client_next_request(nh->nh_ds->ds_cr, 1);
4233 }
4234}
4235
4236/** @NUA_EVENT nua_i_active
4237 *
4238 * A call has been activated.
4239 *
4240 * This event will be sent after a succesful response to the initial
4241 * INVITE has been received and the media has been activated.
4242 *
4243 * @param nh operation handle associated with the call
4244 * @param hmagic application context associated with the call
4245 * @param sip NULL
4246 * @param tags SOATAG_ACTIVE_AUDIO(), SOATAG_ACTIVE_VIDEO(),
4247 * SOATAG_ACTIVE_IMAGE(), SOATAG_ACTIVE_CHAT().
4248 *
4249 * @deprecated Use #nua_i_state instead.
4250 *
4251 * @sa @ref nua_call_model, #nua_i_state, #nua_i_terminated,
4252 * #nua_i_invite
4253 *
4254 * @END_NUA_EVENT
4255 */
4256
4257/** @NUA_EVENT nua_i_terminated
4258 *
4259 * A call has been terminated.
4260 *
4261 * This event will be sent after a call has been terminated. A call is
4262 * terminated, when
4263 * 1) an error response (300..599) is sent to an incoming initial INVITE
4264 * 2) a reliable response (200..299 or reliable preliminary response) to
4265 * an incoming initial INVITE is not acknowledged with ACK or PRACK
4266 * 3) BYE is received or sent
4267 *
4268 * @param nh operation handle associated with the call
4269 * @param hmagic application context associated with the call
4270 * @param sip NULL
4271 * @param tags empty
4272 *
4273 * @deprecated Use #nua_i_state instead.
4274 *
4275 * @sa @ref nua_call_model, #nua_i_state, #nua_i_active, #nua_i_bye,
4276 * #nua_i_invite
4277 *
4278 * @END_NUA_EVENT
4279 */
4280
4281
4282/* ======================================================================== */
4283
4284static
4285int nua_server_retry_after(nua_server_request_t *sr,
4286 int status, char const *phrase,
4287 int min, int max)
4288{
4289 sip_retry_after_t af[1];
4290
4291 sip_retry_after_init(af);
4292 af->af_delta = (unsigned)su_randint(min, max);
4293 af->af_comment = phrase;
4294
4295 sip_add_dup(sr->sr_response.msg, sr->sr_response.sip, (sip_header_t *)af);
4296
4297 return sr_status(sr, status, phrase);
4298}
4299
4300/* ======================================================================== */
4301/* Session timer - RFC 4028 */
4302
4303static int session_timer_is_supported(struct session_timer const *t)
4304{
4305 return t->local.supported;
4306}
4307
4308/** Set session timer preferences */
4309static
4310void session_timer_preferences(struct session_timer *t,
4311 sip_t const *sip,
4312 sip_supported_t const *supported,
4313 unsigned expires,
4314 int isset,
4315 enum nua_session_refresher refresher,
4316 unsigned min_se)
4317{
4318 memset(&t->local, 0, sizeof t->local);
4319
4320 t->local.require = sip_has_feature(sip->sip_require, "timer");
4321 t->local.supported =
4322 sip_has_feature(supported, "timer") ||
4323 sip_has_feature(sip->sip_supported, "timer");
4324 if (isset || refresher != nua_no_refresher)
4325 t->local.expires = expires;
4326 else
4327 t->local.defaults = expires;
4328 t->local.min_se = min_se;
4329 t->local.refresher = refresher;
4330}
4331
4332static int session_timer_check_restart(nua_client_request_t *cr,
4333 int status, char const *phrase,
4334 sip_t const *sip)
4335{
4336 if (status == 422) {
4337 nua_session_usage_t *ss = nua_dialog_usage_private(cr->cr_usage)((cr->cr_usage) ? (void*)((cr->cr_usage) + 1) : ((void*
)0))
;
4338
4339 if (ss && session_timer_is_supported(ss->ss_timer)) {
4340 struct session_timer *t = ss->ss_timer;
4341
4342 if (sip->sip_min_se && t->local.min_se < sip->sip_min_se->min_delta)
4343 t->local.min_se = sip->sip_min_se->min_delta;
4344 if (t->local.expires != 0 && t->local.min_se > t->local.expires)
4345 t->local.expires = t->local.min_se;
4346
4347 return nua_client_restart(cr, 100, "Re-Negotiating Session Timer");
4348 }
4349 }
4350
4351 return nua_base_client_check_restart(cr, status, phrase, sip);
4352}
4353
4354/** Check that received Session-Expires is longer than Min-SE */
4355static
4356int session_timer_check_min_se(msg_t *msg,
4357 sip_t *sip,
4358 sip_t const *request,
4359 unsigned long min)
4360{
4361 if (min == 0)
4362 min = 1;
4363
4364 /*
4365 If an incoming request contains a Supported header field with a value
4366 'timer' and a Session Expires header field, the UAS MAY reject the
4367 INVITE request with a 422 (Session Interval Too Small) response if
4368 the session interval in the Session-Expires header field is smaller
4369 than the minimum interval defined by the UAS' local policy. When
4370 sending the 422 response, the UAS MUST include a Min-SE header field
4371 with the value of its minimum interval. This minimum interval MUST
4372 NOT be lower than 90 seconds.
4373 */
4374 if (request->sip_session_expires &&
4375 sip_has_feature(request->sip_supported, "timer") &&
4376 request->sip_session_expires->x_delta < min) {
4377 sip_min_se_t min_se[1];
4378
4379 if (min < 90)
4380 min = 90;
4381
4382 sip_min_se_init(min_se)->min_delta = min;
4383
4384 /* Include extension parameters, if any */
4385 if (request->sip_min_se)
4386 min_se->min_params = request->sip_min_se->min_params;
4387
4388 sip_add_dup(msg, sip, (sip_header_t *)min_se);
4389
4390 return 422;
4391 }
4392
4393 return 0;
4394}
4395
4396/** Store session timer parameters in request from uac / response from uas */
4397static
4398void session_timer_store(struct session_timer *t,
4399 sip_t const *sip)
4400{
4401 sip_require_t const *require = sip->sip_require;
4402 sip_supported_t const *supported = sip->sip_supported;
4403 sip_session_expires_t const *x = sip->sip_session_expires;
4404
4405 t->remote.require = (require && sip_has_feature(require, "timer"));
6
Assuming 'require' is null
7
Dereference of null pointer
4406 t->remote.supported =
4407 t->remote.supported || (supported && sip_has_feature(supported, "timer"));
4408
4409 t->remote.expires = 0;
4410 t->remote.refresher = nua_any_refresher;
4411 t->remote.min_se = 0;
4412
4413 if (x) {
4414 t->remote.expires = x->x_delta;
4415
4416 if (x->x_refresher) {
4417 int uas = sip->sip_request != NULL((void*)0);
4418
4419 if (su_casenmatch(x->x_refresher, "uac", (sizeof "uac")))
4420 t->remote.refresher = uas ? nua_remote_refresher : nua_local_refresher;
4421 else if (su_casenmatch(x->x_refresher, "uas", (sizeof "uas")))
4422 t->remote.refresher = uas ? nua_local_refresher : nua_remote_refresher;
4423 }
4424 else if (t->remote.require) {
4425 /* Require: timer but no refresher parameter in Session-Expires header */
4426 t->remote.refresher = nua_local_refresher;
4427 }
4428 }
4429
4430 if (sip->sip_min_se)
4431 t->remote.min_se = sip->sip_min_se->min_delta;
4432}
4433
4434/** Add timer feature and Session-Expires/Min-SE headers to request/response
4435 *
4436 */
4437static int
4438session_timer_add_headers(struct session_timer *t,
4439 int initial,
4440 msg_t *msg,
4441 sip_t *sip,
4442 nua_handle_t *nh)
4443{
4444 unsigned long expires, min;
4445 sip_min_se_t min_se[1];
4446 sip_session_expires_t x[1];
4447 int uas;
4448 int autorequire = 1;
4449
4450 enum nua_session_refresher refresher = nua_any_refresher;
4451
4452 static sip_param_t const x_params_uac[] = {"refresher=uac", NULL((void*)0)};
4453 static sip_param_t const x_params_uas[] = {"refresher=uas", NULL((void*)0)};
4454
4455 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)
) {
4456 autorequire = 0;
4457 }
4458
4459 if (!t->local.supported)
4460 return 0;
4461
4462 uas = sip->sip_status != NULL((void*)0);
4463
4464 min = t->local.min_se;
4465 if (min < t->remote.min_se)
4466 min = t->remote.min_se;
4467
4468 if (uas) {
4469 session_timer_negotiate(t, uas = 1);
4470
4471 refresher = t->refresher;
4472 expires = t->interval;
4473 }
4474 else {
4475 /* RFC 4028:
4476 * The UAC MAY include the refresher parameter with value 'uac' if it
4477 * wants to perform the refreshes. However, it is RECOMMENDED that the
4478 * parameter be omitted so that it can be selected by the negotiation
4479 * mechanisms described below.
4480 */
4481 if (t->local.refresher == nua_local_refresher)
4482 refresher = nua_local_refresher;
4483 else if (!initial)
4484 refresher = t->refresher;
4485
4486 expires = t->local.expires;
4487 if (expires != 0 && expires < min)
4488 expires = min;
4489
4490 if (expires == 0 && !initial && t->interval)
4491 expires = t->interval;
4492 }
4493
4494 sip_min_se_init(min_se)->min_delta = min;
4495
4496 sip_session_expires_init(x)->x_delta = expires;
4497 if (refresher == nua_remote_refresher)
4498 x->x_params = uas ? x_params_uac : x_params_uas;
4499 else if (refresher == nua_local_refresher)
4500 x->x_params = uas ? x_params_uas : x_params_uac;
4501
4502 if (expires == 0 && t->remote.min_se == 0)
4503 /* Session timer is not used, do not add headers */
4504 return 1;
4505
4506 sip_add_tl(msg, sip,
4507 TAG_IF(expires != 0, SIPTAG_SESSION_EXPIRES(x))!(expires != 0) ? tag_skip : siptag_session_expires, siptag_session_expires_v
(x)
,
4508 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)
4509 /* 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)
4510 || !initial),!((!uas || sip->sip_status->st_status == 422) &&
(min != 0 || !initial)) ? tag_skip : siptag_min_se, siptag_min_se_v
(min_se)
4511 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)
,
4512 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"
)
,
4513 TAG_END()(tag_type_t)0, (tag_value_t)0);
4514
4515 return 1;
4516}
4517
4518static void
4519session_timer_negotiate(struct session_timer *t, int uas)
4520{
4521 if (!t->local.supported)
4522 t->refresher = nua_no_refresher;
4523 else if (!t->remote.supported)
4524 t->refresher = nua_local_refresher;
4525 else if (t->remote.refresher == nua_local_refresher)
4526 t->refresher = nua_local_refresher;
4527 else if (t->remote.refresher == nua_remote_refresher)
4528 t->refresher = nua_remote_refresher;
4529 else if (uas)
4530 /* UAS defaults UAC to refreshing */
4531 t->refresher = nua_remote_refresher;
4532 else
4533 /* UAC refreshes by itself */
4534 t->refresher = nua_local_refresher;
4535
4536 t->interval = t->remote.expires;
4537 if (t->interval == 0)
4538 t->interval = t->local.expires;
4539 if (t->local.expires != 0 && t->interval > t->local.expires)
4540 t->interval = t->local.expires;
4541 if (t->local.defaults != 0 && t->interval > t->local.defaults)
4542 t->interval = t->local.defaults;
4543
4544 if (t->interval != 0) {
4545 if (t->interval < t->local.min_se)
4546 t->interval = t->local.min_se;
4547 if (t->interval < t->remote.min_se)
4548 t->interval = t->remote.min_se;
4549 }
4550
4551 if (t->interval == 0)
4552 t->refresher = nua_no_refresher;
4553}
4554
4555static void
4556session_timer_set(nua_session_usage_t *ss, int uas)
4557{
4558 nua_dialog_usage_t *du = nua_dialog_usage_public(ss)((ss) ? (nua_dialog_usage_t*)(ss) - 1 : ((void*)0));
4559 struct session_timer *t;
4560
4561 if (ss == NULL((void*)0))
4562 return;
4563
4564 t = ss->ss_timer;
4565
4566 session_timer_negotiate(t, uas);
4567
4568 if (t->refresher == nua_local_refresher) {
4569 unsigned low = t->interval / 2, high = t->interval / 2;
4570
4571 if (t->interval >= 90)
4572 low -=5, high += 5;
4573
4574 nua_dialog_usage_set_refresh_range(du, low, high);
4575 t->timer_set = 1;
4576 }
4577 else if (t->refresher == nua_remote_refresher) {
4578 /* RFC 4028 10.3 and 10.4: Send BYE before the session expires.
4579 Increased interval from 2/3 to 9/10 of session expiration delay
4580 because some endpoints won't UPDATE early enough with very short
4581 sessions (e.g. 120). */
4582
4583 unsigned interval = t->interval;
4584
4585 interval -= 32 > interval / 10 ? interval / 10 : 32;
4586
4587 nua_dialog_usage_set_refresh_range(du, interval, interval);
4588 t->timer_set = 1;
4589 }
4590 else {
4591 nua_dialog_usage_reset_refresh(du);
4592 t->timer_set = 0;
4593 }
4594}
4595
4596/* ======================================================================== */
4597
4598/** Get SDP from a SIP message.
4599 *
4600 * @retval 1 if message contains SDP
4601 * @retval 0 if message does not contain valid SDP
4602 */
4603static
4604int session_get_description(sip_t const *sip,
4605 char const **return_sdp,
4606 size_t *return_len)
4607{
4608 sip_payload_t const *pl = sip->sip_payload;
4609 sip_content_type_t const *ct = sip->sip_content_type;
4610 int matching_content_type = 0;
4611
4612 if (pl == NULL((void*)0))
4613 return 0;
4614 else if (pl->pl_len == 0 || pl->pl_data == NULL((void*)0))
4615 return 0;
4616 else if (ct == NULL((void*)0))
4617 /* Be bug-compatible with our old gateways */
4618 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__, 4619, "nua: no %s, assuming %s\n", "Content-Type"
, nua_application_sdp)) : (void)0)
4619 "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__, 4619, "nua: no %s, assuming %s\n", "Content-Type"
, nua_application_sdp)) : (void)0)
;
4620 else if (ct->c_type == NULL((void*)0))
4621 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__, 4622, "nua: empty %s, assuming %s\n"
, "Content-Type", nua_application_sdp)) : (void)0)
4622 "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__, 4622, "nua: empty %s, assuming %s\n"
, "Content-Type", nua_application_sdp)) : (void)0)
;
4623 else if (!su_casematch(ct->c_type, SDP_MIME_TYPEnua_application_sdp)) {
4624 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__, 4624, "nua: unknown %s: %s\n", "Content-Type"
, ct->c_type)) : (void)0)
;
4625 return 0;
4626 }
4627 else
4628 matching_content_type = 1;
4629
4630 if (pl == NULL((void*)0))
4631 return 0;
4632
4633 if (!matching_content_type) {
4634 /* Make sure we got SDP */
4635 if (pl->pl_len < 3 || !su_casenmatch(pl->pl_data, "v=0", 3))
4636 return 0;
4637 }
4638
4639 if (return_sdp && return_len) {
4640 *return_sdp = pl->pl_data;
4641 *return_len = pl->pl_len;
4642 }
4643
4644 return 1;
4645}
4646
4647/** Insert SDP into SIP message */
4648static
4649int session_include_description(soa_session_t *soa,
4650 int session,
4651 msg_t *msg,
4652 sip_t *sip)
4653{
4654 su_home_t *home = msg_home(msg)((su_home_t*)(msg));
4655
4656 sip_content_disposition_t *cd = NULL((void*)0);
4657 sip_content_type_t *ct = NULL((void*)0);
4658 sip_payload_t *pl = NULL((void*)0);
4659
4660 int retval;
4661
4662 if (!soa)
4663 return 0;
4664
4665 retval = session_make_description(home, soa, session, &cd, &ct, &pl);
4666
4667 if (retval <= 0)
4668 return retval;
4669
4670 if ((cd && sip_header_insert(msg, sip, (sip_header_t *)cd) < 0) ||
4671 sip_header_insert(msg, sip, (sip_header_t *)ct) < 0 ||
4672 sip_header_insert(msg, sip, (sip_header_t *)pl) < 0)
4673 return -1;
4674
4675 return retval;
4676}
4677
4678/** Generate SDP headers */
4679static
4680int session_make_description(su_home_t *home,
4681 soa_session_t *soa,
4682 int session,
4683 sip_content_disposition_t **return_cd,
4684 sip_content_type_t **return_ct,
4685 sip_payload_t **return_pl)
4686{
4687 char const *sdp;
4688 isize_t len;
4689 int retval;
4690
4691 if (!soa)
4692 return 0;
4693
4694 if (session)
4695 retval = soa_get_local_sdp(soa, 0, &sdp, &len);
4696 else
4697 retval = soa_get_capability_sdp(soa, 0, &sdp, &len);
4698
4699 if (retval > 0) {
4700 *return_pl = sip_payload_create(home, sdp, len);
4701 *return_ct = sip_content_type_make(home, SDP_MIME_TYPEnua_application_sdp);
4702 if (session)
4703 *return_cd = sip_content_disposition_make(home, "session");
4704 else
4705 *return_cd = NULL((void*)0);
4706
4707 if (!*return_pl || !*return_ct)
4708 return -1;
4709
4710 if (session && !*return_cd)
4711 return -1;
4712 }
4713
4714 return retval;
4715}
4716
4717/* ====================================================================== */
4718
4719/** @NUA_EVENT nua_i_options
4720 *
4721 * Incoming OPTIONS request. The user-agent should respond to an OPTIONS
4722 * request with the same statuscode as it would respond to an INVITE
4723 * request.
4724 *
4725 * Stack responds automatically to OPTIONS request unless OPTIONS is
4726 * included in the set of application methods, set by NUTAG_APPL_METHOD().
4727 *
4728 * The OPTIONS request does not create a dialog. Currently the processing
4729 * of incoming OPTIONS creates a new handle for each incoming request which
4730 * is not assiciated with an existing dialog. If the handle @a nh is not
4731 * bound, you should probably destroy it after responding to the OPTIONS
4732 * request.
4733 *
4734 * @param status status code of response sent automatically by stack
4735 * @param phrase a short textual description of @a status code
4736 * @param nh operation handle associated with the OPTIONS request
4737 * @param hmagic application context associated with the call
4738 * (NULL if outside session)
4739 * @param sip incoming OPTIONS request
4740 * @param tags empty
4741 *
4742 * @sa nua_respond(), nua_options(), #nua_r_options, @RFC3261 section 11.2
4743 *
4744 * @END_NUA_EVENT
4745 */
4746
4747int nua_options_server_respond(nua_server_request_t *sr, tagi_t const *tags);
4748
4749nua_server_methods_t const nua_options_server_methods =
4750 {
4751 SIP_METHOD_OPTIONSsip_method_options, "OPTIONS",
4752 nua_i_options, /* Event */
4753 {
4754 0, /* Do not create dialog */
4755 0, /* Initial request */
4756 0, /* Not a target refresh request */
4757 1, /* Add Contact */
4758 },
4759 nua_base_server_init((void*)0),
4760 nua_base_server_preprocess((void*)0),
4761 nua_base_server_params((void*)0),
4762 nua_options_server_respond,
4763 nua_base_server_report,
4764 };
4765
4766/** @internal Respond to an OPTIONS request.
4767 *
4768 */
4769int nua_options_server_respond(nua_server_request_t *sr, tagi_t const *tags)
4770{
4771 nua_handle_t *nh = sr->sr_owner;
4772 nua_t *nua = nh->nh_nua;
4773
4774 if (200 <= sr->sr_status && sr->sr_status < 300) {
4775 msg_t *msg = sr->sr_response.msg;
4776 sip_t *sip = sr->sr_response.sip;
4777
4778 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);
4779
4780 if (!sip->sip_payload) { /* XXX - do MIME multipart? */
4781 soa_session_t *soa = nh->nh_soa;
4782
4783 if (soa == NULL((void*)0))
4784 soa = nua->nua_dhandlenua_handles->nh_soa;
4785
4786 session_include_description(soa, 0, msg, sip);
4787 }
4788 }
4789
4790 return nua_base_server_respond(sr, tags);
4791}