GSI Object Oriented Online Offline (Go4)  GO4-6.3.0
TGo4HistogramServer.cxx
Go to the documentation of this file.
1 // $Id$
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 #include "TBufferFile.h"
19 
20 #include "TGo4Log.h"
21 #include "TGo4LockGuard.h"
22 #include "TGo4Socket.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(nullptr), fiServerPort(0), fxTransport(nullptr), fuObjectPort(0),
58  fxConnectTransport(nullptr), fxDisConnectTransport(nullptr), fuConnectPort(0), fbConnectRequest(kFALSE),
59  fbDisConnectRequest(kFALSE), fbConnectIsOpen(kFALSE), fbConnectIsDone(kFALSE), fbConnectIsClose(kTRUE),
60  fxConnectorTimer(nullptr), 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  TGo4Analysis::Instance()->Message(3, "ERROR %d on creation of Histogram server", result);
74  }
75  // start connector thread:
76  const char *ownername;
77  if (fxAnalysisClient) {
80  ownername = fxAnalysisClient->GetName();
81  } else {
82  ownername = "never-come-here";
83  }
84 
85  if (fbUseObjectServer) {
87  fxConnectorTimer->TurnOn();
88  }
89  if (fxThreadHandler) {
90  // thread to serve gsi histogram api:
92  fxConnectorName += ownername;
93 
97  if (fbUseObjectServer) {
98 
99  // thread for root object server:
101  fxObjectThreadName += ownername;
102 
106  }
107  } else {
108  std::cerr << " Histogram Server constructor FATAL ERROR: no threadmanager !!" << std::endl;
109  throw TGo4RuntimeException();
110  }
111 }
112 
114  : fxAnalysisClient(nullptr), fxThreadHandler(nullptr), fiServerPort(0), fxTransport(nullptr), fuObjectPort(0), fxConnectTransport(nullptr),
116  fbDisConnectRequest(kFALSE), fbConnectIsOpen(kFALSE), fbConnectIsDone(kFALSE), fbConnectIsClose(kTRUE),
117  fbUseObjectServer(kFALSE)
118 {
119  TGo4CommandInvoker::Instance(); // make sure we have an invoker instance!
120  TGo4CommandInvoker::Register("HistogramServer", this);
121 }
122 
124 {
125  // prepare stopped flag:
128 
129  // for clean shutdown, we have to connect one last time to get out of the wait:
130  INTS4 *pl_all = nullptr;
131  s_his_head *ps_his_head = nullptr;
132  INTS4 l_size = 0;
133  f_his_gethis((char *)"localhost", fiServerPort, (char *)fxServerName.Data(), (char *)fxServerPass.Data(),
134  (char *)fgcSHUTDOWNNAME, (s_his_head **)&ps_his_head, &pl_all, &l_size);
135 
136  if (fxThreadHandler) {
139  if (fbUseObjectServer) {
141  // here we might connect last time to object server, to investigate!!
144  // this will cancel thread and delete runnable
145  }
146  }
147  delete fxConnectorTimer;
148  f_his_close(); // this will delete api server for histograms
149 
150  if (fxTransport) {
151  fxTransport->Close(); // close go4 server socket for object server
152  delete fxTransport;
153  fxTransport = nullptr;
154  }
155 
157 }
158 
160 {
161  Int_t rev = ConnectObjectClient();
162  if (rev < 0)
163  return rev;
164  if (rev == 0 && CheckLogin()) {
166  } else {
167  }
169  return rev;
170 }
171 
173 {
174  //
175  SetDisConnect(fxTransport); // timer shall do the Close() of negotiation
176  // TGo4Log::Debug(" HistogramServer: Waiting for timer Close() of client ... ");
177  WaitForClose(); // poll until timer has returned from close
178  // TGo4Log::Debug(" HistogramServer: Client connection closed. ");
179 }
180 
182 {
183 
184  static Bool_t isfirsttime = kTRUE;
185  // we delegate the actual TSocket open to the taskconnector timer:
186  SetConnect(fxTransport, "Server mode does not need hostname", 0); // for portscan
187  Int_t waitresult = WaitForOpen(); // wait for the server Open() call by timer
188  if (waitresult == -2)
189  return waitresult; // return in termination mode
190  if (waitresult < 0) {
191  // open timeout
192  TGo4Log::Debug(" HistogramServer: Negotiation channel open TIMEOUT");
193  std::cerr << " HistogramServer TIMEOUT ERROR opening socket connection !!! Terminating..." << std::endl;
195  }
196  Int_t count = 0;
197  while (GetObjPort() == 0) {
198  TGo4Task *task = fxAnalysisClient->GetTask();
200  TGo4Log::Debug(" HistogramServer: Negotiation port getter TIMEOUT");
201  std::cerr << " HistogramServer TIMEOUT ERROR retrieving port number !!! Terminating..." << std::endl;
203  } else if (!task || task->IsTerminating()) {
204  return -1;
205  } else {
207  ++count;
208  }
209  }
210  // TGo4Log::Debug(" HistogramServer is waiting to serve object client request on port %d ... ",
211  // fuObjectPort);
212  if (isfirsttime) {
213  // only tell gui the first time the port number; performance!
214  TGo4Analysis::Instance()->Message(1, "Object Server %s is waiting on port %d", fxServerName.Data(), fuObjectPort);
215  isfirsttime = kFALSE;
216  } else {
217  }
218  Int_t connectwaitseconds = WaitForConnection(); // timer tells us by flag when the transport is opened
219  if (connectwaitseconds < 0) {
220  // case of threadmanager termination:
221  // connector runnable shall stop on return from ServeClient method
222  return connectwaitseconds;
223  } else {
224  // just proceed to the client server negotiations
225  }
226 
227  return 0;
228 }
229 
231 {
233  // check for basename:
234  const char *recvchar = fxTransport->RecvRaw("dummy");
235  if (recvchar && !strcmp(recvchar, fxServerName.Data())) {
236  fxTransport->Send(TGo4TaskHandler::Get_fgcOK()); // handshake to assure the client
237  } else {
238  // TGo4Analysis::Instance()->Message(2,
239  // "Object server connection attempt with wrong basename");
240  std::cerr << "##### check login with wrong base" << std::endl;
243  return kFALSE;
244  }
245  // check for password:
246  recvchar = fxTransport->RecvRaw("dummy");
247  if (recvchar && !strcmp(recvchar, fxServerPass.Data())) {
248  fxTransport->Send(TGo4TaskHandler::Get_fgcOK()); // handshake to assure the client
249  } else {
250  // TGo4Analysis::Instance()->Message(2,
251  // "Object server connection attempt with wrong password");
252  std::cerr << "##### check login with wrong passwd" << std::endl;
255  return kFALSE;
256  }
257  return kTRUE;
258 }
259 
261 {
262  char objectname[TGo4ThreadManager::fguTEXTLENGTH];
263  // get object name
264  char *recvchar = fxTransport->RecvRaw("dummy");
265  if (!recvchar) {
266  std::cerr << "-----Object server received null character for object request!" << std::endl;
267  return kFALSE;
268  }
269  strncpy(objectname, recvchar, TGo4ThreadManager::fguTEXTLENGTH - 1); // get the client name
270  // check here if object is requested or nameslist? :
271  TObject *object = nullptr;
272  if (!strcmp(objectname, fgcCOMGETLIST)) {
273  // get analysis nameslist object
274  TGo4LockGuard mainguard; // protect creation of new nameslist
276  object = fxAnalysis->GetNamesList();
277  } else {
278  // get object from analysis
279  object = fxAnalysis->GetObject(objectname);
280  }
281  return SendObject(object);
282 }
283 
284 Bool_t TGo4HistogramServer::SendObject(TObject *object)
285 {
286  Bool_t retval = kTRUE;
287  // stream object into TBuffer:
288  TBuffer *rootbuffer = nullptr;
289  if (object) {
290  fxTransport->Send(TGo4TaskHandler::Get_fgcOK()); // let client know the object exists
291  TGo4LockGuard mainguard;
292  rootbuffer = new TBufferFile(TBuffer::kWrite);
293  TFile *filsav = gFile;
294  gFile = nullptr;
295  rootbuffer->WriteObject(object);
296  gFile = filsav;
297  fxTransport->SendBuffer(rootbuffer);
298  delete rootbuffer;
299  } else {
301  retval = kFALSE;
302  }
303  char *recvchar = fxTransport->RecvRaw("dummy"); // get exit message
304  if (!recvchar) {
305  TGo4Log::Debug(" HistogramServer: null character on finishing object client channel ");
306  retval = kFALSE;
307  } else if (strcmp(recvchar, TGo4TaskHandler::Get_fgcOK())) {
308  TGo4Log::Debug(" HistogramServer: ERROR on finishing object client channel ");
309  retval = kFALSE;
310  } else {
311  // send object is finished with ok
312  }
313  return retval;
314 }
315 
316 void TGo4HistogramServer::SetConnect(TGo4Socket *trans, const char *host, UInt_t port)
317 {
318  GO4TRACE((12, "TGo4HistogramServer::SetConnect(TGo4Socket *)", __LINE__, __FILE__));
319  fxConnectTransport = trans;
320  fcConnectHost = host;
321  fuConnectPort = port;
322  fbConnectRequest = kTRUE;
323 }
324 
326 {
327  GO4TRACE((12, "TGo4HistogramServer::SetDisConnect(TGo4Socket *)", __LINE__, __FILE__));
328  fxDisConnectTransport = trans;
329  fbDisConnectRequest = kTRUE;
330 }
331 
333 {
334  GO4TRACE((12, "TGo4HistogramServer::TimerConnect()", __LINE__, __FILE__));
335  Int_t rev = 0;
338  if (fbDisConnectRequest) {
339  GO4TRACE((15, "TGo4HistogramServer::TimerConnect()--DisConnectRequest", __LINE__, __FILE__));
340  if (fxDisConnectTransport) {
341  // we have a transport instance to disconnect
343  fbConnectIsClose = kTRUE;
344  fbDisConnectRequest = kFALSE; // we served the request, reset it
345  rev += 1;
346  } else {
347  // error, zero pointer given
348  rev += 32;
349  }
350  } else
351  {
352  GO4TRACE((15, "TGo4HistogramServer::TimerConnect()--NO DisConnectRequest", __LINE__, __FILE__));
353  // no open request, continue
354  rev += 2;
355  }
356 
359  if (fbConnectRequest) {
360  GO4TRACE((15, "TGo4HistogramServer::TimerConnect()--ConnectRequest", __LINE__, __FILE__));
361  // timer shall open a transport as server
362  if (fxConnectTransport) {
363  if (!fxConnectTransport->IsOpen()) {
364  GO4TRACE((10, "TGo4HistogramServer::TimerConnect()--transport is not open", __LINE__, __FILE__));
365  // transport is not open, so do it
366  fbConnectIsOpen = kTRUE; // tell connector thread that we try to open
367  Int_t result = fxConnectTransport->Open(ConnectHost(), fuConnectPort, kTRUE);
368  if (result == 0) {
369  fbConnectIsDone = kTRUE; // tell connector thread we returned from open
370  fbConnectRequest = kFALSE; // we served the request, reset it
371  rev += 4;
372  } else {
373  rev = -4;
374  // open was not finished, we poll once again...
375  }
376  } else {
377  GO4TRACE((10, "TGo4HistogramServer::TimerConnect()--transport already open", __LINE__, __FILE__));
378  // transport was already open, do nothing
379  rev += 8;
380  }
381  }
382  else {
383  GO4TRACE((10, "TGo4HistogramServer::TimerConnect()--no transport specified", __LINE__, __FILE__));
384  rev += 64;
385  }
386  }
387  else {
388  GO4TRACE((15, "TGo4HistogramServer::TimerConnect()--NO ConnectRequest", __LINE__, __FILE__));
389  // no open request, continue
390  rev += 16;
391  }
392  // std::cout <<"TimerConnect: before return" << std::endl;
393  return rev;
394 }
395 
397 {
398  GO4TRACE((12, "TGo4HistogramServer::WaitForOpen()", __LINE__, __FILE__));
399  Int_t count = 0;
400  while (!fbConnectIsOpen) {
401  TGo4Task *task = fxAnalysisClient->GetTask();
403  count = -1; // timeout
404  break;
405  } else if (!task || task->IsTerminating()) {
406  // note: task == nullptr is case of shutdown of analysis server!
407  count = -2;
408  break;
409  } else {
411  ++count;
412  }
413  }
414  fbConnectIsOpen = kFALSE; // reset for next time
415  return count;
416 }
417 
419 {
420  GO4TRACE((12, "TGo4HistogramServer::WaitForClose()", __LINE__, __FILE__));
421  Int_t count = 0;
422  while (!fbConnectIsClose) {
423  // Waiting for close...
425  count = -1; // timeout
426  break;
427  } else {
429  ++count;
430  }
431  }
432  fbConnectIsClose = kFALSE; // reset for next time
433  return count;
434 }
435 
437 {
438  GO4TRACE((12, "TGo4HistogramServer::WaitForConnection()", __LINE__, __FILE__));
439  Int_t count = 0;
440  while (!fbConnectIsDone) {
441  TGo4Task *task = fxAnalysisClient->GetTask();
442  if (!task || task->IsTerminating()) {
443  // note: task == nullptr is case of shutdown of analysis server!
444  count = -2; // termination mode
445  break;
446  } else {
448  ++count;
449  }
450  }
451  fbConnectIsDone = kFALSE; // reset for next time
452  return count;
453 }
454 
456 {
457  if (fxTransport) {
459  }
460  return fuObjectPort;
461 }
const char * GetName() const
TGo4ThreadHandler * GetThreadHandler()
Definition: TGo4Slave.cxx:133
virtual Int_t Close(Option_t *opt="")
Definition: TGo4Socket.cxx:210
static UInt_t Get_fguPORTWAITTIME()
Bool_t IsOpen() const
Definition: TGo4Socket.h:37
virtual Int_t Send(TObject *obj)
Definition: TGo4Socket.cxx:332
Int_t SendBuffer(TBuffer *buf)
Definition: TGo4Socket.cxx:220
static void UnRegister(TGo4CommandReceiver *p)
static const char * fgcCONTHREADNAME
#define COMM__SUCCESS
Definition: s_his_comm.h:27
TGo4Task * GetTask() const
Definition: TGo4TaskOwner.h:42
TGo4AnalysisObjectNames * GetNamesList() const
TGo4ObjConnectorTimer * fxConnectorTimer
TGo4AnalysisClient * fxAnalysisClient
static const Int_t fgiCLOSEWAITCYCLES
static const char * Get_fgcERROR()
static void Sleep(UInt_t millisecs)
Definition: TGo4Thread.cxx:295
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
const char * ObjectThreadName() const
Bool_t NewThread(const char *name, TGo4Runnable *runnable)
INTS4 f_his_close(void)
Definition: f_his_hist.c:706
static const Int_t fgiOPENWAITCYCLES
const char * ConnectHost() const
int INTS4
Definition: typedefs.h:28
static void Debug(const char *text,...) GO4_PRINTF_ARGS
Definition: TGo4Log.cxx:281
Int_t GetPort() const
Definition: TGo4Socket.h:41
TGo4ThreadHandler * fxThreadHandler
virtual char * RecvRaw(const char *name=nullptr)
Definition: TGo4Socket.cxx:401
static const char * fgcSHUTDOWNNAME
static TGo4CommandInvoker * Instance()
void Message(Int_t prio, const char *text,...)
static const UInt_t fguCONNECTWAITCYCLETIME
static const char * fgcOBJTHREADNAME
Bool_t Stop(const char *thname)
TGo4Analysis * GetAnalysis() const
static const UInt_t fguTIMERPERIOD
void SetDisConnect(TGo4Socket *trans)
Bool_t Start(const char *thname)
TNamed * GetObject(const char *name, const char *folder=nullptr)
TGo4Socket * fxConnectTransport
#define GO4TRACE(X)
Definition: TGo4Log.h:25
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
const char * ConnectorName() 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
Bool_t IsTerminating() const
static Int_t Get_fgiPORTWAITCYCLES()
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()
TGo4Socket * fxDisConnectTransport
Bool_t SendObject(TObject *obj)
void SetConnect(TGo4Socket *trans, const char *host, UInt_t port)