Asterisk - The Open Source Telephony Project  18.5.0
Macros | Functions | Variables
reqresp_parser.c File Reference

sip request parsing functions and unit tests More...

#include "asterisk.h"
#include "include/sip.h"
#include "include/sip_utils.h"
#include "include/reqresp_parser.h"
Include dependency graph for reqresp_parser.c:

Go to the source code of this file.

Macros

#define URI_CMP_MATCH   0
 
#define URI_CMP_NOMATCH   1
 

Functions

 AST_TEST_DEFINE (sip_parse_uri_full_test)
 
 AST_TEST_DEFINE (sip_parse_uri_test)
 
 AST_TEST_DEFINE (get_calleridname_test)
 
 AST_TEST_DEFINE (get_name_and_number_test)
 
 AST_TEST_DEFINE (get_in_brackets_test)
 
 AST_TEST_DEFINE (parse_name_andor_addr_test)
 
 AST_TEST_DEFINE (parse_contact_header_test)
 
 AST_TEST_DEFINE (sip_parse_options_test)
 
 AST_TEST_DEFINE (sip_uri_cmp_test)
 
 AST_TEST_DEFINE (parse_via_test)
 
void free_via (struct sip_via *v)
 
const char * get_calleridname (const char *input, char *output, size_t outputsize)
 Get caller id name from SIP headers, copy into output buffer. More...
 
int get_comma (char *in, char **out)
 Parse all contact header contacts. More...
 
char * get_in_brackets (char *tmp)
 Pick out text in brackets from character string. More...
 
int get_in_brackets_const (const char *src, const char **start, int *length)
 Get text in brackets on a const without copy. More...
 
int get_in_brackets_full (char *tmp, char **out, char **residue)
 Get text in brackets and any trailing residue. More...
 
int get_name_and_number (const char *hdr, char **name, char **number)
 Get name and number from sip header. More...
 
int parse_contact_header (char *contactheader, struct contactliststruct *contactlist)
 
int parse_name_andor_addr (char *uri, const char *scheme, char **name, char **user, char **pass, char **hostport, struct uriparams *params, char **headers, char **residue)
 Parse the ABNF structure name-andor-addr = name-addr / addr-spec into its components and return any trailing message-header parameters. More...
 
unsigned int parse_sip_options (const char *options, char *unsupported, size_t unsupported_len)
 Parse supported header in incoming packet. More...
 
int parse_uri (char *uri, const char *scheme, char **user, char **pass, char **hostport, char **transport)
 parses a URI in its components. More...
 
int parse_uri_full (char *uri, const char *scheme, char **user, char **pass, char **hostport, struct uriparams *params, char **headers, char **residue)
 
  • parses a URI in its components.
More...
 
struct sip_viaparse_via (const char *header)
 Parse a Via header. More...
 
void sip_reqresp_parser_exit (void)
 Free resources used by request and response parser. More...
 
int sip_reqresp_parser_init (void)
 initialize request and response parser data More...
 
void sip_request_parser_register_tests (void)
 register request parsing tests More...
 
void sip_request_parser_unregister_tests (void)
 unregister request parsing tests More...
 
int sip_uri_cmp (const char *input1, const char *input2)
 Compare two URIs as described in RFC 3261 Section 19.1.4. More...
 
static int sip_uri_domain_cmp (const char *host1, const char *host2)
 Compare domain sections of SIP URIs. More...
 
static int sip_uri_headers_cmp (const char *input1, const char *input2)
 helper routine for sip_uri_cmp to compare URI headers More...
 
static int sip_uri_params_cmp (const char *input1, const char *input2)
 helper routine for sip_uri_cmp to compare URI parameters More...
 

Variables

locale_t c_locale
 

Detailed Description

sip request parsing functions and unit tests

Definition in file reqresp_parser.c.

Macro Definition Documentation

◆ URI_CMP_MATCH

#define URI_CMP_MATCH   0

Definition at line 2257 of file reqresp_parser.c.

Referenced by AST_TEST_DEFINE().

◆ URI_CMP_NOMATCH

#define URI_CMP_NOMATCH   1

Definition at line 2258 of file reqresp_parser.c.

Referenced by AST_TEST_DEFINE().

Function Documentation

◆ AST_TEST_DEFINE() [1/10]

AST_TEST_DEFINE ( sip_parse_uri_full_test  )

Definition at line 260 of file reqresp_parser.c.

References ast_copy_string(), AST_LIST_ENTRY, AST_LIST_HEAD_NOLOCK(), AST_LIST_HEAD_SET_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, desc, sip_to_pjsip::info(), uriparams::lr, uriparams::maddr, uriparams::method, NULL, parse_uri_full(), pass, TEST_EXECUTE, TEST_INIT, uriparams::transport, uriparams::ttl, uriparams::user, and user.

261 {
262  int res = AST_TEST_PASS;
263  char uri[1024];
264  char *user, *pass, *hostport, *headers, *residue;
265  struct uriparams params;
266 
267  struct testdata {
268  char *desc;
269  char *uri;
270  char *user;
271  char *pass;
272  char *hostport;
273  char *headers;
274  char *residue;
275  struct uriparams params;
276  AST_LIST_ENTRY(testdata) list;
277  };
278 
279 
280  struct testdata *testdataptr;
281 
282  static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
283 
284  struct testdata td1 = {
285  .desc = "no headers",
286  .uri = "sip:user:secret@host:5060;param=discard;transport=tcp;param2=residue",
287  .user = "user",
288  .pass = "secret",
289  .hostport = "host:5060",
290  .headers = "",
291  .residue = "param2=residue",
292  .params.transport = "tcp",
293  .params.lr = 0,
294  .params.user = ""
295  };
296 
297  struct testdata td2 = {
298  .desc = "with headers",
299  .uri = "sip:user:secret@host:5060;param=discard;transport=tcp;param2=discard2?header=blah&header2=blah2;param3=residue",
300  .user = "user",
301  .pass = "secret",
302  .hostport = "host:5060",
303  .headers = "header=blah&header2=blah2",
304  .residue = "param3=residue",
305  .params.transport = "tcp",
306  .params.lr = 0,
307  .params.user = ""
308  };
309 
310  struct testdata td3 = {
311  .desc = "difficult user",
312  .uri = "sip:-_.!~*'()&=+$,;?/:secret@host:5060;transport=tcp",
313  .user = "-_.!~*'()&=+$,;?/",
314  .pass = "secret",
315  .hostport = "host:5060",
316  .headers = "",
317  .residue = "",
318  .params.transport = "tcp",
319  .params.lr = 0,
320  .params.user = ""
321  };
322 
323  struct testdata td4 = {
324  .desc = "difficult pass",
325  .uri = "sip:user:-_.!~*'()&=+$,@host:5060;transport=tcp",
326  .user = "user",
327  .pass = "-_.!~*'()&=+$,",
328  .hostport = "host:5060",
329  .headers = "",
330  .residue = "",
331  .params.transport = "tcp",
332  .params.lr = 0,
333  .params.user = ""
334  };
335 
336  struct testdata td5 = {
337  .desc = "difficult host",
338  .uri = "sip:user:[email protected].:5060;transport=tcp",
339  .user = "user",
340  .pass = "secret",
341  .hostport = "1-1.a-1.:5060",
342  .headers = "",
343  .residue = "",
344  .params.transport = "tcp",
345  .params.lr = 0,
346  .params.user = ""
347  };
348 
349  struct testdata td6 = {
350  .desc = "difficult params near transport",
351  .uri = "sip:user:secret@host:5060;-_.!~*'()[]/:&+$=-_.!~*'()[]/:&+$;transport=tcp",
352  .user = "user",
353  .pass = "secret",
354  .hostport = "host:5060",
355  .headers = "",
356  .residue = "",
357  .params.transport = "tcp",
358  .params.lr = 0,
359  .params.user = ""
360  };
361 
362  struct testdata td7 = {
363  .desc = "difficult params near headers",
364  .uri = "sip:user:secret@host:5060;-_.!~*'()[]/:&+$=-_.!~*'()[]/:&+$?header=blah&header2=blah2;-_.!~*'()[]/:&+$=residue",
365  .user = "user",
366  .pass = "secret",
367  .hostport = "host:5060",
368  .headers = "header=blah&header2=blah2",
369  .residue = "-_.!~*'()[]/:&+$=residue",
370  .params.transport = "",
371  .params.lr = 0,
372  .params.user = ""
373  };
374 
375  struct testdata td8 = {
376  .desc = "lr parameter",
377  .uri = "sip:user:secret@host:5060;param=discard;lr?header=blah",
378  .user = "user",
379  .pass = "secret",
380  .hostport = "host:5060",
381  .headers = "header=blah",
382  .residue = "",
383  .params.transport = "",
384  .params.lr = 1,
385  .params.user = ""
386  };
387 
388  struct testdata td9 = {
389  .desc = "alternative lr parameter",
390  .uri = "sip:user:secret@host:5060;param=discard;lr=yes?header=blah",
391  .user = "user",
392  .pass = "secret",
393  .hostport = "host:5060",
394  .headers = "header=blah",
395  .residue = "",
396  .params.transport = "",
397  .params.lr = 1,
398  .params.user = ""
399  };
400 
401  struct testdata td10 = {
402  .desc = "no lr parameter",
403  .uri = "sip:user:secret@host:5060;paramlr=lr;lr=no;lr=off;lr=0;lr=;=lr;lrextra;lrparam2=lr?header=blah",
404  .user = "user",
405  .pass = "secret",
406  .hostport = "host:5060",
407  .headers = "header=blah",
408  .residue = "",
409  .params.transport = "",
410  .params.lr = 0,
411  .params.user = ""
412  };
413 
414  /* RFC 3966 TEL URI INVITE */
415  struct testdata td11 = {
416  .desc = "tel local number",
417  .uri = "tel:0987654321;phone-context=+32987654321",
418  .user = "0987654321",
419  .pass = "",
420  .hostport = "+32987654321",
421  .headers = "",
422  .residue = "",
423  .params.transport = "",
424  .params.lr = 0,
425  .params.user = ""
426  };
427 
428  struct testdata td12 = {
429  .desc = "tel global number",
430  .uri = "tel:+32987654321",
431  .user = "+32987654321",
432  .pass = "",
433  .hostport = "+32987654321",
434  .headers = "",
435  .residue = "",
436  .params.transport = "",
437  .params.lr = 0,
438  .params.user = ""
439  };
440 
441  /*
442  * Once the full RFC 3966 parsing is implemented,
443  * only the ext= or isub= parameters would be extracted from .user
444  * Then the ;param=discard would be ignored,
445  * and the .user would only contain "0987654321"
446  */
447  struct testdata td13 = {
448  .desc = "tel local number",
449  .uri = "tel:0987654321;ext=1234;param=discard;phone-context=+32987654321;transport=udp;param2=discard2?header=blah&header2=blah2;param3=residue",
450  .user = "0987654321;ext=1234;param=discard",
451  .pass = "",
452  .hostport = "+32987654321",
453  .headers = "header=blah&header2=blah2",
454  .residue = "param3=residue",
455  .params.transport = "udp",
456  .params.lr = 0,
457  .params.user = ""
458  };
459 
460  AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &td1);
461  AST_LIST_INSERT_TAIL(&testdatalist, &td2, list);
462  AST_LIST_INSERT_TAIL(&testdatalist, &td3, list);
463  AST_LIST_INSERT_TAIL(&testdatalist, &td4, list);
464  AST_LIST_INSERT_TAIL(&testdatalist, &td5, list);
465  AST_LIST_INSERT_TAIL(&testdatalist, &td6, list);
466  AST_LIST_INSERT_TAIL(&testdatalist, &td7, list);
467  AST_LIST_INSERT_TAIL(&testdatalist, &td8, list);
468  AST_LIST_INSERT_TAIL(&testdatalist, &td9, list);
469  AST_LIST_INSERT_TAIL(&testdatalist, &td10, list);
470  AST_LIST_INSERT_TAIL(&testdatalist, &td11, list);
471  AST_LIST_INSERT_TAIL(&testdatalist, &td12, list);
472  AST_LIST_INSERT_TAIL(&testdatalist, &td13, list);
473 
474  switch (cmd) {
475  case TEST_INIT:
476  info->name = "sip_uri_full_parse_test";
477  info->category = "/channels/chan_sip/";
478  info->summary = "tests sip full uri parsing";
479  info->description =
480  "Tests full parsing of various URIs "
481  "Verifies output matches expected behavior.";
482  return AST_TEST_NOT_RUN;
483  case TEST_EXECUTE:
484  break;
485  }
486 
487  AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
488  user = pass = hostport = headers = residue = NULL;
489  params.transport = params.user = params.method = params.ttl = params.maddr = NULL;
490  params.lr = 0;
491 
492  ast_copy_string(uri,testdataptr->uri,sizeof(uri));
493  if (parse_uri_full(uri, "sip:,sips:,tel:", &user,
494  &pass, &hostport,
495  &params,
496  &headers,
497  &residue) ||
498  (user && strcmp(testdataptr->user, user)) ||
499  (pass && strcmp(testdataptr->pass, pass)) ||
500  (hostport && strcmp(testdataptr->hostport, hostport)) ||
501  (headers && strcmp(testdataptr->headers, headers)) ||
502  (residue && strcmp(testdataptr->residue, residue)) ||
503  (strcmp(testdataptr->params.transport,params.transport)) ||
504  (testdataptr->params.lr != params.lr) ||
505  (strcmp(testdataptr->params.user,params.user))
506  ) {
507  ast_test_status_update(test, "Sub-Test: %s, failed.\n", testdataptr->desc);
508  res = AST_TEST_FAIL;
509  }
510  }
511 
512 
513  return res;
514 }
static char user[512]
static char pass[512]
static const char desc[]
Definition: cdr_mysql.c:73
#define NULL
Definition: resample.c:96
int parse_uri_full(char *uri, const char *scheme, char **user, char **pass, char **hostport, struct uriparams *params, char **headers, char **residue)
parses a URI in its components.
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
AST_LIST_HEAD_NOLOCK(contactliststruct, contact)
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
def info(msg)
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
uri parameters
#define AST_LIST_HEAD_SET_NOLOCK(head, entry)
Initializes a list head structure with a specified first entry.
Definition: linkedlists.h:387
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401

◆ AST_TEST_DEFINE() [2/10]

AST_TEST_DEFINE ( sip_parse_uri_test  )

Definition at line 532 of file reqresp_parser.c.

References ast_strlen_zero, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, sip_to_pjsip::info(), name, NULL, parse_uri(), pass, TEST_EXECUTE, TEST_INIT, and uriparams::transport.

