Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
NetFileTransfer.cpp
Go to the documentation of this file.
1 #include "precompiled.h"
2 
3 #include "NetFileTransfer.h"
4 
5 #include "lib/timer.h"
6 #include "network/NetMessage.h"
7 #include "network/NetSession.h"
8 #include "ps/CLogger.h"
9 
11 {
12  if (message->GetType() == NMT_FILE_TRANSFER_RESPONSE)
13  {
14  CFileTransferResponseMessage* respMessage = (CFileTransferResponseMessage*)message;
15 
16  if (m_FileReceiveTasks.find(respMessage->m_RequestID) == m_FileReceiveTasks.end())
17  {
18  LOGERROR(L"Net transfer: Unsolicited file transfer response (id=%d)", (int)respMessage->m_RequestID);
19  return ERR::FAIL;
20  }
21 
22  if (respMessage->m_Length == 0 || respMessage->m_Length > MAX_FILE_TRANSFER_SIZE)
23  {
24  LOGERROR(L"Net transfer: Invalid size for file transfer response (length=%d)", (int)respMessage->m_Length);
25  return ERR::FAIL;
26  }
27 
28  shared_ptr<CNetFileReceiveTask> task = m_FileReceiveTasks[respMessage->m_RequestID];
29 
30  task->m_Length = respMessage->m_Length;
31  task->m_Buffer.reserve(respMessage->m_Length);
32 
33  LOGMESSAGERENDER(L"Downloading data over network (%d KB) - please wait...", (int)(task->m_Length/1024));
35 
36  return INFO::OK;
37  }
38  else if (message->GetType() == NMT_FILE_TRANSFER_DATA)
39  {
40  CFileTransferDataMessage* dataMessage = (CFileTransferDataMessage*)message;
41 
42  if (m_FileReceiveTasks.find(dataMessage->m_RequestID) == m_FileReceiveTasks.end())
43  {
44  LOGERROR(L"Net transfer: Unsolicited file transfer data (id=%d)", (int)dataMessage->m_RequestID);
45  return ERR::FAIL;
46  }
47 
48  shared_ptr<CNetFileReceiveTask> task = m_FileReceiveTasks[dataMessage->m_RequestID];
49 
50  task->m_Buffer += dataMessage->m_Data;
51 
52  if (task->m_Buffer.size() > task->m_Length)
53  {
54  LOGERROR(L"Net transfer: Invalid size for file transfer data (length=%d actual=%d)", (int)task->m_Length, (int)task->m_Buffer.size());
55  return ERR::FAIL;
56  }
57 
58  CFileTransferAckMessage ackMessage;
59  ackMessage.m_RequestID = task->m_RequestID;
60  ackMessage.m_NumPackets = 1; // TODO: would be nice to send a single ack for multiple packets at once
61  m_Session->SendMessage(&ackMessage);
62 
63  if (task->m_Buffer.size() == task->m_Length)
64  {
65  LOGMESSAGERENDER(L"Download completed");
66 
67  task->OnComplete();
68  m_FileReceiveTasks.erase(dataMessage->m_RequestID);
69  return INFO::OK;
70  }
71 
72  // TODO: should report progress using proper GUI
73 
74  // Report the download status occassionally
75  double t = timer_Time();
76  if (t > m_LastProgressReportTime + 0.5)
77  {
78  LOGMESSAGERENDER(L"Downloading data: %.1f%% of %d KB", 100.f*task->m_Buffer.size()/task->m_Length, (int)(task->m_Length/1024));
80  }
81 
82  return INFO::OK;
83  }
84  else if (message->GetType() == NMT_FILE_TRANSFER_ACK)
85  {
86  CFileTransferAckMessage* ackMessage = (CFileTransferAckMessage*)message;
87 
88  if (m_FileSendTasks.find(ackMessage->m_RequestID) == m_FileSendTasks.end())
89  {
90  LOGERROR(L"Net transfer: Unsolicited file transfer ack (id=%d)", (int)ackMessage->m_RequestID);
91  return ERR::FAIL;
92  }
93 
94  CNetFileSendTask& task = m_FileSendTasks[ackMessage->m_RequestID];
95 
96  if (ackMessage->m_NumPackets > task.packetsInFlight)
97  {
98  LOGERROR(L"Net transfer: Invalid num packets for file transfer ack (num=%d inflight=%d)",
99  (int)ackMessage->m_NumPackets, (int)task.packetsInFlight);
100  return ERR::FAIL;
101  }
102 
103  task.packetsInFlight -= ackMessage->m_NumPackets;
104 
105  return INFO::OK;
106  }
107 
108  return INFO::SKIPPED;
109 }
110 
111 
112 void CNetFileTransferer::StartTask(const shared_ptr<CNetFileReceiveTask>& task)
113 {
114  u32 requestID = m_NextRequestID++;
115 
116  task->m_RequestID = requestID;
117  m_FileReceiveTasks[requestID] = task;
118 
119  CFileTransferRequestMessage request;
120  request.m_RequestID = requestID;
121  m_Session->SendMessage(&request);
122 }
123 
124 void CNetFileTransferer::StartResponse(u32 requestID, const std::string& data)
125 {
126  CNetFileSendTask task;
127  task.requestID = requestID;
128  task.buffer = data;
129  task.offset = 0;
130  task.packetsInFlight = 0;
132 
133  m_FileSendTasks[task.requestID] = task;
134  CFileTransferResponseMessage respMessage;
135  respMessage.m_RequestID = requestID;
136  respMessage.m_Length = task.buffer.size();
137  m_Session->SendMessage(&respMessage);
138 }
139 
141 {
142  // Find tasks which have fewer packets in flight than their window size,
143  // and send more packets
144  for (FileSendTasksMap::iterator it = m_FileSendTasks.begin(); it != m_FileSendTasks.end(); ++it)
145  {
146  while (it->second.packetsInFlight < it->second.maxWindowSize && it->second.offset < it->second.buffer.size())
147  {
148  CFileTransferDataMessage dataMessage;
149  dataMessage.m_RequestID = it->second.requestID;
150  ssize_t packetSize = std::min(DEFAULT_FILE_TRANSFER_PACKET_SIZE, it->second.buffer.size() - it->second.offset);
151  dataMessage.m_Data = it->second.buffer.substr(it->second.offset, packetSize);
152  it->second.offset += packetSize;
153  it->second.packetsInFlight++;
154  m_Session->SendMessage(&dataMessage);
155  }
156  }
157 
158  // TODO: need to garbage-collect finished tasks
159 }
const Status OK
Definition: status.h:386
#define LOGERROR
Definition: CLogger.h:35
FileSendTasksMap m_FileSendTasks
static const size_t DEFAULT_FILE_TRANSFER_WINDOW_SIZE
static const size_t MAX_FILE_TRANSFER_SIZE
static const size_t DEFAULT_FILE_TRANSFER_PACKET_SIZE
void StartTask(const shared_ptr< CNetFileReceiveTask > &task)
Registers a file-receiving task.
void StartResponse(u32 requestID, const std::string &data)
Registers data to be sent in response to a request.
Status HandleMessageReceive(const CNetMessage *message)
Should be called when a message is received from the network.
FileReceiveTasksMap m_FileReceiveTasks
virtual bool SendMessage(const CNetMessage *message)=0
i64 Status
Error handling system.
Definition: status.h:171
double timer_Time()
Definition: timer.cpp:98
NetMessageType GetType() const
Retrieves the message type.
Definition: NetMessage.h:46
The base class for all network messages exchanged within the game.
Definition: NetMessage.h:32
INetSession * m_Session
intptr_t ssize_t
Definition: wposix_types.h:82
void Poll()
Call frequently (e.g.
const Status SKIPPED
Definition: status.h:392
#define u32
Definition: types.h:41
Network client/server sessions.
#define LOGMESSAGERENDER
Definition: CLogger.h:33
const Status FAIL
Definition: status.h:406
Asynchronous file-sending task.