Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

610 lines
17 KiB

#include "precomp.h"
SIP_MESSAGE::SIP_MESSAGE()
{
ZeroMemory( this, sizeof SIP_MESSAGE );
InitializeListHead(&m_HeaderList);
ParseState = SIP_PARSE_STATE_INIT;
}
SIP_MESSAGE::~SIP_MESSAGE()
{
if (CSeqMethodStr != NULL)
{
free(CSeqMethodStr);
}
FreeHeaderList();
}
void SIP_MESSAGE::Reset()
{
ParseState = SIP_PARSE_STATE_INIT;
BaseBuffer = NULL;
ContentLengthSpecified = FALSE;
MsgBody.Offset = 0;
MsgBody.Length = 0;
FreeHeaderList();
}
// Both do essentially the same thing.
#define InsertBeforeListElement(ListElement, NewElement) \
InsertTailList(ListElement, NewElement)
HRESULT SIP_MESSAGE::AddHeader(
IN OFFSET_STRING *pHeaderName,
IN SIP_HEADER_ENUM HeaderId,
IN OFFSET_STRING *pHeaderValue
)
{
HRESULT hr;
SIP_HEADER_ENTRY *pNewHeaderEntry = new SIP_HEADER_ENTRY;
if (pNewHeaderEntry == NULL)
{
return E_OUTOFMEMORY;
}
pNewHeaderEntry->HeaderName = *pHeaderName;
pNewHeaderEntry->HeaderId = HeaderId;
pNewHeaderEntry->HeaderValue = *pHeaderValue;
LIST_ENTRY *pListEntry;
SIP_HEADER_ENTRY *pHeaderEntry;
pListEntry = m_HeaderList.Flink;
while (pListEntry != &m_HeaderList)
{
pHeaderEntry = CONTAINING_RECORD(pListEntry,
SIP_HEADER_ENTRY,
ListEntry);
// Do an unsigned comparsion so that unknown headers
// are pushed to the end.
if ((ULONG)HeaderId < (ULONG)pHeaderEntry->HeaderId)
{
break;
}
pListEntry = pListEntry->Flink;
}
// Insert before the tail or the element we found with a greater HeaderId
InsertBeforeListElement(pListEntry, &pNewHeaderEntry->ListEntry);
return S_OK;
}
VOID SIP_MESSAGE::FreeHeaderList()
{
LIST_ENTRY *pListEntry;
SIP_HEADER_ENTRY *pHeaderEntry;
while (!IsListEmpty(&m_HeaderList))
{
pListEntry = RemoveHeadList(&m_HeaderList);
pHeaderEntry = CONTAINING_RECORD(pListEntry,
SIP_HEADER_ENTRY,
ListEntry);
delete pHeaderEntry;
}
}
HRESULT
SIP_MESSAGE::StoreCallId()
{
SIP_HEADER_ENTRY *pHeaderEntry;
ULONG NumHeaders;
HRESULT hr;
ENTER_FUNCTION("SIP_MESSAGE::StoreCallId");
hr = GetHeader(SIP_HEADER_CALL_ID, &pHeaderEntry, &NumHeaders);
if (hr != S_OK)
{
LOG((RTC_ERROR, "%s Couldn't find Call-Id header %x",
__fxName, hr));
return hr;
}
else if (NumHeaders != 1)
{
LOG((RTC_ERROR, "%s More than one Call-Id header in message",
__fxName));
return E_FAIL;
}
CallId = pHeaderEntry->HeaderValue;
return S_OK;
}
HRESULT
SIP_MESSAGE::StoreCSeq()
{
HRESULT hr;
PSTR CSeqHeader;
ULONG CSeqHeaderLen;
ULONG BytesParsed = 0;
ENTER_FUNCTION("SIP_MESSAGE::StoreCSeq");
hr = GetSingleHeader(SIP_HEADER_CSEQ, &CSeqHeader, &CSeqHeaderLen);
if (hr != S_OK)
{
LOG((RTC_ERROR, "%s Couldn't find CSeq header %x",
__fxName, hr));
return hr;
}
hr = ParseCSeq(CSeqHeader, CSeqHeaderLen, &BytesParsed,
&CSeq, &CSeqMethodId, &CSeqMethodStr);
if (hr != S_OK)
{
LOG((RTC_ERROR, "%s Parsing CSeq header failed %x",
__fxName, hr));
return hr;
}
// check for unknown method id also that both the strings
// for the method are the same.
if (MsgType == SIP_MESSAGE_TYPE_REQUEST &&
Request.MethodId != CSeqMethodId)
{
LOG((RTC_ERROR, "%s Request Method Id doesn't match CSeq method Id",
__fxName));
return E_FAIL;
}
return S_OK;
}
// Also checks whether the Content-Type is "application/sdp"
HRESULT
SIP_MESSAGE::GetSDPBody(
OUT PSTR *pSDPBody,
OUT ULONG *pSDPBodyLen
)
{
HRESULT hr;
PSTR ContentTypeHdrValue;
ULONG ContentTypeHdrValueLen;
ENTER_FUNCTION("SIP_MESSAGE::GetSDPBody");
if (MsgBody.Length == 0)
{
*pSDPBody = NULL;
*pSDPBodyLen = 0;
return S_OK;
}
// We have Message Body. Check type.
hr = GetSingleHeader(SIP_HEADER_CONTENT_TYPE,
&ContentTypeHdrValue,
&ContentTypeHdrValueLen);
if (hr != S_OK)
{
LOG((RTC_ERROR, "%s - couldn't find Content-Type header",
__fxName));
return E_FAIL;
}
if (IsContentTypeSdp(ContentTypeHdrValue, ContentTypeHdrValueLen))
{
*pSDPBody = MsgBody.GetString(BaseBuffer);
*pSDPBodyLen = MsgBody.Length;
return S_OK;
}
else
{
LOG((RTC_ERROR, "%s - invalid Content-Type %.*s",
__fxName, ContentTypeHdrValueLen, ContentTypeHdrValue));
return E_FAIL;
}
}
// Returns the number of headers if there are multiple headers.
// Should we store the headers in sorted order and do a binary
// search.
// All the headers with the same header name are stored consecutively.
HRESULT SIP_MESSAGE::GetHeader(
IN SIP_HEADER_ENUM HeaderId,
OUT SIP_HEADER_ENTRY **ppHeaderEntry,
OUT ULONG *pNumHeaders
)
{
LIST_ENTRY *pListEntry;
SIP_HEADER_ENTRY *pHeaderEntry;
*ppHeaderEntry = NULL;
*pNumHeaders = 0;
pListEntry = m_HeaderList.Flink;
while (pListEntry != &m_HeaderList)
{
pHeaderEntry = CONTAINING_RECORD(pListEntry,
SIP_HEADER_ENTRY,
ListEntry);
if (HeaderId == pHeaderEntry->HeaderId)
{
*ppHeaderEntry = pHeaderEntry;
while (pListEntry != &m_HeaderList &&
HeaderId == pHeaderEntry->HeaderId)
{
(*pNumHeaders)++;
pListEntry = pListEntry->Flink;
pHeaderEntry = CONTAINING_RECORD(pListEntry,
SIP_HEADER_ENTRY,
ListEntry);
}
return S_OK;
}
pListEntry = pListEntry->Flink;
}
return RTC_E_SIP_HEADER_NOT_PRESENT;
}
// Can be used to get headers such as From, To, CallId,
// which are guaranteed to have just one header (unlike Via, Contact)
HRESULT
SIP_MESSAGE::GetSingleHeader(
IN SIP_HEADER_ENUM HeaderId,
OUT PSTR *pHeaderValue,
OUT ULONG *pHeaderValueLen
)
{
SIP_HEADER_ENTRY *pHeaderEntry;
ULONG NumHeaders;
HRESULT hr;
ENTER_FUNCTION("SIP_MESSAGE::GetSingleHeader");
hr = GetHeader(HeaderId, &pHeaderEntry, &NumHeaders);
if (hr != S_OK)
{
return hr;
}
else if (NumHeaders != 1)
{
LOG((RTC_ERROR, "%s - more than one header : %d",
__fxName, NumHeaders));
return E_FAIL;
}
*pHeaderValueLen = pHeaderEntry->HeaderValue.Length;
*pHeaderValue = pHeaderEntry->HeaderValue.GetString(BaseBuffer);
return S_OK;
}
// Same as GetSingleHeader() except that it could be used
// to get for headers such as Contact which could have multiple
// headers in a message. This function is called if we only care
// about processing the first header.
HRESULT
SIP_MESSAGE::GetFirstHeader(
IN SIP_HEADER_ENUM HeaderId,
OUT PSTR *pHeaderValue,
OUT ULONG *pHeaderValueLen
)
{
SIP_HEADER_ENTRY *pHeaderEntry;
ULONG NumHeaders;
HRESULT hr;
hr = GetHeader(HeaderId, &pHeaderEntry, &NumHeaders);
if (hr != S_OK)
{
return hr;
}
*pHeaderValueLen = pHeaderEntry->HeaderValue.Length;
*pHeaderValue = pHeaderEntry->HeaderValue.GetString(BaseBuffer);
return S_OK;
}
HRESULT
SIP_MESSAGE::GetStoredMultipleHeaders(
IN SIP_HEADER_ENUM HeaderId,
OUT COUNTED_STRING **pStringArray,
OUT ULONG *pNumHeaders
)
{
LIST_ENTRY *pListEntry;
SIP_HEADER_ENTRY *pHeaderEntry;
ULONG NumHeaders = 0;
COUNTED_STRING *StringArray;
HRESULT hr;
ULONG i;
*pStringArray = NULL;
*pNumHeaders = 0;
hr = GetHeader(HeaderId, &pHeaderEntry, &NumHeaders);
if (hr != S_OK)
{
return hr;
}
StringArray = (COUNTED_STRING *) malloc(NumHeaders * sizeof(COUNTED_STRING));
if (StringArray == NULL)
return E_OUTOFMEMORY;
ZeroMemory(StringArray, NumHeaders * sizeof(COUNTED_STRING));
pListEntry = (LIST_ENTRY *)
(pHeaderEntry + FIELD_OFFSET(SIP_HEADER_ENTRY, ListEntry));
for (i = 0; i < NumHeaders; i++)
{
PSTR HeaderValue;
ULONG HeaderLen;
pHeaderEntry = CONTAINING_RECORD(pListEntry,
SIP_HEADER_ENTRY,
ListEntry);
HeaderLen = pHeaderEntry->HeaderValue.Length;
HeaderValue = pHeaderEntry->HeaderValue.GetString(BaseBuffer);
StringArray[i].Buffer = (PSTR) malloc(HeaderLen + 1);
if (StringArray[i].Buffer == NULL)
{
hr = E_OUTOFMEMORY;
goto error;
}
strncpy(StringArray[i].Buffer, HeaderValue, HeaderLen);
StringArray[i].Buffer[HeaderLen] = '\0';
StringArray[i].Length = HeaderLen;
pListEntry = pListEntry->Flink;
}
*pNumHeaders = NumHeaders;
*pStringArray = StringArray;
return S_OK;
error:
if (StringArray != NULL)
{
for (i = 0; i < NumHeaders; i++)
{
if (StringArray[i].Buffer != NULL)
free(StringArray[i].Buffer);
}
free(StringArray);
}
return hr;
}
// The list should be sorted descending using QValue.
HRESULT
SIP_MESSAGE::InsertInContactHeaderList(
IN OUT LIST_ENTRY *pContactHeaderList,
IN CONTACT_HEADER *pNewContactHeader
)
{
LIST_ENTRY *pListEntry;
CONTACT_HEADER *pContactHeader;
pListEntry = pContactHeaderList->Flink;
while (pListEntry != pContactHeaderList)
{
pContactHeader = CONTAINING_RECORD(pListEntry,
CONTACT_HEADER,
m_ListEntry);
// Do an unsigned comparsion so that unknown headers
// are pushed to the end.
if (pNewContactHeader->m_QValue > pContactHeader->m_QValue)
{
break;
}
pListEntry = pListEntry->Flink;
}
// Insert before the tail or the element we found with a greater HeaderId
InsertBeforeListElement(pListEntry, &pNewContactHeader->m_ListEntry);
return S_OK;
}
// pContactHeaderList is the list head. This routine will parse all
// the contact headers into CONTACT_HEADER structures
// (allocated using new) and will add those structures to this
// list. The caller delete the structures when cleaning up the list.
// This function assumes that InitializeListHead() has been called
// earlier on pContactHeaderList.
// The list should be sorted using QValue.
HRESULT
SIP_MESSAGE::ParseContactHeaders(
OUT LIST_ENTRY *pContactHeaderList
)
{
HRESULT hr;
LIST_ENTRY *pListEntry;
SIP_HEADER_ENTRY *pHeaderEntry;
CONTACT_HEADER *pContactHeader;
ULONG NumHeaders = 0;
ULONG i;
ULONG BytesParsed;
PSTR HeaderValue;
ULONG HeaderLen;
ASSERT(IsListEmpty(pContactHeaderList));
ENTER_FUNCTION("SIP_MESSAGE::ParseContactHeaders");
hr = GetHeader(SIP_HEADER_CONTACT, &pHeaderEntry, &NumHeaders);
if (hr != S_OK)
{
LOG((RTC_ERROR, "%s Couldn't find Contact header in msg %x",
__fxName, hr));
return hr;
}
pListEntry = (LIST_ENTRY *)
(pHeaderEntry + FIELD_OFFSET(SIP_HEADER_ENTRY, ListEntry));
for (i = 0; i < NumHeaders; i++)
{
pHeaderEntry = CONTAINING_RECORD(pListEntry,
SIP_HEADER_ENTRY,
ListEntry);
HeaderLen = pHeaderEntry->HeaderValue.Length;
HeaderValue = pHeaderEntry->HeaderValue.GetString(BaseBuffer);
BytesParsed = 0;
while (BytesParsed < HeaderLen)
{
pContactHeader = new CONTACT_HEADER;
if (pContactHeader == NULL)
{
LOG((RTC_ERROR, "%s allocating pContactHeader failed",
__fxName));
FreeContactHeaderList(pContactHeaderList);
return E_OUTOFMEMORY;
}
ZeroMemory( pContactHeader, sizeof(CONTACT_HEADER) );
hr = ParseContactHeader(HeaderValue, HeaderLen, &BytesParsed,
pContactHeader);
if (hr != S_OK)
{
// If parsing a contact header fails we just skip it.
delete pContactHeader;
LOG((RTC_ERROR,
"%s ParseContactHeader failed: %x - skipping Contact header %.*s",
__fxName, hr, HeaderLen, HeaderValue));
break;
}
InsertInContactHeaderList(pContactHeaderList, pContactHeader);
}
pListEntry = pListEntry->Flink;
}
if (IsListEmpty(pContactHeaderList))
{
LOG((RTC_ERROR, "%s - no valid Contact headers returning hr: %x",
__fxName, hr));
return hr;
}
return S_OK;
}
// pRecordRouteHeaderList is the list head. This routine will parse
// all the Record-Route headers into RECORD_ROUTE_HEADER structures
// (allocated using new) and will add those structures to this
// list. The caller delete the structures when cleaning up the list.
// This function assumes that InitializeListHead() has been
// called earlier on pRecordRouteHeaderList.
// The headers are in the order they appear in the message.
HRESULT
SIP_MESSAGE::ParseRecordRouteHeaders(
OUT LIST_ENTRY *pRecordRouteHeaderList
)
{
HRESULT hr;
LIST_ENTRY *pListEntry;
SIP_HEADER_ENTRY *pHeaderEntry;
RECORD_ROUTE_HEADER *pRecordRouteHeader;
ULONG NumHeaders = 0;
ULONG i;
ULONG BytesParsed;
PSTR HeaderValue;
ULONG HeaderLen;
ENTER_FUNCTION("SIP_MESSAGE::ParseRecordRouteHeaders");
hr = GetHeader(SIP_HEADER_RECORD_ROUTE, &pHeaderEntry, &NumHeaders);
if (hr != S_OK)
{
LOG((RTC_TRACE, "%s Couldn't find Record-Route header in msg %x",
__fxName, hr));
return hr;
}
pListEntry = (LIST_ENTRY *)
(pHeaderEntry + FIELD_OFFSET(SIP_HEADER_ENTRY, ListEntry));
for (i = 0; i < NumHeaders; i++)
{
pHeaderEntry = CONTAINING_RECORD(pListEntry,
SIP_HEADER_ENTRY,
ListEntry);
HeaderLen = pHeaderEntry->HeaderValue.Length;
HeaderValue = pHeaderEntry->HeaderValue.GetString(BaseBuffer);
BytesParsed = 0;
while (BytesParsed < HeaderLen)
{
pRecordRouteHeader = new RECORD_ROUTE_HEADER();
if (pRecordRouteHeader == NULL)
{
LOG((RTC_ERROR, "%s allocating pContactHeader failed",
__fxName));
return E_OUTOFMEMORY;
}
hr = ParseRecordRouteHeader(HeaderValue, HeaderLen, &BytesParsed,
pRecordRouteHeader);
if (hr != S_OK)
{
delete pRecordRouteHeader;
LOG((RTC_ERROR, "%s ParseRecordRouteHeader failed: %x",
__fxName, hr));
return hr;
}
InsertTailList(pRecordRouteHeaderList,
&pRecordRouteHeader->m_ListEntry);
}
pListEntry = pListEntry->Flink;
}
return S_OK;
}