GSI Object Oriented Online Offline (Go4) GO4-6.4.0
Loading...
Searching...
No Matches
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
31const Int_t TGo4Socket::fguOPENWAIT=200;
32const Int_t TGo4Socket::fgiOPENCYCLES=6;
33const Int_t TGo4Socket::fgiBUFLENGTH=256;
34const Int_t TGo4Socket::fgiBUFINITSIZE=65536;
36const char *TGo4Socket::fgcGOON = "-I- go on";
37
38TGo4Socket::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
92Int_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
210Int_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
220Int_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)
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
332Int_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
366Int_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 {
376
377#ifdef Linux
378 rev = gSystem->SendRaw(fxSocket->GetDescriptor(), fxLocalBuffer,TGo4Socket::fgiBUFLENGTH, MSG_NOSIGNAL);
379#else
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
401char *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
431TObject *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
461void 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}
#define TGo4LockGuard
#define GO4TRACE(X)
Definition TGo4Log.h:25
static void Debug(const char *text,...) GO4_PRINTF_ARGS
User shortcut for message with prio 0.
Definition TGo4Log.cxx:281
static void SetSigWINCH(Bool_t enabled=kTRUE)
char * fxLocalBuffer
Definition TGo4Socket.h:102
Int_t ReceiveBuffer()
Receive raw buffer and fill the internal TBuffer of this socket instance with it.
Bool_t fbOpen
True if connection is open.
Definition TGo4Socket.h:91
TServerSocket * fxServerSocket
Server Socket (server mode only)
Definition TGo4Socket.h:97
static const Int_t fguOPENWAIT
Time to sleep between client open retries.
Definition TGo4Socket.h:62
Bool_t IsOpen() const
Definition TGo4Socket.h:37
static const Int_t fgiBUFINITSIZE
Initial size for object receive buffer (TBuffer)
Definition TGo4Socket.h:71
TSocket * fxSocket
root TSocket class doing the work
Definition TGo4Socket.h:94
virtual Int_t Send(TObject *obj)
virtual ~TGo4Socket()
virtual Int_t Close(Option_t *opt="")
static const Int_t fgiBUFEXTRASPACE
ROOT internal constant: extra space for reallocating object receive buffer (TBuffer)
Definition TGo4Socket.h:74
static const Int_t fgiBUFLENGTH
Raw transport buffer size.
Definition TGo4Socket.h:68
virtual Int_t Open(const char *host, Int_t port, Bool_t keepservsock=kFALSE)
virtual TObject * Recv(const char *name=nullptr)
Bool_t fbClientMode
True if instance runs in as client.
Definition TGo4Socket.h:88
static const char * fgcGOON
First connection string, we are told to go on...
Definition TGo4Socket.h:77
static const Int_t fgiOPENCYCLES
Number of retries for client open.
Definition TGo4Socket.h:65
TGo4Socket()=delete
TBuffer * fxBuffer
aggregation 1
Definition TGo4Socket.h:106
Int_t SendBuffer(TBuffer *buf)
Send raw buffer of external TBuffer object.
Int_t fiPort
Connected port number (of server socket which opened with portnumberscan)
Definition TGo4Socket.h:100
void ReallocBuffer(TBuffer *buffer, Int_t oldsize, Int_t newsize)
Reallocate the fixed input buffer if necessary.
virtual char * RecvRaw(const char *name=nullptr)