Exemplo n.º 1
0
/** Parse SIP version.
 *
 * Parse a SIP version string. Update the
 * pointer at @a ss to first non-LWS character after the version string.
 *
 * @param ss   string to be parsed [IN/OUT]
 * @param ver  value result for version [OUT]
 *
 * @retval 0 when successful,
 * @retval -1 upon an error.
 */
int sip_version_d(char **ss, char const **ver)
{
  char *s = *ss;
  char const *result;
  size_t const version_size = sizeof(sip_version_2_0) - 1;

  if (su_casenmatch(s, sip_version_2_0, version_size) &&
      !IS_TOKEN(s[version_size])) {
    result = sip_version_2_0;
    s += version_size;
  }
  else {
    /* Version consists of two tokens, separated by / */
    size_t l1 = 0, l2 = 0, n;

    result = s;

    l1 = span_token(s);
    for (n = l1; IS_LWS(s[n]); n++)
      {}
    if (s[n] == '/') {
      for (n++; IS_LWS(s[n]); n++)
        {}
      l2 = span_token(s + n);
      n += l2;
    }

    if (l1 == 0 || l2 == 0)
      return -1;

    /* If there is extra ws between tokens, compact version */
    if (n > l1 + 1 + l2) {
      s[l1] = '/';
      memmove(s + l1 + 1, s + n - l2, l2);
      s[l1 + 1 + l2] = 0;

      /* Compare again with compacted version */
      if (su_casematch(s, sip_version_2_0))
	result = sip_version_2_0;
    }

    s += n;
  }

  while (IS_WS(*s)) *s++ = '\0';

  *ss = s;

  if (ver)
    *ver = result;

  return 0;
}
Exemplo n.º 2
0
static bool parse_next(char **data, char **key, char **value)
{
	/* @UNSAFE */
	char *p, *dest;

	p = *data;
	while (IS_LWS(*p)) p++;

	/* get key */
	*key = p;
	while (*p != '\0' && *p != '=' && *p != ',')
		p++;

	if (*p != '=') {
		*data = p;
		return FALSE;
	}

	*value = p+1;

	/* skip trailing whitespace in key */
	while (p > *data && IS_LWS(p[-1]))
		p--;
	*p = '\0';

	/* get value */
	p = *value;
	while (IS_LWS(*p)) p++;

	if (*p != '"') {
		while (*p != '\0' && *p != ',')
			p++;

		*data = p+1;
		while (IS_LWS(p[-1]))
			p--;
		*p = '\0';
	} else {
		/* quoted string */
		*value = dest = ++p;
		while (*p != '\0' && *p != '"') {
			if (*p == '\\' && p[1] != '\0')
				p++;
			*dest++ = *p++;
		}

		*data = *p == '"' ? p+1 : p;
		*dest = '\0';
	}

	return TRUE;
}
Exemplo n.º 3
0
/**Parse a HTTP method name.
 *
 * The function @c http_method_d() parses a HTTP method, and returns a code
 * corresponding to the method.  It stores the address of the first non-LWS
 * character after method name in @c *ss.
 *
 * @param ss    pointer to pointer to string to be parsed
 * @param nname pointer to value-result parameter formethod name
 *
 * @note
 * If there is no whitespace after method name, the value in @a *nname
 * 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.
 *
 * @return The function @c http_method_d returns the method code if method
 * was identified, 0 (@c http_method_unknown) if method is not known, or @c -1
 * (@c http_method_invalid) if an error occurred.
 *
 * If the value-result argument @a nname is not @c NULL, http_method_d()
 * stores a pointer to the method name to it.
 */
http_method_t http_method_d(char **ss, char const **nname)
{
  char *s = *ss, c = *s;
  char const *name;
  int code = http_method_unknown;
  size_t n = 0;

#define MATCH(s, m) (su_casenmatch(s, m, n = sizeof(m) - 1))

  if (c >= 'a' && c <= 'z')
    c += 'A' - 'a';

  switch (c) {
  case 'C': if (MATCH(s, "CONNECT")) code = http_method_connect; break;
  case 'D': if (MATCH(s, "DELETE")) code = http_method_delete; break;
  case 'G': if (MATCH(s, "GET")) code = http_method_get; break;
  case 'H': if (MATCH(s, "HEAD")) code = http_method_head; break;
  case 'O': if (MATCH(s, "OPTIONS")) code = http_method_options; break;
  case 'P': if (MATCH(s, "POST")) code = http_method_post;
            else
            if (MATCH(s, "PUT")) code = http_method_put; break;
  case 'T': if (MATCH(s, "TRACE")) code = http_method_trace; break;
  }

#undef MATCH

  if (!code || IS_NON_WS(s[n])) {
    /* Unknown method */
    code = http_method_unknown;
    name = s;
    for (n = 0; IS_UNRESERVED(s[n]); n++)
      ;
    if (s[n]) {
      if (!IS_LWS(s[n]))
	return http_method_invalid;
      if (nname)
	s[n++] = '\0';
    }
  }
  else {
    name = methods[code];
  }

  while (IS_LWS(s[n]))
    n++;

  *ss = (s + n);
  if (nname) *nname = name;

  return (http_method_t)code;
}
Exemplo n.º 4
0
/* Scan a cookie parameter */
static issize_t set_cookie_scanner(char *s)
{
  char *rest;

#define LOOKING_AT(s, what) \
  (su_casenmatch((s), what, strlen(what)) && (rest = s + strlen(what)))

  /* Special cases from Netscape spec */
  if (LOOKING_AT(s, "expires=")) {
    msg_time_t value;
    msg_date_d((char const **)&rest, &value);
  } else if (LOOKING_AT(s, "path=/")) {
    for (;;) {
      rest += span_unreserved(rest);
      if (*rest != '/')
	break;
      rest++;
    }
  } else {
    return msg_attribute_value_scanner(s);
  }
#undef LOOKING_AT

  if (IS_LWS(*rest)) {
    *rest++ = '\0'; skip_lws(&rest);
  }

  return rest - s;
}
Exemplo n.º 5
0
issize_t sip_refer_to_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
{
  issize_t retval;
  sip_refer_to_t *r = (sip_refer_to_t *)h;

  retval = sip_name_addr_d(home, &s,
			   &r->r_display,
			   r->r_url,
			   &r->r_params,
			   NULL);
  if (retval < 0)
    return retval;

  if (*s == '?' && !r->r_display && !r->r_url->url_headers) {
    /* Missing <> around URL */
    *s++ = '\0';
    r->r_url->url_headers = s;
    s += strcspn(s, " \t;,");
    if (IS_LWS(*s))
      *s++ = '\0', skip_lws(&s);
    if (*s)
      return -1;
    r->r_display = s;	/* Put empty string in display so that we encode using <> */
  }
  else if (*s)
    return -1;

  return retval;
}
Exemplo n.º 6
0
/* Scan a cookie parameter */
static issize_t cookie_scanner(char *s)
{
  char *p = s;
  size_t tlen;

  skip_token(&s);

  if (s == p)		/* invalid parameter name */
    return -1;

  tlen = s - p;

  if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); }

  if (*s == '=') {
    char *v;
    s++;
    skip_lws(&s);

    v = s;

    /* get value */
    if (*s == '"') {
      size_t qlen = span_quoted(s);
      if (!qlen)
	return -1;
      s += qlen;
    }
    else {
      s += strcspn(s, ",;" LWS);
      if (s == v)
	return -1;
    }

    if (p + tlen + 1 != v) {
      memmove(p + tlen + 1, v, s - v);
      p[tlen] = '=';
      p[tlen + 1 + (s - v)] = '\0';
    }
  }

  if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); }

  return s - p;
}
Exemplo n.º 7
0
issize_t sip_rack_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
{
  sip_rack_t *ra = h->sh_rack;

  ra->ra_response = strtoul(s, &s, 10);

  if (IS_LWS(*s)) {
    skip_lws(&s);
    ra->ra_cseq = strtoul(s, &s, 10);

    if (IS_LWS(*s)) {
      skip_lws(&s);
      if ((ra->ra_method = sip_method_d(&s, &ra->ra_method_name)) >= 0) {
	return 0;
      }
    }
  }

  return -1;
}
Exemplo n.º 8
0
issize_t sip_priority_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
{
  sip_priority_t *priority = (sip_priority_t *)h;

  if (msg_token_d(&s, &priority->g_string) < 0)
    return -1;

  if (*s && !IS_LWS(*s))	/* Something extra after priority token? */
    return -1;

  return 0;
}
Exemplo n.º 9
0
issize_t sip_timestamp_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
{
  sip_timestamp_t *ts = (sip_timestamp_t*)h;

  ts->ts_stamp = s;
  s += span_digit(s);
  if (s == ts->ts_stamp)
    return -1;
  if (*s == '.') { s += span_digit(s + 1) + 1; }

  if (IS_LWS(*s)) {
    *s = '\0';
    s += span_lws(s + 1) + 1;
    ts->ts_delay = s;
    s += span_digit(s); if (*s == '.') { s += span_digit(s + 1) + 1; }
  }

  if (!*s || IS_LWS(*s))
    *s++ = '\0';
  else
    return -1;

  return 0;
}
Exemplo n.º 10
0
/** Decode a string containg header field.
 *
 * The header object is initialized with the contents of the string. The
 * string is modified when parsing. The home is used to allocate extra
 * memory required when parsing, e.g., for parameter list or when there
 * string contains multiple header fields.
 *
 * @deprecated
 * Use msg_header_make() or header-specific make functions, e.g.,
 * sip_via_make().
 *
 * @retval 0 when successful
 * @retval -1 upon an error.
 */
issize_t sip_header_field_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
{
  if (h && s && s[slen] == '\0') {
    size_t n = span_lws(s);
    s += n; slen -= n;

    for (n = slen; n >= 1 && IS_LWS(s[n - 1]); n--)
      ;

    s[n] = '\0';

    assert(SIP_HDR_TEST(h));

    return h->sh_class->hc_parse(home, h, s, slen);
  }
  else
    return -1;
}
Exemplo n.º 11
0
/** Parse SIP <word "@" word> construct used in @CallID. */
char *sip_word_at_word_d(char **ss)
{
  char *rv = *ss, *s0 = *ss;

  skip_word(ss);
  if (s0 == *ss)
    return NULL;
  if (**ss == '@') {
    (*ss)++;
    s0 = *ss;
    skip_word(ss);
    if (s0 == *ss)
      return NULL;
  }
  if (IS_LWS(**ss))
    (*ss)++;
  skip_lws(ss);

  return rv;
}
Exemplo n.º 12
0
/** Decode transport */
issize_t sip_transport_d(char **ss, char const **ttransport)
{
  char const *transport;
  char *pn, *pv, *pt;
  size_t pn_len, pv_len, pt_len;
  char *s = *ss;

#define TRANSPORT_MATCH(t) \
  (su_casenmatch(s + 7, t + 7, (sizeof t) - 8) && \
   (!s[sizeof(t) - 1] || IS_LWS(s[sizeof(t) - 1]))	\
   && (transport = t, s += sizeof(t) - 1))

  if (!su_casenmatch(s, "SIP/2.0", 7) ||
      (!TRANSPORT_MATCH(sip_transport_udp) &&
       !TRANSPORT_MATCH(sip_transport_tcp) &&
       !TRANSPORT_MATCH(sip_transport_sctp) &&
       !TRANSPORT_MATCH(sip_transport_ws) &&
       !TRANSPORT_MATCH(sip_transport_wss) &&
       !TRANSPORT_MATCH(sip_transport_tls))) {
    /* Protocol name */
    transport = pn = s;
    skip_token(&s);
    pn_len = s - pn;
    skip_lws(&s);
    if (pn_len == 0 || *s++ != '/') return -1;
    skip_lws(&s);

    /* Protocol version */
    pv = s;
    skip_token(&s);
    pv_len = s - pv;
    skip_lws(&s);
    if (pv_len == 0 || *s++ != '/') return -1;
    skip_lws(&s);

    /* Transport protocol */
    pt = s;
    skip_token(&s);
    pt_len = s - pt;
    if (pt_len == 0) return -1;

    /* Remove whitespace between protocol name and version */
    if (pn + pn_len + 1 != pv) {
      pn[pn_len] = '/';
      pv = memmove(pn + pn_len + 1, pv, pv_len);
    }

    /* Remove whitespace between protocol version and transport */
    if (pv + pv_len + 1 != pt) {
      pv[pv_len] = '/';
      pt = memmove(pv + pv_len + 1, pt, pt_len);
      pt[pt_len] = '\0';

      /* extra whitespace? */
      if (su_casematch(transport, sip_transport_udp))
	transport = sip_transport_udp;
      else if (su_casematch(transport, sip_transport_tcp))
	transport = sip_transport_tcp;
      else if (su_casematch(transport, sip_transport_sctp))
	transport = sip_transport_sctp;
      else if (su_casematch(transport, sip_transport_ws))
	transport = sip_transport_ws;
      else if (su_casematch(transport, sip_transport_wss))
	transport = sip_transport_wss;
      else if (su_casematch(transport, sip_transport_tls))
	transport = sip_transport_tls;
    }
  }

  if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); }
  *ss = s;
  *ttransport = transport;
  return 0;
}
Exemplo n.º 13
0
/**Parse a SIP method name.
 *
 * Parse a SIP method name and return a code corresponding to the method.
 * The address of the first non-LWS character after method name is stored in
 * @a *ss.
 *
 * @param ss    pointer to pointer to string to be parsed
 * @param return_name  value-result parameter for method name
 *
 * @note
 * If there is no whitespace after method name, the value in @a *return_name
 * 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.
 *
 * @return The method code if method
 * was identified, 0 (sip_method_unknown()) if method is not known, or @c -1
 * (sip_method_invalid()) if an error occurred.
 *
 * If the value-result argument @a return_name is not @c NULL,
 * a pointer to the method name is stored to it.
 */
