μHAL (v2.6.5)
Part of the IPbus software repository
ProtocolUDP.cpp
Go to the documentation of this file.
1 /*
2 ---------------------------------------------------------------------------
3 
4  This file is part of uHAL.
5 
6  uHAL is a hardware access library and programming framework
7  originally developed for upgrades of the Level-1 trigger of the CMS
8  experiment at CERN.
9 
10  uHAL is free software: you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation, either version 3 of the License, or
13  (at your option) any later version.
14 
15  uHAL is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with uHAL. If not, see <http://www.gnu.org/licenses/>.
22 
23 
24  Andrew Rose, Imperial College, London
25  email: awr01 <AT> imperial.ac.uk
26 
27  Marc Magrans de Abril, CERN
28  email: marc.magrans.de.abril <AT> cern.ch
29 
30 ---------------------------------------------------------------------------
31 */
32 
33 #include "uhal/ProtocolUDP.hpp"
34 
35 
36 #include <exception>
37 #include <utility>
38 
39 #include <boost/bind/bind.hpp>
40 #include <boost/lambda/lambda.hpp>
41 #include <boost/asio/connect.hpp>
42 #include <boost/asio/write.hpp>
43 #include <boost/asio/read.hpp>
44 #include <boost/asio/placeholders.hpp>
45 #include "boost/date_time/posix_time/posix_time.hpp"
46 
47 #include "uhal/log/LogLevels.hpp"
51 #include "uhal/log/log.hpp"
52 #include "uhal/grammars/URI.hpp"
53 #include "uhal/Buffers.hpp"
54 #include "uhal/ProtocolIPbus.hpp"
55 
56 
57 namespace uhal
58 {
59 
60  //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
61  //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
62 
63  template < typename InnerProtocol >
64  UDP< InnerProtocol >::UDP ( const std::string& aId, const URI& aUri ) :
65  InnerProtocol ( aId , aUri ),
66  mIOservice ( ),
67  mSocket ( mIOservice , boost::asio::ip::udp::endpoint ( boost::asio::ip::udp::v4(), 0 ) ),
68  mEndpoint ( *boost::asio::ip::udp::resolver ( mIOservice ).resolve ( boost::asio::ip::udp::resolver::query ( boost::asio::ip::udp::v4() , aUri.mHostname , aUri.mPort ) ) ),
69  mDeadlineTimer ( mIOservice ),
70  mReplyMemory ( 1500 , 0x00000000 ),
71  mIOserviceWork ( mIOservice ),
72  mDispatchThread ( boost::bind ( &boost::asio::io_service::run , & ( mIOservice ) ) ),
73  mDispatchQueue(),
74  mReplyQueue(),
75  mPacketsInFlight ( 0 ),
76  mFlushDone ( true ),
77  // mDispatchBuffers ( NULL ),
78  // mReplyBuffers ( NULL ),
79  mAsynchronousException ( NULL )
80  {
81  mDeadlineTimer.async_wait ( boost::bind ( &UDP::CheckDeadline, this ) );
82  }
83 
84 
85  template < typename InnerProtocol >
87  {
88  try
89  {
90  mSocket.close();
91 
92  while ( mSocket.is_open() )
93  {}
94 
95  mIOservice.stop();
96  mDispatchThread.join();
97  boost::lock_guard<boost::mutex> lLock ( mTransportLayerMutex );
100  }
101  catch ( const std::exception& aExc )
102  {
103  log ( Error() , "Exception " , Quote ( aExc.what() ) , " caught at " , ThisLocation() );
104  }
105  }
106 
107 
108 
109  template < typename InnerProtocol >
111  {
112  boost::lock_guard<boost::mutex> lLock ( mTransportLayerMutex );
113 
115  {
116  log ( *mAsynchronousException , "Rethrowing Asynchronous Exception from " , ThisLocation() );
117  mAsynchronousException->ThrowAsDerivedType();
118  }
119 
120  if ( ! mSocket.is_open() )
121  {
122  connect();
123  }
124 
125 
126  if ( mDispatchBuffers || mPacketsInFlight == this->getMaxNumberOfBuffers() )
127  {
128  mDispatchQueue.push_back ( aBuffers );
129  // std::cout << "extended mDispatchQueue" << std::endl;
130  }
131  else
132  {
133  mDispatchBuffers = aBuffers;
134  write ( );
135  }
136  }
137 
138 
139  template < typename InnerProtocol >
141  {
142  return (350 * 4);
143  }
144 
145 
146  template < typename InnerProtocol >
148  {
149  return (350 * 4);
150  }
151 
152 
153  template < typename InnerProtocol >
155  {
156  log ( Info() , "Creating new UDP socket for device " , Quote ( this->uri() ) , ", as it appears to have been closed..." );
157  //mSocket = boost::asio::ip::udp::socket ( mIOservice , boost::asio::ip::udp::endpoint ( boost::asio::ip::udp::v4(), 0 ) );
158  mSocket.open ( boost::asio::ip::udp::v4() );
159  // boost::asio::socket_base::non_blocking_io lNonBlocking ( true );
160  // mSocket.io_control ( lNonBlocking );
161  log ( Info() , "UDP socket created successfully." );
162  }
163 
164 
165  template < typename InnerProtocol >
167  {
168  NotifyConditionalVariable ( false );
169 
170  if ( !mDispatchBuffers )
171  {
172  log ( Error() , __PRETTY_FUNCTION__ , " called when 'mDispatchBuffers' was NULL" );
173  return;
174  }
175 
176  /* std::vector<uint32_t>::const_iterator lBegin ( reinterpret_cast<uint32_t*> ( aBuffers->getSendBuffer() ) );
177  std::vector<uint32_t>::const_iterator lEnd = lBegin + ( aBuffers->sendCounter() >>2 );
178  std::vector<uint32_t> lData;
179 
180  for ( ; lBegin!=lEnd ; ++lBegin )
181  {
182  std::cout << std::setfill ( '0' ) << std::hex << std::setw ( 8 ) << *lBegin << std::endl;
183  }*/
184  // mAsioSendBuffer.clear();
185  std::vector< boost::asio::const_buffer > lAsioSendBuffer;
186  lAsioSendBuffer.push_back ( boost::asio::const_buffer ( mDispatchBuffers->getSendBuffer() , mDispatchBuffers->sendCounter() ) );
187  log ( Debug() , "Sending " , Integer ( mDispatchBuffers->sendCounter() ) , " bytes" );
188  mDeadlineTimer.expires_from_now ( this->getBoostTimeoutPeriod() );
189 
190  // Patch for suspected bug in using boost asio with boost python; see https://svnweb.cern.ch/trac/cactus/ticket/323#comment:7
191  while ( mDeadlineTimer.expires_from_now() < boost::posix_time::microseconds ( 600 ) )
192  {
193  log ( Debug() , "Resetting deadline timer since it just got set to strange value, likely due to a bug within boost (expires_from_now was: ", mDeadlineTimer.expires_from_now() , ")." );
194  mDeadlineTimer.expires_from_now ( this->getBoostTimeoutPeriod() );
195  }
196 
197  mSocket.async_send_to ( lAsioSendBuffer , mEndpoint , boost::bind ( &UDP< InnerProtocol >::write_callback, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred ) );
199  }
200 
201 
202  template < typename InnerProtocol >
203  void UDP< InnerProtocol >::write_callback ( const boost::system::error_code& aErrorCode , std::size_t aBytesTransferred )
204  {
205  // if( !mDispatchBuffers)
206  // {
207  // log( Error() , __PRETTY_FUNCTION__ , " called when 'mDispatchBuffers' was NULL" );
208  // return;
209  // }
210  boost::lock_guard<boost::mutex> lLock ( mTransportLayerMutex );
211 
213  {
214  NotifyConditionalVariable ( true );
215  return;
216  }
217 
218  if ( mDeadlineTimer.expires_at () == boost::posix_time::pos_infin )
219  {
220  exception::UdpTimeout* lExc = new exception::UdpTimeout();
221  log ( *lExc , "Timeout (" , Integer ( this->getBoostTimeoutPeriod().total_milliseconds() ) , " milliseconds) occurred for UDP send to target with URI: ", this->uri() );
222 
223  if ( aErrorCode && aErrorCode != boost::asio::error::operation_aborted )
224  {
225  log ( *lExc , "ASIO reported an error: " , Quote ( aErrorCode.message() ) );
226  }
227 
228  mAsynchronousException = lExc;
229  NotifyConditionalVariable ( true );
230  return;
231  }
232 
233  if ( ( aErrorCode && ( aErrorCode != boost::asio::error::eof ) ) || ( aBytesTransferred != mDispatchBuffers->sendCounter() ) )
234  {
235  mSocket.close();
236  exception::ASIOUdpError* lExc = new exception::ASIOUdpError();
237  if ( aErrorCode )
238  {
239  log ( *lExc , "Error ", Quote ( aErrorCode.message() ) , " encountered during send to UDP target with URI: " , this->uri() );
240  }
241  if ( aBytesTransferred != mDispatchBuffers->sendCounter() )
242  {
243  log ( *lExc , "Only ", Integer ( aBytesTransferred ) , " of " , Integer ( mDispatchBuffers->sendCounter() ) , " bytes transferred in UDP send to URI: " , this->uri() );
244  }
245  mAsynchronousException = lExc;
246  NotifyConditionalVariable ( true );
247  return;
248  }
249 
250  if ( mReplyBuffers )
251  {
252  mReplyQueue.push_back ( mDispatchBuffers );
253  // std::cout << "extended mReplyQueue" << std::endl;
254  }
255  else
256  {
258  read ( );
259  }
260 
261  if ( mDispatchQueue.size() && mPacketsInFlight != this->getMaxNumberOfBuffers() )
262  {
264  mDispatchQueue.pop_front();
265  //std::cout << "reduced mDispatchQueue" << std::endl;
266  write();
267  }
268  else
269  {
270  mDispatchBuffers.reset();
271  }
272  }
273 
274 
275  template < typename InnerProtocol >
277  {
278  if ( !mReplyBuffers )
279  {
280  log ( Error() , __PRETTY_FUNCTION__ , " called when 'mReplyBuffers' was NULL" );
281  NotifyConditionalVariable ( true );
282  return;
283  }
284 
285  std::vector<boost::asio::mutable_buffer> lAsioReplyBuffer ( 1 , boost::asio::mutable_buffer ( & ( mReplyMemory.at ( 0 ) ) , mReplyBuffers->replyCounter() ) );
286  log ( Debug() , "Expecting " , Integer ( mReplyBuffers->replyCounter() ) , " bytes in reply." );
287  mDeadlineTimer.expires_from_now ( this->getBoostTimeoutPeriod() );
288 
289  // Patch for suspected bug in using boost asio with boost python; see https://svnweb.cern.ch/trac/cactus/ticket/323#comment:7
290  while ( mDeadlineTimer.expires_from_now() < boost::posix_time::microseconds ( 600 ) )
291  {
292  log ( Debug() , "Resetting deadline timer since it just got set to strange value, likely due to a bug within boost (expires_from_now was: ", mDeadlineTimer.expires_from_now() , ")." );
293  mDeadlineTimer.expires_from_now ( this->getBoostTimeoutPeriod() );
294  }
295 
296  mSocket.async_receive ( lAsioReplyBuffer , 0 , boost::bind ( &UDP<InnerProtocol>::read_callback, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred ) );
297  }
298 
299 
300  template < typename InnerProtocol >
301  void UDP< InnerProtocol >::read_callback ( const boost::system::error_code& aErrorCode , std::size_t aBytesTransferred )
302  {
303  {
304  boost::lock_guard<boost::mutex> lLock ( mTransportLayerMutex );
306  {
307  NotifyConditionalVariable ( true );
308  return;
309  }
310 
311  if ( mDeadlineTimer.expires_at () == boost::posix_time::pos_infin )
312  {
313  mAsynchronousException = new exception::UdpTimeout();
314  log ( *mAsynchronousException , "Timeout (" , Integer ( this->getBoostTimeoutPeriod().total_milliseconds() ) , " milliseconds) occurred for UDP receive from target with URI: ", this->uri() );
315 
316  if ( aErrorCode && aErrorCode != boost::asio::error::operation_aborted )
317  {
318  log ( *mAsynchronousException , "ASIO reported an error: " , Quote ( aErrorCode.message() ) );
319  }
320 
321  NotifyConditionalVariable ( true );
322  return;
323  }
324  }
325 
326  if ( !mReplyBuffers )
327  {
328  log ( Error() , __PRETTY_FUNCTION__ , " called when 'mReplyBuffers' was NULL" );
329  return;
330  }
331 
332  if ( aBytesTransferred != mReplyBuffers->replyCounter() )
333  {
334  log ( Error() , "Expected " , Integer ( mReplyBuffers->replyCounter() ) , "-byte UDP payload from target " , Quote ( this->uri() ) , ", but only received " , Integer ( aBytesTransferred ) , " bytes. Validating returned data to work out where error occurred." );
335  }
336 
337  if ( aErrorCode && ( aErrorCode != boost::asio::error::eof ) )
338  {
339  mSocket.close();
340 
341  boost::lock_guard<boost::mutex> lLock ( mTransportLayerMutex );
342  mAsynchronousException = new exception::ASIOUdpError();
343  log ( *mAsynchronousException , "Error ", Quote ( aErrorCode.message() ) , " encountered during receive from UDP target with URI: " , this->uri() );
344 
345  NotifyConditionalVariable ( true );
346  return;
347  }
348 
349  // uint32_t lCounter(0);
350  // for ( std::vector< boost::asio::mutable_buffer >::iterator lIt = lAsioReplyBuffer.begin() ; lIt != lAsioReplyBuffer.end() ; ++lIt )
351  // {
352  // uint32_t s1 = boost::asio::buffer_size(*lIt)>>2;
353  // uint32_t* p1 = boost::asio::buffer_cast<uint32_t*>(*lIt);
354  //
355  // for( uint32_t i(0) ; i!= s1 ; ++i , ++p1 )
356  // {
357  // log ( Debug() , Integer ( lCounter++ ) , " : " , Integer ( *p1 , IntFmt<hex,fixed>() ) );
358  // }
359  // }
360  // TargetToHostInspector< 2 , 0 > lT2HInspector;
361  // std::vector<uint32_t>::const_iterator lBegin2 ( ( uint32_t* ) ( & mReplyMemory[0] ) );
362  // std::vector<uint32_t>::const_iterator lEnd2 ( ( uint32_t* ) ( & mReplyMemory[aBuffers->replyCounter() ] ) );
363  // lT2HInspector.analyze ( lBegin2 , lEnd2 );
364  // std::cout << "Filling reply buffer : " << mReplyBuffers << std::endl;
365  std::deque< std::pair< uint8_t* , uint32_t > >& lReplyBuffers ( mReplyBuffers->getReplyBuffer() );
366  uint8_t* lReplyBuf ( & ( mReplyMemory.at ( 0 ) ) );
367 
368  for ( std::deque< std::pair< uint8_t* , uint32_t > >::iterator lIt = lReplyBuffers.begin() ; lIt != lReplyBuffers.end() ; ++lIt )
369  {
370  // Don't copy more of mReplyMemory than was written to, for cases when less data received than expected
371  if ( static_cast<uint32_t> ( lReplyBuf - ( & mReplyMemory.at ( 0 ) ) ) >= aBytesTransferred )
372  {
373  break;
374  }
375 
376  uint32_t lNrBytesToCopy = std::min ( lIt->second , static_cast<uint32_t> ( aBytesTransferred - ( lReplyBuf - ( & mReplyMemory.at ( 0 ) ) ) ) );
377  memcpy ( lIt->first, lReplyBuf, lNrBytesToCopy );
378  lReplyBuf += lNrBytesToCopy;
379  }
380 
381  try
382  {
383  if ( uhal::exception::exception* lExc = ClientInterface::validate ( mReplyBuffers ) ) //Control of the pointer has been passed back to the client interface
384  {
385  boost::lock_guard<boost::mutex> lLock ( mTransportLayerMutex );
386  mAsynchronousException = lExc;
387  }
388  }
389  catch ( exception::exception& aExc )
390  {
391  boost::lock_guard<boost::mutex> lLock ( mTransportLayerMutex );
392  mAsynchronousException = new exception::ValidationError ();
393  log ( *mAsynchronousException , "Exception caught during reply validation for UDP device with URI " , Quote ( this->uri() ) , "; what returned: " , Quote ( aExc.what() ) );
394  }
395 
396  boost::lock_guard<boost::mutex> lLock ( mTransportLayerMutex );
397 
399  {
400  NotifyConditionalVariable ( true );
401  return;
402  }
403 
404  if ( mReplyQueue.size() )
405  {
406  mReplyBuffers = mReplyQueue.front();
407  mReplyQueue.pop_front();
408  // std::cout << "reduced mReplyQueue" << std::endl;
409  read();
410  }
411  else
412  {
413  mReplyBuffers.reset();
414  }
415 
417 
418  if ( !mDispatchBuffers && mDispatchQueue.size() && mPacketsInFlight != this->getMaxNumberOfBuffers() )
419  {
421  mDispatchQueue.pop_front();
422  //std::cout << "reduced mDispatchQueue" << std::endl;
423  write();
424  }
425 
426  if ( !mDispatchBuffers && !mReplyBuffers )
427  {
428  mDeadlineTimer.expires_from_now( boost::posix_time::seconds(60) );
429  NotifyConditionalVariable ( true );
430  }
431  }
432 
433 
434 
435  template < typename InnerProtocol >
437  {
438  // Check whether the deadline has passed. We compare the deadline against
439  // the current time since a new asynchronous operation may have moved the
440  // deadline before this actor had a chance to run.
441  boost::lock_guard<boost::mutex> lLock ( this->mTransportLayerMutex );
442 
443  if ( mDeadlineTimer.expires_at() <= boost::asio::deadline_timer::traits_type::now() )
444  {
445  // SETTING THE EXCEPTION HERE CAN APPEAR AS A TIMEOUT WHEN NONE ACTUALLY EXISTS
447  {
448  log ( Warning() , "Closing UDP socket for URI " , Quote ( this->uri() ) , " since deadline has passed" );
449  }
450  else
451  {
452  log ( Debug() , "Closing UDP socket for URI " , Quote ( this->uri() ) , " since no communication in last 60 seconds" );
453  }
454 
455  // The deadline has passed. The socket is closed so that any outstanding
456  // asynchronous operations are cancelled.
457  mSocket.close();
458  // There is no longer an active deadline. The expiry is set to positive
459  // infinity so that the actor takes no action until a new deadline is set.
460  mDeadlineTimer.expires_at ( boost::posix_time::pos_infin );
461  // log ( Error() , "ASIO deadline timer timed out" );
462  }
463 
464  // Put the actor back to sleep.
465  mDeadlineTimer.async_wait ( boost::bind ( &UDP::CheckDeadline, this ) );
466  }
467 
468 
469  template < typename InnerProtocol >
471  {
473 
474  boost::lock_guard<boost::mutex> lLock ( mTransportLayerMutex );
476  {
477  mAsynchronousException->ThrowAsDerivedType();
478  }
479  }
480 
481 
482 
483  template < typename InnerProtocol >
485  {
486  log ( Warning() , "Closing Socket since exception detected." );
487 
488  if ( mSocket.is_open() )
489  {
490  try
491  {
492  mSocket.close();
493 
494  while ( mSocket.is_open() )
495  {}
496  }
497  catch ( ... )
498  {}
499  }
500 
501  NotifyConditionalVariable ( true );
502 
504  {
505  delete mAsynchronousException;
506  mAsynchronousException = NULL;
507  }
508 
511  mPacketsInFlight = 0;
512 
514  mDispatchBuffers.reset();
516  mReplyBuffers.reset();
517 
518  InnerProtocol::dispatchExceptionHandler();
519  }
520 
521  //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
522  //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
523 
524 
525  template < typename InnerProtocol >
527  {
528  {
529  boost::lock_guard<boost::mutex> lLock ( mConditionalVariableMutex );
530  mFlushDone = aValue;
531  }
532  mConditionalVariable.notify_one();
533  }
534 
535 
536  template < typename InnerProtocol >
538  {
539  boost::unique_lock<boost::mutex> lLock ( mConditionalVariableMutex );
540 
541  while ( !mFlushDone )
542  {
543  mConditionalVariable.wait ( lLock );
544  }
545  }
546 
547 
548  template class UDP< IPbus< 1 , 3 > >;
549  template class UDP< IPbus< 2 , 0 > >;
550 }
551 
std::deque< boost::shared_ptr< Buffers > > mDispatchQueue
The list of buffers still waiting to be sent.
void returnBufferToPool(boost::shared_ptr< Buffers > &aBuffers)
Function to return a buffer to the buffer pool.
uint32_t getMaxSendSize()
Return the maximum size to be sent based on the buffer size in the target.
uint32_t getMaxReplySize()
Return the maximum size of reply packet based on the buffer size in the target.
Transport protocol to transfer an IPbus buffer via UDP.
Definition: ProtocolUDP.hpp:84
boost::asio::io_service mIOservice
The boost::asio::io_service used to create the connections.
minutes past the hour formatted as two digits e.g.
uint32_t mPacketsInFlight
Counter of how many writes have been sent, for which no reply has yet been received.
void CheckDeadline()
Function called by the ASIO deadline timer.
void NotifyConditionalVariable(const bool &aValue)
Function to set the value of a variable associated with a BOOST conditional-variable and then notify ...
boost::asio::deadline_timer mDeadlineTimer
The mechanism for providing the time-out.
WarningLevel Warning
Definition: LogLevels.cpp:79
An abstract base exception class providing an interface to a throw/ThrowAsDerivedType mechanism which...
Definition: exception.hpp:89
boost::shared_ptr< Buffers > mReplyBuffers
The receive operation currently in progress or the next to be done.
virtual ~UDP()
Destructor.
Definition: ProtocolUDP.cpp:86
void read_callback(const boost::system::error_code &aErrorCode, std::size_t aBytesTransferred)
Callback function which is called upon completion of the ASIO async receive This, then...
ErrorLevel Error
Definition: LogLevels.cpp:61
virtual void dispatchExceptionHandler()
Function which tidies up this protocol layer in the event of an exception.
boost::shared_ptr< Buffers > mDispatchBuffers
The send operation currently in progress.
boost::mutex mTransportLayerMutex
A MutEx lock used to make sure the access functions are thread safe.
_Quote< T > Quote(const T &aT)
virtual void Flush()
Concrete implementation of the synchronization function to block until all buffers have been sent...
boost::condition_variable mConditionalVariable
A conditional variable for blocking the main thread until the variable with which it is associated is...
UDP(const UDP &aUDP)
Copy Constructor This creates a new socket, dispatch queue, dispatch thread, etc. ...
boost::asio::ip::udp::socket mSocket
A shared pointer to a boost::asio udp socket through which the operation will be performed.
void connect()
Set up the UDP socket.
boost::thread mDispatchThread
The Worker thread in Multi-threaded mode.
virtual const char * what() const
Function which returns the error message associated with an exception If no error message has previou...
Definition: exception.cpp:116
void write_callback(const boost::system::error_code &aErrorCode, std::size_t aBytesTransferred)
Callback function which is called upon completion of the ASIO async send This, then, makes a call to read to read back the reply to what has just been sent.
void write()
Initialize performing the next UDP write operation In multi-threaded mode, this runs the ASIO async s...
void read()
Initialize performing the next UDP read operation In multi-threaded mode, this runs the ASIO async re...
std::vector< uint8_t > mReplyMemory
A block of memory into which we write replies, before copying them to their final destination...
std::deque< boost::shared_ptr< Buffers > > mReplyQueue
The list of buffers still awaiting a reply.
bool mFlushDone
A variable associated with the conditional variable which specifies whether all packets have been sen...
#define ThisLocation()
boost::asio::ip::udp::endpoint mEndpoint
A shared pointer to a boost::asio udp endpoint - used in the ASIO send and receive functions (UDP has...
std::string uri
Definition: test_single.cpp:89
DebugLevel Debug
Definition: LogLevels.cpp:133
void implementDispatch(boost::shared_ptr< Buffers > aBuffers)
Send the IPbus buffer to the target, read back the response and call the packing-protocol&#39;s validate ...
virtual exception::exception * validate(boost::shared_ptr< Buffers > aBuffers)
Function which dispatch calls when the reply is received to check that the headers are as expected...
uhal::exception::exception * mAsynchronousException
A pointer to an exception object for passing exceptions from the worker thread to the main thread...
InfoLevel Info
Definition: LogLevels.cpp:114
void WaitOnConditionalVariable()
Function to block a thread pending a BOOST conditional-variable and its associated regular variable...
boost::mutex mConditionalVariableMutex
A mutex for use by the conditional variable.
_Integer< T, IntFmt<> > Integer(const T &aT)
Forward declare a function which creates an instance of the ultra-lightweight wrapper from an integer...
Struct to store a URI when parsed by boost spirit.
Definition: URI.hpp:49