From b4b5e68d6d946edc5c4fffe4c434abad67260116 Mon Sep 17 00:00:00 2001 From: Denis Tereshkin Date: Wed, 16 Jul 2025 21:29:15 +0700 Subject: [PATCH] elbapp-server: support multiple clients --- eblapp-client/src/main.c | 8 +- eblapp-server/src/main.c | 370 ++++++++++++++++++++++++--------------- 2 files changed, 233 insertions(+), 145 deletions(-) diff --git a/eblapp-client/src/main.c b/eblapp-client/src/main.c index f5bcc7a..9c868e3 100644 --- a/eblapp-client/src/main.c +++ b/eblapp-client/src/main.c @@ -11,7 +11,7 @@ #include "eblapp.h" #define PORT 1069 -#define MAX_PACKET_SIZE 1024 +#define MAX_PACKET_SIZE 1400 #define TIMEOUT 5 void error(const char *msg) { @@ -86,7 +86,7 @@ int main(int argc, char *argv[]) { if (n < 4) continue; - printf("opcode %d\n", data->opcode); + // printf("opcode %d\n", data->opcode); if (data->opcode == EBLAPP_TRANSFER_DATA) { // DATA struct Eblapp_ack ack = {0}; if (data->block_start != current_offset) { @@ -97,13 +97,13 @@ int main(int argc, char *argv[]) { ack.ack_byte = current_offset; if (sendto(sockfd, &ack, sizeof(ack), 0, (struct sockaddr *)&serv_addr, serv_len) < 0) { - error("ERROR sending ACK"); + error("ERROR sending WTF"); } wtf = 1; } } else { wtf = 0; - printf("got %d\n", current_offset); + printf("got %d (%d)\n", current_offset, n - 8); current_offset += (n - 8); ack.opcode = EBLAPP_ACK; ack.ack_byte = current_offset; diff --git a/eblapp-server/src/main.c b/eblapp-server/src/main.c index 24bfd6d..12225d9 100644 --- a/eblapp-server/src/main.c +++ b/eblapp-server/src/main.c @@ -1,20 +1,40 @@ // Eltex BoolLoader Application Provisioning Protocol Server #include +#include #include +#include +#include #include #include #include +#include #include #include +#include #include #include "eblapp.h" -#include "ring_buffer.h" #define BUFFER_SIZE 20000 #define PORT 1069 #define MAX_PACKET_SIZE 1400 #define TIMEOUT 5 +#define MAX_CLIENTS 10 + +struct client +{ + bool valid; + struct sockaddr_in client_addr; + socklen_t addr_len; + size_t current_offset; + size_t current_acked_byte; + int fd; + const uint8_t* file_data; + size_t file_size; + time_t last_time; +}; + +struct client g_clients[MAX_CLIENTS]; void error(const char* msg) { @@ -22,6 +42,159 @@ void error(const char* msg) exit(1); } +struct client* lookup_client(struct sockaddr* client_addr, size_t addr_len) +{ + for(size_t i = 0; i < MAX_CLIENTS; i++) + { + if(g_clients[i].valid && g_clients[i].addr_len == addr_len && memcmp(&g_clients[i].client_addr, client_addr, addr_len) == 0) + { + return &g_clients[i]; + } + } + return NULL; +} + +struct client* find_free_client_entry() +{ + for(size_t i = 0; i < MAX_CLIENTS; i++) + { + if(!g_clients[i].valid) + { + return &g_clients[i]; + } + } + return NULL; +} + +void delete_client(struct client* client) +{ + munmap((void*)client->file_data, client->file_size); + close(client->fd); + client->valid = false; +} + +int init_client(struct client* client_data, struct sockaddr_in* client_addr, socklen_t addr_len, const char* filename) +{ + int ret = 0; + struct stat st = {}; + printf("Request file: %s\n", filename); + ret = stat(filename, &st); + if(ret) + { + printf("stat failed(): %d", ret); + return ret; + } + + int fd = open(filename, O_RDONLY); + if(fd < 0) + { + printf("File not found: %s\n", filename); + return ret; + } + const uint8_t* const file_data = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + if(file_data == MAP_FAILED) + { + printf("Unable to mmap file: %d\n", errno); + return ret; + } + + memcpy(&client_data->client_addr, client_addr, sizeof(*client_addr)); + client_data->addr_len = addr_len; + client_data->fd = fd; + client_data->file_data = file_data; + client_data->file_size = st.st_size; + client_data->last_time = time(NULL); + client_data->current_acked_byte = 0; + client_data->current_offset = 0; + client_data->valid = true; + + return 0; +} + +void client_loop(int sockfd, struct client* client_data) +{ + uint8_t buffer[MAX_PACKET_SIZE]; + size_t bytes_left = client_data->file_size - client_data->current_offset; + size_t unacked = client_data->current_offset - client_data->current_acked_byte; + while(bytes_left && unacked < BUFFER_SIZE) + { + struct Eblapp_transfer_data* data = (struct Eblapp_transfer_data*)buffer; + size_t toread = bytes_left; + if(toread > MAX_PACKET_SIZE - 8) + { + toread = MAX_PACKET_SIZE - 8; + } + if(client_data->file_size - client_data->current_offset > 256) + { + // Keep destination nice and aligned + toread &= ~(0x0f); + if(toread == 0) + break; + } + // printf("bytes_left: %zu, current_offset: %zu\n", bytes_left, client_data->current_offset); + memcpy(buffer + 8, &client_data->file_data[client_data->current_offset], toread); + + data->opcode = EBLAPP_TRANSFER_DATA; + data->block_start = client_data->current_offset; + int n = sendto(sockfd, buffer, toread + sizeof(*data), 0, (struct sockaddr*)&client_data->client_addr, client_data->addr_len); + if(n < 0) + { + error("ERROR sending packet"); + } + + client_data->current_offset += toread; + bytes_left -= toread; + unacked += toread; + } + time_t now = time(NULL); + if(now - client_data->last_time > TIMEOUT) + { + printf("!ack recevied: %zu/%zu/(%zu)\n", client_data->current_acked_byte, client_data->current_offset, + client_data->current_offset - client_data->current_acked_byte); + client_data->current_offset = client_data->current_acked_byte; + } +} + +int client_ack(int sockfd, struct client* client_data, size_t acked_byte, bool* done) +{ + if(acked_byte >= client_data->file_size) + { + printf("Transfer done\n"); + *done = true; + struct Eblapp_transfer_end transfer_end = {}; + transfer_end.opcode = EBLAPP_TRANSFER_END; + + int n = sendto(sockfd, &transfer_end, sizeof(transfer_end), 0, (struct sockaddr*)&client_data->client_addr, client_data->addr_len); + if(n < 0) + { + error("ERROR sending transfer end"); + } + else + { + printf("sent %d\n", n); + } + return 0; + } + + if(acked_byte >= client_data->current_acked_byte) + { + size_t delta = acked_byte - client_data->current_acked_byte; + client_data->current_acked_byte = acked_byte; + } + client_data->last_time = time(NULL); + + client_loop(sockfd, client_data); +} + +int client_wtf(int sockfd, struct client* client_data, size_t acked_byte) +{ + client_data->current_offset = client_data->current_acked_byte; + client_data->last_time = time(NULL); + + client_loop(sockfd, client_data); + return 0; +} + int main() { int ret = 0; @@ -49,168 +222,83 @@ int main() { char buffer[MAX_PACKET_SIZE]; clilen = sizeof(cli_addr); - int n = recvfrom(sockfd, buffer, MAX_PACKET_SIZE, 0, (struct sockaddr*)&cli_addr, &clilen); - if(n < 0) - { - error("ERROR reading from socket"); - } - struct Eblapp_request* request = (struct Eblapp_request*)buffer; - if(request->opcode == EBLAPP_REQUEST_FILE) - { - size_t current_acked_byte = 0; + fd_set readfds; + struct timeval tv; + int ack_received = 0; - struct ring_buffer* ring_buffer = NULL; - if(ring_buffer__init(&ring_buffer, BUFFER_SIZE)) - { - error("ring_buffer__init() failed"); - } - struct stat st = {}; - char filename[256] = {}; - uint32_t current_offset = 0; - struct Eblapp_request* request = (struct Eblapp_request*)buffer; - memcpy(filename, request->filename, request->filename_size); - printf("Request file: %s\n", filename); - ret = stat(filename, &st); - if(ret) - { - printf("stat failed(): %d", ret); - break; - } + FD_ZERO(&readfds); + FD_SET(sockfd, &readfds); + tv.tv_sec = 0; + tv.tv_usec = 500000; - int fd = open(filename, O_RDONLY); - if(fd < 0) + int rv = select(sockfd + 1, &readfds, NULL, NULL, &tv); + if(rv > 0) + { + int n = recvfrom(sockfd, buffer, MAX_PACKET_SIZE, 0, (struct sockaddr*)&cli_addr, &clilen); + if(n < 0) { - printf("File not found: %s\n", filename); - continue; + error("ERROR reading from socket"); } - while(1) + struct Eblapp_request* request = (struct Eblapp_request*)buffer; + if(request->opcode == EBLAPP_REQUEST_FILE) { - size_t space_left = 0; - size_t bytes_left = 0; - ring_buffer__get_free_bytes(ring_buffer, &space_left); - while(space_left) + size_t current_acked_byte = 0; + uint32_t current_offset = 0; + + char filename[256] = {}; + struct Eblapp_request* request = (struct Eblapp_request*)buffer; + memcpy(filename, request->filename, request->filename_size); + struct client* client_data = find_free_client_entry(); + if(!client_data) { - size_t toread = space_left > MAX_PACKET_SIZE ? MAX_PACKET_SIZE : space_left; - int bytes_read = read(fd, buffer, toread); - if(bytes_read <= 0) - { - break; - } - - if(ring_buffer__write(ring_buffer, buffer, bytes_read) < 0) - { - error("ring_buffer__write() failed"); - } - - ring_buffer__get_free_bytes(ring_buffer, &space_left); + printf("No free clients entry\n"); + continue; } - - ring_buffer__get_unread_bytes(ring_buffer, &bytes_left); - while(bytes_left) + if(init_client(client_data, &cli_addr, clilen, filename)) { - struct Eblapp_transfer_data* data = (struct Eblapp_transfer_data*)buffer; - size_t toread = bytes_left; - if(toread > MAX_PACKET_SIZE - 8) - { - toread = MAX_PACKET_SIZE - 8; - } - if (st.st_size - current_offset > 256) - { - // Keep destination nice and aligned - toread &= ~(0x0f); - if (toread == 0) - break; - } - if(ring_buffer__read(ring_buffer, buffer + 8, &toread) < 0) - { - perror("ring_buffer__read() failed"); - } - - data->opcode = EBLAPP_TRANSFER_DATA; - data->block_start = current_offset; - int n = sendto(sockfd, buffer, toread + sizeof(*data), 0, (struct sockaddr*)&cli_addr, clilen); - if(n < 0) - { - error("ERROR sending packet"); - } - - current_offset += (n - 8); - ring_buffer__get_unread_bytes(ring_buffer, &bytes_left); + error("Unable to init client"); } - - // Wait for ACKs - fd_set readfds; - struct timeval tv; - int ack_received = 0; - - FD_ZERO(&readfds); - FD_SET(sockfd, &readfds); - tv.tv_sec = TIMEOUT; - tv.tv_usec = 0; - - int rv = select(sockfd + 1, &readfds, NULL, NULL, &tv); - if(rv > 0) + client_loop(sockfd, client_data); + } + else if(request->opcode == EBLAPP_ACK) + { + struct Eblapp_ack* ack_packet = (struct Eblapp_ack*)buffer; + bool done = false; + struct client* client = lookup_client((struct sockaddr*)&cli_addr, clilen); + if(!client) { - n = recvfrom(sockfd, buffer, MAX_PACKET_SIZE, 0, (struct sockaddr*)&cli_addr, &clilen); - if(n >= 4) - { - struct Eblapp_ack* ack_packet = (struct Eblapp_ack*)buffer; - if(ack_packet->opcode == EBLAPP_ACK) - { - uint32_t acked_byte = ack_packet->ack_byte; - if(acked_byte >= st.st_size) - { - printf("Transfer done\n"); - break; - } - - if(acked_byte >= current_acked_byte) - { - size_t delta = acked_byte - current_acked_byte; - ring_buffer__ack(ring_buffer, delta); - current_acked_byte = acked_byte; - } - ack_received = 1; - } - else if(ack_packet->opcode == EBLAPP_WTF) - { - printf("Wtf received: %d/%d\n", ack_packet->ack_byte, current_acked_byte); - ack_received = 0; - } - } + printf("Unknown client packet\n"); + continue; } - - if(!ack_received) + client_ack(sockfd, client, ack_packet->ack_byte, &done); + if(done) { - // Timeout, resend all packets in window - printf("!ack recevied: %d/%d/(%d)\n", current_acked_byte, current_offset, current_offset - current_acked_byte); - ring_buffer__unread(ring_buffer, current_offset - current_acked_byte); - current_offset = current_acked_byte; + delete_client(client); } } - - close(fd); - printf("File %s sent successfully\n", filename); - + else if(request->opcode == EBLAPP_WTF) { - struct Eblapp_transfer_end transfer_end = {}; - transfer_end.opcode = EBLAPP_TRANSFER_END; - - int n = sendto(sockfd, &transfer_end, sizeof(transfer_end), 0, (struct sockaddr*)&cli_addr, clilen); - if(n < 0) - { - error("ERROR sending transfer end"); - } - else + struct Eblapp_ack* ack_packet = (struct Eblapp_ack*)buffer; + struct client* client = lookup_client((struct sockaddr*)&cli_addr, clilen); + if(!client) { - printf("sent %d\n", n); + printf("Unknown client packet\n"); + continue; } + printf("Wtf received: %d/%d\n", ack_packet->ack_byte, client->current_acked_byte); + client_wtf(sockfd, client, ack_packet->ack_byte); + } + } + for(size_t i = 0; i < MAX_CLIENTS; i++) + { + if(g_clients[i].valid) + { + client_loop(sockfd, &g_clients[i]); } } } - close(sockfd); return 0; }