Browse Source

elbapp-server: support multiple clients

master
Denis Tereshkin 5 months ago
parent
commit
b4b5e68d6d
  1. 8
      eblapp-client/src/main.c
  2. 370
      eblapp-server/src/main.c

8
eblapp-client/src/main.c

@ -11,7 +11,7 @@
#include "eblapp.h" #include "eblapp.h"
#define PORT 1069 #define PORT 1069
#define MAX_PACKET_SIZE 1024 #define MAX_PACKET_SIZE 1400
#define TIMEOUT 5 #define TIMEOUT 5
void error(const char *msg) { void error(const char *msg) {
@ -86,7 +86,7 @@ int main(int argc, char *argv[]) {
if (n < 4) if (n < 4)
continue; continue;
printf("opcode %d\n", data->opcode); // printf("opcode %d\n", data->opcode);
if (data->opcode == EBLAPP_TRANSFER_DATA) { // DATA if (data->opcode == EBLAPP_TRANSFER_DATA) { // DATA
struct Eblapp_ack ack = {0}; struct Eblapp_ack ack = {0};
if (data->block_start != current_offset) { if (data->block_start != current_offset) {
@ -97,13 +97,13 @@ int main(int argc, char *argv[]) {
ack.ack_byte = current_offset; ack.ack_byte = current_offset;
if (sendto(sockfd, &ack, sizeof(ack), 0, if (sendto(sockfd, &ack, sizeof(ack), 0,
(struct sockaddr *)&serv_addr, serv_len) < 0) { (struct sockaddr *)&serv_addr, serv_len) < 0) {
error("ERROR sending ACK"); error("ERROR sending WTF");
} }
wtf = 1; wtf = 1;
} }
} else { } else {
wtf = 0; wtf = 0;
printf("got %d\n", current_offset); printf("got %d (%d)\n", current_offset, n - 8);
current_offset += (n - 8); current_offset += (n - 8);
ack.opcode = EBLAPP_ACK; ack.opcode = EBLAPP_ACK;
ack.ack_byte = current_offset; ack.ack_byte = current_offset;

370
eblapp-server/src/main.c

@ -1,20 +1,40 @@
// Eltex BoolLoader Application Provisioning Protocol Server // Eltex BoolLoader Application Provisioning Protocol Server
#include <arpa/inet.h> #include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <netinet/in.h>
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/mman.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <time.h>
#include <unistd.h> #include <unistd.h>
#include "eblapp.h" #include "eblapp.h"
#include "ring_buffer.h"
#define BUFFER_SIZE 20000 #define BUFFER_SIZE 20000
#define PORT 1069 #define PORT 1069
#define MAX_PACKET_SIZE 1400 #define MAX_PACKET_SIZE 1400
#define TIMEOUT 5 #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) void error(const char* msg)
{ {
@ -22,6 +42,159 @@ void error(const char* msg)
exit(1); 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 main()
{ {
int ret = 0; int ret = 0;
@ -49,168 +222,83 @@ int main()
{ {
char buffer[MAX_PACKET_SIZE]; char buffer[MAX_PACKET_SIZE];
clilen = sizeof(cli_addr); 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; fd_set readfds;
if(request->opcode == EBLAPP_REQUEST_FILE) struct timeval tv;
{ int ack_received = 0;
size_t current_acked_byte = 0;
struct ring_buffer* ring_buffer = NULL; FD_ZERO(&readfds);
if(ring_buffer__init(&ring_buffer, BUFFER_SIZE)) FD_SET(sockfd, &readfds);
{ tv.tv_sec = 0;
error("ring_buffer__init() failed"); tv.tv_usec = 500000;
}
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;
}
int fd = open(filename, O_RDONLY); int rv = select(sockfd + 1, &readfds, NULL, NULL, &tv);
if(fd < 0) 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); error("ERROR reading from socket");
continue;
} }
while(1) struct Eblapp_request* request = (struct Eblapp_request*)buffer;
if(request->opcode == EBLAPP_REQUEST_FILE)
{ {
size_t space_left = 0; size_t current_acked_byte = 0;
size_t bytes_left = 0; uint32_t current_offset = 0;
ring_buffer__get_free_bytes(ring_buffer, &space_left);
while(space_left) 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; printf("No free clients entry\n");
int bytes_read = read(fd, buffer, toread); continue;
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);
} }
if(init_client(client_data, &cli_addr, clilen, filename))
ring_buffer__get_unread_bytes(ring_buffer, &bytes_left);
while(bytes_left)
{ {
struct Eblapp_transfer_data* data = (struct Eblapp_transfer_data*)buffer; error("Unable to init client");
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);
} }
client_loop(sockfd, client_data);
// Wait for ACKs }
fd_set readfds; else if(request->opcode == EBLAPP_ACK)
struct timeval tv; {
int ack_received = 0; struct Eblapp_ack* ack_packet = (struct Eblapp_ack*)buffer;
bool done = false;
FD_ZERO(&readfds); struct client* client = lookup_client((struct sockaddr*)&cli_addr, clilen);
FD_SET(sockfd, &readfds); if(!client)
tv.tv_sec = TIMEOUT;
tv.tv_usec = 0;
int rv = select(sockfd + 1, &readfds, NULL, NULL, &tv);
if(rv > 0)
{ {
n = recvfrom(sockfd, buffer, MAX_PACKET_SIZE, 0, (struct sockaddr*)&cli_addr, &clilen); printf("Unknown client packet\n");
if(n >= 4) continue;
{
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;
}
}
} }
client_ack(sockfd, client, ack_packet->ack_byte, &done);
if(!ack_received) if(done)
{ {
// Timeout, resend all packets in window delete_client(client);
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;
} }
} }
else if(request->opcode == EBLAPP_WTF)
close(fd);
printf("File %s sent successfully\n", filename);
{ {
struct Eblapp_transfer_end transfer_end = {}; struct Eblapp_ack* ack_packet = (struct Eblapp_ack*)buffer;
transfer_end.opcode = EBLAPP_TRANSFER_END; struct client* client = lookup_client((struct sockaddr*)&cli_addr, clilen);
if(!client)
int n = sendto(sockfd, &transfer_end, sizeof(transfer_end), 0, (struct sockaddr*)&cli_addr, clilen);
if(n < 0)
{
error("ERROR sending transfer end");
}
else
{ {
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); close(sockfd);
return 0; return 0;
} }

Loading…
Cancel
Save