Logo ROOT  
Reference Guide
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)
96 : TApplication(), fUrl(url)
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;
142 TString sc = gScript;
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("\"","");
154 TString userhost = fUrl.GetHost();
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";
160 TString scriptCmd;
161 scriptCmd.Form(gScriptCmd, sc.Data(), kRRemote_Protocol, rport, fUrl.GetFile(), debug);
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
228 TString hostname;
229 (*msg) >> hostname >> fLogFilePath;
230 fUrl.SetHost(hostname);
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
334 Long_t nto = timeout;
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;
402 Bool_t delete_mess = kTRUE;
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") {
430 TRemoteObject *robj = (TRemoteObject *)o;
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()))
444 fRootFiles->Add(robj);
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;
504 Bool_t lfeed;
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.
521 char *imp = gSystem->Which(TROOT::GetMacroPath(), fname, kReadPermission);
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 {
528 TString impfile = imp;
529 delete [] imp;
530 Int_t dot = impfile.Last('.');
531
532 // Is there any associated header file
533 Bool_t hasHeader = kTRUE;
534 TString headfile = impfile;
535 if (dot != kNPOS)
536 headfile.Remove(dot);
537 headfile += ".h";
538 if (gSystem->AccessPathName(headfile, kReadPermission)) {
539 TString h = headfile;
540 headfile.Remove(dot);
541 headfile += ".hh";
542 if (gSystem->AccessPathName(headfile, kReadPermission)) {
543 hasHeader = kFALSE;
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
608 Int_t fdout = fileno(stdout);
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{
676 Bool_t sendto = kFALSE;
677
678 if (!IsValid()) return -1;
679
680 // The filename for the cache
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) {
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
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 }
714 TMessage mess(kMESS_ANY);
715 mess << Int_t(kRRT_CheckFile) << TString(gSystem->BaseName(file)) << fs->fMD5;
716 fSocket->Send(mess);
717
718 TMessage *reply;
719 fSocket->Recv(reply);
720 if (reply) {
721 if (reply->What() == kMESS_ANY) {
722 // Check the type
723 Int_t type;
724 Bool_t uptodate;
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 }
732 sendto = uptodate ? kFALSE : kTRUE;
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
854{
855 TMessage mess(kMESS_ANY);
856 mess << (Int_t)kRRT_Terminate << status;
857 Broadcast(mess);
858
862}
863
864////////////////////////////////////////////////////////////////////////////////
865/// Set port parameters for tunnelling. A value of -1 means unchanged
866
868{
869 if (lower > -1)
870 fgPortLower = lower;
871 if (upper > -1)
872 fgPortUpper = upper;
873 if (attempts > -1)
874 fgPortAttempts = attempts;
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;
982 n = fSocket->RecvRaw(waste, nch);
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
1010 fSocket->GetOption(kAtMark, atmark);
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
Definition: MessageTypes.h:31
@ kMESS_NOTOK
Definition: MessageTypes.h:33
@ kMESS_OBJECT
Definition: MessageTypes.h:35
@ kMESS_CINT
Definition: MessageTypes.h:36
ROOT::R::TRInterface & r
Definition: Object.C:4
#define SafeDelete(p)
Definition: RConfig.hxx:534
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
const Ssiz_t kNPOS
Definition: RtypesCore.h:124
int Int_t
Definition: RtypesCore.h:45
long Longptr_t
Definition: RtypesCore.h:82
const Bool_t kFALSE
Definition: RtypesCore.h:101
long Long_t
Definition: RtypesCore.h:54
bool Bool_t
Definition: RtypesCore.h:63
long long Long64_t
Definition: RtypesCore.h:80
const Bool_t kTRUE
Definition: RtypesCore.h:100
const char Option_t
Definition: RtypesCore.h:66
#define ClassImp(name)
Definition: Rtypes.h:364
static const char * gSshCmd
static const char * gScript
static const char * gScriptCmd
R__EXTERN TApplication * gApplication
Definition: TApplication.h:165
#define gDirectory
Definition: TDirectory.h:348
XFontStruct * id
Definition: TGX11.cxx:109
int type
Definition: TGX11.cxx:121
Int_t gDebug
Definition: TROOT.cxx:592
#define gROOT
Definition: TROOT.h:404
char * Form(const char *fmt,...)
void Printf(const char *fmt,...)
@ kBytesToRead
Definition: TSystem.h:225
@ kAtMark
Definition: TSystem.h:224
@ kOob
Definition: TSystem.h:230
@ kReadPermission
Definition: TSystem.h:47
R__EXTERN TSystem * gSystem
Definition: TSystem.h:559
#define O_BINARY
Definition: civetweb.c:799
#define snprintf
Definition: civetweb.c:1540
TApplicationRemote * fApplicationRemote
Bool_t Notify()
TApplicationRemote interrupt handler.
virtual void Browse(TBrowser *b)
Browse remote application (working directory and ROOT files).
void Print(Option_t *option="") const
Print some info about this instance.
Int_t CollectInput()
Collect and analyze available input from the socket.
virtual ~TApplicationRemote()
Destructor.
Int_t BroadcastRaw(const void *buffer, Int_t length)
Broadcast a raw buffer of specified length to the remote session.
Longptr_t ProcessLine(const char *line, Bool_t=kFALSE, Int_t *error=0)
Parse a single command line and forward the request to the remote server where it will be processed.
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 Terminate(Int_t status=0)
Terminate this session.
void Interrupt(Int_t type=kRRI_Hard)
Send interrupt OOB byte to server.
TApplicationRemote(const char *url, Int_t debug=0, const char *script=0)
Main constructor: start a remote session at 'url' accepting callbacks on local port 'port'; if port i...
static Int_t fgPortUpper
void RecvLogFile(Int_t size)
Receive the log file from the server.
TSeqCollection * fRootFiles
Int_t SendFile(const char *file, Int_t opt=kAscii, const char *rfile=0)
Send a file to the server.
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.
static Int_t fgPortLower
Bool_t IsValid() const
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...
Definition: TApplication.h:39
virtual void Help(const char *line)
The function lists useful commands (".help") or opens the online reference guide, generated with Doxy...
virtual Longptr_t ProcessLine(const char *line, Bool_t sync=kFALSE, Int_t *error=0)
void InitializeGraphics()
Initialize the graphics environment.
static void NeedGraphicsLibs()
Static method.
Using a TBrowser one can browse all ROOT objects.
Definition: TBrowser.h:37
TObject * ReadObject(const TClass *cl) override
Read object from I/O buffer.
void WriteString(const char *s) override
Write string to I/O buffer.
char * ReadString(char *s, Int_t max) override
Read string from I/O buffer.
void WriteObject(const TObject *obj, Bool_t cacheReuse=kTRUE) override
Write object to I/O buffer.
Definition: TBufferIO.cxx:530
virtual TObject * FindObject(const char *name) const
Find an object in this collection using its name.
void SetName(const char *name)
Definition: TCollection.h:206
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
Find object using its name.
Definition: THashList.cxx:262
A doubly linked list.
Definition: TList.h:44
virtual void Add(TObject *obj)
Definition: TList.h:87
virtual TObject * First() const
Return the first object in the list. Returns 0 when list is empty.
Definition: TList.cxx:659
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
UInt_t What() const
Definition: TMessage.h:75
TClass * GetClass() const
Definition: TMessage.h:71
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
virtual const char * GetTitle() const
Returns title of object.
Definition: TNamed.h:48
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
Mother of all ROOT objects.
Definition: TObject.h:37
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:187
virtual void SysError(const char *method, const char *msgfmt,...) const
Issue system error message.
Definition: TObject.cxx:907
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition: TObject.cxx:130
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:879
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:696
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:893
virtual void Draw(Option_t *option="")
Default Draw method for all objects.
Definition: TObject.cxx:197
void ResetBit(UInt_t f)
Definition: TObject.h:186
@ kInvalidObject
if object ctor succeeded but object should not be used
Definition: TObject.h:68
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:867
static const char * GetMacroPath()
Get macro search path. Static utility function.
Definition: TROOT.cxx:2715
The TRemoteObject class provides protocol for browsing ROOT objects from a remote ROOT session.
Definition: TRemoteObject.h:34
const char * GetClassName() const
Definition: TRemoteObject.h:54
virtual void Add(TObject *obj)
virtual TSocket * Accept(UChar_t Opt=0)
Accept a connection on a server socket.
virtual void Add()
Add signal handler to system signal handler list.
virtual void Remove()
Remove signal handler from system signal handler list.
Option_t * GetOption() const
Definition: TSocket.h:98
virtual Int_t Recv(TMessage *&mess)
Receive a TMessage object.
Definition: TSocket.cxx:818
virtual Int_t RecvRaw(void *buffer, Int_t length, ESendRecvOptions opt=kDefault)
Receive a raw buffer of specified length bytes.
Definition: TSocket.cxx:898
virtual Int_t SendRaw(const void *buffer, Int_t length, ESendRecvOptions opt=kDefault)
Send a raw buffer of specified length.
Definition: TSocket.cxx:620
virtual Int_t SendObject(const TObject *obj, Int_t kind=kMESS_OBJECT)
Send an object.
Definition: TSocket.cxx:600
virtual Bool_t IsValid() const
Definition: TSocket.h:132
virtual Int_t Send(const TMessage &mess)
Send a TMessage object.
Definition: TSocket.cxx:522
Basic string class.
Definition: TString.h:136
TString & Insert(Ssiz_t pos, const char *s)
Definition: TString.h:649
const char * Data() const
Definition: TString.h:369
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition: TString.h:692
Ssiz_t Last(char c) const
Find last occurrence of a character c.
Definition: TString.cxx:916
TString & Remove(Ssiz_t pos)
Definition: TString.h:673
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2314
static void ResetErrno()
Static function resetting system error number.
Definition: TSystem.cxx:279
static Int_t GetErrno()
Static function returning system error number.
Definition: TSystem.cxx:263
virtual TTime Now()
Get current time in milliseconds since 0:00 Jan 1 1995.
Definition: TSystem.cxx:466
virtual Int_t Exec(const char *shellcmd)
Execute a command.
Definition: TSystem.cxx:656
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:1398
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:1296
virtual const char * BaseName(const char *pathname)
Base name of a file name. Base name of /user/root is root.
Definition: TSystem.cxx:935
virtual Int_t GetEffectiveUid()
Returns the effective user id.
Definition: TSystem.cxx:1570
virtual void Sleep(UInt_t milliSec)
Sleep milliSec milli seconds.
Definition: TSystem.cxx:440
virtual char * Which(const char *search, const char *file, EAccessMode mode=kFileExists)
Find location of file in a search path.
Definition: TSystem.cxx:1546
virtual UserGroup_t * GetUserInfo(Int_t uid)
Returns all user info in the UserGroup_t structure.
Definition: TSystem.cxx:1599
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:471
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 constexpr double s
Definition: file.py:1
const char * cnt
Definition: TXMLSetup.cxx:75
static const char * what
Definition: stlLoader.cc:6
TString fUser
Definition: TSystem.h:141
auto * m
Definition: textangle.C:8