Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TApplicationRemote.cxx
Go to the documentation of this file.
1// @(#)root/net:$Id$
2// Author: G. Ganis 10/5/2007
3
4/*************************************************************************
5 * Copyright (C) 1995-2007, 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// TApplicationRemote //
15// //
16// TApplicationRemote maps a remote session. It starts a remote session //
17// and takes care of redirecting the commands to be processed to the //
18// remote session, to collect the graphic output objects and to display //
19// them locally. //
20// //
21//////////////////////////////////////////////////////////////////////////
22
23#include <errno.h>
24#include <random>
25
26#include "TApplicationRemote.h"
27
28#include "TBrowser.h"
29#include "TDirectory.h"
30#include "TError.h"
31#include "THashList.h"
32#include "TMonitor.h"
33#include "TROOT.h"
34#include "TServerSocket.h"
35#include "TSystem.h"
36#include "TRemoteObject.h"
37#include "snprintf.h"
38#ifdef WIN32
39#include <io.h>
40#include <sys/types.h>
41#endif
42
43//
44// TApplicationRemote Interrupt signal handler
45////////////////////////////////////////////////////////////////////////////////
46/// TApplicationRemote interrupt handler.
47
49{
50 Info("Notify","Processing interrupt signal ...");
51
52 // Handle interrupt condition on socket(s)
54
55 return kTRUE;
56}
57
58
60
61static const char *gScript = "roots";
62static const char *gScriptCmd = "\\\"%s %d localhost:%d/%s -d=%d\\\"";
63#ifndef WIN32
64static const char *gSshCmd = "ssh %s -f4 %s -R %d:localhost:%d sh -c \
65 \"'(sh=\\`basename \'\\\\\\$SHELL\'\\`; \
66 if test xbash = x\'\\\\\\$sh\' -o xsh = x\'\\\\\\$sh\' -o xzsh = x\'\\\\\\$sh\' -o xdash = x\'\\\\\\$sh\'; then \
67 \'\\\\\\$SHELL\' -l -c %s; \
68 elif test xcsh = x\'\\\\\\$sh\' -o xtcsh = x\'\\\\\\$sh\' -o xksh = x\'\\\\\\$sh\'; then \
69 \'\\\\\\$SHELL\' -c %s; \
70 else \
71 echo \\\"Unknown shell \'\\\\\\$SHELL\'\\\"; \
72 fi)'\"";
73#else
74static const char *gSshCmd = "ssh %s -f4 %s -R %d:localhost:%d sh -c \
75 \"'(sh=`basename $SHELL`; \
76 if test xbash = x$sh -o xsh = x$sh -o xzsh = x$sh -o xdash = x$sh; then \
77 $SHELL -l -c %s; \
78 elif test xcsh = x$sh -o xtcsh = x$sh -o xksh = x$sh; then \
79 $SHELL -c %s; \
80 else \
81 echo \"Unknown shell $SHELL\"; \
82 fi)'\"";
83#endif
84
85Int_t TApplicationRemote::fgPortAttempts = 100; // number of attempts to find a port
86Int_t TApplicationRemote::fgPortLower = 49152; // lower bound for ports
87Int_t TApplicationRemote::fgPortUpper = 65535; // upper bound for ports
88
89////////////////////////////////////////////////////////////////////////////////
90/// Main constructor: start a remote session at 'url' accepting callbacks
91/// on local port 'port'; if port is already in use scan up to 'scan - 1'
92/// ports starting from port + 1, i.e. port + 1, ... , port + scan - 1
93
95 const char *script)
97{
98 // Unique name (used also in the prompt)
99 fName = fUrl.GetHost();
100 if (strlen(fUrl.GetOptions()) > 0)
101 fName += Form("-%s", fUrl.GetOptions());
103 TString user = (pw) ? (const char*) pw->fUser : "";
104 SafeDelete(pw);
105 if (strlen(fUrl.GetUser()) > 0 && user != fUrl.GetUser())
106 fName.Insert(0,Form("%s@", fUrl.GetUser()));
107
108 fIntHandler = 0;
109 fSocket = 0;
110 fMonitor = 0;
111 fFileList = 0;
112 fWorkingDir = 0;
113 fRootFiles = 0;
114 fReceivedObject = 0;
116
117 // Create server socket; generate randomly a port to find a free one
118 Int_t port = -1;
120 Long64_t now = gSystem->Now();
121 std::default_random_engine randomEngine(now);
122 std::uniform_int_distribution<Int_t> randomPort(fgPortLower, fgPortUpper);
123 TServerSocket *ss = 0;
124 while (na--) {
125 port = randomPort(randomEngine);
126 ss = new TServerSocket(port);
127 if (ss->IsValid())
128 break;
129 }
130 if (!ss || !ss->IsValid()) {
131 Error("TApplicationRemote","unable to find a free port for connections");
133 return;
134 }
135
136 // Create a monitor and add the socket to it
137 TMonitor *mon = new TMonitor;
138 mon->Add(ss);
139
140 // Start the remote server
141 Int_t rport = (port < fgPortUpper) ? port + 1 : port - 1;
143 if (script && *script) {
144 // script is enclosed by " ", so ignore first " char
145 if (script[1] == '<') {
146 if (script[2])
147 sc.Form("source %s; %s", script+2, gScript);
148 else
149 Error("TApplicationRemote", "illegal script name <");
150 } else
151 sc = script;
152 }
153 sc.ReplaceAll("\"","");
155 if (strlen(fUrl.GetUser()) > 0)
156 userhost.Insert(0, Form("%s@", fUrl.GetUser()));
157 const char *verb = "";
158 if (debug > 0)
159 verb = "-v";
162 TString cmd;
163 cmd.Form(gSshCmd, verb, userhost.Data(), rport, port, scriptCmd.Data(), scriptCmd.Data());
164#ifdef WIN32
165 // make sure that the Gpad and GUI libs are loaded
168#endif
169 if (gDebug > 0)
170 Info("TApplicationRemote", "executing: %s", cmd.Data());
171 if (gSystem->Exec(cmd) != 0) {
172 Info("TApplicationRemote", "an error occured during SSH connection");
173 mon->DeActivateAll();
174 delete mon;
175 delete ss;
178 return;
179 }
180
181 // Wait for activity on the socket
182 mon->Select();
183
184 // Get the connection
185 if (!(fSocket = ss->Accept())) {
186 Error("TApplicationRemote", "failed to open connection");
188 return;
189 }
190
191 // Cleanup the monitor and the server socket
192 mon->DeActivateAll();
193 delete mon;
194 delete ss;
195
196 // Receive the startup message
197 Int_t what;
198 char buf[512];
199 if (fSocket->Recv(buf, sizeof(buf), what) <= 0) {
200 Error("TApplicationRemote", "failed to receive startup message");
203 return;
204 }
205 Printf("%s", buf);
206
207 // Receive the protocol version run remotely
208 if (fSocket->Recv(fProtocol, what) != 2*sizeof(Int_t)) {
209 Error("TApplicationRemote", "failed to receive remote server protocol");
212 return;
213 }
215 Info("TApplicationRemote","server runs a different protocol version: %d (vs %d)",
217
218 TMessage *msg = 0;
219 // Receive the protocol version run remotely
220 if (fSocket->Recv(msg) < 0 || msg->What() != kMESS_ANY) {
221 Error("TApplicationRemote", "failed to receive server info - protocol error");
224 return;
225 }
226
227 // Real host name and full path to remote log
229 (*msg) >> hostname >> fLogFilePath;
231
232 // Monitor the socket
233 fMonitor = new TMonitor;
235
236 // Set interrupt handler from now on
238
239 // To get the right cleaning sequence
240 gROOT->GetListOfSockets()->Remove(fSocket);
241 gROOT->GetListOfSockets()->Add(this);
242
243 fRootFiles = new TList;
244 fRootFiles->SetName("Files");
245
246 // Collect startup notifications
247 Collect();
248
249 // Done
250 return;
251}
252
253////////////////////////////////////////////////////////////////////////////////
254/// Destructor
255
257{
258 gROOT->GetListOfSockets()->Remove(this);
259 Terminate(0);
260}
261
262////////////////////////////////////////////////////////////////////////////////
263/// Broadcast a message to the remote session.
264/// Returns 0 on success, -1 in case of error.
265
267{
268 if (!IsValid()) return -1;
269
270 if (fSocket->Send(mess) == -1) {
271 Error("Broadcast", "could not send message");
272 return -1;
273 }
274 // Done
275 return 0;
276}
277
278////////////////////////////////////////////////////////////////////////////////
279/// Broadcast a character string buffer to the remote session.
280/// Use kind to set the TMessage what field.
281/// Returns 0 on success, -1 in case of error.
282
284{
285 TMessage mess(kind);
286 if (kind == kMESS_ANY)
287 mess << type;
288 if (str) mess.WriteString(str);
289 return Broadcast(mess);
290}
291
292////////////////////////////////////////////////////////////////////////////////
293/// Broadcast an object to the remote session.
294/// Use kind to set the TMessage what field.
295/// Returns 0 on success, -1 in case of error.
296
298{
299 TMessage mess(kind);
300 mess.WriteObject(obj);
301 return Broadcast(mess);
302}
303
304////////////////////////////////////////////////////////////////////////////////
305/// Broadcast a raw buffer of specified length to the remote session.
306/// Returns 0 on success, -1 in case of error.
307
309{
310 if (!IsValid()) return -1;
311
312 if (fSocket->SendRaw(buffer, length) == -1) {
313 Error("Broadcast", "could not send raw buffer");
314 return -1;
315 }
316 // Done
317 return 0;
318}
319
320////////////////////////////////////////////////////////////////////////////////
321/// Collect responses from the remote server.
322/// Returns the number of messages received.
323/// If timeout >= 0, wait at most timeout seconds (timeout = -1 by default,
324/// which means wait forever).
325
327{
328 // Activate monitoring
330 if (!fMonitor->GetActive())
331 return 0;
332
333 // Timeout counter
335 if (gDebug > 2)
336 Info("Collect","active: %d", fMonitor->GetActive());
337
338 // On clients, handle Ctrl-C during collection
339 if (fIntHandler)
340 fIntHandler->Add();
341
342 // We are now going to collect from the server
344
345 Int_t rc = 0, cnt = 0;
346 while (fMonitor->GetActive() && (nto < 0 || nto > 0)) {
347
348 // Wait for a ready socket
349 TSocket *s = fMonitor->Select(1000);
350
351 if (s && s != (TSocket *)(-1)) {
352 // Get and analyse the info it did receive
353 if ((rc = CollectInput()) != 0) {
354 // Deactivate it if we are done with it
356 if (gDebug > 2)
357 Info("Collect","deactivating %p", s);
358 }
359
360 // Update counter (if no error occured)
361 if (rc >= 0)
362 cnt++;
363
364 } else {
365 // If not timed-out, exit if not stopped or not aborted
366 // (player exits status is finished in such a case); otherwise,
367 // we still need to collect the partial output info
368 if (!s)
370 // Decrease the timeout counter if requested
371 if (s == (TSocket *)(-1) && nto > 0)
372 nto--;
373 }
374 }
375
376 // Collection is over
378
379 // If timed-out, deactivate everything
380 if (nto == 0)
382
383 // Deactivate Ctrl-C special handler
384 if (fIntHandler)
386
387 return cnt;
388}
389
390////////////////////////////////////////////////////////////////////////////////
391/// Collect and analyze available input from the socket.
392/// Returns 0 on success, -1 if any failure occurs.
393
395{
396 TMessage *mess;
397 Int_t rc = 0;
398
399 char str[512];
400 TObject *obj;
401 Int_t what;
403
404 if (fSocket->Recv(mess) < 0) {
407 return -1;
408 }
409 if (!mess) {
410 // we get here in case the remote server died
413 return -1;
414 }
415
416 what = mess->What();
417
418 if (gDebug > 2)
419 Info("CollectInput","what %d", what);
420
421 switch (what) {
422
423 case kMESS_OBJECT:
424 { // The server sent over an object: read it in memory
425 TObject *o = mess->ReadObject(mess->GetClass());
426 // If a canvas, draw it
427 if (TString(o->ClassName()) == "TCanvas")
428 o->Draw();
429 else if (TString(o->ClassName()) == "TRemoteObject") {
431 if (TString(robj->GetClassName()) == "TSystemDirectory") {
432 if (fWorkingDir == 0) {
434 }
435 }
436 }
437 else if (TString(o->ClassName()) == "TList") {
438 TList *list = (TList *)o;
439 TRemoteObject *robj = (TRemoteObject *)list->First();
440 if (robj && (TString(robj->GetClassName()) == "TFile")) {
441 TIter next(list);
442 while ((robj = (TRemoteObject *)next())) {
443 if (!fRootFiles->FindObject(robj->GetName()))
445 }
446 gROOT->RefreshBrowsers();
447 }
448 }
449 fReceivedObject = o;
450 }
451 break;
452
453 case kMESS_ANY:
454 // Generic message: read out the type
455 { Int_t type;
456 (*mess) >> type;
457
458 if (gDebug > 2)
459 Info("CollectInput","type %d", type);
460
461 switch (type) {
462
463 case kRRT_GetObject:
464 // send server the object it asks for
465 mess->ReadString(str, sizeof(str));
466 obj = gDirectory->Get(str);
467 if (obj) {
468 fSocket->SendObject(obj);
469 } else {
470 Warning("CollectInput",
471 "server requested an object that we do not have");
473 }
474 break;
475
476 case kRRT_Fatal:
477 // Fatal error
479 rc = -1;
480 break;
481
482 case kRRT_LogFile:
483 { Int_t size;
484 (*mess) >> size;
486 }
487 break;
488
489 case kRRT_LogDone:
490 { Int_t st;
491 (*mess) >> st;
492 if (st < 0) {
493 // Problem: object should not be used
495 }
496 if (gDebug > 1)
497 Info("CollectInput","kRTT_LogDone: status %d", st);
498 rc = 1;
499 }
500 break;
501
502 case kRRT_Message:
503 { TString msg;
505 (*mess) >> msg >> lfeed;
506 if (lfeed)
507 fprintf(stderr,"%s\n", msg.Data());
508 else
509 fprintf(stderr,"%s\r", msg.Data());
510 }
511 break;
512
513 case kRRT_SendFile:
514 { TString fname;
515 (*mess) >> fname;
516 // Prepare the reply
518 m << (Int_t) kRRT_SendFile;
519 // The server needs a file: we send also the related header
520 // if we have it.
522 if (!imp) {
523 Error("CollectInput", "file %s not found in path(s) %s",
524 fname.Data(), TROOT::GetMacroPath());
525 m << (Bool_t) kFALSE;
526 Broadcast(m);
527 } else {
529 delete [] imp;
530 Int_t dot = impfile.Last('.');
531
532 // Is there any associated header file
535 if (dot != kNPOS)
536 headfile.Remove(dot);
537 headfile += ".h";
540 headfile.Remove(dot);
541 headfile += ".hh";
544 if (gDebug > 0)
545 Info("CollectInput", "no associated header file"
546 " found: tried: %s %s",
547 h.Data(), headfile.Data());
548 }
549 }
550
551 // Send files now;
552 m << (Bool_t) kTRUE;
553 Broadcast(m);
554 if (SendFile(impfile, kForce) == -1) {
555 Info("CollectInput", "problems sending file %s", impfile.Data());
556 return 0;
557 }
558 if (hasHeader) {
559 Broadcast(m);
560 if (SendFile(headfile, kForce) == -1) {
561 Info("CollectInput", "problems sending file %s", headfile.Data());
562 return 0;
563 }
564 }
565 }
566 // End of transmission
567 m.Reset(kMESS_ANY);
568 m << (Int_t) kRRT_SendFile;
569 m << (Bool_t) kFALSE;
570 Broadcast(m);
571 }
572 break;
573
574 default:
575 Warning("CollectInput","unknown type received from server: %d", type);
576 break;
577
578 }
579 }
580 break;
581
582 default:
583 Error("CollectInput", "unknown command received from server: %d", what);
586 rc = -1;
587 break;
588 }
589
590 // Cleanup
591 if (delete_mess)
592 delete mess;
593
594 // We are done successfully
595 return rc;
596}
597
598
599////////////////////////////////////////////////////////////////////////////////
600/// Receive the log file from the server
601
603{
604 const Int_t kMAXBUF = 16384; //32768 //16384 //65536;
605 char buf[kMAXBUF];
606
607 // Append messages to active logging unit
609 if (fdout < 0) {
610 Warning("RecvLogFile", "file descriptor for outputs undefined (%d):"
611 " will not log msgs", fdout);
612 return;
613 }
614 lseek(fdout, (off_t) 0, SEEK_END);
615
616 Int_t left, rec, r;
617 Long_t filesize = 0;
618
619 while (filesize < size) {
620 left = Int_t(size - filesize);
621 if (left > kMAXBUF)
622 left = kMAXBUF;
623 rec = fSocket->RecvRaw(&buf, left);
624 filesize = (rec > 0) ? (filesize + rec) : filesize;
625 if (rec > 0) {
626
627 char *p = buf;
628 r = rec;
629 while (r) {
630 Int_t w;
631
632 w = write(fdout, p, r);
633
634 if (w < 0) {
635 SysError("RecvLogFile", "error writing to unit: %d", fdout);
636 break;
637 }
638 r -= w;
639 p += w;
640 }
641 } else if (rec < 0) {
642 Error("RecvLogFile", "error during receiving log file");
643 break;
644 }
645 }
646}
647
648////////////////////////////////////////////////////////////////////////////////
649/// Send object to server.
650/// Return 0 on success, -1 in case of error.
651
653{
654 if (!IsValid() || !obj) return -1;
655
657 mess.WriteObject(obj);
658 return Broadcast(mess);
659}
660
661////////////////////////////////////////////////////////////////////////////////
662/// Check if a file needs to be send to the server. Use the following
663/// algorithm:
664/// - check if file appears in file map
665/// - if yes, get file's modtime and check against time in map,
666/// if modtime not same get md5 and compare against md5 in map,
667/// if not same return kTRUE.
668/// - if no, get file's md5 and modtime and store in file map, ask
669/// slave if file exists with specific md5, if yes return kFALSE,
670/// if no return kTRUE.
671/// Returns kTRUE in case file needs to be send, returns kFALSE in case
672/// file is already on remote node.
673
675{
677
678 if (!IsValid()) return -1;
679
680 // The filename for the cache
681 TString fn = gSystem->BaseName(file);
682
683 // Check if the file is already in the cache
684 TARFileStat *fs = 0;
685 if (fFileList && (fs = (TARFileStat *) fFileList->FindObject(fn))) {
686 // File in cache
687 if (fs->fModtime != modtime) {
688 TMD5 *md5 = TMD5::FileChecksum(file);
689 if (md5) {
690 if ((*md5) != fs->fMD5) {
691 sendto = kTRUE;
692 fs->fMD5 = *md5;
693 fs->fModtime = modtime;
694 }
695 delete md5;
696 } else {
697 Error("CheckFile", "could not calculate local MD5 check sum - dont send");
698 return kFALSE;
699 }
700 }
701 } else {
702 // file not in the cache
703 TMD5 *md5 = TMD5::FileChecksum(file);
704 if (md5) {
705 fs = new TARFileStat(fn, md5, modtime);
706 if (!fFileList)
707 fFileList = new THashList;
708 fFileList->Add(fs);
709 delete md5;
710 } else {
711 Error("CheckFile", "could not calculate local MD5 check sum - dont send");
712 return kFALSE;
713 }
715 mess << Int_t(kRRT_CheckFile) << TString(gSystem->BaseName(file)) << fs->fMD5;
716 fSocket->Send(mess);
717
720 if (reply) {
721 if (reply->What() == kMESS_ANY) {
722 // Check the type
723 Int_t type;
725 (*reply) >> type >> uptodate;
726 if (type != kRRT_CheckFile) {
727 // Protocol error
728 Warning("CheckFile", "received wrong type:"
729 " %d (expected %d): protocol error?",
731 }
733 } else {
734 // Protocol error
735 Error("CheckFile", "received wrong message: %d (expected %d)",
736 reply->What(), kMESS_ANY);
737 }
738 } else {
739 Error("CheckFile", "received empty message");
740 }
741 // Collect logs
742 Collect();
743 }
744
745 // Done
746 return sendto;
747}
748
749////////////////////////////////////////////////////////////////////////////////
750/// Send a file to the server. Return 0 on success, -1 in case of error.
751/// If defined, the full path of the remote path will be rfile.
752/// The mask 'opt' is an or of ESendFileOpt:
753///
754/// kAscii (0x0) if set true ascii file transfer is used
755/// kBinary (0x1) if set true binary file transfer is used
756/// kForce (0x2) if not set an attempt is done to find out
757/// whether the file really needs to be downloaded
758/// (a valid copy may already exist in the cache
759/// from a previous run)
760///
761
762Int_t TApplicationRemote::SendFile(const char *file, Int_t opt, const char *rfile)
763{
764 if (!IsValid()) return -1;
765
766#ifndef R__WIN32
767 Int_t fd = open(file, O_RDONLY);
768#else
769 Int_t fd = open(file, O_RDONLY | O_BINARY);
770#endif
771 if (fd < 0) {
772 SysError("SendFile", "cannot open file %s", file);
773 return -1;
774 }
775
776 // Get info about the file
778 Long_t id, flags, modtime;
779 if (gSystem->GetPathInfo(file, &id, &size, &flags, &modtime) == 1) {
780 Error("SendFile", "cannot stat file %s", file);
781 close(fd);
782 return -1;
783 }
784 if (size == 0) {
785 Error("SendFile", "empty file %s", file);
786 close(fd);
787 return -1;
788 }
789
790 // Decode options
791 Bool_t bin = (opt & kBinary) ? kTRUE : kFALSE;
792 Bool_t force = (opt & kForce) ? kTRUE : kFALSE;
793
794 const Int_t kMAXBUF = 32768; //16384 //65536;
795 char buf[kMAXBUF];
796
797 const char *fnam = (rfile) ? rfile : gSystem->BaseName(file);
798
799 Bool_t sendto = force ? kTRUE : CheckFile(file, modtime);
800
801 // The value of 'size' is used as flag remotely, so we need to
802 // reset it to 0 if we are not going to send the file
803 size = sendto ? size : 0;
804
805 if (gDebug > 1 && size > 0)
806 Info("SendFile", "sending file %s", file);
807
808 snprintf(buf, kMAXBUF, "%s %d %lld", fnam, bin, size);
809 if (Broadcast(buf, kMESS_ANY, kRRT_File) == -1) {
811 close(fd);
812 return -1;
813 }
814
815 if (sendto) {
816
817 lseek(fd, 0, SEEK_SET);
818
819 Int_t len;
820 do {
821 while ((len = read(fd, buf, kMAXBUF)) < 0 && TSystem::GetErrno() == EINTR)
823
824 if (len < 0) {
825 SysError("SendFile", "error reading from file %s", file);
826 Interrupt();
827 close(fd);
828 return -1;
829 }
830
831 if (len > 0 && fSocket->SendRaw(buf, len) == -1) {
832 SysError("SendFile", "error writing to server @ %s:%d (now offline)",
833 fUrl.GetHost(), fUrl.GetPort());
835 break;
836 }
837
838 } while (len > 0);
839 }
840 close(fd);
841
842 // Get the log (during collection this will be done at the end
843 if (!TestBit(kCollecting))
844 Collect();
845
846 // Done
847 return IsValid() ? 0 : -1;
848}
849
850////////////////////////////////////////////////////////////////////////////////
851/// Terminate this session
852
863
864////////////////////////////////////////////////////////////////////////////////
865/// Set port parameters for tunnelling. A value of -1 means unchanged
866
868{
869 if (lower > -1)
871 if (upper > -1)
873 if (attempts > -1)
875
876 ::Info("TApplicationRemote::SetPortParam","port scan: %d attempts in [%d,%d]",
878}
879
880////////////////////////////////////////////////////////////////////////////////
881/// Parse a single command line and forward the request to the remote server
882/// where it will be processed. The line is either a C++ statement or an
883/// interpreter command starting with a ".".
884/// Return the return value of the command casted to a long.
885
887{
888 if (!line || !*line) return 0;
889
890 if (!strncasecmp(line, ".q", 2)) {
891 // terminate the session
892 gApplication->ProcessLine(".R -close");
893 return 0;
894 }
895
896 if (!strncmp(line, "?", 1)) {
897 Help(line);
898 return 1;
899 }
900
901 fReceivedObject = 0;
902
903 // Init graphics
905
906 // Ok, now we pack the command and we send it over for processing
908
909 // And collect the results
910 Collect();
911
912 // Done
914 return 1;
915}
916
917////////////////////////////////////////////////////////////////////////////////
918/// Print some info about this instance
919
921{
922 TString s(Form("OBJ: TApplicationRemote %s", fName.Data()));
923 Printf("%s", s.Data());
924 if (opt && opt[0] == 'F') {
925 s = " url: ";
926 if (strlen(fUrl.GetUser()) > 0)
927 s += Form("%s@", fUrl.GetUser());
928 s += fUrl.GetHostFQDN();
929 s += Form(" logfile: %s", fLogFilePath.Data());
930 Printf("%s", s.Data());
931 }
932}
933////////////////////////////////////////////////////////////////////////////////
934/// Send interrupt OOB byte to server.
935/// Returns 0 if ok, -1 in case of error
936
938{
939 if (!IsValid()) return;
940
942
943#if 1
944 Info("Interrupt", "*** Ctrl-C not yet enabled *** (type= %d)", type);
945 return;
946#else
947
948 char oobc = (char) type;
949 const int kBufSize = 1024;
950 char waste[kBufSize];
951
952 // Send one byte out-of-band message to server
953 if (fSocket->SendRaw(&oobc, 1, kOob) <= 0) {
954 Error("Interrupt", "error sending oobc to server");
955 return;
956 }
957
958 if (type == kRRI_Hard) {
959 char oob_byte;
960 int n, nch, nbytes = 0, nloop = 0;
961
962 // Receive the OOB byte
963 while ((n = fSocket->RecvRaw(&oob_byte, 1, kOob)) < 0) {
964 if (n == -2) { // EWOULDBLOCK
965 //
966 // The OOB data has not yet arrived: flush the input stream
967 //
968 // In some systems (Solaris) regular recv() does not return upon
969 // receipt of the oob byte, which makes the below call to recv()
970 // block indefinitely if there are no other data in the queue.
971 // FIONREAD ioctl can be used to check if there are actually any
972 // data to be flushed. If not, wait for a while for the oob byte
973 // to arrive and try to read it again.
974 //
976 if (nch == 0) {
977 gSystem->Sleep(1000);
978 continue;
979 }
980
981 if (nch > kBufSize) nch = kBufSize;
983 if (n <= 0) {
984 Error("Interrupt", "error receiving waste from server");
985 break;
986 }
987 nbytes += n;
988 } else if (n == -3) { // EINVAL
989 //
990 // The OOB data has not arrived yet
991 //
992 gSystem->Sleep(100);
993 if (++nloop > 100) { // 10 seconds time-out
994 Error("Interrupt", "server does not respond");
995 break;
996 }
997 } else {
998 Error("Interrupt", "error receiving OOB from server");
999 break;
1000 }
1001 }
1002
1003 //
1004 // Continue flushing the input socket stream until the OOB
1005 // mark is reached
1006 //
1007 while (1) {
1008 int atmark;
1009
1011
1012 if (atmark)
1013 break;
1014
1015 // find out number of bytes to read before atmark
1017 if (nch == 0) {
1018 gSystem->Sleep(1000);
1019 continue;
1020 }
1021
1022 if (nch > kBufSize) nch = kBufSize;
1023 n = fSocket->RecvRaw(waste, nch);
1024 if (n <= 0) {
1025 Error("Interrupt", "error receiving waste (2) from server");
1026 break;
1027 }
1028 nbytes += n;
1029 }
1030 if (nbytes > 0)
1031 Info("Interrupt", "server synchronized: %d bytes discarded", nbytes);
1032
1033 // Get log file from server after a hard interrupt
1034 Collect();
1035
1036 } else if (type == kRRI_Soft) {
1037
1038 // Get log file from server after a soft interrupt
1039 Collect();
1040
1041 } else if (type == kRRI_Shutdown) {
1042
1043 ; // nothing expected to be returned
1044
1045 } else {
1046
1047 // Unexpected message, just receive log file
1048 Collect();
1049 }
1050#endif
1051}
1052
1053////////////////////////////////////////////////////////////////////////////////
1054/// Browse remote application (working directory and ROOT files).
1055
1057{
1058 b->Add(fRootFiles, "ROOT Files");
1060 gROOT->RefreshBrowsers();
1061}
@ kMESS_ANY
@ kMESS_NOTOK
@ kMESS_OBJECT
@ kMESS_CINT
#define SafeDelete(p)
Definition RConfig.hxx:538
const Int_t kRRemote_Protocol
@ kRRT_Terminate
@ kRRT_LogFile
@ kRRT_CheckFile
@ kRRT_GetObject
@ kRRT_File
@ kRRT_LogDone
@ kRRT_Message
@ kRRT_SendFile
@ kRRT_Fatal
@ kRRI_Shutdown
@ kRRI_Soft
@ kRRI_Hard
#define b(i)
Definition RSha256.hxx:100
#define h(i)
Definition RSha256.hxx:106
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
bool Bool_t
Definition RtypesCore.h:63
int Int_t
Definition RtypesCore.h:45
long Longptr_t
Definition RtypesCore.h:75
long Long_t
Definition RtypesCore.h:54
constexpr Bool_t kFALSE
Definition RtypesCore.h:94
constexpr Ssiz_t kNPOS
Definition RtypesCore.h:117
constexpr Bool_t kTRUE
Definition RtypesCore.h:93
const char Option_t
Definition RtypesCore.h:66
#define ClassImp(name)
Definition Rtypes.h:374
static const char * gSshCmd
static const char * gScript
static const char * gScriptCmd
R__EXTERN TApplication * gApplication
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define gDirectory
Definition TDirectory.h:384
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h length
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize id
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize fs
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
TUrl fUrl
Definition TProof.h:250
Int_t gDebug
Definition TROOT.cxx:622
#define gROOT
Definition TROOT.h:414
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2489
void Printf(const char *fmt,...)
Formats a string in a circular formatting buffer and prints the string.
Definition TString.cxx:2503
@ kBytesToRead
Definition TSystem.h:239
@ kAtMark
Definition TSystem.h:238
@ kOob
Definition TSystem.h:244
@ kReadPermission
Definition TSystem.h:55
R__EXTERN TSystem * gSystem
Definition TSystem.h:572
#define O_BINARY
Definition civetweb.c:912
#define snprintf
Definition civetweb.c:1540
TApplicationRemote * fApplicationRemote
Bool_t Notify() override
TApplicationRemote interrupt handler.
Int_t CollectInput()
Collect and analyze available input from the socket.
TApplicationRemote(const char *url, Int_t debug=0, const char *script=nullptr)
Main constructor: start a remote session at 'url' accepting callbacks on local port 'port'; if port i...
virtual ~TApplicationRemote()
Destructor.
void Terminate(Int_t status=0) override
Terminate this session.
Int_t BroadcastRaw(const void *buffer, Int_t length)
Broadcast a raw buffer of specified length to the remote session.
Bool_t CheckFile(const char *file, Long_t modtime)
Check if a file needs to be send to the server.
static void SetPortParam(Int_t lower=-1, Int_t upper=-1, Int_t attempts=-1)
Set port parameters for tunnelling. A value of -1 means unchanged.
TRemoteObject * fWorkingDir
void Print(Option_t *option="") const override
Print some info about this instance.
void Browse(TBrowser *b) override
Browse remote application (working directory and ROOT files).
void Interrupt(Int_t type=kRRI_Hard)
Send interrupt OOB byte to server.
Int_t SendFile(const char *file, Int_t opt=kAscii, const char *rfile=nullptr)
Send a file to the server.
void RecvLogFile(Int_t size)
Receive the log file from the server.
TSeqCollection * fRootFiles
Longptr_t ProcessLine(const char *line, Bool_t=kFALSE, Int_t *error=nullptr) override
Parse a single command line and forward the request to the remote server where it will be processed.
Int_t BroadcastObject(const TObject *obj, Int_t kind=kMESS_OBJECT)
Broadcast an object to the remote session.
Int_t SendObject(const TObject *obj)
Send object to server.
Int_t Collect(Long_t timeout=-1)
Collect responses from the remote server.
static Int_t fgPortAttempts
TSignalHandler * fIntHandler
Int_t Broadcast(const TMessage &mess)
Broadcast a message to the remote session.
This class creates the ROOT Application Environment that interfaces to the windowing system eventloop...
virtual Longptr_t ProcessLine(const char *line, Bool_t sync=kFALSE, Int_t *error=nullptr)
Process a single command line, either a C++ statement or an interpreter command starting with a "....
virtual void Help(const char *line)
The function lists useful commands (".help") or opens the online reference guide, generated with Doxy...
void InitializeGraphics(Bool_t only_web=kFALSE)
Initialize the graphics environment.
static void NeedGraphicsLibs()
Static method.
Using a TBrowser one can browse all ROOT objects.
Definition TBrowser.h:37
void SetName(const char *name)
TObject * FindObject(const char *name) const override
Find an object in this collection using its name.
THashList implements a hybrid collection class consisting of a hash table and a list to store TObject...
Definition THashList.h:34
TObject * FindObject(const char *name) const override
Find object using its name.
A doubly linked list.
Definition TList.h:38
void Add(TObject *obj) override
Definition TList.h:81
This code implements the MD5 message-digest algorithm.
Definition TMD5.h:44
static TMD5 * FileChecksum(const char *file)
Returns checksum of specified file.
Definition TMD5.cxx:474
virtual void ActivateAll()
Activate all de-activated sockets.
Definition TMonitor.cxx:268
TSocket * Select()
Return pointer to socket for which an event is waiting.
Definition TMonitor.cxx:322
virtual void Add(TSocket *sock, Int_t interest=kRead)
Add socket to the monitor's active list.
Definition TMonitor.cxx:168
Int_t GetActive(Long_t timeout=-1) const
Return number of sockets in the active list.
Definition TMonitor.cxx:438
virtual void DeActivateAll()
De-activate all activated sockets.
Definition TMonitor.cxx:302
virtual void DeActivate(TSocket *sock)
De-activate a socket.
Definition TMonitor.cxx:284
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:50
Mother of all ROOT objects.
Definition TObject.h:41
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:205
virtual void SysError(const char *method, const char *msgfmt,...) const
Issue system error message.
Definition TObject.cxx:1085
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:226
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1057
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:864
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1071
virtual void Draw(Option_t *option="")
Default Draw method for all objects.
Definition TObject.cxx:293
void ResetBit(UInt_t f)
Definition TObject.h:204
@ kInvalidObject
if object ctor succeeded but object should not be used
Definition TObject.h:78
static const char * GetMacroPath()
Get macro search path. Static utility function.
Definition TROOT.cxx:2790
The TRemoteObject class provides protocol for browsing ROOT objects from a remote ROOT session.
void Add(TObject *obj) override
This class implements server sockets.
void Add() override
Add signal handler to system signal handler list.
void Remove() override
Remove signal handler from system signal handler list.
This class implements client sockets.
Definition TSocket.h:41
virtual Int_t Recv(TMessage *&mess)
Receive a TMessage object.
Definition TSocket.cxx:820
virtual Int_t RecvRaw(void *buffer, Int_t length, ESendRecvOptions opt=kDefault)
Receive a raw buffer of specified length bytes.
Definition TSocket.cxx:905
virtual Int_t SendRaw(const void *buffer, Int_t length, ESendRecvOptions opt=kDefault)
Send a raw buffer of specified length.
Definition TSocket.cxx:622
Option_t * GetOption() const override
Definition TSocket.h:98
virtual Int_t SendObject(const TObject *obj, Int_t kind=kMESS_OBJECT)
Send an object.
Definition TSocket.cxx:602
virtual Int_t Send(const TMessage &mess)
Send a TMessage object.
Definition TSocket.cxx:524
Basic string class.
Definition TString.h:139
TString & Insert(Ssiz_t pos, const char *s)
Definition TString.h:661
const char * Data() const
Definition TString.h:376
static void ResetErrno()
Static function resetting system error number.
Definition TSystem.cxx:284
static Int_t GetErrno()
Static function returning system error number.
Definition TSystem.cxx:276
virtual TTime Now()
Get current time in milliseconds since 0:00 Jan 1 1995.
Definition TSystem.cxx:463
virtual Int_t Exec(const char *shellcmd)
Execute a command.
Definition TSystem.cxx:653
int GetPathInfo(const char *path, Long_t *id, Long_t *size, Long_t *flags, Long_t *modtime)
Get info about a file: id, size, flags, modification time.
Definition TSystem.cxx:1410
virtual Bool_t AccessPathName(const char *path, EAccessMode mode=kFileExists)
Returns FALSE if one can access a file using the specified access mode.
Definition TSystem.cxx:1308
virtual const char * BaseName(const char *pathname)
Base name of a file name. Base name of /user/root is root.
Definition TSystem.cxx:946
virtual Int_t GetEffectiveUid()
Returns the effective user id.
Definition TSystem.cxx:1584
virtual void Sleep(UInt_t milliSec)
Sleep milliSec milli seconds.
Definition TSystem.cxx:437
virtual char * Which(const char *search, const char *file, EAccessMode mode=kFileExists)
Find location of file in a search path.
Definition TSystem.cxx:1560
virtual UserGroup_t * GetUserInfo(Int_t uid)
Returns all user info in the UserGroup_t structure.
Definition TSystem.cxx:1613
const char * GetFile() const
Definition TUrl.h:69
const char * GetUser() const
Definition TUrl.h:65
const char * GetHost() const
Definition TUrl.h:67
const char * GetHostFQDN() const
Return fully qualified domain name of url host.
Definition TUrl.cxx:473
const char * GetOptions() const
Definition TUrl.h:71
void SetHost(const char *host)
Definition TUrl.h:84
Int_t GetPort() const
Definition TUrl.h:78
TLine * line
std::ostream & Info()
Definition hadd.cxx:171
const Int_t n
Definition legend1.C:16
static const char * what
Definition stlLoader.cc:5
TMarker m
Definition textangle.C:8