From 55203ed0d72d28df807ea9f8d326e00cd77f5ee4 Mon Sep 17 00:00:00 2001
From: David Yat Sin <dyatsin@sangoma.com>
Date: Fri, 10 Dec 2010 19:14:08 -0500
Subject: [PATCH 1/2] Support for call ID

---
 libs/freetdm/src/ftdm_io.c         | 75 ++++++++++++++++++++++++++----
 libs/freetdm/src/include/freetdm.h |  8 +++-
 2 files changed, 72 insertions(+), 11 deletions(-)

diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c
index eaa25e3da5..78ae3d2b65 100644
--- a/libs/freetdm/src/ftdm_io.c
+++ b/libs/freetdm/src/ftdm_io.c
@@ -57,11 +57,14 @@ struct tm *localtime_r(const time_t *clock, struct tm *result);
 #define SPAN_PENDING_SIGNALS_QUEUE_SIZE 1000
 #define FTDM_READ_TRACE_INDEX 0
 #define FTDM_WRITE_TRACE_INDEX 1
+#define MAX_CALLIDS 6000
 
 ftdm_time_t time_last_throttle_log = 0;
 ftdm_time_t time_current_throttle_log = 0;
 
 static ftdm_iterator_t *get_iterator(ftdm_iterator_type_t type, ftdm_iterator_t *iter);
+static ftdm_status_t ftdm_call_set_call_id(ftdm_caller_data_t *caller_data);
+static ftdm_status_t ftdm_call_clear_call_id(ftdm_caller_data_t *caller_data);
 
 static int time_is_init = 0;
 
@@ -235,6 +238,10 @@ static struct {
 	ftdm_span_t *spans;
 	ftdm_group_t *groups;
 	cpu_monitor_t cpu_monitor;
+	
+	ftdm_caller_data_t *call_ids[MAX_CALLIDS+1];
+	ftdm_mutex_t *call_id_mutex;
+	uint32_t last_call_id;
 } globals;
 
 enum ftdm_enum_cpu_alarm_action_flags
@@ -1896,8 +1903,6 @@ static ftdm_status_t ftdm_channel_reset(ftdm_channel_t *ftdmchan)
 		ftdmchan->dtmf_off = FTDM_DEFAULT_DTMF_OFF;
 	}
 
-	ftdm_call_clear_vars(&ftdmchan->caller_data);
-			
 	memset(ftdmchan->dtmf_hangup_buf, '\0', ftdmchan->span->dtmf_hangup_len);
 
 	if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE)) {
@@ -2483,6 +2488,7 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_place(const char *file, const char
 
 	ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_STATE_CHANGE, 100);
 
+	ftdm_call_set_call_id(&ftdmchan->caller_data);
 	ftdm_channel_unlock(ftdmchan);
 
 	return status;
@@ -2545,9 +2551,6 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan)
 	ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "Null channel can't be done!\n");
 
 	ftdm_mutex_lock(ftdmchan->mutex);
-
-	memset(&ftdmchan->caller_data, 0, sizeof(ftdmchan->caller_data));
-
 	ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_INUSE);
 	ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND);
 	ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_WINK);
@@ -2587,7 +2590,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan)
 		sigmsg.channel = ftdmchan;
 		sigmsg.event_id = FTDM_SIGEVENT_RELEASED;
 		ftdm_span_send_signal(ftdmchan->span, &sigmsg);
-	}
+		ftdm_call_clear_call_id(&ftdmchan->caller_data);
+	}	
 
 	if (ftdmchan->txdrops || ftdmchan->rxdrops) {
 		ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "channel dropped data: txdrops = %d, rxdrops = %d\n", 
@@ -2595,8 +2599,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan)
 	}
 
 	ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "channel done\n");
-
-
+	memset(&ftdmchan->caller_data, 0, sizeof(ftdmchan->caller_data));
 	ftdm_mutex_unlock(ftdmchan->mutex);
 
 	return FTDM_SUCCESS;
