Browse Source

eblapp proof-of-concept

master
Denis Tereshkin 5 months ago
commit
26b22a3bc1
  1. 9
      eblapp-client/CMakeLists.txt
  2. 40
      eblapp-client/include/eblapp.h
  3. 126
      eblapp-client/src/main.c
  4. 165
      eblapp-server/.clang-format
  5. 9
      eblapp-server/CMakeLists.txt
  6. 104
      eblapp-server/include/crc32.h
  7. 46
      eblapp-server/include/eblapp.h
  8. 20
      eblapp-server/include/ring_buffer.h
  9. 215
      eblapp-server/src/main.c
  10. 190
      eblapp-server/src/ring_buffer.c

9
eblapp-client/CMakeLists.txt

@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.10)
project(eblapp-client LANGUAGES C)
include_directories(include)
file(GLOB SOURCE_FILES src/*.c)
add_executable(eblapp-client
${SOURCE_FILES})

40
eblapp-client/include/eblapp.h

@ -0,0 +1,40 @@
#ifndef EBLAPP_H
#define EBLAPP_H
#include <stdint.h>
#define EBLAPP_REQUEST_FILE 0x11
#define EBLAPP_TRANSFER_START 0x12
#define EBLAPP_TRANSFER_DATA 0x13
#define EBLAPP_TRANSFER_END 0x14
#define EBLAPP_ACK 0x15
#define EBLAPP_WTF 0x16
struct Eblapp_request {
uint32_t opcode;
uint32_t filename_size;
uint8_t filename[];
};
struct Eblapp_transfer_start {
uint32_t opcode;
uint32_t file_size;
uint32_t crc;
};
struct Eblapp_transfer_data {
uint32_t opcode;
uint32_t block_start;
uint8_t payload[];
};
struct Eblapp_transfer_end {
uint32_t opcode;
};
struct Eblapp_ack {
uint32_t opcode;
uint32_t ack_byte;
};
#endif /* EBLAPP_H */

126
eblapp-client/src/main.c

@ -0,0 +1,126 @@
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <unistd.h>
#include "eblapp.h"
#define PORT 1069
#define MAX_PACKET_SIZE 1024
#define TIMEOUT 5
void error(const char *msg) {
perror(msg);
exit(1);
}
int main(int argc, char *argv[]) {
if (argc < 3) {
fprintf(stderr, "Usage: %s hostname filename\n", argv[0]);
exit(1);
}
char buffer[MAX_PACKET_SIZE];
uint32_t current_offset = 0;
int sockfd;
struct sockaddr_in serv_addr;
struct hostent *server;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr, "ERROR, no such host\n");
exit(1);
}
memset((char *)&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
memcpy((char *)&serv_addr.sin_addr.s_addr, (char *)server->h_addr,
server->h_length);
serv_addr.sin_port = htons(PORT);
struct Eblapp_request *request = (struct Eblapp_request *)buffer;
request->opcode = EBLAPP_REQUEST_FILE;
request->filename_size = strlen(argv[2]);
memcpy(request + 1, argv[2], request->filename_size);
int packet_len = strlen(argv[2]) + sizeof(*request);
if (sendto(sockfd, buffer, packet_len, 0, (struct sockaddr *)&serv_addr,
sizeof(serv_addr)) < 0) {
error("ERROR sending RRQ");
}
printf("Requesting file: %s\n", argv[2]);
// Open output file
int fd = open(argv[3], O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd < 0) {
error("ERROR creating file");
}
int wtf = 0;
while (1) {
fd_set readfds;
struct timeval tv;
struct Eblapp_transfer_data *data = (struct Eblapp_transfer_data *)buffer;
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) {
socklen_t serv_len = sizeof(serv_addr);
int n = recvfrom(sockfd, buffer, MAX_PACKET_SIZE, 0,
(struct sockaddr *)&serv_addr, &serv_len);
if (n < 4)
continue;
printf("opcode %d\n", data->opcode);
if (data->opcode == EBLAPP_TRANSFER_DATA) { // DATA
struct Eblapp_ack ack = {0};
if (data->block_start != current_offset) {
if (!wtf) {
printf("Invalid order (%d/%d)\n", data->block_start,
current_offset);
ack.opcode = EBLAPP_WTF;
ack.ack_byte = current_offset;
if (sendto(sockfd, &ack, sizeof(ack), 0,
(struct sockaddr *)&serv_addr, serv_len) < 0) {
error("ERROR sending ACK");
}
wtf = 1;
}
} else {
wtf = 0;
printf("got %d\n", current_offset);
current_offset += (n - 8);
ack.opcode = EBLAPP_ACK;
ack.ack_byte = current_offset;
if (sendto(sockfd, &ack, sizeof(ack), 0,
(struct sockaddr *)&serv_addr, serv_len) < 0) {
error("ERROR sending ACK");
}
write(fd, buffer + 8, (n - 8));
}
} else if (data->opcode == EBLAPP_TRANSFER_END) {
printf("got transfer end\n");
break;
}
}
}
close(sockfd);
close(fd);
return 0;
}

165
eblapp-server/.clang-format

@ -0,0 +1,165 @@
---
Language: C
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: DontAlign
AlignConsecutiveMacros: None
AlignConsecutiveAssignments: None
AlignConsecutiveBitFields: None
AlignConsecutiveDeclarations: None
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortEnumsOnASingleLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
AttributeMacros:
- __capability
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: true
BreakBeforeBraces: Allman
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 160
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: false
DerivePointerAlignment: false
DisableFormat: false
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
StatementAttributeLikeMacros:
- Q_EMIT
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentCaseLabels: false
IndentCaseBlocks: false
IndentGotoLabels: true
IndentPPDirectives: None
IndentExternBlock: AfterExternBlock
IndentRequires: false
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PenaltyIndentedWhitespace: 0
PointerAlignment: Left
ReflowComments: true
SortIncludes: true
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: Never
SpaceAroundPointerQualifiers: Default
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: Both
Standard: Latest
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 4
UseCRLF: false
UseTab: Never
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
- NS_SWIFT_NAME
- CF_SWIFT_NAME
...

9
eblapp-server/CMakeLists.txt

@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.10)
project(eblapp-server LANGUAGES C)
include_directories(include)
file(GLOB SOURCE_FILES src/*.c)
add_executable(eblapp-server
${SOURCE_FILES})

104
eblapp-server/include/crc32.h

@ -0,0 +1,104 @@
// Polynomial = 0xEDB88320
#ifndef __CRC_32__
#define __CRC_32__
typedef unsigned int crc32_t;
static crc32_t crc32_table[256] =
{
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};
crc32_t crc32(const void *data, unsigned int length) {
crc32_t crc = 0xFFFFFFFF;
for (unsigned int index = 0; index< length; index++) {
crc = (crc >> 8) ^ crc32_table[(crc ^ ((unsigned char*)data)[index]) & 0xFF];
}
return crc ^ 0xFFFFFFFF;
}
crc32_t crc32_init() {
return 0xFFFFFFFF;
}
crc32_t crc32_update(unsigned int crc, void *data, unsigned int length) {
crc32_t _crc = crc;
for (unsigned int index = 0; index < length; index++) {
_crc = (_crc >> 8) ^ crc32_table[(_crc ^ ((unsigned char*)data)[index]) & 0xFF];
}
return _crc;
}
crc32_t crc32_final(unsigned int _crc) {
return _crc ^ 0XFFFFFFFF;
}
#endif

46
eblapp-server/include/eblapp.h

@ -0,0 +1,46 @@
#ifndef EBLAPP_H
#define EBLAPP_H
#include <stdint.h>
#define EBLAPP_REQUEST_FILE 0x11
#define EBLAPP_TRANSFER_START 0x12
#define EBLAPP_TRANSFER_DATA 0x13
#define EBLAPP_TRANSFER_END 0x14
#define EBLAPP_ACK 0x15
#define EBLAPP_WTF 0x16
struct Eblapp_request
{
uint32_t opcode;
uint32_t filename_size;
uint8_t filename[];
};
struct Eblapp_transfer_start
{
uint32_t opcode;
uint32_t file_size;
uint32_t crc;
};
struct Eblapp_transfer_data
{
uint32_t opcode;
uint32_t block_start;
uint8_t payload[];
};
struct Eblapp_transfer_end
{
uint32_t opcode;
};
struct Eblapp_ack
{
uint32_t opcode;
uint32_t ack_byte;
};
#endif /* EBLAPP_H */

20
eblapp-server/include/ring_buffer.h

@ -0,0 +1,20 @@
#ifndef RING_BUFFER_H
#define RING_BUFFER_H
#include <stddef.h>
#include <stdint.h>
struct ring_buffer;
int ring_buffer__init(struct ring_buffer **buffer, size_t size);
int ring_buffer__fini(struct ring_buffer *buffer);
int ring_buffer__write(struct ring_buffer *buffer, uint8_t *data,
size_t datalen);
int ring_buffer__read(struct ring_buffer *buffer, uint8_t *data,
size_t *datalen);
int ring_buffer__unread(struct ring_buffer *buffer, size_t bytes);
int ring_buffer__ack(struct ring_buffer *buffer, size_t acked_bytes);
int ring_buffer__get_unread_bytes(struct ring_buffer *buffer, size_t *bytes);
int ring_buffer__get_free_bytes(struct ring_buffer *buffer, size_t *bytes);
#endif /* RING_BUFFER_H */

215
eblapp-server/src/main.c

@ -0,0 +1,215 @@
// Eltex BoolLoader Application Provisioning Protocol Server
#include <arpa/inet.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <unistd.h>
#include "eblapp.h"
#include "ring_buffer.h"
#define BUFFER_SIZE 65536
#define PORT 1069
#define MAX_PACKET_SIZE 1024
#define TIMEOUT 5
void error(const char* msg)
{
perror(msg);
exit(1);
}
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);
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;
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;
}
int fd = open(filename, O_RDONLY);
if(fd < 0)
{
printf("File not found: %s\n", filename);
continue;
}
while(1)
{
size_t space_left = 0;
size_t bytes_left = 0;
ring_buffer__get_free_bytes(ring_buffer, &space_left);
printf("space_left: %zu\n", space_left);
while(space_left)
{
size_t toread = space_left > MAX_PACKET_SIZE ? MAX_PACKET_SIZE : space_left;
int bytes_read = read(fd, buffer, toread);
printf("bytes_read: %d\n", bytes_read);
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("space_left: %zu\n", space_left);
}
ring_buffer__get_unread_bytes(ring_buffer, &bytes_left);
printf("bytes_left: %zu\n", bytes_left);
while(bytes_left)
{
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(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);
printf("bytes_left: %zu (sent: %d)\n", bytes_left, current_offset);
}
// 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)
{
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;
printf("ack %d/%zu\n", acked_byte, st.st_size);
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;
}
}
}
if(!ack_received)
{
// 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;
}
}
close(fd);
printf("File %s sent successfully\n", filename);
{
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
{
printf("sent %d\n", n);
}
}
}
}
close(sockfd);
return 0;
}

190
eblapp-server/src/ring_buffer.c

@ -0,0 +1,190 @@
#include "ring_buffer.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct ring_buffer
{
uint8_t* buffer;
size_t size;
size_t write_ptr;
size_t read_ptr;
size_t ack_ptr;
};
static size_t min_size_t(size_t a, size_t b)
{
return a < b ? a : b;
}
int ring_buffer__init(struct ring_buffer** buffer, size_t size)
{
if(!buffer || size == 0)
{
return -1;
}
struct ring_buffer* rb = (struct ring_buffer*)calloc(1, sizeof(struct ring_buffer));
if(!rb)
{
return -1;
}
rb->buffer = (uint8_t*)malloc(size);
if(!rb->buffer)
{
free(rb);
return -1;
}
rb->size = size;
rb->write_ptr = 0;
rb->read_ptr = 0;
rb->ack_ptr = 0;
*buffer = rb;
return 0;
}
int ring_buffer__fini(struct ring_buffer* buffer)
{
if(!buffer)
{
return -1;
}
if(buffer->buffer)
{
free(buffer->buffer);
}
free(buffer);
return 0;
}
int ring_buffer__write(struct ring_buffer* buffer, uint8_t* data, size_t datalen)
{
if(!buffer || !data || datalen == 0)
{
return -1;
}
size_t free_space = (buffer->size - 1 - (buffer->write_ptr - buffer->ack_ptr)) % buffer->size;
if(free_space < datalen)
{
return -1; // Недостаточно места
}
size_t part1 = buffer->size - (buffer->write_ptr % buffer->size);
if(datalen <= part1)
{
memcpy(buffer->buffer + (buffer->write_ptr % buffer->size), data, datalen);
}
else
{
memcpy(buffer->buffer + (buffer->write_ptr % buffer->size), data, part1);
memcpy(buffer->buffer, data + part1, datalen - part1);
}
buffer->write_ptr = (buffer->write_ptr + datalen) % buffer->size;
return 0;
}
int ring_buffer__read(struct ring_buffer* buffer, uint8_t* data, size_t* datalen)
{
if(!buffer || !data || !datalen || *datalen == 0)
{
return -1;
}
size_t available = (buffer->write_ptr - buffer->read_ptr + buffer->size) % buffer->size;
if(available == 0)
{
*datalen = 0;
return -1; // Нет данных для чтения
}
size_t to_read = min_size_t(*datalen, available);
size_t part1 = buffer->size - (buffer->read_ptr % buffer->size);
if(to_read <= part1)
{
memcpy(data, buffer->buffer + (buffer->read_ptr % buffer->size), to_read);
}
else
{
memcpy(data, buffer->buffer + (buffer->read_ptr % buffer->size), part1);
memcpy(data + part1, buffer->buffer, to_read - part1);
}
buffer->read_ptr = (buffer->read_ptr + to_read) % buffer->size;
*datalen = to_read;
return 0;
}
int ring_buffer__unread(struct ring_buffer* buffer, size_t bytes)
{
if(!buffer)
{
return -1;
}
buffer->read_ptr = (buffer->read_ptr - bytes) % buffer->size;
}
int ring_buffer__ack(struct ring_buffer* buffer, size_t acked_bytes)
{
if(!buffer || acked_bytes == 0)
{
return -1;
}
size_t available = (buffer->read_ptr - buffer->ack_ptr + buffer->size) % buffer->size;
if(acked_bytes > available)
{
acked_bytes = available; // Защита от переполнения
}
buffer->ack_ptr = (buffer->ack_ptr + acked_bytes) % buffer->size;
return 0;
}
int ring_buffer__get_unread_bytes(struct ring_buffer* buffer, size_t* bytes)
{
if(!buffer || !bytes)
{
return -1;
}
size_t free_space = 0;
if(buffer->write_ptr >= buffer->read_ptr)
{
free_space = buffer->write_ptr - buffer->read_ptr;
}
else
{
free_space = buffer->size - (buffer->read_ptr - buffer->write_ptr);
}
*bytes = free_space;
return 0;
}
int ring_buffer__get_free_bytes(struct ring_buffer* buffer, size_t* bytes)
{
if(!buffer || !bytes)
{
return -1;
}
size_t free_space = 0;
if(buffer->write_ptr >= buffer->ack_ptr)
{
free_space = buffer->size - 1 - (buffer->write_ptr - buffer->ack_ptr);
}
else
{
free_space = (buffer->ack_ptr - buffer->write_ptr) - 1;
}
*bytes = free_space;
return 0;
}
Loading…
Cancel
Save