Skip to content

Commit

Permalink
Add API to set callback for CoAP msg prevalidation (ARMmbed#115)
Browse files Browse the repository at this point in the history
Application can set callback method that is used to validate 
message before passing it further. CoAP service will reject 
requests if prevalidation fails.
  • Loading branch information
Arto Kinnunen committed Dec 18, 2018
1 parent 0eb6630 commit 46f86d4
Show file tree
Hide file tree
Showing 16 changed files with 218 additions and 12 deletions.
37 changes: 36 additions & 1 deletion coap-service/coap_service_api.h
Expand Up @@ -120,6 +120,25 @@ typedef int coap_service_security_start_cb(int8_t service_id, uint8_t address[st
*/
typedef int coap_service_security_done_cb(int8_t service_id, uint8_t address[static 16], uint8_t keyblock[static 40]);

/**
* \brief Message prevalidation callback
*
* Message prevalidation callback function type used in method coap_service_msg_prevalidate_callback_set.
*
* \param interface_id Application interface ID.
* \param source_address Sender address.
* \param source_port Sender port.
* \param local_address Local address.
* \param local_port Local port.
* \param request_uri CoAP URI, NUL terminated.
*
* \return <0 in case of errors,
* 0 if message is valid to process further,
* >0 if message should be dropped.
*/

typedef int coap_service_msg_prevalidate_cb(int8_t interface_id, uint8_t source_address[static 16], uint16_t source_port, uint8_t local_address[static 16], uint16_t local_port, char *request_uri);

/**
* \brief Initialise server instance.
*
Expand All @@ -131,7 +150,7 @@ typedef int coap_service_security_done_cb(int8_t service_id, uint8_t address[sta
* \param *start_ptr Callback to inform security handling is started and to fetch device password.
* \param *coap_security_done_cb Callback to inform security handling is done.
*
* \return service_id / -1 for failure
* \return service_id / -1 for failure
*/
extern 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);

Expand Down Expand Up @@ -373,6 +392,22 @@ extern int8_t coap_service_certificate_set(int8_t service_id, const unsigned cha
*- 0 For success
*/
extern int8_t coap_service_blockwise_size_set(int8_t service_id, uint16_t size);

/**
* \brief Set message prevalidation callback function.
*
* Set message prevalidation callback function for the service. Callback will be called for all services using the same listen port.
*
* CoAP service will call this function to allow application prevalidate incoming CoAP message before passing it to application.
*
* \param service_id Id number of the current service.
* \param msg_prevalidate_cb Callback to be called to validate incoming message before pprocessing it.
*
* \return -1 For failure
* 0 For success
*/
extern int8_t coap_service_msg_prevalidate_callback_set(int8_t service_id, coap_service_msg_prevalidate_cb *msg_prevalidate_cb);

#ifdef __cplusplus
}
#endif
Expand Down
20 changes: 20 additions & 0 deletions source/coap_connection_handler.c
Expand Up @@ -36,6 +36,7 @@ typedef enum session_state_e {

typedef struct internal_socket_s {
coap_conn_handler_t *parent;
cch_func_cb *cch_function_callback; // callback function

uint32_t timeout_min;
uint32_t timeout_max;
Expand Down Expand Up @@ -1023,3 +1024,22 @@ void coap_connection_handler_exec(uint32_t time)
}
}
}

int coap_connection_handler_msg_prevalidate_callback_set(coap_conn_handler_t *handler, cch_func_cb *function_callback)
{
if (!handler) {
return -1;
}
handler->socket->cch_function_callback = function_callback;
return 0;
}

cch_func_cb *coap_connection_handler_msg_prevalidate_callback_get(coap_conn_handler_t *handler, uint16_t *listen_socket_port)
{
if (!handler || !listen_socket_port) {
return NULL;
}

*listen_socket_port = handler->socket->listen_port;
return handler->socket->cch_function_callback;
}
10 changes: 5 additions & 5 deletions source/coap_message_handler.c
Expand Up @@ -294,14 +294,14 @@ coap_transaction_t *coap_message_handler_find_transaction(uint8_t *address_ptr,
}

int16_t coap_message_handler_coap_msg_process(coap_msg_handler_t *handle, int8_t socket_id, const uint8_t source_addr_ptr[static 16], uint16_t port, const uint8_t dst_addr_ptr[static 16],
uint8_t *data_ptr, uint16_t data_len, int16_t (cb)(int8_t, sn_coap_hdr_s *, coap_transaction_t *))
uint8_t *data_ptr, uint16_t data_len, int16_t (msg_process_callback)(int8_t, sn_coap_hdr_s *, coap_transaction_t *, const uint8_t *))
{
sn_nsdl_addr_s src_addr;
sn_coap_hdr_s *coap_message;
int16_t ret_val = 0;
coap_transaction_t *this = NULL;

if (!cb || !handle) {
if (!msg_process_callback || !handle) {
return -1;
}

Expand Down Expand Up @@ -337,21 +337,21 @@ int16_t coap_message_handler_coap_msg_process(coap_msg_handler_t *handle, int8_t
goto exit;
}

/* Request received */
if (coap_message->msg_code > 0 && coap_message->msg_code < 32) {
/* Request received */
transaction_ptr->msg_id = coap_message->msg_id;
transaction_ptr->req_msg_type = coap_message->msg_type;
if (coap_message->token_len) {
memcpy(transaction_ptr->token, coap_message->token_ptr, coap_message->token_len);
transaction_ptr->token_len = coap_message->token_len;
}
if (cb(socket_id, coap_message, transaction_ptr) < 0) {
if (msg_process_callback(socket_id, coap_message, transaction_ptr, dst_addr_ptr) < 0) {
// negative return value = message ignored -> delete transaction
transaction_delete(transaction_ptr);
}
goto exit;
/* Response received */
} else {
/* Response received */
transaction_delete(transaction_ptr); // transaction_ptr not needed in response
if (coap_message->token_ptr) {
this = transaction_find_client_by_token(coap_message->token_ptr, coap_message->token_len, source_addr_ptr, port);
Expand Down
33 changes: 30 additions & 3 deletions source/coap_service_api.c
Expand Up @@ -36,7 +36,7 @@
#include "coap_message_handler.h"
#include "mbed-coap/sn_coap_protocol.h"

static int16_t coap_msg_process_callback(int8_t socket_id, sn_coap_hdr_s *coap_message, coap_transaction_t *transaction_ptr);
static int16_t coap_msg_process_callback(int8_t socket_id, sn_coap_hdr_s *coap_message, coap_transaction_t *transaction_ptr, const uint8_t * local_addr);

typedef struct uri_registration {
char *uri_ptr;
Expand Down Expand Up @@ -211,7 +211,7 @@ static void service_event_handler(arm_event_s *event)
eventOS_event_timer_request((uint8_t)COAP_TICK_TIMER, ARM_LIB_SYSTEM_TIMER_EVENT, tasklet_id, 1000);
}

static int16_t coap_msg_process_callback(int8_t socket_id, sn_coap_hdr_s *coap_message, coap_transaction_t *transaction_ptr)
static int16_t coap_msg_process_callback(int8_t socket_id, sn_coap_hdr_s *coap_message, coap_transaction_t *transaction_ptr, const uint8_t * local_addr)
{
coap_service_t *this;
if (!coap_message || !transaction_ptr) {
Expand Down Expand Up @@ -239,7 +239,25 @@ static int16_t coap_msg_process_callback(int8_t socket_id, sn_coap_hdr_s *coap_m
// this check can be removed I think
transaction_ptr->options = COAP_REQUEST_OPTIONS_SECURE_BYPASS;
}
coap_service_msg_prevalidate_cb *msg_prevalidate_callback;
uint16_t listen_socket_port;

transaction_ptr->service_id = this->service_id;

msg_prevalidate_callback = (coap_service_msg_prevalidate_cb*)coap_connection_handler_msg_prevalidate_callback_get(this->conn_handler, &listen_socket_port);
if (msg_prevalidate_callback) {
// message prevalidation activated for the port
char request_uri[coap_message->uri_path_len + 1];
memcpy(request_uri, coap_message->uri_path_ptr, coap_message->uri_path_len);
request_uri[coap_message->uri_path_len] = 0;

int msg_prevalidate_status = msg_prevalidate_callback(this->interface_id, transaction_ptr->remote_address, transaction_ptr->remote_port, (uint8_t*)local_addr, listen_socket_port, request_uri);
if (msg_prevalidate_status == 1) {
tr_warn("Drop msg %s", request_uri);
return -1;
}
}

return uri_reg_ptr->request_recv_cb(this->service_id, transaction_ptr->remote_address, transaction_ptr->remote_port, coap_message);
}
return -1;
Expand All @@ -261,7 +279,7 @@ static int recv_cb(int8_t socket_id, uint8_t src_address[static 16], uint16_t po
}
memcpy(data_ptr, data, len);
data_len = len;
tr_debug("service recv socket data len %d ", data_len);
tr_debug("Service recv %d bytes", data_len);

//parse coap message what CoAP to use
int ret = coap_message_handler_coap_msg_process(coap_service_handle, socket_id, src_address, port, dst_address, data_ptr, data_len, &coap_msg_process_callback);
Expand Down Expand Up @@ -626,3 +644,12 @@ int8_t coap_service_blockwise_size_set(int8_t service_id, uint16_t size)

return sn_coap_protocol_set_block_size(coap_service_handle->coap, size);
}

int8_t coap_service_msg_prevalidate_callback_set(int8_t service_id, coap_service_msg_prevalidate_cb *msg_prevalidate_cb)
{
coap_service_t *this = service_find(service_id);
if (this) {
return (int8_t)coap_connection_handler_msg_prevalidate_callback_set(this->conn_handler, (cch_func_cb*)msg_prevalidate_cb);
}
return -1;
}
5 changes: 5 additions & 0 deletions source/include/coap_connection_handler.h
Expand Up @@ -38,6 +38,7 @@ typedef int send_to_socket_cb(int8_t socket_id, const uint8_t address[static 16]
typedef int receive_from_socket_cb(int8_t socket_id, uint8_t src_address[static 16], uint16_t port, const uint8_t dst_address[static 16], unsigned char *, int);
typedef int get_pw_cb(int8_t socket_id, uint8_t address[static 16], uint16_t port, coap_security_keys_t *security_ptr);
typedef void security_done_cb(int8_t socket_id, uint8_t address[static 16], uint16_t port, uint8_t keyblock[static 40]);
typedef void cch_func_cb(void);

typedef struct coap_conn_handler_s {
struct internal_socket_s *socket;
Expand Down Expand Up @@ -81,4 +82,8 @@ int8_t coap_connection_handler_handshake_limits_set(uint8_t handshakes_limit, ui

void coap_connection_handler_exec(uint32_t time);

int coap_connection_handler_msg_prevalidate_callback_set(coap_conn_handler_t *handler, cch_func_cb *function_callback);

cch_func_cb *coap_connection_handler_msg_prevalidate_callback_get(coap_conn_handler_t *handler, uint16_t *listen_socket_port);

#endif
2 changes: 1 addition & 1 deletion source/include/coap_message_handler.h
Expand Up @@ -85,7 +85,7 @@ extern coap_transaction_t *coap_message_handler_transaction_valid(coap_transacti
extern coap_transaction_t *coap_message_handler_find_transaction(uint8_t *address_ptr, uint16_t port);

extern int16_t coap_message_handler_coap_msg_process(coap_msg_handler_t *handle, int8_t socket_id, const uint8_t source_addr_ptr[static 16], uint16_t port, const uint8_t dst_addr_ptr[static 16],
uint8_t *data_ptr, uint16_t data_len, int16_t (cb)(int8_t, sn_coap_hdr_s *, coap_transaction_t *));
uint8_t *data_ptr, uint16_t data_len, int16_t (msg_process_callback)(int8_t, sn_coap_hdr_s *, coap_transaction_t *, const uint8_t *));

extern uint16_t coap_message_handler_request_send(coap_msg_handler_t *handle, int8_t service_id, uint8_t options, const uint8_t destination_addr[static 16],
uint16_t destination_port, sn_coap_msg_type_e msg_type, sn_coap_msg_code_e msg_code, const char *uri, sn_coap_content_format_e cont_type,
Expand Down
Expand Up @@ -71,3 +71,8 @@ TEST(coap_connection_handler, test_security_callbacks)
CHECK(test_security_callbacks());
}

TEST(coap_connection_handler, test_coap_connection_handler_msg_prevalidate_cb_read_and_set)
{
CHECK(test_coap_connection_handler_msg_prevalidate_cb_read_and_set());
}

Expand Up @@ -511,3 +511,41 @@ bool test_security_callbacks()
sckt_data = NULL;
return true;
}

bool test_coap_connection_handler_msg_prevalidate_cb_read_and_set()
{
coap_security_handler_stub.counter = -1;

coap_security_handler_stub.sec_obj = coap_security_handler_stub_alloc();

nsdynmemlib_stub.returnCounter = 1;
coap_conn_handler_t *handler = connection_handler_create(&receive_from_sock_cb, &send_to_sock_cb, NULL, NULL);
nsdynmemlib_stub.returnCounter = 2;
if (0 != coap_connection_handler_open_connection(handler, 22, false, true, true, false)) {
return false;
}

if (-1 != coap_connection_handler_msg_prevalidate_callback_set(NULL, 1000)) {
return false;
}

if (0 != coap_connection_handler_msg_prevalidate_callback_set(handler, 1000)) {
return false;
}

uint16_t listen_socket_port;
if (NULL != coap_connection_handler_msg_prevalidate_callback_get(NULL, &listen_socket_port)) {
return false;
}

if (1000 != coap_connection_handler_msg_prevalidate_callback_get(handler, &listen_socket_port)) {
return false;
}

connection_handler_destroy(handler, false);

free(coap_security_handler_stub.sec_obj);
coap_security_handler_stub.sec_obj = NULL;

return true;
}
Expand Up @@ -41,6 +41,8 @@ bool test_socket_api_callbacks();

bool test_security_callbacks();

bool test_coap_connection_handler_msg_prevalidate_cb_read_and_set();

#ifdef __cplusplus
}
#endif
Expand Down
3 changes: 2 additions & 1 deletion test/coap-service/unittest/coap_service_api/Makefile
Expand Up @@ -33,7 +33,8 @@ TEST_SRC_FILES = \
../stub/coap_connection_handler_stub.c \
../stub/coap_message_handler_stub.c \
../stub/common_functions_stub.c \
../stub/sn_coap_protocol_stub.c
../stub/sn_coap_protocol_stub.c \
../stub/socket_api_stub.c

include ../MakefileWorker.mk

Expand Down
Expand Up @@ -120,3 +120,9 @@ TEST(coap_service_api, test_coap_service_handshake_limit_set)
{
CHECK(test_coap_service_handshake_limit_set())
}

TEST(coap_service_api, test_coap_service_msg_prevalidate_cb_read_and_set)
{
CHECK(test_coap_service_msg_prevalidate_cb_read_and_set())
}

Expand Up @@ -45,6 +45,11 @@ int virtual_sock_send_cb(int8_t service_id, uint8_t destination_addr_ptr[static
return 2;
}

int msg_prevalidate_cb(int8_t interface_id, uint8_t address[static 16])
{
return 1;
}

bool test_coap_service_initialize()
{
if (-1 != coap_service_initialize(1, 2, 0, NULL, NULL)) {
Expand Down Expand Up @@ -439,6 +444,19 @@ bool test_conn_handler_callbacks()

coap_transaction_t *tr = (coap_transaction_t *)malloc(sizeof(coap_transaction_t));
memset(tr, 0, sizeof(coap_transaction_t));
tr->local_address[0] = 2;

if (0 != coap_service_msg_prevalidate_callback_set(1, msg_prevalidate_cb)) {
return false;
}

if (-1 != coap_message_handler_stub.cb(1, coap, tr)) {
return false;
}

if (0 != coap_service_msg_prevalidate_callback_set(1, NULL)) {
return false;
}

if (2 != coap_message_handler_stub.cb(1, coap, tr)) {
return false;
Expand Down Expand Up @@ -645,3 +663,36 @@ bool test_coap_service_handshake_limit_set()

return true;
}

bool test_coap_service_msg_prevalidate_cb_read_and_set()
{
/* No valid service ID - return failure */
if (0 == coap_service_msg_prevalidate_callback_set(0, msg_prevalidate_cb)) {
return false;
}

/* Init service */
thread_conn_handler_stub.handler_obj = (coap_conn_handler_t *)malloc(sizeof(coap_conn_handler_t));
memset(thread_conn_handler_stub.handler_obj, 0, sizeof(coap_conn_handler_t));

nsdynmemlib_stub.returnCounter = 1;
thread_conn_handler_stub.bool_value = 0;
if (1 != coap_service_initialize(1, 2, 0, NULL, NULL)) {
return false;
}

if (0 != coap_service_msg_prevalidate_callback_set(1, msg_prevalidate_cb)) {
return false;
}

if (0 != coap_service_msg_prevalidate_callback_set(1, NULL)) {
return false;
}

/* Teardown */
coap_service_delete(1);
free(thread_conn_handler_stub.handler_obj);
thread_conn_handler_stub.handler_obj = NULL;

return true;
}
Expand Up @@ -61,6 +61,8 @@ bool test_coap_service_if_find_by_socket();

bool test_coap_service_handshake_limit_set();

bool test_coap_service_msg_prevalidate_cb_read_and_set();


#ifdef __cplusplus
}
Expand Down

0 comments on commit 46f86d4

Please sign in to comment.