void sngisdn_snd_event(sngisdn_span_data_t *signal_data, ftdm_oob_event_t event) { sng_l1_event_t l1_event; if (!signal_data->dchan) { return; } memset(&l1_event, 0, sizeof(l1_event)); switch(event) { case FTDM_OOB_ALARM_CLEAR: l1_event.type = SNG_L1EVENT_ALARM_OFF; sng_isdn_event_ind(signal_data->link_id, &l1_event); if (!signal_data->dl_request_pending) { signal_data->dl_request_pending = 1; ftdm_sched_timer(signal_data->sched, "delayed_dl_req", 8000, sngisdn_delayed_dl_req, (void*) signal_data, NULL); } break; case FTDM_OOB_ALARM_TRAP: l1_event.type = SNG_L1EVENT_ALARM_ON; sng_isdn_event_ind(signal_data->link_id, &l1_event); break; default: /* We do not care about the other OOB events for now */ return; } return; }
void sngisdn_set_chan_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status) { ftdm_sigmsg_t sig; sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)ftdmchan->span->signal_data; ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Signalling link status changed to %s\n", ftdm_signaling_status2str(status)); memset(&sig, 0, sizeof(sig)); sig.chan_id = ftdmchan->chan_id; sig.span_id = ftdmchan->span_id; sig.channel = ftdmchan; sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; sig.ev_data.sigstatus.status = status; ftdm_span_send_signal(ftdmchan->span, &sig); if (FTDM_SPAN_IS_BRI(ftdmchan->span)) { sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data; if (ftdm_test_flag(sngisdn_info, FLAG_ACTIVATING)) { ftdm_clear_flag(sngisdn_info, FLAG_ACTIVATING); ftdm_sched_timer(signal_data->sched, "delayed_setup", 1000, sngisdn_delayed_setup, (void*) sngisdn_info, NULL); } } return; }
int main(int argc, char *argv[]) { ftdm_status_t status; custom_data_t data; ftdm_sched_t *sched; signal(SIGINT, trap); ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG); ftdm_cpu_monitor_disable(); if (ftdm_global_init() != FTDM_SUCCESS) { fprintf(stderr, "Error loading FreeTDM\n"); exit(-1); } status = ftdm_sched_create(&sched, "testsched"); if (status != FTDM_SUCCESS) { fprintf(stderr, "Error creating sched\n"); exit(-1); } data.sched = sched; data.counter = 10; data.beat = 5000; data.callback = handle_heartbeat; status = ftdm_sched_timer(sched, "heartbeat", data.beat, data.callback, &data, &data.heartbeat_timer); if (status != FTDM_SUCCESS) { fprintf(stderr, "Error creating heartbeat timer\n"); exit(-1); } ftdm_sched_free_run(sched); while (running) { ftdm_sleep(10); } ftdm_global_destroy(); printf("Done, press any key to die!\n"); getchar(); return 0; }
void handle_heartbeat(void *usrdata) { ftdm_status_t status; custom_data_t *data = usrdata; printf("beep (elapsed %dms count= %d)\n", data->beat, data->counter); if (data->beat > 1000) { data->beat -= 1000; } else if (data->beat <= 1000 && data->beat > 200) { data->beat -= 100; } else if (data->beat <= 200 && data->beat > 100) { if (!data->counter--) { data->counter = 5; data->beat -= 100; } } else if (data->beat <= 100 && data->beat > 10) { if (!data->counter--) { data->counter = 10; data->beat -= 10; if (data->beat == 10) { data->counter = 200; } } } else { if (!data->counter--) { data->counter = 5; data->beat--; } } if (!data->beat) { printf("beeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeep you're dead!\n"); return; } data->heartbeat_timer = NULL; status = ftdm_sched_timer(data->sched, "heartbeat", data->beat, data->callback, data, &data->heartbeat_timer); if (status != FTDM_SUCCESS) { fprintf(stderr, "Error creating heartbeat timer\n"); running = 0; return; } }
void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event) { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); int16_t suId = sngisdn_event->suId; uint32_t suInstId = sngisdn_event->suInstId; uint32_t spInstId = sngisdn_event->spInstId; sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info; ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan; StaEvnt *staEvnt = &sngisdn_event->event.staEvnt; uint8_t call_state = 0; if (staEvnt->callSte.eh.pres && staEvnt->callSte.callGlblSte.pres) { call_state = staEvnt->callSte.callGlblSte.val; } ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Processing STATUS CONFIRM (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE), "State change flag pending\n"); if (staEvnt->causeDgn[0].eh.pres && staEvnt->causeDgn[0].causeVal.pres) { if (staEvnt->callSte.eh.pres && staEvnt->callSte.callGlblSte.pres) { call_state = staEvnt->callSte.callGlblSte.val; } else { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Received STATUS without call state\n"); ISDN_FUNC_TRACE_EXIT(__FUNCTION__); return; } switch (staEvnt->causeDgn[0].causeVal.val) { case FTDM_CAUSE_RESPONSE_TO_STATUS_ENQUIRY: ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Status Check OK:%d", call_state); ISDN_FUNC_TRACE_EXIT(__FUNCTION__); return; case FTDM_CAUSE_WRONG_CALL_STATE: ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Message incompatible with call state (call_state:%d channel-state:%s cause:%d) (suId:%u suInstId:%u spInstId:%u)\n", call_state, ftdm_channel_state2str(ftdmchan->state), staEvnt->causeDgn[0].causeVal.val, suId, suInstId, spInstId); break; case FTDM_CAUSE_RECOVERY_ON_TIMER_EXPIRE: ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Recovery on timer expire (call_state:%d channel-state:%s cause:%d) (suId:%u suInstId:%u spInstId:%u)\n", call_state, ftdm_channel_state2str(ftdmchan->state), staEvnt->causeDgn[0].causeVal.val, suId, suInstId, spInstId); break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "STATUS CONFIRM (call_state:%d channel-state:%s cause:%d) (suId:%u suInstId:%u spInstId:%u)\n", call_state, ftdm_channel_state2str(ftdmchan->state), staEvnt->causeDgn[0].causeVal.val, suId, suInstId, spInstId); break; } /* Section 4.3.30 from INT Interface - Service Definition */ ftdmchan->caller_data.hangup_cause = staEvnt->causeDgn[0].causeVal.val; switch(call_state) { /* Sere ITU-T Q931 for definition of call states */ case 0: /* Remote switch thinks there are no calls on this channel */ switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_COLLECT: case FTDM_CHANNEL_STATE_DIALING: case FTDM_CHANNEL_STATE_UP: sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_ABORT); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); break; case FTDM_CHANNEL_STATE_TERMINATING: /* We are in the process of clearing local states, just make sure we will not send any messages to remote switch */ sngisdn_set_flag(sngisdn_info, FLAG_REMOTE_ABORT); break; case FTDM_CHANNEL_STATE_HANGUP: /* This cannot happen, state_advance always sets ftdmchan to STATE_HANGUP_COMPLETE when in STATE_HANGUP and we called check_for_state_change earlier so something is very wrong here!!! */ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "How can we we in FTDM_CHANNEL_STATE_HANGUP after checking for state change?\n"); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); break; case FTDM_CHANNEL_STATE_HANGUP_COMPLETE: /* We were waiting for remote switch to send RELEASE COMPLETE but this will not happen, so just clear local state */ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); break; case FTDM_CHANNEL_STATE_DOWN: /* If our local state is down as well, then there is nothing to do */ break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state)); break; } break; case 1: switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_UP: /* Remote side is still waiting for our CONNECT message */ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { ftdm_sched_timer(((sngisdn_span_data_t*)ftdmchan->span->signal_data)->sched, "delayed_connect", 1, sngisdn_delayed_connect, (void*) sngisdn_info, NULL); break; } /* Fall-through */ default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state)); break; } break; case 2: /* overlap sending/receiving */ switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_COLLECT: /* T302 Timeout reached */ /* Send the call to user, and see if they accept it */ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "T302 Timer expired, proceeding with call\n"); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); break; case FTDM_CHANNEL_STATE_PROGRESS: case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Remote switch expecting OVERLAP receive, but we are already PROCEEDING\n"); sngisdn_snd_disconnect(ftdmchan); break; case FTDM_CHANNEL_STATE_DOWN: case FTDM_CHANNEL_STATE_HANGUP_COMPLETE: /* We hung up locally, but remote switch doesn't know send disconnect again*/ sngisdn_snd_disconnect(ftdmchan); break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state)); break; } break; case 3: switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_PROGRESS: /* T310 timer has expired */ ftdmchan->caller_data.hangup_cause = staEvnt->causeDgn[0].causeVal.val; ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "T310 Timer expired, hanging up call\n"); sngisdn_set_flag(sngisdn_info, FLAG_SEND_DISC); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); break; case FTDM_CHANNEL_STATE_UP: /* Remote side is still waiting for our CONNECT message */ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { ftdm_sched_timer(((sngisdn_span_data_t*)ftdmchan->span->signal_data)->sched, "delayed_connect", 1, sngisdn_delayed_connect, (void*) sngisdn_info, NULL); break; } /* Fall-through */ default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state)); break; } break; case 8: /* Remote switch is in "Connect Request state" */ switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_UP: /* This is ok. We sent a Connect, and we are waiting for a connect ack */ /* Do nothing */ break; case FTDM_CHANNEL_STATE_HANGUP_COMPLETE: /* We hung up locally, but remote switch doesn't know send disconnect again*/ sngisdn_snd_disconnect(ftdmchan); break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state)); break; } break; case 9: /* Remote switch is in "Incoming call proceeding" state */ switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_PROGRESS: case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: case FTDM_CHANNEL_STATE_GET_CALLERID: /* Do nothing */ break; case FTDM_CHANNEL_STATE_UP: /* Remote switch missed our CONNECT message, re-send */ ftdm_sched_timer(((sngisdn_span_data_t*)ftdmchan->span->signal_data)->sched, "delayed_connect", 1, sngisdn_delayed_connect, (void*) sngisdn_info, NULL); break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state)); break; } break; case 10: /* Remote switch is in active state */ switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_UP: /* This is ok, they are in active state and we are in active state */ /* Do nothing */ break; case FTDM_CHANNEL_STATE_HANGUP_COMPLETE: /* We sent a disconnect message, but remote side missed it ? */ ftdm_sched_timer(((sngisdn_span_data_t*)ftdmchan->span->signal_data)->sched, "delayed_disconnect", 1, sngisdn_delayed_disconnect, (void*) sngisdn_info, NULL); break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state)); break; } break; case 22: switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_UP: /* Stack is in the process of clearing the call*/ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); break; case FTDM_CHANNEL_STATE_HANGUP_COMPLETE: /* Do nothing as we will get a RELEASE COMPLETE */ break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state)); //ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); break; } default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state)); //ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); break; } } ISDN_FUNC_TRACE_EXIT(__FUNCTION__); return; }
/* Remote side transmit a SETUP */ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); int16_t suId = sngisdn_event->suId; uint32_t suInstId = sngisdn_event->suInstId; uint32_t spInstId = sngisdn_event->spInstId; int16_t dChan = sngisdn_event->dChan; uint8_t ces = sngisdn_event->ces; sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info; ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan; sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; ConEvnt *conEvnt = &sngisdn_event->event.conEvnt; ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE), "State change flag pending\n"); ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_DEBUG, "Processing SETUP (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_DOWN: /* Proper state to receive a SETUP */ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE) || ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Received SETUP but channel is in USE, saving call for later processing\n"); /* the flag the channel as having a collision */ sngisdn_set_flag(sngisdn_info, FLAG_GLARE); /* save the SETUP for processing once the channel has gone to DOWN */ memcpy(&sngisdn_info->glare.setup, conEvnt, sizeof(*conEvnt)); sngisdn_info->glare.suId = suId; sngisdn_info->glare.suInstId = suInstId; /* Do not generate a suInstId now, we will generate when glared call gets extracted */ sngisdn_info->glare.spInstId = spInstId; sngisdn_info->glare.dChan = dChan; sngisdn_info->glare.ces = ces; break; } sngisdn_info->suInstId = get_unique_suInstId(suId); sngisdn_info->spInstId = spInstId; /* If this is a glared call that was previously saved, we moved all the info to the current call, so clear the glared saved data */ if (sngisdn_info->glare.spInstId == spInstId) { clear_call_glare_data(sngisdn_info); } ftdm_mutex_lock(g_sngisdn_data.ccs[suId].mutex); g_sngisdn_data.ccs[suId].active_suInstIds[sngisdn_info->suInstId] = sngisdn_info; ftdm_mutex_unlock(g_sngisdn_data.ccs[suId].mutex); ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND); if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP && signal_data->signalling == SNGISDN_SIGNALING_NET) { sngisdn_info->ces = ces; } /* try to open the channel */ if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to open channel"); sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_REL); ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_TEMPORARY_FAILURE; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); break; } #if 0 /* Export ftdmchan variables here if we need to */ ftdm_channel_add_var(ftdmchan, "isdn_specific_var", "1"); ftdm_channel_add_var(ftdmchan, "isdn_crap", "morecrap"); ftdm_channel_add_var(ftdmchan, "isdn_stuff", "s"); ftdm_channel_add_var(ftdmchan, "isdn_d", "asdsadasdasdsad"); #endif /* Fill in call information */ cpy_calling_num_from_stack(&ftdmchan->caller_data, &conEvnt->cgPtyNmb); cpy_called_num_from_stack(&ftdmchan->caller_data, &conEvnt->cdPtyNmb); cpy_calling_name_from_stack(&ftdmchan->caller_data, &conEvnt->display); if (conEvnt->bearCap[0].eh.pres) { ftdmchan->caller_data.bearer_layer1 = sngisdn_get_infoTranCap_from_stack(conEvnt->bearCap[0].usrInfoLyr1Prot.val); ftdmchan->caller_data.bearer_capability = sngisdn_get_infoTranCap_from_stack(conEvnt->bearCap[0].infoTranCap.val); } if (signal_data->switchtype == SNGISDN_SWITCH_NI2) { if (conEvnt->shift11.eh.pres && conEvnt->ni2OctStr.eh.pres) { if (conEvnt->ni2OctStr.str.len == 4 && conEvnt->ni2OctStr.str.val[0] == 0x37) { snprintf(ftdmchan->caller_data.aniII, 5, "%.2d", conEvnt->ni2OctStr.str.val[3]); } } if (signal_data->facility == SNGISDN_OPT_TRUE && conEvnt->facilityStr.eh.pres) { /* Verify whether the Caller Name will come in a subsequent FACILITY message */ uint16_t ret_val; char retrieved_str[255]; ret_val = sng_isdn_retrieve_facility_caller_name(conEvnt->facilityStr.facilityStr.val, conEvnt->facilityStr.facilityStr.len, retrieved_str); /* return values for "sng_isdn_retrieve_facility_information_following": If there will be no information following, or fails to decode IE, returns -1 If there will be no information following, but current FACILITY IE contains a caller name, returns 0 If there will be information following, returns 1 */ if (ret_val == 1) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Expecting Caller name in FACILITY\n"); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_GET_CALLERID); /* Launch timer in case we never get a FACILITY msg */ if (signal_data->facility_timeout) { ftdm_sched_timer(signal_data->sched, "facility_timeout", signal_data->facility_timeout, sngisdn_facility_timeout, (void*) sngisdn_info, &sngisdn_info->timers[SNGISDN_TIMER_FACILITY]); } break; } else if (ret_val == 0) { strcpy(ftdmchan->caller_data.cid_name, retrieved_str); } } } if (signal_data->overlap_dial == SNGISDN_OPT_TRUE && !conEvnt->sndCmplt.eh.pres) { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT); } else { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); } break; case FTDM_CHANNEL_STATE_TERMINATING: ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Processing SETUP in TERMINATING state, saving SETUP info for later processing\n"); ftdm_assert(!sngisdn_test_flag(sngisdn_info, FLAG_GLARE), "Trying to save GLARE info, but we already had a glare\n"); sngisdn_set_flag(sngisdn_info, FLAG_GLARE); /* save the SETUP for processing once the channel has gone to DOWN */ memcpy(&sngisdn_info->glare.setup, conEvnt, sizeof(*conEvnt)); sngisdn_info->glare.suId = suId; sngisdn_info->glare.suInstId = suInstId; /* Do not generate a suInstId now, we will generate when glared call gets extracted */ sngisdn_info->glare.spInstId = spInstId; sngisdn_info->glare.dChan = dChan; sngisdn_info->glare.ces = ces; break; case FTDM_CHANNEL_STATE_DIALING: /* glare */ if (signal_data->signalling == SNGISDN_SIGNALING_NET) { /* Save inbound call info so we can send a RELEASE when this channel goes to a different state */ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Processing SETUP in DIALING state, rejecting inbound call\n"); sngisdn_set_flag(sngisdn_info, FLAG_DELAYED_REL); sngisdn_info->glare.suId = suId; sngisdn_info->glare.suInstId = get_unique_suInstId(suId); sngisdn_info->glare.spInstId = spInstId; sngisdn_info->glare.dChan = dChan; sngisdn_info->glare.ces = ces; ftdmchan->caller_data.hangup_cause = 0x2C; /* Channel requested not available */ ftdm_sched_timer(signal_data->sched, "delayed_release", 1, sngisdn_delayed_release, (void*) sngisdn_info, NULL); } else { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Processing SETUP in DIALING state, saving SETUP info for later processing\n"); /* the flag the channel as having a collision */ ftdm_assert(!sngisdn_test_flag(sngisdn_info, FLAG_GLARE), "Trying to save GLARE info, but we already had a glare"); sngisdn_set_flag(sngisdn_info, FLAG_GLARE); /* save the SETUP for processing once the channel has gone to DOWN */ memcpy(&sngisdn_info->glare.setup, conEvnt, sizeof(*conEvnt)); sngisdn_info->glare.suId = suId; sngisdn_info->glare.suInstId = suInstId; /* Do not generate a suInstId now, we will generate when glared call gets extracted */ sngisdn_info->glare.spInstId = spInstId; sngisdn_info->glare.dChan = dChan; sngisdn_info->glare.ces = ces; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); } break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Processing SETUP in an invalid state (%s)\n", ftdm_channel_state2str(ftdmchan->state)); break; } ISDN_FUNC_TRACE_EXIT(__FUNCTION__); return; }
static ftdm_status_t att_courtesy_vru(ftdm_channel_t *ftdmchan, sngisdn_transfer_type_t type, char* args) { char dtmf_digits[64]; ftdm_status_t status = FTDM_FAIL; sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data; sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; char *p = args; uint8_t forced_answer = 0; switch (signal_data->switchtype) { case SNGISDN_SWITCH_5ESS: case SNGISDN_SWITCH_4ESS: break; default: ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "AT&T Courtesy Transfer not supported for switchtype\n"); return FTDM_FAIL; } while (!ftdm_strlen_zero(p)) { if (!isdigit(*p) && *p != 'w' && *p != 'W') { ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Cannot transfer to non-numeric number:%s\n", args); return FTDM_FAIL; } p++; } ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Performing AT&T Courtesy Transfer-VRU%s to %s\n", (type == SNGISDN_TRANSFER_ATT_COURTESY_VRU_DATA) ?"--data" : "", args); sprintf(dtmf_digits, "*8w%s", args); ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending digits %s\n", dtmf_digits); switch (ftdmchan->last_state) { case FTDM_CHANNEL_STATE_PROCEED: case FTDM_CHANNEL_STATE_PROGRESS: case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: /* Call has to be in answered state - so send a CONNECT message if we did not answer this call yet */ forced_answer++; sngisdn_snd_connect(ftdmchan); /* fall-through */ case FTDM_CHANNEL_STATE_UP: memset(&sngisdn_info->transfer_data.tdata.att_courtesy_vru.dtmf_digits, 0, sizeof(sngisdn_info->transfer_data.tdata.att_courtesy_vru.dtmf_digits)); sngisdn_info->transfer_data.type = type; /* We will be polling the channel for IO so that we can receive the DTMF events, * Disable user RX otherwise it is a race between who calls channel_read */ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_RX_DISABLED); ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_DTMF_DETECT, NULL); ftdm_channel_command(ftdmchan, FTDM_COMMAND_SEND_DTMF, dtmf_digits); if (type == SNGISDN_TRANSFER_ATT_COURTESY_VRU_DATA) { /* We need to save transfer data, so we can send it in the disconnect msg */ const char *val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "transfer_data"); if (ftdm_strlen_zero(val)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Cannot perform data transfer because transfer_data variable is not set\n"); goto done; } if (strlen(val) > COURTESY_TRANSFER_MAX_DATA_SIZE) { ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Data exceeds max size (len:%"FTDM_SIZE_FMT" max:%d), cannot perform transfer\n", strlen(val), COURTESY_TRANSFER_MAX_DATA_SIZE); goto done; } memcpy(sngisdn_info->transfer_data.tdata.att_courtesy_vru.data, val, strlen(val)); } ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP); if (forced_answer) { /* Notify the user that we answered the call */ sngisdn_send_signal(sngisdn_info, FTDM_SIGEVENT_UP); } if (signal_data->transfer_timeout) { ftdm_sched_timer(((sngisdn_span_data_t*)ftdmchan->span->signal_data)->sched, "courtesy_transfer_timeout", signal_data->transfer_timeout, att_courtesy_transfer_timeout, (void*) sngisdn_info, &sngisdn_info->timers[SNGISDN_CHAN_TIMER_ATT_TRANSFER]); } status = FTDM_SUCCESS; break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Cannot perform transfer in state %s\n", ftdm_channel_state2str(ftdmchan->state)); break; } done: return status; }