/****************************************************************************
 *
 *  Copyright (C) 2000-2001 RealNetworks, Inc. All rights reserved.
 *
 *  This program is free software.  It may be distributed under the terms
 *  in the file LICENSE, found in the top level of the source distribution.
 *
 */

#ifndef _RTSPPROT_H
#define _RTSPPROT_H

#include "sock.h"
#include "rtspmsg.h"
#include "tran.h"

class CRtspProtocol;

enum RtspErr
{
    RTSPE_NONE,
    RTSPE_CLOSED,
    RTSPE_NOTRAN,
    RTSPE_MAX
};

// A "pseudo-socket" for RTSP/TCP interleaved data
class CRtspInterleavedSocket : public CSocket
{
    friend class CRtspProtocol;

private:
    CRtspInterleavedSocket( const CRtspInterleavedSocket& );
    CRtspInterleavedSocket& operator=( const CRtspInterleavedSocket& );

public:
    CRtspInterleavedSocket( void );
    CRtspInterleavedSocket( CStreamResponse* pResponse );
    virtual ~CRtspInterleavedSocket( void );

    virtual bool    IsOpen( void );
    virtual void    Close( void );
    virtual size_t  Read( PVOID pbuf, size_t nLen );
    virtual size_t  Write( CPVOID pbuf, size_t nLen );

    bool Connect( UINT chan, CRtspProtocol* pProt );

    // These functions should not be called
    UINT32  GetPeerIP( void ) { assert(false); return 0; }
    void    Select( UINT32 )  { assert(false); }

protected:
    CRtspProtocol* m_pProt;
    UINT           m_chan;
    CBuffer*       m_pbuf;
};

class CRtspProtocolResponse
{
public:
    virtual void OnError( RtspErr err ) = 0;

    virtual void OnDescribeRequest( CRtspRequestMsg* pmsg ) = 0;
    virtual void OnAnnounceRequest( CRtspRequestMsg* pmsg ) = 0;
    virtual void OnGetParamRequest( CRtspRequestMsg* pmsg ) = 0;
    virtual void OnSetParamRequest( CRtspRequestMsg* pmsg ) = 0;
    virtual void OnOptionsRequest( CRtspRequestMsg* pmsg ) = 0;
    virtual void OnPauseRequest( CRtspRequestMsg* pmsg ) = 0;
    virtual void OnPlayRequest( CRtspRequestMsg* pmsg ) = 0;
    virtual void OnRecordRequest( CRtspRequestMsg* pmsg ) = 0;
    virtual void OnRedirectRequest( CRtspRequestMsg* pmsg ) = 0;
    virtual void OnSetupRequest( CRtspRequestMsg* pmsg ) = 0;
    virtual void OnTeardownRequest( CRtspRequestMsg* pmsg ) = 0;
    virtual void OnExtensionRequest( CRtspRequestMsg* pmsg ) = 0;

    virtual void OnDescribeResponse( CRtspResponseMsg* pmsg ) = 0;
    virtual void OnAnnounceResponse( CRtspResponseMsg* pmsg ) = 0;
    virtual void OnGetParamResponse( CRtspResponseMsg* pmsg ) = 0;
    virtual void OnSetParamResponse( CRtspResponseMsg* pmsg ) = 0;
    virtual void OnOptionsResponse( CRtspResponseMsg* pmsg ) = 0;
    virtual void OnPauseResponse( CRtspResponseMsg* pmsg ) = 0;
    virtual void OnPlayResponse( CRtspResponseMsg* pmsg ) = 0;
    virtual void OnRecordResponse( CRtspResponseMsg* pmsg ) = 0;
    virtual void OnRedirectResponse( CRtspResponseMsg* pmsg ) = 0;
    virtual void OnSetupResponse( CRtspResponseMsg* pmsg ) = 0;
    virtual void OnTeardownResponse( CRtspResponseMsg* pmsg ) = 0;
    virtual void OnExtensionResponse( CRtspResponseMsg* pmsg ) = 0;
};

class CRtspProtocol : public CStreamResponse
{
    //XXX: for access to m_psock, but should be more elegant
    friend class CRtspInterleavedSocket;

public:
    CRtspProtocol( CRtspProtocolResponse* pResponse );
    virtual ~CRtspProtocol( void );

    void   Init( CSocket* pSock );
    UINT32 GetNextCseq( void ) { return ++m_cseqSend; }
    void   SendRequest( CRtspRequestMsg* pmsg );
    void   SendResponse( CRtspResponseMsg* pmsg );

protected:
    // These functions handle input
    char* parseLine( void );
    void  handleReadCmd( void );
    void  handleReadHdr( void );
    void  handleReadBody( void );
    void  handleReadPkt( void );
    void  dispatchMessage( void );

protected:
    virtual void OnConnectDone( int err );
    virtual void OnReadReady  ( void );
    virtual void OnWriteReady ( void );
    virtual void OnExceptReady( void );
    virtual void OnClosed     ( void );

private:
    class CRtspRequestTag
    {
    public:
        CRtspRequestTag( UINT cseq, RtspVerb verb ) : m_cseq(cseq), m_verb(verb) {}

        //XXX: Keep rtsp version, url, etc...?
        UINT32   m_cseq;
        RtspVerb m_verb;
    };
    typedef TDoubleList<CRtspRequestTag> CRtspRequestTagList;

private:
    CRtspProtocolResponse*  m_pResponse;
    CRtspInterleavedSocket* m_ppSockets[256];

    enum ReadState {
        stFail,         // Unrecoverable error occurred
        stSync,         // Trying to resync
        stReady,        // Waiting for a command
        stPkt,          // Reading interleaved packet
        stCmd,          // Reading command (request or response line)
        stHdr,          // Reading headers
        stBody,         // Reading body (entity)
        stDispatch,     // Fully formed message
        stREADSTATE_LAST
    } m_state;

    CSocket*     m_psock;
    size_t       m_nBufLen;
    char*        m_pReadBuf;
    char*        m_pTail;

    UINT32       m_cseqSend;    // Our next cseq
    UINT32       m_cseqRecv;    // Peer's last cseq
    CRtspMsg*    m_pmsg;        // Incoming message
    size_t       m_nBodyLen;    // Length of body (entity)

    CRtspRequestTagList m_listRequestQueue; // Requests awaiting responses
};

#endif //ndef _RTSPPROT_H


syntax highlighted by Code2HTML, v. 0.9.1