//  Beta release only.
//
//  Copyright(c) Ivyware Pty Ltd  2002-2011
//               MELBOURNE, VICTORIA, AUSTRALIA, 3130
//
//  Provided no fee is charged (either by the distributer or user)
//  permission to use, copy, modify, and distribute this software and
//  its documentation for any purpose and without fee is hereby granted,
//  provided that the above copyright notice appear in all copies and
//  that both that copyright notice and this permission notice appear
//  in supporting documentation.
//
//  No waranty or suitablity for purpose is implied.
//
//
//  P2Peerio base class implementation
//  NOTES: Manages P2PeerMsg image exchanges
//

#include "StdAfx.h"
#include "P2Peerio.h"
#include "P2PeerCon.h"
#include "P2Pwin32.h"

///////////////////////////////////////////////////////////////////////
//  Constructors and destructor

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

P2Peerio::~P2Peerio ( )
{
    // Cancellation of PITimer's
    if ( m_nPITimerIDack )
      CancelP2PmsgTimer ( m_nPITimerIDack );

    // Garbage collection
    if ( m_pCon           &&
         m_pOVERLAPPEDack    )
      m_pCon -> DropOVERLAPPED ( m_pOVERLAPPEDack );
}

void
P2Peerio::RenderThisSafe()
{
    // Attributes
    m_pCon           = 0;
    m_bIFTraceEoD    = false;
    m_bAckEoD        = false;
    m_dwIFmask       =~(DWORD)0;
    m_nPITimerIDack  = 0;
    m_dwMaxSendSize  = 2048;
    m_dwMaxRecvSize  = 2048;

    m_pOVERLAPPEDack = 0;
}

P2Peerio*
P2Peerio::Clone ( )
{   
    P2Peerio *pP2Peerio = new P2Peerio();
              pP2Peerio -> SetIFmask ( GetIFmask() );
              pP2Peerio -> m_dwMaxRecvSize = m_dwMaxRecvSize;
              pP2Peerio -> m_dwMaxSendSize = m_dwMaxSendSize;
    return    pP2Peerio;
}

P2Peerio*
P2Peerio::Register ( P2PeerCon *pCon )
{   
    m_pCon = pCon;
    return this;
}

//
//  Processes I/O completion port packets mapped to an instance of this
//  object.
//  NOTES: Such packets are retieved via the Win32
//         GetQueuedCompletionStatus() module.
//
//
//  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.
//
//  Returns:    bool
//              Processing summary flag
//                true... Packet processed
//                false.. Not handled
bool
P2Peerio::On_QueuedCompletionStatus ( DWORD dwError
                                    , DWORD dwBytes
                                    , OVERLAPPEDcon *pOVERLAPPEDcon )
{
    UNREFERENCED_PARAMETER(dwError);
    UNREFERENCED_PARAMETER(dwBytes);

    // P2Psignal_ACK
    // NOTES: Simply release OVERLAPPEDcon whilst infrastructure
    //        manages life cycle
    if ( pOVERLAPPEDcon->nSigID == P2PsigIO_ACK )
    {
      m_pCon -> releaseOVERLAPPED ( pOVERLAPPEDcon );
      if ( pOVERLAPPEDcon->bDelete )
        m_pCon -> DropOVERLAPPED ( pOVERLAPPEDcon );
      return true;
    }

    // Tidy up and
    return false;
}

///////////////////////////////////////////////////////////////////////
//  IO
//  NOTES: Completion Port transmission and receipt
//       : Override for 3rd Party protocol implementation
//

//
//  Sends P2PeerMsg
//  NOTES: Override this method to customise a protocol
//
//
//  Parameters:  HANDLE hFile
//               Send P2PeerMsg file handle
//
//               P2PeerMsg *pMsg
//               Message to be sent
//
//               OVERLAPPEDcon *pOVERLAPPEDsend
//               Pointer to an OVERLAPPEDcon send buffer
//
DWORD
P2Peerio::SendP2PeerMsg ( HANDLE hFile
                        , P2PeerMsg *pMsg
                        , OVERLAPPEDcon *pOVERLAPPEDsend )
{
    // Introduce locals
    const void *pvSendMsg;
    DWORD        nSendMsgSize;
    DWORD       dwResult;

    // To be sure, to be sure
    // NOTES: Confirm buffer not already in use
    ASSERT(!pOVERLAPPEDsend->bQueued);
    if ( pOVERLAPPEDsend->bQueued )
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , m_pCon->GetP2PaddrHub().c_str()
                    , m_pCon->m_oThatP2Paddr.c_str() )
           ->Message(_T("OVERLAPPEDsend buffer already in use") )
           ->Advice (_T("Internal conflict (Bug)") )
           ->Group(_T("P2P"))->Throw();
    pMsg -> PrepareIOmage  ( GetIFmask() );      // Mandatory

    // Prepare IMAGE type message exchanges
    // NOTES: These messages are sent in two parts, the first
    //        being the size and the second being the actual
    //        message
    //      : Expectation is that pMsg exists in a static state
    //        for the duration of the Send()
    ASSERT(!pMsg->Map_MatchName(P2Pmsg_3rdParty));
    pvSendMsg     = pMsg -> IOmage ( );
     nSendMsgSize = pMsg -> IOmageSize ( );
    ASSERT(nSendMsgSize);

    // Send message
    if ( Send(hFile,pvSendMsg,nSendMsgSize,pOVERLAPPEDsend) )
    {
      dwResult = GetLastError();
      if ( dwResult != ERROR_IO_PENDING )
        EVERR->Module (__FUNCTION__"(%s-%s)"
                      , m_pCon->GetP2PaddrHub().c_str()
                      , m_pCon->m_oThatP2Paddr.c_str() )
             ->Message(_T("Send(%i bytes) failed")
                      , nSendMsgSize )
             ->Group(_T("W32"))->HResult( dwResult )->Throw();
    }

    // Tidy up and
    return 0;
}

//
//  Sends buffer via IO completion port
//  NOTES: Expect errors due to broken or dropped connections etc
//
//
//  Parameters: HANDLE hFile
//              Send data file handle
//
//              const void *pvData
//              Buffer to be sent.  This buffer must remain in scope
//              for the duration of the overlapped IO sequence
//
//              DWORD dwSize
//              Buffer size in bytes
//
//              OVERLAPPEDcon *pOVERLAPPEDsend
//              Pointer to OVERLAPPEDcon structure. Returned via the
//              GetQueuedCompletionStatus()
//               
//
//  Returns:    DWORD
//              Result
//                0.. Queued OK
//                ?.. System error code
DWORD
P2Peerio::Send ( HANDLE hFile
               , const void *pvData, DWORD wDataSize
               , OVERLAPPEDcon *pOVERLAPPEDsend )
{
    // Locals
    DWORD hResult = S_OK;

    // To be sure, to be sure
    // NOTES: Confirm buffer not already queued
    if ( pOVERLAPPEDsend->bQueued )
      EVERR->Module (__FUNCTION__"(%s-%s)"
                    , m_pCon->GetP2PaddrHub().c_str()
                    , m_pCon->m_oThatP2Paddr.c_str() )
           ->Message("Transmit buffer already in use")
           ->Advice ("Internal conflict (Bug)" )
           ->Group("P2P")->Throw();

    // Preparation
    pOVERLAPPEDsend -> oOverlapped.Internal     = 0; 
    pOVERLAPPEDsend -> oOverlapped.InternalHigh = 0; 
    pOVERLAPPEDsend -> oOverlapped.Offset       = 0; 
    pOVERLAPPEDsend -> oOverlapped.OffsetHigh   = 0; 
    pOVERLAPPEDsend -> oOverlapped.hEvent       = 0;

    // Implementation
    // NOTES: The pvData buffer may or may not be contained within
    //        pOVERLAPPED send object
    m_pCon->prepareOVERLAPPED ( pOVERLAPPEDsend );
    if ( !WriteFile ( hFile
                    , pvData, wDataSize
                    , 0, (OVERLAPPED *)pOVERLAPPEDsend ) )
    {
      hResult = GetLastError();
      if ( hResult == WAIT_TIMEOUT )
      {
        SetLastError ( ERROR_IO_PENDING );
        hResult = GetLastError();
      }

      if ( hResult != ERROR_IO_PENDING )
        m_pCon->releaseOVERLAPPED ( pOVERLAPPEDsend );
    }

    // Tidy up, and
    return hResult;
}

//
//  Pre-destruction handler for sent P2PeerMsg objects
//  NOTES: Called as part of the P2PeerCon management procedures
//         immediately prior to destruction
//       : Override this default implementation for special processing,
//         P2PeerMsg reuse etc
//
//
//  Parameters:  P2PeerMsg*
//               Sent message as per IOCP completion status
//
//  Returns:     P2PeerMsg*
//                 0.. Negates destruction and facilitates reuse
//                 
P2PeerMsg*
P2Peerio::PreDestroySendP2PeerMsg ( P2PeerMsg *pMsg )
{
   // Default implementation
   return pMsg;
}

//
//  Receives next P2PeerMsg
//  NOTES: Handles receipt of following message types
//           P2PeerMsg images, including headers
//           BSTR images, headers manufactured
//       : Override for other message formats
//
//
//  Parameters: HANDLE hFile
//              Receive P2PeerMsg file handle
//
//              OVERLAPPEDcon *pOVERLAPPEDrecv
//              Pointer to an OVERLAPPEDcon receive buffer
//
//  Returns:    P2PeerMsg*
//              Received P2PeerMsg.  Client assumes control over
//              life cycle
//                0.. Incomplete, queued IO completion port receive
//                     
//
P2PeerMsg*
P2Peerio::RecvP2PeerMsg ( HANDLE hFile
                        , OVERLAPPEDcon *pOVERLAPPEDrecv )
{
    // Introduce locals
    DWORD        dwResult;
    VBListIOmage *pIOmage = 0;
    //DWORD      dwBytes    = pOVERLAPPEDrecv->dwBytes;
    //DWORD      dwBytesMax = pOVERLAPPEDrecv->dwBytesMax;
    //char       *pBuffer   = pOVERLAPPEDrecv->pBuffer;
    //P2Psize_t  *pMsgSize  = (P2Psize_t *)pOVERLAPPEDrecv->pBuffer;

    // Stage 0 - Initialisation
    // NOTES: Interface works off dual buffers.  The first persistant
    //        and the second dynamic.  Intended to be performed once
    //        at start of data receival.
    if ( pOVERLAPPEDrecv->pUserDB1 == 0 )
    {
      pOVERLAPPEDrecv -> pUserDB1   = new char [sizeof(VBListIOmage)+4];
      pOVERLAPPEDrecv -> dwBytesMax = sizeof(pIOmage->oSync);
      pOVERLAPPEDrecv -> dwBytes    = 0;
      if ( pOVERLAPPEDrecv->pBuffer == pOVERLAPPEDrecv->pUserDB2 )
        pOVERLAPPEDrecv -> pBuffer = 0;
      delete pOVERLAPPEDrecv -> pUserDB2;
             pOVERLAPPEDrecv -> pUserDB2 = 0;
      delete pOVERLAPPEDrecv -> pBuffer;
             pOVERLAPPEDrecv -> pBuffer  = 0;
    }

    // Stage 1 - Fetch message P2PmsgIOmage header
    // NOTES: Utilises the first buffer and defines remaining data
    //        stream.
STAGE1:
    pIOmage = (VBListIOmage *)pOVERLAPPEDrecv->pUserDB1;
    if ( pOVERLAPPEDrecv->dwBytes < sizeof(pIOmage->oSync) )
    {
      char  *pBuffer     = pOVERLAPPEDrecv -> pUserDB1;
      DWORD dwBytes      = pOVERLAPPEDrecv -> dwBytes;
      DWORD dwBytes2Recv = sizeof(pIOmage->oSync)-dwBytes;
      dwResult = Recv ( hFile, &pBuffer[dwBytes], dwBytes2Recv
                      , pOVERLAPPEDrecv );
      if ( dwResult )
      {
        if ( dwResult != ERROR_IO_PENDING )
          EVERR->Module (__FUNCTION__"(%s-%s)"
                        , m_pCon->GetP2PaddrHub().c_str()
                        , m_pCon->m_oThatP2Paddr.c_str() )
               ->Message("Recv(%i bytes) failed", dwBytes2Recv )
               ->HResult( dwResult )->Throw();
      }
    }

    // Stage 2 - Size message according to received header
    // NOTES: IOCP header contains P2Pmsg size properties.  Attempt
    //        synchronisation upon failure
    if ( pOVERLAPPEDrecv->pUserDB2 == NULL                  &&
         pOVERLAPPEDrecv->dwBytes  >= sizeof(pIOmage->oSync)   )
    {
      if ( (pIOmage->oSync.uiSync1+pIOmage->oSync.uiSync2) == ~0 )
      {
        UINT nSizeof = pIOmage -> oSync.uiSync1 & 0x00FFFFFF;
        if ( nSizeof > m_dwMaxRecvSize )
          EVERR->Module (__FUNCTION__"(%s-%s)"
                        , m_pCon->GetP2PaddrHub().c_str()
                        , m_pCon->m_oThatP2Paddr.c_str() )
               ->Message("Attempt to exceed maximum (%i) buffer size (%i)"
                        , m_dwMaxRecvSize, nSizeof )
               ->Advice ("Connection discontinued")
               ->Throw();
        pOVERLAPPEDrecv -> pUserDB2   = new char [nSizeof+4];
        pOVERLAPPEDrecv -> dwBytesMax = nSizeof;
        memcpy ( pOVERLAPPEDrecv->pUserDB2, pOVERLAPPEDrecv->pUserDB1
               , sizeof(pIOmage->oSync) );
      }
      else                             // Re-synchronisation required
      {//TODO: Why is this required, firing unnecessarily?
        char *pBuffer = pOVERLAPPEDrecv -> pUserDB1;
        memcpy ( &pBuffer[0], &pBuffer[1], --pOVERLAPPEDrecv->dwBytes );
        pBuffer[pOVERLAPPEDrecv->dwBytes] = 0;
        goto STAGE1;
      }
    }

    // Stage 3 - Fetch message data
    UINT nSizeof = pIOmage -> oSync.uiSync1 & 0x00FFFFFF;
    if ( pOVERLAPPEDrecv->dwBytes >= sizeof(pIOmage->oSync) &&
         pOVERLAPPEDrecv->dwBytes <  nSizeof                   )
    {
      // To be sure, to be sure
      if ( pOVERLAPPEDrecv->dwBytes > pOVERLAPPEDrecv->dwBytesMax )
        EVERR->Module (__FUNCTION__"(%s-%s)"
                      , m_pCon->GetP2PaddrHub().c_str()
                      , m_pCon->m_oThatP2Paddr.c_str() )
             ->Message("Recv(%i vs %i) bytes failed\n"
                       "Attempted buffer overrun"
                      , pOVERLAPPEDrecv->dwBytes, pOVERLAPPEDrecv->dwBytesMax )
             ->Group("P2P")->Throw();

      DWORD dwBytes      = pOVERLAPPEDrecv -> dwBytes;
      DWORD dwBytes2Recv = nSizeof - dwBytes;
      dwResult = Recv ( hFile
                      ,&pOVERLAPPEDrecv->pUserDB2[dwBytes], dwBytes2Recv
                      , pOVERLAPPEDrecv );
      if ( dwResult )
      {
        if ( dwResult != ERROR_IO_PENDING )
          EVERR->Module (__FUNCTION__"(%s-%s)"
                        , m_pCon->GetP2PaddrHub().c_str()
                        , m_pCon->m_oThatP2Paddr.c_str() )
               ->Message("Overlapped Recv(%i bytes) failed\n"
                        , dwBytes2Recv )
               ->HResult( dwResult )->Throw();
      }
    }

    // Stage 4 - Construct P2PeerMsg
    if ( pOVERLAPPEDrecv->dwBytes >= sizeof(pIOmage->oSync) &&
         pOVERLAPPEDrecv->dwBytes >=        nSizeof            )
    {
      ASSERT(pOVERLAPPEDrecv->dwBytes==nSizeof);
      if ( pOVERLAPPEDrecv->pUserDB2 == pOVERLAPPEDrecv->pBuffer ||
           pOVERLAPPEDrecv->pUserDB1 == pOVERLAPPEDrecv->pBuffer    )
        pOVERLAPPEDrecv->pBuffer = 0;

      P2PeerMsg *pMsg = new P2PeerMsg ( (VBListIOmage *)pOVERLAPPEDrecv->pUserDB2 );
      pOVERLAPPEDrecv -> pUserDB2   = 0;
      pOVERLAPPEDrecv -> dwBytes    = 0;
      pOVERLAPPEDrecv -> dwBytesMax = sizeof(VBListIOmage);
      pIOmage -> oSync.uiSync1 = 0;

      // Tidy up, and
      return pMsg;
    }

    // Tidy up and
    return (P2PeerMsg *)0;
}

