static switch_status_t loopback_bowout_on_execute_state_handler(switch_core_session_t *session) { switch_channel_t *channel = switch_core_session_get_channel(session); switch_channel_state_t state = switch_channel_get_state(channel); private_t *tech_pvt = NULL; if (state == CS_EXECUTE) { const char *uuid; switch_core_session_t *other_session = NULL; switch_channel_t *b_channel = NULL; tech_pvt = switch_core_session_get_private(session); if (switch_core_session_read_lock(tech_pvt->other_session) == SWITCH_STATUS_SUCCESS) { b_channel = switch_core_session_get_channel(tech_pvt->other_session); /* Wait for b_channel to be fully bridged */ switch_channel_wait_for_flag(b_channel, CF_BRIDGED, SWITCH_TRUE, 5000, NULL); uuid = switch_channel_get_partner_uuid(b_channel); if (uuid && (other_session = switch_core_session_locate(uuid))) { switch_channel_t *other_channel = switch_core_session_get_channel(other_session); switch_caller_profile_t *cp, *clone; switch_channel_wait_for_state(other_channel, NULL, CS_EXCHANGE_MEDIA); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->other_session), SWITCH_LOG_INFO, "Replacing loopback channel: %s with real channel: %s\n", switch_channel_get_name(b_channel), switch_channel_get_name(other_channel)); if ((cp = switch_channel_get_caller_profile(channel))) { clone = switch_caller_profile_clone(other_session, cp); clone->originator_caller_profile = NULL; clone->originatee_caller_profile = NULL; switch_channel_set_caller_profile(other_channel, clone); } switch_channel_caller_extension_masquerade(channel, other_channel, 0); switch_channel_set_state(other_channel, CS_RESET); switch_channel_wait_for_state(other_channel, NULL, CS_RESET); switch_channel_set_variable(channel, "process_cdr", "false"); switch_channel_set_variable(b_channel, "process_cdr", "false"); switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); switch_channel_set_state(other_channel, CS_EXECUTE); switch_core_session_rwunlock(other_session); } switch_core_session_rwunlock(tech_pvt->other_session); } switch_core_event_hook_remove_state_change(session, loopback_bowout_on_execute_state_handler); } return SWITCH_STATUS_SUCCESS; }
/* This is where we actually charge the guy This can be called anytime a call is in progress or at the end of a call before the session is destroyed */ static switch_status_t do_billing(switch_core_session_t *session) { /* FS vars we will use */ switch_channel_t *channel; switch_caller_profile_t *profile; /* Local vars */ nibble_data_t *nibble_data; switch_time_t ts = switch_micro_time_now(); double billamount; char date[80] = ""; char *uuid; switch_size_t retsize; switch_time_exp_t tm; const char *billrate; const char *billincrement; const char *billaccount; double nobal_amt = globals.nobal_amt; double lowbal_amt = globals.lowbal_amt; double balance; if (!session) { /* Why are we here? */ return SWITCH_STATUS_SUCCESS; } uuid = switch_core_session_get_uuid(session); /* Get channel var */ if (!(channel = switch_core_session_get_channel(session))) { return SWITCH_STATUS_SUCCESS; } /* Variables kept in FS but relevant only to this module */ billrate = switch_channel_get_variable(channel, "nibble_rate"); billincrement = switch_channel_get_variable(channel, "nibble_increment"); billaccount = switch_channel_get_variable(channel, "nibble_account"); if (!zstr(switch_channel_get_variable(channel, "nobal_amt"))) { nobal_amt = atof(switch_channel_get_variable(channel, "nobal_amt")); } if (!zstr(switch_channel_get_variable(channel, "lowbal_amt"))) { lowbal_amt = atof(switch_channel_get_variable(channel, "lowbal_amt")); } /* Return if there's no billing information on this session */ if (!billrate || !billaccount) { return SWITCH_STATUS_SUCCESS; } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Attempting to bill at $%s per minute to account %s\n", billrate, billaccount); /* Get caller profile info from channel */ profile = switch_channel_get_caller_profile(channel); if (!profile || !profile->times) { /* No caller profile (why would this happen?) */ return SWITCH_STATUS_SUCCESS; } if (profile->times->answered < 1) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Not billing %s - call is not in answered state\n", billaccount); /* See if this person has enough money left to continue the call */ balance = get_balance(billaccount, channel); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Comparing %f to hangup balance of %f\n", balance, nobal_amt); if (balance <= nobal_amt) { /* Not enough money - reroute call to nobal location */ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Balance of %f fell below allowed amount of %f! (Account %s)\n", balance, nobal_amt, billaccount); transfer_call(session, globals.nobal_action); } return SWITCH_STATUS_SUCCESS; } /* Lock this session's data for this module while we tinker with it */ if (globals.mutex) { switch_mutex_lock(globals.mutex); } /* Get our nibble data var. This will be NULL if it's our first call here for this session */ nibble_data = (nibble_data_t *) switch_channel_get_private(channel, "_nibble_data_"); /* Are we in paused mode? If so, we don't do anything here - go back! */ if (nibble_data && (nibble_data->pausets > 0)) { if (globals.mutex) { switch_mutex_unlock(globals.mutex); } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Received heartbeat, but we're paused - ignoring\n"); return SWITCH_STATUS_SUCCESS; } /* Have we done any billing on this channel yet? If no, set up vars for doing so */ if (!nibble_data) { nibble_data = switch_core_session_alloc(session, sizeof(*nibble_data)); memset(nibble_data, 0, sizeof(*nibble_data)); /* Setup new billing data (based on call answer time, in case this module started late with active calls) */ nibble_data->lastts = profile->times->answered; /* Set the initial answer time to match when the call was really answered */ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Beginning new billing on %s\n", uuid); } switch_time_exp_lt(&tm, nibble_data->lastts); switch_strftime_nocheck(date, &retsize, sizeof(date), "%Y-%m-%d %T", &tm); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%d seconds passed since last bill time of %s\n", (int) ((ts - nibble_data->lastts) / 1000000), date); if ((ts - nibble_data->lastts) >= 0) { /* If billincrement is set we bill by it and not by time elapsed */ if (!(switch_strlen_zero(billincrement))) { switch_time_t chargedunits = (ts - nibble_data->lastts) / 1000000 <= atol(billincrement) ? atol(billincrement) * 1000000 : (switch_time_t)(ceil((ts - nibble_data->lastts) / (atol(billincrement) * 1000000.0))) * atol(billincrement) * 1000000; billamount = (atof(billrate) / 1000000 / 60) * chargedunits - nibble_data->bill_adjustments; /* Account for the prepaid amount */ nibble_data->lastts += chargedunits; } else { /* Convert billrate into microseconds and multiply by # of microseconds that have passed since last *successful* bill */ billamount = (atof(billrate) / 1000000 / 60) * ((ts - nibble_data->lastts)) - nibble_data->bill_adjustments; /* Update the last time we billed */ nibble_data->lastts = ts; } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Billing $%f to %s (Call: %s / %f so far)\n", billamount, billaccount, uuid, nibble_data->total); /* DO ODBC BILLING HERE and reset counters if it's successful! */ if (bill_event(billamount, billaccount, channel) == SWITCH_STATUS_SUCCESS) { /* Increment total cost */ nibble_data->total += billamount; /* Reset manual billing adjustments from pausing */ nibble_data->bill_adjustments = 0; /* Update channel variable with current billing */ switch_channel_set_variable_printf(channel, "nibble_total_billed", "%f", nibble_data->total); } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Failed to log to database!\n"); } } else { if (switch_strlen_zero(billincrement)) switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Just tried to bill %s negative minutes! That should be impossible.\n", uuid); } /* Save this location */ if (channel) { switch_channel_set_private(channel, "_nibble_data_", nibble_data); /* don't verify balance and transfer to nobal if we're done with call */ if (switch_channel_get_state(channel) != CS_REPORTING && switch_channel_get_state(channel) != CS_HANGUP) { balance = get_balance(billaccount, channel); /* See if we've achieved low balance */ if (!nibble_data->lowbal_action_executed && balance <= lowbal_amt) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Balance of %f fell below low balance amount of %f! (Account %s)\n", balance, lowbal_amt, billaccount); if (exec_app(session, globals.lowbal_action) != SWITCH_STATUS_SUCCESS) switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Low balance action didn't execute\n"); else nibble_data->lowbal_action_executed = 1; } /* See if this person has enough money left to continue the call */ if (balance <= nobal_amt) { /* Not enough money - reroute call to nobal location */ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Balance of %f fell below allowed amount of %f! (Account %s)\n", balance, nobal_amt, billaccount); /* IMPORTANT: Billing must be paused before the transfer occurs! This prevents infinite loops, since the transfer will result */ /* in nibblebill checking the call again in the routing process for an allowed balance! */ /* If you intend to give the user the option to re-up their balance, you must clear & resume billing once the balance is updated! */ nibblebill_pause(session); transfer_call(session, globals.nobal_action); } } } /* Done changing - release lock */ if (globals.mutex) { switch_mutex_unlock(globals.mutex); } /* Go check if this call is allowed to continue */ return SWITCH_STATUS_SUCCESS; }
static switch_status_t my_on_reporting(switch_core_session_t *session) { switch_status_t status = SWITCH_STATUS_SUCCESS; switch_channel_t *channel = switch_core_session_get_channel(session); switch_event_header_t *hi; switch_caller_profile_t *caller_profile; switch_app_log_t *app_log; bson cdr; int is_b; char *tmp; if (globals.shutdown) { return SWITCH_STATUS_SUCCESS; } is_b = channel && switch_channel_get_originator_caller_profile(channel); if (!globals.log_b && is_b) { const char *force_cdr = switch_channel_get_variable(channel, SWITCH_FORCE_PROCESS_CDR_VARIABLE); if (!switch_true(force_cdr)) { return SWITCH_STATUS_SUCCESS; } } bson_init(&cdr); /* Channel data */ bson_append_start_object(&cdr, "channel_data"); bson_append_string(&cdr, "state", switch_channel_state_name(switch_channel_get_state(channel))); bson_append_string(&cdr, "direction", switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND ? "outbound" : "inbound"); bson_append_int(&cdr, "state_number", switch_channel_get_state(channel)); if ((tmp = switch_channel_get_flag_string(channel))) { bson_append_string(&cdr, "flags", tmp); free(tmp); } if ((tmp = switch_channel_get_cap_string(channel))) { bson_append_string(&cdr, "caps", tmp); free(tmp); } bson_append_finish_object(&cdr); /* channel_data */ /* Channel variables */ bson_append_start_object(&cdr, "variables"); if ((hi = switch_channel_variable_first(channel))) { for (; hi; hi = hi->next) { if (!zstr(hi->name) && !zstr(hi->value)) { bson_append_string(&cdr, hi->name, hi->value); } } switch_channel_variable_last(channel); } bson_append_finish_object(&cdr); /* variables */ /* App log */ if ((app_log = switch_core_session_get_app_log(session))) { switch_app_log_t *ap; bson_append_start_object(&cdr, "app_log"); for (ap = app_log; ap; ap = ap->next) { bson_append_start_object(&cdr, "application"); bson_append_string(&cdr, "app_name", ap->app); bson_append_string(&cdr, "app_data", ap->arg); bson_append_long(&cdr, "app_stamp", ap->stamp); bson_append_finish_object(&cdr); /* application */ } bson_append_finish_object(&cdr); /* app_log */ } /* Callflow */ caller_profile = switch_channel_get_caller_profile(channel); while (caller_profile) { bson_append_start_object(&cdr, "callflow"); if (!zstr(caller_profile->dialplan)) { bson_append_string(&cdr, "dialplan", caller_profile->dialplan); } if (!zstr(caller_profile->profile_index)) { bson_append_string(&cdr, "profile_index", caller_profile->profile_index); } if (caller_profile->caller_extension) { switch_caller_application_t *ap; bson_append_start_object(&cdr, "extension"); bson_append_string(&cdr, "name", caller_profile->caller_extension->extension_name); bson_append_string(&cdr, "number", caller_profile->caller_extension->extension_number); if (caller_profile->caller_extension->current_application) { bson_append_string(&cdr, "current_app", caller_profile->caller_extension->current_application->application_name); } for (ap = caller_profile->caller_extension->applications; ap; ap = ap->next) { bson_append_start_object(&cdr, "application"); if (ap == caller_profile->caller_extension->current_application) { bson_append_bool(&cdr, "last_executed", 1); } bson_append_string(&cdr, "app_name", ap->application_name); bson_append_string(&cdr, "app_data", ap->application_data); bson_append_finish_object(&cdr); } if (caller_profile->caller_extension->children) { switch_caller_profile_t *cp = NULL; for (cp = caller_profile->caller_extension->children; cp; cp = cp->next) { if (!cp->caller_extension) { continue; } bson_append_start_object(&cdr, "sub_extensions"); bson_append_start_object(&cdr, "extension"); bson_append_string(&cdr, "name", cp->caller_extension->extension_name); bson_append_string(&cdr, "number", cp->caller_extension->extension_number); bson_append_string(&cdr, "dialplan", cp->dialplan); if (cp->caller_extension->current_application) { bson_append_string(&cdr, "current_app", cp->caller_extension->current_application->application_name); } for (ap = cp->caller_extension->applications; ap; ap = ap->next) { bson_append_start_object(&cdr, "application"); if (ap == cp->caller_extension->current_application) { bson_append_bool(&cdr, "last_executed", 1); } bson_append_string(&cdr, "app_name", ap->application_name); bson_append_string(&cdr, "app_data", ap->application_data); bson_append_finish_object(&cdr); } bson_append_finish_object(&cdr); /* extension */ bson_append_finish_object(&cdr); /* sub_extensions */ } } bson_append_finish_object(&cdr); /* extension */ } bson_append_start_object(&cdr, "caller_profile"); set_bson_profile_data(&cdr, caller_profile); if (caller_profile->origination_caller_profile) { switch_caller_profile_t *cp = NULL; bson_append_start_object(&cdr, "origination"); for (cp = caller_profile->origination_caller_profile; cp; cp = cp->next) { bson_append_start_object(&cdr, "origination_caller_profile"); set_bson_profile_data(&cdr, cp); bson_append_finish_object(&cdr); } bson_append_finish_object(&cdr); /* origination */ } if (caller_profile->originator_caller_profile) { switch_caller_profile_t *cp = NULL; bson_append_start_object(&cdr, "originator"); for (cp = caller_profile->originator_caller_profile; cp; cp = cp->next) { bson_append_start_object(&cdr, "originator_caller_profile"); set_bson_profile_data(&cdr, cp); bson_append_finish_object(&cdr); } bson_append_finish_object(&cdr); /* originator */ } if (caller_profile->originatee_caller_profile) { switch_caller_profile_t *cp = NULL; bson_append_start_object(&cdr, "originatee"); for (cp = caller_profile->originatee_caller_profile; cp; cp = cp->next) { bson_append_start_object(&cdr, "originatee_caller_profile"); set_bson_profile_data(&cdr, cp); bson_append_finish_object(&cdr); } bson_append_finish_object(&cdr); /* originatee */ } bson_append_finish_object(&cdr); /* caller_profile */ /* Timestamps */ if (caller_profile->times) { bson_append_start_object(&cdr, "times"); /* Insert timestamps as long ints (microseconds) to preserve accuracy */ bson_append_long(&cdr, "created_time", caller_profile->times->created); bson_append_long(&cdr, "profile_created_time", caller_profile->times->profile_created); bson_append_long(&cdr, "progress_time", caller_profile->times->progress); bson_append_long(&cdr, "progress_media_time", caller_profile->times->progress_media); bson_append_long(&cdr, "answered_time", caller_profile->times->answered); bson_append_long(&cdr, "bridged_time", caller_profile->times->bridged); bson_append_long(&cdr, "last_hold_time", caller_profile->times->last_hold); bson_append_long(&cdr, "hold_accum_time", caller_profile->times->hold_accum); bson_append_long(&cdr, "hangup_time", caller_profile->times->hungup); bson_append_long(&cdr, "resurrect_time", caller_profile->times->resurrected); bson_append_long(&cdr, "transfer_time", caller_profile->times->transferred); bson_append_finish_object(&cdr); /* times */ } bson_append_finish_object(&cdr); /* callflow */ caller_profile = caller_profile->next; } bson_finish(&cdr); switch_mutex_lock(globals.mongo_mutex); if (mongo_insert(globals.mongo_conn, globals.mongo_namespace, &cdr) != MONGO_OK) { if (globals.mongo_conn->err == MONGO_IO_ERROR) { mongo_error_t db_status; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "MongoDB connection failed; attempting reconnect...\n"); db_status = mongo_reconnect(globals.mongo_conn); if (db_status != MONGO_OK) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MongoDB reconnect failed with error code %d\n", db_status); status = SWITCH_STATUS_FALSE; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "MongoDB connection re-established.\n"); if (mongo_insert(globals.mongo_conn, globals.mongo_namespace, &cdr) != MONGO_OK) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mongo_insert: error code %d\n", globals.mongo_conn->err); status = SWITCH_STATUS_FALSE; } } } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mongo_insert: error code %d\n", globals.mongo_conn->err); status = SWITCH_STATUS_FALSE; } } switch_mutex_unlock(globals.mongo_mutex); bson_destroy(&cdr); return status; }
static void switch_core_standard_on_routing(switch_core_session_t *session) { switch_dialplan_interface_t *dialplan_interface = NULL; switch_caller_profile_t *caller_profile; switch_caller_extension_t *extension = NULL; char *expanded = NULL; char *dpstr = NULL; switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Standard ROUTING\n", switch_channel_get_name(session->channel)); switch_channel_set_variable(session->channel, "call_uuid", switch_core_session_get_uuid(session)); if ((switch_channel_test_flag(session->channel, CF_ANSWERED) || switch_channel_test_flag(session->channel, CF_EARLY_MEDIA) || switch_channel_test_flag(session->channel, CF_SIGNAL_BRIDGE_TTL)) && switch_channel_test_flag(session->channel, CF_PROXY_MODE)) { switch_ivr_media(session->uuid_str, SMF_NONE); } if ((caller_profile = switch_channel_get_caller_profile(session->channel)) == 0) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't get profile!\n"); switch_channel_hangup(session->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); return; } else { char *dp[25]; int argc, x, count = 0; if ((extension = switch_channel_get_queued_extension(session->channel))) { switch_channel_set_caller_extension(session->channel, extension); switch_channel_set_state(session->channel, CS_EXECUTE); goto end; } if (!zstr(caller_profile->dialplan)) { if ((dpstr = switch_core_session_strdup(session, caller_profile->dialplan))) { expanded = switch_channel_expand_variables(session->channel, dpstr); argc = switch_separate_string(expanded, ',', dp, (sizeof(dp) / sizeof(dp[0]))); for (x = 0; x < argc; x++) { char *dpname = dp[x]; char *dparg = NULL; if (dpname) { if ((dparg = strchr(dpname, ':'))) { *dparg++ = '\0'; } } else { continue; } if (!(dialplan_interface = switch_loadable_module_get_dialplan_interface(dpname))) { continue; } count++; extension = dialplan_interface->hunt_function(session, dparg, NULL); UNPROTECT_INTERFACE(dialplan_interface); if (extension) { switch_channel_set_caller_extension(session->channel, extension); switch_channel_set_state(session->channel, CS_EXECUTE); goto end; } } } } if (!count) { if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { if (switch_channel_test_flag(session->channel, CF_ANSWERED)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "No Dialplan on answered channel, changing state to HANGUP\n"); switch_channel_hangup(session->channel, SWITCH_CAUSE_NO_ROUTE_DESTINATION); } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "No Dialplan, changing state to CONSUME_MEDIA\n"); switch_channel_set_state(session->channel, CS_CONSUME_MEDIA); } goto end; } } } if (!extension) { if (switch_ivr_blind_transfer_ack(session, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "No Route, Aborting\n"); switch_channel_hangup(session->channel, SWITCH_CAUSE_NO_ROUTE_DESTINATION); } } end: if (expanded && dpstr && expanded != dpstr) { free(expanded); } }
static int oreka_send_sip_message(oreka_session_t *oreka, oreka_recording_status_t status, oreka_stream_type_t type) { switch_stream_handle_t sip_header = { 0 }; switch_stream_handle_t sdp = { 0 }; switch_stream_handle_t udp_packet = { 0 }; switch_caller_profile_t *caller_profile = NULL; switch_channel_t *channel = NULL; switch_event_t *extra_headers = NULL; switch_event_header_t *ei = NULL; switch_core_session_t *session = oreka->session; const char *method = status == FS_OREKA_START ? "INVITE" : "BYE"; const char *session_uuid = switch_core_session_get_uuid(oreka->session); const char *caller_id_number = NULL; const char *caller_id_name = NULL; const char *callee_id_number = NULL; const char *callee_id_name = NULL; int rc = 0; channel = switch_core_session_get_channel(session); SWITCH_STANDARD_STREAM(sip_header); SWITCH_STANDARD_STREAM(sdp); SWITCH_STANDARD_STREAM(udp_packet); extra_headers = get_extra_headers(oreka, status); caller_profile = switch_channel_get_caller_profile(channel); /* Get caller meta data */ caller_id_number = switch_caller_get_field_by_name(caller_profile, "caller_id_number"); caller_id_name = switch_caller_get_field_by_name(caller_profile, "caller_id_name"); if (zstr(caller_id_name)) { caller_id_name = caller_id_number; } callee_id_number = switch_caller_get_field_by_name(caller_profile, "callee_id_number"); if (zstr(callee_id_number)) { callee_id_number = switch_caller_get_field_by_name(caller_profile, "destination_number"); } callee_id_name = switch_caller_get_field_by_name(caller_profile, "callee_id_name"); if (zstr(callee_id_name)) { callee_id_name = callee_id_number; } /* Setup the RTP */ if (status == FS_OREKA_START) { if (oreka_setup_rtp(oreka, type)) { rc = -1; goto done; } } if (status == FS_OREKA_STOP) { oreka_tear_down_rtp(oreka, type); } /* Fill in the SDP first if this is the beginning */ if (status == FS_OREKA_START) { sdp.write_function(&sdp, "v=0\r\n"); sdp.write_function(&sdp, "o=freeswitch %s 1 IN IP4 %s\r\n", session_uuid, globals.local_ipv4_str); sdp.write_function(&sdp, "c=IN IP4 %s\r\n", globals.sip_server_ipv4_str); sdp.write_function(&sdp, "s=Phone Recording (%s)\r\n", type == FS_OREKA_READ ? "RX" : "TX"); sdp.write_function(&sdp, "i=FreeSWITCH Oreka Recorder (pid=%d)\r\n", globals.our_pid); sdp.write_function(&sdp, "m=audio %d RTP/AVP 0\r\n", type == FS_OREKA_READ ? oreka->read_rtp_port : oreka->write_rtp_port); sdp.write_function(&sdp, "a=rtpmap:0 PCMU/%d\r\n", type == FS_OREKA_READ ? oreka->read_impl.samples_per_second : oreka->write_impl.samples_per_second); } /* Request line */ sip_header.write_function(&sip_header, "%s sip:%s@%s:5060 SIP/2.0\r\n", method, callee_id_name, globals.local_ipv4_str); /* Via */ sip_header.write_function(&sip_header, "Via: SIP/2.0/UDP %s:5061;branch=z9hG4bK-%s\r\n", globals.local_ipv4_str, session_uuid); /* From */ sip_header.write_function(&sip_header, "From: <sip:%s@%s:5061;tag=1>\r\n", caller_id_number, globals.local_ipv4_str); /* To */ sip_header.write_function(&sip_header, "To: <sip:%s@%s:5060>\r\n", callee_id_number, globals.local_ipv4_str); /* Call-ID */ sip_header.write_function(&sip_header, "Call-ID: %s\r\n", session_uuid); /* CSeq */ sip_header.write_function(&sip_header, "CSeq: 1 %s\r\n", method); /* Contact */ sip_header.write_function(&sip_header, "Contact: sip:freeswitch@%s:5061\r\n", globals.local_ipv4_str); /* Max-Forwards */ sip_header.write_function(&sip_header, "Max-Forwards: 70\r\n", method); /* Subject */ sip_header.write_function(&sip_header, "Subject: %s %s recording of %s\r\n", status == FS_OREKA_START ? "BEGIN": "END", type == FS_OREKA_READ ? "RX" : "TX", caller_id_name); /* Add any custom extra headers */ for (ei = extra_headers->headers; ei; ei = ei->next) { const char *name = ei->name; char *value = ei->value; if (!strncasecmp(name, SIP_OREKA_HEADER_PREFIX, SIP_OREKA_HEADER_PREFIX_LEN)) { const char *hname = name + SIP_OREKA_HEADER_PREFIX_LEN; sip_header.write_function(&sip_header, "%s: %s\r\n", hname, value); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Adding custom oreka SIP header %s: %s\n", hname, value); } } if (status == FS_OREKA_START) { /* Content-Type */ sip_header.write_function(&sip_header, "Content-Type: application/sdp\r\n"); } /* Content-Length */ sip_header.write_function(&sip_header, "Content-Length: %d\r\n", sdp.data_len); udp_packet.write_function(&udp_packet, "%s\r\n%s\n", sip_header.data, sdp.data); oreka_write_udp(oreka, &udp_packet); done: if (sip_header.data) { free(sip_header.data); } if (sdp.data) { free(sdp.data); } if (udp_packet.data) { free(udp_packet.data); } if (status == FS_OREKA_STOP) { oreka_destroy(oreka); } return rc; }
static switch_status_t channel_on_execute(switch_core_session_t *session) { switch_channel_t *channel = NULL; loopback_private_t *tech_pvt = NULL; switch_caller_extension_t *exten = NULL; const char *bowout = NULL; int bow = 0; channel = switch_core_session_get_channel(session); assert(channel != NULL); tech_pvt = switch_core_session_get_private(session); assert(tech_pvt != NULL); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL EXECUTE\n", switch_channel_get_name(channel)); if ((bowout = switch_channel_get_variable(tech_pvt->channel, "loopback_bowout_on_execute")) && switch_true(bowout)) { /* loopback_bowout_on_execute variable is set */ bow = 1; } else if ((exten = switch_channel_get_caller_extension(channel))) { /* check for bowout flag */ switch_caller_application_t *app_p; for (app_p = exten->applications; app_p; app_p = app_p->next) { int32_t flags; switch_core_session_get_app_flags(app_p->application_name, &flags); if ((flags & SAF_NO_LOOPBACK)) { bow = 1; break; } } } if (bow) { switch_core_session_t *other_session = NULL; switch_caller_profile_t *cp, *clone; const char *other_uuid = NULL; switch_event_t *event = NULL; switch_set_flag(tech_pvt, TFLAG_BOWOUT); if ((find_non_loopback_bridge(tech_pvt->other_session, &other_session, &other_uuid) == SWITCH_STATUS_SUCCESS)) { switch_channel_t *other_channel = switch_core_session_get_channel(other_session); switch_channel_wait_for_state_timeout(other_channel, CS_EXCHANGE_MEDIA, 5000); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_INFO, "BOWOUT Replacing loopback channel with real channel: %s\n", switch_channel_get_name(other_channel)); if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, "loopback::bowout") == SWITCH_STATUS_SUCCESS) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Resigning-UUID", switch_channel_get_uuid(channel)); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Acquired-UUID", switch_channel_get_uuid(other_channel)); switch_event_fire(&event); } if ((cp = switch_channel_get_caller_profile(channel))) { clone = switch_caller_profile_clone(other_session, cp); clone->originator_caller_profile = NULL; clone->originatee_caller_profile = NULL; switch_channel_set_caller_profile(other_channel, clone); } switch_channel_caller_extension_masquerade(channel, other_channel, 0); switch_channel_set_state(other_channel, CS_RESET); switch_channel_wait_for_state(other_channel, NULL, CS_RESET); switch_channel_set_state(other_channel, CS_EXECUTE); switch_core_session_rwunlock(other_session); switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_UNSPECIFIED); } } return SWITCH_STATUS_SUCCESS; }
static switch_status_t generate_json_cdr(switch_core_session_t *session, struct json_object **json_cdr) { struct json_object *cdr = json_object_new_object(); switch_channel_t *channel = switch_core_session_get_channel(session); switch_caller_profile_t *caller_profile; struct json_object *variables, *j_main_cp, *j_caller_profile, *j_caller_extension, *j_times, *time_tag, *j_application, *j_callflow, *j_inner_extension, *j_apps, *j_o, *j_channel_data, *j_field; switch_app_log_t *app_log; char tmp[512], *f; if (is_error(cdr)) { return SWITCH_STATUS_FALSE; } j_channel_data = json_object_new_object(); if (is_error(j_channel_data)) { goto error; } json_object_object_add(cdr, "channel_data", j_channel_data); j_field = json_object_safe_new_string((char *) switch_channel_state_name(switch_channel_get_state(channel))); json_object_object_add(j_channel_data, "state", j_field); j_field = json_object_safe_new_string(switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND ? "outbound" : "inbound"); json_object_object_add(j_channel_data, "direction", j_field); switch_snprintf(tmp, sizeof(tmp), "%d", switch_channel_get_state(channel)); j_field = json_object_new_string((char *) tmp); json_object_object_add(j_channel_data, "state_number", j_field); if ((f = switch_channel_get_flag_string(channel))) { j_field = json_object_safe_new_string((char *) f); json_object_object_add(j_channel_data, "flags", j_field); free(f); } if ((f = switch_channel_get_cap_string(channel))) { j_field = json_object_safe_new_string((char *) f); json_object_object_add(j_channel_data, "caps", j_field); free(f); } variables = json_object_new_object(); json_object_object_add(cdr, "variables", variables); if (is_error(variables)) { goto error; } set_json_chan_vars(variables, channel); if ((app_log = switch_core_session_get_app_log(session))) { switch_app_log_t *ap; j_apps = json_object_new_object(); if (is_error(j_apps)) { goto error; } json_object_object_add(cdr, "app_log", j_apps); for (ap = app_log; ap; ap = ap->next) { j_application = json_object_new_object(); if (is_error(j_application)) { goto error; } json_object_object_add(j_application, "app_name", json_object_safe_new_string(ap->app)); json_object_object_add(j_application, "app_data", json_object_safe_new_string(ap->arg)); json_object_object_add(j_apps, "application", j_application); } } caller_profile = switch_channel_get_caller_profile(channel); while (caller_profile) { j_callflow = json_object_new_object(); if (is_error(j_callflow)) { goto error; } json_object_object_add(cdr, "callflow", j_callflow); if (!zstr(caller_profile->dialplan)) { json_object_object_add(j_callflow, "dialplan", json_object_safe_new_string((char *)caller_profile->dialplan)); } if (!zstr(caller_profile->profile_index)) { json_object_object_add(j_callflow, "profile_index", json_object_safe_new_string((char *)caller_profile->profile_index)); } if (caller_profile->caller_extension) { switch_caller_application_t *ap; j_caller_extension = json_object_new_object(); if (is_error(j_caller_extension)) { goto error; } json_object_object_add(j_callflow, "extension", j_caller_extension); json_object_object_add(j_caller_extension, "name", json_object_safe_new_string(caller_profile->caller_extension->extension_name)); json_object_object_add(j_caller_extension, "number", json_object_safe_new_string(caller_profile->caller_extension->extension_number)); if (caller_profile->caller_extension->current_application) { json_object_object_add(j_caller_extension, "current_app", json_object_safe_new_string(caller_profile->caller_extension->current_application->application_name)); } for (ap = caller_profile->caller_extension->applications; ap; ap = ap->next) { j_application = json_object_new_object(); if (is_error(j_application)) { goto error; } json_object_object_add(j_caller_extension, "application", j_application); if (ap == caller_profile->caller_extension->current_application) { json_object_object_add(j_application, "last_executed", json_object_new_string("true")); } json_object_object_add(j_application, "app_name", json_object_safe_new_string(ap->application_name)); json_object_object_add(j_application, "app_data", json_object_safe_new_string(switch_str_nil(ap->application_data))); } if (caller_profile->caller_extension->children) { switch_caller_profile_t *cp = NULL; for (cp = caller_profile->caller_extension->children; cp; cp = cp->next) { if (!cp->caller_extension) { continue; } j_inner_extension = json_object_new_object(); if (is_error(j_inner_extension)) { goto error; } json_object_object_add(j_caller_extension, "sub_extensions", j_inner_extension); j_caller_extension = json_object_new_object(); if (is_error(j_caller_extension)) { goto error; } json_object_object_add(j_inner_extension, "extension", j_caller_extension); json_object_object_add(j_caller_extension, "name", json_object_safe_new_string(cp->caller_extension->extension_name)); json_object_object_add(j_caller_extension, "number", json_object_safe_new_string(cp->caller_extension->extension_number)); json_object_object_add(j_caller_extension, "dialplan", json_object_safe_new_string((char *)cp->dialplan)); if (cp->caller_extension->current_application) { json_object_object_add(j_caller_extension, "current_app", json_object_safe_new_string(cp->caller_extension->current_application->application_name)); } for (ap = cp->caller_extension->applications; ap; ap = ap->next) { j_application = json_object_new_object(); if (is_error(j_application)) { goto error; } json_object_object_add(j_caller_extension, "application", j_application); if (ap == cp->caller_extension->current_application) { json_object_object_add(j_application, "last_executed", json_object_new_string("true")); } json_object_object_add(j_application, "app_name", json_object_safe_new_string(ap->application_name)); json_object_object_add(j_application, "app_data", json_object_safe_new_string(switch_str_nil(ap->application_data))); } } } } j_main_cp = json_object_new_object(); if (is_error(j_main_cp)) { goto error; } json_object_object_add(j_callflow, "caller_profile", j_main_cp); set_json_profile_data(j_main_cp, caller_profile); if (caller_profile->originator_caller_profile) { switch_caller_profile_t *cp = NULL; j_o = json_object_new_object(); if (is_error(j_o)) { goto error; } json_object_object_add(j_main_cp, "originator", j_o); for (cp = caller_profile->originator_caller_profile; cp; cp = cp->next) { j_caller_profile = json_object_new_object(); if (is_error(j_caller_profile)) { goto error; } json_object_object_add(j_o, "originator_caller_profile", j_caller_profile); set_json_profile_data(j_caller_profile, cp); } } if (caller_profile->originatee_caller_profile) { switch_caller_profile_t *cp = NULL; j_o = json_object_new_object(); if (is_error(j_o)) { goto error; } json_object_object_add(j_main_cp, "originatee", j_o); for (cp = caller_profile->originatee_caller_profile; cp; cp = cp->next) { j_caller_profile = json_object_new_object(); if (is_error(j_caller_profile)) { goto error; } json_object_object_add(j_o, "originatee_caller_profile", j_caller_profile); set_json_profile_data(j_caller_profile, cp); } } if (caller_profile->times) { j_times = json_object_new_object(); if (is_error(j_times)) { goto error; } json_object_object_add(j_callflow, "times", j_times); switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->created); time_tag = json_object_new_string(tmp); if (is_error(time_tag)) { goto error; } json_object_object_add(j_times, "created_time", time_tag); switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->profile_created); time_tag = json_object_new_string(tmp); if (is_error(time_tag)) { goto error; } json_object_object_add(j_times, "profile_created_time", time_tag); switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->progress); time_tag = json_object_new_string(tmp); if (is_error(time_tag)) { goto error; } json_object_object_add(j_times, "progress_time", time_tag); switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->progress_media); time_tag = json_object_new_string(tmp); if (is_error(time_tag)) { goto error; } json_object_object_add(j_times, "progress_media_time", time_tag); switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->answered); time_tag = json_object_new_string(tmp); if (is_error(time_tag)) { goto error; } json_object_object_add(j_times, "answered_time", time_tag); switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->hungup); time_tag = json_object_new_string(tmp); if (is_error(time_tag)) { goto error; } json_object_object_add(j_times, "hangup_time", time_tag); switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->resurrected); time_tag = json_object_new_string(tmp); if (is_error(time_tag)) { goto error; } json_object_object_add(j_times, "resurrect_time", time_tag); switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->transferred); time_tag = json_object_new_string(tmp); if (is_error(time_tag)) { goto error; } json_object_object_add(j_times, "transfer_time", time_tag); } caller_profile = caller_profile->next; } *json_cdr = cdr; return SWITCH_STATUS_SUCCESS; error: if (cdr) { json_object_put(cdr); } return SWITCH_STATUS_FALSE; }
static switch_status_t my_on_reporting(switch_core_session_t *session) { switch_xml_t cdr = NULL; switch_channel_t *channel = switch_core_session_get_channel(session); rc_handle *rad_config; switch_status_t retval = SWITCH_STATUS_TERM; VALUE_PAIR *send = NULL; uint32_t client_port = 0; uint32_t framed_addr = 0; uint32_t status_type = PW_STATUS_STOP; switch_time_t callstartdate = 0; switch_time_t callanswerdate = 0; switch_time_t callenddate = 0; switch_time_t calltransferdate = 0; switch_time_t billusec = 0; uint32_t billsec = 0; char *uuid_str; switch_time_exp_t tm; char buffer[32] = ""; if (globals.shutdown) { return SWITCH_STATUS_FALSE; } if (channel) { const char *disable_flag = switch_channel_get_variable(channel, "disable_radius_stop"); if (switch_true(disable_flag)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "[mod_radius_cdr] Not Sending RADIUS Stop\n"); return SWITCH_STATUS_SUCCESS; } } switch_thread_rwlock_rdlock(globals.rwlock); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "[mod_radius_cdr] Entering my_on_reporting\n"); rad_config = my_radius_init(); if (rad_config == NULL) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "[mod_radius_cdr] Error initializing radius, session not logged.\n"); goto end; } if (switch_ivr_generate_xml_cdr(session, &cdr) == SWITCH_STATUS_SUCCESS) { uuid_str = switch_core_session_get_uuid(session); } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "[mod_radius_cdr] Error Generating Data!\n"); goto end; } /* Create the radius packet */ /* Set Status Type */ if (rc_avpair_add(rad_config, &send, PW_ACCT_STATUS_TYPE, &status_type, -1, 0) == NULL) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "failed adding Acct-Session-ID: %s\n", uuid_str); rc_destroy(rad_config); goto end; } if (rc_avpair_add(rad_config, &send, PW_ACCT_SESSION_ID, uuid_str, -1, 0) == NULL) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "failed adding Acct-Session-ID: %s\n", uuid_str); rc_destroy(rad_config); goto end; } /* Add VSAs */ if (channel) { switch_call_cause_t cause; switch_caller_profile_t *profile; cause = switch_channel_get_cause(channel); if (rc_avpair_add(rad_config, &send, PW_FS_HANGUPCAUSE, &cause, -1, PW_FS_PEC) == NULL) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "failed adding Freeswitch-Hangupcause: %d\n", cause); rc_destroy(rad_config); goto end; } profile = switch_channel_get_caller_profile(channel); if (profile) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "[mod_radius_cdr] Calculating billable time\n"); /* calculate billable time */ callstartdate = profile->times->created; callanswerdate = profile->times->answered; calltransferdate = profile->times->transferred; callenddate = profile->times->hungup; if (switch_channel_test_flag(channel, CF_ANSWERED)) { if (callstartdate && callanswerdate) { if (callenddate) billusec = callenddate - callanswerdate; else if (calltransferdate) billusec = calltransferdate - callanswerdate; } } else if (switch_channel_test_flag(channel, CF_TRANSFER)) { if (callanswerdate && calltransferdate) billusec = calltransferdate - callanswerdate; } billsec = (billusec / 1000000); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "[mod_radius_cdr] Finished calculating billable time\n"); if (profile->username) { if (rc_avpair_add(rad_config, &send, PW_USER_NAME, (void *) profile->username, -1, 0) == NULL) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "failed adding User-Name: %s\n", profile->username); rc_destroy(rad_config); goto end; } } if (profile->caller_id_number) { if (rc_avpair_add(rad_config, &send, PW_FS_SRC, (void *) profile->caller_id_number, -1, PW_FS_PEC) == NULL) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "failed adding Freeswitch-Src: %s\n", profile->caller_id_number); rc_destroy(rad_config); goto end; } } if (profile->caller_id_name) { if (rc_avpair_add(rad_config, &send, PW_FS_CLID, (void *) profile->caller_id_name, -1, PW_FS_PEC) == NULL) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "failed adding Freeswitch-CLID: %s\n", profile->caller_id_name); rc_destroy(rad_config); goto end; } } if (profile->destination_number) { if (rc_avpair_add(rad_config, &send, PW_FS_DST, (void *) profile->destination_number, -1, PW_FS_PEC) == NULL) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "failed adding Freeswitch-Dst: %s\n", profile->destination_number); rc_destroy(rad_config); goto end; } } if (profile->dialplan) { if (rc_avpair_add(rad_config, &send, PW_FS_DIALPLAN, (void *) profile->dialplan, -1, PW_FS_PEC) == NULL) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "failed adding Freeswitch-Dialplan: %s\n", profile->dialplan); rc_destroy(rad_config); goto end; } } if (profile->network_addr) { inet_pton(AF_INET, (void *) profile->network_addr, &framed_addr); framed_addr = htonl(framed_addr); if (rc_avpair_add(rad_config, &send, PW_FRAMED_IP_ADDRESS, &framed_addr, -1, 0) == NULL) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "failed adding Framed-IP-Address: %s\n", profile->network_addr); rc_destroy(rad_config); goto end; } } if (profile->rdnis) { if (rc_avpair_add(rad_config, &send, PW_FS_RDNIS, (void *) profile->rdnis, -1, PW_FS_PEC) == NULL) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "failed adding Freeswitch-RDNIS: %s\n", profile->rdnis); rc_destroy(rad_config); goto end; } } if (profile->context) { if (rc_avpair_add(rad_config, &send, PW_FS_CONTEXT, (void *) profile->context, -1, PW_FS_PEC) == NULL) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "failed adding Freeswitch-Context: %s\n", profile->context); rc_destroy(rad_config); goto end; } } if (profile->ani) { if (rc_avpair_add(rad_config, &send, PW_FS_ANI, (void *) profile->ani, -1, PW_FS_PEC) == NULL) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "failed adding Freeswitch-ANI: %s\n", profile->ani); rc_destroy(rad_config); goto end; } } if (profile->aniii) { if (rc_avpair_add(rad_config, &send, PW_FS_ANIII, (void *) profile->aniii, -1, PW_FS_PEC) == NULL) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "failed adding Freeswitch-ANIII: %s\n", profile->aniii); rc_destroy(rad_config); goto end; } } if (profile->source) { if (rc_avpair_add(rad_config, &send, PW_FS_SOURCE, (void *) profile->source, -1, PW_FS_PEC) == NULL) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "failed adding Freeswitch-Source: %s\n", profile->source); rc_destroy(rad_config); goto end; } } if (profile->caller_extension && profile->caller_extension->last_application && profile->caller_extension->last_application->application_name) { if (rc_avpair_add(rad_config, &send, PW_FS_LASTAPP, (void *) profile->caller_extension->last_application->application_name, -1, PW_FS_PEC) == NULL) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "failed adding Freeswitch-Lastapp: %s\n", profile->source); rc_destroy(rad_config); goto end; } } if (rc_avpair_add(rad_config, &send, PW_FS_BILLUSEC, &billusec, -1, PW_FS_PEC) == NULL) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "failed adding Freeswitch-Billusec: %u\n", (uint32_t) billusec); rc_destroy(rad_config); goto end; } if (callstartdate > 0) { switch_time_exp_lt(&tm, callstartdate); switch_snprintf(buffer, sizeof(buffer), "%04u-%02u-%02uT%02u:%02u:%02u.%06u%+03d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec, tm.tm_gmtoff / 3600, tm.tm_gmtoff % 3600); if (rc_avpair_add(rad_config, &send, PW_FS_CALLSTARTDATE, &buffer, -1, PW_FS_PEC) == NULL) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "failed adding Freeswitch-Callstartdate: %s\n", buffer); rc_destroy(rad_config); goto end; } } if (callanswerdate > 0) { switch_time_exp_lt(&tm, callanswerdate); switch_snprintf(buffer, sizeof(buffer), "%04u-%02u-%02uT%02u:%02u:%02u.%06u%+03d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec, tm.tm_gmtoff / 3600, tm.tm_gmtoff % 3600); if (rc_avpair_add(rad_config, &send, PW_FS_CALLANSWERDATE, &buffer, -1, PW_FS_PEC) == NULL) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "failed adding Freeswitch-Callanswerdate: %s\n", buffer); rc_destroy(rad_config); goto end; } } if (calltransferdate > 0) { switch_time_exp_lt(&tm, calltransferdate); switch_snprintf(buffer, sizeof(buffer), "%04u-%02u-%02uT%02u:%02u:%02u.%06u%+03d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec, tm.tm_gmtoff / 3600, tm.tm_gmtoff % 3600); if (rc_avpair_add(rad_config, &send, PW_FS_CALLTRANSFERDATE, &buffer, -1, PW_FS_PEC) == NULL) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "failed adding Freeswitch-Calltransferdate: %s\n", buffer); rc_destroy(rad_config); goto end; } } if (callenddate > 0) { switch_time_exp_lt(&tm, callenddate); switch_snprintf(buffer, sizeof(buffer), "%04u-%02u-%02uT%02u:%02u:%02u.%06u%+03d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec, tm.tm_gmtoff / 3600, tm.tm_gmtoff % 3600); if (rc_avpair_add(rad_config, &send, PW_FS_CALLENDDATE, &buffer, -1, PW_FS_PEC) == NULL) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "failed adding Freeswitch-Callenddate: %s\n", buffer); rc_destroy(rad_config); goto end; } } if (rc_avpair_add(rad_config, &send, PW_ACCT_SESSION_TIME, &billsec, -1, 0) == NULL) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "failed adding Acct-Session-Time: %u\n", billsec); rc_destroy(rad_config); goto end; } { const char *direction_str = profile->direction == SWITCH_CALL_DIRECTION_INBOUND ? "inbound" : "outbound"; if (rc_avpair_add(rad_config, &send, PW_FS_DIRECTION, (void *) direction_str, -1, PW_FS_PEC) == NULL) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "failed adding Freeswitch-Direction: %s\n", direction_str); rc_destroy(rad_config); goto end; } } } else { /* no profile, can't create data to send */ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "profile == NULL\n"); } } if (rc_acct(rad_config, client_port, send) == OK_RC) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "RADIUS Accounting OK\n"); retval = SWITCH_STATUS_SUCCESS; } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "RADIUS Accounting Failed\n"); retval = SWITCH_STATUS_TERM; } rc_avpair_free(send); rc_destroy(rad_config); end: switch_xml_free(cdr); switch_thread_rwlock_unlock(globals.rwlock); return (retval); }
switch_status_t mod_xml_radius_add_params(switch_core_session_t *session, switch_event_t *params, rc_handle *handle, VALUE_PAIR **send, switch_xml_t fields) { switch_xml_t param; void *av_value = NULL; if ( (param = switch_xml_child(fields, "param")) == NULL) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to locate a param under the fields section\n"); goto err; } for (; param; param = param->next) { DICT_ATTR *attribute = NULL; DICT_VENDOR *vendor = NULL; int attr_num = 0, vend_num = 0; char *var = (char *) switch_xml_attr(param, "name"); char *vend = (char *) switch_xml_attr(param, "vendor"); char *variable = (char *) switch_xml_attr(param, "variable"); char *variable_secondary = (char *) switch_xml_attr(param, "variable_secondary"); char *val_default = (char *) switch_xml_attr(param, "default"); char *format = (char *) switch_xml_attr(param, "format"); char *other_leg = (char *) switch_xml_attr(param, "other_leg"); attribute = rc_dict_findattr(handle, var); if ( attribute == NULL ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: Could not locate attribute '%s' in the configured dictionary\n", var); goto err; } if ( GLOBAL_DEBUG ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: dict attr '%s' value '%d' type '%d'\n", attribute->name, attribute->value, attribute->type); } attr_num = attribute->value; if ( vend ) { vendor = rc_dict_findvend(handle, vend); if ( vendor == NULL ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: Could not locate vendor '%s' in the configured dictionary %p\n", vend, vend); goto err; } if ( GLOBAL_DEBUG ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: dict vend name '%s' vendorpec '%d'\n", vendor->vendorname, vendor->vendorpec); } vend_num = vendor->vendorpec; } if ( var ) { if ( session ) { switch_channel_t *channel = switch_core_session_get_channel(session); /* Accounting only */ if ( strncmp( var, "h323-setup-time", 15) == 0 ) { switch_caller_profile_t *profile = switch_channel_get_caller_profile(channel); switch_time_t time = profile->times->created; switch_time_exp_t tm; if ( !time ) { goto end_loop; } switch_time_exp_lt(&tm, time); if ( GLOBAL_TIME_FORMAT == 1 ) { av_value = switch_mprintf("%02u:%02u:%02u.%03u %s %s %s %02u %04u", tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec/1000, GLOBAL_TIME_ZONE, radattrdays[tm.tm_wday], radattrmonths[tm.tm_mon], tm.tm_mday, tm.tm_year + 1900); } else { av_value = switch_mprintf("%04u-%02u-%02uT%02u:%02u:%02u.%06u%+03d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec, tm.tm_gmtoff / 3600, tm.tm_gmtoff % 3600); } if (rc_avpair_add(handle, send, attr_num, av_value, -1, vend_num) == NULL) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: failed to add option to handle\n"); goto err; } if ( GLOBAL_DEBUG ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: value: %s\n", (char *) av_value); } } else if ( strncmp( var, "h323-connect-time", 17) == 0 ) { switch_caller_profile_t *profile = switch_channel_get_caller_profile(channel); switch_time_t time = profile->times->answered; switch_time_exp_t tm; if ( !time ) { goto end_loop; } switch_time_exp_lt(&tm, time); if ( GLOBAL_TIME_FORMAT == 1 ) { av_value = switch_mprintf("%02u:%02u:%02u.%03u %s %s %s %02u %04u", tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec/1000, GLOBAL_TIME_ZONE, radattrdays[tm.tm_wday], radattrmonths[tm.tm_mon], tm.tm_mday, tm.tm_year + 1900); } else { av_value = switch_mprintf("%04u-%02u-%02uT%02u:%02u:%02u.%06u%+03d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec, tm.tm_gmtoff / 3600, tm.tm_gmtoff % 3600); } if (rc_avpair_add(handle, send, attr_num, av_value, -1, vend_num) == NULL) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: failed to add option to handle\n"); goto err; } if ( GLOBAL_DEBUG ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: value: %s\n", (char *) av_value); } } else if ( strncmp( var, "h323-disconnect-time", 20) == 0 ) { switch_caller_profile_t *profile = switch_channel_get_caller_profile(channel); switch_time_t time = profile->times->hungup; switch_time_exp_t tm; if ( !time ) { if ( variable_secondary != NULL && strncmp(variable_secondary, "now", 3) == 0 ) { time = switch_time_now(); } else { goto end_loop; } } switch_time_exp_lt(&tm, time); if ( GLOBAL_TIME_FORMAT == 1 ) { av_value = switch_mprintf("%02u:%02u:%02u.%03u %s %s %s %02u %04u", tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec/1000, GLOBAL_TIME_FORMAT, radattrdays[tm.tm_wday], radattrmonths[tm.tm_mon], tm.tm_mday, tm.tm_year + 1900); } else { av_value = switch_mprintf("%04u-%02u-%02uT%02u:%02u:%02u.%06u%+03d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec, tm.tm_gmtoff / 3600, tm.tm_gmtoff % 3600); } if (rc_avpair_add(handle, send, attr_num, av_value, -1, vend_num) == NULL) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: failed to add option to handle\n"); goto err; } if ( GLOBAL_DEBUG ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: value: %s\n", (char *) av_value); } } else if ( strncmp( var, "h323-disconnect-cause", 21) == 0 ) { switch_call_cause_t cause = switch_channel_get_cause(channel); av_value = switch_mprintf("h323-disconnect-cause=%x", cause); if (rc_avpair_add(handle, send, 30, av_value, -1, 9) == NULL) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: failed to add disconnect cause \n"); goto err; } } else { if ( format == NULL ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing format attribute for %s variable\n", variable); goto err; } if ( attribute->type == 0 ) { const char *val = NULL; if ( other_leg ) { val = switch_channel_get_variable_partner(channel, variable); if ( val == NULL && variable_secondary != NULL) { val = switch_channel_get_variable_partner(channel, variable_secondary); } } else { val = switch_channel_get_variable(channel, variable); if ( val == NULL && variable_secondary != NULL) { val = switch_channel_get_variable(channel, variable_secondary); } } if ( val == NULL && val_default != NULL) { av_value = switch_mprintf(format, val_default); } else { av_value = switch_mprintf(format, val); } if ( GLOBAL_DEBUG ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: value: %s\n", (char *) av_value); } if (rc_avpair_add(handle, send, attr_num, av_value, -1, vend_num) == NULL) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: failed to add option with val '%s' to handle\n", (char *) av_value); goto err; } } else if ( attribute->type == 1 ) { int number = atoi(switch_channel_get_variable(channel, variable)); if (rc_avpair_add(handle, send, attr_num, &number, -1, vend_num) == NULL) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: failed to add option with value '%d' to handle\n", number); goto err; } } } } else if ( params ) { /* Auth only */ char *tmp = switch_event_get_header(params, variable); if ( GLOBAL_DEBUG ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: param var '%s' val: %s\n", variable, tmp); } if ( tmp == NULL ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: Unable to locate '%s' on the event\n", variable); goto err; } av_value = switch_mprintf(format, tmp); if (rc_avpair_add(handle, send, attr_num, av_value, -1, vend_num) == NULL) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: failed to add option to handle\n"); goto err; } } else { goto err; } } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: all params must have a name attribute\n"); goto err; } end_loop: if ( av_value != NULL ) { free(av_value); av_value = NULL; } } return SWITCH_STATUS_SUCCESS; err: if ( av_value != NULL ) { free(av_value); av_value = NULL; } return SWITCH_STATUS_GENERR; }