Esempio n. 1
0
/**
 * Drop all dialogs belonging to one AOR.
 *  on deregistration for example.
 * @param aor - the public identity of the user
 * @returns the number of dialogs dropped 
 */
int S_drop_all_dialogs(str aor)
{
	s_dialog *d,*dn;
	int i,cnt=0;;
	
	LOG(L_DBG,"DBG:"M_NAME":S_drop_all_dialogs: Called for <%.*s>\n",aor.len,aor.s);

	for(i=0;i<s_dialogs_hash_size;i++){
		d_lock(i);
			d = s_dialogs[i].head;
			while(d){
				dn = d->next;
				if (d->direction == DLG_MOBILE_ORIGINATING &&
					d->aor.len == aor.len &&
					strncasecmp(d->aor.s,aor.s,aor.len)==0) {
					if (!terminate_s_dialog(d)) del_s_dialog(d);
					cnt++;
				}						
				d = dn;
			}
		d_unlock(i);
	}
	//print_s_dialogs(L_INFO);	
	return cnt;
}
Esempio n. 2
0
/**
 * Prints the dialog hash table.
 * @param log_level - the log_level to print with
 */
void print_p_dialogs(int log_level)
{
	p_dialog *d;
	int i,j;
	if (debug<log_level) return; /* to avoid useless calls when nothing will be printed */
	d_act_time();
	LOG(log_level,"INF:"M_NAME":----------  P-CSCF Dialog List begin --------------\n");
	for(i=0;i<p_dialogs_hash_size;i++){
		d_lock(i);
			d = p_dialogs[i].head;
			while(d){
				LOG(log_level,"INF:"M_NAME":[%4d] Dir:["ANSI_MAGENTA"%d"ANSI_GREEN
					"]\tCall-ID:<"ANSI_BLUE"%.*s"ANSI_GREEN
					">\tAOR:"ANSI_RED"%d://%.*s:%d"ANSI_GREEN"\n"
					,i,				
					d->direction,
					d->call_id.len,d->call_id.s,
					d->transport,d->host.len,d->host.s,d->port);
				LOG(log_level,"INF:"M_NAME":\t\tMethod:["ANSI_MAGENTA"%d"ANSI_GREEN
					"] State:["ANSI_MAGENTA"%d"ANSI_GREEN
					"] Exp:["ANSI_MAGENTA"%4d"ANSI_GREEN"]\n",
					d->method,d->state,
					(int)(d->expires - d_time_now));	
				for(j=0;j<d->routes_cnt;j++)
					LOG(log_level,"INF:"M_NAME":\t\t RR: <"ANSI_YELLOW"%.*s"ANSI_GREEN">\n",			
						d->routes[j].len,d->routes[j].s);					
				d = d->next;
			} 		
		d_unlock(i);
	}
	LOG(log_level,"INF:"M_NAME":----------  P-CSCF Dialog List end   --------------\n");	
}
Esempio n. 3
0
/**
 * Given a call-id, locate if its terminating,orginating or both
 * release the dialog involved and drop the dialog
 * @param callid - the Call-ID to release
 * @param reason - the Reason header to include in messages
 * @returns 0 on error, 1 on success  
 */ 
int release_call(str callid,str reason)
{
	s_dialog *d=0;
	unsigned int hash;
	int res = 0;
	
	d = get_s_dialog_dir(callid,DLG_MOBILE_ORIGINATING);
	if (d) {				
		hash = d->hash;
		if (release_call_s(d,reason)>0) res = 1;		
		goto done;		
	}
	d = get_s_dialog_dir(callid,DLG_MOBILE_TERMINATING);
	if (d) {				
		hash = d->hash;
		if (release_call_s(d,reason)>0) res = 1;		
		goto done;
	} 
	
	/*Neither ORGINATING nor TERMINATING is UNKNOWN!*/
	/*or doesn't exist*/
	/*drop it silently?*/
	/*treat it as ORIGINATING or TERMINATING?*/				
done:		
	if (d) d_unlock(hash);
	return res;	
}
Esempio n. 4
0
/**
 * Drop all dialogs belonging to one contact.
 *  on deregistration for example.
 * @param host - host that originates/terminates this dialog
 * @param port - port that originates/terminates this dialog
 * @param transport - transport that originates/terminates this dialog
 * @returns the number of dialogs dropped 
 */
int P_drop_all_dialogs(str host,int port, int transport)
{
	p_dialog *d,*dn;
	int i,cnt=0;;
	
	LOG(L_DBG,"DBG:"M_NAME":P_drop_all_dialogs: Called for <%d://%.*s:%d>\n",transport,host.len,host.s,port);

	for(i=0;i<p_dialogs_hash_size;i++){
		d_lock(i);
			d = p_dialogs[i].head;
			while(d){
				dn = d->next;
				if (d->transport == transport &&
					d->port == port &&
					d->host.len == host.len &&
					strncasecmp(d->host.s,host.s,host.len)==0) {
					del_p_dialog(d);
					cnt++;
				}						
				d = dn;
			}
		d_unlock(i);
	}
//	print_p_dialogs(L_INFO);	
	return cnt;
}
Esempio n. 5
0
/**
 * Finds out if a dialog is in the hash table.
 * @param call_id - dialog's call_id
 * @param dir - the direction of the dialog
 * @returns - 1 if the dialog exists, 0 if not
 * \note transport is ignored.
 */
int is_p_dialog_dir(str call_id,enum p_dialog_direction dir)
{
	p_dialog *d=0;
	unsigned int hash = get_p_dialog_hash(call_id);
		d_lock(hash);
		d = p_dialogs[hash].head;
		while(d){
			if (d->direction==dir && d->call_id.len == call_id.len &&
						strncasecmp(d->call_id.s,call_id.s,call_id.len)==0) {
				d_unlock(hash);
				return 1;
			}
			d=d->next;
		}
		d_unlock(hash);
		return 0;
}
/**
 * Finds out if a dialog is in the hash table.
 * @param call_id - dialog's call_id
 * @param dir - the direction of the dialog. if NULL, it doesn't matter
 * @returns - 1 if the dialog exists, 0 if not
 * \note transport is ignored.
 */
int is_lrf_dialog(str call_id,enum lrf_dialog_direction *dir)
{
	lrf_dialog *d=0;
	unsigned int hash = get_lrf_dialog_hash(call_id);

	d_lock(hash);
		d = lrf_dialogs[hash].head;
		while(d){
			if ((!dir || d->direction == *dir) &&
				d->call_id.len == call_id.len &&
				strncasecmp(d->call_id.s,call_id.s,call_id.len)==0) {
					d_unlock(hash);
					return 1;
				}
			d = d->next;
		}
	d_unlock(hash);
	return 0;
}
Esempio n. 7
0
/**
 * Releases a call from the on reply route block
 * called with any reply to an INVITE
 * useful in cases of rejecting a call when you are processing the SDP
 * or handling QoS things
 * @msg  - the sip message being processed
 * @str1 - the first parameter  "orig" or "term"
 * @str2 - [optional] the Reason header that you want to go to the messages 
 * @returns - TRUE on success or FALSE on misscall and BREAK on error
 */
int P_release_call_onreply(struct sip_msg *msg,char *str1,char *str2)
{
	enum p_dialog_direction dir;
	p_dialog *d=NULL;
	str callid;
	struct hdr_field *h1;
	str reason={NULL,0};
	
	if (str2) {
		reason.s=str2;
		reason.len=strlen(str2);
	} else
		reason = _488_text_s;
		
	
	dir= (str1[0]=='o' || str1[0]=='O' || str1[0]=='0')? DLG_MOBILE_ORIGINATING : DLG_MOBILE_TERMINATING;
	
	if (msg->first_line.type== SIP_REQUEST)
	{
		LOG(L_ERR,"ERR: P_release_call_on_reply called with a request\n");
		return CSCF_RETURN_FALSE;
	}
	
	callid=cscf_get_call_id(msg,&h1);
	if (is_p_dialog_dir(callid,dir)) {
		d=get_p_dialog_dir(callid,dir);
		if (msg->first_line.u.reply.statuscode > 199)
		{
			release_call_previous(d,RELEASE_CALL_WEIRD,488,reason);
			d_unlock(d->hash);
			return CSCF_RETURN_TRUE;
		} else {
			release_call_previous(d,RELEASE_CALL_EARLY,488,reason);
			d_unlock(d->hash);
			return CSCF_RETURN_TRUE;
		}
	} else {
		LOG(L_ERR,"ERR:"M_NAME "P_release_call_onreply :  unable to find dialog\n");
		return CSCF_RETURN_BREAK;
	}
	
}
Esempio n. 8
0
/**
 * Finds out if a dialog is in the hash table.
 * @param call_id - call_id of the dialog
 * @param aor - aor of the user
 * @returns 1 if found, 0 if not found
 */
int is_s_dialog(str call_id,str aor)
{
	s_dialog *d=0;
	unsigned int hash = get_s_dialog_hash(call_id);

	d_lock(hash);
		d = s_dialogs[hash].head;
		while(d){
				if (d->aor.len == aor.len &&
				d->call_id.len == call_id.len &&
				strncasecmp(d->aor.s,aor.s,aor.len)==0 &&
				strncasecmp(d->call_id.s,call_id.s,call_id.len)==0) {
					d_unlock(hash);
					return 1;
				}
			d = d->next;
		}
	d_unlock(hash);
	return 0;
}
Esempio n. 9
0
/**
 * Callback function for BYE requests!
 * Identify the s_dialog, then see if one BYE has already been recieved
 * if yes drop it , if no, wait for the second
 */
void bye_response(struct cell *t,int type,struct tmcb_params *ps)
{		
	s_dialog *d;
	unsigned int hash;
	str call_id;
	
	enum s_dialog_direction dir;
	
	
	if (!ps->param) return;
	dir = *((enum s_dialog_direction *) *(ps->param));
	shm_free(*ps->param);
	*ps->param = 0;		
		
	call_id = t->callid;
  	call_id.s+=9;
  	call_id.len-=11;

	LOG(L_INFO,"DBG:"M_NAME":bye_response(): Received a %d response to BYE for a call release for <%.*s> DIR[%d].\n",
		ps->code, call_id.len,call_id.s,dir);
			
	d = get_s_dialog_dir(call_id,dir);
	if (!d)	{
		LOG(L_ERR,"ERR:"M_NAME":bye_response(): Received a BYE response for a call release but there is no dialog for <%.*s> DIR[%d].\n",
			call_id.len,call_id.s,dir);
		return;
	}
	
	if (ps->code>=200){
		if (d->state==DLG_STATE_TERMINATED_ONE_SIDE){
			hash=d->hash;
			LOG(L_INFO,"INFO:"M_NAME":bye_response(): Received a response to second BYE. Dialog is dropped.\n");
			del_s_dialog(d);
			d_unlock(hash);			 
		} else {
			hash=d->hash;
			d->state=DLG_STATE_TERMINATED_ONE_SIDE;
			d_unlock(hash);
		}		
	} 	
}
Esempio n. 10
0
/**
 * Callback function for BYE requests!
 * Identify the s_dialog, then see if one BYE has already been recieved
 * if yes drop it , if no, wait for the second
 */
void confirmed_response(struct cell *t,int type,struct tmcb_params *ps)
{		
	p_dialog *d;
	unsigned int hash;
	str call_id;
	
	enum p_dialog_direction dir;
	
	
	if (!ps->param) return;
	dir = *((enum p_dialog_direction *) *(ps->param));
	shm_free(*ps->param);
	*ps->param = 0;		
		
	//call_id = cscf_get_call_id(ps->rpl,0);
	call_id = t->callid;
  	call_id.s+=9;
  	call_id.len-=11;
	
	LOG(L_INFO,"DBG:"M_NAME":confirmed_response(): Received a BYE for a call release for <%.*s> DIR[%d].\n",
		call_id.len,call_id.s,dir);
	
	d = get_p_dialog_dir(call_id,dir);
	if (!d)	{
		LOG(L_ERR,"ERR:"M_NAME":confirmed_response(): Received a BYE for a call release but there is no dialog for <%.*s> DIR[%d].\n",
			call_id.len,call_id.s,dir);
		return;
	}
	
	if (ps->code>=200){
		if (d->state==DLG_STATE_TERMINATED_ONE_SIDE){
			hash=d->hash;
			del_p_dialog(d);
			d_unlock(hash);			 
		} else {
			hash=d->hash;
			d->state=DLG_STATE_TERMINATED_ONE_SIDE;
			d_unlock(hash);
		}		
	} 
}
Esempio n. 11
0
/**
 * Saves a dialog.
 * @param msg - the initial request
 * @param str1 - direction - "orig" or "term"
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error 
 */
int S_save_dialog(struct sip_msg* msg, char* str1, char* str2)
{
	str call_id;
	s_dialog *d;
	str aor;
	str uri,tag;
	str ruri;	
	enum s_dialog_direction dir = get_dialog_direction(str1);
	
	if (!find_dialog_aor(msg,dir,&aor)){
		LOG(L_ERR,"ERR:"M_NAME":S_save_dialog(): Error retrieving %s contact\n",str1);
		return CSCF_RETURN_BREAK;
	}		
		
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;

	LOG(L_INFO,"DBG:"M_NAME":S_save_dialog(%s): Call-ID <%.*s>\n",str1,call_id.len,call_id.s);

	if (is_s_dialog(call_id,aor)){
		LOG(L_ERR,"ERR:"M_NAME":S_save_dialog: dialog already exists!\n");	
		return CSCF_RETURN_FALSE;
	}
	
	d = add_s_dialog(call_id,aor,dir);
	if (!d) return CSCF_RETURN_FALSE;

	d->method = get_dialog_method(msg->first_line.u.request.method);
	STR_SHM_DUP(d->method_str,msg->first_line.u.request.method,"shm");
	d->first_cseq = cscf_get_cseq(msg,0);
	d->last_cseq = d->first_cseq;
	d->state = DLG_STATE_INITIAL;
	d->expires = d_act_time()+60;
	
	cscf_get_from_tag(msg,&tag);
	cscf_get_from_uri(msg,&uri);
	ruri=cscf_get_identity_from_ruri(msg);
	 
	tmb.new_dlg_uac(&call_id,
						&tag,
						d->first_cseq,&uri,
						&ruri,
						&d->dialog_c);
	
	tmb.new_dlg_uas(msg,99,&d->dialog_s);

	d_unlock(d->hash);
	
//	print_s_dialogs(L_INFO);
	
	return CSCF_RETURN_TRUE;	
}
Esempio n. 12
0
/**
 * Finds out if a dialog is in the hash table.
 * @param call_id - dialog's call_id
 * @param host - host that originates/terminates this dialog
 * @param port - port that originates/terminates this dialog
 * @param transport - transport that originates/terminates this dialog
 * @param dir - the direction of the dialog. if NULL, it doesn't matter
 * @returns - 1 if the dialog exists, 0 if not
 * \note transport is ignored.
 */
int is_p_dialog(str call_id,str host,int port, int transport,enum p_dialog_direction *dir)
{
	p_dialog *d=0;
	unsigned int hash = get_p_dialog_hash(call_id);

	d_lock(hash);
		d = p_dialogs[hash].head;
		while(d){
			if ((!dir || d->direction == *dir) &&
				d->port == port &&
/*				d->transport == transport &&*/
/* commented because of strange behaviour */
				d->host.len == host.len &&
				d->call_id.len == call_id.len &&
				strncasecmp(d->host.s,host.s,host.len)==0 &&
				strncasecmp(d->call_id.s,call_id.s,call_id.len)==0) {
					d_unlock(hash);
					return 1;
				}
			d = d->next;
		}
	d_unlock(hash);
	return 0;
}
Esempio n. 13
0
/**
 * Drops and deletes a dialog.
 * @param msg - the request/response
 * @param str1 - direction - "orig" or "term"
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error 
 */
