GSI Object Oriented Online Offline (Go4)  GO4-6.2.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
TGo4HistogramServer.cxx
Go to the documentation of this file.
1 // $Id: TGo4HistogramServer.cxx 3344 2021-10-18 13:41:52Z linev $
2 //-----------------------------------------------------------------------
3 // The GSI Online Offline Object Oriented (Go4) Project
4 // Experiment Data Processing at EE department, GSI
5 //-----------------------------------------------------------------------
6 // Copyright (C) 2000- GSI Helmholtzzentrum fuer Schwerionenforschung GmbH
7 // Planckstr. 1, 64291 Darmstadt, Germany
8 // Contact: http://go4.gsi.de
9 //-----------------------------------------------------------------------
10 // This software can be used under the license agreements as stated
11 // in Go4License.txt file which is part of the distribution.
12 //-----------------------------------------------------------------------
13 
14 #include "TGo4HistogramServer.h"
15 
16 #include <iostream>
17 #include "TFile.h"
18 
19 #include "TGo4Log.h"
20 #include "TGo4LockGuard.h"
21 #include "TGo4Socket.h"
22 #include "TGo4Buffer.h"
23 
26 #include "TGo4ObjConnectorTimer.h"
27 #include "TGo4CommandInvoker.h"
28 #include "TGo4AnalysisClientImp.h"
29 #include "TGo4AnalysisImp.h"
31 #include "TGo4Task.h"
32 #include "TGo4Thread.h"
33 #include "TGo4ThreadManager.h"
34 #include "TGo4ThreadHandler.h"
35 #include "TGo4TerminateException.h"
36 #include "TGo4TaskHandler.h"
37 
38 extern "C" {
39  #include "f_his_hist.h"
40 }
41 
42 const char *TGo4HistogramServer::fgcCONTHREADNAME = "HISTOSERV-";
43 const char *TGo4HistogramServer::fgcSHUTDOWNNAME = "__HServLast__";
44 const char *TGo4HistogramServer::fgcCOMGETLIST = "__OServNamesList__";
45 
46 const char *TGo4HistogramServer::fgcOBJTHREADNAME = "OBJECTSERV-";
47 const UInt_t TGo4HistogramServer::fguTIMERPERIOD = 200; // time in ms (20)
48 const Int_t TGo4HistogramServer::fgiOPENWAITCYCLES = 100; // wait cycles (100)
49 const UInt_t TGo4HistogramServer::fguOPENWAITCYCLETIME = 500; // time in ms (20)
50 const Int_t TGo4HistogramServer::fgiCLOSEWAITCYCLES = 100; // wait cycles (100)
51 const UInt_t TGo4HistogramServer::fguCLOSEWAITCYCLETIME = 500; // time in ms (20)
52 const Int_t TGo4HistogramServer::fgiCONNECTWAITCYCLES = 20; // wait cycles (20)
53 const UInt_t TGo4HistogramServer::fguCONNECTWAITCYCLETIME = 500; // time in ms (20)
54 
55 TGo4HistogramServer::TGo4HistogramServer(TGo4AnalysisClient *owner, const char *servername, const char *password,
56  Bool_t useobjectserver)
57  : fxAnalysisClient(owner), fxThreadHandler(0), fiServerPort(0), fxTransport(0), fuObjectPort(0),
58  fxConnectTransport(0), fxDisConnectTransport(0), fuConnectPort(0), fbConnectRequest(kFALSE),
59  fbDisConnectRequest(kFALSE), fbConnectIsOpen(kFALSE), fbConnectIsDone(kFALSE), fbConnectIsClose(kTRUE),
60  fxConnectorTimer(0), fbUseObjectServer(useobjectserver)
61 {
62  TGo4CommandInvoker::Instance(); // make sure we have an invoker instance!
63  TGo4CommandInvoker::Register("HistogramServer", this);
65  fxTransport = new TGo4Socket(kFALSE); // raw transport in server mode for object server
66  // we use the histogram api instead of stccomm:
67  Int_t result = f_his_server((CHARS *)servername, (CHARS *)password, &fiServerPort);
68  if (result == COMM__SUCCESS) {
69  fxServerName = servername;
70  fxServerPass = password;
71  TGo4Analysis::Instance()->Message(1, "Created Histogram server %s on port %d", servername, fiServerPort);
72  } else {
73  // std::cout <<"ERROR on creation of Histogram server: "<< result << std::endl;
74  TGo4Analysis::Instance()->Message(3, "ERROR %d on creation of Histogram server", result);
75  }
76  // start connector thread:
77  const char *ownername;
78  if (fxAnalysisClient) {
81  ownername = fxAnalysisClient->GetName();
82  } else {
83  ownername = "never-come-here";
84  }
85 
86  if (fbUseObjectServer) {
88  fxConnectorTimer->TurnOn();
89  }
90  if (fxThreadHandler) {
91  // thread to serve gsi histogram api:
93  fxConnectorName += ownername;
94 
98  if (fbUseObjectServer) {
99 
100  // thread for root object server:
102  fxObjectThreadName += ownername;
103 
107  }
108  } else {
109  std::cerr << " Histogram Server constructor FATAL ERROR: no threadmanager !!" << std::endl;
110  throw TGo4RuntimeException();
111  }
112 }
113 
115  : fxAnalysisClient(0), fxThreadHandler(0), fiServerPort(0), fxTransport(0), fuObjectPort(0), fxConnectTransport(0),
116  fxDisConnectTransport(0), fcConnectHost(0), fuConnectPort(0), fbConnectRequest(kFALSE),
117  fbDisConnectRequest(kFALSE), fbConnectIsOpen(kFALSE), fbConnectIsDone(kFALSE), fbConnectIsClose(kTRUE),
118  fbUseObjectServer(kFALSE)
119 {
120  TGo4CommandInvoker::Instance(); // make sure we have an invoker instance!
121  TGo4CommandInvoker::Register("HistogramServer", this);
122 }
123 
125 {
126  // prepare stopped flag:
129 
130  // for clean shutdown, we have to connect one last time to get out of the wait:
131  INTS4 *pl_all = NULL;
132  s_his_head *ps_his_head = NULL;
133  INTS4 l_size = 0;
134  f_his_gethis((char *)"localhost", fiServerPort, (char *)fxServerName.Data(), (char *)fxServerPass.Data(),
135  (char *)fgcSHUTDOWNNAME, (s_his_head **)&ps_his_head, &pl_all, &l_size);
136 
137  if (fxThreadHandler) {
140  if (fbUseObjectServer) {
142  // here we might connect last time to object server, to investigate!!
145  // this will cancel thread and delete runnable
146  }
147  }
148  delete fxConnectorTimer;
149  f_his_close(); // this will delete api server for histograms
150 
151  if (fxTransport) {
152  fxTransport->Close(); // close go4 server socket for object server
153  delete fxTransport;
154  fxTransport = 0;
155  }
156 
158 }
159 
161 {
162  Int_t rev = ConnectObjectClient();
163  if (rev < 0)
164  return rev;
165  if (rev == 0 && CheckLogin()) {
167  } else {
168  }
170  return rev;
171 }
172 
174 {
175  //
176  SetDisConnect(fxTransport); // timer shall do the Close() of negotiation
177  // TGo4Log::Debug(" HistogramServer: Waiting for timer Close() of client ... ");
178  WaitForClose(); // poll until timer has returned from close
179  // TGo4Log::Debug(" HistogramServer: Client connection closed. ");
180 }
181 
183 {
184 
185  static Bool_t isfirsttime = kTRUE;
186  // we delegate the actual TSocket open to the taskconnector timer:
187  SetConnect(fxTransport, "Server mode does not need hostname", 0); // for portscan
188  Int_t waitresult = WaitForOpen(); // wait for the server Open() call by timer
189  if (waitresult == -2)
190  return waitresult; // return in termination mode
191  if (waitresult < 0) {
192  // open timeout
193  TGo4Log::Debug(" HistogramServer: Negotiation channel open TIMEOUT");
194  std::cerr << " HistogramServer TIMEOUT ERROR opening socket connection !!! Terminating..." << std::endl;
196  }
197  Int_t count = 0;
198  while (GetObjPort() == 0) {
199  TGo4Task *task = fxAnalysisClient->GetTask();
201  TGo4Log::Debug(" HistogramServer: Negotiation port getter TIMEOUT");
202  std::cerr << " HistogramServer TIMEOUT ERROR retrieving port number !!! Terminating..." << std::endl;
204  } else if (task == 0 || task->IsTerminating()) {
205  return -1;
206  } else {
208  ++count;
209  }
210  }
211  // TGo4Log::Debug(" HistogramServer is waiting to serve object client request on port %d ... ",
212  // fuObjectPort);
213  if (isfirsttime) {
214  // only tell gui the first time the port number; performance!
215  TGo4Analysis::Instance()->Message(1, "Object Server %s is waiting on port %d", fxServerName.Data(), fuObjectPort);
216  isfirsttime = kFALSE;
217  } else {
218  }
219  Int_t connectwaitseconds = WaitForConnection(); // timer tells us by flag when the transport is opened
220  if (connectwaitseconds < 0) {
221  // case of threadmanager termination:
222  // connector runnable shall stop on return from ServeClient method
223  return connectwaitseconds;
224  } else {
225  // just proceed to the client server negotiations
226  }
227 
228  return 0;
229 }
230 
232 {
234  // check for basename:
235  // std::cout <<"##### check login " << std::endl;
236  const char *recvchar = fxTransport->RecvRaw("dummy");
237  if (recvchar && !strcmp(recvchar, fxServerName.Data())) {
238  fxTransport->Send(TGo4TaskHandler::Get_fgcOK()); // handshake to assure the client
239  } else {
240  // TGo4Analysis::Instance()->Message(2,
241  // "Object server connection attempt with wrong basename");
242  std::cerr << "##### check login with wrong base" << std::endl;
245  return kFALSE;
246  }
247  // check for password:
248  recvchar = fxTransport->RecvRaw("dummy");
249  if (recvchar && !strcmp(recvchar, fxServerPass.Data())) {
250  fxTransport->Send(TGo4TaskHandler::Get_fgcOK()); // handshake to assure the client
251  } else {
252  // TGo4Analysis::Instance()->Message(2,
253  // "Object server connection attempt with wrong password");
254  std::cerr << "##### check login with wrong passwd" << std::endl;
257  return kFALSE;
258  }
259  return kTRUE;
260 }
261 
263 {
264  char objectname[TGo4ThreadManager::fguTEXTLENGTH];
265  char *recvchar = 0;
266  // get object name
267  recvchar = fxTransport->RecvRaw("dummy");
268  if (recvchar == 0) {
269  std::cerr << "-----Object server received null character for object request!" << std::endl;
270  return kFALSE;
271  }
272  strncpy(objectname, recvchar, TGo4ThreadManager::fguTEXTLENGTH - 1); // get the client name
273  // check here if object is requested or nameslist? :
274  TObject *object = 0;
275  if (!strcmp(objectname, fgcCOMGETLIST)) {
276  // get analysis nameslist object
277  TGo4LockGuard mainguard; // protect creation of new nameslist
279  object = fxAnalysis->GetNamesList();
280  } else {
281  // get object from analysis
282  object = fxAnalysis->GetObject(objectname);
283  }
284  return SendObject(object);
285 }
286 
287 Bool_t TGo4HistogramServer::SendObject(TObject *object)
288 {
289  Bool_t retval = kTRUE;
290  // stream object into TBuffer:
291  TBuffer *rootbuffer = 0;
292  if (object != 0) {
293  fxTransport->Send(TGo4TaskHandler::Get_fgcOK()); // let client know the object exists
294  TGo4LockGuard mainguard;
295  rootbuffer = new TGo4Buffer(TBuffer::kWrite);
296  TFile *filsav = gFile;
297  gFile = 0;
298  rootbuffer->WriteObject(object);
299  gFile = filsav;
300  fxTransport->SendBuffer(rootbuffer);
301  delete rootbuffer;
302  } else {
303  // std::cout <<"Error: object not found in analysis!" << std::endl;
305  retval = kFALSE;
306  }
307  char *recvchar = fxTransport->RecvRaw("dummy"); // get exit message
308  if (recvchar == 0) {
309  TGo4Log::Debug(" HistogramServer: null character on finishing object client channel ");
310  retval = kFALSE;
311  } else if (strcmp(recvchar, TGo4TaskHandler::Get_fgcOK())) {
312  TGo4Log::Debug(" HistogramServer: ERROR on finishing object client channel ");
313  retval = kFALSE;
314  } else {
315  // std::cout <<"##### send object is finished with ok." << std::endl;
316  }
317  return retval;
318 }
319 
320 void TGo4HistogramServer::SetConnect(TGo4Socket *trans, const char *host, UInt_t port)
321 {
322  GO4TRACE((12, "TGo4HistogramServer::SetConnect(TGo4Socket *)", __LINE__, __FILE__));
323  fxConnectTransport = trans;
324  fcConnectHost = host;
325  fuConnectPort = port;
326  fbConnectRequest = kTRUE;
327 }
328 
330 {
331  GO4TRACE((12, "TGo4HistogramServer::SetDisConnect(TGo4Socket *)", __LINE__, __FILE__));
332  fxDisConnectTransport = trans;
333  fbDisConnectRequest = kTRUE;
334 }
335 
337 {
338  GO4TRACE((12, "TGo4HistogramServer::TimerConnect()", __LINE__, __FILE__));
339  Int_t rev = 0;
342  if (fbDisConnectRequest) {
343  GO4TRACE((15, "TGo4HistogramServer::TimerConnect()--DisConnectRequest", __LINE__, __FILE__));
344  if (fxDisConnectTransport != 0) {
345  // we have a transport instance to disconnect
347  fbConnectIsClose = kTRUE;
348  fbDisConnectRequest = kFALSE; // we served the request, reset it
349  rev += 1;
350  } else {
351  // error, zero pointer given
352  rev += 32;
353  }
354  } else
355  {
356  GO4TRACE((15, "TGo4HistogramServer::TimerConnect()--NO DisConnectRequest", __LINE__, __FILE__));
357  // no open request, continue
358  rev += 2;
359  }
360 
363  if (fbConnectRequest) {
364  GO4TRACE((15, "TGo4HistogramServer::TimerConnect()--ConnectRequest", __LINE__, __FILE__));
365  // timer shall open a transport as server
366  if (fxConnectTransport != 0) {
367  if (!fxConnectTransport->IsOpen()) {
368  GO4TRACE((10, "TGo4HistogramServer::TimerConnect()--transport is not open", __LINE__, __FILE__));
369  // transport is not open, so do it
370  fbConnectIsOpen = kTRUE; // tell connector thread that we try to open
371  // std::cout <<"TimerConnect: connect before open" << std::endl;
372  Int_t result = fxConnectTransport->Open(ConnectHost(), fuConnectPort, kTRUE);
373  if (result == 0) {
374  fbConnectIsDone = kTRUE; // tell connector thread we returned from open
375  fbConnectRequest = kFALSE; // we served the request, reset it
376  rev += 4;
377  } else {
378  rev = -4;
379  // open was not finished, we poll once again...
380  }
381  } else {
382  GO4TRACE((10, "TGo4HistogramServer::TimerConnect()--transport already open", __LINE__, __FILE__));
383  // transport was already open, do nothing
384  rev += 8;
385  }
386  } // if(fxConnectTransport!=0)
387  else {
388  GO4TRACE((10, "TGo4HistogramServer::TimerConnect()--no transport specified", __LINE__, __FILE__));
389  rev += 64;
390  }
391  }
392  else {
393  GO4TRACE((15, "TGo4HistogramServer::TimerConnect()--NO ConnectRequest", __LINE__, __FILE__));
394  // no open request, continue
395  rev += 16;
396  }
397  // std::cout <<"TimerConnect: before return" << std::endl;
398  return rev;
399 }
400 
402 {
403  GO4TRACE((12, "TGo4HistogramServer::WaitForOpen()", __LINE__, __FILE__));
404  Int_t count = 0;
405  while (!fbConnectIsOpen) {
406  TGo4Task *task = fxAnalysisClient->GetTask();
408  count = -1; // timeout
409  break;
410  } else if (task == 0 || task->IsTerminating()) {
411  // note: task==0 is case of shutdown of analysis server!
412  count = -2;
413  break;
414  } else {
416  ++count;
417  }
418  // std::cout << "*****WaitForOpen()"<< std::endl;
419  }
420  fbConnectIsOpen = kFALSE; // reset for next time
421  return count;
422 }
423 
425 {
426  GO4TRACE((12, "TGo4HistogramServer::WaitForClose()", __LINE__, __FILE__));
427  Int_t count = 0;
428  while (!fbConnectIsClose) {
429  // std::cout <<"Waiting for close..." << std::endl;
431  // std::cout <<"reached closewaitcycles "<< count << std::endl;
432  count = -1; // timeout
433  break;
434  } else {
436  ++count;
437  }
438  // std::cout << "*****WaitForClose() "<<count<< std::endl;
439  }
440  fbConnectIsClose = kFALSE; // reset for next time
441  return count;
442 }
443 
445 {
446  GO4TRACE((12, "TGo4HistogramServer::WaitForConnection()", __LINE__, __FILE__));
447  Int_t count = 0;
448  while (!fbConnectIsDone) {
449  TGo4Task *task = fxAnalysisClient->GetTask();
450  if (task == 0 || task->IsTerminating()) {
451  // note: task==0 is case of shutdown of analysis server!
452  count = -2; // termination mode
453  break;
454  } else {
456  ++count;
457  }
458  // std::cout << "*****WaitForConnection()"<< std::endl;
459  }
460  fbConnectIsDone = kFALSE; // reset for next time
461  return count;
462 }
463 
465 {
466  if (fxTransport) {
468  }
469  return fuObjectPort;
470 }
TGo4ThreadHandler * GetThreadHandler()
Definition: TGo4Slave.cxx:137
virtual Int_t Close(Option_t *opt="")
Definition: TGo4Socket.cxx:212
static UInt_t Get_fguPORTWAITTIME()
virtual Int_t Send(TObject *obj)
Definition: TGo4Socket.cxx:338
const char * ConnectHost() const
Int_t SendBuffer(TBuffer *buf)
Definition: TGo4Socket.cxx:222
static void UnRegister(TGo4CommandReceiver *p)
static const char * fgcCONTHREADNAME
#define COMM__SUCCESS
Definition: s_his_comm.h:27
TGo4ObjConnectorTimer * fxConnectorTimer
TGo4AnalysisClient * fxAnalysisClient
static const Int_t fgiCLOSEWAITCYCLES
static const char * Get_fgcERROR()
const char * ObjectThreadName() const
static void Sleep(UInt_t millisecs)
Definition: TGo4Thread.cxx:336
static const char * Get_fgcOK()
friend class TGo4HisConnectorRunnable
static void Register(const char *name, TGo4CommandReceiver *p)
virtual Int_t Open(const char *host, Int_t port, Bool_t keepservsock=kFALSE)
Definition: TGo4Socket.cxx:92
Bool_t NewThread(const char *name, TGo4Runnable *runnable)
INTS4 f_his_close(void)
Definition: f_his_hist.c:706
static const Int_t fgiOPENWAITCYCLES
int INTS4
Definition: typedefs.h:28
TGo4ThreadHandler * fxThreadHandler
static const char * fgcSHUTDOWNNAME
static TGo4CommandInvoker * Instance()
void Message(Int_t prio, const char *text,...)
TGo4Task * GetTask()
Definition: TGo4TaskOwner.h:41
TGo4Analysis * GetAnalysis() const
static const UInt_t fguCONNECTWAITCYCLETIME
static const char * fgcOBJTHREADNAME
Bool_t Stop(const char *thname)
static const UInt_t fguTIMERPERIOD
const char * GetName() const
void SetDisConnect(TGo4Socket *trans)
Bool_t Start(const char *thname)
const char * ConnectorName() const
#define TGo4Buffer
Definition: TGo4Buffer.h:27
TGo4Socket * fxConnectTransport
#define GO4TRACE(X)
Definition: TGo4Log.h:26
INTS4 f_his_gethis(CHARS *pc_server, INTS4 l_port, CHARS *pc_base, CHARS *pc_access, CHARS *pc_histo, s_his_head **p_head, INTS4 **p_buffer, INTS4 *pl_size)
Definition: f_his_hist.c:311
TGo4AnalysisObjectNames * GetNamesList() const
virtual Int_t TimerConnect()
static const UInt_t fguOPENWAITCYCLETIME
Bool_t RemoveThread(const char *name)
static const Int_t fgiCONNECTWAITCYCLES
static const UInt_t fguCLOSEWAITCYCLETIME
TNamed * GetObject(const char *name, const char *folder=0)
Bool_t IsTerminating() const
static Int_t Get_fgiPORTWAITCYCLES()
Int_t GetPort() const
Definition: TGo4Socket.h:40
Bool_t IsOpen() const
Definition: TGo4Socket.h:36
char CHARS
Definition: typedefs.h:21
INTS4 f_his_server(CHARS *pc_base, CHARS *pc_access, INTS4 *pl_port)
Definition: f_his_hist.c:418
static const char * fgcCOMGETLIST
static TGo4Analysis * Instance()
virtual char * RecvRaw(const char *name=0)
Definition: TGo4Socket.cxx:407
TGo4Socket * fxDisConnectTransport
Bool_t SendObject(TObject *obj)
void SetConnect(TGo4Socket *trans, const char *host, UInt_t port)
static void Debug(const char *text,...)
Definition: TGo4Log.cxx:284