Files
freeswitch/libs/sipcc/core/sipstack/ccsip_task.c
T
2012-12-17 20:15:23 -05:00

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, &regConfigValue, 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, &regConfigValue, 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);
}