sip_method_t sip_method_d(char **ss, char const **return_name)
{
  char *s = *ss, c = *s;
  char const *name;
  int code = sip_method_unknown;
  size_t n = 0;

#define MATCH(s, m) (strncmp(s, m, n = sizeof(m) - 1) == 0)

  switch (c) {
  case 'A': if (MATCH(s, "ACK")) code = sip_method_ack; break;
  case 'B': if (MATCH(s, "BYE")) code = sip_method_bye; break;
  case 'C':
    if (MATCH(s, "CANCEL"))
      code = sip_method_cancel;
    break;
  case 'I':
    if (MATCH(s, "INVITE"))
      code = sip_method_invite;
    else if (MATCH(s, "INFO"))
      code = sip_method_info;
    break;
  case 'M': if (MATCH(s, "MESSAGE")) code = sip_method_message; break;
  case 'N': if (MATCH(s, "NOTIFY")) code = sip_method_notify; break;
  case 'O': if (MATCH(s, "OPTIONS")) code = sip_method_options; break;
  case 'P':
    if (MATCH(s, "PRACK")) code = sip_method_prack;
    else if (MATCH(s, "PUBLISH")) code = sip_method_publish;
    break;
  case 'R':
    if (MATCH(s, "REGISTER"))
      code = sip_method_register;
    else if (MATCH(s, "REFER"))
      code = sip_method_refer;
    break;
  case 'S':
    if (MATCH(s, "SUBSCRIBE"))
      code = sip_method_subscribe;
    break;
  case 'U':
    if (MATCH(s, "UPDATE"))
      code = sip_method_update;
    break;
  }

#undef MATCH

  if (IS_NON_WS(s[n]))
    /* Unknown method */
    code = sip_method_unknown;

  if (code == sip_method_unknown) {
    name = s;
    for (n = 0; IS_UNRESERVED(s[n]); n++)
      ;
    if (s[n]) {
      if (!IS_LWS(s[n]))
	return sip_method_invalid;
      if (return_name)
	s[n++] = '\0';
    }
  }
  else {
    name = sip_method_names[code];
  }

  while (IS_LWS(s[n]))
    n++;

  *ss = (s + n);
  if (return_name) *return_name = name;

  return (sip_method_t)code;
}