XRootD
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 
49 const char *XrdXrootdResponse::TraceID = "Response";
50 
51 /******************************************************************************/
52 /* L o c a l D e f i n e s */
53 /******************************************************************************/
54 
55 
56 namespace
57 {
58 const 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 
86 int 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 
110 int 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 
187 int 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 
211 int 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 
238 int 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 
266 int 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 
301 int 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]
408  ServerResponseHeader theHdr;
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 
469 void XrdXrootdResponse::Set(unsigned char *stream)
470 {
471  static char hv[] = "0123456789abcdef";
472  char *outbuff;
473  int i;
474 
475  Resp.streamid[0] = stream[0];
476  Resp.streamid[1] = stream[1];
477 
478  if (TRACING((TRACE_REQ|TRACE_RSP)))
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 
492 int 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
Definition: XProtocol.hh:1261
struct ServerResponseHeader hdr
Definition: XProtocol.hh:1260
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)
Definition: XrdBwmTrace.hh:42
#define EMSG(x)
Definition: XrdCpConfig.cc:55
#define TRACE_REQ
Definition: XrdHttpTrace.hh:51
#define TRACE_RSP
Definition: XrdHttpTrace.hh:53
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.
Definition: XrdOucSFVec.hh:47
int sendsz
Length of data at offset.
Definition: XrdOucSFVec.hh:46