📄 dlg.c
字号:
/* * $Id: dlg.c,v 1.16 2004/08/24 09:00:40 janakj Exp $ * * Copyright (C) 2001-2003 FhG Fokus * * This file is part of ser, a free SIP server. * * ser is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * For a license to use the ser software under conditions * other than those described here, or to purchase support for this * software, please contact iptel.org by e-mail at the following addresses: * info@iptel.org * * ser is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * ------- * 2003-03-29 Created by janakj * 2003-07-08 added wrapper to calculate_hooks, needed by b2bua (dcm) */#include <string.h>#include "../../mem/shm_mem.h"#include "../../dprint.h"#include "../../parser/contact/parse_contact.h"#include "../../parser/parse_to.h"#include "../../parser/parse_from.h"#include "../../parser/parse_uri.h"#include "../../trim.h"#include "../../ut.h"#include "../../config.h"#include "dlg.h"#include "t_reply.h"#include "../../parser/parser_f.h"#define NORMAL_ORDER 0 /* Create route set in normal order - UAS */#define REVERSE_ORDER 1 /* Create route set in reverse order - UAC */#define ROUTE_PREFIX "Route: "#define ROUTE_PREFIX_LEN (sizeof(ROUTE_PREFIX) - 1)#define ROUTE_SEPARATOR "," CRLF " "#define ROUTE_SEPARATOR_LEN (sizeof(ROUTE_SEPARATOR) - 1)/*** Temporary hack ! *//* * This function skips name part * uri parsed by parse_contact must be used * (the uri must not contain any leading or * trailing part and if angle bracket were * used, right angle bracket must be the * last character in the string) * * _s will be modified so it should be a tmp * copy */void get_raw_uri(str* _s){ char* aq; if (_s->s[_s->len - 1] == '>') { aq = find_not_quoted(_s, '<'); _s->len -= aq - _s->s + 2; _s->s = aq + 1; }}/* * Make a copy of a str structure using shm_malloc */static inline int str_duplicate(str* _d, str* _s){ _d->s = shm_malloc(_s->len); if (!_d->s) { LOG(L_ERR, "str_duplicate(): No memory left\n"); return -1; } memcpy(_d->s, _s->s, _s->len); _d->len = _s->len; return 0;}/* * Calculate dialog hooks */static inline int calculate_hooks(dlg_t* _d){ str* uri; struct sip_uri puri; param_hooks_t hooks; param_t* params; if (_d->route_set) { uri = &_d->route_set->nameaddr.uri; if (parse_uri(uri->s, uri->len, &puri) < 0) { LOG(L_ERR, "calculate_hooks(): Error while parsing URI\n"); return -1; } if (parse_params(&puri.params, CLASS_URI, &hooks, ¶ms) < 0) { LOG(L_ERR, "calculate_hooks(): Error while parsing parameters\n"); return -2; } free_params(params); if (hooks.uri.lr) { if (_d->rem_target.s) _d->hooks.request_uri = &_d->rem_target; else _d->hooks.request_uri = &_d->rem_uri; _d->hooks.next_hop = &_d->route_set->nameaddr.uri; _d->hooks.first_route = _d->route_set; } else { _d->hooks.request_uri = &_d->route_set->nameaddr.uri; _d->hooks.next_hop = _d->hooks.request_uri; _d->hooks.first_route = _d->route_set->next; _d->hooks.last_route = &_d->rem_target; } } else { if (_d->rem_target.s) _d->hooks.request_uri = &_d->rem_target; else _d->hooks.request_uri = &_d->rem_uri; _d->hooks.next_hop = _d->hooks.request_uri; } if ((_d->hooks.request_uri) && (_d->hooks.request_uri->s) && (_d->hooks.request_uri->len)) { _d->hooks.ru.s = _d->hooks.request_uri->s; _d->hooks.ru.len = _d->hooks.request_uri->len; _d->hooks.request_uri = &_d->hooks.ru; get_raw_uri(_d->hooks.request_uri); } if ((_d->hooks.next_hop) && (_d->hooks.next_hop->s) && (_d->hooks.next_hop->len)) { _d->hooks.nh.s = _d->hooks.next_hop->s; _d->hooks.nh.len = _d->hooks.next_hop->len; _d->hooks.next_hop = &_d->hooks.nh; get_raw_uri(_d->hooks.next_hop); } return 0;}/* * wrapper to calculate_hooks * added by dcm */int w_calculate_hooks(dlg_t* _d){ return calculate_hooks(_d);}/* * Create a new dialog */int new_dlg_uac(str* _cid, str* _ltag, unsigned int _lseq, str* _luri, str* _ruri, dlg_t** _d){ dlg_t* res; if (!_cid || !_ltag || !_luri || !_ruri || !_d) { LOG(L_ERR, "new_dlg_uac(): Invalid parameter value\n"); return -1; } res = (dlg_t*)shm_malloc(sizeof(dlg_t)); if (res == 0) { LOG(L_ERR, "new_dlg_uac(): No memory left\n"); return -2; } /* Clear everything */ memset(res, 0, sizeof(dlg_t)); /* Make a copy of Call-ID */ if (str_duplicate(&res->id.call_id, _cid) < 0) return -3; /* Make a copy of local tag (usually From tag) */ if (str_duplicate(&res->id.loc_tag, _ltag) < 0) return -4; /* Make a copy of local URI (usually From) */ if (str_duplicate(&res->loc_uri, _luri) < 0) return -5; /* Make a copy of remote URI (usually To) */ if (str_duplicate(&res->rem_uri, _ruri) < 0) return -6; /* Make a copy of local sequence (usually CSeq) */ res->loc_seq.value = _lseq; /* And mark it as set */ res->loc_seq.is_set = 1; *_d = res; if (calculate_hooks(*_d) < 0) { LOG(L_ERR, "new_dlg_uac(): Error while calculating hooks\n"); /* FIXME: free everything here */ shm_free(res); return -2; } return 0;}/* * Parse Contact header field body and extract URI * Does not parse headers !! */static inline int get_contact_uri(struct sip_msg* _m, str* _uri){ contact_t* c; _uri->len = 0; if (!_m->contact) return 1; if (parse_contact(_m->contact) < 0) { LOG(L_ERR, "get_contact_uri(): Error while parsing Contact body\n"); return -2; } c = ((contact_body_t*)_m->contact->parsed)->contacts; if (!c) { LOG(L_ERR, "get_contact_uri(): Empty body or * contact\n"); return -3; } _uri->s = c->uri.s; _uri->len = c->uri.len; return 0;}/* * Extract tag from To header field of a response * Doesn't parse message headers !! */static inline int get_to_tag(struct sip_msg* _m, str* _tag){ if (!_m->to) { LOG(L_ERR, "get_to_tag(): To header field missing\n"); return -1; } if (get_to(_m)->tag_value.len) { _tag->s = get_to(_m)->tag_value.s; _tag->len = get_to(_m)->tag_value.len; } else { _tag->len = 0; } return 0;}/* * Extract tag from From header field of a request */static inline int get_from_tag(struct sip_msg* _m, str* _tag){ if (parse_from_header(_m) == -1) { LOG(L_ERR, "get_from_tag(): Error while parsing From header\n"); return -1; } if (get_from(_m)->tag_value.len) { _tag->s = get_from(_m)->tag_value.s; _tag->len = get_from(_m)->tag_value.len; } else { _tag->len = 0; } return 0;}/* * Extract Call-ID value * Doesn't parse headers !! */static inline int get_callid(struct sip_msg* _m, str* _cid){ if (_m->callid == 0) { LOG(L_ERR, "get_callid(): Call-ID not found\n"); return -1; } _cid->s = _m->callid->body.s; _cid->len = _m->callid->body.len; trim(_cid); return 0;}/* * Create a copy of route set either in normal or reverse order */static inline int get_route_set(struct sip_msg* _m, rr_t** _rs, unsigned char _order){ struct hdr_field* ptr; rr_t* last, *p, *t; last = 0; ptr = _m->record_route; while(ptr) { if (ptr->type == HDR_RECORDROUTE) { if (parse_rr(ptr) < 0) { LOG(L_ERR, "get_route_set(): Error while parsing Record-Route body\n"); goto error; } p = (rr_t*)ptr->parsed; while(p) { if (shm_duplicate_rr(&t, p) < 0) { LOG(L_ERR, "get_route_set(): Error while duplicating rr_t\n"); goto error; } if (_order == NORMAL_ORDER) { if (!*_rs) *_rs = t; if (last) last->next = t; last = t; } else { t->next = *_rs; *_rs = t; } p = p->next; } } ptr = ptr->next; } return 0; error: shm_free_rr(_rs); return -1;}/* * Extract all necessary information from a response and put it * in a dialog structure */static inline int response2dlg(struct sip_msg* _m, dlg_t* _d){ str contact, rtag; /* Parse the whole message, we will need all Record-Route headers */ if (parse_headers(_m, HDR_EOH, 0) == -1) { LOG(L_ERR, "response2dlg(): Error while parsing headers\n"); return -1; } if (get_contact_uri(_m, &contact) < 0) return -2; if (contact.len && str_duplicate(&_d->rem_target, &contact) < 0) return -3; if (get_to_tag(_m, &rtag) < 0) goto err1; if (rtag.len && str_duplicate(&_d->id.rem_tag, &rtag) < 0) goto err1; if (get_route_set(_m, &_d->route_set, REVERSE_ORDER) < 0) goto err2; return 0; err2: if (_d->id.rem_tag.s) shm_free(_d->id.rem_tag.s); _d->id.rem_tag.s = 0; _d->id.rem_tag.len = 0; err1: if (_d->rem_target.s) shm_free(_d->rem_target.s); _d->rem_target.s = 0; _d->rem_target.len = 0; return -4;}/* * Handle dialog in DLG_NEW state, we will be processing the * first response */static inline int dlg_new_resp_uac(dlg_t* _d, struct sip_msg* _m){ int code; /* * Dialog is in DLG_NEW state, we will copy remote * target URI, remote tag if present, and route-set * if present. And we will transit into DLG_CONFIRMED * if the response was 2xx and to DLG_DESTROYED if the * request was a negative final response. */ code = _m->first_line.u.reply.statuscode; if (code < 200) { /* A provisional response, do nothing, we could * update remote tag and route set but we will do that * for a positive final response anyway and I don't want * bet on presence of these fields in provisional responses * * Send a request to jan@iptel.org if you need to update * the structures here */ } else if ((code >= 200) && (code < 299)) { /* A final response, update the structures and transit * into DLG_CONFIRMED */ if (response2dlg(_m, _d) < 0) return -1; _d->state = DLG_CONFIRMED; if (calculate_hooks(_d) < 0) { LOG(L_ERR, "dlg_new_resp_uac(): Error while calculating hooks\n"); return -2; } } else { /* * A negative final response, mark the dialog as destroyed * Again, I do not update the structures here because it * makes no sense to me, a dialog shouldn't be used after * it is destroyed */ _d->state = DLG_DESTROYED; /* Signalize the termination with positive return value */ return 1; } return 0;}/* * Handle dialog in DLG_EARLY state, we will be processing either * next provisional response or a final response */static inline int dlg_early_resp_uac(dlg_t* _d, struct sip_msg* _m){ int code; code = _m->first_line.u.reply.statuscode; if (code < 200) { /* We are in early state already, do nothing */ } else if ((code >= 200) && (code <= 299)) { /* Same as in dlg_new_resp_uac */ /* A final response, update the structures and transit * into DLG_CONFIRMED */ if (response2dlg(_m, _d) < 0) return -1; _d->state = DLG_CONFIRMED; if (calculate_hooks(_d) < 0) { LOG(L_ERR, "dlg_early_resp_uac(): Error while calculating hooks\n"); return -2; } } else { /* Else terminate the dialog */ _d->state = DLG_DESTROYED; /* Signalize the termination with positive return value */ return 1; } return 0;}/* * Extract method from CSeq header field */static inline int get_cseq_method(struct sip_msg* _m, str* _method){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -