21 #include "RConfigure.h"
33 #include <sys/types.h>
36 #if (defined(__FreeBSD__) && (__FreeBSD__ < 4)) || \
37 (defined(__APPLE__) && (!defined(MAC_OS_X_VERSION_10_3) || \
38 (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_3)))
40 #define lockf(fd, op, sz) flock((fd), (op))
42 #define F_LOCK (LOCK_EX | LOCK_NB)
45 #define F_ULOCK LOCK_UN
65 #include "compiledata.h"
72 class TASInterruptHandler :
public TSignalHandler {
73 TApplicationServer *fServ;
75 TASInterruptHandler(TApplicationServer *s)
76 : TSignalHandler(kSigUrgent, kFALSE) { fServ = s; }
83 Bool_t TASInterruptHandler::Notify()
85 fServ->HandleUrgentData();
86 if (TROOT::Initialized()) {
95 class TASSigPipeHandler :
public TSignalHandler {
96 TApplicationServer *fServ;
98 TASSigPipeHandler(TApplicationServer *s) : TSignalHandler(kSigPipe, kFALSE)
106 Bool_t TASSigPipeHandler::Notify()
108 fServ->HandleSigPipe();
115 class TASInputHandler :
public TFileHandler {
116 TApplicationServer *fServ;
118 TASInputHandler(TApplicationServer *s, Int_t fd) : TFileHandler(fd, 1)
121 Bool_t ReadNotify() {
return Notify(); }
127 Bool_t TASInputHandler::Notify()
129 fServ->HandleSocketInput();
133 TString TASLogHandler::fgPfx =
"";
137 TASLogHandler::TASLogHandler(
const char *cmd, TSocket *s,
const char *pfx)
138 : TFileHandler(-1, 1), fSocket(s), fPfx(pfx)
140 ResetBit(kFileIsPipe);
143 fFile = gSystem->OpenPipe(cmd,
"r");
145 SetFd(fileno(fFile));
152 Error(
"TASLogHandler",
"executing command in pipe");
155 Error(
"TASLogHandler",
156 "undefined command (%p) or socket (%p)", (
int *)cmd, s);
162 TASLogHandler::TASLogHandler(FILE *f, TSocket *s,
const char *pfx)
163 : TFileHandler(-1, 1), fSocket(s), fPfx(pfx)
165 ResetBit(kFileIsPipe);
169 SetFd(fileno(fFile));
173 Error(
"TASLogHandler",
"undefined file (%p) or socket (%p)", f, s);
179 TASLogHandler::~TASLogHandler()
181 if (TestBit(kFileIsPipe) && fFile)
182 gSystem->ClosePipe(fFile);
185 ResetBit(kFileIsPipe);
190 Bool_t TASLogHandler::Notify()
193 TMessage m(kMESS_ANY);
197 while (fgets(line,
sizeof(line), fFile)) {
198 if ((plf = strchr(line,
'\n')))
202 m << (Int_t)kRRT_Message;
203 if (fPfx.Length() > 0) {
205 m << TString(Form(
"%s: %s", fPfx.Data(), line));
206 }
else if (fgPfx.Length() > 0) {
208 m << TString(Form(
"%s: %s", fgPfx.Data(), line));
221 void TASLogHandler::SetDefaultPrefix(
const char *pfx)
229 TASLogHandlerGuard::TASLogHandlerGuard(
const char *cmd, TSocket *s,
230 const char *pfx, Bool_t on)
234 fExecHandler =
new TASLogHandler(cmd, s, pfx);
235 if (fExecHandler->IsValid()) {
236 gSystem->AddFileHandler(fExecHandler);
238 Error(
"TASLogHandlerGuard",
"invalid handler");
242 Error(
"TASLogHandlerGuard",
"undefined command");
249 TASLogHandlerGuard::TASLogHandlerGuard(FILE *f, TSocket *s,
250 const char *pfx, Bool_t on)
254 fExecHandler =
new TASLogHandler(f, s, pfx);
255 if (fExecHandler->IsValid()) {
256 gSystem->AddFileHandler(fExecHandler);
258 Error(
"TASLogHandlerGuard",
"invalid handler");
262 Error(
"TASLogHandlerGuard",
"undefined file");
269 TASLogHandlerGuard::~TASLogHandlerGuard()
271 if (fExecHandler && fExecHandler->IsValid()) {
272 gSystem->RemoveFileHandler(fExecHandler);
273 SafeDelete(fExecHandler);
277 ClassImp(TApplicationServer);
283 TApplicationServer::TApplicationServer(Int_t *argc,
char **argv,
284 FILE *flog,
const char *logfile)
285 : TApplication(
"server", argc, argv, 0, -1)
288 GetOptions(argc, argv);
291 gErrorAbortLevel = kSysError + 1;
292 SetErrorHandler(ErrorHandler);
298 fLogFilePath = logfile;
301 if (!fLogFile || (fLogFileDes = fileno(fLogFile)) < 0)
304 fRealTimeLog = kFALSE;
308 TASLogHandler::SetDefaultPrefix(Form(
"roots:%s", gSystem->HostName()));
314 if (!(fSocket =
new TSocket(GetHost(), GetPort()))) {
318 Int_t sock = fSocket->GetDescriptor();
321 Error(
"TApplicationServer",
"failed to setup - quitting");
327 ProcessLine(
"#include <iostream>", kTRUE);
328 ProcessLine(
"#include <string>",kTRUE);
332 logon = gEnv->GetValue(
"Rint.Load", (
char *)0);
334 char *mac = gSystem->Which(TROOT::GetMacroPath(), logon, kReadPermission);
336 ProcessLine(Form(
".L %s", logon), kTRUE);
344 gBenchmark =
new TBenchmark();
347 gInterpreter->SaveContext();
348 gInterpreter->SaveGlobalsContext();
351 gSystem->AddSignalHandler(
new TASInterruptHandler(
this));
352 gSystem->AddFileHandler(
new TASInputHandler(
this, sock));
366 Int_t TApplicationServer::Setup()
369 snprintf(str, 512,
"**** Remote session @ %s started ****", gSystem->HostName());
370 if (fSocket->Send(str) != 1+
static_cast<Int_t
>(strlen(str))) {
371 Error(
"Setup",
"failed to send startup message");
376 if (fSocket->Send(kRRemote_Protocol, kROOTD_PROTOCOL) != 2*
sizeof(Int_t)) {
377 Error(
"Setup",
"failed to send local protocol");
382 TMessage msg(kMESS_ANY);
383 msg << TString(gSystem->HostName()) << fLogFilePath;
387 fWorkDir = gSystem->WorkingDirectory();
388 if (strlen(fUrl.GetFile()) > 0) {
389 fWorkDir = fUrl.GetFile();
390 char *workdir = gSystem->ExpandPathName(fWorkDir.Data());
396 if (gSystem->AccessPathName(fWorkDir)) {
397 gSystem->mkdir(fWorkDir, kTRUE);
398 if (!gSystem->ChangeDirectory(fWorkDir)) {
399 SysError(
"Setup",
"can not change to directory %s",
403 if (!gSystem->ChangeDirectory(fWorkDir)) {
404 gSystem->Unlink(fWorkDir);
405 gSystem->mkdir(fWorkDir, kTRUE);
406 if (!gSystem->ChangeDirectory(fWorkDir)) {
407 SysError(
"Setup",
"can not change to directory %s",
413 #if 0 // G.Ganis May 11, 2007
416 if (fSocket->SetOption(kProcessGroup, (-1)*gSystem->GetPid()) != 0)
417 SysWarning(
"Setup",
"failed to enable SIGURG generation on incoming OOB");
421 if (fSocket->SetOption(kNoDelay, 1) != 0) {}
425 if (fSocket->SetOption(kKeepAlive, 1) != 0) {}
429 gSystem->AddSignalHandler(
new TASSigPipeHandler(
this));
439 TApplicationServer::~TApplicationServer()
441 fSentCanvases->SetOwner(kFALSE);
442 SafeDelete(fSentCanvases);
451 void TApplicationServer::GetOptions(Int_t *argc,
char **argv)
454 Fatal(
"GetOptions",
"must be started with 4 arguments");
459 fProtocol = TString(argv[1]).Atoi();
462 fUrl.SetUrl(argv[2]);
466 TString argdbg(argv[3]);
467 if (argdbg.BeginsWith(
"-d=")) {
468 argdbg.ReplaceAll(
"-d=",
"");
469 gDebug = argdbg.Atoi();
476 void TApplicationServer::Run(Bool_t retrn)
481 TApplication::Run(retrn);
483 Error(
"Run",
"invalid instance: cannot Run()");
491 void TApplicationServer::HandleSocketInput()
497 if (fSocket->Recv(mess) <= 0) {
500 Error(
"HandleSocketInput",
"retrieving message from input socket");
507 Info(
"HandleSocketInput",
"got message of type %d", what);
512 { TASLogHandlerGuard hg(fLogFile, fSocket,
"", fRealTimeLog);
513 mess->ReadString(str,
sizeof(str));
515 Info(
"HandleSocketInput:kMESS_CINT",
"processing: %s...", str);
523 mess->ReadString(str,
sizeof(str));
527 mess->ReadObject(mess->GetClass());
536 mess->ReadString(str,
sizeof(str));
542 HandleCheckFile(mess);
547 mess->ReadString(str,
sizeof(str));
548 {
char name[2048], i1[20], i2[40];
549 sscanf(str,
"%2047s %19s %39s", name, i1, i2);
550 Int_t bin = atoi(i1);
551 Long_t size = atol(i2);
552 ReceiveFile(name, bin ? kTRUE : kFALSE, size);
570 Warning(
"HandleSocketInput",
"message type unknown (%d)", what);
581 void TApplicationServer::HandleUrgentData()
584 Int_t n, nch, wasted = 0;
586 const Int_t kBufSize = 1024;
587 char waste[kBufSize];
590 TASLogHandlerGuard hg(fLogFile, fSocket,
"", fRealTimeLog);
592 Info(
"HandleUrgentData",
"handling oob...");
595 while ((n = fSocket->RecvRaw(&oob_byte, 1, kOob)) < 0) {
607 fSocket->GetOption(kBytesToRead, nch);
609 gSystem->Sleep(1000);
613 if (nch > kBufSize) nch = kBufSize;
614 n = fSocket->RecvRaw(waste, nch);
616 Error(
"HandleUrgentData",
"error receiving waste");
621 Error(
"HandleUrgentData",
"error receiving OOB (n = %d)",n);
626 Info(
"HandleUrgentData",
"got OOB byte: %d\n", oob_byte);
631 Info(
"HandleUrgentData",
"*** Hard Interrupt");
637 fSocket->GetOption(kAtMark, atmark);
642 n = fSocket->SendRaw(&oob_byte, 1, kOob);
644 Error(
"HandleUrgentData",
"error sending OOB");
649 fSocket->GetOption(kBytesToRead, nch);
651 gSystem->Sleep(1000);
655 if (nch > kBufSize) nch = kBufSize;
656 n = fSocket->RecvRaw(waste, nch);
658 Error(
"HandleUrgentData",
"error receiving waste (2)");
668 Info(
"HandleUrgentData",
"Soft Interrupt");
671 Error(
"HandleUrgentData",
"soft interrupt flushed stream");
682 Info(
"HandleUrgentData",
"Shutdown Interrupt");
689 Error(
"HandleUrgentData",
"unexpected OOB byte");
698 void TApplicationServer::HandleSigPipe()
701 TASLogHandlerGuard hg(fLogFile, fSocket,
"", fRealTimeLog);
703 Info(
"HandleSigPipe",
"client died");
710 void TApplicationServer::Reset(
const char *dir)
720 if (gDirectory != gROOT) {
721 gDirectory->Delete();
731 Int_t TApplicationServer::ReceiveFile(
const char *file, Bool_t bin, Long64_t size)
733 if (size <= 0)
return 0;
736 Int_t fd = open(file, O_CREAT | O_TRUNC | O_WRONLY, 0600);
738 SysError(
"ReceiveFile",
"error opening file %s", file);
742 const Int_t kMAXBUF = 16384;
743 char buf[kMAXBUF], cpy[kMAXBUF];
746 Long64_t filesize = 0;
748 while (filesize < size) {
749 left = Int_t(size - filesize);
752 r = fSocket->RecvRaw(&buf, left);
761 Int_t k = 0, i = 0, j = 0;
778 SysError(
"ReceiveFile",
"error writing to file %s", file);
786 Error(
"ReceiveFile",
"error during receiving file %s", file);
804 void TApplicationServer::SendLogFile(Int_t status, Int_t start, Int_t end)
809 off_t ltot=0, lnow=0;
811 Bool_t adhoc = kFALSE;
813 if (fLogFileDes > -1) {
814 ltot = lseek(fileno(stdout), (off_t) 0, SEEK_END);
815 lnow = lseek(fLogFileDes, (off_t) 0, SEEK_CUR);
817 SysError(
"SendLogFile",
"lseek failed");
822 lseek(fLogFileDes, (off_t) start, SEEK_SET);
823 if (end <= start || end > ltot)
825 left = (Int_t)(end - start);
830 left = (Int_t)(ltot - lnow);
834 TMessage m(kMESS_ANY);
838 m << (Int_t)kRRT_LogFile << left;
841 const Int_t kMAXBUF = 32768;
843 Int_t wanted = (left > kMAXBUF) ? kMAXBUF : left;
846 while ((len = read(fLogFileDes, buf, wanted)) < 0 &&
847 TSystem::GetErrno() == EINTR)
848 TSystem::ResetErrno();
851 SysError(
"SendLogFile",
"error reading log file");
855 if (end == ltot && len == wanted)
858 if (fSocket->SendRaw(buf, len) < 0) {
859 SysError(
"SendLogFile",
"error sending log file");
865 wanted = (left > kMAXBUF) ? kMAXBUF : left;
867 }
while (len > 0 && left > 0);
872 lseek(fLogFileDes, lnow, SEEK_SET);
875 m << (Int_t)kRRT_LogDone << status;
883 Int_t TApplicationServer::SendCanvases()
888 TMessage mess(kMESS_OBJECT);
889 TIter next(gROOT->GetListOfCanvases());
891 while ((o = next())) {
893 fSentCanvases =
new TList;
894 Bool_t sentalready = kFALSE;
897 TObjLink *lnk = fSentCanvases->FirstLink();
899 TObject *sc = lnk->GetObject();
901 if ((sc->TestBit(kNotDeleted)) && sc == o)
906 Info(
"SendCanvases",
"new canvas found: %p", o);
907 mess.Reset(kMESS_OBJECT);
911 fSentCanvases->Add(o);
920 Int_t TApplicationServer::BrowseDirectory(
const char *dirname)
924 TMessage mess(kMESS_OBJECT);
925 if (!fWorkingDir || !dirname || !*dirname) {
927 fWorkingDir =
new TRemoteObject(fWorkDir, fWorkDir,
"TSystemDirectory");
928 fWorkingDir->Browse();
929 mess.Reset(kMESS_OBJECT);
930 mess.WriteObject(fWorkingDir);
934 else if (fWorkingDir) {
935 TRemoteObject dir(dirname, dirname,
"TSystemDirectory");
936 TList *list = dir.Browse();
937 mess.Reset(kMESS_OBJECT);
938 mess.WriteObject(list);
949 Int_t TApplicationServer::BrowseFile(
const char *fname)
953 TList *list =
new TList;
954 TMessage mess(kMESS_OBJECT);
955 if (!fname || !*fname) {
957 TIter next(gROOT->GetListOfFiles());
960 while ((fh = (TNamed *)next())) {
961 robj =
new TRemoteObject(fh->GetName(), fh->GetTitle(),
"TFile");
964 if (list->GetEntries() > 0) {
965 mess.Reset(kMESS_OBJECT);
966 mess.WriteObject(list);
973 TDirectory *fh = (TDirectory *)gROOT->GetListOfFiles()->FindObject(fname);
976 TRemoteObject dir(fh->GetName(), fh->GetTitle(),
"TFile");
977 TList *keylist = (TList *)gROOT->ProcessLine(Form(
"((TFile *)0x%lx)->GetListOfKeys();", (ULong_t)fh));
978 TIter nextk(keylist);
981 while ((key = (TNamed *)nextk())) {
982 robj =
new TRemoteObject(key->GetName(), key->GetTitle(),
"TKey");
983 const char *classname = (
const char *)gROOT->ProcessLine(Form(
"((TKey *)0x%lx)->GetClassName();", (ULong_t)key));
984 robj->SetKeyClassName(classname);
985 Bool_t isFolder = (Bool_t)gROOT->ProcessLine(Form(
"((TKey *)0x%lx)->IsFolder();", (ULong_t)key));
986 robj->SetFolder(isFolder);
987 robj->SetRemoteAddress((Long_t) key);
990 if (list->GetEntries() > 0) {
991 mess.Reset(kMESS_OBJECT);
992 mess.WriteObject(list);
1004 Int_t TApplicationServer::BrowseKey(
const char *keyname)
1008 TMessage mess(kMESS_OBJECT);
1009 TNamed *obj = (TNamed *)gROOT->ProcessLine(Form(
"gFile->GetKey(\"%s\")->ReadObj();", keyname));
1011 mess.Reset(kMESS_OBJECT);
1012 mess.WriteObject(obj);
1013 fSocket->Send(mess);
1022 void TApplicationServer::Terminate(Int_t status)
1029 gSystem->Unlink(fLogFilePath);
1030 TString cleanup = fLogFilePath;
1031 cleanup.ReplaceAll(
".log",
".cleanup");
1032 gSystem->Unlink(cleanup);
1037 TIter next(gSystem->GetListOfFileHandlers());
1039 while ((fh = next())) {
1040 TASInputHandler *ih =
dynamic_cast<TASInputHandler *
>(fh);
1042 gSystem->RemoveFileHandler(ih);
1046 gSystem->Exit(status);
1052 void TApplicationServer::HandleCheckFile(TMessage *mess)
1056 TMessage m(kMESS_ANY);
1059 (*mess) >> filenam >> md5;
1062 TMD5 *md5local = TMD5::FileChecksum(filenam);
1063 if (md5local && md5 == (*md5local)) {
1065 m << (Int_t) kRRT_CheckFile << (Bool_t) kTRUE;
1068 Info("HandleCheckFile", "up-to-date version of %s available", filenam.Data());
1070 m << (Int_t) kRRT_CheckFile << (Bool_t) kFALSE;
1073 Info("HandleCheckFile", "file %s needs to be uploaded", filenam.Data());
1082 void TApplicationServer::ErrorHandler(Int_t level, Bool_t abort, const
char *location,
1085 if (gErrorIgnoreLevel == kUnset) {
1086 gErrorIgnoreLevel = 0;
1088 TString slevel = gEnv->GetValue(
"Root.ErrorIgnoreLevel",
"Print");
1089 if (!slevel.CompareTo(
"Print", TString::kIgnoreCase))
1090 gErrorIgnoreLevel = kPrint;
1091 else if (!slevel.CompareTo(
"Info", TString::kIgnoreCase))
1092 gErrorIgnoreLevel = kInfo;
1093 else if (!slevel.CompareTo(
"Warning", TString::kIgnoreCase))
1094 gErrorIgnoreLevel = kWarning;
1095 else if (!slevel.CompareTo(
"Error", TString::kIgnoreCase))
1096 gErrorIgnoreLevel = kError;
1097 else if (!slevel.CompareTo(
"Break", TString::kIgnoreCase))
1098 gErrorIgnoreLevel = kBreak;
1099 else if (!slevel.CompareTo(
"SysError", TString::kIgnoreCase))
1100 gErrorIgnoreLevel = kSysError;
1101 else if (!slevel.CompareTo(
"Fatal", TString::kIgnoreCase))
1102 gErrorIgnoreLevel = kFatal;
1106 if (level < gErrorIgnoreLevel)
1109 static TString syslogService;
1111 if (syslogService.IsNull()) {
1112 syslogService =
"server";
1113 gSystem->Openlog(syslogService, kLogPid | kLogCons, kLogLocal5);
1116 const char *type = 0;
1117 ELogLevel loglevel = kLogInfo;
1119 if (level >= kPrint) {
1120 loglevel = kLogInfo;
1123 if (level >= kInfo) {
1124 loglevel = kLogInfo;
1127 if (level >= kWarning) {
1128 loglevel = kLogWarning;
1131 if (level >= kError) {
1135 if (level >= kBreak) {
1137 type =
"*** Break ***";
1139 if (level >= kSysError) {
1143 if (level >= kFatal) {
1148 TString node =
"server";
1151 if (!location || !location[0] ||
1152 (level >= kPrint && level < kInfo) ||
1153 (level >= kBreak && level < kSysError)) {
1154 fprintf(stderr,
"%s on %s: %s\n", type, node.Data(), msg);
1155 buf.Form(
"%s:%s:%s", node.Data(), type, msg);
1157 fprintf(stderr,
"%s in <%s> on %s: %s\n", type, location, node.Data(), msg);
1158 buf.Form(
"%s:%s:<%s>:%s", node.Data(), type, location, msg);
1162 gSystem->Syslog(loglevel, buf);
1165 fprintf(stderr,
"aborting\n");
1167 gSystem->StackTrace();
1178 Long_t TApplicationServer::ProcessLine(
const char *line, Bool_t, Int_t *)
1180 if (!line || !*line)
return 0;
1184 if (!strncmp(line,
".L", 2) || !strncmp(line,
".U", 2) ||
1185 !strncmp(line,
".X", 2) || !strncmp(line,
".x", 2)) {
1189 TString fname = gSystem->SplitAclicMode(line+3, aclicMode, arguments, io);
1191 char *imp = gSystem->Which(TROOT::GetMacroPath(), fname, kReadPermission);
1195 if (gSystem->AccessPathName(gSystem->WorkingDirectory(), kWritePermission)) {
1196 Error(
"ProcessLine",
"no write permission in %s", gSystem->WorkingDirectory());
1201 Info(
"ProcessLine",
"macro %s not found in path %s: asking the client",
1202 fname.Data(), TROOT::GetMacroPath());
1203 TMessage m(kMESS_ANY);
1204 m << (Int_t) kRRT_SendFile << TString(gSystem->BaseName(fname));
1209 Bool_t filefollows = kTRUE;
1211 while (filefollows) {
1215 if (fSocket->Recv(rm) <= 0) {
1216 Error(
"ProcessLine",
"ask-file: received empty message from client");
1219 if (rm->What() != kMESS_ANY) {
1220 Error(
"ProcessLine",
"ask-file: wrong message received (what: %d)", rm->What());
1224 if (type != kRRT_SendFile) {
1225 Error(
"ProcessLine",
"ask-file: wrong sub-type received (type: %d)", type);
1228 (*rm) >> filefollows;
1231 if (fSocket->Recv(rm) <= 0) {
1232 Error(
"ProcessLine",
"file: received empty message from client");
1235 if (rm->What() != kMESS_ANY) {
1236 Error(
"ProcessLine",
"file: wrong message received (what: %d)", rm->What());
1240 if (type != kRRT_File) {
1241 Error(
"ProcessLine",
"file: wrong sub-type received (type: %d)", type);
1246 rm->ReadString(str,
sizeof(str));
1247 char name[2048], i1[20], i2[40];
1248 sscanf(str,
"%2047s %19s %39s", name, i1, i2);
1249 Int_t bin = atoi(i1);
1250 Long_t size = atol(i2);
1251 ReceiveFile(name, bin ? kTRUE : kFALSE, size);
1259 return TApplication::ProcessLine(line);
1271 void TApplicationServer::ExecLogon()
1273 if (NoLogOpt())
return;
1275 TString name =
".rootlogon.C";
1276 TString sname =
"system";
1278 char *s = gSystem->ConcatFileName(TROOT::GetEtcDir(), sname);
1279 if (!gSystem->AccessPathName(s, kReadPermission)) {
1283 s = gSystem->ConcatFileName(gSystem->HomeDirectory(), name);
1284 if (!gSystem->AccessPathName(s, kReadPermission)) {
1289 if (strcmp(gSystem->HomeDirectory(), gSystem->WorkingDirectory())) {
1290 if (!gSystem->AccessPathName(name, kReadPermission))
1295 const char *logon = gEnv->GetValue(
"Rint.Logon", (
char*)0);
1297 char *mac = gSystem->Which(TROOT::GetMacroPath(), logon, kReadPermission);