📄 t_fwd.c
字号:
/* * $Id: t_fwd.c,v 1.26 2006/05/30 15:41:57 bogdan_iancu Exp $ * * Copyright (C) 2001-2003 FhG Fokus * * This file is part of openser, a free SIP server. * * openser 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 * * openser 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-02-13 proto support added (andrei) * 2003-02-24 s/T_NULL/T_NULL_CELL/ to avoid redefinition conflict w/ * nameser_compat.h (andrei) * 2003-03-01 kr set through a function now (jiri) * 2003-03-06 callbacks renamed; "blind UAC" introduced, which makes * transaction behave as if it was forwarded even if it was * not -- good for local UAS, like VM (jiri) * 2003-03-19 replaced all the mallocs/frees w/ pkg_malloc/pkg_free (andrei) * 2003-03-30 we now watch downstream delivery and if it fails, send an * error message upstream (jiri) * 2003-04-14 use protocol from uri (jiri) * 2003-12-04 global TM callbacks switched to per transaction callbacks * (bogdan) * 2004-02-13: t->is_invite and t->local replaced with flags (bogdan) */#include "../../dprint.h"#include "../../config.h"#include "../../ut.h"#include "../../dset.h"#include "../../timer.h"#include "../../hash_func.h"#include "../../globals.h"#include "../../action.h"#include "../../data_lump.h"#include "../../usr_avp.h"#include "../../mem/mem.h"#include "../../parser/parser_f.h"#include "t_funcs.h"#include "t_hooks.h"#include "t_msgbuilder.h"#include "ut.h"#include "t_cancel.h"#include "t_lookup.h"#include "t_fwd.h"#include "fix_lumps.h"#include "path.h"#include "config.h"/* route to execute for the branches */static int goto_on_branch;unsigned int gflags_mask = 0xffffffff;int _tm_branch_index = 0;void t_on_branch( unsigned int go_to ){ struct cell *t = get_t(); /* in MODE_REPLY and MODE_ONFAILURE T will be set to current transaction; * in MODE_REQUEST T will be set only if the transaction was already * created; if not -> use the static variable */ if (route_type==BRANCH_ROUTE || !t || t==T_UNDEFINED ) goto_on_branch=go_to; else t->on_branch = go_to;}unsigned int get_on_branch(){ return goto_on_branch;}static inline int pre_print_uac_request( struct cell *t, int branch, struct sip_msg *request){ int backup_route_type; struct usr_avp **backup_list; char *p; /* ... we calculate branch ... */ if (!t_calc_branch(t, branch, request->add_to_branch_s, &request->add_to_branch_len )) { LOG(L_ERR, "ERROR:pre_print_uac_request: branch computation failed\n"); goto error; } /* from now on, flag all new lumps with LUMPFLAG_BRANCH flag in order to * be able to remove them later --bogdan */ set_init_lump_flags(LUMPFLAG_BRANCH); /* add path vector as Route HF */ if (request->path_vec.s && request->path_vec.len) { if (insert_path_as_route(request, &request->path_vec) < 0) goto error; } /********** run route & callback ************/ /* run branch route, if any; run it before RURI's DNS lookup * to allow to be changed --bogdan */ if (t->on_branch) { /* need to pkg_malloc the dst_uri */ if ( request->dst_uri.len ) { if ( (p=pkg_malloc(request->dst_uri.len))==0 ) { LOG(L_ERR,"ERROR:tm:pre_print_uac_request: no more pkg mem\n"); ser_error=E_OUT_OF_MEM; goto error; } memcpy( p, request->dst_uri.s, request->dst_uri.len); request->dst_uri.s = p; } /* need to pkg_malloc the new_uri */ if ( (p=pkg_malloc(request->new_uri.len))==0 ) { LOG(L_ERR,"ERROR:tm:pre_print_uac_request: no more pkg mem\n"); ser_error=E_OUT_OF_MEM; goto error; } memcpy( p, request->new_uri.s, request->new_uri.len); request->new_uri.s = p; /* make available the avp list from transaction */ backup_list = set_avp_list( &t->user_avps ); /* run branch route */ swap_route_type( backup_route_type, BRANCH_ROUTE); _tm_branch_index = branch+1; if (run_top_route(branch_rlist[t->on_branch], request)&ACT_FL_DROP) { DBG("DEBUG:tm:pre_print_uac_request: dropping branch <%.*s>\n", request->new_uri.len, request->new_uri.s); _tm_branch_index = 0; goto error; } _tm_branch_index = 0; set_route_type( backup_route_type ); /* restore original avp list */ set_avp_list( backup_list ); } /* run the specific callbacks for this transaction */ run_trans_callbacks( TMCB_REQUEST_FWDED, t, request, 0, -request->REQ_METHOD); return 0;error: return -1;}/* be aware and use it *all* the time between pre_* and post_* functions! */static inline char *print_uac_request(struct sip_msg *i_req, unsigned int *len, struct socket_info *send_sock, enum sip_protos proto ){ char *buf, *shbuf; shbuf=0; /* build the shm buffer now */ buf=build_req_buf_from_sip_req( i_req, len, send_sock, proto ); if (!buf) { LOG(L_ERR, "ERROR:tm:print_uac_request: no pkg_mem\n"); ser_error=E_OUT_OF_MEM; goto error01; } shbuf=(char *)shm_malloc(*len); if (!shbuf) { ser_error=E_OUT_OF_MEM; LOG(L_ERR, "ERROR:tm:print_uac_request: no shmem\n"); goto error02; } memcpy( shbuf, buf, *len );error02: pkg_free( buf );error01: return shbuf;}static inline void post_print_uac_request(struct sip_msg *request, str *org_uri, str *org_dst){ reset_init_lump_flags(); /* delete inserted branch lumps */ del_flaged_lumps( &request->add_rm, LUMPFLAG_BRANCH); del_flaged_lumps( &request->body_lumps, LUMPFLAG_BRANCH); /* reset branch flags */ request->flags &= gflags_mask; /* free any potential new uri */ if (request->new_uri.s!=org_uri->s) { pkg_free(request->new_uri.s); /* and just to be sure */ request->new_uri.s = 0; request->new_uri.len = 0; request->parsed_uri_ok = 0; } /* free any potential dst uri */ if (request->dst_uri.s!=org_dst->s) { pkg_free(request->dst_uri.s); /* and just to be sure */ request->dst_uri.s = 0; request->dst_uri.len = 0; }}/* introduce a new uac, which is blind -- it only creates the data structures and starts FR timer, but that's it; it does not print messages and send anything anywhere; that is good for FIFO apps -- the transaction must look operationally and FR must be ticking, whereas the request is "forwarded" using a non-SIP way and will be replied the same way*/int add_blind_uac( /*struct cell *t*/ ){ unsigned short branch; struct cell *t; t=get_t(); if (t==T_UNDEFINED || !t ) { LOG(L_ERR, "ERROR: add_blind_uac: no transaction context\n"); return -1; } branch=t->nr_of_outgoings; if (branch==MAX_BRANCHES) { LOG(L_ERR, "ERROR: add_blind_uac: " "maximum number of branches exceeded\n"); return -1; } /* make sure it will be replied */ t->flags |= T_NOISY_CTIMER_FLAG; t->nr_of_outgoings++; /* start FR timer -- protocol set by default to PROTO_NONE, which means retransmission timer will not be started */ start_retr(&t->uac[branch].request); /* we are on a timer -- don't need to put on wait on script clean-up */ set_kr(REQ_FWDED); return 1; /* success */}/* introduce a new uac to transaction; returns its branch id (>=0) or error (<0); it doesn't send a message yet -- a reply to it might interfere with the processes of adding multiple branches*/int add_uac( struct cell *t, struct sip_msg *request, str *uri, str* next_hop, str* path, struct proxy_l *proxy){ int ret; short temp_proxy; union sockaddr_union to; unsigned short branch; struct socket_info* send_sock; char *shbuf; unsigned int len; branch=t->nr_of_outgoings; if (branch==MAX_BRANCHES) { LOG(L_ERR, "ERROR:tm:add_uac: maximum number of branches exceeded\n"); ret=E_CFG; goto error; } /* check existing buffer -- rewriting should never occur */ if (t->uac[branch].request.buffer.s) { LOG(L_CRIT, "ERROR:tm:add_uac: buffer rewrite attempt\n"); ret=ser_error=E_BUG; goto error; } /* set proper RURI to request to reflect the branch */ request->new_uri=*uri; request->parsed_uri_ok=0; request->dst_uri=*next_hop; request->path_vec=*path; if ( pre_print_uac_request( t, branch, request)!= 0 ) { ret = -1; goto error01; } /* check DNS resolution */ if (proxy){ temp_proxy=0; }else { proxy=uri2proxy( request->dst_uri.len ? &request->dst_uri:&request->new_uri, PROTO_NONE ); if (proxy==0) { ret=E_BAD_ADDRESS; goto error01; } temp_proxy=1; } if (proxy->ok==0) { if (proxy->host.h_addr_list[proxy->addr_idx+1]) proxy->addr_idx++; else proxy->addr_idx=0; proxy->ok=1; } hostent2su( &to, &proxy->host, proxy->addr_idx, proxy->port ? proxy->port:SIP_PORT); send_sock=get_send_socket( request, &to , proxy->proto); if (send_sock==0) { LOG(L_ERR, "ERROR:tm:add_uac: can't fwd to af %d, proto %d " " (no corresponding listening socket)\n", to.s.sa_family, proxy->proto ); ret=ser_error=E_NO_SOCKET; goto error02; } /* now message printing starts ... */ shbuf=print_uac_request( request, &len, send_sock, proxy->proto ); if (!shbuf) { ret=ser_error=E_OUT_OF_MEM; goto error02; } /* things went well, move ahead and install new buffer! */ t->uac[branch].request.dst.to=to; t->uac[branch].request.dst.send_sock=send_sock; t->uac[branch].request.dst.proto=proxy->proto; t->uac[branch].request.dst.proto_reserved1=0; t->uac[branch].request.buffer.s=shbuf; t->uac[branch].request.buffer.len=len; t->uac[branch].uri.s=t->uac[branch].request.buffer.s+ request->first_line.u.request.method.len+1; t->uac[branch].uri.len=request->new_uri.len; t->uac[branch].br_flags = request->flags&(~gflags_mask); t->nr_of_outgoings++; /* update stats */ proxy->tx++; proxy->tx_bytes+=len; /* done! */ ret=branch;error02: if (temp_proxy) { free_proxy( proxy ); pkg_free( proxy ); }error01: post_print_uac_request( request, uri, next_hop);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -