#define DEBUG #define FU08 "%hhu" #define FU16 "%hu" #define FU32 "%lu" #define FU64 "%llu" #define FSTR "%s" #include #include #include #include #include #include #include //--Tools Module #include uint64_t TIME_u64Current(void) { return time(NULL); } uint16_t RAND_u16GetNumber(uint16_t u16Min, uint16_t u16Max) { static uint8_t i = 0; if (i == 0) { srand(time(NULL)); i++; } return rand() % (u16Max + 1 - u16Min) + u16Min; } //--Log Module #include sem_t semLog; void LOG_vSetup(void) { sem_init(&semLog, 0, 1); } void LOG_vPrintf(const char* format, ...) { sem_wait(&semLog); va_list args; va_start(args, format); #ifdef DEBUG printf(FU64":", TIME_u64Current()); vprintf(format, args); #endif FILE* fp; fp = fopen("/tmp/log.txt", "a"); if (fp != NULL) { fprintf(fp, FU64":", TIME_u64Current()); vfprintf(fp, format, args); fclose(fp); } va_end(args); sem_post(&semLog); } //--File Module #define FILE_EOF 0xFF int8_t FILE_i08Compare(char* pchPath1, char* pchPath2) { FILE* file1 = fopen(pchPath1, "r"); FILE* file2 = fopen(pchPath2, "r"); if (file1 == NULL) { if (file2 != NULL) fclose(file2); return 1; } if (file2 == NULL) { fclose(file1); return 2; } char ch1, ch2; do { ch1 = fgetc(file1); ch2 = fgetc(file2); if (ch1 != ch2) { fclose(file1); fclose(file2); return 0; } } while (ch1 != FILE_EOF && ch2 != FILE_EOF); if (ch1 == FILE_EOF && ch2 == FILE_EOF) { fclose(file1); fclose(file2); return 3; } else { fclose(file1); fclose(file2); return 0; } } //--WiFi Module #define NETWORK_TYPE "wlan0" #include #include #define WIFI_BUFFER 2000 #include struct ParserArgs { int sock; struct sockaddr_in client_address; socklen_t client_address_len; bool (*bParse)(uint8_t* pu08Address, char* pchBuffer); }; void WiFi_vParser(void* ptr) { struct ParserArgs temp; memcpy(&temp, ptr, sizeof(struct ParserArgs)); char pchRemoteAddress[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &(temp.client_address.sin_addr), pchRemoteAddress, INET_ADDRSTRLEN); //uint16_t pu16RemotePort = temp.client_address.sin_port; char pchBuffer[WIFI_BUFFER]; char* pchTemp = (char*)pchBuffer; int16_t i16New = 0; uint16_t u16Length = 0; uint16_t u16Remaining = WIFI_BUFFER; while ((i16New = recv(temp.sock, pchTemp, u16Remaining, 0)) > 0) { pchTemp += i16New; u16Remaining -= i16New; u16Length += i16New; pchTemp[0] = '\0'; } uint8_t pu08Levels[4]; sscanf(pchRemoteAddress, FU08"."FU08"."FU08"."FU08, &pu08Levels[0], &pu08Levels[1], &pu08Levels[2], &pu08Levels[3]); temp.bParse(pu08Levels, pchBuffer); close(temp.sock); } bool WiFi_bListener(int32_t i32ServerPort, bool (*bParse)(uint8_t* pu08Address, char* pchBuffer)) { struct sockaddr_in server_address; memset(&server_address, 0, sizeof(server_address)); server_address.sin_family = AF_INET; server_address.sin_port = htons(i32ServerPort); server_address.sin_addr.s_addr = htonl(INADDR_ANY); int listen_sock; if ((listen_sock = socket(PF_INET, SOCK_STREAM, 0)) == -1) return false; if ((bind(listen_sock, (struct sockaddr *)&server_address, sizeof(server_address))) == -1) { close(listen_sock); return false; } if (listen(listen_sock, WIFI_BUFFER) == -1) { close(listen_sock); return false; } while (true) { LOG_vPrintf("WiFiListener-New\n"); struct ParserArgs client; client.client_address_len = sizeof(client.client_address); client.bParse = bParse; LOG_vPrintf("WiFiListener-Start\n"); if ((client.sock = accept(listen_sock, (struct sockaddr *)&client.client_address, &client.client_address_len)) == -1) { return false; } WiFi_vParser(&client); LOG_vPrintf("WiFiListener-Stop\n"); } close(listen_sock); return true; } bool WiFi_bSend(char* pchServerAddress, int32_t i32ServerPort, char* pchServerText) { LOG_vPrintf("WiFi-Send-Sock\n"); int sock; if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { LOG_vPrintf("WiFi-Send-Fail\n"); return false; } LOG_vPrintf("WiFi-Send-Init\n"); struct sockaddr_in server_address; memset(&server_address, 0, sizeof(server_address)); server_address.sin_family = AF_INET; server_address.sin_addr.s_addr = inet_addr(pchServerAddress); server_address.sin_port = htons(i32ServerPort); LOG_vPrintf("WiFi-Send-Connect\n"); if (connect(sock, (struct sockaddr*)&server_address, sizeof(server_address)) == -1) { LOG_vPrintf("WiFi-Send-Fail\n"); close(sock); return false; } LOG_vPrintf("WiFi-Send-Send\n"); if (send(sock, pchServerText, strlen(pchServerText), MSG_CONFIRM) == -1) { LOG_vPrintf("WiFi-Send-NoConfirmation\n"); close(sock); return false; } LOG_vPrintf("WiFi-Send-Close\n"); close(sock); return true; } //--Messages Module #define PAYLOAD_SIZE 256 #define PAYLOAD_DELIMITER '_' #define MESSAGES_SIZE 2000 typedef struct tMessage { uint32_t u32Sender; uint32_t u32Receiver; uint64_t u64Timestamp; char pchMessage[PAYLOAD_SIZE]; bool bDone; uint32_t* pu32Sent; uint32_t u32Sent; } sMessage; typedef struct tMessages { uint32_t u32Owner; sMessage psArray[MESSAGES_SIZE]; uint16_t u16ArrayIndex; bool bFull; uint32_t u32CheckedMessages; uint32_t u32LoggedMessages; sem_t semAccess; } sMessages; void MSG_vSetup(sMessages* psMessages, uint32_t u32Owner) { sem_init(&psMessages->semAccess, 0, 1); psMessages->u32Owner = u32Owner; psMessages->u16ArrayIndex = 0; psMessages->bFull = false; psMessages->u32CheckedMessages = 0; psMessages->u32LoggedMessages = 0; } static inline sMessage* MSG_mGet(sMessages* psMessages, uint16_t u16Index) { //sem_wait(&semMessages); sMessage* temp; if (psMessages->bFull) { temp = &psMessages->psArray[(psMessages->u16ArrayIndex + u16Index) % MESSAGES_SIZE]; } else temp = &psMessages->psArray[u16Index]; //sem_post(&semMessages); return temp; } static inline uint16_t MSG_u16Length(sMessages* psMessages) { //sem_wait(&semMessages); uint16_t temp; if (psMessages->bFull) temp = MESSAGES_SIZE; else temp = psMessages->u16ArrayIndex; //sem_post(&semMessages); return temp; } void MSG_vInsert(sMessages* psMessages, sMessage* psMessage, bool bSent, uint32_t u32Device) { sem_wait(&psMessages->semAccess); psMessages->psArray[psMessages->u16ArrayIndex].u32Sender = psMessage->u32Sender; psMessages->psArray[psMessages->u16ArrayIndex].u32Receiver = psMessage->u32Receiver; psMessages->psArray[psMessages->u16ArrayIndex].u64Timestamp = psMessage->u64Timestamp; psMessages->psArray[psMessages->u16ArrayIndex].bDone = (psMessage->u32Receiver == psMessages->u32Owner); memcpy(psMessages->psArray[psMessages->u16ArrayIndex].pchMessage, psMessage->pchMessage, strlen(psMessage->pchMessage)); if (bSent) { psMessages->psArray[psMessages->u16ArrayIndex].u32Sent = 1; psMessages->psArray[psMessages->u16ArrayIndex].pu32Sent = (uint32_t*)malloc(1 * sizeof(uint32_t)); psMessages->psArray[psMessages->u16ArrayIndex].pu32Sent[0] = u32Device; } else psMessages->psArray[psMessages->u16ArrayIndex].u32Sent = 0; psMessages->u16ArrayIndex = (psMessages->u16ArrayIndex + 1) % MESSAGES_SIZE; if (psMessages->u16ArrayIndex == 0) psMessages->bFull = true; psMessages->u32LoggedMessages++; sem_post(&psMessages->semAccess); } bool MSG_bCheck(sMessages* psMessages, sMessage* psMessage) { sem_wait(&psMessages->semAccess); uint16_t u16ArrayLength = MSG_u16Length(psMessages); bool flag = false; for (uint16_t i = 0; i < u16ArrayLength; i++) { sMessage* temp = MSG_mGet(psMessages, i); if (temp->u32Sender != psMessage->u32Sender) continue; if (temp->u32Receiver != psMessage->u32Receiver) continue; if (temp->u64Timestamp != psMessage->u64Timestamp) continue; if (strcmp(temp->pchMessage, psMessage->pchMessage) != 0) continue; flag = true; break; } psMessages->u32CheckedMessages++; sem_post(&psMessages->semAccess); return flag; } bool MSG_bParse(sMessage* psMessage, char* pchBuffer) { char* pchArrays[4]; bool bFlag = false; uint16_t i; char* s = pchBuffer; for (i = 0; s[i]; s[i] == PAYLOAD_DELIMITER ? i++ : *s++); if (i != 3) return false; char* pchRest = pchBuffer; for (uint8_t i = 0; i < 3; i++) { const char s[2] = { PAYLOAD_DELIMITER, '\0'}; pchArrays[i] = strtok(pchRest, s); if (pchArrays[i] == NULL) { bFlag = true; break; } else { pchRest += strlen(pchRest) + 1; } } pchArrays[3] = pchRest; if (!bFlag) { psMessage->u32Sender = atoi(pchArrays[0]); psMessage->u32Receiver = atoi(pchArrays[1]); psMessage->u64Timestamp = atoi(pchArrays[2]); strcpy(psMessage->pchMessage, pchArrays[3]); } return (!bFlag); } void MSG_vExport(sMessages* psMessages) { sem_wait(&psMessages->semAccess); uint16_t u16ArrayLength = MSG_u16Length(psMessages); FILE* file = fopen("/tmp/messages.txt", "w"); if (file == NULL) { sem_post(&psMessages->semAccess); return; } fprintf(file, "Checked:"FU32"\n", psMessages->u32CheckedMessages); fprintf(file, "Logged:"FU32"\n", psMessages->u32LoggedMessages); fprintf(file, "Index:"FU32"\n", psMessages->u16ArrayIndex); fprintf(file, "index:sender_receiver_timestamp_message:sent:done\n"); for (uint16_t i = 0; i < u16ArrayLength; i++) { sMessage* temp = MSG_mGet(psMessages, i); fprintf(file, FU16":"FU32"_"FU32"_"FU64"_"FSTR":"FU32":"FU08"\n", i, temp->u32Sender, temp->u32Receiver, temp->u64Timestamp, temp->pchMessage, temp->u32Sent, (temp->bDone ? 1 : 0)); } fclose(file); sem_post(&psMessages->semAccess); } void MSG_vSend(sMessages* psMessages, uint32_t u32Receiver, bool (*bSend)(char* pchBuffer)) { sem_wait(&psMessages->semAccess); uint16_t u16Length; if (psMessages->bFull) u16Length = MESSAGES_SIZE; else u16Length = psMessages->u16ArrayIndex; for (uint16_t i = 0; i < u16Length; i++) { sMessage* temp = MSG_mGet(psMessages, i); bool bFlag = false; if (temp->bDone) bFlag = true; else { for (uint32_t j = 0 ; j < temp->u32Sent; j++) { if (temp->pu32Sent[j] == u32Receiver) { bFlag = true; break; } } } if (bFlag) continue; else { LOG_vPrintf("Message-Send-"FU32"-Start\n", i); char pchBuffer[5 + 5 + 3 + 10 + 256]; sprintf(pchBuffer, FU32"_"FU32"_"FU64"_"FSTR, temp->u32Sender, temp->u32Receiver, temp->u64Timestamp, temp->pchMessage); LOG_vPrintf("Message-Send-"FU32"-Send\n", i); if (bSend(pchBuffer)) { if (temp->u32Sent == 0) temp->pu32Sent = (uint32_t*)malloc(1 * sizeof(uint32_t)); else temp->pu32Sent = (uint32_t*)realloc(temp->pu32Sent, (temp->u32Sent + 1) * sizeof(uint32_t)); temp->pu32Sent[temp->u32Sent] = u32Receiver; temp->u32Sent++; temp->bDone = (temp->u32Receiver == u32Receiver); } else { LOG_vPrintf("Message-Send-"FU32"-Error\n", i); } LOG_vPrintf("Message-Send-"FU32"-Stop\n", i); } } sem_post(&psMessages->semAccess); } sMessages sMessagesList; //--Devices Module #define DEVICES_SIZE 100 typedef struct tDevice { uint32_t u32Id; bool bActive; uint64_t u64Start; uint64_t u64Last; } sDevice; typedef struct tDevices { sDevice psArray[DEVICES_SIZE]; uint16_t u16ArrayIndex; bool bFull; sem_t semAccess; } sDevices; void DVC_vSetup(sDevices* psDevices) { sem_init(&psDevices->semAccess, 0, 1); psDevices->u16ArrayIndex = 0; psDevices->bFull = false; } void DVC_vInsert(sDevices* psDevices, uint16_t u32Id) { //sem_wait(&semDevices); psDevices->psArray[psDevices->u16ArrayIndex].u32Id = u32Id; psDevices->psArray[psDevices->u16ArrayIndex].bActive = true; psDevices->psArray[psDevices->u16ArrayIndex].u64Start = TIME_u64Current(); psDevices->psArray[psDevices->u16ArrayIndex].u64Last = 0; psDevices->u16ArrayIndex = (psDevices->u16ArrayIndex + 1) % DEVICES_SIZE; if (psDevices->u16ArrayIndex == 0) psDevices->bFull = true; //sem_post(&semDevices); } uint16_t DVC_u16Update(sDevices* psDevices, uint32_t* pu32Id, uint16_t u16IdSize, uint32_t* pu32New) { sem_wait(&psDevices->semAccess); uint16_t u16ArrayLength; if (psDevices->bFull) u16ArrayLength = DEVICES_SIZE; else u16ArrayLength = psDevices->u16ArrayIndex; bool pbFlag[u16IdSize]; for (uint16_t j = 0; j < u16IdSize; j++) { pbFlag[j] = false; } for (uint16_t i = 0; i < u16ArrayLength; i++) { bool bFlag = false; for (uint16_t j = 0; j < u16IdSize; j++) { if (psDevices->psArray[i].u32Id == pu32Id[j]) { bFlag = true; pbFlag[j] = true; break; } } if (bFlag) { if (psDevices->psArray[i].bActive) psDevices->psArray[i].u64Last = TIME_u64Current(); else { psDevices->psArray[i].bActive = true; psDevices->psArray[i].u64Start = TIME_u64Current(); psDevices->psArray[i].u64Last = 0; } } else { psDevices->psArray[i].bActive = false; } } uint16_t u16Cnt = 0; for (uint16_t j = 0; j < u16IdSize; j++) { if (!pbFlag[j]) { DVC_vInsert(psDevices, pu32Id[j]); pu32New[u16Cnt] = pu32Id[j]; u16Cnt++; } } sem_post(&psDevices->semAccess); return u16Cnt; } void DVC_vExport(sDevices* psDevices) { sem_wait(&psDevices->semAccess); uint16_t u16ArrayLength; if (psDevices->bFull) u16ArrayLength = DEVICES_SIZE; else u16ArrayLength = psDevices->u16ArrayIndex; FILE* file = fopen("/tmp/devices.txt", "w"); if (file == NULL) { sem_post(&psDevices->semAccess); return; } fprintf(file, FU32"\n", psDevices->u16ArrayIndex); fprintf(file, "index:active,id,start,stop\n"); for (uint16_t i = 0; i < u16ArrayLength; i++) fprintf(file, FU32":"FSTR","FU32","FU64","FU64"\n", i, psDevices->psArray[i].bActive ? "true" : "false", psDevices->psArray[i].u32Id, psDevices->psArray[i].u64Start, psDevices->psArray[i].u64Last); fclose(file); sem_post(&psDevices->semAccess); } sDevices sDevicesList; //--Timer Module #include #include typedef struct tInterrupt { bool bRunning; uint32_t u32Ticks; void (*vCallback)(uint32_t); } sInterrupt; sInterrupt sTimer; void TMR_vHandler(int sig) { static uint32_t i = 0; sTimer.vCallback(i - 1); i++; if (sTimer.u32Ticks > 0 && i >= sTimer.u32Ticks) { struct itimerval sInterval = {0}; setitimer(ITIMER_REAL, &sInterval, NULL); sTimer.bRunning = false; } } bool TMR_bSetup(suseconds_t susInterval, void (*vCallback)(uint32_t)) { sTimer.vCallback = vCallback; sTimer.u32Ticks = 0; sTimer.bRunning = true; signal(SIGALRM, TMR_vHandler); struct itimerval sInterval; sInterval.it_interval.tv_usec = susInterval % 1000000; sInterval.it_interval.tv_sec = susInterval / 1000000; sInterval.it_value = sInterval.it_interval; if (setitimer(ITIMER_REAL, &sInterval, NULL) != 0) return false; return true; } //--High Level Application #include #include #include #define AEM 8844 #define SERVER_PORT 2288 #define INTERRUPTS #ifdef INTERRUPTS sem_t semSearcher; #endif const uint32_t pu32FriendsList[] = {7000, 7001, 7002, 7003, 8845}; const uint8_t u08FriendsSize = 5; #define CREATE_PERIOD_MIN 1 //secs #define CREATE_PERIOD_MAX 1 //secs //#define CREATE_PERIOD_MIN 1*60 //secs //#define CREATE_PERIOD_MAX 5*60 //secs uint32_t u32Selector(void) { static uint32_t count = 0; count++; uint8_t index = RAND_u16GetNumber(0, u08FriendsSize - 1); sMessage temp; temp.u32Sender = AEM; temp.u32Receiver = pu32FriendsList[index]; temp.u64Timestamp = TIME_u64Current(); sprintf(temp.pchMessage, "I am message #%d of GKyri", count); temp.u32Sent = 0; LOG_vPrintf("Selector-Insert\n"); MSG_vInsert(&sMessagesList, &temp, false, 0); /* LOG_vPrintf("Selector-Export\n"); MSG_vExport(&sMessagesList); */ return pu32FriendsList[index]; } void APP_vCallback(uint32_t u32Tick) { static bool bRunning = false; if (!bRunning) { bRunning = true; LOG_vPrintf("Callback-Start\n"); u32Selector(); LOG_vPrintf("Callback-Stop\n"); #ifdef INTERRUPTS sem_post(&semSearcher); #endif bRunning = false; } } void APP_vCreator(void) { uint16_t u16Interval = RAND_u16GetNumber(CREATE_PERIOD_MIN, CREATE_PERIOD_MAX); if (TMR_bSetup(500000, APP_vCallback)) { //if (TMR_bSetup(u16Interval * 1000000, APP_vCallback)) { while (true) pause(); } } bool APP_bReceiveBuffer(uint8_t* pu08Address, char* pchBuffer) { LOG_vPrintf("Receiver-Start\n"); uint32_t u32Id = (uint32_t)pu08Address[2] * 100 + pu08Address[3]; sMessage temp; if (!MSG_bParse(&temp, pchBuffer)) return false; temp.u32Sent = 0; if (!MSG_bCheck(&sMessagesList, &temp)) { LOG_vPrintf("Receiver-Insert\n"); MSG_vInsert(&sMessagesList, &temp, true, u32Id); /* LOG_vPrintf("Receiver-Export\n"); MSG_vExport(&sMessagesList); */ } LOG_vPrintf("Receiver-Stop\n"); #ifdef INTERRUPTS sem_post(&semSearcher); #endif return true; } void APP_vListener(void) { WiFi_bListener(SERVER_PORT, APP_bReceiveBuffer); } char pchMessageReceiver[15 + 1]; bool APP_bSendBuffer(char* pchBuffer) { return WiFi_bSend(pchMessageReceiver, SERVER_PORT, pchBuffer); } bool APP_bSender(uint32_t u32Receiver) { sprintf(pchMessageReceiver, "10.0."FU08"."FU08, u32Receiver / 100, u32Receiver % 100); char pchTest[13 + 15 + 12 + 1]; sprintf(pchTest, "ping -c1 -w1 "FSTR" > /dev/null", pchMessageReceiver); if (system(pchTest) == 0) { MSG_vSend(&sMessagesList, u32Receiver, APP_bSendBuffer); return true; } else { return false; } } #define SEARCHER_SLEEP_PERIOD 60 //secs #define SEARCHER_SLEEP_DELAY 30 //secs void APP_vSearcher(void) { #ifdef INTERRUPTS sem_init(&semSearcher, 0, 0); #endif sleep(SEARCHER_SLEEP_PERIOD); while (true) { LOG_vPrintf("Searcher-Start\n"); uint16_t u16Cnt = 0; uint32_t* pu32Id = (uint32_t*)malloc(1 * sizeof(uint32_t)); for (uint8_t i = 0; i < u08FriendsSize; i++) { uint32_t u32Receiver = pu32FriendsList[i]; sprintf(pchMessageReceiver, "10.0."FU08"."FU08, u32Receiver / 100, u32Receiver % 100); char pchTest[13 + 15 + 12 + 1]; sprintf(pchTest, "ping -c1 -w1 "FSTR" > /dev/null", pchMessageReceiver); if (system(pchTest) == 0) { pu32Id[u16Cnt] = u32Receiver; u16Cnt++; pu32Id = (uint32_t*)realloc(pu32Id, (u16Cnt + 1) * sizeof(uint32_t)); } } LOG_vPrintf("Searcher-Send-Start\n"); uint32_t pu32New[u16Cnt]; //uint16_t u16NewLength = DVC_u16Update(&sDevicesList, pu32Id, u16Cnt, pu32New); DVC_u16Update(&sDevicesList, pu32Id, u16Cnt, pu32New); for (uint16_t i = 0; i < u16Cnt; i++) { LOG_vPrintf("Searcher-Send-"FU32"-Start\n", i); APP_bSender(pu32Id[i]); LOG_vPrintf("Searcher-Send-"FU32"-Stop\n", i); } free(pu32Id); LOG_vPrintf("Searcher-Send-Stop\n"); LOG_vPrintf("Searcher-Export\n"); DVC_vExport(&sDevicesList); MSG_vExport(&sMessagesList); LOG_vPrintf("Searcher-Stop\n"); #ifdef INTERRUPTS for (uint16_t i = 0; i < SEARCHER_SLEEP_PERIOD; i++) { int value; sem_getvalue(&semSearcher, &value); if (value > 0) { if (i > SEARCHER_SLEEP_DELAY) { LOG_vPrintf("Searcher-Interrupt\n"); sem_wait(&semSearcher); break; } } sleep(1); } #else sleep(SLEEP_PERIOD); #endif } } void APP_vSetup(void){ int8_t i08Result; bool bFlag = false; i08Result = FILE_i08Compare("/root/wpa_supplicant.conf", "/etc/wpa_supplicant/wpa_supplicant.conf"); if (i08Result == 0 || i08Result == 2) { bFlag = true; LOG_vPrintf("Replacing 'wpa_supplicant'\n"); system("sudo cp /root/wpa_supplicant.conf /etc/wpa_supplicant/wpa_supplicant.conf"); } i08Result = FILE_i08Compare("/root/interfaces", "/etc/network/interfaces"); if (i08Result == 0 || i08Result == 2) { bFlag = true; LOG_vPrintf("Replacing 'interfaces'\n"); system("sudo cp /root/interfaces /etc/network/interfaces"); } i08Result = FILE_i08Compare("/root/messenger.service", "/etc/systemd/system/messenger.service"); if (i08Result == 0 || i08Result == 2) { bFlag = true; LOG_vPrintf("Replacing 'messenger.service'\n"); system("sudo cp /root/messenger.service /etc/systemd/system"); system("systemctl enable messenger"); } if (bFlag) { LOG_vPrintf("Restarting\n"); system("shutdown -r 0"); exit(EXIT_SUCCESS); } } void* Th1Func(void* ptr) { APP_vListener(); return NULL; } void* Th2Func(void* ptr) { APP_vCreator(); return NULL; } void* Th3Func(void* ptr) { APP_vSearcher(); return NULL; } int main( int argc, char* const* argv) { APP_vSetup(); LOG_vSetup(); MSG_vSetup(&sMessagesList, AEM); DVC_vSetup(&sDevicesList); pthread_t thread1, thread2, thread3; pthread_create( &thread1, NULL, Th1Func, NULL); pthread_create( &thread2, NULL, Th2Func, NULL); pthread_create( &thread3, NULL, Th3Func, NULL); pthread_join( thread1, NULL); pthread_join( thread2, NULL); pthread_join( thread3, NULL); return EXIT_SUCCESS; }