Wed Jan 8 2020 09:50:17

Asterisk developer's documentation


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"

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)
 
char * get_in_brackets (char *tmp)
 
int get_in_brackets_const (const char *src, const char **start, int *length)
 
int get_in_brackets_full (char *tmp, char **out, char **residue)
 
int get_name_and_number (const char *hdr, char **name, char **number)
 
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)
 
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)
 
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_via * parse_via (const char *header)
 
void sip_reqresp_parser_exit (void)
 
int sip_reqresp_parser_init (void)
 
void sip_request_parser_register_tests (void)
 
void sip_request_parser_unregister_tests (void)
 
int sip_uri_cmp (const char *input1, const char *input2)
 
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

#define URI_CMP_MATCH   0

Definition at line 2149 of file reqresp_parser.c.

Referenced by AST_TEST_DEFINE().

#define URI_CMP_NOMATCH   1

Definition at line 2150 of file reqresp_parser.c.

Referenced by AST_TEST_DEFINE().

Function Documentation

AST_TEST_DEFINE ( sip_parse_uri_full_test  )

Definition at line 224 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, parse_uri_full(), pass, TEST_EXECUTE, TEST_INIT, and user.

225 {
226  int res = AST_TEST_PASS;
227  char uri[1024];
228  char *user, *pass, *hostport, *headers, *residue;
229  struct uriparams params;
230 
231  struct testdata {
232  char *desc;
233  char *uri;
234  char *user;
235  char *pass;
236  char *hostport;
237  char *headers;
238  char *residue;
239  struct uriparams params;
240  AST_LIST_ENTRY(testdata) list;
241  };
242 
243 
244  struct testdata *testdataptr;
245 
246  static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
247 
248  struct testdata td1 = {
249  .desc = "no headers",
250  .uri = "sip:user:secret@host:5060;param=discard;transport=tcp;param2=residue",
251  .user = "user",
252  .pass = "secret",
253  .hostport = "host:5060",
254  .headers = "",
255  .residue = "param2=residue",
256  .params.transport = "tcp",
257  .params.lr = 0,
258  .params.user = ""
259  };
260 
261  struct testdata td2 = {
262  .desc = "with headers",
263  .uri = "sip:user:secret@host:5060;param=discard;transport=tcp;param2=discard2?header=blah&header2=blah2;param3=residue",
264  .user = "user",
265  .pass = "secret",
266  .hostport = "host:5060",
267  .headers = "header=blah&header2=blah2",
268  .residue = "param3=residue",
269  .params.transport = "tcp",
270  .params.lr = 0,
271  .params.user = ""
272  };
273 
274  struct testdata td3 = {
275  .desc = "difficult user",
276  .uri = "sip:-_.!~*'()&=+$,;?/:secret@host:5060;transport=tcp",
277  .user = "-_.!~*'()&=+$,;?/",
278  .pass = "secret",
279  .hostport = "host:5060",
280  .headers = "",
281  .residue = "",
282  .params.transport = "tcp",
283  .params.lr = 0,
284  .params.user = ""
285  };
286 
287  struct testdata td4 = {
288  .desc = "difficult pass",
289  .uri = "sip:user:-_.!~*'()&=+$,@host:5060;transport=tcp",
290  .user = "user",
291  .pass = "-_.!~*'()&=+$,",
292  .hostport = "host:5060",
293  .headers = "",
294  .residue = "",
295  .params.transport = "tcp",
296  .params.lr = 0,
297  .params.user = ""
298  };
299 
300  struct testdata td5 = {
301  .desc = "difficult host",
302  .uri = "sip:user:secret@1-1.a-1.:5060;transport=tcp",
303  .user = "user",
304  .pass = "secret",
305  .hostport = "1-1.a-1.:5060",
306  .headers = "",
307  .residue = "",
308  .params.transport = "tcp",
309  .params.lr = 0,
310  .params.user = ""
311  };
312 
313  struct testdata td6 = {
314  .desc = "difficult params near transport",
315  .uri = "sip:user:secret@host:5060;-_.!~*'()[]/:&+$=-_.!~*'()[]/:&+$;transport=tcp",
316  .user = "user",
317  .pass = "secret",
318  .hostport = "host:5060",
319  .headers = "",
320  .residue = "",
321  .params.transport = "tcp",
322  .params.lr = 0,
323  .params.user = ""
324  };
325 
326  struct testdata td7 = {
327  .desc = "difficult params near headers",
328  .uri = "sip:user:secret@host:5060;-_.!~*'()[]/:&+$=-_.!~*'()[]/:&+$?header=blah&header2=blah2;-_.!~*'()[]/:&+$=residue",
329  .user = "user",
330  .pass = "secret",
331  .hostport = "host:5060",
332  .headers = "header=blah&header2=blah2",
333  .residue = "-_.!~*'()[]/:&+$=residue",
334  .params.transport = "",
335  .params.lr = 0,
336  .params.user = ""
337  };
338 
339  struct testdata td8 = {
340  .desc = "lr parameter",
341  .uri = "sip:user:secret@host:5060;param=discard;lr?header=blah",
342  .user = "user",
343  .pass = "secret",
344  .hostport = "host:5060",
345  .headers = "header=blah",
346  .residue = "",
347  .params.transport = "",
348  .params.lr = 1,
349  .params.user = ""
350  };
351 
352  struct testdata td9 = {
353  .desc = "alternative lr parameter",
354  .uri = "sip:user:secret@host:5060;param=discard;lr=yes?header=blah",
355  .user = "user",
356  .pass = "secret",
357  .hostport = "host:5060",
358  .headers = "header=blah",
359  .residue = "",
360  .params.transport = "",
361  .params.lr = 1,
362  .params.user = ""
363  };
364 
365  struct testdata td10 = {
366  .desc = "no lr parameter",
367  .uri = "sip:user:secret@host:5060;paramlr=lr;lr=no;lr=off;lr=0;lr=;=lr;lrextra;lrparam2=lr?header=blah",
368  .user = "user",
369  .pass = "secret",
370  .hostport = "host:5060",
371  .headers = "header=blah",
372  .residue = "",
373  .params.transport = "",
374  .params.lr = 0,
375  .params.user = ""
376  };
377 
378 
379  AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &td1);
380  AST_LIST_INSERT_TAIL(&testdatalist, &td2, list);
381  AST_LIST_INSERT_TAIL(&testdatalist, &td3, list);
382  AST_LIST_INSERT_TAIL(&testdatalist, &td4, list);
383  AST_LIST_INSERT_TAIL(&testdatalist, &td5, list);
384  AST_LIST_INSERT_TAIL(&testdatalist, &td6, list);
385  AST_LIST_INSERT_TAIL(&testdatalist, &td7, list);
386  AST_LIST_INSERT_TAIL(&testdatalist, &td8, list);
387  AST_LIST_INSERT_TAIL(&testdatalist, &td9, list);
388  AST_LIST_INSERT_TAIL(&testdatalist, &td10, list);
389 
390 
391  switch (cmd) {
392  case TEST_INIT:
393  info->name = "sip_uri_full_parse_test";
394  info->category = "/channels/chan_sip/";
395  info->summary = "tests sip full uri parsing";
396  info->description =
397  "Tests full parsing of various URIs "
398  "Verifies output matches expected behavior.";
399  return AST_TEST_NOT_RUN;
400  case TEST_EXECUTE:
401  break;
402  }
403 
404  AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
405  user = pass = hostport = headers = residue = NULL;
406  params.transport = params.user = params.method = params.ttl = params.maddr = NULL;
407  params.lr = 0;
408 
409  ast_copy_string(uri,testdataptr->uri,sizeof(uri));
410  if (parse_uri_full(uri, "sip:,sips:", &user,
411  &pass, &hostport,
412  &params,
413  &headers,
414  &residue) ||
415  (user && strcmp(testdataptr->user, user)) ||
416  (pass && strcmp(testdataptr->pass, pass)) ||
417  (hostport && strcmp(testdataptr->hostport, hostport)) ||
418  (headers && strcmp(testdataptr->headers, headers)) ||
419  (residue && strcmp(testdataptr->residue, residue)) ||
420  (strcmp(testdataptr->params.transport,params.transport)) ||
421  (testdataptr->params.lr != params.lr) ||
422  (strcmp(testdataptr->params.user,params.user))
423  ) {
424  ast_test_status_update(test, "Sub-Test: %s, failed.\n", testdataptr->desc);
425  res = AST_TEST_FAIL;
426  }
427  }
428 
429 
430  return res;
431 }
static char user[512]
static char pass[512]
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
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:224
static const char desc[]
Definition: cdr_radius.c:85
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
#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
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
AST_TEST_DEFINE ( sip_parse_uri_test  )

Definition at line 448 of file reqresp_parser.c.

References ast_strlen_zero(), AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, name, parse_uri(), pass, TEST_EXECUTE, and TEST_INIT.

449 {
450  int res = AST_TEST_PASS;
451  char *name, *pass, *hostport, *transport;
452  char uri1[] = "sip:name@host";
453  char uri2[] = "sip:name@host;transport=tcp";
454  char uri3[] = "sip:name:secret@host;transport=tcp";
455  char uri4[] = "sip:name:secret@host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
456  /* test 5 is for NULL input */
457  char uri6[] = "sip:name:secret@host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
458  char uri7[] = "sip:name:secret@host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
459  char uri8[] = "sip:host";
460  char uri9[] = "sip:host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
461  char uri10[] = "host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
462  char uri11[] = "host";
463 
464  switch (cmd) {
465  case TEST_INIT:
466  info->name = "sip_uri_parse_test";
467  info->category = "/channels/chan_sip/";
468  info->summary = "tests sip uri parsing";
469  info->description =
470  "Tests parsing of various URIs "
471  "Verifies output matches expected behavior.";
472  return AST_TEST_NOT_RUN;
473  case TEST_EXECUTE:
474  break;
475  }
476 
477  /* Test 1, simple URI */
478  name = pass = hostport = transport = NULL;
479  if (parse_uri(uri1, "sip:,sips:", &name, &pass, &hostport, &transport) ||
480  strcmp(name, "name") ||
481  !ast_strlen_zero(pass) ||
482  strcmp(hostport, "host") ||
483  !ast_strlen_zero(transport)) {
484  ast_test_status_update(test, "Test 1: simple uri failed. \n");
485  res = AST_TEST_FAIL;
486  }
487 
488  /* Test 2, add tcp transport */
489  name = pass = hostport = transport = NULL;
490  if (parse_uri(uri2, "sip:,sips:", &name, &pass, &hostport, &transport) ||
491  strcmp(name, "name") ||
492  !ast_strlen_zero(pass) ||
493  strcmp(hostport, "host") ||
494  strcmp(transport, "tcp")) {
495  ast_test_status_update(test, "Test 2: uri with addtion of tcp transport failed. \n");
496  res = AST_TEST_FAIL;
497  }
498 
499  /* Test 3, add secret */
500  name = pass = hostport = transport = NULL;
501  if (parse_uri(uri3, "sip:,sips:", &name, &pass, &hostport, &transport) ||
502  strcmp(name, "name") ||
503  strcmp(pass, "secret") ||
504  strcmp(hostport, "host") ||
505  strcmp(transport, "tcp")) {
506  ast_test_status_update(test, "Test 3: uri with addition of secret failed.\n");
507  res = AST_TEST_FAIL;
508  }
509 
510  /* Test 4, add port and unparsed header field*/
511  name = pass = hostport = transport = NULL;
512  if (parse_uri(uri4, "sip:,sips:", &name, &pass, &hostport, &transport) ||
513  strcmp(name, "name") ||
514  strcmp(pass, "secret") ||
515  strcmp(hostport, "host:port") ||
516  strcmp(transport, "tcp")) {
517  ast_test_status_update(test, "Test 4: add port and unparsed header field failed.\n");
518  res = AST_TEST_FAIL;
519  }
520 
521  /* Test 5, verify parse_uri does not crash when given a NULL uri */
522  name = pass = hostport = transport = NULL;
523  if (!parse_uri(NULL, "sip:,sips:", &name, &pass, &hostport, &transport)) {
524  ast_test_status_update(test, "Test 5: passing a NULL uri failed.\n");
525  res = AST_TEST_FAIL;
526  }
527 
528  /* Test 6, verify parse_uri does not crash when given a NULL output parameters */
529  name = pass = hostport = transport = NULL;
530  if (parse_uri(uri6, "sip:,sips:", NULL, NULL, NULL, NULL)) {
531  ast_test_status_update(test, "Test 6: passing NULL output parameters failed.\n");
532  res = AST_TEST_FAIL;
533  }
534 
535  /* Test 7, verify parse_uri returns user:secret and hostport when no port or secret output parameters are supplied. */
536  name = pass = hostport = transport = NULL;
537  if (parse_uri(uri7, "sip:,sips:", &name, NULL, &hostport, NULL) ||
538  strcmp(name, "name:secret") ||
539  strcmp(hostport, "host:port")) {
540 
541  ast_test_status_update(test, "Test 7: providing no port and secret output parameters failed.\n");
542  res = AST_TEST_FAIL;
543  }
544 
545  /* Test 8, verify parse_uri can handle a hostport only uri */
546  name = pass = hostport = transport = NULL;
547  if (parse_uri(uri8, "sip:,sips:", &name, &pass, &hostport, &transport) ||
548  strcmp(hostport, "host") ||
549  !ast_strlen_zero(name)) {
550  ast_test_status_update(test, "Test 8: add port and unparsed header field failed.\n");
551  res = AST_TEST_FAIL;
552  }
553 
554  /* Test 9, add port and unparsed header field with hostport only uri*/
555  name = pass = hostport = transport = NULL;
556  if (parse_uri(uri9, "sip:,sips:", &name, &pass, &hostport, &transport) ||
557  !ast_strlen_zero(name) ||
558  !ast_strlen_zero(pass) ||
559  strcmp(hostport, "host:port") ||
560  strcmp(transport, "tcp")) {
561  ast_test_status_update(test, "Test 9: hostport only uri failed \n");
562  res = AST_TEST_FAIL;
563  }
564 
565  /* Test 10, handle invalid/missing "sip:,sips:" scheme
566  * we expect parse_uri to return an error, but still parse
567  * the results correctly here */
568  name = pass = hostport = transport = NULL;
569  if (!parse_uri(uri10, "sip:,sips:", &name, &pass, &hostport, &transport) ||
570  !ast_strlen_zero(name) ||
571  !ast_strlen_zero(pass) ||
572  strcmp(hostport, "host:port") ||
573  strcmp(transport, "tcp")) {
574  ast_test_status_update(test, "Test 10: missing \"sip:sips:\" scheme failed\n");
575  res = AST_TEST_FAIL;
576  }
577 
578  /* Test 11, simple hostport only URI with missing scheme
579  * we expect parse_uri to return an error, but still parse
580  * the results correctly here */
581  name = pass = hostport = transport = NULL;
582  if (!parse_uri(uri11, "sip:,sips:", &name, &pass, &hostport, &transport) ||
583  !ast_strlen_zero(name) ||
584  !ast_strlen_zero(pass) ||
585  strcmp(hostport, "host") ||
586  !ast_strlen_zero(transport)) {
587  ast_test_status_update(test, "Test 11: simple uri with missing scheme failed. \n");
588  res = AST_TEST_FAIL;
589  }
590 
591  return res;
592 }
static char pass[512]
int parse_uri(char *uri, const char *scheme, char **user, char **pass, char **hostport, char **transport)
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
static const char name[]
AST_TEST_DEFINE ( get_calleridname_test  )

Definition at line 723 of file reqresp_parser.c.

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

724 {
725  int res = AST_TEST_PASS;
726  const char *in1 = " \" quoted-text internal \\\" quote \"<stuff>";
727  const char *in2 = " token text with no quotes <stuff>";
728  const char *overflow1 = " \"quoted-text overflow 1234567890123456789012345678901234567890\" <stuff>";
729  const char *overflow2 = " non-quoted text overflow 1234567890123456789012345678901234567890 <stuff>";
730  const char *noendquote = " \"quoted-text no end <stuff>";
731  const char *addrspec = " sip:blah@blah";
732  const char *no_quotes_no_brackets = "blah@blah";
733  const char *after_dname;
734  char dname[40];
735 
736  switch (cmd) {
737  case TEST_INIT:
738  info->name = "sip_get_calleridname_test";
739  info->category = "/channels/chan_sip/";
740  info->summary = "decodes callerid name from sip header";
741  info->description = "Decodes display-name field of sip header. Checks for valid output and expected failure cases.";
742  return AST_TEST_NOT_RUN;
743  case TEST_EXECUTE:
744  break;
745  }
746 
747  /* quoted-text with backslash escaped quote */
748  after_dname = get_calleridname(in1, dname, sizeof(dname));
749  ast_test_status_update(test, "display-name1: %s\nafter: %s\n", dname, after_dname);
750  if (strcmp(dname, " quoted-text internal \" quote ")) {
751  ast_test_status_update(test, "display-name1 test failed\n");
752  res = AST_TEST_FAIL;
753  }
754 
755  /* token text */
756  after_dname = get_calleridname(in2, dname, sizeof(dname));
757  ast_test_status_update(test, "display-name2: %s\nafter: %s\n", dname, after_dname);
758  if (strcmp(dname, "token text with no quotes")) {
759  ast_test_status_update(test, "display-name2 test failed\n");
760  res = AST_TEST_FAIL;
761  }
762 
763  /* quoted-text buffer overflow */
764  after_dname = get_calleridname(overflow1, dname, sizeof(dname));
765  ast_test_status_update(test, "overflow display-name1: %s\nafter: %s\n", dname, after_dname);
766  if (strcmp(dname, "quoted-text overflow 123456789012345678")) {
767  ast_test_status_update(test, "overflow display-name1 test failed\n");
768  res = AST_TEST_FAIL;
769  }
770 
771  /* non-quoted-text buffer overflow */
772  after_dname = get_calleridname(overflow2, dname, sizeof(dname));
773  ast_test_status_update(test, "overflow display-name2: %s\nafter: %s\n", dname, after_dname);
774  if (strcmp(dname, "non-quoted text overflow 12345678901234")) {
775  ast_test_status_update(test, "overflow display-name2 test failed\n");
776  res = AST_TEST_FAIL;
777  }
778 
779  /* quoted-text buffer with no terminating end quote */
780  after_dname = get_calleridname(noendquote, dname, sizeof(dname));
781  ast_test_status_update(test, "noendquote display-name1: %s\nafter: %s\n", dname, after_dname);
782  if (*dname != '\0' && after_dname != noendquote) {
783  ast_test_status_update(test, "no end quote for quoted-text display-name failed\n");
784  res = AST_TEST_FAIL;
785  }
786 
787  /* addr-spec rather than display-name. */
788  after_dname = get_calleridname(addrspec, dname, sizeof(dname));
789  ast_test_status_update(test, "addr-spec display-name1: %s\nafter: %s\n", dname, after_dname);
790  if (*dname != '\0' && after_dname != addrspec) {
791  ast_test_status_update(test, "detection of addr-spec failed\n");
792  res = AST_TEST_FAIL;
793  }
794 
795  /* no quotes, no brackets */
796  after_dname = get_calleridname(no_quotes_no_brackets, dname, sizeof(dname));
797  ast_test_status_update(test, "no_quotes_no_brackets display-name1: %s\nafter: %s\n", dname, after_dname);
798  if (*dname != '\0' && after_dname != no_quotes_no_brackets) {
799  ast_test_status_update(test, "detection of addr-spec failed\n");
800  res = AST_TEST_FAIL;
801  }
802 
803  return res;
804 }
#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.
AST_TEST_DEFINE ( get_name_and_number_test  )

Definition at line 846 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(), name, TEST_EXECUTE, and TEST_INIT.

847 {
848  int res = AST_TEST_PASS;
849  char *name = NULL;
850  char *number = NULL;
851  const char *in1 = "NAME <sip:NUMBER@place>";
852  const char *in2 = "\"NA><ME\" <sip:NUMBER@place>";
853  const char *in3 = "NAME";
854  const char *in4 = "<sip:NUMBER@place>";
855  const char *in5 = "This is a screwed up string <sip:LOLCLOWNS<sip:>@place>";
856 
857  switch (cmd) {
858  case TEST_INIT:
859  info->name = "sip_get_name_and_number_test";
860  info->category = "/channels/chan_sip/";
861  info->summary = "Tests getting name and number from sip header";
862  info->description =
863  "Runs through various test situations in which a name and "
864  "and number can be retrieved from a sip header.";
865  return AST_TEST_NOT_RUN;
866  case TEST_EXECUTE:
867  break;
868  }
869 
870  /* Test 1. get name and number */
871  number = name = NULL;
872  if ((get_name_and_number(in1, &name, &number)) ||
873  strcmp(name, "NAME") ||
874  strcmp(number, "NUMBER")) {
875 
876  ast_test_status_update(test, "Test 1, simple get name and number failed.\n");
877  res = AST_TEST_FAIL;
878  }
879  ast_free(name);
880  ast_free(number);
881 
882  /* Test 2. get quoted name and number */
883  number = name = NULL;
884  if ((get_name_and_number(in2, &name, &number)) ||
885  strcmp(name, "NA><ME") ||
886  strcmp(number, "NUMBER")) {
887 
888  ast_test_status_update(test, "Test 2, get quoted name and number failed.\n");
889  res = AST_TEST_FAIL;
890  }
891  ast_free(name);
892  ast_free(number);
893 
894  /* Test 3. name only */
895  number = name = NULL;
896  if (!(get_name_and_number(in3, &name, &number))) {
897 
898  ast_test_status_update(test, "Test 3, get name only was expected to fail but did not.\n");
899  res = AST_TEST_FAIL;
900  }
901  ast_free(name);
902  ast_free(number);
903 
904  /* Test 4. number only */
905  number = name = NULL;
906  if ((get_name_and_number(in4, &name, &number)) ||
907  !ast_strlen_zero(name) ||
908  strcmp(number, "NUMBER")) {
909 
910  ast_test_status_update(test, "Test 4, get number with no name present failed.\n");
911  res = AST_TEST_FAIL;
912  }
913  ast_free(name);
914  ast_free(number);
915 
916  /* Test 5. malformed string, since number can not be parsed, this should return an error. */
917  number = name = NULL;
918  if (!(get_name_and_number(in5, &name, &number)) ||
919  !ast_strlen_zero(name) ||
920  !ast_strlen_zero(number)) {
921 
922  ast_test_status_update(test, "Test 5, processing malformed string failed.\n");
923  res = AST_TEST_FAIL;
924  }
925  ast_free(name);
926  ast_free(number);
927 
928  /* Test 6. NULL output parameters */
929  number = name = NULL;
930  if (!(get_name_and_number(in5, NULL, NULL))) {
931 
932  ast_test_status_update(test, "Test 6, NULL output parameters failed.\n");
933  res = AST_TEST_FAIL;
934  }
935 
936  /* Test 7. NULL input parameter */
937  number = name = NULL;
938  if (!(get_name_and_number(NULL, &name, &number)) ||
939  !ast_strlen_zero(name) ||
940  !ast_strlen_zero(number)) {
941 
942  ast_test_status_update(test, "Test 7, NULL input parameter failed.\n");
943  res = AST_TEST_FAIL;
944  }
945  ast_free(name);
946  ast_free(number);
947 
948  return res;
949 }
Number structure.
Definition: app_followme.c:109
int get_name_and_number(const char *hdr, char **name, char **number)
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
static const char name[]
#define ast_free(a)
Definition: astmm.h:97
AST_TEST_DEFINE ( get_in_brackets_test  )

Definition at line 1082 of file reqresp_parser.c.

References AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, get_in_brackets(), TEST_EXECUTE, and TEST_INIT.

1083 {
1084  int res = AST_TEST_PASS;
1085  char in_brackets[] = "sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah";
1086  char no_name[] = "<sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
1087  char quoted_string[] = "\"I'm a quote stri><ng\" <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
1088  char missing_end_quote[] = "\"I'm a quote string <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
1089  char name_no_quotes[] = "name not in quotes <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
1090  char no_end_bracket[] = "name not in quotes <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah";
1091  char no_name_no_brackets[] = "sip:name@host";
1092  char missing_start_bracket[] = "sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
1093  char *uri = NULL;
1094 
1095  switch (cmd) {
1096  case TEST_INIT:
1097  info->name = "sip_get_in_brackets_test";
1098  info->category = "/channels/chan_sip/";
1099  info->summary = "Tests getting a sip uri in <> brackets within a sip header.";
1100  info->description =
1101  "Runs through various test situations in which a sip uri "
1102  "in angle brackets needs to be retrieved";
1103  return AST_TEST_NOT_RUN;
1104  case TEST_EXECUTE:
1105  break;
1106  }
1107 
1108  /* Test 1, simple get in brackets */
1109  if (!(uri = get_in_brackets(no_name)) || strcmp(uri, in_brackets)) {
1110  ast_test_status_update(test, "Test 1, simple get in brackets failed. %s\n", uri);
1111  res = AST_TEST_FAIL;
1112  }
1113 
1114  /* Test 2, starts with quoted string */
1115  if (!(uri = get_in_brackets(quoted_string)) || strcmp(uri, in_brackets)) {
1116  ast_test_status_update(test, "Test 2, get in brackets with quoted string in front failed. %s\n", uri);
1117  res = AST_TEST_FAIL;
1118  }
1119 
1120  /* Test 3, missing end quote */
1121  if (!(uri = get_in_brackets(missing_end_quote)) || !strcmp(uri, in_brackets)) {
1122  ast_test_status_update(test, "Test 3, missing end quote failed. %s\n", uri);
1123  res = AST_TEST_FAIL;
1124  }
1125 
1126  /* Test 4, starts with a name not in quotes */
1127  if (!(uri = get_in_brackets(name_no_quotes)) || strcmp(uri, in_brackets)) {
1128  ast_test_status_update(test, "Test 4, passing name not in quotes failed. %s\n", uri);
1129  res = AST_TEST_FAIL;
1130  }
1131 
1132  /* Test 5, no end bracket, should just return everything after the first '<' */
1133  if (!(uri = get_in_brackets(no_end_bracket)) || !strcmp(uri, in_brackets)) {
1134  ast_test_status_update(test, "Test 5, no end bracket failed. %s\n", uri);
1135  res = AST_TEST_FAIL;
1136  }
1137 
1138  /* Test 6, NULL input */
1139  if (get_in_brackets(NULL)) {
1140  ast_test_status_update(test, "Test 6, NULL input failed.\n");
1141  res = AST_TEST_FAIL;
1142  }
1143 
1144  /* Test 7, no name, and no brackets. */
1145  if (!(uri = get_in_brackets(no_name_no_brackets)) || strcmp(uri, "sip:name@host")) {
1146  ast_test_status_update(test, "Test 7 failed. %s\n", uri);
1147  res = AST_TEST_FAIL;
1148  }
1149 
1150  /* Test 8, no start bracket, but with ending bracket. */
1151  if (!(uri = get_in_brackets(missing_start_bracket)) || strcmp(uri, in_brackets)) {
1152  ast_test_status_update(test, "Test 8 failed. %s\n", uri);
1153  res = AST_TEST_FAIL;
1154  }
1155 
1156  return res;
1157 }
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
char * get_in_brackets(char *tmp)
AST_TEST_DEFINE ( parse_name_andor_addr_test  )

Definition at line 1204 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, name, parse_name_andor_addr(), pass, TEST_EXECUTE, TEST_INIT, and user.

1205 {
1206  int res = AST_TEST_PASS;
1207  char uri[1024];
1208  char *name, *user, *pass, *hostport, *headers, *residue;
1209  struct uriparams params;
1210 
1211  struct testdata {
1212  char *desc;
1213  char *uri;
1214  char *name;
1215  char *user;
1216  char *pass;
1217  char *hostport;
1218  char *headers;
1219  char *residue;
1220  struct uriparams params;
1221  AST_LIST_ENTRY(testdata) list;
1222  };
1223 
1224  struct testdata *testdataptr;
1225 
1226  static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
1227 
1228  struct testdata td1 = {
1229  .desc = "quotes and brackets",
1230  .uri = "\"name :@ \" <sip:user:secret@host:5060;param=discard;transport=tcp>;tag=tag",
1231  .name = "name :@ ",
1232  .user = "user",
1233  .pass = "secret",
1234  .hostport = "host:5060",
1235  .headers = "",
1236  .residue = "tag=tag",
1237  .params.transport = "tcp",
1238  .params.lr = 0,
1239  .params.user = ""
1240  };
1241 
1242  struct testdata td2 = {
1243  .desc = "no quotes",
1244  .uri = "givenname familyname <sip:user:secret@host:5060;param=discard;transport=tcp>;expires=3600",
1245  .name = "givenname familyname",
1246  .user = "user",
1247  .pass = "secret",
1248  .hostport = "host:5060",
1249  .headers = "",
1250  .residue = "expires=3600",
1251  .params.transport = "tcp",
1252  .params.lr = 0,
1253  .params.user = ""
1254  };
1255 
1256  struct testdata td3 = {
1257  .desc = "no brackets",
1258  .uri = "sip:user:secret@host:5060;param=discard;transport=tcp;q=1",
1259  .name = "",
1260  .user = "user",
1261  .pass = "secret",
1262  .hostport = "host:5060",
1263  .headers = "",
1264  .residue = "q=1",
1265  .params.transport = "tcp",
1266  .params.lr = 0,
1267  .params.user = ""
1268  };
1269 
1270  struct testdata td4 = {
1271  .desc = "just host",
1272  .uri = "sips:host",
1273  .name = "",
1274  .user = "",
1275  .pass = "",
1276  .hostport = "host",
1277  .headers = "",
1278  .residue = "",
1279  .params.transport = "",
1280  .params.lr = 0,
1281  .params.user = ""
1282  };
1283 
1284 
1285  AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &td1);
1286  AST_LIST_INSERT_TAIL(&testdatalist, &td2, list);
1287  AST_LIST_INSERT_TAIL(&testdatalist, &td3, list);
1288  AST_LIST_INSERT_TAIL(&testdatalist, &td4, list);
1289 
1290 
1291  switch (cmd) {
1292  case TEST_INIT:
1293  info->name = "parse_name_andor_addr_test";
1294  info->category = "/channels/chan_sip/";
1295  info->summary = "tests parsing of name_andor_addr abnf structure";
1296  info->description =
1297  "Tests parsing of abnf name-andor-addr = name-addr / addr-spec "
1298  "Verifies output matches expected behavior.";
1299  return AST_TEST_NOT_RUN;
1300  case TEST_EXECUTE:
1301  break;
1302  }
1303 
1304  AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
1305  name = user = pass = hostport = headers = residue = NULL;
1306  params.transport = params.user = params.method = params.ttl = params.maddr = NULL;
1307  params.lr = 0;
1308  ast_copy_string(uri,testdataptr->uri,sizeof(uri));
1309  if (parse_name_andor_addr(uri, "sip:,sips:",
1310  &name,
1311  &user,
1312  &pass,
1313  &hostport,
1314  &params,
1315  &headers,
1316  &residue) ||
1317  (name && strcmp(testdataptr->name, name)) ||
1318  (user && strcmp(testdataptr->user, user)) ||
1319  (pass && strcmp(testdataptr->pass, pass)) ||
1320  (hostport && strcmp(testdataptr->hostport, hostport)) ||
1321  (headers && strcmp(testdataptr->headers, headers)) ||
1322  (residue && strcmp(testdataptr->residue, residue)) ||
1323  (strcmp(testdataptr->params.transport,params.transport)) ||
1324  (strcmp(testdataptr->params.user,params.user))
1325  ) {
1326  ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc);
1327  res = AST_TEST_FAIL;
1328  }
1329  }
1330 
1331  return res;
1332 }
static char user[512]
static char pass[512]
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:224
static const char desc[]
Definition: cdr_radius.c:85
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
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)
#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[]
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
AST_TEST_DEFINE ( parse_contact_header_test  )

Definition at line 1429 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, parse_contact_header(), TEST_EXECUTE, and TEST_INIT.

1430 {
1431  int res = AST_TEST_PASS;
1432  char contactheader[1024];
1433  int star;
1434  struct contactliststruct contactlist;
1435  struct contactliststruct *contactlistptr=&contactlist;
1436 
1437  struct testdata {
1438  char *desc;
1439  char *contactheader;
1440  int star;
1441  struct contactliststruct *contactlist;
1442 
1443  AST_LIST_ENTRY(testdata) list;
1444  };
1445 
1446  struct testdata *testdataptr;
1447  struct contact *tdcontactptr;
1448  struct contact *contactptr;
1449 
1450  static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
1451  struct contactliststruct contactlist1, contactlist2;
1452 
1453  struct testdata td1 = {
1454  .desc = "single contact",
1455  .contactheader = "\"name :@;?&,\" <sip:user:secret@host:5082;param=discard;transport=tcp>;expires=3600",
1456  .contactlist = &contactlist1,
1457  .star = 0
1458  };
1459  struct contact contact11 = {
1460  .name = "name :@;?&,",
1461  .user = "user",
1462  .pass = "secret",
1463  .hostport = "host:5082",
1464  .params.transport = "tcp",
1465  .params.ttl = "",
1466  .params.lr = 0,
1467  .headers = "",
1468  .expires = "3600",
1469  .q = ""
1470  };
1471 
1472  struct testdata td2 = {
1473  .desc = "multiple contacts",
1474  .contactheader = "sip:,user1,:,secret1,@host1;ttl=7;q=1;expires=3600,sips:host2",
1475  .contactlist = &contactlist2,
1476  .star = 0,
1477  };
1478  struct contact contact21 = {
1479  .name = "",
1480  .user = ",user1,",
1481  .pass = ",secret1,",
1482  .hostport = "host1",
1483  .params.transport = "",
1484  .params.ttl = "7",
1485  .params.lr = 0,
1486  .headers = "",
1487  .expires = "3600",
1488  .q = "1"
1489  };
1490  struct contact contact22 = {
1491  .name = "",
1492  .user = "",
1493  .pass = "",
1494  .hostport = "host2",
1495  .params.transport = "",
1496  .params.ttl = "",
1497  .params.lr = 0,
1498  .headers = "",
1499  .expires = "",
1500  .q = ""
1501  };
1502 
1503  struct testdata td3 = {
1504  .desc = "star - all contacts",
1505  .contactheader = "*",
1506  .star = 1,
1507  .contactlist = NULL
1508  };
1509 
1510  AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &td1);
1511  AST_LIST_INSERT_TAIL(&testdatalist, &td2, list);
1512  AST_LIST_INSERT_TAIL(&testdatalist, &td3, list);
1513 
1514  AST_LIST_HEAD_SET_NOLOCK(&contactlist1, &contact11);
1515 
1516  AST_LIST_HEAD_SET_NOLOCK(&contactlist2, &contact21);
1517  AST_LIST_INSERT_TAIL(&contactlist2, &contact22, list);
1518 
1519 
1520  switch (cmd) {
1521  case TEST_INIT:
1522  info->name = "parse_contact_header_test";
1523  info->category = "/channels/chan_sip/";
1524  info->summary = "tests parsing of sip contact header";
1525  info->description =
1526  "Tests parsing of a contact header including those with multiple contacts "
1527  "Verifies output matches expected behavior.";
1528  return AST_TEST_NOT_RUN;
1529  case TEST_EXECUTE:
1530  break;
1531  }
1532 
1533  AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
1534  ast_copy_string(contactheader,testdataptr->contactheader,sizeof(contactheader));
1535  star = parse_contact_header(contactheader,contactlistptr);
1536  if (testdataptr->star) {
1537  /* expecting star rather than list of contacts */
1538  if (!star) {
1539  ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc);
1540  res = AST_TEST_FAIL;
1541  break;
1542  }
1543  } else {
1544  contactptr = AST_LIST_FIRST(contactlistptr);
1545  AST_LIST_TRAVERSE(testdataptr->contactlist, tdcontactptr, list) {
1546  if (!contactptr ||
1547  strcmp(tdcontactptr->name, contactptr->name) ||
1548  strcmp(tdcontactptr->user, contactptr->user) ||
1549  strcmp(tdcontactptr->pass, contactptr->pass) ||
1550  strcmp(tdcontactptr->hostport, contactptr->hostport) ||
1551  strcmp(tdcontactptr->headers, contactptr->headers) ||
1552  strcmp(tdcontactptr->expires, contactptr->expires) ||
1553  strcmp(tdcontactptr->q, contactptr->q) ||
1554  strcmp(tdcontactptr->params.transport, contactptr->params.transport) ||
1555  strcmp(tdcontactptr->params.ttl, contactptr->params.ttl) ||
1556  (tdcontactptr->params.lr != contactptr->params.lr)
1557  ) {
1558  ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc);
1559  res = AST_TEST_FAIL;
1560  break;
1561  }
1562 
1563  contactptr = AST_LIST_NEXT(contactptr,list);
1564  }
1565 
1566  while ((contactptr = AST_LIST_REMOVE_HEAD(contactlistptr,list))) {
1567  ast_free(contactptr);
1568  }
1569  }
1570  }
1571 
1572  return res;
1573 }
#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
#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:818
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:224
static const char desc[]
Definition: cdr_radius.c:85
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
int parse_contact_header(char *contactheader, struct contactliststruct *contactlist)
#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
#define ast_free(a)
Definition: astmm.h:97
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
AST_TEST_DEFINE ( sip_parse_options_test  )

Definition at line 1661 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, name, parse_sip_options(), TEST_EXECUTE, and TEST_INIT.

