/****************************************************************************
*
* 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.
*
*/
#include "types.h"
#include "dbg.h"
#include "proxytran.h"
#include "proxypkt.h"
// The UDP port range that we will use
#define MIN_UDP_PORT 6970
#define MAX_UDP_PORT 32000
CProxyTransport::CProxyTransport( void ) :
CTransport( ),
m_nPorts( 0 ),
m_portBase( 0 ),
m_protData( this ),
m_protCtrl( this ),
m_pSibling( NULL )
{
// Empty
}
CProxyTransport::~CProxyTransport( void )
{
// Empty
}
/*
* Look through the transport spec (supplied by the client) and bind to the
* appropriate local port(s), if any.
*/
bool CProxyTransport::Init( int nPorts )
{
assert( nPorts <= 2 );
if( ! nPorts ) return true;
bool bRet = false;
static UINT16 port = MIN_UDP_PORT;
UINT16 wrap = port;
do
{
if( m_protData.Init( port ) )
{
if( nPorts == 1 )
{
bRet = true;
break;
}
if( m_protCtrl.Init( port+1 ) )
{
bRet = true;
break;
}
else
{
m_protData.Close( );
}
}
port += 2;
if( port >= MAX_UDP_PORT ) port = MIN_UDP_PORT;
}
while( port != wrap );
if( bRet )
{
m_nPorts = nPorts;
m_portBase = port;
}
return bRet;
}
bool CProxyTransport::Init( int nChannels, UINT16 chan, CRtspProtocol* pProt )
{
assert( nChannels <= 2 );
if( ! nChannels ) return true;
if( !m_protData.Init( chan, pProt ) )
{
return false;
}
if( nChannels == 2 )
{
if( !m_protCtrl.Init( chan + 1, pProt ) )
{
return false;
}
}
m_nPorts = nChannels;
m_portBase = chan;
return true;
}
void CProxyTransport::Close( void )
{
m_protData.Close( );
if(m_nPorts == 2)
{
m_protCtrl.Close( );
}
}
void CProxyTransport::SetPeer( const CString& strHost, UINT16 port )
{
m_protData.SetPeer( strHost, port );
if( m_nPorts > 1 ) m_protCtrl.SetPeer( strHost, port+1 );
}
void CProxyTransport::SetPeer( const CInetAddr& host, UINT16 port )
{
m_protData.SetPeer( host, port );
if( m_nPorts > 1 ) m_protCtrl.SetPeer( host, port+1 );
}
UINT16 CProxyTransport::GetBasePort( void )
{
return m_portBase;
}
void CProxyTransport::SendPacket( UINT chan, CPacket* ppkt )
{
//assert( chan >= m_portBase && chan - m_portBase < m_nPorts );
assert( ppkt );
if( chan == 0 )
{
m_protData.SendPacket( ppkt );
}
else
{
m_protCtrl.SendPacket( ppkt );
}
}
void CProxyTransport::SetSibling(CProxyTransport * pSibling)
{
m_pSibling = pSibling;
}
void CProxyTransport::OnPacket( UINT chan, CBuffer* pbuf )
{
CProxyPacket pkt;
pkt.Set( pbuf );
m_pSibling->SendPacket( chan - m_portBase, &pkt );
}
/**************************************
*
* Passthru protocol class
*
**************************************/
CProxyTransport::CPassthruProtocol::CPassthruProtocol( CProxyTransport* pOwner ) :
m_pOwner( pOwner ),
m_pSock( NULL ),
m_chan( 0 )
{
// Empty
}
CProxyTransport::CPassthruProtocol::~CPassthruProtocol( void )
{
Close( );
}
bool CProxyTransport::CPassthruProtocol::Init( UINT16 port )
{
m_pSock = new CUdpSocket( this );
m_chan = port;
CSockAddr addr( CInetAddr::Any(), port );
if( ( ( CUdpSocket* )m_pSock )->Bind( addr ) )
{
return true;
}
delete m_pSock;
m_pSock = NULL;
return false;
}
bool CProxyTransport::CPassthruProtocol::Init( UINT16 chan, CRtspProtocol * pProt)
{
m_pSock = new CRtspInterleavedSocket( this );
m_chan = chan;
return ( ( CRtspInterleavedSocket* )m_pSock )->Connect( chan, pProt );
}
void CProxyTransport::CPassthruProtocol::Close( )
{
if( m_pSock )
{
m_pSock->Close( );
delete m_pSock;
m_pSock = NULL;
}
}
void CProxyTransport::CPassthruProtocol::SetPeer( const CString& strHost, UINT16 port )
{
( ( CUdpSocket* )m_pSock )->Connect( CSockAddr( strHost, port ) );
m_pSock->Select( SF_READ );
}
void CProxyTransport::CPassthruProtocol::SetPeer( const CInetAddr& host, UINT16 port )
{
( ( CUdpSocket* )m_pSock )->Connect( CSockAddr( host, port ) );
m_pSock->Select( SF_READ );
}
void CProxyTransport::CPassthruProtocol::SendPacket( CPacket* ppkt )
{
CProxyPacket* pproxypkt;
#ifdef NO_RTTI
pproxypkt = (CProxyPacket*)ppkt; //XXX: very bad, upgrade compiler
#else
pproxypkt = dynamic_cast<CProxyPacket*>( ppkt );
#endif
assert_or_ret( pproxypkt );
CBuffer* pbuf = pproxypkt->Get( );
assert( pbuf );
m_pSock->Write( pbuf->GetBuffer( ), pbuf->GetSize( ) );
}
void CProxyTransport::CPassthruProtocol::OnConnectDone( int err )
{
assert( false );
}
void CProxyTransport::CPassthruProtocol::OnReadReady( void )
{
CBuffer buf;
buf.SetSize( MAX_UDP_LEN+1 );
size_t len = 0;
len = m_pSock->Read( buf.GetBuffer( ), MAX_UDP_LEN+1 );
if( len )
{
if( len <= MAX_UDP_LEN + 1 )
{
buf.SetSize( len );
m_pOwner->OnPacket( m_chan, &buf );
}
else
{
dbgout( "CProxyTransport::CPassthruProtocol::OnReadReady: UDP packet too large" );
}
}
}
void CProxyTransport::CPassthruProtocol::OnWriteReady( void )
{
assert( false );
}
void CProxyTransport::CPassthruProtocol::OnExceptReady( void )
{
assert( false );
}
void CProxyTransport::CPassthruProtocol::OnClosed( void )
{
//dbgout( "CProxyTransport::CPassthruProtocol::OnClosed: socket closed" );
}
syntax highlighted by Code2HTML, v. 0.9.1