533 {
534  int res = AST_TEST_PASS;
535  char *name, *pass, *hostport, *transport;
536  char uri1[] = "sip:name@host";
537  char uri2[] = "sip:name@host;transport=tcp";
538  char uri3[] = "sip:name:secret@host;transport=tcp";
539  char uri4[] = "sip:name:secret@host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
540  /* test 5 is for NULL input */
541  char uri6[] = "sip:name:secret@host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
542  char uri7[] = "sip:name:secret@host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
543  char uri8[] = "sip:host";
544  char uri9[] = "sip:host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
545  char uri10[] = "host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
546  char uri11[] = "host";
547  char uri12[] = "tel:911"; /* TEL URI Local number without context or global number */
548 
549  switch (cmd) {
550  case TEST_INIT:
551  info->name = "sip_uri_parse_test";
552  info->category = "/channels/chan_sip/";
553  info->summary = "tests sip uri parsing";
554  info->description =
555  "Tests parsing of various URIs "
556  "Verifies output matches expected behavior.";
557  return AST_TEST_NOT_RUN;
558  case TEST_EXECUTE:
559  break;
560  }
561 
562  /* Test 1, simple URI */
563  name = pass = hostport = transport = NULL;
564  if (parse_uri(uri1, "sip:,sips:", &name, &pass, &hostport, &transport) ||
565  strcmp(name, "name") ||
566  !ast_strlen_zero(pass) ||
567  strcmp(hostport, "host") ||
568  !ast_strlen_zero(transport)) {
569  ast_test_status_update(test, "Test 1: simple uri failed. \n");
570  res = AST_TEST_FAIL;
571  }
572 
573  /* Test 2, add tcp transport */
574  name = pass = hostport = transport = NULL;
575  if (parse_uri(uri2, "sip:,sips:", &name, &pass, &hostport, &transport) ||
576  strcmp(name, "name") ||
577  !ast_strlen_zero(pass) ||
578  strcmp(hostport, "host") ||
579  strcmp(transport, "tcp")) {
580  ast_test_status_update(test, "Test 2: uri with addtion of tcp transport failed. \n");
581  res = AST_TEST_FAIL;
582  }
583 
584  /* Test 3, add secret */
585  name = pass = hostport = transport = NULL;
586  if (parse_uri(uri3, "sip:,sips:", &name, &pass, &hostport, &transport) ||
587  strcmp(name, "name") ||
588  strcmp(pass, "secret") ||
589  strcmp(hostport, "host") ||
590  strcmp(transport, "tcp")) {
591  ast_test_status_update(test, "Test 3: uri with addition of secret failed.\n");
592  res = AST_TEST_FAIL;
593  }
594 
595  /* Test 4, add port and unparsed header field*/
596  name = pass = hostport = transport = NULL;
597  if (parse_uri(uri4, "sip:,sips:", &name, &pass, &hostport, &transport) ||
598  strcmp(name, "name") ||
599  strcmp(pass, "secret") ||
600  strcmp(hostport, "host:port") ||
601  strcmp(transport, "tcp")) {
602  ast_test_status_update(test, "Test 4: add port and unparsed header field failed.\n");
603  res = AST_TEST_FAIL;
604  }
605 
606  /* Test 5, verify parse_uri does not crash when given a NULL uri */
607  name = pass = hostport = transport = NULL;
608  if (!parse_uri(NULL, "sip:,sips:", &name, &pass, &hostport, &transport)) {
609  ast_test_status_update(test, "Test 5: passing a NULL uri failed.\n");
610  res = AST_TEST_FAIL;
611  }
612 
613  /* Test 6, verify parse_uri does not crash when given a NULL output parameters */
614  name = pass = hostport = transport = NULL;
615  if (parse_uri(uri6, "sip:,sips:", NULL, NULL, NULL, NULL)) {
616  ast_test_status_update(test, "Test 6: passing NULL output parameters failed.\n");
617  res = AST_TEST_FAIL;
618  }
619 
620  /* Test 7, verify parse_uri returns user:secret and hostport when no port or secret output parameters are supplied. */
621  name = pass = hostport = transport = NULL;
622  if (parse_uri(uri7, "sip:,sips:", &name, NULL, &hostport, NULL) ||
623  strcmp(name, "name:secret") ||
624  strcmp(hostport, "host:port")) {
625 
626  ast_test_status_update(test, "Test 7: providing no port and secret output parameters failed.\n");
627  res = AST_TEST_FAIL;
628  }
629 
630  /* Test 8, verify parse_uri can handle a hostport only uri */
631  name = pass = hostport = transport = NULL;
632  if (parse_uri(uri8, "sip:,sips:", &name, &pass, &hostport, &transport) ||
633  strcmp(hostport, "host") ||
634  !ast_strlen_zero(name)) {
635  ast_test_status_update(test, "Test 8: add port and unparsed header field failed.\n");
636  res = AST_TEST_FAIL;
637  }
638 
639  /* Test 9, add port and unparsed header field with hostport only uri*/
640  name = pass = hostport = transport = NULL;
641  if (parse_uri(uri9, "sip:,sips:", &name, &pass, &hostport, &transport) ||
642  !ast_strlen_zero(name) ||
643  !ast_strlen_zero(pass) ||
644  strcmp(hostport, "host:port") ||
645  strcmp(transport, "tcp")) {
646  ast_test_status_update(test, "Test 9: hostport only uri failed \n");
647  res = AST_TEST_FAIL;
648  }
649 
650  /* Test 10, handle invalid/missing "sip:,sips:" scheme
651  * we expect parse_uri to return an error, but still parse
652  * the results correctly here */
653  name = pass = hostport = transport = NULL;
654  if (!parse_uri(uri10, "sip:,sips:", &name, &pass, &hostport, &transport) ||
655  !ast_strlen_zero(name) ||
656  !ast_strlen_zero(pass) ||
657  strcmp(hostport, "host:port") ||
658  strcmp(transport, "tcp")) {
659  ast_test_status_update(test, "Test 10: missing \"sip:sips:\" scheme failed\n");
660  res = AST_TEST_FAIL;
661  }
662 
663  /* Test 11, simple hostport only URI with missing scheme
664  * we expect parse_uri to return an error, but still parse
665  * the results correctly here */
666  name = pass = hostport = transport = NULL;
667  if (!parse_uri(uri11, "sip:,sips:", &name, &pass, &hostport, &transport) ||
668  !ast_strlen_zero(name) ||
669  !ast_strlen_zero(pass) ||
670  strcmp(hostport, "host") ||
671  !ast_strlen_zero(transport)) {
672  ast_test_status_update(test, "Test 11: simple uri with missing scheme failed. \n");
673  res = AST_TEST_FAIL;
674  }
675 
676  /* Test 12, simple URI */
677  name = pass = hostport = transport = NULL;
678  if (!parse_uri(uri12, "sip:,sips:,tel:", &name, &pass, &hostport, &transport) ||
679  strcmp(name, "911") || /* We return local number anyway */
680  !ast_strlen_zero(pass) ||
681  !ast_strlen_zero(hostport) || /* No global number nor context */
682  !ast_strlen_zero(transport)) {
683  ast_test_status_update(test, "Test 12: TEL URI INVITE failed.\n");
684  res = AST_TEST_FAIL;
685  }
686 
687  return res;
688 }
static char pass[512]
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
int parse_uri(char *uri, const char *scheme, char **user, char **pass, char **hostport, char **transport)
parses a URI in its components.
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
def info(msg)
static const char name[]
Definition: cdr_mysql.c:74

◆ AST_TEST_DEFINE() [3/10]

AST_TEST_DEFINE ( get_calleridname_test  )

Definition at line 821 of file reqresp_parser.c.

References AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, get_calleridname(), sip_to_pjsip::info(), TEST_EXECUTE, and TEST_INIT.

822 {
823  int res = AST_TEST_PASS;
824  const char *in1 = " \" quoted-text internal \\\" quote \"<stuff>";
825  const char *in2 = " token text with no quotes <stuff>";
826  const char *overflow1 = " \"quoted-text overflow 1234567890123456789012345678901234567890\" <stuff>";
827  const char *overflow2 = " non-quoted text overflow 1234567890123456789012345678901234567890 <stuff>";
828  const char *noendquote = " \"quoted-text no end <stuff>";
829  const char *addrspec = " sip:blah@blah";
830  const char *no_quotes_no_brackets = "blah@blah";
831  const char *after_dname;
832  char dname[40];
833 
834  switch (cmd) {
835  case TEST_INIT:
836  info->name = "sip_get_calleridname_test";
837  info->category = "/channels/chan_sip/";
838  info->summary = "decodes callerid name from sip header";
839  info->description = "Decodes display-name field of sip header. Checks for valid output and expected failure cases.";
840  return AST_TEST_NOT_RUN;
841  case TEST_EXECUTE:
842  break;
843  }
844 
845  /* quoted-text with backslash escaped quote */
846  after_dname = get_calleridname(in1, dname, sizeof(dname));
847  ast_test_status_update(test, "display-name1: %s\nafter: %s\n", dname, after_dname);
848  if (strcmp(dname, " quoted-text internal \" quote ")) {
849  ast_test_status_update(test, "display-name1 test failed\n");
850  res = AST_TEST_FAIL;
851  }
852 
853  /* token text */
854  after_dname = get_calleridname(in2, dname, sizeof(dname));
855  ast_test_status_update(test, "display-name2: %s\nafter: %s\n", dname, after_dname);
856  if (strcmp(dname, "token text with no quotes")) {
857  ast_test_status_update(test, "display-name2 test failed\n");
858  res = AST_TEST_FAIL;
859  }
860 
861  /* quoted-text buffer overflow */
862  after_dname = get_calleridname(overflow1, dname, sizeof(dname));
863  ast_test_status_update(test, "overflow display-name1: %s\nafter: %s\n", dname, after_dname);
864  if (strcmp(dname, "quoted-text overflow 123456789012345678")) {
865  ast_test_status_update(test, "overflow display-name1 test failed\n");
866  res = AST_TEST_FAIL;
867  }
868 
869  /* non-quoted-text buffer overflow */
870  after_dname = get_calleridname(overflow2, dname, sizeof(dname));
871  ast_test_status_update(test, "overflow display-name2: %s\nafter: %s\n", dname, after_dname);
872  if (strcmp(dname, "non-quoted text overflow 12345678901234")) {
873  ast_test_status_update(test, "overflow display-name2 test failed\n");
874  res = AST_TEST_FAIL;
875  }
876 
877  /* quoted-text buffer with no terminating end quote */
878  after_dname = get_calleridname(noendquote, dname, sizeof(dname));
879  ast_test_status_update(test, "noendquote display-name1: %s\nafter: %s\n", dname, after_dname);
880  if (*dname != '\0' && after_dname != noendquote) {
881  ast_test_status_update(test, "no end quote for quoted-text display-name failed\n");
882  res = AST_TEST_FAIL;
883  }
884 
885  /* addr-spec rather than display-name. */
886  after_dname = get_calleridname(addrspec, dname, sizeof(dname));
887  ast_test_status_update(test, "addr-spec display-name1: %s\nafter: %s\n", dname, after_dname);
888  if (*dname != '\0' && after_dname != addrspec) {
889  ast_test_status_update(test, "detection of addr-spec failed\n");
890  res = AST_TEST_FAIL;
891  }
892 
893  /* no quotes, no brackets */
894  after_dname = get_calleridname(no_quotes_no_brackets, dname, sizeof(dname));
895  ast_test_status_update(test, "no_quotes_no_brackets display-name1: %s\nafter: %s\n", dname, after_dname);
896  if (*dname != '\0' && after_dname != no_quotes_no_brackets) {
897  ast_test_status_update(test, "detection of addr-spec failed\n");
898  res = AST_TEST_FAIL;
899  }
900 
901  return res;
902 }
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
const char * get_calleridname(const char *input, char *output, size_t outputsize)
Get caller id name from SIP headers, copy into output buffer.
def info(msg)

◆ AST_TEST_DEFINE() [4/10]

AST_TEST_DEFINE ( get_name_and_number_test  )

Definition at line 946 of file reqresp_parser.c.

References ast_free, ast_strlen_zero, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, get_name_and_number(), sip_to_pjsip::info(), name, NULL, TEST_EXECUTE, and TEST_INIT.

947 {
948  int res = AST_TEST_PASS;
949  char *name = NULL;
950  char *number = NULL;
951  const char *in1 = "NAME <sip:NUMBER@place>";
952  const char *in2 = "\"NA><ME\" <sip:NUMBER@place>";
953  const char *in3 = "NAME";
954  const char *in4 = "<sip:NUMBER@place>";
955  const char *in5 = "This is a screwed up string <sip:LOLCLOWNS<sip:>@place>";
956 
957  switch (cmd) {
958  case TEST_INIT:
959  info->name = "sip_get_name_and_number_test";
960  info->category = "/channels/chan_sip/";
961  info->summary = "Tests getting name and number from sip header";
962  info->description =
963  "Runs through various test situations in which a name and "
964  "and number can be retrieved from a sip header.";
965  return AST_TEST_NOT_RUN;
966  case TEST_EXECUTE:
967  break;
968  }
969 
970  /* Test 1. get name and number */
971  number = name = NULL;
972  if ((get_name_and_number(in1, &name, &number)) ||
973  strcmp(name, "NAME") ||
974  strcmp(number, "NUMBER")) {
975 
976  ast_test_status_update(test, "Test 1, simple get name and number failed.\n");
977  res = AST_TEST_FAIL;
978  }
979  ast_free(name);
980  ast_free(number);
981 
982  /* Test 2. get quoted name and number */
983  number = name = NULL;
984  if ((get_name_and_number(in2, &name, &number)) ||
985  strcmp(name, "NA><ME") ||
986  strcmp(number, "NUMBER")) {
987 
988  ast_test_status_update(test, "Test 2, get quoted name and number failed.\n");
989  res = AST_TEST_FAIL;
990  }
991  ast_free(name);
992  ast_free(number);
993 
994  /* Test 3. name only */
995  number = name = NULL;
996  if (!(get_name_and_number(in3, &name, &number))) {
997 
998  ast_test_status_update(test, "Test 3, get name only was expected to fail but did not.\n");
999  res = AST_TEST_FAIL;
1000  }
1001  ast_free(name);
1002  ast_free(number);
1003 
1004  /* Test 4. number only */
1005  number = name = NULL;
1006  if ((get_name_and_number(in4, &name, &number)) ||
1007  !ast_strlen_zero(name) ||
1008  strcmp(number, "NUMBER")) {
1009 
1010  ast_test_status_update(test, "Test 4, get number with no name present failed.\n");
1011  res = AST_TEST_FAIL;
1012  }
1013  ast_free(name);
1014  ast_free(number);
1015 
1016  /* Test 5. malformed string, since number can not be parsed, this should return an error. */
1017  number = name = NULL;
1018  if (!(get_name_and_number(in5, &name, &number)) ||
1019  !ast_strlen_zero(name) ||
1020  !ast_strlen_zero(number)) {
1021 
1022  ast_test_status_update(test, "Test 5, processing malformed string failed.\n");
1023  res = AST_TEST_FAIL;
1024  }
1025  ast_free(name);
1026  ast_free(number);
1027 
1028  /* Test 6. NULL output parameters */
1029  number = name = NULL;
1030  if (!(get_name_and_number(in5, NULL, NULL))) {
1031 
1032  ast_test_status_update(test, "Test 6, NULL output parameters failed.\n");
1033  res = AST_TEST_FAIL;
1034  }
1035 
1036  /* Test 7. NULL input parameter */
1037  number = name = NULL;
1038  if (!(get_name_and_number(NULL, &name, &number)) ||
1039  !ast_strlen_zero(name) ||
1040  !ast_strlen_zero(number)) {
1041 
1042  ast_test_status_update(test, "Test 7, NULL input parameter failed.\n");
1043  res = AST_TEST_FAIL;
1044  }
1045  ast_free(name);
1046  ast_free(number);
1047 
1048  return res;
1049 }
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
Number structure.
Definition: app_followme.c:154
int get_name_and_number(const char *hdr, char **name, char **number)
Get name and number from sip header.
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
def info(msg)
static const char name[]
Definition: cdr_mysql.c:74
#define ast_free(a)
Definition: astmm.h:182

◆ AST_TEST_DEFINE() [5/10]

AST_TEST_DEFINE ( get_in_brackets_test  )

Definition at line 1184 of file reqresp_parser.c.

References AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, get_in_brackets(), sip_to_pjsip::info(), NULL, TEST_EXECUTE, and TEST_INIT.

