Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
NetPeer.cpp
Go to the documentation of this file.
1 /* Project nGenEx
2  Destroyer Studios LLC
3  Copyright © 1997-2004. All Rights Reserved.
4 
5  SUBSYSTEM: NetEx.lib
6  FILE: NetPeer.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  One side of a UDP net link connection
13 */
14 
15 
16 #include "MemDebug.h"
17 #include <windows.h>
18 #include "NetPeer.h"
19 #include "NetGram.h"
20 #include "NetMsg.h"
21 #include "NetLayer.h"
22 
23 #include <stdio.h>
24 
25 // +-------------------------------------------------------------------+
26 
27 const int MULTIPART_CHUNKSIZE = 232;
28 const int MULTIPART_HEADER = 16;
29 const int UDP_HEADER_SIZE = 34;
30 
31 static NetMsgMultipart multi_part_buffer;
32 static DWORD multi_msg_sequence = 1;
33 
34 // +-------------------------------------------------------------------+
35 
36 NetPeer::NetPeer(const NetAddr& a, DWORD id)
37  : addr(a), netid(id), sequence(0), pps(0), bps(0), max_qsize(0),
38  status(OK), hist_indx(0), send_size(0), recv_size(0),
39  chunk_size(MULTIPART_CHUNKSIZE)
40 {
41  ZeroMemory(hist_time, sizeof(hist_time));
42  ZeroMemory(hist_size, sizeof(hist_size));
43 
44  last_recv_time = NetLayer::GetUTC();
45 }
46 
48 {
49  send_list.destroy();
50  recv_list.destroy();
51 
52  multi_send_list.destroy();
53  multi_recv_list.destroy();
54 }
55 
56 // +-------------------------------------------------------------------+
57 
58 bool
60 {
61  if (msg) {
62  if (max_qsize > 0 && msg->Length() + send_size > max_qsize) {
63  status = SEND_OVERFLOW;
64  delete msg;
65  return false;
66  }
67 
68  // simple message
69  if (msg->Length() <= (int) chunk_size) {
70  if (msg->IsPriority())
71  send_list.insert(msg);
72  else
73  send_list.append(msg);
74 
75  send_size += msg->Length();
76  }
77 
78  // multipart message
79  else {
80  List<NetMsg>* list = &send_list;
81 
82  if (msg->IsScatter())
83  list = &multi_send_list;
84 
85  DWORD nparts = msg->Length() / chunk_size;
86  DWORD extra = msg->Length() % chunk_size;
87 
88  if (extra > 0) nparts++;
89 
90  multi_part_buffer.type = NetMsg::MULTIPART;
91  multi_part_buffer.msgid = multi_msg_sequence++;
92  multi_part_buffer.nparts = nparts;
93 
94  DWORD header_size = (DWORD) (&multi_part_buffer.payload) -
95  (DWORD) (&multi_part_buffer);
96 
97  const BYTE* p = msg->Data();
98 
99  for (DWORD i = 0; i < nparts; i++) {
100  multi_part_buffer.partno = i;
101  NetMsg* part = 0;
102  DWORD part_size = chunk_size;
103 
104  if (i == nparts-1 && extra > 0) // last partial payload
105  part_size = extra;
106 
107  CopyMemory(multi_part_buffer.payload, p, part_size);
108  p += part_size;
109  part = new(__FILE__,__LINE__) NetMsg(msg->NetID(),
110  &multi_part_buffer,
111  header_size + part_size,
112  msg->Flags());
113 
114  if (part) {
115  list->append(part);
116  send_size += part->Length();
117  }
118  }
119  }
120 
121  return true;
122  }
123 
124  return false;
125 }
126 
127 // +-------------------------------------------------------------------+
128 
129 NetMsg*
131 {
132  if (recv_list.size() > 0) {
133  NetMsg* msg = recv_list.removeIndex(0);
134  recv_size -= msg->Length();
135  return msg;
136  }
137 
138  return 0;
139 }
140 
141 // +-------------------------------------------------------------------+
142 
143 NetGram*
145 {
146  NetGram* g = 0;
147 
148  if ((send_list.size() || multi_send_list.size()) && OKtoSend()) {
149  AutoThreadSync auto_sync(sync);
150 
151  int xmit_size = send_size;
152  int nmsg = send_list.size();
153  int limit = NET_GRAM_MAX_SIZE;
154  bool reliable = false;
155  bool is_multi = false;
156 
157  NetMsg* multi_msg = 0;
158  List<NetMsg>* list = &send_list;
159 
160  if (xmit_size > limit) {
161  xmit_size = 0;
162  nmsg = 0;
163 
164  if (send_list.size() > 0) {
165  NetMsg* msg = 0;
166 
167  // if there is regular traffic, and multipart traffic
168  if (multi_send_list.size()) {
169  // just send one multipart message in this packet
170  multi_msg = multi_send_list.removeIndex(0);
171  limit -= msg->Length();
172  reliable = true;
173  is_multi = true;
174  }
175 
176  for (int i = 0; i < send_list.size(); i++) {
177  NetMsg* msg = send_list[i];
178 
179  if (xmit_size + msg->Length() < limit) {
180  xmit_size += msg->Length();
181  nmsg++;
182  }
183  else {
184  break;
185  }
186  }
187  }
188  else {
189  // if there is only multipart traffic,
190  // send as many multipart messages as will fit:
191  list = &multi_send_list;
192  reliable = true;
193  is_multi = true;
194 
195  for (int i = 0; i < multi_send_list.size(); i++) {
196  NetMsg* msg = multi_send_list[i];
197 
198  if (xmit_size + msg->Length() < limit) {
199  xmit_size += msg->Length();
200  nmsg++;
201  }
202  else {
203  break;
204  }
205  }
206  }
207  }
208 
209  if (xmit_size > 0 && nmsg > 0) {
210  BYTE* buffer = new(__FILE__,__LINE__) BYTE[xmit_size];
211  BYTE* p = buffer;
212 
213  if (multi_msg) {
214  if (buffer) {
215  CopyMemory(p, multi_msg->Data(), multi_msg->Length());
216  p[1] = multi_msg->Length();
217  p += multi_msg->Length();
218  }
219  delete multi_msg;
220  }
221 
222  while (nmsg-- && p < buffer + xmit_size) {
223  NetMsg* msg = list->removeIndex(0);
224 
225  if (msg) {
226  if (msg->IsReliable()) reliable = true;
227  if (buffer) {
228  CopyMemory(p, msg->Data(), msg->Length());
229  p[1] = msg->Length();
230  p += msg->Length();
231  }
232  delete msg;
233  }
234  }
235 
236  if (buffer) {
237  Text user_data((const char*) buffer, xmit_size);
238  int retries = 0;
239 
240  if (reliable)
241  retries = 5;
242 
243  if (is_multi)
244  retries = 10;
245 
246  send_size -= xmit_size;
247 
248  hist_size[hist_indx] = xmit_size + UDP_HEADER_SIZE;
249  hist_time[hist_indx] = NetLayer::GetTime();
250  hist_indx++;
251 
252  if (hist_indx >= HIST_SIZE)
253  hist_indx = 0;
254 
255  g = new(__FILE__,__LINE__) NetGram(addr, user_data, retries);
256  delete[] buffer;
257  }
258  }
259 
260  // the next msg is too big to fit in a single packet
261  else {
262  NetMsg* m = send_list.removeIndex(0);
263  send_size -= m->Length();
264  delete m;
265  }
266  }
267 
268  return g;
269 }
270 
271 // +-------------------------------------------------------------------+
272 
273 bool
275 {
276  if (g) {
277  if (max_qsize > 0 && recv_size + g->Size() > max_qsize) {
278  status = RECV_OVERFLOW;
279  delete g;
280  return false;
281  }
282 
283  sequence = g->Sequence();
284  recv_size += g->Size() - NET_GRAM_HEADER_SIZE;
285 
286  // PARSE THE BLOCKS:
287  BYTE* p = g->UserData();
288 
289  while (p < g->Data() + g->Size()) {
290  BYTE block_type = p[0];
291  BYTE block_size = p[1];
292 
293  if (!block_type || !block_size)
294  break;
295 
296  NetMsg* msg = new(__FILE__,__LINE__) NetMsg(netid, p, block_size);
297 
298  if (msg) {
299  if (msg->Type() < NetMsg::RESERVED) {
300  msg->SetSequence(sequence);
301 
302  recv_list.insertSort(msg);
303 
304  if (q)
305  q->insertSort(msg);
306 
307  p += block_size;
308  }
309 
310  else if (msg->Type() == NetMsg::MULTIPART) {
311  multi_recv_list.insertSort(msg);
312  p += block_size;
313 
314  CheckMultiRecv(q);
315  }
316  }
317  }
318 
319  last_recv_time = NetLayer::GetUTC();
320 
321  delete g;
322  return true;
323  }
324 
325  return false;
326 }
327 
328 // +-------------------------------------------------------------------+
329 
330 bool
331 NetPeer::OKtoSend() const
332 {
333  if (pps || bps) {
334  DWORD hist_total = 0;
335  DWORD hist_count = 0;
336  DWORD now = NetLayer::GetTime();
337  DWORD hist_oldest = now;
338  DWORD hist_newest = 0;
339 
340  for (int i = 0; i < HIST_SIZE; i++) {
341  if (hist_size[i] > 0) {
342  hist_total += hist_size[i];
343  hist_count++;
344  }
345 
346  if (hist_time[i] > 0) {
347  if (hist_time[i] < hist_oldest)
348  hist_oldest = hist_time[i];
349 
350  if (hist_time[i] > hist_newest)
351  hist_newest = hist_time[i];
352  }
353  }
354 
355  if (now - hist_newest < (DWORD) pps)
356  return false;
357 
358  DWORD delta = now - hist_oldest;
359  DWORD avg_bps = hist_total / delta;
360 
361  if (bps > 0 && avg_bps > (DWORD) bps)
362  return false;
363  }
364 
365  return true;
366 }
367 
368 // +-------------------------------------------------------------------+
369 
371  DWORD msgid;
372  DWORD netid;
373  int nreq;
374  int nparts;
375  int nbytes;
376 };
377 
378 void
379 NetPeer::CheckMultiRecv(List<NetMsg>* q)
380 {
381  const int MAX_SIMULTANEOUS_MULTI_SEQUENCES = 8;
382 
383  PacketAssembly assy[MAX_SIMULTANEOUS_MULTI_SEQUENCES];
384  ZeroMemory(assy, sizeof(assy));
385 
386  DWORD header_size = (DWORD) (&multi_part_buffer.payload) -
387  (DWORD) (&multi_part_buffer);
388 
389  // Catalog how much of each multipart sequence has been received:
390  for (int i = 0; i < multi_recv_list.size(); i++) {
391  NetMsg* msg = multi_recv_list[i];
392  NetMsgMultipart* m = (NetMsgMultipart*) msg->Data();
393 
394  for (int n = 0; n < MAX_SIMULTANEOUS_MULTI_SEQUENCES; n++) {
395  PacketAssembly* a = assy + n;
396 
397  if (a->msgid == 0 || (a->msgid == m->msgid && a->netid == msg->NetID())) {
398  a->msgid = m->msgid;
399  a->netid = msg->NetID();
400  a->nreq = m->nparts;
401  a->nparts += 1;
402  a->nbytes += m->len - header_size;
403  break;
404  }
405  }
406  }
407 
408  for (int n = 0; n < MAX_SIMULTANEOUS_MULTI_SEQUENCES; n++) {
409  PacketAssembly* a = assy + n;
410 
411  // is this sequence complete?
412  if (a->msgid && a->nparts == a->nreq) {
413  BYTE* buffer = new BYTE[a->nbytes];
414  BYTE* p = buffer;
415  WORD nid = 0;
416 
417  ListIter<NetMsg> iter = multi_recv_list;
418  while (++iter) {
419  netid = iter->NetID();
420  NetMsgMultipart* m = (NetMsgMultipart*) iter->Data();
421 
422  // found part of the sequence
423  if (m->msgid == a->msgid && netid == a->netid) {
424  // copy it into the buffer
425  CopyMemory(p, m->payload, m->len - header_size);
426  p += m->len - header_size;
427 
428  delete iter.removeItem();
429  }
430  }
431 
432  NetMsg* msg = new(__FILE__,__LINE__) NetMsg(netid, buffer, a->nbytes, NetMsg::RELIABLE);
433  if (msg) {
434  recv_list.insertSort(msg);
435 
436  if (q)
437  q->insertSort(msg);
438  }
439  }
440  }
441 }