lwm2m_observed_t * observe_findByUri(lwm2m_context_t * contextP, lwm2m_uri_t * uriP) { lwm2m_observed_t * targetP; LOG_URI(uriP); targetP = contextP->observedList; while (targetP != NULL) { if (targetP->uri.objectId == uriP->objectId) { if ((!LWM2M_URI_IS_SET_INSTANCE(uriP) && !LWM2M_URI_IS_SET_INSTANCE(&(targetP->uri))) || (LWM2M_URI_IS_SET_INSTANCE(uriP) && LWM2M_URI_IS_SET_INSTANCE(&(targetP->uri)) && (uriP->instanceId == targetP->uri.instanceId))) { if ((!LWM2M_URI_IS_SET_RESOURCE(uriP) && !LWM2M_URI_IS_SET_RESOURCE(&(targetP->uri))) || (LWM2M_URI_IS_SET_RESOURCE(uriP) && LWM2M_URI_IS_SET_RESOURCE(&(targetP->uri)) && (uriP->resourceId == targetP->uri.resourceId))) { LOG_ARG("Found one with%s observers.", targetP->watcherList ? "" : " no"); LOG_URI(&(targetP->uri)); return targetP; } } } targetP = targetP->next; } LOG("Found nothing"); return NULL; }
int lwm2m_dm_read(lwm2m_context_t * contextP, uint16_t clientID, lwm2m_uri_t * uriP, lwm2m_result_callback_t callback, void * userData) { lwm2m_client_t * clientP; lwm2m_media_type_t format; LOG_ARG("clientID: %d", clientID); LOG_URI(uriP); clientP = (lwm2m_client_t *)lwm2m_list_find((lwm2m_list_t *)contextP->clientList, clientID); if (clientP == NULL) return COAP_404_NOT_FOUND; if (clientP->supportJSON == true) { format = LWM2M_CONTENT_JSON; } else { format = LWM2M_CONTENT_TLV; } return prv_makeOperation(contextP, clientID, uriP, COAP_GET, format, NULL, 0, callback, userData); }
int lwm2m_dm_write(lwm2m_context_t * contextP, uint16_t clientID, lwm2m_uri_t * uriP, lwm2m_media_type_t format, uint8_t * buffer, int length, lwm2m_result_callback_t callback, void * userData) { LOG_ARG("clientID: %d, format: %s, length: %d", clientID, STR_MEDIA_TYPE(format), length); LOG_URI(uriP); if (!LWM2M_URI_IS_SET_INSTANCE(uriP) || length == 0) { return COAP_400_BAD_REQUEST; } if (LWM2M_URI_IS_SET_RESOURCE(uriP)) { return prv_makeOperation(contextP, clientID, uriP, COAP_PUT, format, buffer, length, callback, userData); } else { return prv_makeOperation(contextP, clientID, uriP, COAP_POST, format, buffer, length, callback, userData); } }
int lwm2m_bootstrap_delete(lwm2m_context_t * contextP, void * sessionH, lwm2m_uri_t * uriP) { lwm2m_transaction_t * transaction; bs_data_t * dataP; LOG_URI(uriP); transaction = transaction_new(sessionH, COAP_DELETE, NULL, uriP, contextP->nextMID++, 4, NULL); if (transaction == NULL) return COAP_500_INTERNAL_SERVER_ERROR; dataP = (bs_data_t *)lwm2m_malloc(sizeof(bs_data_t)); if (dataP == NULL) { transaction_free(transaction); return COAP_500_INTERNAL_SERVER_ERROR; } if (uriP == NULL) { LWM2M_URI_RESET(&dataP->uri); } else { memcpy(&dataP->uri, uriP, sizeof(lwm2m_uri_t)); } dataP->callback = contextP->bootstrapCallback; dataP->userData = contextP->bootstrapUserData; transaction->callback = prv_resultCallback; transaction->userData = (void *)dataP; contextP->transactionList = (lwm2m_transaction_t *)LWM2M_LIST_ADD(contextP->transactionList, transaction); return transaction_send(contextP, transaction); }
uint8_t bootstrap_handleRequest(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, void * fromSessionH, coap_packet_t * message, coap_packet_t * response) { uint8_t result; char * name; LOG_URI(uriP); if (contextP->bootstrapCallback == NULL) return COAP_500_INTERNAL_SERVER_ERROR; if (message->code != COAP_POST) return COAP_400_BAD_REQUEST; if (message->uri_query == NULL) return COAP_400_BAD_REQUEST; if (message->payload != NULL) return COAP_400_BAD_REQUEST; if (lwm2m_strncmp((char *)message->uri_query->data, QUERY_NAME, QUERY_NAME_LEN) != 0) { return COAP_400_BAD_REQUEST; } if (message->uri_query->len == QUERY_NAME_LEN) return COAP_400_BAD_REQUEST; if (message->uri_query->next != NULL) return COAP_400_BAD_REQUEST; name = (char *)lwm2m_malloc(message->uri_query->len - QUERY_NAME_LEN + 1); if (name == NULL) return COAP_500_INTERNAL_SERVER_ERROR; memcpy(name, message->uri_query->data + QUERY_NAME_LEN, message->uri_query->len - QUERY_NAME_LEN); name[message->uri_query->len - QUERY_NAME_LEN] = 0; result = contextP->bootstrapCallback(fromSessionH, COAP_NO_ERROR, NULL, name, contextP->bootstrapUserData); lwm2m_free(name); return result; }
int lwm2m_data_parse(lwm2m_uri_t * uriP, uint8_t * buffer, size_t bufferLen, lwm2m_media_type_t format, lwm2m_data_t ** dataP) { int res; LOG_ARG("format: %s, bufferLen: %d", STR_MEDIA_TYPE(format), bufferLen); LOG_URI(uriP); switch (format) { case LWM2M_CONTENT_TEXT: if (!LWM2M_URI_IS_SET_RESOURCE(uriP)) return 0; *dataP = lwm2m_data_new(1); if (*dataP == NULL) return 0; (*dataP)->id = uriP->resourceId; (*dataP)->type = LWM2M_TYPE_STRING; res = prv_setBuffer(*dataP, buffer, bufferLen); if (res == 0) { lwm2m_data_free(1, *dataP); *dataP = NULL; } return res; case LWM2M_CONTENT_OPAQUE: if (!LWM2M_URI_IS_SET_RESOURCE(uriP)) return 0; *dataP = lwm2m_data_new(1); if (*dataP == NULL) return 0; (*dataP)->id = uriP->resourceId; (*dataP)->type = LWM2M_TYPE_OPAQUE; res = prv_setBuffer(*dataP, buffer, bufferLen); if (res == 0) { lwm2m_data_free(1, *dataP); *dataP = NULL; } return res; #ifdef LWM2M_OLD_CONTENT_FORMAT_SUPPORT case LWM2M_CONTENT_TLV_OLD: #endif case LWM2M_CONTENT_TLV: return tlv_parse(buffer, bufferLen, dataP); #ifdef LWM2M_SUPPORT_JSON #ifdef LWM2M_OLD_CONTENT_FORMAT_SUPPORT case LWM2M_CONTENT_JSON_OLD: #endif case LWM2M_CONTENT_JSON: return json_parse(uriP, buffer, bufferLen, dataP); #endif default: return 0; } }
int uri_toString(lwm2m_uri_t * uriP, uint8_t * buffer, size_t bufferLen, uri_depth_t * depthP) { size_t head; int res; LOG_ARG("bufferLen: %u", bufferLen); LOG_URI(uriP); buffer[0] = '/'; if (uriP == NULL) { if (depthP) *depthP = URI_DEPTH_OBJECT; return 1; } head = 1; res = utils_intToText(uriP->objectId, buffer + head, bufferLen - head); if (res <= 0) return -1; head += res; if (head >= bufferLen - 1) return -1; if (depthP) *depthP = URI_DEPTH_OBJECT_INSTANCE; if (LWM2M_URI_IS_SET_INSTANCE(uriP)) { buffer[head] = '/'; head++; res = utils_intToText(uriP->instanceId, buffer + head, bufferLen - head); if (res <= 0) return -1; head += res; if (head >= bufferLen - 1) return -1; if (depthP) *depthP = URI_DEPTH_RESOURCE; if (LWM2M_URI_IS_SET_RESOURCE(uriP)) { buffer[head] = '/'; head++; res = utils_intToText(uriP->resourceId, buffer + head, bufferLen - head); if (res <= 0) return -1; head += res; if (head >= bufferLen - 1) return -1; if (depthP) *depthP = URI_DEPTH_RESOURCE_INSTANCE; } } buffer[head] = '/'; head++; LOG_ARG("length: %u, buffer: \"%.*s\"", head, head, buffer); return head; }
void lwm2m_resource_value_changed(lwm2m_context_t * contextP, lwm2m_uri_t * uriP) { lwm2m_observed_t * targetP; LOG_URI(uriP); targetP = contextP->observedList; while (targetP != NULL) { if (targetP->uri.objectId == uriP->objectId) { if (!LWM2M_URI_IS_SET_INSTANCE(uriP) || (targetP->uri.flag & LWM2M_URI_FLAG_INSTANCE_ID) == 0 || uriP->instanceId == targetP->uri.instanceId) { if (!LWM2M_URI_IS_SET_RESOURCE(uriP) || (targetP->uri.flag & LWM2M_URI_FLAG_RESOURCE_ID) == 0 || uriP->resourceId == targetP->uri.resourceId) { lwm2m_watcher_t * watcherP; LOG("Found an observation"); LOG_URI(&(targetP->uri)); for (watcherP = targetP->watcherList ; watcherP != NULL ; watcherP = watcherP->next) { if (watcherP->active == true) { LOG("Tagging a watcher"); watcherP->update = true; } } } } } targetP = targetP->next; } }
int lwm2m_dm_delete(lwm2m_context_t * contextP, uint16_t clientID, lwm2m_uri_t * uriP, lwm2m_result_callback_t callback, void * userData) { LOG_ARG("clientID: %d", clientID); LOG_URI(uriP); if (!LWM2M_URI_IS_SET_INSTANCE(uriP) || LWM2M_URI_IS_SET_RESOURCE(uriP)) { return COAP_400_BAD_REQUEST; } return prv_makeOperation(contextP, clientID, uriP, COAP_DELETE, LWM2M_CONTENT_TEXT, NULL, 0, callback, userData); }
int lwm2m_bootstrap_write(lwm2m_context_t * contextP, void * sessionH, lwm2m_uri_t * uriP, lwm2m_media_type_t format, uint8_t * buffer, size_t length) { lwm2m_transaction_t * transaction; bs_data_t * dataP; LOG_URI(uriP); if (uriP == NULL || buffer == NULL || length == 0) { return COAP_400_BAD_REQUEST; } transaction = transaction_new(sessionH, COAP_PUT, NULL, uriP, contextP->nextMID++, 4, NULL); if (transaction == NULL) return COAP_500_INTERNAL_SERVER_ERROR; coap_set_header_content_type(transaction->message, format); coap_set_payload(transaction->message, buffer, length); dataP = (bs_data_t *)lwm2m_malloc(sizeof(bs_data_t)); if (dataP == NULL) { transaction_free(transaction); return COAP_500_INTERNAL_SERVER_ERROR; } dataP->isUri = true; memcpy(&dataP->uri, uriP, sizeof(lwm2m_uri_t)); dataP->callback = contextP->bootstrapCallback; dataP->userData = contextP->bootstrapUserData; transaction->callback = prv_resultCallback; transaction->userData = (void *)dataP; contextP->transactionList = (lwm2m_transaction_t *)LWM2M_LIST_ADD(contextP->transactionList, transaction); return transaction_send(contextP, transaction); }
int lwm2m_dm_read(lwm2m_context_t * contextP, uint16_t clientID, lwm2m_uri_t * uriP, lwm2m_result_callback_t callback, void * userData) { lwm2m_client_t * clientP; LOG_ARG("clientID: %d", clientID); LOG_URI(uriP); clientP = (lwm2m_client_t *)lwm2m_list_find((lwm2m_list_t *)contextP->clientList, clientID); if (clientP == NULL) return COAP_404_NOT_FOUND; return prv_makeOperation(contextP, clientID, uriP, COAP_GET, clientP->format, NULL, 0, callback, userData); }
int lwm2m_dm_discover(lwm2m_context_t * contextP, uint16_t clientID, lwm2m_uri_t * uriP, lwm2m_result_callback_t callback, void * userData) { lwm2m_client_t * clientP; lwm2m_transaction_t * transaction; dm_data_t * dataP; LOG_ARG("clientID: %d", clientID); LOG_URI(uriP); clientP = (lwm2m_client_t *)lwm2m_list_find((lwm2m_list_t *)contextP->clientList, clientID); if (clientP == NULL) return COAP_404_NOT_FOUND; transaction = transaction_new(clientP->sessionH, COAP_GET, clientP->altPath, uriP, contextP->nextMID++, 4, NULL); if (transaction == NULL) return COAP_500_INTERNAL_SERVER_ERROR; coap_set_header_accept(transaction->message, LWM2M_CONTENT_LINK); if (callback != NULL) { dataP = (dm_data_t *)lwm2m_malloc(sizeof(dm_data_t)); if (dataP == NULL) { transaction_free(transaction); return COAP_500_INTERNAL_SERVER_ERROR; } memcpy(&dataP->uri, uriP, sizeof(lwm2m_uri_t)); dataP->clientID = clientP->internalID; dataP->callback = callback; dataP->userData = userData; transaction->callback = prv_resultCallback; transaction->userData = (void *)dataP; } contextP->transactionList = (lwm2m_transaction_t *)LWM2M_LIST_ADD(contextP->transactionList, transaction); return transaction_send(contextP, transaction); }
void observe_clear(lwm2m_context_t * contextP, lwm2m_uri_t * uriP) { lwm2m_observed_t * observedP; LOG_URI(uriP); observedP = contextP->observedList; while(observedP != NULL) { if (observedP->uri.objectId == uriP->objectId && (LWM2M_URI_IS_SET_INSTANCE(uriP) == false || observedP->uri.instanceId == uriP->instanceId)) { lwm2m_observed_t * nextP; lwm2m_watcher_t * watcherP; nextP = observedP->next; for (watcherP = observedP->watcherList; watcherP != NULL; watcherP = watcherP->next) { if (watcherP->parameters != NULL) lwm2m_free(watcherP->parameters); } LWM2M_LIST_FREE(observedP->watcherList); prv_unlinkObserved(contextP, observedP); lwm2m_free(observedP); observedP = nextP; } else { observedP = observedP->next; } } }
int lwm2m_dm_write_attributes(lwm2m_context_t * contextP, uint16_t clientID, lwm2m_uri_t * uriP, lwm2m_attributes_t * attrP, lwm2m_result_callback_t callback, void * userData) { #define _PRV_BUFFER_SIZE 32 lwm2m_client_t * clientP; lwm2m_transaction_t * transaction; coap_packet_t * coap_pkt; uint8_t buffer[_PRV_BUFFER_SIZE]; size_t length; LOG_ARG("clientID: %d", clientID); LOG_URI(uriP); if (attrP == NULL) return COAP_400_BAD_REQUEST; if (0 != (attrP->toSet & attrP->toClear)) return COAP_400_BAD_REQUEST; if (0 != (attrP->toSet & ATTR_FLAG_NUMERIC) && !LWM2M_URI_IS_SET_RESOURCE(uriP)) return COAP_400_BAD_REQUEST; if (ATTR_FLAG_NUMERIC == (attrP->toSet & ATTR_FLAG_NUMERIC) && (attrP->lessThan + 2 * attrP->step >= attrP->greaterThan)) return COAP_400_BAD_REQUEST; clientP = (lwm2m_client_t *)lwm2m_list_find((lwm2m_list_t *)contextP->clientList, clientID); if (clientP == NULL) return COAP_404_NOT_FOUND; transaction = transaction_new(clientP->sessionH, COAP_PUT, clientP->altPath, uriP, contextP->nextMID++, 4, NULL); if (transaction == NULL) return COAP_500_INTERNAL_SERVER_ERROR; if (callback != NULL) { dm_data_t * dataP; dataP = (dm_data_t *)lwm2m_malloc(sizeof(dm_data_t)); if (dataP == NULL) { transaction_free(transaction); return COAP_500_INTERNAL_SERVER_ERROR; } memcpy(&dataP->uri, uriP, sizeof(lwm2m_uri_t)); dataP->clientID = clientP->internalID; dataP->callback = callback; dataP->userData = userData; transaction->callback = prv_resultCallback; transaction->userData = (void *)dataP; } coap_pkt = (coap_packet_t *)transaction->message; free_multi_option(coap_pkt->uri_query); if (attrP->toSet & LWM2M_ATTR_FLAG_MIN_PERIOD) { memcpy(buffer, ATTR_MIN_PERIOD_STR, ATTR_MIN_PERIOD_LEN); length = utils_intToText(attrP->minPeriod, buffer + ATTR_MIN_PERIOD_LEN, _PRV_BUFFER_SIZE - ATTR_MIN_PERIOD_LEN); if (length == 0) { transaction_free(transaction); return COAP_500_INTERNAL_SERVER_ERROR; } coap_add_multi_option(&(coap_pkt->uri_query), buffer, ATTR_MIN_PERIOD_LEN + length, 0); SET_OPTION(coap_pkt, COAP_OPTION_URI_QUERY); } if (attrP->toSet & LWM2M_ATTR_FLAG_MAX_PERIOD) { memcpy(buffer, ATTR_MAX_PERIOD_STR, ATTR_MAX_PERIOD_LEN); length = utils_intToText(attrP->maxPeriod, buffer + ATTR_MAX_PERIOD_LEN, _PRV_BUFFER_SIZE - ATTR_MAX_PERIOD_LEN); if (length == 0) { transaction_free(transaction); return COAP_500_INTERNAL_SERVER_ERROR; } coap_add_multi_option(&(coap_pkt->uri_query), buffer, ATTR_MAX_PERIOD_LEN + length, 0); SET_OPTION(coap_pkt, COAP_OPTION_URI_QUERY); } if (attrP->toSet & LWM2M_ATTR_FLAG_GREATER_THAN) { memcpy(buffer, ATTR_GREATER_THAN_STR, ATTR_GREATER_THAN_LEN); length = utils_floatToText(attrP->greaterThan, buffer + ATTR_GREATER_THAN_LEN, _PRV_BUFFER_SIZE - ATTR_GREATER_THAN_LEN); if (length == 0) { transaction_free(transaction); return COAP_500_INTERNAL_SERVER_ERROR; } coap_add_multi_option(&(coap_pkt->uri_query), buffer, ATTR_GREATER_THAN_LEN + length, 0); SET_OPTION(coap_pkt, COAP_OPTION_URI_QUERY); } if (attrP->toSet & LWM2M_ATTR_FLAG_LESS_THAN) { memcpy(buffer, ATTR_LESS_THAN_STR, ATTR_LESS_THAN_LEN); length = utils_floatToText(attrP->lessThan, buffer + ATTR_LESS_THAN_LEN, _PRV_BUFFER_SIZE - ATTR_LESS_THAN_LEN); if (length == 0) { transaction_free(transaction); return COAP_500_INTERNAL_SERVER_ERROR; } coap_add_multi_option(&(coap_pkt->uri_query), buffer, ATTR_LESS_THAN_LEN + length, 0); SET_OPTION(coap_pkt, COAP_OPTION_URI_QUERY); } if (attrP->toSet & LWM2M_ATTR_FLAG_STEP) { memcpy(buffer, ATTR_STEP_STR, ATTR_STEP_LEN); length = utils_floatToText(attrP->step, buffer + ATTR_STEP_LEN, _PRV_BUFFER_SIZE - ATTR_STEP_LEN); if (length == 0) { transaction_free(transaction); return COAP_500_INTERNAL_SERVER_ERROR; } coap_add_multi_option(&(coap_pkt->uri_query), buffer, ATTR_STEP_LEN + length, 0); SET_OPTION(coap_pkt, COAP_OPTION_URI_QUERY); } if (attrP->toClear & LWM2M_ATTR_FLAG_MIN_PERIOD) { coap_add_multi_option(&(coap_pkt->uri_query), (uint8_t*)ATTR_MIN_PERIOD_STR, ATTR_MIN_PERIOD_LEN -1, 0); SET_OPTION(coap_pkt, COAP_OPTION_URI_QUERY); } if (attrP->toClear & LWM2M_ATTR_FLAG_MAX_PERIOD) { coap_add_multi_option(&(coap_pkt->uri_query), (uint8_t*)ATTR_MAX_PERIOD_STR, ATTR_MAX_PERIOD_LEN - 1, 0); SET_OPTION(coap_pkt, COAP_OPTION_URI_QUERY); } if (attrP->toClear & LWM2M_ATTR_FLAG_GREATER_THAN) { coap_add_multi_option(&(coap_pkt->uri_query), (uint8_t*)ATTR_GREATER_THAN_STR, ATTR_GREATER_THAN_LEN - 1, 0); SET_OPTION(coap_pkt, COAP_OPTION_URI_QUERY); } if (attrP->toClear & LWM2M_ATTR_FLAG_LESS_THAN) { coap_add_multi_option(&(coap_pkt->uri_query), (uint8_t*)ATTR_LESS_THAN_STR, ATTR_LESS_THAN_LEN - 1, 0); SET_OPTION(coap_pkt, COAP_OPTION_URI_QUERY); } if (attrP->toClear & LWM2M_ATTR_FLAG_STEP) { coap_add_multi_option(&(coap_pkt->uri_query), (uint8_t*)ATTR_STEP_STR, ATTR_STEP_LEN - 1, 0); SET_OPTION(coap_pkt, COAP_OPTION_URI_QUERY); } contextP->transactionList = (lwm2m_transaction_t *)LWM2M_LIST_ADD(contextP->transactionList, transaction); return transaction_send(contextP, transaction); }
coap_status_t observe_setParameters(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, lwm2m_server_t * serverP, lwm2m_attributes_t * attrP) { uint8_t result; lwm2m_watcher_t * watcherP; LOG_URI(uriP); LOG_ARG("toSet: %08X, toClear: %08X, minPeriod: %d, maxPeriod: %d, greaterThan: %f, lessThan: %f, step: %f", attrP->toSet, attrP->toClear, attrP->minPeriod, attrP->maxPeriod, attrP->greaterThan, attrP->lessThan, attrP->step); if (!LWM2M_URI_IS_SET_INSTANCE(uriP) && LWM2M_URI_IS_SET_RESOURCE(uriP)) return COAP_400_BAD_REQUEST; result = object_checkReadable(contextP, uriP); if (COAP_205_CONTENT != result) return result; if (0 != (attrP->toSet & ATTR_FLAG_NUMERIC)) { result = object_checkNumeric(contextP, uriP); if (COAP_205_CONTENT != result) return result; } watcherP = prv_getWatcher(contextP, uriP, serverP); if (watcherP == NULL) return COAP_500_INTERNAL_SERVER_ERROR; // Check rule “lt” value + 2*”stp” values < “gt” value if ((((attrP->toSet | (watcherP->parameters?watcherP->parameters->toSet:0)) & ~attrP->toClear) & ATTR_FLAG_NUMERIC) == ATTR_FLAG_NUMERIC) { float gt; float lt; float stp; if (0 != (attrP->toSet & LWM2M_ATTR_FLAG_GREATER_THAN)) { gt = attrP->greaterThan; } else { gt = watcherP->parameters->greaterThan; } if (0 != (attrP->toSet & LWM2M_ATTR_FLAG_LESS_THAN)) { lt = attrP->lessThan; } else { lt = watcherP->parameters->lessThan; } if (0 != (attrP->toSet & LWM2M_ATTR_FLAG_STEP)) { stp = attrP->step; } else { stp = watcherP->parameters->step; } if (lt + (2 * stp) >= gt) return COAP_400_BAD_REQUEST; } if (watcherP->parameters == NULL) { if (attrP->toSet != 0) { watcherP->parameters = (lwm2m_attributes_t *)lwm2m_malloc(sizeof(lwm2m_attributes_t)); if (watcherP->parameters == NULL) return COAP_500_INTERNAL_SERVER_ERROR; memcpy(watcherP->parameters, attrP, sizeof(lwm2m_attributes_t)); } } else { watcherP->parameters->toSet &= ~attrP->toClear; if (attrP->toSet & LWM2M_ATTR_FLAG_MIN_PERIOD) { watcherP->parameters->minPeriod = attrP->minPeriod; } if (attrP->toSet & LWM2M_ATTR_FLAG_MAX_PERIOD) { watcherP->parameters->maxPeriod = attrP->maxPeriod; } if (attrP->toSet & LWM2M_ATTR_FLAG_GREATER_THAN) { watcherP->parameters->greaterThan = attrP->greaterThan; } if (attrP->toSet & LWM2M_ATTR_FLAG_LESS_THAN) { watcherP->parameters->lessThan = attrP->lessThan; } if (attrP->toSet & LWM2M_ATTR_FLAG_STEP) { watcherP->parameters->step = attrP->step; } } LOG_ARG("Final toSet: %08X, minPeriod: %d, maxPeriod: %d, greaterThan: %f, lessThan: %f, step: %f", watcherP->parameters->toSet, watcherP->parameters->minPeriod, watcherP->parameters->maxPeriod, watcherP->parameters->greaterThan, watcherP->parameters->lessThan, watcherP->parameters->step); return COAP_204_CHANGED; }
int json_serialize(lwm2m_uri_t * uriP, int size, lwm2m_data_t * tlvP, uint8_t ** bufferP) { int index; size_t head; uint8_t bufferJSON[PRV_JSON_BUFFER_SIZE]; uint8_t baseUriStr[URI_MAX_STRING_LEN]; int baseUriLen; uri_depth_t rootLevel; int num; lwm2m_data_t * targetP; LOG_ARG("size: %d", size); LOG_URI(uriP); if (size != 0 && tlvP == NULL) return -1; baseUriLen = uri_toString(uriP, baseUriStr, URI_MAX_STRING_LEN, &rootLevel); if (baseUriLen < 0) return -1; num = prv_findAndCheckData(uriP, rootLevel, size, tlvP, &targetP); if (num < 0) return -1; while (num == 1 && (targetP->type == LWM2M_TYPE_OBJECT || targetP->type == LWM2M_TYPE_OBJECT_INSTANCE || targetP->type == LWM2M_TYPE_MULTIPLE_RESOURCE)) { int res; res = utils_intToText(targetP->id, baseUriStr + baseUriLen, URI_MAX_STRING_LEN - baseUriLen); if (res <= 0) return 0; baseUriLen += res; if (baseUriLen >= URI_MAX_STRING_LEN -1) return 0; num = targetP->value.asChildren.count; targetP = targetP->value.asChildren.array; baseUriStr[baseUriLen] = '/'; baseUriLen++; } if (baseUriLen > 0) { memcpy(bufferJSON, JSON_BN_HEADER_1, JSON_BN_HEADER_1_SIZE); head = JSON_BN_HEADER_1_SIZE; memcpy(bufferJSON + head, baseUriStr, baseUriLen); head += baseUriLen; memcpy(bufferJSON + head, JSON_BN_HEADER_2, JSON_BN_HEADER_2_SIZE); head += JSON_BN_HEADER_2_SIZE; } else { memcpy(bufferJSON, JSON_HEADER, JSON_HEADER_SIZE); head = JSON_HEADER_SIZE; } for (index = 0 ; index < num && head < PRV_JSON_BUFFER_SIZE ; index++) { int res; res = prv_serializeData(targetP + index, NULL, 0, bufferJSON + head, PRV_JSON_BUFFER_SIZE - head); if (res < 0) return res; head += res; } if (head + JSON_FOOTER_SIZE - 1 > PRV_JSON_BUFFER_SIZE) return 0; if (num > 0) head = head - 1; memcpy(bufferJSON + head, JSON_FOOTER, JSON_FOOTER_SIZE); head = head + JSON_FOOTER_SIZE; *bufferP = (uint8_t *)lwm2m_malloc(head); if (*bufferP == NULL) return -1; memcpy(*bufferP, bufferJSON, head); return head; }
int senml_json_parse(const lwm2m_uri_t * uriP, const uint8_t * buffer, size_t bufferLen, lwm2m_data_t ** dataP) { size_t index; int count = 0; _record_t * recordArray; lwm2m_data_t * parsedP; int recordIndex; char baseUri[URI_MAX_STRING_LEN + 1]; time_t baseTime; lwm2m_data_t baseValue; LOG_ARG("bufferLen: %d, buffer: \"%s\"", bufferLen, (char *)buffer); LOG_URI(uriP); *dataP = NULL; recordArray = NULL; parsedP = NULL; index = json_skipSpace(buffer, bufferLen); if (index == bufferLen) return -1; if (buffer[index] != JSON_HEADER) return -1; _GO_TO_NEXT_CHAR(index, buffer, bufferLen); count = json_countItems(buffer + index, bufferLen - index); if (count <= 0) goto error; recordArray = (_record_t*)lwm2m_malloc(count * sizeof(_record_t)); if (recordArray == NULL) goto error; /* at this point we are sure buffer[index] is '{' and all { and } are matching */ recordIndex = 0; baseUri[0] = '\0'; baseTime = 0; memset(&baseValue, 0, sizeof(baseValue)); while (recordIndex < count) { int itemLen = json_itemLength(buffer + index, bufferLen - index); if (itemLen < 0) goto error; if (prv_parseItem(buffer + index + 1, itemLen - 2, recordArray + recordIndex, baseUri, &baseTime, &baseValue)) { goto error; } recordIndex++; index += itemLen - 1; _GO_TO_NEXT_CHAR(index, buffer, bufferLen); switch (buffer[index]) { case JSON_SEPARATOR: _GO_TO_NEXT_CHAR(index, buffer, bufferLen); break; case JSON_FOOTER: if (recordIndex != count) goto error; break; default: goto error; } } if (buffer[index] != JSON_FOOTER) goto error; lwm2m_data_t * resultP; int size; count = prv_convertRecord(recordArray, count, &parsedP); lwm2m_free(recordArray); recordArray = NULL; if (count > 0 && uriP != NULL && LWM2M_URI_IS_SET_OBJECT(uriP)) { if (parsedP->type != LWM2M_TYPE_OBJECT) goto error; if (parsedP->id != uriP->objectId) goto error; if (!LWM2M_URI_IS_SET_INSTANCE(uriP)) { size = parsedP->value.asChildren.count; resultP = parsedP->value.asChildren.array; } else { int i; resultP = NULL; /* be permissive and allow full object JSON when requesting for a single instance */ for (i = 0 ; i < (int)parsedP->value.asChildren.count && resultP == NULL; i++) { lwm2m_data_t * targetP; targetP = parsedP->value.asChildren.array + i; if (targetP->id == uriP->instanceId) { resultP = targetP->value.asChildren.array; size = targetP->value.asChildren.count; } } if (resultP == NULL) goto error; if (LWM2M_URI_IS_SET_RESOURCE(uriP)) { lwm2m_data_t * resP; resP = NULL; for (i = 0 ; i < size && resP == NULL; i++) { lwm2m_data_t * targetP; targetP = resultP + i; if (targetP->id == uriP->resourceId) { if (targetP->type == LWM2M_TYPE_MULTIPLE_RESOURCE && LWM2M_URI_IS_SET_RESOURCE_INSTANCE(uriP)) { resP = targetP->value.asChildren.array; size = targetP->value.asChildren.count; } else { size = json_dataStrip(1, targetP, &resP); if (size <= 0) goto error; lwm2m_data_free(count, parsedP); parsedP = NULL; } } } if (resP == NULL) goto error; resultP = resP; } if (LWM2M_URI_IS_SET_RESOURCE_INSTANCE(uriP)) { lwm2m_data_t * resP; resP = NULL; for (i = 0 ; i < size && resP == NULL; i++) { lwm2m_data_t * targetP; targetP = resultP + i; if (targetP->id == uriP->resourceInstanceId) { size = json_dataStrip(1, targetP, &resP); if (size <= 0) goto error; lwm2m_data_free(count, parsedP); parsedP = NULL; } } if (resP == NULL) goto error; resultP = resP; } } } else { resultP = parsedP; size = count; } if (parsedP != NULL) { lwm2m_data_t * tempP; size = json_dataStrip(size, resultP, &tempP); if (size <= 0) goto error; lwm2m_data_free(count, parsedP); resultP = tempP; } count = size; *dataP = resultP; LOG_ARG("Parsing successful. count: %d", count); return count; error: LOG("Parsing failed"); if (parsedP != NULL) { lwm2m_data_free(count, parsedP); parsedP = NULL; } if (recordArray != NULL) { lwm2m_free(recordArray); } return -1; }
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; }
void observe_step(lwm2m_context_t * contextP, time_t currentTime, time_t * timeoutP) { lwm2m_observed_t * targetP; LOG("Entering"); for (targetP = contextP->observedList ; targetP != NULL ; targetP = targetP->next) { lwm2m_watcher_t * watcherP; uint8_t * buffer = NULL; size_t length = 0; lwm2m_data_t * dataP = NULL; int size = 0; double floatValue = 0; int64_t integerValue = 0; bool storeValue = false; coap_packet_t message[1]; time_t interval; LOG_URI(&(targetP->uri)); if (LWM2M_URI_IS_SET_RESOURCE(&targetP->uri)) { if (COAP_205_CONTENT != object_readData(contextP, &targetP->uri, &size, &dataP)) continue; switch (dataP->type) { case LWM2M_TYPE_INTEGER: if (1 != lwm2m_data_decode_int(dataP, &integerValue)) { lwm2m_data_free(size, dataP); continue; } storeValue = true; break; case LWM2M_TYPE_FLOAT: if (1 != lwm2m_data_decode_float(dataP, &floatValue)) { lwm2m_data_free(size, dataP); continue; } storeValue = true; break; default: break; } } for (watcherP = targetP->watcherList ; watcherP != NULL ; watcherP = watcherP->next) { if (watcherP->active == true) { bool notify = false; if (watcherP->update == true) { // value changed, should we notify the server ? if (watcherP->parameters == NULL || watcherP->parameters->toSet == 0) { // no conditions notify = true; LOG("Notify with no conditions"); LOG_URI(&(targetP->uri)); } if (notify == false && watcherP->parameters != NULL && (watcherP->parameters->toSet & ATTR_FLAG_NUMERIC) != 0) { if ((watcherP->parameters->toSet & LWM2M_ATTR_FLAG_LESS_THAN) != 0) { LOG("Checking lower threshold"); // Did we cross the lower threshold ? switch (dataP->type) { case LWM2M_TYPE_INTEGER: if ((integerValue <= watcherP->parameters->lessThan && watcherP->lastValue.asInteger > watcherP->parameters->lessThan) || (integerValue >= watcherP->parameters->lessThan && watcherP->lastValue.asInteger < watcherP->parameters->lessThan)) { LOG("Notify on lower threshold crossing"); notify = true; } break; case LWM2M_TYPE_FLOAT: if ((floatValue <= watcherP->parameters->lessThan && watcherP->lastValue.asFloat > watcherP->parameters->lessThan) || (floatValue >= watcherP->parameters->lessThan && watcherP->lastValue.asFloat < watcherP->parameters->lessThan)) { LOG("Notify on lower threshold crossing"); notify = true; } break; default: break; } } if ((watcherP->parameters->toSet & LWM2M_ATTR_FLAG_GREATER_THAN) != 0) { LOG("Checking upper threshold"); // Did we cross the upper threshold ? switch (dataP->type) { case LWM2M_TYPE_INTEGER: if ((integerValue <= watcherP->parameters->greaterThan && watcherP->lastValue.asInteger > watcherP->parameters->greaterThan) || (integerValue >= watcherP->parameters->greaterThan && watcherP->lastValue.asInteger < watcherP->parameters->greaterThan)) { LOG("Notify on lower upper crossing"); notify = true; } break; case LWM2M_TYPE_FLOAT: if ((floatValue <= watcherP->parameters->greaterThan && watcherP->lastValue.asFloat > watcherP->parameters->greaterThan) || (floatValue >= watcherP->parameters->greaterThan && watcherP->lastValue.asFloat < watcherP->parameters->greaterThan)) { LOG("Notify on lower upper crossing"); notify = true; } break; default: break; } } if ((watcherP->parameters->toSet & LWM2M_ATTR_FLAG_STEP) != 0) { LOG("Checking step"); switch (dataP->type) { case LWM2M_TYPE_INTEGER: { int64_t diff; diff = integerValue - watcherP->lastValue.asInteger; if ((diff < 0 && (0 - diff) >= watcherP->parameters->step) || (diff >= 0 && diff >= watcherP->parameters->step)) { LOG("Notify on step condition"); notify = true; } } break; case LWM2M_TYPE_FLOAT: { double diff; diff = floatValue - watcherP->lastValue.asFloat; if ((diff < 0 && (0 - diff) >= watcherP->parameters->step) || (diff >= 0 && diff >= watcherP->parameters->step)) { LOG("Notify on step condition"); notify = true; } } break; default: break; } } } if (watcherP->parameters != NULL && (watcherP->parameters->toSet & LWM2M_ATTR_FLAG_MIN_PERIOD) != 0) { LOG_ARG("Checking minimal period (%d s)", watcherP->parameters->minPeriod); if (watcherP->lastTime + watcherP->parameters->minPeriod > currentTime) { // Minimum Period did not elapse yet interval = watcherP->lastTime + watcherP->parameters->minPeriod - currentTime; if (*timeoutP > interval) *timeoutP = interval; notify = false; } else { LOG("Notify on minimal period"); notify = true; } } } // Is the Maximum Period reached ? if (notify == false && watcherP->parameters != NULL && (watcherP->parameters->toSet & LWM2M_ATTR_FLAG_MAX_PERIOD) != 0) { LOG_ARG("Checking maximal period (%d s)", watcherP->parameters->minPeriod); if (watcherP->lastTime + watcherP->parameters->maxPeriod <= currentTime) { LOG("Notify on maximal period"); notify = true; } } if (notify == true) { if (buffer == NULL) { if (dataP != NULL) { int res; res = lwm2m_data_serialize(&targetP->uri, size, dataP, &(watcherP->format), &buffer); if (res < 0) { break; } else { length = (size_t)res; } } else { if (COAP_205_CONTENT != object_read(contextP, &targetP->uri, &(watcherP->format), &buffer, &length)) { buffer = NULL; break; } } coap_init_message(message, COAP_TYPE_NON, COAP_205_CONTENT, 0); coap_set_header_content_type(message, watcherP->format); coap_set_payload(message, buffer, length); } watcherP->lastTime = currentTime; watcherP->lastMid = contextP->nextMID++; message->mid = watcherP->lastMid; coap_set_header_token(message, watcherP->token, watcherP->tokenLen); coap_set_header_observe(message, watcherP->counter++); (void)message_send(contextP, message, watcherP->server->sessionH); watcherP->update = false; } // Store this value if (notify == true && storeValue == true) { switch (dataP->type) { case LWM2M_TYPE_INTEGER: watcherP->lastValue.asInteger = integerValue; break; case LWM2M_TYPE_FLOAT: watcherP->lastValue.asFloat = floatValue; break; default: break; } } if (watcherP->parameters != NULL && (watcherP->parameters->toSet & LWM2M_ATTR_FLAG_MAX_PERIOD) != 0) { // update timers interval = watcherP->lastTime + watcherP->parameters->maxPeriod - currentTime; if (*timeoutP > interval) *timeoutP = interval; } } } if (dataP != NULL) lwm2m_data_free(size, dataP); if (buffer != NULL) lwm2m_free(buffer); } }
bool parseURI(string stringUri, URI &uri) { /* * schema://[username[:password]@]host[:port][/[path[?parameters]]] */ LOG_URI("------------------------"); LOG_URI("stringUri: `%s`", STR(stringUri)); string fullUri; string fullUriWithAuth = stringUri; string scheme; string authentication; string username; string password; string hostPort; string host; string portString; uint16_t port; bool portSpecified; string fullDocumentPathWithParameters; string fullDocumentPath; string fullParameters; string documentPath; string document; string documentWithFullParameters; Variant parameters; string::size_type cursor = 0; string::size_type pos = 0; //1. Reset uri.Reset(); //2. trim trim(stringUri); if (stringUri == "") { FATAL("Empty uri"); return false; } //2. Get the scheme and the default port pos = stringUri.find("://", cursor); if (pos == string::npos) { FATAL("Unable to determine scheme"); return false; } scheme = lowerCase(stringUri.substr(cursor, pos - cursor)); cursor = pos + 3; if (_schemeToPort.size() == 0) { _schemeToPort["http"] = 80; _schemeToPort["rtmpt"] = 80; _schemeToPort["rtmpte"] = 80; _schemeToPort["https"] = 443; _schemeToPort["rtmps"] = 443; _schemeToPort["rtsp"] = 554; _schemeToPort["rtmp"] = 1935; _schemeToPort["rtmpe"] = 1935; _schemeToPort["mms"] = 1755; } if (MAP_HAS1(_schemeToPort, scheme)) { port = _schemeToPort[scheme]; } // else { // FATAL("Scheme `%s` not supported", STR(scheme)); // return false; // } LOG_URI("scheme: %s; default port: %"PRIu16, STR(scheme), port); //3. get the authentication portion. the search starts from //where the scheme detection left and up to the first / character string::size_type limit = stringUri.find("/", cursor); bool hasAuthentication = false; pos = stringUri.find("@", cursor); if (pos != string::npos) { if (limit != string::npos) { hasAuthentication = pos<limit; } hasAuthentication = true; } if (hasAuthentication) { authentication = stringUri.substr(cursor, pos - cursor); fullUri = stringUri.substr(0, cursor); fullUri += stringUri.substr(pos + 1); cursor = pos + 1; } else { fullUri = fullUriWithAuth; } if (authentication != "") { pos = authentication.find(":"); if (pos != string::npos) { username = authentication.substr(0, pos); password = authentication.substr(pos + 1); } else { username = authentication; password = ""; } } LOG_URI("fullUri: `%s`; fullUriWithAuth: `%s`", STR(fullUri), STR(fullUriWithAuth)); LOG_URI("username: `%s`; password: `%s`", STR(username), STR(password)); //4. Get the host:port pos = stringUri.find("/", cursor); if (pos == string::npos) { hostPort = stringUri.substr(cursor); cursor = stringUri.size() - 1; fullDocumentPathWithParameters = "/"; } else { hostPort = stringUri.substr(cursor, pos - cursor); cursor = pos + 1; fullDocumentPathWithParameters = "/" + stringUri.substr(cursor); } trim(hostPort); if (hostPort == "") { FATAL("Invalid host:port specified"); return false; } pos = hostPort.find(":"); if (pos == string::npos) { host = hostPort; portSpecified = false; } else { host = hostPort.substr(0, pos); trim(host); portString = hostPort.substr(pos + 1); portSpecified = true; port = (uint16_t) atoi(STR(portString)); if (format("%"PRIu16, port) != portString) { FATAL("Invalid port number specified: `%s`", STR(portString)); return false; } } LOG_URI("host: %s; port: %"PRIu16"; portSpecified: %d", STR(host), port, portSpecified); //5. fullDocumentPathWithParameters fullDocumentPath = "/"; fullParameters = ""; documentPath = "/"; document = ""; documentWithFullParameters = ""; parameters.Reset(); parameters.IsArray(false); if (fullDocumentPathWithParameters != "/") { pos = fullDocumentPathWithParameters.find("?"); if (pos == string::npos) { fullDocumentPath = fullDocumentPathWithParameters; fullParameters = ""; } else { fullDocumentPath = fullDocumentPathWithParameters.substr(0, pos); fullParameters = fullDocumentPathWithParameters.substr(pos + 1); } trim(fullParameters); if (fullParameters != "") { vector<string> elements; split(fullParameters, "&", elements); for (uint32_t i = 0; i < elements.size(); i++) { string kvp = elements[i]; if (kvp == "") continue; string k = ""; string v = ""; pos = kvp.find("="); if (pos == string::npos) { k = kvp; v = ""; } else { k = kvp.substr(0, pos); v = kvp.substr(pos + 1); } if (k == "") continue; parameters[k] = v; } } for (string::size_type i = fullDocumentPath.size() - 1; i >= 0; i--) { if (fullDocumentPath[i] == '/') break; document = fullDocumentPath[i] + document; } documentPath = fullDocumentPath.substr(0, fullDocumentPath.size() - document.size()); documentWithFullParameters = document; if (fullParameters != "") documentWithFullParameters += "?" + fullParameters; } LOG_URI("fullDocumentPathWithParameters: `%s`", STR(fullDocumentPathWithParameters)); LOG_URI("fullDocumentPath: `%s`", STR(fullDocumentPath)); LOG_URI("fullParameters: `%s`", STR(fullParameters)); LOG_URI("documentPath: `%s`", STR(documentPath)); LOG_URI("document: `%s`", STR(document)); LOG_URI("documentWithFullParameters: `%s`", STR(documentWithFullParameters)); LOG_URI("parameters:"); #ifdef DEBUG_URI FOR_MAP(parameters, string, Variant, i) { LOG_URI("\t`%s`: `%s`", STR(MAP_KEY(i)), STR(MAP_VAL(i))); }
int senml_json_serialize(const lwm2m_uri_t * uriP, int size, const lwm2m_data_t * tlvP, uint8_t ** bufferP) { int index; size_t head; uint8_t bufferJSON[PRV_JSON_BUFFER_SIZE]; uint8_t baseUriStr[URI_MAX_STRING_LEN]; int baseUriLen; uri_depth_t rootLevel; uri_depth_t baseLevel; int num; lwm2m_data_t * targetP; const uint8_t *parentUriStr = NULL; size_t parentUriLen = 0; LOG_ARG("size: %d", size); LOG_URI(uriP); if (size != 0 && tlvP == NULL) return -1; baseUriLen = uri_toString(uriP, baseUriStr, URI_MAX_STRING_LEN, &baseLevel); if (baseUriLen < 0) return -1; if (baseUriLen > 1 && baseLevel != URI_DEPTH_RESOURCE && baseLevel != URI_DEPTH_RESOURCE_INSTANCE) { if (baseUriLen >= URI_MAX_STRING_LEN -1) return 0; baseUriStr[baseUriLen++] = '/'; } num = json_findAndCheckData(uriP, json_decreaseLevel(baseLevel), size, tlvP, &targetP); if (num < 0) return -1; switch (tlvP->type) { case LWM2M_TYPE_OBJECT: rootLevel = URI_DEPTH_OBJECT; break; case LWM2M_TYPE_OBJECT_INSTANCE: rootLevel = URI_DEPTH_OBJECT_INSTANCE; break; case LWM2M_TYPE_MULTIPLE_RESOURCE: if (baseUriLen > 1 && baseUriStr[baseUriLen - 1] != '/') { if (baseUriLen >= URI_MAX_STRING_LEN -1) return 0; baseUriStr[baseUriLen++] = '/'; } rootLevel = URI_DEPTH_RESOURCE_INSTANCE; break; default: if (baseLevel == URI_DEPTH_RESOURCE_INSTANCE) { rootLevel = URI_DEPTH_RESOURCE_INSTANCE; } else { rootLevel = URI_DEPTH_RESOURCE; } break; } if (!baseUriLen || baseUriStr[baseUriLen - 1] != '/') { parentUriStr = (const uint8_t *)"/"; parentUriLen = 1; } head = 0; bufferJSON[head++] = JSON_HEADER; bool baseNameOutput = false; for (index = 0 ; index < num && head < PRV_JSON_BUFFER_SIZE ; index++) { int res; if (index != 0) { if (head + 1 > PRV_JSON_BUFFER_SIZE) return 0; bufferJSON[head++] = JSON_SEPARATOR; } res = prv_serializeData(targetP + index, baseUriStr, baseUriLen, baseLevel, parentUriStr, parentUriLen, rootLevel, &baseNameOutput, bufferJSON + head, PRV_JSON_BUFFER_SIZE - head); if (res < 0) return res; head += res; } if (head + 1 > PRV_JSON_BUFFER_SIZE) return 0; bufferJSON[head++] = JSON_FOOTER; *bufferP = (uint8_t *)lwm2m_malloc(head); if (*bufferP == NULL) return -1; memcpy(*bufferP, bufferJSON, head); return head; }
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; }
int json_parse(lwm2m_uri_t * uriP, uint8_t * buffer, size_t bufferLen, lwm2m_data_t ** dataP) { size_t index; int count = 0; bool eFound = false; bool bnFound = false; bool btFound = false; int bnStart; int bnLen; _record_t * recordArray; lwm2m_data_t * parsedP; LOG_ARG("bufferLen: %d, buffer: \"%s\"", bufferLen, (char *)buffer); LOG_URI(uriP); *dataP = NULL; recordArray = NULL; parsedP = NULL; index = prv_skipSpace(buffer, bufferLen); if (index == bufferLen) return -1; if (buffer[index] != '{') return -1; do { _GO_TO_NEXT_CHAR(index, buffer, bufferLen); if (buffer[index] != '"') goto error; if (index++ >= bufferLen) goto error; switch (buffer[index]) { case 'e': { int recordIndex; if (bufferLen-index < JSON_MIN_ARRAY_LEN) goto error; index++; if (buffer[index] != '"') goto error; if (eFound == true) goto error; eFound = true; _GO_TO_NEXT_CHAR(index, buffer, bufferLen); if (buffer[index] != ':') goto error; _GO_TO_NEXT_CHAR(index, buffer, bufferLen); if (buffer[index] != '[') goto error; _GO_TO_NEXT_CHAR(index, buffer, bufferLen); count = prv_countItems(buffer + index, bufferLen - index); if (count <= 0) goto error; recordArray = (_record_t*)lwm2m_malloc(count * sizeof(_record_t)); if (recordArray == NULL) goto error; // at this point we are sure buffer[index] is '{' and all { and } are matching recordIndex = 0; while (recordIndex < count) { int itemLen; if (buffer[index] != '{') goto error; itemLen = 0; while (buffer[index + itemLen] != '}') itemLen++; if (0 != prv_parseItem(buffer + index + 1, itemLen - 1, recordArray + recordIndex)) { goto error; } recordIndex++; index += itemLen; _GO_TO_NEXT_CHAR(index, buffer, bufferLen); switch (buffer[index]) { case ',': _GO_TO_NEXT_CHAR(index, buffer, bufferLen); break; case ']': if (recordIndex == count) break; // else this is an error default: goto error; } } if (buffer[index] != ']') goto error; } break; case 'b': if (bufferLen-index < JSON_MIN_BX_LEN) goto error; index++; switch (buffer[index]) { case 't': index++; if (buffer[index] != '"') goto error; if (btFound == true) goto error; btFound = true; // TODO: handle timed values // temp: skip this token while(index < bufferLen && buffer[index] != ',' && buffer[index] != '}') index++; if (index == bufferLen) goto error; index--; // end temp break; case 'n': { int next; int tokenStart; int tokenLen; int itemLen; index++; if (buffer[index] != '"') goto error; if (bnFound == true) goto error; bnFound = true; index -= 3; itemLen = 0; while (buffer[index + itemLen] != '}' && buffer[index + itemLen] != ',' && index + itemLen < bufferLen) { itemLen++; } if (index + itemLen == bufferLen) goto error; next = prv_split(buffer+index, itemLen, &tokenStart, &tokenLen, &bnStart, &bnLen); if (next < 0) goto error; bnStart += index; index += next - 1; } break; default: goto error; } break; default: goto error; } _GO_TO_NEXT_CHAR(index, buffer, bufferLen); } while (buffer[index] == ','); if (buffer[index] != '}') goto error; if (eFound == true) { lwm2m_uri_t baseURI; lwm2m_uri_t * baseUriP; lwm2m_data_t * resultP; int size; memset(&baseURI, 0, sizeof(lwm2m_uri_t)); if (bnFound == false) { baseUriP = uriP; } else { int res; // we ignore the request URI and use the bn one. // Check for " around URI if (bnLen < 3 || buffer[bnStart] != '"' || buffer[bnStart+bnLen-1] != '"') { goto error; } bnStart += 1; bnLen -= 2; if (bnLen == 1) { if (buffer[bnStart] != '/') goto error; baseUriP = NULL; } else { res = lwm2m_stringToUri((char *)buffer + bnStart, bnLen, &baseURI); if (res < 0 || res != bnLen) goto error; baseUriP = &baseURI; } } count = prv_convertRecord(baseUriP, recordArray, count, &parsedP); lwm2m_free(recordArray); recordArray = NULL; if (count > 0 && uriP != NULL) { if (parsedP->type != LWM2M_TYPE_OBJECT || parsedP->id != uriP->objectId) goto error; if (!LWM2M_URI_IS_SET_INSTANCE(uriP)) { size = parsedP->value.asChildren.count; resultP = parsedP->value.asChildren.array; } else { int i; resultP = NULL; // be permissive and allow full object JSON when requesting for a single instance for (i = 0 ; i < (int)parsedP->value.asChildren.count && resultP == NULL; i++) { lwm2m_data_t * targetP; targetP = parsedP->value.asChildren.array + i; if (targetP->id == uriP->instanceId) { resultP = targetP->value.asChildren.array; size = targetP->value.asChildren.count; } } if (resultP == NULL) goto error; if (LWM2M_URI_IS_SET_RESOURCE(uriP)) { lwm2m_data_t * resP; resP = NULL; for (i = 0 ; i < size && resP == NULL; i++) { lwm2m_data_t * targetP; targetP = resultP + i; if (targetP->id == uriP->resourceId) { if (targetP->type == LWM2M_TYPE_MULTIPLE_RESOURCE) { resP = targetP->value.asChildren.array; size = targetP->value.asChildren.count; } else { size = prv_dataStrip(1, targetP, &resP); if (size <= 0) goto error; lwm2m_data_free(count, parsedP); parsedP = NULL; } } } if (resP == NULL) goto error; resultP = resP; } } } else { resultP = parsedP; size = count; } if (parsedP != NULL) { lwm2m_data_t * tempP; size = prv_dataStrip(size, resultP, &tempP); if (size <= 0) goto error; lwm2m_data_free(count, parsedP); resultP = tempP; } count = size; *dataP = resultP; } LOG_ARG("Parsing successful. count: %d", count); return count; error: LOG("Parsing failed"); if (parsedP != NULL) { lwm2m_data_free(count, parsedP); parsedP = NULL; } if (recordArray != NULL) { lwm2m_free(recordArray); } return -1; }
int lwm2m_observe(lwm2m_context_t * contextP, uint16_t clientID, lwm2m_uri_t * uriP, lwm2m_result_callback_t callback, void * userData) { lwm2m_client_t * clientP; lwm2m_transaction_t * transactionP; lwm2m_observation_t * observationP; uint8_t token[4]; LOG_ARG("clientID: %d", clientID); LOG_URI(uriP); if (!LWM2M_URI_IS_SET_INSTANCE(uriP) && LWM2M_URI_IS_SET_RESOURCE(uriP)) return COAP_400_BAD_REQUEST; clientP = (lwm2m_client_t *)lwm2m_list_find((lwm2m_list_t *)contextP->clientList, clientID); if (clientP == NULL) return COAP_404_NOT_FOUND; for (observationP = clientP->observationList; observationP != NULL; observationP = observationP->next) { if (uriP->objectId == observationP->uri.objectId && (LWM2M_URI_IS_SET_INSTANCE(uriP) == false || observationP->uri.instanceId == uriP->instanceId) && (LWM2M_URI_IS_SET_INSTANCE(uriP) == false || observationP->uri.instanceId == uriP->instanceId)) { break; } } if (observationP == NULL) { observationP = (lwm2m_observation_t *)lwm2m_malloc(sizeof(lwm2m_observation_t)); if (observationP == NULL) return COAP_500_INTERNAL_SERVER_ERROR; memset(observationP, 0, sizeof(lwm2m_observation_t)); observationP->id = lwm2m_list_newId((lwm2m_list_t *)clientP->observationList); memcpy(&observationP->uri, uriP, sizeof(lwm2m_uri_t)); observationP->clientP = clientP; observationP->clientP->observationList = (lwm2m_observation_t *)LWM2M_LIST_ADD(observationP->clientP->observationList, observationP); } observationP->status = STATE_REG_PENDING; observationP->callback = callback; observationP->userData = userData; token[0] = clientP->internalID >> 8; token[1] = clientP->internalID & 0xFF; token[2] = observationP->id >> 8; token[3] = observationP->id & 0xFF; transactionP = transaction_new(clientP->sessionH, COAP_GET, clientP->altPath, uriP, contextP->nextMID++, 4, token); if (transactionP == NULL) { observationP->clientP->observationList = (lwm2m_observation_t *)LWM2M_LIST_RM(observationP->clientP->observationList, observationP->id, NULL); lwm2m_free(observationP); return COAP_500_INTERNAL_SERVER_ERROR; } coap_set_header_observe(transactionP->message, 0); if (clientP->supportJSON == true) { coap_set_header_accept(transactionP->message, LWM2M_CONTENT_JSON); } else { coap_set_header_accept(transactionP->message, LWM2M_CONTENT_TLV); } transactionP->callback = prv_obsRequestCallback; transactionP->userData = (void *)observationP; contextP->transactionList = (lwm2m_transaction_t *)LWM2M_LIST_ADD(contextP->transactionList, transactionP); return transaction_send(contextP, transactionP); }
lwm2m_transaction_t * transaction_new(void * sessionH, coap_method_t method, char * altPath, lwm2m_uri_t * uriP, uint16_t mID, uint8_t token_len, uint8_t* token) { lwm2m_transaction_t * transacP; int result; LOG_ARG("method: %d, altPath: \"%s\", mID: %d, token_len: %d", method, altPath, mID, token_len); LOG_URI(uriP); // no transactions without peer if (NULL == sessionH) return NULL; transacP = (lwm2m_transaction_t *)lwm2m_malloc(sizeof(lwm2m_transaction_t)); if (NULL == transacP) return NULL; memset(transacP, 0, sizeof(lwm2m_transaction_t)); transacP->message = lwm2m_malloc(sizeof(coap_packet_t)); if (NULL == transacP->message) goto error; coap_init_message(transacP->message, COAP_TYPE_CON, method, mID); transacP->peerH = sessionH; transacP->mID = mID; if (altPath != NULL) { // TODO: Support multi-segment alternative path coap_set_header_uri_path_segment(transacP->message, altPath + 1); } if (NULL != uriP) { char stringID[LWM2M_STRING_ID_MAX_LEN]; result = utils_intToText(uriP->objectId, (uint8_t*)stringID, LWM2M_STRING_ID_MAX_LEN); if (result == 0) goto error; stringID[result] = 0; coap_set_header_uri_path_segment(transacP->message, stringID); if (LWM2M_URI_IS_SET_INSTANCE(uriP)) { result = utils_intToText(uriP->instanceId, (uint8_t*)stringID, LWM2M_STRING_ID_MAX_LEN); if (result == 0) goto error; stringID[result] = 0; coap_set_header_uri_path_segment(transacP->message, stringID); } else { if (LWM2M_URI_IS_SET_RESOURCE(uriP)) { coap_set_header_uri_path_segment(transacP->message, NULL); } } if (LWM2M_URI_IS_SET_RESOURCE(uriP)) { result = utils_intToText(uriP->resourceId, (uint8_t*)stringID, LWM2M_STRING_ID_MAX_LEN); if (result == 0) goto error; stringID[result] = 0; coap_set_header_uri_path_segment(transacP->message, stringID); } } if (0 < token_len) { if (NULL != token) { coap_set_header_token(transacP->message, token, token_len); } else { // generate a token uint8_t temp_token[COAP_TOKEN_LEN]; time_t tv_sec = lwm2m_gettime(); // initialize first 6 bytes, leave the last 2 random temp_token[0] = mID; temp_token[1] = mID >> 8; temp_token[2] = tv_sec; temp_token[3] = tv_sec >> 8; temp_token[4] = tv_sec >> 16; temp_token[5] = tv_sec >> 24; // use just the provided amount of bytes coap_set_header_token(transacP->message, temp_token, token_len); } } LOG("Exiting on success"); return transacP; error: LOG("Exiting on failure"); lwm2m_free(transacP); return NULL; }
int lwm2m_observe_cancel(lwm2m_context_t * contextP, uint16_t clientID, lwm2m_uri_t * uriP, lwm2m_result_callback_t callback, void * userData) { lwm2m_client_t * clientP; lwm2m_observation_t * observationP; LOG_ARG("clientID: %d", clientID); LOG_URI(uriP); clientP = (lwm2m_client_t *)lwm2m_list_find((lwm2m_list_t *)contextP->clientList, clientID); if (clientP == NULL) return COAP_404_NOT_FOUND; observationP = prv_findObservationByURI(clientP, uriP); if (observationP == NULL) return COAP_404_NOT_FOUND; switch (observationP->status) { case STATE_REGISTERED: { lwm2m_transaction_t * transactionP; cancellation_data_t * cancelP; uint8_t token[4]; token[0] = clientP->internalID >> 8; token[1] = clientP->internalID & 0xFF; token[2] = observationP->id >> 8; token[3] = observationP->id & 0xFF; transactionP = transaction_new(clientP->sessionH, COAP_GET, clientP->altPath, uriP, contextP->nextMID++, 4, token); if (transactionP == NULL) { return COAP_500_INTERNAL_SERVER_ERROR; } cancelP = (cancellation_data_t *)lwm2m_malloc(sizeof(cancellation_data_t)); if (cancelP == NULL) { lwm2m_free(transactionP); return COAP_500_INTERNAL_SERVER_ERROR; } coap_set_header_observe(transactionP->message, 1); cancelP->observationP = observationP; cancelP->callbackP = callback; cancelP->userDataP = userData; transactionP->callback = prv_obsCancelRequestCallback; transactionP->userData = (void *)cancelP; contextP->transactionList = (lwm2m_transaction_t *)LWM2M_LIST_ADD(contextP->transactionList, transactionP); return transaction_send(contextP, transactionP); } case STATE_REG_PENDING: observationP->status = STATE_DEREG_PENDING; break; default: // Should not happen break; } return COAP_NO_ERROR; }
int lwm2m_stringToUri(const char * buffer, size_t buffer_len, lwm2m_uri_t * uriP) { size_t head; int readNum; LOG_ARG("buffer_len: %u, buffer: \"%.*s\"", buffer_len, buffer_len, buffer); if (buffer == NULL || buffer_len == 0 || uriP == NULL) return 0; memset(uriP, 0, sizeof(lwm2m_uri_t)); // Skip any white space head = 0; while (head < buffer_len && isspace(buffer[head]&0xFF)) { head++; } if (head == buffer_len) return 0; // Check the URI start with a '/' if (buffer[head] != '/') return 0; head++; if (head == buffer_len) return 0; // Read object ID readNum = prv_parseNumber((uint8_t *)buffer, buffer_len, &head); if (readNum < 0 || readNum > LWM2M_MAX_ID) return 0; uriP->objectId = (uint16_t)readNum; uriP->flag |= LWM2M_URI_FLAG_OBJECT_ID; if (buffer[head] == '/') head += 1; if (head >= buffer_len) { LOG_ARG("Parsed characters: %u", head); LOG_URI(uriP); return head; } readNum = prv_parseNumber((uint8_t *)buffer, buffer_len, &head); if (readNum < 0 || readNum >= LWM2M_MAX_ID) return 0; uriP->instanceId = (uint16_t)readNum; uriP->flag |= LWM2M_URI_FLAG_INSTANCE_ID; if (buffer[head] == '/') head += 1; if (head >= buffer_len) { LOG_ARG("Parsed characters: %u", head); LOG_URI(uriP); return head; } readNum = prv_parseNumber((uint8_t *)buffer, buffer_len, &head); if (readNum < 0 || readNum >= LWM2M_MAX_ID) return 0; uriP->resourceId = (uint16_t)readNum; uriP->flag |= LWM2M_URI_FLAG_RESOURCE_ID; if (head != buffer_len) return 0; LOG_ARG("Parsed characters: %u", head); LOG_URI(uriP); return head; }
int lwm2m_data_serialize(lwm2m_uri_t * uriP, int size, lwm2m_data_t * dataP, lwm2m_media_type_t * formatP, uint8_t ** bufferP) { LOG_URI(uriP); LOG_ARG("size: %d, formatP: %s", size, STR_MEDIA_TYPE(*formatP)); // Check format if (*formatP == LWM2M_CONTENT_TEXT || *formatP == LWM2M_CONTENT_OPAQUE) { if (size != 1 || (uriP != NULL && !LWM2M_URI_IS_SET_RESOURCE(uriP)) || dataP->type == LWM2M_TYPE_OBJECT || dataP->type == LWM2M_TYPE_OBJECT_INSTANCE || dataP->type == LWM2M_TYPE_MULTIPLE_RESOURCE) { #ifdef LWM2M_SUPPORT_JSON *formatP = LWM2M_CONTENT_JSON; #else *formatP = LWM2M_CONTENT_TLV; #endif } } if (*formatP == LWM2M_CONTENT_OPAQUE && dataP->type != LWM2M_TYPE_OPAQUE) { LOG("Opaque format is reserved to opaque resources."); return -1; } LOG_ARG("Final format: %s", STR_MEDIA_TYPE(*formatP)); switch (*formatP) { case LWM2M_CONTENT_TEXT: return prv_textSerialize(dataP, bufferP); case LWM2M_CONTENT_OPAQUE: *bufferP = (uint8_t *)lwm2m_malloc(dataP->value.asBuffer.length); if (*bufferP == NULL) return -1; memcpy(*bufferP, dataP->value.asBuffer.buffer, dataP->value.asBuffer.length); return (int)dataP->value.asBuffer.length; case LWM2M_CONTENT_TLV: case LWM2M_CONTENT_TLV_OLD: { bool isResourceInstance; if (uriP != NULL && LWM2M_URI_IS_SET_RESOURCE(uriP) && (size != 1 || dataP->id != uriP->resourceId)) { isResourceInstance = true; } else { isResourceInstance = false; } return tlv_serialize(isResourceInstance, size, dataP, bufferP); } #ifdef LWM2M_CLIENT_MODE case LWM2M_CONTENT_LINK: return discover_serialize(NULL, uriP, NULL, size, dataP, bufferP); #endif #ifdef LWM2M_SUPPORT_JSON case LWM2M_CONTENT_JSON: case LWM2M_CONTENT_JSON_OLD: return json_serialize(uriP, size, dataP, bufferP); #endif default: return -1; } }
lwm2m_uri_t * uri_decode(char * altPath, multi_option_t *uriPath) { lwm2m_uri_t * uriP; int readNum; LOG_ARG("altPath: \"%s\"", altPath); uriP = (lwm2m_uri_t *)lwm2m_malloc(sizeof(lwm2m_uri_t)); if (NULL == uriP) return NULL; memset(uriP, 0, sizeof(lwm2m_uri_t)); // Read object ID if (NULL != uriPath && URI_REGISTRATION_SEGMENT_LEN == uriPath->len && 0 == strncmp(URI_REGISTRATION_SEGMENT, (char *)uriPath->data, uriPath->len)) { uriP->flag |= LWM2M_URI_FLAG_REGISTRATION; uriPath = uriPath->next; if (uriPath == NULL) return uriP; } else if (NULL != uriPath && URI_BOOTSTRAP_SEGMENT_LEN == uriPath->len && 0 == strncmp(URI_BOOTSTRAP_SEGMENT, (char *)uriPath->data, uriPath->len)) { uriP->flag |= LWM2M_URI_FLAG_BOOTSTRAP; uriPath = uriPath->next; if (uriPath != NULL) goto error; return uriP; } if ((uriP->flag & LWM2M_URI_MASK_TYPE) != LWM2M_URI_FLAG_REGISTRATION) { // Read altPath if any if (altPath != NULL) { int i; if (NULL == uriPath) { lwm2m_free(uriP); return NULL; } for (i = 0 ; i < uriPath->len ; i++) { if (uriPath->data[i] != altPath[i+1]) { lwm2m_free(uriP); return NULL; } } uriPath = uriPath->next; } if (NULL == uriPath || uriPath->len == 0) { uriP->flag |= LWM2M_URI_FLAG_DELETE_ALL; return uriP; } } readNum = uri_getNumber(uriPath->data, uriPath->len); if (readNum < 0 || readNum > LWM2M_MAX_ID) goto error; uriP->objectId = (uint16_t)readNum; uriP->flag |= LWM2M_URI_FLAG_OBJECT_ID; uriPath = uriPath->next; if ((uriP->flag & LWM2M_URI_MASK_TYPE) == LWM2M_URI_FLAG_REGISTRATION) { if (uriPath != NULL) goto error; return uriP; } uriP->flag |= LWM2M_URI_FLAG_DM; if (uriPath == NULL) return uriP; // Read object instance if (uriPath->len != 0) { readNum = uri_getNumber(uriPath->data, uriPath->len); if (readNum < 0 || readNum >= LWM2M_MAX_ID) goto error; uriP->instanceId = (uint16_t)readNum; uriP->flag |= LWM2M_URI_FLAG_INSTANCE_ID; } uriPath = uriPath->next; if (uriPath == NULL) return uriP; // Read resource ID if (uriPath->len != 0) { // resource ID without an instance ID is not allowed if ((uriP->flag & LWM2M_URI_FLAG_INSTANCE_ID) == 0) goto error; readNum = uri_getNumber(uriPath->data, uriPath->len); if (readNum < 0 || readNum > LWM2M_MAX_ID) goto error; uriP->resourceId = (uint16_t)readNum; uriP->flag |= LWM2M_URI_FLAG_RESOURCE_ID; } // must be the last segment if (NULL == uriPath->next) { LOG_URI(uriP); return uriP; } error: LOG("Exiting on error"); lwm2m_free(uriP); return NULL; }
coap_status_t registration_handleRequest(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, void * fromSessionH, coap_packet_t * message, coap_packet_t * response) { coap_status_t result; time_t tv_sec; LOG_URI(uriP); tv_sec = lwm2m_gettime(); if (tv_sec < 0) return COAP_500_INTERNAL_SERVER_ERROR; switch(message->code) { case COAP_POST: { char * name = NULL; uint32_t lifetime; char * msisdn; char * altPath; lwm2m_binding_t binding; lwm2m_client_object_t * objects; bool supportJSON; lwm2m_client_t * clientP; char location[MAX_LOCATION_LENGTH]; if (0 != prv_getParameters(message->uri_query, &name, &lifetime, &msisdn, &binding)) { return COAP_400_BAD_REQUEST; } if (message->content_type != LWM2M_CONTENT_LINK && message->content_type != LWM2M_CONTENT_TEXT) { return COAP_400_BAD_REQUEST; } objects = prv_decodeRegisterPayload(message->payload, message->payload_len, &supportJSON, &altPath); switch (uriP->flag & LWM2M_URI_MASK_ID) { case 0: // Register operation if (objects == NULL) { lwm2m_free(name); if (msisdn != NULL) lwm2m_free(msisdn); return COAP_400_BAD_REQUEST; } // Endpoint client name is mandatory if (name == NULL) { if (msisdn != NULL) lwm2m_free(msisdn); return COAP_400_BAD_REQUEST; } if (lifetime == 0) { lifetime = LWM2M_DEFAULT_LIFETIME; } clientP = prv_getClientByName(contextP, name); if (clientP != NULL) { // we reset this registration lwm2m_free(clientP->name); if (clientP->msisdn != NULL) lwm2m_free(clientP->msisdn); if (clientP->altPath != NULL) lwm2m_free(clientP->altPath); prv_freeClientObjectList(clientP->objectList); clientP->objectList = NULL; } else { clientP = (lwm2m_client_t *)lwm2m_malloc(sizeof(lwm2m_client_t)); if (clientP == NULL) { lwm2m_free(name); lwm2m_free(altPath); if (msisdn != NULL) lwm2m_free(msisdn); prv_freeClientObjectList(objects); return COAP_500_INTERNAL_SERVER_ERROR; } memset(clientP, 0, sizeof(lwm2m_client_t)); clientP->internalID = lwm2m_list_newId((lwm2m_list_t *)contextP->clientList); contextP->clientList = (lwm2m_client_t *)LWM2M_LIST_ADD(contextP->clientList, clientP); } clientP->name = name; clientP->binding = binding; clientP->msisdn = msisdn; clientP->altPath = altPath; clientP->supportJSON = supportJSON; clientP->lifetime = lifetime; clientP->endOfLife = tv_sec + lifetime; clientP->objectList = objects; clientP->sessionH = fromSessionH; if (prv_getLocationString(clientP->internalID, location) == 0) { registration_freeClient(clientP); return COAP_500_INTERNAL_SERVER_ERROR; } if (coap_set_header_location_path(response, location) == 0) { registration_freeClient(clientP); return COAP_500_INTERNAL_SERVER_ERROR; } if (contextP->monitorCallback != NULL) { contextP->monitorCallback(clientP->internalID, NULL, COAP_201_CREATED, LWM2M_CONTENT_TEXT, NULL, 0, contextP->monitorUserData); } result = COAP_201_CREATED; break; case LWM2M_URI_FLAG_OBJECT_ID: clientP = (lwm2m_client_t *)lwm2m_list_find((lwm2m_list_t *)contextP->clientList, uriP->objectId); if (clientP == NULL) return COAP_404_NOT_FOUND; // Endpoint client name MUST NOT be present if (name != NULL) { lwm2m_free(name); if (msisdn != NULL) lwm2m_free(msisdn); return COAP_400_BAD_REQUEST; } if (binding != BINDING_UNKNOWN) { clientP->binding = binding; } if (msisdn != NULL) { if (clientP->msisdn != NULL) lwm2m_free(clientP->msisdn); clientP->msisdn = msisdn; } if (lifetime != 0) { clientP->lifetime = lifetime; } // client IP address, port or MSISDN may have changed clientP->sessionH = fromSessionH; if (objects != NULL) { lwm2m_observation_t * observationP; // remove observations on object/instance no longer existing observationP = clientP->observationList; while (observationP != NULL) { lwm2m_client_object_t * objP; lwm2m_observation_t * nextP; nextP = observationP->next; objP = (lwm2m_client_object_t *)lwm2m_list_find((lwm2m_list_t *)objects, observationP->uri.objectId); if (objP == NULL) { observationP->callback(clientP->internalID, &observationP->uri, COAP_202_DELETED, LWM2M_CONTENT_TEXT, NULL, 0, observationP->userData); observe_remove(clientP, observationP); } else { if ((observationP->uri.flag & LWM2M_URI_FLAG_INSTANCE_ID) != 0) { if (lwm2m_list_find((lwm2m_list_t *)objP->instanceList, observationP->uri.instanceId) == NULL) { observationP->callback(clientP->internalID, &observationP->uri, COAP_202_DELETED, LWM2M_CONTENT_TEXT, NULL, 0, observationP->userData); observe_remove(clientP, observationP); } } } observationP = nextP; } prv_freeClientObjectList(clientP->objectList); clientP->objectList = objects; } clientP->endOfLife = tv_sec + clientP->lifetime; if (contextP->monitorCallback != NULL) { contextP->monitorCallback(clientP->internalID, NULL, COAP_204_CHANGED, LWM2M_CONTENT_TEXT, NULL, 0, contextP->monitorUserData); } result = COAP_204_CHANGED; break; default: return COAP_400_BAD_REQUEST; } } break; case COAP_DELETE: { lwm2m_client_t * clientP; if ((uriP->flag & LWM2M_URI_MASK_ID) != LWM2M_URI_FLAG_OBJECT_ID) return COAP_400_BAD_REQUEST; contextP->clientList = (lwm2m_client_t *)LWM2M_LIST_RM(contextP->clientList, uriP->objectId, &clientP); if (clientP == NULL) return COAP_400_BAD_REQUEST; if (contextP->monitorCallback != NULL) { contextP->monitorCallback(clientP->internalID, NULL, COAP_202_DELETED, LWM2M_CONTENT_TEXT, NULL, 0, contextP->monitorUserData); } registration_freeClient(clientP); result = COAP_202_DELETED; } break; default: return COAP_400_BAD_REQUEST; } return result; }