XRootD
Loading...
Searching...
No Matches
XrdClMessageUtils.cc
Go to the documentation of this file.
1//------------------------------------------------------------------------------
2// Copyright (c) 2011-2014 by European Organization for Nuclear Research (CERN)
3// Author: Lukasz Janyst <ljanyst@cern.ch>
4//------------------------------------------------------------------------------
5// This file is part of the XRootD software suite.
6//
7// XRootD is free software: you can redistribute it and/or modify
8// it under the terms of the GNU Lesser General Public License as published by
9// the Free Software Foundation, either version 3 of the License, or
10// (at your option) any later version.
11//
12// XRootD is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU Lesser General Public License
18// along with XRootD. If not, see <http://www.gnu.org/licenses/>.
19//
20// In applying this licence, CERN does not waive the privileges and immunities
21// granted to it by virtue of its status as an Intergovernmental Organization
22// or submit itself to any jurisdiction.
23//------------------------------------------------------------------------------
24
26#include "XrdCl/XrdClLog.hh"
35
37
38namespace XrdCl
39{
40 //----------------------------------------------------------------------------
41 // Send a message
42 //----------------------------------------------------------------------------
44 Message *msg,
45 ResponseHandler *handler,
46 MessageSendParams &sendParams,
47 LocalFileHandler *lFileHandler )
48 {
49 //--------------------------------------------------------------------------
50 // Get the stuff needed to send the message
51 //--------------------------------------------------------------------------
52 Log *log = DefaultEnv::GetLog();
54 XRootDStatus st;
55
56 if( !postMaster )
58
59 log->Dump( XRootDMsg, "[%s] Sending message %s",
60 url.GetHostId().c_str(), msg->GetObfuscatedDescription().c_str() );
61
62 //--------------------------------------------------------------------------
63 // Get an instance of SID manager object
64 //--------------------------------------------------------------------------
65 std::shared_ptr<SIDManager> sidMgr( SIDMgrPool::Instance().GetSIDMgr( url ) );
67
68 //--------------------------------------------------------------------------
69 // Allocate the SID and marshall the message
70 //--------------------------------------------------------------------------
71 st = sidMgr->AllocateSID( req->streamid );
72 if( !st.IsOK() )
73 {
74 log->Error( XRootDMsg, "[%s] Unable to allocate stream id",
75 url.GetHostId().c_str() );
76 return st;
77 }
78
79 //--------------------------------------------------------------------------
80 // Make sure that in case of checkpoint xeq request the embedded request
81 // SID is matching
82 //--------------------------------------------------------------------------
83 if( req->requestid == kXR_chkpoint )
84 {
86 if( r->chkpoint.opcode == kXR_ckpXeq )
87 {
89 xeq->header.streamid[0] = req->streamid[0];
90 xeq->header.streamid[1] = req->streamid[1];
91 }
92 }
93
95
96 //--------------------------------------------------------------------------
97 // Create and set up the message handler
98 //--------------------------------------------------------------------------
99 XRootDMsgHandler *msgHandler;
100 msgHandler = new XRootDMsgHandler( msg, handler, &url, sidMgr, lFileHandler );
101 msgHandler->SetExpiration( sendParams.expires );
102 msgHandler->SetRedirectAsAnswer( !sendParams.followRedirects );
103 msgHandler->SetOksofarAsAnswer( sendParams.chunkedResponse );
104 msgHandler->SetChunkList( sendParams.chunkList );
105 msgHandler->SetKernelBuffer( sendParams.kbuff );
106 msgHandler->SetRedirectCounter( sendParams.redirectLimit );
107 msgHandler->SetStateful( sendParams.stateful );
108 msgHandler->SetCrc32cDigests( std::move( sendParams.crc32cDigests ) );
109
110 if( sendParams.loadBalancer.url.IsValid() )
111 msgHandler->SetLoadBalancer( sendParams.loadBalancer );
112
113 HostList *list = 0;
114 if( sendParams.hostList )
115 {
116 list = sendParams.hostList;
117 sendParams.hostList = nullptr;
118 }
119 else
120 list = new HostList();
121 list->push_back( url );
122 msgHandler->SetHostList( list );
123
124 //--------------------------------------------------------------------------
125 // Send the message
126 //--------------------------------------------------------------------------
127 st = postMaster->Send( url, msg, msgHandler, sendParams.stateful,
128 sendParams.expires );
129 if( !st.IsOK() )
130 {
132 log->Error( XRootDMsg, "[%s] Unable to send the message %s: %s",
133 url.GetHostId().c_str(), msg->GetObfuscatedDescription().c_str(),
134 st.ToString().c_str() );
135
136 // we need to reassign req as its current value might have been
137 // invalidated in the meanwhile due to a realloc
138 req = (ClientRequestHdr*)msg->GetBuffer();
139 // Release the SID as the request was never send
140 sidMgr->ReleaseSID( req->streamid );
141 delete msgHandler;
142 return st;
143 }
144 return XRootDStatus();
145 }
146
147 //----------------------------------------------------------------------------
148 // Redirect a message
149 //----------------------------------------------------------------------------
151 Message *msg,
152 ResponseHandler *handler,
153 MessageSendParams &sendParams,
154 LocalFileHandler *lFileHandler )
155 {
156 //--------------------------------------------------------------------------
157 // Register a new virtual redirector
158 //--------------------------------------------------------------------------
160 Status st = registry.Register( url );
161 if( !st.IsOK() )
162 return st;
163
164 //--------------------------------------------------------------------------
165 // Get the stuff needed to send the message
166 //--------------------------------------------------------------------------
167 Log *log = DefaultEnv::GetLog();
169
170 if( !postMaster )
172
173 log->Dump( XRootDMsg, "[%s] Redirecting message %s",
174 url.GetHostId().c_str(), msg->GetObfuscatedDescription().c_str() );
175
177
178 //--------------------------------------------------------------------------
179 // Create and set up the message handler
180 //--------------------------------------------------------------------------
181 XRootDMsgHandler *msgHandler;
182 msgHandler = new XRootDMsgHandler( msg, handler, &url, std::shared_ptr<SIDManager>(), lFileHandler );
183 msgHandler->SetExpiration( sendParams.expires );
184 msgHandler->SetRedirectAsAnswer( !sendParams.followRedirects );
185 msgHandler->SetOksofarAsAnswer( sendParams.chunkedResponse );
186 msgHandler->SetChunkList( sendParams.chunkList );
187 msgHandler->SetRedirectCounter( sendParams.redirectLimit );
188 msgHandler->SetFollowMetalink( true );
189
190 HostInfo info( url, true );
192 sendParams.loadBalancer = info;
193 msgHandler->SetLoadBalancer( info );
194
195 HostList *list = 0;
196 list = new HostList();
197 list->push_back( info );
198 msgHandler->SetHostList( list );
199
200 //--------------------------------------------------------------------------
201 // Redirect the message
202 //--------------------------------------------------------------------------
203 st = postMaster->Redirect( url, msg, msgHandler );
204 if( !st.IsOK() )
205 {
207 log->Error( XRootDMsg, "[%s] Unable to send the message %s: %s",
208 url.GetHostId().c_str(), msg->GetObfuscatedDescription().c_str(),
209 st.ToString().c_str() );
210 delete msgHandler;
211 delete list;
212 return st;
213 }
214 return Status();
215 }
216
217 //----------------------------------------------------------------------------
218 // Process sending params
219 //----------------------------------------------------------------------------
221 {
222 //--------------------------------------------------------------------------
223 // Timeout
224 //--------------------------------------------------------------------------
225 Env *env = DefaultEnv::GetEnv();
226 if( sendParams.timeout == 0 )
227 {
228 int requestTimeout = DefaultRequestTimeout;
229 env->GetInt( "RequestTimeout", requestTimeout );
230 sendParams.timeout = requestTimeout;
231 }
232
233 if( sendParams.expires == 0 )
234 sendParams.expires = ::time(0)+sendParams.timeout;
235
236 //--------------------------------------------------------------------------
237 // Redirect limit
238 //--------------------------------------------------------------------------
239 if( sendParams.redirectLimit == 0 )
240 {
241 int redirectLimit = DefaultRedirectLimit;
242 env->GetInt( "RedirectLimit", redirectLimit );
243 sendParams.redirectLimit = redirectLimit;
244 }
245 }
246
247 //----------------------------------------------------------------------------
249 //----------------------------------------------------------------------------
251 const URL::ParamsMap &newCgi,
252 bool replace,
253 const std::string &newPath,
254 std::string *opathp )
255 {
256 ClientRequest *req = (ClientRequest *)msg->GetBuffer();
257 switch( req->header.requestid )
258 {
259 case kXR_chmod:
260 case kXR_mkdir:
261 case kXR_mv:
262 case kXR_open:
263 case kXR_rm:
264 case kXR_rmdir:
265 case kXR_stat:
266 case kXR_truncate:
267 {
268 //----------------------------------------------------------------------
269 // Get the pointer to the appropriate path
270 //----------------------------------------------------------------------
271 char *path = msg->GetBuffer( 24 );
272 size_t length = req->header.dlen;
273 if( req->header.requestid == kXR_mv )
274 {
275 for( int i = 0; i < req->header.dlen; ++i, ++path, --length )
276 if( *path == ' ' )
277 break;
278 ++path;
279 --length;
280 }
281
282 //----------------------------------------------------------------------
283 // Create a fake URL from an existing CGI
284 //----------------------------------------------------------------------
285 char *pathWithNull = new char[length+1];
286 memcpy( pathWithNull, path, length );
287 pathWithNull[length] = 0;
288 std::ostringstream o;
289 o << "fake://fake:111/" << pathWithNull;
290 delete [] pathWithNull;
291
292 URL currentPath( o.str() );
293 URL::ParamsMap currentCgi = currentPath.GetParams();
294 MergeCGI( currentCgi, newCgi, replace );
295 currentPath.SetParams( currentCgi );
296 if( opathp )
297 *opathp = currentPath.GetPath();
298 if( !newPath.empty() )
299 currentPath.SetPath( newPath );
300 std::string newPathWitParams = currentPath.GetPathWithFilteredParams();
301
302 //----------------------------------------------------------------------
303 // Write the path with the new cgi appended to the message
304 //----------------------------------------------------------------------
305 uint32_t newDlen = req->header.dlen - length + newPathWitParams.size();
306 msg->ReAllocate( 24+newDlen );
307 req = (ClientRequest *)msg->GetBuffer();
308 path = msg->GetBuffer( 24 );
309 if( req->header.requestid == kXR_mv )
310 {
311 for( int i = 0; i < req->header.dlen; ++i, ++path )
312 if( *path == ' ' )
313 break;
314 ++path;
315 }
316 memcpy( path, newPathWitParams.c_str(), newPathWitParams.size() );
317 req->header.dlen = newDlen;
318 break;
319 }
320 case kXR_locate:
321 {
322 Env *env = DefaultEnv::GetEnv();
323 int preserveLocateTried = DefaultPreserveLocateTried;
324 env->GetInt( "PreserveLocateTried", preserveLocateTried );
325
326 if( !preserveLocateTried ) break;
327
328 //----------------------------------------------------------------------
329 // In case of locate we only want to preserve tried/triedrc CGI info
330 //----------------------------------------------------------------------
331 URL::ParamsMap triedCgi;
332 URL::ParamsMap::const_iterator itr = newCgi.find( "triedrc" );
333 if( itr != newCgi.end() )
334 triedCgi[itr->first] = itr->second;
335 itr = newCgi.find( "tried" );
336 if( itr != newCgi.end() )
337 triedCgi[itr->first] = itr->second;
338
339 //----------------------------------------------------------------------
340 // Is there anything to do?
341 //----------------------------------------------------------------------
342 if( triedCgi.empty() ) break;
343
344 //----------------------------------------------------------------------
345 // Get the pointer to the appropriate path
346 //----------------------------------------------------------------------
347 char *path = msg->GetBuffer( 24 );
348 size_t length = req->header.dlen;
349
350 //----------------------------------------------------------------------
351 // Create a fake URL from an existing CGI
352 //----------------------------------------------------------------------
353 std::string strpath( path, length );
354 std::ostringstream o;
355 o << "fake://fake:111/" << strpath;
356
357 URL currentPath( o.str() );
358 URL::ParamsMap currentCgi = currentPath.GetParams();
359 MergeCGI( currentCgi, triedCgi, replace );
360 currentPath.SetParams( currentCgi );
361 std::string pathWitParams = currentPath.GetPathWithFilteredParams();
362
363 //----------------------------------------------------------------------
364 // Write the path with the new cgi appended to the message
365 //----------------------------------------------------------------------
366 uint32_t newDlen = pathWitParams.size();
367 msg->ReAllocate( 24+newDlen );
368 req = (ClientRequest *)msg->GetBuffer();
369 path = msg->GetBuffer( 24 );
370 memcpy( path, pathWitParams.c_str(), pathWitParams.size() );
371 req->header.dlen = newDlen;
372 break;
373 }
374 }
376 }
377
378 //------------------------------------------------------------------------
380 //------------------------------------------------------------------------
382 const URL::ParamsMap &cgi2,
383 bool replace )
384 {
385 URL::ParamsMap::const_iterator it;
386 for( it = cgi2.begin(); it != cgi2.end(); ++it )
387 {
388 if( replace || cgi1.find( it->first ) == cgi1.end() )
389 cgi1[it->first] = it->second;
390 else
391 {
392 std::string &v = cgi1[it->first];
393 if( v.empty() )
394 v = it->second;
395 else
396 {
397 v += ',';
398 v += it->second;
399 }
400 }
401 }
402 }
403
404 //------------------------------------------------------------------------
406 //------------------------------------------------------------------------
407 Status MessageUtils::CreateXAttrVec( const std::vector<xattr_t> &attrs,
408 std::vector<char> &avec )
409 {
410 if( attrs.empty() )
411 return Status();
412
413 if( attrs.size() > xfaLimits::kXR_faMaxVars )
414 return Status( stError, errInvalidArgs );
415
416 //----------------------------------------------------------------------
417 // Calculate the name and value vector lengths
418 //----------------------------------------------------------------------
419
420 // 2 bytes for rc + 1 byte for null character at the end
421 static const int name_overhead = 3;
422 // 4 bytes for value length
423 static const int value_overhead = 4;
424
425 size_t nlen = 0, vlen = 0;
426 for( auto itr = attrs.begin(); itr != attrs.end(); ++itr )
427 {
428 nlen += std::get<xattr_name>( *itr ).size() + name_overhead;
429 vlen += std::get<xattr_value>( *itr ).size() + value_overhead;
430 }
431
432 if( nlen > xfaLimits::kXR_faMaxNlen )
433 return Status( stError, errInvalidArgs );
434
435 if( vlen > xfaLimits::kXR_faMaxVlen )
436 return Status( stError, errInvalidArgs );
437
438 //----------------------------------------------------------------------
439 // Create name and value vectors
440 //----------------------------------------------------------------------
441 avec.resize( nlen + vlen, 0 );
442 char *nvec = avec.data(), *vvec = avec.data() + nlen;
443
444 for( auto itr = attrs.begin(); itr != attrs.end(); ++itr )
445 {
446 const std::string &name = std::get<xattr_name>( *itr );
447 nvec = ClientFattrRequest::NVecInsert( name.c_str(), nvec );
448 const std::string &value = std::get<xattr_value>( *itr );
449 vvec = ClientFattrRequest::VVecInsert( value.c_str(), vvec );
450 }
451
452 return Status();
453 }
454
455 //------------------------------------------------------------------------
456 // Create xattr name vector vector
457 //------------------------------------------------------------------------
458 Status MessageUtils::CreateXAttrVec( const std::vector<std::string> &attrs,
459 std::vector<char> &nvec )
460 {
461 if( attrs.empty() )
462 return Status();
463
464 if( attrs.size() > xfaLimits::kXR_faMaxVars )
465 return Status( stError, errInvalidArgs );
466
467 //----------------------------------------------------------------------
468 // Calculate the name and value vector lengths
469 //----------------------------------------------------------------------
470
471 // 2 bytes for rc + 1 byte for null character at the end
472 static const int name_overhead = 3;
473
474 size_t nlen = 0;
475 for( auto itr = attrs.begin(); itr != attrs.end(); ++itr )
476 nlen += itr->size() + name_overhead;
477
478 if( nlen > xfaLimits::kXR_faMaxNlen )
479 return Status( stError, errInvalidArgs );
480
481 //----------------------------------------------------------------------
482 // Create name vector
483 //----------------------------------------------------------------------
484 nvec.resize( nlen, 0 );
485 char *nptr = nvec.data();
486
487 for( auto itr = attrs.begin(); itr != attrs.end(); ++itr )
488 nptr = ClientFattrRequest::NVecInsert( itr->c_str(), nptr );
489
490 return Status();
491 }
492}
#define kXR_isManager
#define kXR_attrMeta
kXR_char streamid[2]
Definition XProtocol.hh:158
static const int kXR_ckpXeq
Definition XProtocol.hh:218
struct ClientRequestHdr header
Definition XProtocol.hh:887
kXR_unt16 requestid
Definition XProtocol.hh:159
@ kXR_open
Definition XProtocol.hh:123
@ kXR_mkdir
Definition XProtocol.hh:121
@ kXR_chmod
Definition XProtocol.hh:115
@ kXR_rm
Definition XProtocol.hh:127
@ kXR_rmdir
Definition XProtocol.hh:128
@ kXR_truncate
Definition XProtocol.hh:141
@ kXR_mv
Definition XProtocol.hh:122
@ kXR_stat
Definition XProtocol.hh:130
@ kXR_chkpoint
Definition XProtocol.hh:125
@ kXR_locate
Definition XProtocol.hh:140
#define kXR_attrVirtRdr
@ kXR_faMaxVars
Definition XProtocol.hh:310
@ kXR_faMaxVlen
Definition XProtocol.hh:312
@ kXR_faMaxNlen
Definition XProtocol.hh:311
struct ClientChkPointRequest chkpoint
Definition XProtocol.hh:890
void ReAllocate(uint32_t size)
Reallocate the buffer to a new location of a given size.
const char * GetBuffer(uint32_t offset=0) const
Get the message buffer.
static Log * GetLog()
Get default log.
static PostMaster * GetPostMaster()
Get default post master.
static Env * GetEnv()
Get default client environment.
bool GetInt(const std::string &key, int &value)
Definition XrdClEnv.cc:115
Handle diagnostics.
Definition XrdClLog.hh:101
void Error(uint64_t topic, const char *format,...)
Report an error.
Definition XrdClLog.cc:231
void Dump(uint64_t topic, const char *format,...)
Print a dump message.
Definition XrdClLog.cc:299
static void MergeCGI(URL::ParamsMap &cgi1, const URL::ParamsMap &cgi2, bool replace)
Merge cgi2 into cgi1.
static Status CreateXAttrVec(const std::vector< xattr_t > &attrs, std::vector< char > &avec)
Create xattr vector.
static void ProcessSendParams(MessageSendParams &sendParams)
Process sending params.
static void RewriteCGIAndPath(Message *msg, const URL::ParamsMap &newCgi, bool replace, const std::string &newPath, std::string *opathp=nullptr)
Append cgi to the one already present in the message.
static Status RedirectMessage(const URL &url, Message *msg, ResponseHandler *handler, MessageSendParams &sendParams, LocalFileHandler *lFileHandler)
Redirect message.
static XRootDStatus SendMessage(const URL &url, Message *msg, ResponseHandler *handler, MessageSendParams &sendParams, LocalFileHandler *lFileHandler)
Send message.
The message representation used throughout the system.
const std::string & GetObfuscatedDescription() const
Get the description of the message with authz parameter obfuscated.
A hub for dispatching and receiving messages.
XRootDStatus Send(const URL &url, Message *msg, MsgHandler *handler, bool stateful, time_t expires)
Status Redirect(const URL &url, Message *msg, MsgHandler *handler)
Singleton access to URL to virtual redirector mapping.
static RedirectorRegistry & Instance()
Returns reference to the single instance.
XRootDStatus Register(const URL &url)
Creates a new virtual redirector and registers it (async).
Handle an async response.
static SIDMgrPool & Instance()
URL representation.
Definition XrdClURL.hh:31
const std::string & GetPath() const
Get the path.
Definition XrdClURL.hh:217
std::string GetHostId() const
Get the host part of the URL (user:password@host:port).
Definition XrdClURL.hh:99
std::map< std::string, std::string > ParamsMap
Definition XrdClURL.hh:33
void SetParams(const std::string &params)
Set params.
Definition XrdClURL.cc:402
std::string GetPathWithFilteredParams() const
Get the path with params, filteres out 'xrdcl.'.
Definition XrdClURL.cc:331
void SetPath(const std::string &path)
Set the path.
Definition XrdClURL.hh:225
const ParamsMap & GetParams() const
Get the URL params.
Definition XrdClURL.hh:244
bool IsValid() const
Is the url valid.
Definition XrdClURL.cc:452
Handle/Process/Forward XRootD messages.
void SetRedirectCounter(uint16_t redirectCounter)
Set the redirect counter.
void SetFollowMetalink(bool followMetalink)
void SetChunkList(ChunkList *chunkList)
Set the chunk list.
void SetHostList(HostList *hostList)
Set host list.
void SetCrc32cDigests(std::vector< uint32_t > &&crc32cDigests)
void SetLoadBalancer(const HostInfo &loadBalancer)
Set the load balancer.
void SetOksofarAsAnswer(bool oksofarAsAnswer)
void SetKernelBuffer(XrdSys::KernelBuffer *kbuff)
Set the kernel buffer.
void SetExpiration(time_t expiration)
Set a timestamp after which we give up.
void SetRedirectAsAnswer(bool redirectAsAnswer)
static void SetDescription(Message *msg)
Get the description of a message.
static XRootDStatus UnMarshallRequest(Message *msg)
static XRootDStatus MarshallRequest(Message *msg)
Marshal the outgoing message.
const int DefaultPreserveLocateTried
const int DefaultRedirectLimit
const uint16_t errUninitialized
const uint16_t stError
An error occurred that could potentially be retried.
const uint64_t XRootDMsg
std::vector< HostInfo > HostList
const uint16_t errInvalidArgs
const int DefaultRequestTimeout
static char * VVecInsert(const char *value, char *buffer)
Definition XProtocol.cc:192
static char * NVecInsert(const char *name, char *buffer)
Definition XProtocol.cc:176
URL url
URL of the host.
uint32_t flags
Host type.
std::vector< uint32_t > crc32cDigests
XrdSys::KernelBuffer * kbuff
Procedure execution status.
bool IsOK() const
We're fine.
std::string ToString() const
Create a string representation.