TApplicationServer.cxx

Go to the documentation of this file.
00001 // @(#)root/net:$Id: TApplicationServer.cxx 36116 2010-10-06 13:58:05Z ganis $
00002 // Author: G. Ganis  10/5/2007
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2007, 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 // TApplicationServer                                                   //
00015 //                                                                      //
00016 // TApplicationServer is the remote application run by the roots main   //
00017 // program. The input is taken from the socket connection to the client.//
00018 //                                                                      //
00019 //////////////////////////////////////////////////////////////////////////
00020 
00021 #include "RConfigure.h"
00022 #include "RConfig.h"
00023 #include "Riostream.h"
00024 
00025 #ifdef WIN32
00026    #include <io.h>
00027    typedef long off_t;
00028 #endif
00029 #include <stdlib.h>
00030 #include <errno.h>
00031 #include <time.h>
00032 #include <fcntl.h>
00033 #include <sys/types.h>
00034 #include <sys/stat.h>
00035 
00036 #if (defined(__FreeBSD__) && (__FreeBSD__ < 4)) || \
00037     (defined(__APPLE__) && (!defined(MAC_OS_X_VERSION_10_3) || \
00038      (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_3)))
00039 #include <sys/file.h>
00040 #define lockf(fd, op, sz)   flock((fd), (op))
00041 #ifndef F_LOCK
00042 #define F_LOCK             (LOCK_EX | LOCK_NB)
00043 #endif
00044 #ifndef F_ULOCK
00045 #define F_ULOCK             LOCK_UN
00046 #endif
00047 #endif
00048 
00049 #include "RRemoteProtocol.h"
00050 
00051 #include "TApplicationServer.h"
00052 #include "TBenchmark.h"
00053 #include "TEnv.h"
00054 #include "TError.h"
00055 #include "TException.h"
00056 #include "TInterpreter.h"
00057 #include "TMD5.h"
00058 #include "TMessage.h"
00059 #include "TROOT.h"
00060 #include "TSocket.h"
00061 #include "TSystem.h"
00062 #include "TRemoteObject.h"
00063 #include "TUrl.h"
00064 #include "TObjString.h"
00065 #include "compiledata.h"
00066 #include "TClass.h"
00067 
00068 
00069 //----- Interrupt signal handler -----------------------------------------------
00070 //______________________________________________________________________________
00071 class TASInterruptHandler : public TSignalHandler {
00072    TApplicationServer  *fServ;
00073 public:
00074    TASInterruptHandler(TApplicationServer *s)
00075       : TSignalHandler(kSigUrgent, kFALSE) { fServ = s; }
00076    Bool_t  Notify();
00077 };
00078 
00079 //______________________________________________________________________________
00080 Bool_t TASInterruptHandler::Notify()
00081 {
00082    // Handle this interrupt
00083 
00084    fServ->HandleUrgentData();
00085    if (TROOT::Initialized()) {
00086       Throw(GetSignal());
00087    }
00088    return kTRUE;
00089 }
00090 
00091 //----- SigPipe signal handler -------------------------------------------------
00092 //______________________________________________________________________________
00093 class TASSigPipeHandler : public TSignalHandler {
00094    TApplicationServer  *fServ;
00095 public:
00096    TASSigPipeHandler(TApplicationServer *s) : TSignalHandler(kSigPipe, kFALSE)
00097       { fServ = s; }
00098    Bool_t  Notify();
00099 };
00100 
00101 //______________________________________________________________________________
00102 Bool_t TASSigPipeHandler::Notify()
00103 {
00104    // Handle this signal
00105 
00106    fServ->HandleSigPipe();
00107    return kTRUE;
00108 }
00109 
00110 //----- Input handler for messages from client -----------------------
00111 //______________________________________________________________________________
00112 class TASInputHandler : public TFileHandler {
00113    TApplicationServer  *fServ;
00114 public:
00115    TASInputHandler(TApplicationServer *s, Int_t fd) : TFileHandler(fd, 1)
00116       { fServ = s; }
00117    Bool_t Notify();
00118    Bool_t ReadNotify() { return Notify(); }
00119 };
00120 
00121 //______________________________________________________________________________
00122 Bool_t TASInputHandler::Notify()
00123 {
00124    // Handle this input
00125 
00126    fServ->HandleSocketInput();
00127    return kTRUE;
00128 }
00129 
00130 TString TASLogHandler::fgPfx = ""; // Default prefix to be prepended to messages
00131 //______________________________________________________________________________
00132 TASLogHandler::TASLogHandler(const char *cmd, TSocket *s, const char *pfx)
00133               : TFileHandler(-1, 1), fSocket(s), fPfx(pfx)
00134 {
00135    // Execute 'cmd' in a pipe and handle output messages from the related file
00136 
00137    ResetBit(kFileIsPipe);
00138    fFile = 0;
00139    if (s && cmd) {
00140       fFile = gSystem->OpenPipe(cmd, "r");
00141       if (fFile) {
00142          SetFd(fileno(fFile));
00143          // Notify what already in the file
00144          Notify();
00145          // Used in the destructor
00146          SetBit(kFileIsPipe);
00147       } else {
00148          fSocket = 0;
00149          Error("TASLogHandler", "executing command in pipe");
00150       }
00151    } else {
00152       Error("TASLogHandler",
00153             "undefined command (%p) or socket (%p)", (int *)cmd, s);
00154    }
00155 }
00156 //______________________________________________________________________________
00157 TASLogHandler::TASLogHandler(FILE *f, TSocket *s, const char *pfx)
00158               : TFileHandler(-1, 1), fSocket(s), fPfx(pfx)
00159 {
00160    // Handle available message from the open file 'f'
00161 
00162    ResetBit(kFileIsPipe);
00163    fFile = 0;
00164    if (s && f) {
00165       fFile = f;
00166       SetFd(fileno(fFile));
00167       // Notify what already in the file
00168       Notify();
00169    } else {
00170       Error("TASLogHandler", "undefined file (%p) or socket (%p)", f, s);
00171    }
00172 }
00173 //______________________________________________________________________________
00174 TASLogHandler::~TASLogHandler()
00175 {
00176    // Handle available message in the open file
00177 
00178    if (TestBit(kFileIsPipe) && fFile)
00179       gSystem->ClosePipe(fFile);
00180    fFile = 0;
00181    fSocket = 0;
00182    ResetBit(kFileIsPipe);
00183 }
00184 //______________________________________________________________________________
00185 Bool_t TASLogHandler::Notify()
00186 {
00187    // Handle available message in the open file
00188 
00189    if (IsValid()) {
00190       TMessage m(kMESS_ANY);
00191       // Read buffer
00192       char line[4096];
00193       char *plf = 0;
00194       while (fgets(line, sizeof(line), fFile)) {
00195          if ((plf = strchr(line, '\n')))
00196             *plf = 0;
00197          // Send the message one level up
00198          m.Reset(kMESS_ANY);
00199          m << (Int_t)kRRT_Message;
00200          if (fPfx.Length() > 0) {
00201             // Prepend prefix specific to this instance
00202             m << TString(Form("%s: %s", fPfx.Data(), line));
00203          } else if (fgPfx.Length() > 0) {
00204             // Prepend default prefix
00205             m << TString(Form("%s: %s", fgPfx.Data(), line));
00206          } else {
00207             // Nothing to prepend
00208             m << TString(line);
00209          }
00210          fSocket->Send(m);
00211       }
00212    }
00213    return kTRUE;
00214 }
00215 //______________________________________________________________________________
00216 void TASLogHandler::SetDefaultPrefix(const char *pfx)
00217 {
00218    // Static method to set the default prefix
00219 
00220    fgPfx = pfx;
00221 }
00222 
00223 //______________________________________________________________________________
00224 TASLogHandlerGuard::TASLogHandlerGuard(const char *cmd, TSocket *s,
00225                                        const char *pfx, Bool_t on)
00226 {
00227    // Init a guard for executing a command in a pipe
00228 
00229    fExecHandler = 0;
00230    if (cmd && on) {
00231       fExecHandler = new TASLogHandler(cmd, s, pfx);
00232       if (fExecHandler->IsValid()) {
00233          gSystem->AddFileHandler(fExecHandler);
00234       } else {
00235          Error("TASLogHandlerGuard","invalid handler");
00236       }
00237    } else {
00238       if (on)
00239          Error("TASLogHandlerGuard","undefined command");
00240    }
00241 }
00242 
00243 //______________________________________________________________________________
00244 TASLogHandlerGuard::TASLogHandlerGuard(FILE *f, TSocket *s,
00245                                        const char *pfx, Bool_t on)
00246 {
00247    // Init a guard for executing a command in a pipe
00248 
00249    fExecHandler = 0;
00250    if (f && on) {
00251       fExecHandler = new TASLogHandler(f, s, pfx);
00252       if (fExecHandler->IsValid()) {
00253          gSystem->AddFileHandler(fExecHandler);
00254       } else {
00255          Error("TASLogHandlerGuard","invalid handler");
00256       }
00257    } else {
00258       if (on)
00259          Error("TASLogHandlerGuard","undefined file");
00260    }
00261 }
00262 
00263 //______________________________________________________________________________
00264 TASLogHandlerGuard::~TASLogHandlerGuard()
00265 {
00266    // Close a guard for executing a command in a pipe
00267 
00268    if (fExecHandler && fExecHandler->IsValid()) {
00269       gSystem->RemoveFileHandler(fExecHandler);
00270       SafeDelete(fExecHandler);
00271    }
00272 }
00273 
00274 ClassImp(TApplicationServer)
00275 
00276 //______________________________________________________________________________
00277 TApplicationServer::TApplicationServer(Int_t *argc, char **argv,
00278                                        FILE *flog, const char *logfile)
00279        : TApplication("server", argc, argv, 0, -1)
00280 {
00281    // Main constructor. Create an application environment. The TApplicationServer
00282    // environment provides an eventloop via inheritance of TApplication.
00283 
00284    // Parse options
00285    GetOptions(argc, argv);
00286 
00287    // Abort on higher than kSysError's and set error handler
00288    gErrorAbortLevel = kSysError + 1;
00289    SetErrorHandler(ErrorHandler);
00290 
00291    fInterrupt       = kFALSE;
00292    fSocket          = 0;
00293    fWorkingDir      = 0;
00294 
00295    fLogFilePath     = logfile;
00296    fLogFile         = flog;
00297    fLogFileDes      = -1;
00298    if (!fLogFile || (fLogFileDes = fileno(fLogFile)) < 0)
00299       // For some reason we failed setting a redirection; we cannot continue
00300       Terminate(0);
00301    fRealTimeLog     = kFALSE;
00302    fSentCanvases    = 0;
00303 
00304    // Default prefix for notifications
00305    TASLogHandler::SetDefaultPrefix(Form("roots:%s", gSystem->HostName()));
00306 
00307    // Now we contact back the client: if we fail we set ourselves
00308    // as invalid
00309    fIsValid = kFALSE;
00310 
00311    if (!(fSocket = new TSocket(GetHost(), GetPort()))) {
00312       Terminate(0);
00313       return;
00314    }
00315    Int_t sock = fSocket->GetDescriptor();
00316 
00317    if (Setup() != 0) {
00318       Error("TApplicationServer", "failed to setup - quitting");
00319       SendLogFile(-98);
00320       Terminate(0);
00321    }
00322 
00323    // Everybody expects iostream to be available, so load it...
00324    ProcessLine("#include <iostream>", kTRUE);
00325    ProcessLine("#include <string>",kTRUE); // for std::string iostream.
00326 
00327    // Load user functions
00328    const char *logon;
00329    logon = gEnv->GetValue("Rint.Load", (char *)0);
00330    if (logon) {
00331       char *mac = gSystem->Which(TROOT::GetMacroPath(), logon, kReadPermission);
00332       if (mac)
00333          ProcessLine(Form(".L %s", logon), kTRUE);
00334       delete [] mac;
00335    }
00336 
00337    // Execute logon macro
00338    ExecLogon();
00339 
00340    // Init benchmarking
00341    gBenchmark = new TBenchmark();
00342 
00343    // Save current interpreter context
00344    gInterpreter->SaveContext();
00345    gInterpreter->SaveGlobalsContext();
00346 
00347    // Install interrupt and message input handlers
00348    gSystem->AddSignalHandler(new TASInterruptHandler(this));
00349    gSystem->AddFileHandler(new TASInputHandler(this, sock));
00350 
00351    // We are done
00352    fIsValid = kTRUE;
00353 
00354    // Startup notification
00355    BrowseDirectory(0);
00356    SendLogFile();
00357 }
00358 
00359 //______________________________________________________________________________
00360 Int_t TApplicationServer::Setup()
00361 {
00362    // Print the Remote Server logo on standard output.
00363    // Return 0 on success, -1 on failure
00364 
00365    char str[512];
00366    snprintf(str, 512, "**** Remote session @ %s started ****", gSystem->HostName());
00367    if (fSocket->Send(str) != 1+static_cast<Int_t>(strlen(str))) {
00368       Error("Setup", "failed to send startup message");
00369       return -1;
00370    }
00371 
00372    // Send our protocol level to the client
00373    if (fSocket->Send(kRRemote_Protocol, kROOTD_PROTOCOL) != 2*sizeof(Int_t)) {
00374       Error("Setup", "failed to send local protocol");
00375       return -1;
00376    }
00377 
00378    // Send the host name and full path to log file
00379    TMessage msg(kMESS_ANY);
00380    msg << TString(gSystem->HostName()) << fLogFilePath;
00381    fSocket->Send(msg);
00382 
00383    // Set working directory
00384    fWorkDir = gSystem->WorkingDirectory();
00385    if (strlen(fUrl.GetFile()) > 0) {
00386       fWorkDir = fUrl.GetFile();
00387       char *workdir = gSystem->ExpandPathName(fWorkDir.Data());
00388       fWorkDir = workdir;
00389       delete [] workdir;
00390    }
00391 
00392    // Go to working dir
00393    if (gSystem->AccessPathName(fWorkDir)) {
00394       gSystem->mkdir(fWorkDir, kTRUE);
00395       if (!gSystem->ChangeDirectory(fWorkDir)) {
00396          SysError("Setup", "can not change to directory %s",
00397                   fWorkDir.Data());
00398       }
00399    } else {
00400       if (!gSystem->ChangeDirectory(fWorkDir)) {
00401          gSystem->Unlink(fWorkDir);
00402          gSystem->mkdir(fWorkDir, kTRUE);
00403          if (!gSystem->ChangeDirectory(fWorkDir)) {
00404             SysError("Setup", "can not change to directory %s",
00405                      fWorkDir.Data());
00406          }
00407       }
00408    }
00409 
00410 #if 0 // G.Ganis May 11, 2007
00411    // This needs to be fixed: we disable for the time being
00412    // Socket options: incoming OOB should generate a SIGURG
00413    if (fSocket->SetOption(kProcessGroup, (-1)*gSystem->GetPid()) != 0)
00414       SysWarning("Setup", "failed to enable SIGURG generation on incoming OOB");
00415 #endif
00416 
00417    // Send messages off immediately to reduce latency
00418    if (fSocket->SetOption(kNoDelay, 1) != 0) {}
00419       //SysWarning("Setup", "failed to set no-delay option on input socket");
00420 
00421    // Check every two hours if client is still alive
00422    if (fSocket->SetOption(kKeepAlive, 1) != 0) {}
00423       //SysWarning("Setup", "failed to set keepalive option on input socket");
00424 
00425    // Install SigPipe handler to handle kKeepAlive failure
00426    gSystem->AddSignalHandler(new TASSigPipeHandler(this));
00427 
00428    // Done
00429    return 0;
00430 }
00431 
00432 //______________________________________________________________________________
00433 TApplicationServer::~TApplicationServer()
00434 {
00435    // Cleanup. Not really necessary since after this dtor there is no
00436    // live anyway.
00437 
00438    fSentCanvases->SetOwner(kFALSE);
00439    SafeDelete(fSentCanvases);
00440    SafeDelete(fSocket);
00441    close(fLogFileDes);
00442 }
00443 
00444 //______________________________________________________________________________
00445 void TApplicationServer::GetOptions(Int_t *argc, char **argv)
00446 {
00447    // Get and handle command line options. Fixed format:
00448    // "protocol  url"
00449 
00450    if (*argc < 4) {
00451       Fatal("GetOptions", "must be started with 4 arguments");
00452       gSystem->Exit(1);
00453    }
00454 
00455    // Protocol run by the client
00456    fProtocol = TString(argv[1]).Atoi();
00457 
00458    // Client URL
00459    fUrl.SetUrl(argv[2]);
00460 
00461    // Debug level
00462    gDebug = 0;
00463    TString argdbg(argv[3]);
00464    if (argdbg.BeginsWith("-d=")) {
00465       argdbg.ReplaceAll("-d=","");
00466       gDebug = argdbg.Atoi();
00467    }
00468 }
00469 
00470 //______________________________________________________________________________
00471 void TApplicationServer::Run(Bool_t retrn)
00472 {
00473    // Main server eventloop.
00474 
00475    // Setup the server
00476    if (fIsValid) {
00477       // Run the main event loop
00478       TApplication::Run(retrn);
00479    } else {
00480       Error("Run", "invalid instance: cannot Run()");
00481       gSystem->Exit(1);
00482    }
00483 }
00484 
00485 //______________________________________________________________________________
00486 void TApplicationServer::HandleSocketInput()
00487 {
00488    // Handle input coming from the client or from the master server.
00489 
00490    TMessage *mess;
00491    char      str[2048];
00492    Int_t     what;
00493 
00494    if (fSocket->Recv(mess) <= 0) {
00495       // Pending: do something more intelligent here
00496       // but at least get a message in the log file
00497       Error("HandleSocketInput", "retrieving message from input socket");
00498       Terminate(0);
00499       return;
00500    }
00501 
00502    what = mess->What();
00503    if (gDebug > 0)
00504       Info("HandleSocketInput", "got message of type %d", what);
00505 
00506    switch (what) {
00507 
00508       case kMESS_CINT:
00509          {  TASLogHandlerGuard hg(fLogFile, fSocket, "", fRealTimeLog);
00510             mess->ReadString(str, sizeof(str));
00511             if (gDebug > 1)
00512                Info("HandleSocketInput:kMESS_CINT", "processing: %s...", str);
00513             ProcessLine(str);
00514          }
00515          SendCanvases();
00516          SendLogFile();
00517          break;
00518 
00519       case kMESS_STRING:
00520          mess->ReadString(str, sizeof(str));
00521          break;
00522 
00523       case kMESS_OBJECT:
00524          mess->ReadObject(mess->GetClass());
00525          break;
00526 
00527       case kMESS_ANY:
00528          {
00529             Int_t type;
00530             (*mess) >> type;
00531             switch (type) {
00532                case kRRT_Reset:
00533                   mess->ReadString(str, sizeof(str));
00534                   Reset(str);
00535                   break;
00536 
00537                case kRRT_CheckFile:
00538                   // Handle file checking request
00539                   HandleCheckFile(mess);
00540                   break;
00541 
00542                case kRRT_File:
00543                   // A file follows
00544                   mess->ReadString(str, sizeof(str));
00545                   {  char   name[2048], i1[20], i2[40];
00546                      sscanf(str, "%2047s %19s %39s", name, i1, i2);
00547                      Int_t  bin = atoi(i1);
00548                      Long_t size = atol(i2);
00549                      ReceiveFile(name, bin ? kTRUE : kFALSE, size);
00550                   }
00551                   break;
00552 
00553                case kRRT_Terminate:
00554                   // Terminate the session (will not return from here)
00555                   Int_t status;
00556                   (*mess) >> status;
00557                   Terminate(status);
00558                   break;
00559 
00560                default:
00561                   break;
00562             }
00563          }
00564          SendLogFile();
00565          break;
00566       default:
00567          Warning("HandleSocketInput","message type unknown (%d)", what);
00568          SendLogFile();
00569          break;
00570    }
00571 
00572    delete mess;
00573 }
00574 
00575 //______________________________________________________________________________
00576 void TApplicationServer::HandleUrgentData()
00577 {
00578    // Handle Out-Of-Band data sent by the master or client.
00579 
00580    char  oob_byte;
00581    Int_t n, nch, wasted = 0;
00582 
00583    const Int_t kBufSize = 1024;
00584    char waste[kBufSize];
00585 
00586    // Real-time notification of messages
00587    TASLogHandlerGuard hg(fLogFile, fSocket, "", fRealTimeLog);
00588 
00589    Info("HandleUrgentData", "handling oob...");
00590 
00591    // Receive the OOB byte
00592    while ((n = fSocket->RecvRaw(&oob_byte, 1, kOob)) < 0) {
00593       if (n == -2) {   // EWOULDBLOCK
00594          //
00595          // The OOB data has not yet arrived: flush the input stream
00596          //
00597          // In some systems (Solaris) regular recv() does not return upon
00598          // receipt of the oob byte, which makes the below call to recv()
00599          // block indefinitely if there are no other data in the queue.
00600          // FIONREAD ioctl can be used to check if there are actually any
00601          // data to be flushed.  If not, wait for a while for the oob byte
00602          // to arrive and try to read it again.
00603          //
00604          fSocket->GetOption(kBytesToRead, nch);
00605          if (nch == 0) {
00606             gSystem->Sleep(1000);
00607             continue;
00608          }
00609 
00610          if (nch > kBufSize) nch = kBufSize;
00611          n = fSocket->RecvRaw(waste, nch);
00612          if (n <= 0) {
00613             Error("HandleUrgentData", "error receiving waste");
00614             break;
00615          }
00616          wasted = 1;
00617       } else {
00618          Error("HandleUrgentData", "error receiving OOB (n = %d)",n);
00619          return;
00620       }
00621    }
00622 
00623    Info("HandleUrgentData", "got OOB byte: %d\n", oob_byte);
00624 
00625    switch (oob_byte) {
00626 
00627       case kRRI_Hard:
00628          Info("HandleUrgentData", "*** Hard Interrupt");
00629 
00630          // Flush input socket
00631          while (1) {
00632             Int_t atmark;
00633 
00634             fSocket->GetOption(kAtMark, atmark);
00635 
00636             if (atmark) {
00637                // Send the OOB byte back so that the client knows where
00638                // to stop flushing its input stream of obsolete messages
00639                n = fSocket->SendRaw(&oob_byte, 1, kOob);
00640                if (n <= 0)
00641                   Error("HandleUrgentData", "error sending OOB");
00642                break;
00643             }
00644 
00645             // find out number of bytes to read before atmark
00646             fSocket->GetOption(kBytesToRead, nch);
00647             if (nch == 0) {
00648                gSystem->Sleep(1000);
00649                continue;
00650             }
00651 
00652             if (nch > kBufSize) nch = kBufSize;
00653             n = fSocket->RecvRaw(waste, nch);
00654             if (n <= 0) {
00655                Error("HandleUrgentData", "error receiving waste (2)");
00656                break;
00657             }
00658          }
00659 
00660          SendLogFile();
00661 
00662          break;
00663 
00664       case kRRI_Soft:
00665          Info("HandleUrgentData", "Soft Interrupt");
00666 
00667          if (wasted) {
00668             Error("HandleUrgentData", "soft interrupt flushed stream");
00669             break;
00670          }
00671 
00672          Interrupt();
00673 
00674          SendLogFile();
00675 
00676          break;
00677 
00678       case kRRI_Shutdown:
00679          Info("HandleUrgentData", "Shutdown Interrupt");
00680 
00681          Terminate(0);
00682 
00683          break;
00684 
00685       default:
00686          Error("HandleUrgentData", "unexpected OOB byte");
00687          break;
00688    }
00689 }
00690 
00691 //______________________________________________________________________________
00692 void TApplicationServer::HandleSigPipe()
00693 {
00694    // Called when the client is not alive anymore (i.e. when kKeepAlive
00695    // has failed).
00696 
00697    // Real-time notification of messages
00698    TASLogHandlerGuard hg(fLogFile, fSocket, "", fRealTimeLog);
00699 
00700    Info("HandleSigPipe", "client died");
00701    Terminate(0);  // will not return from here....
00702 }
00703 
00704 //______________________________________________________________________________
00705 void TApplicationServer::Reset(const char *dir)
00706 {
00707    // Reset environment to be ready for execution of next command.
00708 
00709    // First go to new directory.
00710    gDirectory->cd(dir);
00711 
00712    // Clear interpreter environment.
00713    gROOT->Reset();
00714 
00715    // Make sure current directory is empty (don't delete anything when
00716    // we happen to be in the ROOT memory only directory!?)
00717    if (gDirectory != gROOT) {
00718       gDirectory->Delete();
00719    }
00720 }
00721 
00722 //______________________________________________________________________________
00723 Int_t TApplicationServer::ReceiveFile(const char *file, Bool_t bin, Long64_t size)
00724 {
00725    // Receive a file, either sent by a client or a master server.
00726    // If bin is true it is a binary file, other wise it is an ASCII
00727    // file and we need to check for Windows \r tokens. Returns -1 in
00728    // case of error, 0 otherwise.
00729 
00730    if (size <= 0) return 0;
00731 
00732    // open file, overwrite already existing file
00733    Int_t fd = open(file, O_CREAT | O_TRUNC | O_WRONLY, 0600);
00734    if (fd < 0) {
00735       SysError("ReceiveFile", "error opening file %s", file);
00736       return -1;
00737    }
00738 
00739    const Int_t kMAXBUF = 16384;  //32768  //16384  //65536;
00740    char buf[kMAXBUF], cpy[kMAXBUF];
00741 
00742    Int_t    left, r;
00743    Long64_t filesize = 0;
00744 
00745    while (filesize < size) {
00746       left = Int_t(size - filesize);
00747       if (left > kMAXBUF)
00748          left = kMAXBUF;
00749       r = fSocket->RecvRaw(&buf, left);
00750       if (r > 0) {
00751          char *p = buf;
00752 
00753          filesize += r;
00754          while (r) {
00755             Int_t w;
00756 
00757             if (!bin) {
00758                Int_t k = 0, i = 0, j = 0;
00759                char *q;
00760                while (i < r) {
00761                   if (p[i] == '\r') {
00762                      i++;
00763                      k++;
00764                   }
00765                   cpy[j++] = buf[i++];
00766                }
00767                q = cpy;
00768                r -= k;
00769                w = write(fd, q, r);
00770             } else {
00771                w = write(fd, p, r);
00772             }
00773 
00774             if (w < 0) {
00775                SysError("ReceiveFile", "error writing to file %s", file);
00776                close(fd);
00777                return -1;
00778             }
00779             r -= w;
00780             p += w;
00781          }
00782       } else if (r < 0) {
00783          Error("ReceiveFile", "error during receiving file %s", file);
00784          close(fd);
00785          return -1;
00786       }
00787    }
00788 
00789    close(fd);
00790 
00791    chmod(file, 0644);
00792 
00793    return 0;
00794 }
00795 
00796 //______________________________________________________________________________
00797 void TApplicationServer::SendLogFile(Int_t status, Int_t start, Int_t end)
00798 {
00799    // Send log file to master.
00800    // If start > -1 send only bytes in the range from start to end,
00801    // if end <= start send everything from start.
00802 
00803    // Determine the number of bytes left to be read from the log file.
00804    fflush(stdout);
00805 
00806    off_t ltot=0, lnow=0;
00807    Int_t left = -1;
00808    Bool_t adhoc = kFALSE;
00809 
00810    if (fLogFileDes > -1) {
00811       ltot = lseek(fileno(stdout), (off_t) 0, SEEK_END);
00812       lnow = lseek(fLogFileDes, (off_t) 0, SEEK_CUR);
00813       if (lnow == -1) {
00814          SysError("SendLogFile", "lseek failed");
00815          lnow = 0;
00816       }
00817 
00818       if (start > -1) {
00819          lseek(fLogFileDes, (off_t) start, SEEK_SET);
00820          if (end <= start || end > ltot)
00821             end = ltot;
00822          left = (Int_t)(end - start);
00823          if (end < ltot)
00824             left++;
00825          adhoc = kTRUE;
00826       } else {
00827          left = (Int_t)(ltot - lnow);
00828       }
00829    }
00830 
00831    TMessage m(kMESS_ANY);
00832 
00833    if (left > 0) {
00834 
00835       m << (Int_t)kRRT_LogFile << left;
00836       fSocket->Send(m);
00837 
00838       const Int_t kMAXBUF = 32768;  //16384  //65536;
00839       char buf[kMAXBUF];
00840       Int_t wanted = (left > kMAXBUF) ? kMAXBUF : left;
00841       Int_t len;
00842       do {
00843          while ((len = read(fLogFileDes, buf, wanted)) < 0 &&
00844                 TSystem::GetErrno() == EINTR)
00845             TSystem::ResetErrno();
00846 
00847          if (len < 0) {
00848             SysError("SendLogFile", "error reading log file");
00849             break;
00850          }
00851 
00852          if (end == ltot && len == wanted)
00853             buf[len-1] = '\n';
00854 
00855          if (fSocket->SendRaw(buf, len) < 0) {
00856             SysError("SendLogFile", "error sending log file");
00857             break;
00858          }
00859 
00860          // Update counters
00861          left -= len;
00862          wanted = (left > kMAXBUF) ? kMAXBUF : left;
00863 
00864       } while (len > 0 && left > 0);
00865    }
00866 
00867    // Restore initial position if partial send
00868    if (adhoc)
00869       lseek(fLogFileDes, lnow, SEEK_SET);
00870 
00871    m.Reset();
00872    m << (Int_t)kRRT_LogDone << status;
00873 
00874    fSocket->Send(m);
00875 }
00876 
00877 //______________________________________________________________________________
00878 Int_t TApplicationServer::SendCanvases()
00879 {
00880    // Send any created canvas to client
00881 
00882    Int_t nc = 0;
00883 
00884    // Send back new canvases
00885    TMessage mess(kMESS_OBJECT);
00886    TIter next(gROOT->GetListOfCanvases());
00887    TObject *o = 0;
00888    while ((o = next())) {
00889       if (!fSentCanvases)
00890          fSentCanvases = new TList;
00891       Bool_t sentalready = kFALSE;
00892       // We cannot use FindObject here because there may be invalid
00893       // objects in the send list (i.e. deleted canvases)
00894       TObjLink *lnk = fSentCanvases->FirstLink();
00895       while (lnk) {
00896          TObject *sc = lnk->GetObject();
00897          lnk = lnk->Next();
00898          if ((sc->TestBit(kNotDeleted)) && sc == o)
00899             sentalready = kTRUE;
00900       }
00901       if (!sentalready) {
00902          if (gDebug > 0)
00903             Info("SendCanvases","new canvas found: %p", o);
00904          mess.Reset(kMESS_OBJECT);
00905          mess.WriteObject(o);
00906          fSocket->Send(mess);
00907          nc++;
00908          fSentCanvases->Add(o);
00909       }
00910    }
00911    return nc;
00912 }
00913 
00914 //______________________________________________________________________________
00915 Int_t TApplicationServer::BrowseDirectory(const char *dirname)
00916 {
00917    // Browse directory and send back its content to client.
00918 
00919    Int_t nc = 0;
00920 
00921    TMessage mess(kMESS_OBJECT);
00922    if (!fWorkingDir || !dirname || !*dirname) {
00923       if (!fWorkingDir)
00924          fWorkingDir = new TRemoteObject(fWorkDir, fWorkDir, "TSystemDirectory");
00925       fWorkingDir->Browse();
00926       mess.Reset(kMESS_OBJECT);
00927       mess.WriteObject(fWorkingDir);
00928       fSocket->Send(mess);
00929       nc++;
00930    }
00931    else if (fWorkingDir) {
00932       TRemoteObject dir(dirname, dirname, "TSystemDirectory");
00933       TList *list = dir.Browse();
00934       mess.Reset(kMESS_OBJECT);
00935       mess.WriteObject(list);
00936       fSocket->Send(mess);
00937       nc++;
00938    }
00939    return nc;
00940 }
00941 
00942 //______________________________________________________________________________
00943 Int_t TApplicationServer::BrowseFile(const char *fname)
00944 {
00945    // Browse root file and send back its content;
00946    // if fname is null, send the full list of files.
00947 
00948    Int_t nc = 0;
00949 
00950    TList *list = new TList;
00951    TMessage mess(kMESS_OBJECT);
00952    if (!fname || !*fname) {
00953       // fname is null, so send the list of files.
00954       TIter next(gROOT->GetListOfFiles());
00955       TNamed *fh = 0;
00956       TRemoteObject *robj;
00957       while ((fh = (TNamed *)next())) {
00958          robj = new TRemoteObject(fh->GetName(), fh->GetTitle(), "TFile");
00959          list->Add(robj);
00960       }
00961       if (list->GetEntries() > 0) {
00962          mess.Reset(kMESS_OBJECT);
00963          mess.WriteObject(list);
00964          fSocket->Send(mess);
00965          nc++;
00966       }
00967    }
00968    else {
00969       // get Root file content and send the list of objects
00970       TDirectory *fh = (TDirectory *)gROOT->GetListOfFiles()->FindObject(fname);
00971       if (fh) {
00972          fh->cd();
00973          TRemoteObject dir(fh->GetName(), fh->GetTitle(), "TFile");
00974          TList *keylist = (TList *)gROOT->ProcessLine(Form("((TFile *)0x%lx)->GetListOfKeys();", (ULong_t)fh));
00975          TIter nextk(keylist);
00976          TNamed *key = 0;
00977          TRemoteObject *robj;
00978          while ((key = (TNamed *)nextk())) {
00979             robj = new TRemoteObject(key->GetName(), key->GetTitle(), "TKey");
00980             const char *classname = (const char *)gROOT->ProcessLine(Form("((TKey *)0x%lx)->GetClassName();", (ULong_t)key));
00981             robj->SetKeyClassName(classname);
00982             Bool_t isFolder = (Bool_t)gROOT->ProcessLine(Form("((TKey *)0x%lx)->IsFolder();", (ULong_t)key));
00983             robj->SetFolder(isFolder);
00984             robj->SetRemoteAddress((Long_t) key);
00985             list->Add(robj);
00986          }
00987          if (list->GetEntries() > 0) {
00988             mess.Reset(kMESS_OBJECT);
00989             mess.WriteObject(list);
00990             fSocket->Send(mess);
00991             nc++;
00992          }
00993       }
00994    }
00995    return nc;
00996 }
00997 
00998 //______________________________________________________________________________
00999 Int_t TApplicationServer::BrowseKey(const char *keyname)
01000 {
01001    // Read key object and send it back to client.
01002 
01003    Int_t nc = 0;
01004 
01005    TMessage mess(kMESS_OBJECT);
01006    TNamed *obj = (TNamed *)gROOT->ProcessLine(Form("gFile->GetKey(\"%s\")->ReadObj();", keyname));
01007    if (obj) {
01008       mess.Reset(kMESS_OBJECT);
01009       mess.WriteObject(obj);
01010       fSocket->Send(mess);
01011       nc++;
01012    }
01013    return nc;
01014 }
01015 
01016 //______________________________________________________________________________
01017 void TApplicationServer::Terminate(Int_t status)
01018 {
01019    // Terminate the proof server.
01020 
01021    // Close and remove the log file; remove the cleanup script
01022    if (fLogFile) {
01023       fclose(fLogFile);
01024       // Delete the log file unless we are in debug mode
01025       if (gDebug <= 0)
01026          gSystem->Unlink(fLogFilePath);
01027       TString cleanup = fLogFilePath;
01028       cleanup.ReplaceAll(".log", ".cleanup");
01029       gSystem->Unlink(cleanup);
01030    }
01031 
01032    // Remove input handler to avoid spurious signals in socket
01033    // selection for closing activities executed upon exit()
01034    TIter next(gSystem->GetListOfFileHandlers());
01035    TObject *fh = 0;
01036    while ((fh = next())) {
01037       TASInputHandler *ih = dynamic_cast<TASInputHandler *>(fh);
01038       if (ih)
01039          gSystem->RemoveFileHandler(ih);
01040    }
01041 
01042    // Stop processing events
01043    gSystem->Exit(status);
01044 }
01045 
01046 //______________________________________________________________________________
01047 void TApplicationServer::HandleCheckFile(TMessage *mess)
01048 {
01049    // Handle file checking request.
01050 
01051    TString filenam;
01052    TMD5    md5;
01053    TMessage m(kMESS_ANY);
01054 
01055    // Parse message
01056    (*mess) >> filenam >> md5;
01057 
01058    // check file in working directory
01059    TMD5 *md5local = TMD5::FileChecksum(filenam);
01060    if (md5local && md5 == (*md5local)) {
01061       // We have an updated copy of the file
01062       m << (Int_t) kRRT_CheckFile << (Bool_t) kTRUE;
01063       fSocket->Send(m);
01064       if (gDebug > 0)
01065          Info("HandleCheckFile", "up-to-date version of %s available", filenam.Data());
01066    } else {
01067       m << (Int_t) kRRT_CheckFile << (Bool_t) kFALSE;
01068       fSocket->Send(m);
01069       if (gDebug > 0)
01070          Info("HandleCheckFile", "file %s needs to be uploaded", filenam.Data());
01071    }
01072    delete md5local;
01073 }
01074 
01075 //______________________________________________________________________________
01076 void TApplicationServer::ErrorHandler(Int_t level, Bool_t abort, const char *location,
01077                               const char *msg)
01078 {
01079    // The error handler function. It prints the message on stderr and
01080    // if abort is set it aborts the application.
01081 
01082    if (gErrorIgnoreLevel == kUnset) {
01083       gErrorIgnoreLevel = 0;
01084       if (gEnv) {
01085          TString slevel = gEnv->GetValue("Root.ErrorIgnoreLevel", "Print");
01086          if (!slevel.CompareTo("Print", TString::kIgnoreCase))
01087             gErrorIgnoreLevel = kPrint;
01088          else if (!slevel.CompareTo("Info", TString::kIgnoreCase))
01089             gErrorIgnoreLevel = kInfo;
01090          else if (!slevel.CompareTo("Warning", TString::kIgnoreCase))
01091             gErrorIgnoreLevel = kWarning;
01092          else if (!slevel.CompareTo("Error", TString::kIgnoreCase))
01093             gErrorIgnoreLevel = kError;
01094          else if (!slevel.CompareTo("Break", TString::kIgnoreCase))
01095             gErrorIgnoreLevel = kBreak;
01096          else if (!slevel.CompareTo("SysError", TString::kIgnoreCase))
01097             gErrorIgnoreLevel = kSysError;
01098          else if (!slevel.CompareTo("Fatal", TString::kIgnoreCase))
01099             gErrorIgnoreLevel = kFatal;
01100       }
01101    }
01102 
01103    if (level < gErrorIgnoreLevel)
01104       return;
01105 
01106    static TString syslogService;
01107 
01108    if (syslogService.IsNull()) {
01109       syslogService = "server";
01110       gSystem->Openlog(syslogService, kLogPid | kLogCons, kLogLocal5);
01111    }
01112 
01113    const char *type   = 0;
01114    ELogLevel loglevel = kLogInfo;
01115 
01116    if (level >= kPrint) {
01117       loglevel = kLogInfo;
01118       type = "Print";
01119    }
01120    if (level >= kInfo) {
01121       loglevel = kLogInfo;
01122       type = "Info";
01123    }
01124    if (level >= kWarning) {
01125       loglevel = kLogWarning;
01126       type = "Warning";
01127    }
01128    if (level >= kError) {
01129       loglevel = kLogErr;
01130       type = "Error";
01131    }
01132    if (level >= kBreak) {
01133       loglevel = kLogErr;
01134       type = "*** Break ***";
01135    }
01136    if (level >= kSysError) {
01137       loglevel = kLogErr;
01138       type = "SysError";
01139    }
01140    if (level >= kFatal) {
01141       loglevel = kLogErr;
01142       type = "Fatal";
01143    }
01144 
01145    TString node = "server";
01146    TString buf;
01147 
01148    if (!location || strlen(location) == 0 ||
01149        (level >= kPrint && level < kInfo) ||
01150        (level >= kBreak && level < kSysError)) {
01151       fprintf(stderr, "%s on %s: %s\n", type, node.Data(), msg);
01152       buf.Form("%s:%s:%s", node.Data(), type, msg);
01153    } else {
01154       fprintf(stderr, "%s in <%s> on %s: %s\n", type, location, node.Data(), msg);
01155       buf.Form("%s:%s:<%s>:%s", node.Data(), type, location, msg);
01156    }
01157    fflush(stderr);
01158 
01159    gSystem->Syslog(loglevel, buf);
01160 
01161    if (abort) {
01162       fprintf(stderr, "aborting\n");
01163       fflush(stderr);
01164       gSystem->StackTrace();
01165       gSystem->Abort();
01166    }
01167 }
01168 
01169 //______________________________________________________________________________
01170 Long_t TApplicationServer::ProcessLine(const char *line, Bool_t, Int_t *)
01171 {
01172    // Parse a command line received from the client, making sure that the files
01173    // needed for the execution, if any, are available. The line is either a C++
01174    // statement or an interpreter command starting with a ".".
01175    // Return the return value of the command casted to a long.
01176 
01177    if (!line || !*line) return 0;
01178 
01179    // If load or execute request we must make sure that we have the files.
01180    // If not we ask the client to send them, blocking until we have everything.
01181    if (!strncmp(line, ".L", 2) || !strncmp(line, ".U", 2) ||
01182        !strncmp(line, ".X", 2) || !strncmp(line, ".x", 2)) {
01183       TString aclicMode;
01184       TString arguments;
01185       TString io;
01186       TString fname = gSystem->SplitAclicMode(line+3, aclicMode, arguments, io);
01187 
01188       char *imp = gSystem->Which(TROOT::GetMacroPath(), fname, kReadPermission);
01189       if (!imp) {
01190 
01191          // Make sure that we can write in the directory where we are
01192          if (gSystem->AccessPathName(gSystem->WorkingDirectory(), kWritePermission)) {
01193             Error("ProcessLine","no write permission in %s", gSystem->WorkingDirectory());
01194             return 0;
01195          }
01196 
01197          if (gDebug > 0)
01198             Info("ProcessLine", "macro %s not found in path %s: asking the client",
01199                                 fname.Data(), TROOT::GetMacroPath());
01200          TMessage m(kMESS_ANY);
01201          m << (Int_t) kRRT_SendFile << TString(gSystem->BaseName(fname));
01202          fSocket->Send(m);
01203 
01204          // Wait for the reply(ies)
01205          Int_t type;
01206          Bool_t filefollows = kTRUE;
01207 
01208          while (filefollows) {
01209 
01210             // Get a message
01211             TMessage *rm = 0;
01212             if (fSocket->Recv(rm) <= 0) {
01213                Error("ProcessLine","ask-file: received empty message from client");
01214                return 0;
01215             }
01216             if (rm->What() != kMESS_ANY) {
01217                Error("ProcessLine","ask-file: wrong message received (what: %d)", rm->What());
01218                return 0;
01219             }
01220             (*rm) >> type;
01221             if (type != kRRT_SendFile) {
01222                Error("ProcessLine","ask-file: wrong sub-type received (type: %d)", type);
01223                return 0;
01224             }
01225             (*rm) >> filefollows;
01226             if (filefollows) {
01227                // Read the file specifications
01228                if (fSocket->Recv(rm) <= 0) {
01229                   Error("ProcessLine","file: received empty message from client");
01230                   return 0;
01231                }
01232                if (rm->What() != kMESS_ANY) {
01233                   Error("ProcessLine","file: wrong message received (what: %d)", rm->What());
01234                   return 0;
01235                }
01236                (*rm) >> type;
01237                if (type != kRRT_File) {
01238                   Error("ProcessLine","file: wrong sub-type received (type: %d)", type);
01239                   return 0;
01240                }
01241                // A file follows
01242                char str[2048];
01243                rm->ReadString(str, sizeof(str));
01244                char   name[2048], i1[20], i2[40];
01245                sscanf(str, "%2047s %19s %39s", name, i1, i2);
01246                Int_t  bin = atoi(i1);
01247                Long_t size = atol(i2);
01248                ReceiveFile(name, bin ? kTRUE : kFALSE, size);
01249             }
01250          }
01251       }
01252       delete [] imp;
01253    }
01254 
01255    // Process the line now
01256    return TApplication::ProcessLine(line);
01257 }
01258 
01259 //______________________________________________________________________________
01260 void TApplicationServer::ExecLogon()
01261 {
01262    // Execute logon macro's. There are three levels of logon macros that
01263    // will be executed: the system logon etc/system.rootlogon.C, the global
01264    // user logon ~/.rootlogon.C and the local ./.rootlogon.C. For backward
01265    // compatibility also the logon macro as specified by the Rint.Logon
01266    // environment setting, by default ./rootlogon.C, will be executed.
01267    // No logon macros will be executed when the system is started with
01268    // the -n option.
01269 
01270    if (NoLogOpt()) return;
01271 
01272    TString name = ".rootlogon.C";
01273    TString sname = "system";
01274    sname += name;
01275 #ifdef ROOTETCDIR
01276    char *s = gSystem->ConcatFileName(ROOTETCDIR, sname);
01277 #else
01278    TString etc = gRootDir;
01279 #ifdef WIN32
01280    etc += "\\etc";
01281 #else
01282    etc += "/etc";
01283 #endif
01284    char *s = gSystem->ConcatFileName(etc, sname);
01285 #endif
01286    if (!gSystem->AccessPathName(s, kReadPermission)) {
01287       ProcessFile(s);
01288    }
01289    delete [] s;
01290    s = gSystem->ConcatFileName(gSystem->HomeDirectory(), name);
01291    if (!gSystem->AccessPathName(s, kReadPermission)) {
01292       ProcessFile(s);
01293    }
01294    delete [] s;
01295    // avoid executing ~/.rootlogon.C twice
01296    if (strcmp(gSystem->HomeDirectory(), gSystem->WorkingDirectory())) {
01297       if (!gSystem->AccessPathName(name, kReadPermission))
01298          ProcessFile(name);
01299    }
01300 
01301    // execute also the logon macro specified by "Rint.Logon"
01302    const char *logon = gEnv->GetValue("Rint.Logon", (char*)0);
01303    if (logon) {
01304       char *mac = gSystem->Which(TROOT::GetMacroPath(), logon, kReadPermission);
01305       if (mac)
01306          ProcessFile(logon);
01307       delete [] mac;
01308    }
01309 }

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