aboutsummaryrefslogtreecommitdiffstats
path: root/src/jake2/qcommon/Netchan.java
diff options
context:
space:
mode:
authorHolger Zickner <[email protected]>2004-07-07 19:59:59 +0000
committerHolger Zickner <[email protected]>2004-07-07 19:59:59 +0000
commit6e23fc1074d1f0c2c2812f4c2e663f5a21a43c20 (patch)
tree46ecc6d0255c874ba4cd26dc3d0733f785019896 /src/jake2/qcommon/Netchan.java
import of Jake2 version sunrisesunrise
Diffstat (limited to 'src/jake2/qcommon/Netchan.java')
-rw-r--r--src/jake2/qcommon/Netchan.java389
1 files changed, 389 insertions, 0 deletions
diff --git a/src/jake2/qcommon/Netchan.java b/src/jake2/qcommon/Netchan.java
new file mode 100644
index 0000000..d949588
--- /dev/null
+++ b/src/jake2/qcommon/Netchan.java
@@ -0,0 +1,389 @@
+/*
+ * NetChannel.java
+ * Copyright (C) 2003
+ *
+ * $Id: Netchan.java,v 1.1 2004-07-07 19:59:32 hzi Exp $
+ */
+/*
+Copyright (C) 1997-2001 Id Software, Inc.
+
+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 2
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+package jake2.qcommon;
+
+import sun.applet.resources.MsgAppletViewer;
+import jake2.*;
+import jake2.client.*;
+import jake2.game.*;
+import jake2.render.*;
+import jake2.server.*;
+import jake2.sys.NET;
+import jake2.sys.Sys;
+import jake2.util.Lib;
+
+/**
+ * Netchan
+ */
+public final class Netchan extends SV_MAIN {
+
+ /*
+
+ packet header
+ -------------
+ 31 sequence
+ 1 does this message contains a reliable payload
+ 31 acknowledge sequence
+ 1 acknowledge receipt of even/odd message
+ 16 qport
+
+ The remote connection never knows if it missed a reliable message, the
+ local side detects that it has been dropped by seeing a sequence acknowledge
+ higher thatn the last reliable sequence, but without the correct evon/odd
+ bit for the reliable set.
+
+ If the sender notices that a reliable message has been dropped, it will be
+ retransmitted. It will not be retransmitted again until a message after
+ the retransmit has been acknowledged and the reliable still failed to get there.
+
+ if the sequence number is -1, the packet should be handled without a netcon
+
+ The reliable message can be added to at any time by doing
+ MSG_Write* (&netchan.message, <data>).
+
+ If the message buffer is overflowed, either by a single message, or by
+ multiple frames worth piling up while the last reliable transmit goes
+ unacknowledged, the netchan signals a fatal error.
+
+ Reliable messages are always placed first in a packet, then the unreliable
+ message is included if there is sufficient room.
+
+ To the receiver, there is no distinction between the reliable and unreliable
+ parts of the message, they are just processed out as a single larger message.
+
+ Illogical packet sequence numbers cause the packet to be dropped, but do
+ not kill the connection. This, combined with the tight window of valid
+ reliable acknowledgement numbers provides protection against malicious
+ address spoofing.
+
+
+ The qport field is a workaround for bad address translating routers that
+ sometimes remap the client's source port on a packet during gameplay.
+
+ If the base part of the net address matches and the qport matches, then the
+ channel matches even if the IP port differs. The IP port should be updated
+ to the new value before sending out any replies.
+
+
+ If there is no information that needs to be transfered on a given frame,
+ such as during the connection stage while waiting for the client to load,
+ then a packet only needs to be delivered if there is something in the
+ unacknowledged reliable
+ */
+
+ public static cvar_t showpackets;
+ public static cvar_t showdrop;
+ public static cvar_t qport;
+
+ //public static netadr_t net_from = new netadr_t();
+ public static sizebuf_t net_message = new sizebuf_t();
+ public static byte net_message_buffer[] = new byte[Defines.MAX_MSGLEN];
+
+ /*
+ ===============
+ Netchan_Init
+
+ ===============
+ */
+ //ok.
+ public static void Netchan_Init() {
+ long port;
+
+ // pick a port value that should be nice and random
+ port = Sys.Milliseconds() & 0xffff;
+
+ showpackets = Cvar.Get("showpackets", "0", 0);
+ showdrop = Cvar.Get("showdrop", "0", 0);
+ qport = Cvar.Get("qport", "" + port, Defines.CVAR_NOSET);
+ }
+
+ /*
+ ===============
+ Netchan_OutOfBand
+
+ Sends an out-of-band datagram
+ ================
+ */
+ //ok.
+ public static void Netchan_OutOfBand(int net_socket, netadr_t adr, int length, byte data[]) {
+ sizebuf_t send = new sizebuf_t();
+ byte send_buf[] = new byte[Defines.MAX_MSGLEN];
+
+ // write the packet header
+ SZ.Init(send, send_buf, Defines.MAX_MSGLEN);
+
+ MSG.WriteInt(send, -1); // -1 sequence means out of band
+ SZ.Write(send, data, length);
+
+ // send the datagram
+ NET.SendPacket(net_socket, send.cursize, send.data, adr);
+ }
+
+ public static void OutOfBandPrint(int net_socket, netadr_t adr, String s) {
+ Netchan_OutOfBand(net_socket, adr, s.length(), s.getBytes());
+ }
+
+ /*
+ ==============
+ Netchan_Setup
+
+ called to open a channel to a remote system
+ ==============
+ */
+ public static void Setup(int sock, netchan_t chan, netadr_t adr, int qport) {
+ //memset (chan, 0, sizeof(*chan));
+
+ chan.clear();
+ chan.sock = sock;
+ chan.remote_address = adr.copy();
+ chan.qport = qport;
+ chan.last_received = (int) Globals.curtime;
+ chan.incoming_sequence = 0;
+ chan.outgoing_sequence = 1;
+
+ SZ.Init(chan.message, chan.message_buf, chan.message_buf.length);
+ chan.message.allowoverflow = true;
+ }
+
+ /*
+ ===============
+ Netchan_CanReliable
+
+ Returns true if the last reliable message has acked
+ ================
+ */
+ public static boolean Netchan_CanReliable(netchan_t chan) {
+ if (chan.reliable_length != 0)
+ return false; // waiting for ack
+ return true;
+ }
+ // das ist richtig !!!
+ public static boolean Netchan_NeedReliable(netchan_t chan) {
+ boolean send_reliable;
+
+ // if the remote side dropped the last reliable message, resend it
+ send_reliable = false;
+
+ if (chan.incoming_acknowledged > chan.last_reliable_sequence && chan.incoming_reliable_acknowledged != chan.reliable_sequence)
+ send_reliable = true;
+
+ // if the reliable transmit buffer is empty, copy the current message out
+ if (0 == chan.reliable_length && chan.message.cursize != 0) {
+ send_reliable = true;
+ }
+
+ return send_reliable;
+ }
+
+ /*
+ ===============
+ Netchan_Transmit
+
+ tries to send an unreliable message to a connection, and handles the
+ transmition / retransmition of the reliable messages.
+
+ A 0 length will still generate a packet and deal with the reliable messages.
+ ================
+ */
+ public static void Transmit(netchan_t chan, int length, byte data[]) {
+ sizebuf_t send = new sizebuf_t();
+ byte send_buf[] = new byte[MAX_MSGLEN];
+ int send_reliable;
+ int w1, w2;
+
+ // check for message overflow
+ if (chan.message.overflowed) {
+ chan.fatal_error = true;
+ Com.Printf(NET.AdrToString(chan.remote_address) + ":Outgoing message overflow\n");
+ return;
+ }
+
+ send_reliable = Netchan_NeedReliable(chan) ? 1 : 0;
+
+ if (chan.reliable_length == 0 && chan.message.cursize != 0) {
+ Lib.memcpy(chan.reliable_buf, chan.message_buf, chan.message.cursize);
+ chan.reliable_length = chan.message.cursize;
+ chan.message.cursize = 0;
+ chan.reliable_sequence ^= 1;
+ }
+
+ // write the packet header
+ SZ.Init(send, send_buf, send_buf.length);
+
+ 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 = (int) Globals.curtime;
+
+ MSG.WriteInt(send, w1);
+ MSG.WriteInt(send, w2);
+
+ // send the qport if we are a client
+ if (chan.sock == Defines.NS_CLIENT)
+ MSG.WriteShort(send, (int) qport.value);
+
+ // copy the reliable message to the packet first
+ if (send_reliable != 0) {
+ SZ.Write(send, chan.reliable_buf, chan.reliable_length);
+ chan.last_reliable_sequence = chan.outgoing_sequence;
+ }
+
+ // add the unreliable part if space is available
+ if (send.maxsize - send.cursize >= length)
+ SZ.Write(send, data, length);
+ else
+ Com.Printf("Netchan_Transmit: dumped unreliable\n");
+
+ // send the datagram
+ NET.SendPacket(chan.sock, send.cursize, send.data, chan.remote_address);
+
+ if (showpackets.value != 0) {
+ if (send_reliable != 0)
+ Com.Printf(//"send %4i : s=%i reliable=%i ack=%i rack=%i\n"
+ "send "
+ + send.cursize
+ + " : s="
+ + (chan.outgoing_sequence - 1)
+ + " reliable="
+ + chan.reliable_sequence
+ + " ack="
+ + chan.incoming_sequence
+ + " rack="
+ + chan.incoming_reliable_sequence
+ + "\n");
+ else
+ Com.Printf(//"send %4i : s=%i ack=%i rack=%i\n"
+ "send "
+ + send.cursize
+ + " : s="
+ + (chan.outgoing_sequence - 1)
+ + " ack="
+ + chan.incoming_sequence
+ + " rack="
+ + chan.incoming_reliable_sequence
+ + "\n");
+ }
+ }
+
+ /*
+ =================
+ Netchan_Process
+
+ called when the current net_message is from remote_address
+ modifies net_message so that it points to the packet payload
+ =================
+ */
+ public static boolean Process(netchan_t chan, sizebuf_t msg) {
+ int sequence, sequence_ack;
+ int reliable_ack, reliable_message;
+ int qport;
+
+ // get sequence numbers
+ MSG.BeginReading(msg);
+ sequence = MSG.ReadLong(msg);
+ sequence_ack = MSG.ReadLong(msg);
+
+ // read the qport if we are a server
+ if (chan.sock == NS_SERVER)
+ qport = MSG.ReadShort(msg);
+
+ // achtung unsigned int
+ reliable_message = sequence >>> 31;
+ reliable_ack = sequence_ack >>> 31;
+
+ sequence &= ~(1 << 31);
+ sequence_ack &= ~(1 << 31);
+
+ if (showpackets.value != 0) {
+ if (reliable_message != 0)
+ Com.Printf(//"recv %4i : s=%i reliable=%i ack=%i rack=%i\n"
+ "recv "
+ + msg.cursize
+ + " : s="
+ + sequence
+ + " reliable="
+ + (chan.incoming_reliable_sequence ^ 1)
+ + " ack="
+ + sequence_ack
+ + " rack="
+ + reliable_ack
+ + "\n");
+ else
+ Com.Printf(//"recv %4i : s=%i ack=%i rack=%i\n"
+ "recv " + msg.cursize + " : s=" + sequence + " ack=" + sequence_ack + " rack=" + reliable_ack + "\n");
+ }
+
+ //
+ // discard stale or duplicated packets
+ //
+ if (sequence <= chan.incoming_sequence) {
+ if (showdrop.value != 0)
+ Com.Printf(
+ NET.AdrToString(chan.remote_address)
+ + ":Out of order packet "
+ + sequence
+ + " at "
+ + chan.incoming_sequence
+ + "\n");
+ return false;
+ }
+
+ //
+ // dropped packets don't keep the message from being used
+ //
+ chan.dropped = sequence - (chan.incoming_sequence + 1);
+ if (chan.dropped > 0) {
+ if (showdrop.value != 0)
+ Com.Printf(NET.AdrToString(chan.remote_address) + ":Dropped " + chan.dropped + " packets at " + sequence + "\n");
+ }
+
+ //
+ // if the current outgoing reliable message has been acknowledged
+ // clear the buffer to make way for the next
+ //
+ if (reliable_ack == chan.reliable_sequence)
+ chan.reliable_length = 0; // it has been received
+
+ //
+ // if this message contains a reliable message, bump incoming_reliable_sequence
+ //
+ chan.incoming_sequence = sequence;
+ chan.incoming_acknowledged = sequence_ack;
+ chan.incoming_reliable_acknowledged = reliable_ack;
+ if (reliable_message != 0) {
+ chan.incoming_reliable_sequence ^= 1;
+ }
+
+ //
+ // the message can now be read from the current message pointer
+ //
+ chan.last_received = (int) Globals.curtime;
+
+ return true;
+ }
+
+}