/*
 *
 * @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:       RTSPSessionInterface.h

    Contains:   Presents an API for session-wide resources for modules to use.
                Implements the RTSP Session dictionary for QTSS API.
    
    
*/

#ifndef __RTSPSESSIONINTERFACE_H__
#define __RTSPSESSIONINTERFACE_H__

#include "RTSPRequestStream.h"
#include "RTSPResponseStream.h"
#include "Task.h"
#include "QTSS.h"
#include "QTSSDictionary.h"
#include "atomic.h"
#include "RTSPSession3GPP.h"

class RTSPSessionInterface : public QTSSDictionary, public Task
{
public:

    //Initialize must be called right off the bat to initialize dictionary resources
    static void     Initialize();
    static void     SetBase64Decoding(Bool16 newVal) { sDoBase64Decoding = newVal; }
    
    RTSPSessionInterface();
    virtual ~RTSPSessionInterface();
    
    //Is this session alive? If this returns false, clean up and begone as
    //fast as possible
    Bool16 IsLiveSession()      { return fSocket.IsConnected() && fLiveSession; }
    
    // Allows clients to refresh the timeout
    void RefreshTimeout()       { fTimeoutTask.RefreshTimeout(); }

    // In order to facilitate sending out of band data on the RTSP connection,
    // other objects need to have direct pointer access to this object. But,
    // because this object is a task object it can go away at any time. If # of
    // object holders is > 0, the RTSPSession will NEVER go away. However,
    // the object managing the session should be aware that if IsLiveSession returns
    // false it may be wise to relinquish control of the session
    void IncrementObjectHolderCount() { (void)atomic_add(&fObjectHolders, 1); }
    void DecrementObjectHolderCount();
    
    // If RTP data is interleaved into the RTSP connection, we need to associate
    // 2 unique channel numbers with each RTP stream, one for RTP and one for RTCP.
    // This function allocates 2 channel numbers, returns the lower one. The other one
    // is implicitly 1 greater.
    //
    // Pass in the RTSP Session ID of the Client session to which these channel numbers will
    // belong.
    UInt8               GetTwoChannelNumbers(StrPtrLen* inRTSPSessionID);

    //
    // Given a channel number, returns the RTSP Session ID to which this channel number refers
    StrPtrLen*  GetSessionIDForChannelNum(UInt8 inChannelNum);
    
    //Two main things are persistent through the course of a session, not
    //associated with any one request. The RequestStream (which can be used for
    //getting data from the client), and the socket. OOps, and the ResponseStream
    RTSPRequestStream*  GetInputStream()    { return &fInputStream; }
    RTSPResponseStream* GetOutputStream()   { return &fOutputStream; }
    TCPSocket*          GetSocket()         { return &fSocket; }
    OSMutex*            GetSessionMutex()   { return &fSessionMutex; }
    
    UInt32              GetSessionID()      { return fSessionID; }
    
    // Request Body Length
    // This object can enforce a length of the request body to prevent callers
    // of Read() from overrunning the request body and going into the next request.
    // -1 is an unknown request body length. If the body length is unknown,
    // this object will do no length enforcement. 
    void                SetRequestBodyLength(SInt32 inLength)   { fRequestBodyLen = inLength; }
    SInt32              GetRemainingReqBodyLen()                { return fRequestBodyLen; }
    
    // QTSS STREAM FUNCTIONS
    
    // Allows non-buffered writes to the client. These will flow control.
    
    // THE FIRST ENTRY OF THE IOVEC MUST BE BLANK!!!
    virtual QTSS_Error WriteV(iovec* inVec, UInt32 inNumVectors, UInt32 inTotalLength, UInt32* outLenWritten);
    virtual QTSS_Error Write(void* inBuffer, UInt32 inLength, UInt32* outLenWritten, UInt32 inFlags);
    virtual QTSS_Error Read(void* ioBuffer, UInt32 inLength, UInt32* outLenRead);
    virtual QTSS_Error RequestEvent(QTSS_EventType inEventMask);

