lwm2m_object_t * get_object_conn_m(void) { /* * The get_object_conn_m() function create the object itself and return a pointer to the structure that represent it. */ lwm2m_object_t * connObj; connObj = (lwm2m_object_t *) lwm2m_malloc(sizeof(lwm2m_object_t)); if (NULL != connObj) { memset(connObj, 0, sizeof(lwm2m_object_t)); /* * It assigns his unique ID */ connObj->objID = LWM2M_CONN_MONITOR_OBJECT_ID; /* * and its unique instance * */ connObj->instanceList = (lwm2m_list_t *)lwm2m_malloc(sizeof(lwm2m_list_t)); if (NULL != connObj->instanceList) { memset(connObj->instanceList, 0, sizeof(lwm2m_list_t)); } else { lwm2m_free(connObj); return NULL; } /* * And the private function that will access the object. * Those function will be called when a read/write/execute query is made by the server. In fact the library don't need to * know the resources of the object, only the server does. */ connObj->readFunc = prv_read; connObj->closeFunc = prv_close; connObj->executeFunc = NULL; connObj->userData = lwm2m_malloc(sizeof(conn_m_data_t)); /* * Also some user data can be stored in the object with a private structure containing the needed variables */ if (NULL != connObj->userData) { conn_m_data_t *myData = (conn_m_data_t*) connObj->userData; myData->cellId = VALUE_CELL_ID; myData->signalStrength = VALUE_RADIO_SIGNAL_STRENGTH; myData->linkQuality = VALUE_LINK_QUALITY; myData->linkUtilization = VALUE_LINK_UTILIZATION; strcpy(myData->ipAddresses[0], VALUE_IP_ADDRESS_1); strcpy(myData->ipAddresses[1], VALUE_IP_ADDRESS_2); strcpy(myData->routerIpAddresses[0], VALUE_ROUTER_IP_ADDRESS_1); strcpy(myData->routerIpAddresses[1], VALUE_ROUTER_IP_ADDRESS_2); } else { lwm2m_free(connObj); connObj = NULL; } } return connObj; }
static int prv_getParameters(multi_option_t * query, char ** nameP, uint32_t * lifetimeP, char ** msisdnP, lwm2m_binding_t * bindingP) { *nameP = NULL; *lifetimeP = 0; *msisdnP = NULL; *bindingP = BINDING_UNKNOWN; while (query != NULL) { if (lwm2m_strncmp((char *)query->data, QUERY_TEMPLATE, QUERY_LENGTH) == 0) { if (*nameP != NULL) goto error; if (query->len == QUERY_LENGTH) goto error; *nameP = (char *)lwm2m_malloc(query->len - QUERY_LENGTH + 1); if (*nameP != NULL) { memcpy(*nameP, query->data + QUERY_LENGTH, query->len - QUERY_LENGTH); (*nameP)[query->len - QUERY_LENGTH] = 0; } } else if (lwm2m_strncmp((char *)query->data, QUERY_SMS, QUERY_SMS_LEN) == 0) { if (*msisdnP != NULL) goto error; if (query->len == QUERY_SMS_LEN) goto error; *msisdnP = (char *)lwm2m_malloc(query->len - QUERY_SMS_LEN + 1); if (*msisdnP != NULL) { memcpy(*msisdnP, query->data + QUERY_SMS_LEN, query->len - QUERY_SMS_LEN); (*msisdnP)[query->len - QUERY_SMS_LEN] = 0; } } else if (lwm2m_strncmp((char *)query->data, QUERY_LIFETIME, QUERY_LIFETIME_LEN) == 0) { int i; if (*lifetimeP != 0) goto error; if (query->len == QUERY_LIFETIME_LEN) goto error; for (i = QUERY_LIFETIME_LEN ; i < query->len ; i++) { if (query->data[i] < '0' || query->data[i] > '9') goto error; *lifetimeP = (*lifetimeP * 10) + (query->data[i] - '0'); } } else if (lwm2m_strncmp((char *)query->data, QUERY_VERSION, QUERY_VERSION_LEN) == 0) { if ((query->len != QUERY_VERSION_FULL_LEN) || (lwm2m_strncmp((char *)query->data, QUERY_VERSION_FULL, QUERY_VERSION_FULL_LEN) != 0)) { goto error; } } else if (lwm2m_strncmp((char *)query->data, QUERY_BINDING, QUERY_BINDING_LEN) == 0) { if (*bindingP != BINDING_UNKNOWN) goto error; if (query->len == QUERY_BINDING_LEN) goto error; *bindingP = lwm2m_stringToBinding(query->data + QUERY_BINDING_LEN, query->len - QUERY_BINDING_LEN); } query = query->next; } return 0; error: if (*nameP != NULL) lwm2m_free(*nameP); if (*msisdnP != NULL) lwm2m_free(*msisdnP); return -1; }
void observe_remove(lwm2m_observation_t * observationP) { LOG("Entering"); observationP->clientP->observationList = (lwm2m_observation_t *) LWM2M_LIST_RM(observationP->clientP->observationList, observationP->id, NULL); lwm2m_free(observationP); }
uint8_t dm_handleRequest(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, lwm2m_server_t * serverP, coap_packet_t * message, coap_packet_t * response) { uint8_t result; lwm2m_media_type_t format; LOG_ARG("Code: %02X, server status: %s", message->code, STR_STATUS(serverP->status)); LOG_URI(uriP); if (IS_OPTION(message, COAP_OPTION_CONTENT_TYPE)) { format = utils_convertMediaType(message->content_type); } else { format = LWM2M_CONTENT_TLV; } if (uriP->objectId == LWM2M_SECURITY_OBJECT_ID) { return COAP_404_NOT_FOUND; } if (serverP->status != STATE_REGISTERED && serverP->status != STATE_REG_UPDATE_NEEDED && serverP->status != STATE_REG_FULL_UPDATE_NEEDED && serverP->status != STATE_REG_UPDATE_PENDING) { return COAP_IGNORE; } // TODO: check ACL switch (message->code) { case COAP_GET: { uint8_t * buffer = NULL; size_t length = 0; int res; if (IS_OPTION(message, COAP_OPTION_OBSERVE)) { lwm2m_data_t * dataP = NULL; int size = 0; result = object_readData(contextP, uriP, &size, &dataP); if (COAP_205_CONTENT == result) { result = observe_handleRequest(contextP, uriP, serverP, size, dataP, message, response); if (COAP_205_CONTENT == result) { if (IS_OPTION(message, COAP_OPTION_ACCEPT)) { format = utils_convertMediaType(message->accept[0]); } else { format = LWM2M_CONTENT_TLV; } res = lwm2m_data_serialize(uriP, size, dataP, &format, &buffer); if (res < 0) { result = COAP_500_INTERNAL_SERVER_ERROR; } else { length = (size_t)res; LOG_ARG("Observe Request[/%d/%d/%d]: %.*s\n", uriP->objectId, uriP->instanceId, uriP->resourceId, length, buffer); } } lwm2m_data_free(size, dataP); } } else if (IS_OPTION(message, COAP_OPTION_ACCEPT) && message->accept_num == 1 && message->accept[0] == APPLICATION_LINK_FORMAT) { format = LWM2M_CONTENT_LINK; result = object_discover(contextP, uriP, serverP, &buffer, &length); } else { if (IS_OPTION(message, COAP_OPTION_ACCEPT)) { format = utils_convertMediaType(message->accept[0]); } result = object_read(contextP, uriP, &format, &buffer, &length); } if (COAP_205_CONTENT == result) { coap_set_header_content_type(response, format); coap_set_payload(response, buffer, length); // lwm2m_handle_packet will free buffer } else { lwm2m_free(buffer); } } break; case COAP_POST: { if (!LWM2M_URI_IS_SET_INSTANCE(uriP)) { result = object_create(contextP, uriP, format, message->payload, message->payload_len); if (result == COAP_201_CREATED) { //longest uri is /65535/65535 = 12 + 1 (null) chars char location_path[13] = ""; //instanceId expected if (!LWM2M_URI_IS_SET_INSTANCE(uriP)) { result = COAP_500_INTERNAL_SERVER_ERROR; break; } if (sprintf(location_path, "/%d/%d", uriP->objectId, uriP->instanceId) < 0) { result = COAP_500_INTERNAL_SERVER_ERROR; break; } coap_set_header_location_path(response, location_path); lwm2m_update_registration(contextP, 0, true); } } else if (!LWM2M_URI_IS_SET_RESOURCE(uriP)) { result = object_write(contextP, uriP, format, message->payload, message->payload_len); } else { result = object_execute(contextP, uriP, message->payload, message->payload_len); } } break; case COAP_PUT: { if (IS_OPTION(message, COAP_OPTION_URI_QUERY)) { lwm2m_attributes_t attr; if (0 != prv_readAttributes(message->uri_query, &attr)) { result = COAP_400_BAD_REQUEST; } else { result = observe_setParameters(contextP, uriP, serverP, &attr); } } else if (LWM2M_URI_IS_SET_INSTANCE(uriP)) { result = object_write(contextP, uriP, format, message->payload, message->payload_len); } else { result = COAP_400_BAD_REQUEST; } } break; case COAP_DELETE: { if (!LWM2M_URI_IS_SET_INSTANCE(uriP) || LWM2M_URI_IS_SET_RESOURCE(uriP)) { result = COAP_400_BAD_REQUEST; } else { result = object_delete(contextP, uriP); if (result == COAP_202_DELETED) { lwm2m_update_registration(contextP, 0, true); } } } break; default: result = COAP_400_BAD_REQUEST; break; } return result; }
static coap_status_t handle_request(lwm2m_context_t * contextP, void * fromSessionH, coap_packet_t * message, coap_packet_t * response) { lwm2m_uri_t * uriP; coap_status_t result = COAP_IGNORE; #ifdef LWM2M_CLIENT_MODE uriP = uri_decode(contextP->altPath, message->uri_path); #else uriP = uri_decode(NULL, message->uri_path); #endif if (uriP == NULL) return COAP_400_BAD_REQUEST; switch(uriP->flag & LWM2M_URI_MASK_TYPE) { #ifdef LWM2M_CLIENT_MODE case LWM2M_URI_FLAG_DM: { lwm2m_server_t * serverP; serverP = utils_findServer(contextP, fromSessionH); if (serverP != NULL) { result = dm_handleRequest(contextP, uriP, serverP, message, response); } #ifdef LWM2M_BOOTSTRAP else { serverP = utils_findBootstrapServer(contextP, fromSessionH); if (serverP != NULL) { result = bootstrap_handleCommand(contextP, uriP, serverP, message, response); } } #endif } break; #ifdef LWM2M_BOOTSTRAP case LWM2M_URI_FLAG_DELETE_ALL: if (COAP_DELETE != message->code) { result = COAP_400_BAD_REQUEST; } else { result = bootstrap_handleDeleteAll(contextP, fromSessionH); } break; case LWM2M_URI_FLAG_BOOTSTRAP: if (message->code == COAP_POST) { result = bootstrap_handleFinish(contextP, fromSessionH); } break; #endif #endif #ifdef LWM2M_SERVER_MODE case LWM2M_URI_FLAG_REGISTRATION: result = registration_handleRequest(contextP, uriP, fromSessionH, message, response); break; #endif #ifdef LWM2M_BOOTSTRAP_SERVER_MODE case LWM2M_URI_FLAG_BOOTSTRAP: result = bootstrap_handleRequest(contextP, uriP, fromSessionH, message, response); break; #endif default: result = COAP_IGNORE; break; } coap_set_status_code(response, result); if (COAP_IGNORE < result && result < COAP_400_BAD_REQUEST) { result = NO_ERROR; } lwm2m_free(uriP); return result; }
int transaction_send(lwm2m_context_t * contextP, lwm2m_transaction_t * transacP) { bool maxRetriesReached = false; LOG_ARG("Entering: transaction=%p", transacP); if (transacP->buffer == NULL) { transacP->buffer_len = coap_serialize_get_size(transacP->message); if (transacP->buffer_len == 0) { transaction_remove(contextP, transacP); return COAP_500_INTERNAL_SERVER_ERROR; } transacP->buffer = (uint8_t*)lwm2m_malloc(transacP->buffer_len); if (transacP->buffer == NULL) { transaction_remove(contextP, transacP); return COAP_500_INTERNAL_SERVER_ERROR; } transacP->buffer_len = coap_serialize_message(transacP->message, transacP->buffer); if (transacP->buffer_len == 0) { lwm2m_free(transacP->buffer); transacP->buffer = NULL; transaction_remove(contextP, transacP); return COAP_500_INTERNAL_SERVER_ERROR; } } if (!transacP->ack_received) { long unsigned timeout; if (0 == transacP->retrans_counter) { time_t tv_sec = lwm2m_gettime(); if (0 <= tv_sec) { transacP->retrans_time = tv_sec + COAP_RESPONSE_TIMEOUT; transacP->retrans_counter = 1; timeout = 0; } else { maxRetriesReached = true; } } else { timeout = COAP_RESPONSE_TIMEOUT << (transacP->retrans_counter - 1); } if (COAP_MAX_RETRANSMIT + 1 >= transacP->retrans_counter) { (void)lwm2m_buffer_send(transacP->peerH, transacP->buffer, transacP->buffer_len, contextP->userData); transacP->retrans_time += timeout; transacP->retrans_counter += 1; } else { maxRetriesReached = true; } } if (transacP->ack_received || maxRetriesReached) { if (transacP->callback) { LOG_ARG("transaction %p expired..calling callback", transacP); transacP->callback(transacP, NULL); } transaction_remove(contextP, transacP); return -1; } return 0; }
lwm2m_uri_t * lwm2m_decode_uri(char * altPath, multi_option_t *uriPath) { lwm2m_uri_t * uriP; int readNum; uriP = (lwm2m_uri_t *)lwm2m_malloc(sizeof(lwm2m_uri_t)); if (NULL == uriP) return NULL; memset(uriP, 0, sizeof(lwm2m_uri_t)); // Read object ID if (NULL != uriPath && URI_REGISTRATION_SEGMENT_LEN == uriPath->len && 0 == strncmp(URI_REGISTRATION_SEGMENT, (char *)uriPath->data, uriPath->len)) { uriP->flag |= LWM2M_URI_FLAG_REGISTRATION; uriPath = uriPath->next; if (uriPath == NULL) return uriP; } else if (NULL != uriPath && URI_BOOTSTRAP_SEGMENT_LEN == uriPath->len && 0 == strncmp(URI_BOOTSTRAP_SEGMENT, (char *)uriPath->data, uriPath->len)) { uriP->flag |= LWM2M_URI_FLAG_BOOTSTRAP; uriPath = uriPath->next; if (uriPath != NULL) goto error; return uriP; } if ((uriP->flag & LWM2M_URI_MASK_TYPE) != LWM2M_URI_FLAG_REGISTRATION) { // Read altPath if any if (altPath != NULL) { int i; if (NULL == uriPath) { lwm2m_free(uriP); return NULL; } for (i = 0 ; i < uriPath->len ; i++) { if (uriPath->data[i] != altPath[i+1]) { lwm2m_free(uriP); return NULL; } } uriPath = uriPath->next; } if (NULL == uriPath || uriPath->len == 0) { uriP->flag |= LWM2M_URI_FLAG_DELETE_ALL; return uriP; } } readNum = prv_get_number(uriPath->data, uriPath->len); if (readNum < 0 || readNum > LWM2M_MAX_ID) goto error; uriP->objectId = (uint16_t)readNum; uriP->flag |= LWM2M_URI_FLAG_OBJECT_ID; uriPath = uriPath->next; if ((uriP->flag & LWM2M_URI_MASK_TYPE) == LWM2M_URI_FLAG_REGISTRATION) { if (uriPath != NULL) goto error; return uriP; } uriP->flag |= LWM2M_URI_FLAG_DM; if (uriPath == NULL) return uriP; // Read object instance if (uriPath->len != 0) { readNum = prv_get_number(uriPath->data, uriPath->len); if (readNum < 0 || readNum >= LWM2M_MAX_ID) goto error; uriP->instanceId = (uint16_t)readNum; uriP->flag |= LWM2M_URI_FLAG_INSTANCE_ID; } uriPath = uriPath->next; if (uriPath == NULL) return uriP; // Read resource ID if (uriPath->len != 0) { // resource ID without an instance ID is not allowed if ((uriP->flag & LWM2M_URI_FLAG_INSTANCE_ID) == 0) goto error; readNum = prv_get_number(uriPath->data, uriPath->len); if (readNum < 0 || readNum > LWM2M_MAX_ID) goto error; uriP->resourceId = (uint16_t)readNum; uriP->flag |= LWM2M_URI_FLAG_RESOURCE_ID; } // must be the last segment if (NULL == uriPath->next) return uriP; error: lwm2m_free(uriP); return NULL; }
static void prv_location_close(lwm2m_object_t * object) { lwm2m_list_free(object->instanceList); lwm2m_free(object->userData); }
static uint8_t prv_security_write(uint16_t instanceId, int numData, lwm2m_tlv_t * dataArray, lwm2m_object_t * objectP) { security_instance_t * targetP; int i; uint8_t result = COAP_204_CHANGED; targetP = (security_instance_t *)lwm2m_list_find(objectP->instanceList, instanceId); if (NULL == targetP) return COAP_404_NOT_FOUND; i = 0; do { switch (dataArray[i].id) { case LWM2M_SECURITY_URI_ID: if (targetP->uri != NULL) lwm2m_free(targetP->uri); targetP->uri = (char *)lwm2m_malloc(dataArray[i].length + 1); if (targetP->uri != NULL) { strncpy(targetP->uri, dataArray[i].value, dataArray[i].length); result = COAP_204_CHANGED; } else { result = COAP_500_INTERNAL_SERVER_ERROR; } break; case LWM2M_SECURITY_BOOTSTRAP_ID: if (1 == lwm2m_tlv_decode_bool(dataArray + i, &(targetP->isBootstrap))) { result = COAP_204_CHANGED; } else { result = COAP_400_BAD_REQUEST; } break; case LWM2M_SECURITY_SECURITY_ID: // Let just ignore this result = COAP_204_CHANGED; break; case LWM2M_SECURITY_PUBLIC_KEY_ID: // Let just ignore this result = COAP_204_CHANGED; break; case LWM2M_SECURITY_SERVER_PUBLIC_KEY_ID: // Let just ignore this result = COAP_204_CHANGED; break; case LWM2M_SECURITY_SECRET_KEY_ID: // Let just ignore this result = COAP_204_CHANGED; break; case LWM2M_SECURITY_SMS_SECURITY_ID: // Let just ignore this result = COAP_204_CHANGED; break; case LWM2M_SECURITY_SMS_KEY_PARAM_ID: // Let just ignore this result = COAP_204_CHANGED; break; case LWM2M_SECURITY_SMS_SECRET_KEY_ID: // Let just ignore this result = COAP_204_CHANGED; break; case LWM2M_SECURITY_SMS_SERVER_NUMBER_ID: // Let just ignore this result = COAP_204_CHANGED; break; case LWM2M_SECURITY_SHORT_SERVER_ID: { int64_t value; if (1 == lwm2m_tlv_decode_int(dataArray + i, &value)) { if (value >= 0 && value <= 0xFFFF) { targetP->shortID = value; result = COAP_204_CHANGED; } else { result = COAP_406_NOT_ACCEPTABLE; } } else { result = COAP_400_BAD_REQUEST; } } break; case LWM2M_SECURITY_HOLD_OFF_ID: // Let just ignore this result = COAP_204_CHANGED; break; default: return COAP_404_NOT_FOUND; } i++; } while (i < numData && result == COAP_204_CHANGED); return result; }
static int prv_convertRecord(const _record_t * recordArray, int count, lwm2m_data_t ** dataP) { int index; int freeIndex; lwm2m_data_t * rootP; rootP = lwm2m_data_new(count); if (NULL == rootP) { *dataP = NULL; return -1; } freeIndex = 0; for (index = 0 ; index < count ; index++) { lwm2m_data_t * targetP; int i; targetP = json_findDataItem(rootP, count, recordArray[index].ids[0]); if (targetP == NULL) { targetP = rootP + freeIndex; freeIndex++; targetP->id = recordArray[index].ids[0]; targetP->type = LWM2M_TYPE_OBJECT; } if (recordArray[index].ids[1] != LWM2M_MAX_ID) { lwm2m_data_t * parentP; uri_depth_t level; parentP = targetP; level = URI_DEPTH_OBJECT_INSTANCE; for (i = 1 ; i <= 2 ; i++) { if (recordArray[index].ids[i] == LWM2M_MAX_ID) break; targetP = json_findDataItem(parentP->value.asChildren.array, parentP->value.asChildren.count, recordArray[index].ids[i]); if (targetP == NULL) { targetP = json_extendData(parentP); if (targetP == NULL) goto error; targetP->id = recordArray[index].ids[i]; targetP->type = utils_depthToDatatype(level); } level = json_decreaseLevel(level); parentP = targetP; } if (recordArray[index].ids[3] != LWM2M_MAX_ID) { targetP->type = LWM2M_TYPE_MULTIPLE_RESOURCE; targetP = json_extendData(targetP); if (targetP == NULL) goto error; targetP->id = recordArray[index].ids[3]; targetP->type = LWM2M_TYPE_UNDEFINED; } } if (!prv_convertValue(recordArray + index, targetP)) goto error; } if (freeIndex < count) { *dataP = lwm2m_data_new(freeIndex); if (*dataP == NULL) goto error; memcpy(*dataP, rootP, freeIndex * sizeof(lwm2m_data_t)); lwm2m_free(rootP); /* do not use lwm2m_data_free() to keep pointed values */ } else { *dataP = rootP; } return freeIndex; error: lwm2m_data_free(count, rootP); *dataP = NULL; return -1; }
int senml_json_parse(const lwm2m_uri_t * uriP, const uint8_t * buffer, size_t bufferLen, lwm2m_data_t ** dataP) { size_t index; int count = 0; _record_t * recordArray; lwm2m_data_t * parsedP; int recordIndex; char baseUri[URI_MAX_STRING_LEN + 1]; time_t baseTime; lwm2m_data_t baseValue; LOG_ARG("bufferLen: %d, buffer: \"%s\"", bufferLen, (char *)buffer); LOG_URI(uriP); *dataP = NULL; recordArray = NULL; parsedP = NULL; index = json_skipSpace(buffer, bufferLen); if (index == bufferLen) return -1; if (buffer[index] != JSON_HEADER) return -1; _GO_TO_NEXT_CHAR(index, buffer, bufferLen); count = json_countItems(buffer + index, bufferLen - index); if (count <= 0) goto error; recordArray = (_record_t*)lwm2m_malloc(count * sizeof(_record_t)); if (recordArray == NULL) goto error; /* at this point we are sure buffer[index] is '{' and all { and } are matching */ recordIndex = 0; baseUri[0] = '\0'; baseTime = 0; memset(&baseValue, 0, sizeof(baseValue)); while (recordIndex < count) { int itemLen = json_itemLength(buffer + index, bufferLen - index); if (itemLen < 0) goto error; if (prv_parseItem(buffer + index + 1, itemLen - 2, recordArray + recordIndex, baseUri, &baseTime, &baseValue)) { goto error; } recordIndex++; index += itemLen - 1; _GO_TO_NEXT_CHAR(index, buffer, bufferLen); switch (buffer[index]) { case JSON_SEPARATOR: _GO_TO_NEXT_CHAR(index, buffer, bufferLen); break; case JSON_FOOTER: if (recordIndex != count) goto error; break; default: goto error; } } if (buffer[index] != JSON_FOOTER) goto error; lwm2m_data_t * resultP; int size; count = prv_convertRecord(recordArray, count, &parsedP); lwm2m_free(recordArray); recordArray = NULL; if (count > 0 && uriP != NULL && LWM2M_URI_IS_SET_OBJECT(uriP)) { if (parsedP->type != LWM2M_TYPE_OBJECT) goto error; if (parsedP->id != uriP->objectId) goto error; if (!LWM2M_URI_IS_SET_INSTANCE(uriP)) { size = parsedP->value.asChildren.count; resultP = parsedP->value.asChildren.array; } else { int i; resultP = NULL; /* be permissive and allow full object JSON when requesting for a single instance */ for (i = 0 ; i < (int)parsedP->value.asChildren.count && resultP == NULL; i++) { lwm2m_data_t * targetP; targetP = parsedP->value.asChildren.array + i; if (targetP->id == uriP->instanceId) { resultP = targetP->value.asChildren.array; size = targetP->value.asChildren.count; } } if (resultP == NULL) goto error; if (LWM2M_URI_IS_SET_RESOURCE(uriP)) { lwm2m_data_t * resP; resP = NULL; for (i = 0 ; i < size && resP == NULL; i++) { lwm2m_data_t * targetP; targetP = resultP + i; if (targetP->id == uriP->resourceId) { if (targetP->type == LWM2M_TYPE_MULTIPLE_RESOURCE && LWM2M_URI_IS_SET_RESOURCE_INSTANCE(uriP)) { resP = targetP->value.asChildren.array; size = targetP->value.asChildren.count; } else { size = json_dataStrip(1, targetP, &resP); if (size <= 0) goto error; lwm2m_data_free(count, parsedP); parsedP = NULL; } } } if (resP == NULL) goto error; resultP = resP; } if (LWM2M_URI_IS_SET_RESOURCE_INSTANCE(uriP)) { lwm2m_data_t * resP; resP = NULL; for (i = 0 ; i < size && resP == NULL; i++) { lwm2m_data_t * targetP; targetP = resultP + i; if (targetP->id == uriP->resourceInstanceId) { size = json_dataStrip(1, targetP, &resP); if (size <= 0) goto error; lwm2m_data_free(count, parsedP); parsedP = NULL; } } if (resP == NULL) goto error; resultP = resP; } } } else { resultP = parsedP; size = count; } if (parsedP != NULL) { lwm2m_data_t * tempP; size = json_dataStrip(size, resultP, &tempP); if (size <= 0) goto error; lwm2m_data_free(count, parsedP); resultP = tempP; } count = size; *dataP = resultP; LOG_ARG("Parsing successful. count: %d", count); return count; error: LOG("Parsing failed"); if (parsedP != NULL) { lwm2m_data_free(count, parsedP); parsedP = NULL; } if (recordArray != NULL) { lwm2m_free(recordArray); } return -1; }
static bool prv_convertValue(const _record_t * recordP, lwm2m_data_t * targetP) { switch (recordP->value.type) { case LWM2M_TYPE_STRING: if (0 != recordP->value.value.asBuffer.length) { size_t stringLen; uint8_t *string = (uint8_t *)lwm2m_malloc(recordP->value.value.asBuffer.length); if (!string) return false; stringLen = json_unescapeString(string, recordP->value.value.asBuffer.buffer, recordP->value.value.asBuffer.length); if (stringLen) { lwm2m_data_encode_nstring((char *)string, stringLen, targetP); lwm2m_free(string); } else { lwm2m_free(string); return false; } } else { lwm2m_data_encode_nstring(NULL, 0, targetP); } break; case LWM2M_TYPE_OPAQUE: if (0 != recordP->value.value.asBuffer.length) { size_t dataLength; uint8_t *data; dataLength = utils_base64GetDecodedSize((const char *)recordP->value.value.asBuffer.buffer, recordP->value.value.asBuffer.length); data = lwm2m_malloc(dataLength); if (!data) return false; dataLength = utils_base64Decode((const char *)recordP->value.value.asBuffer.buffer, recordP->value.value.asBuffer.length, data, dataLength); if (dataLength) { lwm2m_data_encode_opaque(data, dataLength, targetP); lwm2m_free(data); } else { lwm2m_free(data); return false; } } else { lwm2m_data_encode_opaque(NULL, 0, targetP); } break; default: targetP->type = recordP->value.type; memcpy(&targetP->value, &recordP->value.value, sizeof(targetP->value)); break; case LWM2M_TYPE_OBJECT: case LWM2M_TYPE_OBJECT_INSTANCE: case LWM2M_TYPE_MULTIPLE_RESOURCE: case LWM2M_TYPE_CORE_LINK: /* Should never happen */ return false; } return true; }
int lwm2m_observe_cancel(lwm2m_context_t * contextP, uint16_t clientID, lwm2m_uri_t * uriP, lwm2m_result_callback_t callback, void * userData) { lwm2m_client_t * clientP; lwm2m_observation_t * observationP; LOG_ARG("clientID: %d", clientID); LOG_URI(uriP); clientP = (lwm2m_client_t *)lwm2m_list_find((lwm2m_list_t *)contextP->clientList, clientID); if (clientP == NULL) return COAP_404_NOT_FOUND; observationP = prv_findObservationByURI(clientP, uriP); if (observationP == NULL) return COAP_404_NOT_FOUND; switch (observationP->status) { case STATE_REGISTERED: { lwm2m_transaction_t * transactionP; cancellation_data_t * cancelP; uint8_t token[4]; token[0] = clientP->internalID >> 8; token[1] = clientP->internalID & 0xFF; token[2] = observationP->id >> 8; token[3] = observationP->id & 0xFF; transactionP = transaction_new(clientP->sessionH, COAP_GET, clientP->altPath, uriP, contextP->nextMID++, 4, token); if (transactionP == NULL) { return COAP_500_INTERNAL_SERVER_ERROR; } cancelP = (cancellation_data_t *)lwm2m_malloc(sizeof(cancellation_data_t)); if (cancelP == NULL) { lwm2m_free(transactionP); return COAP_500_INTERNAL_SERVER_ERROR; } coap_set_header_observe(transactionP->message, 1); cancelP->observationP = observationP; cancelP->callbackP = callback; cancelP->userDataP = userData; transactionP->callback = prv_obsCancelRequestCallback; transactionP->userData = (void *)cancelP; contextP->transactionList = (lwm2m_transaction_t *)LWM2M_LIST_ADD(contextP->transactionList, transactionP); return transaction_send(contextP, transactionP); } case STATE_REG_PENDING: observationP->status = STATE_DEREG_PENDING; break; default: // Should not happen break; } return COAP_NO_ERROR; }
int lwm2m_observe(lwm2m_context_t * contextP, uint16_t clientID, lwm2m_uri_t * uriP, lwm2m_result_callback_t callback, void * userData) { lwm2m_client_t * clientP; lwm2m_transaction_t * transactionP; lwm2m_observation_t * observationP; uint8_t token[4]; LOG_ARG("clientID: %d", clientID); LOG_URI(uriP); if (!LWM2M_URI_IS_SET_INSTANCE(uriP) && LWM2M_URI_IS_SET_RESOURCE(uriP)) return COAP_400_BAD_REQUEST; clientP = (lwm2m_client_t *)lwm2m_list_find((lwm2m_list_t *)contextP->clientList, clientID); if (clientP == NULL) return COAP_404_NOT_FOUND; for (observationP = clientP->observationList; observationP != NULL; observationP = observationP->next) { if (uriP->objectId == observationP->uri.objectId && (LWM2M_URI_IS_SET_INSTANCE(uriP) == false || observationP->uri.instanceId == uriP->instanceId) && (LWM2M_URI_IS_SET_INSTANCE(uriP) == false || observationP->uri.instanceId == uriP->instanceId)) { break; } } if (observationP == NULL) { observationP = (lwm2m_observation_t *)lwm2m_malloc(sizeof(lwm2m_observation_t)); if (observationP == NULL) return COAP_500_INTERNAL_SERVER_ERROR; memset(observationP, 0, sizeof(lwm2m_observation_t)); observationP->id = lwm2m_list_newId((lwm2m_list_t *)clientP->observationList); memcpy(&observationP->uri, uriP, sizeof(lwm2m_uri_t)); observationP->clientP = clientP; observationP->clientP->observationList = (lwm2m_observation_t *)LWM2M_LIST_ADD(observationP->clientP->observationList, observationP); } observationP->status = STATE_REG_PENDING; observationP->callback = callback; observationP->userData = userData; token[0] = clientP->internalID >> 8; token[1] = clientP->internalID & 0xFF; token[2] = observationP->id >> 8; token[3] = observationP->id & 0xFF; transactionP = transaction_new(clientP->sessionH, COAP_GET, clientP->altPath, uriP, contextP->nextMID++, 4, token); if (transactionP == NULL) { observationP->clientP->observationList = (lwm2m_observation_t *)LWM2M_LIST_RM(observationP->clientP->observationList, observationP->id, NULL); lwm2m_free(observationP); return COAP_500_INTERNAL_SERVER_ERROR; } coap_set_header_observe(transactionP->message, 0); if (clientP->supportJSON == true) { coap_set_header_accept(transactionP->message, LWM2M_CONTENT_JSON); } else { coap_set_header_accept(transactionP->message, LWM2M_CONTENT_TLV); } transactionP->callback = prv_obsRequestCallback; transactionP->userData = (void *)observationP; contextP->transactionList = (lwm2m_transaction_t *)LWM2M_LIST_ADD(contextP->transactionList, transactionP); return transaction_send(contextP, transactionP); }
int lwm2m_configure(lwm2m_context_t * contextP, const char * endpointName, const char * msisdn, const char * altPath, uint16_t numObject, lwm2m_object_t * objectList[]) { int i; uint8_t found; // This API can be called only once for now if (contextP->endpointName != NULL) return COAP_400_BAD_REQUEST; if (endpointName == NULL) return COAP_400_BAD_REQUEST; if (numObject < 3) return COAP_400_BAD_REQUEST; // Check that mandatory objects are present found = 0; for (i = 0 ; i < numObject ; i++) { if (objectList[i]->objID == LWM2M_SECURITY_OBJECT_ID) found |= 0x01; if (objectList[i]->objID == LWM2M_SERVER_OBJECT_ID) found |= 0x02; if (objectList[i]->objID == LWM2M_DEVICE_OBJECT_ID) found |= 0x04; } if (found != 0x07) return COAP_400_BAD_REQUEST; if (altPath != NULL) { if (0 == prv_isAltPathValid(altPath)) { return COAP_400_BAD_REQUEST; } if (altPath[1] == 0) { altPath = NULL; } } contextP->endpointName = lwm2m_strdup(endpointName); if (contextP->endpointName == NULL) { return COAP_500_INTERNAL_SERVER_ERROR; } if (msisdn != NULL) { contextP->msisdn = lwm2m_strdup(msisdn); if (contextP->msisdn == NULL) { return COAP_500_INTERNAL_SERVER_ERROR; } } if (altPath != NULL) { contextP->altPath = lwm2m_strdup(altPath); if (contextP->altPath == NULL) { return COAP_500_INTERNAL_SERVER_ERROR; } } contextP->objectList = (lwm2m_object_t **)lwm2m_malloc(numObject * sizeof(lwm2m_object_t *)); if (NULL != contextP->objectList) { memcpy(contextP->objectList, objectList, numObject * sizeof(lwm2m_object_t *)); contextP->numObject = numObject; } else { lwm2m_free(contextP->endpointName); contextP->endpointName = NULL; return COAP_500_INTERNAL_SERVER_ERROR; } return COAP_NO_ERROR; }
coap_status_t handle_registration_request(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, void * fromSessionH, coap_packet_t * message, coap_packet_t * response) { coap_status_t result; switch(message->code) { case COAP_POST: { char * name = NULL; lwm2m_client_object_t * objects; lwm2m_client_t * clientP; char location[MAX_LOCATION_LENGTH]; if ((uriP->flag & LWM2M_URI_MASK_ID) != 0) return COAP_400_BAD_REQUEST; prv_getParameters(message->uri_query, &name); if (name == NULL) return COAP_400_BAD_REQUEST; objects = prv_decodeRegisterPayload(message->payload, message->payload_len); if (objects == NULL) { lwm2m_free(name); return COAP_400_BAD_REQUEST; } clientP = prv_getClientByName(contextP, name); if (clientP != NULL) { // we reset this registration lwm2m_free(clientP->name); prv_freeClientObjectList(clientP->objectList); clientP->objectList = NULL; } else { clientP = (lwm2m_client_t *)lwm2m_malloc(sizeof(lwm2m_client_t)); if (clientP == NULL) { lwm2m_free(name); prv_freeClientObjectList(objects); return COAP_500_INTERNAL_SERVER_ERROR; } memset(clientP, 0, sizeof(lwm2m_client_t)); clientP->internalID = lwm2m_list_newId((lwm2m_list_t *)contextP->clientList); contextP->clientList = (lwm2m_client_t *)LWM2M_LIST_ADD(contextP->clientList, clientP); } clientP->name = name; clientP->objectList = objects; clientP->sessionH = fromSessionH; if (prv_getLocationString(clientP->internalID, location) == 0) { prv_freeClient(clientP); return COAP_500_INTERNAL_SERVER_ERROR; } if (coap_set_header_location_path(response, location) == 0) { prv_freeClient(clientP); return COAP_500_INTERNAL_SERVER_ERROR; } if (contextP->monitorCallback != NULL) { contextP->monitorCallback(clientP->internalID, NULL, CREATED_2_01, NULL, 0, contextP->monitorUserData); } result = CREATED_2_01; } break; case COAP_PUT: result = COAP_501_NOT_IMPLEMENTED; break; case COAP_DELETE: { lwm2m_client_t * clientP; if ((uriP->flag & LWM2M_URI_MASK_ID) != LWM2M_URI_FLAG_OBJECT_ID) return COAP_400_BAD_REQUEST; contextP->clientList = (lwm2m_client_t *)LWM2M_LIST_RM(contextP->clientList, uriP->objectId, &clientP); if (clientP == NULL) return COAP_400_BAD_REQUEST; if (contextP->monitorCallback != NULL) { contextP->monitorCallback(clientP->internalID, NULL, DELETED_2_02, NULL, 0, contextP->monitorUserData); } prv_freeClient(clientP); result = DELETED_2_02; } break; default: return COAP_400_BAD_REQUEST; } return result; }
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_ARG("Exiting on success. new transac=%p", transacP); return transacP; error: LOG("Exiting on failure"); lwm2m_free(transacP); return NULL; }
void lwm2m_close(lwm2m_context_t * contextP) { int i; #ifdef LWM2M_CLIENT_MODE for (i = 0 ; i < contextP->numObject ; i++) { if (NULL != contextP->objectList[i]->closeFunc) { contextP->objectList[i]->closeFunc(contextP->objectList[i]); } lwm2m_free(contextP->objectList[i]); } if (NULL != contextP->bootstrapServer) { if (NULL != contextP->bootstrapServer->uri) lwm2m_free (contextP->bootstrapServer->uri); if (NULL != contextP->bootstrapServer->security.privateKey) lwm2m_free (contextP->bootstrapServer->security.privateKey); if (NULL != contextP->bootstrapServer->security.publicKey) lwm2m_free (contextP->bootstrapServer->security.publicKey); lwm2m_free(contextP->bootstrapServer); } while (NULL != contextP->serverList) { lwm2m_server_t * targetP; targetP = contextP->serverList; contextP->serverList = contextP->serverList->next; registration_deregister(contextP, targetP); if (NULL != targetP->location) lwm2m_free(targetP->location); if (NULL != targetP->security.privateKey) lwm2m_free (targetP->security.privateKey); if (NULL != targetP->security.publicKey) lwm2m_free (targetP->security.publicKey); lwm2m_free(targetP); } while (NULL != contextP->observedList) { lwm2m_observed_t * targetP; targetP = contextP->observedList; contextP->observedList = contextP->observedList->next; while (NULL != targetP->watcherList) { lwm2m_watcher_t * watcherP; watcherP = targetP->watcherList; targetP->watcherList = targetP->watcherList->next; lwm2m_free(watcherP); } lwm2m_free(targetP); } if (NULL != contextP->objectList) { lwm2m_free(contextP->objectList); } lwm2m_free(contextP->endpointName); #endif #ifdef LWM2M_SERVER_MODE while (NULL != contextP->clientList) { lwm2m_client_t * clientP; clientP = contextP->clientList; contextP->clientList = contextP->clientList->next; prv_freeClient(clientP); } #endif while (NULL != contextP->transactionList) { lwm2m_transaction_t * transacP; transacP = contextP->transactionList; contextP->transactionList = contextP->transactionList->next; transaction_free(transacP); } lwm2m_free(contextP); }
void free_object_conn_s(lwm2m_object_t * objectP) { lwm2m_free(objectP->userData); lwm2m_list_free(objectP->instanceList); lwm2m_free(objectP); }
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); }
int object_getServers(lwm2m_context_t * contextP) { lwm2m_object_t * securityObjP; lwm2m_object_t * serverObjP; lwm2m_list_t * securityInstP; // instanceID of the server in the LWM2M Security Object int i; for (i = 0 ; i < contextP->numObject ; i++) { if (contextP->objectList[i]->objID == LWM2M_SECURITY_OBJECT_ID) { securityObjP = contextP->objectList[i]; } else if (contextP->objectList[i]->objID == LWM2M_SERVER_OBJECT_ID) { serverObjP = contextP->objectList[i]; } } securityInstP = securityObjP->instanceList; while (securityInstP != NULL) { lwm2m_tlv_t * tlvP; int size; lwm2m_server_t * targetP; bool isBootstrap; int64_t value = 0; size = 3; tlvP = lwm2m_tlv_new(size); if (tlvP == NULL) return -1; tlvP[0].id = LWM2M_SECURITY_BOOTSTRAP_ID; tlvP[1].id = LWM2M_SECURITY_SHORT_SERVER_ID; tlvP[2].id = LWM2M_SECURITY_HOLD_OFF_ID; if (securityObjP->readFunc(securityInstP->id, &size, &tlvP, securityObjP) != COAP_205_CONTENT) { lwm2m_free(tlvP); return -1; } targetP = (lwm2m_server_t *)lwm2m_malloc(sizeof(lwm2m_server_t)); if (targetP == NULL) return -1; memset(targetP, 0, sizeof(lwm2m_server_t)); if (0 == lwm2m_tlv_decode_bool(tlvP + 0, &isBootstrap)) { lwm2m_free(targetP); lwm2m_free(tlvP); return -1; } if (0 == lwm2m_tlv_decode_int(tlvP + 1, &value) || value <= 0 || value >0xFFFF) // 0 is forbidden as a Short Server ID { lwm2m_free(targetP); lwm2m_free(tlvP); return -1; } targetP->shortID = value; if (isBootstrap == true) { if (0 == lwm2m_tlv_decode_int(tlvP + 1, &value) || value < 0 || value >0xFFFFFFFF) // This is an implementation limit { lwm2m_free(targetP); lwm2m_free(tlvP); return -1; } targetP->lifetime = value; contextP->bootstrapServerList = (lwm2m_server_t*)LWM2M_LIST_ADD(contextP->bootstrapServerList, targetP); } else { lwm2m_list_t * serverInstP; // instanceID of the server in the LWM2M Server Object serverInstP = prv_findServerInstance(serverObjP, targetP->shortID); if (serverInstP == NULL) { lwm2m_free(targetP); lwm2m_free(tlvP); return -1; } if (0 != prv_getMandatoryInfo(serverObjP, serverInstP->id, targetP)) { lwm2m_free(targetP); lwm2m_free(tlvP); return -1; } contextP->serverList = (lwm2m_server_t*)LWM2M_LIST_ADD(contextP->serverList, targetP); } lwm2m_free(tlvP); securityInstP = securityInstP->next; } return 0; }
int object_getServers(lwm2m_context_t * contextP) { lwm2m_object_t * securityObjP = NULL; lwm2m_object_t * serverObjP = NULL; lwm2m_list_t * securityInstP; // instanceID of the server in the LWM2M Security Object int i; for (i = 0 ; i < contextP->numObject ; i++) { if (contextP->objectList[i]->objID == LWM2M_SECURITY_OBJECT_ID) { securityObjP = contextP->objectList[i]; } else if (contextP->objectList[i]->objID == LWM2M_SERVER_OBJECT_ID) { serverObjP = contextP->objectList[i]; } } if (NULL == securityObjP) return -1; securityInstP = securityObjP->instanceList; while (securityInstP != NULL) { if (LWM2M_LIST_FIND(contextP->bootstrapServerList, securityInstP->id) == NULL && LWM2M_LIST_FIND(contextP->serverList, securityInstP->id) == NULL) { // This server is new. eg created by last bootstrap lwm2m_data_t * dataP; int size; lwm2m_server_t * targetP; bool isBootstrap; int64_t value = 0; size = 3; dataP = lwm2m_data_new(size); if (dataP == NULL) return -1; dataP[0].id = LWM2M_SECURITY_BOOTSTRAP_ID; dataP[1].id = LWM2M_SECURITY_SHORT_SERVER_ID; dataP[2].id = LWM2M_SECURITY_HOLD_OFF_ID; if (securityObjP->readFunc(securityInstP->id, &size, &dataP, securityObjP) != COAP_205_CONTENT) { lwm2m_data_free(size, dataP); return -1; } targetP = (lwm2m_server_t *)lwm2m_malloc(sizeof(lwm2m_server_t)); if (targetP == NULL) { lwm2m_data_free(size, dataP); return -1; } memset(targetP, 0, sizeof(lwm2m_server_t)); targetP->secObjInstID = securityInstP->id; if (0 == lwm2m_data_decode_bool(dataP + 0, &isBootstrap)) { lwm2m_free(targetP); lwm2m_data_free(size, dataP); return -1; } if (0 == lwm2m_data_decode_int(dataP + 1, &value) || value < (isBootstrap ? 0 : 1) || value > 0xFFFF) // 0 is forbidden as a Short Server ID { lwm2m_free(targetP); lwm2m_data_free(size, dataP); return -1; } targetP->shortID = value; if (isBootstrap == true) { if (0 == lwm2m_data_decode_int(dataP + 2, &value) || value < 0 || value > 0xFFFFFFFF) // This is an implementation limit { lwm2m_free(targetP); lwm2m_data_free(size, dataP); return -1; } // lifetime of a bootstrap server is set to ClientHoldOffTime targetP->lifetime = value; contextP->bootstrapServerList = (lwm2m_server_t*)LWM2M_LIST_ADD(contextP->bootstrapServerList, targetP); } else { lwm2m_list_t * serverInstP; // instanceID of the server in the LWM2M Server Object serverInstP = prv_findServerInstance(serverObjP, targetP->shortID); if (serverInstP == NULL) { lwm2m_free(targetP); lwm2m_data_free(size, dataP); return -1; } if (0 != prv_getMandatoryInfo(serverObjP, serverInstP->id, targetP)) { lwm2m_free(targetP); lwm2m_data_free(size, dataP); return -1; } targetP->status = STATE_DEREGISTERED; contextP->serverList = (lwm2m_server_t*)LWM2M_LIST_ADD(contextP->serverList, targetP); } lwm2m_data_free(size, dataP); } securityInstP = securityInstP->next; } return 0; }
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); }
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; }
/* This function is an adaptation of function coap_receive() from Erbium's er-coap-13-engine.c. * Erbium is Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich * All rights reserved. */ void lwm2m_handle_packet(lwm2m_context_t * contextP, uint8_t * buffer, int length, void * fromSessionH) { coap_status_t coap_error_code = NO_ERROR; static coap_packet_t message[1]; static coap_packet_t response[1]; coap_error_code = coap_parse_message(message, buffer, (uint16_t)length); if (message[0].uri_path && message[0].uri_path->next && (message[0].uri_path->next->is_static != 0 && message[0].uri_path->next->is_static != 1)) { printf("BLA\n"); } if (coap_error_code == NO_ERROR) { LOG(" Parsed: ver %u, type %u, tkl %u, code %u.%.2u, mid %u\r\n", message->version, message->type, message->token_len, message->code >> 5, message->code & 0x1F, message->mid); LOG(" Content type: %d\r\n Payload: %.*s\r\n\n", message->content_type, message->payload_len, message->payload); if (message->code >= COAP_GET && message->code <= COAP_DELETE) { uint32_t block_num = 0; uint16_t block_size = REST_MAX_CHUNK_SIZE; uint32_t block_offset = 0; int64_t new_offset = 0; /* prepare response */ if (message->type == COAP_TYPE_CON) { /* Reliable CON requests are answered with an ACK. */ coap_init_message(response, COAP_TYPE_ACK, COAP_205_CONTENT, message->mid); } else { /* Unreliable NON requests are answered with a NON as well. */ coap_init_message(response, COAP_TYPE_NON, COAP_205_CONTENT, contextP->nextMID++); } /* mirror token */ if (message->token_len) { coap_set_header_token(response, message->token, message->token_len); } /* get offset for blockwise transfers */ if (coap_get_header_block2(message, &block_num, NULL, &block_size, &block_offset)) { LOG("Blockwise: block request %u (%u/%u) @ %u bytes\n", block_num, block_size, REST_MAX_CHUNK_SIZE, block_offset); block_size = MIN(block_size, REST_MAX_CHUNK_SIZE); new_offset = block_offset; } coap_error_code = handle_request(contextP, fromSessionH, message, response); if (coap_error_code==NO_ERROR) { /* Apply blockwise transfers. */ if ( IS_OPTION(message, COAP_OPTION_BLOCK1) && response->code<COAP_400_BAD_REQUEST && !IS_OPTION(response, COAP_OPTION_BLOCK1) ) { LOG("Block1 NOT IMPLEMENTED\n"); coap_error_code = COAP_501_NOT_IMPLEMENTED; coap_error_message = "NoBlock1Support"; } else if ( IS_OPTION(message, COAP_OPTION_BLOCK2) ) { /* unchanged new_offset indicates that resource is unaware of blockwise transfer */ if (new_offset==block_offset) { LOG("Blockwise: unaware resource with payload length %u/%u\n", response->payload_len, block_size); if (block_offset >= response->payload_len) { LOG("handle_incoming_data(): block_offset >= response->payload_len\n"); response->code = COAP_402_BAD_OPTION; coap_set_payload(response, "BlockOutOfScope", 15); /* a const char str[] and sizeof(str) produces larger code size */ } else { coap_set_header_block2(response, block_num, response->payload_len - block_offset > block_size, block_size); coap_set_payload(response, response->payload+block_offset, MIN(response->payload_len - block_offset, block_size)); } /* if (valid offset) */ } else { /* resource provides chunk-wise data */ LOG("Blockwise: blockwise resource, new offset %d\n", (int) new_offset); coap_set_header_block2(response, block_num, new_offset!=-1 || response->payload_len > block_size, block_size); if (response->payload_len > block_size) coap_set_payload(response, response->payload, block_size); } /* if (resource aware of blockwise) */ } else if (new_offset!=0) { LOG("Blockwise: no block option for blockwise resource, using block size %u\n", REST_MAX_CHUNK_SIZE); coap_set_header_block2(response, 0, new_offset!=-1, REST_MAX_CHUNK_SIZE); coap_set_payload(response, response->payload, MIN(response->payload_len, REST_MAX_CHUNK_SIZE)); } /* if (blockwise request) */ coap_error_code = message_send(contextP, response, fromSessionH); lwm2m_free(response->payload); response->payload = NULL; response->payload_len = 0; } else if (coap_error_code != COAP_IGNORE) { if (1 == coap_set_status_code(response, coap_error_code)) { coap_error_code = message_send(contextP, response, fromSessionH); } } } else { /* Responses */ switch (message->type) { case COAP_TYPE_NON: case COAP_TYPE_CON: { bool done = transaction_handleResponse(contextP, fromSessionH, message, response); #ifdef LWM2M_SERVER_MODE if (!done && IS_OPTION(message, COAP_OPTION_OBSERVE) && ((message->code == COAP_204_CHANGED) || (message->code == COAP_205_CONTENT))) { done = observe_handleNotify(contextP, fromSessionH, message, response); } #endif if (!done && message->type == COAP_TYPE_CON ) { coap_init_message(response, COAP_TYPE_ACK, 0, message->mid); coap_error_code = message_send(contextP, response, fromSessionH); } } break; case COAP_TYPE_RST: /* Cancel possible subscriptions. */ handle_reset(contextP, fromSessionH, message); transaction_handleResponse(contextP, fromSessionH, message, NULL); break; case COAP_TYPE_ACK: transaction_handleResponse(contextP, fromSessionH, message, NULL); break; default: break; } } /* Request or Response */ coap_free_header(message); } /* if (parsed correctly) */
static void prv_close(lwm2m_object_t * objectP) { lwm2m_free(objectP->userData); lwm2m_list_free(objectP->instanceList); }
static lwm2m_client_object_t * prv_decodeRegisterPayload(uint8_t * payload, uint16_t payloadLength, bool * supportJSON, char ** altPath) { uint16_t index; lwm2m_client_object_t * objList; bool linkAttrFound; *altPath = NULL; *supportJSON = false; objList = NULL; linkAttrFound = false; index = 0; while (index <= payloadLength) { uint16_t start; uint16_t length; int result; uint16_t id; uint16_t instance; while (index < payloadLength && payload[index] == ' ') index++; if (index == payloadLength) break; start = index; while (index < payloadLength && payload[index] != REG_DELIMITER) index++; length = index - start; result = prv_getId(payload + start, length, &id, &instance); if (result != 0) { lwm2m_client_object_t * objectP; objectP = (lwm2m_client_object_t *)lwm2m_list_find((lwm2m_list_t *)objList, id); if (objectP == NULL) { objectP = (lwm2m_client_object_t *)lwm2m_malloc(sizeof(lwm2m_client_object_t)); memset(objectP, 0, sizeof(lwm2m_client_object_t)); if (objectP == NULL) goto error; objectP->id = id; objList = (lwm2m_client_object_t *)LWM2M_LIST_ADD(objList, objectP); } if (result == 2) { lwm2m_list_t * instanceP; instanceP = lwm2m_list_find(objectP->instanceList, instance); if (instanceP == NULL) { instanceP = (lwm2m_list_t *)lwm2m_malloc(sizeof(lwm2m_list_t)); memset(instanceP, 0, sizeof(lwm2m_list_t)); instanceP->id = instance; objectP->instanceList = LWM2M_LIST_ADD(objectP->instanceList, instanceP); } } } else if (linkAttrFound == false) { result = prv_parseLinkAttributes(payload + start, length, supportJSON, altPath); if (result == 0) goto error; linkAttrFound = true; } else goto error; index++; } return objList; error: if (*altPath != NULL) { lwm2m_free(*altPath); *altPath = NULL; } prv_freeClientObjectList(objList); return NULL; }
void observe_step(lwm2m_context_t * contextP, time_t currentTime, time_t * timeoutP) { lwm2m_observed_t * targetP; LOG("Entering"); for (targetP = contextP->observedList ; targetP != NULL ; targetP = targetP->next) { lwm2m_watcher_t * watcherP; uint8_t * buffer = NULL; size_t length = 0; lwm2m_data_t * dataP = NULL; int size = 0; double floatValue = 0; int64_t integerValue = 0; bool storeValue = false; coap_packet_t message[1]; time_t interval; LOG_URI(&(targetP->uri)); if (LWM2M_URI_IS_SET_RESOURCE(&targetP->uri)) { if (COAP_205_CONTENT != object_readData(contextP, &targetP->uri, &size, &dataP)) continue; switch (dataP->type) { case LWM2M_TYPE_INTEGER: if (1 != lwm2m_data_decode_int(dataP, &integerValue)) { lwm2m_data_free(size, dataP); continue; } storeValue = true; break; case LWM2M_TYPE_FLOAT: if (1 != lwm2m_data_decode_float(dataP, &floatValue)) { lwm2m_data_free(size, dataP); continue; } storeValue = true; break; default: break; } } for (watcherP = targetP->watcherList ; watcherP != NULL ; watcherP = watcherP->next) { if (watcherP->active == true) { bool notify = false; if (watcherP->update == true) { // value changed, should we notify the server ? if (watcherP->parameters == NULL || watcherP->parameters->toSet == 0) { // no conditions notify = true; LOG("Notify with no conditions"); LOG_URI(&(targetP->uri)); } if (notify == false && watcherP->parameters != NULL && (watcherP->parameters->toSet & ATTR_FLAG_NUMERIC) != 0) { if ((watcherP->parameters->toSet & LWM2M_ATTR_FLAG_LESS_THAN) != 0) { LOG("Checking lower threshold"); // Did we cross the lower threshold ? switch (dataP->type) { case LWM2M_TYPE_INTEGER: if ((integerValue <= watcherP->parameters->lessThan && watcherP->lastValue.asInteger > watcherP->parameters->lessThan) || (integerValue >= watcherP->parameters->lessThan && watcherP->lastValue.asInteger < watcherP->parameters->lessThan)) { LOG("Notify on lower threshold crossing"); notify = true; } break; case LWM2M_TYPE_FLOAT: if ((floatValue <= watcherP->parameters->lessThan && watcherP->lastValue.asFloat > watcherP->parameters->lessThan) || (floatValue >= watcherP->parameters->lessThan && watcherP->lastValue.asFloat < watcherP->parameters->lessThan)) { LOG("Notify on lower threshold crossing"); notify = true; } break; default: break; } } if ((watcherP->parameters->toSet & LWM2M_ATTR_FLAG_GREATER_THAN) != 0) { LOG("Checking upper threshold"); // Did we cross the upper threshold ? switch (dataP->type) { case LWM2M_TYPE_INTEGER: if ((integerValue <= watcherP->parameters->greaterThan && watcherP->lastValue.asInteger > watcherP->parameters->greaterThan) || (integerValue >= watcherP->parameters->greaterThan && watcherP->lastValue.asInteger < watcherP->parameters->greaterThan)) { LOG("Notify on lower upper crossing"); notify = true; } break; case LWM2M_TYPE_FLOAT: if ((floatValue <= watcherP->parameters->greaterThan && watcherP->lastValue.asFloat > watcherP->parameters->greaterThan) || (floatValue >= watcherP->parameters->greaterThan && watcherP->lastValue.asFloat < watcherP->parameters->greaterThan)) { LOG("Notify on lower upper crossing"); notify = true; } break; default: break; } } if ((watcherP->parameters->toSet & LWM2M_ATTR_FLAG_STEP) != 0) { LOG("Checking step"); switch (dataP->type) { case LWM2M_TYPE_INTEGER: { int64_t diff; diff = integerValue - watcherP->lastValue.asInteger; if ((diff < 0 && (0 - diff) >= watcherP->parameters->step) || (diff >= 0 && diff >= watcherP->parameters->step)) { LOG("Notify on step condition"); notify = true; } } break; case LWM2M_TYPE_FLOAT: { double diff; diff = floatValue - watcherP->lastValue.asFloat; if ((diff < 0 && (0 - diff) >= watcherP->parameters->step) || (diff >= 0 && diff >= watcherP->parameters->step)) { LOG("Notify on step condition"); notify = true; } } break; default: break; } } } if (watcherP->parameters != NULL && (watcherP->parameters->toSet & LWM2M_ATTR_FLAG_MIN_PERIOD) != 0) { LOG_ARG("Checking minimal period (%d s)", watcherP->parameters->minPeriod); if (watcherP->lastTime + watcherP->parameters->minPeriod > currentTime) { // Minimum Period did not elapse yet interval = watcherP->lastTime + watcherP->parameters->minPeriod - currentTime; if (*timeoutP > interval) *timeoutP = interval; notify = false; } else { LOG("Notify on minimal period"); notify = true; } } } // Is the Maximum Period reached ? if (notify == false && watcherP->parameters != NULL && (watcherP->parameters->toSet & LWM2M_ATTR_FLAG_MAX_PERIOD) != 0) { LOG_ARG("Checking maximal period (%d s)", watcherP->parameters->minPeriod); if (watcherP->lastTime + watcherP->parameters->maxPeriod <= currentTime) { LOG("Notify on maximal period"); notify = true; } } if (notify == true) { if (buffer == NULL) { if (dataP != NULL) { int res; res = lwm2m_data_serialize(&targetP->uri, size, dataP, &(watcherP->format), &buffer); if (res < 0) { break; } else { length = (size_t)res; } } else { if (COAP_205_CONTENT != object_read(contextP, &targetP->uri, &(watcherP->format), &buffer, &length)) { buffer = NULL; break; } } coap_init_message(message, COAP_TYPE_NON, COAP_205_CONTENT, 0); coap_set_header_content_type(message, watcherP->format); coap_set_payload(message, buffer, length); } watcherP->lastTime = currentTime; watcherP->lastMid = contextP->nextMID++; message->mid = watcherP->lastMid; coap_set_header_token(message, watcherP->token, watcherP->tokenLen); coap_set_header_observe(message, watcherP->counter++); (void)message_send(contextP, message, watcherP->server->sessionH); watcherP->update = false; } // Store this value if (notify == true && storeValue == true) { switch (dataP->type) { case LWM2M_TYPE_INTEGER: watcherP->lastValue.asInteger = integerValue; break; case LWM2M_TYPE_FLOAT: watcherP->lastValue.asFloat = floatValue; break; default: break; } } if (watcherP->parameters != NULL && (watcherP->parameters->toSet & LWM2M_ATTR_FLAG_MAX_PERIOD) != 0) { // update timers interval = watcherP->lastTime + watcherP->parameters->maxPeriod - currentTime; if (*timeoutP > interval) *timeoutP = interval; } } } if (dataP != NULL) lwm2m_data_free(size, dataP); if (buffer != NULL) lwm2m_free(buffer); } }