Changeset View
Changeset View
Standalone View
Standalone View
source/network/NetFileTransfer.cpp
/* Copyright (C) 2016 Wildfire Games. | /* Copyright (C) 2018 Wildfire Games. | ||||
* This file is part of 0 A.D. | * This file is part of 0 A.D. | ||||
* | * | ||||
* 0 A.D. is free software: you can redistribute it and/or modify | * 0 A.D. is free software: you can redistribute it and/or modify | ||||
* it under the terms of the GNU General Public License as published by | * it under the terms of the GNU General Public License as published by | ||||
* the Free Software Foundation, either version 2 of the License, or | * the Free Software Foundation, either version 2 of the License, or | ||||
* (at your option) any later version. | * (at your option) any later version. | ||||
* | * | ||||
* 0 A.D. is distributed in the hope that it will be useful, | * 0 A.D. is distributed in the hope that it will be useful, | ||||
Show All 11 Lines | |||||
#include "lib/timer.h" | #include "lib/timer.h" | ||||
#include "network/NetMessage.h" | #include "network/NetMessage.h" | ||||
#include "network/NetSession.h" | #include "network/NetSession.h" | ||||
#include "ps/CLogger.h" | #include "ps/CLogger.h" | ||||
Status CNetFileTransferer::HandleMessageReceive(const CNetMessage* message) | Status CNetFileTransferer::HandleMessageReceive(const CNetMessage* message) | ||||
{ | { | ||||
if (message->GetType() == NMT_FILE_TRANSFER_RESPONSE) | if (message->GetType() == NMT_FILE_TRANSFER_RESPONSE) | ||||
vladislavbelov: I think this place is good for `switch`. | |||||
elexisAuthorUnsubmitted Not Done Inline ActionsSo you disagree with the idea of this patch? I think we could move all the NetClient and NetServer functions into a single switch statement too. elexis: So you disagree with the idea of this patch? I think we could move all the NetClient and… | |||||
elexisAuthorUnsubmitted Not Done Inline ActionsSorry, didn't comprehend what you meant. Preferably it should become an FSM but here we can use the switch indeed elexis: Sorry, didn't comprehend what you meant.
Preferably it should become an FSM but here we can… | |||||
return OnFileTransferResponse(message); | |||||
if (message->GetType() == NMT_FILE_TRANSFER_DATA) | |||||
return OnFileTransferData(message); | |||||
if (message->GetType() == NMT_FILE_TRANSFER_ACK) | |||||
return OnFileTransferAck(message); | |||||
return INFO::SKIPPED; | |||||
} | |||||
Status CNetFileTransferer::OnFileTransferResponse(const CNetMessage* message) | |||||
{ | { | ||||
CFileTransferResponseMessage* respMessage = (CFileTransferResponseMessage*)message; | CFileTransferResponseMessage* respMessage = (CFileTransferResponseMessage*)message; | ||||
vladislavbelovUnsubmitted Not Done Inline Actionsstatic_cast here and below. vladislavbelov: `static_cast` here and below. | |||||
if (m_FileReceiveTasks.find(respMessage->m_RequestID) == m_FileReceiveTasks.end()) | if (m_FileReceiveTasks.find(respMessage->m_RequestID) == m_FileReceiveTasks.end()) | ||||
{ | { | ||||
LOGERROR("Net transfer: Unsolicited file transfer response (id=%d)", (int)respMessage->m_RequestID); | LOGERROR("Net transfer: Unsolicited file transfer response (id=%d)", (int)respMessage->m_RequestID); | ||||
return ERR::FAIL; | return ERR::FAIL; | ||||
} | } | ||||
if (respMessage->m_Length == 0 || respMessage->m_Length > MAX_FILE_TRANSFER_SIZE) | if (respMessage->m_Length == 0 || respMessage->m_Length > MAX_FILE_TRANSFER_SIZE) | ||||
{ | { | ||||
LOGERROR("Net transfer: Invalid size for file transfer response (length=%d)", (int)respMessage->m_Length); | LOGERROR("Net transfer: Invalid size for file transfer response (length=%d)", (int)respMessage->m_Length); | ||||
return ERR::FAIL; | return ERR::FAIL; | ||||
} | } | ||||
shared_ptr<CNetFileReceiveTask> task = m_FileReceiveTasks[respMessage->m_RequestID]; | shared_ptr<CNetFileReceiveTask> task = m_FileReceiveTasks[respMessage->m_RequestID]; | ||||
task->m_Length = respMessage->m_Length; | task->m_Length = respMessage->m_Length; | ||||
task->m_Buffer.reserve(respMessage->m_Length); | task->m_Buffer.reserve(respMessage->m_Length); | ||||
LOGMESSAGERENDER("Downloading data over network (%d KB) - please wait...", (int)(task->m_Length/1024)); | LOGMESSAGERENDER("Downloading data over network (%d KB) - please wait...", (int)(task->m_Length/1024)); | ||||
m_LastProgressReportTime = timer_Time(); | m_LastProgressReportTime = timer_Time(); | ||||
return INFO::OK; | return INFO::OK; | ||||
} | } | ||||
else if (message->GetType() == NMT_FILE_TRANSFER_DATA) | |||||
Status CNetFileTransferer::OnFileTransferData(const CNetMessage* message) | |||||
{ | { | ||||
CFileTransferDataMessage* dataMessage = (CFileTransferDataMessage*)message; | CFileTransferDataMessage* dataMessage = (CFileTransferDataMessage*)message; | ||||
if (m_FileReceiveTasks.find(dataMessage->m_RequestID) == m_FileReceiveTasks.end()) | if (m_FileReceiveTasks.find(dataMessage->m_RequestID) == m_FileReceiveTasks.end()) | ||||
{ | { | ||||
LOGERROR("Net transfer: Unsolicited file transfer data (id=%d)", (int)dataMessage->m_RequestID); | LOGERROR("Net transfer: Unsolicited file transfer data (id=%d)", (int)dataMessage->m_RequestID); | ||||
return ERR::FAIL; | return ERR::FAIL; | ||||
} | } | ||||
shared_ptr<CNetFileReceiveTask> task = m_FileReceiveTasks[dataMessage->m_RequestID]; | shared_ptr<CNetFileReceiveTask> task = m_FileReceiveTasks[dataMessage->m_RequestID]; | ||||
task->m_Buffer += dataMessage->m_Data; | task->m_Buffer += dataMessage->m_Data; | ||||
if (task->m_Buffer.size() > task->m_Length) | if (task->m_Buffer.size() > task->m_Length) | ||||
{ | { | ||||
LOGERROR("Net transfer: Invalid size for file transfer data (length=%d actual=%d)", (int)task->m_Length, (int)task->m_Buffer.size()); | LOGERROR("Net transfer: Invalid size for file transfer data (length=%d actual=%d)", (int)task->m_Length, (int)task->m_Buffer.size()); | ||||
return ERR::FAIL; | return ERR::FAIL; | ||||
} | } | ||||
CFileTransferAckMessage ackMessage; | CFileTransferAckMessage ackMessage; | ||||
ackMessage.m_RequestID = task->m_RequestID; | ackMessage.m_RequestID = task->m_RequestID; | ||||
ackMessage.m_NumPackets = 1; // TODO: would be nice to send a single ack for multiple packets at once | ackMessage.m_NumPackets = 1; // TODO: would be nice to send a single ack for multiple packets at once | ||||
m_Session->SendMessage(&ackMessage); | m_Session->SendMessage(&ackMessage); | ||||
if (task->m_Buffer.size() == task->m_Length) | if (task->m_Buffer.size() == task->m_Length) | ||||
{ | { | ||||
LOGMESSAGERENDER("Download completed"); | LOGMESSAGERENDER("Download completed"); | ||||
task->OnComplete(); | task->OnComplete(); | ||||
m_FileReceiveTasks.erase(dataMessage->m_RequestID); | m_FileReceiveTasks.erase(dataMessage->m_RequestID); | ||||
return INFO::OK; | return INFO::OK; | ||||
} | } | ||||
// TODO: should report progress using proper GUI | // TODO: should report progress using proper GUI | ||||
// Report the download status occassionally | // Report the download status occassionally | ||||
double t = timer_Time(); | double t = timer_Time(); | ||||
if (t > m_LastProgressReportTime + 0.5) | if (t > m_LastProgressReportTime + 0.5) | ||||
vladislavbelovUnsubmitted Not Done Inline ActionsIt'd be good to describe why exactly 0.5, and probably add a constant name. vladislavbelov: It'd be good to describe why exactly `0.5`, and probably add a constant name. | |||||
elexisAuthorUnsubmitted Not Done Inline ActionsOr implementing the TODO elexis: Or implementing the TODO | |||||
elexisAuthorUnsubmitted Done Inline ActionsI guess it's exactly 0.5 because that's 1/2 :p as in at most two LOG draws per second. elexis: I guess it's exactly 0.5 because that's 1/2 :p as in at most two LOG draws per second.
The… | |||||
{ | { | ||||
LOGMESSAGERENDER("Downloading data: %.1f%% of %d KB", 100.f*task->m_Buffer.size()/task->m_Length, (int)(task->m_Length/1024)); | LOGMESSAGERENDER("Downloading data: %.1f%% of %d KB", 100.f*task->m_Buffer.size()/task->m_Length, (int)(task->m_Length/1024)); | ||||
m_LastProgressReportTime = t; | m_LastProgressReportTime = t; | ||||
} | } | ||||
return INFO::OK; | return INFO::OK; | ||||
} | } | ||||
else if (message->GetType() == NMT_FILE_TRANSFER_ACK) | |||||
Status CNetFileTransferer::OnFileTransferAck(const CNetMessage* message) | |||||
{ | { | ||||
CFileTransferAckMessage* ackMessage = (CFileTransferAckMessage*)message; | CFileTransferAckMessage* ackMessage = (CFileTransferAckMessage*)message; | ||||
if (m_FileSendTasks.find(ackMessage->m_RequestID) == m_FileSendTasks.end()) | if (m_FileSendTasks.find(ackMessage->m_RequestID) == m_FileSendTasks.end()) | ||||
{ | { | ||||
LOGERROR("Net transfer: Unsolicited file transfer ack (id=%d)", (int)ackMessage->m_RequestID); | LOGERROR("Net transfer: Unsolicited file transfer ack (id=%d)", (int)ackMessage->m_RequestID); | ||||
return ERR::FAIL; | return ERR::FAIL; | ||||
} | } | ||||
Done Inline ActionsWe can reuse the iterator below to avoid the duplicate lookup. Also the [] operator has the side effect of insertion when most of the time it would be an error to insert this way. elexis: We can reuse the iterator below to avoid the duplicate lookup. Also the `[]` operator has the… | |||||
CNetFileSendTask& task = m_FileSendTasks[ackMessage->m_RequestID]; | CNetFileSendTask& task = m_FileSendTasks[ackMessage->m_RequestID]; | ||||
if (ackMessage->m_NumPackets > task.packetsInFlight) | if (ackMessage->m_NumPackets > task.packetsInFlight) | ||||
{ | { | ||||
LOGERROR("Net transfer: Invalid num packets for file transfer ack (num=%d inflight=%d)", | LOGERROR("Net transfer: Invalid num packets for file transfer ack (num=%d inflight=%d)", | ||||
(int)ackMessage->m_NumPackets, (int)task.packetsInFlight); | (int)ackMessage->m_NumPackets, (int)task.packetsInFlight); | ||||
return ERR::FAIL; | return ERR::FAIL; | ||||
} | } | ||||
task.packetsInFlight -= ackMessage->m_NumPackets; | task.packetsInFlight -= ackMessage->m_NumPackets; | ||||
return INFO::OK; | return INFO::OK; | ||||
} | |||||
return INFO::SKIPPED; | |||||
} | } | ||||
void CNetFileTransferer::StartTask(const shared_ptr<CNetFileReceiveTask>& task) | void CNetFileTransferer::StartTask(const shared_ptr<CNetFileReceiveTask>& task) | ||||
{ | { | ||||
u32 requestID = m_NextRequestID++; | u32 requestID = m_NextRequestID++; | ||||
task->m_RequestID = requestID; | task->m_RequestID = requestID; | ||||
m_FileReceiveTasks[requestID] = task; | m_FileReceiveTasks[requestID] = task; | ||||
CFileTransferRequestMessage request; | CFileTransferRequestMessage request; | ||||
▲ Show 20 Lines • Show All 42 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator
I think this place is good for switch.