/*----------------------------------------------------------------------------*/ void coap_separate_resume(void *response, coap_separate_t *separate_store, uint8_t code) { coap_init_message(response, separate_store->type, code, separate_store->mid); if(separate_store->token_len) { coap_set_token(response, separate_store->token, separate_store->token_len); } if(separate_store->block1_size) { coap_set_header_block1(response, separate_store->block1_num, 0, separate_store->block1_size); } }
static void res_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { coap_packet_t *const coap_req = (coap_packet_t *)request; uint8_t *incoming = NULL; size_t len = 0; unsigned int ct = -1; if(!REST.get_header_content_type(request, &ct)) { REST.set_response_status(response, REST.status.BAD_REQUEST); const char *error_msg = "NoContentType"; REST.set_response_payload(response, error_msg, strlen(error_msg)); return; } if((len = REST.get_request_payload(request, (const uint8_t **)&incoming))) { if(coap_req->block1_num * coap_req->block1_size + len <= sizeof(large_update_store)) { memcpy( large_update_store + coap_req->block1_num * coap_req->block1_size, incoming, len); large_update_size = coap_req->block1_num * coap_req->block1_size + len; large_update_ct = ct; REST.set_response_status(response, REST.status.CHANGED); coap_set_header_block1(response, coap_req->block1_num, 0, coap_req->block1_size); } else { REST.set_response_status(response, REST.status.REQUEST_ENTITY_TOO_LARGE); REST.set_response_payload( response, buffer, snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "%uB max.", sizeof(large_update_store))); return; } } else { REST.set_response_status(response, REST.status.BAD_REQUEST); const char *error_msg = "NoPayload"; REST.set_response_payload(response, error_msg, strlen(error_msg)); return; } }
/** * \brief Block 1 support within a coap-ressource * * This function will help you to use block 1. If target is null * error handling and response configuration is active. On return * value 0, the last block was recived, while on return value 1 * more blocks will follow. With target, len and maxlen this * function will assemble the blocks. * * You can find an example in: * examples/er-rest-example/resources/res-b1-sep-b2.c * * \param request Request pointer from the handler * \param response Response pointer from the handler * \param target Pointer to the buffer where the request payload can be assembled * \param len Pointer to the variable, where the function stores the actual length * \param max_len Length of the "target"-Buffer * * \return 0 if initialisation was successful * -1 if initialisation failed */ int coap_block1_handler(void *request, void *response, uint8_t *target, size_t *len, size_t max_len) { const uint8_t *payload = 0; int pay_len = REST.get_request_payload(request, &payload); if(!pay_len || !payload) { erbium_status_code = REST.status.BAD_REQUEST; coap_error_message = "NoPayload"; return -1; } coap_packet_t *packet = (coap_packet_t *)request; if(packet->block1_offset + pay_len > max_len) { erbium_status_code = REST.status.REQUEST_ENTITY_TOO_LARGE; coap_error_message = "Message to big"; return -1; } if(target && len) { memcpy(target + packet->block1_offset, payload, pay_len); *len = packet->block1_offset + pay_len; } if(IS_OPTION(packet, COAP_OPTION_BLOCK1)) { PRINTF("Blockwise: block 1 request: Num: %u, More: %u, Size: %u, Offset: %u\n", packet->block1_num, packet->block1_more, packet->block1_size, packet->block1_offset); coap_set_header_block1(response, packet->block1_num, packet->block1_more, packet->block1_size); if(packet->block1_more) { coap_set_status_code(response, CONTINUE_2_31); return 1; } } return 0; }
void large_create_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { coap_packet_t *const coap_req = (coap_packet_t *) request; uint8_t *incoming = NULL; size_t len = 0; unsigned int ct = REST.get_header_content_type(request); if (ct==-1) { REST.set_response_status(response, REST.status.BAD_REQUEST); const char *error_msg = "NoContentType"; REST.set_response_payload(response, error_msg, strlen(error_msg)); return; } if ((len = REST.get_request_payload(request, &incoming))) { if (coap_req->block1_num*coap_req->block1_size+len <= 2048) { REST.set_response_status(response, REST.status.CREATED); REST.set_header_location(response, "/nirvana"); coap_set_header_block1(response, coap_req->block1_num, 0, coap_req->block1_size); } else { REST.set_response_status(response, REST.status.REQUEST_ENTITY_TOO_LARGE); const char *error_msg = "2048B max."; REST.set_response_payload(response, error_msg, strlen(error_msg)); return; } } else { REST.set_response_status(response, REST.status.BAD_REQUEST); const char *error_msg = "NoPayload"; REST.set_response_payload(response, error_msg, strlen(error_msg)); return; } }
void mirror_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { /* The ETag and Token is copied to the header. */ uint8_t opaque[] = {0x0A, 0xBC, 0xDE}; /* Strings are not copied, so use static string buffers or strings in .text memory (char *str = "string in .text";). */ static char location[] = {'/','f','/','a','?','k','&','e', 0}; /* Getter for the header option Content-Type. If the option is not set, text/plain is returned by default. */ unsigned int content_type = REST.get_header_content_type(request); /* The other getters copy the value (or string/array pointer) to the given pointers and return 1 for success or the length of strings/arrays. */ uint32_t max_age_and_size = 0; const char *str = NULL; uint32_t observe = 0; const uint8_t *bytes = NULL; uint32_t block_num = 0; uint8_t block_more = 0; uint16_t block_size = 0; const char *query = ""; int len = 0; /* Mirror the received header options in the response payload. Unsupported getters (e.g., rest_get_header_observe() with HTTP) will return 0. */ int strpos = 0; /* snprintf() counts the terminating '\0' to the size parameter. * The additional byte is taken care of by allocating REST_MAX_CHUNK_SIZE+1 bytes in the REST framework. * Add +1 to fill the complete buffer, as the payload does not need a terminating '\0'. */ if (content_type!=-1) { strpos += snprintf((char *)buffer, REST_MAX_CHUNK_SIZE+1, "CT %u\n", content_type); } /* Some getters such as for ETag or Location are omitted, as these options should not appear in a request. * Max-Age might appear in HTTP requests or used for special purposes in CoAP. */ if (strpos<=REST_MAX_CHUNK_SIZE && REST.get_header_max_age(request, &max_age_and_size)) { strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "MA %lu\n", max_age_and_size); } /* For HTTP this is the Length option, for CoAP it is the Size option. */ if (strpos<=REST_MAX_CHUNK_SIZE && REST.get_header_length(request, &max_age_and_size)) { strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "SZ %lu\n", max_age_and_size); } if (strpos<=REST_MAX_CHUNK_SIZE && (len = REST.get_header_host(request, &str))) { strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "UH %.*s\n", len, str); } /* CoAP-specific example: actions not required for normal RESTful Web service. */ #if WITH_COAP > 1 if (strpos<=REST_MAX_CHUNK_SIZE && coap_get_header_observe(request, &observe)) { strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "Ob %lu\n", observe); } if (strpos<=REST_MAX_CHUNK_SIZE && (len = coap_get_header_token(request, &bytes))) { strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "To 0x"); int index = 0; for (index = 0; index<len; ++index) { strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "%02X", bytes[index]); } strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "\n"); } if (strpos<=REST_MAX_CHUNK_SIZE && (len = coap_get_header_etag(request, &bytes))) { strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "ET 0x"); int index = 0; for (index = 0; index<len; ++index) { strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "%02X", bytes[index]); } strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "\n"); } if (strpos<=REST_MAX_CHUNK_SIZE && (len = coap_get_header_uri_path(request, &str))) { strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "UP "); strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "%.*s\n", len, str); } #if WITH_COAP == 3 if (strpos<=REST_MAX_CHUNK_SIZE && (len = coap_get_header_location(request, &str))) { strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "Lo %.*s\n", len, str); } if (strpos<=REST_MAX_CHUNK_SIZE && coap_get_header_block(request, &block_num, &block_more, &block_size, NULL)) /* This getter allows NULL pointers to get only a subset of the block parameters. */ { strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "Bl %lu%s (%u)\n", block_num, block_more ? "+" : "", block_size); } #else if (strpos<=REST_MAX_CHUNK_SIZE && (len = coap_get_header_location_path(request, &str))) { strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "LP %.*s\n", len, str); } if (strpos<=REST_MAX_CHUNK_SIZE && (len = coap_get_header_location_query(request, &str))) { strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "LQ %.*s\n", len, str); } if (strpos<=REST_MAX_CHUNK_SIZE && coap_get_header_block2(request, &block_num, &block_more, &block_size, NULL)) /* This getter allows NULL pointers to get only a subset of the block parameters. */ { strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "B2 %lu%s (%u)\n", block_num, block_more ? "+" : "", block_size); } /* * Critical Block1 option is currently rejected by engine. * if (strpos<=REST_MAX_CHUNK_SIZE && coap_get_header_block1(request, &block_num, &block_more, &block_size, NULL)) { strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "B1 %lu%s (%u)\n", block_num, block_more ? "+" : "", block_size); } */ #endif /* CoAP > 03 */ #endif /* CoAP-specific example */ if (strpos<=REST_MAX_CHUNK_SIZE && (len = REST.get_query(request, &query))) { strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "Qu %.*s\n", len, query); } if (strpos<=REST_MAX_CHUNK_SIZE && (len = REST.get_request_payload(request, &bytes))) { strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "%.*s", len, bytes); } if (strpos >= REST_MAX_CHUNK_SIZE) { buffer[REST_MAX_CHUNK_SIZE-1] = 0xBB; /* '»' to indicate truncation */ } REST.set_response_payload(response, buffer, strpos); PRINTF("/mirror options received: %s\n", buffer); /* Set dummy header options for response. Like getters, some setters are not implemented for HTTP and have no effect. */ REST.set_header_content_type(response, REST.type.TEXT_PLAIN); REST.set_header_max_age(response, 17); /* For HTTP, browsers will not re-request the page for 17 seconds. */ REST.set_header_etag(response, opaque, 2); REST.set_header_location(response, location); /* Initial slash is omitted by framework */ REST.set_header_length(response, strpos); /* For HTTP, browsers will not re-request the page for 10 seconds. CoAP action depends on the client. */ /* CoAP-specific example: actions not required for normal RESTful Web service. */ #if WITH_COAP > 1 coap_set_header_uri_host(response, "tiki"); coap_set_header_observe(response, 10); #if WITH_COAP == 3 coap_set_header_block(response, 42, 0, 64); /* The block option might be overwritten by the framework when blockwise transfer is requested. */ #else coap_set_header_proxy_uri(response, "ftp://x"); coap_set_header_block2(response, 42, 0, 64); /* The block option might be overwritten by the framework when blockwise transfer is requested. */ coap_set_header_block1(response, 23, 0, 16); coap_set_header_accept(response, TEXT_PLAIN); coap_set_header_if_none_match(response); #endif /* CoAP > 03 */ #endif /* CoAP-specific example */ }
/* This function is an adaptation of function coap_receive() from Erbium's er-coap-13-engine.c. * Erbium is Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich * All rights reserved. */ void lwm2m_handle_packet(lwm2m_context_t * contextP, uint8_t * buffer, int length, void * fromSessionH) { uint8_t coap_error_code = NO_ERROR; static coap_packet_t message[1]; static coap_packet_t response[1]; LOG("Entering"); coap_error_code = coap_parse_message(message, buffer, (uint16_t)length); if (coap_error_code == NO_ERROR) { LOG_ARG("Parsed: ver %u, type %u, tkl %u, code %u.%.2u, mid %u, Content type: %d", message->version, message->type, message->token_len, message->code >> 5, message->code & 0x1F, message->mid, message->content_type); LOG_ARG("Payload: %.*s", message->payload_len, message->payload); if (message->code >= COAP_GET && message->code <= COAP_DELETE) { uint32_t block_num = 0; uint16_t block_size = REST_MAX_CHUNK_SIZE; uint32_t block_offset = 0; int64_t new_offset = 0; /* prepare response */ if (message->type == COAP_TYPE_CON) { /* Reliable CON requests are answered with an ACK. */ coap_init_message(response, COAP_TYPE_ACK, COAP_205_CONTENT, message->mid); } else { /* Unreliable NON requests are answered with a NON as well. */ coap_init_message(response, COAP_TYPE_NON, COAP_205_CONTENT, contextP->nextMID++); } /* mirror token */ if (message->token_len) { coap_set_header_token(response, message->token, message->token_len); } /* get offset for blockwise transfers */ if (coap_get_header_block2(message, &block_num, NULL, &block_size, &block_offset)) { LOG_ARG("Blockwise: block request %u (%u/%u) @ %u bytes", block_num, block_size, REST_MAX_CHUNK_SIZE, block_offset); block_size = MIN(block_size, REST_MAX_CHUNK_SIZE); new_offset = block_offset; } /* handle block1 option */ if (IS_OPTION(message, COAP_OPTION_BLOCK1)) { #ifdef LWM2M_CLIENT_MODE // get server lwm2m_server_t * serverP; serverP = utils_findServer(contextP, fromSessionH); #ifdef LWM2M_BOOTSTRAP if (serverP == NULL) { serverP = utils_findBootstrapServer(contextP, fromSessionH); } #endif if (serverP == NULL) { coap_error_code = COAP_500_INTERNAL_SERVER_ERROR; } else { uint32_t block1_num; uint8_t block1_more; uint16_t block1_size; uint8_t * complete_buffer = NULL; size_t complete_buffer_size; // parse block1 header coap_get_header_block1(message, &block1_num, &block1_more, &block1_size, NULL); LOG_ARG("Blockwise: block1 request NUM %u (SZX %u/ SZX Max%u) MORE %u", block1_num, block1_size, REST_MAX_CHUNK_SIZE, block1_more); // handle block 1 coap_error_code = coap_block1_handler(&serverP->block1Data, message->mid, message->payload, message->payload_len, block1_size, block1_num, block1_more, &complete_buffer, &complete_buffer_size); // if payload is complete, replace it in the coap message. if (coap_error_code == NO_ERROR) { message->payload = complete_buffer; message->payload_len = complete_buffer_size; } else if (coap_error_code == COAP_231_CONTINUE) { block1_size = MIN(block1_size, REST_MAX_CHUNK_SIZE); coap_set_header_block1(response,block1_num, block1_more,block1_size); } } #else coap_error_code = COAP_501_NOT_IMPLEMENTED; #endif } if (coap_error_code == NO_ERROR) { coap_error_code = handle_request(contextP, fromSessionH, message, response); } if (coap_error_code==NO_ERROR) { /* Save original payload pointer for later freeing. Payload in response may be updated. */ uint8_t *payload = response->payload; if ( IS_OPTION(message, COAP_OPTION_BLOCK2) ) { /* unchanged new_offset indicates that resource is unaware of blockwise transfer */ if (new_offset==block_offset) { LOG_ARG("Blockwise: unaware resource with payload length %u/%u", response->payload_len, block_size); if (block_offset >= response->payload_len) { LOG("handle_incoming_data(): block_offset >= response->payload_len"); response->code = COAP_402_BAD_OPTION; coap_set_payload(response, "BlockOutOfScope", 15); /* a const char str[] and sizeof(str) produces larger code size */ } else { coap_set_header_block2(response, block_num, response->payload_len - block_offset > block_size, block_size); coap_set_payload(response, response->payload+block_offset, MIN(response->payload_len - block_offset, block_size)); } /* if (valid offset) */ } else { /* resource provides chunk-wise data */ LOG_ARG("Blockwise: blockwise resource, new offset %d", (int) new_offset); coap_set_header_block2(response, block_num, new_offset!=-1 || response->payload_len > block_size, block_size); if (response->payload_len > block_size) coap_set_payload(response, response->payload, block_size); } /* if (resource aware of blockwise) */ } else if (new_offset!=0) { LOG_ARG("Blockwise: no block option for blockwise resource, using block size %u", REST_MAX_CHUNK_SIZE); coap_set_header_block2(response, 0, new_offset!=-1, REST_MAX_CHUNK_SIZE); coap_set_payload(response, response->payload, MIN(response->payload_len, REST_MAX_CHUNK_SIZE)); } /* if (blockwise request) */ coap_error_code = message_send(contextP, response, fromSessionH); lwm2m_free(payload); response->payload = NULL; response->payload_len = 0; } else if (coap_error_code != COAP_IGNORE) { if (1 == coap_set_status_code(response, coap_error_code)) { coap_error_code = message_send(contextP, response, fromSessionH); } } } else { /* Responses */ switch (message->type) { case COAP_TYPE_NON: case COAP_TYPE_CON: { bool done = transaction_handleResponse(contextP, fromSessionH, message, response); #ifdef LWM2M_SERVER_MODE if (!done && IS_OPTION(message, COAP_OPTION_OBSERVE) && ((message->code == COAP_204_CHANGED) || (message->code == COAP_205_CONTENT))) { done = observe_handleNotify(contextP, fromSessionH, message, response); } #endif if (!done && message->type == COAP_TYPE_CON ) { coap_init_message(response, COAP_TYPE_ACK, 0, message->mid); coap_error_code = message_send(contextP, response, fromSessionH); } } break; case COAP_TYPE_RST: /* Cancel possible subscriptions. */ handle_reset(contextP, fromSessionH, message); transaction_handleResponse(contextP, fromSessionH, message, NULL); break; case COAP_TYPE_ACK: transaction_handleResponse(contextP, fromSessionH, message, NULL); break; default: break; } } /* Request or Response */ coap_free_header(message); } /* if (parsed correctly) */
void large_update_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { coap_packet_t *const coap_req = (coap_packet_t *) request; uint8_t method = REST.get_method_type(request); if (method & METHOD_GET) { /* Check the offset for boundaries of the resource data. */ if (*offset>=large_update_size) { REST.set_response_status(response, REST.status.BAD_OPTION); /* A block error message should not exceed the minimum block size (16). */ const char *error_msg = "BlockOutOfScope"; REST.set_response_payload(response, error_msg, strlen(error_msg)); return; } REST.set_response_payload(response, large_update_store+*offset, preferred_size); REST.set_header_content_type(response, large_update_ct); /* IMPORTANT for chunk-wise resources: Signal chunk awareness to REST engine. */ *offset += preferred_size; /* Signal end of resource representation. */ if (*offset>=large_update_size) { *offset = -1; } } else { uint8_t *incoming = NULL; size_t len = 0; unsigned int ct = REST.get_header_content_type(request); if (ct==-1) { REST.set_response_status(response, REST.status.BAD_REQUEST); const char *error_msg = "NoContentType"; REST.set_response_payload(response, error_msg, strlen(error_msg)); return; } if ((len = REST.get_request_payload(request, &incoming))) { if (coap_req->block1_num*coap_req->block1_size+len <= sizeof(large_update_store)) { memcpy(large_update_store+coap_req->block1_num*coap_req->block1_size, incoming, len); large_update_size = coap_req->block1_num*coap_req->block1_size+len; large_update_ct = REST.get_header_content_type(request); REST.set_response_status(response, REST.status.CHANGED); coap_set_header_block1(response, coap_req->block1_num, 0, coap_req->block1_size); } else { REST.set_response_status(response, REST.status.REQUEST_ENTITY_TOO_LARGE); REST.set_response_payload(response, buffer, snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "%uB max.", sizeof(large_update_store))); return; } } else { REST.set_response_status(response, REST.status.BAD_REQUEST); const char *error_msg = "NoPayload"; REST.set_response_payload(response, error_msg, strlen(error_msg)); return; } } }
/*----------------------------------------------------------------------------*/ void pf_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset, tres_res_t *task) { rest_resource_flags_t method; uint32_t num = 0; uint8_t more = 0; uint16_t size = 0; uint32_t b1_offset = 0; uint16_t plen; const uint8_t *payload; method = REST.get_method_type(request); PRINTF("Method %d\n", method); switch (method) { case METHOD_GET: //TODO: retrieve python bytecode REST.set_response_status(response, REST.status.NOT_IMPLEMENTED); break; case METHOD_PUT: if(coap_get_header_block1(request, &num, &more, &size, &b1_offset)) { coap_set_header_block1(response, num, more, size); } PRINTF("Request on /pf: num = %"PRIu32", more = %"PRIu8", size = %"PRIu16 ", offset = %"PRIu32"\n", num, more, size, b1_offset); // if it's the first packet, stop input resource monitoring if(b1_offset == 0) { tres_stop_monitoring(task); // if the user is actually updating the PF, clear it first if(task->pf_img) { tres_mem_pf_clear(task->pf_img); task_reset_state(task); } } plen = coap_get_payload(request, &payload); PRINTF("Payload len: %d\n", plen); #if TRES_COPPER_WORKAROUND // if no block-wise transfer and payload len equal to maximum size, then // we probably need block wise transfer. FIXME: that may be not true if(size == 0 && plen == REST_MAX_CHUNK_SIZE) { more = 1; size = REST_MAX_CHUNK_SIZE; coap_set_header_block1(response, num, more, size); } #endif // if it's the first packet, allocate a memory slot if(b1_offset == 0) { // ... but, if the first byte is not 0x0a than it is not python bytecode if(payload[0] != 0x0a) { REST.set_response_status(response, REST.status.BAD_REQUEST); return; } task->sid = tres_mem_pf_store_start(); if(task->sid < 0) { PRINTF("No memory slot available\n"); // TODO: we should return a server error code return; } } // store the current block if(tres_mem_pf_store_step(task->sid, payload, plen) < 0) { PRINTF("PF too big\n"); return; } // if it's the final block, finalize the memory slot if(more == 0) { task->pf_img = tres_mem_pf_store_done(task->sid); PRINTF("task->pf_img: %p\n", task->pf_img); REST.set_response_status(response, REST.status.CHANGED); } break; case METHOD_POST: REST.set_response_status(response, REST.status.METHOD_NOT_ALLOWED); break; case METHOD_DELETE: if(task->pf_img) { tres_stop_monitoring(task); tres_mem_pf_clear(task->pf_img); task_reset_state(task); task->pf_img = NULL; } REST.set_response_status(response, REST.status.DELETED); break; default: break; } }
/*----------------------------------------------------------------------------*/ void tasks_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { const char *path; char name[TRES_TASK_NAME_MAX_LEN]; char subres[SUBRES_LEN]; int len; int retv; #if TRES_COPPER_WORKAROUND uint32_t num = 0; uint8_t more = 0; uint16_t size = 0; uint32_t b1_offset = 0; int i; tres_res_t *task; int32_t strpos = 0; int16_t bufpos = 0; if(coap_get_header_block1(request, &num, &more, &size, &b1_offset) && more == 0) { coap_set_header_block1(response, num, more, size); } #endif len = REST.get_url(request, &path); retv = parse_tasks_path(path, len, name, subres); if(retv < 0) { PRINTF("Invalid path: %d\n", retv); REST.set_response_status(response, REST.status.BAD_REQUEST); return; } if(*name) { PRINTF("name: %s\n", name); task_name_handler(request, response, buffer, preferred_size, offset, name, subres); return; } for(i = 0; i < tasks_mem.num; i++) { task = &tasks_mem_memb_mem[i]; if(task->name[0]) { /* </tasks/[task_name] */ if(strpos == 0) { BLOCK_SPRINTF("</" TRES_BASE_PATH "/", strpos, bufpos, offset, preferred_size, buffer); } else { BLOCK_SPRINTF(",</" TRES_BASE_PATH "/", strpos, bufpos, offset, preferred_size, buffer); } BLOCK_SPRINTF(task->name, strpos, bufpos, offset, preferred_size, buffer); BLOCK_SPRINTF(">;ct=40", strpos, bufpos, offset, preferred_size, buffer); } } REST.set_response_payload(response, buffer, bufpos); REST.set_header_content_type(response, APPLICATION_LINK_FORMAT); if(bufpos >= preferred_size || *offset > 0) { if(i == tasks_mem.num) { *offset = -1; } else { *offset += preferred_size; } } }