    // @(#)root/netx:$Name:  $:$Id: TXMessage.cxx,v 1.4 2004/12/16 19:23:18 rdm Exp $
    // Author: Alvise Dorigo, Fabrizio Furano

    /*************************************************************************
     * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers.               *
     * All rights reserved.                                                  *
     *                                                                       *
     * For the licensing terms see $ROOTSYS/LICENSE.                         *
     * For the list of contributors see $ROOTSYS/README/CREDITS.             *
     *************************************************************************/

    //////////////////////////////////////////////////////////////////////////
    //                                                                      //
    // TXMessage                                                            //
    //                                                                      //
    // Class to handle messages to/from xrootd.                             //
    //                                                                      //
    //////////////////////////////////////////////////////////////////////////

    #include "TXMessage.h"
    #include "TXPhyConnection.h"
    #include "TXProtocol.h"
    #include "TError.h"
    #include "TXDebug.h"

    ClassImp(TXMessage);

    //__________________________________________________________________________
     TXMessage::TXMessage(struct ServerResponseHeader header)
    {
       // Constructor

       fStatusCode = kXMSC_ok;
       memcpy((void *)&fHdr, (const void*)&header, sizeof(ServerResponseHeader));
       fData = 0;
       fMarshalled = false;
       if (!CreateData()) {
          Error("TXMessage",
                "Error allocating %d bytes for this TXMessage", fHdr.dlen);
          fAllocated = false;
       } else
          fAllocated = true;
    }

    //__________________________________________________________________________
     TXMessage::TXMessage()
    {
       // Default constructor

       memset(&fHdr, 0, sizeof(fHdr));
       fStatusCode = kXMSC_ok;
       fData = 0;
       fMarshalled = false;
       fAllocated = false;
    }

    //__________________________________________________________________________
     TXMessage::~TXMessage()
    {
       // Destructor

       if (fData)
          free(fData);
    }

    //__________________________________________________________________________
     void *TXMessage::DonateData()
    {
       // Unlink the owned data in order to pass them elsewhere

       void *res = fData;
       fData = 0;
       fAllocated = false;

       return (res);
    }

    //__________________________________________________________________________
     Bool_t TXMessage::CreateData()
    {
       // Allocate data

       if (!fAllocated) {
          if (fHdr.dlen) {
             fData = malloc(fHdr.dlen+1);
             if (!fData) {
                Error("TXMessage::CreateData","Fatal ERROR *** malloc failed."
                      " Probable system resources exhausted.");
                gSystem->Abort();
             }
             char *tmpPtr = (char *)fData;
             memset((void*)(tmpPtr+fHdr.dlen), 0, 1);
          }
          if (!fData)
             return kFALSE;
          else
             return kTRUE;
       } else
          return kTRUE;
    }

    //__________________________________________________________________________
     void TXMessage::Marshall()
    {
       // Marshall, i.e. put in network byte order

       if (!fMarshalled) {
          ROOT::ServerResponseHeader2NetFmt(&fHdr);
          fMarshalled = kTRUE;
       }
    }

    //__________________________________________________________________________
     void TXMessage::Unmarshall()
    {
       // Unmarshall, i.e. from network byte to normal order

       if (fMarshalled) {
          ROOT::clientUnmarshall(&fHdr);
          fMarshalled = kFALSE;
       }
    }

    //__________________________________________________________________________
     Int_t TXMessage::ReadRaw(TXPhyConnection *phy, ESendRecvOptions opt)
    {
       // Given a physical connection, we completely build the content
       // of the message, reading it from the socket of a phyconn

       Int_t bytesread;
       int readLen = sizeof(ServerResponseHeader);

       if (DebugLevel() >= kDUMPDEBUG)
          Info("TXMessage::ReadRaw", "Reading header (%d bytes) from socket.",
     	   readLen);

       bytesread = phy->ReadRaw((void *)&fHdr, readLen, opt);
       if (bytesread < readLen) {
          if (bytesread == TXSOCK_ERR_TIMEOUT)
             SetStatusCode(kXMSC_timeout);
          else {
             if (!(phy->ReaderThreadKilled())) {
                Error("TXMessage::ReadRaw", "Error reading %d bytes", readLen);
                SetStatusCode(kXMSC_readerr);
             } else
                // It is like a timeout
                SetStatusCode(kXMSC_timeout);
          }
          memset(&fHdr, 0, sizeof(fHdr));
          return 1;
       }

       // the data arrive marshalled from the server (i.e. network byte order)
       SetMarshalled(kTRUE);
       Unmarshall();

       if (fHdr.dlen) {
          if (DebugLevel() >= kDUMPDEBUG)
             Info("TXMessage::ReadRaw", "Reading data (%d bytes) from socket.",
                  fHdr.dlen);
          CreateData();
          if (phy->ReadRaw(fData, fHdr.dlen, opt) < fHdr.dlen) {
             if (!(phy->ReaderThreadKilled())) {
                Error("TXMessage::ReadRaw", "Error reading %d bytes.", fHdr.dlen);
                SetStatusCode(kXMSC_readerr);
             } else
                // It is like a timeout
                SetStatusCode(kXMSC_timeout);
          }
       }
       return 1;
    }

    //___________________________________________________________________________
     void TXMessage::Int2CharStreamid(kXR_char *charstreamid, Short_t intstreamid)
    {
       // Converts a streamid given as an integer to its representation
       // suitable for the streamid inside the messages (i.e. ascii)

       memcpy(charstreamid, &intstreamid, sizeof(intstreamid));
    }

    //___________________________________________________________________________
     Short_t TXMessage::CharStreamid2Int(kXR_char *charstreamid)
    {
       // Converts a streamid given as an integer to its representation
       // suitable for the streamid inside the messages (i.e. ascii)

       Int_t res = *((Short_t *)charstreamid);

       return res;
    }