blob: 938f433f48730c1713d874ced57048bf5d264bd0 [file] [log] [blame]
#define LOG_MODULE PacketLogModuleSipLayer
#include "SipLayer.h"
#include "SdpLayer.h"
#include "PayloadLayer.h"
#include "Logger.h"
#include <string.h>
#include <algorithm>
#include <stdlib.h>
namespace pcpp
{
const std::string SipMethodEnumToString[14] = {
"INVITE",
"ACK",
"BYE",
"CANCEL",
"REGISTER",
"PRACK",
"OPTIONS",
"SUBSCRIBE",
"NOTIFY",
"PUBLISH",
"INFO",
"REFER",
"MESSAGE",
"UPDATE"
};
// -------- Class SipLayer -----------------
int SipLayer::getContentLength()
{
std::string contentLengthFieldName(PCPP_SIP_CONTENT_LENGTH_FIELD);
std::transform(contentLengthFieldName.begin(), contentLengthFieldName.end(), contentLengthFieldName.begin(), ::tolower);
HeaderField* contentLengthField = getFieldByName(contentLengthFieldName);
if (contentLengthField != NULL)
return atoi(contentLengthField->getFieldValue().c_str());
return 0;
}
HeaderField* SipLayer::setContentLength(int contentLength, const std::string prevFieldName)
{
char contentLengthAsString[20];
snprintf (contentLengthAsString, sizeof(contentLengthAsString), "%d",contentLength);
std::string contentLengthFieldName(PCPP_SIP_CONTENT_LENGTH_FIELD);
HeaderField* contentLengthField = getFieldByName(contentLengthFieldName);
if (contentLengthField == NULL)
{
HeaderField* prevField = getFieldByName(prevFieldName);
contentLengthField = insertField(prevField, PCPP_SIP_CONTENT_LENGTH_FIELD, contentLengthAsString);
}
else
contentLengthField->setFieldValue(std::string(contentLengthAsString));
return contentLengthField;
}
void SipLayer::parseNextLayer()
{
if (getLayerPayloadSize() == 0)
return;
size_t headerLen = getHeaderLen();
if (getContentLength() > 0)
{
m_NextLayer = new SdpLayer(m_Data + headerLen, m_DataLen - headerLen, this, m_Packet);
}
else
{
m_NextLayer = new PayloadLayer(m_Data + headerLen, m_DataLen - headerLen, this, m_Packet);
}
}
void SipLayer::computeCalculateFields()
{
HeaderField* contentLengthField = getFieldByName(PCPP_SIP_CONTENT_LENGTH_FIELD);
if (contentLengthField == NULL)
return;
size_t headerLen = getHeaderLen();
if (m_DataLen > headerLen)
{
int currentContentLength = getContentLength();
if (currentContentLength != (int)(m_DataLen - headerLen))
setContentLength(m_DataLen - headerLen);
}
}
// -------- Class SipRequestFirstLine -----------------
SipRequestFirstLine::SipRequestFirstLine(SipRequestLayer* sipRequest) : m_SipRequest(sipRequest)
{
m_Method = parseMethod((char*)m_SipRequest->m_Data, m_SipRequest->getDataLen());
if (m_Method == SipRequestLayer::SipMethodUnknown)
{
m_UriOffset = -1;
LOG_DEBUG("Couldn't resolve SIP request method");
}
else
m_UriOffset = SipMethodEnumToString[m_Method].length() + 1;
parseVersion();
char* endOfFirstLine;
if ((endOfFirstLine = (char *)memchr((char*)(m_SipRequest->m_Data + m_VersionOffset), '\n', m_SipRequest->m_DataLen-(size_t)m_VersionOffset)) != NULL)
{
m_FirstLineEndOffset = endOfFirstLine - (char*)m_SipRequest->m_Data + 1;
m_IsComplete = true;
}
else
{
m_FirstLineEndOffset = m_SipRequest->getDataLen();
m_IsComplete = false;
}
LOG_DEBUG("Method='%s'; SIP version='%s'; URI='%s'", SipMethodEnumToString[m_Method].c_str(), m_Version.c_str(), getUri().c_str());
}
SipRequestFirstLine::SipRequestFirstLine(SipRequestLayer* sipRequest, SipRequestLayer::SipMethod method, std::string version, std::string uri)
throw(SipRequestFirstLineException)
{
if (method == SipRequestLayer::SipMethodUnknown)
{
m_Exception.setMessage("Method supplied was SipMethodUnknown");
throw m_Exception;
}
if (version == "")
{
m_Exception.setMessage("Version supplied was empty string");
throw m_Exception;
}
m_SipRequest = sipRequest;
m_Method = method;
m_Version = version;
std::string firstLine = SipMethodEnumToString[m_Method] + " " + uri + " " + version + "\r\n";
m_UriOffset = SipMethodEnumToString[m_Method].length() + 1;
m_FirstLineEndOffset = firstLine.length();
m_VersionOffset = m_UriOffset + uri.length() + 6;
m_SipRequest->m_DataLen = firstLine.length();
m_SipRequest->m_Data = new uint8_t[m_SipRequest->m_DataLen];
memcpy(m_SipRequest->m_Data, firstLine.c_str(), m_SipRequest->m_DataLen);
m_IsComplete = true;
}
SipRequestLayer::SipMethod SipRequestFirstLine::parseMethod(char* data, size_t dataLen)
{
if (dataLen < 4)
{
return SipRequestLayer::SipMethodUnknown;
}
switch (data[0])
{
case 'A':
if (data[1] == 'C' && data[2] == 'K' && data[3] == ' ')
return SipRequestLayer::SipACK;
else
return SipRequestLayer::SipMethodUnknown;
break;
case 'B':
if (data[1] == 'Y' && data[2] == 'E' && data[3] == ' ')
return SipRequestLayer::SipBYE;
else
return SipRequestLayer::SipMethodUnknown;
break;
case 'C':
if (dataLen < 7)
return SipRequestLayer::SipMethodUnknown;
else if (data[1] == 'A' && data[2] == 'N' && data[3] == 'C' && data[4] == 'E' && data[5] == 'L' && data[6] == ' ')
return SipRequestLayer::SipCANCEL;
else
return SipRequestLayer::SipMethodUnknown;
break;
case 'O':
if (dataLen < 8)
return SipRequestLayer::SipMethodUnknown;
else if (data[1] == 'P' && data[2] == 'T' && data[3] == 'I' && data[4] == 'O' && data[5] == 'N' && data[6] == 'S' && data[7] == ' ')
return SipRequestLayer::SipOPTIONS;
else
return SipRequestLayer::SipMethodUnknown;
break;
case 'R':
if (dataLen < 6)
return SipRequestLayer::SipMethodUnknown;
else if (data[1] == 'E' && data[2] == 'F' && data[3] == 'E' && data[4] == 'R' && data[5] == ' ')
return SipRequestLayer::SipREFER;
else if (dataLen < 9)
return SipRequestLayer::SipMethodUnknown;
else if (data[1] == 'E' && data[2] == 'G' && data[3] == 'I' && data[4] == 'S' && data[5] == 'T' && data[6] == 'E' && data[7] == 'R' && data[8] == ' ')
return SipRequestLayer::SipREGISTER;
else
return SipRequestLayer::SipMethodUnknown;
break;
case 'P':
if (dataLen < 6)
return SipRequestLayer::SipMethodUnknown;
else if (data[1] == 'R' && data[2] == 'A' && data[3] == 'C' && data[4] == 'K' && data[5] == ' ')
return SipRequestLayer::SipPRACK;
else if (dataLen < 8)
return SipRequestLayer::SipMethodUnknown;
else if (data[1] == 'U' && data[2] == 'B' && data[3] == 'L' && data[4] == 'I' && data[5] == 'S' && data[6] == 'H' && data[7] == ' ')
return SipRequestLayer::SipPUBLISH;
break;
case 'S':
if (dataLen < 10)
return SipRequestLayer::SipMethodUnknown;
else if (data[1] == 'U' && data[2] == 'B' && data[3] == 'S' && data[4] == 'C' && data[5] == 'R' && data[6] == 'I' && data[7] == 'B' && data[8] == 'E' && data[9] == ' ')
return SipRequestLayer::SipSUBSCRIBE;
break;
case 'N':
if (dataLen < 7)
return SipRequestLayer::SipMethodUnknown;
else if (data[1] == 'O' && data[2] == 'T' && data[3] == 'I' && data[4] == 'F' && data[5] == 'Y' && data[6] == ' ')
return SipRequestLayer::SipNOTIFY;
break;
case 'I':
if (data[1] == 'N' && data[2] == 'F' && data[3] == 'O')
return SipRequestLayer::SipINFO;
else if (dataLen < 7)
return SipRequestLayer::SipMethodUnknown;
else if (data[1] == 'N' && data[2] == 'V' && data[3] == 'I' && data[4] == 'T' && data[5] == 'E' && data[6] == ' ')
return SipRequestLayer::SipINVITE;
break;
case 'M':
if (dataLen < 8)
return SipRequestLayer::SipMethodUnknown;
else if (data[1] == 'E' && data[2] == 'S' && data[3] == 'S' && data[4] == 'A' && data[5] == 'G' && data[6] == 'E' && data[7] == ' ')
return SipRequestLayer::SipMESSAGE;
break;
case 'U':
if (dataLen < 7)
return SipRequestLayer::SipMethodUnknown;
else if (data[1] == 'P' && data[2] == 'D' && data[3] == 'A' && data[4] == 'T' && data[5] == 'E' && data[6] == ' ')
return SipRequestLayer::SipUPDATE;
break;
default:
return SipRequestLayer::SipMethodUnknown;
}
return SipRequestLayer::SipMethodUnknown;
}
void SipRequestFirstLine::parseVersion()
{
char* data = (char*)(m_SipRequest->m_Data + m_UriOffset);
char* verPos = strstr(data, " SIP/");
if (verPos == NULL)
{
m_Version = "";
m_VersionOffset = -1;
return;
}
// verify packet doesn't end before the version, meaning still left place for " SIP/x.y" (7 chars)
if ((uint16_t)(verPos + 7 - (char*)m_SipRequest->m_Data) > m_SipRequest->getDataLen())
{
m_Version = "";
m_VersionOffset = -1;
return;
}
//skip the space char
verPos++;
int endOfVerPos = 0;
while (((verPos+endOfVerPos)[0] != '\r') && ((verPos+endOfVerPos)[0] != '\n'))
endOfVerPos++;
m_Version = std::string(verPos, endOfVerPos);
m_VersionOffset = verPos - (char*)m_SipRequest->m_Data;
}
bool SipRequestFirstLine::setMethod(SipRequestLayer::SipMethod newMethod)
{
if (newMethod == SipRequestLayer::SipMethodUnknown)
{
LOG_ERROR("Requested method is SipMethodUnknown");
return false;
}
//extend or shorten layer
int lengthDifference = SipMethodEnumToString[newMethod].length() - SipMethodEnumToString[m_Method].length();
if (lengthDifference > 0)
{
if (!m_SipRequest->extendLayer(0, lengthDifference))
{
LOG_ERROR("Cannot change layer size");
return false;
}
}
else if (lengthDifference < 0)
{
if (!m_SipRequest->shortenLayer(0, 0-lengthDifference))
{
LOG_ERROR("Cannot change layer size");
return false;
}
}
if (lengthDifference != 0)
{
m_SipRequest->shiftFieldsOffset(m_SipRequest->getFirstField(), lengthDifference);
m_SipRequest->m_FieldsOffset += lengthDifference;
}
memcpy(m_SipRequest->m_Data, SipMethodEnumToString[newMethod].c_str(), SipMethodEnumToString[newMethod].length());
m_UriOffset += lengthDifference;
m_VersionOffset += lengthDifference;
m_FirstLineEndOffset += lengthDifference;
m_Method = newMethod;
return true;
}
std::string SipRequestFirstLine::getUri()
{
std::string result;
if (m_UriOffset != -1 && m_VersionOffset != -1)
result.assign((char*)(m_SipRequest->m_Data + m_UriOffset), m_VersionOffset-1-m_UriOffset);
//else first line is illegal, return empty string
return result;
}
bool SipRequestFirstLine::setUri(std::string newUri)
{
if (newUri == "")
{
LOG_ERROR("URI cannot be empty");
return false;
}
//extend or shorten layer
std::string currentUri = getUri();
int lengthDifference = newUri.length() - currentUri.length();
if (lengthDifference > 0)
{
if (!m_SipRequest->extendLayer(m_UriOffset, lengthDifference))
{
LOG_ERROR("Cannot change layer size");
return false;
}
}
else if (lengthDifference < 0)
{
if (!m_SipRequest->shortenLayer(m_UriOffset, 0-lengthDifference))
{
LOG_ERROR("Cannot change layer size");
return false;
}
}
if (lengthDifference != 0)
{
m_SipRequest->shiftFieldsOffset(m_SipRequest->getFirstField(), lengthDifference);
m_SipRequest->m_FieldsOffset += lengthDifference;
}
memcpy(m_SipRequest->m_Data + m_UriOffset, newUri.c_str(), newUri.length());
m_VersionOffset += lengthDifference;
m_FirstLineEndOffset += lengthDifference;
return true;
}
// -------- Class SipRequestLayer -----------------
SipRequestLayer::SipRequestLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) : SipLayer(data, dataLen, prevLayer, packet)
{
m_Protocol = SIPRequest;
m_FirstLine = new SipRequestFirstLine(this);
m_FieldsOffset = m_FirstLine->getSize();
parseFields();
}
SipRequestLayer::SipRequestLayer(SipMethod method, std::string requestUri, std::string version)
{
m_Protocol = SIPRequest;
m_FirstLine = new SipRequestFirstLine(this, method, version, requestUri);
m_FieldsOffset = m_FirstLine->getSize();
}
SipRequestLayer::SipRequestLayer(const SipRequestLayer& other) : SipLayer(other)
{
m_FirstLine = new SipRequestFirstLine(this);
}
SipRequestLayer& SipRequestLayer::operator=(const SipRequestLayer& other)
{
SipLayer::operator=(other);
if (m_FirstLine != NULL)
delete m_FirstLine;
m_FirstLine = new SipRequestFirstLine(this);
return *this;
}
SipRequestLayer::~SipRequestLayer()
{
delete m_FirstLine;
}
std::string SipRequestLayer::toString()
{
static const int maxLengthToPrint = 120;
std::string result = "SIP request, ";
int size = m_FirstLine->getSize() - 2; // the -2 is to remove \r\n at the end of the first line
if (size <= maxLengthToPrint)
{
char* firstLine = new char[size+1];
strncpy(firstLine, (char*)m_Data, size);
firstLine[size] = 0;
result += std::string(firstLine);
delete[] firstLine;
}
else
{
char firstLine[maxLengthToPrint+1];
strncpy(firstLine, (char*)m_Data, maxLengthToPrint-3);
firstLine[maxLengthToPrint-3] = '.';
firstLine[maxLengthToPrint-2] = '.';
firstLine[maxLengthToPrint-1] = '.';
firstLine[maxLengthToPrint] = 0;
result += std::string(firstLine);
}
return result;
}
// -------- Class SipResponseLayer -----------------
const std::string StatusCodeEnumToString[74] = {
"Trying",
"Ringing",
"Call is Being Forwarded",
"Queued",
"Session in Progress",
"Early Dialog Terminated",
"OK",
"Accepted",
"No Notification",
"Multiple Choices",
"Moved Permanently",
"Moved Temporarily",
"Use Proxy",
"Alternative Service",
"Bad Request",
"Unauthorized",
"Payment Required",
"Forbidden",
"Not Found",
"Method Not Allowed",
"Not Acceptable",
"Proxy Authentication Required",
"Request Timeout",
"Conflict",
"Gone",
"Length Required",
"Conditional Request Failed",
"Request Entity Too Large",
"Request-URI Too Long",
"Unsupported Media Type",
"Unsupported URI Scheme",
"Unknown Resource-Priority",
"Bad Extension",
"Extension Required",
"Session Interval Too Small",
"Interval Too Brief",
"Bad Location Information",
"Use Identity Header",
"Provide Referrer Identity",
"Flow Failed",
"Anonymity Disallowed",
"Bad Identity-Info",
"Unsupported Certificate",
"Invalid Identity Header",
"First Hop Lacks Outbound Support",
"Max-Breadth Exceeded",
"Bad Info Package",
"Consent Needed",
"Temporarily Unavailable",
"Call_Transaction Does Not Exist",
"Loop Detected",
"Too Many Hops",
"Address Incomplete",
"Ambiguous",
"Busy Here",
"Request Terminated",
"Not Acceptable Here",
"Bad Event",
"Request Pending",
"Undecipherable",
"Security Agreement Required",
"Server Internal Error",
"Not Implemented",
"Bad Gateway",
"Service Unavailable",
"Server Timeout",
"Version Not Supported",
"Message Too Large",
"Precondition Failure",
"Busy Everywhere",
"Decline",
"Does Not Exist Anywhere",
"Not Acceptable",
"Unwanted"
};
const int StatusCodeEnumToInt[74] = {
100,
180,
181,
182,
183,
199,
200,
202,
204,
300,
301,
302,
305,
380,
400,
401,
402,
403,
404,
405,
406,
407,
408,
409,
410,
411,
412,
413,
414,
415,
416,
417,
420,
421,
422,
423,
424,
428,
429,
430,
433,
436,
437,
438,
439,
440,
469,
470,
480,
481,
482,
483,
484,
485,
486,
487,
488,
489,
491,
493,
494,
500,
501,
502,
503,
504,
505,
513,
580,
600,
603,
604,
606,
607
};
SipResponseLayer::SipResponseLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) : SipLayer(data, dataLen, prevLayer, packet)
{
m_Protocol = SIPResponse;
m_FirstLine = new SipResponseFirstLine(this);
m_FieldsOffset = m_FirstLine->getSize();
parseFields();
}
SipResponseLayer::SipResponseLayer(SipResponseLayer::SipResponseStatusCode statusCode, std::string statusCodeString, std::string sipVersion)
{
m_Protocol = SIPResponse;
m_FirstLine = new SipResponseFirstLine(this, sipVersion, statusCode, statusCodeString);
m_FieldsOffset = m_FirstLine->getSize();
}
SipResponseLayer::~SipResponseLayer()
{
delete m_FirstLine;
}
SipResponseLayer::SipResponseLayer(const SipResponseLayer& other) : SipLayer(other)
{
m_FirstLine = new SipResponseFirstLine(this);
}
SipResponseLayer& SipResponseLayer::operator=(const SipResponseLayer& other)
{
SipLayer::operator=(other);
if (m_FirstLine != NULL)
delete m_FirstLine;
m_FirstLine = new SipResponseFirstLine(this);
return *this;
}
std::string SipResponseLayer::toString()
{
static const int maxLengthToPrint = 120;
std::string result = "SIP response, ";
int size = m_FirstLine->getSize() - 2; // the -2 is to remove \r\n at the end of the first line
if (size <= maxLengthToPrint)
{
char* firstLine = new char[size+1];
strncpy(firstLine, (char*)m_Data, size);
firstLine[size] = 0;
result += std::string(firstLine);
delete[] firstLine;
}
else
{
char firstLine[maxLengthToPrint+1];
strncpy(firstLine, (char*)m_Data, maxLengthToPrint-3);
firstLine[maxLengthToPrint-3] = '.';
firstLine[maxLengthToPrint-2] = '.';
firstLine[maxLengthToPrint-1] = '.';
firstLine[maxLengthToPrint] = 0;
result += std::string(firstLine);
}
return result;
}
// -------- Class SipResponseFirstLine -----------------
int SipResponseFirstLine::getStatusCodeAsInt()
{
return StatusCodeEnumToInt[m_StatusCode];
}
std::string SipResponseFirstLine::getStatusCodeString()
{
std::string result;
int statusStringOffset = 12;
if (m_StatusCode != SipResponseLayer::SipStatusCodeUnknown)
{
int statusStringEndOffset = m_FirstLineEndOffset - 2;
if ((*(m_SipResponse->m_Data + statusStringEndOffset)) != '\r')
statusStringEndOffset++;
result.assign((char*)(m_SipResponse->m_Data + statusStringOffset), statusStringEndOffset-statusStringOffset);
}
//else first line is illegal, return empty string
return result;
}
bool SipResponseFirstLine::setStatusCode(SipResponseLayer::SipResponseStatusCode newStatusCode, std::string statusCodeString)
{
if (newStatusCode == SipResponseLayer::SipStatusCodeUnknown)
{
LOG_ERROR("Requested status code is SipStatusCodeUnknown");
return false;
}
//extend or shorten layer
size_t statusStringOffset = 12;
if (statusCodeString == "")
statusCodeString = StatusCodeEnumToString[newStatusCode];
int lengthDifference = statusCodeString.length() - getStatusCodeString().length();
if (lengthDifference > 0)
{
if (!m_SipResponse->extendLayer(statusStringOffset, lengthDifference))
{
LOG_ERROR("Cannot change layer size");
return false;
}
}
else if (lengthDifference < 0)
{
if (!m_SipResponse->shortenLayer(statusStringOffset, 0-lengthDifference))
{
LOG_ERROR("Cannot change layer size");
return false;
}
}
if (lengthDifference != 0)
{
m_SipResponse->shiftFieldsOffset(m_SipResponse->getFirstField(), lengthDifference);
m_SipResponse->m_FieldsOffset += lengthDifference;
}
// copy status string
memcpy(m_SipResponse->m_Data+statusStringOffset, statusCodeString.c_str(), statusCodeString.length());
// change status code
char statusCodeAsString[4];
// convert code to string
snprintf (statusCodeAsString, sizeof(statusCodeAsString), "%d",StatusCodeEnumToInt[newStatusCode]);
memcpy(m_SipResponse->m_Data+8, statusCodeAsString, 3);
m_StatusCode = newStatusCode;
m_FirstLineEndOffset += lengthDifference;
return true;
}
void SipResponseFirstLine::setVersion(std::string newVersion)
{
if (newVersion == "")
return;
if (newVersion.length() != m_Version.length())
{
LOG_ERROR("Expected version length is %d characters in the format of SIP/x.y", (int)m_Version.length());
return;
}
char* verPos = (char*)m_SipResponse->m_Data;
memcpy(verPos, newVersion.c_str(), newVersion.length());
m_Version = newVersion;
}
SipResponseLayer::SipResponseStatusCode SipResponseFirstLine::validateStatusCode(char* data, size_t dataLen, SipResponseLayer::SipResponseStatusCode potentialCode)
{
if (data[0] != ' ')
return SipResponseLayer::SipStatusCodeUnknown;
return potentialCode;
}
SipResponseLayer::SipResponseStatusCode SipResponseFirstLine::parseStatusCode(char* data, size_t dataLen)
{
// minimum data should be 12B long: "SIP/x.y XXX"
if (dataLen < 12)
return SipResponseLayer::SipStatusCodeUnknown;
char* statusCodeData = data + 8;
size_t statusCodeDataLen = dataLen - 8;
switch (statusCodeData[0])
{
case '1':
switch (statusCodeData[1])
{
case '0':
if (statusCodeData[2] == '0')
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip100Trying);
else
return SipResponseLayer::SipStatusCodeUnknown;
break;
case '8':
switch (statusCodeData[2])
{
case '0':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip180Ringing);
case '1':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip181CallisBeingForwarded);
case '2':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip182Queued);
case '3':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip183SessioninProgress);
default:
return SipResponseLayer::SipStatusCodeUnknown;
};
break;
case '9':
if (statusCodeData[2] == '9')
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip199EarlyDialogTerminated);
else
return SipResponseLayer::SipStatusCodeUnknown;
break;
default:
return SipResponseLayer::SipStatusCodeUnknown;
};
break;
case '2':
if (statusCodeData[1] == '0')
{
switch (statusCodeData[2])
{
case '0':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip200OK);
case '2':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip202Accepted);
case '4':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip204NoNotification);
default:
return SipResponseLayer::SipStatusCodeUnknown;
};
}
else
return SipResponseLayer::SipStatusCodeUnknown;
break;
case '3':
switch (statusCodeData[1])
{
case '0':
switch (statusCodeData[2])
{
case '0':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip300MultipleChoices);
case '1':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip301MovedPermanently);
case '2':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip302MovedTemporarily);
case '5':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip305UseProxy);
default:
return SipResponseLayer::SipStatusCodeUnknown;
};
break;
case '8':
if (statusCodeData[2] == '0')
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip380AlternativeService);
else
return SipResponseLayer::SipStatusCodeUnknown;
break;
default:
return SipResponseLayer::SipStatusCodeUnknown;
};
break;
case '4':
switch (statusCodeData[1])
{
case '0':
switch (statusCodeData[2])
{
case '0':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip400BadRequest);
case '1':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip401Unauthorized);
case '2':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip402PaymentRequired);
case '3':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip403Forbidden);
case '4':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip404NotFound);
case '5':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip405MethodNotAllowed);
case '6':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip406NotAcceptable);
case '7':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip407ProxyAuthenticationRequired);
case '8':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip408RequestTimeout);
case '9':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip409Conflict);
default:
return SipResponseLayer::SipStatusCodeUnknown;
};
break;
case '1':
switch (statusCodeData[2])
{
case '0':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip410Gone);
case '1':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip411LengthRequired);
case '2':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip412ConditionalRequestFailed);
case '3':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip413RequestEntityTooLarge);
case '4':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip414RequestURITooLong);
case '5':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip415UnsupportedMediaType);
case '6':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip416UnsupportedURIScheme);
case '7':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip417UnknownResourcePriority);
case '8':
default:
return SipResponseLayer::SipStatusCodeUnknown;
};
break;
case '2':
switch (statusCodeData[2])
{
case '0':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip420BadExtension);
case '1':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip421ExtensionRequired);
case '2':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip422SessionIntervalTooSmall);
case '3':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip423IntervalTooBrief);
case '4':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip424BadLocationInformation);
case '8':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip428UseIdentityHeader);
case '9':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip429ProvideReferrerIdentity);
default:
return SipResponseLayer::SipStatusCodeUnknown;
};
break;
case '3':
switch (statusCodeData[2])
{
case '0':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip430FlowFailed);
case '3':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip433AnonymityDisallowed);
case '6':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip436BadIdentityInfo);
case '7':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip437UnsupportedCertificate);
case '8':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip438InvalidIdentityHeader);
case '9':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip439FirstHopLacksOutboundSupport);
default:
return SipResponseLayer::SipStatusCodeUnknown;
};
break;
case '4':
if (statusCodeData[2] == '0')
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip440MaxBreadthExceeded);
else
return SipResponseLayer::SipStatusCodeUnknown;
break;
case '6':
if (statusCodeData[2] == '9')
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip469BadInfoPackage);
else
return SipResponseLayer::SipStatusCodeUnknown;
break;
case '8':
switch (statusCodeData[2])
{
case '0':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip480TemporarilyUnavailable);
case '1':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip481Call_TransactionDoesNotExist);
case '2':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip482LoopDetected);
case '3':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip483TooManyHops);
case '4':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip484AddressIncomplete);
case '5':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip485Ambiguous);
case '6':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip486BusyHere);
case '7':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip487RequestTerminated);
case '8':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip488NotAcceptableHere);
case '9':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip489BadEvent);
default:
return SipResponseLayer::SipStatusCodeUnknown;
};
break;
case '9':
switch (statusCodeData[2])
{
case '1':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip491RequestPending);
case '3':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip493Undecipherable);
case '4':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip494SecurityAgreementRequired);
default:
return SipResponseLayer::SipStatusCodeUnknown;
};
break;
default:
return SipResponseLayer::SipStatusCodeUnknown;
};
break;
case '5':
switch (statusCodeData[1])
{
case '0':
switch (statusCodeData[2])
{
case '0':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip500ServerInternalError);
case '1':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip501NotImplemented);
case '2':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip502BadGateway);
case '3':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip503ServiceUnavailable);
case '4':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip504ServerTimeout);
case '5':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip505VersionNotSupported);
default:
return SipResponseLayer::SipStatusCodeUnknown;
};
break;
case '1':
if (statusCodeData[2] == '3')
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip513MessageTooLarge);
else
return SipResponseLayer::SipStatusCodeUnknown;
break;
case '8':
if (statusCodeData[2] == '0')
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip580PreconditionFailure);
else
return SipResponseLayer::SipStatusCodeUnknown;
break;
default:
return SipResponseLayer::SipStatusCodeUnknown;
};
break;
case '6':
if (statusCodeData[1] == '0')
{
switch (statusCodeData[2])
{
case '0':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip600BusyEverywhere);
case '3':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip603Decline);
case '4':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip604DoesNotExistAnywhere);
case '6':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip606NotAcceptable);
case '7':
return validateStatusCode(statusCodeData+3, statusCodeDataLen-3, SipResponseLayer::Sip607Unwanted);
default:
return SipResponseLayer::SipStatusCodeUnknown;
};
}
else
return SipResponseLayer::SipStatusCodeUnknown;
break;
default:
return SipResponseLayer::SipStatusCodeUnknown;
};
return SipResponseLayer::SipStatusCodeUnknown;
}
SipResponseFirstLine::SipResponseFirstLine(SipResponseLayer* sipResponse) : m_SipResponse(sipResponse)
{
m_Version = parseVersion((char*)m_SipResponse->m_Data, m_SipResponse->getDataLen());
if (m_Version == "")
{
m_StatusCode = SipResponseLayer::SipStatusCodeUnknown;
}
else
{
m_StatusCode = parseStatusCode((char*)m_SipResponse->m_Data, m_SipResponse->getDataLen());
}
char* endOfFirstLine;
if ((endOfFirstLine = (char *)memchr((char*)(m_SipResponse->m_Data), '\n', m_SipResponse->m_DataLen)) != NULL)
{
m_FirstLineEndOffset = endOfFirstLine - (char*)m_SipResponse->m_Data + 1;
m_IsComplete = true;
}
else
{
m_FirstLineEndOffset = m_SipResponse->getDataLen();
m_IsComplete = false;
}
LOG_DEBUG("Version='%s'; Status code=%d '%s'", m_Version.c_str(), StatusCodeEnumToInt[m_StatusCode], getStatusCodeString().c_str());
}
SipResponseFirstLine::SipResponseFirstLine(SipResponseLayer* sipResponse, std::string version, SipResponseLayer::SipResponseStatusCode statusCode, std::string statusCodeString)
{
if (statusCode == SipResponseLayer::SipStatusCodeUnknown)
{
m_Exception.setMessage("Status code supplied was SipStatusCodeUnknown");
throw m_Exception;
}
if (version == "")
{
m_Exception.setMessage("Version supplied was unknown");
throw m_Exception;
}
m_SipResponse = sipResponse;
m_StatusCode = statusCode;
m_Version = version;
char statusCodeAsString[4];
snprintf (statusCodeAsString, sizeof(statusCodeAsString), "%d",StatusCodeEnumToInt[m_StatusCode]);
if (statusCodeString == "")
statusCodeString = StatusCodeEnumToString[m_StatusCode];
std::string firstLine = m_Version + " " + std::string(statusCodeAsString) + " " + statusCodeString + "\r\n";
m_FirstLineEndOffset = firstLine.length();
m_SipResponse->m_DataLen = firstLine.length();
m_SipResponse->m_Data = new uint8_t[m_SipResponse->m_DataLen];
memcpy(m_SipResponse->m_Data, firstLine.c_str(), m_SipResponse->m_DataLen);
m_IsComplete = true;
}
std::string SipResponseFirstLine::parseVersion(char* data, size_t dataLen)
{
if (dataLen < 7) // "SIP/x.y"
{
LOG_DEBUG("SIP response length < 7, cannot identify version");
return "";
}
if (data[0] != 'S' || data[1] != 'I' || data[2] != 'P' || data[3] != '/')
{
LOG_DEBUG("SIP response does not begin with 'SIP/'");
return "";
}
char* nextSpace = strchr(data, ' ');
if (nextSpace - data > (int)dataLen)
return "";
return std::string(data, nextSpace - data);
}
}