1185 {
1186  int res = AST_TEST_PASS;
1187  char in_brackets[] = "sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah";
1188  char no_name[] = "<sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
1189  char quoted_string[] = "\"I'm a quote stri><ng\" <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
1190  char missing_end_quote[] = "\"I'm a quote string <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
1191  char name_no_quotes[] = "name not in quotes <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
1192  char no_end_bracket[] = "name not in quotes <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah";
1193  char no_name_no_brackets[] = "sip:name@host";
1194  char missing_start_bracket[] = "sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
1195  char *uri = NULL;
1196 
1197  switch (cmd) {
1198  case TEST_INIT:
1199  info->name = "sip_get_in_brackets_test";
1200  info->category = "/channels/chan_sip/";
1201  info->summary = "Tests getting a sip uri in <> brackets within a sip header.";
1202  info->description =
1203  "Runs through various test situations in which a sip uri "
1204  "in angle brackets needs to be retrieved";
1205  return AST_TEST_NOT_RUN;
1206  case TEST_EXECUTE:
1207  break;
1208  }
1209 
1210  /* Test 1, simple get in brackets */
1211  if (!(uri = get_in_brackets(no_name)) || strcmp(uri, in_brackets)) {
1212  ast_test_status_update(test, "Test 1, simple get in brackets failed. %s\n", uri);
1213  res = AST_TEST_FAIL;
1214  }
1215 
1216  /* Test 2, starts with quoted string */
1217  if (!(uri = get_in_brackets(quoted_string)) || strcmp(uri, in_brackets)) {
1218  ast_test_status_update(test, "Test 2, get in brackets with quoted string in front failed. %s\n", uri);
1219  res = AST_TEST_FAIL;
1220  }
1221 
1222  /* Test 3, missing end quote */
1223  if (!(uri = get_in_brackets(missing_end_quote)) || !strcmp(uri, in_brackets)) {
1224  ast_test_status_update(test, "Test 3, missing end quote failed. %s\n", uri);
1225  res = AST_TEST_FAIL;
1226  }
1227 
1228  /* Test 4, starts with a name not in quotes */
1229  if (!(uri = get_in_brackets(name_no_quotes)) || strcmp(uri, in_brackets)) {
1230  ast_test_status_update(test, "Test 4, passing name not in quotes failed. %s\n", uri);
1231  res = AST_TEST_FAIL;
1232  }
1233 
1234  /* Test 5, no end bracket, should just return everything after the first '<' */
1235  if (!(uri = get_in_brackets(no_end_bracket)) || !strcmp(uri, in_brackets)) {
1236  ast_test_status_update(test, "Test 5, no end bracket failed. %s\n", uri);
1237  res = AST_TEST_FAIL;
1238  }
1239 
1240  /* Test 6, NULL input */
1241  if (get_in_brackets(NULL)) {
1242  ast_test_status_update(test, "Test 6, NULL input failed.\n");
1243  res = AST_TEST_FAIL;
1244  }
1245 
1246  /* Test 7, no name, and no brackets. */
1247  if (!(uri = get_in_brackets(no_name_no_brackets)) || strcmp(uri, "sip:name@host")) {
1248  ast_test_status_update(test, "Test 7 failed. %s\n", uri);
1249  res = AST_TEST_FAIL;
1250  }
1251 
1252  /* Test 8, no start bracket, but with ending bracket. */
1253  if (!(uri = get_in_brackets(missing_start_bracket)) || strcmp(uri, in_brackets)) {
1254  ast_test_status_update(test, "Test 8 failed. %s\n", uri);
1255  res = AST_TEST_FAIL;
1256  }
1257 
1258  return res;
1259 }
#define NULL
Definition: resample.c:96
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
char * get_in_brackets(char *tmp)
Pick out text in brackets from character string.
def info(msg)

◆ AST_TEST_DEFINE() [6/10]

AST_TEST_DEFINE ( parse_name_andor_addr_test  )

Definition at line 1307 of file reqresp_parser.c.

References ast_copy_string(), AST_LIST_ENTRY, AST_LIST_HEAD_NOLOCK(), AST_LIST_HEAD_SET_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, desc, sip_to_pjsip::info(), uriparams::lr, uriparams::maddr, uriparams::method, name, NULL, parse_name_andor_addr(), pass, TEST_EXECUTE, TEST_INIT, uriparams::transport, uriparams::ttl, uriparams::user, and user.

1308 {
1309  int res = AST_TEST_PASS;
1310  char uri[1024];
1311  char *name, *user, *pass, *hostport, *headers, *residue;
1312  struct uriparams params;
1313 
1314  struct testdata {
1315  char *desc;
1316  char *uri;
1317  char *name;
1318  char *user;
1319  char *pass;
1320  char *hostport;
1321  char *headers;
1322  char *residue;
1323  struct uriparams params;
1324  AST_LIST_ENTRY(testdata) list;
1325  };
1326 
1327  struct testdata *testdataptr;
1328 
1329  static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
1330 
1331  struct testdata td1 = {
1332  .desc = "quotes and brackets",
1333  .uri = "\"name :@ \" <sip:user:secret@host:5060;param=discard;transport=tcp>;tag=tag",
1334  .name = "name :@ ",
1335  .user = "user",
1336  .pass = "secret",
1337  .hostport = "host:5060",
1338  .headers = "",
1339  .residue = "tag=tag",
1340  .params.transport = "tcp",
1341  .params.lr = 0,
1342  .params.user = ""
1343  };
1344 
1345  struct testdata td2 = {
1346  .desc = "no quotes",
1347  .uri = "givenname familyname <sip:user:secret@host:5060;param=discard;transport=tcp>;expires=3600",
1348  .name = "givenname familyname",
1349  .user = "user",
1350  .pass = "secret",
1351  .hostport = "host:5060",
1352  .headers = "",
1353  .residue = "expires=3600",
1354  .params.transport = "tcp",
1355  .params.lr = 0,
1356  .params.user = ""
1357  };
1358 
1359  struct testdata td3 = {
1360  .desc = "no brackets",
1361  .uri = "sip:user:secret@host:5060;param=discard;transport=tcp;q=1",
1362  .name = "",
1363  .user = "user",
1364  .pass = "secret",
1365  .hostport = "host:5060",
1366  .headers = "",
1367  .residue = "q=1",
1368  .params.transport = "tcp",
1369  .params.lr = 0,
1370  .params.user = ""
1371  };
1372 
1373  struct testdata td4 = {
1374  .desc = "just host",
1375  .uri = "sips:host",
1376  .name = "",
1377  .user = "",
1378  .pass = "",
1379  .hostport = "host",
1380  .headers = "",
1381  .residue = "",
1382  .params.transport = "",
1383  .params.lr = 0,
1384  .params.user = ""
1385  };
1386 
1387 
1388  AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &td1);
1389  AST_LIST_INSERT_TAIL(&testdatalist, &td2, list);
1390  AST_LIST_INSERT_TAIL(&testdatalist, &td3, list);
1391  AST_LIST_INSERT_TAIL(&testdatalist, &td4, list);
1392 
1393 
1394  switch (cmd) {
1395  case TEST_INIT:
1396  info->name = "parse_name_andor_addr_test";
1397  info->category = "/channels/chan_sip/";
1398  info->summary = "tests parsing of name_andor_addr abnf structure";
1399  info->description =
1400  "Tests parsing of abnf name-andor-addr = name-addr / addr-spec "
1401  "Verifies output matches expected behavior.";
1402  return AST_TEST_NOT_RUN;
1403  case TEST_EXECUTE:
1404  break;
1405  }
1406 
1407  AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
1408  name = user = pass = hostport = headers = residue = NULL;
1409  params.transport = params.user = params.method = params.ttl = params.maddr = NULL;
1410  params.lr = 0;
1411  ast_copy_string(uri,testdataptr->uri,sizeof(uri));
1412  if (parse_name_andor_addr(uri, "sip:,sips:",
1413  &name,
1414  &user,
1415  &pass,
1416  &hostport,
1417  &params,
1418  &headers,
1419  &residue) ||
1420  (name && strcmp(testdataptr->name, name)) ||
1421  (user && strcmp(testdataptr->user, user)) ||
1422  (pass && strcmp(testdataptr->pass, pass)) ||
1423  (hostport && strcmp(testdataptr->hostport, hostport)) ||
1424  (headers && strcmp(testdataptr->headers, headers)) ||
1425  (residue && strcmp(testdataptr->residue, residue)) ||
1426  (strcmp(testdataptr->params.transport,params.transport)) ||
1427  (strcmp(testdataptr->params.user,params.user))
1428  ) {
1429  ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc);
1430  res = AST_TEST_FAIL;
1431  }
1432  }
1433 
1434  return res;
1435 }
static char user[512]
static char pass[512]
static const char desc[]
Definition: cdr_mysql.c:73
#define NULL
Definition: resample.c:96
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
AST_LIST_HEAD_NOLOCK(contactliststruct, contact)
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
def info(msg)
int parse_name_andor_addr(char *uri, const char *scheme, char **name, char **user, char **pass, char **hostport, struct uriparams *params, char **headers, char **residue)
Parse the ABNF structure name-andor-addr = name-addr / addr-spec into its components and return any t...
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
uri parameters
#define AST_LIST_HEAD_SET_NOLOCK(head, entry)
Initializes a list head structure with a specified first entry.
Definition: linkedlists.h:387
static const char name[]
Definition: cdr_mysql.c:74
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401

◆ AST_TEST_DEFINE() [7/10]

AST_TEST_DEFINE ( parse_contact_header_test  )

Definition at line 1534 of file reqresp_parser.c.

References ast_copy_string(), ast_free, AST_LIST_ENTRY, AST_LIST_FIRST, AST_LIST_HEAD_NOLOCK(), AST_LIST_HEAD_SET_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_NEXT, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, desc, contact::expires, contact::headers, contact::hostport, sip_to_pjsip::info(), uriparams::lr, contact::name, NULL, contact::params, parse_contact_header(), contact::pass, contact::q, TEST_EXECUTE, TEST_INIT, uriparams::transport, uriparams::ttl, and contact::user.

1535 {
1536  int res = AST_TEST_PASS;
1537  char contactheader[1024];
1538  int star;
1539  struct contactliststruct contactlist;
1540  struct contactliststruct *contactlistptr=&contactlist;
1541 
1542  struct testdata {
1543  char *desc;
1544  char *contactheader;
1545  int star;
1546  struct contactliststruct *contactlist;
1547 
1548  AST_LIST_ENTRY(testdata) list;
1549  };
1550 
1551  struct testdata *testdataptr;
1552  struct contact *tdcontactptr;
1553  struct contact *contactptr;
1554 
1555  static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
1556  struct contactliststruct contactlist1, contactlist2;
1557 
1558  struct testdata td1 = {
1559  .desc = "single contact",
1560  .contactheader = "\"name :@;?&,\" <sip:user:secret@host:5082;param=discard;transport=tcp>;expires=3600",
1561  .contactlist = &contactlist1,
1562  .star = 0
1563  };
1564  struct contact contact11 = {
1565  .name = "name :@;?&,",
1566  .user = "user",
1567  .pass = "secret",
1568  .hostport = "host:5082",
1569  .params.transport = "tcp",
1570  .params.ttl = "",
1571  .params.lr = 0,
1572  .headers = "",
1573  .expires = "3600",
1574  .q = ""
1575  };
1576 
1577  struct testdata td2 = {
1578  .desc = "multiple contacts",
1579  .contactheader = "sip:,user1,:,secret1,@host1;ttl=7;q=1;expires=3600,sips:host2",
1580  .contactlist = &contactlist2,
1581  .star = 0,
1582  };
1583  struct contact contact21 = {
1584  .name = "",
1585  .user = ",user1,",
1586  .pass = ",secret1,",
1587  .hostport = "host1",
1588  .params.transport = "",
1589  .params.ttl = "7",
1590  .params.lr = 0,
1591  .headers = "",
1592  .expires = "3600",
1593  .q = "1"
1594  };
1595  struct contact contact22 = {
1596  .name = "",
1597  .user = "",
1598  .pass = "",
1599  .hostport = "host2",
1600  .params.transport = "",
1601  .params.ttl = "",
1602  .params.lr = 0,
1603  .headers = "",
1604  .expires = "",
1605  .q = ""
1606  };
1607 
1608  struct testdata td3 = {
1609  .desc = "star - all contacts",
1610  .contactheader = "*",
1611  .star = 1,
1612  .contactlist = NULL
1613  };
1614 
1615  AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &td1);
1616  AST_LIST_INSERT_TAIL(&testdatalist, &td2, list);
1617  AST_LIST_INSERT_TAIL(&testdatalist, &td3, list);
1618 
1619  AST_LIST_HEAD_SET_NOLOCK(&contactlist1, &contact11);
1620 
1621  AST_LIST_HEAD_SET_NOLOCK(&contactlist2, &contact21);
1622  AST_LIST_INSERT_TAIL(&contactlist2, &contact22, list);
1623 
1624 
1625  switch (cmd) {
1626  case TEST_INIT:
1627  info->name = "parse_contact_header_test";
1628  info->category = "/channels/chan_sip/";
1629  info->summary = "tests parsing of sip contact header";
1630  info->description =
1631  "Tests parsing of a contact header including those with multiple contacts "
1632  "Verifies output matches expected behavior.";
1633  return AST_TEST_NOT_RUN;
1634  case TEST_EXECUTE:
1635  break;
1636  }
1637 
1638  AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
1639  ast_copy_string(contactheader,testdataptr->contactheader,sizeof(contactheader));
1640  star = parse_contact_header(contactheader,contactlistptr);
1641  if (testdataptr->star) {
1642  /* expecting star rather than list of contacts */
1643  if (!star) {
1644  ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc);
1645  res = AST_TEST_FAIL;
1646  break;
1647  }
1648  } else {
1649  contactptr = AST_LIST_FIRST(contactlistptr);
1650  AST_LIST_TRAVERSE(testdataptr->contactlist, tdcontactptr, list) {
1651  if (!contactptr ||
1652  strcmp(tdcontactptr->name, contactptr->name) ||
1653  strcmp(tdcontactptr->user, contactptr->user) ||
1654  strcmp(tdcontactptr->pass, contactptr->pass) ||
1655  strcmp(tdcontactptr->hostport, contactptr->hostport) ||
1656  strcmp(tdcontactptr->headers, contactptr->headers) ||
1657  strcmp(tdcontactptr->expires, contactptr->expires) ||
1658  strcmp(tdcontactptr->q, contactptr->q) ||
1659  strcmp(tdcontactptr->params.transport, contactptr->params.transport) ||
1660  strcmp(tdcontactptr->params.ttl, contactptr->params.ttl) ||
1661  (tdcontactptr->params.lr != contactptr->params.lr)
1662  ) {
1663  ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc);
1664  res = AST_TEST_FAIL;
1665  break;
1666  }
1667 
1668  contactptr = AST_LIST_NEXT(contactptr,list);
1669  }
1670 
1671  while ((contactptr = AST_LIST_REMOVE_HEAD(contactlistptr,list))) {
1672  ast_free(contactptr);
1673  }
1674  }
1675  }
1676 
1677  return res;
1678 }
char * user
struct uriparams params
char * headers
char * expires
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:438
static const char desc[]
Definition: cdr_mysql.c:73
#define NULL
Definition: resample.c:96
char * transport
char * hostport
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
AST_LIST_HEAD_NOLOCK(contactliststruct, contact)
char * pass
char * name
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
int parse_contact_header(char *contactheader, struct contactliststruct *contactlist)
def info(msg)
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
#define AST_LIST_HEAD_SET_NOLOCK(head, entry)
Initializes a list head structure with a specified first entry.
Definition: linkedlists.h:387
char * ttl
#define ast_free(a)
Definition: astmm.h:182
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
char * q

◆ AST_TEST_DEFINE() [8/10]

AST_TEST_DEFINE ( sip_parse_options_test  )

Definition at line 1768 of file reqresp_parser.c.

References ARRAY_LEN, AST_LIST_ENTRY, AST_LIST_HEAD_NOLOCK(), AST_LIST_HEAD_SET_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, sip_to_pjsip::info(), name, NULL, parse_sip_options(), SIP_OPT_REPLACES, SIP_OPT_TIMER, SIP_OPT_UNKNOWN, TEST_EXECUTE, and TEST_INIT.

