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_context lService;
98 boost::asio::ip::udp::endpoint lEndpoint (
99 *boost::asio::ip::udp::resolver ( lService ).resolve (
100 boost::asio::ip::udp::v4() , lIP.first , lIP.second
103 lAddr = lEndpoint.address().to_string();
104 lPort = lEndpoint.port();
106 catch (
const std::exception& aExc )
108 exception::HostnameToIPlookupFailed lExc;
109 log ( lExc ,
"Hostname to IP look up failed for hostname=" , lIP.first ,
", port=" , lIP.second );
110 log ( lExc ,
"ASIO threw exception with what returning: ",
Quote ( aExc.what() ) );
114 std::vector< uint32_t > lIPAddr;
118 boost::spirit::qi::phrase_parse ( lAddr.begin() ,
120 ( boost::spirit::qi::eps >
121 boost::spirit::qi::uint_ > boost::spirit::qi::lit (
"." ) >
122 boost::spirit::qi::uint_ > boost::spirit::qi::lit (
"." ) >
123 boost::spirit::qi::uint_ > boost::spirit::qi::lit (
"." ) >
124 boost::spirit::qi::uint_ ),
125 boost::spirit::ascii::space ,
129 catch (
const std::exception& aExc )
131 exception::ParsingTargetURLfailed lExc;
132 log ( lExc ,
"Boost::ASIO returned address " ,
Quote ( lAddr ) ,
" for hostname " ,
Quote (lIP.first) ,
" which could not be parsed as " ,
Quote (
"aaa.bbb.ccc.ddd" ) );
136 uint32_t lIPaddress = ( lIPAddr[0] <<24 ) | ( lIPAddr[1] <<16 ) | ( lIPAddr[2] <<8 ) | ( lIPAddr[3] );
137 log (
Info() ,
"Converted IP address string " ,
Quote ( lIt->second ) ,
" to " ,
140 return std::make_pair ( lIPaddress , lPort );
144 template <
typename InnerProtocol >
146 InnerProtocol ( aId , aUri ),
147 mDeviceIPaddress ( 0 ),
156 template <
typename InnerProtocol >
162 template <
typename InnerProtocol >
178 std::lock_guard<std::mutex> lPreamblesLock ( mPreamblesMutex );
180 tpreamble* lPreambles = & mPreambles.back();
182 aBuffers->send ( mDeviceIPaddress );
183 aBuffers->send ( mDevicePort );
184 lPreambles->
mSendWordCountPtr = ( uint16_t* ) ( aBuffers->send ( ( uint16_t ) ( 0 ) ) );
191 InnerProtocol::preamble ( aBuffers );
196 template <
typename InnerProtocol >
199 return InnerProtocol::getPreambleSize() + 2;
203 template <
typename InnerProtocol >
206 InnerProtocol::predispatch ( aBuffers );
207 std::lock_guard<std::mutex> lPreamblesLock ( mPreamblesMutex );
208 tpreamble& lPreambles = mPreambles.back();
209 uint32_t lByteCount ( aBuffers->sendCounter() );
214 template <
typename InnerProtocol >
216 uint8_t* aSendBufferEnd ,
217 std::deque< std::pair< uint8_t* , uint32_t > >
::iterator aReplyStartIt ,
218 std::deque< std::pair< uint8_t* , uint32_t > >
::iterator aReplyEndIt )
221 uint32_t lReplyIPaddress ( * ( ( uint32_t* ) ( aReplyStartIt->first ) ) );
223 if ( lReplyIPaddress != mDeviceIPaddress )
225 uhal::exception::ControlHubReturnedWrongAddress* lExc =
new uhal::exception::ControlHubReturnedWrongAddress();
228 " for device with URI: " , this->uri() );
229 std::lock_guard<std::mutex> lPreamblesLock ( mPreamblesMutex );
230 mPreambles.pop_front();
235 uint16_t lReplyPort ( * ( ( uint16_t* ) ( aReplyStartIt->first ) ) );
237 if ( lReplyPort != mDevicePort )
239 uhal::exception::ControlHubReturnedWrongAddress* lExc =
new uhal::exception::ControlHubReturnedWrongAddress();
240 log ( *lExc ,
"Returned Port number " ,
Integer ( lReplyPort ) ,
241 " does not match that sent " ,
Integer ( mDevicePort ) ,
242 " for device with URI: " , this->uri() );
243 std::lock_guard<std::mutex> lPreamblesLock ( mPreamblesMutex );
244 mPreambles.pop_front();
249 uint16_t lErrorCode ( ntohs ( * ( ( uint16_t* ) ( aReplyStartIt->first ) ) ) );
251 if ( lErrorCode != 0 )
253 std::lock_guard<std::mutex> lPreamblesLock ( mPreamblesMutex );
254 mPreambles.pop_front();
256 if ( lErrorCode == 1 || lErrorCode == 3 || lErrorCode == 4 )
258 uhal::exception::ControlHubTargetTimeout* lExc =
new uhal::exception::ControlHubTargetTimeout();
259 log ( *lExc ,
"The ControlHub did not receive any response from the target with URI ",
Quote(this->uri()) );
264 uhal::exception::ControlHubErrorCodeSet* lExc =
new uhal::exception::ControlHubErrorCodeSet();
267 " for target with URI " ,
Quote(this->uri()) );
272 std::lock_guard<std::mutex> lPreamblesLock ( mPreamblesMutex );
273 mPreambles.pop_front();
275 return InnerProtocol::validate ( ( aSendBufferStart+=8 ) , aSendBufferEnd , ( ++aReplyStartIt ) , aReplyEndIt );
279 template <
typename InnerProtocol >
286 template <
typename InnerProtocol >
290 std::lock_guard<std::mutex> lPreamblesLock ( mPreamblesMutex );
293 InnerProtocol::dispatchExceptionHandler();
297 template <
typename InnerProtocol >
300 switch (aErrorCode) {
302 aStream <<
"success";
305 aStream <<
"no reply to control packet";
308 aStream <<
"internal timeout within ControlHub";
311 aStream <<
"no reply to status packet";
314 aStream <<
"no reply to resend request";
317 aStream <<
"malformed status packet received";
320 aStream <<
"request uses incorrect protocol version";
323 aStream <<
"device is not in the ControlHub's allowlist";
326 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....