commit
26b22a3bc1
10 changed files with 924 additions and 0 deletions
@ -0,0 +1,9 @@
@@ -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}) |
||||
@ -0,0 +1,40 @@
@@ -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 */ |
||||
@ -0,0 +1,126 @@
@@ -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; |
||||
} |
||||
@ -0,0 +1,165 @@
@@ -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 |
||||
... |
||||
@ -0,0 +1,9 @@
@@ -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}) |
||||
@ -0,0 +1,104 @@
@@ -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 |
||||
@ -0,0 +1,46 @@
@@ -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 */ |
||||
@ -0,0 +1,20 @@
@@ -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 */ |
||||
@ -0,0 +1,215 @@
@@ -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; |
||||
} |
||||
@ -0,0 +1,190 @@
@@ -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…
Reference in new issue