Пример #1
0
void resume_ro_session_ontimeout(struct interim_ccr *i_req, int timeout_or_error) {
    time_t now = get_current_time_micro();
    long used_secs;
    struct ro_session_entry *ro_session_entry = NULL;
    int call_terminated = 0;

    if (!i_req) {
        LM_ERR("This is so wrong: i_req is NULL\n");
        return;
    }

    ro_session_entry = &(ro_session_table->entries[i_req->ro_session->h_entry]);
    ro_session_lock(ro_session_table, ro_session_entry);
    LM_DBG("credit=%d credit_valid_for=%d", i_req->new_credit, i_req->credit_valid_for);

    used_secs = rint((now - ((timeout_or_error==1 && i_req->ro_session->last_event_timestamp_backup>0)?i_req->ro_session->last_event_timestamp_backup : i_req->ro_session->last_event_timestamp)) / (float) 1000000);

    /* check to make sure diameter server is giving us sane values */
    if (i_req->credit_valid_for !=0 && i_req->new_credit > i_req->credit_valid_for) {
        LM_WARN("That's weird, Diameter server gave us credit with a lower validity period :D. Setting reserved time to validity period instead \n");
        i_req->new_credit = i_req->credit_valid_for;
    }

    if (i_req->new_credit > 0) {
        //now insert the new timer
        i_req->ro_session->last_event_timestamp = get_current_time_micro();
        i_req->ro_session->event_type = answered;
        i_req->ro_session->valid_for = i_req->credit_valid_for;

        int ret = 0;
        if (i_req->is_final_allocation) {
            LM_DBG("This is a final allocation and call will end in %i seconds\n", i_req->new_credit);
            i_req->ro_session->event_type = no_more_credit;
            ret = insert_ro_timer(&i_req->ro_session->ro_tl, i_req->new_credit);
        } else {
            int timer_timeout = i_req->new_credit;

            if (i_req->new_credit > ro_timer_buffer /*TIMEOUTBUFFER*/) {

                // We haven't finished using our 1st block of units, and we need to set the timer to
                // (new_credit - ro_timer_buffer[5 secs]) to ensure we get new credit before our previous
                // reservation is exhausted. This will only be done the first time, because the timer
                // will always be fired 5 seconds before we run out of time thanks to this operation
                timer_timeout = i_req->new_credit - ro_timer_buffer;
            }

            ret = insert_ro_timer(&i_req->ro_session->ro_tl, timer_timeout);

        }

        // update to the new block of units we got
        i_req->ro_session->reserved_secs = i_req->new_credit;

        if (ret != 0) {
            LM_CRIT("unable to insert timer for Ro Session [%.*s]\n",
                    i_req->ro_session->ro_session_id.len, i_req->ro_session->ro_session_id.s);
        } else {
            ref_ro_session(i_req->ro_session, 1, 0);
        }

        if (ro_db_mode == DB_MODE_REALTIME) {
            i_req->ro_session->flags |= RO_SESSION_FLAG_CHANGED;
            if (update_ro_dbinfo_unsafe(i_req->ro_session) != 0) {
                LM_ERR("Failed to update Ro session in DB... continuing\n");
            }
        }
    } else {
        /* just put the timer back in with however many seconds are left (if any!!! in which case we need to kill */
        /* also update the event type to no_more_credit to save on processing the next time we get here */
        i_req->ro_session->event_type = no_more_credit;
        if (!timeout_or_error)
		i_req->ro_session->last_event_timestamp = get_current_time_micro();
        
        int whatsleft = i_req->ro_session->reserved_secs - used_secs;
        if (whatsleft <= 0) {
            // TODO we need to handle this situation more precisely.
            // in case CCR times out, we get a call shutdown but the error message assumes it was due to a lack of credit.
            //
            LM_WARN("Immediately killing call due to no more credit *OR* no CCA received (timeout) after reservation request\n");

            //
            // we need to unlock the session or else we might get a deadlock on dlg_terminated() dialog callback.
            // Do not unref the session because it will be made inside the dlg_terminated() function.
            //

            //unref_ro_session_unsafe(i_req->ro_session, 1, ro_session_entry);
            ro_session_unlock(ro_session_table, ro_session_entry);

            dlgb.lookup_terminate_dlg(i_req->ro_session->dlg_h_entry, i_req->ro_session->dlg_h_id, NULL);
            call_terminated = 1;
        } else {
            LM_DBG("No more credit for user - letting call run out of money in [%i] seconds", whatsleft);
            int ret = insert_ro_timer(&i_req->ro_session->ro_tl, whatsleft);
            if (ret != 0) {
                LM_CRIT("unable to insert timer for Ro Session [%.*s]\n",
                        i_req->ro_session->ro_session_id.len, i_req->ro_session->ro_session_id.s);
            } else {
                ref_ro_session(i_req->ro_session, 1, 0);
            }
        }
    }

    //
    // if call was forcefully terminated, the lock was released before dlgb.lookup_terminate_dlg() function call.
    //
    if (!call_terminated) {
        unref_ro_session(i_req->ro_session, 1, 0); //unref from the initial timer that fired this event.
        ro_session_unlock(ro_session_table, ro_session_entry);
    }

    shm_free(i_req);
    LM_DBG("Exiting async ccr interim nicely");
}
Пример #2
0
void dlg_terminated(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params) {
	//int i;
	int unref = 0;
	struct ro_session *ro_session = 0;
	struct ro_session_entry *ro_session_entry;
	struct sip_msg *request;
	
	LM_DBG("dialog [%p] terminated, lets send stop record\n", dlg);

	if (!_params) {
		return;
	}
	
	ro_session = (struct ro_session*)*_params->param;
	if (!ro_session) {
		LM_ERR("Ro Session object is NULL...... aborting\n");
		return;
	}
	
	request = _params->req;
	if (!request) {
		LM_WARN("dlg_terminated has no SIP request associated.\n");
	}

	if (dlg && (dlg->callid.s && dlg->callid.len > 0)) {
		
	    
	    /* find the session for this call, possibly both for orig and term*/
		//for (i=0; i<2; i++) {
			//TODO: try and get the Ro session specifically for terminating dialog or originating one
			//currently the way we are doing is a hack.....
			//if ((ro_session = lookup_ro_session(dlg->h_entry, &dlg->callid, 0, 0))) {
				ro_session_entry =
						&(ro_session_table->entries[ro_session->h_entry]);

				//if the Ro session is not active we don't need to do anything. This prevents
				//double processing for various dialog_terminated callback events.
				//If however, the call was never answered, then we can continue as normal
				if (!ro_session->active && (ro_session->start_time != 0)) {
					unref_ro_session(ro_session,1);
					LM_ERR("Ro Session is not active, but may have been answered [%d]\n", (int)ro_session->start_time);
					return;
				}
			
	
				ro_session_lock(ro_session_table, ro_session_entry);

				if (ro_session->active) { // if the call was never activated, there's no timer to remove
					int ret = remove_ro_timer(&ro_session->ro_tl);
					if (ret < 0) {
						LM_CRIT("unable to unlink the timer on ro_session %p [%.*s]\n", 
							ro_session, ro_session->cdp_session_id.len, ro_session->cdp_session_id.s);
					} else if (ret > 0) {
						LM_WARN("inconsistent ro timer data on ro_session %p [%.*s]\n",
							ro_session, ro_session->cdp_session_id.len, ro_session->cdp_session_id.s);						
					} else {
						unref++;
					}
				}

				LM_DBG("Sending CCR STOP on Ro_Session [%p]\n", ro_session);
				send_ccr_stop(ro_session);
				ro_session->active = 0;
				//ro_session->start_time;
				unref_ro_session_unsafe(ro_session, 1+unref, ro_session_entry); //lock already acquired
				//unref_ro_session_unsafe(ro_session, 2+unref, ro_session_entry); //lock already acquired
				ro_session_unlock(ro_session_table, ro_session_entry);
			//}
		//}
	}
}
Пример #3
0
void dlg_reply(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params) {
	struct sip_msg *reply;
	struct ro_session* session = 0;
	struct ro_session_entry* ro_session_entry;
	time_t now = time(0);
	time_t time_since_last_event;

	LM_DBG("dlg_reply callback entered\n");
	
	if (!_params) {
		return;
	}
	
	reply = _params->rpl;
	if (!reply) {
		LM_WARN("dlg_reply has no SIP reply associated.\n");
	}
	
//	if (reply != FAKED_REPLY && reply->REPLY_STATUS == 200) {
//		//get CC session from callback param
//		char* cdp_session_id = (char*)*_params->param;
//		LM_INFO("Call answered\n");
//		LM_DBG("Call answered and we have a session id of [%s]\n", cdp_session_id);
//
//		str session_id;
//		session_id.s = cdp_session_id;
//		session_id.len = strlen(cdp_session_id);
//		AAASession* cdp_session = cdpb.AAAGetCCAccSession(session_id);
//		if (!cdp_session) {
//			LM_ERR("could not find find CC App CDP session\n");
//			return;
//		}
//
//		cdpb.AAAStartChargingCCAccSession(cdp_session);
//		cdpb.AAASessionsUnlock(cdp_session->hash);
//	}

	if (reply != FAKED_REPLY && reply->REPLY_STATUS == 200) {
		LM_DBG("Call answered on dlg [%p] - search for Ro Session and initialise timers.\n", dlg);
		
		session = (struct ro_session*)*_params->param;
		if (!session) {
			LM_ERR("Ro Session object is NULL...... aborting\n");
			return;
		}

		ro_session_entry = &(ro_session_table->entries[session->h_entry]);

		ro_session_lock(ro_session_table, ro_session_entry);

		if (session->active) {
			LM_CRIT("Why the heck am i receiving a double confirmation of the dialog? Ignoring... ");
			ro_session_unlock(ro_session_table, ro_session_entry);
			return;
		}
	
		time_since_last_event = now - session->last_event_timestamp;
		session->start_time = session->last_event_timestamp = now;
		session->event_type = answered;
		session->active = 1;
		

		/* check to make sure that the validity of the credit is enough for the bundle */
		int ret = 0;
		if (session->reserved_secs < (session->valid_for - time_since_last_event)) {
			if (session->reserved_secs > ro_timer_buffer/*TIMEOUTBUFFER*/) {
				ret = insert_ro_timer(&session->ro_tl, session->reserved_secs - ro_timer_buffer); //subtract 5 seconds so as to get more credit before we run out
			} else {
				ret = insert_ro_timer(&session->ro_tl, session->reserved_secs);
			}
		} else {
			if (session->valid_for > ro_timer_buffer) {
				ret = insert_ro_timer(&session->ro_tl, session->valid_for - ro_timer_buffer); //subtract 5 seconds so as to get more credit before we run out
			} else {
				ret = insert_ro_timer(&session->ro_tl, session->valid_for);
			}
		}


		if (ret != 0) {
			LM_CRIT("unable to insert timer for Ro Session [%.*s]\n", session->ro_session_id.len, session->ro_session_id.s); 
		} else {
			ref_ro_session_unsafe(session, 1); // lock already acquired
		}
				
		ro_session_unlock(ro_session_table, ro_session_entry);

		AAASession* cdp_session = cdpb.AAAGetCCAccSession(session->ro_session_id);
		if (!cdp_session) {
			LM_ERR("could not find find CC App CDP session for session [%.*s]\n", session->ro_session_id.len, session->ro_session_id.s);
//			ro_session_unlock(ro_session_table, ro_session_entry);
			return;
		}
		
//		ro_session_unlock(ro_session_table, ro_session_entry);

		cdpb.AAAStartChargingCCAccSession(cdp_session);
		cdpb.AAASessionsUnlock(cdp_session->hash);		
		
//		unref_ro_session(session, 1);	DONT need this anymore because we don't do lookup so no addition to ref counter
	}
}
Пример #4
0
void dlg_answered(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params) {
    struct sip_msg *reply;
    struct ro_session* session = 0;
    struct ro_session_entry* ro_session_entry;
    time_t now = get_current_time_micro();
    time_t time_since_last_event;

    LM_DBG("dlg_reply callback entered\n");

    if (!_params) {
        return;
    }

    session = (struct ro_session*) *_params->param;
    if (!session) {
        LM_ERR("Ro Session object is NULL...... aborting\n");
        return;
    }
    
    LM_DBG("Call answered on dlg [%p] - search for Ro Session [%p]\n", dlg, session);

    ro_session_entry = &(ro_session_table->entries[session->h_entry]);

    ro_session_lock(ro_session_table, ro_session_entry);

    if (session->active) {
        LM_CRIT("Why the heck am i receiving a double confirmation of the dialog? Ignoring... ");
        ro_session_unlock(ro_session_table, ro_session_entry);
        return;
    } else if (session->active < 0) {   //session has already been terminated - we can't reactivate...
        LM_WARN("Received an answer after terminating dialog.... ignoring\n");
        ro_session_unlock(ro_session_table, ro_session_entry);
        return;
    }

    time_since_last_event = (now - session->last_event_timestamp)/1000000;
    session->start_time = session->last_event_timestamp = now;
    session->event_type = answered;
    session->active = 1;


    /* check to make sure that the validity of the credit is enough for the bundle */
    int ret = 0;
    LM_DBG("we were granted %d seconds (valud for %d seconds) and it's been %d seconds since we requested\n", (int)session->reserved_secs, (int)session->valid_for, (int)time_since_last_event);
    if (session->reserved_secs < (session->valid_for - time_since_last_event)) {
        if (session->reserved_secs > ro_timer_buffer/*TIMEOUTBUFFER*/) {
            ret = insert_ro_timer(&session->ro_tl, session->reserved_secs - ro_timer_buffer); //subtract 5 seconds so as to get more credit before we run out
        } else {
            ret = insert_ro_timer(&session->ro_tl, session->reserved_secs);
        }
    } else {
        if (session->valid_for > ro_timer_buffer) {
            ret = insert_ro_timer(&session->ro_tl, session->valid_for - ro_timer_buffer); //subtract 5 seconds so as to get more credit before we run out
        } else {
            ret = insert_ro_timer(&session->ro_tl, session->valid_for);
        }
    }


    if (ret != 0) {
        LM_CRIT("unable to insert timer for Ro Session [%.*s]\n", session->ro_session_id.len, session->ro_session_id.s);
    } else {
        ref_ro_session_unsafe(session, 1); // lock already acquired
    }

    if (ro_db_mode == DB_MODE_REALTIME) {
        session->flags |= RO_SESSION_FLAG_CHANGED;
        if (update_ro_dbinfo_unsafe(session) != 0) {
            LM_ERR("Failed to update ro_session in database... continuing\n");
        };
    }

    ro_session_unlock(ro_session_table, ro_session_entry);

    AAASession* cdp_session = cdpb.AAAGetCCAccSession(session->ro_session_id);
    if (!cdp_session) {
        LM_ERR("could not find find CC App CDP session for session [%.*s]\n", session->ro_session_id.len, session->ro_session_id.s);
        return;
    }

    cdpb.AAAStartChargingCCAccSession(cdp_session);
    cdpb.AAASessionsUnlock(cdp_session->hash);


}
Пример #5
0
/* must be called with lock on ro_session */
void send_ccr_interim(struct ro_session* ro_session, unsigned int used, unsigned int reserve) {
    AAASession * auth = 0;

    AAAMessage * ccr = 0;
    Ro_CCR_t *ro_ccr_data = 0;
    ims_information_t *ims_info = 0;
    int32_t acc_record_type;
    subscription_id_t subscr;
    time_stamps_t *time_stamps;
    struct interim_ccr *i_req = shm_malloc(sizeof (struct interim_ccr));
    int ret = 0;
    event_type_t *event_type;

    memset(i_req, 0, sizeof (sizeof (struct interim_ccr)));
    i_req->ro_session = ro_session;

    str sip_method = str_init("dummy");
    str sip_event = str_init("dummy");

    str user_name = {0, 0};

    time_t req_timestamp;

    event_type = new_event_type(&sip_method, &sip_event, 0);

    LM_DBG("Sending interim CCR request for (usage:new) [%i:%i] seconds for user [%.*s] using session id [%.*s] active rating group [%d] active service identifier [%d] incoming_trunk_id [%.*s] outgoing_trunk_id [%.*s]\n",
            used,
            reserve,
            ro_session->asserted_identity.len, ro_session->asserted_identity.s,
            ro_session->ro_session_id.len, ro_session->ro_session_id.s,
            ro_session->rating_group, ro_session->service_identifier,
            ro_session->incoming_trunk_id.len, ro_session->incoming_trunk_id.s,
            ro_session->outgoing_trunk_id.len, ro_session->outgoing_trunk_id.s);

    req_timestamp = time(0);

    if (!(time_stamps = new_time_stamps(&req_timestamp, NULL, NULL, NULL)))
        goto error;

    if (!(ims_info = new_ims_information(event_type, time_stamps, &ro_session->callid, &ro_session->callid, &ro_session->asserted_identity,
            &ro_session->called_asserted_identity, 0, 0, 0, ro_session->direction, &ro_session->incoming_trunk_id, &ro_session->outgoing_trunk_id, &ro_session->pani)))
        goto error;

    LM_DBG("Created IMS information\n");

    event_type = 0;

    if (ro_session->direction == RO_ORIG_DIRECTION) {
        subscr.id = ro_session->asserted_identity;


    } else if (ro_session->direction == RO_TERM_DIRECTION) {
        subscr.id = ro_session->called_asserted_identity;
    } else {
        LM_CRIT("don't know what to do in unknown mode - should we even get here\n");
        goto error;
    }

    //getting subscription id type
    if (strncasecmp(subscr.id.s, "tel:", 4) == 0) {
        subscr.type = Subscription_Type_MSISDN;
        // Strip "tel:":
        subscr.id.s += 4;
        subscr.id.len -= 4;
    } else {
        subscr.type = Subscription_Type_IMPU; //default is END_USER_SIP_URI
    }

    user_name.s = subscr.id.s;
    user_name.len = subscr.id.len;

    acc_record_type = AAA_ACCT_INTERIM;

    ro_ccr_data = new_Ro_CCR(acc_record_type, &user_name, ims_info, &subscr);
    if (!ro_ccr_data) {
        LM_ERR("no memory left for generic\n");
        goto error;
    }
    ims_info = NULL;

    auth = cdpb.AAAGetCCAccSession(ro_session->ro_session_id);
    if (!auth) {
        LM_DBG("Diameter Auth Session has timed out.... creating a new one.\n");
        /* lets try and recreate this session */
        //TODO: make a CC App session auth = cdpb.AAASession(ro_session->auth_appid, ro_session->auth_session_type, ro_session->ro_session_id); //TODO: would like this session to last longer (see session timeout in cdp
        //BUG("Oh shit, session timed out and I don't know how to create a new one.");

        auth = cdpb.AAAMakeSession(ro_session->auth_appid, ro_session->auth_session_type, ro_session->ro_session_id); //TODO: would like this session to last longer (see session timeout in cdp
        if (!auth)
            goto error;
    }

    //don't send INTERIM record if session is not in OPEN state (it could already be waiting for a previous response, etc)
    if (auth->u.cc_acc.state != ACC_CC_ST_OPEN) {
        LM_WARN("ignoring interim update on CC session not in correct state, currently in state [%d]\n", auth->u.cc_acc.state);
        goto error;
    }

    if (!(ccr = Ro_new_ccr(auth, ro_ccr_data)))
        goto error;

    if (!Ro_add_vendor_specific_appid(ccr, IMS_vendor_id_3GPP, IMS_Ro, 0/*acct id*/)) {
        LM_ERR("Problem adding Vendor specific ID\n");
    }
    ro_session->hop_by_hop += 1;
    if (!Ro_add_cc_request(ccr, RO_CC_INTERIM, ro_session->hop_by_hop)) {
        LM_ERR("Problem adding CC-Request data\n");
    }
    if (!Ro_add_event_timestamp(ccr, time(NULL))) {
        LM_ERR("Problem adding Event-Timestamp data\n");
    }

    if (!Ro_add_user_equipment_info(ccr, AVP_EPC_User_Equipment_Info_Type_MAC, ro_session->mac)) {
        LM_ERR("Problem adding User-Equipment data\n");
    }

    if (!Ro_add_subscription_id(ccr, subscr.type, &(subscr.id))) {
        LM_ERR("Problem adding Subscription ID data\n");
    }

    if (!Ro_add_multiple_service_credit_Control(ccr, interim_request_credits/*INTERIM_CREDIT_REQ_AMOUNT*/, used, ro_session->rating_group, ro_session->service_identifier)) {
        LM_ERR("Problem adding Multiple Service Credit Control data\n");
    }

    LM_DBG("Sending CCR Diameter message.\n");

    cdpb.AAASessionsUnlock(auth->hash);

    if (ro_forced_peer.len > 0) {
        ret = cdpb.AAASendMessageToPeer(ccr, &ro_forced_peer, resume_on_interim_ccr, (void *) i_req);
    } else {
        ret = cdpb.AAASendMessage(ccr, resume_on_interim_ccr, (void *) i_req);
    }

    if (ret != 1) {
        goto error;
    }
    //    cdpb.AAASessionsUnlock(auth->hash);

    Ro_free_CCR(ro_ccr_data);

    counter_inc(ims_charging_cnts_h.interim_ccrs);
    return;
error:
    LM_ERR("error trying to reserve interim credit\n");

    if (ro_ccr_data)
        Ro_free_CCR(ro_ccr_data);

    if (ccr)
        cdpb.AAAFreeMessage(&ccr);

    if (auth) {
        cdpb.AAASessionsUnlock(auth->hash);
        cdpb.AAADropCCAccSession(auth);
    }

    shm_free(i_req);
    //
    // since callback function will be never called because of the error, we need to release the lock on the session
    // to it can be reused later.
    //
    struct ro_session_entry *ro_session_entry = &(ro_session_table->entries[ro_session->h_entry]);
    ro_session_lock(ro_session_table, ro_session_entry);
    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;
}
Пример #6
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;
}
Пример #7
0
void resume_ro_session_ontimeout(struct interim_ccr *i_req) {
	time_t now = time(0);
	time_t used_secs;
	struct ro_session_entry *ro_session_entry = NULL;

	if (!i_req) {
		LM_ERR("This is so wrong: i_req is NULL\n");
		return;
	}

	LM_DBG("credit=%d credit_valid_for=%d", i_req->new_credit, i_req->credit_valid_for);

	used_secs = now - i_req->ro_session->last_event_timestamp;

	/* check to make sure diameter server is giving us sane values */
	if (i_req->new_credit > i_req->credit_valid_for) {
		LM_WARN("That's weird, Diameter server gave us credit with a lower validity period :D. Setting reserved time to validity perioud instead \n");
		i_req->new_credit = i_req->credit_valid_for;
	}

	if (i_req->new_credit > 0) {
		//now insert the new timer
		i_req->ro_session->last_event_timestamp = time(0);
		i_req->ro_session->event_type = answered;
		i_req->ro_session->valid_for = i_req->credit_valid_for;

		int ret = 0;
		if (i_req->is_final_allocation) {
			LM_DBG("This is a final allocation and call will end in %i seconds\n", i_req->new_credit);
			i_req->ro_session->event_type = no_more_credit;
			ret = insert_ro_timer(&i_req->ro_session->ro_tl, i_req->new_credit);
		}
		else {
			int timer_timeout = i_req->new_credit;

			if (i_req->new_credit > ro_timer_buffer /*TIMEOUTBUFFER*/) {

				// We haven't finished using our 1st block of units, and we need to set the timer to
				// (new_credit - ro_timer_buffer[5 secs]) to ensure we get new credit before our previous
				// reservation is exhausted. This will only be done the first time, because the timer
				// will always be fired 5 seconds before we run out of time thanks to this operation

				if ((now - i_req->ro_session->start_time) /* call time */ < i_req->ro_session->reserved_secs)
					timer_timeout = i_req->new_credit - ro_timer_buffer;
				else
					timer_timeout = i_req->new_credit;
			}

			ret = insert_ro_timer(&i_req->ro_session->ro_tl, timer_timeout);

		}

		// update to the new block of units we got
		i_req->ro_session->reserved_secs = i_req->new_credit;

		if (ret != 0) {
			LM_CRIT("unable to insert timer for Ro Session [%.*s]\n",
					i_req->ro_session->ro_session_id.len, i_req->ro_session->ro_session_id.s);
		}
		else {
			ref_ro_session_unsafe(i_req->ro_session, 1);
		}
	}
	else {
		/* just put the timer back in with however many seconds are left (if any!!! in which case we need to kill */
		/* also update the event type to no_more_credit to save on processing the next time we get here */
		i_req->ro_session->event_type = no_more_credit;
		int whatsleft = i_req->ro_session->reserved_secs - used_secs;
		if (whatsleft <= 0) {
			LM_WARN("Immediately killing call due to no more credit\n");
			dlgb.lookup_terminate_dlg(i_req->ro_session->dlg_h_entry, i_req->ro_session->dlg_h_id, NULL );
		}
		else {
			LM_DBG("No more credit for user - letting call run out of money in [%i] seconds", whatsleft);
			int ret = insert_ro_timer(&i_req->ro_session->ro_tl, whatsleft);
			if (ret != 0) {
				LM_CRIT("unable to insert timer for Ro Session [%.*s]\n",
						i_req->ro_session->ro_session_id.len, i_req->ro_session->ro_session_id.s);
			}
			else {
				ref_ro_session_unsafe(i_req->ro_session, 1);
			}
		}
	}

	ro_session_entry = &(ro_session_table->entries[i_req->ro_session->h_entry]);

	unref_ro_session_unsafe(i_req->ro_session, 1, ro_session_entry);//unref from the initial timer that fired this event.
	ro_session_unlock(ro_session_table, ro_session_entry);

	shm_free(i_req);
	LM_DBG("Exiting async ccr interim nicely");
}
Пример #8
0
void dlg_terminated(struct dlg_cell *dlg, int type, unsigned int termcode, char* reason, struct dlg_cb_params *_params) {
	//int i;
	int unref = 0;
	struct ro_session *ro_session = 0;
	struct ro_session_entry *ro_session_entry;
	struct sip_msg *request;
        str s_reason;
        
        s_reason.s = reason;
        s_reason.len = strlen(reason);
	
	LM_DBG("dialog [%p] terminated on type [%d], lets send stop record\n", dlg, type);

	if (!_params) {
		return;
	}
	
	LM_DBG("Direction is %d\n", _params->direction);
	if (_params->req) {
		if (_params->req->first_line.u.request.method_value == METHOD_BYE) {
			if (_params->direction == DLG_DIR_DOWNSTREAM) {
				LM_DBG("Dialog ended by Caller\n");
			} else {
				LM_DBG("Dialog ended by Callee\n");
			}
		} else {
			LM_DBG("Request is %.*s\n", _params->req->first_line.u.request.method.len, _params->req->first_line.u.request.method.s);
		}

		struct hdr_field* h = get_hdr_by_name(_params->req, "Reason", 6);
		if(h!=NULL){
                        LM_DBG("reason header is [%.*s]\n", h->body.len, h->body.s);
			s_reason = h->body;
		}
	} else if (_params->rpl) {
		LM_DBG("Reply is [%d - %.*s]", _params->rpl->first_line.u.reply.statuscode, _params->rpl->first_line.u.reply.reason.len, _params->rpl->first_line.u.reply.reason.s);
	}
	
	ro_session = (struct ro_session*)*_params->param;
	if (!ro_session) {
		LM_ERR("Ro Session object is NULL...... aborting\n");
		return;
	}
	
	request = _params->req;
	if (!request) {
		LM_WARN("dlg_terminated has no SIP request associated.\n");
	}

	if (dlg && (dlg->callid.s && dlg->callid.len > 0)) {
		
	    
	    /* find the session for this call, possibly both for orig and term*/
		//for (i=0; i<2; i++) {
			//TODO: try and get the Ro session specifically for terminating dialog or originating one
			//currently the way we are doing is a hack.....
			//if ((ro_session = lookup_ro_session(dlg->h_entry, &dlg->callid, 0, 0))) {
				ro_session_entry =
						&(ro_session_table->entries[ro_session->h_entry]);

				//if the Ro session is not active we don't need to do anything. This prevents
				//double processing for various dialog_terminated callback events.
				//If however, the call was never answered, then we can continue as normal
				ro_session_lock(ro_session_table, ro_session_entry);
                                
                                LM_DBG("processing dlg_terminated in Ro and session [%.*s] has active = %d", ro_session->ro_session_id.len, ro_session->ro_session_id.s, ro_session->active);
				if ((!ro_session->active && (ro_session->start_time != 0)) || (ro_session->ccr_sent == 1)) {
					unref_ro_session_unsafe(ro_session,1,ro_session_entry);
					LM_DBG("CCR already sent or Ro Session is not active, but may have been answered [%d]\n", (int)ro_session->start_time);
					ro_session_unlock(ro_session_table, ro_session_entry);
					return;
				}

				if (ro_session->active) { // if the call was never activated, there's no timer to remove
					int ret = remove_ro_timer(&ro_session->ro_tl);
					if (ret < 0) {
						LM_CRIT("unable to unlink the timer on ro_session %p [%.*s]\n", 
							ro_session, ro_session->ro_session_id.len, ro_session->ro_session_id.s);
					} else if (ret > 0) {
						LM_WARN("inconsistent ro timer data on ro_session %p [%.*s]\n",
							ro_session, ro_session->ro_session_id.len, ro_session->ro_session_id.s);						
					} else {
						unref++;
					}
				}

				LM_DBG("Sending CCR STOP on Ro_Session [%p]\n", ro_session);
				send_ccr_stop_with_param(ro_session, termcode, &s_reason);
				ro_session->active = -1;    //deleted.... terminated ....
                                ro_session->ccr_sent = 1;
//                                counter_add(ims_charging_cnts_h.active_ro_sessions, -1);
				
				if (ro_db_mode == DB_MODE_REALTIME) {
				    ro_session->flags |= RO_SESSION_FLAG_DELETED;
				    if (update_ro_dbinfo_unsafe(ro_session) != 0) {
					LM_ERR("Unable to update Ro session in DB...continuing\n");
				    }
				}
				
				//ro_session->start_time;
				unref_ro_session_unsafe(ro_session, 1+unref, ro_session_entry); //lock already acquired
				//unref_ro_session_unsafe(ro_session, 2+unref, ro_session_entry); //lock already acquired
				ro_session_unlock(ro_session_table, ro_session_entry);
			//}
		//}
	}
}