📄 t_reply.c
字号:
/* * $Id: t_reply.c,v 1.98.2.5 2005/09/01 13:53:01 andrei 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-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-09-01 reverted to the old way of checking response.dst.send_sock * in t_retransmit_reply & reply_light (andrei) */#include "../../comp_defs.h"#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 "defs.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"/* restart fr timer on each provisional reply, default yes */int restart_fr_on_each_reply=1;/* are we processing original or shmemed request ? */enum route_mode rmode=MODE_REQUEST;/* private place where we create to-tags for replies *//* janakj: made public, I need to access this value to store it in dialogs */char tm_tags[TOTAG_VALUE_LEN];/* bogdan: pack tm_tag buffer and len into a str to pass them to * build_res_buf_from_sip_req() */static str tm_tag = {tm_tags,TOTAG_VALUE_LEN};char *tm_tag_suffix;/* 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;/* 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 get_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 get_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, "SER-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,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 an ACK to a negative reply */static char *build_ack(struct sip_msg* rpl,struct cell *trans,int branch, unsigned int *ret_len){ str to; if (parse_headers(rpl,HDR_TO, 0)==-1 || !rpl->to ) { LOG(L_ERR, "ERROR: build_ack: " "cannot generate a HBH ACK if key HFs in reply missing\n"); return NULL; } to.s=rpl->to->name.s; to.len=rpl->to->len; return build_local( trans, branch, ret_len, ACK, ACK_LEN, &to );}/* * The function builds an ACK to 200 OK of local transactions, honor the * route set, the URI to which the message should be sent will be returned * in next_hop parameter */static char *build_local_ack(struct sip_msg* rpl, struct cell *trans, int branch, unsigned int *ret_len, str* next_hop){ str to; if (parse_headers(rpl, HDR_EOH, 0) == -1 || !rpl->to) { LOG(L_ERR, "ERROR: build_local_ack: Error while parsing headers\n"); return 0; } to.s = rpl->to->name.s; to.len = rpl->to->len; return build_dlg_ack(rpl, trans, branch, &to, ret_len, next_hop);} /* * The function is used to send a localy generated ACK to INVITE * (tm generates the ACK on behalf of application using UAC */static int send_local_ack(struct sip_msg* msg, str* next_hop, char* ack, int ack_len){ struct socket_info* send_sock; union sockaddr_union to_su; if (!next_hop) { LOG(L_ERR, "send_local_ack: Invalid parameter value\n"); return -1; } send_sock = uri2sock(msg, next_hop, &to_su, PROTO_NONE); if (!send_sock) { LOG(L_ERR, "send_local_ack: no socket found\n"); return -1; } return msg_send(send_sock, send_sock->proto, &to_su, 0, ack, ack_len);}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: _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: _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 ? len : len + REPLY_OVERBUFFER_LEN; rb->buffer = (char*)shm_resize( rb->buffer, buf_len ); /* puts the reply's buffer to uas.response */ if (! rb->buffer ) { LOG(L_ERR, "ERROR: _reply_light: cannot allocate shmem buffer\n"); goto error3; } update_local_tags(trans, bm, rb->buffer, buf); rb->buffer_len = len ; memcpy( rb->buffer , buf , len ); /* needs to be protected too because what timers are set depends on current transactions status */ /* t_update_timers_after_sending_reply( rb ); */ update_reply_stats( code ); trans->relaied_reply_branch=-2; tm_stats->replied_localy++; 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: local transaction completed from _reply\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) ) run_trans_callbacks( TMCB_RESPONSE_OUT, trans, trans->uas.request, FAKED_REPLY, code); } cleanup_uac_timers( trans ); if (is_invite(trans)) cancel_uacs( trans, cancel_bitmap ); set_final_timer( trans ); } /* send it out */ /* first check if we managed to resolve topmost Via -- if not yet, don't try to retransmit */ /* response.dst.send_sock might be unset if the process that created the original transaction has not finished initialising the retransmission buffer (see t_newtran/ init_rb). If reply_to_via is set and via contains a host name (and not an ip) the chances for this increase a lot. */ if (!trans->uas.response.dst.send_sock) { LOG(L_ERR, "ERROR: _reply_light: no resolved dst to send reply to\n"); } else { SEND_PR_BUFFER( rb, buf, len ); DBG("DEBUG: reply sent out. buf=%p: %.9s..., shmem=%p: %.9s\n", buf, buf, rb->buffer, rb->buffer ); } pkg_free( buf ) ; DBG("DEBUG: _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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -