void RTSPServer
::RTSPClientConnection::handleCmd_REGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/,
					   char const* url, char const* urlSuffix, char const* fullRequestStr,
					   Boolean reuseConnection, Boolean deliverViaTCP, char const* proxyURLSuffix) {
  char* responseStr;
  if (fOurRTSPServer.weImplementREGISTER(cmd, proxyURLSuffix, responseStr)) {
    // The "REGISTER"/"DEREGISTER" command - if we implement it - may require access control:
    if (!authenticationOK(cmd, urlSuffix, fullRequestStr)) return;
    
    // We implement the "REGISTER"/"DEREGISTER" command by first replying to it, then actually
    // handling it (in a separate event-loop task, that will get called after the reply has
    // been done).
    // Hack: If we're going to reuse the command's connection for subsequent RTSP commands, then we
    // delay the actual handling of the command slightly, to make it less likely that the first
    // subsequent RTSP command (e.g., "DESCRIBE") will end up in the client's reponse buffer before
    // the socket (at the far end) gets reused for RTSP command handling.
    setRTSPResponse(responseStr == NULL ? "200 OK" : responseStr);
    delete[] responseStr;
    
    ParamsForREGISTER* registerParams = new ParamsForREGISTER(cmd, this, url, urlSuffix, reuseConnection, deliverViaTCP, proxyURLSuffix);
    envir().taskScheduler().scheduleDelayedTask(reuseConnection ? DELAY_USECS_AFTER_REGISTER_RESPONSE : 0,
						(TaskFunc*)continueHandlingREGISTER, registerParams);
  } else if (responseStr != NULL) {
    setRTSPResponse(responseStr);
    delete[] responseStr;
  } else {
    handleCmd_notSupported();
  }
}
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);
	}
}
void RTSPServer
::RTSPClientConnection::handleCmd_REGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/,
					   char const* url, char const* urlSuffix, char const* fullRequestStr,
					   Boolean reuseConnection, Boolean deliverViaTCP, char const* proxyURLSuffix) {
  char* responseStr;
  if (fOurRTSPServer.weImplementREGISTER(cmd, proxyURLSuffix, responseStr)) {
    // The "REGISTER"/"DEREGISTER" command - if we implement it - may require access control:
    if (!authenticationOK(cmd, urlSuffix, fullRequestStr)) return;
    
    // We implement the "REGISTER"/"DEREGISTER" command by first replying to it, then actually handling it
    // (in a separate event-loop task, that will get called after the reply has been done):
    setRTSPResponse(responseStr == NULL ? "200 OK" : responseStr);
    delete[] responseStr;
    
    ParamsForREGISTER* registerParams = new ParamsForREGISTER(cmd, this, url, urlSuffix, reuseConnection, deliverViaTCP, proxyURLSuffix);
    envir().taskScheduler().scheduleDelayedTask(0, (TaskFunc*)continueHandlingREGISTER, registerParams);
  } else if (responseStr != NULL) {
    setRTSPResponse(responseStr);
    delete[] responseStr;
  } else {
    handleCmd_notSupported();
  }
}
void RTSPServer::RTSPClientSession::incomingRequestHandler1() {
  noteLiveness();

  struct sockaddr_in dummy; // 'from' address, meaningless in this case
  Boolean endOfMsg = False;
  unsigned char* ptr = &fRequestBuffer[fRequestBytesAlreadySeen];

  int bytesRead = readSocket(envir(), fClientSocket,
					 ptr, fRequestBufferBytesLeft, dummy);
  if (bytesRead <= 0 || (unsigned)bytesRead >= fRequestBufferBytesLeft) {
		// Either the client socket has died, or the request was too big for us.
		// Terminate this connection:
#ifdef DEBUG
	  fprintf(stderr, "RTSPClientSession[%p]::incomingRequestHandler1() read %d bytes (of %d); terminating connection!\n", this, bytesRead, fRequestBufferBytesLeft);
#endif
	  delete this;
	  return;
	}
#ifdef DEBUG
  ptr[bytesRead] = '\0';
  fprintf(stderr, "RTSPClientSession[%p]::incomingRequestHandler1() read %d bytes:%s\n", this, bytesRead, ptr);
#endif

	// Look for the end of the message: <CR><LF><CR><LF>
  unsigned char *tmpPtr = ptr;
  if (fRequestBytesAlreadySeen > 0) --tmpPtr;
			// in case the last read ended with a <CR>
  while (tmpPtr < &ptr[bytesRead-1]) {
	  if (*tmpPtr == '\r' && *(tmpPtr+1) == '\n') {
		  if (tmpPtr - fLastCRLF == 2) { // This is it:
	endOfMsg = 1;
	break;
			}
		  fLastCRLF = tmpPtr;
		}
		++tmpPtr;
	}

  fRequestBufferBytesLeft -= bytesRead;
  fRequestBytesAlreadySeen += bytesRead;

  if (!endOfMsg) return; // subsequent reads will be needed to complete the request

	// Parse the request string into command name and 'CSeq',
	// then handle the command:
  fRequestBuffer[fRequestBytesAlreadySeen] = '\0';
  char cmdName[RTSP_PARAM_STRING_MAX];
  char urlPreSuffix[RTSP_PARAM_STRING_MAX];
  char urlSuffix[RTSP_PARAM_STRING_MAX];
  char cseq[RTSP_PARAM_STRING_MAX];
  if (!parseRTSPRequestString((char*)fRequestBuffer, fRequestBytesAlreadySeen,
					  cmdName, sizeof cmdName,
					  urlPreSuffix, sizeof urlPreSuffix,
					  urlSuffix, sizeof urlSuffix,
					  cseq, sizeof cseq)) {
#ifdef DEBUG
	  fprintf(stderr, "parseRTSPRequestString() failed!\n");
#endif
	  handleCmd_bad(cseq);
	} else {
#ifdef DEBUG
	  fprintf(stderr, "parseRTSPRequestString() returned cmdName \"%s\", urlPreSuffix \"%s\", urlSuffix \"%s\"\n", cmdName, urlPreSuffix, urlSuffix);
#endif
	  if (strcmp(cmdName, "OPTIONS") == 0) {
		  handleCmd_OPTIONS(cseq);
		} else if (strcmp(cmdName, "DESCRIBE") == 0) {
		  handleCmd_DESCRIBE(cseq, urlSuffix, (char const*)fRequestBuffer);
		} else if (strcmp(cmdName, "SETUP") == 0) {
		  handleCmd_SETUP(cseq, urlPreSuffix, urlSuffix, (char const*)fRequestBuffer);
		} else if (strcmp(cmdName, "TEARDOWN") == 0
				 || strcmp(cmdName, "PLAY") == 0
				 || strcmp(cmdName, "PAUSE") == 0
				 || strcmp(cmdName, "GET_PARAMETER") == 0
				 || strcmp(cmdName, "SET_PARAMETER") == 0) {
		  handleCmd_withinSession(cmdName, urlPreSuffix, urlSuffix, cseq,
						(char const*)fRequestBuffer);
		} else {
		  handleCmd_notSupported(cseq);
		}
	}

#ifdef DEBUG
  fprintf(stderr, "sending response: %s", fResponseBuffer);
#endif
  send(fClientSocket, (char const*)fResponseBuffer, strlen((char*)fResponseBuffer), 0);

  if (strcmp(cmdName, "SETUP") == 0 && fStreamAfterSETUP) {
		// The client has asked for streaming to commence now, rather than after a
		// subsequent "PLAY" command.  So, simulate the effect of a "PLAY" command:
	  handleCmd_withinSession("PLAY", urlPreSuffix, urlSuffix, cseq,
					(char const*)fRequestBuffer);
	}

  resetRequestBuffer(); // to prepare for any subsequent request
  if (!fSessionIsActive) delete this;
}
void RTSPServer::RTSPClientSession
::handleCmd_SET_PARAMETER(ServerMediaSubsession* /*subsession*/, char const* cseq,
			  char const* /*fullRequestStr*/) {
	// By default, we don't implement "SET_PARAMETER":
  handleCmd_notSupported(cseq);
}
Exemple #6
0
bool RTSPServer::RTSPClientSession::handleRequest() {
  // Parse the request string into command name and 'CSeq',
  // then handle the command:
  char cmdName[RTSP_PARAM_STRING_MAX];
  char urlPreSuffix[RTSP_PARAM_STRING_MAX];
  char urlSuffix[RTSP_PARAM_STRING_MAX];
  char cseq[RTSP_PARAM_STRING_MAX];
  char* request = (char*)fRequestBuffer;

  if (!parseRTSPRequestString(request, strlen(request),
			      cmdName, sizeof cmdName,
			      urlPreSuffix, sizeof urlPreSuffix,
			      urlSuffix, sizeof urlSuffix,
			      cseq, sizeof cseq)) {
#ifdef DEBUG
    fprintf(stderr, "parseRTSPRequestString() failed!\n");
#endif
    handleCmd_bad(cseq);
  } else {
#ifdef DEBUG
    fprintf(stderr, "parseRTSPRequestString() returned cmdName \"%s\", urlPreSuffix \"%s\", urlSuffix \"%s\"\n", cmdName, urlPreSuffix, urlSuffix);
#endif
    if (strcmp(cmdName, "OPTIONS") == 0) {
      handleCmd_OPTIONS(cseq);
    } else if (strcmp(cmdName, "DESCRIBE") == 0) {
	  if (strlen(urlPreSuffix) > 0)
	    strcat(urlPreSuffix, "/");
	  strcat(urlPreSuffix, urlSuffix);
      handleCmd_DESCRIBE(cseq, urlPreSuffix, request);
    } else if (strcmp(cmdName, "SETUP") == 0) {
      handleCmd_SETUP(cseq, urlPreSuffix, urlSuffix, request);
    } else if (strcmp(cmdName, "TEARDOWN") == 0
	       || strcmp(cmdName, "PLAY") == 0
	       || strcmp(cmdName, "PAUSE") == 0
	       || strcmp(cmdName, "GET_PARAMETER") == 0) {
      handleCmd_withinSession(cmdName, urlPreSuffix, urlSuffix, cseq,
			      request);
    } else {
      handleCmd_notSupported(cseq);
    }
  }
    
#ifdef DEBUG
  fprintf(stderr, "sending response: %s", fResponseBuffer);
#endif
  send(fClientSocket, (char const*)fResponseBuffer, strlen((char*)fResponseBuffer), 0);

  if (strcmp(cmdName, "SETUP") == 0 && fStreamAfterSETUP) {
    // The client has asked for streaming to commence now, rather than after a
    // subsequent "PLAY" command.  So, simulate the effect of a "PLAY" command:
    handleCmd_withinSession("PLAY", urlPreSuffix, urlSuffix, cseq,
			    request);
  }

  resetRequestBuffer(); // to prepare for any subsequent request

  if (fObserver != NULL) {
	int statusCode = 0;

	sscanf((char const*)fResponseBuffer, "RTSP/1.0 %d", &statusCode);
    fObserver->requestHandled(this, statusCode);
  }

  if (!fSessionIsActive) {
    if (fObserver != NULL) {
       fObserver->clientSessionEnded(this);
	}
	
	delete this;
	return false;
  }

  return true;
}