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