FT_DECLARE(const char *) ftdm_channel_get_last_state_str(const ftdm_channel_t *ftdmchan) { const char *state; ftdm_channel_lock(ftdmchan); state = ftdm_channel_state2str(ftdmchan->last_state); ftdm_channel_unlock(ftdmchan); return state; }
FT_DECLARE(int) ftdm_channel_get_last_state(const ftdm_channel_t *ftdmchan) { int last_state; ftdm_channel_lock(ftdmchan); last_state = ftdmchan->last_state; ftdm_channel_unlock(ftdmchan); return last_state; }
static __inline__ void pritap_check_state(ftdm_span_t *span) { if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE)) { uint32_t j; ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE); for(j = 1; j <= span->chan_count; j++) { ftdm_channel_lock(span->channels[j]); ftdm_channel_advance_states(span->channels[j]); ftdm_channel_unlock(span->channels[j]); } } }
static __inline__ ftdm_channel_t *tap_pri_get_fchan(pritap_t *pritap, passive_call_t *pcall, int channel) { ftdm_channel_t *fchan = NULL; int err = 0; int chanpos = PRI_CHANNEL(channel); if (!chanpos || chanpos > pritap->span->chan_count) { ftdm_log(FTDM_LOG_CRIT, "Invalid pri tap channel %d requested in span %s\n", channel, pritap->span->name); return NULL; } fchan = pritap->span->channels[PRI_CHANNEL(channel)]; ftdm_channel_lock(fchan); if (ftdm_test_flag(fchan, FTDM_CHANNEL_INUSE)) { ftdm_log(FTDM_LOG_ERROR, "Channel %d requested in span %s is already in use!\n", channel, pritap->span->name); err = 1; goto done; } if (ftdm_channel_open_chan(fchan) != FTDM_SUCCESS) { ftdm_log(FTDM_LOG_ERROR, "Could not open tap channel %d requested in span %s\n", channel, pritap->span->name); err = 1; goto done; } memset(&fchan->caller_data, 0, sizeof(fchan->caller_data)); ftdm_set_string(fchan->caller_data.cid_num.digits, pcall->callingnum.digits); if (!ftdm_strlen_zero(pcall->callingname)) { ftdm_set_string(fchan->caller_data.cid_name, pcall->callingname); } else { ftdm_set_string(fchan->caller_data.cid_name, pcall->callingnum.digits); } ftdm_set_string(fchan->caller_data.ani.digits, pcall->callingani.digits); ftdm_set_string(fchan->caller_data.dnis.digits, pcall->callednum.digits); done: if (fchan) { ftdm_channel_unlock(fchan); } if (err) { return NULL; } return fchan; }
static ftdm_status_t sngisdn_map_call(sngisdn_span_data_t *signal_data, sngisdn_frame_info_t frame_info, ftdm_channel_t **found) { sngisdn_chan_data_t *sngisdn_info; ftdm_channel_t *ftdmchan = NULL; ftdm_iterator_t *chaniter = NULL; ftdm_iterator_t *curr = NULL; ftdm_status_t status = FTDM_FAIL; uint8_t outbound_call = 0; if ((!frame_info.call_ref_flag && frame_info.dir == FTDM_TRACE_DIR_OUTGOING) || (frame_info.call_ref_flag && frame_info.dir == FTDM_TRACE_DIR_INCOMING)) { /* If this is an outgoing frame and this frame was sent by the originating side of the call (frame_info.call_ref_flag == 0), then this is an outbound call */ outbound_call = 1; } else { outbound_call = 0; } switch (frame_info.msgtype) { case PROT_Q931_MSGTYPE_SETUP: /* We initiated this outgoing call try to match the call reference with our internal call-id*/ if (!frame_info.bchan_no) { /* We were not able to determine the bchannel on this call, so we will not be able to match it anyway */ status = FTDM_FAIL; } chaniter = ftdm_span_get_chan_iterator(signal_data->ftdm_span, NULL); for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) { ftdmchan = (ftdm_channel_t*)(ftdm_iterator_current(curr)); ftdm_channel_lock(ftdmchan); if (outbound_call) { sngisdn_info = (sngisdn_chan_data_t*)ftdmchan->call_data; if (sngisdn_info && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { if (ftdmchan->caller_data.call_id && ftdmchan->physical_chan_id == frame_info.bchan_no) { sngisdn_info->call_ref = frame_info.call_ref; *found = ftdmchan; status = FTDM_SUCCESS; } } } else { if (ftdmchan->physical_chan_id == frame_info.bchan_no) { *found = ftdmchan; status = FTDM_SUCCESS; } } ftdm_channel_unlock(ftdmchan); } ftdm_iterator_free(chaniter); break; case PROT_Q931_MSGTYPE_ALERTING: case PROT_Q931_MSGTYPE_PROCEEDING: case PROT_Q931_MSGTYPE_PROGRESS: case PROT_Q931_MSGTYPE_CONNECT: case PROT_Q931_MSGTYPE_SETUP_ACK: case PROT_Q931_MSGTYPE_CONNECT_ACK: case PROT_Q931_MSGTYPE_USER_INFO: case PROT_Q931_MSGTYPE_DISCONNECT: case PROT_Q931_MSGTYPE_RELEASE: case PROT_Q931_MSGTYPE_RELEASE_ACK: case PROT_Q931_MSGTYPE_RELEASE_COMPLETE: case PROT_Q931_MSGTYPE_FACILITY: case PROT_Q931_MSGTYPE_NOTIFY: case PROT_Q931_MSGTYPE_STATUS_ENQUIRY: case PROT_Q931_MSGTYPE_INFORMATION: case PROT_Q931_MSGTYPE_STATUS: /* Look for an outbound call on that span and and try to match the call-id */ chaniter = ftdm_span_get_chan_iterator(signal_data->ftdm_span, NULL); for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) { ftdmchan = (ftdm_channel_t*)(ftdm_iterator_current(curr)); ftdm_channel_lock(ftdmchan); sngisdn_info = (sngisdn_chan_data_t*)ftdmchan->call_data; if (outbound_call) { if (sngisdn_info && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { if (sngisdn_info->call_ref == frame_info.call_ref) { *found = ftdmchan; status = FTDM_SUCCESS; } } } else { if (sngisdn_info && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { if (sngisdn_info->call_ref && sngisdn_info->call_ref == frame_info.call_ref) { *found = ftdmchan; status = FTDM_SUCCESS; } } } ftdm_channel_unlock(ftdmchan); } ftdm_iterator_free(chaniter); break; default: /* This frame is not call specific, ignore */ break; } if (status == FTDM_SUCCESS) { ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Mapped %s with Call Ref:%04x to call-id:%d\n", get_code_2_str(frame_info.msgtype, dcodQ931MsgTypeTable), frame_info.call_ref, (*found)->caller_data.call_id); } else { /* We could not map this frame to a call-id */ ftdm_log(FTDM_LOG_DEBUG, "Failed to map %s with Call Ref:%04x to local call\n", get_code_2_str(frame_info.msgtype, dcodQ931MsgTypeTable), frame_info.call_ref); } return status; }
static void *ftdm_gsm_run(ftdm_thread_t *me, void *obj) { ftdm_log(FTDM_LOG_INFO,"ftdm_gsm_run\r\n"); ftdm_channel_t *ftdmchan = NULL; ftdm_span_t *span = (ftdm_span_t *) obj; ftdm_gsm_span_data_t *gsm_data = NULL; ftdm_interrupt_t *data_sources[2] = {NULL, NULL}; int waitms = 0; gsm_data = span->signal_data; ftdm_assert_return(gsm_data != NULL, NULL, "No gsm data attached to span\n"); ftdm_log(FTDM_LOG_DEBUG, "GSM monitor thread for span %s started\n", span->name); if (!gsm_data->dchan || ftdm_channel_open_chan(gsm_data->dchan) != FTDM_SUCCESS) { ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to open GSM d-channel of span %s!\n", span->name); gsm_data->dchan = NULL; goto done; } while (ftdm_running()) { wat_span_run(span->span_id); waitms = wat_span_schedule_next(span->span_id); if (waitms > GSM_POLL_INTERVAL_MS) { waitms = GSM_POLL_INTERVAL_MS; } ///////////////////// { ftdm_wait_flag_t flags = FTDM_READ | FTDM_EVENTS; ftdm_status_t status = ftdm_channel_wait(gsm_data->dchan, &flags, waitms); /* double check that this channel has a state change pending */ ftdm_channel_lock(gsm_data->bchan); ftdm_channel_advance_states(gsm_data->bchan); if(FTDM_SUCCESS == status ) { if(flags &FTDM_READ ) { char buffer[1025]; int n = 0, m = 0; memset(buffer, 0, sizeof(buffer)); n = read_channel(gsm_data->dchan, buffer, sizeof(buffer)-1); m = strlen(buffer); wat_span_process_read(span->span_id, buffer, m); #if LOG_SIG_DATA printf("<<======================= incomming data len = %d, %s\r\n", n, buffer); #endif } } ftdm_channel_advance_states(gsm_data->bchan); ftdm_channel_unlock(gsm_data->bchan); } ftdm_span_trigger_signals(span); } done: if (data_sources[0]) { ftdm_interrupt_destroy(&data_sources[0]); } ftdm_log(FTDM_LOG_DEBUG, "GSM thread ending.\n"); return NULL; }
static void handle_pri_passive_event(pritap_t *pritap, pri_event *e) { passive_call_t *pcall = NULL; passive_call_t *peerpcall = NULL; ftdm_channel_t *fchan = NULL; ftdm_channel_t *peerfchan = NULL; int layer1, transcap = 0; int crv = 0; pritap_t *peertap = pritap->peerspan->signal_data; switch (e->e) { case PRI_EVENT_RING: /* we cannot use ftdm_channel_t because we still dont know which channel will be used * (ie, flexible channel was requested), thus, we need our own list of call references */ crv = tap_pri_get_crv(pritap->pri, e->ring.call); ftdm_log(FTDM_LOG_DEBUG, "Ring on channel %s:%d:%d with callref %d\n", pritap->span->name, PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), crv); pcall = tap_pri_get_pcall_bycrv(pritap, crv); if (pcall) { ftdm_log(FTDM_LOG_WARNING, "There is a call with callref %d already, ignoring duplicated ring event\n", crv); break; } /* Try to get a recycled call (ie, e->ring.call is a call that the PRI stack allocated previously and then * re-used for the next RING event because we did not destroy it fast enough) */ pcall = tap_pri_get_pcall(pritap, e->ring.call); if (!pcall) { /* ok so the call is really not known to us, let's get a new one */ pcall = tap_pri_get_pcall(pritap, NULL); if (!pcall) { ftdm_log(FTDM_LOG_ERROR, "Failed to get a free passive PRI call slot for callref %d, this is a bug!\n", crv); break; } } pcall->callref = e->ring.call; ftdm_set_string(pcall->callingnum.digits, e->ring.callingnum); ftdm_set_string(pcall->callingani.digits, e->ring.callingani); ftdm_set_string(pcall->callednum.digits, e->ring.callednum); ftdm_set_string(pcall->callingname, e->ring.callingname); break; case PRI_EVENT_PROGRESS: crv = tap_pri_get_crv(pritap->pri, e->proceeding.call); ftdm_log(FTDM_LOG_DEBUG, "Progress on channel %s:%d:%d with callref %d\n", pritap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv); break; case PRI_EVENT_PROCEEDING: crv = tap_pri_get_crv(pritap->pri, e->proceeding.call); /* at this point we should know the real b chan that will be used and can therefore proceed to notify about the call, but * only if a couple of call tests are passed first */ ftdm_log(FTDM_LOG_DEBUG, "Proceeding on channel %s:%d:%d with callref %d\n", pritap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv); /* check that we already know about this call in the peer PRI (which was the one receiving the PRI_EVENT_RING event) */ if (!(pcall = tap_pri_get_pcall_bycrv(peertap, crv))) { ftdm_log(FTDM_LOG_DEBUG, "ignoring proceeding in channel %s:%d:%d for callref %d since we don't know about it\n", pritap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv); break; } if (pcall->proceeding) { ftdm_log(FTDM_LOG_DEBUG, "Ignoring duplicated proceeding with callref %d\n", crv); break; } pcall->proceeding = 1; /* This call should not be known to this PRI yet ... */ if ((peerpcall = tap_pri_get_pcall_bycrv(pritap, crv))) { ftdm_log(FTDM_LOG_ERROR, "ignoring proceeding in channel %s:%d:%d for callref %d, dup???\n", pritap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv); break; } /* Check if the call pointer is being recycled */ peerpcall = tap_pri_get_pcall(pritap, e->proceeding.call); if (!peerpcall) { peerpcall = tap_pri_get_pcall(pritap, NULL); if (!peerpcall) { ftdm_log(FTDM_LOG_ERROR, "Failed to get a free peer PRI passive call slot for callref %d in span %s, this is a bug!\n", crv, pritap->span->name); break; } peerpcall->callref = e->proceeding.call; } /* check that the layer 1 and trans capability are supported */ layer1 = pri_get_layer1(peertap->pri, pcall->callref); transcap = pri_get_transcap(peertap->pri, pcall->callref); if (PRI_LAYER_1_ULAW != layer1 && PRI_LAYER_1_ALAW != layer1) { ftdm_log(FTDM_LOG_NOTICE, "Not monitoring callref %d with unsupported layer 1 format %d\n", crv, layer1); break; } if (transcap != PRI_TRANS_CAP_SPEECH && transcap != PRI_TRANS_CAP_3_1K_AUDIO && transcap != PRI_TRANS_CAP_7K_AUDIO) { ftdm_log(FTDM_LOG_NOTICE, "Not monitoring callref %d with unsupported capability %d\n", crv, transcap); break; } fchan = tap_pri_get_fchan(pritap, pcall, e->proceeding.channel); if (!fchan) { ftdm_log(FTDM_LOG_ERROR, "Proceeding requested on odd/unavailable channel %s:%d:%d for callref %d\n", pritap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv); break; } peerfchan = tap_pri_get_fchan(peertap, pcall, e->proceeding.channel); if (!peerfchan) { ftdm_log(FTDM_LOG_ERROR, "Proceeding requested on odd/unavailable channel %s:%d:%d for callref %d\n", peertap->span->name, PRI_SPAN(e->proceeding.channel), PRI_CHANNEL(e->proceeding.channel), crv); break; } pcall->fchan = fchan; peerpcall->fchan = fchan; ftdm_log_chan(fchan, FTDM_LOG_NOTICE, "Starting new tapped call with callref %d\n", crv); ftdm_channel_lock(fchan); fchan->call_data = peerfchan; ftdm_set_state(fchan, FTDM_CHANNEL_STATE_RING); ftdm_channel_unlock(fchan); ftdm_channel_lock(peerfchan); peerfchan->call_data = fchan; ftdm_channel_unlock(peerfchan); break; case PRI_EVENT_ANSWER: crv = tap_pri_get_crv(pritap->pri, e->answer.call); ftdm_log(FTDM_LOG_DEBUG, "Answer on channel %s:%d:%d with callref %d\n", pritap->span->name, PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), crv); if (!(pcall = tap_pri_get_pcall_bycrv(pritap, crv))) { ftdm_log(FTDM_LOG_DEBUG, "ignoring answer in channel %s:%d:%d for callref %d since we don't know about it\n", pritap->span->name, PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->proceeding.channel), crv); break; } if (!pcall->fchan) { ftdm_log(FTDM_LOG_ERROR, "Received answer in channel %s:%d:%d for callref %d but we never got a channel\n", pritap->span->name, PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), crv); break; } ftdm_channel_lock(pcall->fchan); ftdm_log_chan(pcall->fchan, FTDM_LOG_NOTICE, "Tapped call was answered in state %s\n", ftdm_channel_state2str(pcall->fchan->state)); ftdm_set_pflag(pcall->fchan, PRITAP_NETWORK_ANSWER); ftdm_set_state(pcall->fchan, FTDM_CHANNEL_STATE_UP); ftdm_channel_unlock(pcall->fchan); break; case PRI_EVENT_HANGUP_REQ: crv = tap_pri_get_crv(pritap->pri, e->hangup.call); ftdm_log(FTDM_LOG_DEBUG, "Hangup on channel %s:%d:%d with callref %d\n", pritap->span->name, PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), crv); if (!(pcall = tap_pri_get_pcall_bycrv(pritap, crv))) { ftdm_log(FTDM_LOG_DEBUG, "ignoring hangup in channel %s:%d:%d for callref %d since we don't know about it", pritap->span->name, PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), crv); break; } if (pcall->fchan) { fchan = pcall->fchan; ftdm_channel_lock(fchan); if (fchan->state < FTDM_CHANNEL_STATE_TERMINATING) { ftdm_set_state(fchan, FTDM_CHANNEL_STATE_TERMINATING); } pcall->fchan = NULL; /* after this event we're not supposed to need to do anything with the channel anymore */ ftdm_channel_unlock(fchan); } tap_pri_put_pcall(pritap, e->hangup.call); tap_pri_put_pcall(peertap, e->hangup.call); break; case PRI_EVENT_HANGUP_ACK: crv = tap_pri_get_crv(pritap->pri, e->hangup.call); ftdm_log(FTDM_LOG_DEBUG, "Hangup ack on channel %s:%d:%d with callref %d\n", pritap->span->name, PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), crv); tap_pri_put_pcall(pritap, e->hangup.call); tap_pri_put_pcall(peertap, e->hangup.call); break; default: ftdm_log(FTDM_LOG_DEBUG, "Ignoring passive event %s on span %s\n", pri_event2str(e->gen.e), pritap->span->name); break; } }
static ftdm_status_t state_advance(ftdm_channel_t *ftdmchan) { ftdm_status_t status; ftdm_sigmsg_t sig; pritap_t *pritap = ftdmchan->span->signal_data; pritap_t *peer_pritap = pritap->peerspan->signal_data; ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "processing state %s\n", ftdm_channel_state2str(ftdmchan->state)); memset(&sig, 0, sizeof(sig)); sig.chan_id = ftdmchan->chan_id; sig.span_id = ftdmchan->span_id; sig.channel = ftdmchan; ftdm_channel_complete_state(ftdmchan); switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_DOWN: { ftdm_channel_t *fchan = ftdmchan; /* Destroy the peer data first */ if (fchan->call_data) { ftdm_channel_t *peerchan = fchan->call_data; ftdm_channel_t *pchan = peerchan; ftdm_channel_lock(peerchan); pchan->call_data = NULL; pchan->pflags = 0; ftdm_channel_close(&pchan); ftdm_channel_unlock(peerchan); } else { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "No call data?\n"); } ftdmchan->call_data = NULL; ftdmchan->pflags = 0; ftdm_channel_close(&fchan); } break; case FTDM_CHANNEL_STATE_PROGRESS: case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: case FTDM_CHANNEL_STATE_HANGUP: break; case FTDM_CHANNEL_STATE_UP: { if (ftdm_test_pflag(ftdmchan, PRITAP_NETWORK_ANSWER)) { ftdm_clear_pflag(ftdmchan, PRITAP_NETWORK_ANSWER); sig.event_id = FTDM_SIGEVENT_UP; ftdm_span_send_signal(ftdmchan->span, &sig); } } break; case FTDM_CHANNEL_STATE_RING: { sig.event_id = FTDM_SIGEVENT_START; /* The ring interface (where the setup was received) is the peer, since we RING the channel * where PROCEED/PROGRESS is received */ ftdm_sigmsg_add_var(&sig, "pritap_ring_interface", PRITAP_GET_INTERFACE(peer_pritap->iface)); if ((status = ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS)) { ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); } } break; case FTDM_CHANNEL_STATE_TERMINATING: { if (ftdmchan->last_state != FTDM_CHANNEL_STATE_HANGUP) { sig.event_id = FTDM_SIGEVENT_STOP; status = ftdm_span_send_signal(ftdmchan->span, &sig); } ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); } break; default: { ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "ignoring state change from %s to %s\n", ftdm_channel_state2str(ftdmchan->last_state), ftdm_channel_state2str(ftdmchan->state)); } break; } return FTDM_SUCCESS; }