XRootD
Loading...
Searching...
No Matches
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
34#include "XrdOuc/XrdOucCRC.hh"
36
37/******************************************************************************/
38/* G l o b a l s */
39/******************************************************************************/
40
41namespace
42{
43static const int pgPageMask = XrdProto::kXR_pgPageSZ-1;
44static const int pgPageSize = XrdProto::kXR_pgPageSZ;
45static const int pgCsumSize = sizeof(uint32_t);
46static const int pgUnitSize = XrdProto::kXR_pgPageSZ + pgCsumSize;
47static const int pgMaxBSize = INT_MAX & ~pgPageMask;
48}
49
50/******************************************************************************/
51/* c s C a l c */
52/******************************************************************************/
53
54void 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
77void 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
109int 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
129int 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
166bool 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
227int 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
310int 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.