예제 #1
0
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;
}
예제 #2
0
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;
}
예제 #3
0
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;
}
예제 #4
0
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;
}
예제 #5
0
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);
}
예제 #6
0
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;
}
예제 #7
0
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;
}
예제 #8
0
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;
}
예제 #9
0
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;
}
예제 #10
0
// 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;
}
예제 #11
0
char* strDupSize(char const* str) {
  size_t dummy;

  return strDupSize(str, dummy);
}
예제 #12
0
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;
}
예제 #13
0
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;
}
예제 #14
0
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;
}
예제 #15
0
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;
}