📄 sip_dialog.c
字号:
/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END *//* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */#pragma ident "@(#)sip_dialog.c 1.28 06/08/16 SMI"#include "sip_msg.h"#include "sip_hash.h"#include "sip_dialog.h"#include "sip_miscdefs.h"#include "sip_parse_generic.h"#define SIP_DLG_XCHG_FROM 0#define SIP_DLG_XCHG_TO 1/* Dialog state change callback function */void (*sip_dlg_ulp_state_cb)(sip_dialog_t, sip_msg_t, int, int) = NULL;boolean_t sip_incomplete_dialog(sip_dialog_t);/* Exchange From/To header */_sip_header_t *sip_dlg_xchg_from_to(sip_msg_t, int);/* Complete dialog hash table */sip_hash_t sip_dialog_hash[SIP_HASH_SZ];/* Partial dialog hash table */sip_hash_t sip_dialog_phash[SIP_HASH_SZ];/* Route set structure */typedef struct sip_dlg_route_set_s { char *sip_dlg_route; sip_str_t sip_dlg_ruri; boolean_t sip_dlg_route_lr; struct sip_dlg_route_set_s *sip_dlg_route_next;}sip_dlg_route_set_t;sip_dialog_t sip_seed_dialog(sip_conn_object_t, _sip_msg_t *, void (*func)(sip_dialog_t, sip_msg_t, void *), boolean_t, int);sip_dialog_t sip_complete_dialog(_sip_msg_t *, _sip_dialog_t *, void (*func)(sip_dialog_t, sip_msg_t, void *));sip_dialog_t sip_dialog_create(_sip_msg_t *, _sip_msg_t *, int);int sip_dialog_process(_sip_msg_t *, sip_dialog_t *, void (*func)(sip_dialog_t, sip_msg_t, void *));void sip_dialog_delete(_sip_dialog_t *);void sip_dialog_init();sip_dialog_t sip_dialog_find(_sip_msg_t *);boolean_t sip_dialog_match(void *, void *);boolean_t sip_dialog_free(void *, void *, int *);sip_dialog_t sip_update_dialog(sip_dialog_t, _sip_msg_t *, void (*func)(sip_dialog_t, sip_msg_t, void *));char *sip_dialog_req_uri(sip_dialog_t);static void sip_release_dialog_res(_sip_dialog_t *);void sip_dlg_self_destruct(void *);static int sip_dialog_get_route_set(_sip_dialog_t *, _sip_msg_t *, int);static void sip_dialog_free_rset(sip_dlg_route_set_t *);/* Timer object for partial dialogs */typedef struct sip_dialog_timer_obj_s { _sip_dialog_t *dialog; void (*func)(sip_dialog_t, sip_msg_t, void *);} sip_dialog_timer_obj_t;/* To avoid duplication all over the place */static voidsip_release_dialog_res(_sip_dialog_t *dialog){ assert(dialog->sip_dlg_ref_cnt == 0); if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer)) SIP_CANCEL_TIMER(dialog->sip_dlg_timer); if (dialog->sip_dlg_call_id != NULL) sip_free_header(dialog->sip_dlg_call_id); if (dialog->sip_dlg_local_uri_tag != NULL) sip_free_header(dialog->sip_dlg_local_uri_tag); if (dialog->sip_dlg_remote_uri_tag != NULL) sip_free_header(dialog->sip_dlg_remote_uri_tag); if (dialog->sip_dlg_remote_target != NULL) sip_free_header(dialog->sip_dlg_remote_target); if (dialog->sip_dlg_route_set != NULL) sip_free_header(dialog->sip_dlg_route_set); if (dialog->sip_dlg_event != NULL) sip_free_header(dialog->sip_dlg_event); if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) { free(dialog->sip_dlg_req_uri.sip_str_ptr); dialog->sip_dlg_req_uri.sip_str_ptr = NULL; dialog->sip_dlg_req_uri.sip_str_len = 0; } if (dialog->sip_dlg_rset.sip_str_ptr != NULL) { free(dialog->sip_dlg_rset.sip_str_ptr); dialog->sip_dlg_rset.sip_str_len = 0; dialog->sip_dlg_rset.sip_str_ptr = NULL; } (void) pthread_mutex_destroy(&dialog->sip_dlg_mutex); free(dialog);}/* * Get the route information from the 'value' and add it to the route * set. */static sip_dlg_route_set_t *sip_add_route_to_set(sip_hdr_value_t *value){ int vlen = 0; sip_dlg_route_set_t *rset; char *crlf; const sip_param_t *uri_param; int error; rset = calloc(1, sizeof (*rset)); if (rset == NULL) return (NULL); rset->sip_dlg_route_next = NULL; vlen = value->sip_value_end - value->sip_value_start; /* check for CRLF */ crlf = value->sip_value_end - strlen(SIP_CRLF); while (crlf != NULL && strncmp(crlf, SIP_CRLF, strlen(SIP_CRLF)) == 0) { vlen -= strlen(SIP_CRLF); crlf -= strlen(SIP_CRLF); } rset->sip_dlg_route = calloc(1, vlen + 1); if (rset->sip_dlg_route == NULL) { free(rset); return (NULL); } /* loose routing */ rset->sip_dlg_route_lr = B_FALSE; (void) strncpy(rset->sip_dlg_route, value->sip_value_start, vlen); rset->sip_dlg_ruri.sip_str_ptr = rset->sip_dlg_route + (value->cftr_uri.sip_str_ptr - value->sip_value_start); rset->sip_dlg_ruri.sip_str_len = value->cftr_uri.sip_str_len; rset->sip_dlg_route[vlen] = '\0'; assert(value->sip_value_parsed_uri != NULL); /* * Check if the 'lr' param is present for this route. */ uri_param = sip_get_uri_params(value->sip_value_parsed_uri, &error); if (error != 0) { free(rset->sip_dlg_route); free(rset); return (NULL); } if (uri_param != NULL) { rset->sip_dlg_route_lr = sip_is_param_present(uri_param, "lr", strlen("lr")); } return (rset);}/* * Depending on the route-set, determine the request URI. */char *sip_dialog_req_uri(sip_dialog_t dialog){ const sip_str_t *req_uri; char *uri; _sip_dialog_t *_dialog; _dialog = (_sip_dialog_t *)dialog; if (_dialog->sip_dlg_route_set == NULL || _dialog->sip_dlg_req_uri.sip_str_ptr == NULL) { const struct sip_value *val; val = sip_get_header_value(_dialog->sip_dlg_remote_target, NULL); req_uri = &((sip_hdr_value_t *)val)->cftr_uri; } else { req_uri = &_dialog->sip_dlg_req_uri; } uri = (char *)malloc(req_uri->sip_str_len + 1); if (uri == NULL) return (NULL); (void) strncpy(uri, req_uri->sip_str_ptr, req_uri->sip_str_len); uri[req_uri->sip_str_len] = '\0'; return (uri);}/* Free the route set. */voidsip_dialog_free_rset(sip_dlg_route_set_t *rset){ sip_dlg_route_set_t *next; while (rset != NULL) { next = rset->sip_dlg_route_next; rset->sip_dlg_route_next = NULL; free(rset->sip_dlg_route); free(rset); rset = next; }}/* Recompute route-set */static intsip_dlg_recompute_rset(_sip_dialog_t *dialog, _sip_msg_t *sip_msg, int what){ int ret; if (dialog->sip_dlg_route_set != NULL) { sip_free_header(dialog->sip_dlg_route_set); dialog->sip_dlg_route_set = NULL; } if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) { free(dialog->sip_dlg_req_uri.sip_str_ptr); dialog->sip_dlg_req_uri.sip_str_ptr = NULL; dialog->sip_dlg_req_uri.sip_str_len = 0; } if (dialog->sip_dlg_rset.sip_str_ptr != NULL) { free(dialog->sip_dlg_rset.sip_str_ptr); dialog->sip_dlg_rset.sip_str_ptr = NULL; dialog->sip_dlg_rset.sip_str_len = 0; } ret = sip_dialog_get_route_set(dialog, sip_msg, what); return (ret);}/* * If the route set is empty, the UAC MUST place the remote target URI * into the Request-URI. The UAC MUST NOT add a Route header field to * the request. * * If the route set is not empty, and the first URI in the route set * contains the lr parameter (see Section 19.1.1), the UAC MUST place * the remote target URI into the Request-URI and MUST include a Route * header field containing the route set values in order, including all * parameters. * * If the route set is not empty, and its first URI does not contain the * lr parameter, the UAC MUST place the first URI from the route set * into the Request-URI, stripping any parameters that are not allowed * in a Request-URI. The UAC MUST add a Route header field containing * the remainder of the route set values in order, including all * parameters. The UAC MUST then place the remote target URI into the * Route header field as the last value. */intsip_dialog_set_route_hdr(_sip_dialog_t *dialog, sip_dlg_route_set_t *rset_head, int rcnt, int rlen){ size_t rset_len; _sip_header_t *rhdr; char *rset; char *rp; char *rsp; int count; sip_dlg_route_set_t *route; boolean_t first = B_TRUE; const sip_str_t *to_uri; char *uri = NULL; int rspl; int rpl; assert(rcnt > 0); dialog->sip_dlg_rset.sip_str_len = rlen + rcnt - 1; dialog->sip_dlg_rset.sip_str_ptr = malloc(rlen + rcnt); if (dialog->sip_dlg_rset.sip_str_ptr == NULL) return (ENOMEM); rsp = dialog->sip_dlg_rset.sip_str_ptr; rspl = rlen + rcnt; route = rset_head; rset_len = rlen; if (!route->sip_dlg_route_lr) { const struct sip_value *val; val = sip_get_header_value(dialog->sip_dlg_remote_target, NULL); to_uri = &((sip_hdr_value_t *)val)->cftr_uri; uri = (char *)malloc(to_uri->sip_str_len + 1); if (uri == NULL) { free(dialog->sip_dlg_rset.sip_str_ptr); dialog->sip_dlg_rset.sip_str_len = 0; dialog->sip_dlg_rset.sip_str_ptr = NULL; return (ENOMEM); } (void) strncpy(uri, to_uri->sip_str_ptr, to_uri->sip_str_len); uri[to_uri->sip_str_len] = '\0'; rset_len = rlen - strlen(route->sip_dlg_route) + strlen(uri) + SIP_SPACE + sizeof (char) + SIP_SPACE + sizeof (char); count = snprintf(rsp, rspl, "%s", route->sip_dlg_route); dialog->sip_dlg_req_uri.sip_str_ptr = malloc( route->sip_dlg_ruri.sip_str_len + 1); if (dialog->sip_dlg_req_uri.sip_str_ptr == NULL) { free(uri); free(dialog->sip_dlg_rset.sip_str_ptr); dialog->sip_dlg_rset.sip_str_len = 0; dialog->sip_dlg_rset.sip_str_ptr = NULL; return (ENOMEM); } (void) strncpy(dialog->sip_dlg_req_uri.sip_str_ptr, rsp + (route->sip_dlg_ruri.sip_str_ptr - route->sip_dlg_route), route->sip_dlg_ruri.sip_str_len); dialog->sip_dlg_req_uri.sip_str_ptr[ route->sip_dlg_ruri.sip_str_len] = '\0'; dialog->sip_dlg_req_uri.sip_str_len = route->sip_dlg_ruri.sip_str_len; rsp += count; rspl -= count; route = route->sip_dlg_route_next; } /* rcnt - 1 is for the number of COMMAs */ rset_len += strlen(SIP_ROUTE) + SIP_SPACE + sizeof (char) + SIP_SPACE + rcnt - 1; rset = malloc(rset_len + 1); if (rset == NULL) { free(dialog->sip_dlg_rset.sip_str_ptr); dialog->sip_dlg_rset.sip_str_len = 0; dialog->sip_dlg_rset.sip_str_ptr = NULL; return (ENOMEM); } rhdr = sip_new_header(rset_len + strlen(SIP_CRLF)); if (rhdr == NULL) { free(rset); free(dialog->sip_dlg_rset.sip_str_ptr); dialog->sip_dlg_rset.sip_str_len = 0; dialog->sip_dlg_rset.sip_str_ptr = NULL; return (ENOMEM); } rp = rset; rpl = rset_len + 1; count = snprintf(rp, rpl, "%s %c ", SIP_ROUTE, SIP_HCOLON); rp += count; rpl -= count; while (route != NULL) { if (first) { count = snprintf(rp, rpl, "%s", route->sip_dlg_route); rp += count; rpl -= count; first = B_FALSE; if (uri != NULL) { count = snprintf(rsp, rspl, "%c%s", SIP_COMMA, route->sip_dlg_route); } else { count = snprintf(rsp, rspl, "%s", route->sip_dlg_route); } rsp += count; rspl -= count; } else { count = snprintf(rp, rpl, "%c%s", SIP_COMMA, route->sip_dlg_route); rp += count; rpl -= count; count = snprintf(rsp, rspl, "%c%s", SIP_COMMA, route->sip_dlg_route); rsp += count; rspl -= count; } route = route->sip_dlg_route_next; } assert(rsp <= dialog->sip_dlg_rset.sip_str_ptr + dialog->sip_dlg_rset.sip_str_len);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -