sm64coopdx/src/pc/network/packets/packet_download.c
2022-02-05 10:26:07 -08:00

203 lines
6.5 KiB
C

#include <stdio.h>
#include "../network.h"
#include "pc/djui/djui.h"
#include "pc/mod_list.h"
#include "pc/debuglog.h"
#define CHUNK_SIZE 400
#define OFFSET_COUNT 5
static u64 sOffset[OFFSET_COUNT] = { 0 };
static bool sWaitingForOffset[OFFSET_COUNT] = { 0 };
u64 sTotalDownloadBytes = 0;
extern float gDownloadProgress;
void network_send_next_download_request(void) {
SOFT_ASSERT(gNetworkType == NT_CLIENT);
for (int i = 0; i < gModTableRemote.entryCount; i++) {
struct ModListEntry* entry = &gModTableRemote.entries[i];
if (entry->complete) { continue; }
//LOG_INFO("sending download request: %d, %d, %lld", i, entry->remoteIndex, entry->curOffset);
network_send_download_request(i, entry->remoteIndex, entry->curOffset);
return;
}
//LOG_INFO("sending join request");
network_send_join_request();
djui_panel_modlist_create(NULL);
}
void network_send_download_request(u16 clientIndex, u16 serverIndex, u64 offset) {
SOFT_ASSERT(gNetworkType == NT_CLIENT);
struct Packet p = { 0 };
packet_init(&p, PACKET_DOWNLOAD_REQUEST, true, PLMT_NONE);
packet_write(&p, &clientIndex, sizeof(u16));
packet_write(&p, &serverIndex, sizeof(u16));
packet_write(&p, &offset, sizeof(u64));
if (clientIndex == 0 && offset == 0) {
sTotalDownloadBytes = 0;
gDownloadProgress = 0;
}
struct ModListEntry* entry = &gModTableRemote.entries[clientIndex];
for (int i = 0; i < OFFSET_COUNT; i++) {
sOffset[i] = offset + CHUNK_SIZE * i;
sWaitingForOffset[i] = (sOffset[i] < entry->size);
}
network_send_to((gNetworkPlayerServer != NULL) ? gNetworkPlayerServer->localIndex : 0, &p);
}
void network_receive_download_request(struct Packet* p) {
SOFT_ASSERT(gNetworkType == NT_SERVER);
u16 clientIndex;
u16 serverIndex;
u64 offset;
packet_read(p, &clientIndex, sizeof(u16));
packet_read(p, &serverIndex, sizeof(u16));
packet_read(p, &offset, sizeof(u64));
struct ModListEntry* entry = &gModTableLocal.entries[serverIndex];
if (serverIndex >= gModTableLocal.entryCount) {
LOG_ERROR("Requested download of invalid index %u:%llu", serverIndex, offset);
return;
}
for (int i = 0; i < OFFSET_COUNT; i++) {
u64 o = offset + CHUNK_SIZE * i;
if (o >= entry->size) { break; }
network_send_download(clientIndex, serverIndex, o);
}
}
void network_send_download(u16 clientIndex, u16 serverIndex, u64 offset) {
SOFT_ASSERT(gNetworkType == NT_SERVER);
if (serverIndex >= gModTableLocal.entryCount) {
LOG_ERROR("Requested download of invalid index %u:%llu", serverIndex, offset);
return;
}
struct ModListEntry* entry = &gModTableLocal.entries[serverIndex];
if (offset >= entry->size) {
LOG_ERROR("Requested download of invalid offset %u:%llu", serverIndex, offset);
return;
}
if (entry->fp == NULL) {
LOG_ERROR("Requested download of invalid file pointer %u:%llu", serverIndex, offset);
return;
}
u16 chunkSize = 400;
if ((offset + chunkSize) > entry->size) {
chunkSize = entry->size - offset;
}
u8 chunk[400] = { 0 };
fseek(entry->fp, offset, SEEK_SET);
fread(chunk, chunkSize, 1, entry->fp);
struct Packet p = { 0 };
packet_init(&p, PACKET_DOWNLOAD, true, PLMT_NONE);
packet_write(&p, &clientIndex, sizeof(u16));
packet_write(&p, &serverIndex, sizeof(u16));
packet_write(&p, &offset, sizeof(u64));
packet_write(&p, &chunkSize, sizeof(u16));
packet_write(&p, chunk, chunkSize * sizeof(u8));
network_send_to(0, &p);
}
void network_receive_download(struct Packet* p) {
SOFT_ASSERT(gNetworkType == NT_CLIENT);
if (p->localIndex != UNKNOWN_LOCAL_INDEX) {
if (gNetworkPlayerServer == NULL || gNetworkPlayerServer->localIndex != p->localIndex) {
LOG_ERROR("Received download from known local index '%d'", p->localIndex);
return;
}
}
u16 clientIndex;
u16 serverIndex;
u64 offset;
u16 chunkSize;
u8 chunk[400] = { 0 };
packet_read(p, &clientIndex, sizeof(u16));
packet_read(p, &serverIndex, sizeof(u16));
packet_read(p, &offset, sizeof(u64));
packet_read(p, &chunkSize, sizeof(u16));
packet_read(p, chunk, chunkSize * sizeof(u8));
//LOG_ERROR("Received download %u:%llu", clientIndex, offset);
if (clientIndex >= gModTableRemote.entryCount) {
LOG_ERROR("Received download of invalid index %u:%llu", clientIndex, offset);
return;
}
struct ModListEntry* entry = &gModTableRemote.entries[clientIndex];
if (offset >= entry->size) {
LOG_ERROR("Received download of invalid offset %u:%llu", clientIndex, offset);
return;
}
if (entry->fp == NULL) {
LOG_ERROR("Received download of invalid file pointer %u:%llu", clientIndex, offset);
return;
}
if ((offset + chunkSize) > entry->size) {
LOG_ERROR("Received download of invalid chunk size %u:%llu:%u", clientIndex, offset, chunkSize);
return;
}
// check if we're still waiting for chunks
bool found = false;
bool waiting = false;
for (int i = 0; i < OFFSET_COUNT; i++) {
if (sOffset[i] == offset) {
found = sWaitingForOffset[i];
sWaitingForOffset[i] = false;
}
waiting = waiting || sWaitingForOffset[i];
}
if (!found) {
LOG_ERROR("Received download of unexpected offset [ %llu <-> %llu ] != %llu", entry->curOffset, entry->curOffset + CHUNK_SIZE * OFFSET_COUNT, offset);
return;
}
// write to the file
fseek(entry->fp, offset, SEEK_SET);
fwrite(chunk, sizeof(u8) * chunkSize, 1, entry->fp);
// update progress
sTotalDownloadBytes += chunkSize;
gDownloadProgress = (float)sTotalDownloadBytes / (float)gModTableRemote.totalSize;
if (!waiting) {
// check if we're finished with this file
//LOG_INFO("Checking download of '%s': %lld, %lld", entry->name, sOffset[OFFSET_COUNT - 1] + CHUNK_SIZE, entry->size);
if (sOffset[OFFSET_COUNT - 1] + CHUNK_SIZE >= entry->size) {
LOG_INFO("Finished download of '%s'", entry->name);
fclose(entry->fp);
// parse mod header
entry->fp = fopen(entry->path, "rb");
mod_list_extract_lua_fields(entry);
fclose(entry->fp);
entry->fp = NULL;
entry->complete = true;
}
entry->curOffset += CHUNK_SIZE * OFFSET_COUNT;
network_send_next_download_request();
}
}