#include "qcommon.h"
cvar_t *showpackets;
cvar_t *showdrop;
cvar_t *qport;
netadr_t net_from;
sizebuf_t net_message;
byte net_message_buffer[MAX_MSGLEN];
void Netchan_Init(void) {
int port;
port = Sys_Milliseconds() & 0xffff;
showpackets = Cvar_Get("showpackets", "0", 0);
showdrop = Cvar_Get("showdrop", "0", 0);
qport = Cvar_Get("qport", va("%i", port), CVAR_NOSET);
}
void Netchan_OutOfBand(int net_socket, netadr_t adr, int length, byte *data) {
sizebuf_t send;
byte send_buf[MAX_MSGLEN];
SZ_Init(&send, send_buf, sizeof(send_buf));
MSG_WriteLong(&send, -1); SZ_Write(&send, data, length);
NET_SendPacket(net_socket, send.cursize, send.data, adr);
}
void Netchan_OutOfBandPrint(int net_socket, netadr_t adr, char *format, ...) {
va_list argptr;
static char string[MAX_MSGLEN - 4];
va_start(argptr, format);
vsprintf(string, sizeof(string), format, argptr);
va_end(argptr);
Netchan_OutOfBand(net_socket, adr, strlen(string), (byte *)string);
}
void Netchan_Setup(netsrc_t sock, netchan_t *chan, netadr_t adr, int qport) {
memset(chan, 0, sizeof(*chan));
chan->sock = sock;
chan->remote_address = adr;
chan->qport = qport;
chan->last_received = curtime;
chan->incoming_sequence = 0;
chan->outgoing_sequence = 1;
SZ_Init(&chan->message, chan->message_buf, sizeof(chan->message_buf));
chan->message.allowoverflow = true;
}
bool Netchan_CanReliable(netchan_t *chan) {
if(chan->reliable_length)
return false; return true;
}
bool Netchan_NeedReliable(netchan_t *chan) {
bool send_reliable;
send_reliable = false;
if(chan->incoming_acknowledged > chan->last_reliable_sequence &&
chan->incoming_reliable_acknowledged != chan->reliable_sequence)
send_reliable = true;
if(!chan->reliable_length && chan->message.cursize) {
send_reliable = true;
}
return send_reliable;
}
void Netchan_Transmit(netchan_t *chan, int length, byte *data) {
sizebuf_t send;
byte send_buf[MAX_MSGLEN];
bool send_reliable;
unsigned w1, w2;
if(chan->message.overflowed) {
chan->fatal_error = true;
Com_Printf("%s:Outgoing message overflow\n", NET_AdrToString(chan->remote_address));
return;
}
send_reliable = Netchan_NeedReliable(chan);
if(!chan->reliable_length && chan->message.cursize) {
memcpy(chan->reliable_buf, chan->message_buf, chan->message.cursize);
chan->reliable_length = chan->message.cursize;
chan->message.cursize = 0;
chan->reliable_sequence ^= 1;
}
SZ_Init(&send, send_buf, sizeof(send_buf));
w1 = (chan->outgoing_sequence & ~(1 << 31)) | (send_reliable << 31);
w2 = (chan->incoming_sequence & ~(1 << 31)) | (chan->incoming_reliable_sequence << 31);
chan->outgoing_sequence++;
chan->last_sent = curtime;
MSG_WriteLong(&send, w1);
MSG_WriteLong(&send, w2);
if(chan->sock == NS_CLIENT)
MSG_WriteShort(&send, qport->value);
if(send_reliable) {
SZ_Write(&send, chan->reliable_buf, chan->reliable_length);
chan->last_reliable_sequence = chan->outgoing_sequence;
}
if(send.maxsize - send.cursize >= length)
SZ_Write(&send, data, length);
else
Com_Printf("Netchan_Transmit: dumped unreliable\n");
NET_SendPacket(chan->sock, send.cursize, send.data, chan->remote_address);
if(showpackets->value) {
if(send_reliable)
Com_Printf("send %4i : s=%i reliable=%i ack=%i rack=%i\n", send.cursize, chan->outgoing_sequence - 1,
chan->reliable_sequence, chan->incoming_sequence, chan->incoming_reliable_sequence);
else
Com_Printf("send %4i : s=%i ack=%i rack=%i\n", send.cursize, chan->outgoing_sequence - 1, chan->incoming_sequence,
chan->incoming_reliable_sequence);
}
}
bool Netchan_Process(netchan_t *chan, sizebuf_t *msg) {
unsigned sequence, sequence_ack;
unsigned reliable_ack, reliable_message;
int qport;
MSG_BeginReading(msg);
sequence = MSG_ReadLong(msg);
sequence_ack = MSG_ReadLong(msg);
if(chan->sock == NS_SERVER)
qport = MSG_ReadShort(msg);
(void)qport;
reliable_message = sequence >> 31;
reliable_ack = sequence_ack >> 31;
sequence &= ~(1 << 31);
sequence_ack &= ~(1 << 31);
if(showpackets->value) {
if(reliable_message)
Com_Printf("recv %4i : s=%i reliable=%i ack=%i rack=%i\n", msg->cursize, sequence,
chan->incoming_reliable_sequence ^ 1, sequence_ack, reliable_ack);
else
Com_Printf("recv %4i : s=%i ack=%i rack=%i\n", msg->cursize, sequence, sequence_ack, reliable_ack);
}
if(sequence <= chan->incoming_sequence) {
if(showdrop->value)
Com_Printf("%s:Out of order packet %i at %i\n", NET_AdrToString(chan->remote_address), sequence,
chan->incoming_sequence);
return false;
}
chan->dropped = sequence - (chan->incoming_sequence + 1);
if(chan->dropped > 0) {
if(showdrop->value)
Com_Printf("%s:Dropped %i packets at %i\n", NET_AdrToString(chan->remote_address), chan->dropped, sequence);
}
if(reliable_ack == chan->reliable_sequence)
chan->reliable_length = 0;
chan->incoming_sequence = sequence;
chan->incoming_acknowledged = sequence_ack;
chan->incoming_reliable_acknowledged = reliable_ack;
if(reliable_message) {
chan->incoming_reliable_sequence ^= 1;
}
chan->last_received = curtime;
return true;
}