/******************************************************************************/
/* */
/* X r d S u t B u f f e r . c c */
/* */
/* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University */
/* Produced by Gerri Ganis for CERN */
/* */
/* 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. */
/******************************************************************************/
#include
#include
#include
#include
#include
#include
#include "XrdSec/XrdSecInterface.hh"
#include "XrdOuc/XrdOucString.hh"
#include "XrdSut/XrdSutBuffer.hh"
#include "XrdSut/XrdSutTrace.hh"
/******************************************************************************/
/* */
/* Buffer structure for managing exchanged buckets */
/* */
/******************************************************************************/
//_____________________________________________________________________________
XrdSutBuffer::XrdSutBuffer(const char *buf, kXR_int32 len)
{
// Constructor from compact form (used for exchange over the network)
// If the buffer begins with "&P=", then only the protocol name and
// options are extracted, assuming the format "&P=,".
// Otherwise the format "..." is
// assumed
EPNAME("Buffer::XrdSutBuffer");
bool ok = 1;
// Default initialization
fOptions = "";
fProtocol = "";
fStep = 0;
//
// Check type of buffer
if (!strncmp(buf,"&P=",3)) {
//
// Initial buffer format
// Extract protocol name and options
int cur = 3;
int k = 0;
while (buf[cur+k] && buf[cur+k] != ',' &&
k < XrdSecPROTOIDSIZE && (cur+k) < len) k++;
if (!k) {
PRINT("no protocol name - do nothing");
} else {
//
// Extract protocol name
char proto[XrdSecPROTOIDSIZE];
strncpy(proto,buf+cur,k);
proto[(k >= XrdSecPROTOIDSIZE ? XrdSecPROTOIDSIZE-1:k)]=0; // null-terminated
fProtocol = proto;
cur += (k+1);
//
// Extract options, if any
if (cur < len) {
k = 0;
while ((cur+k) < len && buf[cur+k])
k++;
if (k) {
char *opts = new char[k+1];
if (opts) {
strncpy(opts,buf+cur,k);
opts[k] = 0; // null-terminated
fOptions = opts;
delete[] opts;
}
}
cur += (k+1);
}
}
} else {
//
// Assume exchange info format
// Check integrity
int k = 0;
while ( k < XrdSecPROTOIDSIZE && k < len && buf[k]) { k++; }
if (!k || k == XrdSecPROTOIDSIZE) {
PRINT("no protocol name: do nothing");
ok = 0;
}
int cur = k+1;
if (ok) {
//
// Extract protocol name
char proto[XrdSecPROTOIDSIZE];
strcpy(proto,buf);
fProtocol = proto;
//
// Step/Iteration number
kXR_int32 step;
memcpy(&step,&buf[cur],sizeof(kXR_int32));
fStep = ntohl(step);
cur += sizeof(kXR_int32);
}
//
// Total length of buckets (sizes+buffers) (excluded trailing 0)
int ltot = len - sizeof(kXR_int32);
TRACE(Dump,"ltot: " < ltot)
ok = 0;
else {
//
// Store only active buckets
if (type != kXRS_inactive){
//
// Normal active bucket: save it in the vector
if ((buck = new char[blen])) {
memcpy(buck,&buf[cur],blen);
if ((tmp = new XrdSutBucket(buck,blen,type))) {
fBuckets.PushBack(tmp);
} else {
PRINT("error creating bucket: "<type);
delete bp;
// Get next bucket
bp = fBuckets.Next();
}
}
//_____________________________________________________________________________
int XrdSutBuffer::UpdateBucket(const char *b, int sz, int ty)
{
// Update existing bucket (or add a new bucket to the list)
// with sz bytes at 'b'.
// Returns 0 or -1 if error allocating bucket
EPNAME("Buffer::UpdateBucket");
XrdSutBucket *bp = GetBucket(ty);
if (!bp) {
bp = new XrdSutBucket(0,0,ty);
if (!bp) {
DEBUG("Out-Of-Memory allocating bucket");
return -1;
}
AddBucket(bp);
}
bp->SetBuf(b,sz);
// Done
return 0;
}
//_____________________________________________________________________________
int XrdSutBuffer::UpdateBucket(XrdOucString s, int ty)
{
// Update existing bucket (or add a new bucket to the list)
// with string s.
// Returns 0 or -1 if error allocating bucket
return UpdateBucket(s.c_str(),s.length(),ty);
}
//_____________________________________________________________________________
void XrdSutBuffer::Dump(const char *stepstr, bool all)
{
// Dump content of buffer. If all is false, only active buckets are dumped;
// this is the default behaviour.
EPNAME("Buffer::Dump");
PRINT("//-----------------------------------------------------//");
PRINT("// //")
PRINT("// XrdSutBuffer DUMP //")
PRINT("// //")
int nbuck = fBuckets.Size();
PRINT("// Buffer : " <type != kXRS_inactive) {
PRINT("// buck: " <Dump(0);
}
// Get next
bp = fBuckets.Next();
}
if (!all) PRINT("// # active buckets found: " << kb);
PRINT("// //")
PRINT("//-----------------------------------------------------//");
}
//_____________________________________________________________________________
void XrdSutBuffer::Message(const char *prepose)
{
// Print content of any bucket of type kXRS_message
// Prepose 'prepose', if defined
bool pripre = 0;
if (prepose)
pripre = 1;
XrdSutBucket *bp = fBuckets.Begin();
while (bp) {
if (bp->type == kXRS_message) {
if (bp->size > 0 && bp->buffer) {
if (pripre) {
XrdOucString premsg(prepose);
cerr << premsg << endl;
pripre = 0;
}
XrdOucString msg(bp->buffer,bp->size);
cerr << msg << endl;
}
}
// Get next
bp = fBuckets.Next();
}
}
//_____________________________________________________________________________
kXR_int32 XrdSutBuffer::MarshalBucket(kXR_int32 type, kXR_int32 code)
{
// Search the vector of buckets for the first bucket of
// type 'type'. Reset its content and fill it with 'code'
// in network byte order. If no bucket 'type' exists, add
// a new one.
// Returns -1 if new bucket could be allocated; 0 otherwise .
EPNAME("Buffer::MarshalBucket");
// Convert to network byte order
kXR_int32 mcod = htonl(code);
// Get the bucket
XrdSutBucket *bck = GetBucket(type);
if (!bck) {
// Allocate a new one
bck = new XrdSutBucket(0,0,type);
if (!bck) {
DEBUG("could not allocate new bucket of type:"<SetBuf((char *)(&mcod),sizeof(kXR_int32));
// We are done
return 0;
}
//_____________________________________________________________________________
kXR_int32 XrdSutBuffer::UnmarshalBucket(kXR_int32 type, kXR_int32 &code)
{
// Search the vector of buckets for the first bucket of
// type 'type'. Unmarshalled its content to host byte order
// and fill it in code.
// Returns 0 if ok.
// Returns -1 if no bucket of requested 'type' could be
// found; -2 if the bucket size is inconsistent.
EPNAME("Buffer::UnmarshalBucket");
code = 0;
// Get the bucket
XrdSutBucket *bck = GetBucket(type);
if (!bck) {
DEBUG("could not find a bucket of type:"<size != sizeof(kXR_int32)) {
DEBUG("Wrong size: type:"<size<<", expected:"<buffer,sizeof(kXR_int32));
//
// Unmarshal
code = ntohl(code);
// We are done
return 0;
}
//_____________________________________________________________________________
XrdSutBucket *XrdSutBuffer::GetBucket(kXR_int32 type, const char *tag)
{
// Search the vector of buckets for the first bucket of
// type 'type'.
// If tag is defined, search buckets whose buffer contains tag
// in the form '\0'.
// Returns the pointer to the buffer; 0 if the no bucket
// is found
//
// Check tag, if any
int ltag = (tag) ? strlen(tag) : 0;
//
// Loop over buckets
XrdSutBucket *bp = fBuckets.Begin();
while (bp) {
if (type == bp->type && (!tag || (ltag < bp->size &&
!strncmp(bp->buffer,tag,ltag) &&
(bp->buffer)[ltag] == '\0')))
return bp;
// Get next
bp = fBuckets.Next();
}
// Nothing found
return 0;
}
//_____________________________________________________________________________
void XrdSutBuffer::Deactivate(kXR_int32 type)
{
// Deactivate first bucket of type 'type', if any
// If type == -1, deactivate all buckets (cleanup)
//
// Loop over buckets
XrdSutBucket *bp = fBuckets.Begin();
while (bp) {
if (type == bp->type) {
bp->type = kXRS_inactive;
break;
} else if (type == -1) {
bp->type = kXRS_inactive;
}
// Get next
bp = fBuckets.Next();
}
}
//_____________________________________________________________________________
int XrdSutBuffer::Serialized(char **buffer, char opt)
{
// Serialize the content in a form suited for exchange
// over the net; the result is saved in '*buffer', which
// must be deleted (opt = 'n', default) or freed (opt == 'm') by the caller.
// Returns the length of the buffer in case of success.
// Returns -1 in case of problems allocating the buffer.
EPNAME("Buffer::Serialized");
//
// Check that we got a valid argument
if (!buffer) {
DEBUG("invalid input argument");
errno = EINVAL;
return -1;
}
//
// Calculate the length of the buffer
int blen = fProtocol.length() + 1 + 2*sizeof(kXR_int32);
// buckets
XrdSutBucket *bp = fBuckets.Begin();
while (bp) {
if (bp->type != kXRS_inactive) {
blen += 2*sizeof(kXR_int32);
blen += bp->size;
}
// Get next
bp = fBuckets.Next();
}
//
// Allocate the buffer
*buffer = (opt == 'n') ? (new char[blen]) : (char *)malloc(blen);
if (!(*buffer))
return -1;
char *tbuf = *buffer;
int cur = 0;
//
// Add protocol
memcpy(tbuf,fProtocol.c_str(),fProtocol.length());
tbuf[fProtocol.length()] = 0;
cur += fProtocol.length() + 1;
//
// Add step number
kXR_int32 step = htonl(fStep);
memcpy(tbuf+cur,&step,sizeof(kXR_int32));
cur += sizeof(kXR_int32);
//
// Add buckets
bp = fBuckets.Begin();
while (bp) {
if (bp->type != kXRS_inactive) {
kXR_int32 type = htonl(bp->type);
memcpy(tbuf+cur,&type,sizeof(kXR_int32));
cur += sizeof(kXR_int32);
kXR_int32 size = htonl(bp->size);
memcpy(tbuf+cur,&size,sizeof(kXR_int32));
cur += sizeof(kXR_int32);
memcpy(tbuf+cur,bp->buffer,bp->size);
cur += bp->size;
}
// Get next bucket
bp = fBuckets.Next();
}
//
// Add 0 termination
kXR_int32 ltmp = htonl(kXRS_none);
memcpy(tbuf+cur,<mp,sizeof(kXR_int32));
// Return total length
return blen;
}