/* this is the function called when a we need to request more funds/credit. We need to try and reserve more credit. * If we cant we need to put a new timer to kill the call at the appropriate time */ void ro_session_ontimeout(struct ro_tl *tl) { time_t now, call_time; long used_secs; int adjustment; str default_out_of_credit_hdrs = {"Reason: outofcredit\r\n", 21}; LM_DBG("We have a fired timer [p=%p] and tl=[%i].\n", tl, tl->timeout); /* find the session id for this timer*/ struct ro_session* ro_session = ((struct ro_session*) ((char *) (tl) - (unsigned long) (&((struct ro_session*) 0)->ro_tl))); LM_DBG("offset for ro_tl is [%lu] and ro_session id is [%.*s]\n", (unsigned long) (&((struct ro_session*) 0)->ro_tl), ro_session->ro_session_id.len, ro_session->ro_session_id.s); if (!ro_session) { LM_ERR("Can't find a session. This is bad"); return; } LM_DBG("event-type=%d", ro_session->event_type); // if (!ro_session->active) { // LM_ALERT("Looks like this session was terminated while requesting more units"); // goto exit; // return; // } if(ro_session->is_final_allocation) { now = get_current_time_micro(); used_secs = now - ro_session->last_event_timestamp; if((ro_session->reserved_secs - used_secs) > 0) { update_ro_timer(&ro_session->ro_tl, (ro_session->reserved_secs - used_secs)); return; } else { ro_session->event_type = no_more_credit; } } switch (ro_session->event_type) { case answered: now = get_current_time_micro(); used_secs = rint((now - ro_session->last_event_timestamp) / (float) 1000000); call_time = rint((now - ro_session->start_time) / (float) 1000000); if ((used_secs + ro_session->billed) < (call_time)) { adjustment = call_time - (used_secs + ro_session->billed); LM_DBG("Making adjustment for Ro interim timer by adding %d seconds\n", adjustment); used_secs += adjustment; } counter_add(ims_charging_cnts_h.billed_secs, used_secs); if (ro_session->callid.s != NULL && ro_session->ro_session_id.s != NULL) { LM_DBG("Found a session to re-apply for timing [%.*s] and user is [%.*s]\n", ro_session->ro_session_id.len, ro_session->ro_session_id.s, ro_session->asserted_identity.len, ro_session->asserted_identity.s); LM_DBG("Call session has been active for %i seconds. The last reserved secs was [%i] and the last event was [%i seconds] ago", (unsigned int) call_time, (unsigned int) ro_session->reserved_secs, (unsigned int) used_secs); LM_DBG("Call session [p=%p]: we will now make a request for another [%i] of credit with a usage of [%i] seconds from the last bundle.\n", ro_session, interim_request_credits/* new reservation request amount */, (unsigned int) used_secs/* charged seconds from previous reservation */); // Apply for more credit. // // The function call will return immediately and we will receive the reply asynchronously via a callback ro_session->billed += used_secs; send_ccr_interim(ro_session, (unsigned int) used_secs, interim_request_credits); return; } else { LM_ERR("Hmmm, the session we have either doesn't have all the data or something else has gone wrong.\n"); /* put the timer back so the call will be killed according to previous timeout. */ ro_session->event_type = unknown_error; int ret = insert_ro_timer(&ro_session->ro_tl, (ro_session->reserved_secs - used_secs) / 1000000); if (ret != 0) { LM_CRIT("unable to insert timer for Ro Session [%.*s]\n", ro_session->ro_session_id.len, ro_session->ro_session_id.s); } else { ref_ro_session(ro_session, 1, 0); return; } LM_ERR("Immediately killing call due to unknown error\n"); } break; case delayed_delete: destroy_ro_session(ro_session); return; case pending: /* call is not answered yet. No point asking more credit. Just wait for dialog to progress somehow */ return; default: LM_ERR("Diameter call session - event [%d]\n", ro_session->event_type); if (ro_session->event_type == no_more_credit) LM_INFO("Call/session must be ended - no more funds.\n"); else if (ro_session->event_type == unknown_error) LM_ERR("last event caused an error. We will now tear down this session.\n"); } counter_inc(ims_charging_cnts_h.killed_calls); dlgb.lookup_terminate_dlg(ro_session->dlg_h_entry, ro_session->dlg_h_id, &default_out_of_credit_hdrs); return; }
/* this is the function called when a we need to request more funds/credit. We need to try and reserve more credit. * If we cant we need to put a new timer to kill the call at the appropriate time */ void ro_session_ontimeout(struct ro_tl *tl) { time_t now, used_secs, call_time; LM_DBG("We have a fired timer [p=%p] and tl=[%i].\n", tl, tl->timeout); /* find the session id for this timer*/ struct ro_session_entry *ro_session_entry = NULL; struct ro_session* ro_session; ro_session = ((struct ro_session*) ((char *) (tl) - (unsigned long) (&((struct ro_session*) 0)->ro_tl))); if (!ro_session) { LM_ERR("Can't find a session. This is bad"); return; } // LM_ALERT("LOCKING... "); ro_session_entry = &(ro_session_table->entries[ro_session->h_entry]); ro_session_lock(ro_session_table, ro_session_entry); // LM_ALERT("LOCKED!"); LM_DBG("event-type=%d", ro_session->event_type); // if (!ro_session->active) { // LM_ALERT("Looks like this session was terminated while requesting more units"); // goto exit; // return; // } switch (ro_session->event_type) { case answered: now = time(0); used_secs = now - ro_session->last_event_timestamp; call_time = now - ro_session->start_time; update_stat(billed_secs, used_secs); if (ro_session->callid.s != NULL && ro_session->dlg_h_entry > 0 && ro_session->dlg_h_id > 0 && ro_session->ro_session_id.s != NULL) { LM_DBG("Found a session to re-apply for timing [%.*s] and user is [%.*s]\n", ro_session->ro_session_id.len, ro_session->ro_session_id.s, ro_session->from_uri.len, ro_session->from_uri.s); LM_DBG("Call session has been active for %i seconds. The last reserved secs was [%i] and the last event was [%i seconds] ago", (unsigned int) call_time, (unsigned int) ro_session->reserved_secs, (unsigned int) used_secs); LM_DBG("Call session [p=%p]: we will now make a request for another [%i] of credit with a usage of [%i] seconds from the last bundle.\n", ro_session, interim_request_credits/* new reservation request amount */, (unsigned int) used_secs/* charged seconds from previous reservation */); // Apply for more credit. // // The function call will return immediately and we will receive the reply asynchronously via a callback send_ccr_interim(ro_session, (unsigned int) used_secs, interim_request_credits); return; } else { LM_ERR("Hmmm, the session we have either doesn't have all the data or something else has gone wrong.\n"); /* put the timer back so the call will be killed according to previous timeout. */ ro_session->event_type = unknown_error; int ret = insert_ro_timer(&ro_session->ro_tl, ro_session->reserved_secs - used_secs); if (ret != 0) { LM_CRIT("unable to insert timer for Ro Session [%.*s]\n", ro_session->ro_session_id.len, ro_session->ro_session_id.s); } else { ref_ro_session_unsafe(ro_session, 1); } LM_ERR("Immediately killing call due to unknown error\n"); dlgb.lookup_terminate_dlg(ro_session->dlg_h_entry, ro_session->dlg_h_id, NULL ); } break; default: LM_ERR("Diameter call session - event [%d]\n", ro_session->event_type); if (ro_session->event_type == no_more_credit) LM_INFO("Call/session must be ended - no more funds.\n"); else if (ro_session->event_type == unknown_error) LM_ERR("last event caused an error. We will now tear down this session.\n"); dlgb.lookup_terminate_dlg(ro_session->dlg_h_entry, ro_session->dlg_h_id, NULL ); } update_stat(killed_calls, 1); unref_ro_session_unsafe(ro_session, 1, ro_session_entry); //unref from the initial timer that fired this event. ro_session_unlock(ro_session_table, ro_session_entry); return; }