1662 {
1663  int res = AST_TEST_PASS;
1664  char unsupported[64];
1665  unsigned int option_profile = 0;
1666  struct testdata {
1667  char *name;
1668  char *input_options;
1669  char *expected_unsupported;
1670  unsigned int expected_profile;
1671  AST_LIST_ENTRY(testdata) list;
1672  };
1673 
1674  struct testdata *testdataptr;
1675  static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
1676 
1677  struct testdata test1 = {
1678  .name = "test_all_unsupported",
1679  .input_options = "unsupported1,,, ,unsupported2,unsupported3,unsupported4",
1680  .expected_unsupported = "unsupported1,unsupported2,unsupported3,unsupported4",
1681  .expected_profile = SIP_OPT_UNKNOWN,
1682  };
1683  struct testdata test2 = {
1684  .name = "test_all_unsupported_one_supported",
1685  .input_options = " unsupported1, replaces, unsupported3 , , , ,unsupported4",
1686  .expected_unsupported = "unsupported1,unsupported3,unsupported4",
1687  .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES
1688  };
1689  struct testdata test3 = {
1690  .name = "test_two_supported_two_unsupported",
1691  .input_options = ",, timer ,replaces ,unsupported3,unsupported4",
1692  .expected_unsupported = "unsupported3,unsupported4",
1693  .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES | SIP_OPT_TIMER,
1694  };
1695 
1696  struct testdata test4 = {
1697  .name = "test_all_supported",
1698  .input_options = "timer,replaces",
1699  .expected_unsupported = "",
1700  .expected_profile = SIP_OPT_REPLACES | SIP_OPT_TIMER,
1701  };
1702 
1703  struct testdata test5 = {
1704  .name = "test_all_supported_redundant",
1705  .input_options = "timer,replaces,timer,replace,timer,replaces",
1706  .expected_unsupported = "",
1707  .expected_profile = SIP_OPT_REPLACES | SIP_OPT_TIMER,
1708  };
1709  struct testdata test6 = {
1710  .name = "test_buffer_overflow",
1711  .input_options = "unsupported1,replaces,timer,unsupported4,unsupported_huge____"
1712  "____________________________________,__________________________________________"
1713  "________________________________________________",
1714  .expected_unsupported = "unsupported1,unsupported4",
1715  .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES | SIP_OPT_TIMER,
1716  };
1717  struct testdata test7 = {
1718  .name = "test_null_input",
1719  .input_options = NULL,
1720  .expected_unsupported = "",
1721  .expected_profile = 0,
1722  };
1723  struct testdata test8 = {
1724  .name = "test_whitespace_input",
1725  .input_options = " ",
1726  .expected_unsupported = "",
1727  .expected_profile = 0,
1728  };
1729  struct testdata test9 = {
1730  .name = "test_whitespace_plus_option_input",
1731  .input_options = " , , ,timer , , , , , ",
1732  .expected_unsupported = "",
1733  .expected_profile = SIP_OPT_TIMER,
1734  };
1735 
1736  switch (cmd) {
1737  case TEST_INIT:
1738  info->name = "sip_parse_options_test";
1739  info->category = "/channels/chan_sip/";
1740  info->summary = "Tests parsing of sip options";
1741  info->description =
1742  "Tests parsing of SIP options from supported and required "
1743  "header fields. Verifies when unsupported options are encountered "
1744  "that they are appended to the unsupported out buffer and that the "
1745  "correct bit field representnig the option profile is returned.";
1746  return AST_TEST_NOT_RUN;
1747  case TEST_EXECUTE:
1748  break;
1749  }
1750 
1751  AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &test1);
1752  AST_LIST_INSERT_TAIL(&testdatalist, &test2, list);
1753  AST_LIST_INSERT_TAIL(&testdatalist, &test3, list);
1754  AST_LIST_INSERT_TAIL(&testdatalist, &test4, list);
1755  AST_LIST_INSERT_TAIL(&testdatalist, &test5, list);
1756  AST_LIST_INSERT_TAIL(&testdatalist, &test6, list);
1757  AST_LIST_INSERT_TAIL(&testdatalist, &test7, list);
1758  AST_LIST_INSERT_TAIL(&testdatalist, &test8, list);
1759  AST_LIST_INSERT_TAIL(&testdatalist, &test9, list);
1760 
1761  /* Test with unsupported char buffer */
1762  AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
1763  memset(unsupported, 0, sizeof(unsupported));
1764  option_profile = parse_sip_options(testdataptr->input_options, unsupported, ARRAY_LEN(unsupported));
1765  if (option_profile != testdataptr->expected_profile ||
1766  strcmp(unsupported, testdataptr->expected_unsupported)) {
1767  ast_test_status_update(test, "Test with output buffer \"%s\", expected unsupported: %s actual unsupported:"
1768  "%s expected bit profile: %x actual bit profile: %x\n",
1769  testdataptr->name,
1770  testdataptr->expected_unsupported,
1771  unsupported,
1772  testdataptr->expected_profile,
1773  option_profile);
1774  res = AST_TEST_FAIL;
1775  } else {
1776  ast_test_status_update(test, "\"%s\" passed got expected unsupported: %s and bit profile: %x\n",
1777  testdataptr->name,
1778  unsupported,
1779  option_profile);
1780  }
1781 
1782  option_profile = parse_sip_options(testdataptr->input_options, NULL, 0);
1783  if (option_profile != testdataptr->expected_profile) {
1784  ast_test_status_update(test, "NULL output test \"%s\", expected bit profile: %x actual bit profile: %x\n",
1785  testdataptr->name,
1786  testdataptr->expected_profile,
1787  option_profile);
1788  res = AST_TEST_FAIL;
1789  } else {
1790  ast_test_status_update(test, "\"%s\" with NULL output buf passed, bit profile: %x\n",
1791  testdataptr->name,
1792  option_profile);
1793  }
1794  }
1795 
1796  return res;
1797 }
#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 ast_test_status_update(a, b, c...)
Definition: test.h:129
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:224
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
#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[]
AST_TEST_DEFINE ( sip_uri_cmp_test  )

Definition at line 2152 of file reqresp_parser.c.

References ARRAY_LEN, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, sip_uri_cmp(), TEST_EXECUTE, TEST_INIT, URI_CMP_MATCH, and URI_CMP_NOMATCH.

2153 {
2154  static const struct {
2155  const char *uri1;
2156  const char *uri2;
2157  int expected_result;
2158  } uri_cmp_tests [] = {
2159  /* These are identical, so they match */
2160  { "sip:bob@example.com", "sip:bob@example.com", URI_CMP_MATCH },
2161  /* Different usernames. No match */
2162  { "sip:alice@example.com", "sip:bob@example.com", URI_CMP_NOMATCH },
2163  /* Different hosts. No match */
2164  { "sip:bob@example.com", "sip:bob@examplez.com", URI_CMP_NOMATCH },
2165  /* Now start using IP addresses. Identical, so they match */
2166  { "sip:bob@1.2.3.4", "sip:bob@1.2.3.4", URI_CMP_MATCH },
2167  /* Two identical IPv4 addresses represented differently. Match */
2168  { "sip:bob@1.2.3.4", "sip:bob@001.002.003.004", URI_CMP_MATCH },
2169  /* Logically equivalent IPv4 Address and hostname. No Match */
2170  { "sip:bob@127.0.0.1", "sip:bob@localhost", URI_CMP_NOMATCH },
2171  /* Logically equivalent IPv6 address and hostname. No Match */
2172  { "sip:bob@[::1]", "sip:bob@localhost", URI_CMP_NOMATCH },
2173  /* Try an IPv6 one as well */
2174  { "sip:bob@[2001:db8::1234]", "sip:bob@[2001:db8::1234]", URI_CMP_MATCH },
2175  /* Two identical IPv6 addresses represented differently. Match */
2176  { "sip:bob@[2001:db8::1234]", "sip:bob@[2001:0db8::1234]", URI_CMP_MATCH },
2177  /* Different ports. No match */
2178  { "sip:bob@1.2.3.4:5060", "sip:bob@1.2.3.4:5061", URI_CMP_NOMATCH },
2179  /* Same port logically, but only one address specifies it. No match */
2180  { "sip:bob@1.2.3.4:5060", "sip:bob@1.2.3.4", URI_CMP_NOMATCH },
2181  /* And for safety, try with IPv6 */
2182  { "sip:bob@[2001:db8:1234]:5060", "sip:bob@[2001:db8:1234]", URI_CMP_NOMATCH },
2183  /* User comparison is case sensitive. No match */
2184  { "sip:bob@example.com", "sip:BOB@example.com", URI_CMP_NOMATCH },
2185  /* Host comparison is case insensitive. Match */
2186  { "sip:bob@example.com", "sip:bob@EXAMPLE.COM", URI_CMP_MATCH },
2187  /* Add headers to the URI. Identical, so they match */
2188  { "sip:bob@example.com?header1=value1&header2=value2", "sip:bob@example.com?header1=value1&header2=value2", URI_CMP_MATCH },
2189  /* Headers in URI 1 are not in URI 2. No Match */
2190  { "sip:bob@example.com?header1=value1&header2=value2", "sip:bob@example.com", URI_CMP_NOMATCH },
2191  /* Header present in both URIs does not have matching values. No match */
2192  { "sip:bob@example.com?header1=value1&header2=value2", "sip:bob@example.com?header1=value1&header2=value3", URI_CMP_NOMATCH },
2193  /* Add parameters to the URI. Identical so they match */
2194  { "sip:bob@example.com;param1=value1;param2=value2", "sip:bob@example.com;param1=value1;param2=value2", URI_CMP_MATCH },
2195  /* Same parameters in both URIs but appear in different order. Match */
2196  { "sip:bob@example.com;param2=value2;param1=value1", "sip:bob@example.com;param1=value1;param2=value2", URI_CMP_MATCH },
2197  /* params in URI 1 are not in URI 2. Match */
2198  { "sip:bob@example.com;param1=value1;param2=value2", "sip:bob@example.com", URI_CMP_MATCH },
2199  /* param present in both URIs does not have matching values. No match */
2200  { "sip:bob@example.com;param1=value1;param2=value2", "sip:bob@example.com;param1=value1;param2=value3", URI_CMP_NOMATCH },
2201  /* URI 1 has a maddr param but URI 2 does not. No match */
2202  { "sip:bob@example.com;param1=value1;maddr=192.168.0.1", "sip:bob@example.com;param1=value1", URI_CMP_NOMATCH },
2203  /* URI 1 and URI 2 both have identical maddr params. Match */
2204  { "sip:bob@example.com;param1=value1;maddr=192.168.0.1", "sip:bob@example.com;param1=value1;maddr=192.168.0.1", URI_CMP_MATCH },
2205  /* URI 1 is a SIPS URI and URI 2 is a SIP URI. No Match */
2206  { "sips:bob@example.com", "sip:bob@example.com", URI_CMP_NOMATCH },
2207  /* No URI schemes. No match */
2208  { "bob@example.com", "bob@example.com", URI_CMP_NOMATCH },
2209  /* Crashiness tests. Just an address scheme. No match */
2210  { "sip", "sips", URI_CMP_NOMATCH },
2211  /* Still just an address scheme. Even though they're the same, No match */
2212  { "sip", "sip", URI_CMP_NOMATCH },
2213  /* Empty strings. No match */
2214  { "", "", URI_CMP_NOMATCH },
2215  /* An empty string and a NULL. No match */
2216  { "", NULL, URI_CMP_NOMATCH },
2217  };
2218  int i;
2219  int test_res = AST_TEST_PASS;
2220  switch (cmd) {
2221  case TEST_INIT:
2222  info->name = "sip_uri_cmp_test";
2223  info->category = "/channels/chan_sip/";
2224  info->summary = "Tests comparison of SIP URIs";
2225  info->description = "Several would-be tricky URI comparisons are performed";
2226  return AST_TEST_NOT_RUN;
2227  case TEST_EXECUTE:
2228  break;
2229  }
2230 
2231  for (i = 0; i < ARRAY_LEN(uri_cmp_tests); ++i) {
2232  int cmp_res1;
2233  int cmp_res2;
2234  if ((cmp_res1 = sip_uri_cmp(uri_cmp_tests[i].uri1, uri_cmp_tests[i].uri2))) {
2235  /* URI comparison may return -1 or +1 depending on the failure. Standardize
2236  * the return value to be URI_CMP_NOMATCH on any failure
2237  */
2238  cmp_res1 = URI_CMP_NOMATCH;
2239  }
2240  if (cmp_res1 != uri_cmp_tests[i].expected_result) {
2241  ast_test_status_update(test, "Unexpected comparison result for URIs %s and %s. "
2242  "Expected %s but got %s\n", uri_cmp_tests[i].uri1, uri_cmp_tests[i].uri2,
2243  uri_cmp_tests[i].expected_result == URI_CMP_MATCH ? "Match" : "No Match",
2244  cmp_res1 == URI_CMP_MATCH ? "Match" : "No Match");
2245  test_res = AST_TEST_FAIL;
2246  }
2247 
2248  /* All URI comparisons are commutative, so for the sake of being thorough, we'll
2249  * rerun the comparison with the parameters reversed
2250  */
2251  if ((cmp_res2 = sip_uri_cmp(uri_cmp_tests[i].uri2, uri_cmp_tests[i].uri1))) {
2252  /* URI comparison may return -1 or +1 depending on the failure. Standardize
2253  * the return value to be URI_CMP_NOMATCH on any failure
2254  */
2255  cmp_res2 = URI_CMP_NOMATCH;
2256  }
2257  if (cmp_res2 != uri_cmp_tests[i].expected_result) {
2258  ast_test_status_update(test, "Unexpected comparison result for URIs %s and %s. "
2259  "Expected %s but got %s\n", uri_cmp_tests[i].uri2, uri_cmp_tests[i].uri1,
2260  uri_cmp_tests[i].expected_result == URI_CMP_MATCH ? "Match" : "No Match",
2261  cmp_res2 == URI_CMP_MATCH ? "Match" : "No Match");
2262  test_res = AST_TEST_FAIL;
2263  }
2264  }
2265 
2266  return test_res;
2267 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
#define URI_CMP_NOMATCH
int sip_uri_cmp(const char *input1, const char *input2)
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define URI_CMP_MATCH
AST_TEST_DEFINE ( parse_via_test  )

Definition at line 2354 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, free_via(), parse_via(), TEST_EXECUTE, and TEST_INIT.

2355 {
2356  int res = AST_TEST_PASS;
2357  int i = 1;
2358  struct sip_via *via;
2359  struct testdata {
2360  char *in;
2361  char *expected_protocol;
2362  char *expected_branch;
2363  char *expected_sent_by;
2364  char *expected_maddr;
2365  unsigned int expected_port;
2366  unsigned char expected_ttl;
2367  int expected_null;
2368  AST_LIST_ENTRY(testdata) list;
2369  };
2370  struct testdata *testdataptr;
2371  static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
2372  struct testdata t1 = {
2373  .in = "SIP/2.0/UDP host:port;branch=thebranch",
2374  .expected_protocol = "SIP/2.0/UDP",
2375  .expected_sent_by = "host:port",
2376  .expected_branch = "thebranch",
2377  };
2378  struct testdata t2 = {
2379  .in = "SIP/2.0/UDP host:port",
2380  .expected_protocol = "SIP/2.0/UDP",
2381  .expected_sent_by = "host:port",
2382  .expected_branch = "",
2383  };
2384  struct testdata t3 = {
2385  .in = "SIP/2.0/UDP",
2386  .expected_null = 1,
2387  };
2388  struct testdata t4 = {
2389  .in = "BLAH/BLAH/BLAH host:port;branch=",
2390  .expected_protocol = "BLAH/BLAH/BLAH",
2391  .expected_sent_by = "host:port",
2392  .expected_branch = "",
2393  };
2394  struct testdata t5 = {
2395  .in = "SIP/2.0/UDP host:5060;branch=thebranch;maddr=224.0.0.1;ttl=1",
2396  .expected_protocol = "SIP/2.0/UDP",
2397  .expected_sent_by = "host:5060",
2398  .expected_port = 5060,
2399  .expected_branch = "thebranch",
2400  .expected_maddr = "224.0.0.1",
2401  .expected_ttl = 1,
2402  };
2403  struct testdata t6 = {
2404  .in = "SIP/2.0/UDP host:5060;\n branch=thebranch;\r\n maddr=224.0.0.1; ttl=1",
2405  .expected_protocol = "SIP/2.0/UDP",
2406  .expected_sent_by = "host:5060",
2407  .expected_port = 5060,
2408  .expected_branch = "thebranch",
2409  .expected_maddr = "224.0.0.1",
2410  .expected_ttl = 1,
2411  };
2412  struct testdata t7 = {
2413  .in = "SIP/2.0/UDP [::1]:5060",
2414  .expected_protocol = "SIP/2.0/UDP",
2415  .expected_sent_by = "[::1]:5060",
2416  .expected_port = 5060,
2417  .expected_branch = "",
2418  };
2419  switch (cmd) {
2420  case TEST_INIT:
2421  info->name = "parse_via_test";
2422  info->category = "/channels/chan_sip/";
2423  info->summary = "Tests parsing the Via header";
2424  info->description =
2425  "Runs through various test situations in which various "
2426  " parameters parameter must be extracted from a VIA header";
2427  return AST_TEST_NOT_RUN;
2428  case TEST_EXECUTE:
2429  break;
2430  }
2431 
2432  AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &t1);
2433  AST_LIST_INSERT_TAIL(&testdatalist, &t2, list);
2434  AST_LIST_INSERT_TAIL(&testdatalist, &t3, list);
2435  AST_LIST_INSERT_TAIL(&testdatalist, &t4, list);
2436  AST_LIST_INSERT_TAIL(&testdatalist, &t5, list);
2437  AST_LIST_INSERT_TAIL(&testdatalist, &t6, list);
2438  AST_LIST_INSERT_TAIL(&testdatalist, &t7, list);
2439 
2440 
2441  AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
2442  via = parse_via(testdataptr->in);
2443  if (!via) {
2444  if (!testdataptr->expected_null) {
2445  ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2446  "failed to parse header\n",
2447  i, testdataptr->in);
2448  res = AST_TEST_FAIL;
2449  }
2450  i++;
2451  continue;
2452  }
2453 
2454  if (testdataptr->expected_null) {
2455  ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2456  "successfully parased invalid via header\n",
2457  i, testdataptr->in);
2458  res = AST_TEST_FAIL;
2459  free_via(via);
2460  i++;
2461  continue;
2462  }
2463 
2464  if ((ast_strlen_zero(via->protocol) && !ast_strlen_zero(testdataptr->expected_protocol))
2465  || (!ast_strlen_zero(via->protocol) && strcmp(via->protocol, testdataptr->expected_protocol))) {
2466 
2467  ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2468  "parsed protocol = \"%s\"\n"
2469  "expected = \"%s\"\n"
2470  "failed to parse protocol\n",
2471  i, testdataptr->in, via->protocol, testdataptr->expected_protocol);
2472  res = AST_TEST_FAIL;
2473  }
2474 
2475  if ((ast_strlen_zero(via->sent_by) && !ast_strlen_zero(testdataptr->expected_sent_by))
2476  || (!ast_strlen_zero(via->sent_by) && strcmp(via->sent_by, testdataptr->expected_sent_by))) {
2477 
2478  ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2479  "parsed sent_by = \"%s\"\n"
2480  "expected = \"%s\"\n"
2481  "failed to parse sent-by\n",
2482  i, testdataptr->in, via->sent_by, testdataptr->expected_sent_by);
2483  res = AST_TEST_FAIL;
2484  }
2485 
2486  if (testdataptr->expected_port && testdataptr->expected_port != via->port) {
2487  ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2488  "parsed port = \"%u\"\n"
2489  "expected = \"%u\"\n"
2490  "failed to parse port\n",
2491  i, testdataptr->in, via->port, testdataptr->expected_port);
2492  res = AST_TEST_FAIL;
2493  }
2494 
2495  if ((ast_strlen_zero(via->branch) && !ast_strlen_zero(testdataptr->expected_branch))
2496  || (!ast_strlen_zero(via->branch) && strcmp(via->branch, testdataptr->expected_branch))) {
2497 
2498  ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2499  "parsed branch = \"%s\"\n"
2500  "expected = \"%s\"\n"
2501  "failed to parse branch\n",
2502  i, testdataptr->in, via->branch, testdataptr->expected_branch);
2503  res = AST_TEST_FAIL;
2504  }
2505 
2506  if ((ast_strlen_zero(via->maddr) && !ast_strlen_zero(testdataptr->expected_maddr))
2507  || (!ast_strlen_zero(via->maddr) && strcmp(via->maddr, testdataptr->expected_maddr))) {
2508 
2509  ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2510  "parsed maddr = \"%s\"\n"
2511  "expected = \"%s\"\n"
2512  "failed to parse maddr\n",
2513  i, testdataptr->in, via->maddr, testdataptr->expected_maddr);
2514  res = AST_TEST_FAIL;
2515  }
2516 
2517  if (testdataptr->expected_ttl && testdataptr->expected_ttl != via->ttl) {
2518  ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2519  "parsed ttl = \"%d\"\n"
2520  "expected = \"%d\"\n"
2521  "failed to parse ttl\n",
2522  i, testdataptr->in, via->ttl, testdataptr->expected_ttl);
2523  res = AST_TEST_FAIL;
2524  }
2525 
2526  free_via(via);
2527  i++;
2528  }
2529  return res;
2530 }
static uint16_t t7
Definition: res_pktccops.c:160
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
void free_via(struct sip_via *v)
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:224
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
#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
struct sip_via * parse_via(const char *header)
static uint16_t t1
Definition: res_pktccops.c:159
void free_via ( struct sip_via *  v)

Definition at line 2269 of file reqresp_parser.c.

References ast_free.

Referenced by AST_TEST_DEFINE(), find_call(), parse_via(), process_via(), and sip_alloc().

2270 {
2271  if (!v) {
2272  return;
2273  }
2274 
2275  ast_free(v->via);
2276  ast_free(v);
2277 }
#define ast_free(a)
Definition: astmm.h:97
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 598 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(), and parse_name_andor_addr().

599 {
600  /* From RFC3261:
601  *
602  * From = ( "From" / "f" ) HCOLON from-spec
603  * from-spec = ( name-addr / addr-spec ) *( SEMI from-param )
604  * name-addr = [ display-name ] LAQUOT addr-spec RAQUOT
605  * display-name = *(token LWS)/ quoted-string
606  * token = 1*(alphanum / "-" / "." / "!" / "%" / "*"
607  * / "_" / "+" / "`" / "'" / "~" )
608  * quoted-string = SWS DQUOTE *(qdtext / quoted-pair ) DQUOTE
609  * qdtext = LWS / %x21 / %x23-5B / %x5D-7E
610  * / UTF8-NONASCII
611  * quoted-pair = "\" (%x00-09 / %x0B-0C / %x0E-7F)
612  *
613  * HCOLON = *WSP ":" SWS
614  * SWS = [LWS]
615  * LWS = *[*WSP CRLF] 1*WSP
616  * WSP = (SP / HTAB)
617  *
618  * Deviations from it:
619  * - following CRLF's in LWS is not done (here at least)
620  * - ascii NUL is never legal as it terminates the C-string
621  * - utf8-nonascii is not checked for validity
622  */
623  char *orig_output = output;
624  const char *orig_input = input;
625 
626  if (!output || !outputsize) {
627  /* Bad output parameters. Should never happen. */
628  return input;
629  }
630 
631  /* clear any empty characters in the beginning */
633 
634  /* make sure the output buffer is initilized */
635  *orig_output = '\0';
636 
637  /* make room for '\0' at the end of the output buffer */
638  --outputsize;
639 
640  /* no data at all or no display name? */
641  if (!input || *input == '<') {
642  return input;
643  }
644 
645  /* quoted-string rules */
646  if (input[0] == '"') {
647  input++; /* skip the first " */
648 
649  for (; *input; ++input) {
650  if (*input == '"') { /* end of quoted-string */
651  break;
652  } else if (*input == 0x5c) { /* quoted-pair = "\" (%x00-09 / %x0B-0C / %x0E-7F) */
653  ++input;
654  if (!*input) {
655  break;
656  }
657  if ((unsigned char) *input > 0x7f || *input == 0xa || *input == 0xd) {
658  continue; /* not a valid quoted-pair, so skip it */
659  }
660  } else if ((*input != 0x9 && (unsigned char) *input < 0x20)
661  || *input == 0x7f) {
662  continue; /* skip this invalid character. */
663  }
664 
665  if (0 < outputsize) {
666  /* We still have room for the output display-name. */
667  *output++ = *input;
668  --outputsize;
669  }
670  }
671 
672  /* if this is successful, input should be at the ending quote */
673  if (*input != '"') {
674  ast_log(LOG_WARNING, "No ending quote for display-name was found\n");
675  *orig_output = '\0';
676  return orig_input;
677  }
678 
679  /* make sure input is past the last quote */
680  ++input;
681 
682  /* terminate output */
683  *output = '\0';
684  } else { /* either an addr-spec or tokenLWS-combo */
685  for (; *input; ++input) {
686  /* token or WSP (without LWS) */
687  if ((*input >= '0' && *input <= '9') || (*input >= 'A' && *input <= 'Z')
688  || (*input >= 'a' && *input <= 'z') || *input == '-' || *input == '.'
689  || *input == '!' || *input == '%' || *input == '*' || *input == '_'
690  || *input == '+' || *input == '`' || *input == '\'' || *input == '~'
691  || *input == 0x9 || *input == ' ') {
692  if (0 < outputsize) {
693  /* We still have room for the output display-name. */
694  *output++ = *input;
695  --outputsize;
696  }
697  } else if (*input == '<') { /* end of tokenLWS-combo */
698  /* we could assert that the previous char is LWS, but we don't care */
699  break;
700  } else if (*input == ':') {
701  /* This invalid character which indicates this is addr-spec rather than display-name. */
702  *orig_output = '\0';
703  return orig_input;
704  } else { /* else, invalid character we can skip. */
705  continue; /* skip this character */
706  }
707  }
708 
709  if (*input != '<') { /* if we never found the start of addr-spec then this is invalid */
710  *orig_output = '\0';
711  return orig_input;
712  }
713 
714  /* terminate output while trimming any trailing whitespace */
715  do {
716  *output-- = '\0';
717  } while (orig_output <= output && (*output == 0x9 || *output == ' '));
718  }
719 
720  return input;
721 }
#define LOG_WARNING
Definition: logger.h:144
static int input(yyscan_t yyscanner)
Definition: ast_expr2f.c:1575
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:97
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
int get_comma ( char *  in,
char **  out 
)

