Skip to content

Commit

Permalink
Add option to join COAP multicast group (ARMmbed#67)
Browse files Browse the repository at this point in the history
* Add option to join COAP multicast group

Option COAP_SERVICE_OPTIONS_MULTICAST_JOIN added to service_api to
join COAP multicast group. The group is left when service is deleted.
  • Loading branch information
Arto Kinnunen authored May 5, 2017
1 parent 381d910 commit 76490a7
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 58 deletions.
2 changes: 2 additions & 0 deletions coap-service/coap_service_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ extern "C" {
#define COAP_SERVICE_OPTIONS_EPHEMERAL_PORT 0x04
/** Coap interface selected as socket interface */
#define COAP_SERVICE_OPTIONS_SELECT_SOCKET_IF 0x08
/** Register to COAP multicast groups */
#define COAP_SERVICE_OPTIONS_MULTICAST_JOIN 0x10
/** Link-layer security bypass option is set*/
#define COAP_SERVICE_OPTIONS_SECURE_BYPASS 0x80

Expand Down
47 changes: 32 additions & 15 deletions source/coap_connection_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,9 +225,30 @@ static secure_session_t *secure_session_find(internal_socket_t *parent, const ui
return this;
}

static internal_socket_t *int_socket_create(uint16_t listen_port, bool use_ephemeral_port, bool is_secure, bool real_socket, bool bypassSec, int8_t socket_interface_selection)
static void coap_multicast_group_join_or_leave(int8_t socket_id, uint8_t opt_name, int8_t interface_id)
{
ns_ipv6_mreq_t ns_ipv6_mreq;
int8_t ret_val;

// Join or leave COAP multicast groups
ns_ipv6_mreq.ipv6mr_interface = interface_id;

memcpy(ns_ipv6_mreq.ipv6mr_multiaddr, COAP_MULTICAST_ADDR_LINK_LOCAL, 16);
ret_val = socket_setsockopt(socket_id, SOCKET_IPPROTO_IPV6, opt_name, &ns_ipv6_mreq, sizeof(ns_ipv6_mreq));

memcpy(ns_ipv6_mreq.ipv6mr_multiaddr, COAP_MULTICAST_ADDR_ADMIN_LOCAL, 16);
ret_val |= socket_setsockopt(socket_id, SOCKET_IPPROTO_IPV6, opt_name, &ns_ipv6_mreq, sizeof(ns_ipv6_mreq));

memcpy(ns_ipv6_mreq.ipv6mr_multiaddr, COAP_MULTICAST_ADDR_SITE_LOCAL, 16);
ret_val |= socket_setsockopt(socket_id, SOCKET_IPPROTO_IPV6, opt_name, &ns_ipv6_mreq, sizeof(ns_ipv6_mreq));

if (ret_val) {
tr_error("Multicast group access failed, err=%d, name=%d", ret_val, opt_name);
}
}

static internal_socket_t *int_socket_create(uint16_t listen_port, bool use_ephemeral_port, bool is_secure, bool real_socket, bool bypassSec, int8_t socket_interface_selection, bool multicast_registration)
{
internal_socket_t *this = ns_dyn_mem_alloc(sizeof(internal_socket_t));

if (!this) {
Expand Down Expand Up @@ -276,17 +297,9 @@ static internal_socket_t *int_socket_create(uint16_t listen_port, bool use_ephem
socket_setsockopt(this->socket, SOCKET_IPPROTO_IPV6, SOCKET_INTERFACE_SELECT, &socket_interface_selection, sizeof(socket_interface_selection));
}

// Join COAP multicast group(s)
ns_ipv6_mreq.ipv6mr_interface = socket_interface_selection; // It is OK to use 0 or real interface id here

memcpy(ns_ipv6_mreq.ipv6mr_multiaddr, COAP_MULTICAST_ADDR_LINK_LOCAL, 16);
socket_setsockopt(this->socket, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_JOIN_GROUP, &ns_ipv6_mreq, sizeof(ns_ipv6_mreq));

memcpy(ns_ipv6_mreq.ipv6mr_multiaddr, COAP_MULTICAST_ADDR_ADMIN_LOCAL, 16);
socket_setsockopt(this->socket, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_JOIN_GROUP, &ns_ipv6_mreq, sizeof(ns_ipv6_mreq));

memcpy(ns_ipv6_mreq.ipv6mr_multiaddr, COAP_MULTICAST_ADDR_SITE_LOCAL, 16);
socket_setsockopt(this->socket, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_JOIN_GROUP, &ns_ipv6_mreq, sizeof(ns_ipv6_mreq));
if (multicast_registration) {
coap_multicast_group_join_or_leave(this->socket, SOCKET_IPV6_JOIN_GROUP, socket_interface_selection);
}
} else {
this->socket = virtual_socket_id_allocate();
}
Expand Down Expand Up @@ -793,9 +806,13 @@ coap_conn_handler_t *connection_handler_create(receive_from_socket_cb *recv_from

return handler;
}
void connection_handler_destroy(coap_conn_handler_t *handler)

void connection_handler_destroy(coap_conn_handler_t *handler, bool multicast_group_leave)
{
if(handler){
if (multicast_group_leave) {
coap_multicast_group_join_or_leave(handler->socket->socket, SOCKET_IPV6_LEAVE_GROUP, handler->socket_interface_selection);
}
int_socket_delete(handler->socket);
ns_dyn_mem_free(handler);
}
Expand All @@ -815,7 +832,7 @@ void connection_handler_close_secure_connection( coap_conn_handler_t *handler, u
}
}

int coap_connection_handler_open_connection(coap_conn_handler_t *handler, uint16_t listen_port, bool use_ephemeral_port, bool is_secure, bool is_real_socket, bool bypassSec, int8_t socket_interface_selection)
int coap_connection_handler_open_connection(coap_conn_handler_t *handler, uint16_t listen_port, bool use_ephemeral_port, bool is_secure, bool is_real_socket, bool bypassSec)
{
if (!handler) {
return -1;
Expand All @@ -830,7 +847,7 @@ int coap_connection_handler_open_connection(coap_conn_handler_t *handler, uint16

internal_socket_t *current = !use_ephemeral_port?int_socket_find(listen_port, is_secure, is_real_socket, bypassSec):NULL;
if (!current) {
handler->socket = int_socket_create(listen_port, use_ephemeral_port, is_secure, is_real_socket, bypassSec, socket_interface_selection);
handler->socket = int_socket_create(listen_port, use_ephemeral_port, is_secure, is_real_socket, bypassSec, handler->socket_interface_selection, handler->registered_to_multicast);
if (!handler->socket) {
return -1;
}
Expand Down
38 changes: 33 additions & 5 deletions source/coap_service_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,27 @@ static coap_service_t *service_find_by_uri(uint8_t socket_id, uint8_t *uri_ptr,
return NULL;
}

static bool coap_service_can_leave_multicast_group(coap_conn_handler_t *conn_handler)
{
int mc_count = 0;
bool current_handler_joined_to_mc_group = false;

ns_list_foreach(coap_service_t, cur_ptr, &instance_list) {
if (cur_ptr->conn_handler && cur_ptr->conn_handler->registered_to_multicast) {
if (conn_handler == cur_ptr->conn_handler) {
current_handler_joined_to_mc_group = true;
}
mc_count ++;
}
}

if (mc_count == 1 && current_handler_joined_to_mc_group) {
// current handler is the only one joined to multicast group
return true;
}

return false;
}

/**
* Coap handling functions
Expand Down Expand Up @@ -280,8 +301,8 @@ static int get_passwd_cb(int8_t socket_id, uint8_t address[static 16], uint16_t
int8_t coap_service_initialize(int8_t interface_id, uint16_t listen_port, uint8_t service_options,
coap_service_security_start_cb *start_ptr, coap_service_security_done_cb *coap_security_done_cb)
{
int8_t socket_interface_selection = 0; // zero is illegal interface ID
coap_service_t *this = ns_dyn_mem_alloc(sizeof(coap_service_t));

if (!this) {
return -1;
}
Expand Down Expand Up @@ -310,16 +331,18 @@ int8_t coap_service_initialize(int8_t interface_id, uint16_t listen_port, uint8_
return -1;
}

this->conn_handler->socket_interface_selection = 0; // zero is illegal interface ID
if (this->service_options & COAP_SERVICE_OPTIONS_SELECT_SOCKET_IF) {
socket_interface_selection = this->interface_id;
this->conn_handler->socket_interface_selection = this->interface_id;
}

this->conn_handler->registered_to_multicast = this->service_options & COAP_SERVICE_OPTIONS_MULTICAST_JOIN;

if (0 > coap_connection_handler_open_connection(this->conn_handler, listen_port,
(this->service_options & COAP_SERVICE_OPTIONS_EPHEMERAL_PORT),
(this->service_options & COAP_SERVICE_OPTIONS_SECURE),
!(this->service_options & COAP_SERVICE_OPTIONS_VIRTUAL_SOCKET),
(this->service_options & COAP_SERVICE_OPTIONS_SECURE_BYPASS),
socket_interface_selection)) {
(this->service_options & COAP_SERVICE_OPTIONS_SECURE_BYPASS))) {
ns_dyn_mem_free(this->conn_handler);
ns_dyn_mem_free(this);
return -1;
Expand All @@ -346,7 +369,12 @@ void coap_service_delete(int8_t service_id)
}

if (this->conn_handler){
connection_handler_destroy(this->conn_handler);
bool leave_multicast_group = false;
if (coap_service_can_leave_multicast_group(this->conn_handler)) {
// This is the last handler joined to multicast group
leave_multicast_group = true;
}
connection_handler_destroy(this->conn_handler, leave_multicast_group);
}

//TODO clear all transactions
Expand Down
6 changes: 4 additions & 2 deletions source/include/coap_connection_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,20 @@ typedef struct coap_conn_handler_s{
send_to_socket_cb *_send_cb;
get_pw_cb *_get_password_cb;
security_done_cb *_security_done_cb;
int8_t socket_interface_selection;
bool registered_to_multicast;
} coap_conn_handler_t;

coap_conn_handler_t *connection_handler_create(receive_from_socket_cb *recv_from_cb,
send_to_socket_cb *send_to_cb,
get_pw_cb *pw_cb,
security_done_cb *done_cb);

void connection_handler_destroy( coap_conn_handler_t *handler );
void connection_handler_destroy( coap_conn_handler_t *handler, bool multicast_group_leave);

void connection_handler_close_secure_connection( coap_conn_handler_t *handler, uint8_t destination_addr_ptr[static 16], uint16_t port );

int coap_connection_handler_open_connection(coap_conn_handler_t *handler, uint16_t listen_port, bool use_ephemeral_port, bool is_secure, bool real_socket, bool bypassSec, int8_t socket_interface_selection);
int coap_connection_handler_open_connection(coap_conn_handler_t *handler, uint16_t listen_port, bool use_ephemeral_port, bool is_secure, bool real_socket, bool bypassSec);

//If returns -2, it means security was started and data was not send
int coap_connection_handler_send_data(coap_conn_handler_t *handler, const ns_address_t *dest_addr, const uint8_t src_address[static 16], uint8_t *data_ptr, uint16_t data_len, bool bypass_link_sec);
Expand Down
Loading

0 comments on commit 76490a7

Please sign in to comment.