Esempio n. 1
0
void RTSPServer::RTSPClientSession
::handleCmd_withinSession(char const* cmdName,
			  char const* urlPreSuffix, char const* urlSuffix,
			  char const* cseq, char const* fullRequestStr) {
	// This will either be:
	// - a non-aggregated operation, if "urlPreSuffix" is the session (stream)
	//	 name and "urlSuffix" is the subsession (track) name, or
	// - a aggregated operation, if "urlSuffix" is the session (stream) name,
	//	 or "urlPreSuffix" is the session (stream) name, and "urlSuffix"
	//	 is empty.
	// First, figure out which of these it is:
  if (fOurServerMediaSession == NULL) { // There wasn't a previous SETUP!
	  handleCmd_notSupported(cseq);
	  return;
	}
  ServerMediaSubsession* subsession;
  if (urlSuffix[0] != '\0' &&
		  strcmp(fOurServerMediaSession->streamName(), urlPreSuffix) == 0) {
		// Non-aggregated operation.
		// Look up the media subsession whose track id is "urlSuffix":
	  ServerMediaSubsessionIterator iter(*fOurServerMediaSession);
	  while ((subsession = iter.next()) != NULL) {
		  if (strcmp(subsession->trackId(), urlSuffix) == 0) break; // success
		}
	  if (subsession == NULL) { // no such track!
		  handleCmd_notFound(cseq);
		  return;
		}
	} else if (strcmp(fOurServerMediaSession->streamName(), urlSuffix) == 0 ||
			 strcmp(fOurServerMediaSession->streamName(), urlPreSuffix) == 0) {
		// Aggregated operation
	  subsession = NULL;
	} else { // the request doesn't match a known stream and/or track at all!
	  handleCmd_notFound(cseq);
	  return;
	}

  if (strcmp(cmdName, "TEARDOWN") == 0) {
	  handleCmd_TEARDOWN(subsession, cseq);
	} else if (strcmp(cmdName, "PLAY") == 0) {
	  handleCmd_PLAY(subsession, cseq, fullRequestStr);
	} else if (strcmp(cmdName, "PAUSE") == 0) {
	  handleCmd_PAUSE(subsession, cseq);
	} else if (strcmp(cmdName, "GET_PARAMETER") == 0) {
	  handleCmd_GET_PARAMETER(subsession, cseq, fullRequestStr);
	} else if (strcmp(cmdName, "SET_PARAMETER") == 0) {
	  handleCmd_SET_PARAMETER(subsession, cseq, fullRequestStr);
	}
}
Esempio n. 2
0
void RTSPServer::RTSPClientSession
::handleCmd_DESCRIBE(char const* cseq, char const* urlSuffix,
				 char const* fullRequestStr) {
  char* sdpDescription = NULL;
  char* rtspURL = NULL;
  do {
		  if (!authenticationOK("DESCRIBE", cseq, urlSuffix, fullRequestStr))
				  break;

		// We should really check that the request contains an "Accept:" #####
		// for "application/sdp", because that's what we're sending back #####

		// Begin by looking up the "ServerMediaSession" object for the
		// specified "urlSuffix":
	  ServerMediaSession* session = fOurServer.lookupServerMediaSession(urlSuffix);
	  if (session == NULL) {
		  handleCmd_notFound(cseq);
		  break;
		}

		// Then, assemble a SDP description for this session:
	  sdpDescription = session->generateSDPDescription();
	  if (sdpDescription == NULL) {
			// This usually means that a file name that was specified for a
			// "ServerMediaSubsession" does not exist.
		  snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
				 "RTSP/1.0 404 File Not Found, Or In Incorrect Format\r\n"
				 "CSeq: %s\r\n"
				 "%s\r\n",
				 cseq,
				 dateHeader());
		 break;
		}
	  unsigned sdpDescriptionSize = strlen(sdpDescription);

		// Also, generate our RTSP URL, for the "Content-Base:" header
		// (which is necessary to ensure that the correct URL gets used in
		// subsequent "SETUP" requests).
	  rtspURL = fOurServer.rtspURL(session, fClientSocket);

	  snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
			 "RTSP/1.0 200 OK\r\nCSeq: %s\r\n"
			 "%s"
			 "Content-Base: %s/\r\n"
			 "Content-Type: application/sdp\r\n"
			 "Content-Length: %d\r\n\r\n"
			 "%s",
			 cseq,
			 dateHeader(),
			 rtspURL,
			 sdpDescriptionSize,
			 sdpDescription);
	} while (0);

  delete[] sdpDescription;
  delete[] rtspURL;
}
Esempio n. 3
0
int RtspClientConnection::handle_describle(
										   std::string & urlPreSuffix,
										   std::string & urlSuffix,
										   std::string & fullRequestStr)
{

	std::string urlTotalSuffix = urlPreSuffix ;
	if (!urlTotalSuffix.empty()){
		urlTotalSuffix.append("/");
	}
	urlTotalSuffix.append(urlSuffix);

	//authenticationOK, add

	MediaSession * session = m_rtsp->createAttachMediaSession(urlTotalSuffix);
	if (!session){
		handleCmd_notFound();
		return -1;
	}

	const ipaddr & localAddr = m_client->get_localaddr();
	std::string sdp = session->GenerateSDPDescription(localAddr);

	//get the rtsp url
	//rtsp://127.0.0.1/
	std::string rtspUrl;

	append(rtspUrl, "rtsp://%s:%u/%s", 
		localAddr.ip, watcher::instance()->tcp_port() ,
		session->StreamName().c_str());

	std::string response = "RTSP/1.0 200 OK\r\n";

	append(response, "CSeq: %s\r\n"
					 "%s"
					 "Content-Base: %s\r\n"
					 "Content-Type: application/sdp\r\n"
					 "Content-Length: %d\r\n\r\n"
					 "%s",
					 getSeq().c_str(),
					 dateStr().c_str(),
					 rtspUrl.c_str(),
					 sdp.length(),
					 sdp.c_str());

	debug_log("S-C : %s\n", response.c_str());
	
	return post_send(response.c_str(), response.length());
}
Esempio n. 4
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;
}