ON Semiconductor / mbed-os

Dependents:   mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers coap_message_handler.c Source File

coap_message_handler.c

00001 /*
00002  * Copyright (c) 2015-2016 ARM Limited. All Rights Reserved.
00003  */
00004 
00005 #include <string.h>
00006 #include "nsdynmemLIB.h"
00007 #include "coap_service_api_internal.h"
00008 #include "coap_message_handler.h"
00009 #include "sn_coap_protocol.h"
00010 #include "socket_api.h"
00011 #include "ns_types.h"
00012 #include "ns_list.h"
00013 #include "ns_trace.h"
00014 #include "randLIB.h"
00015 
00016 #define TRACE_GROUP "CoSA"
00017 
00018 static void *own_alloc(uint16_t size)
00019 {
00020     if (size) {
00021         return ns_dyn_mem_temporary_alloc(size);
00022     } else {
00023         return 0;
00024     }
00025 }
00026 
00027 static void own_free(void *ptr)
00028 {
00029     if (ptr) {
00030         ns_dyn_mem_free(ptr);
00031     }
00032 }
00033 
00034 static NS_LIST_DEFINE(request_list, coap_transaction_t, link);
00035 
00036 static coap_transaction_t *transaction_find_client_by_token(uint8_t token[4])
00037 {
00038     coap_transaction_t *this = NULL;
00039     ns_list_foreach(coap_transaction_t, cur_ptr, &request_list) {
00040         if (memcmp(cur_ptr->token,token,4) == 0 && cur_ptr->client_request) {
00041            this = cur_ptr;
00042             break;
00043         }
00044     }
00045     return this;
00046 }
00047 
00048 static coap_transaction_t *transaction_find_server(uint16_t msg_id)
00049 {
00050     coap_transaction_t *this = NULL;
00051     ns_list_foreach(coap_transaction_t, cur_ptr, &request_list) {
00052         if (cur_ptr->msg_id == msg_id && !cur_ptr->client_request) {
00053             this = cur_ptr;
00054             break;
00055         }
00056     }
00057     return this;
00058 }
00059 
00060 static coap_transaction_t *transaction_find_by_address(uint8_t *address_ptr, uint16_t port)
00061 {
00062     coap_transaction_t *this = NULL;
00063     ns_list_foreach(coap_transaction_t, cur_ptr, &request_list) {
00064         if (cur_ptr->remote_port == port && memcmp(cur_ptr->remote_address, address_ptr, 16) == 0) {
00065             this = cur_ptr;
00066             break;
00067         }
00068     }
00069     return this;
00070 }
00071 
00072 static coap_transaction_t *transaction_create(void)
00073 {
00074     coap_transaction_t *this = ns_dyn_mem_alloc(sizeof(coap_transaction_t));
00075     if (this) {
00076         memset(this, 0, sizeof(coap_transaction_t));
00077         this->client_request = true;// default to client initiated method
00078         this->create_time = coap_service_get_internal_timer_ticks();
00079         ns_list_add_to_start(&request_list, this);
00080     }
00081 
00082     return this;
00083 }
00084 
00085 static void transaction_free(coap_transaction_t *this)
00086 {
00087     if (!this) {
00088         return;
00089     }
00090 
00091     if (this->data_ptr) {
00092         ns_dyn_mem_free(this->data_ptr);
00093     }
00094     ns_dyn_mem_free(this);
00095 }
00096 
00097 void transaction_delete(coap_transaction_t *this)
00098 {
00099     if (this) {
00100         ns_list_remove(&request_list, this);
00101         transaction_free(this);
00102     }
00103 
00104     return;
00105 }
00106 
00107 void transactions_delete_all(uint8_t *address_ptr, uint16_t port)
00108 {
00109     coap_transaction_t *transaction = transaction_find_by_address(address_ptr, port);
00110 
00111     while (transaction) {
00112         ns_list_remove(&request_list, transaction);
00113         if (transaction->resp_cb) {
00114             transaction->resp_cb(transaction->service_id, address_ptr, port, NULL);
00115         }
00116         sn_coap_protocol_delete_retransmission(coap_service_handle->coap, transaction->msg_id);
00117         transaction_free(transaction);
00118         transaction = transaction_find_by_address(address_ptr, port);
00119     }
00120 }
00121 
00122 static int8_t coap_rx_function(sn_coap_hdr_s *resp_ptr, sn_nsdl_addr_s *address_ptr, void *param)
00123 {
00124     coap_transaction_t *this = NULL;
00125     (void)address_ptr;
00126     (void)param;
00127     tr_warn("transaction was not handled %d", resp_ptr->msg_id);
00128     if (!resp_ptr) {
00129         return -1;
00130     }
00131     if( resp_ptr->token_ptr ){
00132         this = transaction_find_client_by_token(resp_ptr->token_ptr);
00133     }
00134     if (!this) {
00135         return 0;
00136     }
00137 
00138     ns_list_remove(&request_list, this);
00139     if (this->resp_cb) {
00140         this->resp_cb(this->service_id, address_ptr->addr_ptr, address_ptr->port, NULL);
00141     }
00142     transaction_free(this);
00143     return 0;
00144 }
00145 
00146 coap_msg_handler_t *coap_message_handler_init(void *(*used_malloc_func_ptr)(uint16_t), void (*used_free_func_ptr)(void *),
00147                                   uint8_t (*used_tx_callback_ptr)(uint8_t *, uint16_t, sn_nsdl_addr_s *, void *)){
00148 
00149     if ((used_malloc_func_ptr == NULL) || (used_free_func_ptr == NULL) || (used_tx_callback_ptr == NULL)) {
00150         return NULL;
00151     }
00152 
00153     coap_msg_handler_t *handle;
00154     handle = used_malloc_func_ptr(sizeof(coap_msg_handler_t));
00155     if (handle == NULL) {
00156         return NULL;
00157     }
00158 
00159     memset(handle, 0, sizeof(coap_msg_handler_t));
00160 
00161     handle->sn_coap_tx_callback = used_tx_callback_ptr;
00162 
00163     handle->sn_coap_service_free = used_free_func_ptr;
00164     handle->sn_coap_service_malloc = used_malloc_func_ptr;
00165 
00166     handle->coap = sn_coap_protocol_init(used_malloc_func_ptr, used_free_func_ptr, used_tx_callback_ptr, &coap_rx_function);
00167     if( !handle->coap ){
00168         used_free_func_ptr(handle);
00169         return NULL;
00170     }
00171     return handle;
00172 }
00173 
00174 int8_t coap_message_handler_destroy(coap_msg_handler_t *handle){
00175     if( !handle ){
00176         return -1;
00177     }
00178 
00179     if( handle->coap ){
00180         sn_coap_protocol_destroy(handle->coap);
00181     }
00182 
00183     //Destroy transactions
00184     ns_list_foreach_safe(coap_transaction_t, cur_ptr, &request_list) {
00185         ns_list_remove(&request_list, cur_ptr);
00186         ns_dyn_mem_free(cur_ptr);
00187         cur_ptr = NULL;
00188     }
00189 
00190     handle->sn_coap_service_free(handle);
00191     return 0;
00192 }
00193 
00194 coap_transaction_t *coap_message_handler_transaction_valid(coap_transaction_t *tr_ptr)
00195 {
00196     ns_list_foreach(coap_transaction_t, cur_ptr, &request_list) {
00197         if (cur_ptr == tr_ptr) {
00198             return tr_ptr;
00199         }
00200     }
00201     return NULL;
00202 }
00203 
00204 coap_transaction_t *coap_message_handler_find_transaction(uint8_t *address_ptr, uint16_t port)
00205 {
00206     if( !address_ptr )
00207         return NULL;
00208     return transaction_find_by_address( address_ptr, port );
00209 }
00210 
00211 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],
00212                                       uint8_t *data_ptr, uint16_t data_len, int16_t (cb)(int8_t, sn_coap_hdr_s *, coap_transaction_t *))
00213 {
00214     if (!cb || !handle) {
00215         return -1;
00216     }
00217     sn_nsdl_addr_s src_addr;
00218     sn_coap_hdr_s *coap_message;
00219     src_addr.addr_ptr = (uint8_t *)source_addr_ptr;
00220     src_addr.addr_len  =  16;
00221     src_addr.type  =  SN_NSDL_ADDRESS_TYPE_IPV6;
00222     src_addr.port  =  port;
00223 
00224     coap_message = sn_coap_protocol_parse(handle->coap, &src_addr, data_len, data_ptr, NULL);
00225     if (coap_message == NULL) {
00226         tr_err("CoAP Parsing failed");
00227         return -1;
00228     }
00229     tr_debug("CoAP status:%d, type:%d, code:%d, id:%d", coap_message->coap_status, coap_message->msg_type, coap_message->msg_code, coap_message->msg_id);
00230     /* Check, if coap itself sends response, or block receiving is ongoing... */
00231     if (coap_message->coap_status != COAP_STATUS_OK && coap_message->coap_status != COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED) {
00232         tr_debug("CoAP library responds");
00233         sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_message);
00234         return -1;
00235     }
00236     /* Request received */
00237     if (coap_message->msg_code > 0 && coap_message->msg_code < 32) {
00238         coap_transaction_t *transaction_ptr = transaction_create();
00239         if (transaction_ptr) {
00240             transaction_ptr->service_id = coap_service_id_find_by_socket(socket_id);
00241             transaction_ptr->msg_id = coap_message->msg_id;
00242             transaction_ptr->client_request = false;// this is server transaction
00243             memcpy(transaction_ptr->local_address, *(dst_addr_ptr) == 0xFF ? ns_in6addr_any : dst_addr_ptr, 16);
00244             memcpy(transaction_ptr->remote_address, source_addr_ptr, 16);
00245             transaction_ptr->remote_port = port;
00246 
00247             int ret = cb(socket_id, coap_message, transaction_ptr);
00248             if (ret != 0) {
00249                 tr_debug("Service %d, no response expected", transaction_ptr->service_id);
00250                 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_message);
00251                 transaction_delete(transaction_ptr);
00252                 return -1;
00253             }
00254         } else {
00255             //TODO: handle error case
00256         }
00257     /* Response received */
00258     } else {
00259         coap_transaction_t *this = NULL;
00260         if (coap_message->token_ptr) {
00261             this = transaction_find_client_by_token(coap_message->token_ptr);
00262         }
00263         if (!this) {
00264             tr_error("client transaction not found");
00265             sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_message);
00266             return -1;
00267         }
00268         tr_debug("Service %d, response received", this->service_id);
00269         ns_list_remove(&request_list, this);
00270         if (this->resp_cb) {
00271             this->resp_cb(this->service_id, (uint8_t *)source_addr_ptr, port, coap_message);
00272         }
00273         sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_message);
00274         transaction_free(this);
00275     }
00276 
00277     return 0;
00278 
00279 }
00280 
00281 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],
00282                                    uint16_t destination_port, sn_coap_msg_type_e msg_type, sn_coap_msg_code_e msg_code, const char *uri,
00283                                    sn_coap_content_format_e cont_type, const uint8_t *payload_ptr, uint16_t payload_len, coap_message_handler_response_recv *request_response_cb)
00284 {
00285     coap_transaction_t *transaction_ptr;
00286     sn_coap_hdr_s request;
00287     sn_nsdl_addr_s dst_addr;
00288     uint8_t token[4];
00289     uint16_t data_len;
00290     uint8_t *data_ptr;
00291 
00292     tr_debug("Service %d, send CoAP request payload_len %d", service_id, payload_len);
00293     transaction_ptr = transaction_create();
00294 
00295     if (!uri || !transaction_ptr) {
00296         return 0;
00297     }
00298 
00299     transaction_ptr->service_id = service_id;
00300     transaction_ptr->client_request = true;
00301     transaction_ptr->resp_cb = request_response_cb;
00302     transaction_ptr->options = options;
00303     memcpy(transaction_ptr->remote_address, destination_addr, 16);
00304     transaction_ptr->remote_port = destination_port;
00305     memset(&request, 0, sizeof(request));
00306     dst_addr.addr_ptr = (uint8_t *) destination_addr; // Cast away const and trust that nsdl doesn't modify...
00307     dst_addr.addr_len  =  16;
00308     dst_addr.type  =  SN_NSDL_ADDRESS_TYPE_IPV6;
00309     dst_addr.port  =  destination_port;
00310 
00311     request.msg_type = msg_type;
00312     request.msg_code = msg_code;
00313     request.uri_path_ptr = (uint8_t *)uri;
00314     request.uri_path_len = strlen(uri);
00315     request.content_format = cont_type;
00316 
00317     do{
00318         randLIB_get_n_bytes_random(token,4);
00319     }while(transaction_find_client_by_token(token));
00320     memcpy(transaction_ptr->token,token,4);
00321     request.token_ptr = transaction_ptr->token;
00322     request.token_len = 4;
00323 
00324     request.payload_len = payload_len;
00325     request.payload_ptr = (uint8_t *) payload_ptr;  // Cast away const and trust that nsdl doesn't modify...
00326     data_len = sn_coap_builder_calc_needed_packet_data_size(&request);
00327     data_ptr = own_alloc(data_len);
00328     if(data_len > 0 && !data_ptr){
00329         transaction_delete(transaction_ptr);
00330         return 0;
00331     }
00332     sn_coap_protocol_build(handle->coap, &dst_addr, data_ptr, &request, transaction_ptr);
00333     transaction_ptr->msg_id = request.msg_id;
00334     handle->sn_coap_tx_callback(data_ptr, data_len, &dst_addr, transaction_ptr);
00335 
00336     // Free allocated data
00337     own_free(data_ptr);
00338     if(request_response_cb == NULL){
00339         //No response expected
00340         return 0;
00341     }
00342     return transaction_ptr->msg_id;
00343 }
00344 
00345 int8_t coap_message_handler_response_send(coap_msg_handler_t *handle, int8_t service_id, uint8_t options, sn_coap_hdr_s *request_ptr, sn_coap_msg_code_e message_code, sn_coap_content_format_e content_type, const uint8_t *payload_ptr, uint16_t payload_len)
00346 {
00347     coap_transaction_t *transaction_ptr;
00348     sn_coap_hdr_s *response;
00349     sn_nsdl_addr_s dst_addr;
00350     uint16_t data_len;
00351     uint8_t *data_ptr;
00352     (void) options;
00353     (void)service_id;
00354 
00355     tr_debug("Service %d, send CoAP response", service_id);
00356     if (!request_ptr || !handle) {
00357         tr_error("invalid params");
00358         return -1;
00359     }
00360 
00361     transaction_ptr = transaction_find_server(request_ptr->msg_id);
00362 
00363     if (!transaction_ptr) {
00364         tr_error("response transaction not found");
00365         return -2;
00366     }
00367     dst_addr.addr_ptr  =  transaction_ptr->remote_address;
00368     dst_addr.addr_len  =  16;
00369     dst_addr.type  =  SN_NSDL_ADDRESS_TYPE_IPV6;
00370     dst_addr.port  =  transaction_ptr->remote_port;
00371 
00372     response = sn_coap_build_response(handle->coap, request_ptr, message_code);
00373     if( !response ){
00374         return -1;
00375     }
00376     response->payload_len = payload_len;
00377     response->payload_ptr = (uint8_t *) payload_ptr;  // Cast away const and trust that nsdl doesn't modify...
00378     response->content_format = content_type;
00379 
00380     data_len = sn_coap_builder_calc_needed_packet_data_size(response);
00381     data_ptr = own_alloc(data_len);
00382     if (data_len > 0 && !data_ptr) {
00383         sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, response);
00384         return -1;
00385     }
00386     sn_coap_protocol_build(handle->coap, &dst_addr, data_ptr, response, transaction_ptr);
00387     sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, response);
00388     handle->sn_coap_tx_callback(data_ptr, data_len, &dst_addr, transaction_ptr);
00389     sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, request_ptr);
00390     own_free(data_ptr);
00391     return 0;
00392 }
00393 
00394 int8_t coap_message_handler_exec(coap_msg_handler_t *handle, uint32_t current_time){
00395 
00396     if( !handle ){
00397         return -1;
00398     }
00399 
00400     // Remove outdated transactions from queue
00401     ns_list_foreach_safe(coap_transaction_t, transaction, &request_list) {
00402         if ((transaction->create_time + TRANSACTION_LIFETIME) < current_time) {
00403             transaction_delete(transaction);
00404         }
00405     }
00406 
00407     return sn_coap_protocol_exec(handle->coap, current_time);
00408 }