mirror of
https://github.com/Cesarus85/ringfall-mjolnir-vr.git
synced 2026-10-23 06:00:25 +02:00
1767 lines
49 KiB
C
1767 lines
49 KiB
C
/*
|
|
NETWORK_CONNECTION.C
|
|
|
|
symbols in this file:
|
|
00117B30 0010:
|
|
_network_connection_initialize (0000)
|
|
00117B40 0070:
|
|
_network_server_allow_client_connections (0000)
|
|
00117BB0 0060:
|
|
_network_connection_connected (0000)
|
|
00117C10 00a0:
|
|
_network_connection_get_address (0000)
|
|
00117CB0 0120:
|
|
_network_connection_connect (0000)
|
|
00117DD0 0040:
|
|
_network_connection_set_connection_rejection_procedure (0000)
|
|
00117E10 00a0:
|
|
_network_connection_server_accept_client_connection (0000)
|
|
00117EB0 0040:
|
|
_network_connection_active (0000)
|
|
00117EF0 0040:
|
|
_network_connection_going_stale (0000)
|
|
00117F30 0200:
|
|
_network_client_unreliable_connection_read (0000)
|
|
00118130 0440:
|
|
_network_connection_log_traffic_event (0000)
|
|
00118570 0010:
|
|
_network_connection_keep_alive (0000)
|
|
00118580 00d0:
|
|
_network_connection_delete (0000)
|
|
00118650 0330:
|
|
_network_connection_write (0000)
|
|
00118980 0140:
|
|
_network_server_close_client_connection (0000)
|
|
00118AC0 0080:
|
|
_network_connection_create_client_from_endpoint (0000)
|
|
00118B40 01e0:
|
|
_network_client_reliable_connection_read (0000)
|
|
00118D20 01e0:
|
|
_network_connection_idle_client_reliable_endpoint (0000)
|
|
00118F00 0240:
|
|
_network_connection_new (0000)
|
|
00119140 0090:
|
|
_network_connection_read (0000)
|
|
001191D0 00b0:
|
|
_network_connection_disconnect (0000)
|
|
00119280 02c0:
|
|
_network_connection_idle_server_reliable_endpoint (0000)
|
|
00119540 0310:
|
|
_network_connection_idle (0000)
|
|
00282D74 003d:
|
|
??_C@_0DN@LALHHLDL@server_connection?9?$DOflags?$CGFLAG?$CI_c@ (0000)
|
|
00282DB4 0012:
|
|
??_C@_0BC@MBGFNKLH@server_connection?$AA@ (0000)
|
|
00282DC8 002f:
|
|
??_C@_0CP@PHHPIMDF@c?3?2halo?2SOURCE?2networking?2networ@ (0000)
|
|
00282DF8 000b:
|
|
??_C@_0L@IJAFCDGM@connection?$AA@ (0000)
|
|
00282E04 003c:
|
|
??_C@_0DM@JFKHFKGL@connect_endpoint?$CI?$CJ?5on?5reliable?5e@ (0000)
|
|
00282E40 003e:
|
|
??_C@_0DO@PHFNEMHH@connect_endpoint?$CI?$CJ?5on?5unreliable@ (0000)
|
|
00282E80 002d:
|
|
??_C@_0CN@MMKPPGGM@connect_endpoint_async?$CI?$CJ?5returne@ (0000)
|
|
00282EB0 000f:
|
|
??_C@_0P@GENNJCOH@remote_address?$AA@ (0000)
|
|
00282EC0 0012:
|
|
??_C@_0BC@IIEOAGFH@client_connection?$AA@ (0000)
|
|
00282ED4 003e:
|
|
??_C@_0DO@KJEOOHFJ@partial?5datagram?5in?5queue?5?$CI?$CD?$CFd?5o@ (0000)
|
|
00282F14 0020:
|
|
??_C@_0CA@COBEMAD@encryption?5should?5not?5be?5active?$AA@ (0000)
|
|
00282F38 0065:
|
|
??_C@_0GF@CMFKGJHL@packet?5in?5queue?5is?5?$CD?$CFd?5bytes?0?5bu@ (0000)
|
|
00282FA0 0050:
|
|
??_C@_0FA@BBOJNMPA@got?5an?5unusually?5large?5datagram?5@ (0000)
|
|
00282FF0 0024:
|
|
??_C@_0CE@GAKKKNNF@?$CKbuffer_size?$DOsizeof?$CImessage_head@ (0000)
|
|
00283014 000c:
|
|
??_C@_0M@JLCCDMKC@buffer_size?$AA@ (0000)
|
|
00283020 0008:
|
|
??_C@_07ONPBMBOP@message?$AA@ (0000)
|
|
00283028 007b:
|
|
??_C@_0HL@CDIBBPO@connection?5?$CG?$CG?5connection?9?$DOunreli@ (0000)
|
|
002830A4 0019:
|
|
??_C@_0BJ@POEPMLNA@?$CB?$CCunknown?5traffic?5event?$CC?$AA@ (0000)
|
|
002830C0 0014:
|
|
??_C@_0BE@HPLCINIF@?$CFg?7?$CFld?7?$CFld?7?$CFld?7?$CFld?6?$AA@ (0000)
|
|
002830D4 0025:
|
|
??_C@_0CF@EIHEBDPA@connection?8s?5remote?5address?5was?3@ (0000)
|
|
002830FC 0020:
|
|
??_C@_0CA@JMADEGFJ@connection?5lifetime?7?$CFg?7seconds?6?$AA@ (0000)
|
|
00283120 0008:
|
|
__real@3f50624dd2f1a9fc (0000)
|
|
00283128 0042:
|
|
??_C@_0EC@HNHLBFPB@NOTE?3?5header?5overhead?5is?5not?5inc@ (0000)
|
|
0028316C 002f:
|
|
??_C@_0CP@CCJIMFN@stream?5overhead?5?$CIheaders?$CJ?7?$CFld?7by@ (0000)
|
|
0028319C 0032:
|
|
??_C@_0DC@JMBOAMCF@datagram?5overhead?5?$CIheaders?$CJ?7?$CFld?7@ (0000)
|
|
002831D0 001e:
|
|
??_C@_0BO@BKOHNOBI@stream?5messages?5received?7?$CFld?6?$AA@ (0000)
|
|
002831F0 001a:
|
|
??_C@_0BK@PLGDKDKM@stream?5messages?5sent?7?$CFld?6?$AA@ (0000)
|
|
0028320C 0018:
|
|
??_C@_0BI@CKENGKMK@datagrams?5received?7?$CFld?6?$AA@ (0000)
|
|
00283224 0014:
|
|
??_C@_0BE@MACKCCIC@datagrams?5sent?7?$CFld?6?$AA@ (0000)
|
|
00283238 0003:
|
|
??_C@_02PHMGELLB@?6?6?$AA@ (0000)
|
|
00283240 0045:
|
|
??_C@_0EF@PFDCDHNI@time?0?5seconds?7udp?5bytes?5out?7udp?5@ (0000)
|
|
00283288 0011:
|
|
??_C@_0BB@KBOPNJJN@_traffic_log?4xls?$AA@ (0000)
|
|
0028329C 0034:
|
|
??_C@_0DE@OCDLPLKI@client?5call?5to?5write_endpoint?$CI?$CJ?5@ (0000)
|
|
002832D0 0089:
|
|
??_C@_0IJ@ILIPJAEL@?$CIconnection?9?$DOflags?$CGFLAG?$CI_connect@ (0000)
|
|
0028335C 002a:
|
|
??_C@_0CK@OKGABJCB@message?5size?5exceeds?5maximum?5all@ (0000)
|
|
00283388 0025:
|
|
??_C@_0CF@KHJDIFFG@buffer_size?5?$DM?$DN?5DATAGRAM_MAXIMUM_@ (0000)
|
|
002833B0 001d:
|
|
??_C@_0BN@GKPOMGCO@buffer?5size?5was?5?$CFd?5max?5is?5?$CFd?$AA@ (0000)
|
|
002833D0 000d:
|
|
??_C@_0N@JGCLEACH@dest_address?$AA@ (0000)
|
|
002833E0 000a:
|
|
??_C@_09PFGDAODL@?$CBreliable?$AA@ (0000)
|
|
002833EC 0025:
|
|
??_C@_0CF@HBNJJBN@bad?5message?5or?5buffer_size?5param@ (0000)
|
|
00283418 0061:
|
|
??_C@_0GB@CPNIJODL@failed?5to?5remove?5a?5client?5endpoi@ (0000)
|
|
0028347C 0014:
|
|
??_C@_0BE@LJCKNEPN@server?9?$DOclient_list?$AA@ (0000)
|
|
00283490 0015:
|
|
??_C@_0BF@OMPKMEKG@server?9?$DOendpoint_set?$AA@ (0000)
|
|
002834A8 003f:
|
|
??_C@_0DP@KMHECGJA@server_connection?9?$DOflags?5?$CG?5FLAG?$CI@ (0000)
|
|
002834E8 0012:
|
|
??_C@_0BC@EKDFJKMJ@incoming?9reliable?$AA@ (0000)
|
|
002834FC 0012:
|
|
??_C@_0BC@LBJNKONM@reliable_endpoint?$AA@ (0000)
|
|
00283510 0063:
|
|
??_C@_0GD@KDKCLKAJ@packet?5in?5queue?5is?5?$CD?$CFd?5bytes?0?5bu@ (0000)
|
|
00283578 004d:
|
|
??_C@_0EN@FFFBCEEK@got?5an?5unusually?5large?5message?5?$CI@ (0000)
|
|
002835C8 0032:
|
|
??_C@_0DC@NIPJCDFJ@connection?5?$CG?$CG?5connection?9?$DOreliab@ (0000)
|
|
002835FC 003c:
|
|
??_C@_0DM@BHKHEGGG@blocked?5in?5network_connection_id@ (0000)
|
|
00283638 0020:
|
|
??_C@_0CA@CDMGOOMC@client?5reliable?5connection?5lost?$AA@ (0000)
|
|
00283658 0031:
|
|
??_C@_0DB@HLCKNJA@error?5?8?$CFs?8?5reading?5from?5client?5r@ (0000)
|
|
0028368C 0023:
|
|
??_C@_0CD@EEPBCOBK@circular_queue_queue_data?$CI?$CJ?5fail@ (0000)
|
|
002836B0 0024:
|
|
??_C@_0CE@ELOAAFGD@connection?9?$DOreliable_incoming_qu@ (0000)
|
|
002836D4 001e:
|
|
??_C@_0BO@GNMCHDOP@connection?9?$DOreliable_endpoint?$AA@ (0000)
|
|
002836F4 0014:
|
|
??_C@_0BE@NPIEPOBN@incoming?9unreliable?$AA@ (0000)
|
|
00283708 0030:
|
|
??_C@_0DA@ONKNJAHC@well_known_port?5?$DO?5MAXIMUM_RESERV@ (0000)
|
|
00283738 0065:
|
|
??_C@_0GF@LBGPIAAM@?$CIflags?$CGFLAG?$CI_connection_create_s@ (0000)
|
|
002837A0 0085:
|
|
??_C@_0IF@LOPDJAMN@connection?9?$DOflags?$CGFLAG?$CI_connecti@ (0000)
|
|
00283828 0028:
|
|
??_C@_0CI@GBLKHCFP@poll_endpoint_set?$CI?$CJ?5returned?5err@ (0000)
|
|
00283850 0027:
|
|
??_C@_0CH@EFPCNJNH@rogue?5endpoint?5connected?5to?5the?5@ (0000)
|
|
00283878 0042:
|
|
??_C@_0EC@FCONNFAI@failed?5to?5remove?5a?5client?5endpoi@ (0000)
|
|
002838BC 0020:
|
|
??_C@_0CA@KMGAFGOG@accept_endpoint?$CI?$CJ?5returned?5NULL?$AA@ (0000)
|
|
002838DC 0018:
|
|
??_C@_0BI@LPNBCLGA@error?5adding?5new?5client?$AA@ (0000)
|
|
002838F4 0016:
|
|
??_C@_0BG@BDEGOGDF@new_client_connection?$AA@ (0000)
|
|
0028390C 0019:
|
|
??_C@_0BJ@CNCMMBDB@connection?9?$DOendpoint_set?$AA@ (0000)
|
|
00283928 0029:
|
|
??_C@_0CJ@LIBJNIBK@connection?9?$DOconnection?4reliable_@ (0000)
|
|
00283954 0013:
|
|
??_C@_0BD@NCEDJJHP@connection?5?$CB?$DN?5NULL?$AA@ (0000)
|
|
00283968 0027:
|
|
??_C@_0CH@PJEDOOFH@datagram?5received?5from?5unknown?5a@ (0000)
|
|
00283990 0049:
|
|
??_C@_0EJ@EBOPBIBA@circular_queue_queue_data?$CI?$CJ?5fail@ (0000)
|
|
002839DC 0020:
|
|
??_C@_0CA@NHHJOLOM@endpoint?5read?5buffer?5overflowed?$AA@ (0000)
|
|
002839FC 0038:
|
|
??_C@_0DI@GAIEALCC@network_connection_idle_client_r@ (0000)
|
|
00283A34 0023:
|
|
??_C@_0CD@EAHAMPLA@timeout?5in?5network_connection_id@ (0000)
|
|
00283A58 0038:
|
|
??_C@_0DI@JINGJIOI@network_connection_idle_server_r@ (0000)
|
|
00283A90 0039:
|
|
??_C@_0DJ@ODICILDO@dont?5timeout?5is?5active?5so?5not?5ti@ (0000)
|
|
004566DA 0001:
|
|
_global_connection_dont_timeout (0000)
|
|
*/
|
|
|
|
/* ---------- headers */
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "cseries/cseries.h"
|
|
#include "cseries/cseries_windows.h"
|
|
#include "cseries/errors.h"
|
|
#include "bungie_net/common/message_header.h"
|
|
#include "bungie_net/network/transport.h"
|
|
#include "bungie_net/network/transport_endpoint_winsock.h"
|
|
#include "memory/circular_queue.h"
|
|
#include "network_connection.h"
|
|
|
|
/* ---------- constants */
|
|
|
|
/* the client connections a server accepts: one per machine, the host's own
|
|
included. The Xbox game uses the split screen player count (4), which is
|
|
also its machine count; the native builds use their machine limit
|
|
(port/linux/include/halo_port_limits.h). */
|
|
#ifdef HALO_LINUX
|
|
#define NETWORK_CONNECTION_MAXIMUM_CLIENTS HALO_PORT_MAXIMUM_NETWORK_MACHINES
|
|
#else
|
|
#define NETWORK_CONNECTION_MAXIMUM_CLIENTS MAXIMUM_NUMBER_OF_LOCAL_PLAYERS
|
|
#endif
|
|
|
|
enum
|
|
{
|
|
#ifdef HALO_LINUX
|
|
/* the per-tick update of 128 players is 3,857 bytes */
|
|
RELIABLE_MESSAGE_MAXIMUM_SIZE = HALO_PORT_MAXIMUM_NETWORK_MESSAGE_SIZE,
|
|
/* how long a stream write waits for a peer that is not reading */
|
|
NETWORK_CONNECTION_WRITE_TIMEOUT = 2000,
|
|
#else
|
|
RELIABLE_MESSAGE_MAXIMUM_SIZE = 2048,
|
|
#endif
|
|
MAXIMUM_RESERVED_NETWORK_PORT = 1023,
|
|
_transport_type_udp = 0x11,
|
|
_transport_type_tcp,
|
|
_connection_closed_bit = 4,
|
|
_connection_going_stale_bit,
|
|
};
|
|
|
|
enum network_connection_traffic_event
|
|
{
|
|
_network_connection_traffic_event_open,
|
|
_network_connection_traffic_event_close,
|
|
_network_connection_traffic_event_datagram_sent,
|
|
_network_connection_traffic_event_datagram_received,
|
|
_network_connection_traffic_event_stream_bytes_sent,
|
|
_network_connection_traffic_event_stream_bytes_received,
|
|
_network_connection_traffic_event_stream_message_sent,
|
|
_network_connection_traffic_event_stream_message_received,
|
|
};
|
|
|
|
/* ---------- macros */
|
|
|
|
/* ---------- structures */
|
|
|
|
struct network_connection
|
|
{
|
|
struct transport_endpoint *reliable_endpoint;
|
|
struct transport_endpoint *unreliable_endpoint;
|
|
unsigned long last_keep_alive_time;
|
|
network_connection_rejection_procedure connection_rejection_procedure;
|
|
struct circular_queue *reliable_incoming_queue;
|
|
struct circular_queue *unreliable_incoming_queue;
|
|
FILE *traffic_log;
|
|
unsigned long traffic_log_start_time;
|
|
long datagrams_sent;
|
|
long datagrams_received;
|
|
long stream_messages_sent;
|
|
long stream_messages_received;
|
|
unsigned long flags;
|
|
word well_known_port;
|
|
word padding36;
|
|
};
|
|
|
|
struct network_server_connection
|
|
{
|
|
struct network_connection connection;
|
|
struct transport_endpoint_set *endpoint_set;
|
|
struct network_connection *client_list[NETWORK_CONNECTION_MAXIMUM_CLIENTS];
|
|
boolean allow_client_connections;
|
|
};
|
|
|
|
/* ---------- prototypes */
|
|
|
|
static boolean network_client_reliable_connection_read(
|
|
struct network_connection *connection,
|
|
void *message,
|
|
word *buffer_size,
|
|
struct transport_address *source_address);
|
|
static struct network_connection *network_connection_create_client_from_endpoint(
|
|
struct transport_endpoint *reliable_endpoint);
|
|
static boolean network_connection_idle_client_reliable_endpoint(
|
|
struct network_connection *connection);
|
|
static boolean network_connection_idle_server_reliable_endpoint(
|
|
struct network_server_connection *connection,
|
|
struct network_connection **new_client_connection);
|
|
static void network_connection_log_traffic_event(
|
|
enum network_connection_traffic_event event,
|
|
long amount,
|
|
struct network_connection *connection);
|
|
static boolean network_client_unreliable_connection_read(
|
|
struct network_connection *connection,
|
|
void *message,
|
|
word *buffer_size,
|
|
struct transport_address *source_address);
|
|
|
|
/* ---------- globals */
|
|
|
|
boolean global_connection_dont_timeout = FALSE;
|
|
|
|
/* ---------- public code */
|
|
|
|
void network_connection_initialize(
|
|
void)
|
|
{
|
|
return;
|
|
}
|
|
|
|
boolean network_connection_connected(
|
|
struct network_connection *connection)
|
|
{
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x15C,
|
|
connection);
|
|
|
|
return ((connection->flags & FLAG(_connection_create_clientside_client_bit)) ||
|
|
(connection->flags & FLAG(_connection_create_serverside_client_bit))) &&
|
|
connection->reliable_endpoint &&
|
|
(boolean)endpoint_connected(connection->reliable_endpoint);
|
|
}
|
|
|
|
static void network_connection_log_traffic_event(
|
|
enum network_connection_traffic_event event,
|
|
long amount,
|
|
struct network_connection *connection)
|
|
{
|
|
struct transport_address address;
|
|
double elapsed_seconds;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x4CC,
|
|
connection);
|
|
|
|
if (amount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
switch (event)
|
|
{
|
|
case _network_connection_traffic_event_open:
|
|
{
|
|
if (get_endpoint_address(connection->reliable_endpoint, &address) &&
|
|
get_endpoint_address(connection->unreliable_endpoint, &address))
|
|
{
|
|
memset(&address, 0, sizeof(address));
|
|
address.address_length = IPV4_ADDRESS_LENGTH;
|
|
}
|
|
{
|
|
char traffic_log_name[256] = { 0 };
|
|
long character_index;
|
|
|
|
strcpy(traffic_log_name, transport_address_to_string(&address));
|
|
for (character_index = 0; traffic_log_name[character_index]; character_index++)
|
|
{
|
|
if (traffic_log_name[character_index] == ':')
|
|
{
|
|
traffic_log_name[character_index] = 0;
|
|
break;
|
|
}
|
|
}
|
|
strcat(traffic_log_name, "_traffic_log.xls");
|
|
connection->traffic_log = fopen(traffic_log_name, "w");
|
|
if (connection->traffic_log)
|
|
{
|
|
fprintf(connection->traffic_log, "time, seconds\tudp bytes out\tudp bytes in\ttcp bytes out\ttcp bytes in\n");
|
|
fflush(connection->traffic_log);
|
|
}
|
|
}
|
|
connection->traffic_log_start_time = system_milliseconds();
|
|
return;
|
|
}
|
|
|
|
case _network_connection_traffic_event_close:
|
|
if (!connection->traffic_log)
|
|
{
|
|
return;
|
|
}
|
|
if (get_endpoint_address(connection->reliable_endpoint, &address))
|
|
{
|
|
memset(&address, 0, sizeof(address));
|
|
address.address_length = IPV4_ADDRESS_LENGTH;
|
|
}
|
|
fprintf(connection->traffic_log, "\n\n");
|
|
fprintf(connection->traffic_log, "datagrams sent\t%ld\n", connection->datagrams_sent);
|
|
fprintf(connection->traffic_log, "datagrams received\t%ld\n", connection->datagrams_received);
|
|
fprintf(connection->traffic_log, "stream messages sent\t%ld\n", connection->stream_messages_sent);
|
|
fprintf(connection->traffic_log, "stream messages received\t%ld\n", connection->stream_messages_received);
|
|
fprintf(connection->traffic_log, "datagram overhead (headers)\t%ld\tbytes per packet\n", 0x1C);
|
|
fprintf(connection->traffic_log, "stream overhead (headers)\t%ld\tbytes per chunk\n", 0x28);
|
|
fprintf(connection->traffic_log, "NOTE: header overhead is not included in the above traffic graph\n");
|
|
fprintf(
|
|
connection->traffic_log,
|
|
"connection lifetime\t%g\tseconds\n",
|
|
(double)(system_milliseconds() - connection->traffic_log_start_time) / 1000.0);
|
|
fprintf(connection->traffic_log, "connection's remote address was: %s\n", transport_address_to_string(&address));
|
|
fclose(connection->traffic_log);
|
|
connection->traffic_log = NULL;
|
|
return;
|
|
|
|
case _network_connection_traffic_event_datagram_sent:
|
|
if (connection->traffic_log)
|
|
{
|
|
elapsed_seconds = (double)(system_milliseconds() - connection->traffic_log_start_time) / 1000.0;
|
|
fprintf(connection->traffic_log, "%g\t%ld\t%ld\t%ld\t%ld\n", elapsed_seconds, amount, 0, 0, 0);
|
|
fflush(connection->traffic_log);
|
|
}
|
|
connection->datagrams_sent++;
|
|
return;
|
|
|
|
case _network_connection_traffic_event_datagram_received:
|
|
if (connection->traffic_log)
|
|
{
|
|
elapsed_seconds = (double)(system_milliseconds() - connection->traffic_log_start_time) / 1000.0;
|
|
fprintf(connection->traffic_log, "%g\t%ld\t%ld\t%ld\t%ld\n", elapsed_seconds, 0, amount, 0, 0);
|
|
fflush(connection->traffic_log);
|
|
}
|
|
connection->datagrams_received++;
|
|
return;
|
|
|
|
case _network_connection_traffic_event_stream_bytes_sent:
|
|
if (connection->traffic_log)
|
|
{
|
|
elapsed_seconds = (double)(system_milliseconds() - connection->traffic_log_start_time) / 1000.0;
|
|
fprintf(connection->traffic_log, "%g\t%ld\t%ld\t%ld\t%ld\n", elapsed_seconds, 0, 0, amount, 0);
|
|
fflush(connection->traffic_log);
|
|
}
|
|
return;
|
|
|
|
case _network_connection_traffic_event_stream_bytes_received:
|
|
if (connection->traffic_log)
|
|
{
|
|
elapsed_seconds = (double)(system_milliseconds() - connection->traffic_log_start_time) / 1000.0;
|
|
fprintf(connection->traffic_log, "%g\t%ld\t%ld\t%ld\t%ld\n", elapsed_seconds, 0, 0, 0, amount);
|
|
fflush(connection->traffic_log);
|
|
}
|
|
return;
|
|
|
|
case _network_connection_traffic_event_stream_message_sent:
|
|
connection->stream_messages_sent++;
|
|
return;
|
|
|
|
case _network_connection_traffic_event_stream_message_received:
|
|
connection->stream_messages_received++;
|
|
return;
|
|
|
|
default:
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x557,
|
|
!"unknown traffic event");
|
|
return;
|
|
}
|
|
}
|
|
|
|
void network_connection_get_address(
|
|
struct network_connection *connection,
|
|
struct transport_address *reliable_address,
|
|
struct transport_address *unreliable_address)
|
|
{
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x292,
|
|
connection);
|
|
|
|
if (reliable_address)
|
|
{
|
|
if (connection->reliable_endpoint)
|
|
{
|
|
if (get_endpoint_address(connection->reliable_endpoint, reliable_address))
|
|
{
|
|
memset(reliable_address, 0, sizeof(*reliable_address));
|
|
reliable_address->address_length = IPV4_ADDRESS_LENGTH;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
memset(reliable_address, 0, sizeof(*reliable_address));
|
|
reliable_address->address_length = IPV4_ADDRESS_LENGTH;
|
|
}
|
|
}
|
|
|
|
if (unreliable_address)
|
|
{
|
|
if (connection->unreliable_endpoint)
|
|
{
|
|
if (get_endpoint_address(connection->unreliable_endpoint, unreliable_address))
|
|
{
|
|
memset(unreliable_address, 0, sizeof(*unreliable_address));
|
|
unreliable_address->address_length = IPV4_ADDRESS_LENGTH;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
memset(unreliable_address, 0, sizeof(*unreliable_address));
|
|
unreliable_address->address_length = IPV4_ADDRESS_LENGTH;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
boolean network_connection_connect(
|
|
struct network_connection *connection,
|
|
struct transport_address const *remote_address,
|
|
void *process_reference)
|
|
{
|
|
short result;
|
|
boolean success;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x2C0,
|
|
connection);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x2C1,
|
|
remote_address);
|
|
|
|
if (!connection->reliable_endpoint && !connection->unreliable_endpoint)
|
|
{
|
|
return FALSE;
|
|
}
|
|
success = TRUE;
|
|
|
|
if (connection->unreliable_endpoint)
|
|
{
|
|
result = connect_endpoint(connection->unreliable_endpoint, remote_address);
|
|
if (result)
|
|
{
|
|
error(
|
|
2,
|
|
"connect_endpoint() on unreliable endpoint returned error '%s'",
|
|
transport_error_to_string(result));
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (connection->reliable_endpoint)
|
|
{
|
|
if (process_reference)
|
|
{
|
|
result = connect_endpoint_async(connection->reliable_endpoint, remote_address, process_reference);
|
|
if (result && result != _transport_result_connect_in_progress)
|
|
{
|
|
error(
|
|
2,
|
|
"connect_endpoint_async() returned error '%s'",
|
|
transport_error_to_string(result));
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result = connect_endpoint(connection->reliable_endpoint, remote_address);
|
|
if (result)
|
|
{
|
|
error(
|
|
2,
|
|
"connect_endpoint() on reliable endpoint returned error '%s'",
|
|
transport_error_to_string(result));
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
void network_connection_set_connection_rejection_procedure(
|
|
struct network_connection *connection,
|
|
network_connection_rejection_procedure connection_rejection_procedure)
|
|
{
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x318,
|
|
connection);
|
|
|
|
connection->connection_rejection_procedure = connection_rejection_procedure;
|
|
|
|
return;
|
|
}
|
|
|
|
boolean network_connection_server_accept_client_connection(
|
|
struct network_connection *server_connection,
|
|
struct network_connection *client_connection)
|
|
{
|
|
struct network_server_connection *server = (struct network_server_connection *)server_connection;
|
|
boolean success;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x324,
|
|
server_connection);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x325,
|
|
server_connection->flags&FLAG(_connection_create_server_bit));
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x326,
|
|
client_connection);
|
|
|
|
success = !add_endpoint_to_set(client_connection->reliable_endpoint, server->endpoint_set);
|
|
|
|
return success;
|
|
}
|
|
|
|
boolean network_connection_active(
|
|
struct network_connection *connection)
|
|
{
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x330,
|
|
connection);
|
|
|
|
return !TEST_FLAG(connection->flags, _connection_closed_bit);
|
|
}
|
|
|
|
boolean network_connection_going_stale(
|
|
struct network_connection *connection)
|
|
{
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x338,
|
|
connection);
|
|
|
|
return TEST_FLAG(connection->flags, _connection_going_stale_bit);
|
|
}
|
|
|
|
static boolean network_client_unreliable_connection_read(
|
|
struct network_connection *connection,
|
|
void *message,
|
|
word *buffer_size,
|
|
struct transport_address *source_address)
|
|
{
|
|
message_header header;
|
|
unsigned long source_ipv4_address;
|
|
word message_size;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x3BA,
|
|
connection &&
|
|
connection->unreliable_incoming_queue &&
|
|
!(connection->flags&FLAG(_connection_create_serverside_client_bit)));
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x3BB,
|
|
message);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x3BC,
|
|
buffer_size);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x3BD,
|
|
*buffer_size>sizeof(message_header));
|
|
|
|
if (circular_queue_dequeue_data(connection->unreliable_incoming_queue, &header, sizeof(header), FALSE))
|
|
{
|
|
byte_swap_message_header(&header, _byte_order_host);
|
|
message_size = GET_MESSAGE_SIZE(header);
|
|
if (message_size > DATAGRAM_MAXIMUM_SIZE)
|
|
{
|
|
error(
|
|
_error_silent,
|
|
"got an unusually large datagram (#d bytes); resetting unreliable incoming queue",
|
|
message_size);
|
|
}
|
|
else if (message_size > *buffer_size)
|
|
{
|
|
error(
|
|
_error_silent,
|
|
"packet in queue is #%d bytes, but we can only handle #%d bytes!; resetting unreliable incoming queue",
|
|
message_size,
|
|
*buffer_size);
|
|
}
|
|
else if (message_size + sizeof(source_ipv4_address) <= (unsigned long)circular_queue_size(connection->unreliable_incoming_queue) &&
|
|
circular_queue_dequeue_data(connection->unreliable_incoming_queue, message, message_size, TRUE) &&
|
|
circular_queue_dequeue_data(connection->unreliable_incoming_queue, &source_ipv4_address, sizeof(source_ipv4_address), TRUE))
|
|
{
|
|
*(message_header *)message = header;
|
|
match_vassert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x3DF,
|
|
!TEST_FLAG(header, 0),
|
|
"encryption should not be active");
|
|
if (source_address)
|
|
{
|
|
source_address->address.long_words[0] = source_ipv4_address;
|
|
source_address->port = 0;
|
|
source_address->address_length = IPV4_ADDRESS_LENGTH;
|
|
}
|
|
*buffer_size = message_size;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
error(
|
|
_error_silent,
|
|
"partial datagram in queue (#%d of #%d bytes); resetting queue",
|
|
circular_queue_size(connection->unreliable_incoming_queue),
|
|
message_size);
|
|
}
|
|
circular_queue_reset(connection->unreliable_incoming_queue);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void network_connection_keep_alive(
|
|
struct network_connection *connection)
|
|
{
|
|
connection->last_keep_alive_time = system_milliseconds();
|
|
|
|
return;
|
|
}
|
|
|
|
void network_connection_delete(
|
|
struct network_connection *connection)
|
|
{
|
|
struct network_server_connection *server = (struct network_server_connection *)connection;
|
|
struct network_connection **client;
|
|
long client_index;
|
|
|
|
if (connection)
|
|
{
|
|
network_connection_log_traffic_event(
|
|
_network_connection_traffic_event_close,
|
|
TRUE,
|
|
connection);
|
|
if (connection->reliable_endpoint)
|
|
{
|
|
delete_transport_endpoint(connection->reliable_endpoint);
|
|
}
|
|
if (connection->unreliable_endpoint)
|
|
{
|
|
delete_transport_endpoint(connection->unreliable_endpoint);
|
|
}
|
|
if (connection->reliable_incoming_queue)
|
|
{
|
|
circular_queue_delete(connection->reliable_incoming_queue);
|
|
}
|
|
if (connection->unreliable_incoming_queue)
|
|
{
|
|
circular_queue_delete(connection->unreliable_incoming_queue);
|
|
}
|
|
if (TEST_FLAG(connection->flags, _connection_create_server_bit))
|
|
{
|
|
client = server->client_list;
|
|
if (client)
|
|
{
|
|
for (client_index = 0; client_index < NETWORK_CONNECTION_MAXIMUM_CLIENTS; client_index++, client++)
|
|
{
|
|
if (*client)
|
|
{
|
|
if (server->endpoint_set)
|
|
{
|
|
remove_endpoint_from_set((*client)->reliable_endpoint, server->endpoint_set);
|
|
}
|
|
network_connection_delete(*client);
|
|
}
|
|
}
|
|
}
|
|
if (server->endpoint_set)
|
|
{
|
|
delete_endpoint_set(server->endpoint_set);
|
|
}
|
|
}
|
|
match_free(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x145,
|
|
connection);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void network_server_allow_client_connections(
|
|
struct network_connection *server_connection,
|
|
boolean allow_client_connections)
|
|
{
|
|
struct network_server_connection *server = (struct network_server_connection *)server_connection;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x151,
|
|
server_connection);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x152,
|
|
server_connection->flags&FLAG(_connection_create_server_bit));
|
|
|
|
server->allow_client_connections = allow_client_connections;
|
|
|
|
return;
|
|
}
|
|
|
|
boolean network_connection_write(
|
|
struct network_connection *connection,
|
|
void *message,
|
|
word buffer_size,
|
|
struct transport_address *dest_address,
|
|
boolean reliable)
|
|
{
|
|
message_header *header = message;
|
|
long result = 0;
|
|
boolean success;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x170,
|
|
message);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x171,
|
|
buffer_size);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x172,
|
|
connection);
|
|
match_vassert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x174,
|
|
GET_MESSAGE_SIZE(*header) == buffer_size,
|
|
"bad message or buffer_size parameter");
|
|
|
|
byte_swap_message_header(header, _byte_order_network);
|
|
|
|
if (TEST_FLAG(connection->flags, _connection_create_server_bit))
|
|
{
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x17B,
|
|
!reliable);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x17C,
|
|
dest_address);
|
|
if (buffer_size > DATAGRAM_MAXIMUM_SIZE)
|
|
{
|
|
error(
|
|
_error_silent,
|
|
"buffer size was %d max is %d",
|
|
buffer_size,
|
|
DATAGRAM_MAXIMUM_SIZE);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x182,
|
|
buffer_size <= DATAGRAM_MAXIMUM_SIZE);
|
|
}
|
|
result = write_to_endpoint(
|
|
connection->unreliable_endpoint,
|
|
message,
|
|
buffer_size,
|
|
dest_address);
|
|
network_connection_log_traffic_event(
|
|
_network_connection_traffic_event_datagram_sent,
|
|
buffer_size,
|
|
connection);
|
|
}
|
|
else if (reliable)
|
|
{
|
|
long bytes_written;
|
|
|
|
match_vassert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x18E,
|
|
buffer_size <= RELIABLE_MESSAGE_MAXIMUM_SIZE,
|
|
"message size exceeds maximum allowed size");
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x190,
|
|
(connection->flags&FLAG(_connection_create_clientside_client_bit)) ||
|
|
(connection->flags&FLAG(_connection_create_serverside_client_bit)));
|
|
|
|
#ifdef HALO_LINUX
|
|
/* A stream socket may take only part of a message (the per-tick
|
|
update of 128 players is 3.9 KB): send the rest too, or the peer
|
|
loses its place in the stream. A peer that stops reading for
|
|
NETWORK_CONNECTION_WRITE_TIMEOUT is dropped rather than stalling
|
|
everyone else. */
|
|
{
|
|
long bytes_sent = 0;
|
|
unsigned long start_time = system_milliseconds();
|
|
boolean timed_out = FALSE;
|
|
|
|
bytes_written = 0;
|
|
while (bytes_sent < buffer_size)
|
|
{
|
|
long sent = write_endpoint(
|
|
connection->reliable_endpoint,
|
|
(byte *)message + bytes_sent,
|
|
buffer_size - bytes_sent);
|
|
|
|
if (sent > 0)
|
|
{
|
|
bytes_sent += sent;
|
|
}
|
|
else if (sent != _transport_result_operation_would_block)
|
|
{
|
|
bytes_written = sent < 0 ? sent : _transport_error_endpoint_io;
|
|
break;
|
|
}
|
|
else if (system_milliseconds() - start_time >= NETWORK_CONNECTION_WRITE_TIMEOUT)
|
|
{
|
|
bytes_written = _transport_error_endpoint_io;
|
|
timed_out = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (bytes_sent == buffer_size)
|
|
{
|
|
bytes_written = bytes_sent;
|
|
}
|
|
else if (bytes_sent > 0 || timed_out)
|
|
{
|
|
/* part of a message is on its way, or the peer has stopped
|
|
reading: the stream cannot recover, and going on without this
|
|
message would leave the peer out of step (a client that misses
|
|
a game update puts the whole game out of sync) */
|
|
SET_FLAG(connection->flags, _connection_closed_bit, TRUE);
|
|
}
|
|
}
|
|
#else
|
|
do
|
|
{
|
|
bytes_written = write_endpoint(
|
|
connection->reliable_endpoint,
|
|
message,
|
|
buffer_size);
|
|
}
|
|
while (bytes_written <= 0 && bytes_written == _transport_result_operation_would_block);
|
|
#endif
|
|
|
|
if (bytes_written > 0)
|
|
{
|
|
result = TRUE;
|
|
network_connection_log_traffic_event(
|
|
_network_connection_traffic_event_stream_bytes_sent,
|
|
bytes_written,
|
|
connection);
|
|
network_connection_log_traffic_event(
|
|
_network_connection_traffic_event_stream_message_sent,
|
|
TRUE,
|
|
connection);
|
|
}
|
|
else
|
|
{
|
|
error(
|
|
_error_silent,
|
|
"client call to write_endpoint() returned error '%s'",
|
|
transport_error_to_string((short)bytes_written));
|
|
}
|
|
}
|
|
else if (connection->unreliable_endpoint)
|
|
{
|
|
match_vassert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x1B0,
|
|
buffer_size <= DATAGRAM_MAXIMUM_SIZE,
|
|
"message size exceeds maximum allowed size");
|
|
if (!dest_address)
|
|
{
|
|
if ((boolean)endpoint_connected(connection->unreliable_endpoint))
|
|
{
|
|
write_endpoint(
|
|
connection->unreliable_endpoint,
|
|
message,
|
|
buffer_size);
|
|
network_connection_log_traffic_event(
|
|
_network_connection_traffic_event_datagram_sent,
|
|
buffer_size,
|
|
connection);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
write_to_endpoint(
|
|
connection->unreliable_endpoint,
|
|
message,
|
|
buffer_size,
|
|
dest_address);
|
|
network_connection_log_traffic_event(
|
|
_network_connection_traffic_event_datagram_sent,
|
|
buffer_size,
|
|
connection);
|
|
}
|
|
}
|
|
|
|
if (!reliable)
|
|
{
|
|
success = TRUE;
|
|
}
|
|
else
|
|
{
|
|
success = result > 0;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
static struct network_connection *network_connection_create_client_from_endpoint(
|
|
struct transport_endpoint *reliable_endpoint)
|
|
{
|
|
struct network_connection *connection;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x345,
|
|
reliable_endpoint);
|
|
|
|
connection = debug_malloc(
|
|
sizeof(*connection),
|
|
TRUE,
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x347);
|
|
if (connection)
|
|
{
|
|
connection->flags = FLAG(_connection_create_serverside_client_bit);
|
|
connection->reliable_endpoint = reliable_endpoint;
|
|
connection->reliable_incoming_queue = circular_queue_new(
|
|
"incoming-reliable",
|
|
0x8000);
|
|
if (!connection->reliable_incoming_queue)
|
|
{
|
|
network_connection_delete(connection);
|
|
return NULL;
|
|
}
|
|
|
|
network_connection_log_traffic_event(
|
|
_network_connection_traffic_event_open,
|
|
TRUE,
|
|
connection);
|
|
}
|
|
|
|
return connection;
|
|
}
|
|
|
|
static boolean network_connection_idle_client_reliable_endpoint(
|
|
struct network_connection *connection)
|
|
{
|
|
byte buffer[RELIABLE_MESSAGE_MAXIMUM_SIZE];
|
|
unsigned long start_time = system_milliseconds();
|
|
boolean success = TRUE;
|
|
long free_space;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x481,
|
|
connection);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x482,
|
|
connection->reliable_endpoint);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x483,
|
|
connection->reliable_incoming_queue);
|
|
|
|
free_space = circular_queue_free_space(connection->reliable_incoming_queue);
|
|
while (success && endpoint_readable(connection->reliable_endpoint, 0) && free_space > 0)
|
|
{
|
|
long bytes_read;
|
|
|
|
if (free_space >= RELIABLE_MESSAGE_MAXIMUM_SIZE)
|
|
{
|
|
free_space = RELIABLE_MESSAGE_MAXIMUM_SIZE;
|
|
}
|
|
bytes_read = read_endpoint(connection->reliable_endpoint, buffer, free_space);
|
|
if (bytes_read <= 0)
|
|
{
|
|
if (bytes_read != _transport_result_operation_would_block)
|
|
{
|
|
if (bytes_read == _transport_error_connection_lost)
|
|
{
|
|
SET_FLAG(connection->flags, _connection_closed_bit, TRUE);
|
|
}
|
|
else if (bytes_read)
|
|
{
|
|
error(
|
|
_error_silent,
|
|
"error '%s' reading from client reliable endpoint",
|
|
transport_error_to_string((short)bytes_read));
|
|
}
|
|
else
|
|
{
|
|
error(_error_silent, "client reliable connection lost");
|
|
}
|
|
success = FALSE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
connection->last_keep_alive_time = system_milliseconds();
|
|
network_connection_log_traffic_event(
|
|
_network_connection_traffic_event_stream_bytes_received,
|
|
bytes_read,
|
|
connection);
|
|
if (!circular_queue_queue_data(connection->reliable_incoming_queue, buffer, bytes_read))
|
|
{
|
|
error(_error_silent, "circular_queue_queue_data() failed");
|
|
success = FALSE;
|
|
}
|
|
free_space = circular_queue_free_space(connection->reliable_incoming_queue);
|
|
}
|
|
|
|
if (system_milliseconds() - start_time > MILLISECONDS_PER_SECOND)
|
|
{
|
|
error(_error_silent, "blocked in network_connection_idle_client_reliable_endpoint");
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
struct network_connection *network_connection_new(
|
|
unsigned long flags,
|
|
word well_known_port)
|
|
{
|
|
struct network_connection *connection = NULL;
|
|
long reliable_queue_size;
|
|
long unreliable_queue_size;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x9D,
|
|
(flags&FLAG(_connection_create_server_bit))|| (flags&FLAG(_connection_create_clientside_client_bit)));
|
|
|
|
if (TEST_FLAG(flags, _connection_create_server_bit))
|
|
{
|
|
struct network_server_connection *server;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0xA3,
|
|
well_known_port > MAXIMUM_RESERVED_NETWORK_PORT);
|
|
server = debug_malloc(
|
|
sizeof(struct network_server_connection),
|
|
TRUE,
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0xA5);
|
|
if (server)
|
|
{
|
|
server->allow_client_connections = TRUE;
|
|
server->endpoint_set = create_endpoint_set(NETWORK_CONNECTION_MAXIMUM_CLIENTS + 1);
|
|
if (server->endpoint_set)
|
|
{
|
|
connection = &server->connection;
|
|
reliable_queue_size = 0;
|
|
#ifdef HALO_LINUX
|
|
/* room for every machine's input datagrams between two idles */
|
|
unreliable_queue_size = 0x20000;
|
|
#else
|
|
unreliable_queue_size = 0x1900;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
network_connection_delete(&server->connection);
|
|
}
|
|
}
|
|
}
|
|
else if (TEST_FLAG(flags, _connection_create_clientside_client_bit))
|
|
{
|
|
connection = debug_malloc(
|
|
sizeof(struct network_connection),
|
|
TRUE,
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0xB6);
|
|
if (connection)
|
|
{
|
|
#ifdef HALO_LINUX
|
|
/* a few seconds of per-tick updates of 128 players (3.9 KB each) */
|
|
reliable_queue_size = 0x40000;
|
|
#else
|
|
reliable_queue_size = 0x8000;
|
|
#endif
|
|
unreliable_queue_size = 0x640;
|
|
}
|
|
}
|
|
|
|
if (connection)
|
|
{
|
|
boolean success = TRUE;
|
|
|
|
connection->last_keep_alive_time = system_milliseconds();
|
|
connection->flags = flags;
|
|
connection->reliable_endpoint = create_transport_endpoint(_transport_type_tcp);
|
|
if (!connection->reliable_endpoint)
|
|
{
|
|
success = FALSE;
|
|
}
|
|
|
|
if (success && TEST_FLAG(flags, _connection_create_server_bit))
|
|
{
|
|
struct transport_address server_address = {0};
|
|
|
|
server_address.address_length = IPV4_ADDRESS_LENGTH;
|
|
server_address.port = well_known_port;
|
|
if (bind_endpoint(connection->reliable_endpoint, &server_address) ||
|
|
set_endpoint_blocking(connection->reliable_endpoint, FALSE) ||
|
|
listen_endpoint(connection->reliable_endpoint) ||
|
|
add_endpoint_to_set(
|
|
connection->reliable_endpoint,
|
|
((struct network_server_connection *)connection)->endpoint_set))
|
|
{
|
|
success = FALSE;
|
|
}
|
|
}
|
|
|
|
if (success)
|
|
{
|
|
connection->unreliable_endpoint = create_transport_endpoint(_transport_type_udp);
|
|
if (!connection->unreliable_endpoint)
|
|
{
|
|
success = FALSE;
|
|
}
|
|
}
|
|
|
|
if (success)
|
|
{
|
|
struct transport_address address;
|
|
|
|
address.address_length = IPV4_ADDRESS_LENGTH;
|
|
address.address.long_words[0] = 0;
|
|
address.port = well_known_port;
|
|
connection->well_known_port = well_known_port;
|
|
if (bind_endpoint(connection->unreliable_endpoint, &address) ||
|
|
set_endpoint_blocking(connection->unreliable_endpoint, FALSE))
|
|
{
|
|
success = FALSE;
|
|
}
|
|
}
|
|
|
|
if (success && reliable_queue_size)
|
|
{
|
|
connection->reliable_incoming_queue = circular_queue_new(
|
|
"incoming-reliable",
|
|
reliable_queue_size);
|
|
if (!connection->reliable_incoming_queue)
|
|
{
|
|
success = FALSE;
|
|
}
|
|
}
|
|
|
|
if (success && unreliable_queue_size)
|
|
{
|
|
connection->unreliable_incoming_queue = circular_queue_new(
|
|
"incoming-unreliable",
|
|
unreliable_queue_size);
|
|
if (!connection->unreliable_incoming_queue)
|
|
{
|
|
success = FALSE;
|
|
}
|
|
}
|
|
|
|
if (!success)
|
|
{
|
|
network_connection_delete(connection);
|
|
connection = NULL;
|
|
}
|
|
else
|
|
{
|
|
network_connection_log_traffic_event(
|
|
_network_connection_traffic_event_open,
|
|
TRUE,
|
|
connection);
|
|
}
|
|
}
|
|
|
|
return connection;
|
|
}
|
|
|
|
static boolean network_client_reliable_connection_read(
|
|
struct network_connection *connection,
|
|
void *message,
|
|
word *buffer_size,
|
|
struct transport_address *source_address)
|
|
{
|
|
message_header header;
|
|
word message_size;
|
|
boolean success = FALSE;
|
|
boolean reset_queue = FALSE;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x371,
|
|
connection && connection->reliable_incoming_queue);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x372,
|
|
message);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x373,
|
|
buffer_size);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x374,
|
|
*buffer_size>sizeof(message_header));
|
|
|
|
if (circular_queue_dequeue_data(connection->reliable_incoming_queue, &header, sizeof(header), FALSE))
|
|
{
|
|
byte_swap_message_header(&header, _byte_order_host);
|
|
message_size = GET_MESSAGE_SIZE(header);
|
|
if (message_size > RELIABLE_MESSAGE_MAXIMUM_SIZE)
|
|
{
|
|
error(
|
|
_error_silent,
|
|
"got an unusually large message (#d bytes); resetting reliable incoming queue",
|
|
message_size);
|
|
reset_queue = TRUE;
|
|
}
|
|
else if (message_size > *buffer_size)
|
|
{
|
|
error(
|
|
_error_silent,
|
|
"packet in queue is #%d bytes, but we can only handle #%d bytes!; resetting reliable incoming queue",
|
|
message_size,
|
|
*buffer_size);
|
|
reset_queue = TRUE;
|
|
}
|
|
else if (message_size <= circular_queue_size(connection->reliable_incoming_queue) &&
|
|
circular_queue_dequeue_data(connection->reliable_incoming_queue, message, message_size, TRUE))
|
|
{
|
|
*(message_header *)message = header;
|
|
match_vassert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x394,
|
|
!TEST_FLAG(header, 0),
|
|
"encryption should not be active");
|
|
if (source_address && get_endpoint_address(connection->reliable_endpoint, source_address))
|
|
{
|
|
memset(source_address, 0, sizeof(*source_address));
|
|
source_address->address_length = IPV4_ADDRESS_LENGTH;
|
|
}
|
|
*buffer_size = message_size;
|
|
success = TRUE;
|
|
connection->stream_messages_received++;
|
|
}
|
|
|
|
if (reset_queue)
|
|
{
|
|
circular_queue_reset(connection->reliable_incoming_queue);
|
|
}
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
boolean network_connection_read(
|
|
struct network_connection *connection,
|
|
void *buffer,
|
|
word *buffer_size,
|
|
struct transport_address *source_address)
|
|
{
|
|
boolean result;
|
|
|
|
if (TEST_FLAG(connection->flags, _connection_create_server_bit))
|
|
{
|
|
return network_client_unreliable_connection_read(connection, buffer, buffer_size, source_address);
|
|
}
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x1E0,
|
|
connection->flags&FLAG(_connection_create_clientside_client_bit) ||
|
|
connection->flags&FLAG(_connection_create_serverside_client_bit));
|
|
|
|
result = network_client_reliable_connection_read(connection, buffer, buffer_size, source_address);
|
|
if (!result && TEST_FLAG(connection->flags, _connection_create_clientside_client_bit))
|
|
{
|
|
result = network_client_unreliable_connection_read(connection, buffer, buffer_size, source_address);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
boolean network_server_close_client_connection(
|
|
struct network_connection *server_connection,
|
|
struct network_connection *client_connection)
|
|
{
|
|
struct network_server_connection *server = (struct network_server_connection *)server_connection;
|
|
long client_index;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x1F7,
|
|
server_connection);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x1F8,
|
|
client_connection);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x1F9,
|
|
server_connection->flags & FLAG(_connection_create_server_bit));
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x1FA,
|
|
server->endpoint_set);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x1FB,
|
|
server->client_list);
|
|
|
|
for (client_index = 0; client_index < NETWORK_CONNECTION_MAXIMUM_CLIENTS; client_index++)
|
|
{
|
|
if (server->client_list[client_index] &&
|
|
server->client_list[client_index] == client_connection)
|
|
{
|
|
if (client_connection->reliable_endpoint &&
|
|
remove_endpoint_from_set(
|
|
server->client_list[client_index]->reliable_endpoint,
|
|
server->endpoint_set))
|
|
{
|
|
error(
|
|
_error_silent,
|
|
"failed to remove a client endpoint from the server's endpoint set (maybe it was already removed)");
|
|
}
|
|
|
|
network_connection_delete(server->client_list[client_index]);
|
|
server->client_list[client_index] = NULL;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
boolean network_connection_disconnect(
|
|
struct network_connection *connection)
|
|
{
|
|
boolean success = TRUE;
|
|
|
|
if (network_connection_connected(connection))
|
|
{
|
|
if ((connection->flags & FLAG(_connection_create_clientside_client_bit)) ||
|
|
(connection->flags & FLAG(_connection_create_serverside_client_bit)))
|
|
{
|
|
network_connection_idle_client_reliable_endpoint(connection);
|
|
}
|
|
disconnect_endpoint(connection->reliable_endpoint);
|
|
}
|
|
|
|
if (connection->unreliable_endpoint && connection->well_known_port)
|
|
{
|
|
struct transport_address address;
|
|
|
|
address.address_length = IPV4_ADDRESS_LENGTH;
|
|
address.address.ipv4_address = 0;
|
|
address.port = connection->well_known_port;
|
|
|
|
delete_transport_endpoint(connection->unreliable_endpoint);
|
|
connection->unreliable_endpoint = create_transport_endpoint(_transport_type_udp);
|
|
success = connection->unreliable_endpoint &&
|
|
(bind_endpoint(connection->unreliable_endpoint, &address) == _transport_error_none) &&
|
|
(set_endpoint_blocking(connection->unreliable_endpoint, FALSE) == _transport_error_none);
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
static boolean network_connection_idle_server_reliable_endpoint(
|
|
struct network_server_connection *connection,
|
|
struct network_connection **new_client_connection)
|
|
{
|
|
struct transport_endpoint *endpoint;
|
|
boolean success = TRUE;
|
|
short result;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x405,
|
|
connection != NULL);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x406,
|
|
connection->connection.reliable_endpoint);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x407,
|
|
connection->endpoint_set);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x408,
|
|
new_client_connection);
|
|
|
|
*new_client_connection = NULL;
|
|
result = poll_endpoint_set(connection->endpoint_set, 0);
|
|
if (result == _transport_error_none)
|
|
{
|
|
rewind_endpoint_set(connection->endpoint_set);
|
|
while (success &&
|
|
(endpoint = get_next_endpoint_from_set(connection->endpoint_set)) != NULL &&
|
|
result == _transport_error_none)
|
|
{
|
|
if (endpoint_readable(endpoint, 0))
|
|
{
|
|
if (endpoint == connection->connection.reliable_endpoint)
|
|
{
|
|
if (connection->allow_client_connections &&
|
|
count_endpoints_in_set(connection->endpoint_set) < NETWORK_CONNECTION_MAXIMUM_CLIENTS + 1)
|
|
{
|
|
struct transport_endpoint *accepted_endpoint = accept_endpoint(endpoint);
|
|
struct network_connection *client_connection = NULL;
|
|
|
|
if (accepted_endpoint &&
|
|
set_endpoint_blocking(accepted_endpoint, FALSE) == _transport_error_none)
|
|
{
|
|
client_connection = network_connection_create_client_from_endpoint(accepted_endpoint);
|
|
}
|
|
if (client_connection)
|
|
{
|
|
long client_index;
|
|
|
|
for (client_index = 0; client_index < NETWORK_CONNECTION_MAXIMUM_CLIENTS; client_index++)
|
|
{
|
|
if (!connection->client_list[client_index])
|
|
{
|
|
*new_client_connection = client_connection;
|
|
connection->client_list[client_index] = client_connection;
|
|
break;
|
|
}
|
|
}
|
|
if (client_index >= NETWORK_CONNECTION_MAXIMUM_CLIENTS)
|
|
{
|
|
error(_error_silent, "error adding new client");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
error(_error_silent, "accept_endpoint() returned NULL");
|
|
}
|
|
}
|
|
else if (connection->connection.connection_rejection_procedure)
|
|
{
|
|
struct transport_endpoint *accepted_endpoint = accept_endpoint(endpoint);
|
|
|
|
if (accepted_endpoint)
|
|
{
|
|
connection->connection.connection_rejection_procedure(accepted_endpoint);
|
|
delete_transport_endpoint(accepted_endpoint);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result = reject_endpoint(endpoint);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
long client_index;
|
|
|
|
for (client_index = 0; client_index < NETWORK_CONNECTION_MAXIMUM_CLIENTS; client_index++)
|
|
{
|
|
if (connection->client_list[client_index] &&
|
|
connection->client_list[client_index]->reliable_endpoint == endpoint)
|
|
{
|
|
success = network_connection_idle_client_reliable_endpoint(connection->client_list[client_index]);
|
|
if (!success)
|
|
{
|
|
if (remove_endpoint_from_set(
|
|
connection->client_list[client_index]->reliable_endpoint,
|
|
connection->endpoint_set) != _transport_error_none)
|
|
{
|
|
error(
|
|
_error_silent,
|
|
"failed to remove a client endpoint from the server's endpoint set");
|
|
}
|
|
SET_FLAG(connection->client_list[client_index]->flags, _connection_closed_bit, TRUE);
|
|
success = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
match_vassert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x469,
|
|
client_index < NETWORK_CONNECTION_MAXIMUM_CLIENTS,
|
|
"rogue endpoint connected to the server");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (result != _transport_result_poll_timeout)
|
|
{
|
|
error(
|
|
_error_silent,
|
|
"poll_endpoint_set() returned error '%s'",
|
|
transport_error_to_string(result));
|
|
success = FALSE;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
boolean network_connection_idle(
|
|
struct network_connection *connection,
|
|
long timeout,
|
|
struct network_connection **new_client_connection)
|
|
{
|
|
byte buffer[DATAGRAM_MAXIMUM_SIZE + sizeof(unsigned long)];
|
|
unsigned long current_time = system_milliseconds();
|
|
boolean success = TRUE;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x21D,
|
|
connection);
|
|
|
|
SET_FLAG(connection->flags, _connection_going_stale_bit, FALSE);
|
|
if (timeout)
|
|
{
|
|
if (current_time > connection->last_keep_alive_time + MILLISECONDS_PER_SECOND * 5)
|
|
{
|
|
SET_FLAG(connection->flags, _connection_going_stale_bit, TRUE);
|
|
}
|
|
if (current_time > connection->last_keep_alive_time + timeout)
|
|
{
|
|
if (global_connection_dont_timeout)
|
|
{
|
|
error(
|
|
_error_silent,
|
|
"dont timeout is active so not timing out of a connection");
|
|
connection->last_keep_alive_time = current_time;
|
|
}
|
|
else
|
|
{
|
|
error(_error_silent, "timeout in network_connection_idle");
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
connection->last_keep_alive_time = current_time;
|
|
}
|
|
|
|
if (TEST_FLAG(connection->flags, _connection_create_server_bit))
|
|
{
|
|
success = network_connection_idle_server_reliable_endpoint(
|
|
(struct network_server_connection *)connection,
|
|
new_client_connection);
|
|
if (!success)
|
|
{
|
|
error(_error_silent, "network_connection_idle_server_reliable_endpoint failed");
|
|
}
|
|
}
|
|
else if (connection->flags &
|
|
(FLAG(_connection_create_clientside_client_bit) | FLAG(_connection_create_serverside_client_bit)))
|
|
{
|
|
success = network_connection_idle_client_reliable_endpoint(connection);
|
|
if (!success)
|
|
{
|
|
error(_error_silent, "network_connection_idle_client_reliable_endpoint failed");
|
|
}
|
|
}
|
|
|
|
if (success && connection->unreliable_endpoint)
|
|
{
|
|
long free_space = circular_queue_free_space(connection->unreliable_incoming_queue);
|
|
|
|
while (success &&
|
|
free_space >= DATAGRAM_MAXIMUM_SIZE + sizeof(unsigned long))
|
|
{
|
|
struct transport_address source_address;
|
|
long buffer_size;
|
|
unsigned long source_ipv4_address;
|
|
|
|
if ((boolean)endpoint_connected(connection->unreliable_endpoint))
|
|
{
|
|
buffer_size = read_endpoint(
|
|
connection->unreliable_endpoint,
|
|
buffer,
|
|
DATAGRAM_MAXIMUM_SIZE);
|
|
if (buffer_size > 0)
|
|
{
|
|
if (get_endpoint_address(connection->unreliable_endpoint, &source_address) != _transport_error_none)
|
|
{
|
|
memset(&source_address, 0, sizeof(source_address));
|
|
source_address.address_length = IPV4_ADDRESS_LENGTH;
|
|
}
|
|
network_connection_log_traffic_event(
|
|
_network_connection_traffic_event_datagram_received,
|
|
buffer_size,
|
|
connection);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
buffer_size = read_from_endpoint(
|
|
connection->unreliable_endpoint,
|
|
buffer,
|
|
DATAGRAM_MAXIMUM_SIZE,
|
|
&source_address);
|
|
if (buffer_size > 0)
|
|
{
|
|
network_connection_log_traffic_event(
|
|
_network_connection_traffic_event_datagram_received,
|
|
buffer_size,
|
|
connection);
|
|
}
|
|
}
|
|
|
|
match_vassert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x26D,
|
|
buffer_size <= DATAGRAM_MAXIMUM_SIZE,
|
|
"endpoint read buffer overflowed");
|
|
if (buffer_size <= 0)
|
|
{
|
|
return success;
|
|
}
|
|
|
|
source_ipv4_address = source_address.address.long_words[0];
|
|
if (source_ipv4_address)
|
|
{
|
|
csmemcpy(
|
|
buffer + buffer_size,
|
|
&source_ipv4_address,
|
|
sizeof(source_ipv4_address));
|
|
buffer_size += sizeof(source_ipv4_address);
|
|
success = circular_queue_queue_data(
|
|
connection->unreliable_incoming_queue,
|
|
buffer,
|
|
buffer_size);
|
|
match_vassert(
|
|
"c:\\halo\\SOURCE\\networking\\network_connection.c",
|
|
0x279,
|
|
success,
|
|
"circular_queue_queue_data() failed though it should have had enough room");
|
|
}
|
|
else
|
|
{
|
|
error(_error_silent, "datagram received from unknown address");
|
|
}
|
|
|
|
free_space = circular_queue_free_space(connection->unreliable_incoming_queue);
|
|
}
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
/* ---------- private code */
|