HDLC-Daemon
HdlcdClient.h
Go to the documentation of this file.
1 
39 #ifndef HDLCD_CLIENT_H
40 #define HDLCD_CLIENT_H
41 
42 #include <boost/asio.hpp>
43 #include <vector>
44 #include <string>
45 #include "HdlcdPacketEndpoint.h"
46 #include "HdlcdSessionHeader.h"
47 #include "HdlcdPacketData.h"
48 #include "HdlcdPacketCtrl.h"
49 #include "FrameEndpoint.h"
50 
60 class HdlcdClient {
61 public:
68  HdlcdClient(boost::asio::io_service& a_IOService, const std::string &a_SerialPortName, HdlcdSessionDescriptor a_HdlcdSessionDescriptor):
69  m_IOService(a_IOService),
70  m_SerialPortName(a_SerialPortName),
71  m_HdlcdSessionDescriptor(a_HdlcdSessionDescriptor),
72  m_bClosed(false),
73  m_TcpSocketData(a_IOService),
74  m_TcpSocketCtrl(a_IOService),
75  m_eTcpSocketDataState(SOCKET_STATE_ERROR),
76  m_eTcpSocketCtrlState(SOCKET_STATE_ERROR) {
77  }
78 
84  void AsyncConnect(boost::asio::ip::tcp::resolver::iterator a_EndpointIterator, std::function<void(bool a_bSuccess)> a_OnConnectedCallback) {
85  // Checks
86  assert(a_OnConnectedCallback);
87  assert(m_eTcpSocketDataState == SOCKET_STATE_ERROR); // not tried yet, or retrying
88  assert(m_eTcpSocketCtrlState == SOCKET_STATE_ERROR); // not tried yet, or retrying
89 
90  // Connect the data socket
91  m_OnConnectedCallback = a_OnConnectedCallback;
92  m_eTcpSocketDataState = SOCKET_STATE_CONNECTING;
93  boost::asio::async_connect(m_TcpSocketData, a_EndpointIterator, [this](boost::system::error_code a_ErrorCode, boost::asio::ip::tcp::resolver::iterator) {
94  if (a_ErrorCode == boost::asio::error::operation_aborted) return;
95  if (a_ErrorCode) {
96  OnTcpSocketDataConnected(false);
97  } else {
98  OnTcpSocketDataConnected(true);
99  } // else
100  });
101 
102  // Connect the control socket
103  m_eTcpSocketCtrlState = SOCKET_STATE_CONNECTING;
104  boost::asio::async_connect(m_TcpSocketCtrl, a_EndpointIterator, [this](boost::system::error_code a_ErrorCode, boost::asio::ip::tcp::resolver::iterator) {
105  if (a_ErrorCode == boost::asio::error::operation_aborted) return;
106  if (a_ErrorCode) {
107  OnTcpSocketCtrlConnected(false);
108  } else {
109  OnTcpSocketCtrlConnected(true);
110  } // else
111  });
112  }
113 
119  m_OnDataCallback = nullptr;
120  m_OnCtrlCallback = nullptr;
121  m_OnClosedCallback = nullptr;
122  Close();
123  }
124 
129  void Shutdown() {
130  if (m_PacketEndpointData) {
131  m_PacketEndpointData->Shutdown();
132  } // if
133 
134  if (m_PacketEndpointCtrl) {
135  m_PacketEndpointCtrl->Shutdown();
136  } // if
137  }
138 
143  void Close() {
144  if (m_bClosed == false) {
145  m_bClosed = true;
146  if (m_PacketEndpointData) {
147  m_PacketEndpointData->Close();
148  m_PacketEndpointData.reset();
149  } else {
150  m_TcpSocketData.cancel();
151  m_TcpSocketData.close();
152  } // else
153 
154  if (m_PacketEndpointCtrl) {
155  m_PacketEndpointCtrl->Close();
156  m_PacketEndpointCtrl.reset();
157  } else {
158  m_TcpSocketCtrl.cancel();
159  m_TcpSocketCtrl.close();
160  } // else
161 
162  if (m_OnClosedCallback) {
163  m_OnClosedCallback();
164  } // if
165  } // if
166  }
167 
174  void SetOnDataCallback(std::function<void(const HdlcdPacketData& a_PacketData)> a_OnDataCallback) {
175  m_OnDataCallback = a_OnDataCallback;
176  }
177 
184  void SetOnCtrlCallback(std::function<void(const HdlcdPacketCtrl& a_PacketCtrl)> a_OnCtrlCallback) {
185  m_OnCtrlCallback = a_OnCtrlCallback;
186  }
187 
194  void SetOnClosedCallback(std::function<void()> a_OnClosedCallback) {
195  m_OnClosedCallback = a_OnClosedCallback;
196  }
197 
209  bool Send(const HdlcdPacketData& a_PacketData, std::function<void()> a_OnSendDoneCallback = nullptr) {
210  bool l_bRetVal = false;
211  if (m_PacketEndpointData) {
212  l_bRetVal = m_PacketEndpointData->Send(a_PacketData, a_OnSendDoneCallback);
213  } else {
214  if (a_OnSendDoneCallback) {
215  m_IOService.post([a_OnSendDoneCallback](){ a_OnSendDoneCallback(); });
216  } // if
217  } // else
218 
219  return l_bRetVal;
220  }
221 
233  bool Send(const HdlcdPacketCtrl& a_PacketCtrl, std::function<void()> a_OnSendDoneCallback = nullptr) {
234  bool l_bRetVal = false;
235  if (m_PacketEndpointCtrl) {
236  l_bRetVal= m_PacketEndpointCtrl->Send(a_PacketCtrl, a_OnSendDoneCallback);
237  } else {
238  if (a_OnSendDoneCallback) {
239  m_IOService.post([a_OnSendDoneCallback](){ a_OnSendDoneCallback(); });
240  } // if
241  } // else
242 
243  return l_bRetVal;
244  }
245 
246 private:
253  void OnTcpSocketDataConnected(bool l_bSuccess) {
254  // Checks
255  assert(m_eTcpSocketDataState == SOCKET_STATE_CONNECTING);
256  if (l_bSuccess) {
257  m_eTcpSocketDataState = SOCKET_STATE_CONNECTED;
258  } else {
259  m_eTcpSocketDataState = SOCKET_STATE_ERROR;
260  } // else
261 
262  OnTcpSocketConnected();
263  }
264 
271  void OnTcpSocketCtrlConnected(bool l_bSuccess) {
272  // Checks
273  assert(m_eTcpSocketCtrlState == SOCKET_STATE_CONNECTING);
274  if (l_bSuccess) {
275  m_eTcpSocketCtrlState = SOCKET_STATE_CONNECTED;
276  } else {
277  m_eTcpSocketCtrlState = SOCKET_STATE_ERROR;
278  } // else
279 
280  OnTcpSocketConnected();
281  }
282 
287  void OnTcpSocketConnected() {
288  // Checks
289  if ((m_eTcpSocketDataState == SOCKET_STATE_CONNECTING) && (m_eTcpSocketCtrlState == SOCKET_STATE_CONNECTING)) {
290  // Invalid state
291  assert(false);
292  return;
293  } // if
294 
295  if ((m_eTcpSocketDataState == SOCKET_STATE_CONNECTED) && (m_eTcpSocketCtrlState == SOCKET_STATE_CONNECTED)) {
296  // Success!
297  // Create and start the packet endpoint for the exchange of user data packets
298  m_PacketEndpointData = std::make_shared<HdlcdPacketEndpoint>(m_IOService, std::make_shared<FrameEndpoint>(m_IOService, m_TcpSocketData));
299  m_PacketEndpointData->SetOnDataCallback([this](std::shared_ptr<const HdlcdPacketData> a_PacketData){ return OnDataReceived(a_PacketData); });
300  m_PacketEndpointData->SetOnClosedCallback([this](){ OnClosed(); });
301  m_PacketEndpointData->Start();
302  m_PacketEndpointData->Send(HdlcdSessionHeader::Create(m_HdlcdSessionDescriptor, m_SerialPortName));
303 
304  // Create and start the packet endpoint for the exchange of control packets
305  m_PacketEndpointCtrl = std::make_shared<HdlcdPacketEndpoint>(m_IOService, std::make_shared<FrameEndpoint>(m_IOService, m_TcpSocketCtrl));
306  m_PacketEndpointCtrl->SetOnCtrlCallback([this](const HdlcdPacketCtrl& a_PacketCtrl){ return OnCtrlReceived(a_PacketCtrl); });
307  m_PacketEndpointCtrl->SetOnClosedCallback([this](){ OnClosed(); });
308  m_PacketEndpointCtrl->Start();
309  m_PacketEndpointCtrl->Send(HdlcdSessionHeader::Create(HdlcdSessionDescriptor(SESSION_TYPE_TRX_STATUS, SESSION_FLAGS_NONE), m_SerialPortName));
310  m_OnConnectedCallback(true);
311  return;
312  } // if
313 
314  if ((m_eTcpSocketDataState == SOCKET_STATE_CONNECTING) || (m_eTcpSocketCtrlState == SOCKET_STATE_CONNECTING)) {
315  // Needs to wait for the second socket
316  return;
317  } // if
318 
319 
320  if (m_eTcpSocketDataState == SOCKET_STATE_CONNECTED) {
321  // The control socket failed after the data socket succeeded
322  assert(m_eTcpSocketCtrlState == SOCKET_STATE_ERROR);
323  m_eTcpSocketDataState = SOCKET_STATE_ERROR;
324  m_TcpSocketData.close();
325  m_OnConnectedCallback(false);
326  return;
327  } // else if
328 
329  if (m_eTcpSocketCtrlState == SOCKET_STATE_CONNECTED) {
330  // The data socket failed after the control socket succeeded
331  assert(m_eTcpSocketDataState == SOCKET_STATE_ERROR);
332  m_eTcpSocketCtrlState = SOCKET_STATE_ERROR;
333  m_TcpSocketCtrl.close();
334  m_OnConnectedCallback(false);
335  return;
336  } // else if
337 
338  // Both sockets failed
339  assert(m_eTcpSocketDataState == SOCKET_STATE_ERROR);
340  assert(m_eTcpSocketCtrlState == SOCKET_STATE_ERROR);
341  m_OnConnectedCallback(false);
342  return;
343  }
344 
355  bool OnDataReceived(std::shared_ptr<const HdlcdPacketData> a_PacketData) {
356  if (m_OnDataCallback) {
357  m_OnDataCallback(*(a_PacketData.get()));
358  } // if
359 
361  return true; // Do not stall the receiver
362  }
363 
370  void OnCtrlReceived(const HdlcdPacketCtrl& a_PacketCtrl) {
371  if (m_OnCtrlCallback) {
372  m_OnCtrlCallback(a_PacketCtrl);
373  } // if
374  }
375 
380  void OnClosed() {
381  Close();
382  }
383 
384  // Members
385  boost::asio::io_service& m_IOService;
386  const std::string m_SerialPortName;
387  const HdlcdSessionDescriptor m_HdlcdSessionDescriptor;
388  bool m_bClosed;
389 
390  std::function<void(bool a_bSuccess)> m_OnConnectedCallback;
391  boost::asio::ip::tcp::socket m_TcpSocketData;
392  boost::asio::ip::tcp::socket m_TcpSocketCtrl;
393  typedef enum {
394  SOCKET_STATE_ERROR = 0,
395  SOCKET_STATE_CONNECTING = 1,
396  SOCKET_STATE_CONNECTED = 2,
397  } E_SOCKET_STATE;
398  E_SOCKET_STATE m_eTcpSocketDataState;
399  E_SOCKET_STATE m_eTcpSocketCtrlState;
400 
401  std::shared_ptr<HdlcdPacketEndpoint> m_PacketEndpointData;
402  std::shared_ptr<HdlcdPacketEndpoint> m_PacketEndpointCtrl;
403 
404  // All possible callbacks for a user of this class
405  std::function<void(const HdlcdPacketData&)> m_OnDataCallback;
406  std::function<void(const HdlcdPacketCtrl&)> m_OnCtrlCallback;
407  std::function<void()> m_OnClosedCallback;
408 };
409 
410 #endif // HDLCD_CLIENT_H
This file contains the header declaration of class HdlcdSessionHeader.
This file contains the header declaration of class FrameEndpoint.
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:84
bool Send(const HdlcdPacketData &a_PacketData, std::function< void()> a_OnSendDoneCallback=nullptr)
Send a single data packet to the peer entity.
Definition: HdlcdClient.h:209
Empty list of flags.
~HdlcdClient()
The destructor of HdlcdClient objects.
Definition: HdlcdClient.h:118
void Shutdown()
Shuts all TCP connections down.
Definition: HdlcdClient.h:129
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:184
Class HdlcdClient.
Definition: HdlcdClient.h:60
void SetOnClosedCallback(std::function< void()> a_OnClosedCallback)
Provide a callback method to be called if this client entity is closing.
Definition: HdlcdClient.h:194
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:174
Port status only, no data exchange, port status read and write.
HdlcdClient(boost::asio::io_service &a_IOService, const std::string &a_SerialPortName, HdlcdSessionDescriptor a_HdlcdSessionDescriptor)
The constructor of HdlcdClient objects.
Definition: HdlcdClient.h:68
bool Send(const HdlcdPacketCtrl &a_PacketCtrl, std::function< void()> a_OnSendDoneCallback=nullptr)
Send a single control packet to the peer entity.
Definition: HdlcdClient.h:233
static HdlcdSessionHeader Create(HdlcdSessionDescriptor a_HdlcdSessionDescriptor, const std::string &a_SerialPortName)
Static creator to create an object in the process of transmission.
void Close()
Close the client entity.
Definition: HdlcdClient.h:143
Copyright (c) 2016, Florian Evers, florian-evers@gmx.de All rights reserved.
Class HdlcdSessionDescriptor.