File transfers working.
This commit is contained in:
parent
1a9fcdaaf3
commit
d15b264ef6
13 changed files with 167 additions and 79 deletions
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "network.h"
|
||||
#include "packet.h"
|
||||
#include "array.h"
|
||||
|
||||
#include "taglist.h"
|
||||
#include "window.h"
|
||||
|
@ -28,12 +29,22 @@
|
|||
#include "file.h"
|
||||
|
||||
|
||||
// All this queue nonsense allows you to request more
|
||||
// downloads while downloads are currently running.
|
||||
typedef struct FileListS {
|
||||
char **files;
|
||||
fileCallback callback;
|
||||
} FileListT;
|
||||
|
||||
|
||||
static uint8_t _channel = 0;
|
||||
static uint8_t _dialogVisible = 0;
|
||||
static int16_t _index = -1;
|
||||
static char **_fileList = NULL;
|
||||
static FileListT **_fileList = NULL;
|
||||
static FileListT *_current = NULL;
|
||||
static uint32_t _currentLength = 0;
|
||||
static char *_currentSha256 = NULL;
|
||||
static char *_file = NULL;
|
||||
static FILE *_handle = NULL;
|
||||
static fileCallback _done = NULL;
|
||||
static WindowT *_winFile = NULL;
|
||||
static LabelT *_lblFile = NULL;
|
||||
|
||||
|
@ -45,11 +56,24 @@ static void packetHandler(PacketDecodeDataT *packet);
|
|||
|
||||
|
||||
void fileCacheCheck(fileCallback callback, char *vpaths[]) {
|
||||
_done = callback;
|
||||
_fileList = vpaths;
|
||||
_index = -1;
|
||||
FileListT *newList = NULL;
|
||||
uint16_t i = 0;
|
||||
|
||||
// Add new entries to anything already in the queue.
|
||||
NEW(FileListT, newList);
|
||||
newList->callback = callback;
|
||||
newList->files = NULL;
|
||||
while (vpaths[i] != NULL) {
|
||||
arrput(newList->files, strdup(vpaths[i]));
|
||||
i++;
|
||||
}
|
||||
arrput(_fileList, newList);
|
||||
|
||||
// New queue?
|
||||
if (_channel == 0) {
|
||||
_dialogVisible = 0;
|
||||
_channel = netChannelGet(packetHandler);
|
||||
}
|
||||
|
||||
fileCheckNext();
|
||||
}
|
||||
|
@ -60,25 +84,57 @@ static void fileCheckNext(void) {
|
|||
char *packetData = NULL;
|
||||
uint16_t length = 0;
|
||||
uint32_t temp = 0;
|
||||
uint8_t doRecheck = 0;
|
||||
char *shaPointer = NULL;
|
||||
static char *badSHA = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
|
||||
|
||||
_index++;
|
||||
do {
|
||||
// This is ugly since both lists kind of depend on each other.
|
||||
doRecheck = 0;
|
||||
|
||||
if (_fileList[_index] == NULL) {
|
||||
// End of list!
|
||||
// Do we need a new entry from the queue?
|
||||
if (_current == NULL) {
|
||||
// End of queue?
|
||||
if (arrlen(_fileList) == 0) {
|
||||
logWrite("End of queue.\n");
|
||||
arrfree(_fileList);
|
||||
if (_dialogVisible) guiDelete(D(_winFile));
|
||||
netChannelRelease(_channel);
|
||||
_done();
|
||||
return;
|
||||
}
|
||||
|
||||
// Get next queue entry.
|
||||
logWrite("Next queue entry.\n");
|
||||
_currentLength = 0;
|
||||
_current = _fileList[0];
|
||||
arrdel(_fileList, 0);
|
||||
}
|
||||
|
||||
if (_file) DEL(_file);
|
||||
|
||||
// End of current queue file list?
|
||||
if (arrlen(_current->files) == 0) {
|
||||
logWrite("End of files.\n");
|
||||
// End of list!
|
||||
arrfree(_current->files);
|
||||
_current->callback();
|
||||
DEL(_current);
|
||||
// See if there's more.
|
||||
doRecheck = 1;
|
||||
} else {
|
||||
// No. Get next file.
|
||||
logWrite("Next file.\n");
|
||||
_file = _current->files[0];
|
||||
arrdel(_current->files, 0);
|
||||
}
|
||||
} while (doRecheck);
|
||||
|
||||
// Check next file.
|
||||
temp = FILE_REQUEST_CHECK;
|
||||
shaPointer = cacheSha256Get(_fileList[_index]);
|
||||
shaPointer = cacheSha256Get(_file);
|
||||
if (!shaPointer) shaPointer = badSHA;
|
||||
packetData = packetContentPack(&length, "iss", temp, shaPointer, _fileList[_index]);
|
||||
logWrite("Checking [%d] [%s] [%s]\n", temp, shaPointer, _fileList[_index]);
|
||||
packetData = packetContentPack(&length, "iss", temp, shaPointer, _file);
|
||||
logWrite("Checking [%d] [%s] [%s]\n", temp, shaPointer, _file);
|
||||
encoded.control = PACKET_CONTROL_DAT;
|
||||
encoded.packetType = PACKET_TYPE_FILE_REQUEST;
|
||||
encoded.channel = _channel;
|
||||
|
@ -117,18 +173,14 @@ static void fileShowError(char *message) {
|
|||
|
||||
static void packetHandler(PacketDecodeDataT *packet) {
|
||||
FileResponseT response = 0;
|
||||
uint32_t fileLength = 0;
|
||||
PacketEncodeDataT encoded = { 0 };
|
||||
char *packetData = NULL;
|
||||
uint16_t length = 0;
|
||||
uint32_t temp = 0;
|
||||
|
||||
logWrite("Got packet %d\n", packet->packetType);
|
||||
|
||||
if (packet->packetType == PACKET_TYPE_FILE_RESPONSE) {
|
||||
// Extract the response type. We get more data later.
|
||||
packetContentUnpack(packet->data, "i", &response);
|
||||
logWrite("Got response %d [%d bytes]\n", response, sizeof(response));
|
||||
switch (response) {
|
||||
case FILE_RESPONSE_UNKNOWN:
|
||||
logWrite("Unknown file transfer response.\n");
|
||||
|
@ -142,29 +194,36 @@ static void packetHandler(PacketDecodeDataT *packet) {
|
|||
break;
|
||||
|
||||
case FILE_RESPONSE_SEND:
|
||||
// Get file size.
|
||||
// Start of new file. Get SHA and length.
|
||||
logWrite("Got FILE_RESPONSE_SEND\n");
|
||||
packetContentUnpack(packet->data, "ii", &response, &fileLength);
|
||||
packetContentUnpack(packet->data, "iis", &response, &_currentLength, &_currentSha256);
|
||||
break;
|
||||
|
||||
case FILE_RESPONSE_DATA:
|
||||
// Get file size.
|
||||
logWrite("Got FILE_RESPONSE_DATA\n");
|
||||
// Receive new file data.
|
||||
if (!_dialogVisible) fileShowDialog();
|
||||
// Are we starting a new file?
|
||||
if (_handle == NULL) {
|
||||
logWrite("Opening [%s]\n", _fileList[_index]);
|
||||
_handle = cacheFOpen(_fileList[_index], "wb");
|
||||
logWrite("Opening [%s]\n", _file);
|
||||
_handle = cacheFOpen(_file, "wb");
|
||||
if (!_handle) {
|
||||
fileShowError("Unable to write to cache.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Write data to file, skipping first two integers stored in packet.
|
||||
logWrite("Writing %d bytes to [%s]\n", packet->length - 8, _fileList[_index]);
|
||||
fwrite(&packet->data[8], packet->length - 8, 1, _handle);
|
||||
// Write data to file, skipping first integer stored in packet.
|
||||
logWrite("Writing %d bytes to [%s]\n", packet->length - 4, _file);
|
||||
fwrite(&packet->data[4], packet->length - 4, 1, _handle);
|
||||
// Is this file complete?
|
||||
if (ftell(_handle) >= fileLength) {
|
||||
logWrite("Closing [%s]\n", _fileList[_index]);
|
||||
if (ftell(_handle) >= _currentLength) {
|
||||
logWrite("Closing [%s]\n", _file);
|
||||
// Close this file.
|
||||
cacheFClose(_handle);
|
||||
_handle = NULL;
|
||||
// Update cache entry to include SHA.
|
||||
cacheEntryAdd(_currentSha256, cacheEntryNameGet(_file), _file);
|
||||
// Next file!
|
||||
fileCheckNext();
|
||||
} else {
|
||||
|
|
|
@ -96,7 +96,7 @@ static void timHangupProgress(WidgetT *widget) {
|
|||
|
||||
case S_WAITING:
|
||||
// Shut down packet processing & COM port.
|
||||
netShutdown();
|
||||
netPacketHandlerStop();
|
||||
comClose(__configData.serialCom - 1);
|
||||
timerStop(t);
|
||||
// On to the next dialog.
|
||||
|
|
|
@ -220,7 +220,7 @@ static void tableLoad(void) {
|
|||
line = (char *)malloc(4096);
|
||||
if (line) {
|
||||
// Load string cache.
|
||||
cache = cacheFOpen("system:strings", "rt");
|
||||
cache = cacheFOpen("data:strings.dat", "rt");
|
||||
if (cache) {
|
||||
while (fscanf(cache, "%s\n", line) != EOF) {
|
||||
p = strstr(line, "=");
|
||||
|
@ -239,7 +239,7 @@ static void tableLoad(void) {
|
|||
cacheFClose(cache);
|
||||
}
|
||||
// Load integer cache.
|
||||
cache = cacheFOpen("system:integers", "rt");
|
||||
cache = cacheFOpen("data:integers.dat", "rt");
|
||||
if (cache) {
|
||||
while (fscanf(cache, "%s\n", line) != EOF) {
|
||||
p = strstr(line, "=");
|
||||
|
@ -262,7 +262,7 @@ static void tableSave(void) {
|
|||
FILE *cache = NULL;
|
||||
|
||||
// Save & free integer table.
|
||||
cache = cacheFOpen("system:integers", "wt");
|
||||
cache = cacheFOpen("data:integers.dat", "wt");
|
||||
if (cache) {
|
||||
if (__runtimeData.integers) {
|
||||
while (shlen(__runtimeData.integers) > 0) {
|
||||
|
@ -276,7 +276,7 @@ static void tableSave(void) {
|
|||
}
|
||||
|
||||
// Save & free string table.
|
||||
cache = cacheFOpen("system:strings", "wt");
|
||||
cache = cacheFOpen("data:strings.dat", "wt");
|
||||
if (cache) {
|
||||
if (__runtimeData.strings) {
|
||||
while (shlen(__runtimeData.strings) > 0) {
|
||||
|
|
|
@ -53,7 +53,7 @@ static void btnLogoffClick(WidgetT *widget) {
|
|||
(void)widget;
|
||||
|
||||
setButtons(0);
|
||||
msgBoxTwo("Cancel?", MSGBOX_ICON_QUESTION, "Cancel login?\n \nThis will disconnect you from the server.", "Okay", btnMsgBoxLogoff, "Cancel", btnMsgBoxLogoff);
|
||||
msgBoxTwo("Logoff?", MSGBOX_ICON_QUESTION, "This will disconnect you from the server.", "Okay", btnMsgBoxLogoff, "Cancel", btnMsgBoxLogoff);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -115,6 +115,8 @@ uint8_t cacheEntryAdd(char *sha256, char *entryName, char *virtualPath) {
|
|||
|
||||
// Index format is: SHA256 ENTRYNAME VIRTUALPATH
|
||||
|
||||
logWrite("Adding SHA [%s] Entry [%s] VPath [%s]\n", sha256, entryName, virtualPath);
|
||||
|
||||
sprintf(index, "CACHE%cINDEX.DAT", OS_PATH_SLASH);
|
||||
sprintf(indexNew, "CACHE%cINDEX.NEW", OS_PATH_SLASH);
|
||||
|
||||
|
@ -243,7 +245,7 @@ void cacheFClose(FILE *handle) {
|
|||
static char *cacheFieldGet(char *virtualPath, uint8_t field) {
|
||||
FILE *in = NULL;
|
||||
char index[16] = { 0 };
|
||||
static char buffer[1024] = { 0 };
|
||||
static char buffer[2048] = { 0 };
|
||||
static char *name = NULL;
|
||||
static char *path = NULL;
|
||||
static char *result = NULL;
|
||||
|
@ -258,7 +260,7 @@ static char *cacheFieldGet(char *virtualPath, uint8_t field) {
|
|||
if (osFileExists(index)) {
|
||||
in = fopen(index, "rt");
|
||||
if (in) {
|
||||
while ((fgets(buffer, 1024, in) != 0) && result == NULL) {
|
||||
while (result == NULL && (fgets(buffer, 2048, in) != 0)) {
|
||||
name = strstr(buffer, " ");
|
||||
*name = 0;
|
||||
name++;
|
||||
|
|
|
@ -21,8 +21,8 @@ TEMPLATE = subdirs
|
|||
CONFIG *= ORDERED
|
||||
|
||||
SUBDIRS = \
|
||||
client \
|
||||
server
|
||||
client
|
||||
# server
|
||||
# precache
|
||||
# font
|
||||
# primes
|
||||
|
|
12
schema.sql
12
schema.sql
|
@ -44,13 +44,13 @@ DROP TABLE IF EXISTS `files`;
|
|||
CREATE TABLE `files` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`realPath` varchar(1024) NOT NULL,
|
||||
`virtualPath` varchar(1024) NOT NULL,
|
||||
`virtualPath` varchar(512) NOT NULL,
|
||||
`sha256` varchar(64) NOT NULL,
|
||||
`description` varchar(255) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `virtualPath` (`virtualPath`),
|
||||
UNIQUE KEY `realPath` (`realPath`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
|
@ -99,14 +99,14 @@ CREATE TABLE `users` (
|
|||
`first` varchar(64) NOT NULL,
|
||||
`last` varchar(64) NOT NULL,
|
||||
`user` varchar(64) NOT NULL,
|
||||
`pass` varchar(64) NOT NULL,
|
||||
`pass` varchar(128) NOT NULL,
|
||||
`email` varchar(256) NOT NULL,
|
||||
`enabled` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`notes` text NOT NULL,
|
||||
`notes` text NOT NULL DEFAULT '',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `emailIDX` (`email`),
|
||||
UNIQUE KEY `userIDX` (`user`) USING BTREE
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||
|
||||
|
@ -118,4 +118,4 @@ CREATE TABLE `users` (
|
|||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2022-02-09 15:58:23
|
||||
-- Dump completed on 2022-02-14 20:13:22
|
||||
|
|
|
@ -179,8 +179,12 @@ void *clientThread(void *data) {
|
|||
arrdel(client->packetQueue, 0);
|
||||
}
|
||||
arrfree(client->packetQueue);
|
||||
|
||||
pthread_mutex_destroy(&client->packetQueueMutex);
|
||||
packetThreadDataDestroy(&client->packetThreadData);
|
||||
|
||||
if (client->handle) fclose(client->handle);
|
||||
|
||||
DEL(client);
|
||||
|
||||
pthread_exit(NULL);
|
||||
|
|
|
@ -51,8 +51,8 @@ typedef struct ClientThreadS {
|
|||
double pingLow;
|
||||
void *peer;
|
||||
// User State Stuff.
|
||||
uint8_t authenticated;
|
||||
FILE *handle; // ***TODO*** Needs to support more than one file transfer at a time.
|
||||
uint8_t authenticated; // Is the user logged in?
|
||||
FILE *handle; // Handle of file currently being transferred to client.
|
||||
uint32_t fileSize; // Length of current file being transferred.
|
||||
} ClientThreadT;
|
||||
|
||||
|
|
|
@ -75,19 +75,26 @@ static void clientApiFileRequestCheck(ClientThreadT *client, PacketDecodeDataT *
|
|||
PacketEncodeDataT encoded = { 0 };
|
||||
char *packetData = NULL;
|
||||
uint16_t length = 0;
|
||||
char shaInDB[128] = { 0 };
|
||||
char buffer[1024] = { 0 };
|
||||
char buffer2[1024] = { 0 };
|
||||
char buffer2[2048] = { 0 };
|
||||
uint32_t temp = 0;
|
||||
|
||||
logWrite("Got FILE_REQUEST_CHECK\n\r");
|
||||
|
||||
// Is something still open?
|
||||
if (client->handle) {
|
||||
fclose(client->handle);
|
||||
client->handle = NULL;
|
||||
}
|
||||
|
||||
// Extract the request.
|
||||
packetContentUnpack(data->data, "iss", &request, &sha256, &path);
|
||||
logWrite("[%s] [%s]\n\r", sha256, path);
|
||||
|
||||
// Look up the entry and compare SHA256.
|
||||
dbFileSha256Get(path, buffer, FILE_VIRTUAL_PATH_MAX);
|
||||
if (strcasecmp(sha256, buffer) == 0) {
|
||||
dbFileSha256Get(path, shaInDB, FILE_VIRTUAL_PATH_MAX);
|
||||
if (strcasecmp(sha256, shaInDB) == 0) {
|
||||
logWrite("File is current. Sending FILE_RESPONSE_OKAY.\n\r");
|
||||
// File is already current on client.
|
||||
temp = FILE_RESPONSE_OKAY;
|
||||
|
@ -103,21 +110,32 @@ static void clientApiFileRequestCheck(ClientThreadT *client, PacketDecodeDataT *
|
|||
logWrite("File needs updated.\n\r");
|
||||
// Get real path.
|
||||
dbFileRealPathGet(path, buffer, FILE_VIRTUAL_PATH_MAX);
|
||||
snprintf(buffer2, 1024, "%s%s", __settingsFile, buffer);
|
||||
snprintf(buffer2, 2048, "%s%s", __settingsFile, buffer);
|
||||
// Open file & get file size.
|
||||
client->handle = fopen(buffer2, "rb");
|
||||
if (!client->handle) {
|
||||
logWrite("Unable to open [%s]\n", buffer2);
|
||||
// ***TODO*** Handle error
|
||||
return;
|
||||
}
|
||||
fseek(client->handle, 0, SEEK_END);
|
||||
client->fileSize = ftell(client->handle);
|
||||
fseek(client->handle, 0, SEEK_SET);
|
||||
// Start sending new file to client.
|
||||
packetData = (char *)malloc(PACKET_MAX);
|
||||
if (!packetData) {
|
||||
// ***TODO*** Handle error
|
||||
}
|
||||
logWrite("Size is %d\n\r", client->fileSize);
|
||||
|
||||
// Send file metadata to start transfer
|
||||
logWrite("Sending FILE_RESPONSE_SEND.\n\r");
|
||||
temp = FILE_RESPONSE_SEND;
|
||||
packetData = packetContentPack(&length, "iis", temp, client->fileSize, shaInDB);
|
||||
encoded.control = PACKET_CONTROL_DAT;
|
||||
encoded.packetType = PACKET_TYPE_FILE_RESPONSE;
|
||||
encoded.channel = data->channel;
|
||||
encoded.encrypt = 0;
|
||||
packetEncode(client->packetThreadData, &encoded, packetData, length);
|
||||
packetSend(client->packetThreadData, &encoded);
|
||||
DEL(packetData);
|
||||
|
||||
// Start sending actual file data.
|
||||
clientApiFileRequestNext(client, data);
|
||||
}
|
||||
}
|
||||
|
@ -127,39 +145,36 @@ static void clientApiFileRequestNext(ClientThreadT *client, PacketDecodeDataT *d
|
|||
uint32_t temp = 0;
|
||||
PacketEncodeDataT encoded = { 0 };
|
||||
uint16_t length = 0;
|
||||
uint16_t dataSize = 0;
|
||||
char packetData[PACKET_MAX];
|
||||
|
||||
// Do we have an open file?
|
||||
if (client->handle) {
|
||||
logWrite("Sending FILE_RESPONSE_SEND.\n\r");
|
||||
logWrite("Sending FILE_RESPONSE_DATA.\n\r");
|
||||
// Add response type.
|
||||
temp = FILE_RESPONSE_SEND;
|
||||
memcpy(packetData, &temp, sizeof(int32_t));
|
||||
|
||||
// Add file length.
|
||||
memcpy(&packetData[4], &client->fileSize, sizeof(int32_t));
|
||||
temp = FILE_RESPONSE_DATA;
|
||||
memcpy(&packetData[0], &temp, sizeof(int32_t));
|
||||
|
||||
// Add file data.
|
||||
dataSize = client->fileSize - ftell(client->handle);
|
||||
if (dataSize > PACKET_MAX - 8) {
|
||||
// ***TODO*** We can't send quite a full packet for some reason.
|
||||
length = client->fileSize - ftell(client->handle);
|
||||
if (length > PACKET_MAX - 14) {
|
||||
// File is larger than a packet size.
|
||||
dataSize = PACKET_MAX - 8; // 8 for two integers of response data.
|
||||
fread(&packetData[8], dataSize, 1, client->handle);
|
||||
length = PACKET_MAX - 14; // 4 for integer of response type. 10 more because a full PACKET_MAX causes issues.
|
||||
fread(&packetData[4], length, 1, client->handle);
|
||||
} else {
|
||||
// File remains will fit in this packet.
|
||||
fread(&packetData[8], dataSize, 1, client->handle);
|
||||
fread(&packetData[4], length, 1, client->handle);
|
||||
fclose(client->handle);
|
||||
client->handle = NULL;
|
||||
}
|
||||
logWrite("Sending %d bytes\n\r", dataSize);
|
||||
logWrite("Sending %d bytes of file\n\r", length);
|
||||
|
||||
// Build packet.
|
||||
encoded.control = PACKET_CONTROL_DAT;
|
||||
encoded.packetType = PACKET_TYPE_FILE_RESPONSE;
|
||||
encoded.channel = data->channel;
|
||||
encoded.encrypt = 0;
|
||||
packetEncode(client->packetThreadData, &encoded, packetData, length);
|
||||
packetEncode(client->packetThreadData, &encoded, packetData, length + 4);
|
||||
// Send it.
|
||||
packetSend(client->packetThreadData, &encoded);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,9 @@
|
|||
#include "database.h"
|
||||
|
||||
|
||||
// ***TODO*** Left/Right trim whitespace from returned strings?
|
||||
|
||||
|
||||
#define STATEMENT_MAX 2048
|
||||
|
||||
|
||||
|
|
|
@ -153,6 +153,8 @@ void *serverThread(void *data) {
|
|||
client->pingLow = 9999;
|
||||
// User State Stuff.
|
||||
client->authenticated = 0;
|
||||
client->handle = NULL;
|
||||
client->fileSize = 0;
|
||||
// Keep our client in the peer data for later.
|
||||
event.peer->data = (void *)client;
|
||||
// Make new thread for this client.
|
||||
|
|
|
@ -64,7 +64,9 @@ typedef enum PacketTypeE {
|
|||
* Client -> PACKET_TYPE_FILE_REQUEST FILE_REQUEST_CHECK SHA256 VPATH
|
||||
* Server -> PACKET_TYPE_FILE_RESPONSE FILE_RESPONSE_OKAY
|
||||
* - or -
|
||||
* Server -> PACKET_TYPE_FILE_RESPONSE FILE_RESPONSE_SEND (4 bytes length) (data...)
|
||||
* Server -> PACKET_TYPE_FILE_RESPONSE FILE_RESPONSE_SEND (4 bytes length) SHA256
|
||||
*
|
||||
* Server -> PACKET_TYPE_FILE_RESPONSE FILE_RESPONSE_DATA (data...)
|
||||
* Client -> PACKET_TYPE_FILE_REQUEST FILE_REQUEST_NEXT
|
||||
* (Repeat until received data matches the length.)
|
||||
*/
|
||||
|
@ -76,6 +78,7 @@ typedef enum FileRequestsE {
|
|||
|
||||
typedef enum FileResponseE {
|
||||
FILE_RESPONSE_UNKNOWN = 0,
|
||||
FILE_RESPONSE_DATA,
|
||||
FILE_RESPONSE_OKAY,
|
||||
FILE_RESPONSE_SEND
|
||||
} FileResponseT;
|
||||
|
|
Loading…
Add table
Reference in a new issue