|
|
/*++
Copyright (c) 1999 - 2000 Microsoft Corporation
Module Name:
parser.c
Abstract:
This module encode and decode ssdp notify and search messages.
Author:
Ting Cai (tingcai) creation-date-07-25-99
--*/
/* Note:
Use midl memory routines for SSDP_REQUEST
*/
#include <pch.h>
#pragma hdrstop
#include "ssdpparserp.h"
#include "ssdpapi.h"
#include "limits.h"
#include "ncstring.h"
#define HTTP_VERSION "HTTP/1.1"
#define END_HEADERS_SIZE 3
const char * szEndOfHeaders = "\n\r\n";
#define HEADER_END_SIZE 4
const char * szHeaderEnd = "\r\n\r\n";
BOOL IsStrDigits(LPSTR pszStr); VOID strtrim(CHAR ** pszStr);
static const CHAR c_szMaxAge[] = "max-age"; static const DWORD c_cchMaxAge = celems(c_szMaxAge) - 1;
// Keep in sync with SSDP_METHOD in ssdp.idl
CHAR *SsdpMethodStr[] = { "NOTIFY", "M-SEARCH", "SUBSCRIBE", "UNSUBSCRIBE", "INVALID", };
// Keep in sync with SSDP_HEADER in ssdp.idl
CHAR *SsdpHeaderStr[] = { "Host", "NT", "NTS", "ST", "Man", "MX", "Location", "AL", "USN", "Cache-Control", "Callback", "Timeout", "Scope", "SID", "SEQ", "Content-Length", "Content-Type", "Server", "Ext", }; /*
NOTIFY * HTTP/1.1 Host: reservedSSDPmulticastaddress NT: blenderassociation:blender NTS: ssdp:alive USN: someunique:idscheme3 AL: <blender:ixl><http://foo/bar>
Cache-Control: max-age = 7393
To-do: HTTP headers are all ascii, the API may accept unicode, but convert to ascii before calling the rpc interface. The server keeps ascii version only.
To-do: Support arbitrary content.
*/
// Compose an SSDP alive message from the a SSDP Message structure, caller should
// free the memory when done.
BOOL ComposeSsdpResponse(const SSDP_REQUEST *Source, CHAR **pszBytes) { CHAR ResponseHeader[40] = "HTTP/1.1 200 OK"; INT iLength = 0; INT iNumOfBytes = 0; CHAR * szBytes; INT i;
iLength = strlen(ResponseHeader) + strlen(CRLF);
if (Source->Headers[SSDP_NT] != NULL) { iLength += strlen(SsdpHeaderStr[SSDP_ST]) + strlen(COLON) + strlen(Source->Headers[SSDP_NT]) + strlen(CRLF); }
if (Source->Headers[SSDP_LOCATION] != NULL) { iLength += strlen(SsdpHeaderStr[SSDP_LOCATION]) + strlen(COLON) + strlen(Source->Headers[SSDP_LOCATION]) + strlen(CRLF); }
if (Source->Headers[SSDP_AL] != NULL) { iLength += strlen(SsdpHeaderStr[SSDP_AL]) + strlen(COLON) + strlen(Source->Headers[SSDP_AL]) + strlen(CRLF); } if (Source->Headers[SSDP_USN] != NULL) { iLength += strlen(SsdpHeaderStr[SSDP_USN]) + strlen(COLON) + strlen(Source->Headers[SSDP_USN]) + strlen(CRLF); }
if (Source->Headers[SSDP_CACHECONTROL] != NULL) { iLength += strlen(SsdpHeaderStr[SSDP_CACHECONTROL]) + strlen(COLON) + strlen(Source->Headers[SSDP_CACHECONTROL]) + strlen(CRLF); }
if (Source->Headers[GENA_SID] != NULL) { iLength += strlen(SsdpHeaderStr[GENA_SID]) + strlen(COLON) + strlen(Source->Headers[GENA_SID]) + strlen(CRLF); }
if (Source->Headers[GENA_TIMEOUT] != NULL) { iLength += strlen(SsdpHeaderStr[GENA_TIMEOUT]) + strlen(COLON) + strlen(Source->Headers[GENA_TIMEOUT]) + strlen(CRLF); }
if (Source->Headers[SSDP_SERVER] != NULL) { iLength += strlen(SsdpHeaderStr[SSDP_SERVER]) + strlen(COLON) + strlen(Source->Headers[SSDP_SERVER]) + strlen(CRLF); }
if (Source->Headers[SSDP_EXT] != NULL) { iLength += strlen(SsdpHeaderStr[SSDP_EXT]) + strlen(COLON) + strlen(Source->Headers[SSDP_EXT]) + strlen(CRLF); }
iLength += strlen(CRLF);
szBytes = (CHAR *) midl_user_allocate(sizeof(CHAR) * iLength + 1);
if (szBytes == NULL) { TraceTag(ttidSsdpParser, "Faled to allocate memory for the ssdp message."); return FALSE; }
iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s%s", ResponseHeader, CRLF);
if (Source->Headers[SSDP_NT] != NULL) { iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s%s%s%s", SsdpHeaderStr[SSDP_ST], COLON, Source->Headers[SSDP_NT],CRLF); }
if (Source->Headers[SSDP_USN] != NULL) { iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s%s%s%s", SsdpHeaderStr[SSDP_USN], COLON, Source->Headers[SSDP_USN],CRLF); }
if (Source->Headers[SSDP_LOCATION] != NULL) { iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s%s%s%s", SsdpHeaderStr[SSDP_LOCATION], COLON, Source->Headers[SSDP_LOCATION],CRLF); }
if (Source->Headers[SSDP_AL] != NULL) { iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s%s%s%s", SsdpHeaderStr[SSDP_AL], COLON, Source->Headers[SSDP_AL],CRLF); }
if (Source->Headers[SSDP_CACHECONTROL] != NULL) { iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s%s%s%s", SsdpHeaderStr[SSDP_CACHECONTROL], COLON, Source->Headers[SSDP_CACHECONTROL],CRLF); }
if (Source->Headers[GENA_SID] != NULL) { iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s%s%s%s", SsdpHeaderStr[GENA_SID], COLON, Source->Headers[GENA_SID],CRLF); }
if (Source->Headers[GENA_TIMEOUT] != NULL) { iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s%s%s%s", SsdpHeaderStr[GENA_TIMEOUT], COLON, Source->Headers[GENA_TIMEOUT],CRLF); }
if (Source->Headers[SSDP_SERVER] != NULL) { iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s%s%s%s", SsdpHeaderStr[SSDP_SERVER], COLON, Source->Headers[SSDP_SERVER],CRLF); }
if (Source->Headers[SSDP_EXT] != NULL) { iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s%s%s%s", SsdpHeaderStr[SSDP_EXT], COLON, Source->Headers[SSDP_EXT],CRLF); }
iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s",CRLF);
*pszBytes = szBytes;
return TRUE; }
// To-do: optimize, cache does not care about the request/response line
BOOL ComposeSsdpRequest(const SSDP_REQUEST *Source, CHAR **pszBytes) { INT iLength = 0; INT iNumOfBytes = 0; CHAR iLifeTime[10]; CHAR * szBytes; INT i;
if (Source->Method != SSDP_INVALID && Source->RequestUri != NULL) { iLength += strlen(SsdpMethodStr[Source->Method]) + strlen(SP) + strlen(Source->RequestUri) + strlen(SP) + strlen(HTTP_VERSION) + strlen(CRLF); }
for (i = 0; i < NUM_OF_HEADERS; i++) { if (Source->Headers[i] != NULL) { iLength += strlen(SsdpHeaderStr[i]) + strlen(COLON) + strlen(Source->Headers[i]) + strlen(CRLF); } }
iLength += strlen(CRLF);
szBytes = (CHAR *) malloc(sizeof(CHAR) * iLength + 1);
if (szBytes == NULL) { TraceTag(ttidSsdpParser, "Faled to allocate memory for the ssdp message."); return FALSE; }
if (Source->Method != SSDP_INVALID && Source->RequestUri != NULL) { iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s%s%s%s%s%s", SsdpMethodStr[Source->Method], SP, Source->RequestUri, SP, HTTP_VERSION, CRLF); }
for (i = 0; i < NUM_OF_HEADERS; i++) { if (Source->Headers[i] != NULL) { iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s%s%s%s", SsdpHeaderStr[i], COLON, Source->Headers[i],CRLF); } }
iNumOfBytes += wsprintf(szBytes + iNumOfBytes, "%s",CRLF);
*pszBytes = szBytes;
return TRUE; }
BOOL FReplaceTokenInLocation(LPCSTR szIn, LPSTR szReplace, LPSTR *pszOut) { CHAR * pch;
Assert(pszOut);
*pszOut = NULL;
if (pch = strstr(szIn, c_szReplaceGuid)) { LPSTR szOut; DWORD cbOut;
cbOut = (lstrlen(szIn) - c_cchReplaceGuid + lstrlen(szReplace) + 1) * sizeof(CHAR);
szOut = (LPSTR)malloc(cbOut); if (szOut) { lstrcpyn(szOut, szIn, (int)(pch - szIn + 1)); lstrcat(szOut, szReplace);
pch += c_cchReplaceGuid;
lstrcat(szOut, pch);
*pszOut = szOut; } else { return FALSE; }
}
return TRUE; }
// Pre-Conditions:
// Result->Headers[CONTENT_LENGTH] contains only digits.
// pContent points to the first char "\r\n\r\n".
// Return szValue:
// returns FALSE if there not enough content.
BOOL ParseContent(const char *pContent, DWORD cbContent, SSDP_REQUEST *Result) { if(!Result->Headers[CONTENT_LENGTH]) { return TRUE; }
DWORD dwContentLength = strtoul(Result->Headers[CONTENT_LENGTH], NULL, 10); if (dwContentLength == 0) { // If it can't be conver to a number or it is 0.
TraceTag(ttidSsdpParser, "Content-Length is 0."); return TRUE; } else if ((cbContent == (DWORD)(-1)) || (cbContent == dwContentLength)) { Result->Content = (CHAR*) midl_user_allocate(dwContentLength + 1); if (Result->Content == NULL) { TraceTag(ttidSsdpParser, "Failed to allocate memory for Content"); return FALSE; } else { lstrcpyn(Result->Content,pContent, dwContentLength + 1);
return TRUE; } }
return FALSE; }
CHAR * ParseRequestLine(CHAR * szMessage, SSDP_REQUEST *Result) { CHAR *token; INT i;
Assert(NULL != szMessage); // Make sure we don't go past the end of the buffer
CHAR * pchEnd = szMessage + lstrlen(szMessage);
// Get the HTTP method
token = strtok(szMessage," \t\n"); if (token == NULL) { TraceTag(ttidSsdpParser, "Parser could not locate the seperator, " "space, tab or eol"); return NULL; }
for (i = 0; i < NUM_OF_METHODS; i++) { if (_stricmp(SsdpMethodStr[i],token) == 0) { Result->Method = (SSDP_METHOD)i; break; } }
if (i == NUM_OF_METHODS) { TraceTag(ttidSsdpParser, "Parser could not find method . " "Received %s", token); return NULL; }
// Get the Request-URI
token = strtok(NULL," "); if (token == NULL) { TraceTag(ttidSsdpParser, "Parser could not find the url in the " "message."); return NULL; }
// Ingore the name space parsing for now, get the string after the last '/'.
Result->RequestUri = (CHAR*) midl_user_allocate(strlen(token) + 1);
if (Result->RequestUri == NULL) { TraceTag(ttidSsdpParser, "Parser could not allocate memory for url."); return NULL; }
// Record the service.
strcpy(Result->RequestUri, token);
// Get the version number
token = strtok(NULL," \t\r");
// To-Do: Record the version number when necessary.
if (token == NULL) { TraceTag(ttidSsdpParser, "Failed to get the version in the request " "header."); FreeSsdpRequest(Result); return NULL; }
if (_stricmp(token, "HTTP/1.1") != 0) { TraceTag(ttidSsdpParser, "The version specified in the request " "message is not HTTP/1.1"); FreeSsdpRequest(Result); return NULL; }
// point to the rest of the header data, after the current token
token += lstrlen(token) + 1; if (token >= pchEnd) { TraceTag(ttidSsdpParser, "no data following HTTP/1.1 in the request"); FreeSsdpRequest(Result); return NULL; } return token; }
BOOL VerifySsdpHeaders(SSDP_REQUEST *Result) { if (Result->Method == SSDP_M_SEARCH) { if (Result->Headers[SSDP_ST] == NULL || Result->Headers[SSDP_MX] == NULL || *Result->Headers[SSDP_MX] == L'\0' || *Result->Headers[SSDP_ST] == L'\0') { TraceTag(ttidSsdpParser, "ST and MX header should not be NULL for M-SEARCH"); return FALSE; }
if (Result->Headers[SSDP_MAN] == NULL || lstrcmpi(Result->Headers[SSDP_MAN], "\"ssdp:discover\"")) { TraceTag(ttidSsdpParser, "MAN header for M-SEARCH must be \"ssdp:discover\""); return FALSE; }
if (Result->Headers[SSDP_HOST] == NULL || lstrcmpi(Result->Headers[SSDP_HOST], SSDP_ADDR_PORT)) { TraceTag(ttidSsdpParser, "HOST must be 239.255.255.250:1900" "for n M-SEARCH message."); return FALSE; } }
if (Result->Headers[SSDP_MX] != NULL && IsStrDigits(Result->Headers[SSDP_MX]) == FALSE) { TraceTag(ttidSsdpParser, "MX header should be all digits"); return FALSE; }
if (Result->Method == SSDP_NOTIFY) { if (Result->Headers[SSDP_NT] == NULL || Result->Headers[SSDP_NTS] == NULL) { TraceTag(ttidSsdpParser, "NT and NTS headers should not be NULL for a NOTIFY message."); return FALSE; }
// Assume NOTIFY other than upnp:propchange requires USN header.
// Currently, ssdp:alive and ssdp:byebye
if (lstrcmpi(Result->Headers[SSDP_NTS], "upnp:propchange")) { if (Result->Headers[SSDP_USN] == NULL) { TraceTag(ttidSsdpParser, "USN headers should not be NULL for " "a NOTIFY message."); return FALSE; }
if (!lstrcmpi(Result->Headers[SSDP_NTS], "ssdp:alive")) { // ssdp:alive messages must have a location header
if (Result->Headers[SSDP_LOCATION] == NULL) { TraceTag(ttidSsdpParser, "LOCATION header can not be NULL " "for a NOTIFY message."); return FALSE; }
// ssdp:alive messages must have a SERVER header
if (Result->Headers[SSDP_SERVER] == NULL) { TraceTag(ttidSsdpParser, "SERVER header can not be NULL " "for a NOTIFY message."); return FALSE; } if (Result->Headers[SSDP_HOST] == NULL || lstrcmpi(Result->Headers[SSDP_HOST], SSDP_ADDR_PORT)) { TraceTag(ttidSsdpParser, "HOST must be 239.255.255.250:1900" "for a NOTIFY message."); return FALSE; } } else if (!lstrcmpi(Result->Headers[SSDP_NTS], "ssdp:byebye")) { if (Result->Headers[SSDP_HOST] == NULL || lstrcmpi(Result->Headers[SSDP_HOST], SSDP_ADDR_PORT)) { TraceTag(ttidSsdpParser, "HOST must be 239.255.255.250:1900" "for a NOTIFY message."); return FALSE; } } } }
if (Result->Headers[CONTENT_LENGTH] != NULL && IsStrDigits(Result->Headers[CONTENT_LENGTH]) == FALSE ) { TraceTag(ttidSsdpParser, "Content length header should be all digits"); return FALSE; }
return TRUE; }
BOOL HasContentBody(PSSDP_REQUEST Result) { return (Result->Headers[CONTENT_LENGTH] != NULL); }
BOOL ParseSsdpRequest(CHAR * szMessage, PSSDP_REQUEST Result) { CHAR *szHeaders;
szHeaders = ParseRequestLine(szMessage, Result);
if (szHeaders == NULL) { return FALSE; }
char *pContent = ParseHeaders(szHeaders, Result); if ( pContent == NULL) { return FALSE; } else { if (VerifySsdpHeaders(Result) == FALSE) { return FALSE; }
// Headers are OK.
if (Result->Headers[CONTENT_LENGTH] != NULL) { // To-Do: Maybe we can share the this routine with those
// in ProcessTcpReceiveData();
// In that case, we need catch the return szValue of ParseContent
// and probably return a more meaningful error code.
ParseContent(pContent, (DWORD)(-1), Result); } return TRUE; } }
// Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
// Returns a pointer to the first CHAR after the status line
// Returns NULL if fail to parse status line
BOOL ParseSsdpResponse(CHAR *szMessage, SSDP_REQUEST *Result) { CHAR *token; CHAR *szHeaders;
Assert(NULL != szMessage);
// Make sure we don't go past the end of the buffer
CHAR * pchEnd = szMessage + lstrlen(szMessage);
// get the version
token = strtok(szMessage," \t\n"); if (token == NULL) { TraceTag(ttidSsdpParser, "Response: Parser could not locate the " "seperator, space, tab or eol"); return FALSE; }
if (_stricmp(token, "HTTP/1.1") != 0) { TraceTag(ttidSsdpParser, "The version specified in the response " "message is not HTTP/1.1"); return FALSE; }
// get the response code
token = strtok(NULL," "); if (token == NULL) { TraceTag(ttidSsdpParser, "Parser could not find the url in the " "message."); return FALSE; }
if (_stricmp(token, "200") != 0) { TraceTag(ttidSsdpParser, "The response code in the response message " "is not HTTP/1.1"); return FALSE; }
// get the response message, no need for now.
token = strtok(NULL," \t\r");
if (token == NULL) { TraceTag(ttidSsdpParser, "Failed to get the version in the request " "header."); return FALSE; }
szHeaders = token + strlen(token) + 1; if (szHeaders >= pchEnd) { TraceTag(ttidSsdpParser, "no data following HTTP/1.1 200 in the request"); return FALSE; }
char *pContent = ParseHeaders(szHeaders, Result);
if (pContent == NULL || Result->Headers[SSDP_USN] == NULL) { return FALSE; } else { if (Result->Headers[CONTENT_LENGTH] != NULL) { ParseContent(pContent, (DWORD)(-1), Result); } return TRUE; } }
BOOL ParseCacheControlHeader(SSDP_REQUEST *Result) { if (Result->Headers[SSDP_CACHECONTROL]) { // Further parse the cache-control header
//
CHAR * szValue = strstr(Result->Headers[SSDP_CACHECONTROL], c_szMaxAge); if (szValue) { CHAR * szTemp = szValue + c_cchMaxAge;
strtrim(&szTemp); if (*szTemp != '=') { TraceTag(ttidSsdpParser, "Invalid max-age directive" " in cache-control header."); return FALSE; } else { szTemp++; memcpy(Result->Headers[SSDP_CACHECONTROL], c_szMaxAge, c_cchMaxAge); Result->Headers[SSDP_CACHECONTROL][c_cchMaxAge] = '=';
strtrim(&szTemp); szValue = szTemp; while (isdigit(*szTemp)) { szTemp++; } if (szTemp == szValue) { // no digits found
TraceTag(ttidSsdpParser, "Invalid max-age directive" " in cache-control header."); return FALSE; }
memcpy(Result->Headers[SSDP_CACHECONTROL] + c_cchMaxAge+1, szValue, (size_t)(szTemp - szValue));
// Nul term the string so the cache-control
// header should now be "max-age=398733" and
// nothing more or less
size_t cch = c_cchMaxAge + 1 + (szTemp - szValue); Result->Headers[SSDP_CACHECONTROL][cch] = 0; } } else { TraceTag(ttidSsdpParser, "Cache-control header" "did not include max-age directive."); return TRUE; } } return TRUE; }
char * ParseHeaders(CHAR *szMessage, SSDP_REQUEST *Result) { CHAR *token; INT i = NUM_OF_HEADERS; INT iPrevHeader = NUM_OF_HEADERS;
Assert(NULL != szMessage); if (NULL == strstr(szMessage, szHeaderEnd)) { TraceTag(ttidSsdpParser, "Invalid header - does not end with double CRLF"); return NULL; }
// Get the next header
token = strtok(szMessage, "\r\n");
while (token != NULL) { CHAR * pHeaderSep; // points to the ':' that seperates the header and its content.
CHAR * pHeaderCopy; CHAR * pBeyondTokenEnd;
pBeyondTokenEnd = token + strlen(token) + 1;
if ((*token == ' ' || *token == '\t') && iPrevHeader != NUM_OF_HEADERS) { // this is a continuation of the last line
strtrim(&token); if (Result->Headers[iPrevHeader]) { // we already have this header, so add this data to it.
CHAR* szTemp = (CHAR*)midl_user_allocate( sizeof(CHAR) * (strlen(token) + strlen(Result->Headers[iPrevHeader]) + 3)); if (szTemp) { strcpy(szTemp, Result->Headers[iPrevHeader]); strcat(szTemp, " "); strcat(szTemp, token); midl_user_free(Result->Headers[iPrevHeader]); Result->Headers[iPrevHeader] = szTemp; } else { TraceTag(ttidSsdpParser, "Failed to allocate memory " "for token %s", token); FreeSsdpRequest(Result); return NULL; }
} else { TraceTag(ttidSsdpParser, "Memory not already allocated for header %s", SsdpHeaderStr[iPrevHeader]); FreeSsdpRequest(Result); return NULL; }
} else { pHeaderSep = strchr( token, ':' ); if (pHeaderSep == NULL) { TraceTag(ttidSsdpParser, "Token %s does not have a ':', ignored.", token); } else { *pHeaderSep = '\0';
strtrim(&token);
// determine which header we are looking at
for (i = 0; i < NUM_OF_HEADERS; i++) { if (_stricmp(SsdpHeaderStr[i],token) == 0) break; }
if (i < NUM_OF_HEADERS) { CHAR *szValue;
szValue = pHeaderSep + 1; strtrim(&szValue);
if (Result->Headers[i]) { // we already have this header, so add this data to it.
CHAR* szTemp = (CHAR*)midl_user_allocate( sizeof(CHAR) * (strlen(szValue) + strlen(Result->Headers[i]) + 3)); if (szTemp) { strcpy(szTemp, Result->Headers[i]); strcat(szTemp, ", "); strcat(szTemp, szValue); midl_user_free(Result->Headers[i]); Result->Headers[i] = szTemp; } else { midl_user_free(Result->Headers[i]); Result->Headers[i] = NULL; } } else { Result->Headers[i] = (CHAR *) midl_user_allocate( sizeof(CHAR) * (strlen(szValue) + 1)); if (Result->Headers[i]) { strcpy(Result->Headers[i], szValue); } } if (Result->Headers[i] == NULL) { TraceTag(ttidSsdpParser, "Failed to allocate memory " "for szValue %s",szValue); FreeSsdpRequest(Result); return NULL; } } else { // Ignore not recognized header
TraceTag(ttidSsdpParser, "Token %s does not match any SSDP " "headers",token); } } }
// Get the next header
if (!strncmp(pBeyondTokenEnd, szEndOfHeaders, END_HEADERS_SIZE)) { // no more headers. parse what we have
if (!ParseCacheControlHeader(Result)) { FreeSsdpRequest(Result); return NULL; } return (pBeyondTokenEnd + END_HEADERS_SIZE); } else { token = strtok(NULL, "\r\n"); iPrevHeader = i; } }
// We should always have a "\r\n\r\n" in any legal message.
TraceTag(ttidSsdpParser, "Received message does not contain \\r\\n\\r\\n. Ignored. "); FreeSsdpRequest(Result);
return NULL; }
BOOL InitializeSsdpRequest(SSDP_REQUEST *pRequest) { INT i;
pRequest->Method = SSDP_INVALID; pRequest->RequestUri = NULL;
for (i = 0; i < NUM_OF_HEADERS; i++) { pRequest->Headers[i] = NULL; }
pRequest->ContentType = NULL;
pRequest->Content = NULL;
return TRUE; }
VOID FreeSsdpRequest(SSDP_REQUEST *pSsdpRequest) { INT i = 0;
if (pSsdpRequest->Content != NULL) { midl_user_free(pSsdpRequest->Content); pSsdpRequest->Content = NULL; }
if (pSsdpRequest->ContentType != NULL) { midl_user_free(pSsdpRequest->ContentType); pSsdpRequest->ContentType = NULL; }
if (pSsdpRequest->RequestUri != NULL) { midl_user_free(pSsdpRequest->RequestUri); pSsdpRequest->RequestUri = NULL; }
for (i = 0; i < NUM_OF_HEADERS; i++) { if (pSsdpRequest->Headers[i] != NULL) { midl_user_free(pSsdpRequest->Headers[i]); pSsdpRequest->Headers[i] = NULL; } } } // Get rid of leading or trailing white space or tab.
VOID PrintSsdpRequest(const SSDP_REQUEST *pssdpRequest) { INT i;
for (i = 0; i < NUM_OF_HEADERS; i++) { if (pssdpRequest->Headers[i] == NULL) { TraceTag(ttidSsdpParser, "%s = (NULL) ",SsdpHeaderStr[i], pssdpRequest->Headers[i]); } else { TraceTag(ttidSsdpParser, "%s = (%s) ",SsdpHeaderStr[i], pssdpRequest->Headers[i]); } } }
// Assume szValue does not have beginning or trailing spaces.
INT GetMaxAgeFromCacheControl(const CHAR *szValue) { CHAR * pEqual; _int64 Temp;
if (szValue == NULL) { return -1; }
pEqual = strchr(szValue, '='); if (pEqual == NULL) { return -1; }
Temp = _atoi64(pEqual+1);
if (Temp > UINT_MAX / 1000) {
TraceTag(ttidSsdpAnnounce, "Life time exceeded the UINT limit. " "Set to limit");
Temp = UINT_MAX; }
return (UINT)Temp; }
BOOL ConvertToByebyeNotify(PSSDP_REQUEST pSsdpRequest) { CHAR * szTemp = "ssdp:byebye";
free(pSsdpRequest->Headers[SSDP_NTS]); pSsdpRequest->Headers[SSDP_NTS] = NULL;
pSsdpRequest->Headers[SSDP_NTS] = SzaDupSza(szTemp);
if (pSsdpRequest->Headers[SSDP_NTS] == NULL) { return FALSE; } else { return TRUE; } }
BOOL ConvertToAliveNotify(PSSDP_REQUEST pSsdpRequest) { CHAR * szTemp = "ssdp:alive";
Assert(pSsdpRequest->Headers[SSDP_ST] != NULL); Assert(pSsdpRequest->Headers[SSDP_NTS] == NULL); pSsdpRequest->Headers[SSDP_NTS] = SzaDupSza(szTemp);
if (pSsdpRequest->Headers[SSDP_NTS] == NULL) { return FALSE; } else { pSsdpRequest->Headers[SSDP_NT] = pSsdpRequest->Headers[SSDP_ST]; pSsdpRequest->Headers[SSDP_ST] = NULL; return TRUE; } }
BOOL CompareSsdpRequest(const SSDP_REQUEST * pRequestA, const SSDP_REQUEST * pRequestB) { INT i;
for (i = 0; i < NUM_OF_HEADERS; i++) { if ((pRequestA->Headers[i] == NULL && pRequestB->Headers[i]!= NULL) || (pRequestA->Headers[i] != NULL && pRequestB->Headers[i]== NULL)) { return FALSE; } else if (pRequestA->Headers[i] != NULL && pRequestB->Headers[i] != NULL) { if (strcmp(pRequestA->Headers[i], pRequestB->Headers[i]) != 0) { TraceTag(ttidSsdpParser, "Different headers index %d",i); return FALSE; } } }
Assert(pRequestA->Content == NULL && pRequestB->Content == NULL);
Assert(pRequestA->ContentType == NULL && pRequestB->ContentType == NULL);
// We ignore Request URI, as they should always be * for alive and byebye.
return TRUE;
}
// Deep copy
BOOL CopySsdpRequest(PSSDP_REQUEST Destination, const SSDP_REQUEST * Source) { INT i;
ZeroMemory(Destination, sizeof(*Destination));
Destination->Method = Source->Method ;
for (i = 0; i < NUM_OF_HEADERS; i++) { if (Source->Headers[i] != NULL) { Destination->Headers[i] = (CHAR *) midl_user_allocate( strlen(Source->Headers[i]) + 1); if (Destination->Headers[i] == NULL) { goto cleanup; } else { strcpy(Destination->Headers[i], Source->Headers[i]); } } }
if (Source->Content != NULL) { Destination->Content = (CHAR *) midl_user_allocate( strlen(Source->Content) + 1); if (Destination->Content == NULL) { goto cleanup; } else { strcpy(Destination->Content, Source->Content); } }
if (Source->ContentType != NULL) { Destination->ContentType = (CHAR *) midl_user_allocate( strlen(Source->ContentType) + 1); if (Destination->ContentType == NULL) { goto cleanup; } else { strcpy(Destination->ContentType, Source->ContentType); } }
if (Source->RequestUri != NULL) { Destination->RequestUri = (CHAR *) midl_user_allocate( strlen(Source->RequestUri) + 1); if (Destination->RequestUri == NULL) { goto cleanup; } else { strcpy(Destination->RequestUri, Source->RequestUri); } }
Destination->guidInterface = Source->guidInterface;
return TRUE;
cleanup:
FreeSsdpRequest(Destination); return FALSE; }
BOOL IsStrDigits(LPSTR pszStr) { int i = 0; while (pszStr[i] != '\0') { if (isdigit(pszStr[i++]) == 0) { return FALSE; } }
return TRUE; } VOID strtrim(CHAR ** pszStr) {
CHAR *end; CHAR *begin;
// Empty string. Nothing to do.
//
if (!(**pszStr)) { return; }
begin = *pszStr; end = begin + strlen(*pszStr) - 1;
while (*begin == ' ' || *begin == '\t') { begin++; }
*pszStr = begin;
while ((end > begin) && (*end == ' ' || *end == '\t')) { end--; }
*(end+1) = '\0'; }
CHAR* IsHeadersComplete(const CHAR *szHeaders) { return strstr(szHeaders, szHeaderEnd); }
|