1769 {
1770  int res = AST_TEST_PASS;
1771  char unsupported[64];
1772  unsigned int option_profile = 0;
1773  struct testdata {
1774  char *name;
1775  char *input_options;
1776  char *expected_unsupported;
1777  unsigned int expected_profile;
1778  AST_LIST_ENTRY(testdata) list;
1779  };
1780 
1781  struct testdata *testdataptr;
1782  static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
1783 
1784  struct testdata test1 = {
1785  .name = "test_all_unsupported",
1786  .input_options = "unsupported1,,, ,unsupported2,unsupported3,unsupported4",
1787  .expected_unsupported = "unsupported1,unsupported2,unsupported3,unsupported4",
1788  .expected_profile = SIP_OPT_UNKNOWN,
1789  };
1790  struct testdata test2 = {
1791  .name = "test_all_unsupported_one_supported",
1792  .input_options = " unsupported1, replaces, unsupported3 , , , ,unsupported4",
1793  .expected_unsupported = "unsupported1,unsupported3,unsupported4",
1794  .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES
1795  };
1796  struct testdata test3 = {
1797  .name = "test_two_supported_two_unsupported",
1798  .input_options = ",, timer ,replaces ,unsupported3,unsupported4",
1799  .expected_unsupported = "unsupported3,unsupported4",
1800  .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES | SIP_OPT_TIMER,
1801  };
1802 
1803  struct testdata test4 = {
1804  .name = "test_all_supported",
1805  .input_options = "timer,replaces",
1806  .expected_unsupported = "",
1807  .expected_profile = SIP_OPT_REPLACES | SIP_OPT_TIMER,
1808  };
1809 
1810  struct testdata test5 = {
1811  .name = "test_all_supported_redundant",
1812  .input_options = "timer,replaces,timer,replace,timer,replaces",
1813  .expected_unsupported = "",
1814  .expected_profile = SIP_OPT_REPLACES | SIP_OPT_TIMER,
1815  };
1816  struct testdata test6 = {
1817  .name = "test_buffer_overflow",
1818  .input_options = "unsupported1,replaces,timer,unsupported4,unsupported_huge____"
1819  "____________________________________,__________________________________________"
1820  "________________________________________________",
1821  .expected_unsupported = "unsupported1,unsupported4",
1822  .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES | SIP_OPT_TIMER,
1823  };
1824  struct testdata test7 = {
1825  .name = "test_null_input",
1826  .input_options = NULL,
1827  .expected_unsupported = "",
1828  .expected_profile = 0,
1829  };
1830  struct testdata test8 = {
1831  .name = "test_whitespace_input",
1832  .input_options = " ",
1833  .expected_unsupported = "",
1834  .expected_profile = 0,
1835  };
1836  struct testdata test9 = {
1837  .name = "test_whitespace_plus_option_input",
1838  .input_options = " , , ,timer , , , , , ",
1839  .expected_unsupported = "",
1840  .expected_profile = SIP_OPT_TIMER,
1841  };
1842 
1843  switch (cmd) {
1844  case TEST_INIT:
1845  info->name = "sip_parse_options_test";
1846  info->category = "/channels/chan_sip/";
1847  info->summary = "Tests parsing of sip options";
1848  info->description =
1849  "Tests parsing of SIP options from supported and required "
1850  "header fields. Verifies when unsupported options are encountered "
1851  "that they are appended to the unsupported out buffer and that the "
1852  "correct bit field representnig the option profile is returned.";
1853  return AST_TEST_NOT_RUN;
1854  case TEST_EXECUTE:
1855  break;
1856  }
1857 
1858  AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &test1);
1859  AST_LIST_INSERT_TAIL(&testdatalist, &test2, list);
1860  AST_LIST_INSERT_TAIL(&testdatalist, &test3, list);
1861  AST_LIST_INSERT_TAIL(&testdatalist, &test4, list);
1862  AST_LIST_INSERT_TAIL(&testdatalist, &test5, list);
1863  AST_LIST_INSERT_TAIL(&testdatalist, &test6, list);
1864  AST_LIST_INSERT_TAIL(&testdatalist, &test7, list);
1865  AST_LIST_INSERT_TAIL(&testdatalist, &test8, list);
1866  AST_LIST_INSERT_TAIL(&testdatalist, &test9, list);
1867 
1868  /* Test with unsupported char buffer */
1869  AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
1870  memset(unsupported, 0, sizeof(unsupported));
1871  option_profile = parse_sip_options(testdataptr->input_options, unsupported, ARRAY_LEN(unsupported));
1872  if (option_profile != testdataptr->expected_profile ||
1873  strcmp(unsupported, testdataptr->expected_unsupported)) {
1874  ast_test_status_update(test, "Test with output buffer \"%s\", expected unsupported: %s actual unsupported:"
1875  "%s expected bit profile: %x actual bit profile: %x\n",
1876  testdataptr->name,
1877  testdataptr->expected_unsupported,
1878  unsupported,
1879  testdataptr->expected_profile,
1880  option_profile);
1881  res = AST_TEST_FAIL;
1882  } else {
1883  ast_test_status_update(test, "\"%s\" passed got expected unsupported: %s and bit profile: %x\n",
1884  testdataptr->name,
1885  unsupported,
1886  option_profile);
1887  }
1888 
1889  option_profile = parse_sip_options(testdataptr->input_options, NULL, 0);
1890  if (option_profile != testdataptr->expected_profile) {
1891  ast_test_status_update(test, "NULL output test \"%s\", expected bit profile: %x actual bit profile: %x\n",
1892  testdataptr->name,
1893  testdataptr->expected_profile,
1894  option_profile);
1895  res = AST_TEST_FAIL;
1896  } else {
1897  ast_test_status_update(test, "\"%s\" with NULL output buf passed, bit profile: %x\n",
1898  testdataptr->name,
1899  option_profile);
1900  }
1901  }
1902 
1903  return res;
1904 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
unsigned int parse_sip_options(const char *options, char *unsupported, size_t unsupported_len)
Parse supported header in incoming packet.
#define SIP_OPT_UNKNOWN
Definition: sip.h:167
#define SIP_OPT_TIMER
Definition: sip.h:148
#define NULL
Definition: resample.c:96
char name[10]
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
AST_LIST_HEAD_NOLOCK(contactliststruct, contact)
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
def info(msg)
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
#define AST_LIST_HEAD_SET_NOLOCK(head, entry)
Initializes a list head structure with a specified first entry.
Definition: linkedlists.h:387
static const char name[]
Definition: cdr_mysql.c:74
#define SIP_OPT_REPLACES
Definition: sip.h:146

◆ AST_TEST_DEFINE() [9/10]

AST_TEST_DEFINE ( sip_uri_cmp_test  )

Definition at line 2261 of file reqresp_parser.c.

References ARRAY_LEN, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, sip_to_pjsip::info(), NULL, sip_uri_cmp(), TEST_EXECUTE, TEST_INIT, test_res, URI_CMP_MATCH, and URI_CMP_NOMATCH.

2262 {
2263  static const struct {
2264  const char *uri1;
2265  const char *uri2;
2266  int expected_result;
2267  } uri_cmp_tests [] = {
2268  /* These are identical, so they match */
2270  /* Different usernames. No match */
2272  /* Different hosts. No match */
2274  /* Now start using IP addresses. Identical, so they match */
2276  /* Two identical IPv4 addresses represented differently. Match */
2278  /* Logically equivalent IPv4 Address and hostname. No Match */
2279  { "sip:[email protected]", "sip:bob@localhost", URI_CMP_NOMATCH },
2280  /* Logically equivalent IPv6 address and hostname. No Match */
2281  { "sip:bob@[::1]", "sip:bob@localhost", URI_CMP_NOMATCH },
2282  /* Try an IPv6 one as well */
2283  { "sip:bob@[2001:db8::1234]", "sip:bob@[2001:db8::1234]", URI_CMP_MATCH },
2284  /* Two identical IPv6 addresses represented differently. Match */
2285  { "sip:bob@[2001:db8::1234]", "sip:bob@[2001:0db8::1234]", URI_CMP_MATCH },
2286  /* Different ports. No match */
2287  { "sip:[email protected]:5060", "sip:[email protected]:5061", URI_CMP_NOMATCH },
2288  /* Same port logically, but only one address specifies it. No match */
2289  { "sip:[email protected]:5060", "sip:[email protected]", URI_CMP_NOMATCH },
2290  /* And for safety, try with IPv6 */
2291  { "sip:bob@[2001:db8:1234]:5060", "sip:bob@[2001:db8:1234]", URI_CMP_NOMATCH },
2292  /* User comparison is case sensitive. No match */
2294  /* Host comparison is case insensitive. Match */
2296  /* Add headers to the URI. Identical, so they match */
2297  { "sip:[email protected]?header1=value1&header2=value2", "sip:[email protected]?header1=value1&header2=value2", URI_CMP_MATCH },
2298  /* Headers in URI 1 are not in URI 2. No Match */
2299  { "sip:[email protected]?header1=value1&header2=value2", "sip:[email protected]", URI_CMP_NOMATCH },
2300  /* Header present in both URIs does not have matching values. No match */
2301  { "sip:[email protected]?header1=value1&header2=value2", "sip:[email protected]?header1=value1&header2=value3", URI_CMP_NOMATCH },
2302  /* Add parameters to the URI. Identical so they match */
2303  { "sip:[email protected];param1=value1;param2=value2", "sip:[email protected];param1=value1;param2=value2", URI_CMP_MATCH },
2304  /* Same parameters in both URIs but appear in different order. Match */
2305  { "sip:[email protected];param2=value2;param1=value1", "sip:[email protected];param1=value1;param2=value2", URI_CMP_MATCH },
2306  /* params in URI 1 are not in URI 2. Match */
2307  { "sip:[email protected];param1=value1;param2=value2", "sip:[email protected]", URI_CMP_MATCH },
2308  /* param present in both URIs does not have matching values. No match */
2309  { "sip:[email protected];param1=value1;param2=value2", "sip:[email protected];param1=value1;param2=value3", URI_CMP_NOMATCH },
2310  /* URI 1 has a maddr param but URI 2 does not. No match */
2311  { "sip:[email protected];param1=value1;maddr=192.168.0.1", "sip:[email protected];param1=value1", URI_CMP_NOMATCH },
2312  /* URI 1 and URI 2 both have identical maddr params. Match */
2313  { "sip:[email protected];param1=value1;maddr=192.168.0.1", "sip:[email protected];param1=value1;maddr=192.168.0.1", URI_CMP_MATCH },
2314  /* URI 1 is a SIPS URI and URI 2 is a SIP URI. No Match */
2316  /* No URI schemes. No match */
2318  /* Crashiness tests. Just an address scheme. No match */
2319  { "sip", "sips", URI_CMP_NOMATCH },
2320  /* Still just an address scheme. Even though they're the same, No match */
2321  { "sip", "sip", URI_CMP_NOMATCH },
2322  /* Empty strings. No match */
2323  { "", "", URI_CMP_NOMATCH },
2324  /* An empty string and a NULL. No match */
2325  { "", NULL, URI_CMP_NOMATCH },
2326  };
2327  int i;
2328  int test_res = AST_TEST_PASS;
2329  switch (cmd) {
2330  case TEST_INIT:
2331  info->name = "sip_uri_cmp_test";
2332  info->category = "/channels/chan_sip/";
2333  info->summary = "Tests comparison of SIP URIs";
2334  info->description = "Several would-be tricky URI comparisons are performed";
2335  return AST_TEST_NOT_RUN;
2336  case TEST_EXECUTE:
2337  break;
2338  }
2339 
2340  for (i = 0; i < ARRAY_LEN(uri_cmp_tests); ++i) {
2341  int cmp_res1;
2342  int cmp_res2;
2343  if ((cmp_res1 = sip_uri_cmp(uri_cmp_tests[i].uri1, uri_cmp_tests[i].uri2))) {
2344  /* URI comparison may return -1 or +1 depending on the failure. Standardize
2345  * the return value to be URI_CMP_NOMATCH on any failure
2346  */
2347  cmp_res1 = URI_CMP_NOMATCH;
2348  }
2349  if (cmp_res1 != uri_cmp_tests[i].expected_result) {
2350  ast_test_status_update(test, "Unexpected comparison result for URIs %s and %s. "
2351  "Expected %s but got %s\n", uri_cmp_tests[i].uri1, uri_cmp_tests[i].uri2,
2352  uri_cmp_tests[i].expected_result == URI_CMP_MATCH ? "Match" : "No Match",
2353  cmp_res1 == URI_CMP_MATCH ? "Match" : "No Match");
2354  test_res = AST_TEST_FAIL;
2355  }
2356 
2357  /* All URI comparisons are commutative, so for the sake of being thorough, we'll
2358  * rerun the comparison with the parameters reversed
2359  */
2360  if ((cmp_res2 = sip_uri_cmp(uri_cmp_tests[i].uri2, uri_cmp_tests[i].uri1))) {
2361  /* URI comparison may return -1 or +1 depending on the failure. Standardize
2362  * the return value to be URI_CMP_NOMATCH on any failure
2363  */
2364  cmp_res2 = URI_CMP_NOMATCH;
2365  }
2366  if (cmp_res2 != uri_cmp_tests[i].expected_result) {
2367  ast_test_status_update(test, "Unexpected comparison result for URIs %s and %s. "
2368  "Expected %s but got %s\n", uri_cmp_tests[i].uri2, uri_cmp_tests[i].uri1,
2369  uri_cmp_tests[i].expected_result == URI_CMP_MATCH ? "Match" : "No Match",
2370  cmp_res2 == URI_CMP_MATCH ? "Match" : "No Match");
2371  test_res = AST_TEST_FAIL;
2372  }
2373  }
2374 
2375  return test_res;
2376 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
#define URI_CMP_NOMATCH
int sip_uri_cmp(const char *input1, const char *input2)
Compare two URIs as described in RFC 3261 Section 19.1.4.
#define NULL
Definition: resample.c:96
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define URI_CMP_MATCH
static enum ast_test_result_state test_res
def info(msg)

◆ AST_TEST_DEFINE() [10/10]

AST_TEST_DEFINE ( parse_via_test  )

Definition at line 2465 of file reqresp_parser.c.

References AST_LIST_ENTRY, AST_LIST_HEAD_NOLOCK(), AST_LIST_HEAD_SET_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_strlen_zero, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, sip_via::branch, free_via(), in, sip_to_pjsip::info(), sip_via::maddr, parse_via(), sip_via::port, sip_via::protocol, sip_via::sent_by, TEST_EXECUTE, TEST_INIT, sip_via::ttl, and sip_via::via.

2466 {
2467  int res = AST_TEST_PASS;
2468  int i = 1;
2469  struct sip_via *via;
2470  struct testdata {
2471  char *in;
2472  char *expected_protocol;
2473  char *expected_branch;
2474  char *expected_sent_by;
2475  char *expected_maddr;
2476  unsigned int expected_port;
2477  unsigned char expected_ttl;
2478  int expected_null;
2479  AST_LIST_ENTRY(testdata) list;
2480  };
2481  struct testdata *testdataptr;
2482  static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
2483  struct testdata t1 = {
2484  .in = "SIP/2.0/UDP host:port;branch=thebranch",
2485  .expected_protocol = "SIP/2.0/UDP",
2486  .expected_sent_by = "host:port",
2487  .expected_branch = "thebranch",
2488  };
2489  struct testdata t2 = {
2490  .in = "SIP/2.0/UDP host:port",
2491  .expected_protocol = "SIP/2.0/UDP",
2492  .expected_sent_by = "host:port",
2493  .expected_branch = "",
2494  };
2495  struct testdata t3 = {
2496  .in = "SIP/2.0/UDP",
2497  .expected_null = 1,
2498  };
2499  struct testdata t4 = {
2500  .in = "BLAH/BLAH/BLAH host:port;branch=",
2501  .expected_protocol = "BLAH/BLAH/BLAH",
2502  .expected_sent_by = "host:port",
2503  .expected_branch = "",
2504  };
2505  struct testdata t5 = {
2506  .in = "SIP/2.0/UDP host:5060;branch=thebranch;maddr=224.0.0.1;ttl=1",
2507  .expected_protocol = "SIP/2.0/UDP",
2508  .expected_sent_by = "host:5060",
2509  .expected_port = 5060,
2510  .expected_branch = "thebranch",
2511  .expected_maddr = "224.0.0.1",
2512  .expected_ttl = 1,
2513  };
2514  struct testdata t6 = {
2515  .in = "SIP/2.0/UDP host:5060;\n branch=thebranch;\r\n maddr=224.0.0.1; ttl=1",
2516  .expected_protocol = "SIP/2.0/UDP",
2517  .expected_sent_by = "host:5060",
2518  .expected_port = 5060,
2519  .expected_branch = "thebranch",
2520  .expected_maddr = "224.0.0.1",
2521  .expected_ttl = 1,
2522  };
2523  struct testdata t7 = {
2524  .in = "SIP/2.0/UDP [::1]:5060",
2525  .expected_protocol = "SIP/2.0/UDP",
2526  .expected_sent_by = "[::1]:5060",
2527  .expected_port = 5060,
2528  .expected_branch = "",
2529  };
2530  switch (cmd) {
2531  case TEST_INIT:
2532  info->name = "parse_via_test";
2533  info->category = "/channels/chan_sip/";
2534  info->summary = "Tests parsing the Via header";
2535  info->description =
2536  "Runs through various test situations in which various "
2537  " parameters parameter must be extracted from a VIA header";
2538  return AST_TEST_NOT_RUN;
2539  case TEST_EXECUTE:
2540  break;
2541  }
2542 
2543  AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &t1);
2544  AST_LIST_INSERT_TAIL(&testdatalist, &t2, list);
2545  AST_LIST_INSERT_TAIL(&testdatalist, &t3, list);
2546  AST_LIST_INSERT_TAIL(&testdatalist, &t4, list);
2547  AST_LIST_INSERT_TAIL(&testdatalist, &t5, list);
2548  AST_LIST_INSERT_TAIL(&testdatalist, &t6, list);
2549  AST_LIST_INSERT_TAIL(&testdatalist, &t7, list);
2550 
2551 
2552  AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
2553  via = parse_via(testdataptr->in);
2554  if (!via) {
2555  if (!testdataptr->expected_null) {
2556  ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2557  "failed to parse header\n",
2558  i, testdataptr->in);
2559  res = AST_TEST_FAIL;
2560  }
2561  i++;
2562  continue;
2563  }
2564 
2565  if (testdataptr->expected_null) {
2566  ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2567  "successfully parased invalid via header\n",
2568  i, testdataptr->in);
2569  res = AST_TEST_FAIL;
2570  free_via(via);
2571  i++;
2572  continue;
2573  }
2574 
2575  if ((ast_strlen_zero(via->protocol) && !ast_strlen_zero(testdataptr->expected_protocol))
2576  || (!ast_strlen_zero(via->protocol) && strcmp(via->protocol, testdataptr->expected_protocol))) {
2577 
2578  ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2579  "parsed protocol = \"%s\"\n"
2580  "expected = \"%s\"\n"
2581  "failed to parse protocol\n",
2582  i, testdataptr->in, via->protocol, testdataptr->expected_protocol);
2583  res = AST_TEST_FAIL;
2584  }
2585 
2586  if ((ast_strlen_zero(via->sent_by) && !ast_strlen_zero(testdataptr->expected_sent_by))
2587  || (!ast_strlen_zero(via->sent_by) && strcmp(via->sent_by, testdataptr->expected_sent_by))) {
2588 
2589  ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2590  "parsed sent_by = \"%s\"\n"
2591  "expected = \"%s\"\n"
2592  "failed to parse sent-by\n",
2593  i, testdataptr->in, via->sent_by, testdataptr->expected_sent_by);
2594  res = AST_TEST_FAIL;
2595  }
2596 
2597  if (testdataptr->expected_port && testdataptr->expected_port != via->port) {
2598  ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2599  "parsed port = \"%u\"\n"
2600  "expected = \"%u\"\n"
2601  "failed to parse port\n",
2602  i, testdataptr->in, via->port, testdataptr->expected_port);
2603  res = AST_TEST_FAIL;
2604  }
2605 
2606  if ((ast_strlen_zero(via->branch) && !ast_strlen_zero(testdataptr->expected_branch))
2607  || (!ast_strlen_zero(via->branch) && strcmp(via->branch, testdataptr->expected_branch))) {
2608 
2609  ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2610  "parsed branch = \"%s\"\n"
2611  "expected = \"%s\"\n"
2612  "failed to parse branch\n",
2613  i, testdataptr->in, via->branch, testdataptr->expected_branch);
2614  res = AST_TEST_FAIL;
2615  }
2616 
2617  if ((ast_strlen_zero(via->maddr) && !ast_strlen_zero(testdataptr->expected_maddr))
2618  || (!ast_strlen_zero(via->maddr) && strcmp(via->maddr, testdataptr->expected_maddr))) {
2619 
2620  ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2621  "parsed maddr = \"%s\"\n"
2622  "expected = \"%s\"\n"
2623  "failed to parse maddr\n",
2624  i, testdataptr->in, via->maddr, testdataptr->expected_maddr);
2625  res = AST_TEST_FAIL;
2626  }
2627 
2628  if (testdataptr->expected_ttl && testdataptr->expected_ttl != via->ttl) {
2629  ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2630  "parsed ttl = \"%d\"\n"
2631  "expected = \"%d\"\n"
2632  "failed to parse ttl\n",
2633  i, testdataptr->in, via->ttl, testdataptr->expected_ttl);
2634  res = AST_TEST_FAIL;
2635  }
2636 
2637  free_via(via);
2638  i++;
2639  }
2640  return res;
2641 }
const char * maddr
Definition: sip.h:879
unsigned char ttl
Definition: sip.h:881
static uint16_t t7
Definition: res_pktccops.c:158
#define ast_strlen_zero(foo)
Definition: strings.h:52
Structure to store Via information.
Definition: sip.h:874
FILE * in
Definition: utils/frame.c:33
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
const char * branch
Definition: sip.h:878
void free_via(struct sip_via *v)
AST_LIST_HEAD_NOLOCK(contactliststruct, contact)
char * via
Definition: sip.h:875
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
def info(msg)
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
#define AST_LIST_HEAD_SET_NOLOCK(head, entry)
Initializes a list head structure with a specified first entry.
Definition: linkedlists.h:387
const char * sent_by
Definition: sip.h:877
unsigned int port
Definition: sip.h:880
struct sip_via * parse_via(const char *header)
Parse a Via header.
const char * protocol
Definition: sip.h:876
static uint16_t t1
Definition: res_pktccops.c:157

