static void test_raw_expected(const char * uriStr, const char * testBuf, size_t testLen, const char * expectBuf, size_t expectLen, lwm2m_media_type_t format, const char * id) { lwm2m_data_t * tlvP; lwm2m_uri_t uri; int size; if (uriStr != NULL) { lwm2m_stringToUri(uriStr, strlen(uriStr), &uri); } size = lwm2m_data_parse((uriStr != NULL) ? &uri : NULL, (uint8_t *)testBuf, testLen, format, &tlvP); CU_ASSERT_TRUE_FATAL(size>0); // Serialize to the same format and compare to the input buffer test_data_and_compare(uriStr, format, tlvP, size, id, (uint8_t*)expectBuf, expectLen); // Serialize to the other format respectivly. if (format == LWM2M_CONTENT_TLV) test_data(uriStr, LWM2M_CONTENT_JSON, tlvP, size, id); else if (format == LWM2M_CONTENT_JSON) test_data(uriStr, LWM2M_CONTENT_TLV, tlvP, size, id); }
static void test_data(const char * uriStr, lwm2m_media_type_t format, lwm2m_data_t * tlvP, int size, const char * id) { lwm2m_uri_t uri; uint8_t * buffer; int length; if (uriStr != NULL) { lwm2m_stringToUri(uriStr, strlen(uriStr), &uri); } length = lwm2m_data_serialize((uriStr != NULL) ? &uri : NULL, size, tlvP, &format, &buffer); if (length <= 0) { printf("Serialize lwm2m_data_t %s to %s failed.\n", id, format==LWM2M_CONTENT_JSON?"JSON":"TLV"); //dump_data_t(stdout, size, tlvP, 0); CU_TEST_FATAL(CU_FALSE); } else { //printf("\n\nSerialize lwm2m_data_t %s:\n", id); //output_buffer(stdout, buffer, length, 0); lwm2m_free(buffer); } }
/** * @brief Parses the testBuf to an array of lwm2m_data_t objects and serializes the result * to TLV and JSON and if applicable compares it to the original testBuf. * @param testBuf The input buffer. * @param testLen The length of the input buffer. * @param format The format of the testBuf. Maybe LWM2M_CONTENT_TLV or LWM2M_CONTENT_JSON at the moment. * @param id The test object id for debug out. */ static void test_raw(const char * uriStr, const char * testBuf, size_t testLen, lwm2m_media_type_t format, const char * id) { lwm2m_data_t * tlvP; lwm2m_uri_t uri; int size; if (uriStr != NULL) { lwm2m_stringToUri(uriStr, strlen(uriStr), &uri); } size = lwm2m_data_parse((uriStr != NULL) ? &uri : NULL, (uint8_t *)testBuf, testLen, format, &tlvP); CU_ASSERT_TRUE_FATAL(size>0); // Serialize to the same format and compare to the input buffer test_data_and_compare(uriStr, format, tlvP, size, id, (uint8_t*)testBuf, testLen); // Serialize to the TLV format // the reverse is not possible as TLV format loses the data type information if (format == LWM2M_CONTENT_JSON) { test_data(uriStr, LWM2M_CONTENT_TLV, tlvP, size, id); } }
static void prv_cancel_client(char * buffer, void * user_data) { lwm2m_context_t * lwm2mH = (lwm2m_context_t *) user_data; uint16_t clientId; lwm2m_uri_t uri; int result; result = prv_read_id(buffer, &clientId); if (result != 1) goto syntax_error; buffer = get_next_arg(buffer); if (buffer[0] == 0) goto syntax_error; result = lwm2m_stringToUri(buffer, strlen(buffer), &uri); if (result == 0) goto syntax_error; result = lwm2m_observe_cancel(lwm2mH, clientId, &uri, prv_result_callback, NULL); if (result == 0) { fprintf(stdout, "OK"); } else { fprintf(stdout, "Error %d.%2d", (result&0xE0)>>5, result&0x1F); } return; syntax_error: fprintf(stdout, "Syntax error !"); }
static void prv_cancel_client(char * buffer, void * user_data) { lwm2m_context_t * lwm2mH = (lwm2m_context_t *) user_data; uint16_t clientId; lwm2m_uri_t uri; char* end = NULL; int result; result = prv_read_id(buffer, &clientId); if (result != 1) goto syntax_error; buffer = get_next_arg(buffer, &end); if (buffer[0] == 0) goto syntax_error; result = lwm2m_stringToUri(buffer, end - buffer, &uri); if (result == 0) goto syntax_error; if (!check_end_of_args(end)) goto syntax_error; result = lwm2m_observe_cancel(lwm2mH, clientId, &uri, prv_result_callback, NULL); if (result == 0) { fprintf(stdout, "OK"); } else { prv_print_error(result); } return; syntax_error: fprintf(stdout, "Syntax error !"); }
static void prv_change(char * buffer, void * user_data) { lwm2m_context_t * lwm2mH = (lwm2m_context_t *) user_data; lwm2m_uri_t uri; char * end = NULL; int result; end = get_end_of_arg(buffer); if (end[0] == 0) goto syntax_error; result = lwm2m_stringToUri(buffer, end - buffer, &uri); if (result == 0) goto syntax_error; buffer = get_next_arg(end, &end); if (buffer[0] == 0) { fprintf(stderr, "report change!\n"); lwm2m_resource_value_changed(lwm2mH, &uri); } else { handle_value_changed(lwm2mH, &uri, buffer, end - buffer); } return; syntax_error: fprintf(stdout, "Syntax error !\n"); }
static void update_battery_level(lwm2m_context_t * context) { static time_t next_change_time = 0; time_t tv_sec; tv_sec = lwm2m_gettime(); if (tv_sec < 0) return; if (next_change_time < tv_sec) { char value[15]; int valueLength; lwm2m_uri_t uri; int level = rand() % 100; if (0 > level) level = -level; if (lwm2m_stringToUri("/3/0/9", 6, &uri)) { valueLength = sprintf(value, "%d", level); fprintf(stderr, "New Battery Level: %d\n", level); handle_value_changed(context, &uri, value, valueLength); } level = rand() % 20; if (0 > level) level = -level; next_change_time = tv_sec + level + 10; } }
static void prv_create_client(char * buffer, void * user_data) { lwm2m_context_t * lwm2mH = (lwm2m_context_t *) user_data; uint16_t clientId; lwm2m_uri_t uri; char * end = NULL; int result; int64_t value; uint8_t temp_buffer[MAX_PACKET_SIZE]; int temp_length = 0; lwm2m_media_type_t format = LWM2M_CONTENT_TEXT; //Get Client ID result = prv_read_id(buffer, &clientId); if (result != 1) goto syntax_error; //Get Uri buffer = get_next_arg(buffer, &end); if (buffer[0] == 0) goto syntax_error; result = lwm2m_stringToUri(buffer, end - buffer, &uri); if (result == 0) goto syntax_error; //Get Data to Post buffer = get_next_arg(end, &end); if (buffer[0] == 0) goto syntax_error; if (!check_end_of_args(end)) goto syntax_error; // TLV /* Client dependent part */ if (uri.objectId == 1024) { result = lwm2m_PlainTextToInt64((uint8_t *)buffer, end - buffer, &value); temp_length = lwm2m_intToTLV(LWM2M_TYPE_RESOURCE, value, (uint16_t) 1, temp_buffer, MAX_PACKET_SIZE); format = LWM2M_CONTENT_TLV; } /* End Client dependent part*/ //Create result = lwm2m_dm_create(lwm2mH, clientId, &uri, format, temp_buffer, temp_length, prv_result_callback, NULL); if (result == 0) { fprintf(stdout, "OK"); } else { prv_print_error(result); } return; syntax_error: fprintf(stdout, "Syntax error !"); }
static void prv_time_client(char * buffer, void * user_data) { lwm2m_context_t * lwm2mH = (lwm2m_context_t *) user_data; uint16_t clientId; lwm2m_uri_t uri; char * end = NULL; int result; lwm2m_attributes_t attr; int nb; int value; result = prv_read_id(buffer, &clientId); if (result != 1) goto syntax_error; buffer = get_next_arg(buffer, &end); if (buffer[0] == 0) goto syntax_error; result = lwm2m_stringToUri(buffer, end - buffer, &uri); if (result == 0) goto syntax_error; memset(&attr, 0, sizeof(lwm2m_attributes_t)); attr.toSet = LWM2M_ATTR_FLAG_MIN_PERIOD | LWM2M_ATTR_FLAG_MAX_PERIOD; buffer = get_next_arg(end, &end); if (buffer[0] == 0) goto syntax_error; nb = sscanf(buffer, "%d", &value); if (nb != 1) goto syntax_error; if (value < 0) goto syntax_error; attr.minPeriod = value; buffer = get_next_arg(end, &end); if (buffer[0] == 0) goto syntax_error; nb = sscanf(buffer, "%d", &value); if (nb != 1) goto syntax_error; if (value < 0) goto syntax_error; attr.maxPeriod = value; if (!check_end_of_args(end)) goto syntax_error; result = lwm2m_dm_write_attributes(lwm2mH, clientId, &uri, &attr, prv_result_callback, NULL); if (result == 0) { fprintf(stdout, "OK"); } else { prv_print_error(result); } return; syntax_error: fprintf(stdout, "Syntax error !"); }
static void prv_resultCallback(lwm2m_transaction_t * transacP, void * message) { dm_data_t * dataP = (dm_data_t *)transacP->userData; if (message == NULL) { dataP->callback(dataP->clientID, &dataP->uri, COAP_503_SERVICE_UNAVAILABLE, LWM2M_CONTENT_TEXT, NULL, 0, dataP->userData); } else { coap_packet_t * packet = (coap_packet_t *)message; //if packet is a CREATE response and the instanceId was assigned by the client if (packet->code == COAP_201_CREATED && packet->location_path != NULL) { char * locationString = NULL; int result = 0; lwm2m_uri_t locationUri; locationString = coap_get_multi_option_as_string(packet->location_path); if (locationString == NULL) { LOG("Error: coap_get_multi_option_as_string() failed for Location_path option in prv_resultCallback()"); return; } result = lwm2m_stringToUri(locationString, strlen(locationString), &locationUri); if (result == 0) { LOG("Error: lwm2m_stringToUri() failed for Location_path option in prv_resultCallback()"); lwm2m_free(locationString); return; } ((dm_data_t*)transacP->userData)->uri.instanceId = locationUri.instanceId; ((dm_data_t*)transacP->userData)->uri.flag = locationUri.flag; lwm2m_free(locationString); } dataP->callback(dataP->clientID, &dataP->uri, packet->code, utils_convertMediaType(packet->content_type), packet->payload, packet->payload_len, dataP->userData); } lwm2m_free(dataP); }
static void prv_exec_client(char * buffer, void * user_data) { lwm2m_context_t * lwm2mH = (lwm2m_context_t *) user_data; uint16_t clientId; lwm2m_uri_t uri; char * uriString; int i; int result; result = prv_read_id(buffer, &clientId); if (result != 1) goto syntax_error; buffer = get_next_arg(buffer); if (buffer[0] == 0) goto syntax_error; uriString = buffer; buffer = get_next_arg(buffer); i = 0; while (uriString + i < buffer && !isspace(uriString[i])) { i++; } result = lwm2m_stringToUri(uriString, i, &uri); if (result == 0) goto syntax_error; if (buffer[0] == 0) { result = lwm2m_dm_execute(lwm2mH, clientId, &uri, NULL, 0, prv_result_callback, NULL); } else { result = lwm2m_dm_execute(lwm2mH, clientId, &uri, buffer, strlen(buffer), prv_result_callback, NULL); } if (result == 0) { fprintf(stdout, "OK"); } else { fprintf(stdout, "Error %d.%2d", (result&0xE0)>>5, result&0x1F); } return; syntax_error: fprintf(stdout, "Syntax error !"); }
static void prv_object_dump(char * buffer, void * user_data) { lwm2m_context_t * lwm2mH = (lwm2m_context_t *) user_data; lwm2m_uri_t uri; char * end = NULL; int result; lwm2m_object_t * objectP; uint16_t i; end = get_end_of_arg(buffer); if (end[0] == 0) goto syntax_error; result = lwm2m_stringToUri(buffer, end - buffer, &uri); if (result == 0) goto syntax_error; if (uri.flag & LWM2M_URI_FLAG_RESOURCE_ID) goto syntax_error; objectP = prv_find_object(lwm2mH, uri.objectId); if (objectP == NULL) { fprintf(stdout, "Object not found.\n"); return; } if (uri.flag & LWM2M_URI_FLAG_INSTANCE_ID) { prv_instance_dump(objectP, uri.instanceId); } else { lwm2m_list_t * instanceP; for (instanceP = objectP->instanceList; instanceP != NULL ; instanceP = instanceP->next) { fprintf(stdout, "Instance %d:\r\n", instanceP->id); prv_instance_dump(objectP, instanceP->id); fprintf(stdout, "\r\n"); } } return; syntax_error: fprintf(stdout, "Syntax error !\n"); }
static void test_data_and_compare(const char * uriStr, lwm2m_media_type_t format, lwm2m_data_t * tlvP, int size, const char * id, uint8_t* original_buffer, size_t original_length) { lwm2m_uri_t uri; uint8_t * buffer; int length; if (uriStr != NULL) { lwm2m_stringToUri(uriStr, strlen(uriStr), &uri); } length = lwm2m_data_serialize((uriStr != NULL) ? &uri : NULL, size, tlvP, &format, &buffer); if (length <= 0) { printf("(Serialize lwm2m_data_t %s to TLV failed.)\t", id); //dump_data_t(stdout, size, tlvP, 0); CU_TEST_FATAL(CU_FALSE); return; } if (format != LWM2M_CONTENT_JSON) { CU_ASSERT_EQUAL(original_length, length); if ((original_length != (size_t)length) || (memcmp(original_buffer, buffer, length) != 0)) { printf("Comparing buffer after parse/serialize failed for %s:\n", id); output_buffer(stdout, buffer, length, 0); printf("\ninstead of:\n"); output_buffer(stdout, original_buffer, original_length, 0); CU_TEST_FATAL(CU_FALSE); } } lwm2m_free(buffer); }
static void prv_clear_client(char * buffer, void * user_data) { lwm2m_context_t * lwm2mH = (lwm2m_context_t *) user_data; uint16_t clientId; lwm2m_uri_t uri; char * end = NULL; int result; lwm2m_attributes_t attr; result = prv_read_id(buffer, &clientId); if (result != 1) goto syntax_error; buffer = get_next_arg(buffer, &end); if (buffer[0] == 0) goto syntax_error; result = lwm2m_stringToUri(buffer, end - buffer, &uri); if (result == 0) goto syntax_error; memset(&attr, 0, sizeof(lwm2m_attributes_t)); attr.toClear = LWM2M_ATTR_FLAG_LESS_THAN | LWM2M_ATTR_FLAG_GREATER_THAN | LWM2M_ATTR_FLAG_STEP | LWM2M_ATTR_FLAG_MIN_PERIOD | LWM2M_ATTR_FLAG_MAX_PERIOD ; buffer = get_next_arg(end, &end); if (!check_end_of_args(end)) goto syntax_error; result = lwm2m_dm_write_attributes(lwm2mH, clientId, &uri, &attr, prv_result_callback, NULL); if (result == 0) { fprintf(stdout, "OK"); } else { prv_print_error(result); } return; syntax_error: fprintf(stdout, "Syntax error !"); }
static void test_data_and_compare(const char * uriStr, lwm2m_media_type_t format, lwm2m_data_t * tlvP, int size, const char * id, const uint8_t* original_buffer, size_t original_length) { lwm2m_uri_t uri; uint8_t * buffer; size_t length; if (uriStr != NULL) { lwm2m_stringToUri(uriStr, strlen(uriStr), &uri); } length = lwm2m_data_serialize((uriStr != NULL) ? &uri : NULL, size, tlvP, &format, &buffer); if (length <= 0) { printf("Serialize lwm2m_data_t %s to TLV failed.\n", id); //dump_data_t(stdout, size, tlvP, 0); CU_TEST_FATAL(CU_FALSE); return; } char* original_compact; if (format == LWM2M_CONTENT_JSON) { // Remove white spaces from original_buffer if not in a "" context // so that the original input string can be compared to the serialized data output, // which does not contain additional white spaces. original_compact= malloc(original_length); char* s = (char*)original_buffer; char* d = original_compact; uint8_t in_string_context = 0; do { *d = *s; // Toggle "in_string_context" flag if " has been detected and if " is not escaped if (*d == '"' && *(d-1) != '\\') in_string_context = !in_string_context; if(in_string_context || !isspace(*d)) d++; } while(*s++ != 0); original_length = strlen(original_compact); } else { // No JSON format? Just use the original buffer original_compact = (char*)original_buffer; } CU_ASSERT_EQUAL(original_length, length); if ((original_length != length) || (memcmp(original_compact, buffer, length) != 0)) { printf("Comparing buffer after parse/serialize failed for %s:\n", id); output_buffer(stdout, buffer, length, 0); printf("\ninstead of:\n"); output_buffer(stdout, (uint8_t*)original_compact, original_length, 0); CU_TEST_FATAL(CU_FALSE); } // Free the compact representation of the original buffer if (original_compact != (char*)original_buffer) free(original_compact); lwm2m_free(buffer); }
static void prv_create_client(char * buffer, void * user_data) { lwm2m_context_t * lwm2mH = (lwm2m_context_t *) user_data; uint16_t clientId; lwm2m_uri_t uri; char * end = NULL; int result; int64_t value; uint8_t * temp_buffer = NULL; int temp_length = 0; lwm2m_media_type_t format = LWM2M_CONTENT_TEXT; //Get Client ID result = prv_read_id(buffer, &clientId); if (result != 1) goto syntax_error; //Get Uri buffer = get_next_arg(buffer, &end); if (buffer[0] == 0) goto syntax_error; result = lwm2m_stringToUri(buffer, end - buffer, &uri); if (result == 0) goto syntax_error; //Get Data to Post buffer = get_next_arg(end, &end); if (buffer[0] == 0) goto syntax_error; if (!check_end_of_args(end)) goto syntax_error; // TLV /* Client dependent part */ if (uri.objectId == 1024) { lwm2m_data_t * dataP; dataP = lwm2m_data_new(1); if (dataP == NULL) { fprintf(stdout, "Allocation error !"); return; } lwm2m_data_encode_int(value, dataP); dataP->id = 1; format = LWM2M_CONTENT_TLV; temp_length = lwm2m_data_serialize(NULL, 1, dataP, &format, &temp_buffer); } /* End Client dependent part*/ //Create result = lwm2m_dm_create(lwm2mH, clientId, &uri, format, temp_buffer, temp_length, prv_result_callback, NULL); if (result == 0) { fprintf(stdout, "OK"); } else { prv_print_error(result); } return; syntax_error: fprintf(stdout, "Syntax error !"); }
static void prv_attr_client(char * buffer, void * user_data) { lwm2m_context_t * lwm2mH = (lwm2m_context_t *) user_data; uint16_t clientId; lwm2m_uri_t uri; char * end = NULL; int result; lwm2m_attributes_t attr; int nb; float value; result = prv_read_id(buffer, &clientId); if (result != 1) goto syntax_error; buffer = get_next_arg(buffer, &end); if (buffer[0] == 0) goto syntax_error; result = lwm2m_stringToUri(buffer, end - buffer, &uri); if (result == 0) goto syntax_error; memset(&attr, 0, sizeof(lwm2m_attributes_t)); attr.toSet = LWM2M_ATTR_FLAG_LESS_THAN | LWM2M_ATTR_FLAG_GREATER_THAN; buffer = get_next_arg(end, &end); if (buffer[0] == 0) goto syntax_error; nb = sscanf(buffer, "%f", &value); if (nb != 1) goto syntax_error; attr.lessThan = value; buffer = get_next_arg(end, &end); if (buffer[0] == 0) goto syntax_error; nb = sscanf(buffer, "%f", &value); if (nb != 1) goto syntax_error; attr.greaterThan = value; buffer = get_next_arg(end, &end); if (buffer[0] != 0) { nb = sscanf(buffer, "%f", &value); if (nb != 1) goto syntax_error; attr.step = value; attr.toSet |= LWM2M_ATTR_FLAG_STEP; } if (!check_end_of_args(end)) goto syntax_error; result = lwm2m_dm_write_attributes(lwm2mH, clientId, &uri, &attr, prv_result_callback, NULL); if (result == 0) { fprintf(stdout, "OK"); } else { prv_print_error(result); } return; syntax_error: fprintf(stdout, "Syntax error !"); }
static void prv_resultCallback(lwm2m_context_t * contextP, lwm2m_transaction_t * transacP, void * message) { dm_data_t * dataP = (dm_data_t *)transacP->userData; (void)contextP; /* unused */ if (message == NULL) { dataP->callback(dataP->clientID, &dataP->uri, COAP_503_SERVICE_UNAVAILABLE, LWM2M_CONTENT_TEXT, NULL, 0, dataP->userData); } else { coap_packet_t * packet = (coap_packet_t *)message; //if packet is a CREATE response and the instanceId was assigned by the client if (packet->code == COAP_201_CREATED && packet->location_path != NULL) { char * locationString = NULL; int result = 0; lwm2m_uri_t locationUri; locationString = coap_get_multi_option_as_string(packet->location_path); if (locationString == NULL) { LOG("Error: coap_get_multi_option_as_string() failed for Location_path option in prv_resultCallback()"); return; } result = lwm2m_stringToUri(locationString, strlen(locationString), &locationUri); if (result == 0) { LOG("Error: lwm2m_stringToUri() failed for Location_path option in prv_resultCallback()"); lwm2m_free(locationString); return; } if (!LWM2M_URI_IS_SET_OBJECT(&locationUri) || !LWM2M_URI_IS_SET_INSTANCE(&locationUri) || LWM2M_URI_IS_SET_RESOURCE(&locationUri) || locationUri.objectId != ((dm_data_t*)transacP->userData)->uri.objectId) { LOG("Error: invalid Location_path option in prv_resultCallback()"); lwm2m_free(locationString); return; } memcpy(&((dm_data_t*)transacP->userData)->uri, &locationUri, sizeof(locationUri)); lwm2m_free(locationString); } dataP->callback(dataP->clientID, &dataP->uri, packet->code, utils_convertMediaType(packet->content_type), packet->payload, packet->payload_len, dataP->userData); } lwm2m_free(dataP); }
static bs_endpoint_info_t * prv_read_next_endpoint(FILE * fd) { char * key; char * value; bs_endpoint_info_t * endptP; int res; bs_command_t * cmdP; if (prv_find_next_section(fd, "Endpoint") == 0) return NULL; endptP = (bs_endpoint_info_t *)lwm2m_malloc(sizeof(bs_endpoint_info_t)); if (endptP == NULL) return NULL; memset(endptP, 0, sizeof(bs_endpoint_info_t)); cmdP = NULL; while((res = prv_read_key_value(fd, &key, &value)) == 1) { if (strcasecmp(key, "Name") == 0) { endptP->name = value; } else if (strcasecmp(key, "Delete") == 0) { lwm2m_uri_t uri; if (lwm2m_stringToUri(value, strlen(value), &uri) == 0) { if (value[0] == '/' && value[1] == 0) { uri.flag = 0; } else goto error; } cmdP = (bs_command_t *)lwm2m_malloc(sizeof(bs_command_t)); if (cmdP == NULL) goto error; memset(cmdP, 0, sizeof(bs_command_t)); cmdP->operation = BS_DELETE; if (uri.flag != 0) { cmdP->uri = (lwm2m_uri_t *)lwm2m_malloc(sizeof(lwm2m_uri_t)); if (cmdP->uri == NULL) goto error; memcpy(cmdP->uri, &uri, sizeof(lwm2m_uri_t)); } lwm2m_free(value); } else if (strcasecmp(key, "Server") == 0) { int num; if (sscanf(value, "%d", &num) != 1) goto error; if (num <= 0 || num > LWM2M_MAX_ID) goto error; cmdP = (bs_command_t *)lwm2m_malloc(sizeof(bs_command_t)); if (cmdP == NULL) goto error; memset(cmdP, 0, sizeof(bs_command_t)); cmdP->next = (bs_command_t *)lwm2m_malloc(sizeof(bs_command_t)); if (cmdP->next == NULL) goto error; memset(cmdP->next, 0, sizeof(bs_command_t)); cmdP->operation = BS_WRITE_SECURITY; cmdP->serverId = num; cmdP->next->operation = BS_WRITE_SERVER; cmdP->next->serverId = num; lwm2m_free(value); } else { // ignore key for now lwm2m_free(value); } lwm2m_free(key); if (cmdP != NULL) { if (endptP->commandList == NULL) { endptP->commandList = cmdP; } else { bs_command_t * parentP; parentP = endptP->commandList; while (parentP->next != NULL) { parentP = parentP->next; } parentP->next = cmdP; } cmdP = NULL; } } if (endptP->commandList != NULL) { bs_command_t * parentP; cmdP = (bs_command_t *)lwm2m_malloc(sizeof(bs_command_t)); if (cmdP == NULL) goto error; memset(cmdP, 0, sizeof(bs_command_t)); cmdP->operation = BS_FINISH; parentP = endptP->commandList; while (parentP->next != NULL) { parentP = parentP->next; } parentP->next = cmdP; } return endptP; error: if (key != NULL) lwm2m_free(key); if (value != NULL) lwm2m_free(value); while (cmdP != NULL) { bs_command_t * tempP; if (cmdP->uri != NULL) lwm2m_free(cmdP->uri); tempP = cmdP; cmdP = cmdP->next; lwm2m_free(tempP); } if (endptP != NULL) { if (endptP->name != NULL) lwm2m_free(endptP->name); while (endptP->commandList != NULL) { cmdP = endptP->commandList; endptP->commandList =endptP->commandList->next; if (cmdP->uri != NULL) lwm2m_free(cmdP->uri); lwm2m_free(cmdP); } lwm2m_free(endptP); } return NULL; }
TEST(uri, test_uri_decode) { lwm2m_uri_t* uri; multi_option_t extraID = { .next = nullptr, .is_static = 1, .len = 3, .data = (uint8_t *) "555" }; multi_option_t rID = { .next = nullptr, .is_static = 1, .len = 1, .data = (uint8_t *) "0" }; multi_option_t iID = { .next = &rID, .is_static = 1, .len = 2, .data = (uint8_t *) "11" }; multi_option_t oID = { .next = &iID, .is_static = 1, .len = 4, .data = (uint8_t *) "9050" }; multi_option_t location = { .next = nullptr, .is_static = 1, .len = 4, .data = (uint8_t *) "5a3f" }; multi_option_t locationDecimal = { .next = nullptr, .is_static = 1, .len = 4, .data = (uint8_t *) "5312" }; multi_option_t reg = { .next = nullptr, .is_static = 1, .len = 2, .data = (uint8_t *) "rd" }; multi_option_t boot = { .next = nullptr, .is_static = 1, .len = 2, .data = (uint8_t *) "bs" }; memoryObserver.reset(); /* "/rd" */ uri = uri_decode(nullptr, ®); ASSERT_TRUE(uri); ASSERT_EQ(uri->flag, LWM2M_URI_FLAG_REGISTRATION); lwm2m_free(uri); /* "/rd/5a3f" */ reg.next = &location; uri = uri_decode(nullptr, ®); /* should not fail, error in uri_parse */ /* ASSERT_TRUE(uri); */ lwm2m_free(uri); /* "/rd/5312" */ reg.next = &locationDecimal; uri = uri_decode(nullptr, ®); ASSERT_TRUE(uri); ASSERT_EQ(uri->flag, LWM2M_URI_FLAG_REGISTRATION | LWM2M_URI_FLAG_OBJECT_ID); ASSERT_EQ(uri->objectId, 5312); lwm2m_free(uri); /* "/bs" */ uri = uri_decode(nullptr, &boot); ASSERT_TRUE(uri); ASSERT_EQ(uri->flag, LWM2M_URI_FLAG_BOOTSTRAP); lwm2m_free(uri); /* "/bs/5a3f" */ boot.next = &location; uri = uri_decode(nullptr, &boot); ASSERT_FALSE(uri); lwm2m_free(uri); /* "/9050/11/0" */ uri = uri_decode(nullptr, &oID); ASSERT_TRUE(uri); ASSERT_EQ(uri->flag, LWM2M_URI_FLAG_DM | LWM2M_URI_FLAG_OBJECT_ID | LWM2M_URI_FLAG_INSTANCE_ID | LWM2M_URI_FLAG_RESOURCE_ID); ASSERT_EQ(uri->objectId, 9050); ASSERT_EQ(uri->instanceId, 11); ASSERT_EQ(uri->resourceId, 0); lwm2m_free(uri); /* "/11/0" */ uri = uri_decode(nullptr, &iID); ASSERT_TRUE(uri); ASSERT_EQ(uri->flag, LWM2M_URI_FLAG_DM | LWM2M_URI_FLAG_OBJECT_ID | LWM2M_URI_FLAG_INSTANCE_ID); ASSERT_EQ(uri->objectId, 11); ASSERT_EQ(uri->instanceId, 0); lwm2m_free(uri); /* "/0" */ uri = uri_decode(nullptr, &rID); ASSERT_TRUE(uri); ASSERT_EQ(uri->flag, LWM2M_URI_FLAG_DM | LWM2M_URI_FLAG_OBJECT_ID); ASSERT_EQ(uri->objectId, 0); lwm2m_free(uri); /* "/9050/11/0/555" */ rID.next = &extraID; uri = uri_decode(nullptr, &oID); ASSERT_FALSE(uri); lwm2m_free(uri); /* "/0/5a3f" */ rID.next = &location; uri = uri_decode(nullptr, &rID); ASSERT_FALSE(uri); lwm2m_free(uri); MEMEVAL(FAIL()); } TEST(uri, test_string_to_uri) { int result; lwm2m_uri_t uri; memoryObserver.reset(); result = lwm2m_stringToUri("", 0, &uri); ASSERT_EQ(result, 0); result = lwm2m_stringToUri("no_uri", 6, &uri); ASSERT_EQ(result, 0); result = lwm2m_stringToUri("/1", 2, &uri); ASSERT_EQ(result, 2); ASSERT_EQ((uri.flag & LWM2M_URI_FLAG_OBJECT_ID), LWM2M_URI_FLAG_OBJECT_ID); ASSERT_EQ(uri.objectId, 1); ASSERT_EQ((uri.flag & LWM2M_URI_FLAG_INSTANCE_ID), 0); ASSERT_EQ((uri.flag & LWM2M_URI_FLAG_RESOURCE_ID), 0); result = lwm2m_stringToUri("/1/2", 4, &uri); ASSERT_EQ(result, 4); ASSERT_EQ((uri.flag & LWM2M_URI_FLAG_OBJECT_ID), LWM2M_URI_FLAG_OBJECT_ID); ASSERT_EQ(uri.objectId, 1); ASSERT_EQ((uri.flag & LWM2M_URI_FLAG_INSTANCE_ID), LWM2M_URI_FLAG_INSTANCE_ID); ASSERT_EQ(uri.instanceId, 2); ASSERT_EQ((uri.flag & LWM2M_URI_FLAG_RESOURCE_ID), 0); result = lwm2m_stringToUri("/1/2/3", 6, &uri); ASSERT_EQ(result, 6); ASSERT_EQ((uri.flag & LWM2M_URI_FLAG_OBJECT_ID), LWM2M_URI_FLAG_OBJECT_ID); ASSERT_EQ(uri.objectId, 1); ASSERT_EQ((uri.flag & LWM2M_URI_FLAG_INSTANCE_ID), LWM2M_URI_FLAG_INSTANCE_ID); ASSERT_EQ(uri.instanceId, 2); ASSERT_EQ((uri.flag & LWM2M_URI_FLAG_RESOURCE_ID), LWM2M_URI_FLAG_RESOURCE_ID); ASSERT_EQ(uri.resourceId, 3); MEMEVAL(FAIL()); }
static int prv_parseItem(const uint8_t * buffer, size_t bufferLen, _record_t * recordP, char * baseUri, time_t * baseTime, lwm2m_data_t *baseValue) { size_t index; const uint8_t *name = NULL; size_t nameLength = 0; bool timeSeen = false; bool bnSeen = false; bool btSeen = false; bool bvSeen = false; bool bverSeen = false; memset(recordP->ids, 0xFF, 4*sizeof(uint16_t)); memset(&recordP->value, 0, sizeof(recordP->value)); recordP->time = 0; index = 0; do { size_t tokenStart; size_t tokenLen; size_t valueStart; size_t valueLen; int next; next = json_split(buffer+index, bufferLen-index, &tokenStart, &tokenLen, &valueStart, &valueLen); if (next < 0) return -1; if (tokenLen == 0) return -1; switch (buffer[index+tokenStart]) { case 'b': if (tokenLen == 2 && buffer[index+tokenStart+1] == 'n') { if (bnSeen) return -1; bnSeen = true; /* Check for " around URI */ if (valueLen < 2 || buffer[index+valueStart] != '"' || buffer[index+valueStart+valueLen-1] != '"') { return -1; } if (valueLen >= 3) { if (valueLen == 3 && buffer[index+valueStart+1] != '/') return -1; if (valueLen > URI_MAX_STRING_LEN) return -1; memcpy(baseUri, buffer+index+valueStart+1, valueLen-2); baseUri[valueLen-2] = '\0'; } else { baseUri[0] = '\0'; } } else if (tokenLen == 2 && buffer[index+tokenStart+1] == 't') { if (btSeen) return -1; btSeen = true; if (!json_convertTime(buffer+index+valueStart, valueLen, baseTime)) return -1; } else if (tokenLen == 2 && buffer[index+tokenStart+1] == 'v') { if (bvSeen) return -1; bvSeen = true; if (valueLen == 0) { baseValue->type = LWM2M_TYPE_UNDEFINED; } else { if (!json_convertNumeric(buffer+index+valueStart, valueLen, baseValue)) return -1; /* Convert explicit 0 to implicit 0 */ switch (baseValue->type) { case LWM2M_TYPE_INTEGER: if (baseValue->value.asInteger == 0) { baseValue->type = LWM2M_TYPE_UNDEFINED; } break; case LWM2M_TYPE_UNSIGNED_INTEGER: if (baseValue->value.asUnsigned == 0) { baseValue->type = LWM2M_TYPE_UNDEFINED; } break; case LWM2M_TYPE_FLOAT: if (baseValue->value.asFloat == 0.0) { baseValue->type = LWM2M_TYPE_UNDEFINED; } break; default: return -1; } } } else if (tokenLen == 4 && buffer[index+tokenStart+1] == 'v' && buffer[index+tokenStart+2] == 'e' && buffer[index+tokenStart+3] == 'r') { int64_t value; int res; if (bverSeen) return -1; bverSeen = true; res = utils_textToInt(buffer+index+valueStart, valueLen, &value); /* Only the default version (10) is supported */ if (!res || value != 10) { return -1; } } else if (buffer[index+tokenStart+tokenLen-1] == '_') { /* Label ending in _ must be supported or generate error. */ return -1; } break; case 'n': { if (tokenLen == 1) { if (name) return -1; /* Check for " around URI */ if (valueLen < 2 || buffer[index+valueStart] != '"' || buffer[index+valueStart+valueLen-1] != '"') { return -1; } name = buffer + index + valueStart + 1; nameLength = valueLen - 2; } else if (buffer[index+tokenStart+tokenLen-1] == '_') { /* Label ending in _ must be supported or generate error. */ return -1; } break; } case 't': if (tokenLen == 1) { if (timeSeen) return -1; timeSeen = true; if (!json_convertTime(buffer+index+valueStart, valueLen, &recordP->time)) return -1; } else if (buffer[index+tokenStart+tokenLen-1] == '_') { /* Label ending in _ must be supported or generate error. */ return -1; } break; case 'v': if (tokenLen == 1) { if (recordP->value.type != LWM2M_TYPE_UNDEFINED) return -1; if (!json_convertNumeric(buffer+index+valueStart, valueLen, &recordP->value)) return -1; } else if (tokenLen == 2 && buffer[index+tokenStart+1] == 'b') { if (recordP->value.type != LWM2M_TYPE_UNDEFINED) return -1; if (0 == lwm2m_strncmp(JSON_TRUE_STRING, (char *)buffer + index + valueStart, valueLen)) { lwm2m_data_encode_bool(true, &recordP->value); } else if (0 == lwm2m_strncmp(JSON_FALSE_STRING, (char *)buffer + index + valueStart, valueLen)) { lwm2m_data_encode_bool(false, &recordP->value); } else { return -1; } } else if (tokenLen == 2 && (buffer[index+tokenStart+1] == 'd' || buffer[index+tokenStart+1] == 's')) { if (recordP->value.type != LWM2M_TYPE_UNDEFINED) return -1; /* Check for " around value */ if (valueLen < 2 || buffer[index+valueStart] != '"' || buffer[index+valueStart+valueLen-1] != '"') { return -1; } if (buffer[index+tokenStart+1] == 'd') { /* Don't use lwm2m_data_encode_opaque here. It would copy the buffer */ recordP->value.type = LWM2M_TYPE_OPAQUE; } else { /* Don't use lwm2m_data_encode_nstring here. It would copy the buffer */ recordP->value.type = LWM2M_TYPE_STRING; } recordP->value.value.asBuffer.buffer = (uint8_t *)buffer + index + valueStart + 1; recordP->value.value.asBuffer.length = valueLen - 2; } else if (tokenLen == 3 && buffer[index+tokenStart+1] == 'l' && buffer[index+tokenStart+2] == 'o') { if (recordP->value.type != LWM2M_TYPE_UNDEFINED) return -1; /* Check for " around value */ if (valueLen < 2 || buffer[index+valueStart] != '"' || buffer[index+valueStart+valueLen-1] != '"') { return -1; } if (!utils_textToObjLink(buffer + index + valueStart + 1, valueLen - 2, &recordP->value.value.asObjLink.objectId, &recordP->value.value.asObjLink.objectInstanceId)) { return -1; } recordP->value.type = LWM2M_TYPE_OBJECT_LINK; } else if (buffer[index+tokenStart+tokenLen-1] == '_') { /* Label ending in _ must be supported or generate error. */ return -1; } break; default: if (buffer[index+tokenStart+tokenLen-1] == '_') { /* Label ending in _ must be supported or generate error. */ return -1; } break; } index += next + 1; } while (index < bufferLen); /* Combine with base values */ recordP->time += *baseTime; if (baseUri[0] || name) { lwm2m_uri_t uri; size_t length = strlen(baseUri); char uriStr[URI_MAX_STRING_LEN]; if (length > sizeof(uriStr)) return -1; memcpy(uriStr, baseUri, length); if (nameLength) { if (nameLength + length > sizeof(uriStr)) return -1; memcpy(uriStr + length, name, nameLength); length += nameLength; } if (!lwm2m_stringToUri(uriStr, length, &uri)) return -1; if (LWM2M_URI_IS_SET_OBJECT(&uri)) { recordP->ids[0] = uri.objectId; } if (LWM2M_URI_IS_SET_INSTANCE(&uri)) { recordP->ids[1] = uri.instanceId; } if (LWM2M_URI_IS_SET_RESOURCE(&uri)) { recordP->ids[2] = uri.resourceId; } if (LWM2M_URI_IS_SET_RESOURCE_INSTANCE(&uri)) { recordP->ids[3] = uri.resourceInstanceId; } } if (baseValue->type != LWM2M_TYPE_UNDEFINED) { if (recordP->value.type == LWM2M_TYPE_UNDEFINED) { memcpy(&recordP->value, baseValue, sizeof(*baseValue)); } else { switch (recordP->value.type) { case LWM2M_TYPE_INTEGER: switch(baseValue->type) { case LWM2M_TYPE_INTEGER: recordP->value.value.asInteger += baseValue->value.asInteger; break; case LWM2M_TYPE_UNSIGNED_INTEGER: recordP->value.value.asInteger += baseValue->value.asUnsigned; break; case LWM2M_TYPE_FLOAT: recordP->value.value.asInteger += baseValue->value.asFloat; break; default: return -1; } break; case LWM2M_TYPE_UNSIGNED_INTEGER: switch(baseValue->type) { case LWM2M_TYPE_INTEGER: recordP->value.value.asUnsigned += baseValue->value.asInteger; break; case LWM2M_TYPE_UNSIGNED_INTEGER: recordP->value.value.asUnsigned += baseValue->value.asUnsigned; break; case LWM2M_TYPE_FLOAT: recordP->value.value.asUnsigned += baseValue->value.asFloat; break; default: return -1; } break; case LWM2M_TYPE_FLOAT: switch(baseValue->type) { case LWM2M_TYPE_INTEGER: recordP->value.value.asFloat += baseValue->value.asInteger; break; case LWM2M_TYPE_UNSIGNED_INTEGER: recordP->value.value.asFloat += baseValue->value.asUnsigned; break; case LWM2M_TYPE_FLOAT: recordP->value.value.asFloat += baseValue->value.asFloat; break; default: return -1; } break; default: return -1; } } } return 0; }
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; }