XRootD
XrdClXRootDTransport.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/XrdClConstants.hh"
27 #include "XrdCl/XrdClLog.hh"
28 #include "XrdCl/XrdClSocket.hh"
29 #include "XrdCl/XrdClMessage.hh"
30 #include "XrdCl/XrdClDefaultEnv.hh"
31 #include "XrdCl/XrdClSIDManager.hh"
32 #include "XrdCl/XrdClUtils.hh"
34 #include "XrdCl/XrdClTls.hh"
35 #include "XrdNet/XrdNetAddr.hh"
36 #include "XrdNet/XrdNetUtils.hh"
37 #include "XrdSys/XrdSysPlatform.hh"
38 #include "XrdOuc/XrdOucErrInfo.hh"
39 #include "XrdOuc/XrdOucUtils.hh"
40 #include "XrdOuc/XrdOucCRC.hh"
42 #include "XrdSys/XrdSysTimer.hh"
43 #include "XrdSys/XrdSysAtomics.hh"
44 #include "XrdSys/XrdSysPlugin.hh"
46 #include "XrdSec/XrdSecProtect.hh"
47 #include "XrdSys/XrdSysE2T.hh"
48 #include "XrdCl/XrdClTls.hh"
49 #include "XrdCl/XrdClSocket.hh"
50 #include "XProtocol/XProtocol.hh"
51 #include "XrdVersion.hh"
52 
53 #include <arpa/inet.h>
54 #include <sys/types.h>
55 #include <unistd.h>
56 #include <dlfcn.h>
57 #include <sstream>
58 #include <iomanip>
59 #include <set>
60 #include <limits>
61 
62 #include <atomic>
63 
65 
66 namespace XrdCl
67 {
69  {
70  PluginUnloadHandler() : unloaded( false ) { }
71 
72  static void UnloadHandler()
73  {
74  UnloadHandler( "root" );
75  UnloadHandler( "xroot" );
76  }
77 
78  static void UnloadHandler( const std::string &trProt )
79  {
81  TransportHandler *trHandler = trManager->GetHandler( trProt );
82  trHandler->WaitBeforeExit();
83  }
84 
85  void Register( const std::string &protocol )
86  {
87  XrdSysRWLockHelper scope( lock, false ); // obtain write lock
88  std::pair< std::set<std::string>::iterator, bool > ret = protocols.insert( protocol );
89  // if that's the first time we are using the protocol, the sec lib
90  // was just loaded so now's the time to register the atexit handler
91  if( ret.second )
92  {
93  atexit( UnloadHandler );
94  }
95  }
96 
98  bool unloaded;
99  std::set<std::string> protocols;
100  };
101 
102  //----------------------------------------------------------------------------
104  //----------------------------------------------------------------------------
106  {
107  //--------------------------------------------------------------------------
108  // Define the stream status for the link negotiation purposes
109  //--------------------------------------------------------------------------
111  {
120  Connected
121  };
122 
123  //--------------------------------------------------------------------------
124  // Constructor
125  //--------------------------------------------------------------------------
127  {
128  }
129 
131  uint8_t pathId;
132  };
133 
134  //----------------------------------------------------------------------------
136  //----------------------------------------------------------------------------
138  {
139  StreamSelector( uint16_t size )
140  {
141  //----------------------------------------------------------------------
142  // Subtract one because we shouldn't take into account the control
143  // stream.
144  //----------------------------------------------------------------------
145  strmqueues.resize( size - 1, 0 );
146  }
147 
148  //------------------------------------------------------------------------
149  // @param size : number of streams
150  //------------------------------------------------------------------------
151  void AdjustQueues( uint16_t size )
152  {
153  strmqueues.resize( size - 1, 0);
154  }
155 
156  //------------------------------------------------------------------------
157  // @param connected : bitarray stating if given sub-stream is connected
158  //
159  // @return : substream number
160  //------------------------------------------------------------------------
161  uint16_t Select( const std::vector<bool> &connected )
162  {
163  uint16_t ret = 0;
164  size_t minval = std::numeric_limits<size_t>::max();
165 
166  for( size_t i = 0; i < connected.size() && i < strmqueues.size(); ++i )
167  {
168  if( !connected[i] ) continue;
169 
170  if( strmqueues[i] < minval )
171  {
172  ret = i;
173  minval = strmqueues[i];
174  }
175  }
176 
177  ++strmqueues[ret];
178  return ret + 1;
179  }
180 
181  //--------------------------------------------------------------------------
182  // Update queue for given substream
183  //--------------------------------------------------------------------------
184  void MsgReceived( uint16_t substrm )
185  {
186  if( substrm > 0 )
187  --strmqueues[substrm - 1];
188  }
189 
190  private:
191 
192  std::vector<size_t> strmqueues;
193  };
194 
196  {
197  BindPrefSelector( std::vector<std::string> && bindprefs ) :
198  bindprefs( std::move( bindprefs ) ), next( 0 )
199  {
200  }
201 
202  inline const std::string& Get()
203  {
204  std::string &ret = bindprefs[next];
205  ++next;
206  if( next >= bindprefs.size() )
207  next = 0;
208  return ret;
209  }
210 
211  private:
212  std::vector<std::string> bindprefs;
213  size_t next;
214  };
215 
216  //----------------------------------------------------------------------------
218  //----------------------------------------------------------------------------
220  {
221  //--------------------------------------------------------------------------
222  // Constructor
223  //--------------------------------------------------------------------------
224  XRootDChannelInfo( const URL &url ):
225  serverFlags(0),
226  protocolVersion(0),
227  firstLogIn(true),
228  authBuffer(0),
229  authProtocol(0),
230  authParams(0),
231  authEnv(0),
232  finstcnt(0),
233  openFiles(0),
234  waitBarrier(0),
235  protection(0),
236  protRespBody(0),
237  protRespSize(0),
238  encrypted(false),
239  istpc(false)
240  {
242  memset( sessionId, 0, 16 );
243  memset( oldSessionId, 0, 16 );
244  }
245 
246  //--------------------------------------------------------------------------
247  // Destructor
248  //--------------------------------------------------------------------------
250  {
251  delete [] authBuffer;
252  }
253 
254  typedef std::vector<XRootDStreamInfo> StreamInfoVector;
255 
256  //--------------------------------------------------------------------------
257  // Data
258  //--------------------------------------------------------------------------
259  uint32_t serverFlags;
260  uint32_t protocolVersion;
261  uint8_t sessionId[16];
262  uint8_t oldSessionId[16];
264  std::shared_ptr<SIDManager> sidManager;
265  char *authBuffer;
270  std::string streamName;
271  std::string authProtocolName;
272  std::set<uint16_t> sentOpens;
273  std::set<uint16_t> sentCloses;
274  std::atomic<uint32_t> finstcnt; // file instance count
275  uint32_t openFiles;
276  time_t waitBarrier;
279  unsigned int protRespSize;
280  std::unique_ptr<StreamSelector> strmSelector;
281  bool encrypted;
282  bool istpc;
283  std::unique_ptr<BindPrefSelector> bindSelector;
284  std::string logintoken;
286  };
287 
288  //----------------------------------------------------------------------------
289  // Constructor
290  //----------------------------------------------------------------------------
292  pSecUnloadHandler( new PluginUnloadHandler() )
293  {
294  }
295 
296  //----------------------------------------------------------------------------
297  // Destructor
298  //----------------------------------------------------------------------------
300  {
301  delete pSecUnloadHandler; pSecUnloadHandler = 0;
302  }
303 
304  //----------------------------------------------------------------------------
305  // Read message header from socket
306  //----------------------------------------------------------------------------
308  {
309  //--------------------------------------------------------------------------
310  // A new message - allocate the space needed for the header
311  //--------------------------------------------------------------------------
312  if( message.GetCursor() == 0 && message.GetSize() < 8 )
313  message.Allocate( 8 );
314 
315  //--------------------------------------------------------------------------
316  // Read the message header
317  //--------------------------------------------------------------------------
318  if( message.GetCursor() < 8 )
319  {
320  size_t leftToBeRead = 8 - message.GetCursor();
321  while( leftToBeRead )
322  {
323  int bytesRead = 0;
324  XRootDStatus status = socket->Read( message.GetBufferAtCursor(),
325  leftToBeRead, bytesRead );
326  if( !status.IsOK() || status.code == suRetry )
327  return status;
328 
329  leftToBeRead -= bytesRead;
330  message.AdvanceCursor( bytesRead );
331  }
332  UnMarshallHeader( message );
333 
334  uint32_t bodySize = *(uint32_t*)(message.GetBuffer(4));
335  Log *log = DefaultEnv::GetLog();
336  log->Dump( XRootDTransportMsg, "[msg: %p] Expecting %d bytes of message "
337  "body", (void*)&message, bodySize );
338 
339  return XRootDStatus( stOK, suDone );
340  }
341  return XRootDStatus( stError, errInternal );
342  }
343 
344  //----------------------------------------------------------------------------
345  // Read message body from socket
346  //----------------------------------------------------------------------------
348  {
349  //--------------------------------------------------------------------------
350  // Retrieve the body
351  //--------------------------------------------------------------------------
352  size_t leftToBeRead = 0;
353  uint32_t bodySize = 0;
355  bodySize = rsphdr->dlen;
356 
357  if( message.GetSize() < bodySize + 8 )
358  message.ReAllocate( bodySize + 8 );
359 
360  leftToBeRead = bodySize-(message.GetCursor()-8);
361  while( leftToBeRead )
362  {
363  int bytesRead = 0;
364  XRootDStatus status = socket->Read( message.GetBufferAtCursor(), leftToBeRead, bytesRead );
365 
366  if( !status.IsOK() || status.code == suRetry )
367  return status;
368 
369  leftToBeRead -= bytesRead;
370  message.AdvanceCursor( bytesRead );
371  }
372 
373  return XRootDStatus( stOK, suDone );
374  }
375 
376  //----------------------------------------------------------------------------
377  // Read more of the message body from socket
378  //----------------------------------------------------------------------------
380  {
382  if( rsphdr->status != kXR_status )
383  return XRootDStatus( stError, errInvalidOp );
384 
385  //--------------------------------------------------------------------------
386  // In case of non kXR_status responses we read all the response, including
387  // data. For kXR_status responses we first read only the remainder of the
388  // header. The header must then be unmarshalled, and then a second call to
389  // GetMore (repeated for suRetry as needed) will read the data.
390  //--------------------------------------------------------------------------
391 
392  uint32_t bodySize = rsphdr->dlen;
393  if( bodySize+8 < sizeof( ServerResponseStatus ) )
395  "kXR_status: invalid message size." );
396 
398  bodySize += rspst->bdy.dlen;
399 
400  if( message.GetSize() < bodySize + 8 )
401  message.ReAllocate( bodySize + 8 );
402 
403  size_t leftToBeRead = bodySize-(message.GetCursor()-8);
404  while( leftToBeRead )
405  {
406  int bytesRead = 0;
407  XRootDStatus status = socket->Read( message.GetBufferAtCursor(), leftToBeRead, bytesRead );
408 
409  if( !status.IsOK() || status.code == suRetry )
410  return status;
411 
412  leftToBeRead -= bytesRead;
413  message.AdvanceCursor( bytesRead );
414  }
415 
416  // Unmarchal to message body
417  Log *log = DefaultEnv::GetLog();
419  if( !st.IsOK() && st.code == errDataError )
420  {
421  log->Error( XRootDTransportMsg, "[msg: %p] %s", (void*)&message,
422  st.GetErrorMessage().c_str() );
423  return st;
424  }
425 
426  if( !st.IsOK() )
427  {
428  log->Error( XRootDTransportMsg, "[msg: %p] Failed to unmarshall status body.",
429  (void*)&message );
430  return st;
431  }
432 
433  return XRootDStatus( stOK, suDone );
434  }
435 
436  //----------------------------------------------------------------------------
437  // Initialize channel
438  //----------------------------------------------------------------------------
440  AnyObject &channelData )
441  {
442  XRootDChannelInfo *info = new XRootDChannelInfo( url );
443  XrdSysMutexHelper scopedLock( info->mutex );
444  channelData.Set( info );
445 
446  Env *env = DefaultEnv::GetEnv();
447  int streams = DefaultSubStreamsPerChannel;
448  env->GetInt( "SubStreamsPerChannel", streams );
449  if( streams < 1 ) streams = 1;
450  info->stream.resize( streams );
451  info->strmSelector.reset( new StreamSelector( streams ) );
452  info->encrypted = url.IsSecure();
453  info->istpc = url.IsTPC();
454  info->logintoken = url.GetLoginToken();
455  }
456 
457  //----------------------------------------------------------------------------
458  // Finalize channel
459  //----------------------------------------------------------------------------
461  {
462  }
463 
464  //----------------------------------------------------------------------------
465  // HandShake
466  //----------------------------------------------------------------------------
468  AnyObject &channelData )
469  {
470  XRootDChannelInfo *info = 0;
471  channelData.Get( info );
472 
473  if (!info)
475 
476  XrdSysMutexHelper scopedLock( info->mutex );
477 
478  if( info->stream.size() <= handShakeData->subStreamId )
479  {
480  Log *log = DefaultEnv::GetLog();
482  "[%s] Internal error: not enough substreams",
483  handShakeData->streamName.c_str() );
484  return XRootDStatus( stFatal, errInternal );
485  }
486 
487  if( handShakeData->subStreamId == 0 )
488  {
489  info->streamName = handShakeData->streamName;
490  return HandShakeMain( handShakeData, channelData );
491  }
492  return HandShakeParallel( handShakeData, channelData );
493  }
494 
495  //----------------------------------------------------------------------------
496  // Hand shake the main stream
497  //----------------------------------------------------------------------------
498  XRootDStatus XRootDTransport::HandShakeMain( HandShakeData *handShakeData,
499  AnyObject &channelData )
500  {
501  XRootDChannelInfo *info = 0;
502  channelData.Get( info );
503 
504  if (!info) {
506  "[%s] Internal error: no channel info",
507  handShakeData->streamName.c_str());
509  }
510 
511  XRootDStreamInfo &sInfo = info->stream[handShakeData->subStreamId];
512 
513  //--------------------------------------------------------------------------
514  // First step - we need to create and initial handshake and send it out
515  //--------------------------------------------------------------------------
516  if( sInfo.status == XRootDStreamInfo::Disconnected ||
517  sInfo.status == XRootDStreamInfo::Broken )
518  {
519  handShakeData->out = GenerateInitialHSProtocol( handShakeData, info,
521  sInfo.status = XRootDStreamInfo::HandShakeSent;
522  return XRootDStatus( stOK, suContinue );
523  }
524 
525  //--------------------------------------------------------------------------
526  // Second step - we got the reply message to the initial handshake
527  //--------------------------------------------------------------------------
528  if( sInfo.status == XRootDStreamInfo::HandShakeSent )
529  {
530  XRootDStatus st = ProcessServerHS( handShakeData, info );
531  if( st.IsOK() )
533  else
534  sInfo.status = XRootDStreamInfo::Broken;
535  return st;
536  }
537 
538  //--------------------------------------------------------------------------
539  // Third step - we got the response to the protocol request, we need
540  // to process it and send out a login request
541  //--------------------------------------------------------------------------
542  if( sInfo.status == XRootDStreamInfo::HandShakeReceived )
543  {
544  XRootDStatus st = ProcessProtocolResp( handShakeData, info );
545 
546  if( !st.IsOK() )
547  {
548  sInfo.status = XRootDStreamInfo::Broken;
549  return st;
550  }
551 
552  if( st.code == suRetry )
553  {
554  handShakeData->out = GenerateProtocol( handShakeData, info,
557  return XRootDStatus( stOK, suRetry );
558  }
559 
560  handShakeData->out = GenerateLogIn( handShakeData, info );
561  sInfo.status = XRootDStreamInfo::LoginSent;
562  return XRootDStatus( stOK, suContinue );
563  }
564 
565  //--------------------------------------------------------------------------
566  // Fourth step - handle the log in response and proceed with the
567  // authentication if required by the server
568  //--------------------------------------------------------------------------
569  if( sInfo.status == XRootDStreamInfo::LoginSent )
570  {
571  XRootDStatus st = ProcessLogInResp( handShakeData, info );
572 
573  if( !st.IsOK() )
574  {
575  sInfo.status = XRootDStreamInfo::Broken;
576  return st;
577  }
578 
579  if( st.IsOK() && st.code == suDone )
580  {
581  //----------------------------------------------------------------------
582  // If it's not our first log in we need to end the previous session
583  // to make sure that the server noticed our disconnection and closed
584  // all the writable handles that we owned
585  //----------------------------------------------------------------------
586  if( !info->firstLogIn )
587  {
588  handShakeData->out = GenerateEndSession( handShakeData, info );
589  sInfo.status = XRootDStreamInfo::EndSessionSent;
590  return XRootDStatus( stOK, suContinue );
591  }
592 
593  sInfo.status = XRootDStreamInfo::Connected;
594  info->firstLogIn = false;
595  return st;
596  }
597 
598  st = DoAuthentication( handShakeData, info );
599  if( !st.IsOK() )
600  sInfo.status = XRootDStreamInfo::Broken;
601  else
602  sInfo.status = XRootDStreamInfo::AuthSent;
603  return st;
604  }
605 
606  //--------------------------------------------------------------------------
607  // Fifth step and later - proceed with the authentication
608  //--------------------------------------------------------------------------
609  if( sInfo.status == XRootDStreamInfo::AuthSent )
610  {
611  XRootDStatus st = DoAuthentication( handShakeData, info );
612 
613  if( !st.IsOK() )
614  {
615  sInfo.status = XRootDStreamInfo::Broken;
616  return st;
617  }
618 
619  if( st.IsOK() && st.code == suDone )
620  {
621  //----------------------------------------------------------------------
622  // If it's not our first log in we need to end the previous session
623  //----------------------------------------------------------------------
624  if( !info->firstLogIn )
625  {
626  handShakeData->out = GenerateEndSession( handShakeData, info );
627  sInfo.status = XRootDStreamInfo::EndSessionSent;
628  return XRootDStatus( stOK, suContinue );
629  }
630 
631  sInfo.status = XRootDStreamInfo::Connected;
632  info->firstLogIn = false;
633  return st;
634  }
635 
636  return st;
637  }
638 
639  //--------------------------------------------------------------------------
640  // The last step - kXR_endsess returned
641  //--------------------------------------------------------------------------
642  if( sInfo.status == XRootDStreamInfo::EndSessionSent )
643  {
644  XRootDStatus st = ProcessEndSessionResp( handShakeData, info );
645 
646  if( st.IsOK() && st.code == suDone )
647  {
648  sInfo.status = XRootDStreamInfo::Connected;
649  }
650  else if( !st.IsOK() )
651  {
652  sInfo.status = XRootDStreamInfo::Broken;
653  }
654 
655  return st;
656  }
657 
658  return XRootDStatus( stOK, suDone );
659  }
660 
661  //----------------------------------------------------------------------------
662  // Hand shake parallel stream
663  //----------------------------------------------------------------------------
664  XRootDStatus XRootDTransport::HandShakeParallel( HandShakeData *handShakeData,
665  AnyObject &channelData )
666  {
667  XRootDChannelInfo *info = 0;
668  channelData.Get( info );
669 
670  if (!info) {
672  "[%s] Internal error: no channel info",
673  handShakeData->streamName.c_str());
674  return XRootDStatus(stFatal, errInternal);
675  }
676 
677  XRootDStreamInfo &sInfo = info->stream[handShakeData->subStreamId];
678 
679  //--------------------------------------------------------------------------
680  // First step - we need to create and initial handshake and send it out
681  //--------------------------------------------------------------------------
682  if( sInfo.status == XRootDStreamInfo::Disconnected ||
683  sInfo.status == XRootDStreamInfo::Broken )
684  {
685  handShakeData->out = GenerateInitialHSProtocol( handShakeData, info,
687  sInfo.status = XRootDStreamInfo::HandShakeSent;
688  return XRootDStatus( stOK, suContinue );
689  }
690 
691  //--------------------------------------------------------------------------
692  // Second step - we got the reply message to the initial handshake,
693  // if successful we need to send bind
694  //--------------------------------------------------------------------------
695  if( sInfo.status == XRootDStreamInfo::HandShakeSent )
696  {
697  XRootDStatus st = ProcessServerHS( handShakeData, info );
698  if( st.IsOK() )
700  else
701  sInfo.status = XRootDStreamInfo::Broken;
702  return st;
703  }
704 
705  //--------------------------------------------------------------------------
706  // Second step bis - we got the response to the protocol request, we need
707  // to process it and send out a bind request
708  //--------------------------------------------------------------------------
709  if( sInfo.status == XRootDStreamInfo::HandShakeReceived )
710  {
711  XRootDStatus st = ProcessProtocolResp( handShakeData, info );
712 
713  if( !st.IsOK() )
714  {
715  sInfo.status = XRootDStreamInfo::Broken;
716  return st;
717  }
718 
719  handShakeData->out = GenerateBind( handShakeData, info );
720  sInfo.status = XRootDStreamInfo::BindSent;
721  return XRootDStatus( stOK, suContinue );
722  }
723 
724  //--------------------------------------------------------------------------
725  // Third step - we got the response to the kXR_bind
726  //--------------------------------------------------------------------------
727  if( sInfo.status == XRootDStreamInfo::BindSent )
728  {
729  XRootDStatus st = ProcessBindResp( handShakeData, info );
730 
731  if( !st.IsOK() )
732  {
733  sInfo.status = XRootDStreamInfo::Broken;
734  return st;
735  }
736  sInfo.status = XRootDStreamInfo::Connected;
737  return XRootDStatus();
738  }
739  return XRootDStatus();
740  }
741 
742  //------------------------------------------------------------------------
743  // @return true if handshake has been done and stream is connected,
744  // false otherwise
745  //------------------------------------------------------------------------
747  AnyObject &channelData )
748  {
749  XRootDChannelInfo *info = 0;
750  channelData.Get( info );
751 
752  if (!info) {
754  "[%s] Internal error: no channel info",
755  handShakeData->streamName.c_str());
756  return false;
757  }
758 
759  XRootDStreamInfo &sInfo = info->stream[handShakeData->subStreamId];
760  return ( sInfo.status == XRootDStreamInfo::Connected );
761  }
762 
763  //----------------------------------------------------------------------------
764  // Check if the stream should be disconnected
765  //----------------------------------------------------------------------------
766  bool XRootDTransport::IsStreamTTLElapsed( time_t inactiveTime,
767  AnyObject &channelData )
768  {
769  XRootDChannelInfo *info = 0;
770  channelData.Get( info );
771 
772  Env *env = DefaultEnv::GetEnv();
773  Log *log = DefaultEnv::GetLog();
774 
775  if (!info) {
777  "Internal error: no channel info, behaving as if TTL has elapsed");
778  return true;
779  }
780 
781  //--------------------------------------------------------------------------
782  // Check the TTL settings for the current server
783  //--------------------------------------------------------------------------
784  int ttl;
785  if( info->serverFlags & kXR_isServer )
786  {
787  ttl = DefaultDataServerTTL;
788  env->GetInt( "DataServerTTL", ttl );
789  }
790  else
791  {
793  env->GetInt( "LoadBalancerTTL", ttl );
794  }
795 
796  //--------------------------------------------------------------------------
797  // See whether we can give a go-ahead for the disconnection
798  //--------------------------------------------------------------------------
799  XrdSysMutexHelper scopedLock( info->mutex );
800  uint16_t allocatedSIDs = info->sidManager->GetNumberOfAllocatedSIDs();
801  log->Dump( XRootDTransportMsg, "[%s] Stream inactive since %lld seconds, "
802  "TTL: %d, allocated SIDs: %d, open files: %d, bound file objects: %d",
803  info->streamName.c_str(), (long long) inactiveTime, ttl, allocatedSIDs,
804  info->openFiles, info->finstcnt.load( std::memory_order_relaxed ) );
805 
806  if( info->openFiles != 0 && info->finstcnt.load( std::memory_order_relaxed ) != 0 )
807  return false;
808 
809  if( !allocatedSIDs && inactiveTime > ttl )
810  return true;
811 
812  return false;
813  }
814 
815  //----------------------------------------------------------------------------
816  // Check the stream is broken - ie. TCP connection got broken and
817  // went undetected by the TCP stack
818  //----------------------------------------------------------------------------
820  AnyObject &channelData )
821  {
822  XRootDChannelInfo *info = 0;
823  channelData.Get( info );
824  Env *env = DefaultEnv::GetEnv();
825  Log *log = DefaultEnv::GetLog();
826 
827  if (!info) {
829  "Internal error: no channel info, behaving as if stream is broken");
830  return true;
831  }
832 
833  int streamTimeout = DefaultStreamTimeout;
834  env->GetInt( "StreamTimeout", streamTimeout );
835 
836  XrdSysMutexHelper scopedLock( info->mutex );
837 
838  const time_t now = time(0);
839  const bool anySID =
840  info->sidManager->IsAnySIDOldAs( now - streamTimeout );
841 
842  log->Dump( XRootDTransportMsg, "[%s] Stream inactive since %lld seconds, "
843  "stream timeout: %d, any SID: %d, wait barrier: %s",
844  info->streamName.c_str(), (long long) inactiveTime, streamTimeout,
845  anySID, Utils::TimeToString(info->waitBarrier).c_str() );
846 
847  if( inactiveTime < streamTimeout )
848  return Status();
849 
850  if( now < info->waitBarrier )
851  return Status();
852 
853  if( !anySID )
854  return Status();
855 
856  return Status( stError, errSocketTimeout );
857  }
858 
859  //----------------------------------------------------------------------------
860  // Multiplex
861  //----------------------------------------------------------------------------
863  {
864  return PathID( 0, 0 );
865  }
866 
867  //----------------------------------------------------------------------------
868  // Multiplex
869  //----------------------------------------------------------------------------
871  AnyObject &channelData,
872  PathID *hint )
873  {
874  XRootDChannelInfo *info = 0;
875  channelData.Get( info );
876 
877  if (!info) {
879  "Internal error: no channel info, cannot multiplex");
880  return PathID(0,0);
881  }
882 
883  XrdSysMutexHelper scopedLock( info->mutex );
884 
885  //--------------------------------------------------------------------------
886  // If we're not connected to a data server or we don't know that yet
887  // we stream through 0
888  //--------------------------------------------------------------------------
889  if( !(info->serverFlags & kXR_isServer) || info->stream.size() == 0 )
890  return PathID( 0, 0 );
891 
892  //--------------------------------------------------------------------------
893  // Select the streams
894  //--------------------------------------------------------------------------
895  Log *log = DefaultEnv::GetLog();
896  uint16_t upStream = 0;
897  uint16_t downStream = 0;
898 
899  if( hint )
900  {
901  upStream = hint->up;
902  downStream = hint->down;
903  }
904  else
905  {
906  upStream = 0;
907  std::vector<bool> connected;
908  connected.reserve( info->stream.size() - 1 );
909  size_t nbConnected = 0;
910  for( size_t i = 1; i < info->stream.size(); ++i )
911  if( info->stream[i].status == XRootDStreamInfo::Connected )
912  {
913  connected.push_back( true );
914  ++nbConnected;
915  }
916  else
917  connected.push_back( false );
918 
919  if( nbConnected == 0 )
920  downStream = 0;
921  else
922  downStream = info->strmSelector->Select( connected );
923  }
924 
925  if( upStream >= info->stream.size() )
926  {
928  "[%s] Up link stream %d does not exist, using 0",
929  info->streamName.c_str(), upStream );
930  upStream = 0;
931  }
932 
933  if( downStream >= info->stream.size() )
934  {
936  "[%s] Down link stream %d does not exist, using 0",
937  info->streamName.c_str(), downStream );
938  downStream = 0;
939  }
940 
941  //--------------------------------------------------------------------------
942  // Modify the message
943  //--------------------------------------------------------------------------
944  UnMarshallRequest( msg );
946  switch( hdr->requestid )
947  {
948  //------------------------------------------------------------------------
949  // Read - we update the path id to tell the server where we want to
950  // get the response, but we still send the request through stream 0
951  // We need to allocate space for read_args if we don't have it
952  // included yet
953  //------------------------------------------------------------------------
954  case kXR_read:
955  {
956  if( msg->GetSize() < sizeof(ClientReadRequest) + 8 )
957  {
958  msg->ReAllocate( sizeof(ClientReadRequest) + 8 );
959  void *newBuf = msg->GetBuffer(sizeof(ClientReadRequest));
960  memset( newBuf, 0, 8 );
962  req->dlen += 8;
963  }
964  read_args *args = (read_args*)msg->GetBuffer(sizeof(ClientReadRequest));
965  args->pathid = info->stream[downStream].pathId;
966  break;
967  }
968 
969 
970  //------------------------------------------------------------------------
971  // PgRead - we update the path id to tell the server where we want to
972  // get the response, but we still send the request through stream 0
973  // We need to allocate space for ClientPgReadReqArgs if we don't have it
974  // included yet
975  //------------------------------------------------------------------------
976  case kXR_pgread:
977  {
978  if( msg->GetSize() < sizeof( ClientPgReadRequest ) + sizeof( ClientPgReadReqArgs ) )
979  {
980  msg->ReAllocate( sizeof( ClientPgReadRequest ) + sizeof( ClientPgReadReqArgs ) );
981  void *newBuf = msg->GetBuffer( sizeof( ClientPgReadRequest ) );
982  memset( newBuf, 0, sizeof( ClientPgReadReqArgs ) );
984  req->dlen += sizeof( ClientPgReadReqArgs );
985  }
986  ClientPgReadReqArgs *args = reinterpret_cast<ClientPgReadReqArgs*>(
987  msg->GetBuffer( sizeof( ClientPgReadRequest ) ) );
988  args->pathid = info->stream[downStream].pathId;
989  break;
990  }
991 
992  //------------------------------------------------------------------------
993  // ReadV - the situation is identical to read but we don't need any
994  // additional structures to specify the return path
995  //------------------------------------------------------------------------
996  case kXR_readv:
997  {
999  req->pathid = info->stream[downStream].pathId;
1000  break;
1001  }
1002 
1003  //------------------------------------------------------------------------
1004  // Write - multiplexing writes doesn't work properly in the server
1005  //------------------------------------------------------------------------
1006  case kXR_write:
1007  {
1008 // ClientWriteRequest *req = (ClientWriteRequest*)msg->GetBuffer();
1009 // req->pathid = info->stream[downStream].pathId;
1010  break;
1011  }
1012 
1013  //------------------------------------------------------------------------
1014  // WriteV - multiplexing writes doesn't work properly in the server
1015  //------------------------------------------------------------------------
1016  case kXR_writev:
1017  {
1018 // ClientWriteVRequest *req = (ClientWriteVRequest*)msg->GetBuffer();
1019 // req->pathid = info->stream[downStream].pathId;
1020  break;
1021  }
1022 
1023  //------------------------------------------------------------------------
1024  // PgWrite - multiplexing writes doesn't work properly in the server
1025  //------------------------------------------------------------------------
1026  case kXR_pgwrite:
1027  {
1028 // ClientWriteVRequest *req = (ClientWriteVRequest*)msg->GetBuffer();
1029 // req->pathid = info->stream[downStream].pathId;
1030  break;
1031  }
1032  };
1033  MarshallRequest( msg );
1034  return PathID( upStream, downStream );
1035  }
1036 
1037  //----------------------------------------------------------------------------
1038  // Return a number of substreams per stream that should be created
1039  // This depends on the environment and whether we are connected to
1040  // a data server or not
1041  //----------------------------------------------------------------------------
1043  {
1044  XRootDChannelInfo *info = 0;
1045  channelData.Get( info );
1046 
1047  if (!info) {
1048  DefaultEnv::GetLog()->Error(XRootDTransportMsg, "Internal error: no channel info");
1049  return 1;
1050  }
1051 
1052  XrdSysMutexHelper scopedLock( info->mutex );
1053 
1054  //--------------------------------------------------------------------------
1055  // If the connection has been opened in order to orchestrate a TPC or
1056  // the remote server is a Manager or Metamanager we will need only one
1057  // (control) stream.
1058  //--------------------------------------------------------------------------
1059  if( info->istpc || !(info->serverFlags & kXR_isServer ) ) return 1;
1060 
1061  //--------------------------------------------------------------------------
1062  // Number of streams requested by user
1063  //--------------------------------------------------------------------------
1064  uint16_t ret = info->stream.size();
1065 
1067  int nodata = DefaultTlsNoData;
1068  env->GetInt( "TlsNoData", nodata );
1069 
1070  // Does the server require the stream 0 to be encrypted?
1071  bool srvTlsStrm0 = ( info->serverFlags & kXR_gotoTLS ) ||
1072  ( info->serverFlags & kXR_tlsLogin ) ||
1073  ( info->serverFlags & kXR_tlsSess );
1074  // Does the server NOT require the data streams to be encrypted?
1075  bool srvNoTlsData = !( info->serverFlags & kXR_tlsData );
1076  // Does the user require the stream 0 to be encrypted?
1077  bool usrTlsStrm0 = info->encrypted;
1078  // Does the user NOT require the data streams to be encrypted?
1079  bool usrNoTlsData = !info->encrypted || ( info->encrypted && nodata );
1080 
1081  if( ( usrTlsStrm0 && usrNoTlsData && srvNoTlsData ) ||
1082  ( srvTlsStrm0 && srvNoTlsData && usrNoTlsData ) )
1083  {
1084  //------------------------------------------------------------------------
1085  // The server or user asked us to encrypt stream 0, but to send the data
1086  // (read/write) using a plain TCP connection
1087  //------------------------------------------------------------------------
1088  if( ret == 1 ) ++ret;
1089  }
1090 
1091  if( ret > info->stream.size() )
1092  {
1093  info->stream.resize( ret );
1094  info->strmSelector->AdjustQueues( ret );
1095  }
1096 
1097  return ret;
1098  }
1099 
1100  //----------------------------------------------------------------------------
1101  // Marshall
1102  //----------------------------------------------------------------------------
1104  {
1105  ClientRequest *req = (ClientRequest*)msg;
1106  switch( req->header.requestid )
1107  {
1108  //------------------------------------------------------------------------
1109  // kXR_protocol
1110  //------------------------------------------------------------------------
1111  case kXR_protocol:
1112  req->protocol.clientpv = htonl( req->protocol.clientpv );
1113  break;
1114 
1115  //------------------------------------------------------------------------
1116  // kXR_login
1117  //------------------------------------------------------------------------
1118  case kXR_login:
1119  req->login.pid = htonl( req->login.pid );
1120  break;
1121 
1122  //------------------------------------------------------------------------
1123  // kXR_locate
1124  //------------------------------------------------------------------------
1125  case kXR_locate:
1126  req->locate.options = htons( req->locate.options );
1127  break;
1128 
1129  //------------------------------------------------------------------------
1130  // kXR_query
1131  //------------------------------------------------------------------------
1132  case kXR_query:
1133  req->query.infotype = htons( req->query.infotype );
1134  break;
1135 
1136  //------------------------------------------------------------------------
1137  // kXR_truncate
1138  //------------------------------------------------------------------------
1139  case kXR_truncate:
1140  req->truncate.offset = htonll( req->truncate.offset );
1141  break;
1142 
1143  //------------------------------------------------------------------------
1144  // kXR_mkdir
1145  //------------------------------------------------------------------------
1146  case kXR_mkdir:
1147  req->mkdir.mode = htons( req->mkdir.mode );
1148  break;
1149 
1150  //------------------------------------------------------------------------
1151  // kXR_chmod
1152  //------------------------------------------------------------------------
1153  case kXR_chmod:
1154  req->chmod.mode = htons( req->chmod.mode );
1155  break;
1156 
1157  //------------------------------------------------------------------------
1158  // kXR_open
1159  //------------------------------------------------------------------------
1160  case kXR_open:
1161  req->open.mode = htons( req->open.mode );
1162  req->open.options = htons( req->open.options );
1163  break;
1164 
1165  //------------------------------------------------------------------------
1166  // kXR_read
1167  //------------------------------------------------------------------------
1168  case kXR_read:
1169  req->read.offset = htonll( req->read.offset );
1170  req->read.rlen = htonl( req->read.rlen );
1171  break;
1172 
1173  //------------------------------------------------------------------------
1174  // kXR_write
1175  //------------------------------------------------------------------------
1176  case kXR_write:
1177  req->write.offset = htonll( req->write.offset );
1178  break;
1179 
1180  //------------------------------------------------------------------------
1181  // kXR_mv
1182  //------------------------------------------------------------------------
1183  case kXR_mv:
1184  req->mv.arg1len = htons( req->mv.arg1len );
1185  break;
1186 
1187  //------------------------------------------------------------------------
1188  // kXR_readv
1189  //------------------------------------------------------------------------
1190  case kXR_readv:
1191  {
1192  uint16_t numChunks = (req->readv.dlen)/16;
1193  readahead_list *dataChunk = (readahead_list*)( msg + 24 );
1194  for( size_t i = 0; i < numChunks; ++i )
1195  {
1196  dataChunk[i].rlen = htonl( dataChunk[i].rlen );
1197  dataChunk[i].offset = htonll( dataChunk[i].offset );
1198  }
1199  break;
1200  }
1201 
1202  //------------------------------------------------------------------------
1203  // kXR_writev
1204  //------------------------------------------------------------------------
1205  case kXR_writev:
1206  {
1207  uint16_t numChunks = (req->writev.dlen)/16;
1208  XrdProto::write_list *wrtList =
1209  reinterpret_cast<XrdProto::write_list*>( msg + 24 );
1210  for( size_t i = 0; i < numChunks; ++i )
1211  {
1212  wrtList[i].wlen = htonl( wrtList[i].wlen );
1213  wrtList[i].offset = htonll( wrtList[i].offset );
1214  }
1215 
1216  break;
1217  }
1218 
1219  case kXR_pgread:
1220  {
1221  req->pgread.offset = htonll( req->pgread.offset );
1222  req->pgread.rlen = htonl( req->pgread.rlen );
1223  break;
1224  }
1225 
1226  case kXR_pgwrite:
1227  {
1228  req->pgwrite.offset = htonll( req->pgwrite.offset );
1229  break;
1230  }
1231 
1232  //------------------------------------------------------------------------
1233  // kXR_prepare
1234  //------------------------------------------------------------------------
1235  case kXR_prepare:
1236  {
1237  req->prepare.optionX = htons( req->prepare.optionX );
1238  req->prepare.port = htons( req->prepare.port );
1239  break;
1240  }
1241 
1242  case kXR_chkpoint:
1243  {
1244  if( req->chkpoint.opcode == kXR_ckpXeq )
1245  MarshallRequest( msg + 24 );
1246  break;
1247  }
1248  };
1249 
1250  req->header.requestid = htons( req->header.requestid );
1251  req->header.dlen = htonl( req->header.dlen );
1252  return XRootDStatus();
1253  }
1254 
1255  //----------------------------------------------------------------------------
1256  // Unmarshall the request - sometimes the requests need to be rewritten,
1257  // so we need to unmarshall them
1258  //----------------------------------------------------------------------------
1260  {
1261  if( !msg->IsMarshalled() ) return XRootDStatus( stOK, suAlreadyDone );
1262  // We rely on the marshaling process to be symmetric!
1263  // First we unmarshall the request ID and the length because
1264  // MarshallRequest() relies on these, and then we need to unmarshall these
1265  // two again, because they get marshalled in MarshallRequest().
1266  // All this is pretty damn ugly and should be rewritten.
1267  ClientRequest *req = (ClientRequest*)msg->GetBuffer();
1268  req->header.requestid = htons( req->header.requestid );
1269  req->header.dlen = htonl( req->header.dlen );
1270  XRootDStatus st = MarshallRequest( msg );
1271  req->header.requestid = htons( req->header.requestid );
1272  req->header.dlen = htonl( req->header.dlen );
1273  msg->SetIsMarshalled( false );
1274  return st;
1275  }
1276 
1277  //----------------------------------------------------------------------------
1278  // Unmarshall the body of the incoming message
1279  //----------------------------------------------------------------------------
1281  {
1282  ServerResponse *m = (ServerResponse *)msg->GetBuffer();
1283 
1284  //--------------------------------------------------------------------------
1285  // kXR_ok
1286  //--------------------------------------------------------------------------
1287  if( m->hdr.status == kXR_ok )
1288  {
1289  switch( reqType )
1290  {
1291  //----------------------------------------------------------------------
1292  // kXR_protocol
1293  //----------------------------------------------------------------------
1294  case kXR_protocol:
1295  if( m->hdr.dlen < 8 )
1296  return XRootDStatus( stError, errInvalidMessage, 0, "kXR_protocol: body too short." );
1297  m->body.protocol.pval = ntohl( m->body.protocol.pval );
1298  m->body.protocol.flags = ntohl( m->body.protocol.flags );
1299  break;
1300  }
1301  }
1302  //--------------------------------------------------------------------------
1303  // kXR_error
1304  //--------------------------------------------------------------------------
1305  else if( m->hdr.status == kXR_error )
1306  {
1307  if( m->hdr.dlen < 4 )
1308  return XRootDStatus( stError, errInvalidMessage, 0, "kXR_error: body too short." );
1309  m->body.error.errnum = ntohl( m->body.error.errnum );
1310  }
1311 
1312  //--------------------------------------------------------------------------
1313  // kXR_wait
1314  //--------------------------------------------------------------------------
1315  else if( m->hdr.status == kXR_wait )
1316  {
1317  if( m->hdr.dlen < 4 )
1318  return XRootDStatus( stError, errInvalidMessage, 0, "kXR_wait: body too short." );
1319  m->body.wait.seconds = htonl( m->body.wait.seconds );
1320  }
1321 
1322  //--------------------------------------------------------------------------
1323  // kXR_redirect
1324  //--------------------------------------------------------------------------
1325  else if( m->hdr.status == kXR_redirect )
1326  {
1327  if( m->hdr.dlen < 4 )
1328  return XRootDStatus( stError, errInvalidMessage, 0, "kXR_redirect: body too short." );
1329  m->body.redirect.port = htonl( m->body.redirect.port );
1330  }
1331 
1332  //--------------------------------------------------------------------------
1333  // kXR_waitresp
1334  //--------------------------------------------------------------------------
1335  else if( m->hdr.status == kXR_waitresp )
1336  {
1337  if( m->hdr.dlen < 4 )
1338  return XRootDStatus( stError, errInvalidMessage, 0, "kXR_waitresp: body too short." );
1339  m->body.waitresp.seconds = htonl( m->body.waitresp.seconds );
1340  }
1341 
1342  //--------------------------------------------------------------------------
1343  // kXR_attn
1344  //--------------------------------------------------------------------------
1345  else if( m->hdr.status == kXR_attn )
1346  {
1347  if( m->hdr.dlen < 4 )
1348  return XRootDStatus( stError, errInvalidMessage, 0, "kXR_attn: body too short." );
1349  m->body.attn.actnum = htonl( m->body.attn.actnum );
1350  }
1351 
1352  return XRootDStatus();
1353  }
1354 
1355  //------------------------------------------------------------------------
1357  //------------------------------------------------------------------------
1359  {
1360  //--------------------------------------------------------------------------
1361  // Calculate the crc32c before the unmarshaling the body!
1362  //--------------------------------------------------------------------------
1364  char *buffer = msg.GetBuffer( 8 + sizeof( rspst->bdy.crc32c ) );
1365  size_t length = rspst->hdr.dlen - sizeof( rspst->bdy.crc32c );
1366  uint32_t crcval = XrdOucCRC::Calc32C( buffer, length );
1367 
1368  size_t stlen = sizeof( ServerResponseStatus );
1369  switch( reqType )
1370  {
1371  case kXR_pgread:
1372  {
1373  stlen += sizeof( ServerResponseBody_pgRead );
1374  break;
1375  }
1376 
1377  case kXR_pgwrite:
1378  {
1379  stlen += sizeof( ServerResponseBody_pgWrite );
1380  break;
1381  }
1382  }
1383 
1384  if( msg.GetSize() < stlen ) return XRootDStatus( stError, errInvalidMessage, 0,
1385  "kXR_status: invalid message size." );
1386 
1387  rspst->bdy.crc32c = ntohl( rspst->bdy.crc32c );
1388  rspst->bdy.dlen = ntohl( rspst->bdy.dlen );
1389 
1390  switch( reqType )
1391  {
1392  case kXR_pgread:
1393  {
1395  pgrdbdy->offset = ntohll( pgrdbdy->offset );
1396  break;
1397  }
1398 
1399  case kXR_pgwrite:
1400  {
1402  pgwrtbdy->offset = ntohll( pgwrtbdy->offset );
1403  break;
1404  }
1405  }
1406 
1407  //--------------------------------------------------------------------------
1408  // Do the integrity checks
1409  //--------------------------------------------------------------------------
1410  if( crcval != rspst->bdy.crc32c )
1411  {
1412  return XRootDStatus( stError, errDataError, 0, "kXR_status response header "
1413  "corrupted (crc32c integrity check failed)." );
1414  }
1415 
1416  if( rspst->hdr.streamid[0] != rspst->bdy.streamID[0] ||
1417  rspst->hdr.streamid[1] != rspst->bdy.streamID[1] )
1418  {
1419  return XRootDStatus( stError, errDataError, 0, "response header corrupted "
1420  "(stream ID mismatch)." );
1421  }
1422 
1423 
1424 
1425  if( rspst->bdy.requestid + kXR_1stRequest != reqType )
1426  {
1427  return XRootDStatus( stError, errDataError, 0, "kXR_status response header corrupted "
1428  "(request ID mismatch)." );
1429  }
1430 
1431  return XRootDStatus();
1432  }
1433 
1435  {
1437  uint16_t reqType = rsp->status.bdy.requestid + kXR_1stRequest;
1438 
1439  switch( reqType )
1440  {
1441  case kXR_pgwrite:
1442  {
1443  //--------------------------------------------------------------------------
1444  // If there's no additional data there's nothing to unmarshal
1445  //--------------------------------------------------------------------------
1446  if( rsp->status.bdy.dlen == 0 ) return XRootDStatus();
1447  //--------------------------------------------------------------------------
1448  // If there's not enough data to form correction-segment report an error
1449  //--------------------------------------------------------------------------
1450  if( size_t( rsp->status.bdy.dlen ) < sizeof( ServerResponseBody_pgWrCSE ) )
1452  "kXR_status: invalid message size." );
1453 
1454  //--------------------------------------------------------------------------
1455  // Calculate the crc32c for the additional data
1456  //--------------------------------------------------------------------------
1458  cse->cseCRC = ntohl( cse->cseCRC );
1459  size_t length = rsp->status.bdy.dlen - sizeof( uint32_t );
1460  void* buffer = msg.GetBuffer( sizeof( ServerResponseV2 ) + sizeof( uint32_t ) );
1461  uint32_t crcval = XrdOucCRC::Calc32C( buffer, length );
1462 
1463  //--------------------------------------------------------------------------
1464  // Do the integrity checks
1465  //--------------------------------------------------------------------------
1466  if( crcval != cse->cseCRC )
1467  {
1468  return XRootDStatus( stError, errDataError, 0, "kXR_status response header "
1469  "corrupted (crc32c integrity check failed)." );
1470  }
1471 
1472  cse->dlFirst = ntohs( cse->dlFirst );
1473  cse->dlLast = ntohs( cse->dlLast );
1474 
1475  size_t pgcnt = ( rsp->status.bdy.dlen - sizeof( ServerResponseBody_pgWrCSE ) ) /
1476  sizeof( kXR_int64 );
1477  kXR_int64 *pgoffs = (kXR_int64*)msg.GetBuffer( sizeof( ServerResponseV2 ) +
1478  sizeof( ServerResponseBody_pgWrCSE ) );
1479 
1480  for( size_t i = 0; i < pgcnt; ++i )
1481  pgoffs[i] = ntohll( pgoffs[i] );
1482 
1483  return XRootDStatus();
1484  break;
1485  }
1486 
1487  default:
1488  break;
1489  }
1490 
1492  }
1493 
1494  //----------------------------------------------------------------------------
1495  // Unmarshall the header of the incoming message
1496  //----------------------------------------------------------------------------
1498  {
1500  header->status = ntohs( header->status );
1501  header->dlen = ntohl( header->dlen );
1502  }
1503 
1504  //----------------------------------------------------------------------------
1505  // Log server error response
1506  //----------------------------------------------------------------------------
1508  {
1509  Log *log = DefaultEnv::GetLog();
1510  ServerResponse *rsp = (ServerResponse *)msg.GetBuffer();
1511  char *errmsg = new char[rsp->hdr.dlen-3]; errmsg[rsp->hdr.dlen-4] = 0;
1512  memcpy( errmsg, rsp->body.error.errmsg, rsp->hdr.dlen-4 );
1513  log->Error( XRootDTransportMsg, "Server responded with an error [%d]: %s",
1514  rsp->body.error.errnum, errmsg );
1515  delete [] errmsg;
1516  }
1517 
1518  //------------------------------------------------------------------------
1519  // Number of currently connected data streams
1520  //------------------------------------------------------------------------
1522  {
1523  XRootDChannelInfo *info = 0;
1524  channelData.Get( info );
1525 
1526  if (!info) {
1527  DefaultEnv::GetLog()->Error(XRootDTransportMsg, "Internal error: no channel info");
1528  return 0;
1529  }
1530 
1531  XrdSysMutexHelper scopedLock( info->mutex );
1532 
1533  uint16_t nbConnected = 0;
1534  for( size_t i = 1; i < info->stream.size(); ++i )
1535  if( info->stream[i].status == XRootDStreamInfo::Connected )
1536  ++nbConnected;
1537 
1538  return nbConnected;
1539  }
1540 
1541  //----------------------------------------------------------------------------
1542  // The stream has been disconnected, do the cleanups
1543  //----------------------------------------------------------------------------
1545  uint16_t subStreamId )
1546  {
1547  XRootDChannelInfo *info = 0;
1548  channelData.Get( info );
1549 
1550  if (!info) {
1551  DefaultEnv::GetLog()->Error(XRootDTransportMsg, "Internal error: no channel info");
1552  return;
1553  }
1554 
1555  XrdSysMutexHelper scopedLock( info->mutex );
1556 
1557  CleanUpProtection( info );
1558 
1559  if( !info->stream.empty() )
1560  {
1561  XRootDStreamInfo &sInfo = info->stream[subStreamId];
1563  }
1564 
1565  if( subStreamId == 0 )
1566  {
1567  info->sidManager->ReleaseAllTimedOut();
1568  info->sentOpens.clear();
1569  info->sentCloses.clear();
1570  info->openFiles = 0;
1571  info->waitBarrier = 0;
1572  }
1573  }
1574 
1575  //------------------------------------------------------------------------
1576  // Query the channel
1577  //------------------------------------------------------------------------
1579  AnyObject &result,
1580  AnyObject &channelData )
1581  {
1582  XRootDChannelInfo *info = 0;
1583  channelData.Get( info );
1584 
1585  if (!info)
1586  return XRootDStatus(stFatal, errInternal);
1587 
1588  XrdSysMutexHelper scopedLock( info->mutex );
1589 
1590  switch( query )
1591  {
1592  //------------------------------------------------------------------------
1593  // Protocol name
1594  //------------------------------------------------------------------------
1595  case TransportQuery::Name:
1596  result.Set( (const char*)"XRootD", false );
1597  return Status();
1598 
1599  //------------------------------------------------------------------------
1600  // Authentication
1601  //------------------------------------------------------------------------
1602  case TransportQuery::Auth:
1603  result.Set( new std::string( info->authProtocolName ), false );
1604  return Status();
1605 
1606  //------------------------------------------------------------------------
1607  // Server flags
1608  //------------------------------------------------------------------------
1610  result.Set( new int( info->serverFlags ), false );
1611  return Status();
1612 
1613  //------------------------------------------------------------------------
1614  // Protocol version
1615  //------------------------------------------------------------------------
1617  result.Set( new int( info->protocolVersion ), false );
1618  return Status();
1619 
1621  result.Set( new bool( info->encrypted ), false );
1622  return Status();
1623  };
1624  return Status( stError, errQueryNotSupported );
1625  }
1626 
1627  //----------------------------------------------------------------------------
1628  // Check whether the transport can hijack the message
1629  //----------------------------------------------------------------------------
1631  uint16_t subStream,
1632  AnyObject &channelData )
1633  {
1634  XRootDChannelInfo *info = 0;
1635  channelData.Get( info );
1636  if( !info ) return NoAction;
1637  XrdSysMutexHelper scopedLock( info->mutex );
1638  Log *log = DefaultEnv::GetLog();
1639 
1640  //--------------------------------------------------------------------------
1641  // Update the substream queues
1642  //--------------------------------------------------------------------------
1643  info->strmSelector->MsgReceived( subStream );
1644 
1645  //--------------------------------------------------------------------------
1646  // Check whether this message is a response to a request that has
1647  // timed out, and if so, drop it
1648  //--------------------------------------------------------------------------
1649  ServerResponse *rsp = (ServerResponse*)msg.GetBuffer();
1650  if( rsp->hdr.status == kXR_attn )
1651  {
1652  return NoAction;
1653  }
1654 
1655  if( info->sidManager->IsTimedOut( rsp->hdr.streamid ) )
1656  {
1657  log->Error( XRootDTransportMsg, "Message %p, stream [%d, %d] is a "
1658  "response that we're no longer interested in (timed out)",
1659  (void*)&msg, rsp->hdr.streamid[0], rsp->hdr.streamid[1] );
1660  //------------------------------------------------------------------------
1661  // If it is kXR_waitresp there will be another one,
1662  // so we don't release the sid yet
1663  //------------------------------------------------------------------------
1664  if( rsp->hdr.status != kXR_waitresp )
1665  info->sidManager->ReleaseTimedOut( rsp->hdr.streamid );
1666  //------------------------------------------------------------------------
1667  // If it is a successful response to an open request
1668  // that timed out, we need to send a close
1669  //------------------------------------------------------------------------
1670  uint16_t sid; memcpy( &sid, rsp->hdr.streamid, 2 );
1671  std::set<uint16_t>::iterator sidIt = info->sentOpens.find( sid );
1672  if( sidIt != info->sentOpens.end() )
1673  {
1674  info->sentOpens.erase( sidIt );
1675  if( rsp->hdr.status == kXR_ok ) return RequestClose;
1676  }
1677  return DigestMsg;
1678  }
1679 
1680  //--------------------------------------------------------------------------
1681  // If we have a wait or waitresp
1682  //--------------------------------------------------------------------------
1683  uint32_t seconds = 0;
1684  if( rsp->hdr.status == kXR_wait )
1685  seconds = ntohl( rsp->body.wait.seconds ) + 5; // we need extra time
1686  // to re-send the request
1687  else if( rsp->hdr.status == kXR_waitresp )
1688  {
1689  seconds = ntohl( rsp->body.waitresp.seconds );
1690 
1691  log->Dump( XRootDMsg, "[%s] Got kXR_waitresp response of %u seconds, "
1692  "setting up wait barrier.",
1693  info->streamName.c_str(),
1694  seconds );
1695  }
1696 
1697  time_t barrier = time(0) + seconds;
1698  if( info->waitBarrier < barrier )
1699  info->waitBarrier = barrier;
1700 
1701  //--------------------------------------------------------------------------
1702  // If we got a response to an open request, we may need to bump the counter
1703  // of open files
1704  //--------------------------------------------------------------------------
1705  uint16_t sid; memcpy( &sid, rsp->hdr.streamid, 2 );
1706  std::set<uint16_t>::iterator sidIt = info->sentOpens.find( sid );
1707  if( sidIt != info->sentOpens.end() )
1708  {
1709  if( rsp->hdr.status == kXR_waitresp )
1710  return NoAction;
1711  info->sentOpens.erase( sidIt );
1712  if( rsp->hdr.status == kXR_ok )
1713  {
1714  ++info->openFiles;
1715  info->finstcnt.fetch_add( 1, std::memory_order_relaxed ); // another file File object instance has been bound with this connection
1716  }
1717  return NoAction;
1718  }
1719 
1720  //--------------------------------------------------------------------------
1721  // If we got a response to a close, we may need to decrement the counter of
1722  // open files
1723  //--------------------------------------------------------------------------
1724  sidIt = info->sentCloses.find( sid );
1725  if( sidIt != info->sentCloses.end() )
1726  {
1727  if( rsp->hdr.status == kXR_waitresp )
1728  return NoAction;
1729  info->sentCloses.erase( sidIt );
1730  --info->openFiles;
1731  return NoAction;
1732  }
1733  return NoAction;
1734  }
1735 
1736  //----------------------------------------------------------------------------
1737  // Notify the transport about a message having been sent
1738  //----------------------------------------------------------------------------
1740  uint16_t subStream,
1741  uint32_t bytesSent,
1742  AnyObject &channelData )
1743  {
1744  // Called when a message has been sent. For messages that return on a
1745  // different pathid (and hence may use a different poller) it is possible
1746  // that the server has already replied and the reply will trigger
1747  // MessageReceived() before this method has been called. However for open
1748  // and close this is never the case and this method is used for tracking
1749  // only those.
1750  XRootDChannelInfo *info = 0;
1751  channelData.Get( info );
1752  if( !info ) return;
1753  XrdSysMutexHelper scopedLock( info->mutex );
1754  ClientRequest *req = (ClientRequest*)msg->GetBuffer();
1755  uint16_t reqid = ntohs( req->header.requestid );
1756 
1757 
1758  //--------------------------------------------------------------------------
1759  // We need to track opens to know if we can close streams due to idleness
1760  //--------------------------------------------------------------------------
1761  uint16_t sid;
1762  memcpy( &sid, req->header.streamid, 2 );
1763 
1764  if( reqid == kXR_open )
1765  info->sentOpens.insert( sid );
1766  else if( reqid == kXR_close )
1767  info->sentCloses.insert( sid );
1768  }
1769 
1770 
1771  //----------------------------------------------------------------------------
1772  // Get signature for given message
1773  //----------------------------------------------------------------------------
1775  {
1776  XRootDChannelInfo *info = 0;
1777  channelData.Get( info );
1778  return GetSignature( toSign, sign, info );
1779  }
1780 
1781  //------------------------------------------------------------------------
1783  //------------------------------------------------------------------------
1785  Message *&sign,
1786  XRootDChannelInfo *info )
1787  {
1788  XrdSysRWLockHelper scope( pSecUnloadHandler->lock );
1789  if( pSecUnloadHandler->unloaded ) return Status( stError, errInvalidOp );
1790 
1791  ClientRequest *thereq = reinterpret_cast<ClientRequest*>( toSign->GetBuffer() );
1792  if( !info ) return Status( stError, errInternal );
1793  if( info->protection )
1794  {
1795  SecurityRequest *newreq = 0;
1796  // check if we have to secure the request in the first place
1797  if( !( NEED2SECURE ( info->protection )( *thereq ) ) ) return Status();
1798  // secure (sign/encrypt) the request
1799  int rc = info->protection->Secure( newreq, *thereq, 0 );
1800  // there was an error
1801  if( rc < 0 )
1802  return Status( stError, errInternal, -rc );
1803 
1804  sign = new Message();
1805  sign->Grab( reinterpret_cast<char*>( newreq ), rc );
1806  }
1807 
1808  return Status();
1809  }
1810 
1811  //------------------------------------------------------------------------
1813  //------------------------------------------------------------------------
1815  {
1816  XRootDChannelInfo *info = 0;
1817  channelData.Get( info );
1818  if( info->finstcnt.load( std::memory_order_relaxed ) > 0 )
1819  info->finstcnt.fetch_sub( 1, std::memory_order_relaxed );
1820  }
1821 
1822  //----------------------------------------------------------------------------
1823  // Wait before exit
1824  //----------------------------------------------------------------------------
1826  {
1827  XrdSysRWLockHelper scope( pSecUnloadHandler->lock, false ); // obtain write lock
1828  pSecUnloadHandler->unloaded = true;
1829  }
1830 
1831  //----------------------------------------------------------------------------
1832  // @return : true if encryption should be turned on, false otherwise
1833  //----------------------------------------------------------------------------
1835  AnyObject &channelData )
1836  {
1837  XRootDChannelInfo *info = 0;
1838  channelData.Get( info );
1839 
1841  int notlsok = DefaultNoTlsOK;
1842  env->GetInt( "NoTlsOK", notlsok );
1843 
1844 
1845  if( notlsok )
1846  return info->encrypted;
1847 
1848  // Did the server instructed us to switch to TLS right away?
1849  if( info->serverFlags & kXR_gotoTLS )
1850  {
1851  info->encrypted = true;
1852  return true ;
1853  }
1854 
1855  XRootDStreamInfo &sInfo = info->stream[handShakeData->subStreamId];
1856 
1857  //--------------------------------------------------------------------------
1858  // The control stream (sub-stream 0) might need to switch to TLS before
1859  // login or after login
1860  //--------------------------------------------------------------------------
1861  if( handShakeData->subStreamId == 0 )
1862  {
1863  //------------------------------------------------------------------------
1864  // We are about to login and the server asked to start encrypting
1865  // before login
1866  //------------------------------------------------------------------------
1867  if( ( sInfo.status == XRootDStreamInfo::LoginSent ) &&
1868  ( info->serverFlags & kXR_tlsLogin ) )
1869  {
1870  info->encrypted = true;
1871  return true;
1872  }
1873 
1874  //--------------------------------------------------------------------
1875  // The hand-shake is done and the server requested to encrypt the session
1876  //--------------------------------------------------------------------
1877  if( (sInfo.status == XRootDStreamInfo::Connected ||
1878  //--------------------------------------------------------------------
1879  // we really need to turn on TLS before we sent kXR_endsess and we
1880  // are about to do so (1st enable encryption, then send kXR_endsess)
1881  //--------------------------------------------------------------------
1883  ( info->serverFlags & kXR_tlsSess ) )
1884  {
1885  info->encrypted = true;
1886  return true;
1887  }
1888  }
1889  //--------------------------------------------------------------------------
1890  // A data stream (sub-stream > 0) if need be will be switched to TLS before
1891  // bind.
1892  //--------------------------------------------------------------------------
1893  else
1894  {
1895  //------------------------------------------------------------------------
1896  // We are about to bind a data stream and the server asked to start
1897  // encrypting before bind
1898  //------------------------------------------------------------------------
1899  if( ( sInfo.status == XRootDStreamInfo::BindSent ) &&
1900  ( info->serverFlags & kXR_tlsData ) )
1901  {
1902  info->encrypted = true;
1903  return true;
1904  }
1905  }
1906 
1907  return false;
1908  }
1909 
1910  //------------------------------------------------------------------------
1911  // Get bind preference for the next data stream
1912  //------------------------------------------------------------------------
1914  AnyObject &channelData )
1915  {
1916  XRootDChannelInfo *info = 0;
1917  channelData.Get( info );
1918 
1919  if(!info || !info->bindSelector)
1920  return url;
1921 
1922  return URL( info->bindSelector->Get() );
1923  }
1924 
1925  //----------------------------------------------------------------------------
1926  // Generate the message to be sent as an initial handshake
1927  // (handshake+kXR_protocol)
1928  //----------------------------------------------------------------------------
1929  Message *XRootDTransport::GenerateInitialHSProtocol( HandShakeData *hsData,
1930  XRootDChannelInfo *info,
1931  kXR_char expect )
1932  {
1933  Log *log = DefaultEnv::GetLog();
1934  log->Debug( XRootDTransportMsg,
1935  "[%s] Sending out the initial hand shake + kXR_protocol",
1936  hsData->streamName.c_str() );
1937 
1938  Message *msg = new Message();
1939 
1940  msg->Allocate( 20+sizeof(ClientProtocolRequest) );
1941  msg->Zero();
1942 
1944  init->fourth = htonl(4);
1945  init->fifth = htonl(2012);
1946 
1948  InitProtocolReq( proto, info, expect );
1949 
1950  return msg;
1951  }
1952 
1953  //------------------------------------------------------------------------
1954  // Generate the protocol message
1955  //------------------------------------------------------------------------
1956  Message *XRootDTransport::GenerateProtocol( HandShakeData *hsData,
1957  XRootDChannelInfo *info,
1958  kXR_char expect )
1959  {
1960  Log *log = DefaultEnv::GetLog();
1961  log->Debug( XRootDTransportMsg,
1962  "[%s] Sending out the kXR_protocol",
1963  hsData->streamName.c_str() );
1964 
1965  Message *msg = new Message();
1966  msg->Allocate( sizeof(ClientProtocolRequest) );
1967  msg->Zero();
1968 
1969  ClientProtocolRequest *proto = (ClientProtocolRequest *)msg->GetBuffer();
1970  InitProtocolReq( proto, info, expect );
1971 
1972  return msg;
1973  }
1974 
1975  //------------------------------------------------------------------------
1976  // Initialize protocol request
1977  //------------------------------------------------------------------------
1978  void XRootDTransport::InitProtocolReq( ClientProtocolRequest *request,
1979  XRootDChannelInfo *info,
1980  kXR_char expect )
1981  {
1982  request->requestid = htons(kXR_protocol);
1983  request->clientpv = htonl(kXR_PROTOCOLVERSION);
1986 
1987  int notlsok = DefaultNoTlsOK;
1988  int tlsnodata = DefaultTlsNoData;
1989 
1991 
1992  env->GetInt( "NoTlsOK", notlsok );
1993 
1995  env->GetInt( "TlsNoData", tlsnodata );
1996 
1997  if (info->encrypted || InitTLS())
1999 
2000  if (info->encrypted && !(notlsok || tlsnodata))
2002 
2003  request->expect = expect;
2004 
2005  //--------------------------------------------------------------------------
2006  // If we are in the curse of establishing a connection in the context of
2007  // TPC update the expect! (this will be never followed be a bind)
2008  //--------------------------------------------------------------------------
2009  if( info->istpc )
2011  }
2012 
2013  //----------------------------------------------------------------------------
2014  // Process the server initial handshake response
2015  //----------------------------------------------------------------------------
2016  XRootDStatus XRootDTransport::ProcessServerHS( HandShakeData *hsData,
2017  XRootDChannelInfo *info )
2018  {
2019  Log *log = DefaultEnv::GetLog();
2020 
2021  Message *msg = hsData->in;
2022  ServerResponseHeader *respHdr = (ServerResponseHeader *)msg->GetBuffer();
2023  ServerInitHandShake *hs = (ServerInitHandShake *)msg->GetBuffer(4);
2024 
2025  if( respHdr->status != kXR_ok )
2026  {
2027  log->Error( XRootDTransportMsg, "[%s] Invalid hand shake response",
2028  hsData->streamName.c_str() );
2029 
2030  return XRootDStatus( stFatal, errHandShakeFailed, 0, "Invalid hand shake response." );
2031  }
2032 
2033  info->protocolVersion = ntohl(hs->protover);
2034  info->serverFlags = ntohl(hs->msgval) == kXR_DataServer ?
2035  kXR_isServer:
2036  kXR_isManager;
2037 
2038  log->Debug( XRootDTransportMsg,
2039  "[%s] Got the server hand shake response (%s, protocol "
2040  "version %x)",
2041  hsData->streamName.c_str(),
2042  ServerFlagsToStr( info->serverFlags ).c_str(),
2043  info->protocolVersion );
2044 
2045  return XRootDStatus( stOK, suContinue );
2046  }
2047 
2048  //----------------------------------------------------------------------------
2049  // Process the protocol response
2050  //----------------------------------------------------------------------------
2051  XRootDStatus XRootDTransport::ProcessProtocolResp( HandShakeData *hsData,
2052  XRootDChannelInfo *info )
2053  {
2054  Log *log = DefaultEnv::GetLog();
2055 
2056  XRootDStatus st = UnMarshallBody( hsData->in, kXR_protocol );
2057  if( !st.IsOK() )
2058  return st;
2059 
2060  ServerResponse *rsp = (ServerResponse*)hsData->in->GetBuffer();
2061 
2062 
2063  if( rsp->hdr.status != kXR_ok )
2064  {
2065  log->Error( XRootDTransportMsg, "[%s] kXR_protocol request failed",
2066  hsData->streamName.c_str() );
2067 
2068  return XRootDStatus( stFatal, errHandShakeFailed, 0, "kXR_protocol request failed" );
2069  }
2070 
2072  int notlsok = DefaultNoTlsOK;
2073  env->GetInt( "NoTlsOK", notlsok );
2074 
2075  if( rsp->body.protocol.pval < kXR_PROTTLSVERSION && info->encrypted )
2076  {
2077  //------------------------------------------------------------------------
2078  // User requested an encrypted connection but the server is to old to
2079  // support it!
2080  //------------------------------------------------------------------------
2081  if( !notlsok ) return XRootDStatus( stFatal, errTlsError, ENOTSUP, "TLS not supported" );
2082 
2083  //------------------------------------------------------------------------
2084  // We are falling back to unencrypted data transmission, as configured
2085  // in XRD_NOTLSOK environment variable
2086  //------------------------------------------------------------------------
2087  log->Info( XRootDTransportMsg,
2088  "[%s] Falling back to unencrypted transmission, server does "
2089  "not support TLS encryption.",
2090  hsData->streamName.c_str() );
2091  info->encrypted = false;
2092  }
2093 
2094  if( rsp->body.protocol.pval >= 0x297 )
2095  info->serverFlags = rsp->body.protocol.flags;
2096 
2097  if( rsp->hdr.dlen > 8 )
2098  {
2099  info->protRespBody = new ServerResponseBody_Protocol();
2100  info->protRespBody->flags = rsp->body.protocol.flags;
2101  info->protRespBody->pval = rsp->body.protocol.pval;
2102 
2103  char* bodybuff = reinterpret_cast<char*>( &rsp->body.protocol.secreq );
2104  size_t bodysize = rsp->hdr.dlen - 8;
2105  XRootDStatus st = ProcessProtocolBody( bodybuff, bodysize, info );
2106  if( !st.IsOK() )
2107  return st;
2108  }
2109 
2110  log->Debug( XRootDTransportMsg,
2111  "[%s] kXR_protocol successful (%s, protocol version %x)",
2112  hsData->streamName.c_str(),
2113  ServerFlagsToStr( info->serverFlags ).c_str(),
2114  info->protocolVersion );
2115 
2116  if( !( info->serverFlags & kXR_haveTLS ) && info->encrypted )
2117  {
2118  //------------------------------------------------------------------------
2119  // User requested an encrypted connection but the server was not configured
2120  // to support encryption!
2121  //------------------------------------------------------------------------
2122  return XRootDStatus( stFatal, errTlsError, ECONNREFUSED,
2123  "Server was not configured to support encryption." );
2124  }
2125 
2126  //--------------------------------------------------------------------------
2127  // Now see if we have to enforce encryption in case the server does not
2128  // support PgRead/PgWrite
2129  //--------------------------------------------------------------------------
2130  int tlsOnNoPgrw = DefaultWantTlsOnNoPgrw;
2131  env->GetInt( "WantTlsOnNoPgrw", tlsOnNoPgrw );
2132  if( !( info->serverFlags & kXR_suppgrw ) && tlsOnNoPgrw )
2133  {
2134  //------------------------------------------------------------------------
2135  // If user requested encryption just make sure it is not switched off for
2136  // data
2137  //------------------------------------------------------------------------
2138  if( info->encrypted )
2139  {
2140  log->Debug( XRootDTransportMsg,
2141  "[%s] Server does not support PgRead/PgWrite and"
2142  " WantTlsOnNoPgrw is on; enforcing encryption for data.",
2143  hsData->streamName.c_str() );
2144  env->PutInt( "TlsNoData", DefaultTlsNoData );
2145  }
2146  //------------------------------------------------------------------------
2147  // Otherwise, if server is not enforcing data encryption, we will need to
2148  // redo the protocol request with kXR_wantTLS set.
2149  //------------------------------------------------------------------------
2150  else if( !( info->serverFlags & kXR_tlsData ) &&
2151  ( info->serverFlags & kXR_haveTLS ) )
2152  {
2153  info->encrypted = true;
2154  return XRootDStatus( stOK, suRetry );
2155  }
2156  }
2157 
2158  return XRootDStatus( stOK, suContinue );
2159  }
2160 
2161  XRootDStatus XRootDTransport::ProcessProtocolBody( char *bodybuff,
2162  size_t bodysize,
2163  XRootDChannelInfo *info )
2164  {
2165  //--------------------------------------------------------------------------
2166  // Parse bind preferences
2167  //--------------------------------------------------------------------------
2168  XrdProto::bifReqs *bifreq = reinterpret_cast<XrdProto::bifReqs*>( bodybuff );
2169  if( bodysize >= sizeof( XrdProto::bifReqs ) && bifreq->theTag == 'B' )
2170  {
2171  bodybuff += sizeof( XrdProto::bifReqs );
2172  bodysize -= sizeof( XrdProto::bifReqs );
2173 
2174  if( bodysize < bifreq->bifILen )
2175  return XRootDStatus( stError, errDataError, 0, "Received incomplete "
2176  "protocol response." );
2177  std::string bindprefs_str( bodybuff, bifreq->bifILen );
2178  std::vector<std::string> bindprefs;
2179  Utils::splitString( bindprefs, bindprefs_str, "," );
2180  info->bindSelector.reset( new BindPrefSelector( std::move( bindprefs ) ) );
2181  bodybuff += bifreq->bifILen;
2182  bodysize -= bifreq->bifILen;
2183  }
2184  //--------------------------------------------------------------------------
2185  // Parse security requirements
2186  //--------------------------------------------------------------------------
2187  XrdProto::secReqs *secreq = reinterpret_cast<XrdProto::secReqs*>( bodybuff );
2188  if( bodysize >= 6 /*XrdProto::secReqs*/ && secreq->theTag == 'S' )
2189  {
2190  memcpy( &info->protRespBody->secreq, secreq, bodysize );
2191  info->protRespSize = bodysize + 8 /*pval & flags*/;
2192  }
2193 
2194  return XRootDStatus();
2195  }
2196 
2197  //----------------------------------------------------------------------------
2198  // Generate the bind message
2199  //----------------------------------------------------------------------------
2200  Message *XRootDTransport::GenerateBind( HandShakeData *hsData,
2201  XRootDChannelInfo *info )
2202  {
2203  Log *log = DefaultEnv::GetLog();
2204 
2205  log->Debug( XRootDTransportMsg,
2206  "[%s] Sending out the bind request",
2207  hsData->streamName.c_str() );
2208 
2209 
2210  Message *msg = new Message( sizeof( ClientBindRequest ) );
2211  ClientBindRequest *bindReq = (ClientBindRequest *)msg->GetBuffer();
2212 
2213  bindReq->requestid = kXR_bind;
2214  memcpy( bindReq->sessid, info->sessionId, 16 );
2215  bindReq->dlen = 0;
2216  MarshallRequest( msg );
2217  return msg;
2218  }
2219 
2220  //----------------------------------------------------------------------------
2221  // Generate the bind message
2222  //----------------------------------------------------------------------------
2223  XRootDStatus XRootDTransport::ProcessBindResp( HandShakeData *hsData,
2224  XRootDChannelInfo *info )
2225  {
2226  Log *log = DefaultEnv::GetLog();
2227 
2228  XRootDStatus st = UnMarshallBody( hsData->in, kXR_bind );
2229  if( !st.IsOK() )
2230  return st;
2231 
2232  ServerResponse *rsp = (ServerResponse*)hsData->in->GetBuffer();
2233 
2234  if( rsp->hdr.status != kXR_ok )
2235  {
2236  log->Error( XRootDTransportMsg, "[%s] kXR_bind request failed",
2237  hsData->streamName.c_str() );
2238  return XRootDStatus( stFatal, errHandShakeFailed, 0, "kXR_bind request failed" );
2239  }
2240 
2241  info->stream[hsData->subStreamId].pathId = rsp->body.bind.substreamid;
2242  log->Debug( XRootDTransportMsg, "[%s] kXR_bind successful",
2243  hsData->streamName.c_str() );
2244 
2245  return XRootDStatus();
2246  }
2247 
2248  //----------------------------------------------------------------------------
2249  // Generate the login message
2250  //----------------------------------------------------------------------------
2251  Message *XRootDTransport::GenerateLogIn( HandShakeData *hsData,
2252  XRootDChannelInfo *info )
2253  {
2254  Log *log = DefaultEnv::GetLog();
2255  Env *env = DefaultEnv::GetEnv();
2256 
2257  //--------------------------------------------------------------------------
2258  // Compute the login cgi
2259  //--------------------------------------------------------------------------
2260  int timeZone = XrdSysTimer::TimeZone();
2261  char *hostName = XrdNetUtils::MyHostName();
2262  std::string countryCode = Utils::FQDNToCC( hostName );
2263  char *cgiBuffer = new char[1024 + info->logintoken.size()];
2264  std::string appName;
2265  std::string monInfo;
2266  env->GetString( "AppName", appName );
2267  env->GetString( "MonInfo", monInfo );
2268  if( info->logintoken.empty() )
2269  {
2270  snprintf( cgiBuffer, 1024,
2271  "xrd.cc=%s&xrd.tz=%d&xrd.appname=%s&xrd.info=%s&"
2272  "xrd.hostname=%s&xrd.rn=%s", countryCode.c_str(), timeZone,
2273  appName.c_str(), monInfo.c_str(), hostName, XrdVERSION );
2274  }
2275  else
2276  {
2277  snprintf( cgiBuffer, 1024,
2278  "xrd.cc=%s&xrd.tz=%d&xrd.appname=%s&xrd.info=%s&"
2279  "xrd.hostname=%s&xrd.rn=%s&%s", countryCode.c_str(), timeZone,
2280  appName.c_str(), monInfo.c_str(), hostName, XrdVERSION, info->logintoken.c_str() );
2281  }
2282  uint16_t cgiLen = strlen( cgiBuffer );
2283  free( hostName );
2284 
2285  //--------------------------------------------------------------------------
2286  // Generate the message
2287  //--------------------------------------------------------------------------
2288  Message *msg = new Message( sizeof(ClientLoginRequest) + cgiLen );
2289  ClientLoginRequest *loginReq = (ClientLoginRequest *)msg->GetBuffer();
2290 
2291  loginReq->requestid = kXR_login;
2292  loginReq->pid = ::getpid();
2293  loginReq->capver[0] = (kXR_char) kXR_asyncap | (kXR_char) kXR_ver005;
2294  loginReq->dlen = cgiLen;
2296 #ifdef WITH_XRDEC
2297  loginReq->ability2 = kXR_ecredir;
2298 #endif
2299 
2300  int multiProtocol = 0;
2301  env->GetInt( "MultiProtocol", multiProtocol );
2302  if(multiProtocol)
2303  loginReq->ability |= kXR_multipr;
2304 
2305  //--------------------------------------------------------------------------
2306  // Check the IP stacks
2307  //--------------------------------------------------------------------------
2309  bool dualStack = false;
2310  bool privateIPv6 = false;
2311  bool privateIPv4 = false;
2312 
2313  if( (stacks & XrdNetUtils::hasIP64) == XrdNetUtils::hasIP64 )
2314  {
2315  dualStack = true;
2316  loginReq->ability |= kXR_hasipv64;
2317  }
2318 
2319  if( (stacks & XrdNetUtils::hasIPv6) && !(stacks & XrdNetUtils::hasPub6) )
2320  {
2321  privateIPv6 = true;
2322  loginReq->ability |= kXR_onlyprv6;
2323  }
2324 
2325  if( (stacks & XrdNetUtils::hasIPv4) && !(stacks & XrdNetUtils::hasPub4) )
2326  {
2327  privateIPv4 = true;
2328  loginReq->ability |= kXR_onlyprv4;
2329  }
2330 
2331  // The following code snippet tries to overcome the problem that this host
2332  // may still be dual-stacked but we don't know it because one of the
2333  // interfaces was not registered in DNS.
2334  //
2335  if( !dualStack && hsData->serverAddr )
2336  {if ( ( ( stacks & XrdNetUtils::hasIPv4 )
2337  && hsData->serverAddr->isIPType(XrdNetAddrInfo::IPv6))
2338  || ( ( stacks & XrdNetUtils::hasIPv6 )
2339  && hsData->serverAddr->isIPType(XrdNetAddrInfo::IPv4)))
2340  {dualStack = true;
2341  loginReq->ability |= kXR_hasipv64;
2342  }
2343  }
2344 
2345  //--------------------------------------------------------------------------
2346  // Check the username
2347  //--------------------------------------------------------------------------
2348  std::string buffer( 8, 0 );
2349  if( hsData->url->GetUserName().length() )
2350  buffer = hsData->url->GetUserName();
2351  else
2352  {
2353  char *name = new char[1024];
2354  if( !XrdOucUtils::UserName( geteuid(), name, 1024 ) )
2355  buffer = name;
2356  else
2357  buffer = "_anon_";
2358  delete [] name;
2359  }
2360  buffer.resize( 8, 0 );
2361  std::copy( buffer.begin(), buffer.end(), (char*)loginReq->username );
2362 
2363  msg->Append( cgiBuffer, cgiLen, 24 );
2364 
2365  log->Debug( XRootDTransportMsg, "[%s] Sending out kXR_login request, "
2366  "username: %s, cgi: %s, dual-stack: %s, private IPv4: %s, "
2367  "private IPv6: %s", hsData->streamName.c_str(),
2368  loginReq->username, cgiBuffer, dualStack ? "true" : "false",
2369  privateIPv4 ? "true" : "false",
2370  privateIPv6 ? "true" : "false" );
2371 
2372  delete [] cgiBuffer;
2373  MarshallRequest( msg );
2374  return msg;
2375  }
2376 
2377  //----------------------------------------------------------------------------
2378  // Process the protocol response
2379  //----------------------------------------------------------------------------
2380  XRootDStatus XRootDTransport::ProcessLogInResp( HandShakeData *hsData,
2381  XRootDChannelInfo *info )
2382  {
2383  Log *log = DefaultEnv::GetLog();
2384 
2385  XRootDStatus st = UnMarshallBody( hsData->in, kXR_login );
2386  if( !st.IsOK() )
2387  return st;
2388 
2389  ServerResponse *rsp = (ServerResponse*)hsData->in->GetBuffer();
2390 
2391  if( rsp->hdr.status != kXR_ok )
2392  {
2393  log->Error( XRootDTransportMsg, "[%s] Got invalid login response",
2394  hsData->streamName.c_str() );
2395  return XRootDStatus( stFatal, errLoginFailed, 0, "Got invalid login response." );
2396  }
2397 
2398  if( !info->firstLogIn )
2399  memcpy( info->oldSessionId, info->sessionId, 16 );
2400 
2401  if( rsp->hdr.dlen == 0 && info->protocolVersion <= 0x289 )
2402  {
2403  //--------------------------------------------------------------------------
2404  // This if statement is there only to support dCache inaccurate
2405  // implementation of XRoot protocol, that in some cases returns
2406  // an empty login response for protocol version <= 2.8.9.
2407  //--------------------------------------------------------------------------
2408  memset( info->sessionId, 0, 16 );
2409  log->Warning( XRootDTransportMsg,
2410  "[%s] Logged in, accepting empty login response.",
2411  hsData->streamName.c_str() );
2412  return XRootDStatus();
2413  }
2414 
2415  if( rsp->hdr.dlen < 16 )
2416  return XRootDStatus( stError, errDataError, 0, "Login response too short." );
2417 
2418  memcpy( info->sessionId, rsp->body.login.sessid, 16 );
2419 
2420  std::string sessId = Utils::Char2Hex( rsp->body.login.sessid, 16 );
2421 
2422  log->Debug( XRootDTransportMsg, "[%s] Logged in, session: %s",
2423  hsData->streamName.c_str(), sessId.c_str() );
2424 
2425  //--------------------------------------------------------------------------
2426  // We have an authentication info to process
2427  //--------------------------------------------------------------------------
2428  if( rsp->hdr.dlen > 16 )
2429  {
2430  size_t len = rsp->hdr.dlen-16;
2431  info->authBuffer = new char[len+1];
2432  info->authBuffer[len] = 0;
2433  memcpy( info->authBuffer, rsp->body.login.sec, len );
2434  log->Debug( XRootDTransportMsg, "[%s] Authentication is required: %s",
2435  hsData->streamName.c_str(), info->authBuffer );
2436 
2437  return XRootDStatus( stOK, suContinue );
2438  }
2439 
2440  return XRootDStatus();
2441  }
2442 
2443  //----------------------------------------------------------------------------
2444  // Do the authentication
2445  //----------------------------------------------------------------------------
2446  XRootDStatus XRootDTransport::DoAuthentication( HandShakeData *hsData,
2447  XRootDChannelInfo *info )
2448  {
2449  //--------------------------------------------------------------------------
2450  // Prepare
2451  //--------------------------------------------------------------------------
2452  Log *log = DefaultEnv::GetLog();
2453  XRootDStreamInfo &sInfo = info->stream[hsData->subStreamId];
2454  XrdSecCredentials *credentials = 0;
2455  std::string protocolName;
2456 
2457  //--------------------------------------------------------------------------
2458  // We're doing this for the first time
2459  //--------------------------------------------------------------------------
2460  if( sInfo.status == XRootDStreamInfo::LoginSent )
2461  {
2462  log->Debug( XRootDTransportMsg, "[%s] Sending authentication data",
2463  hsData->streamName.c_str() );
2464 
2465  //------------------------------------------------------------------------
2466  // Set up the authentication environment
2467  //------------------------------------------------------------------------
2468  info->authEnv = new XrdOucEnv();
2469  info->authEnv->Put( "sockname", hsData->clientName.c_str() );
2470  info->authEnv->Put( "username", hsData->url->GetUserName().c_str() );
2471  info->authEnv->Put( "password", hsData->url->GetPassword().c_str() );
2472 
2473  const URL::ParamsMap &urlParams = hsData->url->GetParams();
2474  URL::ParamsMap::const_iterator it;
2475  for( it = urlParams.begin(); it != urlParams.end(); ++it )
2476  {
2477  if( it->first.compare( 0, 4, "xrd." ) == 0 ||
2478  it->first.compare( 0, 6, "xrdcl." ) == 0 )
2479  info->authEnv->Put( it->first.c_str(), it->second.c_str() );
2480  }
2481 
2482  //------------------------------------------------------------------------
2483  // Initialize some other structs
2484  //------------------------------------------------------------------------
2485  size_t authBuffLen = strlen( info->authBuffer );
2486  char *pars = (char *)malloc( authBuffLen + 1 );
2487  memcpy( pars, info->authBuffer, authBuffLen );
2488  info->authParams = new XrdSecParameters( pars, authBuffLen );
2489  sInfo.status = XRootDStreamInfo::AuthSent;
2490  delete [] info->authBuffer;
2491  info->authBuffer = 0;
2492 
2493  //------------------------------------------------------------------------
2494  // Find a protocol that gives us valid credentials
2495  //------------------------------------------------------------------------
2496  XRootDStatus st = GetCredentials( credentials, hsData, info );
2497  if( !st.IsOK() )
2498  {
2499  CleanUpAuthentication( info );
2500  return st;
2501  }
2502  protocolName = info->authProtocol->Entity.prot;
2503  }
2504 
2505  //--------------------------------------------------------------------------
2506  // We've been here already
2507  //--------------------------------------------------------------------------
2508  else
2509  {
2510  ServerResponse *rsp = (ServerResponse*)hsData->in->GetBuffer();
2511  protocolName = info->authProtocol->Entity.prot;
2512 
2513  //------------------------------------------------------------------------
2514  // We're required to send out more authentication data
2515  //------------------------------------------------------------------------
2516  if( rsp->hdr.status == kXR_authmore )
2517  {
2518  log->Debug( XRootDTransportMsg,
2519  "[%s] Sending more authentication data for %s",
2520  hsData->streamName.c_str(), protocolName.c_str() );
2521 
2522  uint32_t len = rsp->hdr.dlen;
2523  char *secTokenData = (char*)malloc( len );
2524  memcpy( secTokenData, rsp->body.authmore.data, len );
2525  XrdSecParameters *secToken = new XrdSecParameters( secTokenData, len );
2526  XrdOucErrInfo ei( "", info->authEnv);
2527  credentials = info->authProtocol->getCredentials( secToken, &ei );
2528  delete secToken;
2529 
2530  //----------------------------------------------------------------------
2531  // The protocol handler refuses to give us the data
2532  //----------------------------------------------------------------------
2533  if( !credentials )
2534  {
2535  log->Error( XRootDTransportMsg,
2536  "[%s] Auth protocol handler for %s refuses to give "
2537  "us more credentials %s",
2538  hsData->streamName.c_str(), protocolName.c_str(),
2539  ei.getErrText() );
2540  CleanUpAuthentication( info );
2541  return XRootDStatus( stFatal, errAuthFailed, 0, ei.getErrText() );
2542  }
2543  }
2544 
2545  //------------------------------------------------------------------------
2546  // We have succeeded
2547  //------------------------------------------------------------------------
2548  else if( rsp->hdr.status == kXR_ok )
2549  {
2550  info->authProtocolName = info->authProtocol->Entity.prot;
2551 
2552  //----------------------------------------------------------------------
2553  // Do we need protection?
2554  //----------------------------------------------------------------------
2555  if( info->protRespBody )
2556  {
2557  int rc = XrdSecGetProtection( info->protection, *info->authProtocol, *info->protRespBody, info->protRespSize );
2558  if( rc > 0 )
2559  {
2560  log->Debug( XRootDTransportMsg,
2561  "[%s] XrdSecProtect loaded.", hsData->streamName.c_str() );
2562  }
2563  else if( rc == 0 )
2564  {
2565  log->Debug( XRootDTransportMsg,
2566  "[%s] XrdSecProtect: no protection needed.",
2567  hsData->streamName.c_str() );
2568  }
2569  else
2570  {
2571  log->Debug( XRootDTransportMsg,
2572  "[%s] Failed to load XrdSecProtect: %s",
2573  hsData->streamName.c_str(), XrdSysE2T( -rc ) );
2574  CleanUpAuthentication( info );
2575 
2576  return XRootDStatus( stError, errAuthFailed, -rc, XrdSysE2T( -rc ) );
2577  }
2578  }
2579 
2580  if( !info->protection )
2581  CleanUpAuthentication( info );
2582  else
2583  pSecUnloadHandler->Register( info->authProtocolName );
2584 
2585  log->Debug( XRootDTransportMsg,
2586  "[%s] Authenticated with %s.", hsData->streamName.c_str(),
2587  protocolName.c_str() );
2588 
2589  //--------------------------------------------------------------------
2590  // Clear the SSL error queue of the calling thread, as there might be
2591  // some leftover from the authentication!
2592  //--------------------------------------------------------------------
2594 
2595  return XRootDStatus();
2596  }
2597  //------------------------------------------------------------------------
2598  // Failure
2599  //------------------------------------------------------------------------
2600  else if( rsp->hdr.status == kXR_error )
2601  {
2602  char *errmsg = new char[rsp->hdr.dlen-3]; errmsg[rsp->hdr.dlen-4] = 0;
2603  memcpy( errmsg, rsp->body.error.errmsg, rsp->hdr.dlen-4 );
2604  log->Error( XRootDTransportMsg,
2605  "[%s] Authentication with %s failed: %s",
2606  hsData->streamName.c_str(), protocolName.c_str(),
2607  errmsg );
2608  delete [] errmsg;
2609 
2610  info->authProtocol->Delete();
2611  info->authProtocol = 0;
2612 
2613  //----------------------------------------------------------------------
2614  // Find another protocol that gives us valid credentials
2615  //----------------------------------------------------------------------
2616  XRootDStatus st = GetCredentials( credentials, hsData, info );
2617  if( !st.IsOK() )
2618  {
2619  CleanUpAuthentication( info );
2620  return st;
2621  }
2622  protocolName = info->authProtocol->Entity.prot;
2623  }
2624  //------------------------------------------------------------------------
2625  // God knows what
2626  //------------------------------------------------------------------------
2627  else
2628  {
2629  info->authProtocolName = info->authProtocol->Entity.prot;
2630  CleanUpAuthentication( info );
2631 
2632  log->Error( XRootDTransportMsg,
2633  "[%s] Authentication with %s failed: unexpected answer",
2634  hsData->streamName.c_str(), protocolName.c_str() );
2635  return XRootDStatus( stFatal, errAuthFailed, 0, "Authentication failed: unexpected answer." );
2636  }
2637  }
2638 
2639  //--------------------------------------------------------------------------
2640  // Generate the client request
2641  //--------------------------------------------------------------------------
2642  Message *msg = new Message( sizeof(ClientAuthRequest)+credentials->size );
2643  msg->Zero();
2644  ClientRequest *req = (ClientRequest*)msg->GetBuffer();
2645  char *reqBuffer = msg->GetBuffer(sizeof(ClientAuthRequest));
2646 
2647  req->header.requestid = kXR_auth;
2648  req->auth.dlen = credentials->size;
2649  memcpy( req->auth.credtype, protocolName.c_str(),
2650  protocolName.length() > 4 ? 4 : protocolName.length() );
2651 
2652  memcpy( reqBuffer, credentials->buffer, credentials->size );
2653  hsData->out = msg;
2654  MarshallRequest( msg );
2655  delete credentials;
2656 
2657  //------------------------------------------------------------------------
2658  // Clear the SSL error queue of the calling thread, as there might be
2659  // some leftover from the authentication!
2660  //------------------------------------------------------------------------
2662 
2663  return XRootDStatus( stOK, suContinue );
2664  }
2665 
2666  //------------------------------------------------------------------------
2667  // Get the initial credentials using one of the protocols
2668  //------------------------------------------------------------------------
2669  XRootDStatus XRootDTransport::GetCredentials( XrdSecCredentials *&credentials,
2670  HandShakeData *hsData,
2671  XRootDChannelInfo *info )
2672  {
2673  //--------------------------------------------------------------------------
2674  // Set up the auth handler
2675  //--------------------------------------------------------------------------
2676  Log *log = DefaultEnv::GetLog();
2677  XrdOucErrInfo ei( "", info->authEnv);
2678  XrdSecGetProt_t authHandler = GetAuthHandler();
2679  if( !authHandler )
2680  return XRootDStatus( stFatal, errAuthFailed, 0, "Could not load authentication handler." );
2681 
2682  //--------------------------------------------------------------------------
2683  // Retrieve secuid and secgid, if available. These will override the fsuid
2684  // and fsgid of the current thread reading the credentials to prevent
2685  // security holes in case this process is running with elevated permissions.
2686  //--------------------------------------------------------------------------
2687  char *secuidc = (ei.getEnv()) ? ei.getEnv()->Get("xrdcl.secuid") : 0;
2688  char *secgidc = (ei.getEnv()) ? ei.getEnv()->Get("xrdcl.secgid") : 0;
2689 
2690  int secuid = -1;
2691  int secgid = -1;
2692 
2693  if(secuidc) secuid = atoi(secuidc);
2694  if(secgidc) secgid = atoi(secgidc);
2695 
2696 #ifdef __linux__
2697  ScopedFsUidSetter uidSetter(secuid, secgid, hsData->streamName);
2698  if(!uidSetter.IsOk()) {
2699  log->Error( XRootDTransportMsg, "[%s] Error while setting (fsuid, fsgid) to (%d, %d)",
2700  hsData->streamName.c_str(), secuid, secgid );
2701  return XRootDStatus( stFatal, errAuthFailed, 0, "Error while setting (fsuid, fsgid)." );
2702  }
2703 #else
2704  if(secuid >= 0 || secgid >= 0) {
2705  log->Error( XRootDTransportMsg, "[%s] xrdcl.secuid and xrdcl.secgid only supported on Linux.",
2706  hsData->streamName.c_str() );
2707  return XRootDStatus( stFatal, errAuthFailed, 0, "xrdcl.secuid and xrdcl.secgid"
2708  " only supported on Linux" );
2709  }
2710 #endif
2711 
2712  //--------------------------------------------------------------------------
2713  // Loop over the possible protocols to find one that gives us valid
2714  // credentials
2715  //--------------------------------------------------------------------------
2716  XrdNetAddr &srvAddrInfo = *const_cast<XrdNetAddr *>(hsData->serverAddr);
2717  srvAddrInfo.SetTLS( info->encrypted );
2718  while(1)
2719  {
2720  //------------------------------------------------------------------------
2721  // Get the protocol
2722  //------------------------------------------------------------------------
2723  info->authProtocol = (*authHandler)( hsData->url->GetHostName().c_str(),
2724  srvAddrInfo,
2725  *info->authParams,
2726  &ei );
2727  if( !info->authProtocol )
2728  {
2729  log->Error( XRootDTransportMsg, "[%s] No protocols left to try",
2730  hsData->streamName.c_str() );
2731  return XRootDStatus( stFatal, errAuthFailed, 0, "No protocols left to try" );
2732  }
2733 
2734  std::string protocolName = info->authProtocol->Entity.prot;
2735  log->Debug( XRootDTransportMsg, "[%s] Trying to authenticate using %s",
2736  hsData->streamName.c_str(), protocolName.c_str() );
2737 
2738  //------------------------------------------------------------------------
2739  // Get the credentials from the current protocol
2740  //------------------------------------------------------------------------
2741  credentials = info->authProtocol->getCredentials( 0, &ei );
2742  if( !credentials )
2743  {
2744  log->Debug( XRootDTransportMsg,
2745  "[%s] Cannot get credentials for protocol %s: %s",
2746  hsData->streamName.c_str(), protocolName.c_str(),
2747  ei.getErrText() );
2748  info->authProtocol->Delete();
2749  continue;
2750  }
2751  return XRootDStatus( stOK, suContinue );
2752  }
2753  }
2754 
2755  //------------------------------------------------------------------------
2756  // Clean up the data structures created for the authentication process
2757  //------------------------------------------------------------------------
2758  Status XRootDTransport::CleanUpAuthentication( XRootDChannelInfo *info )
2759  {
2760  if( info->authProtocol )
2761  info->authProtocol->Delete();
2762  delete info->authParams;
2763  delete info->authEnv;
2764  info->authProtocol = 0;
2765  info->authParams = 0;
2766  info->authEnv = 0;
2768  return Status();
2769  }
2770 
2771  //------------------------------------------------------------------------
2772  // Clean up the data structures created for the protection purposes
2773  //------------------------------------------------------------------------
2774  Status XRootDTransport::CleanUpProtection( XRootDChannelInfo *info )
2775  {
2776  XrdSysRWLockHelper scope( pSecUnloadHandler->lock );
2777  if( pSecUnloadHandler->unloaded ) return Status( stError, errInvalidOp );
2778 
2779  if( info->protection )
2780  {
2781  info->protection->Delete();
2782  info->protection = 0;
2783 
2784  CleanUpAuthentication( info );
2785  }
2786 
2787  if( info->protRespBody )
2788  {
2789  delete info->protRespBody;
2790  info->protRespBody = 0;
2791  info->protRespSize = 0;
2792  }
2793 
2794  return Status();
2795  }
2796 
2797  //----------------------------------------------------------------------------
2798  // Get the authentication function handle
2799  //----------------------------------------------------------------------------
2800  XrdSecGetProt_t XRootDTransport::GetAuthHandler()
2801  {
2802  Log *log = DefaultEnv::GetLog();
2803  char errorBuff[1024];
2804 
2805  // the static constructor is invoked only once and it is guaranteed that this
2806  // is thread safe
2807  static std::atomic<XrdSecGetProt_t> authHandler( XrdSecLoadSecFactory( errorBuff, 1024 ) );
2808  auto ret = authHandler.load( std::memory_order_relaxed );
2809  if( ret ) return ret;
2810 
2811  // if we are here it means we failed to load the security library for the
2812  // first time and we hope the environment changed
2813 
2814  // obtain a lock
2815  static XrdSysMutex mtx;
2816  XrdSysMutexHelper lck( mtx );
2817  // check if in the meanwhile some else didn't load the library
2818  ret = authHandler.load( std::memory_order_relaxed );
2819  if( ret ) return ret;
2820 
2821  // load the library
2822  ret = XrdSecLoadSecFactory( errorBuff, 1024 );
2823  authHandler.store( ret, std::memory_order_relaxed );
2824  // if we failed report an error
2825  if( !ret )
2826  {
2827  log->Error( XRootDTransportMsg,
2828  "Unable to get the security framework: %s", errorBuff );
2829  return 0;
2830  }
2831  return ret;
2832  }
2833 
2834  //----------------------------------------------------------------------------
2835  // Generate the end session message
2836  //----------------------------------------------------------------------------
2837  Message *XRootDTransport::GenerateEndSession( HandShakeData *hsData,
2838  XRootDChannelInfo *info )
2839  {
2840  Log *log = DefaultEnv::GetLog();
2841 
2842  //--------------------------------------------------------------------------
2843  // Generate the message
2844  //--------------------------------------------------------------------------
2845  Message *msg = new Message( sizeof(ClientEndsessRequest) );
2846  ClientEndsessRequest *endsessReq = (ClientEndsessRequest *)msg->GetBuffer();
2847 
2848  endsessReq->requestid = kXR_endsess;
2849  memcpy( endsessReq->sessid, info->oldSessionId, 16 );
2850  std::string sessId = Utils::Char2Hex( endsessReq->sessid, 16 );
2851 
2852  log->Debug( XRootDTransportMsg, "[%s] Sending out kXR_endsess for session:"
2853  " %s", hsData->streamName.c_str(), sessId.c_str() );
2854 
2855  MarshallRequest( msg );
2856 
2857  Message *sign = 0;
2858  GetSignature( msg, sign, info );
2859  if( sign )
2860  {
2861  //------------------------------------------------------------------------
2862  // Now place both the signature and the request in a single buffer
2863  //------------------------------------------------------------------------
2864  uint32_t size = sign->GetSize();
2865  sign->ReAllocate( size + msg->GetSize() );
2866  char* buffer = sign->GetBuffer( size );
2867  memcpy( buffer, msg->GetBuffer(), msg->GetSize() );
2868  msg->Grab( sign->GetBuffer(), sign->GetSize() );
2869  }
2870 
2871  return msg;
2872  }
2873 
2874  //----------------------------------------------------------------------------
2875  // Process the protocol response
2876  //----------------------------------------------------------------------------
2877  Status XRootDTransport::ProcessEndSessionResp( HandShakeData *hsData,
2878  XRootDChannelInfo *info )
2879  {
2880  Log *log = DefaultEnv::GetLog();
2881 
2882  Status st = UnMarshallBody( hsData->in, kXR_endsess );
2883  if( !st.IsOK() )
2884  return st;
2885 
2886  ServerResponse *rsp = (ServerResponse*)hsData->in->GetBuffer();
2887 
2888  // If we're good, we're good!
2889  if( rsp->hdr.status == kXR_ok )
2890  return Status();
2891 
2892  // we ignore not found errors as such an error means the connection
2893  // has been already terminated
2894  if( rsp->hdr.status == kXR_error && rsp->body.error.errnum == kXR_NotFound )
2895  return Status();
2896 
2897  // other errors
2898  if( rsp->hdr.status == kXR_error )
2899  {
2900  std::string errorMsg( rsp->body.error.errmsg, rsp->hdr.dlen - 4 );
2901  log->Error( XRootDTransportMsg, "[%s] Got error response to "
2902  "kXR_endsess: %s", hsData->streamName.c_str(),
2903  errorMsg.c_str() );
2904  return Status( stFatal, errHandShakeFailed );
2905  }
2906 
2907  // Wait Response.
2908  if( rsp->hdr.status == kXR_wait )
2909  {
2910  std::string msg( rsp->body.wait.infomsg, rsp->hdr.dlen - 4 );
2911  log->Info( XRootDTransportMsg, "[%s] Got wait response to "
2912  "kXR_endsess: %s", hsData->streamName.c_str(),
2913  msg.c_str() );
2914  hsData->out = GenerateEndSession( hsData, info );
2915  return Status( stOK, suRetry );
2916  }
2917 
2918  // Any other response is protocol violation
2919  return Status( stError, errDataError );
2920  }
2921 
2922  //----------------------------------------------------------------------------
2923  // Get a string representation of the server flags
2924  //----------------------------------------------------------------------------
2925  std::string XRootDTransport::ServerFlagsToStr( uint32_t flags )
2926  {
2927  std::string repr = "type: ";
2928  if( flags & kXR_isManager )
2929  repr += "manager ";
2930 
2931  else if( flags & kXR_isServer )
2932  repr += "server ";
2933 
2934  repr += "[";
2935 
2936  if( flags & kXR_attrMeta )
2937  repr += "meta ";
2938 
2939  else if( flags & kXR_attrCache )
2940  repr += "cache ";
2941 
2942  else if( flags & kXR_attrProxy )
2943  repr += "proxy ";
2944 
2945  else if( flags & kXR_attrSuper )
2946  repr += "super ";
2947 
2948  else
2949  repr += " ";
2950 
2951  repr.erase( repr.length()-1, 1 );
2952 
2953  repr += "]";
2954  return repr;
2955  }
2956 }
2957 
2958 namespace
2959 {
2960  // Extract file name from a request
2961  //----------------------------------------------------------------------------
2962  char *GetDataAsString( char *msg )
2963  {
2964  ClientRequestHdr *req = (ClientRequestHdr*)msg;
2965  char *fn = new char[req->dlen+1];
2966  memcpy( fn, msg + 24, req->dlen );
2967  fn[req->dlen] = 0;
2968  return fn;
2969  }
2970 }
2971 
2972 namespace XrdCl
2973 {
2974  //----------------------------------------------------------------------------
2975  // Get the description of a message
2976  //----------------------------------------------------------------------------
2977  void XRootDTransport::GenerateDescription( char *msg, std::ostringstream &o )
2978  {
2979  Log *log = DefaultEnv::GetLog();
2980  if( log->GetLevel() < Log::ErrorMsg )
2981  return;
2982 
2983  ClientRequestHdr *req = (ClientRequestHdr *)msg;
2984  switch( req->requestid )
2985  {
2986  //------------------------------------------------------------------------
2987  // kXR_open
2988  //------------------------------------------------------------------------
2989  case kXR_open:
2990  {
2991  ClientOpenRequest *sreq = (ClientOpenRequest *)msg;
2992  o << "kXR_open (";
2993  char *fn = GetDataAsString( msg );
2994  o << "file: " << fn << ", ";
2995  delete [] fn;
2996  o << "mode: 0" << std::setbase(8) << sreq->mode << ", ";
2997  o << std::setbase(10);
2998  o << "flags: ";
2999  if( sreq->options == 0 )
3000  o << "none";
3001  else
3002  {
3003  if( sreq->options & kXR_compress )
3004  o << "kXR_compress ";
3005  if( sreq->options & kXR_delete )
3006  o << "kXR_delete ";
3007  if( sreq->options & kXR_force )
3008  o << "kXR_force ";
3009  if( sreq->options & kXR_mkpath )
3010  o << "kXR_mkpath ";
3011  if( sreq->options & kXR_new )
3012  o << "kXR_new ";
3013  if( sreq->options & kXR_nowait )
3014  o << "kXR_nowait ";
3015  if( sreq->options & kXR_open_apnd )
3016  o << "kXR_open_apnd ";
3017  if( sreq->options & kXR_open_read )
3018  o << "kXR_open_read ";
3019  if( sreq->options & kXR_open_updt )
3020  o << "kXR_open_updt ";
3021  if( sreq->options & kXR_open_wrto )
3022  o << "kXR_open_wrto ";
3023  if( sreq->options & kXR_posc )
3024  o << "kXR_posc ";
3025  if( sreq->options & kXR_prefname )
3026  o << "kXR_prefname ";
3027  if( sreq->options & kXR_refresh )
3028  o << "kXR_refresh ";
3029  if( sreq->options & kXR_4dirlist )
3030  o << "kXR_4dirlist ";
3031  if( sreq->options & kXR_replica )
3032  o << "kXR_replica ";
3033  if( sreq->options & kXR_seqio )
3034  o << "kXR_seqio ";
3035  if( sreq->options & kXR_async )
3036  o << "kXR_async ";
3037  if( sreq->options & kXR_retstat )
3038  o << "kXR_retstat ";
3039  }
3040  o << ")";
3041  break;
3042  }
3043 
3044  //------------------------------------------------------------------------
3045  // kXR_close
3046  //------------------------------------------------------------------------
3047  case kXR_close:
3048  {
3049  ClientCloseRequest *sreq = (ClientCloseRequest *)msg;
3050  o << "kXR_close (";
3051  o << "handle: " << FileHandleToStr( sreq->fhandle );
3052  o << ")";
3053  break;
3054  }
3055 
3056  //------------------------------------------------------------------------
3057  // kXR_stat
3058  //------------------------------------------------------------------------
3059  case kXR_stat:
3060  {
3061  ClientStatRequest *sreq = (ClientStatRequest *)msg;
3062  o << "kXR_stat (";
3063  if( sreq->dlen )
3064  {
3065  char *fn = GetDataAsString( msg );;
3066  o << "path: " << fn << ", ";
3067  delete [] fn;
3068  }
3069  else
3070  {
3071  o << "handle: " << FileHandleToStr( sreq->fhandle );
3072  o << ", ";
3073  }
3074  o << "flags: ";
3075  if( sreq->options == 0 )
3076  o << "none";
3077  else
3078  {
3079  if( sreq->options & kXR_vfs )
3080  o << "kXR_vfs";
3081  }
3082  o << ")";
3083  break;
3084  }
3085 
3086  //------------------------------------------------------------------------
3087  // kXR_read
3088  //------------------------------------------------------------------------
3089  case kXR_read:
3090  {
3091  ClientReadRequest *sreq = (ClientReadRequest *)msg;
3092  o << "kXR_read (";
3093  o << "handle: " << FileHandleToStr( sreq->fhandle );
3094  o << std::setbase(10);
3095  o << ", ";
3096  o << "offset: " << sreq->offset << ", ";
3097  o << "size: " << sreq->rlen << ")";
3098  break;
3099  }
3100 
3101  //------------------------------------------------------------------------
3102  // kXR_pgread
3103  //------------------------------------------------------------------------
3104  case kXR_pgread:
3105  {
3107  o << "kXR_pgread (";
3108  o << "handle: " << FileHandleToStr( sreq->fhandle );
3109  o << std::setbase(10);
3110  o << ", ";
3111  o << "offset: " << sreq->offset << ", ";
3112  o << "size: " << sreq->rlen << ")";
3113  break;
3114  }
3115 
3116  //------------------------------------------------------------------------
3117  // kXR_write
3118  //------------------------------------------------------------------------
3119  case kXR_write:
3120  {
3121  ClientWriteRequest *sreq = (ClientWriteRequest *)msg;
3122  o << "kXR_write (";
3123  o << "handle: " << FileHandleToStr( sreq->fhandle );
3124  o << std::setbase(10);
3125  o << ", ";
3126  o << "offset: " << sreq->offset << ", ";
3127  o << "size: " << sreq->dlen << ")";
3128  break;
3129  }
3130 
3131  //------------------------------------------------------------------------
3132  // kXR_pgwrite
3133  //------------------------------------------------------------------------
3134  case kXR_pgwrite:
3135  {
3137  o << "kXR_pgwrite (";
3138  o << "handle: " << FileHandleToStr( sreq->fhandle );
3139  o << std::setbase(10);
3140  o << ", ";
3141  o << "offset: " << sreq->offset << ", ";
3142  o << "size: " << sreq->dlen << ")";
3143  break;
3144  }
3145 
3146  //------------------------------------------------------------------------
3147  // kXR_fattr
3148  //------------------------------------------------------------------------
3149  case kXR_fattr:
3150  {
3151  ClientFattrRequest *sreq = (ClientFattrRequest *)msg;
3152  int nattr = sreq->numattr;
3153  int options = sreq->options;
3154  o << "kXR_fattr";
3155  switch (sreq->subcode) {
3156  case kXR_fattrGet:
3157  o << "Get";
3158  break;
3159  case kXR_fattrSet:
3160  o << "Set";
3161  break;
3162  case kXR_fattrList:
3163  o << "List";
3164  break;
3165  case kXR_fattrDel:
3166  o << "Delete";
3167  break;
3168  default:
3169  o << " unknown subcode: " << sreq->subcode;
3170  break;
3171  }
3172  o << " (handle: " << FileHandleToStr( sreq->fhandle );
3173  o << std::setbase(10);
3174  if (nattr)
3175  o << ", numattr: " << nattr;
3176  if (options) {
3177  o << ", options: ";
3178  if (options & 0x01)
3179  o << "new";
3180  if (options & 0x10)
3181  o << "list values";
3182  }
3183  o << ", total size: " << req->dlen << ")";
3184  break;
3185  }
3186 
3187  //------------------------------------------------------------------------
3188  // kXR_sync
3189  //------------------------------------------------------------------------
3190  case kXR_sync:
3191  {
3192  ClientSyncRequest *sreq = (ClientSyncRequest *)msg;
3193  o << "kXR_sync (";
3194  o << "handle: " << FileHandleToStr( sreq->fhandle );
3195  o << ")";
3196  break;
3197  }
3198 
3199  //------------------------------------------------------------------------
3200  // kXR_truncate
3201  //------------------------------------------------------------------------
3202  case kXR_truncate:
3203  {
3205  o << "kXR_truncate (";
3206  if( !sreq->dlen )
3207  o << "handle: " << FileHandleToStr( sreq->fhandle );
3208  else
3209  {
3210  char *fn = GetDataAsString( msg );
3211  o << "file: " << fn;
3212  delete [] fn;
3213  }
3214  o << std::setbase(10);
3215  o << ", ";
3216  o << "offset: " << sreq->offset;
3217  o << ")";
3218  break;
3219  }
3220 
3221  //------------------------------------------------------------------------
3222  // kXR_readv
3223  //------------------------------------------------------------------------
3224  case kXR_readv:
3225  {
3226  unsigned char *fhandle = 0;
3227  o << "kXR_readv (";
3228 
3229  o << "handle: ";
3230  readahead_list *dataChunk = (readahead_list*)(msg + 24 );
3231  fhandle = dataChunk[0].fhandle;
3232  if( fhandle )
3233  o << FileHandleToStr( fhandle );
3234  else
3235  o << "unknown";
3236  o << ", ";
3237  o << std::setbase(10);
3238  o << "chunks: [";
3239  uint64_t size = 0;
3240  for( size_t i = 0; i < req->dlen/sizeof(readahead_list); ++i )
3241  {
3242  size += dataChunk[i].rlen;
3243  o << "(offset: " << dataChunk[i].offset;
3244  o << ", size: " << dataChunk[i].rlen << "); ";
3245  }
3246  o << "], ";
3247  o << "total size: " << size << ")";
3248  break;
3249  }
3250 
3251  //------------------------------------------------------------------------
3252  // kXR_writev
3253  //------------------------------------------------------------------------
3254  case kXR_writev:
3255  {
3256  unsigned char *fhandle = 0;
3257  o << "kXR_writev (";
3258 
3259  XrdProto::write_list *wrtList =
3260  reinterpret_cast<XrdProto::write_list*>( msg + 24 );
3261  uint64_t size = 0;
3262  uint32_t numChunks = 0;
3263  for( size_t i = 0; i < req->dlen/sizeof(XrdProto::write_list); ++i )
3264  {
3265  fhandle = wrtList[i].fhandle;
3266  size += wrtList[i].wlen;
3267  ++numChunks;
3268  }
3269  o << "handle: ";
3270  if( fhandle )
3271  o << FileHandleToStr( fhandle );
3272  else
3273  o << "unknown";
3274  o << ", ";
3275  o << std::setbase(10);
3276  o << "chunks: " << numChunks << ", ";
3277  o << "total size: " << size << ")";
3278  break;
3279  }
3280 
3281  //------------------------------------------------------------------------
3282  // kXR_locate
3283  //------------------------------------------------------------------------
3284  case kXR_locate:
3285  {
3287  char *fn = GetDataAsString( msg );;
3288  o << "kXR_locate (";
3289  o << "path: " << fn << ", ";
3290  delete [] fn;
3291  o << "flags: ";
3292  if( sreq->options == 0 )
3293  o << "none";
3294  else
3295  {
3296  if( sreq->options & kXR_refresh )
3297  o << "kXR_refresh ";
3298  if( sreq->options & kXR_prefname )
3299  o << "kXR_prefname ";
3300  if( sreq->options & kXR_nowait )
3301  o << "kXR_nowait ";
3302  if( sreq->options & kXR_force )
3303  o << "kXR_force ";
3304  if( sreq->options & kXR_compress )
3305  o << "kXR_compress ";
3306  }
3307  o << ")";
3308  break;
3309  }
3310 
3311  //------------------------------------------------------------------------
3312  // kXR_mv
3313  //------------------------------------------------------------------------
3314  case kXR_mv:
3315  {
3316  ClientMvRequest *sreq = (ClientMvRequest *)msg;
3317  o << "kXR_mv (";
3318  o << "source: ";
3319  o.write( msg + sizeof( ClientMvRequest ), sreq->arg1len );
3320  o << ", ";
3321  o << "destination: ";
3322  o.write( msg + sizeof( ClientMvRequest ) + sreq->arg1len + 1, sreq->dlen - sreq->arg1len - 1 );
3323  o << ")";
3324  break;
3325  }
3326 
3327  //------------------------------------------------------------------------
3328  // kXR_query
3329  //------------------------------------------------------------------------
3330  case kXR_query:
3331  {
3332  ClientQueryRequest *sreq = (ClientQueryRequest *)msg;
3333  o << "kXR_query (";
3334  o << "code: ";
3335  switch( sreq->infotype )
3336  {
3337  case kXR_Qconfig: o << "kXR_Qconfig"; break;
3338  case kXR_Qckscan: o << "kXR_Qckscan"; break;
3339  case kXR_Qcksum: o << "kXR_Qcksum"; break;
3340  case kXR_Qopaque: o << "kXR_Qopaque"; break;
3341  case kXR_Qopaquf: o << "kXR_Qopaquf"; break;
3342  case kXR_Qopaqug: o << "kXR_Qopaqug"; break;
3343  case kXR_QPrep: o << "kXR_QPrep"; break;
3344  case kXR_Qspace: o << "kXR_Qspace"; break;
3345  case kXR_QStats: o << "kXR_QStats"; break;
3346  case kXR_Qvisa: o << "kXR_Qvisa"; break;
3347  case kXR_Qxattr: o << "kXR_Qxattr"; break;
3348  default: o << sreq->infotype; break;
3349  }
3350  o << ", ";
3351 
3352  if( sreq->infotype == kXR_Qopaqug || sreq->infotype == kXR_Qvisa )
3353  {
3354  o << "handle: " << FileHandleToStr( sreq->fhandle );
3355  o << ", ";
3356  }
3357 
3358  o << "arg length: " << sreq->dlen << ")";
3359  break;
3360  }
3361 
3362  //------------------------------------------------------------------------
3363  // kXR_rm
3364  //------------------------------------------------------------------------
3365  case kXR_rm:
3366  {
3367  o << "kXR_rm (";
3368  char *fn = GetDataAsString( msg );;
3369  o << "path: " << fn << ")";
3370  delete [] fn;
3371  break;
3372  }
3373 
3374  //------------------------------------------------------------------------
3375  // kXR_mkdir
3376  //------------------------------------------------------------------------
3377  case kXR_mkdir:
3378  {
3379  ClientMkdirRequest *sreq = (ClientMkdirRequest *)msg;
3380  o << "kXR_mkdir (";
3381  char *fn = GetDataAsString( msg );
3382  o << "path: " << fn << ", ";
3383  delete [] fn;
3384  o << "mode: 0" << std::setbase(8) << sreq->mode << ", ";
3385  o << std::setbase(10);
3386  o << "flags: ";
3387  if( sreq->options[0] == 0 )
3388  o << "none";
3389  else
3390  {
3391  if( sreq->options[0] & kXR_mkdirpath )
3392  o << "kXR_mkdirpath";
3393  }
3394  o << ")";
3395  break;
3396  }
3397 
3398  //------------------------------------------------------------------------
3399  // kXR_rmdir
3400  //------------------------------------------------------------------------
3401  case kXR_rmdir:
3402  {
3403  o << "kXR_rmdir (";
3404  char *fn = GetDataAsString( msg );
3405  o << "path: " << fn << ")";
3406  delete [] fn;
3407  break;
3408  }
3409 
3410  //------------------------------------------------------------------------
3411  // kXR_chmod
3412  //------------------------------------------------------------------------
3413  case kXR_chmod:
3414  {
3415  ClientChmodRequest *sreq = (ClientChmodRequest *)msg;
3416  o << "kXR_chmod (";
3417  char *fn = GetDataAsString( msg );
3418  o << "path: " << fn << ", ";
3419  delete [] fn;
3420  o << "mode: 0" << std::setbase(8) << sreq->mode << ")";
3421  break;
3422  }
3423 
3424  //------------------------------------------------------------------------
3425  // kXR_ping
3426  //------------------------------------------------------------------------
3427  case kXR_ping:
3428  {
3429  o << "kXR_ping ()";
3430  break;
3431  }
3432 
3433  //------------------------------------------------------------------------
3434  // kXR_protocol
3435  //------------------------------------------------------------------------
3436  case kXR_protocol:
3437  {
3439  o << "kXR_protocol (";
3440  o << "clientpv: 0x" << std::setbase(16) << sreq->clientpv << ")";
3441  break;
3442  }
3443 
3444  //------------------------------------------------------------------------
3445  // kXR_dirlist
3446  //------------------------------------------------------------------------
3447  case kXR_dirlist:
3448  {
3449  o << "kXR_dirlist (";
3450  char *fn = GetDataAsString( msg );;
3451  o << "path: " << fn << ")";
3452  delete [] fn;
3453  break;
3454  }
3455 
3456  //------------------------------------------------------------------------
3457  // kXR_set
3458  //------------------------------------------------------------------------
3459  case kXR_set:
3460  {
3461  o << "kXR_set (";
3462  char *fn = GetDataAsString( msg );;
3463  o << "data: " << fn << ")";
3464  delete [] fn;
3465  break;
3466  }
3467 
3468  //------------------------------------------------------------------------
3469  // kXR_prepare
3470  //------------------------------------------------------------------------
3471  case kXR_prepare:
3472  {
3474  o << "kXR_prepare (";
3475  o << "flags: ";
3476 
3477  if( sreq->options == 0 )
3478  o << "none";
3479  else
3480  {
3481  if( sreq->options & kXR_stage )
3482  o << "kXR_stage ";
3483  if( sreq->options & kXR_wmode )
3484  o << "kXR_wmode ";
3485  if( sreq->options & kXR_coloc )
3486  o << "kXR_coloc ";
3487  if( sreq->options & kXR_fresh )
3488  o << "kXR_fresh ";
3489  }
3490 
3491  o << ", priority: " << (int) sreq->prty << ", ";
3492 
3493  char *fn = GetDataAsString( msg );
3494  char *cursor;
3495  for( cursor = fn; *cursor; ++cursor )
3496  if( *cursor == '\n' ) *cursor = ' ';
3497 
3498  o << "paths: " << fn << ")";
3499  delete [] fn;
3500  break;
3501  }
3502 
3503  case kXR_chkpoint:
3504  {
3506  o << "kXR_chkpoint (";
3507  o << "opcode: ";
3508  if( sreq->opcode == kXR_ckpBegin ) o << "kXR_ckpBegin)";
3509  else if( sreq->opcode == kXR_ckpCommit ) o << "kXR_ckpCommit)";
3510  else if( sreq->opcode == kXR_ckpQuery ) o << "kXR_ckpQuery)";
3511  else if( sreq->opcode == kXR_ckpRollback ) o << "kXR_ckpRollback)";
3512  else if( sreq->opcode == kXR_ckpXeq )
3513  {
3514  o << "kXR_ckpXeq) ";
3515  // In this case our request body will be one of kXR_pgwrite,
3516  // kXR_truncate, kXR_write, or kXR_writev request.
3517  GenerateDescription( msg + sizeof( ClientChkPointRequest ), o );
3518  }
3519 
3520  break;
3521  }
3522 
3523  //------------------------------------------------------------------------
3524  // Default
3525  //------------------------------------------------------------------------
3526  default:
3527  {
3528  o << "kXR_unknown (length: " << req->dlen << ")";
3529  break;
3530  }
3531  };
3532  }
3533 
3534  //----------------------------------------------------------------------------
3535  // Get a string representation of file handle
3536  //----------------------------------------------------------------------------
3537  std::string XRootDTransport::FileHandleToStr( const unsigned char handle[4] )
3538  {
3539  std::ostringstream o;
3540  o << "0x";
3541  for( uint8_t i = 0; i < 4; ++i )
3542  {
3543  o << std::setbase(16) << std::setfill('0') << std::setw(2);
3544  o << (int)handle[i];
3545  }
3546  return o.str();
3547  }
3548 }
kXR_int32 dlen
Definition: XProtocol.hh:171
static const int kXR_ckpRollback
Definition: XProtocol.hh:215
@ kXR_NotFound
Definition: XProtocol.hh:1001
kXR_int16 arg1len
Definition: XProtocol.hh:430
#define kXR_isManager
Definition: XProtocol.hh:1156
struct ClientTruncateRequest truncate
Definition: XProtocol.hh:875
union ServerResponse::@0 body
@ kXR_ecredir
Definition: XProtocol.hh:371
#define kXR_tlsLogin
Definition: XProtocol.hh:1184
@ kXR_fattrDel
Definition: XProtocol.hh:270
@ kXR_fattrSet
Definition: XProtocol.hh:273
@ kXR_fattrList
Definition: XProtocol.hh:272
@ kXR_fattrGet
Definition: XProtocol.hh:271
#define kXR_suppgrw
Definition: XProtocol.hh:1174
kXR_int32 dlen
Definition: XProtocol.hh:182
kXR_char fhandle[4]
Definition: XProtocol.hh:531
kXR_unt16 requestid
Definition: XProtocol.hh:394
ServerResponseStatus status
Definition: XProtocol.hh:1310
kXR_char fhandle[4]
Definition: XProtocol.hh:782
#define kXR_gotoTLS
Definition: XProtocol.hh:1180
#define kXR_attrMeta
Definition: XProtocol.hh:1159
struct ClientPgReadRequest pgread
Definition: XProtocol.hh:861
kXR_char fhandle[4]
Definition: XProtocol.hh:807
#define kXR_haveTLS
Definition: XProtocol.hh:1179
kXR_char streamid[2]
Definition: XProtocol.hh:156
kXR_char fhandle[4]
Definition: XProtocol.hh:771
struct ClientMkdirRequest mkdir
Definition: XProtocol.hh:858
kXR_int32 dlen
Definition: XProtocol.hh:431
struct ClientAuthRequest auth
Definition: XProtocol.hh:847
kXR_int64 offset
Definition: XProtocol.hh:646
kXR_char streamid[2]
Definition: XProtocol.hh:914
kXR_unt16 options
Definition: XProtocol.hh:481
static const int kXR_ckpXeq
Definition: XProtocol.hh:216
struct ClientPgWriteRequest pgwrite
Definition: XProtocol.hh:862
#define kXR_attrSuper
Definition: XProtocol.hh:1161
struct ClientReadVRequest readv
Definition: XProtocol.hh:868
kXR_char pathid
Definition: XProtocol.hh:653
kXR_char credtype[4]
Definition: XProtocol.hh:170
kXR_char username[8]
Definition: XProtocol.hh:396
@ kXR_open_wrto
Definition: XProtocol.hh:469
@ kXR_compress
Definition: XProtocol.hh:452
@ kXR_async
Definition: XProtocol.hh:458
@ kXR_delete
Definition: XProtocol.hh:453
@ kXR_prefname
Definition: XProtocol.hh:461
@ kXR_nowait
Definition: XProtocol.hh:467
@ kXR_open_read
Definition: XProtocol.hh:456
@ kXR_open_updt
Definition: XProtocol.hh:457
@ kXR_mkpath
Definition: XProtocol.hh:460
@ kXR_seqio
Definition: XProtocol.hh:468
@ kXR_replica
Definition: XProtocol.hh:465
@ kXR_posc
Definition: XProtocol.hh:466
@ kXR_refresh
Definition: XProtocol.hh:459
@ kXR_new
Definition: XProtocol.hh:455
@ kXR_force
Definition: XProtocol.hh:454
@ kXR_4dirlist
Definition: XProtocol.hh:464
@ kXR_open_apnd
Definition: XProtocol.hh:462
@ kXR_retstat
Definition: XProtocol.hh:463
struct ClientOpenRequest open
Definition: XProtocol.hh:860
@ kXR_waitresp
Definition: XProtocol.hh:906
@ kXR_redirect
Definition: XProtocol.hh:904
@ kXR_status
Definition: XProtocol.hh:907
@ kXR_ok
Definition: XProtocol.hh:899
@ kXR_authmore
Definition: XProtocol.hh:902
@ kXR_attn
Definition: XProtocol.hh:901
@ kXR_wait
Definition: XProtocol.hh:905
@ kXR_error
Definition: XProtocol.hh:903
struct ServerResponseBody_Status bdy
Definition: XProtocol.hh:1262
struct ClientRequestHdr header
Definition: XProtocol.hh:846
kXR_char fhandle[4]
Definition: XProtocol.hh:509
kXR_unt16 infotype
Definition: XProtocol.hh:631
kXR_int32 fourth
Definition: XProtocol.hh:87
kXR_char fhandle[4]
Definition: XProtocol.hh:645
kXR_char fhandle[4]
Definition: XProtocol.hh:659
struct ClientWriteVRequest writev
Definition: XProtocol.hh:877
kXR_char fhandle[4]
Definition: XProtocol.hh:229
struct ClientLoginRequest login
Definition: XProtocol.hh:857
kXR_unt16 requestid
Definition: XProtocol.hh:157
kXR_char fhandle[4]
Definition: XProtocol.hh:633
kXR_char sessid[16]
Definition: XProtocol.hh:181
@ kXR_read
Definition: XProtocol.hh:125
@ kXR_open
Definition: XProtocol.hh:122
@ kXR_writev
Definition: XProtocol.hh:143
@ kXR_readv
Definition: XProtocol.hh:137
@ kXR_mkdir
Definition: XProtocol.hh:120
@ kXR_sync
Definition: XProtocol.hh:128
@ kXR_chmod
Definition: XProtocol.hh:114
@ kXR_bind
Definition: XProtocol.hh:136
@ kXR_dirlist
Definition: XProtocol.hh:116
@ kXR_fattr
Definition: XProtocol.hh:132
@ kXR_rm
Definition: XProtocol.hh:126
@ kXR_query
Definition: XProtocol.hh:113
@ kXR_write
Definition: XProtocol.hh:131
@ kXR_login
Definition: XProtocol.hh:119
@ kXR_auth
Definition: XProtocol.hh:112
@ kXR_endsess
Definition: XProtocol.hh:135
@ kXR_set
Definition: XProtocol.hh:130
@ kXR_rmdir
Definition: XProtocol.hh:127
@ kXR_1stRequest
Definition: XProtocol.hh:111
@ kXR_truncate
Definition: XProtocol.hh:140
@ kXR_protocol
Definition: XProtocol.hh:118
@ kXR_mv
Definition: XProtocol.hh:121
@ kXR_ping
Definition: XProtocol.hh:123
@ kXR_stat
Definition: XProtocol.hh:129
@ kXR_pgread
Definition: XProtocol.hh:142
@ kXR_chkpoint
Definition: XProtocol.hh:124
@ kXR_locate
Definition: XProtocol.hh:139
@ kXR_close
Definition: XProtocol.hh:115
@ kXR_pgwrite
Definition: XProtocol.hh:138
@ kXR_prepare
Definition: XProtocol.hh:133
struct ClientChmodRequest chmod
Definition: XProtocol.hh:850
#define kXR_isServer
Definition: XProtocol.hh:1157
#define kXR_attrCache
Definition: XProtocol.hh:1158
kXR_int32 protover
Definition: XProtocol.hh:95
struct ClientQueryRequest query
Definition: XProtocol.hh:866
kXR_int32 dlen
Definition: XProtocol.hh:648
struct ClientReadRequest read
Definition: XProtocol.hh:867
struct ClientMvRequest mv
Definition: XProtocol.hh:859
kXR_int32 rlen
Definition: XProtocol.hh:660
kXR_unt16 requestid
Definition: XProtocol.hh:180
kXR_char sessid[16]
Definition: XProtocol.hh:259
struct ClientChkPointRequest chkpoint
Definition: XProtocol.hh:849
kXR_char fhandle[4]
Definition: XProtocol.hh:794
struct ServerResponseHeader hdr
Definition: XProtocol.hh:1261
kXR_unt16 mode
Definition: XProtocol.hh:480
@ kXR_asyncap
Definition: XProtocol.hh:378
#define kXR_attrProxy
Definition: XProtocol.hh:1160
kXR_char options[1]
Definition: XProtocol.hh:416
#define kXR_PROTOCOLVERSION
Definition: XProtocol.hh:70
static const int kXR_ckpCommit
Definition: XProtocol.hh:213
kXR_int64 offset
Definition: XProtocol.hh:661
@ kXR_vfs
Definition: XProtocol.hh:763
struct ClientPrepareRequest prepare
Definition: XProtocol.hh:864
@ kXR_mkdirpath
Definition: XProtocol.hh:410
@ kXR_wmode
Definition: XProtocol.hh:591
@ kXR_fresh
Definition: XProtocol.hh:593
@ kXR_coloc
Definition: XProtocol.hh:592
@ kXR_stage
Definition: XProtocol.hh:590
static const int kXR_ckpQuery
Definition: XProtocol.hh:214
#define kXR_tlsSess
Definition: XProtocol.hh:1185
#define kXR_DataServer
Definition: XProtocol.hh:1150
kXR_int64 offset
Definition: XProtocol.hh:808
struct ClientWriteRequest write
Definition: XProtocol.hh:876
#define kXR_PROTTLSVERSION
Definition: XProtocol.hh:72
kXR_int32 dlen
Definition: XProtocol.hh:772
kXR_char options
Definition: XProtocol.hh:769
kXR_char capver[1]
Definition: XProtocol.hh:399
kXR_int32 rlen
Definition: XProtocol.hh:647
struct ClientProtocolRequest protocol
Definition: XProtocol.hh:865
@ kXR_QPrep
Definition: XProtocol.hh:616
@ kXR_Qopaqug
Definition: XProtocol.hh:625
@ kXR_Qconfig
Definition: XProtocol.hh:621
@ kXR_Qopaquf
Definition: XProtocol.hh:624
@ kXR_Qckscan
Definition: XProtocol.hh:620
@ kXR_Qxattr
Definition: XProtocol.hh:618
@ kXR_Qspace
Definition: XProtocol.hh:619
@ kXR_Qvisa
Definition: XProtocol.hh:622
@ kXR_QStats
Definition: XProtocol.hh:615
@ kXR_Qcksum
Definition: XProtocol.hh:617
@ kXR_Qopaque
Definition: XProtocol.hh:623
struct ClientLocateRequest locate
Definition: XProtocol.hh:856
@ kXR_ver005
Definition: XProtocol.hh:389
kXR_int32 msgval
Definition: XProtocol.hh:96
#define kXR_tlsData
Definition: XProtocol.hh:1182
@ kXR_readrdok
Definition: XProtocol.hh:360
@ kXR_fullurl
Definition: XProtocol.hh:358
@ kXR_onlyprv4
Definition: XProtocol.hh:362
@ kXR_lclfile
Definition: XProtocol.hh:364
@ kXR_multipr
Definition: XProtocol.hh:359
@ kXR_redirflags
Definition: XProtocol.hh:365
@ kXR_hasipv64
Definition: XProtocol.hh:361
@ kXR_onlyprv6
Definition: XProtocol.hh:363
kXR_int32 dlen
Definition: XProtocol.hh:159
ServerResponseHeader hdr
Definition: XProtocol.hh:1288
static const int kXR_ckpBegin
Definition: XProtocol.hh:212
long long kXR_int64
Definition: XPtypes.hh:98
unsigned char kXR_char
Definition: XPtypes.hh:65
XrdVERSIONINFOREF(XrdCl)
XrdSecBuffer XrdSecParameters
XrdSecProtocol *(* XrdSecGetProt_t)(const char *hostname, XrdNetAddrInfo &endPoint, XrdSecParameters &sectoken, XrdOucErrInfo *einfo)
Typedef to simplify the encoding of methods returning XrdSecProtocol.
XrdSecGetProt_t XrdSecLoadSecFactory(char *eBuff, int eBlen, const char *seclib)
int XrdSecGetProtection(XrdSecProtect *&protP, XrdSecProtocol &aprot, ServerResponseBody_Protocol &resp, unsigned int resplen)
#define NEED2SECURE(protP)
This class implements the XRootD protocol security protection.
const char * XrdSysE2T(int errcode)
Definition: XrdSysE2T.cc:104
void Set(Type object, bool own=true)
void Get(Type &object)
Retrieve the object being held.
void AdvanceCursor(uint32_t delta)
Advance the cursor.
Definition: XrdClBuffer.hh:156
void Grab(char *buffer, uint32_t size)
Grab a buffer allocated outside.
Definition: XrdClBuffer.hh:228
void Zero()
Zero.
Definition: XrdClBuffer.hh:124
const char * GetBuffer(uint32_t offset=0) const
Get the message buffer.
Definition: XrdClBuffer.hh:72
void ReAllocate(uint32_t size)
Reallocate the buffer to a new location of a given size.
Definition: XrdClBuffer.hh:88
void Allocate(uint32_t size)
Allocate the buffer.
Definition: XrdClBuffer.hh:110
uint32_t GetCursor() const
Get append cursor.
Definition: XrdClBuffer.hh:140
uint32_t GetSize() const
Get the size of the message.
Definition: XrdClBuffer.hh:132
char * GetBufferAtCursor()
Get the buffer pointer at the append cursor.
Definition: XrdClBuffer.hh:189
static TransportManager * GetTransportManager()
Get transport manager.
static Log * GetLog()
Get default log.
static Env * GetEnv()
Get default client environment.
bool PutInt(const std::string &key, int value)
Definition: XrdClEnv.cc:110
bool GetInt(const std::string &key, int &value)
Definition: XrdClEnv.cc:89
Handle diagnostics.
Definition: XrdClLog.hh:101
@ ErrorMsg
report errors
Definition: XrdClLog.hh:109
void Error(uint64_t topic, const char *format,...)
Report an error.
Definition: XrdClLog.cc:231
LogLevel GetLevel() const
Get the log level.
Definition: XrdClLog.hh:258
void Dump(uint64_t topic, const char *format,...)
Print a dump message.
Definition: XrdClLog.cc:299
void Debug(uint64_t topic, const char *format,...)
Print a debug message.
Definition: XrdClLog.cc:282
The message representation used throughout the system.
Definition: XrdClMessage.hh:32
void SetIsMarshalled(bool isMarshalled)
Set the marshalling status.
Definition: XrdClMessage.hh:81
bool IsMarshalled() const
Check if the message is marshalled.
Definition: XrdClMessage.hh:73
static SIDMgrPool & Instance()
std::shared_ptr< SIDManager > GetSIDMgr(const URL &url)
A network socket.
Definition: XrdClSocket.hh:43
virtual XRootDStatus Read(char *buffer, size_t size, int &bytesRead)
Definition: XrdClSocket.cc:740
static void ClearErrorQueue()
Clear the error queue for the calling thread.
Definition: XrdClTls.cc:422
Perform the handshake and the authentication for each physical stream.
@ RequestClose
Send a close request.
virtual void WaitBeforeExit()=0
Wait before exit.
Manage transport handler objects.
TransportHandler * GetHandler(const std::string &protocol)
Get a transport handler object for a given protocol.
URL representation.
Definition: XrdClURL.hh:31
std::string GetChannelId() const
Definition: XrdClURL.cc:512
std::map< std::string, std::string > ParamsMap
Definition: XrdClURL.hh:33
bool IsSecure() const
Does the protocol indicate encryption.
Definition: XrdClURL.cc:482
bool IsTPC() const
Is the URL used in TPC context.
Definition: XrdClURL.cc:490
std::string GetLoginToken() const
Get the login token if present in the opaque info.
Definition: XrdClURL.cc:367
static std::string TimeToString(time_t timestamp)
Convert timestamp to a string.
Definition: XrdClUtils.cc:256
static std::string FQDNToCC(const std::string &fqdn)
Convert the fully qualified host name to country code.
Definition: XrdClUtils.cc:490
static std::string Char2Hex(uint8_t *array, uint16_t size)
Print a char array as hex.
Definition: XrdClUtils.cc:635
static void splitString(Container &result, const std::string &input, const std::string &delimiter)
Split a string.
Definition: XrdClUtils.hh:56
const std::string & GetErrorMessage() const
Get error message.
static uint16_t NbConnectedStrm(AnyObject &channelData)
Number of currently connected data streams.
virtual bool IsStreamTTLElapsed(time_t time, AnyObject &channelData)
Check if the stream should be disconnected.
virtual void Disconnect(AnyObject &channelData, uint16_t subStreamId)
The stream has been disconnected, do the cleanups.
virtual uint32_t MessageReceived(Message &msg, uint16_t subStream, AnyObject &channelData)
Check if the message invokes a stream action.
virtual void WaitBeforeExit()
Wait until the program can safely exit.
static XRootDStatus UnMarshallBody(Message *msg, uint16_t reqType)
Unmarshall the body of the incoming message.
virtual XRootDStatus GetBody(Message &message, Socket *socket)
virtual XRootDStatus GetHeader(Message &message, Socket *socket)
virtual uint16_t SubStreamNumber(AnyObject &channelData)
Return a number of substreams per stream that should be created.
virtual void FinalizeChannel(AnyObject &channelData)
Finalize channel.
virtual bool HandShakeDone(HandShakeData *handShakeData, AnyObject &channelData)
virtual Status GetSignature(Message *toSign, Message *&sign, AnyObject &channelData)
Get signature for given message.
virtual void MessageSent(Message *msg, uint16_t subStream, uint32_t bytesSent, AnyObject &channelData)
Notify the transport about a message having been sent.
virtual XRootDStatus HandShake(HandShakeData *handShakeData, AnyObject &channelData)
HandShake.
virtual XRootDStatus GetMore(Message &message, Socket *socket)
static void GenerateDescription(char *msg, std::ostringstream &o)
Get the description of a message.
static XRootDStatus UnMarshallRequest(Message *msg)
static XRootDStatus UnMarchalStatusMore(Message &msg)
Unmarshall the correction-segment of the status response for pgwrite.
static void LogErrorResponse(const Message &msg)
Log server error response.
virtual void DecFileInstCnt(AnyObject &channelData)
Decrement file object instance count bound to this channel.
virtual PathID Multiplex(Message *msg, AnyObject &channelData, PathID *hint=0)
virtual void InitializeChannel(const URL &url, AnyObject &channelData)
Initialize channel.
virtual Status Query(uint16_t query, AnyObject &result, AnyObject &channelData)
Query the channel.
static void UnMarshallHeader(Message &msg)
Unmarshall the header incoming message.
static XRootDStatus UnMarshalStatusBody(Message &msg, uint16_t reqType)
Unmarshall the body of the status response.
static XRootDStatus MarshallRequest(Message *msg)
Marshal the outgoing message.
virtual URL GetBindPreference(const URL &url, AnyObject &channelData)
Get bind preference for the next data stream.
virtual PathID MultiplexSubStream(Message *msg, AnyObject &channelData, PathID *hint=0)
virtual bool NeedEncryption(HandShakeData *handShakeData, AnyObject &channelData)
virtual Status IsStreamBroken(time_t inactiveTime, AnyObject &channelData)
void SetTLS(bool val)
Definition: XrdNetAddr.cc:590
static char * MyHostName(const char *eName="*unknown*", const char **eText=0)
Definition: XrdNetUtils.cc:702
static NetProt NetConfig(NetType netquery=qryINET, const char **eText=0)
Definition: XrdNetUtils.cc:716
static uint32_t Calc32C(const void *data, size_t count, uint32_t prevcs=0)
Definition: XrdOucCRC.cc:190
static int UserName(uid_t uID, char *uName, int uNsz)
virtual int Secure(SecurityRequest *&newreq, ClientRequest &thereq, const char *thedata)
static int TimeZone()
Definition: XrdSysTimer.cc:210
const uint16_t suRetry
Definition: XrdClStatus.hh:40
const uint16_t errQueryNotSupported
Definition: XrdClStatus.hh:89
const int DefaultLoadBalancerTTL
const uint64_t XRootDTransportMsg
const uint16_t errTlsError
Definition: XrdClStatus.hh:80
const uint16_t stFatal
Fatal error, it's still an error.
Definition: XrdClStatus.hh:33
const uint16_t stError
An error occurred that could potentially be retried.
Definition: XrdClStatus.hh:32
const uint16_t errLoginFailed
Definition: XrdClStatus.hh:87
const int DefaultWantTlsOnNoPgrw
const uint16_t errSocketTimeout
Definition: XrdClStatus.hh:73
const uint64_t XRootDMsg
const uint16_t errDataError
data is corrupted
Definition: XrdClStatus.hh:63
const uint16_t errInternal
Internal error.
Definition: XrdClStatus.hh:56
const uint16_t stOK
Everything went OK.
Definition: XrdClStatus.hh:31
const int DefaultSubStreamsPerChannel
const uint16_t errInvalidOp
Definition: XrdClStatus.hh:51
const int DefaultDataServerTTL
const uint16_t errHandShakeFailed
Definition: XrdClStatus.hh:86
const int DefaultStreamTimeout
const uint16_t suAlreadyDone
Definition: XrdClStatus.hh:42
const uint16_t errNotSupported
Definition: XrdClStatus.hh:62
const uint16_t suDone
Definition: XrdClStatus.hh:38
const uint16_t suContinue
Definition: XrdClStatus.hh:39
bool InitTLS()
Definition: XrdClTls.cc:96
const int DefaultTlsNoData
const int DefaultNoTlsOK
const uint16_t errAuthFailed
Definition: XrdClStatus.hh:88
const uint16_t errInvalidMessage
Definition: XrdClStatus.hh:85
XrdSysError Log
Definition: XrdConfig.cc:113
kXR_char fhandle[4]
Definition: XProtocol.hh:832
struct ServerResponseBifs_Protocol bifReqs
Definition: XProtocol.hh:1120
kXR_char fhandle[4]
Definition: XProtocol.hh:288
BindPrefSelector(std::vector< std::string > &&bindprefs)
const std::string & Get()
Data structure that carries the handshake information.
std::string streamName
Name of the stream.
uint16_t subStreamId
Sub-stream id.
Message * out
Message to be sent out.
static void UnloadHandler(const std::string &trProt)
void Register(const std::string &protocol)
std::set< std::string > protocols
Procedure execution status.
Definition: XrdClStatus.hh:115
uint16_t code
Error type, or additional hints on what to do.
Definition: XrdClStatus.hh:147
bool IsOK() const
We're fine.
Definition: XrdClStatus.hh:124
Selects less loaded stream for read operation over multiple streams.
void AdjustQueues(uint16_t size)
void MsgReceived(uint16_t substrm)
uint16_t Select(const std::vector< bool > &connected)
static const uint16_t Name
Transport name, returns const char *.
static const uint16_t Auth
Transport name, returns std::string *.
Information holder for xrootd channels.
std::vector< XRootDStreamInfo > StreamInfoVector
std::set< uint16_t > sentCloses
std::unique_ptr< StreamSelector > strmSelector
std::unique_ptr< BindPrefSelector > bindSelector
std::atomic< uint32_t > finstcnt
ServerResponseBody_Protocol * protRespBody
std::set< uint16_t > sentOpens
std::shared_ptr< SIDManager > sidManager
static const uint16_t ServerFlags
returns server flags
static const uint16_t ProtocolVersion
returns the protocol version
static const uint16_t IsEncrypted
returns true if the channel is encrypted
Information holder for XRootDStreams.
Generic structure to pass security information back and forth.
char * buffer
Pointer to the buffer.
int size
Size of the buffer or length of data in the buffer.