TServerSocket.cxx

Go to the documentation of this file.
00001 // @(#)root/net:$Id: TServerSocket.cxx 35197 2010-09-08 12:34:39Z rdm $
00002 // Author: Fons Rademakers   18/12/96
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //                                                                      //
00014 // TServerSocket                                                        //
00015 //                                                                      //
00016 // This class implements server sockets. A server socket waits for      //
00017 // requests to come in over the network. It performs some operation     //
00018 // based on that request and then possibly returns a full duplex socket //
00019 // to the requester. The actual work is done via the TSystem class      //
00020 // (either TUnixSystem or TWinNTSystem).                                //
00021 //                                                                      //
00022 //////////////////////////////////////////////////////////////////////////
00023 
00024 #include "TServerSocket.h"
00025 #include "TSocket.h"
00026 #include "TSystem.h"
00027 #include "TROOT.h"
00028 #include "TError.h"
00029 #include <string>
00030 #include "TVirtualMutex.h"
00031 
00032 // Hook to server authentication wrapper
00033 SrvAuth_t TServerSocket::fgSrvAuthHook = 0;
00034 SrvClup_t TServerSocket::fgSrvAuthClupHook = 0;
00035 
00036 // Defaul options for accept
00037 UChar_t TServerSocket::fgAcceptOpt = kSrvNoAuth;
00038 
00039 TVirtualMutex *gSrvAuthenticateMutex = 0;
00040 
00041 ClassImp(TServerSocket)
00042 
00043 //______________________________________________________________________________
00044 static void setaccopt(UChar_t &Opt, UChar_t Mod)
00045 {
00046    // Kind of macro to parse input options
00047    // Modify Opt according to modifier Mod
00048    R__LOCKGUARD2(gSrvAuthenticateMutex);
00049 
00050    if (!Mod) return;
00051 
00052    if ((Mod & kSrvAuth))      Opt |= kSrvAuth;
00053    if ((Mod & kSrvNoAuth))    Opt &= ~kSrvAuth;
00054 }
00055 
00056 //______________________________________________________________________________
00057 TServerSocket::TServerSocket(const char *service, Bool_t reuse, Int_t backlog,
00058                              Int_t tcpwindowsize)
00059 {
00060    // Create a server socket object for a named service. Set reuse to true
00061    // to force reuse of the server socket (i.e. do not wait for the time
00062    // out to pass). Using backlog one can set the desirable queue length
00063    // for pending connections.
00064    // Use tcpwindowsize to specify the size of the receive buffer, it has
00065    // to be specified here to make sure the window scale option is set (for
00066    // tcpwindowsize > 65KB and for platforms supporting window scaling).
00067    // Use IsValid() to check the validity of the
00068    // server socket. In case server socket is not valid use GetErrorCode()
00069    // to obtain the specific error value. These values are:
00070    //  0 = no error (socket is valid)
00071    // -1 = low level socket() call failed
00072    // -2 = low level bind() call failed
00073    // -3 = low level listen() call failed
00074    // Every valid server socket is added to the TROOT sockets list which
00075    // will make sure that any open sockets are properly closed on
00076    // program termination.
00077 
00078    R__ASSERT(gROOT);
00079    R__ASSERT(gSystem);
00080 
00081    SetName("ServerSocket");
00082 
00083    fSecContext = 0;
00084    fSecContexts = new TList;
00085 
00086    // If this is a local path, try announcing a UNIX socket service
00087    ResetBit(TSocket::kIsUnix);
00088    if (service && (!gSystem->AccessPathName(service) ||
00089 #ifndef WIN32
00090       service[0] == '/')) {
00091 #else
00092       service[0] == '/' || (service[1] == ':' && service[2] == '/'))) {
00093 #endif
00094       SetBit(TSocket::kIsUnix);
00095       fService = "unix:";
00096       fService += service;
00097       fSocket = gSystem->AnnounceUnixService(service, backlog);
00098       if (fSocket >= 0) {
00099          R__LOCKGUARD2(gROOTMutex);
00100          gROOT->GetListOfSockets()->Add(this);
00101       }
00102    } else {
00103       // TCP / UDP socket
00104       fService = service;
00105       int port = gSystem->GetServiceByName(service);
00106       if (port != -1) {
00107          fSocket = gSystem->AnnounceTcpService(port, reuse, backlog, tcpwindowsize);
00108          if (fSocket >= 0) {
00109             R__LOCKGUARD2(gROOTMutex);
00110             gROOT->GetListOfSockets()->Add(this);
00111          }
00112       } else {
00113          fSocket = -1;
00114       }
00115    }
00116 }
00117 
00118 //______________________________________________________________________________
00119 TServerSocket::TServerSocket(Int_t port, Bool_t reuse, Int_t backlog,
00120                              Int_t tcpwindowsize)
00121 {
00122    // Create a server socket object on a specified port. Set reuse to true
00123    // to force reuse of the server socket (i.e. do not wait for the time
00124    // out to pass). Using backlog one can set the desirable queue length
00125    // for pending connections. If port is 0 a port scan will be done to
00126    // find a free port. This option is mutual exlusive with the reuse option.
00127    // Use tcpwindowsize to specify the size of the receive buffer, it has
00128    // to be specified here to make sure the window scale option is set (for
00129    // tcpwindowsize > 65KB and for platforms supporting window scaling).
00130    // Use IsValid() to check the validity of the
00131    // server socket. In case server socket is not valid use GetErrorCode()
00132    // to obtain the specific error value. These values are:
00133    //  0 = no error (socket is valid)
00134    // -1 = low level socket() call failed
00135    // -2 = low level bind() call failed
00136    // -3 = low level listen() call failed
00137    // Every valid server socket is added to the TROOT sockets list which
00138    // will make sure that any open sockets are properly closed on
00139    // program termination.
00140 
00141    R__ASSERT(gROOT);
00142    R__ASSERT(gSystem);
00143 
00144    SetName("ServerSocket");
00145 
00146    fSecContext = 0;
00147    fSecContexts = new TList;
00148    fService = gSystem->GetServiceByPort(port);
00149    SetTitle(fService);
00150 
00151    fSocket = gSystem->AnnounceTcpService(port, reuse, backlog, tcpwindowsize);
00152    if (fSocket >= 0) {
00153       R__LOCKGUARD2(gROOTMutex);
00154       gROOT->GetListOfSockets()->Add(this);
00155    }
00156 }
00157 
00158 //______________________________________________________________________________
00159 TServerSocket::~TServerSocket()
00160 {
00161    // Destructor: cleanup authentication stuff (if any) and close
00162 
00163    R__LOCKGUARD2(gSrvAuthenticateMutex);
00164    if (fSecContexts) {
00165       if (fgSrvAuthClupHook) {
00166          // Cleanup the security contexts
00167          (*fgSrvAuthClupHook)(fSecContexts);
00168       }
00169       // Remove the list
00170       fSecContexts->Delete();
00171       SafeDelete(fSecContexts);
00172       fSecContexts = 0;
00173    }
00174 
00175    Close();
00176 }
00177 
00178 //______________________________________________________________________________
00179 TSocket *TServerSocket::Accept(UChar_t Opt)
00180 {
00181    // Accept a connection on a server socket. Returns a full-duplex
00182    // communication TSocket object. If no pending connections are
00183    // present on the queue and nonblocking mode has not been enabled
00184    // with SetOption(kNoBlock,1) the call blocks until a connection is
00185    // present. The returned socket must be deleted by the user. The socket
00186    // is also added to the TROOT sockets list which will make sure that
00187    // any open sockets are properly closed on program termination.
00188    // In case of error 0 is returned and in case non-blocking I/O is
00189    // enabled and no connections are available -1 is returned.
00190    //
00191    // Opt can be used to require client authentication; valid options are
00192    //
00193    //    kSrvAuth   =   require client authentication
00194    //    kSrvNoAuth =   force no client authentication
00195    //
00196    // Example: use Opt = kSrvAuth to require client authentication.
00197    //
00198    // Default options are taken from fgAcceptOpt and are initially
00199    // equivalent to kSrvNoAuth; they can be changed with the static
00200    // method TServerSocket::SetAcceptOptions(Opt).
00201    // The active defaults can be visualized using the static method
00202    // TServerSocket::ShowAcceptOptions().
00203    //
00204 
00205    if (fSocket == -1) { return 0; }
00206 
00207    TSocket *socket = new TSocket;
00208 
00209    Int_t soc = gSystem->AcceptConnection(fSocket);
00210    if (soc == -1) { delete socket; return 0; }
00211    if (soc == -2) { delete socket; return (TSocket*) -1; }
00212 
00213    // Parse Opt
00214    UChar_t acceptOpt = fgAcceptOpt;
00215    setaccopt(acceptOpt,Opt);
00216    Bool_t auth = (Bool_t)(acceptOpt & kSrvAuth);
00217 
00218    socket->fSocket  = soc;
00219    socket->fSecContext = 0;
00220    socket->fService = fService;
00221    if (!TestBit(TSocket::kIsUnix))
00222       socket->fAddress = gSystem->GetPeerName(socket->fSocket);
00223    if (socket->fSocket >= 0) {
00224       R__LOCKGUARD2(gROOTMutex);
00225       gROOT->GetListOfSockets()->Add(socket);
00226    }
00227 
00228    // Perform authentication, if required
00229    if (auth) {
00230       if (!Authenticate(socket)) {
00231          delete socket;
00232          socket = 0;
00233       }
00234    }
00235 
00236    return socket;
00237 }
00238 
00239 //______________________________________________________________________________
00240 TInetAddress TServerSocket::GetLocalInetAddress()
00241 {
00242    // Return internet address of host to which the server socket is bound,
00243    // i.e. the local host. In case of error TInetAddress::IsValid() returns
00244    // kFALSE.
00245 
00246    if (fSocket != -1) {
00247       if (fAddress.GetPort() == -1)
00248          fAddress = gSystem->GetSockName(fSocket);
00249       return fAddress;
00250    }
00251    return TInetAddress();
00252 }
00253 
00254 //______________________________________________________________________________
00255 Int_t TServerSocket::GetLocalPort()
00256 {
00257    // Get port # to which server socket is bound. In case of error returns -1.
00258 
00259    if (fSocket != -1) {
00260       if (fAddress.GetPort() == -1)
00261          fAddress = GetLocalInetAddress();
00262       return fAddress.GetPort();
00263    }
00264    return -1;
00265 }
00266 
00267 
00268 //______________________________________________________________________________
00269 UChar_t TServerSocket::GetAcceptOptions()
00270 {
00271    // Return default options for Accept
00272 
00273    return fgAcceptOpt;
00274 }
00275 
00276 //______________________________________________________________________________
00277 void TServerSocket::SetAcceptOptions(UChar_t mod)
00278 {
00279    // Set default options for Accept according to modifier 'mod'.
00280    // Use:
00281    //   kSrvAuth                 require client authentication
00282    //   kSrvNoAuth               do not require client authentication
00283 
00284    setaccopt(fgAcceptOpt,mod);
00285 }
00286 
00287 //______________________________________________________________________________
00288 void TServerSocket::ShowAcceptOptions()
00289 {
00290    // Print default options for Accept
00291 
00292    ::Info("ShowAcceptOptions","    Auth: %d",(Bool_t)(fgAcceptOpt & kSrvAuth));
00293 }
00294 
00295 //______________________________________________________________________________
00296 Bool_t TServerSocket::Authenticate(TSocket *sock)
00297 {
00298    // Check authentication request from the client on new
00299    // open connection
00300 
00301    if (!fgSrvAuthHook) {
00302       R__LOCKGUARD2(gSrvAuthenticateMutex);
00303 
00304       // Load libraries needed for (server) authentication ...
00305       TString srvlib = "libSrvAuth";
00306       char *p = 0;
00307       // The generic one
00308       if ((p = gSystem->DynamicPathName(srvlib, kTRUE))) {
00309          delete[] p;
00310          if (gSystem->Load(srvlib) == -1) {
00311             Error("Authenticate", "can't load %s",srvlib.Data());
00312             return kFALSE;
00313          }
00314       } else {
00315          Error("Authenticate", "can't locate %s",srvlib.Data());
00316          return kFALSE;
00317       }
00318       //
00319       // Locate SrvAuthenticate
00320       Func_t f = gSystem->DynFindSymbol(srvlib,"SrvAuthenticate");
00321       if (f)
00322          fgSrvAuthHook = (SrvAuth_t)(f);
00323       else {
00324          Error("Authenticate", "can't find SrvAuthenticate");
00325          return kFALSE;
00326       }
00327       //
00328       // Locate SrvAuthCleanup
00329       f = gSystem->DynFindSymbol(srvlib,"SrvAuthCleanup");
00330       if (f)
00331          fgSrvAuthClupHook = (SrvClup_t)(f);
00332       else {
00333          Warning("Authenticate", "can't find SrvAuthCleanup");
00334       }
00335    }
00336 
00337    TString confdir;
00338 #ifndef ROOTPREFIX
00339    // try to guess the config directory...
00340    if (gSystem->Getenv("ROOTSYS")) {
00341       confdir = TString(gSystem->Getenv("ROOTSYS"));
00342    } else {
00343       // Try to guess it from 'root.exe' path
00344       char *rootexe = gSystem->Which(gSystem->Getenv("PATH"),
00345                                      "root.exe", kExecutePermission);
00346       confdir = rootexe;
00347       confdir.Resize(confdir.Last('/'));
00348       delete [] rootexe;
00349    }
00350 #else
00351    confdir = TString(ROOTPREFIX);
00352 #endif
00353    if (!confdir.Length()) {
00354       Error("Authenticate", "config dir undefined");
00355       return kFALSE;
00356    }
00357 
00358    // dir for temporary files
00359    TString tmpdir = TString(gSystem->TempDirectory());
00360    if (gSystem->AccessPathName(tmpdir, kWritePermission))
00361       tmpdir = TString("/tmp");
00362 
00363    // Get Host name
00364    TString openhost(sock->GetInetAddress().GetHostName());
00365    if (gDebug > 2)
00366       Info("Authenticate","OpenHost = %s", openhost.Data());
00367 
00368    // Run Authentication now
00369    std::string user;
00370    Int_t meth = -1;
00371    Int_t auth = 0;
00372    Int_t type = 0;
00373    std::string ctkn = "";
00374    if (fgSrvAuthHook)
00375       auth = (*fgSrvAuthHook)(sock, confdir, tmpdir, user,
00376                               meth, type, ctkn, fSecContexts);
00377 
00378    if (gDebug > 2)
00379       Info("Authenticate","auth = %d, type= %d, ctkn= %s",
00380             auth, type, ctkn.c_str());
00381 
00382    return auth;
00383 }

Generated on Tue Jul 5 14:46:11 2011 for ROOT_528-00b_version by  doxygen 1.5.1