HAN-FUN API  1.5.3
This project provides the common implementation of ULE Alliance's HAN-FUN application protocol.
transport.cpp
Go to the documentation of this file.
1 // =============================================================================
16 // =============================================================================
17 #include <iostream>
18 #include <iomanip>
19 
20 #include <cassert>
21 #include <cstdlib>
22 #include <cstdint>
23 
24 #include "uv.h"
25 
26 #include "hanfun.h"
27 
28 #include "application.h"
29 
30 #include "transport.h"
31 
32 #include "common.h"
33 
39 // =============================================================================
40 // Defines
41 // =============================================================================
42 
43 #define NONE_MSG 0xFFFF
44 #define HELLO_MSG 0x0101
45 #define DATA_MSG 0x0201
46 
47 
50 #define CHECK_STATUS() \
51  if (status != 0) \
52  { \
53  print_error(uv_last_error(uv_default_loop())); \
54  exit(-1); \
55  }
56 
60 struct msg_t
61 {
62  uint16_t nbytes;
63  uint16_t primitive;
65 
71  msg_t(uint16_t primitive = NONE_MSG):
73  {}
74 
83  {}
84 
86  static constexpr uint16_t min_size = sizeof(nbytes) + sizeof(primitive);
87 
89  uint16_t size() const
90  {
91  return min_size + data.size();
92  }
93 
95  uint16_t pack(HF::Common::ByteArray &array, uint16_t offset = 0) const
96  {
97  HF_SERIALIZABLE_CHECK(array, offset, size());
98 
99  uint16_t start = offset;
100 
101  uint16_t temp = (uint16_t) (sizeof(uint16_t) + data.size());
102 
103  offset += array.write(offset, temp);
104 
105  offset += array.write(offset, primitive);
106 
107  std::copy(data.begin(), data.end(), array.begin() + offset);
108 
109  return offset - start;
110  }
111 
113  uint16_t unpack(HF::Common::ByteArray &array, uint16_t offset = 0)
114  {
115  HF_SERIALIZABLE_CHECK(array, offset, min_size);
116 
117  uint16_t start = offset;
118 
119  offset += array.read(offset, nbytes);
120 
121  offset += array.read(offset, primitive);
122 
123  uint16_t data_size = nbytes - sizeof(primitive);
124 
125  data = HF::Common::ByteArray(data_size);
126 
127  auto begin = array.begin();
128 
129  begin += offset;
130 
131  auto end = begin + data_size;
132 
133  std::copy(begin, end, data.begin());
134 
135  return offset - start;
136  }
137 };
138 
143 {
144  uint8_t core;
145  uint8_t profiles;
146  uint8_t interfaces;
147 
149 
150  hello_msg_t():
152  {}
153 
155  static constexpr uint16_t min_size = 3 * sizeof(uint8_t);
156 
158  uint16_t size() const
159  {
160  return min_size + uid.size();
161  }
162 
164  uint16_t pack(HF::Common::ByteArray &array, uint16_t offset = 0) const
165  {
166  HF_SERIALIZABLE_CHECK(array, offset, size());
167 
168  uint16_t start = offset;
169 
170  offset += array.write(offset, core);
171  offset += array.write(offset, profiles);
172  offset += array.write(offset, interfaces);
173 
174  offset += uid.pack(array, offset);
175 
176  return offset - start;
177  }
178 
180  uint16_t unpack(HF::Common::ByteArray &array, uint16_t offset = 0)
181  {
182  HF_SERIALIZABLE_CHECK(array, offset, min_size);
183 
184  uint16_t start = offset;
185 
186  offset += array.read(offset, core);
187  offset += array.read(offset, profiles);
188  offset += array.read(offset, interfaces);
189 
190  uid.unpack(array, offset);
191 
192  return offset - start;
193  }
194 };
195 
196 // =============================================================================
197 // Libuv Helpers
198 // =============================================================================
199 
200 // =============================================================================
201 // alloc_buffer
202 // =============================================================================
211 // =============================================================================
212 uv_buf_t alloc_buffer(uv_handle_t *handle, size_t suggested_size)
213 {
214  UNUSED(handle);
215  return uv_buf_init((char *) calloc(1, suggested_size), suggested_size);
216 }
217 
218 // =============================================================================
219 // print_error
220 // =============================================================================
226 // =============================================================================
227 void print_error(uv_err_t status)
228 {
229  LOG(ERROR) << uv_err_name((uv_err_t &) status) << " - "
230  << uv_strerror((uv_err_t &) status) << NL;
231 }
232 
233 static void handle_message(HF::Application::Link *link, msg_t &msg);
234 
235 // =============================================================================
236 // on_close
237 // =============================================================================
243 // =============================================================================
244 static void on_close(uv_handle_t *handle)
245 {
246  LOG(DEBUG) << "Connection Closed!" << NL;
247 
248  UNUSED(handle);
249 }
250 
251 // =============================================================================
252 // on_read
253 // =============================================================================
261 // =============================================================================
262 static void on_read(uv_stream_t *stream, ssize_t nread, uv_buf_t buf)
263 {
264  HF::Application::Link *link = (HF::Application::Link *) stream->data;
265 
266  HF::Application::Transport *tsp = link->transport();
267 
268  LOG(TRACE) << __PRETTY_FUNCTION__ << " : " << stream << " : " << link << NL;
269 
270  if (nread < 0)
271  {
272  LOG(DEBUG) << "Could not read from stream !" << NL;
273  LOG(DEBUG) << "Stream closed !" << NL;
274 
275  tsp->remove(link);
276 
277  uv_close((uv_handle_t *) stream, on_close);
278  }
279  else if (nread > 0)
280  {
281  HF::Common::ByteArray payload((uint8_t *) buf.base, nread);
282 
283  LOG(TRACE) << "RECV : " << payload << NL;
284 
285  msg_t msg;
286  msg.unpack(payload);
287 
288  LOG(TRACE) << "Size : " << msg.nbytes << NL;
289  LOG(TRACE) << "Primitive : " << std::hex << std::setw(4) << std::setfill('0')
290  << msg.primitive << NL;
291  LOG(TRACE) << "Data : " << msg.data << NL;
292 
293  handle_message(link, msg);
294  }
295 
296  free(buf.base);
297 }
298 
299 // =============================================================================
300 // on_write
301 // =============================================================================
308 // =============================================================================
309 static void on_write(uv_write_t *req, int status)
310 {
311  CHECK_STATUS();
312 
313  LOG(TRACE) << __PRETTY_FUNCTION__ << NL;
314 
315  assert(req->type == UV_WRITE);
316 
317  /* Free the read/write buffer and the request */
318  free(req);
319 }
320 
321 // =============================================================================
322 // send_message
323 // =============================================================================
330 // =============================================================================
331 static void send_message(uv_stream_t *stream, msg_t &msg)
332 {
333  HF::Common::ByteArray payload(msg.size());
334  msg.pack(payload);
335 
336  LOG(TRACE) << "SEND : " << payload << NL;
337 
338  uv_write_t *req = (uv_write_t *) calloc(1, sizeof(uv_write_t));
339  uv_buf_t buf = uv_buf_init((char *) payload.data(), payload.size());
340 
341  uv_write(req, (uv_stream_t *) stream, &buf, 1 /*nbufs*/, on_write);
342 }
343 
344 // =============================================================================
345 // send_hello
346 // =============================================================================
353 // =============================================================================
354 static void send_hello(uv_stream_t *stream, HF::Application::Transport *tsp)
355 {
356  hello_msg_t hello;
357 
358  hello.uid = tsp->uid();
359 
360  msg_t msg(HELLO_MSG);
361 
362  msg.data = HF::Common::ByteArray(hello.size());
363 
364  hello.pack(msg.data);
365 
366  send_message(stream, msg);
367 }
368 
369 // =============================================================================
370 // handle_message
371 // =============================================================================
378 // =============================================================================
379 static void handle_message(HF::Application::Link *link, msg_t &msg)
380 {
381  HF::Application::Transport *tsp = link->transport();
382 
383  switch (msg.primitive)
384  {
385  case HELLO_MSG:
386  {
387  hello_msg_t hello;
388 
389  hello.unpack(msg.data);
390 
391  LOG(TRACE) << hello.uid << NL;
392 
393  ((HF::Application::Link *) link)->uid(hello.uid.raw()->clone());
394 
395  tsp->add(link);
396 
397  break;
398  }
399  case DATA_MSG:
400  {
401  tsp->receive(link, msg.data);
402  break;
403  }
404  default:
405  break;
406  }
407 }
408 
409 // =============================================================================
410 // on_connect
411 // =============================================================================
420 // =============================================================================
421 
422 #ifdef HF_BASE_APP
423 
424 // =============================================================================
425 // on_connect
426 // =============================================================================
430 // =============================================================================
431 static void on_connect(uv_stream_t *server, int status)
432 {
433  CHECK_STATUS();
434 
435  LOG(TRACE) << __PRETTY_FUNCTION__ << NL;
436 
437  uv_tcp_t *client = (uv_tcp_t *) calloc(1, sizeof(uv_tcp_t));
438 
439  client->data = nullptr;
440 
441  uv_tcp_init(server->loop, client);
442 
443  if (uv_accept(server, (uv_stream_t *) client))
444  {
445  LOG(ERROR) << "Could not accept the connection !" << NL;
446  uv_close((uv_handle_t *) client, on_close);
447  }
448  else
449  {
450  LOG(INFO) << "Connection accepted !" << NL;
451 
452  HF::Application::Transport *tsp = ((HF::Application::Transport *) server->data);
453  HF::Application::Link *link = new HF::Application::Link(tsp, (uv_stream_t *) client);
454 
455  client->data = link;
456 
457  uv_read_start((uv_stream_t *) client, (uv_alloc_cb) alloc_buffer, on_read);
458 
459  send_hello((uv_stream_t *) client, tsp);
460  }
461 }
462 
463 // =============================================================================
464 // API
465 // =============================================================================
466 
467 // =============================================================================
468 // Transport::initialize
469 // =============================================================================
473 // =============================================================================
475 {
476  uv_loop_t *loop = uv_default_loop();
477 
478  uv_tcp_init(loop, &socket);
479 
480  socket.data = this;
481 
482  LOG(TRACE) << __PRETTY_FUNCTION__ << NL;
483 
484  struct sockaddr_in bind_addr = uv_ip4_addr("127.0.0.1", 8000);
485 
486  if (uv_tcp_bind(&socket, bind_addr) != 0)
487  {
488  print_error(loop->last_err);
489  exit(-1);
490  }
491 
492  if (uv_listen((uv_stream_t *) &socket, 128, on_connect) != 0)
493  {
494  print_error(loop->last_err);
495  exit(-2);
496  }
497 }
498 
499 #endif
500 
501 #ifdef HF_NODE_APP
502 
503 // =============================================================================
504 // on_connect
505 // =============================================================================
509 // =============================================================================
510 static void on_connect(uv_connect_t *conn, int status)
511 {
512  CHECK_STATUS();
513 
514  LOG(TRACE) << __PRETTY_FUNCTION__ << NL;
515 
516  uv_stream_t *stream = conn->handle;
517 
518  uv_read_start(stream, (uv_alloc_cb) alloc_buffer, on_read);
519 
520  if (uv_is_writable(stream) && uv_is_readable(stream))
521  {
522  LOG(INFO) << "Connected !" << NL;
523 
524  HF::Application::Transport *tsp = ((HF::Application::Transport *) stream->data);
525  HF::Application::Link *link = new HF::Application::Link(tsp, stream);
526 
527  stream->data = link;
528 
529  send_hello(stream, tsp);
530  }
531  else
532  {
533  LOG(ERROR) << "Cannot read/write to stream !" << NL;
534  uv_close((uv_handle_t *) conn->handle, NULL);
535  }
536 
537  free(conn);
538 }
539 
540 // =============================================================================
541 // API
542 // =============================================================================
543 
544 // =============================================================================
545 // Transport::initialize
546 // =============================================================================
550 // =============================================================================
552 {
553  LOG(TRACE) << __PRETTY_FUNCTION__ << NL;
554 
555  uv_tcp_init(uv_default_loop(), &socket);
556  uv_tcp_keepalive(&socket, 1, 60);
557 
558  socket.data = this;
559 
560  uv_connect_t *connect = (uv_connect_t *) calloc(1, sizeof(uv_connect_t));
561 
562  struct sockaddr_in dest = uv_ip4_addr("127.0.0.1", 8000);
563 
564  uv_tcp_connect(connect, &socket, dest, on_connect);
565 }
566 
567 #endif
568 
569 // =============================================================================
570 // Transport::destroy
571 // =============================================================================
575 // =============================================================================
577 {
578  LOG(TRACE) << __PRETTY_FUNCTION__ << NL;
579 }
580 
581 // =============================================================================
582 // HF::Application::Link::send
583 // =============================================================================
587 // =============================================================================
589 {
590  LOG(TRACE) << __PRETTY_FUNCTION__ << NL;
591 
592  msg_t msg(DATA_MSG);
593 
594  msg.data = array;
595 
596  send_message((uv_stream_t *) stream, msg);
597 }
598 
601 #if HF_GROUP_SUPPORT
602 
603 // =============================================================================
604 // HF::Transport::Group::create
605 // =============================================================================
609 // =============================================================================
610 HF::Common::Result HF::Transport::Group::create(Endpoint &ep, uint16_t group)
611 {
612  UNUSED(ep);
613  UNUSED(group);
614 
615  LOG(WARN) << __PRETTY_FUNCTION__ << ": Not implemented !!" << NL;
616 
618 }
619 
620 // =============================================================================
621 // HF::Transport::Group::add
622 // =============================================================================
626 // =============================================================================
627 HF::Common::Result HF::Transport::Group::add(Endpoint &ep, uint16_t group, uint16_t device)
628 {
629  UNUSED(ep);
630  UNUSED(group);
631  UNUSED(device);
632 
633  LOG(WARN) << __PRETTY_FUNCTION__ << ": Not implemented !!" << NL;
634 
636 }
637 
638 // =============================================================================
639 // HF::Transport::Group::remove
640 // =============================================================================
644 // =============================================================================
645 void HF::Transport::Group::remove(Endpoint &ep, uint16_t group, uint16_t device)
646 {
647  UNUSED(ep);
648  UNUSED(group);
649  UNUSED(device);
650 
651  LOG(WARN) << __PRETTY_FUNCTION__ << ": Not implemented !!" << NL;
652 }
653 
654 // =============================================================================
655 // HF::Transport::Group::remove
656 // =============================================================================
660 // =============================================================================
661 void HF::Transport::Group::remove(Endpoint &ep, uint16_t group)
662 {
663  UNUSED(ep);
664  UNUSED(group);
665 
666  LOG(WARN) << __PRETTY_FUNCTION__ << ": Not implemented !!" << NL;
667 }
668 
669 #endif
uv_buf_t alloc_buffer(uv_handle_t *handle, size_t suggested_size)
This function is used to allocate the buffers used with libuv.
Definition: transport.cpp:212
uint16_t write(uint16_t offset, uint8_t data)
Write a byte into the array at the given offset.
void receive(HF::Transport::Link *link, HF::Common::ByteArray &payload)
Receive the data in payload, coming in in the given link and deliver the decoded packet to all regist...
uint8_t core
HAN-FUN Core Services & Interfaces version.
Definition: transport.cpp:144
constexpr uint8_t CORE_VERSION
Core Service & Interfaces major version supported.
This is the top level include file for the HAN-FUN library.
uint16_t unpack(HF::Common::ByteArray &array, uint16_t offset=0)
Read a message from a ByteArray.
Definition: transport.cpp:180
Common::Result create(Endpoint &ep, uint16_t group)
Create a new group of devices at the transport layer with the given address.
Transport Layer implementation over TCP/IP using libuv.
This file contains the definitions for the HAN-FUN example applications.
#define CHECK_STATUS()
Helper macro the check libuv command status.
Definition: transport.cpp:50
constexpr uint8_t PROFILES_VERSION
Profiles major version supported.
msg_t(uint16_t primitive, HF::Common::ByteArray &data)
Constructor.
Definition: transport.cpp:81
virtual T * clone() const =0
Create a clone object of the object where this method is being called.
uint16_t size() const
Number bytes needed to serialize the message.
Definition: transport.cpp:158
uint16_t size() const
Number bytes needed to serialize the message.
Definition: uids.h:604
UID_T const * raw() const
Get the underling wrapped UID_T pointer.
Definition: uids.h:704
uint16_t pack(Common::ByteArray &array, uint16_t offset) const
Write the object on to a ByteArray so it can be sent over the network.
Definition: uids.h:609
This file contains the declarations of the transport layer over libuv.
#define NONE_MSG
No message primitive id.
Definition: transport.cpp:43
void destroy()
Free the system resources associated with this transport layer.
Definition: transport.cpp:576
#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...
uint8_t profiles
HAN-FUN Profiles version.
Definition: transport.cpp:145
uv_tcp_t socket
libuv tcp/ip socket.
Hello message payload.
Definition: transport.cpp:142
uint16_t pack(HF::Common::ByteArray &array, uint16_t offset=0) const
Write the object on to a ByteArray so it can be sent over the network.
Definition: transport.cpp:95
uint16_t unpack(HF::Common::ByteArray &array, uint16_t offset=0)
Read a message from a ByteArray.
Definition: transport.cpp:113
uint16_t primitive
Message type.
Definition: transport.cpp:63
uint8_t interfaces
HAN-FUN Interfaces version.
Definition: transport.cpp:146
constexpr uint8_t INTERFACES_VERSION
Interfaces major version supported.
Common::Result add(Endpoint &ep, uint16_t group, uint16_t device)
Add the given device to the given group for the given end-point ep.
void print_error(uv_err_t status)
Print a user friendly string for given status code.
Definition: transport.cpp:227
uint16_t nbytes
Number of bytes in the message.
Definition: transport.cpp:62
Message sent between the concentrator and the nodes.
Definition: transport.cpp:60
Wrapper around UID_T pointer&#39;s.
Definition: uids.h:531
This class represents a byte array.
#define NL
Helper define for new-line and stream clear.
Definition: debug.h:34
const HF::UID::UID uid() const
Return the UID of the local device on this transport layer.
#define DATA_MSG
Data message primitive id.
Definition: transport.cpp:45
HF::Common::ByteArray data
Message payload.
Definition: transport.cpp:64
void add(HF::Transport::Endpoint *ep)
Register the given Endpoint to receive events.
Definition: devices.h:945
Fail - Not Supported.
uint16_t read(uint16_t offset, uint8_t &data) const
Read the byte at offset into data.
void send(HF::Common::ByteArray &array)
Send the data in the given ByteArray using the link to the remote end-point.
Definition: transport.cpp:588
static constexpr uint16_t min_size
Minimum pack/unpack required data size.
Definition: transport.cpp:155
#define UNUSED(x)
Helper macro to remove warning about unused function/method argument.
void initialize()
Initialize the associated transport layer.
Definition: transport.cpp:474
This file contains the definitions for the common functionality in the HAN-FUN example applications...
uint16_t size() const
Number bytes needed to serialize the message.
Definition: transport.cpp:89
static constexpr uint16_t min_size
Minimum pack/unpack required data size.
Definition: transport.cpp:86
void remove(Endpoint &ep, uint16_t group, uint16_t device)
Remove the given device from the given group for the given end-point ep.
HF::UID::UID uid
Remote device UID.
Definition: transport.cpp:148
#define LOG(X)
Log messages with the level given by X.
Definition: debug.h:81
uint16_t pack(HF::Common::ByteArray &array, uint16_t offset=0) const
Write the object on to a ByteArray so it can be sent over the network.
Definition: transport.cpp:164
#define HELLO_MSG
Hello message primitive id.
Definition: transport.cpp:44
msg_t(uint16_t primitive=NONE_MSG)
Constructor.
Definition: transport.cpp:71
Result
Commands result codes.
uint16_t unpack(const Common::ByteArray &array, uint16_t offset)
Read a message from a ByteArray.
Top-level namespace for the HAN-FUN library.
Definition: attributes.h:22