@@ -5328,7 +5331,7 @@ static void execute_safety_hangup(void *data)
 FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t *sigmsg)
 {
 	if (sigmsg->channel) {
-		ftdm_mutex_lock(sigmsg->channel->mutex);
+		ftdm_mutex_lock(sigmsg->channel->mutex);		
 	}
 	
 	/* some core things to do on special events */
@@ -5347,6 +5350,7 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t
 
 	case FTDM_SIGEVENT_START:
 		{
+			ftdm_call_set_call_id(&sigmsg->channel->caller_data);
 			ftdm_set_echocancel_call_begin(sigmsg->channel);
 			if (sigmsg->channel->dtmfdbg.requested) {
 				ftdm_channel_command(sigmsg->channel, FTDM_COMMAND_ENABLE_DEBUG_DTMF, NULL);
@@ -5376,7 +5380,10 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t
 		break;	
 
 	}
-	
+
+	if (sigmsg->channel) {
+		sigmsg->call_id = sigmsg->channel->caller_data.call_id;
+	}
 	/* if the signaling module uses a queue for signaling notifications, then enqueue it */
 	if (ftdm_test_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE)) {
 		ftdm_span_queue_signal(span, sigmsg);
@@ -5471,6 +5478,7 @@ static void ftdm_cpu_monitor_stop(void)
 
 FT_DECLARE(ftdm_status_t) ftdm_global_init(void)
 {
+	int i;
 	memset(&globals, 0, sizeof(globals));
 
 	time_init();
@@ -5485,6 +5493,8 @@ FT_DECLARE(ftdm_status_t) ftdm_global_init(void)
 	ftdm_mutex_create(&globals.mutex);
 	ftdm_mutex_create(&globals.span_mutex);
 	ftdm_mutex_create(&globals.group_mutex);
+	ftdm_mutex_create(&globals.call_id_mutex);
+	
 	ftdm_sched_global_init();
 	if (ftdm_sched_create(&globals.timingsched, "freetdm-master") != FTDM_SUCCESS) {
 		ftdm_log(FTDM_LOG_CRIT, "Failed to create master timing schedule context\n");
@@ -5494,6 +5504,9 @@ FT_DECLARE(ftdm_status_t) ftdm_global_init(void)
 		ftdm_log(FTDM_LOG_CRIT, "Failed to run master timing schedule context\n");
 		return FTDM_FAIL;
 	}
+	for(i=0;i<MAX_CALLIDS;i++) {
+		globals.call_ids[i] = NULL;
+	}
 	globals.running = 1;
 	return FTDM_SUCCESS;
 }
@@ -5597,6 +5610,7 @@ FT_DECLARE(ftdm_status_t) ftdm_global_destroy(void)
 	ftdm_mutex_destroy(&globals.mutex);
 	ftdm_mutex_destroy(&globals.span_mutex);
 	ftdm_mutex_destroy(&globals.group_mutex);
+	ftdm_mutex_destroy(&globals.call_id_mutex);
 
 	memset(&globals, 0, sizeof(globals));
 	return FTDM_SUCCESS;
@@ -5955,6 +5969,47 @@ FT_DECLARE(char *) ftdm_channel_get_history_str(const ftdm_channel_t *fchan)
 	return stream.data;
 }
 
+static ftdm_status_t ftdm_call_set_call_id(ftdm_caller_data_t *caller_data)
+{
+	uint32_t current_call_id;
+	ftdm_assert_return(!caller_data->call_id, FTDM_FAIL, "Overwriting non-cleared call-id");
+
+	ftdm_mutex_lock(globals.call_id_mutex);
+	current_call_id = globals.last_call_id;
+
+	do {
+		if (++current_call_id > MAX_CALLIDS) {
+			current_call_id = 1;
+		}
+		if (globals.call_ids[current_call_id] != NULL) {
+			continue;
+		}
+	} while (0);
+
+	globals.last_call_id = current_call_id;
+	caller_data->call_id = current_call_id;
+
+	globals.call_ids[current_call_id] = caller_data;
+	ftdm_mutex_unlock(globals.call_id_mutex);
+	return FTDM_SUCCESS;
+}
+
+static ftdm_status_t ftdm_call_clear_call_id(ftdm_caller_data_t *caller_data)
+{
+	ftdm_assert_return((caller_data->call_id && caller_data->call_id <= MAX_CALLIDS), FTDM_FAIL, "Clearing call with invalid call-id\n");
+	ftdm_mutex_lock(globals.call_id_mutex);
+	if (globals.call_ids[caller_data->call_id]) {
+		caller_data->call_id = 0;
+		globals.call_ids[caller_data->call_id] = NULL;
+	} else {
+		ftdm_log(FTDM_LOG_CRIT, "call-id did not exist %u\n", caller_data->call_id);
+	} 
+	ftdm_mutex_unlock(globals.call_id_mutex);
+	return FTDM_SUCCESS;
+}
+
+
+
 
 /* For Emacs:
  * Local Variables:
diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h
index 4ee6ff5f52..cc32d66bdd 100644
--- a/libs/freetdm/src/include/freetdm.h
+++ b/libs/freetdm/src/include/freetdm.h
@@ -295,6 +295,11 @@ typedef struct ftdm_caller_data {
 	/* user information layer 1 protocol */
 	ftdm_user_layer1_prot_t bearer_layer1;
 	ftdm_variable_container_t variables; /*!<variables attached to this call */
+	/* We need call_id inside caller_data for the user to be able to retrieve 
+	 * the call_id when ftdm_channel_call_place is called. This is the only time
+	 * that the user can use caller_data.call_id to obtain the call_id. The user
+	 * should use the call_id from sigmsg otherwise */
+	uint32_t call_id; /*!< Unique call ID for this call */
 } ftdm_caller_data_t;
 
 /*! \brief Tone type */
@@ -381,9 +386,10 @@ struct ftdm_sigmsg {
 	ftdm_channel_t *channel; /*!< Related channel */
 	uint32_t chan_id; /*!< easy access to chan id */
 	uint32_t span_id; /*!< easy access to span_id */
-	ftdm_signaling_status_t sigstatus; /*!< Signaling status (valid if event_id is FTDM_SIGEVENT_SIGSTATUS_CHANGED) */	
+	ftdm_signaling_status_t sigstatus; /*!< Signaling status (valid if event_id is FTDM_SIGEVENT_SIGSTATUS_CHANGED) */
 	void *raw_data; /*!< Message specific data if any */
 	uint32_t raw_data_len; /*!< Data len in case is needed */
+	uint32_t call_id; /*!< unique call id for this call */
 };
 
 /*! \brief Crash policy 

From f87a32c66a059474f160a9055e7d582c424c152b Mon Sep 17 00:00:00 2001
From: David Yat Sin <dyatsin@sangoma.com>
Date: Mon, 13 Dec 2010 11:29:38 -0500
Subject: [PATCH 2/2] removed unnecessary initialization

---
 libs/freetdm/src/ftdm_io.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c
index 78ae3d2b65..8dd0a2de01 100644
--- a/libs/freetdm/src/ftdm_io.c
+++ b/libs/freetdm/src/ftdm_io.c
@@ -5478,7 +5478,6 @@ static void ftdm_cpu_monitor_stop(void)
 
 FT_DECLARE(ftdm_status_t) ftdm_global_init(void)
 {
-	int i;
 	memset(&globals, 0, sizeof(globals));
 
 	time_init();
@@ -5504,9 +5503,7 @@ FT_DECLARE(ftdm_status_t) ftdm_global_init(void)
 		ftdm_log(FTDM_LOG_CRIT, "Failed to run master timing schedule context\n");
 		return FTDM_FAIL;
 	}
-	for(i=0;i<MAX_CALLIDS;i++) {
-		globals.call_ids[i] = NULL;
-	}
+
 	globals.running = 1;
 	return FTDM_SUCCESS;
 }