You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
309 lines
10 KiB
309 lines
10 KiB
/* |
|
netchan.h - net channel abstraction layer |
|
Copyright (C) 2007 Uncle Mike |
|
|
|
This program is free software: you can redistribute it and/or modify |
|
it under the terms of the GNU General Public License as published by |
|
the Free Software Foundation, either version 3 of the License, or |
|
(at your option) any later version. |
|
|
|
This program is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
GNU General Public License for more details. |
|
*/ |
|
|
|
#ifndef NET_MSG_H |
|
#define NET_MSG_H |
|
|
|
/* |
|
========================================================== |
|
|
|
ELEMENTS COMMUNICATED ACROSS THE NET |
|
|
|
========================================================== |
|
*/ |
|
#include "crtlib.h" |
|
#include "net_buffer.h" |
|
|
|
// 0 == regular, 1 == file stream |
|
#define MAX_STREAMS 2 |
|
|
|
// flow control bytes per second limits |
|
#define MAX_RATE 100000.0f |
|
#define MIN_RATE 1000.0f |
|
|
|
// default data rate |
|
#define DEFAULT_RATE (9999.0f) |
|
|
|
// NETWORKING INFO |
|
|
|
// This is the packet payload without any header bytes (which are attached for actual sending) |
|
#define NET_MAX_PAYLOAD MAX_INIT_MSG |
|
|
|
// Theoretically maximum size of UDP-packet without header and hardware-specific data |
|
#define NET_MAX_FRAGMENT 65535 |
|
|
|
// because encoded as highpart of uint32 |
|
#define NET_MAX_BUFFER_ID 32767 |
|
|
|
// because encoded as lowpart of uint32 |
|
#define NET_MAX_BUFFERS_COUNT 32767 |
|
|
|
// This is the payload plus any header info (excluding UDP header) |
|
|
|
// Packet header is: |
|
// 4 bytes of outgoing seq |
|
// 4 bytes of incoming seq |
|
// and for each stream |
|
// { |
|
// byte (on/off) |
|
// int (fragment id) |
|
// int (startpos) |
|
// int (length) |
|
// } |
|
#define HEADER_BYTES ( 8 + MAX_STREAMS * 13 ) |
|
|
|
// Pad this to next higher 16 byte boundary |
|
// This is the largest packet that can come in/out over the wire, before processing the header |
|
// bytes will be stripped by the networking channel layer |
|
#define NET_MAX_MESSAGE PAD_NUMBER(( NET_MAX_PAYLOAD + HEADER_BYTES ), 16 ) |
|
|
|
#define MASTERSERVER_ADR "master.hl.ygg:27010" |
|
#define MASTERSERVER_ADR_TEST "master.hl.ygg:27011" |
|
#define MS_SCAN_REQUEST "1\xFF" "0.0.0.0:0\0" |
|
|
|
#define PORT_MASTER 27010 |
|
#define PORT_SERVER 27015 |
|
|
|
#define MULTIPLAYER_BACKUP 64 // how many data slots to use when in multiplayer (must be power of 2) |
|
#define SINGLEPLAYER_BACKUP 16 // same for single player |
|
#define CMD_BACKUP 64 // allow a lot of command backups for very fast systems |
|
#define CMD_MASK (CMD_BACKUP - 1) |
|
#define NUM_PACKET_ENTITIES 256 // 170 Mb for multiplayer with 32 players |
|
#define MAX_CUSTOM_BASELINES 64 |
|
#define NET_LEGACY_EXT_SPLIT (1U<<1) |
|
#define NETSPLIT_BACKUP 8 |
|
#define NETSPLIT_BACKUP_MASK (NETSPLIT_BACKUP - 1) |
|
#define NETSPLIT_HEADER_SIZE 18 |
|
|
|
#if XASH_LOW_MEMORY == 2 |
|
#undef MULTIPLAYER_BACKUP |
|
#undef SINGLEPLAYER_BACKUP |
|
#undef NUM_PACKET_ENTITIES |
|
#undef MAX_CUSTOM_BASELINES |
|
#undef NET_MAX_FRAGMENT |
|
#define MULTIPLAYER_BACKUP 4 // breaks protocol in legacy mode, new protocol status unknown |
|
#define SINGLEPLAYER_BACKUP 4 |
|
#define NUM_PACKET_ENTITIES 32 |
|
#define MAX_CUSTOM_BASELINES 8 |
|
#define NET_MAX_FRAGMENT 32768 |
|
#elif XASH_LOW_MEMORY == 1 |
|
#undef SINGLEPLAYER_BACKUP |
|
#undef NUM_PACKET_ENTITIES |
|
#undef MAX_CUSTOM_BASELINES |
|
#undef NET_MAX_FRAGMENT |
|
#define SINGLEPLAYER_BACKUP 4 |
|
#define NUM_PACKET_ENTITIES 64 |
|
#define MAX_CUSTOM_BASELINES 8 |
|
#define NET_MAX_FRAGMENT 32768 |
|
#endif |
|
|
|
typedef struct netsplit_chain_packet_s |
|
{ |
|
// bool vector |
|
uint32_t recieved_v[8]; |
|
// serial number |
|
uint32_t id; |
|
byte data[NET_MAX_PAYLOAD]; |
|
byte received; |
|
byte count; |
|
} netsplit_chain_packet_t; |
|
|
|
// raw packet format |
|
typedef struct netsplit_packet_s |
|
{ |
|
uint32_t signature; // 0xFFFFFFFE |
|
uint32_t length; |
|
uint32_t part; |
|
uint32_t id; |
|
// max 256 parts |
|
byte count; |
|
byte index; |
|
byte data[NET_MAX_PAYLOAD - NETSPLIT_HEADER_SIZE]; |
|
} netsplit_packet_t; |
|
|
|
|
|
typedef struct netsplit_s |
|
{ |
|
netsplit_chain_packet_t packets[NETSPLIT_BACKUP]; |
|
uint64_t total_received; |
|
uint64_t total_received_uncompressed; |
|
} netsplit_t; |
|
|
|
// packet splitting |
|
qboolean NetSplit_GetLong( netsplit_t *ns, netadr_t *from, byte *data, size_t *length ); |
|
|
|
|
|
/* |
|
============================================================== |
|
|
|
NET |
|
|
|
============================================================== |
|
*/ |
|
#define MAX_FLOWS 2 |
|
|
|
#define FLOW_OUTGOING 0 |
|
#define FLOW_INCOMING 1 |
|
#define MAX_LATENT 32 |
|
#define MASK_LATENT ( MAX_LATENT - 1 ) |
|
|
|
#define FRAG_NORMAL_STREAM 0 |
|
#define FRAG_FILE_STREAM 1 |
|
|
|
// message data |
|
typedef struct |
|
{ |
|
int size; // size of message sent/received |
|
double time; // time that message was sent/received |
|
} flowstats_t; |
|
|
|
typedef struct |
|
{ |
|
flowstats_t stats[MAX_LATENT]; // data for last MAX_LATENT messages |
|
int current; // current message position |
|
double nextcompute; // time when we should recompute k/sec data |
|
float kbytespersec; // average data |
|
float avgkbytespersec; |
|
int totalbytes; |
|
} flow_t; |
|
|
|
// generic fragment structure |
|
typedef struct fragbuf_s |
|
{ |
|
struct fragbuf_s *next; // next buffer in chain |
|
int bufferid; // id of this buffer |
|
sizebuf_t frag_message; // message buffer where raw data is stored |
|
byte *frag_message_buf; // the actual data sits here |
|
qboolean isfile; // is this a file buffer? |
|
qboolean isbuffer; // is this file buffer from memory ( custom decal, etc. ). |
|
qboolean iscompressed; // is compressed file, we should using filename.ztmp |
|
char filename[MAX_OSPATH]; // name of the file to save out on remote host |
|
int foffset; // offset in file from which to read data |
|
int size; // size of data to read at that offset |
|
} fragbuf_t; |
|
|
|
// Waiting list of fragbuf chains |
|
typedef struct fbufqueue_s |
|
{ |
|
struct fbufqueue_s *next; // next chain in waiting list |
|
int fragbufcount; // number of buffers in this chain |
|
fragbuf_t *fragbufs; // the actual buffers |
|
} fragbufwaiting_t; |
|
|
|
typedef enum fragsize_e |
|
{ |
|
FRAGSIZE_FRAG, |
|
FRAGSIZE_SPLIT, |
|
FRAGSIZE_UNRELIABLE |
|
} fragsize_t; |
|
|
|
// Network Connection Channel |
|
typedef struct netchan_s |
|
{ |
|
netsrc_t sock; // NS_SERVER or NS_CLIENT, depending on channel. |
|
netadr_t remote_address; // address this channel is talking to. |
|
int qport; // qport value to write when transmitting |
|
|
|
double last_received; // for timeouts |
|
double connect_time; // Usage: host.realtime - netchan.connect_time |
|
double rate; // bandwidth choke. bytes per second |
|
double cleartime; // if realtime > cleartime, free to send next packet |
|
|
|
// Sequencing variables |
|
unsigned int incoming_sequence; // increasing count of sequence numbers |
|
unsigned int incoming_acknowledged; // # of last outgoing message that has been ack'd. |
|
unsigned int incoming_reliable_acknowledged; // toggles T/F as reliable messages are received. |
|
unsigned int incoming_reliable_sequence; // single bit, maintained local |
|
unsigned int outgoing_sequence; // message we are sending to remote |
|
unsigned int reliable_sequence; // whether the message contains reliable payload, single bit |
|
unsigned int last_reliable_sequence; // outgoing sequence number of last send that had reliable data |
|
|
|
// callback to get actual framgment size |
|
void *client; |
|
int (*pfnBlockSize)( void *cl, fragsize_t mode ); |
|
|
|
// staging and holding areas |
|
sizebuf_t message; |
|
byte message_buf[NET_MAX_MESSAGE]; |
|
|
|
// reliable message buffer. |
|
// we keep adding to it until reliable is acknowledged. Then we clear it. |
|
int reliable_length; |
|
byte reliable_buf[NET_MAX_MESSAGE]; // unacked reliable message (max size for loopback connection) |
|
|
|
// Waiting list of buffered fragments to go onto queue. |
|
// Multiple outgoing buffers can be queued in succession |
|
fragbufwaiting_t *waitlist[MAX_STREAMS]; |
|
|
|
int reliable_fragment[MAX_STREAMS]; // is reliable waiting buf a fragment? |
|
uint reliable_fragid[MAX_STREAMS]; // buffer id for each waiting fragment |
|
|
|
fragbuf_t *fragbufs[MAX_STREAMS]; // the current fragment being set |
|
int fragbufcount[MAX_STREAMS]; // the total number of fragments in this stream |
|
|
|
int frag_startpos[MAX_STREAMS]; // position in outgoing buffer where frag data starts |
|
int frag_length[MAX_STREAMS]; // length of frag data in the buffer |
|
|
|
fragbuf_t *incomingbufs[MAX_STREAMS]; // incoming fragments are stored here |
|
qboolean incomingready[MAX_STREAMS]; // set to true when incoming data is ready |
|
|
|
// Only referenced by the FRAG_FILE_STREAM component |
|
char incomingfilename[MAX_OSPATH]; // Name of file being downloaded |
|
|
|
void *tempbuffer; // download file buffer |
|
int tempbuffersize; // current size |
|
|
|
// incoming and outgoing flow metrics |
|
flow_t flow[MAX_FLOWS]; |
|
|
|
// added for net_speeds |
|
size_t total_sended; |
|
size_t total_received; |
|
qboolean split; |
|
unsigned int maxpacket; |
|
unsigned int splitid; |
|
netsplit_t netsplit; |
|
} netchan_t; |
|
|
|
extern netadr_t net_from; |
|
extern netadr_t net_local; |
|
extern netadr_t net6_local; |
|
extern sizebuf_t net_message; |
|
extern byte net_message_buffer[NET_MAX_MESSAGE]; |
|
extern convar_t sv_lan; |
|
extern convar_t sv_lan_rate; |
|
extern int net_drop; |
|
|
|
void Netchan_Init( void ); |
|
void Netchan_Shutdown( void ); |
|
void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport, void *client, int (*pfnBlockSize)(void *, fragsize_t mode ) ); |
|
void Netchan_CreateFileFragmentsFromBuffer( netchan_t *chan, const char *filename, byte *pbuf, int size ); |
|
qboolean Netchan_CopyNormalFragments( netchan_t *chan, sizebuf_t *msg, size_t *length ); |
|
qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg ); |
|
void Netchan_CreateFragments( netchan_t *chan, sizebuf_t *msg ); |
|
int Netchan_CreateFileFragments( netchan_t *chan, const char *filename ); |
|
void Netchan_TransmitBits( netchan_t *chan, int lengthInBits, byte *data ); |
|
void Netchan_OutOfBand( int net_socket, netadr_t adr, int length, byte *data ); |
|
void Netchan_OutOfBandPrint( int net_socket, netadr_t adr, const char *format, ... ) _format( 3 ); |
|
qboolean Netchan_Process( netchan_t *chan, sizebuf_t *msg ); |
|
void Netchan_UpdateProgress( netchan_t *chan ); |
|
qboolean Netchan_IncomingReady( netchan_t *chan ); |
|
qboolean Netchan_CanPacket( netchan_t *chan, qboolean choke ); |
|
qboolean Netchan_IsLocal( netchan_t *chan ); |
|
void Netchan_ReportFlow( netchan_t *chan ); |
|
void Netchan_FragSend( netchan_t *chan ); |
|
void Netchan_Clear( netchan_t *chan ); |
|
|
|
#endif//NET_MSG_H
|
|
|