/* ================= CL_PacketEvent A packet has arrived from the main event loop ================= */ public void PacketEvent(Net.Packet packet) { clc.lastPacketTime = realtime; if (packet.Type == NetMessageType.OutOfBandData) { ConnectionlessPacket(packet); return; } if (state < ConnectState.CONNECTED) return; // can't be a valid sequenced packet // // packet from server // if (!IPAddress.Equals(packet.Address.Address, clc.netchan.remoteAddress.Address)) { Common.Instance.WriteLine("{0}: sequence packet without connection", packet.Address.Address.ToString()); return; } if (!NetChan_Process(clc.netchan, packet)) return; // out of order, duplicated, etc // the header is different lengths for reliable and unreliable messages int headerBytes = packet.Buffer.Position; // track the last message received so it can be returned in // client messages, allowing the server to detect a dropped // gamestate int oldpos = packet.Buffer.Position; packet.Buffer.Position = 0; clc.serverMessageSequence = packet.Buffer.ReadInt32(); packet.Buffer.Position = oldpos; clc.lastPacketTime = realtime; ParseServerMessage(packet); }
void ConnectionlessPacket(Net.Packet packet) { string s = packet.Buffer.ReadString(); string[] tokens = Commands.TokenizeString(s); Common.Instance.WriteLine("CL Packet: {0}:{1}: {2}", packet.Address.Address, packet.Address.Port, s); string c = tokens[0]; if (c.Equals("challengeResponse")) { if (state != ConnectState.CONNECTING) { Common.Instance.WriteLine("Unwanted challenge response recieved. Ignored."); return; } if (!IPAddress.Equals(clc.serverAddress.Address, packet.Address.Address)) { // This challenge response is not coming from the expected address. // Check whether we have a matching client challenge to prevent // connection hi-jacking. c = tokens[2]; if (!int.Parse(c).Equals(clc.challenge)) { Common.Instance.WriteLine("Challenge response recieved from unexpected source. Ignored."); return; } } // start sending challenge response instead of challenge request packets clc.challenge = int.Parse(tokens[1]); state = ConnectState.CHALLENGING; clc.connectPacketCount = 0; clc.connectTime = -99999; // take this address as the new server address. This allows // a server proxy to hand off connections to multiple servers clc.serverAddress = packet.Address; Common.Instance.WriteLine("Challenge response: {0}", clc.challenge); return; } // server connection if (c.Equals("connectResponse")) { if ((int)state >= (int)ConnectState.CONNECTED) { Common.Instance.WriteLine("Duplicate connect recieved. Ignored"); return; } if (state != ConnectState.CHALLENGING) { Common.Instance.WriteLine("connectResponse packet while not connecting. Ignored."); return; } if (!IPAddress.Equals(packet.Address.Address, clc.serverAddress.Address)) { Common.Instance.WriteLine("connectResponse from wrong address. Ignored"); } clc.netchan = Net.Instance.NetChan_Setup(Net.NetSource.CLIENT, packet.Address, CVars.Instance.VariableIntegerValue("net_qport")); Net.Instance.ClientConnect(packet.Address); state = ConnectState.CONNECTED; clc.lastPacketSentTime = -99999; // send first packet immediately return; } if (c.Equals("print")) { s = tokens[1]; clc.serverMessage = s; Common.Instance.WriteLine(s); return; } Common.Instance.WriteLine("Unknown connectionless packet: {0}" + s); }
void ParseServerMessage(Net.Packet packet) { // get the reliable sequence acknowledge number clc.reliableAcknowledge = packet.Buffer.ReadInt32(); if (clc.reliableAcknowledge < clc.reliableSequence - 64) { clc.reliableAcknowledge = clc.reliableSequence; } // // parse the message // NetBuffer buf = packet.Buffer; while (true) { int cmd = buf.ReadByte(); // See if this is an extension command after the EOF, which means we // got data that a legacy client should ignore. if ((cmd == (int)svc_ops_e.svc_EOF) && (buf.PeekByte() == (int)clc_ops_e.clc_extension)) { //Common.Instance.WriteLine("NET: EXTENSION"); buf.ReadByte(); // throw the svc_extension byte away. cmd = buf.ReadByte(); // something legacy clients can't do! // sometimes you get a svc_extension at end of stream...dangling // bits in the huffman decoder giving a bogus value? if (cmd == -1) cmd = (int)svc_ops_e.svc_EOF; } if (cmd == (int)svc_ops_e.svc_EOF) { // END OF MESSAGE break; } switch (cmd) { case (int)svc_ops_e.svc_serverCommand: ParseCommandString(buf); break; case (int)svc_ops_e.svc_gamestate: ParseGameState(buf); break; case (int)svc_ops_e.svc_snapshot: ParseSnapshot(buf); break; case (int)svc_ops_e.svc_download: //ParseDownload(buf); break; case (int)svc_ops_e.svc_nop: break; default: Common.Instance.Error("Illegible server message"); break; } } }
bool NetChan_Process(Net.netchan_t chan, Net.Packet packet) { bool ret = Net.Instance.NetChan_Process(chan, packet); return ret; }
public void NetChan_Transmit(Net.netchan_t chan, NetBuffer msg) { msg.Write((byte)clc_ops_e.clc_EOF); Net.Instance.NetChan_Transmit(chan, msg); }
/* ================= SV_ConnectionlessPacket A connectionless packet has four leading 0xff characters to distinguish it from a game channel. Clients that are in the game can still send connectionless packets. ================= */ void ConnectionLessPacket(Net.Packet packet) { NetBuffer buf = packet.Buffer; string data = buf.ReadString(); Common.Instance.WriteLine("SV_ConnLessPacket: {0}=>{1}", packet.Address, data); string[] tokens = Commands.TokenizeString(data); string c = tokens[0]; if (c.Equals("getchallenge")) { GetChallenge(packet.Address, tokens[1]); } else if (c.Equals("connect")) { DirectConnect(packet.Address, tokens); } }
/* ================= SV_PacketEvent A packet has arrived from the main event loop ================= */ public void PacketEvent(Net.Packet packet) { // check for connectionless packet (0xffffffff) first if (packet.Type == Lidgren.Network.NetMessageType.OutOfBandData) { ConnectionLessPacket(packet); return; } // read the qport out of the message so we can fix up // stupid address translating routers NetBuffer buf = packet.Buffer; buf.ReadInt32(); int qport = buf.ReadInt16() & 0xffff; // find which client the message is from for (int i = 0; i < clients.Count; i++) { client_t client = clients[i]; if (client.state == clientState_t.CS_FREE) continue; if (!packet.Address.Address.Equals(client.netchan.remoteAddress.Address)) continue; // it is possible to have multiple clients from a single IP // address, so they are differentiated by the qport variable if (client.netchan.qport != qport) { continue; } // the IP port can't be used to differentiate them, because // some address translating routers periodically change UDP // port assignments if (client.netchan.remoteAddress.Port != packet.Address.Port) { Common.Instance.WriteLine("PacketEvent: fixing up translation port"); client.netchan.remoteAddress.Port = packet.Address.Port; } // make sure it is a valid, in sequence packet //?? // zombie clients still need to do the Netchan_Process // to make sure they don't need to retransmit the final // reliable message, but they don't do any other processing if (client.state != clientState_t.CS_ZOMBIE) { client.lastPacketTime = time; // don't timeout ExecuteClientMessage(client, buf); } return; } // if we received a sequenced packet from an address we don't recognize, // send an out of band disconnect packet to it Net.Instance.OutOfBandMessage(Net.NetSource.SERVER, packet.Address, "disconnect"); }