//  Beta release only.
//
//  Copyright(c) Ivyware Pty Ltd  2002-2009
//               MELBOURNE, VICTORIA, AUSTRALIA, 3130
//
//
//  Description: P2PeerCon base class implementation
//               NOTES: Manages connections between P2PeerHub's
//

#include "StdAfx.h"
#include "Kernel32_Ext.h"
#include "P2PeerCon.h"
#include "P2PeerHub.h"
#include "P2Pwin32.h"

///////////////////////////////////////////////////////////////////////
//  Constructors and destructor
IMPLEMENT_DYNCREATE(P2PeerCon,P2PeerConPlc)

const __time64_t
iLoginTimeoutSeconds = 20;             // Login sequences must be
                                       //   processed within this time

P2PeerCon::P2PeerCon ( )
{
    // Firstly
    RenderThisSafe ( );
}

//
//  Parameters: P2PaddrSTR strThatP2Paddr
//              Identification address for that, or the other end
//
P2PeerCon::P2PeerCon ( P2PaddrSTR pThatP2PaddrSTR
                     , P2Peerio *pP2Peerio )
{
    // Firstly
    RenderThisSafe ( );
    m_oP2Padomain    = pThatP2PaddrSTR;
    //m_oThisP2Paddr   = pThisP2PaddrSTR;
    m_oThatP2Paddr   = pThatP2PaddrSTR;
    if ( !pP2Peerio )
      pP2Peerio = new P2Peerio ( );
    m_pP2Peerio = pP2Peerio -> Register ( this );
}

P2PeerCon::P2PeerCon ( P2Peerio *pP2Peerio )
{
    // Firstly
    RenderThisSafe ( );
    //m_oThisP2Paddr = pThisP2PaddrSTR;
    //m_oThatP2Paddr = pThisP2PaddrSTR;
    if ( !pP2Peerio )
      pP2Peerio = new P2Peerio ( );
    m_pP2Peerio = pP2Peerio -> Register ( this );
}

P2PeerCon::~P2PeerCon ( )
{
    // Timers
    // NOTES: Target specific timers. Others handled in derived class
    CancelP2PmsgTimer ( m_uRestartTimerID );
    CancelP2PmsgTimer ( m_uLoginTimerID );

    // P2PeerMsg queue
    FlushP2PeerMsg ( );
    DeleteCriticalSection ( &m_oCSectMsgQue );

    // Resources
    Drop ( 0 );

    // OVERLAPPED resources
    // NOTES: Reclaimed previously, to be sure, to be sure.
    DropOVERLAPPED ( m_pOVERLAPPEDsend,    false );
    DropOVERLAPPED ( m_pOVERLAPPEDrecv,    false );
    DropOVERLAPPED ( m_pOVERLAPPEDaccept,  false );
    DropOVERLAPPED ( m_pOVERLAPPEDconnect, false );

    // Garbage collection
    //delete m_pP2PeerMsgQue;
    delete m_pP2Peerio;
    if ( m_pEvent )
      m_pEvent -> Cancel ( false );
    delete m_pstrVisualSummary;
ASSERT(AfxCheckMemory()); //TODO: Delete-Debugging
}

void
P2PeerCon::RenderThisSafe ( )
{
    // Publics
    m_uAutoRestart       = 20000;      // Autorestart delay in MSecs

    // Resources
    m_hP2PmsgCon         = NULL;
    m_hCPort             = NULL;
    m_hFile              = NULL;
    m_hFileCPort         = NULL;
    m_dwCompletionKey    = (UINT_PTR)this;
    m_hCPortP2PumpID     = 0;
    m_pP2PeerTarget      = 0;
    m_pP2Peerio          = 0;
    m_pstrVisualSummary  = 0;

    // Timers
    m_uRestartTimerID    = 0;
    m_uLoginTimerID      = 0;

    // Overlapped IO 
    m_pP2PeerMsgSend     = 0;
    //m_bP2PeerMsgHdr      = true;

    // Overlapped IO buffers
    m_pOVERLAPPEDsend    = 0;
    m_pOVERLAPPEDrecv    = 0;
    m_pOVERLAPPEDaccept  = 0;
    m_pOVERLAPPEDconnect = 0;

    // Queues
    //m_pP2PeerMsgQue  = new P2PeerMsgQue ( 0 );
    InitializeCriticalSection ( &m_oCSectMsgQue );

    // Addressing
    m_eP2PeerIDmap   = P2PeerIDmap_NONE;
    //m_oThisP2Paddr  = 0; m_nThisP2PeerID1 = 0;
    //m_oThatP2Paddr  = 0; m_nThatP2PeerID1 = 0;

    // Control 
    m_dwState        = 0;
    m_eP2PeerConMode = P2PeerCon_Unknown;
    m_pEvent         = 0;
}

//
//  Description: Splits listening connection into listening and
//               accepted P2PeerCon'nections
//               NOTES: Derived classes must delegate
//
//
//  Parameters:  P2PeerCon **pConListen = 0
//               Previously manufactured listening instance
//
//               P2PeerCon **pConAccept = 0
//               Previously manufactured accept instance
//
/*void
P2PeerCon::AcceptSplit ( P2PeerCon **ppConListen, P2PeerCon **ppConAccept )
{
    // Locals
    P2PeerCon *pConListen = *ppConListen;
    P2PeerCon *pConAccept = *ppConAccept;

    // Manufacture listening object
    // NOTES: This object by default
    if ( !pConListen )
      pConListen = this;

    // Settlement
    if ( pConListen != this )
    {
           pConListen -> m_hCPortP2PumpID  = m_hCPortP2PumpID;
           pConListen -> m_hCPort          = m_hCPort;
    delete pConListen -> m_pP2Peerio;
           pConListen -> m_pP2Peerio       = m_pP2Peerio -> Clone();
           pConListen -> m_pP2Peerio -> Register ( pConListen );
           pConListen -> m_oThisP2Paddr    = m_oThisP2Paddr;
           pConListen -> m_oThisP2Paddr1   = m_oThisP2Paddr1;
           pConListen -> m_oThatP2Paddr    = m_oThatP2Paddr;
           pConListen -> m_oThatP2Paddr1   = m_oThatP2Paddr1;
           pConListen -> m_eP2PeerIDmap    = m_eP2PeerIDmap;
           pConListen -> m_eP2PeerConMode  =    P2PeerCon_SERVICE;
           pConListen -> m_dwState
                       = m_dwState & ~( ConState_Recv
                                      | ConState_Send
                                      | ConState_Login );
    }

    // Manufacture acceptance object
    // NOTES: Mandatory P2PeerConPlc integration
    if ( !pConAccept )
    {
      ASSERT(0); //TODO:LJM FIX_ME
       //pConAccept  = new P2PeerCon ( );
      *this += pConAccept;
    }

    // Settlement
    if ( pConAccept != this )
    {
           pConAccept -> m_hCPortP2PumpID  = m_hCPortP2PumpID;
           pConAccept -> m_hCPort          = m_hCPort;
    delete pConAccept -> m_pP2Peerio;
           pConAccept -> m_pP2Peerio       = m_pP2Peerio -> Clone();
           pConAccept -> m_pP2Peerio -> Register ( pConAccept );
           pConAccept -> m_oThisP2Paddr    = m_oThisP2Paddr;
           pConAccept -> m_oThisP2Paddr1   =   "";
           pConAccept -> m_oThatP2Paddr    = m_oThatP2Paddr;
           pConAccept -> m_oThatP2Paddr1   =   "";
           pConAccept -> m_eP2PeerIDmap    = m_eP2PeerIDmap;
           pConAccept -> m_oP2Padom        = m_oP2Padom;
           pConAccept -> m_eP2PeerConMode  =    P2PeerCon_Accept;
           pConAccept -> m_dwState
                       = m_dwState & ~( ConState_Recv
                                      | ConState_Send
                                      | ConState_Login );
    }

    // Tidy up, and
    // NOTES:
    P2PaddrSTR strThatP2Paddr;
    *ppConListen   = pConListen;
    strThatP2Paddr = pConListen -> m_oThatP2Paddr;
                     pConListen -> m_oThatP2Paddr = strThatP2Paddr;// | 0x00000001;
    *ppConAccept   = pConAccept;
    strThatP2Paddr = pConAccept -> m_oThatP2Paddr;
                     pConAccept -> m_oThatP2Paddr = strThatP2Paddr;// &~0x00000001;
}*/

P2PeerCon*
P2PeerCon::AcceptSpawn ( P2PeerCon *pConSpawn )
{
    // Accept
    // NOTES: Mandatory P2PeerConPlc integration
    if (  pConSpawn          != this &&
         !pConSpawn->m_hP2PmsgCon       )
         //pConSpawn->m_pPrev ==   0  &&
         //pConSpawn->m_pNext ==   0     )
    {
      //*this += pConSpawn;
      pConSpawn -> m_pP2PeerTarget = m_pP2PeerTarget;
      PostP2PmsgCon ( GetP2PmsgHubID(/*this*/), pConSpawn );
    }

    // Settlement
    if ( pConSpawn != this )
    {
           pConSpawn -> m_hCPortP2PumpID  = m_hCPortP2PumpID;
           pConSpawn -> m_hCPort          = m_hCPort;
    delete pConSpawn -> m_pP2Peerio;
           pConSpawn -> m_pP2Peerio       = m_pP2Peerio -> Clone();
           pConSpawn -> m_pP2Peerio -> Register ( pConSpawn );
           //pConSpawn -> m_oThisP2Paddr    = m_oThisP2Paddr;
           pConSpawn -> m_oThisP2Paddr1   = _T("");
           pConSpawn -> m_oThatP2Paddr    = m_oThatP2Paddr;
           pConSpawn -> m_oThatP2Paddr1   = _T("");
           pConSpawn -> m_eP2PeerIDmap    = m_eP2PeerIDmap;
           pConSpawn -> m_eP2PeerConMode  =    P2PeerCon_Accept;
           pConSpawn -> m_oP2Padomain     = m_oP2Padomain;
           pConSpawn -> m_dwState
                       = m_dwState & ~( ConState_Recv
                                      | ConState_Send
                                      | ConState_Login );
    }

    // Tidy up, and
    // NOTES:
    return pConSpawn;
}

///////////////////////////////////////////////////////////////////////
//  IOCP Integration
//

//
//  Description: Associates IO Completion Port
//               NOTES: Refer win32 CreateIoCompletionPort() for
//                      further details
//
//
//  Parameters:  HANDLE hFile
//               File for with IOCP instance is to be created
void
P2PeerCon::CreateIOCP ( HANDLE hFile )
{
    // To be sure, to be sure
    if ( ( m_hFile          &&
           m_hFile != hFile    ) ||
           m_hFileCPort             )
      EVERR->Module  (__FUNCTION__"(%s-%s)"
                     , (P2PaddrSTR)GetP2PaddrHub()
                     , (P2PaddrSTR)GetP2Paddress() )
           ->Message (_T("IOCP already created") )
           ->Advice  (_T("Incomplete reset or sequence bug") )
           ->HResult ( GetLastError() )->Throw();
    m_hFile = hFile;

    // IO completion port attachment
    // NOTES:
    m_hFileCPort = CreateIoCompletionPort ( m_hFile
                                          , m_hCPort
                                          , m_dwCompletionKey
                                          , 0 );
    if ( m_hFileCPort == 0 )
      EVERR->Module  (__FUNCTION__"(%s-%s)"
                     , (P2PaddrSTR)GetP2PaddrHub()
                     , (P2PaddrSTR)GetP2Paddress() )
           ->Message (_T("CreateIoCompletionPort() failed") )
           ->HResult ( GetLastError() )->Throw();
}

//
//  Description: Processes I/O completion port packets mapped to and
//               instance of this object.
//               NOTES: Such packets are retieved via the Microsoft
//                      File Storage SDK - GetQueuedCompletionStatus()
//                      module.
//
//  Exceptions:  Notification will eventually be routed through to
//               ON_P2PeerCon_CLOSE() handler. At which point Restart()
//               may be used on non accepted sockets or this object
//               conDROP'ed
//            :  ON_P2PeerCon_CLOSE() handler to which this posted object
//               is routed MUST cancel the attached event.  OnClose()
//               contains such default processing.
//            :  P2P_Close notification MUST be performed once per
//               attached event. Subsequent P2P_Close notifications are
//               blocked until the original event is cancelled.
//
//
//  Parameters:  DWORD dwError
//               Number of bytes transferred during an I/O operation
//               that has completed.  Refer ::GetQueuedCompletionStatus
//               for further details.
//               
//               DWORD dbBytes
//               Number of bytes transferred during an I/O operation
//               that has completed.  Refer ::GetQueuedCompletionStatus
//               for further details.
//
//               OVERLAPPEDcon *pOVERLAPPEDcon
//               Address of OVERLAPPEDcon structure that was specified
//               for the I/O operation.
//
bool
P2PeerCon::On_QueuedCompletionStatus ( DWORD dwError
                                     , DWORD dwBytes
                                     , OVERLAPPEDcon *pOVERLAPPEDcon )
{
    // Pre-processing
    HRESULT hr = dwError;
    if ( hr == S_OK )
      hr = pOVERLAPPEDcon -> hr;
ASSERT(pOVERLAPPEDcon->bQueued);
ASSERT(AfxIsValidAddress(pOVERLAPPEDcon, sizeof(OVERLAPPEDcon)));
    // Recv
    // NOTES: Default implementation.
    if ( pOVERLAPPEDcon == m_pOVERLAPPEDrecv )
    {
ASSERT(m_eP2PeerConMode!=P2PeerCon_SERVICE);
      // Success
      // NOTES: Received buffer may contain several messages, in which
      //        case we process to completion.
      //      : Handle 3rdParty formats by overriding P2Peerio
      releaseOVERLAPPED ( pOVERLAPPEDcon );
      if (   hr == S_OK &&
           m_hFileCPort    )
      {
        P2PeerMsg *pMsg;
        pOVERLAPPEDcon -> dwBytes += dwBytes;
        while ( (pMsg=m_pP2Peerio
                    ->RecvP2PeerMsg(m_hFile,pOVERLAPPEDcon)) != NULL )
        {
          // Interface mapping
          // NOTES: Mandatory
          if ( m_eP2PeerIDmap )
            PerformIFaddrTransform ( true, pMsg );

          // Special interceptions
          if (  pMsg->Map_MatchName(P2Pmsg_Login) &&
               !pMsg->GetSource()                    )
            PostP2Pmsg ( m_oThatP2Paddr, CN_P2PeerCon, P2P_Login
                       , this, pMsg, m_hCPortP2PumpID ); //was 0
          else if ( pMsg->Map_MatchName(P2Pmsg_Login) &&
                    pMsg->GetSource()                       )
            PostP2Pmsg ( pMsg->GetSource(), CN_P2PeerCon, P2P_Login
                       , this, pMsg, m_hCPortP2PumpID ); //was 0
          else if ( pMsg->Map_MatchName(P2Pmsg_LoginAck) )
            PostP2Pmsg ( m_oThatP2Paddr, CN_P2PeerCon, P2P_LoginAck
                       , this, pMsg, m_hCPortP2PumpID ); // was 0
        /*else if ( pMsg->GetDestin() == m_oThisP2Paddr &&
                    pMsg->Type() == MSG_P2PeerAck           )
            PostP2Pmsg ( m_oThatP2Paddr, CN_P2PeerCon, P2P_Ack
                        , this, pMsg )*/
          else
            PostP2Pmsg ( pMsg->GetSource(), CN_P2PeerMsg, 0
                       ,(P2PeerCon *)0, pMsg, m_hCPortP2PumpID ); // was 0
        }
      }

      // Failure
      // NOTES: Remote connection dropped out.  P2PeerMsg receipt for
      //        connection discontinued.
      //      : Perform On_P2PeerCon_CLOSE() notification.
      else if (   hr         &&
                m_hFileCPort    )
      {
        EVERR->Module  (__FUNCTION__"(%s-%s)"
                       , GetP2PaddrHub().c_str()
                       , (P2PaddrSTR)m_oThatP2Paddr )
              ->Message_T("Receive failure" )
              ->Advice_T ("Conection dropped out" )
              ->HResult( hr )->Throw();
      }

      // Cancellation
      // NOTES: IoCancel(m_hFileCPort), CloseHandle(m_hFileCPort) or
      //        whatever issued.  P2PeerMsg receipt for connection
      //        discontinued
      else
        m_pOVERLAPPEDrecv = DropOVERLAPPED ( pOVERLAPPEDcon );
    }

    // Send 
    // NOTES: Confirmation must be received before next P2PeerMsg
    //        transmission is attempted.
    else if ( pOVERLAPPEDcon == m_pOVERLAPPEDsend )
    {
ASSERT(m_eP2PeerConMode!=P2PeerCon_SERVICE);
      // Success
      // NOTES: Passed buffer contains details of previous message
      //        and return with details of next
      //      : Handle 3rdParty formats by overriding RecvP2PeerMsg()
      releaseOVERLAPPED ( pOVERLAPPEDcon );
      if (   hr == S_OK &&
            m_hFileCPort    )
      {
        if ( m_pP2PeerMsgSend )
        {
          ((P2PeerMsgPrefix *)m_pP2PeerMsgSend->r_data().c_vBlob())
                             -> uiState &= ~P2PeerMsgState_Posted;
          delete m_pP2Peerio -> PreDestroySendP2PeerMsg ( m_pP2PeerMsgSend );
          m_pP2PeerMsgSend = 0;
        }
        // Fetch next message
        if ( m_pP2PeerMsgSend == NULL )
        {
          m_pP2PeerMsgSend = GetP2PeerMsg ( );
          // Interface mapping
          // NOTES: Mandatory
          if ( m_eP2PeerIDmap   &&
               m_pP2PeerMsgSend    )
            PerformIFaddrTransform ( false, m_pP2PeerMsgSend );
         }

        // May become idle here
        if ( m_pP2PeerMsgSend )
          m_pP2Peerio -> SendP2PeerMsg ( m_hFile, m_pP2PeerMsgSend
                                       , pOVERLAPPEDcon );
        else if ( (m_dwState&ConState_CloseOnIdle) == ConState_CloseOnIdle )
          Drop ( 0 );
      }

      // Failure
      // NOTES: Remote connection dropped out.  P2PeerMsg transmission
      //        for connection discontinued.
      //      : Perform On_P2PeerCon_CLOSE() notification.
      else if (   hr         &&
                m_hFileCPort    )
        EVERR->Module  (__FUNCTION__"(%s-%s)"
                       , GetP2PaddrHub().c_str()
                       , m_oThatP2Paddr.c_str() )
              ->Message("Send failed\n"
                        "ADVICE\t: Connection dropped out" )
              ->HResult( hr )->Throw();

      // Cancellation
      // NOTES: IoCancel(m_hFileCPort), CloseHandle(m_hFileCPort) or
      //        whatever issued.  P2PeerMsg transmission for connection
      //        discontinued
      else
        m_pOVERLAPPEDsend = DropOVERLAPPED ( pOVERLAPPEDcon );
    }

    // Accept
    // NOTES: Perform On_P2PeerCon_ACCEPT() notification.  At which
    //        point the intercepting handler will initiate state
    //        changes.
    //      : Perform On_P2PeerCon_LISTEN() notification.  At which
    //        point the intercepting handler will listen for another
    //        connection
    else if ( pOVERLAPPEDcon == m_pOVERLAPPEDaccept )
    {
ASSERT(m_eP2PeerConMode==P2PeerCon_SERVICE);
      // Success
      // NOTES: Honour expectation that the On_P2PeerCon_ACCEPT()
      //        processed before the ON_P2PeerCon_LISTEN()
      //        notification
      releaseOVERLAPPED ( pOVERLAPPEDcon );
      if (   hr == S_OK &&
           m_hFileCPort    )
      {
        // Split into listening, usually this, and accepted P2PeerCon
        // NOTES: The underlying P2PeerCon objects have different styles
        //        according to the derived type.
        //P2PeerCon *pConAccept = 0, *pConListen = 0;
        //AcceptSplit ( &pConListen, &pConAccept );

        // Perform ON_P2PeerOLD_ACCEPT() notification
        // NOTES: Accepted P2PeerCon is spawned within the handler
        //if ( pConAccept == 0 && pConListen == 0 )
        PostP2Pmsg ( m_oThatP2Paddr, CN_P2PeerCon, P2P_Accept
                   , this, 0, m_hCPortP2PumpID );

        // ON_P2PeerOLD_ACCEPT() notification
        // NOTES: Spawn accepted connection
        //if ( pConAccept )
        //PostP2Pmsg ( pConAccept->m_oThatP2Paddr, CN_P2PeerCon, P2P_Accept
        //           , pConAccept, 0 );

        // ON_P2PeerCon_LISTEN() notification
        // NOTES: Listen for new connection, or stop listening etc
        //if ( pConListen )
        //{
        //P2PaddrSTR strThatP2Paddr = pConListen->m_oThatP2Paddr;
        //PostP2Pmsg ( pConListen->m_oThatP2Paddr.IsNull()
        //                 ?pConListen->m_oThatP2Paddr
        //                 :pConListen->m_oThisP2Paddr
        //PostP2Pmsg ( (strThatP2Paddr&1)==0?pConListen->m_oThisP2Paddr
        //                                  :pConListen->m_oThatP2Paddr
        //           , CN_P2PeerCon, P2P_Listen, pConListen, 0 );
        //}
      }

      // Failure
      // NOTES: Accepted connection failure
      else if (   hr         &&
                m_hFileCPort    )
        EVERR->Module (__FUNCTION__"[%s-%s]"
                      , GetP2PaddrHub().c_str()
                      , m_oThatP2Paddr.c_str() )
             ->Message(_T("Overlapped accept failed"))
             ->HResult( hr ) -> Throw();

      // Cancellation
      // NOTES: IoCancel(m_hFileCPort), CloseHandle(m_hFileCPort) or
      //        whatever issued.  Acceptance discontinued 
      else
        m_pOVERLAPPEDaccept = DropOVERLAPPED ( pOVERLAPPEDcon );
    }

    // Connect
    // NOTES: Perform On_P2PeerCon_CONNECT() notification.  At which
    //        point the intercepting handler will initiate the
    //        appropriate state changes.
    else if ( pOVERLAPPEDcon == m_pOVERLAPPEDconnect )
    {
ASSERT(m_eP2PeerConMode!=P2PeerCon_SERVICE);
      // Success
      // NOTES: OVERLAPPEDsend and OVERLAPPEDrecv buffer creation
      //        triggers IO Completion port scheduling immediately
      //        after the object has been routed through the
      //        P2PeerCon_MAP.
      releaseOVERLAPPED ( pOVERLAPPEDcon );
      if (   hr == S_OK &&
            m_hFileCPort    )
      {
        if ( m_pOVERLAPPEDsend == NULL )
          m_pOVERLAPPEDsend = MakeOVERLAPPED ( );
        if ( m_pOVERLAPPEDrecv == NULL )
          m_pOVERLAPPEDrecv = MakeOVERLAPPED ( m_pP2Peerio->GetMaxRecvSize() );

        // Perform On_P2PeerCon_CONNECT notification
        PostP2Pmsg  ( m_oThatP2Paddr, CN_P2PeerCon, P2P_Connect
                    , this, (P2PeerMsg *)0, m_hCPortP2PumpID );
      }

      // Failure
      // NOTES: Connection failed to complete
      //      : Perform On_P2PeerCon_CLOSE() notification.
      else if (   hr         &&
                m_hFileCPort    )
      {
        EVERR->Module (__FUNCTION__"(%s-%s)"
                      , GetP2PaddrHub().c_str()
                      , m_oThatP2Paddr.c_str() )
             ->Message(_T("Remote connection request failed") )
             ->Advice (_T("Remote server not running") )
             ->Advice (_T("Firewall configuration") )
                           /*"\t: Invalid connection address [%s]\n"
                             "\t: Invalid connection port [%i]"
                      , m_oCSIpAddress
                      , m_nIpPort*/
             ->HResult( hr )->Throw();
      }

      // Cancellation
      // NOTES: IoCancel(m_hFileCPort), CloseHandle(m_hFileCPort) or
      //        whatever issued.
      else
        m_pOVERLAPPEDconnect = DropOVERLAPPED ( pOVERLAPPEDcon );
    }

    // P2Psignal_MSG
    // NOTES: Injects P2PeerMsg into P2PeerCon object.  Primarily
    //        used to emulate 3rdParty and legacy interfaces from
    //        P2Peerio derived objects
    else if ( pOVERLAPPEDcon->nSigID == P2PsigCon_MSG )
    {
ASSERT(m_eP2PeerConMode!=P2PeerCon_SERVICE);
      releaseOVERLAPPED ( pOVERLAPPEDcon );
      //INT_PTR whatever = *(INT_PTR*)(pOVERLAPPEDcon->pBuffer);
      P2PeerMsg *pMsg  =  (P2PeerMsg *)*(INT_PTR*)(pOVERLAPPEDcon->pBuffer); 
      pOVERLAPPEDcon   = DropOVERLAPPED ( pOVERLAPPEDcon, false );
ASSERT(m_pOVERLAPPEDrecv);
      // Special interceptions
      if ( pMsg->Map_MatchName(P2Pmsg_Login) )
        PostP2Pmsg ( m_oThatP2Paddr, CN_P2PeerCon, P2P_Login
                   , this, pMsg, m_hCPortP2PumpID );
      else if ( pMsg->Map_MatchName(P2Pmsg_LoginAck) )
        PostP2Pmsg ( m_oThatP2Paddr, CN_P2PeerCon, P2P_LoginAck
                   , this, pMsg, m_hCPortP2PumpID );
      else
        PostP2Pmsg ( pMsg->GetSource(), CN_P2PeerMsg, 0
                   ,(P2PeerCon *)0, pMsg, m_hCPortP2PumpID );
    }

    // P2PsigID_CLOSE
    // NOTES: Perform On_P2PeerCon_CLOSE() notification.  At which
    //        point the intercepting handler will manage state
    //        changes.
    else if ( pOVERLAPPEDcon->nSigID == P2PsigCon_CLOSE )
    {
      releaseOVERLAPPED ( pOVERLAPPEDcon );
      pOVERLAPPEDcon = DropOVERLAPPED ( pOVERLAPPEDcon, false );
      Drop ( 0 );
    }

    // P2PsigID_CLOSEONIDLE
    // NOTES: Perform On_P2PeerCon_CLOSE() notification.  At which
    //        point the intercepting handler will manage state
    //        changes.
    else if ( pOVERLAPPEDcon->nSigID == P2PsigCon_CLOSEONIDLE )
    {
      releaseOVERLAPPED ( pOVERLAPPEDcon );
      pOVERLAPPEDcon = DropOVERLAPPED ( pOVERLAPPEDcon, false );
      m_dwState |= ConState_CloseOnIdle;
      if ( m_pP2PeerMsgSend == 0 )
        Drop ( 0 );
    }

    // P2PsigID_SHUTDOWN
    // NOTES: Perform On_P2PeerCon_DESTROY() notification.  At which
    //        point the intercepting handler will initiate state
    //        changes.
    else if ( pOVERLAPPEDcon->nSigID == P2PsigCon_SHUTDOWN )
    {
      releaseOVERLAPPED ( pOVERLAPPEDcon );
      pOVERLAPPEDcon = DropOVERLAPPED ( pOVERLAPPEDcon, false );
      this -> Destroy ( );
      PostP2Pmsg ( m_oThatP2Paddr
                 , CN_P2PeerCon, m_hFile ? P2P_Close : P2P_Shutdown
                 , this, (P2PeerMsg *)0, m_hCPortP2PumpID  );
    }

    // P2PsigID_DESTROY
    // NOTES: Perform On_P2PeerCon_DESTROY() notification.  At which
    //        point the intercepting handler will initiate state
    //        changes.
    else if ( pOVERLAPPEDcon->nSigID == P2PsigCon_DESTROY )
    {
      releaseOVERLAPPED ( pOVERLAPPEDcon );
      pOVERLAPPEDcon = DropOVERLAPPED ( pOVERLAPPEDcon, false );
      this -> Destroy ( );
      PostP2Pmsg ( m_oThatP2Paddr
                 , CN_P2PeerCon, m_hFile ? P2P_Close : P2P_Shutdown
                 , this, (P2PeerMsg *)0, m_hCPortP2PumpID  );
      //Drop ( 0 );
      //Destroy ( );
    }

    // Command
    // NOTES: Last resort P2Peerio delegation
    else if ( pOVERLAPPEDcon )
    {
      if ( !m_pP2Peerio      ||
           !m_pP2Peerio        
                -> On_QueuedCompletionStatus ( dwError
                                             , dwBytes
                                             ,  pOVERLAPPEDcon) )
      {
        releaseOVERLAPPED( pOVERLAPPEDcon );
        pOVERLAPPEDcon = DropOVERLAPPED   ( pOVERLAPPEDcon );
        EVERR->Module   (__FUNCTION__"(%s-%s)"
                        , GetP2PaddrHub().c_str()
                        , m_oThatP2Paddr.c_str() )
             ->Message_T( "Unhandled OVERLAPPEDcon object" )
             ->Advice_T ( "Bug (SNHappen)" )
             ->HResult( hr )->Throw();
      }
    }

    // Tidy up and
    return true;
}

//
//  Description: Allocate and optionally size OVERLAPPEDcon object
//
//
//  Parameters:  DWORD dwBytesMax = 0
//               Allocated OVERLAPPEDcon.pBuffer size
//
//
//  Returns:     OVERLAPPEDcon*
//               Allocated and optionally size buffer
//
OVERLAPPEDcon*
P2PeerCon::MakeOVERLAPPED ( DWORD dwBytesMax )
{
    // Allocation
    OVERLAPPEDcon *pOVERLAPPEDcon = new OVERLAPPEDcon;
    ZeroMemory ( pOVERLAPPEDcon, sizeof(OVERLAPPEDcon) );

    // Buffers
    if ( dwBytesMax )
      pOVERLAPPEDcon -> pBuffer = new char [dwBytesMax];
    pOVERLAPPEDcon -> dwBytesMax = dwBytesMax;

    // Tidy up, and
    return pOVERLAPPEDcon;
}

//
//  Description: Drops OVERLAPPEDcon object
//               NOTES: Cross-references against and sets to NULL
//                      OVERLAPPEDcon class pointers
//
//
//  Parameters:  OVERLAPPEDcon *pOVERLAPPEDcon
//               Object to be dropped
//
//               bool bNotify = true
//               Perform appropriate P2PeerCon_MAP notifications
//
OVERLAPPEDcon*
P2PeerCon::DropOVERLAPPED ( OVERLAPPEDcon *pOVERLAPPEDcon
                          , bool /*bNotify*/ )
{
    // To be sure, to be sure
ASSERT(AfxCheckMemory());
    if ( pOVERLAPPEDcon == NULL )
      return 0;

    // OVERLAPPEDsend
    if ( pOVERLAPPEDcon == m_pOVERLAPPEDsend )
      m_pOVERLAPPEDsend = 0;

    // OVERLAPPEDrecv
    else if ( pOVERLAPPEDcon == m_pOVERLAPPEDrecv )
      m_pOVERLAPPEDrecv = 0;

    // OVERLAPPEDconnect
    else if ( pOVERLAPPEDcon == m_pOVERLAPPEDconnect )
      m_pOVERLAPPEDconnect = 0;

    // OVERLAPPEDaccept
    else if ( pOVERLAPPEDcon == m_pOVERLAPPEDaccept )
      m_pOVERLAPPEDaccept = 0;

    // Garbage collection
    if ( pOVERLAPPEDcon->pUserDB1 == pOVERLAPPEDcon->pBuffer )
      pOVERLAPPEDcon->pBuffer = 0;
    delete [] pOVERLAPPEDcon->pUserDB1;
    if ( pOVERLAPPEDcon->pUserDB2 == pOVERLAPPEDcon->pBuffer )
      pOVERLAPPEDcon->pBuffer = 0;
    delete [] pOVERLAPPEDcon->pUserDB2;
    if ( pOVERLAPPEDcon->dwBytesMax > 0 ) //TODO:LJM should this be pBuffer
      delete [] pOVERLAPPEDcon->pBuffer;
    delete    pOVERLAPPEDcon;
ASSERT(AfxCheckMemory());
    return     0;
}

//
//  Description: Posts passed OVERLAPPEDcon object 
//
//
//  Parameters:  OVERLAPPEDcon *pOVERLAPPEDcon
//               Object to be posted
void
P2PeerCon::PostOVERLAPPED ( OVERLAPPEDcon *pOVERLAPPEDcon )
{
    // To be sure, to be sure
    bool bQueued = pOVERLAPPEDcon -> bQueued;
                   pOVERLAPPEDcon -> bQueued = bQueued;
if(pOVERLAPPEDcon->bQueued)
{
Sleep(500);//TODO:LJM timing hack
pOVERLAPPEDcon->bQueued=false;
}
    ASSERT(!pOVERLAPPEDcon->bQueued);
    if ( pOVERLAPPEDcon->bQueued )
      EVERR->Module  (__FUNCTION__"(%s-%s)"
                     , GetP2PaddrHub().c_str()
                     , m_oThatP2Paddr.c_str() )
           ->Message ("Passed OVERLAPPEDcon buffer locked" )
           ->Throw();

    // To be sure, to be sure
    if (  pOVERLAPPEDcon->dwBytesMax > 0 &&
         !pOVERLAPPEDcon->pBuffer           ) 
      EVERR->Module  (__FUNCTION__"(%s-%s)"
                     , GetP2PaddrHub().c_str()
                     , m_oThatP2Paddr.c_str() )
           ->Message ("Corrupted OVERLAPPEDcon configuration" )
           ->Advice  ("Bug(SNHappen)")
           ->Throw();
            
    // Implementation
ASSERT(m_dwCompletionKey==(UINT_PTR)this); //TODO: Delete, debugging
    prepareOVERLAPPED ( pOVERLAPPEDcon );
if(pOVERLAPPEDcon!=m_pOVERLAPPEDsend&&
   pOVERLAPPEDcon!=m_pOVERLAPPEDrecv&&
   pOVERLAPPEDcon!=m_pOVERLAPPEDaccept&&
   pOVERLAPPEDcon!=m_pOVERLAPPEDconnect)
   pOVERLAPPEDcon=pOVERLAPPEDcon;
    if ( !PostQueuedCompletionStatus( m_hCPort // was m_hFileCPort changed for P2PeerConDmx
                                    , 0
                                    , m_dwCompletionKey 
                                    ,(OVERLAPPED *)pOVERLAPPEDcon) )
    {
      releaseOVERLAPPED ( pOVERLAPPEDcon );
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , GetP2PaddrHub().c_str()
                    , m_oThatP2Paddr.c_str() )
           ->Message("PostQueuedCompletionStatus() failed" )
           ->HResult( GetLastError() )->Throw();
    }
}

//
//  Prepares OVERLAPPEDcon objects prior to posting to the win32 IO
//  Completion port utilities
//  NOTES: prepareOVERLAPPED() must be complimented by 
//         releaseOVERLAPPED() for any given OVERLAPPED con object
//
//
//  Parameters:  OVERLAPPEDcon *pOVERLAPPEDcon
//               Object to be prepared
void
P2PeerCon::prepareOVERLAPPED ( OVERLAPPEDcon *pOVERLAPPEDcon )
{
    // Implementation
    ASSERT(!pOVERLAPPEDcon->bQueued);
    pOVERLAPPEDcon -> bQueued = true;
    pOVERLAPPEDcon -> hr      = S_OK;
    AddRef ( );
}

//
//  Releases OVERLAPPEDcon objects upon return from the win32 IO
//  Completion port utilities
//  NOTES: prepareOVERLAPPED() must be complimented by
//         releaseOVERLAPPED() for any given OVERLAPPED con object
//
//
//  Parameters:  OVERLAPPEDcon *pOVERLAPPEDcon
//               Object to be released
void
P2PeerCon::releaseOVERLAPPED ( OVERLAPPEDcon *pOVERLAPPEDcon )
{
    // Implementation
    ASSERT(pOVERLAPPEDcon->bQueued);
    pOVERLAPPEDcon -> bQueued = false;
    Release ( );
}

//
//  Asynchronously signals this connection
//  NOTES: Provides facility by which P2PeerCon objects may be
//         controlled other than P2PeerCon_MAP handlers
//                     
//
//  Parameters:  P2Psignal uiSignal
//               Signal to be posted
//
//               void *pvData
//               Signal data
//
//               int iDataSize
//               Signal data size
void
P2PeerCon::Signal ( P2PsigID nSigID, void *pvData, int iDataSize  )
{
    // Interception - Start P2PeerMsg receipt
    if ( nSigID == P2PsigCon_RECV )
    {
      if ( !m_pOVERLAPPEDrecv->bQueued &&
           !m_pOVERLAPPEDrecv->bDelete    )
        PostOVERLAPPED ( m_pOVERLAPPEDrecv );
      return;
    }

    // Manufacture - Generic control
    OVERLAPPEDcon *pOVERLAPPEDcon = MakeOVERLAPPED ( iDataSize );
    pOVERLAPPEDcon -> nSigID = nSigID;
    if ( iDataSize )
      memcpy ( pOVERLAPPEDcon->pBuffer, pvData, iDataSize );
    pOVERLAPPEDcon->dwBytes = iDataSize;

    // Implementation
ASSERT(m_dwCompletionKey==(UINT_PTR)this); //TODO: Delete, debugging
    prepareOVERLAPPED ( pOVERLAPPEDcon );
    if ( !PostQueuedCompletionStatus( m_hCPort
                                    , 0
                                    , m_dwCompletionKey 
                                    , (OVERLAPPED *)pOVERLAPPEDcon) )
    {
      releaseOVERLAPPED ( pOVERLAPPEDcon );
      pOVERLAPPEDcon = DropOVERLAPPED ( pOVERLAPPEDcon );
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , GetP2PaddrHub().c_str()
                    , m_oThatP2Paddr.c_str() )
           ->Message("PostQueuedCompletionStatus() failed\n" )
           ->HResult( GetLastError() )->Throw();
    }
}

///////////////////////////////////////////////////////////////////////
//  Timers

//
//  Sets PIT for connection
//  NOTES: Outstanding timers must be cancelled in destructor for
//         this object
//
//
//  Parameters:  P2Pmsecs_t uMSecDelay
//               Specifies the time-out value, in milliseconds
//
//               DWORD dwUserKey
//               User defined data key supplied to timeout handler
//
//  Returns:     PITimerID
//               Identifier of the new timer if successful. An
//               application passes this value to the KillTimer member
//               function to kill the timer.
//
PITimerID
P2PeerCon::SetPITimer ( P2Pmsecs_t uMSecDelay, DWORD dwUserKey )
{
    // Simply
    // NOTES: Handler for this object always called
    return SetP2PmsgTimer ( m_hCPortP2PumpID, this, uMSecDelay, dwUserKey );
}

//
//  PIT handler for connection
//  NOTES: Override for specialisation.  But always delegate
//         unhandled timers through
//
//
//  Parameters:  bool bCancel
//               Cancellation flag.  Refer CancelPITimer() for further
//               details
//                 true... Cancelled
//                 false.. Triggered
//
//               PITimerID nPITimerID
//               Timer identification.  Refer SetPITimer() for
//               further details
//
//               DWORD dwUserKey
//               Timer user key
//
void
P2PeerCon::On_PITimer ( bool bCancel
                      , PITimerID nPITimerID, DWORD dwUserKey )
{
    // Startup timer
    // NOTES: Perform connection restart.  Context is managed in the
    //        handler.  Nothing is static in an asynchronous environment
    if ( nPITimerID == m_uRestartTimerID )
    {
      m_uRestartTimerID = 0;           // No longer exists
      if ( !bCancel )
        PostP2Pmsg ( m_oThatP2Paddr, CN_P2PeerCon, P2P_Startup
                   , this, 0, m_hCPortP2PumpID );
    }

    // Login timer
    // NOTES: Login must be performed within nominated period, otherwise
    //        connection is closed via thrown exception
    //      : Should the remote P2PeerHub fail to login, we end up in
    //        limbo.  It's the exchange of P2PeerMsg's that drives the
    //        P2PeerCon'nection objects
    else if ( nPITimerID == m_uLoginTimerID )
    {
      m_uLoginTimerID = 0;             // No longer exists
      if ( !bCancel )
        EVERR->Module (__FUNCTION__"()[%s-%s]"
                      , (P2PaddrSTR)GetP2PaddrHub()
                      , (P2PaddrSTR)GetP2Paddress() )
             ->Message("Login timed out\n"
                       "ADVICE\t: Remote connection withheld login\n"
                             "\t: Problem within remote P2PeerHub" )
             ->Throw  ();
    }

    // Unknown timer
    // NOTES: Report and ignore.  Maintain existing P2PeerCon state
    else
      EVERR->Module (__FUNCTION__"(%i,%i)[%s-%s]"
                    , nPITimerID, dwUserKey
                    , (P2PaddrSTR)GetP2PaddrHub()
                    , (P2PaddrSTR)GetP2Paddress() )
           ->Message("PITimer not handled\n"
                     "ADVICE\t: Ignored, bug (SNHappen)")
           ->Cancel ();
}

///////////////////////////////////////////////////////////////////////
//  IO Implementation
//  NOTES: Manages IO Completion Port implementation
//

//
//  Description: Drops the encapsulated connection and performs the
//               appropriate ON_P2PeerCon_CLOSE() notification
//               NOTES: Should an EVENT already be attached the passed
//                      EVENT is simply cancelled.
//
//
//  Parameters:  P2Pevent *pEVENT
//               Precipitating event.  May be NULL
//               NOTES: Control assumed over life cycle.
//
void
P2PeerCon::Drop ( P2Pevent *pEVENT )
{
    // State
    SetState ( 0, ON_ConClose );

    // Restart timers
    if ( m_uRestartTimerID > 0 )
      KillP2PmsgTimer ( m_uRestartTimerID );
    m_uRestartTimerID = 0;

    // Protocol 
    if ( m_pP2Peerio )
      m_pP2Peerio -> Reset ( );

    // Reclaim IO Completion Port buffers
    if (  m_pOVERLAPPEDaccept          &&
         !m_pOVERLAPPEDaccept->bQueued    )
      m_pOVERLAPPEDaccept = DropOVERLAPPED ( m_pOVERLAPPEDaccept );
    if (  m_pOVERLAPPEDconnect          &&
         !m_pOVERLAPPEDconnect->bQueued    )
      m_pOVERLAPPEDconnect = DropOVERLAPPED ( m_pOVERLAPPEDconnect );
    if (  m_pOVERLAPPEDsend          &&
         !m_pOVERLAPPEDsend->bQueued    )
      m_pOVERLAPPEDsend = DropOVERLAPPED ( m_pOVERLAPPEDsend );
    if (  m_pOVERLAPPEDrecv          &&
         !m_pOVERLAPPEDrecv->bQueued    )
      m_pOVERLAPPEDrecv = DropOVERLAPPED ( m_pOVERLAPPEDrecv );

    // Firstly drop connection
    // NOTES: Cancels all outstanding overlapped IO
    if ( m_hFile )
    {
      if (     CloseHandle(m_hFile) &&
             !pEVENT                &&
           !m_pEvent                    )
        pEVENT =
         EVERR->Module (__FUNCTION__"(%s-%s)"
                       , GetP2PaddrHub().c_str()
                       , m_oThatP2Paddr.c_str() )
              ->Message("CloseHandle() failed\n"
                        "ADVICE\t: Bug (SNHappen)" )
              ->HResult( GetLastError() );
      m_hFile      = 0;
      m_hFileCPort = 0;
    }

    // Secondly attach the precipitating EVENT
    // NOTES: Original precipitating event is latched.  Once
    //        latched such events are cancelled as part of the
    //        ON_P2PeerCon_CLOSE() handler processing
    if ( m_pEvent )
      pEVENT = pEVENT -> Cancel ( false );
    else
      m_pEvent = pEVENT;

    // Perform notification
    // NOTES: Assigned pump is mandatory
    //      : Previously latched event cancels notification
    if ( ( !m_pEvent           ||
            m_pEvent == pEVENT    )                      &&
           !PostDestroyState()                           &&
           !CheckP2PmsgPumpState(CN_P2PeerCon,P2P_Close)    )
      PostP2Pmsg ( m_oThatP2Paddr, CN_P2PeerCon, P2P_Close
                 , this, (P2PeerMsg *)0, m_hCPortP2PumpID  );
}

///////////////////////////////////////////////////////////////////////
//  P2PeerMsg Management

//
//  Posts a message to this P2PeerCon object. Thread safe
//  asynchronous operation
//  NOTES: Posted messages are pended until connection is completed
//
//
//  Parameters:  P2PeerMsg *pMsg
//               Message to be posted.
//
//  Returns:     P2PeerMsg*
//               Null P2PeerMsg routed pointer.  Otherwise exception.
//
P2PeerMsg*
P2PeerCon::PostP2PeerMsg ( P2PeerMsg *pMsg )
{
    // Append to queue
    if ( g_bP2Pmsg_AssertValid )
      pMsg -> AssertValid ( );
    //m_pP2PeerMsgQue->Append ( pMsg );
    P2PsafeCS  oSafeCS  = m_oCSectMsgQue;
    P2Pri_t    nP2Pri   = pMsg->Priority();
    //P2PeerMsg *pMsgLock = pMsg;
    ASSERT(m_eP2PeerConMode!=P2PeerCon_SERVICE);

    // Optimise - no entries, last entry or first entry
    // NOTES: Most common or normal senarios
    if ( m_oCListMsgQue.GetCount() <= 0                 ||
         m_oCListMsgQue.GetTail()->Priority() <= nP2Pri ||
         m_oCListMsgQue.GetHead()->Priority()  > nP2Pri    )
      m_oCListMsgQue.AddTail ( pMsg );

    // Sorted
    else
    {
      POSITION pos = m_oCListMsgQue.GetTailPosition();
      POSITION posInsert = 0;
      while ( pos )
      {
        posInsert = pos;
        if ( m_oCListMsgQue.GetPrev(pos)->Priority() <= nP2Pri )
        {
          m_oCListMsgQue.InsertAfter ( posInsert, pMsg );
          pMsg = 0;
          pos  = 0;
        }
      }
      if ( pMsg )
        m_oCListMsgQue.AddHead ( pMsg );
    }

    // Wakeup
    // NOTES: P2PeerCon may be idle and waiting for next P2PeerMsg
    // P2PeerMsg_P2PeerConLock ( pMsgLock, true );
    if ( m_pP2PeerMsgSend == 0      &&
         m_pOVERLAPPEDsend          &&
        !m_pOVERLAPPEDsend->bQueued    )
      PostOVERLAPPED ( m_pOVERLAPPEDsend );

    // Tidy up and
    return (P2PeerMsg *)0;
}
//
//  Fetches the next highest priority message from P2PeerMsg queue.
//  NOTES: Client assumes responsibility for life cycle of
//         retrieved P2PeerMsg
//       : Clears the P2PeerioTag, assumption is message will be
//         passed to posted P2Peerio object for transmission
//
//
//  Returns:     P2PeerMsg*
//               Retrieved message
//                 0.. No entries on the queue
//               
P2PeerMsg*
P2PeerCon::GetP2PeerMsg ( )
{
    // Isolation and retrieval
    P2PsafeCS oSafeCS = m_oCSectMsgQue;
    if ( m_oCListMsgQue.GetCount() <= 0 )
      return 0;
    return m_oCListMsgQue.RemoveHead();
}

//
//  Flushes queued P2PeerMsg's
//
void
P2PeerCon::FlushP2PeerMsg ( )
{
    // Isolation and garbage collection
    P2PsafeCS oSafeCS = m_oCSectMsgQue;
    while ( m_oCListMsgQue.GetCount() > 0 )
      delete m_oCListMsgQue.RemoveHead();
}

//
//  Retrieves queued P2PeerMsgt
//
//  Returns:     int
//               Number of queued P2PeerMsg's
int
P2PeerCon::GetP2PeerMsgCount ( )
{
    // Delegate
    return m_oCListMsgQue.GetCount();
}

///////////////////////////////////////////////////////////////////////
//  Connection state management 
//  NOTES: Referenced from P2PeerCon_MAP handlers only

//
//  Initiates startup processing
//  NOTES: Startup processing must be performed for all connection
//         objects.  Usually from the ON_P2PeerCon_STARTUP handlers.
//       : Override Listen() or Connect() to provide interface
//         specialisation
//               
void
P2PeerCon::OnStartup ( )
{
    // State confirmation
    // NOTES: Audits the development cycle and traps illogical states
    //        that can propogate subtle bugs.
    //      : Low frequency check more than worth the overhead
    if ( !CheckP2PmsgPumpState(CN_P2PeerCon,P2P_Startup) )
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , GetP2PaddrHub().c_str()
                    , m_oThatP2Paddr.c_str() )
           ->Message("Requires ON_P2PeerCon_STARTUP handler state\n"
                     "ADVICE\t: Bug (SNHappen)" )
           ->Throw  ( );

    // Event state
    // NOTES: Previously latched P2Pevent's MUST have been cleared
    if ( m_pEvent )
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , GetP2PaddrHub().c_str()
                    , GetP2Paddress().c_str() )
           ->Message("Attempt to startup connection with uncleared P2Pevent\n"
                     "ADVICE\t: OnClose() processing not performed" )
           ->Throw  ( );
}

//
//  Performs default listen mode processing
//  NOTES: Processing must be performed for all connections.  Usually
//         from ON_P2PeerCon_STARTUP type handler.
//       : Override implementation for various connection
//         types, WSA, RS232, etc
//
bool
P2PeerCon::Listen ( )
{
    // State confirmation
    // NOTES: Audits the development cycle and traps illogical states
    //        that can propogate subtle bugs.
    //      : Low frequency check more than worth the overhead
    if ( !CheckP2PmsgPumpState(CN_P2PeerCon,P2P_Startup) )
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , GetP2PaddrHub().c_str()
                    , m_oThatP2Paddr.c_str() )
           ->Message("Requires ON_P2PeerCon_STARTUP handler state\n"
                     "ADVICE\t: Bug (SNHappen)" )
           ->Throw  ( );

    // Done
    // NOTES: Derived class provides implementation
    m_eP2PeerConMode = P2PeerCon_SERVICE;
ASSERT(!m_pOVERLAPPEDrecv&&!m_pOVERLAPPEDsend);
    return true;
}

//
//  Description: Performs default listening processing
//               NOTES: This processing must be performed for all
//                      listening sockets
//
void
P2PeerCon::OnListen ( )
{
    // State confirmation
    // NOTES: Audits the development cycle and traps illogical states
    //        that can propogate subtle bugs.
    //      : Low frequency check more than worth the overhead
    if ( !CheckP2PmsgPumpState(CN_P2PeerCon,P2P_Listen) )
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , GetP2PaddrHub().c_str()
                    , m_oThatP2Paddr.c_str() )
           ->Message("Requires ON_P2PeerCon_LISTEN handler state\n"
                     "ADVICE\t: Bug (SNHappen)" )
           ->Throw  ( );
ASSERT(!m_pOVERLAPPEDrecv&&!m_pOVERLAPPEDsend);
}

//
//  Initiates accept facility for object.
//  NOTES: Usually referenced from ON_P2PeerCon_STARTUP or recursively
//         from ON_P2PeerOLD_ACCEPT handlers.
//       : Accepted connections are processed via ON_P2PeerOLD_ACCEPT
//         handlers
//
//
//  Returns:     bool
//
bool
P2PeerCon::Accept ( )
{
    // State confirmation
    // NOTES: Audits the development cycle and traps illogical states
    //        that can propogate subtle bugs.
    //      : Low frequency check more than worth the overhead
    if ( !CheckP2PmsgPumpState(CN_P2PeerCon,P2P_Listen) &&   //TODO:LJM This state will be phased out
         !CheckP2PmsgPumpState(CN_P2PeerCon,P2P_Accept)    )
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , GetP2PaddrHub().c_str()
                    , m_oThatP2Paddr.c_str() )
           ->Message("Requires ON_P2PeerOLD_ACCEPT handler state\n"
                     "ADVICE\t: Bug (SNHappen)" )
           ->Throw  ( );

    // Mode confirmation
    // NOTES: Audits the development cycle and traps illogical states
    //        that can propogate subtle bugs.
    //      : Low frequency check more than worth the overhead
    if ( m_eP2PeerConMode != P2PeerCon_SERVICE )
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , GetP2PaddrHub().c_str()
                    , m_oThatP2Paddr.c_str() )
           ->Message("Requires Listen mode\n"
                     "ADVICE\t: Bug (SNHappen)" )
           ->Throw  ( );

    // Done
    return true;
}

//
//  Performs ACCEPT'ed connection processing
//  NOTES: This processing must be performed for all accepted
//         connections
//       : Reference from within ON_P2PeerOLD_ACCEPT() handlers
//
//
//  Parameters:  P2PaddrSTR pThatP2PaddrSTR
//               Address assigned to remote client
//               NOTES: Assignment may be defered to the login 
//                      phase by specifying a NULL value
//
P2PeerCon*
P2PeerCon::OnAccept ( )
{
    // State confirmation
    // NOTES: Audits the development cycle and traps illogical states
    //        that can propogate subtle bugs.
    //      : Low frequency check more than worth the overhead
    if ( !CheckP2PmsgPumpState(CN_P2PeerCon,P2P_Accept) )
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , GetP2PaddrHub().c_str()
                    , (P2PaddrSTR)m_oThatP2Paddr )
           ->Message("Requires ON_P2PeerOLD_ACCEPT handler state\n"
                     "ADVICE\t: Bug (SNHappen)" )
           ->Throw  ( );

    // Mode confirmation
    // NOTES: Audits the development cycle and traps illogical states
    //        that can propogate subtle bugs.
    //      : Low frequency check more than worth the overhead
    if ( m_eP2PeerConMode != P2PeerCon_SERVICE )
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , GetP2PaddrHub().c_str()
                    , (P2Paddr)m_oThatP2Paddr )
           ->Message("Requires P2PeerCon_SERVICE mode not %i\n"
                     "ADVICE\t: Bug (SNHappen)"
                    , m_eP2PeerConMode )
           ->Throw  ( );

    // Spawn accepted P2PeerCon
    P2PeerCon *pConAccept = AcceptSpawn ( 0 );
    if ( pConAccept == NULL )
      return pConAccept;

    // Associate with IO Completion Port
    // NOTES: All subsequent notifications received via queued
    //        IO Completion Packets
    if ( !pConAccept->m_hFileCPort &&
          pConAccept->m_hFile         )
      pConAccept -> CreateIOCP ( pConAccept->m_hFile );

    // Activate P2PeerMsg receipt
    // NOTES: Action is negated whenever OVERLAPPEDrecv object already
    //        exists
    //if ( !pConAccept->m_pOVERLAPPEDsend )
    //  pConAccept -> m_pOVERLAPPEDsend = pConAccept -> MakeOVERLAPPED ( );
    //if ( !pConAccept->m_pOVERLAPPEDrecv )
    //  pConAccept -> m_pOVERLAPPEDrecv = pConAccept -> MakeOVERLAPPED ( MAX_P2Psize );
    //if ( !pConAccept->m_pOVERLAPPEDrecv->bQueued )
    //  pConAccept -> PostOVERLAPPED ( pConAccept->m_pOVERLAPPEDrecv );

    // Tidy up, and
    pConAccept -> SetState ( ConState_Send | ConState_Recv, 0 );
    return pConAccept;
}

void
P2PeerCon::OnAccept ( const P2Paddr oThatP2Paddr )
{
    // State confirmation
    // NOTES: Audits the development cycle and traps illogical states
    //        that can propogate subtle bugs.
    //      : Low frequency check more than worth the overhead
    if ( !CheckP2PmsgPumpState(CN_P2PeerCon,P2P_Accept) )
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , GetP2PaddrHub().c_str()
                    , (P2PaddrSTR)m_oThatP2Paddr )
           ->Message("Requires ON_P2PeerOLD_ACCEPT handler state\n"
                     "ADVICE\t: Bug (SNHappen)" )
           ->Throw  ( );

    // Mode confirmation
    // NOTES: Audits the development cycle and traps illogical states
    //        that can propogate subtle bugs.
    //      : Low frequency check more than worth the overhead
    if ( m_eP2PeerConMode != P2PeerCon_Accept )
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , GetP2PaddrHub().c_str()
                    , (P2Paddr)m_oThatP2Paddr )
           ->Message("Requires P2PeerCon_Accept mode not %i\n"
                     "ADVICE\t: Bug (SNHappen)"
                    , m_eP2PeerConMode )
           ->Throw  ( );

    // To be sure, to be sure
if(!oThatP2Paddr.IsNull())
m_oThatP2Paddr=oThatP2Paddr;//TODO:LJM Hack to make progress
    if (   !oThatP2Paddr.IsNull()        &&
         !m_oThatP2Paddr.IsNull()        &&
          m_oThatP2Paddr != oThatP2Paddr    )
      EVERR->MODULE
           ->Message("Attempt to swap P2Paddr's from [%s] to [%s]"
                    , (P2PaddrSTR)m_oThatP2Paddr
                    , (P2PaddrSTR)  oThatP2Paddr )
           ->Throw();

    // Assign
    if ( !oThatP2Paddr.IsNull() )
      m_oThatP2Paddr = oThatP2Paddr;

    // Associate with IO Completion Port
    // NOTES: All subsequent notifications received via queued
    //        IO Completion Packets
    if ( !m_hFileCPort )
      CreateIOCP ( m_hFile );

    // Activate P2PeerMsg receipt
    // NOTES: Action is negated whenever OVERLAPPEDrecv object already
    //        exists
    if ( !m_pOVERLAPPEDrecv )
      m_pOVERLAPPEDrecv = MakeOVERLAPPED ( m_pP2Peerio->GetMaxRecvSize() );
    if ( !m_pOVERLAPPEDsend )
      m_pOVERLAPPEDsend = MakeOVERLAPPED ( );
    if ( !m_pOVERLAPPEDrecv->bQueued )
      PostOVERLAPPED ( m_pOVERLAPPEDrecv );

    // Tidy up, and
    SetState ( ConState_Send | ConState_Recv, 0 );
    return;
}

//
//  Performs default connection processing
//  NOTES: Processing must be performed for all connections.  Usually
//         from ON_P2PeerCon_STARTUP type handler.
//       : Override implementation for various connection types, WSA,
//         RS232, etc
//
bool
P2PeerCon::Connect ( )
{
    // State confirmation
    // NOTES: Audits the development cycle and traps illogical states
    //        that can propogate subtle bugs.
    //      : Low frequency check more than worth the overhead
    if ( !CheckP2PmsgPumpState(CN_P2PeerCon,P2P_Startup) )
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , GetP2PaddrHub().c_str()
                    , m_oThatP2Paddr.c_str() )
           ->Message(_T("Requires ON_P2PeerCon_STARTUP handler state") )
           ->Message(_T("Bug (SNHappen)") )
           ->Throw  ( );

    // Mode confirmation
    // NOTES: Audits the development cycle and traps illogical states
    //        that can propogate subtle bugs.
    //      : Low frequency check more than worth the overhead
    if ( m_eP2PeerConMode != P2PeerCon_CLIENT )
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , GetP2PaddrHub().c_str()
                    , m_oThatP2Paddr.c_str() )
           ->Message(_T("Requires connection mode") )
           ->Advice (_T("Bug (SNHappen)") )
           ->Throw  ( );

    // Done
    return true;
}

//
//  Performs CONNECT'ed processing
//  NOTES: This processing must be performed for all connections
//       : Reference from within ON_P2PeerCon_CONNECT() handlers
//
//
void
P2PeerCon::OnConnect ( )
{
    // State confirmation
    // NOTES: Audits the development cycle and traps illogical states
    //        that can propogate subtle bugs.
    //      : Low frequency check more than worth the overhead
    if ( !CheckP2PmsgPumpState(CN_P2PeerCon,P2P_Connect) )
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , GetP2PaddrHub().c_str()
                    , m_oThatP2Paddr.c_str() )
           ->Message(_T("Requires ON_P2PeerCon_CONNECT handler state") )
           ->Advice (_T("Bug (SNHappen)") )
           ->Throw  ( );

    // Activate P2PeerMsg flow
    // NOTES: Action is negated should either of the OVERLAPPEDrecv
    //        or OVERLAPPEDsend objects already exists
    if ( !m_pOVERLAPPEDrecv )
      m_pOVERLAPPEDrecv = MakeOVERLAPPED ( MAX_P2Psize );
    if ( !m_pOVERLAPPEDrecv->bQueued )
      PostOVERLAPPED ( m_pOVERLAPPEDrecv );
    if ( !m_pOVERLAPPEDsend )
      m_pOVERLAPPEDsend = MakeOVERLAPPED ( );

    // Tidy up, and
    SetState ( ConState_Send | ConState_Recv, 0 );
    return;
}

//
//  Perform login sequence with P2PeerCon object within remote P2PeerHub
//  NOTES: First connection message exchanged and initiates P2Paddr
//         negotiations.  Logically object must be connected
//       : Upon receipt the remote P2PeerHub will process the request
//         via OnLogin(), respond via LoginAck(), which in turn
//         will be procesed via OnLoginAck() within this object
//       : 3rd Party type interfaces MUST simulate above exchange.
//
//
//  Parameters:  P2PaddrSTR strThatP2Paddr
//               Optionally assigned address of remote client
//                 0.. Empty, adopt currently assigned address
//                 ?.. Adopt passed remote client identification
//
//               const void *pvLoginMsg
//               Login message as supplied to remote P2PeerCon object
//
//               P2Psize_t iSize
//               Size of above message
//
//  Returns:     BOOL
//               Success summary
//                 true... Successfully queued request
//                 false.. Operation failed. Refer GetLastEvent()
//                         for further details
//
void
P2PeerCon::Login ( P2PaddrSTR strThatP2Paddr
                 , const void *pvLoginMsg, P2Psize_t iSize )
{
    // Introduce locals
    P2Paddr oThatP2Paddr(strThatP2Paddr);
    if ( oThatP2Paddr.IsNull() )
      oThatP2Paddr = m_oThatP2Paddr;

//if(strThatP2Paddr==~0)
//strThatP2Paddr=0;//FIX-ME default value should be 0
    // State confirmation
    // NOTES: Audits the development cycle and traps illogical states
    //        that can propogate subtle bugs.
    //      : Low frequency check more than worth the overhead
    if ( !CheckP2PmsgPumpState(CN_P2PeerCon,P2P_Connect) &&
         !CheckP2PmsgPumpState(CN_P2PeerCon,P2P_Accept)     )
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , GetP2PaddrHub().c_str()
                    , (P2PaddrSTR)m_oThatP2Paddr )
           ->Message("Requires ON_P2PeerCon_CONNECT, ACCEPT handler state")->AFP(iSize)
           ->Advice ("Bug (SNHappen)" )
           ->Throw  ( );

    // To be sure, to be sure
    /*if (       oP2Paddr.IsNull() &&
         m_oThatP2Paddr.IsNull()    )
      EVERR->MODULE
           ->Message("Remote P2PeerHub has null P2Paddr[%s]"
                    , (P2PaddrSTR)oP2Paddr )
           ->Throw();*/

    // To be sure, to be sure
    /*if (    !oP2Paddr.IsNull()        &&
          !m_oThatP2Paddr.IsNull()    &&
           m_oThatP2Paddr != oP2Paddr    )
      EVERR->MODULE
           ->Message("Attempt to swap remote P2Paddr from [%s] to [%s]"
                    , (P2PaddrSTR)m_oThatP2Paddr
                    , (P2PaddrSTR)oP2Paddr )
           ->Throw();*/

    if ( !oThatP2Paddr.IsNull() )
      m_oThatP2Paddr = oThatP2Paddr;

    // Implementation
    // NOTES: Logon acknowledgement is posted directly to the
    //        output queue.
P2PeerMsg *pMsg = new P2PeerMsg( GetP2PaddrHub(), m_oThatP2Paddr //TODO:LJM delete this
               , P2Pmsg_Login
               , pvLoginMsg, iSize );
//ASSERT(pMsg->Exists(VBLockBSTR_MSG));
//pMsg->r_node(0)+= P3PmsgNode(P3PmsgField("Test",21));
PostP2PeerMsg(pMsg);//Delete above
    // FIX-ME possible memory leak if PostP2PeerMsg() fails
    //PostP2PeerMsg ( new P2PeerMsg ( GetP2PaddrHub(), m_oThatP2Paddr
    //                              , P2Pmsg_Login
    //                              , pvLoginMsg, iSize ) );

    // Tidy up, and
    return;
}

void
P2PeerCon::Login_Fractal ( P2PaddrSTR strThisP2Paddr1, P2PaddrSTR strThatP2Paddr1
                         , const void *pvLoginMsg, P2Psize_t iSize )
{
    // Introduce locals
    P2Paddr oThisP2Paddr1(strThisP2Paddr1);
    if ( oThisP2Paddr1.IsNull() )
      oThisP2Paddr1 = m_oThisP2Paddr1;
    P2Paddr oThatP2Paddr1(strThatP2Paddr1);
    if ( oThatP2Paddr1.IsNull() )
      oThatP2Paddr1 = m_oThatP2Paddr1;

//if(strThatP2Paddr==~0)
//strThatP2Paddr=0;//FIX-ME default value should be 0
    // State confirmation
    // NOTES: Audits the development cycle and traps illogical states
    //        that can propogate subtle bugs.
    //      : Low frequency check more than worth the overhead
    if ( !CheckP2PmsgPumpState(CN_P2PeerCon,P2P_Connect) &&
         !CheckP2PmsgPumpState(CN_P2PeerCon,P2P_Accept)     )
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , GetP2PaddrHub().c_str()
                    , (P2PaddrSTR)m_oThatP2Paddr )
           ->Message("Requires ON_P2PeerCon_CONNECT, ACCEPT handler state")->AFP(iSize)
           ->Advice ("Bug (SNHappen)" )
           ->Throw  ( );

    // To be sure, to be sure
    /*if (       oP2Paddr.IsNull() &&
         m_oThatP2Paddr.IsNull()    )
      EVERR->MODULE
           ->Message("Remote P2PeerHub has null P2Paddr[%s]"
                    , (P2PaddrSTR)oP2Paddr )
           ->Throw();*/

    // To be sure, to be sure
    /*if (    !oP2Paddr.IsNull()        &&
          !m_oThatP2Paddr.IsNull()    &&
           m_oThatP2Paddr != oP2Paddr    )
      EVERR->MODULE
           ->Message("Attempt to swap remote P2Paddr from [%s] to [%s]"
                    , (P2PaddrSTR)m_oThatP2Paddr
                    , (P2PaddrSTR)oP2Paddr )
           ->Throw();*/

    if ( !oThisP2Paddr1.IsNull() )
      m_oThisP2Paddr1 = oThisP2Paddr1;
    if ( !oThatP2Paddr1.IsNull() )
      m_oThatP2Paddr1 = oThatP2Paddr1;
    m_eP2PeerIDmap = P2PeerIDmap_FRACTAL;

    // Implementation
    // NOTES: Logon acknowledgement is posted directly to the
    //        output queue.
P2PeerMsg *pMsg = new P2PeerMsg( GetP2PaddrHub(), m_oThatP2Paddr //TODO:LJM delete this
               , P2Pmsg_Login
               , pvLoginMsg, iSize );
//ASSERT(pMsg->Exists(VBLockBSTR_MSG));
//pMsg->r_node(0)+= P3PmsgNode(P3PmsgField("Test",21));
PostP2PeerMsg(pMsg);//Delete above
    // FIX-ME possible memory leak if PostP2PeerMsg() fails
    //PostP2PeerMsg ( new P2PeerMsg ( GetP2PaddrHub(), m_oThatP2Paddr
    //                              , P2Pmsg_Login
    //                              , pvLoginMsg, iSize ) );

    // Tidy up, and
    return;
}

//
//  Performs login request processing
//  NOTES: Default processing for remote client Login() request
//       : Processing cycle is completed via subsequent
//         LoginAck() response.
//
//
//  Parameters:  const P2Paddr oThatP2Paddr
//               Assigned remote identification address
//                 0.. Retain existing identification
//                 ?.. Adopt passed remote client identification
//
void
P2PeerCon::OnLogin ( const P2Paddr& oThatP2Paddr )
{
//if(strThatP2Paddr==~0)
//strThatP2Paddr=0;//FIX-ME default value should be 0
    // State confirmation
    // NOTES: Audits the development cycle and traps illogical states
    //        that can propogate subtle bugs.
    //      : Low frequency check more than worth the overhead
    if ( !CheckP2PmsgPumpState(CN_P2PeerCon,P2P_Login) )
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , GetP2PaddrHub().c_str()
                    , (P2PaddrSTR)m_oThatP2Paddr )
           ->Message("Requires ON_P2PeerCon_LOGIN handler state\n"
                     "ADVICE\t: Bug (SNHappen)" )
           ->Throw  ( );

    // Selected timers
    CancelP2PmsgTimer ( m_uLoginTimerID );

    // To be sure, to be sure
    // NOTES: P2Paddr is mandatory at this stage
    if (   oThatP2Paddr.IsNull() &&
         m_oThatP2Paddr.IsNull()    )
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , GetP2PaddrHub().c_str()
                    , (P2PaddrSTR)m_oThatP2Paddr )
           ->Message("Null remote P2Paddr[%s]"
                    , (P2PaddrSTR)m_oThatP2Paddr )
           ->Throw();

    // To be sure, to be sure
    // NOTES: P2Paddr MUST have previously been assigned to the hub
    P2Paddr oP2PaddrHub = GetP2Paddress();
    if ( oP2PaddrHub.IsNull() )
      EVERR->Module (__FUNCTION__"(%s)"
                    , (P2PaddrSTR)m_oThatP2Paddr )
           ->Message("Null local P2PmsgHub address" )
           ->Throw();

    // To be sure, to be sure
    // NOTES: Passed strP2Paddr MUST exist within the P2Paddr domain
    //        assigned to this P2PeerCon
    //LPCTSTR str1=oThatP2Paddr;
    //LPCTSTR str2=m_oThatP2Paddr;
    //LPCTSTR str3=m_oP2Padomain;
    if (   !oThatP2Paddr.IsNull()              &&
         !m_oThatP2Paddr.IsNull()              &&
         !m_oP2Padomain.IsMapped(oThatP2Paddr)     )
      EVERR->Module (__FUNCTION__"(%s)"
                    , (P2PaddrSTR)m_oThatP2Paddr )
           ->Message("Login P2Paddr[%s] is not within domain [%s]"
                    ,   oThatP2Paddr.c_str()
                    , m_oP2Padomain.c_str() )
           ->Throw();

    // Assignment
    if ( !oThatP2Paddr.IsNull() )
      m_oThatP2Paddr = oThatP2Paddr;

    // Tidy up, and
    SetState ( ConState_Login, 0 );
    return;
}

//
//  Perform login acknowledgement to complete remote client integration
//  NOTES: Usually performed in the ON_P2PeerCon_LOGIN() handler.
//
//
//  Parameters:  P2PaddrSTR strThatP2Paddr
//               Identification address assigned to the remote client
//                 0.. Retain existing identification
//                 ?.. Adopt passed remote client identification
//
//               void *pvLoginAck
//               Login message
//
//               P2PeerSize_t iSize
//               Size of above message
//
//  Returns:     BOOL
//               Success summary
//                 TRUE... Successfully queued request
//                 FALSE.. Operation failed. Refer P2Pevent::GetLast()
//                         for further details
//
BOOL
P2PeerCon::LoginAck ( const P2Paddr& oThatP2Paddr
                    , const void *pvLoginAck, P2Psize_t iSize )
{
    // Introduce locals
    BOOL bResult = TRUE;

//if(strThatP2Paddr==~0)
//strThatP2Paddr=0;//FIX-ME default value should be 0

    // To be sure, to be sure
    if (   oThatP2Paddr.IsNull() &&
         m_oThatP2Paddr.IsNull()    )
      EVERR->Module (__FUNCTION__"(%s,%i,%i)"
                    , m_oThatP2Paddr.c_str(), (int)pvLoginAck, iSize )
           ->Message("Remote hub has null P2Paddr")
           ->Advice ("P2PeerCon=[%s->null]"
                    , GetP2PaddrHub().c_str() )
           ->Group("P2P")->Throw();

    // To be sure, to be sure
    if ( GetP2PaddrHub().IsNull()  )
      EVERR->Module (__FUNCTION__"(%s,%i,%i)"
                    , m_oThatP2Paddr.c_str(), (int)pvLoginAck, iSize )
           ->Message("Local hub has null P2Paddr")
           ->Advice ("P2PeerCon=[null->%s]"
                    , m_oThatP2Paddr.c_str() )
           ->Group("P2P")->Throw();

    // Accepted P2Paddr assignment
    // NOTES: Such P2Paddr's may be auto-assigned from the domain
    if (  m_eP2PeerConMode == P2PeerCon_Accept &&
           !oThatP2Paddr.IsNull()              &&
         !m_oThatP2Paddr.IsNull()                 )
    {
      /*TODO:Activate debugging if ( !m_oP2Padomain.IsMapped(oThatP2Paddr) )
        EVERR->Module (__FUNCTION__"(%s,%i,%i)"
                      , m_oThatP2Paddr.c_str(), (int)pvLoginAck, iSize )
             ->Message("LoginAck P2Paddr[%s] is not within domain [%s]"
                      ,   oThatP2Paddr.c_str()
                      , m_oP2Padomain.c_str() )
             ->Advice ("P2PeerCon=[%s->%s]"
                      , GetP2PaddrHub().c_str(),m_oThatP2Paddr.c_str() )
             ->Advice ("Connection mis-match" )
             ->Advice ("Attempted security breach" )
             ->Group("P2P")->Throw();*/
      m_oThatP2Paddr = oThatP2Paddr;
    }

    // To be sure, to be sure
    if (   !oThatP2Paddr.IsNull()          &&
         !m_oThatP2Paddr.IsNull()          &&
          m_oThatP2Paddr !=   oThatP2Paddr &&
          m_oThatP2Paddr != GetP2PaddrHub()   )
      EVERR->Module (__FUNCTION__"(%s,%i,%i)"
                    , m_oThatP2Paddr.c_str(), (int)pvLoginAck, iSize )
            ->Message("Attempt to swap P2PeerID's from [%s] to [%s]"
                    , (P2PaddrSTR)m_oThatP2Paddr
                    , (P2PaddrSTR)  oThatP2Paddr )
            ->Group("P2P")->Throw();

    if ( !oThatP2Paddr.IsNull() )
      m_oThatP2Paddr = oThatP2Paddr;

    // Implementation
    // NOTES: Logon acknowledgement is posted directly to the
    //        output queue.
    P2PeerMsg *pMsg = new P2PeerMsg ( GetP2PaddrHub().c_str(), m_oThatP2Paddr.c_str()
                                    , P2Pmsg_LoginAck
                                    , pvLoginAck, iSize );
    PostP2PeerMsg ( pMsg );

    // Tidy up, and
    SetState ( ConState_Login, 0 );
    return bResult;
}

//
//  Process login acknowledgement to complete P2PeerCon integration
//  with remote P2PeerHub
//  NOTES: Usually performed in the ON_P2PeerCon_LOGINACK() handler.
//       : Observes interface addressing style, refer SetIFaddrTransform()
//         for further details
//
//
//  Parameters:  const P2Paddr oThisP2Paddr
//               Remotely assigned or adopted identification address of
//               peer to which this P2PeerCon object is posted
//                 0.. Retain existing identification
//                 ?.. Adopt passed remote P2PeerHub address
//
//               const P2Paddr oThatP2Paddr
//               Remotely assigned or adopted identification address of
//               peer to which this P2PeerCon object is connected
//                 0.. Retain existing identification
//                 ?.. Adopt passed remote P2PeerHub address
//
void
P2PeerCon::OnLoginAck ( const P2Paddr& oThisP2Paddr
                      , const P2Paddr& oThatP2Paddr )
{
    // State confirmation
    // NOTES: Audits the development cycle and traps illogical states
    //        that can propogate subtle bugs.
    //      : Low frequency check more than worth the overhead
    if ( !CheckP2PmsgPumpState(CN_P2PeerCon,P2P_LoginAck) )
      EVERR->MODULE->AFP(oThisP2Paddr)->AFP(oThatP2Paddr)
           ->Message("Requires ON_P2PeerCon_LOGINACK handler state")
           ->Advice ("Bug (SNHappen)" )
           ->Throw  ( );

    // Observe selected interface mapping
    switch ( m_eP2PeerIDmap )
    {
      // None
      case P2PeerIDmap_NONE:
        break;

      // Static interface mapping
      case P2PeerIDmap_STATIC:
        OnLoginAck_Static ( oThisP2Paddr, oThatP2Paddr );
        return;

      // Static interface mapping
      case P2PeerIDmap_FRACTAL:
        OnLoginAck_Fractal ( oThisP2Paddr, oThatP2Paddr );
        return;

      // Unknown type
      default:
        EVERR->MODULE->AFP(oThisP2Paddr)->AFP(oThatP2Paddr)
             ->Message("Unknown interface mapping (%i)"
                      , m_eP2PeerIDmap )
             ->Advice ("Bug (SNHappen)")
             ->Throw();
    }

//if(strThisP2Paddr==~0)
//strThisP2Paddr=0;//FIX-ME default value should be 0

    // To be sure, to be sure
    if (     oThisP2Paddr.IsNull() &&
          GetP2PaddrHub().IsNull()    )
      EVERR->MODULE->AFP(oThisP2Paddr)->AFP(oThatP2Paddr)
           ->Message("Local P2PeerHub has null P2Paddr[%s]"
                    , GetP2PaddrHub().c_str() )
           ->Throw();

    // To be sure, to be sure
    if (   !oThisP2Paddr.IsNull()         &&
         !GetP2PaddrHub().IsNull()        &&
          GetP2PaddrHub() != oThisP2Paddr    )
      EVERR->MODULE->AFP(oThisP2Paddr)->AFP(oThatP2Paddr)
           ->Message("Attempt to swap P2Paddr's from [%s] to [%s]"
                    , GetP2PaddrHub().c_str()
                    , oThisP2Paddr.c_str() )
           ->Throw();

    if ( !oThisP2Paddr.IsNull() )
      m_pP2PeerTarget -> GetP2PeerHub() -> SetP2PaddrHub ( oThisP2Paddr );
    //m_oThisP2Paddr = oThisP2Paddr;

    // Tidy up, and
    SetState ( ConState_Login, 0 );
}

//
//  Process static interface login acknowledgement to complete
//  P2PeerCon address integration with remote P2PeerHub
//  NOTES: Usually performed in the ON_P2PeerCon_LOGINACK() handler
//       : Confirms IFaddrTrans_STATIC interface addressing style,
//         refer SetIFaddrTransform() for further details.  Swaps to such
//         style if existing style set to IFaddrTrans_NONE
//
//
//  Parameters:  const P2Paddr oThisP2Paddr1
//               This or the local P2Paddr.  Defines our P2PeerHub in
//               another P2Peer virtual network for which we have no
//               knowledge of structure.  Substituted for the source
//               address on out-going messages
//                 0.. Retain existing identification
//                 ?.. Adopt passed remote client identification
//
//               const P2Paddr oThatP2Paddr1
//               That or the remote P2Paddr.  Defines a P2PeerHub in
//               another P2Peer virtual network for which we have no
//               knowledge of structure.  Substituted for the
//               destination address on out-going messages
//                 0.. Retain existing identification
//                 ?.. Adopt passed remote client identification
//
void
P2PeerCon::OnLoginAck_Static ( const P2Paddr& oThisP2Paddr1
                             , const P2Paddr& oThatP2Paddr1 )
{
    // State confirmation
    // NOTES: Audits the development cycle and traps illogical states
    //        that can propogate subtle bugs.
    //      : Low frequency check more than worth the overhead
    if ( !CheckP2PmsgPumpState(CN_P2PeerCon,P2P_LoginAck) )
      EVERR->MODULE->AFP(oThisP2Paddr1)->AFP(oThatP2Paddr1)
           ->Message("Requires ON_P2PeerCon_LOGINACK handler state" )
           ->Advice ("Bug (SNHappen)" )
           ->Throw  ( );

    // Interface addressing style confirmation
    if ( m_eP2PeerIDmap != P2PeerIDmap_STATIC &&
         m_eP2PeerIDmap != P2PeerIDmap_NONE      )
      EVERR->MODULE->AFP(oThisP2Paddr1)->AFP(oThatP2Paddr1)
           ->Message("Incompatible interface address styles (%i vs %i)"
                    , m_eP2PeerIDmap, P2PeerIDmap_STATIC )
           ->Advice ("Bug (SNHappen)" )
           ->Throw  ( );

    // This P2Paddr
    // NOTES: The other virtual network must have assigned a valid
    //        non-null P2Paddr to this peer
    if (   oThisP2Paddr1.IsNull() &&
         m_oThisP2Paddr1.IsNull()    )
      EVERR->MODULE->AFP(oThisP2Paddr1)->AFP(oThatP2Paddr1)
           ->Message("Remotely assigned this P2Paddr[%s] is null"
                    , (P2PaddrSTR)m_oThisP2Paddr1 )
           ->Throw();

    // That P2Paddr
    // NOTES: The other virtual network must have assigned a valid
    //        non-null P2Paddr to that peer
    if (    oThatP2Paddr1.IsNull() &&
          m_oThatP2Paddr1.IsNull()     )
      EVERR->MODULE->AFP(oThisP2Paddr1)->AFP(oThatP2Paddr1)
           ->Message("Remotely assigned that P2Paddr[%s] is null"
                    , (P2PaddrSTR)m_oThatP2Paddr1 )
           ->Throw();

    // Persist
    // NOTES: Thereafter all P2PeerMsg's will have their source and
    //        destination P2Paddr's re-assigned upon send and receive
    if ( !oThisP2Paddr1.IsNull() )
      m_oThisP2Paddr1 = oThisP2Paddr1;
    if ( !oThatP2Paddr1.IsNull() )
      m_oThatP2Paddr1 = oThatP2Paddr1;
    m_eP2PeerIDmap = P2PeerIDmap_STATIC;

    // Default attributes
    SetState ( ConState_Login, 0 );
}

//
//  Process fractal interface login acknowledgement to complete
//  P2PeerCon address integration with remote P2PeerHub
//  NOTES: Usually performed in the ON_P2PeerCon_LOGINACK() handler
//       : Confirms IFaddrTrans_FRACTAL interface addressing style,
//         refer SetIFaddrTransform() for further details.  Swaps to such
//         style if existing style set to IFaddrTrans_NONE
//
//
//  Parameters:  const P2Paddr oThisP2Paddr1
//               This or the local P2Paddr.  Defines our P2PeerHub in
//               another P2Peer virtual network for which we have no
//               knowledge of structure.  Substituted for the source
//               address on out-going messages
//                 0.. Retain existing identification
//                 ?.. Adopt passed remote client identification
//
//               const P2Paddr oThatP2Paddr1
//               That or the remote P2Paddr.  Defines a P2PeerHub in
//               another P2Peer virtual network for which we have no
//               knowledge of structure.  Substituted for the
//               destination address on out-going messages
//                 0.. Retain existing identification
//                 ?.. Adopt passed remote client identification
//
void
P2PeerCon::OnLoginAck_Fractal ( const P2Paddr& oThisP2Paddr1
                              , const P2Paddr& oThatP2Paddr1 )
{
    // State confirmation
    // NOTES: Audits the development cycle and traps illogical states
    //        that can propogate subtle bugs.
    //      : Low frequency check more than worth the overhead
    if ( !CheckP2PmsgPumpState(CN_P2PeerCon,P2P_LoginAck) )
      EVERR->MODULE->AFP(oThisP2Paddr1)->AFP(oThatP2Paddr1)
           ->Message("Requires ON_P2PeerCon_LOGINACK handler state" )
           ->Advice ("Bug (SNHappen)" )
           ->Throw  ( );

    // Interface addressing style confirmation
    if ( m_eP2PeerIDmap != P2PeerIDmap_FRACTAL &&
         m_eP2PeerIDmap != P2PeerIDmap_NONE       )
      EVERR->MODULE->AFP(oThisP2Paddr1)->AFP(oThatP2Paddr1)
           ->Message("Incompatible interface address styles (%i vs %i)"
                    , m_eP2PeerIDmap, P2PeerIDmap_STATIC )
           ->Advice ("Bug (SNHappen)" )
           ->Throw  ( );

    // This P2Paddr
    // NOTES: The other virtual network must have assigned a valid
    //        non-null P2Paddr to this peer
    if (   oThisP2Paddr1.IsNull() &&
         m_oThisP2Paddr1.IsNull()     )
      EVERR->MODULE->AFP(oThisP2Paddr1)->AFP(oThatP2Paddr1)
           ->Message("Remotely assigned this P2Paddr[%s] is null"
                    , (P2PaddrSTR)m_oThisP2Paddr1 )
           ->Throw();

    // That P2Paddr
    // NOTES: The other virtual network must have assigned a valid
    //        non-null P2Paddr to that peer
    if (    oThatP2Paddr1.IsNull() &&
          m_oThatP2Paddr1.IsNull()     )
      EVERR->MODULE->AFP(oThisP2Paddr1)->AFP(oThatP2Paddr1)
           ->Message("Remotely assigned that P2Paddr[%s] is null"
                    , (P2PaddrSTR)m_oThatP2Paddr1 )
           ->Throw();

    // Persist
    // NOTES: Thereafter all P2PeerMsg's will have their source and
    //        destination P2Paddr's re-assigned upon send and receive
    if ( !oThisP2Paddr1.IsNull() )
      m_oThisP2Paddr1 = oThisP2Paddr1;
    if ( !oThatP2Paddr1.IsNull() )
      m_oThatP2Paddr1 = oThatP2Paddr1;
    m_eP2PeerIDmap = P2PeerIDmap_FRACTAL;

    // Default attributes
    SetState ( ConState_Login, 0 );
}

//
//  Restarts connection after nominated delay
//  NOTES: Operation is usually performed from within
//         P2PeerCon_CLOSE handlers
//
//
//  Parameters:  P2Pmsecs_t uiMSecDelay
//               Millisecond restart delay
//
//
//  Returns:     P2PeerTime_t
//               Restart time in milliseconds
//
P2Pmsecs_t
P2PeerCon::Restart ( P2Pmsecs_t uiMSecDelay )
{
    // State confirmation
    // NOTES: Audits the development cycle and traps illogical states
    //        that can propogate subtle bugs.
    //      : Low frequency check more than worth the overhead
    if ( !CheckP2PmsgPumpState(CN_P2PeerCon,P2P_Close) )
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , GetP2PaddrHub().c_str()
                    , m_oThatP2Paddr.c_str() )
           ->Message("Requires ON_P2PeerCon_CLOSE handler state" )
           ->Message("Bug (SNHappen)" )
           ->Throw  ( );

    // Mode confirmation
    // NOTES: Audits the development cycle and traps illogical states
    //        that can propogate subtle bugs.
    //      : Low frequency check more than worth the overhead
    if ( m_eP2PeerConMode != P2PeerCon_CLIENT  &&
         m_eP2PeerConMode != P2PeerCon_SERVICE     )
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , GetP2PaddrHub().c_str()
                    , m_oThatP2Paddr.c_str() )->AFP(uiMSecDelay)
           ->Message("Requires Connect or Service mode" )
           ->Advice ("Bug (SNHappen)" )
           ->Throw  ( );

    // Event state
    // NOTES: Previously latched P2Pevent's MUST have been cleared
    if ( m_pEvent )
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , (P2PaddrSTR)GetP2PaddrHub()
                    , (P2PaddrSTR)GetP2Paddress() )
           ->Message("Attempt to restart connection with uncleared event" )
           ->Advice ("OnClose() processing not performed" )
           ->Throw  ( );

    // Flagged destruction
    if ( PostDestroyState() )
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , (P2PaddrSTR)GetP2PaddrHub()
                    , (P2PaddrSTR)GetP2Paddress() )
           ->Message("Attempt to restart destroyed connection" )
           ->Advice ("Refer PostDestroyState() for further details" )
           ->Throw  ( );


    // Connection restart time
    // NOTES: Trigger processing cycle for the hub
    P2Pmsecs_t iRestartTime = _time64(0)*1000 + uiMSecDelay;
    CancelP2PmsgTimer ( m_uRestartTimerID );
    m_uRestartTimerID = SetPITimer ( uiMSecDelay );

    // To be sure, to be sure
    if ( m_uRestartTimerID <= 0 )
    {
      m_uRestartTimerID = 0;
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , GetP2PaddrHub().c_str()
                    , m_oThatP2Paddr.c_str() )
           ->Message("Failed to set restart timer" )
           ->Advice ("Bug (SNHappen)" )
           ->Throw  ( );
    }

    // Tidy up, and
    return iRestartTime;
}

//
//  Initiates close connection processing for object.
//  NOTES: May be referenced from On_P2PeerCon_STARTUP, and
//         ACCEPT handlers.
//
void
P2PeerCon::Close  ( )
{
    // State
    SetState ( 0, ON_ConClose );

    // Implementation
    PostP2Pmsg ( m_oThatP2Paddr, CN_P2PeerCon, P2P_Close
               , this, (P2PeerMsg *)0, m_hCPortP2PumpID  );
}

//
//  Performs default ON_P2PeerCon_CLOSE() handler processing
//  NOTES: Closed connections may be Restart()'ed
//       : Usually performed from ON_P2PeerCon_CLOSE() handlers
//
//
//  Returns:     conRESULT
//               Connection handler result code
//
conRESULT
P2PeerCon::OnClose ( )
{
    // Locals
    conRESULT conResult = conHANDLED;

    // State confirmation
    // NOTES: Audits the development cycle and traps illogical states
    //        that can propogate subtle bugs.
    //      : Low frequency check more than worth the overhead
    SetState ( 0, ON_ConClose );
    if ( !CheckP2PmsgPumpState(CN_P2PeerCon,P2P_Close) )
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , GetP2PaddrHub().c_str()
                    , m_oThatP2Paddr.c_str() )
           ->Message("Requires ON_P2PeerCon_CLOSE handler state" )
           ->Advice ("Bug (SNHappen)" )
           ->Throw  ( );

    // Selected timers
    CancelP2PmsgTimer ( m_uLoginTimerID );

    // Display precipitating event
    // NOTES: Skip event display when remote connection drops out
    //      : Always discard event.  Such events MUST be discarded
    //        as part of the ON_P2PeerCon_CLOSE() handler processing
    if ( m_pEvent )
    {
      bool bDisplay = !HasDroppedOut ( m_pEvent->GetHRESULT() );
      m_pEvent = m_pEvent -> Cancel ( bDisplay );
    }
 
    // Reflect all internally queued messages as undeliverable
    // NOTES: Handle any buffered P2PeerMsg's first.
    while ( m_pP2PeerMsgSend              ||
            m_oCListMsgQue.GetCount() > 0    )
    {
      // Isolate undeliverable P2PeerMsg
      P2PeerMsgSP spP2PeerMsg;
      if ( m_pP2PeerMsgSend )
      {
        spP2PeerMsg = m_pP2PeerMsgSend;
                      m_pP2PeerMsgSend = 0;
      }
      else
        spP2PeerMsg = GetP2PeerMsg();

ASSERT(!spP2PeerMsg.IsEmpty());
ASSERT(AfxCheckMemory());
Sleep(100);
ASSERT(AfxCheckMemory());
spP2PeerMsg->AssertValid();
      // Implementation
      // NOTES: Deliver P2PeerMsg exception back to source
      P2Pevent *pEVT =
      EVTRC->Module (__FUNCTION__"(%s)"
                    , (P2PaddrSTR)m_oThatP2Paddr )
           ->Message( spP2PeerMsg->GetVisualRTSummary() )
           ->Message("Undeliverable message\n"
                     "ADVICE\t: Connection closed" )
           ->HResult(P2Pevent_UNDELIVERABLE)
           ->Group("P2P");

    /*PostP2Pmsg ( GetP2Paddr(), CN_P2PeerMsg, 0
                 ,(P2PeerCon *)0
                 , spP2PeerMsg->ExceptionFactory(pEVT)  );FIX-ME Activate*/
      spP2PeerMsg = 0;                 // Control garbage collection
      pEVT -> Cancel ( false );
    }

    // Tidy up and
    if ( PostDestroyState() )
      conResult = conDROP;
    return conResult;
}

//
//  Initiates shutdown processing for object.
//  NOTES: May be referenced from On_P2PeerCon_CLOSE,
//         ????????? and ???????? handlers.
//
void
P2PeerCon::Shutdown  ( )
{
    // State
    SetState ( 0, ON_ConShutdown );

    // Implementation
    PostP2Pmsg ( m_oThatP2Paddr, CN_P2PeerCon, P2P_Shutdown
               , this, (P2PeerMsg *)0, m_hCPortP2PumpID  );
}

//
//  Performs default ON_P2PeerCon_SHUTDOWN() handler processing
//  NOTES: Closed connections may be Restart()'ed
//       : Usually performed from ON_P2PeerCon_CLOSE() handlers
//
//
//  Returns:     conRESULT
//               Handler result
//
BOOL
P2PeerCon::OnShutdown ( )
{
    // State confirmation
    // NOTES: Audits the development cycle and traps illogical states
    //        that can propogate subtle bugs.
    //      : Low frequency check more than worth the overhead
    SetState ( 0, ON_ConShutdown );
    if ( !CheckP2PmsgPumpState(CN_P2PeerCon,P2P_Shutdown) )
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , GetP2PaddrHub().c_str()
                    , m_oThatP2Paddr.c_str() )
           ->Message("Requires ON_P2PeerCon_SHUTDOWN handler state\n"
                     "ADVICE\t: Bug (SNHappen)" )
           ->Throw  ( );

    // Selected timers
    CancelP2PmsgTimer ( m_uLoginTimerID );

    // Display precipitating event
    // NOTES: Skip event display when remote connection drops out
    //      : Always discard event.  Such events MUST be discarded
    //        as part of the ON_P2PeerCon_CLOSE() handler processing
    if ( m_pEvent )
    {
      bool bDisplay = !HasDroppedOut ( m_pEvent->GetHRESULT() );
      m_pEvent = m_pEvent -> Cancel ( bDisplay );
    }
 
    // Reflect all internally queued messages as undeliverable
    // NOTES: Handle any buffered P2PeerMsg's first.
    while ( m_pP2PeerMsgSend              ||
            m_oCListMsgQue.GetCount() > 0    )
    {
      // Isolate undeliverable P2PeerMsg
      P2PeerMsgSP spP2PeerMsg;
      if ( m_pP2PeerMsgSend )
      {
        spP2PeerMsg = m_pP2PeerMsgSend;
                      m_pP2PeerMsgSend = 0;
      }
      else
        spP2PeerMsg = GetP2PeerMsg();

ASSERT(!spP2PeerMsg.IsEmpty());
      // Implementation
      // NOTES: Deliver P2PeerMsg exception back to source
      P2Pevent *pEVT =
      EVTRC->Module (__FUNCTION__"(%s)"
                    , (P2PaddrSTR)m_oThatP2Paddr )
           ->Message( spP2PeerMsg->GetVisualRTSummary() )
           ->Message("Undeliverable message\n"
                     "ADVICE\t: Connection closed" )
           ->HResult(P2Pevent_UNDELIVERABLE)
           ->Group("P2P");

    /*PostP2Pmsg ( GetP2Paddr(), CN_P2PeerMsg, 0
                 ,(P2PeerCon *)0
                 , spP2PeerMsg->ExceptionFactory(pEVT)  );FIX-ME Activate*/
      spP2PeerMsg = 0;                 // Control garbage collection
      pEVT -> Cancel ( false );
    }

    // Tidy up and
    return conDROP;
}

///////////////////////////////////////////////////////////////////////
//  Utilities

//
//  Performs interface address mapping
//  NOTES: Override this method to provide 3rd party mapping
//         alternatives.  Refer SetIFaddrTransform() for further details
//       : Should mapping be considered necessary.  Then by
//         convention it is performed by the peer actively pursuing
//         the connection.  The peer accepting the connection remains
//         passive
//
//
//  Parameters:  bool bSoR
//               Receive (true=1nput) or send (false=0utput) mapping flag
//             
//               P2PeerMsg *pMsg
//               Message to be mapped
void
P2PeerCon::PerformIFaddrTransform ( BOOL bSoR, P2PeerMsg *pMsg )
{
    // Optimise
    if ( m_eP2PeerIDmap == P2PeerIDmap_NONE )
      return;

    // Introduce locals
    //P2PeerMsgHdr *pHdr = (P2PeerMsgHdr *)pMsg->Message();

    // Friendly interface mapping
    // NOTES: Facilitates friendly inter-P2Peer network address mapping
    //        whereby either side indirectly exposes internal 
    if ( m_eP2PeerIDmap == P2PeerIDmap_STATIC )
    {
      // P2PeerMsg receive mapping
      if ( bSoR )
      {
        //pHdr -> nWsamapID = pHdr -> nSourceID;
        //pHdr -> nSourceID = m_oThatP2Paddr;
        //pHdr -> strDestin = m_oThisP2Paddr;
        pMsg -> SetSource ( m_oThatP2Paddr );
        pMsg -> SetDestin ( GetP2PaddrHub() );
      }

      // P2PeerMsg send mapping
      else
      {
        //pHdr -> nSourceID = m_nThisP2PeerID1;
        //pHdr -> strDestin = m_nThatP2PeerID1;
        //if ( pHdr->nWsamapID )
        //  pHdr -> strDestin = pHdr -> nWsamapID;
        pMsg -> SetSource ( m_oThisP2Paddr1 );
        pMsg -> SetDestin ( m_oThatP2Paddr1 );
        if ( strlen(pMsg->GetConmap()) > 0 )
          pMsg -> SetDestin ( pMsg->GetConmap() );
      }
    }

    // Fractal interface mapping
    // NOTES: Push addressing and substitute on the way out, simply
    //        pop on the way in
    //      : Should security be an issue you would never use this style
    else if ( m_eP2PeerIDmap == P2PeerIDmap_FRACTAL )
    {
      // P2PeerMsg receive mapping
      if ( bSoR )
      {
        if ( pMsg->r_Source().IsStacked() )
          pMsg -> r_Source().r_Stck().Pop();
        else
          pMsg -> SetSource(m_oThatP2Paddr);
        if ( pMsg->r_Destin().IsStacked() )
          pMsg -> r_Destin().r_Stck().Pop();
        else
          pMsg -> SetDestin(GetP2PaddrHub().c_str());
      }
      // P2PeerMsg send mapping
      else
      {
pMsg->Print(stdout);
        LPCTSTR lpszThisP2Paddr = m_oThisP2Paddr1.c_str();
        pMsg->r_Source().r_Stck().Push().r_data().c_memcpy(lpszThisP2Paddr,0);
pMsg->Print(stdout);
        LPCTSTR lpszThatP2Paddr = m_oThatP2Paddr1.c_str();
        pMsg->r_Destin().r_Stck().Push().r_data().c_memcpy(lpszThatP2Paddr,0);
pMsg->Print(stdout);
      }
    }

    // Wrapped messages
    // NOTES: Recursive implementation
    if ( pMsg->IsWrapped() )
      PerformIFaddrTransform ( bSoR, &(*pMsg)[1] );
}

///////////////////////////////////////////////////////////////////////
//  P2PeerCon_MAP routing
//  NOTES: Used for P2PeerCon routing and handler assignment

/*bool
P2PeerCon::MAP_MatchName ( const P2Pmsg_t nMapWildcard )
{
    // Translation
    const char *pszMapWildcard = 0;
    if ( nMapWildcard == ~0 )
      pszMapWildcard = "*";
    else
      pszMapWildcard = (*g_fptrEncodeP2PeerID) ( nMapWildcard );

    // Delegate
    return MAP_MatchName ( pszMapWildcard );
}*/

//
//  Description: P2PeerCon_MAP name matching utility
//               NOTES: Internal P2Peer path is matched against the
//                      passed P2PeerCon_MAP wildcard
//                    : Example 1 (Backwards connection)
//                        Hub1/Hub2/whatever, matches wildcards
//                           */Hub2/whatever, and
//                                */whatever, and
//
//
//  Parameters:  P2PaddrSTR pszMapWildcard
//               P2PeerHub name wildcard
//
//  Returns:     bool
//                 true... Connection matches wildcard
//                 false.. No match
//
/*bool
P2PeerCon::MAP_P2Paddr ( P2PaddrSTR pszMapWildcard )
{
    // Preparation
    bool  star   = false;
    const char *pszHub = m_oThatP2Paddr.c_str();

    // Implmentation
Top:
    const char *p, *s;
    for ( s = pszHub, p = pszMapWildcard; *s; ++s, ++p )
    {
      switch (*p) {
         case '?':
            if (*s == '.') goto starCheck;
            break;
         case '*':
            star = TRUE;
            pszHub = s, pszMapWildcard = p;
            if (!*++pszMapWildcard) return TRUE;
            goto Top;
         default:
            //if (mapCaseTable[*s] != mapCaseTable[*p])
            if (*s != *p )
               goto starCheck;
            break;
      }
   }
   if (*p == '*') ++p;
   return (!*p);

starCheck:
   if (!star) return FALSE;
   pszHub++;
   goto Top;
}*/

//
//  Description: L4Caddr matching utility
//               NOTES:
//
//
//  Parameters:  P2PaddrSTR strP2PaddrThat
//               Remote connection address to be mapped against
//               contained L4Caddr
//
//  Returns:     bool
//                 true... Matched
//                 false.. No match
//
/*bool
P2PeerCon::MAP_L4Caddr ( P2PaddrSTR strP2PaddrThat )
{
    // Introduce the locals
    char        *pFormat   = (char *)m_oThatP2Paddr.c_str();
    P2Parser     oL4Caddr( (char *)strP2PaddrThat );
    P2Parser    *m_pClpEnv = &oL4Caddr;
    va_list      ap;
    char        *pCompleted = m_pClpEnv -> m_pCompleted;
    int          nMatched   = 0;

    // Loop until passed format exhausted
    while ( *pFormat )
    {
LPCTSTR lpszCommand=m_pClpEnv->m_pCommand;//DELETE-ME
LPCTSTR lpszCompleted=m_pClpEnv->m_pCompleted;//DELETE-ME
      // Alternative sequences field
      if ( *pFormat == '<' )
      {
        pFormat++;                   // Consume '<' character
        m_pClpEnv = m_pClpEnv -> Push ( m_pClpEnv -> m_pCommand
                                      , 0
                                      , m_pClpEnv -> m_pCommand );

        m_pClpEnv -> m_eFCF    = '<';
        m_pClpEnv -> m_eSeqNum =  0;

        m_pClpEnv = m_pClpEnv -> Push ( 0, 0, 0 );
        continue;
      }

      // Numeric range field
      if ( *pFormat == '#' )
      {
        pFormat++;                     // Consume '#' character
        int iBegin = strtol ( pFormat, &pFormat, 10 );
        if ( *pFormat != '-' )
          EVERR->MODULE
               ->Message("M4Caddr '#n-n' missing '-' delimiter" )
               ->Advice ("L4Caddr=[%s]", m_oThatP2Paddr.c_str() )
               ->Throw();
        pFormat++;                     // Consume '-' character
        int iEnd   = strtol ( pFormat, &pFormat, 10 );
        int iNum;
        if ( !m_pClpEnv->GetINT(iNum)    &&
             !m_pClpEnv -> m_bOptional   &&
              m_pClpEnv -> m_eFCF != '<'    )
          return false;                // Matching failed
        if ( iNum < iBegin ||
             iNum > iEnd      )
        {
          if ( !m_pClpEnv -> m_bOptional   &&
                m_pClpEnv -> m_eFCF != '<'    )
            return false;
        }
        continue;
      }

      // Manage optional logic
      // NOTES: Any sequence contained between '[...]' characters
      if ( *pFormat == '[' )
      {
        pFormat++;                       // Consume '[' character
        m_pClpEnv = m_pClpEnv -> Push ( 0
                                      , 0
                                      , m_pClpEnv -> m_pCommand );
        m_pClpEnv -> m_bOptional = true; // Flag optional logic
        continue;
      }

      if ( *pFormat == ']' )
      {
        pFormat++;                       // Consume ']' character
        if ( !m_pClpEnv -> m_bOptional )
          EVERR->MODULE
               ->Message("M4Caddr ']' mismatch" )
               ->Throw();
        m_pClpEnv = m_pClpEnv -> Pop ( 0
                                     , 0
                                     , m_pClpEnv -> m_pCommand );
        continue;
      }

      // Tokens
      // NOTES: Any field bounded by the delimiters {...|...|...}
      if ( *pFormat == ',' ||
           *pFormat == '>'    )
      {
        if ( m_pClpEnv -> m_eFCF != '<' )
          EVERR->MODULE
               ->Message("Mismatching { , , } delimiters")
               ->Advice ("L4Caddr=[%s]", m_oThatP2Paddr.c_str() )
               ->Throw();

        // Matching field flagged by skip mode not set
        if ( !m_pClpEnv -> m_bSkip )
        {
lpszCommand=m_pClpEnv->m_pCommand;//DELETE-ME
lpszCompleted=m_pClpEnv->m_pCompleted;//DELETE-ME
          m_pClpEnv = m_pClpEnv -> Pop (  0
                                       , m_pClpEnv -> m_pCommand
                                       , m_pClpEnv -> m_pCheckpoint );
lpszCommand=m_pClpEnv->m_pCommand;//DELETE-ME
lpszCompleted=m_pClpEnv->m_pCompleted;//DELETE-ME

          if ( m_pClpEnv -> m_nEnumItem >= 0 )
            EVERR->MODULE
                 ->Message("Command sequence (%s) is not unique"
                          , m_pClpEnv -> m_pCommand )
                 ->Group("CLP")->Throw();

          m_pClpEnv -> m_nEnumItem = m_pClpEnv -> m_eSeqNum;
          nMatched++;
        }

        // Non-matching field flagged by skip mode being set
        else
          m_pClpEnv = m_pClpEnv -> Pop ( 0, 0, 0 );

        // End of token, start of new token
        // NOTES: Move command pointer back to checkpoint position
        if ( *pFormat == ',' )
        {
          pFormat++;                   // Consume '|' character
          m_pClpEnv -> m_eSeqNum++;    // This sequence number
          m_pClpEnv = m_pClpEnv -> Push ( 0
                                        , 0
                                        , m_pClpEnv -> m_pCheckpoint );
          continue;
        }

        // End of token sequence
        // NOTES: Confirm one of the enumerates matched
        if ( *pFormat == '>' )
        {
          pFormat++;                   // Consume '}' character
          if (  m_pClpEnv -> m_nEnumItem < 0 &&
               !m_pClpEnv -> m_bOptional        )
            return false;

          m_pClpEnv = m_pClpEnv -> Pop ( 0
                                       , 0
                                       , m_pClpEnv -> m_pCompleted );
lpszCommand=m_pClpEnv->m_pCommand;//DELETE-ME
lpszCompleted=m_pClpEnv->m_pCompleted;//DELETE-ME
          continue;
        }
      }

      // Pattern matching is the default
      if ( *pFormat == '\\' )
        pFormat++;

      if ( !m_pClpEnv -> m_bSkip )     // Not if skip mode is on
      {
        if ( !isalnum(*pFormat)       &&
                      *pFormat != '.'    )
          EVERR->MODULE
               ->Message("Invalid L4Caddr character[%c]"
                        , *pFormat )
               ->Advice ("L4Caddr=[%s]", m_oThatP2Paddr.c_str() )
               ->Throw();

        if ( toupper( (int)*pFormat )
                         == toupper ( (int)*(m_pClpEnv->m_pCommand) ) )
        {
          pFormat++;                   // Consume character
          m_pClpEnv -> m_pCommand++;
          continue;
        }

        if ( m_pClpEnv -> m_bOptional        ||
             m_pClpEnv -> m_eFCF      == '<'    )
        {
          m_pClpEnv -> m_bSkip = 1;    // Activate skip flag
          pFormat++;                   // Consume character
          continue;
        }

        // Matching failed
        return false;
      }
      pFormat++;                       // Increment format position
    }

    // Tidy up, and
    if ( m_pClpEnv -> m_nLevel != 0 )
      EVERR->MODULE
           ->Message("Parsing level (%i) did not return to zero"
                    , m_pClpEnv -> m_nLevel )
           ->Throw();
    return true;
}*/

///////////////////////////////////////////////////////////////////////
//  P2PeerCon_MAP routing
//  NOTES: Used for P2PeerCon routing and handler assignment


//
//  Description: 
//
//
//  Parameters:  const char *pszMsgWildcard
//               Message wildcard
//
//  Returns:     bool
//                 true... Message matches wildcard
//                 false.. No match
//
/*bool
P2PeerCon::Map_MatchP2PeerID ( P2PeerID_ nMapID, P2PeerID_ nSourceID )
{
    // Mask matching
    if ( (nMapID&M4Cbit) == M4Cbit )
    {
      nSourceID |= M4Cbit;
      if ( (nMapID | nSourceID) == nMapID    &&
           (nMapID & nSourceID) == nSourceID    )
        return true;
    }

    // Address matching
    if ( (nMapID&M4Cbit) != M4Cbit )
    {
      if ( nMapID == nSourceID )
        return true;
    }

    // No Match
    return false;
}*/

///////////////////////////////////////////////////////////////////////
//  Property management

//
//  Exposes P2Paddr for this connection
//  NOTES: By convention the P2Paddr of P2PeerCon objects is the
//         P2Paddr of the P2PeerHub for which the connection is being
//         managed
//
//
//  Returns:     P2Paddr&
//               Identification assigned to this P2PeerCon object.
//               NOTES: May be empty
//
const P2Paddr&
P2PeerCon::GetP2Paddress ( )
{
    // Simply
    return m_oThatP2Paddr;
}

const P2Padomain&
P2PeerCon::GetP2Padomain ( ) const
{
    return m_oP2Padomain;
}

//
//  Sets the P2Paddr of this P2PeerCon object
//  NOTES: Usually the P2Paddr of a P2PeerHub is assigned at creation
//         time.  However, under some circumstances such as negotiating
//         a console connection P2Paddr need to be set dynamically by
//         the server.
//
//
//  Parameters:  P2Paddr nThisP2PaddrSTR
//               New P2PeerHub identification code.
//               NOTES: The passed P2PaddrSTR must maintain the child
//                      relationship with P2PeerHub parent and
//                      parent relationship with any P2PeerHub
//                      children
//
//  Returns:     bool
//               Success summary
//                 true... Successfully re-addressed
//                 false.. Operation failed. Refer GetLastEvent()
//                         for further details
//
BOOL
P2PeerCon::SetP2Paddr ( P2PaddrSTR oThisP2PaddrSTR )
{
    // Simply
    // NOTES: Listening objects have equivalent m_oThisP2Paddr and
    //        m_oThatP2Paddr's
    if ( !GetP2PaddrHub().IsNull()          &&
          GetP2PaddrHub() == m_oThatP2Paddr    )
      m_oThatP2Paddr = oThisP2PaddrSTR;
    m_pP2PeerTarget -> GetP2PeerHub() -> SetP2PaddrHub ( oThisP2PaddrSTR );

    // Tidy up and
    return TRUE;
}

const P2Paddr
P2PeerCon::GetP2PaddrHub ( ) const
{
    // Simply
    if ( m_nP2PconID )
      return P2Paddr ( GetP2PmsgHubAddr(this) );
    return P2Paddr ( _T("") );
}

//const P2Paddr&
//P2PeerCon::GetThatP2Paddr ( ) const
//{
//    // Simply
//    return m_oThatP2Paddr;
//}

void
P2PeerCon::SetIFaddrTransform ( P2PeerIDmap_e eIFaddrTrans )
{
    // Simply
    m_eP2PeerIDmap = eIFaddrTrans;
}

void
P2PeerCon::SetP2Peerio  ( P2Peerio *pP2Peerio )
{
    // Simply
    delete m_pP2Peerio;
           m_pP2Peerio = 0;
           m_pP2Peerio = pP2Peerio -> Register ( this );
}

P2Peerio*
P2PeerCon::GetP2Peerio ( )
{
    // Simply
    return m_pP2Peerio;
}

DWORD
P2PeerCon::SetState ( DWORD dwAdd, DWORD dwRemove )
{
    // Apply
    m_dwState &= ~dwRemove;
    m_dwState |=  dwAdd;

    // Tidy up, and
    return m_dwState;
}

DWORD
P2PeerCon::GetState ( DWORD dwMask )
{
    // Simply
    return m_dwState & dwMask;
}

bool
P2PeerCon::HasState ( DWORD dwStateMask )
{
    // Simply
    return ( (m_dwState & dwStateMask)==dwStateMask )
           ? true
           : false;
}

//
//  Description: Exposes P2PeerCon object mode
//
//
//  Returns:     P2PeerConMode_e
//               Object mode
P2PeerConMode_e
P2PeerCon::GetMode ( )
{
    // Simply
    return m_eP2PeerConMode;
}

DWORD
P2PeerCon::GetUDState ( )
{
   ASSERT(0);                          // Expected to be specialised
   return 0;
}

P2Pevent*
P2PeerCon::SetP2Pevent ( P2PeventSP& spP2Pevent )
{
   if ( m_pEvent )
     m_pEvent -> Cancel ( false );
   m_pEvent = spP2Pevent.Dereference ( );
   return m_pEvent;
}
P2Pevent*
P2PeerCon::GetP2Pevent ( )
{
   return m_pEvent;
}

//
//  Description: Fetches pointer to visual header report
//               NOTES: Header report demand encoded
//                      P2PeerCon[this-that]
//
//
//  Returns:     LPCTSTR
//               Pointer to visually encoded header
//
//LPCTSTR
//P2PeerCon::GetVisualHdr_ ( )
//{
//    // Simply encode header
//    sprintf ( m_szVisualHdr
//            ,"P2PeerCon[%s-%s]n"
//            , m_oThisP2Paddr.c_str()
//            , m_oThatP2Paddr.c_str() );
//
//    // Tidy up and
//    return m_szVisualHdr;
//}

//
//  Summarises connection failure
//  NOTES: Expectation is that the derived class will provide an
//         implementation specialised for physical layer
//
//  Parameters:  HRESULT hr
//               Precipitating error as returned from WriteFile(),
//               ReadFile()
//
//  Returns:     bool
//               Connection failure summary
//                 true... Remote failure
//                 false.. Local failure
bool
P2PeerCon::HasDroppedOut ( HRESULT /*hr*/ )
{
    // Default action
    return false;
}

///////////////////////////////////////////////////////////////////////
//  Troubleshooting

void
P2PeerCon::AssertValid ( ) const
{
    // Firstly delegate
    P2PeerConPlc::AssertValid ( );

    // IOCP completion key
    // NOTES: Very problematic should the value be corrupted
    ASSERT ( m_dwCompletionKey == (DWORD)this );

    // TODO: Additional validation
}

//
//  Generates Visual Runtime Summary for P2PeerCon instance
//  FORMAT: [P2PeerCon Hub=Name, Con=Name, Domain=Domain]
//        : Such brief summaries are used to pass brief P2PeerCon state
//          information to P2Pevent's
//
//
//  Returns:     LPCTSTR
//               Pointer to encoded P2PeerCon summary
//               NOTES: (Re-)Encoded upon each reference
//
LPCTSTR
P2PeerCon::GetVisualRTSummary ( )
{
    // Container
    if ( !m_pstrVisualSummary )
      m_pstrVisualSummary = new CString ( );

    // Simply encode header
    m_pstrVisualSummary
      -> Format ( "[P2PeerCon Hub=%s, Con=%s, Domain=%s]"
                , GetP2PaddrHub().c_str()
                , GetP2Paddress().c_str()
                , GetP2Padomain().c_str() );

    // Tidy up and
    return *m_pstrVisualSummary;
}

//
//  Generates state snapshot for this P2PeerCon instance
//  NOTES: Such summaries are used to inject P2PeerCon state information
//         P2PeerMsg's and P2Pevent's etc
//
//  Parameters:  LPCTSTR lpszVar
//               Name assigned to the generated P3PmsgNode
//
//  Returns:     P3PmsgNode
//               Snapshot instance
//
P3PmsgNode
P2PeerCon::SetP2PeventFParams ( LPCTSTR lpszVar )
{
    // Create a placeholder for receipt of P2PeerCon details
    // NOTES: This will be passed by value back up the stack
    P3PmsgNode oNodeVar ( P3PmsgField(lpszVar,P3PmsgData(m_nP2PconID)) );

    // Append our state to node
    oNodeVar += P3PmsgField ( "P2PaddrHub", DataBSTR16(GetP2PaddrHub().c_str()) );
    oNodeVar += P3PmsgField ( "P2Paddress", DataBSTR16(GetP2PaddrHub().c_str()) );
    oNodeVar += P3PmsgField ( "P2Padomain", DataBSTR16(GetP2Padomain().c_str()) );
    oNodeVar += P3PmsgField ( "RestartTimerID", P3PmsgData(m_uRestartTimerID) );
    oNodeVar += P3PmsgField ( "LoginTimerID",   P3PmsgData(m_uLoginTimerID) );

    // Tidy up and
    return oNodeVar;
}
P3PmsgNode
P2PeerCon::Serialise ( LPCTSTR lpszVar )
{
    bool bDsc = true;

    // Create a placeholder for receipt of P2PeerCon details
    // NOTES: This will be passed by value back up the stack
    if ( lpszVar == 0 )
      lpszVar = _T("{P2PeerCon}");
    P3PmsgNode oNodeVar ( P3PmsgField(lpszVar,P3PmsgData(m_nP2PconID)) );

    // Append our state to node
    P3PmsgField_SERIALISE ( oNodeVar, _T("P2Paddress"), GetP2Paddress().c_str(), bDsc
                          , _T("Allocated connection address") );
    P3PmsgField_SERIALISE ( oNodeVar, _T("P2Padomain"), GetP2Padomain().c_str(), bDsc
                          , _T("Assigned connection address domain") );
    P3PmsgField_SERIALISE ( oNodeVar, _T("ConMode"), (int)m_eP2PeerConMode, bDsc
                          , _T("Connection mode") );
    if ( m_eP2PeerConMode != P2PeerCon_Accept )
      P3PmsgField_SERIALISE ( oNodeVar, _T("LoginTimerID"), m_uLoginTimerID, bDsc
                            , _T("Restart connection timer identification") );

    // Tidy up and
    return oNodeVar;
}

///////////////////////////////////////////////////////////////////////
//  P2PeerConPlc
//  NOTES: Place marker for lists of P2PeerCon objects
//       : Optimised for and targeted to self extracting lists
//         of P2PeerCon objects
//       : Manages private interactions between P2Peer, P2PeerCon
//         objects and the P2Pmsg pump
IMPLEMENT_DYNCREATE(P2PeerConPlc,CObject)
P2PeerConPlc::P2PeerConPlc ( )
{
    // Firstly
    m_cRef      = 0;
    m_bDestroy  = false;
    m_nP2PconID = 0;
    m_pP2Props  = 0;
}

P2PeerConPlc::~P2PeerConPlc ( )
{
    ASSERT(m_cRef==0);
    delete m_pP2Props;
}

UINT
P2PeerConPlc::AddRef ( )
{
    return ++m_cRef;
}

UINT
P2PeerConPlc::Release ( )
{
    // Implementation
    int cRef   = --m_cRef;
ASSERT(cRef>=0);
    if ( m_cRef <= 0 && m_nP2PconID == 0 )
      Destroy ( );
    if ( m_cRef <= 0 && m_bDestroy )
    {
      DropP2PmsgCon ( (P2PeerCon *)this );
      delete this;
    }
    return cRef;
}

UINT
P2PeerConPlc::Destroy ( )
{
    // Implementation
    m_bDestroy |= true;
    return m_cRef;
}

bool
P2PeerConPlc::PostDestroyState ( )
{
    // Implementation
    return m_bDestroy || m_cRef <= 0;
}

void
P2PeerConPlc::AssertValid ( ) const
{
    // Validation
    ASSERT(m_cRef>=0);
}

//  Properties
P3PmsgNode&
P2PeerConPlc::GetP2Props ( )
{
    if ( m_pP2Props == 0 )
      m_pP2Props = new P3PmsgNode ( );
    return *m_pP2Props;
}
P2PconID
P2PeerConPlc::GetP2PconID ( ) const
{
    ASSERT(m_nP2PconID);
    return m_nP2PconID;
}

///////////////////////////////////////////////////////////////////////
//  Safe P2PeerCon container
//  NOTES: Intended for use form P2PeerMsg handlers in conjunction
//         with P2PeerHub::ConQuery()
//
SafeP2PeerCon::SafeP2PeerCon ( )
{   RenderThisSafe(); }
SafeP2PeerCon::SafeP2PeerCon ( P2PeerCon *pCon )
{   RenderThisSafe(); pCon->AddRef(); m_pP2PeerCon = pCon; }
SafeP2PeerCon::~SafeP2PeerCon ( )
{   if ( m_pP2PeerCon ) m_pP2PeerCon -> Release ( ); }
void
SafeP2PeerCon::RenderThisSafe ( )
{   m_pP2PeerCon = 0; }
SafeP2PeerCon&
SafeP2PeerCon::operator = ( P2PeerCon *pCon )
{   if ( pCon ) pCon->AddRef();
    if ( m_pP2PeerCon ) m_pP2PeerCon->Release();
    m_pP2PeerCon = pCon;
    return *this; }
P2PeerCon*
SafeP2PeerCon::operator -> ( ) const
{   return m_pP2PeerCon; }
SafeP2PeerCon::operator P2PeerCon* ( )
{   return m_pP2PeerCon; }
SafeP2PeerCon::operator bool ( )
{   return m_pP2PeerCon ? true : false; }
