XRootD
XrdOucPgrwUtils.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d O u c P g r w U t i l s . c c */
4 /* */
5 /* (c) 2021 by the Board of Trustees of the Leland Stanford, Jr., University */
6 /* All Rights Reserved */
7 /* Produced by Andrew Hanushevsky for Stanford University under contract */
8 /* DE-AC02-76-SFO0515 with the Department of Energy */
9 /* */
10 /* This file is part of the XRootD software suite. */
11 /* */
12 /* XRootD is free software: you can redistribute it and/or modify it under */
13 /* the terms of the GNU Lesser General Public License as published by the */
14 /* Free Software Foundation, either version 3 of the License, or (at your */
15 /* option) any later version. */
16 /* */
17 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
18 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
19 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
20 /* License for more details. */
21 /* */
22 /* You should have received a copy of the GNU Lesser General Public License */
23 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
24 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
25 /* */
26 /* The copyright holder's institutional names and contributor's names may not */
27 /* be used to endorse or promote products derived from this software without */
28 /* specific prior written permission of the institution or contributor. */
29 /******************************************************************************/
30 
31 #include <limits.h>
32 
33 #include "XProtocol/XProtocol.hh"
34 #include "XrdOuc/XrdOucCRC.hh"
36 
37 /******************************************************************************/
38 /* G l o b a l s */
39 /******************************************************************************/
40 
41 namespace
42 {
43 static const int pgPageMask = XrdProto::kXR_pgPageSZ-1;
44 static const int pgPageSize = XrdProto::kXR_pgPageSZ;
45 static const int pgCsumSize = sizeof(uint32_t);
46 static const int pgUnitSize = XrdProto::kXR_pgPageSZ + pgCsumSize;
47 static const int pgMaxBSize = INT_MAX & ~pgPageMask;
48 }
49 
50 /******************************************************************************/
51 /* c s C a l c */
52 /******************************************************************************/
53 
54 void XrdOucPgrwUtils::csCalc(const char* data, off_t offs, size_t count,
55  uint32_t* csval)
56 {
57  int pgOff = offs & pgPageMask;
58 
59 // If this is unaligned, the we must compute the checksum of the leading bytes
60 // to align them to the next page boundary if one exists.
61 //
62  if (pgOff)
63  {size_t chkLen = pgPageSize - pgOff;
64  if (chkLen >= count) {chkLen = count; count = 0;}
65  else count -= chkLen;
66  *csval++ = XrdOucCRC::Calc32C((void *)data, chkLen);
67  data += chkLen;
68  }
69 
70 // Compute the remaining checksums, if any are left
71 //
72  if (count) XrdOucCRC::Calc32C((void *)data, count, csval);
73 }
74 
75 /******************************************************************************/
76 
77 void XrdOucPgrwUtils::csCalc(const char* data, off_t offs, size_t count,
78  std::vector<uint32_t> &csvec)
79 {
80  int pgOff = offs & pgPageMask;
81  int n = XrdOucPgrwUtils::csNum(offs, count);
82 
83 // Size the vector to be of correct size
84 //
85  csvec.resize(n);
86  csvec.assign(n, 0);
87  uint32_t *csval = csvec.data();
88 
89 // If this is unaligned, the we must compute the checksum of the leading bytes
90 // to align them to the next page boundary if one exists.
91 //
92  if (pgOff)
93  {size_t chkLen = pgPageSize - pgOff;
94  if (chkLen >= count) {chkLen = count; count = 0;}
95  else count -= chkLen;
96  *csval++ = XrdOucCRC::Calc32C((void *)data, chkLen);
97  data += chkLen;
98  }
99 
100 // Compute the remaining checksums, if any are left
101 //
102  if (count) XrdOucCRC::Calc32C((void *)data, count, csval);
103 }
104 
105 /******************************************************************************/
106 /* c s N u m */
107 /******************************************************************************/
108 
109 int XrdOucPgrwUtils::csNum(off_t offs, int count)
110 {
111  int k, pgOff = offs & pgPageMask;
112 
113 // Account for unaligned start
114 //
115  if (!pgOff) k = 0;
116  else {int chkLen = pgPageSize - pgOff;
117  if (chkLen >= count) return 1;
118  count -= chkLen;
119  k = 1;
120  }
121 
122 // Return the number of checksum required or will be generated.
123 //
124  return k + count/pgPageSize + ((count & pgPageMask) != 0);
125 }
126 
127 /******************************************************************************/
128 
129 int XrdOucPgrwUtils::csNum(off_t offs, int count, int &fLen, int &lLen)
130 {
131  int pgOff = offs & pgPageMask;
132 
133 // Gaurd against invalid input
134 //
135  if (!count)
136  {fLen = lLen = 0;
137  return 0;
138  }
139 
140 // Account for unaligned start
141 //
142  if (!pgOff) fLen = (pgPageSize <= (int)count ? pgPageSize : count);
143  else {fLen = pgPageSize - pgOff;
144  if (fLen >= count) fLen = count;
145  }
146 
147 // Compute length of last segement and return number of checksums required
148 //
149  count -= fLen;
150  if (count)
151  {pgOff = count & pgPageMask;
152  lLen = (pgOff ? pgOff : pgPageSize);
153  return 1 + count/pgPageSize + (pgOff != 0);
154  }
155 
156 // There is only one checksum and the last length is the same as the first
157 //
158  lLen = fLen;
159  return 1;
160 }
161 
162 /******************************************************************************/
163 /* c s V e r */
164 /******************************************************************************/
165 
166 bool XrdOucPgrwUtils::csVer(dataInfo &dInfo, off_t &bado, int &badc)
167 {
168  int pgOff = dInfo.offs & pgPageMask;
169 
170 // Make sure we have something to do
171 //
172  if (dInfo.count <= 0) return true;
173 
174 // If this is unaligned, the we must verify the checksum of the leading bytes
175 // to align them to the next page boundary if one exists.
176 //
177  if (pgOff)
178  {off_t tempsave;
179  int chkLen = pgPageSize - pgOff;
180  if (dInfo.count < chkLen) {chkLen = dInfo.count; dInfo.count = 0;}
181  else dInfo.count -= chkLen;
182 
183  bool aOK = XrdOucCRC::Ver32C((void *)dInfo.data, chkLen, dInfo.csval[0]);
184 
185  dInfo.data += chkLen;
186  tempsave = dInfo.offs;
187  dInfo.offs += chkLen;
188  dInfo.csval++;
189 
190  if (!aOK)
191  {bado = tempsave;
192  badc = chkLen;
193  return false;
194  }
195  }
196 
197 // Verify the remaining checksums, if any are left (offset is page aligned)
198 //
199  if (dInfo.count > 0)
200  {uint32_t valcs;
201  int pgNum = XrdOucCRC::Ver32C((void *)dInfo.data, dInfo.count,
202  dInfo.csval, valcs);
203  if (pgNum >= 0)
204  {bado = dInfo.offs + (pgPageSize * pgNum);
205  int xlen = (bado - dInfo.offs);
206  dInfo.data += xlen;
207  dInfo.offs += xlen;
208  dInfo.count -= xlen;
209  badc = (dInfo.count <= pgPageSize ? dInfo.count : pgPageSize);
210  dInfo.data += badc;
211  dInfo.offs += badc;
212  dInfo.count -= badc;
213  dInfo.csval += (pgNum+1);
214  return false;
215  }
216  }
217 
218 // All sent well
219 //
220  return true;
221 }
222 
223 /******************************************************************************/
224 /* r e c v L a y o u t */
225 /******************************************************************************/
226 
227 int XrdOucPgrwUtils::recvLayout(Layout &layout, off_t offs, int dlen, int bsz)
228 {
229  int csNum, dataLen, maxLen;
230 
231 // Make sure length is correct
232 //
233  if (dlen <= pgCsumSize)
234  {layout.eWhy = "invalid length";
235  return 0;
236  }
237 
238 // Either validate the bsz or compute a virtual bsz
239 //
240  if (bsz <= 0) bsz = pgMaxBSize;
241  else if (bsz & pgPageMask)
242  {layout.eWhy = "invalid buffer size (logic error)";
243  return 0;
244  }
245 
246 // Compute the data length of this request and set initial buffer pointer. While
247 // the layout should have been verified before we goot here we will return an
248 // error should something be amiss.
249 //
250  dlen -= pgCsumSize;
251  if ((layout.bOffset = offs & pgPageMask))
252  {dataLen = pgPageSize - layout.bOffset;
253  csNum = 1;
254  if (dlen <= dataLen)
255  {dataLen = dlen;
256  maxLen = 0;
257  } else {
258  dlen -= dataLen;
259  maxLen = bsz - pgPageSize;
260  }
261  layout.fLen = dataLen;
262  layout.lLen = 0;
263  } else {
264  if (dlen <= pgPageSize)
265  {dataLen = layout.fLen = dlen;
266  layout.lLen = 0;
267  maxLen = 0;
268  csNum = 1;
269  } else {
270  dlen += pgCsumSize;
271  dataLen = 0;
272  maxLen = bsz;
273  csNum = 0;
274  layout.fLen = pgPageSize;
275  }
276  }
277 
278 // Compute the length without the checksums and the maximum data bytes to read
279 // And the number of checksums we will have.
280 //
281  if (maxLen)
282  {int bytes = dlen / pgUnitSize * pgPageSize;
283  int bfrag = dlen % pgUnitSize;
284  if (bfrag)
285  {if (bfrag <= pgCsumSize)
286  {layout.eWhy = "last page too short";
287  return 0;
288  }
289  bytes += bfrag - pgCsumSize;
290  }
291  if (bytes > maxLen) bytes = maxLen;
292  dataLen += bytes;
293  layout.lLen = bytes & pgPageMask;
294  csNum += bytes/pgPageSize + (layout.lLen != 0);
295  if (layout.lLen == 0) layout.lLen = pgPageSize;
296  }
297 
298 // Set layout data bytes and sock bytes and return the number of checksums
299 //
300  layout.dataLen = dataLen;
301  layout.sockLen = dataLen + (csNum * pgCsumSize);
302  layout.eWhy = 0;
303  return csNum;
304 }
305 
306 /******************************************************************************/
307 /* s e n d L a y o u t */
308 /******************************************************************************/
309 
310 int XrdOucPgrwUtils::sendLayout(Layout &layout, off_t offs, int dlen, int bsz)
311 {
312  int csNum, pgOff = offs & pgPageMask;
313 
314 // Make sure length is correct
315 //
316  if (dlen <= 0)
317  {layout.eWhy = "invalid length";
318  return 0;
319  }
320 
321 // Either validate the bsz or compute a virtual bsz
322 //
323  if (bsz <= 0) bsz = pgMaxBSize;
324  else if (bsz & pgPageMask)
325  {layout.eWhy = "invalid buffer size (logic error)";
326  return 0;
327  }
328  layout.eWhy = 0;
329 
330 // Account for unaligned start
331 //
332  if (!pgOff) layout.fLen = (pgPageSize <= dlen ? pgPageSize : dlen);
333  else {layout.fLen = pgPageSize - pgOff;
334  if (layout.fLen > dlen) layout.fLen = dlen;
335  }
336  layout.bOffset = pgOff;
337 
338 // Adjust remaining length and reduce the buffer size as we have effectively
339 // used the first page of the buffer.
340 //
341  bsz -= pgPageSize;
342  dlen -= layout.fLen;
343 
344 // Compute length of last segement and compute number of checksums required
345 //
346  if (dlen && bsz)
347  {if (dlen > bsz) dlen = bsz;
348  if ((pgOff = dlen & pgPageMask)) layout.lLen = pgOff;
349  else layout.lLen = (pgPageSize <= dlen ? pgPageSize : dlen);
350  csNum = 1 + dlen/pgPageSize + (pgOff != 0);
351  layout.dataLen = layout.fLen + dlen;
352  } else {
353  csNum = 1;
354  layout.lLen = 0;
355  layout.dataLen = layout.fLen;
356  }
357 
358 // Set network bytes and return number of checksumss the same as the first
359 //
360  layout.sockLen = layout.dataLen + (csNum * pgCsumSize);
361  return csNum;
362 }
static uint32_t Calc32C(const void *data, size_t count, uint32_t prevcs=0)
Definition: XrdOucCRC.cc:190
static bool Ver32C(const void *data, size_t count, const uint32_t csval, uint32_t *csbad=0)
Definition: XrdOucCRC.cc:222
static void csCalc(const char *data, off_t offs, size_t count, uint32_t *csval)
off_t bOffset
Buffer offset to apply iov[1].iov_base.
int dataLen
Total number of filesys bytes the iovec will handle.
static int sendLayout(Layout &layout, off_t offs, int dlen, int bsz=0)
int fLen
Length to use for iov[1].iov_len.
static bool csVer(dataInfo &dInfo, off_t &bado, int &badc)
int sockLen
Total number of network bytes the iovec will handle.
const char * eWhy
Reason for failure when zero is returned.
static int csNum(off_t offs, int count)
Compute the required size of a checksum vector based on offset & length.
int lLen
Length to use for iov[csnum*2-1].iov_len)
static int recvLayout(Layout &layout, off_t offs, int dlen, int bsz=0)
Compute the layout for an iovec that receives network bytes applying.
static const int kXR_pgPageSZ
Definition: XProtocol.hh:494
const char * data
Pointer to data buffer.
int count
Number of bytes to check.
const uint32_t * csval
Pointer to vector of checksums.
off_t offs
Offset associated with data.