示例#1
0
/* 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;
}
示例#2
0
/* 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;
}