/** * Authorization Client State-Machine - Stateless * \Note - should be called with a lock on the session and will unlock it - do not use it after! * @param s * @param event * @param msg */ inline void auth_client_stateless_sm_process(cdp_session_t* s, int event, AAAMessage *msg) { cdp_auth_session_t *x; int rc; if (!s) return; x = &(s->u.auth); switch(x->state){ case AUTH_ST_IDLE: switch(event){ case AUTH_EV_SEND_REQ: x->state = AUTH_ST_PENDING; break; default: LOG(L_ERR,"ERR:auth_client_stateless_sm_process(): Received invalid event %d while in state %s!\n", event,auth_states[x->state]); } break; case AUTH_ST_PENDING: if (!is_req(msg)){ rc = get_result_code(msg); if (rc>=2000 && rc<3000 && get_auth_session_state(msg)==NO_STATE_MAINTAINED) event = AUTH_EV_RECV_ANS_SUCCESS; else event = AUTH_EV_RECV_ANS_UNSUCCESS; } switch(event){ case AUTH_EV_RECV_ANS_SUCCESS: x->state = AUTH_ST_OPEN; break; case AUTH_EV_RECV_ANS_UNSUCCESS: x->state = AUTH_ST_IDLE; break; default: LOG(L_ERR,"ERR:auth_client_stateless_sm_process(): Received invalid event %d while in state %s!\n", event,auth_states[x->state]); } break; case AUTH_ST_OPEN: switch(event){ case AUTH_EV_SESSION_TIMEOUT: x->state = AUTH_ST_IDLE; break; case AUTH_EV_SERVICE_TERMINATED: x->state = AUTH_ST_IDLE; break; default: LOG(L_ERR,"ERR:auth_client_stateless_sm_process(): Received invalid event %d while in state %s!\n", event,auth_states[x->state]); } break; default: LOG(L_ERR,"ERR:auth_client_stateless_sm_process(): Received event %d while in invalid state %d!\n", event,x->state); } if (s) AAASessionsUnlock(s->hash); }
/** * stateful client state machine * \Note - should be called with a lock on the session and will unlock it - do not use it after! * @param auth - AAAAuthSession which uses this state machine * @param ev - Event * @param msg - AAAMessage * @returns 0 if msg should be given to the upper layer 1 if not */ inline int auth_client_statefull_sm_process(cdp_session_t* s, int event, AAAMessage* msg) { cdp_auth_session_t *x; int rc; int rv = 0; //return value if (!s) { switch (event) { case AUTH_EV_RECV_ASR: Send_ASA(0, msg); break; default: LM_ERR("auth_client_statefull_sm_process(): Received invalid event %d with no session!\n", event); } return rv; } x = &(s->u.auth); if (s->cb) (s->cb)(event, s); LM_INFO("after callback of event %i\n", event); //if (x && x->state && msg) LM_ERR("auth_client_statefull_sm_process [event %i] [state %i] endtoend %u hopbyhop %u\n",event,x->state,msg->endtoendId,msg->hopbyhopId); switch (x->state) { case AUTH_ST_IDLE: switch (event) { case AUTH_EV_SEND_REQ: s->application_id = msg->applicationId; s->u.auth.state = AUTH_ST_PENDING; update_auth_session_timers(x, msg); add_auth_session_timers(x, msg); //Richard add this add: add destination realm to cdp session //use msg origin realm as the destination realm //we do this here as this is were the state changes to open //Where must we free this? s->dest_realm.s = (char*) shm_malloc(msg->dest_realm->data.len); memcpy(s->dest_realm.s, msg->dest_realm->data.s, msg->dest_realm->data.len); s->dest_realm.len = msg->dest_realm->data.len; //LM_INFO("state machine: i was in idle and i am going to pending\n"); break; default: LM_ERR("auth_client_statefull_sm_process(): Received invalid event %d while in state %s!(data %p)\n", event, auth_states[x->state], x->generic_data); } break; case AUTH_ST_PENDING: if (event == AUTH_EV_RECV_ANS && msg && !is_req(msg)) { rc = get_result_code(msg); if (rc >= 2000 && rc < 3000 && get_auth_session_state(msg) == STATE_MAINTAINED) event = AUTH_EV_RECV_ANS_SUCCESS; else event = AUTH_EV_RECV_ANS_UNSUCCESS; } switch (event) { case AUTH_EV_RECV_ANS_SUCCESS: x->state = AUTH_ST_OPEN; update_auth_session_timers(x, msg); //LM_INFO("state machine: i was in pending and i am going to open\n"); break; case AUTH_EV_RECV_ANS_UNSUCCESS: LM_DBG("In state AUTH_ST_PENDING and received AUTH_EV_RECV_ANS_UNSUCCESS - nothing to do but clean up session\n"); case AUTH_EV_SESSION_TIMEOUT: case AUTH_EV_SERVICE_TERMINATED: case AUTH_EV_SESSION_GRACE_TIMEOUT: cdp_session_cleanup(s, NULL); s = 0; break; default: LM_ERR("auth_client_stateless_sm_process(): Received invalid event %d while in state %s!\n", event, auth_states[x->state]); } break; case AUTH_ST_OPEN: if (event == AUTH_EV_RECV_ANS && msg && !is_req(msg)) { rc = get_result_code(msg); if (rc >= 2000 && rc < 3000 && get_auth_session_state(msg) == STATE_MAINTAINED) event = AUTH_EV_RECV_ANS_SUCCESS; else event = AUTH_EV_RECV_ANS_UNSUCCESS; } switch (event) { case AUTH_EV_SEND_REQ: // if the request is STR i should move to Discon .. // this is not in the state machine but I (Alberto Diez) need it if (msg->commandCode == IMS_STR) s->u.auth.state = AUTH_ST_DISCON; else { s->u.auth.state = AUTH_ST_OPEN; add_auth_session_timers(x, msg); } break; case AUTH_EV_RECV_ANS_SUCCESS: x->state = AUTH_ST_OPEN; update_auth_session_timers(x, msg); //LM_INFO("state machine: i was in open and i am going to open\n"); break; case AUTH_EV_RECV_ANS_UNSUCCESS: x->state = AUTH_ST_DISCON; //LM_INFO("state machine: i was in open and i am going to discon\n"); break; case AUTH_EV_SESSION_TIMEOUT: case AUTH_EV_SERVICE_TERMINATED: case AUTH_EV_SESSION_GRACE_TIMEOUT: x->state = AUTH_ST_DISCON; //LM_INFO("state machine: i was in open and i am going to discon\n"); Send_STR(s, msg); break; case AUTH_EV_SEND_ASA_SUCCESS: x->state = AUTH_ST_DISCON; //LM_INFO("state machine: i was in open and i am going to discon\n"); Send_STR(s, msg); break; case AUTH_EV_SEND_ASA_UNSUCCESS: x->state = AUTH_ST_OPEN; update_auth_session_timers(x, msg); //LM_INFO("state machine: i was in open and i am going to open\n"); break; case AUTH_EV_RECV_ASR: // two cases , client will comply or will not // our client is very nice and always complys.. because // our brain is in the PCRF... if he says to do this , we do it // Alberto Diez , (again this is not Diameter RFC) x->state = AUTH_ST_DISCON; Send_ASA(s, msg); Send_STR(s, msg); break; default: LM_ERR("auth_client_statefull_sm_process(): Received invalid event %d while in state %s!\n", event, auth_states[x->state]); } break; case AUTH_ST_DISCON: switch (event) { case AUTH_EV_RECV_ASR: x->state = AUTH_ST_DISCON; //LM_INFO("state machine: i was in discon and i am going to discon\n"); Send_ASA(s, msg); break; // Just added this because it might happen if the other peer doesnt // send a valid STA, then the session stays open forever... // We dont accept that... we have lifetime+grace_period for that // This is not in the Diameter RFC ... case AUTH_EV_SESSION_TIMEOUT: case AUTH_EV_SESSION_GRACE_TIMEOUT: // thats the addition case AUTH_EV_RECV_STA: x->state = AUTH_ST_IDLE; LM_INFO("state machine: AUTH_EV_RECV_STA about to clean up\n"); if (msg) AAAFreeMessage(&msg); // if might be needed in frequency // If I register a ResponseHandler then i Free the STA there not here.. // but i dont have interest in that now.. cdp_session_cleanup(s, NULL); s = 0; rv = 1; break; default: LM_ERR("auth_client_statefull_sm_process(): Received invalid event %d while in state %s!\n", event, auth_states[x->state]); } break; default: LM_ERR("auth_client_statefull_sm_process(): Received event %d while in invalid state %d!\n", event, x->state); } if (s) { if (s->cb) (s->cb)(AUTH_EV_SESSION_MODIFIED, s); AAASessionsUnlock(s->hash); } return rv; }