⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 t_reply.c

📁 用来作为linux中SIP SERVER,完成VOIP网络电话中服务器的功能
💻 C
📖 第 1 页 / 共 4 页
字号:
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*/,			p_msg, &len, &bm);		return _reply_light(trans,buf,len,code,text,			0, 0, /* no to-tag */lock, &bm);	}}/*if msg is set -> it will fake the env. vars conforming with the msg; if NULL * the env. will be restore to original */static inline void faked_env( struct cell *t,struct sip_msg *msg){	static enum route_mode backup_mode;	static struct cell *backup_t;	static unsigned int backup_msgid;	static struct usr_avp **backup_list;	static struct socket_info* backup_si;	if (msg) {		/* remember we are back in request processing, but process		 * a shmem-ed replica of the request; advertise it in rmode;		 * for example t_reply needs to know that		 */		backup_mode=rmode;		rmode=MODE_ONFAILURE;		/* also, tm actions look in beginning whether transaction is		 * set -- whether we are called from a reply-processing 		 * or a timer process, we need to set current transaction;		 * otherwise the actions would attempt to look the transaction		 * up (unnecessary overhead, refcounting)		 */		/* backup */		backup_t=get_t();		backup_msgid=global_msg_id;		/* fake transaction and message id */		global_msg_id=msg->id;		set_t(t);		/* make available the avp list from transaction */		backup_list = set_avp_list( &t->user_avps );		/* set default send address to the saved value */		backup_si=bind_address;		bind_address=t->uac[0].request.dst.send_sock;	} else {		/* restore original environment */		set_t(backup_t);		global_msg_id=backup_msgid;		rmode=backup_mode;		/* restore original avp list */		set_avp_list( backup_list );		bind_address=backup_si;	}}static inline int fake_req(struct sip_msg *faked_req, 				struct sip_msg *shmem_msg){	/* on_negative_reply faked msg now copied from shmem msg (as opposed	 * to zero-ing) -- more "read-only" actions (exec in particular) will	 * work from reply_route as they will see msg->from, etc.; caution,	 * rw actions may append some pkg stuff to msg, which will possibly be	 * never released (shmem is released in a single block) */	memcpy( faked_req, shmem_msg, sizeof(struct sip_msg));	/* if we set msg_id to something different from current's message	 * id, the first t_fork will properly clean new branch URIs */	faked_req->id=shmem_msg->id-1;	/* msg->parsed_uri_ok must be reset since msg_parsed_uri is	 * not cloned (and cannot be cloned) */	faked_req->parsed_uri_ok = 0;	/* new_uri can change -- make a private copy */	if (shmem_msg->new_uri.s!=0 && shmem_msg->new_uri.len!=0) {		faked_req->new_uri.s=pkg_malloc(shmem_msg->new_uri.len+1);		if (!faked_req->new_uri.s) {			LOG(L_ERR, "ERROR: fake_req: no uri/pkg mem\n");			goto error00;		}		faked_req->new_uri.len=shmem_msg->new_uri.len;		memcpy( faked_req->new_uri.s, shmem_msg->new_uri.s, 			faked_req->new_uri.len);		faked_req->new_uri.s[faked_req->new_uri.len]=0;	}	/* dst_uri can change ALSO!!! -- make a private copy */	if (shmem_msg->dst_uri.s!=0 && shmem_msg->dst_uri.len!=0) {		faked_req->dst_uri.s=pkg_malloc(shmem_msg->dst_uri.len+1);		if (!faked_req->dst_uri.s) {			LOG(L_ERR, "ERROR: fake_req: no uri/pkg mem\n");			goto error00;		}		faked_req->dst_uri.len=shmem_msg->dst_uri.len;		memcpy( faked_req->dst_uri.s, shmem_msg->dst_uri.s, 			faked_req->dst_uri.len);		faked_req->dst_uri.s[faked_req->dst_uri.len]=0;	}	return 1;error00:	return 0;}void inline static free_faked_req(struct sip_msg *faked_req, struct cell *t){	struct hdr_field *hdr;	if (faked_req->new_uri.s) {		pkg_free(faked_req->new_uri.s);		faked_req->new_uri.s = 0;	}	if (faked_req->dst_uri.s) {		pkg_free(faked_req->dst_uri.s);		faked_req->dst_uri.s = 0;	}	/* free all types of lump that were added in failure handlers */	del_nonshm_lump( &(faked_req->add_rm) );	del_nonshm_lump( &(faked_req->body_lumps) );	del_nonshm_lump_rpl( &(faked_req->reply_lump) );	/* free header's parsed structures that were added by failure handlers */	for( hdr=faked_req->headers ; hdr ; hdr=hdr->next ) {		if ( hdr->parsed && hdr_allocs_parse(hdr) &&		(hdr->parsed<(void*)t->uas.request ||		hdr->parsed>=(void*)t->uas.end_request)) {			/* header parsed filed doesn't point inside uas.request memory			 * chunck -> it was added by failure funcs.-> free it as pkg */			DBG("DBG:free_faked_req: removing hdr->parsed %d\n",					hdr->type);			clean_hdr_field(hdr);			hdr->parsed = 0;		}	}}/* return 1 if a failure_route processes */static inline int run_failure_handlers(struct cell *t, struct sip_msg *rpl,																	int code){	static struct sip_msg faked_req;	struct sip_msg *shmem_msg = t->uas.request;	int on_failure;	/* failure_route for a local UAC? */	if (!shmem_msg) {		LOG(L_WARN,"Warning: run_failure_handlers: no UAC support (%d, %d) \n",			t->on_negative, t->tmcb_hl.reg_types);		return 0;	}	/* don't start faking anything if we don't have to */	if ( !has_tran_tmcbs( t, TMCB_ON_FAILURE) && !t->on_negative ) {		LOG(L_WARN, 			"Warning: run_failure_handlers: no negative handler (%d, %d)\n",			t->on_negative, 			t->tmcb_hl.reg_types);		return 1;	}	if (!fake_req(&faked_req, shmem_msg)) {		LOG(L_ERR, "ERROR: run_failure_handlers: fake_req failed\n");		return 0;	}	/* fake also the env. conforming to the fake msg */	faked_env( t, &faked_req);	/* DONE with faking ;-) -> run the failure handlers */	if ( has_tran_tmcbs( t, TMCB_ON_FAILURE) ) {		run_trans_callbacks( TMCB_ON_FAILURE, t, &faked_req, rpl, code);	}	if (t->on_negative) {		/* avoid recursion -- if failure_route forwards, and does not 		 * set next failure route, failure_route will not be reentered		 * on failure */		on_failure = t->on_negative;		t->on_negative=0;		/* run a reply_route action if some was marked */		if (run_actions(failure_rlist[on_failure], &faked_req)<0)			LOG(L_ERR, "ERROR: run_failure_handlers: Error in do_action\n");	}	/* restore original environment and free the fake msg */	faked_env( t, 0);	free_faked_req(&faked_req,t);	/* if failure handler changed flag, update transaction context */	shmem_msg->flags = faked_req.flags;	return 1;}/* select a branch for forwarding; returns: * 0..X ... branch number * -1   ... error * -2   ... can't decide yet -- incomplete branches present */int t_pick_branch(int inc_branch, int inc_code, struct cell *t, int *res_code){	int lowest_b, lowest_s, b;	lowest_b=-1; lowest_s=999;	for ( b=0; b<t->nr_of_outgoings ; b++ ) {		/* "fake" for the currently processed branch */		if (b==inc_branch) {			if (inc_code<lowest_s) {				lowest_b=b;				lowest_s=inc_code;			}			continue;		}		/* skip 'empty branches' */		if (!t->uac[b].request.buffer) continue;		/* there is still an unfinished UAC transaction; wait now! */		if ( t->uac[b].last_received<200 ) 			return -2;		if ( t->uac[b].last_received<lowest_s ) {			lowest_b =b;			lowest_s = t->uac[b].last_received;		}	} /* find lowest branch */	*res_code=lowest_s;	return lowest_b;}/* This is the neurological point of reply processing -- called * from within a REPLY_LOCK, t_should_relay_response decides * how a reply shall be processed and how transaction state is * affected. * * Checks if the new reply (with new_code status) should be sent or not *  based on the current * transaction status. * Returns 	- branch number (0,1,...) which should be relayed *         -1 if nothing to be relayed */static enum rps t_should_relay_response( struct cell *Trans , int new_code,	int branch , int *should_store, int *should_relay,	branch_bm_t *cancel_bitmap, struct sip_msg *reply ){	int branch_cnt;	int picked_branch;	int picked_code;	int inv_through;	/* note: this code never lets replies to CANCEL go through;	   we generate always a local 200 for CANCEL; 200s are	   not relayed because it's not an INVITE transaction;	   >= 300 are not relayed because 200 was already sent	   out	*/	DBG("->>>>>>>>> T_code=%d, new_code=%d\n",Trans->uas.status,new_code);	inv_through=new_code>=200 && new_code<300 && is_invite(Trans);	/* if final response sent out, allow only INVITE 2xx  */	if ( Trans->uas.status >= 200 ) {		if (inv_through) {			DBG("DBG: t_should_relay_response: 200 INV after final sent\n");			*should_store=0;			Trans->uac[branch].last_received=new_code;			*should_relay=branch;			return RPS_PUSHED_AFTER_COMPLETION;		} 		/* except the exception above, too late  messages will		   be discarded */		goto discard;	} 	/* if final response received at this branch, allow only INVITE 2xx */	if (Trans->uac[branch].last_received>=200			&& !(inv_through && Trans->uac[branch].last_received<300)) {		/* don't report on retransmissions */		if (Trans->uac[branch].last_received==new_code) {			DBG("DEBUG: final reply retransmission\n");			goto discard;		}		/* if you FR-timed-out, faked a local 408 and 487 came, don't		 * report on it either */		if (Trans->uac[branch].last_received==408 && new_code==487) {			DBG("DEBUG: 487 came for a timed-out branch\n");			goto discard;		}		/* this looks however how a very strange status rewrite attempt;		 * report on it */		LOG(L_ERR, "ERROR: t_should_relay_response: status rewrite by UAS: "			"stored: %d, received: %d\n",			Trans->uac[branch].last_received, new_code );		goto discard;	}	/* no final response sent yet */	/* negative replies subject to fork picking */	if (new_code >=300 ) {		Trans->uac[branch].last_received=new_code;		/* if all_final return lowest */		picked_branch=t_pick_branch(branch,new_code, Trans, &picked_code);		if (picked_branch==-2) { /* branches open yet */			*should_store=1;			*should_relay=-1;			return RPS_STORE;		}		if (picked_branch==-1) {			LOG(L_CRIT, "ERROR: t_should_relay_response: lowest==-1\n");			goto error;		}		/* no more pending branches -- try if that changes after		   a callback; save branch count to be able to determine		   later if new branches were initiated */		branch_cnt=Trans->nr_of_outgoings;		/* run ON_FAILURE handlers ( route and callbacks) */		if ( has_tran_tmcbs( Trans, TMCB_ON_FAILURE_RO|TMCB_ON_FAILURE)		|| Trans->on_negative ) {			run_failure_handlers( Trans,				picked_branch==branch?reply:Trans->uac[picked_branch].reply, 				picked_code);		}		/* look if the callback perhaps replied transaction; it also		   covers the case in which a transaction is replied localy		   on CANCEL -- then it would make no sense to proceed to		   new branches bellow		*/		if (Trans->uas.status >= 200) {			*should_store=0;			*should_relay=-1;			/* this might deserve an improvement -- if something			   was already replied, it was put on wait and then,			   returning RPS_COMPLETED will make t_on_reply			   put it on wait again; perhaps splitting put_on_wait			   from send_reply or a new RPS_ code would be healthy			*/			return RPS_COMPLETED;		}		/* look if the callback/failure_route introduced new branches ... */		if (branch_cnt<Trans->nr_of_outgoings)  {			/* await then result of new branches */			*should_store=1;			*should_relay=-1;			return RPS_STORE;		}		/* really no more pending branches -- return lowest code */		*should_store=0;		*should_relay=picked_branch;		/* we dont need 'which_cancel' here -- all branches 		   known to have completed */		/* which_cancel( Trans, cancel_bitmap ); */		return RPS_COMPLETED;	} 	/* not >=300 ... it must be 2xx or provisional 1xx */	if (new_code>=100) {		/* 1xx and 2xx except 100 will be relayed */		Trans->uac[branch].last_received=new_code;		*should_store=0;		*should_relay= new_code==100? -1 : branch;		if (new_code>=200 ) {			which_cancel( Trans, cancel_bitmap );			return RPS_COMPLETED;		} else return RPS_PROVISIONAL;	}error:	/* reply_status didn't match -- it must be something weird */	LOG(L_CRIT, "ERROR: Oh my gooosh! We don't know whether to relay %d\n",		new_code);discard:	*should_store=0;	*should_relay=-1;	return RPS_DISCARDED;}/* Retransmits the last sent inbound reply. * input: p_msg==request for which I want to retransmit an associated reply * Returns  -1 - error *           1 - OK */int t_retransmit_reply( struct cell *t ){	static char b[BUF_SIZE];	int len;	/* 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 (!t->uas.response.dst.send_sock) {		LOG(L_WARN, "WARNING: t_retransmit_reply: "			"no resolved dst to retransmit\n");		return -1;	}	/* we need to lock the transaction as messages from	   upstream may change it continuously	*/	LOCK_REPLIES( t );	if (!t->uas.response.buffer) {		DBG("DBG: t_retransmit_reply: nothing to retransmit\n");		goto error;	}	len=t->uas.response.buffer_len;	if ( len==0 || len>BUF_SIZE )  {		DBG("DBG: t_retransmit_reply: "			"zero length or too big to retransmit: %d\n", len);		goto error;	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -