Browse Source

elbapp-server: support multiple clients

master
Denis Tereshkin 5 months ago
parent
commit
b4b5e68d6d
  1. 8
      eblapp-client/src/main.c
  2. 306
      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;

306
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,93 +42,81 @@ void error(const char* msg)
exit(1); exit(1);
} }
int main() struct client* lookup_client(struct sockaddr* client_addr, size_t addr_len)
{ {
int ret = 0; for(size_t i = 0; i < MAX_CLIENTS; i++)
int sockfd, newsockfd;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd < 0)
{ {
error("ERROR opening socket"); 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;
} }
memset((char*)&serv_addr, 0, sizeof(serv_addr)); struct client* find_free_client_entry()
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(PORT);
if(bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
error("ERROR on binding");
printf("Server started on port %d\n", PORT);
while(1)
{ {
char buffer[MAX_PACKET_SIZE]; for(size_t i = 0; i < MAX_CLIENTS; i++)
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"); if(!g_clients[i].valid)
{
return &g_clients[i];
}
}
return NULL;
} }
struct Eblapp_request* request = (struct Eblapp_request*)buffer; void delete_client(struct client* client)
if(request->opcode == EBLAPP_REQUEST_FILE)
{ {
size_t current_acked_byte = 0; munmap((void*)client->file_data, client->file_size);
close(client->fd);
client->valid = false;
}
struct ring_buffer* ring_buffer = NULL; int init_client(struct client* client_data, struct sockaddr_in* client_addr, socklen_t addr_len, const char* filename)
if(ring_buffer__init(&ring_buffer, BUFFER_SIZE))
{ {
error("ring_buffer__init() failed"); int ret = 0;
}
struct stat st = {}; 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); printf("Request file: %s\n", filename);
ret = stat(filename, &st); ret = stat(filename, &st);
if(ret) if(ret)
{ {
printf("stat failed(): %d", ret); printf("stat failed(): %d", ret);
break; return ret;
} }
int fd = open(filename, O_RDONLY); int fd = open(filename, O_RDONLY);
if(fd < 0) if(fd < 0)
{ {
printf("File not found: %s\n", filename); printf("File not found: %s\n", filename);
continue; return ret;
} }
const uint8_t* const file_data = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
while(1) if(file_data == MAP_FAILED)
{
size_t space_left = 0;
size_t bytes_left = 0;
ring_buffer__get_free_bytes(ring_buffer, &space_left);
while(space_left)
{ {
size_t toread = space_left > MAX_PACKET_SIZE ? MAX_PACKET_SIZE : space_left; printf("Unable to mmap file: %d\n", errno);
int bytes_read = read(fd, buffer, toread); return ret;
if(bytes_read <= 0)
{
break;
} }
if(ring_buffer__write(ring_buffer, buffer, bytes_read) < 0) memcpy(&client_data->client_addr, client_addr, sizeof(*client_addr));
{ client_data->addr_len = addr_len;
error("ring_buffer__write() failed"); 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;
ring_buffer__get_free_bytes(ring_buffer, &space_left); return 0;
} }
ring_buffer__get_unread_bytes(ring_buffer, &bytes_left); void client_loop(int sockfd, struct client* client_data)
while(bytes_left) {
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; struct Eblapp_transfer_data* data = (struct Eblapp_transfer_data*)buffer;
size_t toread = bytes_left; size_t toread = bytes_left;
@ -116,101 +124,181 @@ int main()
{ {
toread = MAX_PACKET_SIZE - 8; toread = MAX_PACKET_SIZE - 8;
} }
if (st.st_size - current_offset > 256) if(client_data->file_size - client_data->current_offset > 256)
{ {
// Keep destination nice and aligned // Keep destination nice and aligned
toread &= ~(0x0f); toread &= ~(0x0f);
if(toread == 0) if(toread == 0)
break; break;
} }
if(ring_buffer__read(ring_buffer, buffer + 8, &toread) < 0) // 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);
perror("ring_buffer__read() failed");
}
data->opcode = EBLAPP_TRANSFER_DATA; data->opcode = EBLAPP_TRANSFER_DATA;
data->block_start = current_offset; data->block_start = client_data->current_offset;
int n = sendto(sockfd, buffer, toread + sizeof(*data), 0, (struct sockaddr*)&cli_addr, clilen); int n = sendto(sockfd, buffer, toread + sizeof(*data), 0, (struct sockaddr*)&client_data->client_addr, client_data->addr_len);
if(n < 0) if(n < 0)
{ {
error("ERROR sending packet"); error("ERROR sending packet");
} }
current_offset += (n - 8); client_data->current_offset += toread;
ring_buffer__get_unread_bytes(ring_buffer, &bytes_left); 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;
int sockfd, newsockfd;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd < 0)
{
error("ERROR opening socket");
}
memset((char*)&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(PORT);
if(bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
error("ERROR on binding");
printf("Server started on port %d\n", PORT);
while(1)
{
char buffer[MAX_PACKET_SIZE];
clilen = sizeof(cli_addr);
// Wait for ACKs
fd_set readfds; fd_set readfds;
struct timeval tv; struct timeval tv;
int ack_received = 0; int ack_received = 0;
FD_ZERO(&readfds); FD_ZERO(&readfds);
FD_SET(sockfd, &readfds); FD_SET(sockfd, &readfds);
tv.tv_sec = TIMEOUT; tv.tv_sec = 0;
tv.tv_usec = 0; tv.tv_usec = 500000;
int rv = select(sockfd + 1, &readfds, NULL, NULL, &tv); int rv = select(sockfd + 1, &readfds, NULL, NULL, &tv);
if(rv > 0) if(rv > 0)
{ {
n = recvfrom(sockfd, buffer, MAX_PACKET_SIZE, 0, (struct sockaddr*)&cli_addr, &clilen); int n = recvfrom(sockfd, buffer, MAX_PACKET_SIZE, 0, (struct sockaddr*)&cli_addr, &clilen);
if(n >= 4) if(n < 0)
{
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"); error("ERROR reading from socket");
break;
} }
if(acked_byte >= current_acked_byte) struct Eblapp_request* request = (struct Eblapp_request*)buffer;
if(request->opcode == EBLAPP_REQUEST_FILE)
{ {
size_t delta = acked_byte - current_acked_byte; size_t current_acked_byte = 0;
ring_buffer__ack(ring_buffer, delta); uint32_t current_offset = 0;
current_acked_byte = acked_byte;
} char filename[256] = {};
ack_received = 1; 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)
{
printf("No free clients entry\n");
continue;
} }
else if(ack_packet->opcode == EBLAPP_WTF) if(init_client(client_data, &cli_addr, clilen, filename))
{ {
printf("Wtf received: %d/%d\n", ack_packet->ack_byte, current_acked_byte); error("Unable to init client");
ack_received = 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)
{
printf("Unknown client packet\n");
continue;
} }
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"); printf("Unknown client packet\n");
continue;
} }
else printf("Wtf received: %d/%d\n", ack_packet->ack_byte, client->current_acked_byte);
{ client_wtf(sockfd, client, ack_packet->ack_byte);
printf("sent %d\n", n);
} }
} }
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