/** * 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); }
void session_timer(time_t now, void* ptr) { int hash; cdp_session_t *x; AAASessionCallback_f *cb; LOG(L_DBG,"-------session timer --------\n"); for(hash=0;hash<sessions_hash_size;hash++){ sessions_lock(hash); for(x = sessions[hash].head;x;x=x->next) { LOG(L_DBG,"session of type [%i] with id %.*s in hash %u\n",x->type,x->id.len,x->id.s,hash); if (x->type==AUTH_CLIENT_STATEFULL) { LOG(L_DBG,"auth state [%i] timeout [%li]\n",x->u.auth.state,x->u.auth.timeout-now); } else LOG(L_INFO,"\n"); switch (x->type){ case AUTH_CLIENT_STATEFULL: if (x->u.auth.timeout!=0 && x->u.auth.timeout<=now){ //Session timeout LOG(L_CRIT,"session TIMEOUT\n"); if (x->cb) { cb = x->cb; (cb)(AUTH_EV_SESSION_TIMEOUT,x->cb_param,x); } auth_client_statefull_sm_process(x,AUTH_EV_SESSION_TIMEOUT,0); } if (x->u.auth.timeout!=0 && x->u.auth.lifetime+x->u.auth.grace_period<=now){ //lifetime + grace timeout LOG(L_CRIT,"grace TIMEOUT\n"); if (x->cb){ cb = x->cb; (cb)(AUTH_EV_SESSION_GRACE_TIMEOUT,x->cb_param,x); } auth_client_statefull_sm_process(x,AUTH_EV_SESSION_GRACE_TIMEOUT,0); } break; default: break; } } sessions_unlock(hash); } LOG(L_DBG,"-------------------------------\n"); }
/** * Sends a Service terminated event to the session */ void AAATerminateAuthSession(AAASession *s) { if (s->type==AUTH_CLIENT_STATEFULL) { auth_client_statefull_sm_process(s,AUTH_EV_SERVICE_TERMINATED,0); } }
/** * Processes an incoming message. * This actually just puts the message into a message queue. One worker will pick-it-up * and do the actual processing. * \note Must be called with a lock on the peer. * @param p - peer received from * @param msg - the message received */ void Rcv_Process(peer *p, AAAMessage *msg) { AAASession *session=0; int nput=0; if (msg->sessionId) session = cdp_get_session(msg->sessionId->data); if (session){ switch (session->type){ case AUTH_CLIENT_STATEFULL: if (is_req(msg)){ if (msg->commandCode==IMS_ASR) auth_client_statefull_sm_process(session,AUTH_EV_RECV_ASR,msg); else auth_client_statefull_sm_process(session,AUTH_EV_RECV_REQ,msg); session = 0; }else { if (msg->commandCode==IMS_STA) nput=auth_client_statefull_sm_process(session,AUTH_EV_RECV_STA,msg); else auth_client_statefull_sm_process(session,AUTH_EV_RECV_ANS,msg); session = 0; } break; case AUTH_SERVER_STATEFULL: if (is_req(msg)) { if (msg->commandCode==IMS_STR) { auth_server_statefull_sm_process(session,AUTH_EV_RECV_STR,msg); } else { auth_server_statefull_sm_process(session,AUTH_EV_RECV_REQ,msg); } session = 0; }else{ if (msg->commandCode==IMS_ASA) auth_server_statefull_sm_process(session,AUTH_EV_RECV_ASA,msg); else auth_server_statefull_sm_process(session,AUTH_EV_RECV_ANS,msg); session = 0; } break; default: AAASessionsUnlock(session->hash); session =0; break; } }else{ if (msg->sessionId){ if (msg->commandCode == IMS_ASR) auth_client_statefull_sm_process(0,AUTH_EV_RECV_ASR,msg); } } if (!nput && !put_task(p,msg)){ LM_ERR("Rcv_Process(): Queue refused task\n"); if (msg) AAAFreeMessage(&msg); } //if (msg) LM_ERR("Rcv_Process(): task added to queue command %d, flags %#1x endtoend %u hopbyhop %u\n",msg->commandCode,msg->flags,msg->endtoendId,msg->hopbyhopId); // AAAPrintMessage(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) { 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); }
/** * Processes an incoming message. * This actually just puts the message into a message queue. One worker will pick-it-up * and do the actual processing. * \note Must be called with a lock on the peer. * @param p - peer received from * @param msg - the message received */ void Rcv_Process(peer *p, AAAMessage *msg) { AAASession *session=0; int nput=0; if (msg->sessionId) session = cdp_get_session(msg->sessionId->data); if (session){ switch (session->type){ case ACCT_CC_CLIENT: if (is_req(msg)){ LM_WARN("unhandled receive request on Credit Control Acct session\n"); AAASessionsUnlock(session->hash); //must be called because we dont call state machine here session = 0; //we dont call SM here so we mustnt set to 0 } else { cc_acc_client_stateful_sm_process(session, ACC_CC_EV_RECV_ANS, msg); session = 0; } break; case AUTH_CLIENT_STATEFULL: if (is_req(msg)){ if (msg->commandCode==IMS_ASR) auth_client_statefull_sm_process(session,AUTH_EV_RECV_ASR,msg); else auth_client_statefull_sm_process(session,AUTH_EV_RECV_REQ,msg); session = 0; }else { if (msg->commandCode==IMS_STA) nput=auth_client_statefull_sm_process(session,AUTH_EV_RECV_STA,msg); else auth_client_statefull_sm_process(session,AUTH_EV_RECV_ANS,msg); session = 0; } break; case AUTH_SERVER_STATEFULL: if (is_req(msg)) { if (msg->commandCode==IMS_STR) { auth_server_statefull_sm_process(session,AUTH_EV_RECV_STR,msg); } else { auth_server_statefull_sm_process(session,AUTH_EV_RECV_REQ,msg); } session = 0; }else{ if (msg->commandCode==IMS_ASA) auth_server_statefull_sm_process(session,AUTH_EV_RECV_ASA,msg); else auth_server_statefull_sm_process(session,AUTH_EV_RECV_ANS,msg); session = 0; } break; default: AAASessionsUnlock(session->hash); session =0; break; } }else{ if (msg->sessionId){ if (msg->commandCode == IMS_ASR) auth_client_statefull_sm_process(0,AUTH_EV_RECV_ASR,msg); } } if (!nput && !put_task(p,msg)){ LM_ERR("Rcv_Process(): Queue refused task\n"); if (msg) AAAFreeMessage(&msg); } //if (msg) LM_ERR("Rcv_Process(): task added to queue command %d, flags %#1x endtoend %u hopbyhop %u\n",msg->commandCode,msg->flags,msg->endtoendId,msg->hopbyhopId); // AAAPrintMessage(msg); }
/** * Processes an incoming message. * This actually just puts the message into a message queue. One worker will pick-it-up * and do the actual processing. * \note Must be called with a lock on the peer. * @param p - peer received from * @param msg - the message received */ void Rcv_Process(peer *p, AAAMessage *msg) { AAASession *session=0; unsigned int hash; // we need this here because after the sm_processing , we might end up // with no session any more if (msg->sessionId) session = get_session(msg->sessionId->data); if (session){ hash=session->hash; switch (session->type){ case AUTH_CLIENT_STATEFULL: if (is_req(msg)){ if (msg->commandCode==IMS_ASR) auth_client_statefull_sm_process(session,AUTH_EV_RECV_ASR,msg); else auth_client_statefull_sm_process(session,AUTH_EV_RECV_REQ,msg); }else { if (msg->commandCode==IMS_STA) auth_client_statefull_sm_process(session,AUTH_EV_RECV_STA,msg); else auth_client_statefull_sm_process(session,AUTH_EV_RECV_ANS,msg); } break; case AUTH_SERVER_STATEFULL: if (is_req(msg)) { auth_server_statefull_sm_process(session,AUTH_EV_RECV_REQ,msg); }else{ if (msg->commandCode==IMS_ASA) auth_server_statefull_sm_process(session,AUTH_EV_RECV_ASA,msg); else auth_server_statefull_sm_process(session,AUTH_EV_RECV_ANS,msg); } break; default: break; } sessions_unlock(hash); }else{ if (msg->sessionId){ if (msg->commandCode == IMS_ASR) auth_client_statefull_sm_process(0,AUTH_EV_RECV_ASR,msg); if (msg->commandCode == IMS_AAR) { session=AAACreateAuthSession(0,0,1,0,0); shm_str_dup(session->id,msg->sessionId->data); auth_server_statefull_sm_process(0,AUTH_EV_RECV_REQ,msg); } // Any other cases to think about? } } if (!put_task(p,msg)){ LOG(L_ERR,"ERROR:Rcv_Process(): Queue refused task\n"); AAAFreeMessage(&msg); } LOG(L_DBG,"DBG:Rcv_Process(): task added to queue\n"); // AAAPrintMessage(msg); }
int cdp_sessions_timer(time_t now, void* ptr) { int hash; cdp_session_t *x,*n; for(hash=0;hash<sessions_hash_size;hash++){ AAASessionsLock(hash); for(x = sessions[hash].head;x;x=n) { n = x->next; switch (x->type){ case ACCT_CC_CLIENT: if (x->u.cc_acc.type == ACC_CC_TYPE_SESSION) { //check for old, stale sessions, we need to do something more elegant //here to ensure that if a CCR start record is sent and the client never sends anything //else that we catch it and clean up the session from within CDP, calling all callbacks, etc if ((time(0) > (x->u.cc_acc.discon_time + GRACE_DISCON_TIMEOUT)) && (x->u.cc_acc.state==ACC_CC_ST_DISCON)) { cc_acc_client_stateful_sm_process(x, ACC_CC_EV_SESSION_STALE, 0); } //check reservation timers - again here we are assuming CC-Time applications int last_res_timestamp = x->u.cc_acc.last_reservation_request_time; int res_valid_for = x->u.cc_acc.reserved_units_validity_time; int last_reservation = x->u.cc_acc.reserved_units; int buffer_time = 15; //15 seconds - TODO: add as config parameter //we should check for reservation expiries if the state is open if(x->u.cc_acc.state==ACC_CC_ST_OPEN){ if (last_res_timestamp) { //we have obv already started reservations if ((last_res_timestamp + res_valid_for) < (time(0) + last_reservation + buffer_time)) { LM_DBG("reservation about to expire, sending callback\n"); cc_acc_client_stateful_sm_process(x, ACC_CC_EV_RSVN_WARNING, 0); } } } /* TODO: if reservation has expired we need to tear down the session. Ideally * the client application (module) should do this but for completeness we should * put a failsafe here too. */ } break; case AUTH_CLIENT_STATEFULL: if (x->u.auth.timeout>=0 && x->u.auth.timeout<=now){ //Session timeout LM_CRIT("session TIMEOUT\n"); auth_client_statefull_sm_process(x,AUTH_EV_SESSION_TIMEOUT,0); } else if (x->u.auth.lifetime>0 && x->u.auth.lifetime+x->u.auth.grace_period<=now){ //lifetime + grace timeout LM_CRIT("lifetime+grace TIMEOUT\n"); auth_client_statefull_sm_process(x,AUTH_EV_SESSION_GRACE_TIMEOUT,0); }else if (x->u.auth.lifetime>0 && x->u.auth.lifetime<=now){ //lifetime timeout LM_CRIT("lifetime+grace TIMEOUT\n"); auth_client_statefull_sm_process(x,AUTH_EV_SESSION_LIFETIME_TIMEOUT,0); } break; case AUTH_SERVER_STATEFULL: if (x->u.auth.timeout>=0 && x->u.auth.timeout<=now){ //Session timeout LM_CRIT("session TIMEOUT\n"); auth_server_statefull_sm_process(x,AUTH_EV_SESSION_TIMEOUT,0); }else if (x->u.auth.lifetime>0 && x->u.auth.lifetime+x->u.auth.grace_period<=now){ //lifetime + grace timeout LM_CRIT("lifetime+grace TIMEOUT\n"); auth_server_statefull_sm_process(x,AUTH_EV_SESSION_GRACE_TIMEOUT,0); }else if (x->u.auth.lifetime>0 && x->u.auth.lifetime<=now){ //lifetime timeout LM_CRIT("lifetime+grace TIMEOUT\n"); auth_server_statefull_sm_process(x,AUTH_EV_SESSION_LIFETIME_TIMEOUT,0); } break; default: break; } } AAASessionsUnlock(hash); } if (now%5==0)cdp_sessions_log(); return 1; }