Files
freeswitch/libs/sipcc/core/sipstack/ccsip_subsmanager.c
T

5291 lines
205 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_in.h"
#include "cpr_stdio.h"
#include "cpr_stdlib.h"
#include "cpr_string.h"
#include "cpr_rand.h"
#include "ccsip_subsmanager.h"
#include "util_string.h"
#include "ccapi.h"
#include "phone_debug.h"
#include "ccsip_messaging.h"
#include "ccsip_platform_udp.h"
#include "ccsip_macros.h"
#include "ccsip_task.h"
#include "sip_common_transport.h"
#include "ccsip_platform_timers.h"
#include "platform_api.h"
#include "ccsip_register.h"
#include "ccsip_reldev.h"
#include "phntask.h"
#include "subapi.h"
#include "debug.h"
#include "ccsip_callinfo.h"
#include "regmgrapi.h"
#include "text_strings.h"
#include "configapp.h"
#include "kpmlmap.h"
/*
* Global Variables
*/
sipSCB_t subsManagerSCBS[MAX_SCBS]; // Array of SCBS
sipSubsHistory_t gSubHistory[MAX_SCB_HISTORY];
sipTimerCallbackFn_t callbackFunctionSubNot = sip_platform_subnot_msg_timer_callback;
sipTimerCallbackFn_t callbackFunctionPeriodic = sip_platform_subnot_periodic_timer_callback;
extern sipPlatformUITimer_t sipPlatformUISMSubNotTimers[]; // Array of timers
const char kpmlRequestAcceptHeader[] = SIP_CONTENT_TYPE_KPML_REQUEST;
const char kpmlResponseAcceptHeader[] = SIP_CONTENT_TYPE_KPML_RESPONSE;
const char dialogAcceptHeader[] = SIP_CONTENT_TYPE_DIALOG;
const char presenceAcceptHeader[] = "application/cpim-pidf+xml";
const char remoteccResponseAcceptHeader[] = SIP_CONTENT_TYPE_REMOTECC_RESPONSE;
const char remoteccRequestAcceptHeader[] = SIP_CONTENT_TYPE_REMOTECC_REQUEST;
static sll_handle_t s_TCB_list = NULL; // signly linked list handle of TCBs
// Externs
extern int dns_error_code; // Global DNS error code
// Status and statistics for the Subscription Manager
int subsManagerRunning = 0;
int internalRegistrations = 0;
int incomingSubscribes = 0;
int incomingRefers = 0;
int incomingNotifies = 0;
int incomingUnsolicitedNotifies = 0;
int incomingSubscriptions = 0;
int outgoingSubscribes = 0;
int outgoingNotifies = 0;
int outgoingUnsolicitedNotifies = 0;
int outgoingSubscriptions = 0;
int currentScbsAllocated = 0;
int maxScbsAllocated = 0;
#define MAX_SUB_EVENTS 5
#define MAX_SUB_EVENT_NAME_LEN 16
/*
* sub_id format:
*
* sub_id is a 32 bit quantity. The bit 32-16 holds a unique ID and
* the bits 15-0 holds a SCB index. The following definitions help
* support this formation.
*
* Assumption: The above format assumes that SCB index never be
* larger than 16 bit unsigned value.
*/
#define SUB_ID_UNIQUE_ID_POSITION 16 /* shift position of unique id part*/
#define SUB_IDSCB_INDEX_MASK 0xffff /* mask for obtaining scb index */
#define GET_SCB_INDEX_FROM_SUB_ID(sub_id) \
(sub_id & SUB_IDSCB_INDEX_MASK)
/*
* Event names
*/
const char eventNames[MAX_SUB_EVENTS][MAX_SUB_EVENT_NAME_LEN] =
{
"dialog",
"sip-profile",
"kpml",
"presence",
"refer"
};
/*
* Forward Function Declarations
*/
boolean sipSPISendSubscribe(sipSCB_t *scbp, boolean renew, boolean authen);
boolean sipSPISendSubNotify(ccsip_common_cb_t *cbp, boolean authen);
boolean sipSPISendSubscribeNotifyResponse(sipSCB_t *scbp,
uint16_t response_code,
uint32_t cseq);
boolean sipSPISendSubNotifyResponse(sipSCB_t *scbp, int response_code);
void free_scb(int scb_index, const char *fname);
// External Declarations
extern uint32_t IPNameCk(char *name, char *addr_error);
extern void kpml_init(void);
extern void kpml_shutdown(void);
extern void sip_platform_handle_service_control_notify(sipServiceControl_t * scp);
cc_int32_t show_subsmanager_stats(cc_int32_t argc, const char *argv[]);
static void show_scbs_inuse(void);
static void tcb_reset(void);
typedef struct {
unsigned long cseq;
char *via;
} sub_not_trxn_t;
/*
* Function: find_matching_trxn()
*
* Parameters: key - key to find the matching node.
* data - node data.
*
* Descriotion: is invoked by sll_find() to find the matching node based on the key.
*
* Returns: either SLL_MATCH_FOUND or SLL_MATCH_NOT_FOUND.
*/
static sll_match_e
find_matching_trxn (void *key, void *data)
{
unsigned long cseq = *((unsigned long *)key);
sub_not_trxn_t *trxn_p = (sub_not_trxn_t *) data;
if (cseq == trxn_p->cseq) {
return SLL_MATCH_FOUND;
}
return SLL_MATCH_NOT_FOUND;
}
/*
* Function: store_incoming_trxn()
*
* Description: stores the via header in incoming_trxns
*
* Parameters: via, cseq and scbp
*
* Returns: TRUE if the via header is successfully stored,
* FALSE otherwise.
*/
static boolean
store_incoming_trxn (const char *via, unsigned long cseq, sipSCB_t *scbp)
{
static const char *fname = "store_incoming_trxn";
size_t size = 0;
sub_not_trxn_t *sub_not_trxn_p;
if (scbp->incoming_trxns == NULL) {
scbp->incoming_trxns = sll_create(find_matching_trxn);
if (scbp->incoming_trxns == NULL) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sll_create() failed\n", fname);
return FALSE;
}
}
sub_not_trxn_p = (sub_not_trxn_t *)cpr_malloc(sizeof(sub_not_trxn_t));
if (sub_not_trxn_p == NULL) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"malloc failed\n", fname);
return FALSE;
}
sub_not_trxn_p->cseq = cseq;
size = strlen(via) + 1;
sub_not_trxn_p->via = (char *) cpr_malloc(size);
if (sub_not_trxn_p->via) {
sstrncpy(sub_not_trxn_p->via, via, size);
}
(void) sll_append(scbp->incoming_trxns, sub_not_trxn_p);
return TRUE;
}
void
free_event_data (ccsip_event_data_t *event_data)
{
ccsip_event_data_t *tmp;
if (event_data == NULL) {
return;
}
while (event_data != NULL) {
tmp = event_data->next;
if (event_data->type == EVENT_DATA_RAW) {
if (event_data->u.raw_data.data)
cpr_free(event_data->u.raw_data.data);
}
cpr_free(event_data);
event_data = tmp;
}
}
void
append_event_data (ccsip_event_data_t * event_data,
ccsip_event_data_t *new_data)
{
while (event_data->next != NULL) {
event_data = event_data->next;
}
event_data->next = new_data;
new_data->next = NULL;
}
void
free_pending_requests (sipspi_msg_list_t *pendingRequests)
{
sipspi_msg_list_t *tmp;
while (pendingRequests) {
switch (pendingRequests->cmd) {
case SIPSPI_EV_CC_NOTIFY:
{
sipspi_notify_t *notify = &(pendingRequests->msg->msg.notify);
free_event_data(notify->eventData);
cpr_free(pendingRequests->msg);
}
break;
case SIPSPI_EV_CC_SUBSCRIBE_REGISTER:
cpr_free(&pendingRequests->msg->msg.subs_reg);
break;
case SIPSPI_EV_CC_SUBSCRIBE:
{
sipspi_subscribe_t *subs = &(pendingRequests->msg->msg.subscribe);
free_event_data(subs->eventData);
cpr_free(pendingRequests->msg);
}
break;
case SIPSPI_EV_CC_SUBSCRIBE_RESPONSE:
cpr_free(pendingRequests->msg);
break;
case SIPSPI_EV_CC_NOTIFY_RESPONSE:
cpr_free(pendingRequests->msg);
break;
case SIPSPI_EV_CC_SUBSCRIPTION_TERMINATED:
cpr_free(pendingRequests->msg);
break;
default:
break;
}
tmp = pendingRequests;
pendingRequests = pendingRequests->next;
cpr_free(tmp);
}
}
boolean
append_pending_requests (sipSCB_t *scbp,
sipspi_msg_t *newRequest,
uint32_t cmd)
{
static const char *fname = "append_pending_requests";
sipspi_msg_list_t *pendingRequest = NULL;
sipspi_msg_list_t *tmp = NULL;
if (!scbp)
return (FALSE);
pendingRequest = (sipspi_msg_list_t *)
cpr_malloc(sizeof(sipspi_msg_list_t));
if (!pendingRequest) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"malloc failed\n", fname);
return (FALSE);
}
pendingRequest->cmd = cmd;
pendingRequest->msg = newRequest;
pendingRequest->next = NULL;
if (scbp->pendingRequests == NULL) {
scbp->pendingRequests = pendingRequest;
return (TRUE);
}
tmp = scbp->pendingRequests;
while (tmp->next != NULL) {
tmp = tmp->next;
}
tmp->next = pendingRequest;
return (TRUE);
}
void
handle_pending_requests (sipSCB_t *scbp)
{
sipspi_msg_list_t *pendingRequest = NULL;
if (scbp->pendingRequests) {
pendingRequest = scbp->pendingRequests;
scbp->pendingRequests = pendingRequest->next;
switch (pendingRequest->cmd) {
case SIPSPI_EV_CC_NOTIFY:
{
sipspi_msg_t *notify = pendingRequest->msg;
cpr_free(pendingRequest);
(void) subsmanager_handle_ev_app_notify(notify);
cpr_free(notify);
}
break;
case SIPSPI_EV_CC_SUBSCRIBE_REGISTER:
cpr_free(pendingRequest->msg);
cpr_free(pendingRequest);
break;
case SIPSPI_EV_CC_SUBSCRIBE:
{
sipspi_msg_t *subs = pendingRequest->msg;
cpr_free(pendingRequest);
(void) subsmanager_handle_ev_app_subscribe(subs);
cpr_free(subs);
}
break;
case SIPSPI_EV_CC_SUBSCRIBE_RESPONSE:
{
sipspi_msg_t *subs_resp = pendingRequest->msg;
cpr_free(pendingRequest);
(void) subsmanager_handle_ev_app_subscribe_response(subs_resp);
cpr_free(subs_resp);
}
break;
case SIPSPI_EV_CC_NOTIFY_RESPONSE:
{
sipspi_msg_t *not_resp = pendingRequest->msg;
cpr_free(pendingRequest);
(void) subsmanager_handle_ev_app_notify_response(not_resp);
cpr_free(not_resp);
}
break;
case SIPSPI_EV_CC_SUBSCRIPTION_TERMINATED:
{
sipspi_msg_t *term = pendingRequest->msg;
cpr_free(pendingRequest);
(void) subsmanager_handle_ev_app_subscription_terminated(term);
cpr_free(term);
}
break;
default:
if (pendingRequest->msg) {
cpr_free(pendingRequest->msg);
}
cpr_free(pendingRequest);
break;
}
}
}
///////////////////////////////////////////////////////////// Test Only !!
static void
ccsip_api_subscribe_result (ccsip_sub_not_data_t * msg_data)
{
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Received Subscribe Response: request_id=%d, sub_id=%x\n",
DEB_F_PREFIX_ARGS(SIP_SUB_RESP, "ccsip_api_subscribe_result"),
msg_data->request_id, msg_data->sub_id);
if (msg_data->u.subs_result_data.status_code == REQUEST_TIMEOUT) {
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Request timed out\n", DEB_F_PREFIX_ARGS(SIP_SUB_RESP, "ccsip_api_subscribe_result"));
}
}
static void
print_event_data (ccsip_event_data_t * eventDatap)
{
static const char *fname = "print_event_data";
while (eventDatap) {
switch (eventDatap->type) {
case EVENT_DATA_INVALID:
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Invalid Data Received\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
break;
case EVENT_DATA_KPML_REQUEST:
CCSIP_DEBUG_TASK(DEB_F_PREFIX"KPML Request Event Data Received\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
break;
case EVENT_DATA_KPML_RESPONSE:
CCSIP_DEBUG_TASK(DEB_F_PREFIX"KPML Response Event Data Received\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
break;
case EVENT_DATA_PRESENCE:
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Presence Event Data Received\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
break;
case EVENT_DATA_DIALOG:
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Dialog Event Data Received\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
break;
case EVENT_DATA_RAW:
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Raw Event Data Received\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
break;
default:
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Event Data Type Not Understood\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
break;
}
eventDatap = eventDatap->next;
}
}
static void
ccsip_api_notify_result (ccsip_sub_not_data_t *msg_data)
{
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Received Notify Response\n", DEB_F_PREFIX_ARGS(SIP_SUB_RESP, "ccsip_api_notify_result"));
}
static void
ccsip_api_notify_ind (ccsip_sub_not_data_t *msg)
{
static const char *fname = "ccsip_api_notify_ind";
sipspi_msg_t not_resp;
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Received Notify, request_id=%d, sub_id=%x\n",DEB_F_PREFIX_ARGS(SIP_SUB_RESP, fname),
msg->request_id, msg->sub_id);
// Check out what's there in the notify indication
if (msg->u.notify_ind_data.eventData) {
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Event Data Received\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
print_event_data(msg->u.notify_ind_data.eventData);
free_event_data(msg->u.notify_ind_data.eventData);
} else {
CCSIP_DEBUG_TASK(DEB_F_PREFIX"No event data received\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
}
// Respond with a 200OK
memset(&not_resp, 0, sizeof(sipspi_msg_t));
not_resp.msg.notify_resp.sub_id = msg->sub_id;
not_resp.msg.notify_resp.response_code = SIP_SUCCESS_SETUP;
not_resp.msg.notify_resp.duration = 3600;
(void) subsmanager_handle_ev_app_notify_response(&not_resp);
}
static void
ccsip_api_subscribe_terminate (ccsip_sub_not_data_t *msg_data)
{
sipspi_msg_t terminate;
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Received Terminate notice\n", DEB_F_PREFIX_ARGS(SIP_SUB, "ccsip_api_subscribe_terminate"));
if (msg_data->u.subs_term_data.status_code == NETWORK_SUBSCRIPTION_EXPIRED) {
terminate.msg.subs_term.sub_id = msg_data->sub_id;
terminate.msg.subs_term.immediate = TRUE;
(void) subsmanager_handle_ev_app_subscription_terminated(&terminate);
}
}
static void
ccsip_api_subscribe_ind (ccsip_sub_not_data_t *msg)
{
static const char *fname = "ccsip_api_subscribe_ind";
sipspi_msg_t subs_resp, notify, terminate;
ccsip_event_data_t *eventData;
char *junkdata;
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Received Subscription Request\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
// Check out what's there in the subs indication
if (msg->u.subs_ind_data.eventData) {
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Event Data Received\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
print_event_data(msg->u.subs_ind_data.eventData);
free_event_data(msg->u.subs_ind_data.eventData);
} else {
CCSIP_DEBUG_TASK(DEB_F_PREFIX"No event data received\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
}
// Accept the subscription with a 200 OK response
subs_resp.msg.subscribe_resp.duration = msg->u.subs_ind_data.expires;
subs_resp.msg.subscribe_resp.response_code = SIP_SUCCESS_SETUP;
subs_resp.msg.subscribe_resp.sub_id = msg->sub_id;
(void) subsmanager_handle_ev_app_subscribe_response(&subs_resp);
// Now send a NOTIFY
notify.msg.notify.notifyResultCallback = ccsip_api_notify_result;
notify.msg.notify.sub_id = msg->sub_id;
notify.msg.notify.eventData = NULL;
// Now fill in some data in the kpml structure
eventData = (ccsip_event_data_t *) cpr_malloc(sizeof(ccsip_event_data_t));
if (eventData == NULL) {
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Malloc of ccsip event data structure failed.\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
return;
}
memset(eventData, 0, sizeof(ccsip_event_data_t));
sstrncpy(eventData->u.kpml_request.pattern.regex.regexData, "012", 32);
sstrncpy(eventData->u.kpml_request.version, "1.0", 16);
eventData->type = EVENT_DATA_KPML_REQUEST;
notify.msg.notify.eventData = eventData;
// Now fill in some other junk data
eventData = (ccsip_event_data_t *) cpr_malloc(sizeof(ccsip_event_data_t));
if (eventData == NULL) {
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Malloc of ccsip event structure failed.\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
cpr_free(notify.msg.notify.eventData);
return;
}
junkdata = (char *) cpr_malloc(20);
if (junkdata == NULL) {
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Malloc of junk data structure failed.\n", DEB_F_PREFIX_ARGS(SIP_EVT, fname));
cpr_free(eventData);
cpr_free(notify.msg.notify.eventData);
return;
}
memset(eventData, 0, sizeof(ccsip_event_data_t));
memset(junkdata, 0, 20);
sstrncpy(junkdata, "Hello", 20);
eventData->u.raw_data.data = junkdata;
eventData->u.raw_data.length = strlen(junkdata);
eventData->type = EVENT_DATA_RAW;
notify.msg.notify.eventData->next = eventData;
(void) subsmanager_handle_ev_app_notify(&notify);
// If expires is 0, terminate the subscription
if (msg->u.subs_ind_data.expires == 0) {
terminate.msg.subs_term.sub_id = msg->sub_id;
terminate.msg.subs_term.immediate = TRUE;
(void) subsmanager_handle_ev_app_subscription_terminated(&terminate);
}
}
static void
test_send_subscribe ()
{
sipspi_msg_t subscribe;
ccsip_event_data_t *eventData;
memset(&subscribe.msg.subscribe, 0, sizeof(sipspi_subscribe_t));
subscribe.msg.subscribe.eventPackage = CC_SUBSCRIPTIONS_KPML;
subscribe.msg.subscribe.duration = 15;
sstrncpy(subscribe.msg.subscribe.subscribe_uri, "19921", CC_MAX_DIALSTRING_LEN);
sstrncpy(subscribe.msg.subscribe.subscriber_uri, "12345", CC_MAX_DIALSTRING_LEN);
subscribe.msg.subscribe.request_id = 1003;
subscribe.msg.subscribe.dn_line = 2;
subscribe.msg.subscribe.sub_id = CCSIP_SUBS_INVALID_SUB_ID;
subscribe.msg.subscribe.subsResultCallback = ccsip_api_subscribe_result;
subscribe.msg.subscribe.subsTermCallback = ccsip_api_subscribe_terminate;
subscribe.msg.subscribe.notifyIndCallback = ccsip_api_notify_ind;
subscribe.msg.subscribe.auto_resubscribe = TRUE;
// Now fill in some data in the kpml structure
/*
* eventData = (ccsip_event_data_t *) cpr_malloc(sizeof(ccsip_event_data_t));
* if (eventData == NULL) {
* CCSIP_DEBUG_TASK("Malloc of ccsip event data failed.\n");
* return;
* }
*
* memset(eventData, 0, sizeof(ccsip_event_data_t));
* sstrncpy(eventData->u.kpml_request.pattern.regex.regexData, "012", sizeof(eventData->u.kpml_request.pattern.regex.regexData));
* sstrncpy(eventData->u.kpml_request.version, "1.0", sizeof(eventData->u.kpml_request.version));
* eventData->type = EVENT_DATA_KPML_REQUEST;
* subscribe.msg.subscribe.eventData = eventData;
*/
// Now fill in some other junk data
eventData = (ccsip_event_data_t *) cpr_malloc(sizeof(ccsip_event_data_t));
if (eventData == NULL) {
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Malloc of ccsip event data failed.\n", DEB_F_PREFIX_ARGS(SIP_EVT, "test_send_subscribe"));
return;
}
memset(eventData, 0, sizeof(ccsip_event_data_t));
eventData->type = EVENT_DATA_RAW;
eventData->u.raw_data.data = (char *) cpr_malloc(150);
if (eventData->u.raw_data.data) {
eventData->u.raw_data.length = 150;
memset(eventData->u.raw_data.data, 'V', 150);
} else {
eventData->u.raw_data.length = 0;
}
eventData->next = NULL;
subscribe.msg.subscribe.eventData = eventData;
(void) subsmanager_handle_ev_app_subscribe(&subscribe);
}
static void
test_send_register ()
{
sipspi_msg_t register_msg;
memset(&register_msg, 0, sizeof(sipspi_msg_t));
register_msg.msg.subs_reg.eventPackage = CC_SUBSCRIPTIONS_PRESENCE;
register_msg.msg.subs_reg.subsIndCallback = ccsip_api_subscribe_ind;
register_msg.msg.subs_reg.subsTermCallback = ccsip_api_subscribe_terminate;
(void) subsmanager_handle_ev_app_subscribe_register(&register_msg);
}
int
subsmanager_test_start_routine ()
{
static int subscribe_sent = 0;
static int register_sent = 0;
if (subscribe_sent == 0) {
test_send_subscribe();
subscribe_sent = 1;
}
if (register_sent == 0) {
test_send_register();
register_sent = 1;
}
return 0;
}
/************************************************************
* Send local error to the calling application
* This function reuses the callback interface to pass the
* (bad) result of requests from the application
************************************************************/
void
sip_send_error_message (ccsip_sub_not_data_t *msg_data,
cc_srcs_t dest_task,
int msgid,
ccsipGenericCallbackFn_t callbackFn,
const char *fname)
{
if (!msg_data) {
return;
}
if (callbackFn) {
(*callbackFn) (msg_data);
} else if (dest_task != CC_SRC_MIN) {
(void) sip_send_message(msg_data, dest_task, msgid);
}
}
/********************************************************
* Shutdown the Subscription Manager
********************************************************/
int
sip_subsManager_shut ()
{
const char *fname = "sip_subsManager_shut";
int i;
sipSCB_t *scbp = NULL;
ccsip_sub_not_data_t error_data;
if (subsManagerRunning == 0) {
return (0);
}
error_data.reason_code = SM_REASON_CODE_SHUTDOWN;
// Send indication of subscription ended to internal apps
// then clean and free up subscriptions and SCB
for (i = 0; i < MAX_SCBS; i++) {
scbp = &(subsManagerSCBS[i]);
if (scbp->smState == SUBS_STATE_IDLE) {
continue;
}
error_data.sub_id = scbp->sub_id;
error_data.request_id = scbp->request_id;
error_data.sub_duration = 0;
error_data.event = scbp->hb.event_type;
error_data.msg_id = scbp->subsTermCallbackMsgID;
error_data.line_id = scbp->hb.dn_line;
error_data.gsm_id = scbp->gsm_id;
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Sending shutdown notification for scb=%d"
" sub_id=%x\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname), i, scbp->sub_id);
sip_send_error_message(&error_data, scbp->subsNotCallbackTask,
scbp->subsTermCallbackMsgID,
scbp->subsTermCallback, fname);
free_scb(i, fname);
}
// Shut down the periodic timer
(void) sip_platform_subnot_periodic_timer_stop();
// Mark subsManager as stopped running
subsManagerRunning = 0;
tcb_reset();
return (0);
}
/********************************************************
* Common code notifying application for a failover/fallback
* or CCM new registration (reset) event. Send a notification to
* applications that have an active subscription
********************************************************/
static int
sip_subsManager_reg_failure_common (ccsip_reason_code_e reason)
{
const char *fname = "sip_subsManager_reg_failure_common";
int i;
sipSCB_t *scbp = NULL;
ccsip_sub_not_data_t error_data;
if (subsManagerRunning == 0) {
return (0);
}
error_data.reason_code = reason;
// Send indication of subscription ended to internal apps
// then clean and free up subscriptions and SCB
for (i = 0; i < MAX_SCBS; i++) {
scbp = &(subsManagerSCBS[i]);
if (scbp->smState == SUBS_STATE_IDLE ||
scbp->smState == SUBS_STATE_REGISTERED) {
// Update addr and port after rollover/ccm reset
scbp->hb.local_port = sipTransportGetListenPort(1, NULL);
sipTransportGetServerIPAddr(&(scbp->hb.dest_sip_addr),1);
scbp->hb.dest_sip_port = sipTransportGetPrimServerPort(1);
continue;
}
error_data.sub_id = scbp->sub_id;
error_data.line_id = scbp->hb.dn_line;
error_data.request_id = scbp->request_id;
error_data.sub_duration = 0;
error_data.event = scbp->hb.event_type;
error_data.msg_id = scbp->subsTermCallbackMsgID;
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Sending reg failure notification for "
"scb=%d sub_id=%x reason=%d\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname), i,
scbp->sub_id, reason);
sip_send_error_message(&error_data, scbp->subsNotCallbackTask,
scbp->subsTermCallbackMsgID,
scbp->subsTermCallback, fname);
if (scbp->internal) {
outgoingSubscriptions--;
} else {
incomingSubscriptions--;
}
free_scb(i, fname);
}
sipRelDevAllMessagesClear();
return (0);
}
/********************************************************
* Handle a failover/fallback event
* to handle this event, send a notification to all
* applications that have an active subscription
********************************************************/
int
sip_subsManager_rollover ()
{
tcb_reset();
return (sip_subsManager_reg_failure_common(SM_REASON_CODE_ROLLOVER));
}
/********************************************************
* Handle a (CCM or Proxy) server down and up event^M
* to handle this event, send a notification to all^M
* applications that have an active subscription^M
********************************************************/
int
sip_subsManager_reset_reg (void)
{
return (sip_subsManager_reg_failure_common(SM_REASON_CODE_RESET_REG));
}
/***********************************************************
* Send a protocol error message to application. The application
* decides whether to terminate and restart the subscription
* or otherwise
***********************************************************/
void
sip_subsManager_send_protocol_error (sipSCB_t *scbp, int scb_index,
boolean terminate)
{
const char *fname = "sip_subsManager_send_protocol_error";
ccsip_sub_not_data_t error_data;
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Protocol Error for scb=%d sub_id=%x\n", fname,
scb_index, scbp->sub_id);
error_data.reason_code = SM_REASON_CODE_ERROR;
error_data.sub_id = scbp->sub_id;
error_data.request_id = scbp->request_id;
error_data.sub_duration = 0;
error_data.event = scbp->hb.event_type;
error_data.msg_id = scbp->subsTermCallbackMsgID;
error_data.line_id = scbp->hb.dn_line;
sip_send_error_message(&error_data, scbp->subsNotCallbackTask,
scbp->subsTermCallbackMsgID, scbp->subsTermCallback,
fname);
if (terminate) {
free_scb(scb_index, fname);
}
}
/********************************************************
* Start and initialize the Subscription Manager
********************************************************/
void
initialize_scb (sipSCB_t *scbp)
{
int nat_enable = 0;
if (!scbp) {
return;
}
memset(scbp, 0, sizeof(sipSCB_t));
scbp->sub_id = CCSIP_SUBS_INVALID_SUB_ID;
scbp->pendingClean = FALSE;
scbp->pendingCount = 0;
scbp->internal = FALSE;
scbp->subsIndCallback = NULL;
scbp->subsResultCallback = NULL;
scbp->notifyIndCallback = NULL;
scbp->notifyResultCallback = NULL;
scbp->subsTermCallback = NULL;
scbp->notIndCallbackMsgID = 0;
scbp->notResCallbackMsgID = 0;
scbp->subsIndCallbackMsgID = 0;
scbp->subsResCallbackMsgID = 0;
scbp->subsTermCallbackMsgID = 0;
scbp->subsIndCallbackTask = CC_SRC_MIN;
scbp->subsNotCallbackTask = CC_SRC_MIN;
config_get_value(CFGID_NAT_ENABLE, &nat_enable, sizeof(nat_enable));
if (nat_enable == 0) {
sip_config_get_net_device_ipaddr(&(scbp->hb.src_addr));
} else {
sip_config_get_nat_ipaddr(&(scbp->hb.src_addr));
}
scbp->hb.cb_type = SUBNOT_CB;
scbp->hb.dn_line = 1;
scbp->hb.local_port = sipTransportGetListenPort(scbp->hb.dn_line, NULL);
sipTransportGetServerIPAddr(&(scbp->hb.dest_sip_addr),1);
scbp->hb.dest_sip_port = sipTransportGetPrimServerPort(1);
scbp->hb.sipCallID[0] = '\0';
scbp->smState = SUBS_STATE_IDLE;
scbp->SubURI[0] = '\0';
scbp->SubscriberURI[0] = '\0';
scbp->sip_from = strlib_empty();
scbp->sip_to = strlib_empty();
scbp->sip_to_tag = strlib_empty();
scbp->sip_from_tag = strlib_empty();
scbp->sip_contact = strlib_empty();
scbp->cached_record_route = strlib_empty();
scbp->callingNumber = strlib_empty();
scbp->subscription_state = SUBSCRIPTION_STATE_INVALID;
scbp->norefersub = FALSE;
scbp->request_id = -1;
scbp->hb.authen.cred_type = 0;
scbp->hb.authen.authorization = NULL;
scbp->hb.authen.status_code = 0;
scbp->hb.authen.nc_count = 0;
scbp->hb.authen.new_flag = FALSE;
scbp->hb.event_data_p = NULL;
scbp->pendingRequests = NULL;
}
int
sip_subsManager_init ()
{
// Initialize SCBS array
const char *fname = "sip_subsManager_init";
line_t i = 0;
sipSCB_t *scbp;
if (subsManagerRunning == 1) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Subscription Manager already running!!\n", fname);
return SIP_OK;
}
for (i = 0; i < MAX_SCBS; i++) {
scbp = &(subsManagerSCBS[i]);
initialize_scb(scbp);
scbp->line = i;
}
for (i = 0; i < MAX_SCB_HISTORY; i++) {
gSubHistory[i].last_call_id[0] = '\0';
gSubHistory[i].last_from_tag[0] = '\0';
gSubHistory[i].eventPackage = CC_SUBSCRIPTIONS_NONE;
}
// reset status and stats
internalRegistrations = 0;
incomingSubscribes = 0;
incomingRefers = 0;
incomingNotifies = 0;
incomingUnsolicitedNotifies = 0;
incomingSubscriptions = 0;
outgoingSubscribes = 0;
outgoingNotifies = 0;
outgoingUnsolicitedNotifies = 0;
outgoingSubscriptions = 0;
currentScbsAllocated = 0;
maxScbsAllocated = 0;
// Start periodic timer
(void) sip_platform_subnot_periodic_timer_start(TMR_PERIODIC_SUBNOT_INTERVAL * 1000);
subsManagerRunning = 1;
// Print out the size of the SCB
// CCSIP_DEBUG_ERROR("SCB Size=%d\n", sizeof(sipSCB_t));
// CCSIP_DEBUG_ERROR("CCB Size=%d\n", sizeof(ccsipCCB_t));
// Kick-off the test routine
// subsmanager_test_start_routine();
/* Initialize modules which uses SUB/MANAGER */
kpml_init();
configapp_init();
return SIP_OK;
}
/********************************************************
* Functions to allocate, locate, free, and update SCBs
********************************************************/
/*
* Function: find_scb_by_callid
*
* Parameters:
* callID - pointer to const. char for the target call ID.
* scb_index - pointer to int where the SCB index of the result
* SCB to be stored.
*
* Description:
* The find_scb_by_callid function searches for an SCB that
* contains the matching callID. It is possible to have multiple
* SCB that matches the given callID. The function only returns
* the first SCB that has the matching callID.
*
* Returns:
* Pointer to SCB and its index if the SCB is found. Otherwise
* it returns NULL and the index is undefined.
*/
sipSCB_t *
find_scb_by_callid (const char *callID, int *scb_index)
{
int i;
int num_scb = currentScbsAllocated;
sipSCB_t *scbp;
if (num_scb == 0) {
/* No active subscription */
return (NULL);
}
scbp = &subsManagerSCBS[0];
for (i = 0; (i < MAX_SCBS) && num_scb; i++, scbp++) {
if (scbp->smState != SUBS_STATE_IDLE) {
if ((scbp->smState != SUBS_STATE_REGISTERED) &&
(strcmp(callID, scbp->hb.sipCallID) == 0)) {
*scb_index = i;
return (scbp);
}
num_scb--;
}
}
return (NULL);
}
/*
* Function: find_req_scb
*
* Parameters:
* callID - pointer to const. char for the target call ID.
* method - SIP method to match.
* cseq - CSEQ value to match.
* scb_index - pointer to int where the SCB index of the result
* SCB to be stored.
*
* Description:
* The find_req_scb function searches for an SCB that contains
* the matching callID, last request method and last cseq sent. If
* the match SCB is found, the function returns the pointer to the
* sipSCB_t along with the corresponding index.
*
* Returns:
* Pointer to SCB and its index if the SCB is found. Otherwise
* returns NULL and the index will be set to MAX_SCBS.
*/
static sipSCB_t *
find_req_scb (const char *callID, sipMethod_t method,
uint32_t cseq, int *scb_index)
{
int idx, num_scb;
sipSCB_t *scbp;
scbp = &subsManagerSCBS[0];
num_scb = currentScbsAllocated;
/*
* Search SCB tables for all allocated SCBs.
*/
for (idx = 0; (idx < MAX_SCBS) && num_scb; idx++, scbp++) {
if (scbp->smState != SUBS_STATE_IDLE) {
if ((scbp->smState != SUBS_STATE_REGISTERED) &&
(scbp->last_sent_request_cseq_method == method) &&
(scbp->last_sent_request_cseq == cseq) &&
(strcmp(callID, scbp->hb.sipCallID) == 0)) {
/* Found the matching scb */
*scb_index = idx;
return (scbp);
}
num_scb--;
}
}
*scb_index = MAX_SCBS;
return (NULL);
}
/*
* Function: find_scb_by_sub_id
*
* Parameters:
* sub_id - the sub_id_t parameter from which scb index
* to be obtained.
* scb_index - pointer to int for index of the SCB entry to
* be returned if the pointer is provided (not
* NULL).
*
* Description:
* The function finds the SCB for the given sub_id.
*
* Returns:
* 1) pointer to sipSCB_t or NULL if finding fails.
* 2) the index into the SCB array is also returned if the
* scb_index parameter is provided.
*/
static sipSCB_t *
find_scb_by_sub_id (sub_id_t sub_id, int *scb_index)
{
int idx, ret_idx = MAX_SCBS;
sipSCB_t *scbp = NULL;
/*
* Use index part of the sub_id to find the SCB
*/
idx = GET_SCB_INDEX_FROM_SUB_ID(sub_id);
if (idx < MAX_SCBS) {
/*
* SCB index is within a valid range, get the SCB by index.
* Match the SCB's sub_id and the one provided.
*/
if (subsManagerSCBS[idx].sub_id == sub_id) {
/* The correct SCB is found */
scbp = &(subsManagerSCBS[idx]);
ret_idx = idx;
}
}
if (scb_index != NULL) {
*scb_index = ret_idx;
}
return (scbp);
}
sipSCB_t *
find_scb_by_registration (cc_subscriptions_t event, int *scb_index)
{
int i;
for (i = 0; i < MAX_SCBS; i++) {
if ((subsManagerSCBS[i].hb.event_type == event) &&
(subsManagerSCBS[i].smState == SUBS_STATE_REGISTERED)) {
*scb_index = i;
return &(subsManagerSCBS[i]);
}
}
return (NULL);
}
sipSCB_t *
find_scb_by_subscription (cc_subscriptions_t event, int *scb_index,
const char *callID)
{
int i;
for (i = 0; i < MAX_SCBS; i++) {
if (cpr_strcasecmp(subsManagerSCBS[i].hb.sipCallID, callID) == 0) {
*scb_index = i;
return &(subsManagerSCBS[i]);
}
}
return (NULL);
}
/*
* Function: new_sub_id
*
* Parameters:
* scb_index - the SCB index.
*
* Description:
* The function allocates a new unique sub_id and return
* it to the caller.
*
* NOTE: the scb_index can not exceed 16 bit unsigned value.
*
* Returns:
* sub_id.
*/
static sub_id_t
new_sub_id (int scb_index)
{
static sub_id_t unique_id = 0;
sub_id_t sub_id;
/*
* Form the sub_id is encoded as the following:
* bit 31 - bit 16 contains unique ID
* bit 15 - bit 0 contains scb index.
*/
sub_id = (unique_id << SUB_ID_UNIQUE_ID_POSITION) |
(sub_id_t)(scb_index & SUB_IDSCB_INDEX_MASK);
unique_id++; /* next unique sub id */
if (sub_id == CCSIP_SUBS_INVALID_SUB_ID) {
/* sub_id becomes the invalid value marker, re-calcualte new id */
sub_id = (unique_id << SUB_ID_UNIQUE_ID_POSITION) |
(sub_id_t)(scb_index & SUB_IDSCB_INDEX_MASK);
unique_id++;
}
return (sub_id);
}
sipSCB_t *
allocate_scb (int *scb_index)
{
int i;
for (i = 0; i < MAX_SCBS; i++) {
if (subsManagerSCBS[i].smState == SUBS_STATE_IDLE) {
*scb_index = i;
currentScbsAllocated++;
if (currentScbsAllocated > maxScbsAllocated) {
maxScbsAllocated = currentScbsAllocated;
}
/*
* assigned sub_id to the allocated SCB.
*/
subsManagerSCBS[i].sub_id = new_sub_id(i);
CCSIP_DEBUG_TASK("allocate_scb scb_index: %d, currentScbsAllocated: %d, "
"maxScbsAllocated: %d, sub_id: %x\n", scb_index,
currentScbsAllocated, maxScbsAllocated, subsManagerSCBS[i].sub_id);
/*
* local port may have changed because of failover/fallback.
* So update it with current info so that the Via & Contact headers
* in SUB/NOT are generated correctly.
*/
subsManagerSCBS[i].hb.local_port =
sipTransportGetListenPort(subsManagerSCBS[i].hb.dn_line, NULL);
return &(subsManagerSCBS[i]);
}
}
return (NULL);
}
boolean
is_previous_sub (const char *pCallID,
char *pFromTag,
cc_subscriptions_t event)
{
int i;
if (!pCallID || !pFromTag) {
return FALSE;
}
for (i = 0; i < MAX_SCB_HISTORY; i++) {
if (strncmp(gSubHistory[i].last_call_id, pCallID, MAX_SIP_CALL_ID) == 0) {
if (strncmp(gSubHistory[i].last_from_tag, pFromTag, MAX_SIP_TAG_LENGTH) == 0) {
if (gSubHistory[i].eventPackage == event) {
return TRUE;
}
}
}
}
return FALSE;
}
void
clean_scb (sipSCB_t *scbp)
{
sub_not_trxn_t *trxn_p;
if (scbp) {
strlib_free(scbp->sip_from);
strlib_free(scbp->sip_to);
strlib_free(scbp->sip_to_tag);
strlib_free(scbp->sip_from_tag);
strlib_free(scbp->callingNumber);
strlib_free(scbp->sip_contact);
strlib_free(scbp->cached_record_route);
if (scbp->contact_info)
sippmh_free_contact(scbp->contact_info);
if (scbp->record_route_info)
sippmh_free_record_route(scbp->record_route_info);
if (scbp->hb.event_data_p)
free_event_data(scbp->hb.event_data_p);
if (scbp->pendingRequests) {
free_pending_requests(scbp->pendingRequests);
}
scbp->hb.authen.cnonce[0] = '\0';
if (scbp->hb.authen.authorization != NULL) {
cpr_free(scbp->hb.authen.authorization);
scbp->hb.authen.authorization = NULL;
}
if (scbp->hb.authen.sip_authen != NULL) {
sippmh_free_authen(scbp->hb.authen.sip_authen);
scbp->hb.authen.sip_authen = NULL;
}
/* free all transactions */
if (scbp->incoming_trxns) {
while ((trxn_p = (sub_not_trxn_t *)
sll_next(scbp->incoming_trxns, NULL)) != NULL) {
(void) sll_remove(scbp->incoming_trxns, (void *)trxn_p);
cpr_free(trxn_p->via);
cpr_free(trxn_p);
}
sll_destroy(scbp->incoming_trxns);
scbp->incoming_trxns = NULL;
}
}
}
void
store_scb_history (sipSCB_t *scbp)
{
// Copy SCB parameters in the next available history array
static int next_history = 0;
next_history++;
if (next_history == MAX_SCB_HISTORY) {
next_history = 0;
}
sstrncpy(gSubHistory[next_history].last_call_id, scbp->hb.sipCallID, MAX_SIP_CALL_ID);
sstrncpy(gSubHistory[next_history].last_from_tag, scbp->sip_from_tag, MAX_SIP_TAG_LENGTH);
gSubHistory[next_history].eventPackage = scbp->hb.event_type;
}
/**
*
* frees the SCB. It will cleanup the scb (ie, free the memory allocated for any sub fields).
* It will also mark the SCB as free (smState = SUBS_STATE_IDLE).
* Please note this function may be invoked can be invoked even when smState == SUBS_STATE_IDLE.
* An example case is when parse_body() fails.
*
* @param[in] scb_index - indext of the SCB into SCB array.
* @param[in] fname - name of the function calling this function.
*
* @return none
*
* @pre (scb_index >= 0) and (scb_index < MAX_SCBS)
* @post (subsManagerSCBS[scb_index].smState equals FALSE)
*/
void
free_scb (int scb_index, const char *fname)
{
sipSCB_t *scbp = NULL;
if (scb_index >= MAX_SCBS || scb_index < 0) {
CCSIP_DEBUG_ERROR("%s Trying to free an invalid scb_index. Return.\n", fname);
return;
}
scbp = &(subsManagerSCBS[scb_index]);
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Freeing SCB: scb=%d sub_id=%x\n",
DEB_F_PREFIX_ARGS(SIP_SUB, "free_scb"), scb_index, scbp->sub_id);
if (scbp->smState != SUBS_STATE_IDLE) {
currentScbsAllocated--;
/*
* This condition should never happen. If occurs, it is a strong indication
* something has gone wrong in our code logic and should be investigated.
*/
if (currentScbsAllocated < 0) {
CCSIP_DEBUG_ERROR("%s: Error somewhere in scb accounting which results"
"in negative currentScbsAllocated. Set it to 0.\n", fname);
currentScbsAllocated = 0;
}
}
// If this was an incoming subscription, store values in history first
if ((scbp->internal == FALSE) && (scbp->smState != SUBS_STATE_REGISTERED)) {
store_scb_history(scbp);
}
clean_scb(scbp);
// Stop associated message retry timer
if (sipPlatformUISMSubNotTimers[scb_index].outstanding) {
sip_platform_msg_timer_subnot_stop(&sipPlatformUISMSubNotTimers[scb_index]);
}
// Re-initialize
initialize_scb(scbp);
scbp->line = (line_t) scb_index;
}
/**
* This function will free up the TCB resources and removes it from the TCB list.
*
* @param[in] tcbp - pointer to a TCB.
*
* @return none
*
* @pre (tcbp != NULL)
*/
static void free_tcb (sipTCB_t *tcbp)
{
if (tcbp->hb.authen.authorization != NULL) {
cpr_free(tcbp->hb.authen.authorization);
}
if (tcbp->hb.authen.sip_authen != NULL) {
sippmh_free_authen(tcbp->hb.authen.sip_authen);
}
(void)cprDestroyTimer(tcbp->timer);
free_event_data(tcbp->hb.event_data_p);
(void)sll_remove(s_TCB_list, (void *)tcbp);
cpr_free(tcbp);
}
/**
* This function will find matching TCB by the SIP Call-ID in the TCB list.
*
* @param[in] callID_p - SIP Call-ID
*
* @return NULL if there is no matching TCB
* Otherwise, pointer to the found TCB is returned.
*
* @pre (callID_p != NULL)
*/
sipTCB_t *find_tcb_by_sip_callid (const char *callID_p)
{
sipTCB_t *tcb_p;
tcb_p = (sipTCB_t *)sll_next(s_TCB_list, NULL);
while (tcb_p != NULL) {
if (strncmp(callID_p, tcb_p->hb.sipCallID, (sizeof(tcb_p->hb.sipCallID) -1)) == 0) {
return tcb_p;
}
tcb_p = (sipTCB_t *)sll_next(s_TCB_list, tcb_p);
}
return NULL;
}
/**
* This function will free up TCBs when
* 1. restarting or
* 2. failing over/ falling back
*
* @param[in] none
*
* @return none
*/
static void tcb_reset (void)
{
sipTCB_t *tcb_p;
tcb_p = (sipTCB_t *)sll_next(s_TCB_list, NULL);
while (tcb_p != NULL) {
free_tcb(tcb_p);
tcb_p = (sipTCB_t *)sll_next(s_TCB_list, NULL);
}
}
/*
* Function is called to remove ccb pointer from scb
* When the dialog is cleared then ccb associated with
* that dialog is cleared as well. Remove that from
* scb parameters as well
*/
void
submanager_update_ccb_addr (ccsipCCB_t *ccb)
{
sipSCB_t *scbp = NULL;
int scb_index = 0;
int num_scb;
if ((ccb == NULL) || (currentScbsAllocated == 0)) {
/* The CCB is NULL or no active SCBs */
return;
}
/* Once the dialog is cleared i.e ccb is removed, the subnot
* should continue to use from its last sequence number. So
* re-assign last sequence value to scbp.
*
* There are possibility of multiple subscriptions associate
* with a call dialog. Search all of the SCB for the given CCB.
*/
scbp = &subsManagerSCBS[0];
num_scb = currentScbsAllocated;
for (scb_index = 0; (scb_index < MAX_SCBS) && num_scb; scb_index++, scbp++) {
if (scbp->smState != SUBS_STATE_IDLE) {
if ((scbp->smState != SUBS_STATE_REGISTERED) &&
(scbp->ccbp == ccb)) {
scbp->last_sent_request_cseq = ccb->last_used_cseq;
scbp->ccbp = NULL;
}
num_scb--;
}
}
}
/*
* Takes care of all the parsing requirements
*/
static int
parse_body (cc_subscriptions_t event_type, char *msgBody, int msgLength,
ccsip_event_data_t **eventDatapp,
const char *fname)
{
const char *fname1 = "parse_body";
ccsip_event_data_type_e type = EVENT_DATA_INVALID;
if (!msgBody) {
return SIP_ERROR;
}
switch (event_type) {
case CC_SUBSCRIPTIONS_KPML:
type = EVENT_DATA_KPML_REQUEST;
break;
case CC_SUBSCRIPTIONS_CONFIGAPP:
type = EVENT_DATA_CONFIGAPP_REQUEST;
break;
default:
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"%s: unknown event type %d\n", fname1, fname, type);
return SIP_ERROR;
}
return SIP_OK;
}
boolean
add_content (ccsip_event_data_t *eventData, sipMessage_t *request, const char *fname)
{
return FALSE;
/* This function requires XML handling */
#if 0
const char *fname1 = "add_content";
uint32_t len;
char *eventBody = NULL;
while (eventData) {
/* Encode eventData into eventBody here */
len = strlen(eventBody);
switch (eventData->type) {
case EVENT_DATA_RAW:
// Assume body is of type CMXML for now
(void) sippmh_add_message_body(request, eventBody, len,
SIP_CONTENT_TYPE_CMXML,
SIP_CONTENT_DISPOSITION_SESSION_VALUE, TRUE, NULL);
break;
case EVENT_DATA_KPML_REQUEST:
(void) sippmh_add_message_body(request, eventBody, len,
SIP_CONTENT_TYPE_KPML_REQUEST,
SIP_CONTENT_DISPOSITION_SESSION_VALUE, TRUE, NULL);
break;
case EVENT_DATA_KPML_RESPONSE:
(void) sippmh_add_message_body(request, eventBody, len,
SIP_CONTENT_TYPE_KPML_RESPONSE,
SIP_CONTENT_DISPOSITION_SESSION_VALUE, TRUE, NULL);
break;
default:
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"%s: Data type not supported\n", fname1, fname);
cpr_free(eventBody);
break;
}
eventData = eventData->next;
}
return (TRUE);
#endif
}
// Functions to handle requests from internal applications
/************************************************************
* Applications Register to Receive an incoming subscribe(s)
************************************************************/
int
subsmanager_handle_ev_app_subscribe_register (cprBuffer_t buf)
{
const char *fname = "subsmanager_handle_ev_app_register";
sipspi_subscribe_reg_t *reg_datap;
sipSCB_t *scbp = NULL;
int scb_index;
sipspi_msg_t *pSIPSPIMsg = NULL;
pSIPSPIMsg = (sipspi_msg_t *) buf;
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Processing a new subscription registration\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
if (!subsManagerRunning) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Subscription Manager Not Initialized!\n", fname);
return SIP_ERROR;
}
reg_datap = &(pSIPSPIMsg->msg.subs_reg);
if (reg_datap->subsIndCallback == NULL &&
reg_datap->subsIndCallbackMsgID == 0) {
return SIP_ERROR;
}
scbp = find_scb_by_registration(reg_datap->eventPackage, &scb_index);
if (scbp) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Duplicate registration!\n", fname);
return SIP_ERROR;
} else {
scbp = allocate_scb(&scb_index);
if (!scbp) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Subscription control block allocation failed\n", fname);
return SIP_ERROR;
}
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Allocated SCB for App Registration,"
" event=%d, scb=%d, sub_id=%x\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname),
reg_datap->eventPackage,
GET_SCB_INDEX_FROM_SUB_ID(scbp->sub_id),
scbp->sub_id);
}
scbp->hb.dn_line = 1;
scbp->hb.event_type = reg_datap->eventPackage;
if (reg_datap->eventPackage - CC_SUBSCRIPTIONS_DIALOG > -1 &&
reg_datap->eventPackage - CC_SUBSCRIPTIONS_DIALOG < 5) {
sstrncpy(scbp->event_name, eventNames[reg_datap->eventPackage - CC_SUBSCRIPTIONS_DIALOG], MAX_EVENT_NAME_LEN);
}
// Get callback information (either event or function)
scbp->subsIndCallback = reg_datap->subsIndCallback;
scbp->subsIndCallbackTask = reg_datap->subsIndCallbackTask;
scbp->subsNotCallbackTask = reg_datap->subsIndCallbackTask;
scbp->subsIndCallbackMsgID = reg_datap->subsIndCallbackMsgID;
scbp->subsTermCallback = reg_datap->subsTermCallback;
scbp->subsTermCallbackMsgID = reg_datap->subsTermCallbackMsgID;
scbp->subsTermCallback = reg_datap->subsTermCallback;
scbp->subsTermCallbackMsgID = reg_datap->subsTermCallbackMsgID;
scbp->smState = SUBS_STATE_REGISTERED;
internalRegistrations++;
return (0);
}
/********************************************************
* Application Generated Subscribe Request
********************************************************/
int
subsmanager_handle_ev_app_subscribe (cprBuffer_t buf)
{
const char *fname = "subsmanager_handle_ev_app_subscribe";
sipspi_subscribe_t *sub_datap;
sipSCB_t *scbp = NULL;
int scb_index;
ccsip_sub_not_data_t subs_result_data;
boolean reSubscribe = FALSE;
ccsipCCB_t *ccbp = NULL;
sipspi_msg_t *pSIPSPIMsg = NULL;
int subscription_expires;
pSIPSPIMsg = (sipspi_msg_t *) buf;
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Processing a new App subscription request\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
if (!subsManagerRunning) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Subscription Manager Not Initialized!\n", fname);
return SIP_ERROR;
}
// Get Data
sub_datap = &(pSIPSPIMsg->msg.subscribe);
/* Steps:
* * Extract subscription details from the event information
* * Check data to ensure we support the event package asked for
* * Allocate an SCB to hold subscription details
* * Create body of the SUBSCRIBE message, if needed
* * Prep the message by adding fields to the SCB
* * Call sipSPISendSubscribe to send the message out
*/
// Get ready for any failure
subs_result_data.u.subs_result_data.expires = 0;
subs_result_data.u.subs_result_data.status_code = SUBSCRIBE_REQUEST_FAILED;
subs_result_data.sub_id = CCSIP_SUBS_INVALID_SUB_ID;
subs_result_data.request_id = sub_datap->request_id;
subs_result_data.msg_id = sub_datap->subsResCallbackMsgID;
/*
* Finding SCB by sub_id or request id and eventPakage if the
* sub_id is not known.
*/
if (sub_datap->sub_id == CCSIP_SUBS_INVALID_SUB_ID) {
/*
* find scb based on request_id and event package.
* This scenario is possible if application decides to terminate a
* subscription before subsmanager provides app with sub_id.
*/
for (scb_index = 0; scb_index < MAX_SCBS; scb_index++) {
if ((subsManagerSCBS[scb_index].request_id == sub_datap->request_id) &&
(subsManagerSCBS[scb_index].hb.event_type == sub_datap->eventPackage) &&
(!subsManagerSCBS[scb_index].pendingClean)) {
scbp = &(subsManagerSCBS[scb_index]);
break;
}
}
} else {
/* Find SCB from sub_id */
scbp = find_scb_by_sub_id(sub_datap->sub_id, &scb_index);
}
if (scbp == NULL) {
// Process new subscription
if ((sub_datap->eventPackage != CC_SUBSCRIPTIONS_DIALOG) &&
(sub_datap->eventPackage != CC_SUBSCRIPTIONS_KPML) &&
(sub_datap->eventPackage != CC_SUBSCRIPTIONS_PRESENCE)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Event %d not supported!\n",
fname, sub_datap->eventPackage);
subs_result_data.u.subs_result_data.status_code = SUBSCRIBE_FAILED_BADEVENT;
sip_send_error_message(&subs_result_data, sub_datap->subsNotCallbackTask,
sub_datap->subsResCallbackMsgID, sub_datap->subsResultCallback,
fname);
return SIP_ERROR;
}
// Reject this if there is no way to get back to the subscriber
if (!((sub_datap->subsResultCallback) ||
((sub_datap->subsNotCallbackTask != CC_SRC_MIN) &&
sub_datap->subsResCallbackMsgID))) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"No callback info provided by the App\n", fname);
subs_result_data.u.subs_result_data.status_code =
SUBSCRIBE_FAILED_BADINFO;
sip_send_error_message(&subs_result_data,
sub_datap->subsNotCallbackTask,
sub_datap->subsResCallbackMsgID,
sub_datap->subsResultCallback,
fname);
return SIP_ERROR;
}
// If this is a presence request - check if sufficient SCBs will still
// be available for other "more important" functions
if (sub_datap->eventPackage == CC_SUBSCRIPTIONS_PRESENCE) {
if (currentScbsAllocated >= LIMIT_SCBS_USAGE) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"reached Presence SCBs threshold\n", fname);
subs_result_data.u.subs_result_data.status_code =
SUBSCRIBE_FAILED_NORESOURCE;
sip_send_error_message(&subs_result_data,
sub_datap->subsNotCallbackTask,
sub_datap->subsResCallbackMsgID,
sub_datap->subsResultCallback, fname);
return SIP_ERROR;
}
}
// Allocate SCB and copy needed parameters
scbp = allocate_scb(&scb_index);
if (!scbp) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"ran out of SCBs\n", fname);
subs_result_data.u.subs_result_data.status_code =
SUBSCRIBE_FAILED_NORESOURCE;
sip_send_error_message(&subs_result_data,
sub_datap->subsNotCallbackTask,
sub_datap->subsResCallbackMsgID,
sub_datap->subsResultCallback,
fname);
show_scbs_inuse();
return SIP_ERROR;
}
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Allocated SCB for Sending Subscribe,"
" event=%d scb=%d sub_id=%x\n",
DEB_F_PREFIX_ARGS(SIP_SUB, fname), sub_datap->eventPackage,
scb_index, scbp->sub_id);
if (sub_datap->dn_line == 0 || sub_datap->dn_line > MAX_REG_LINES) {
// By not giving a DN line, the app is asking us to use
// device addressing and not line addressing
scbp->hb.dn_line = 1;
scbp->useDeviceAddressing = TRUE;
} else {
scbp->hb.dn_line = sub_datap->dn_line;
}
scbp->gsm_id = sub_datap->call_id;
if (scbp->gsm_id != 0) {
ccbp = sip_sm_get_ccb_by_gsm_id(scbp->gsm_id);
} else {
ccbp = NULL;
}
scbp->ccbp = ccbp;
scbp->hb.event_type = sub_datap->eventPackage;
scbp->hb.accept_type = sub_datap->acceptPackage;
if (sub_datap->eventPackage - CC_SUBSCRIPTIONS_DIALOG > -1 &&
sub_datap->eventPackage - CC_SUBSCRIPTIONS_DIALOG < 5) {
sstrncpy(scbp->event_name, eventNames[sub_datap->eventPackage - CC_SUBSCRIPTIONS_DIALOG], MAX_EVENT_NAME_LEN);
}
sstrncpy(scbp->SubURIOriginal, sub_datap->subscribe_uri,
sizeof(scbp->SubURIOriginal));
sstrncpy(scbp->SubscriberURI, sub_datap->subscriber_uri,
sizeof(scbp->SubscriberURI));
scbp->subsResultCallback = sub_datap->subsResultCallback;
scbp->notifyIndCallback = sub_datap->notifyIndCallback;
scbp->subsTermCallback = sub_datap->subsTermCallback;
scbp->subsNotCallbackTask = sub_datap->subsNotCallbackTask;
scbp->subsResCallbackMsgID = sub_datap->subsResCallbackMsgID;
scbp->notIndCallbackMsgID = sub_datap->subsNotIndCallbackMsgID;
scbp->subsTermCallbackMsgID = sub_datap->subsTermCallbackMsgID;
scbp->hb.dest_sip_addr = sub_datap->dest_sip_addr;
scbp->hb.dest_sip_port = sub_datap->dest_sip_port;
scbp->auto_resubscribe = sub_datap->auto_resubscribe;
scbp->norefersub = sub_datap->norefersub;
scbp->request_id = sub_datap->request_id;
// Set default value of subscribe duration, if not specified
if (sub_datap->duration < 0) {
config_get_value(CFGID_TIMER_SUBSCRIBE_EXPIRES, &subscription_expires,
sizeof(subscription_expires));
sub_datap->duration = subscription_expires;
}
scbp->internal = TRUE;
} else {
/* SCB exists, it is a re-subscribe */
reSubscribe = TRUE;
}
scbp->hb.expires = sub_datap->duration;
scbp->hb.orig_expiration = sub_datap->duration;
if (scbp->hb.event_data_p) {
free_event_data(scbp->hb.event_data_p);
scbp->hb.event_data_p = NULL;
}
// Copy any body received - it will be framed later
if (sub_datap->eventData) {
scbp->hb.event_data_p = sub_datap->eventData;
sub_datap->eventData = NULL;
}
//re-initialize cred_type
scbp->hb.authen.cred_type = 0;
if (sipSPISendSubscribe(scbp, reSubscribe, FALSE /* auth */)) {
if (scbp->smState == SUBS_STATE_RCVD_NOTIFY) {
scbp->smState = SUBS_STATE_SENT_SUBSCRIBE_RCVD_NOTIFY;
} else {
scbp->smState = SUBS_STATE_SENT_SUBSCRIBE;
}
outgoingSubscribes++;
if (!reSubscribe) {
outgoingSubscriptions++;
}
return (0);
}
// If unable to send subscribe, return error immediately
// and return scb to the pool if not resubscribing
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to send SUBSCRIBE message\n", fname);
sip_send_error_message(&subs_result_data, scbp->subsNotCallbackTask,
scbp->subsResCallbackMsgID,
scbp->subsResultCallback, fname);
if (!reSubscribe) {
free_scb(scb_index, fname);
}
return SIP_ERROR;
}
/***********************************************************
* Handle Application Response to a Remote Subscribe Request
***********************************************************/
int
subsmanager_handle_ev_app_subscribe_response (cprBuffer_t buf)
{
const char *fname = "subsmanager_handle_ev_app_subscribe_response";
sipspi_subscribe_resp_t *subres_datap;
sipSCB_t *scbp;
sipspi_msg_t *pSIPSPIMsg = NULL;
pSIPSPIMsg = (sipspi_msg_t *) buf;
subres_datap = &(pSIPSPIMsg->msg.subscribe_resp);
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Processing an app subscribe response for"
" sub_id=%x\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname), subres_datap->sub_id);
/*
* Find SCB from the sub_id.
*/
scbp = find_scb_by_sub_id(subres_datap->sub_id, NULL);
if (scbp == NULL) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"no SCB for sub_id=%x found\n",
fname, subres_datap->sub_id);
return SIP_ERROR;
}
scbp->hb.expires = subres_datap->duration;
if (sipSPISendSubscribeNotifyResponse
(scbp, subres_datap->response_code, scbp->last_recv_request_cseq)) {
if (scbp->smState == SUBS_STATE_RCVD_SUBSCRIBE_SENT_NOTIFY) {
scbp->smState = SUBS_STATE_SENT_NOTIFY;
} else {
scbp->smState = SUBS_STATE_ACTIVE;
}
} else {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to send SUBSCRIBE Response\n", fname);
return SIP_ERROR;
}
return (0);
}
/********************************************************
* Handle Application Generated NOTIFY
********************************************************/
int
subsmanager_handle_ev_app_notify (cprBuffer_t buf)
{
const char *fname = "subsmanager_handle_ev_app_notify";
sipspi_notify_t *not_datap;
sipSCB_t *scbp;
ccsip_sub_not_data_t notify_result_data;
sipspi_msg_t *pSIPSPIMsg = NULL;
sipspi_msg_t *temp_SIPSPIMsg = NULL;
pSIPSPIMsg = (sipspi_msg_t *) buf;
not_datap = &(pSIPSPIMsg->msg.notify);
// Fill in the return data structure in case we encounter any problems
notify_result_data.u.notify_result_data.status_code = NOTIFY_REQUEST_FAILED;
notify_result_data.msg_id = not_datap->subsNotResCallbackMsgID;
notify_result_data.sub_id = not_datap->sub_id;
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Processing an app notify request for"
" sub_id=%x\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname),
not_datap->sub_id);
/*
* Find SCB from the sub_id.
*/
scbp = find_scb_by_sub_id(not_datap->sub_id, NULL);
if (scbp == NULL) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"no SCB for sub_id=%x found\n", fname,
not_datap->sub_id);
free_event_data(not_datap->eventData);
sip_send_error_message(&notify_result_data,
not_datap->subsNotCallbackTask,
not_datap->subsNotResCallbackMsgID,
not_datap->notifyResultCallback,
fname);
return SIP_ERROR;
}
notify_result_data.line_id = scbp->hb.dn_line;
// Check state to see if we need to queue this request
if ((scbp->smState == SUBS_STATE_SENT_NOTIFY) ||
(scbp->smState == SUBS_STATE_RCVD_SUBSCRIBE_SENT_NOTIFY)) {
// This means we have sent a NOTIFY but have not received a response
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Queueing request for later transmission\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
temp_SIPSPIMsg = (sipspi_msg_t *) cpr_malloc(sizeof(sipspi_msg_t));
if (temp_SIPSPIMsg) {
/* Copy the content so that we do not touch the pSIPSPImsg */
(*temp_SIPSPIMsg) = (*pSIPSPIMsg);
/* Append the request */
if (append_pending_requests(scbp, temp_SIPSPIMsg,
SIPSPI_EV_CC_NOTIFY)) {
return SIP_DEFER;
}
cpr_free(temp_SIPSPIMsg);
}
/* We either do not have buffer or failed to append msg. */
free_event_data(not_datap->eventData);
sip_send_error_message(&notify_result_data,
not_datap->subsNotCallbackTask,
not_datap->subsNotResCallbackMsgID,
not_datap->notifyResultCallback,
fname);
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unable to queue request\n", fname);
return SIP_ERROR;
}
// Check state to see if we are in a position to send this NOTIFY
if (scbp->smState == SUBS_STATE_IDLE) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Bad SCB State: %d\n", fname, scbp->smState);
free_event_data(not_datap->eventData);
sip_send_error_message(&notify_result_data,
not_datap->subsNotCallbackTask,
not_datap->subsNotResCallbackMsgID,
not_datap->notifyResultCallback, fname);
return SIP_ERROR;
}
// Copy the callback function, if not already copied
if (not_datap->notifyResultCallback == NULL &&
not_datap->subsNotResCallbackMsgID == 0) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"No callback event or function\n", fname);
// Can't really send back any error ...
free_event_data(not_datap->eventData);
return SIP_ERROR;
} else {
scbp->notifyResultCallback = not_datap->notifyResultCallback;
scbp->notResCallbackMsgID = not_datap->subsNotResCallbackMsgID;
}
if (scbp->hb.event_data_p) {
free_event_data(scbp->hb.event_data_p);
scbp->hb.event_data_p = NULL;
}
// Copy any body received - it will be framed later
if (not_datap->eventData) {
scbp->hb.event_data_p = not_datap->eventData;
not_datap->eventData = NULL;
}
// Find out if app wants to terminate this subscription
if (not_datap->subState == SUBSCRIPTION_TERMINATE) {
scbp->hb.expires = 0;
}
//re-initialize cred_type
scbp->hb.authen.cred_type = 0;
if (sipSPISendSubNotify((ccsip_common_cb_t *)scbp, FALSE) != TRUE) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to send Notify Message\n", fname);
sip_send_error_message(&notify_result_data, scbp->subsNotCallbackTask,
scbp->notResCallbackMsgID,
scbp->notifyResultCallback, fname);
return SIP_ERROR;
}
if (scbp->smState == SUBS_STATE_RCVD_SUBSCRIBE) {
scbp->smState = SUBS_STATE_RCVD_SUBSCRIBE_SENT_NOTIFY;
} else {
scbp->smState = SUBS_STATE_SENT_NOTIFY;
}
outgoingNotifies++;
return (0);
}
/**
* This function will handle Application Generated unsolicited NOTIFY
*
* @param[in] buf - pointer to sipspi_msg_t
* @param[in] line - line id.
*
* @return none
*/
void subsmanager_handle_ev_app_unsolicited_notify (cprBuffer_t buf, line_t line)
{
const char *fname = "subsmanager_handle_ev_app_unsolicited_notify";
sipspi_msg_t *pSIPSPIMsg = NULL;
sipspi_notify_t *not_datap;
sipTCB_t *tcbp;
int nat_enable = 0;
static uint32_t trxn_id = 1;
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Processing an outgoing unsolicited notify request\n",
DEB_F_PREFIX_ARGS(SIP_SUB, fname));
pSIPSPIMsg = (sipspi_msg_t *) buf;
not_datap = &(pSIPSPIMsg->msg.notify);
/*
* If TCB list is not created yet, create the list.
*/
if (s_TCB_list == NULL) {
s_TCB_list = sll_create(NULL);
if (s_TCB_list == NULL) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"malloc of TCBList failed\n", fname);
free_event_data(not_datap->eventData);
return;
}
}
/*
* create a TCB (transaction control block)
*/
tcbp = cpr_malloc(sizeof(sipTCB_t));
if (tcbp == NULL) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"malloc of TCB failed\n", fname);
free_event_data(not_datap->eventData);
return;
}
memset(tcbp, 0, sizeof(sipTCB_t));
tcbp->trxn_id = trxn_id;
trxn_id++;
if (trxn_id == 0) {
trxn_id = 1;
}
tcbp->timer = cprCreateTimer("Unsolicited transaction timer",
SIP_UNSOLICITED_TRANSACTION_TIMER,
TIMER_EXPIRATION,
sip_msgq);
if (tcbp->timer == NULL) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to create a timer\n", fname);
free_event_data(not_datap->eventData);
cpr_free(tcbp);
return;
}
tcbp->hb.cb_type = UNSOLICIT_NOTIFY_CB;
config_get_value(CFGID_NAT_ENABLE, &nat_enable, sizeof(nat_enable));
if (nat_enable == 0) {
sip_config_get_net_device_ipaddr(&(tcbp->hb.src_addr));
} else {
sip_config_get_nat_ipaddr(&(tcbp->hb.src_addr));
}
tcbp->hb.dn_line = line;
tcbp->hb.local_port = sipTransportGetListenPort(tcbp->hb.dn_line, NULL);
tcbp->hb.event_type = not_datap->eventPackage;
// Copy any body received - it will be framed later
if (not_datap->eventData) {
tcbp->hb.event_data_p = not_datap->eventData;
not_datap->eventData = NULL;
}
(void) sll_append(s_TCB_list, tcbp);
if (sipSPISendSubNotify((ccsip_common_cb_t *)tcbp, FALSE) != TRUE) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to send Notify Message\n", fname);
free_tcb(tcbp);
return;
}
outgoingUnsolicitedNotifies++;
return;
}
/**
* This function will handle network generated response to unsolicited NOTIFY
*
* @param[in] pSipMessage - pointer to sipMessage_t
* @param[in] tcbp - pointer to associated trnsaction control block.
*
* @returns SIP_OK/SIP_ERROR
*/
int subsmanager_handle_ev_sip_unsolicited_notify_response (sipMessage_t *pSipMessage, sipTCB_t *tcbp)
{
int response_code = 0;
const char *fname = "subsmanager_handle_ev_sip_unsolicited_notify_response";
// Parse the return code
(void) sipGetResponseCode(pSipMessage, &response_code);
/*
* if the response is < 200, do nothing.
*/
if (response_code < 200) {
CCSIP_DEBUG_TASK(DEB_F_PREFIX"received %d response\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname), response_code);
return SIP_OK;
}
if ((response_code == SIP_CLI_ERR_UNAUTH) ||
(response_code == SIP_CLI_ERR_PROXY_REQD)) {
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Authentication Required\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
if (ccsip_common_util_generate_auth(pSipMessage, &tcbp->hb, SIP_METHOD_NOTIFY,
response_code, tcbp->full_ruri) == TRUE) {
if (sipSPISendSubNotify((ccsip_common_cb_t *)tcbp, TRUE) == TRUE) {
CCSIP_DEBUG_TASK(DEB_F_PREFIX"sent request with Auth header\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
return SIP_OK;
}
}
free_tcb (tcbp);
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to respond to auth challenge\n", fname);
return SIP_ERROR;
}
free_tcb(tcbp);
CCSIP_DEBUG_TASK(DEB_F_PREFIX"received %d response\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname), response_code);
return SIP_OK;
}
/**
* This function will handle outgoing unsolicited NOTIFY transaction timeout.
*
* @param[in] data - pointer to an id that identifies the TCB.
*
* @returns none.
*/
void subsmanager_unsolicited_notify_timeout (void *data)
{
const char *fname = "subsmanager_unsolicited_notify_timeout";
uint32_t trxn_id = (long)data;
sipTCB_t *temp_tcbp = NULL;
/*
* make sure that the TCB still exists.
*/
temp_tcbp = (sipTCB_t *)sll_next(s_TCB_list, NULL);
while (temp_tcbp != NULL) {
if (temp_tcbp->trxn_id == trxn_id) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"unsolicited notify transaction timedout\n", fname);
free_tcb(temp_tcbp);
return;
}
temp_tcbp = (sipTCB_t *)sll_next(s_TCB_list, temp_tcbp);
}
}
/**********************************************************
* Handle Application Response to a received Notify request
**********************************************************/
int
subsmanager_handle_ev_app_notify_response (cprBuffer_t buf)
{
sipspi_notify_resp_t *notify_resp;
sipSCB_t *scbp = NULL;
sipspi_msg_t *pSIPSPIMsg = NULL;
uint32_t cseq;
const char *fname = "subsmanager_handle_ev_app_notify_response";
pSIPSPIMsg = (sipspi_msg_t *) buf;
notify_resp = &(pSIPSPIMsg->msg.notify_resp);
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Processing an app notify response for"
" sub_id=%x\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname),
notify_resp->sub_id);
// Retrieve response parameters
/*
* Find SCB from the sub_id.
*/
scbp = find_scb_by_sub_id(notify_resp->sub_id, NULL);
if (scbp == NULL) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"no SCB for sub_id=%x found\n",
fname, notify_resp->sub_id);
return SIP_ERROR;
}
if (notify_resp->cseq == 0) {
cseq = scbp->last_recv_request_cseq;
} else {
cseq = notify_resp->cseq;
}
// Call function to make and send the response
if (sipSPISendSubscribeNotifyResponse(scbp,
(uint16_t)(notify_resp->response_code), cseq)) {
/*
* if the outstanding NOTIFY transaction is only one,
* then update the scbp->smState.
*/
if (scbp->outstandingIncomingNotifyTrxns == 1) {
if (scbp->smState == SUBS_STATE_SENT_SUBSCRIBE_RCVD_NOTIFY) {
scbp->smState = SUBS_STATE_SENT_SUBSCRIBE;
} else {
scbp->smState = SUBS_STATE_ACTIVE;
}
}
scbp->outstandingIncomingNotifyTrxns -= 1;
return (0);
}
return SIP_ERROR;
}
/********************************************************
* Handle Application Request to Terminate Subscription
********************************************************/
int
subsmanager_handle_ev_app_subscription_terminated (cprBuffer_t buf)
{
/*
* This function is used by the application to clean up a subscription
* whether internally or externally initiated. The application should have
* taken care of all the protocol related messaging before calling this
* function.
*/
const char *fname = "subsmanager_handle_ev_app_subscription_terminated";
sipspi_subscribe_term_t *subs_term;
int scb_index;
sipSCB_t *scbp;
sipspi_msg_t *pSIPSPIMsg = NULL;
pSIPSPIMsg = (sipspi_msg_t *) buf;
subs_term = &(pSIPSPIMsg->msg.subs_term);
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Processing terminate request for sub_id=%x\n",
DEB_F_PREFIX_ARGS(SIP_SUB, fname), subs_term->sub_id);
/*
* Find SCB from the sub_id and allow matching with request ID and
* eventPackage if sub id is not known.
*/
if (subs_term->sub_id == CCSIP_SUBS_INVALID_SUB_ID) {
/*
* find scb based on request_id and event package.
* This scenario is possible if application decides to terminate a
* subscription before subsmanager provides app with sub_id.
*/
for (scb_index = 0; scb_index < MAX_SCBS; scb_index++) {
if ((subsManagerSCBS[scb_index].request_id == subs_term->request_id) &&
(subsManagerSCBS[scb_index].hb.event_type == subs_term->eventPackage) &&
(!subsManagerSCBS[scb_index].pendingClean)) {
break;
}
}
if (scb_index >= MAX_SCBS) {
scbp = NULL;
} else {
scbp = &(subsManagerSCBS[scb_index]);
}
} else {
/* Find SCB by sub_id */
scbp = find_scb_by_sub_id(subs_term->sub_id, &scb_index);
}
if (scbp == NULL) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"no SCB for sub_id=%x or request id %d"
" and eventPackage %d found\n", fname,
subs_term->sub_id, subs_term->request_id,
subs_term->eventPackage);
return SIP_ERROR;
}
if (scbp->smState == SUBS_STATE_IDLE || scbp->pendingClean) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"SCB: scb=%d sub_id=%x has already been"
" cleaned up\n", fname,
scb_index, subs_term->sub_id);
return 0;
}
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Cleaning out subscription for SCB: scb=%d sub_id=%x\n",
DEB_F_PREFIX_ARGS(SIP_SUB, fname), scb_index, scbp->sub_id);
if (scbp->internal) {
outgoingSubscriptions--;
} else {
incomingSubscriptions--;
}
// There could still be messages left to receive and flush, so if not
// immediate, we mark this SCB as pending deletion and we will clean it up
// later
if (subs_term->immediate) {
free_scb(scb_index, fname);
} else {
scbp->pendingClean = TRUE;
if (scbp->pendingRequests)
scbp->pendingCount = 2 * TMR_PERIODIC_SUBNOT_INTERVAL;
else
scbp->pendingCount = 1 * TMR_PERIODIC_SUBNOT_INTERVAL;
}
return (0);
}
/********************************************************
* Handle network response to a Sub/Not request
********************************************************/
int
subsmanager_handle_ev_sip_response (sipMessage_t *pSipMessage)
{
const char *fname = "subsmanager_handle_ev_sip_response";
sipSCB_t *scbp;
int scb_index;
ccsip_sub_not_data_t sub_not_result_data;
// currently not used SysHdr *pSm = NULL;
int response_code = 0;
const char *pCallID = NULL;
const char *rsp_method = NULL;
sipMethod_t method = sipMethodInvalid;
sipStatusCodeClass_t code_class = codeClassInvalid;
const char *expires = NULL;
long expiry_time;
const char *to = NULL, *from = NULL;
const char *record_route = NULL;
sipLocation_t *to_loc = NULL;
sipCseq_t *resp_cseq_structure = NULL;
uint32_t cseq;
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Processing a response\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
if (sipGetResponseMethod(pSipMessage, &method) < 0) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
fname, "sipGetResponseMethod");
return SIP_ERROR;
}
if (method == sipMethodSubscribe) {
rsp_method = SIP_METHOD_SUBSCRIBE;
} else if (method == sipMethodRefer) {
rsp_method = SIP_METHOD_REFER;
} else {
rsp_method = SIP_METHOD_NOTIFY;
}
pCallID = sippmh_get_cached_header_val(pSipMessage, CALLID);
if (!pCallID) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Cannot obtain SIP Call ID.\n", fname);
return SIP_ERROR;
}
if (!getCSeqInfo(pSipMessage, &resp_cseq_structure)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Cannot obtain SIP CSEQ.\n", fname);
return SIP_ERROR;
}
cseq = resp_cseq_structure->number;
cpr_free(resp_cseq_structure);
// Locate request scbp from that match the response
scbp = find_req_scb(pCallID, method, cseq, &scb_index);
if (!scbp) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"No matching request found\n", fname);
return SIP_ERROR;
}
// Cancel any outstanding retry timer
if (scbp->hb.retx_flag == TRUE) {
sip_platform_msg_timer_subnot_stop(&sipPlatformUISMSubNotTimers[scb_index]);
scbp->hb.retx_flag = FALSE;
}
// Parse the return code
(void) sipGetResponseCode(pSipMessage, &response_code);
code_class = sippmh_get_code_class((uint16_t) response_code);
/*
* If it is a response (18x/2xx) to a dialog initiating SUBSCRIBE,
* parse the Record-Route header and set up Route set for this dialog.
* If the sip_to_tag is not yet populated and if there is no associated
* CCB, then this can be considered as a response to dialog
* initating SUBSCRIBE.
*/
if ((strcmp(rsp_method, SIP_METHOD_SUBSCRIBE) == 0) &&
(scbp->ccbp == NULL) && (scbp->sip_to_tag[0] == '\0')) {
if (((response_code >= 180) && (response_code <= 189)) ||
((response_code >= 200) && (response_code <= 299))) {
record_route = sippmh_get_cached_header_val(pSipMessage,
RECORD_ROUTE);
if (record_route) {
if (scbp->record_route_info) {
sippmh_free_record_route(scbp->record_route_info);
}
scbp->record_route_info = sippmh_parse_record_route(record_route);
if (scbp->record_route_info == NULL) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sippmh_parse_record_route() failed",
fname);
return SIP_ERROR;
}
}
}
}
if ((response_code == SIP_CLI_ERR_UNAUTH) ||
(response_code == SIP_CLI_ERR_PROXY_REQD)) {
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Authentication Required\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
if (ccsip_common_util_generate_auth(pSipMessage, (ccsip_common_cb_t *)scbp, rsp_method,
response_code, scbp->SubURI) == TRUE) {
// Send Sub/Not message again - this time with authorization
if ((method == sipMethodSubscribe) || (method == sipMethodRefer)) {
(void) sipSPISendSubscribe(scbp, TRUE, TRUE);
} else {
(void) sipSPISendSubNotify((ccsip_common_cb_t *)scbp, TRUE);
}
} else {
// Return error to caller
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to generate Auth header", fname);
return SIP_ERROR;
}
return (0);
}
// If this subscription has been cleaned by the application, then
// return SCB to IDLE state and discard this response
if (scbp->pendingClean) {
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Recd msg for terminated sub\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
if (scbp->pendingRequests) {
scbp->pendingCount += TMR_PERIODIC_SUBNOT_INTERVAL;
scbp->smState = SUBS_STATE_ACTIVE;
handle_pending_requests(scbp);
} else {
free_scb(scb_index, fname);
}
return (0);
}
/*
* if response code is 423, grab Min-Expires and let app know so
* that it can be used for subsequent subscriptions.
*/
if ((response_code == SIP_CLI_ERR_INTERVAL_TOO_SMALL) &&
(strcmp(rsp_method, SIP_METHOD_SUBSCRIBE) == 0)) {
expires = sippmh_get_header_val(pSipMessage,
(const char *)SIP_HEADER_MIN_EXPIRES,
NULL);
if (expires) {
expiry_time = strtoul(expires, NULL, 10);
//ensure new Min-Expires is > what we set before in Expires
if ((long) expiry_time > scbp->hb.expires) {
scbp->hb.expires = expiry_time;
}
}
} else {
// Get the expires header value and add to scb
expires = sippmh_get_header_val(pSipMessage, SIP_HEADER_EXPIRES, NULL);
if (expires) {
expiry_time = strtoul(expires, NULL, 10);
scbp->hb.expires = expiry_time;
}
}
// update to and from headers to capture the tag
if (strcmp(rsp_method, SIP_METHOD_SUBSCRIBE) == 0) {
to = sippmh_get_cached_header_val(pSipMessage, TO);
from = sippmh_get_cached_header_val(pSipMessage, FROM);
scbp->sip_to = strlib_update(scbp->sip_to, to);
// grab the to-tag if present, and if this is a response to a SUBSCRIBE
to_loc = sippmh_parse_from_or_to((char *) to, TRUE);
if (to_loc != NULL) {
if (to_loc->tag != NULL) {
scbp->sip_to_tag = strlib_update(scbp->sip_to_tag,
sip_sm_purify_tag(to_loc->tag));
}
sippmh_free_location(to_loc);
}
scbp->sip_from = strlib_update(scbp->sip_from, from);
}
// Delete body, if any, since it is no longer needed
if (code_class > codeClass1xx) {
if (scbp->hb.event_data_p) {
free_event_data(scbp->hb.event_data_p);
scbp->hb.event_data_p = NULL;
}
}
if ((scbp->smState == SUBS_STATE_SENT_SUBSCRIBE_RCVD_NOTIFY) ||
(scbp->smState == SUBS_STATE_SENT_SUBSCRIBE)) {
sub_not_result_data.u.subs_result_data.expires = scbp->hb.expires;
sub_not_result_data.u.subs_result_data.status_code = response_code;
sub_not_result_data.request_id = scbp->request_id;
sub_not_result_data.sub_id = scbp->sub_id;
sub_not_result_data.msg_id = scbp->subsResCallbackMsgID;
sub_not_result_data.gsm_id = scbp->gsm_id;
sub_not_result_data.line_id = scbp->hb.dn_line;
if (code_class > codeClass1xx) {
if (scbp->smState == SUBS_STATE_SENT_SUBSCRIBE_RCVD_NOTIFY) {
scbp->smState = SUBS_STATE_RCVD_NOTIFY;
} else {
scbp->smState = SUBS_STATE_ACTIVE;
}
}
if (scbp->subsResultCallback) {
(scbp->subsResultCallback) (&sub_not_result_data);
} else if (scbp->subsNotCallbackTask != CC_SRC_MIN) {
(void) sip_send_message(&sub_not_result_data,
scbp->subsNotCallbackTask,
scbp->subsResCallbackMsgID);
}
} else if ((scbp->smState == SUBS_STATE_SENT_NOTIFY) ||
(scbp->smState == SUBS_STATE_RCVD_SUBSCRIBE_SENT_NOTIFY)) {
sub_not_result_data.u.notify_result_data.status_code = response_code;
sub_not_result_data.request_id = scbp->request_id;
sub_not_result_data.sub_id = scbp->sub_id;
sub_not_result_data.msg_id = scbp->notResCallbackMsgID;
sub_not_result_data.gsm_id = scbp->gsm_id;
sub_not_result_data.line_id = scbp->hb.dn_line;
if (code_class > codeClass1xx) {
if (scbp->smState == SUBS_STATE_RCVD_SUBSCRIBE_SENT_NOTIFY) {
scbp->smState = SUBS_STATE_RCVD_SUBSCRIBE;
} else {
scbp->smState = SUBS_STATE_ACTIVE;
}
}
if (scbp->notifyResultCallback) {
(scbp->notifyResultCallback) (&sub_not_result_data);
} else if (scbp->subsNotCallbackTask != CC_SRC_MIN) {
(void) sip_send_message(&sub_not_result_data,
scbp->subsNotCallbackTask,
scbp->notResCallbackMsgID);
}
// If there are pending requests - handle them now
if (scbp->pendingRequests) {
handle_pending_requests(scbp);
}
} else {
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Incorrect SCB State\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
return SIP_ERROR;
}
return (0);
}
/********************************************************
* Handle Network Received Subscribe Request
********************************************************/
int
subsmanager_handle_ev_sip_subscribe (sipMessage_t *pSipMessage,
sipMethod_t sipMethod,
boolean in_dialog)
{
const char *fname = "subsmanager_handle_ev_sip_subscribe";
const char *event = NULL;
cc_subscriptions_t eventPackage = CC_SUBSCRIPTIONS_NONE;
sipSCB_t *scbpReg = NULL, *scbp = NULL;
const char *callID = NULL, *via = NULL;
const char *contact = NULL;
const char *record_route = NULL;
const char *expires = NULL;
const char *require = NULL, *supported = NULL;
sipCseq_t *request_cseq_structure = NULL;
unsigned long request_cseq_number = 0, expiry_time = 0;
// currently not used unsigned long diff_time = 0;
sipMethod_t request_cseq_method = sipMethodInvalid;
unsigned int content_length = 0;
line_t dn_line = 0;
boolean request_uri_error = FALSE;
sipReqLine_t *requestURI = NULL;
// currently not used sipLocation_t *uri_loc = NULL;
genUrl_t *genUrl = NULL;
const char *sip_from = NULL;
const char *sip_to = NULL;
sipLocation_t *to_loc = NULL;
sipLocation_t *from_loc = NULL;
sipUrl_t *sipUriUrl = NULL, *sipFromUrl = NULL;
char *pUser = NULL;
char *sip_to_tag_temp, *sip_to_temp;
char *kpml_call_id = NULL, *from_tag, *to_tag;
ccsip_event_data_t *subDatap = NULL;
int scb_index;
boolean reSubscribe = FALSE;
ccsip_sub_not_data_t subs_ind_data;
ccsipCCB_t *ccb = NULL;
char *referToString = NULL;
uint32_t tags = 0;
int result;
int requestStatus = SIP_MESSAGING_ERROR;
uint8_t i;
char line_contact[MAX_LINE_CONTACT_SIZE];
char line_name[MAX_LINE_NAME_SIZE];
int noOfReferTo = 0;
sipServiceControl_t *scp=NULL;
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Processing a new SIP subscription request\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
if (!subsManagerRunning) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Subscription Manager Not Initialized!\n", fname);
return SIP_ERROR;
}
/* Steps:
* * Check request for support by a registered app
* * If not, reject the request as unsupported
* * Decode the body, if any, and if understood
* * Allocate and fill in SCB
* * Call the callback function by registered application
*/
if (!in_dialog) {
requestStatus = sipSPICheckRequest(NULL, pSipMessage);
if (requestStatus != SIP_MESSAGING_OK) {
if (requestStatus == SIP_MESSAGING_DUPLICATE) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Recieved duplicate request\n", fname);
} else {
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);
}
}
return SIP_ERROR;
}
}
memset(&subs_ind_data, 0, sizeof(ccsip_sub_not_data_t));
// Get relevant parameters from the SIP message
// These are: Event, Subscription-State, Accept, Content-Length besides
// To, From, Via, Call-ID, CSeq, and Contact
event = sippmh_get_header_val(pSipMessage, SIP_HEADER_EVENT,
SIP_C_HEADER_EVENT);
if (event) {
if (cpr_strcasecmp(event, "dialog") == 0) {
eventPackage = CC_SUBSCRIPTIONS_DIALOG;
} else if (cpr_strncasecmp(event, "kpml", 4) == 0) {
eventPackage = CC_SUBSCRIPTIONS_KPML;
} else if (cpr_strcasecmp(event, "presence") == 0) {
eventPackage = CC_SUBSCRIPTIONS_PRESENCE;
} else {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unsupported event=%s\n", fname, event);
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_EVENT,
SIP_CLI_ERR_BAD_EVENT_PHRASE,
0, NULL, NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_CLI_ERR_BAD_EVENT);
}
return SIP_ERROR;
}
} else if (sipMethod == sipMethodRefer) {
} else if (sipMethod == sipMethodBye) {
return SIP_ERROR;
} else {
// Reached here in error
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"No event header\n", fname);
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_EVENT,
SIP_CLI_ERR_BAD_EVENT_PHRASE,
SIP_WARN_MISC,
NULL,
NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_CLI_ERR_BAD_EVENT);
}
return SIP_ERROR;
}
// Parse Call-ID
callID = sippmh_get_cached_header_val(pSipMessage, CALLID);
if (!callID) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unable to obtain request's "
"Call-ID header.\n", fname);
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
SIP_CLI_ERR_BAD_REQ_PHRASE,
SIP_WARN_MISC,
SIP_CLI_ERR_BAD_REQ_CALLID_ABSENT,
NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_CLI_ERR_BAD_REQ);
}
return SIP_ERROR;
}
// Check content
content_length = sippmh_get_content_length(pSipMessage);
if (pSipMessage->raw_body) {
if (content_length != strlen(pSipMessage->raw_body)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"\n Mismatched Content length and \
Actual message body length:content length=%d \
\n and message as %s \
\n and strlenof messagebody = %d\n", fname,
content_length, pSipMessage->raw_body,
strlen(pSipMessage->raw_body));
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
SIP_CLI_ERR_BAD_REQ_PHRASE,
SIP_WARN_MISC,
SIP_CLI_ERR_BAD_REQ_CONTENT_LENGTH_ERROR,
NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_CLI_ERR_BAD_REQ);
}
return SIP_ERROR;
}
} else if (content_length != 0) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"\n Mismatched Content length and \
Actual message body length:content length=%d \
\n and message is EMPTY \
\n and strlenof messagebody = 0\n", fname,
content_length);
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
SIP_CLI_ERR_BAD_REQ_PHRASE,
SIP_WARN_MISC,
SIP_CLI_ERR_BAD_REQ_CONTENT_LENGTH_ERROR,
NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_CLI_ERR_BAD_REQ);
}
return SIP_ERROR;
}
// Parse CSEQ
if (getCSeqInfo(pSipMessage, &request_cseq_structure) == FALSE) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unable to obtain or parse request's CSeq "
"header.\n", fname);
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
SIP_CLI_ERR_BAD_REQ_PHRASE,
SIP_WARN_MISC,
SIP_CLI_ERR_BAD_REQ_CSEQ_FIELD,
NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_CLI_ERR_BAD_REQ);
}
return SIP_ERROR;
}
request_cseq_number = request_cseq_structure->number;
request_cseq_method = request_cseq_structure->method;
cpr_free(request_cseq_structure);
// Parse From
sip_from = sippmh_get_cached_header_val(pSipMessage, FROM);
from_loc = sippmh_parse_from_or_to((char *) sip_from, TRUE);
if (!from_loc) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
fname,
get_debug_string(DEBUG_FUNCTIONNAME_SIPPMH_PARSE_FROM));
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
SIP_CLI_ERR_BAD_REQ_PHRASE,
SIP_WARN_MISC,
SIP_CLI_ERR_BAD_REQ_FROM_OR_TO_FIELD,
NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_CLI_ERR_BAD_REQ);
}
return SIP_ERROR;
}
// Parse To
sip_to = sippmh_get_cached_header_val(pSipMessage, TO);
to_loc = sippmh_parse_from_or_to((char *) sip_to, TRUE);
if (!to_loc) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
fname,
get_debug_string(DEBUG_FUNCTIONNAME_SIPPMH_PARSE_TO));
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
SIP_CLI_ERR_BAD_REQ_PHRASE,
SIP_WARN_MISC,
SIP_CLI_ERR_BAD_REQ_FROM_OR_TO_FIELD,
NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_CLI_ERR_BAD_REQ);
}
sippmh_free_location(from_loc);
return SIP_ERROR;
}
// Parse Req-URI
requestURI = sippmh_get_request_line(pSipMessage);
if (requestURI) {
if (requestURI->url) {
genUrl = sippmh_parse_url(requestURI->url, TRUE);
if (genUrl) {
if (genUrl->schema != URL_TYPE_SIP) {
request_uri_error = TRUE;
}
} else {
request_uri_error = TRUE;
}
} else {
request_uri_error = TRUE;
}
} else {
request_uri_error = TRUE;
}
if (request_uri_error) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Invalid Request URI" "failed.\n", fname);
if (to_loc)
sippmh_free_location(to_loc);
if (from_loc)
sippmh_free_location(from_loc);
if (genUrl)
sippmh_genurl_free(genUrl);
if (requestURI)
SIPPMH_FREE_REQUEST_LINE(requestURI);
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
SIP_CLI_ERR_BAD_REQ_PHRASE,
SIP_WARN_MISC,
SIP_CLI_ERR_BAD_REQ_URL_ERROR,
NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_CLI_ERR_BAD_REQ);
}
return SIP_ERROR;
}
// Parse Expires header
expires = sippmh_get_header_val(pSipMessage, SIP_HEADER_EXPIRES, NULL);
if (expires) {
expiry_time = strtoul(expires, NULL, 10);
} else {
// No expires header, use default
expiry_time = 3600;
}
scbp = find_scb_by_subscription(eventPackage, &scb_index, callID);
if (scbp && eventPackage == scbp->hb.event_type) {
// SCB is already there - must be a re-subscribe
reSubscribe = TRUE;
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Received a reSubscribe Message\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
if (scbp->pendingClean) {
// Oops, the application has already terminated this subscription
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Subscribe received for subscription "
"already terminated by application.\n", fname);
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
SIP_CLI_ERR_BAD_REQ_PHRASE,
SIP_WARN_MISC,
SIP_CLI_ERR_BAD_REQ_SUBSCRIPTION_DELETED,
NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_CLI_ERR_BAD_REQ);
}
sippmh_free_location(to_loc);
sippmh_free_location(from_loc);
sippmh_genurl_free(genUrl);
SIPPMH_FREE_REQUEST_LINE(requestURI);
return SIP_ERROR;
}
// Check continuity of CSeq numbers
if (request_cseq_number <= scbp->last_recv_request_cseq) {
// Return 500 Internal Server Error
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Out of order CSeq number received\n",
fname);
if (sipSPISendErrorResponse(pSipMessage, SIP_SERV_ERR_INTERNAL,
SIP_SERV_ERR_INTERNAL_PHRASE,
SIP_WARN_MISC,
SIP_CLI_ERR_BAD_REQ_CSEQ_FIELD,
NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_SERV_ERR_INTERNAL);
}
sippmh_free_location(to_loc);
sippmh_free_location(from_loc);
sippmh_genurl_free(genUrl);
SIPPMH_FREE_REQUEST_LINE(requestURI);
return SIP_ERROR;
}
sippmh_free_location(to_loc);
sippmh_free_location(from_loc);
sippmh_genurl_free(genUrl);
SIPPMH_FREE_REQUEST_LINE(requestURI);
} else {
// Check if this is a SUBSCRIBE request for an already terminated
// subscription. If this subscription is associated with an
// existing dialog, let it go
ccb = sip_sm_get_ccb_by_callid(callID);
if ((ccb == NULL) &&
is_previous_sub(callID, from_loc->tag, eventPackage)) {
// Return 481 Internal Server Error
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"SUBSCRIBE received for terminated "
"subscription\n", fname);
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_CALLEG,
SIP_CLI_ERR_CALLEG_PHRASE,
SIP_WARN_MISC,
SIP_CLI_ERR_BAD_REQ_SUBSCRIPTION_DELETED,
NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_CLI_ERR_CALLEG);
}
sippmh_free_location(to_loc);
sippmh_free_location(from_loc);
sippmh_genurl_free(genUrl);
SIPPMH_FREE_REQUEST_LINE(requestURI);
return SIP_ERROR;
}
// This is a valid new subscription - get all the params
scbpReg = find_scb_by_registration(eventPackage, &scb_index);
if (!scbpReg) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"No application registered "
"to accept this event.\n", fname);
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_EVENT,
SIP_CLI_ERR_BAD_EVENT_PHRASE,
0, NULL, NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_CLI_ERR_BAD_EVENT);
}
sippmh_free_location(to_loc);
sippmh_free_location(from_loc);
sippmh_genurl_free(genUrl);
SIPPMH_FREE_REQUEST_LINE(requestURI);
return SIP_ERROR;
}
scbp = allocate_scb(&scb_index);
if (!scbp) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"No SCB Available "
"to accept this event.\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_CLI_ERR_BAD_REQ);
}
sippmh_free_location(to_loc);
sippmh_free_location(from_loc);
sippmh_genurl_free(genUrl);
SIPPMH_FREE_REQUEST_LINE(requestURI);
show_scbs_inuse();
return SIP_ERROR;
}
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Allocated SCB for Received Subscribe, event=%d,"
" scb=%d sub_id=%x\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname), scbpReg->hb.event_type,
scb_index, scbp->sub_id);
scbp->hb.event_type = scbpReg->hb.event_type;
scbp->subsIndCallback = scbpReg->subsIndCallback;
scbp->subsIndCallbackTask = scbpReg->subsIndCallbackTask;
scbp->subsNotCallbackTask = scbpReg->subsNotCallbackTask;
scbp->subsIndCallbackMsgID = scbpReg->subsIndCallbackMsgID;
scbp->subsTermCallback = scbpReg->subsTermCallback;
scbp->subsTermCallbackMsgID = scbpReg->subsTermCallbackMsgID;
sstrncpy(scbp->event_name, scbpReg->event_name, MAX_EVENT_NAME_LEN);
scbp->internal = FALSE;
/* If the event package is KPML then check if the ID values
* are associated with it
*/
if (eventPackage == CC_SUBSCRIPTIONS_KPML) {
/*
* At this point from_tag and to_tag is never used. Since
* kpml_call_id, from_tag and to_tag just point to the
* appropriate location and does not allocate memory by itself.
*/
(void) sippmh_parse_kpml_event_id_params((char *)event,
&kpml_call_id,
&from_tag,
&to_tag);
}
if (kpml_call_id) {
ccb = sip_sm_get_ccb_by_callid(kpml_call_id);
} else {
ccb = sip_sm_get_ccb_by_callid(callID);
scbp->ccbp = ccb;
}
if (ccb) {
scbp->gsm_id = ccb->gsm_id;
scbp->hb.dn_line = ccb->dn_line;
} else {
scbp->gsm_id = 0;
scbp->hb.dn_line = 0;
}
// Parse Supported and Required headers to see if there is the
// norefersub option tag specified
require = sippmh_get_cached_header_val(pSipMessage, REQUIRE);
if (require) {
tags = sippmh_parse_supported_require(require, NULL);
if (tags & norefersub_tag) {
scbp->norefersub = TRUE;
}
}
if ((eventPackage == CC_SUBSCRIPTIONS_CONFIGAPP) &&
(scbp->norefersub == FALSE)) {
//noReferSub tag is required for OOD Refer for config change
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"noReferSub missing from Require header.\n",
fname);
if (sipSPISendErrorResponse(pSipMessage,
SIP_CLI_ERR_BAD_REQ,
SIP_CLI_ERR_BAD_REQ_PHRASE,
SIP_WARN_MISC,
SIP_CLI_ERR_BAD_REQ_REQUIRE_HDR,
NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_CLI_ERR_BAD_REQ);
}
free_scb(scb_index, fname);
sippmh_free_location(to_loc);
sippmh_free_location(from_loc);
sippmh_genurl_free(genUrl);
SIPPMH_FREE_REQUEST_LINE(requestURI);
return SIP_ERROR;
}
supported = sippmh_get_cached_header_val(pSipMessage, SUPPORTED);
if (supported) {
tags = sippmh_parse_supported_require(supported, NULL);
if (tags & norefersub_tag) {
scbp->norefersub = TRUE;
}
}
// Check to see if the expires value is within the acceptable range,
// if any has been given to us
if (scbp->min_expires != 0) {
if (expiry_time < scbp->min_expires && expiry_time < 3600) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Too small expiry time: %d; "
"Min acceptable: %d.\n", fname,
expiry_time, scbp->min_expires);
if (sipSPISendErrorResponse(pSipMessage,
SIP_CLI_ERR_INTERVAL_TOO_SMALL,
SIP_CLI_ERR_INTERVAL_TOO_SMALL_PHRASE,
0, NULL, NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_CLI_ERR_INTERVAL_TOO_SMALL);
}
free_scb(scb_index, fname);
sippmh_free_location(to_loc);
sippmh_free_location(from_loc);
sippmh_genurl_free(genUrl);
SIPPMH_FREE_REQUEST_LINE(requestURI);
return SIP_ERROR;
}
}
if (scbp->max_expires != 0) {
if (expiry_time > scbp->max_expires) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Too large expiry time: %d; "
"Max acceptable: %d.\n", fname,
expiry_time, scbp->max_expires);
// There doesn't seem to be any particular error code for
// maximum expiry time so just return the generic error
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
SIP_CLI_ERR_BAD_REQ_PHRASE,
SIP_WARN_MISC,
SIP_CLI_ERR_INTERVAL_TOO_LARGE_PHRASE,
NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_CLI_ERR_BAD_REQ);
}
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Freeing SCB: scb=%d sub_id=%x\n",
DEB_F_PREFIX_ARGS(SIP_SUB, fname), scb_index, scbp->sub_id);
free_scb(scb_index, fname);
sippmh_free_location(to_loc);
sippmh_free_location(from_loc);
sippmh_genurl_free(genUrl);
SIPPMH_FREE_REQUEST_LINE(requestURI);
return SIP_ERROR;
}
}
sipUriUrl = genUrl->u.sipUrl;
if (sipUriUrl) {
pUser = sippmh_parse_user(sipUriUrl->user);
if (pUser) {
sstrncpy(scbp->SubURI, pUser, sizeof(scbp->SubURI));
cpr_free(pUser);
} else {
/* An error occurred, copy the whole thing.. */
sstrncpy(scbp->SubURI, sipUriUrl->user, sizeof(scbp->SubURI));
}
}
sippmh_genurl_free(genUrl);
SIPPMH_FREE_REQUEST_LINE(requestURI);
scbp->sip_from = strlib_update(scbp->sip_from, sip_from);
if (from_loc->tag) {
scbp->sip_from_tag = strlib_update(scbp->sip_from_tag,
sip_sm_purify_tag(from_loc->tag));
}
if (from_loc->genUrl->schema == URL_TYPE_SIP) {
sipFromUrl = from_loc->genUrl->u.sipUrl;
}
if (sipFromUrl) {
if (sipFromUrl->user) {
char *pUserTemp, *target = NULL, addr_error;
uint32_t sip_address = 0;
pUserTemp = sippmh_parse_user(sipFromUrl->user);
if (pUserTemp) {
scbp->callingNumber = strlib_update(scbp->callingNumber,
pUserTemp);
cpr_free(pUserTemp);
} else {
scbp->callingNumber = strlib_update(scbp->callingNumber,
sipFromUrl->user);
}
target = cpr_strdup(sipFromUrl->host);
if (!target) {
sip_address = 0;
} else {
//CPR TODO: need reference for
//Should replace with a boolean util_check_ip_addr(char *addr) call
sip_address = IPNameCk(target, &addr_error);
cpr_free(target);
}
if ((from_loc->genUrl->schema == URL_TYPE_SIP) &&
(!sip_address)) {
if (scbp->callingNumber) {
scbp->callingNumber = strlib_append(scbp->callingNumber, "@");
scbp->callingNumber = strlib_append(scbp->callingNumber, sipFromUrl->host);
}
}
} else {
scbp->callingNumber = strlib_update(scbp->callingNumber,
"Unknown Number");
}
}
scbp->sip_to = strlib_update(scbp->sip_to, sip_to);
if (to_loc->tag == NULL) {
// Create To tag
sip_to_tag_temp = strlib_open(scbp->sip_to_tag, MAX_SIP_TAG_LENGTH);
if (sip_to_tag_temp) {
sip_util_make_tag(sip_to_tag_temp);
}
scbp->sip_to_tag = strlib_close(sip_to_tag_temp);
sip_to_temp = strlib_open(scbp->sip_to, MAX_SIP_URL_LENGTH);
if (sip_to_temp) {
sstrncat(sip_to_temp, ";tag=",
MAX_SIP_URL_LENGTH - strlen(sip_to_temp));
if (scbp->sip_to_tag) {
sstrncat(sip_to_temp, scbp->sip_to_tag,
MAX_SIP_URL_LENGTH - strlen(sip_to_temp));
}
}
scbp->sip_to = strlib_close(sip_to_temp);
}
sippmh_free_location(to_loc);
sippmh_free_location(from_loc);
sstrncpy(scbp->hb.sipCallID, callID, MAX_SIP_CALL_ID);
// Parse Contact info
contact = sippmh_get_cached_header_val(pSipMessage, CONTACT);
if (contact) {
if (scbp->contact_info) {
sippmh_free_contact(scbp->contact_info);
}
scbp->contact_info = sippmh_parse_contact(contact);
if ((scbp->contact_info == NULL) || // contact in msg, parse error
(sipSPICheckContact(contact) < 0)) { // If contact is invalid
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
SIP_CLI_ERR_BAD_REQ_PHRASE,
SIP_WARN_MISC,
SIP_CLI_ERR_BAD_REQ_CONTACT_FIELD,
NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_CLI_ERR_BAD_REQ);
}
free_scb(scb_index, fname);
return SIP_ERROR;
}
}
if ((sipMethod == sipMethodSubscribe) && (scbp->ccbp == NULL)) {
record_route = sippmh_get_cached_header_val(pSipMessage,
RECORD_ROUTE);
if (record_route) {
if (scbp->record_route_info) {
sippmh_free_record_route(scbp->record_route_info);
}
scbp->record_route_info = sippmh_parse_record_route(record_route);
if (scbp->record_route_info == NULL) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sippmh_parse_record_route() failed",
fname);
free_scb(scb_index, fname);
return SIP_ERROR;
}
/*
* Store the Record-Route header value to be used
* in 18x or 2xx response
*/
scbp->cached_record_route = strlib_update(scbp->cached_record_route,
record_route);
}
}
} // End of populating a new SCB
scbp->hb.expires = expiry_time;
scbp->hb.orig_expiration = expiry_time;
scbp->last_recv_request_cseq = request_cseq_number;
scbp->last_recv_request_cseq_method = request_cseq_method;
// Parse Refer-To
if (sipMethod == sipMethodRefer) {
sipReferTo_t *referto = NULL;
noOfReferTo = sippmh_get_num_particular_headers(pSipMessage,
SIP_HEADER_REFER_TO,
SIP_C_HEADER_REFER_TO,
&referToString,
MAX_REFER_TO_HEADERS);
if ((noOfReferTo == 0) || (noOfReferTo > 1)) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
scb_index, scbp->hb.dn_line, fname,
"Incorrect number of Refer-To headers\n");
(void) sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
SIP_CLI_ERR_BAD_REQ_PHRASE,
SIP_WARN_MISC,
SIP_CLI_ERR_BAD_REQ_PHRASE_REFER_TO,
NULL);
return SIP_ERROR;
}
// Note that the refer-to header is not parsed for CCM mode since it was
// malformed in older versions of CCM
if (sip_regmgr_get_cc_mode(1) != REG_MODE_CCM) {
referto = sippmh_parse_refer_to(referToString);
if (referto == NULL) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
scb_index, scbp->hb.dn_line, fname,
"Refer-To header could not be parsed\n");
(void) sipSPISendErrorResponse(pSipMessage,
SIP_CLI_ERR_BAD_REQ,
SIP_CLI_ERR_BAD_REQ_PHRASE,
SIP_WARN_MISC,
SIP_CLI_ERR_BAD_REQ_PHRASE_REFER_TO,
NULL);
return SIP_ERROR;
} else {
sippmh_free_refer_to(referto);
}
}
}
// Parse and store Via Header
via = sippmh_get_cached_header_val(pSipMessage, VIA);
if (via) {
/* store the via header */
if (store_incoming_trxn(via, request_cseq_number, scbp) == FALSE) {
(void) sipSPISendErrorResponse(pSipMessage,
SIP_SERV_ERR_INTERNAL,
SIP_SERV_ERR_INTERNAL_PHRASE,
0,
NULL,
NULL);
return SIP_ERROR;
}
}
// See if can determine dn_line from any of the parameters
// 1st try the REQ-URI
// CCM should send us
// SUBSCRIBE sip:<subscribed-line-pkid>@<phone-ip> SIP/2.0
// and we should be able to get the line from its pkid
if (scbp->hb.dn_line == 0) {
for (dn_line = 1; dn_line <= MAX_REG_LINES; dn_line++) {
if (sip_config_check_line(dn_line) == FALSE) {
continue;
}
config_get_line_string(CFGID_LINE_CONTACT, line_contact,
dn_line, sizeof(line_contact));
if (cpr_strcasecmp(line_contact, UNPROVISIONED) != 0) {
if (cpr_strcasecmp(scbp->SubURI, line_contact) == 0) {
scbp->hb.dn_line = dn_line;
break;
}
}
}
}
if (scbp->hb.dn_line == 0) {
// If no match there, check against the DN number
for (dn_line = 1; dn_line <= MAX_REG_LINES; dn_line++) {
config_get_line_string(CFGID_LINE_NAME, line_name,
dn_line, sizeof(line_name));
if (!cpr_strcasecmp(scbp->SubURI, line_name)) {
scbp->hb.dn_line = dn_line;
break;
}
}
}
// If unable to determine dn_line, the SUBSCRIBE is directed to device
// Could make sure and check against the MAC address here
if (scbp->hb.dn_line == 0) {
scbp->useDeviceAddressing = TRUE;
}
// Parse Body
subs_ind_data.u.subs_ind_data.eventData = NULL;
i = 0;
while (i < HTTPISH_MAX_BODY_PARTS && pSipMessage->mesg_body[i].msgBody
!= NULL) {
if (pSipMessage->mesg_body[i].msgContentTypeValue != SIP_CONTENT_TYPE_DIALOG_VALUE &&
pSipMessage->mesg_body[i].msgContentTypeValue != SIP_CONTENT_TYPE_KPML_REQUEST_VALUE &&
pSipMessage->mesg_body[i].msgContentTypeValue != SIP_CONTENT_TYPE_REMOTECC_REQUEST_VALUE &&
pSipMessage->mesg_body[i].msgContentTypeValue != SIP_CONTENT_TYPE_REMOTECC_RESPONSE_VALUE &&
pSipMessage->mesg_body[i].msgContentTypeValue != SIP_CONTENT_TYPE_CONFIGAPP_VALUE &&
pSipMessage->mesg_body[i].msgContentTypeValue != SIP_CONTENT_TYPE_PRESENCE_VALUE) {
if (pSipMessage->mesg_body[i].msgContentTypeValue == SIP_CONTENT_TYPE_CMXML_VALUE) {
// Body can not be parsed - send it up as it is
subDatap = (ccsip_event_data_t *) cpr_malloc(sizeof(ccsip_event_data_t));
if (subDatap == NULL) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"malloc of subDatap failed.\n",
fname);
return (0);
}
subDatap->u.raw_data.data = pSipMessage->mesg_body[i].msgBody;
subDatap->u.raw_data.length = pSipMessage->mesg_body[i].msgLength;
pSipMessage->mesg_body[i].msgBody = NULL;
pSipMessage->mesg_body[i].msgLength = 0;
subDatap->type = EVENT_DATA_RAW;
subDatap->next = NULL;
} else {
/* There are other applications that has been handled like syncCheck
*/
scp = sippmh_parse_service_control_body(pSipMessage->mesg_body[i].msgBody,
pSipMessage->mesg_body[i].msgLength);
if (scp != NULL) {
// Hand over the event to platform
sip_platform_handle_service_control_notify(scp);
sippmh_free_service_control_info(scp);
}
/* If this is the only body then have to send the response out as
* no other application will be requesting to send response
*/
if (i== 0 && pSipMessage->mesg_body[i+1].msgBody == NULL) {
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);
}
if (!reSubscribe) {
free_scb(scb_index, fname);
}
return(0);
}
}
} else {
result = parse_body(scbp->hb.event_type, pSipMessage->mesg_body[i].msgBody,
pSipMessage->mesg_body[i].msgLength, &subDatap, fname);
if (result == SIP_ERROR) {
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
SIP_CLI_ERR_BAD_REQ_PHRASE,
SIP_WARN_MISC,
SIP_CLI_ERR_BAD_REQ_BAD_BODY_ENCODING, NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_CLI_ERR_BAD_REQ);
}
if (!reSubscribe) {
free_scb(scb_index, fname);
}
free_event_data(subDatap);
free_event_data(subs_ind_data.u.subs_ind_data.eventData);
return SIP_ERROR;
}
}
if (subs_ind_data.u.subs_ind_data.eventData == NULL &&
subDatap != NULL) {
subs_ind_data.u.subs_ind_data.eventData = subDatap;
subDatap->next = NULL;
} else if (subs_ind_data.u.subs_ind_data.eventData != NULL &&
subDatap != NULL){
append_event_data(subs_ind_data.u.subs_ind_data.eventData,
subDatap);
}
i++;
}
// Prepare subscription indication data
subs_ind_data.event = eventPackage;
subs_ind_data.u.subs_ind_data.expires = scbp->hb.expires;
subs_ind_data.u.subs_ind_data.from = scbp->sip_from;
subs_ind_data.u.subs_ind_data.to = scbp->sip_to;
subs_ind_data.u.subs_ind_data.line = scbp->hb.dn_line;
subs_ind_data.sub_duration = scbp->hb.expires;
subs_ind_data.sub_id = scbp->sub_id;
subs_ind_data.msg_id = scbp->subsIndCallbackMsgID;
subs_ind_data.gsm_id = scbp->gsm_id;
subs_ind_data.line_id = scbp->hb.dn_line;
subs_ind_data.norefersub = scbp->norefersub;
subs_ind_data.request_id = -1;
// Eventually let the subscribing application know
if (scbp->subsIndCallback) {
(scbp->subsIndCallback) (&subs_ind_data);
} else if ((scbp->subsIndCallbackTask != CC_SRC_MIN) && (scbp->subsIndCallbackMsgID != 0)) {
(void) sip_send_message(&subs_ind_data, scbp->subsIndCallbackTask,
scbp->subsIndCallbackMsgID);
}
if (scbp->smState == SUBS_STATE_SENT_NOTIFY) {
scbp->smState = SUBS_STATE_RCVD_SUBSCRIBE_SENT_NOTIFY;
} else {
scbp->smState = SUBS_STATE_RCVD_SUBSCRIBE;
}
incomingSubscribes++;
if (!reSubscribe) {
incomingSubscriptions++;
}
return (0);
}
/**
* This function will decode the xml bodies.
*
* @param[in] event_type - event type.
* @param[in] pSipMessage - pointer to sipMessage_t
* @param[out] dataPP - pointer to pointer to decoded data.
*
* @returns TRUE/FALSE
*
* @pre (pSipMessage != NULL) && (dataPP != NULL)
*/
static boolean
decode_message_body (cc_subscriptions_t event_type, sipMessage_t *pSipMessage, ccsip_event_data_t **dataPP)
{
const char *fname = "decode_message_body";
uint8_t i = 0;
ccsip_event_data_t *notDatap = NULL;
int result;
// Decode the body, if any
while (i < HTTPISH_MAX_BODY_PARTS && pSipMessage->mesg_body[i].msgBody
!= NULL) {
if (pSipMessage->mesg_body[0].msgContentTypeValue != SIP_CONTENT_TYPE_DIALOG_VALUE &&
pSipMessage->mesg_body[0].msgContentTypeValue != SIP_CONTENT_TYPE_KPML_REQUEST_VALUE &&
pSipMessage->mesg_body[0].msgContentTypeValue != SIP_CONTENT_TYPE_REMOTECC_REQUEST_VALUE &&
pSipMessage->mesg_body[0].msgContentTypeValue != SIP_CONTENT_TYPE_REMOTECC_RESPONSE_VALUE &&
pSipMessage->mesg_body[0].msgContentTypeValue != SIP_CONTENT_TYPE_PRESENCE_VALUE) {
// Body can not be parsed - send it up as it is
notDatap = (ccsip_event_data_t *) cpr_malloc(sizeof(ccsip_event_data_t));
if (notDatap == NULL) {
CCSIP_DEBUG_ERROR("%s: Error - malloc of notDatap failed.\n",
fname);
return FALSE;
}
notDatap->u.raw_data.data = pSipMessage->mesg_body[0].msgBody;
notDatap->u.raw_data.length = pSipMessage->mesg_body[0].msgLength;
pSipMessage->mesg_body[0].msgBody = NULL;
pSipMessage->mesg_body[0].msgLength = 0;
notDatap->type = EVENT_DATA_RAW;
notDatap->next = NULL;
} else {
result = parse_body(event_type, pSipMessage->mesg_body[i].msgBody,
pSipMessage->mesg_body[i].msgLength, &notDatap, fname);
if (result == SIP_ERROR) {
free_event_data(notDatap);
free_event_data(*dataPP);
return FALSE;
}
}
if ((*dataPP) == NULL) {
(*dataPP) = notDatap;
notDatap->next = NULL;
} else {
append_event_data((*dataPP), notDatap);
}
i++;
}
return TRUE;
}
/********************************************************
* Handle Network Received Notify Request
********************************************************/
int
subsmanager_handle_ev_sip_subscribe_notify (sipMessage_t *pSipMessage)
{
const char *fname = "subsmanager_handle_ev_sip_subscribe_notify";
cc_subscriptions_t eventPackage;
sipSCB_t *scbp = NULL;
const char *callID = NULL;
const char *event = NULL;
int scb_index;
sipCseq_t *request_cseq_structure = NULL;
unsigned long request_cseq_number = 0;
sipMethod_t request_cseq_method = sipMethodInvalid;
ccsip_sub_not_data_t notify_ind_data;
int16_t requestStatus = SIP_MESSAGING_ERROR;
const char *from = NULL, *to = NULL;
const char *subs_state = NULL;
boolean subs_header_found = FALSE;
sipLocation_t *to_loc = NULL;
const char *via = NULL;
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Processing a network generated NOTIFY\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
memset(&notify_ind_data, 0, sizeof(notify_ind_data));
requestStatus = (uint16_t) sipSPICheckRequest(NULL, pSipMessage);
if (requestStatus != SIP_MESSAGING_OK) {
if (requestStatus == SIP_MESSAGING_DUPLICATE) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Received duplicate request\n", fname);
} else {
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);
}
}
return SIP_ERROR;
}
// Get fields from NOTIFY
event = sippmh_get_header_val(pSipMessage, SIP_HEADER_EVENT,
SIP_C_HEADER_EVENT);
if (event) {
if (cpr_strcasecmp(event, SIP_EVENT_DIALOG) == 0) {
eventPackage = CC_SUBSCRIPTIONS_DIALOG;
} else if (cpr_strcasecmp(event, SIP_EVENT_KPML) == 0) {
eventPackage = CC_SUBSCRIPTIONS_KPML;
} else if (cpr_strcasecmp(event, SIP_EVENT_CONFIG) == 0) {
eventPackage = CC_SUBSCRIPTIONS_CONFIG;
} else if (cpr_strcasecmp(event, SIP_EVENT_PRESENCE) == 0) {
eventPackage = CC_SUBSCRIPTIONS_PRESENCE;
} else if ((cpr_strcasecmp(event, SIP_EVENT_REFER) == 0) &&
(pSipMessage->mesg_body[0].msgContentTypeValue == SIP_CONTENT_TYPE_DIALOG_VALUE)) {
eventPackage = CC_SUBSCRIPTIONS_DIALOG;
} else {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unsupported event=%s\n", fname, event);
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_EVENT,
SIP_CLI_ERR_BAD_EVENT_PHRASE,
0, NULL, NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_CLI_ERR_BAD_EVENT);
}
return SIP_ERROR;
}
} else {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Missing Event header\n", fname);
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_EVENT,
SIP_CLI_ERR_BAD_EVENT_PHRASE,
0, NULL, NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_CLI_ERR_BAD_EVENT);
}
return SIP_ERROR;
}
callID = sippmh_get_cached_header_val(pSipMessage, CALLID);
if (!callID) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unable to obtain request's "
"Call-ID header.\n", fname);
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
SIP_CLI_ERR_BAD_REQ_PHRASE,
SIP_WARN_MISC,
SIP_CLI_ERR_BAD_REQ_CALLID_ABSENT,
NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_CLI_ERR_BAD_REQ);
}
return SIP_ERROR;
}
// Find the proper SCB
scbp = find_scb_by_subscription(eventPackage, &scb_index, callID);
if (!scbp) {
/*
* check if it is an unsolicited dialog/presence event NOTIFY
* check if it has a to-tag. if so, then it is not considered unsolicited NOTIFY.
* Presence of to-tag could be because it is a final NOTIFY of a subscription which
* we have just terminated.
*/
to = sippmh_get_cached_header_val(pSipMessage, TO);
to_loc = sippmh_parse_from_or_to((char *) to, TRUE);
if ((to_loc == NULL) || (to_loc->tag == NULL)) {
if (eventPackage == CC_SUBSCRIPTIONS_DIALOG) {
notify_ind_data.line_id = 1;
/* decode the body */
if (decode_message_body(CC_SUBSCRIPTIONS_DIALOG, pSipMessage,
&(notify_ind_data.u.notify_ind_data.eventData)) == FALSE) {
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_CLI_ERR_BAD_REQ);
return SIP_ERROR;
}
}
if (sipSPISendErrorResponse(pSipMessage, SIP_STATUS_SUCCESS,
SIP_SUCCESS_SETUP_PHRASE,
0, NULL, NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_STATUS_SUCCESS);
}
incomingUnsolicitedNotifies++;
sippmh_free_location(to_loc);
return (0);
} else if (eventPackage == CC_SUBSCRIPTIONS_PRESENCE) {
/* decode the body */
if (decode_message_body(CC_SUBSCRIPTIONS_PRESENCE, pSipMessage,
&(notify_ind_data.u.notify_ind_data.eventData)) == FALSE) {
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_CLI_ERR_BAD_REQ);
return SIP_ERROR;
}
}
pres_unsolicited_notify_ind(&notify_ind_data);
if (sipSPISendErrorResponse(pSipMessage, SIP_STATUS_SUCCESS,
SIP_SUCCESS_SETUP_PHRASE,
0, NULL, NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_STATUS_SUCCESS);
}
incomingUnsolicitedNotifies++;
sippmh_free_location(to_loc);
return (0);
}
}
sippmh_free_location(to_loc);
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"No prior subscription", fname);
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_CALLEG,
SIP_CLI_ERR_SUBS_DOES_NOT_EXIST_PHRASE,
0, NULL, NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_CLI_ERR_CALLEG);
}
return SIP_ERROR;
}
if (scbp->pendingClean) {
// Oops, the application has already terminated this subscription
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Notify received for subscription "
"already terminated by application.\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
if (sipSPISendErrorResponse(pSipMessage, SIP_SUCCESS_SETUP,
SIP_SUCCESS_SETUP_PHRASE,
0, NULL, NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_SUCCESS_SETUP);
}
return (0);
}
// Check SCB state
if (scbp->smState == SUBS_STATE_SENT_SUBSCRIBE) {
// Have just sent a SUBSCRIBE but have not received a response
// This could happen if the NOTIFY from the remote side comes in
// before its 2xx response to SUBSCRIBE does
// Should still process this as if received a 2xx response
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Bad subscription state: "
"But still processing out-of-turn NOTIFY.\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
}
// Copy stuff from the message into the SCB - the parts that we
// need to keep to respond to this request. This includes: Via&Branch
// (From and To & Tags, CallID are simply inverse of the ones in
// SUBSCRIBE), and CSeq
// Parse subscription state header
subs_state = sippmh_get_header_val(pSipMessage,
SIP_HEADER_SUBSCRIPTION_STATE,
SIP_HEADER_SUBSCRIPTION_STATE);
if (subs_state) {
sipSubscriptionStateInfo_t subsStateInfo;
memset(&subsStateInfo, 0, sizeof(sipSubscriptionStateInfo_t));
// Get the state, expires, retry-after and reason
if (sippmh_parse_subscription_state(&subsStateInfo, subs_state) == 0) {
// Store values in SCB
scbp->hb.expires = subsStateInfo.expires;
scbp->subscription_state = subsStateInfo.state;
scbp->retry_after = subsStateInfo.retry_after;
scbp->subscription_state_reason = subsStateInfo.reason;
subs_header_found = TRUE;
}
}
if (!subs_header_found) {
// Subscription-State header not present - reject
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unable to obtain or parse request's "
"Subs-state header.\n", fname);
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
SIP_CLI_ERR_BAD_REQ_PHRASE,
SIP_WARN_MISC,
SIP_CLI_ERR_BAD_REQ_NO_SUBSCRIPTION_HEADER,
NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_CLI_ERR_BAD_REQ);
}
// Send message to the app and let it decide what it wants
// to do with a bad NOTIFY
sip_subsManager_send_protocol_error(scbp, scb_index, FALSE);
return SIP_ERROR;
}
// Parse CSEQ
if (getCSeqInfo(pSipMessage, &request_cseq_structure) == FALSE) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Unable to obtain or parse request's CSeq "
"header.\n", fname);
if (sipSPISendErrorResponse(pSipMessage, SIP_CLI_ERR_BAD_REQ,
SIP_CLI_ERR_BAD_REQ_PHRASE,
SIP_WARN_MISC,
SIP_CLI_ERR_BAD_REQ_CSEQ_FIELD,
NULL) != TRUE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_SPI_SEND_ERROR),
fname, SIP_CLI_ERR_BAD_REQ);
}
// Send message to the app and let it decide what it wants
// to do with a bad NOTIFY
sip_subsManager_send_protocol_error(scbp, scb_index, FALSE);
return SIP_ERROR;
}
request_cseq_number = request_cseq_structure->number;
request_cseq_method = request_cseq_structure->method;
cpr_free(request_cseq_structure);
// Check continuity of CSeq numbers
if (request_cseq_number <= scbp->last_recv_request_cseq) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Out of order CSeq number received\n",
fname);
} else {
scbp->last_recv_request_cseq = request_cseq_number;
scbp->last_recv_request_cseq_method = request_cseq_method;
}
// Parse and store Via Header
via = sippmh_get_cached_header_val(pSipMessage, VIA);
if (via) {
/* store the via header */
if (store_incoming_trxn(via, request_cseq_number, scbp) == FALSE) {
(void) sipSPISendErrorResponse(pSipMessage,
SIP_SERV_ERR_INTERNAL,
SIP_SERV_ERR_INTERNAL_PHRASE,
0,
NULL,
NULL);
return SIP_ERROR;
}
}
// Update from/to headers - note this is reversed
// as we generated the initial SUBSCRIBE
to = sippmh_get_cached_header_val(pSipMessage, TO);
from = sippmh_get_cached_header_val(pSipMessage, FROM);
if (to) {
scbp->sip_from = strlib_update(scbp->sip_from, to);
}
if (from) {
scbp->sip_to = strlib_update(scbp->sip_to, from);
}
if ((scbp->smState == SUBS_STATE_SENT_SUBSCRIBE) ||
(scbp->smState == SUBS_STATE_SENT_SUBSCRIBE_RCVD_NOTIFY)) {
scbp->smState = SUBS_STATE_SENT_SUBSCRIBE_RCVD_NOTIFY;
} else {
scbp->smState = SUBS_STATE_RCVD_NOTIFY;
}
// Decode the body, if any
if (decode_message_body(eventPackage, pSipMessage, &(notify_ind_data.u.notify_ind_data.eventData)) == FALSE) {
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_CLI_ERR_BAD_REQ);
}
// Send message to the app and let it decide what it
// wants to do with a bad NOTIFY
sip_subsManager_send_protocol_error(scbp, scb_index, FALSE);
return SIP_ERROR;
}
// Fill out the return structure and call the callback routine
notify_ind_data.event = eventPackage;
notify_ind_data.sub_id = scbp->sub_id;
notify_ind_data.msg_id = scbp->notIndCallbackMsgID;
notify_ind_data.gsm_id = scbp->gsm_id;
notify_ind_data.line_id = scbp->hb.dn_line;
notify_ind_data.request_id = scbp->request_id;
notify_ind_data.u.notify_ind_data.subscription_state =
scbp->subscription_state;
notify_ind_data.u.notify_ind_data.expires = scbp->hb.expires;
notify_ind_data.u.notify_ind_data.retry_after = scbp->retry_after;
notify_ind_data.u.notify_ind_data.subscription_state_reason =
scbp->subscription_state_reason;
notify_ind_data.u.notify_ind_data.cseq = request_cseq_number;
if (scbp->notifyIndCallback) {
(scbp->notifyIndCallback) (&notify_ind_data);
} else if (scbp->subsNotCallbackTask != CC_SRC_MIN) {
(void) sip_send_message(&notify_ind_data, scbp->subsNotCallbackTask,
scbp->notIndCallbackMsgID);
}
scbp->outstandingIncomingNotifyTrxns += 1;
incomingNotifies++;
return (0);
}
static sipRet_t
sm_add_contact (ccsip_common_cb_t *cbp, sipMessage_t *msg)
{
char src_addr_str[MAX_IPADDR_STR_LEN];
uint8_t mac_address[MAC_ADDRESS_LENGTH];
char contact[MAX_LINE_CONTACT_SIZE];
char contact_str[MAX_SIP_URL_LENGTH];
size_t escaped_char_str_len;
sipSCB_t *scbp = (sipSCB_t *)cbp;
if (!cbp || !msg) {
return HSTATUS_FAILURE;
}
ipaddr2dotted(src_addr_str, &cbp->src_addr);
if ((cbp->cb_type == SUBNOT_CB) && (scbp->useDeviceAddressing)) {
platform_get_wired_mac_address(mac_address);
snprintf(contact_str, MAX_SIP_URL_LENGTH, "<sip:%.4x%.4x%.4x@%s:%d>",
mac_address[0] * 256 + mac_address[1],
mac_address[2] * 256 + mac_address[3],
mac_address[4] * 256 + mac_address[5],
src_addr_str, scbp->hb.local_port);
} else {
snprintf(contact_str, 6, "<sip:");
contact[0] = '\0';
config_get_line_string(CFGID_LINE_CONTACT, contact,
cbp->dn_line, sizeof(contact));
if ((cpr_strcasecmp(contact, UNPROVISIONED) == 0) ||
(contact[0] == '\0')) {
// pk-id has not been provisioned, use line name instead
config_get_line_string(CFGID_LINE_NAME, contact,
cbp->dn_line, sizeof(contact));
}
escaped_char_str_len = sippmh_convertURLCharToEscChar(contact,
strlen(contact),
contact_str + 5,
(MAX_SIP_URL_LENGTH - 5),
FALSE);
snprintf(contact_str + 5 + escaped_char_str_len,
sizeof(contact_str) - 5 - escaped_char_str_len,
"@%s:%d;transport=%s>", src_addr_str, cbp->local_port,
sipTransportGetTransportType(cbp->dn_line, TRUE, NULL));
}
return sippmh_add_text_header(msg, SIP_HEADER_CONTACT, contact_str);
}
static sipRet_t
sm_add_cseq (sipSCB_t *scbp, sipMethod_t method, sipMessage_t *msg)
{
uint32_t cseq_number;
if (!scbp || !msg) {
return HSTATUS_FAILURE;
}
if (scbp->ccbp) {
// Use cseq from CCB
cseq_number = ++(scbp->ccbp->last_used_cseq);
/*
* Remember CSEQ for the request aside from ccb so that
* CSEQ can be match when response is received (can not.
* depend on last CSEQ stored on CCB since it can be
* changed).
*/
scbp->last_sent_request_cseq = cseq_number;
} else if (scbp->last_sent_request_cseq == 0) {
cseq_number = scbp->last_sent_request_cseq = CCSIP_SUBS_START_CSEQ;
} else {
cseq_number = ++(scbp->last_sent_request_cseq);
}
return (sippmh_add_cseq(msg, sipGetMethodString(method), cseq_number));
}
static boolean
sipSPIAddRouteHeadersToSubNot (sipMessage_t *msg, sipSCB_t * scbp,
char *result_route, int result_route_length)
{
const char *fname = "sipSPIAddRouteHeadersToSubNot";
static char route[MAX_SIP_HEADER_LENGTH * NUM_INITIAL_RECORD_ROUTE_BUFS];
static char Contact[MAX_SIP_HEADER_LENGTH];
boolean lr = FALSE;
sipRecordRoute_t *rr_info;
/* Check args */
if (!msg) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_BADARGUMENT),
fname, "msg");
return (FALSE);
}
if (!scbp) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_BADARGUMENT),
fname, "scbp");
return (FALSE);
}
if (scbp->ccbp) {
rr_info = scbp->ccbp->record_route_info;
} else {
rr_info = scbp->record_route_info;
}
if (!rr_info) {
CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Route info not available; will not"
" add Route header.\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
return (TRUE);
}
memset(route, 0, MAX_SIP_HEADER_LENGTH * NUM_INITIAL_RECORD_ROUTE_BUFS);
memset(Contact, 0, MAX_SIP_HEADER_LENGTH);
if (scbp->internal == FALSE) { /* incoming subscription */
/*
* For Incoming dialog (UAS), Copy the RR headers as it is
* If Contact is present, append it at the end
*/
if (sipSPIGenerateRouteHeaderUAS(rr_info, route, sizeof(route), &lr)
== FALSE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
fname, "sipSPIGenerateRouteHeaderUAS()");
return (FALSE);
}
} else {
/*
* For Outgoing dialog (UAC), Copy the RR headers in the reverse
* order. If Contact is present, append it at the end
*/
if (sipSPIGenerateRouteHeaderUAC(rr_info, route, sizeof(route), &lr)
== FALSE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
fname, "sipSPIGenerateRouteHeaderUAC()");
return (FALSE);
}
}
/*
* If loose_routing is TRUE, then the contact header is NOT appended
* to the Routeset but is instead used in the Req-URI^M
*/
if (!lr) {
Contact[0] = '\0';
if (sipSPIGenerateContactHeader(scbp->contact_info, Contact,
sizeof(Contact)) == FALSE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
fname, "sipSPIGenerateContactHeader()");
return (FALSE);
}
/* Append Contact to the Route Header, if Contact is available */
if (Contact[0] != '\0') {
if (route[0] != '\0') {
sstrncat(route, ", ", sizeof(route) - strlen(route));
}
sstrncat(route, Contact, MIN((sizeof(route) - strlen(route)), sizeof(Contact)));
}
}
if (route[0] != '\0') {
if (STATUS_SUCCESS == sippmh_add_text_header(msg, SIP_HEADER_ROUTE,
route)) {
CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Adding route = %s\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname), route);
if (result_route) {
sstrncpy(result_route, route, result_route_length);
}
} else {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
fname, "sippmh_add_text_header(ROUTE)");
return (FALSE);
}
} else {
/* Having nothing in Route header is a legal case.
* This would happen when the Record-Route header has
* a single entry and Contact was NULL
*/
CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Not adding route \n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
}
return (TRUE);
}
/**************************************************************
* Format and Send an application generated SUBSCRIBE
**************************************************************/
boolean
sipSPISendSubscribe (sipSCB_t *scbp, boolean renew, boolean authen)
{
const char *fname = "SIPSPISendSubscribe";
sipMessage_t *request = NULL;
sipMethod_t method = sipMethodInvalid;
sipRet_t flag = STATUS_SUCCESS;
char src_addr_str[MAX_IPADDR_STR_LEN];
char dest_sip_addr_str[MAX_IPADDR_STR_LEN];
char addr[MAX_IPADDR_STR_LEN];
char *sip_from_temp, *sip_from_tag, *sip_to_temp;
char via[SIP_MAX_VIA_LENGTH];
char display_name[MAX_LINE_NAME_SIZE];
char line_name[MAX_LINE_NAME_SIZE];
uint8_t mac_address[MAC_ADDRESS_LENGTH];
static uint16_t count = 1;
int timeout = 0, max_forwards_value = 70;
#define CID_LENGTH 9
char cid[CID_LENGTH];
char tmp_header[MAX_SIP_URL_LENGTH + 2];
char *remvtag = NULL;
char *domainloc = NULL;
char allow[MAX_SIP_HEADER_LENGTH];
/*
* This function builds and sends a SUBSCRIBE message.
* Specific subscription information including the encoded body, if any,
* is taken from the SCB pointer passed. The renew flag indicates that the
* SUBSCRIBE message is to be sent to renew a previous subscription
*/
CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_MSG_SENDING_REQUEST), fname, "SUBSCRIBE");
if (!scbp) {
return FALSE;
}
// Fill in source and destination addresses
// Destination address should be the current CCM that is serving us
// In the future, this part of the code will be using the tables provided
// by the connection manager
// First check if the application gave us any forwarding address
if (scbp->hb.dest_sip_addr.type == CPR_IP_ADDR_INVALID) {
sipTransportGetPrimServerAddress(scbp->hb.dn_line, addr);
dns_error_code = sipTransportGetServerAddrPort(addr,
&scbp->hb.dest_sip_addr,
(uint16_t *)&scbp->hb.dest_sip_port,
&scbp->hb.SRVhandle,
FALSE);
if (dns_error_code == 0) {
util_ntohl(&(scbp->hb.dest_sip_addr), &(scbp->hb.dest_sip_addr));
} else {
sipTransportGetServerIPAddr(&(scbp->hb.dest_sip_addr), scbp->hb.dn_line);
}
scbp->hb.dest_sip_port = ((dns_error_code == 0) &&
(scbp->hb.dest_sip_port)) ?
ntohs((uint16_t) scbp->hb.dest_sip_port) : (sipTransportGetPrimServerPort(scbp->hb.dn_line));
}
ipaddr2dotted(src_addr_str, &scbp->hb.src_addr);
ipaddr2dotted(dest_sip_addr_str, &scbp->hb.dest_sip_addr);
// Get the MAC address once - since need it in several places
platform_get_wired_mac_address(mac_address);
// If there is a related dialog, use the From header + tag,
// To header + tag, and the call-id from that dialog
if (scbp->ccbp) {
if (scbp->ccbp->flags & INCOMING) {
// If the call was incoming - reverse the headers for an
// outgoing request
scbp->sip_to = strlib_copy(scbp->ccbp->sip_from);
scbp->sip_to_tag = strlib_copy(scbp->ccbp->sip_from_tag);
scbp->sip_from = strlib_copy(scbp->ccbp->sip_to);
scbp->sip_from_tag = strlib_copy(scbp->ccbp->sip_to_tag);
} else {
// Otherwise copy then in order
scbp->sip_from = strlib_copy(scbp->ccbp->sip_from);
scbp->sip_from_tag = strlib_copy(scbp->ccbp->sip_from_tag);
scbp->sip_to = strlib_copy(scbp->ccbp->sip_to);
scbp->sip_to_tag = strlib_copy(scbp->ccbp->sip_to_tag);
}
if (scbp->ccbp &&
(scbp->ccbp->state >= SIP_STATE_SENT_INVITE_CONNECTED)) {
sstrncpy(scbp->SubURI, scbp->ccbp->ReqURI, MAX_SIP_URL_LENGTH);
} else {
sstrncpy(scbp->SubURI, "sip:", MAX_SIP_URL_LENGTH);
domainloc = scbp->SubURI + strlen(scbp->SubURI);
sstrncpy(domainloc, dest_sip_addr_str,
MAX_SIP_URL_LENGTH - (domainloc - (scbp->SubURI)));
}
sstrncpy(scbp->hb.sipCallID, scbp->ccbp->sipCallID, MAX_SIP_CALL_ID);
} else if (!renew) {
// Create the From header
sip_from_temp = strlib_open(scbp->sip_from, MAX_SIP_URL_LENGTH);
if (sip_from_temp) {
// Use the subscriberURI, if present
if (scbp->SubscriberURI[0] != '\0') {
if (scbp->hb.src_addr.type == CPR_IP_ADDR_IPV6) {
snprintf(sip_from_temp, MAX_SIP_URL_LENGTH, "<sip:%s@[%s]>",
scbp->SubscriberURI, src_addr_str);
} else {
snprintf(sip_from_temp, MAX_SIP_URL_LENGTH, "<sip:%s@%s>",
scbp->SubscriberURI, src_addr_str);
}
} else if (scbp->useDeviceAddressing) {
if (scbp->hb.src_addr.type == CPR_IP_ADDR_IPV6) {
snprintf(sip_from_temp, MAX_SIP_URL_LENGTH,
"<sip:%.4x%.4x%.4x@[%s]>",
mac_address[0] * 256 + mac_address[1],
mac_address[2] * 256 + mac_address[3],
mac_address[4] * 256 + mac_address[5],
src_addr_str);
} else {
snprintf(sip_from_temp, MAX_SIP_URL_LENGTH,
"<sip:%.4x%.4x%.4x@%s>",
mac_address[0] * 256 + mac_address[1],
mac_address[2] * 256 + mac_address[3],
mac_address[4] * 256 + mac_address[5],
src_addr_str);
}
} else {
sip_config_get_display_name(scbp->hb.dn_line, display_name,
sizeof(display_name));
config_get_line_string(CFGID_LINE_NAME, line_name,
scbp->hb.dn_line, sizeof(line_name));
if (scbp->hb.src_addr.type == CPR_IP_ADDR_IPV6) {
snprintf(sip_from_temp, MAX_SIP_URL_LENGTH,
"\"%s\" <sip:%s@[%s]>", display_name,
line_name, src_addr_str);
} else {
snprintf(sip_from_temp, MAX_SIP_URL_LENGTH,
"\"%s\" <sip:%s@%s>", display_name,
line_name, src_addr_str);
}
}
// Add tag to the From header (need to allocate and fill in scbp->sip_from_tag
sip_from_tag = strlib_open(scbp->sip_from_tag, MAX_SIP_URL_LENGTH);
if (sip_from_tag) {
sip_util_make_tag(sip_from_tag);
sstrncat(sip_from_temp, ";tag=",
MAX_SIP_URL_LENGTH - strlen(sip_from_temp));
sstrncat(sip_from_temp, sip_from_tag,
MAX_SIP_URL_LENGTH - strlen(sip_from_temp));
}
scbp->sip_from_tag = strlib_close(sip_from_tag);
}
scbp->sip_from = strlib_close(sip_from_temp);
// Create the Call-ID header - For now create own call-id
count++;
snprintf(scbp->hb.sipCallID, MAX_SIP_CALL_ID,
"%.4x%.4x-%.4x%.4x-%.8x-%.8x@%s",
mac_address[0] * 256 + mac_address[1],
mac_address[2] * 256 + mac_address[3],
mac_address[4] * 256 + mac_address[5], count,
(unsigned int) cpr_rand(),
(unsigned int) cpr_rand(),
src_addr_str);
// Create the ReqURI
sstrncpy(scbp->SubURI, "sip:", MAX_SIP_URL_LENGTH);
/* Indialog requests should contain suburi only
*/
sstrncat(scbp->SubURI, scbp->SubURIOriginal, MAX_SIP_URL_LENGTH - sizeof("sip:"));
domainloc = strchr(scbp->SubURI, '@');
if (domainloc == NULL) {
domainloc = scbp->SubURI + strlen(scbp->SubURI);
if ((domainloc - scbp->SubURI) < (MAX_SIP_URL_LENGTH - 1)) {
/* Do not include @ when there is no user part */
if (scbp->SubURIOriginal[0] != '\0') {
*domainloc++ = '@';
}
sstrncpy(domainloc, dest_sip_addr_str,
MAX_SIP_URL_LENGTH - (domainloc - (scbp->SubURI)));
}
}
// Create the To header
sip_to_temp = strlib_open(scbp->sip_to, MAX_SIP_URL_LENGTH);
if (sip_to_temp) {
snprintf(sip_to_temp, MAX_SIP_URL_LENGTH, "<%s>", scbp->SubURI);
scbp->sip_to = strlib_close(sip_to_temp);
}
}
method = sipMethodSubscribe;
scbp->last_sent_request_cseq_method = method;
// Get a blank SIP message template and fill it in
request = GET_SIP_MESSAGE();
if (!request) {
return FALSE;
}
// Can't use CreateRequest to fill in the message since not using CCB. So
// do the following:
// 1. Add request line (sipSPIAddRequestLine).
if (HSTATUS_SUCCESS != sippmh_add_request_line(request,
sipGetMethodString(method),
scbp->SubURI, SIP_VERSION)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Request line\n", fname);
free_sip_message(request);
return (FALSE);
}
// 2. Add local Via (sipSPIAddLocalVia)
snprintf(via, sizeof(via), "SIP/2.0/%s %s:%d;%s=%s%.8x",
sipTransportGetTransportType(scbp->hb.dn_line, TRUE, NULL),
src_addr_str, scbp->hb.local_port, VIA_BRANCH,
VIA_BRANCH_START, (unsigned int) cpr_rand());
if (HSTATUS_SUCCESS != sippmh_add_text_header(request, SIP_HEADER_VIA, via)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding VIA header\n", fname);
free_sip_message(request);
return (FALSE);
}
// 3. Add common headers (sipSPIAddCommonHeaders)
if ((HSTATUS_SUCCESS != sippmh_add_text_header(request, SIP_HEADER_FROM, scbp->sip_from)) ||
(HSTATUS_SUCCESS != sippmh_add_text_header(request, SIP_HEADER_TO, scbp->sip_to)) ||
(HSTATUS_SUCCESS != sippmh_add_text_header(request, SIP_HEADER_CALLID, scbp->hb.sipCallID)) ||
(HSTATUS_SUCCESS != sipAddDateHeader(request)) ||
(HSTATUS_SUCCESS != sm_add_cseq(scbp, method, request))) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding either From, To, CallID, "
"Date or Cseq header\n", fname);
free_sip_message(request);
return (FALSE);
}
// 4. Add text headers (sippmh_add_text_header)
(void) sippmh_add_text_header(request, SIP_HEADER_USER_AGENT,
sipHeaderUserAgent);
// 5. Add general headers (AddGeneralHeaders)
// Event header is not needed for Refer msg
if (method != sipMethodRefer) {
if (HSTATUS_SUCCESS != sippmh_add_text_header(request, SIP_HEADER_EVENT,
scbp->event_name)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Event header\n", fname);
free_sip_message(request);
return (FALSE);
}
}
if (scbp->hb.accept_type == CC_SUBSCRIPTIONS_DIALOG) {
flag = sippmh_add_text_header(request, SIP_HEADER_ACCEPT,
dialogAcceptHeader);
} else if (scbp->hb.event_type == CC_SUBSCRIPTIONS_KPML) {
flag = sippmh_add_text_header(request, SIP_HEADER_ACCEPT,
kpmlResponseAcceptHeader);
} else if (scbp->hb.event_type == CC_SUBSCRIPTIONS_DIALOG) {
flag = sippmh_add_text_header(request, SIP_HEADER_ACCEPT,
dialogAcceptHeader);
} else if (scbp->hb.event_type == CC_SUBSCRIPTIONS_PRESENCE) {
flag = sippmh_add_text_header(request, SIP_HEADER_ACCEPT,
presenceAcceptHeader);
}
if (HSTATUS_SUCCESS != flag) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Accept header\n", fname);
free_sip_message(request);
return (FALSE);
}
if (HSTATUS_SUCCESS != sippmh_add_int_header(request, SIP_HEADER_EXPIRES,
scbp->hb.expires)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Expires header\n", fname);
free_sip_message(request);
return (FALSE);
}
// Add max-forwards header
config_get_value(CFGID_SIP_MAX_FORWARDS, &max_forwards_value,
sizeof(max_forwards_value));
if (HSTATUS_SUCCESS !=
sippmh_add_int_header(request, SIP_HEADER_MAX_FORWARDS,
max_forwards_value)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Max-Forwards header\n", fname);
free_sip_message(request);
return (FALSE);
}
// Add Contact header
if (HSTATUS_SUCCESS != sm_add_contact(&(scbp->hb), request)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Contact header\n", fname);
free_sip_message(request);
return (FALSE);
}
if (authen) {
if (HSTATUS_SUCCESS != sippmh_add_text_header(request, AUTHOR_HDR(scbp->hb.authen.status_code),
scbp->hb.authen.authorization)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Authorization header\n", fname);
free_sip_message(request);
return (FALSE);
}
}
if (scbp->norefersub) {
if (HSTATUS_SUCCESS != sippmh_add_text_header(request, SIP_HEADER_REQUIRE, "norefersub")) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Require header\n", fname);
free_sip_message(request);
return (FALSE);
}
}
if (method == sipMethodRefer) {
// Add Refer-To, Referred-By, and Content-ID headers
sstrncpy(tmp_header, (const char *) (scbp->sip_from), MAX_SIP_URL_LENGTH + 1);
remvtag = strstr(tmp_header, ";tag=");
if (remvtag) {
*remvtag = '\0';
}
if (HSTATUS_SUCCESS != sippmh_add_text_header(request, SIP_HEADER_REFERRED_BY, tmp_header)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Referred-By header\n", fname);
free_sip_message(request);
return (FALSE);
}
snprintf(cid, sizeof(cid), "%.8x", (unsigned int)cpr_rand());
snprintf(tmp_header, sizeof(tmp_header), "cid:%s@%s", cid, src_addr_str);
if (HSTATUS_SUCCESS != sippmh_add_text_header(request, SIP_HEADER_REFER_TO, tmp_header)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Refer-To header\n", fname);
free_sip_message(request);
return (FALSE);
}
snprintf(tmp_header, sizeof(tmp_header), "<%s@%s>", cid, src_addr_str);
if (HSTATUS_SUCCESS != sippmh_add_text_header(request, SIP_HEADER_CONTENT_ID, tmp_header)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Content-ID header\n", fname);
free_sip_message(request);
return (FALSE);
}
}
// Add Allow
snprintf(allow, MAX_SIP_HEADER_LENGTH, "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s",
SIP_METHOD_ACK, SIP_METHOD_BYE, SIP_METHOD_CANCEL,
SIP_METHOD_INVITE, SIP_METHOD_NOTIFY, SIP_METHOD_OPTIONS,
SIP_METHOD_REFER, SIP_METHOD_REGISTER, SIP_METHOD_UPDATE,
SIP_METHOD_SUBSCRIBE);
if (HSTATUS_SUCCESS != sippmh_add_text_header(request, SIP_HEADER_ALLOW, allow)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Allow header\n", fname);
free_sip_message(request);
return (FALSE);
}
/*
* Add route header if needed.
*/
if (FALSE == sipSPIAddRouteHeadersToSubNot(request, scbp, NULL, 0)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Route header\n", fname);
free_sip_message(request);
return (FALSE);
}
// Add content, if any
if (scbp->hb.event_data_p) {
if (add_content(scbp->hb.event_data_p, request, fname) == FALSE) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Content\n", fname);
free_sip_message(request);
return (FALSE);
}
} else {
if (HSTATUS_SUCCESS != sippmh_add_int_header(request, SIP_HEADER_CONTENT_LENGTH, 0)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Content-Len\n", fname);
free_sip_message(request);
return (FALSE);
}
}
ccsip_common_util_set_retry_settings((ccsip_common_cb_t *)scbp, &timeout);
if (sipTransportCreateSendMessage(NULL, request, method,
&(scbp->hb.dest_sip_addr),
(int16_t) scbp->hb.dest_sip_port,
FALSE, TRUE, timeout, scbp,
RELDEV_NO_STORED_MSG) < 0) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to send message\n", fname);
return (FALSE);
}
return (TRUE);
}
/**************************************************************
* Format and send a response to a network received SUBSCRIBE
**************************************************************/
boolean
sipSPISendSubscribeNotifyResponse (sipSCB_t *scbp,
uint16_t response_code,
uint32_t cseq)
{
const char *fname = "sipSPISendSubscribeNotifyResponse";
sipMessage_t *response = NULL;
sipVia_t *via = NULL;
sub_not_trxn_t *trxn_p;
int status_code = 0;
// currently not used const char *request_callid = NULL;
cpr_ip_addr_t cc_remote_ipaddr;
uint16_t cc_remote_port = 0;
// currently not used int timeout = 0;
char *pViaHeaderStr = NULL;
char *dest_ip_addr_str = 0;
char src_addr_str[MAX_IPADDR_STR_LEN];
char response_text[MAX_SIP_URL_LENGTH];
boolean port_present = FALSE;
int reldev_stored_msg;
sipRet_t tflag = HSTATUS_SUCCESS;
CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_MSG_SENDING_RESPONSE), fname, response_code);
memset(&cc_remote_ipaddr, 0, sizeof(cpr_ip_addr_t));
cc_remote_ipaddr = ip_addr_invalid;
if (!scbp) {
return FALSE;
}
/*
* In the response to Subscribe:
* The Via header gets a ";received" addition (...;received: 192.168.0.7)
* The From header is the same as in the subscribe request
* The To header is the same as in the subscribe request but has a tag
* The call-id is the same as in the request
* Content Length is set to 0
*/
response = GET_SIP_MESSAGE();
if (!response) {
return FALSE;
}
get_sip_error_string(response_text, response_code);
tflag = sippmh_add_response_line(response, SIP_VERSION, response_code,
response_text);
if (tflag != HSTATUS_SUCCESS) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding response line", fname);
free_sip_message(response);
return FALSE;
}
/*
* find the transaction and fetch the via header
*/
trxn_p = sll_find(scbp->incoming_trxns, &cseq);
if (trxn_p) {
pViaHeaderStr = trxn_p->via;
/* remove the transaction because we are done with it */
(void)sll_remove(scbp->incoming_trxns, trxn_p);
cpr_free(trxn_p);
}
if (pViaHeaderStr) {
via = sippmh_parse_via(pViaHeaderStr);
}
if (!via || !pViaHeaderStr) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
fname, "No or Bad Via Header present in Message!");
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in parsing Via header", fname);
if (via)
sippmh_free_via(via);
free_sip_message(response);
cpr_free(pViaHeaderStr);
return (FALSE);
}
if (STATUS_SUCCESS != sippmh_add_text_header(response, SIP_HEADER_VIA, pViaHeaderStr)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Via header", fname);
sippmh_free_via(via);
free_sip_message(response);
cpr_free(pViaHeaderStr);
return (FALSE);
}
/* free the via header because we will not need it anymore */
cpr_free(pViaHeaderStr);
// Add common headers: From, To, CallID, Date, CSeq, Contact
// Note: If this is a response to a NOTIFY, then from and to headers
// must be reversed
if (scbp->last_recv_request_cseq_method == sipMethodNotify) {
if (STATUS_SUCCESS != sippmh_add_text_header(response, SIP_HEADER_FROM, scbp->sip_to)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding From header", fname);
sippmh_free_via(via);
free_sip_message(response);
return (FALSE);
}
if (STATUS_SUCCESS != sippmh_add_text_header(response, SIP_HEADER_TO, scbp->sip_from)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding To header", fname);
sippmh_free_via(via);
free_sip_message(response);
return (FALSE);
}
} else {
if (STATUS_SUCCESS != sippmh_add_text_header(response, SIP_HEADER_FROM, scbp->sip_from)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding From header", fname);
sippmh_free_via(via);
free_sip_message(response);
return (FALSE);
}
if (STATUS_SUCCESS != sippmh_add_text_header(response, SIP_HEADER_TO, scbp->sip_to)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding To header", fname);
sippmh_free_via(via);
free_sip_message(response);
return (FALSE);
}
}
if (STATUS_SUCCESS != sippmh_add_text_header(response, SIP_HEADER_CALLID, scbp->hb.sipCallID)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding CallID header", fname);
sippmh_free_via(via);
free_sip_message(response);
return (FALSE);
}
if (HSTATUS_SUCCESS != sipAddDateHeader(response)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Date header", fname);
sippmh_free_via(via);
free_sip_message(response);
return (FALSE);
}
if (HSTATUS_SUCCESS != sippmh_add_cseq(response,
sipGetMethodString(scbp->
last_recv_request_cseq_method),
cseq)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding CSeq header", fname);
sippmh_free_via(via);
free_sip_message(response);
return (FALSE);
}
tflag = sippmh_add_text_header(response, SIP_HEADER_SERVER, sipHeaderServer);
if (tflag != HSTATUS_SUCCESS) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Server header", fname);
sippmh_free_via(via);
free_sip_message(response);
return (FALSE);
}
ipaddr2dotted(src_addr_str, &scbp->hb.src_addr);
tflag = sm_add_contact(&(scbp->hb), response);
if (tflag != HSTATUS_SUCCESS) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Contact header", fname);
sippmh_free_via(via);
free_sip_message(response);
return (FALSE);
}
// Add expires header - only for a SUBSCRIBE response
if (scbp->last_recv_request_cseq_method == sipMethodSubscribe) {
if (sippmh_add_int_header(response, SIP_HEADER_EXPIRES, scbp->hb.expires) != 0) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Expires header", fname);
sippmh_free_via(via);
free_sip_message(response);
return (FALSE);
}
/*
* add Record-Route Header, if it is a response (18x/2xx) to
* dialog initiating SUBSCRIBE.
*/
if ((scbp->cached_record_route[0] != '\0') &&
(((response_code >= 180) && (response_code <= 189)) ||
((response_code >= 200) && (response_code <= 299)))) {
tflag = sippmh_add_text_header(response, SIP_HEADER_RECORD_ROUTE,
scbp->cached_record_route);
if (tflag != HSTATUS_SUCCESS) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Record-Route header",
fname);
sippmh_free_via(via);
free_sip_message(response);
return (FALSE);
}
}
/* free the cached record_route, once the final resp is sent */
if (response_code >= 200) {
strlib_free(scbp->cached_record_route);
scbp->cached_record_route = strlib_empty();
}
}
// Add other headers such as content-length, content-type
if (HSTATUS_SUCCESS != sippmh_add_int_header(response, SIP_HEADER_CONTENT_LENGTH, 0)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Content-Length header", fname);
sippmh_free_via(via);
free_sip_message(response);
return (FALSE);
}
// Send Response
// Get information on where to send the response from via headers
if (via->remote_port) {
cc_remote_port = via->remote_port;
port_present = TRUE;
} else {
/* Use default 5060 if via does not have port */
cc_remote_port = SIP_WELL_KNOWN_PORT;
}
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Via host: %s, port: %d, rcvd host: %s\n",
fname, via->host, via->remote_port, via->recd_host);
if (via->maddr) {
if (!port_present) {
dns_error_code = sipTransportGetServerAddrPort(via->maddr,
&cc_remote_ipaddr,
&cc_remote_port,
NULL, FALSE);
} else {
dns_error_code = dnsGetHostByName(via->maddr, &cc_remote_ipaddr,
100, 1);
}
if (dns_error_code != 0) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
fname,
"sipTransportGetServerAddrPort or dnsGetHostByName()");
} else {
util_ntohl(&cc_remote_ipaddr, &cc_remote_ipaddr);
}
}
// If all else fails send the response to where we got the request from
if (cc_remote_ipaddr.type == CPR_IP_ADDR_INVALID) {
if (via->recd_host) {
dest_ip_addr_str = via->recd_host;
} else {
dest_ip_addr_str = via->host;
}
if (!port_present) {
dns_error_code = sipTransportGetServerAddrPort(dest_ip_addr_str,
&cc_remote_ipaddr,
&cc_remote_port,
NULL, FALSE);
} else {
dns_error_code = dnsGetHostByName(dest_ip_addr_str,
&cc_remote_ipaddr, 100, 1);
}
if (dns_error_code != 0) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
fname,
"sipTransportGetServerAddrPort or dnsGetHostByName()");
// cpr_free(request_cseq_structure);
sippmh_free_via(via);
free_sip_message(response);
return (FALSE);
} else {
util_ntohl(&cc_remote_ipaddr, &cc_remote_ipaddr);
}
}
// Store cc_remote_ipaddr and cc_remote_port values in SCB for later use
// in the corresponding NOTIFY, if any
scbp->hb.dest_sip_addr = cc_remote_ipaddr;
scbp->hb.dest_sip_port = cc_remote_port;
reldev_stored_msg = sipRelDevCoupledMessageStore(response, scbp->hb.sipCallID,
cseq,
scbp->last_recv_request_cseq_method,
FALSE,
status_code,
&cc_remote_ipaddr,
cc_remote_port, TRUE);
sippmh_free_via(via);
scbp->hb.retx_flag = FALSE;
if (sipTransportCreateSendMessage(NULL, response, sipMethodSubscribe,
&cc_remote_ipaddr, cc_remote_port,
FALSE, TRUE, 0, scbp, reldev_stored_msg) != 0) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to send message", fname);
return (FALSE);
}
return (TRUE);
}
/**************************************************************
* Format and send a locally generated NOTIFY
**************************************************************/
boolean
sipSPISendSubNotify (ccsip_common_cb_t *cbp, boolean authen)
{
const char *fname = "SIPSPISendSubNotify";
sipMessage_t *request = NULL;
static uint32_t cseq = 0;
// currently not used char *message_body = NULL;
// currently not used sipRet_t flag = STATUS_SUCCESS;
char src_addr_str[MAX_IPADDR_STR_LEN];
char dest_sip_addr_str[MAX_IPADDR_STR_LEN];
char addr[MAX_IPADDR_STR_LEN];
// currently not used uint32_t nbytes = SIP_UDP_MESSAGE_SIZE;
char via[SIP_MAX_VIA_LENGTH];
// currently not used short send_to_proxy_handle = INVALID_SOCKET;
static char ReqURI[MAX_SIP_URL_LENGTH];
static char sip_temp_str[MAX_SIP_URL_LENGTH];
static char sip_temp_tag[MAX_SIP_URL_LENGTH];
sipSubscriptionStateInfo_t subs_state;
int timeout = 0, max_forwards_value = 70;
char allow[MAX_SIP_HEADER_LENGTH];
sipSCB_t *scbp = (sipSCB_t *)cbp;
sipTCB_t *tcbp = (sipTCB_t *)cbp;
/*
* This function builds and sends a NOTIFY message as a follow up to
* a previously received SUBSCRIBE
*/
CCSIP_DEBUG_STATE(get_debug_string(DEBUG_SIP_MSG_SENDING_REQUEST), fname, "NOTIFY");
if (!cbp) {
return FALSE;
}
if (util_check_if_ip_valid(&cbp->dest_sip_addr)== FALSE) {
sipTransportGetPrimServerAddress(scbp->hb.dn_line, addr);
dns_error_code = sipTransportGetServerAddrPort(addr,
&cbp->dest_sip_addr,
(uint16_t *)&cbp->dest_sip_port,
&cbp->SRVhandle,
FALSE);
if (dns_error_code == 0) {
util_ntohl(&(cbp->dest_sip_addr), &(cbp->dest_sip_addr));
} else {
sipTransportGetServerIPAddr(&(cbp->dest_sip_addr), cbp->dn_line);
}
cbp->dest_sip_port = ((dns_error_code == 0) &&
(cbp->dest_sip_port)) ?
ntohs(cbp->dest_sip_port) : (sipTransportGetPrimServerPort(cbp->dn_line));
}
ipaddr2dotted(src_addr_str, &cbp->src_addr);
ipaddr2dotted(dest_sip_addr_str, &cbp->dest_sip_addr);
// Create the request
request = GET_SIP_MESSAGE();
/*
* Determine the Request-URI
*/
memset(ReqURI, 0, sizeof(ReqURI));
if (cbp->cb_type == SUBNOT_CB) {
if (scbp->contact_info) {
// Build Req-URI from contact info
sipContact_t *response_contact_info;
sipUrl_t *sipUrl = NULL;
cpr_ip_addr_t request_uri_addr;
uint16_t request_uri_port = 0;
request_uri_addr = ip_addr_invalid;
response_contact_info = scbp->contact_info;
if (response_contact_info->locations[0]->genUrl->schema == URL_TYPE_SIP) {
sipUrl = response_contact_info->locations[0]->genUrl->u.sipUrl;
} else {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"URL is not SIP\n", fname);
free_sip_message(request);
return (FALSE);
}
request_uri_port = sipUrl->port;
dns_error_code = sipTransportGetServerAddrPort(sipSPIUrlDestination(sipUrl),
&request_uri_addr,
&request_uri_port, NULL, FALSE);
if (dns_error_code == 0) {
util_ntohl(&request_uri_addr, &request_uri_addr);
} else {
request_uri_addr = ip_addr_invalid;
}
if (sipUrl->user != NULL) {
if (sipUrl->password) {
snprintf(ReqURI, sizeof(ReqURI),
sipUrl->is_phone ?
"sip:%s:%s@%s:%d;user=phone" :
"sip:%s:%s@%s:%d",
sipUrl->user, sipUrl->password,
sipUrl->host, sipUrl->port);
} else {
snprintf(ReqURI, sizeof(ReqURI),
sipUrl->is_phone ?
"sip:%s@%s:%d;user=phone" :
"sip:%s@%s:%d",
sipUrl->user, sipUrl->host,
sipUrl->port);
}
} else {
snprintf(ReqURI, sizeof(ReqURI),
sipUrl->is_phone ?
"sip:%s:%d;user=phone" :
"sip:%s:%d",
sipUrl->host, sipUrl->port);
}
} else {
// Build Req-URI from FROM field
sipLocation_t *request_uri_loc = NULL;
char sip_from[MAX_SIP_URL_LENGTH];
sipUrl_t *request_uri_url = NULL;
sstrncpy(sip_from, scbp->sip_from, MAX_SIP_URL_LENGTH);
request_uri_loc = sippmh_parse_from_or_to(sip_from, TRUE);
if (!request_uri_loc) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
fname, "sippmh_parse_from_or_to(TO)");
free_sip_message(request);
return (FALSE);
}
if (!sippmh_valid_url(request_uri_loc->genUrl)) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
fname, "sippmh_valid_url()");
sippmh_free_location(request_uri_loc);
free_sip_message(request);
return (FALSE);
}
CCSIP_DEBUG_STATE(DEB_F_PREFIX"Forming Req-URI (Caller): using original "
"Req-URI\n", DEB_F_PREFIX_ARGS(SIP_SUB, fname));
/*
* if (request_uri_loc->name) {
* if (request_uri_loc->name[0]) {
* sstrncat(ReqURI, "\"", sizeof(ReqURI)-strlen(ReqURI));
* sstrncat(ReqURI, request_uri_loc->name,
* sizeof(ReqURI)-strlen(ReqURI));
* sstrncat(ReqURI, "\" ", sizeof(ReqURI)-strlen(ReqURI));
* }
* }
*/
sstrncat(ReqURI, "sip:", sizeof(ReqURI) - strlen(ReqURI));
if (request_uri_loc->genUrl->schema == URL_TYPE_SIP) {
request_uri_url = request_uri_loc->genUrl->u.sipUrl;
} else {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"URL is not SIP\n", fname);
sippmh_free_location(request_uri_loc);
free_sip_message(request);
return (FALSE);
}
if (request_uri_url->user) {
sstrncat(ReqURI, request_uri_url->user,
sizeof(ReqURI) - strlen(ReqURI));
sstrncat(ReqURI, "@", sizeof(ReqURI) - strlen(ReqURI));
}
if (request_uri_url->is_phone) {
sstrncat(ReqURI, ";user=phone",
sizeof(ReqURI) - strlen(ReqURI));
}
sstrncat(ReqURI, request_uri_url->host,
sizeof(ReqURI) - strlen(ReqURI));
// sstrncat(ReqURI, ">", sizeof(ReqURI)-strlen(ReqURI));
sippmh_free_location(request_uri_loc);
}
} else { //Unsolicited NOTIFY
char line_name[MAX_LINE_NAME_SIZE];
config_get_line_string(CFGID_LINE_NAME, line_name, cbp->dn_line, sizeof(line_name));
snprintf(ReqURI, MAX_SIP_URL_LENGTH, "sip:%s@%s", line_name, dest_sip_addr_str);
sstrncpy(tcbp->full_ruri, ReqURI, MAX_SIP_URL_LENGTH);
}
(void) sippmh_add_request_line(request,
sipGetMethodString(sipMethodNotify),
ReqURI, SIP_VERSION);
// The Via header has the local URI and a new branch
snprintf(via, sizeof(via), "SIP/2.0/%s %s:%d;%s=%s%.8x",
sipTransportGetTransportType(cbp->dn_line, TRUE, NULL),
src_addr_str, cbp->local_port, VIA_BRANCH,
VIA_BRANCH_START, (unsigned int) cpr_rand());
if (STATUS_SUCCESS != sippmh_add_text_header(request, SIP_HEADER_VIA, via)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding VIA header\n", fname);
free_sip_message(request);
return (FALSE);
}
// The To field including the tag is the same as the From field in the
// response to SUBSCRIBE
if (cbp->cb_type != SUBNOT_CB) {
snprintf(sip_temp_str, MAX_SIP_URL_LENGTH, "<%s>", ReqURI);
}
if (STATUS_SUCCESS != sippmh_add_text_header(request, SIP_HEADER_TO,
((cbp->cb_type == SUBNOT_CB) ? scbp->sip_from : sip_temp_str))) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding To header\n", fname);
free_sip_message(request);
return (FALSE);
}
// The From field including the tag is the same as the To field in the
// response to SUBSCRIBE
if (cbp->cb_type != SUBNOT_CB) {
sstrncat(sip_temp_str, ";tag=", MAX_SIP_URL_LENGTH - strlen(sip_temp_str));
sip_util_make_tag(sip_temp_tag);
sstrncat(sip_temp_str, sip_temp_tag, MAX_SIP_URL_LENGTH - strlen(sip_temp_str));
}
if (STATUS_SUCCESS != sippmh_add_text_header(request, SIP_HEADER_FROM,
((cbp->cb_type == SUBNOT_CB) ? scbp->sip_to : sip_temp_str))) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding From header\n", fname);
free_sip_message(request);
return (FALSE);
}
// The call-id used is the same as in the SCB
if (cbp->sipCallID[0] == 0) {
snprintf(tcbp->hb.sipCallID, sizeof(tcbp->hb.sipCallID), "%.8x-%.8x@%s", // was MAX_SIP_URL_LENGTH
(unsigned int) cpr_rand(),
(unsigned int) cpr_rand(),
src_addr_str);
}
if (STATUS_SUCCESS != sippmh_add_text_header(request, SIP_HEADER_CALLID, cbp->sipCallID)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding CallID header\n", fname);
free_sip_message(request);
return (FALSE);
}
if (HSTATUS_SUCCESS != sipAddDateHeader(request)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Date header\n", fname);
free_sip_message(request);
return (FALSE);
}
if (cbp->cb_type == SUBNOT_CB) {
if (sm_add_cseq(scbp, sipMethodNotify, request) != HSTATUS_SUCCESS) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding CSeq header\n", fname);
free_sip_message(request);
return (FALSE);
}
} else {
cseq++;
if (cseq == 0) {
cseq = 1;
}
if (HSTATUS_SUCCESS != sippmh_add_cseq(request, sipGetMethodString(sipMethodNotify), cseq)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding CSEQ header\n", fname);
free_sip_message(request);
return (FALSE);
}
}
// Event is the event name
// The subscription-state header is active
if (cbp->event_type - CC_SUBSCRIPTIONS_DIALOG > -1 &&
cbp->event_type - CC_SUBSCRIPTIONS_DIALOG < 5) {
if (HSTATUS_SUCCESS != sippmh_add_text_header(request, SIP_HEADER_EVENT,
eventNames[cbp->event_type - CC_SUBSCRIPTIONS_DIALOG])) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Event header\n", fname);
free_sip_message(request);
return (FALSE);
}
}
subs_state.expires = cbp->expires;
if (cbp->cb_type == SUBNOT_CB) {
if (subs_state.expires > 0) {
subs_state.state = SUBSCRIPTION_STATE_ACTIVE;
} else {
subs_state.state = SUBSCRIPTION_STATE_TERMINATED;
}
} else {
subs_state.state = SUBSCRIPTION_STATE_ACTIVE;
}
if (sippmh_add_subscription_state(request, &subs_state) != 0) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Subscription-State header", fname);
free_sip_message(request);
return (FALSE);
}
// Add max-forwards header
config_get_value(CFGID_SIP_MAX_FORWARDS, &max_forwards_value,
sizeof(max_forwards_value));
(void) sippmh_add_int_header(request, SIP_HEADER_MAX_FORWARDS,
max_forwards_value);
// Add contact header
if (sm_add_contact(cbp, request) != HSTATUS_SUCCESS) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Contact header\n", fname);
free_sip_message(request);
return (FALSE);
}
if (authen) {
(void) sippmh_add_text_header(request,
AUTHOR_HDR(scbp->hb.authen.status_code),
scbp->hb.authen.authorization);
}
// Add Allow
snprintf(allow, MAX_SIP_HEADER_LENGTH, "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s",
SIP_METHOD_ACK, SIP_METHOD_BYE, SIP_METHOD_CANCEL,
SIP_METHOD_INVITE, SIP_METHOD_NOTIFY, SIP_METHOD_OPTIONS,
SIP_METHOD_REFER, SIP_METHOD_REGISTER, SIP_METHOD_UPDATE,
SIP_METHOD_SUBSCRIBE);
(void) sippmh_add_text_header(request, SIP_HEADER_ALLOW, allow);
if (cbp->cb_type == SUBNOT_CB) {
/* keep the request method to be sent */
scbp->last_sent_request_cseq_method = sipMethodNotify;
/*
* Add route header if needed.
*/
if (FALSE == sipSPIAddRouteHeadersToSubNot(request, scbp, NULL, 0)) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in adding Route header\n", fname);
free_sip_message(request);
return (FALSE);
}
ccsip_common_util_set_retry_settings((ccsip_common_cb_t *)scbp, &timeout);
}
// Add content, if any
if (cbp->event_data_p) {
if (add_content(cbp->event_data_p, request, fname) == FALSE) {
free_sip_message(request);
return (FALSE);
}
} else {
(void) sippmh_add_int_header(request, SIP_HEADER_CONTENT_LENGTH, 0);
}
if (sipTransportCreateSendMessage(NULL, request, sipMethodNotify,
&(scbp->hb.dest_sip_addr),
(int16_t) scbp->hb.dest_sip_port,
FALSE, TRUE, timeout, cbp,
RELDEV_NO_STORED_MSG) != 0) {
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error in sending message\n", fname);
return (FALSE);
}
return (TRUE);
}
/**************************************************************
* Handle message retries
*************************************************************/
int
subsmanager_handle_retry_timer_expire (int scb_index)
{
const char *fname = "subsmanager_handle_retry_timer_expire";
sipSCB_t *scbp = NULL;
uint32_t max_retx = 0;
ccsip_sub_not_data_t sub_not_result_data;
uint32_t time_t1 = 0;
uint32_t time_t2 = 0;
uint32_t timeout = 0;
CCSIP_DEBUG_TASK("Entering %s. scb_index: %d\n", fname, scb_index);
if (scb_index < 0 || scb_index >= MAX_SCBS) {
return (-1);
}
scbp = &(subsManagerSCBS[scb_index]);
if (scbp->hb.retx_flag == TRUE) {
config_get_value(CFGID_SIP_RETX, &max_retx, sizeof(max_retx));
if (max_retx > MAX_NON_INVITE_RETRY_ATTEMPTS) {
max_retx = MAX_NON_INVITE_RETRY_ATTEMPTS;
}
if (scbp->hb.retx_counter < max_retx) {
config_get_value(CFGID_TIMER_T1, &time_t1, sizeof(time_t1));
scbp->hb.retx_counter++;
timeout = time_t1 * (1 << scbp->hb.retx_counter);
config_get_value(CFGID_TIMER_T2, &time_t2, sizeof(time_t2));
if (timeout > time_t2) {
timeout = time_t2;
}
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Resending message #%d\n",
DEB_F_PREFIX_ARGS(SIP_SUB, fname), scbp->hb.retx_counter);
if (sipTransportSendMessage(NULL,
sipPlatformUISMSubNotTimers[scb_index].message_buffer,
sipPlatformUISMSubNotTimers[scb_index].message_buffer_len,
sipPlatformUISMSubNotTimers[scb_index].message_type,
&(sipPlatformUISMSubNotTimers[scb_index].ipaddr),
sipPlatformUISMSubNotTimers[scb_index].port,
FALSE, TRUE, timeout, scbp) < 0) {
return (-1);
}
} else {
// Should we terminate this dialog? At the very least - stop
// the timer block, display error, and send a message to the app
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Either exceeded max retries for UDP"
" or Timer F fired for TCP\n", fname);
sip_platform_msg_timer_subnot_stop(&sipPlatformUISMSubNotTimers[scb_index]);
scbp->hb.retx_flag = FALSE;
scbp->hb.retx_counter = 0;
memset(&sub_not_result_data, 0, sizeof(sub_not_result_data));
sub_not_result_data.request_id = scbp->request_id;
sub_not_result_data.sub_id = scbp->sub_id;
sub_not_result_data.gsm_id = scbp->gsm_id;
sub_not_result_data.line_id = scbp->hb.dn_line;
if ((scbp->last_sent_request_cseq_method == sipMethodSubscribe) ||
(scbp->last_sent_request_cseq_method == sipMethodRefer)) {
sub_not_result_data.u.subs_result_data.status_code = REQUEST_TIMEOUT;
sip_send_error_message(&sub_not_result_data,
scbp->subsNotCallbackTask,
scbp->subsResCallbackMsgID,
scbp->subsResultCallback, fname);
} else {
sub_not_result_data.u.notify_result_data.status_code = REQUEST_TIMEOUT;
// Set the state to ACTIVE, so we can go on appropriately. Note that
// this assignment below should be placed before sip_send_error_message() so
// that in case of callback running on same thread freed the scb, we will not
// set it back to active and try to use it later.
scbp->smState = SUBS_STATE_ACTIVE;
sip_send_error_message(&sub_not_result_data,
scbp->subsNotCallbackTask,
scbp->notResCallbackMsgID,
scbp->notifyResultCallback, fname);
}
// If there are any pending requests, execute them now
if (scbp->pendingRequests) {
handle_pending_requests(scbp);
}
}
}
return (0);
}
/**************************************************************
* Handle periodic timer
*************************************************************/
void
subsmanager_handle_periodic_timer_expire (void)
{
const char *fname = "subsmanager_handle_periodic_timer_expire";
sipSCB_t *scbp = NULL;
int scb_index;
ccsip_sub_not_data_t subs_term_data;
sipspi_msg_t subscribe;
int subscription_delta = 0;
// static char count = 0;
/*
* Go through the list of SCBs and pick out the ones for
* which some action needs to be taken. This action may include:
* 1. If an incoming SUBSCRIBE has expired, inform the application
* 2. If auto-subscribe is set on an outgoing subscribe, send
* a re-SUBSCRIBE message
*/
config_get_value(CFGID_TIMER_SUBSCRIBE_DELTA, &subscription_delta,
sizeof(subscription_delta));
for (scb_index = 0; scb_index < MAX_SCBS; scb_index++) {
scbp = &(subsManagerSCBS[scb_index]);
if (scbp->pendingClean) {
if (scbp->pendingCount > 0) {
scbp->pendingCount -= TMR_PERIODIC_SUBNOT_INTERVAL;
} else {
free_scb(scb_index, fname);
}
continue;
}
if (scbp->smState == SUBS_STATE_REGISTERED) {
continue;
}
if (scbp->smState != SUBS_STATE_IDLE) {
if (scbp->hb.expires > 0) {
scbp->hb.expires -= TMR_PERIODIC_SUBNOT_INTERVAL;
}
if (scbp->hb.expires > (subscription_delta + TMR_PERIODIC_SUBNOT_INTERVAL)) {
continue;
}
if (scbp->internal) {
// Subscription was internally generated
if (scbp->auto_resubscribe) {
if (scbp->smState != SUBS_STATE_SENT_SUBSCRIBE) {
// Send re-SUBSCRIBE message - but not if we just sent one
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Auto reSubscribing:"
" scb=%d sub_id=%x\n",
DEB_F_PREFIX_ARGS(SIP_SUB, fname), scb_index, scbp->sub_id);
memset(&subscribe, 0, sizeof(sipspi_msg_t));
subscribe.msg.subscribe.sub_id = scbp->sub_id;
subscribe.msg.subscribe.duration = scbp->hb.orig_expiration;
(void) subsmanager_handle_ev_app_subscribe(&subscribe);
}
} else {
// Let app know its own SUBSCRIBE is about to expire
// Application SHOULD renew its own subscription
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Notifying App of internal"
" expiry: scb=%d sub_id=%x\n",
DEB_F_PREFIX_ARGS(SIP_SUB, fname), scb_index, scbp->sub_id);
subs_term_data.sub_id = scbp->sub_id;
subs_term_data.event = scbp->hb.event_type;
subs_term_data.msg_id = scbp->subsTermCallbackMsgID;
subs_term_data.request_id = scbp->request_id;
subs_term_data.reason_code = SM_REASON_CODE_NORMAL;
subs_term_data.u.subs_term_data.status_code =
APPLICATION_SUBSCRIPTION_EXPIRED;
if (scbp->subsTermCallback) {
scbp->subsTermCallback(&subs_term_data);
} else if (scbp->subsIndCallbackTask != CC_SRC_MIN) {
(void) sip_send_message(&subs_term_data, scbp->subsIndCallbackTask,
scbp->subsTermCallbackMsgID);
}
}
} else {
// Subscription was received from network
if (scbp->hb.expires <= 0) {
// Let app know this SUBSCRIBE has expired
// App SHOULD send final NOTIFY and terminate the session
CCSIP_DEBUG_TASK(DEB_F_PREFIX"Notifying App of external"
" expiry: scb=%d sub_id=%x\n",
DEB_F_PREFIX_ARGS(SIP_SUB, fname), scb_index, scbp->sub_id);
subs_term_data.sub_id = scbp->sub_id;
subs_term_data.event = scbp->hb.event_type;
subs_term_data.msg_id = scbp->subsTermCallbackMsgID;
subs_term_data.line_id = scbp->hb.dn_line;
subs_term_data.gsm_id = scbp->gsm_id;
subs_term_data.reason_code = SM_REASON_CODE_NORMAL;
subs_term_data.u.subs_term_data.status_code =
NETWORK_SUBSCRIPTION_EXPIRED;
if (scbp->subsTermCallback) {
scbp->subsTermCallback(&subs_term_data);
} else if (scbp->subsIndCallbackTask != CC_SRC_MIN) {
(void) sip_send_message(&subs_term_data, scbp->subsIndCallbackTask,
scbp->subsTermCallbackMsgID);
}
}
}
}
}
// Re-start periodic timer
(void) sip_platform_subnot_periodic_timer_start(TMR_PERIODIC_SUBNOT_INTERVAL * 1000);
/*
* Comment out the periodic show since now we have a show-subscription-statistics CLI
* Do not want to completely remove this code since the CLI is not available in
* IP-Communicator where this could be enabled for debugging
*/
/*
* if (count == 50) {
* // Show the stats for the Subsmanager
* CCSIP_DEBUG_TASK("Reg - RecdSubs RecdNots ActiveExtSubs - SentSubs SentNots ActiveIntSubs - CurSCBs MaxSCBs\n");
* CCSIP_DEBUG_TASK("-----------------------------------------------------------------------------------\n");
* CCSIP_DEBUG_TASK("%d - %d %d %d - %d %d %d - %d %d\n",
* internalRegistrations, incomingSubscribes,
* incomingNotifies, incomingSubscriptions,
* outgoingSubscribes, outgoingNotifies,
* outgoingSubscriptions, currentScbsAllocated,
* maxScbsAllocated);
* count = 0;
* } else {
* count ++;
* }
*/
}
/**************************************************************
* Format and send a response to a network received NOTIFY
* Currently this action is handled together with the response
* to SUBSCRIBE
**************************************************************/
boolean
sipSPISendSubNotifyResponse (sipSCB_t *scbp, int response_code)
{
return TRUE;
}
static void
show_scbs_inuse ()
{
int i;
sipSCB_t *scbp = NULL;
if (subsManagerRunning == 0) {
return;
}
debugif_printf("---------SCB DUMP----------\n");
for (i = 0; i < MAX_SCBS; i++) {
scbp = &(subsManagerSCBS[i]);
if (scbp->smState == SUBS_STATE_IDLE) {
debugif_printf("SCB# %d, State = %d (IDLE)\n", i, scbp->smState);
continue;
}
if (scbp->smState == SUBS_STATE_REGISTERED) {
debugif_printf("SCB# %d, State = %d (REGISTERED) sub_id=%x\n",
i, scbp->smState, scbp->sub_id);
debugif_printf("SCB# %d, eventPackage=%d\n",
i, scbp->hb.event_type);
continue;
}
debugif_printf("SCB# %d, State = %d sub_id=%x\n", i, scbp->smState,
scbp->sub_id);
debugif_printf("SCB# %d, pendingClean=%d, internal=%d, eventPackage=%d, "
"norefersub=%d, subscriptionState=%d, expires=%d\n", i,
scbp->pendingClean, scbp->internal, scbp->hb.event_type,
scbp->norefersub, scbp->subscription_state, scbp->hb.expires);
debugif_printf("-----------------------------\n");
}
}
cc_int32_t
show_subsmanager_stats (cc_int32_t argc, const char *argv[])
{
debugif_printf("------ Current Subsmanager Statistics ------\n");
debugif_printf("Internal Registrations: %d\n", internalRegistrations);
debugif_printf("Total Incoming Subscribes: %d\n", incomingSubscribes);
debugif_printf("Total Incoming Notifies: %d\n", incomingNotifies);
debugif_printf("Total Incoming Unsolicited Notifies: %d\n", incomingUnsolicitedNotifies);
debugif_printf("Active Incoming Subscriptions: %d\n", incomingSubscriptions);
debugif_printf("Total Outgoing Subscribes: %d\n", outgoingSubscribes);
debugif_printf("Total Outgoing Notifies: %d\n", outgoingNotifies);
debugif_printf("Total Outgoing Unsolicited Notifies: %d\n", outgoingUnsolicitedNotifies);
debugif_printf("Active Outgoing Subscriptions: %d\n", outgoingSubscriptions);
debugif_printf("Current SCBs Allocated: %d\n", currentScbsAllocated);
debugif_printf("Total Maximum SCBs Ever Allocated: %d\n", maxScbsAllocated);
debugif_printf("------ End of Subsmanager Statistics ------\n");
// Now print out the status of all SCBs
show_scbs_inuse();
return 0;
}