Definition at line 1334 of file reqresp_parser.c.

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

Referenced by parse_contact_header().

1335 {
1336  char *c;
1337  char *parse = in;
1338  if (out) {
1339  *out = in;
1340  }
1341 
1342  /* Skip any quoted text */
1343  while (*parse) {
1344  if ((c = strchr(parse, '"'))) {
1345  in = (char *)find_closing_quote((const char *)c + 1, NULL);
1346  if (!*in) {
1347  ast_log(LOG_WARNING, "No closing quote found in '%s'\n", c);
1348  return -1;
1349  } else {
1350  break;
1351  }
1352  } else {
1353  break;
1354  }
1355  parse++;
1356  }
1357  parse = in;
1358 
1359  /* Skip any userinfo components of a uri as they may contain commas */
1360  if ((c = strchr(parse,'@'))) {
1361  parse = c+1;
1362  }
1363  if ((out) && (c = strchr(parse,','))) {
1364  *c++ = '\0';
1365  *out = c;
1366  return 0;
1367  }
1368  return 1;
1369 }
#define LOG_WARNING
Definition: logger.h:144
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:4627
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1858
char* get_in_brackets ( char *  tmp)

Definition at line 1072 of file reqresp_parser.c.

References get_in_brackets_full().

Referenced by AST_TEST_DEFINE(), build_route(), 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(), register_verify(), reqprep(), sip_get_cc_information(), transmit_refer(), and transmit_state_notify().

1073 {
1074  char *out;
1075 
1076  if ((get_in_brackets_full(tmp, &out, NULL))) {
1077  return tmp;
1078  }
1079  return out;
1080 }
int get_in_brackets_full(char *tmp, char **out, char **residue)
int get_in_brackets_const ( const char *  src,
const char **  start,
int *  length 
)

Definition at line 951 of file reqresp_parser.c.

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

Referenced by build_route().

952 {
953  const char *parse = src;
954  const char *first_bracket;
955  const char *second_bracket;
956 
957  if (start == NULL) {
958  return -1;
959  }
960  if (length == NULL) {
961  return -1;
962  }
963  *start = NULL;
964  *length = -1;
965  if (ast_strlen_zero(src)) {
966  return 1;
967  }
968 
969  /*
970  * Skip any quoted text until we find the part in brackets.
971  * On any error give up and return -1
972  */
973  while ( (first_bracket = strchr(parse, '<')) ) {
974  const char *first_quote = strchr(parse, '"');
975  first_bracket++;
976  if (!first_quote || first_quote >= first_bracket) {
977  break; /* no need to look at quoted part */
978  }
979  /* the bracket is within quotes, so ignore it */
980  parse = find_closing_quote(first_quote + 1, NULL);
981  if (!*parse) {
982  ast_log(LOG_WARNING, "No closing quote found in '%s'\n", src);
983  return -1;
984  }
985  parse++;
986  }
987 
988  /* Require a first bracket. Unlike get_in_brackets_full, this procedure is passed a const,
989  * so it can expect a pointer to an original value */
990  if (!first_bracket) {
991  ast_log(LOG_WARNING, "No opening bracket found in '%s'\n", src);
992  return 1;
993  }
994 
995  if ((second_bracket = strchr(first_bracket, '>'))) {
996  *start = first_bracket;
997  *length = second_bracket - first_bracket;
998  return 0;
999  }
1000  ast_log(LOG_WARNING, "No closing bracket found in '%s'\n", src);
1001  return -1;
1002 }
#define LOG_WARNING
Definition: logger.h:144
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:4627
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1858
int get_in_brackets_full ( char *  tmp,
char **  out,
char **  residue 
)

Definition at line 1004 of file reqresp_parser.c.

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

Referenced by get_in_brackets(), and parse_name_andor_addr().

1005 {
1006  const char *parse = tmp;
1007  char *first_bracket;
1008  char *second_bracket;
1009 
1010  if (out) {
1011  *out = "";
1012  }
1013  if (residue) {
1014  *residue = "";
1015  }
1016 
1017  if (ast_strlen_zero(tmp)) {
1018  return 1;
1019  }
1020 
1021  /*
1022  * Skip any quoted text until we find the part in brackets.
1023  * On any error give up and return -1
1024  */
1025  while ( (first_bracket = strchr(parse, '<')) ) {
1026  char *first_quote = strchr(parse, '"');
1027  first_bracket++;
1028  if (!first_quote || first_quote >= first_bracket) {
1029  break; /* no need to look at quoted part */
1030  }
1031  /* the bracket is within quotes, so ignore it */
1032  parse = find_closing_quote(first_quote + 1, NULL);
1033  if (!*parse) {
1034  ast_log(LOG_WARNING, "No closing quote found in '%s'\n", tmp);
1035  return -1;
1036  }
1037  parse++;
1038  }
1039 
1040  /* If no first bracket then still look for a second bracket as some other parsing functions
1041  may overwrite first bracket with NULL when terminating a token based display-name. As this
1042  only affects token based display-names there is no danger of brackets being in quotes */
1043  if (first_bracket) {
1044  parse = first_bracket;
1045  } else {
1046  parse = tmp;
1047  }
1048 
1049  if ((second_bracket = strchr(parse, '>'))) {
1050  *second_bracket++ = '\0';
1051  if (out) {
1052  *out = (char *) parse;
1053  }
1054  if (residue) {
1055  *residue = second_bracket;
1056  }
1057  return 0;
1058  }
1059 
1060  if ((first_bracket)) {
1061  ast_log(LOG_WARNING, "No closing bracket found in '%s'\n", tmp);
1062  return -1;
1063  }
1064 
1065  if (out) {
1066  *out = tmp;
1067  }
1068 
1069  return 1;
1070 }
#define LOG_WARNING
Definition: logger.h:144
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:4627
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1858
int get_name_and_number ( const char *  hdr,
char **  name,
char **  number 
)

Definition at line 806 of file reqresp_parser.c.

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

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

807 {
808  char header[256];
809  char tmp_name[256];
810  char *tmp_number = NULL;
811  char *hostport = NULL;
812  char *dummy = NULL;
813 
814  if (!name || !number || ast_strlen_zero(hdr)) {
815  return -1;
816  }
817 
818  *number = NULL;
819  *name = NULL;
820  ast_copy_string(header, hdr, sizeof(header));
821 
822  /* strip the display-name portion off the beginning of the header. */
823  get_calleridname(header, tmp_name, sizeof(tmp_name));
824 
825  /* get uri within < > brackets */
826  tmp_number = get_in_brackets(header);
827 
828  /* parse out the number here */
829  if (parse_uri(tmp_number, "sip:,sips:", &tmp_number, &dummy, &hostport, NULL) || ast_strlen_zero(tmp_number)) {
830  ast_log(LOG_ERROR, "can not parse name and number from sip header.\n");
831  return -1;
832  }
833 
834  /* number is not option, and must be present at this point */
835  *number = ast_strdup(tmp_number);
837 
838  /* name is optional and may not be present at this point */
839  if (!ast_strlen_zero(tmp_name)) {
840  *name = ast_strdup(tmp_name);
841  }
842 
843  return 0;
844 }
#define ast_strdup(a)
Definition: astmm.h:109
void ast_uri_decode(char *s)
Decode URI, URN, URL (overwrite string)
Definition: utils.c:484
static void dummy(char *unused,...)
Definition: chan_unistim.c:188
Number structure.
Definition: app_followme.c:109
int parse_uri(char *uri, const char *scheme, char **user, char **pass, char **hostport, char **transport)
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
char * get_in_brackets(char *tmp)
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:155
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static const char name[]
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
int parse_contact_header ( char *  contactheader,
struct contactliststruct *  contactlist 
)

Definition at line 1371 of file reqresp_parser.c.

References ast_calloc, AST_LIST_HEAD_SET_NOLOCK, AST_LIST_INSERT_TAIL, get_comma(), last, parse_name_andor_addr(), and value.

Referenced by AST_TEST_DEFINE().

1372 {
1373  int res;
1374  int last;
1375  char *comma;
1376  char *residue;
1377  char *param;
1378  char *value;
1379  struct contact *split_contact = NULL;
1380 
1381  if (*contactheader == '*') {
1382  return 1;
1383  }
1384 
1385  split_contact = ast_calloc(1, sizeof(*split_contact));
1386 
1387  AST_LIST_HEAD_SET_NOLOCK(contactlist, split_contact);
1388  while ((last = get_comma(contactheader, &comma)) != -1) {
1389  res = parse_name_andor_addr(contactheader, "sip:,sips:",
1390  &split_contact->name, &split_contact->user,
1391  &split_contact->pass, &split_contact->hostport,
1392  &split_contact->params, &split_contact->headers,
1393  &residue);
1394  if (res == -1) {
1395  return res;
1396  }
1397 
1398  /* parse contact params */
1399  split_contact->expires = split_contact->q = "";
1400 
1401  while ((value = strchr(residue,'='))) {
1402  *value++ = '\0';
1403 
1404  param = residue;
1405  if ((residue = strchr(value,';'))) {
1406  *residue++ = '\0';
1407  } else {
1408  residue = "";
1409  }
1410 
1411  if (!strcmp(param,"expires")) {
1412  split_contact->expires = value;
1413  } else if (!strcmp(param,"q")) {
1414  split_contact->q = value;
1415  }
1416  }
1417 
1418  if (last) {
1419  return 0;
1420  }
1421  contactheader = comma;
1422 
1423  split_contact = ast_calloc(1, sizeof(*split_contact));
1424  AST_LIST_INSERT_TAIL(contactlist, split_contact, list);
1425  }
1426  return last;
1427 }
int value
Definition: syslog.c:39
struct sla_ringing_trunk * last
Definition: app_meetme.c:965
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
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)
int get_comma(char *in, char **out)
#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(a, b)
Definition: astmm.h:82
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 
)

Definition at line 1160 of file reqresp_parser.c.

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

Referenced by AST_TEST_DEFINE(), and parse_contact_header().

1164 {
1165  char buf[1024];
1166  char **residue2 = residue;
1167  char *orig_uri = uri;
1168  int ret;
1169 
1170  buf[0] = '\0';
1171  if (name) {
1172  uri = (char *) get_calleridname(uri, buf, sizeof(buf));
1173  }
1174  ret = get_in_brackets_full(uri, &uri, residue);
1175  if (ret == 0) {
1176  /*
1177  * The uri is in brackets so do not treat unknown trailing uri
1178  * parameters as potential message header parameters.
1179  */
1180  if (residue && **residue) {
1181  /* step over the first semicolon as per parse_uri_full residue */
1182  *residue = *residue + 1;
1183  }
1184  residue2 = NULL;
1185  }
1186 
1187  if (name) {
1188  if (buf[0]) {
1189  /*
1190  * There is always room at orig_uri for the display-name because
1191  * at least one character has always been removed. A '"' or '<'
1192  * has been removed.
1193  */
1194  strcpy(orig_uri, buf);
1195  *name = orig_uri;
1196  } else {
1197  *name = "";
1198  }
1199  }
1200 
1201  return parse_uri_full(uri, scheme, user, pass, hostport, params, headers, residue2);
1202 }
static char pass[512]
int get_in_brackets_full(char *tmp, char **out, char **residue)
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.
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[]
structure to hold users read from users.conf
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
optionlist
unsupportedout buffer (optional)
unsupportedout buffer length (optional)

