示例#1
0
/**
 * Checks if Session-Expires value is over Min_SE local policy
 * @param msg - the initial request
 * @param str1 - not used
 * @param str2 - not used
 * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not
*/
int S_check_session_expires(struct sip_msg* msg, char* str1, char* str2)
{
	time_t t_time;
	time_t min_se_time = 0;
	str ses_exp = {0,0};
 	str min_se = {0,0};
	str new_min_se = {0,0};
	str new_ses_exp = {0,0};
	struct hdr_field *h_se, *h_min_se;
	str refresher;

	ses_exp = cscf_get_session_expires_body(msg, &h_se);
	t_time = cscf_get_session_expires(ses_exp, &refresher);
	
	if (!t_time || t_time >= scscf_min_se)
		return CSCF_RETURN_TRUE;
	if (!supports_extension(msg, &str_ext_timer)) //does not suports timer extension
	{
		//add Min-SE header with its minimum interval
		min_se = cscf_get_min_se(msg, &h_min_se);
		if (min_se.len) {
			strtotime(min_se, min_se_time);
			if (min_se_time < scscf_min_se)
				cscf_del_header(msg, h_min_se);
			else
				return CSCF_RETURN_TRUE;
		}
		new_min_se.len = 11/*int value*/ + str_min_se.len+3;
		new_min_se.s = pkg_malloc(new_min_se.len+1);
		if (!new_min_se.s) {
			LOG(L_ERR,"ERR:"M_NAME":S_check_session_expires: Error allocating %d bytes\n",new_min_se.len);
			goto error;
		}
		new_min_se.len = snprintf(new_min_se.s, new_min_se.len, "%.*s %d\r\n",str_min_se.len, str_min_se.s, scscf_min_se);
		min_se_time = scscf_min_se;
		cscf_add_header(msg, &new_min_se, HDR_OTHER_T);
		if (t_time < scscf_min_se) {
			cscf_del_header(msg, h_se);
			new_ses_exp.len = 11 + str_se.len+3;
			new_ses_exp.s = pkg_malloc(new_ses_exp.len+1);
			if (!new_ses_exp.s) {
				LOG(L_ERR,"ERR:"M_NAME":S_check_session_expires: Error allocating %d bytes\n",new_ses_exp.len);
				goto error;
			}
			new_ses_exp.len = snprintf(new_ses_exp.s, new_ses_exp.len, "%.*s %d\r\n",str_se.len, str_se.s, scscf_min_se);
			t_time = scscf_min_se;
			cscf_add_header(msg, &new_ses_exp, HDR_OTHER_T);
		}
		return CSCF_RETURN_TRUE;
	}
error:
	if (new_min_se.s) pkg_free(new_min_se.s);
	if (new_ses_exp.s) pkg_free(new_ses_exp.s);
	return CSCF_RETURN_FALSE;
}		
示例#2
0
/**
 * Updates dialog on reply message
 * @param msg - the SIP message 
 * @param d - dialog to modify
 * @returns 1 on success or 0 on error
 */
int update_dialog_on_reply(struct sip_msg *msg, s_dialog *d)
{
	struct hdr_field *h_req;
	struct hdr_field *h=0;
	int res=0;
	time_t t_time=0;
	str ses_exp = {0,0};
	str refresher = {0,0};
	str new_ses_exp = {0,0};
	str new_ext = {0,0};
	int expires = 0;

	ses_exp = cscf_get_session_expires_body(msg, &h);
	t_time = cscf_get_session_expires(ses_exp, &refresher);
	if (!t_time) //i.e not session-expires header in response
	{
		if (!d->uac_supp_timer || !d->lr_session_expires)
		{
			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;
			}
		}
		else// uac supports timer, but no session-expires header found in response
		{
			d->expires = d_act_time()+d->lr_session_expires;
			
			new_ses_exp.len = 11/*int value*/ + str_se.len+s_refresher.len+8;
			new_ses_exp.s = pkg_malloc(new_ses_exp.len+1);
			if (!new_ses_exp.s) {
				LOG(L_ERR,"ERR:"M_NAME":update_dialog_on_reply: Error allocating %d bytes\n",new_ses_exp.len);
				goto error;
			}
			new_ses_exp.len = snprintf(new_ses_exp.s, new_ses_exp.len, "%.*s %d; %.*suac\r\n",str_se.len, str_se.s, (int)d->lr_session_expires ,s_refresher.len, s_refresher.s);
			cscf_add_header(msg, &new_ses_exp, HDR_OTHER_T);
			if (!requires_extension(msg, &str_ext_timer)) //must have require timer extenstion
			{
				/* walk through all Require headers to find first require header*/
				res = parse_headers(msg, HDR_EOH_F, 0);
				if (res == -1) {
					ERR("Error while parsing headers (%d)\n", res);
					return 0; /* what to return here ? */
				}
				
				h_req = msg->require;
				while (h_req) {
					if (h_req->type == HDR_REQUIRE_T) {
						if (h_req->body.s[new_ext.len-1]=='\n')
						{
							new_ext.len = str_require.len + 1/* */+h_req->body.len + 7;/*, timer*/
							new_ext.s = pkg_malloc(new_ext.len);
							if (!new_ext.s) {
								LOG(L_ERR,"ERR:"M_NAME":update_dialog_on_reply: Error allocating %d bytes\n",new_ext.len);
								goto error;
							}			
							new_ext.len = snprintf(new_ext.s, str_require.len, "%.*s %.*s, timer\r\n", str_require.len, str_require.s, h_req->body.len-2, h_req->body.s);
						}
						else
						{
							new_ext.len = str_require.len + 1/*space*/ + h_req->body.len + 9;/*, timer\r\n*/
							new_ext.s = pkg_malloc(new_ext.len);
							if (!new_ext.s) {
								LOG(L_ERR,"ERR:"M_NAME":update_dialog_on_reply: Error allocating %d bytes\n",new_ext.len);
								goto error;
							}			
							new_ext.len = snprintf(new_ext.s, str_require.len, "%.*s %.*s, timer\r\n", str_require.len, str_require.s, h_req->body.len, h_req->body.s);
						}
						cscf_del_header(msg, h_req);
						cscf_add_header(msg, &new_ext, HDR_REQUIRE_T);
						break;
					}
					h_req = h_req->next;
				}
			}
		}
	}
	else{
		d->expires = d_act_time() + t_time;
		d->lr_session_expires = t_time;
	}
	return 1;
error:
	if (new_ses_exp.s) pkg_free(new_ses_exp.s);
	if (new_ext.s) pkg_free(new_ext.s);
	return 0;	
}
示例#3
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;	
}
示例#4
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;	
}
示例#5
0
文件: dlg_state.c 项目: asyn/openvims
/**
 * 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;	
}