mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-02-18 23:59:07 +00:00
577 lines
16 KiB
C
Executable File
577 lines
16 KiB
C
Executable File
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "cpr.h"
|
|
#include "cpr_in.h"
|
|
#include "cpr_stdlib.h"
|
|
#include "cpr_ipc.h"
|
|
#include "phntask.h"
|
|
#include <stdarg.h>
|
|
#include "configmgr.h"
|
|
#include "debug.h"
|
|
#include "config.h"
|
|
#include "vcm.h"
|
|
#include "dialplan.h"
|
|
#include "debug.h"
|
|
#include "phone_debug.h"
|
|
#include "CCProvider.h"
|
|
#include "ccsip_task.h"
|
|
#include "gsm.h"
|
|
#include "misc_apps_task.h"
|
|
#include "plat_api.h"
|
|
#include "ccapp_task.h"
|
|
|
|
#include "phone_platform_constants.h"
|
|
/** The following defines are used to tune the total memory that pSIPCC
|
|
* allocates and uses. */
|
|
/** Block size for emulated heap space, i.e. 1kB */
|
|
#define BLK_SZ 1024
|
|
|
|
/** 5 MB Heap Based on 0.5 MB initial use + 4 MB for calls (20K * 200) + 0.5 MB misc */
|
|
/** The number of supported blocks for the emulated heap space */
|
|
#define MEM_BASE_BLK 500 //500 blocks, ~ 0.5M
|
|
#define MEM_MISC_BLK 500 //500 blocks, ~ 0.5M
|
|
/** Size of the emulated heap space. This is the value passed to the memory
|
|
* management pre-init procedure. The total memory allocated is
|
|
* "PRIVATE_SYS_MEM_SIZE + 2*64" where the additional numbers are for a gaurd
|
|
* band. */
|
|
#define MEM_PER_CALL_BLK 20 //20 block, ~20k
|
|
#define PRIVATE_SYS_MEM_SIZE ((MEM_BASE_BLK + MEM_MISC_BLK + (MEM_PER_CALL_BLK) * MAX_CALLS) * BLK_SZ)
|
|
|
|
// used in early init code where config has not been setup
|
|
const boolean gHardCodeSDPMode = TRUE;
|
|
boolean gStopTickTask = FALSE;
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
* Local definitions
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
#define GSMSTKSZ 61440
|
|
|
|
/*
|
|
* CNU thread queue sizes.
|
|
*
|
|
* On CNU, the message queue size can hold up to 31 entries only.
|
|
* This is too small for a phone that can support the MAX_CALLS that
|
|
* is close to or higher than 31 calls simultaneously. In a scenario when
|
|
* the number of active calls on the phone reaches its MAC_CALLS then
|
|
* there can be a potential MAX_CALLS that is great ther than 31 events on
|
|
* a queue to GSM or SIP thread.
|
|
*
|
|
* One known scenario is a 7970 phone having 50 held calls where all
|
|
* calls are not from the same CCM that this phone registers with but
|
|
* still within the same cluster. If that CCM is restarted, the CCM that
|
|
* this phone registers with will terminate these calls on the phone by
|
|
* sending BYEs, SUBSCRIBE (to terminate) DTMF digi collection and etc. to
|
|
* all these calls very quickly together. Handling these SIP messages
|
|
* can generate many internal events between SIP and GSM threads including
|
|
* events that are sent to self (such as GSM which includes applications
|
|
* that runs as part of GSM). The amount of the events posted on the queues
|
|
* during this time can be far exceeding than 31 and MAX_CALLS entries.
|
|
*
|
|
* The followings define queue sizes for GSM, SIP and the other threads.
|
|
* The GSM's queue size is defined to be larger than SIP's queue size to
|
|
* account for self sending event. The formular below is based on the
|
|
* testing with the above scenario and with 8-3-x phone load. The maximum
|
|
* queue depth observed for GSM under
|
|
* this condition is 129 entries and the maximum queue depth of
|
|
* SIP under the same condition is about 67 entries. Therefore, the queue
|
|
* depth of GSM thread is given to 3 times MAX_CALLS (or 153) and
|
|
* 2 times (or 102) for SIP thread for 7970 case.
|
|
*
|
|
*/
|
|
#define GSMQSZ (MAX_CALLS*3) /* GSM message queue size */
|
|
#define SIPQSZ (MAX_CALLS*2) /* SIP message queue size */
|
|
#define DEFQSZ 0 /* default message queue size */
|
|
#define DEFAPPQSZ MAX_REG_LINES
|
|
|
|
/*--------------------------------------------------------------------------
|
|
* Global data
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
|
|
cprMsgQueue_t ccapp_msgq;
|
|
cprThread_t ccapp_thread;
|
|
|
|
cprMsgQueue_t sip_msgq;
|
|
cprThread_t sip_thread;
|
|
#ifdef NO_SOCKET_POLLING
|
|
cprThread_t sip_msgqwait_thread;
|
|
#endif
|
|
|
|
cprMsgQueue_t gsm_msgq;
|
|
cprThread_t gsm_thread;
|
|
|
|
cprMsgQueue_t misc_app_msgq;
|
|
cprThread_t misc_app_thread;
|
|
|
|
#ifdef JINDO_DEBUG_SUPPORTED
|
|
cprMsgQueue_t debug_msgq;
|
|
cprThread_t debug_thread;
|
|
#endif
|
|
|
|
#ifdef EXTERNAL_TICK_REQUIRED
|
|
cprMsgQueue_t ticker_msgq;
|
|
cprThread_t ticker_thread;
|
|
#endif
|
|
|
|
/* Platform initialized flag */
|
|
boolean platform_initialized = FALSE;
|
|
|
|
static int thread_init(void);
|
|
|
|
/*--------------------------------------------------------------------------
|
|
* External data references
|
|
* -------------------------------------------------------------------------
|
|
*/
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
* External function prototypes
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
extern void gsm_set_initialized(void);
|
|
extern void vcm_init(void);
|
|
extern void dp_init(void *);
|
|
extern cprBuffer_t SIPTaskGetBuffer(uint16_t size);
|
|
|
|
extern void sip_platform_task_loop(void *arg);
|
|
#ifdef NO_SOCKET_POLLING
|
|
extern void sip_platform_task_msgqwait(void *arg);
|
|
#endif
|
|
extern void GSMTask(void *);
|
|
#ifndef VENDOR_BUILD
|
|
extern void debug_task(void *);
|
|
#endif
|
|
extern void MiscAppTask(void *);
|
|
extern void cpr_timer_tick(void);
|
|
|
|
extern void cprTimerSystemInit(void);
|
|
extern int32_t ui_clear_mwi(int32_t argc, const char *argv[]);
|
|
void gsm_shutdown(void);
|
|
void dp_shutdown(void);
|
|
void MiscAppTaskShutdown(void);
|
|
void CCAppShutdown(void);
|
|
cprBuffer_t gsm_get_buffer (uint16_t size);
|
|
|
|
|
|
|
|
|
|
/*--------------------------------------------------------------------------
|
|
* Local scope function prototypes
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
#ifdef EXTERNAL_TICK_REQUIRED
|
|
int TickerTask(void *);
|
|
#endif
|
|
|
|
void send_protocol_config_msg(void);
|
|
|
|
/**
|
|
* ccMemInit()
|
|
*/
|
|
extern
|
|
int ccMemInit(size_t size) {
|
|
return CPR_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* ccPreInit
|
|
*
|
|
* Initialization routine to call before any application level
|
|
* code initializes.
|
|
*
|
|
* Parameters: None
|
|
*
|
|
* Return Value: CPR_SUCCESS or CPR_FAILURE
|
|
*/
|
|
|
|
int
|
|
ccPreInit ()
|
|
{
|
|
static boolean ccPreInit_called = FALSE;
|
|
|
|
if (ccPreInit_called == FALSE) {
|
|
ccPreInit_called = TRUE;
|
|
//Initializes the memory first
|
|
ccMemInit(PRIVATE_SYS_MEM_SIZE);
|
|
cprPreInit();
|
|
}
|
|
|
|
return CPR_SUCCESS;
|
|
}
|
|
|
|
int
|
|
ccInit ()
|
|
{
|
|
|
|
TNP_DEBUG(DEB_F_PREFIX"started init of SIP call control\n", DEB_F_PREFIX_ARGS(SIP_CC_INIT, "ccInit"));
|
|
|
|
platInit();
|
|
|
|
strlib_init();
|
|
|
|
/*
|
|
* below should move to cprPreInit. keep it here until then
|
|
*/
|
|
#ifdef _WIN32
|
|
cprTimerSystemInit();
|
|
#endif
|
|
|
|
/* Initialize threads, queues etc. */
|
|
(void) thread_init();
|
|
|
|
platform_initialized = TRUE;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
thread_init ()
|
|
{
|
|
gStopTickTask = FALSE;
|
|
/*
|
|
* This will have already been called for CPR CNU code,
|
|
* but may be called here for Windows emulation.
|
|
*/
|
|
(void) cprPreInit();
|
|
|
|
|
|
PHNChangeState(STATE_FILE_CFG);
|
|
|
|
/* initialize message queues */
|
|
sip_msgq = cprCreateMessageQueue("SIPQ", SIPQSZ);
|
|
gsm_msgq = cprCreateMessageQueue("GSMQ", GSMQSZ);
|
|
|
|
if (FALSE == gHardCodeSDPMode) {
|
|
misc_app_msgq = cprCreateMessageQueue("MISCAPPQ", DEFQSZ);
|
|
}
|
|
ccapp_msgq = cprCreateMessageQueue("CCAPPQ", DEFQSZ);
|
|
#ifdef JINDO_DEBUG_SUPPORTED
|
|
debug_msgq = cprCreateMessageQueue("DEBUGAPPQ", DEFQSZ);
|
|
#endif
|
|
#ifdef EXTERNAL_TICK_REQUIRED
|
|
ticker_msgq = cprCreateMessageQueue("Ticker", DEFQSZ);
|
|
#endif
|
|
|
|
|
|
/*
|
|
* Initialize the command parser and debug infrastructure
|
|
*/
|
|
debugInit();
|
|
|
|
/* create threads */
|
|
ccapp_thread = cprCreateThread("CCAPP Task",
|
|
(cprThreadStartRoutine) CCApp_task,
|
|
GSMSTKSZ, CCPROVIDER_THREAD_RELATIVE_PRIORITY /* pri */, ccapp_msgq);
|
|
if (ccapp_thread == NULL) {
|
|
err_msg("failed to create CCAPP task \n");
|
|
}
|
|
|
|
#ifdef JINDO_DEBUG_SUPPORTED
|
|
#ifndef VENDOR_BUILD
|
|
debug_thread = cprCreateThread("Debug Task",
|
|
(cprThreadStartRoutine) debug_task, STKSZ,
|
|
0 /*pri */ , debug_msgq);
|
|
|
|
if (debug_thread == NULL) {
|
|
err_msg("failed to create debug task\n");
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
/* SIP main thread */
|
|
sip_thread = cprCreateThread("SIPStack task",
|
|
(cprThreadStartRoutine) sip_platform_task_loop,
|
|
STKSZ, SIP_THREAD_RELATIVE_PRIORITY /* pri */, sip_msgq);
|
|
if (sip_thread == NULL) {
|
|
err_msg("failed to create sip task \n");
|
|
}
|
|
|
|
#ifdef NO_SOCKET_POLLING
|
|
/* SIP message wait queue task */
|
|
sip_msgqwait_thread = cprCreateThread("SIP MsgQueueWait task",
|
|
(cprThreadStartRoutine)
|
|
sip_platform_task_msgqwait,
|
|
STKSZ, SIP_THREAD_RELATIVE_PRIORITY /* pri */, sip_msgq);
|
|
if (sip_msgqwait_thread == NULL) {
|
|
err_msg("failed to create sip message queue wait task\n");
|
|
}
|
|
#endif
|
|
|
|
gsm_thread = cprCreateThread("GSM Task",
|
|
(cprThreadStartRoutine) GSMTask,
|
|
GSMSTKSZ, GSM_THREAD_RELATIVE_PRIORITY /* pri */, gsm_msgq);
|
|
if (gsm_thread == NULL) {
|
|
err_msg("failed to create gsm task \n");
|
|
}
|
|
|
|
if (FALSE == gHardCodeSDPMode) {
|
|
misc_app_thread = cprCreateThread("MiscApp Task",
|
|
(cprThreadStartRoutine) MiscAppTask,
|
|
STKSZ, 0 /* pri */, misc_app_msgq);
|
|
if (misc_app_thread == NULL) {
|
|
err_msg("failed to create MiscApp task \n");
|
|
}
|
|
}
|
|
|
|
#ifdef EXTERNAL_TICK_REQUIRED
|
|
ticker_thread = cprCreateThread("Ticker task",
|
|
(cprThreadStartRoutine) TickerTask,
|
|
STKSZ, 0, ticker_msgq);
|
|
if (ticker_thread == NULL) {
|
|
err_msg("failed to create ticker task \n");
|
|
}
|
|
#endif
|
|
|
|
/* Associate the threads with the message queues */
|
|
(void) cprSetMessageQueueThread(sip_msgq, sip_thread);
|
|
(void) cprSetMessageQueueThread(gsm_msgq, gsm_thread);
|
|
|
|
if (FALSE == gHardCodeSDPMode) {
|
|
(void) cprSetMessageQueueThread(misc_app_msgq, misc_app_thread);
|
|
}
|
|
|
|
(void) cprSetMessageQueueThread(ccapp_msgq, ccapp_thread);
|
|
#ifdef JINDO_DEBUG_SUPPORTED
|
|
(void) cprSetMessageQueueThread(debug_msgq, debug_thread);
|
|
#endif
|
|
#ifdef EXTERNAL_TICK_REQUIRED
|
|
(void) cprSetMessageQueueThread(ticker_msgq, ticker_thread);
|
|
#endif
|
|
|
|
/*
|
|
* initialize debugs of other modules.
|
|
*
|
|
* dp_init needs the gsm_msgq id. This
|
|
* is set in a global variable by the
|
|
* GSM task running. However due to timing
|
|
* issues dp_init is sometimes run before
|
|
* the GSM task has set this variable resulting
|
|
* in a NULL msgqueue ptr being passed to CPR
|
|
* which returns an error and does not create
|
|
* the dialplan timer. Thus pass is the same
|
|
* data to dp_init that is passed into the
|
|
* cprCreateThread call for GSM above.
|
|
*/
|
|
config_init();
|
|
vcmInit();
|
|
dp_init(gsm_msgq);
|
|
|
|
if (sip_minimum_config_check() != 0) {
|
|
PHNChangeState(STATE_UNPROVISIONED);
|
|
} else {
|
|
PHNChangeState(STATE_CONNECTED);
|
|
}
|
|
|
|
(void) cprPostInit();
|
|
|
|
if ( vcmGetVideoCodecList(VCM_DSP_FULLDUPLEX) ) {
|
|
cc_media_update_native_video_support(TRUE);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
|
|
#ifdef EXTERNAL_TICK_REQUIRED
|
|
|
|
uint16_t SecTimer = 50;
|
|
|
|
unsigned long timeofday_in_seconds = 0;
|
|
|
|
void
|
|
MAIN0Timer (void)
|
|
{
|
|
if (SecTimer-- == 0) {
|
|
SecTimer = 50;
|
|
timeofday_in_seconds++;
|
|
}
|
|
//gtick +=2;
|
|
cpr_timer_tick();
|
|
}
|
|
|
|
int
|
|
TickerTask (void *a)
|
|
{
|
|
TNP_DEBUG(DEB_F_PREFIX"Ticker Task initialized..\n", DEB_F_PREFIX_ARGS(SIP_CC_INIT, "TickerTask"));
|
|
while (FALSE == gStopTickTask) {
|
|
cprSleep(20);
|
|
MAIN0Timer();
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
void
|
|
send_protocol_config_msg (void)
|
|
{
|
|
const char *fname = "send_protocol_config_msg";
|
|
char *msg;
|
|
|
|
TNP_DEBUG(DEB_F_PREFIX"send TCP_DONE message to sip thread..\n", DEB_F_PREFIX_ARGS(SIP_CC_INIT, fname));
|
|
|
|
msg = (char *) SIPTaskGetBuffer(4);
|
|
if (msg == NULL) {
|
|
TNP_DEBUG(DEB_F_PREFIX"failed to allocate message..\n", DEB_F_PREFIX_ARGS(SIP_CC_INIT, fname));
|
|
return;
|
|
}
|
|
/* send a config done message to the SIP Task */
|
|
if (SIPTaskSendMsg(TCP_PHN_CFG_TCP_DONE, msg, 0, NULL) == CPR_FAILURE) {
|
|
err_msg("%s: notify SIP stack ready failed", fname);
|
|
cpr_free(msg);
|
|
}
|
|
gsm_set_initialized();
|
|
PHNChangeState(STATE_CONNECTED);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
* Function: send_task_unload_msg
|
|
*
|
|
* Description:
|
|
* - send shutdown and thread destroy msg to sip, gsm, ccapp, misc
|
|
* threads
|
|
* Parameters: destination thread
|
|
*
|
|
* Returns: none
|
|
*
|
|
*/
|
|
void
|
|
send_task_unload_msg(cc_srcs_t dest_id)
|
|
{
|
|
const char *fname = "send_task_unload_msg";
|
|
uint16_t len = 4;
|
|
cprBuffer_t msg = gsm_get_buffer(len);
|
|
int sdpmode = 0;
|
|
|
|
config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
|
|
|
|
if (msg == NULL) {
|
|
err_msg("%s: failed to allocate msg cprBuffer_t\n", fname);
|
|
return;
|
|
}
|
|
|
|
DEF_DEBUG(DEB_F_PREFIX"send Unload message to %s task ..\n",
|
|
DEB_F_PREFIX_ARGS(SIP_CC_INIT, fname),
|
|
dest_id == CC_SRC_SIP ? "SIP" :
|
|
dest_id == CC_SRC_GSM ? "GSM" :
|
|
dest_id == CC_SRC_MISC_APP ? "Misc App" :
|
|
dest_id == CC_SRC_CCAPP ? "CCApp" : "Unknown");
|
|
|
|
switch(dest_id) {
|
|
case CC_SRC_SIP:
|
|
{
|
|
/* send this msg so phone can send unRegister msg */
|
|
SIPTaskPostShutdown(SIP_EXTERNAL, CC_CAUSE_SHUTDOWN, "");
|
|
/* allow unRegister msg to sent out and shutdown to complete */
|
|
|
|
if (!sdpmode) {
|
|
cprSleep(2000);
|
|
}
|
|
/* send a unload message to the SIP Task to kill sip thread*/
|
|
msg = SIPTaskGetBuffer(len);
|
|
if (msg == NULL) {
|
|
err_msg("%s:%d: failed to allocate sip msg buffer\n", fname);
|
|
return;
|
|
}
|
|
|
|
if (SIPTaskSendMsg(THREAD_UNLOAD, (cprBuffer_t)msg, len, NULL) == CPR_FAILURE)
|
|
{
|
|
cpr_free(msg);
|
|
err_msg("%s: Unable to send THREAD_UNLOAD msg to sip thread", fname);
|
|
}
|
|
}
|
|
break;
|
|
case CC_SRC_GSM:
|
|
{
|
|
msg = gsm_get_buffer(len);
|
|
if (msg == NULL) {
|
|
err_msg("%s: failed to allocate gsm msg cprBuffer_t\n", fname);
|
|
return;
|
|
}
|
|
if (CPR_FAILURE == gsm_send_msg(THREAD_UNLOAD, msg, len)) {
|
|
err_msg("%s: Unable to send THREAD_UNLOAD msg to gsm thread", fname);
|
|
}
|
|
}
|
|
break;
|
|
case CC_SRC_MISC_APP:
|
|
{
|
|
msg = cpr_malloc(len);
|
|
if (msg == NULL) {
|
|
err_msg("%s: failed to allocate misc msg cprBuffer_t\n", fname);
|
|
return;
|
|
}
|
|
if (CPR_FAILURE == MiscAppTaskSendMsg(THREAD_UNLOAD, msg, len)) {
|
|
err_msg("%s: Unable to send THREAD_UNLOAD msg to Misc App thread", fname);
|
|
}
|
|
}
|
|
break;
|
|
case CC_SRC_CCAPP:
|
|
{
|
|
msg = cpr_malloc(len);
|
|
if (msg == NULL) {
|
|
err_msg("%s: failed to allocate ccapp msg cprBuffer_t\n", fname);
|
|
return;
|
|
}
|
|
if (ccappTaskPostMsg(CCAPP_THREAD_UNLOAD, msg, len, CCAPP_CCPROVIER) == CPR_FAILURE )
|
|
{
|
|
err_msg("%s: Unable to send THREAD_UNLOAD msg to CCapp thread", fname);
|
|
}
|
|
err_msg("%s: send UNLOAD msg to CCapp thread good", fname);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
err_msg("%s: Unknown destination task passed=%d.", fname, dest_id);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Function: ccUnload
|
|
*
|
|
* Description:
|
|
* - deinit portable runtime.
|
|
* - Cleanup call control modules, GSM and SIp Stack
|
|
*
|
|
* Parameters: none
|
|
*
|
|
* Returns: none
|
|
*
|
|
*/
|
|
void
|
|
ccUnload (void)
|
|
{
|
|
static const char fname[] = "ccUnload";
|
|
|
|
DEF_DEBUG(DEB_F_PREFIX"ccUnload called..\n", DEB_F_PREFIX_ARGS(SIP_CC_INIT, fname));
|
|
if (platform_initialized == FALSE)
|
|
{
|
|
TNP_DEBUG(DEB_F_PREFIX"system is not loaded, ignore unload\n", DEB_F_PREFIX_ARGS(SIP_CC_INIT, fname));
|
|
return;
|
|
}
|
|
/*
|
|
* We are going to send an unload msg to each of the thread, which on
|
|
* receiving the msg, will kill itself.
|
|
*/
|
|
send_task_unload_msg(CC_SRC_SIP);
|
|
send_task_unload_msg(CC_SRC_GSM);
|
|
|
|
if (FALSE == gHardCodeSDPMode) {
|
|
send_task_unload_msg(CC_SRC_MISC_APP);
|
|
}
|
|
|
|
send_task_unload_msg(CC_SRC_CCAPP);
|
|
|
|
cprSleep(200);
|
|
|
|
gStopTickTask = TRUE;
|
|
}
|
|
|