Esempio n. 1
0
int RtspClientSession::handle_setup(RtspClientConnection * rcc, 
									std::string & urlPreSuffix, 
									std::string & urlSuffix, 
									std::string & fullRequestStr){

	//    "urlPreSuffix" is empty and "urlSuffix" is the session (stream) name, or
	//    "urlPreSuffix" concatenated with "urlSuffix" (with "/" inbetween) is the session (stream) name.

	//rtsp://192.168.20.136:5000/xxx666/trackID=0 RTSP/1.0 

	std::string streamName = urlPreSuffix;
	std::string trackId = urlSuffix;
	if(urlPreSuffix.empty()){
		streamName = urlSuffix;
	}
	
	if(m_mediaSession){
		if (m_mediaSession->StreamName() != streamName){
			return rcc->handleCmd_bad();
		}
	}
	else{
		m_mediaSession = rcc->get_rtsp()->getAndDetachMediaSession(streamName);
	}
	
	if (!m_mediaSession){
		return rcc->handleCmd_notFound();
	}

	if (trackId.empty() && m_mediaSession->SubSessionCount() != 1){
		return rcc->handleCmd_bad();
	}

	MediaSubSession * subsession = NULL;
	if (trackId.empty()){
		subsession = m_mediaSession->GetSubSession(0);
	}
	else{
		 subsession = m_mediaSession->Lookup(trackId);
	}

	if (!subsession){
		return rcc->handleCmd_notFound();
	}

	int transMode = RTP_UDP;
	std::string strDstAdder;
	uchar  dstTTL = 255;
	uint  rtpPort = 0;  //UDP
	uint  rtcpPort = 1; //UDP
	uchar  rtpChannel = 0xff; //tcp
	uchar  rtcpChannel = 0xff; //tcp	
	
	parseTransportHeader(fullRequestStr, transMode, strDstAdder, dstTTL, 
		rtpPort, rtcpPort, rtpChannel, rtcpChannel);
	
	if (transMode == RAW_UDP){
		rcc->handleCmd_notSupported();
		return -1;
	}

	if (transMode == RTP_TCP && rtpChannel == 0xff){
		// An anomolous situation, caused by a buggy client.  Either:
		// 1/ TCP streaming was requested, but with no "interleaving=" fields.  (QuickTime Player sometimes does this.), or
		// 2/ TCP streaming was not requested, but we're doing RTSP-over-HTTP tunneling (which implies TCP streaming).
		rtpChannel = m_tcpStreamCount++;
		rtcpChannel = m_tcpStreamCount++;
	}

	if (fullRequestStr.find("x-playNow:") != std::string::npos){
		rcc->handleCmd_notSupported();
		return -1;
	}
	
	ipaddr dstAddr = {{0},0};
	if(!strDstAdder.empty()){
		strncpy(dstAddr.ip, strDstAdder.c_str(), sizeof(dstAddr.ip));
	}
	else{
		dstAddr = rcc->get_peeraddr();
	}
	
	const ipaddr & localAddr = rcc->get_localaddr();
	uint dstIp = ntohl(inet_addr(dstAddr.ip ));
	
	std::string response;

	if (transMode == RTP_TCP){
		subsession->GetTcpParam((void*)rcc, rtpChannel, rtcpChannel, dstTTL);
		append(response,
			"RTSP/1.0 200 OK\r\n"
			"CSeq: %s\r\n"
			"%s"
			"Transport: RTP/AVP/TCP;unicast;destination=%s;source=%s;interleaved=%d-%d\r\n"
			"Session: %s\r\n\r\n",
			rcc->getSeq().c_str(), 
			dateStr().c_str(),
			dstAddr.ip, localAddr.ip, 
			rtpChannel, rtcpChannel,
			m_sessionId.c_str());
	}
	else{
		
		uint serverRtpPort  = 0;
		uint serverRtcpPort = 0;
		subsession->GetUdpParam(rtpPort, rtcpPort, dstIp, serverRtpPort, serverRtcpPort);
		append(response,
			"RTSP/1.0 200 OK\r\n"
			"CSeq: %s\r\n"
			"%s"
			"Transport: RTP/AVP;unicast;source=%s;client_port=%d-%d;server_port=%d-%d\r\n"
			"Session: %s\r\n\r\n",
			rcc->getSeq().c_str(), 
			dateStr().c_str(), 
			localAddr.ip,
			rtpPort, rtcpPort, serverRtpPort, serverRtcpPort,
			m_sessionId.c_str());
	}
	
	debug_log("S->C : %s\n", response.c_str());
	rcc->post_send(response.c_str(), response.length());

	return 0;
}
Esempio n. 2
0
void RTSPServer::RTSPClientSession
::handleCmd_SETUP(char const* cseq,
		  char const* urlPreSuffix, char const* urlSuffix,
		  char const* fullRequestStr) {
	// "urlPreSuffix" should be the session (stream) name, and
	// "urlSuffix" should be the subsession (track) name.
  char const* streamName = urlPreSuffix;
  char const* trackId = urlSuffix;

	// Check whether we have existing session state, and, if so, whether it's
	// for the session that's named in "streamName".	(Note that we don't
	// support more than one concurrent session on the same client connection.) #####
  if (fOurServerMediaSession != NULL
			&& strcmp(streamName, fOurServerMediaSession->streamName()) != 0) {
	  fOurServerMediaSession = NULL;
	}
  if (fOurServerMediaSession == NULL) {
		// Set up this session's state.

		// Look up the "ServerMediaSession" object for the specified stream:
	  if (streamName[0] != '\0' ||
	fOurServer.lookupServerMediaSession("") != NULL) { // normal case
		} else { // weird case: there was no track id in the URL
		  streamName = urlSuffix;
		  trackId = NULL;
		}
	  fOurServerMediaSession = fOurServer.lookupServerMediaSession(streamName);
	  if (fOurServerMediaSession == NULL) {
		  handleCmd_notFound(cseq);
		  return;
		}

	  fOurServerMediaSession->incrementReferenceCount();

		// Set up our array of states for this session's subsessions (tracks):
	  reclaimStreamStates();
	  ServerMediaSubsessionIterator iter(*fOurServerMediaSession);
	  for (fNumStreamStates = 0; iter.next() != NULL; ++fNumStreamStates) {}
	  fStreamStates = new struct streamState[fNumStreamStates];
	  iter.reset();
	  ServerMediaSubsession* subsession;
	  for (unsigned i = 0; i < fNumStreamStates; ++i) {
		  subsession = iter.next();
		  fStreamStates[i].subsession = subsession;
		  fStreamStates[i].streamToken = NULL; // for now; reset by SETUP later
		}
	}

	// Look up information for the specified subsession (track):
  ServerMediaSubsession* subsession = NULL;
  unsigned streamNum;
  if (trackId != NULL && trackId[0] != '\0') { // normal case
	  for (streamNum = 0; streamNum < fNumStreamStates; ++streamNum) {
		  subsession = fStreamStates[streamNum].subsession;
		  if (subsession != NULL && strcmp(trackId, subsession->trackId()) == 0) break;
		}
	  if (streamNum >= fNumStreamStates) {
			// The specified track id doesn't exist, so this request fails:
		  handleCmd_notFound(cseq);
		  return;
		}
	} else {
		// Weird case: there was no track id in the URL.
		// This works only if we have only one subsession:
	  if (fNumStreamStates != 1) {
		  handleCmd_bad(cseq);
		  return;
		}
	  streamNum = 0;
	  subsession = fStreamStates[streamNum].subsession;
	}
	// ASSERT: subsession != NULL

	// Look for a "Transport:" header in the request string,
	// to extract client parameters:
  StreamingMode streamingMode;
  char* streamingModeString = NULL; // set when RAW_UDP streaming is specified
  char* clientsDestinationAddressStr;
  u_int8_t clientsDestinationTTL;
  portNumBits clientRTPPortNum, clientRTCPPortNum;
  unsigned char rtpChannelId, rtcpChannelId;
  parseTransportHeader(fullRequestStr, streamingMode, streamingModeString, fIsMulticast,
					 clientsDestinationAddressStr, clientsDestinationTTL,
					 clientRTPPortNum, clientRTCPPortNum,
					 rtpChannelId, rtcpChannelId);
  if (streamingMode == RTP_TCP && rtpChannelId == 0xFF) {
		// TCP streaming was requested, but with no "interleaving=" fields.
		// (QuickTime Player sometimes does this.)  Set the RTP and RTCP channel ids to
		// proper values:
	  rtpChannelId = fTCPStreamIdCount; rtcpChannelId = fTCPStreamIdCount+1;
	}
  fTCPStreamIdCount += 2;

  Port clientRTPPort(clientRTPPortNum);
  Port clientRTCPPort(clientRTCPPortNum);

	// Next, check whether a "Range:" header is present in the request.
	// This isn't legal, but some clients do this to combine "SETUP" and "PLAY":
  double rangeStart = 0.0, rangeEnd = 0.0;
  fStreamAfterSETUP = parseRangeHeader(fullRequestStr, rangeStart, rangeEnd) ||
										  parsePlayNowHeader(fullRequestStr);

	// Then, get server parameters from the 'subsession':
  int tcpSocketNum = streamingMode == RTP_TCP ? fClientSocket : -1;
  netAddressBits destinationAddress = 0;
  u_int8_t destinationTTL = 5;
#ifdef RTSP_ALLOW_CLIENT_DESTINATION_SETTING
  if (clientsDestinationAddressStr != NULL) {
		// Use the client-provided "destination" address.
		// Note: This potentially allows the server to be used in denial-of-service
		// attacks, so don't enable this code unless you're sure that clients are
		// trusted.
	  destinationAddress = our_inet_addr(clientsDestinationAddressStr);
	}
	// Also use the client-provided TTL.
  destinationTTL = clientsDestinationTTL;
#endif
  delete[] clientsDestinationAddressStr;
  Port serverRTPPort(0);
  Port serverRTCPPort(0);
  subsession->getStreamParameters(fOurSessionId, fClientAddr.sin_addr.s_addr,
				  clientRTPPort, clientRTCPPort,
				  tcpSocketNum, rtpChannelId, rtcpChannelId,
				  destinationAddress, destinationTTL, fIsMulticast,
				  serverRTPPort, serverRTCPPort,
				  fStreamStates[streamNum].streamToken);
  struct in_addr destinationAddr; destinationAddr.s_addr = destinationAddress;
  char* destAddrStr = strDup(our_inet_ntoa(destinationAddr));
  struct sockaddr_in sourceAddr; SOCKLEN_T namelen = sizeof sourceAddr;
  getsockname(fClientSocket, (struct sockaddr*)&sourceAddr, &namelen);
  char* sourceAddrStr = strDup(our_inet_ntoa(sourceAddr.sin_addr));
  if (fIsMulticast) {
	  switch (streamingMode) {
	  case RTP_UDP:
			  snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
								 "RTSP/1.0 200 OK\r\n"
								 "CSeq: %s\r\n"
								 "%s"
								 "Transport: RTP/AVP;multicast;destination=%s;source=%s;port=%d-%d;ttl=%d\r\n"
								 "Session: %08X\r\n\r\n",
								 cseq,
								 dateHeader(),
								 destAddrStr, sourceAddrStr, ntohs(serverRTPPort.num()), ntohs(serverRTCPPort.num()), destinationTTL,
								 fOurSessionId);
			  break;
	  case RTP_TCP:
				// multicast streams can't be sent via TCP
			  handleCmd_unsupportedTransport(cseq);
			  break;
	  case RAW_UDP:
			  snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
								 "RTSP/1.0 200 OK\r\n"
								 "CSeq: %s\r\n"
								 "%s"
								 "Transport: %s;multicast;destination=%s;source=%s;port=%d;ttl=%d\r\n"
								 "Session: %08X\r\n\r\n",
								 cseq,
								 dateHeader(),
								 streamingModeString, destAddrStr, sourceAddrStr, ntohs(serverRTPPort.num()), destinationTTL,
								 fOurSessionId);
			  break;
		}
	} else {
	  switch (streamingMode) {
	  case RTP_UDP: {
		  snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
				 "RTSP/1.0 200 OK\r\n"
				 "CSeq: %s\r\n"
				 "%s"
				 "Transport: RTP/AVP;unicast;destination=%s;source=%s;client_port=%d-%d;server_port=%d-%d\r\n"
				 "Session: %08X\r\n\r\n",
				 cseq,
				 dateHeader(),
				 destAddrStr, sourceAddrStr, ntohs(clientRTPPort.num()), ntohs(clientRTCPPort.num()), ntohs(serverRTPPort.num()), ntohs(serverRTCPPort.num()),
				 fOurSessionId);
		  break;
		}
	  case RTP_TCP: {
		  snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
				 "RTSP/1.0 200 OK\r\n"
				 "CSeq: %s\r\n"
				 "%s"
				 "Transport: RTP/AVP/TCP;unicast;destination=%s;source=%s;interleaved=%d-%d\r\n"
				 "Session: %08X\r\n\r\n",
				 cseq,
				 dateHeader(),
				 destAddrStr, sourceAddrStr, rtpChannelId, rtcpChannelId,
				 fOurSessionId);
		  break;
		}
	  case RAW_UDP: {
		  snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
				 "RTSP/1.0 200 OK\r\n"
				 "CSeq: %s\r\n"
				 "%s"
				 "Transport: %s;unicast;destination=%s;source=%s;client_port=%d;server_port=%d\r\n"
				 "Session: %08X\r\n\r\n",
				 cseq,
				 dateHeader(),
				 streamingModeString, destAddrStr, sourceAddrStr, ntohs(clientRTPPort.num()), ntohs(serverRTPPort.num()),
				 fOurSessionId);
		  break;
		}
		}
	}
  delete[] destAddrStr; delete[] sourceAddrStr; delete[] streamingModeString;
}