◆ free_via()

void free_via ( struct sip_via v)

Definition at line 2379 of file reqresp_parser.c.

References ast_free, and sip_via::via.

Referenced by __find_call(), __sip_alloc(), AST_TEST_DEFINE(), parse_via(), and process_via().

2380 {
2381  if (!v) {
2382  return;
2383  }
2384 
2385  ast_free(v->via);
2386  ast_free(v);
2387 }
char * via
Definition: sip.h:875
#define ast_free(a)
Definition: astmm.h:182

◆ get_calleridname()

const char* get_calleridname ( const char *  input,
char *  output,
size_t  outputsize 
)

Get caller id name from SIP headers, copy into output buffer.

Return values
inputstring pointer placed after display-name field if possible

Definition at line 695 of file reqresp_parser.c.

References ast_log, ast_skip_blanks(), input(), and LOG_WARNING.

Referenced by AST_TEST_DEFINE(), check_user_full(), get_name_and_number(), parse_name_andor_addr(), and receive_message().

696 {
697  /* From RFC3261:
698  *
699  * From = ( "From" / "f" ) HCOLON from-spec
700  * from-spec = ( name-addr / addr-spec ) *( SEMI from-param )
701  * name-addr = [ display-name ] LAQUOT addr-spec RAQUOT
702  * display-name = *(token LWS)/ quoted-string
703  * token = 1*(alphanum / "-" / "." / "!" / "%" / "*"
704  * / "_" / "+" / "`" / "'" / "~" )
705  * quoted-string = SWS DQUOTE *(qdtext / quoted-pair ) DQUOTE
706  * qdtext = LWS / %x21 / %x23-5B / %x5D-7E
707  * / UTF8-NONASCII
708  * quoted-pair = "\" (%x00-09 / %x0B-0C / %x0E-7F)
709  *
710  * HCOLON = *WSP ":" SWS
711  * SWS = [LWS]
712  * LWS = *[*WSP CRLF] 1*WSP
713  * WSP = (SP / HTAB)
714  *
715  * Deviations from it:
716  * - following CRLF's in LWS is not done (here at least)
717  * - ascii NUL is never legal as it terminates the C-string
718  * - utf8-nonascii is not checked for validity
719  */
720  char *orig_output = output;
721  const char *orig_input = input;
722 
723  if (!output || !outputsize) {
724  /* Bad output parameters. Should never happen. */
725  return input;
726  }
727 
728  /* clear any empty characters in the beginning */
730 
731  /* make sure the output buffer is initilized */
732  *orig_output = '\0';
733 
734  /* make room for '\0' at the end of the output buffer */
735  --outputsize;
736 
737  /* no data at all or no display name? */
738  if (!input || *input == '<') {
739  return input;
740  }
741 
742  /* quoted-string rules */
743  if (input[0] == '"') {
744  input++; /* skip the first " */
745 
746  for (; *input; ++input) {
747  if (*input == '"') { /* end of quoted-string */
748  break;
749  } else if (*input == 0x5c) { /* quoted-pair = "\" (%x00-09 / %x0B-0C / %x0E-7F) */
750  ++input;
751  if (!*input) {
752  break;
753  }
754  if ((unsigned char) *input > 0x7f || *input == 0xa || *input == 0xd) {
755  continue; /* not a valid quoted-pair, so skip it */
756  }
757  } else if ((*input != 0x9 && (unsigned char) *input < 0x20)
758  || *input == 0x7f) {
759  continue; /* skip this invalid character. */
760  }
761 
762  if (0 < outputsize) {
763  /* We still have room for the output display-name. */
764  *output++ = *input;
765  --outputsize;
766  }
767  }
768 
769  /* if this is successful, input should be at the ending quote */
770  if (*input != '"') {
771  ast_log(LOG_WARNING, "No ending quote for display-name was found\n");
772  *orig_output = '\0';
773  return orig_input;
774  }
775 
776  /* make sure input is past the last quote */
777  ++input;
778 
779  /* terminate output */
780  *output = '\0';
781  } else { /* either an addr-spec or tokenLWS-combo */
782  for (; *input; ++input) {
783  /* token or WSP (without LWS) */
784  if ((*input >= '0' && *input <= '9') || (*input >= 'A' && *input <= 'Z')
785  || (*input >= 'a' && *input <= 'z') || *input == '-' || *input == '.'
786  || *input == '!' || *input == '%' || *input == '*' || *input == '_'
787  || *input == '+' || *input == '`' || *input == '\'' || *input == '~'
788  || *input == 0x9 || *input == ' ') {
789  if (0 < outputsize) {
790  /* We still have room for the output display-name. */
791  *output++ = *input;
792  --outputsize;
793  }
794  } else if (*input == '<') { /* end of tokenLWS-combo */
795  /* we could assert that the previous char is LWS, but we don't care */
796  break;
797  } else if (*input == ':') {
798  /* This invalid character which indicates this is addr-spec rather than display-name. */
799  *orig_output = '\0';
800  return orig_input;
801  } else { /* else, invalid character we can skip. */
802  continue; /* skip this character */
803  }
804  }
805 
806  if (*input != '<') { /* if we never found the start of addr-spec then this is invalid */
807  *orig_output = '\0';
808  return orig_input;
809  }
810 
811  /* terminate output while trimming any trailing whitespace */
812  do {
813  *output-- = '\0';
814  } while (orig_output <= output && (*output == 0x9 || *output == ' '));
815  }
816 
817  return input;
818 }
#define LOG_WARNING
Definition: logger.h:274
static int input(yyscan_t yyscanner)
Definition: ast_expr2f.c:1584
#define ast_log
Definition: astobj2.c:42
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:157

◆ get_comma()

int get_comma ( char *  parse,
char **  out 
)

Parse all contact header contacts.

Return values
0success
-1failure
1all contacts (star)

Definition at line 1438 of file reqresp_parser.c.

References ast_log, c, find_closing_quote(), in, LOG_WARNING, NULL, and parse().

Referenced by parse_contact_header().

1439 {
1440  char *c;
1441  char *parse = in;
1442  if (out) {
1443  *out = in;
1444  }
1445 
1446  /* Skip any quoted text */
1447  while (*parse) {
1448  if ((c = strchr(parse, '"'))) {
1449  in = (char *)find_closing_quote((const char *)c + 1, NULL);
1450  if (!*in) {
1451  ast_log(LOG_WARNING, "No closing quote found in '%s'\n", c);
1452  return -1;
1453  } else {
1454  break;
1455  }
1456  } else {
1457  break;
1458  }
1459  parse++;
1460  }
1461  parse = in;
1462 
1463  /* Skip any userinfo components of a uri as they may contain commas */
1464  if ((c = strchr(parse,'@'))) {
1465  parse = c+1;
1466  }
1467  if ((out) && (c = strchr(parse,','))) {
1468  *c++ = '\0';
1469  *out = c;
1470  return 0;
1471  }
1472  return 1;
1473 }
#define LOG_WARNING
Definition: logger.h:274
static struct test_val c
const char * find_closing_quote(const char *start, const char *lim)
Locate closing quote in a string, skipping escaped quotes. optionally with a limit on the search...
Definition: chan_sip.c:5074
#define NULL
Definition: resample.c:96
#define ast_log
Definition: astobj2.c:42
FILE * in
Definition: utils/frame.c:33
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
FILE * out
Definition: utils/frame.c:33

◆ get_in_brackets()

char* get_in_brackets ( char *  tmp)

Pick out text in brackets from character string.

Returns
pointer to terminated stripped string
Parameters
tmpinput string that will be modified

Examples:

* "foo" <bar>  valid input, returns bar
*  foo returns the whole string
* < "foo ... > returns the string between brackets
* < "foo...    bogus (missing closing bracket), returns the whole string
* 

Definition at line 1173 of file reqresp_parser.c.

References get_in_brackets_full(), NULL, out, and tmp().

Referenced by AST_TEST_DEFINE(), check_user_full(), extract_uri(), get_also_info(), get_destination(), get_domain(), get_name_and_number(), get_pai(), get_rdnis(), get_refer_info(), handle_cc_notify(), parse_moved_contact(), parse_ok_contact(), parse_register_contact(), receive_message(), register_verify(), reqprep(), sip_get_cc_information(), sip_msg_send(), transmit_refer(), transmit_state_notify(), uac_sips_contact(), and uas_sips_contact().

1174 {
1175  char *out;
1176 
1177  if ((get_in_brackets_full(tmp, &out, NULL))) {
1178  return tmp;
1179  }
1180  return out;
1181 }
static int tmp()
Definition: bt_open.c:389
int get_in_brackets_full(char *tmp, char **out, char **residue)
Get text in brackets and any trailing residue.
#define NULL
Definition: resample.c:96
FILE * out
Definition: utils/frame.c:33

◆ get_in_brackets_const()

int get_in_brackets_const ( const char *  src,
const char **  start,
int *  length 
)

Get text in brackets on a const without copy.

