474 lines
17 KiB
C++
474 lines
17 KiB
C++
/*
|
|
*
|
|
* @APPLE_LICENSE_HEADER_START@
|
|
*
|
|
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
|
|
*
|
|
* This file contains Original Code and/or Modifications of Original Code
|
|
* as defined in and that are subject to the Apple Public Source License
|
|
* Version 2.0 (the 'License'). You may not use this file except in
|
|
* compliance with the License. Please obtain a copy of the License at
|
|
* http://www.opensource.apple.com/apsl/ and read it before using this
|
|
* file.
|
|
*
|
|
* The Original Code and all software distributed under the License are
|
|
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
|
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
|
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
|
* Please see the License for the specific language governing rights and
|
|
* limitations under the License.
|
|
*
|
|
* @APPLE_LICENSE_HEADER_END@
|
|
*
|
|
*/
|
|
/*
|
|
File: RTSPClient.h
|
|
|
|
Works only for QTSS.
|
|
Assumes that different streams within a session is distinguished by trackID=
|
|
For example, streams within sample.mov would be refered to as sample.mov/trackID=4
|
|
Does not work if the URL contains digits!!!
|
|
*/
|
|
|
|
#ifndef __RTSP_CLIENT_H__
|
|
#define __RTSP_CLIENT_H__
|
|
|
|
#include "OSHeaders.h"
|
|
#include "StrPtrLen.h"
|
|
#include "TCPSocket.h"
|
|
#include "ClientSocket.h"
|
|
#include "RTPMetaInfoPacket.h"
|
|
#include "StringFormatter.h"
|
|
#include "SVector.h"
|
|
|
|
// for authentication
|
|
#include "StringParser.h"
|
|
class Authenticator
|
|
{
|
|
|
|
public:
|
|
enum { kAuthBufferLen = 1024 };
|
|
|
|
enum
|
|
{
|
|
kNoType = 0,
|
|
kBasicType = 1,
|
|
kDigestType = 2 // higher number is stronger type
|
|
};
|
|
|
|
Authenticator();
|
|
virtual ~Authenticator() {};
|
|
virtual SInt16 GetType() { return 0;};
|
|
virtual Bool16 ParseParams(StrPtrLen *authParamsPtr) {return 0;};
|
|
virtual void AttachAuthParams(StrPtrLen *theRequestPtr) {};
|
|
virtual void ResetAuthParams() {};
|
|
|
|
StrPtrLen fAuthBuffer;
|
|
|
|
StrPtrLen fNameSPL;// client
|
|
StrPtrLen fPasswordSPL;// client
|
|
StrPtrLen fRealmSPL; // server
|
|
StrPtrLen fURISPL; // client
|
|
StrPtrLen fMethodSPL; // client -- must be all caps
|
|
time_t fAuthTime;
|
|
|
|
//the outHeaderStr argument is not actually implemented
|
|
//char *GetRequestHeader( StrPtrLen *inSourceStr, StrPtrLen *searchHeaderStr,StrPtrLen *outHeaderStr = NULL);
|
|
char *GetRequestHeader( StrPtrLen *inSourceStr, StrPtrLen *searchHeaderStr);
|
|
//Does nothing if the Authorization header is not found
|
|
void RemoveAuthLine(StrPtrLen *theRequestPtr);
|
|
|
|
static Bool16 CopyParam(StrPtrLen *inPtr, StrPtrLen *outPtr);
|
|
|
|
void SetName(StrPtrLen *inNamePtr);
|
|
void SetPassword(StrPtrLen *inPasswordPtr);
|
|
void SetMethod(StrPtrLen *inMethodStr);
|
|
void SetRealm(StrPtrLen *inRealmPtr);
|
|
void SetURI(StrPtrLen *inURIPtr);
|
|
|
|
void ResetRequestLen(StrPtrLen *theRequestPtr, StrPtrLen *theParamsPtr);
|
|
void ParseTag(StringParser *parserPtr,StrPtrLen *outTagPtr);
|
|
|
|
Bool16 GetParamValue(StringParser *valueSourcePtr, StrPtrLen *outParamValuePtr);
|
|
Bool16 GetParamValueAsNewCopy(StringParser *valueSourcePtr, StrPtrLen *outParamValueCopyPtr);
|
|
Bool16 GetMatchListParamValueAsNewCopy(StringParser *valueSourcePtr, StrPtrLen *inMatchListParamValuePtr, SInt16 numToMatch, StrPtrLen *outParamValueCopyPtr);
|
|
Bool16 ParseRealm(StringParser *realmParserPtr);
|
|
|
|
static StrPtrLen sAuthorizationStr;
|
|
static StrPtrLen sRealmStr;
|
|
static StrPtrLen sAuthBasicStr;
|
|
static StrPtrLen sAuthDigestStr;
|
|
static StrPtrLen sUsernameStr;
|
|
static StrPtrLen sWildCardMatch;
|
|
static StrPtrLen sTrue;
|
|
static StrPtrLen sFalse;
|
|
|
|
void Clean();
|
|
|
|
|
|
private:
|
|
|
|
StrPtrLen fCurrentAuthLine;
|
|
};
|
|
|
|
class BasicAuth : public Authenticator
|
|
{
|
|
public:
|
|
BasicAuth() {};
|
|
~BasicAuth() {Clean();}
|
|
|
|
SInt16 GetType() { return kBasicType; };
|
|
Bool16 ParseParams(StrPtrLen *authParamsPtr);
|
|
void AttachAuthParams(StrPtrLen *theRequestPtr);
|
|
UInt32 ParamsLen(StrPtrLen *requestParams);
|
|
void ResetAuthParams() {};
|
|
protected:
|
|
enum { kEncodedBufferLen = 256 };
|
|
char fEncodedBuffer[kEncodedBufferLen];
|
|
|
|
};
|
|
|
|
class DigestAuth : public Authenticator
|
|
{
|
|
public:
|
|
|
|
SInt16 GetType() { return kDigestType; };
|
|
Bool16 ParseParams(StrPtrLen *authParamsPtr);
|
|
void AttachAuthParams(StrPtrLen *theRequestPtr);
|
|
void ResetAuthParams();
|
|
|
|
StrPtrLen fcnonce;
|
|
StrPtrLen fNonceCountStr;
|
|
SInt16 fNonceCount;
|
|
|
|
StrPtrLen fnonce;
|
|
StrPtrLen fopaque;
|
|
|
|
StrPtrLen fqop;
|
|
StrPtrLen fAlgorithmStr;
|
|
StrPtrLen fStaleStr;
|
|
StrPtrLen fURIStr;
|
|
StrPtrLen fRequestDigestStr;
|
|
|
|
SInt16 fAlgorithm;
|
|
Bool16 fStale;
|
|
|
|
void GenerateAuthorizationRequestLine(StrPtrLen *requestPtr);
|
|
DigestAuth();
|
|
~DigestAuth();
|
|
|
|
enum {kMaxReqParams = 10};
|
|
|
|
private:
|
|
|
|
struct ReqFields
|
|
{
|
|
StrPtrLen *fReqParamTags[kMaxReqParams];
|
|
StrPtrLen *fReqParamValues[kMaxReqParams];
|
|
Bool16 fQuoted[kMaxReqParams];
|
|
SInt16 fNumFields;
|
|
};
|
|
ReqFields fReqFields;
|
|
void ReqFieldsClean() { memset( (void *) fReqFields.fReqParamTags,0,sizeof(StrPtrLen *) * kMaxReqParams);
|
|
memset( (void *) fReqFields.fReqParamValues,0,sizeof(StrPtrLen *) * kMaxReqParams);
|
|
memset( (void *) fReqFields.fQuoted,0,sizeof(Bool16) * kMaxReqParams);
|
|
fReqFields.fNumFields = 0;
|
|
}
|
|
|
|
void AddAuthParam(StrPtrLen *theTagPtr, StrPtrLen *theValuePtr, Bool16 quoted);
|
|
|
|
UInt32 ParamsLen(StrPtrLen *requestParams);
|
|
void SetNonceCountStr();
|
|
void MakeRequestDigest();
|
|
void MakeCNonce();
|
|
|
|
// request tags
|
|
static StrPtrLen sCnonceStr;
|
|
static StrPtrLen sUriStr;
|
|
static StrPtrLen sResponseStr;
|
|
static StrPtrLen sNonceCountStr;
|
|
|
|
// response tags
|
|
static StrPtrLen sStaleStr;
|
|
|
|
// request and response tags
|
|
static StrPtrLen sNonceStr;
|
|
static StrPtrLen sQopStr;
|
|
static StrPtrLen sOpaqueStr;
|
|
static StrPtrLen sDomainStr;
|
|
static StrPtrLen sAlgorithmStr;
|
|
|
|
// response values
|
|
static StrPtrLen sQopAuthStr;
|
|
static StrPtrLen sQopAuthIntStr;
|
|
static StrPtrLen sMD5Str;
|
|
static StrPtrLen sMD5SessStr;
|
|
|
|
};
|
|
|
|
class AuthParser
|
|
{
|
|
public:
|
|
AuthParser() {};
|
|
~AuthParser() {}
|
|
|
|
Authenticator *ParseChallenge(StrPtrLen *challenge);
|
|
};
|
|
|
|
class RTSPClient
|
|
{
|
|
public:
|
|
|
|
//
|
|
// Before using this class, you must set the User Agent this way.
|
|
static void SetUserAgentStr(char* inUserAgent) { sUserAgent = inUserAgent; }
|
|
|
|
// verbosePrinting = print out all requests and responses
|
|
RTSPClient(ClientSocket* inSocket, Bool16 verbosePrinting = false, char* inUserAgent = NULL);
|
|
~RTSPClient();
|
|
|
|
// This must be called before any other function. Sets up very important info; sets the URL
|
|
void Set(const StrPtrLen& inURL);
|
|
|
|
//
|
|
// This function allows you to add some special-purpose headers to your
|
|
// SETUP request if you want. These are mainly used for the caching proxy protocol,
|
|
// though there may be other uses.
|
|
//
|
|
// inLateTolerance: default = 0 (don't care)
|
|
// inMetaInfoFields: default = NULL (don't want RTP-Meta-Info packets
|
|
// inSpeed: default = 1 (normal speed)
|
|
void SetSetupParams(Float32 inLateTolerance, char* inMetaInfoFields);
|
|
|
|
// Send specified RTSP request to server, wait for complete response.
|
|
// These return EAGAIN if transaction is in progress, OS_NoErr if transaction
|
|
// was successful, EINPROGRESS if connection is in progress, or some other
|
|
// error if transaction failed entirely.
|
|
OS_Error SendDescribe(Bool16 inAppendJunkData = false);
|
|
|
|
OS_Error SendReliableUDPSetup(UInt32 inTrackID, UInt16 inClientPort);
|
|
OS_Error SendUDPSetup(UInt32 inTrackID, UInt16 inClientPort);
|
|
OS_Error SendTCPSetup(UInt32 inTrackID, UInt16 inClientRTPid, UInt16 inClientRTCPid);
|
|
OS_Error SendPlay(UInt32 inStartPlayTimeInSec, Float32 inSpeed = 1, UInt32 inTrackID = kUInt32_Max); //use a inTrackID of kUInt32_Max to turn off per stream headers
|
|
OS_Error SendPacketRangePlay(char* inPacketRangeHeader, Float32 inSpeed = 1);
|
|
OS_Error SendReceive(UInt32 inStartPlayTimeInSec);
|
|
OS_Error SendAnnounce(char *sdp);
|
|
OS_Error SendTeardown();
|
|
OS_Error SendInterleavedWrite(UInt8 channel, UInt16 len, char*data,Bool16 *getNext);
|
|
|
|
OS_Error SendSetParameter();
|
|
OS_Error SendOptions();
|
|
OS_Error SendOptionsWithRandomDataRequest(SInt32 dataSize);
|
|
//
|
|
// If you just want to send a generic request, do it this way
|
|
OS_Error SendRTSPRequest(iovec* inRequest, UInt32 inNumVecs);
|
|
|
|
//
|
|
// Once you call all of the above functions, assuming they return an error, you
|
|
// should call DoTransaction until it returns OS_NoErr, then you can move onto your
|
|
// next request
|
|
OS_Error DoTransaction();
|
|
|
|
//
|
|
// If any of the tracks are being interleaved, this fetches a media packet from
|
|
// the control connection. This function assumes that SendPlay has already completed
|
|
// successfully and media packets are being sent.
|
|
OS_Error GetMediaPacket( UInt32* outTrackID, Bool16* outIsRTCP,
|
|
char** outBuffer, UInt32* outLen);
|
|
|
|
//
|
|
// If any of the tracks are being interleaved, this puts a media packet to the control
|
|
// connection. This function assumes that SendPlay has already completed
|
|
// successfully and media packets are being sent.
|
|
OS_Error PutMediaPacket( UInt32 inTrackID, Bool16 isRTCP, char* inBuffer, UInt16 inLen);
|
|
|
|
// set name and password for authentication in case we are challenged
|
|
void SetName(char *name);
|
|
void SetPassword(char *password);
|
|
|
|
// set control id string default is "trackID"
|
|
void SetControlID(char* controlID);
|
|
|
|
// level 0, 1, 2, or 3
|
|
void SetVerboseLevel(UInt32 level) { fVerboseLevel = level; }
|
|
|
|
//Sets the 3GPP-Link-Char header values; set to all 0 to not send this header
|
|
void Set3GPPLinkChars(UInt32 GBW = 0, UInt32 MBW = 0, UInt32 MTD = 0)
|
|
{
|
|
fGuarenteedBitRate = GBW;
|
|
fMaxBitRate = MBW;
|
|
fMaxTransferDelay = MTD;
|
|
}
|
|
//Use 0 for undefined
|
|
void SetBandwidth(UInt32 bps = 0) { fBandwidth = bps; }
|
|
void Set3GPPRateAdaptation(UInt32 bufferSpace = 0, UInt32 delayTime = 0)
|
|
{
|
|
fBufferSpace = bufferSpace;
|
|
fDelayTime = delayTime;
|
|
}
|
|
|
|
// ACCESSORS
|
|
|
|
StrPtrLen* GetURL() { return &fURL; }
|
|
UInt32 GetStatus() { return fStatus; }
|
|
StrPtrLen* GetSessionID() { return &fSessionID; }
|
|
UInt16 GetServerPort() { return fServerPort; }
|
|
UInt32 GetContentLength() { return fContentLength; }
|
|
char* GetContentBody() { return fRecvContentBuffer; }
|
|
ClientSocket* GetSocket() { return fSocket; }
|
|
UInt32 GetTransportMode() { return fTransportMode; }
|
|
void SetTransportMode(UInt32 theMode) { fTransportMode = theMode; };
|
|
|
|
char* GetResponse() { return fRecvHeaderBuffer; }
|
|
UInt32 GetResponseLen() { return fHeaderLen; }
|
|
Bool16 IsTransactionInProgress() { return fState != kInitial; }
|
|
Bool16 IsVerbose() { return fVerboseLevel >= 1; }
|
|
|
|
// If available, returns the SSRC associated with the track in the PLAY response.
|
|
// Returns 0 if SSRC is not available.
|
|
UInt32 GetSSRCByTrack(UInt32 inTrackID);
|
|
|
|
enum { kPlayMode=0,kPushMode=1,kRecordMode=2};
|
|
|
|
//
|
|
// If available, returns the RTP-Meta-Info field ID array for
|
|
// a given track. For more details, see RTPMetaInfoPacket.h
|
|
RTPMetaInfoPacket::FieldID* GetFieldIDArrayByTrack(UInt32 inTrackID);
|
|
|
|
enum
|
|
{
|
|
kMinNumChannelElements = 5,
|
|
kReqBufSize = 4095,
|
|
kMethodBuffLen = 24 //buffer for "SETUP" or "PLAY" etc.
|
|
};
|
|
|
|
OSMutex* GetMutex() { return &fMutex; }
|
|
|
|
private:
|
|
static char* sUserAgent;
|
|
|
|
|
|
// Helper methods
|
|
void ParseInterleaveSubHeader(StrPtrLen* inSubHeader);
|
|
void ParseRTPInfoHeader(StrPtrLen* inHeader);
|
|
void ParseRTPMetaInfoHeader(StrPtrLen* inHeader);
|
|
//Use a inTrackID of kUInt32_Max to turn the Rate-Adaptation header off
|
|
void Attach3GPPHeaders(StringFormatter &fmt, UInt32 inTrackID = kUInt32_Max);
|
|
|
|
// Call this to receive an RTSP response from the server.
|
|
// Returns EAGAIN until a complete response has been received.
|
|
OS_Error ReceiveResponse();
|
|
|
|
OSMutex fMutex;//this data structure is shared!
|
|
|
|
AuthParser fAuthenticationParser;
|
|
Authenticator *fAuthenticator; // only one will be supported
|
|
|
|
ClientSocket* fSocket;
|
|
UInt32 fVerboseLevel;
|
|
|
|
// Information we need to send the request
|
|
StrPtrLen fURL;
|
|
UInt32 fCSeq;
|
|
|
|
// authenticate info
|
|
StrPtrLen fName;
|
|
StrPtrLen fPassword;
|
|
|
|
// Response data we get back
|
|
UInt32 fStatus;
|
|
StrPtrLen fSessionID;
|
|
UInt16 fServerPort;
|
|
UInt32 fContentLength;
|
|
//StrPtrLen fRTPInfoHeader;
|
|
|
|
// Special purpose SETUP params
|
|
char* fSetupHeaders;
|
|
|
|
// If we are interleaving, this maps channel numbers to track IDs
|
|
struct ChannelMapElem
|
|
{
|
|
UInt32 fTrackID;
|
|
Bool16 fIsRTCP;
|
|
};
|
|
ChannelMapElem* fChannelTrackMap;
|
|
UInt8 fNumChannelElements;
|
|
|
|
//Maps between trackID and SSRC number
|
|
struct SSRCMapElem
|
|
{
|
|
UInt32 fTrackID;
|
|
UInt32 fSSRC;
|
|
SSRCMapElem(UInt32 trackID = kUInt32_Max, UInt32 inSSRC = 0)
|
|
: fTrackID(trackID), fSSRC(inSSRC)
|
|
{}
|
|
};
|
|
SVector<SSRCMapElem> fSSRCMap;
|
|
|
|
// For storing FieldID arrays
|
|
struct FieldIDArrayElem
|
|
{
|
|
UInt32 fTrackID;
|
|
RTPMetaInfoPacket::FieldID fFieldIDs[RTPMetaInfoPacket::kNumFields];
|
|
};
|
|
FieldIDArrayElem* fFieldIDMap;
|
|
UInt32 fNumFieldIDElements;
|
|
UInt32 fFieldIDMapSize;
|
|
|
|
// If we are interleaving, we need this stuff to support the GetMediaPacket function
|
|
char* fPacketBuffer;
|
|
UInt32 fPacketBufferOffset;
|
|
Bool16 fPacketOutstanding;
|
|
|
|
|
|
// Data buffers
|
|
char fMethod[kMethodBuffLen]; // holds the current method
|
|
char fSendBuffer[kReqBufSize + 1]; // for sending requests
|
|
char fRecvHeaderBuffer[kReqBufSize + 1];// for receiving response headers
|
|
char* fRecvContentBuffer; // for receiving response body
|
|
|
|
// Tracking the state of our receives
|
|
UInt32 fContentRecvLen;
|
|
UInt32 fHeaderRecvLen;
|
|
UInt32 fHeaderLen;
|
|
UInt32 fSetupTrackID; //is valid during a Setup Transaction
|
|
|
|
enum { kInitial, kRequestSending, kResponseReceiving, kHeaderReceived };
|
|
UInt32 fState;
|
|
|
|
//UInt32 fEventMask;
|
|
Bool16 fAuthAttempted;
|
|
UInt32 fTransportMode;
|
|
|
|
//
|
|
// For tracking media data that got read into the header buffer
|
|
UInt32 fPacketDataInHeaderBufferLen;
|
|
char* fPacketDataInHeaderBuffer;
|
|
|
|
|
|
char* fUserAgent;
|
|
static char* sControlID;
|
|
char* fControlID;
|
|
|
|
//These values are for the wireless links only -- not end-to-end
|
|
//For the following values; use 0 for undefined.
|
|
UInt32 fGuarenteedBitRate; //kbps
|
|
UInt32 fMaxBitRate; //kbps
|
|
UInt32 fMaxTransferDelay; //milliseconds
|
|
UInt32 fBandwidth; //bps
|
|
UInt32 fBufferSpace; //bytes
|
|
UInt32 fDelayTime; //milliseconds
|
|
|
|
struct InterleavedParams
|
|
{
|
|
char *extraBytes;
|
|
int extraLen;
|
|
UInt8 extraChannel;
|
|
int extraByteOffset;
|
|
};
|
|
static InterleavedParams sInterleavedParams;
|
|
|
|
};
|
|
|
|
#endif //__CLIENT_SESSION_H__
|