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); }
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; }