HAN-FUN API  1.5.3
This project provides the common implementation of ULE Alliance's HAN-FUN application protocol.
session_management.h
Go to the documentation of this file.
1 // =============================================================================
15 // =============================================================================
16 #ifndef HF_SESSION_MANAGEMENT_H
17 #define HF_SESSION_MANAGEMENT_H
18 
19 #include "hanfun/common.h"
20 #include "hanfun/protocol.h"
21 
22 namespace HF
23 {
24  namespace Core
25  {
29  namespace SessionManagement
30  {
42  typedef enum _CMD
43  {
45  GET,
46  END,
47  } CMD;
48 
49  // =============================================================================
50  // Messages API
51  // =============================================================================
52 
57  {
58  uint16_t count;
59 
65  StartResponse(uint16_t count = 0):
66  count(count)
67  {}
68 
70  static constexpr uint16_t min_size = Protocol::Response::min_size + sizeof(uint16_t);
71 
72  uint16_t size() const
73  {
74  return min_size;
75  }
76 
77  uint16_t pack(Common::ByteArray &array, uint16_t offset = 0) const
78  {
79  HF_SERIALIZABLE_CHECK(array, offset, min_size);
80 
81  offset += Protocol::Response::pack(array, offset);
82  array.write(offset, count);
83 
84  return min_size;
85  }
86 
87  uint16_t unpack(const Common::ByteArray &array, uint16_t offset = 0)
88  {
89  HF_SERIALIZABLE_CHECK(array, offset, min_size);
90 
91  offset += Protocol::Response::unpack(array, offset);
92  array.read(offset, count);
93 
94  return min_size;
95  }
96  };
97 
102  {
103  uint16_t offset;
104  uint8_t count;
105 
106 
107  GetEntriesMessage(uint16_t offset = 0, uint8_t count = 0):
109  {}
110 
112  constexpr static uint16_t min_size = sizeof(offset) + sizeof(count);
113 
115  uint16_t size() const
116  {
117  return min_size;
118  }
119 
121  uint16_t pack(Common::ByteArray &array, uint16_t offset = 0) const
122  {
124 
125  offset += array.write(offset, this->offset);
126  array.write(offset, this->count);
127 
128  return min_size;
129  }
130 
132  uint16_t unpack(const Common::ByteArray &array, uint16_t offset = 0)
133  {
135 
136  offset += array.read(offset, this->offset);
137  array.read(offset, this->count);
138 
139  return min_size;
140  }
141  };
142 
143  template<typename _Entry>
144  struct GetEntriesResponse: public Protocol::Response
145  {
146  std::vector<_Entry> entries;
147 
149  static constexpr uint16_t min_size = Protocol::Response::min_size
150  + sizeof(uint8_t); // Number of entries.
151 
152  uint16_t size() const
153  {
154  uint16_t result = min_size;
155 
156  /* *INDENT-OFF* */
157  std::for_each (entries.begin (), entries.end (), [&result](const _Entry &entry)
158  {
159  result += entry.size ();
160  });
161  /* *INDENT-ON* */
162 
163  return result;
164  }
165 
166  uint16_t pack(Common::ByteArray &array, uint16_t offset = 0) const
167  {
168  HF_SERIALIZABLE_CHECK(array, offset, size());
169 
170  uint16_t start = offset;
171 
172  offset += Protocol::Response::pack(array, offset);
173 
174  uint8_t count = entries.size();
175  offset += array.write(offset, count);
176 
177  /* *INDENT-OFF* */
178  std::for_each(entries.begin(), entries.end(),
179  [&offset, &array](const _Entry &entry)
180  {
181  offset += entry.pack (array, offset);
182  });
183  /* *INDENT-ON* */
184 
185  return offset - start;
186  }
187 
188  uint16_t unpack(const Common::ByteArray &array, uint16_t offset = 0)
189  {
190  HF_SERIALIZABLE_CHECK(array, offset, min_size);
191 
192  uint16_t start = offset;
193 
194  offset += Protocol::Response::unpack(array, offset);
195 
196  uint8_t count = 0;
197  offset += array.read(offset, count);
198 
199  entries.clear();
200 
201  _Entry entry;
202 
203  for (uint8_t i = 0; i < count; i++)
204  {
205  offset += entry.unpack(array, offset);
206  entries.push_back(entry);
207  }
208 
209  return offset - start;
210  }
211  };
212 
213  template<>
214  struct GetEntriesResponse<void>: public Protocol::Response
215  {
216  uint8_t count;
217 
218  GetEntriesResponse(): count(0)
219  {}
220 
222  static constexpr uint16_t min_size = Protocol::Response::min_size
223  + sizeof(uint8_t); // Number of entries.
224 
225  uint16_t size() const
226  {
227  return min_size;
228  }
229 
230  uint16_t pack(Common::ByteArray &array, uint16_t offset = 0) const
231  {
232  HF_SERIALIZABLE_CHECK(array, offset, min_size);
233 
234  offset += Protocol::Response::pack(array, offset);
235 
236  uint8_t count = 0;
237  array.write(offset, count);
238 
239  return min_size;
240  }
241 
242  uint16_t unpack(const Common::ByteArray &array, uint16_t offset = 0)
243  {
244  HF_SERIALIZABLE_CHECK(array, offset, min_size);
245 
246  offset += Protocol::Response::unpack(array, offset);
247 
248  uint8_t count = 0;
249  array.read(offset, count);
250 
251  return min_size;
252  }
253  };
254 
255  typedef GetEntriesResponse<void> GetEntriesEmptyResponse;
256 
257  // =============================================================================
258  // Server API
259  // =============================================================================
260 
264  struct IServer
265  {
273  virtual void start_session(uint16_t address) = 0;
274 
281  virtual void end_session(uint16_t address) = 0;
282 
291  virtual bool exists(uint16_t address) const = 0;
292 
303  virtual bool is_valid(uint16_t address) const = 0;
304  };
305 
309  class AbstractServer: public IServer
310  {
311  protected:
312 
319  struct Session
320  {
321  uint16_t address;
322  bool valid;
323 
330  Session(uint16_t _address = HF::Protocol::BROADCAST_ADDR, bool _valid = false):
331  address(_address), valid(_valid)
332  {}
333  };
334 
335  typedef std::vector<Session> Container;
336  typedef Container::iterator iterator;
337  typedef Container::const_iterator const_iterator;
338 
340  Container sessions;
341 
342  // =============================================================================
343  // API
344  // =============================================================================
345 
346  public:
347 
349  AbstractServer(): sessions(Container())
350  {}
351 
352  virtual ~AbstractServer()
353  {}
354 
355  void start_session(uint16_t address)
356  {
357  auto it = find(address);
358 
359  if (it == sessions.end()) // Session does not exist.
360  {
361  sessions.push_back(Session(address, true));
362  }
363  else // Session already exists. Update state.
364  {
365  it->valid = true;
366  }
367  }
368 
369  void end_session(uint16_t address)
370  {
371  auto it = find(address);
372 
373  if (it != sessions.end())
374  {
375  sessions.erase(it);
376  }
377  }
378 
379  bool exists(uint16_t address) const
380  {
381  return find(address) != sessions.end();
382  }
383 
384  bool is_valid(uint16_t address) const
385  {
386  auto it = find(address);
387 
388  if (it != sessions.end())
389  {
390  return it->valid;
391  }
392 
393  return false;
394  }
395 
399  void invalidate()
400  {
401  /* *INDENT-OFF* */
402  std::for_each (sessions.begin (), sessions.end (), [](Session &session)
403  {
404  session.valid = false;
405  });
406  /* *INDENT-ON* */
407  }
408 
409  protected:
410 
429  Common::ByteArray &payload, uint16_t offset = 0);
430 
438  iterator find(uint16_t address)
439  {
440  /* *INDENT-OFF* */
441  return std::find_if (sessions.begin (), sessions.end (),
442  [address](const Session &session)
443  {
444  return address == session.address;
445  });
446  /* *INDENT-ON* */
447  }
448 
456  const_iterator find(uint16_t address) const
457  {
458  /* *INDENT-OFF* */
459  return std::find_if (sessions.cbegin (), sessions.cend (),
460  [address](const Session &session)
461  {
462  return address == session.address;
463  });
464  /* *INDENT-ON* */
465  }
466 
475  uint16_t payload_size(CMD cmd) const;
476 
488  Common::Result check_offset(uint16_t offset, uint8_t &count, uint16_t size) const;
489 
491  virtual void send(const Protocol::Address &addr, Protocol::Message &message) = 0;
492 
498  virtual uint16_t entries_size() const = 0;
499 
516  virtual Common::Result entries(uint16_t offset,
517  uint8_t count,
518  Common::ByteArray &payload) = 0;
519 
533  Common::Result check_session(uint16_t address, Common::ByteArray &payload) const;
534  };
535 
543  template<typename Parent>
544  class EntriesWrapper: public Parent
545  {
546  AbstractServer &manager;
547 
548  public:
549 
550  typedef typename Parent::value_type value_type;
551 
557  EntriesWrapper(AbstractServer &_manager): Parent(),
558  manager(_manager)
559  {}
560 
567  EntriesWrapper(const EntriesWrapper &other, AbstractServer &_manager):
568  Parent(other), manager(_manager)
569  {}
570 
571  virtual ~EntriesWrapper()
572  {}
573 
575  Common::Result save(const value_type &entry)
576  {
577  auto res = Parent::save(entry);
578 
579  manager.invalidate();
580  return res;
581  }
582 
584  Common::Result destroy(const value_type &entry)
585  {
586  auto res = Parent::destroy(entry);
587 
588  manager.invalidate();
589  return res;
590  }
591  };
592 
597  template<typename _Entries>
598  struct Server: public AbstractServer
599  {
600  typedef EntriesWrapper<_Entries> Container;
601 
607  Container &entries() const
608  {
609  return const_cast<Container &>(_entries);
610  }
611 
612  protected:
613 
614  Server(): AbstractServer(), _entries(*this)
615  {}
616 
617  virtual ~Server()
618  {}
619 
627  Server(const Server &other):
628  AbstractServer(other), _entries(other._entries, *this)
629  {}
630 
631  // =============================================================================
632  // API
633  // =============================================================================
634 
635  uint16_t entries_size() const
636  {
637  return static_cast<uint16_t>(_entries.size());
638  }
639 
640  typedef typename _Entries::value_type value_type;
641 
642  Common::Result entries(uint16_t offset, uint8_t count, Common::ByteArray &payload)
643  {
644  GetEntriesResponse<value_type> response;
645 
646  response.code = check_offset(offset, count, entries_size());
647 
648  if (response.code == Common::Result::OK)
649  {
650  auto start = _entries.begin();
651  std::advance(start, offset);
652 
653  auto end = start;
654  std::advance(end, count);
655  std::copy(start, end, std::back_inserter(response.entries));
656  }
657 
658  payload = Common::ByteArray(response.size());
659 
660  response.pack(payload);
661 
662  return response.code;
663  }
664 
665  private:
666 
668  Container _entries;
669  };
670 
671  // =============================================================================
672  // Client API
673  // =============================================================================
674 
679  {
680  // ======================================================================
681  // Commands
682  // ======================================================================
685 
689  virtual void start_session() const = 0;
690 
694  virtual void end_session() const = 0;
695 
702  virtual void get_entries(uint16_t offset, uint8_t count = 0) const = 0;
703 
705  // ======================================================================
706  // ======================================================================
707  // Events
708  // ======================================================================
711 
718  virtual void session_started(StartResponse &response)
719  {
720  UNUSED(response);
721  }
722 
729  virtual void session_ended(Protocol::Response &response)
730  {
731  UNUSED(response);
732  }
733 
735  // ======================================================================
736 
737  protected:
738 
756  Common::ByteArray &payload, uint16_t offset = 0);
757 
766  uint16_t payload_size(CMD cmd) const;
767 
775  template<uint8_t _role, uint16_t _uid, uint8_t _member>
776  void get_entries(uint16_t offset, uint8_t count = 0) const
777  {
778  SessionManagement::GetEntriesMessage msg(offset, count);
779 
780  Protocol::Address addr(0, 0);
781  Protocol::Message message;
782 
783  message.itf.role = _role;
784  message.itf.id = _uid;
785  message.itf.member = _member;
786 
787  message.payload = Common::ByteArray(msg.size());
788 
789  msg.pack(message.payload);
790 
791  const_cast<AbstractClient *>(this)->send(addr, message);
792  }
793 
802  template<uint8_t _role, uint16_t _uid, uint8_t _member>
803  void request() const
804  {
805  Protocol::Address addr(0, 0);
806  Protocol::Message message;
807 
808  message.itf.role = _role;
809  message.itf.id = _uid;
810  message.itf.member = _member;
811 
812  const_cast<AbstractClient *>(this)->send(addr, message);
813  }
814 
816  virtual void send(const Protocol::Address &addr, Protocol::Message &message) = 0;
817  };
818 
823  template<typename _Entry>
824  struct Client: public AbstractClient
825  {
826  // ======================================================================
827  // Events
828  // ======================================================================
831 
837  virtual void entries(const GetEntriesResponse<_Entry> &response)
838  {
839  UNUSED(response);
840  }
841 
843  // ======================================================================
844 
845  protected:
846 
847  Common::Result handle_command(CMD cmd, Protocol::Packet &packet,
848  Common::ByteArray &payload, uint16_t offset = 0)
849  {
850  if (cmd == GET)
851  {
852  GetEntriesResponse<_Entry> response;
853  response.unpack(payload, offset);
854  entries(response);
855  return Common::Result::OK;
856  }
857  else
858  {
859  return AbstractClient::handle_command(cmd, packet, payload, offset);
860  }
861  }
862  };
863 
864  } // namespace SessionManagement
865 
868  } // namespace Core
869 
870 } // namespace HF
871 
872 #endif /* HF_SESSION_MANAGEMENT_H */
uint16_t unpack(const Common::ByteArray &array, uint16_t offset=0)
Read a message from a ByteArray.
uint16_t write(uint16_t offset, uint8_t data)
Write a byte into the array at the given offset.
bool response(Message::Type type)
Check if message is a response.
Helper template to inject session management functionality into services requiring it - Server side...
virtual void entries(const GetEntriesResponse< _Entry > &response)
This event is called when a response to a get entries is received.
virtual uint16_t entries_size() const =0
Get the number of entries present in the container.
Wrapper over persistent storage APIs to invalidate sessions on save and destroy.
Helper template to inject session management functionality into services requiring it - Client side...
Server(const Server &other)
Copy-Constructor.
virtual bool is_valid(uint16_t address) const =0
Check if the session for the device with the given address is valid, i.e., the underling entries have...
void get_entries(uint16_t offset, uint8_t count=0) const
Helper method to send a message to read, count entries starting at offset from the server...
This file contains the common defines for the HAN-FUN library.
uint16_t count
Number of device entries.
uint16_t size() const
Number bytes needed to serialize the message.
Common::Result entries(uint16_t offset, uint8_t count, Common::ByteArray &payload)
Create a GetEntriesResponse message message with, count entries starting from the given offset and se...
bool valid
Indicate if the session is still valid.
EntriesWrapper(AbstractServer &_manager)
Constructor.
Parent class for session management functionality - Server side.
constexpr uint16_t BROADCAST_ADDR
HAN-FUN Broadcast - device address.
Definition: protocol.h:45
uint16_t id
Identifier of the interface.
Container & entries() const
Return the container for the service entries.
virtual void send(const Protocol::Address &addr, Protocol::Message &message)=0
Send message msg to the network address given by addr.
static constexpr uint16_t min_size
Minimum pack/unpack required data size.
uint16_t pack(Common::ByteArray &array, uint16_t offset=0) const
Write the object on to a ByteArray so it can be sent over the network.
Container sessions
Session&#39;s database.
virtual void start_session(uint16_t address)=0
Start a session for the device with the given address.
This file contains the definitions for the HAN-FUN protocol messages.
const_iterator find(uint16_t address) const
Find the session associated with the given device address.
Common::Result destroy(const value_type &entry)
Destroy the given entry in the persistent storage.
static constexpr uint16_t min_size
Minimum pack/unpack required data size.
Common::ByteArray payload
Message payload.
Definition: protocol.h:134
Parent class for bind management - server role.
virtual void send(const Protocol::Address &addr, Protocol::Message &message)=0
Send message msg to the network address given by addr.
uint16_t offset
Start index for the first entry to be provided.
Protocol::Message * destroy(Type type, uint8_t report_id)
Remove the rule with the given type and the given report_id.
#define HF_SERIALIZABLE_CHECK(__array, __offset, __size)
Helper macro to check if the given __array has enough size so __size bytes can be written/read from t...
End the session for device.
Parent class for session management functionality - Client side.
iterator find(uint16_t address)
Find the session associated with the given device address.
bool is_valid(uint16_t address) const
Check if the session for the device with the given address is valid, i.e., the underling entries have...
uint8_t count
Number of entries to be sent in the response.
uint16_t role
Interface role : Server or Client.
Common::Result check_offset(uint16_t offset, uint8_t &count, uint16_t size) const
Check if the given offset is valid and adjust the count value if necessary.
bool exists(uint16_t address) const
Check if a session for the device with the given address exists.
uint16_t pack(Common::ByteArray &array, uint16_t offset=0) const
Write the object on to a ByteArray so it can be sent over the network.
This class represents a byte array.
virtual bool exists(uint16_t address) const =0
Check if a session for the device with the given address exists.
void invalidate()
Invalidate all sessions.
Start Read Session Command Message.
void end_session(uint16_t address)
Terminate the session associated with the device with the given address.
Network Address.
Definition: protocol.h:201
uint8_t member
Interface destination member.
Definition: protocol.h:99
uint16_t payload_size(CMD cmd) const
Get the minimum number of bytes necessary to pack/unpack a message of the given command.
CMD
Available commands for session management.
Network Message.
Definition: protocol.h:60
Session Management API : Server side.
virtual Common::Result entries(uint16_t offset, uint8_t count, Common::ByteArray &payload)=0
Create a GetEntriesResponse message message with, count entries starting from the given offset and se...
Session(uint16_t _address=HF::Protocol::BROADCAST_ADDR, bool _valid=false)
Constructor.
void start_session(uint16_t address)
Start a session for the device with the given address.
HAN-FUN Protocol Packet.
Definition: protocol.h:298
EntriesWrapper(const EntriesWrapper &other, AbstractServer &_manager)
Constructor.
Interface itf
Interface Address.
Definition: protocol.h:129
uint16_t read(uint16_t offset, uint8_t &data) const
Read the byte at offset into data.
StartResponse(uint16_t count=0)
Constructor.
Parent class for the response messages.
Definition: protocol.h:368
Common::Result handle_command(CMD cmd, Protocol::Packet &packet, Common::ByteArray &payload, uint16_t offset=0)
Handle command request/response messages.
#define UNUSED(x)
Helper macro to remove warning about unused function/method argument.
Common::Result handle_command(CMD cmd, Protocol::Packet &packet, Common::ByteArray &payload, uint16_t offset=0)
Handle command request/response messages.
Common::Result check_session(uint16_t address, Common::ByteArray &payload) const
Check if a session for the given device address exists and if it is valid.
static constexpr uint16_t min_size
Minimum number of bytes required by this message.
Definition: protocol.h:375
void request() const
Helper method to create a session management request.
Common::Result save(const value_type &entry)
Store the given entry to persistent storage.
virtual void end_session(uint16_t address)=0
Terminate the session associated with the device with the given address.
uint16_t unpack(const Common::ByteArray &array, uint16_t offset=0)
Read a message from a ByteArray.
uint16_t payload_size(CMD cmd) const
Get the minimum number of bytes necessary to pack/unpack a message of the given command.
Result
Commands result codes.
uint16_t entries_size() const
Get the number of entries present in the container.
Start a new session for a device.
Top-level namespace for the HAN-FUN library.
Definition: attributes.h:22