Asterisk - The Open Source Telephony Project  GIT-master-a24979a
Data Structures | Functions
reqresp_parser.h File Reference

sip request response parser header file More...

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  contact
 
struct  uriparams
 uri parameters More...
 

Functions

 AST_LIST_HEAD_NOLOCK (contactliststruct, contact)
 
void free_via (struct sip_via *v)
 Free parsed Via data. More...
 
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 *parse, char **out)
 Parse all contact header contacts. More...
 
char * get_in_brackets (char *tmp)
 Pick out text in brackets from character string. More...
 
int get_in_brackets_const (const char *src, const char **start, int *length)
 Get text in brackets on a const without copy. More...
 
int get_in_brackets_full (char *tmp, char **out, char **residue)
 Get text in brackets and any trailing residue. More...
 
int get_name_and_number (const char *hdr, char **name, char **number)
 Get name and number from sip header. More...
 
int parse_contact_header (char *contactheader, struct contactliststruct *contactlist)
 
int parse_name_andor_addr (char *uri, const char *scheme, char **name, char **user, char **pass, char **domain, struct uriparams *params, char **headers, char **residue)
 Parse the ABNF structure name-andor-addr = name-addr / addr-spec into its components and return any trailing message-header parameters. More...
 
unsigned int parse_sip_options (const char *options, char *unsupported, size_t unsupported_len)
 Parse supported header in incoming packet. More...
 
int parse_uri (char *uri, const char *scheme, char **ret_name, char **pass, char **hostport, char **transport)
 parses a URI in its components. More...
 
int parse_uri_full (char *uri, const char *scheme, char **user, char **pass, char **hostport, struct uriparams *params, char **headers, char **residue)
 parses a URI in to all of its components and any trailing residue More...
 
struct sip_viaparse_via (const char *header)
 Parse a Via header. More...
 
void sip_reqresp_parser_exit (void)
 Free resources used by request and response parser. More...
 
int sip_reqresp_parser_init (void)
 initialize request and response parser data More...
 
void sip_request_parser_register_tests (void)
 register request parsing tests More...
 
void sip_request_parser_unregister_tests (void)
 unregister request parsing tests More...
 
int sip_uri_cmp (const char *input1, const char *input2)
 Compare two URIs as described in RFC 3261 Section 19.1.4. More...
 

Detailed Description

sip request response parser header file

Definition in file reqresp_parser.h.

Function Documentation

◆ AST_LIST_HEAD_NOLOCK()

AST_LIST_HEAD_NOLOCK ( contactliststruct  ,
contact   
)

◆ free_via()

void free_via ( struct sip_via v)

Free parsed Via data.

Definition at line 2375 of file reqresp_parser.c.

2376 {
2377  if (!v) {
2378  return;
2379  }
2380 
2381  ast_free(v->via);
2382  ast_free(v);
2383 }
#define ast_free(a)
Definition: astmm.h:180
char * via
Definition: sip.h:874

References ast_free, and sip_via::via.

Referenced by __find_call(), __sip_alloc(), match_req_to_dialog(), and parse_via().

◆ get_calleridname()

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

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

Returns
input string pointer placed after display-name field if possible

Definition at line 695 of file reqresp_parser.c.

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

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

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

◆ get_comma()

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

Parse all contact header contacts.

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

Definition at line 1438 of file reqresp_parser.c.

1439 {
1440  char *c;
1441  char *parse = in;
1442  if (out) {
1443  *out = in;
1444  }
1445 
1446  /* Skip any quoted text */
1447  while (*parse) {
1448  if ((c = strchr(parse, '"'))) {
1449  in = (char *)find_closing_quote((const char *)c + 1, NULL);
1450  if (!*in) {
1451  ast_log(LOG_WARNING, "No closing quote found in '%s'\n", c);
1452  return -1;
1453  } else {
1454  break;
1455  }
1456  } else {
1457  break;
1458  }
1459  parse++;
1460  }
1461  parse = in;
1462 
1463  /* Skip any userinfo components of a uri as they may contain commas */
1464  if ((c = strchr(parse,'@'))) {
1465  parse = c+1;
1466  }
1467  if ((out) && (c = strchr(parse,','))) {
1468  *c++ = '\0';
1469  *out = c;
1470  return 0;
1471  }
1472  return 1;
1473 }
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1844
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:5085
#define NULL
Definition: resample.c:96
static struct test_val c
FILE * out
Definition: utils/frame.c:33
FILE * in
Definition: utils/frame.c:33

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

