t_reply.c
来自「性能优秀的SIP Proxy」· C语言 代码 · 共 1,744 行 · 第 1/4 页
C
1,744 行
/* * $Id: t_reply.c,v 1.28 2006/06/27 14:58:33 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-01-19 faked lump list created in on_reply handlers * 2003-01-27 next baby-step to removing ZT - PRESERVE_ZT (jiri) * 2003-02-13 updated to use rb->dst (andrei) * 2003-02-18 replaced TOTAG_LEN w/ TOTAG_VALUE_LEN (TOTAG_LEN was defined * twice with different values!) (andrei) * 2003-02-28 scratchpad compatibility abandoned (jiri) * 2003-03-01 kr set through a function now (jiri) * 2003-03-06 saving of to-tags for ACK/200 matching introduced, * voicemail changes accepted, updated to new callback * names (jiri) * 2003-03-10 fixed new to tag bug/typo (if w/o {}) (andrei) * 2003-03-16 removed _TOTAG (jiri) * 2003-03-31 200 for INVITE/UAS resent even for UDP (jiri) * 2003-03-31 removed msg->repl_add_rm (andrei) * 2003-04-05 s/reply_route/failure_route, onreply_route introduced (jiri) * 2003-04-14 local acks generated before reply processing to avoid * delays in length reply processing (like opening TCP * connection to an unavailable destination) (jiri) * 2003-09-11 updates to new build_res_buf_from_sip_req() interface (bogdan) * 2003-09-11 t_reply_with_body() reshaped to use reply_lumps + * build_res_buf_from_sip_req() instead of * build_res_buf_with_body_from_sip_req() (bogdan) * 2003-11-05 flag context updated from failure/reply handlers back * to transaction context (jiri) * 2003-11-11: build_lump_rpl() removed, add_lump_rpl() has flags (bogdan) * 2003-12-04 global TM callbacks switched to per transaction callbacks * (bogdan) * 2004-02-06: support for user pref. added - destroy_avps (bogdan) * 2003-11-05 flag context updated from failure/reply handlers back * to transaction context (jiri) * 2003-11-11: build_lump_rpl() removed, add_lump_rpl() has flags (bogdan) * 2004-02-13: t->is_invite and t->local replaced with flags (bogdan) * 2004-02-18 fifo_t_reply imported from vm module (bogdan) * 2004-08-23 avp list is available from failure/on_reply routes (bogdan) * 2004-10-01 added a new param.: restart_fr_on_each_reply (andrei) * 2005-03-01 force for statefull replies the incoming interface of * the request (bogdan) * 2005-03-01 local ACK sent to same address as INVITE -> * all [build|send]_[local]_ack functions merged into * send_ack() (bogdan) */#include "../../hash_func.h"#include "../../dprint.h"#include "../../config.h"#include "../../parser/parser_f.h"#include "../../ut.h"#include "../../timer.h"#include "../../error.h"#include "../../action.h"#include "../../dset.h"#include "../../tags.h"#include "../../data_lump.h"#include "../../data_lump_rpl.h"#include "../../usr_avp.h"#include "../../fifo_server.h"#include "../../unixsock_server.h"#include "h_table.h"#include "t_hooks.h"#include "t_funcs.h"#include "t_reply.h"#include "t_cancel.h"#include "t_msgbuilder.h"#include "t_lookup.h"#include "t_fwd.h"#include "fix_lumps.h"#include "t_stats.h"#include "uac.h"/* restart fr timer on each provisional reply, default yes */int restart_fr_on_each_reply=1;/* private place where we create to-tags for replies */char tm_tags[TOTAG_VALUE_LEN];static str tm_tag = {tm_tags,TOTAG_VALUE_LEN};char *tm_tag_suffix;static int picked_branch=-1;/* where to go if there is no positive reply */static int goto_on_negative=0;/* where to go on receipt of reply */static int goto_on_reply=0;/* returns the picked branch */int t_get_picked_branch(){ return picked_branch;}/* we store the reply_route # in private memory which is then processed during t_relay; we cannot set this value before t_relay creates transaction context or after t_relay when a reply may arrive after we set this value; that's why we do it how we do it, i.e., *inside* t_relay using hints stored in private memory before t_relay is called*/void t_on_negative( 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 (!t || t==T_UNDEFINED ) goto_on_negative=go_to; else t->on_negative = go_to;}void t_on_reply( 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 (!t || t==T_UNDEFINED ) goto_on_reply=go_to; else t->on_reply = go_to;}unsigned int get_on_negative(){ return goto_on_negative;}unsigned int get_on_reply(){ return goto_on_reply;}void tm_init_tags(){ init_tags(tm_tags, &tm_tag_suffix, "OpenSER-TM/tags", TM_TAG_SEPARATOR );}/* returns 0 if the message was previously acknowledged * (i.e., no E2EACK callback is needed) and one if the * callback shall be executed */int unmatched_totag(struct cell *t, struct sip_msg *ack){ struct totag_elem *i; str *tag; if (parse_headers(ack, HDR_TO_F,0)==-1 || !ack->to ) { LOG(L_ERR, "ERROR: unmatched_totag: To invalid\n"); return 1; } tag=&get_to(ack)->tag_value; for (i=t->fwded_totags; i; i=i->next) { if (i->tag.len==tag->len && memcmp(i->tag.s, tag->s, tag->len)==0) { DBG("DEBUG: totag for e2e ACK found: %d\n", i->acked); /* to-tag recorded, and an ACK has been received for it */ if (i->acked) return 0; /* to-tag recorded, but this ACK came for the first time */ i->acked=1; return 1; } } /* surprising: to-tag never sighted before */ return 1;}static inline void update_local_tags(struct cell *trans, struct bookmark *bm, char *dst_buffer, char *src_buffer /* to which bm refers */){ if (bm->to_tag_val.s) { trans->uas.local_totag.s=bm->to_tag_val.s-src_buffer+dst_buffer; trans->uas.local_totag.len=bm->to_tag_val.len; }}/* append a newly received tag from a 200/INVITE to * transaction's set; (only safe if called from within * a REPLY_LOCK); it returns 1 if such a to tag already * exists */inline static int update_totag_set(struct cell *t, struct sip_msg *ok){ struct totag_elem *i, *n; str *tag; char *s; if (!ok->to || !ok->to->parsed) { LOG(L_ERR, "ERROR: update_totag_set: to not parsed\n"); return 0; } tag=&get_to(ok)->tag_value; if (!tag->s) { DBG("ERROR: update_totag_set: no tag in to\n"); return 0; } for (i=t->fwded_totags; i; i=i->next) { if (i->tag.len==tag->len && memcmp(i->tag.s, tag->s, tag->len) ==0 ){ /* to tag already recorded */#ifdef XL_DEBUG LOG(L_CRIT, "DEBUG: update_totag_set: totag retransmission\n");#else DBG("DEBUG: update_totag_set: totag retransmission\n");#endif return 1; } } /* that's a new to-tag -- record it */ shm_lock(); n=(struct totag_elem*) shm_malloc_unsafe(sizeof(struct totag_elem)); s=(char *)shm_malloc_unsafe(tag->len); shm_unlock(); if (!s || !n) { LOG(L_ERR, "ERROR: update_totag_set: no memory \n"); if (n) shm_free(n); if (s) shm_free(s); return 0; } memset(n, 0, sizeof(struct totag_elem)); memcpy(s, tag->s, tag->len ); n->tag.s=s;n->tag.len=tag->len; n->next=t->fwded_totags; t->fwded_totags=n; DBG("DEBUG: update_totag_set: new totag \n"); return 0;}/* * Build and send an ACK to a negative reply */static int send_ack(struct sip_msg* rpl, struct cell *trans, int branch){ str to; char *ack_p; unsigned int ack_len; if (parse_headers( rpl, is_local(trans)?HDR_EOH_F:HDR_TO_F, 0)==-1 || !rpl->to ) { LOG(L_ERR, "ERROR:tm:send_ack: " "cannot generate a HBH ACK if key HFs in reply missing\n"); goto error; } to.s=rpl->to->name.s; to.len=rpl->to->len; ack_p = is_local(trans)? build_dlg_ack(rpl, trans, branch, &to, &ack_len): build_local( trans, branch, &ack_len, ACK, ACK_LEN, &to ); if (ack_p==0) { LOG(L_ERR, "ERROR:tm:send_ack: failed to build ACK\n"); goto error; } SEND_PR_BUFFER(&trans->uac[branch].request, ack_p, ack_len); shm_free(ack_p); return 0;error: return -1;}static int _reply_light( struct cell *trans, char* buf, unsigned int len, unsigned int code, char * text, char *to_tag, unsigned int to_tag_len, int lock, struct bookmark *bm ){ struct retr_buf *rb; unsigned int buf_len; branch_bm_t cancel_bitmap; if (!buf) { DBG("DEBUG:tm:_reply_light: response building failed\n"); /* determine if there are some branches to be canceled */ if ( is_invite(trans) ) { if (lock) LOCK_REPLIES( trans ); which_cancel(trans, &cancel_bitmap ); if (lock) UNLOCK_REPLIES( trans ); } /* and clean-up, including cancellations, if needed */ goto error; } cancel_bitmap=0; if (lock) LOCK_REPLIES( trans ); if ( is_invite(trans) ) which_cancel(trans, &cancel_bitmap ); if (trans->uas.status>=200) { LOG( L_ERR, "ERROR:tm: _reply_light: can't generate %d reply" " when a final %d was sent out\n", code, trans->uas.status); goto error2; } rb = & trans->uas.response; rb->activ_type=code; trans->uas.status = code; buf_len = rb->buffer.s ? len : len + REPLY_OVERBUFFER_LEN; rb->buffer.s = (char*)shm_resize( rb->buffer.s, buf_len ); /* puts the reply's buffer to uas.response */ if (! rb->buffer.s ) { LOG(L_ERR,"ERROR:tm:_reply_light: cannot allocate shmem buffer\n"); goto error3; } update_local_tags(trans, bm, rb->buffer.s, buf); rb->buffer.len = len ; memcpy( rb->buffer.s , buf , len ); /* needs to be protected too because what timers are set depends on current transactions status */ /* t_update_timers_after_sending_reply( rb ); */ trans->relaied_reply_branch=-2; if (lock) UNLOCK_REPLIES( trans ); /* do UAC cleanup procedures in case we generated a final answer whereas there are pending UACs */ if (code>=200) { if ( is_local(trans) ) { DBG("DEBUG:tm:_reply_light: local transaction completed\n"); if ( has_tran_tmcbs(trans, TMCB_LOCAL_COMPLETED) ) { run_trans_callbacks( TMCB_LOCAL_COMPLETED, trans, 0, FAKED_REPLY, code); } } else { if ( has_tran_tmcbs(trans, TMCB_RESPONSE_OUT) ) { set_extra_tmcb_params( &rb->buffer, &rb->dst); run_trans_callbacks( TMCB_RESPONSE_OUT, trans, trans->uas.request, FAKED_REPLY, code); } } if (!is_hopbyhop_cancel(trans)) { cleanup_uac_timers( trans ); if (is_invite(trans)) cancel_uacs( trans, cancel_bitmap ); set_final_timer( trans ); } } /* send it out : response.dst.send_sock is valid all the time now, * as it's taken from original request -bogdan */ if (!trans->uas.response.dst.send_sock) { LOG(L_CRIT,"BUG:tm:_reply_light: send_sock is NULL\n"); } SEND_PR_BUFFER( rb, buf, len ); DBG("DEBUG:tm:_reply_light: reply sent out. buf=%p: %.9s..., " "shmem=%p: %.9s\n", buf, buf, rb->buffer.s, rb->buffer.s ); pkg_free( buf ) ; stats_trans_rpl( code, 1 /*local*/ ); DBG("DEBUG:tm:_reply_light: finished\n"); return 1;error3:error2: if (lock) UNLOCK_REPLIES( trans ); pkg_free ( buf );error: /* do UAC cleanup */ cleanup_uac_timers( trans ); if ( is_invite(trans) ) cancel_uacs( trans, cancel_bitmap ); /* we did not succeed -- put the transaction on wait */ put_on_wait(trans); return -1;}/* send a UAS reply * returns 1 if everything was OK or -1 for error */static int _reply( struct cell *trans, struct sip_msg* p_msg, unsigned int code, char * text, int lock ){ unsigned int len; char * buf, *dset; struct bookmark bm; int dset_len; if (code>=200) set_kr(REQ_RPLD); /* compute the buffer in private memory prior to entering lock; * create to-tag if needed */ /* if that is a redirection message, dump current message set to it */ if (code>=300 && code<400) { dset=print_dset(p_msg, &dset_len); if (dset) { add_lump_rpl(p_msg, dset, dset_len, LUMP_RPL_HDR); } } if (code>=180 && p_msg->to && (get_to(p_msg)->tag_value.s==0 || get_to(p_msg)->tag_value.len==0)) { calc_crc_suffix( p_msg, tm_tag_suffix ); buf = build_res_buf_from_sip_req(code,text, &tm_tag, p_msg, &len, &bm); return _reply_light( trans, buf, len, code, text, tm_tag.s, TOTAG_VALUE_LEN, lock, &bm); } else { buf = build_res_buf_from_sip_req(code,text, 0 /*no to-tag*/,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?