Definition at line 1587 of file reqresp_parser.c.

References ARRAY_LEN, ast_copy_string(), ast_debug, ast_strdupa, ast_strip(), ast_strlen_zero(), FALSE, text, and TRUE.

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

1588 {
1589  char *next, *sep;
1590  char *temp;
1591  int i, found, supported;
1592  unsigned int profile = 0;
1593 
1594  char *out = unsupported;
1595  size_t outlen = unsupported_len;
1596  char *cur_out = out;
1597 
1598  if (ast_strlen_zero(options) )
1599  return 0;
1600 
1601  temp = ast_strdupa(options);
1602 
1603  ast_debug(3, "Begin: parsing SIP \"Supported: %s\"\n", options);
1604  for (next = temp; next; next = sep) {
1605  found = FALSE;
1606  supported = FALSE;
1607  if ((sep = strchr(next, ',')) != NULL) {
1608  *sep++ = '\0';
1609  }
1610 
1611  /* trim leading and trailing whitespace */
1612  next = ast_strip(next);
1613 
1614  if (ast_strlen_zero(next)) {
1615  continue; /* if there is a blank argument in there just skip it */
1616  }
1617 
1618  ast_debug(3, "Found SIP option: -%s-\n", next);
1619  for (i = 0; i < ARRAY_LEN(sip_options); i++) {
1620  if (!strcasecmp(next, sip_options[i].text)) {
1621  profile |= sip_options[i].id;
1622  if (sip_options[i].supported == SUPPORTED) {
1623  supported = TRUE;
1624  }
1625  found = TRUE;
1626  ast_debug(3, "Matched SIP option: %s\n", next);
1627  break;
1628  }
1629  }
1630 
1631  /* If option is not supported, add to unsupported out buffer */
1632  if (!supported && out && outlen) {
1633  size_t copylen = strlen(next);
1634  size_t cur_outlen = strlen(out);
1635  /* Check to see if there is enough room to store this option.
1636  * Copy length is string length plus 2 for the ',' and '\0' */
1637  if ((cur_outlen + copylen + 2) < outlen) {
1638  /* if this isn't the first item, add the ',' */
1639  if (cur_outlen) {
1640  *cur_out = ',';
1641  cur_out++;
1642  cur_outlen++;
1643  }
1644  ast_copy_string(cur_out, next, (outlen - cur_outlen));
1645  cur_out += copylen;
1646  }
1647  }
1648 
1649  if (!found) {
1650  profile |= SIP_OPT_UNKNOWN;
1651  if (!strncasecmp(next, "x-", 2))
1652  ast_debug(3, "Found private SIP option, not supported: %s\n", next);
1653  else
1654  ast_debug(3, "Found no match for SIP option: %s (Please file bug report!)\n", next);
1655  }
1656  }
1657 
1658  return profile;
1659 }
#define FALSE
Definition: app_minivm.c:506
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
char * text
Definition: app_queue.c:1091
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:155
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
#define TRUE
Definition: app_minivm.c:503
int parse_uri ( char *  uri,
const char *  scheme,
char **  user,
char **  pass,
char **  hostport,
char **  transport 
)

Definition at line 434 of file reqresp_parser.c.

References parse_uri_full().

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

435  {
436  int ret;
437  char *headers;
438  struct uriparams params;
439 
440  headers = NULL;
441  ret = parse_uri_full(uri, scheme, user, pass, hostport, &params, &headers, NULL);
442  if (transport) {
443  *transport=params.transport;
444  }
445  return ret;
446 }
static char pass[512]
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.
structure to hold users read from users.conf
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.

Definition at line 39 of file reqresp_parser.c.

References ast_debug, ast_strdupa, ast_strlen_zero(), strsep(), and value.

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

