#include "stdafx.h"



VOID
IcqWriteCompletionRoutine
				(
				ULONG ErrorCode,
				ULONG BytesTransferred,
				PNH_BUFFER Bufferp
				)
/*++

Routine Description:

    A generic Write Completion Routine.
    
Arguments:

    none.

Return Value:

    

--*/
{
	PCNhSock Socketp = Bufferp->Socketp;

	ICQ_TRC(TM_IO, TL_DUMP, ("-- WRITE COMPLETION ROUTINE --"));

	NhReleaseBuffer(Bufferp);

	//Dereference Interface;

	DEREF_COMPONENT( Socketp, eRefIoWrite);

	DEREF_COMPONENT( g_IcqComponentReferencep, eRefIoWrite);
}









VOID
ReadServerCompletionRoutine
				(
				ULONG ErrorCode,
				ULONG BytesTransferred,
				PNH_BUFFER Bufferp
				)
/*++

Routine Description:

    Reads the Server Responses to Client packets
    and then multiplexes this responses to the approprate client
    which was given in the Context information
    
    
Arguments:

    none.

Return Value:

    

--*/
{
    PICQ_CLIENT IcqClientp       = NULL;
	PCNhSock	Socketp			 = NULL;
	ULONG		Error			 = NO_ERROR;

    ICQ_TRC(TM_IO, TL_ERROR, (" "));

	PROFILER(TM_IO, TL_TRACE, ("> UDP-SERVER - READ "));

	if(Bufferp is NULL) return;

	//
	// Get the Client Information 
	Socketp = Bufferp->Socketp;

	IcqClientp = (PICQ_CLIENT)Bufferp->Context;

    ASSERT(IcqClientp != NULL);

	if(ErrorCode)
	{
		// Re-issue a read operation if it is not critical Error.
		ICQ_TRC(TM_IO, TL_ERROR,
                ("**  !! READ ERROR in Server -> Client (UDP) !! **"));

		NhReleaseBuffer(Bufferp);

		//ErrorOut();

	}
	else  // we need the context information
	{
        //
		// reissue read first
        //
        REF_COMPONENT( IcqClientp, eRefIoRead );

		Error = Socketp->NhReadDatagramSocket(g_IcqComponentReferencep,
								              NULL,
								              ReadServerCompletionRoutine,
								              IcqClientp,
                                              NULL);
		if(Error)
		{
			ICQ_TRC(TM_IO, TL_ERROR, ("READ ERROR"));

            DEREF_COMPONENT( IcqClientp, eRefIoRead );
		}
		
		// multiplex the data
		Error = IcqClientp->ServerRead(Bufferp, 0, 0);

        if(Error)
        {
            NhReleaseBuffer( Bufferp );
        }
	}

	// DEREFERENCING
	DEREF_COMPONENT( Socketp, eRefIoRead );

	DEREF_COMPONENT( g_IcqComponentReferencep, eRefIoRead );

	DEREF_COMPONENT( IcqClientp, eRefIoRead );
}






VOID
IcqReadClientUdpCompletionRoutine
                 (
				 ULONG ErrorCode,
				 ULONG BytesTransferred,
				 PNH_BUFFER Bufferp
				 )
/*++

Routine Description:

    This is the READ - DISPATCHER for the UDP 
    Clients sending packets to the server will be caught here..
    it will dispatch the packet to the appropriate ICQ client objects READER
    
    
Arguments:

    none.

Return Value:

    

--*/
{
	PCNhSock    Socketp			 = Bufferp->Socketp;
	ULONG		Error			 = NO_ERROR;
	// HANDLE DynamicRedirectHandle = (HANDLE) Bufferp->Context;

    ICQ_TRC(TM_IO, TL_ERROR, (" "));

	PROFILER(TM_IO, TL_TRACE,("UDP-CLIEN-READ DATA CAME from %s e(%hu)", 
		    INET_NTOA(Bufferp->ReadAddress.sin_addr.S_un.S_addr), ErrorCode));

    do
    {
        if(ErrorCode)
    	{
    		// Re-issue a read operation if it is not critical Error.
    		ICQ_TRC(TM_IO, TL_ERROR,
                    ("** !! CLIENT~SERVER READ ERROR - Deletin all the Client Entries"));

            Error = g_IcqPrxp->ReadFromClientCompletionRoutine(ErrorCode,
                                                               BytesTransferred,
                                                               Bufferp);
            break;
        }
    	else
    	{
    		// Re-issue a read operation.
    		Error = Socketp->NhReadDatagramSocket(g_IcqComponentReferencep,
    											  NULL,
    											  IcqReadClientUdpCompletionRoutine,
    											  NULL,// DynamicRedirectHandle,
    											  NULL);
    		if(Error) 
    		{
    			ICQ_TRC(TM_IO, TL_ERROR,("TREAD !!> REISsUE READ ERROR "));
    
    			break;
    		}

            g_IcqPrxp->ReadFromClientCompletionRoutine(ErrorCode,
                                                       BytesTransferred,
                                                       Bufferp);
    
    	} // else for  if (ErrorCode)

    } while ( FALSE );

	DEREF_COMPONENT( Socketp, eRefIoRead);

	DEREF_COMPONENT( g_IcqComponentReferencep, eRefIoRead);
}