Referenced by parse_contact_header().

◆ get_in_brackets()

char* get_in_brackets ( char *  tmp)

Pick out text in brackets from character string.

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

Examples:

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

Definition at line 1173 of file reqresp_parser.c.

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

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

Referenced by determine_sip_publish_type(), extract_uri(), get_also_info(), get_destination(), get_domain(), get_name_and_number(), get_pai(), get_refer_info(), handle_cc_notify(), parse_moved_contact(), parse_ok_contact(), receive_message(), reqprep(), sip_get_cc_information(), transmit_refer(), transmit_state_notify(), uac_sips_contact(), and uas_sips_contact().

◆ get_in_brackets_const()

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

Get text in brackets on a const without copy.

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

Definition at line 1052 of file reqresp_parser.c.

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

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

Referenced by build_route(), and sip_route_process_header().

◆ get_in_brackets_full()

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

Get text in brackets and any trailing residue.

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

Definition at line 1105 of file reqresp_parser.c.

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

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

Referenced by get_in_brackets(), and parse_name_andor_addr().

◆ get_name_and_number()

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

Get name and number from sip header.

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

Definition at line 905 of file reqresp_parser.c.

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

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

Referenced by change_redirecting_information(), and get_pai().

◆ parse_contact_header()

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

Definition at line 1475 of file reqresp_parser.c.

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

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

◆ parse_name_andor_addr()

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

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

Return values
0success
-1failure

Definition at line 1262 of file reqresp_parser.c.

