commit
26b22a3bc1
10 changed files with 924 additions and 0 deletions
@ -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 @@ |
|||||||
|
#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 @@ |
|||||||
|
#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 @@ |
|||||||
|
--- |
||||||
|
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 @@ |
|||||||
|
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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
#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 @@ |
|||||||
|
#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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
#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