//
//  Receives buffer via IO completion port
//  NOTES: Expect errors due to broken or dropped connections etc
//
//
//  Parameters: HANDLE hFile
//              Receive data file handle
//
//              void *pvData
//              Data receive buffer.  This buffer must remain in scope
//              for the duration of the completion port read sequence
//
//              DWORD dwSize
//              Buffer size in bytes
//
//              OVERLAPPEDcon *pOVERLAPPEDrecv
//              Pointer to OVERLAPPEDcon structure. Returned via the
//              GetQueuedCompletionStatus()
//
//  Returns:    DWORD
//              Result
//                0.. Queued OK
//                ?.. System error code
DWORD
P2Peerio::Recv ( HANDLE hFile
               , void *pvData, DWORD dwSize
               , OVERLAPPEDcon *pOVERLAPPEDrecv )
{
    // Locals
    DWORD hResult = S_OK;

    // To be sure, to be sure
    // NOTES: Confirm buffer not already queued
    if ( pOVERLAPPEDrecv->bQueued )
      EVERR->Module   (__FUNCTION__"(%s-%s)"
                      , m_pCon->GetP2PaddrHub().c_str()
                      , m_pCon->m_oThatP2Paddr.c_str() )
           ->Message_T("Receive buffer already in use" )
           ->Advice_T ("Internal conflict (Bug)" )
           ->Group("P2P")->Throw();

    // Preparation
    pOVERLAPPEDrecv -> oOverlapped.Internal     = 0; 
    pOVERLAPPEDrecv -> oOverlapped.InternalHigh = 0; 
    pOVERLAPPEDrecv -> oOverlapped.Offset       = 0; 
    pOVERLAPPEDrecv -> oOverlapped.OffsetHigh   = 0; 
    pOVERLAPPEDrecv -> oOverlapped.hEvent       = 0; 

    // Implementation
    // NOTES: Queue request, RecvP2PeerMsg() processes the result
    //      : Operation expected to return ERROR_IO_PENDING state
    m_pCon -> prepareOVERLAPPED ( pOVERLAPPEDrecv );
    //DWORD dwRead = 0;
    if ( !ReadFile(hFile
                  ,pvData,dwSize,0/*&dwRead*/,(OVERLAPPED *)pOVERLAPPEDrecv) )
    { // Error condition, OVERLAPPED object rejected by IOCP
      hResult = GetLastError();
      if ( hResult == WAIT_TIMEOUT )
      {
        SetLastError ( ERROR_IO_PENDING );
        hResult = GetLastError();
      }

      if ( hResult != ERROR_IO_PENDING )
        m_pCon -> releaseOVERLAPPED ( pOVERLAPPEDrecv );
    }

    // Alternatively EOF, usually flags connection has dropped out
    // between the previous Recv() and this instance. Browsers do this
    // NOTES: OVERLAPPEDrecv is effectively being pumped through the
    //        IOCP and as such should not be released here
    //      : Requires careful attention to the win32 ReadFile() doco
    //      : P2Pevent::OnClose() processing optionally reports event
    else if ( (hResult=GetLastError()) != ERROR_IO_PENDING &&
               hResult                                         )
    { // Success with condition, OVERLAPPED object passing through IOCP
      P2PeventSP spEvent
        = EVERR->Module   (__FUNCTION__"(%s-%s)"
                          , m_pCon->GetP2PaddrHub().c_str()
                          , m_pCon->m_oThatP2Paddr.c_str() )
               ->Message_T(_T("Conflicting ReadFile() outcome") )
               ->HResult  (hResult);
      m_pCon -> SetP2Pevent ( spEvent );
    }

    // Tidy up, and
    return hResult;
}

