/** * 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); }
/** * Sends a message to the peer. * \note Must be called with a lock on the peer. * @param p - peer to send to * @param msg - message to send */ void Snd_Message(peer *p, AAAMessage *msg) { AAASession *session=0; int rcode; int send_message_before_session_sm=0; touch_peer(p); if (msg->sessionId) session = get_session(msg->sessionId->data); if (session){ switch (session->type){ case AUTH_CLIENT_STATEFULL: if (is_req(msg)) auth_client_statefull_sm_process(session,AUTH_EV_SEND_REQ,msg); else { if (msg->commandCode == IMS_ASA){ if (!msg->res_code){ msg->res_code = AAAFindMatchingAVP(msg,0,AVP_Result_Code,0,0); } if (!msg->res_code) auth_client_statefull_sm_process(session,AUTH_EV_SEND_ASA_UNSUCCESS,msg); else { rcode = get_4bytes(msg->res_code->data.s); if (rcode>=2000 && rcode<3000) { peer_send_msg(p,msg); send_message_before_session_sm=1; auth_client_statefull_sm_process(session,AUTH_EV_SEND_ASA_SUCCESS,msg); } else auth_client_statefull_sm_process(session,AUTH_EV_SEND_ASA_UNSUCCESS,msg); } }else auth_client_statefull_sm_process(session,AUTH_EV_SEND_ANS,msg); } break; case AUTH_SERVER_STATEFULL: if (is_req(msg)) { if (msg->commandCode== IMS_ASR) { auth_server_statefull_sm_process(session,AUTH_EV_SEND_ASR,msg); } else { //would be a RAR but ok! auth_server_statefull_sm_process(session,AUTH_EV_SEND_REQ,msg); } } else { if (msg->commandCode == IMS_STR) auth_server_statefull_sm_process(session,AUTH_EV_SEND_STA,msg); else auth_server_statefull_sm_process(session,AUTH_EV_SEND_ANS,msg); } break; default: break; } sessions_unlock(session->hash); } if (!send_message_before_session_sm) peer_send_msg(p,msg); }
/** * Finds a peer based on the FQDN and Realm. * @param fqdn - the FQDN to look for * @param realm - the Realm to look for * @returns the peer* or NULL if not found */ peer *get_peer_from_fqdn(str fqdn,str realm) { peer *i; lock_get(peer_list_lock); i = peer_list->head; while(i){ if (fqdn.len == i->fqdn.len && strncasecmp(fqdn.s,i->fqdn.s,fqdn.len)==0) break; i = i->next; } lock_release(peer_list_lock); if (!i&&config->accept_unknown_peers){ i = new_peer(fqdn,realm,3868); if (i){ i->is_dynamic=1; touch_peer(i); add_peer(i); } } return i; }
/** * Receives a mesasge and does basic processing or call the sm_process(). * This gets called from the receive_loop for every message that is received. * @param msg - the message received * @param sock - socket received on */ void receive_message(AAAMessage *msg,int sock) { AAA_AVP *avp1,*avp2; LOG(L_DBG,"DBG:receive_message(): [%d] Recv msg %d\n",sock,msg->commandCode); if (!this_peer) { this_peer = get_peer_from_sock(sock); set_peer_pipe(); } if (!this_peer){ switch (msg->commandCode){ case Code_CE: if (is_req(msg)){ avp1 = AAAFindMatchingAVP(msg,msg->avpList.head,AVP_Origin_Host,0,0); avp2 = AAAFindMatchingAVP(msg,msg->avpList.head,AVP_Origin_Realm,0,0); if (avp1&&avp2){ this_peer = get_peer_from_fqdn(avp1->data,avp2->data); } if (!this_peer) { LOG(L_ERR,"ERROR:receive_msg(): Received CER from unknown peer (accept unknown=%d) -ignored\n", config->accept_unknown_peers); AAAFreeMessage(&msg); }else{ set_peer_pipe(); sm_process(this_peer,R_Conn_CER,msg,0,sock); } } else{ LOG(L_ERR,"ERROR:receive_msg(): Received CEA from an unknown peer -ignored\n"); AAAFreeMessage(&msg); } break; default: LOG(L_ERR,"ERROR:receive_msg(): Received non-CE from an unknown peer -ignored\n"); AAAFreeMessage(&msg); } }else{ touch_peer(this_peer); switch (this_peer->state){ case Wait_I_CEA: if (msg->commandCode!=Code_CE||is_req(msg)){ sm_process(this_peer,I_Rcv_Non_CEA,msg,0,sock); }else sm_process(this_peer,I_Rcv_CEA,msg,0,sock); break; case I_Open: switch (msg->commandCode){ case Code_CE: if (is_req(msg)) sm_process(this_peer,I_Rcv_CER,msg,0,sock); else sm_process(this_peer,I_Rcv_CEA,msg,0,sock); break; case Code_DW: if (is_req(msg)) sm_process(this_peer,I_Rcv_DWR,msg,0,sock); else sm_process(this_peer,I_Rcv_DWA,msg,0,sock); break; case Code_DP: if (is_req(msg)) sm_process(this_peer,I_Rcv_DPR,msg,0,sock); else sm_process(this_peer,I_Rcv_DPA,msg,0,sock); break; default: sm_process(this_peer,I_Rcv_Message,msg,0,sock); } break; case R_Open: switch (msg->commandCode){ case Code_CE: if (is_req(msg)) sm_process(this_peer,R_Rcv_CER,msg,0,sock); else sm_process(this_peer,R_Rcv_CEA,msg,0,sock); break; case Code_DW: if (is_req(msg)) sm_process(this_peer,R_Rcv_DWR,msg,0,sock); else sm_process(this_peer,R_Rcv_DWA,msg,0,sock); break; case Code_DP: if (is_req(msg)) sm_process(this_peer,R_Rcv_DPR,msg,0,sock); else sm_process(this_peer,R_Rcv_DPA,msg,0,sock); break; default: sm_process(this_peer,R_Rcv_Message,msg,0,sock); } break; default: LOG(L_ERR,"ERROR:receive_msg(): Received msg while peer in state %d -ignored\n",this_peer->state); AAAFreeMessage(&msg); } } }
/** * Receiver - Accept a connection. * \note Must be called with a lock on the peer. * @param p - peer identification * @param sock - socket to communicate through */ void R_Accept(peer *p,int sock) { p->R_sock = sock; touch_peer(p); }
/** * Sends a message to the peer. * \note Must be called with a lock on the peer. * @param p - peer to send to * @param msg - message to send */ void Snd_Message(peer *p, AAAMessage *msg) { AAASession *session=0; int rcode; int send_message_before_session_sm=0; LM_DBG("Snd_Message called to peer [%.*s] for %s with code %d \n", p->fqdn.len,p->fqdn.s,is_req(msg)?"request":"response",msg->commandCode); touch_peer(p); if (msg->sessionId) session = cdp_get_session(msg->sessionId->data); if (session){ LM_DBG("There is a session of type %d\n",session->type); switch (session->type){ case AUTH_CLIENT_STATEFULL: if (is_req(msg)) { auth_client_statefull_sm_process(session,AUTH_EV_SEND_REQ,msg); session = 0; } else { if (msg->commandCode == IMS_ASA){ if (!msg->res_code){ msg->res_code = AAAFindMatchingAVP(msg,0,AVP_Result_Code,0,0); } if (!msg->res_code) { auth_client_statefull_sm_process(session,AUTH_EV_SEND_ASA_UNSUCCESS,msg); session = 0; } else { rcode = get_4bytes(msg->res_code->data.s); if (rcode>=2000 && rcode<3000) { peer_send_msg(p,msg); send_message_before_session_sm=1; auth_client_statefull_sm_process(session,AUTH_EV_SEND_ASA_SUCCESS,msg); session = 0; } else { auth_client_statefull_sm_process(session,AUTH_EV_SEND_ASA_UNSUCCESS,msg); session = 0; } } }else { auth_client_statefull_sm_process(session,AUTH_EV_SEND_ANS,msg); session = 0; } } break; case AUTH_SERVER_STATEFULL: LM_DBG("this message is matched here to see what request or reply it is\n"); if (is_req(msg)) { if (msg->commandCode== IMS_ASR) { LM_DBG("ASR\n"); auth_server_statefull_sm_process(session,AUTH_EV_SEND_ASR,msg); session = 0; } else { //would be a RAR but ok! LM_DBG("other request\n"); auth_server_statefull_sm_process(session,AUTH_EV_SEND_REQ,msg); session = 0; } } else { if (msg->commandCode == IMS_STR) { LM_DBG("STA\n"); auth_server_statefull_sm_process(session,AUTH_EV_SEND_STA,msg); session = 0; } else { LM_DBG("other reply\n"); auth_server_statefull_sm_process(session,AUTH_EV_SEND_ANS,msg); session = 0; } } break; default: break; } if (session) AAASessionsUnlock(session->hash); } if (!send_message_before_session_sm) peer_send_msg(p,msg); }
/** * 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; }
/** * Receives a message and does basic processing or call the sm_process(). * This gets called from the do_receive() for every message that is received. * Basic processing, before the state machine, is done here. * @param msg - the message received * @param sp - the serviced peer that it was receiver on */ void receive_message(AAAMessage *msg,serviced_peer_t *sp) { AAA_AVP *avp1,*avp2; LM_DBG("receive_message(): [%.*s] Recv msg %d\n", sp->p?sp->p->fqdn.len:0, sp->p?sp->p->fqdn.s:0, msg->commandCode); if (!sp->p){ switch (msg->commandCode){ case Code_CE: if (is_req(msg)){ avp1 = AAAFindMatchingAVP(msg,msg->avpList.head,AVP_Origin_Host,0,0); avp2 = AAAFindMatchingAVP(msg,msg->avpList.head,AVP_Origin_Realm,0,0); if (avp1&&avp2){ sp->p = get_peer_from_fqdn(avp1->data,avp2->data); } if (!sp->p) { LM_ERR("receive_msg(): Received CER from unknown peer (accept unknown=%d) -ignored\n", config->accept_unknown_peers); AAAFreeMessage(&msg); }else{ LM_DBG("receive_message(): [%.*s] This receiver has no peer associated\n", sp->p?sp->p->fqdn.len:0, sp->p?sp->p->fqdn.s:0 ); //set_peer_pipe(); make_send_pipe(sp); sm_process(sp->p,R_Conn_CER,msg,0,sp->tcp_socket); } } else{ LM_ERR("receive_msg(): Received CEA from an unknown peer -ignored\n"); AAAFreeMessage(&msg); } break; default: LM_ERR("receive_msg(): Received non-CE from an unknown peer -ignored\n"); AAAFreeMessage(&msg); } }else{ touch_peer(sp->p); switch (sp->p->state){ case Wait_I_CEA: if (msg->commandCode!=Code_CE||is_req(msg)){ sm_process(sp->p,I_Rcv_Non_CEA,msg,0,sp->tcp_socket); }else sm_process(sp->p,I_Rcv_CEA,msg,0,sp->tcp_socket); break; case I_Open: switch (msg->commandCode){ case Code_CE: if (is_req(msg)) sm_process(sp->p,I_Rcv_CER,msg,0,sp->tcp_socket); else sm_process(sp->p,I_Rcv_CEA,msg,0,sp->tcp_socket); break; case Code_DW: if (is_req(msg)) sm_process(sp->p,I_Rcv_DWR,msg,0,sp->tcp_socket); else sm_process(sp->p,I_Rcv_DWA,msg,0,sp->tcp_socket); break; case Code_DP: if (is_req(msg)) sm_process(sp->p,I_Rcv_DPR,msg,0,sp->tcp_socket); else sm_process(sp->p,I_Rcv_DPA,msg,0,sp->tcp_socket); break; default: sm_process(sp->p,I_Rcv_Message,msg,0,sp->tcp_socket); } break; case R_Open: switch (msg->commandCode){ case Code_CE: if (is_req(msg)) sm_process(sp->p,R_Rcv_CER,msg,0,sp->tcp_socket); else sm_process(sp->p,R_Rcv_CEA,msg,0,sp->tcp_socket); break; case Code_DW: if (is_req(msg)) sm_process(sp->p,R_Rcv_DWR,msg,0,sp->tcp_socket); else sm_process(sp->p,R_Rcv_DWA,msg,0,sp->tcp_socket); break; case Code_DP: if (is_req(msg)) sm_process(sp->p,R_Rcv_DPR,msg,0,sp->tcp_socket); else sm_process(sp->p,R_Rcv_DPA,msg,0,sp->tcp_socket); break; default: sm_process(sp->p,R_Rcv_Message,msg,0,sp->tcp_socket); } break; default: LM_ERR("receive_msg(): [%.*s] Received msg while peer in state %d -ignored\n", sp->p->fqdn.len, sp->p->fqdn.s, sp->p->state); AAAFreeMessage(&msg); } } }
/** * Sends a message to the peer. * \note Must be called with a lock on the peer. * @param p - peer to send to * @param msg - message to send */ void Snd_Message(peer *p, AAAMessage *msg) { touch_peer(p); peer_send_msg(p,msg); }