Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TSocket.cxx
Go to the documentation of this file.
1 // @(#)root/net:$Id$
2 // Author: Fons Rademakers 18/12/96
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 //////////////////////////////////////////////////////////////////////////
13 // //
14 // TSocket //
15 // //
16 // This class implements client sockets. A socket is an endpoint for //
17 // communication between two machines. //
18 // The actual work is done via the TSystem class (either TUnixSystem //
19 // or TWinNTSystem). //
20 // //
21 //////////////////////////////////////////////////////////////////////////
22 
23 #include "Bytes.h"
24 #include "Compression.h"
25 #include "NetErrors.h"
26 #include "TEnv.h"
27 #include "TError.h"
28 #include "TMessage.h"
29 #include "TPSocket.h"
30 #include "TPluginManager.h"
31 #include "TROOT.h"
32 #include "TString.h"
33 #include "TSystem.h"
34 #include "TUrl.h"
35 #include "TVirtualAuth.h"
36 #include "TStreamerInfo.h"
37 #include "TProcessID.h"
38 
39 ULong64_t TSocket::fgBytesSent = 0;
40 ULong64_t TSocket::fgBytesRecv = 0;
41 
42 //
43 // Client "protocol changes"
44 //
45 // This was in TNetFile and TAuthenticate before, but after the introduction
46 // of TSocket::CreateAuthSocket the common place for all the clients is TSocket,
47 // so this seems to be the right place for a version number
48 //
49 // 7: added support for ReOpen(), kROOTD_BYE and kROOTD_PROTOCOL2
50 // 8: added support for update being a create (open stat = 2 and not 1)
51 // 9: added new authentication features (see README.AUTH)
52 // 10: added support for authenticated socket via TSocket::CreateAuthSocket(...)
53 // 11: modified SSH protocol + support for server 'no authentication' mode
54 // 12: add random tags to avoid reply attacks (password+token)
55 // 13: authentication re-organization; cleanup in PROOF
56 // 14: support for SSH authentication via SSH tunnel
57 // 15: cope with fixes in TUrl::GetFile
58 // 16: add env setup message exchange
59 //
60 Int_t TSocket::fgClientProtocol = 17; // increase when client protocol changes
61 
62 TVirtualMutex *gSocketAuthMutex = 0;
63 
64 ClassImp(TSocket);
65 
66 ////////////////////////////////////////////////////////////////////////////////
67 /// Create a socket. Connect to the named service at address addr.
68 /// Use tcpwindowsize to specify the size of the receive buffer, it has
69 /// to be specified here to make sure the window scale option is set (for
70 /// tcpwindowsize > 65KB and for platforms supporting window scaling).
71 /// Returns when connection has been accepted by remote side. Use IsValid()
72 /// to check the validity of the socket. Every socket is added to the TROOT
73 /// sockets list which will make sure that any open sockets are properly
74 /// closed on program termination.
75 
76 TSocket::TSocket(TInetAddress addr, const char *service, Int_t tcpwindowsize)
77  : TNamed(addr.GetHostName(), service), fCompress(ROOT::RCompressionSetting::EAlgorithm::kUseGlobal)
78 {
79  R__ASSERT(gROOT);
80  R__ASSERT(gSystem);
81 
82  fService = service;
83  fSecContext = 0;
84  fRemoteProtocol= -1;
85  fServType = kSOCKD;
86  if (fService.Contains("root"))
87  fServType = kROOTD;
88  if (fService.Contains("proof"))
89  fServType = kPROOFD;
90  fAddress = addr;
91  fAddress.fPort = gSystem->GetServiceByName(service);
92  fBytesSent = 0;
93  fBytesRecv = 0;
94  fTcpWindowSize = tcpwindowsize;
95  fUUIDs = 0;
96  fLastUsageMtx = 0;
97  ResetBit(TSocket::kBrokenConn);
98 
99  if (fAddress.GetPort() != -1) {
100  fSocket = gSystem->OpenConnection(addr.GetHostName(), fAddress.GetPort(),
101  tcpwindowsize);
102 
103  if (fSocket != kInvalid) {
104  gROOT->GetListOfSockets()->Add(this);
105  }
106  } else
107  fSocket = kInvalid;
108 
109 }
110 
111 ////////////////////////////////////////////////////////////////////////////////
112 /// Create a socket. Connect to the specified port # at address addr.
113 /// Use tcpwindowsize to specify the size of the receive buffer, it has
114 /// to be specified here to make sure the window scale option is set (for
115 /// tcpwindowsize > 65KB and for platforms supporting window scaling).
116 /// Returns when connection has been accepted by remote side. Use IsValid()
117 /// to check the validity of the socket. Every socket is added to the TROOT
118 /// sockets list which will make sure that any open sockets are properly
119 /// closed on program termination.
120 
121 TSocket::TSocket(TInetAddress addr, Int_t port, Int_t tcpwindowsize)
122  : TNamed(addr.GetHostName(), ""), fCompress(ROOT::RCompressionSetting::EAlgorithm::kUseGlobal)
123 {
124  R__ASSERT(gROOT);
125  R__ASSERT(gSystem);
126 
127  fService = gSystem->GetServiceByPort(port);
128  fSecContext = 0;
129  fRemoteProtocol= -1;
130  fServType = kSOCKD;
131  if (fService.Contains("root"))
132  fServType = kROOTD;
133  if (fService.Contains("proof"))
134  fServType = kPROOFD;
135  fAddress = addr;
136  fAddress.fPort = port;
137  SetTitle(fService);
138  fBytesSent = 0;
139  fBytesRecv = 0;
140  fTcpWindowSize = tcpwindowsize;
141  fUUIDs = 0;
142  fLastUsageMtx = 0;
143  ResetBit(TSocket::kBrokenConn);
144 
145  fSocket = gSystem->OpenConnection(addr.GetHostName(), fAddress.GetPort(),
146  tcpwindowsize);
147  if (fSocket == kInvalid)
148  fAddress.fPort = -1;
149  else {
150  gROOT->GetListOfSockets()->Add(this);
151  }
152 }
153 
154 ////////////////////////////////////////////////////////////////////////////////
155 /// Create a socket. Connect to named service on the remote host.
156 /// Use tcpwindowsize to specify the size of the receive buffer, it has
157 /// to be specified here to make sure the window scale option is set (for
158 /// tcpwindowsize > 65KB and for platforms supporting window scaling).
159 /// Returns when connection has been accepted by remote side. Use IsValid()
160 /// to check the validity of the socket. Every socket is added to the TROOT
161 /// sockets list which will make sure that any open sockets are properly
162 /// closed on program termination.
163 
164 TSocket::TSocket(const char *host, const char *service, Int_t tcpwindowsize)
165  : TNamed(host, service), fCompress(ROOT::RCompressionSetting::EAlgorithm::kUseGlobal)
166 {
167  R__ASSERT(gROOT);
168  R__ASSERT(gSystem);
169 
170  fService = service;
171  fSecContext = 0;
172  fRemoteProtocol= -1;
173  fServType = kSOCKD;
174  if (fService.Contains("root"))
175  fServType = kROOTD;
176  if (fService.Contains("proof"))
177  fServType = kPROOFD;
178  fAddress = gSystem->GetHostByName(host);
179  fAddress.fPort = gSystem->GetServiceByName(service);
180  SetName(fAddress.GetHostName());
181  fBytesSent = 0;
182  fBytesRecv = 0;
183  fTcpWindowSize = tcpwindowsize;
184  fUUIDs = 0;
185  fLastUsageMtx = 0;
186  ResetBit(TSocket::kBrokenConn);
187 
188  if (fAddress.GetPort() != -1) {
189  fSocket = gSystem->OpenConnection(host, fAddress.GetPort(), tcpwindowsize);
190  if (fSocket != kInvalid) {
191  gROOT->GetListOfSockets()->Add(this);
192  }
193  } else
194  fSocket = kInvalid;
195 }
196 
197 ////////////////////////////////////////////////////////////////////////////////
198 /// Create a socket; see CreateAuthSocket for the form of url.
199 /// Connect to the specified port # on the remote host.
200 /// If user is specified in url, try authentication as user.
201 /// Use tcpwindowsize to specify the size of the receive buffer, it has
202 /// to be specified here to make sure the window scale option is set (for
203 /// tcpwindowsize > 65KB and for platforms supporting window scaling).
204 /// Returns when connection has been accepted by remote side. Use IsValid()
205 /// to check the validity of the socket. Every socket is added to the TROOT
206 /// sockets list which will make sure that any open sockets are properly
207 /// closed on program termination.
208 
209 TSocket::TSocket(const char *url, Int_t port, Int_t tcpwindowsize)
210  : TNamed(TUrl(url).GetHost(), ""), fCompress(ROOT::RCompressionSetting::EAlgorithm::kUseGlobal)
211 {
212  R__ASSERT(gROOT);
213  R__ASSERT(gSystem);
214 
215  fUrl = TString(url);
216  TString host(TUrl(fUrl).GetHost());
217 
218  fService = gSystem->GetServiceByPort(port);
219  fSecContext = 0;
220  fRemoteProtocol= -1;
221  fServType = kSOCKD;
222  if (fUrl.Contains("root"))
223  fServType = kROOTD;
224  if (fUrl.Contains("proof"))
225  fServType = kPROOFD;
226  fAddress = gSystem->GetHostByName(host);
227  fAddress.fPort = port;
228  SetName(fAddress.GetHostName());
229  SetTitle(fService);
230  fBytesSent = 0;
231  fBytesRecv = 0;
232  fTcpWindowSize = tcpwindowsize;
233  fUUIDs = 0;
234  fLastUsageMtx = 0;
235  ResetBit(TSocket::kBrokenConn);
236 
237  fSocket = gSystem->OpenConnection(host, fAddress.GetPort(), tcpwindowsize);
238  if (fSocket == kInvalid) {
239  fAddress.fPort = kInvalid;
240  } else {
241  gROOT->GetListOfSockets()->Add(this);
242  }
243 }
244 
245 ////////////////////////////////////////////////////////////////////////////////
246 /// Create a socket in the Unix domain on 'sockpath'.
247 /// Returns when connection has been accepted by the server. Use IsValid()
248 /// to check the validity of the socket. Every socket is added to the TROOT
249 /// sockets list which will make sure that any open sockets are properly
250 /// closed on program termination.
251 
252 TSocket::TSocket(const char *sockpath) : TNamed(sockpath, ""),
253  fCompress(ROOT::RCompressionSetting::EAlgorithm::kUseGlobal)
254 {
255  R__ASSERT(gROOT);
256  R__ASSERT(gSystem);
257 
258  fUrl = sockpath;
259 
260  fService = "unix";
261  fSecContext = 0;
262  fRemoteProtocol= -1;
263  fServType = kSOCKD;
264  fAddress.fPort = -1;
265  fName.Form("unix:%s", sockpath);
266  SetTitle(fService);
267  fBytesSent = 0;
268  fBytesRecv = 0;
269  fTcpWindowSize = -1;
270  fUUIDs = 0;
271  fLastUsageMtx = 0;
272  ResetBit(TSocket::kBrokenConn);
273 
274  fSocket = gSystem->OpenConnection(sockpath, -1, -1);
275  if (fSocket > 0) {
276  gROOT->GetListOfSockets()->Add(this);
277  }
278 }
279 
280 ////////////////////////////////////////////////////////////////////////////////
281 /// Create a socket. The socket will adopt previously opened TCP socket with
282 /// descriptor desc.
283 
284 TSocket::TSocket(Int_t desc) : TNamed("", ""), fCompress(ROOT::RCompressionSetting::EAlgorithm::kUseGlobal)
285 {
286  R__ASSERT(gROOT);
287  R__ASSERT(gSystem);
288 
289  fSecContext = 0;
290  fRemoteProtocol = 0;
291  fService = (char *)kSOCKD;
292  fServType = kSOCKD;
293  fBytesSent = 0;
294  fBytesRecv = 0;
295  fTcpWindowSize = -1;
296  fUUIDs = 0;
297  fLastUsageMtx = 0;
298  ResetBit(TSocket::kBrokenConn);
299 
300  if (desc >= 0) {
301  fSocket = desc;
302  fAddress = gSystem->GetPeerName(fSocket);
303  gROOT->GetListOfSockets()->Add(this);
304  } else
305  fSocket = kInvalid;
306 }
307 
308 ////////////////////////////////////////////////////////////////////////////////
309 /// Create a socket. The socket will adopt previously opened Unix socket with
310 /// descriptor desc. The sockpath arg is for info purposes only. Use
311 /// this method to adopt e.g. a socket created via socketpair().
312 
313 TSocket::TSocket(Int_t desc, const char *sockpath) : TNamed(sockpath, ""),
314  fCompress(ROOT::RCompressionSetting::EAlgorithm::kUseGlobal)
315 {
316  R__ASSERT(gROOT);
317  R__ASSERT(gSystem);
318 
319  fUrl = sockpath;
320 
321  fService = "unix";
322  fSecContext = 0;
323  fRemoteProtocol= -1;
324  fServType = kSOCKD;
325  fAddress.fPort = -1;
326  fName.Form("unix:%s", sockpath);
327  SetTitle(fService);
328  fBytesSent = 0;
329  fBytesRecv = 0;
330  fTcpWindowSize = -1;
331  fUUIDs = 0;
332  fLastUsageMtx = 0;
333  ResetBit(TSocket::kBrokenConn);
334 
335  if (desc >= 0) {
336  fSocket = desc;
337  gROOT->GetListOfSockets()->Add(this);
338  } else
339  fSocket = kInvalid;
340 }
341 
342 
343 ////////////////////////////////////////////////////////////////////////////////
344 /// TSocket copy ctor.
345 
346 TSocket::TSocket(const TSocket &s) : TNamed(s)
347 {
348  fSocket = s.fSocket;
349  fService = s.fService;
350  fAddress = s.fAddress;
351  fLocalAddress = s.fLocalAddress;
352  fBytesSent = s.fBytesSent;
353  fBytesRecv = s.fBytesRecv;
354  fCompress = s.fCompress;
355  fSecContext = s.fSecContext;
356  fRemoteProtocol = s.fRemoteProtocol;
357  fServType = s.fServType;
358  fTcpWindowSize = s.fTcpWindowSize;
359  fUUIDs = 0;
360  fLastUsageMtx = 0;
361  ResetBit(TSocket::kBrokenConn);
362 
363  if (fSocket != kInvalid) {
364  gROOT->GetListOfSockets()->Add(this);
365  }
366 }
367 ////////////////////////////////////////////////////////////////////////////////
368 /// Close the socket and mark as due to a broken connection.
369 
370 void TSocket::MarkBrokenConnection()
371 {
372  SetBit(TSocket::kBrokenConn);
373  if (IsValid()) {
374  gSystem->CloseConnection(fSocket, kFALSE);
375  fSocket = kInvalidStillInList;
376  }
377 
378  SafeDelete(fUUIDs);
379  SafeDelete(fLastUsageMtx);
380 }
381 
382 ////////////////////////////////////////////////////////////////////////////////
383 /// Close the socket. If option is "force", calls shutdown(id,2) to
384 /// shut down the connection. This will close the connection also
385 /// for the parent of this process. Also called via the dtor (without
386 /// option "force", call explicitly Close("force") if this is desired).
387 
388 void TSocket::Close(Option_t *option)
389 {
390  Bool_t force = option ? (!strcmp(option, "force") ? kTRUE : kFALSE) : kFALSE;
391 
392  if (fSocket != kInvalid) {
393  if (IsValid()) { // Filter out kInvalidStillInList case (disconnected but not removed from list)
394  gSystem->CloseConnection(fSocket, force);
395  }
396  gROOT->GetListOfSockets()->Remove(this);
397  }
398  fSocket = kInvalid;
399 
400  SafeDelete(fUUIDs);
401  SafeDelete(fLastUsageMtx);
402 }
403 
404 ////////////////////////////////////////////////////////////////////////////////
405 /// Return internet address of local host to which the socket is bound.
406 /// In case of error TInetAddress::IsValid() returns kFALSE.
407 
408 TInetAddress TSocket::GetLocalInetAddress()
409 {
410  if (IsValid()) {
411  if (fLocalAddress.GetPort() == -1)
412  fLocalAddress = gSystem->GetSockName(fSocket);
413  return fLocalAddress;
414  }
415  return TInetAddress();
416 }
417 
418 ////////////////////////////////////////////////////////////////////////////////
419 /// Return the local port # to which the socket is bound.
420 /// In case of error return -1.
421 
422 Int_t TSocket::GetLocalPort()
423 {
424  if (IsValid()) {
425  if (fLocalAddress.GetPort() == -1)
426  GetLocalInetAddress();
427  return fLocalAddress.GetPort();
428  }
429  return -1;
430 }
431 
432 ////////////////////////////////////////////////////////////////////////////////
433 /// Waits for this socket to change status. If interest=kRead,
434 /// the socket will be watched to see if characters become available for
435 /// reading; if interest=kWrite the socket will be watched to
436 /// see if a write will not block.
437 /// The argument 'timeout' specifies a maximum time to wait in millisec.
438 /// Default no timeout.
439 /// Returns 1 if a change of status of interest has been detected within
440 /// timeout; 0 in case of timeout; < 0 if an error occured.
441 
442 Int_t TSocket::Select(Int_t interest, Long_t timeout)
443 {
444  Int_t rc = 1;
445 
446  // Associate a TFileHandler to this socket
447  TFileHandler fh(fSocket, interest);
448 
449  // Wait for an event now
450  rc = gSystem->Select(&fh, timeout);
451 
452  return rc;
453 }
454 
455 ////////////////////////////////////////////////////////////////////////////////
456 /// Send a single message opcode. Use kind (opcode) to set the
457 /// TMessage "what" field. Returns the number of bytes that were sent
458 /// (always sizeof(Int_t)) and -1 in case of error. In case the kind has
459 /// been or'ed with kMESS_ACK, the call will only return after having
460 /// received an acknowledgement, making the sending process synchronous.
461 
462 Int_t TSocket::Send(Int_t kind)
463 {
464  TMessage mess(kind);
465 
466  Int_t nsent;
467  if ((nsent = Send(mess)) < 0)
468  return -1;
469 
470  return nsent;
471 }
472 
473 ////////////////////////////////////////////////////////////////////////////////
474 /// Send a status and a single message opcode. Use kind (opcode) to set the
475 /// TMessage "what" field. Returns the number of bytes that were sent
476 /// (always 2*sizeof(Int_t)) and -1 in case of error. In case the kind has
477 /// been or'ed with kMESS_ACK, the call will only return after having
478 /// received an acknowledgement, making the sending process synchronous.
479 
480 Int_t TSocket::Send(Int_t status, Int_t kind)
481 {
482  TMessage mess(kind);
483  mess << status;
484 
485  Int_t nsent;
486  if ((nsent = Send(mess)) < 0)
487  return -1;
488 
489  return nsent;
490 }
491 
492 ////////////////////////////////////////////////////////////////////////////////
493 /// Send a character string buffer. Use kind to set the TMessage "what" field.
494 /// Returns the number of bytes in the string str that were sent and -1 in
495 /// case of error. In case the kind has been or'ed with kMESS_ACK, the call
496 /// will only return after having received an acknowledgement, making the
497 /// sending process synchronous.
498 
499 Int_t TSocket::Send(const char *str, Int_t kind)
500 {
501  TMessage mess(kind);
502  if (str) mess.WriteString(str);
503 
504  Int_t nsent;
505  if ((nsent = Send(mess)) < 0)
506  return -1;
507 
508  return nsent - sizeof(Int_t); // - TMessage::What()
509 }
510 
511 ////////////////////////////////////////////////////////////////////////////////
512 /// Send a TMessage object. Returns the number of bytes in the TMessage
513 /// that were sent and -1 in case of error. In case the TMessage::What
514 /// has been or'ed with kMESS_ACK, the call will only return after having
515 /// received an acknowledgement, making the sending process synchronous.
516 /// Returns -4 in case of kNoBlock and errno == EWOULDBLOCK.
517 /// Returns -5 if pipe broken or reset by peer (EPIPE || ECONNRESET).
518 /// support for streaming TStreamerInfo added by Rene Brun May 2008
519 /// support for streaming TProcessID added by Rene Brun June 2008
520 
521 Int_t TSocket::Send(const TMessage &mess)
522 {
523  TSystem::ResetErrno();
524 
525  if (!IsValid()) return -1;
526 
527  if (mess.IsReading()) {
528  Error("Send", "cannot send a message used for reading");
529  return -1;
530  }
531 
532  // send streamer infos in case schema evolution is enabled in the TMessage
533  SendStreamerInfos(mess);
534 
535  // send the process id's so TRefs work
536  SendProcessIDs(mess);
537 
538  mess.SetLength(); //write length in first word of buffer
539 
540  if (GetCompressionLevel() > 0 && mess.GetCompressionLevel() == 0)
541  const_cast<TMessage&>(mess).SetCompressionSettings(fCompress);
542 
543  if (mess.GetCompressionLevel() > 0)
544  const_cast<TMessage&>(mess).Compress();
545 
546  char *mbuf = mess.Buffer();
547  Int_t mlen = mess.Length();
548  if (mess.CompBuffer()) {
549  mbuf = mess.CompBuffer();
550  mlen = mess.CompLength();
551  }
552 
553  ResetBit(TSocket::kBrokenConn);
554  Int_t nsent;
555  if ((nsent = gSystem->SendRaw(fSocket, mbuf, mlen, 0)) <= 0) {
556  if (nsent == -5) {
557  // Connection reset by peer or broken
558  MarkBrokenConnection();
559  }
560  return nsent;
561  }
562 
563  fBytesSent += nsent;
564  fgBytesSent += nsent;
565 
566  // If acknowledgement is desired, wait for it
567  if (mess.What() & kMESS_ACK) {
568  TSystem::ResetErrno();
569  ResetBit(TSocket::kBrokenConn);
570  char buf[2];
571  Int_t n = 0;
572  if ((n = gSystem->RecvRaw(fSocket, buf, sizeof(buf), 0)) < 0) {
573  if (n == -5) {
574  // Connection reset by peer or broken
575  MarkBrokenConnection();
576  } else
577  n = -1;
578  return n;
579  }
580  if (strncmp(buf, "ok", 2)) {
581  Error("Send", "bad acknowledgement");
582  return -1;
583  }
584  fBytesRecv += 2;
585  fgBytesRecv += 2;
586  }
587 
588  Touch(); // update usage timestamp
589 
590  return nsent - sizeof(UInt_t); //length - length header
591 }
592 
593 ////////////////////////////////////////////////////////////////////////////////
594 /// Send an object. Returns the number of bytes sent and -1 in case of error.
595 /// In case the "kind" has been or'ed with kMESS_ACK, the call will only
596 /// return after having received an acknowledgement, making the sending
597 /// synchronous.
598 
599 Int_t TSocket::SendObject(const TObject *obj, Int_t kind)
600 {
601  //stream object to message buffer
602  TMessage mess(kind);
603  mess.WriteObject(obj);
604 
605  //now sending the object itself
606  Int_t nsent;
607  if ((nsent = Send(mess)) < 0)
608  return -1;
609 
610  return nsent;
611 }
612 
613 ////////////////////////////////////////////////////////////////////////////////
614 /// Send a raw buffer of specified length. Using option kOob one can send
615 /// OOB data. Returns the number of bytes sent or -1 in case of error.
616 /// Returns -4 in case of kNoBlock and errno == EWOULDBLOCK.
617 /// Returns -5 if pipe broken or reset by peer (EPIPE || ECONNRESET).
618 
619 Int_t TSocket::SendRaw(const void *buffer, Int_t length, ESendRecvOptions opt)
620 {
621  TSystem::ResetErrno();
622 
623  if (!IsValid()) return -1;
624 
625  ResetBit(TSocket::kBrokenConn);
626  Int_t nsent;
627  if ((nsent = gSystem->SendRaw(fSocket, buffer, length, (int) opt)) <= 0) {
628  if (nsent == -5) {
629  // Connection reset or broken: close
630  MarkBrokenConnection();
631  }
632  return nsent;
633  }
634 
635  fBytesSent += nsent;
636  fgBytesSent += nsent;
637 
638  Touch(); // update usage timestamp
639 
640  return nsent;
641 }
642 
643 ////////////////////////////////////////////////////////////////////////////////
644 /// Check if TStreamerInfo must be sent. The list of TStreamerInfo of classes
645 /// in the object in the message is in the fInfos list of the message.
646 /// We send only the TStreamerInfos not yet sent on this socket.
647 
648 void TSocket::SendStreamerInfos(const TMessage &mess)
649 {
650  if (mess.fInfos && mess.fInfos->GetEntries()) {
651  TIter next(mess.fInfos);
652  TStreamerInfo *info;
653  TList *minilist = 0;
654  while ((info = (TStreamerInfo*)next())) {
655  Int_t uid = info->GetNumber();
656  if (fBitsInfo.TestBitNumber(uid))
657  continue; //TStreamerInfo had already been sent
658  fBitsInfo.SetBitNumber(uid);
659  if (!minilist)
660  minilist = new TList();
661  if (gDebug > 0)
662  Info("SendStreamerInfos", "sending TStreamerInfo: %s, version = %d",
663  info->GetName(),info->GetClassVersion());
664  minilist->Add(info);
665  }
666  if (minilist) {
667  TMessage messinfo(kMESS_STREAMERINFO);
668  messinfo.WriteObject(minilist);
669  delete minilist;
670  if (messinfo.fInfos)
671  messinfo.fInfos->Clear();
672  if (Send(messinfo) < 0)
673  Warning("SendStreamerInfos", "problems sending TStreamerInfo's ...");
674  }
675  }
676 }
677 
678 ////////////////////////////////////////////////////////////////////////////////
679 /// Check if TProcessIDs must be sent. The list of TProcessIDs
680 /// in the object in the message is found by looking in the TMessage bits.
681 /// We send only the TProcessIDs not yet send on this socket.
682 
683 void TSocket::SendProcessIDs(const TMessage &mess)
684 {
685  if (mess.TestBitNumber(0)) {
686  TObjArray *pids = TProcessID::GetPIDs();
687  Int_t npids = pids->GetEntries();
688  TProcessID *pid;
689  TList *minilist = 0;
690  for (Int_t ipid = 0; ipid < npids; ipid++) {
691  pid = (TProcessID*)pids->At(ipid);
692  if (!pid || !mess.TestBitNumber(pid->GetUniqueID()+1))
693  continue;
694  //check if a pid with this title has already been sent through the socket
695  //if not add it to the fUUIDs list
696  if (!fUUIDs) {
697  fUUIDs = new TList();
698  } else {
699  if (fUUIDs->FindObject(pid->GetTitle()))
700  continue;
701  }
702  fUUIDs->Add(new TObjString(pid->GetTitle()));
703  if (!minilist)
704  minilist = new TList();
705  if (gDebug > 0)
706  Info("SendProcessIDs", "sending TProcessID: %s", pid->GetTitle());
707  minilist->Add(pid);
708  }
709  if (minilist) {
710  TMessage messpid(kMESS_PROCESSID);
711  messpid.WriteObject(minilist);
712  delete minilist;
713  if (Send(messpid) < 0)
714  Warning("SendProcessIDs", "problems sending TProcessID's ...");
715  }
716  }
717 }
718 
719 ////////////////////////////////////////////////////////////////////////////////
720 /// Receive a character string message of maximum max length. The expected
721 /// message must be of type kMESS_STRING. Returns length of received string
722 /// (can be 0 if otherside of connection is closed) or -1 in case of error
723 /// or -4 in case a non-blocking socket would block (i.e. there is nothing
724 /// to be read).
725 
726 Int_t TSocket::Recv(char *str, Int_t max)
727 {
728  Int_t n, kind;
729 
730  ResetBit(TSocket::kBrokenConn);
731  if ((n = Recv(str, max, kind)) <= 0) {
732  if (n == -5) {
733  SetBit(TSocket::kBrokenConn);
734  n = -1;
735  }
736  return n;
737  }
738 
739  if (kind != kMESS_STRING) {
740  Error("Recv", "got message of wrong kind (expected %d, got %d)",
741  kMESS_STRING, kind);
742  return -1;
743  }
744 
745  return n;
746 }
747 
748 ////////////////////////////////////////////////////////////////////////////////
749 /// Receive a character string message of maximum max length. Returns in
750 /// kind the message type. Returns length of received string+4 (can be 0 if
751 /// other side of connection is closed) or -1 in case of error or -4 in
752 /// case a non-blocking socket would block (i.e. there is nothing to be read).
753 
754 Int_t TSocket::Recv(char *str, Int_t max, Int_t &kind)
755 {
756  Int_t n;
757  TMessage *mess;
758 
759  ResetBit(TSocket::kBrokenConn);
760  if ((n = Recv(mess)) <= 0) {
761  if (n == -5) {
762  SetBit(TSocket::kBrokenConn);
763  n = -1;
764  }
765  return n;
766  }
767 
768  kind = mess->What();
769  if (str) {
770  if (mess->BufferSize() > (Int_t)sizeof(Int_t)) // if mess contains more than kind
771  mess->ReadString(str, max);
772  else
773  str[0] = 0;
774  }
775 
776  delete mess;
777 
778  return n; // number of bytes read (len of str + sizeof(kind)
779 }
780 
781 ////////////////////////////////////////////////////////////////////////////////
782 /// Receives a status and a message type. Returns length of received
783 /// integers, 2*sizeof(Int_t) (can be 0 if other side of connection
784 /// is closed) or -1 in case of error or -4 in case a non-blocking
785 /// socket would block (i.e. there is nothing to be read).
786 
787 Int_t TSocket::Recv(Int_t &status, Int_t &kind)
788 {
789  Int_t n;
790  TMessage *mess;
791 
792  ResetBit(TSocket::kBrokenConn);
793  if ((n = Recv(mess)) <= 0) {
794  if (n == -5) {
795  SetBit(TSocket::kBrokenConn);
796  n = -1;
797  }
798  return n;
799  }
800 
801  kind = mess->What();
802  (*mess) >> status;
803 
804  delete mess;
805 
806  return n; // number of bytes read (2 * sizeof(Int_t)
807 }
808 
809 ////////////////////////////////////////////////////////////////////////////////
810 /// Receive a TMessage object. The user must delete the TMessage object.
811 /// Returns length of message in bytes (can be 0 if other side of connection
812 /// is closed) or -1 in case of error or -4 in case a non-blocking socket
813 /// would block (i.e. there is nothing to be read) or -5 if pipe broken
814 /// or reset by peer (EPIPE || ECONNRESET). In those case mess == 0.
815 
816 Int_t TSocket::Recv(TMessage *&mess)
817 {
818  TSystem::ResetErrno();
819 
820  if (!IsValid()) {
821  mess = 0;
822  return -1;
823  }
824 
825 oncemore:
826  ResetBit(TSocket::kBrokenConn);
827  Int_t n;
828  UInt_t len;
829  if ((n = gSystem->RecvRaw(fSocket, &len, sizeof(UInt_t), 0)) <= 0) {
830  if (n == 0 || n == -5) {
831  // Connection closed, reset or broken
832  MarkBrokenConnection();
833  }
834  mess = 0;
835  return n;
836  }
837  len = net2host(len); //from network to host byte order
838 
839  ResetBit(TSocket::kBrokenConn);
840  char *buf = new char[len+sizeof(UInt_t)];
841  if ((n = gSystem->RecvRaw(fSocket, buf+sizeof(UInt_t), len, 0)) <= 0) {
842  if (n == 0 || n == -5) {
843  // Connection closed, reset or broken
844  MarkBrokenConnection();
845  }
846  delete [] buf;
847  mess = 0;
848  return n;
849  }
850 
851  fBytesRecv += n + sizeof(UInt_t);
852  fgBytesRecv += n + sizeof(UInt_t);
853 
854  mess = new TMessage(buf, len+sizeof(UInt_t));
855 
856  // receive any streamer infos
857  if (RecvStreamerInfos(mess))
858  goto oncemore;
859 
860  // receive any process ids
861  if (RecvProcessIDs(mess))
862  goto oncemore;
863 
864  if (mess->What() & kMESS_ACK) {
865  ResetBit(TSocket::kBrokenConn);
866  char ok[2] = { 'o', 'k' };
867  Int_t n2 = 0;
868  if ((n2 = gSystem->SendRaw(fSocket, ok, sizeof(ok), 0)) < 0) {
869  if (n2 == -5) {
870  // Connection reset or broken
871  MarkBrokenConnection();
872  }
873  delete mess;
874  mess = 0;
875  return n2;
876  }
877  mess->SetWhat(mess->What() & ~kMESS_ACK);
878 
879  fBytesSent += 2;
880  fgBytesSent += 2;
881  }
882 
883  Touch(); // update usage timestamp
884 
885  return n;
886 }
887 
888 ////////////////////////////////////////////////////////////////////////////////
889 /// Receive a raw buffer of specified length bytes. Using option kPeek
890 /// one can peek at incoming data. Returns number of received bytes.
891 /// Returns -1 in case of error. In case of opt == kOob: -2 means
892 /// EWOULDBLOCK and -3 EINVAL. In case of non-blocking mode (kNoBlock)
893 /// -4 means EWOULDBLOCK. Returns -5 if pipe broken or reset by
894 /// peer (EPIPE || ECONNRESET).
895 
896 Int_t TSocket::RecvRaw(void *buffer, Int_t length, ESendRecvOptions opt)
897 {
898  TSystem::ResetErrno();
899 
900  if (!IsValid()) return -1;
901  if (length == 0) return 0;
902 
903  ResetBit(TSocket::kBrokenConn);
904  Int_t n;
905  if ((n = gSystem->RecvRaw(fSocket, buffer, length, (int) opt)) <= 0) {
906  if (n == 0 || n == -5) {
907  // Connection closed, reset or broken
908  MarkBrokenConnection();
909  }
910  return n;
911  }
912 
913  fBytesRecv += n;
914  fgBytesRecv += n;
915 
916  Touch(); // update usage timestamp
917 
918  return n;
919 }
920 
921 ////////////////////////////////////////////////////////////////////////////////
922 /// Receive a message containing streamer infos. In case the message contains
923 /// streamer infos they are imported, the message will be deleted and the
924 /// method returns kTRUE.
925 
926 Bool_t TSocket::RecvStreamerInfos(TMessage *mess)
927 {
928  if (mess->What() == kMESS_STREAMERINFO) {
929  TList *list = (TList*)mess->ReadObject(TList::Class());
930  TIter next(list);
931  TStreamerInfo *info;
932  TObjLink *lnk = list->FirstLink();
933  // First call BuildCheck for regular class
934  while (lnk) {
935  info = (TStreamerInfo*)lnk->GetObject();
936  TObject *element = info->GetElements()->UncheckedAt(0);
937  Bool_t isstl = element && strcmp("This",element->GetName())==0;
938  if (!isstl) {
939  info->BuildCheck();
940  if (gDebug > 0)
941  Info("RecvStreamerInfos", "importing TStreamerInfo: %s, version = %d",
942  info->GetName(), info->GetClassVersion());
943  }
944  lnk = lnk->Next();
945  }
946  // Then call BuildCheck for stl class
947  lnk = list->FirstLink();
948  while (lnk) {
949  info = (TStreamerInfo*)lnk->GetObject();
950  TObject *element = info->GetElements()->UncheckedAt(0);
951  Bool_t isstl = element && strcmp("This",element->GetName())==0;
952  if (isstl) {
953  info->BuildCheck();
954  if (gDebug > 0)
955  Info("RecvStreamerInfos", "importing TStreamerInfo: %s, version = %d",
956  info->GetName(), info->GetClassVersion());
957  }
958  lnk = lnk->Next();
959  }
960  delete list;
961  delete mess;
962 
963  return kTRUE;
964  }
965  return kFALSE;
966 }
967 
968 ////////////////////////////////////////////////////////////////////////////////
969 /// Receive a message containing process ids. In case the message contains
970 /// process ids they are imported, the message will be deleted and the
971 /// method returns kTRUE.
972 
973 Bool_t TSocket::RecvProcessIDs(TMessage *mess)
974 {
975  if (mess->What() == kMESS_PROCESSID) {
976  TList *list = (TList*)mess->ReadObject(TList::Class());
977  TIter next(list);
978  TProcessID *pid;
979  while ((pid = (TProcessID*)next())) {
980  // check that a similar pid is not already registered in fgPIDs
981  TObjArray *pidslist = TProcessID::GetPIDs();
982  TIter nextpid(pidslist);
983  TProcessID *p;
984  while ((p = (TProcessID*)nextpid())) {
985  if (!strcmp(p->GetTitle(), pid->GetTitle())) {
986  delete pid;
987  pid = 0;
988  break;
989  }
990  }
991  if (pid) {
992  if (gDebug > 0)
993  Info("RecvProcessIDs", "importing TProcessID: %s", pid->GetTitle());
994  pid->IncrementCount();
995  pidslist->Add(pid);
996  Int_t ind = pidslist->IndexOf(pid);
997  pid->SetUniqueID((UInt_t)ind);
998  }
999  }
1000  delete list;
1001  delete mess;
1002 
1003  return kTRUE;
1004  }
1005  return kFALSE;
1006 }
1007 
1008 ////////////////////////////////////////////////////////////////////////////////
1009 /// Set socket options.
1010 
1011 Int_t TSocket::SetOption(ESockOptions opt, Int_t val)
1012 {
1013  if (!IsValid()) return -1;
1014 
1015  return gSystem->SetSockOpt(fSocket, opt, val);
1016 }
1017 
1018 ////////////////////////////////////////////////////////////////////////////////
1019 /// Get socket options. Returns -1 in case of error.
1020 
1021 Int_t TSocket::GetOption(ESockOptions opt, Int_t &val)
1022 {
1023  if (!IsValid()) return -1;
1024 
1025  return gSystem->GetSockOpt(fSocket, opt, &val);
1026 }
1027 
1028 ////////////////////////////////////////////////////////////////////////////////
1029 /// Returns error code. Meaning depends on context where it is called.
1030 /// If no error condition returns 0 else a value < 0.
1031 /// For example see TServerSocket ctor.
1032 
1033 Int_t TSocket::GetErrorCode() const
1034 {
1035  if (!IsValid())
1036  return fSocket;
1037 
1038  return 0;
1039 }
1040 
1041 ////////////////////////////////////////////////////////////////////////////////
1042 /// See comments for function SetCompressionSettings
1043 
1044 void TSocket::SetCompressionAlgorithm(Int_t algorithm)
1045 {
1046  if (algorithm < 0 || algorithm >= ROOT::RCompressionSetting::EAlgorithm::kUndefined) algorithm = 0;
1047  if (fCompress < 0) {
1048  fCompress = 100 * algorithm + ROOT::RCompressionSetting::ELevel::kUseMin;
1049  } else {
1050  int level = fCompress % 100;
1051  fCompress = 100 * algorithm + level;
1052  }
1053 }
1054 
1055 ////////////////////////////////////////////////////////////////////////////////
1056 /// See comments for function SetCompressionSettings
1057 
1058 void TSocket::SetCompressionLevel(Int_t level)
1059 {
1060  if (level < 0) level = 0;
1061  if (level > 99) level = 99;
1062  if (fCompress < 0) {
1063  // if the algorithm is not defined yet use 0 as a default
1064  fCompress = level;
1065  } else {
1066  int algorithm = fCompress / 100;
1067  if (algorithm >= ROOT::RCompressionSetting::EAlgorithm::kUndefined) algorithm = 0;
1068  fCompress = 100 * algorithm + level;
1069  }
1070 }
1071 
1072 ////////////////////////////////////////////////////////////////////////////////
1073 /// Used to specify the compression level and algorithm:
1074 /// settings = 100 * algorithm + level
1075 ///
1076 /// level = 0, objects written to this file will not be compressed.
1077 /// level = 1, minimal compression level but fast.
1078 /// ....
1079 /// level = 9, maximal compression level but slower and might use more memory.
1080 /// (For the currently supported algorithms, the maximum level is 9)
1081 /// If compress is negative it indicates the compression level is not set yet.
1082 ///
1083 /// The enumeration ROOT::RCompressionSetting::EAlgorithm associates each
1084 /// algorithm with a number. There is a utility function to help
1085 /// to set the value of the argument. For example,
1086 /// ROOT::CompressionSettings(ROOT::kLZMA, 1)
1087 /// will build an integer which will set the compression to use
1088 /// the LZMA algorithm and compression level 1. These are defined
1089 /// in the header file Compression.h.
1090 ///
1091 /// Note that the compression settings may be changed at any time.
1092 /// The new compression settings will only apply to branches created
1093 /// or attached after the setting is changed and other objects written
1094 /// after the setting is changed.
1095 
1096 void TSocket::SetCompressionSettings(Int_t settings)
1097 {
1098  fCompress = settings;
1099 }
1100 
1101 ////////////////////////////////////////////////////////////////////////////////
1102 /// Authenticated the socket with specified user.
1103 
1104 Bool_t TSocket::Authenticate(const char *user)
1105 {
1106  Bool_t rc = kFALSE;
1107 
1108  // Parse protocol name, for PROOF, send message with server role
1109  TString sproto = TUrl(fUrl).GetProtocol();
1110  if (sproto.Contains("sockd")) {
1111  fServType = kSOCKD;
1112  } else if (sproto.Contains("rootd")) {
1113  fServType = kROOTD;
1114  } else if (sproto.Contains("proofd")) {
1115  fServType = kPROOFD;
1116  // Parse options
1117  TString opt(TUrl(fUrl).GetOptions());
1118  //First letter in Opt describes type of proofserv to invoke
1119  if (!strncasecmp(opt, "S", 1)) {
1120  if (Send("slave") < 0) return rc;
1121  } else if (!strncasecmp(opt, "M", 1)) {
1122  if (Send("master") < 0) return rc;
1123  } else {
1124  Warning("Authenticate",
1125  "called by TSlave: unknown option '%c' %s",
1126  opt[0], " - assuming Slave");
1127  if (Send("slave") < 0) return rc;
1128  }
1129  }
1130  if (gDebug > 2)
1131  Info("Authenticate","Local protocol: %s",sproto.Data());
1132 
1133  // Get server protocol level
1134  Int_t kind = kROOTD_PROTOCOL;
1135  // Warning: for backward compatibility reasons here we have to
1136  // send exactly 4 bytes: for fgClientClientProtocol > 99
1137  // the space in the format must be dropped
1138  if (fRemoteProtocol == -1) {
1139  if (Send(Form(" %d", fgClientProtocol), kROOTD_PROTOCOL) < 0) {
1140  return rc;
1141  }
1142  if (Recv(fRemoteProtocol, kind) < 0) {
1143  return rc;
1144  }
1145  //
1146  // If we are talking to an old rootd server we get a fatal
1147  // error here and we need to reopen the connection,
1148  // communicating first the size of the parallel socket
1149  if (kind == kROOTD_ERR) {
1150  fRemoteProtocol = 9;
1151  return kFALSE;
1152  }
1153  }
1154 
1155  // Find out whether authentication is required
1156  Bool_t runauth = kTRUE;
1157  if (fRemoteProtocol > 1000) {
1158  // Authentication not required by the remote server
1159  runauth = kFALSE;
1160  fRemoteProtocol %= 1000;
1161  }
1162 
1163  // If authentication is required, we need to find out which library
1164  // has to be loaded (preparation for near future, 9/7/05)
1165  TString host = GetInetAddress().GetHostName();
1166  if (runauth) {
1167 
1168  // Default (future)
1169  TString alib = "Xrd";
1170  if (fRemoteProtocol < 100) {
1171  // Standard Authentication lib
1172  alib = "Root";
1173  }
1174 
1175  // Load the plugin
1176  TPluginHandler *h =
1177  gROOT->GetPluginManager()->FindHandler("TVirtualAuth", alib);
1178  if (!h || h->LoadPlugin() != 0) {
1179  Error("Authenticate",
1180  "could not load properly %s authentication plugin", alib.Data());
1181  return rc;
1182  }
1183 
1184  // Get an instance of the interface class
1185  TVirtualAuth *auth = (TVirtualAuth *)(h->ExecPlugin(0));
1186  if (!auth) {
1187  Error("Authenticate", "could not instantiate the interface class");
1188  return rc;
1189  }
1190  if (gDebug > 1)
1191  Info("Authenticate", "class for '%s' authentication loaded", alib.Data());
1192 
1193  Option_t *opts = (gROOT->IsProofServ()) ? "P" : "";
1194  if (!(auth->Authenticate(this, host, user, opts))) {
1195  Error("Authenticate",
1196  "authentication attempt failed for %s@%s", user, host.Data());
1197  } else {
1198  rc = kTRUE;
1199  }
1200  } else {
1201 
1202  // Communicate who we are and our target user
1203  UserGroup_t *u = gSystem->GetUserInfo();
1204  if (u) {
1205  if (Send(Form("%s %s", u->fUser.Data(), user), kROOTD_USER) < 0)
1206  Warning("Authenticate", "problem sending kROOTD_USER (%s,%s)", u->fUser.Data(), user);
1207  delete u;
1208  } else
1209  if (Send(Form("-1 %s", user), kROOTD_USER) < 0)
1210  Warning("Authenticate", "problem sending kROOTD_USER (-1,%s)", user);
1211 
1212  rc = kFALSE;
1213 
1214  // Receive confirmation that everything went well
1215  Int_t stat;
1216  if (Recv(stat, kind) > 0) {
1217 
1218  if (kind == kROOTD_ERR) {
1219  if (gDebug > 0)
1220  TSocket::NetError("TSocket::Authenticate", stat);
1221  } else if (kind == kROOTD_AUTH) {
1222 
1223  // Authentication was not required: create inactive
1224  // security context for consistency
1225  fSecContext = new TSecContext(user, host, 0, -4, 0, 0);
1226  if (gDebug > 3)
1227  Info("Authenticate", "no authentication required remotely");
1228 
1229  // Set return flag;
1230  rc = 1;
1231  } else {
1232  if (gDebug > 0)
1233  Info("Authenticate", "expected message type %d, received %d",
1234  kROOTD_AUTH, kind);
1235  }
1236  } else {
1237  if (gDebug > 0)
1238  Info("Authenticate", "error receiving message");
1239  }
1240 
1241  }
1242 
1243  return rc;
1244 }
1245 
1246 ////////////////////////////////////////////////////////////////////////////////
1247 /// Creates a socket or a parallel socket and authenticates to the
1248 /// remote server.
1249 ///
1250 /// url: [[proto][p][auth]://][user@]host[:port][/service][?options]
1251 ///
1252 /// where proto = "sockd", "rootd", "proofd"
1253 /// indicates the type of remote server;
1254 /// if missing "sockd" is assumed ("sockd" indicates
1255 /// any remote server session using TServerSocket)
1256 /// [p] = for parallel sockets (forced internally for
1257 /// rootd; ignored for proofd)
1258 /// [auth] = "up" or "k" to force UsrPwd or Krb5 authentication
1259 /// [port] = is the remote port number
1260 /// [service] = service name used to determine the port
1261 /// (for backward compatibility, specification of
1262 /// port as priority)
1263 /// options = "m" or "s", when proto=proofd indicates whether
1264 /// we are master or slave (used internally by
1265 /// TSlave)
1266 ///
1267 /// An already opened connection can be used by passing its socket
1268 /// in opensock.
1269 ///
1270 /// If 'err' is defined, '*err' on return from a failed call contains an error
1271 /// code (see NetErrors.h).
1272 ///
1273 /// Example:
1274 ///
1275 /// TSocket::CreateAuthSocket("pk://qwerty@machine.fq.dn:5052",3)
1276 ///
1277 /// creates an authenticated parallel socket of size 3 to a sockd
1278 /// server running on remote machine machine.fq.dn on port 5052;
1279 /// authentication will attempt protocol Kerberos first.
1280 ///
1281 /// NB: may hang if the remote server is not of the correct type;
1282 /// at present TSocket has no way to find out the type of the
1283 /// remote server automatically
1284 ///
1285 /// Returns pointer to an authenticated socket or 0 if creation or
1286 /// authentication is unsuccessful.
1287 
1288 TSocket *TSocket::CreateAuthSocket(const char *url, Int_t size, Int_t tcpwindowsize,
1289  TSocket *opensock, Int_t *err)
1290 {
1291  R__LOCKGUARD2(gSocketAuthMutex);
1292 
1293  // Url to be passed to chosen constructor
1294  TString eurl(url);
1295 
1296  // Parse protocol, if any
1297  Bool_t parallel = kFALSE;
1298  TString proto(TUrl(url).GetProtocol());
1299  TString protosave = proto;
1300 
1301  // Get rid of authentication suffix
1302  TString asfx = "";
1303  if (proto.EndsWith("up") || proto.EndsWith("ug")) {
1304  asfx = proto;
1305  asfx.Remove(0,proto.Length()-2);
1306  proto.Resize(proto.Length()-2);
1307  } else if (proto.EndsWith("s") || proto.EndsWith("k") ||
1308  proto.EndsWith("g") || proto.EndsWith("h")) {
1309  asfx = proto;
1310  asfx.Remove(0,proto.Length()-1);
1311  proto.Resize(proto.Length()-1);
1312  }
1313 
1314  // Find out if parallel (ignore if proofd, force if rootd)
1315  if (((proto.EndsWith("p") || size > 1) &&
1316  !proto.BeginsWith("proof")) ||
1317  proto.BeginsWith("root") ) {
1318  parallel = kTRUE;
1319  if (proto.EndsWith("p"))
1320  proto.Resize(proto.Length()-1);
1321  }
1322 
1323  // Force "sockd" if the rest is not recognized
1324  if (!proto.BeginsWith("sock") && !proto.BeginsWith("proof") &&
1325  !proto.BeginsWith("root"))
1326  proto = "sockd";
1327 
1328  // Substitute this for original proto in eurl
1329  protosave += "://";
1330  proto += asfx;
1331  proto += "://";
1332  eurl.ReplaceAll(protosave,proto);
1333 
1334  // Create the socket now
1335 
1336  TSocket *sock = 0;
1337  if (!parallel) {
1338 
1339  // Simple socket
1340  if (opensock && opensock->IsValid())
1341  sock = opensock;
1342  else
1343  sock = new TSocket(eurl, TUrl(url).GetPort(), tcpwindowsize);
1344 
1345  // Authenticate now
1346  if (sock && sock->IsValid()) {
1347  if (!sock->Authenticate(TUrl(url).GetUser())) {
1348  // Nothing to do except setting the error code (if required) and sock to NULL
1349  if (err) {
1350  *err = (Int_t)kErrAuthNotOK;
1351  if (sock->TestBit(TSocket::kBrokenConn)) *err = (Int_t)kErrConnectionRefused;
1352  }
1353  sock->Close();
1354  delete sock;
1355  sock = 0;
1356  }
1357  }
1358 
1359  } else {
1360 
1361  // Tell TPSocket that we want authentication, which has to
1362  // be done using the original socket before creation of set
1363  // of parallel sockets
1364  if (eurl.Contains("?"))
1365  eurl.Resize(eurl.Index("?"));
1366  eurl += "?A";
1367 
1368  // Parallel socket
1369  if (opensock && opensock->IsValid())
1370  sock = new TPSocket(eurl, TUrl(url).GetPort(), size, opensock);
1371  else
1372  sock = new TPSocket(eurl, TUrl(url).GetPort(), size, tcpwindowsize);
1373 
1374  // Cleanup if failure ...
1375  if (sock && !sock->IsAuthenticated()) {
1376  // Nothing to do except setting the error code (if required) and sock to NULL
1377  if (err) {
1378  *err = (Int_t)kErrAuthNotOK;
1379  if (sock->TestBit(TSocket::kBrokenConn)) *err = (Int_t)kErrConnectionRefused;
1380  }
1381  if (sock->IsValid())
1382  // And except when the sock is valid; this typically
1383  // happens when talking to a old server, because the
1384  // the parallel socket system is open before authentication
1385  delete sock;
1386  sock = 0;
1387  }
1388  }
1389 
1390  return sock;
1391 }
1392 
1393 ////////////////////////////////////////////////////////////////////////////////
1394 /// Creates a socket or a parallel socket and authenticates to the
1395 /// remote server specified in 'url' on remote 'port' as 'user'.
1396 ///
1397 /// url: [[proto][p][auth]://]host[/?options]
1398 ///
1399 /// where proto = "sockd", "rootd", "proofd"
1400 /// indicates the type of remote server
1401 /// if missing "sockd" is assumed ("sockd" indicates
1402 /// any remote server session using TServerSocket)
1403 /// [p] = for parallel sockets (forced internally for
1404 /// rootd)
1405 /// [auth] = "up" or "k" to force UsrPwd or Krb5 authentication
1406 /// [options] = "m" or "s", when proto=proofd indicates whether
1407 /// we are master or slave (used internally by TSlave)
1408 ///
1409 /// An already opened connection can be used by passing its socket
1410 /// in opensock.
1411 ///
1412 /// If 'err' is defined, '*err' on return from a failed call contains an error
1413 /// code (see NetErrors.h).
1414 ///
1415 /// Example:
1416 ///
1417 /// TSocket::CreateAuthSocket("qwerty","pk://machine.fq.dn:5052",3)
1418 ///
1419 /// creates an authenticated parallel socket of size 3 to a sockd
1420 /// server running on remote machine machine.fq.dn on port 5052;
1421 /// authentication will attempt protocol Kerberos first.
1422 ///
1423 /// NB: may hang if the remote server is not of the correct type;
1424 /// at present TSocket has no way to find out the type of the
1425 /// remote server automatically
1426 ///
1427 /// Returns pointer to an authenticated socket or 0 if creation or
1428 /// authentication is unsuccessful.
1429 
1430 TSocket *TSocket::CreateAuthSocket(const char *user, const char *url,
1431  Int_t port, Int_t size, Int_t tcpwindowsize,
1432  TSocket *opensock, Int_t *err)
1433 {
1434  R__LOCKGUARD2(gSocketAuthMutex);
1435 
1436  // Extended url to be passed to base call
1437  TString eurl;
1438 
1439  // Add protocol, if any
1440  if (TString(TUrl(url).GetProtocol()).Length() > 0) {
1441  eurl += TString(TUrl(url).GetProtocol());
1442  eurl += TString("://");
1443  }
1444  // Add user, if any
1445  if (!user || strlen(user) > 0) {
1446  eurl += TString(user);
1447  eurl += TString("@");
1448  }
1449  // Add host
1450  eurl += TString(TUrl(url).GetHost());
1451  // Add port
1452  eurl += TString(":");
1453  eurl += (port > 0 ? port : 0);
1454  // Add options, if any
1455  if (TString(TUrl(url).GetOptions()).Length() > 0) {
1456  eurl += TString("/?");
1457  eurl += TString(TUrl(url).GetOptions());
1458  }
1459 
1460  // Create the socket and return it
1461  return TSocket::CreateAuthSocket(eurl,size,tcpwindowsize,opensock,err);
1462 }
1463 
1464 ////////////////////////////////////////////////////////////////////////////////
1465 /// Static method returning supported client protocol.
1466 
1467 Int_t TSocket::GetClientProtocol()
1468 {
1469  return fgClientProtocol;
1470 }
1471 
1472 ////////////////////////////////////////////////////////////////////////////////
1473 /// Print error string depending on error code.
1474 
1475 void TSocket::NetError(const char *where, Int_t err)
1476 {
1477  // Make sure it is in range
1478  err = (err < kErrError) ? ((err > -1) ? err : 0) : kErrError;
1479 
1480  if (gDebug > 0)
1481  ::Error(where, "%s", gRootdErrStr[err]);
1482 }
1483 
1484 ////////////////////////////////////////////////////////////////////////////////
1485 /// Get total number of bytes sent via all sockets.
1486 
1487 ULong64_t TSocket::GetSocketBytesSent()
1488 {
1489  return fgBytesSent;
1490 }
1491 
1492 ////////////////////////////////////////////////////////////////////////////////
1493 /// Get total number of bytes received via all sockets.
1494 
1495 ULong64_t TSocket::GetSocketBytesRecv()
1496 {
1497  return fgBytesRecv;
1498 }