/******************************************************************************/
/* */
/* X r d C l i e n t M e s s a g e . c c */
/* */
/* Author: Fabrizio Furano (INFN Padova, 2004) */
/* Adapted from TXNetFile (root.cern.ch) originally done by */
/* Alvise Dorigo, Fabrizio Furano */
/* INFN Padova, 2003 */
/* */
/* This file is part of the XRootD software suite. */
/* */
/* XRootD 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, either version 3 of the License, or (at your */
/* option) any later version. */
/* */
/* XRootD 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 Lesser General Public */
/* License for more details. */
/* */
/* You should have received a copy of the GNU Lesser General Public License */
/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
/* COPYING (GPL license). If not, see . */
/* */
/* The copyright holder's institutional names and contributor's names may not */
/* be used to endorse or promote products derived from this software without */
/* specific prior written permission of the institution or contributor. */
/******************************************************************************/
//////////////////////////////////////////////////////////////////////////
// //
// A message coming from a physical connection. I.e. a server response //
// or some kind of error //
// //
//////////////////////////////////////////////////////////////////////////
#include "XrdClient/XrdClientMessage.hh"
#include "XrdClient/XrdClientProtocol.hh"
#include "XrdClient/XrdClientDebug.hh"
#include "XrdClient/XrdClientPhyConnection.hh"
#include "XrdSys/XrdSysPlatform.hh"
#include // for malloc
#include // for memcpy
//__________________________________________________________________________
XrdClientMessage::XrdClientMessage(struct ServerResponseHeader header)
{
// Constructor
fStatusCode = kXrdMSC_ok;
memcpy((void *)&fHdr, (const void*)&header, sizeof(ServerResponseHeader));
fData = 0;
fMarshalled = false;
if (!CreateData()) {
Error("XrdClientMessage",
"Error allocating " << fHdr.dlen << " bytes.");
fAllocated = false;
} else
fAllocated = true;
}
//__________________________________________________________________________
XrdClientMessage::XrdClientMessage()
{
// Default constructor
memset(&fHdr, 0, sizeof(fHdr));
fStatusCode = kXrdMSC_ok;
fData = 0;
fMarshalled = false;
fAllocated = false;
}
//__________________________________________________________________________
XrdClientMessage::~XrdClientMessage()
{
// Destructor
if (fData)
free(fData);
}
//__________________________________________________________________________
void *XrdClientMessage::DonateData()
{
// Unlink the owned data in order to pass them elsewhere
void *res = fData;
fData = 0;
fAllocated = false;
return (res);
}
//__________________________________________________________________________
bool XrdClientMessage::CreateData()
{
// Allocate data
if (!fAllocated) {
if (fHdr.dlen > 0) {
long pgsz = sysconf(_SC_PAGESIZE);
int memtrbl = 0;
if ((pgsz > 0) && (fHdr.dlen+1 > pgsz))
memtrbl = posix_memalign(&fData, pgsz, fHdr.dlen+1);
else
fData = malloc(fHdr.dlen+1);
if (!fData || memtrbl) {
Error("XrdClientMessage::CreateData",
"Fatal ERROR *** memory allocation alloc of " <<
fHdr.dlen+1 << " bytes failed."
" Probable system resources exhausted.");
return FALSE;
}
char *tmpPtr = (char *)fData;
// Useful to get always 0-terminated strings
tmpPtr[fHdr.dlen] = '\0';
}
if (!fData)
return FALSE;
else
return TRUE;
} else
return TRUE;
}
//__________________________________________________________________________
void XrdClientMessage::Marshall()
{
// Marshall, i.e. put in network byte order
if (!fMarshalled) {
ServerResponseHeader2NetFmt(&fHdr);
fMarshalled = TRUE;
}
}
//__________________________________________________________________________
void XrdClientMessage::Unmarshall()
{
// Unmarshall, i.e. from network byte to normal order
if (fMarshalled) {
clientUnmarshall(&fHdr);
fMarshalled = FALSE;
}
}
//__________________________________________________________________________
int XrdClientMessage::ReadRaw(XrdClientPhyConnection *phy)
{
// Given a physical connection, we completely build the content
// of the message, reading it from the socket of a phyconn
int readres;
int readLen = sizeof(ServerResponseHeader);
int usedsubstreamid = 0;
phy->ReadLock();
Info(XrdClientDebug::kDUMPDEBUG,
"XrdClientMessage::ReadRaw",
"Reading header (" << readLen << " bytes).");
// Read a header from any substream and report it
readres = phy->ReadRaw((void *)&fHdr, readLen, -1, &usedsubstreamid);
if (readres == readLen) phy->PauseSelectOnSubstream(usedsubstreamid);
phy->ReadUnLock();
if (readres != readLen) {
if (readres == TXSOCK_ERR_TIMEOUT)
SetStatusCode(kXrdMSC_timeout);
else {
Info(XrdClientDebug::kNODEBUG,"XrdClientMessage::ReadRaw",
"Failed to read header (" << readLen << " bytes).");
SetStatusCode(kXrdMSC_readerr);
}
memset(&fHdr, 0, sizeof(fHdr));
}
// the data arrive marshalled from the server (i.e. network byte order)
SetMarshalled(TRUE);
Unmarshall();
Info(XrdClientDebug::kDUMPDEBUG,
"XrdClientMessage::ReadRaw"," sid: "< 0) {
Info(XrdClientDebug::kDUMPDEBUG,
"XrdClientMessage::ReadRaw",
"Reading data (" << fHdr.dlen << " bytes) from substream " << usedsubstreamid);
if (!CreateData()) {
Info(XrdClientDebug::kNODEBUG,"XrdClientMessage::ReadRaw",
"Failed to create data (" << fHdr.dlen << " bytes) from substream " <<
usedsubstreamid << ".");
SetStatusCode(kXrdMSC_timeout);
memset(&fHdr, 0, sizeof(fHdr));
} else if (phy->ReadRaw(fData, fHdr.dlen, usedsubstreamid) != fHdr.dlen) {
Info(XrdClientDebug::kNODEBUG,"XrdClientMessage::ReadRaw",
"Failed to read data (" << fHdr.dlen << " bytes) from substream " <<
usedsubstreamid << ".");
free( DonateData() );
if (readres == TXSOCK_ERR_TIMEOUT)
SetStatusCode(kXrdMSC_timeout);
else
SetStatusCode(kXrdMSC_readerr);
memset(&fHdr, 0, sizeof(fHdr));
}
}
phy->RestartSelectOnSubstream(usedsubstreamid);
// phy->ReadUnLock();
return 1;
}
//___________________________________________________________________________
void XrdClientMessage::Int2CharStreamid(kXR_char *charstreamid, short 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));
}
//___________________________________________________________________________
kXR_unt16 XrdClientMessage::CharStreamid2Int(kXR_char *charstreamid)
{
// Converts a streamid given as an integer to its representation
// suitable for the streamid inside the messages (i.e. ascii)
kXR_unt16 res = *((short *)charstreamid);
return res;
}