XRootD
XrdSutBuffer.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d S u t B u f f e r . c c */
4 /* */
5 /* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University */
6 /* Produced by Gerri Ganis for CERN */
7 /* */
8 /* This file is part of the XRootD software suite. */
9 /* */
10 /* XRootD is free software: you can redistribute it and/or modify it under */
11 /* the terms of the GNU Lesser General Public License as published by the */
12 /* Free Software Foundation, either version 3 of the License, or (at your */
13 /* option) any later version. */
14 /* */
15 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
16 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
17 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
18 /* License for more details. */
19 /* */
20 /* You should have received a copy of the GNU Lesser General Public License */
21 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
22 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
23 /* */
24 /* The copyright holder's institutional names and contributor's names may not */
25 /* be used to endorse or promote products derived from this software without */
26 /* specific prior written permission of the institution or contributor. */
27 /******************************************************************************/
28 
29 #include <cinttypes>
30 #include <cstdio>
31 #include <cstring>
32 #include <cerrno>
33 #include <netinet/in.h>
34 #include <sys/types.h>
35 
37 #include "XrdOuc/XrdOucString.hh"
38 #include "XrdSut/XrdSutBuffer.hh"
39 #include "XrdSut/XrdSutTrace.hh"
40 
41 /******************************************************************************/
42 /* */
43 /* Buffer structure for managing exchanged buckets */
44 /* */
45 /******************************************************************************/
46 
47 //_____________________________________________________________________________
49 {
50  // Constructor from compact form (used for exchange over the network)
51  // If the buffer begins with "&P=", then only the protocol name and
52  // options are extracted, assuming the format "&P=<protocol>,<options>".
53  // Otherwise the format "<protocol><step><bucket_1>...<bucket_n>" is
54  // assumed
55  EPNAME("Buffer::XrdSutBuffer");
56 
57  bool ok = 1;
58 
59  // Default initialization
60  fOptions = "";
61  fProtocol = "";
62  fStep = 0;
63 
64  //
65  // Check type of buffer
66  if (!strncmp(buf,"&P=",3)) {
67  //
68  // Initial buffer format
69  // Extract protocol name and options
70  int cur = 3;
71  int k = 0;
72  while (buf[cur+k] && buf[cur+k] != ',' &&
73  k < XrdSecPROTOIDSIZE && (cur+k) < len) k++;
74  if (!k) {
75  PRINT("no protocol name - do nothing");
76  } else {
77  //
78  // Extract protocol name
79  char proto[XrdSecPROTOIDSIZE];
80  strncpy(proto,buf+cur,k);
81  proto[(k >= XrdSecPROTOIDSIZE ? XrdSecPROTOIDSIZE-1:k)]=0; // null-terminated
82  fProtocol = proto;
83  cur += (k+1);
84  //
85  // Extract options, if any
86  if (cur < len) {
87  k = 0;
88  while ((cur+k) < len && buf[cur+k])
89  k++;
90  if (k) {
91  char *opts = new char[k+1];
92  if (opts) {
93  strncpy(opts,buf+cur,k);
94  opts[k] = 0; // null-terminated
95  fOptions = opts;
96  delete[] opts;
97  }
98  }
99  cur += (k+1);
100  }
101  }
102 
103  } else {
104  //
105  // Assume exchange info format
106  // Check integrity
107  int k = 0;
108  while ( k < XrdSecPROTOIDSIZE && k < len && buf[k]) { k++; }
109  if (!k || k == XrdSecPROTOIDSIZE) {
110  PRINT("no protocol name: do nothing");
111  ok = 0;
112  }
113  int cur = k+1;
114  if (ok) {
115  //
116  // Extract protocol name
117  char proto[XrdSecPROTOIDSIZE];
118  strcpy(proto,buf);
119  fProtocol = proto;
120 
121  //
122  // Step/Iteration number
123  kXR_int32 step;
124  memcpy(&step,&buf[cur],sizeof(kXR_int32));
125  fStep = ntohl(step);
126  cur += sizeof(kXR_int32);
127  }
128 
129  //
130  // Total length of buckets (sizes+buffers) (excluded trailing 0)
131  int ltot = len - sizeof(kXR_int32);
132  TRACE(Dump,"ltot: " <<ltot);
133 
134  //
135  // Now the buckets
136  kXR_int32 type;
137  kXR_int32 blen;
138  XrdSutBucket *tmp = 0;
139  char *buck = 0;
140  while (ok) {
141 
142  //
143  // Get type
144  memcpy(&type,&buf[cur],sizeof(kXR_int32));
145  type = ntohl(type);
146  TRACE(Dump,"type: " <<XrdSutBuckStr(type));
147 
148  if (type == kXRS_none) {
149  //
150  // We are over
151  ok = 0;
152  } else {
153  //
154  cur += sizeof(kXR_int32);
155  //
156  // Get length and test consistency
157  memcpy(&blen,&buf[cur],sizeof(kXR_int32));
158  blen = ntohl(blen);
159  TRACE(Dump,"blen: " <<blen);
160  //
161  cur += sizeof(kXR_int32);
162  TRACE(Dump,"cur: " <<cur);
163  if ((cur-1+blen) > ltot)
164  ok = 0;
165  else {
166  //
167  // Store only active buckets
168  if (type != kXRS_inactive){
169  //
170  // Normal active bucket: save it in the vector
171  if ((buck = new char[blen])) {
172  memcpy(buck,&buf[cur],blen);
173  if ((tmp = new XrdSutBucket(buck,blen,type))) {
174  fBuckets.PushBack(tmp);
175  } else {
176  PRINT("error creating bucket: "<<XrdSutBuckStr(type)
177  <<" (size: "<<blen<<", !buck:"<<(!buck)<<")");
178  }
179  } else {
180  PRINT("error allocating buffer for bucket: "
181  <<XrdSutBuckStr(type)<<" (size:"<<blen<<")");
182  }
183  }
184  cur += blen;
185  }
186  }
187  }
188  }
189 }
190 
191 //_____________________________________________________________________________
193 {
194  // Destructor
195  // XrdSutBuffer is responsible of the buckets in the list
196  EPNAME("Buffer::~XrdSutBuffer");
197 
198  XrdSutBucket *bp = fBuckets.Begin();
199  while (bp) {
200  TRACE(Dump,"type: " << bp->type);
201  delete bp;
202  // Get next bucket
203  bp = fBuckets.Next();
204  }
205 }
206 
207 //_____________________________________________________________________________
208 int XrdSutBuffer::UpdateBucket(const char *b, int sz, int ty)
209 {
210  // Update existing bucket (or add a new bucket to the list)
211  // with sz bytes at 'b'.
212  // Returns 0 or -1 if error allocating bucket
213  EPNAME("Buffer::UpdateBucket");
214 
215  XrdSutBucket *bp = GetBucket(ty);
216  if (!bp) {
217  bp = new XrdSutBucket(0,0,ty);
218  if (!bp) {
219  DEBUG("Out-Of-Memory allocating bucket");
220  return -1;
221  }
222  AddBucket(bp);
223  }
224  bp->SetBuf(b,sz);
225  // Done
226  return 0;
227 }
228 
229 //_____________________________________________________________________________
231 {
232  // Update existing bucket (or add a new bucket to the list)
233  // with string s.
234  // Returns 0 or -1 if error allocating bucket
235 
236  return UpdateBucket(s.c_str(),s.length(),ty);
237 }
238 
239 //_____________________________________________________________________________
240 void XrdSutBuffer::Dump(const char *stepstr, bool all)
241 {
242  // Dump content of buffer. If all is false, only active buckets are dumped;
243  // this is the default behaviour.
244  EPNAME("Buffer::Dump");
245 
246  PRINT("//-----------------------------------------------------//");
247  PRINT("// //")
248  PRINT("// XrdSutBuffer DUMP //")
249  PRINT("// //")
250 
251  int nbuck = fBuckets.Size();
252 
253  PRINT("// Buffer : " <<this);
254  PRINT("// ");
255  PRINT("// Proto : " <<fProtocol.c_str());
256  if (fOptions.length()) {
257  PRINT("// Options : " <<fOptions.c_str());
258  } else {
259  PRINT("// Options : none");
260  }
261  if (stepstr) {
262  PRINT("// Step : " <<stepstr);
263  } else {
264  PRINT("// Step : " <<fStep);
265  }
266  if (!all) {
267  PRINT("// Dumping active buckets only ");
268  } else {
269  PRINT("// # of buckets : " <<nbuck);
270  }
271  PRINT("// ");
272 
273  int kb = 0;
274  XrdSutBucket *bp = fBuckets.Begin();
275  while (bp) {
276  PRINT("// ");
277  if (all || bp->type != kXRS_inactive) {
278  PRINT("// buck: " <<kb++);
279  bp->Dump(0);
280  }
281  // Get next
282  bp = fBuckets.Next();
283  }
284  if (!all) PRINT("// # active buckets found: " << kb);
285  PRINT("// //")
286  PRINT("//-----------------------------------------------------//");
287 }
288 
289 //_____________________________________________________________________________
290 void XrdSutBuffer::Message(const char *prepose)
291 {
292  // Print content of any bucket of type kXRS_message
293  // Prepose 'prepose', if defined
294 
295  bool pripre = 0;
296  if (prepose)
297  pripre = 1;
298 
299  XrdSutBucket *bp = fBuckets.Begin();
300  while (bp) {
301  if (bp->type == kXRS_message) {
302  if (bp->size > 0 && bp->buffer) {
303  if (pripre) {
304  XrdOucString premsg(prepose);
305  std::cerr << premsg << std::endl;
306  pripre = 0;
307  }
308  XrdOucString msg(bp->buffer,bp->size);
309  std::cerr << msg << std::endl;
310  }
311  }
312  // Get next
313  bp = fBuckets.Next();
314  }
315 }
316 
317 //_____________________________________________________________________________
319 {
320  // Search the vector of buckets for the first bucket of
321  // type 'type'. Reset its content and fill it with 'code'
322  // in network byte order. If no bucket 'type' exists, add
323  // a new one.
324  // Returns -1 if new bucket could be allocated; 0 otherwise .
325  EPNAME("Buffer::MarshalBucket");
326 
327  // Convert to network byte order
328  kXR_int32 mcod = htonl(code);
329 
330  // Get the bucket
331  XrdSutBucket *bck = GetBucket(type);
332  if (!bck) {
333  // Allocate a new one
334  bck = new XrdSutBucket(0,0,type);
335  if (!bck) {
336  DEBUG("could not allocate new bucket of type:"<<XrdSutBuckStr(type));
337  errno = ENOMEM;
338  return -1;
339  }
340  // Add it to the list
341  AddBucket(bck);
342  }
343 
344  // Set content
345  bck->SetBuf((char *)(&mcod),sizeof(kXR_int32));
346 
347  // We are done
348  return 0;
349 }
350 
351 //_____________________________________________________________________________
353 {
354  // Search the vector of buckets for the first bucket of
355  // type 'type'. Unmarshalled its content to host byte order
356  // and fill it in code.
357  // Returns 0 if ok.
358  // Returns -1 if no bucket of requested 'type' could be
359  // found; -2 if the bucket size is inconsistent.
360  EPNAME("Buffer::UnmarshalBucket");
361 
362  code = 0;
363  // Get the bucket
364  XrdSutBucket *bck = GetBucket(type);
365  if (!bck) {
366  DEBUG("could not find a bucket of type:"<<XrdSutBuckStr(type));
367  errno = ENOENT;
368  return -1;
369  }
370  if (bck->size != sizeof(kXR_int32)) {
371  DEBUG("Wrong size: type:"<<XrdSutBuckStr(type)
372  <<", size:"<<bck->size<<", expected:"<<sizeof(kXR_int32));
373  errno = EINVAL;
374  return -2;
375  }
376  //
377  // Get the content
378  memcpy(&code,bck->buffer,sizeof(kXR_int32));
379  //
380  // Unmarshal
381  code = ntohl(code);
382 
383  // We are done
384  return 0;
385 }
386 
387 //_____________________________________________________________________________
389 {
390  // Search the vector of buckets for the first bucket of
391  // type 'type'.
392  // If tag is defined, search buckets whose buffer contains tag
393  // in the form <tag>'\0'<rest_of_buffer>.
394  // Returns the pointer to the buffer; 0 if the no bucket
395  // is found
396 
397  //
398  // Check tag, if any
399  int ltag = (tag) ? strlen(tag) : 0;
400  //
401  // Loop over buckets
402  XrdSutBucket *bp = fBuckets.Begin();
403  while (bp) {
404  if (type == bp->type && (!tag || (ltag < bp->size &&
405  !strncmp(bp->buffer,tag,ltag) &&
406  (bp->buffer)[ltag] == '\0')))
407  return bp;
408  // Get next
409  bp = fBuckets.Next();
410  }
411 
412  // Nothing found
413  return 0;
414 }
415 
416 //_____________________________________________________________________________
418 {
419  // Deactivate first bucket of type 'type', if any
420  // If type == -1, deactivate all buckets (cleanup)
421 
422  //
423  // Loop over buckets
424  XrdSutBucket *bp = fBuckets.Begin();
425  while (bp) {
426  if (type == bp->type) {
427  bp->type = kXRS_inactive;
428  break;
429  } else if (type == -1) {
430  bp->type = kXRS_inactive;
431  }
432  // Get next
433  bp = fBuckets.Next();
434  }
435 }
436 
437 //_____________________________________________________________________________
438 int XrdSutBuffer::Serialized(char **buffer, char opt)
439 {
440  // Serialize the content in a form suited for exchange
441  // over the net; the result is saved in '*buffer', which
442  // must be deleted (opt = 'n', default) or freed (opt == 'm') by the caller.
443  // Returns the length of the buffer in case of success.
444  // Returns -1 in case of problems allocating the buffer.
445  EPNAME("Buffer::Serialized");
446 
447  //
448  // Check that we got a valid argument
449  if (!buffer) {
450  DEBUG("invalid input argument");
451  errno = EINVAL;
452  return -1;
453  }
454 
455  //
456  // Calculate the length of the buffer
457  int blen = fProtocol.length() + 1 + 2*sizeof(kXR_int32);
458  // buckets
459  XrdSutBucket *bp = fBuckets.Begin();
460  while (bp) {
461  if (bp->type != kXRS_inactive) {
462  blen += 2*sizeof(kXR_int32);
463  blen += bp->size;
464  }
465  // Get next
466  bp = fBuckets.Next();
467  }
468 
469  //
470  // Allocate the buffer
471  *buffer = (opt == 'n') ? (new char[blen]) : (char *)malloc(blen);
472  if (!(*buffer))
473  return -1;
474  char *tbuf = *buffer;
475  int cur = 0;
476 
477  //
478  // Add protocol
479  memcpy(tbuf,fProtocol.c_str(),fProtocol.length());
480  tbuf[fProtocol.length()] = 0;
481  cur += fProtocol.length() + 1;
482 
483  //
484  // Add step number
485  kXR_int32 step = htonl(fStep);
486  memcpy(tbuf+cur,&step,sizeof(kXR_int32));
487  cur += sizeof(kXR_int32);
488 
489  //
490  // Add buckets
491  bp = fBuckets.Begin();
492  while (bp) {
493  if (bp->type != kXRS_inactive) {
494  kXR_int32 type = htonl(bp->type);
495  memcpy(tbuf+cur,&type,sizeof(kXR_int32));
496  cur += sizeof(kXR_int32);
497  kXR_int32 size = htonl(bp->size);
498  memcpy(tbuf+cur,&size,sizeof(kXR_int32));
499  cur += sizeof(kXR_int32);
500  memcpy(tbuf+cur,bp->buffer,bp->size);
501  cur += bp->size;
502  }
503  // Get next bucket
504  bp = fBuckets.Next();
505  }
506 
507  //
508  // Add 0 termination
509  kXR_int32 ltmp = htonl(kXRS_none);
510  memcpy(tbuf+cur,&ltmp,sizeof(kXR_int32));
511 
512  // Return total length
513  return blen;
514 }
int kXR_int32
Definition: XPtypes.hh:89
#define DEBUG(x)
Definition: XrdBwmTrace.hh:54
#define EPNAME(x)
Definition: XrdBwmTrace.hh:56
#define PRINT(y)
#define XrdSecPROTOIDSIZE
Definition: XrdSecEntity.hh:47
struct myOpts opts
const char * XrdSutBuckStr(int kbck)
Definition: XrdSutAux.cc:121
@ kXRS_message
Definition: XrdSutAux.hh:68
@ kXRS_inactive
Definition: XrdSutAux.hh:56
@ kXRS_none
Definition: XrdSutAux.hh:55
#define TRACE(act, x)
Definition: XrdTrace.hh:63
const char * c_str() const
int length() const
void PushBack(XrdSutBucket *b)
int Size() const
XrdSutBucket * Next()
XrdSutBucket * Begin()
kXR_int32 type
Definition: XrdSutBucket.hh:46
kXR_int32 size
Definition: XrdSutBucket.hh:47
int SetBuf(const char *nb=0, int ns=0)
void Dump(int opt=1)
int AddBucket(char *bp=0, int sz=0, int ty=0)
Definition: XrdSutBuffer.hh:59
int UpdateBucket(const char *bp, int sz, int ty)
void Message(const char *prepose=0)
int Serialized(char **buffer, char opt='n')
XrdSutBuffer(const char *prot, const char *opts=0)
Definition: XrdSutBuffer.hh:53
void Dump(const char *stepstr=0, bool all=false)
virtual ~XrdSutBuffer()
XrdSutBucket * GetBucket(kXR_int32 type, const char *tag=0)
kXR_int32 MarshalBucket(kXR_int32 type, kXR_int32 code)
void Deactivate(kXR_int32 type)
kXR_int32 UnmarshalBucket(kXR_int32 type, kXR_int32 &code)