int S_drop_dialog(struct sip_msg* msg, char* str1, char* str2)
{
	str call_id;
	s_dialog *d;
	int hash;
//	struct sip_msg *req;
	enum s_dialog_direction dir = get_dialog_direction(str1);
	
	
//	if (!find_dialog_aor(msg,str1,&aor)){
//		LOG(L_ERR,"ERR:"M_NAME":S_is_in_dialog(): Error retrieving %s contact\n",str1);
//		return CSCF_RETURN_BREAK;
//	}		
		
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;

	LOG(L_DBG,"DBG:"M_NAME":S_drop_dialog(%s): Call-ID <%.*s> DIR[%d]\n",
		str1,call_id.len,call_id.s,
		dir);

	d = get_s_dialog_dir(call_id,dir);
//	if (!d && msg->first_line.type==SIP_REPLY){
//		/* Try to get the dialog from the request */
//		req = cscf_get_request_from_reply(msg);		
//		if (!find_dialog_aor(req,str1,&aor)){
//			LOG(L_ERR,"ERR:"M_NAME":S_update_dialog(%s): Error retrieving %s contact\n",str1,str1);
//			return CSCF_RETURN_BREAK;
//		}		
//		d = get_s_dialog(call_id,aor);		
//	}
	if (!d){
		LOG(L_ERR,"ERR:"M_NAME":S_drop_dialog: dialog does not exists!\n");	
		return CSCF_RETURN_FALSE;
	}

	hash = d->hash;
	
	del_s_dialog(d);
		
	d_unlock(hash);
	
	print_s_dialogs(L_INFO);
	
	return CSCF_RETURN_TRUE;	
}
Esempio n. 14
0
/**
 * Destroy the registrar
 */
void s_dialogs_destroy()
{
	int i;
	s_dialog *d,*nd;
	for(i=0;i<s_dialogs_hash_size;i++){
		d_lock(i);
			d = s_dialogs[i].head;
			while(d){
				nd = d->next;
				free_s_dialog(d);
				d = nd;
			}
		d_unlock(i);
		lock_dealloc(s_dialogs[i].lock);
	}
	shm_free(s_dialogs);
}
Esempio n. 15
0
/**
 * Drops and deletes a dialog.
 * @param msg - the request/response
 * @param str1 - direction - "orig" or "term"
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error 
 */
int P_drop_dialog(struct sip_msg* msg, char* str1, char* str2)
{
	str call_id;
	p_dialog *d;
	int hash;
	str host;
	int port,transport;
	struct sip_msg *req;
	enum p_dialog_direction dir;
	
	dir = get_dialog_direction(str1);
	
	if (msg->first_line.type==SIP_REPLY) req = cscf_get_request_from_reply(msg);
	else req = msg;
	if (!find_dialog_contact(req,dir,&host,&port,&transport)){
		LOG(L_ERR,"ERR:"M_NAME":P_is_in_dialog(): Error retrieving %s contact\n",str1);
		return CSCF_RETURN_BREAK;
	}		
		
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;

	LOG(L_DBG,"DBG:"M_NAME":P_drop_dialog(%s): Call-ID <%.*s> %d://%.*s:%d\n",
		str1,call_id.len,call_id.s,
		transport,host.len,host.s,port);

	d = get_p_dialog(call_id,host,port,transport,&dir);
	if (!d)
		d = get_p_dialog(call_id,host,port,transport,0);
	if (!d){
		LOG(L_INFO,"INFO:"M_NAME":P_drop_dialog: dialog does not exists!\n");	
		return CSCF_RETURN_FALSE;
	}

	hash = d->hash;
	
	del_p_dialog(d);
		
	d_unlock(hash);
	
	print_p_dialogs(L_INFO);
	
	return CSCF_RETURN_TRUE;	
}
Esempio n. 16
0
/**
 * Drops and deletes a dialog.
 * @param msg - the request/response
 * @param str1 - direction - "orig" or "term"
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error 
 */
int LRF_drop_dialog(struct sip_msg* msg, char* str1, char* str2)
{
	str call_id;
	lrf_dialog *d;
	int hash;
	struct sip_msg *req;
	enum lrf_dialog_direction dir;
	str target_uri = {0,0};
	dir = get_dialog_direction(str1);
	
	if (msg->first_line.type==SIP_REPLY) req = cscf_get_request_from_reply(msg);
	else req = msg;
	if (!find_dialog_contact(req,dir,&target_uri)){
		LOG(L_ERR,"ERR:"M_NAME":LRF_is_in_dialog(): Error retrieving %s contact\n",str1);
		return CSCF_RETURN_BREAK;
	}		
		
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;

	LOG(L_DBG,"DBG:"M_NAME":LRF_drop_dialog(%s): Call-ID <%.*s>: target <%.*s>\n",
		str1,call_id.len,call_id.s,
		target_uri.len, target_uri.s);
	d = get_lrf_dialog(call_id, &dir);
	if (!d)
		d = get_lrf_dialog(call_id, NULL);
	if (!d){
		LOG(L_INFO,"INFO:"M_NAME":LRF_drop_dialog: dialog does not exists!\n");	
		return CSCF_RETURN_FALSE;
	}

	hash = d->hash;
	
	del_lrf_dialog(d);
		
	d_unlock(hash);
	
	print_lrf_dialogs(L_INFO);
	
	return CSCF_RETURN_TRUE;	
}
Esempio n. 17
0
/**
 * Prints the list of dialogs.
 * @param log_level - level to log at
 */
void print_s_dialogs(int log_level)
{
	s_dialog *d;
	int i;
	d_act_time();
	LOG(log_level,"INF:"M_NAME":----------  S-CSCF Dialog List begin --------------\n");
	for(i=0;i<s_dialogs_hash_size;i++){
		d_lock(i);
			d = s_dialogs[i].head;
			while(d){
				LOG(log_level,"INF:"M_NAME":[%4d] Call-ID:<%.*s>\t DIR[%d] AOR:<%.*s>\tMet:[%d]\tState:[%d] Exp:[%4d]\n",i,				
					d->call_id.len,d->call_id.s,d->direction,
					d->aor.len,d->aor.s,
					d->method,d->state,
					(int)(d->expires - d_time_now));
					
				d = d->next;
			} 		
		d_unlock(i);
	}
	LOG(log_level,"INF:"M_NAME":----------  S-CSCF Dialog List end   --------------\n");	
}
Esempio n. 18
0
/**
 * Prints the list of dialogs.
 * @param log_level - level to log at
 */
void print_s_dialogs(int log_level)
{
	s_dialog *d;
	int i;
#ifdef SER_MOD_INTERFACE
	if (!is_printable(log_level))
#else		
	if (debug<log_level)
#endif	
		 return; /* to avoid useless calls when nothing will be printed */
	d_act_time();
	LOG(log_level,"INF:"M_NAME":----------  S-CSCF Dialog List begin --------------\n");
	for(i=0;i<s_dialogs_hash_size;i++){
		d_lock(i);
			d = s_dialogs[i].head;
			while(d){
				LOG(log_level,"INF:"M_NAME":[%4d] Dir["ANSI_MAGENTA"%d"ANSI_GREEN
					"] Call-ID:<"ANSI_BLUE"%.*s"ANSI_GREEN
					"> AOR:<"ANSI_RED"%.*s"ANSI_GREEN
					">\n",i,				
					d->direction,
					d->call_id.len,d->call_id.s,
					d->aor.len,d->aor.s);
				LOG(log_level,"INF:"M_NAME":\t\tMethod:["ANSI_MAGENTA"%d"ANSI_GREEN
					"] State:["ANSI_MAGENTA"%d"ANSI_GREEN
					"] Exp:["ANSI_MAGENTA"%4d"ANSI_GREEN"] Ref:["ANSI_MAGENTA"%.*s"ANSI_GREEN"] Event:["ANSI_MAGENTA"%.*s"ANSI_GREEN"]\n",				
					d->method,
					d->state,
					(int)(d->expires - d_time_now),
					d->refresher.len,d->refresher.s,
					d->event.len,d->event.s);
					
				d = d->next;
			} 		
		d_unlock(i);
	}
	LOG(log_level,"INF:"M_NAME":----------  S-CSCF Dialog List end   --------------\n");	
}
Esempio n. 19
0
/**
 * The dialog timer looks for expired dialogs and removes them.
 * @param ticks - the current time
 * @param param - pointer to the dialogs list
 */
void dialog_timer(unsigned int ticks, void* param)
{
	p_dialog *d,*dn;
	int i;
	#ifdef WITH_IMS_PM
		int dialog_cnt[DLG_METHOD_MAX+1];
		for(i=0;i<=DLG_METHOD_MAX;i++)
			dialog_cnt[i]=0;
	#endif
	
	LOG(L_DBG,"DBG:"M_NAME":dialog_timer: Called at %d\n",ticks);
	if (!p_dialogs) p_dialogs = (p_dialog_hash_slot*)param;

	d_act_time();
	
	for(i=0;i<p_dialogs_hash_size;i++){
		d_lock(i);
			d = p_dialogs[i].head;
			while(d){
				dn = d->next;
				if (d->expires<=d_time_now) {						
						if (!terminate_p_dialog(d)) 
							del_p_dialog(d);					
				}
				#ifdef WITH_IMS_PM
					else dialog_cnt[d->method]++;
				#endif										
				d = dn;
			}
		d_unlock(i);
	}
	print_p_dialogs(L_INFO);
	#ifdef WITH_IMS_PM
		for(i=0;i<=DLG_METHOD_MAX;i++)
			IMS_PM_LOG11(RD_NbrDialogs,get_dialog_method_str(i),dialog_cnt[i]);		
	#endif	
}
Esempio n. 20
0
/**
 * The dialog timer looks for expires dialogs and removes them
 * @param ticks - the current time
 * @param param - pointer to the dialogs list
 */
