bs_info_t * bs_get_info(FILE * fd) { bs_info_t * infoP; read_server_t * readSrvP; bs_endpoint_info_t * cltInfoP; bs_command_t * cmdP; infoP = (bs_info_t *)lwm2m_malloc(sizeof(bs_info_t)); if (infoP == NULL) return NULL; memset(infoP, 0, sizeof(bs_info_t)); do { readSrvP = prv_read_next_server(fd); if (readSrvP != NULL) { if (prv_add_server(infoP, readSrvP) != 0) goto error; } } while (readSrvP != NULL); rewind(fd); do { cltInfoP = prv_read_next_endpoint(fd); if (cltInfoP != NULL) { cltInfoP->next = infoP->endpointList; infoP->endpointList = cltInfoP; } } while (cltInfoP != NULL); // check validity if (infoP->endpointList == NULL) goto error; cltInfoP = infoP->endpointList; while (cltInfoP != NULL) { bs_endpoint_info_t * otherP; bs_command_t * cmdP; bs_command_t * parentP; // check names are unique otherP = cltInfoP->next; while (otherP != NULL) { if (cltInfoP->name == NULL) { if (otherP->name == NULL) goto error; } else { if (otherP->name != NULL && strcmp(cltInfoP->name, otherP->name) == 0) { goto error; } } otherP = otherP->next; } // check servers exist cmdP = cltInfoP->commandList; parentP = NULL; // be careful: iterator changes are inside the switch/case while (cmdP != NULL) { switch (cmdP->operation) { case BS_WRITE_SECURITY: if (LWM2M_LIST_FIND(infoP->serverList, cmdP->serverId) == NULL) goto error; parentP = cmdP; cmdP = cmdP->next; break; case BS_WRITE_SERVER: { bs_server_tlv_t * serverP; serverP = (bs_server_tlv_t *)LWM2M_LIST_FIND(infoP->serverList, cmdP->serverId); if (serverP == NULL) goto error; if (serverP->serverData == NULL) { // this is a Bootstrap server, remove this command if (parentP == NULL) { cltInfoP->commandList = cmdP->next; lwm2m_free(cmdP); cmdP = cltInfoP->commandList; } else { parentP->next = cmdP->next; lwm2m_free(cmdP); cmdP = parentP->next; } } else { cmdP = cmdP->next; } } break; case BS_DELETE: default: parentP = cmdP; cmdP = cmdP->next; break; } } cltInfoP = cltInfoP->next; } return infoP; error: bs_free_info(infoP); return NULL; }
int main(int argc, char *argv[]) { fd_set readfds; struct timeval tv; int result; char * port = "5685"; internal_data_t data; char * filename = "bootstrap_server.ini"; int opt; FILE * fd; command_desc_t commands[] = { {"boot", "Bootstrap a client (Server Initiated).", " boot URI [NAME]\r\n" " URI: uri of the client to bootstrap\r\n" " NAME: endpoint name of the client as in the .ini file (optionnal)\r\n" "Example: boot coap://[::1]:56830 testlwm2mclient", prv_bootstrap_client, &data}, {"q", "Quit the server.", NULL, prv_quit, NULL}, COMMAND_END_LIST }; while ((opt = getopt(argc, argv, "f:p:")) != -1) { switch (opt) { case 'f': filename = optarg; break; case 'p': port = optarg; break; default: print_usage(filename, port); return 0; } } memset(&data, 0, sizeof(internal_data_t)); data.sock = create_socket(port); if (data.sock < 0) { fprintf(stderr, "Error opening socket: %d\r\n", errno); return -1; } data.lwm2mH = lwm2m_init(NULL, prv_buffer_send, NULL); if (NULL == data.lwm2mH) { fprintf(stderr, "lwm2m_init() failed\r\n"); return -1; } signal(SIGINT, handle_sigint); fd = fopen(filename, "r"); if (fd == NULL) { fprintf(stderr, "Opening file %s failed.\r\n", filename); return -1; } data.bsInfo = bs_get_info(fd); fclose(fd); if (data.bsInfo == NULL) { fprintf(stderr, "Reading Bootsrap Info from file %s failed.\r\n", filename); return -1; } lwm2m_set_bootstrap_callback(data.lwm2mH, prv_bootstrap_callback, (void *)&data); fprintf(stdout, "LWM2M Bootstrap Server now listening on port %s.\r\n\n", port); fprintf(stdout, "> "); fflush(stdout); while (0 == g_quit) { endpoint_t * endP; FD_ZERO(&readfds); FD_SET(data.sock, &readfds); FD_SET(STDIN_FILENO, &readfds); tv.tv_sec = 60; tv.tv_usec = 0; result = lwm2m_step(data.lwm2mH, &(tv.tv_sec)); if (result != 0) { fprintf(stderr, "lwm2m_step() failed: 0x%X\r\n", result); return -1; } result = select(FD_SETSIZE, &readfds, 0, 0, &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; // Packet received if (FD_ISSET(data.sock, &readfds)) { struct sockaddr_storage addr; socklen_t addrLen; addrLen = sizeof(addr); numBytes = recvfrom(data.sock, buffer, MAX_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrLen); if (numBytes == -1) { fprintf(stderr, "Error in recvfrom(): %d\r\n", errno); } else { char s[INET6_ADDRSTRLEN]; in_port_t port; connection_t * connP; s[0] = 0; 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)); output_buffer(stderr, buffer, numBytes, 0); connP = connection_find(data.connList, &addr, addrLen); if (connP == NULL) { connP = connection_new_incoming(data.connList, data.sock, (struct sockaddr *)&addr, addrLen); if (connP != NULL) { data.connList = connP; } } if (connP != NULL) { lwm2m_handle_packet(data.lwm2mH, buffer, numBytes, connP); } } } // command line input else if (FD_ISSET(STDIN_FILENO, &readfds)) { numBytes = read(STDIN_FILENO, buffer, MAX_PACKET_SIZE - 1); if (numBytes > 1) { buffer[numBytes] = 0; handle_command(commands, (char*)buffer); } if (g_quit == 0) { fprintf(stdout, "\r\n> "); fflush(stdout); } else { fprintf(stdout, "\r\n"); } } // Do operations on endpoints prv_endpoint_clean(&data); endP = data.endpointList; while (endP != NULL) { switch(endP->status) { case CMD_STATUS_OK: endP->cmdList = endP->cmdList->next; endP->status = CMD_STATUS_NEW; // fall through case CMD_STATUS_NEW: prv_send_command(&data, endP); break; default: break; } endP = endP->next; } } } lwm2m_close(data.lwm2mH); bs_free_info(data.bsInfo); while (data.endpointList != NULL) { endpoint_t * endP; endP = data.endpointList; data.endpointList = data.endpointList->next; prv_endpoint_free(endP); } close(data.sock); connection_free(data.connList); return 0; }