/** * Destroys the session related structures. */ int cdp_sessions_destroy() { int i; cdp_session_t *n,*x; if (session_lock){ lock_get(session_lock); lock_destroy(session_lock); lock_dealloc((void*)session_lock); session_lock=0; } for(i=0;i<sessions_hash_size;i++){ AAASessionsLock(i); for(x = sessions[i].head; x; x = n){ n = x->next; free_session(x); } lock_destroy(sessions[i].lock); lock_dealloc((void*)sessions[i].lock); } shm_free(sessions); shm_free(session_id1); shm_free(session_id2); return 1; }
/** * Adds the session to the session list. * \note This returns with a lock, so unlock when done * @param x - the session to add */ void cdp_add_session(cdp_session_t *x) { // unsigned int hash; if (!x) return; // hash = get_str_hash(x->id,sessions_hash_size); // x->hash = hash; LM_DBG("adding a session with id %.*s\n",x->id.len,x->id.s); AAASessionsLock(x->hash); x->next = 0; x->prev = sessions[x->hash].tail; if (sessions[x->hash].tail) sessions[x->hash].tail->next = x; sessions[x->hash].tail = x; if (!sessions[x->hash].head) sessions[x->hash].head = x; }
/** * Finds a session in the session hash table. * \note Returns with a lock on the sessions[x->hash].lock!!! * @param id - the id of the session * @returns the session if found or 0 if not */ cdp_session_t* cdp_get_session(str id) { unsigned int hash; cdp_session_t *x; if (!id.len) return 0; hash = get_str_hash(id,sessions_hash_size); LM_DBG("called get session with id %.*s and hash %u\n",id.len,id.s,hash); AAASessionsLock(hash); for(x = sessions[hash].head;x;x=x->next){ LM_DBG("looking for |%.*s| in |%.*s|\n",id.len,id.s,x->id.len,x->id.s); if (x->id.len == id.len && strncasecmp(x->id.s,id.s,id.len)==0) return x; } AAASessionsUnlock(hash); LM_DBG("no session found\n"); return 0; }
void cdp_sessions_log() { int hash; cdp_session_t *x; LM_DBG(ANSI_MAGENTA"------- CDP Sessions ----------------\n"ANSI_GREEN); for(hash=0;hash<sessions_hash_size;hash++){ AAASessionsLock(hash); for(x = sessions[hash].head;x;x=x->next) { LM_DBG(ANSI_GRAY" %3u. [%.*s] AppId [%d] Type [%d]\n", hash, x->id.len,x->id.s, x->application_id, x->type); switch (x->type){ case AUTH_CLIENT_STATEFULL: case AUTH_SERVER_STATEFULL: LM_DBG(ANSI_GRAY"\tAuth State [%d] Timeout [%d] Lifetime [%d] Grace [%d] Generic [%p]\n", x->u.auth.state, (int)(x->u.auth.timeout-time(0)), x->u.auth.lifetime?(int)(x->u.auth.lifetime-time(0)):-1, (int)(x->u.auth.grace_period), x->u.auth.generic_data); break; case ACCT_CC_CLIENT: LM_DBG(ANSI_GRAY"\tCCAcct State [%d] Charging Active [%c (%d)s] Reserved Units(valid=%ds) [%d] Generic [%p]\n", x->u.cc_acc.state, (x->u.cc_acc.charging_start_time&&x->u.cc_acc.state!=ACC_CC_ST_DISCON)?'Y':'N', x->u.cc_acc.charging_start_time?(int)((int)time(0) - (int)x->u.cc_acc.charging_start_time):-1, x->u.cc_acc.reserved_units?(int)((int)x->u.cc_acc.last_reservation_request_time + x->u.cc_acc.reserved_units_validity_time) - (int)time(0):-1, x->u.cc_acc.reserved_units, x->u.cc_acc.generic_data); break; default: break; } } AAASessionsUnlock(hash); } LM_DBG(ANSI_MAGENTA"-------------------------------------\n"ANSI_GREEN); }
/** * Get the first peer that is connected from the list of routing entries. * @param r - the list of routing entries to look into * @returns - the peer or null if none connected */ peer* get_first_connected_route(cdp_session_t* cdp_session, routing_entry *r, int app_id, int vendor_id) { peer * peers[LB_MAX_PEERS]; int peer_count = 0; int prev_metric = 0; routing_entry *i; peer *p; int j; time_t least_recent_time; struct timespec time_spec; if (cdp_session) { /*try and find an already used peer for this session - sticky*/ if ((cdp_session->sticky_peer_fqdn.len > 0) && cdp_session->sticky_peer_fqdn.s) { //we have an old sticky peer. let's make sure it's up and connected before we use it. AAASessionsUnlock(cdp_session->hash); /*V1.1 - Don't attempt to hold two locks at same time */ p = get_peer_by_fqdn(&cdp_session->sticky_peer_fqdn); AAASessionsLock(cdp_session->hash); /*V1.1 - As we were...no call seems to pass cdp_session unlocked */ if (p && !p->disabled && (p->state == I_Open || p->state == R_Open) && peer_handles_application(p, app_id, vendor_id)) { p->last_selected = time(NULL); LM_DBG("Found a sticky peer [%.*s] for this session - re-using\n", p->fqdn.len, p->fqdn.s); return p; } } } for (i = r; i; i = i->next) { if (peer_count >= LB_MAX_PEERS) break; p = get_peer_by_fqdn(&(i->fqdn)); if (!p) LM_DBG("The peer %.*s does not seem to be connected or configured\n", i->fqdn.len, i->fqdn.s); else LM_DBG("The peer %.*s state is %s\n", i->fqdn.len, i->fqdn.s, (p->state == I_Open || p->state == R_Open) ? "opened" : "closed"); if (p && !p->disabled && (p->state == I_Open || p->state == R_Open) && peer_handles_application(p, app_id, vendor_id)) { LM_DBG("The peer %.*s matches - will forward there\n", i->fqdn.len, i->fqdn.s); if (peer_count != 0) {//check the metric if (i->metric != prev_metric) break; //metric must be the same peers[peer_count++] = p; } else {//we're first prev_metric = i->metric; peers[peer_count++] = p; } } } if (peer_count == 0) { return 0; } least_recent_time = peers[0]->last_selected; LM_DBG("peer [%.*s] was last used @ %ld\n", peers[0]->fqdn.len, peers[0]->fqdn.s, peers[0]->last_selected); p = peers[0]; for (j = 1; j < peer_count; j++) { LM_DBG("Peer [%.*s] was last used at [%ld]\n", peers[j]->fqdn.len, peers[j]->fqdn.s, peers[j]->last_selected); if (peers[j]->last_selected < least_recent_time) { least_recent_time = peers[j]->last_selected; p = peers[j]; } } ser_clock_gettime(&time_spec); p->last_selected = (time_spec.tv_sec*1000000) + round(time_spec.tv_nsec / 1.0e3); // Convert nanoseconds to microseconds LM_DBG("chosen peer [%.*s]\n", p->fqdn.len, p->fqdn.s); if (cdp_session) { if (cdp_session->sticky_peer_fqdn_buflen <= p->fqdn.len) { LM_DBG("not enough storage for sticky peer - allocating more\n"); if (cdp_session->sticky_peer_fqdn.s) shm_free(cdp_session->sticky_peer_fqdn.s); cdp_session->sticky_peer_fqdn.s = (char*) shm_malloc(p->fqdn.len + 1); if (!cdp_session->sticky_peer_fqdn.s) { LM_ERR("no more shm memory\n"); return 0; } cdp_session->sticky_peer_fqdn_buflen = p->fqdn.len + 1; memset(cdp_session->sticky_peer_fqdn.s, 0, p->fqdn.len + 1); } cdp_session->sticky_peer_fqdn.len = p->fqdn.len; memcpy(cdp_session->sticky_peer_fqdn.s, p->fqdn.s, p->fqdn.len); } return p; }
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; }