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