///////////////////////////////////////////////////////////////////////
//  Timers
//  NOTES: Implemented via synchronous callbacks from the assigned
//         P2PmsgPump

//
//  Sets PIT for P2Peerio
//  NOTES: Outstanding timers must be cancelled in destructor for
//         this object
//       : Triggered timer is implemented via On_PITimer() call back
//         to this object
//
//
//  Parameters: P2PeerTime_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
P2Peerio::SetPITimer ( P2Pmsecs_t uMSecDelay, DWORD dwUserKey )
{
    // Delegation
    // NOTES: Handler for this object always called
    return SetP2PmsgTimer ( 0, this, uMSecDelay, dwUserKey );
}

//
//  PITimer handler for P2Peerio
//  NOTES: Override for specialisation.  But always delegate unhandled
//         timers through
//       : Callbacks to this method are synchronous from the assigned
//         pump and as such should not indulge in lengthy processing
//         sequences or suspend control flow
//
//
//  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
P2Peerio::On_PITimer ( bool bCancel
                     , PITimerID nPITimerID, DWORD dwUserKey )
{
    // Acknowledgement
    if ( nPITimerID == m_nPITimerIDack )
    {
      m_nPITimerIDack = 0;
      // TODO: Implement default acknowledgement processing
      return;
    }

    // Unknown timer
    // NOTES: Report and ignore.  Maintain existing P2PeerCon state
    EVERR->Module ( T__FUNCTION__ )
         ->AFP(bCancel)->AFP(nPITimerID)->AFP(dwUserKey)
         ->Message(_T("PITimer on (%s-%s) not handled")
                  , m_pCon->GetP2PaddrHub().c_str()
                  , m_pCon->m_oThatP2Paddr.c_str() )
         ->Advice (_T("Ignored, bug (SNHappen)") )
         ->Cancel ();
}

///////////////////////////////////////////////////////////////////////
//  Specialisation

//
//  Acknowledge message receipt
//  NOTES: Acknowledge P2PeerMsg's in the context that they are
//         received.  As a consequence multiple OVERLAPPED sends
//         may be outstanding.
//
//
//  Parameters: HANDLE hFile
//              Send acknowledgement file handle
//
//              P2PeerMsg *pMsg
//              Message to be acknowledged
// 
void
P2Peerio::Acknowledge ( HANDLE hFile, P2PeerMsg *pMsg )
{
    UNREFERENCED_PARAMETER ( hFile );
    UNREFERENCED_PARAMETER ( pMsg );
}

//
//  On_Acknowledgement receipt processing
//  NOTES: Available for those interfaces observing low
//         level ack - nak protocols
//       : Introduces significant overhead on throughput
//
//
//  Parameters: bool bAckNak
//              Acknowledgement state
//
//
//  Returns:    Summary
//                true... Expected
//                false.. Unexpected
bool
P2Peerio::On_Acknowledge ( bool bAckNak )
{
    // Observe expectations
    // NOTES: OVERLAPPEDsend passes through the IOCP at least
    //        two times per P2PeerMsg
    //      : Important, clear wait for acknowledgement flag, set
    //        acknowledgement state
    if ( !m_pCon->m_pOVERLAPPEDsend->bQueued )
    {
      m_pCon -> PostOVERLAPPED ( m_pCon->m_pOVERLAPPEDsend );
      return true;
    }

    // Cancel acknowledgement PITimerID
    if ( m_nPITimerIDack )
      CancelP2PmsgTimer ( m_nPITimerIDack );

    // Tidy up, and
    return false;
}

//
//  Resets internals
//  NOTES: Intention is for object to be left in a re-usable state
//
void
P2Peerio::Reset ( )
{
    // Cancellation of PITimer's
    if ( m_nPITimerIDack )
      CancelP2PmsgTimer ( m_nPITimerIDack );

    // Garbage collection
    if ( m_pCon           &&
         m_pOVERLAPPEDack    )
      m_pCon -> DropOVERLAPPED ( m_pOVERLAPPEDack );
}

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

void
P2Peerio::AssertValid ( ) const
{
    // TODO: Additional validation
}

///////////////////////////////////////////////////////////////////////
//  Properties

//
//  Toggles interface trace on and off
//
//  Parameters: bool bIFTraceEoD
//              Enabled or disabled state
//
//
//  Returns:    State
//                true... Enabled
//                false.. Disabled
bool
P2Peerio::SetIFTrace ( bool bIFTraceEoD )
{   
    return m_bIFTraceEoD = bIFTraceEoD;
}
bool
P2Peerio::GetIFTrace (  )
{   
    return m_bIFTraceEoD;
}

//
//  Exposes managing P2PeerCon object
//  NOTES: P2Peerio objects MUST be managed by a single P2PeerCon object
//
//  Returns:    P2PeerCon*
//              Managing connection object
//                0.. Unassigned or floating instance
//
P2PeerCon*
P2Peerio::GetP2PeerCon ( )
{   
    return m_pCon;
}

DWORD
P2Peerio::SetIFmask ( DWORD dwIFmask )
{   
    return m_dwIFmask = dwIFmask;
}

DWORD
P2Peerio::GetIFmask ( )
{   
    return m_dwIFmask;
}

DWORD
P2Peerio::SetMaxRecvSize ( DWORD dwMaxRecvSize )
{   
    ASSERT(dwMaxRecvSize>0);
    m_dwMaxRecvSize = dwMaxRecvSize;
    return m_dwMaxRecvSize;
}

DWORD
P2Peerio::GetMaxRecvSize ( ) const
{   
    return m_dwMaxRecvSize;
}

DWORD
P2Peerio::SetMaxSendSize ( DWORD dwMaxSendSize )
{   
    ASSERT(dwMaxSendSize>0);
    m_dwMaxSendSize = dwMaxSendSize;
    return m_dwMaxSendSize;
}

DWORD
P2Peerio::GetMaxSendSize ( ) const
{   
    return m_dwMaxSendSize;
}
