diff --git a/core/internals.h b/core/internals.h index 35c926fbd..983bbd410 100644 --- a/core/internals.h +++ b/core/internals.h @@ -157,6 +157,8 @@ #define URI_REGISTRATION_SEGMENT_LEN 2 #define URI_BOOTSTRAP_SEGMENT "bs" #define URI_BOOTSTRAP_SEGMENT_LEN 2 +#define URI_SEND_SEGMENT "dp" +#define URI_SEND_SEGMENT_LEN 2 #define QUERY_STARTER "?" #define QUERY_NAME "ep=" @@ -320,6 +322,10 @@ int object_getRegisterPayload(lwm2m_context_t * contextP, uint8_t * buffer, size int object_getServers(lwm2m_context_t * contextP, bool checkOnly); uint8_t object_createInstance(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, lwm2m_data_t * dataP); uint8_t object_writeInstance(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, lwm2m_data_t * dataP); +#ifndef LWM2M_VERSION_1_0 +uint8_t object_readCompositeData(lwm2m_context_t *contextP, lwm2m_uri_t *uriP, size_t numUris, int *sizeP, + lwm2m_data_t **dataP); +#endif // defined in transaction.c 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); @@ -458,4 +464,4 @@ lwm2m_server_t * utils_findBootstrapServer(lwm2m_context_t * contextP, void * fr lwm2m_client_t * utils_findClient(lwm2m_context_t * contextP, void * fromSessionH); #endif -#endif +#endif \ No newline at end of file diff --git a/core/objects.c b/core/objects.c index a5290c7a3..26f82ddfe 100644 --- a/core/objects.c +++ b/core/objects.c @@ -1233,4 +1233,218 @@ uint8_t object_writeInstance(lwm2m_context_t * contextP, return targetP->writeFunc(contextP, dataP->id, dataP->value.asChildren.count, dataP->value.asChildren.array, targetP, LWM2M_WRITE_REPLACE_INSTANCE); } +#ifndef LWM2M_VERSION_1_0 +uint8_t object_readCompositeData(lwm2m_context_t *contextP, lwm2m_uri_t *uriP, size_t numUris, int *sizeP, + lwm2m_data_t **dataP) { + size_t i; + int count; + uint8_t result = COAP_205_CONTENT; + + *sizeP = 0; + *dataP = NULL; + + for (i = 0; i < numUris; i++) { + int partialSize = 0; + lwm2m_data_t *partialDataP = NULL; + uint8_t res; + if (uriP[i].objectId == LWM2M_SECURITY_OBJECT_ID || uriP[i].objectId == LWM2M_OSCORE_OBJECT_ID) { + res = COAP_401_UNAUTHORIZED; + } else { + res = object_readData(contextP, uriP + i, &partialSize, &partialDataP); + } + if (res == COAP_205_CONTENT && partialSize > 0) { + size_t *countP; + lwm2m_data_t **childrenP; + bool finished = false; + lwm2m_data_t *parentP = NULL; + size_t j; + + if (LWM2M_URI_IS_SET_OBJECT(uriP + i)) { + // Find the object + for (j = 0; (int)j < *sizeP; j++) { + if (uriP[i].objectId == (*dataP)[j].id) { + if (LWM2M_URI_IS_SET_INSTANCE(uriP + i)) { + parentP = (*dataP) + j; + } else { + // Duplicate or overlapping reads. Replace all instances. + lwm2m_data_free((*dataP)[j].value.asChildren.count, (*dataP)[j].value.asChildren.array); + (*dataP)[j].value.asChildren.count = partialSize; + (*dataP)[j].value.asChildren.array = partialDataP; + finished = true; + } + break; + } + } + if ((int)j == *sizeP) { + // Need to add a new object + if (0 != lwm2m_data_append_one(sizeP, dataP, LWM2M_TYPE_OBJECT, uriP[i].objectId)) { + parentP = *dataP + *sizeP - 1; + + if (!LWM2M_URI_IS_SET_INSTANCE(uriP + i)) { + // Need to add the instances + parentP->value.asChildren.count = partialSize; + parentP->value.asChildren.array = partialDataP; + finished = true; + } + } else { + lwm2m_data_free(partialSize, partialDataP); + if (result == COAP_205_CONTENT) { + result = COAP_400_BAD_REQUEST; + } + finished = true; + } + } + } else { + // Root level. Add objects + if (0 == lwm2m_data_append(sizeP, dataP, partialSize, partialDataP)) { + lwm2m_data_free(partialSize, partialDataP); + if (result == COAP_205_CONTENT) { + result = COAP_400_BAD_REQUEST; + } + } + finished = true; + } + + if (!finished) { + // Find the instance + countP = &parentP->value.asChildren.count; + childrenP = &parentP->value.asChildren.array; + for (j = 0; j < *countP; j++) { + if (uriP[i].instanceId == (*childrenP)[j].id) { + if (LWM2M_URI_IS_SET_RESOURCE(uriP + i)) { + parentP = (*childrenP) + j; + } else { + // Duplicate or overlapping reads. replace all resources. + lwm2m_data_free((*childrenP)[j].value.asChildren.count, + (*childrenP)[j].value.asChildren.array); + (*childrenP)[j].value.asChildren.count = partialSize; + (*childrenP)[j].value.asChildren.array = partialDataP; + finished = true; + } + break; + } + } + if (j == *countP) { + // Need to add a new instance + count = parentP->value.asChildren.count; + if (0 != lwm2m_data_append_one(&count, &parentP->value.asChildren.array, LWM2M_TYPE_OBJECT_INSTANCE, + uriP[i].instanceId)) { + parentP->value.asChildren.count = count; + parentP = parentP->value.asChildren.array + count - 1; + + if (!LWM2M_URI_IS_SET_RESOURCE(uriP + i)) { + parentP->value.asChildren.count = partialSize; + parentP->value.asChildren.array = partialDataP; + finished = true; + } + } else { + lwm2m_data_free(partialSize, partialDataP); + if (result == COAP_205_CONTENT) { + result = COAP_400_BAD_REQUEST; + } + finished = true; + } + } + } + + if (!finished) { + // Find the resource + countP = &parentP->value.asChildren.count; + childrenP = &parentP->value.asChildren.array; + for (j = 0; j < *countP; j++) { + if (uriP[i].resourceId == (*childrenP)[j].id) { + if (LWM2M_URI_IS_SET_RESOURCE_INSTANCE(uriP + i)) { + parentP = (*childrenP) + j; + } else { + // Duplicate or overlapping reads. + if ((*childrenP)[j].type == LWM2M_TYPE_MULTIPLE_RESOURCE) { + // Replace the resource instances + lwm2m_data_free((*childrenP)[j].value.asChildren.count, + (*childrenP)[j].value.asChildren.array); + (*childrenP)[j].value.asChildren.count = partialSize; + (*childrenP)[j].value.asChildren.array = partialDataP; + } else { + // Overwrite the value + memcpy((*childrenP) + j, partialDataP, sizeof(lwm2m_data_t)); + // Shallow free + memset(partialDataP, 0, sizeof(lwm2m_data_t)); + lwm2m_data_free(partialSize, partialDataP); + } + finished = true; + } + break; + } + } + if (j == *countP) { + // Need to add a new resource + count = parentP->value.asChildren.count; + if (0 != lwm2m_data_append_one(&count, &parentP->value.asChildren.array, LWM2M_TYPE_UNDEFINED, + uriP[i].instanceId)) { + parentP->value.asChildren.count = count; + parentP = parentP->value.asChildren.array + count - 1; + + memcpy(parentP, partialDataP, sizeof(lwm2m_data_t)); + // Shallow free + memset(partialDataP, 0, sizeof(lwm2m_data_t)); + lwm2m_data_free(partialSize, partialDataP); + finished = true; + } else { + lwm2m_data_free(partialSize, partialDataP); + if (result == COAP_205_CONTENT) { + result = COAP_400_BAD_REQUEST; + } + finished = true; + } + } + } + + if (!finished) { + // Find the resource instance + countP = &parentP->value.asChildren.count; + childrenP = &parentP->value.asChildren.array; + for (j = 0; j < *countP; j++) { + if (uriP[i].resourceInstanceId == (*childrenP)[j].id) { + // Duplicate or overlapping reads. + // Overwrite the value + memcpy((*childrenP) + j, partialDataP->value.asChildren.array, sizeof(lwm2m_data_t)); + // Shallow free + memset(partialDataP, 0, sizeof(lwm2m_data_t)); + lwm2m_data_free(partialSize, partialDataP); + break; + } + } + if (j == *countP) { + // Need to add a new resource instance + count = parentP->value.asChildren.count; + if (0 != lwm2m_data_append_one(&count, &parentP->value.asChildren.array, LWM2M_TYPE_UNDEFINED, + uriP[i].instanceId)) { + parentP->value.asChildren.count = count; + parentP = parentP->value.asChildren.array + count - 1; + memcpy(parentP, partialDataP->value.asChildren.array, sizeof(lwm2m_data_t)); + // Shallow free + memset(partialDataP, 0, sizeof(lwm2m_data_t)); + lwm2m_data_free(partialSize, partialDataP); + } else { + lwm2m_data_free(partialSize, partialDataP); + if (result == COAP_205_CONTENT) { + result = COAP_400_BAD_REQUEST; + } + } + } + } + } else if (result == COAP_205_CONTENT && res != COAP_404_NOT_FOUND) { + result = res; + } + } + + if (*sizeP > 0) { + result = COAP_205_CONTENT; + } else if (result == COAP_205_CONTENT) { + result = COAP_404_NOT_FOUND; + } + + return result; +} #endif + +#endif \ No newline at end of file diff --git a/core/observe.c b/core/observe.c index 31370decd..bd874023c 100644 --- a/core/observe.c +++ b/core/observe.c @@ -843,6 +843,142 @@ void observe_step(lwm2m_context_t * contextP, } } +#ifndef LWM2M_VERSION_1_0 +int lwm2m_send(lwm2m_context_t *contextP, uint16_t shortServerID, lwm2m_uri_t *urisP, size_t numUris, + lwm2m_transaction_callback_t callback, void *userData) { +#if defined(LWM2M_SUPPORT_SENML_CBOR) || defined(LWM2M_SUPPORT_SENML_JSON) + lwm2m_transaction_t *transactionP; + lwm2m_server_t *targetP; + lwm2m_data_t *dataP = NULL; +#ifdef LWM2M_SUPPORT_SENML_CBOR + lwm2m_media_type_t format = LWM2M_CONTENT_SENML_CBOR; +#else + lwm2m_media_type_t format = LWM2M_CONTENT_SENML_JSON; +#endif + lwm2m_uri_t uri; + int ret; + int size = 0; + uint8_t *buffer = NULL; + int length; + size_t i; + bool oneGood = false; + + LOG_ARG("shortServerID: %d", shortServerID); + for (i = 0; i < numUris; i++) { + LOG_URI(urisP + i); + } + + for (i = 0; i < numUris; i++) { + if (!LWM2M_URI_IS_SET_OBJECT(urisP + i)) + return COAP_400_BAD_REQUEST; + if (!LWM2M_URI_IS_SET_INSTANCE(urisP + i) && LWM2M_URI_IS_SET_RESOURCE(urisP + i)) + return COAP_400_BAD_REQUEST; + } + + ret = object_readCompositeData(contextP, urisP, numUris, &size, &dataP); + if (ret != COAP_205_CONTENT) + return ret; + + LWM2M_URI_RESET(&uri); + if (size == 1) { + uri.objectId = dataP->id; + if (dataP->value.asChildren.count == 1) { + uri.instanceId = dataP->value.asChildren.array->id; + } + } + ret = lwm2m_data_serialize(&uri, size, dataP, &format, &buffer); + lwm2m_data_free(size, dataP); + if (ret < 0) { + return COAP_500_INTERNAL_SERVER_ERROR; + } else { + length = ret; + } + + if (shortServerID == 0 && contextP->serverList != NULL && contextP->serverList->next == NULL) { + // Only 1 server + shortServerID = contextP->serverList->shortID; + } + + ret = COAP_404_NOT_FOUND; + for (targetP = contextP->serverList; targetP != NULL; targetP = targetP->next) { + bool mute = true; + lwm2m_data_t *muteDataP; + int muteSize; + + if (shortServerID != 0 && shortServerID != targetP->shortID) + continue; + if (targetP->sessionH == NULL || + (targetP->status != STATE_REGISTERED && targetP->status != STATE_REG_UPDATE_PENDING && + targetP->status != STATE_REG_UPDATE_NEEDED && targetP->status != STATE_REG_FULL_UPDATE_NEEDED)) { + if (ret == COAP_404_NOT_FOUND) + ret = COAP_405_METHOD_NOT_ALLOWED; + if (shortServerID == 0) + continue; + break; + } + + LWM2M_URI_RESET(&uri); + uri.objectId = LWM2M_SERVER_OBJECT_ID; + uri.instanceId = targetP->servObjInstID; + uri.resourceId = LWM2M_SERVER_MUTE_SEND_ID; + if (COAP_205_CONTENT == object_readData(contextP, &uri, &muteSize, &muteDataP)) { + lwm2m_data_decode_bool(muteDataP, &mute); + lwm2m_data_free(muteSize, muteDataP); + } + if (mute) { + if (ret == COAP_404_NOT_FOUND) + ret = COAP_405_METHOD_NOT_ALLOWED; + if (shortServerID == 0) + continue; + break; + } + + LWM2M_URI_RESET(&uri); + transactionP = transaction_new(targetP->sessionH, COAP_POST, NULL, &uri, contextP->nextMID++, 0, NULL); + if (transactionP == NULL) { + ret = COAP_500_INTERNAL_SERVER_ERROR; + // Going to the next server likely won't fix this, just get out. + break; + } + + coap_set_header_uri_path(transactionP->message, "/" URI_SEND_SEGMENT); + coap_set_header_content_type(transactionP->message, format); + coap_set_payload(transactionP->message, buffer, length); + + transactionP->callback = callback; + transactionP->userData = userData; + + contextP->transactionList = (lwm2m_transaction_t *)LWM2M_LIST_ADD(contextP->transactionList, transactionP); + + ret = transaction_send(contextP, transactionP); + if (ret == NO_ERROR) { + oneGood = true; + } else { + LOG_ARG("transaction_send failed for %d: 0x%02X!", targetP->shortID, ret); + } + coap_set_payload(transactionP->message, NULL, 0); // Clear the payload + if (shortServerID != 0) + break; + } + if (buffer) { + lwm2m_free(buffer); + } + if (oneGood) + ret = NO_ERROR; + return ret; +#else + /* Unused parameters */ + (void)contextP; + (void)shortServerID; + (void)urisP; + (void)numUris; + (void)callback; + (void)userData; + return COAP_415_UNSUPPORTED_CONTENT_FORMAT; +#endif +} +#endif + #endif #ifdef LWM2M_SERVER_MODE @@ -1355,4 +1491,4 @@ bool observe_handleNotify(lwm2m_context_t * contextP, } return true; } -#endif +#endif \ No newline at end of file diff --git a/data/data.c b/data/data.c index 814794345..718cf0094 100644 --- a/data/data.c +++ b/data/data.c @@ -818,3 +818,63 @@ int lwm2m_data_serialize(lwm2m_uri_t * uriP, } } +int lwm2m_data_append(int *sizeP, lwm2m_data_t **dataP, int addDataSize, lwm2m_data_t *addDataP) { + int result = 0; + int tmpSize = (*sizeP) + addDataSize; + + if (addDataSize == 0) { + // Nothing to do. + result = 1; + } + if (*sizeP == 0) { + *dataP = addDataP; + *sizeP = addDataSize; + result = 1; + } + // Guard against overflow + else if (tmpSize > *sizeP && tmpSize > addDataSize) { + lwm2m_data_t *tmpDataP = lwm2m_data_new(tmpSize); + if (tmpDataP != NULL) { + // Shallow copy into new array + memcpy(tmpDataP, *dataP, (*sizeP) * sizeof(lwm2m_data_t)); + memcpy(tmpDataP + *sizeP, addDataP, addDataSize * sizeof(lwm2m_data_t)); + // Shallow free old data + memset(*dataP, 0, (*sizeP) * sizeof(lwm2m_data_t)); + lwm2m_data_free(*sizeP, *dataP); + memset(addDataP, 0, addDataSize * sizeof(lwm2m_data_t)); + lwm2m_data_free(addDataSize, addDataP); + // Set new data + *dataP = tmpDataP; + *sizeP = tmpSize; + result = 1; + } + } + + return result; +} + +int lwm2m_data_append_one(int *sizeP, lwm2m_data_t **dataP, lwm2m_data_type_t type, uint16_t id) { + int result = 0; + int tmpSize = *sizeP + 1; + + // Guard against overflow + if (tmpSize > *sizeP) { + lwm2m_data_t *tmpDataP = lwm2m_data_new(tmpSize); + if (tmpDataP != NULL) { + // Shallow copy into new array + memcpy(tmpDataP, *dataP, (*sizeP) * sizeof(lwm2m_data_t)); + // Shallow free old data + memset(*dataP, 0, (*sizeP) * sizeof(lwm2m_data_t)); + lwm2m_data_free(*sizeP, *dataP); + // Set the new one + tmpDataP[*sizeP].id = id; + tmpDataP[*sizeP].type = type; + // Set new data + *dataP = tmpDataP; + *sizeP = tmpSize; + result = 1; + } + } + + return result; +} \ No newline at end of file diff --git a/examples/client/lwm2mclient.c b/examples/client/lwm2mclient.c index 0dbb3847f..20e45b093 100644 --- a/examples/client/lwm2mclient.c +++ b/examples/client/lwm2mclient.c @@ -571,6 +571,72 @@ static void prv_update(lwm2m_context_t * lwm2mH, fprintf(stdout, "Syntax error !\n"); } +#ifndef LWM2M_VERSION_1_0 +static void prv_send(lwm2m_context_t *lwm2mH, char *buffer, void *user_data) { + lwm2m_uri_t uri; + lwm2m_uri_t *uris = NULL; + size_t uriCount = 0; + char *tmp; + char *end = NULL; + int result; + uint16_t serverId; + + /* unused parameter */ + (void)user_data; + + if (buffer[0] == 0) + goto syntax_error; + + result = atoi(buffer); + if (result < 0 || result > LWM2M_MAX_ID) + goto syntax_error; + serverId = (uint16_t)result; + + tmp = buffer; + do { + tmp = get_next_arg(tmp, &end); + if (tmp[0] == 0) + goto syntax_error; + + result = lwm2m_stringToUri(tmp, end - tmp, &uri); + if (result == 0) + goto syntax_error; + uriCount++; + } while (!check_end_of_args(end)); + + uris = lwm2m_malloc(uriCount * sizeof(lwm2m_uri_t)); + if (uris != NULL) { + size_t i; + for (i = 0; i < uriCount; i++) { + buffer = get_next_arg(buffer, &end); + if (buffer[0] == 0) + goto syntax_error; + + result = lwm2m_stringToUri(buffer, end - buffer, uris + i); + if (result == 0) + goto syntax_error; + } + + result = lwm2m_send(lwm2mH, serverId, uris, uriCount, NULL, NULL); + lwm2m_free(uris); + } else { + result = COAP_500_INTERNAL_SERVER_ERROR; + } + if (result != 0) { + fprintf(stdout, "Send error: "); + print_status(stdout, result); + fprintf(stdout, "\r\n"); + } + return; + +syntax_error: + if (uris != NULL) { + lwm2m_free(uris); + } + fprintf(stdout, "Syntax error !\n"); +} +#endif + static void update_battery_level(lwm2m_context_t * context) { static time_t next_change_time = 0; @@ -895,30 +961,43 @@ int main(int argc, char *argv[]) * The firsts tree are easy to understand, the callback is the function that will be called when this command is typed * and in the last one will be stored the lwm2m context (allowing access to the server settings and the objects). */ - command_desc_t commands[] = - { - {"list", "List known servers.", NULL, prv_output_servers, NULL}, - {"change", "Change the value of resource.", " change URI [DATA]\r\n" - " URI: uri of the resource such as /3/0, /3/0/2\r\n" - " DATA: (optional) new value\r\n", prv_change, NULL}, - {"update", "Trigger a registration update", " update SERVER\r\n" - " SERVER: short server id such as 123\r\n", prv_update, NULL}, + command_desc_t commands[] = { + {"list", "List known servers.", NULL, prv_output_servers, NULL}, + {"change", "Change the value of resource.", + " change URI [DATA]\r\n" + " URI: uri of the resource such as /3/0, /3/0/2\r\n" + " DATA: (optional) new value\r\n", + prv_change, NULL}, + {"update", "Trigger a registration update", + " update SERVER\r\n" + " SERVER: short server id such as 123\r\n", + prv_update, NULL}, +#ifndef LWM2M_VERSION_1_0 + {"send", "Send one or more resources", + " send SERVER URI [URI...]\r\n" + " SERVER: short server id such as 123. 0 for all.\r\n" + " URI: uri of the resource such as /3/0, /3/0/2\r\n", + prv_send, NULL}, +#endif #ifdef LWM2M_BOOTSTRAP - {"bootstrap", "Initiate a DI bootstrap process", NULL, prv_initiate_bootstrap, NULL}, - {"dispb", "Display current backup of objects/instances/resources\r\n" - "\t(only security and server objects are backupped)", NULL, prv_display_backup, NULL}, + {"bootstrap", "Initiate a DI bootstrap process", NULL, prv_initiate_bootstrap, NULL}, + {"dispb", + "Display current backup of objects/instances/resources\r\n" + "\t(only security and server objects are backupped)", + NULL, prv_display_backup, NULL}, #endif - {"ls", "List Objects and Instances", NULL, prv_object_list, NULL}, - {"disp", "Display current objects/instances/resources", NULL, prv_display_objects, NULL}, - {"dump", "Dump an Object", "dump URI" - "URI: uri of the Object or Instance such as /3/0, /1\r\n", prv_object_dump, NULL}, - {"add", "Add support of object 31024", NULL, prv_add, NULL}, - {"rm", "Remove support of object 31024", NULL, prv_remove, NULL}, - {"quit", "Quit the client gracefully.", NULL, prv_quit, NULL}, - {"^C", "Quit the client abruptly (without sending a de-register message).", NULL, NULL, NULL}, - - COMMAND_END_LIST - }; + {"ls", "List Objects and Instances", NULL, prv_object_list, NULL}, + {"disp", "Display current objects/instances/resources", NULL, prv_display_objects, NULL}, + {"dump", "Dump an Object", + "dump URI" + "URI: uri of the Object or Instance such as /3/0, /1\r\n", + prv_object_dump, NULL}, + {"add", "Add support of object 31024", NULL, prv_add, NULL}, + {"rm", "Remove support of object 31024", NULL, prv_remove, NULL}, + {"quit", "Quit the client gracefully.", NULL, prv_quit, NULL}, + {"^C", "Quit the client abruptly (without sending a de-register message).", NULL, NULL, NULL}, + + COMMAND_END_LIST}; memset(&data, 0, sizeof(client_data_t)); data.addressFamily = AF_INET6; @@ -1460,4 +1539,4 @@ int main(int argc, char *argv[]) acl_ctrl_free_object(objArray[8]); return 0; -} +} \ No newline at end of file diff --git a/examples/client/object_server.c b/examples/client/object_server.c index a1e9098c6..aeb3ad586 100644 --- a/examples/client/object_server.c +++ b/examples/client/object_server.c @@ -72,6 +72,7 @@ typedef struct _server_instance_ int communicationRetryTimer; // <0 when it doesn't exist int communicationSequenceDelayTimer; // <0 when it doesn't exist int communicationSequenceRetryCount; // <0 when it doesn't exist + bool muteSend; #endif } server_instance_t; @@ -212,6 +213,10 @@ static uint8_t prv_get_value(lwm2m_data_t * dataP, return COAP_404_NOT_FOUND; } + case LWM2M_SERVER_MUTE_SEND_ID: + lwm2m_data_encode_bool(targetP->muteSend, dataP); + return COAP_205_CONTENT; + #endif default: @@ -239,22 +244,16 @@ static uint8_t prv_server_read(lwm2m_context_t *contextP, if (*numDataP == 0) { uint16_t resList[] = { - LWM2M_SERVER_SHORT_ID_ID, - LWM2M_SERVER_LIFETIME_ID, - LWM2M_SERVER_MIN_PERIOD_ID, - LWM2M_SERVER_MAX_PERIOD_ID, - LWM2M_SERVER_TIMEOUT_ID, - LWM2M_SERVER_STORING_ID, + LWM2M_SERVER_SHORT_ID_ID, LWM2M_SERVER_LIFETIME_ID, + LWM2M_SERVER_MIN_PERIOD_ID, LWM2M_SERVER_MAX_PERIOD_ID, + LWM2M_SERVER_TIMEOUT_ID, LWM2M_SERVER_STORING_ID, LWM2M_SERVER_BINDING_ID, #ifndef LWM2M_VERSION_1_0 - LWM2M_SERVER_REG_ORDER_ID, - LWM2M_SERVER_INITIAL_REG_DELAY_ID, - LWM2M_SERVER_REG_FAIL_BLOCK_ID, - LWM2M_SERVER_REG_FAIL_BOOTSTRAP_ID, - LWM2M_SERVER_COMM_RETRY_COUNT_ID, - LWM2M_SERVER_COMM_RETRY_TIMER_ID, - LWM2M_SERVER_SEQ_DELAY_TIMER_ID, - LWM2M_SERVER_SEQ_RETRY_COUNT_ID, + LWM2M_SERVER_REG_ORDER_ID, LWM2M_SERVER_INITIAL_REG_DELAY_ID, + LWM2M_SERVER_REG_FAIL_BLOCK_ID, LWM2M_SERVER_REG_FAIL_BOOTSTRAP_ID, + LWM2M_SERVER_COMM_RETRY_COUNT_ID, LWM2M_SERVER_COMM_RETRY_TIMER_ID, + LWM2M_SERVER_SEQ_DELAY_TIMER_ID, LWM2M_SERVER_SEQ_RETRY_COUNT_ID, + LWM2M_SERVER_MUTE_SEND_ID, #endif }; int nbRes = sizeof(resList)/sizeof(uint16_t); @@ -407,24 +406,17 @@ static uint8_t prv_server_discover(lwm2m_context_t *contextP, if (*numDataP == 0) { uint16_t resList[] = { - LWM2M_SERVER_SHORT_ID_ID, - LWM2M_SERVER_LIFETIME_ID, - LWM2M_SERVER_MIN_PERIOD_ID, - LWM2M_SERVER_MAX_PERIOD_ID, - LWM2M_SERVER_DISABLE_ID, - LWM2M_SERVER_TIMEOUT_ID, - LWM2M_SERVER_STORING_ID, - LWM2M_SERVER_BINDING_ID, + LWM2M_SERVER_SHORT_ID_ID, LWM2M_SERVER_LIFETIME_ID, + LWM2M_SERVER_MIN_PERIOD_ID, LWM2M_SERVER_MAX_PERIOD_ID, + LWM2M_SERVER_DISABLE_ID, LWM2M_SERVER_TIMEOUT_ID, + LWM2M_SERVER_STORING_ID, LWM2M_SERVER_BINDING_ID, LWM2M_SERVER_UPDATE_ID, #ifndef LWM2M_VERSION_1_0 - LWM2M_SERVER_REG_ORDER_ID, - LWM2M_SERVER_INITIAL_REG_DELAY_ID, - LWM2M_SERVER_REG_FAIL_BLOCK_ID, - LWM2M_SERVER_REG_FAIL_BOOTSTRAP_ID, - LWM2M_SERVER_COMM_RETRY_COUNT_ID, - LWM2M_SERVER_COMM_RETRY_TIMER_ID, - LWM2M_SERVER_SEQ_DELAY_TIMER_ID, - LWM2M_SERVER_SEQ_RETRY_COUNT_ID, + LWM2M_SERVER_REG_ORDER_ID, LWM2M_SERVER_INITIAL_REG_DELAY_ID, + LWM2M_SERVER_REG_FAIL_BLOCK_ID, LWM2M_SERVER_REG_FAIL_BOOTSTRAP_ID, + LWM2M_SERVER_COMM_RETRY_COUNT_ID, LWM2M_SERVER_COMM_RETRY_TIMER_ID, + LWM2M_SERVER_SEQ_DELAY_TIMER_ID, LWM2M_SERVER_SEQ_RETRY_COUNT_ID, + LWM2M_SERVER_MUTE_SEND_ID, #endif }; int nbRes = sizeof(resList) / sizeof(uint16_t); @@ -609,6 +601,9 @@ static uint8_t prv_server_discover(lwm2m_context_t *contextP, result = COAP_404_NOT_FOUND; } break; + + case LWM2M_SERVER_MUTE_SEND_ID: + break; #endif default: @@ -929,6 +924,17 @@ static uint8_t prv_server_write(lwm2m_context_t *contextP, } break; } + + case LWM2M_SERVER_MUTE_SEND_ID: { + bool value; + if (1 == lwm2m_data_decode_bool(dataArray + i, &value)) { + targetP->muteSend = value; + result = COAP_204_CHANGED; + } else { + result = COAP_400_BAD_REQUEST; + } + break; + } #endif default: @@ -1086,6 +1092,7 @@ void display_server_object(lwm2m_object_t * object) fprintf(stdout, ", communicationSequenceDelayTimer: %d", serverInstance->communicationSequenceDelayTimer); if(serverInstance->communicationSequenceRetryCount >= 0) fprintf(stdout, ", communicationSequenceRetryCount: %d", serverInstance->communicationSequenceRetryCount); + fprintf(stdout, ", muteSend: %s", serverInstance->muteSend ? "true" : "false"); #endif fprintf(stdout, "\r\n"); serverInstance = (server_instance_t *)serverInstance->next; @@ -1137,6 +1144,7 @@ lwm2m_object_t * get_server_object(int serverId, serverInstance->communicationRetryTimer = -1; serverInstance->communicationSequenceDelayTimer = -1; serverInstance->communicationSequenceRetryCount = -1; + serverInstance->muteSend = false; #endif serverObj->instanceList = LWM2M_LIST_ADD(serverObj->instanceList, serverInstance); diff --git a/include/liblwm2m.h b/include/liblwm2m.h index 50d0d0435..8c0fe6019 100644 --- a/include/liblwm2m.h +++ b/include/liblwm2m.h @@ -157,23 +157,24 @@ bool lwm2m_session_is_equal(void * session1, void * session2, void * userData); #define COAP_IGNORE (uint8_t)0x01 #define COAP_RETRANSMISSION (uint8_t)0x02 -#define COAP_201_CREATED (uint8_t)0x41 -#define COAP_202_DELETED (uint8_t)0x42 -#define COAP_204_CHANGED (uint8_t)0x44 -#define COAP_205_CONTENT (uint8_t)0x45 -#define COAP_231_CONTINUE (uint8_t)0x5F -#define COAP_400_BAD_REQUEST (uint8_t)0x80 -#define COAP_401_UNAUTHORIZED (uint8_t)0x81 -#define COAP_402_BAD_OPTION (uint8_t)0x82 -#define COAP_404_NOT_FOUND (uint8_t)0x84 -#define COAP_405_METHOD_NOT_ALLOWED (uint8_t)0x85 -#define COAP_406_NOT_ACCEPTABLE (uint8_t)0x86 -#define COAP_408_REQ_ENTITY_INCOMPLETE (uint8_t)0x88 -#define COAP_412_PRECONDITION_FAILED (uint8_t)0x8C -#define COAP_413_ENTITY_TOO_LARGE (uint8_t)0x8D -#define COAP_500_INTERNAL_SERVER_ERROR (uint8_t)0xA0 -#define COAP_501_NOT_IMPLEMENTED (uint8_t)0xA1 -#define COAP_503_SERVICE_UNAVAILABLE (uint8_t)0xA3 +#define COAP_201_CREATED (uint8_t)0x41 +#define COAP_202_DELETED (uint8_t)0x42 +#define COAP_204_CHANGED (uint8_t)0x44 +#define COAP_205_CONTENT (uint8_t)0x45 +#define COAP_231_CONTINUE (uint8_t)0x5F +#define COAP_400_BAD_REQUEST (uint8_t)0x80 +#define COAP_401_UNAUTHORIZED (uint8_t)0x81 +#define COAP_402_BAD_OPTION (uint8_t)0x82 +#define COAP_404_NOT_FOUND (uint8_t)0x84 +#define COAP_405_METHOD_NOT_ALLOWED (uint8_t)0x85 +#define COAP_406_NOT_ACCEPTABLE (uint8_t)0x86 +#define COAP_408_REQ_ENTITY_INCOMPLETE (uint8_t)0x88 +#define COAP_412_PRECONDITION_FAILED (uint8_t)0x8C +#define COAP_413_ENTITY_TOO_LARGE (uint8_t)0x8D +#define COAP_415_UNSUPPORTED_CONTENT_FORMAT (uint8_t)0x8F +#define COAP_500_INTERNAL_SERVER_ERROR (uint8_t)0xA0 +#define COAP_501_NOT_IMPLEMENTED (uint8_t)0xA1 +#define COAP_503_SERVICE_UNAVAILABLE (uint8_t)0xA3 /* * Standard Object IDs @@ -387,6 +388,8 @@ lwm2m_data_t * lwm2m_data_new(int size); int lwm2m_data_parse(lwm2m_uri_t * uriP, const uint8_t * buffer, size_t bufferLen, lwm2m_media_type_t format, lwm2m_data_t ** dataP); int lwm2m_data_serialize(lwm2m_uri_t * uriP, int size, lwm2m_data_t * dataP, lwm2m_media_type_t * formatP, uint8_t ** bufferP); void lwm2m_data_free(int size, lwm2m_data_t * dataP); +int lwm2m_data_append(int *sizeP, lwm2m_data_t **dataP, int addDataSize, lwm2m_data_t *addDataP); +int lwm2m_data_append_one(int *sizeP, lwm2m_data_t **dataP, lwm2m_data_type_t type, uint16_t id); void lwm2m_data_encode_string(const char * string, lwm2m_data_t * dataP); void lwm2m_data_encode_nstring(const char * string, size_t length, lwm2m_data_t * dataP); @@ -824,6 +827,14 @@ int lwm2m_update_registration(lwm2m_context_t * contextP, uint16_t shortServerID // send deregistration to all servers connected to client void lwm2m_deregister(lwm2m_context_t * context); void lwm2m_resource_value_changed(lwm2m_context_t * contextP, lwm2m_uri_t * uriP); + +#ifndef LWM2M_VERSION_1_0 +// send resources specified by URIs to the server specified by the server short +// identifier or all if the ID is 0. NO_ERROR is returned if sending to any +// server is successful. +int lwm2m_send(lwm2m_context_t *contextP, uint16_t shortServerID, lwm2m_uri_t *urisP, size_t numUris, + lwm2m_transaction_callback_t callback, void *userData); +#endif #endif #ifdef LWM2M_SERVER_MODE @@ -872,4 +883,4 @@ int lwm2m_bootstrap_read(lwm2m_context_t * contextP, void * sessionH, lwm2m_uri_ } #endif -#endif +#endif \ No newline at end of file