/** 
 * 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);
}
Example #2
0
/**
 * 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;
}