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 @@ @@ -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[]) { @@ -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[]) { @@ -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;

370
eblapp-server/src/main.c

@ -1,20 +1,40 @@ @@ -1,20 +1,40 @@
// Eltex BoolLoader Application Provisioning Protocol Server
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#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) @@ -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() @@ -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;
}

Loading…
Cancel
Save