1266 {
1267  char buf[1024];
1268  char **residue2 = residue;
1269  char *orig_uri = uri;
1270  int ret;
1271 
1272  buf[0] = '\0';
1273  if (name) {
1274  uri = (char *) get_calleridname(uri, buf, sizeof(buf));
1275  }
1276  ret = get_in_brackets_full(uri, &uri, residue);
1277  if (ret == 0) {
1278  /*
1279  * The uri is in brackets so do not treat unknown trailing uri
1280  * parameters as potential message header parameters.
1281  */
1282  if (residue && **residue) {
1283  /* step over the first semicolon as per parse_uri_full residue */
1284  *residue = *residue + 1;
1285  }
1286  residue2 = NULL;
1287  }
1288 
1289  if (name) {
1290  if (buf[0]) {
1291  /*
1292  * There is always room at orig_uri for the display-name because
1293  * at least one character has always been removed. A '"' or '<'
1294  * has been removed.
1295  */
1296  strcpy(orig_uri, buf);
1297  *name = orig_uri;
1298  } else {
1299  *name = "";
1300  }
1301  }
1302 
1303  return parse_uri_full(uri, scheme, user, pass, hostport, params, headers, residue2);
1304 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
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.
static char pass[512]
structure to hold users read from users.conf

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

Referenced by parse_contact_header().

◆ parse_sip_options()

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

Parse supported header in incoming packet.

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

Parameters
optionslist
[in,out]unsupportedbuffer (optional)
[in,out]unsupported_lenbuffer length
Note
Because this function can be called multiple times, it will append whatever options are specified in options to unsupported. Callers of this function should make sure the unsupported buffer is clear before calling this function.

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.

Definition at line 1689 of file reqresp_parser.c.

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

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

Referenced by handle_request_bye(), and handle_request_invite().

◆ parse_uri()

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

parses a URI in its components.

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

Definition at line 517 of file reqresp_parser.c.

518  {
519  int ret;
520  char *headers;
521  struct uriparams params;
522 
523  headers = NULL;
524  ret = parse_uri_full(uri, scheme, user, pass, hostport, &params, &headers, NULL);
525  if (transport) {
526  *transport=params.transport;
527  }
528  return ret;
529 }
uri parameters
char * transport

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

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

◆ parse_uri_full()

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

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

Return values
0on success
-1on error.

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

Definition at line 37 of file reqresp_parser.c.

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

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

Referenced by parse_name_andor_addr(), and parse_uri().

◆ parse_via()

struct sip_via* parse_via ( const char *  header)

Parse a Via header.

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

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

Definition at line 2385 of file reqresp_parser.c.

2386 {
2387  struct sip_via *v = ast_calloc(1, sizeof(*v));
2388  char *via, *parm;
2389 
2390  if (!v) {
2391  return NULL;
2392  }
2393 
2394  v->via = ast_strdup(header);
2395  v->ttl = 1;
2396 
2397  via = v->via;
2398 
2399  if (ast_strlen_zero(via)) {
2400  ast_log(LOG_ERROR, "received request without a Via header\n");
2401  free_via(v);
2402  return NULL;
2403  }
2404 
2405  /* seperate the first via-parm */
2406  via = strsep(&via, ",");
2407 
2408  /* chop off sent-protocol */
2409  v->protocol = strsep(&via, " \t\r\n");
2410  if (ast_strlen_zero(v->protocol)) {
2411  ast_log(LOG_ERROR, "missing sent-protocol in Via header\n");
2412  free_via(v);
2413  return NULL;
2414  }
2416 
2417  if (via) {
2418  via = ast_skip_blanks(via);
2419  }
2420 
2421  /* chop off sent-by */
2422  v->sent_by = strsep(&via, "; \t\r\n");
2423  if (ast_strlen_zero(v->sent_by)) {
2424  ast_log(LOG_ERROR, "missing sent-by in Via header\n");
2425  free_via(v);
2426  return NULL;
2427  }
2428  v->sent_by = ast_skip_blanks(v->sent_by);
2429 
2430  /* store the port, we have to handle ipv6 addresses containing ':'
2431  * characters gracefully */
2432  if (((parm = strchr(v->sent_by, ']')) && *(++parm) == ':') || (!(parm = strchr(v->sent_by, ']')) && (parm = strchr(v->sent_by, ':')))) {
2433  char *endptr;
2434 
2435  v->port = strtol(++parm, &endptr, 10);
2436  }
2437 
2438  /* evaluate any via-parms */
2439  while ((parm = strsep(&via, "; \t\r\n"))) {
2440  char *c;
2441  if ((c = strstr(parm, "maddr="))) {
2442  v->maddr = ast_skip_blanks(c + sizeof("maddr=") - 1);
2443  } else if ((c = strstr(parm, "branch="))) {
2444  v->branch = ast_skip_blanks(c + sizeof("branch=") - 1);
2445  } else if ((c = strstr(parm, "ttl="))) {
2446  char *endptr;
2447  c = ast_skip_blanks(c + sizeof("ttl=") - 1);
2448  v->ttl = strtol(c, &endptr, 10);
2449 
2450  /* make sure we got a valid ttl value */
2451  if (c == endptr) {
2452  v->ttl = 1;
2453  }
2454  }
2455  }
2456 
2457  return v;
2458 }
void free_via(struct sip_via *v)
Free parsed Via data.
Structure to store Via information.
Definition: sip.h:873
unsigned char ttl
Definition: sip.h:880
const char * branch
Definition: sip.h:877
const char * sent_by
Definition: sip.h:876
const char * protocol
Definition: sip.h:875
unsigned int port
Definition: sip.h:879
const char * maddr
Definition: sip.h:878

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

Referenced by __find_call(), __sip_alloc(), and match_req_to_dialog().

◆ sip_reqresp_parser_exit()

void sip_reqresp_parser_exit ( void  )

Free resources used by request and response parser.

Definition at line 2678 of file reqresp_parser.c.

2679 {
2680 #ifdef HAVE_XLOCALE_H
2681  if (c_locale) {
2682  freelocale(c_locale);
2683  c_locale = NULL;
2684  }
2685 #endif
2686 }

References NULL.

◆ sip_reqresp_parser_init()

int sip_reqresp_parser_init ( void  )

initialize request and response parser data

Return values
0Success
-1Failure

Definition at line 2667 of file reqresp_parser.c.

2668 {
2669 #ifdef HAVE_XLOCALE_H
2670  c_locale = newlocale(LC_CTYPE_MASK, "C", NULL);
2671  if (!c_locale) {
2672  return -1;
2673  }
2674 #endif
2675  return 0;
2676 }

References NULL.

Referenced by load_module().

◆ sip_request_parser_register_tests()

void sip_request_parser_register_tests ( void  )

register request parsing tests

Definition at line 2640 of file reqresp_parser.c.

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

References AST_TEST_REGISTER.

Referenced by sip_register_tests().

◆ sip_request_parser_unregister_tests()

void sip_request_parser_unregister_tests ( void  )

unregister request parsing tests

Definition at line 2653 of file reqresp_parser.c.

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

References AST_TEST_UNREGISTER.

◆ sip_uri_cmp()

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

Compare two URIs as described in RFC 3261 Section 19.1.4.

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

Definition at line 2149 of file reqresp_parser.c.

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

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

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