/**************************************************************************** * * 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( 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" ); }