msg_parser_util.c

来自「Sofia SIP is an open-source SIP User-Age」· C语言 代码 · 共 1,997 行 · 第 1/4 页

C
1,997
字号
  char *end = b + bsiz, *b0 = b;  msg_param_t p;  if (pparams)     for (i = 0; (p = pparams[i]); i++) {      if (p[0]) {	MSG_CHAR_E(b, end, ';');	MSG_STRING_E(b, end, p);      }    }  return b - b0;}/** Duplicate a parameter list */char *msg_params_dup(msg_param_t const **d, msg_param_t const s[],		     char *b, isize_t xtra){  char *end = b + xtra;  char **pp;  int i;  isize_t n;  n = msg_params_count(s);  if (n == 0) {    *d = NULL;    return b;  }  MSG_STRUCT_ALIGN(b);  pp = (char **)b;  b += sizeof(*pp) * MSG_PARAMS_NUM(n + 1);  for (i = 0; s[i]; i++) {    MSG_STRING_DUP(b, pp[i], s[i]);  }  pp[i] = NULL;   assert(b <= end); (void)end;   *d = (msg_param_t const *)pp;  return b;} /** Parse a comma-separated list. * * Parses a comma-separated list. The parsed string is passed in @a *ss, * which is updated to point to the first non-linear-whitespace character * after the list. The function modifies the string as it parses it. * * A pointer to the resulting list is returned in @a *retval. If there * already is a list in @a *retval, new items are appended. Empty list items * are ignored, and are not included in the list. * * The function can be passed an optional scanning function. The scanning * function scans for a legitimate list item, for example, a token. It also * compacts the list item, for instance, if the item consists of @c * name=value parameter definitions.  The scanning function returns the * length of the scanned item, including any linear whitespace after it. * * By default, the scanning function accepts tokens, quoted strings or * separators (except comma, of course). * * @param[in]     home    memory home for allocating list pointers  * @param[in,out] ss      pointer to pointer to string to be parsed  * @param[in,out] append_list  pointer to list *                             where parsed list items are appended * @param[in]     scanner pointer to function scanning a single item  *                        (optional) *  * @retval 0  if successful. * @retval -1 upon an error. */issize_t msg_commalist_d(su_home_t *home, 			 char **ss, 			 msg_param_t **append_list,			 issize_t (*scanner)(char *s)){  scanner = scanner ? scanner : msg_comma_scanner;  return msg_any_list_d(home, ss, append_list, scanner, ',');}/** Token scanner for msg_commalist_d() accepting also empty entries. */issize_t msg_token_scan(char *start){  char *s = start;  skip_token(&s);  if (IS_LWS(*s))    *s++ = '\0';  skip_lws(&s);  return s - start;}/** Scan and compact a comma-separated item */staticissize_t msg_comma_scanner(char *start){  size_t tlen;  char *s, *p;    s = p = start;  if (s[0] == ',')    return 0;  for (;;) {    /* Grab next section - token, quoted string, or separator character */    char c = *s;    if (IS_TOKEN(c))       tlen = span_token(s);    else if (c == '"')      tlen = span_quoted(s);    else /* if (IS_SEPARATOR(c)) */      tlen = 1;        if (tlen == 0)      return -1;    if (p != s)      memmove(p, s, tlen);	/* Move section to end of paramexter */    p += tlen; s += tlen;        skip_lws(&s);		/* Skip possible LWS */        if (*s == '\0' || *s == ',') {		/* Test for possible end */      if (p != s) *p = '\0';      return s - start;    }    if (IS_TOKEN(c) && IS_TOKEN(*s))      *p++ = ' ';		/* Two tokens must be separated by LWS */  }}/** Parse a comment. * * Parses a multilevel comment. The comment assigned to return-value * parameter @a return_comment is NUL-terminated. The string at return-value * parameter @a ss is updated to point to first non-linear-whitespace * character after the comment. */issize_t msg_comment_d(char **ss, char const **return_comment){  /* skip comment */  int level = 1;  char *s = *ss;  assert(s[0] == '(');  if (*s != '(')    return -1;  *s++ = '\0';  if (return_comment)    *return_comment = s;        while (level) switch (*s++) {  case '(': level++; break;  case ')': level--; break;  case '\0': /* ERROR */ return -1;  }        assert(s[-1] == ')');        s[-1] = '\0';  skip_lws(&s);  *ss = s;  return 0;}/** Parse a quoted string */issize_t msg_quoted_d(char **ss, char **return_quoted){  char *s= *ss, *s0 = s;  ssize_t n = span_quoted(s);  if (n <= 0)    return -1;  *return_quoted = s;  s += n;  if (IS_LWS(*s)) {    *s++ = '\0';    skip_lws(&s);		/* skip linear whitespace */  }  *ss = s;  return s - s0;}#if 0/** Calculate length of string when quoted. */int msg_quoted_len(char const *u){  int rv;  if (!u)    return 0;  rv = span_token_lws(u);  if (u[rv]) {    /* We need to quote string */    int n;    int extra = 2; /* quote chars */    /* Find all characters to quote */    for (n = strcspn(u + rv, "\\\""); u[rv + n]; rv += n)      extra++;    rv += extra;  }  return rv;}#endif/**Parse @e host[":"port] pair. * * Parses a @e host[":"port] pair. The caller passes function a pointer to a * string via @a ss, and pointers to which parsed host and port are assigned * via @a hhost and @a pport, respectively. The value-result parameter @a * *pport must be initialized to default value (e.g., NULL). *  * @param ss    pointer to pointer to string to be parsed * @param return_host value-result parameter for @e host * @param return_port value-result parameter for @e port * @return  * Returns zero when successful, and a negative value upon an error. The * parsed values for host and port are assigned via @a return_host and @a * return_port, respectively. The function also updates the pointer @a *ss, * so if call is successful, the @a *ss points to first * non-linear-whitespace character after @e host[":"port] pair. * * @note * If there is no whitespace after @e port, the value in @a *pport may not be * NUL-terminated.  The calling function @b must NUL terminate the value by * setting the @a **ss to NUL after first examining its value. */int msg_hostport_d(char **ss, 		   char const **return_host, 		   char const **return_port){  char *host, *s = *ss;  char *port = NULL;  /* Host name */  host = s;   if (s[0] != '[') {    skip_token(&s); if (host == s) return -1;  }  else {    /* IPv6 */    size_t n = strspn(++s, HEX ":.");    if (s[n] != ']') return -1;    s += n + 1;  }  if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); }  if (s[0] == ':') {    unsigned long nport;    *s++ = '\0'; skip_lws(&s);    if (!IS_DIGIT(*s))      return -1;    port = s;    nport = strtoul(s, &s, 10);    if (nport > 65535)      return -1;    if (IS_LWS(*s)) {      *s++ = '\0';      skip_lws(&s);    }  }  *return_host = host;  *return_port = port;    *ss = s;  return 0;}/** Find a header parameter. * * Searches for given parameter @a name from the header. If parameter is * found, it returns a non-NULL pointer to the parameter value. If there is * no value for the name (in form "name" or "name=value"), the returned pointer * points to a NUL character. * * @param h     pointer to header structure * @param name  parameter name (with or without "=" sign) * * @return * A pointer to parameter value, or NULL if parameter was not found. */char const *msg_header_find_param(msg_common_t const *h, char const *name){  if (h && h->h_class->hc_params) {    msg_param_t const **params = (msg_param_t const **)      ((char *)h + h->h_class->hc_params);    return msg_params_find(*params, name);  }  return NULL;}/**Modify a parameter value or list item in a header. *  * A header parameter @a param can be just a C-string (@a is_item > 0), or * it can have internal format <i>name [ "=" value]</i>. In the latter case, * the value part following = is ignored when replacing or removing the * parameter. * * @param home      memory home used to re-allocate parameter list in header * @param h         pointer to a header * @param param     parameter to be replaced or added * @param is_item   how to interpret @a param: *                  - 1 case-sensitive, no structure *                  - 0 case-insensitive, <i>name [ "=" value ]</i> * @param remove_replace_add  what operation to do: *                  - -1 remove *                  - 0 replace *                  - 1 add * * @retval 1 if parameter was replaced or removed successfully * @retval 0 if parameter was added successfully,  *           or there was nothing to remove * @retval -1 upon an error */static int msg_header_param_modify(su_home_t *home, msg_common_t *h,			    char const *param,			    int is_item,			    int remove_replace_add){  msg_param_t *params, **pointer_to_params;  size_t plen, n;  if (!h || !h->h_class->hc_params || !param)    return -1;  pointer_to_params = (msg_param_t **)((char *)h + h->h_class->hc_params);  params = *pointer_to_params;  plen = is_item > 0 ? strlen(param) : strcspn(param, "=");  n = 0;    if (params) {    /* Existing list, try to replace or remove  */    for (; params[n]; n++) {      char const *maybe = params[n];            if (remove_replace_add > 0)	continue;      if (is_item > 0) {	if (strcmp(maybe, param) == 0) {	  if (remove_replace_add == 0)	    return 1;	}      }      else {	if (strncasecmp(maybe, param, plen) == 0 &&	    (maybe[plen] == '=' || maybe[plen] == 0))	  break;      }    }  }    /* Not found? */  if (!params || !params[n]) {    if (remove_replace_add < 0)      return 0;		/* Nothing to remove */    else      remove_replace_add = 1;	/* Add instead of replace */  }    if (remove_replace_add < 0) { /* Remove */    for (; params[n]; n++)       params[n] = params[n + 1];  }  else {    if (remove_replace_add > 0) { /* Add */      size_t m_before = MSG_PARAMS_NUM(n + 1);      size_t m_after =  MSG_PARAMS_NUM(n + 2);            assert(!params || !params[n]);            if (m_before != m_after || !params) {	msg_param_t *p;	/* XXX - we should know when to do realloc */	p = su_alloc(home, m_after * sizeof(*p)); 	if (!p) return -1;	if (n > 0)	  memcpy(p, params, n * sizeof(p[0]));	*pointer_to_params = params = p;      }      params[n + 1] = NULL;    }        params[n] = param;	/* Add .. or replace */  }    msg_fragment_clear(h);  if (h->h_class->hc_update) {    /* Update shortcuts */    size_t namelen;    char const *name, *value;        name = param;    namelen = strcspn(name, "=");        if (remove_replace_add < 0)      value = NULL;    else      value = param + namelen + (name[namelen] == '=');        h->h_class->hc_update(h, name, namelen, value);  }  return remove_replace_add <= 0; /* 0 when added, 1 otherwise */}/** Add a parameter to a header. * * You should use this function only when the header accepts multiple * parameters (or list items) with the same name. If that is not the case, * you should use msg_header_replace_param(). * * @note This function @b does @b not duplicate @p param. The caller should * have allocated the @a param from the memory home associated with header * @a h. * * The possible shortcuts to parameter values are updated. For example, the * "received" parameter in @Via header has shortcut in structure #sip_via_t, * the @ref sip_via_s::v_received "v_received" field. The shortcut is usully * a pointer to the parameter value. If the parameter was * "received=127.0.0.1" the @ref sip_via_s::v_received "v_received" field * would be a pointer to "127.0.0.1". If the parameter was "received=" or * "received", the shortcut would be a pointer to an empty string, "". * * @param home      memory home used to re-allocate parameter list in header * @param h         pointer to a header * @param param     parameter to be replaced or added * * @retval 0 if parameter was added * @retval -1 upon an error * * @sa msg_header_replace_param(), msg_header_remove_param(),  * msg_header_update_params(), * #msg_common_t, #msg_header_t,  * #msg_hclass_t, msg_hclass_t::hc_params, msg_hclass_t::hc_update */int msg_header_add_param(su_home_t *home, msg_common_t *h, char const *param){  return msg_header_param_modify(home, h, param, 				 0 /* case-insensitive name=value */, 				 1 /* add */);}/** Replace or add a parameter to a header.  * * A header parameter @a param is a string of format <i>name "=" value</i> * or just name. The value part following "=" is ignored when selecting a * parameter to replace. * * @note This function @b does @b not duplicate @p param. The caller should * have allocated the @a param from the memory home associated with header * @a h. * * The possible shortcuts to parameter values are updated. For example, the * "received" parameter in @Via header has shortcut in structure #sip_via_t, * the @ref sip_via_s::v_received "v_received" field. * * @param home      memory home used to re-allocate parameter list in header * @param h         pointer to a header * @param param     parameter to be replaced or added * * @retval 0 if parameter was added * @retval 1 if parameter was replaced * @retval -1 upon an error * * @sa msg_header_add_param(), msg_header_remove_param(),  * msg_header_update_params(), * #msg_common_t, #msg_header_t,  * #msg_hclass_t, msg_hclass_t::hc_params, msg_hclass_t::hc_update

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?