    // performs RTP over RTSP
    QTSS_Error  InterleavedWrite(void* inBuffer, UInt32 inLen, UInt32* outLenWritten, unsigned char channel);

	// OPTIONS request
	void		SaveOutputStream();
	void		RevertOutputStream();
	void		ResetOutputStream() { fOutputStream.Reset(); fOutputStream.ResetBytesWritten();}
	void		SendOptionsRequest();
	Bool16		SentOptionsRequest() { return fSentOptionsRequest; }
	SInt32		RoundTripTime() { return fRoundTripTime; }
	
    enum
    {
        kMaxUserNameLen         = 32,
        kMaxUserPasswordLen     = 32,
        kMaxUserRealmLen        = 64
    };

    enum                        // Quality of protection
    {
        kNoQop          = 0,    // No Quality of protection
        kAuthQop        = 1,    // Authentication
        kAuthIntQop     = 2     // Authentication with Integrity        
    };
        
	// DJM PROTOTYPE
	enum
    {
        kMaxRandomDataSize		= 256 * 1024,
    };
        
protected:
    enum
    {
        kFirstRTSPSessionID     = 1,    //UInt32
    };

    //Each RTSP session has a unique number that identifies it.

    char                fUserNameBuf[kMaxUserNameLen];
    char                fUserPasswordBuf[kMaxUserPasswordLen];
    char                fUserRealmBuf[kMaxUserRealmLen];

    TimeoutTask         fTimeoutTask;//allows the session to be timed out
    
    RTSPRequestStream   fInputStream;
    RTSPResponseStream  fOutputStream;
    
    // Any RTP session sending interleaved data on this RTSP session must
    // be prevented from writing while an RTSP request is in progress
    OSMutex             fSessionMutex;
    
    // for coalescing small interleaved writes into a single TCP frame
    enum
    {
          kTCPCoalesceBufferSize = 1450 //1450 is the max data space in an TCP segment over ent
        , kTCPCoalesceDirectWriteSize = 0 // if > this # bytes bypass coalescing and make a direct write
        , kInteleaveHeaderSize = 4  // '$ '+ 1 byte ch ID + 2 bytes length
    };
    char*       fTCPCoalesceBuffer;
    SInt32      fNumInCoalesceBuffer;


    //+rt  socket we get from "accept()"
    TCPSocket           fSocket;
    TCPSocket*          fOutputSocketP;
    TCPSocket*          fInputSocketP;  // <-- usually same as fSocketP, unless we're HTTP Proxying
    
    void        SnarfInputSocket( RTSPSessionInterface* fromRTSPSession );
    
    // What session type are we?
    QTSS_RTSPSessionType    fSessionType;
    Bool16              fLiveSession;
    unsigned int        fObjectHolders;
    UInt8               fCurChannelNum;
    StrPtrLen*          fChNumToSessIDMap;  
    
    QTSS_StreamRef      fStreamRef;

    UInt32              fSessionID;
    UInt32              fLocalAddr;
    UInt32              fRemoteAddr;
    SInt32              fRequestBodyLen;
    
    UInt16              fLocalPort;
    UInt16              fRemotePort;
    
	// For OPTIONS request
	StrPtrLen				fOldOutputStreamBuffer;
	Bool16					fSentOptionsRequest;
	SInt64					fOptionsRequestSendTime;
	SInt32					fRoundTripTime;
	Bool16					fRoundTripTimeCalculation;
	
	RTSPSession3GPP         fRTSPSession3GPP;
	RTSPSession3GPP*        fRTSPSession3GPPPtr;
		
    static unsigned int sSessionIDCounter;
    static Bool16           sDoBase64Decoding;
    
	static 	UInt32			sOptionsRequestBody[kMaxRandomDataSize / sizeof(UInt32)];
	
    //Dictionary support
    
    // Param retrieval function
    static void*        SetupParams(QTSSDictionary* inSession, UInt32* outLen);
    
    static QTSSAttrInfoDict::AttrInfo   sAttributes[];
};
#endif // __RTSPSESSIONINTERFACE_H__

