📄 sip_util.c
字号:
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 (@Route, @RecordRoute, @Path, @ServiceRoute). */sip_route_t *sip_route_reverse_as(su_home_t *home, msg_hclass_t *hc, sip_route_t const *route){ sip_route_t *reverse = NULL; sip_route_t r[1], *tmp; sip_route_init(r); r->r_common->h_class = hc; 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_t *)msg_header_dup_as(home, hc, (msg_header_t *)r); if (!tmp) goto error; tmp->r_next = reverse; reverse = tmp; } return reverse; error: msg_header_free_all(home, (msg_header_t *)reverse); return NULL;}/**@ingroup sip_route * * Reverse a @Route header. * * Reverse A route header like @RecordRoute or @Path. */sip_route_t *sip_route_reverse(su_home_t *home, sip_route_t const *route){ return sip_route_reverse_as(home, sip_route_class, route);}/**@ingroup sip_route * * Fix and duplicate a route header (@Route, @RecordRoute, @Path, @ServiceRoute). * */sip_route_t *sip_route_fixdup_as(su_home_t *home, msg_hclass_t *hc, 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_t *)msg_header_dup_as(home, hc, (msg_header_t *)r); if (!*rr) goto error; rr = &(*rr)->r_next; } return copy; error: msg_header_free_all(home, (msg_header_t *)copy); return NULL;}/**@ingroup sip_route * * Fix and duplicate a @Route header. * * Copy a route header like @RecordRoute or @Path as @Route. * */sip_route_t *sip_route_fixdup(su_home_t *home, sip_route_t const *route){ return sip_route_fixdup_as(home, sip_route_class, route);}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; size_t 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 @RFC3261 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) url_strip_transport(url); if (url->url_params) url->url_params = url_strip_param_string((char *)url->url_params, "lr"); return 0;}/** Compare @SecurityVerify header with @SecurityServer header. */int sip_security_verify_compare(sip_security_server_t const *s, sip_security_verify_t const *v, msg_param_t *return_d_ver){ size_t i, j; int 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 @SecurityClient header. * * @note We assume that @SecurityServer 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. * * @RFC5057 */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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -