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

Last change on this file since 5972 was 2492, checked in by tbretz, 21 years ago
*** empty log message ***
File size: 7.8 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 TDatime now;
139 cout << now.AsString() << ": Waiting for connection..." << endl;
140
141 //
142 // fRxSocket<0 means: No connection,non-blocking mode
143 // fRxSocket==0 means: Error
144 // This is only done until timeout is reached
145 //
146 while (fRxSocket==0 && gSystem->Now()<timeout)
147 {
148 fRxSocket = fServSock->Accept();
149 if (fRxSocket==0)
150 {
151 cout << "MReadSocket::OpenConnection: ERROR - TServerSock::Accept()" << endl;
152 setstate(ios::failbit);
153 return;
154 }
155 if ((Long_t)fRxSocket<0)
156 fRxSocket=NULL;
157
158 usleep(10);
159 }
160
161 //
162 // No connection has been established. Restart waiting for
163 // connection except we are in non-blocking mode.
164 //
165 if (fRxSocket==0)
166 continue;
167
168 //
169 // Check if the established connection is valid
170 //
171 if (fRxSocket->IsValid())
172 {
173 cout << "Connection established..." << endl;
174 fRxSocket->SetOption(kNoBlock, 1);
175 clear();
176 return;
177 }
178
179 cout << "TSocket: Connection not valid..." << endl;
180 delete fRxSocket;
181 fRxSocket=NULL;
182 setstate(ios::failbit);
183 return;
184
185 } while (block);
186}
187
188// --------------------------------------------------------------------------
189//
190// Open the connectionj on port port. Wait until the connection has
191// been established. If an error occures and the connection cannot
192// be established return kFALSE. To check whether an error occured
193// use operator!() or operator void*() or fail()
194//
195Bool_t MReadSocket::Open(int port, Bool_t block)
196{
197 //
198 // If no port is given use the port given in the constructor
199 //
200 if (port<=0)
201 port = fPort;
202
203 //
204 // Remember port for later uses
205 //
206 if (fPort<=0)
207 fPort = port;
208
209 //
210 // Check whether a connection has already been established
211 //
212 if (fServSock)
213 {
214 //
215 // Check whether the connection has the right port
216 //
217 if (fServSock->GetLocalPort()!=port)
218 Close();
219 }
220
221 //
222 // Check whether port is valid
223 //
224 if (port<=0)
225 {
226 cout << "Invalid port #" << port << "!" << endl;
227 clear(ios::failbit);
228 return kFALSE;
229 }
230
231 //
232 // Start server socket...
233 //
234 OpenServerSocket(port);
235 if (!fServSock)
236 return kFALSE;
237
238 OpenConnection(block);
239 if (!fRxSocket)
240 return kFALSE;
241
242 underflow();
243 return kTRUE;
244}
245
246void MReadSocket::Close()
247{
248 if (fRxSocket)
249 {
250 delete fRxSocket;
251 fRxSocket=NULL;
252 }
253 if (fServSock)
254 {
255 const Int_t port = fServSock->GetLocalPort();
256
257 delete fServSock;
258 fServSock=NULL;
259
260 cout << "Connection on Port #" << port << " closed." << endl;
261 }
262
263 clear(ios::eofbit);
264}
265
266// --------------------------------------------------------------------------
267//
268// This is called to flush the buffer of the streaming devices
269//
270int MReadSocket::sync()
271{
272 cout << "sync" << endl;
273 return 0;
274}
275
276int MReadSocket::underflow()
277{
278 // FIXME: vvvvv is this correct?
279 if (fail() || eof())
280 {
281 setg(fBuffer, fBuffer, fBuffer+fMtu);
282 return 0;
283 }
284
285 //
286 // This simple trick should do its job, because the
287 // TCP/IP stream is buffered already
288 //
289 const TTime timeout = fTimeout+gSystem->Now();
290
291 Int_t len=-1;
292 while (len<0 && gSystem->Now()<timeout)
293 {
294 Int_t l;
295 fRxSocket->GetOption(kBytesToRead, l);
296 if (l==0)
297 {
298 gSystem->Sleep(1);
299 continue;
300 }
301 len = fRxSocket->RecvRaw(fBuffer, TMath::Min(fMtu, l));
302 }
303
304 if (len<0)
305 {
306 cout << "MReadSocket: TSocket::RecvRaw - Connection timed out." << endl;
307 setstate(ios::failbit);
308 memset(fBuffer, 0, fMtu);
309 len = fMtu;
310 }
311
312 setg(fBuffer, fBuffer, fBuffer+len);
313 return 0;
314}
Note: See TracBrowser for help on using the repository browser.