42 {
43  char *userinfo = NULL;
44  char *parameters = NULL;
45  char *endparams = NULL;
46  char *c = NULL;
47  int error = 0;
48 
49  /*
50  * Initialize requested strings - some functions don't care if parse_uri fails
51  * and will attempt to use string pointers passed into parse_uri even after a
52  * parse_uri failure
53  */
54  if (user) {
55  *user = "";
56  }
57  if (pass) {
58  *pass = "";
59  }
60  if (hostport) {
61  *hostport = "";
62  }
63  if (headers) {
64  *headers = "";
65  }
66  if (residue) {
67  *residue = "";
68  }
69 
70  /* check for valid input */
71  if (ast_strlen_zero(uri)) {
72  return -1;
73  }
74 
75  if (scheme) {
76  int l;
77  char *scheme2 = ast_strdupa(scheme);
78  char *cur = strsep(&scheme2, ",");
79  for (; !ast_strlen_zero(cur); cur = strsep(&scheme2, ",")) {
80  l = strlen(cur);
81  if (!strncasecmp(uri, cur, l)) {
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 {
97  char *dom = "";
98  if ((c = strchr(uri, '@'))) {
99  *c++ = '\0';
100  dom = c;
101  userinfo = uri;
102  uri = c; /* userinfo can contain ? and ; chars so step forward before looking for params and headers */
103  } else {
104  /* domain-only URI, according to the SIP RFC. */
105  dom = uri;
106  userinfo = "";
107  }
108 
109  *hostport = dom;
110  }
111 
112  if (pass && (c = strchr(userinfo, ':'))) { /* user:password */
113  *c++ = '\0';
114  *pass = c;
115  } else if (pass) {
116  *pass = "";
117  }
118 
119  if (user) {
120  *user = userinfo;
121  }
122 
123  parameters = uri;
124  /* strip [?headers] from end of uri - even if no header pointer exists*/
125  if ((c = strrchr(uri, '?'))) {
126  *c++ = '\0';
127  uri = c;
128  if (headers) {
129  *headers = c;
130  }
131  if ((c = strrchr(uri, ';'))) {
132  *c++ = '\0';
133  } else {
134  c = strrchr(uri, '\0');
135  }
136  uri = c; /* residue */
137 
138 
139  } else if (headers) {
140  *headers = "";
141  }
142 
143  /* parse parameters */
144  endparams = strchr(parameters,'\0');
145  if ((c = strchr(parameters, ';'))) {
146  *c++ = '\0';
147  parameters = c;
148  } else {
149  parameters = endparams;
150  }
151 
152  if (params) {
153  char *rem = parameters; /* unparsed or unrecognised remainder */
154  char *label;
155  char *value;
156  int lr = 0;
157 
158  params->transport = "";
159  params->user = "";
160  params->method = "";
161  params->ttl = "";
162  params->maddr = "";
163  params->lr = 0;
164 
165  rem = parameters;
166 
167  while ((value = strchr(parameters, '=')) || (lr = !strncmp(parameters, "lr", 2))) {
168  /* The while condition will not continue evaluation to set lr if it matches "lr=" */
169  if (lr) {
170  value = parameters;
171  } else {
172  *value++ = '\0';
173  }
174  label = parameters;
175  if ((c = strchr(value, ';'))) {
176  *c++ = '\0';
177  parameters = c;
178  } else {
179  parameters = endparams;
180  }
181 
182  if (!strcmp(label, "transport")) {
183  params->transport = value;
184  rem = parameters;
185  } else if (!strcmp(label, "user")) {
186  params->user = value;
187  rem = parameters;
188  } else if (!strcmp(label, "method")) {
189  params->method = value;
190  rem = parameters;
191  } else if (!strcmp(label, "ttl")) {
192  params->ttl = value;
193  rem = parameters;
194  } else if (!strcmp(label, "maddr")) {
195  params->maddr = value;
196  rem = parameters;
197  /* 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 */
198  } else if ((!strcmp(label, "lr") && strcmp(value, "no") && strcmp(value, "off") && strcmp(value, "0") && strcmp(value, "")) || ((lr) && strcmp(value, "lr"))) {
199  params->lr = 1;
200  rem = parameters;
201  } else {
202  value--;
203  *value = '=';
204  if (c) {
205  c--;
206  *c = ';';
207  }
208  }
209  }
210  if (rem > uri) { /* no headers */
211  uri = rem;
212  }
213 
214  }
215 
216  if (residue) {
217  *residue = uri;
218  }
219 
220  return error;
221 }
static char pass[512]
char * strsep(char **str, const char *delims)
int value
Definition: syslog.c:39
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
structure to hold users read from users.conf
struct sip_via* parse_via ( const char *  header)

Definition at line 2279 of file reqresp_parser.c.

References ast_calloc, ast_log(), ast_skip_blanks(), ast_strdup, ast_strlen_zero(), free_via(), LOG_ERROR, and strsep().

Referenced by AST_TEST_DEFINE(), find_call(), process_via(), and sip_alloc().

2280 {
2281  struct sip_via *v = ast_calloc(1, sizeof(*v));
2282  char *via, *parm;
2283 
2284  if (!v) {
2285  return NULL;
2286  }
2287 
2288  v->via = ast_strdup(header);
2289  v->ttl = 1;
2290 
2291  via = v->via;
2292 
2293  if (ast_strlen_zero(via)) {
2294  ast_log(LOG_ERROR, "received request without a Via header\n");
2295  free_via(v);
2296  return NULL;
2297  }
2298 
2299  /* seperate the first via-parm */
2300  via = strsep(&via, ",");
2301 
2302  /* chop off sent-protocol */
2303  v->protocol = strsep(&via, " \t\r\n");
2304  if (ast_strlen_zero(v->protocol)) {
2305  ast_log(LOG_ERROR, "missing sent-protocol in Via header\n");
2306  free_via(v);
2307  return NULL;
2308  }
2309  v->protocol = ast_skip_blanks(v->protocol);
2310 
2311  if (via) {
2312  via = ast_skip_blanks(via);
2313  }
2314 
2315  /* chop off sent-by */
2316  v->sent_by = strsep(&via, "; \t\r\n");
2317  if (ast_strlen_zero(v->sent_by)) {
2318  ast_log(LOG_ERROR, "missing sent-by in Via header\n");
2319  free_via(v);
2320  return NULL;
2321  }
2322  v->sent_by = ast_skip_blanks(v->sent_by);
2323 
2324  /* store the port, we have to handle ipv6 addresses containing ':'
2325  * characters gracefully */
2326  if (((parm = strchr(v->sent_by, ']')) && *(++parm) == ':') || (parm = strchr(v->sent_by, ':'))) {
2327  char *endptr;
2328 
2329  v->port = strtol(++parm, &endptr, 10);
2330  }
2331 
2332  /* evaluate any via-parms */
2333  while ((parm = strsep(&via, "; \t\r\n"))) {
2334  char *c;
2335  if ((c = strstr(parm, "maddr="))) {
2336  v->maddr = ast_skip_blanks(c + sizeof("maddr=") - 1);
2337  } else if ((c = strstr(parm, "branch="))) {
2338  v->branch = ast_skip_blanks(c + sizeof("branch=") - 1);
2339  } else if ((c = strstr(parm, "ttl="))) {
2340  char *endptr;
2341  c = ast_skip_blanks(c + sizeof("ttl=") - 1);
2342  v->ttl = strtol(c, &endptr, 10);
2343 
2344  /* make sure we got a valid ttl value */
2345  if (c == endptr) {
2346  v->ttl = 1;
2347  }
2348  }
2349  }
2350 
2351  return v;
2352 }
char * strsep(char **str, const char *delims)
#define ast_strdup(a)
Definition: astmm.h:109
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
void free_via(struct sip_via *v)
#define LOG_ERROR
Definition: logger.h:155
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:97
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ast_calloc(a, b)
Definition: astmm.h:82
void sip_reqresp_parser_exit ( void  )

Definition at line 2570 of file reqresp_parser.c.

Referenced by unload_module().

2571 {
2572 #ifdef HAVE_XLOCALE_H
2573  if (c_locale) {
2574  freelocale(c_locale);
2575  c_locale = NULL;
2576  }
2577 #endif
2578 }
locale_t c_locale
int sip_reqresp_parser_init ( void  )

Definition at line 2559 of file reqresp_parser.c.

Referenced by load_module().

2560 {
2561 #ifdef HAVE_XLOCALE_H
2562  c_locale = newlocale(LC_CTYPE_MASK, "C", NULL);
2563  if (!c_locale) {
2564  return -1;
2565  }
2566 #endif
2567  return 0;
2568 }
locale_t c_locale
void sip_request_parser_register_tests ( void  )

Definition at line 2532 of file reqresp_parser.c.

References AST_TEST_REGISTER.

Referenced by sip_register_tests().

2533 {
2534  AST_TEST_REGISTER(get_calleridname_test);
2535  AST_TEST_REGISTER(sip_parse_uri_test);
2536  AST_TEST_REGISTER(get_in_brackets_test);
2537  AST_TEST_REGISTER(get_name_and_number_test);
2538  AST_TEST_REGISTER(sip_parse_uri_full_test);
2539  AST_TEST_REGISTER(parse_name_andor_addr_test);
2540  AST_TEST_REGISTER(parse_contact_header_test);
2541  AST_TEST_REGISTER(sip_parse_options_test);
2542  AST_TEST_REGISTER(sip_uri_cmp_test);
2543  AST_TEST_REGISTER(parse_via_test);
2544 }
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
void sip_request_parser_unregister_tests ( void  )

Definition at line 2545 of file reqresp_parser.c.

References AST_TEST_UNREGISTER.

Referenced by sip_unregister_tests().

2546 {
2547  AST_TEST_UNREGISTER(sip_parse_uri_test);
2548  AST_TEST_UNREGISTER(get_calleridname_test);
2549  AST_TEST_UNREGISTER(get_in_brackets_test);
2550  AST_TEST_UNREGISTER(get_name_and_number_test);
2551  AST_TEST_UNREGISTER(sip_parse_uri_full_test);
2552  AST_TEST_UNREGISTER(parse_name_andor_addr_test);
2553  AST_TEST_UNREGISTER(parse_contact_header_test);
2554  AST_TEST_UNREGISTER(sip_parse_options_test);
2555  AST_TEST_UNREGISTER(sip_uri_cmp_test);
2556  AST_TEST_UNREGISTER(parse_via_test);
2557 }
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
int sip_uri_cmp ( const char *  input1,
const char *  input2 
)

Definition at line 2045 of file reqresp_parser.c.

References ast_strdupa, ast_strlen_zero(), ast_uri_decode(), 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().

2046 {
2047  char *uri1;
2048  char *uri2;
2049  char *uri_scheme1;
2050  char *uri_scheme2;
2051  char *host1;
2052  char *host2;
2053  char *params1;
2054  char *params2;
2055  char *headers1;
2056  char *headers2;
2057 
2058  /* XXX It would be really nice if we could just use parse_uri_full() here
2059  * to separate the components of the URI, but unfortunately it is written
2060  * in a way that can cause URI parameters to be discarded.
2061  */
2062 
2063  if (!input1 || !input2) {
2064  return 1;
2065  }
2066 
2067  uri1 = ast_strdupa(input1);
2068  uri2 = ast_strdupa(input2);
2069 
2070  ast_uri_decode(uri1);
2071  ast_uri_decode(uri2);
2072 
2073  uri_scheme1 = strsep(&uri1, ":");
2074  uri_scheme2 = strsep(&uri2, ":");
2075 
2076  if (strcmp(uri_scheme1, uri_scheme2)) {
2077  return 1;
2078  }
2079 
2080  /* This function is tailored for SIP and SIPS URIs. There's no
2081  * need to check uri_scheme2 since we have determined uri_scheme1
2082  * and uri_scheme2 are equivalent already.
2083  */
2084  if (strcmp(uri_scheme1, "sip") && strcmp(uri_scheme1, "sips")) {
2085  return 1;
2086  }
2087 
2088  if (ast_strlen_zero(uri1) || ast_strlen_zero(uri2)) {
2089  return 1;
2090  }
2091 
2092  if ((host1 = strchr(uri1, '@'))) {
2093  *host1++ = '\0';
2094  }
2095  if ((host2 = strchr(uri2, '@'))) {
2096  *host2++ = '\0';
2097  }
2098 
2099  /* Check for mismatched username and passwords. This is the
2100  * only case-sensitive comparison of a SIP URI
2101  */
2102  if ((host1 && !host2) ||
2103  (host2 && !host1) ||
2104  (host1 && host2 && strcmp(uri1, uri2))) {
2105  return 1;
2106  }
2107 
2108  if (!host1) {
2109  host1 = uri1;
2110  }
2111  if (!host2) {
2112  host2 = uri2;
2113  }
2114 
2115  /* Strip off the parameters and headers so we can compare
2116  * host and port
2117  */
2118 
2119  if ((params1 = strchr(host1, ';'))) {
2120  *params1++ = '\0';
2121  }
2122  if ((params2 = strchr(host2, ';'))) {
2123  *params2++ = '\0';
2124  }
2125 
2126  /* Headers come after parameters, but there may be headers without
2127  * parameters, thus the S_OR
2128  */
2129  if ((headers1 = strchr(S_OR(params1, host1), '?'))) {
2130  *headers1++ = '\0';
2131  }
2132  if ((headers2 = strchr(S_OR(params2, host2), '?'))) {
2133  *headers2++ = '\0';
2134  }
2135 
2136  if (sip_uri_domain_cmp(host1, host2)) {
2137  return 1;
2138  }
2139 
2140  /* Headers have easier rules to follow, so do those first */
2141  if (sip_uri_headers_cmp(headers1, headers2)) {
2142  return 1;
2143  }
2144 
2145  /* And now the parameters. Ugh */
2146  return sip_uri_params_cmp(params1, params2);
2147 }
char * strsep(char **str, const char *delims)
void ast_uri_decode(char *s)
Decode URI, URN, URL (overwrite string)
Definition: utils.c:484
static int sip_uri_domain_cmp(const char *host1, const char *host2)
Compare domain sections of SIP URIs.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
static int sip_uri_headers_cmp(const char *input1, const char *input2)
helper routine for sip_uri_cmp to compare URI headers
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:77
static int sip_uri_params_cmp(const char *input1, const char *input2)
helper routine for sip_uri_cmp to compare URI parameters
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 2007 of file reqresp_parser.c.

References ast_sockaddr_cmp(), and ast_sockaddr_parse().

Referenced by sip_uri_cmp().

2008 {
2009  struct ast_sockaddr addr1;
2010  struct ast_sockaddr addr2;
2011  int addr1_parsed;
2012  int addr2_parsed;
2013 
2014  addr1_parsed = ast_sockaddr_parse(&addr1, host1, 0);
2015  addr2_parsed = ast_sockaddr_parse(&addr2, host2, 0);
2016 
2017  if (addr1_parsed != addr2_parsed) {
2018  /* One domain was an IP address and the other had
2019  * a host name. FAIL!
2020  */
2021  return 1;
2022  }
2023 
2024  /* Both are host names. A string comparison will work
2025  * perfectly here. Specifying the "C" locale ensures that
2026  * The LC_CTYPE conventions use those defined in ANSI C,
2027  * i.e. ASCII.
2028  */
2029  if (!addr1_parsed) {
2030 #ifdef HAVE_XLOCALE_H
2031  if(!c_locale) {
2032  return strcasecmp(host1, host2);
2033  } else {
2034  return strcasecmp_l(host1, host2, c_locale);
2035  }
2036 #else
2037  return strcasecmp(host1, host2);
2038 #endif
2039  }
2040 
2041  /* Both contain IP addresses */
2042  return ast_sockaddr_cmp(&addr1, &addr2);
2043 }
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
Definition: netsock2.c:198
int ast_sockaddr_cmp(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
Compares two ast_sockaddr structures.
Definition: netsock2.c:300
Socket address structure.
Definition: netsock2.h:63
locale_t c_locale
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 1942 of file reqresp_parser.c.

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

Referenced by sip_uri_cmp().

1943 {
1944  char *headers1 = NULL;
1945  char *headers2 = NULL;
1946  int zerolength1 = 0;
1947  int zerolength2 = 0;
1948  int different = 0;
1949  char *header1;
1950 
1951  if (ast_strlen_zero(input1)) {
1952  zerolength1 = 1;
1953  } else {
1954  headers1 = ast_strdupa(input1);
1955  }
1956 
1957  if (ast_strlen_zero(input2)) {
1958  zerolength2 = 1;
1959  } else {
1960  headers2 = ast_strdupa(input2);
1961  }
1962 
1963  /* If one URI contains no headers and the other
1964  * does, then they cannot possibly match
1965  */
1966  if (zerolength1 != zerolength2) {
1967  return 1;
1968  }
1969 
1970  if (zerolength1 && zerolength2)
1971  return 0;
1972 
1973  /* At this point, we can definitively state that both inputs are
1974  * not zero-length. First, one more optimization. If the length
1975  * of the headers is not equal, then we definitely have no match
1976  */
1977  if (strlen(headers1) != strlen(headers2)) {
1978  return 1;
1979  }
1980 
1981  for (header1 = strsep(&headers1, "&"); header1; header1 = strsep(&headers1, "&")) {
1982  if (!strcasestr(headers2, header1)) {
1983  different = 1;
1984  break;
1985  }
1986  }
1987 
1988  return different;
1989 }
char * strsep(char **str, const char *delims)
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
char * strcasestr(const char *, const char *)
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 1816 of file reqresp_parser.c.

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

Referenced by sip_uri_cmp().

1817 {
1818  char *params1 = NULL;
1819  char *params2 = NULL;
1820  char *pos1;
1821  char *pos2;
1822  int zerolength1 = 0;
1823  int zerolength2 = 0;
1824  int maddrmatch = 0;
1825  int ttlmatch = 0;
1826  int usermatch = 0;
1827  int methodmatch = 0;
1828 
1829  if (ast_strlen_zero(input1)) {
1830  zerolength1 = 1;
1831  } else {
1832  params1 = ast_strdupa(input1);
1833  }
1834  if (ast_strlen_zero(input2)) {
1835  zerolength2 = 1;
1836  } else {
1837  params2 = ast_strdupa(input2);
1838  }
1839 
1840  /* Quick optimization. If both params are zero-length, then
1841  * they match
1842  */
1843  if (zerolength1 && zerolength2) {
1844  return 0;
1845  }
1846 
1847  for (pos1 = strsep(&params1, ";"); pos1; pos1 = strsep(&params1, ";")) {
1848  char *value1 = pos1;
1849  char *name1 = strsep(&value1, "=");
1850  char *params2dup = NULL;
1851  int matched = 0;
1852  if (!value1) {
1853  value1 = "";
1854  }
1855  /* Checkpoint reached. We have the name and value parsed for param1
1856  * We have to duplicate params2 each time through this loop
1857  * or else the inner loop below will not work properly.
1858  */
1859  if (!zerolength2) {
1860  params2dup = ast_strdupa(params2);
1861  }
1862  for (pos2 = strsep(&params2dup, ";"); pos2; pos2 = strsep(&params2dup, ";")) {
1863  char *name2 = pos2;
1864  char *value2 = strchr(pos2, '=');
1865  if (!value2) {
1866  value2 = "";
1867  } else {
1868  *value2++ = '\0';
1869  }
1870  if (!strcasecmp(name1, name2)) {
1871  if (strcasecmp(value1, value2)) {
1872  goto fail;
1873  } else {
1874  matched = 1;
1875  break;
1876  }
1877  }
1878  }
1879  /* Check to see if the parameter is one of the 'must-match' parameters */
1880  if (!strcasecmp(name1, "maddr")) {
1881  if (matched) {
1882  maddrmatch = 1;
1883  } else {
1884  goto fail;
1885  }
1886  } else if (!strcasecmp(name1, "ttl")) {
1887  if (matched) {
1888  ttlmatch = 1;
1889  } else {
1890  goto fail;
1891  }
1892  } else if (!strcasecmp(name1, "user")) {
1893  if (matched) {
1894  usermatch = 1;
1895  } else {
1896  goto fail;
1897  }
1898  } else if (!strcasecmp(name1, "method")) {
1899  if (matched) {
1900  methodmatch = 1;
1901  } else {
1902  goto fail;
1903  }
1904  }
1905  }
1906 
1907  /* We've made it out of that horrible O(m*n) construct and there are no
1908  * failures yet. We're not done yet, though, because params2 could have
1909  * an maddr, ttl, user, or method header and params1 did not.
1910  */
1911  for (pos2 = strsep(&params2, ";"); pos2; pos2 = strsep(&params2, ";")) {
1912  char *value2 = pos2;
1913  char *name2 = strsep(&value2, "=");
1914  if (!value2) {
1915  value2 = "";
1916  }
1917  if ((!strcasecmp(name2, "maddr") && !maddrmatch) ||
1918  (!strcasecmp(name2, "ttl") && !ttlmatch) ||
1919  (!strcasecmp(name2, "user") && !usermatch) ||
1920  (!strcasecmp(name2, "method") && !methodmatch)) {
1921  goto fail;
1922  }
1923  }
1924  return 0;
1925 
1926 fail:
1927  return 1;
1928 }
char * strsep(char **str, const char *delims)
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663

Variable Documentation

locale_t c_locale

Definition at line 35 of file reqresp_parser.c.