//////////////////////////////////////////////////////////
//
//    Copyright (c) 2001 Microsoft Corporation
//
//    Module Name:
//       receive.cpp
//
//    Abstract:
//       This module contains code which implements receive
//       commands from the dll
//
//////////////////////////////////////////////////////////

#include "stdafx.h"

///////////////////////////////////////////////////////////////////////
// Public functions
///////////////////////////////////////////////////////////////////////

// --------------------------------------------------------------------
//
// Function:   DoReceiveDatagram
//
// Arguments:  TdiHandle -- handle of address object
//             pInTransportAddress -- TA for receiving on
//             pOutTransportAddress -- full TA data was received on
//             ppucBuffer   -- buffer to stuff with received data
//
// Returns:    length of data in buffer (0 if none or error)
//
// Descript:   This function causes the driver to receive a datagram
//
//---------------------------------------------------------------------


ULONG
DoReceiveDatagram(ULONG                ulTdiHandle,
                  PTRANSPORT_ADDRESS   pInTransportAddress,
                  PTRANSPORT_ADDRESS   pOutTransportAddress,
                  PUCHAR               *ppucBuffer)
{
   PUCHAR   pucBuffer = (PUCHAR)LocalAllocateMemory(ulMAX_BUFFER_LENGTH);

   if (!pucBuffer)
   {
      return 0;
   }

   SEND_BUFFER    SendBuffer;       // arguments for command

   //
   // set up arguments
   //
   SendBuffer.TdiHandle = ulTdiHandle;
   SendBuffer.COMMAND_ARGS.SendArgs.ulBufferLength = ulMAX_BUFFER_LENGTH;
   SendBuffer.COMMAND_ARGS.SendArgs.pucUserModeBuffer = pucBuffer;
   
   //
   // if passed in a transport address to receive on
   //
   if (pInTransportAddress)
   {
      memcpy(&SendBuffer.COMMAND_ARGS.SendArgs.TransAddr,
             pInTransportAddress,
             (FIELD_OFFSET(TRANSPORT_ADDRESS, Address)
               + FIELD_OFFSET(TA_ADDRESS, Address)
                  + pInTransportAddress->Address[0].AddressLength));

   }
   //
   // else, set the number of addresses field to 0
   //
   else
   {
      SendBuffer.COMMAND_ARGS.SendArgs.TransAddr.TAAddressCount = 0;
   }

   //
   // call the driver
   //
   RECEIVE_BUFFER ReceiveBuffer;    // return info from command
   NTSTATUS       lStatus = TdiLibDeviceIO(ulRECEIVEDATAGRAM,
                                           &SendBuffer,
                                           &ReceiveBuffer);

   //
   // deal with results -- assume no packet received or error occurred
   //
   ULONG    ulBufferLength = 0;
   *ppucBuffer = NULL;

      
   //
   // will return with success but ulBufferLength = 0 if there is no
   // packet available 
   //
   if (lStatus == STATUS_SUCCESS)
   {
      ulBufferLength = ReceiveBuffer.RESULTS.RecvDgramRet.ulBufferLength;
   }
   
   if (ulBufferLength)
   {
      if (pOutTransportAddress)
      {
         memcpy(pOutTransportAddress,
                &ReceiveBuffer.RESULTS.RecvDgramRet.TransAddr,
                (FIELD_OFFSET(TRANSPORT_ADDRESS, Address)
                  + FIELD_OFFSET(TA_ADDRESS, Address)
                     + ReceiveBuffer.RESULTS.RecvDgramRet.TransAddr.TaAddress.AddressLength));
      }
      *ppucBuffer = pucBuffer;   
   }
   else
   {
      LocalFreeMemory(pucBuffer);
   }
   return ulBufferLength;
}


// --------------------------------------------------------------------
//
// Function:   DoReceive
//
// Arguments:  TdiHandle -- handle of endpoint object
//             ppucBuffer   -- buffer to stuff with received data
//
// Returns:    length of data in buffer (0 if error)
//
// Descript:   This function causes the driver to receive data sent
//             over a connection
//
//---------------------------------------------------------------------


ULONG
DoReceive(ULONG   ulTdiHandle,
          PUCHAR  *ppucBuffer)
{
   PUCHAR   pucBuffer = (PUCHAR)LocalAllocateMemory(ulMAX_BUFFER_LENGTH);

   if (!pucBuffer)
   {
      return 0;
   }

   SEND_BUFFER    SendBuffer;       // arguments for command

   //
   // set up arguments
   //
   SendBuffer.TdiHandle = ulTdiHandle;
   SendBuffer.COMMAND_ARGS.SendArgs.ulBufferLength = ulMAX_BUFFER_LENGTH;
   SendBuffer.COMMAND_ARGS.SendArgs.pucUserModeBuffer = pucBuffer;

   //
   // call the driver
   //
   RECEIVE_BUFFER ReceiveBuffer;    // return info from command
   NTSTATUS       lStatus = TdiLibDeviceIO(ulRECEIVE,
                                           &SendBuffer,
                                           &ReceiveBuffer);

   //
   // deal with results -- assume no data or error
   //
   *ppucBuffer = NULL;
   ULONG ulBufferLength = 0;   // data length to return
   
   //
   // will return success with 0 bufferlength if no packet available
   //
   if (lStatus == STATUS_SUCCESS)
   {
      ulBufferLength = ReceiveBuffer.RESULTS.RecvDgramRet.ulBufferLength;
   }

   if (ulBufferLength)
   {
      *ppucBuffer = pucBuffer;   
   }
   else
   {
      LocalFreeMemory(pucBuffer);
   }
   return ulBufferLength;
}


// ---------------------------------------
//
// Function:   DoPostReceiveBuffer
//
// Arguments:  TdiHandle -- handle for address object or endpoint
//             ulBufferLength -- length of buffer to post for receive
//
// Returns:    status of command
//
// Descript:   This function allocates a buffer, which it then passed to
//             the driver.  The driver locks the buffer down, and posts it
//             for a receive or receivedatagram.
//
// ----------------------------------------


VOID
DoPostReceiveBuffer(ULONG  ulTdiHandle,
                    ULONG  ulBufferLength)
{
   NTSTATUS       lStatus;          // status of command
   RECEIVE_BUFFER ReceiveBuffer;    // return info from command
   SEND_BUFFER    SendBuffer;       // arguments for command

   //
   // set up arguments
   //
   SendBuffer.TdiHandle = ulTdiHandle;
   SendBuffer.COMMAND_ARGS.SendArgs.ulBufferLength = ulBufferLength;

   PUCHAR   pucBuffer = (PUCHAR)LocalAllocateMemory(ulBufferLength);
   if (pucBuffer)
   {
      SendBuffer.COMMAND_ARGS.SendArgs.pucUserModeBuffer = pucBuffer;

      //
      // call the driver
      //
      lStatus = TdiLibDeviceIO(ulPOSTRECEIVEBUFFER,
                               &SendBuffer,
                               &ReceiveBuffer);
   
      if (lStatus != STATUS_SUCCESS)
      {
         _tprintf(TEXT("DoPostReceiveBuffer: failure, status = %s\n"), TdiLibStatusMessage(lStatus));
         LocalFreeMemory(pucBuffer);
      }
   }
   else
   {
      _putts(TEXT("DoPostReceiveBuffer:  failed to allocate buffer\n"));
   }
}


// ------------------------------------------
//
// Function:   DoFetchReceiveBuffer
//
// Arguments:  TdiHandle -- handle of address object or endpoint
//             pulBufferLength -- length of data returned
//             ppDataBuffer -- allocated buffer with data
//
// Returns:    status of operation
//
// Descript:   This function retrieves the oldest posted buffer.  If no
//             data is available, it will cancel the appropriate irp
//             It then returns the data to the caller as appropriate
//
// -------------------------------------------

ULONG
DoFetchReceiveBuffer(ULONG    ulTdiHandle,
                     PUCHAR   *ppDataBuffer)
{
   NTSTATUS       lStatus;          // status of command
   RECEIVE_BUFFER ReceiveBuffer;    // return info from command
   SEND_BUFFER    SendBuffer;       // arguments for command
   ULONG          ulBufferLength = 0;   
   //
   // set up arguments
   //
   SendBuffer.TdiHandle = ulTdiHandle;
   *ppDataBuffer        = NULL;

   //
   // call the driver
   //
   lStatus = TdiLibDeviceIO(ulFETCHRECEIVEBUFFER,
                            &SendBuffer,
                            &ReceiveBuffer);
      
   if (lStatus == STATUS_SUCCESS)
   {
      PUCHAR   pucTempBuffer  = ReceiveBuffer.RESULTS.RecvDgramRet.pucUserModeBuffer;
                  
      ulBufferLength = ReceiveBuffer.RESULTS.RecvDgramRet.ulBufferLength;
      if (ulBufferLength)
      {
         *ppDataBuffer = pucTempBuffer;
      }
      else if (pucTempBuffer)
      {
         LocalFreeMemory(pucTempBuffer);
      }
   }

   return ulBufferLength;
}

////////////////////////////////////////////////////////////////////
// end of file receive.cpp
////////////////////////////////////////////////////////////////////