📄 sip_util.c
字号:
* The function sip_route_reverse() reverses a route header like @b * Record-Route or @b Path. */sip_route_t *sip_route_reverse(su_home_t *home, sip_route_t const *route){ sip_route_t *reverse = NULL; sip_route_t r[1], *tmp; sip_route_init(r); for (reverse = NULL; route; route = route->r_next) { *r->r_url = *route->r_url; /* Fix broken (Record-)Routes without <> */ if (r->r_url->url_params == NULL && r->r_params && r->r_params[0] && (r->r_params[0][0] == 'l' || r->r_params[0][0] == 'L') && (r->r_params[0][1] == 'r' || r->r_params[0][1] == 'R') && (r->r_params[0][2] == '=' || r->r_params[0][2] == 0)) r->r_url->url_params = route->r_params[0], r->r_params = route->r_params + 1; else r->r_params = route->r_params; tmp = sip_route_dup(home, r); if (!tmp) goto error; tmp->r_next = reverse; reverse = tmp; } return reverse; error: while (reverse) { sip_route_t *r_next = reverse->r_next; su_free(home, reverse); reverse = r_next; } return NULL;}/**@ingroup sip_route * * Fix and duplicate a route header. * * The function sip_route_reverse() reverses a route header like @b * Record-Route or @b Path. * */sip_route_t *sip_route_fixdup(su_home_t *home, sip_route_t const *route){ sip_route_t *copy = NULL; sip_route_t r[1], **rr; sip_route_init(r); /* Copy the record route as route */ for (rr = © route; route = route->r_next) { *r->r_url = *route->r_url; /* Fix broken (Record-)Routes without <> */ if (r->r_url->url_params == NULL && r->r_params && r->r_params[0] && (r->r_params[0][0] == 'l' || r->r_params[0][0] == 'L') && (r->r_params[0][1] == 'r' || r->r_params[0][1] == 'R') && (r->r_params[0][2] == '=' || r->r_params[0][2] == 0)) r->r_url->url_params = route->r_params[0], r->r_params = route->r_params + 1; else r->r_params = route->r_params; *rr = sip_route_dup(home, r); if (!*rr) goto error; rr = &(*rr)->r_next; } return copy; error: while (copy) { sip_route_t *r_next = copy->r_next; su_free(home, copy); copy = r_next; } return NULL;}static void sip_fragment_clear_chain(sip_header_t *h){ void const *next; for (h = h; h; h = h->sh_succ) { next = (char *)h->sh_data + h->sh_len; sip_fragment_clear(h->sh_common); if (!next || !h->sh_succ || h->sh_next != h->sh_succ || h->sh_succ->sh_data != next || h->sh_succ->sh_len) return; }}/**@ingroup sip_route * * Fix Route header. */sip_route_t *sip_route_fix(sip_route_t *route){ sip_route_t *r; sip_header_t *h = NULL; int i; for (r = route; r; r = r->r_next) { /* Keep track of first header structure on this header line */ if (!h || (char *)h->sh_data + h->sh_len != r->r_common->h_data || r->r_common->h_len) h = (sip_header_t *)r; if (r->r_url->url_params == NULL && r->r_params && r->r_params[0] && (r->r_params[0][0] == 'l' || r->r_params[0][0] == 'L') && (r->r_params[0][1] == 'r' || r->r_params[0][1] == 'R') && (r->r_params[0][2] == '=' || r->r_params[0][2] == 0)) { r->r_url->url_params = r->r_params[0]; for (i = 0; r->r_params[i]; i++) ((char const **)r->r_params)[i] = r->r_params[i + 1]; sip_fragment_clear_chain(h); } } return route;}/**@ingroup sip_via * * Get first via header and remove it from its fragment chain. */sip_via_t *sip_via_remove(msg_t *msg, sip_t *sip){ sip_via_t *v; if (sip == NULL) return NULL; for (v = sip->sip_via; v; v = v->v_next) { sip_fragment_clear(v->v_common); if (v->v_next != (void *)v->v_common->h_succ) break; } if ((v = sip->sip_via)) msg_header_remove(msg, (msg_pub_t *)sip, (msg_header_t *)v); return v;}/** Serialize payload. * * The sip_payload_serialize() adds missing headers to MIME multiparty payload, * encodes them and orders them in header chain. It also calculates the total * length of the payload. */unsigned long sip_payload_serialize(msg_t *msg, sip_payload_t *pl){ unsigned long total; for (total = 0; pl; pl = (sip_payload_t *)pl->pl_next) { total += (unsigned)pl->pl_common->h_len; } return total;}/** * Remove extra parameters from an AOR URL. The parameters listed in the RFC * 3261 table 1 include port number, method, maddr, ttl, transport, lr and * headers. * * @note The funtion modifies the @a url. */int sip_aor_strip(url_t *url){ if (url == NULL) return -1; url->url_port = NULL; url->url_headers = NULL; if (url->url_params) { char *d, *s; size_t n; int semi;# define PARAM_MATCH(s, tag) \ (strncasecmp(s, tag, strlen(tag)) == 0 && \ (s[strlen(tag)] == '\0' || \ s[strlen(tag)] == ';' || \ s[strlen(tag)] == '=')) for (d = s = (char *)url->url_params; *s; s += n + semi) { n = strcspn(s, ";"); semi = s[n] != '\0'; if (PARAM_MATCH(s, "method")) continue; if (PARAM_MATCH(s, "maddr")) continue; if (PARAM_MATCH(s, "ttl")) continue; if (PARAM_MATCH(s, "transport")) continue; if (PARAM_MATCH(s, "lr")) continue; if (s != d) { if (d != url->url_params) d++; if (s != d) memcpy(d, s, n + 1); } d += n; } if (d == url->url_params) url->url_params = NULL; else if (d != s) *d = '\0';# undef PARAM_MATCH } return 0;}/** Compare Security-Verify header with Security-Server header. */int sip_security_verify_compare(sip_security_server_t const *s, sip_security_verify_t const *v, msg_param_t *return_d_ver){ int i, j, retval, digest; msg_param_t const *s_params, *v_params, empty[] = { NULL }; if (return_d_ver) *return_d_ver = NULL; if (s == NULL) return 0; for (;;s = s->sa_next, v = v->sa_next) { if (s == NULL || v == NULL) return (s == NULL) - (v == NULL); if ((retval = str0cmp(s->sa_mec, v->sa_mec))) return retval; digest = strcasecmp(s->sa_mec, "Digest") == 0; s_params = s->sa_params, v_params = v->sa_params; if (digest && s_params == NULL && v_params != NULL) s_params = empty; if (s_params == NULL || v_params == NULL) { if ((retval = (s_params == NULL) - (v_params == NULL))) return retval; continue; } for (i = 0, j = 0;; i++, j++) { if (digest && v_params[j] && strncasecmp(v_params[j], "d-ver=", 6) == 0) { if (return_d_ver) *return_d_ver = v_params[j] + strlen("d-ver="); j++; } retval = str0cmp(s_params[i], v_params[j]); if (retval || s_params[i] == NULL || v_params[j] == NULL) break; } if (retval) return retval; }}/** Select best mechanism from Security-Client header. * * @note We assume that Security-Server header in @a s is sorted by * preference. */sip_security_client_t const *sip_security_client_select(sip_security_client_t const *client, sip_security_server_t const *server){ sip_security_server_t const *c, *s; if (server == NULL || client == NULL) return NULL; for (s = server; s; s = s->sa_next) { for (c = client; c; c = c->sa_next) { if (str0cmp(s->sa_mec, c->sa_mec) == 0) return c; } } return NULL;}/**Checks if the response with given response code terminates dialog or * dialog usage. * * @return -1 if the response with given code terminates whole dialog. * @return 1 if the response terminates the dialog usage. * @return 0 if the response does not terminate dialog or dialog usage. * * @return * The @a *return_graceful_terminate_usage is set to 1, if application * should gracefully terminate its dialog usage. It is set to 0, if no * graceful terminate is required. If it is up to application policy to * decide whether to gracefully terminate or not, the * @a *return_graceful_terminate_usage is left unmodified. * * @sa * http://www.ietf.org/internet-drafts/draft-sparks-sipping-dialogusage-01.txt */int sip_response_terminates_dialog(int response_code, sip_method_t method, int *return_graceful_terminate_usage){ enum { no_effect, terminate_usage = 1, terminate_dialog = -1 }; int dummy; if (!return_graceful_terminate_usage) return_graceful_terminate_usage = &dummy; if (response_code < 300) return *return_graceful_terminate_usage = 0; /* 3xx responses: Redirection mid-dialog is not well understood in SIP, but whatever effect it has impacts the entire dialog and all of its usages equally. In our example scenario, both the subscription and the invite usage would be redirected by this single response. */ if (response_code < 400) return *return_graceful_terminate_usage = 0; if (response_code < 500) switch (response_code) { default: case 400: /** @par 400 and unrecognized 4xx responses These responses affect only the NOTIFY transaction, not the subscription, the dialog it resides in (beyond affecting the local CSeq), or any other usage of that dialog. In general, the response is a complaint about this transaction, not the usage or dialog the transaction occurs in. */ *return_graceful_terminate_usage = 0; return 0; case 401: case 407: /** @par 401 Unauthorized and 407 Proxy Authentication Required This request, not the subscription or dialog, is being challenged. The usages and dialog are not terminated. */ *return_graceful_terminate_usage = 0; return 0; case 402: /** @par 402 Payment Required This is a reserved response code. If encountered, it should be treated as an unrecognized 4xx. */ *return_graceful_terminate_usage = 0; return 0; case 403: /** @par 403 Forbidden This response terminates the subscription, but has no effect on any other usages of the dialog. In our example scenario, the invite usage continues to exist. Similarly, if the 403 came in response to a re-INVITE, the invite usage would be terminated, but not the subscription. */ return terminate_usage; case 404: /** @par 404 Not Found This response destroys the dialog and all usages sharing it. The Request-URI that is being 404ed is the remote target set by the Contact provided by the peer. Getting this response means something has gone fundamentally wrong with the dialog state. */ return terminate_dialog;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -