diff options
author | Rene Stoeckel <[email protected]> | 2004-09-22 19:22:16 +0000 |
---|---|---|
committer | Rene Stoeckel <[email protected]> | 2004-09-22 19:22:16 +0000 |
commit | c4fcffe436fbfb5b0f3b7be2e5ee103ec74932f7 (patch) | |
tree | 7c9439ab1d9f5a4fd61bd57c755069007b23e0b6 /src/jake2/qcommon/Netchan.java | |
parent | bcb4ac6eefb425d5b0a90009da506361d5739e75 (diff) |
major refactoring in game, server and client package
Diffstat (limited to 'src/jake2/qcommon/Netchan.java')
-rw-r--r-- | src/jake2/qcommon/Netchan.java | 707 |
1 files changed, 346 insertions, 361 deletions
diff --git a/src/jake2/qcommon/Netchan.java b/src/jake2/qcommon/Netchan.java index 3331646..458bcbd 100644 --- a/src/jake2/qcommon/Netchan.java +++ b/src/jake2/qcommon/Netchan.java @@ -2,27 +2,27 @@ * NetChannel.java * Copyright (C) 2003 * - * $Id: Netchan.java,v 1.3 2004-07-12 20:47:00 hzi Exp $ + * $Id: Netchan.java,v 1.4 2004-09-22 19:22:09 salomo Exp $ */ /* -Copyright (C) 1997-2001 Id Software, Inc. + 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 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. + 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. + 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. + 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 jake2.Defines; @@ -37,350 +37,335 @@ import jake2.sys.Sys; */ 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.set(adr); - chan.qport = qport; - chan.last_received = 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) { - System.arraycopy(chan.message_buf, 0, chan.reliable_buf, 0, 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; - } - -} + /* + * + * 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.set(adr); + chan.qport = qport; + chan.last_received = 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[Defines.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) { + System.arraycopy(chan.message_buf, 0, chan.reliable_buf, 0, + 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 == Defines.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; + } +}
\ No newline at end of file |