static void prv_restore_objects(lwm2m_context_t * context) { uint16_t i; /* * Restore content of objects 0 (security) and 1 (server) */ for (i = 0; i < context->numObject; i++) { lwm2m_object_t * object = context->objectList[i]; if (NULL != object) { switch (object->objID) { case LWM2M_SECURITY_OBJECT_ID: // first delete internal content object->closeFunc(object); // then restore previous object copy_security_object(object, backupObjectArray[0]); break; case LWM2M_SERVER_OBJECT_ID: // first delete internal content object->closeFunc(object); // then restore previous object copy_server_object(object, backupObjectArray[1]); break; default: break; } } } // restart the old servers lwm2m_start(context); fprintf(stdout, "[BOOTSTRAP] ObjectList restored\r\n"); }
void update_bootstrap_state(lwm2m_context_t * context, uint32_t currentTime, time_t* timeoutP) { if (context->bsState == BOOTSTRAP_REQUESTED) { context->bsState = BOOTSTRAP_CLIENT_HOLD_OFF; context->bsStart = currentTime; LOG("[BOOTSTRAP] Bootstrap requested at: %lu, now waiting during ClientHoldOffTime...\r\n", (unsigned long)context->bsStart); } if (context->bsState == BOOTSTRAP_CLIENT_HOLD_OFF) { lwm2m_server_t * bootstrapServer = context->bootstrapServerList; if (bootstrapServer != NULL) { // get ClientHoldOffTime from bootstrapServer->lifetime // (see objects.c => object_getServers()) int32_t timeToBootstrap = (context->bsStart + bootstrapServer->lifetime) - currentTime; LOG("[BOOTSTRAP] ClientHoldOffTime %ld\r\n", (long)timeToBootstrap); if (0 >= timeToBootstrap) { bootstrap_initiating_request(context); } else if (timeToBootstrap < *timeoutP) { *timeoutP = timeToBootstrap; } } else { bootstrap_failed(context); } } if (context->bsState == BOOTSTRAP_PENDING) { // Use COAP_DEFAULT_MAX_AGE according proposal in // https://github.com/OpenMobileAlliance/OMA-LwM2M-Public-Review/issues/35 int32_t timeToBootstrap = (context->bsStart + COAP_DEFAULT_MAX_AGE) - currentTime; LOG("[BOOTSTRAP] Pending %ld\r\n", (long)timeToBootstrap); if (0 >= timeToBootstrap) { // Time out and no error => bootstrap OK // TODO: add smarter condition for bootstrap success: // 1) security object contains at least one bootstrap server // 2) there are coherent configurations for provisioned DM servers // if these conditions are not met, then bootstrap has failed and previous security // and server object configurations might be restored by client LOG("\r\n[BOOTSTRAP] Bootstrap finished at: %lu (difftime: %lu s)\r\n", (unsigned long)currentTime, (unsigned long)(currentTime - context->bsStart)); context->bsState = BOOTSTRAP_FINISHED; context->bsStart = currentTime; *timeoutP = 1; } else if (timeToBootstrap < *timeoutP) { *timeoutP = timeToBootstrap; } } else if (context->bsState == BOOTSTRAP_FINISHED) { context->bsStart = currentTime; if (0 <= lwm2m_start(context)) { context->bsState = BOOTSTRAPPED; } else { bootstrap_failed(context); } // during next step, lwm2m_update_registrations will connect the client to DM server } if (BOOTSTRAP_FAILED == context->bsState) { lwm2m_server_t * bootstrapServer = context->bootstrapServerList; if (bootstrapServer != NULL) { // get ClientHoldOffTime from bootstrapServer->lifetime // (see objects.c => object_getServers()) int32_t timeToBootstrap = (context->bsStart + bootstrapServer->lifetime) - currentTime; LOG("[BOOTSTRAP] Bootstrap failed: %lu, now waiting during ClientHoldOffTime %ld ...\r\n", (unsigned long)context->bsStart, (long)timeToBootstrap); if (0 >= timeToBootstrap) { context->bsState = NOT_BOOTSTRAPPED; context->bsStart = currentTime; LOG("[BOOTSTRAP] Bootstrap failed: retry ...\r\n"); *timeoutP = 1; } else if (timeToBootstrap < *timeoutP) { *timeoutP = timeToBootstrap; } } } }
int main() { int result; lwm2m_object_t * objArray[4]; printf("Start\n"); ethSetup(); printf("Initializing tinydtls\n"); // fake loading of PSK.. psk_id_length = strlen(PSK_DEFAULT_IDENTITY); psk_key_length = strlen(PSK_DEFAULT_KEY); memcpy(psk_id, PSK_DEFAULT_IDENTITY, psk_id_length); memcpy(psk_key, PSK_DEFAULT_KEY, psk_key_length); printf("Init\n"); dtls_init(); printf("New context\n"); dtls_context = dtls_new_context(&lwm2mH); if (dtls_context == NULL) { printf("error creating the dtls context\n"); } printf("Setting handlers\n"); dtls_set_handler(dtls_context, &cb); if (!dtls_context) { printf("can't create dtls_context\n"); exit(-1); } printf("Initialazing Wakaama\n"); // create objects objArray[0] = get_security_object(123, "coaps://5.39.83.206:5684", false); securityObjP = objArray[0]; objArray[1] = get_server_object(123, "U", 20, false); serverObject = objArray[1]; objArray[2] = get_object_device(); objArray[3] = get_object_firmware(); /* * The liblwm2m library is now initialized with the functions that will be in * charge of communication */ lwm2mH = lwm2m_init(prv_connect_server, prv_buffer_send, NULL); if (NULL == lwm2mH) { fprintf(stderr, "lwm2m_init() failed\r\n"); return -1; } // configure the liblwm2m lib result = lwm2m_configure(lwm2mH, "julien", NULL, 4, objArray); if (result != 0) { printf("lwm2m_configure() failed: 0x%X\n", result); return -1; } // start result = lwm2m_start(lwm2mH); if (result != 0) { printf("lwm2m_start() failed: 0x%X\n", result); return -1; } // main loop while (true) { char buffer[1024]; Endpoint server; printf("loop...\n"); struct timeval timeout; timeout.tv_sec = 10; timeout.tv_usec = 0; result = lwm2m_step(lwm2mH, &timeout); if (result != 0) { printf("lwm2m_step error %d\n", result); } int n = udp.receiveFrom(server, buffer, sizeof(buffer)); printf("Received packet from: %s of size %d\n", server.get_address(), n); if (n>0) { // TODO: find connection connection_t * connP = connList; while(connP != NULL) { if (strcmp(connP->host, server.get_address()) == 0) { printf("found connection\n"); // is it a secure connection? if (connP->dtlsSession != NULL) { printf("dtls session\n"); result = dtls_handle_message(dtls_context, connP->dtlsSession, buffer, n); printf("dtls handle message %d\n",result); } else { printf("nosec session\n"); lwm2m_handle_packet(lwm2mH, (uint8_t*)buffer, n, (void*)connP); } break; } } if (connP == NULL) printf("no connection\n"); } } }
int main(int argc, char *argv[]) { client_data_t data; int result; lwm2m_context_t * lwm2mH = NULL; int i; const char * localPort = "56830"; const char * server = "localhost"; const char * serverPort = LWM2M_STANDARD_PORT_STR; char * name = "testlwm2mclient"; int lifetime = 300; int batterylevelchanging = 0; time_t reboot_time = 0; int opt; bool bootstrapRequested = false; #ifdef LWM2M_BOOTSTRAP lwm2m_bootstrap_state_t previousBootstrapState = NOT_BOOTSTRAPPED; #endif /* * The function start by setting up the command line interface (which may or not be useful depending on your project) * * This is an array of commands describes as { name, description, long description, callback, userdata }. * 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}, #ifdef LWM2M_BOOTSTRAP {"bootstrap", "Initiate a DI bootstrap process", NULL, prv_initiate_bootstrap, NULL}, {"disp", "Display current objects/instances/resources", NULL, prv_display_objects, 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}, {"dump", "Dump an Object", "dump URI" "URI: uri of the Object or Instance such as /3/0, /1\r\n", prv_object_dump, 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)); while ((opt = getopt(argc, argv, "bcl:n:p:t:h:")) != -1) { switch (opt) { case 'b': bootstrapRequested = true; break; case 'c': batterylevelchanging = 1; break; case 't': sscanf(optarg, "%d", &lifetime); break; case 'n': name = optarg; break; case 'l': localPort = optarg; break; case 'h': server = optarg; break; case 'p': serverPort = optarg; break; default: print_usage(); return 0; } } /* *This call an internal function that create an IPV6 socket on the port 5683. */ fprintf(stderr, "Trying to bind LWM2M Client to port %s\r\n", localPort); data.sock = create_socket(localPort); if (data.sock < 0) { fprintf(stderr, "Failed to open socket: %d\r\n", errno); return -1; } /* * Now the main function fill an array with each object, this list will be later passed to liblwm2m. * Those functions are located in their respective object file. */ char serverUri[50]; int serverId = 123; sprintf (serverUri, "coap://%s:%s", server, serverPort); #ifdef LWM2M_BOOTSTRAP objArray[0] = get_security_object(serverId, serverUri, bootstrapRequested); #else objArray[0] = get_security_object(serverId, serverUri, false); #endif if (NULL == objArray[0]) { fprintf(stderr, "Failed to create security object\r\n"); return -1; } data.securityObjP = objArray[0]; objArray[1] = get_server_object(serverId, "U", lifetime, false); if (NULL == objArray[1]) { fprintf(stderr, "Failed to create server object\r\n"); return -1; } objArray[2] = get_object_device(); if (NULL == objArray[2]) { fprintf(stderr, "Failed to create Device object\r\n"); return -1; } objArray[3] = get_object_firmware(); if (NULL == objArray[3]) { fprintf(stderr, "Failed to create Firmware object\r\n"); return -1; } objArray[4] = get_object_location(); if (NULL == objArray[4]) { fprintf(stderr, "Failed to create location object\r\n"); return -1; } objArray[5] = get_test_object(); if (NULL == objArray[5]) { fprintf(stderr, "Failed to create test object\r\n"); return -1; } objArray[6] = get_object_conn_m(); if (NULL == objArray[6]) { fprintf(stderr, "Failed to create connectivity monitoring object\r\n"); return -1; } objArray[7] = get_object_conn_s(); if (NULL == objArray[7]) { fprintf(stderr, "Failed to create connectivity statistics object\r\n"); return -1; } int instId = 0; objArray[8] = acc_ctrl_create_object(); if (NULL == objArray[8]) { fprintf(stderr, "Failed to create Access Control object\r\n"); return -1; } else if (acc_ctrl_obj_add_inst(objArray[8], instId, 3, 0, serverId)==false) { fprintf(stderr, "Failed to create Access Control object instance\r\n"); return -1; } else if (acc_ctrl_oi_add_ac_val(objArray[8], instId, 0, 0b000000000001111)==false) { fprintf(stderr, "Failed to create Access Control ACL default resource\r\n"); return -1; } else if (acc_ctrl_oi_add_ac_val(objArray[8], instId, 999, 0b000000000000001)==false) { fprintf(stderr, "Failed to create Access Control ACL resource for serverId: 999\r\n"); return -1; } /* * The liblwm2m library is now initialized with the functions that will be in * charge of communication */ lwm2mH = lwm2m_init(prv_connect_server, prv_buffer_send, &data); if (NULL == lwm2mH) { fprintf(stderr, "lwm2m_init() failed\r\n"); return -1; } #ifdef LWM2M_BOOTSTRAP /* * Bootstrap state initialization */ if (bootstrapRequested) { lwm2mH->bsState = BOOTSTRAP_REQUESTED; } else { lwm2mH->bsState = NOT_BOOTSTRAPPED; } #endif /* * We configure the liblwm2m library with the name of the client - which shall be unique for each client - * the number of objects we will be passing through and the objects array */ result = lwm2m_configure(lwm2mH, name, NULL, NULL, OBJ_COUNT, objArray); if (result != 0) { fprintf(stderr, "lwm2m_configure() failed: 0x%X\r\n", result); return -1; } signal(SIGINT, handle_sigint); /* * This function start your client to the LWM2M servers */ result = lwm2m_start(lwm2mH); if (result != 0) { fprintf(stderr, "lwm2m_start() failed: 0x%X\r\n", result); return -1; } /** * Initialize value changed callback. */ init_value_change(lwm2mH); /* * As you now have your lwm2m context complete you can pass it as an argument to all the command line functions * precedently viewed (first point) */ for (i = 0 ; commands[i].name != NULL ; i++) { commands[i].userData = (void *)lwm2mH; } fprintf(stdout, "LWM2M Client \"%s\" started on port %s\r\n", name, localPort); fprintf(stdout, "> "); fflush(stdout); /* * We now enter in a while loop that will handle the communications from the server */ while (0 == g_quit) { struct timeval tv; fd_set readfds; if (g_reboot) { time_t tv_sec; tv_sec = lwm2m_gettime(); if (0 == reboot_time) { reboot_time = tv_sec + 5; } if (reboot_time < tv_sec) { /* * Message should normally be lost with reboot ... */ fprintf(stderr, "reboot time expired, rebooting ..."); system_reboot(); } else { tv.tv_sec = reboot_time - tv_sec; } } else if (batterylevelchanging) { update_battery_level(lwm2mH); tv.tv_sec = 5; } else { tv.tv_sec = 60; } tv.tv_usec = 0; FD_ZERO(&readfds); FD_SET(data.sock, &readfds); FD_SET(STDIN_FILENO, &readfds); /* * This function does two things: * - first it does the work needed by liblwm2m (eg. (re)sending some packets). * - Secondly it adjusts the timeout value (default 60s) depending on the state of the transaction * (eg. retransmission) and the time between the next operation */ result = lwm2m_step(lwm2mH, &(tv.tv_sec)); if (result != 0) { fprintf(stderr, "lwm2m_step() failed: 0x%X\r\n", result); return -1; } #ifdef LWM2M_BOOTSTRAP update_bootstrap_info(&previousBootstrapState, lwm2mH); #endif /* * This part will set up an interruption until an event happen on SDTIN or the socket until "tv" timed out (set * with the precedent function) */ result = select(FD_SETSIZE, &readfds, NULL, NULL, &tv); if (result < 0) { if (errno != EINTR) { fprintf(stderr, "Error in select(): %d\r\n", errno); } } else if (result > 0) { uint8_t buffer[MAX_PACKET_SIZE]; int numBytes; /* * If an event happens on the socket */ if (FD_ISSET(data.sock, &readfds)) { struct sockaddr_storage addr; socklen_t addrLen; addrLen = sizeof(addr); /* * We retrieve the data received */ numBytes = recvfrom(data.sock, buffer, MAX_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrLen); if (0 > numBytes) { fprintf(stderr, "Error in recvfrom(): %d\r\n", errno); } else if (0 < numBytes) { char s[INET6_ADDRSTRLEN]; in_port_t port; connection_t * connP; if (AF_INET == addr.ss_family) { struct sockaddr_in *saddr = (struct sockaddr_in *)&addr; inet_ntop(saddr->sin_family, &saddr->sin_addr, s, INET6_ADDRSTRLEN); port = saddr->sin_port; } else if (AF_INET6 == addr.ss_family) { struct sockaddr_in6 *saddr = (struct sockaddr_in6 *)&addr; inet_ntop(saddr->sin6_family, &saddr->sin6_addr, s, INET6_ADDRSTRLEN); port = saddr->sin6_port; } fprintf(stderr, "%d bytes received from [%s]:%hu\r\n", numBytes, s, ntohs(port)); /* * Display it in the STDERR */ output_buffer(stderr, buffer, numBytes, 0); connP = connection_find(data.connList, &addr, addrLen); if (connP != NULL) { /* * Let liblwm2m respond to the query depending on the context */ lwm2m_handle_packet(lwm2mH, buffer, numBytes, connP); conn_s_updateRxStatistic(objArray[7], numBytes, false); } else { fprintf(stderr, "received bytes ignored!\r\n"); } } } /* * If the event happened on the SDTIN */ else if (FD_ISSET(STDIN_FILENO, &readfds)) { numBytes = read(STDIN_FILENO, buffer, MAX_PACKET_SIZE - 1); if (numBytes > 1) { buffer[numBytes] = 0; /* * We call the corresponding callback of the typed command passing it the buffer for further arguments */ handle_command(commands, (char*)buffer); } if (g_quit == 0) { fprintf(stdout, "\r\n> "); fflush(stdout); } else { fprintf(stdout, "\r\n"); } } } } /* * Finally when the loop is left smoothly - asked by user in the command line interface - we unregister our client from it */ if (g_quit == 1) { #ifdef LWM2M_BOOTSTRAP close_backup_object(); #endif lwm2m_close(lwm2mH); } close(data.sock); connection_free(data.connList); #ifdef MEMORY_TRACE if (g_quit == 1) { trace_print(0, 1); } #endif return 0; }