//
// CLIENT - RELATED  IO COMPLETION ROUTINES
//


VOID
IcqPeerConnectionCompletionRoutine
							(
								 ULONG ErrorCode,
								 ULONG BytesTransferred,
								 PNH_BUFFER Bufferp
							 )
/*++

Routine Description:

    
    
Arguments:

    none.

Return Value:

    

--*/
{
	PCNhSock Socketp = NULL;
	PICQ_PEER IcqPeerp = NULL;
	ULONG Error;
	
	// ASSERT(Bufferp);

	Socketp = Bufferp->Socketp;

	IcqPeerp = reinterpret_cast<PICQ_PEER>(Bufferp->Context);
	//	IcqClientp = reinterpret_cast<PICQ_CLIENT>(Bufferp->Context2);

	ICQ_TRC(TM_IO, TL_TRACE, ("> IcqPeerConnectionCompletionRoutine"));

	// ASSERT on all of them.
	do
	{
		if(ErrorCode)
		{
			// Do - we need it?
			// Delete the Shadow mapping

			//
			// if can't connect then Delete the existing Socket to which we have 
			// established connection.
			//
			if(IcqPeerp->MappingDirection is IcqFlagOutgoing)
			{
                STOP_COMPONENT(IcqPeerp->ToClientSocketp);

				//DEREFERENCE_COMPONENT(IcqPeerp->ToClientSocketp);
			}
            else // incoming
			{
                STOP_COMPONENT(IcqPeerp->ToPeerSocketp);

				//DEREFERENCE_COMPONENT(IcqPeerp->ToClientSocketp);
			}

            break;
		}
		else
		{
			ULONG srcIp;
			USHORT srcPort;
			
			Socketp->NhQueryRemoteEndpointSocket(&srcIp, &srcPort);

			//
			//
			ICQ_TRC(TM_IO, TL_TRACE, 
					("Connected to - Remote end is at %s:%hu",
					INET_NTOA(srcIp), htons(srcPort)));
			
			//
			// Activate The Connection
			// Issue the Read Operations on both Sockets with the Peer as their 
			// Context 
            //
			if(IcqPeerp->MappingDirection is IcqFlagOutgoing)
			{
				IcqPeerp->ToPeerSocketp = Socketp;

				ICQ_TRC(TM_MSG, TL_DUMP, 
						 ("Mapping is outGoing.. this socket is to the peer"));
			}
			else
			{
				IcqPeerp->ToClientSocketp = Socketp;
			}

			ICQ_TRC(TM_IO, TL_TRACE, ("Issuing firstRead"));
			
			Socketp = IcqPeerp->ToClientSocketp;

            REF_COMPONENT( IcqPeerp, eRefIoRead );

			Error = Socketp->NhReadStreamSocket
										(
											g_IcqComponentReferencep,
											NULL,  
											ICQ_BUFFER_SIZE,     // we should give a size
											0,
											IcqPeerReadCompletionRoutine,
											IcqPeerp,
											NULL
										);

			if(Error)
			{
				ErrorOut();

				ICQ_TRC(TM_MSG, TL_ERROR, (" ERROR - Read failed on ToClient Sock"));

                DEREF_COMPONENT( IcqPeerp, eRefIoRead );
				
				break;
			}

			

			//
			// The other read operation
			//

			ICQ_TRC(TM_IO, TL_TRACE, ("Issuing second Read"));

			Socketp = IcqPeerp->ToPeerSocketp;

            REF_COMPONENT( IcqPeerp, eRefIoRead );
			
			Error = Socketp->NhReadStreamSocket
										(
											g_IcqComponentReferencep,
											NULL,
											ICQ_BUFFER_SIZE,
											0,
											IcqPeerReadCompletionRoutine,
											IcqPeerp,
											NULL
										);
			if(Error)
			{
				ErrorOut();

				ICQ_TRC(TM_MSG, TL_ERROR, (" ERROR - Read failed on ToPeer Sock"));

                STOP_COMPONENT(IcqPeerp->ToClientSocketp); // reference will be cleared later

				DEREF_COMPONENT( IcqPeerp, eRefIoRead);

                DEREF_COMPONENT( IcqPeerp, eRefIoRead );
				
				break;
			}
		
			//
			// Reference the ICQ_PEER twice due to two read issues

			IcqPeerp->bActivated = TRUE;
		}
	} while (FALSE);

	DEREF_COMPONENT( Bufferp->Socketp, eRefIoConnect );

	DEREF_COMPONENT( IcqPeerp, eRefIoConnect);

	DEREF_COMPONENT( g_IcqComponentReferencep, eRefIoConnect );
}