void dialog_timer(unsigned int ticks, void* param)
{
	s_dialog *d,*dn;
	int i;
	
	LOG(L_DBG,"DBG:"M_NAME":dialog_timer: Called at %d\n",ticks);
	if (!s_dialogs) s_dialogs = (s_dialog_hash_slot*)param;

	d_act_time();
	
	for(i=0;i<s_dialogs_hash_size;i++){
		d_lock(i);
			d = s_dialogs[i].head;
			while(d){
				dn = d->next;
				if (d->expires<=d_time_now) {
					if (!terminate_s_dialog(d)) del_s_dialog(d);
				}						
				d = dn;
			}
		d_unlock(i);
	}
	print_s_dialogs(L_INFO);
}
Esempio n. 21
0
/**
 * Updates a dialog.
 * If the initial request was:
 * - INVITE - refreshes the expiration or looks for the BYE and destroys the dialog 
 * if found
 * - SUBSCRIBE - looks for the Subscription-state in NOTIFY, refreshes the expiration 
 * and if terminated destroys the dialog
 * - When adding more dialogs, add the refreshal methods here or they will expire and will
 * be destroyed. Also add the termination to reduce the memory consumption and improve the
 * performance.
 * @param msg - the request/response
 * @param str1 - direction - "orig" or "term"
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error 
 */
int P_update_dialog(struct sip_msg* msg, char* str1, char* str2)
{
	str call_id;
	p_dialog *d;
	int response;
	int cseq;
	struct hdr_field *h=0;
	struct sip_msg *req=0;
	str host;
	int port,transport;
	int expires;
	str totag;
	time_t t_time=0;
	str ses_exp = {0,0};
	str refresher = {0,0};
	enum p_dialog_direction dir;
	
	dir = get_dialog_direction(str1);
	
	if (msg->first_line.type==SIP_REPLY) req = cscf_get_request_from_reply(msg);
	else req = msg;
	if (!find_dialog_contact(req,dir,&host,&port,&transport)){
		LOG(L_ERR,"ERR:"M_NAME":P_update_dialog(%s): Error retrieving %s contact\n",str1,str1);
		return CSCF_RETURN_BREAK;
	}		
		
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;

	LOG(L_DBG,"DBG:"M_NAME":P_update_dialog(%s): Call-ID <%.*s>\n",str1,call_id.len,call_id.s);

	d = get_p_dialog(call_id,host,port,transport,&dir);
	if (!d)
		d = get_p_dialog(call_id,host,port,transport,0);
	if (!d){
		if (msg->first_line.type==SIP_REQUEST &&
			msg->first_line.u.request.method.len == 3 && 
			strncasecmp(msg->first_line.u.request.method.s,"ACK",3)){
			/* to skip the ACK after a 4xx when the dialog was dropped already*/
			return CSCF_RETURN_TRUE;
		}else{
			LOG(L_CRIT,"ERR:"M_NAME":P_update_dialog: dialog does not exists!\n");
			return CSCF_RETURN_FALSE;
		}	
	}


	if (msg->first_line.type==SIP_REQUEST){
		/* Request */
		LOG(L_DBG,"DBG:"M_NAME":P_update_dialog(%s): Method <%.*s> \n",str1,
			msg->first_line.u.request.method.len,msg->first_line.u.request.method.s);
		cseq = cscf_get_cseq(msg,&h);
		if (cseq>d->last_cseq) d->last_cseq = cseq;
		if (get_dialog_method(msg->first_line.u.request.method) == DLG_METHOD_INVITE)
		{
			d->uac_supp_timer = supports_extension(msg, &str_ext_timer);
	
			ses_exp = cscf_get_session_expires_body(msg, &h);
			t_time = cscf_get_session_expires(ses_exp, &refresher);
			if (!t_time){
				d->expires = d_act_time()+pcscf_dialogs_expiration_time;
				d->lr_session_expires = 0;
			} else {
				d->expires = d_act_time() + t_time;
				d->lr_session_expires = t_time;
				if (refresher.len)
					STR_SHM_DUP(d->refresher, refresher, "DIALOG_REFRESHER");
			}
		}
		else if (d->method == DLG_METHOD_SUBSCRIBE && 
			msg->first_line.u.request.method.len == 6 && 
			strncasecmp(msg->first_line.u.request.method.s,"NOTIFY",6)==0)
		{
			// Subscription-State header is mandatory for NOTIFY. See RFC 3265, Section 7.2
			expires = cscf_get_subscription_state(msg);
			if (expires >= 0)
			{
				d->expires = d_act_time()+expires;
			}
			else
			{
				d->expires = d_act_time()+pcscf_dialogs_expiration_time;
			}
		}
		else
		{
			expires = cscf_get_expires_hdr(msg);
			if (expires >= 0) 
			{
				LOG(L_INFO,"DBG:"M_NAME":P_update_dialog(%.*s): Update expiration time to %d via Expire header 2\n",call_id.len,call_id.s,expires);
				d->expires = d_act_time()+expires;
			}
			else
			{
				LOG(L_INFO,"INF:"M_NAME": update_dialog(%.*s): d->expires+=pcscf_dialogs_expiration_time 4\n",call_id.len,call_id.s);
				d->expires = d_act_time()+pcscf_dialogs_expiration_time;
			}
			d->lr_session_expires = 0;		
		}
	}else{
		/* Reply */
		response = msg->first_line.u.reply.statuscode;
		LOG(L_DBG,"DBG:"M_NAME":P_update_dialog(%s): <%d> \n",str1,response);
		cseq = cscf_get_cseq(msg,&h);
		if (cseq==0 || h==0) return CSCF_RETURN_FALSE;
		if (d->first_cseq==cseq && d->method_str.len == ((struct cseq_body *)h->parsed)->method.len &&
			strncasecmp(d->method_str.s,((struct cseq_body *)h->parsed)->method.s,d->method_str.len)==0 &&
			d->state < DLG_STATE_CONFIRMED){
			/* reply to initial request */
			if (response<200 && response>100){
				save_dialog_routes(msg,str1,d);
				d->state = DLG_STATE_EARLY;
				d->expires = d_act_time()+300;
				cscf_get_to_tag(msg,&totag);
				tmb.update_dlg_uas(d->dialog_s,response,&totag);
				tmb.dlg_response_uac(d->dialog_c,msg,IS_NOT_TARGET_REFRESH);
			}else
			if (response>=200 && response<300){
				save_dialog_routes(msg,str1,d);
				d->state = DLG_STATE_CONFIRMED;
				
				update_dialog_on_reply(msg, d);
				
				cscf_get_to_tag(msg,&totag);
				tmb.update_dlg_uas(d->dialog_s,response,&totag);
				tmb.dlg_response_uac(d->dialog_c,msg,IS_NOT_TARGET_REFRESH);
				
			}else
				if (response>300){
					d->state = DLG_STATE_TERMINATED;
					d_unlock(d->hash);				
					return P_drop_dialog(msg,str1,str2);
				}				
		}else{
			/* reply to subsequent request */			
			if (!req) req = cscf_get_request_from_reply(msg);
			
			/* destroy dialogs on specific methods */
			switch (d->method){
				case DLG_METHOD_OTHER:							
					expires = cscf_get_expires_hdr(msg);
					if (expires >= 0)
					{
						d->expires = d_act_time()+expires;
					}
					else
					{
						d->expires = d_act_time()+pcscf_dialogs_expiration_time;
					}
					d->lr_session_expires = 0;
					break;
				case DLG_METHOD_INVITE:
					if (req && req->first_line.u.request.method.len==3 &&
						strncasecmp(req->first_line.u.request.method.s,"BYE",3)==0){
						d->state = DLG_STATE_TERMINATED;
						d_unlock(d->hash);				
						return P_drop_dialog(msg,str1,str2);
					}
					update_dialog_on_reply(msg, d);
					break;
				case DLG_METHOD_SUBSCRIBE:
//					if (req && req->first_line.u.request.method.len==9 &&
//						strncasecmp(req->first_line.u.request.method.s,"SUBSCRIBE",9)==0 &&
//						cscf_get_expires_hdr(msg)==0){						
//						d->state = DLG_STATE_TERMINATED;
//						d_unlock(d->hash);				
//						return P_drop_dialog(msg,str1,str2);
//					}
					if (req && req->first_line.u.request.method.len==6 &&
						strncasecmp(req->first_line.u.request.method.s,"NOTIFY",6)==0){
						expires = cscf_get_subscription_state(req);
						if (expires==0){						
							d->state = DLG_STATE_TERMINATED;
							d_unlock(d->hash);				
							return P_drop_dialog(msg,str1,str2);
						}else if (expires>0){
							d->expires = d_act_time() + expires;
						}
					}
					break;
			}
			if (cseq>d->last_cseq) d->last_cseq = cseq;
		}
	}
	
	d_unlock(d->hash);
	
	print_p_dialogs(L_INFO);
	
	return CSCF_RETURN_TRUE;	
out_of_memory:
	d_unlock(d->hash);
	return CSCF_RETURN_ERROR;	
}
Esempio n. 22
0
/**
 * Releases a call from the on reply route block
 * called with any reply to an INVITE
 * useful in cases of rejecting a call when you are processing the SDP
 * or handling QoS things
 * @msg  - the sip message being processed
 * @str1 - the first parameter  "orig" or "term"
 * @str2 - [optional] the Reason header that you want to go to the messages
 * @returns - BREAK ... whatever happens this message is not relayed
 */
int P_release_call_onreply(struct sip_msg *msg,char *str1,char *str2)
{
    enum p_dialog_direction dir;
    p_dialog *d=NULL;
    str callid;
    struct hdr_field *h1;
    str reason= {NULL,0};
    unsigned int hash;

    struct cell* t; /*needed to distinguish between UPDATE and INVITE*/

    LOG(L_INFO,ANSI_WHITE"P_release_call_on_reply\n");

    if (str2) {
        reason.s=str2;
        reason.len=strlen(str2);
    } else
        reason = _488_text_s;


    dir= (str1[0]=='o' || str1[0]=='O' || str1[0]=='0')? DLG_MOBILE_ORIGINATING : DLG_MOBILE_TERMINATING;

    if (msg->first_line.type== SIP_REQUEST)
    {
        LOG(L_ERR,"ERR: P_release_call_on_reply called with a request\n");
        return CSCF_RETURN_FALSE;
    }

    callid=cscf_get_call_id(msg,&h1);
    if (is_p_dialog_dir(callid,dir)) {
        d=get_p_dialog_dir(callid,dir);
        hash=d->hash;

        t=tmb.t_gett();
        if (!t) {
            LOG(L_ERR,"P_release_call_onreply(): unable to get transaction\n");
            return CSCF_RETURN_BREAK;
        }
        if (t->method.len==6 && memcmp(t->method.s,"INVITE",6)==0)
        {
            // If its an INVTE, the state depends on which reply we are processing

            if (msg->first_line.u.reply.statuscode > 199)
            {
                release_call_previous(d,RELEASE_CALL_WEIRD,488,reason);
            } else {
                release_call_previous(d,RELEASE_CALL_EARLY,488,reason);
            }
            // This means we already finished with the dialog
            if (d->pcc_session_id.s) shm_free(d->pcc_session_id.s);
            d->pcc_session_id.s=0;
            d->pcc_session_id.len=0;
            d_unlock(hash);
            return CSCF_RETURN_BREAK;
        } else {

            //UPDATE so early
            release_call_early(d,488,reason);
            d_unlock(hash);
            return CSCF_RETURN_BREAK;

        }

    } else {
        LOG(L_ERR,"ERR:"M_NAME "P_release_call_onreply :  unable to find dialog\n");
        return CSCF_RETURN_ERROR;
    }

}
Esempio n. 23
0
/**
 * Checks if the message follows the saved dialog routes.
 * @param msg - the SIP request
 * @param str1 - direction - "orig" or "term"
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error 
 */
int P_follows_dialog_routes(struct sip_msg *msg,char *str1,char *str2)
{
	int i;
	struct hdr_field *hdr=0;
	rr_t *r;
	p_dialog *d;
	str call_id,host;
	int port,transport;
	enum p_dialog_direction dir;
	
	dir = get_dialog_direction(str1);
	
	if (!find_dialog_contact(msg,dir,&host,&port,&transport)){
		LOG(L_ERR,"ERR:"M_NAME":P_follows_dialog_routes(): Error retrieving %s contact\n",str1);
		return CSCF_RETURN_BREAK;
	}		
		
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;

	LOG(L_DBG,"DBG:"M_NAME":P_follows_dialog_routes(%s): Call-ID <%.*s> %d://%.*s:%d\n",
		str1,call_id.len,call_id.s,
		transport,host.len,host.s,port);

	d = get_p_dialog(call_id,host,port,transport,&dir);
	if (!d)
		d = get_p_dialog(call_id,host,port,transport,0);
	if (!d){
		LOG(L_ERR,"ERR:"M_NAME":P_follows_dialog_routes: dialog does not exists!\n");	
		return CSCF_RETURN_FALSE;
	}
	/* todo - fix this to match exactly the first request */
	if (d->first_cseq == cscf_get_cseq(msg,0) &&
		d->method == get_dialog_method(msg->first_line.u.request.method)){
		LOG(L_INFO,"INF:"M_NAME":P_follows_dialog_routes: this looks like the initial request (retransmission?)!\n");
		goto ok;		
	}

	hdr = cscf_get_next_route(msg,0);
	r = 0;
	if (!hdr){
		if (d->routes_cnt==0) goto ok;
		else goto nok;
	}
	r = (rr_t*) hdr->parsed;	
	for(i=0;i<d->routes_cnt;i++){
		LOG(L_DBG,"DBG:"M_NAME":P_follows_dialog_routes:  must <%.*s>\n",
			d->routes[i].len,d->routes[i].s);		
		if (!r) {
			hdr = cscf_get_next_route(msg,hdr);
			if (!hdr) goto nok;
			r = (rr_t*) hdr->parsed;	
		}
		LOG(L_DBG,"DBG:"M_NAME":P_follows_dialog_routes: src %.*s\n",
			r->nameaddr.uri.len,r->nameaddr.uri.s);		
		if (r->nameaddr.uri.len==d->routes[i].len &&
				strncasecmp(r->nameaddr.uri.s,
					d->routes[i].s,d->routes[i].len)==0)
		{
			LOG(L_DBG,"DBG:"M_NAME":P_follows_dialog_routes: src match\n");		
		} else {
			LOG(L_DBG,"DBG:"M_NAME":P_follows_dialog_routes: found <%.*s>\n",
				r->nameaddr.uri.len,r->nameaddr.uri.s);					
			goto nok;
		}
		r = r->next;
	}
	if (r) {
		LOG(L_DBG,"DBG:"M_NAME":P_follows_dialog_routes: still has some extra Routes\n");		
		goto nok;
	}
	else 
		if (cscf_get_next_route(msg,hdr)) goto nok;
	
ok:
	if (d) d_unlock(d->hash);
	return CSCF_RETURN_TRUE;	
nok:
	if (d) d_unlock(d->hash);
	return CSCF_RETURN_FALSE;		
}
Esempio n. 24
0
/**
 * Updates a dialog.
 * If the initial request was:
 * - INVITE - refreshes the expiration or looks for the BYE and destroys the dialog 
 * if found
 * - SUBSCRIBE - looks for the Subscription-state in NOTIFY, refreshes the expiration 
 * and if terminated destroys the dialog
 * - When adding more dialogs, add the refreshal methods here or they will expire and will
 * be destroyed. Also add the termination to reduce the memory consumption and improve the
 * performance.
 * @param msg - the request/response
 * @param str1 - direction - "orig" or "term"
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error 
 */
int S_update_dialog(struct sip_msg* msg, char* str1, char* str2)
{
	str call_id;
	s_dialog *d;
	int response;
	int cseq;

	struct hdr_field *h=0;
	struct sip_msg *req=0;
	int expires=0;
	str totag;
	time_t t_time;
	str ses_exp = {0,0};
	str refresher = {0,0};

	enum s_dialog_direction dir = get_dialog_direction(str1);
		
//	if (!find_dialog_aor(msg,str1,&aor)){
//		req = cscf_get_request_from_reply(msg);		
//		if (!find_dialog_aor(req,str1,&aor)){
//			LOG(L_ERR,"ERR:"M_NAME":S_update_dialog(%s): Error retrieving %s contact\n",str1,str1);
//			return CSCF_RETURN_BREAK;
//		}
//	}		
		
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;

	LOG(L_DBG,"DBG:"M_NAME":S_update_dialog(%s): Call-ID <%.*s>\n",str1,call_id.len,call_id.s);

	d = get_s_dialog_dir(call_id,dir);
//	if (!d && msg->first_line.type==SIP_REPLY){
//		/* Try to get the dialog from the request */
//		if (!req) req = cscf_get_request_from_reply(msg);		
//		if (!find_dialog_aor(req,str1,&aor)){
//			LOG(L_ERR,"ERR:"M_NAME":S_update_dialog(%s): Error retrieving %s contact\n",str1,str1);
//			return CSCF_RETURN_BREAK;
//		}		
//		d = get_s_dialog_dir(call_id,aor);		
//	}
	if (!d){
		LOG(L_INFO,"INFO:"M_NAME":S_update_dialog: dialog does not exists!\n");	
		return CSCF_RETURN_FALSE;
	}


	if (msg->first_line.type==SIP_REQUEST){
		/* Request */
		LOG(L_DBG,"DBG:"M_NAME":S_update_dialog(%s): Method <%.*s> \n",str1,
			msg->first_line.u.request.method.len,msg->first_line.u.request.method.s);
		cseq = cscf_get_cseq(msg,&h);
		if (cseq>d->last_cseq) d->last_cseq = cseq;
		if (get_dialog_method(msg->first_line.u.request.method) == DLG_METHOD_INVITE)
		{
			d->uac_supp_timer = supports_extension(msg, &str_ext_timer);
	
			ses_exp = cscf_get_session_expires_body(msg, &h);
			t_time = cscf_get_session_expires(ses_exp, &refresher);
			if (!t_time)
			{
				d->expires = d_act_time()+scscf_dialogs_expiration_time;
				d->lr_session_expires = 0;
			}
			else
			{
				d->expires = d_act_time() + t_time;
				d->lr_session_expires = t_time;
				if (refresher.len)
					STR_SHM_DUP(d->refresher, refresher, "DIALOG_REFRESHER");
			}
		}
		else if (d->method == DLG_METHOD_SUBSCRIBE &&
			msg->first_line.u.request.method.len == 6 &&
			strncasecmp(msg->first_line.u.request.method.s,"NOTIFY",6)==0)
		{
			// Subscription-State header is mandatory for NOTIFY. See RFC 3265, Section 7.2
			expires = cscf_get_subscription_state(msg);
			if (expires >= 0)
				d->expires = d_act_time()+expires;
			else
				d->expires = d_act_time()+scscf_dialogs_expiration_time;
		}
		else
		{
			expires = cscf_get_expires_hdr(msg,0);
			if (expires >= 0)
			        d->expires = d_act_time()+expires;
			else
					d->expires = d_act_time()+scscf_dialogs_expiration_time;
	
			d->lr_session_expires = 0;		
		}
	}else{
		/* Reply */
		response = msg->first_line.u.reply.statuscode;
		LOG(L_DBG,"DBG:"M_NAME":S_update_dialog(%s): <%d> \n",str1,response);
		cseq = cscf_get_cseq(msg,&h);
		if (cseq==0 || h==0) return CSCF_RETURN_FALSE;
		if (d->first_cseq==cseq && d->method_str.len == ((struct cseq_body *)h->parsed)->method.len &&
			strncasecmp(d->method_str.s,((struct cseq_body *)h->parsed)->method.s,d->method_str.len)==0 &&
			d->state < DLG_STATE_CONFIRMED){
			/* reply to initial request */
			if (response<200){
				d->state = DLG_STATE_EARLY;
				d->expires = d_act_time()+300;
			}else
			if (response>=200 && response<300){
				d->state = DLG_STATE_CONFIRMED;
				update_dialog_on_reply(msg, d);
				
				/*I save the dialogs only here because
				 * i only want to release confirmed dialogs*/
				cscf_get_to_tag(msg,&totag);
				if (d->dialog_s){
					tmb.update_dlg_uas(d->dialog_s,response,&totag);
					tmb.dlg_response_uac(d->dialog_c,msg,IS_NOT_TARGET_REFRESH);
				}else{
					LOG(L_ERR,"ERR:S_update_dialog(): dialog_s for dialog was NULL!\n");
				}
			}else
				if (response>300){
					d->state = DLG_STATE_TERMINATED;
					d_unlock(d->hash);				
					struct cell * t = tmb.t_gett();
					if(t->nr_of_outgoings < 2)
						return S_drop_dialog(msg,str1,str2);
				}				
		}else{
			/* reply to subsequent request */			
			if (!req) req = cscf_get_request_from_reply(msg);
			
			/* destroy dialogs on specific methods */
			switch (d->method){
				case DLG_METHOD_OTHER:							
					d->expires = d_act_time()+scscf_dialogs_expiration_time;
					d->lr_session_expires = 0;
					break;
				
				case DLG_METHOD_INVITE:
					if (req && req->first_line.u.request.method.len==3 &&
						strncasecmp(req->first_line.u.request.method.s,"BYE",3)==0){
						d->state = DLG_STATE_TERMINATED;
						d_unlock(d->hash);				
						return S_drop_dialog(msg,str1,str2);
					}
					update_dialog_on_reply(msg, d);
					break;
				case DLG_METHOD_SUBSCRIBE:
//					if (req && req->first_line.u.request.method.len==9 &&
//						strncasecmp(req->first_line.u.request.method.s,"SUBSCRIBE",9)==0 &&
//						cscf_get_expires_hdr(msg)==0){						
//						d->state = DLG_STATE_TERMINATED;
//						d_unlock(d->hash);				
//						return P_dros_dialog(msg,str1,str2);
//					}
					if (req && req->first_line.u.request.method.len==6 &&
						strncasecmp(req->first_line.u.request.method.s,"NOTIFY",6)==0){
						expires = cscf_get_subscription_state(req);
						if (expires==0){						
							d->state = DLG_STATE_TERMINATED;
							d_unlock(d->hash);				
							return S_drop_dialog(msg,str1,str2);
						}else if (expires>0){
							d->expires = d_act_time() + expires;
						}
					}
					else if (req && req->first_line.u.request.method.len==9 &&
						strncasecmp(req->first_line.u.request.method.s,"SUBSCRIBE",9)==0){
						expires = cscf_get_expires_hdr(msg,0);
						if (expires >= 0)
							d->expires = d_act_time()+expires;
						else
							d->expires = d_act_time()+scscf_dialogs_expiration_time;
					}					
					break;
			}
			if (cseq>d->last_cseq) d->last_cseq = cseq;						
		}
	}
	
	d_unlock(d->hash);
	
	print_s_dialogs(L_INFO);
	
	return CSCF_RETURN_TRUE;	
out_of_memory:
	if (d) d_unlock(d->hash);
	return CSCF_RETURN_ERROR;	
}
Esempio n. 25
0
/**
 * Inserts the Route header containing the dialog routes to be enforced
 * @param msg - the SIP message to add to
 * @param str1 - the value to insert - !!! quoted if needed
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error 
 */
