From b58eb64fc32eb4a19efd3fcf938239f80df200df Mon Sep 17 00:00:00 2001 From: Manish Garg Date: Mon, 23 Sep 2024 14:33:04 +0530 Subject: [PATCH] UDP server support to send CSI data to UDP client ADD sample client file for datadump over UDP Changes in csifw_test app and data-format in saved file --- apps/examples/csifw_test/csifw_test.c | 119 +++++----- framework/src/csifw/CSILogsDumper.c | 219 ++++++++++++++++++ framework/src/csifw/CSIService.c | 92 ++++++++ framework/src/csifw/Make.defs | 3 + framework/src/csifw/include/CSILogsDumper.h | 40 ++++ .../README_csi_datadump_udp_client.md | 27 +++ tools/csi_datadump/csi_datadump_udp_client.c | 135 +++++++++++ 7 files changed, 577 insertions(+), 58 deletions(-) create mode 100644 framework/src/csifw/CSILogsDumper.c create mode 100644 framework/src/csifw/include/CSILogsDumper.h create mode 100644 tools/csi_datadump/README_csi_datadump_udp_client.md create mode 100644 tools/csi_datadump/csi_datadump_udp_client.c diff --git a/apps/examples/csifw_test/csifw_test.c b/apps/examples/csifw_test/csifw_test.c index 6cef64c3d0..9d2034e896 100644 --- a/apps/examples/csifw_test/csifw_test.c +++ b/apps/examples/csifw_test/csifw_test.c @@ -139,67 +139,70 @@ int csifw_test_main(void) return 0; } printf("[APP]: CSI Manager START SUCCESS\n"); - printf("[APP]: SLEEP--> 15 seconds\n"); + // printf("[APP]: SLEEP--> 15 seconds\n"); PRNT_LN2; - sleep(15); + while (1) { + sleep(2); + } + // sleep(15); - PRNT_LN3; - printf("[APP]: csi_service_stop\n"); - PRNT_LN2; - sleep(2); - CSIFW_REASON reason = CSIFW_NORMAL; + // PRNT_LN3; + // printf("[APP]: csi_service_stop\n"); + // PRNT_LN2; + // sleep(2); + // CSIFW_REASON reason = CSIFW_NORMAL; - if (csi_service_stop(reason)== CSIFW_ERROR) { - printf("[APP]: CSI Manager STOP FAIL\n"); - PRNT_LN2; - return 0; - } - printf("[APP]: CSI Manager STOP SUCCESS\n"); - printf("[APP]: SLEEP--> 10 seconds\n"); - PRNT_LN2; - sleep(10); - - PRNT_LN3; - printf("[APP]: csi_service_start\n"); - PRNT_LN2; - sleep(2); - if (csi_service_start() == CSIFW_ERROR) { - printf("[APP]: CSI Manager START FAIL\n"); - PRNT_LN2; - return 0; - } - printf("[APP]: SLEEP--> 20 seconds\n"); - PRNT_LN2; - sleep(20); - - PRNT_LN3; - printf("[APP]: csi_service_stop\n"); - PRNT_LN2; - sleep(2); - if (csi_service_stop(reason) == CSIFW_ERROR) { - printf("[APP]: CSI Manager STOP FAIL\n"); - PRNT_LN2; - return 0; - } - printf("[APP]: SLEEP--> 10 seconds\n"); - PRNT_LN2; - sleep(10); - - PRNT_LN3; - printf("[APP]: csi_service_deinit\n"); - PRNT_LN2; - sleep(2); - if (csi_service_deinit() == CSIFW_ERROR) { - printf("[APP]: CSI Manager DEINIT FAIL\n"); - PRNT_LN2; - return 0; - } - printf("[APP]: SLEEP--> 20 seconds\n"); - PRNT_LN2; - sleep(20); - PRNT_LN2; - printf("[APP]: DEFAULT FLOW ENDSSS\n"); - printf("[APP]: DEFAULT FLOW ENDSSS\n"); + // if (csi_service_stop(reason)== CSIFW_ERROR) { + // printf("[APP]: CSI Manager STOP FAIL\n"); + // PRNT_LN2; + // return 0; + // } + // printf("[APP]: CSI Manager STOP SUCCESS\n"); + // printf("[APP]: SLEEP--> 10 seconds\n"); + // PRNT_LN2; + // sleep(10); + + // PRNT_LN3; + // printf("[APP]: csi_service_start\n"); + // PRNT_LN2; + // sleep(2); + // if (csi_service_start() == CSIFW_ERROR) { + // printf("[APP]: CSI Manager START FAIL\n"); + // PRNT_LN2; + // return 0; + // } + // printf("[APP]: SLEEP--> 20 seconds\n"); + // PRNT_LN2; + // sleep(20); + + // PRNT_LN3; + // printf("[APP]: csi_service_stop\n"); + // PRNT_LN2; + // sleep(2); + // if (csi_service_stop(reason) == CSIFW_ERROR) { + // printf("[APP]: CSI Manager STOP FAIL\n"); + // PRNT_LN2; + // return 0; + // } + // printf("[APP]: SLEEP--> 10 seconds\n"); + // PRNT_LN2; + // sleep(10); + + // PRNT_LN3; + // printf("[APP]: csi_service_deinit\n"); + // PRNT_LN2; + // sleep(2); + // if (csi_service_deinit() == CSIFW_ERROR) { + // printf("[APP]: CSI Manager DEINIT FAIL\n"); + // PRNT_LN2; + // return 0; + // } + // printf("[APP]: SLEEP--> 20 seconds\n"); + // PRNT_LN2; + // sleep(20); + // PRNT_LN2; + // printf("[APP]: DEFAULT FLOW ENDSSS\n"); + // printf("[APP]: DEFAULT FLOW ENDSSS\n"); return 0; } diff --git a/framework/src/csifw/CSILogsDumper.c b/framework/src/csifw/CSILogsDumper.c new file mode 100644 index 0000000000..e19f12d8bb --- /dev/null +++ b/framework/src/csifw/CSILogsDumper.c @@ -0,0 +1,219 @@ +/**************************************************************************** + * + * Copyright 2024 Samsung Electronics All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + * + ****************************************************************************/ + +#include "include/CSILogsDumper.h" +#include +#include +#include +#include + +#define PORT 5000 +#define CONTROL_COMMAND_BUFFER_SIZE 128 +#define CSI_DATA_DUMP_BUFFER_SIZE 1024 + +unsigned char gCSIDataDumpBuffer[CSI_DATA_DUMP_BUFFER_SIZE]; +char gControlCommandBuffer[CONTROL_COMMAND_BUFFER_SIZE]; + +csiDataDumpListener gListener = NULL; +static pthread_t gThreadId = -1; +static int gSockFd = -1, gFifoFd = -1; +struct sockaddr_in gServerAddr, gClientAddr; +socklen_t gClientLen = sizeof(gClientAddr); +fd_set readfds; +int maxfd; + +static int gWaitingForData = 0; +static int gRemainingBytes = 0; +static int gBytesReadSofar = 0; + +static int recv_message(int fd, void *buf, int buflen) +{ + int received = 0; + while (1) { + int res = read(fd, buf + received, buflen - received); + if (res < 0) { + int err_no = errno; + if (err_no == EAGAIN || err_no == EINTR) { + continue; + } + CSIFW_LOGE("read error %d\n", err_no); + return -1; + } + received += res; + if (received == buflen) { + break; + } + } + return received; +} + +static void print_buf(const unsigned char* buf, int len) +{ + printf("\n-------------------------------------------RAW DATA- %d ----------------------------------------------------\n\n", len); + unsigned long long *buff_tmp = (u64 *)buf; + int buff_len = (len / 8) + 1; + for (int i = 0; i < buff_len; i++) { + printf("[%02d]0x%016llx\n", i, buff_tmp[i]); + } +} + +void set_event_listener(csiDataDumpListener listener) +{ + gListener = listener; +} + +void *dataTransmitter(void *arg) +{ + int len; + while (1) { + FD_ZERO(&readfds); + FD_SET(gSockFd, &readfds); + FD_SET(gFifoFd, &readfds); + maxfd = (gSockFd > gFifoFd) ? gSockFd : gFifoFd; + + CSIFW_LOGI("Wait for an activity on one of the file descriptors"); + int ret = select(maxfd + 1, &readfds, NULL, NULL, NULL); + if (ret < 0) { + if (errno == EBADF){ + CSIFW_LOGE("select operation failed due to file descripter close: %d", errno); + return; + } + else if(errno == EINTR){ + CSIFW_LOGE("select operation failed due to Temporary Interrupt: %d", errno); + continue;; + } + CSIFW_LOGE("select operation failed over file descripters: %d", errno); + return; + } + + // Check if there's data on the UDP socket + if (FD_ISSET(gSockFd, &readfds)) { + CSIFW_LOGI("Received an activity on sockfd descriptors"); + len = recvfrom(gSockFd, gControlCommandBuffer, CONTROL_COMMAND_BUFFER_SIZE-1, 0, (struct sockaddr *)&gClientAddr, &gClientLen); + if (len < 0) { + continue; + } + gControlCommandBuffer[len] = '\0'; + if (strncmp(gControlCommandBuffer, "START", 6) == 0) { + gListener(START_DUMP); + CSIFW_LOGI("Received START command. Starting to send data to client from FIFO"); + } else if (strncmp(gControlCommandBuffer, "STOP", 5) == 0) { + gListener(STOP_DUMP); + CSIFW_LOGI("Received STOP command. Stopping data transfer to client from FIFO"); + } else { + CSIFW_LOGI("Received unknown command: %s", gControlCommandBuffer); + continue; + } + } + + // Check if there's data on the FIFO + if (FD_ISSET(gFifoFd, &readfds)) { + CSIFW_LOGI("Received an activity on Fifo descriptors"); + if (!gWaitingForData) { + // Get the length from the first 2 bytes + len = recv_message(gFifoFd, (void *)gCSIDataDumpBuffer, 2); + if (len <= 0) { + CSIFW_LOGE("operation to read length of data from FIFO Failed"); + continue; + } + uint16_t length; + memcpy(&length , gCSIDataDumpBuffer, sizeof(length)); + CSIFW_LOGI("Read %d length to client:", length); + gRemainingBytes = length; + gWaitingForData = 1; + gBytesReadSofar = 0; + } + if (gWaitingForData) { + // We are expecting to read the actual data + ssize_t bytes_read = read(gFifoFd, gCSIDataDumpBuffer + gBytesReadSofar, gRemainingBytes); + if (bytes_read < 0) { + int err_no = errno; + if (err_no == EAGAIN || err_no == EINTR) { + continue; + } + CSIFW_LOGE("read error %d\n", err_no); + continue; // or return + } + + gBytesReadSofar += bytes_read; + gRemainingBytes -= bytes_read; + + if (gRemainingBytes == 0) { + // Complete data received + gWaitingForData = 0; + // Send the data to the client + len = sendto(gSockFd, gCSIDataDumpBuffer, gBytesReadSofar, 0, (struct sockaddr *)&gClientAddr, sizeof(gClientAddr)); + if (len == -1) { + CSIFW_LOGE("sendto error:%d", errno); + continue; + } + CSIFW_LOGI("Sent %d bytes to client", len); + print_buf(gCSIDataDumpBuffer,len); + } + } + } + } +} + +CSIFW_RES csi_logs_dumper_init(void) +{ + if ((gSockFd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + CSIFW_LOGE("failed to create a socket fd"); + return CSIFW_ERROR; + } + + memset(&gServerAddr, 0, sizeof(gServerAddr)); + gServerAddr.sin_family = AF_INET; + gServerAddr.sin_addr.s_addr = INADDR_ANY; + gServerAddr.sin_port = htons(PORT); + + if (bind(gSockFd, (struct sockaddr*)&gServerAddr, sizeof(gServerAddr)) < 0) { + CSIFW_LOGE("binding socket failed"); + close(gSockFd); + return CSIFW_ERROR; + } + printf("server Socket Created\n"); + gFifoFd = open(CSI_DUMP_DATA_QUEUE_NAME, O_RDONLY | O_NONBLOCK); + if (gFifoFd < 0) { + CSIFW_LOGE("open CSI_DUMP_DATA_QUEUE fail %d", errno); + close(gSockFd); + return CSIFW_ERROR; + } + + if (pthread_create(&gThreadId, NULL, dataTransmitter, NULL) != 0) { + CSIFW_LOGE("Failed to create dataTransmitter thread %d", errno); + close(gSockFd); + close(gFifoFd); + return CSIFW_ERROR; + } + + if (pthread_setname_np(gThreadId, "CSI_DataDumpOverNetwork") != 0) { + CSIFW_LOGE("Error in setting dataTransmitter thread name, error_no: %d", errno); + } + CSIFW_LOGI("CSI_DataDumpOverNetwork created"); + return CSIFW_OK; +} + +CSIFW_RES csi_logs_dumper_deinit() +{ + gListener = NULL; + close(gSockFd); + close(gFifoFd); + pthread_join(gThreadId, NULL); + return CSIFW_OK; +} diff --git a/framework/src/csifw/CSIService.c b/framework/src/csifw/CSIService.c index a6fb8337a4..766aa0303c 100644 --- a/framework/src/csifw/CSIService.c +++ b/framework/src/csifw/CSIService.c @@ -22,6 +22,11 @@ #include "include/CSIParser.h" #include "include/CSIPacketReceiver.h" #include "include/CSINetworkMonitor.h" +#ifdef CONFIG_CSI_DATA_DUMP_OVER_NETWORK +#include "include/CSILogsDumper.h" +#endif +#include +#include COLLECT_STATE g_service_state = CSI_STATE_UNITIALIZED; CONNECTION_STATE g_nw_state; @@ -33,6 +38,57 @@ upd_parsed_data_listener g_parsed_callback; static void* g_ptr; static csi_action_param_t g_csifw_config __attribute__((aligned(64))) = {0,}; +#ifdef CONFIG_CSI_DATA_DUMP_OVER_NETWORK +#define CSI_DATA_BUFFER_SIZE 1024 + +unsigned char gCSIDataBuffer[CSI_DATA_BUFFER_SIZE]; +int gDataDumpDescriptor; +bool gCSIDataDumpEvent = STOP_DUMP; + +static void csi_data_dump_listener(EVENT event) { + CSIFW_LOGD("csi_data_dump_listener called\n"); + gCSIDataDumpEvent = event; + return; +} + +static int send_message(int fd, void *buf, int buflen) +{ + int sent = 0; + while (1) { + int res = write(fd, (void *)buf + sent, buflen - sent); + if (res < 0) { + int err_no = errno; + if (err_no == EAGAIN || err_no == EINTR) { + continue; + } + CSIFW_LOGE("write error %d", err_no); + return -1; + } + sent += res; + if (sent == buflen) { + break; + } + } + return 0; +} + +CSIFW_RES csi_logs_dumper_send_to_queue(unsigned char *csi_buf, int len) +{ + // Copy the length to the first two bytes and the data to the rest of the output buffer + uint16_t dest_len = (uint16_t)len; + memcpy(gCSIDataBuffer, &dest_len, 2); + memcpy(gCSIDataBuffer + 2, csi_buf, len); + + int res = send_message(gDataDumpDescriptor, (void *)gCSIDataBuffer, len + 2); + + if (res < 0) { + CSIFW_LOGE("Failed to send message to CSI_DUMP_DATA_QUEUE"); + return CSIFW_ERROR; + } + return CSIFW_OK; +} +#endif + static void CSIRawDataListener(CSIFW_RES res, int raw_csi_buff_len, unsigned char *raw_csi_buff, int raw_csi_data_len) { //Send raw data to UPD @@ -42,6 +98,15 @@ static void CSIRawDataListener(CSIFW_RES res, int raw_csi_buff_len, unsigned cha } if (g_raw_callback) { g_raw_callback(res, raw_csi_buff_len, raw_csi_buff, g_ptr); + #ifdef CONFIG_CSI_DATA_DUMP_OVER_NETWORK + if (gCSIDataDumpEvent) { + CSIFW_RES ret = csi_logs_dumper_send_to_queue(raw_csi_buff, raw_csi_buff_len); + if (ret != CSIFW_OK) { + CSIFW_LOGE("Failed to send CSI data to CSI_DUMP_DATA_QUEUE"); + } + CSIFW_LOGD("CSI data sent to CSI_DUMP_DATA_QUEUE"); + } + #endif } } @@ -53,6 +118,28 @@ CSIFW_RES csi_manager_init(void) CSIFW_RES csi_service_init(upd_raw_data_listener raw_callback, upd_parsed_data_listener parsed_callback, unsigned int interval, void* ptr) { + #ifdef CONFIG_CSI_DATA_DUMP_OVER_NETWORK + int result = mkfifo(CSI_DUMP_DATA_QUEUE_NAME, 0666); + if (result < 0 && result != -EEXIST) { + CSIFW_LOGE("create CSI_DUMP_DATA_QUEUE fail %d", errno); + return CSIFW_ERROR; + } + gDataDumpDescriptor = open(CSI_DUMP_DATA_QUEUE_NAME, O_WRONLY | O_NONBLOCK); + if (gDataDumpDescriptor < 0) { + CSIFW_LOGE("open CSI_DUMP_DATA_QUEUE fail %d", errno); + unlink(CSI_DUMP_DATA_QUEUE_NAME); + return CSIFW_ERROR; + } + result = csi_logs_dumper_init(); + if (result != CSIFW_OK) { + CSIFW_LOGE("open csi_logs_dumper_init fail"); + close(gDataDumpDescriptor); + unlink(CSI_DUMP_DATA_QUEUE_NAME); + return CSIFW_ERROR; + } + set_event_listener(csi_data_dump_listener); + #endif + g_ptr = ptr; if (g_service_state != CSI_STATE_UNITIALIZED) { CSIFW_LOGE("Already Initialized"); @@ -137,6 +224,11 @@ CSIFW_RES csi_service_deinit() } g_service_state = CSI_STATE_UNITIALIZED; csi_packet_receiver_deinit(); + #ifdef CONFIG_CSI_DATA_DUMP_OVER_NETWORK + csi_logs_dumper_deinit(); + close(gDataDumpDescriptor); + unlink(CSI_DUMP_DATA_QUEUE_NAME); + #endif if (g_parsed_buffptr) { free(g_parsed_buffptr); g_parsed_buffptr = NULL; diff --git a/framework/src/csifw/Make.defs b/framework/src/csifw/Make.defs index 84589cc556..e49f7ca6d8 100644 --- a/framework/src/csifw/Make.defs +++ b/framework/src/csifw/Make.defs @@ -20,6 +20,9 @@ ifeq ($(CONFIG_CSIFW), y) CSRCS += CSIPacketReceiver.c CSIParser.c CSIService.c PingGenerator.c CSINetworkMonitor.c rb.c +ifeq ($(CONFIG_CSI_DATA_DUMP_OVER_NETWORK), y) + CSRCS += CSILogsDumper.c +endif DEPPATH += --dep-path src/csifw VPATH += :src/csifw diff --git a/framework/src/csifw/include/CSILogsDumper.h b/framework/src/csifw/include/CSILogsDumper.h new file mode 100644 index 0000000000..677cd416f2 --- /dev/null +++ b/framework/src/csifw/include/CSILogsDumper.h @@ -0,0 +1,40 @@ +/****************************************************************** + * + * Copyright 2024 Samsung Electronics All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************/ + +#ifndef __CSI_LOGS_DUMPER__ +#define __CSI_LOGS_DUMPER__ + +#include "csifw.h" + +#ifdef CONFIG_CSI_DATA_DUMP_OVER_NETWORK +#define CSI_DUMP_DATA_QUEUE_NAME "/dev/csidump_data" + +typedef enum EVENT { + STOP_DUMP, + START_DUMP +} EVENT; + +CSIFW_RES csi_logs_dumper_init(); +CSIFW_RES csi_logs_dumper_deinit(); + +typedef void (*csiDataDumpListener)(EVENT event); +void set_event_listener(csiDataDumpListener listener); +#endif + +#endif /* __CSI_LOGS_DUMPER__ */ + diff --git a/tools/csi_datadump/README_csi_datadump_udp_client.md b/tools/csi_datadump/README_csi_datadump_udp_client.md new file mode 100644 index 0000000000..7b49930290 --- /dev/null +++ b/tools/csi_datadump/README_csi_datadump_udp_client.md @@ -0,0 +1,27 @@ +# How To Run csi_datadump_udp_client.c File + +## Steps: +### 1. First compile the file: +```bash +gcc -o program csi_datadump_udp_client.c -lpthread +``` + +### 2. Run the program + Command Format: ./program + +Here "BYTES" is the number of bytes you want to receive from server (Optional Parameter) +Default Value: 155 + +```bash +./program 192.168.1.120 5000 +``` +OR + +```bash +./program 192.168.1.120 5000 155 +``` + +## How to STOP the datadump +#### Type *STOP* in terminal and press enter. + +You will get the file "received_data.txt" in your current directory, In which data will be saved in the binary format. diff --git a/tools/csi_datadump/csi_datadump_udp_client.c b/tools/csi_datadump/csi_datadump_udp_client.c new file mode 100644 index 0000000000..390237a9a8 --- /dev/null +++ b/tools/csi_datadump/csi_datadump_udp_client.c @@ -0,0 +1,135 @@ +/**************************************************************************** + * + * Copyright 2024 Samsung Electronics All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + * + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#define BUFFER_SIZE 1024 +#define FILENAME "received_data.txt" +#define BYTES 155 +FILE* file; +int stop = 0; +int count = 0; +uint16_t length; +int gSockFd; +struct sockaddr_in server_addr; +socklen_t addr_len; + +// static void print_buf(const unsigned char* buf, int len) +// { +// for (int i = 0; i < len; i++){ +// fprintf(file, "%02x", buf[i]); +// } +// fprintf(file, "\n"); +// } + +void* receive_data(void* arg) { + char buffer[BUFFER_SIZE]; + int n; + int received; + while (!stop) { + received = 0; + while(received < length){ + n = recvfrom(gSockFd, (char *)buffer + received, length - received, 0, NULL, NULL); + if (n < 0) { + if (errno == EBADF) { + return NULL; + } + printf("Receive Length failed\n"); + break; + } + received += n; + } + printf("write data success\n"); + // print_buf(buffer,length); + fwrite(buffer, sizeof(unsigned char), length, file); + count += 1; + if(count % 100 == 0){ + fflush(file); //flush every 100 writes + } + } + pthread_exit(NULL); +} + +int main(int argc, char *argv[]) { + pthread_t recv_thread; + char message[20]; + if (argc == 3 || argc == 4) { + if (argc == 4){ + length = atoi(argv[3]); + } + else { + length = BYTES; + } + } + else { + printf("Input Error\n"); + return -1; + } + + if ((gSockFd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + printf("Socket creation failed\n"); + return -1; + } + + // Server address setup + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(atoi(argv[2])); + if (inet_pton(AF_INET, argv[1], &server_addr.sin_addr) <= 0) { + printf("Invalid IP address\n"); + close(gSockFd); + return -1; + } + addr_len = sizeof(server_addr); + + // Send START command + strncpy(message, "START", 6); + sendto(gSockFd, message, strlen(message), 0, (const struct sockaddr *)&server_addr, addr_len); + + file = fopen(FILENAME, "w"); + if (file == NULL) { + printf("Error opening file\n"); + return -1; + } + pthread_create(&recv_thread, NULL, receive_data, NULL); + + // Wait for the user to type "stop" + while (1) { + fgets(message, sizeof(message), stdin); + message[strcspn(message, "\n")] = '\0'; // Remove newline character + + if (strncmp(message, "STOP", 5) == 0) { + stop = 1; + sendto(gSockFd, (const char *)message, strlen(message), 0, (const struct sockaddr *) &server_addr, addr_len); + printf("Stop command sent to server\n"); + shutdown(gSockFd,SHUT_RDWR); + close(gSockFd); + sleep(2); + break; + } + } + pthread_join(recv_thread, NULL); + fclose(file); + return 0; +}