Parameters
srcString to search
[out]startSet to first character inside left bracket.
[out]lengthSet to lenght of string inside brackets
Return values
0success
-1failure
1no brackets so got all

Definition at line 1052 of file reqresp_parser.c.

References ast_log, ast_strlen_zero, find_closing_quote(), LOG_WARNING, NULL, and parse().

Referenced by build_route(), and sip_route_process_header().

1053 {
1054  const char *parse = src;
1055  const char *first_bracket;
1056  const char *second_bracket;
1057 
1058  if (start == NULL) {
1059  return -1;
1060  }
1061  if (length == NULL) {
1062  return -1;
1063  }
1064  *start = NULL;
1065  *length = -1;
1066  if (ast_strlen_zero(src)) {
1067  return 1;
1068  }
1069 
1070  /*
1071  * Skip any quoted text until we find the part in brackets.
1072  * On any error give up and return -1
1073  */
1074  while ( (first_bracket = strchr(parse, '<')) ) {
1075  const char *first_quote = strchr(parse, '"');
1076  first_bracket++;
1077  if (!first_quote || first_quote >= first_bracket) {
1078  break; /* no need to look at quoted part */
1079  }
1080  /* the bracket is within quotes, so ignore it */
1081  parse = find_closing_quote(first_quote + 1, NULL);
1082  if (!*parse) {
1083  ast_log(LOG_WARNING, "No closing quote found in '%s'\n", src);
1084  return -1;
1085  }
1086  parse++;
1087  }
1088 
1089  /* Require a first bracket. Unlike get_in_brackets_full, this procedure is passed a const,
1090  * so it can expect a pointer to an original value */
1091  if (!first_bracket) {
1092  ast_log(LOG_WARNING, "No opening bracket found in '%s'\n", src);
1093  return 1;
1094  }
1095 
1096  if ((second_bracket = strchr(first_bracket, '>'))) {
1097  *start = first_bracket;
1098  *length = second_bracket - first_bracket;
1099  return 0;
1100  }
1101  ast_log(LOG_WARNING, "No closing bracket found in '%s'\n", src);
1102  return -1;
1103 }
#define LOG_WARNING
Definition: logger.h:274
const char * find_closing_quote(const char *start, const char *lim)
Locate closing quote in a string, skipping escaped quotes. optionally with a limit on the search...
Definition: chan_sip.c:5074
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872

◆ get_in_brackets_full()

int get_in_brackets_full ( char *  tmp,
char **  out,
char **  residue 
)

Get text in brackets and any trailing residue.

Return values
0success
-1failure
1no brackets so got all

Definition at line 1105 of file reqresp_parser.c.

References ast_log, ast_strlen_zero, find_closing_quote(), LOG_WARNING, NULL, parse(), and tmp().

Referenced by get_in_brackets(), and parse_name_andor_addr().

1106 {
1107  const char *parse = tmp;
1108  char *first_bracket;
1109  char *second_bracket;
1110 
1111  if (out) {
1112  *out = "";
1113  }
1114  if (residue) {
1115  *residue = "";
1116  }
1117 
1118  if (ast_strlen_zero(tmp)) {
1119  return 1;
1120  }
1121 
1122  /*
1123  * Skip any quoted text until we find the part in brackets.
1124  * On any error give up and return -1
1125  */
1126  while ( (first_bracket = strchr(parse, '<')) ) {
1127  char *first_quote = strchr(parse, '"');
1128  first_bracket++;
1129  if (!first_quote || first_quote >= first_bracket) {
1130  break; /* no need to look at quoted part */
1131  }
1132  /* the bracket is within quotes, so ignore it */
1133  parse = find_closing_quote(first_quote + 1, NULL);
1134  if (!*parse) {
1135  ast_log(LOG_WARNING, "No closing quote found in '%s'\n", tmp);
1136  return -1;
1137  }
1138  parse++;
1139  }
1140 
1141  /* If no first bracket then still look for a second bracket as some other parsing functions
1142  may overwrite first bracket with NULL when terminating a token based display-name. As this
1143  only affects token based display-names there is no danger of brackets being in quotes */
1144  if (first_bracket) {
1145  parse = first_bracket;
1146  } else {
1147  parse = tmp;
1148  }
1149 
1150  if ((second_bracket = strchr(parse, '>'))) {
1151  *second_bracket++ = '\0';
1152  if (out) {
1153  *out = (char *) parse;
1154  }
1155  if (residue) {
1156  *residue = second_bracket;
1157  }
1158  return 0;
1159  }
1160 
1161  if ((first_bracket)) {
1162  ast_log(LOG_WARNING, "No closing bracket found in '%s'\n", tmp);
1163  return -1;
1164  }
1165 
1166  if (out) {
1167  *out = tmp;
1168  }
1169 
1170  return 1;
1171 }
#define LOG_WARNING
Definition: logger.h:274
static int tmp()
Definition: bt_open.c:389
const char * find_closing_quote(const char *start, const char *lim)
Locate closing quote in a string, skipping escaped quotes. optionally with a limit on the search...
Definition: chan_sip.c:5074
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
FILE * out
Definition: utils/frame.c:33

◆ get_name_and_number()

int get_name_and_number ( const char *  hdr,
char **  name,
char **  number 
)

Get name and number from sip header.

Note
name and number point to malloced memory on return and must be freed. If name or number is not found, they will be returned as NULL.
Return values
0success
-1failure

Definition at line 905 of file reqresp_parser.c.

References ast_copy_string(), ast_log, ast_strdup, ast_strlen_zero, ast_uri_decode(), ast_uri_sip_user, dummy(), get_calleridname(), get_in_brackets(), LOG_ERROR, NULL, and parse_uri().

Referenced by AST_TEST_DEFINE(), change_redirecting_information(), and get_pai().

906 {
907  char header[256];
908  char tmp_name[256];
909  char *tmp_number = NULL;
910  char *hostport = NULL;
911  char *dummy = NULL;
912 
913  if (!name || !number || ast_strlen_zero(hdr)) {
914  return -1;
915  }
916 
917  *number = NULL;
918  *name = NULL;
919  ast_copy_string(header, hdr, sizeof(header));
920 
921  /* strip the display-name portion off the beginning of the header. */
922  get_calleridname(header, tmp_name, sizeof(tmp_name));
923 
924  /* get uri within < > brackets */
925  tmp_number = get_in_brackets(header);
926 
927  /* parse out the number here */
928  if (parse_uri(tmp_number, "sip:,sips:", &tmp_number, &dummy, &hostport, NULL) || ast_strlen_zero(tmp_number)) {
929  ast_log(LOG_ERROR, "can not parse name and number from sip header.\n");
930  return -1;
931  }
932 
933  /* number is not option, and must be present at this point */
934  *number = ast_strdup(tmp_number);
936 
937  /* name is optional and may not be present at this point */
938  if (!ast_strlen_zero(tmp_name)) {
939  *name = ast_strdup(tmp_name);
940  }
941 
942  return 0;
943 }
void ast_uri_decode(char *s, struct ast_flags spec)
Decode URI, URN, URL (overwrite string)
Definition: main/utils.c:616
static void dummy(char *unused,...)
Definition: chan_unistim.c:220
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
Number structure.
Definition: app_followme.c:154
int parse_uri(char *uri, const char *scheme, char **user, char **pass, char **hostport, char **transport)
parses a URI in its components.
#define ast_log
Definition: astobj2.c:42
char * get_in_brackets(char *tmp)
Pick out text in brackets from character string.
const char * get_calleridname(const char *input, char *output, size_t outputsize)
Get caller id name from SIP headers, copy into output buffer.
#define LOG_ERROR
Definition: logger.h:285
static const char name[]
Definition: cdr_mysql.c:74
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
const struct ast_flags ast_uri_sip_user
Definition: main/utils.c:575

◆ parse_contact_header()

int parse_contact_header ( char *  contactheader,
struct contactliststruct *  contactlist 
)

Definition at line 1475 of file reqresp_parser.c.

References ast_calloc, AST_LIST_HEAD_SET_NOLOCK, AST_LIST_INSERT_TAIL, contact::expires, get_comma(), contact::headers, contact::hostport, last, contact::name, NULL, contact::params, parse_name_andor_addr(), contact::pass, contact::q, contact::user, and value.

Referenced by AST_TEST_DEFINE().

1476 {
1477  int res;
1478  int last;
1479  char *comma;
1480  char *residue;
1481  char *param;
1482  char *value;
1483  struct contact *split_contact = NULL;
1484 
1485  if (*contactheader == '*') {
1486  return 1;
1487  }
1488 
1489  split_contact = ast_calloc(1, sizeof(*split_contact));
1490 
1491  AST_LIST_HEAD_SET_NOLOCK(contactlist, split_contact);
1492  while ((last = get_comma(contactheader, &comma)) != -1) {
1493  res = parse_name_andor_addr(contactheader, "sip:,sips:",
1494  &split_contact->name, &split_contact->user,
1495  &split_contact->pass, &split_contact->hostport,
1496  &split_contact->params, &split_contact->headers,
1497  &residue);
1498  if (res == -1) {
1499  return res;
1500  }
1501 
1502  /* parse contact params */
1503  split_contact->expires = split_contact->q = "";
1504 
1505  while ((value = strchr(residue,'='))) {
1506  *value++ = '\0';
1507 
1508  param = residue;
1509  if ((residue = strchr(value,';'))) {
1510  *residue++ = '\0';
1511  } else {
1512  residue = "";
1513  }
1514 
1515  if (!strcmp(param,"expires")) {
1516  split_contact->expires = value;
1517  } else if (!strcmp(param,"q")) {
1518  split_contact->q = value;
1519  }
1520  }
1521 
1522  if (last) {
1523  return 0;
1524  }
1525  contactheader = comma;
1526 
1527  split_contact = ast_calloc(1, sizeof(*split_contact));
1528  AST_LIST_INSERT_TAIL(contactlist, split_contact, list);
1529  }
1530  return last;
1531 }
char * user
struct uriparams params
char * headers
char * expires
#define NULL
Definition: resample.c:96
int value
Definition: syslog.c:37
char * hostport
struct sla_ringing_trunk * last
Definition: app_meetme.c:1092
char * pass
char * name
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
int parse_name_andor_addr(char *uri, const char *scheme, char **name, char **user, char **pass, char **hostport, struct uriparams *params, char **headers, char **residue)
Parse the ABNF structure name-andor-addr = name-addr / addr-spec into its components and return any t...
int get_comma(char *in, char **out)
Parse all contact header contacts.
#define AST_LIST_HEAD_SET_NOLOCK(head, entry)
Initializes a list head structure with a specified first entry.
Definition: linkedlists.h:387
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
char * q

◆ parse_name_andor_addr()

int parse_name_andor_addr ( char *  uri,
const char *  scheme,
char **  name,
char **  user,
char **  pass,
char **  domain,
struct uriparams params,
char **  headers,
char **  remander 
)

Parse the ABNF structure name-andor-addr = name-addr / addr-spec into its components and return any trailing message-header parameters.

Return values
0success
-1failure

Definition at line 1262 of file reqresp_parser.c.

References buf, get_calleridname(), get_in_brackets_full(), NULL, and parse_uri_full().

Referenced by AST_TEST_DEFINE(), and parse_contact_header().

1266 {
1267  char buf[1024];
1268  char **residue2 = residue;
1269  char *orig_uri = uri;
1270  int ret;
1271 
1272  buf[0] = '\0';
1273  if (name) {
1274  uri = (char *) get_calleridname(uri, buf, sizeof(buf));
1275  }
1276  ret = get_in_brackets_full(uri, &uri, residue);
1277  if (ret == 0) {
1278  /*
1279  * The uri is in brackets so do not treat unknown trailing uri
1280  * parameters as potential message header parameters.
1281  */
1282  if (residue && **residue) {
1283  /* step over the first semicolon as per parse_uri_full residue */
1284  *residue = *residue + 1;
1285  }
1286  residue2 = NULL;
1287  }
1288 
1289  if (name) {
1290  if (buf[0]) {
1291  /*
1292  * There is always room at orig_uri for the display-name because
1293  * at least one character has always been removed. A '"' or '<'
1294  * has been removed.
1295  */
1296  strcpy(orig_uri, buf);
1297  *name = orig_uri;
1298  } else {
1299  *name = "";
1300  }
1301  }
1302 
1303  return parse_uri_full(uri, scheme, user, pass, hostport, params, headers, residue2);
1304 }
static char pass[512]
char * headers
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
int get_in_brackets_full(char *tmp, char **out, char **residue)
Get text in brackets and any trailing residue.
#define NULL
Definition: resample.c:96
int parse_uri_full(char *uri, const char *scheme, char **user, char **pass, char **hostport, struct uriparams *params, char **headers, char **residue)
parses a URI in its components.
char * hostport
const char * get_calleridname(const char *input, char *output, size_t outputsize)
Get caller id name from SIP headers, copy into output buffer.
static const char name[]
Definition: cdr_mysql.c:74
structure to hold users read from users.conf

◆ parse_sip_options()

unsigned int parse_sip_options ( const char *  options,
char *  unsupported,
size_t  unsupported_len 
)

Parse supported header in incoming packet.

This function parses through the options parameters and builds a bit field representing all the SIP options in that field. When an item is found that is not supported, it is copied to the unsupported out buffer.

Parameters
optionslist
unsupportedout buffer (optional)
unsupported_lenout buffer length (optional)

Definition at line 1693 of file reqresp_parser.c.

References ARRAY_LEN, ast_copy_string(), ast_debug, ast_strdupa, ast_strip(), ast_strlen_zero, FALSE, cfsip_options::id, NULL, out, SIP_OPT_UNKNOWN, sip_options, SUPPORTED, text, and TRUE.

Referenced by AST_TEST_DEFINE(), handle_request_bye(), and handle_request_invite().

1694 {
1695  char *next, *sep;
1696  char *temp;
1697  int i, found, supported;
1698  unsigned int profile = 0;
1699 
1700  char *out = unsupported;
1701  size_t outlen = unsupported_len;
1702  char *cur_out = out;
1703 
1704  if (ast_strlen_zero(options) )
1705  return 0;
1706 
1707  temp = ast_strdupa(options);
1708 
1709  ast_debug(3, "Begin: parsing SIP \"Supported: %s\"\n", options);
1710  for (next = temp; next; next = sep) {
1711  found = FALSE;
1712  supported = FALSE;
1713  if ((sep = strchr(next, ',')) != NULL) {
1714  *sep++ = '\0';
1715  }
1716 
1717  /* trim leading and trailing whitespace */
1718  next = ast_strip(next);
1719 
1720  if (ast_strlen_zero(next)) {
1721  continue; /* if there is a blank argument in there just skip it */
1722  }
1723 
1724  ast_debug(3, "Found SIP option: -%s-\n", next);
1725  for (i = 0; i < ARRAY_LEN(sip_options); i++) {
1726  if (!strcasecmp(next, sip_options[i].text)) {
1727  profile |= sip_options[i].id;
1728  if (sip_options[i].supported == SUPPORTED) {
1729  supported = TRUE;
1730  }
1731  found = TRUE;
1732  ast_debug(3, "Matched SIP option: %s\n", next);
1733  break;
1734  }
1735  }
1736 
1737  /* If option is not supported, add to unsupported out buffer */
1738  if (!supported && out && outlen) {
1739  size_t copylen = strlen(next);
1740  size_t cur_outlen = strlen(out);
1741  /* Check to see if there is enough room to store this option.
1742  * Copy length is string length plus 2 for the ',' and '\0' */
1743  if ((cur_outlen + copylen + 2) < outlen) {
1744  /* if this isn't the first item, add the ',' */
1745  if (cur_outlen) {
1746  *cur_out = ',';
1747  cur_out++;
1748  cur_outlen++;
1749  }
1750  ast_copy_string(cur_out, next, (outlen - cur_outlen));
1751  cur_out += copylen;
1752  }
1753  }
1754 
1755  if (!found) {
1756  profile |= SIP_OPT_UNKNOWN;
1757  if (!strncasecmp(next, "x-", 2))
1758  ast_debug(3, "Found private SIP option, not supported: %s\n", next);
1759  else
1760  ast_debug(3, "Found no match for SIP option: %s (Please file bug report!)\n", next);
1761  }
1762  }
1763 
1764  return profile;
1765 }
#define FALSE
Definition: app_minivm.c:521
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
#define SIP_OPT_UNKNOWN
Definition: sip.h:167
char * text
Definition: app_queue.c:1508
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:219
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
int id
Definition: sip.h:1828
static const struct cfsip_options sip_options[]
#define SUPPORTED
Definition: sip.h:142
FILE * out
Definition: utils/frame.c:33
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
#define TRUE
Definition: app_minivm.c:518
static struct test_options options

