XRootD
XrdHttpTpcPMarkManager.cc
Go to the documentation of this file.
1 //------------------------------------------------------------------------------
2 // This file is part of XrdHttpTpcTPC
3 //
4 // Copyright (c) 2023 by European Organization for Nuclear Research (CERN)
5 // Author: Cedric Caffy <ccaffy@cern.ch>
6 // File Date: Oct 2023
7 //------------------------------------------------------------------------------
8 // XRootD is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Lesser General Public License as published by
10 // the Free Software Foundation, either version 3 of the License, or
11 // (at your option) any later version.
12 //
13 // XRootD is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public License
19 // along with XRootD. If not, see <http://www.gnu.org/licenses/>.
20 //------------------------------------------------------------------------------
21 
22 
23 #include <sstream>
25 #include "XrdNet/XrdNetUtils.hh"
27 
28 namespace XrdHttpTpc
29 {
30 PMarkManager::SocketInfo::SocketInfo(int fd, const struct sockaddr * sockP) {
31  netAddr.Set(sockP,fd);
32  client.addrInfo = static_cast<XrdNetAddrInfo*>(&netAddr);
33 }
34 
36  : mPmark(req.pmark), mSciTag(req.mSciTag), mResource(req.resource.c_str()), mTransferWillStart(false), mTpcType(tpcType) {}
37 
38 PMarkManager::PMarkManager(XrdNetPMark *pmark, int sciTag, const TPC::TpcType tpcType)
39  : mPmark(pmark), mSciTag(sciTag), mResource(NULL), mTransferWillStart(false), mTpcType(tpcType) {}
40 
41 void PMarkManager::addFd(int fd, const struct sockaddr * sockP) {
42  if(isEnabled() && mTransferWillStart) {
43  // The transfer will start and the packet marking has been configured, this socket must be registered for future packet marking
44  mSocketInfos.emplace(fd, sockP);
45  }
46 }
47 
48 bool PMarkManager::connect(int fd, const struct sockaddr *sockP, size_t sockPLen, uint32_t timeout_sec, std::stringstream &err) {
49  if(isEnabled()) {
50  // We only connect if the packet marking is enabled
51  bool couldConnect = XrdNetUtils::ConnectWithTimeout(fd,sockP,sockPLen,timeout_sec,err);
52  if(couldConnect) {
53  addFd(fd,sockP);
54  } else {
55  return false;
56  }
57  }
58  // If pmark is not enabled, we leave libcurl doing the connection
59  return true;
60 }
61 
63  return mPmark && (mSciTag >= 0);
64 }
65 
67  mTransferWillStart = true;
68 }
69 
71  if(mSocketInfos.empty()) {
72  return;
73  }
74 
75  if(mPmarkHandles.empty()) {
76  // Create the first pmark handle
77  std::stringstream ss;
78  ss << "scitag.flow=" << mSciTag
79  // One has to consider that this server is the client side of a normal HTTP PUT/GET. But unlike normal HTTP PUT and GET requests where clients
80  // do not emit a firefly, this server WILL emit a firefly.
81  //
82  // For PULL: it is expected that I send a GET request to the remote server
83  // however, it is myself who will emit the firefly, then I should consider that the GET is actually a PUT
84  // that I do on behalf of the remote server... Hence why if the tpc transfer type is Pull, the pmark.appname
85  // will be equal to http-put
86  //
87  // For PUSH: it is expected that I send a PUT request to the remote server.
88  // however, it is myself who will emit the firefly, then I should consider that the PUT is actually a GET
89  // that I do on behalf of the remote server... Hence why if the tpc transfer is Push, the pmark.appname will be equal to http-get.
90  << "&" << "pmark.appname=" << ((mTpcType == TPC::TpcType::Pull) ? "http-put" : "http-get");
91  SocketInfo & sockInfo = mSocketInfos.front();
92  auto pmark = mPmark->Begin(sockInfo.client, mResource, ss.str().c_str(), "http-tpc");
93  if(!pmark) {
94  return;
95  }
96  mPmarkHandles.emplace(sockInfo.client.addrInfo->SockFD(),std::unique_ptr<XrdNetPMark::Handle>(pmark));
97  mSocketInfos.pop();
98  }
99 
100  auto pmarkHandleItor = mPmarkHandles.begin();
101  while(!mSocketInfos.empty()) {
102  SocketInfo & sockInfo = mSocketInfos.front();
103  auto pmark = mPmark->Begin(*sockInfo.client.addrInfo, *(pmarkHandleItor->second), nullptr);
104  if (!pmark) {
105  // The packet marking handle could not be created from the first handle, let's retry next time
106  break;
107  }
108 
109  int fd = sockInfo.client.addrInfo->SockFD();
110  mPmarkHandles.emplace(fd, std::unique_ptr<XrdNetPMark::Handle>(pmark));
111  mSocketInfos.pop();
112  }
113 }
114 
116  // We need to delete the PMark handle associated to the fd passed in parameter
117  // we just look for it and reset the unique_ptr to nullptr to trigger the PMark handle deletion
118  mPmarkHandles.erase(fd);
119 }
120 } // namespace XrdHttpTpc
SocketInfo(int fd, const struct sockaddr *sockP)
bool connect(int fd, const struct sockaddr *sockP, size_t sockPLen, uint32_t timeout_sec, std::stringstream &err)
PMarkManager(XrdHttpExtReq &req, const TPC::TpcType type)
const char * Set(const char *hSpec, int pNum=PortInSpec)
Definition: XrdNetAddr.cc:216
virtual Handle * Begin(XrdSecEntity &Client, const char *path=0, const char *cgi=0, const char *app=0)=0
static bool ConnectWithTimeout(int sockfd, const struct sockaddr *clientAddr, size_t clientAddrLen, uint32_t timeout_sec, std::stringstream &errMsg)
Definition: XrdNetUtils.cc:981
XrdNetAddrInfo * addrInfo
Entity's connection details.
Definition: XrdSecEntity.hh:80