📄 sip_util.c
字号:
while (q[0] == '0') q++; if (q[0] >= '1' && q[0] <= '9') return 1000; if (q[0] == '\0') return 0; if (q[0] != '.') return 500; /* Garbage... */ if (q[1] >= '0' && q[1] <= '9') { value = (q[1] - '0') * 100; if (q[2] >= '0' && q[2] <= '9') { value += (q[2] - '0') * 10; if (q[3] >= '0' && q[3] <= '9') { value += (q[3] - '0'); if (q[4] > '5' && q[4] <= '9') /* Round upwards */ value += 1; else if (q[4] == '5') value += value & 1; /* Round to even */ } } } return value;}/**@ingroup sip_route * * Get first route header and remove it from its fragment chain. * */sip_route_t *sip_route_remove(msg_t *msg, sip_t *sip){ sip_route_t *r; if ((r = sip->sip_route)) msg_header_remove(msg, (msg_pub_t *)sip, (msg_header_t *)r); return r;}/**@ingroup sip_route * * Get last route header and remove it from its fragment chain. * */sip_route_t *sip_route_pop(msg_t *msg, sip_t *sip){ sip_route_t *r; for (r = sip->sip_route; r; r = r->r_next) if (r->r_next == NULL) { msg_header_remove(msg, (msg_pub_t *)sip, (msg_header_t *)r); return r; } return NULL;}/**@ingroup sip_route * * Get first route header and rewrite the RequestURI. */sip_route_t *sip_route_follow(msg_t *msg, sip_t *sip){ if (sip->sip_route) { /* XXX - in case of outbound proxy, route may contain our address */ sip_route_t *r = sip_route_remove(msg, sip); sip_request_t *rq = sip->sip_request; rq = sip_request_create(msg_home(msg), rq->rq_method, rq->rq_method_name, (url_string_t const *)r->r_url, rq->rq_version); url_strip_transport(rq->rq_url); msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)rq); return r; } return NULL;}/**@ingroup sip_route * * Check if route header has lr param. * * "lr" param can be either URL or header parameter. */int sip_route_is_loose(sip_route_t const *r){ if (!r) return 0; if (r->r_url->url_params) return url_has_param(r->r_url, "lr"); else return r->r_params && msg_params_find(r->r_params, "lr") != NULL;}/**@ingroup sip_route * * Reverse a route header. * * 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 extra 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 and the strings attached to it. * * @retval 0 when successful * @retval -1 upon an error */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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -