/***********************************************************************
 * 
 *  Copyright (C) 2006 Novell, Inc. All Rights Reserved.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; version 2.1
 *  of the License.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, Novell, Inc.
 * 
 *  To contact Novell about this file by physical or electronic mail, 
 *  you may find current contact information at www.novell.com.
 * 
 *  Author: Juan Carlos Luciani <jluciani@novell.com>
 *
 ***********************************************************************/


//===[ Include files ]=====================================================

#include "ipcint.h"

//===[ External data ]=====================================================

//===[ External prototypes ]===============================================

//===[ Manifest constants ]================================================

//===[ Type definitions ]==================================================

//===[ Function prototypes ]===============================================

//===[ Global variables ]==================================================

// Channel Packet Types
string DataCarrierTypeTemplate = "TypeXX";
string ReqDataCarrierType =      "Type01";
string ReqErrorCarrierType =     "Type02";

// Channel Packet Headers
string ReqIdHdr = "ReqIdHdr =";
string PayloadLengthHdr = "PayloadLength =";

// Req Data Pkt Hdr Template
string ReqDataPktHdrTemplate =   "Type01\r\nReqIdHdr =XXXXXXXX\r\nPayloadLength =XXXXXXXX\r\n\r\n";

// Req Error Pkt Hdr Template
string ReqErrorPktHdrTemplate =  "Type02\r\nReqIdHdr =XXXXXXXX\r\nPayloadLength =XXXXXXXX\r\n\r\n";


//++=======================================================================
int
ChannelProto::buildReqDataPktHdr(
   uint32_t reqId,
   int32_t payloadLength,
   char *pPktHdr)
//
//  Arguments: 
//
//  Returns:   
//
//  Abstract:  
//
//  Notes:
//
// L2
//=======================================================================--
{
   int   retStatus = -1;

   DbgTrace(1, "ChannelProto::buildReqDataPktHdr- Start\n", 0);

   try {
      // - Req Data Packet Header Format -
      //
      // ReqDataCarrierType
      // ReqIdHdr value (value format=%08X)
      // PayloadLengthHdr value (value format=%08X)
      //

      // Setup the necessary value strings
      char wrkBuffer[10];

      sprintf(wrkBuffer, "%08X", reqId);
      string reqIdValue = wrkBuffer;
      sprintf(wrkBuffer, "%08X", payloadLength);
      string payloadLengthValue = wrkBuffer;

      // Format the header.
      char* pCurr = pPktHdr;

      memcpy(pCurr, ReqDataCarrierType.c_str(), ReqDataCarrierType.length());
      pCurr += ReqDataCarrierType.length();
      memcpy(pCurr, "\r\n", 2);
      pCurr += 2;

      memcpy(pCurr, ReqIdHdr.c_str(), ReqIdHdr.length());
      pCurr += ReqIdHdr.length();
      memcpy(pCurr, reqIdValue.c_str(), reqIdValue.length());
      pCurr += reqIdValue.length();
      memcpy(pCurr, "\r\n", 2);
      pCurr += 2;

      memcpy(pCurr, PayloadLengthHdr.c_str(), PayloadLengthHdr.length());
      pCurr += PayloadLengthHdr.length();
      memcpy(pCurr, payloadLengthValue.c_str(), payloadLengthValue.length());
      pCurr += payloadLengthValue.length();
      memcpy(pCurr, "\r\n\r\n", 4);

      // Success
      retStatus = 0;
   }
   catch (...) {
      DbgTrace(0, "ChannelProto::buildReqDataPktHdr- Exception caught while creating header\n", 0);
   }

   DbgTrace(1, "ChannelProto::buildReqDataPktHdr- End, retStatus = %08X\n", retStatus);

   return retStatus;

}  /*-- ChannelProto::buildReqDataPktHdr() --*/


//++=======================================================================
int
ChannelProto::buildReqErrorPktHdr(
   uint32_t reqId,
   int32_t payloadLength,
   char *pPktHdr)
//
//  Arguments: 
//
//  Returns:   
//
//  Abstract:  
//
//  Notes:
//
// L2
//=======================================================================--
{
   int   retStatus = -1;

   DbgTrace(1, "ChannelProto::buildReqErrorPktHdr- Start\n", 0);

   try {
      // - Req Error Packet Header Format -
      //
      // ReqErrorCarrierType
      // ReqIdHdr value (value format=%08X)
      // PayloadLengthHdr value (value format=%08X)
      //

      // Setup the necessary value strings
      char wrkBuffer[10];

      sprintf(wrkBuffer, "%08X", reqId);
      string reqIdValue = wrkBuffer;
      sprintf(wrkBuffer, "%08X", payloadLength);
      string payloadLengthValue = wrkBuffer;

      // Format the header.
      char* pCurr = pPktHdr;

      memcpy(pCurr, ReqErrorCarrierType.c_str(), ReqErrorCarrierType.length());
      pCurr += ReqErrorCarrierType.length();
      memcpy(pCurr, "\r\n", 2);
      pCurr += 2;

      memcpy(pCurr, ReqIdHdr.c_str(), ReqIdHdr.length());
      pCurr += ReqIdHdr.length();
      memcpy(pCurr, reqIdValue.c_str(), reqIdValue.length());
      pCurr += reqIdValue.length();
      memcpy(pCurr, "\r\n", 2);
      pCurr += 2;

      memcpy(pCurr, PayloadLengthHdr.c_str(), PayloadLengthHdr.length());
      pCurr += PayloadLengthHdr.length();
      memcpy(pCurr, payloadLengthValue.c_str(), payloadLengthValue.length());
      pCurr += payloadLengthValue.length();
      memcpy(pCurr, "\r\n\r\n", 4);

      // Success
      retStatus = 0;
   }
   catch (...) {
      DbgTrace(0, "ChannelProto::buildReqErrorPktHdr- Exception caught while creating header\n", 0);
   }

   DbgTrace(1, "ChannelProto::buildReqErrorPktHdr- End, retStatus = %08X\n", retStatus);

   return retStatus;

}  /*-- ChannelProto::buildReqErrorPktHdr() --*/


//++=======================================================================
ChannelProto::PacketTypes
ChannelProto::getPktType(
   char &buff)
//
//  Arguments: 
//
//  Returns:   
//
//  Abstract:  
//
//  Notes:
//
// L2
//=======================================================================--
{
   PacketTypes packetType = UnknownPacketType;

   DbgTrace(1, "ChannelProto::getPktType- Start\n", 0);

   // Find the end of the Channel Packet Type
   char *pCurr = &buff;
   while (*pCurr != '\r')
      pCurr ++;

   // Found the end of the Channel Packet Type, now
   // calculate its length.
   int channelPktTypeLength = pCurr - &buff;

   // Now start comparing
   if (channelPktTypeLength == ReqDataCarrierType.length()
       && !memcmp(&buff, ReqDataCarrierType.c_str(), channelPktTypeLength))
   {
      // The type is Channel Req Data Carrier
      packetType = ReqDataCarrierPacketType;
   }
   else if (channelPktTypeLength == ReqErrorCarrierType.length()
            && !memcmp(&buff, ReqErrorCarrierType.c_str(), channelPktTypeLength))
   {
      // The type is Channel Req Error Carrier
      packetType = ReqErrorCarrierPacketType;
   }
   else
   {
      DbgTrace(0, "ChannelProto::getPktType- No match found\n", 0);
   }

   DbgTrace(1, "ChannelProto::getPktType- End, type = %d\n", packetType);

   return packetType;

}  /*-- ChannelProto::getPktType() --*/


//++=======================================================================
bool
ChannelProto::getReqIdAndPayloadLength(
   char *pBuff,
   int hdrLength,
   uint32_t *pReqId,
   int32_t *pPayloadLength)
//
//  Arguments: 
//
//  Returns:   
//
//  Abstract:  
//
//  Notes:
//
// L2
//=======================================================================--
{
   bool  reqIdObtained = false;
   bool  payloadLengthObtained = false;

   DbgTrace(1, "ChannelProto::getReqIdAndPayloadLength- Start\n", 0);

   char *pCurr = pBuff;
   char *pChannelHdr = NULL;
   int bytesLeft = hdrLength;

   // Skip the Channel Packet Type
   while (bytesLeft >= 2)
   {
      if (*pCurr == '\r'
          && *(pCurr+1) == '\n')
      {
         // Found the end of the channel packet type
         pCurr += 2;
         bytesLeft -= 2;
         break;
      }
      else
      {
         pCurr ++;
         bytesLeft --;
      }
   }

   // Start processing Channel Packet Headers
   pChannelHdr = pCurr;
   while (bytesLeft >= 2
          && (!reqIdObtained || !payloadLengthObtained))
   {
      if (*pCurr == '\r'
          && *(pCurr+1) == '\n')
      {
         // Found the end of the current channel header
         pCurr += 2;
         bytesLeft -= 2;

         // Check if the line is empty or if it contained a
         // channel header.
         if ((pCurr - pChannelHdr) == 2)
         {
            // This was an empty line, which means that
            // we reached the end of the channel packet header.
            break;
         }
         else
         {
            // Check if the header is the Req Id Hdr
            if (!reqIdObtained && (pCurr - pChannelHdr) > ReqIdHdr.length()
                && !memcmp(pChannelHdr, ReqIdHdr.c_str(), ReqIdHdr.length()))
            {
               // We found the Req Id Hdr, get the value.
               char *pValue = pChannelHdr + ReqIdHdr.length();

               // Temporarily NULL terminate the value
               *(pCurr-2) = '\0';

               // Convert the value to hex
               *pReqId = strtoul(pValue, NULL, 16);

               // Undo the damage that we did
               *(pCurr-2) = '\r';

               // Remember that the Req Id was obtained
               reqIdObtained = true;
            }
            // Check if the header is the Payload Length Hdr
            else if ((pCurr - pChannelHdr) > PayloadLengthHdr.length()
                     && !memcmp(pChannelHdr, PayloadLengthHdr.c_str(), PayloadLengthHdr.length()))
            {
               // We found the Payload Length Hdr, get the value.
               char *pValue = pChannelHdr + PayloadLengthHdr.length();

               // Temporarily NULL terminate the value
               *(pCurr-2) = '\0';

               // Convert the value to hex
               *pPayloadLength = strtoul(pValue, NULL, 16);

               // Undo the damage that we did
               *(pCurr-2) = '\r';

               // Remember that the Payload Lenght was obtained
               payloadLengthObtained = true;
            }

            // Get set to process the next header
            pChannelHdr = pCurr;
         }
      }
      else
      {
         pCurr ++;
         bytesLeft --;
      }
   }

   DbgTrace(1,
            "ChannelProto::getReqIdAndPayloadLength- End, retStatus = %08X\n",
            reqIdObtained && payloadLengthObtained);

   return reqIdObtained && payloadLengthObtained;

}  /*-- ChannelProto::getReqIdAndPayloadLength() --*/


//=========================================================================
//=========================================================================