mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-07-11 23:01:54 +00:00
3033 lines
110 KiB
C
3033 lines
110 KiB
C
/* 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_types.h"
|
|
#include "cpr_stdio.h"
|
|
#include "cpr_stdlib.h"
|
|
#include "cpr_string.h"
|
|
#include "cpr_socket.h"
|
|
#include "cpr_timers.h"
|
|
#include "cpr_memory.h"
|
|
#include "cpr_in.h"
|
|
#include "cpr_ipc.h"
|
|
#include "phntask.h"
|
|
#include "util_string.h"
|
|
#include "task.h"
|
|
#include "phone.h"
|
|
#include "text_strings.h"
|
|
#include "ccsip_task.h"
|
|
#include "ccsip_core.h"
|
|
#include "ccsip_macros.h"
|
|
#include "ccsip_messaging.h"
|
|
#include "ccsip_sim.h"
|
|
#include "ccsip_platform_udp.h"
|
|
#include "ccsip_platform.h"
|
|
#include "phone_debug.h"
|
|
#include "ccsip_register.h"
|
|
#include "debug.h"
|
|
#include "ccsip_reldev.h"
|
|
#include "ccsip_cc.h"
|
|
#include "gsm.h"
|
|
#include "fim.h"
|
|
#include "ccapi.h"
|
|
#include "lsm.h"
|
|
#include "config.h"
|
|
#include "check_sync.h"
|
|
#include "sip_common_transport.h"
|
|
#include "uiapi.h"
|
|
#include "sip_csps_transport.h"
|
|
#include "sip_common_regmgr.h"
|
|
#include "sip_platform_task.h"
|
|
#include "platform_api.h"
|
|
#include "sip_interface_regmgr.h"
|
|
#include "ccsip_publish.h"
|
|
#include "platform_api.h"
|
|
|
|
#ifdef SAPP_SAPP_GSM
|
|
#define SAPP_APP_GSM 3
|
|
#define SAPP_APP SAPP_APP_GSM
|
|
#include "sapp.h"
|
|
#endif
|
|
|
|
#if defined SIP_OS_WINDOWS
|
|
#include "../win32/cpr_win_defines.h"
|
|
#endif
|
|
|
|
|
|
|
|
extern sipSCB_t *find_scb_by_callid(const char *callID, int *scb_index);
|
|
extern int platThreadInit(char *);
|
|
void sip_platform_handle_service_control_notify(sipServiceControl_t *scp);
|
|
short SIPTaskProcessTimerExpiration(void *msg, uint32_t *cmd);
|
|
extern cprMsgQueue_t sip_msgq;
|
|
extern cprMsgQueue_t gsm_msgq;
|
|
extern void ccsip_dump_recv_msg_info(sipMessage_t *pSIPMessage,
|
|
cpr_ip_addr_t *cc_remote_ipaddr,
|
|
uint16_t cc_remote_port);
|
|
void destroy_sip_thread(void);
|
|
|
|
// Global variables
|
|
|
|
|
|
/*---------------------------------------------------------
|
|
*
|
|
* Definitions
|
|
*
|
|
*/
|
|
|
|
#define MESSAGE_WAITING_STR_SIZE 5
|
|
|
|
#define MAC_ADDR_STR_LENGTH 16
|
|
#define SIP_HEADER_SERVER_LEN 80
|
|
#define SIP_HEADER_USER_AGENT_LEN 80
|
|
#define SIP_PHONE_MODEL_NUMBER_LEN 32
|
|
|
|
/* The maximun number of gsm_msgq depth to allow new incoming call,
|
|
*/
|
|
/*
|
|
* for RT, the threshold of 60 is not based on testing.
|
|
* As discussed in CSCsz33584 Code Review, it is better to drop the heavy load as it enters the system than let it go deep into the system.
|
|
* So we add the same logic into RT, but RT still cannot pass the test in CSCsz33584.
|
|
* Bottleneck of RT might be ccapp_msgq instead of gsm_msgq.
|
|
* A more complex solution should be studied to prevent RT phone from overload.
|
|
*/
|
|
#define MAX_DEPTH_OF_GSM_MSGQ_TO_ALLOW_NEW_INCOMING_CALL 60
|
|
|
|
/* Internal request structure for restart/re-init request from platform */
|
|
typedef enum {
|
|
SIP_RESTART_REQ_NONE,
|
|
SIP_RESTART_REQ_RESTART, /* to restart */
|
|
SIP_RESTART_REQ_REINIT /* to re-init */
|
|
} ccsip_restart_cmd;
|
|
|
|
typedef enum {
|
|
SIP_SHUTDOWN_REQ_NONE,
|
|
SIP_SHUTDOWN_REQ_SHUT
|
|
} ccsip_shutdown_cmd;
|
|
|
|
typedef struct ccsip_restart_req_t_ {
|
|
ccsip_restart_cmd cmd; /* restart command */
|
|
} ccsip_restart_req;
|
|
|
|
typedef struct ccsip_shutdown_req_t_ {
|
|
ccsip_shutdown_cmd cmd; /* shutdown command */
|
|
int action;
|
|
int reason;
|
|
} ccsip_shutdown_req_t;
|
|
|
|
|
|
extern cprThread_t sip_thread;
|
|
|
|
|
|
/*---------------------------------------------------------
|
|
*
|
|
* Local Variables
|
|
*
|
|
*/
|
|
// static uint16_t nfds = 0; No reference. Should this be removed?
|
|
extern fd_set read_fds;
|
|
extern fd_set write_fds;
|
|
// static cpr_socket_t listenSocket = INVALID_SOCKET; No reference. Should this be removed?
|
|
// static sip_connection_t sipConn; Set in ccsip_task.c but never used. Should this be removed?
|
|
// static cprMsgQueue_t sip_msg_queue; No reference. Should this be removed?
|
|
// static cprRegion_t sip_region; No reference. Should this be removed?
|
|
// static cprPool_t sip_pool; No reference. Should this be removed?
|
|
|
|
|
|
|
|
/*---------------------------------------------------------
|
|
*
|
|
* Global Variables
|
|
*
|
|
*/
|
|
sipGlobal_t sip;
|
|
boolean sip_mode_quiet = FALSE;
|
|
char sipHeaderServer[SIP_HEADER_SERVER_LEN];
|
|
char sipHeaderUserAgent[SIP_HEADER_SERVER_LEN];
|
|
char sipPhoneModelNumber[SIP_PHONE_MODEL_NUMBER_LEN];
|
|
char sipUnregisterReason[MAX_SIP_REASON_LENGTH];
|
|
|
|
boolean Is794x = FALSE;
|
|
|
|
/*---------------------------------------------------------
|
|
*
|
|
* External Variables
|
|
* TODO reference through proper header files
|
|
*/
|
|
extern sipCallHistory_t gCallHistory[];
|
|
|
|
|
|
/*---------------------------------------------------------
|
|
*
|
|
* Function declarations
|
|
*
|
|
*/
|
|
static void SIPTaskProcessSIPMessage(sipMessage_t *message);
|
|
static int SIPTaskProcessSIPNotify(sipMessage_t *pSipMessage);
|
|
static int SIPTaskProcessSIPNotifyMWI(sipMessage_t *pSipMessage,
|
|
line_t dn_line);
|
|
static void SIPTaskProcessSIPNotifyCheckSync(sipMessage_t *pSipMessage);
|
|
static void SIPTaskProcessSIPPreviousCallByeResponse(sipMessage_t *pSipMessage,
|
|
int response_code,
|
|
line_t previous_call_index);
|
|
static void SIPTaskProcessSIPPreviousCallInviteResponse(sipMessage_t *pResponse,
|
|
int response_code,
|
|
line_t previous_call_index);
|
|
static void SIPTaskProcessSIPNotifyRefer(sipMessage_t *pSipMessage);
|
|
static int SIPTaskProcessSIPNotifyServiceControl(sipMessage_t *pSipMessage);
|
|
static void SIPTaskProcessRestart(ccsip_restart_cmd cmd);
|
|
static void SIPTaskProcessShutdown(int action, int reason);
|
|
|
|
/*---------------------------------------------------------
|
|
*
|
|
* Functions
|
|
*
|
|
*/
|
|
void
|
|
get_ua_model_and_device (char sipHdrUserAgent[])
|
|
{
|
|
const char fname[] = "get_ua_model_and_device";
|
|
char *model = NULL;
|
|
|
|
model = (char *)platGetModel();
|
|
|
|
if (model) {
|
|
if (strncmp(model, CSF_MODEL, 3) == 0) {
|
|
sstrncat(sipHdrUserAgent, CCSIP_SIP_CSF_USER_AGENT,
|
|
SIP_HEADER_SERVER_LEN - strlen(sipHdrUserAgent));
|
|
sstrncpy(sipPhoneModelNumber, PHONE_MODEL_NUMBER_CSF,
|
|
SIP_PHONE_MODEL_NUMBER_LEN);
|
|
} else if (strcmp(model, PHONE_MODEL) == 0) {
|
|
//if phone model is any of vendor defined, set as is.
|
|
sstrncat(sipHdrUserAgent, CCSIP_SIP_USER_AGENT,
|
|
SIP_HEADER_SERVER_LEN - strlen(sipHdrUserAgent));
|
|
sstrncpy(sipPhoneModelNumber, PHONE_MODEL_NUMBER,
|
|
SIP_PHONE_MODEL_NUMBER_LEN);
|
|
} else {
|
|
// Default to 7970
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"unknown model,defaulting to model 7970: %s\n", fname, model);
|
|
sstrncat(sipHdrUserAgent, CCSIP_SIP_7970_USER_AGENT,
|
|
SIP_HEADER_SERVER_LEN - strlen(sipHdrUserAgent));
|
|
sstrncpy(sipPhoneModelNumber, PHONE_MODEL_NUMBER_7970,
|
|
SIP_PHONE_MODEL_NUMBER_LEN);
|
|
}
|
|
} else {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"could not obtain model information\n", fname);
|
|
sstrncat(sipHdrUserAgent, CCSIP_SIP_7970_USER_AGENT,
|
|
SIP_HEADER_SERVER_LEN - strlen(sipHdrUserAgent));
|
|
sstrncpy(sipPhoneModelNumber, PHONE_MODEL_NUMBER_7970,
|
|
SIP_PHONE_MODEL_NUMBER_LEN);
|
|
}
|
|
}
|
|
|
|
extern void ccsip_debug_init(void);
|
|
|
|
/**
|
|
*
|
|
* SIPTaskInit
|
|
*
|
|
* Initialize the SIP Task
|
|
*
|
|
* Parameters: None
|
|
*
|
|
* Return Value: SIP_OK
|
|
*
|
|
*/
|
|
void
|
|
SIPTaskInit (void)
|
|
{
|
|
/*
|
|
* Initialize platform specific parameters
|
|
*/
|
|
|
|
// sipConn is set but never used. Should this be removed?
|
|
// for (i = 0; i < MAX_SIP_CONNECTIONS; i++) {
|
|
// sipConn.read[i] = INVALID_SOCKET;
|
|
// sipConn.write[i] = INVALID_SOCKET;
|
|
//}
|
|
|
|
/*
|
|
* Initialize cprSelect call parameters
|
|
*/
|
|
// XXX already did in sip_platform_task_init(), like, two instructions ago
|
|
FD_ZERO(&read_fds);
|
|
FD_ZERO(&write_fds);
|
|
/*
|
|
* Do the debug init right here so that we can enable
|
|
* sip debugs during startup and not wait for sip stack
|
|
* to initialize.
|
|
*/
|
|
ccsip_debug_init();
|
|
|
|
/************************
|
|
// Move all initialization to sip_sm_init called after config
|
|
if (ccsip_register_init() == SIP_ERROR) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"ccsip_register_init() failed.\n", fname);
|
|
return SIP_ERROR;
|
|
}
|
|
|
|
*
|
|
* Allocate timers for CCBs
|
|
*
|
|
if (sip_platform_timers_init() == SIP_ERROR) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sip_platform_timers_init() failed\n", fname);
|
|
return SIP_ERROR;
|
|
}
|
|
*************************/
|
|
// Initialize the value of the UA and Server headers
|
|
sipHeaderUserAgent[0] = '\0';
|
|
sipPhoneModelNumber[0] = '\0';
|
|
sipHeaderServer[0] = '\0';
|
|
|
|
#if defined _COMMUNICATOR_
|
|
sstrncat(sipHeaderUserAgent, CCSIP_SIP_COMMUNICATOR_USER_AGENT,
|
|
sizeof(sipHeaderUserAgent) - strlen(sipHeaderUserAgent));
|
|
sstrncpy(sipPhoneModelNumber, PHONE_MODEL_NUMBER_COMMUNICATOR,
|
|
SIP_PHONE_MODEL_NUMBER_LEN);
|
|
#else
|
|
get_ua_model_and_device(sipHeaderUserAgent);
|
|
#endif
|
|
|
|
// Now add the firmware version
|
|
sstrncat(sipHeaderUserAgent, "/",
|
|
sizeof(sipHeaderUserAgent) - strlen(sipHeaderUserAgent));
|
|
sstrncat(sipHeaderUserAgent, gVersion,
|
|
sizeof(sipHeaderUserAgent) - strlen(sipHeaderUserAgent));
|
|
sstrncpy(sipHeaderServer, sipHeaderUserAgent,
|
|
SIP_HEADER_SERVER_LEN);
|
|
}
|
|
|
|
|
|
/**
|
|
*
|
|
* SIPTaskSendMsg (API)
|
|
*
|
|
* The API to send a message to the SIP task
|
|
*
|
|
* Parameters: cmd - the message type
|
|
* msg - the message buffer to send
|
|
* len - length of the message buffer
|
|
* usr - user pointer TEMPORARY VALUE TO MOVE INTO msg
|
|
*
|
|
* Return Value: SIP_OK or SIP_ERROR
|
|
*
|
|
*/
|
|
cpr_status_e
|
|
SIPTaskSendMsg (uint32_t cmd, void *msg, uint16_t len, void *usr)
|
|
{
|
|
phn_syshdr_t *syshdr;
|
|
|
|
syshdr = (phn_syshdr_t *) cprGetSysHeader(msg);
|
|
if (!syshdr) {
|
|
return CPR_FAILURE;
|
|
}
|
|
syshdr->Cmd = cmd;
|
|
syshdr->Len = len;
|
|
syshdr->Usr.UsrPtr = usr;
|
|
|
|
/*
|
|
* If we send a message to the task too soon the sip variable is not set yet.
|
|
* so just use the global for now. This happens if we create sip thread
|
|
* and immediately send a CFG_DONE message to sip thread from the main thread.
|
|
* This can be solved by waiting for an echo roundtrip from Thread before sending
|
|
* any other message. Will do someday.
|
|
*/
|
|
if (cprSendMessage(sip_msgq /*sip.msgQueue */ , (cprBuffer_t)msg, (void **)&syshdr)
|
|
== CPR_FAILURE) {
|
|
cprReleaseSysHeader(syshdr);
|
|
return CPR_FAILURE;
|
|
}
|
|
return CPR_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* SIPTaskGetBuffer (API)
|
|
*
|
|
* The API to grab a buffer from the SIP buffer pool
|
|
*
|
|
* Parameters: size - size of the buffer requested
|
|
*
|
|
* Return Value: requested buffer or NULL
|
|
*
|
|
*/
|
|
cprBuffer_t
|
|
SIPTaskGetBuffer (uint16_t size)
|
|
{
|
|
return cpr_malloc(size);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* SIPTaskProcessListEvent (Internal API)
|
|
*
|
|
* Process a SIP event/message
|
|
*
|
|
* Parameters: cmd - the type of event
|
|
* msg - the event message
|
|
* pUsr- a user pointer (TEMPORARY FIELD to be put into msg)
|
|
* len - the length of the message
|
|
*
|
|
* Return Value: None
|
|
*
|
|
*/
|
|
void
|
|
SIPTaskProcessListEvent (uint32_t cmd, void *msg, void *pUsr, uint16_t len)
|
|
{
|
|
static const char *fname = "SIPTaskProcessListEvent";
|
|
sipSMEvent_t sip_sm_event;
|
|
int idx;
|
|
int p2psip = 0;
|
|
int sdpmode = 0;
|
|
cprCallBackTimerMsg_t *timerMsg;
|
|
line_t last_available_line;
|
|
CCM_ID ccm_id;
|
|
|
|
timerMsg = (cprCallBackTimerMsg_t *) msg;
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"cmd = 0x%x\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname), cmd);
|
|
|
|
/*
|
|
* Loop and wait until we get a TCP_PHN_CFG_TCP_DONE or a RESTART
|
|
* message from the phone before we finish
|
|
* initializing the SIPTask and SIP state machine
|
|
* (note this can happen any time the network stack is re-spun)
|
|
*/
|
|
if ((sip.taskInited == FALSE) &&
|
|
((cmd != TCP_PHN_CFG_TCP_DONE) &&
|
|
(cmd != SIP_RESTART) &&
|
|
(cmd != SIP_TMR_SHUTDOWN_PHASE2) &&
|
|
(cmd != SIP_SHUTDOWN) &&
|
|
(cmd != TIMER_EXPIRATION) &&
|
|
(cmd != THREAD_UNLOAD)) ) {
|
|
cpr_free(msg);
|
|
DEF_DEBUG(DEB_F_PREFIX" !!!sip.taskInited is false. So not executing cmd=0x%x\n",
|
|
DEB_F_PREFIX_ARGS(SIP_EVT, fname), cmd);
|
|
return;
|
|
}
|
|
|
|
memset(&sip_sm_event, 0, sizeof(sipSMEvent_t));
|
|
|
|
/*
|
|
* Before CPR used to call the timer callback function out of its'
|
|
* timer tick so quite a few of the SIP timers would just post
|
|
* a timer expiration event back to its' queue to release the
|
|
* CPR thread. Now CPR just sends a timer expiration event
|
|
* to the SIP task so we don't want to double post a timer
|
|
* expiration event. Therefore check to see if this is a timer
|
|
* expiration event and if so possibly update the command before
|
|
* switching on it. If the function returns false it means all
|
|
* it did was update the command so we need to process the switch
|
|
* statement, if it returns true the timer event has been handled.
|
|
*/
|
|
if (cmd == TIMER_EXPIRATION) {
|
|
if (SIPTaskProcessTimerExpiration(msg, &cmd)) {
|
|
cpr_free(msg);
|
|
return;
|
|
}
|
|
/*
|
|
* No need to release the buffer if we overwrote the command
|
|
* as the code that handles the new command below will release
|
|
* the buffer.
|
|
*/
|
|
}
|
|
|
|
config_get_value(CFGID_P2PSIP, &p2psip, sizeof(p2psip));
|
|
config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
|
|
|
|
switch (cmd) {
|
|
/*
|
|
* See comment above
|
|
*/
|
|
case TCP_PHN_CFG_TCP_DONE:
|
|
/*
|
|
* Ignore any TCP_PHN_CFG_TCP_DONE message since it is only used to
|
|
* determine when the SIP sm should be initialized
|
|
*/
|
|
cpr_free(msg);
|
|
|
|
// If P2P set transport to UDP
|
|
if (p2psip == TRUE)
|
|
CC_Config_setIntValue(CFGID_TRANSPORT_LAYER_PROT, 2);
|
|
|
|
|
|
if (sip_sm_init() < 0) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sip_sm_init() failed ", fname);
|
|
return;
|
|
}
|
|
|
|
sip_mode_quiet = FALSE;
|
|
|
|
/*
|
|
* If P2P or SDP only do not register with SIP Server
|
|
*/
|
|
if (!p2psip && !sdpmode)
|
|
sip_platform_init();
|
|
else
|
|
ui_set_sip_registration_state(CC_ALL_LINES, TRUE);
|
|
|
|
sip.taskInited = TRUE;
|
|
DEF_DEBUG(SIP_F_PREFIX"sip.taskInited is set to true ", fname);
|
|
#ifdef SAPP_SAPP_GSM
|
|
/*
|
|
* Initialize SAPP.
|
|
*/
|
|
if (sapp_init() != 0) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sapp_init() failed.\n", fname);
|
|
break;
|
|
}
|
|
/*
|
|
* Start SAPP. SAPP will register with the CCM.
|
|
*/
|
|
if (sapp_test() != 0) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sapp_test() failed.\n", fname);
|
|
break;
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
case SIP_GSM:
|
|
/*
|
|
* GSM CC Events
|
|
*/
|
|
|
|
#ifdef SAPP_SAPP_GSM
|
|
if (sapp_process_cc_event(msg) == 0) {
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
if (p2psip == TRUE)
|
|
sipTransportSetSIPServer();
|
|
|
|
if (sip_sm_process_cc_event(msg) != SIP_OK) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sip_sm_process_cc_event() "
|
|
"failed.\n", fname);
|
|
}
|
|
break;
|
|
|
|
case SIP_TMR_INV_EXPIRE:
|
|
idx = (long) (timerMsg->usrData);
|
|
sip_sm_event.ccb = sip_sm_get_ccb_by_index((line_t)idx);
|
|
cpr_free(msg);
|
|
if (!sip_sm_event.ccb) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"usrData does not point to a valid ccb "
|
|
"discarding SIP_TMR_INV_EXPIRE event\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
|
|
break;
|
|
}
|
|
sip_sm_event.type = E_SIP_INV_EXPIRES_TIMER;
|
|
if (sip_sm_process_event(&sip_sm_event) < 0) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(SM_PROCESS_EVENT_ERROR), fname, sip_sm_event.type);
|
|
}
|
|
break;
|
|
|
|
case SIP_TMR_SUPERVISION_DISCONNECT:
|
|
idx = (long) (timerMsg->usrData);
|
|
sip_sm_event.ccb = sip_sm_get_ccb_by_index((line_t)idx);
|
|
cpr_free(msg);
|
|
if (!sip_sm_event.ccb) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"usrData does not point to a valid ccb "
|
|
"discarding SIP_TMR_SUPERVISION_DISCONNECT event.\n",
|
|
DEB_F_PREFIX_ARGS(SIP_EVT, fname));
|
|
break;
|
|
}
|
|
sip_sm_event.type = E_SIP_SUPERVISION_DISCONNECT_TIMER;
|
|
if (sip_sm_process_event(&sip_sm_event) < 0) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(SM_PROCESS_EVENT_ERROR), fname, sip_sm_event.type);
|
|
}
|
|
break;
|
|
|
|
case SIP_TMR_INV_LOCALEXPIRE:
|
|
idx = (long) (timerMsg->usrData);
|
|
sip_sm_event.ccb = sip_sm_get_ccb_by_index((line_t)idx);
|
|
cpr_free(msg);
|
|
if (!sip_sm_event.ccb) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"usrData does not point to valid ccb "
|
|
"discarding SIP_TMR_INV_LOCALEXPIRE "
|
|
"event.\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
|
|
break;
|
|
}
|
|
sip_sm_event.type = E_SIP_INV_LOCALEXPIRES_TIMER;
|
|
if (sip_sm_process_event(&sip_sm_event) < 0) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(SM_PROCESS_EVENT_ERROR), fname, sip_sm_event.type);
|
|
}
|
|
break;
|
|
|
|
/*
|
|
* UsrInfo is set to the IP address that bounced when an
|
|
* IMCP Unreachable. -1 means we had a timeout, not a bounce.
|
|
*/
|
|
case SIP_TMR_MSG_RETRY:
|
|
idx = (long) (timerMsg->usrData);
|
|
sip_sm_event.ccb = sip_sm_get_ccb_by_index((line_t)idx);
|
|
sip_sm_event.type = E_SIP_TIMER;
|
|
sip_sm_event.u.UsrInfo = ip_addr_invalid;
|
|
cpr_free(msg);
|
|
if (sip_sm_process_event(&sip_sm_event) < 0) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(SM_PROCESS_EVENT_ERROR), fname, sip_sm_event.type);
|
|
}
|
|
break;
|
|
|
|
case SIP_ICMP_UNREACHABLE:
|
|
{
|
|
sipMethod_t retxMessageType;
|
|
|
|
idx = msg ? (line_t) (*((uint32_t *)msg)) : 0;
|
|
sip_sm_event.ccb = sip_sm_get_ccb_by_index((line_t)idx);
|
|
/* IP address that bounced */
|
|
sip_sm_event.u.UsrInfo = (*(cpr_ip_addr_t *)pUsr);
|
|
cpr_free(msg);
|
|
if (!sip_sm_event.ccb) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"event does not point to valid ccb "
|
|
"SIP_ICMP_UNREACHABLE event.\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
|
|
break;
|
|
}
|
|
/*
|
|
* Retrieve message type and cancel outstanding
|
|
* timer and remove ICMP Handler
|
|
*/
|
|
CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_ENTRY),
|
|
sip_sm_event.ccb->index,
|
|
sip_sm_event.ccb->dn_line,
|
|
fname, "ICMP_UNREACHABLE");
|
|
|
|
/* Do not need to process the ICMP_UNREACHABLE for fallback ccbs */
|
|
if (sip_sm_event.ccb->index <= REG_BACKUP_CCB) {
|
|
retxMessageType =
|
|
sip_platform_msg_timer_messageType_get(sip_sm_event.ccb->index);
|
|
sip_platform_msg_timer_stop(sip_sm_event.ccb->index);
|
|
|
|
if (retxMessageType == sipMethodInvite) {
|
|
config_get_value(CFGID_SIP_INVITE_RETX,
|
|
&sip_sm_event.ccb->retx_counter,
|
|
sizeof(sip_sm_event.ccb->retx_counter));
|
|
if (sip_sm_event.ccb->retx_counter > MAX_INVITE_RETRY_ATTEMPTS) {
|
|
sip_sm_event.ccb->retx_counter = MAX_INVITE_RETRY_ATTEMPTS;
|
|
}
|
|
} else {
|
|
config_get_value(CFGID_SIP_RETX,
|
|
&sip_sm_event.ccb->retx_counter,
|
|
sizeof(sip_sm_event.ccb->retx_counter));
|
|
if (sip_sm_event.ccb->retx_counter > MAX_NON_INVITE_RETRY_ATTEMPTS) {
|
|
sip_sm_event.ccb->retx_counter = MAX_NON_INVITE_RETRY_ATTEMPTS;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If REG CCB send into registration state machine else send
|
|
* into sip call processing machine
|
|
*/
|
|
if (retxMessageType == sipMethodRegister) {
|
|
/*
|
|
* UsrInfo is set to the IP address that bounced when an
|
|
* ICMP Unreachable. -1 means we had a timeout, not a bounce.
|
|
*/
|
|
sip_sm_event.type = (sipSMEventType_t) E_SIP_REG_TMR_RETRY;
|
|
if (sip_reg_sm_process_event(&sip_sm_event) < 0) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(REG_SM_PROCESS_EVENT_ERROR), fname, sip_sm_event.type);
|
|
}
|
|
} else {
|
|
sip_sm_event.type = E_SIP_ICMP_UNREACHABLE;
|
|
if (sip_sm_process_event(&sip_sm_event) < 0) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(SM_PROCESS_EVENT_ERROR), fname, sip_sm_event.type);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SIP_TMR_REG_EXPIRE:
|
|
idx = (long) (timerMsg->usrData);
|
|
sip_sm_event.ccb = sip_sm_get_ccb_by_index((line_t)idx);
|
|
sip_sm_event.type = (sipSMEventType_t) E_SIP_REG_TMR_EXPIRE;
|
|
cpr_free(msg);
|
|
if (sip_reg_sm_process_event(&sip_sm_event) < 0) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(REG_SM_PROCESS_EVENT_ERROR), fname, sip_sm_event.type);
|
|
}
|
|
break;
|
|
|
|
case SIP_TMR_REG_ACK:
|
|
idx = (long) (timerMsg->usrData);
|
|
sip_sm_event.ccb = sip_sm_get_ccb_by_index((line_t)idx);
|
|
sip_sm_event.type = (sipSMEventType_t) E_SIP_REG_TMR_ACK;
|
|
cpr_free(msg);
|
|
if (sip_reg_sm_process_event(&sip_sm_event) < 0) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(REG_SM_PROCESS_EVENT_ERROR), fname, sip_sm_event.type);
|
|
}
|
|
break;
|
|
|
|
case SIP_TMR_REG_WAIT:
|
|
idx = msg ? (line_t) (*((uint32_t *)msg)) : CC_NO_LINE;
|
|
sip_sm_event.ccb = sip_sm_get_ccb_by_index((line_t)idx);
|
|
sip_sm_event.type = (sipSMEventType_t) E_SIP_REG_TMR_WAIT;
|
|
cpr_free(msg);
|
|
if (sip_reg_sm_process_event(&sip_sm_event) < 0) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(REG_SM_PROCESS_EVENT_ERROR), fname, sip_sm_event.type);
|
|
}
|
|
break;
|
|
|
|
/*
|
|
* UsrInfo is set to the IP address that bounced when an
|
|
* ICMP Unreachable. -1 means we had a timeout, not a bounce.
|
|
*/
|
|
/*
|
|
* currently, we only look for ccm_id for SIP_TMR_REG_RETRY. for rest
|
|
* of the REG msg, existing code will work because first field of
|
|
* ccsip_registration_msg_t is uint32_t.
|
|
*/
|
|
case SIP_TMR_REG_RETRY:
|
|
idx = msg ? (line_t) ((ccsip_registration_msg_t *)msg)->ccb_index : CC_NO_LINE;
|
|
ccm_id = msg ? ((ccsip_registration_msg_t *)msg)->ccm_id : UNUSED_PARAM;
|
|
sip_sm_event.ccb = sip_sm_get_ccb_by_ccm_id_and_index(ccm_id, (line_t) idx);
|
|
sip_sm_event.type = (sipSMEventType_t) E_SIP_REG_TMR_RETRY;
|
|
sip_sm_event.u.UsrInfo = ip_addr_invalid;
|
|
cpr_free(msg);
|
|
if (sip_sm_event.ccb == NULL || sip_reg_sm_process_event(&sip_sm_event) < 0) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(REG_SM_PROCESS_EVENT_ERROR), fname, sip_sm_event.type);
|
|
}
|
|
break;
|
|
|
|
case SIP_REG_REQ:
|
|
idx = msg ? (line_t) (*((uint32_t *)msg)) : CC_NO_LINE;
|
|
cpr_free(msg);
|
|
sip_sm_event.ccb = sip_sm_get_ccb_by_index((line_t) idx);
|
|
if (!sip_sm_event.ccb) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"event data does not point to a valid ccb"
|
|
"SIP_REG_REQ event.\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
|
|
break;
|
|
}
|
|
(void) sip_sm_ccb_init(sip_sm_event.ccb, (line_t)idx, idx, SIP_REG_STATE_IDLE);
|
|
sip_sm_event.ccb->state = (sipSMStateType_t) SIP_REG_STATE_IDLE;
|
|
sip_sm_event.type = (sipSMEventType_t) E_SIP_REG_REG_REQ;
|
|
if (sip_reg_sm_process_event(&sip_sm_event) < 0) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(REG_SM_PROCESS_EVENT_ERROR), fname, sip_sm_event.type);
|
|
}
|
|
break;
|
|
|
|
case SIP_REG_CANCEL:
|
|
idx = msg ? (line_t) (*((uint32_t *)msg)) : CC_NO_LINE;
|
|
sip_sm_event.ccb = sip_sm_get_ccb_by_index((line_t) idx);
|
|
sip_sm_event.type = (sipSMEventType_t) E_SIP_REG_CANCEL;
|
|
cpr_free(msg);
|
|
if (sip_reg_sm_process_event(&sip_sm_event) < 0) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(REG_SM_PROCESS_EVENT_ERROR), fname, sip_sm_event.type);
|
|
}
|
|
break;
|
|
|
|
case SIP_REG_CLEANUP:
|
|
idx = msg ? (line_t) (*((uint32_t *)msg)) : CC_NO_LINE;
|
|
sip_sm_event.ccb = sip_sm_get_ccb_by_index((line_t) idx);
|
|
sip_sm_event.type = (sipSMEventType_t) E_SIP_REG_CLEANUP;
|
|
cpr_free(msg);
|
|
if (sip_reg_sm_process_event(&sip_sm_event) < 0) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(REG_SM_PROCESS_EVENT_ERROR), fname, sip_sm_event.type);
|
|
}
|
|
break;
|
|
|
|
case SIP_TMR_STANDBY_KEEPALIVE:
|
|
sip_sm_event.ccb = sip_sm_get_ccb_by_index(REG_BACKUP_CCB);
|
|
sip_sm_event.type = (sipSMEventType_t) E_SIP_REG_TMR_WAIT;
|
|
cpr_free(msg);
|
|
if (sip_reg_sm_process_event(&sip_sm_event) < 0) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(REG_SM_PROCESS_EVENT_ERROR), fname, sip_sm_event.type);
|
|
}
|
|
break;
|
|
|
|
|
|
// Subscribe/Notify Events
|
|
case SIPSPI_EV_CC_SUBSCRIBE_REGISTER:
|
|
if (subsmanager_handle_ev_app_subscribe_register(msg) < 0) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"subsmanager_handle_ev_app_subscribe_register() "
|
|
"returned error.\n", fname);
|
|
}
|
|
cpr_free(msg);
|
|
break;
|
|
case SIPSPI_EV_CC_SUBSCRIBE:
|
|
if (subsmanager_handle_ev_app_subscribe(msg) < 0) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"subsmanager_handle_ev_app_subscribe() "
|
|
"returned error.\n", fname);
|
|
}
|
|
cpr_free(msg);
|
|
break;
|
|
case SIPSPI_EV_CC_SUBSCRIBE_RESPONSE:
|
|
if (subsmanager_handle_ev_app_subscribe_response(msg) < 0) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"subsmanager_handle_ev_app_subscribe_response() "
|
|
"returned error.\n", fname);
|
|
}
|
|
cpr_free(msg);
|
|
break;
|
|
case SIPSPI_EV_CC_NOTIFY:
|
|
{
|
|
int ret;
|
|
|
|
ret = subsmanager_handle_ev_app_notify(msg);
|
|
if (ret == SIP_ERROR) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"subsmanager_handle_ev_app_notify() "
|
|
"returned error.\n", fname);
|
|
} else if (ret == SIP_DEFER) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"subsmanager_handle_ev_app_notify() "
|
|
"deferred request.\n", fname);
|
|
}
|
|
}
|
|
cpr_free(msg);
|
|
break;
|
|
case SIPSPI_EV_CC_NOTIFY_RESPONSE:
|
|
if (subsmanager_handle_ev_app_notify_response(msg) < 0) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"subsmanager_handle_ev_app_notify_response() "
|
|
"returned error.\n", fname);
|
|
}
|
|
cpr_free(msg);
|
|
break;
|
|
case SIPSPI_EV_CC_SUBSCRIPTION_TERMINATED:
|
|
if (subsmanager_handle_ev_app_subscription_terminated(msg) < 0) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"subsmanager_handle_ev_app_subscription_terminated() "
|
|
"returned error.\n", fname);
|
|
}
|
|
cpr_free(msg);
|
|
break;
|
|
|
|
case SIPSPI_EV_CC_PUBLISH_REQ:
|
|
if (publish_handle_ev_app_publish(msg) < 0) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"publish_handle_ev_app_publish() "
|
|
"returned error.\n", fname);
|
|
}
|
|
cpr_free(msg);
|
|
break;
|
|
|
|
case SIP_REG_UPDATE:
|
|
last_available_line = msg ? (line_t) (*((uint32_t *)msg)) : CC_NO_LINE;
|
|
cpr_free(msg);
|
|
regmgr_handle_register_update(last_available_line);
|
|
break;
|
|
case REG_MGR_STATE_CHANGE:
|
|
|
|
sip_regmgr_rsp(((cc_regmgr_t *)msg)->rsp_id,
|
|
((cc_regmgr_t *)msg)->rsp_type,
|
|
((cc_regmgr_t *)msg)->wait_flag);
|
|
cpr_free(msg);
|
|
break;
|
|
|
|
|
|
// Retry timer expired for Sub/Not
|
|
case SIP_TMR_MSG_RETRY_SUBNOT:
|
|
idx = (long) (timerMsg->usrData);
|
|
cpr_free(msg);
|
|
if (subsmanager_handle_retry_timer_expire(idx) < 0) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"subsmanager_handle_retry_timer_expire() "
|
|
"returned error.\n", fname);
|
|
}
|
|
break;
|
|
// Sub/Not periodic timer
|
|
case SIP_TMR_PERIODIC_SUBNOT:
|
|
cpr_free(msg);
|
|
subsmanager_handle_periodic_timer_expire();
|
|
publish_handle_periodic_timer_expire();
|
|
break;
|
|
|
|
case SIP_RESTART:
|
|
{
|
|
ccsip_restart_req *req = (ccsip_restart_req *) msg;
|
|
ccsip_restart_cmd restartCmd;
|
|
|
|
restartCmd = req->cmd;
|
|
// Handle restart event from platform
|
|
cpr_free(msg);
|
|
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Received SIP_RESTART event restartCmd = (%d)\n",
|
|
DEB_F_PREFIX_ARGS(SIP_EVT, fname), restartCmd);
|
|
SIPTaskProcessRestart(restartCmd);
|
|
break;
|
|
}
|
|
|
|
case SIP_TMR_SHUTDOWN_PHASE2:
|
|
{
|
|
// Handle shutdown phase 2 event (after unregistration)
|
|
// Note: boolean is 8 bits, but 32 bits have been allocated for it
|
|
// so we need to dereference msg with 32 bits
|
|
int action;
|
|
|
|
if (msg) {
|
|
action = (*((uint32_t *)msg));
|
|
} else {
|
|
action = SIP_INTERNAL;
|
|
}
|
|
|
|
cpr_free(msg);
|
|
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Received SIP_TMR_SHUTDOWN_PHASE2 event action= (%d)\n",
|
|
DEB_F_PREFIX_ARGS(SIP_EVT, fname), action);
|
|
sip_shutdown_phase2(action);
|
|
}
|
|
break;
|
|
|
|
case SIP_SHUTDOWN:
|
|
{
|
|
ccsip_shutdown_req_t *req = (ccsip_shutdown_req_t *) msg;
|
|
int action;
|
|
int reason;
|
|
|
|
action = req->action;
|
|
reason = req->reason;
|
|
cpr_free(msg);
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Received SIP_SHUTDOWN message\n",
|
|
DEB_F_PREFIX_ARGS(SIP_EVT, fname));
|
|
SIPTaskProcessShutdown(action, reason);
|
|
}
|
|
break;
|
|
|
|
case THREAD_UNLOAD:
|
|
{
|
|
destroy_sip_thread();
|
|
}
|
|
break;
|
|
|
|
case SIP_TMR_GLARE_AVOIDANCE:
|
|
// Handle glare retry timer expiry
|
|
idx = (long) (timerMsg->usrData);
|
|
sip_sm_event.ccb = sip_sm_get_ccb_by_index((line_t)idx);
|
|
sip_sm_event.type = (sipSMEventType_t) E_SIP_GLARE_AVOIDANCE_TIMER;
|
|
cpr_free(msg);
|
|
if (sip_sm_process_event(&sip_sm_event) < 0) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(SM_PROCESS_EVENT_ERROR), fname, sip_sm_event.type);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
cpr_free(msg);
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unknown message\n, fname");
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* SIPTaskCheckSource
|
|
*
|
|
* Ensure that sender is a trusted source
|
|
*
|
|
* Parameters: from - the source address for the message
|
|
*
|
|
* Return Value: SIP_OK if message can be processed further
|
|
*/
|
|
int
|
|
SIPTaskCheckSource (cpr_sockaddr_storage from)
|
|
{
|
|
static const char fname[] = "SIPTaskCheckSource";
|
|
int regConfigValue;
|
|
line_t line_index, line_end;
|
|
cpr_ip_addr_t fromIPAddr;
|
|
int retval = SIP_ERROR;
|
|
char fromIPAddrStr[MAX_IPADDR_STR_LEN];
|
|
ccsipCCB_t *ccb = NULL;
|
|
uint32_t data, *data_p;
|
|
|
|
// If not registered, return ok
|
|
config_get_value(CFGID_PROXY_REGISTER, ®ConfigValue, sizeof(regConfigValue));
|
|
if (regConfigValue == 0) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"CFGID_PROXY_REGISTER is false\n",
|
|
DEB_F_PREFIX_ARGS(SIP_IP_MATCH, fname));
|
|
return SIP_OK;
|
|
}
|
|
|
|
line_end = 1;
|
|
line_end += TEL_CCB_END;
|
|
|
|
util_extract_ip(&fromIPAddr,&from);
|
|
util_ntohl(&fromIPAddr, &fromIPAddr);
|
|
|
|
fromIPAddrStr[0] = '\0';
|
|
ipaddr2dotted(fromIPAddrStr, &fromIPAddr);
|
|
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Attempting to recognize \"%s\"\n",
|
|
DEB_F_PREFIX_ARGS(SIP_IP_MATCH, fname), fromIPAddrStr);
|
|
// Get the proxy configured for all lines and check against those
|
|
for (line_index = REG_CCB_START; line_index <= line_end; line_index++) {
|
|
// Check the binary from-IP address with the ccb->reg.addr value
|
|
if (sip_config_check_line((line_t)(line_index - TEL_CCB_END))) {
|
|
ccb = sip_sm_get_ccb_by_index(line_index);
|
|
if (ccb && util_compare_ip(&(ccb->reg.addr), &fromIPAddr)) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Found server IP match\n",
|
|
DEB_F_PREFIX_ARGS(SIP_IP_MATCH, fname));
|
|
retval = SIP_OK;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (retval == SIP_OK) {
|
|
return retval;
|
|
}
|
|
// Not found - continue to check backup CCBs
|
|
ccb = sip_sm_get_ccb_by_index(REG_BACKUP_CCB);
|
|
if (ccb && util_compare_ip(&(ccb->reg.addr), &fromIPAddr)) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Found backup server IP match\n",
|
|
DEB_F_PREFIX_ARGS(SIP_IP_MATCH, fname));
|
|
retval = SIP_OK;
|
|
}
|
|
if (retval == SIP_OK) {
|
|
return retval;
|
|
}
|
|
// Not found - continue to check with fallback CCBs
|
|
data = 0x00;
|
|
data_p = &data;
|
|
ccb = sip_regmgr_get_fallback_ccb_list(data_p);
|
|
while ((ccb != NULL) && (retval != SIP_OK)) {
|
|
if (util_compare_ip(&(ccb->reg.addr), &fromIPAddr)) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Found fallback server IP match\n",
|
|
DEB_F_PREFIX_ARGS(SIP_IP_MATCH, fname));
|
|
retval = SIP_OK;
|
|
}
|
|
ccb = sip_regmgr_get_fallback_ccb_list(data_p);
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* SIPTaskProcessUDPMessage (Internal API)
|
|
*
|
|
* Process the received (via UDP) SIP message
|
|
*
|
|
* Parameters: msg - the message buffer
|
|
* len - length of the message buffer
|
|
* from - the source address for the message
|
|
*
|
|
* Return Value: SIP_OK if message could be processed (though this itself
|
|
* may fail) or SIP_ERROR
|
|
*
|
|
*/
|
|
int
|
|
SIPTaskProcessUDPMessage (cprBuffer_t msg,
|
|
uint16_t len,
|
|
cpr_sockaddr_storage from)
|
|
{
|
|
static const char *fname = "SIPProcessUDPMessage";
|
|
sipMessage_t *pSipMessage = NULL;
|
|
static char buf[SIP_UDP_MESSAGE_SIZE + 1];
|
|
char remoteIPAddrStr[MAX_IPADDR_STR_LEN];
|
|
uint32_t bytes_used = 0;
|
|
int accept_msg = SIP_OK;
|
|
cpr_ip_addr_t ip_addr;
|
|
int p2psip = 0;
|
|
/*
|
|
* Convert IP address to string, for debugs
|
|
*/
|
|
util_extract_ip(&ip_addr, &from);
|
|
|
|
util_ntohl(&ip_addr, &ip_addr);
|
|
|
|
if (SipDebugMessage) {
|
|
ipaddr2dotted(remoteIPAddrStr, &ip_addr);
|
|
}
|
|
|
|
util_extract_ip(&ip_addr, &from);
|
|
|
|
if (len > SIP_UDP_MESSAGE_SIZE) {
|
|
CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Received UDP message from <%s>:<%d>: "
|
|
"message too big: msg size = %d, max SIP "
|
|
"pkt size = %d\n", DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname), remoteIPAddrStr,
|
|
util_get_port(&from), bytes_used, SIP_UDP_MESSAGE_SIZE);
|
|
cpr_free(msg);
|
|
return SIP_ERROR;
|
|
}
|
|
|
|
/*
|
|
* Copy message to a local memory and release the system buffer
|
|
*/
|
|
memcpy(buf, (char *)msg, len);
|
|
buf[len] = '\0'; /* NULL terminate for debug printing */
|
|
cpr_free(msg);
|
|
|
|
/*
|
|
* Print the received UDP packet info
|
|
*/
|
|
CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"recv UDP message from <%s>:<%d>, length=<%d>, "
|
|
"message=\n", DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname), remoteIPAddrStr,
|
|
util_get_port(&from), len);
|
|
CCSIP_DEBUG_MESSAGE_PKT(buf);
|
|
|
|
/*
|
|
* Determine whether we want to process this packet
|
|
* Initially just do this if we are talking to CCM - can be expanded later
|
|
*/
|
|
|
|
|
|
|
|
config_get_value(CFGID_P2PSIP, &p2psip, sizeof(p2psip));
|
|
|
|
if (p2psip == 0) {
|
|
if (sip_regmgr_get_cc_mode(1) == REG_MODE_CCM) {
|
|
accept_msg = SIPTaskCheckSource(from);
|
|
if (accept_msg != SIP_OK) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"SIPTaskCheckSource() failed - Sender not "
|
|
"recognized\n", fname);
|
|
return SIP_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Convert to SIP representation
|
|
*/
|
|
pSipMessage = sippmh_message_create();
|
|
if (!pSipMessage) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sippmh_message_create() failed\n", fname);
|
|
return SIP_ERROR;
|
|
}
|
|
|
|
bytes_used = len;
|
|
|
|
if (sippmh_process_network_message(pSipMessage, buf, &bytes_used)
|
|
== STATUS_FAILURE) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sippmh_process_network_message() "
|
|
"failed. discarding the message.\n", fname);
|
|
free_sip_message(pSipMessage);
|
|
return SIP_ERROR;
|
|
}
|
|
/*
|
|
* Add processing here to append received=<ip_address> to the first Via
|
|
* field if the IP address we received this message from is not the same
|
|
* as the IP address in the Via field or if it contains a domain name
|
|
*/
|
|
sippmh_process_via_header(pSipMessage, &ip_addr);
|
|
|
|
ccsip_dump_recv_msg_info(pSipMessage, &ip_addr, 0);
|
|
|
|
/* Process SIP message */
|
|
SIPTaskProcessSIPMessage(pSipMessage);
|
|
return SIP_OK;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* SIPTaskProcessTCPMessage (Internal API)
|
|
*
|
|
* Process the received (via TCP) SIP message
|
|
*
|
|
* Parameters: msg - the message buffer
|
|
* len - length of the message buffer
|
|
* from - the source address for the message
|
|
*
|
|
* Return Value: SIP_OK if message could be processed (though this itself
|
|
* may fail) or SIP_ERROR
|
|
*
|
|
*/
|
|
void
|
|
SIPTaskProcessTCPMessage (sipMessage_t *pSipMessage, cpr_sockaddr_storage from)
|
|
{
|
|
cpr_ip_addr_t ip_addr;
|
|
|
|
CPR_IP_ADDR_INIT(ip_addr);
|
|
/*
|
|
* Convert IP address to string, for debugs
|
|
*/
|
|
util_extract_ip(&ip_addr, &from);
|
|
|
|
/*
|
|
* Add processing here to append received=<ip_address> to the first Via
|
|
* field if the IP address we received this message from is not the same
|
|
* as the IP address in the Via field or if it contains a domain name
|
|
*/
|
|
sippmh_process_via_header(pSipMessage, &ip_addr);
|
|
|
|
/* Process SIP message */
|
|
SIPTaskProcessSIPMessage(pSipMessage);
|
|
}
|
|
|
|
int
|
|
SIPTaskRetransmitPreviousResponse (sipMessage_t *pSipMessage,
|
|
const char *fname,
|
|
const char *pCallID,
|
|
sipCseq_t *sipCseq,
|
|
int response_code,
|
|
boolean is_request)
|
|
{
|
|
sipRelDevMessageRecord_t *pRequestRecord = NULL;
|
|
int handle = -1;
|
|
const char *reldev_to = NULL;
|
|
const char *reldev_from = NULL;
|
|
sipLocation_t *reldev_to_loc = NULL;
|
|
sipLocation_t *reldev_from_loc = NULL;
|
|
|
|
pRequestRecord = (sipRelDevMessageRecord_t *)
|
|
cpr_calloc(1, sizeof(sipRelDevMessageRecord_t));
|
|
if (!pRequestRecord) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unable to allocate "
|
|
"mem for pRequestRecord.\n", fname);
|
|
return SIP_ERROR;
|
|
}
|
|
|
|
// Copy to-tag
|
|
reldev_to = sippmh_get_cached_header_val(pSipMessage, TO);
|
|
if (reldev_to) {
|
|
reldev_to_loc = sippmh_parse_from_or_to((char *)reldev_to, TRUE);
|
|
if ((reldev_to_loc) && (reldev_to_loc->tag)) {
|
|
sstrncpy(pRequestRecord->tag,
|
|
sip_sm_purify_tag(reldev_to_loc->tag),
|
|
MAX_SIP_TAG_LENGTH);
|
|
}
|
|
|
|
// Copy to-user
|
|
if (reldev_to_loc) {
|
|
sstrncpy(pRequestRecord->to_user,
|
|
reldev_to_loc->genUrl->u.sipUrl->user,
|
|
RELDEV_MAX_USER_NAME_LEN);
|
|
sippmh_free_location(reldev_to_loc);
|
|
}
|
|
}
|
|
|
|
// Copy from-user and from-host
|
|
reldev_from = sippmh_get_cached_header_val(pSipMessage, FROM);
|
|
if (reldev_from) {
|
|
reldev_from_loc = sippmh_parse_from_or_to((char *)reldev_from, TRUE);
|
|
if (reldev_from_loc) {
|
|
sstrncpy(pRequestRecord->from_user,
|
|
reldev_from_loc->genUrl->u.sipUrl->user,
|
|
RELDEV_MAX_USER_NAME_LEN);
|
|
sstrncpy(pRequestRecord->from_host,
|
|
reldev_from_loc->genUrl->u.sipUrl->host,
|
|
RELDEV_MAX_HOST_NAME_LEN);
|
|
|
|
sippmh_free_location(reldev_from_loc);
|
|
}
|
|
}
|
|
|
|
pRequestRecord->is_request = is_request;
|
|
pRequestRecord->response_code = response_code;
|
|
|
|
// Copy Call-id
|
|
sstrncpy(pRequestRecord->call_id, (pCallID) ? pCallID : "",
|
|
MAX_SIP_CALL_ID);
|
|
|
|
// Copy CSeq values
|
|
pRequestRecord->cseq_method = sipCseq->method;
|
|
pRequestRecord->cseq_number = sipCseq->number;
|
|
|
|
if (sipRelDevMessageIsDuplicate(pRequestRecord, &handle)) {
|
|
cpr_free(pRequestRecord);
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Line filter: Previous "
|
|
"Call ID. Resending stored "
|
|
"response...\n", DEB_F_PREFIX_ARGS(SIP_MSG, fname));
|
|
if (sipRelDevCoupledMessageSend(handle) < 0) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sipRelDevCoupledMessageSend(%d)"
|
|
"returned error.\n", fname, handle);
|
|
}
|
|
return SIP_OK;
|
|
} else {
|
|
cpr_free(pRequestRecord);
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Line filter: Previous Call "
|
|
"ID. Message not in reTx list.\n", DEB_F_PREFIX_ARGS(SIP_MSG, fname));
|
|
}
|
|
return SIP_ERROR;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* SIPTaskProcessTimerExpiration
|
|
*
|
|
* Process a msg indicating a timer has expired
|
|
*
|
|
* Parameters: msg - the timer callback msg
|
|
* cmd - allows us to overwrite the cmd if needed
|
|
*
|
|
* Return Value: boolean, if true return as timer has been processed.
|
|
*
|
|
*/
|
|
short
|
|
SIPTaskProcessTimerExpiration (void *msg, uint32_t *cmd)
|
|
{
|
|
static const char fname[] = "SIPTaskProcessTimerExpiration";
|
|
cprCallBackTimerMsg_t *timerMsg;
|
|
boolean returnCode = TRUE;
|
|
uint32_t handle;
|
|
|
|
timerMsg = (cprCallBackTimerMsg_t *) msg;
|
|
TMR_DEBUG(DEB_F_PREFIX"Timer %s expired. Id is %d\n", DEB_F_PREFIX_ARGS(SIP_TIMER, fname),
|
|
timerMsg->expiredTimerName, timerMsg->expiredTimerId);
|
|
|
|
/* The REGALLFAIL Timer message could come in before the task has
|
|
* been initialized. Need to handle this timer, in order to restart
|
|
* the system. */
|
|
if ((sip.taskInited == FALSE) && (timerMsg->expiredTimerId != SIP_REGALLFAIL_TIMER)) {
|
|
return returnCode;
|
|
}
|
|
|
|
switch (timerMsg->expiredTimerId) {
|
|
case SIP_ACK_TIMER:
|
|
*cmd = SIP_TMR_REG_ACK;
|
|
returnCode = FALSE;
|
|
break;
|
|
|
|
case SIP_WAIT_TIMER:
|
|
sip_regmgr_wait_timeout_expire(timerMsg->usrData);
|
|
break;
|
|
|
|
case SIP_RETRY_TIMER:
|
|
sip_regmgr_retry_timeout_expire(timerMsg->usrData);
|
|
break;
|
|
|
|
case SIP_MSG_TIMER:
|
|
*cmd = SIP_TMR_MSG_RETRY;
|
|
returnCode = FALSE;
|
|
break;
|
|
|
|
case SIP_EXPIRES_TIMER:
|
|
*cmd = SIP_TMR_INV_EXPIRE;
|
|
returnCode = FALSE;
|
|
break;
|
|
|
|
case SIP_REG_TIMEOUT_TIMER:
|
|
ccsip_register_timeout_retry(timerMsg->usrData);
|
|
break;
|
|
|
|
case SIP_REG_EXPIRES_TIMER:
|
|
*cmd = SIP_TMR_REG_EXPIRE;
|
|
returnCode = FALSE;
|
|
break;
|
|
|
|
case SIP_LOCAL_EXPIRES_TIMER:
|
|
*cmd = SIP_TMR_INV_LOCALEXPIRE;
|
|
returnCode = FALSE;
|
|
break;
|
|
|
|
case SIP_SUPERVISION_TIMER:
|
|
*cmd = SIP_TMR_SUPERVISION_DISCONNECT;
|
|
returnCode = FALSE;
|
|
break;
|
|
|
|
case SIP_GLARE_AVOIDANCE_TIMER:
|
|
*cmd = SIP_TMR_GLARE_AVOIDANCE;
|
|
returnCode = FALSE;
|
|
break;
|
|
|
|
case SIP_KEEPALIVE_TIMER:
|
|
*cmd = SIP_TMR_STANDBY_KEEPALIVE;
|
|
returnCode = FALSE;
|
|
break;
|
|
|
|
case SIP_UNREGISTRATION_TIMER:
|
|
sip_platform_unregistration_callback(timerMsg->usrData);
|
|
break;
|
|
|
|
case SIP_SUBNOT_TIMER:
|
|
*cmd = SIP_TMR_MSG_RETRY_SUBNOT;
|
|
returnCode = FALSE;
|
|
break;
|
|
|
|
case SIP_SUBNOT_PERIODIC_TIMER:
|
|
sip_platform_subnot_periodic_timer_callback(timerMsg->usrData);
|
|
break;
|
|
|
|
case SIP_PUBLISH_RETRY_TIMER:
|
|
handle = (long)(timerMsg->usrData);
|
|
if (publish_handle_retry_timer_expire(handle) < 0) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"publish_handle_retry_timer_expire() "
|
|
"returned error.\n", fname);
|
|
}
|
|
break;
|
|
|
|
case SIP_UNSOLICITED_TRANSACTION_TIMER:
|
|
subsmanager_unsolicited_notify_timeout(timerMsg->usrData);
|
|
break;
|
|
|
|
case SIP_NOTIFY_TIMER:
|
|
sip_regmgr_notify_timer_callback(timerMsg->usrData);
|
|
break;
|
|
|
|
case SIP_PASSTHROUGH_TIMER:
|
|
CCSIP_DEBUG_ERROR("%s: Pass Through Timer fired ! \n", fname);
|
|
break;
|
|
|
|
case SIP_REGALLFAIL_TIMER:
|
|
sip_regmgr_regallfail_timer_callback(timerMsg->usrData);
|
|
break;
|
|
|
|
default:
|
|
err_msg("%s: unknown timer %s\n", fname, timerMsg->expiredTimerName);
|
|
break;
|
|
}
|
|
return (returnCode);
|
|
}
|
|
|
|
|
|
/**
|
|
*
|
|
* SIPTaskProcessSIPMessage
|
|
*
|
|
* Process a received SIP message
|
|
*
|
|
* Parameters: pSipMessage - the SIP message
|
|
*
|
|
* Return Value: SIP_OK or SIP_ERROR
|
|
*
|
|
*/
|
|
static void
|
|
SIPTaskProcessSIPMessage (sipMessage_t *pSipMessage)
|
|
{
|
|
static const char *fname = "SIPTaskProcessSIPMessage";
|
|
sipSMEvent_t sip_sm_event;
|
|
ccsipCCB_t *reg_ccb = NULL,*ccb = NULL;
|
|
sipStatusCodeClass_t code_class = codeClassInvalid;
|
|
sipMethod_t method = sipMethodInvalid;
|
|
const char *pCallID = NULL;
|
|
line_t line_index = 1;
|
|
boolean is_request = FALSE;
|
|
int regConfigValue, response_code = 0;
|
|
int requestStatus = SIP_MESSAGING_ERROR;
|
|
char errortext[MAX_SIP_URL_LENGTH];
|
|
const char *cseq = NULL;
|
|
sipCseq_t *sipCseq = NULL;
|
|
uint16_t result_code = 0;
|
|
const char *max_fwd_hdr = NULL;
|
|
int32_t max_fwd_hdr_val;
|
|
int rc;
|
|
char tmp_str[STATUS_LINE_MAX_LEN];
|
|
sipSCB_t *scbp = NULL;
|
|
sipTCB_t *tcbp = NULL;
|
|
int scb_index;
|
|
//ccsip_event_data_t * evt_data_ptr = NULL;
|
|
|
|
sip_sm_event.u.pSipMessage = pSipMessage;
|
|
/*
|
|
* is_complete will be FALSE if we received fewer bytes than
|
|
* specified in the content_length field. If that happens, we
|
|
* want to return a 400 Bad Request message.
|
|
*/
|
|
if (!sippmh_is_message_complete(pSipMessage)) {
|
|
/* Send 400 error */
|
|
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
|
|
SIP_CLI_ERR_BAD_REQ_PHRASE,
|
|
SIP_WARN_MISC,
|
|
SIP_CLI_ERR_BAD_REQ_SDP_ERROR,
|
|
NULL) != TRUE) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
|
|
fname, SIP_CLI_ERR_BAD_REQ);
|
|
}
|
|
free_sip_message(pSipMessage);
|
|
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
|
|
fname, "sippmh_is_message_complete()");
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Determine Type, Method, and Call ID of this SIP message
|
|
* If the SIP message is a response, also get the response code.
|
|
*/
|
|
is_request = sippmh_is_request(pSipMessage);
|
|
if (is_request) {
|
|
/*
|
|
* Check the value of the max-forwards header - if present
|
|
*/
|
|
max_fwd_hdr = sippmh_get_header_val(pSipMessage,
|
|
SIP_HEADER_MAX_FORWARDS, NULL);
|
|
if (max_fwd_hdr) {
|
|
max_fwd_hdr_val = sippmh_parse_max_forwards(max_fwd_hdr);
|
|
if (max_fwd_hdr_val < 0) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Invalid Max Fwd Value detected\n",
|
|
fname);
|
|
/* Send 483 error */
|
|
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_MANY_HOPS,
|
|
SIP_CLI_ERR_MANY_HOPS_PHRASE,
|
|
SIP_WARN_MISC,
|
|
NULL, NULL) != TRUE) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
|
|
fname, SIP_CLI_ERR_BAD_REQ);
|
|
}
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
}
|
|
}
|
|
|
|
sipGetRequestMethod(pSipMessage, &method);
|
|
|
|
switch (method) {
|
|
case sipMethodInvalid:
|
|
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
|
|
fname, "sipGetResponseMethod");
|
|
/* Send 400 error */
|
|
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
|
|
SIP_CLI_ERR_BAD_REQ_PHRASE,
|
|
SIP_WARN_MISC,
|
|
SIP_CLI_ERR_BAD_REQ_METHOD_UNKNOWN,
|
|
NULL) != TRUE) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
|
|
fname, SIP_CLI_ERR_BAD_REQ);
|
|
}
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
|
|
case sipMethodUnknown:
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"SIP method not implemented\n", fname);
|
|
// Send 501 error
|
|
if (sipSPISendErrorResponse(pSipMessage, SIP_SERV_ERR_NOT_IMPLEM,
|
|
SIP_SERV_ERR_NOT_IMPLEM_PHRASE, 0,
|
|
NULL, NULL) != TRUE) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
|
|
fname, SIP_SERV_ERR_NOT_IMPLEM);
|
|
}
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
|
|
case sipMethodRegister:
|
|
case sipMethodPrack:
|
|
case sipMethodComet:
|
|
case sipMethodMessage:
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"SIP method not allowed\n", fname);
|
|
// Send 405 error
|
|
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_NOT_ALLOWED,
|
|
SIP_CLI_ERR_NOT_ALLOWED_PHRASE, 0,
|
|
NULL, NULL) != TRUE) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
|
|
fname, SIP_CLI_ERR_NOT_ALLOWED);
|
|
}
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
} else {
|
|
if (sipGetResponseMethod(pSipMessage, &method) < 0) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
|
|
fname, "sipGetResponseMethod");
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
}
|
|
if (sipGetResponseCode(pSipMessage, &response_code) < 0) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
|
|
fname, "sipGetResponseCode");
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
}
|
|
code_class = sippmh_get_code_class((uint16_t) response_code);
|
|
}
|
|
|
|
/* Get the CSeq */
|
|
cseq = sippmh_get_cached_header_val(pSipMessage, CSEQ);
|
|
if (!cseq) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unable to extract "
|
|
"CSeq from message.\n", fname);
|
|
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
|
|
SIP_CLI_ERR_BAD_REQ_PHRASE,
|
|
SIP_WARN_MISC,
|
|
SIP_CLI_ERR_BAD_REQ_VIA_OR_CSEQ,
|
|
NULL) != TRUE) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
|
|
fname, SIP_CLI_ERR_BAD_REQ);
|
|
}
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
}
|
|
sipCseq = sippmh_parse_cseq(cseq);
|
|
if (!sipCseq) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unable to parse "
|
|
"CSeq from message.\n", fname);
|
|
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
|
|
SIP_CLI_ERR_BAD_REQ_PHRASE,
|
|
SIP_WARN_MISC,
|
|
SIP_CLI_ERR_BAD_REQ_VIA_OR_CSEQ,
|
|
NULL) != TRUE) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
|
|
fname, SIP_CLI_ERR_BAD_REQ);
|
|
}
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
}
|
|
|
|
pCallID = sippmh_get_cached_header_val(pSipMessage, CALLID);
|
|
if (!pCallID) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Cannot obtain SIP Call ID.\n", fname);
|
|
/*
|
|
* Since we have no Call-ID, we can't create a response;
|
|
* therefore, we drop it.
|
|
*/
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Unsolicited NOTIFY processing
|
|
*/
|
|
if ((is_request) && (method == sipMethodNotify)) {
|
|
CCSIP_DEBUG_TASK(get_debug_string(DEBUG_SIP_MSG_RECV),
|
|
fname, SIP_METHOD_NOTIFY);
|
|
rc = SIPTaskProcessSIPNotify(pSipMessage);
|
|
if (rc != SIP_DEFER) {
|
|
if (rc != 0) {
|
|
// This Notify is in response to a previous SUBSCRIBE or REFER
|
|
(void) subsmanager_handle_ev_sip_subscribe_notify(pSipMessage);
|
|
}
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* SUBSCRIBE processing. Subscription requests received from the network,
|
|
* are processed here and do not interact with the main call processing
|
|
* states. All SUBSCRIBE requests and responses are directed to the
|
|
* subscription manager. However NOTIFY responses need to be testes to
|
|
* see whether the NOTIFY request was generated via CC or SM
|
|
*/
|
|
if ((is_request) && (method == sipMethodSubscribe)) {
|
|
|
|
config_get_value(CFGID_PROXY_REGISTER, ®ConfigValue, sizeof(regConfigValue));
|
|
|
|
reg_ccb = sip_sm_get_ccb_by_index(REG_CCB_START);
|
|
|
|
if ((regConfigValue == 0) || (reg_ccb && reg_ccb->reg.registered)) {
|
|
|
|
CCSIP_DEBUG_TASK(get_debug_string(DEBUG_SIP_MSG_RECV),
|
|
fname, SIP_METHOD_SUBSCRIBE);
|
|
(void) subsmanager_handle_ev_sip_subscribe(pSipMessage, method, FALSE);
|
|
} else {
|
|
if (sipSPISendErrorResponse(pSipMessage, SIP_SERV_ERR_INTERNAL,
|
|
SIP_SERV_ERR_INTERNAL_PHRASE,
|
|
0, NULL, NULL) != TRUE) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
|
|
fname, SIP_SERV_ERR_INTERNAL);
|
|
}
|
|
|
|
}
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
}
|
|
if (is_request == FALSE) {
|
|
switch (method) {
|
|
case sipMethodSubscribe:
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Recv Subs Response.\n",
|
|
DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname));
|
|
(void) subsmanager_handle_ev_sip_response(pSipMessage);
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
|
|
case sipMethodNotify:
|
|
scbp = find_scb_by_callid(pCallID, &scb_index);
|
|
if (scbp != NULL) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Recv Notify response\n",
|
|
DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname));
|
|
(void) subsmanager_handle_ev_sip_response(pSipMessage);
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
} else {
|
|
tcbp = find_tcb_by_sip_callid(pCallID);
|
|
if (tcbp != NULL) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Recv Unsolicited Notify response\n",
|
|
DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname));
|
|
(void) subsmanager_handle_ev_sip_unsolicited_notify_response(pSipMessage, tcbp);
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case sipMethodPublish:
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Recv PUBLISH Response.\n",
|
|
DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname));
|
|
(void) publish_handle_ev_sip_response(pSipMessage);
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
|
|
case sipMethodInfo:
|
|
// XXX FIXME see the comments in sipSPISendInfo()
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Recv INFO Response (silently dropped).\n",
|
|
DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname));
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
|
|
default:
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Determine which line this SIP message is for.
|
|
*/
|
|
result_code = sip_sm_determine_ccb(pCallID, sipCseq, pSipMessage,
|
|
is_request, &ccb);
|
|
if (result_code != 0) {
|
|
if (is_request) {
|
|
if (result_code == SIP_CLI_ERR_LOOP_DETECT) {
|
|
/* Send 482 error */
|
|
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_LOOP_DETECT,
|
|
SIP_CLI_ERR_LOOP_DETECT_PHRASE,
|
|
SIP_WARN_MISC,
|
|
NULL, NULL) != TRUE) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
|
|
fname, SIP_CLI_ERR_LOOP_DETECT);
|
|
}
|
|
} else {
|
|
/* Send 400 error */
|
|
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
|
|
SIP_CLI_ERR_BAD_REQ_PHRASE,
|
|
SIP_WARN_MISC,
|
|
NULL, NULL) != TRUE) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
|
|
fname, SIP_CLI_ERR_BAD_REQ);
|
|
}
|
|
}
|
|
} else { //is response
|
|
// This may be a response for a request generated via sub/not i/f
|
|
scbp = find_scb_by_callid(pCallID, &scb_index);
|
|
if (scbp != NULL) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Recv Refer Response.\n",
|
|
DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname));
|
|
(void) subsmanager_handle_ev_sip_response(pSipMessage);
|
|
} else {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sip_sm_determine_ccb(): "
|
|
"bad response. Dropping message.\n", fname);
|
|
}
|
|
}
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
}
|
|
|
|
if (ccb) {
|
|
sip_sm_event.ccb = ccb;
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Line filter: Call ID match: Destination line = "
|
|
"<%d/%d>.\n", DEB_F_PREFIX_ARGS(SIP_ID, fname), ccb->index, ccb->dn_line);
|
|
|
|
} else {
|
|
|
|
boolean is_previous_call_id = FALSE;
|
|
line_t previous_call_index = 0;
|
|
|
|
/*
|
|
* Unsolicited options processing
|
|
*/
|
|
if ((is_request) && (method == sipMethodOptions)) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"recv SIP OPTIONS (outside of dialog) message.\n",
|
|
DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname)); //
|
|
/*
|
|
* Send an options request to the gsm for this out of call
|
|
* options request. pSipMessage will be freed on return.
|
|
*/
|
|
sip_cc_options(CC_NO_CALL_ID, CC_NO_LINE, pSipMessage);
|
|
cpr_free(sipCseq);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Unsolicited INFO processing
|
|
*/
|
|
if ((is_request) && (method == sipMethodInfo)) {
|
|
CCSIP_DEBUG_ERROR("%s: Error: recv out-of-dialog SIP INFO message.\n", fname); //
|
|
/* Send 481 Call Leg/Transaction Does Not Exist */
|
|
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_CALLEG,
|
|
SIP_CLI_ERR_CALLEG_PHRASE,
|
|
0, NULL, NULL) != TRUE) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
|
|
fname, SIP_CLI_ERR_NOT_ALLOWED);
|
|
}
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
}
|
|
|
|
|
|
/* + If this is a request and method is INVITE, obtain
|
|
* the next available line and forward the request to
|
|
* that state machine. This is a new incoming call.
|
|
* + Otherwise, this message is spurious -- reject it.
|
|
* Do not accept an incoming INVITE for a new call
|
|
* if in quiet mode
|
|
*/
|
|
is_previous_call_id = sip_sm_is_previous_call_id(pCallID,
|
|
&previous_call_index);
|
|
if ((method == sipMethodInvite) && (is_request)) {
|
|
if (sip_mode_quiet) {
|
|
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_NOT_AVAIL,
|
|
SIP_CLI_ERR_NOT_AVAIL_PHRASE, 0,
|
|
NULL, NULL) != TRUE) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
|
|
fname, SIP_CLI_ERR_NOT_AVAIL);
|
|
}
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
}
|
|
else if (cprGetDepth(gsm_msgq) > MAX_DEPTH_OF_GSM_MSGQ_TO_ALLOW_NEW_INCOMING_CALL) {
|
|
/*
|
|
* CSCsz33584
|
|
* if gsm_msgq depth is larger than MAX_DEPTH_OF_GSM_MSGQ_TO_ALLOW_NEW_INCOMING_CALL,
|
|
* it's risky to accept new incoming call.
|
|
* just ignore the INVITE message to save CPU time so that the messages in gsm_msgq can be processed faster.
|
|
*/
|
|
CCSIP_DEBUG_ERROR(DEB_F_PREFIX"gsm msgq depth too large, drop incoming INVITEs!!!\n",
|
|
DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname));
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
}
|
|
|
|
ccb = sip_sm_get_ccb_next_available(&line_index);
|
|
if (!ccb) {
|
|
/* All lines are busy. Return 486 BUSY */
|
|
if (platGetPhraseText(STR_INDEX_NO_FREE_LINES,
|
|
(char *)tmp_str,
|
|
STATUS_LINE_MAX_LEN - 1) == CPR_SUCCESS) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Line filter: Call ID match not "
|
|
"found: INVITE: %s\n Sending 486 BUSY\n",
|
|
DEB_F_PREFIX_ARGS(SIP_ID, fname), tmp_str);
|
|
}
|
|
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BUSY_HERE,
|
|
SIP_CLI_ERR_BUSY_HERE_PHRASE, 0,
|
|
NULL, NULL) != TRUE) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
|
|
fname, SIP_CLI_ERR_BUSY_HERE);
|
|
}
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
}
|
|
sip_sm_event.ccb = ccb;
|
|
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Line filter: Call ID match not "
|
|
"found: INVITE: free ccb index = %d.\n",
|
|
DEB_F_PREFIX_ARGS(SIP_ID, fname), line_index);
|
|
|
|
} else if (is_previous_call_id && (method != sipMethodAck) &&
|
|
is_request) {
|
|
/*
|
|
* Detect whether the message is a non-ACK request addressing the
|
|
* previous call. If so, reTx the stored response.
|
|
*/
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Line filter: Previous Call ID.\n",
|
|
DEB_F_PREFIX_ARGS(SIP_ID, fname));
|
|
if (SipRelDevEnabled) {
|
|
if (SIPTaskRetransmitPreviousResponse(pSipMessage, fname,
|
|
pCallID, sipCseq, 0, TRUE) == SIP_OK) {
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
}
|
|
} else {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Line filter: Previous Call ID. "
|
|
"Reliable Delivery is OFF.\n", DEB_F_PREFIX_ARGS(SIP_ID, fname));
|
|
}
|
|
|
|
if (method == sipMethodBye) {
|
|
(void) sipSPISendErrorResponse(pSipMessage, 200,
|
|
SIP_SUCCESS_SETUP_PHRASE,
|
|
0, NULL, NULL);
|
|
} else {
|
|
(void) sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_CALLEG,
|
|
SIP_CLI_ERR_CALLEG_PHRASE,
|
|
0, NULL, NULL);
|
|
}
|
|
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
} else if (is_previous_call_id && (method == sipMethodAck) &&
|
|
is_request) {
|
|
/*
|
|
* Detect whether the message is an ACK addressing the previous
|
|
* call. If so, stop any outstanding reTx timers.
|
|
*/
|
|
if (SipRelDevEnabled) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Stopping any outstanding "
|
|
"reTx timers...\n", DEB_F_PREFIX_ARGS(SIP_TIMER, fname));
|
|
sip_sm_check_retx_timers(sip_sm_get_ccb_by_index(previous_call_index),
|
|
pSipMessage);
|
|
}
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Not forwarding response to SIP SM.\n",
|
|
DEB_F_PREFIX_ARGS(SIP_FWD, fname));
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
} else if (is_previous_call_id && (!is_request)) {
|
|
/*
|
|
* Detect whether the message is a response addressing the previous
|
|
* call. If the request is 200 OK, stop any outstanding reTx timers.
|
|
* This will prevent extraneous reTx of BYE/CANCEL messages at the
|
|
* the end of the call.
|
|
*/
|
|
if (SipRelDevEnabled) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Stopping any outstanding "
|
|
"reTx timers...\n", DEB_F_PREFIX_ARGS(SIP_TIMER, fname));
|
|
sip_sm_check_retx_timers(sip_sm_get_ccb_by_index(previous_call_index),
|
|
pSipMessage);
|
|
// Check for stored responses
|
|
if (SIPTaskRetransmitPreviousResponse(pSipMessage, fname,
|
|
pCallID, sipCseq,
|
|
response_code, FALSE) == SIP_OK) {
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
}
|
|
}
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Not forwarding response to SIP SM.\n",
|
|
DEB_F_PREFIX_ARGS(SIP_FWD, fname));
|
|
|
|
if (method == sipMethodBye) {
|
|
SIPTaskProcessSIPPreviousCallByeResponse(pSipMessage,
|
|
response_code,
|
|
previous_call_index);
|
|
}
|
|
if (method == sipMethodInvite) {
|
|
SIPTaskProcessSIPPreviousCallInviteResponse(pSipMessage,
|
|
response_code,
|
|
previous_call_index);
|
|
}
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
|
|
} else {
|
|
if (method == sipMethodRefer) {
|
|
if (is_request) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Received OOD Refer.\n",
|
|
DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname));
|
|
if (subsmanager_handle_ev_sip_subscribe(pSipMessage, sipMethodRefer, FALSE) != SIP_ERROR) {
|
|
// Successfully handled
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Successfully handled OOD Refer.\n",
|
|
DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname));
|
|
} else {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Not able to handle OOD Refer.\n",
|
|
DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname));
|
|
}
|
|
} else {
|
|
// This is a response to an OOD REFER generated via sub/not
|
|
// interface
|
|
scbp = find_scb_by_callid(pCallID, &scb_index);
|
|
if (scbp != NULL) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Recv Refer Response\n",
|
|
DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname));
|
|
(void) subsmanager_handle_ev_sip_response(pSipMessage);
|
|
}
|
|
}
|
|
} else {
|
|
if (SipRelDevEnabled) {
|
|
// Check for stored responses
|
|
if (SIPTaskRetransmitPreviousResponse(pSipMessage, fname,
|
|
pCallID, sipCseq,
|
|
response_code,
|
|
FALSE) == SIP_OK) {
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
}
|
|
}
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Line filter: Call ID match not "
|
|
"found: Rejecting.\n", DEB_F_PREFIX_ARGS(SIP_ID, fname));
|
|
if (is_request && (method != sipMethodAck)) {
|
|
/* Send 481 error */
|
|
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_CALLEG,
|
|
SIP_CLI_ERR_CALLEG_PHRASE,
|
|
0, NULL, NULL) != TRUE) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
|
|
fname, SIP_CLI_ERR_CALLEG);
|
|
}
|
|
}
|
|
}
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (is_request) {
|
|
/*
|
|
* Process request
|
|
*/
|
|
requestStatus = sipSPICheckRequest(ccb, pSipMessage);
|
|
switch (requestStatus) {
|
|
case SIP_MESSAGING_OK:
|
|
break;
|
|
|
|
case SIP_MESSAGING_NEW_CALLID:
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sipSPICheckRequest() returned "
|
|
"SIP_MESSAGING_NEW_CALLID.\n", fname);
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
|
|
case SIP_CLI_ERR_FORBIDDEN:
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sipSPICheckRequest() returned "
|
|
"SIP_CLI_ERR_FORBIDDEN.\n", fname);
|
|
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_FORBIDDEN,
|
|
SIP_CLI_ERR_FORBIDDEN_PHRASE,
|
|
0, NULL, NULL) != TRUE) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
|
|
fname, SIP_CLI_ERR_FORBIDDEN);
|
|
}
|
|
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
|
|
case SIP_MESSAGING_DUPLICATE:
|
|
if (method == sipMethodInvite) {
|
|
char test_mac[MAC_ADDR_STR_LENGTH];
|
|
uint8_t mac_addr[MAC_ADDRESS_LENGTH];
|
|
|
|
platform_get_wired_mac_address(mac_addr);
|
|
|
|
/*
|
|
* See if the call id has our mac address in it.
|
|
* If so, then we called ourselves. Report back busy.
|
|
*/
|
|
snprintf(test_mac, MAC_ADDR_STR_LENGTH, "%.4x%.4x-%.4x",
|
|
mac_addr[0] * 256 + mac_addr[1],
|
|
mac_addr[2] * 256 + mac_addr[3],
|
|
mac_addr[4] * 256 + mac_addr[5]);
|
|
if ((ccb->state == SIP_STATE_SENT_INVITE) &&
|
|
(strncmp(test_mac, ccb->sipCallID, 13) == 0)) {
|
|
get_sip_error_string(errortext, SIP_CLI_ERR_BUSY_HERE);
|
|
(void) sipSPISendErrorResponse(pSipMessage,
|
|
SIP_CLI_ERR_BUSY_HERE,
|
|
errortext, 0, NULL, NULL);
|
|
}
|
|
}
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
|
|
case SIP_SERV_ERR_INTERNAL:
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sipSPICheckRequest() returned "
|
|
"SIP_SERV_ERR_INTERNAL.\n", fname);
|
|
if (sipSPISendErrorResponse(pSipMessage, SIP_SERV_ERR_INTERNAL,
|
|
SIP_SERV_ERR_INTERNAL_PHRASE,
|
|
0, NULL, NULL) != TRUE) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
|
|
fname, SIP_SERV_ERR_INTERNAL);
|
|
}
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
|
|
case SIP_CLI_ERR_BAD_REQ:
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sipSPICheckRequest() returned "
|
|
"SIP_CLI_ERR_BAD_REQ.\n", fname);
|
|
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
|
|
SIP_CLI_ERR_BAD_REQ_PHRASE,
|
|
0, NULL, NULL) != TRUE) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
|
|
fname, SIP_CLI_ERR_BAD_REQ);
|
|
}
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
|
|
case SIP_MESSAGING_ERROR_UNSUPPORTED_MEDIA:
|
|
default:
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sipSPICheckRequest() "
|
|
"returned error.\n", fname);
|
|
/* Send error response */
|
|
if (method != sipMethodAck) {
|
|
if (requestStatus == SIP_MESSAGING_ERROR_UNSUPPORTED_MEDIA) {
|
|
requestStatus = SIP_CLI_ERR_MEDIA;
|
|
} else if (requestStatus == SIP_MESSAGING_ENDPOINT_NOT_FOUND) {
|
|
requestStatus = SIP_CLI_ERR_NOT_FOUND;
|
|
} else if (requestStatus == SIP_MESSAGING_NOT_ACCEPTABLE) {
|
|
requestStatus = SIP_CLI_ERR_NOT_ACCEPT;
|
|
} else if (requestStatus != SIP_CLI_ERR_CALLEG) {
|
|
requestStatus = 400;
|
|
}
|
|
get_sip_error_string(errortext, requestStatus);
|
|
if (sipSPISendErrorResponse(pSipMessage, (uint16_t)requestStatus,
|
|
errortext, 0, NULL, NULL) != TRUE) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
|
|
fname, SIP_CLI_ERR_BAD_REQ);
|
|
}
|
|
if (method == sipMethodInvite) {
|
|
ccb->wait_for_ack = TRUE;
|
|
}
|
|
}
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
}
|
|
|
|
switch (method) {
|
|
case sipMethodInvite:
|
|
CCSIP_DEBUG_TASK(get_debug_string(DEBUG_SIP_MSG_RECV),
|
|
fname, SIP_METHOD_INVITE);
|
|
sip_sm_event.type = E_SIP_INVITE;
|
|
break;
|
|
|
|
case sipMethodAck:
|
|
CCSIP_DEBUG_TASK(get_debug_string(DEBUG_SIP_MSG_RECV),
|
|
fname, SIP_METHOD_ACK);
|
|
sip_sm_check_retx_timers(ccb, pSipMessage);
|
|
sip_sm_event.type = E_SIP_ACK;
|
|
break;
|
|
|
|
case sipMethodBye:
|
|
CCSIP_DEBUG_TASK(get_debug_string(DEBUG_SIP_MSG_RECV),
|
|
fname, SIP_METHOD_BYE);
|
|
sip_sm_event.type = E_SIP_BYE;
|
|
break;
|
|
|
|
case sipMethodCancel:
|
|
CCSIP_DEBUG_TASK(get_debug_string(DEBUG_SIP_MSG_RECV),
|
|
fname, SIP_METHOD_CANCEL);
|
|
sip_sm_event.type = E_SIP_CANCEL;
|
|
break;
|
|
|
|
case sipMethodSubscribe:
|
|
CCSIP_DEBUG_TASK(get_debug_string(DEBUG_SIP_MSG_RECV),
|
|
fname, SIP_METHOD_SUBSCRIBE);
|
|
sip_sm_event.type = E_SIP_SUBSCRIBE;
|
|
break;
|
|
|
|
case sipMethodNotify:
|
|
CCSIP_DEBUG_TASK(get_debug_string(DEBUG_SIP_MSG_RECV),
|
|
fname, SIP_METHOD_NOTIFY);
|
|
sip_sm_event.type = E_SIP_NOTIFY;
|
|
break;
|
|
|
|
case sipMethodRefer:
|
|
CCSIP_DEBUG_TASK(get_debug_string(DEBUG_SIP_MSG_RECV),
|
|
fname, SIP_METHOD_REFER);
|
|
sip_sm_event.type = E_SIP_REFER;
|
|
break;
|
|
case sipMethodOptions:
|
|
CCSIP_DEBUG_TASK(get_debug_string(DEBUG_SIP_MSG_RECV),
|
|
fname, SIP_METHOD_OPTIONS);
|
|
sip_sm_event.type = E_SIP_OPTIONS;
|
|
break;
|
|
case sipMethodUpdate:
|
|
CCSIP_DEBUG_TASK(get_debug_string(DEBUG_SIP_MSG_RECV),
|
|
fname, SIP_METHOD_UPDATE);
|
|
sip_sm_event.type = E_SIP_UPDATE;
|
|
break;
|
|
case sipMethodInfo:
|
|
CCSIP_DEBUG_TASK(get_debug_string(DEBUG_SIP_MSG_RECV),
|
|
fname, SIP_METHOD_INFO);
|
|
(void) ccsip_handle_info_package(ccb, pSipMessage);
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
break;
|
|
default:
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Received unknown SIP request message.\n",
|
|
DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname));
|
|
/* The message must be deallocated here */
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
}
|
|
} else {
|
|
int responseStatus = SIP_MESSAGING_ERROR;
|
|
|
|
/*
|
|
* Process response
|
|
*/
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Received SIP response.\n",
|
|
DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname));
|
|
responseStatus = sipSPICheckResponse(ccb, pSipMessage);
|
|
if (responseStatus != SIP_MESSAGING_OK) {
|
|
if (responseStatus == SIP_MESSAGING_DUPLICATE) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Duplicate response detected. "
|
|
"Discarding...\n", DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname));
|
|
} else if (responseStatus == SIP_MESSAGING_ERROR_STALE_RESP) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Stale response detected. "
|
|
"Discarding...\n", DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname));
|
|
} else if (responseStatus == SIP_MESSAGING_ERROR_NO_TRX) {
|
|
// This may be a response for a request generated via sub/not i/f
|
|
scbp = find_scb_by_callid(pCallID, &scb_index);
|
|
if (scbp != NULL) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Recv Refer Response.\n",
|
|
DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname));
|
|
(void) subsmanager_handle_ev_sip_response(pSipMessage);
|
|
}
|
|
} else {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sipSPICheckResponse() "
|
|
"returned error. Discarding response\n",
|
|
fname);
|
|
}
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
}
|
|
|
|
/* Response is ok. Cancel the outstanding reTx timer if any */
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Stopping any outstanding reTx "
|
|
"timers...\n", DEB_F_PREFIX_ARGS(SIP_TIMER, fname));
|
|
sip_sm_check_retx_timers(ccb, pSipMessage);
|
|
|
|
/* got a response, re-set re-transmit flag */
|
|
ccb->retx_flag = FALSE;
|
|
ccb->last_recvd_response_code = response_code;
|
|
/*
|
|
* TEL_CCB_START equates to zero and line_t is an unsigned type,
|
|
* so just check the end condition
|
|
*/
|
|
if (ccb->index <= TEL_CCB_END) {
|
|
gCallHistory[ccb->index].last_rspcode_rcvd = code_class;
|
|
}
|
|
|
|
switch (code_class) {
|
|
case codeClass1xx:
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Recv 1xx message.\n",
|
|
DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname));
|
|
sip_sm_event.type = E_SIP_1xx;
|
|
break;
|
|
|
|
case codeClass2xx:
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Recv 2xx message.\n",
|
|
DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname));
|
|
sip_sm_event.type = E_SIP_2xx;
|
|
break;
|
|
|
|
case codeClass3xx:
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Recv 3xx message.\n",
|
|
DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname));
|
|
sip_sm_event.type = E_SIP_3xx;
|
|
break;
|
|
|
|
case codeClass4xx:
|
|
case codeClass5xx:
|
|
case codeClass6xx:
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Recv 4xx/5xx/6xx message.\n",
|
|
DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname));
|
|
sip_sm_event.type = E_SIP_FAILURE_RESPONSE;
|
|
switch (response_code) {
|
|
case SIP_CLI_ERR_UNAUTH:
|
|
case SIP_CLI_ERR_PROXY_REQD:
|
|
if (sipCseq->method == sipMethodAck) {
|
|
sipSPISendFailureResponseAck(ccb, pSipMessage, FALSE, 0);
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
/* unknown response, keep re-transmitting */
|
|
ccb->retx_flag = TRUE;
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unknown response class.\n", fname);
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
}
|
|
// Change the event type for the UPDATE method since there is only one
|
|
// handler for this
|
|
if (method == sipMethodUpdate) {
|
|
sip_sm_event.type = E_SIP_UPDATE_RESPONSE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Send event to the SIP SM or the SIP REGISTRATION SM
|
|
*/
|
|
if (sip_sm_event.ccb->type == SIP_REG_CCB) {
|
|
sip_sm_event.type = (sipSMEventType_t)
|
|
ccsip_register_sip2sipreg_event(sip_sm_event.type);
|
|
|
|
if ((!is_request) && ((code_class == codeClass5xx) ||
|
|
(code_class == codeClass6xx))) {
|
|
sip_sm_event.type = (sipSMEventType_t) E_SIP_REG_FAILURE_RESPONSE;
|
|
}
|
|
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Register response does not have a body %d\n",
|
|
DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname),
|
|
(pSipMessage->mesg_body[0].msgBody == NULL) ? -1: pSipMessage->mesg_body[0].msgContentTypeValue);
|
|
|
|
if (sip_sm_event.type != (int) E_SIP_REG_NONE) {
|
|
if (sip_reg_sm_process_event(&sip_sm_event) < 0) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(REG_SM_PROCESS_EVENT_ERROR), fname, sip_sm_event.type);
|
|
if (is_request && (method != sipMethodAck)) {
|
|
/* Send 500 error */
|
|
if (sipSPISendErrorResponse(pSipMessage, 500,
|
|
SIP_SERV_ERR_INTERNAL_PHRASE, 0,
|
|
NULL, NULL) != TRUE) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
|
|
fname, SIP_SERV_ERR_INTERNAL);
|
|
}
|
|
}
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
} else {
|
|
cpr_free(sipCseq);
|
|
return;
|
|
}
|
|
}
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Ignoring non-register event= %d\n",
|
|
DEB_F_PREFIX_ARGS(SIP_EVT, fname), sip_sm_event.type);
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
}
|
|
|
|
if (sip_sm_process_event(&sip_sm_event) < 0) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sip_sm_process_event() returned "
|
|
"error.\n", fname);
|
|
if (is_request && (method != sipMethodAck)) {
|
|
/* Send 500 error */
|
|
if (sipSPISendErrorResponse(pSipMessage, 500,
|
|
SIP_SERV_ERR_INTERNAL_PHRASE, 0,
|
|
NULL, NULL) != TRUE) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
|
|
fname, SIP_SERV_ERR_INTERNAL);
|
|
}
|
|
}
|
|
cpr_free(sipCseq);
|
|
free_sip_message(pSipMessage);
|
|
return;
|
|
}
|
|
|
|
cpr_free(sipCseq);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* SIPTaskProcessConfigChangeNotify
|
|
*
|
|
* ???
|
|
*
|
|
* Parameters: ???
|
|
*
|
|
* Return Value: zero(0)
|
|
*
|
|
*/
|
|
int
|
|
SIPTaskProcessConfigChangeNotify (int32_t notify_type)
|
|
{
|
|
static const char *fname = "SIPTaskProcessConfigChangeNotify";
|
|
int retval = 0;
|
|
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Notify received type=%d\n",
|
|
DEB_F_PREFIX_ARGS(SIP_NOTIFY, fname), notify_type);
|
|
|
|
if (notify_type & AA_RELOAD) {
|
|
if ((PHNGetState() == STATE_CONNECTED) ||
|
|
(PHNGetState() == STATE_UNPROVISIONED)) {
|
|
/*
|
|
* If the phone state isn't in STATE_CONNECTED then this change
|
|
* notify is being called because of bootup and not just a SIP
|
|
* menu configuration hang. We only want to handle updates
|
|
* to the number of lines if the phone is already connected,
|
|
* the other case, booting, is handled by the boot code
|
|
*/
|
|
(void) sipTransportInit();
|
|
|
|
/* need to unregister the phone */
|
|
ccsip_register_cancel(FALSE, TRUE);
|
|
ccsip_register_reset_proxy();
|
|
(void) sip_platform_ui_restart();
|
|
} else {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"PHNGetState() is not in STATE_CONNECTED, "
|
|
"bypassing restart\n", fname);
|
|
}
|
|
} else if (notify_type & AA_REGISTER) {
|
|
ccsip_register_commit();
|
|
} else if (notify_type & AA_BU_REG) {
|
|
(void) sipTransportInit();
|
|
ccsip_backup_register_commit();
|
|
}
|
|
|
|
return (retval);
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
*
|
|
* SIPTaskProcessSIPNotify
|
|
*
|
|
* The function processes the unsolicited NOTIFY.
|
|
*
|
|
* Parameters: pSipMessage - pointer to sipMessage_t.
|
|
*
|
|
* Return Value: SIP_OK, SIP_ERROR, SIP_DEFER.
|
|
*
|
|
* Note: The parameter pSipMessage is expected by the caller to be
|
|
* preserved i.e. it can not be freed by this
|
|
* function or the functions called by this function.
|
|
*/
|
|
static int
|
|
SIPTaskProcessSIPNotify (sipMessage_t *pSipMessage)
|
|
{
|
|
static const char *fname = "SIPTaskProcessSIPNotify";
|
|
sipReqLine_t *requestURI = NULL;
|
|
char *pRequestURIUserStr = NULL;
|
|
boolean request_uri_error = TRUE;
|
|
line_t i = 0;
|
|
line_t dn_line = 0;
|
|
const char *event = NULL;
|
|
sipLocation_t *uri_loc = NULL;
|
|
char line_name[MAX_LINE_NAME_SIZE];
|
|
char line_contact[MAX_LINE_CONTACT_SIZE];
|
|
const char *to = NULL;
|
|
sipLocation_t *to_loc = NULL;
|
|
sipUrl_t *sipToUrl = NULL;
|
|
boolean to_header_error = TRUE;
|
|
char *pUser = NULL;
|
|
|
|
|
|
/*
|
|
* Parse the Event header
|
|
*/
|
|
event = sippmh_get_header_val(pSipMessage, SIP_HEADER_EVENT,
|
|
SIP_C_HEADER_EVENT);
|
|
|
|
if (event == NULL) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Missing Event header\n", fname);
|
|
(void) sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
|
|
SIP_CLI_ERR_BAD_REQ_PHRASE,
|
|
0, NULL, NULL);
|
|
return SIP_OK;
|
|
}
|
|
|
|
/*
|
|
* Find the destination DN
|
|
*/
|
|
requestURI = sippmh_get_request_line(pSipMessage);
|
|
if (requestURI) {
|
|
if (requestURI->url) {
|
|
uri_loc = sippmh_parse_from_or_to(requestURI->url, TRUE);
|
|
if (uri_loc) {
|
|
if (uri_loc->genUrl->schema == URL_TYPE_SIP) {
|
|
if (uri_loc->genUrl->u.sipUrl->user) {
|
|
pRequestURIUserStr = uri_loc->genUrl->u.sipUrl->user;
|
|
request_uri_error = FALSE;
|
|
} else {
|
|
sippmh_free_location(uri_loc);
|
|
SIPPMH_FREE_REQUEST_LINE(requestURI);
|
|
}
|
|
} else {
|
|
sippmh_free_location(uri_loc);
|
|
SIPPMH_FREE_REQUEST_LINE(requestURI);
|
|
}
|
|
} else {
|
|
SIPPMH_FREE_REQUEST_LINE(requestURI);
|
|
}
|
|
} else {
|
|
SIPPMH_FREE_REQUEST_LINE(requestURI);
|
|
}
|
|
}
|
|
|
|
if (request_uri_error) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"NOTIFY has error in Req-URI!\n", fname);
|
|
(void) sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
|
|
SIP_CLI_ERR_BAD_REQ_PHRASE,
|
|
SIP_WARN_MISC,
|
|
SIP_CLI_ERR_BAD_REQ_REQLINE_ERROR, NULL);
|
|
return SIP_OK;
|
|
}
|
|
|
|
if (cpr_strncasecmp(event, "refer", 5) == 0) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"NOTIFY: refer\n", DEB_F_PREFIX_ARGS(SIP_NOTIFY, fname));
|
|
SIPTaskProcessSIPNotifyRefer(pSipMessage);
|
|
sippmh_free_location(uri_loc);
|
|
SIPPMH_FREE_REQUEST_LINE(requestURI);
|
|
return SIP_OK;
|
|
}
|
|
|
|
for (i = 1; i <= 1; i++) {
|
|
if (sip_config_check_line(i)) {
|
|
config_get_string((CFGID_LINE_NAME + i - 1), line_name, sizeof(line_name));
|
|
config_get_string((CFGID_LINE_CONTACT + i - 1), line_contact, sizeof(line_contact));
|
|
if ((sippmh_cmpURLStrings(pRequestURIUserStr, line_name, TRUE) == 0) ||
|
|
(sippmh_cmpURLStrings(pRequestURIUserStr, line_contact, TRUE) == 0)) {
|
|
dn_line = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dn_line == 0) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"NOTIFY has unknown user in Req-URI!\n",
|
|
fname);
|
|
(void) sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_NOT_FOUND,
|
|
SIP_CLI_ERR_NOT_FOUND_PHRASE,
|
|
0, NULL, NULL);
|
|
sippmh_free_location(uri_loc);
|
|
SIPPMH_FREE_REQUEST_LINE(requestURI);
|
|
return SIP_OK;
|
|
}
|
|
|
|
sippmh_free_location(uri_loc);
|
|
SIPPMH_FREE_REQUEST_LINE(requestURI);
|
|
|
|
/*
|
|
* Sanity check To header by parsing the header. Note it is not used, just sanitized.
|
|
*/
|
|
to = sippmh_get_cached_header_val(pSipMessage, TO);
|
|
if (to) {
|
|
to_loc = sippmh_parse_from_or_to((char *)to, TRUE);
|
|
if (to_loc) {
|
|
if (to_loc->genUrl->schema == URL_TYPE_SIP) {
|
|
sipToUrl = to_loc->genUrl->u.sipUrl;
|
|
if (sipToUrl) {
|
|
if (sipToUrl->user) {
|
|
pUser = sippmh_parse_user(sipToUrl->user);
|
|
if (pUser) {
|
|
if (pUser[0] != '\0') {
|
|
// To header is good.
|
|
to_header_error = FALSE;
|
|
}
|
|
cpr_free(pUser);
|
|
}
|
|
}
|
|
}
|
|
sippmh_free_location(to_loc);
|
|
} else {
|
|
sippmh_free_location(to_loc);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (to_header_error) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"NOTIFY has error in To header\n", fname);
|
|
(void) sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
|
|
SIP_CLI_ERR_BAD_REQ_PHRASE,
|
|
SIP_WARN_MISC,
|
|
SIP_CLI_ERR_BAD_REQ_ToURL_ERROR, NULL);
|
|
return SIP_OK;
|
|
}
|
|
|
|
/*
|
|
* Request-URI and To header check out. Check Event to determine which
|
|
* Notify function to invoke.
|
|
*/
|
|
if ((cpr_strcasecmp(event, "message-summary") == 0) ||
|
|
(cpr_strcasecmp(event, "simple-message-summary") == 0)) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"NOTIFY: MWI\n", DEB_F_PREFIX_ARGS(SIP_NOTIFY, fname));
|
|
if (SIPTaskProcessSIPNotifyMWI(pSipMessage, dn_line) != 0) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Bad MWI NOTIFY!\n", fname);
|
|
(void) sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
|
|
SIP_CLI_ERR_BAD_REQ_PHRASE,
|
|
SIP_WARN_MISC,
|
|
"Bad MWI NOTIFY", NULL);
|
|
return SIP_OK;
|
|
}
|
|
} else if (cpr_strcasecmp(event, "check-sync") == 0) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"NOTIFY: check-sync\n", DEB_F_PREFIX_ARGS(SIP_NOTIFY, fname));
|
|
SIPTaskProcessSIPNotifyCheckSync(pSipMessage);
|
|
} else if (cpr_strcasecmp(event, "service-control") == 0) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"NOTIFY: service-control\n", DEB_F_PREFIX_ARGS(SIP_NOTIFY, fname));
|
|
return SIPTaskProcessSIPNotifyServiceControl(pSipMessage);
|
|
} else if (cpr_strcasecmp(event, SIP_EVENT_DIALOG) == 0) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"NOTIFY: %s\n", DEB_F_PREFIX_ARGS(SIP_NOTIFY, fname), SIP_EVENT_DIALOG);
|
|
return (2);
|
|
} else if (cpr_strcasecmp(event, SIP_EVENT_CONFIG) == 0) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"NOTIFY: %s\n", DEB_F_PREFIX_ARGS(SIP_NOTIFY, fname), SIP_EVENT_CONFIG);
|
|
return (2);
|
|
} else if (cpr_strcasecmp(event, SIP_EVENT_KPML) == 0) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"NOTIFY: %s\n", DEB_F_PREFIX_ARGS(SIP_NOTIFY, fname), SIP_EVENT_KPML);
|
|
return (2);
|
|
} else if (cpr_strcasecmp(event, SIP_EVENT_PRESENCE) == 0) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"NOTIFY: %s\n", DEB_F_PREFIX_ARGS(SIP_NOTIFY, fname), SIP_EVENT_PRESENCE);
|
|
return (2);
|
|
} else {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unrecognized Event header\n", fname);
|
|
(void) sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
|
|
SIP_CLI_ERR_BAD_REQ_PHRASE,
|
|
0, NULL, NULL);
|
|
}
|
|
|
|
return SIP_OK;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* SIPTaskProcessSIPNotifyMWI
|
|
*
|
|
* ???
|
|
*
|
|
* Parameters: ???
|
|
*
|
|
* Return Value: SIP_OK or SIP_ERROR
|
|
*
|
|
*/
|
|
static int
|
|
SIPTaskProcessSIPNotifyMWI (sipMessage_t* pSipMessage, line_t dn_line)
|
|
{
|
|
sipMessageSummary_t mesgSummary;
|
|
|
|
if (!pSipMessage->mesg_body[0].msgBody ||
|
|
(pSipMessage->mesg_body[0].msgContentTypeValue != SIP_CONTENT_TYPE_MWI_VALUE &&
|
|
pSipMessage->mesg_body[0].msgContentTypeValue != SIP_CONTENT_TYPE_TEXT_PLAIN_VALUE)) {
|
|
return SIP_ERROR;
|
|
}
|
|
|
|
memset(&mesgSummary, 0, sizeof(sipMessageSummary_t));
|
|
|
|
if (sippmh_parse_message_summary(pSipMessage, &mesgSummary) < 0) {
|
|
return SIP_ERROR;
|
|
}
|
|
|
|
sip_cc_mwi(CC_NO_CALL_ID, dn_line, mesgSummary.mesg_waiting_on, mesgSummary.type,
|
|
mesgSummary.newCount, mesgSummary.oldCount, mesgSummary.hpNewCount, mesgSummary.hpOldCount);
|
|
|
|
/*
|
|
* Send 200 OK back
|
|
*/
|
|
(void) sipSPISendErrorResponse(pSipMessage, 200, SIP_SUCCESS_SETUP_PHRASE,
|
|
0, NULL, NULL);
|
|
|
|
return SIP_OK;
|
|
}
|
|
/**
|
|
*
|
|
* SIPTaskProcessSIPNotifyRefer
|
|
*
|
|
* The function processes NOTIFY refer.
|
|
*
|
|
* Parameters: pSipMessage - pointer to the sipMessage_t.
|
|
*
|
|
* Return Value: None
|
|
*
|
|
*/
|
|
static void
|
|
SIPTaskProcessSIPNotifyRefer (sipMessage_t *pSipMessage)
|
|
{
|
|
static const char *fname = "SIPTaskProcessSIPNotifyRefer";
|
|
ccsipCCB_t *ccb = NULL;
|
|
const char *pCallID = NULL;
|
|
sipSCB_t *scbp = NULL;
|
|
int scb_index;
|
|
|
|
pCallID = sippmh_get_cached_header_val(pSipMessage, CALLID);
|
|
if (!pCallID) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Cannot obtain SIP Call ID.\n", fname);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Determine which line this SIP message is for.
|
|
*/
|
|
ccb = sip_sm_get_ccb_by_callid(pCallID);
|
|
if (ccb) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Line filter: Call ID match: Destination line = "
|
|
"<%d/%d>.\n", DEB_F_PREFIX_ARGS(SIP_ID, fname), ccb->index, ccb->dn_line);
|
|
} else {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"ccb is NULL\n", fname);
|
|
// Check if this should be sent to the SM by looking up its callid
|
|
// If found, the we return from here
|
|
scbp = find_scb_by_callid(pCallID, &scb_index);
|
|
if (scbp != NULL) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Recv Notify.\n", DEB_F_PREFIX_ARGS(SIP_NOTIFY, fname));
|
|
(void) subsmanager_handle_ev_sip_subscribe_notify(pSipMessage);
|
|
return;
|
|
}
|
|
}
|
|
(void) sipSPISendErrorResponse(pSipMessage, 200, SIP_SUCCESS_SETUP_PHRASE,
|
|
0, NULL, NULL);
|
|
|
|
if (NULL != ccb) {
|
|
cc_feature_data_t data;
|
|
|
|
/* for some reason pingtel decided they were going to send
|
|
* Notify messages with call progression in the body. Let's
|
|
* just send the 200 back for these and not process them.
|
|
* We should only process a Notify with a final response
|
|
* in the body (ie. 200, 3xx, 4xx, 5xx, 6xx).
|
|
*/
|
|
if (pSipMessage->mesg_body[0].msgBody == NULL) {
|
|
data.notify.cause = CC_CAUSE_OK;
|
|
|
|
if (fsmxfr_get_xcb_by_call_id(ccb->gsm_id) &&
|
|
(fsmxfr_get_xfr_type(ccb->gsm_id) == FSMXFR_TYPE_BLND_XFR)) {
|
|
data.notify.cause = CC_CAUSE_ERROR;
|
|
data.notify.method = CC_XFER_METHOD_REFER;
|
|
}
|
|
} else if ((strstr(pSipMessage->mesg_body[0].msgBody, "100")) ||
|
|
(strstr(pSipMessage->mesg_body[0].msgBody, "180")) ||
|
|
(strstr(pSipMessage->mesg_body[0].msgBody, "181")) ||
|
|
(strstr(pSipMessage->mesg_body[0].msgBody, "182")) ||
|
|
(strstr(pSipMessage->mesg_body[0].msgBody, "183"))) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Ignoring Notify w/Progression\n",
|
|
DEB_F_PREFIX_ARGS(SIP_NOTIFY, fname));
|
|
return;
|
|
} else if (strstr(pSipMessage->mesg_body[0].msgBody, "200")) {
|
|
data.notify.cause = CC_CAUSE_OK;
|
|
data.notify.method = CC_XFER_METHOD_REFER;
|
|
} else {
|
|
data.notify.cause = CC_CAUSE_ERROR;
|
|
data.notify.method = CC_XFER_METHOD_REFER;
|
|
}
|
|
data.notify.subscription = CC_SUBSCRIPTIONS_XFER;
|
|
data.notify.blind_xferror_gsm_id = 0;
|
|
sip_cc_feature(ccb->gsm_id, ccb->dn_line, CC_FEATURE_NOTIFY,
|
|
(void *)&data);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
*
|
|
* SIPTaskProcessSIPNotifyCheckSync
|
|
*
|
|
* ???
|
|
*
|
|
* Parameters: pSipMessage -
|
|
*
|
|
* Return Value: None
|
|
*
|
|
*/
|
|
static void
|
|
SIPTaskProcessSIPNotifyCheckSync (sipMessage_t *pSipMessage)
|
|
{
|
|
/*
|
|
* Send 200 OK back
|
|
*/
|
|
(void) sipSPISendErrorResponse(pSipMessage, 200, SIP_SUCCESS_SETUP_PHRASE,
|
|
0, NULL, NULL);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* SIPTaskProcessSIPNotifyServiceControl
|
|
*
|
|
* Handles an incoming unsolicited NOTIFY service control message
|
|
*
|
|
* Parameters: Incoming pSipMessage
|
|
*
|
|
* Return Value: SIP_OK if request processed.
|
|
* SIP_DEFER if request is deferred for processing
|
|
* by ccsip_core.c.
|
|
*
|
|
*/
|
|
static int
|
|
SIPTaskProcessSIPNotifyServiceControl (sipMessage_t *pSipMessage)
|
|
{
|
|
const char *fname = "SIPTaskProcessSIPNotifyServiceControl";
|
|
sipServiceControl_t *scp;
|
|
int rc = SIP_OK;
|
|
|
|
scp = ccsip_get_notify_service_control(pSipMessage);
|
|
|
|
if (scp != NULL) {
|
|
// The platform code should not alter scp or its fields
|
|
if (scp->action == SERVICE_CONTROL_ACTION_CALL_PRESERVATION) {
|
|
rc = SIP_DEFER;
|
|
} else {
|
|
if (sipSPISendErrorResponse(pSipMessage, 200,
|
|
SIP_SUCCESS_SETUP_PHRASE,
|
|
0, NULL, NULL) != TRUE) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
|
|
fname, SIP_SUCCESS_SETUP);
|
|
}
|
|
|
|
// Hand over the event to platform
|
|
sip_platform_handle_service_control_notify(scp);
|
|
}
|
|
sippmh_free_service_control_info(scp);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* SIPTaskProcessSIPPreviousCallByeResponse
|
|
*
|
|
* ???
|
|
*
|
|
* Parameters: pResponse -
|
|
* response_code -
|
|
* previous_call_index -
|
|
*
|
|
* Return Value: None
|
|
*
|
|
*/
|
|
static void
|
|
SIPTaskProcessSIPPreviousCallByeResponse (sipMessage_t *pResponse,
|
|
int response_code,
|
|
line_t previous_call_index)
|
|
{
|
|
static const char *fname = "SIPTaskProcessSIPPreviousCallByeResponse";
|
|
uint32_t responseCSeqNumber = 0;
|
|
sipMethod_t responseCSeqMethod = sipMethodInvalid;
|
|
boolean bad_authentication = FALSE;
|
|
credentials_t credentials;
|
|
sipAuthenticate_t authen;
|
|
const char *authenticate = NULL;
|
|
int nc_count = 0;
|
|
|
|
memset(&authen, 0, sizeof(authen)); // Initialize
|
|
|
|
switch (response_code) {
|
|
case SIP_CLI_ERR_UNAUTH:
|
|
case SIP_CLI_ERR_PROXY_REQD:
|
|
/* Check CSeq */
|
|
if (sipGetMessageCSeq(pResponse, &responseCSeqNumber,
|
|
&responseCSeqMethod) < 0) {
|
|
return;
|
|
}
|
|
if (responseCSeqNumber !=
|
|
gCallHistory[previous_call_index].last_bye_cseq_number) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"CSeq# mismatch: BYE CSeq=%d, "
|
|
"%d CSeq:%d\n", fname,
|
|
gCallHistory[previous_call_index].last_bye_cseq_number,
|
|
response_code, responseCSeqNumber);
|
|
return;
|
|
}
|
|
|
|
/* Obtain credentials */
|
|
cred_get_line_credentials(gCallHistory[previous_call_index].dn_line,
|
|
&credentials,
|
|
sizeof(credentials.id),
|
|
sizeof(credentials.pw));
|
|
/* Compute Authentication information */
|
|
authenticate = sippmh_get_header_val(pResponse,
|
|
AUTH_HDR(response_code), NULL);
|
|
if (authenticate != NULL) {
|
|
sip_authen_t *sip_authen = NULL;
|
|
|
|
sip_authen = sippmh_parse_authenticate(authenticate);
|
|
if (sip_authen) {
|
|
char *author_str = NULL;
|
|
|
|
if (sipSPIGenerateAuthorizationResponse(sip_authen,
|
|
gCallHistory[previous_call_index].
|
|
last_route_request_uri,
|
|
SIP_METHOD_BYE,
|
|
credentials.id,
|
|
credentials.pw,
|
|
&author_str,
|
|
&nc_count, NULL)) {
|
|
if (author_str != NULL)
|
|
{
|
|
authen.authorization = (char *)
|
|
cpr_malloc(strlen(author_str) * sizeof(char) + 1);
|
|
if (authen.authorization != NULL) {
|
|
sstrncpy(authen.authorization, author_str,
|
|
strlen(author_str) * sizeof(char) + 1);
|
|
authen.status_code = response_code;
|
|
} else {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"malloc() failed "
|
|
"for authen.authorization\n", fname);
|
|
bad_authentication = TRUE;
|
|
}
|
|
cpr_free(author_str);
|
|
} else {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"author_str returned by sipSPIGenerateAuthorizationResponse"
|
|
"is NULL", fname);
|
|
bad_authentication = TRUE;
|
|
}
|
|
} else {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sipSPIGenerateAuthorizationResponse()"
|
|
" returned null.\n", fname);
|
|
bad_authentication = TRUE;
|
|
}
|
|
sippmh_free_authen(sip_authen);
|
|
} else {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sippmh_parse_authenticate() "
|
|
"returned null.\n", fname);
|
|
bad_authentication = TRUE;
|
|
}
|
|
} else {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sippmh_get_header_val(AUTH_HDR) "
|
|
"returned null.\n", fname);
|
|
bad_authentication = TRUE;
|
|
}
|
|
|
|
if (bad_authentication) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Bad authentication header "
|
|
"in %d\n", fname, response_code);
|
|
if (authen.authorization)
|
|
cpr_free(authen.authorization);
|
|
return;
|
|
}
|
|
|
|
/* Resend BYE with authorization */
|
|
(void) sipSPISendByeAuth(pResponse,
|
|
authen,
|
|
&(gCallHistory[previous_call_index].last_bye_dest_ipaddr),
|
|
gCallHistory[previous_call_index].last_bye_dest_port,
|
|
++gCallHistory[previous_call_index].last_bye_cseq_number,
|
|
gCallHistory[previous_call_index].last_bye_also_string,
|
|
gCallHistory[previous_call_index].last_route,
|
|
gCallHistory[previous_call_index].last_route_request_uri,
|
|
previous_call_index);
|
|
if (authen.authorization) {
|
|
cpr_free(authen.authorization);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* SIPTaskProcessSIPPreviousCallInviteResponse
|
|
*
|
|
* ???
|
|
*
|
|
* Parameters: pResponse -
|
|
* response_code -
|
|
* previous_call_index -
|
|
*
|
|
* Return Value: None
|
|
*
|
|
*/
|
|
static void
|
|
SIPTaskProcessSIPPreviousCallInviteResponse (sipMessage_t *pResponse,
|
|
int response_code,
|
|
line_t previous_call_index)
|
|
{
|
|
static const char *fname = "SIPTaskProcessSIPPreviousCallInviteResponse";
|
|
uint32_t responseCSeqNumber = 0;
|
|
sipMethod_t responseCSeqMethod = sipMethodInvalid;
|
|
|
|
if ((response_code >= SIP_CLI_ERR_BAD_REQ) && (response_code < 700)) {
|
|
/* Check CSeq */
|
|
if (sipGetMessageCSeq(pResponse, &responseCSeqNumber,
|
|
&responseCSeqMethod) < 0) {
|
|
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
|
|
fname, "Invalid CSeq");
|
|
return;
|
|
}
|
|
if (responseCSeqNumber !=
|
|
gCallHistory[previous_call_index].last_bye_cseq_number) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Last Bye CSeq=%d, Failure Code = %d, "
|
|
"CSeq:%d\n", fname,
|
|
gCallHistory[previous_call_index].last_bye_cseq_number,
|
|
response_code, responseCSeqNumber);
|
|
return;
|
|
}
|
|
|
|
/* Send ACK */
|
|
sipSPISendFailureResponseAck(NULL, pResponse, TRUE, previous_call_index);
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
SIPTaskPostRestart (boolean restart)
|
|
{
|
|
ccsip_restart_req *msg;
|
|
static const char fname[] = "SIPTaskPostRestart";
|
|
|
|
msg = (ccsip_restart_req *) SIPTaskGetBuffer(sizeof(ccsip_restart_req));
|
|
if (msg == NULL) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to allocate IPC msg ccip_restart_req\n", fname);
|
|
return;
|
|
}
|
|
if (restart) {
|
|
/* This is a restart request from the platform */
|
|
msg->cmd = SIP_RESTART_REQ_RESTART;
|
|
} else {
|
|
/* This is a re-init request from the platform */
|
|
msg->cmd = SIP_RESTART_REQ_REINIT;
|
|
}
|
|
/* send a restart message to the SIP Task */
|
|
if (SIPTaskSendMsg(SIP_RESTART, (cprBuffer_t)msg,
|
|
sizeof(ccsip_restart_req), NULL) == CPR_FAILURE) {
|
|
cpr_free(msg);
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void
|
|
SIPTaskProcessRestart (ccsip_restart_cmd cmd)
|
|
{
|
|
static const char fname[] = "SIPTaskProcessRestart";
|
|
|
|
if (cmd == SIP_RESTART_REQ_RESTART) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Starting Restart Process\n",
|
|
DEB_F_PREFIX_ARGS(SIP_TASK, fname));
|
|
|
|
/* Restart SIP task */
|
|
sip_restart();
|
|
} else if (cmd == SIP_RESTART_REQ_REINIT) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Starting Re-init Process\n",
|
|
DEB_F_PREFIX_ARGS(SIP_TASK, fname));
|
|
|
|
// Re-initialize the various components
|
|
SIPTaskReinitialize(FALSE);
|
|
|
|
/* Clear the quite mode */
|
|
sip_mode_quiet = FALSE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If checkConfig is 0/FALSE, process as a config change without checking
|
|
*/
|
|
void
|
|
SIPTaskReinitialize (boolean checkConfig)
|
|
{
|
|
static const char fname[] = "SIPTaskReinitialize";
|
|
|
|
// Initialize all GSM modules
|
|
cc_fail_fallback_gsm(CC_SRC_SIP, CC_RSP_COMPLETE, CC_REG_FAILOVER_RSP);
|
|
|
|
// If the config has changed, or if the check is being bypassed, re-init reg-mgr
|
|
if ( !checkConfig || sip_regmgr_check_config_change() ) {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Config change detected: Restarting\n",
|
|
DEB_F_PREFIX_ARGS(SIP_TASK, fname));
|
|
sip_regmgr_process_config_change();
|
|
return;
|
|
} else {
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"No config change detected\n",
|
|
DEB_F_PREFIX_ARGS(SIP_TASK, fname));
|
|
}
|
|
}
|
|
|
|
void
|
|
SIPTaskPostShutdown (int action, int reason, const char *reasonInfo)
|
|
{
|
|
ccsip_shutdown_req_t *msg;
|
|
static const char fname[] = "SIPTaskPostShutdown";
|
|
|
|
msg = (ccsip_shutdown_req_t *) SIPTaskGetBuffer(sizeof(ccsip_shutdown_req_t));
|
|
if (msg == NULL) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to allocate IPC msg SIP_SHUTDOWN_REQ_SHUT\n", fname);
|
|
return;
|
|
}
|
|
msg->cmd = SIP_SHUTDOWN_REQ_SHUT;
|
|
msg->action = action;
|
|
msg->reason = reason;
|
|
if (reasonInfo) {
|
|
sstrncpy(sipUnregisterReason, reasonInfo, MAX_SIP_REASON_LENGTH);
|
|
}
|
|
|
|
/* send a restart message to the SIP Task */
|
|
if (SIPTaskSendMsg(SIP_SHUTDOWN, (cprBuffer_t)msg,
|
|
sizeof(ccsip_shutdown_req_t), NULL) == CPR_FAILURE) {
|
|
cpr_free(msg);
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void
|
|
SIPTaskProcessShutdown (int action, int reason)
|
|
{
|
|
static const char fname[] = "SIPTaskProcessShutdown";
|
|
|
|
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Starting Shutdown Process\n", DEB_F_PREFIX_ARGS(SIP_TASK, fname));
|
|
sip_mode_quiet = TRUE;
|
|
/* Shutdown SIP components */
|
|
sip_shutdown_phase1(action, reason);
|
|
}
|
|
/*
|
|
* Function: destroy_sip_thread
|
|
* Description: kill sip msgQ and sip thread
|
|
* Parameters: none
|
|
* Returns: none
|
|
*/
|
|
void destroy_sip_thread()
|
|
{
|
|
static const char fname[] = "destroy_sip_thread";
|
|
DEF_DEBUG(DEB_F_PREFIX"Unloading SIP and destroying sip thread\n",
|
|
DEB_F_PREFIX_ARGS(SIP_CC_INIT, fname));
|
|
|
|
/* kill msgQ thread first, then itself */
|
|
(void) cprDestroyThread(sip_thread);
|
|
}
|