◆ parse_uri()

int parse_uri ( char *  uri,
const char *  scheme,
char **  ret_name,
char **  pass,
char **  hostport,
char **  transport 
)

parses a URI in its components.

Note
  • Multiple scheme's can be specified ',' delimited. ex: "sip:,sips:"
  • If a component is not requested, do not split around it. This means that if we don't have domain, we cannot split name:pass.
  • It is safe to call with ret_name, pass, hostport pointing all to the same place.
  • If no secret parameter is provided, ret_name will return with both parts, user:secret.
  • If the URI contains a port number, hostport will return with both parts, host:port.
  • This function overwrites the URI string.
Return values
0on success
-1on error.
* general form we are expecting is sip:user:password;user-parameters@host:port;uri-parameters?headers
* 

Definition at line 517 of file reqresp_parser.c.

References NULL, parse_uri_full(), and uriparams::transport.

Referenced by AST_TEST_DEFINE(), check_peer_ok(), get_name_and_number(), parse_uri_legacy_check(), and sip_msg_send().

518  {
519  int ret;
520  char *headers;
521  struct uriparams params;
522 
523  headers = NULL;
524  ret = parse_uri_full(uri, scheme, user, pass, hostport, &params, &headers, NULL);
525  if (transport) {
526  *transport=params.transport;
527  }
528  return ret;
529 }
static char pass[512]
char * headers
#define NULL
Definition: resample.c:96
int parse_uri_full(char *uri, const char *scheme, char **user, char **pass, char **hostport, struct uriparams *params, char **headers, char **residue)
parses a URI in its components.
char * transport
uri parameters
structure to hold users read from users.conf

◆ parse_uri_full()

int parse_uri_full ( char *  uri,
const char *  scheme,
char **  user,
char **  pass,
char **  hostport,
struct uriparams params,
char **  headers,
char **  residue 
)

  • parses a URI in its components.

parses a URI in to all of its components and any trailing residue

Definition at line 37 of file reqresp_parser.c.

References ast_debug, ast_strdupa, ast_strlen_zero, c, error(), uriparams::lr, uriparams::maddr, uriparams::method, NULL, strsep(), uriparams::transport, uriparams::ttl, uriparams::user, and value.

Referenced by AST_TEST_DEFINE(), parse_name_andor_addr(), and parse_uri().

40 {
41  char *userinfo = NULL;
42  char *parameters = NULL;
43  char *endparams = NULL;
44  char *c = NULL;
45  int error = 0;
46  int teluri_scheme = 0;
47 
48  /*
49  * Initialize requested strings - some functions don't care if parse_uri fails
50  * and will attempt to use string pointers passed into parse_uri even after a
51  * parse_uri failure
52  */
53  if (user) {
54  *user = "";
55  }
56  if (pass) {
57  *pass = "";
58  }
59  if (hostport) {
60  *hostport = "";
61  }
62  if (headers) {
63  *headers = "";
64  }
65  if (residue) {
66  *residue = "";
67  }
68 
69  /* check for valid input */
70  if (ast_strlen_zero(uri)) {
71  return -1;
72  }
73 
74  if (scheme) {
75  int l;
76  char *scheme2 = ast_strdupa(scheme);
77  char *cur = strsep(&scheme2, ",");
78  for (; !ast_strlen_zero(cur); cur = strsep(&scheme2, ",")) {
79  l = strlen(cur);
80  if (!strncasecmp(uri, cur, l)) {
81  teluri_scheme = !strncasecmp(uri, "tel:", 4); /* TEL URI */
82  uri += l;
83  break;
84  }
85  }
86  if (ast_strlen_zero(cur)) {
87  ast_debug(1, "No supported scheme found in '%s' using the scheme[s] %s\n", uri, scheme);
88  error = -1;
89  }
90  }
91 
92  if (!hostport) {
93  /* if we don't want to split around hostport, keep everything as a
94  * userinfo - cos thats how old parse_uri operated*/
95  userinfo = uri;
96  } else if (teluri_scheme) {
97  /*
98  * tel: TEL URI INVITE RFC 3966 patch
99  * See http://www.ietf.org/rfc/rfc3966.txt
100  *
101  * Once the full RFC 3966 parsing is implemented,
102  * the ext= or isub= parameters would be extracted from userinfo.
103  * When this kind of subaddressing would be implemented, the userinfo must be further parsed.
104  * Those parameters would be used for ISDN or PSTN local extensions.
105  *
106  * Current restrictions:
107  * We currently consider the ";isub=" or the ";ext=" as part of the userinfo (unparsed).
108  */
109 
110  if ((c = strstr(uri, ";phone-context="))) {
111  /*
112  * Local number with context or domain.
113  * ext= or isub= TEL URI parameters should be upfront.
114  * All other parameters should come after the ";phone-context=" parameter.
115  * If other parameters would occur before ";phone-context=" they will be ignored.
116  */
117 
118  *c = '\0';
119  userinfo = uri;
120  uri = c + 15;
121  *hostport = uri;
122  } else if ('+' == uri[0]) {
123  /* Global number without context or domain; possibly followed by RFC 3966 and optional other parameters. */
124 
125  userinfo = uri;
126  *hostport = uri;
127  } else {
128  ast_debug(1, "No RFC 3966 global number or context found in '%s'; returning local number anyway\n", uri);
129  userinfo = uri; /* Return local number anyway */
130  error = -1;
131  }
132  } else {
133  char *dom = "";
134  if ((c = strchr(uri, '@'))) {
135  *c++ = '\0';
136  dom = c;
137  userinfo = uri;
138  uri = c; /* userinfo can contain ? and ; chars so step forward before looking for params and headers */
139  } else {
140  /* domain-only URI, according to the SIP RFC. */
141  dom = uri;
142  userinfo = "";
143  }
144 
145  *hostport = dom;
146  }
147 
148  if (pass && (c = strchr(userinfo, ':'))) { /* user:password */
149  *c++ = '\0';
150  *pass = c;
151  } else if (pass) {
152  *pass = "";
153  }
154 
155  if (user) {
156  *user = userinfo;
157  }
158 
159  parameters = uri;
160  /* strip [?headers] from end of uri - even if no header pointer exists*/
161  if ((c = strrchr(uri, '?'))) {
162  *c++ = '\0';
163  uri = c;
164  if (headers) {
165  *headers = c;
166  }
167  if ((c = strrchr(uri, ';'))) {
168  *c++ = '\0';
169  } else {
170  c = strrchr(uri, '\0');
171  }
172  uri = c; /* residue */
173 
174 
175  } else if (headers) {
176  *headers = "";
177  }
178 
179  /* parse parameters */
180  endparams = strchr(parameters,'\0');
181  if ((c = strchr(parameters, ';'))) {
182  *c++ = '\0';
183  parameters = c;
184  } else {
185  parameters = endparams;
186  }
187 
188  if (params) {
189  char *rem = parameters; /* unparsed or unrecognised remainder */
190  char *label;
191  char *value;
192  int lr = 0;
193 
194  params->transport = "";
195  params->user = "";
196  params->method = "";
197  params->ttl = "";
198  params->maddr = "";
199  params->lr = 0;
200 
201  rem = parameters;
202 
203  while ((value = strchr(parameters, '=')) || (lr = !strncmp(parameters, "lr", 2))) {
204  /* The while condition will not continue evaluation to set lr if it matches "lr=" */
205  if (lr) {
206  value = parameters;
207  } else {
208  *value++ = '\0';
209  }
210  label = parameters;
211  if ((c = strchr(value, ';'))) {
212  *c++ = '\0';
213  parameters = c;
214  } else {
215  parameters = endparams;
216  }
217 
218  if (!strcmp(label, "transport")) {
219  params->transport = value;
220  rem = parameters;
221  } else if (!strcmp(label, "user")) {
222  params->user = value;
223  rem = parameters;
224  } else if (!strcmp(label, "method")) {
225  params->method = value;
226  rem = parameters;
227  } else if (!strcmp(label, "ttl")) {
228  params->ttl = value;
229  rem = parameters;
230  } else if (!strcmp(label, "maddr")) {
231  params->maddr = value;
232  rem = parameters;
233  /* Treat "lr", "lr=yes", "lr=on", "lr=1", "lr=almostanything" as lr enabled and "", "lr=no", "lr=off", "lr=0", "lr=" and "lranything" as lr disabled */
234  } else if ((!strcmp(label, "lr") && strcmp(value, "no") && strcmp(value, "off") && strcmp(value, "0") && strcmp(value, "")) || ((lr) && strcmp(value, "lr"))) {
235  params->lr = 1;
236  rem = parameters;
237  } else {
238  value--;
239  *value = '=';
240  if (c) {
241  c--;
242  *c = ';';
243  }
244  }
245  }
246  if (rem > uri) { /* no headers */
247  uri = rem;
248  }
249 
250  }
251 
252  if (residue) {
253  *residue = uri;
254  }
255 
256  return error;
257 }
static char pass[512]
char * method
static struct test_val c
#define NULL
Definition: resample.c:96
int value
Definition: syslog.c:37
#define ast_strlen_zero(foo)
Definition: strings.h:52
char * transport
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
char * user
char * maddr
char * ttl
structure to hold users read from users.conf
char * strsep(char **str, const char *delims)
int error(const char *format,...)
Definition: utils/frame.c:999

◆ parse_via()

struct sip_via* parse_via ( const char *  header)

Parse a Via header.

This function parses the Via header and processes it according to section 18.2 of RFC 3261 and RFC 3581. Since we don't have a transport layer, we only care about the maddr and ttl parms. The received and rport params are not parsed.

Note
This function fails to parse some odd combinations of SWS in parameter lists.
VIA syntax. RFC 3261 section 25.1
Via = ( "Via" / "v" ) HCOLON via-parm *(COMMA via-parm)
via-parm = sent-protocol LWS sent-by *( SEMI via-params )
via-params = via-ttl / via-maddr
/ via-received / via-branch
/ via-extension
via-ttl = "ttl" EQUAL ttl
via-maddr = "maddr" EQUAL host
via-received = "received" EQUAL (IPv4address / IPv6address)
via-branch = "branch" EQUAL token
via-extension = generic-param
sent-protocol = protocol-name SLASH protocol-version
SLASH transport
protocol-name = "SIP" / token
protocol-version = token
transport = "UDP" / "TCP" / "TLS" / "SCTP"
/ other-transport
sent-by = host [ COLON port ]
ttl = 1*3DIGIT ; 0 to 255

Definition at line 2389 of file reqresp_parser.c.

References ast_calloc, ast_log, ast_skip_blanks(), ast_strdup, ast_strlen_zero, sip_via::branch, c, free_via(), LOG_ERROR, sip_via::maddr, NULL, sip_via::port, sip_via::protocol, sip_via::sent_by, strsep(), sip_via::ttl, and sip_via::via.

Referenced by __find_call(), __sip_alloc(), AST_TEST_DEFINE(), and process_via().

2390 {
2391  struct sip_via *v = ast_calloc(1, sizeof(*v));
2392  char *via, *parm;
2393 
2394  if (!v) {
2395  return NULL;
2396  }
2397 
2398  v->via = ast_strdup(header);
2399  v->ttl = 1;
2400 
2401  via = v->via;
2402 
2403  if (ast_strlen_zero(via)) {
2404  ast_log(LOG_ERROR, "received request without a Via header\n");
2405  free_via(v);
2406  return NULL;
2407  }
2408 
2409  /* seperate the first via-parm */
2410  via = strsep(&via, ",");
2411 
2412  /* chop off sent-protocol */
2413  v->protocol = strsep(&via, " \t\r\n");
2414  if (ast_strlen_zero(v->protocol)) {
2415  ast_log(LOG_ERROR, "missing sent-protocol in Via header\n");
2416  free_via(v);
2417  return NULL;
2418  }
2420 
2421  if (via) {
2422  via = ast_skip_blanks(via);
2423  }
2424 
2425  /* chop off sent-by */
2426  v->sent_by = strsep(&via, "; \t\r\n");
2427  if (ast_strlen_zero(v->sent_by)) {
2428  ast_log(LOG_ERROR, "missing sent-by in Via header\n");
2429  free_via(v);
2430  return NULL;
2431  }
2432  v->sent_by = ast_skip_blanks(v->sent_by);
2433 
2434  /* store the port, we have to handle ipv6 addresses containing ':'
2435  * characters gracefully */
2436  if (((parm = strchr(v->sent_by, ']')) && *(++parm) == ':') || (!(parm = strchr(v->sent_by, ']')) && (parm = strchr(v->sent_by, ':')))) {
2437  char *endptr;
2438 
2439  v->port = strtol(++parm, &endptr, 10);
2440  }
2441 
2442  /* evaluate any via-parms */
2443  while ((parm = strsep(&via, "; \t\r\n"))) {
2444  char *c;
2445  if ((c = strstr(parm, "maddr="))) {
2446  v->maddr = ast_skip_blanks(c + sizeof("maddr=") - 1);
2447  } else if ((c = strstr(parm, "branch="))) {
2448  v->branch = ast_skip_blanks(c + sizeof("branch=") - 1);
2449  } else if ((c = strstr(parm, "ttl="))) {
2450  char *endptr;
2451  c = ast_skip_blanks(c + sizeof("ttl=") - 1);
2452  v->ttl = strtol(c, &endptr, 10);
2453 
2454  /* make sure we got a valid ttl value */
2455  if (c == endptr) {
2456  v->ttl = 1;
2457  }
2458  }
2459  }
2460 
2461  return v;
2462 }
const char * maddr
Definition: sip.h:879
unsigned char ttl
Definition: sip.h:881
static struct test_val c
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
Structure to store Via information.
Definition: sip.h:874
#define ast_log
Definition: astobj2.c:42
const char * branch
Definition: sip.h:878
void free_via(struct sip_via *v)
char * via
Definition: sip.h:875
#define LOG_ERROR
Definition: logger.h:285
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:157
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
const char * sent_by
Definition: sip.h:877
unsigned int port
Definition: sip.h:880
char * strsep(char **str, const char *delims)
const char * protocol
Definition: sip.h:876

◆ sip_reqresp_parser_exit()

void sip_reqresp_parser_exit ( void  )

Free resources used by request and response parser.

Definition at line 2682 of file reqresp_parser.c.

References c_locale, and NULL.

Referenced by unload_module().

2683 {
2684 #ifdef HAVE_XLOCALE_H
2685  if (c_locale) {
2686  freelocale(c_locale);
2687  c_locale = NULL;
2688  }
2689 #endif
2690 }
#define NULL
Definition: resample.c:96
locale_t c_locale

◆ sip_reqresp_parser_init()

int sip_reqresp_parser_init ( void  )

initialize request and response parser data

Return values
0Success
-1Failure

Definition at line 2671 of file reqresp_parser.c.

References c_locale, and NULL.

Referenced by load_module().

