Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510
sn_grs2.c
00001 /* 00002 * Copyright (c) 2011-2015 ARM Limited. All rights reserved. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * Licensed under the Apache License, Version 2.0 (the License); you may 00005 * not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an AS IS BASIS, WITHOUT 00012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 /** 00018 * 00019 * \file sn_grs.c 00020 * 00021 * \brief General resource server. 00022 * 00023 */ 00024 #ifdef MBED_CLIENT_C_NEW_API 00025 #include <string.h> 00026 #include <stdlib.h> 00027 #include "ns_list.h" 00028 #include "ns_types.h" 00029 #include "sn_nsdl.h" 00030 #include "sn_coap_header.h" 00031 #include "sn_coap_protocol.h" 00032 #include "sn_coap_protocol_internal.h" 00033 #include "sn_nsdl_lib.h" 00034 #include "sn_grs.h" 00035 #include "mbed-trace/mbed_trace.h" 00036 00037 /* Defines */ 00038 #define TRACE_GROUP "coap" 00039 #define WELLKNOWN_PATH_LEN 16 00040 #define WELLKNOWN_PATH (".well-known/core") 00041 00042 /* Local static function prototypes */ 00043 static int8_t sn_grs_resource_info_free(struct grs_s *handle, sn_nsdl_dynamic_resource_parameters_s *resource_ptr); 00044 static uint8_t *sn_grs_convert_uri(uint16_t *uri_len, uint8_t *uri_ptr); 00045 #ifndef MEMORY_OPTIMIZED_API 00046 static int8_t sn_grs_add_resource_to_list(struct grs_s *handle, sn_nsdl_dynamic_resource_parameters_s *resource_ptr); 00047 #endif 00048 static int8_t sn_grs_core_request(struct nsdl_s *handle, sn_nsdl_addr_s *src_addr_ptr, sn_coap_hdr_s *coap_packet_ptr); 00049 static uint8_t coap_tx_callback(uint8_t *, uint16_t, sn_nsdl_addr_s *, void *); 00050 static int8_t coap_rx_callback(sn_coap_hdr_s *coap_ptr, sn_nsdl_addr_s *address_ptr, void *param); 00051 00052 /* Extern function prototypes */ 00053 extern int8_t sn_nsdl_build_registration_body(struct nsdl_s *handle, sn_coap_hdr_s *message_ptr, uint8_t updating_registeration); 00054 00055 /** 00056 * \fn int8_t sn_grs_destroy(void) 00057 * \brief This function may be used to flush GRS related stuff when a program exits. 00058 * @return always 0. 00059 */ 00060 extern int8_t sn_grs_destroy(struct grs_s *handle) 00061 { 00062 if( handle == NULL ){ 00063 return 0; 00064 } 00065 ns_list_foreach_safe(sn_nsdl_dynamic_resource_parameters_s, tmp, &handle->resource_root_list) { 00066 ns_list_remove(&handle->resource_root_list, tmp); 00067 --handle->resource_root_count; 00068 sn_grs_resource_info_free(handle, tmp); 00069 } 00070 handle->sn_grs_free(handle); 00071 00072 return 0; 00073 } 00074 00075 static uint8_t coap_tx_callback(uint8_t *data_ptr, uint16_t data_len, sn_nsdl_addr_s *address_ptr, void *param) 00076 { 00077 struct nsdl_s *handle = (struct nsdl_s *)param; 00078 00079 if (handle == NULL) { 00080 return 0; 00081 } 00082 00083 return handle->grs->sn_grs_tx_callback(handle, SN_NSDL_PROTOCOL_COAP, data_ptr, data_len, address_ptr); 00084 } 00085 00086 static int8_t coap_rx_callback(sn_coap_hdr_s *coap_ptr, sn_nsdl_addr_s *address_ptr, void *param) 00087 { 00088 struct nsdl_s *handle = (struct nsdl_s *)param; 00089 00090 if (handle == NULL) { 00091 return 0; 00092 } 00093 00094 return handle->sn_nsdl_rx_callback(handle, coap_ptr, address_ptr); 00095 } 00096 00097 /** 00098 * \fn int8_t sn_grs_init (uint8_t (*sn_grs_tx_callback_ptr)(sn_nsdl_capab_e , uint8_t *, uint16_t, 00099 * sn_nsdl_addr_s *), int8_t (*sn_grs_rx_callback_ptr)(sn_coap_hdr_s *, sn_nsdl_addr_s *), sn_nsdl_mem_s *sn_memory) 00100 * 00101 * \brief GRS library initialize function. 00102 * 00103 * This function initializes GRS and CoAP libraries. 00104 * 00105 * \param sn_grs_tx_callback A function pointer to a transmit callback function. 00106 * \param *sn_grs_rx_callback_ptr A function pointer to a receiving callback function. If received packet is not for GRS, it will be passed to 00107 * upper level (NSDL) to be proceed. 00108 * \param sn_memory A pointer to a structure containing the platform specific functions for memory allocation and free. 00109 * 00110 * \return success = 0, failure = -1 00111 * 00112 */ 00113 extern struct grs_s *sn_grs_init(uint8_t (*sn_grs_tx_callback_ptr)(struct nsdl_s *, sn_nsdl_capab_e , uint8_t *, uint16_t, 00114 sn_nsdl_addr_s *), int8_t (*sn_grs_rx_callback_ptr)(struct nsdl_s *, sn_coap_hdr_s *, sn_nsdl_addr_s *), 00115 void *(*sn_grs_alloc)(uint16_t), void (*sn_grs_free)(void *)) 00116 { 00117 00118 struct grs_s *handle_ptr = NULL; 00119 00120 /* Check parameters */ 00121 if (sn_grs_alloc == NULL || sn_grs_free == NULL || 00122 sn_grs_tx_callback_ptr == NULL || sn_grs_rx_callback_ptr == NULL) { 00123 return NULL; 00124 } 00125 00126 handle_ptr = sn_grs_alloc(sizeof(struct grs_s)); 00127 00128 if (handle_ptr == NULL) { 00129 return NULL; 00130 } 00131 00132 memset(handle_ptr, 0, sizeof(struct grs_s)); 00133 00134 /* Allocation and free - function pointers */ 00135 handle_ptr->sn_grs_alloc = sn_grs_alloc; 00136 handle_ptr->sn_grs_free = sn_grs_free; 00137 00138 /* TX callback function pointer */ 00139 handle_ptr->sn_grs_tx_callback = sn_grs_tx_callback_ptr; 00140 handle_ptr->sn_grs_rx_callback = sn_grs_rx_callback_ptr; 00141 00142 /* Initialize CoAP protocol library */ 00143 handle_ptr->coap = sn_coap_protocol_init(sn_grs_alloc, sn_grs_free, coap_tx_callback, coap_rx_callback); 00144 00145 return handle_ptr; 00146 } 00147 00148 extern sn_grs_resource_list_s *sn_grs_list_resource(struct grs_s *handle, uint16_t pathlen, uint8_t *path) 00149 { 00150 (void) pathlen; 00151 sn_grs_resource_list_s *grs_resource_list_ptr = NULL; 00152 00153 if( handle == NULL || path == NULL){ 00154 return NULL; 00155 } 00156 00157 /* Allocate memory for the resource list to be filled */ 00158 grs_resource_list_ptr = handle->sn_grs_alloc(sizeof(sn_grs_resource_list_s)); 00159 if (!grs_resource_list_ptr) { 00160 goto fail; 00161 } 00162 00163 /* Count resources to the resource list struct */ 00164 grs_resource_list_ptr->res_count = handle->resource_root_count; 00165 grs_resource_list_ptr->res = NULL; 00166 00167 /**************************************/ 00168 /* Fill resource structs to the table */ 00169 /**************************************/ 00170 00171 /* If resources in list */ 00172 if (grs_resource_list_ptr->res_count) { 00173 int i; 00174 00175 /* Allocate memory for resources */ 00176 grs_resource_list_ptr->res = handle->sn_grs_alloc(grs_resource_list_ptr->res_count * sizeof(sn_grs_resource_s)); 00177 if (!grs_resource_list_ptr->res) { 00178 goto fail; 00179 } 00180 00181 /* Initialise the pointers to NULL to permit easy cleanup */ 00182 for (i = 0; i < grs_resource_list_ptr->res_count; i++) { 00183 grs_resource_list_ptr->res[i].path = NULL; 00184 grs_resource_list_ptr->res[i].pathlen = 0; 00185 } 00186 00187 i = 0; 00188 ns_list_foreach(sn_nsdl_dynamic_resource_parameters_s, grs_resource_ptr, &handle->resource_root_list) { 00189 /* Copy pathlen to resource list */ 00190 grs_resource_list_ptr->res[i].pathlen = grs_resource_ptr->static_resource_parameters->pathlen; 00191 00192 /* Allocate memory for path string */ 00193 grs_resource_list_ptr->res[i].path = handle->sn_grs_alloc(grs_resource_list_ptr->res[i].pathlen); 00194 if (!grs_resource_list_ptr->res[i].path) { 00195 goto fail; 00196 } 00197 00198 /* Copy pathstring to resource list */ 00199 memcpy(grs_resource_list_ptr->res[i].path, 00200 grs_resource_ptr->static_resource_parameters->path, 00201 grs_resource_ptr->static_resource_parameters->pathlen); 00202 00203 i++; 00204 } 00205 } 00206 return grs_resource_list_ptr; 00207 00208 fail: 00209 sn_grs_free_resource_list(handle, grs_resource_list_ptr); 00210 return NULL; 00211 } 00212 00213 extern void sn_grs_free_resource_list(struct grs_s *handle, sn_grs_resource_list_s *list) 00214 { 00215 if (!list || !handle) { 00216 return; 00217 } 00218 00219 if (list->res) { 00220 for (int i = 0; i < list->res_count; i++) { 00221 if (list->res[i].path) { 00222 handle->sn_grs_free(list->res[i].path); 00223 list->res[i].path = NULL; 00224 } 00225 } 00226 handle->sn_grs_free(list->res); 00227 list->res = NULL; 00228 } 00229 00230 handle->sn_grs_free(list); 00231 } 00232 00233 extern sn_nsdl_dynamic_resource_parameters_s *sn_grs_get_first_resource(struct grs_s *handle) 00234 { 00235 if( !handle ){ 00236 return NULL; 00237 } 00238 return ns_list_get_first(&handle->resource_root_list); 00239 } 00240 00241 extern sn_nsdl_dynamic_resource_parameters_s *sn_grs_get_next_resource(struct grs_s *handle, 00242 const sn_nsdl_dynamic_resource_parameters_s *sn_grs_current_resource) 00243 { 00244 if( !handle || !sn_grs_current_resource ){ 00245 return NULL; 00246 } 00247 return ns_list_get_next(&handle->resource_root_list, sn_grs_current_resource); 00248 } 00249 00250 extern int8_t sn_grs_delete_resource(struct grs_s *handle, uint16_t pathlen, uint8_t *path) 00251 { 00252 /* Local variables */ 00253 sn_nsdl_dynamic_resource_parameters_s *resource_temp = NULL; 00254 00255 /* Search if resource found */ 00256 resource_temp = sn_grs_search_resource(handle, pathlen, path, SN_GRS_SEARCH_METHOD); 00257 00258 /* If not found */ 00259 if (resource_temp == NULL) { 00260 return SN_NSDL_FAILURE; 00261 } 00262 00263 /* If found, delete it and delete also subresources, if there is any */ 00264 do { 00265 /* Remove from list */ 00266 ns_list_remove(&handle->resource_root_list, resource_temp); 00267 --handle->resource_root_count; 00268 00269 /* Free */ 00270 sn_grs_resource_info_free(handle, resource_temp); 00271 00272 /* Search for subresources */ 00273 resource_temp = sn_grs_search_resource(handle, pathlen, path, SN_GRS_DELETE_METHOD); 00274 } while (resource_temp != NULL); 00275 00276 return SN_NSDL_SUCCESS; 00277 } 00278 00279 #ifndef MEMORY_OPTIMIZED_API 00280 extern int8_t sn_grs_update_resource(struct grs_s *handle, sn_nsdl_dynamic_resource_parameters_s *res) 00281 { 00282 /* Local variables */ 00283 sn_nsdl_dynamic_resource_parameters_s *resource_temp = NULL; 00284 00285 if( !res || !handle ){ 00286 return SN_NSDL_FAILURE; 00287 } 00288 00289 /* Search resource */ 00290 resource_temp = sn_grs_search_resource(handle, 00291 res->static_resource_parameters->pathlen, 00292 res->static_resource_parameters->path, 00293 SN_GRS_SEARCH_METHOD); 00294 if (!resource_temp) { 00295 return SN_NSDL_FAILURE; 00296 } 00297 00298 /* If there is payload on resource, free it */ 00299 if (resource_temp->static_resource_parameters->resource != NULL) { 00300 handle->sn_grs_free(resource_temp->static_resource_parameters->resource); 00301 resource_temp->static_resource_parameters->resource = 0; 00302 } 00303 /* Update resource len */ 00304 resource_temp->static_resource_parameters->resourcelen = 00305 res->static_resource_parameters->resourcelen; 00306 00307 /* If resource len >0, allocate memory and copy payload */ 00308 if (res->static_resource_parameters->resourcelen) { 00309 resource_temp->static_resource_parameters->resource = 00310 handle->sn_grs_alloc(res->static_resource_parameters->resourcelen); 00311 if (resource_temp->static_resource_parameters->resource == NULL) { 00312 resource_temp->static_resource_parameters->resourcelen = 0; 00313 return SN_NSDL_FAILURE; 00314 } 00315 00316 memcpy(resource_temp->static_resource_parameters->resource, 00317 res->static_resource_parameters->resource, 00318 resource_temp->static_resource_parameters->resourcelen); 00319 } 00320 00321 /* Update access rights and callback address */ 00322 resource_temp->access = res->access; 00323 resource_temp->sn_grs_dyn_res_callback = res->sn_grs_dyn_res_callback; 00324 00325 /* TODO: resource_parameters_ptr not copied */ 00326 00327 return SN_NSDL_SUCCESS; 00328 } 00329 00330 extern int8_t sn_grs_create_resource(struct grs_s *handle, sn_nsdl_dynamic_resource_parameters_s *res) 00331 { 00332 if (!res || !handle) { 00333 return SN_NSDL_FAILURE; 00334 } 00335 00336 /* Check path validity */ 00337 if (!res->static_resource_parameters->pathlen || !res->static_resource_parameters->path) { 00338 return SN_GRS_INVALID_PATH; 00339 } 00340 00341 /* Check if resource already exists */ 00342 if (sn_grs_search_resource(handle, 00343 res->static_resource_parameters->pathlen, 00344 res->static_resource_parameters->path, 00345 SN_GRS_SEARCH_METHOD) != 00346 (sn_nsdl_dynamic_resource_parameters_s *)NULL) { 00347 return SN_GRS_RESOURCE_ALREADY_EXISTS; 00348 } 00349 00350 if (res) { 00351 res->registered = SN_NDSL_RESOURCE_NOT_REGISTERED; 00352 } 00353 00354 /* Create resource */ 00355 if (sn_grs_add_resource_to_list(handle, res) == SN_NSDL_SUCCESS) { 00356 return SN_NSDL_SUCCESS; 00357 } 00358 return SN_GRS_LIST_ADDING_FAILURE; 00359 } 00360 00361 /** 00362 * \fn static int8_t sn_grs_add_resource_to_list(sn_nsdl_dynamic_resource_parameters_s *resource_ptr) 00363 * 00364 * \brief Adds given resource to resource list 00365 * 00366 * \param *resource_ptr Pointer to the path string to be search 00367 * 00368 * \return 0 = SN_NSDL_SUCCESS, -1 = SN_NSDL_FAILURE 00369 * 00370 */ 00371 static int8_t sn_grs_add_resource_to_list(struct grs_s *handle, sn_nsdl_dynamic_resource_parameters_s *resource_ptr) 00372 { 00373 /* Local variables */ 00374 00375 uint8_t *path_start_ptr = NULL; 00376 uint16_t path_len = 0; 00377 sn_nsdl_dynamic_resource_parameters_s *resource_copy_ptr = NULL; 00378 00379 /* Allocate memory for the resource info copy */ 00380 if (!resource_ptr->static_resource_parameters->pathlen) { //Dead code 00381 return SN_NSDL_FAILURE; 00382 } 00383 00384 resource_copy_ptr = handle->sn_grs_alloc(sizeof(sn_nsdl_dynamic_resource_parameters_s)); 00385 if (resource_copy_ptr == NULL) { 00386 return SN_NSDL_FAILURE; 00387 } 00388 00389 /* Set everything to zero */ 00390 memset(resource_copy_ptr, 0, sizeof(sn_nsdl_dynamic_resource_parameters_s)); 00391 resource_copy_ptr->sn_grs_dyn_res_callback = resource_ptr->sn_grs_dyn_res_callback; 00392 resource_copy_ptr->publish_uri = resource_ptr->publish_uri; 00393 resource_copy_ptr->free_on_delete = resource_ptr->free_on_delete; 00394 resource_copy_ptr->coap_content_type = resource_ptr->coap_content_type; 00395 resource_copy_ptr->observable = resource_ptr->observable; 00396 resource_copy_ptr->access = resource_ptr->access; 00397 /* If resource parameters exists, copy them */ 00398 if (resource_ptr->static_resource_parameters) { 00399 resource_copy_ptr->static_resource_parameters = handle->sn_grs_alloc(sizeof(sn_nsdl_static_resource_parameters_s)); 00400 if (!resource_copy_ptr->static_resource_parameters) { 00401 sn_grs_resource_info_free(handle, resource_copy_ptr); 00402 return SN_NSDL_FAILURE; 00403 } 00404 00405 memset(resource_copy_ptr->static_resource_parameters, 0, sizeof(sn_nsdl_static_resource_parameters_s)); 00406 resource_copy_ptr->static_resource_parameters->mode = 00407 resource_ptr->static_resource_parameters->mode; 00408 resource_copy_ptr->static_resource_parameters->external_memory_block = 00409 resource_ptr->static_resource_parameters->external_memory_block; 00410 resource_copy_ptr->static_resource_parameters->free_on_delete = 00411 resource_ptr->static_resource_parameters->free_on_delete; 00412 00413 resource_copy_ptr->static_resource_parameters->pathlen = 00414 resource_ptr->static_resource_parameters->pathlen; 00415 resource_copy_ptr->static_resource_parameters->resourcelen = 00416 resource_ptr->static_resource_parameters->resourcelen; 00417 00418 if (resource_ptr->static_resource_parameters->resource_type_ptr) { 00419 // alloc space for terminating zero too 00420 const size_t resource_type_len = strlen(resource_ptr->static_resource_parameters->resource_type_ptr) + 1; 00421 resource_copy_ptr->static_resource_parameters->resource_type_ptr = 00422 handle->sn_grs_alloc(resource_type_len); 00423 if (!resource_copy_ptr->static_resource_parameters->resource_type_ptr) { 00424 sn_grs_resource_info_free(handle, resource_copy_ptr); 00425 return SN_NSDL_FAILURE; 00426 } 00427 memcpy(resource_copy_ptr->static_resource_parameters->resource_type_ptr, 00428 resource_ptr->static_resource_parameters->resource_type_ptr, 00429 resource_type_len); 00430 } 00431 00432 if (resource_ptr->static_resource_parameters->interface_description_ptr) { 00433 // todo: a sn_grs_strdup() or similar helper to avoid this copy-paste pattern. 00434 const size_t interface_description_len = strlen(resource_ptr->static_resource_parameters->interface_description_ptr) + 1; 00435 resource_copy_ptr->static_resource_parameters->interface_description_ptr = 00436 handle->sn_grs_alloc(interface_description_len); 00437 if (!resource_copy_ptr->static_resource_parameters->interface_description_ptr) { 00438 sn_grs_resource_info_free(handle, resource_copy_ptr); 00439 return SN_NSDL_FAILURE; 00440 } 00441 memcpy(resource_copy_ptr->static_resource_parameters->interface_description_ptr, 00442 resource_ptr->static_resource_parameters->interface_description_ptr, 00443 interface_description_len); 00444 } 00445 00446 /* Remove '/' - chars from the beginning and from the end */ 00447 00448 path_len = resource_ptr->static_resource_parameters->pathlen; 00449 path_start_ptr = sn_grs_convert_uri(&path_len, resource_ptr->static_resource_parameters->path); 00450 00451 /* Allocate memory for the path */ 00452 resource_copy_ptr->static_resource_parameters->path = handle->sn_grs_alloc(path_len); 00453 if (!resource_copy_ptr->static_resource_parameters->path) { 00454 sn_grs_resource_info_free(handle, resource_copy_ptr); 00455 return SN_NSDL_FAILURE; 00456 } 00457 00458 /* Update pathlen */ 00459 resource_copy_ptr->static_resource_parameters->pathlen = path_len; 00460 00461 /* Copy path string to the copy */ 00462 memcpy(resource_copy_ptr->static_resource_parameters->path, 00463 path_start_ptr, 00464 resource_copy_ptr->static_resource_parameters->pathlen); 00465 00466 /* Allocate memory for the resource, and copy it to copy */ 00467 if (resource_ptr->static_resource_parameters->resource) { 00468 resource_copy_ptr->static_resource_parameters->resource = 00469 handle->sn_grs_alloc(resource_ptr->static_resource_parameters->resourcelen); 00470 if (!resource_copy_ptr->static_resource_parameters->resource) { 00471 sn_grs_resource_info_free(handle, resource_copy_ptr); 00472 return SN_NSDL_FAILURE; 00473 } 00474 memcpy(resource_copy_ptr->static_resource_parameters->resource, 00475 resource_ptr->static_resource_parameters->resource, 00476 resource_ptr->static_resource_parameters->resourcelen); 00477 } 00478 } 00479 00480 /* Add copied resource to the linked list */ 00481 ns_list_add_to_start(&handle->resource_root_list, resource_copy_ptr); 00482 ++handle->resource_root_count; 00483 00484 return SN_NSDL_SUCCESS; 00485 } 00486 #endif 00487 00488 int8_t sn_grs_put_resource(struct grs_s *handle, sn_nsdl_dynamic_resource_parameters_s *res) 00489 { 00490 if (!res || !handle) { 00491 return SN_NSDL_FAILURE; 00492 } 00493 00494 /* Check path validity */ 00495 if (!res->static_resource_parameters->pathlen || !res->static_resource_parameters->path) { 00496 return SN_GRS_INVALID_PATH; 00497 } 00498 00499 /* Check if resource already exists */ 00500 if (sn_grs_search_resource(handle, 00501 res->static_resource_parameters->pathlen, 00502 res->static_resource_parameters->path, SN_GRS_SEARCH_METHOD) != (sn_nsdl_dynamic_resource_parameters_s *)NULL) { 00503 return SN_GRS_RESOURCE_ALREADY_EXISTS; 00504 } 00505 00506 res->registered = SN_NDSL_RESOURCE_NOT_REGISTERED; 00507 00508 ns_list_add_to_start(&handle->resource_root_list, res); 00509 ++handle->resource_root_count; 00510 00511 return SN_NSDL_SUCCESS; 00512 } 00513 00514 int8_t sn_grs_pop_resource(struct grs_s *handle, sn_nsdl_dynamic_resource_parameters_s *res) 00515 { 00516 if (!res || !handle) { 00517 return SN_NSDL_FAILURE; 00518 } 00519 00520 /* Check path validity */ 00521 if (!res->static_resource_parameters->pathlen || !res->static_resource_parameters->path) { 00522 return SN_GRS_INVALID_PATH; 00523 } 00524 00525 /* Check if resource exists on list. */ 00526 if (sn_grs_search_resource(handle, 00527 res->static_resource_parameters->pathlen, 00528 res->static_resource_parameters->path, SN_GRS_SEARCH_METHOD) == (sn_nsdl_dynamic_resource_parameters_s *)NULL) { 00529 return SN_NSDL_FAILURE; 00530 } 00531 00532 ns_list_remove(&handle->resource_root_list, res); 00533 --handle->resource_root_count; 00534 00535 return SN_NSDL_SUCCESS; 00536 } 00537 00538 /** 00539 * \fn extern int8_t sn_grs_process_coap(uint8_t *packet, uint16_t *packet_len, sn_nsdl_addr_s *src) 00540 * 00541 * \brief To push CoAP packet to GRS library 00542 * 00543 * Used to push an CoAP packet to GRS library for processing. 00544 * 00545 * \param *packet Pointer to a uint8_t array containing the packet (including the CoAP headers). 00546 * After successful execution this array may contain the response packet. 00547 * 00548 * \param *packet_len Pointer to length of the packet. After successful execution this array may contain the length 00549 * of the response packet. 00550 * 00551 * \param *src Pointer to packet source address information. After successful execution this array may contain 00552 * the destination address of the response packet. 00553 * 00554 * \return 0 = success, -1 = failure 00555 */ 00556 extern int8_t sn_grs_process_coap(struct nsdl_s *nsdl_handle, sn_coap_hdr_s *coap_packet_ptr, sn_nsdl_addr_s *src_addr_ptr) 00557 { 00558 tr_debug("sn_grs_process_coap"); 00559 if( !coap_packet_ptr || !nsdl_handle){ 00560 return SN_NSDL_FAILURE; 00561 } 00562 00563 tr_debug("sn_grs_process_coap - coap params:"); 00564 tr_debug("msg code: (%d), msg type: (%d), msg id: (%d), path: (%.*s)", 00565 coap_packet_ptr->msg_code, coap_packet_ptr->msg_type, coap_packet_ptr->msg_id, 00566 coap_packet_ptr->uri_path_len, coap_packet_ptr->uri_path_ptr); 00567 00568 sn_nsdl_dynamic_resource_parameters_s *resource_temp_ptr = NULL; 00569 sn_coap_msg_code_e status = COAP_MSG_CODE_EMPTY; 00570 sn_coap_hdr_s *response_message_hdr_ptr = NULL; 00571 struct grs_s *handle = nsdl_handle->grs; 00572 bool static_get_request = false; 00573 00574 if (coap_packet_ptr->msg_code <= COAP_MSG_CODE_REQUEST_DELETE) { 00575 /* Check if .well-known/core */ 00576 if (coap_packet_ptr->uri_path_len == WELLKNOWN_PATH_LEN && memcmp(coap_packet_ptr->uri_path_ptr, WELLKNOWN_PATH, WELLKNOWN_PATH_LEN) == 0) { 00577 return sn_grs_core_request(nsdl_handle, src_addr_ptr, coap_packet_ptr); 00578 } 00579 00580 /* Get resource */ 00581 resource_temp_ptr = sn_grs_search_resource(handle, coap_packet_ptr->uri_path_len, coap_packet_ptr->uri_path_ptr, SN_GRS_SEARCH_METHOD); 00582 00583 00584 /* * * * * * * * * * * */ 00585 /* If resource exists */ 00586 /* * * * * * * * * * * */ 00587 if (resource_temp_ptr) { 00588 tr_debug("sn_grs_process_coap - found (%.*s)", resource_temp_ptr->static_resource_parameters->pathlen, 00589 resource_temp_ptr->static_resource_parameters->path); 00590 /* If dynamic resource, go to callback */ 00591 if (resource_temp_ptr->static_resource_parameters->mode == SN_GRS_DYNAMIC) { 00592 /* Check accesses */ 00593 if (((coap_packet_ptr->msg_code == COAP_MSG_CODE_REQUEST_GET) && !(resource_temp_ptr->access & SN_GRS_GET_ALLOWED)) || 00594 ((coap_packet_ptr->msg_code == COAP_MSG_CODE_REQUEST_POST) && !(resource_temp_ptr->access & SN_GRS_POST_ALLOWED)) || 00595 ((coap_packet_ptr->msg_code == COAP_MSG_CODE_REQUEST_PUT) && !(resource_temp_ptr->access & SN_GRS_PUT_ALLOWED)) || 00596 ((coap_packet_ptr->msg_code == COAP_MSG_CODE_REQUEST_DELETE) && !(resource_temp_ptr->access & SN_GRS_DELETE_ALLOWED))) { 00597 status = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00598 } else { 00599 /* Do not call null pointer.. */ 00600 if (resource_temp_ptr->sn_grs_dyn_res_callback != NULL) { 00601 resource_temp_ptr->sn_grs_dyn_res_callback(nsdl_handle, coap_packet_ptr, src_addr_ptr, SN_NSDL_PROTOCOL_COAP); 00602 } 00603 00604 if (coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr) { 00605 handle->sn_grs_free(coap_packet_ptr->payload_ptr); 00606 coap_packet_ptr->payload_ptr = 0; 00607 } 00608 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_packet_ptr); 00609 return SN_NSDL_SUCCESS; 00610 } 00611 } else { 00612 /* Static resource handling */ 00613 switch (coap_packet_ptr->msg_code) { 00614 case COAP_MSG_CODE_REQUEST_GET: 00615 if (resource_temp_ptr->access & SN_GRS_GET_ALLOWED) { 00616 status = COAP_MSG_CODE_RESPONSE_CONTENT; 00617 static_get_request = true; 00618 } else { 00619 status = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00620 } 00621 break; 00622 00623 case COAP_MSG_CODE_REQUEST_POST: 00624 case COAP_MSG_CODE_REQUEST_PUT: 00625 case COAP_MSG_CODE_REQUEST_DELETE: 00626 status = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; 00627 break; 00628 00629 default: 00630 status = COAP_MSG_CODE_RESPONSE_FORBIDDEN; 00631 break; 00632 } 00633 } 00634 } 00635 00636 /* * * * * * * * * * * * * * */ 00637 /* If resource was not found */ 00638 /* * * * * * * * * * * * * * */ 00639 00640 else { 00641 if (coap_packet_ptr->msg_code == COAP_MSG_CODE_REQUEST_POST) { 00642 handle->sn_grs_rx_callback(nsdl_handle, coap_packet_ptr, src_addr_ptr); 00643 00644 if (coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr) { 00645 handle->sn_grs_free(coap_packet_ptr->payload_ptr); 00646 coap_packet_ptr->payload_ptr = 0; 00647 } 00648 00649 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_packet_ptr); 00650 return SN_NSDL_SUCCESS; 00651 } else { 00652 status = COAP_MSG_CODE_RESPONSE_NOT_FOUND; 00653 } 00654 } 00655 } 00656 00657 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 00658 /* If received packed was other than reset, create response */ 00659 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 00660 if (coap_packet_ptr->msg_type != COAP_MSG_TYPE_RESET && coap_packet_ptr->msg_type != COAP_MSG_TYPE_ACKNOWLEDGEMENT) { 00661 00662 /* Allocate resopnse message */ 00663 response_message_hdr_ptr = sn_coap_parser_alloc_message(handle->coap); 00664 if (!response_message_hdr_ptr) { 00665 if (coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr) { 00666 handle->sn_grs_free(coap_packet_ptr->payload_ptr); 00667 coap_packet_ptr->payload_ptr = 0; 00668 } 00669 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_packet_ptr); 00670 return SN_NSDL_FAILURE; 00671 } 00672 00673 /* If status has not been defined, response internal server error */ 00674 if (status == COAP_MSG_CODE_EMPTY) { 00675 status = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR; 00676 } 00677 00678 /* Fill header */ 00679 response_message_hdr_ptr->msg_code = status; 00680 00681 if (coap_packet_ptr->msg_type == COAP_MSG_TYPE_CONFIRMABLE) { 00682 response_message_hdr_ptr->msg_type = COAP_MSG_TYPE_ACKNOWLEDGEMENT; 00683 } else { 00684 response_message_hdr_ptr->msg_type = COAP_MSG_TYPE_NON_CONFIRMABLE; 00685 } 00686 00687 response_message_hdr_ptr->msg_id = coap_packet_ptr->msg_id; 00688 00689 if (coap_packet_ptr->token_ptr) { 00690 response_message_hdr_ptr->token_len = coap_packet_ptr->token_len; 00691 response_message_hdr_ptr->token_ptr = handle->sn_grs_alloc(response_message_hdr_ptr->token_len); 00692 if (!response_message_hdr_ptr->token_ptr) { 00693 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, response_message_hdr_ptr); 00694 00695 if (coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr) { 00696 handle->sn_grs_free(coap_packet_ptr->payload_ptr); 00697 coap_packet_ptr->payload_ptr = 0; 00698 } 00699 00700 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_packet_ptr); 00701 return SN_NSDL_FAILURE; 00702 } 00703 memcpy(response_message_hdr_ptr->token_ptr, coap_packet_ptr->token_ptr, response_message_hdr_ptr->token_len); 00704 } 00705 00706 if (status == COAP_MSG_CODE_RESPONSE_CONTENT) { 00707 /* Add content type if other than default */ 00708 if (resource_temp_ptr->static_resource_parameters) { 00709 /* XXXX Why "if != 0"? 0 means text/plain, and is not the default for CoAP - this prevents setting text/plain? */ 00710 if (resource_temp_ptr->coap_content_type != 0) { 00711 response_message_hdr_ptr->content_format = 00712 (sn_coap_content_format_e) resource_temp_ptr->coap_content_type; 00713 } 00714 } 00715 00716 /* Add payload */ 00717 if (resource_temp_ptr->static_resource_parameters->resourcelen != 0) { 00718 response_message_hdr_ptr->payload_len = resource_temp_ptr->static_resource_parameters->resourcelen; 00719 response_message_hdr_ptr->payload_ptr = handle->sn_grs_alloc(response_message_hdr_ptr->payload_len); 00720 00721 if (!response_message_hdr_ptr->payload_ptr) { 00722 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, response_message_hdr_ptr); 00723 00724 if (coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr) { 00725 handle->sn_grs_free(coap_packet_ptr->payload_ptr); 00726 coap_packet_ptr->payload_ptr = 0; 00727 } 00728 00729 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_packet_ptr); 00730 return SN_NSDL_FAILURE; 00731 } 00732 00733 memcpy(response_message_hdr_ptr->payload_ptr, 00734 resource_temp_ptr->static_resource_parameters->resource, 00735 response_message_hdr_ptr->payload_len); 00736 } 00737 // Add max-age attribute for static resources. 00738 // Not a mandatory parameter, no need to return in case of memory allocation fails. 00739 if (static_get_request) { 00740 if (sn_coap_parser_alloc_options(handle->coap, response_message_hdr_ptr)) { 00741 response_message_hdr_ptr->options_list_ptr->max_age = 0; 00742 } 00743 } 00744 } 00745 sn_grs_send_coap_message(nsdl_handle, src_addr_ptr, response_message_hdr_ptr); 00746 00747 if (response_message_hdr_ptr->payload_ptr) { 00748 handle->sn_grs_free(response_message_hdr_ptr->payload_ptr); 00749 response_message_hdr_ptr->payload_ptr = 0; 00750 } 00751 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, response_message_hdr_ptr); 00752 } 00753 00754 /* Free parsed CoAP message */ 00755 if (coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr) { 00756 handle->sn_grs_free(coap_packet_ptr->payload_ptr); 00757 coap_packet_ptr->payload_ptr = 0; 00758 } 00759 sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_packet_ptr); 00760 00761 return SN_NSDL_SUCCESS; 00762 } 00763 00764 extern int8_t sn_grs_send_coap_message(struct nsdl_s *handle, sn_nsdl_addr_s *address_ptr, sn_coap_hdr_s *coap_hdr_ptr) 00765 { 00766 tr_debug("sn_grs_send_coap_message"); 00767 uint8_t *message_ptr = NULL; 00768 uint16_t message_len = 0; 00769 uint8_t ret_val = 0; 00770 00771 if( !handle ){ 00772 return SN_NSDL_FAILURE; 00773 } 00774 00775 #if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE /* If Message blockwising is not used at all, this part of code will not be compiled */ 00776 ret_val = prepare_blockwise_message(handle->grs->coap, coap_hdr_ptr); 00777 if( 0 != ret_val ) { 00778 return SN_NSDL_FAILURE; 00779 } 00780 #endif 00781 00782 /* Calculate message length */ 00783 message_len = sn_coap_builder_calc_needed_packet_data_size_2(coap_hdr_ptr, handle->grs->coap->sn_coap_block_data_size); 00784 tr_debug("sn_grs_send_coap_message - msg len after calc: [%d]", message_len); 00785 tr_debug("sn_grs_send_coap_message - msg id: [%d]", coap_hdr_ptr->msg_id); 00786 00787 /* Allocate memory for message and check was allocating successfully */ 00788 message_ptr = handle->grs->sn_grs_alloc(message_len); 00789 if (message_ptr == NULL) { 00790 return SN_NSDL_FAILURE; 00791 } 00792 00793 /* Build CoAP message */ 00794 if (sn_coap_protocol_build(handle->grs->coap, address_ptr, message_ptr, coap_hdr_ptr, (void *)handle) < 0) { 00795 handle->grs->sn_grs_free(message_ptr); 00796 message_ptr = 0; 00797 return SN_NSDL_FAILURE; 00798 } 00799 00800 /* Call tx callback function to send message */ 00801 ret_val = handle->grs->sn_grs_tx_callback(handle, SN_NSDL_PROTOCOL_COAP, message_ptr, message_len, address_ptr); 00802 00803 /* Free allocated memory */ 00804 handle->grs->sn_grs_free(message_ptr); 00805 message_ptr = 0; 00806 00807 if (ret_val == 0) { 00808 return SN_NSDL_FAILURE; 00809 } else { 00810 return SN_NSDL_SUCCESS; 00811 } 00812 } 00813 00814 static int8_t sn_grs_core_request(struct nsdl_s *handle, sn_nsdl_addr_s *src_addr_ptr, sn_coap_hdr_s *coap_packet_ptr) 00815 { 00816 sn_coap_hdr_s *response_message_hdr_ptr = NULL; 00817 sn_coap_content_format_e wellknown_content_format = COAP_CT_LINK_FORMAT; 00818 00819 /* Allocate response message */ 00820 response_message_hdr_ptr = sn_coap_parser_alloc_message(handle->grs->coap); 00821 if (response_message_hdr_ptr == NULL) { 00822 if (coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr) { 00823 handle->grs->sn_grs_free(coap_packet_ptr->payload_ptr); 00824 coap_packet_ptr->payload_ptr = 0; 00825 } 00826 sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, coap_packet_ptr); 00827 return SN_NSDL_FAILURE; 00828 } 00829 00830 /* Build response */ 00831 response_message_hdr_ptr->msg_code = COAP_MSG_CODE_RESPONSE_CONTENT; 00832 response_message_hdr_ptr->msg_type = COAP_MSG_TYPE_ACKNOWLEDGEMENT; 00833 response_message_hdr_ptr->msg_id = coap_packet_ptr->msg_id; 00834 response_message_hdr_ptr->content_format = wellknown_content_format; 00835 00836 sn_nsdl_build_registration_body(handle, response_message_hdr_ptr, 0); 00837 00838 /* Send and free */ 00839 sn_grs_send_coap_message(handle, src_addr_ptr, response_message_hdr_ptr); 00840 00841 if (response_message_hdr_ptr->payload_ptr) { 00842 handle->grs->sn_grs_free(response_message_hdr_ptr->payload_ptr); 00843 response_message_hdr_ptr->payload_ptr = 0; 00844 } 00845 sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, response_message_hdr_ptr); 00846 00847 /* Free parsed CoAP message */ 00848 if (coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr) { 00849 handle->grs->sn_grs_free(coap_packet_ptr->payload_ptr); 00850 coap_packet_ptr->payload_ptr = 0; 00851 } 00852 sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, coap_packet_ptr); 00853 00854 return SN_NSDL_SUCCESS; 00855 } 00856 00857 /** 00858 * \fn static sn_grs_resource_info_s *sn_grs_search_resource(uint16_t pathlen, uint8_t *path, uint8_t search_method) 00859 * 00860 * \brief Searches given resource from linked list 00861 * 00862 * Search either precise path, or subresources, eg. dr/x -> returns dr/x/1, dr/x/2 etc... 00863 * 00864 * \param pathlen Length of the path to be search 00865 * 00866 * \param *path Pointer to the path string to be search 00867 * 00868 * \param search_method Search method, SEARCH or DELETE 00869 * 00870 * \return Pointer to the resource. If resource not found, return value is NULL 00871 * 00872 */ 00873 00874 sn_nsdl_dynamic_resource_parameters_s *sn_grs_search_resource(struct grs_s *handle, uint16_t pathlen, uint8_t *path, uint8_t search_method) 00875 { 00876 /* Local variables */ 00877 uint8_t *path_temp_ptr = NULL; 00878 /* Check parameters */ 00879 if (!handle || !pathlen || !path) { 00880 return NULL; 00881 } 00882 00883 /* Remove '/' - marks from the end and beginning */ 00884 path_temp_ptr = sn_grs_convert_uri(&pathlen, path); 00885 00886 /* Searchs exact path */ 00887 if (search_method == SN_GRS_SEARCH_METHOD) { 00888 /* Scan all nodes on list */ 00889 ns_list_foreach(sn_nsdl_dynamic_resource_parameters_s, resource_search_temp, &handle->resource_root_list) { 00890 /* If length equals.. */ 00891 if (resource_search_temp->static_resource_parameters->pathlen == pathlen) { 00892 /* Compare paths, If same return node pointer*/ 00893 if (0 == memcmp(resource_search_temp->static_resource_parameters->path, 00894 path_temp_ptr, 00895 pathlen)) { 00896 return resource_search_temp; 00897 } 00898 } 00899 } 00900 } 00901 /* Search also subresources, eg. dr/x -> returns dr/x/1, dr/x/2 etc... */ 00902 else if (search_method == SN_GRS_DELETE_METHOD) { 00903 /* Scan all nodes on list */ 00904 ns_list_foreach(sn_nsdl_dynamic_resource_parameters_s, resource_search_temp, &handle->resource_root_list) { 00905 uint8_t *temp_path = resource_search_temp->static_resource_parameters->path; 00906 if (resource_search_temp->static_resource_parameters->pathlen > pathlen && 00907 (*(temp_path + (uint8_t)pathlen) == '/') && 00908 0 == memcmp(resource_search_temp->static_resource_parameters->path, 00909 path_temp_ptr, 00910 pathlen)) { 00911 return resource_search_temp; 00912 } 00913 } 00914 } 00915 00916 /* If there was not nodes we wanted, return NULL */ 00917 return NULL; 00918 } 00919 00920 /** 00921 * \fn static uint8_t *sn_grs_convert_uri(uint16_t *uri_len, uint8_t *uri_ptr) 00922 * 00923 * \brief Removes '/' from the beginning and from the end of uri string 00924 * 00925 * \param *uri_len Pointer to the length of the path string 00926 * 00927 * \param *uri_ptr Pointer to the path string 00928 * 00929 * \return start pointer of the uri 00930 * 00931 */ 00932 00933 static uint8_t *sn_grs_convert_uri(uint16_t *uri_len, uint8_t *uri_ptr) 00934 { 00935 /* Local variables */ 00936 uint8_t *uri_start_ptr = uri_ptr; 00937 00938 /* If '/' in the beginning, update uri start pointer and uri len */ 00939 if (*uri_ptr == '/') { 00940 uri_start_ptr = uri_ptr + 1; 00941 *uri_len = *uri_len - 1; 00942 } 00943 00944 /* If '/' at the end, update uri len */ 00945 if (*(uri_start_ptr + *uri_len - 1) == '/') { 00946 *uri_len = *uri_len - 1; 00947 } 00948 00949 /* Return start pointer */ 00950 return uri_start_ptr; 00951 } 00952 00953 /** 00954 * \fn static int8_t sn_grs_resource_info_free(sn_grs_resource_info_s *resource_ptr) 00955 * 00956 * \brief Frees resource info structure 00957 * 00958 * \param *resource_ptr Pointer to the resource 00959 * 00960 * \return 0 if success, -1 if failed 00961 * 00962 */ 00963 static int8_t sn_grs_resource_info_free(struct grs_s *handle, sn_nsdl_dynamic_resource_parameters_s *resource_ptr) 00964 { 00965 if (resource_ptr) { 00966 #ifdef MEMORY_OPTIMIZED_API 00967 if (resource_ptr->free_on_delete) { 00968 handle->sn_grs_free(resource_ptr); 00969 } 00970 return SN_NSDL_FAILURE; 00971 #else 00972 if (resource_ptr->static_resource_parameters && 00973 resource_ptr->static_resource_parameters->free_on_delete) { 00974 if (resource_ptr->static_resource_parameters->interface_description_ptr) { 00975 handle->sn_grs_free(resource_ptr->static_resource_parameters->interface_description_ptr); 00976 resource_ptr->static_resource_parameters->interface_description_ptr = 0; 00977 } 00978 00979 if (resource_ptr->static_resource_parameters->resource_type_ptr) { 00980 handle->sn_grs_free(resource_ptr->static_resource_parameters->resource_type_ptr); 00981 resource_ptr->static_resource_parameters->resource_type_ptr = 0; 00982 } 00983 00984 if (resource_ptr->static_resource_parameters->path) { 00985 handle->sn_grs_free(resource_ptr->static_resource_parameters->path); 00986 resource_ptr->static_resource_parameters->path = 0; 00987 } 00988 00989 if (resource_ptr->static_resource_parameters->resource) { 00990 handle->sn_grs_free(resource_ptr->static_resource_parameters->resource); 00991 resource_ptr->static_resource_parameters->resource = 0; 00992 } 00993 00994 handle->sn_grs_free(resource_ptr->static_resource_parameters); 00995 resource_ptr->static_resource_parameters = 0; 00996 } 00997 if (resource_ptr->free_on_delete) { 00998 handle->sn_grs_free(resource_ptr); 00999 } 01000 return SN_NSDL_SUCCESS; 01001 #endif 01002 } 01003 return SN_NSDL_FAILURE; //Dead code? 01004 } 01005 01006 void sn_grs_mark_resources_as_registered(struct nsdl_s *handle) 01007 { 01008 if( !handle ){ 01009 return; 01010 } 01011 01012 sn_nsdl_dynamic_resource_parameters_s *temp_resource; 01013 01014 temp_resource = sn_grs_get_first_resource(handle->grs); 01015 01016 while (temp_resource) { 01017 if (temp_resource->registered == SN_NDSL_RESOURCE_REGISTERING) { 01018 temp_resource->registered = SN_NDSL_RESOURCE_REGISTERED; 01019 } 01020 temp_resource = sn_grs_get_next_resource(handle->grs, temp_resource); 01021 } 01022 } 01023 #endif
Generated on Tue Jul 12 2022 11:02:51 by
