static coap_status_t handle_request(lwm2m_context_t * contextP, void * fromSessionH, coap_packet_t * message, coap_packet_t * response) { lwm2m_uri_t * uriP; coap_status_t result = NOT_FOUND_4_04; uriP = lwm2m_decode_uri(message->uri_path); if (uriP == NULL) return BAD_REQUEST_4_00; switch(uriP->flag & LWM2M_URI_MASK_TYPE) { #ifdef LWM2M_CLIENT_MODE case LWM2M_URI_FLAG_DM: // TODO: Authentify server result = handle_dm_request(contextP, uriP, fromSessionH, message, response); break; case LWM2M_URI_FLAG_BOOTSTRAP: result = NOT_IMPLEMENTED_5_01; break; #endif #ifdef LWM2M_SERVER_MODE case LWM2M_URI_FLAG_REGISTRATION: result = handle_registration_request(contextP, uriP, fromSessionH, message, response); break; #endif default: result = BAD_REQUEST_4_00; break; } coap_set_status_code(response, result); if (result < BAD_REQUEST_4_00) { result = NO_ERROR; } lwm2m_free( uriP); return result; }
/** * \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 well_known_core_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { size_t strpos = 0; /* position in overall string (which is larger than the buffer) */ size_t bufpos = 0; /* position within buffer (bytes written) */ size_t tmplen = 0; resource_t* resource = NULL; /* For filtering. */ const char *filter = NULL; int len = coap_get_query_variable(request, "rt", &filter); char *rt = NULL; for (resource = (resource_t*)list_head(rest_get_resources()); resource; resource = resource->next) { /* Filtering */ if (len && ((rt=strstr(resource->attributes, "rt=\""))==NULL || memcmp(rt+4, filter, len-1)!=0 || (filter[len-1]!='*' && (filter[len-1]!=rt[3+len] || rt[4+len]!='"')))) { continue; } PRINTF("res: /%s (%p)\npos: s%d, o%d, b%d\n", resource->url, resource, strpos, *offset, bufpos); if (strpos >= *offset && bufpos < preferred_size) { buffer[bufpos++] = '<'; } ++strpos; if (strpos >= *offset && bufpos < preferred_size) { buffer[bufpos++] = '/'; } ++strpos; tmplen = strlen(resource->url); if (strpos+tmplen > *offset) { bufpos += snprintf((char *) buffer + bufpos, preferred_size - bufpos + 1, "%s", resource->url + ((*offset-(int32_t)strpos > 0) ? (*offset-(int32_t)strpos) : 0)); /* minimal-net requires these casts */ if (bufpos >= preferred_size) { break; } } strpos += tmplen; if (strpos >= *offset && bufpos < preferred_size) { buffer[bufpos++] = '>'; } ++strpos; if (resource->attributes[0]) { if (strpos >= *offset && bufpos < preferred_size) { buffer[bufpos++] = ';'; } ++strpos; tmplen = strlen(resource->attributes); if (strpos+tmplen > *offset) { bufpos += snprintf((char *) buffer + bufpos, preferred_size - bufpos + 1, "%s", resource->attributes + (*offset-(int32_t)strpos > 0 ? *offset-(int32_t)strpos : 0)); if (bufpos >= preferred_size) { break; } } strpos += tmplen; } if (resource->next) { if (strpos >= *offset && bufpos < preferred_size) { buffer[bufpos++] = ','; } ++strpos; } /* buffer full, but resource not completed yet; or: do not break if resource exactly fills buffer. */ if (bufpos >= preferred_size && strpos-bufpos > *offset) { PRINTF("res: BREAK at %s (%p)\n", resource->url, resource); break; } } if (bufpos>0) { PRINTF("BUF %d: %.*s\n", bufpos, bufpos, (char *) buffer); coap_set_payload(response, buffer, bufpos ); coap_set_header_content_type(response, APPLICATION_LINK_FORMAT); } else if (strpos>0) { PRINTF("well_known_core_handler(): bufpos<=0\n"); coap_set_status_code(response, BAD_OPTION_4_02); coap_set_payload(response, "BlockOutOfScope", 15); } if (resource==NULL) { PRINTF("res: DONE\n"); *offset = -1; } else { PRINTF("res: MORE at %s (%p)\n", resource->url, resource); *offset += preferred_size; } }
void well_known_core_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { size_t strpos = 0; /* position in overall string (which is larger than the buffer) */ size_t bufpos = 0; /* position within buffer (bytes written) */ size_t tmplen = 0; resource_t* resource = NULL; #if COAP_LINK_FORMAT_FILTERING /* For filtering. */ const char *filter = NULL; const char *attrib = NULL; const char *found = NULL; const char *end = NULL; char *value = NULL; char lastchar = '\0'; int len = coap_get_header_uri_query(request, &filter); if (len) { value = strchr(filter, '='); value[0] = '\0'; ++value; len -= strlen(filter)+1; PRINTF("Filter %s = %.*s\n", filter, len, value); if (strcmp(filter,"href")==0 && value[0]=='/') { ++value; --len; } lastchar = value[len-1]; value[len-1] = '\0'; } #endif for (resource = (resource_t*)list_head(rest_get_resources()); resource; resource = resource->next) { #if COAP_LINK_FORMAT_FILTERING /* Filtering */ if (len) { if (strcmp(filter,"href")==0) { attrib=strstr(resource->url, value); if (attrib==NULL || (value[-1]=='/' && attrib!=resource->url)) continue; end = attrib + strlen(attrib); } else { attrib=strstr(resource->attributes, filter); if (attrib==NULL || (attrib[strlen(filter)]!='=' && attrib[strlen(filter)]!='"')) continue; attrib += strlen(filter)+2; end = strchr(attrib, '"'); } PRINTF("Filter: res has attrib %s (%s)\n", attrib, value); found = attrib; while ((found=strstr(found, value))!=NULL) { if (found > end) { found = NULL; break; } if (lastchar==found[len-1] || lastchar=='*') { break; } ++found; } if (found==NULL) { continue; } PRINTF("Filter: res has prefix %s\n", found); if (lastchar!='*' && (found[len]!='"' && found[len]!=' ' && found[len]!='\0')) continue; PRINTF("Filter: res has match\n"); } #endif PRINTF("res: /%s (%p)\npos: s%d, o%ld, b%d\n", resource->url, resource, strpos, *offset, bufpos); if (strpos>0) { if (strpos >= *offset && bufpos < preferred_size) { buffer[bufpos++] = ','; } ++strpos; } if (strpos >= *offset && bufpos < preferred_size) { buffer[bufpos++] = '<'; } ++strpos; if (strpos >= *offset && bufpos < preferred_size) { buffer[bufpos++] = '/'; } ++strpos; tmplen = strlen(resource->url); if (strpos+tmplen > *offset) { bufpos += snprintf((char *) buffer + bufpos, preferred_size - bufpos + 1, "%s", resource->url + ((*offset-(int32_t)strpos > 0) ? (*offset-(int32_t)strpos) : 0)); /* minimal-net requires these casts */ if (bufpos >= preferred_size) { break; } } strpos += tmplen; if (strpos >= *offset && bufpos < preferred_size) { buffer[bufpos++] = '>'; } ++strpos; if (resource->attributes[0]) { if (strpos >= *offset && bufpos < preferred_size) { buffer[bufpos++] = ';'; } ++strpos; tmplen = strlen(resource->attributes); if (strpos+tmplen > *offset) { bufpos += snprintf((char *) buffer + bufpos, preferred_size - bufpos + 1, "%s", resource->attributes + (*offset-(int32_t)strpos > 0 ? *offset-(int32_t)strpos : 0)); if (bufpos >= preferred_size) { break; } } strpos += tmplen; } /* buffer full, but resource not completed yet; or: do not break if resource exactly fills buffer. */ if (bufpos >= preferred_size && strpos-bufpos > *offset) { PRINTF("res: BREAK at %s (%p)\n", resource->url, resource); break; } } if (bufpos>0) { PRINTF("BUF %d: %.*s\n", bufpos, bufpos, (char *) buffer); coap_set_payload(response, buffer, bufpos ); coap_set_header_content_type(response, APPLICATION_LINK_FORMAT); } else if (strpos>0) { PRINTF("well_known_core_handler(): bufpos<=0\n"); coap_set_status_code(response, BAD_OPTION_4_02); coap_set_payload(response, "BlockOutOfScope", 15); } if (resource==NULL) { PRINTF("res: DONE\n"); *offset = -1; } else { PRINTF("res: MORE at %s (%p)\n", resource->url, resource); *offset += preferred_size; } }
/* 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) */
static uint8_t handle_request(lwm2m_context_t * contextP, void * fromSessionH, coap_packet_t * message, coap_packet_t * response) { lwm2m_uri_t uri; lwm2m_request_type_t requestType; uint8_t result = COAP_IGNORE; LOG("Entering"); #ifdef LWM2M_CLIENT_MODE requestType = uri_decode(contextP->altPath, message->uri_path, &uri); #else requestType = uri_decode(NULL, message->uri_path, &uri); #endif switch(requestType) { case LWM2M_REQUEST_TYPE_UNKNOWN: return COAP_400_BAD_REQUEST; #ifdef LWM2M_CLIENT_MODE case LWM2M_REQUEST_TYPE_DM: { lwm2m_server_t * serverP; serverP = utils_findServer(contextP, fromSessionH); if (serverP != NULL) { result = dm_handleRequest(contextP, &uri, serverP, message, response); } #ifdef LWM2M_BOOTSTRAP else { serverP = utils_findBootstrapServer(contextP, fromSessionH); if (serverP != NULL) { result = bootstrap_handleCommand(contextP, &uri, serverP, message, response); } } #endif } break; #ifdef LWM2M_BOOTSTRAP case LWM2M_REQUEST_TYPE_DELETE_ALL: if (COAP_DELETE != message->code) { result = COAP_400_BAD_REQUEST; } else { result = bootstrap_handleDeleteAll(contextP, fromSessionH); } break; case LWM2M_REQUEST_TYPE_BOOTSTRAP: if (message->code == COAP_POST) { result = bootstrap_handleFinish(contextP, fromSessionH); } break; #endif #endif #ifdef LWM2M_SERVER_MODE case LWM2M_REQUEST_TYPE_REGISTRATION: result = registration_handleRequest(contextP, &uri, fromSessionH, message, response); break; #endif #ifdef LWM2M_BOOTSTRAP_SERVER_MODE case LWM2M_REQUEST_TYPE_BOOTSTRAP: result = bootstrap_handleRequest(contextP, &uri, fromSessionH, message, response); break; #endif default: result = COAP_IGNORE; break; } coap_set_status_code(response, result); if (COAP_IGNORE < result && result < COAP_400_BAD_REQUEST) { result = NO_ERROR; } return result; }
/* 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) { coap_status_t coap_error_code = NO_ERROR; static coap_packet_t message[1]; static coap_packet_t response[1]; coap_error_code = coap_parse_message(message, buffer, (uint16_t)length); if (message[0].uri_path && message[0].uri_path->next && (message[0].uri_path->next->is_static != 0 && message[0].uri_path->next->is_static != 1)) { printf("BLA\n"); } if (coap_error_code == NO_ERROR) { LOG(" Parsed: ver %u, type %u, tkl %u, code %u.%.2u, mid %u\r\n", message->version, message->type, message->token_len, message->code >> 5, message->code & 0x1F, message->mid); LOG(" Content type: %d\r\n Payload: %.*s\r\n\n", message->content_type, 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("Blockwise: block request %u (%u/%u) @ %u bytes\n", block_num, block_size, REST_MAX_CHUNK_SIZE, block_offset); block_size = MIN(block_size, REST_MAX_CHUNK_SIZE); new_offset = block_offset; } coap_error_code = handle_request(contextP, fromSessionH, message, response); if (coap_error_code==NO_ERROR) { /* Apply blockwise transfers. */ if ( IS_OPTION(message, COAP_OPTION_BLOCK1) && response->code<COAP_400_BAD_REQUEST && !IS_OPTION(response, COAP_OPTION_BLOCK1) ) { LOG("Block1 NOT IMPLEMENTED\n"); coap_error_code = COAP_501_NOT_IMPLEMENTED; coap_error_message = "NoBlock1Support"; } else if ( IS_OPTION(message, COAP_OPTION_BLOCK2) ) { /* unchanged new_offset indicates that resource is unaware of blockwise transfer */ if (new_offset==block_offset) { LOG("Blockwise: unaware resource with payload length %u/%u\n", response->payload_len, block_size); if (block_offset >= response->payload_len) { LOG("handle_incoming_data(): block_offset >= response->payload_len\n"); 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("Blockwise: blockwise resource, new offset %d\n", (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("Blockwise: no block option for blockwise resource, using block size %u\n", 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(response->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) */
static coap_status_t handle_request(lwm2m_context_t * contextP, void * fromSessionH, coap_packet_t * message, coap_packet_t * response) { lwm2m_uri_t * uriP; coap_status_t result = COAP_IGNORE; #ifdef LWM2M_CLIENT_MODE uriP = uri_decode(contextP->altPath, message->uri_path); #else uriP = uri_decode(NULL, message->uri_path); #endif if (uriP == NULL) return COAP_400_BAD_REQUEST; switch(uriP->flag & LWM2M_URI_MASK_TYPE) { #ifdef LWM2M_CLIENT_MODE case LWM2M_URI_FLAG_DM: { lwm2m_server_t * serverP; serverP = utils_findServer(contextP, fromSessionH); if (serverP != NULL) { result = dm_handleRequest(contextP, uriP, serverP, message, response); } #ifdef LWM2M_BOOTSTRAP else { serverP = utils_findBootstrapServer(contextP, fromSessionH); if (serverP != NULL) { result = bootstrap_handleCommand(contextP, uriP, serverP, message, response); } } #endif } break; #ifdef LWM2M_BOOTSTRAP case LWM2M_URI_FLAG_DELETE_ALL: if (COAP_DELETE != message->code) { result = COAP_400_BAD_REQUEST; } else { result = bootstrap_handleDeleteAll(contextP, fromSessionH); } break; case LWM2M_URI_FLAG_BOOTSTRAP: if (message->code == COAP_POST) { result = bootstrap_handleFinish(contextP, fromSessionH); } break; #endif #endif #ifdef LWM2M_SERVER_MODE case LWM2M_URI_FLAG_REGISTRATION: result = registration_handleRequest(contextP, uriP, fromSessionH, message, response); break; #endif #ifdef LWM2M_BOOTSTRAP_SERVER_MODE case LWM2M_URI_FLAG_BOOTSTRAP: result = bootstrap_handleRequest(contextP, uriP, fromSessionH, message, response); break; #endif default: result = COAP_IGNORE; break; } coap_set_status_code(response, result); if (COAP_IGNORE < result && result < COAP_400_BAD_REQUEST) { result = NO_ERROR; } lwm2m_free(uriP); return result; }
static int coap_HandleRequest(void *packet, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { int result = 1; const char *url = NULL; int urlLen = 0; const uint8_t * payload = NULL; int payloadLen = 0; int content = -1; coap_packet_t * const request = (coap_packet_t *) packet; CoapResponse coapResponse = { .responseContent = buffer, .responseContentLen = preferred_size, .responseCode = 400, }; payloadLen = coap_get_payload(request, &payload); if ((urlLen = coap_get_header_uri_path(request, &url))) { char uriBuf[MAX_COAP_PATH] = { 0 }; rest_resource_flags_t method = (rest_resource_flags_t) (1 << (((coap_packet_t *) packet)->code - 1)); //coap_get_rest_method(request); uriBuf[0] = '/'; memcpy(&uriBuf[1], url, urlLen); char queryBuf[128] = "?"; const char * query = NULL; int queryLength = coap_get_header_uri_query(request, &query); if (queryLength > 0) memcpy(&queryBuf[1], query, queryLength); queryBuf[queryLength+1] = '\0'; CoapRequest coapRequest = { .ctxt = context, .addr = { 0 }, .path = uriBuf, .query = queryBuf, .token = request->token, .tokenLength = request->token_len, .requestContent = payload, .requestContentLen = payloadLen, }; NetworkAddress_SetAddressType(sourceAddress, &coapRequest.addr); switch (method) { case METHOD_GET: coap_get_header_accept(request, &content); coapRequest.contentType = content; int32_t observe; if (!coap_get_header_observe(request, &observe)) observe = -1; switch (observe) { case -1: Lwm2m_Debug("Coap GET for %s\n", uriBuf); coapRequest.type = COAP_GET_REQUEST; requestHandler(&coapRequest, &coapResponse); break; case 0: Lwm2m_Debug("Coap OBSERVE for %s\n", uriBuf); coapRequest.type = COAP_OBSERVE_REQUEST; requestHandler(&coapRequest, &coapResponse); coap_set_header_observe(response, 1); break; case 1: Lwm2m_Debug("Coap CANCEL OBSERVE for %s\n", uriBuf); coapRequest.type = COAP_CANCEL_OBSERVE_REQUEST; requestHandler(&coapRequest, &coapResponse); break; default: break; } coap_set_header_content_format(response, coapResponse.responseContentType); /* text/plain is the default, hence this option could be omitted. */ break; case METHOD_POST: coap_get_header_content_format(request, &content); coapRequest.contentType = content; coapRequest.type = COAP_POST_REQUEST; Lwm2m_Debug("Coap POST for %s\n", uriBuf); requestHandler(&coapRequest, &coapResponse); if (coapResponse.responseContentLen > 0 && coapResponse.responseCode == 201) { coap_set_header_location_path(response, coapResponse.responseContent); } break; case METHOD_PUT: coap_get_header_content_format(request, &content); coapRequest.contentType = content; coapRequest.type = COAP_PUT_REQUEST; Lwm2m_Debug("Coap PUT for %s\n", uriBuf); requestHandler(&coapRequest, &coapResponse); break; case METHOD_DELETE: coapRequest.contentType = ContentType_None; coapRequest.type = COAP_DELETE_REQUEST; Lwm2m_Debug("Coap DELETE for %s\n", uriBuf); requestHandler(&coapRequest, &coapResponse); break; default: break; } if (coapResponse.responseContentLen > 0 && coapResponse.responseCode == 205) { coap_set_payload(response, coapResponse.responseContent, coapResponse.responseContentLen); } } coap_set_status_code(response, COAP_RESPONSE_CODE(coapResponse.responseCode)); return result; }
void device_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { const char *uri_path = NULL; uint8_t uri_len = REST.get_url(request, &uri_path); if (uri_len == 1) { if (*offset >= LEN_D_CORE) { coap_set_status_code(response, BAD_OPTION_4_02); coap_set_payload(response, "BlockOutOfScope", 15); return; } flash_getVar(buffer, RES_D_CORE + *offset, preferred_size); if (LEN_D_CORE - *offset < preferred_size) { preferred_size = LEN_D_CORE - *offset; *offset = -1; } else { *offset += preferred_size; } REST.set_header_content_type(response, APPLICATION_LINK_FORMAT); REST.set_response_payload(response, buffer, preferred_size); return; } //************************************************************************* //* DEVICE NAME * //************************************************************************* if (uri_path[2] == 'n' && uri_path[3] == 'a') { flash_getVar(buffer, RES_NAME, LEN_NAME); REST.set_header_content_type(response, TEXT_PLAIN); REST.set_response_payload(response, buffer, strlen(buffer)); } //************************************************************************* //* DEVICE MODEL * //************************************************************************* if (uri_path[2] == 'm') { flash_getVar(buffer, RES_MODEL, LEN_MODEL); REST.set_header_content_type(response, TEXT_PLAIN); REST.set_response_payload(response, buffer, strlen(buffer)); return; } //************************************************************************* //* DEVICE IDENTIFIER * //************************************************************************* if (uri_path[2] == 'u') { leds_on(LEDS_GREEN); send_hello = 0; flash_getVar(buffer, RES_UUID, LEN_UUID); REST.set_header_content_type(response, APPLICATION_OCTET_STREAM); REST.set_response_payload(response, buffer, LEN_UUID); } //************************************************************************* //* DEVICE TIME * //************************************************************************* if (uri_path[2] == 't') { uint32_t time = uip_htonl(clock_seconds()); memcpy(buffer, &time, 4); REST.set_header_content_type(response, APPLICATION_OCTET_STREAM); REST.set_response_payload(response, buffer, 4); } //************************************************************************* //* DEVICE PSK * //************************************************************************* if (uri_path[2] == 'p') { getPSK(buffer); REST.set_header_content_type(response, APPLICATION_OCTET_STREAM); REST.set_response_payload(response, buffer, LEN_PSK); } //************************************************************************* //* DEVICE DEFAULT ROUTE * //************************************************************************* if (uri_path[2] == 'r') { uip_ipaddr_t *addr = uip_ds6_defrt_choose(); memcpy(buffer, addr, 16); REST.set_header_content_type(response, APPLICATION_OCTET_STREAM); REST.set_response_payload(response, buffer, 16); } //************************************************************************* //* DEVICE NEIGHBOURS * //************************************************************************* if (uri_path[2] == 'n' && uri_path[3] == 'b') { uint32_t o = *offset / 16; uint32_t bfr_ptr = 0; uint32_t i; uip_ds6_nbr_t *nbr = nbr_table_head(ds6_neighbors); for (i = 0; i < (o+2); i++) { if (i >= o) { memcpy(buffer + bfr_ptr, &nbr->ipaddr, 16); bfr_ptr += 16; } nbr = nbr_table_next(ds6_neighbors, nbr); if (nbr == NULL) { if (bfr_ptr == 0) { coap_set_status_code(response, BAD_OPTION_4_02); coap_set_payload(response, "BlockOutOfScope", 15); return; } break; } } if (nbr == NULL) { *offset = -1; } else { *offset += bfr_ptr; } REST.set_header_content_type(response, APPLICATION_OCTET_STREAM); REST.set_response_payload(response, buffer, bfr_ptr); } }