int P_enforce_dialog_routes(struct sip_msg *msg,char *str1,char*str2)
{
	int i;
	str newuri={0,0};
	p_dialog *d;
	str call_id,host;
	int port,transport;
	str x;
	enum p_dialog_direction dir;
	
	dir = get_dialog_direction(str1);
		
	if (!find_dialog_contact(msg,dir,&host,&port,&transport)){
		LOG(L_ERR,"ERR:"M_NAME":P_enforce_dialog_routes(): Error retrieving %s contact\n",str1);
		return CSCF_RETURN_BREAK;
	}		
		
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;

	LOG(L_INFO,"DBG:"M_NAME":P_enforce_dialog_routes(%s): Call-ID <%.*s> %d://%.*s:%d\n",
		str1,call_id.len,call_id.s,
		transport,host.len,host.s,port);

	d = get_p_dialog(call_id,host,port,transport,&dir);
	if (!d)
		d = get_p_dialog(call_id,host,port,transport,0);
	if (!d){
		LOG(L_ERR,"ERR:"M_NAME":P_enforce_dialog_routes: dialog does not exists!\n");	
		return CSCF_RETURN_FALSE;
	}

	if (!d->routes_cnt){
		d_unlock(d->hash);
		return CSCF_RETURN_TRUE;
	}

	x.len = route_s.len + route_e.len + (d->routes_cnt-1)*route_1.len;
	for(i=0;i<d->routes_cnt;i++)
		x.len+=d->routes[i].len;
			
	x.s = pkg_malloc(x.len);
	if (!x.s){
		LOG(L_ERR, "ERR:"M_NAME":P_enforce_dialog_routes: Error allocating %d bytes\n",
			x.len);
		x.len=0;
		d_unlock(d->hash);
		return CSCF_RETURN_ERROR;
	}
	x.len=0;
	STR_APPEND(x,route_s);
	for(i=0;i<d->routes_cnt;i++){
		if (i) STR_APPEND(x,route_1);
		STR_APPEND(x,d->routes[i]);
	}	
	STR_APPEND(x,route_e);
	
	newuri.s = pkg_malloc(d->routes[0].len);
	if (!newuri.s){
		LOG(L_ERR, "ERR:"M_NAME":P_enforce_dialog_routes: Error allocating %d bytes\n",
			d->routes[0].len);
		d_unlock(d->hash);
		return CSCF_RETURN_ERROR;
	}
	newuri.len = d->routes[0].len;
	memcpy(newuri.s,d->routes[0].s,newuri.len);
	if (msg->dst_uri.s) pkg_free(msg->dst_uri.s);
	msg->dst_uri = newuri;
	
	//LOG(L_ERR,"%.*s",x.len,x.s);
	d_unlock(d->hash);
	if (cscf_add_header_first(msg,&x,HDR_ROUTE_T)) {
		if (cscf_del_all_headers(msg,HDR_ROUTE_T))
			return CSCF_RETURN_TRUE;
		else {
			LOG(L_ERR,"ERR:"M_NAME":P_enforce_dialog_routes: new Route headers added, but failed to drop old ones.\n");
			return CSCF_RETURN_ERROR;
		}
	}
	else {
		if (x.s) pkg_free(x.s);
		return CSCF_RETURN_ERROR;
	}
}
Esempio n. 26
0
/**
 * Creates a snapshots of the dialogs data and then calls the dumping function.
 * @returns 1 on success or 0 on failure
 */
int make_snapshot_dialogs()
{
	bin_data x={0,0,0};
	p_dialog *d;
	int i,k;	
	time_t unique = time(0);
	FILE *f;

	switch (pcscf_persistency_mode) {
		case NO_PERSISTENCY:
			return 0;
			
		case WITH_FILES:
			f = bin_dump_to_file_create(pcscf_persistency_location,"pdialogs",unique);
			if (!f) return 0;

			for(i=0;i<p_dialogs_hash_size;i++){
				if (!bin_alloc(&x,1024)) goto error;		
				d_lock(i);
				d = p_dialogs[i].head;
				if (d){
					while(d){
						if (!bin_encode_p_dialog(&x,d)) goto error;
						d = d->next;
					}
					d_unlock(i);
					k = bind_dump_to_file_append(f,&x);
					if (k!=x.len) {
						LOG(L_ERR,"ERR:"M_NAME":make_snapshot_registrar: error while dumping to file - only wrote %d bytes of %d \n",k,x.len);
						d_unlock(i);
						bin_free(&x);
						return 0;
					} 
				}
				else d_unlock(i);
				bin_free(&x);
			}
			return bind_dump_to_file_close(f,pcscf_persistency_location,"pdialogs",unique);

			break;
			
		case WITH_DATABASE_BULK:
			if (!bin_alloc(&x,1024)) goto error;		
			for(i=0;i<p_dialogs_hash_size;i++){
				d_lock(i);
				d = p_dialogs[i].head;
				while(d){
					if (!bin_encode_p_dialog(&x,d)) goto error;
					d = d->next;
				}
				d_unlock(i);
			}

			return bin_dump_to_db(&x, P_DIALOGS);

		case WITH_DATABASE_CACHE:
			return bin_dump_to_db(NULL, P_DIALOGS); //ignore x, x is empty
		default:
			LOG(L_ERR,"ERR:"M_NAME":make_snapshot_registrar: Snapshot done but no such mode %d\n",pcscf_persistency_mode);
			return 0;
		
	}

error:
	if (x.s) bin_free(&x);	
	return 0;
}  
Esempio n. 27
0
/**
 * Updates a dialog.
 * If the initial request was:
 * - INVITE - refreshes the expiration or looks for the BYE and destroys the dialog 
 * if found
 * - SUBSCRIBE - looks for the Subscription-state in NOTIFY, refreshes the expiration 
 * and if terminated destroys the dialog
 * - When adding more dialogs, add the refreshal methods here or they will expire and will
 * be destroyed. Also add the termination to reduce the memory consumption and improve the
 * performance.
 * @param msg - the request/response
 * @param str1 - direction - "orig" or "term"
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error 
 */
int S_update_dialog(struct sip_msg* msg, char* str1, char* str2)
{
	str call_id;
	s_dialog *d;
	int response;
	int cseq;
	struct hdr_field *h=0;
	struct sip_msg *req=0;
	int expires=0;
	str totag;

	enum s_dialog_direction dir = get_dialog_direction(str1);
		
//	if (!find_dialog_aor(msg,str1,&aor)){
//		req = cscf_get_request_from_reply(msg);		
//		if (!find_dialog_aor(req,str1,&aor)){
//			LOG(L_ERR,"ERR:"M_NAME":S_update_dialog(%s): Error retrieving %s contact\n",str1,str1);
//			return CSCF_RETURN_BREAK;
//		}
//	}		
		
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;

	LOG(L_INFO,"DBG:"M_NAME":S_update_dialog(%s): Call-ID <%.*s>\n",str1,call_id.len,call_id.s);

	d = get_s_dialog_dir(call_id,dir);
//	if (!d && msg->first_line.type==SIP_REPLY){
//		/* Try to get the dialog from the request */
//		if (!req) req = cscf_get_request_from_reply(msg);		
//		if (!find_dialog_aor(req,str1,&aor)){
//			LOG(L_ERR,"ERR:"M_NAME":S_update_dialog(%s): Error retrieving %s contact\n",str1,str1);
//			return CSCF_RETURN_BREAK;
//		}		
//		d = get_s_dialog_dir(call_id,aor);		
//	}
	if (!d){
		LOG(L_INFO,"INFO:"M_NAME":S_update_dialog: dialog does not exists!\n");	
		return CSCF_RETURN_FALSE;
	}


	if (msg->first_line.type==SIP_REQUEST){
		/* Request */
		LOG(L_DBG,"DBG:"M_NAME":S_update_dialog(%s): Method <%.*s> \n",str1,
			msg->first_line.u.request.method.len,msg->first_line.u.request.method.s);
		cseq = cscf_get_cseq(msg,&h);
		if (cseq>d->last_cseq) d->last_cseq = cseq;
		d->expires = d_act_time()+scscf_dialogs_expiration_time;
	}else{
		/* Reply */
		response = msg->first_line.u.reply.statuscode;
		LOG(L_DBG,"DBG:"M_NAME":S_update_dialog(%s): <%d> \n",str1,response);
		cseq = cscf_get_cseq(msg,&h);
		if (cseq==0 || h==0) return CSCF_RETURN_FALSE;
		if (d->first_cseq==cseq && d->method_str.len == ((struct cseq_body *)h->parsed)->method.len &&
			strncasecmp(d->method_str.s,((struct cseq_body *)h->parsed)->method.s,d->method_str.len)==0 &&
			d->state < DLG_STATE_CONFIRMED){
			/* reply to initial request */
			if (response<200){
				d->state = DLG_STATE_EARLY;
				d->expires = d_act_time()+300;
			}else
			if (response>=200 && response<300){
				d->state = DLG_STATE_CONFIRMED;
				d->expires = d_act_time()+scscf_dialogs_expiration_time;
				/*I save the dialogs only here because
				 * i only want to release confirmed dialogs*/
				cscf_get_to_tag(msg,&totag);
				tmb.update_dlg_uas(d->dialog_s,response,&totag);
				tmb.dlg_response_uac(d->dialog_c,msg,IS_NOT_TARGET_REFRESH);				
			}else
				if (response>300){
					d->state = DLG_STATE_TERMINATED;
					d_unlock(d->hash);				
					return S_drop_dialog(msg,str1,str2);
				}				
		}else{
			/* reply to subsequent request */			
			if (!req) req = cscf_get_request_from_reply(msg);
			
			/* destroy dialogs on specific methods */
			switch (d->method){
				case DLG_METHOD_OTHER:							
					d->expires = d_act_time()+scscf_dialogs_expiration_time;
					break;
				case DLG_METHOD_INVITE:
					if (req && req->first_line.u.request.method.len==3 &&
						strncasecmp(req->first_line.u.request.method.s,"BYE",3)==0){
						d->state = DLG_STATE_TERMINATED;
						d_unlock(d->hash);				
						return S_drop_dialog(msg,str1,str2);
					}
					d->expires = d_act_time()+scscf_dialogs_expiration_time;
					break;
				case DLG_METHOD_SUBSCRIBE:
//					if (req && req->first_line.u.request.method.len==9 &&
//						strncasecmp(req->first_line.u.request.method.s,"SUBSCRIBE",9)==0 &&
//						cscf_get_expires_hdr(msg)==0){						
//						d->state = DLG_STATE_TERMINATED;
//						d_unlock(d->hash);				
//						return P_dros_dialog(msg,str1,str2);
//					}
					if (req && req->first_line.u.request.method.len==6 &&
						strncasecmp(req->first_line.u.request.method.s,"NOTIFY",6)==0){
						expires = cscf_get_subscription_state(req);
						if (expires==0){						
							d->state = DLG_STATE_TERMINATED;
							d_unlock(d->hash);				
							return S_drop_dialog(msg,str1,str2);
						}else if (expires>0){
							d->expires = expires;
						}
					}
					break;
			}
			if (cseq>d->last_cseq) d->last_cseq = cseq;						
		}
	}
	
	d_unlock(d->hash);
	
//	print_s_dialogs(L_INFO);
	
	return CSCF_RETURN_TRUE;	
}
Esempio n. 28
0
/**
 * Saves a dialog.
 * @param msg - the initial request
 * @param str1 - direction - "orig" or "term"
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error 
 */
