s-net-Tools
HdlcdClient.h
Go to the documentation of this file.
1 
37 #ifndef HDLCD_CLIENT_H
38 #define HDLCD_CLIENT_H
39 
40 #include <boost/asio.hpp>
41 #include <vector>
42 #include <string>
43 #include "HdlcdPacketEndpoint.h"
44 #include "HdlcdSessionHeader.h"
45 #include "HdlcdPacketData.h"
46 #include "HdlcdPacketCtrl.h"
47 #include "FrameEndpoint.h"
48 
54 class HdlcdClient {
55 public:
64  HdlcdClient(boost::asio::io_service& a_IOService, const std::string &a_SerialPortName, HdlcdSessionDescriptor a_HdlcdSessionDescriptor):
65  m_IOService(a_IOService),
66  m_SerialPortName(a_SerialPortName),
67  m_HdlcdSessionDescriptor(a_HdlcdSessionDescriptor),
68  m_bClosed(false),
69  m_TcpSocketData(a_IOService),
70  m_TcpSocketCtrl(a_IOService),
71  m_eTcpSocketDataState(SOCKET_STATE_ERROR),
72  m_eTcpSocketCtrlState(SOCKET_STATE_ERROR) {
73  }
74 
82  void AsyncConnect(boost::asio::ip::tcp::resolver::iterator a_EndpointIterator, std::function<void(bool a_bSuccess)> a_OnConnectedCallback) {
83  // Checks
84  assert(a_OnConnectedCallback);
85  assert(m_eTcpSocketDataState == SOCKET_STATE_ERROR); // not tried yet, or retrying
86  assert(m_eTcpSocketCtrlState == SOCKET_STATE_ERROR); // not tried yet, or retrying
87 
88  // Connect the data socket
89  m_OnConnectedCallback = a_OnConnectedCallback;
90  m_eTcpSocketDataState = SOCKET_STATE_CONNECTING;
91  boost::asio::async_connect(m_TcpSocketData, a_EndpointIterator, [this](boost::system::error_code a_ErrorCode, boost::asio::ip::tcp::resolver::iterator) {
92  if (a_ErrorCode == boost::asio::error::operation_aborted) return;
93  if (a_ErrorCode) {
94  OnTcpSocketDataConnected(false);
95  } else {
96  OnTcpSocketDataConnected(true);
97  } // else
98  });
99 
100  // Connect the control socket
101  m_eTcpSocketCtrlState = SOCKET_STATE_CONNECTING;
102  boost::asio::async_connect(m_TcpSocketCtrl, a_EndpointIterator, [this](boost::system::error_code a_ErrorCode, boost::asio::ip::tcp::resolver::iterator) {
103  if (a_ErrorCode == boost::asio::error::operation_aborted) return;
104  if (a_ErrorCode) {
105  OnTcpSocketCtrlConnected(false);
106  } else {
107  OnTcpSocketCtrlConnected(true);
108  } // else
109  });
110  }
111 
117  m_OnDataCallback = nullptr;
118  m_OnCtrlCallback = nullptr;
119  m_OnClosedCallback = nullptr;
120  Close();
121  }
122 
127  void Shutdown() {
128  if (m_PacketEndpointData) {
129  m_PacketEndpointData->Shutdown();
130  } // if
131 
132  if (m_PacketEndpointCtrl) {
133  m_PacketEndpointCtrl->Shutdown();
134  } // if
135  }
136 
141  void Close() {
142  if (m_bClosed == false) {
143  m_bClosed = true;
144  if (m_PacketEndpointData) {
145  m_PacketEndpointData->Close();
146  m_PacketEndpointData.reset();
147  } else {
148  m_TcpSocketData.cancel();
149  m_TcpSocketData.close();
150  } // else
151 
152  if (m_PacketEndpointCtrl) {
153  m_PacketEndpointCtrl->Close();
154  m_PacketEndpointCtrl.reset();
155  } else {
156  m_TcpSocketCtrl.cancel();
157  m_TcpSocketCtrl.close();
158  } // else
159 
160  if (m_OnClosedCallback) {
161  m_OnClosedCallback();
162  } // if
163  } // if
164  }
165 
172  void SetOnDataCallback(std::function<void(const HdlcdPacketData& a_PacketData)> a_OnDataCallback) {
173  m_OnDataCallback = a_OnDataCallback;
174  }
175 
182  void SetOnCtrlCallback(std::function<void(const HdlcdPacketCtrl& a_PacketCtrl)> a_OnCtrlCallback) {
183  m_OnCtrlCallback = a_OnCtrlCallback;
184  }
185 
192  void SetOnClosedCallback(std::function<void()> a_OnClosedCallback) {
193  m_OnClosedCallback = a_OnClosedCallback;
194  }
195 
203  bool Send(const HdlcdPacketData& a_PacketData, std::function<void()> a_OnSendDoneCallback = nullptr) {
204  bool l_bRetVal = false;
205  if (m_PacketEndpointData) {
206  l_bRetVal = m_PacketEndpointData->Send(a_PacketData, a_OnSendDoneCallback);
207  } else {
208  if (a_OnSendDoneCallback) {
209  m_IOService.post([a_OnSendDoneCallback](){ a_OnSendDoneCallback(); });
210  } // if
211  } // else
212 
213  return l_bRetVal;
214  }
215 
223  bool Send(const HdlcdPacketCtrl& a_PacketCtrl, std::function<void()> a_OnSendDoneCallback = nullptr) {
224  bool l_bRetVal = false;
225  if (m_PacketEndpointCtrl) {
226  l_bRetVal= m_PacketEndpointCtrl->Send(a_PacketCtrl, a_OnSendDoneCallback);
227  } else {
228  if (a_OnSendDoneCallback) {
229  m_IOService.post([a_OnSendDoneCallback](){ a_OnSendDoneCallback(); });
230  } // if
231  } // else
232 
233  return l_bRetVal;
234  }
235 
236 private:
243  void OnTcpSocketDataConnected(bool l_bSuccess) {
244  // Checks
245  assert(m_eTcpSocketDataState == SOCKET_STATE_CONNECTING);
246  if (l_bSuccess) {
247  m_eTcpSocketDataState = SOCKET_STATE_CONNECTED;
248  } else {
249  m_eTcpSocketDataState = SOCKET_STATE_ERROR;
250  } // else
251 
252  OnTcpSocketConnected();
253  }
254 
261  void OnTcpSocketCtrlConnected(bool l_bSuccess) {
262  // Checks
263  assert(m_eTcpSocketCtrlState == SOCKET_STATE_CONNECTING);
264  if (l_bSuccess) {
265  m_eTcpSocketCtrlState = SOCKET_STATE_CONNECTED;
266  } else {
267  m_eTcpSocketCtrlState = SOCKET_STATE_ERROR;
268  } // else
269 
270  OnTcpSocketConnected();
271  }
272 
277  void OnTcpSocketConnected() {
278  // Checks
279  if ((m_eTcpSocketDataState == SOCKET_STATE_CONNECTING) && (m_eTcpSocketCtrlState == SOCKET_STATE_CONNECTING)) {
280  // Invalid state
281  assert(false);
282  return;
283  } // if
284 
285  if ((m_eTcpSocketDataState == SOCKET_STATE_CONNECTED) && (m_eTcpSocketCtrlState == SOCKET_STATE_CONNECTED)) {
286  // Success!
287  // Create and start the packet endpoint for the exchange of user data packets
288  m_PacketEndpointData = std::make_shared<HdlcdPacketEndpoint>(m_IOService, std::make_shared<FrameEndpoint>(m_IOService, m_TcpSocketData));
289  m_PacketEndpointData->SetOnDataCallback([this](std::shared_ptr<const HdlcdPacketData> a_PacketData){ return OnDataReceived(a_PacketData); });
290  m_PacketEndpointData->SetOnClosedCallback([this](){ OnClosed(); });
291  m_PacketEndpointData->Start();
292  m_PacketEndpointData->Send(HdlcdSessionHeader::Create(m_HdlcdSessionDescriptor, m_SerialPortName));
293 
294  // Create and start the packet endpoint for the exchange of control packets
295  m_PacketEndpointCtrl = std::make_shared<HdlcdPacketEndpoint>(m_IOService, std::make_shared<FrameEndpoint>(m_IOService, m_TcpSocketCtrl));
296  m_PacketEndpointCtrl->SetOnCtrlCallback([this](const HdlcdPacketCtrl& a_PacketCtrl){ return OnCtrlReceived(a_PacketCtrl); });
297  m_PacketEndpointCtrl->SetOnClosedCallback([this](){ OnClosed(); });
298  m_PacketEndpointCtrl->Start();
299  m_PacketEndpointCtrl->Send(HdlcdSessionHeader::Create(HdlcdSessionDescriptor(SESSION_TYPE_TRX_STATUS, SESSION_FLAGS_NONE), m_SerialPortName));
300  m_OnConnectedCallback(true);
301  return;
302  } // if
303 
304  if ((m_eTcpSocketDataState == SOCKET_STATE_CONNECTING) || (m_eTcpSocketCtrlState == SOCKET_STATE_CONNECTING)) {
305  // Needs to wait for the second socket
306  return;
307  } // if
308 
309 
310  if (m_eTcpSocketDataState == SOCKET_STATE_CONNECTED) {
311  // The control socket failed after the data socket succeeded
312  assert(m_eTcpSocketCtrlState == SOCKET_STATE_ERROR);
313  m_eTcpSocketDataState = SOCKET_STATE_ERROR;
314  m_TcpSocketData.close();
315  m_OnConnectedCallback(false);
316  return;
317  } // else if
318 
319  if (m_eTcpSocketCtrlState == SOCKET_STATE_CONNECTED) {
320  // The data socket failed after the control socket succeeded
321  assert(m_eTcpSocketDataState == SOCKET_STATE_ERROR);
322  m_eTcpSocketCtrlState = SOCKET_STATE_ERROR;
323  m_TcpSocketCtrl.close();
324  m_OnConnectedCallback(false);
325  return;
326  } // else if
327 
328  // Both sockets failed
329  assert(m_eTcpSocketDataState == SOCKET_STATE_ERROR);
330  assert(m_eTcpSocketCtrlState == SOCKET_STATE_ERROR);
331  m_OnConnectedCallback(false);
332  return;
333  }
334 
341  bool OnDataReceived(std::shared_ptr<const HdlcdPacketData> a_PacketData) {
342  if (m_OnDataCallback) {
343  m_OnDataCallback(*(a_PacketData.get()));
344  } // if
345 
346  return true; // Do not stall the receiver
347  }
348 
355  void OnCtrlReceived(const HdlcdPacketCtrl& a_PacketCtrl) {
356  if (m_OnCtrlCallback) {
357  m_OnCtrlCallback(a_PacketCtrl);
358  } // if
359  }
360 
365  void OnClosed() {
366  Close();
367  }
368 
369  // Members
370  boost::asio::io_service& m_IOService;
371  const std::string m_SerialPortName;
372  const HdlcdSessionDescriptor m_HdlcdSessionDescriptor;
373  bool m_bClosed;
374 
375  std::function<void(bool a_bSuccess)> m_OnConnectedCallback;
376  boost::asio::ip::tcp::socket m_TcpSocketData;
377  boost::asio::ip::tcp::socket m_TcpSocketCtrl;
378  typedef enum {
379  SOCKET_STATE_ERROR = 0,
380  SOCKET_STATE_CONNECTING = 1,
381  SOCKET_STATE_CONNECTED = 2,
382  } E_SOCKET_STATE;
383  E_SOCKET_STATE m_eTcpSocketDataState;
384  E_SOCKET_STATE m_eTcpSocketCtrlState;
385 
386  std::shared_ptr<HdlcdPacketEndpoint> m_PacketEndpointData;
387  std::shared_ptr<HdlcdPacketEndpoint> m_PacketEndpointCtrl;
388 
389  // All possible callbacks for a user of this class
390  std::function<void(const HdlcdPacketData&)> m_OnDataCallback;
391  std::function<void(const HdlcdPacketCtrl&)> m_OnCtrlCallback;
392  std::function<void()> m_OnClosedCallback;
393 };
394 
395 #endif // HDLCD_CLIENT_H
Copyright (c) 2016, Florian Evers, florian-evers@gmx.de All rights reserved.
Copyright (c) 2016, Florian Evers, florian-evers@gmx.de All rights reserved.
void AsyncConnect(boost::asio::ip::tcp::resolver::iterator a_EndpointIterator, std::function< void(bool a_bSuccess)> a_OnConnectedCallback)
Perform an asynchronous connect procedure regarding both TCP sockets.
Definition: HdlcdClient.h:82
bool Send(const HdlcdPacketData &a_PacketData, std::function< void()> a_OnSendDoneCallback=nullptr)
Send a single data packet to the peer entity.
Definition: HdlcdClient.h:203
~HdlcdClient()
The destructor of HdlcdClient objects.
Definition: HdlcdClient.h:116
void Shutdown()
Shuts all TCP connections down.
Definition: HdlcdClient.h:127
Copyright (c) 2016, Florian Evers, florian-evers@gmx.de All rights reserved.
Copyright (c) 2016, Florian Evers, florian-evers@gmx.de All rights reserved.
void SetOnCtrlCallback(std::function< void(const HdlcdPacketCtrl &a_PacketCtrl)> a_OnCtrlCallback)
Provide a callback method to be called for received control packets.
Definition: HdlcdClient.h:182
Class HdlcdClient.
Definition: HdlcdClient.h:54
void SetOnClosedCallback(std::function< void()> a_OnClosedCallback)
Provide a callback method to be called if this client entity is closing.
Definition: HdlcdClient.h:192
void SetOnDataCallback(std::function< void(const HdlcdPacketData &a_PacketData)> a_OnDataCallback)
Provide a callback method to be called for received data packets.
Definition: HdlcdClient.h:172
HdlcdClient(boost::asio::io_service &a_IOService, const std::string &a_SerialPortName, HdlcdSessionDescriptor a_HdlcdSessionDescriptor)
The constructor of HdlcdClient objects.
Definition: HdlcdClient.h:64
bool Send(const HdlcdPacketCtrl &a_PacketCtrl, std::function< void()> a_OnSendDoneCallback=nullptr)
Send a single control packet to the peer entity.
Definition: HdlcdClient.h:223
static HdlcdSessionHeader Create(HdlcdSessionDescriptor a_HdlcdSessionDescriptor, const std::string &a_SerialPortName)
void Close()
Close the client entity.
Definition: HdlcdClient.h:141
Copyright (c) 2016, Florian Evers, florian-evers@gmx.de All rights reserved.