Bug Summary

File:libs/sofia-sip/libsofia-sip-ua/sip/sip_util.c
Location:line 260, column 11
Description:Value stored to 's' during its initialization is never read

Annotated Source Code

1/*
2 * This file is part of the Sofia-SIP package
3 *
4 * Copyright (C) 2005 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 sip_util.c
26 *
27 * SIP utility functions.
28 *
29 * @author Pekka Pessi <Pekka.Pessi@nokia.com>.
30 *
31 * @date Created: Tue Jun 13 02:57:51 2000 ppessi
32 */
33
34#include "config.h"
35
36/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
37#define MSG_PUB_Tstruct sip_s struct sip_s
38#define MSG_HDR_Tunion sip_header_u union sip_header_u
39
40#include <sofia-sip/su_alloc.h>
41#include <sofia-sip/su_strlst.h>
42#include <sofia-sip/su_string.h>
43
44#include "sofia-sip/sip_parser.h"
45#include <sofia-sip/sip_header.h>
46#include <sofia-sip/sip_util.h>
47#include <sofia-sip/sip_status.h>
48
49#include <sofia-sip/bnf.h>
50#include <sofia-sip/hostdomain.h>
51
52
53#include <stdio.h>
54#include <stddef.h>
55#include <stdlib.h>
56#include <string.h>
57#include <assert.h>
58#include <float.h>
59#include <limits.h>
60#include <ctype.h>
61
62/**Compare two SIP addresses ( @From or @To headers).
63 *
64 * @retval nonzero if matching.
65 * @retval zero if not matching.
66 */
67int sip_addr_match(sip_addr_t const *a, sip_addr_t const *b)
68{
69 return
70 (a->a_tag == NULL((void*)0) || b->a_tag == NULL((void*)0) ||
71 su_casematch(a->a_tag, b->a_tag))
72 &&
73 su_casematch(a->a_hosta_url->url_host, b->a_hosta_url->url_host)
74 &&
75 su_strmatch(a->a_usera_url->url_user, b->a_usera_url->url_user)
76 &&
77 su_strmatch(a->a_url->url_scheme, b->a_url->url_scheme);
78}
79
80
81/**@ingroup sip_contact
82 *
83 * Create a contact header.
84 *
85 * Create a @Contact header object with the given URL and list of parameters.
86 *
87 * @param home memory home
88 * @param url URL (string or pointer to url_t)
89 * @param p,... NULL-terminated list of @Contact parameters
90 *
91 * @return
92 * A pointer to newly created @Contact header object when successful or NULL
93 * upon an error.
94 *
95 */
96sip_contact_t * sip_contact_create(su_home_t *home,
97 url_string_t const *url,
98 char const *p, ...)
99{
100 su_strlst_t *l;
101 su_home_t *lhome;
102 sip_contact_t *m;
103
104 if (url == NULL((void*)0))
105 return NULL((void*)0);
106
107 l = su_strlst_create_with(NULL((void*)0), "<", NULL((void*)0)), lhome = su_strlst_home(l);
108 if (l == NULL((void*)0))
109 return NULL((void*)0);
110
111 if (url_is_string(url))
112 su_strlst_append(l, (char const *)url);
113 else
114 su_strlst_append(l, url_as_string(lhome, url->us_url));
115
116 su_strlst_append(l, ">");
117
118 if (p) {
119 va_list ap;
120 va_start(ap, p)__builtin_va_start(ap, p);
121
122 for (; p; p = va_arg(ap, char const *)__builtin_va_arg(ap, char const *)) {
123 su_strlst_append(l, ";");
124 su_strlst_append(l, p);
125 }
126
127 va_end(ap)__builtin_va_end(ap);
128 }
129
130 m = sip_contact_make(home, su_strlst_join(l, lhome, ""));
131
132 su_strlst_destroy(l);
133
134 return m;
135}
136
137/** Convert a @Via header to @Contact header.
138 *
139 * The @Contact URI will contain the port number if needed. If transport
140 * protocol name starts with "TLS", "SIPS:" URI schema is used. Transport
141 * parameter is included in the URI unless the transport protocol is UDP.
142 *
143 * @param home memory home
144 * @param v @Via header field structure
145 * (with <sent-protocol> and <sent-by> parameters)
146 * @param user username for @Contact URI (may be NULL)
147 *
148 * @retval contact header structure
149 * @retval NULL upon an error
150 *
151 * @sa sip_contact_create_from_via_with_transport(),
152 * sip_contact_string_from_via()
153 */
154sip_contact_t *
155sip_contact_create_from_via(su_home_t *home,
156 sip_via_t const *v,
157 char const *user)
158{
159 const char *tp;
160
161 if (!v) return NULL((void*)0);
162
163 tp = v->v_protocol;
164
165 if (tp == sip_transport_udp ||
166 su_casematch(tp, sip_transport_udp)) /* Default is UDP */
167 tp = NULL((void*)0);
168
169 return sip_contact_create_from_via_with_transport(home, v, user, tp);
170}
171
172/** Convert a @Via header to @Contact header.
173 *
174 * The @Contact URI will contain the port number and transport parameters if
175 * needed. If transport protocol name starts with "TLS", "SIPS:" URI schema
176 * is used.
177 *
178 * @param home memory home
179 * @param v @Via header field structure
180 * (with <sent-by> parameter containing host and port)
181 * @param user username for @Contact URI (may be NULL)
182 * @param transport transport name for @Contact URI (may be NULL)
183 *
184 * @retval contact header structure
185 * @retval NULL upon an error
186 *
187 * @sa sip_contact_create_from_via(), sip_contact_string_from_via()
188 */
189sip_contact_t *
190sip_contact_create_from_via_with_transport(su_home_t *home,
191 sip_via_t const *v,
192 char const *user,
193 char const *transport)
194{
195 char *s = sip_contact_string_from_via(NULL((void*)0), v, user, transport);
196 sip_contact_t *m = sip_contact_make(home, s);
197 su_free(NULL((void*)0), s);
198 return m;
199}
200
201/** Convert a @Via header to @Contact URL string.
202 *
203 * The @Contact URI will contain the port number and transport parameters if
204 * needed. If transport protocol name starts with "TLS", "SIPS:" URI schema
205 * is used.
206 *
207 * The contact URI string returned will always have angle brackets ("<" and
208 * ">") around it.
209 *
210 * @param home memory home
211 * @param v @Via header field structure
212 * (with <sent-by> parameter containing host and port)
213 * @param user username for @Contact URI (may be NULL)
214 * @param transport transport name for @Contact URI (may be NULL)
215 *
216 * @retval string containing Contact URI with angle brackets
217 * @retval NULL upon an error
218 */
219char *
220sip_contact_string_from_via(su_home_t *home,
221 sip_via_t const *v,
222 char const *user,
223 char const *transport)
224{
225 const char *host, *port, *maddr, *comp;
226 char const *scheme = "sip:";
227 int one = 1;
228 char _transport[16];
229
230 if (!v) return NULL((void*)0);
231
232 host = v->v_host;
233 if (v->v_received)
234 host = v->v_received;
235 port = sip_via_port(v, &one);
236 maddr = v->v_maddr;
237 comp = v->v_comp;
238
239 if (host == NULL((void*)0))
240 return NULL((void*)0);
241
242 if (sip_transport_has_tls(v->v_protocol) ||
243 sip_transport_has_tls(transport)) {
244 scheme = "sips:";
245 if (port && strcmp(port, SIPS_DEFAULT_SERV)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(port) && __builtin_constant_p ("5061") && (
__s1_len = __builtin_strlen (port), __s2_len = __builtin_strlen
("5061"), (!((size_t)(const void *)((port) + 1) - (size_t)(const
void *)(port) == 1) || __s1_len >= 4) && (!((size_t
)(const void *)(("5061") + 1) - (size_t)(const void *)("5061"
) == 1) || __s2_len >= 4)) ? __builtin_strcmp (port, "5061"
) : (__builtin_constant_p (port) && ((size_t)(const void
*)((port) + 1) - (size_t)(const void *)(port) == 1) &&
(__s1_len = __builtin_strlen (port), __s1_len < 4) ? (__builtin_constant_p
("5061") && ((size_t)(const void *)(("5061") + 1) - (
size_t)(const void *)("5061") == 1) ? __builtin_strcmp (port,
"5061") : (__extension__ ({ const unsigned char *__s2 = (const
unsigned char *) (const char *) ("5061"); int __result = (((
const unsigned char *) (const char *) (port))[0] - __s2[0]); if
(__s1_len > 0 && __result == 0) { __result = (((const
unsigned char *) (const char *) (port))[1] - __s2[1]); if (__s1_len
> 1 && __result == 0) { __result = (((const unsigned
char *) (const char *) (port))[2] - __s2[2]); if (__s1_len >
2 && __result == 0) __result = (((const unsigned char
*) (const char *) (port))[3] - __s2[3]); } } __result; }))) :
(__builtin_constant_p ("5061") && ((size_t)(const void
*)(("5061") + 1) - (size_t)(const void *)("5061") == 1) &&
(__s2_len = __builtin_strlen ("5061"), __s2_len < 4) ? (__builtin_constant_p
(port) && ((size_t)(const void *)((port) + 1) - (size_t
)(const void *)(port) == 1) ? __builtin_strcmp (port, "5061")
: (- (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) (port); int __result = (((const unsigned
char *) (const char *) ("5061"))[0] - __s2[0]); if (__s2_len
> 0 && __result == 0) { __result = (((const unsigned
char *) (const char *) ("5061"))[1] - __s2[1]); if (__s2_len
> 1 && __result == 0) { __result = (((const unsigned
char *) (const char *) ("5061"))[2] - __s2[2]); if (__s2_len
> 2 && __result == 0) __result = (((const unsigned
char *) (const char *) ("5061"))[3] - __s2[3]); } } __result
; })))) : __builtin_strcmp (port, "5061")))); })
== 0)
246 port = NULL((void*)0);
247 if (port || host_is_ip_address(host))
248 transport = NULL((void*)0);
249 }
250 else if (port && strcmp(port, SIP_DEFAULT_SERV)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(port) && __builtin_constant_p ("5060") && (
__s1_len = __builtin_strlen (port), __s2_len = __builtin_strlen
("5060"), (!((size_t)(const void *)((port) + 1) - (size_t)(const
void *)(port) == 1) || __s1_len >= 4) && (!((size_t
)(const void *)(("5060") + 1) - (size_t)(const void *)("5060"
) == 1) || __s2_len >= 4)) ? __builtin_strcmp (port, "5060"
) : (__builtin_constant_p (port) && ((size_t)(const void
*)((port) + 1) - (size_t)(const void *)(port) == 1) &&
(__s1_len = __builtin_strlen (port), __s1_len < 4) ? (__builtin_constant_p
("5060") && ((size_t)(const void *)(("5060") + 1) - (
size_t)(const void *)("5060") == 1) ? __builtin_strcmp (port,
"5060") : (__extension__ ({ const unsigned char *__s2 = (const
unsigned char *) (const char *) ("5060"); int __result = (((
const unsigned char *) (const char *) (port))[0] - __s2[0]); if
(__s1_len > 0 && __result == 0) { __result = (((const
unsigned char *) (const char *) (port))[1] - __s2[1]); if (__s1_len
> 1 && __result == 0) { __result = (((const unsigned
char *) (const char *) (port))[2] - __s2[2]); if (__s1_len >
2 && __result == 0) __result = (((const unsigned char
*) (const char *) (port))[3] - __s2[3]); } } __result; }))) :
(__builtin_constant_p ("5060") && ((size_t)(const void
*)(("5060") + 1) - (size_t)(const void *)("5060") == 1) &&
(__s2_len = __builtin_strlen ("5060"), __s2_len < 4) ? (__builtin_constant_p
(port) && ((size_t)(const void *)((port) + 1) - (size_t
)(const void *)(port) == 1) ? __builtin_strcmp (port, "5060")
: (- (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) (port); int __result = (((const unsigned
char *) (const char *) ("5060"))[0] - __s2[0]); if (__s2_len
> 0 && __result == 0) { __result = (((const unsigned
char *) (const char *) ("5060"))[1] - __s2[1]); if (__s2_len
> 1 && __result == 0) { __result = (((const unsigned
char *) (const char *) ("5060"))[2] - __s2[2]); if (__s2_len
> 2 && __result == 0) __result = (((const unsigned
char *) (const char *) ("5060"))[3] - __s2[3]); } } __result
; })))) : __builtin_strcmp (port, "5060")))); })
== 0 &&
251 (host_is_ip_address(host) || host_has_domain_invalid(host))) {
252 port = NULL((void*)0);
253 }
254
255 if (su_casenmatch(transport, "SIP/2.0/", 8))
256 transport += 8;
257
258 /* Make transport parameter lowercase */
259 if (transport && strlen(transport) < (sizeof _transport)) {
260 char *s = strcpy(_transport, transport);
Value stored to 's' during its initialization is never read
261 short c;
262
263 for (s = _transport; (c = *s) && c != ';'; s++)
264 if (isupper(c)((*__ctype_b_loc ())[(int) ((c))] & (unsigned short int) _ISupper
)
)
265 *s = tolower(c)(__extension__ ({ int __res; if (sizeof (c) > 1) { if (__builtin_constant_p
(c)) { int __c = (c); __res = __c < -128 || __c > 255 ?
__c : (*__ctype_tolower_loc ())[__c]; } else __res = tolower
(c); } else __res = (*__ctype_tolower_loc ())[(int) (c)]; __res
; }))
;
266
267 transport = _transport;
268 }
269
270 return su_strcat_all(home,
271 "<",
272 scheme,
273 user ? user : "", user ? "@" : "",
274 host,
275 SIP_STRLOG(":", port)((port) ? (":") : ""), ((port) ? (port) : ""),
276 SIP_STRLOG(";transport=", transport)((transport) ? (";transport=") : ""), ((transport) ? (transport
) : "")
,
277 SIP_STRLOG(";maddr=", maddr)((maddr) ? (";maddr=") : ""), ((maddr) ? (maddr) : ""),
278 SIP_STRLOG(";comp=", comp)((comp) ? (";comp=") : ""), ((comp) ? (comp) : ""),
279 ">",
280 NULL((void*)0));
281}
282
283/** Check if tranport name refers to TLS */
284int sip_transport_has_tls(char const *transport_name)
285{
286 if (!transport_name)
287 return 0;
288
289 if (transport_name == sip_transport_tls)
290 return 1;
291
292 /* transport name starts with TLS or SIP/2.0/TLS */
293 return
294 su_casenmatch(transport_name, "TLS", 3) ||
295 su_casenmatch(transport_name, sip_transport_tls, 11);
296}
297
298/**Perform sanity check on a SIP message
299 *
300 * Check that the SIP message has all the mandatory fields.
301 *
302 * @param sip SIP message to be checked
303 *
304 * @return
305 * When the SIP message fulfills the minimum requirements, return zero,
306 * otherwise a negative status code.
307 */
308int
309sip_sanity_check(sip_t const *sip)
310{
311 if (!sip ||
312 !((sip->sip_request != NULL((void*)0)) ^ (sip->sip_status != NULL((void*)0))) ||
313 !sip->sip_to ||
314 !sip->sip_from ||
315 !sip->sip_call_id ||
316 !sip->sip_cseq ||
317 !sip->sip_via ||
318 (sip->sip_flags & MSG_FLG_TRUNC))
319 return -1; /* Bad request */
320
321 if (sip->sip_request) {
322 url_t const *ruri = sip->sip_request->rq_url;
323
324 switch (ruri->url_type) {
325 case url_invalid:
326 return -1;
327
328 case url_sip: case url_sips: case url_im: case url_pres:
329 if (!ruri->url_host || strlen(ruri->url_host) == 0)
330 return -1;
331 break;
332
333 case url_tel:
334 if (!ruri->url_user || strlen(ruri->url_user) == 0)
335 return -1;
336 break;
337 }
338
339 if (sip->sip_request->rq_method != sip->sip_cseq->cs_method)
340 return -1;
341
342 if (sip->sip_request->rq_method == sip_method_unknown &&
343 !su_strmatch(sip->sip_request->rq_method_name,
344 sip->sip_cseq->cs_method_name))
345 return -1;
346 }
347
348 return 0;
349}
350
351/** Decode a string containg header field.
352 *
353 * The header object is initialized with the contents of the string. The
354 * string is modified when parsing. The home is used to allocate extra
355 * memory required when parsing, e.g., for parameter list or when there
356 * string contains multiple header fields.
357 *
358 * @deprecated
359 * Use msg_header_make() or header-specific make functions, e.g.,
360 * sip_via_make().
361 *
362 * @retval 0 when successful
363 * @retval -1 upon an error.
364 */
365issize_t sip_header_field_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
366{
367 if (h && s && s[slen] == '\0') {
368 size_t n = span_lws(s);
369 s += n; slen -= n;
370
371 for (n = slen; n >= 1 && IS_LWS(s[n - 1])((s[n - 1]) == ' ' || (s[n - 1]) == '\t' || (s[n - 1]) == '\r'
|| (s[n - 1]) == '\n')
; n--)
372 ;
373
374 s[n] = '\0';
375
376 assert(SIP_HDR_TEST(h))((((h)->sh_common->h_class)) ? (void) (0) : __assert_fail
("((h)->sh_common->h_class)", "sip_util.c", 376, __PRETTY_FUNCTION__
))
;
377
378 return h->sh_classsh_common->h_class->hc_parse(home, h, s, slen);
379 }
380 else
381 return -1;
382}
383
384/** Encode a SIP header contents.
385 *
386 * @deprecated Use msg_header_field_e() instead.
387 */
388issize_t sip_header_field_e(char *b, isize_t bsiz, sip_header_t const *h, int flags)
389{
390 return msg_header_field_e(b, bsiz, h, flags);
391}
392
393/** Convert the header @a h to a string allocated from @a home. */
394char *sip_header_as_string(su_home_t *home, sip_header_t const *h)
395{
396 ssize_t len;
397 char *rv, s[256];
398 ssize_t n;
399
400 if (h == NULL((void*)0))
401 return NULL((void*)0);
402
403 len = sip_header_field_e(s, sizeof(s), h, 0);
404
405 if (len >= 0 && (size_t)len < sizeof(s))
406 return su_strdup(home, s);
407
408 if (len == -1)
409 len = 2 * sizeof(s);
410 else
411 len += 1;
412
413 for (rv = su_alloc(home, len);
414 rv;
415 rv = su_realloc(home, rv, len)) {
416 memset(rv,0,len);
417 n = sip_header_field_e(rv, len, h, 0);
418 if (n > -1 && n + 1 <= len)
419 break;
420 if (n > -1) /* glibc >2.1 */
421 len = n + 1;
422 else /* glibc 2.0 */
423 len *= 2;
424 }
425
426 return rv;
427}
428
429/** Calculate size of a SIP header. */
430isize_t sip_header_size(sip_header_t const *h)
431{
432 assert(h == NULL || h == SIP_NONE || h->sh_class)((h == ((void*)0) || h == ((void const *)-1L) || h->sh_common
->h_class) ? (void) (0) : __assert_fail ("h == ((void*)0) || h == ((void const *)-1L) || h->sh_common->h_class"
, "sip_util.c", 432, __PRETTY_FUNCTION__))
;
433 if (h == NULL((void*)0) || h == SIP_NONE((void const *)-1L))
434 return 0;
435 else
436 return h->sh_classsh_common->h_class->hc_dxtra(h, h->sh_classsh_common->h_class->hc_size);
437}
438
439/** Duplicate a url or make a url out of string.
440 * @deprecated Use url_hdup() instead.
441 */
442url_t *sip_url_dup(su_home_t *home, url_t const *o)
443{
444 return url_hdup(home, o);
445}
446
447/**Calculate Q value.
448 *
449 * Convert q-value string @a q to numeric value
450 * in range (0..1000). Q values are used, for instance, to describe
451 * relative priorities of registered contacts.
452 *
453 * @param q q-value string <code>("1" | "." 1,3DIGIT)</code>
454 *
455 * @return An integer in range 0 .. 1000.
456 */
457unsigned sip_q_value(char const *q)
458{
459 unsigned value = 0;
460
461 if (!q)
462 return 1000;
463 if (q[0] != '0' && q[0] != '.' && q[0] != '1')
464 return 500; /* Garbage... */
465 while (q[0] == '0')
466 q++;
467 if (q[0] >= '1' && q[0] <= '9')
468 return 1000;
469 if (q[0] == '\0')
470 return 0;
471 if (q[0] != '.')
472 return 500; /* Garbage... */
473
474 if (q[1] >= '0' && q[1] <= '9') {
475 value = (q[1] - '0') * 100;
476 if (q[2] >= '0' && q[2] <= '9') {
477 value += (q[2] - '0') * 10;
478 if (q[3] >= '0' && q[3] <= '9') {
479 value += (q[3] - '0');
480 if (q[4] > '5' && q[4] <= '9')
481 /* Round upwards */
482 value += 1;
483 else if (q[4] == '5')
484 value += value & 1; /* Round to even */
485 }
486 }
487 }
488
489 return value;
490}
491
492
493/**@ingroup sip_route
494 *
495 * Get first route header and remove it from its fragment chain.
496 *
497 */
498sip_route_t *sip_route_remove(msg_t *msg, sip_t *sip)
499{
500 sip_route_t *r;
501
502 if ((r = sip->sip_route))
503 msg_header_remove(msg, (msg_pub_t *)sip, (msg_header_t *)r);
504
505 return r;
506}
507
508/**@ingroup sip_route
509 *
510 * Get last route header and remove it from its fragment chain.
511 *
512 */
513sip_route_t *sip_route_pop(msg_t *msg, sip_t *sip)
514{
515 sip_route_t *r;
516
517 for (r = sip->sip_route; r; r = r->r_next)
518 if (r->r_next == NULL((void*)0)) {
519 msg_header_remove(msg, (msg_pub_t *)sip, (msg_header_t *)r);
520 return r;
521 }
522
523 return NULL((void*)0);
524}
525
526
527/**@ingroup sip_route
528 *
529 * Get first route header and rewrite the RequestURI.
530 */
531sip_route_t *sip_route_follow(msg_t *msg, sip_t *sip)
532{
533 if (sip->sip_route) {
534 /* XXX - in case of outbound proxy, route may contain our address */
535
536 sip_route_t *r = sip_route_remove(msg, sip);
537 sip_request_t *rq = sip->sip_request;
538
539 rq = sip_request_create(msg_home(msg)((su_home_t*)(msg)), rq->rq_method, rq->rq_method_name,
540 (url_string_t const *)r->r_url, rq->rq_version);
541 url_strip_transport(rq->rq_url);
542
543 msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)rq);
544
545 return r;
546 }
547 return NULL((void*)0);
548}
549
550/**@ingroup sip_route
551 *
552 * Check if route header has lr param.
553 *
554 * "lr" param can be either URL or header parameter.
555 */
556int
557sip_route_is_loose(sip_route_t const *r)
558{
559 if (!r)
560 return 0;
561 if (r->r_url->url_params)
562 return url_has_param(r->r_url, "lr");
563 else
564 return r->r_params && msg_params_find(r->r_params, "lr") != NULL((void*)0);
565}
566
567/**@ingroup sip_route
568 *
569 * Reverse a route header (@Route, @RecordRoute, @Path, @ServiceRoute).
570 */
571sip_route_t *sip_route_reverse_as(su_home_t *home,
572 msg_hclass_t *hc,
573 sip_route_t const *route)
574{
575 sip_route_t *reverse = NULL((void*)0);
576 sip_route_t r[1], *tmp;
577 sip_route_init(r);
578
579 r->r_common->h_class = hc;
580
581 for (reverse = NULL((void*)0); route; route = route->r_next) {
582 *r->r_url = *route->r_url;
583 /* Fix broken (Record-)Routes without <> */
584 if (r->r_url->url_params == NULL((void*)0)
585 && r->r_params
586 && r->r_params[0]
587 && (r->r_params[0][0] == 'l' || r->r_params[0][0] == 'L')
588 && (r->r_params[0][1] == 'r' || r->r_params[0][1] == 'R')
589 && (r->r_params[0][2] == '=' || r->r_params[0][2] == 0))
590 r->r_url->url_params = route->r_params[0],
591 r->r_params = route->r_params + 1;
592 else
593 r->r_params = route->r_params;
594 tmp = (sip_route_t *)msg_header_dup_as(home, hc, (msg_header_t *)r);
595 if (!tmp)
596 goto error;
597 tmp->r_next = reverse;
598 reverse = tmp;
599 }
600
601 return reverse;
602
603 error:
604 msg_header_free_all(home, (msg_header_t *)reverse);
605 return NULL((void*)0);
606}
607
608
609/**@ingroup sip_route
610 *
611 * Reverse a @Route header.
612 *
613 * Reverse A route header like @RecordRoute or @Path.
614 */
615sip_route_t *sip_route_reverse(su_home_t *home, sip_route_t const *route)
616{
617 return sip_route_reverse_as(home, sip_route_class, route);
618}
619
620
621/**@ingroup sip_route
622 *
623 * Fix and duplicate a route header (@Route, @RecordRoute, @Path, @ServiceRoute).
624 *
625 */
626sip_route_t *sip_route_fixdup_as(su_home_t *home,
627 msg_hclass_t *hc,
628 sip_route_t const *route)
629{
630 sip_route_t *copy = NULL((void*)0);
631 sip_route_t r[1], **rr;
632 sip_route_init(r);
633
634 /* Copy the record route as route */
635 for (rr = &copy; route; route = route->r_next) {
636 *r->r_url = *route->r_url;
637 /* Fix broken (Record-)Routes without <> */
638 if (r->r_url->url_params == NULL((void*)0)
639 && r->r_params
640 && r->r_params[0]
641 && (r->r_params[0][0] == 'l' || r->r_params[0][0] == 'L')
642 && (r->r_params[0][1] == 'r' || r->r_params[0][1] == 'R')
643 && (r->r_params[0][2] == '=' || r->r_params[0][2] == 0))
644 r->r_url->url_params = route->r_params[0],
645 r->r_params = route->r_params + 1;
646 else
647 r->r_params = route->r_params;
648 *rr = (sip_route_t *)msg_header_dup_as(home, hc, (msg_header_t *)r);
649 if (!*rr) goto error;
650 rr = &(*rr)->r_next;
651 }
652
653 return copy;
654
655 error:
656 msg_header_free_all(home, (msg_header_t *)copy);
657 return NULL((void*)0);
658}
659
660
661/**@ingroup sip_route
662 *
663 * Fix and duplicate a @Route header.
664 *
665 * Copy a route header like @RecordRoute or @Path as @Route.
666 *
667 */
668sip_route_t *sip_route_fixdup(su_home_t *home, sip_route_t const *route)
669{
670 return sip_route_fixdup_as(home, sip_route_class, route);
671}
672
673static void sip_fragment_clear_chain(sip_header_t *h)
674{
675 void const *next;
676
677 for (; h; h = h->sh_succsh_common->h_succ) {
678 next = (char *)h->sh_datash_common->h_data + h->sh_lensh_common->h_len;
679
680 sip_fragment_clear(h->sh_common)((h->sh_common)->h_data = ((void*)0), (h->sh_common)
->h_len = 0)
;
681
682 if (!next ||
683 !h->sh_succsh_common->h_succ ||
684 h->sh_nextsh_header_next->shn_next != h->sh_succsh_common->h_succ ||
685 h->sh_succsh_common->h_succ->sh_datash_common->h_data != next ||
686 h->sh_succsh_common->h_succ->sh_lensh_common->h_len)
687 return;
688 }
689}
690
691/**@ingroup sip_route
692 *
693 * Fix @Route header.
694 */
695sip_route_t *sip_route_fix(sip_route_t *route)
696{
697 sip_route_t *r;
698 sip_header_t *h = NULL((void*)0);
699 size_t i;
700
701 for (r = route; r; r = r->r_next) {
702 /* Keep track of first header structure on this header line */
703 if (!h
704 || (char *)h->sh_datash_common->h_data + h->sh_lensh_common->h_len != r->r_common->h_data
705 || r->r_common->h_len)
706 h = (sip_header_t *)r;
707
708 if (r->r_url->url_params == NULL((void*)0)
709 && r->r_params
710 && r->r_params[0]
711 && (r->r_params[0][0] == 'l' || r->r_params[0][0] == 'L')
712 && (r->r_params[0][1] == 'r' || r->r_params[0][1] == 'R')
713 && (r->r_params[0][2] == '=' || r->r_params[0][2] == 0)) {
714 r->r_url->url_params = r->r_params[0];
715
716 for (i = 0; r->r_params[i]; i++)
717 ((char const **)r->r_params)[i] = r->r_params[i + 1];
718
719 sip_fragment_clear_chain(h);
720 }
721 }
722
723 return route;
724}
725
726/**@ingroup sip_via
727 *
728 * Get first via header and remove it from its fragment chain.
729 */
730sip_via_t *sip_via_remove(msg_t *msg, sip_t *sip)
731{
732 sip_via_t *v;
733
734 if (sip == NULL((void*)0))
735 return NULL((void*)0);
736
737 for (v = sip->sip_via; v; v = v->v_next) {
738 sip_fragment_clear(v->v_common)((v->v_common)->h_data = ((void*)0), (v->v_common)->
h_len = 0)
;
739
740 if (v->v_next != (void *)v->v_common->h_succ)
741 break;
742 }
743
744 if ((v = sip->sip_via))
745 msg_header_remove(msg, (msg_pub_t *)sip, (msg_header_t *)v);
746
747 return v;
748}
749
750/** Serialize payload.
751 *
752 * The sip_payload_serialize() adds missing headers to MIME multiparty payload,
753 * encodes them and orders them in header chain. It also calculates the total
754 * length of the payload.
755 */
756unsigned long sip_payload_serialize(msg_t *msg, sip_payload_t *pl)
757{
758 unsigned long total;
759
760 for (total = 0; pl; pl = (sip_payload_t *)pl->pl_next) {
761 total += (unsigned)pl->pl_common->h_len;
762 }
763
764 return total;
765}
766
767/**
768 * Remove extra parameters from an AOR URL.
769 *
770 * The extra parameters listed in the @RFC3261 table 1 include port number,
771 * method, maddr, ttl, transport, lr and headers.
772 *
773 * @note The funtion modifies the @a url and the strings attached to it.
774 *
775 * @retval 0 when successful
776 * @retval -1 upon an error
777 */
778int sip_aor_strip(url_t *url)
779{
780 if (url == NULL((void*)0))
781 return -1;
782
783 url->url_port = NULL((void*)0);
784 url->url_headers = NULL((void*)0);
785
786 if (url->url_params)
787 url_strip_transport(url);
788
789 if (url->url_params)
790 url->url_params =
791 url_strip_param_string((char *)url->url_params, "lr");
792
793 return 0;
794}
795
796/** Compare @SecurityVerify header with @SecurityServer header. */
797int sip_security_verify_compare(sip_security_server_t const *s,
798 sip_security_verify_t const *v,
799 msg_param_t *return_d_ver)
800{
801 size_t i, j;
802 int retval, digest;
803 msg_param_t const *s_params, *v_params, empty[] = { NULL((void*)0) };
804
805 if (return_d_ver)
806 *return_d_ver = NULL((void*)0);
807
808 if (s == NULL((void*)0))
809 return 0;
810
811 for (;;s = s->sa_next, v = v->sa_next) {
812 if (s == NULL((void*)0) || v == NULL((void*)0))
813 return (s == NULL((void*)0)) - (v == NULL((void*)0));
814
815 if ((retval = su_strcmp(s->sa_mec, v->sa_mec)))
816 return retval;
817
818 digest = su_casematch(s->sa_mec, "Digest");
819
820 s_params = s->sa_params, v_params = v->sa_params;
821
822 if (digest && s_params == NULL((void*)0) && v_params != NULL((void*)0))
823 s_params = empty;
824
825 if (s_params == NULL((void*)0) || v_params == NULL((void*)0)) {
826 if ((retval = (s_params == NULL((void*)0)) - (v_params == NULL((void*)0))))
827 return retval;
828 continue;
829 }
830
831 for (i = 0, j = 0;; i++, j++) {
832 if (digest && v_params[j] &&
833 su_casenmatch(v_params[j], "d-ver=", 6)) {
834 if (return_d_ver)
835 *return_d_ver = v_params[j] + strlen("d-ver=");
836 j++;
837 }
838
839 retval = su_strcmp(s_params[i], v_params[j]);
840
841 if (retval || s_params[i] == NULL((void*)0) || v_params[j] == NULL((void*)0))
842 break;
843 }
844
845 if (retval)
846 return retval;
847 }
848}
849
850/** Select best mechanism from @SecurityClient header.
851 *
852 * @note We assume that @SecurityServer header in @a s is sorted by
853 * preference.
854 */
855sip_security_client_t const *
856sip_security_client_select(sip_security_client_t const *client,
857 sip_security_server_t const *server)
858{
859 sip_security_server_t const *c, *s;
860
861 if (server == NULL((void*)0) || client == NULL((void*)0))
862 return NULL((void*)0);
863
864 for (s = server; s; s = s->sa_next) {
865 for (c = client; c; c = c->sa_next) {
866 if (su_strmatch(s->sa_mec, c->sa_mec))
867 return c;
868 }
869 }
870
871 return NULL((void*)0);
872}
873
874/**Checks if the response with given response code terminates dialog or
875 * dialog usage.
876 *
877 * @return -1 if the response with given code terminates whole dialog.
878 * @return 1 if the response terminates the dialog usage.
879 * @return 0 if the response does not terminate dialog or dialog usage.
880 *
881 * @return
882 * The @a *return_graceful_terminate_usage is set to 1, if application
883 * should gracefully terminate its dialog usage. It is set to 0, if no
884 * graceful terminate is required. If it is up to application policy to
885 * decide whether to gracefully terminate or not, the
886 * @a *return_graceful_terminate_usage is left unmodified.
887 *
888 * @RFC5057
889 */
890int sip_response_terminates_dialog(int response_code,
891 sip_method_t method,
892 int *return_graceful_terminate_usage)
893{
894 enum { no_effect, terminate_usage = 1, terminate_dialog = -1 };
895 int dummy;
896
897 if (!return_graceful_terminate_usage)
898 return_graceful_terminate_usage = &dummy;
899
900 if (response_code < 300)
901 return *return_graceful_terminate_usage = 0;
902
903 /*
904 3xx responses: Redirection mid-dialog is not well understood in SIP,
905 but whatever effect it has impacts the entire dialog and all of
906 its usages equally. In our example scenario, both the
907 subscription and the invite usage would be redirected by this
908 single response.
909 */
910 if (response_code < 400)
911 return *return_graceful_terminate_usage = 0;
912
913 if (response_code < 500) switch (response_code) {
914 default:
915 case 400: /** @par 400 and unrecognized 4xx responses
916
917 These responses affect only the NOTIFY transaction, not the
918 subscription, the dialog it resides in (beyond affecting the local
919 CSeq), or any other usage of that dialog. In general, the response
920 is a complaint about this transaction, not the usage or dialog the
921 transaction occurs in.
922 */
923 *return_graceful_terminate_usage = 0;
924 return 0;
925
926 case 401:
927 case 407: /** @par 401 Unauthorized and 407 Proxy Authentication Required
928
929 This request, not the subscription or dialog, is being challenged. The
930 usages and dialog are not terminated.
931 */
932 *return_graceful_terminate_usage = 0;
933 return 0;
934
935 case 402: /** @par 402 Payment Required
936
937 This is a reserved response code. If encountered, it should be
938 treated as an unrecognized 4xx.
939 */
940 *return_graceful_terminate_usage = 0;
941 return 0;
942
943 case 403: /** @par 403 Forbidden
944
945 This response terminates the subscription, but has no effect on
946 any other usages of the dialog. In our example scenario, the
947 invite usage continues to exist. Similarly, if the 403 came in
948 response to a re-INVITE, the invite usage would be terminated, but
949 not the subscription.
950 */
951 *return_graceful_terminate_usage = 0;
952 return 0;
953
954 case 404: /** @par 404 Not Found
955
956 This response destroys the dialog and all usages sharing it. The
957 Request-URI that is being 404ed is the remote target set by the
958 @Contact provided by the peer. Getting this response means
959 something has gone fundamentally wrong with the dialog state.
960 */
961 return terminate_dialog;
962
963 case 405: /** @par 405 Method Not Allowed
964
965 In our example scenario, this response destroys the subscription,
966 but not the invite usage or the dialog. It's an aberrant case for
967 NOTIFYs to receive a 405 since they only come as a result to
968 something that creates subscription. In general, a 405 within a
969 given usage affects only that usage, but does not affect other
970 usages of the dialog.
971 */
972 switch (method) {
973 case sip_method_notify:
974 case sip_method_subscribe:
975 case sip_method_invite:
976 return terminate_usage;
977 default:
978 *return_graceful_terminate_usage = 0;
979 return 0;
980 }
981
982 case 406: /** @par 406 Not Acceptable
983
984 These responses concern details of the message in the transaction.
985 Subsequent requests in this same usage may succeed. Neither the
986 usage nor dialog is terminated, other usages sharing this dialog
987 are unaffected.
988 */
989 *return_graceful_terminate_usage = 0;
990 return 0;
991
992 case 408: /** @par 408 Request Timeout
993
994 Receiving a 408 will have the same effect on
995 usages and dialogs as a real transaction timeout as described in
996 Section 3.2.
997 */
998 return terminate_usage;
999
1000 case 410: /** @par 410 Gone
1001
1002 This response destroys the dialog and all usages sharing
1003 it. The Request-URI that is being rejected is the remote target
1004 set by the @Contact provided by the peer. Similar to 404, getting
1005 this response means something has gone fundamentally wrong with
1006 the dialog state, its slightly less aberrant in that the other
1007 endpoint recognizes that this was once a valid URI that it isn't
1008 willing to respond to anymore.
1009 */
1010 return terminate_dialog;
1011
1012 case 412: /* Conditional Request Failed: */
1013 case 413: /* Request Entity Too Large: */
1014 case 414: /* Request-URI Too Long: */
1015 case 415: /* Unsupported Media Type: */
1016 /** @par 412, 413, 414 and 415
1017
1018 These responses concern details of the message in the transaction.
1019 Subsequent requests in this same usage may succeed. Neither the usage
1020 nor dialog is terminated, other usages sharing this dialog are
1021 unaffected.
1022 */
1023 *return_graceful_terminate_usage = 0;
1024 return 0;
1025
1026 case 416: /** @par 416 Unsupported URI Scheme
1027
1028 Similar to 404 and 410, this response
1029 came to a request whose Request-URI was provided by the peer in a
1030 @Contact header field. Something has gone fundamentally wrong, and
1031 the dialog and all of its usages are destroyed.
1032 */
1033 return terminate_dialog;
1034
1035 case 417:
1036 /** @par 417 Uknown Resource-Priority
1037 The effect of this response on usages
1038 and dialogs is analgous to that for 420 and 488. The usage is not
1039 affected. The dialog is only affected by a change in its local
1040 @CSeq. No other usages of the dialog are affected.
1041 */
1042
1043 case 420: /* Bad Extension */
1044 case 421: /* Extension Required */
1045
1046 /** @par 420 Bad Extension and 421 Extension Required
1047
1048 These responses are objecting to the request, not the usage. The
1049 usage is not affected. The dialog is only affected by a change in
1050 its local @CSeq. No other usages of the dialog are affected.
1051 */
1052
1053 case 422: /** @par 422 Session Interval Too Small
1054
1055 This response will not be returned to
1056 a NOTIFY in our example scenario. This response is non-sensical
1057 for any mid-usage request. If it is received, an element in the
1058 path of the request is violating protocol, and the recipient
1059 should treat this as it would an unknown 4xx response. If the
1060 response came to a request that was attempting to establish a new
1061 usage in an existing dialog, no new usage is created and existing
1062 usages are unaffected.
1063 */
1064
1065 case 423: /** @par 423 Interval Too Brief
1066
1067 This response won't happen in our example
1068 scenario, but if it came in response to a re-SUBSCRIBE, the
1069 subscribe usage is not destroyed (or otherwise affected). No
1070 other usages of the dialog are affected.
1071 */
1072
1073 case 428: /** @par 428 Use Identity Header
1074
1075 This response objects to the request, not
1076 the usage. The usage is not affected. The dialog is only
1077 affected by a change in its local @CSeq. No other usages of the
1078 dialog are affected. */
1079
1080 case 429: /** @par 429 Provide Referrer Identity
1081
1082 This response won't be returned to a NOTIFY as in our example
1083 scenario, but when it is returned to a REFER, it is objecting to
1084 the REFER request itself, not any usage the REFER occurs within.
1085 The usage is unaffected. Any other usages sharing this dialog are
1086 unaffected. The dialog is only affected by a change in its local
1087 @CSeq.
1088 */
1089
1090 case 436: case 437: case 438:
1091 /** @par 436 Bad Identity-Info, 437 Unsupported Certificate, 438 Invalid \
1092 * Identity Header
1093 *
1094 * These responses object to the request, not the usage.
1095 * The usage is not affected. The dialog is only affected by a
1096 * change in its local @CSeq. No other usages of the dialog are
1097 * affected.
1098 */
1099 *return_graceful_terminate_usage = 0;
1100 return 0;
1101
1102
1103 case 480: /** @par 480 Temporarily Unavailable
1104
1105 @RFC3261 is unclear on what this response means for mid-usage
1106 requests. Clarifications will be made to show that this response
1107 affects only the usage in which the request occurs. No other usages
1108 are affected. If the response included a @RetryAfter header field,
1109 further requests in that usage should not be sent until the indicated
1110 time has past. Requests in other usages may still be sent at any time.
1111 */
1112 return terminate_usage;
1113
1114
1115 case 481: /** @par 481 Call/Transaction Does Not Exist
1116
1117 This response indicates that the peer has lost its copy of the dialog
1118 state. The dialog and any usages sharing it are destroyed.
1119
1120 The dialog
1121 itself should not be destroyed unless this was the last usage.
1122 The effects of a 481 on a dialog and its usages are the most
1123 ambiguous of any final response. There are implementations that
1124 have chosen the meaning recommended here, and others that destroy
1125 the entire dialog without regard to the number of outstanding
1126 usages. Going forward with this clarification will allow those
1127 deployed implementations that assumed only the usage was destroyed
1128 to work with a wider number of implementations. Those that made
1129 the other choice will continue to function as they do now,
1130 suffering at most the same extra messages needed for a peer to
1131 discover that that other usages have gone away that they currently
1132 do. However, the necessary clarification to @RFC3261 needs to
1133 make it very clear that the ability to terminate usages
1134 independently from the overall dialog using a 481 is not
1135 justification for designing new applications that count on
1136 multiple usages in a dialog.
1137 */
1138 return terminate_usage;
1139
1140
1141 case 482: /** @par 482 Loop Detected
1142
1143 This response is aberrant mid-dialog. It will
1144 only occur if the @RecordRoute header field was improperly
1145 constructed by the proxies involved in setting up the dialog's
1146 initial usage, or if a mid-dialog request forks and merges (which
1147 should never happen). Future requests using this dialog state
1148 will also fail. The dialog and any usages sharing it are
1149 destroyed.
1150 */
1151 return terminate_dialog;
1152
1153
1154 case 483: /** @par 483 Too Many Hops
1155
1156 Similar to 482, receiving this mid-dialog is
1157 aberrant. Unlike 482, recovery may be possible by increasing
1158 @MaxForwards (assuming that the requester did something strange
1159 like using a smaller value for @MaxForwards in mid-dialog requests
1160 than it used for an initial request). If the request isn't tried
1161 with an increased @MaxForwards, then the agent should attempt to
1162 gracefully terminate this usage and all other usages that share
1163 its dialog.
1164 */
1165 *return_graceful_terminate_usage = 1;
1166 return 0;
1167
1168 case 484: /* Address Incomplete */
1169 /** @par 484 Address Incomplete and 485 Ambiguous
1170
1171 Similar to 404 and 410, these
1172 responses came to a request whose Request-URI was provided by the
1173 peer in a @Contact header field. Something has gone fundamentally
1174 wrong, and the dialog and all of its usages are destroyed.
1175
1176 Asterisk (v 1.2.7.1) does response with 484 if a client does send a refer
1177 with a @ReferTo header to an unknown number. This is therefore not
1178 fundamentally wrong and the dialog should not be destroyed!
1179 */
1180 if (method == sip_method_refer)
1181 {
1182 *return_graceful_terminate_usage = 0;
1183 return 0;
1184 }
1185
1186 case 485: /* Ambiguous */
1187
1188 return terminate_dialog;
1189
1190 case 486: /** @par 486 Busy Here
1191
1192 This response is non-sensical in our example scenario,
1193 or in any scenario where this response comes inside an established
1194 usage. If it occurs in that context, it should be treated as an
1195 unknown 4xx response. The usage, and any other usages sharing its
1196 dialog are unaffected. The dialog is only affected by the change
1197 in its local @CSeq. If this response is to a request that is
1198 attempting to establish a new usage within an existing dialog
1199 (such as an INVITE sent within a dialog established by a
1200 subscription), the request fails, no new usage is created, and no
1201 other usages are affected.
1202 */
1203 *return_graceful_terminate_usage = 0;
1204 return 0;
1205
1206 case 487: /** @par 487 Request Terminated
1207
1208 This response speaks to the disposition of a
1209 particular request (transaction). The usage in which that request
1210 occurs is not affected by this response (it may be affected by
1211 another associated request within that usage). No other usages
1212 sharing this dialog are affected.
1213 */
1214 *return_graceful_terminate_usage = 0;
1215 return 0;
1216
1217 case 488: /** @par 488 Not Acceptable Here
1218
1219 This response is objecting to the request,
1220 not the usage. The usage is not affected. The dialog is only
1221 affected by a change in its local @CSeq. No other usages of the
1222 dialog are affected.
1223 */
1224 *return_graceful_terminate_usage = 0;
1225 return 0;
1226
1227 case 489: /** @par 489 Bad Event
1228
1229 In our example scenario, @RFC3265 declares that the
1230 subscription usage in which the NOTIFY is sent is terminated. The
1231 invite usage is unaffected and the dialog continues to exist.
1232 This response is only valid in the context of SUBSCRIBE and
1233 NOTIFY. UAC behavior for receiving this response to other methods
1234 is not specified, but treating it as an unknown 4xx is a
1235 reasonable practice.
1236 */
1237 *return_graceful_terminate_usage = 0;
1238 return method == sip_method_notify ? terminate_usage : no_effect;
1239
1240 case 491: /** @par 491 Request Pending
1241
1242 This response addresses in-dialog request glare.
1243 Its affect is scoped to the request. The usage in which the
1244 request occurs is not affected. The dialog is only affected by
1245 the change in its local @CSeq. No other usages sharing this dialog
1246 are affected.
1247 */
1248 *return_graceful_terminate_usage = 0;
1249 return 0;
1250
1251 case 493: /** @par 493 Undecipherable
1252
1253 This response objects to the request, not the
1254 usage. The usage is not affected. The dialog is only affected by
1255 a change in its local @CSeq. No other usages of the dialog are
1256 affected.
1257 */
1258 *return_graceful_terminate_usage = 0;
1259 return 0;
1260
1261 case 494: /** @par 494 Security Agreement Required
1262
1263 This response is objecting to the
1264 request, not the usage. The usage is not affected. The dialog is
1265 only affected by a change in its local @CSeq. No other usages of
1266 the dialog are affected.
1267 */
1268 *return_graceful_terminate_usage = 0;
1269 return 0;
1270 }
1271
1272 if (response_code < 600) switch (response_code) {
1273 case 500: /* 500 and 5xx unrecognized responses */
1274 default:
1275 /** @par 500 and 5xx unrecognized responses
1276
1277 These responses are complaints against the request (transaction),
1278 not the usage. If the response contains a @RetryAfter header field
1279 value, the server thinks the condition is temporary and the
1280 request can be retried after the indicated interval. This usage,
1281 and any other usages sharing the dialog are unaffected. If the
1282 response does not contain a @RetryAfter header field value, the UA
1283 may decide to retry after an interval of its choosing or attempt
1284 to gracefully terminate the usage. Whether or not to terminate
1285 other usages depends on the application. If the UA receives a 500
1286 (or unrecognized 5xx) in response to an attempt to gracefully
1287 terminate this usage, it can treat this usage as terminated. If
1288 this is the last usage sharing the dialog, the dialog is also
1289 terminated.
1290 */
1291 /* Do not change *return_graceful_terminate_usage */
1292 return 0;
1293
1294 case 501: /** @par 501 Not Implemented
1295
1296 This would be a degenerate response in our
1297 example scenario since the NOTIFY is being sent as part of an
1298 established subscribe usage. In this case, the UA knows the
1299 condition is unrecoverable and should stop attempting to send
1300 NOTIFYs on this usage. (It may or may not destroy the usage. If
1301 it remembers the bad behavior, it can reject any refresh
1302 subscription). In general, this response may or may not affect
1303 the usage (a 501 to an unknown method or an INFO will not end an
1304 invite usage). It will never affect other usages sharing this
1305 usage's dialog.
1306 */
1307 /* Do not change *return_graceful_terminate_usage */
1308 return 0;
1309
1310 case 502: /** @par 502 Bad Gateway
1311
1312 This response is aberrant mid-dialog. It will only occur if the
1313 @RecordRoute header field was improperly constructed by the
1314 proxies involved in setting up the dialog's initial usage. Future
1315 requests using this dialog state will also fail. The dialog and
1316 any usages sharing it are destroyed.
1317 */
1318 return terminate_dialog;
1319
1320 case 503: /** @par 503 Service Unavailable
1321
1322 As per @RFC3263, the logic handling locating SIP servers for
1323 transactions may handle 503 requests (effectively sequentially
1324 forking at the endpoint based on DNS results). If this process
1325 does not yield a better response, a 503 may be returned to the
1326 transaction user. Like a 500 response, the error is a complaint
1327 about this transaction, not the usage. Because this response
1328 occurred in the context of an established usage (hence an existing
1329 dialog), the route-set has already been formed and any opportunity
1330 to try alternate servers (as recommended in @RFC3261) has been exhausted
1331 by the @RFC3263 logic. The response should be handled as described
1332 for 500 earlier in this memo.
1333 */
1334 /* Do not change *return_graceful_terminate_usage */
1335 return 0;
1336
1337 case 504: /** @par 504 Server Time-out
1338
1339 It is not obvious under what circumstances this
1340 response would be returned to a request in an existing dialog. If
1341 it occurs it should have the same affect on the dialog and its
1342 usages as described for unknown 5xx responses.
1343 */
1344 /* Do not change *return_graceful_terminate_usage */
1345 return 0;
1346
1347 case 505: /* Version Not Supported */
1348 case 513: /* Message Too Large */
1349 /** @par 505 Version Not Supported and 513 Message Too Large
1350
1351 These responses are objecting to the request, not the usage. The
1352 usage is not affected. The dialog is only affected by a change in
1353 its local @CSeq. No other usages of the dialog are affected.
1354 */
1355 *return_graceful_terminate_usage = 0;
1356 return 0;
1357
1358 case 580: /** @par 580 Precondition Failure
1359
1360 This response is objecting to the request,
1361 not the usage. The usage is not affected. The dialog is only
1362 affected by a change in its local @CSeq. No other usages of the
1363 dialog are affected.
1364 */
1365 *return_graceful_terminate_usage = 0;
1366 return 0;
1367 }
1368
1369 if (response_code < 700) switch (response_code) {
1370 case 600: /* 600 and 6xx unrecognized responses */
1371 default:
1372 /** @par 600 and 6xx unrecognized responses
1373
1374 Unlike 400 Bad Request, a 600 response code says something about
1375 the recipient user, not the request that was made. This end user
1376 is stating an unwillingness to communicate.
1377
1378 If the response contains a @RetryAfter header field value, the
1379 user is indicating willingness to communicate later and the
1380 request can be retried after the indicated interval. This usage,
1381 and any other usages sharing the dialog are unaffected. If the
1382 response does not contain a @RetryAfter header field value, the UA
1383 may decide to retry after an interval of its choosing or attempt
1384 to gracefully terminate the usage. Whether or not to terminate
1385 other usages depends on the application. If the UA receives a 600
1386 (or unrecognized 6xx) in response to an attempt to gracefully
1387 terminate this usage, it can treat this usage as terminated. If
1388 this is the last usage sharing the dialog, the dialog is also
1389 terminated.
1390 */
1391 /* Do not change graceful_terminate */
1392 return 0;
1393
1394 case 603: /** @par 603 Decline
1395
1396 This response declines the action indicated by the
1397 associated request. It can be used, for example, to decline a
1398 hold or transfer attempt. Receiving this response does NOT
1399 terminate the usage it occurs in. Other usages sharing the dialog
1400 are unaffected.
1401 */
1402 *return_graceful_terminate_usage = 0;
1403 return 0;
1404
1405 case 604: /** @par 604 Does Not Exist Anywhere
1406
1407 Like 404, this response destroys the
1408 dialog and all usages sharing it. The Request-URI that is being
1409 604ed is the remote target set by the @Contact provided by the
1410 peer. Getting this response means something has gone
1411 fundamentally wrong with the dialog state.
1412 */
1413 return terminate_dialog;
1414
1415 case 606: /** @par 606 Not Acceptable
1416
1417 This response is objecting to aspects of the
1418 associated request, not the usage the request appears in. The
1419 usage is unaffected. Any other usages sharing the dialog are
1420 unaffected. The only affect on the dialog is the change in the
1421 local @CSeq.
1422 */
1423 *return_graceful_terminate_usage = 0;
1424 return 0;
1425 }
1426
1427 /* Do not change graceful_terminate */
1428
1429 return 0;
1430}
1431