VOID
IcqPeerReadCompletionRoutine
							(
								 ULONG ErrorCode,
								 ULONG BytesTransferred,
								 PNH_BUFFER Bufferp
							 )
/*++

Routine Description:

	Reads TCP data between the peers. Within these flows there will be 
    a place where the Data channel is negotiated.
    
Arguments:

    none.

Return Value:

    

--*/
{

	PICQ_PEER IcqPeerp = NULL;
	PCNhSock Socketp = NULL;
	PCNhSock  OtherSocketp = NULL;
	ULONG Error  = NO_ERROR; 

	// ASSeRT(Bufferp);

	Socketp = Bufferp->Socketp;

	IcqPeerp = reinterpret_cast<PICQ_PEER>(Bufferp->Context);


	ICQ_TRC(TM_IO, TL_TRACE, 
            ("> IcqPeerReadCompletionRoutine E:(%X) D:(%u)", 
             ErrorCode, BytesTransferred));

	do 
	{
		if( (ErrorCode != 0)  || 
            ((ErrorCode== 0) && (BytesTransferred == 0))
          )
		{

			ICQ_TRC(TM_IO, TL_ERROR, ("Stoppping the Peer SESSION"));
							
            IcqPeerp->EndPeerSessionForClient(Socketp);

			break;
		}
		else
		{
			if(BytesTransferred)
			{
				OtherSocketp = IcqPeerp->ToClientSocketp;

				ICQ_TRC(TM_IO, TL_TRACE, 
                        (" Regular Data from a Peer(%u)/Client(%s) Socket",
                         IcqPeerp->PeerUIN,            // Peer-UIN
                         INET_NTOA(IcqPeerp->iKey1))); // Client-IP

                //
				// Determine which direction this Socket is from..
                //
				if(OtherSocketp is Socketp)
				{
                    //
					// NOTE: if it is from the ToClientSocketp then Process it
					//
                    IcqPeerp->ProcessOutgoingPeerMessage(Bufferp->Buffer,
                                                         Bufferp->BytesTransferred);

					OtherSocketp = IcqPeerp->ToPeerSocketp;
				}
				
				// then forward it to the other side by simply writing it .
				Error = OtherSocketp->NhWriteStreamSocket(g_IcqComponentReferencep,
                                                          Bufferp,
                                                          BytesTransferred,
                                                          0,
                                                          IcqWriteCompletionRoutine,
                                                          NULL,
                                                          NULL);
                if(Error)
                {
                    ICQ_TRC(TM_MSG, TL_ERROR, 
                            ("Error - In writing to the other side"));
                }
			}

			//
			// Issue another Read operation
			// 
            REF_COMPONENT( IcqPeerp, eRefIoRead );

			Error = Socketp->NhReadStreamSocket(g_IcqComponentReferencep,
					        					NULL,
							        			ICQ_BUFFER_SIZE,
									        	0,
										        IcqPeerReadCompletionRoutine,
										        IcqPeerp,
										        NULL);
            if(Error)
            {
			    DEREF_COMPONENT( IcqPeerp, eRefIoRead);

                ICQ_TRC(TM_MSG, TL_ERROR, ("Peer connection no more??"));
            }
		}
	} while (FALSE);

	DEREF_COMPONENT( Socketp, eRefIoRead );

	DEREF_COMPONENT( IcqPeerp, eRefIoRead );

	DEREF_COMPONENT( g_IcqComponentReferencep, eRefIoRead );
} // End of *IcqPeerReadCompletionRoutine*