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 <cerrno>
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
59
60static const char *gScript = "roots";
61static const char *gScriptCmd = "\\\"%s %d localhost:%d/%s -d=%d\\\"";
62#ifndef WIN32
63static const char *gSshCmd = "ssh %s -f4 %s -R %d:localhost:%d sh -c \
64 \"'(sh=\\`basename \'\\\\\\$SHELL\'\\`; \
65 if test xbash = x\'\\\\\\$sh\' -o xsh = x\'\\\\\\$sh\' -o xzsh = x\'\\\\\\$sh\' -o xdash = x\'\\\\\\$sh\'; then \
66 \'\\\\\\$SHELL\' -l -c %s; \
67 elif test xcsh = x\'\\\\\\$sh\' -o xtcsh = x\'\\\\\\$sh\' -o xksh = x\'\\\\\\$sh\'; then \
68 \'\\\\\\$SHELL\' -c %s; \
69 else \
70 echo \\\"Unknown shell \'\\\\\\$SHELL\'\\\"; \
71 fi)'\"";
72#else
73static const char *gSshCmd = "ssh %s -f4 %s -R %d:localhost:%d sh -c \
74 \"'(sh=`basename $SHELL`; \
75 if test xbash = x$sh -o xsh = x$sh -o xzsh = x$sh -o xdash = x$sh; then \
76 $SHELL -l -c %s; \
77 elif test xcsh = x$sh -o xtcsh = x$sh -o xksh = x$sh; then \
78 $SHELL -c %s; \
79 else \
80 echo \"Unknown shell $SHELL\"; \
81 fi)'\"";
82#endif
83
84Int_t TApplicationRemote::fgPortAttempts = 100; // number of attempts to find a port
85Int_t TApplicationRemote::fgPortLower = 49152; // lower bound for ports
86Int_t TApplicationRemote::fgPortUpper = 65535; // upper bound for ports
87
88////////////////////////////////////////////////////////////////////////////////
89/// Main constructor: start a remote session at 'url' accepting callbacks
90/// on local port 'port'; if port is already in use scan up to 'scan - 1'
91/// ports starting from port + 1, i.e. port + 1, ... , port + scan - 1
92
94 const char *script)
95 : TApplication(), fUrl(url)
96{
97 // Unique name (used also in the prompt)
98 fName = fUrl.GetHost();
99 if (strlen(fUrl.GetOptions()) > 0)
100 fName += Form("-%s", fUrl.GetOptions());
102 TString user = (pw) ? (const char*) pw->fUser : "";
103 SafeDelete(pw);
104 if (strlen(fUrl.GetUser()) > 0 && user != fUrl.GetUser())
105 fName.Insert(0,Form("%s@", fUrl.GetUser()));
106
107 fIntHandler = 0;
108 fSocket = 0;
109 fMonitor = 0;
110 fFileList = 0;
111 fWorkingDir = 0;
112 fRootFiles = 0;
113 fReceivedObject = 0;
115
116 // Create server socket; generate randomly a port to find a free one
117 Int_t port = -1;
119 Long64_t now = gSystem->Now();
120 std::default_random_engine randomEngine(now);
121 std::uniform_int_distribution<Int_t> randomPort(fgPortLower, fgPortUpper);
122 TServerSocket *ss = 0;
123 while (na--) {
124 port = randomPort(randomEngine);
125 ss = new TServerSocket(port);
126 if (ss->IsValid())
127 break;
128 }
129 if (!ss || !ss->IsValid()) {
130 Error("TApplicationRemote","unable to find a free port for connections");
132 return;
133 }
134
135 // Create a monitor and add the socket to it
136 TMonitor *mon = new TMonitor;
137 mon->Add(ss);
138
139 // Start the remote server
140 Int_t rport = (port < fgPortUpper) ? port + 1 : port - 1;
142 if (script && *script) {
143 // script is enclosed by " ", so ignore first " char
144 if (script[1] == '<') {
145 if (script[2])
146 sc.Form("source %s; %s", script+2, gScript);
147 else
148 Error("TApplicationRemote", "illegal script name <");
149 } else
150 sc = script;
151 }
152 sc.ReplaceAll("\"","");
154 if (strlen(fUrl.GetUser()) > 0)
155 userhost.Insert(0, Form("%s@", fUrl.GetUser()));
156 const char *verb = "";
157 if (debug > 0)
158 verb = "-v";
161 TString cmd;
162 cmd.Form(gSshCmd, verb, userhost.Data(), rport, port, scriptCmd.Data(), scriptCmd.Data());
163#ifdef WIN32
164 // make sure that the Gpad and GUI libs are loaded
167#endif
168 if (gDebug > 0)
169 Info("TApplicationRemote", "executing: %s", cmd.Data());
170 if (gSystem->Exec(cmd) != 0) {
171 Info("TApplicationRemote", "an error occurred during SSH connection");
172 mon->DeActivateAll();
173 delete mon;
174 delete ss;
177 return;
178 }
179
180 // Wait for activity on the socket
181 mon->Select();
182
183 // Get the connection
184 if (!(fSocket = ss->Accept())) {
185 Error("TApplicationRemote", "failed to open connection");
187 return;
188 }
189
190 // Cleanup the monitor and the server socket
191 mon->DeActivateAll();
192 delete mon;
193 delete ss;
194
195 // Receive the startup message
196 Int_t what;
197 char buf[512];
198 if (fSocket->Recv(buf, sizeof(buf), what) <= 0) {
199 Error("TApplicationRemote", "failed to receive startup message");
202 return;
203 }
204 Printf("%s", buf);
205
206 // Receive the protocol version run remotely
207 if (fSocket->Recv(fProtocol, what) != 2*sizeof(Int_t)) {
208 Error("TApplicationRemote", "failed to receive remote server protocol");
211 return;
212 }
214 Info("TApplicationRemote","server runs a different protocol version: %d (vs %d)",
216
217 TMessage *msg = 0;
218 // Receive the protocol version run remotely
219 if (fSocket->Recv(msg) < 0 || msg->What() != kMESS_ANY) {
220 Error("TApplicationRemote", "failed to receive server info - protocol error");
223 return;
224 }
225
226 // Real host name and full path to remote log
228 (*msg) >> hostname >> fLogFilePath;
230
231 // Monitor the socket
232 fMonitor = new TMonitor;
234
235 // Set interrupt handler from now on
237
238 // To get the right cleaning sequence
239 gROOT->GetListOfSockets()->Remove(fSocket);
240 gROOT->GetListOfSockets()->Add(this);
241
242 fRootFiles = new TList;
243 fRootFiles->SetName("Files");
244
245 // Collect startup notifications
246 Collect();
247
248 // Done
249 return;
250}
251
252////////////////////////////////////////////////////////////////////////////////
253/// Destructor
254
256{
257 gROOT->GetListOfSockets()->Remove(this);
258 Terminate(0);
259}
260
261////////////////////////////////////////////////////////////////////////////////
262/// Broadcast a message to the remote session.
263/// Returns 0 on success, -1 in case of error.
264
266{
267 if (!IsValid()) return -1;
268
269 if (fSocket->Send(mess) == -1) {
270 Error("Broadcast", "could not send message");
271 return -1;
272 }
273 // Done
274 return 0;
275}
276
277////////////////////////////////////////////////////////////////////////////////
278/// Broadcast a character string buffer to the remote session.
279/// Use kind to set the TMessage what field.
280/// Returns 0 on success, -1 in case of error.
281
283{
284 TMessage mess(kind);
285 if (kind == kMESS_ANY)
286 mess << type;
287 if (str) mess.WriteString(str);
288 return Broadcast(mess);
289}
290
291////////////////////////////////////////////////////////////////////////////////
292/// Broadcast an object to the remote session.
293/// Use kind to set the TMessage what field.
294/// Returns 0 on success, -1 in case of error.
295
297{
298 TMessage mess(kind);
299 mess.WriteObject(obj);
300 return Broadcast(mess);
301}
302
303////////////////////////////////////////////////////////////////////////////////
304/// Broadcast a raw buffer of specified length to the remote session.
305/// Returns 0 on success, -1 in case of error.
306
308{
309 if (!IsValid()) return -1;
310
311 if (fSocket->SendRaw(buffer, length) == -1) {
312 Error("Broadcast", "could not send raw buffer");
313 return -1;
314 }
315 // Done
316 return 0;
317}
318
319////////////////////////////////////////////////////////////////////////////////
320/// Collect responses from the remote server.
321/// Returns the number of messages received.
322/// If timeout >= 0, wait at most timeout seconds (timeout = -1 by default,
323/// which means wait forever).
324
326{
327 // Activate monitoring
329 if (!fMonitor->GetActive())
330 return 0;
331
332 // Timeout counter
334 if (gDebug > 2)
335 Info("Collect","active: %d", fMonitor->GetActive());
336
337 // On clients, handle Ctrl-C during collection
338 if (fIntHandler)
339 fIntHandler->Add();
340
341 // We are now going to collect from the server
343
344 Int_t rc = 0, cnt = 0;
345 while (fMonitor->GetActive() && (nto < 0 || nto > 0)) {
346
347 // Wait for a ready socket
348 TSocket *s = fMonitor->Select(1000);
349
350 if (s && s != (TSocket *)(-1)) {
351 // Get and analyse the info it did receive
352 if ((rc = CollectInput()) != 0) {
353 // Deactivate it if we are done with it
355 if (gDebug > 2)
356 Info("Collect","deactivating %p", s);
357 }
358
359 // Update counter (if no error occurred)
360 if (rc >= 0)
361 cnt++;
362
363 } else {
364 // If not timed-out, exit if not stopped or not aborted
365 // (player exits status is finished in such a case); otherwise,
366 // we still need to collect the partial output info
367 if (!s)
369 // Decrease the timeout counter if requested
370 if (s == (TSocket *)(-1) && nto > 0)
371 nto--;
372 }
373 }
374
375 // Collection is over
377
378 // If timed-out, deactivate everything
379 if (nto == 0)
381
382 // Deactivate Ctrl-C special handler
383 if (fIntHandler)
385
386 return cnt;
387}
388
389////////////////////////////////////////////////////////////////////////////////
390/// Collect and analyze available input from the socket.
391/// Returns 0 on success, -1 if any failure occurs.
392
394{
395 TMessage *mess;
396 Int_t rc = 0;
397
398 char str[512];
399 TObject *obj;
400 Int_t what;
402
403 if (fSocket->Recv(mess) < 0) {
406 return -1;
407 }
408 if (!mess) {
409 // we get here in case the remote server died
412 return -1;
413 }
414
415 what = mess->What();
416
417 if (gDebug > 2)
418 Info("CollectInput","what %d", what);
419
420 switch (what) {
421
422 case kMESS_OBJECT:
423 { // The server sent over an object: read it in memory
424 TObject *o = mess->ReadObject(mess->GetClass());
425 // If a canvas, draw it
426 if (TString(o->ClassName()) == "TCanvas")
427 o->Draw();
428 else if (TString(o->ClassName()) == "TRemoteObject") {
430 if (TString(robj->GetClassName()) == "TSystemDirectory") {
431 if (fWorkingDir == 0) {
433 }
434 }
435 }
436 else if (TString(o->ClassName()) == "TList") {
437 TList *list = (TList *)o;
438 TRemoteObject *robj = (TRemoteObject *)list->First();
439 if (robj && (TString(robj->GetClassName()) == "TFile")) {
440 TIter next(list);
441 while ((robj = (TRemoteObject *)next())) {
442 if (!fRootFiles->FindObject(robj->GetName()))
444 }
445 gROOT->RefreshBrowsers();
446 }
447 }
448 fReceivedObject = o;
449 }
450 break;
451
452 case kMESS_ANY:
453 // Generic message: read out the type
454 { Int_t type;
455 (*mess) >> type;
456
457 if (gDebug > 2)
458 Info("CollectInput","type %d", type);
459
460 switch (type) {
461
462 case kRRT_GetObject:
463 // send server the object it asks for
464 mess->ReadString(str, sizeof(str));
465 obj = gDirectory->Get(str);
466 if (obj) {
467 fSocket->SendObject(obj);
468 } else {
469 Warning("CollectInput",
470 "server requested an object that we do not have");
472 }
473 break;
474
475 case kRRT_Fatal:
476 // Fatal error
478 rc = -1;
479 break;
480
481 case kRRT_LogFile:
482 { Int_t size;
483 (*mess) >> size;
485 }
486 break;
487
488 case kRRT_LogDone:
489 { Int_t st;
490 (*mess) >> st;
491 if (st < 0) {
492 // Problem: object should not be used
494 }
495 if (gDebug > 1)
496 Info("CollectInput","kRTT_LogDone: status %d", st);
497 rc = 1;
498 }
499 break;
500
501 case kRRT_Message:
502 { TString msg;
504 (*mess) >> msg >> lfeed;
505 if (lfeed)
506 fprintf(stderr,"%s\n", msg.Data());
507 else
508 fprintf(stderr,"%s\r", msg.Data());
509 }
510 break;
511
512 case kRRT_SendFile:
513 { TString fname;
514 (*mess) >> fname;
515 // Prepare the reply
517 m << (Int_t) kRRT_SendFile;
518 // The server needs a file: we send also the related header
519 // if we have it.
521 if (!imp) {
522 Error("CollectInput", "file %s not found in path(s) %s",
523 fname.Data(), TROOT::GetMacroPath());
524 m << (Bool_t) kFALSE;
525 Broadcast(m);
526 } else {
528 delete [] imp;
529 Int_t dot = impfile.Last('.');
530
531 // Is there any associated header file
534 if (dot != kNPOS)
535 headfile.Remove(dot);
536 headfile += ".h";
539 headfile.Remove(dot);
540 headfile += ".hh";
543 if (gDebug > 0)
544 Info("CollectInput", "no associated header file"
545 " found: tried: %s %s",
546 h.Data(), headfile.Data());
547 }
548 }
549
550 // Send files now;
551 m << (Bool_t) kTRUE;
552 Broadcast(m);
553 if (SendFile(impfile, kForce) == -1) {
554 Info("CollectInput", "problems sending file %s", impfile.Data());
555 return 0;
556 }
557 if (hasHeader) {
558 Broadcast(m);
559 if (SendFile(headfile, kForce) == -1) {
560 Info("CollectInput", "problems sending file %s", headfile.Data());
561 return 0;
562 }
563 }
564 }
565 // End of transmission
566 m.Reset(kMESS_ANY);
567 m << (Int_t) kRRT_SendFile;
568 m << (Bool_t) kFALSE;
569 Broadcast(m);
570 }
571 break;
572
573 default:
574 Warning("CollectInput","unknown type received from server: %d", type);
575 break;
576
577 }
578 }
579 break;
580
581 default:
582 Error("CollectInput", "unknown command received from server: %d", what);
585 rc = -1;
586 break;
587 }
588
589 // Cleanup
590 if (delete_mess)
591 delete mess;
592
593 // We are done successfully
594 return rc;
595}
596
597
598////////////////////////////////////////////////////////////////////////////////
599/// Receive the log file from the server
600
602{
603 const Int_t kMAXBUF = 16384; //32768 //16384 //65536;
604 char buf[kMAXBUF];
605
606 // Append messages to active logging unit
608 if (fdout < 0) {
609 Warning("RecvLogFile", "file descriptor for outputs undefined (%d):"
610 " will not log msgs", fdout);
611 return;
612 }
613 lseek(fdout, (off_t) 0, SEEK_END);
614
615 Int_t left, rec, r;
616 Long_t filesize = 0;
617
618 while (filesize < size) {
619 left = Int_t(size - filesize);
620 if (left > kMAXBUF)
621 left = kMAXBUF;
622 rec = fSocket->RecvRaw(&buf, left);
623 filesize = (rec > 0) ? (filesize + rec) : filesize;
624 if (rec > 0) {
625
626 char *p = buf;
627 r = rec;
628 while (r) {
629 Int_t w;
630
631 w = write(fdout, p, r);
632
633 if (w < 0) {
634 SysError("RecvLogFile", "error writing to unit: %d", fdout);
635 break;
636 }
637 r -= w;
638 p += w;
639 }
640 } else if (rec < 0) {
641 Error("RecvLogFile", "error during receiving log file");
642 break;
643 }
644 }
645}
646
647////////////////////////////////////////////////////////////////////////////////
648/// Send object to server.
649/// Return 0 on success, -1 in case of error.
650
652{
653 if (!IsValid() || !obj) return -1;
654
656 mess.WriteObject(obj);
657 return Broadcast(mess);
658}
659
660////////////////////////////////////////////////////////////////////////////////
661/// Check if a file needs to be send to the server. Use the following
662/// algorithm:
663/// - check if file appears in file map
664/// - if yes, get file's modtime and check against time in map,
665/// if modtime not same get md5 and compare against md5 in map,
666/// if not same return kTRUE.
667/// - if no, get file's md5 and modtime and store in file map, ask
668/// slave if file exists with specific md5, if yes return kFALSE,
669/// if no return kTRUE.
670/// Returns kTRUE in case file needs to be send, returns kFALSE in case
671/// file is already on remote node.
672
674{
676
677 if (!IsValid()) return -1;
678
679 // The filename for the cache
680 TString fn = gSystem->BaseName(file);
681
682 // Check if the file is already in the cache
683 TARFileStat *fs = 0;
684 if (fFileList && (fs = (TARFileStat *) fFileList->FindObject(fn))) {
685 // File in cache
686 if (fs->fModtime != modtime) {
687 TMD5 *md5 = TMD5::FileChecksum(file);
688 if (md5) {
689 if ((*md5) != fs->fMD5) {
690 sendto = kTRUE;
691 fs->fMD5 = *md5;
692 fs->fModtime = modtime;
693 }
694 delete md5;
695 } else {
696 Error("CheckFile", "could not calculate local MD5 check sum - dont send");
697 return kFALSE;
698 }
699 }
700 } else {
701 // file not in the cache
702 TMD5 *md5 = TMD5::FileChecksum(file);
703 if (md5) {
704 fs = new TARFileStat(fn, md5, modtime);
705 if (!fFileList)
706 fFileList = new THashList;
707 fFileList->Add(fs);
708 delete md5;
709 } else {
710 Error("CheckFile", "could not calculate local MD5 check sum - dont send");
711 return kFALSE;
712 }
714 mess << Int_t(kRRT_CheckFile) << TString(gSystem->BaseName(file)) << fs->fMD5;
715 fSocket->Send(mess);
716
719 if (reply) {
720 if (reply->What() == kMESS_ANY) {
721 // Check the type
722 Int_t type;
724 (*reply) >> type >> uptodate;
725 if (type != kRRT_CheckFile) {
726 // Protocol error
727 Warning("CheckFile", "received wrong type:"
728 " %d (expected %d): protocol error?",
730 }
732 } else {
733 // Protocol error
734 Error("CheckFile", "received wrong message: %d (expected %d)",
735 reply->What(), kMESS_ANY);
736 }
737 } else {
738 Error("CheckFile", "received empty message");
739 }
740 // Collect logs
741 Collect();
742 }
743
744 // Done
745 return sendto;
746}
747
748////////////////////////////////////////////////////////////////////////////////
749/// Send a file to the server. Return 0 on success, -1 in case of error.
750/// If defined, the full path of the remote path will be rfile.
751/// The mask 'opt' is an or of ESendFileOpt:
752///
753/// kAscii (0x0) if set true ascii file transfer is used
754/// kBinary (0x1) if set true binary file transfer is used
755/// kForce (0x2) if not set an attempt is done to find out
756/// whether the file really needs to be downloaded
757/// (a valid copy may already exist in the cache
758/// from a previous run)
759///
760
761Int_t TApplicationRemote::SendFile(const char *file, Int_t opt, const char *rfile)
762{
763 if (!IsValid()) return -1;
764
765#ifndef R__WIN32
766 Int_t fd = open(file, O_RDONLY);
767#else
768 Int_t fd = open(file, O_RDONLY | O_BINARY);
769#endif
770 if (fd < 0) {
771 SysError("SendFile", "cannot open file %s", file);
772 return -1;
773 }
774
775 // Get info about the file
777 Long_t id, flags, modtime;
778 if (gSystem->GetPathInfo(file, &id, &size, &flags, &modtime) == 1) {
779 Error("SendFile", "cannot stat file %s", file);
780 close(fd);
781 return -1;
782 }
783 if (size == 0) {
784 Error("SendFile", "empty file %s", file);
785 close(fd);
786 return -1;
787 }
788
789 // Decode options
790 Bool_t bin = (opt & kBinary) ? kTRUE : kFALSE;
791 Bool_t force = (opt & kForce) ? kTRUE : kFALSE;
792
793 const Int_t kMAXBUF = 32768; //16384 //65536;
794 char buf[kMAXBUF];
795
796 const char *fnam = (rfile) ? rfile : gSystem->BaseName(file);
797
798 Bool_t sendto = force ? kTRUE : CheckFile(file, modtime);
799
800 // The value of 'size' is used as flag remotely, so we need to
801 // reset it to 0 if we are not going to send the file
802 size = sendto ? size : 0;
803
804 if (gDebug > 1 && size > 0)
805 Info("SendFile", "sending file %s", file);
806
807 snprintf(buf, kMAXBUF, "%s %d %lld", fnam, bin, size);
808 if (Broadcast(buf, kMESS_ANY, kRRT_File) == -1) {
810 close(fd);
811 return -1;
812 }
813
814 if (sendto) {
815
816 lseek(fd, 0, SEEK_SET);
817
818 Int_t len;
819 do {
820 while ((len = read(fd, buf, kMAXBUF)) < 0 && TSystem::GetErrno() == EINTR)
822
823 if (len < 0) {
824 SysError("SendFile", "error reading from file %s", file);
825 Interrupt();
826 close(fd);
827 return -1;
828 }
829
830 if (len > 0 && fSocket->SendRaw(buf, len) == -1) {
831 SysError("SendFile", "error writing to server @ %s:%d (now offline)",
832 fUrl.GetHost(), fUrl.GetPort());
834 break;
835 }
836
837 } while (len > 0);
838 }
839 close(fd);
840
841 // Get the log (during collection this will be done at the end
842 if (!TestBit(kCollecting))
843 Collect();
844
845 // Done
846 return IsValid() ? 0 : -1;
847}
848
849////////////////////////////////////////////////////////////////////////////////
850/// Terminate this session
851
862
863////////////////////////////////////////////////////////////////////////////////
864/// Set port parameters for tunnelling. A value of -1 means unchanged
865
867{
868 if (lower > -1)
870 if (upper > -1)
872 if (attempts > -1)
874
875 ::Info("TApplicationRemote::SetPortParam","port scan: %d attempts in [%d,%d]",
877}
878
879////////////////////////////////////////////////////////////////////////////////
880/// Parse a single command line and forward the request to the remote server
881/// where it will be processed. The line is either a C++ statement or an
882/// interpreter command starting with a ".".
883/// Return the return value of the command casted to a long.
884
886{
887 if (!line || !*line) return 0;
888
889 if (!strncasecmp(line, ".q", 2)) {
890 // terminate the session
891 gApplication->ProcessLine(".R -close");
892 return 0;
893 }
894
895 if (!strncmp(line, "?", 1)) {
896 Help(line);
897 return 1;
898 }
899
900 fReceivedObject = 0;
901
902 // Init graphics
904
905 // Ok, now we pack the command and we send it over for processing
907
908 // And collect the results
909 Collect();
910
911 // Done
913 return 1;
914}
915
916////////////////////////////////////////////////////////////////////////////////
917/// Print some info about this instance
918
920{
921 TString s(Form("OBJ: TApplicationRemote %s", fName.Data()));
922 Printf("%s", s.Data());
923 if (opt && opt[0] == 'F') {
924 s = " url: ";
925 if (strlen(fUrl.GetUser()) > 0)
926 s += Form("%s@", fUrl.GetUser());
927 s += fUrl.GetHostFQDN();
928 s += Form(" logfile: %s", fLogFilePath.Data());
929 Printf("%s", s.Data());
930 }
931}
932////////////////////////////////////////////////////////////////////////////////
933/// Send interrupt OOB byte to server.
934/// Returns 0 if ok, -1 in case of error
935
937{
938 if (!IsValid()) return;
939
941
942#if 1
943 Info("Interrupt", "*** Ctrl-C not yet enabled *** (type= %d)", type);
944 return;
945#else
946
947 char oobc = (char) type;
948 const int kBufSize = 1024;
949 char waste[kBufSize];
950
951 // Send one byte out-of-band message to server
952 if (fSocket->SendRaw(&oobc, 1, kOob) <= 0) {
953 Error("Interrupt", "error sending oobc to server");
954 return;
955 }
956
957 if (type == kRRI_Hard) {
958 char oob_byte;
959 int n, nch, nbytes = 0, nloop = 0;
960
961 // Receive the OOB byte
962 while ((n = fSocket->RecvRaw(&oob_byte, 1, kOob)) < 0) {
963 if (n == -2) { // EWOULDBLOCK
964 //
965 // The OOB data has not yet arrived: flush the input stream
966 //
967 // In some systems (Solaris) regular recv() does not return upon
968 // receipt of the oob byte, which makes the below call to recv()
969 // block indefinitely if there are no other data in the queue.
970 // FIONREAD ioctl can be used to check if there are actually any
971 // data to be flushed. If not, wait for a while for the oob byte
972 // to arrive and try to read it again.
973 //
975 if (nch == 0) {
976 gSystem->Sleep(1000);
977 continue;
978 }
979
980 if (nch > kBufSize) nch = kBufSize;
982 if (n <= 0) {
983 Error("Interrupt", "error receiving waste from server");
984 break;
985 }
986 nbytes += n;
987 } else if (n == -3) { // EINVAL
988 //
989 // The OOB data has not arrived yet
990 //
991 gSystem->Sleep(100);
992 if (++nloop > 100) { // 10 seconds time-out
993 Error("Interrupt", "server does not respond");
994 break;
995 }
996 } else {
997 Error("Interrupt", "error receiving OOB from server");
998 break;
999 }
1000 }
1001
1002 //
1003 // Continue flushing the input socket stream until the OOB
1004 // mark is reached
1005 //
1006 while (1) {
1007 int atmark;
1008
1010
1011 if (atmark)
1012 break;
1013
1014 // find out number of bytes to read before atmark
1016 if (nch == 0) {
1017 gSystem->Sleep(1000);
1018 continue;
1019 }
1020
1021 if (nch > kBufSize) nch = kBufSize;
1022 n = fSocket->RecvRaw(waste, nch);
1023 if (n <= 0) {
1024 Error("Interrupt", "error receiving waste (2) from server");
1025 break;
1026 }
1027 nbytes += n;
1028 }
1029 if (nbytes > 0)
1030 Info("Interrupt", "server synchronized: %d bytes discarded", nbytes);
1031
1032 // Get log file from server after a hard interrupt
1033 Collect();
1034
1035 } else if (type == kRRI_Soft) {
1036
1037 // Get log file from server after a soft interrupt
1038 Collect();
1039
1040 } else if (type == kRRI_Shutdown) {
1041
1042 ; // nothing expected to be returned
1043
1044 } else {
1045
1046 // Unexpected message, just receive log file
1047 Collect();
1048 }
1049#endif
1050}
1051
1052////////////////////////////////////////////////////////////////////////////////
1053/// Browse remote application (working directory and ROOT files).
1054
1056{
1057 b->Add(fRootFiles, "ROOT Files");
1059 gROOT->RefreshBrowsers();
1060}
@ kMESS_ANY
@ kMESS_NOTOK
@ kMESS_OBJECT
@ kMESS_CINT
#define SafeDelete(p)
Definition RConfig.hxx:531
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
Boolean (0=false, 1=true) (bool)
Definition RtypesCore.h:77
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:59
long Longptr_t
Integer large enough to hold a pointer (platform-dependent)
Definition RtypesCore.h:89
long Long_t
Signed long integer 4 bytes (long). Size depends on architecture.
Definition RtypesCore.h:68
constexpr Bool_t kFALSE
Definition RtypesCore.h:108
constexpr Ssiz_t kNPOS
The equivalent of std::string::npos for the ROOT class TString.
Definition RtypesCore.h:131
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
const char Option_t
Option string (const char)
Definition RtypesCore.h:80
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:385
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
Int_t gDebug
Global variable setting the debug level. Set to 0 to disable, increase it in steps of 1 to increase t...
Definition TROOT.cxx:627
#define gROOT
Definition TROOT.h:414
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2495
void Printf(const char *fmt,...)
Formats a string in a circular formatting buffer and prints the string.
Definition TString.cxx:2509
@ 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:582
#define O_BINARY
Definition civetweb.c:935
#define snprintf
Definition civetweb.c:1579
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:473
virtual void ActivateAll()
Activate all de-activated sockets.
Definition TMonitor.cxx:267
TSocket * Select()
Return pointer to socket for which an event is waiting.
Definition TMonitor.cxx:321
virtual void Add(TSocket *sock, Int_t interest=kRead)
Add socket to the monitor's active list.
Definition TMonitor.cxx:167
Int_t GetActive(Long_t timeout=-1) const
Return number of sockets in the active list.
Definition TMonitor.cxx:437
virtual void DeActivateAll()
De-activate all activated sockets.
Definition TMonitor.cxx:301
virtual void DeActivate(TSocket *sock)
De-activate a socket.
Definition TMonitor.cxx:283
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:50
Mother of all ROOT objects.
Definition TObject.h:42
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:204
virtual void SysError(const char *method, const char *msgfmt,...) const
Issue system error message.
Definition TObject.cxx:1109
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:224
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1081
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:885
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1095
virtual void Draw(Option_t *option="")
Default Draw method for all objects.
Definition TObject.cxx:290
void ResetBit(UInt_t f)
Definition TObject.h:203
@ kInvalidObject
if object ctor succeeded but object should not be used
Definition TObject.h:81
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:1069
static const char * GetMacroPath()
Get macro search path. Static utility function.
Definition TROOT.cxx:2770
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:811
virtual Int_t RecvRaw(void *buffer, Int_t length, ESendRecvOptions opt=kDefault)
Receive a raw buffer of specified length bytes.
Definition TSocket.cxx:906
virtual Int_t SendRaw(const void *buffer, Int_t length, ESendRecvOptions opt=kDefault)
Send a raw buffer of specified length.
Definition TSocket.cxx:613
Option_t * GetOption() const override
Definition TSocket.h:104
virtual Int_t SendObject(const TObject *obj, Int_t kind=kMESS_OBJECT)
Send an object.
Definition TSocket.cxx:593
virtual Int_t Send(const TMessage &mess)
Send a TMessage object.
Definition TSocket.cxx:515
Basic string class.
Definition TString.h:138
TString & Insert(Ssiz_t pos, const char *s)
Definition TString.h:670
const char * Data() const
Definition TString.h:384
static void ResetErrno()
Static function resetting system error number.
Definition TSystem.cxx:282
static Int_t GetErrno()
Static function returning system error number.
Definition TSystem.cxx:274
virtual TTime Now()
Get current time in milliseconds since 0:00 Jan 1 1995.
Definition TSystem.cxx:461
virtual Int_t Exec(const char *shellcmd)
Execute a command.
Definition TSystem.cxx:651
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:1409
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:1307
virtual const char * BaseName(const char *pathname)
Base name of a file name. Base name of /user/root is root.
Definition TSystem.cxx:944
virtual Int_t GetEffectiveUid()
Returns the effective user id.
Definition TSystem.cxx:1583
virtual void Sleep(UInt_t milliSec)
Sleep milliSec milli seconds.
Definition TSystem.cxx:435
virtual char * Which(const char *search, const char *file, EAccessMode mode=kFileExists)
Find location of file in a search path.
Definition TSystem.cxx:1559
virtual UserGroup_t * GetUserInfo(Int_t uid)
Returns all user info in the UserGroup_t structure.
Definition TSystem.cxx:1612
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:476
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
const Int_t n
Definition legend1.C:16
static const char * what
Definition stlLoader.cc:5
TMarker m
Definition textangle.C:8