joey shelton / LED_Demo

Dependencies:   MAX44000 PWM_Tone_Library nexpaq_mdk

Fork of LED_Demo by Maxim nexpaq

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