GSI Object Oriented Online Offline (Go4)  GO4-6.1.4
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
TGo4Socket.cxx
Go to the documentation of this file.
1 // $Id: TGo4Socket.cxx 2754 2020-04-16 11:13:50Z 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 "TGo4Socket.h"
15 
16 #ifndef WIN32
17 #include <sys/types.h>
18 #include <sys/socket.h>
19 #endif
20 
21 #include "TMessage.h"
22 #include "TSystem.h"
23 #include "TSocket.h"
24 #include "TServerSocket.h"
25 
26 #include "TGo4Log.h"
27 #include "TGo4LockGuard.h"
28 #include "TGo4Buffer.h"
30 
31 const Int_t TGo4Socket::fguOPENWAIT=200;
32 const Int_t TGo4Socket::fgiOPENCYCLES=6;
33 const Int_t TGo4Socket::fgiBUFLENGTH=256;
34 const Int_t TGo4Socket::fgiBUFINITSIZE=65536;
35 const Int_t TGo4Socket::fgiBUFEXTRASPACE=8;
36 const char* TGo4Socket::fgcGOON = "-I- go on";
37 
38 TGo4Socket::TGo4Socket(Bool_t IsClient) :
39  fbClientMode(IsClient),
40  fbOpen(kFALSE),
41  fxSocket(0),
42  fxServerSocket(0),
43  fiPort(0),
44  fxLocalBuffer(0),
45  fxBuffer(0)
46 {
47  GO4TRACE((14,"TGo4Socket::TGo4Socket(Bool_t)", __LINE__, __FILE__));
48 
49  fxBuffer = new TGo4Buffer(TBuffer::kRead, TGo4Socket::fgiBUFINITSIZE);
50 
51  // SL: 10-11-12 no idea why this handler was set
53 
54  // SL: 10-11-12 do not crash program when socket broken
56 
58  if(fbClientMode)
59  TGo4Log::Debug(" Created new Go4Socket in client mode ");
60  else
61  TGo4Log::Debug(" Created new Go4Socket in server mode ");
62 }
63 
65 {
66  GO4TRACE((14,"TGo4Socket::~TGo4Socket()", __LINE__, __FILE__));
67 
68  if (fxBuffer!=0) {
69  // SL: 10-11-12 fix memory leak
70  delete fxBuffer;
71  fxBuffer = 0;
72  }
73 
74  if (fxLocalBuffer) {
75  delete [] fxLocalBuffer;
76  fxLocalBuffer = 0;
77  }
78 
79  if(fxSocket) {
80  fxSocket->Close();
81  delete fxSocket;
82  fxSocket = 0;
83  }
84 
85  if(fxServerSocket) {
86  fxServerSocket->Close();
87  delete fxServerSocket;
88  fxServerSocket = 0;
89  }
90 }
91 
92 Int_t TGo4Socket::Open(const char* host, Int_t port, Bool_t keepservsock)
93 {
94  GO4TRACE((12,"TGo4Socket::Open(const char* host, Int_t port)", __LINE__, __FILE__));
95 
96  if(fbOpen) return 1;
97 
98  Int_t rev=0;
99 
100  if(fbClientMode) {
101  // client socket
102  fxSocket = new TSocket(host, port);
103  Int_t maxcounter=0;
104  while(!fxSocket->IsValid())
105  {
106  if(++maxcounter> TGo4Socket::fgiOPENCYCLES)
107  {
108  TGo4Log::Debug(" Socket: Open timeout!!");
109  break;
110  }
111  else
112  {
113  TGo4Log::Debug(" Socket: Open retry %d ", maxcounter);
114  delete fxSocket;
115  gSystem->Sleep(TGo4Socket::fguOPENWAIT);
116  fxSocket = new TSocket(host, port);
117  }
118  } // while()
119  if(!fxSocket->IsValid())
120  {
121  TGo4Log::Debug(" Socket: Open(const char* host, Int_t port ) as Client failed ");
122  fiPort=0;
123  return -8;
124  }
125  else
126  {
127  fxSocket->SetOption(kNoBlock,0); // set blocking
128  fiPort=fxSocket->GetLocalPort(); // success, get real port number
129  }
130  char str[32];
131  fxSocket->Recv(str, 32);
132  if(!strcmp(str,TGo4Socket::fgcGOON))
133  {
134  //std::cout << "-I- We are told to go on !\n";
135  fbOpen = kTRUE;
136  rev=0;
137  TGo4Log::Debug(" Socket: Connection Established ");
138  }
139  else
140  {
141  TGo4Log::Debug(" Socket: !!! Received unknown string !!! ");
142  }
143  }
144  else // if(fbClientMode)
145  {
146  // server socket:
147  if(!fxServerSocket)
148  {
149  fxServerSocket = new TServerSocket(port, kFALSE); // for portscan
150  fxServerSocket->SetOption(kNoBlock,1);
151  }
152  else
153  {
154  // do nothing, we poll existing server socket
155  }
156  if(!fxServerSocket->IsValid())
157  {
158  TGo4Log::Debug(" Socket: Open(const char* host, Int_t port) as Server failed ");
159  fiPort = 0;
160  return -8;
161  }
162  else
163  {
164  fiPort = fxServerSocket->GetLocalPort(); // success, get real port number
165  //std::cout << " ---- Go4 Socket got local port "<< fiPort << std::endl;
166  }
167  fxSocket = 0;
168  while(1)
169  {
170  if(!fxSocket)
171  {
172  fxSocket = fxServerSocket->Accept();
173  if(!fxSocket || fxSocket==(TSocket*) (-1) )
174  {
175  fxSocket=0;
176  rev=-1;
177  break;
178  // no connection request, leave loop
179  }
180  else
181  {
182  fxSocket->SetOption(kNoBlock,0); // server socket was non blocking, but socket shall block in wait!
184  if(!keepservsock)
185  {
186  fxServerSocket->Close();
187  delete fxServerSocket;
188  fxServerSocket = 0;
189  }
190  else
191  {
192  // do not delete serversocket in "keep" mode
193  // more performant for servers that should be
194  // idle quickly for repeated client requests
195  }// if(!keepservsock)
196  fbOpen = kTRUE;
197  rev=0;
198  break;
199  } // if(!fxSocket || fxSocket==(TSocket*) (-1) )
200  }
201  else
202  {
203  rev=-2; // TSocket already existing
204  break;
205  } // if(!fxSocket)
206  } // while(1)
207  } // end if(fbClientMode)
208  return rev;
209 }
210 
211 
212 Int_t TGo4Socket::Close(Option_t *opt)
213 {
214  GO4TRACE((12,"TGo4Socket::Close()", __LINE__, __FILE__));
215  if(!fbOpen) return 1;
216 
217  fxSocket->Close(opt);
218  fbOpen = kFALSE;
219  return 0;
220 }
221 
222 Int_t TGo4Socket::SendBuffer(TBuffer* buf)
223 {
224  GO4TRACE((12,"TGo4Socket::SendBuffer(TBuffer*)", __LINE__, __FILE__));
225 
226  if(!buf) {
227  TGo4Log::Debug(" !!! Socket: SendBuffer() ERROR : no buffer !!! ");
228  return -2;
229  }
230 
231  if(!IsOpen()) {
232  TGo4Log::Debug(" !!! Socket: SendBuffer() ERROR : socket not open !!! ");
233  return -1;
234  }
235 
236  if(!fxSocket) {
237  TGo4Log::Debug(" !!! Socket: SendBuffer() ERROR : no TSocket !!! ");
238  return -5;
239  } // end if(fxSocket)
240 
241 
242  UInt_t len = buf->Length();
243  char* field = buf->Buffer();
244 
245  if(field==0) {
246  TGo4Log::Debug(" !!! Socket: SendBuffer() ERROR : no data field !!! ");
247  return -5;
248  }
249 
250  char* temp = field;
251  tobuf(temp, (UInt_t)(len - sizeof(UInt_t))); // tobuf changes pointer!
252  //set length into first word of buffer (see TMessage)
254  // std::cout << "))))))))) socket send: buffer length in buffer ";
255  // UInt_t dummy=0;
256  // temp=field;
257  // frombuf(temp,&dummy);
258  // std::cout << dummy << std::endl;
260 
261  // send complete buffer
262 #ifdef Linux
263  Int_t rev = gSystem->SendRaw(fxSocket->GetDescriptor(), field, len, MSG_NOSIGNAL);
264 #else
265  Int_t rev = fxSocket->SendRaw(field, len);
266 #endif
267 
268  if(rev>0) return 0;
269 
270  // error on send
271  TGo4Log::Debug(" !!! Socket: SendBuffer() ERROR # %d !!! ",rev);
272  return rev;
273 }
274 
276 {
277  GO4TRACE((12,"TGo4Socket::ReceiveBuffer()", __LINE__, __FILE__));
278 
279  if(!IsOpen()) {
280  TGo4Log::Debug(" !!! Socket: ReceiveBuffer() ERROR : not open !!! ");
281  return -11;
282  }
283 
284  if(!fxSocket) {
285  TGo4Log::Debug(" !!! Socket: ReceiveBuffer() ERROR : no TSocket !!! ");
286  return -10;
287  } // end if(fxSocket)
288 
289  UInt_t len = 0;
290  // first receive length of following buffer
291 #ifdef Linux
292  Int_t rev = gSystem->RecvRaw(fxSocket->GetDescriptor(), &len, sizeof(UInt_t), MSG_NOSIGNAL);
293 #else
294  Int_t rev = fxSocket->RecvRaw(&len, sizeof(UInt_t));
295 #endif
296  if(rev <= 0) {
297  // error on receive
298  //TGo4Log::Debug(" !!! Socket: ReceiveBuffer() -- receive length ERROR # %d !!! ",rev);
299  // no output here, we will redirect std::cout client runnable (command)
300  return -55;
301  }
302  // check if length exceeds receive buffer
303  len = net2host(len); //from network to host byte order
304  Int_t messlen = len + sizeof(UInt_t); // compatible with root TMessage protocol
305  // std::cout << "))))))))) socket receive: buffer length "<< len << std::endl;
306  // std::cout << "))))))))) socket receive: messlen "<< messlen << std::endl;
307  Int_t oldsize = fxBuffer->BufferSize();
308  Int_t newsize = messlen;
309  if(newsize>oldsize) {
310  ReallocBuffer(fxBuffer, oldsize, newsize);
311  } else
312  if(newsize<oldsize && oldsize>TGo4Socket::fgiBUFINITSIZE) {
313  //std::cout << "))))))))) socket receive shorter messlen "<< messlen << std::endl;
314  if(newsize < TGo4Socket::fgiBUFINITSIZE)
315  newsize = TGo4Socket::fgiBUFINITSIZE;
316  ReallocBuffer(fxBuffer, oldsize, newsize);
317  }
318  // read object buffer into receive buffer:
319  char* buf = fxBuffer->Buffer()+sizeof(UInt_t);
320  // skip first word, see TMessage transport
321 #ifdef Linux
322  rev = gSystem->RecvRaw(fxSocket->GetDescriptor(), buf, len, MSG_NOSIGNAL);
323 #else
324  rev = fxSocket->RecvRaw((void*) buf, len);
325 #endif
326  if(rev <= 0) {
327  // error on receive
328  TGo4Log::Debug(" !!! Socket: ReceiveBuffer() ERROR # %d !!! ",rev);
329  return -56;
330  }
331  // std::cout << "socket: received raw "<< rev << " bytes" << std::endl;
332  // set root byte count for correct object reconstruction:
333  fxBuffer->SetBufferOffset(messlen);
334  fxBuffer->SetByteCount(0);
335  return 0;
336 }
337 
338 Int_t TGo4Socket::Send(TObject *obj)
339 {
340  GO4TRACE((12,"TGo4Socket::Send(TObject *obj)", __LINE__, __FILE__));
341 
342  Int_t rev=0;
343  if(IsOpen())
344  {
345 
346  TMessage mess(kMESS_OBJECT);
347  {
348  TGo4LockGuard guard; // use main mutex
349  mess.WriteObject(obj);
350  }
351 
352  if(fxSocket)
353  {
354  rev = fxSocket->Send(mess);
355  }
356  else
357  {
358  rev=-16;
359  } // end if(fxSocket)
360  } // if(IsOpen())
361  else {
362  // do not send on closed socket
363  rev=-32;
364  } // end if(IsOpen() && IsActive())
365 
366  if(rev < 0)
367  TGo4Log::Debug(" !!! Socket: Send(TObject*) ERROR # %d !!! ",rev);
368 
369  return rev;
370 }
371 
372 Int_t TGo4Socket::Send(const char* name)
373 {
374  GO4TRACE((12,"TGo4Socket::Send(const char* name)", __LINE__, __FILE__));
375 
376  Int_t rev=0;
377  if(IsOpen())
378  {
379  if(fxSocket)
380  {
381  strncpy(fxLocalBuffer,name, TGo4Socket::fgiBUFLENGTH-1);
382 
383 #ifdef Linux
384  rev = gSystem->SendRaw(fxSocket->GetDescriptor(), fxLocalBuffer,TGo4Socket::fgiBUFLENGTH, MSG_NOSIGNAL);
385 #else
386  rev = fxSocket->SendRaw(fxLocalBuffer,TGo4Socket::fgiBUFLENGTH);
387 #endif
388  }
389  else
390  {
391  rev=-16;
392  } // end if(fxSocket)
393  } // if(IsOpen())
394  else
395  {
396  // do not send on closed socket
397  rev=-32;
398  } // end if(IsOpen())
399 
400  if(rev < 0)
401  {
402  TGo4Log::Debug(" !!! Socket: Send(const char*) ERROR # %d !!! ",rev);
403  }
404  return rev;
405 }
406 
407 char* TGo4Socket::RecvRaw(const char* name)
408 {
409 // note: optional parameter const char* name is left for compatibility, has no effect!
410  GO4TRACE((12,"TGo4Socket::RecvRaw(const char* name)", __LINE__, __FILE__));
411 
412  if(!IsOpen()) {
413  TGo4Log::Debug(" !!! Socket: Recv(const char*) ERROR : not open or not active !!! ");
414  return 0;
415  }
416 
417  if (!fxSocket) {
418  TGo4Log::Debug(" !!! Socket: Recv(const char*) ERROR : no TSocket !!! ");
419  return 0;
420  }
421 #ifdef Linux
422  Int_t rev = gSystem->RecvRaw(fxSocket->GetDescriptor(), fxLocalBuffer, TGo4Socket::fgiBUFLENGTH, MSG_NOSIGNAL);
423 #else
424  Int_t rev = fxSocket->RecvRaw(fxLocalBuffer, TGo4Socket::fgiBUFLENGTH);
425 #endif
426 
427  if(rev<=0) {
428  // error on receive
429  TGo4Log::Debug(" !!! Socket: RecvRaw(const char*) ERROR # %d !!! ",rev);
430  return 0;
431  }
432 
433  return fxLocalBuffer;
434 }
435 
436 
437 
438 TObject* TGo4Socket::Recv(const char* name)
439 {
440  // note: optional parameter const char* name is left for compatibility, has no effect!
441  GO4TRACE((12,"TGo4Socket::Recv(const char* name)", __LINE__, __FILE__));
442 
443  TObject* obj=0;
444  if(IsOpen())
445  {
446  if(fxSocket)
447  {
448  TMessage *mess = 0;
449  fxSocket->Recv(mess);
450 
451  if(mess == 0)
452  {
453  //std::cout << "TGo4SocketTransportImp: zero mess" << std::endl;
454  obj=0;
455  }
456  else
457  {
458  TGo4LockGuard socker;
459  if(mess->What() == kMESS_OBJECT)
460  {
461  obj = mess->ReadObject(mess->GetClass());
462  }
463  delete mess;
464  } // end if(mess == NULL)
465 
466  } // if (fxSocket)
467  else
468  {
469  TGo4Log::Debug(" !!! Socket: Recv(TMessage*) ERROR : no TSocket! ");
470  } // end if (fxSocket)
471  }
472  else // if(IsOpen())
473  {
474  TGo4Log::Debug(" !!! Socket: Recv(TMessage*) ERROR : not open or not active! ");
475  }
476  return obj;
477 }
478 
479 
480 void TGo4Socket::ReallocBuffer(TBuffer* buffer, Int_t oldsize, Int_t newsize)
481 {
482  if(buffer==0) return;
483  TGo4LockGuard mainguard;
484  char* memfield = buffer->Buffer();
485  //buffer->Expand(newsize); // is protected! we make it by hand...
486  //Int_t current = buffer->Length(); // cursor position
487  Int_t extraspace = TGo4Socket::fgiBUFEXTRASPACE; // =8, constant within TBuffer
488  // memfield = (char *) TStorage::ReAlloc(memfield,
489  // (newsize + extraspace) * sizeof(char),
490  // (oldsize+ extraspace) * sizeof(char));
491  // this works only for ROOT versions > 3.02/04:
492  memfield = TStorage::ReAllocChar(memfield,
493  (newsize+extraspace),
494  (oldsize+extraspace));
495  //std::cout << "Socket reallocating char receive buffer from "<<oldsize<< " to " << newsize<< std::endl;
496  buffer->ResetBit(TBuffer::kIsOwner);
497 
498  buffer->SetBuffer(memfield, newsize);
499 
500  buffer->SetBit(TBuffer::kIsOwner);
501  // <- here we avoid the ownership of TBuffer for the internal buffer
502  // (new feature of ROOT versions > 3.02/04)
503  // problem: SetBuffer will delete previous buffer in adopt mode (isowner=true)
504  // which might be at the same location as the new buffer after ReAlloc
505  // ergo SetBuffer would set a buffer which it deleted before itself!
506  buffer->SetBufferOffset(newsize);
507 }
virtual Int_t Close(Option_t *opt="")
Definition: TGo4Socket.cxx:212
TBuffer * fxBuffer
Definition: TGo4Socket.h:105
virtual Int_t Send(TObject *obj)
Definition: TGo4Socket.cxx:338
virtual TObject * Recv(const char *name=0)
Definition: TGo4Socket.cxx:438
Int_t SendBuffer(TBuffer *buf)
Definition: TGo4Socket.cxx:222
static const Int_t fgiOPENCYCLES
Definition: TGo4Socket.h:64
static const Int_t fguOPENWAIT
Definition: TGo4Socket.h:61
TServerSocket * fxServerSocket
Definition: TGo4Socket.h:96
virtual Int_t Open(const char *host, Int_t port, Bool_t keepservsock=kFALSE)
Definition: TGo4Socket.cxx:92
static const Int_t fgiBUFLENGTH
Definition: TGo4Socket.h:67
TSocket * fxSocket
Definition: TGo4Socket.h:93
static const char * fgcGOON
Definition: TGo4Socket.h:76
Bool_t fbClientMode
Definition: TGo4Socket.h:87
Int_t ReceiveBuffer()
Definition: TGo4Socket.cxx:275
virtual ~TGo4Socket()
Definition: TGo4Socket.cxx:64
static const Int_t fgiBUFINITSIZE
Definition: TGo4Socket.h:70
void ReallocBuffer(TBuffer *buffer, Int_t oldsize, Int_t newsize)
Definition: TGo4Socket.cxx:480
static void SetSigWINCH(Bool_t enabled=kTRUE)
#define TGo4Buffer
Definition: TGo4Buffer.h:27
Int_t fiPort
Definition: TGo4Socket.h:99
Bool_t fbOpen
Definition: TGo4Socket.h:90
#define GO4TRACE(X)
Definition: TGo4Log.h:26
Bool_t IsOpen() const
Definition: TGo4Socket.h:36
virtual char * RecvRaw(const char *name=0)
Definition: TGo4Socket.cxx:407
static const Int_t fgiBUFEXTRASPACE
Definition: TGo4Socket.h:73
char * fxLocalBuffer
Definition: TGo4Socket.h:101
static void Debug(const char *text,...)
Definition: TGo4Log.cxx:274