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

📄 t_lookup.c

📁 用来作为linux中SIP SERVER,完成VOIP网络电话中服务器的功能
💻 C
📖 第 1 页 / 共 3 页
字号:
			/* in case, we act as UAS for INVITE and reply with 200,			 * we will need to run dialog-matching for subsequent			 * ACK, for which we need From-tag; We also need from-tag			 * in case people want to have proxied e2e ACKs accounted			 */			if (p_msg->REQ_METHOD==METHOD_INVITE 							&& parse_from_header(p_msg)==-1) {				LOG(L_ERR, "ERROR: t_check: from parsing failed\n");				return -1;			}			t_lookup_request( p_msg , 0 /* unlock before returning */ );		} else {			/* we need Via for branch and Cseq method to distinguish			   replies with the same branch/cseqNr (CANCEL)			*/			if ( parse_headers(p_msg, HDR_VIA1|HDR_CSEQ, 0 )==-1			|| !p_msg->via1 || !p_msg->cseq ) {				LOG(L_ERR, "ERROR: reply cannot be parsed\n");				return -1;			}			/* if that is an INVITE, we will also need to-tag			   for later ACK matching			*/            if ( get_cseq(p_msg)->method.len==INVITE_LEN 				&& memcmp( get_cseq(p_msg)->method.s, INVITE, INVITE_LEN )==0 ) {					if (parse_headers(p_msg, HDR_TO, 0)==-1						|| !p_msg->to)  {						LOG(L_ERR, "ERROR: INVITE reply cannot be parsed\n");						return -1;					}			}			t_reply_matching( p_msg ,				param_branch!=0?param_branch:&local_branch );		}#ifdef EXTRA_DEBUG		if ( T && T!=T_UNDEFINED && T->damocles) {			LOG( L_ERR, "ERROR: transaction %p scheduled for deletion "				"and called from t_check\n", T);			abort();		}#endif		DBG("DEBUG: t_check: msg id=%d global id=%d T end=%p\n",			p_msg->id,global_msg_id,T);	} else {		if (T)			DBG("DEBUG: t_check: T already found!\n");		else			DBG("DEBUG: t_check: T previously sought and not found\n");	}	return T ? (T==T_UNDEFINED ? -1 : 1 ) : 0;}int init_rb( struct retr_buf *rb, struct sip_msg *msg){	/*struct socket_info* send_sock;*/	struct via_body* via;	int proto;	int backup_mhomed;	via=msg->via1;	if (!reply_to_via) {		update_sock_struct_from_ip( &rb->dst.to, msg );		proto=msg->rcv.proto;	} else {		/*init retrans buffer*/		if (update_sock_struct_from_via( &(rb->dst.to), msg, via )==-1) {			LOG(L_ERR, "ERROR: init_rb: cannot lookup reply dst: %.*s\n",				via->host.len, via->host.s );			ser_error=E_BAD_VIA;			return 0;		}		proto=via->proto;	}	rb->dst.proto=proto;	rb->dst.proto_reserved1=msg->rcv.proto_reserved1;	/* turn off mhomed for generating replies -- they are ideally sent to where	   request came from to make life with NATs and other beasts easier	*/	backup_mhomed=mhomed;	mhomed=0;	mhomed=backup_mhomed;	/* use for sending replies the incoming interface of the request -bogdan */	/*send_sock=get_send_socket(msg, &rb->dst.to, proto);	if (send_sock==0) {		LOG(L_ERR, "ERROR: init_rb: cannot fwd to af %d, proto %d "			"no socket\n", rb->dst.to.s.sa_family, proto);		ser_error=E_BAD_VIA;		return 0;	}*/	rb->dst.send_sock=msg->rcv.bind_address;	return 1;}static inline void init_new_t(struct cell *new_cell, struct sip_msg *p_msg){	struct sip_msg *shm_msg;	shm_msg=new_cell->uas.request;	new_cell->from.s=shm_msg->from->name.s;	new_cell->from.len=HF_LEN(shm_msg->from);	new_cell->to.s=shm_msg->to->name.s;	new_cell->to.len=HF_LEN(shm_msg->to);	new_cell->callid.s=shm_msg->callid->name.s;	new_cell->callid.len=HF_LEN(shm_msg->callid);	new_cell->cseq_n.s=shm_msg->cseq->name.s;	new_cell->cseq_n.len=get_cseq(shm_msg)->number.s		+get_cseq(shm_msg)->number.len		-shm_msg->cseq->name.s;	new_cell->method=new_cell->uas.request->first_line.u.request.method;	if (p_msg->REQ_METHOD==METHOD_INVITE) new_cell->flags |= T_IS_INVITE_FLAG;	new_cell->on_negative=get_on_negative();	new_cell->on_reply=get_on_reply();}static inline int new_t(struct sip_msg *p_msg){	struct cell *new_cell;	/* for ACK-dlw-wise matching, we want From-tags */	if (p_msg->REQ_METHOD==METHOD_INVITE && parse_from_header(p_msg)<0) {			LOG(L_ERR, "ERROR: new_t: no valid From in INVITE\n");			return E_BAD_REQ;	}	/* make sure uri will be parsed before cloning */	if (parse_sip_msg_uri(p_msg)<0) {		LOG(L_ERR, "ERROR: new_t: uri invalid\n");		return E_BAD_REQ;	}				/* add new transaction */	new_cell = build_cell( p_msg ) ;	if  ( !new_cell ){		LOG(L_ERR, "ERROR: new_t: out of mem:\n");		return E_OUT_OF_MEM;	} 	insert_into_hash_table_unsafe( new_cell, p_msg->hash_index );	set_t(new_cell);	INIT_REF_UNSAFE(T);	/* init pointers to headers needed to construct local	   requests such as CANCEL/ACK	*/	init_new_t(new_cell, p_msg);	return 1;}/* atomic "new_tran" construct; it returns:	<0	on error	+1	if a request did not match a transaction		- it that was an ack, the calling function		  shall forward statelessly		- otherwise it means, a new transaction was		  introduced and the calling function		  shall reply/relay/whatever_appropriate	0 on retransmission*/int t_newtran( struct sip_msg* p_msg ){	int lret, my_err;	/* is T still up-to-date ? */	DBG("DEBUG: t_newtran: msg id=%d , global msg id=%d ,"		" T on entrance=%p\n",p_msg->id,global_msg_id,T);	if ( T && T!=T_UNDEFINED  ) {		LOG(L_ERR, "ERROR: t_newtran: "			"transaction already in process %p\n", T );		return E_SCRIPT;	}	global_msg_id = p_msg->id;	T = T_UNDEFINED;	/* first of all, parse everything -- we will store in shared memory 	   and need to have all headers ready for generating potential replies 	   later; parsing later on demand is not an option since the request 	   will be in shmem and applying parse_headers to it would intermix 	   shmem with pkg_mem	*/		if (parse_headers(p_msg, HDR_EOH, 0 )) {		LOG(L_ERR, "ERROR: t_newtran: parse_headers failed\n");		return E_BAD_REQ;	}	if ((p_msg->parsed_flag & HDR_EOH)!=HDR_EOH) {			LOG(L_ERR, "ERROR: t_newtran: EoH not parsed\n");			return E_OUT_OF_MEM;	}	/* t_lookup_requests attempts to find the transaction; 	   it also calls check_transaction_quadruple -> it is	   safe to assume we have from/callid/cseq/to	*/ 	lret = t_lookup_request( p_msg, 1 /* leave locked if not found */ );	/* on error, pass the error in the stack ... nothing is locked yet	   if 0 is returned */	if (lret==0) return E_BAD_TUPEL;	/* transaction found, it's a retransmission  */	if (lret>0) {		if (p_msg->REQ_METHOD==METHOD_ACK) {			t_release_transaction(T);		} else {			t_retransmit_reply(T);		}		/* things are done -- return from script */		return 0;	}	/* from now on, be careful -- hash table is locked */	if (lret==-2) { /* was it an e2e ACK ? if so, trigger a callback */		/* no callbacks? complete quickly */		if ( !has_tran_tmcbs(t_ack,TMCB_E2EACK_IN) ) {			UNLOCK_HASH(p_msg->hash_index);			return 1;		} 		REF_UNSAFE(t_ack);		UNLOCK_HASH(p_msg->hash_index);		/* we don't call from within REPLY_LOCK -- that introduces		 * a race condition; however, it is so unlikely and the		 * impact is so small (callback called multiple times of		 * multiple ACK/200s received in parallel), that we do not		 * better waste time in locks  */		if (unmatched_totag(t_ack, p_msg)) {			run_trans_callbacks( TMCB_E2EACK_IN , t_ack, p_msg, 0,				-p_msg->REQ_METHOD );		}		UNREF(t_ack);		return 1;	} 	/* transaction not found, it's a new request (lret<0, lret!=-2);	   establish a new transaction ... */	if (p_msg->REQ_METHOD==METHOD_ACK) { /* ... unless it is in ACK */		my_err=1;		goto new_err;	}	my_err=new_t(p_msg);	if (my_err<0) {		LOG(L_ERR, "ERROR: t_newtran: new_t failed\n");		goto new_err;	}	UNLOCK_HASH(p_msg->hash_index);	/* now, when the transaction state exists, check if 	   there is a meaningful Via and calculate it; better 	   do it now than later: state is established so that 	   subsequent retransmissions will be absorbed and will  	  not possibly block during Via DNS resolution; doing	   it later would only burn more CPU as if there is an	   error, we cannot relay later whatever comes out of the  	   the transaction 	*/	if (!init_rb( &T->uas.response, p_msg)) {		LOG(L_ERR, "ERROR: t_newtran: unresolvable via1\n");		put_on_wait( T );		t_unref(p_msg);		return E_BAD_VIA;	}	return 1;new_err:	UNLOCK_HASH(p_msg->hash_index);	return my_err;}int t_unref( struct sip_msg* p_msg  ){	enum kill_reason kr;	if (T==T_UNDEFINED || T==T_NULL_CELL)		return -1;	if (p_msg->first_line.type==SIP_REQUEST){		kr=get_kr();		if (kr==0 				||(p_msg->REQ_METHOD==METHOD_ACK && !(kr & REQ_RLSD))) {			LOG(L_WARN, "WARNING: script writer didn't release transaction\n");			t_release_transaction(T);		}	}	UNREF( T );	set_t(T_UNDEFINED);	return 1;}int t_get_trans_ident(struct sip_msg* p_msg, unsigned int* hash_index, unsigned int* label){    struct cell* t;    if(t_check(p_msg,0) != 1){	LOG(L_ERR,"ERROR: t_get_trans_ident: no transaction found\n");	return -1;    }    t = get_t();    if(!t){	LOG(L_ERR,"ERROR: t_get_trans_ident: transaction found is NULL\n");	return -1;    }        *hash_index = t->hash_index;    *label = t->label;    return 1;}int t_lookup_ident(struct cell ** trans, unsigned int hash_index, unsigned int label){    struct cell* p_cell;    if(hash_index >= TABLE_ENTRIES){		LOG(L_ERR,"ERROR: t_lookup_ident: invalid hash_index=%u\n",hash_index);		return -1;    }    LOCK_HASH(hash_index);    /* all the transactions from the entry are compared */    for ( p_cell = get_tm_table()->entrys[hash_index].first_cell;	  p_cell; p_cell = p_cell->next_cell )     {		if(p_cell->label == label){			REF_UNSAFE(p_cell);    			UNLOCK_HASH(hash_index);			set_t(p_cell);			*trans=p_cell;			DBG("DEBUG: t_lookup_ident: transaction found\n");			return 1;		}    }		UNLOCK_HASH(hash_index);	set_t(0);	*trans=p_cell;	DBG("DEBUG: t_lookup_ident: transaction not found\n");        return -1;}int t_is_local(struct sip_msg* p_msg){    struct cell* t;    if(t_check(p_msg,0) != 1){	LOG(L_ERR,"ERROR: t_is_local: no transaction found\n");	return -1;    }    t = get_t();    if(!t){	LOG(L_ERR,"ERROR: t_is_local: transaction found is NULL\n");	return -1;    }        return is_local(t);}/* lookup a transaction by callid and cseq, parameters are pure * header field content only, e.g. "123@10.0.0.1" and "11" */int t_lookup_callid(struct cell ** trans, str callid, str cseq) {	struct cell* p_cell;	unsigned hash_index;	/* I use MAX_HEADER, not sure if this is a good choice... */	char callid_header[MAX_HEADER];	char cseq_header[MAX_HEADER];	/* save return value of print_* functions here */	char* endpos;	/* need method, which is always INVITE in our case */	/* CANCEL is only useful after INVITE */	str invite_method;	char* invite_string = INVITE;		invite_method.s = invite_string;	invite_method.len = INVITE_LEN;		/* lookup the hash index where the transaction is stored */	hash_index=hash(callid, cseq);	if(hash_index >= TABLE_ENTRIES){		LOG(L_ERR,"ERROR: t_lookup_callid: invalid hash_index=%u\n",hash_index);		return -1;	}	/* create header fields the same way tm does itself, then compare headers */	endpos = print_callid_mini(callid_header, callid);	DBG("created comparable call_id header field: >%.*s<\n", 			(int)(endpos - callid_header), callid_header); 	endpos = print_cseq_mini(cseq_header, &cseq, &invite_method);	DBG("created comparable cseq header field: >%.*s<\n", 			(int)(endpos - cseq_header), cseq_header); 	LOCK_HASH(hash_index);	DBG("just locked hash index %u, looking for transactions there:\n", hash_index);	/* all the transactions from the entry are compared */	for ( p_cell = get_tm_table()->entrys[hash_index].first_cell;	  p_cell; p_cell = p_cell->next_cell ) {				/* compare complete header fields, casecmp to make sure invite=INVITE */		if ( (strncmp(callid_header, p_cell->callid.s, p_cell->callid.len) == 0)			&& (strncasecmp(cseq_header, p_cell->cseq_n.s, p_cell->cseq_n.len) == 0) ) {			DBG("we have a match: callid=>>%.*s<< cseq=>>%.*s<<\n", p_cell->callid.len, 				p_cell->callid.s, p_cell->cseq_n.len, p_cell->cseq_n.s);			REF_UNSAFE(p_cell);			UNLOCK_HASH(hash_index);			set_t(p_cell);			*trans=p_cell;			DBG("DEBUG: t_lookup_callid: transaction found.\n");			return 1;		}		DBG("NO match: callid=%.*s cseq=%.*s\n", p_cell->callid.len, 			p_cell->callid.s, p_cell->cseq_n.len, p_cell->cseq_n.s);				}	UNLOCK_HASH(hash_index);	DBG("DEBUG: t_lookup_callid: transaction not found.\n");    	return -1;}

⌨️ 快捷键说明

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