mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-10-26 05:04:14 +00:00
285 lines
10 KiB
C
285 lines
10 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_string.h"
|
|
#include "ccsip_reldev.h"
|
|
#include "ccsip_macros.h"
|
|
#include "phone_debug.h"
|
|
#include "ccsip_pmh.h"
|
|
#include "ccsip_messaging.h"
|
|
#include "sip_common_transport.h"
|
|
#include "util_string.h"
|
|
|
|
/* Constants */
|
|
#define SIP_RRLIST_LENGTH (MAX_TEL_LINES)
|
|
|
|
/* Global variables */
|
|
sipRelDevMessageRecord_t gSIPRRList[SIP_RRLIST_LENGTH];
|
|
|
|
|
|
void
|
|
sipRelDevMessageStore (sipRelDevMessageRecord_t * pMessageRecord)
|
|
{
|
|
static int counter = 0;
|
|
|
|
/* Loop around */
|
|
if (counter > (SIP_RRLIST_LENGTH - 1)) {
|
|
counter = 0;
|
|
}
|
|
|
|
gSIPRRList[counter] = *pMessageRecord;
|
|
gSIPRRList[counter].valid_coupled_message = FALSE;
|
|
counter++;
|
|
}
|
|
|
|
|
|
boolean
|
|
sipRelDevMessageIsDuplicate (sipRelDevMessageRecord_t *pMessageRecord,
|
|
int *idx)
|
|
{
|
|
int i = 0;
|
|
|
|
for (i = 0; i < SIP_RRLIST_LENGTH; i++) {
|
|
if ((strcmp(pMessageRecord->call_id, gSIPRRList[i].call_id) == 0) &&
|
|
(pMessageRecord->cseq_number == gSIPRRList[i].cseq_number) &&
|
|
(pMessageRecord->cseq_method == gSIPRRList[i].cseq_method) &&
|
|
(strcasecmp_ignorewhitespace(pMessageRecord->tag, gSIPRRList[i].tag) == 0) &&
|
|
(strcmp(pMessageRecord->from_user, gSIPRRList[i].from_user) == 0) &&
|
|
(strcmp(pMessageRecord->from_host, gSIPRRList[i].from_host) == 0) &&
|
|
(strcmp(pMessageRecord->to_user, gSIPRRList[i].to_user) == 0)) {
|
|
|
|
if (pMessageRecord->is_request) {
|
|
*idx = i;
|
|
return (TRUE);
|
|
} else {
|
|
if (pMessageRecord->response_code == gSIPRRList[i].response_code) {
|
|
*idx = i;
|
|
return (TRUE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
*idx = -1;
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
/*
|
|
* Function: sipRelDevCoupledMessageStore
|
|
*
|
|
* Parameters:
|
|
* pCoupledMessage - pointer to sipMessage_t for the message that
|
|
* needed reliable delivery store.
|
|
* call_id - pointer to const. char for the SIP call ID.
|
|
* cseq_number - the uint32_t for CSeq of the message.
|
|
* sipMethod_t - sipMethod_t the SIP method of the message.
|
|
* dest_ipaddr - uint32_t IP address of the destination address.
|
|
* dest_port - uint16_t destination port
|
|
* ignore_tag - boolean to ignore tag.
|
|
*
|
|
* Description:
|
|
* The function finds the corresponding entry in the gSIPRRList
|
|
* array that matches call_id, cseq number, method and possibly tag.
|
|
* If a match entry is found, the SIP message is composed and stored
|
|
* in the corresponding entry.
|
|
*
|
|
* Returns:
|
|
* idx - When the entry is found and successfully stored the
|
|
* SIP message.
|
|
* RELDEV_NO_STORED_MSG - encounter errors or no message is
|
|
* stored.
|
|
*/
|
|
int
|
|
sipRelDevCoupledMessageStore (sipMessage_t *pCoupledMessage,
|
|
const char *call_id,
|
|
uint32_t cseq_number,
|
|
sipMethod_t cseq_method,
|
|
boolean is_request,
|
|
int response_code,
|
|
cpr_ip_addr_t *dest_ipaddr,
|
|
uint16_t dest_port,
|
|
boolean ignore_tag)
|
|
{
|
|
static const char *fname = "sipRelDevCoupledMessageStore";
|
|
int i = 0;
|
|
char to_tag[MAX_SIP_TAG_LENGTH];
|
|
|
|
sipGetMessageToTag(pCoupledMessage, to_tag, MAX_SIP_TAG_LENGTH);
|
|
CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Storing for reTx (cseq=%d, method=%s, "
|
|
"to_tag=<%s>)\n", DEB_F_PREFIX_ARGS(SIP_STORE, fname), cseq_number,
|
|
sipGetMethodString(cseq_method), to_tag);
|
|
|
|
for (i = 0; i < SIP_RRLIST_LENGTH; i++) {
|
|
if ((strcmp(call_id, gSIPRRList[i].call_id) == 0) &&
|
|
(cseq_number == gSIPRRList[i].cseq_number) &&
|
|
(cseq_method == gSIPRRList[i].cseq_method) &&
|
|
((ignore_tag) ? TRUE : (strcasecmp_ignorewhitespace(to_tag,
|
|
gSIPRRList[i].tag)
|
|
== 0))) {
|
|
hStatus_t sippmh_write_status = STATUS_FAILURE;
|
|
uint32_t nbytes = SIP_UDP_MESSAGE_SIZE;
|
|
|
|
/*
|
|
When storing the ACK message check that you are storing it
|
|
coupled with the correct response code and not transitional responses
|
|
*/
|
|
if (is_request == FALSE ||
|
|
(is_request == TRUE && gSIPRRList[i].response_code == response_code)) {
|
|
gSIPRRList[i].coupled_message.message_buf[0] = '\0';
|
|
sippmh_write_status =
|
|
sippmh_write(pCoupledMessage,
|
|
gSIPRRList[i].coupled_message.message_buf,
|
|
&nbytes);
|
|
if (sippmh_write_status == STATUS_FAILURE) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sippmh_write() failed.\n", fname);
|
|
return (RELDEV_NO_STORED_MSG);
|
|
}
|
|
if ((gSIPRRList[i].coupled_message.message_buf[0] == '\0') ||
|
|
(nbytes == 0)) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sippmh_write() returned empty buffer string.\n",
|
|
fname);
|
|
return (RELDEV_NO_STORED_MSG);
|
|
}
|
|
gSIPRRList[i].coupled_message.message_buf_len = nbytes;
|
|
gSIPRRList[i].coupled_message.dest_ipaddr = *dest_ipaddr;
|
|
gSIPRRList[i].coupled_message.dest_port = dest_port;
|
|
gSIPRRList[i].valid_coupled_message = TRUE;
|
|
/* Return the stored idx to the caller */
|
|
return (i);
|
|
}
|
|
}
|
|
}
|
|
return (RELDEV_NO_STORED_MSG);
|
|
}
|
|
|
|
/*
|
|
* Function: sipRelDevGetStoredCoupledMessage
|
|
*
|
|
* Parameters:
|
|
* idx - int for the idx to retrieve stored SIP message.
|
|
* dest_buffer - pointer to char to retrieve the copy of the
|
|
* stored SIP message.
|
|
* dest_buf_size - uint32_t for the size of the dest_buffer.
|
|
*
|
|
* Description:
|
|
* The function gets the stored SIP message for the request entry.
|
|
*
|
|
* Returns:
|
|
* The function returns the number of the bytes of the SIP message
|
|
* obtained if SIP message is found otherwise it returns zero (
|
|
* no SIP message available).
|
|
*/
|
|
uint32_t
|
|
sipRelDevGetStoredCoupledMessage (int idx,
|
|
char *dest_buffer,
|
|
uint32_t dest_buf_size)
|
|
{
|
|
sipRelDevMessageRecord_t *record;
|
|
|
|
if (dest_buffer == NULL) {
|
|
/* No destination buffer given, can not provide any result */
|
|
return (0);
|
|
}
|
|
if ((idx < 0) || (idx >= SIP_RRLIST_LENGTH)) {
|
|
/* the stored message is out of range */
|
|
return (0);
|
|
}
|
|
|
|
record = &gSIPRRList[idx];
|
|
|
|
if (!record->valid_coupled_message) {
|
|
/* No message stored for the given idx */
|
|
return (0);
|
|
}
|
|
if ((record->coupled_message.message_buf_len > dest_buf_size) ||
|
|
(record->coupled_message.message_buf_len == 0)) {
|
|
/*
|
|
* The stored message size is larger than the give buffer or
|
|
* stored message length is zero?
|
|
*/
|
|
return (0);
|
|
}
|
|
/* Get the stored message to the caller */
|
|
memcpy(dest_buffer, &record->coupled_message.message_buf[0],
|
|
record->coupled_message.message_buf_len);
|
|
return (record->coupled_message.message_buf_len);
|
|
}
|
|
|
|
int
|
|
sipRelDevCoupledMessageSend (int idx)
|
|
{
|
|
static const char *fname = "sipRelDevCoupledMessageSend";
|
|
char dest_ipaddr_str[MAX_IPADDR_STR_LEN];
|
|
|
|
if ((idx < 0) || (idx >= SIP_RRLIST_LENGTH)) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Argument Check: idx (=%d) out of bounds.\n",
|
|
fname, idx);
|
|
return SIP_ERROR;
|
|
}
|
|
|
|
if (gSIPRRList[idx].valid_coupled_message) {
|
|
ipaddr2dotted(dest_ipaddr_str,
|
|
&gSIPRRList[idx].coupled_message.dest_ipaddr);
|
|
|
|
CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Sending stored coupled message (idx=%d) to "
|
|
"<%s>:<%d>\n", DEB_F_PREFIX_ARGS(SIP_MSG_SEND, fname), idx, dest_ipaddr_str,
|
|
gSIPRRList[idx].coupled_message.dest_port);
|
|
if (sipTransportChannelSend(NULL,
|
|
gSIPRRList[idx].coupled_message.message_buf,
|
|
gSIPRRList[idx].coupled_message.message_buf_len,
|
|
sipMethodInvalid,
|
|
&(gSIPRRList[idx].coupled_message.dest_ipaddr),
|
|
gSIPRRList[idx].coupled_message.dest_port,
|
|
0) < 0) {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sipTransportChannelSend() failed."
|
|
" Stored message not sent.\n", fname);
|
|
return SIP_ERROR;
|
|
}
|
|
} else {
|
|
CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Duplicate message detected but failed to"
|
|
" find valid coupled message. Stored message not sent.\n",
|
|
fname);
|
|
return SIP_ERROR;
|
|
}
|
|
return SIP_OK;
|
|
}
|
|
|
|
|
|
/*
|
|
* Function for clearing all the messages belonging to the
|
|
* associated with the specified call_id, from_user, from_host,
|
|
* and to_user
|
|
*/
|
|
void
|
|
sipRelDevMessagesClear (const char *call_id,
|
|
const char *from_user,
|
|
const char *from_host,
|
|
const char *to_user)
|
|
{
|
|
int i = 0;
|
|
|
|
for (i = 0; i < SIP_RRLIST_LENGTH; i++) {
|
|
if ((strcmp(call_id, gSIPRRList[i].call_id) == 0) &&
|
|
(strcmp(from_user, gSIPRRList[i].from_user) == 0) &&
|
|
(strcmp(from_host, gSIPRRList[i].from_host) == 0) &&
|
|
(strcmp(to_user, gSIPRRList[i].to_user) == 0)) {
|
|
memset(&gSIPRRList[i], 0, sizeof(sipRelDevMessageRecord_t));
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Function for clearing all the messages
|
|
*/
|
|
void sipRelDevAllMessagesClear(){
|
|
int i = 0;
|
|
for (i = 0; i < SIP_RRLIST_LENGTH; i++) {
|
|
memset(&gSIPRRList[i], 0, sizeof(sipRelDevMessageRecord_t));
|
|
}
|
|
return;
|
|
}
|