Ejemplo n.º 1
0
/**
 * Timer function for peer management.
 * This is registered as a timer by peer_manager_init() and gets called every
 * #PEER_MANAGER_TIMER seconds. Then it looks on what changed and triggers events.
 * @param now - time of call
 * @param ptr - generic pointer for timers - not used
 */
void peer_timer(time_t now,void *ptr)
{
	peer *p,*n;
	LOG(L_DBG,"DBG:peer_timer(): taking care of peers...\n");
	lock_get(peer_list_lock);
	p = peer_list->head;
	while(p){
		lock_get(p->lock);
		n = p->next;
		if (p->activity+config->tc<=now){
			LOG(L_INFO,"DBG:peer_timer(): Peer %.*s \tState %d \n",p->fqdn.len,p->fqdn.s,p->state);
			switch (p->state){
				/* initiating connection */
				case Closed:
					if (p->is_dynamic && config->drop_unknown_peers){
						remove_peer(p);
						free_peer(p,1);
						break;
					}
					touch_peer(p);
					sm_process(p,Start,0,1,0);
					break;
				/* timeouts */	
				case Wait_Conn_Ack:
				case Wait_I_CEA:
				case Closing:
				case Wait_Returns:
					touch_peer(p);
					sm_process(p,Timeout,0,1,0);
					break;	
				/* inactivity detected */
				case I_Open:
				case R_Open:
					if (p->waitingDWA){
						p->waitingDWA = 0;
						if (p->state==I_Open) sm_process(p,I_Peer_Disc,0,1,p->I_sock);
						if (p->state==R_Open) sm_process(p,R_Peer_Disc,0,1,p->R_sock);
					} else {
						p->waitingDWA = 1;
						Snd_DWR(p);
						touch_peer(p);
					}
					break;
				/* ignored states */	
				/* unknown states */
				default:
					LOG(L_ERR,"ERROR:peer_timer(): Peer %.*s inactive  in state %d\n",
						p->fqdn.len,p->fqdn.s,p->state);
			}				
		}
		lock_release(p->lock);
		p = n;
	}
	lock_release(peer_list_lock);
	log_peer_list(L_INFO);	
}
Ejemplo n.º 2
0
/**
 * Timer function for peer management.
 * This is registered as a timer by peer_manager_init() and gets called every
 * #PEER_MANAGER_TIMER seconds. Then it looks on what changed and triggers events.
 * @param now - time of call
 * @param ptr - generic pointer for timers - not used
 */
int peer_timer(time_t now,void *ptr)
{
	peer *p,*n;
	int i;
	LM_DBG("peer_timer(): taking care of peers...\n");
	lock_get(peer_list_lock);
	p = peer_list->head;
	while(p){
		lock_get(p->lock);
		n = p->next;

		if (p->disabled && (p->state != Closed || p->state != Closing)) {
			LM_DBG("Peer [%.*s] has been disabled - shutting down\n", p->fqdn.len, p->fqdn.s);
			if (p->state == I_Open) sm_process(p, Stop, 0, 1, p->I_sock);
			if (p->state == R_Open) sm_process(p, Stop, 0, 1, p->R_sock);
			lock_release(p->lock);
			p = n;
			continue;
		}

		if (p->activity+config->tc<=now){
			LM_DBG("peer_timer(): Peer %.*s State %d \n",p->fqdn.len,p->fqdn.s,p->state);
			switch (p->state){
				/* initiating connection */
				case Closed:
					if (p->is_dynamic && config->drop_unknown_peers){
						remove_peer(p);
						free_peer(p,1);
						break;
					}
					if (!p->disabled) {
						touch_peer(p);
						sm_process(p,Start,0,1,0);
					}
					break;
					/* timeouts */
				case Wait_Conn_Ack:
				case Wait_I_CEA:
				case Closing:
				case Wait_Returns:
				case Wait_Conn_Ack_Elect:
					touch_peer(p);
					sm_process(p,Timeout,0,1,0);
					break;
					/* inactivity detected */
				case I_Open:
				case R_Open:
					if (p->waitingDWA){
						p->waitingDWA = 0;
						if (p->state==I_Open) sm_process(p,I_Peer_Disc,0,1,p->I_sock);
						if (p->state==R_Open) sm_process(p,R_Peer_Disc,0,1,p->R_sock);
						LM_WARN("Inactivity on peer [%.*s] and no DWA, Closing peer...\n", p->fqdn.len, p->fqdn.s);
					} else {
						p->waitingDWA = 1;
						Snd_DWR(p);
						touch_peer(p);
						if (debug_heavy)
						{
							LM_DBG("Inactivity on peer [%.*s], sending DWR... - if we don't get a reply, the peer will be closed\n", p->fqdn.len, p->fqdn.s);
						}
					}
					break;
					/* ignored states */
					/* unknown states */
				default:
					LM_ERR("peer_timer(): Peer %.*s inactive  in state %d\n",
							p->fqdn.len,p->fqdn.s,p->state);
			}
		}
		lock_release(p->lock);
		p = n;
	}
	lock_release(peer_list_lock);
	log_peer_list();
	i = config->tc/5;
	if (i<=0) i=1;
	return i;
}
Ejemplo n.º 3
0
/**
 * Diameter base protocol state-machine processing.
 * This function get's called for every event. It updates the states and can trigger
 * other events.
 * @param p - the peer for which the event happened
 * @param event - the event that happened
 * @param msg - if a Diameter message was received this is it, or NULL if not
 * @param peer_locked - if the peer lock is already aquired
 * @param sock - socket that this event happened on, or NULL if unrelated
 * @returns 1 on success, 0 on error. Also the peer states are updated
 */
int sm_process(peer *p,peer_event_t event,AAAMessage *msg,int peer_locked,int sock)
{
	int result_code;
	peer_event_t next_event;
	int msg_received=0;
		
	if (!peer_locked) lock_get(p->lock);
	LM_DBG("sm_process(): Peer %.*s \tState %s \tEvent %s\n",
		p->fqdn.len,p->fqdn.s,dp_states[p->state],dp_events[event-101]);

	switch (p->state){
		case Closed:
			switch (event){
				case Start:
					p->state = Wait_Conn_Ack;
					next_event = I_Snd_Conn_Req(p);
					if (next_event==I_Rcv_Conn_NAck)
						sm_process(p,next_event,0,1,p->I_sock);
					else{
						/* wait for fd to be transmitted to the respective receiver, in order to get a send pipe opened */						
					}
					break;	
				case R_Conn_CER:
					R_Accept(p,sock);
					result_code = Process_CER(p,msg);
					Snd_CEA(p,msg,result_code,p->R_sock);
					msg=0;
					if (result_code>=2000 && result_code<3000)
						p->state = R_Open;
					else {
						R_Disc(p);
						p->state = Closed;
					}
					log_peer_list(L_INFO);
					break;
				case Stop:
					/* just ignore this state */
					p->state = Closed;
					break;
				default:
					LM_ERR("sm_process(): In state %s invalid event %s\n",
						dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;		
		case Wait_Conn_Ack:
			switch(event){
				case I_Rcv_Conn_Ack:
					I_Snd_CER(p);
					p->state = Wait_I_CEA;
					break;	
				case I_Rcv_Conn_NAck:
					Cleanup(p,p->I_sock);
					p->state = Closed;
					break;
				case R_Conn_CER:
					if (p->r_cer) AAAFreeMessage(&(p->r_cer));
					R_Accept(p,sock);
					result_code = Process_CER(p,msg);
					if (result_code>=2000 && result_code<3000){
						p->state = Wait_Conn_Ack_Elect;
						p->r_cer = msg;
					}
					else {
						p->state = Closed;
						AAAFreeMessage(&msg);
						R_Disc(p);
						I_Disc(p);
					}
					break;
				case Timeout:
					Error(p,p->I_sock);
					p->state = Closed;
				default:
					LM_ERR("sm_process(): In state %s invalid event %s\n",
						dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;
			
		case Wait_I_CEA:
			switch(event){
				case I_Rcv_CEA:
					result_code = Process_CEA(p,msg);
					if (result_code>=2000 && result_code<3000)
						p->state = I_Open; 												
					else {
						Cleanup(p,p->I_sock);
						p->state = Closed;
					}
					log_peer_list(L_INFO);
					break;
				case R_Conn_CER:
					if (p->r_cer) AAAFreeMessage(&(p->r_cer));
					R_Accept(p,sock);
					result_code = Process_CER(p,msg);
					if (result_code>=2000 && result_code<3000){
						p->state = Wait_Returns;
						if (Elect(p,msg)){
							// won the election = > I_Disc(), R_Send_CEA()
							LM_INFO("sm_process():Wait_I_CEA Win Elect \n");
							sm_process(p,Win_Election,msg,1,sock);
						} else {
							// lost the election => wait for I_Recv_CEA, then R_Disc()
							LM_INFO("sm_process():Wait_I_CEA Lose Elect \n");
							p->r_cer = msg;
							sm_process(p,I_Peer_Disc,0,1,p->I_sock);
						}
					}
					else{
						Snd_CEA(p,msg,result_code,p->R_sock);
						R_Disc(p);
						I_Disc(p);
						p->state=Closed;
						break;
					}					
					break;
				case I_Peer_Disc:
					I_Disc(p);
					p->state = Closed;
					break;
				case I_Rcv_Non_CEA:
					Error(p,p->I_sock);
					p->state = Closed;
					break;
				case Timeout:
					Error(p,p->I_sock);
					p->state = Closed;
					break;
				default:
					LM_ERR("sm_process(): In state %s invalid event %s\n",
						dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;	
			
		case Wait_Conn_Ack_Elect:
			switch(event){
				case I_Rcv_Conn_Ack:
					I_Snd_CER(p);
					if (p->r_cer){
						p->state = Wait_Returns;
						if (Elect(p,p->r_cer)){
							// won the election = > I_Disc(), R_Send_CEA()
							LM_INFO("sm_process():Wait_Conn_Ack_Elect Win Elect \n");
							sm_process(p,Win_Election,p->r_cer,1,sock);
							p->r_cer = 0;
						} else {
							// lost the election => wait for I_Recv_CEA, then R_Disc()
							LM_INFO("sm_process():Wait_Conn_Ack_Elect Lose Elect \n");
							AAAFreeMessage(&p->r_cer);
						}
					} else {
						LM_ERR("sm_process():Wait_Conn_Ack_Elect, I_Rcv_Conn_Ack, No R-CER ! \n");
						p->state = Wait_I_CEA;
					}
					break;
				case I_Rcv_Conn_NAck:
					Cleanup(p,p->I_sock);
					if (p->r_cer){
						result_code = Process_CER(p,p->r_cer);
						Snd_CEA(p,p->r_cer,result_code,p->R_sock);
						p->r_cer=0;
						if (result_code>=2000 && result_code<3000)
							p->state = R_Open;
						else {
							R_Disc(p);
							p->state = Closed;
						//	p->state = R_Open; /* Or maybe I should disconnect it?*/
						}
					}else{
						LM_ERR("sm_process():Wait_Conn_Ack_Elect, I_Rcv_Conn_NAck No R-CER ! \n");
					}
					break;
				case R_Peer_Disc:
					R_Disc(p);
					p->state = Wait_Conn_Ack;
					break;
				case R_Conn_CER:
					R_Reject(p,sock);
					AAAFreeMessage(&msg);
					p->state = Wait_Conn_Ack_Elect;
					break;
				case Timeout:
					if (p->I_sock>=0) Error(p,p->I_sock);
					if (p->R_sock>=0) Error(p,p->R_sock);
					p->state = Closed;
					break;
				default:
					LM_ERR("sm_process(): In state %s invalid event %s\n",
						dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;
			
		case Wait_Returns:
			switch(event){
				case Win_Election:
					/* this is the Win Election -> I is dropped, R is kept */
					LM_INFO("sm_process():Wait_Returns Win Elect \n");
					I_Disc(p);
					result_code = Process_CER(p,msg);
					Snd_CEA(p,msg,result_code,p->R_sock);
					if (result_code>=2000 && result_code<3000){
						p->state = R_Open;
					}else{
						R_Disc(p);
						p->state = Closed;
					}
					break;
				case I_Peer_Disc:
					I_Disc(p);
					if (p->r_cer){
						result_code = Process_CER(p,p->r_cer);
						Snd_CEA(p,p->r_cer,result_code,p->R_sock);
						p->r_cer=0;
						if (result_code>=2000 && result_code<3000){
							p->state = R_Open;
						}else{
							R_Disc(p);
							p->state = Closed;
						}
					}else {
						LM_ERR("sm_process():Wait_Returns, I_Peer_Disc No R-CER ! \n");						
					}
					break;
				case I_Rcv_CEA:
					/* this is the Lost Election -> I is kept, R dropped */
					LM_INFO("sm_process():Wait_Returns Lost Elect \n");
					R_Disc(p);
					result_code = Process_CEA(p,msg);
					if (result_code>=2000 && result_code<3000)
						p->state = I_Open; 
					else {
						Cleanup(p,p->I_sock);
						p->state = Closed;
					}
					break;
				case R_Peer_Disc:
					R_Disc(p);
					p->state = Wait_I_CEA;
					break;
				case R_Conn_CER:
					R_Reject(p,p->R_sock);
					AAAFreeMessage(&msg);
					p->state = Wait_Returns;
					break;
				case Timeout:
					if (p->I_sock>=0) Error(p,p->I_sock);
					if (p->R_sock>=0) Error(p,p->R_sock);
					p->state = Closed;
				default:
					LM_ERR("sm_process(): In state %s invalid event %s\n",
						dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;
		case R_Open:
			switch (event){
				case Send_Message:
					Snd_Message(p,msg);
					p->state = R_Open;
					break;
				case R_Rcv_Message:
					// delayed processing until out of the critical zone
					//Rcv_Process(p,msg);
					msg_received = 1;
					p->state = R_Open;
					break;
				case R_Rcv_DWR:
					result_code = Process_DWR(p,msg);
					Snd_DWA(p,msg,result_code,p->R_sock);
					p->state = R_Open;
					break;
				case R_Rcv_DWA:
					Process_DWA(p,msg);
					p->state = R_Open;
					break;
				case R_Conn_CER:
					R_Reject(p,sock);
					AAAFreeMessage(&msg);
					p->state = R_Open;
					break;
				case Stop:
					Snd_DPR(p);
					p->state = Closing;
					break;
				case R_Rcv_DPR:
					Snd_DPA(p,msg,AAA_SUCCESS,p->R_sock);
					R_Disc(p);
					p->state = Closed;
					log_peer_list(L_INFO);
					break;
				case R_Peer_Disc:
					R_Disc(p);
					p->state = Closed;
					log_peer_list(L_INFO);
					break;
				case R_Rcv_CER:
					result_code = Process_CER(p,msg);
					Snd_CEA(p,msg,result_code,p->R_sock);
					if (result_code>=2000 && result_code<3000)
						p->state = R_Open;
					else {
						/*R_Disc(p);p.state = Closed;*/
						p->state = R_Open; /* Or maybe I should disconnect it?*/
					}
					break;
				case R_Rcv_CEA:
					result_code = Process_CEA(p,msg);
					if (result_code>=2000 && result_code<3000)
						p->state = R_Open;
					else {
						/*R_Disc(p);p.state = Closed;*/
						p->state = R_Open; /* Or maybe I should disconnect it?*/
					}
					log_peer_list(L_INFO);
					break;
				default:
					LM_ERR("sm_process(): In state %s invalid event %s\n",
						dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;			
		case I_Open:
			switch (event){
				case Send_Message:
					Snd_Message(p,msg);
					p->state = I_Open;
					break;
				case I_Rcv_Message:
					// delayed processing until out of the critical zone
					//Rcv_Process(p,msg);
					msg_received = 1;
					p->state = I_Open;
					break;
				case I_Rcv_DWR:
					result_code = Process_DWR(p,msg);
					Snd_DWA(p,msg,result_code,p->I_sock);						
					p->state =I_Open;
					break;
				case I_Rcv_DWA:
					Process_DWA(p,msg);
					p->state =I_Open;
					break;
				case R_Conn_CER:
					R_Reject(p,sock);
					AAAFreeMessage(&msg);
					p->state = I_Open;
					break;
				case Stop:
					Snd_DPR(p);
					p->state = Closing;
					break;
				case I_Rcv_DPR:
					Snd_DPA(p,msg,2001,p->I_sock);
					I_Disc(p);
					p->state = Closed;
					log_peer_list(L_INFO);
					break;
				case I_Peer_Disc:
					I_Disc(p);
					p->state = Closed;
					log_peer_list(L_INFO);
					break;
				case I_Rcv_CER:
					result_code = Process_CER(p,msg);
					Snd_CEA(p,msg,result_code,p->I_sock);
					if (result_code>=2000 && result_code<3000)
						p->state = I_Open;
					else {
						/*I_Disc(p);p.state = Closed;*/
						p->state = I_Open; /* Or maybe I should disconnect it?*/
					}
					break;
				case I_Rcv_CEA:
					result_code = Process_CEA(p,msg);
					if (result_code>=2000 && result_code<3000)
						p->state = I_Open;
					else {
						/*I_Disc(p);p.state = Closed;*/
						p->state = I_Open; /* Or maybe I should disconnect it?*/
					}
					break;
				default:
					LM_ERR("sm_process(): In state %s invalid event %s\n",
						dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;				
		case Closing:
			switch(event){
				case I_Rcv_DPA:
					I_Disc(p);
					p->state = Closed;
					break;
				case R_Rcv_DPA:
					R_Disc(p);
					p->state = Closed;
					break;
				case Timeout:
					if (p->I_sock>=0) Error(p,p->I_sock);
					if (p->R_sock>=0) Error(p,p->R_sock);
					p->state = Closed;
					break;
				case I_Peer_Disc:
					I_Disc(p);
					p->state = Closed;
					break;
				case R_Peer_Disc:
					R_Disc(p);
					p->state = Closed;
					break;
				default:
					LM_ERR("sm_process(): In state %s invalid event %s\n",
						dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;				
	}
	if (!peer_locked) lock_release(p->lock);
	
	if (msg_received)
		Rcv_Process(p,msg);
	
	return 1;	
error:
	if (!peer_locked) lock_release(p->lock);
	return 0;	
}
Ejemplo n.º 4
0
/**
 * Diameter base protocol state-machine processing.
 * This function get's called for every event. It updates the states and can trigger
 * other events.
 * @param p - the peer for which the event happened
 * @param event - the event that happened
 * @param msg - if a Diameter message was received this is it, or NULL if not
 * @param peer_locked - if the peer lock is already aquired
 * @param sock - socket that this event happened on, or NULL if unrelated
 * @returns 1 on success, 0 on error. Also the peer states are updated
 */
int sm_process(peer *p,peer_event_t event,AAAMessage *msg,int peer_locked,int sock)
{
	int result_code;
	peer_event_t next_event;
	int msg_received=0;
		
	if (!peer_locked) lock_get(p->lock);
	LOG(L_INFO,"DBG:sm_process(): Peer %.*s \tState %s \tEvent %s\n",
		p->fqdn.len,p->fqdn.s,dp_states[p->state],dp_events[event-101]);

	switch (p->state){
		case Closed:
			switch (event){
				case Start:
					p->state = Wait_Conn_Ack;
					next_event = I_Snd_Conn_Req(p);
					sm_process(p,next_event,0,1,p->I_sock);
					break;	
				case R_Conn_CER:
					R_Accept(p,sock);
					result_code = Process_CER(p,msg);
					Snd_CEA(p,msg,result_code,p->R_sock);
					if (result_code>=2000 && result_code<3000)
						p->state = R_Open;
					else {
						R_Disc(p);
						p->state = Closed;
					}
					log_peer_list(L_INFO);
					break;
				case Stop:
					/* just ignore this state */
					p->state = Closed;
					break;
				default:
					LOG(L_DBG,"DBG:sm_process(): In state %s invalid event %s\n",
						dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;		
		case Wait_Conn_Ack:
			switch(event){
				case I_Rcv_Conn_Ack:
					I_Snd_CER(p);
					p->state = Wait_I_CEA;
					break;	
				case I_Rcv_Conn_NAck:
					Cleanup(p,p->I_sock);
					p->state = Closed;
					break;
/* Commented as not reachable*/						
				case R_Conn_CER:
					R_Accept(p,sock);
					result_code = Process_CER(p,msg);
					if (result_code>=2000 && result_code<3000)
						p->state = Wait_Conn_Ack_Elect;
					else {
						p->state = Wait_Conn_Ack;
						close(sock);
					}
					break;
				case Timeout:
					Error(p,p->I_sock);
					p->state = Closed;
				default:
					LOG(L_DBG,"DBG:sm_process(): In state %s invalid event %s\n",
						dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;
			
		case Wait_I_CEA:
			switch(event){
				case I_Rcv_CEA:
					result_code = Process_CEA(p,msg);
					if (result_code>=2000 && result_code<3000)
						p->state = I_Open; 												
					else {
						Cleanup(p,p->I_sock);
						p->state = Closed;
					}
					log_peer_list(L_INFO);
					break;
				case R_Conn_CER:
					R_Accept(p,sock);
					result_code = Process_CER(p,msg);
					p->state = Wait_Returns;
					if (Elect(p,msg))
						sm_process(p,Win_Election,msg,1,sock);
					break;
				case I_Peer_Disc:
					I_Disc(p);
					p->state = Closed;
					break;
				case I_Rcv_Non_CEA:
					Error(p,p->I_sock);
					p->state = Closed;
					break;
				case Timeout:
					Error(p,p->I_sock);
					p->state = Closed;
					break;
				default:
					LOG(L_DBG,"DBG:sm_process(): In state %s invalid event %s\n",
						dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;	
/* commented as not reachable */
		case Wait_Conn_Ack_Elect:
			switch(event){
				default:
					LOG(L_DBG,"DBG:sm_process(): In state %s invalid event %s\n",
						dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;
		case Wait_Returns:
			switch(event){
				case Win_Election:
					I_Disc(p);
					result_code = Process_CER(p,msg);
					Snd_CEA(p,msg,result_code,p->R_sock);
					if (result_code>=2000 && result_code<3000){
						p->state = R_Open;
					}else{
						R_Disc(p);
						p->state = Closed;
					}
					break;
				case I_Peer_Disc:
					I_Disc(p);
					result_code = Process_CER(p,msg);
					Snd_CEA(p,msg,result_code,p->R_sock);
					if (result_code>=2000 && result_code<3000){
						p->state = R_Open;
					}else{
						R_Disc(p);
						p->state = Closed;
					}
					break;
				case I_Rcv_CEA:
					R_Disc(p);
					result_code = Process_CEA(p,msg);
					if (result_code>=2000 && result_code<3000)
						p->state = I_Open; 
					else {
						Cleanup(p,p->I_sock);
						p->state = Closed;
					}
					break;
				case R_Peer_Disc:
					R_Disc(p);
					p->state = Wait_I_CEA;
					break;
				case R_Conn_CER:
					R_Reject(p,p->R_sock);
					p->state = Wait_Returns;
					break;
				case Timeout:
					if (p->I_sock>=0) Error(p,p->I_sock);
					if (p->R_sock>=0) Error(p,p->R_sock);
					p->state = Closed;
				default:
					LOG(L_DBG,"DBG:sm_process(): In state %s invalid event %s\n",
						dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;
		case R_Open:
			switch (event){
				case Send_Message:
					Snd_Message(p,msg);
					p->state = R_Open;
					break;
				case R_Rcv_Message:
					// delayed processing until out of the critical zone
					//Rcv_Process(p,msg);
					msg_received = 1;
					p->state = R_Open;
					break;
				case R_Rcv_DWR:
					result_code = Process_DWR(p,msg);
					Snd_DWA(p,msg,result_code,p->R_sock);
					p->state = R_Open;
					break;
				case R_Rcv_DWA:
					Process_DWA(p,msg);
					p->state = R_Open;
					break;
				case R_Conn_CER:
					R_Reject(p,sock);
					p->state = R_Open;
					break;
				case Stop:
					Snd_DPR(p);
					p->state = Closing;
					break;
				case R_Rcv_DPR:
					Snd_DPA(p,msg,AAA_SUCCESS,p->R_sock);
					R_Disc(p);
					p->state = Closed;
					log_peer_list(L_INFO);
					break;
				case R_Peer_Disc:
					R_Disc(p);
					p->state = Closed;
					log_peer_list(L_INFO);
					break;
				case R_Rcv_CER:
					result_code = Process_CER(p,msg);
					Snd_CEA(p,msg,result_code,p->R_sock);
					if (result_code>=2000 && result_code<3000)
						p->state = R_Open;
					else {
						/*R_Disc(p);p.state = Closed;*/
						p->state = R_Open; /* Or maybe I should disconnect it?*/
					}
					break;
				case R_Rcv_CEA:
					result_code = Process_CEA(p,msg);
					if (result_code>=2000 && result_code<3000)
						p->state = R_Open;
					else {
						/*R_Disc(p);p.state = Closed;*/
						p->state = R_Open; /* Or maybe I should disconnect it?*/
					}
					log_peer_list(L_INFO);
					break;
				default:
					LOG(L_DBG,"DBG:sm_process(): In state %s invalid event %s\n",
						dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;			
		case I_Open:
			switch (event){
				case Send_Message:
					Snd_Message(p,msg);
					p->state = I_Open;
					break;
				case I_Rcv_Message:
					// delayed processing until out of the critical zone
					//Rcv_Process(p,msg);
					msg_received = 1;
					p->state = I_Open;
					break;
				case I_Rcv_DWR:
					result_code = Process_DWR(p,msg);
					Snd_DWA(p,msg,result_code,p->I_sock);						
					p->state =I_Open;
					break;
				case I_Rcv_DWA:
					Process_DWA(p,msg);
					p->state =I_Open;
					break;
				case R_Conn_CER:
					R_Reject(p,sock);
					p->state = I_Open;
					break;
				case Stop:
					Snd_DPR(p);
					p->state = Closing;
					break;
				case I_Rcv_DPR:
					Snd_DPA(p,msg,2001,p->I_sock);
					R_Disc(p);
					p->state = Closed;
					log_peer_list(L_INFO);
					break;
				case I_Peer_Disc:
					I_Disc(p);
					p->state = Closed;
					log_peer_list(L_INFO);
					break;
				case I_Rcv_CER:
					result_code = Process_CER(p,msg);
					Snd_CEA(p,msg,result_code,p->I_sock);
					if (result_code>=2000 && result_code<3000)
						p->state = I_Open;
					else {
						/*I_Disc(p);p.state = Closed;*/
						p->state = I_Open; /* Or maybe I should disconnect it?*/
					}
					break;
				case I_Rcv_CEA:
					result_code = Process_CEA(p,msg);
					if (result_code>=2000 && result_code<3000)
						p->state = I_Open;
					else {
						/*I_Disc(p);p.state = Closed;*/
						p->state = I_Open; /* Or maybe I should disconnect it?*/
					}
					break;
				default:
					LOG(L_DBG,"DBG:sm_process(): In state %s invalid event %s\n",
						dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;				
		case Closing:
			switch(event){
				case I_Rcv_DPA:
					I_Disc(p);
					p->state = Closed;
					break;
				case R_Rcv_DPA:
					R_Disc(p);
					p->state = Closed;
					break;
				case Timeout:
					if (p->I_sock>=0) Error(p,p->I_sock);
					if (p->R_sock>=0) Error(p,p->R_sock);
					p->state = Closed;
					break;
				case I_Peer_Disc:
					I_Disc(p);
					p->state = Closed;
					break;
				case R_Peer_Disc:
					R_Disc(p);
					p->state = Closed;
					break;
				default:
					LOG(L_DBG,"DBG:sm_process(): In state %s invalid event %s\n",
						dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;				
	}
	if (!peer_locked) lock_release(p->lock);
	
	if (msg_received)
		Rcv_Process(p,msg);
	
	return 1;	
error:
	if (!peer_locked) lock_release(p->lock);
	return 0;	
}