2672 {
2673 #ifdef HAVE_XLOCALE_H
2674  c_locale = newlocale(LC_CTYPE_MASK, "C", NULL);
2675  if (!c_locale) {
2676  return -1;
2677  }
2678 #endif
2679  return 0;
2680 }
#define NULL
Definition: resample.c:96
locale_t c_locale

◆ sip_request_parser_register_tests()

void sip_request_parser_register_tests ( void  )

register request parsing tests

Definition at line 2644 of file reqresp_parser.c.

References AST_TEST_REGISTER.

Referenced by sip_register_tests().

2645 {
2646  AST_TEST_REGISTER(get_calleridname_test);
2647  AST_TEST_REGISTER(sip_parse_uri_test);
2648  AST_TEST_REGISTER(get_in_brackets_test);
2649  AST_TEST_REGISTER(get_name_and_number_test);
2650  AST_TEST_REGISTER(sip_parse_uri_full_test);
2651  AST_TEST_REGISTER(parse_name_andor_addr_test);
2652  AST_TEST_REGISTER(parse_contact_header_test);
2653  AST_TEST_REGISTER(sip_parse_options_test);
2654  AST_TEST_REGISTER(sip_uri_cmp_test);
2655  AST_TEST_REGISTER(parse_via_test);
2656 }
#define AST_TEST_REGISTER(cb)
Definition: test.h:127

◆ sip_request_parser_unregister_tests()

void sip_request_parser_unregister_tests ( void  )

unregister request parsing tests

Definition at line 2657 of file reqresp_parser.c.

References AST_TEST_UNREGISTER.

Referenced by sip_unregister_tests().

2658 {
2659  AST_TEST_UNREGISTER(sip_parse_uri_test);
2660  AST_TEST_UNREGISTER(get_calleridname_test);
2661  AST_TEST_UNREGISTER(get_in_brackets_test);
2662  AST_TEST_UNREGISTER(get_name_and_number_test);
2663  AST_TEST_UNREGISTER(sip_parse_uri_full_test);
2664  AST_TEST_UNREGISTER(parse_name_andor_addr_test);
2665  AST_TEST_UNREGISTER(parse_contact_header_test);
2666  AST_TEST_UNREGISTER(sip_parse_options_test);
2667  AST_TEST_UNREGISTER(sip_uri_cmp_test);
2668  AST_TEST_UNREGISTER(parse_via_test);
2669 }
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128

◆ sip_uri_cmp()

int sip_uri_cmp ( const char *  input1,
const char *  input2 
)

Compare two URIs as described in RFC 3261 Section 19.1.4.

Parameters
input1First URI
input2Second URI
Return values
0URIs match
nonzeroURIs do not match or one or both is malformed

Definition at line 2153 of file reqresp_parser.c.

References ast_strdupa, ast_strlen_zero, ast_uri_decode(), ast_uri_sip_user, S_OR, sip_uri_domain_cmp(), sip_uri_headers_cmp(), sip_uri_params_cmp(), and strsep().

Referenced by AST_TEST_DEFINE(), find_by_notify_uri_helper(), find_by_subscribe_uri_helper(), handle_request_invite(), and match_req_to_dialog().

2154 {
2155  char *uri1;
2156  char *uri2;
2157  char *uri_scheme1;
2158  char *uri_scheme2;
2159  char *host1;
2160  char *host2;
2161  char *params1;
2162  char *params2;
2163  char *headers1;
2164  char *headers2;
2165 
2166  /* XXX It would be really nice if we could just use parse_uri_full() here
2167  * to separate the components of the URI, but unfortunately it is written
2168  * in a way that can cause URI parameters to be discarded.
2169  */
2170 
2171  if (!input1 || !input2) {
2172  return 1;
2173  }
2174 
2175  uri1 = ast_strdupa(input1);
2176  uri2 = ast_strdupa(input2);
2177 
2180 
2181  uri_scheme1 = strsep(&uri1, ":");
2182  uri_scheme2 = strsep(&uri2, ":");
2183 
2184  if (strcmp(uri_scheme1, uri_scheme2)) {
2185  return 1;
2186  }
2187 
2188  /* This function is tailored for SIP and SIPS URIs. There's no
2189  * need to check uri_scheme2 since we have determined uri_scheme1
2190  * and uri_scheme2 are equivalent already.
2191  */
2192  if (strcmp(uri_scheme1, "sip") && strcmp(uri_scheme1, "sips")) {
2193  return 1;
2194  }
2195 
2196  if (ast_strlen_zero(uri1) || ast_strlen_zero(uri2)) {
2197  return 1;
2198  }
2199 
2200  if ((host1 = strchr(uri1, '@'))) {
2201  *host1++ = '\0';
2202  }
2203  if ((host2 = strchr(uri2, '@'))) {
2204  *host2++ = '\0';
2205  }
2206 
2207  /* Check for mismatched username and passwords. This is the
2208  * only case-sensitive comparison of a SIP URI
2209  */
2210  if ((host1 && !host2) ||
2211  (host2 && !host1) ||
2212  (host1 && host2 && strcmp(uri1, uri2))) {
2213  return 1;
2214  }
2215 
2216  if (!host1) {
2217  host1 = uri1;
2218  }
2219  if (!host2) {
2220  host2 = uri2;
2221  }
2222 
2223  /* Strip off the parameters and headers so we can compare
2224  * host and port
2225  */
2226 
2227  if ((params1 = strchr(host1, ';'))) {
2228  *params1++ = '\0';
2229  }
2230  if ((params2 = strchr(host2, ';'))) {
2231  *params2++ = '\0';
2232  }
2233 
2234  /* Headers come after parameters, but there may be headers without
2235  * parameters, thus the S_OR
2236  */
2237  if ((headers1 = strchr(S_OR(params1, host1), '?'))) {
2238  *headers1++ = '\0';
2239  }
2240  if ((headers2 = strchr(S_OR(params2, host2), '?'))) {
2241  *headers2++ = '\0';
2242  }
2243 
2244  if (sip_uri_domain_cmp(host1, host2)) {
2245  return 1;
2246  }
2247 
2248  /* Headers have easier rules to follow, so do those first */
2249  if (sip_uri_headers_cmp(headers1, headers2)) {
2250  return 1;
2251  }
2252 
2253  /* And now the parameters. Ugh */
2254  return sip_uri_params_cmp(params1, params2);
2255 }
void ast_uri_decode(char *s, struct ast_flags spec)
Decode URI, URN, URL (overwrite string)
Definition: main/utils.c:616
static int sip_uri_domain_cmp(const char *host1, const char *host2)
Compare domain sections of SIP URIs.
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static int sip_uri_headers_cmp(const char *input1, const char *input2)
helper routine for sip_uri_cmp to compare URI headers
char * strsep(char **str, const char *delims)
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
const struct ast_flags ast_uri_sip_user
Definition: main/utils.c:575
static int sip_uri_params_cmp(const char *input1, const char *input2)
helper routine for sip_uri_cmp to compare URI parameters

◆ sip_uri_domain_cmp()

static int sip_uri_domain_cmp ( const char *  host1,
const char *  host2 
)
static

Compare domain sections of SIP URIs.

For hostnames, a case insensitive string comparison is used. For IP addresses, a binary comparison is used. This is mainly because IPv6 addresses have many ways of writing the same address.

For specifics about IP address comparison, see the following document: http://tools.ietf.org/html/draft-ietf-sip-ipv6-abnf-fix-05

Parameters
host1The domain from the first URI
host2THe domain from the second URI
Return values
0The domains match
nonzeroThe domains do not match

Definition at line 2115 of file reqresp_parser.c.

References ast_sockaddr_cmp(), ast_sockaddr_parse(), and c_locale.

Referenced by sip_uri_cmp().

2116 {
2117  struct ast_sockaddr addr1;
2118  struct ast_sockaddr addr2;
2119  int addr1_parsed;
2120  int addr2_parsed;
2121 
2122  addr1_parsed = ast_sockaddr_parse(&addr1, host1, 0);
2123  addr2_parsed = ast_sockaddr_parse(&addr2, host2, 0);
2124 
2125  if (addr1_parsed != addr2_parsed) {
2126  /* One domain was an IP address and the other had
2127  * a host name. FAIL!
2128  */
2129  return 1;
2130  }
2131 
2132  /* Both are host names. A string comparison will work
2133  * perfectly here. Specifying the "C" locale ensures that
2134  * The LC_CTYPE conventions use those defined in ANSI C,
2135  * i.e. ASCII.
2136  */
2137  if (!addr1_parsed) {
2138 #ifdef HAVE_XLOCALE_H
2139  if(!c_locale) {
2140  return strcasecmp(host1, host2);
2141  } else {
2142  return strcasecmp_l(host1, host2, c_locale);
2143  }
2144 #else
2145  return strcasecmp(host1, host2);
2146 #endif
2147  }
2148 
2149  /* Both contain IP addresses */
2150  return ast_sockaddr_cmp(&addr1, &addr2);
2151 }
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
Definition: netsock2.c:230
int ast_sockaddr_cmp(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
Compares two ast_sockaddr structures.
Definition: netsock2.c:388
Socket address structure.
Definition: netsock2.h:97
locale_t c_locale

◆ sip_uri_headers_cmp()

static int sip_uri_headers_cmp ( const char *  input1,
const char *  input2 
)
static

helper routine for sip_uri_cmp to compare URI headers

This takes the headers from two SIP URIs and determines if the URIs match. The rules for headers is simple. If a header appears in one URI, then it must also appear in the other URI. The order in which the headers appear does not matter.

Parameters
input1Headers from URI 1
input2Headers from URI 2
Return values
0URI headers match
nonzeroURI headers do not match

Definition at line 2050 of file reqresp_parser.c.

References ast_strdupa, ast_strlen_zero, NULL, strcasestr(), and strsep().

Referenced by sip_uri_cmp().

2051 {
2052  char *headers1 = NULL;
2053  char *headers2 = NULL;
2054  int zerolength1 = 0;
2055  int zerolength2 = 0;
2056  int different = 0;
2057  char *header1;
2058 
2059  if (ast_strlen_zero(input1)) {
2060  zerolength1 = 1;
2061  } else {
2062  headers1 = ast_strdupa(input1);
2063  }
2064 
2065  if (ast_strlen_zero(input2)) {
2066  zerolength2 = 1;
2067  } else {
2068  headers2 = ast_strdupa(input2);
2069  }
2070 
2071  /* If one URI contains no headers and the other
2072  * does, then they cannot possibly match
2073  */
2074  if (zerolength1 != zerolength2) {
2075  return 1;
2076  }
2077 
2078  if (zerolength1 && zerolength2)
2079  return 0;
2080 
2081  /* At this point, we can definitively state that both inputs are
2082  * not zero-length. First, one more optimization. If the length
2083  * of the headers is not equal, then we definitely have no match
2084  */
2085  if (strlen(headers1) != strlen(headers2)) {
2086  return 1;
2087  }
2088 
2089  for (header1 = strsep(&headers1, "&"); header1; header1 = strsep(&headers1, "&")) {
2090  if (!strcasestr(headers2, header1)) {
2091  different = 1;
2092  break;
2093  }
2094  }
2095 
2096  return different;
2097 }
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
char * strcasestr(const char *, const char *)
char * strsep(char **str, const char *delims)

◆ sip_uri_params_cmp()

static int sip_uri_params_cmp ( const char *  input1,
const char *  input2 
)
static

helper routine for sip_uri_cmp to compare URI parameters

This takes the parameters from two SIP URIs and determines if the URIs match. The rules for parameters suck. Here's a breakdown

  1. If a parameter appears in both URIs, then they must have the same value in order for the URIs to match
  2. If one URI has a user, maddr, ttl, or method parameter, then the other URI must also have that parameter and must have the same value in order for the URIs to match
  3. All other headers appearing in only one URI are not considered when determining if URIs match
Parameters
input1Parameters from URI 1
input2Parameters from URI 2
Return values
0URIs' parameters match
nonzeroURIs' parameters do not match

Definition at line 1924 of file reqresp_parser.c.

References ast_strdupa, ast_strlen_zero, NULL, and strsep().

Referenced by sip_uri_cmp().

1925 {
1926  char *params1 = NULL;
1927  char *params2 = NULL;
1928  char *pos1;
1929  char *pos2;
1930  int zerolength1 = 0;
1931  int zerolength2 = 0;
1932  int maddrmatch = 0;
1933  int ttlmatch = 0;
1934  int usermatch = 0;
1935  int methodmatch = 0;
1936 
1937  if (ast_strlen_zero(input1)) {
1938  zerolength1 = 1;
1939  } else {
1940  params1 = ast_strdupa(input1);
1941  }
1942  if (ast_strlen_zero(input2)) {
1943  zerolength2 = 1;
1944  } else {
1945  params2 = ast_strdupa(input2);
1946  }
1947 
1948  /* Quick optimization. If both params are zero-length, then
1949  * they match
1950  */
1951  if (zerolength1 && zerolength2) {
1952  return 0;
1953  }
1954 
1955  for (pos1 = strsep(&params1, ";"); pos1; pos1 = strsep(&params1, ";")) {
1956  char *value1 = pos1;
1957  char *name1 = strsep(&value1, "=");
1958  char *params2dup = NULL;
1959  int matched = 0;
1960  if (!value1) {
1961  value1 = "";
1962  }
1963  /* Checkpoint reached. We have the name and value parsed for param1
1964  * We have to duplicate params2 each time through this loop
1965  * or else the inner loop below will not work properly.
1966  */
1967  if (!zerolength2) {
1968  params2dup = ast_strdupa(params2);
1969  }
1970  for (pos2 = strsep(&params2dup, ";"); pos2; pos2 = strsep(&params2dup, ";")) {
1971  char *name2 = pos2;
1972  char *value2 = strchr(pos2, '=');
1973  if (!value2) {
1974  value2 = "";
1975  } else {
1976  *value2++ = '\0';
1977  }
1978  if (!strcasecmp(name1, name2)) {
1979  if (strcasecmp(value1, value2)) {
1980  goto fail;
1981  } else {
1982  matched = 1;
1983  break;
1984  }
1985  }
1986  }
1987  /* Check to see if the parameter is one of the 'must-match' parameters */
1988  if (!strcasecmp(name1, "maddr")) {
1989  if (matched) {
1990  maddrmatch = 1;
1991  } else {
1992  goto fail;
1993  }
1994  } else if (!strcasecmp(name1, "ttl")) {
1995  if (matched) {
1996  ttlmatch = 1;
1997  } else {
1998  goto fail;
1999  }
2000  } else if (!strcasecmp(name1, "user")) {
2001  if (matched) {
2002  usermatch = 1;
2003  } else {
2004  goto fail;
2005  }
2006  } else if (!strcasecmp(name1, "method")) {
2007  if (matched) {
2008  methodmatch = 1;
2009  } else {
2010  goto fail;
2011  }
2012  }
2013  }
2014 
2015  /* We've made it out of that horrible O(m*n) construct and there are no
2016  * failures yet. We're not done yet, though, because params2 could have
2017  * an maddr, ttl, user, or method header and params1 did not.
2018  */
2019  for (pos2 = strsep(&params2, ";"); pos2; pos2 = strsep(&params2, ";")) {
2020  char *value2 = pos2;
2021  char *name2 = strsep(&value2, "=");
2022  if (!value2) {
2023  value2 = "";
2024  }
2025  if ((!strcasecmp(name2, "maddr") && !maddrmatch) ||
2026  (!strcasecmp(name2, "ttl") && !ttlmatch) ||
2027  (!strcasecmp(name2, "user") && !usermatch) ||
2028  (!strcasecmp(name2, "method") && !methodmatch)) {
2029  goto fail;
2030  }
2031  }
2032  return 0;
2033 
2034 fail:
2035  return 1;
2036 }
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
char * strsep(char **str, const char *delims)

Variable Documentation

◆ c_locale

locale_t c_locale