static uint8_t prv_checkServerStatus(lwm2m_server_t * serverP) { LOG_ARG("Initial status: %s", STR_STATUS(serverP->status)); switch (serverP->status) { case STATE_BS_HOLD_OFF: serverP->status = STATE_BS_PENDING; LOG_ARG("Status changed to: %s", STR_STATUS(serverP->status)); break; case STATE_BS_INITIATED: // The ACK was probably lost serverP->status = STATE_BS_PENDING; LOG_ARG("Status changed to: %s", STR_STATUS(serverP->status)); break; case STATE_DEREGISTERED: // server initiated bootstrap case STATE_BS_PENDING: serverP->registration = lwm2m_gettime() + COAP_EXCHANGE_LIFETIME; break; case STATE_BS_FINISHED: case STATE_BS_FINISHING: case STATE_BS_FAILING: case STATE_BS_FAILED: default: LOG("Returning COAP_IGNORE"); return COAP_IGNORE; } return COAP_NO_ERROR; }
void registration_deregister(lwm2m_context_t * contextP, lwm2m_server_t * serverP) { lwm2m_transaction_t * transaction; LOG_ARG("State: %s, serverP->status: %s", STR_STATE(contextP->state), STR_STATUS(serverP->status)); if (serverP->status == STATE_DEREGISTERED || serverP->status == STATE_REG_PENDING || serverP->status == STATE_DEREG_PENDING || serverP->status == STATE_REG_FAILED || serverP->location == NULL) { return; } transaction = transaction_new(COAP_TYPE_CON, COAP_DELETE, NULL, NULL, contextP->nextMID++, 4, NULL, ENDPOINT_SERVER, (void *)serverP); if (transaction == NULL) return; coap_set_header_uri_path(transaction->message, serverP->location); transaction->callback = prv_handleDeregistrationReply; transaction->userData = (void *) contextP; contextP->transactionList = (lwm2m_transaction_t *)LWM2M_LIST_ADD(contextP->transactionList, transaction); if (transaction_send(contextP, transaction) == 0) { serverP->status = STATE_DEREG_PENDING; } }
/* * Returns STATE_REG_PENDING if at least one registration is still pending * Returns STATE_REGISTERED if no registration is pending and there is at least one server the client is registered to * Returns STATE_REG_FAILED if all registration failed. */ lwm2m_status_t registration_getStatus(lwm2m_context_t * contextP) { lwm2m_server_t * targetP; lwm2m_status_t reg_status; LOG_ARG("State: %s", STR_STATE(contextP->state)); targetP = contextP->serverList; reg_status = STATE_REG_FAILED; while (targetP != NULL) { LOG_ARG("targetP->status: %s", STR_STATUS(targetP->status)); switch (targetP->status) { case STATE_REGISTERED: case STATE_REG_UPDATE_PENDING: if (reg_status == STATE_REG_FAILED) { reg_status = STATE_REGISTERED; } break; case STATE_REG_PENDING: reg_status = STATE_REG_PENDING; break; case STATE_REG_FAILED: case STATE_DEREG_PENDING: case STATE_DEREGISTERED: default: break; } LOG_ARG("reg_status: %s", STR_STATUS(reg_status)); targetP = targetP->next; } return reg_status; }
/* * Returns STATE_BS_PENDING if at least one bootstrap is still pending * Returns STATE_BS_FINISHED if at least one bootstrap succeeded and no bootstrap is pending * Returns STATE_BS_FAILED if all bootstrap failed. */ lwm2m_status_t bootstrap_getStatus(lwm2m_context_t * contextP) { lwm2m_server_t * targetP; lwm2m_status_t bs_status; LOG("Entering"); targetP = contextP->bootstrapServerList; bs_status = STATE_BS_FAILED; while (targetP != NULL) { switch (targetP->status) { case STATE_BS_FINISHED: if (bs_status == STATE_BS_FAILED) { bs_status = STATE_BS_FINISHED; } break; case STATE_BS_HOLD_OFF: case STATE_BS_INITIATED: case STATE_BS_PENDING: case STATE_BS_FINISHING: case STATE_BS_FAILING: bs_status = STATE_BS_PENDING; break; default: break; } targetP = targetP->next; } LOG_ARG("Returned status: %s", STR_STATUS(bs_status)); return bs_status; }
uint8_t bootstrap_handleCommand(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, lwm2m_server_t * serverP, coap_packet_t * message, coap_packet_t * response) { uint8_t result; lwm2m_media_type_t format; LOG_ARG("Code: %02X", message->code); LOG_URI(uriP); format = utils_convertMediaType(message->content_type); result = prv_checkServerStatus(serverP); if (result != COAP_NO_ERROR) return result; switch (message->code) { case COAP_PUT: { if (LWM2M_URI_IS_SET_INSTANCE(uriP)) { if (object_isInstanceNew(contextP, uriP->objectId, uriP->instanceId)) { result = object_create(contextP, uriP, format, message->payload, message->payload_len); if (COAP_201_CREATED == result) { result = COAP_204_CHANGED; } } else { result = object_write(contextP, uriP, format, message->payload, message->payload_len); if (uriP->objectId == LWM2M_SECURITY_OBJECT_ID && result == COAP_204_CHANGED) { prv_tagServer(contextP, uriP->instanceId); } } } else { lwm2m_data_t * dataP = NULL; int size = 0; int i; if (message->payload_len == 0 || message->payload == 0) { result = COAP_400_BAD_REQUEST; } else { size = lwm2m_data_parse(uriP, message->payload, message->payload_len, format, &dataP); if (size == 0) { result = COAP_500_INTERNAL_SERVER_ERROR; break; } for (i = 0 ; i < size ; i++) { if(dataP[i].type == LWM2M_TYPE_OBJECT_INSTANCE) { if (object_isInstanceNew(contextP, uriP->objectId, dataP[i].id)) { result = object_createInstance(contextP, uriP, &dataP[i]); if (COAP_201_CREATED == result) { result = COAP_204_CHANGED; } } else { result = object_writeInstance(contextP, uriP, &dataP[i]); if (uriP->objectId == LWM2M_SECURITY_OBJECT_ID && result == COAP_204_CHANGED) { prv_tagServer(contextP, dataP[i].id); } } if(result != COAP_204_CHANGED) // Stop object create or write when result is error { break; } } else { result = COAP_400_BAD_REQUEST; } } lwm2m_data_free(size, dataP); } } } break; case COAP_DELETE: { if (LWM2M_URI_IS_SET_RESOURCE(uriP)) { result = COAP_400_BAD_REQUEST; } else { result = object_delete(contextP, uriP); if (uriP->objectId == LWM2M_SECURITY_OBJECT_ID && result == COAP_202_DELETED) { if (LWM2M_URI_IS_SET_INSTANCE(uriP)) { prv_tagServer(contextP, uriP->instanceId); } else { prv_tagAllServer(contextP, NULL); } } } } break; case COAP_GET: case COAP_POST: default: result = COAP_400_BAD_REQUEST; break; } if (result == COAP_202_DELETED || result == COAP_204_CHANGED) { if (serverP->status != STATE_BS_PENDING) { serverP->status = STATE_BS_PENDING; contextP->state = STATE_BOOTSTRAPPING; } } LOG_ARG("Server status: %s", STR_STATUS(serverP->status)); return result; }
void bootstrap_step(lwm2m_context_t * contextP, time_t currentTime, time_t * timeoutP) { lwm2m_server_t * targetP; LOG("entering"); targetP = contextP->bootstrapServerList; while (targetP != NULL) { LOG_ARG("Initial status: %s", STR_STATUS(targetP->status)); switch (targetP->status) { case STATE_DEREGISTERED: targetP->registration = currentTime + targetP->lifetime; targetP->status = STATE_BS_HOLD_OFF; if (*timeoutP > targetP->lifetime) { *timeoutP = targetP->lifetime; } break; case STATE_BS_HOLD_OFF: if (targetP->registration <= currentTime) { prv_requestBootstrap(contextP, targetP); } else if (*timeoutP > targetP->registration - currentTime) { *timeoutP = targetP->registration - currentTime; } break; case STATE_BS_INITIATED: // waiting break; case STATE_BS_PENDING: if (targetP->registration <= currentTime) { targetP->status = STATE_BS_FAILING; *timeoutP = 0; } else if (*timeoutP > targetP->registration - currentTime) { *timeoutP = targetP->registration - currentTime; } break; case STATE_BS_FINISHING: if (targetP->sessionH != NULL) { lwm2m_close_connection(targetP->sessionH, contextP->userData); targetP->sessionH = NULL; } targetP->status = STATE_BS_FINISHED; *timeoutP = 0; break; case STATE_BS_FAILING: if (targetP->sessionH != NULL) { lwm2m_close_connection(targetP->sessionH, contextP->userData); targetP->sessionH = NULL; } targetP->status = STATE_BS_FAILED; *timeoutP = 0; break; default: break; } LOG_ARG("Finalal status: %s", STR_STATUS(targetP->status)); targetP = targetP->next; } }
uint8_t dm_handleRequest(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, lwm2m_server_t * serverP, coap_packet_t * message, coap_packet_t * response) { uint8_t result; lwm2m_media_type_t format; LOG_ARG("Code: %02X, server status: %s", message->code, STR_STATUS(serverP->status)); LOG_URI(uriP); if (IS_OPTION(message, COAP_OPTION_CONTENT_TYPE)) { format = utils_convertMediaType(message->content_type); } else { format = LWM2M_CONTENT_TLV; } if (uriP->objectId == LWM2M_SECURITY_OBJECT_ID) { return COAP_404_NOT_FOUND; } if (serverP->status != STATE_REGISTERED && serverP->status != STATE_REG_UPDATE_NEEDED && serverP->status != STATE_REG_FULL_UPDATE_NEEDED && serverP->status != STATE_REG_UPDATE_PENDING) { return COAP_IGNORE; } // TODO: check ACL switch (message->code) { case COAP_GET: { uint8_t * buffer = NULL; size_t length = 0; int res; if (IS_OPTION(message, COAP_OPTION_OBSERVE)) { lwm2m_data_t * dataP = NULL; int size = 0; result = object_readData(contextP, uriP, &size, &dataP); if (COAP_205_CONTENT == result) { result = observe_handleRequest(contextP, uriP, serverP, size, dataP, message, response); if (COAP_205_CONTENT == result) { if (IS_OPTION(message, COAP_OPTION_ACCEPT)) { format = utils_convertMediaType(message->accept[0]); } else { format = LWM2M_CONTENT_TLV; } res = lwm2m_data_serialize(uriP, size, dataP, &format, &buffer); if (res < 0) { result = COAP_500_INTERNAL_SERVER_ERROR; } else { length = (size_t)res; LOG_ARG("Observe Request[/%d/%d/%d]: %.*s\n", uriP->objectId, uriP->instanceId, uriP->resourceId, length, buffer); } } lwm2m_data_free(size, dataP); } } else if (IS_OPTION(message, COAP_OPTION_ACCEPT) && message->accept_num == 1 && message->accept[0] == APPLICATION_LINK_FORMAT) { format = LWM2M_CONTENT_LINK; result = object_discover(contextP, uriP, serverP, &buffer, &length); } else { if (IS_OPTION(message, COAP_OPTION_ACCEPT)) { format = utils_convertMediaType(message->accept[0]); } result = object_read(contextP, uriP, &format, &buffer, &length); } if (COAP_205_CONTENT == result) { coap_set_header_content_type(response, format); coap_set_payload(response, buffer, length); // lwm2m_handle_packet will free buffer } else { lwm2m_free(buffer); } } break; case COAP_POST: { if (!LWM2M_URI_IS_SET_INSTANCE(uriP)) { result = object_create(contextP, uriP, format, message->payload, message->payload_len); if (result == COAP_201_CREATED) { //longest uri is /65535/65535 = 12 + 1 (null) chars char location_path[13] = ""; //instanceId expected if ((uriP->flag & LWM2M_URI_FLAG_INSTANCE_ID) == 0) { result = COAP_500_INTERNAL_SERVER_ERROR; break; } if (sprintf(location_path, "/%d/%d", uriP->objectId, uriP->instanceId) < 0) { result = COAP_500_INTERNAL_SERVER_ERROR; break; } coap_set_header_location_path(response, location_path); lwm2m_update_registration(contextP, 0, true); } } else if (!LWM2M_URI_IS_SET_RESOURCE(uriP)) { result = object_write(contextP, uriP, format, message->payload, message->payload_len); } else { result = object_execute(contextP, uriP, message->payload, message->payload_len); } } break; case COAP_PUT: { if (IS_OPTION(message, COAP_OPTION_URI_QUERY)) { lwm2m_attributes_t attr; if (0 != prv_readAttributes(message->uri_query, &attr)) { result = COAP_400_BAD_REQUEST; } else { result = observe_setParameters(contextP, uriP, serverP, &attr); } } else if (LWM2M_URI_IS_SET_INSTANCE(uriP)) { result = object_write(contextP, uriP, format, message->payload, message->payload_len); } else { result = COAP_400_BAD_REQUEST; } } break; case COAP_DELETE: { if (!LWM2M_URI_IS_SET_INSTANCE(uriP) || LWM2M_URI_IS_SET_RESOURCE(uriP)) { result = COAP_400_BAD_REQUEST; } else { result = object_delete(contextP, uriP); if (result == COAP_202_DELETED) { lwm2m_update_registration(contextP, 0, true); } } } break; default: result = COAP_400_BAD_REQUEST; break; } return result; }
coap_status_t observe_handleRequest(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, lwm2m_server_t * serverP, int size, lwm2m_data_t * dataP, coap_packet_t * message, coap_packet_t * response) { lwm2m_watcher_t * watcherP; uint32_t count; LOG_ARG("Code: %02X, server status: %s", message->code, STR_STATUS(serverP->status)); LOG_URI(uriP); coap_get_header_observe(message, &count); switch (count) { case 0: if (!LWM2M_URI_IS_SET_INSTANCE(uriP) && LWM2M_URI_IS_SET_RESOURCE(uriP)) return COAP_400_BAD_REQUEST; if (message->token_len == 0) return COAP_400_BAD_REQUEST; watcherP = prv_getWatcher(contextP, uriP, serverP); if (watcherP == NULL) return COAP_500_INTERNAL_SERVER_ERROR; watcherP->tokenLen = message->token_len; memcpy(watcherP->token, message->token, message->token_len); watcherP->active = true; watcherP->lastTime = lwm2m_gettime(); if (IS_OPTION(message, COAP_OPTION_ACCEPT)) { watcherP->format = utils_convertMediaType(message->accept[0]); } else { watcherP->format = LWM2M_CONTENT_TLV; } if (LWM2M_URI_IS_SET_RESOURCE(uriP)) { switch (dataP->type) { case LWM2M_TYPE_INTEGER: if (1 != lwm2m_data_decode_int(dataP, &(watcherP->lastValue.asInteger))) return COAP_500_INTERNAL_SERVER_ERROR; break; case LWM2M_TYPE_FLOAT: if (1 != lwm2m_data_decode_float(dataP, &(watcherP->lastValue.asFloat))) return COAP_500_INTERNAL_SERVER_ERROR; break; default: break; } } coap_set_header_observe(response, watcherP->counter++); return COAP_205_CONTENT; case 1: // cancellation observe_cancel(contextP, LWM2M_MAX_ID, serverP->sessionH); return COAP_205_CONTENT; default: return COAP_400_BAD_REQUEST; } }