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; }
int utils_intCopy(char * buffer, size_t length, int32_t value) { #define _PRV_INT32_MAX_STR_LEN 11 uint8_t str[_PRV_INT32_MAX_STR_LEN]; size_t len; len = utils_intToText(value, str, _PRV_INT32_MAX_STR_LEN); if (len == 0) return -1; if (len > length + 1) return -1; memcpy(buffer, str + _PRV_INT32_MAX_STR_LEN - len, len); buffer[len] = 0; return len; }
size_t lwm2m_int64ToPlainText(int64_t data, uint8_t ** bufferP) { #define _PRV_STR_LENGTH 32 uint8_t string[_PRV_STR_LENGTH]; size_t length; length = utils_intToText(data, string, _PRV_STR_LENGTH); if (length == 0) return 0; *bufferP = (uint8_t *)lwm2m_malloc(length); if (NULL == *bufferP) return 0; memcpy(*bufferP, string, length); return length; }
static void test_utils_intToText(void) { size_t i; for (i = 0 ; i < sizeof(ints)/sizeof(ints[0]); i++) { char res[24]; int len; len = utils_intToText(ints[i], (uint8_t*)res, sizeof(res)); CU_ASSERT(len); CU_ASSERT_NSTRING_EQUAL(res, ints_text[i], strlen(ints_text[i])); if (!len) printf("%zu \"%" PRId64 "\" -> fail\n", i, ints[i]); else if (strncmp(res, ints_text[i], strlen(ints_text[i]))) printf("%zu \"%" PRId64 "\" -> fail (%s)\n", i, ints[i], res); } }
size_t utils_floatToText(double data, uint8_t * string, size_t length) { size_t intLength; size_t decLength; int64_t intPart; double decPart; intPart = (int64_t)data; decPart = data - intPart; if (decPart < 0) { decPart = 1 - decPart; } else { decPart = 1 + decPart; } if (decPart <= 1 + FLT_EPSILON) { decPart = 0; } if (intPart == 0 && data < 0) { // deal with numbers between -1 and 0 if (length < 4) return 0; // "-0.n" string[0] = '-'; string[1] = '0'; intLength = 2; } else { intLength = utils_intToText(intPart, string, length); if (intLength == 0) return 0; } decLength = 0; if (decPart != 0) { int i; double noiseFloor; if (intLength >= length - 1) return 0; i = 0; noiseFloor = FLT_EPSILON; do { decPart *= 10; noiseFloor *= 10; i++; } while (decPart - (int64_t)decPart > noiseFloor); decLength = utils_intToText(decPart, string + intLength, length - intLength); if (decLength <= 1) return 0; // replace the leading 1 with a dot string[intLength] = '.'; } return intLength + decLength; }
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_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); }
int discover_serialize(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, int size, lwm2m_data_t * dataP, uint8_t ** bufferP) { uint8_t bufferLink[PRV_LINK_BUFFER_SIZE]; uint8_t baseUriStr[URI_MAX_STRING_LEN]; int baseUriLen; int index; size_t head; int res; lwm2m_uri_t tempUri; baseUriLen = uri_toString(uriP, baseUriStr, URI_MAX_STRING_LEN, NULL); if (baseUriLen < 0) return -1; baseUriLen -= 1; head = 0; memset(&tempUri, 0, sizeof(lwm2m_uri_t)); // get object level attributes PRV_CONCAT_STR(bufferLink, PRV_LINK_BUFFER_SIZE, head, LINK_ITEM_START, LINK_ITEM_START_SIZE); PRV_CONCAT_STR(bufferLink, PRV_LINK_BUFFER_SIZE, head, LINK_URI_SEPARATOR, LINK_URI_SEPARATOR_SIZE); res = utils_intToText(uriP->objectId, bufferLink + head, PRV_LINK_BUFFER_SIZE - head); if (res <= 0) return -1; head += res; PRV_CONCAT_STR(bufferLink, PRV_LINK_BUFFER_SIZE, head, LINK_ITEM_END, LINK_ITEM_END_SIZE); tempUri.objectId = uriP->objectId; res = prv_serializeAttributes(contextP, &tempUri, bufferLink, head - 1, PRV_LINK_BUFFER_SIZE); if (res < 0) return -1; // careful, 0 is valid if (res == 0) head = 0; // rewind else head += res - 1; if (LWM2M_URI_IS_SET_INSTANCE(uriP)) { size_t subHead; // get object instance level attributes subHead = 0; PRV_CONCAT_STR(bufferLink + head, PRV_LINK_BUFFER_SIZE - head, subHead, LINK_ITEM_START, LINK_ITEM_START_SIZE); PRV_CONCAT_STR(bufferLink + head, PRV_LINK_BUFFER_SIZE - head, subHead, LINK_URI_SEPARATOR, LINK_URI_SEPARATOR_SIZE); res = utils_intToText(uriP->objectId, bufferLink + head + subHead, PRV_LINK_BUFFER_SIZE - head - subHead); if (res <= 0) return -1; subHead += res; PRV_CONCAT_STR(bufferLink + head, PRV_LINK_BUFFER_SIZE - head, subHead, LINK_URI_SEPARATOR, LINK_URI_SEPARATOR_SIZE); res = utils_intToText(uriP->instanceId, bufferLink + head + subHead, PRV_LINK_BUFFER_SIZE - head - subHead); if (res <= 0) return -1; subHead += res; PRV_CONCAT_STR(bufferLink + head, PRV_LINK_BUFFER_SIZE - head, subHead, LINK_ITEM_END, LINK_ITEM_END_SIZE); tempUri.instanceId = uriP->instanceId; tempUri.flag = LWM2M_URI_FLAG_INSTANCE_ID; res = prv_serializeAttributes(contextP, &tempUri, bufferLink + head, head + subHead - 1, PRV_LINK_BUFFER_SIZE); if (res < 0) return -1; // careful, 0 is valid if (res == 0) subHead = 0; // rewind else subHead += res - 1; head += subHead; } for (index = 0; index < size && head < PRV_LINK_BUFFER_SIZE; index++) { res = prv_serializeLinkData(contextP, dataP + index, uriP, baseUriStr, baseUriLen, bufferLink + head, PRV_LINK_BUFFER_SIZE - head); if (res < 0) return -1; head += res; } if (head > 0) { head -= 1; *bufferP = (uint8_t *)lwm2m_malloc(head); if (*bufferP == NULL) return 0; memcpy(*bufferP, bufferLink, head); } return (int)head; }
static int prv_serializeAttributes(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, uint8_t * buffer, size_t uriLen, size_t bufferLen) { lwm2m_observed_t * observedP; lwm2m_watcher_t * watcherP; int head; int res; if (contextP == NULL) return 0; observedP = observe_findByUri(contextP, uriP); if (observedP == NULL || observedP->watcherList == NULL) return 0; head = 0; for (watcherP = observedP->watcherList; watcherP != NULL; watcherP = watcherP->next) { lwm2m_attributes_t * paramP; paramP = watcherP->parameters; if (paramP == NULL || paramP->toSet == 0) continue; if (observedP->watcherList->next != NULL) { // multiple servers memcpy(buffer + head, buffer, uriLen); PRV_CONCAT_STR(buffer, bufferLen, head, LINK_ATTR_SEPARATOR, LINK_ATTR_SEPARATOR_SIZE); PRV_CONCAT_STR(buffer, bufferLen, head, ATTR_SERVER_ID_STR, ATTR_SERVER_ID_LEN); res = utils_intToText(watcherP->server->shortID, buffer + head, bufferLen - head); if (res <= 0) return -1; head += res; } else { head = uriLen; } if (paramP->toSet & LWM2M_ATTR_FLAG_MIN_PERIOD) { PRV_CONCAT_STR(buffer, bufferLen, head, LINK_ATTR_SEPARATOR, LINK_ATTR_SEPARATOR_SIZE); PRV_CONCAT_STR(buffer, bufferLen, head, ATTR_MIN_PERIOD_STR, ATTR_MIN_PERIOD_LEN); res = utils_intToText(paramP->minPeriod, buffer + head, bufferLen - head); if (res <= 0) return -1; head += res; } if (paramP->toSet & LWM2M_ATTR_FLAG_MAX_PERIOD) { PRV_CONCAT_STR(buffer, bufferLen, head, LINK_ATTR_SEPARATOR, LINK_ATTR_SEPARATOR_SIZE); PRV_CONCAT_STR(buffer, bufferLen, head, ATTR_MAX_PERIOD_STR, ATTR_MAX_PERIOD_LEN); res = utils_intToText(paramP->maxPeriod, buffer + head, bufferLen - head); if (res <= 0) return -1; head += res; } if (paramP->toSet & LWM2M_ATTR_FLAG_GREATER_THAN) { PRV_CONCAT_STR(buffer, bufferLen, head, LINK_ATTR_SEPARATOR, LINK_ATTR_SEPARATOR_SIZE); PRV_CONCAT_STR(buffer, bufferLen, head, ATTR_GREATER_THAN_STR, ATTR_GREATER_THAN_LEN); res = utils_floatToText(paramP->greaterThan, buffer + head, bufferLen - head); if (res <= 0) return -1; head += res; } if (paramP->toSet & LWM2M_ATTR_FLAG_LESS_THAN) { PRV_CONCAT_STR(buffer, bufferLen, head, LINK_ATTR_SEPARATOR, LINK_ATTR_SEPARATOR_SIZE); PRV_CONCAT_STR(buffer, bufferLen, head, ATTR_LESS_THAN_STR, ATTR_LESS_THAN_LEN); res = utils_floatToText(paramP->lessThan, buffer + head, bufferLen - head); if (res <= 0) return -1; head += res; } if (paramP->toSet & LWM2M_ATTR_FLAG_STEP) { PRV_CONCAT_STR(buffer, bufferLen, head, LINK_ATTR_SEPARATOR, LINK_ATTR_SEPARATOR_SIZE); PRV_CONCAT_STR(buffer, bufferLen, head, ATTR_STEP_STR, ATTR_STEP_LEN); res = utils_floatToText(paramP->step, buffer + head, bufferLen - head); if (res <= 0) return -1; head += res; } PRV_CONCAT_STR(buffer, bufferLen, head, LINK_ITEM_ATTR_END, LINK_ITEM_ATTR_END_SIZE); } if (head > 0) head -= uriLen; return head; }
// dataP array length is assumed to be 1. static int prv_textSerialize(lwm2m_data_t * dataP, uint8_t ** bufferP) { size_t res; switch (dataP->type) { case LWM2M_TYPE_STRING: *bufferP = (uint8_t *)lwm2m_malloc(dataP->value.asBuffer.length); if (*bufferP == NULL) return 0; memcpy(*bufferP, dataP->value.asBuffer.buffer, dataP->value.asBuffer.length); return (int)dataP->value.asBuffer.length; case LWM2M_TYPE_INTEGER: { uint8_t intString[_PRV_STR_LENGTH]; res = utils_intToText(dataP->value.asInteger, intString, _PRV_STR_LENGTH); if (res == 0) return -1; *bufferP = (uint8_t *)lwm2m_malloc(res); if (NULL == *bufferP) return -1; memcpy(*bufferP, intString, res); return (int)res; } case LWM2M_TYPE_FLOAT: { uint8_t floatString[_PRV_STR_LENGTH * 2]; res = utils_floatToText(dataP->value.asFloat, floatString, _PRV_STR_LENGTH * 2); if (res == 0) return -1; *bufferP = (uint8_t *)lwm2m_malloc(res); if (NULL == *bufferP) return -1; memcpy(*bufferP, floatString, res); return (int)res; } case LWM2M_TYPE_BOOLEAN: *bufferP = (uint8_t *)lwm2m_malloc(1); if (NULL == *bufferP) return -1; *bufferP[0] = dataP->value.asBoolean ? '1' : '0'; return 1; case LWM2M_TYPE_OBJECT_LINK: { char stringBuffer[11]; size_t length; length = utils_intToText(dataP->value.asObjLink.objectId, (uint8_t*)stringBuffer, 5); if (length == 0) return -1; stringBuffer[5] = ':'; res = length + 1; length = utils_intToText(dataP->value.asObjLink.objectInstanceId, (uint8_t*)stringBuffer + res, 5); if (length == 0) return -1; res += length; *bufferP = (uint8_t *)lwm2m_malloc(res); if (*bufferP == NULL) return -1; memcpy(*bufferP, stringBuffer, res); return res; } case LWM2M_TYPE_OPAQUE: { size_t length; length = utils_base64GetSize(dataP->value.asBuffer.length); *bufferP = (uint8_t *)lwm2m_malloc(length); if (*bufferP == NULL) return 0; length = utils_base64Encode(dataP->value.asBuffer.buffer, dataP->value.asBuffer.length, *bufferP, length); if (length == 0) { lwm2m_free(*bufferP); *bufferP = NULL; return 0; } return (int)length; } case LWM2M_TYPE_UNDEFINED: default: return -1; } }
static int prv_serializeLinkData(lwm2m_context_t * contextP, lwm2m_data_t * tlvP, lwm2m_uri_t * parentUriP, uint8_t * parentUriStr, size_t parentUriLen, uint8_t * buffer, size_t bufferLen) { int head; int res; lwm2m_uri_t uri; head = 0; switch (tlvP->type) { case LWM2M_TYPE_UNDEFINED: case LWM2M_TYPE_STRING: case LWM2M_TYPE_OPAQUE: case LWM2M_TYPE_INTEGER: case LWM2M_TYPE_FLOAT: case LWM2M_TYPE_BOOLEAN: case LWM2M_TYPE_OBJECT_LINK: case LWM2M_TYPE_MULTIPLE_RESOURCE: if (bufferLen < LINK_ITEM_START_SIZE) return -1; memcpy(buffer + head, LINK_ITEM_START, LINK_ITEM_START_SIZE); head = LINK_ITEM_START_SIZE; if (parentUriLen > 0) { if (bufferLen - head < parentUriLen) return -1; memcpy(buffer + head, parentUriStr, parentUriLen); head += parentUriLen; } if (bufferLen - head < LINK_URI_SEPARATOR_SIZE) return -1; memcpy(buffer + head, LINK_URI_SEPARATOR, LINK_URI_SEPARATOR_SIZE); head += LINK_URI_SEPARATOR_SIZE; res = utils_intToText(tlvP->id, buffer + head, bufferLen - head); if (res <= 0) return -1; head += res; if (tlvP->type == LWM2M_TYPE_MULTIPLE_RESOURCE) { if (bufferLen - head < LINK_ITEM_DIM_START_SIZE) return -1; memcpy(buffer + head, LINK_ITEM_DIM_START, LINK_ITEM_DIM_START_SIZE); head += LINK_ITEM_DIM_START_SIZE; res = utils_intToText(tlvP->value.asChildren.count, buffer + head, bufferLen - head); if (res <= 0) return -1; head += res; if (bufferLen - head < LINK_ITEM_ATTR_END_SIZE) return -1; memcpy(buffer + head, LINK_ITEM_ATTR_END, LINK_ITEM_ATTR_END_SIZE); head += LINK_ITEM_ATTR_END_SIZE; } else { if (bufferLen - head < LINK_ITEM_END_SIZE) return -1; memcpy(buffer + head, LINK_ITEM_END, LINK_ITEM_END_SIZE); head += LINK_ITEM_END_SIZE; } memcpy(&uri, parentUriP, sizeof(lwm2m_uri_t)); uri.resourceId = tlvP->id; uri.flag |= LWM2M_URI_FLAG_RESOURCE_ID; res = prv_serializeAttributes(contextP, &uri, buffer, head - 1, bufferLen); if (res < 0) return -1; // careful, 0 is valid if (res > 0) head += res - 1; break; case LWM2M_TYPE_OBJECT_INSTANCE: { uint8_t uriStr[URI_MAX_STRING_LEN]; size_t uriLen; size_t index; if (parentUriLen > 0) { if (URI_MAX_STRING_LEN < parentUriLen) return -1; memcpy(uriStr, parentUriStr, parentUriLen); uriLen = parentUriLen; } else { uriLen = 0; } if (URI_MAX_STRING_LEN - uriLen < LINK_URI_SEPARATOR_SIZE) return -1; memcpy(uriStr + uriLen, LINK_URI_SEPARATOR, LINK_URI_SEPARATOR_SIZE); uriLen += LINK_URI_SEPARATOR_SIZE; res = utils_intToText(tlvP->id, uriStr + uriLen, URI_MAX_STRING_LEN - uriLen); if (res <= 0) return -1; uriLen += res; memcpy(&uri, parentUriP, sizeof(lwm2m_uri_t)); uri.instanceId = tlvP->id; uri.flag |= LWM2M_URI_FLAG_INSTANCE_ID; head = 0; PRV_CONCAT_STR(buffer, bufferLen, head, LINK_ITEM_START, LINK_ITEM_START_SIZE); PRV_CONCAT_STR(buffer, bufferLen, head, uriStr, uriLen); PRV_CONCAT_STR(buffer, bufferLen, head, LINK_ITEM_END, LINK_ITEM_END_SIZE); res = prv_serializeAttributes(contextP, &uri, buffer, head - 1, bufferLen); if (res < 0) return -1; // careful, 0 is valid if (res == 0) head = 0; // rewind else head += res - 1; for (index = 0; index < tlvP->value.asChildren.count; index++) { res = prv_serializeLinkData(contextP, tlvP->value.asChildren.array + index, &uri, uriStr, uriLen, buffer + head, bufferLen - head); if (res < 0) return -1; head += res; } } break; case LWM2M_TYPE_OBJECT: default: return -1; } return head; }
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 prv_serializeData(lwm2m_data_t * tlvP, uint8_t * parentUriStr, size_t parentUriLen, uint8_t * buffer, size_t bufferLen) { int head; int res; head = 0; switch (tlvP->type) { case LWM2M_TYPE_OBJECT: case LWM2M_TYPE_OBJECT_INSTANCE: case LWM2M_TYPE_MULTIPLE_RESOURCE: { uint8_t uriStr[URI_MAX_STRING_LEN]; size_t uriLen; size_t index; if (parentUriLen > 0) { if (URI_MAX_STRING_LEN < parentUriLen) return -1; memcpy(uriStr, parentUriStr, parentUriLen); uriLen = parentUriLen; } else { uriLen = 0; } res = utils_intToText(tlvP->id, uriStr + uriLen, URI_MAX_STRING_LEN - uriLen); if (res <= 0) return -1; uriLen += res; uriStr[uriLen] = '/'; uriLen++; head = 0; for (index = 0 ; index < tlvP->value.asChildren.count; index++) { res = prv_serializeData(tlvP->value.asChildren.array + index, uriStr, uriLen, buffer + head, bufferLen - head); if (res < 0) return -1; head += res; } } break; default: if (bufferLen < JSON_RES_ITEM_URI_SIZE) return -1; memcpy(buffer, JSON_RES_ITEM_URI, JSON_RES_ITEM_URI_SIZE); head = JSON_RES_ITEM_URI_SIZE; if (parentUriLen > 0) { if (bufferLen - head < parentUriLen) return -1; memcpy(buffer + head, parentUriStr, parentUriLen); head += parentUriLen; } res = utils_intToText(tlvP->id, buffer + head, bufferLen - head); if (res <= 0) return -1; head += res; res = prv_serializeValue(tlvP, buffer + head, bufferLen - head); if (res < 0) return -1; head += res; break; } return head; }
static int prv_serializeValue(lwm2m_data_t * tlvP, uint8_t * buffer, size_t bufferLen) { int res; int head; switch (tlvP->type) { case LWM2M_TYPE_STRING: if (bufferLen < JSON_ITEM_STRING_BEGIN_SIZE) return -1; memcpy(buffer, JSON_ITEM_STRING_BEGIN, JSON_ITEM_STRING_BEGIN_SIZE); head = JSON_ITEM_STRING_BEGIN_SIZE; if (bufferLen - head < tlvP->value.asBuffer.length) return -1; memcpy(buffer + head, tlvP->value.asBuffer.buffer, tlvP->value.asBuffer.length); head += tlvP->value.asBuffer.length; if (bufferLen - head < JSON_ITEM_STRING_END_SIZE) return -1; memcpy(buffer + head, JSON_ITEM_STRING_END, JSON_ITEM_STRING_END_SIZE); head += JSON_ITEM_STRING_END_SIZE; break; case LWM2M_TYPE_INTEGER: { int64_t value; if (0 == lwm2m_data_decode_int(tlvP, &value)) return -1; if (bufferLen < JSON_ITEM_NUM_SIZE) return -1; memcpy(buffer, JSON_ITEM_NUM, JSON_ITEM_NUM_SIZE); head = JSON_ITEM_NUM_SIZE; res = utils_intToText(value, buffer + head, bufferLen - head); if (res <= 0) return -1; head += res; if (bufferLen - head < JSON_ITEM_NUM_END_SIZE) return -1; memcpy(buffer + head, JSON_ITEM_NUM_END, JSON_ITEM_NUM_END_SIZE); head += JSON_ITEM_NUM_END_SIZE; } break; case LWM2M_TYPE_FLOAT: { double value; if (0 == lwm2m_data_decode_float(tlvP, &value)) return -1; if (bufferLen < JSON_ITEM_NUM_SIZE) return -1; memcpy(buffer, JSON_ITEM_NUM, JSON_ITEM_NUM_SIZE); head = JSON_ITEM_NUM_SIZE; res = utils_floatToText(value, buffer + head, bufferLen - head); if (res <= 0) return -1; head += res; if (bufferLen - head < JSON_ITEM_NUM_END_SIZE) return -1; memcpy(buffer + head, JSON_ITEM_NUM_END, JSON_ITEM_NUM_END_SIZE); head += JSON_ITEM_NUM_END_SIZE; } break; case LWM2M_TYPE_BOOLEAN: { bool value; if (0 == lwm2m_data_decode_bool(tlvP, &value)) return -1; if (value == true) { if (bufferLen < JSON_ITEM_BOOL_TRUE_SIZE) return -1; memcpy(buffer, JSON_ITEM_BOOL_TRUE, JSON_ITEM_BOOL_TRUE_SIZE); head = JSON_ITEM_BOOL_TRUE_SIZE; } else { if (bufferLen < JSON_ITEM_BOOL_FALSE_SIZE) return -1; memcpy(buffer, JSON_ITEM_BOOL_FALSE, JSON_ITEM_BOOL_FALSE_SIZE); head = JSON_ITEM_BOOL_FALSE_SIZE; } } break; case LWM2M_TYPE_OPAQUE: if (bufferLen < JSON_ITEM_STRING_BEGIN_SIZE) return -1; memcpy(buffer, JSON_ITEM_STRING_BEGIN, JSON_ITEM_STRING_BEGIN_SIZE); head = JSON_ITEM_STRING_BEGIN_SIZE; res = utils_base64Encode(tlvP->value.asBuffer.buffer, tlvP->value.asBuffer.length, buffer+head, bufferLen - head); if (tlvP->value.asBuffer.length != 0 && res == 0) return -1; head += res; if (bufferLen - head < JSON_ITEM_STRING_END_SIZE) return -1; memcpy(buffer + head, JSON_ITEM_STRING_END, JSON_ITEM_STRING_END_SIZE); head += JSON_ITEM_STRING_END_SIZE; break; case LWM2M_TYPE_OBJECT_LINK: // TODO: implement return -1; default: return -1; } return head; }
static int prv_serializeData(const lwm2m_data_t * tlvP, const uint8_t * baseUriStr, size_t baseUriLen, uri_depth_t baseLevel, const uint8_t * parentUriStr, size_t parentUriLen, uri_depth_t level, bool *baseNameOutput, uint8_t * buffer, size_t bufferLen) { size_t head; int res; head = 0; /* Check to override passed in level */ switch (tlvP->type) { case LWM2M_TYPE_MULTIPLE_RESOURCE: level = URI_DEPTH_RESOURCE; break; case LWM2M_TYPE_OBJECT: level = URI_DEPTH_OBJECT; break; case LWM2M_TYPE_OBJECT_INSTANCE: level = URI_DEPTH_OBJECT_INSTANCE; break; default: break; } switch (tlvP->type) { case LWM2M_TYPE_MULTIPLE_RESOURCE: case LWM2M_TYPE_OBJECT: case LWM2M_TYPE_OBJECT_INSTANCE: { uint8_t uriStr[URI_MAX_STRING_LEN]; size_t uriLen; size_t index; if (parentUriLen > 0) { if (URI_MAX_STRING_LEN < parentUriLen) return -1; memcpy(uriStr, parentUriStr, parentUriLen); uriLen = parentUriLen; } else { uriLen = 0; } res = utils_intToText(tlvP->id, uriStr + uriLen, URI_MAX_STRING_LEN - uriLen); if (res <= 0) return -1; uriLen += res; uriStr[uriLen] = '/'; uriLen++; head = 0; for (index = 0 ; index < tlvP->value.asChildren.count; index++) { if (index != 0) { if (head + 1 > bufferLen) return 0; buffer[head++] = JSON_SEPARATOR; } res = prv_serializeData(tlvP->value.asChildren.array + index, baseUriStr, baseUriLen, baseLevel, uriStr, uriLen, level, baseNameOutput, buffer + head, bufferLen - head); if (res < 0) return -1; head += res; } } break; default: head = 0; if (bufferLen < 1) return -1; buffer[head++] = JSON_ITEM_BEGIN; if (!*baseNameOutput && baseUriLen > 0) { if (bufferLen - head < baseUriLen + JSON_BN_HEADER_SIZE + 2) return -1; memcpy(buffer + head, JSON_BN_HEADER, JSON_BN_HEADER_SIZE); head += JSON_BN_HEADER_SIZE; memcpy(buffer + head, baseUriStr, baseUriLen); head += baseUriLen; buffer[head++] = JSON_ITEM_STRING_END; buffer[head++] = JSON_SEPARATOR; *baseNameOutput = true; } /* TODO: support base time */ if (!baseUriLen || level > baseLevel) { if (bufferLen - head < JSON_ITEM_URI_SIZE) return -1; memcpy(buffer + head, JSON_ITEM_URI, JSON_ITEM_URI_SIZE); head += JSON_ITEM_URI_SIZE; if (parentUriLen > 0) { if (bufferLen - head < parentUriLen) return -1; memcpy(buffer + head, parentUriStr, parentUriLen); head += parentUriLen; } res = utils_intToText(tlvP->id, buffer + head, bufferLen - head); if (res <= 0) return -1; head += res; if (bufferLen - head < 2) return -1; buffer[head++] = JSON_ITEM_URI_END; if (tlvP->type != LWM2M_TYPE_UNDEFINED) { buffer[head++] = JSON_SEPARATOR; } } if (tlvP->type != LWM2M_TYPE_UNDEFINED) { res = prv_serializeValue(tlvP, buffer + head, bufferLen - head); if (res < 0) return -1; head += res; } /* TODO: support time */ if (bufferLen - head < 1) return -1; buffer[head++] = JSON_ITEM_END; break; } return (int)head; }
static int prv_serializeValue(const lwm2m_data_t * tlvP, uint8_t * buffer, size_t bufferLen) { size_t res; size_t head; switch (tlvP->type) { case LWM2M_TYPE_STRING: case LWM2M_TYPE_CORE_LINK: if (bufferLen < JSON_ITEM_STRING_BEGIN_SIZE) return -1; memcpy(buffer, JSON_ITEM_STRING_BEGIN, JSON_ITEM_STRING_BEGIN_SIZE); head = JSON_ITEM_STRING_BEGIN_SIZE; res = json_escapeString(buffer + head, bufferLen - head, tlvP->value.asBuffer.buffer, tlvP->value.asBuffer.length); if (!res) return -1; head += res; if (bufferLen - head < 1) return -1; buffer[head++] = JSON_ITEM_STRING_END; break; case LWM2M_TYPE_INTEGER: { int64_t value; if (0 == lwm2m_data_decode_int(tlvP, &value)) return -1; if (bufferLen < JSON_ITEM_NUM_SIZE) return -1; memcpy(buffer, JSON_ITEM_NUM, JSON_ITEM_NUM_SIZE); head = JSON_ITEM_NUM_SIZE; res = utils_intToText(value, buffer + head, bufferLen - head); if (!res) return -1; head += res; } break; case LWM2M_TYPE_UNSIGNED_INTEGER: { uint64_t value; if (0 == lwm2m_data_decode_uint(tlvP, &value)) return -1; if (bufferLen < JSON_ITEM_NUM_SIZE) return -1; memcpy(buffer, JSON_ITEM_NUM, JSON_ITEM_NUM_SIZE); head = JSON_ITEM_NUM_SIZE; res = utils_uintToText(value, buffer + head, bufferLen - head); if (!res) return -1; head += res; } break; case LWM2M_TYPE_FLOAT: { double value; if (0 == lwm2m_data_decode_float(tlvP, &value)) return -1; if (bufferLen < JSON_ITEM_NUM_SIZE) return -1; memcpy(buffer, JSON_ITEM_NUM, JSON_ITEM_NUM_SIZE); head = JSON_ITEM_NUM_SIZE; res = utils_floatToText(value, buffer + head, bufferLen - head); if (!res) return -1; head += res; } break; case LWM2M_TYPE_BOOLEAN: { bool value; if (0 == lwm2m_data_decode_bool(tlvP, &value)) return -1; if (value) { if (bufferLen < JSON_ITEM_BOOL_SIZE + JSON_TRUE_STRING_SIZE) return -1; memcpy(buffer, JSON_ITEM_BOOL JSON_TRUE_STRING, JSON_ITEM_BOOL_SIZE + JSON_TRUE_STRING_SIZE); head = JSON_ITEM_BOOL_SIZE + JSON_TRUE_STRING_SIZE; } else { if (bufferLen < JSON_ITEM_BOOL_SIZE + JSON_FALSE_STRING_SIZE) return -1; memcpy(buffer, JSON_ITEM_BOOL JSON_FALSE_STRING, JSON_ITEM_BOOL_SIZE + JSON_FALSE_STRING_SIZE); head = JSON_ITEM_BOOL_SIZE + JSON_FALSE_STRING_SIZE; } } break; case LWM2M_TYPE_OPAQUE: if (bufferLen < JSON_ITEM_OPAQUE_BEGIN_SIZE) return -1; memcpy(buffer, JSON_ITEM_OPAQUE_BEGIN, JSON_ITEM_OPAQUE_BEGIN_SIZE); head = JSON_ITEM_OPAQUE_BEGIN_SIZE; if (tlvP->value.asBuffer.length > 0) { res = utils_base64Encode(tlvP->value.asBuffer.buffer, tlvP->value.asBuffer.length, buffer+head, bufferLen - head); if (!res) return -1; head += res; } if (bufferLen - head < 1) return -1; buffer[head++] = JSON_ITEM_OPAQUE_END; break; case LWM2M_TYPE_OBJECT_LINK: if (bufferLen < JSON_ITEM_OBJECT_LINK_BEGIN_SIZE) return -1; memcpy(buffer, JSON_ITEM_OBJECT_LINK_BEGIN, JSON_ITEM_OBJECT_LINK_BEGIN_SIZE); head = JSON_ITEM_OBJECT_LINK_BEGIN_SIZE; res = utils_objLinkToText(tlvP->value.asObjLink.objectId, tlvP->value.asObjLink.objectInstanceId, buffer + head, bufferLen - head); if (!res) return -1; head += res; if (bufferLen - head < 1) return -1; buffer[head++] = JSON_ITEM_OBJECT_LINK_END; break; default: return -1; } return (int)head; }