int S_save_dialog(struct sip_msg* msg, char* str1, char* str2)
{
	str call_id;
	s_dialog *d;
	str aor;
	char buf1[256],buf2[256];
	str uri,tag,ruri,x;	
	time_t t_time;
	str ses_exp = {0,0};
	str refresher = {0,0};
	str event = {0,0};
	struct hdr_field *h;
	unsigned int hash;
	
	enum s_dialog_direction dir = get_dialog_direction(str1);
	
	if (!find_dialog_aor(msg,dir,&aor)){
		LOG(L_ERR,"ERR:"M_NAME":S_save_dialog(): Error retrieving %s contact\n",str1);
		return CSCF_RETURN_BREAK;
	}		
		
	call_id = cscf_get_call_id(msg,0);
	if (!call_id.len)
		return CSCF_RETURN_FALSE;

	LOG(L_INFO,"DBG:"M_NAME":S_save_dialog(%s): Call-ID <%.*s>\n",str1,call_id.len,call_id.s);

	if (is_s_dialog(call_id,aor,dir)){
		LOG(L_ERR,"ERR:"M_NAME":S_save_dialog: dialog already exists!\n");	
		return CSCF_RETURN_TRUE;
	}
	
	d = add_s_dialog(call_id,aor,dir);
	if (!d) return CSCF_RETURN_FALSE;

	d->method = get_dialog_method(msg->first_line.u.request.method);
	STR_SHM_DUP(d->method_str,msg->first_line.u.request.method,"shm");
	d->first_cseq = cscf_get_cseq(msg,0);
	d->last_cseq = d->first_cseq;
	d->state = DLG_STATE_INITIAL;

	d->uac_supp_timer = supports_extension(msg, &str_ext_timer);

	ses_exp = cscf_get_session_expires_body(msg, &h);
	t_time = cscf_get_session_expires(ses_exp, &refresher);
	if (!t_time) {
		d->expires = d_act_time() + 60;
		d->lr_session_expires = 0;
	} else {
		d->expires = d_act_time() + t_time;
		d->lr_session_expires = t_time;
		if (refresher.len)
			STR_SHM_DUP(d->refresher, refresher, "DIALOG_REFRESHER");
	}
	
	cscf_get_from_tag(msg,&tag);
	cscf_get_from_uri(msg,&x);
	uri.len = snprintf(buf1,256,"<%.*s>",x.len,x.s);
	uri.s = buf1;	
	cscf_get_to_uri(msg,&x);
	ruri.len = snprintf(buf2,256,"<%.*s>",x.len,x.s);
	ruri.s = buf2;
	 
	tmb.new_dlg_uac(&call_id,
						&tag,
						d->first_cseq,&uri,
						&ruri,
						&d->dialog_c);
	
	tmb.new_dlg_uas(msg,99,&d->dialog_s);
	
	event = cscf_get_event(msg);
	if (event.len){
		STR_SHM_DUP(d->event,event,"shm");
	}
	else
		d->event = event;

	d_unlock(d->hash);
	
	print_s_dialogs(L_INFO);
	
	return CSCF_RETURN_TRUE;	
out_of_memory:
	if (d){
		hash = d->hash;
		del_s_dialog(d);
		d_unlock(hash);
	}
	return CSCF_RETURN_ERROR;	
}
Esempio n. 29
0
/**
 * Loads the dialogs data from the last snapshot.
 * @returns 1 on success or 0 on failure
 */
int load_snapshot_dialogs()
{
	bin_data x;
	p_dialog *d;
	int k,max;
	FILE *f;

	switch (pcscf_persistency_mode){
		case NO_PERSISTENCY:
			k=0;

		case WITH_FILES:
			f = bin_load_from_file_open(pcscf_persistency_location,"pdialogs");		
			if (!f) return 0;
			bin_alloc(&x,128*1024);
			k=bin_load_from_file_read(f,&x);
			max = x.max;
			x.max=0;
			LOG(L_INFO,"INFO:"M_NAME":load_snapshot_dialogs: max %d len %d\n",x.max,x.len);
			while(x.max<x.len){
				d = bin_decode_p_dialog(&x);
				if (!d) return 0;
				LOG(L_INFO,"INFO:"M_NAME":load_snapshot_dialogs: Loaded p_dialog for <%.*s>\n",d->host.len,d->host.s);
				d_lock(d->hash);
				d->prev = p_dialogs[d->hash].tail;
				d->next = 0;
				if (p_dialogs[d->hash].tail) p_dialogs[d->hash].tail->next = d;
				p_dialogs[d->hash].tail = d;
				if (!p_dialogs[d->hash].head) p_dialogs[d->hash].head = d;
				d_unlock(d->hash);
				
				memmove(x.s,x.s+x.max,x.len-x.max);
				x.len -= x.max;
				x.max = max;
				k=bin_load_from_file_read(f,&x);
				max = x.max;
				x.max = 0;				
			}
			bin_free(&x);
			bin_load_from_file_close(f);
			k = 1;
			break;
			
		case WITH_DATABASE_BULK:
			k=bin_load_from_db(&x, P_DIALOGS);
			x.max=0;
			LOG(L_INFO,"INFO:"M_NAME":load_snapshot_dialogs: max %d len %d\n",x.max,x.len);
			while(x.max<x.len){
				d = bin_decode_p_dialog(&x);
				if (!d) return 0;
				LOG(L_INFO,"INFO:"M_NAME":load_snapshot_dialogs: Loaded p_dialog for <%.*s>\n",d->host.len,d->host.s);
				d_lock(d->hash);
				d->prev = p_dialogs[d->hash].tail;
				d->next = 0;
				if (p_dialogs[d->hash].tail) p_dialogs[d->hash].tail->next = d;
				p_dialogs[d->hash].tail = d;
				if (!p_dialogs[d->hash].head) p_dialogs[d->hash].head = d;
				d_unlock(d->hash);
			}
			bin_free(&x);
			break;
			
		case WITH_DATABASE_CACHE:
			k=bin_load_from_db(NULL, P_DIALOGS); //ignore x, x is empty
			break;
			
		default:
			LOG(L_ERR,"ERR:"M_NAME":load_snapshot_dialogs: Can't resume because no such mode %d\n",pcscf_persistency_mode);
			k=0;
	}	
	if (!k) goto error;
	
	
	return 1;
error:
	return 0;
}