Logo Search packages:      
Sourcecode: helix-player version File versions

hxcloakedtcp.cpp

/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: hxcloakedtcp.cpp,v 1.7.8.2 2004/07/13 18:06:24 bobclark Exp $
 * 
 * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
 * 
 * The contents of this file, and the files included with this file,
 * are subject to the current version of the RealNetworks Public
 * Source License (the "RPSL") available at
 * http://www.helixcommunity.org/content/rpsl unless you have licensed
 * the file under the current version of the RealNetworks Community
 * Source License (the "RCSL") available at
 * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
 * will apply. You may also obtain the license terms directly from
 * RealNetworks.  You may not use this file except in compliance with
 * the RPSL or, if you have a valid RCSL with RealNetworks applicable
 * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
 * the rights, obligations and limitations governing use of the
 * contents of the file.
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL") in which case the provisions of the GPL are applicable
 * instead of those above. If you wish to allow use of your version of
 * this file only under the terms of the GPL, and not to allow others
 * to use your version of this file under the terms of either the RPSL
 * or RCSL, indicate your decision by deleting the provisions above
 * and replace them with the notice and other provisions required by
 * the GPL. If you do not delete the provisions above, a recipient may
 * use your version of this file under the terms of any one of the
 * RPSL, the RCSL or the GPL.
 * 
 * This file is part of the Helix DNA Technology. RealNetworks is the
 * developer of the Original Code and owns the copyrights in the
 * portions it created.
 * 
 * This file, and the files included with this file, is distributed
 * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
 * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
 * ENJOYMENT OR NON-INFRINGEMENT.
 * 
 * Technology Compatibility Kit Test Suite(s) Location:
 *    http://www.helixcommunity.org/content/tck
 * 
 * Contributor(s):
 * 
 * ***** END LICENSE BLOCK ***** */
#include "hlxclib/stdio.h"   
#include "hxcloakedtcp.h"

#include "safestring.h"

#include "hxnetutil.h"

#include "ihxpckts.h"
#include "hxccf.h" // IHXCommonClassFactory

#include "hxthread.h" // HXMutex
#include "hxbuffer.h" // CHXBuffer
#include "conn.h"     // TCP_BUF_SIZE
#include "dbcs.h"     // HXFindString
#include "hxmarsh.h"  // getshort()
#include "chxuuid.h"  // CHXuuid
#include "hxtick.h"   // HX_GET_TICKCOUNT
#include "rtsputil.h" // BinTo64
#include "hxfiles.h"  // CLSID_IHXRequest
#include "hxplnsp.h"  // _CIHXObjectConfiguration_SP
#include "hxcomsp.h"  // _CIHXCommonClassFactory_SP

// necessary for authentication
#include "hxmon.h"
#include "httppars.h"
#include "hxplgns.h"
#include "hxcore.h"

#include "httpclk.h"

#ifdef _MACINTOSH
#include "hx_moreprocesses.h"
#endif

/******************* HTTP Cloaking*****************/

#define QUEUE_START_SIZE    512

#define HTTPCLOAK_PUTRESPONSE_TIMEOUT     2000

#define MAX_HTTP_METHOD_BUFSIZE           2048

#define HXGUID_SIZE     16 // 16 byte GUID plus \r\n

#define ENQUEUE_DATA(x,y,z) (x)->EnQueue((y),(z))

#define ENQUEUE_BYTE(x,y) {UCHAR uChar = (y); \
            (x)->EnQueue(&uChar,sizeof(uChar));}

#define ENQUEUE_WORD(x,y) {UINT16 wTemp = (y); \
            wTemp = WToNet(wTemp); \
            (x)->EnQueue(&wTemp,sizeof(UINT16));}

#define ENQUEUE_DWORD(x,y) {ULONG32 dTemp = (y); \
            dTemp = DwToNet(dTemp); \
            (x)->EnQueue(&dTemp,sizeof(ULONG32));}

#define DEFAULT_HTTP_HEADER_LENGTH  256
#define DEFAULT_OPTION_PADDING_LENGTH     16381

#ifdef _WINCE
#define SCHED_GRANULARITY 10
#else
#define SCHED_GRANULARITY 50
#endif

enum
{
    HTTP_OK = 0,
    HTTP_GENERAL_ERROR, // for any error that is not defined below
    POST_NOT_RECEIVED,  // POST message was not received
    INVALID_GUID  // sent only if the GUID from the Player is already in use
};


/* HXClientCloakedTCPSocket */
HXClientCloakedTCPSocket::HXClientCloakedTCPSocket(IUnknown* pContext):
     m_lRefCount(0)
    ,m_pContext(pContext)
    ,m_pTCPResponse(0)
    ,m_pNetworkServices(0)
    ,m_pGetCtrl(0)
    ,m_pPutCtrl(0)
    ,m_pGetCtrlResponse(0)
    ,m_pPutCtrlResponse(0)
    ,m_bGetReadPending(FALSE)
    ,m_bPutReadPending(FALSE)
    ,m_bPutWantWritePending(FALSE)
    ,m_lForeignAddress(0)
    ,m_nForeignPort(0)
    ,m_bReadPending(FALSE)
    ,m_nRequired(0)
    ,m_pSendTCP(0)
    ,m_pReceiveGetTCP(0)
    ,m_pReceivePutTCP(0)
    ,m_pPreEncodedSendHTTP(0)
    ,m_pPostEncodedSendHTTP(0)
    ,m_pOutBuf(0)
    ,m_pOutEncodedBuf(0)
    ,m_pInBuf(0)
    ,m_bConnected(FALSE)
    ,m_pForiegnHost(0)
    ,m_pGuid(0)
    ,m_bGetConnectDone(FALSE)
    ,m_bPutConnectDone(FALSE)
    ,m_bGetConnectSuccessful(FALSE)
    ,m_bPutConnectSuccessful(FALSE)
    ,m_bConnectResponsePending(TRUE)
    ,m_bOptionsReceived(FALSE)
    ,m_bUseExactContentLength(FALSE)
    ,m_bCloseHttpAfterWrite(FALSE)
    ,m_bMustCloseHTTP(FALSE)
    ,m_bHttpInitialized(FALSE)
    ,m_LastError(HXR_OK)
    ,m_pHTTPHeaderBuffer(0)
    ,m_nHTTPHeaderBufferLength(0)
    ,m_bHTTPGetHeaderReadDone(FALSE)
    ,m_bHTTPPutHeaderReadDone(FALSE)
    ,m_pProxyHostName(0)
    ,m_nProxyPortNumber(0)
    ,m_bInDestructor(FALSE)
    ,m_pScheduler(0)
    ,m_pSchedulerCallback(0)
    ,m_pNonInterruptCallback(0)
    ,m_bInDoRead(FALSE)
    ,m_bInDoGetWrite(FALSE)
    ,m_bInDoPutWrite(FALSE)
    ,m_bInTransferBuffers(FALSE)
    ,m_bInitComplete(FALSE)
    ,m_bDeletePadding(FALSE)
    ,m_uPadLength(10+DEFAULT_OPTION_PADDING_LENGTH) // 10 for the opts and 16381 for the padding
    ,m_pInterruptState(NULL)
    ,m_pResponseInterruptSafe(NULL)
    ,m_pMutex(NULL)
    ,m_pCloakValues(NULL)
    ,m_pCloakContext(NULL)
    ,m_bGetResponsed(FALSE)
    ,m_bPutResponsed(FALSE)
    ,m_pszGetServerIP(NULL)
    ,m_pszPutServerIP(NULL)
    ,m_bReconnectToSameServerIP(FALSE)
    ,m_bConnectToSameServerIP(FALSE)
    ,m_pPreferredTransport(NULL)
    ,m_pPreferredTransportManager(NULL)
#ifdef _MACINTOSH
    ,m_pAuthenticationCallback(NULL)
#endif
    ,m_bInAuthenticationKludge(FALSE)
{
    if(m_pContext)
    {
      m_pContext->AddRef();
      m_pContext->QueryInterface(IID_IHXScheduler, (void**) &m_pScheduler);
      m_pContext->QueryInterface(IID_IHXNetworkServices, (void**) &m_pNetworkServices);
      m_pContext->QueryInterface(IID_IHXInterruptState, (void**) &m_pInterruptState);
      m_pContext->QueryInterface(IID_IHXPreferredTransportManager, (void**)&m_pPreferredTransportManager);
    }

#if defined(THREADS_SUPPORTED) 
    HXMutex::MakeMutex(m_pMutex);
#elif defined(_UNIX_THREADED_NETWORK_IO)
    if( ReadNetworkThreadingPref((IUnknown*)pContext) )
    {
        HXMutex::MakeMutex(m_pMutex);
    }
    else
    { 
        HXMutex::MakeStubMutex(m_pMutex);
    }
#else
    HXMutex::MakeStubMutex(m_pMutex);
#endif

#ifdef _MACINTOSH
    m_pAuthenticationCallback = new MacCloakedTCPSocketAuthenticationCallback(this);
    m_pAuthenticationCallback->AddRef();
#endif
}

HXClientCloakedTCPSocket::~HXClientCloakedTCPSocket()
{
    m_bInDestructor = TRUE;
    
    m_pMutex->Lock();

#ifdef _MACINTOSH
    if (m_pAuthenticationCallback && m_pAuthenticationCallback->m_ulPendingCallbackID &&
            m_pScheduler)
    {
      m_pScheduler->Remove(m_pAuthenticationCallback->m_ulPendingCallbackID);
      m_pAuthenticationCallback->m_ulPendingCallbackID = NULL;
    }
    HX_RELEASE(m_pAuthenticationCallback);
#endif

    while (m_PendingWriteBuffers.GetCount() > 0)
    {
      IHXBuffer* pBuffer = (IHXBuffer*) m_PendingWriteBuffers.RemoveHead();
      pBuffer->Release();
    }

    FlushQueues();

    /* Send a final HTTP done message */
    if (m_bHttpInitialized)
    {
      SendHTTPDone();
    }

    if (m_pSchedulerCallback)
    {
      m_pSchedulerCallback->Unschedule(m_pScheduler);
      HX_RELEASE(m_pSchedulerCallback);
    }

    if (m_pNonInterruptCallback)
    {
      m_pNonInterruptCallback->Unschedule(m_pScheduler);
      HX_RELEASE(m_pNonInterruptCallback);
    }

    HX_RELEASE(m_pGetCtrl);
    HX_RELEASE(m_pPutCtrl);
    HX_RELEASE(m_pGetCtrlResponse);
    HX_RELEASE(m_pPutCtrlResponse);

    HX_RELEASE(m_pCloakValues);
    HX_RELEASE(m_pCloakContext);
    HX_RELEASE(m_pTCPResponse);
    HX_RELEASE(m_pNetworkServices);

    HX_DELETE(m_pSendTCP);
    HX_DELETE(m_pReceiveGetTCP);
    HX_DELETE(m_pReceivePutTCP);
    HX_DELETE(m_pPreEncodedSendHTTP);
    HX_DELETE(m_pPostEncodedSendHTTP);

    HX_VECTOR_DELETE(m_pInBuf);
    HX_VECTOR_DELETE(m_pOutBuf);
    HX_VECTOR_DELETE(m_pOutEncodedBuf);
    HX_VECTOR_DELETE(m_pForiegnHost);
    HX_VECTOR_DELETE(m_pGuid);
    HX_VECTOR_DELETE(m_pHTTPHeaderBuffer);
    HX_VECTOR_DELETE(m_pProxyHostName);
    HX_VECTOR_DELETE(m_pszGetServerIP);
    HX_VECTOR_DELETE(m_pszPutServerIP);

    HX_RELEASE(m_pPreferredTransport);
    HX_RELEASE(m_pPreferredTransportManager);
    HX_RELEASE(m_pInterruptState);
    HX_RELEASE(m_pResponseInterruptSafe);
    HX_RELEASE(m_pScheduler);

    HX_RELEASE(m_pContext);
    m_pMutex->Unlock();
    HX_DELETE(m_pMutex);
}

STDMETHODIMP HXClientCloakedTCPSocket::QueryInterface(REFIID riid, void** ppvObj)
{
    QInterfaceList qiList[] =
        {
            { GET_IIDHANDLE(IID_IHXTCPSocket), (IHXTCPSocket*)this },
            { GET_IIDHANDLE(IID_IHXCloakedTCPSocket), (IHXCloakedTCPSocket*)this },
            { GET_IIDHANDLE(IID_IHXHTTPProxy), (IHXHTTPProxy*)this },
            { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXTCPSocket*)this },
        };
    
    return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
}

STDMETHODIMP_(ULONG32) HXClientCloakedTCPSocket::AddRef()
{
    return InterlockedIncrement(&m_lRefCount);
}

STDMETHODIMP_(ULONG32) HXClientCloakedTCPSocket::Release()
{
    if (InterlockedDecrement(&m_lRefCount) > 0)
    {
        return m_lRefCount;
    }

    delete this;
    return 0;
}

STDMETHODIMP HXClientCloakedTCPSocket::Init(IHXTCPResponse* pTCPResponse)
{
    HX_RESULT rc = HXR_OK;

    if (!pTCPResponse)
    {
      return HXR_UNEXPECTED;
    }

    if (!m_pSchedulerCallback)
    {
      m_pSchedulerCallback = new ScheduledSocketCallback(this, TRUE);
      m_pSchedulerCallback->AddRef();
    }

    if (!m_pNonInterruptCallback)
    {
      m_pNonInterruptCallback = new ScheduledSocketCallback(this, TRUE);
      m_pNonInterruptCallback->AddRef();
    }

    m_pTCPResponse = pTCPResponse;
    m_pTCPResponse->AddRef();

    m_pTCPResponse->QueryInterface(IID_IHXInterruptSafe, 
                           (void**) &m_pResponseInterruptSafe);

    if (!m_pNetworkServices)
    {
      return HXR_FAILED;
    }
    
    if (HXR_OK != m_pNetworkServices->CreateTCPSocket(&m_pGetCtrl))
    {
      return HXR_FAILED;
    }

    if (HXR_OK != m_pNetworkServices->CreateTCPSocket(&m_pPutCtrl))
    {
      return HXR_FAILED;
    }

    m_pGetCtrlResponse = new HTTPCloakTCPResponse(this, TRUE);
    m_pPutCtrlResponse = new HTTPCloakTCPResponse(this, FALSE);
    if (!m_pGetCtrlResponse || !m_pPutCtrlResponse)
    {
      return HXR_OUTOFMEMORY;
    }

    m_pGetCtrlResponse->AddRef();
    m_pPutCtrlResponse->AddRef();

    if (HXR_OK != m_pGetCtrl->Init(m_pGetCtrlResponse) || 
            HXR_OK != m_pPutCtrl->Init(m_pPutCtrlResponse))
    {
      return HXR_FAILED;
    }

    if (HXR_OK != m_pGetCtrl->Bind(HXR_INADDR_ANY, 0) || 
            HXR_OK != m_pPutCtrl->Bind(HXR_INADDR_ANY, 0))
    {
      return HXR_FAILED;
    }

    // allocate TCP send and receive queue
    m_pSendTCP = new CByteGrowingQueue(QUEUE_START_SIZE,1);
    if (!m_pSendTCP || !m_pSendTCP->IsQueueValid())
    {
      return HXR_OUTOFMEMORY;
    }
    m_pSendTCP->SetMaxSize(TCP_BUF_SIZE);

    m_pReceiveGetTCP = new CByteGrowingQueue(QUEUE_START_SIZE,1);
    if (!m_pReceiveGetTCP || !m_pReceiveGetTCP->IsQueueValid())
    {
      return HXR_OUTOFMEMORY;
    }
    m_pReceiveGetTCP->SetMaxSize(TCP_BUF_SIZE);

    m_pPreEncodedSendHTTP = new CByteGrowingQueue(QUEUE_START_SIZE,1);
    if (!m_pPreEncodedSendHTTP || !m_pPreEncodedSendHTTP->IsQueueValid())
    {
      return HXR_OUTOFMEMORY;
    }

    /* Approx. MAX POST header size : 3000*/
    m_pPreEncodedSendHTTP ->SetMaxSize((TCP_BUF_SIZE-1)/2 - 3000);

    m_pPostEncodedSendHTTP = new CByteGrowingQueue(QUEUE_START_SIZE,1);
    if (!m_pPostEncodedSendHTTP || !m_pPostEncodedSendHTTP->IsQueueValid())
    {
      return HXR_OUTOFMEMORY;
    }
    m_pPostEncodedSendHTTP->SetMaxSize(TCP_BUF_SIZE);
    
    m_pInBuf = new char[TCP_BUF_SIZE];
    if (!m_pInBuf)
    {
      return HXR_OUTOFMEMORY;
    }

    m_pOutBuf = new char[TCP_BUF_SIZE];
    if (!m_pOutBuf)
    {
      return HXR_OUTOFMEMORY;
    }

    m_pOutEncodedBuf = new char[TCP_BUF_SIZE];
    if (!m_pOutEncodedBuf)
    {
      return HXR_OUTOFMEMORY;
    }

    CreateGuid();

    return HXR_OK;
}

STDMETHODIMP HXClientCloakedTCPSocket::SetResponse(IHXTCPResponse* pTCPResponse)
{
    m_pMutex->Lock();
    HX_RELEASE(m_pTCPResponse);
    m_pTCPResponse = pTCPResponse;
    m_pTCPResponse->AddRef();

    HX_RELEASE(m_pResponseInterruptSafe);
    m_pTCPResponse->QueryInterface(IID_IHXInterruptSafe, 
                           (void**) &m_pResponseInterruptSafe);
    m_pMutex->Unlock();
    return HXR_OK;
}

STDMETHODIMP HXClientCloakedTCPSocket::Bind(UINT32 ulLocalAddr, UINT16 nPort)
{
    return HXR_NOTIMPL;
}

STDMETHODIMP HXClientCloakedTCPSocket::Connect(const char* pDestination,
                                    UINT16          nPort)
{
    m_nForeignPort = nPort;

    HX_VECTOR_DELETE(m_pForiegnHost);
    m_pForiegnHost = new char [strlen(pDestination) + 1];
    if (!m_pForiegnHost)
    {
      return HXR_OUTOFMEMORY;
    }

    ::strcpy(m_pForiegnHost, pDestination); /* Flawfinder: ignore */

    // m_pCloakValues is only set by RTSP
    if (m_pPreferredTransportManager && m_pCloakValues)
    {
      HX_RELEASE(m_pPreferredTransport);
      m_pPreferredTransportManager->GetPrefTransport(m_pForiegnHost,
                                           PTP_RTSP,
                                           m_pPreferredTransport);

      HX_ASSERT(m_pPreferredTransport);
      if (m_pPreferredTransport)
      {
          m_bConnectToSameServerIP = m_pPreferredTransport->GetHTTPNG();
      }
    }

    return  ActualConnect();
}

STDMETHODIMP HXClientCloakedTCPSocket::Read(UINT16 uSize)
{
    HX_RESULT     theErr      = HXR_OK;
    HX_RESULT     lResult = HXR_OK;

    if (m_bReadPending)
    {
      return HXR_UNEXPECTED;
    }

    m_bReadPending  = TRUE;
    m_nRequired       = uSize;

    m_pMutex->Lock();
    theErr  = DoRead();
    m_pMutex->Unlock();
    lResult = ConvertNetworkError(theErr);

    return lResult;
}

STDMETHODIMP HXClientCloakedTCPSocket::Write(IHXBuffer* pBuffer)
{
    HX_RESULT     theErr      = HXR_OK;
    HX_RESULT     lResult = HXR_OK;

    pBuffer->AddRef();
    m_PendingWriteBuffers.AddTail((void*) pBuffer);
    
    m_pMutex->Lock();
    theErr = DoPutWrite();
    m_pMutex->Unlock();
    lResult = ConvertNetworkError(theErr);

    return lResult;
}

STDMETHODIMP HXClientCloakedTCPSocket::WantWrite()
{
    m_pTCPResponse->WriteReady(HXR_OK);

    return HXR_OK;
}

STDMETHODIMP HXClientCloakedTCPSocket::GetLocalAddress(ULONG32& lAddress)
{
    return HXR_NOTIMPL;
}

STDMETHODIMP HXClientCloakedTCPSocket::GetForeignAddress(ULONG32& lAddress)
{
    if(m_bConnected && m_lForeignAddress)
    {
      lAddress = m_lForeignAddress;
      return HXR_OK;
    }
    return HXR_FAIL;
}

STDMETHODIMP HXClientCloakedTCPSocket::GetLocalPort(UINT16& port)
{
    return HXR_NOTIMPL;
}

STDMETHODIMP HXClientCloakedTCPSocket::GetForeignPort(UINT16& port)
{
    if(m_bConnected)
    {
      port = m_nForeignPort;
      return HXR_OK;
    }
    return HXR_FAIL;
}

/*
 *    IHXHTTPProxy methods
 *
 *  Network addresses and ports are in native byte order
 *  
 */

STDMETHODIMP HXClientCloakedTCPSocket::SetProxy(
                            const char*       /*IN*/  pProxyHostName,
                            UINT16      /*IN*/  nPort)
{
    if(pProxyHostName == 0 || *pProxyHostName == 0) 
    {
      return HXR_FAILED;
    }
    
    HX_VECTOR_DELETE(m_pProxyHostName);
    m_pProxyHostName = new char[::strlen(pProxyHostName) + 1];
    if (!m_pProxyHostName)
    {
      return HXR_OUTOFMEMORY;
    }

    ::strcpy(m_pProxyHostName, pProxyHostName); /* Flawfinder: ignore */
    m_nProxyPortNumber = nPort;

    return HXR_OK;
}

/************************************************************************
 *    Method:
 *        IHXCloakedTCPSocket::InitCloak
 */
STDMETHODIMP
HXClientCloakedTCPSocket::InitCloak(IHXValues* /*IN*/  pValues, IUnknown* pUnknown)
{
    HX_RESULT     rc = HXR_OK;

    if (pValues)
    {
      m_pCloakValues = pValues;
      m_pCloakValues->AddRef();
    }
    if (pUnknown)
    {
      m_pCloakContext = pUnknown;
      m_pCloakContext->AddRef();
    }

    return rc;
}

HX_RESULT
HXClientCloakedTCPSocket::DoRead()
{
    HX_RESULT theErr = HXR_OK;
    char*   pStartAfterDoubleReturn = 0;
    UINT16 count = 0;

    if(m_bInDoRead)
    {
      return HXR_OK;
    }

    m_bInDoRead = TRUE;

    if (m_LastError)
    {
      goto exit;
    }

    // m_pReceivePutTCP is only initialized if we receive POST response
    // from the server
    if (m_pReceivePutTCP)
    {
      count = m_pReceivePutTCP->GetMaxAvailableElements();
    }
    else
    {
      count = TCP_BUF_SIZE;
    }

    // attempt to read from PUT if:
    // * we haven't initiated PUT read already AND
    // * we haven't received the complete POST response header AND
    // * we are not in multi-POST mode
    if (count > 0           && 
      !m_bPutReadPending          && 
      !m_bHTTPPutHeaderReadDone   &&
      !m_bMustCloseHTTP)
    {
      // attempt to read data from TCP link
      m_bPutReadPending = TRUE;
      theErr = m_pPutCtrl->Read(count);
    }

    // check how much room we have in TCP receive queue
    count = m_pReceiveGetTCP->GetMaxAvailableElements();
    if (count > 0 && !m_bGetReadPending)
    {
      // attempt to read data from TCP link
      m_bGetReadPending = TRUE;
      theErr = m_pGetCtrl->Read(count);
      switch(theErr)
      {
          case HXR_AT_INTERRUPT:                
          case HXR_WOULD_BLOCK:
          case HXR_OK:
            // mask out these errors
            theErr = HXR_OK;
            break;

          default:
            theErr = ConvertNetworkError(theErr);
            break;
      }
    }

exit:
    if (theErr && !m_LastError)
    {
      m_LastError = theErr;
    }

    if (m_LastError)
    {
      if (m_bReadPending)
      {
          if (IsSafe())
          {
            m_bReadPending = FALSE;
            m_pTCPResponse->ReadDone(m_LastError, 0);
          }
      }
    }
    else
    {
      count = m_pReceiveGetTCP->GetQueuedItemCount();

      if (m_bReadPending && count > 0 && m_bOptionsReceived 
          && m_bHTTPGetHeaderReadDone)
      {
          /* mask any kind of errors */
          theErr = HXR_OK;

          if (IsSafe())
          {
            m_bReadPending = FALSE;
            if (m_nRequired < count)
            {
                count = m_nRequired;
            }

            CHXBuffer* pBuffer = new CHXBuffer;
            pBuffer->AddRef();
            m_pReceiveGetTCP->DeQueue(m_pInBuf, count);
            pBuffer->Set((UCHAR*) m_pInBuf, count);
            
            m_pTCPResponse->ReadDone(HXR_OK, pBuffer);
            pBuffer->Release();
          }
      }

      if (m_pSchedulerCallback && m_bReadPending)
      {
          m_pSchedulerCallback->ScheduleCallback(CLOAKED_TCP_READ_COMMAND, m_pScheduler, SCHED_GRANULARITY);
      }
    }
 
    m_bInDoRead = FALSE;
    return theErr;
}

HX_RESULT
HXClientCloakedTCPSocket::DoGetWrite()
{
    HX_RESULT theErr = HXR_OK;

    if (m_bInDoGetWrite)
    {
      return HXR_OK;
    }

    m_bInDoGetWrite = TRUE;

    // check how data we have in TCP send queue
    UINT16 count    = m_pSendTCP->GetQueuedItemCount();
    UINT16 actual   = count;
    
    if(count > 0) 
    {
      m_pSendTCP->DeQueue(m_pOutBuf,count);
      CHXBuffer* pBuffer = new CHXBuffer;
      pBuffer->AddRef();
      pBuffer->Set((UCHAR*) m_pOutBuf, (ULONG32) count);
      theErr = m_pGetCtrl->Write(pBuffer);
      pBuffer->Release();
    }
    
    if (theErr)
    {
      switch(theErr)
      {
          case HXR_AT_INTERRUPT:                
          case HXR_WOULD_BLOCK:
            m_pSendTCP->EnQueue(m_pOutBuf, count);
            // mask out these errors
            theErr = HXR_OK;
            break;

          default:
            theErr = ConvertNetworkError(theErr);
            break;
      }
    }

    if (!theErr && !m_bInDestructor &&
      m_pSendTCP->GetQueuedItemCount() > 0 ) {
          m_pSchedulerCallback->ScheduleCallback(CLOAKED_TCP_GETWRITE_COMMAND, m_pScheduler, SCHED_GRANULARITY);
    }

    m_bInDoGetWrite = FALSE;
    return theErr;
}

HX_RESULT
HXClientCloakedTCPSocket::DoPutWrite()
{
    HX_RESULT theErr = HXR_OK;

    if (m_bInDoPutWrite)
    {
      return HXR_OK;
    }

    m_bInDoPutWrite = TRUE;

    /* Transfer pending buffers to TCP send queue */
    if (m_bOptionsReceived && m_pPostEncodedSendHTTP->GetQueuedItemCount() == 0 && !m_bPutWantWritePending)
    {
      TransferBuffers();
    }

    if (!m_bPutConnectDone)
    {
      goto exit;
    }

    // check how data we have in TCP send queue
    UINT16 count;
    UINT16 actual;
    
    count    = m_pPostEncodedSendHTTP->GetQueuedItemCount();
    actual   = count;

    if(count > 0) 
    {
      m_pPostEncodedSendHTTP->DeQueue(m_pOutEncodedBuf,count);
      CHXBuffer* pBuffer = new CHXBuffer;
      pBuffer->AddRef();
      pBuffer->Set((UCHAR*) m_pOutEncodedBuf, (ULONG32) count);
      theErr = m_pPutCtrl->Write(pBuffer);
      pBuffer->Release();
      m_bPutWantWritePending  = TRUE;
      m_pPutCtrl->WantWrite();
    }
    
    if (theErr)
    {
      switch(theErr)
      {
          case HXR_AT_INTERRUPT:                
          case HXR_WOULD_BLOCK:
            m_pPostEncodedSendHTTP->EnQueue(m_pOutEncodedBuf, count);
            // mask out these errors
            theErr = HXR_OK;
            break;

          default:
            theErr = ConvertNetworkError(theErr);
            break;
      }
    }

exit:

    if (!theErr && !m_bInDestructor &&
      (m_pPostEncodedSendHTTP->GetQueuedItemCount() > 0 ||
       m_PendingWriteBuffers.GetCount() > 0)){
          m_pSchedulerCallback->ScheduleCallback(CLOAKED_TCP_PUTWRITE_COMMAND, m_pScheduler, SCHED_GRANULARITY);
    }

    if (!theErr)
    {
      theErr = DoGetWrite();
    }

    m_bInDoPutWrite = FALSE;

    return theErr;
}

void 
HXClientCloakedTCPSocket::GetConnectDone(BOOL bResult)
{
    m_bGetConnectDone = TRUE;

    if (!m_bInDestructor)
    {
      AddRef();
    }

    if (bResult == TRUE)
    {
      m_bGetConnectSuccessful = TRUE;
      m_pGetCtrl->GetForeignAddress(m_lForeignAddress);
    }
    else
    {
      m_bGetConnectSuccessful = FALSE;
    }

    // PUT connection has to been done at this point
    if (m_bPutConnectDone && m_bConnectResponsePending)
    {
      m_bConnectResponsePending = FALSE;

      // either its HTTP-NG server or we are in re-GET mode
      // where we send GET to the same serverIP returned from
      // POST response
      if (m_bConnectToSameServerIP || m_bReconnectToSameServerIP)
      {
          if (m_bPutConnectSuccessful && m_bGetConnectSuccessful)
          {
            m_bConnected = TRUE;
            m_pMutex->Lock();
            PrepareGetMessage();
            DoGetWrite();
            Read(TCP_BUF_SIZE);
            m_pMutex->Unlock();
            if (m_bConnectToSameServerIP)
            {
                // we haven't call ConnectDone yet
                m_pTCPResponse->ConnectDone(HXR_OK);
            }
            else if (m_bReconnectToSameServerIP)
            {
                // we already called ConnectDone upon the initial
                // GET/POST connect done
                Read(TCP_BUF_SIZE);
            }
          }
          else
          {
            m_pTCPResponse->ConnectDone(HXR_NET_CONNECT);
          }
      }
      // don't know the server type yet, keep the old behavior
      // where we send both GET and POST
      else
      {
          if (m_bPutConnectSuccessful && m_bGetConnectSuccessful)
          {
            m_bConnected = TRUE;
            m_pMutex->Lock();
            PreparePostMessage(NULL, 0);
            DoPutWrite();
            PrepareGetMessage();
            DoGetWrite();
            m_pMutex->Unlock();
            m_pTCPResponse->ConnectDone(HXR_OK);
          }
          else
          {
            m_pTCPResponse->ConnectDone(HXR_NET_CONNECT);
          }

      }
    }
      
    if (!m_bInDestructor)
    {
        Release();
    }
}

void 
HXClientCloakedTCPSocket::PutConnectDone(BOOL bResult)
{
    HX_RESULT theErr = HXR_OK;
    m_bPutConnectDone = TRUE;

    if (!m_bInDestructor)
    {
      AddRef();
    }

    if (bResult == TRUE)
    {
      m_bPutConnectSuccessful = TRUE;
    }
    else
    {
      m_bPutConnectSuccessful = FALSE;
    }

    // it's HTTP-NG server, we send POST first
    if (m_bConnectToSameServerIP)
    {
      if (m_bPutConnectSuccessful)
      {
          m_pMutex->Lock();
          PreparePostMessage(NULL, 0);
          DoPutWrite();
          if (!m_bPutReadPending)
          {
            m_bPutReadPending = TRUE;
            m_pPutCtrl->Read(TCP_BUF_SIZE);
          }
          m_pMutex->Unlock();
      }
      else
      {
          m_pTCPResponse->ConnectDone(HXR_NET_CONNECT);
      }
    }
    // don't know the server type yet, so we send both POST
    // and GET
    else if (m_bGetConnectDone && m_bConnectResponsePending)
    {
      m_bConnectResponsePending = FALSE;
      if (m_bPutConnectSuccessful && m_bGetConnectSuccessful)
      {
          m_bConnected = TRUE;
          m_pMutex->Lock();
          PreparePostMessage(NULL, 0);
          DoPutWrite();
          PrepareGetMessage();
          theErr = DoGetWrite();
          m_pMutex->Unlock();
          m_pTCPResponse->ConnectDone(HXR_OK);
      }
      else
      {
          m_pTCPResponse->ConnectDone(HXR_NET_CONNECT);
      }
    }

    if (!m_bInDestructor)
    {
      Release();
    }

    if (m_bConnected && m_pPostEncodedSendHTTP->GetQueuedItemCount() > 0)
    {
      m_pMutex->Lock();
      DoPutWrite();
      m_pMutex->Unlock();
    }
}

HX_RESULT               
HXClientCloakedTCPSocket::DoGetReadDone(HX_RESULT   status, IHXBuffer* pInBuffer)
{
    HX_RESULT     theErr                  = HXR_OK;
    char*   pStartAfterDoubleReturn = 0;
    UINT16  count = 0;

    if (AuthenticationRequired(status, pInBuffer))
    {
      return HXR_OK;
    }

    m_pMutex->Lock();

    m_bGetReadPending = FALSE;
    if (status != HXR_OK && m_LastError == HXR_OK)
    {
      m_LastError = status;
    }

    if (m_LastError)
    {
      goto exit;
    }

    if (pInBuffer)
    {
      m_pReceiveGetTCP->EnQueue(pInBuffer->GetBuffer(), (UINT16) pInBuffer->GetSize());
    }

    count = m_pReceiveGetTCP->GetQueuedItemCount();

    /*
     * if the 16k padding was not received in one big packet
     * delete the remaining padding
     */
    if (m_bDeletePadding && m_uPadLength > 0)
    {
      UINT16 len = (m_uPadLength <= count ? m_uPadLength : count); 
      BYTE* tmpBuf = new BYTE[len];
      
      m_pReceiveGetTCP->DeQueue(tmpBuf, len);
      m_uPadLength -= len;

      if (m_uPadLength == 0)
      {
          m_bDeletePadding = FALSE;
      }
      HX_VECTOR_DELETE(tmpBuf);
      count = m_pReceiveGetTCP->GetQueuedItemCount();
    }

    if (!theErr && !m_bHTTPGetHeaderReadDone && count >= 2 )
    {
      char* pEndLineLocation = 0;

      if (!m_pHTTPHeaderBuffer || m_nHTTPHeaderBufferLength < count+1)
      {
          HX_VECTOR_DELETE(m_pHTTPHeaderBuffer);
          m_nHTTPHeaderBufferLength = count+1 > DEFAULT_HTTP_HEADER_LENGTH ?
                              count+1 : DEFAULT_HTTP_HEADER_LENGTH;
          m_pHTTPHeaderBuffer = new char[m_nHTTPHeaderBufferLength];
          if (!m_pHTTPHeaderBuffer)
          {
            theErr = HXR_OUTOFMEMORY;
            goto exit;
          }
      }

      m_pReceiveGetTCP->DeQueue(m_pHTTPHeaderBuffer, count);
      m_pHTTPHeaderBuffer[count] = '\0';

      if ((pEndLineLocation = (char*) HXFindString(m_pHTTPHeaderBuffer, "\n\n")) ||
          (pEndLineLocation = (char*) HXFindString(m_pHTTPHeaderBuffer, "\r\r")) )
      {
          pStartAfterDoubleReturn = pEndLineLocation+2;
          m_bHTTPGetHeaderReadDone = TRUE;
      }
      else if (count >= 4 &&
          (pEndLineLocation = (char*) HXFindString(m_pHTTPHeaderBuffer, "\r\n\r\n")))
      {
          pStartAfterDoubleReturn = pEndLineLocation+4;
          m_bHTTPGetHeaderReadDone = TRUE;
      }
      else
      {
          /* Put back everything in receive queue*/
          m_pReceiveGetTCP->EnQueue(m_pHTTPHeaderBuffer, count);
          goto exit;
      }

      // determine whether we need to issue re-GET to the same serverIP
      // from the POST response
      if (!m_bGetResponsed && !m_bConnectToSameServerIP)
      {
          m_bGetResponsed = TRUE;
          GetServerIPFromResponse(TRUE, m_pHTTPHeaderBuffer);

          if (m_pszGetServerIP && m_pszPutServerIP)
          {
            m_bReconnectToSameServerIP = strcasecmp(m_pszGetServerIP, m_pszPutServerIP);
          }

          if (m_bReconnectToSameServerIP)
          {
            theErr = ReconnectToSameServerIP();
            goto quit;
          }
      }

      /* If we have read the complete header, see if the content is OK..*/
      char* pFound = (char*) HXFindString(m_pHTTPHeaderBuffer, "HTTP/1.0 200 OK");
      if (!pFound)
      {
          pFound = (char*) HXFindString(m_pHTTPHeaderBuffer, "200 OK");
      }
      
      // XXX HP we are phasing out PNM protocol
      // m_pCloakValues is only set in RTSP so we use this to exclude
      // support for redirect in PNM Cloaking
      if (!pFound)
      {
          if (m_pCloakValues)
          {
            pFound = (char*) HXFindString(m_pHTTPHeaderBuffer, "HTTP/1.0 302");
            if (pFound)
            {
                strncpy(pFound, "RTSP", 4); /* Flawfinder: ignore */

                IHXBuffer* pBuffer = new CHXBuffer;
                pBuffer->AddRef();
                pBuffer->Set((UCHAR*) m_pHTTPHeaderBuffer, count);
                
                m_pTCPResponse->ReadDone(HXR_OK, pBuffer);
                pBuffer->Release();
                goto exit;
            }
          }

          theErr = HXR_DOC_MISSING;
      }

      if (!theErr)
      {
          m_pReceiveGetTCP->EnQueue(pStartAfterDoubleReturn, 
                      (m_pHTTPHeaderBuffer + count) - pStartAfterDoubleReturn);
          
          count = m_pReceiveGetTCP->GetQueuedItemCount();
      }
    }

    /* hmmm... time to read options */ 
    if (!theErr && count > 0 && !m_bOptionsReceived && m_bHTTPGetHeaderReadDone)
    {
      /* There needs to be atleast 4 bytes to have the response
       * reponse_opcode(HTTP_RV_RESPONSE), response len, 
       * actual response(minimum one byte)
       */
      if (count < 3)
      {
          goto exit;
      }

      m_pReceiveGetTCP->DeQueue(m_pInBuf, count);

      if (m_pInBuf[0] == HTTP_RESPONSE)
      {
          m_bOptionsReceived = TRUE;
          
          UINT16 nOptionLen = m_pInBuf[1];
          /* Place any data after the response back in Receive queue.
           * This data needs to be sent to the user*/
          if (count > 2+nOptionLen)
          {
            m_pReceiveGetTCP->EnQueue(m_pInBuf+2+nOptionLen, (count - (2+nOptionLen)));
          }

          theErr = HandleHTTPResponse((UCHAR) m_pInBuf[2]);

          if (!theErr)
          {
            count = m_pReceiveGetTCP->GetQueuedItemCount();
          }
      }
      else if (m_pInBuf[0] == HTTP_RV_RESPONSE)
      {
          if (count < 9)
          {
            m_pReceiveGetTCP->EnQueue(m_pInBuf, count);
            goto exit;
          }
          /*
           * this involves receiving a message from the server of the format:
           * HTTP/1.0 200 OK
           * ...
           * Content-length:2147483000
           * r...O?...16k padding of ZEROs...e
           *
           * r -- HTTP_RV_RESPONSE (same as the 5.0 player)
           * O -- HTTP_OPTION_RESPONSE
           * e -- HTTP_OPT_RESPONSE_END
           */
          BYTE* ptr = (BYTE *)m_pInBuf;
          m_bOptionsReceived = TRUE;
          
          ptr += 2;
          UINT16 nOptionLen = *ptr;
          ptr++;
          
          theErr = HandleHTTPResponse((UCHAR)*ptr);
          ptr++;

          if (!theErr)
          {
            ptr++;  // get past the HTTP_OPTION_RESPONSE char 'O'
            m_uPadLength = (UINT16)getshort(ptr); 
            ptr += 2;

            // skip over the short padding option
            m_uPadLength += 1; // for the 'e' at the end of the 16k padding

            m_pReceiveGetTCP->EnQueue(ptr, 
                (m_uPadLength <= (count - (ptr - (BYTE *)m_pInBuf)) 
                ? m_uPadLength : (count - (ptr - (BYTE *)m_pInBuf))));

            count = m_pReceiveGetTCP->GetQueuedItemCount();

            // get rid of the padding sent with the first response
            UINT16 len = (m_uPadLength <= count ? m_uPadLength : count); 
            BYTE* tmpBuf = new BYTE[len];
            
            m_pReceiveGetTCP->DeQueue(tmpBuf, len);
            m_uPadLength -= len;

            if (m_uPadLength > 0)
            {
                m_bDeletePadding = TRUE;
            }
            // if we got more than the 16k initial buffer, put it back
            if (len && len < count)
                m_pReceiveGetTCP->EnQueue(&m_pInBuf[len], count-len);
            HX_VECTOR_DELETE(tmpBuf);
            count = m_pReceiveGetTCP->GetQueuedItemCount();
          }
      }
      else
      {
          theErr = HXR_BAD_SERVER;
          goto exit;
      }

    }

    if (!theErr && m_bReadPending && count > 0 && m_bOptionsReceived 
      && m_bHTTPGetHeaderReadDone)
    {
      /* mask any kind of errors */
      theErr = HXR_OK;

      if (IsSafe())
      {
          m_bReadPending = FALSE;
          if (m_nRequired < count)
          {
            count = m_nRequired;
          }

          CHXBuffer* pBuffer = new CHXBuffer;
          pBuffer->AddRef();
          m_pReceiveGetTCP->DeQueue(m_pInBuf, count);
          pBuffer->Set((UCHAR*) m_pInBuf, count);
          
          m_pTCPResponse->ReadDone(HXR_OK, pBuffer);
          pBuffer->Release();
      }
    }

exit:
    if (theErr && !m_LastError)
    {
      m_LastError = theErr;
    }

    if (m_LastError)
    {
      if (m_bReadPending)
      {
          if (IsSafe())
          {
            m_bReadPending = FALSE;
            m_pTCPResponse->ReadDone(m_LastError, 0);
          }
      }
    }

    if (!m_LastError)
    {
      DoPutWrite();
      DoRead();
    }

quit:
    m_pMutex->Unlock();

    return HXR_OK;
}

HX_RESULT               
HXClientCloakedTCPSocket::DoPutReadDone(HX_RESULT   status, IHXBuffer* pInBuffer)
{
    HX_RESULT     rc = HXR_OK;
    UINT16  count = 0;

    m_bPutReadPending = FALSE;

    if (HXR_OK != status)
    {
      rc = status;
      goto cleanup;
    }

    // stop processing either we already processed one PUT response or
    // we are in multi-post mode
    if (!m_bPutResponsed && !m_bMustCloseHTTP)
    {
      if (!m_pReceivePutTCP)
      {
          m_pReceivePutTCP = new CByteGrowingQueue(QUEUE_START_SIZE,1);
          if (!m_pReceivePutTCP || !m_pReceivePutTCP->IsQueueValid())
          {
            rc = HXR_OUTOFMEMORY;
            goto cleanup;
          }
          m_pReceivePutTCP->SetMaxSize(TCP_BUF_SIZE);
      }

      if (pInBuffer)
      {
          m_pReceivePutTCP->EnQueue(pInBuffer->GetBuffer(), (UINT16) pInBuffer->GetSize());
      }

      count = m_pReceivePutTCP->GetQueuedItemCount();

      if (count >= 2)
      {
          char* pEndLineLocation = 0;
          if (!m_pHTTPHeaderBuffer || m_nHTTPHeaderBufferLength < count+1)
          {
            HX_VECTOR_DELETE(m_pHTTPHeaderBuffer);
            m_nHTTPHeaderBufferLength = count+1 > DEFAULT_HTTP_HEADER_LENGTH ?
                                  count+1 : DEFAULT_HTTP_HEADER_LENGTH;
            m_pHTTPHeaderBuffer = new char[m_nHTTPHeaderBufferLength];
            if (!m_pHTTPHeaderBuffer)
            {
                rc = HXR_OUTOFMEMORY;
                goto cleanup;
            }
          }

          m_pReceivePutTCP->DeQueue(m_pHTTPHeaderBuffer, count);
          m_pHTTPHeaderBuffer[count] = '\0';

          if ((pEndLineLocation = (char*) HXFindString(m_pHTTPHeaderBuffer, "\n\n")) ||
            (pEndLineLocation = (char*) HXFindString(m_pHTTPHeaderBuffer, "\r\r")) )
          {
            m_bHTTPPutHeaderReadDone = TRUE;
          }
          else if (count >= 4 &&
                (pEndLineLocation = (char*) HXFindString(m_pHTTPHeaderBuffer, "\r\n\r\n")))
          {
            m_bHTTPPutHeaderReadDone = TRUE;
          }
          else
          {
            /* Put back everything in receive queue*/
            m_pReceivePutTCP->EnQueue(m_pHTTPHeaderBuffer, count);
            goto cleanup;
          }

          m_bPutResponsed = TRUE;
          GetServerIPFromResponse(FALSE, m_pHTTPHeaderBuffer);

          if (m_bConnectToSameServerIP)
          {
            rc = ActualConnect();
          }
          else
          {
            if (m_pszPutServerIP && m_pPreferredTransport)
            {
                m_pPreferredTransport->SetHTTPNG(TRUE);
            }

            // determine whether we need to issue re-GET to the same serverIP
            // from the POST response
            if (m_pszGetServerIP && m_pszPutServerIP)
            {
                m_bReconnectToSameServerIP = strcasecmp(m_pszGetServerIP, m_pszPutServerIP);
            }

            if (m_bReconnectToSameServerIP)
            {
                rc = ReconnectToSameServerIP();
            }
          }
      }
    }

cleanup:

    return rc;    
}

void
HXClientCloakedTCPSocket::TransferBuffers()
{
    IHXBuffer* pBuffer = 0;
    HX_RESULT theErr = HXR_OK;

    if (m_bInTransferBuffers)
    {
      return;
    }

    m_bInTransferBuffers = TRUE;

    /*This is where we need to add POST header for multiple POST case*/

    while (m_PendingWriteBuffers.GetCount() > 0)
    {
      pBuffer = (IHXBuffer*) m_PendingWriteBuffers.GetHead();
      if ((UINT16) pBuffer->GetSize() < m_pPreEncodedSendHTTP->GetMaxAvailableElements())
      {
          m_pPreEncodedSendHTTP->EnQueue(pBuffer->GetBuffer(), 
                        (UINT16) pBuffer->GetSize());
          pBuffer->Release();
          m_PendingWriteBuffers.RemoveHead();
      }
      else
      {
          break;
      }
    }

    UINT16 nCount = m_pPreEncodedSendHTTP->GetQueuedItemCount();
    if (nCount > 0)
    {
      if (m_bCloseHttpAfterWrite)
      {
          ENQUEUE_BYTE(m_pPreEncodedSendHTTP, HTTP_POSTDONE);
          nCount++;
      }

      if (m_bMustCloseHTTP && m_pPutCtrl)
      {
          m_pPutCtrl->Release();
          m_pPutCtrl = 0;
          m_bPutConnectDone = FALSE;

          m_pNetworkServices->CreateTCPSocket(&m_pPutCtrl);
          if (!m_pPutCtrl)
          {
            m_LastError = HXR_OUTOFMEMORY;
            m_bInTransferBuffers = FALSE;
            return;
          }

          m_pPutCtrl->Init(m_pPutCtrlResponse);

          const char* pActualHost = m_pForiegnHost;
          UINT16  nActualPort = m_nForeignPort;
          if (m_pProxyHostName)
          {
            pActualHost = m_pProxyHostName;
            nActualPort = m_nProxyPortNumber;
          }

          m_pPutCtrl->Connect(pActualHost,nActualPort);
      }

      m_pPreEncodedSendHTTP->DeQueue(m_pOutBuf, nCount);
      UINT16 nEncodedCount = TCP_BUF_SIZE;
      EncodeBase64((UCHAR*) m_pOutBuf, nCount, (UCHAR*) m_pOutEncodedBuf, nEncodedCount);

        HX_ASSERT(nEncodedCount <= TCP_BUF_SIZE);

      if (m_bCloseHttpAfterWrite)
      {
          theErr = PreparePostMessage((UCHAR*) m_pOutEncodedBuf, nEncodedCount);
      }
      else
      {
          ENQUEUE_DATA(m_pPostEncodedSendHTTP,m_pOutEncodedBuf, nEncodedCount);
      }
    }

    m_bInTransferBuffers = FALSE;
}

/***************************General routines*******/

HX_RESULT
HXClientCloakedTCPSocket::PreparePostMessage(const UCHAR *inData, UINT16 inLength) 
{
    HX_RESULT theErr = HXR_OK;
    int count = 0;
    UINT16 postLength = inLength;
    
    // create a temp buffer to help build the HTTP POST message
    char* s = new char[MAX_HTTP_METHOD_BUFSIZE];
    if(s == NULL)
    {
      return HXR_OUTOFMEMORY;
    }
    // build the HTTP POST message
    if(m_pProxyHostName)
    {
      if (m_nForeignPort)
      {
          count = SafeSprintf(s,MAX_HTTP_METHOD_BUFSIZE,"POST http://%s:%d/SmpDsBhgRl",m_pForiegnHost, m_nForeignPort);
      }
      else
      {
          count = SafeSprintf(s,MAX_HTTP_METHOD_BUFSIZE,"POST http://%s/SmpDsBhgRl",m_pForiegnHost);
      }
    }
    else
    {
            //count = sprintf(s,"POST /SmpDsBhgRl"); /* Flawfinder: ignore */
            count = SafeSprintf(s,MAX_HTTP_METHOD_BUFSIZE,"POST /SmpDsBhgRl"); /* Flawfinder: ignore */
    }
    
    ENQUEUE_DATA(m_pPostEncodedSendHTTP,s,count);

    // enqueue the remainder of the POST line
    count = SafeSprintf(s,MAX_HTTP_METHOD_BUFSIZE," HTTP/1.0\r\n"); /* Flawfinder: ignore */
    ENQUEUE_DATA(m_pPostEncodedSendHTTP,s,count);

    count = SafeSprintf(s,MAX_HTTP_METHOD_BUFSIZE,"User-Agent: RealPlayer G2\r\n"); /* Flawfinder: ignore */
    ENQUEUE_DATA(m_pPostEncodedSendHTTP,s,count);

    count = SafeSprintf(s,MAX_HTTP_METHOD_BUFSIZE,"Pragma: no-cache\r\n"); /* Flawfinder: ignore */
    ENQUEUE_DATA(m_pPostEncodedSendHTTP,s,count);

    count = SafeSprintf(s,MAX_HTTP_METHOD_BUFSIZE,"Expires: Mon, 18 May 1974 00:00:00 GMT\r\n"); /* Flawfinder: ignore */
    ENQUEUE_DATA(m_pPostEncodedSendHTTP,s,count);

    count = SafeSprintf(s,MAX_HTTP_METHOD_BUFSIZE,"Accept: application/x-rtsp-tunnelled, */*\r\n"); /* Flawfinder: ignore */
    ENQUEUE_DATA(m_pPostEncodedSendHTTP,s,count);

    count = SafeSprintf(s,MAX_HTTP_METHOD_BUFSIZE,"Content-type: application/x-pncmd\r\n"); /* Flawfinder: ignore */
    ENQUEUE_DATA(m_pPostEncodedSendHTTP,s,count);

    CHXString strAuth;
    ObtainAuthenticationInformation(strAuth);
    
    if (!strAuth.IsEmpty())
    {
      strAuth += "\r\n";    
      ENQUEUE_DATA(m_pPostEncodedSendHTTP, (void*)(const char*)strAuth, 
                 (UINT16)strAuth.GetLength());
    }

    UINT16 guidSize = ::strlen(m_pGuid);
      
    if(m_bUseExactContentLength)
    {
      // add in the size of the GUID (which was not base64 encoded)
      postLength += guidSize + 2;   // 2 is for the \r\n at the end of the GUID!
      
      // we must report the exact size of the post data in the Content-length parameter
      count = SafeSprintf(s,MAX_HTTP_METHOD_BUFSIZE,"Content-length: %hu\r\n",postLength); /* Flawfinder: ignore */
    }
    else
    {
      count = SafeSprintf(s,MAX_HTTP_METHOD_BUFSIZE,"Content-length: 32767\r\n"); /* Flawfinder: ignore */
    }

    ENQUEUE_DATA(m_pPostEncodedSendHTTP,s,count);

    // enqueue the CR LF to indicate end of the POST header
    count = SafeSprintf(s,MAX_HTTP_METHOD_BUFSIZE,"\r\n"); /* Flawfinder: ignore */
    ENQUEUE_DATA(m_pPostEncodedSendHTTP,s,count);

    // enqueue the GUID (Must be sent with every POST and not base64 encoded)
    ENQUEUE_DATA(m_pPostEncodedSendHTTP,&m_pGuid[0],guidSize);
    
    // enqueue the CR LF to indicate end of the GUID
    count = SafeSprintf(s,MAX_HTTP_METHOD_BUFSIZE,"\r\n"); /* Flawfinder: ignore */
    ENQUEUE_DATA(m_pPostEncodedSendHTTP,s,count);

    if(inLength > 0)
    {
      // enqueue the actual POST data
      ENQUEUE_DATA(m_pPostEncodedSendHTTP,(char *)inData,inLength);
    }
    
    // clean up allocated buffers
    if(s)
    {
      delete [] s;
    }

    return theErr;
}

HX_RESULT
HXClientCloakedTCPSocket::PrepareGetMessage(void) 
{
    HX_RESULT     theErr = HXR_OK;
    IHXBuffer* pBuffer = NULL;

    // create a temp buffer for the HTTP GET message
    char* s = new char[MAX_HTTP_METHOD_BUFSIZE];
    
    if(s == NULL)
    {
      theErr = HXR_OUTOFMEMORY;
    }
    
    /* Flush any prior data in the send queue */
    m_pSendTCP->FlushQueue();

    /* Create a fresh GUID */
    CreateGuid();

    // format the HTTP GET message
    if(!theErr)
    {
      int count = 0;

      // build the HTTP POST message
      if(m_pProxyHostName)
      {   
          if (m_nForeignPort)
          {
            count = SafeSprintf(s,MAX_HTTP_METHOD_BUFSIZE,"GET http://%s:%d/SmpDsBhgRl",m_pForiegnHost, m_nForeignPort);
          }
          else
          {
            count = SafeSprintf(s,MAX_HTTP_METHOD_BUFSIZE,"GET http://%s/SmpDsBhgRl",m_pForiegnHost);
          }
      }
      else
      {
          count = SafeSprintf(s,MAX_HTTP_METHOD_BUFSIZE,"GET /SmpDsBhgRl"); /* Flawfinder: ignore */
      }

      ENQUEUE_DATA(m_pSendTCP,s,count);
      
#if 0 // XXX HP enable this to test re-GET after initial GET/POST response 
      // returned with different serverIP
      if (!m_bReconnectToSameServerIP)
      {
          char* pGuid = new char[strlen(m_pGuid)+1];
          memcpy(pGuid, m_pGuid, strlen(m_pGuid)); /* Flawfinder: ignore */
          pGuid[0] = 'z';
          // enqueue the GUID directly after the SmpDsBhgRl tag
          ENQUEUE_DATA(m_pSendTCP,&pGuid[0],::strlen(pGuid));
          HX_VECTOR_DELETE(pGuid);
      }
      else
#endif
      {
          // enqueue the GUID directly after the SmpDsBhgRl tag
          ENQUEUE_DATA(m_pSendTCP,&m_pGuid[0],::strlen(m_pGuid));
      }

      if (m_pProxyHostName)
      {
          /* 
           * enqueue dummy option to tell the server to send a padding
           * of 16k of ZEROs with the first response
           */
          count = SafeSprintf(s,MAX_HTTP_METHOD_BUFSIZE,"?1=\"1\""); /* Flawfinder: ignore */
          ENQUEUE_DATA(m_pSendTCP,s,count);
      }

      // enqueue the HTTP 1.0 and CR LF
      count = SafeSprintf(s,MAX_HTTP_METHOD_BUFSIZE," HTTP/1.0\r\n"); /* Flawfinder: ignore */
      ENQUEUE_DATA(m_pSendTCP,s,count);

      count = SafeSprintf(s,MAX_HTTP_METHOD_BUFSIZE,"User-Agent: RealPlayer G2\r\n"); /* Flawfinder: ignore */
      ENQUEUE_DATA(m_pSendTCP,s,count);

      count = SafeSprintf(s,MAX_HTTP_METHOD_BUFSIZE,"Expires: Mon, 18 May 1974 00:00:00 GMT\r\n"); /* Flawfinder: ignore */
      ENQUEUE_DATA(m_pSendTCP,s,count);

      count = SafeSprintf(s,MAX_HTTP_METHOD_BUFSIZE,"Pragma: no-cache\r\n"); /* Flawfinder: ignore */
      ENQUEUE_DATA(m_pSendTCP,s,count);

      count = SafeSprintf(s,MAX_HTTP_METHOD_BUFSIZE,"Accept: application/x-rtsp-tunnelled, */*\r\n"); /* Flawfinder: ignore */
      ENQUEUE_DATA(m_pSendTCP,s,count);

      CHXString strAuth;
      ObtainAuthenticationInformation(strAuth);

      if (!strAuth.IsEmpty())
      {
          strAuth += "\r\n";    
          ENQUEUE_DATA(m_pSendTCP, (void*)(const char*)strAuth, 
                   (UINT16)strAuth.GetLength());
      }

      // send client information so that GoldPass Admin
      // can generate redirect URL via HTTPCloaking
      if (m_pCloakValues)
      {
          if (HXR_OK == m_pCloakValues->GetPropertyCString("ClientID", pBuffer))
          {
            UINT32 ulNewSize = pBuffer->GetSize()+25;
            s = (char*)realloc(s, ulNewSize);
                if(s)
                {
                    count = SafeSprintf(s,ulNewSize,"ClientID: %s\r\n", pBuffer->GetBuffer()); /* Flawfinder: ignore */
                    ENQUEUE_DATA(m_pSendTCP,s,count);
                }
                else
                {
                    theErr = HXR_OUTOFMEMORY;
                }
                
          }
          HX_RELEASE(pBuffer);

          if (HXR_OK == m_pCloakValues->GetPropertyCString("Cookie", pBuffer))
          {
            UINT32 ulNewSize = pBuffer->GetSize()+25;
            s = (char*)realloc(s, ulNewSize);
                if(s)
                {
                    count = SafeSprintf(s,ulNewSize,"Cookie: %s\r\n", pBuffer->GetBuffer()); /* Flawfinder: ignore */
                    ENQUEUE_DATA(m_pSendTCP,s,count);
                }
                else
                {
                    theErr = HXR_OUTOFMEMORY;
                }
            }
          HX_RELEASE(pBuffer);

          if (HXR_OK == m_pCloakValues->GetPropertyCString("url", pBuffer))
          {
            UINT32 ulNewSize = pBuffer->GetSize()+25;
                s = (char*)realloc(s, ulNewSize);
                if(s)
                {
                    count = SafeSprintf(s,ulNewSize,"X-Actual-URL: %s\r\n", pBuffer->GetBuffer()); /* Flawfinder: ignore */
                    ENQUEUE_DATA(m_pSendTCP,s,count);
                }
                else
                {
                    theErr = HXR_OUTOFMEMORY;
                }
          }
          HX_RELEASE(pBuffer);
      }

      // enqueue the CR LF to indicate the end of the HTTP GET header
        s = (char*)realloc(s, 25);
        if(s)
        {
            count = SafeSprintf(s,25,"\r\n"); /* Flawfinder: ignore */
            ENQUEUE_DATA(m_pSendTCP,s,count);
        }
        else
        {
            theErr = HXR_OUTOFMEMORY;
        }
    }
    
    // clean up
    HX_DELETE(s);
    
    return theErr;
}

void
HXClientCloakedTCPSocket::CreateGuid(void)
{
    CHXuuid theGuid;
    uuid_tt uuid;
    
    if (m_pGuid)
    {
      return;
    }

    if(m_pGuid)
    {
      delete [] m_pGuid;
      m_pGuid = NULL;
    }
    
    // generate a new GUID
    HX_RESULT theErr = theGuid.GetUuid(&uuid);
//    HX_RESULT theErr = HXR_OK;

    if(!theErr)
    {
      CHXString theString;
      
      CHXuuid::HXUuidToString((const uuid_tt*)&uuid,&theString);
      
      int length = theString.GetLength();
      
      m_pGuid = new char[length + 1];
      
      if(!m_pGuid)
      {
            theErr = HXR_OUTOFMEMORY;
      }
      
      if(!theErr)
      {
            ::strcpy(m_pGuid,(const char *)theString); /* Flawfinder: ignore */
            m_pGuid[length] = '\0';
      }
      
      if(theErr && m_pGuid)
      {
            delete [] m_pGuid;
            m_pGuid = NULL;
      }
    }
    
    if(theErr)  // use our own GUID generator
    {
      theErr = HXR_OK;
      ULONG32 temp = HX_GET_TICKCOUNT();

      if(m_pGuid)
      {
          delete [] m_pGuid;
          m_pGuid = NULL;
      }
    
      m_pGuid = new char[HXGUID_SIZE + 1];

      UINT16 length = SafeSprintf(m_pGuid,HXGUID_SIZE + 1,"%ld",temp);
      
      while(length < HXGUID_SIZE)
      {
            m_pGuid[length++] = '1';
      }
      
      m_pGuid[HXGUID_SIZE] = '\0';
    }
}

HX_RESULT 
HXClientCloakedTCPSocket::EncodeBase64(const UCHAR* inData, UINT16 inLength, UCHAR* outData, UINT16& outLength)
{
    HX_RESULT theErr = HXR_OK;
    
    HX_ASSERT(inData != NULL);
    HX_ASSERT(outData != NULL);
    HX_ASSERT(inLength != 0);
    
    // first base64 encode the buffer
    outLength = (UINT16) BinTo64((const UCHAR*) inData, (ULONG32) inLength,(char *)outData);

    HX_ASSERT(outLength >= inLength);

    return HXR_OK;
}


HX_RESULT
HXClientCloakedTCPSocket::HandleHTTPResponse(UCHAR response)
{
    HX_RESULT theErr = HXR_OK;
    
    switch(response)
    {
      case HTTP_OK:
      {
          m_bUseExactContentLength = FALSE;
          m_bCloseHttpAfterWrite = FALSE;
          m_bHttpInitialized = TRUE;
          /*force a write of the cached data to be sent to the server*/
//        theErr = control_write(); 
      }
      break;
            
      case POST_NOT_RECEIVED:       // POST message was not received
      {
          if (m_pszGetServerIP)
          {
            HX_VECTOR_DELETE(m_pForiegnHost);
            // use serverIP from GET response for multi-POST
            m_pForiegnHost = new char [strlen(m_pszGetServerIP) + 1];
            if (m_pForiegnHost)
            {
                ::strcpy(m_pForiegnHost, m_pszGetServerIP); /* Flawfinder: ignore */
            }
            else
            {
                theErr = HXR_OUTOFMEMORY;
            }
          }
 
          m_bUseExactContentLength = TRUE;
          m_bCloseHttpAfterWrite = TRUE;
          m_bHttpInitialized = TRUE;
          m_bMustCloseHTTP = TRUE;

          /*force a write of the cached data to be sent to the server*/
//        theErr = control_write();
      }
      break;
            
      case INVALID_GUID:                  
      {
          /* sent only if the GUID from the Player is already in use
           * Need to regenerate GUID and send everything again
           */
          /// TBD - Rahul         
          if (m_pGuid)
          {
            delete [] m_pGuid;
            m_pGuid = 0;
          }

          PrepareGetMessage();
          theErr = DoGetWrite();
      }
      break;

      default:
      {
          // shut this clip down and report an appropriate error
          theErr = HXR_HTTP_CONTENT_NOT_FOUND;
      }
      break;
    }
    
    return theErr;
}

/* If we are at interrupt time and the response object is not interrupt safe,
 * schedule a callback to return back the data
 */
BOOL
HXClientCloakedTCPSocket::IsSafe()
{
    if (m_pInterruptState && m_pInterruptState->AtInterruptTime() && 
      (!m_pResponseInterruptSafe || 
       !m_pResponseInterruptSafe->IsInterruptSafe()))
    {
      if (m_pNonInterruptCallback){
          m_pNonInterruptCallback->ScheduleCallback(CLOAKED_TCP_READ_COMMAND, m_pScheduler, 0);
      }

      return FALSE;
    }

    return TRUE;
}

void
HXClientCloakedTCPSocket::FlushQueues(void)
{
    if (m_pSendTCP)
    {
      m_pSendTCP->FlushQueue();
    }

    if (m_pReceiveGetTCP)
    {
      m_pReceiveGetTCP->FlushQueue();
    }

    if (m_pReceivePutTCP)
    {
      m_pReceivePutTCP->FlushQueue();
    }

    if (m_pPreEncodedSendHTTP)
    {
      m_pPreEncodedSendHTTP->FlushQueue();
    }

    if (m_pPostEncodedSendHTTP)
    {
      m_pPostEncodedSendHTTP->FlushQueue();
    }
}

void              
HXClientCloakedTCPSocket::SendHTTPDone(void)
{
    CHXBuffer* pBuffer = new CHXBuffer;
    pBuffer->AddRef();

    BYTE http_done = HTTP_DONE;
    pBuffer->Set((UCHAR*) &http_done, 1);
    m_PendingWriteBuffers.AddTail((void*) pBuffer);

    TransferBuffers();
    DoPutWrite();
}

HX_RESULT
HXClientCloakedTCPSocket::ActualConnect(void)
{
    HX_RESULT     rc = HXR_OK;

    const char* pActualHost = m_pForiegnHost;
    UINT16  nActualPort = m_nForeignPort;
    if (m_pProxyHostName)
    {
      pActualHost = m_pProxyHostName;
      nActualPort = m_nProxyPortNumber;
    }

    if (m_bConnectToSameServerIP)
    {
      if (m_bPutConnectSuccessful)
      {
          rc = m_pGetCtrl->Connect(pActualHost,nActualPort);
      }
      else
      {
          rc = m_pPutCtrl->Connect(pActualHost,nActualPort);
      }
      rc = ConvertNetworkError(rc);
    }
    else
    {
      rc = m_pGetCtrl->Connect(pActualHost,nActualPort);
      rc = ConvertNetworkError(rc);

      if (rc == HXR_OK && !m_bReconnectToSameServerIP)
      {
          rc = m_pPutCtrl->Connect(pActualHost,nActualPort);
          rc = ConvertNetworkError(rc);
      }
    }

    return rc;
}

HX_RESULT
HXClientCloakedTCPSocket::GetServerIPFromResponse(BOOL bGetResponse, const char* pszInBuffer)
{
    HX_RESULT     rc = HXR_OK;
    UINT8   nLength = 0;
    char*   pszServerIPStart = NULL;    
    char*   pszServerIPEnd = NULL;
    char*   pszServerIP = NULL;

    if (!pszInBuffer)
    {
      rc = HXR_FAILED;
      goto cleanup;
    }

    pszServerIPStart = (char*)HXFindString(pszInBuffer, "x-server-ip-address:");

    if (pszServerIPStart)
    {
      pszServerIPStart += strlen("x-server-ip-address:");

      // removing leading spaces
      while (*pszServerIPStart == ' ')
      {
          pszServerIPStart++;
      }

      pszServerIPEnd = (char*)HXFindString(pszServerIPStart, "\r\n");   
      if (pszServerIPEnd)
      {
          nLength = pszServerIPEnd - pszServerIPStart;

          pszServerIP = new char[nLength + 1];
          memset(pszServerIP, 0, nLength + 1);

          strncpy(pszServerIP, pszServerIPStart, nLength); /* Flawfinder: ignore */

          if (bGetResponse)
          {
            HX_VECTOR_DELETE(m_pszGetServerIP);
            m_pszGetServerIP = pszServerIP;
          }
          else
          {
            HX_VECTOR_DELETE(m_pszPutServerIP);
            m_pszPutServerIP = pszServerIP;
          }
      }
    }

cleanup:

    return rc;
}


HX_RESULT
HXClientCloakedTCPSocket::CleanUpAndReInitializeStuff(void)
{
    HX_RESULT     rc = HXR_OK;
    IHXBuffer* pBuffer = NULL;

    m_pMutex->Lock();

    const char* pActualHost = m_pForiegnHost;
    UINT16  nActualPort = m_nForeignPort;
    if (m_pProxyHostName)
    {
      pActualHost = m_pProxyHostName;
      nActualPort = m_nProxyPortNumber;
    }

    if (m_pReceiveGetTCP)
    {
      m_pReceiveGetTCP->FlushQueue();
    }

    /* Send a final HTTP done message */
    if (m_bHttpInitialized)
    {
      SendHTTPDone();
    }

    if (m_pSchedulerCallback)
    {
      m_pSchedulerCallback->Unschedule(m_pScheduler);
    }

    if (m_pNonInterruptCallback)
    {
      m_pNonInterruptCallback->Unschedule(m_pScheduler);
    }

    HX_RELEASE(m_pGetCtrl);
    HX_RELEASE(m_pPutCtrl);
    
    m_bHTTPGetHeaderReadDone = FALSE;
    m_bOptionsReceived = FALSE;
    m_bReadPending = FALSE;
    m_bGetReadPending = FALSE;
    m_bGetConnectDone = FALSE;
    m_bGetConnectSuccessful = FALSE;
    m_bConnectResponsePending = TRUE;
    m_bConnected = FALSE;

    m_bPutConnectDone = FALSE;
    m_bPutReadPending = FALSE;

    m_bInAuthenticationKludge = TRUE;
    
    // OK, clean up is done so now we re-initialize.
    
    
    // use serverIP from PUT response for GET reconnect
    
    if (HXR_OK != m_pNetworkServices->CreateTCPSocket(&m_pGetCtrl))
    {
      rc = HXR_FAILED;
      goto cleanup;
    }

    if (HXR_OK != m_pGetCtrl->Init(m_pGetCtrlResponse))
    {
      rc = HXR_FAILED;
      goto cleanup;
    }

    if (HXR_OK != m_pGetCtrl->Bind(HXR_INADDR_ANY, 0))
    {
      rc = HXR_FAILED;
      goto cleanup;
    }
    
    rc = m_pGetCtrl->Connect(pActualHost, nActualPort);    
    if (HXR_OK != rc)
    {
      goto cleanup;
    }

    if (HXR_OK != m_pNetworkServices->CreateTCPSocket(&m_pPutCtrl))
    {
      rc = HXR_FAILED;
      goto cleanup;
    }

    if (HXR_OK != m_pPutCtrl->Init(m_pPutCtrlResponse))
    {
      rc = HXR_FAILED;
      goto cleanup;
    }

    if (HXR_OK != m_pPutCtrl->Bind(HXR_INADDR_ANY, 0))
    {
      rc = HXR_FAILED;
      goto cleanup;
    }

    rc = m_pPutCtrl->Connect(pActualHost, nActualPort);
    if (HXR_OK != rc) goto cleanup;


cleanup:
    m_pMutex->Unlock();

    return rc;
}

HX_RESULT
HXClientCloakedTCPSocket::ReconnectToSameServerIP(void)
{
    HX_RESULT     rc = HXR_OK;
    IHXBuffer* pBuffer = NULL;

    m_pMutex->Lock();

    if (m_pReceiveGetTCP)
    {
      m_pReceiveGetTCP->FlushQueue();
    }

    /* Send a final HTTP done message */
    if (m_bHttpInitialized)
    {
      SendHTTPDone();
    }

    if (m_pSchedulerCallback)
    {
      m_pSchedulerCallback->Unschedule(m_pScheduler);
    }

    if (m_pNonInterruptCallback)
    {
      m_pNonInterruptCallback->Unschedule(m_pScheduler);
    }

    HX_RELEASE(m_pGetCtrl);
    HX_RELEASE(m_pGetCtrlResponse);
    
    m_bHTTPGetHeaderReadDone = FALSE;
    m_bOptionsReceived = FALSE;
    m_bReadPending = FALSE;
    m_bGetReadPending = FALSE;
    m_bGetConnectDone = FALSE;
    m_bGetConnectSuccessful = FALSE;
    m_bConnectResponsePending = TRUE;
    m_bConnected = FALSE;

    HX_VECTOR_DELETE(m_pForiegnHost);
    // use serverIP from PUT response for GET reconnect
    m_pForiegnHost = new char [strlen(m_pszPutServerIP) + 1];
    if (!m_pForiegnHost)
    {
      rc = HXR_OUTOFMEMORY;
      goto cleanup;
    }
    ::strcpy(m_pForiegnHost, m_pszPutServerIP); /* Flawfinder: ignore */
    
    if (HXR_OK != m_pNetworkServices->CreateTCPSocket(&m_pGetCtrl))
    {
      rc = HXR_FAILED;
      goto cleanup;
    }

    m_pGetCtrlResponse = new HTTPCloakTCPResponse(this, TRUE);
    if (!m_pGetCtrlResponse)
    {
      rc = HXR_FAILED;
      goto cleanup;
    }

    m_pGetCtrlResponse->AddRef();

    if (HXR_OK != m_pGetCtrl->Init(m_pGetCtrlResponse))
    {
      rc = HXR_FAILED;
      goto cleanup;
    }

    if (HXR_OK != m_pGetCtrl->Bind(HXR_INADDR_ANY, 0))
    {
      rc = HXR_FAILED;
      goto cleanup;
    }

    rc = ActualConnect();

cleanup:

    m_pMutex->Unlock();

    return rc;
}

BOOL
HXClientCloakedTCPSocket::AuthenticationRequired(HX_RESULT   status, IHXBuffer* pInBuffer)
{
    if (!pInBuffer)
    {
      return FALSE;
    }

    // start of authenticated proxy logic.

    HTTPParser Parser;
    char* pBufferContents = (char*)(const char*)pInBuffer->GetBuffer();
    ULONG32 nMsgLen = pInBuffer->GetSize();
    HTTPResponseMessage* pMessage = (HTTPResponseMessage*)Parser.parse( pBufferContents, nMsgLen );

    // ignore non-HTTP responses which will be processed by the response object:
    // RTSPClientProtocol
    if (HTTPMessage::T_UNKNOWN == pMessage->tag())
    {
      HX_DELETE(pMessage);
      return FALSE;
    }

    ULONG32 ulHTTPStatus = 0;
    if (strlen(pMessage->errorCode()) > 0)
    {
      ulHTTPStatus = atoi(pMessage->errorCode());
    }

    if (ulHTTPStatus == 401 || ulHTTPStatus == 407)
    {
#ifdef _MACINTOSH
      if (!IsMacInCooperativeThread())
      {
          // xxxbobclark Since there's UI involved with authentication,
          // we'll ensure that we're not at interrupt time.
          if (m_pAuthenticationCallback && !m_pAuthenticationCallback->m_ulPendingCallbackID)
          {
            m_pAuthenticationCallback->m_ulPendingCallbackID  =
                  m_pScheduler->RelativeEnter(m_pAuthenticationCallback, 0);
            m_pAuthenticationCallback->m_Status = status;
            pInBuffer->AddRef();
            m_pAuthenticationCallback->m_pInBuffer = pInBuffer;
          }

          HX_DELETE(pMessage);
          return TRUE;  
      }
#endif
      IHXRequest* pRequest = NULL;

      IHXCommonClassFactory* pCCF;
      HX_RESULT retVal = m_pContext->QueryInterface(IID_IHXCommonClassFactory, (void**)&pCCF);
      
      if (SUCCEEDED(retVal))
      {
          retVal = pCCF->CreateInstance(CLSID_IHXRequest, (void**)&pRequest);

          if(retVal == HXR_OK)
          {
            PrepareGetMessage(); // set up m_pSendTCP

            UINT16 count    = m_pSendTCP->GetQueuedItemCount();
            m_pSendTCP->DeQueue(m_pOutBuf,count);

            retVal = pRequest->SetURL(m_pOutBuf);

            IHXKeyValueList* pResponseHeaders = NULL;

            pCCF->CreateInstance(CLSID_IHXKeyValueList, (void**)&pResponseHeaders);

            MIMEHeaderValue* pHeaderValue = NULL;
            MIMEHeader* pHeader = pMessage->getFirstHeader();
            while (pHeader)
            {
                pHeaderValue = pHeader->getFirstHeaderValue();
                CHXString strHeader;
                while (pHeaderValue)
                {
                  CHXString strTemp;
                  pHeaderValue->asString(strTemp);
                  strHeader += strTemp;
                  pHeaderValue = pHeader->getNextHeaderValue();
                  if (pHeaderValue)
                  {
                      strHeader += ", ";
                  }
                }
                IHXBuffer* pBuffer = NULL;
                CHXBuffer::FromCharArray((const char*)strHeader, &pBuffer);
                pResponseHeaders->AddKeyValue(pHeader->name(), pBuffer);
                HX_RELEASE(pBuffer);

                pHeader = pMessage->getNextHeader();
            }

            IHXValues* pResponseValues = NULL;             

            if (HXR_OK == pResponseHeaders->QueryInterface(IID_IHXValues, (void**)&pResponseValues))
            {
                pRequest->SetResponseHeaders(pResponseValues);
            }

            HandleAuthentication(pRequest, pMessage, m_pForiegnHost, m_pProxyHostName);

            HX_RELEASE(pResponseValues);
            HX_RELEASE(pResponseHeaders);

          }

          HX_RELEASE(pCCF);
      }
      HX_DELETE(pMessage);
      return TRUE;
    }
    HX_DELETE(pMessage);
    return FALSE;
}

#define CLOAKED_WWW_AUTHENTICATION_RECENT_KEY "authentication.http.realm.recent"
#define CLOAKED_PROXY_AUTHENTICATION_RECENT_KEY "proxy-authentication.http.realm.recent"

void
HXClientCloakedTCPSocket::ObtainAuthenticationInformation(CHXString& strAuth)
{
    IHXBuffer* pBuffer = NULL;

    CHXString key("no-authentication-information");

    CHXString recentAuthRealmInfo;
    CHXString recentProxyAuthRealmInfo;

    IHXBuffer* pHeaderBuffer = NULL;
    
    HX_RESULT theErr = HXR_OK;

    IHXRegistry* pRegistry = NULL;
    
    m_pContext->QueryInterface(IID_IHXRegistry, (void**)&pRegistry);
    HX_ASSERT(pRegistry);
    
    if (!pRegistry) return;
    
    theErr = pRegistry->GetStrByName(CLOAKED_WWW_AUTHENTICATION_RECENT_KEY, pHeaderBuffer);
    if (SUCCEEDED(theErr))
    {
      HX_ASSERT(pHeaderBuffer);
      recentAuthRealmInfo = CHXString((const char*)pHeaderBuffer->GetBuffer(), pHeaderBuffer->GetSize());
      HX_RELEASE(pHeaderBuffer);
    }

    theErr = pRegistry->GetStrByName(CLOAKED_PROXY_AUTHENTICATION_RECENT_KEY, pHeaderBuffer);
    if (SUCCEEDED(theErr))
    {
      HX_ASSERT(pHeaderBuffer);
      recentProxyAuthRealmInfo = CHXString((const char*)pHeaderBuffer->GetBuffer(), pHeaderBuffer->GetSize());
      HX_RELEASE(pHeaderBuffer);
    }

    key = "proxy-authentication.http:";
    key += m_pProxyHostName;
    key += ":";
    key += recentProxyAuthRealmInfo;

    if (HXR_OK == pRegistry->GetStrByName((const char*)key, pBuffer) )
    {
      if (pBuffer)
      {
          CHXString authString((const char*)pBuffer->GetBuffer(), pBuffer->GetSize());

          strAuth = "Proxy-Authorization: ";
          strAuth += (const char*)authString;
      }
    }
    HX_RELEASE(pBuffer);

    HX_RELEASE(pRegistry);
}

HX_RESULT
HXClientCloakedTCPSocket::HandleAuthentication(IHXRequest* pRequest, HTTPResponseMessage* pMessage,
            const char* pHost, const char* pProxyHost)
{
    HX_RESULT   ResultStatus = HXR_OK;
    UINT32      ulAltURL = 0;
    CHXString   sConnection;
    IHXValues* pNewHeaders = NULL;


    // xxxbobclark The reason we need to extract the IHXPlayer is that
    // later on the authenticator smart pointer needs a context which knows
    // about authentication conversations. this->m_pContext does not know
    // about the authentication conversation. That's why we have to iterate
    // through the players looking for someone. Sheesh.

    if (!pRequest)
    {
        return HXR_UNEXPECTED;
    }

    HX_RESULT retVal = HXR_OK;
    IHXRegistry* pRegistry = NULL;
    retVal = m_pContext->QueryInterface(IID_IHXRegistry, (void**)&pRegistry);
    if (SUCCEEDED(retVal))
    {
      IHXCommonClassFactory* pCCF;
      retVal = m_pCloakContext->QueryInterface(IID_IHXCommonClassFactory, (void**)&pCCF);
      
      if (SUCCEEDED(retVal))
      {
          IHXValues* pResponseHeaders = NULL;
          
          HX_ASSERT(pRequest);
          if (HXR_OK == pRequest->GetResponseHeaders(pResponseHeaders))
          {
            IHXBuffer* pServerHeaderBuffer = NULL;

            HX_ASSERT(pHost);
            if (pHost)
            {
                retVal = pCCF->CreateInstance(CLSID_IHXBuffer,
                        (void**)&pServerHeaderBuffer);
                if (SUCCEEDED(retVal))
                {
                  UINT32 ulHTTPStatus = atoi(pMessage->errorCode());
                  if (ulHTTPStatus == 407 && pProxyHost)
                  {
                      pServerHeaderBuffer->Set((UCHAR*)pProxyHost, strlen(pProxyHost)+1);
                  }
                  else
                  {
                      pServerHeaderBuffer->Set((UCHAR*)pHost, strlen(pHost)+1);
                  }
                  pResponseHeaders->SetPropertyCString("_server", pServerHeaderBuffer);
                  HX_RELEASE(pServerHeaderBuffer);
                }
            }

                // Add the protocol to the response headers because TLC needs it
                IHXBuffer* pProtocol = NULL;
                if (SUCCEEDED(pCCF->CreateInstance(CLSID_IHXBuffer, (void**)&pProtocol)))
                {
                  pProtocol->Set((UCHAR*)"http", strlen("http") + 1);
                  pResponseHeaders->SetPropertyCString("_protocol", pProtocol);
                  HX_RELEASE(pProtocol);
                }
          }

          if (!spClientAuthConversationAuthenticator.IsValid())
          {
            DECLARE_SMART_POINTER_UNKNOWN spUnknownAuthenticator;
            DECLARE_SMART_POINTER
                  (
                  IHXObjectConfiguration
                  ) spObjectConfigurationAuthenticator;
            DECLARE_SMART_POINTER
                  (
                  IHXCommonClassFactory
                  ) spCommonClassFactoryHXCore;

            spCommonClassFactoryHXCore = m_pCloakContext;

            // Starting conversation
            ResultStatus = spCommonClassFactoryHXCore->CreateInstance
                              (
                              CLSID_CHXClientAuthenticator,
                              (void**)&spUnknownAuthenticator
                              );

            if ( SUCCEEDED(ResultStatus) && spUnknownAuthenticator.IsValid() )
            {
                spObjectConfigurationAuthenticator = 
                  (
                  spUnknownAuthenticator
                  );

                spObjectConfigurationAuthenticator->SetContext(m_pCloakContext);

                spClientAuthConversationAuthenticator = 
                  (
                  spUnknownAuthenticator
                  );
            }
          }

          if ( spClientAuthConversationAuthenticator.IsValid()
                  && !spClientAuthConversationAuthenticator->IsDone() )
          {
            HX_ASSERT(pRequest);
            if (pRequest)
            {
                ResultStatus = 
                  (
                  spClientAuthConversationAuthenticator->MakeResponse
                        (
                        this,
                        pRequest
                        )
                  );

            // Flow continues in ResponseReady()
            }
            else
            {
                // Auth Failed!
                spClientAuthConversationAuthenticator->Authenticated(FALSE);
                ResponseReady(HXR_NOT_AUTHORIZED, pRequest);
            }
          }

          HX_RELEASE(pCCF);
      }
      
      HX_RELEASE(pRegistry);
    }
    

    return ResultStatus;
}

// IHXClientAuthResponse
STDMETHODIMP 
HXClientCloakedTCPSocket::ResponseReady( HX_RESULT ResultStatus, IHXRequest* pRequestResponse)
{
    // now if it's an OK result, then I can use pRequestResponse in a new get.

    if (FAILED(ResultStatus))
    {
      return ResultStatus;
    }

    IHXValues* pHeaders = NULL;

    HX_ASSERT(pRequestResponse);
    if (HXR_OK == pRequestResponse->GetRequestHeaders(pHeaders))
    {
      const char* pName;
      IHXBuffer* pBuf;
      HX_RESULT res = pHeaders->GetFirstPropertyCString(pName, pBuf);
      while (res == HXR_OK)
      {

          if (!strcasecmp(pName, "Proxy-Authorization"))
          {
            HX_RESULT retVal = HXR_OK;
            IHXRegistry* pRegistry = NULL;
            retVal = m_pContext->QueryInterface(IID_IHXRegistry, (void**)&pRegistry);

            IHXCommonClassFactory* pCCF = NULL;

            if (m_pContext)
            {
                m_pContext->AddRef();

                // get the CCF
                m_pContext->QueryInterface(IID_IHXCommonClassFactory, (void**)&pCCF);
            }
      
            if (SUCCEEDED(retVal))
            {
                IHXBuffer* pBuffer = NULL;
                retVal = pCCF->CreateInstance(CLSID_IHXBuffer, (void**)&pBuffer);
                UINT32 regid = 0;
          
                HX_ASSERT(SUCCEEDED(retVal));
                if (SUCCEEDED(retVal))
                {
                  IHXBuffer* pHeaderBuffer = NULL;

                  CHXString key;
                  CHXString recentRealmInfo = "";

                  if (!strcasecmp(pName, "Proxy-Authorization"))
                  {
                      key = "proxy-authentication.http:";
                      retVal = pRegistry->GetStrByName(CLOAKED_PROXY_AUTHENTICATION_RECENT_KEY,
                        pHeaderBuffer);

                      if (SUCCEEDED(retVal))
                      {
                        HX_ASSERT(pHeaderBuffer);
                        recentRealmInfo = CHXString((const char*)pHeaderBuffer->GetBuffer(), pHeaderBuffer->GetSize());
                        HX_RELEASE(pHeaderBuffer);
                      }

                  key += m_pProxyHostName;
                  }

                  key += ":";
                  key += recentRealmInfo;

                  HX_ASSERT(!key.IsEmpty());
                  pBuffer->Set(pBuf->GetBuffer(), pBuf->GetSize());

                  regid = pRegistry->GetId((const char*)key);
                  if (!regid)
                  {
                      pRegistry->AddStr((const char*)key, pBuffer);
                  }
                  else
                  {
                      pRegistry->SetStrByName((const char*)key, pBuffer);
                  }

                  HX_RELEASE(pBuffer);
                  HX_RELEASE(pHeaderBuffer);
                }
            }
            HX_RELEASE(pCCF);
          }
          HX_RELEASE(pBuf);

          res = pHeaders->GetNextPropertyCString(pName, pBuf);
      }
    }

    CleanUpAndReInitializeStuff();

    return HXR_OK;
}

STDMETHODIMP
HXClientCloakedTCPSocket::HandleCallback(INT32  theCommand, HX_RESULT theError)
{
    if (!m_bInDestructor)
    {
      m_pMutex->Lock();

      DoGetWrite();
      DoPutWrite();
      DoRead();

      m_pMutex->Unlock();
    }

    return HXR_OK;
}

HXClientCloakedTCPSocket::HTTPCloakTCPResponse::HTTPCloakTCPResponse(HXClientCloakedTCPSocket* pOwner, BOOL bIsRead) :
     m_pOwner(pOwner)
    ,m_lRefCount(0) 
    ,m_bIsRead(bIsRead)
{
}

HXClientCloakedTCPSocket::HTTPCloakTCPResponse::~HTTPCloakTCPResponse()
{
}

/*
 *  IUnknown methods
 */

/////////////////////////////////////////////////////////////////////////
//  Method:
//    IUnknown::QueryInterface
//  Purpose:
//    Implement this to export the interfaces supported by your 
//    object.
//
STDMETHODIMP HXClientCloakedTCPSocket::HTTPCloakTCPResponse::QueryInterface(REFIID riid, void** ppvObj)
{
    QInterfaceList qiList[] =
        {
            { GET_IIDHANDLE(IID_IHXTCPResponse), (IHXTCPResponse*)this },
            { GET_IIDHANDLE(IID_IHXInterruptSafe), (IHXInterruptSafe*)this },
            { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXTCPResponse*)this },
        };
    
    return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
}

/////////////////////////////////////////////////////////////////////////
//  Method:
//    IUnknown::AddRef
//  Purpose:
//    Everyone usually implements this the same... feel free to use
//    this implementation.
//
STDMETHODIMP_(ULONG32) HXClientCloakedTCPSocket::HTTPCloakTCPResponse::AddRef()
{
    return InterlockedIncrement(&m_lRefCount);
}

/////////////////////////////////////////////////////////////////////////
//  Method:
//    IUnknown::Release
//  Purpose:
//    Everyone usually implements this the same... feel free to use
//    this implementation.
//
STDMETHODIMP_(ULONG32) HXClientCloakedTCPSocket::HTTPCloakTCPResponse::Release()
{
    if (InterlockedDecrement(&m_lRefCount) > 0)
    {
        return m_lRefCount;
    }

    delete this;
    return 0;
}


/*
 *    IHXTCPResponse methods
 */

STDMETHODIMP HXClientCloakedTCPSocket::HTTPCloakTCPResponse::ConnectDone(HX_RESULT status)
{

    // xxxbobclark this authentication kludge is to ensure that layers "above" me
    // never have to care whether they're using an authenticated proxy or not.
    // So since this cloaked socket has already called its owner with ConnectDone
    // messages, it won't resend those... rather, it will reconstruct the same state
    // that the above layer expects.
    // So we set it up so the next ReadDone will work through the proxy and pass
    // through to the above layer and everything should be cool.

    if (m_pOwner->m_bInAuthenticationKludge)
    {
      m_pOwner->m_bInAuthenticationKludge = FALSE;

      if (m_bIsRead)
      {
          m_pOwner->PreparePostMessage(NULL, 0);
          m_pOwner->DoPutWrite();

          m_pOwner->PrepareGetMessage();
          m_pOwner->DoGetWrite();
      }

      m_pOwner->Read(4096);


      m_pOwner->m_bConnected = TRUE;
      return HXR_OK;
    }

    if (m_bIsRead)
    {
      m_pOwner->GetConnectDone(status == HXR_OK ? TRUE : FALSE);/*m_pGetCtrl*/
    }
    else
    {
      m_pOwner->PutConnectDone(status == HXR_OK ? TRUE : FALSE);/*m_pPutCtrl*/
    }

    return HXR_OK;
}


STDMETHODIMP HXClientCloakedTCPSocket::HTTPCloakTCPResponse::ReadDone(  HX_RESULT   status,
                              IHXBuffer* pBuffer)
{
    if (m_bIsRead)
    {
      m_pOwner->DoGetReadDone(status, pBuffer); /*m_pGetCtrl*/
    }
    else 
    {
      m_pOwner->DoPutReadDone(status, pBuffer); /*m_pPutCtrl*/
    }

    return HXR_OK;
}

STDMETHODIMP HXClientCloakedTCPSocket::HTTPCloakTCPResponse::WriteReady(HX_RESULT status)
{
    if (m_bIsRead)
    {
      m_pOwner->m_pMutex->Lock();
      m_pOwner->DoGetWrite(); /*m_pGetCtrl*/
      m_pOwner->m_pMutex->Unlock();
    }
    else
    {
      m_pOwner->m_bPutWantWritePending = FALSE;
      m_pOwner->m_pMutex->Lock();
      m_pOwner->DoPutWrite(); /*m_pPutCtrl*/
      m_pOwner->m_pMutex->Unlock();
    }

    return HXR_OK;
}

STDMETHODIMP HXClientCloakedTCPSocket::HTTPCloakTCPResponse::Closed(HX_RESULT status)
{
    return HXR_OK;
}

#ifdef _MACINTOSH

HXClientCloakedTCPSocket::MacCloakedTCPSocketAuthenticationCallback::MacCloakedTCPSocketAuthenticationCallback (
      HXClientCloakedTCPSocket* pSocket)
    : m_lRefCount(0)
    , m_ulPendingCallbackID(NULL)
    , m_pSocket(pSocket)
    , m_Status(HXR_OK)
    , m_pInBuffer(NULL)
{
}

HXClientCloakedTCPSocket::MacCloakedTCPSocketAuthenticationCallback::~MacCloakedTCPSocketAuthenticationCallback()
{
}

STDMETHODIMP
HXClientCloakedTCPSocket::MacCloakedTCPSocketAuthenticationCallback::QueryInterface(
                                    REFIID riid, void** ppvObj)
{
    QInterfaceList qiList[] =
        {
            { GET_IIDHANDLE(IID_IHXCallback), (IHXCallback*)this },
            { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXCallback*)this },
        };
    
    return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
}

STDMETHODIMP_(ULONG32)
HXClientCloakedTCPSocket::MacCloakedTCPSocketAuthenticationCallback::AddRef()
{
    return InterlockedIncrement( &m_lRefCount );
}

STDMETHODIMP_(ULONG32)
HXClientCloakedTCPSocket::MacCloakedTCPSocketAuthenticationCallback::Release()
{
    if ( InterlockedDecrement( &m_lRefCount ) > 0 )
    {
      return m_lRefCount;
    }
    
    delete this;
    return 0;
}

STDMETHODIMP
HXClientCloakedTCPSocket::MacCloakedTCPSocketAuthenticationCallback::Func()
{
    m_ulPendingCallbackID = NULL;
    
    if (m_pInBuffer)
    {
      m_pSocket->DoGetReadDone(m_Status, m_pInBuffer);
      HX_RELEASE(m_pInBuffer);
    }
    
    return HXR_OK;
}

#endif


Generated by  Doxygen 1.6.0   Back to index