int lwm2m_step(lwm2m_context_t * contextP, struct timeval * timeoutP) { lwm2m_transaction_t * transacP; struct timeval tv; if (0 != lwm2m_gettimeofday(&tv, NULL)) return COAP_500_INTERNAL_SERVER_ERROR; transacP = contextP->transactionList; while (transacP != NULL) { // transaction_send() may remove transaction from the linked list lwm2m_transaction_t * nextP = transacP->next; int removed = 0; if (transacP->retrans_time <= tv.tv_sec) { removed = transaction_send(contextP, transacP); } if (0 == removed) { time_t interval; if (transacP->retrans_time > tv.tv_sec) { interval = transacP->retrans_time - tv.tv_sec; } else { interval = 1; } if (timeoutP->tv_sec > interval) { timeoutP->tv_sec = interval; } } transacP = nextP; } return 0; }
static void prv_handleRegistrationReply(lwm2m_transaction_t * transacP, void * message) { lwm2m_server_t * targetP; coap_packet_t * packet = (coap_packet_t *)message; targetP = (lwm2m_server_t *)(transacP->peerP); struct timeval tv; switch(targetP->status) { case STATE_REG_PENDING: { if (packet == NULL) { targetP->status = STATE_UNKNOWN; targetP->mid = 0; } else if (packet->mid == targetP->mid && packet->type == COAP_TYPE_ACK && packet->location_path != NULL) { if (packet->code == CREATED_2_01) { targetP->status = STATE_REGISTERED; targetP->location = coap_get_multi_option_as_string(packet->location_path); if (0 == lwm2m_gettimeofday(&tv, NULL)) { targetP->registration = tv.tv_sec; } } else if (packet->code == BAD_REQUEST_4_00) { targetP->status = STATE_UNKNOWN; targetP->mid = 0; } } } break; default: break; } }
static void prv_handleRegistrationUpdateReply(lwm2m_transaction_t * transacP, void * message) { lwm2m_server_t * targetP; coap_packet_t * packet = (coap_packet_t *)message; struct timeval tv; targetP = (lwm2m_server_t *)(transacP->peerP); switch(targetP->status) { case STATE_REG_UPDATE_PENDING: { if (packet == NULL) { targetP->status = STATE_UNKNOWN; targetP->mid = 0; } else if (packet->mid == targetP->mid && packet->type == COAP_TYPE_ACK) { if (packet->code == CHANGED_2_04) { if (0 == lwm2m_gettimeofday(&tv, NULL)) { targetP->registration = tv.tv_sec; } targetP->status = STATE_REGISTERED; } else if (packet->code == BAD_REQUEST_4_00) { targetP->status = STATE_UNKNOWN; targetP->mid = 0; // trigger a new registration? infinite loop? } } } break; default: break; } }
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; struct timeval tv; if (lwm2m_gettimeofday(&tv, NULL) != 0) { return COAP_500_INTERNAL_SERVER_ERROR; } switch(message->code) { case COAP_POST: { char * name = NULL; uint32_t lifetime; char * msisdn; lwm2m_binding_t binding; 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; if (0 != prv_getParameters(message->uri_query, &name, &lifetime, &msisdn, &binding)) { return COAP_400_BAD_REQUEST; } objects = prv_decodeRegisterPayload(message->payload, message->payload_len); if (objects == NULL) { lwm2m_free(name); if (msisdn != NULL) lwm2m_free(msisdn); return COAP_400_BAD_REQUEST; } // Endpoint client name is mandatory if (name == NULL) { if (msisdn != NULL) lwm2m_free(msisdn); return COAP_400_BAD_REQUEST; } if (lifetime == 0) { lifetime = LWM2M_DEFAULT_LIFETIME; } clientP = prv_getClientByName(contextP, name); if (clientP != NULL) { // we reset this registration lwm2m_free(clientP->name); if (clientP->msisdn != NULL) lwm2m_free(clientP->msisdn); prv_freeClientObjectList(clientP->objectList); clientP->objectList = NULL; } else { clientP = (lwm2m_client_t *)lwm2m_malloc(sizeof(lwm2m_client_t)); if (clientP == NULL) { lwm2m_free(name); if (msisdn != NULL) lwm2m_free(msisdn); prv_freeClientObjectList(objects); return COAP_500_INTERNAL_SERVER_ERROR; } memset(clientP, 0, sizeof(lwm2m_client_t)); clientP->internalID = lwm2m_list_newId((lwm2m_list_t *)contextP->clientList); contextP->clientList = (lwm2m_client_t *)LWM2M_LIST_ADD(contextP->clientList, clientP); } clientP->name = name; clientP->binding = binding; clientP->msisdn = msisdn; clientP->lifetime = lifetime; clientP->endOfLife = tv.tv_sec + lifetime; 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 = COAP_201_CREATED; } break; case COAP_PUT: { char * name = NULL; uint32_t lifetime; char * msisdn; lwm2m_binding_t binding; lwm2m_client_object_t * objects; lwm2m_client_t * clientP; if ((uriP->flag & LWM2M_URI_MASK_ID) != LWM2M_URI_FLAG_OBJECT_ID) return COAP_400_BAD_REQUEST; clientP = (lwm2m_client_t *)lwm2m_list_find((lwm2m_list_t *)contextP->clientList, uriP->objectId); if (clientP == NULL) return COAP_404_NOT_FOUND; if (0 != prv_getParameters(message->uri_query, &name, &lifetime, &msisdn, &binding)) { return COAP_400_BAD_REQUEST; } objects = prv_decodeRegisterPayload(message->payload, message->payload_len); // Endpoint client name MUST NOT be present if (name != NULL) { lwm2m_free(name); if (msisdn != NULL) lwm2m_free(msisdn); return COAP_400_BAD_REQUEST; } if (binding != BINDING_UNKNOWN) { clientP->binding = binding; } if (msisdn != NULL) { if (clientP->msisdn != NULL) lwm2m_free(clientP->msisdn); clientP->msisdn = msisdn; } if (lifetime != 0) { clientP->lifetime = lifetime; } // client IP address, port or MSISDN may have changed clientP->sessionH = fromSessionH; if (objects != NULL) { lwm2m_observation_t * observationP; // remove observations on object/instance no longer existing observationP = clientP->observationList; while (observationP != NULL) { lwm2m_client_object_t * objP; lwm2m_observation_t * nextP; nextP = observationP->next; objP = (lwm2m_client_object_t *)lwm2m_list_find((lwm2m_list_t *)objects, observationP->uri.objectId); if (objP == NULL) { observationP->callback(clientP->internalID, &observationP->uri, COAP_202_DELETED, NULL, 0, observationP->userData); observation_remove(clientP, observationP); } else { if ((observationP->uri.flag & LWM2M_URI_FLAG_INSTANCE_ID) != 0) { if (lwm2m_list_find((lwm2m_list_t *)objP->instanceList, observationP->uri.instanceId) == NULL) { observationP->callback(clientP->internalID, &observationP->uri, COAP_202_DELETED, NULL, 0, observationP->userData); observation_remove(clientP, observationP); } } } observationP = nextP; } prv_freeClientObjectList(clientP->objectList); clientP->objectList = objects; } clientP->endOfLife = tv.tv_sec + clientP->lifetime; if (contextP->monitorCallback != NULL) { contextP->monitorCallback(clientP->internalID, NULL, COAP_204_CHANGED, NULL, 0, contextP->monitorUserData); } result = COAP_204_CHANGED; } 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 = COAP_202_DELETED; } break; default: return COAP_400_BAD_REQUEST; } return result; }
int transaction_send(lwm2m_context_t * contextP, lwm2m_transaction_t * transacP) { if (transacP->buffer == NULL) { uint8_t tempBuffer[LWM2M_MAX_PACKET_SIZE]; int length; length = coap_serialize_message(transacP->message, tempBuffer); if (length <= 0) return COAP_500_INTERNAL_SERVER_ERROR; transacP->buffer = (uint8_t*)lwm2m_malloc(length); if (transacP->buffer == NULL) return COAP_500_INTERNAL_SERVER_ERROR; memcpy(transacP->buffer, tempBuffer, length); transacP->buffer_len = length; } switch(transacP->peerType) { case ENDPOINT_CLIENT: LOG("Sending %d bytes\r\n", transacP->buffer_len); contextP->bufferSendCallback(((lwm2m_client_t*)transacP->peerP)->sessionH, transacP->buffer, transacP->buffer_len, contextP->bufferSendUserData); break; case ENDPOINT_SERVER: LOG("Sending %d bytes\r\n", transacP->buffer_len); contextP->bufferSendCallback(((lwm2m_server_t*)transacP->peerP)->sessionH, transacP->buffer, transacP->buffer_len, contextP->bufferSendUserData); break; case ENDPOINT_BOOTSTRAP: // not implemented yet break; default: return 0; } if (transacP->retrans_counter == 0) { struct timeval tv; if (0 == lwm2m_gettimeofday(&tv, NULL)) { transacP->retrans_time = tv.tv_sec; transacP->retrans_counter = 1; } else { // crude error handling transacP->retrans_counter = COAP_MAX_RETRANSMIT; } } if (transacP->retrans_counter < COAP_MAX_RETRANSMIT) { transacP->retrans_time += COAP_RESPONSE_TIMEOUT * transacP->retrans_counter; transacP->retrans_counter++; } else { if (transacP->callback) { transacP->callback(transacP, NULL); } transaction_remove(contextP, transacP); return -1; } return 0; }