static Boolean parseSourceFilterAttribute(char const* sdpLine, struct in_addr& sourceAddr) { // Check for a "a=source-filter:incl IN IP4 <something> <source>" line. // Note: At present, we don't check that <something> really matches // one of our multicast addresses. We also don't support more than // one <source> ##### Boolean result = False; // until we succeed char* sourceName = strDupSize(sdpLine); // ensures we have enough space do { if (sscanf(sdpLine, "a=source-filter: incl IN IP4 %*s %s", sourceName) != 1) break; // Now, convert this name to an address, if we can: NetAddressList addresses(sourceName); if (addresses.numAddresses() == 0) break; netAddressBits sourceAddrBits = *(netAddressBits*)(addresses.firstAddress()->data()); if (sourceAddrBits == 0) break; sourceAddr.s_addr = sourceAddrBits; result = True; } while (0); delete[] sourceName; return result; }
Boolean MediaSubsession::parseSDPAttribute_rtpmap(char const* sdpLine) { // Check for a "a=rtpmap:<fmt> <codec>/<freq>" line: // (Also check without the "/<freq>"; RealNetworks omits this) // Also check for a trailing "/<numChannels>". Boolean parseSuccess = False; unsigned rtpmapPayloadFormat; char* codecName = strDupSize(sdpLine); // ensures we have enough space unsigned rtpTimestampFrequency = 0; unsigned numChannels = 1; if (sscanf(sdpLine, "a=rtpmap: %u %[^/]/%u/%u", &rtpmapPayloadFormat, codecName, &rtpTimestampFrequency, &numChannels) == 4 || sscanf(sdpLine, "a=rtpmap: %u %[^/]/%u", &rtpmapPayloadFormat, codecName, &rtpTimestampFrequency) == 3 || sscanf(sdpLine, "a=rtpmap: %u %s", &rtpmapPayloadFormat, codecName) == 2) { parseSuccess = True; if (rtpmapPayloadFormat == fRTPPayloadFormat) { // This "rtpmap" matches our payload format, so set our // codec name and timestamp frequency: // (First, make sure the codec name is upper case) { Locale l("POSIX"); for (char* p = codecName; *p != '\0'; ++p) *p = toupper(*p); } delete[] fCodecName; fCodecName = strDup(codecName); fRTPTimestampFrequency = rtpTimestampFrequency; fNumChannels = numChannels; } } delete[] codecName; return parseSuccess; }
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; }
static char* parseCLine(char const* sdpLine) { char* resultStr = NULL; char* buffer = strDupSize(sdpLine); // ensures we have enough space if (sscanf(sdpLine, "c=IN IP4 %[^/ ]", buffer) == 1) { // Later, handle the optional /<ttl> and /<numAddresses> ##### resultStr = strDup(buffer); } delete[] buffer; return resultStr; }
void setupSubsession(MediaSubsession* subsession, Boolean /*streamUsingTCP*/, Boolean /*forceMulticastOnUnspecified*/,RTSPClient::responseHandler* afterFunc) { subsession->setSessionId("mumble"); // anything that's non-NULL will work ////////// BEGIN hack code that should really be implemented in SIPClient ////////// // Parse the "Transport:" header parameters: // We do not send audio, but we need port for RTCP char* serverAddressStr; portNumBits serverPortNum; unsigned char rtpChannelId, rtcpChannelId; rtpChannelId = rtcpChannelId = 0xff; serverPortNum = 0; serverAddressStr = NULL; char* sdp = strDup(ourSIPClient->getInviteSdpReply()); char* lineStart; char* nextLineStart = sdp; while (1) { lineStart = nextLineStart; if (lineStart == NULL) { break; } nextLineStart = getLine(lineStart); char* toTagStr = strDupSize(lineStart); if (sscanf(lineStart, "m=audio %[^/\r\n]", toTagStr) == 1) { sscanf(toTagStr, "%hu", &serverPortNum); } else if (sscanf(lineStart, "c=IN IP4 %[^/\r\n]", toTagStr) == 1) { serverAddressStr = strDup(toTagStr); } delete[] toTagStr; } if(sdp != NULL) { delete[] sdp; } delete[] subsession->connectionEndpointName(); subsession->connectionEndpointName() = serverAddressStr; subsession->serverPortNum = serverPortNum; subsession->rtpChannelId = rtpChannelId; subsession->rtcpChannelId = rtcpChannelId; // Set the RTP and RTCP sockets' destination address and port from the information in the SETUP response (if present): netAddressBits destAddress = subsession->connectionEndpointAddress(); if (destAddress != 0) { subsession->setDestinations(destAddress); } ////////// END hack code that should really be implemented in SIPClient ////////// afterFunc(NULL, 0, NULL); }
Boolean MediaSession::parseSDPAttribute_control(char const* sdpLine) { // Check for a "a=control:<control-path>" line: Boolean parseSuccess = False; char* controlPath = strDupSize(sdpLine); // ensures we have enough space if (sscanf(sdpLine, "a=control: %s", controlPath) == 1) { parseSuccess = True; delete[] fControlPath; fControlPath = strDup(controlPath); } delete[] controlPath; return parseSuccess; }
Boolean MediaSession::parseSDPLine_i(char const* sdpLine) { // Check for "i=<session description>" line char* buffer = strDupSize(sdpLine); Boolean parseSuccess = False; if (sscanf(sdpLine, "i=%[^\r\n]", buffer) == 1) { delete[] fSessionDescription; fSessionDescription = strDup(buffer); parseSuccess = True; } delete[] buffer; return parseSuccess; }
Boolean MediaSession::parseSDPLine_s(char const* sdpLine) { // Check for "s=<session name>" line char* buffer = strDupSize(sdpLine); Boolean parseSuccess = False; if (sscanf(sdpLine, "s=%[^\r\n]", buffer) == 1) { delete[] fSessionName; fSessionName = strDup(buffer); parseSuccess = True; } delete[] buffer; return parseSuccess; }
Boolean MediaSession::parseSDPAttribute_type(char const* sdpLine) { // Check for a "a=type:broadcast|meeting|moderated|test|H.332|recvonly" line: Boolean parseSuccess = False; char* buffer = strDupSize(sdpLine); if (sscanf(sdpLine, "a=type: %[^ ]", buffer) == 1) { delete[] fMediaSessionType; fMediaSessionType = strDup(buffer); parseSuccess = True; } delete[] buffer; return parseSuccess; }
// 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; }
char* strDupSize(char const* str) { size_t dummy; return strDupSize(str, dummy); }
Boolean MediaSubsession::parseSDPAttribute_fmtp(char const* sdpLine) { // Check for a "a=fmtp:" line: // TEMP: We check only for a handful of expected parameter names ##### // Later: (i) check that payload format number matches; ##### // (ii) look for other parameters also (generalize?) ##### do { if (strncmp(sdpLine, "a=fmtp:", 7) != 0) break; sdpLine += 7; while (isdigit(*sdpLine)) ++sdpLine; // The remaining "sdpLine" should be a sequence of // <name>=<value>; // parameter assignments. Look at each of these. // First, convert the line to lower-case, to ease comparison: char* const lineCopy = strDup(sdpLine); char* line = lineCopy; { Locale l("POSIX"); for (char* c = line; *c != '\0'; ++c) *c = tolower(*c); } while (*line != '\0' && *line != '\r' && *line != '\n') { unsigned u; char* valueStr = strDupSize(line); if (sscanf(line, " auxiliarydatasizelength = %u", &u) == 1) { fAuxiliarydatasizelength = u; } else if (sscanf(line, " constantduration = %u", &u) == 1) { fConstantduration = u; } else if (sscanf(line, " constantsize; = %u", &u) == 1) { fConstantsize = u; } else if (sscanf(line, " crc = %u", &u) == 1) { fCRC = u; } else if (sscanf(line, " ctsdeltalength = %u", &u) == 1) { fCtsdeltalength = u; } else if (sscanf(line, " de-interleavebuffersize = %u", &u) == 1) { fDe_interleavebuffersize = u; } else if (sscanf(line, " dtsdeltalength = %u", &u) == 1) { fDtsdeltalength = u; } else if (sscanf(line, " indexdeltalength = %u", &u) == 1) { fIndexdeltalength = u; } else if (sscanf(line, " indexlength = %u", &u) == 1) { fIndexlength = u; } else if (sscanf(line, " interleaving = %u", &u) == 1) { fInterleaving = u; } else if (sscanf(line, " maxdisplacement = %u", &u) == 1) { fMaxdisplacement = u; } else if (sscanf(line, " objecttype = %u", &u) == 1) { fObjecttype = u; } else if (sscanf(line, " octet-align = %u", &u) == 1) { fOctetalign = u; } else if (sscanf(line, " profile-level-id = %x", &u) == 1) { // Note that the "profile-level-id" parameter is assumed to be hexadecimal fProfile_level_id = u; } else if (sscanf(line, " robust-sorting = %u", &u) == 1) { fRobustsorting = u; } else if (sscanf(line, " sizelength = %u", &u) == 1) { fSizelength = u; } else if (sscanf(line, " streamstateindication = %u", &u) == 1) { fStreamstateindication = u; } else if (sscanf(line, " streamtype = %u", &u) == 1) { fStreamtype = u; } else if (sscanf(line, " cpresent = %u", &u) == 1) { fCpresent = u != 0; } else if (sscanf(line, " randomaccessindication = %u", &u) == 1) { fRandomaccessindication = u != 0; } else if (sscanf(line, " config = %[^; \t\r\n]", valueStr) == 1) { delete[] fConfig; fConfig = strDup(valueStr); } else if (sscanf(line, " mode = %[^; \t\r\n]", valueStr) == 1) { delete[] fMode; fMode = strDup(valueStr); } else if (sscanf(sdpLine, " sprop-parameter-sets = %[^; \t\r\n]", valueStr) == 1) { // Note: We used "sdpLine" here, because the value is case-sensitive. delete[] fSpropParameterSets; fSpropParameterSets = strDup(valueStr); } else { // Some of the above parameters are Boolean. Check whether the parameter // names appear alone, without a "= 1" at the end: if (sscanf(line, " %[^; \t\r\n]", valueStr) == 1) { if (strcmp(valueStr, "octet-align") == 0) { fOctetalign = 1; } else if (strcmp(valueStr, "cpresent") == 0) { fCpresent = True; } else if (strcmp(valueStr, "crc") == 0) { fCRC = 1; } else if (strcmp(valueStr, "robust-sorting") == 0) { fRobustsorting = 1; } else if (strcmp(valueStr, "randomaccessindication") == 0) { fRandomaccessindication = True; } } } delete[] valueStr; // Move to the next parameter assignment string: while (*line != '\0' && *line != '\r' && *line != '\n' && *line != ';') ++line; while (*line == ';') ++line; // Do the same with sdpLine; needed for finding case sensitive values: while (*sdpLine != '\0' && *sdpLine != '\r' && *sdpLine != '\n' && *sdpLine != ';') ++sdpLine; while (*sdpLine == ';') ++sdpLine; } delete[] lineCopy; return True; } while (0); return False; }
Boolean MediaSession::initializeWithSDP(char const* sdpDescription) { if (sdpDescription == NULL) return False; // Begin by processing all SDP lines until we see the first "m=" char const* sdpLine = sdpDescription; char const* nextSDPLine; while (1) { if (!parseSDPLine(sdpLine, nextSDPLine)) return False; //##### We should really check for: // - "a=control:" attributes (to set the URL for aggregate control) // - the correct SDP version (v=0) if (sdpLine[0] == 'm') break; sdpLine = nextSDPLine; if (sdpLine == NULL) break; // there are no m= lines at all // Check for various special SDP lines that we understand: if (parseSDPLine_s(sdpLine)) continue; if (parseSDPLine_i(sdpLine)) continue; if (parseSDPLine_c(sdpLine)) continue; if (parseSDPAttribute_control(sdpLine)) continue; if (parseSDPAttribute_range(sdpLine)) continue; if (parseSDPAttribute_type(sdpLine)) continue; if (parseSDPAttribute_source_filter(sdpLine)) continue; #ifdef SUPPORT_REAL_RTSP if (RealParseSDPAttributes(this, sdpLine)) continue; #endif } while (sdpLine != NULL) { // We have a "m=" line, representing a new sub-session: MediaSubsession* subsession = new MediaSubsession(*this); if (subsession == NULL) { envir().setResultMsg("Unable to create new MediaSubsession"); return False; } // Parse the line as "m=<medium_name> <client_portNum> RTP/AVP <fmt>" // or "m=<medium_name> <client_portNum>/<num_ports> RTP/AVP <fmt>" // (Should we be checking for >1 payload format number here?)##### char* mediumName = strDupSize(sdpLine); // ensures we have enough space char* protocolName = NULL; unsigned payloadFormat; if ((sscanf(sdpLine, "m=%s %hu RTP/AVP %u", mediumName, &subsession->fClientPortNum, &payloadFormat) == 3 || sscanf(sdpLine, "m=%s %hu/%*u RTP/AVP %u", mediumName, &subsession->fClientPortNum, &payloadFormat) == 3) && payloadFormat <= 127) { protocolName = "RTP"; } else if ((sscanf(sdpLine, "m=%s %hu UDP %u", mediumName, &subsession->fClientPortNum, &payloadFormat) == 3 || sscanf(sdpLine, "m=%s %hu udp %u", mediumName, &subsession->fClientPortNum, &payloadFormat) == 3 || sscanf(sdpLine, "m=%s %hu RAW/RAW/UDP %u", mediumName, &subsession->fClientPortNum, &payloadFormat) == 3) && payloadFormat <= 127) { // This is a RAW UDP source protocolName = "UDP"; } else { // This "m=" line is bad; output an error message saying so: char* sdpLineStr; if (nextSDPLine == NULL) { sdpLineStr = (char*)sdpLine; } else { sdpLineStr = strDup(sdpLine); sdpLineStr[nextSDPLine-sdpLine] = '\0'; } envir() << "Bad SDP \"m=\" line: " << sdpLineStr << "\n"; if (sdpLineStr != (char*)sdpLine) delete[] sdpLineStr; delete[] mediumName; delete subsession; // Skip the following SDP lines, up until the next "m=": while (1) { sdpLine = nextSDPLine; if (sdpLine == NULL) break; // we've reached the end if (!parseSDPLine(sdpLine, nextSDPLine)) return False; if (sdpLine[0] == 'm') break; // we've reached the next subsession } continue; } // Insert this subsession at the end of the list: if (fSubsessionsTail == NULL) { fSubsessionsHead = fSubsessionsTail = subsession; } else { fSubsessionsTail->setNext(subsession); fSubsessionsTail = subsession; } subsession->serverPortNum = subsession->fClientPortNum; // by default char const* mStart = sdpLine; subsession->fSavedSDPLines = strDup(mStart); subsession->fMediumName = strDup(mediumName); delete[] mediumName; subsession->fProtocolName = strDup(protocolName); subsession->fRTPPayloadFormat = payloadFormat; // Process the following SDP lines, up until the next "m=": while (1) { sdpLine = nextSDPLine; if (sdpLine == NULL) break; // we've reached the end if (!parseSDPLine(sdpLine, nextSDPLine)) return False; if (sdpLine[0] == 'm') break; // we've reached the next subsession // Check for various special SDP lines that we understand: if (subsession->parseSDPLine_c(sdpLine)) continue; if (subsession->parseSDPAttribute_rtpmap(sdpLine)) continue; if (subsession->parseSDPAttribute_control(sdpLine)) continue; if (subsession->parseSDPAttribute_range(sdpLine)) continue; if (subsession->parseSDPAttribute_fmtp(sdpLine)) continue; if (subsession->parseSDPAttribute_source_filter(sdpLine)) continue; if (subsession->parseSDPAttribute_x_dimensions(sdpLine)) continue; if (subsession->parseSDPAttribute_framerate(sdpLine)) continue; if ( subsession->parseSDPAttribute_bandwidth( sdpLine ) ) { continue; } #ifdef SUPPORT_REAL_RTSP if (RealParseSDPAttributes(subsession, sdpLine)) continue; #endif // (Later, check for malformed lines, and other valid SDP lines#####) } if (sdpLine != NULL) subsession->fSavedSDPLines[sdpLine-mStart] = '\0'; // If we don't yet know the codec name, try looking it up from the // list of static payload types: if (subsession->fCodecName == NULL) { subsession->fCodecName = lookupPayloadFormat(subsession->fRTPPayloadFormat, subsession->fRTPTimestampFrequency, subsession->fNumChannels); if (subsession->fCodecName == NULL) { char typeStr[20]; sprintf(typeStr, "%d", subsession->fRTPPayloadFormat); envir().setResultMsg("Unknown codec name for RTP payload type ", typeStr); return False; } } // If we don't yet know this subsession's RTP timestamp frequency // (because it uses a dynamic payload type and the corresponding // SDP "rtpmap" attribute erroneously didn't specify it), // then guess it now: if (subsession->fRTPTimestampFrequency == 0) { subsession->fRTPTimestampFrequency = guessRTPTimestampFrequency(subsession->fMediumName, subsession->fCodecName); } } 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; }
unsigned SIPClient::getResponseCode() { unsigned responseCode = 0; do { // Get the response from the server: unsigned const readBufSize = 10000; char readBuffer[readBufSize+1]; char* readBuf = readBuffer; char* firstLine = NULL; char* nextLineStart = NULL; unsigned bytesRead = getResponse(readBuf, readBufSize); if (bytesRead == 0) break; if (fVerbosityLevel >= 1) { envir() << "Received INVITE response: " << readBuf << "\n"; } // Inspect the first line to get the response code: firstLine = readBuf; nextLineStart = getLine(firstLine); if (!parseResponseCode(firstLine, responseCode)) break; if (responseCode != 200) { if (responseCode >= 400 && responseCode <= 499 && fWorkingAuthenticator != NULL) { // We have an authentication failure, so fill in // "*fWorkingAuthenticator" using the contents of a following // "Proxy-Authenticate:" line. (Once we compute a 'response' for // "fWorkingAuthenticator", it can be used in a subsequent request // - that will hopefully succeed.) char* lineStart; while (1) { lineStart = nextLineStart; if (lineStart == NULL) break; nextLineStart = getLine(lineStart); if (lineStart[0] == '\0') break; // this is a blank line char* realm = strDupSize(lineStart); char* nonce = strDupSize(lineStart); // ##### Check for the format of "Proxy-Authenticate:" lines from // ##### known server types. // ##### This is a crock! We should make the parsing more general Boolean foundAuthenticateHeader = False; if ( // Asterisk ##### sscanf(lineStart, "Proxy-Authenticate: Digest realm=\"%[^\"]\", nonce=\"%[^\"]\"", realm, nonce) == 2 || // Cisco ATA ##### sscanf(lineStart, "Proxy-Authenticate: Digest algorithm=MD5,domain=\"%*[^\"]\",nonce=\"%[^\"]\", realm=\"%[^\"]\"", nonce, realm) == 2) { fWorkingAuthenticator->setRealmAndNonce(realm, nonce); foundAuthenticateHeader = True; } delete[] realm; delete[] nonce; if (foundAuthenticateHeader) break; } } envir().setResultMsg("cannot handle INVITE response: ", firstLine); break; } // Skip every subsequent header line, until we see a blank line. // While doing so, check for "To:" and "Content-Length:" lines. // The remaining data is assumed to be the SDP descriptor that we want. // We should really do some more checking on the headers here - e.g., to // check for "Content-type: application/sdp", "CSeq", etc. ##### int contentLength = -1; char* lineStart; while (1) { lineStart = nextLineStart; if (lineStart == NULL) break; nextLineStart = getLine(lineStart); if (lineStart[0] == '\0') break; // this is a blank line char* toTagStr = strDupSize(lineStart); if (sscanf(lineStart, "To:%*[^;]; tag=%s", toTagStr) == 1) { delete[] (char*)fToTagStr; fToTagStr = strDup(toTagStr); fToTagStrSize = strlen(fToTagStr); } delete[] toTagStr; if (sscanf(lineStart, "Content-Length: %d", &contentLength) == 1 || sscanf(lineStart, "Content-length: %d", &contentLength) == 1) { if (contentLength < 0) { envir().setResultMsg("Bad \"Content-Length:\" header: \"", lineStart, "\""); break; } } } // We're now at the end of the response header lines if (lineStart == NULL) { envir().setResultMsg("no content following header lines: ", readBuf); break; } // Use the remaining data as the SDP descr, but first, check // the "Content-Length:" header (if any) that we saw. We may need to // read more data, or we may have extraneous data in the buffer. char* bodyStart = nextLineStart; if (bodyStart != NULL && contentLength >= 0) { // We saw a "Content-Length:" header unsigned numBodyBytes = &readBuf[bytesRead] - bodyStart; if (contentLength > (int)numBodyBytes) { // We need to read more data. First, make sure we have enough // space for it: unsigned numExtraBytesNeeded = contentLength - numBodyBytes; #ifdef USING_TCP // THIS CODE WORKS ONLY FOR TCP: ##### unsigned remainingBufferSize = readBufSize - (bytesRead + (readBuf - readBuffer)); if (numExtraBytesNeeded > remainingBufferSize) { char tmpBuf[200]; sprintf(tmpBuf, "Read buffer size (%d) is too small for \"Content-Length:\" %d (need a buffer size of >= %d bytes\n", readBufSize, contentLength, readBufSize + numExtraBytesNeeded - remainingBufferSize); envir().setResultMsg(tmpBuf); break; } // Keep reading more data until we have enough: if (fVerbosityLevel >= 1) { envir() << "Need to read " << numExtraBytesNeeded << " extra bytes\n"; } while (numExtraBytesNeeded > 0) { char* ptr = &readBuf[bytesRead]; unsigned bytesRead2; struct sockaddr_in fromAddr; Boolean readSuccess = fOurSocket->handleRead((unsigned char*)ptr, numExtraBytesNeeded, bytesRead2, fromAddr); if (!readSuccess) break; ptr[bytesRead2] = '\0'; if (fVerbosityLevel >= 1) { envir() << "Read " << bytesRead2 << " extra bytes: " << ptr << "\n"; } bytesRead += bytesRead2; numExtraBytesNeeded -= bytesRead2; } #endif if (numExtraBytesNeeded > 0) break; // one of the reads failed } bodyStart[contentLength] = '\0'; // trims any extra data delete[] fInviteSDPDescriptionReturned; fInviteSDPDescriptionReturned = strDup(bodyStart); } } while (0); return responseCode; }