40#include <boost/asio.hpp>
41#include <boost/fusion/adapted/std_pair.hpp>
42#include <boost/spirit/include/qi.hpp>
43#include <boost/spirit/include/qi_eps.hpp>
53 NameValuePairVectorType::const_iterator lIt = aUri.
mArguments.begin();
57 if ( lIt->first ==
"target" )
65 exception::XMLfileMissingRequiredParameters lExc;
66 log ( lExc ,
"Expected URI arguments of the form " ,
Quote (
"target=192.168.200.200:50001" ) ,
". It appears that this is missing in URI " , aUri );
70 std::pair< std::string , std::string > lIP;
74 boost::spirit::qi::phrase_parse ( lIt->second.begin() ,
76 ( boost::spirit::qi::eps >
77 * ( boost::spirit::qi::char_ - boost::spirit::qi::lit (
":" ) ) >
78 boost::spirit::qi::lit (
":" ) >
79 *boost::spirit::qi::char_
81 boost::spirit::ascii::space ,
85 catch (
const std::exception& aExc )
87 exception::ParsingTargetURLfailed lExc;
88 log ( lExc ,
"Expected a string of the form " ,
Quote (
"hostIP:port" ) ,
" or " ,
Quote (
"hostname:port" ) ,
" but received " ,
Quote ( lIt->second ) ,
"." );
97 boost::asio::io_service lService;
98 boost::asio::ip::udp::endpoint lEndpoint (
99 *boost::asio::ip::udp::resolver::iterator (
100 boost::asio::ip::udp::resolver ( lService ).resolve (
101 boost::asio::ip::udp::resolver::query ( boost::asio::ip::udp::v4() , lIP.first , lIP.second )
105 lAddr = lEndpoint.address().to_string();
106 lPort = lEndpoint.port();
108 catch (
const std::exception& aExc )
110 exception::HostnameToIPlookupFailed lExc;
111 log ( lExc ,
"Hostname to IP look up failed for hostname=" , lIP.first ,
", port=" , lIP.second );
112 log ( lExc ,
"ASIO threw exception with what returning: ",
Quote ( aExc.what() ) );
116 std::vector< uint32_t > lIPAddr;
120 boost::spirit::qi::phrase_parse ( lAddr.begin() ,
122 ( boost::spirit::qi::eps >
123 boost::spirit::qi::uint_ > boost::spirit::qi::lit (
"." ) >
124 boost::spirit::qi::uint_ > boost::spirit::qi::lit (
"." ) >
125 boost::spirit::qi::uint_ > boost::spirit::qi::lit (
"." ) >
126 boost::spirit::qi::uint_ ),
127 boost::spirit::ascii::space ,
131 catch (
const std::exception& aExc )
133 exception::ParsingTargetURLfailed lExc;
134 log ( lExc ,
"Boost::ASIO returned address " ,
Quote ( lAddr ) ,
" for hostname " ,
Quote (lIP.first) ,
" which could not be parsed as " ,
Quote (
"aaa.bbb.ccc.ddd" ) );
138 uint32_t lIPaddress = ( lIPAddr[0] <<24 ) | ( lIPAddr[1] <<16 ) | ( lIPAddr[2] <<8 ) | ( lIPAddr[3] );
139 log (
Info() ,
"Converted IP address string " ,
Quote ( lIt->second ) ,
" to " ,
142 return std::make_pair ( lIPaddress , lPort );
146 template <
typename InnerProtocol >
148 InnerProtocol ( aId , aUri ),
149 mDeviceIPaddress ( 0 ),
158 template <
typename InnerProtocol >
164 template <
typename InnerProtocol >
180 std::lock_guard<std::mutex> lPreamblesLock ( mPreamblesMutex );
182 tpreamble* lPreambles = & mPreambles.back();
184 aBuffers->send ( mDeviceIPaddress );
185 aBuffers->send ( mDevicePort );
186 lPreambles->
mSendWordCountPtr = ( uint16_t* ) ( aBuffers->send ( ( uint16_t ) ( 0 ) ) );
193 InnerProtocol::preamble ( aBuffers );
198 template <
typename InnerProtocol >
201 return InnerProtocol::getPreambleSize() + 2;
205 template <
typename InnerProtocol >
208 InnerProtocol::predispatch ( aBuffers );
209 std::lock_guard<std::mutex> lPreamblesLock ( mPreamblesMutex );
210 tpreamble& lPreambles = mPreambles.back();
211 uint32_t lByteCount ( aBuffers->sendCounter() );
216 template <
typename InnerProtocol >
218 uint8_t* aSendBufferEnd ,
219 std::deque< std::pair< uint8_t* , uint32_t > >
::iterator aReplyStartIt ,
220 std::deque< std::pair< uint8_t* , uint32_t > >
::iterator aReplyEndIt )
223 uint32_t lReplyIPaddress ( * ( ( uint32_t* ) ( aReplyStartIt->first ) ) );
225 if ( lReplyIPaddress != mDeviceIPaddress )
227 uhal::exception::ControlHubReturnedWrongAddress* lExc =
new uhal::exception::ControlHubReturnedWrongAddress();
230 " for device with URI: " , this->uri() );
231 std::lock_guard<std::mutex> lPreamblesLock ( mPreamblesMutex );
232 mPreambles.pop_front();
237 uint16_t lReplyPort ( * ( ( uint16_t* ) ( aReplyStartIt->first ) ) );
239 if ( lReplyPort != mDevicePort )
241 uhal::exception::ControlHubReturnedWrongAddress* lExc =
new uhal::exception::ControlHubReturnedWrongAddress();
242 log ( *lExc ,
"Returned Port number " ,
Integer ( lReplyPort ) ,
243 " does not match that sent " ,
Integer ( mDevicePort ) ,
244 " for device with URI: " , this->uri() );
245 std::lock_guard<std::mutex> lPreamblesLock ( mPreamblesMutex );
246 mPreambles.pop_front();
251 uint16_t lErrorCode ( ntohs ( * ( ( uint16_t* ) ( aReplyStartIt->first ) ) ) );
253 if ( lErrorCode != 0 )
255 std::lock_guard<std::mutex> lPreamblesLock ( mPreamblesMutex );
256 mPreambles.pop_front();
258 if ( lErrorCode == 1 || lErrorCode == 3 || lErrorCode == 4 )
260 uhal::exception::ControlHubTargetTimeout* lExc =
new uhal::exception::ControlHubTargetTimeout();
261 log ( *lExc ,
"The ControlHub did not receive any response from the target with URI ",
Quote(this->uri()) );
266 uhal::exception::ControlHubErrorCodeSet* lExc =
new uhal::exception::ControlHubErrorCodeSet();
269 " for target with URI " ,
Quote(this->uri()) );
274 std::lock_guard<std::mutex> lPreamblesLock ( mPreamblesMutex );
275 mPreambles.pop_front();
277 return InnerProtocol::validate ( ( aSendBufferStart+=8 ) , aSendBufferEnd , ( ++aReplyStartIt ) , aReplyEndIt );
281 template <
typename InnerProtocol >
288 template <
typename InnerProtocol >
292 std::lock_guard<std::mutex> lPreamblesLock ( mPreamblesMutex );
295 InnerProtocol::dispatchExceptionHandler();
299 template <
typename InnerProtocol >
302 switch (aErrorCode) {
304 aStream <<
"success";
307 aStream <<
"no reply to control packet";
310 aStream <<
"internal timeout within ControlHub";
313 aStream <<
"no reply to status packet";
316 aStream <<
"no reply to resend request";
319 aStream <<
"malformed status packet received";
322 aStream <<
"request uses incorrect protocol version";
325 aStream <<
"device is not in the ControlHub's allowlist";
328 aStream <<
"UNKNOWN";
\rst Wraps a Python iterator so that it can also be used as a C++ input iterator
Transport protocol to transfer an IPbus buffer via ControlHub.
virtual void preamble(std::shared_ptr< Buffers > aBuffers)
Add a preamble to an IPbus buffer.
ControlHub(const std::string &aId, const URI &aUri)
Constructor.
uint32_t mDeviceIPaddress
The IP address of the target device that is connected to the Control Hub.
static void translateErrorCode(std::ostream &aStream, const uint16_t &aErrorCode)
virtual exception::exception * validate(uint8_t *aSendBufferStart, uint8_t *aSendBufferEnd, std::deque< std::pair< uint8_t *, uint32_t > >::iterator aReplyStartIt, std::deque< std::pair< uint8_t *, uint32_t > >::iterator aReplyEndIt)
Function which the dispatch calls when the reply is received to check that the headers are as expecte...
virtual void predispatch(std::shared_ptr< Buffers > aBuffers)
Finalize an IPbus buffer before it is transmitted.
virtual void dispatchExceptionHandler()
Function which tidies up this protocol layer in the event of an exception.
virtual uint32_t getPreambleSize()
Get the size of the preamble added by this protocol layer.
virtual uint32_t getMaxNumberOfBuffers()
Returns the maximum number of buffers that should be in-flight from the uHAL client at any given time...
uint16_t mDevicePort
The port number of the target device that is connected to the Control Hub.
virtual ~ControlHub()
Destructor.
An abstract base exception class, including an interface to throw as the derived type (for passing ex...
_Quote< T > Quote(const T &aT)
_Integer< T, IntFmt<> > Integer(const T &aT)
Forward declare a function which creates an instance of the ultra-lightweight wrapper from an integer...
void log(FatalLevel &aFatal, const T0 &aArg0)
Function to add a log entry at Fatal level.
std::pair< uint32_t, uint16_t > ExtractTargetID(const URI &aUri)
Extract an IP-address and port number from a URI object.
A struct representing the preamble which will be prepended to an IPbus buffer for the benefit of the ...
uint16_t * mSendWordCountPtr
The number of 32-bit words in the IPbus packet (legacy and could be removed)
uint32_t mReplyChunkByteCounter
A legacy counter.
uint16_t mReplyDevicePort
The returned target device ID (port number)
uint16_t mReplyErrorCode
An error code returned describing the status of the control hub.
uint32_t mReplyDeviceIPaddress
The returned target device ID (IP address)
Empty struct which acts as a dummy variable for passing the formatting information around.
Struct to store a URI when parsed by boost spirit.
NameValuePairVectorType mArguments
The "key1=val1&key2=val2&key3=val3" part of a URI of the form "protocol://host:port/patha/pathb/blah....