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