XRootD
Loading...
Searching...
No Matches
XrdXrootdResponse.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d X r o o t d R e s p o n s e . c c */
4/* */
5/* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University */
6/* Produced by Andrew Hanushevsky for Stanford University under contract */
7/* DE-AC02-76-SFO0515 with the Department of Energy */
8/* */
9/* This file is part of the XRootD software suite. */
10/* */
11/* XRootD is free software: you can redistribute it and/or modify it under */
12/* the terms of the GNU Lesser General Public License as published by the */
13/* Free Software Foundation, either version 3 of the License, or (at your */
14/* option) any later version. */
15/* */
16/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
17/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
18/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
19/* License for more details. */
20/* */
21/* You should have received a copy of the GNU Lesser General Public License */
22/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
23/* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
24/* */
25/* The copyright holder's institutional names and contributor's names may not */
26/* be used to endorse or promote products derived from this software without */
27/* specific prior written permission of the institution or contributor. */
28/******************************************************************************/
29
30#include <netinet/in.h>
31#include <cinttypes>
32#include <cstdint>
33#include <cstring>
34#include <sys/types.h>
35
36#include "Xrd/XrdLinkCtl.hh"
37#include "XrdOuc/XrdOucCRC.hh"
39#define TRACELINK Link
42
43/******************************************************************************/
44/* G l o b a l s */
45/******************************************************************************/
46
48
49const char *XrdXrootdResponse::TraceID = "Response";
50
51/******************************************************************************/
52/* L o c a l D e f i n e s */
53/******************************************************************************/
54
55
56namespace
57{
58const char *sName[] = {"final ", "partial ", "progress "};
59}
60
61/******************************************************************************/
62/* S e n d */
63/******************************************************************************/
64
66{
67 static kXR_unt16 isOK = static_cast<kXR_unt16>(htons(kXR_ok));
68
69 TRACES(RSP, "sending OK");
70
71 if (Bridge)
72 {if (Bridge->Send(kXR_ok, 0, 0, 0) >= 0) return 0;
73 return Link->setEtext("send failure");
74 }
75
76 Resp.status = isOK;
77 Resp.dlen = 0;
78
79 if (Link->Send((char *)&Resp, sizeof(Resp)) < 0)
80 return Link->setEtext("send failure");
81 return 0;
82}
83
84/******************************************************************************/
85
86int XrdXrootdResponse::Send(const char *msg)
87{
88 static kXR_unt16 isOK = static_cast<kXR_unt16>(htons(kXR_ok));
89
90 TRACES(RSP, "sending OK: " <<msg);
91
92 RespIO[1].iov_base = (caddr_t)msg;
93 RespIO[1].iov_len = strlen(msg)+1;
94
95 if (Bridge)
96 {if (Bridge->Send(kXR_ok,&RespIO[1],1,RespIO[1].iov_len) >= 0) return 0;
97 return Link->setEtext("send failure");
98 }
99
100 Resp.status = isOK;
101 Resp.dlen = static_cast<kXR_int32>(htonl(RespIO[1].iov_len));
102
103 if (Link->Send(RespIO, 2, sizeof(Resp) + RespIO[1].iov_len) < 0)
104 return Link->setEtext("send failure");
105 return 0;
106}
107
108/******************************************************************************/
109
110int XrdXrootdResponse::Send(XResponseType rcode, void *data, int dlen)
111{
112
113 TRACES(RSP, "sending " <<dlen <<" data bytes; status=" <<rcode);
114
115 RespIO[1].iov_base = (caddr_t)data;
116 RespIO[1].iov_len = dlen;
117
118 if (Bridge)
119 {if (Bridge->Send(rcode, &RespIO[1], 1, dlen) >= 0) return 0;
120 return Link->setEtext("send failure");
121 }
122
123 Resp.status = static_cast<kXR_unt16>(htons(rcode));
124 Resp.dlen = static_cast<kXR_int32>(htonl(dlen));
125
126 if (Link->Send(RespIO, 2, sizeof(Resp) + dlen) < 0)
127 return Link->setEtext("send failure");
128 return 0;
129}
130
131/******************************************************************************/
132
134 struct iovec *IOResp,int iornum, int iolen)
135{
136 int i, dlen = 0;
137
138 if (iolen < 0) for (i = 1; i < iornum; i++) dlen += IOResp[i].iov_len;
139 else dlen = iolen;
140 TRACES(RSP, "sending " <<dlen <<" data bytes; status=" <<rcode);
141
142 if (Bridge)
143 {if (Bridge->Send(rcode, &IOResp[1], iornum-1, dlen) >= 0) return 0;
144 return Link->setEtext("send failure");
145 }
146
147 IOResp[0].iov_base = RespIO[0].iov_base;
148 IOResp[0].iov_len = RespIO[0].iov_len;
149 Resp.status = static_cast<kXR_unt16>(htons(rcode));
150 Resp.dlen = static_cast<kXR_int32>(htonl(dlen));
151
152 if (Link->Send(IOResp, iornum, sizeof(Resp) + dlen) < 0)
153 return Link->setEtext("send failure");
154 return 0;
155}
156
157/******************************************************************************/
158
160 const char *data, int dsz)
161{
162 kXR_int32 xbuf = static_cast<kXR_int32>(htonl(info));
163 int dlen;
164
165 RespIO[1].iov_base = (caddr_t)(&xbuf);
166 RespIO[1].iov_len = sizeof(xbuf);
167 RespIO[2].iov_base = (caddr_t)data;
168 RespIO[2].iov_len = dlen = (dsz < 0 ? strlen(data) : dsz);
169
170 TRACES(RSP,"sending " <<(sizeof(xbuf)+dlen) <<" data bytes; status=" <<rcode);
171
172 if (Bridge)
173 {if (Bridge->Send(rcode, &RespIO[1], 2, dlen) >= 0) return 0;
174 return Link->setEtext("send failure");
175 }
176
177 Resp.status = static_cast<kXR_unt16>(htons(rcode));
178 Resp.dlen = static_cast<kXR_int32>(htonl((dlen+sizeof(xbuf))));
179
180 if (Link->Send(RespIO, 3, sizeof(Resp) + dlen + sizeof(xbuf)) < 0)
181 return Link->setEtext("send failure");
182 return 0;
183}
184
185/******************************************************************************/
186
187int XrdXrootdResponse::Send(void *data, int dlen)
188{
189 static kXR_unt16 isOK = static_cast<kXR_unt16>(htons(kXR_ok));
190
191 TRACES(RSP, "sending " <<dlen <<" data bytes");
192
193 RespIO[1].iov_base = (caddr_t)data;
194 RespIO[1].iov_len = dlen;
195
196 if (Bridge)
197 {if (Bridge->Send(kXR_ok, &RespIO[1], 1, dlen) >= 0) return 0;
198 return Link->setEtext("send failure");
199 }
200
201 Resp.status = isOK;
202 Resp.dlen = static_cast<kXR_int32>(htonl(dlen));
203
204 if (Link->Send(RespIO, 2, sizeof(Resp) + dlen) < 0)
205 return Link->setEtext("send failure");
206 return 0;
207}
208
209/******************************************************************************/
210
211int XrdXrootdResponse::Send(struct iovec *IOResp, int iornum, int iolen)
212{
213 static kXR_unt16 isOK = static_cast<kXR_unt16>(htons(kXR_ok));
214 int dlen = 0;
215
216 if (iolen < 0) for (int i = 1; i < iornum; i++) dlen += IOResp[i].iov_len;
217 else dlen = iolen;
218 TRACES(RSP, "sending " <<dlen <<" data bytes; status=0");
219
220
221 if (Bridge)
222 {if (Bridge->Send(kXR_ok, &IOResp[1], iornum-1, dlen) >= 0) return 0;
223 return Link->setEtext("send failure");
224 }
225
226 IOResp[0].iov_base = RespIO[0].iov_base;
227 IOResp[0].iov_len = RespIO[0].iov_len;
228 Resp.status = isOK;
229 Resp.dlen = static_cast<kXR_int32>(htonl(dlen));
230
231 if (Link->Send(IOResp, iornum, sizeof(Resp) + dlen) < 0)
232 return Link->setEtext("send failure");
233 return 0;
234}
235
236/******************************************************************************/
237
238int XrdXrootdResponse::Send(XErrorCode ecode, const char *msg)
239{
240 int dlen;
241 kXR_int32 erc = static_cast<kXR_int32>(htonl(ecode));
242
243 TRACES(EMSG, "sending err " <<ecode <<": " <<msg);
244
245 RespIO[1].iov_base = (char *)&erc;
246 RespIO[1].iov_len = sizeof(erc);
247 RespIO[2].iov_base = (caddr_t)msg;
248 RespIO[2].iov_len = strlen(msg)+1;
249 dlen = sizeof(erc) + RespIO[2].iov_len;
250
251 if (Bridge)
252 {if (Bridge->Send(kXR_error, &RespIO[1], 2, dlen) >= 0) return 0;
253 return Link->setEtext("send failure");
254 }
255
256 Resp.status = static_cast<kXR_unt16>(htons(kXR_error));
257 Resp.dlen = static_cast<kXR_int32>(htonl(dlen));
258
259 if (Link->Send(RespIO, 3, sizeof(Resp) + dlen) < 0)
260 return Link->setEtext("send failure");
261 return 0;
262}
263
264/******************************************************************************/
265
266int XrdXrootdResponse::Send(int fdnum, long long offset, int dlen)
267{
268 static kXR_unt16 isOK = static_cast<kXR_unt16>(htons(kXR_ok));
269 XrdLink::sfVec myVec[2];
270
271 TRACES(RSP, "sendfile " <<dlen <<" data bytes");
272
273 if (Bridge)
274 {if (Bridge->Send(offset, dlen, fdnum) >= 0) return 0;
275 return Link->setEtext("send failure");
276 }
277
278// We are only called should sendfile be enabled for this response
279//
280 Resp.status = isOK;
281 Resp.dlen = static_cast<kXR_int32>(htonl(dlen));
282
283// Fill out the sendfile vector
284//
285 myVec[0].buffer = (char *)&Resp;
286 myVec[0].sendsz = sizeof(Resp);
287 myVec[0].fdnum = -1;
288 myVec[1].offset = static_cast<off_t>(offset);
289 myVec[1].sendsz = dlen;
290 myVec[1].fdnum = fdnum;
291
292// Send off the request
293//
294 if (Link->Send(myVec, 2) < 0)
295 return Link->setEtext("sendfile failure");
296 return 0;
297}
298
299/******************************************************************************/
300
301int XrdXrootdResponse::Send(XrdOucSFVec *sfvec, int sfvnum, int dlen)
302{
303 static kXR_unt16 isOK = static_cast<kXR_unt16>(htons(kXR_ok));
304
305 TRACES(RSP, "sendfile " <<dlen <<" data bytes");
306
307 if (Bridge)
308 {if (Bridge->Send(sfvec, sfvnum, dlen) >= 0) return 0;
309 return Link->setEtext("send failure");
310 }
311
312// We are only called should sendfile be enabled for this response
313//
314 Resp.status = isOK;
315 Resp.dlen = static_cast<kXR_int32>(htonl(dlen));
316 sfvec[0].buffer = (char *)&Resp;
317 sfvec[0].sendsz = sizeof(Resp);
318 sfvec[0].fdnum = -1;
319
320// Send off the request
321//
322 if (Link->Send(sfvec, sfvnum) < 0)
323 return Link->setEtext("sendfile failure");
324 return 0;
325}
326
327/******************************************************************************/
328
330{
331
332// Fill out the status structure and send this off
333//
334 if (Link->Send((char *)&srs, srsComplete(srs, iLen)) < 0)
335 return Link->setEtext("send failure");
336 return 0;
337}
338
339/******************************************************************************/
340
342 void *data, int dlen)
343{
344 int rc;
345
346// Send off the appropriate response
347//
348 if (!dlen) rc = Link->Send((char *)&srs, srsComplete(srs, iLen));
349 else {struct iovec srsIOV[2];
350 srsIOV[0].iov_base = &srs;
351 srsIOV[0].iov_len = srsComplete(srs, iLen, dlen);
352 srsIOV[1].iov_base = (caddr_t)data;
353 srsIOV[1].iov_len = dlen;
354 rc = Link->Send(srsIOV, 2, srsIOV[0].iov_len + dlen);
355 }
356
357// Finish up
358//
359 if (rc < 0) return Link->setEtext("send failure");
360 return 0;
361}
362
363/******************************************************************************/
364
366 struct iovec *IOResp, int iornum, int iolen)
367{
368 int dlen = 0;
369
370// If we need to compute the amount of data we are sending, do so now.
371//
372 if (iolen < 0) for (int i = 1; i < iornum; i++) dlen += IOResp[i].iov_len;
373 else dlen = iolen;
374
375// Fill out the status structure
376//
377 int rspLen = srsComplete(srs, iLen, dlen);
378
379// Complete the iovec for the send
380
381 IOResp[0].iov_base = &srs;
382 IOResp[0].iov_len = rspLen;
383
384// Send the data off
385//
386 if (Link->Send(IOResp, iornum, rspLen + dlen) < 0)
387 return Link->setEtext("send failure");
388 return 0;
389}
390
391/******************************************************************************/
392
394 XResponseType Status,
395 struct iovec *IOResp,
396 int iornum,
397 int iolen)
398{
399 static const kXR_unt16 Xattn = static_cast<kXR_unt16>(htons(kXR_attn));
400 static const kXR_int32 Xarsp = static_cast<kXR_int32>(htonl(kXR_asynresp));
401
402// We would have used struct ServerResponseBody_Attn_asynresp but the silly
403// imbedded 4096 char array causes grief when computing lengths.
404//
405 struct {ServerResponseHeader atnHdr;
406 kXR_int32 act;
407 kXR_int32 rsvd; // Same as char[4]
409 } asynResp;
410
411 static const int sfxLen = sizeof(asynResp) - sizeof(asynResp.atnHdr);
412
413 XrdLink *Link;
414 unsigned char theSID[2];
415 int theFD, rc, ioxlen = iolen;
416 unsigned int theInst;
417
418// Fill out the header with constant information
419//
420 asynResp.atnHdr.streamid[0] = '\0';
421 asynResp.atnHdr.streamid[1] = '\0';
422 asynResp.atnHdr.status = Xattn;
423 asynResp.act = Xarsp;
424 asynResp.rsvd = 0;
425
426// Complete the io vector to send this response
427//
428 IOResp[0].iov_base = (char *)&asynResp;
429 IOResp[0].iov_len = sizeof(asynResp); // 0
430
431// Insert the status code
432//
433 asynResp.theHdr.status = static_cast<kXR_unt16>(htons(Status));
434
435// We now insert the length of the delayed response and the full response
436//
437 asynResp.theHdr.dlen = static_cast<kXR_int32>(htonl(iolen));
438 iolen += sfxLen;
439 asynResp.atnHdr.dlen = static_cast<kXR_int32>(htonl(iolen));
440 iolen += sizeof(ServerResponseHeader);
441
442// Decode the destination
443//
444 ReqID.getID(theSID, theFD, theInst);
445
446// Map the destination to an endpoint, and send the response
447//
448 if ((Link = XrdLinkCtl::fd2link(theFD, theInst)))
449 {Link->setRef(1);
450 if (Link->isInstance(theInst))
451 {if (Link->hasBridge())
452 rc = XrdXrootdTransit::Attn(Link, (short *)theSID, int(Status),
453 &IOResp[1], iornum-1, ioxlen);
454 else {asynResp.theHdr.streamid[0] = theSID[0];
455 asynResp.theHdr.streamid[1] = theSID[1];
456 rc = Link->Send(IOResp, iornum, iolen);
457 }
458 } else rc = -1;
459 Link->setRef(-1);
460 return (rc < 0 ? -1 : 0);
461 }
462 return -1;
463}
464
465/******************************************************************************/
466/* S e t */
467/******************************************************************************/
468
469void XrdXrootdResponse::Set(unsigned char *stream)
470{
471 static const char hv[] = "0123456789abcdef";
472 char *outbuff;
473 int i;
474
475 Resp.streamid[0] = stream[0];
476 Resp.streamid[1] = stream[1];
477
479 {outbuff = trsid;
480 for (i = 0; i < (int)sizeof(Resp.streamid); i++)
481 {*outbuff++ = hv[(stream[i] >> 4) & 0x0f];
482 *outbuff++ = hv[ stream[i] & 0x0f];
483 }
484 *outbuff++ = ' '; *outbuff = '\0';
485 }
486}
487
488/******************************************************************************/
489/* Private: s r s C o m p l e t e */
490/******************************************************************************/
491
492int XrdXrootdResponse::srsComplete(ServerResponseStatus &srs,
493 int iLen, int dlen)
494{
495 static const int csSZ = sizeof(kXR_unt32);
496 static const int bdSZ = sizeof(ServerResponseBody_Status);
497
498 const unsigned char *body;
500
501// Do some tracing if so requested
502//
503 TRACES(RSP, "sending " <<sName[srs.bdy.resptype]
504 <<iLen <<" info and " <<dlen <<" data bytes");
505
506// Fill out the header
507//
508 srs.hdr.streamid[0] = Resp.streamid[0];
509 srs.hdr.streamid[1] = Resp.streamid[1];
510 srs.hdr.status = htons(kXR_status);
511 srs.hdr.dlen = htonl(bdSZ+iLen);
512
513// Complete the status body
514//
515 srs.bdy.streamID[0] = Resp.streamid[0];
516 srs.bdy.streamID[1] = Resp.streamid[1];
517 srs.bdy.dlen = htonl(dlen);
518
519// Finally, compute the crc for the body
520//
521 body = ((const unsigned char *)&srs.bdy.crc32c)+csSZ;
522 crc32c = XrdOucCRC::Calc32C(body, bdSZ-csSZ+iLen);
523 srs.bdy.crc32c = htonl(crc32c);
524
525// Return the total amount of bytes to send for the header
526//
527 return sizeof(ServerResponseStatus) + iLen;
528}
@ kXR_asynresp
Definition XProtocol.hh:938
XErrorCode
Definition XProtocol.hh:989
kXR_char streamid[2]
Definition XProtocol.hh:914
XResponseType
Definition XProtocol.hh:898
@ kXR_status
Definition XProtocol.hh:907
@ kXR_ok
Definition XProtocol.hh:899
@ kXR_attn
Definition XProtocol.hh:901
@ kXR_error
Definition XProtocol.hh:903
struct ServerResponseBody_Status bdy
struct ServerResponseHeader hdr
int kXR_int32
Definition XPtypes.hh:89
unsigned int kXR_unt32
Definition XPtypes.hh:90
unsigned short kXR_unt16
Definition XPtypes.hh:67
#define TRACES(x)
#define EMSG(x)
#define TRACE_REQ
#define TRACE_RSP
uint32_t crc32c(uint32_t crc, void const *buf, size_t len)
#define TRACING(x)
Definition XrdTrace.hh:70
XrdSysTrace XrdXrootdTrace
static XrdLink * fd2link(int fd)
Definition XrdLinkCtl.hh:72
static uint32_t Calc32C(const void *data, size_t count, uint32_t prevcs=0)
Definition XrdOucCRC.cc:190
unsigned long long getID()
void Set(XrdLink *lp)
int Send(int rcode, const struct iovec *ioVec, int ioNum, int ioLen)
Handle request data response.
static int Attn(XrdLink *lP, short *theSID, int rcode, const struct iovec *ioVec, int ioNum, int ioLen)
Handle attention response (i.e. async response)
int fdnum
File descriptor for data.
int sendsz
Length of data at offset.