source: trunk/MagicSoft/Mars/mbase/MReadSocket.cc@ 9492

Last change on this file since 9492 was 8750, checked in by tbretz, 17 years ago
*** empty log message ***
File size: 7.7 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz, 10/2003 <mailto:tbretz@astro.uni.wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2003
21!
22!
23\* ======================================================================== */
24
25
26//////////////////////////////////////////////////////////////////////////////
27//
28// MReadSocket
29//
30// This class acts like a standard C++ istream, but read from a socket
31// (ifstream works similar)
32//
33// ios::io_state:
34// --------------
35// eof() or ios::eofbit: Connection closed or not established
36// fail() or ios::failbit: Error trying to establish connection or
37// waiting for data in underflow() timed out
38// good() tells you that everything is ok and we can read from the stream
39//
40// Example:
41// --------
42//
43// Double_t d;
44//
45// MReadSocket sin(1024); // open port 1024
46//
47// sin >> d;
48// sin.read((char*)&d, sizeof(Double_t));
49//
50//
51//////////////////////////////////////////////////////////////////////////////
52#include "MReadSocket.h"
53
54#include <unistd.h> // usleep
55
56#include <TMath.h> // TMath::Min
57#include <TTime.h> // TTime
58#include <TDatime.h> // TDatime
59#include <TSystem.h> // gSystem
60#include <TSocket.h> // TSocket
61#include <TServerSocket.h> // TServerSocket
62
63ClassImp(MReadSocket);
64
65using namespace std;
66
67// --------------------------------------------------------------------------
68//
69// You can use the constructor in two ways:
70//
71// MReadSocket read(7000);
72// This opens the socket and blocks until the connection has been
73// established.
74//
75// MReadSocket read;
76// Returns immidiatly. The connection will be opend by calling
77// read.Open(7000);
78//
79MReadSocket::MReadSocket(int port, int mtu) : istream(this), fMtu(mtu), fTimeout(2500), fServSock(NULL), fRxSocket(NULL)
80{
81 fBuffer = new char[mtu];
82
83 setg(fBuffer, fBuffer, fBuffer+1);
84
85 clear(ios::eofbit);
86
87 if (port>0)
88 Open(port);
89}
90
91// --------------------------------------------------------------------------
92//
93// Destructor. Close an possible open connection and delete the fBuffer
94//
95MReadSocket::~MReadSocket()
96{
97 Close();
98 delete fBuffer;
99}
100
101void MReadSocket::OpenServerSocket(int port)
102{
103 if (fServSock)
104 return;
105
106 cout << "Starting server socket on port #" << port << "..." << endl;
107
108 while (!fServSock)
109 {
110 fServSock=new TServerSocket(port, kTRUE);
111 if (fServSock->IsValid())
112 continue;
113
114 cout << "ServerSocket not valid: ";
115 switch (fServSock->GetErrorCode())
116 {
117 case 0: cout << "No error." << endl; break;
118 case -1: cout << "low level socket() call failed." << endl; break;
119 case -2: cout << "low level bind() call failed." << endl; break;
120 case -3: cout << "low level listen() call failed." << endl; break;
121 default: cout << "Unknown." << endl; break;
122 }
123
124 Close();
125 clear(ios::failbit);
126 return;
127 }
128
129 fServSock->SetOption(kNoBlock, 1);
130}
131
132void MReadSocket::OpenConnection(Bool_t block)
133{
134 do
135 {
136 const TTime timeout = gSystem->Now() + TTime(5000);
137
138 cout << TDatime().AsString() << ": Waiting for connection..." << endl;
139
140 //
141 // fRxSocket<0 means: No connection,non-blocking mode
142 // fRxSocket==0 means: Error
143 // This is only done until timeout is reached
144 //
145 while (fRxSocket==0 && gSystem->Now()<timeout)
146 {
147 fRxSocket = fServSock->Accept();
148 if (fRxSocket==0)
149 {
150 cout << "MReadSocket::OpenConnection: ERROR - TServerSock::Accept()" << endl;
151 setstate(ios::failbit);
152 return;
153 }
154 if ((Long_t)fRxSocket<0)
155 fRxSocket=NULL;
156
157 usleep(10);
158 }
159
160 //
161 // No connection has been established. Restart waiting for
162 // connection except we are in non-blocking mode.
163 //
164 if (fRxSocket==0)
165 continue;
166
167 //
168 // Check if the established connection is valid
169 //
170 if (fRxSocket->IsValid())
171 {
172 cout << "Connection established..." << endl;
173 fRxSocket->SetOption(kNoBlock, 1);
174 clear();
175 return;
176 }
177
178 cout << "TSocket: Connection not valid..." << endl;
179 delete fRxSocket;
180 fRxSocket=NULL;
181 setstate(ios::failbit);
182 return;
183
184 } while (block);
185}
186
187// --------------------------------------------------------------------------
188//
189// Open the connectionj on port port. Wait until the connection has
190// been established. If an error occures and the connection cannot
191// be established return kFALSE. To check whether an error occured
192// use operator!() or operator void*() or fail()
193//
194Bool_t MReadSocket::Open(int port, Bool_t block)
195{
196 //
197 // If no port is given use the port given in the constructor
198 //
199 if (port<=0)
200 port = fPort;
201
202 //
203 // Remember port for later uses
204 //
205 if (fPort<=0)
206 fPort = port;
207
208 //
209 // Check whether a connection has already been established
210 //
211 if (fServSock)
212 {
213 //
214 // Check whether the connection has the right port
215 //
216 if (fServSock->GetLocalPort()!=port)
217 Close();
218 }
219
220 //
221 // Check whether port is valid
222 //
223 if (port<=0)
224 {
225 cout << "Invalid port #" << port << "!" << endl;
226 clear(ios::failbit);
227 return kFALSE;
228 }
229
230 //
231 // Start server socket...
232 //
233 OpenServerSocket(port);
234 if (!fServSock)
235 return kFALSE;
236
237 OpenConnection(block);
238 if (!fRxSocket)
239 return kFALSE;
240
241 underflow();
242 return kTRUE;
243}
244
245void MReadSocket::Close()
246{
247 if (fRxSocket)
248 {
249 delete fRxSocket;
250 fRxSocket=NULL;
251 }
252 if (fServSock)
253 {
254 const Int_t port = fServSock->GetLocalPort();
255
256 delete fServSock;
257 fServSock=NULL;
258
259 cout << "Connection on Port #" << port << " closed." << endl;
260 }
261
262 clear(ios::eofbit);
263}
264
265// --------------------------------------------------------------------------
266//
267// This is called to flush the buffer of the streaming devices
268//
269int MReadSocket::sync()
270{
271 cout << "sync" << endl;
272 return 0;
273}
274
275int MReadSocket::underflow()
276{
277 // FIXME: vvvvv is this correct?
278 if (fail() || eof())
279 {
280 setg(fBuffer, fBuffer, fBuffer+fMtu);
281 return 0;
282 }
283
284 //
285 // This simple trick should do its job, because the
286 // TCP/IP stream is buffered already
287 //
288 const TTime timeout = fTimeout+gSystem->Now();
289
290 Int_t len=-1;
291 while (len<0 && gSystem->Now()<timeout)
292 {
293 Int_t l;
294 fRxSocket->GetOption(kBytesToRead, l);
295 if (l==0)
296 {
297 gSystem->Sleep(1);
298 continue;
299 }
300 len = fRxSocket->RecvRaw(fBuffer, TMath::Min(fMtu, l));
301 }
302
303 if (len<0)
304 {
305 cout << "MReadSocket: TSocket::RecvRaw - Connection timed out." << endl;
306 setstate(ios::failbit);
307 memset(fBuffer, 0, fMtu);
308 len = fMtu;
309 }
310
311 setg(fBuffer, fBuffer, fBuffer+len);
312 return 0;
313}
Note: See TracBrowser for help on using the repository browser.