Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers coap_service_api.c Source File

coap_service_api.c

00001 /*
00002  * Copyright (c) 2015-2017, Arm Limited and affiliates.
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 
00019 
00020 #include <string.h>
00021 
00022 #include "ns_types.h"
00023 #include "ns_list.h"
00024 #include "ns_trace.h"
00025 #include "nsdynmemLIB.h"
00026 #include "mbed-coap/sn_coap_header.h"
00027 #include "coap_service_api.h"
00028 #include "coap_message_handler.h"
00029 #include "eventOS_event.h"
00030 #include "eventOS_scheduler.h"
00031 #include "eventOS_event_timer.h"
00032 #include "common_functions.h"
00033 #include "coap_connection_handler.h"
00034 #include "net_interface.h"
00035 #include "coap_service_api_internal.h"
00036 #include "coap_message_handler.h"
00037 #include "mbed-coap/sn_coap_protocol.h"
00038 
00039 static int16_t coap_msg_process_callback(int8_t socket_id, int8_t recv_if_id, sn_coap_hdr_s *coap_message, coap_transaction_t *transaction_ptr, const uint8_t *local_addr);
00040 
00041 typedef struct uri_registration {
00042     char *uri_ptr;
00043     uint16_t uri_len;
00044     uint8_t allowed_method;
00045     coap_service_request_recv_cb *request_recv_cb;
00046     ns_list_link_t link;
00047 } uri_registration_t;
00048 
00049 typedef NS_LIST_HEAD (uri_registration_t, link) uri_registration_list_t;
00050 
00051 typedef struct coap_service {
00052     coap_service_security_done_cb *coap_security_done_cb;
00053     coap_service_security_start_cb *security_start_cb;
00054     coap_service_virtual_socket_send_cb *virtual_socket_send_cb;
00055     uri_registration_list_t uri_list;
00056     coap_conn_handler_t *conn_handler;
00057     int8_t interface_id;
00058     int8_t service_id;
00059     int8_t listen_socket;
00060     uint8_t service_options;
00061     ns_list_link_t link;
00062 } coap_service_t;
00063 
00064 #define TRACE_GROUP "ThSA"
00065 
00066 static NS_LIST_DEFINE(instance_list, coap_service_t, link);
00067 static int8_t tasklet_id = -1;
00068 coap_msg_handler_t *coap_service_handle = NULL;
00069 static uint32_t coap_ticks = 1;
00070 
00071 #define COAP_TICK_TIMER 0xf1
00072 
00073 //#define TRACE_DEEP
00074 #ifdef TRACE_DEEP
00075 #define tr_deep   tr_debug
00076 #else
00077 #define tr_deep(...)
00078 #endif
00079 
00080 static uri_registration_t *uri_registration_find(coap_service_t *this, const void *uri_ptr, uint16_t uri_len)
00081 {
00082     ns_list_foreach(uri_registration_t, cur_ptr, &this->uri_list) {
00083         if (cur_ptr->uri_len == uri_len && memcmp(cur_ptr->uri_ptr, uri_ptr, uri_len) == 0) {
00084             return cur_ptr;
00085         }
00086     }
00087     return NULL;
00088 }
00089 static coap_service_t *service_find(int8_t service_id)
00090 {
00091     coap_service_t *this = NULL;
00092     ns_list_foreach(coap_service_t, cur_ptr, &instance_list) {
00093         if (cur_ptr->service_id == service_id) {
00094             this = cur_ptr;
00095             break;
00096         }
00097     }
00098     return this;
00099 }
00100 
00101 static coap_service_t *service_find_by_socket(int8_t socket_id)
00102 {
00103     coap_service_t *this = NULL;
00104     ns_list_foreach(coap_service_t, cur_ptr, &instance_list) {
00105         if (coap_connection_handler_socket_belongs_to(cur_ptr->conn_handler, socket_id)) {
00106             this = cur_ptr;
00107             break;
00108         }
00109     }
00110     return this;
00111 }
00112 
00113 static coap_service_t *service_find_by_uri(uint8_t socket_id, uint8_t *uri_ptr, uint16_t uri_len)
00114 {
00115     ns_list_foreach(coap_service_t, cur_ptr, &instance_list) {
00116         if (coap_connection_handler_socket_belongs_to(cur_ptr->conn_handler, socket_id) && uri_registration_find(cur_ptr, uri_ptr, uri_len)) {
00117             return cur_ptr;
00118         }
00119     }
00120     return NULL;
00121 }
00122 
00123 static bool coap_service_can_leave_multicast_group(coap_conn_handler_t *conn_handler)
00124 {
00125     int mc_count = 0;
00126     bool current_handler_joined_to_mc_group = false;
00127 
00128     ns_list_foreach(coap_service_t, cur_ptr, &instance_list) {
00129         if (cur_ptr->conn_handler && cur_ptr->conn_handler->registered_to_multicast) {
00130             if (conn_handler == cur_ptr->conn_handler) {
00131                 current_handler_joined_to_mc_group = true;
00132             }
00133             mc_count ++;
00134         }
00135     }
00136 
00137     if (mc_count == 1 && current_handler_joined_to_mc_group) {
00138         // current handler is the only one joined to multicast group
00139         return true;
00140     }
00141 
00142     return false;
00143 }
00144 
00145 /**
00146  *  Coap handling functions
00147  */
00148 static void *own_alloc(uint16_t size)
00149 {
00150     if (size) {
00151         return ns_dyn_mem_temporary_alloc(size);
00152     } else {
00153         return 0;
00154     }
00155 }
00156 
00157 static void own_free(void *ptr)
00158 {
00159     if (ptr) {
00160         ns_dyn_mem_free(ptr);
00161     }
00162 }
00163 
00164 static uint8_t coap_tx_function(uint8_t *data_ptr, uint16_t data_len, sn_nsdl_addr_s *address_ptr, void *param)
00165 {
00166     coap_service_t *this;
00167     coap_transaction_t *transaction_ptr = coap_message_handler_transaction_valid(param);
00168     ns_address_t dest_addr;
00169     int ret_val;
00170 
00171     if (!transaction_ptr || !data_ptr) {
00172         return 0;
00173     }
00174 
00175     tr_debug("Service %d, CoAP TX - mid: %d", transaction_ptr->service_id, common_read_16_bit(data_ptr + 2));
00176 
00177     this = service_find(transaction_ptr->service_id);
00178     if (!this) {
00179         return 0;
00180     }
00181 
00182     memcpy(&(dest_addr.address), address_ptr->addr_ptr, 16);
00183     dest_addr.identifier = address_ptr->port;
00184     dest_addr.type = ADDRESS_IPV6;
00185 
00186     ret_val = coap_connection_handler_send_data(this->conn_handler, &dest_addr, transaction_ptr->local_address,
00187                                                 data_ptr, data_len, (this->service_options & COAP_SERVICE_OPTIONS_SECURE_BYPASS) == COAP_SERVICE_OPTIONS_SECURE_BYPASS);
00188     if (ret_val == 0) {
00189         if (!transaction_ptr->data_ptr) {
00190             transaction_ptr->data_ptr = ns_dyn_mem_alloc(data_len);
00191             if (!transaction_ptr->data_ptr) {
00192                 tr_debug("coap tx out of memory");
00193                 return 0;
00194             }
00195             memcpy(transaction_ptr->data_ptr, data_ptr, data_len);
00196             transaction_ptr->data_len = data_len;
00197         }
00198     } else if ((ret_val == -1) || (!transaction_ptr->resp_cb && transaction_ptr->req_msg_type == COAP_MSG_TYPE_NON_CONFIRMABLE)) {
00199         transaction_delete(transaction_ptr);
00200     }
00201 
00202     return 0;
00203 }
00204 
00205 static void service_event_handler(arm_event_s *event)
00206 {
00207     if (event->event_type == ARM_LIB_TASKLET_INIT_EVENT) {
00208         tr_debug("service tasklet initialised");
00209         /*initialize coap service and listen socket*/
00210     }
00211 
00212     if (event->event_type == ARM_LIB_SYSTEM_TIMER_EVENT && event->event_id == COAP_TICK_TIMER) {
00213         coap_message_handler_exec(coap_service_handle, coap_ticks++);
00214         if (coap_ticks && !(coap_ticks % SECURE_SESSION_CLEAN_INTERVAL)) {
00215             coap_connection_handler_exec(coap_ticks);
00216         }
00217     }
00218     eventOS_event_timer_request((uint8_t)COAP_TICK_TIMER, ARM_LIB_SYSTEM_TIMER_EVENT, tasklet_id, 1000);
00219 }
00220 
00221 static int16_t coap_msg_process_callback(int8_t socket_id, int8_t recv_if_id, sn_coap_hdr_s *coap_message, coap_transaction_t *transaction_ptr, const uint8_t *local_addr)
00222 {
00223     coap_service_t *this;
00224     coap_service_msg_prevalidate_cb *msg_prevalidate_callback;
00225     uint16_t listen_socket_port;
00226 
00227     if (!coap_message || !transaction_ptr) {
00228         return -1;
00229     }
00230 
00231     // Message is request, find correct handle based on URI
00232     this = service_find_by_uri(socket_id, coap_message->uri_path_ptr, coap_message->uri_path_len);
00233     if (!this) {
00234         tr_deep("URI %.*s not registered", coap_message->uri_path_len, coap_message->uri_path_ptr);
00235         // URI is not available, find any service that holds the same shared socket so that we can get msg_prevalidate_callback to validate addresses
00236         this = service_find_by_socket(socket_id);
00237         if (!this) {
00238             return -1;
00239         }
00240     }
00241 
00242     msg_prevalidate_callback = (coap_service_msg_prevalidate_cb *)coap_connection_handler_msg_prevalidate_callback_get(this->conn_handler, &listen_socket_port);
00243     if (msg_prevalidate_callback) {
00244         // message prevalidation activated for the port
00245         char request_uri[coap_message->uri_path_len + 1];
00246         memcpy(request_uri, coap_message->uri_path_ptr, coap_message->uri_path_len);
00247         request_uri[coap_message->uri_path_len] = 0;
00248 
00249         int msg_prevalidate_status = msg_prevalidate_callback(this->interface_id, (uint8_t *)local_addr, listen_socket_port, recv_if_id, transaction_ptr->remote_address, transaction_ptr->remote_port, request_uri);
00250         if (msg_prevalidate_status >= 1) {
00251             tr_deep("Drop CoAP msg %s from %s to %s", request_uri, trace_ipv6(transaction_ptr->remote_address), trace_ipv6(local_addr));
00252             return -1;
00253         }
00254     }
00255 
00256     uri_registration_t *uri_reg_ptr = uri_registration_find(this, coap_message->uri_path_ptr, coap_message->uri_path_len);
00257     if (!uri_reg_ptr) {
00258         /* URI is not available, stop further processing */
00259         if (coap_message->msg_type == COAP_MSG_TYPE_CONFIRMABLE) {
00260             coap_message_handler_response_send(coap_service_handle, transaction_ptr->service_id, COAP_SERVICE_OPTIONS_NONE, coap_message,
00261                                                COAP_MSG_CODE_RESPONSE_NOT_FOUND, COAP_CT_NONE, NULL, 0);
00262             return 0;
00263         }
00264         return -1;
00265     }
00266 
00267     if (uri_reg_ptr->request_recv_cb) {
00268         if ((this->service_options & COAP_SERVICE_OPTIONS_SECURE_BYPASS) == COAP_SERVICE_OPTIONS_SECURE_BYPASS) { //TODO Add secure bypass option
00269             // Service has secure bypass active TODO this is not defined in interface
00270             // this check can be removed I think
00271             transaction_ptr->options = COAP_REQUEST_OPTIONS_SECURE_BYPASS;
00272         }
00273 
00274         transaction_ptr->service_id = this->service_id;
00275         tr_debug("Service %d, recv msg: %.*s", this->service_id, coap_message->uri_path_len, coap_message->uri_path_ptr);
00276         return uri_reg_ptr->request_recv_cb(this->service_id, transaction_ptr->remote_address, transaction_ptr->remote_port, coap_message);
00277     }
00278 
00279     return -1;
00280 }
00281 
00282 static int recv_cb(int8_t socket_id, int8_t recv_if_id, uint8_t src_address[static 16], uint16_t port, const uint8_t dst_address[static 16], unsigned char *data, int len)
00283 {
00284     uint8_t *data_ptr = NULL;
00285     uint16_t data_len = 0;
00286 
00287     if (!data || !len) {
00288         return -1;
00289     }
00290 
00291     data_ptr = own_alloc(len);
00292 
00293     if (!data_ptr) {
00294         return -1;
00295     }
00296     memcpy(data_ptr, data, len);
00297     data_len = len;
00298 
00299     //parse coap message what CoAP to use
00300     int ret = coap_message_handler_coap_msg_process(coap_service_handle, socket_id, recv_if_id, src_address, port, dst_address, data_ptr, data_len, &coap_msg_process_callback);
00301     own_free(data_ptr);
00302     return ret;
00303 }
00304 
00305 static int virtual_send_cb(int8_t socket_id, const uint8_t address[static 16], uint16_t port, const void *data_ptr, int data_len)
00306 {
00307     coap_service_t *this = service_find_by_socket(socket_id);
00308     if (this && this->virtual_socket_send_cb) {
00309         tr_debug("send to virtual socket, service: %d", this->service_id);
00310         return this->virtual_socket_send_cb(this->service_id, (uint8_t *)address, port, data_ptr, data_len);
00311     }
00312     return -1;
00313 }
00314 
00315 static void sec_done_cb(int8_t socket_id, uint8_t address[static 16], uint16_t port, uint8_t keyblock[static 40])
00316 {
00317     //TODO: this is not enough if shared socket. Inform all!
00318     coap_service_t *this = service_find_by_socket(socket_id);
00319     if (this && this->coap_security_done_cb) { // secure done callback
00320         this->coap_security_done_cb(this->service_id, address, keyblock);
00321     }
00322 
00323     //TODO: send all unsend transactions if more than 1
00324     coap_transaction_t *transaction_ptr = coap_message_handler_find_transaction(address, port);
00325     if (transaction_ptr && transaction_ptr->data_ptr) {
00326         tr_debug("send delayed packet");
00327         ns_address_t dest_addr;
00328         memcpy(dest_addr.address, address, 16);
00329         dest_addr.identifier = port;
00330         dest_addr.type = ADDRESS_IPV6;
00331 
00332         coap_connection_handler_send_data(this->conn_handler, &dest_addr, transaction_ptr->local_address,
00333                                           transaction_ptr->data_ptr, transaction_ptr->data_len, (this->service_options & COAP_SERVICE_OPTIONS_SECURE_BYPASS) == COAP_SERVICE_OPTIONS_SECURE_BYPASS);
00334         ns_dyn_mem_free(transaction_ptr->data_ptr);
00335         transaction_ptr->data_ptr = NULL;
00336         transaction_ptr->data_len = 0;
00337         if (!transaction_ptr->resp_cb && transaction_ptr->req_msg_type == COAP_MSG_TYPE_NON_CONFIRMABLE) {
00338             transaction_delete(transaction_ptr);
00339         }
00340     }
00341 }
00342 
00343 static int get_passwd_cb(int8_t socket_id, uint8_t address[static 16], uint16_t port, coap_security_keys_t *security_ptr)
00344 {
00345     uint8_t *pw_ptr = NULL;
00346     uint8_t pw_len = 0;
00347     coap_service_t *this = service_find_by_socket(socket_id);
00348 
00349     if (!this || !security_ptr) {
00350         return -1;
00351     }
00352 
00353     /* Certificates set */
00354     if (this->conn_handler->security_keys) {
00355         *security_ptr = *this->conn_handler->security_keys;
00356         return 0;
00357     }
00358 
00359     pw_ptr = ns_dyn_mem_alloc(64);
00360     if (!pw_ptr) {
00361         return -1;
00362     }
00363 
00364     if (this->security_start_cb && !this->security_start_cb(this->service_id, address, port, pw_ptr, &pw_len)) {
00365         security_ptr->mode = ECJPAKE;
00366         security_ptr->_key = pw_ptr;
00367         security_ptr->_key_len = pw_len;
00368         return 0;
00369     }
00370 
00371     return -1;
00372 }
00373 
00374 int8_t coap_service_initialize(int8_t interface_id, uint16_t listen_port, uint8_t service_options,
00375                                coap_service_security_start_cb *start_ptr, coap_service_security_done_cb *coap_security_done_cb)
00376 {
00377     coap_service_t *this = ns_dyn_mem_alloc(sizeof(coap_service_t));
00378 
00379     if (!this) {
00380         return -1;
00381     }
00382     memset(this, 0, sizeof(coap_service_t));
00383     tr_debug("service init interface %d, port %d, options %d", interface_id, listen_port, service_options);
00384 
00385     int8_t id = 1;// get unique id
00386     while (service_find(id) && id < 127) {
00387         id++;
00388     }
00389     this->interface_id = interface_id;
00390     this->service_id = id;
00391     this->service_options = service_options;
00392 
00393     this->security_start_cb = start_ptr;
00394     this->coap_security_done_cb = coap_security_done_cb;
00395 
00396     if (tasklet_id == -1) {
00397         tr_debug("service tasklet init");
00398         tasklet_id = eventOS_event_handler_create(&service_event_handler, ARM_LIB_TASKLET_INIT_EVENT);
00399     }
00400 
00401     this->conn_handler = connection_handler_create(recv_cb, virtual_send_cb, get_passwd_cb, sec_done_cb);
00402     if (!this->conn_handler) {
00403         ns_dyn_mem_free(this);
00404         return -1;
00405     }
00406 
00407     this->conn_handler->socket_interface_selection = 0; // zero is illegal interface ID
00408     if (this->service_options & COAP_SERVICE_OPTIONS_SELECT_SOCKET_IF) {
00409         this->conn_handler->socket_interface_selection = this->interface_id;
00410     }
00411 
00412     this->conn_handler->registered_to_multicast = this->service_options & COAP_SERVICE_OPTIONS_MULTICAST_JOIN;
00413 
00414     if (0 > coap_connection_handler_open_connection(this->conn_handler, listen_port,
00415                                                     (this->service_options & COAP_SERVICE_OPTIONS_EPHEMERAL_PORT),
00416                                                     (this->service_options & COAP_SERVICE_OPTIONS_SECURE),
00417                                                     !(this->service_options & COAP_SERVICE_OPTIONS_VIRTUAL_SOCKET),
00418                                                     (this->service_options & COAP_SERVICE_OPTIONS_SECURE_BYPASS))) {
00419         ns_dyn_mem_free(this->conn_handler);
00420         ns_dyn_mem_free(this);
00421         return -1;
00422     }
00423 
00424     if (!coap_service_handle) {
00425         coap_service_handle = coap_message_handler_init(&own_alloc, &own_free, &coap_tx_function);
00426     }
00427     if (!coap_service_handle) {
00428         tr_error("coap service alloc failed");
00429         //TODO proper handling
00430     }
00431 
00432     ns_list_add_to_start(&instance_list, this);
00433 
00434     return id;
00435 }
00436 
00437 void coap_service_delete(int8_t service_id)
00438 {
00439     coap_service_t *this = service_find(service_id);
00440     if (!this) {
00441         return;
00442     }
00443 
00444     if (this->conn_handler) {
00445         bool leave_multicast_group = false;
00446         if (coap_service_can_leave_multicast_group(this->conn_handler)) {
00447             // This is the last handler joined to multicast group
00448             leave_multicast_group = true;
00449         }
00450         connection_handler_destroy(this->conn_handler, leave_multicast_group);
00451     }
00452 
00453     //TODO clear all transactions
00454     ns_list_foreach_safe(uri_registration_t, cur_ptr, &this->uri_list) {
00455         ns_dyn_mem_free(cur_ptr->uri_ptr);
00456         ns_list_remove(&this->uri_list, cur_ptr);
00457         ns_dyn_mem_free(cur_ptr);
00458     }
00459 
00460     ns_list_remove(&instance_list, this);
00461     ns_dyn_mem_free(this);
00462     return;
00463 }
00464 
00465 extern void coap_service_close_secure_connection(int8_t service_id, uint8_t destination_addr_ptr[static 16], uint16_t port)
00466 {
00467     coap_service_t *this = service_find(service_id);
00468     if (!this || !destination_addr_ptr) {
00469         return;
00470     }
00471     if (this->conn_handler) {
00472         connection_handler_close_secure_connection(this->conn_handler, destination_addr_ptr, port);
00473     }
00474 }
00475 
00476 int16_t coap_service_virtual_socket_recv(int8_t service_id, uint8_t source_addr_ptr[static 16], uint16_t port, uint8_t *data_ptr, uint16_t data_len)
00477 {
00478     coap_service_t *this = service_find(service_id);
00479     tr_debug("Service %d, virtual socket received", service_id);
00480     if (!this) {
00481         return -1;
00482     }
00483     return coap_connection_handler_virtual_recv(this->conn_handler, source_addr_ptr, port, data_ptr, data_len);
00484 }
00485 
00486 int16_t coap_service_virtual_socket_set_cb(int8_t service_id, coap_service_virtual_socket_send_cb *send_method_ptr)
00487 {
00488     coap_service_t *this = service_find(service_id);
00489     tr_debug("register virtual socket cb to service %d", service_id);
00490     if (!this) {
00491         return -1;
00492     }
00493     this->virtual_socket_send_cb = send_method_ptr;
00494     return 0;
00495 }
00496 
00497 int8_t coap_service_register_uri(int8_t service_id, const char *uri, uint8_t allowed_method, coap_service_request_recv_cb *request_recv_cb)
00498 {
00499     coap_service_t *this = service_find(service_id);
00500     uri_registration_t *uri_reg_ptr;
00501     char *uri_ptr = NULL;
00502     uint16_t uri_len;
00503     tr_debug("Service %d, Uri registration uri: %s", service_id, uri);
00504     if (!this || !uri) {
00505         return -1;
00506     }
00507     uri_len = strlen(uri);
00508 
00509     uri_reg_ptr = uri_registration_find(this, uri, uri_len);
00510     if (!uri_reg_ptr) {
00511         uri_reg_ptr = ns_dyn_mem_alloc(sizeof(uri_registration_t));
00512         if (!uri_reg_ptr) {
00513             tr_error("Uri registration failed, OOM");
00514             return -2;
00515         }
00516         uri_reg_ptr->uri_ptr = NULL;
00517     } else {
00518         ns_dyn_mem_free(uri_reg_ptr->uri_ptr);
00519         ns_list_remove(&this->uri_list, uri_reg_ptr);
00520     }
00521 
00522     uri_ptr = ns_dyn_mem_alloc(uri_len);
00523     if (!uri_ptr) {
00524         ns_dyn_mem_free(uri_reg_ptr);
00525         tr_error("Uri registration failed, OOM");
00526         return -2;
00527     }
00528 
00529     uri_reg_ptr->uri_ptr = memcpy(uri_ptr, uri, uri_len);
00530     uri_reg_ptr->uri_len = uri_len;
00531     uri_reg_ptr->request_recv_cb = request_recv_cb;
00532     uri_reg_ptr->allowed_method = allowed_method;
00533     ns_list_add_to_start(&this->uri_list, uri_reg_ptr);
00534     return 0;
00535 }
00536 
00537 int8_t coap_service_unregister_uri(int8_t service_id, const char *uri)
00538 {
00539     coap_service_t *this = service_find(service_id);
00540     uri_registration_t *uri_reg_ptr;
00541     tr_debug("Service %d, Uri unregistration uri: %s", service_id, uri);
00542     if (!this || !uri) {
00543         return -1;
00544     }
00545 
00546     uri_reg_ptr = uri_registration_find(this, uri, strlen(uri));
00547     if (!uri_reg_ptr) {
00548         return -2;
00549     }
00550 
00551     ns_dyn_mem_free(uri_reg_ptr->uri_ptr);
00552     ns_list_remove(&this->uri_list, uri_reg_ptr);
00553     ns_dyn_mem_free(uri_reg_ptr);
00554 
00555     return 0;
00556 }
00557 
00558 uint16_t coap_service_request_send(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,
00559                                    sn_coap_content_format_e cont_type, const uint8_t *payload_ptr, uint16_t payload_len, coap_service_response_recv *request_response_cb)
00560 {
00561     //TODO: coap_service_response_recv is an ugly cast, this should be refactored away + sn_coap_hdr_s MUST NOT be exposed to users of coap-service!
00562     //Callback would be still needed, but where to store callback?
00563     return coap_message_handler_request_send(coap_service_handle, service_id, options, destination_addr, destination_port, msg_type, msg_code, uri, cont_type, payload_ptr, payload_len, request_response_cb);
00564 }
00565 
00566 int8_t coap_service_response_send(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)
00567 {
00568     return coap_message_handler_response_send(coap_service_handle, service_id, options, request_ptr, message_code, content_type, payload_ptr, payload_len);
00569 }
00570 
00571 int8_t coap_service_response_send_by_msg_id(int8_t service_id, uint8_t options, uint16_t msg_id, sn_coap_msg_code_e message_code, sn_coap_content_format_e content_type, const uint8_t *payload_ptr, uint16_t payload_len)
00572 {
00573     return coap_message_handler_response_send_by_msg_id(coap_service_handle, service_id, options, msg_id, message_code, content_type, payload_ptr, payload_len);
00574 }
00575 
00576 int8_t coap_service_request_delete(int8_t service_id, uint16_t msg_id)
00577 {
00578     return coap_message_handler_request_delete(coap_service_handle, service_id, msg_id);
00579 }
00580 
00581 void coap_service_request_delete_by_service_id(int8_t service_id)
00582 {
00583     coap_message_handler_request_delete_by_service_id(coap_service_handle, service_id);
00584 }
00585 
00586 int8_t coap_service_set_handshake_timeout(int8_t service_id, uint32_t min, uint32_t max)
00587 {
00588     coap_service_t *this = service_find(service_id);
00589     if (!this) {
00590         return -1;
00591     }
00592 
00593     return coap_connection_handler_set_timeout(this->conn_handler, min, max);
00594 }
00595 
00596 int8_t coap_service_handshake_limits_set(uint8_t handshakes_max, uint8_t connections_max)
00597 {
00598     return coap_connection_handler_handshake_limits_set(handshakes_max, connections_max);
00599 }
00600 
00601 int8_t coap_service_set_duplicate_message_buffer(int8_t service_id, uint8_t size)
00602 {
00603     (void) service_id;
00604 
00605     if (!coap_service_handle) {
00606         return -1;
00607     }
00608 
00609     return sn_coap_protocol_set_duplicate_buffer_size(coap_service_handle->coap, size);
00610 }
00611 
00612 uint32_t coap_service_get_internal_timer_ticks(void)
00613 {
00614     return coap_ticks;
00615 }
00616 
00617 uint16_t coap_service_id_find_by_socket(int8_t socket_id)
00618 {
00619     coap_service_t *this = service_find_by_socket(socket_id);
00620 
00621     return this ? this->service_id : 0;
00622 }
00623 
00624 int8_t coap_service_certificate_set(int8_t service_id, const unsigned char *cert, uint16_t cert_len, const unsigned char *priv_key, uint8_t priv_key_len)
00625 {
00626     coap_service_t *this = service_find(service_id);
00627     if (!this) {
00628         return -1;
00629     }
00630 
00631     if (!this->conn_handler->security_keys) {
00632         this->conn_handler->security_keys = ns_dyn_mem_alloc(sizeof(coap_security_keys_t));
00633 
00634         if (!this->conn_handler->security_keys) {
00635             return -1;
00636         }
00637     }
00638 
00639     memset(this->conn_handler->security_keys, 0, sizeof(coap_security_keys_t));
00640 
00641     this->conn_handler->security_keys->_cert = cert;
00642     this->conn_handler->security_keys->_cert_len = cert_len;
00643 
00644     this->conn_handler->security_keys->_priv_key = priv_key;
00645     this->conn_handler->security_keys->_priv_key_len = priv_key_len;
00646 
00647     this->conn_handler->security_keys->mode = CERTIFICATE;
00648 
00649     return 0;
00650 }
00651 
00652 int8_t coap_service_blockwise_size_set(int8_t service_id, uint16_t size)
00653 {
00654     (void) service_id;
00655 
00656     if (!coap_service_handle) {
00657         return -1;
00658     }
00659 
00660     return sn_coap_protocol_set_block_size(coap_service_handle->coap, size);
00661 }
00662 
00663 int8_t coap_service_msg_prevalidate_callback_set(uint16_t listen_socket, coap_service_msg_prevalidate_cb *msg_prevalidate_cb)
00664 {
00665     coap_conn_handler_t *conn_handler = coap_connection_handler_find_by_socket_port(listen_socket);
00666     if (conn_handler) {
00667         return (int8_t)coap_connection_handler_msg_prevalidate_callback_set(conn_handler, (cch_func_cb *)msg_prevalidate_cb);
00668     }
00669     return -1;
00670 }