Boolean parseRangeHeader(char const* buf, double& rangeStart, double& rangeEnd) { // First, find "Range:" while (1) { if (*buf == '\0') return False; // not found if (_strncasecmp(buf, "Range: ", 7) == 0) break; ++buf; } // Then, run through each of the fields, looking for ones we handle: char const* fields = buf + 7; while (*fields == ' ') ++fields; double start, end; Locale l("C", LC_NUMERIC); if (sscanf(fields, "npt = %lf - %lf", &start, &end) == 2) { rangeStart = start; rangeEnd = end; } else if (sscanf(fields, "npt = %lf -", &start) == 1) { rangeStart = start; rangeEnd = 0.0; } else { return False; // The header is malformed } return True; }
Boolean parsePlayNowHeader(char const* buf) { // Find "x-playNow:" header, if present while (1) { if (*buf == '\0') return False; // not found if (_strncasecmp(buf, "x-playNow:", 10) == 0) break; ++buf; } return True; }
Boolean parseRangeHeader(char const* buf, double& rangeStart, double& rangeEnd, char*& absStartTime, char*& absEndTime) { // First, find "Range:" while (1) { if (*buf == '\0') return False; // not found if (_strncasecmp(buf, "Range: ", 7) == 0) break; ++buf; } // Then, run through each of the fields, looking for ones we handle: char const* fields = buf + 7; while (*fields == ' ') ++fields; return parseRangeParam(fields, rangeStart, rangeEnd, absStartTime, absEndTime); }
// A special version of "parseTransportHeader()", used just for parsing the "Transport:" header in an incoming "REGISTER" command: void parseTransportHeaderForREGISTER(char const* buf, Boolean &reuseConnection, Boolean& deliverViaTCP, char*& proxyURLSuffix) { // Initialize the result parameters to default values: reuseConnection = False; deliverViaTCP = False; proxyURLSuffix = NULL; // First, find "Transport:" while (1) { if (*buf == '\0') return; // not found if (*buf == '\r' && *(buf+1) == '\n' && *(buf+2) == '\r') return; // end of the headers => not found if (_strncasecmp(buf, "Transport:", 10) == 0) break; ++buf; } // Then, run through each of the fields, looking for ones we handle: char const* fields = buf + 10; while (*fields == ' ') ++fields; char* field = strDupSize(fields); while (sscanf(fields, "%[^;\r\n]", field) == 1) { if (strcmp(field, "reuse_connection") == 0) { reuseConnection = True; } else if (_strncasecmp(field, "preferred_delivery_protocol=udp", 31) == 0) { deliverViaTCP = False; } else if (_strncasecmp(field, "preferred_delivery_protocol=interleaved", 39) == 0) { deliverViaTCP = True; } else if (_strncasecmp(field, "proxy_url_suffix=", 17) == 0) { delete[] proxyURLSuffix; proxyURLSuffix = strDup(field+17); } fields += strlen(field); while (*fields == ';' || *fields == ' ' || *fields == '\t') ++fields; // skip over separating ';' chars or whitespace if (*fields == '\0' || *fields == '\r' || *fields == '\n') break; } delete[] field; }
Boolean parseRangeHeader(char const* buf, double& rangeStart, double& rangeEnd, char*& absStartTime, char*& absEndTime, Boolean& startTimeIsNow) { // First, find "Range:" while (1) { if (*buf == '\0') return False; // not found if (_strncasecmp(buf, "Range: ", 7) == 0) break; ++buf; } char const* fields = buf + 7; while (*fields == ' ') ++fields; return parseRangeParam(fields, rangeStart, rangeEnd, absStartTime, absEndTime, startTimeIsNow); }
static Boolean parseAuthorizationHeader(char const* buf, char const*& username, char const*& realm, char const*& nonce, char const*& uri, char const*& response) { // Initialize the result parameters to default values: username = realm = nonce = uri = response = NULL; // First, find "Authorization:" while (1) { if (*buf == '\0') return False; // not found if (_strncasecmp(buf, "Authorization: Digest ", 22) == 0) break; ++buf; } // Then, run through each of the fields, looking for ones we handle: char const* fields = buf + 22; while (*fields == ' ') ++fields; char* parameter = strDupSize(fields); char* value = strDupSize(fields); while (1) { value[0] = '\0'; if (sscanf(fields, "%[^=]=\"%[^\"]\"", parameter, value) != 2 && sscanf(fields, "%[^=]=\"\"", parameter) != 1) { break; } if (strcmp(parameter, "username") == 0) { username = strDup(value); } else if (strcmp(parameter, "realm") == 0) { realm = strDup(value); } else if (strcmp(parameter, "nonce") == 0) { nonce = strDup(value); } else if (strcmp(parameter, "uri") == 0) { uri = strDup(value); } else if (strcmp(parameter, "response") == 0) { response = strDup(value); } fields += strlen(parameter) + 2 /*="*/ + strlen(value) + 1 /*"*/; while (*fields == ',' || *fields == ' ') ++fields; // skip over any separating ',' and ' ' chars if (*fields == '\0' || *fields == '\r' || *fields == '\n') break; } delete[] parameter; delete[] value; return True; }
Boolean SIPClient::parseSIPURLUsernamePassword(char const* url, char*& username, char*& password) { username = password = NULL; // by default do { // Parse the URL as "sip:<username>[:<password>]@<whatever>" char const* prefix = "sip:"; unsigned const prefixLength = 4; if (_strncasecmp(url, prefix, prefixLength) != 0) break; // Look for the ':' and '@': unsigned usernameIndex = prefixLength; unsigned colonIndex = 0, atIndex = 0; for (unsigned i = usernameIndex; url[i] != '\0' && url[i] != '/'; ++i) { if (url[i] == ':' && colonIndex == 0) { colonIndex = i; } else if (url[i] == '@') { atIndex = i; break; // we're done } } if (atIndex == 0) break; // no '@' found char* urlCopy = strDup(url); urlCopy[atIndex] = '\0'; if (colonIndex > 0) { urlCopy[colonIndex] = '\0'; password = strDup(&urlCopy[colonIndex+1]); } else { password = strDup(""); } username = strDup(&urlCopy[usernameIndex]); delete[] urlCopy; return True; } while (0); return False; }
Boolean parseScaleHeader(char const* buf, float& scale) { // Initialize the result parameter to a default value: scale = 1.0; // First, find "Scale:" while (1) { if (*buf == '\0') return False; // not found if (_strncasecmp(buf, "Scale:", 6) == 0) break; ++buf; } char const* fields = buf + 6; while (*fields == ' ') ++fields; float sc; if (sscanf(fields, "%f", &sc) == 1) { scale = sc; } else { return False; // The header is malformed } return True; }
Boolean parseSpecifiedStringParam(char const* buf, char *find_str, char *specified_str, Boolean specified_str_len) { // First, find "Content-type:" while (1) { if (*buf == '\0') return False; // not found if (_strncasecmp(buf, specified_str, specified_str_len) == 0) break; ++buf; } // Then, run through each of the fields, looking for ones we handle: char const* fields = buf + specified_str_len; while (*fields == ' ') ++fields; Boolean i = 0; while (1) { if (fields[i] == '\r' && fields[i+1] == '\n'){ find_str[i] = '\0'; return i; } find_str[i] = fields[i]; ++i; } return True; }
Boolean parseRTSPRequestString(char const* reqStr, unsigned reqStrSize, char* resultCmdName, unsigned resultCmdNameMaxSize, char* resultURLPreSuffix, unsigned resultURLPreSuffixMaxSize, char* resultURLSuffix, unsigned resultURLSuffixMaxSize, char* resultCSeq, unsigned resultCSeqMaxSize, char* resultSessionIdStr, unsigned resultSessionIdStrMaxSize, unsigned& contentLength, unsigned& resultPinId, unsigned& resultDisplayId) { // This parser is currently rather dumb; it should be made smarter ##### // Read everything up to the first space as the command name: Boolean parseSucceeded = False; unsigned i; for (i = 0; i < resultCmdNameMaxSize-1 && i < reqStrSize; ++i) { char c = reqStr[i]; if (c == ' ' || c == '\t') { parseSucceeded = True; break; } resultCmdName[i] = c; } resultCmdName[i] = '\0'; if (!parseSucceeded) return False; // Skip over the prefix of any "rtsp://" or "rtsp:/" URL that follows: unsigned j = i+1; while (j < reqStrSize && (reqStr[j] == ' ' || reqStr[j] == '\t')) ++j; // skip over any additional white space for (; (int)j < (int)(reqStrSize-8); ++j) { if ((reqStr[j] == 'r' || reqStr[j] == 'R') && (reqStr[j+1] == 't' || reqStr[j+1] == 'T') && (reqStr[j+2] == 's' || reqStr[j+2] == 'S') && (reqStr[j+3] == 'p' || reqStr[j+3] == 'P') && reqStr[j+4] == ':' && reqStr[j+5] == '/') { j += 6; if (reqStr[j] == '/') { // This is a "rtsp://" URL; skip over the host:port part that follows: ++j; while (j < reqStrSize && reqStr[j] != '/' && reqStr[j] != ' ') ++j; } else { // This is a "rtsp:/" URL; back up to the "/": --j; } i = j; break; } } // Look for the URL suffix (before the following "RTSP/"): parseSucceeded = False; for (unsigned k = i+1; (int)k < (int)(reqStrSize-5); ++k) { if (reqStr[k] == 'R' && reqStr[k+1] == 'T' && reqStr[k+2] == 'S' && reqStr[k+3] == 'P' && reqStr[k+4] == '/') { while (--k >= i && reqStr[k] == ' ') {} // go back over all spaces before "RTSP/" unsigned k1 = k; while (k1 > i && reqStr[k1] != '/') --k1; // ASSERT: At this point // i: first space or slash after "host" or "host:port" // k: last non-space before "RTSP/" // k1: last slash in the range [i,k] // The URL suffix comes from [k1+1,k] // Copy "resultURLSuffix": unsigned n = 0, k2 = k1+1; if (i <= k) { // There's a slash after "host" or "host:port" if (k - k1 + 1 > resultURLSuffixMaxSize) return False; // there's no room while (k2 <= k) resultURLSuffix[n++] = reqStr[k2++]; } resultURLSuffix[n] = '\0'; // The URL 'pre-suffix' comes from [i+1,k1-1] // Copy "resultURLPreSuffix": n = 0; k2 = i + 1; if (i <= k) { // There's a slash after "host" or "host:port" if (k1 - i > resultURLPreSuffixMaxSize) return False; // there's no room while (k2 <= k1 - 1) resultURLPreSuffix[n++] = reqStr[k2++]; } resultURLPreSuffix[n] = '\0'; decodeURL(resultURLPreSuffix); i = k + 7; // to go past " RTSP/" parseSucceeded = True; break; } } if (!parseSucceeded) return False; // Look for "CSeq:" (mandatory, case insensitive), skip whitespace, // then read everything up to the next \r or \n as 'CSeq': parseSucceeded = False; for (j = i; (int)j < (int)(reqStrSize-5); ++j) { if (_strncasecmp("CSeq:", &reqStr[j], 5) == 0) { j += 5; while (j < reqStrSize && (reqStr[j] == ' ' || reqStr[j] == '\t')) ++j; unsigned n; for (n = 0; n < resultCSeqMaxSize-1 && j < reqStrSize; ++n,++j) { char c = reqStr[j]; if (c == '\r' || c == '\n') { parseSucceeded = True; break; } resultCSeq[n] = c; } resultCSeq[n] = '\0'; break; } } if (!parseSucceeded) return False; // Look for "Session:" (optional, case insensitive), skip whitespace, // then read everything up to the next \r or \n as 'Session': resultSessionIdStr[0] = '\0'; // default value (empty string) for (j = i; (int)j < (int)(reqStrSize-8); ++j) { if (_strncasecmp("Session:", &reqStr[j], 8) == 0) { j += 8; while (j < reqStrSize && (reqStr[j] == ' ' || reqStr[j] == '\t')) ++j; unsigned n; for (n = 0; n < resultSessionIdStrMaxSize-1 && j < reqStrSize; ++n,++j) { char c = reqStr[j]; if (c == '\r' || c == '\n') { break; } resultSessionIdStr[n] = c; } resultSessionIdStr[n] = '\0'; break; } } // Also: Look for "Content-Length:" (optional, case insensitive) contentLength = 0; // default value for (j = i; (int)j < (int)(reqStrSize-15); ++j) { if (_strncasecmp("Content-Length:", &(reqStr[j]), 15) == 0) { j += 15; while (j < reqStrSize && (reqStr[j] == ' ' || reqStr[j] == '\t')) ++j; unsigned num; if (sscanf(&reqStr[j], "%u", &num) == 1) { contentLength = num; } } } // ESD: Look for "DisplayId:" (optional, case insensitive) resultDisplayId = 1; // default value for (j = i; (int)j < (int)(reqStrSize-10); ++j) { if (_strncasecmp("DisplayId:", &(reqStr[j]), 10) == 0) { j += 10; while (j < reqStrSize && (reqStr[j] == ' ' || reqStr[j] == '\t')) ++j; unsigned num; if (sscanf(&reqStr[j], "%u", &num) == 1) { resultDisplayId = num; } } } // ESD: Look for "Pin:" (optional, case insensitive) resultPinId = 0; // default value for (j = i; (int)j < (int)(reqStrSize-4); ++j) { if (_strncasecmp("Pin:", &(reqStr[j]), 4) == 0) { j += 4; while (j < reqStrSize && (reqStr[j] == ' ' || reqStr[j] == '\t')) ++j; unsigned num; if (sscanf(&reqStr[j], "%u", &num) == 1) { resultPinId = num; } } } return true; }
void parseTransportHeader(char const* buf, StreamingMode& streamingMode, char*& streamingModeString, char*& destinationAddressStr, unsigned char& destinationTTL, unsigned short& clientRTPPortNum, // if UDP unsigned short& clientRTCPPortNum, // if UDP unsigned char& rtpChannelId, // if TCP unsigned char& rtcpChannelId // if TCP ) { // Initialize the result parameters to default values: streamingMode = RTP_UDP; streamingModeString = NULL; destinationAddressStr = NULL; destinationTTL = 255; clientRTPPortNum = 0; clientRTCPPortNum = 1; rtpChannelId = rtcpChannelId = 0xFF; unsigned short p1, p2; unsigned ttl, rtpCid, rtcpCid; // First, find "Transport:" while (1) { if (*buf == '\0') return; // not found if (_strncasecmp(buf, "Transport: ", 11) == 0) break; ++buf; } // Then, run through each of the fields, looking for ones we handle: char const* fields = buf + 11; char* field = strDupSize(fields); while (sscanf(fields, "%[^;]", field) == 1) { if (strcmp(field, "RTP/AVP/TCP") == 0) { streamingMode = RTP_TCP; } else if (strcmp(field, "RAW/RAW/UDP") == 0 || strcmp(field, "MP2T/H2221/UDP") == 0) { streamingMode = RAW_UDP; streamingModeString = strDup(field); } else if (_strncasecmp(field, "destination=", 12) == 0) { delete[] destinationAddressStr; destinationAddressStr = strDup(field+12); } else if (sscanf(field, "ttl%u", &ttl) == 1) { destinationTTL = (unsigned char)ttl; } else if (sscanf(field, "client_port=%hu-%hu", &p1, &p2) == 2) { clientRTPPortNum = p1; clientRTCPPortNum = p2; } else if (sscanf(field, "client_port=%hu", &p1) == 1) { clientRTPPortNum = p1; clientRTCPPortNum = streamingMode == RAW_UDP ? 0 : p1 + 1; } else if (sscanf(field, "interleaved=%u-%u", &rtpCid, &rtcpCid) == 2) { rtpChannelId = (unsigned char)rtpCid; rtcpChannelId = (unsigned char)rtcpCid; } fields += strlen(field); while (*fields == ';') ++fields; // skip over separating ';' chars if (*fields == '\0' || *fields == '\r' || *fields == '\n') break; } delete[] field; }
Boolean SIPClient::parseSIPURL(UsageEnvironment& env, char const* url, NetAddress& address, portNumBits& portNum) { do { // Parse the URL as "sip:<username>@<address>:<port>/<etc>" // (with ":<port>" and "/<etc>" optional) // Also, skip over any "<username>[:<password>]@" preceding <address> char const* prefix = "sip:"; unsigned const prefixLength = 4; if (_strncasecmp(url, prefix, prefixLength) != 0) { env.setResultMsg("URL is not of the form \"", prefix, "\""); break; } unsigned const parseBufferSize = 100; char parseBuffer[parseBufferSize]; unsigned addressStartIndex = prefixLength; while (url[addressStartIndex] != '\0' && url[addressStartIndex++] != '@') {} char const* from = &url[addressStartIndex]; // Skip over any "<username>[:<password>]@" char const* from1 = from; while (*from1 != '\0' && *from1 != '/') { if (*from1 == '@') { from = ++from1; break; } ++from1; } char* to = &parseBuffer[0]; unsigned i; for (i = 0; i < parseBufferSize; ++i) { if (*from == '\0' || *from == ':' || *from == '/') { // We've completed parsing the address *to = '\0'; break; } *to++ = *from++; } if (i == parseBufferSize) { env.setResultMsg("URL is too long"); break; } NetAddressList addresses(parseBuffer); if (addresses.numAddresses() == 0) { env.setResultMsg("Failed to find network address for \"", parseBuffer, "\""); break; } address = *(addresses.firstAddress()); portNum = 5060; // default value char nextChar = *from; if (nextChar == ':') { int portNumInt; if (sscanf(++from, "%d", &portNumInt) != 1) { env.setResultMsg("No port number follows ':'"); break; } if (portNumInt < 1 || portNumInt > 65535) { env.setResultMsg("Bad port number"); break; } portNum = (portNumBits)portNumInt; } return True; } while (0); return False; }