📄 packetfactory.cs
字号:
// PacketFactory.cs// Copyright (C) 2002 Matt Zyzik (www.FileScope.com)// // 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 USAusing System;using System.Net;using System.Text;using System.Collections;using ICSharpCode.SharpZipLib.Zip.Compression;namespace FileScope.Gnutella2{ /* * anything involving crafting packets for departure is done in PacketFactory.cs * reading packets should be totally OOP-based to allow clean & easy & flexible processing * when crafting packets, we care less about flexibility, and more about speed * there are static packets that are cached, packets that are part cached, and totally dynamic packets * all of these forms are covered and dealt with in this file */ /// <summary> /// Encapsulate all outgoing G2 root packets. /// Many subclasses representing packet types will inherit from this class. /// </summary> public abstract class OMessage { /// <summary> /// Set the llen in the control byte. /// </summary> public static void Setllen(byte[] byt, int loc, int llen) { byt[loc] = 0x00; byt[loc] |= (byte)(llen << 6); } /// <summary> /// Set the nlen in the control byte. /// </summary> public static void Setnlen(byte[] byt, int loc, int nlen) { byt[loc] |= (byte)((nlen-1) << 3); } /// <summary> /// Set the CF and BE flags in the control byte. /// </summary> public static void SetRest(byte[] byt, int loc, bool children) { if(children) byt[loc] |= 0x04; if(!Stats.Updated.le) byt[loc] |= 0x02; } public abstract bool FillSendBuff(Sck sck, ref int buffIndex); /// <summary> /// If the OMessage subclass doesn't have a custom way of filling the send buffer, it should use this routine. /// Hopefully the JITer will inline this function. /// pckt is copied into sck.sendBuff /// </summary> public static bool StandardFill(Sck sck, ref int buffIndex, byte[] pckt) { int lenLeft = sck.sendBuff.Length - buffIndex; if(pckt.Length > lenLeft) { if(buffIndex == 0) sck.sendBuff = new byte[pckt.Length]; else return false; } Array.Copy(pckt, 0, sck.sendBuff, buffIndex, pckt.Length); buffIndex += pckt.Length; return true; } /// <summary>
/// If sameArrayRefIfTooBig is false, the contents of pckt will be copied into sck.sendBuff.
/// If sameArrayRefIfTooBig is true, sck.sendBuff will be set to pckt.
/// </summary> public static bool StandardFill(Sck sck, ref int buffIndex, byte[] pckt, bool sameArrayRefIfTooBig) { int lenLeft = sck.sendBuff.Length - buffIndex; if(pckt.Length > lenLeft) { if(buffIndex == 0) { if(sameArrayRefIfTooBig) { sck.sendBuff = pckt; buffIndex += pckt.Length; return true; } else sck.sendBuff = new byte[pckt.Length]; } else return false; } Array.Copy(pckt, 0, sck.sendBuff, buffIndex, pckt.Length); buffIndex += pckt.Length; return true; } /// <summary>
/// pckt will be copied into sck.sendBuff.
/// </summary> public static bool StandardFill(Sck sck, ref int buffIndex, byte[] pckt, int pcktLen) { int lenLeft = sck.sendBuff.Length - buffIndex; if(pcktLen > lenLeft) { if(buffIndex == 0) sck.sendBuff = new byte[pcktLen]; else return false; } Array.Copy(pckt, 0, sck.sendBuff, buffIndex, pcktLen); buffIndex += pcktLen; return true; } /// <summary> /// Just find out if the packet can fit. /// </summary> public static bool CanFit(Sck sck, ref int buffIndex, int len) { if(len > (sck.sendBuff.Length - buffIndex)) { if(buffIndex == 0) sck.sendBuff = new byte[len]; else return false; } return true; } } /// <summary> /// Any OMessage aiming to be sent over a udp medium must implement this interface. /// </summary> public interface IUdpMessage { void SetupUdpPacket(OutgoingPacket op); } public class OHandshake : OMessage { public string handshake = ""; public override bool FillSendBuff(Sck sck, ref int buffIndex) { if(CanFit(sck, ref buffIndex, handshake.Length)) { Encoding.ASCII.GetBytes(handshake, 0, handshake.Length, sck.sendBuff, buffIndex); buffIndex += handshake.Length; return true; } else return false; } } public class OKeepAlivePing : OMessage, IUdpMessage { public static byte[] pckt = null; public void SetupUdpPacket(OutgoingPacket op) { CreatePacket(); byte[] udpPckt = new byte[pckt.Length+8]; Array.Copy(pckt, 0, udpPckt, 8, pckt.Length); op.deflate = false; //whatever byte[] op.pcktData is set to shouldn't be static because doing so is dangerous op.pcktData = udpPckt; op.acks = null; op.parts = new BitArray(UDPSR.GetPartCount(udpPckt.Length-8), false); op.len = udpPckt.Length-8; } public override bool FillSendBuff(Sck sck, ref int buffIndex) { CreatePacket(); return OMessage.StandardFill(sck, ref buffIndex, pckt); } void CreatePacket() { if(pckt == null) { pckt = new byte[1+2]; Setllen(pckt, 0, 0); Setnlen(pckt, 0, 2); SetRest(pckt, 0, false); pckt[1] = (byte)'P'; pckt[2] = (byte)'I'; } } } public class OUdpPing : OMessage { public static byte[] pckt = new byte[0]; public byte[] endpoint = new byte[6]; public override bool FillSendBuff(Sck sck, ref int buffIndex) { lock(pckt) { if(pckt.Length == 0) { pckt = new byte[1+1+2 + 1+1+3+6]; Setllen(pckt, 0, 1); Setnlen(pckt, 0, 2); SetRest(pckt, 0, true); Endian.VarBytesFromInt(pckt, 1, pckt.Length-4, 1); pckt[2] = (byte)'P'; pckt[3] = (byte)'I'; Setllen(pckt, 4, 1); Setnlen(pckt, 4, 3); SetRest(pckt, 4, false); Endian.VarBytesFromInt(pckt, 5, 6, 1); pckt[6] = (byte)'U'; pckt[7] = (byte)'D'; pckt[8] = (byte)'P'; //[endpoint] } Array.Copy(this.endpoint, 0, pckt, 9, 6); return OMessage.StandardFill(sck, ref buffIndex, pckt); } } } public class OUdpPingRelay : OMessage { public static byte[] pckt = new byte[0]; public byte[] endpoint = new byte[6]; public override bool FillSendBuff(Sck sck, ref int buffIndex) { lock(pckt) { if(pckt.Length == 0) { pckt = new byte[1+1+2 + 1+1+3+6 + 1+5]; Setllen(pckt, 0, 1); Setnlen(pckt, 0, 2); SetRest(pckt, 0, true); Endian.VarBytesFromInt(pckt, 1, pckt.Length-4, 1); pckt[2] = (byte)'P'; pckt[3] = (byte)'I'; Setllen(pckt, 4, 1); Setnlen(pckt, 4, 3); SetRest(pckt, 4, false); Endian.VarBytesFromInt(pckt, 5, 6, 1); pckt[6] = (byte)'U'; pckt[7] = (byte)'D'; pckt[8] = (byte)'P'; //[endpoint] Setllen(pckt, 15, 0); Setnlen(pckt, 15, 5); SetRest(pckt, 15, false); pckt[16] = (byte)'R'; pckt[17] = (byte)'E'; pckt[18] = (byte)'L'; pckt[19] = (byte)'A'; pckt[20] = (byte)'Y'; } Array.Copy(this.endpoint, 0, pckt, 9, 6); return OMessage.StandardFill(sck, ref buffIndex, pckt); } } } public class OPong : OMessage, IUdpMessage { public static byte[] pckt = null; public override bool FillSendBuff(Sck sck, ref int buffIndex) { CreatePacket(); return OMessage.StandardFill(sck, ref buffIndex, pckt); } public void SetupUdpPacket(OutgoingPacket op) { CreatePacket(); byte[] udpPckt = new byte[pckt.Length+8]; Array.Copy(pckt, 0, udpPckt, 8, pckt.Length); op.deflate = false; op.pcktData = udpPckt; op.acks = null; op.parts = new BitArray(UDPSR.GetPartCount(udpPckt.Length-8), false); op.len = udpPckt.Length-8; } void CreatePacket() { if(pckt == null) { pckt = new byte[1+2]; Setllen(pckt, 0, 0); Setnlen(pckt, 0, 2); SetRest(pckt, 0, false); pckt[1] = (byte)'P'; pckt[2] = (byte)'O'; } } } public class OPongRelay : OMessage, IUdpMessage { public static byte[] pckt = null; public override bool FillSendBuff(Sck sck, ref int buffIndex) { CreatePacket(); return OMessage.StandardFill(sck, ref buffIndex, pckt); } public void SetupUdpPacket(OutgoingPacket op) { CreatePacket(); byte[] udpPckt = new byte[pckt.Length+8]; Array.Copy(pckt, 0, udpPckt, 8, pckt.Length); op.deflate = false; op.pcktData = udpPckt; op.acks = null; op.parts = new BitArray(UDPSR.GetPartCount(udpPckt.Length-8), false); op.len = udpPckt.Length-8; } void CreatePacket() { if(pckt == null) { pckt = new byte[1+1+2 + 1+5]; Setllen(pckt, 0, 1); Setnlen(pckt, 0, 2); SetRest(pckt, 0, true); Endian.VarBytesFromInt(pckt, 1, pckt.Length-4, 1); pckt[2] = (byte)'P'; pckt[3] = (byte)'O'; Setllen(pckt, 4, 0); Setnlen(pckt, 4, 5); SetRest(pckt, 4, false); pckt[5] = (byte)'R'; pckt[6] = (byte)'E'; pckt[7] = (byte)'L'; pckt[8] = (byte)'A'; pckt[9] = (byte)'Y'; } } } public class OLNI : OMessage { public static byte[] pckt = new byte[0]; public override bool FillSendBuff(Sck sck, ref int buffIndex) { lock(pckt) { if(pckt.Length == 0) { pckt = new byte[1+1+3 + 1+1+2+6 + 1+1+2+16 + 1+1+1+4 + 1+1+2+8 + 1+1+2+4]; Setllen(pckt, 0, 1); Setnlen(pckt, 0, 3); SetRest(pckt, 0, true); //[len] pckt[2] = (byte)'L'; pckt[3] = (byte)'N'; pckt[4] = (byte)'I'; Setllen(pckt, 5, 1); Setnlen(pckt, 5, 2); SetRest(pckt, 5, false); Endian.VarBytesFromInt(pckt, 6, 6, 1); pckt[7] = (byte)'N'; pckt[8] = (byte)'A'; //[endpoint] Setllen(pckt, 15, 1); Setnlen(pckt, 15, 2); SetRest(pckt, 15, false); Endian.VarBytesFromInt(pckt, 16, 16, 1); pckt[17] = (byte)'G'; pckt[18] = (byte)'U'; Array.Copy(Stats.settings.myGUID, 0, pckt, 19, 16); Setllen(pckt, 35, 1); Setnlen(pckt, 35, 1); SetRest(pckt, 35, false); Endian.VarBytesFromInt(pckt, 36, 4, 1); pckt[37] = (byte)'V'; pckt[38] = (byte)'F'; pckt[39] = (byte)'S'; pckt[40] = (byte)'C'; pckt[41] = (byte)'P'; Setllen(pckt, 42, 1); Setnlen(pckt, 42, 2); SetRest(pckt, 42, false); Endian.VarBytesFromInt(pckt, 43, 8, 1); pckt[44] = (byte)'L'; pckt[45] = (byte)'S'; //[library status (8)] Setllen(pckt, 54, 1); Setnlen(pckt, 54, 2); SetRest(pckt, 54, false); Endian.VarBytesFromInt(pckt, 55, 4, 1); pckt[56] = (byte)'H'; pckt[57] = (byte)'S'; //[hub status (4)] } int pcktLen; if(Stats.Updated.Gnutella2.ultrapeer) { pcktLen = pckt.Length; //library status uint filesTotal = (uint)Stats.Updated.filesShared; uint kbTotal = (uint)Stats.Updated.kbShared; foreach(Sck elsck in Sck.scks) if(elsck != null) if(elsck.mode == G2Mode.Leaf) { filesTotal += elsck.numFiles; kbTotal += elsck.numKB; } Array.Copy(Endian.GetBytes(filesTotal, !Stats.Updated.le), 0, pckt, 46, 4); Array.Copy(Endian.GetBytes(kbTotal, !Stats.Updated.le), 0, pckt, 50, 4); //hub status Array.Copy(Endian.GetBytes((ushort)ConnectionManager.leaves.Count, !Stats.Updated.le), 0, pckt, 58, 2); Array.Copy(Endian.GetBytes((ushort)Stats.settings.gConnectionsToKeep, !Stats.Updated.le), 0, pckt, 60, 2); } else { pcktLen = pckt.Length - 8; //library status Array.Copy(Endian.GetBytes(Stats.Updated.filesShared, !Stats.Updated.le), 0, pckt, 46, 4); Array.Copy(Endian.GetBytes(Stats.Updated.kbShared, !Stats.Updated.le), 0, pckt, 50, 4); } Endian.VarBytesFromInt(pckt, 1, pcktLen-5, 1); Array.Copy(Endian.BigEndianIP(Stats.settings.ipAddress), 0, pckt, 9, 4); Array.Copy(Endian.GetBytes((ushort)Stats.settings.port, !Stats.Updated.le), 0, pckt, 13, 2); return OMessage.StandardFill(sck, ref buffIndex, pckt, pcktLen); } } } public class OKHL : OMessage { int chCount; public override bool FillSendBuff(Sck sck, ref int buffIndex) { lock(HostCache.recentHubs) { int total = SizeTimestamp()+SizeNHs()+SizeCHs(); int numBytesLen = Endian.NumBytesFromInt(total); if(!OMessage.CanFit(sck, ref buffIndex, 1+numBytesLen+3+total)) return false; Setllen(sck.sendBuff, buffIndex, numBytesLen); Setnlen(sck.sendBuff, buffIndex, 3); SetRest(sck.sendBuff, buffIndex, true); buffIndex++; Endian.VarBytesFromInt(sck.sendBuff, buffIndex, total, numBytesLen); buffIndex += numBytesLen; sck.sendBuff[buffIndex] = (byte)'K'; buffIndex++; sck.sendBuff[buffIndex] = (byte)'H'; buffIndex++; sck.sendBuff[buffIndex] = (byte)'L'; buffIndex++; //timestamp Setllen(sck.sendBuff, buffIndex, 1); Setnlen(sck.sendBuff, buffIndex, 2); SetRest(sck.sendBuff, buffIndex, false); buffIndex++; Endian.VarBytesFromInt(sck.sendBuff, buffIndex, 4, 1); buffIndex++; sck.sendBuff[buffIndex] = (byte)'T'; buffIndex++; sck.sendBuff[buffIndex] = (byte)'S'; buffIndex++; Array.Copy(Endian.GetBytes(Stats.Updated.timestamp, !Stats.Updated.le), 0, sck.sendBuff, buffIndex, 4); buffIndex += 4; //neighboring hubs for(int x = 0; x < ConnectionManager.ultrapeers.Count; x++) { Setllen(sck.sendBuff, buffIndex, 1); Setnlen(sck.sendBuff, buffIndex, 2); SetRest(sck.sendBuff, buffIndex, false); buffIndex++; Endian.VarBytesFromInt(sck.sendBuff, buffIndex, 6, 1); buffIndex++; sck.sendBuff[buffIndex] = (byte)'N'; buffIndex++; sck.sendBuff[buffIndex] = (byte)'H'; buffIndex++; Array.Copy(Endian.GetBytes(Sck.scks[((ConnectionManager.G2Host)ConnectionManager.ultrapeers.GetKey(x)).sockNum].remoteIPA), 0, sck.sendBuff, buffIndex, 4); buffIndex += 4; Array.Copy(Endian.GetBytes((ushort)Sck.scks[((ConnectionManager.G2Host)ConnectionManager.ultrapeers.GetKey(x)).sockNum].port, !Stats.Updated.le), 0, sck.sendBuff, buffIndex, 2); buffIndex += 2; } //cached hubs int pos = GUID.rand.Next(0, HostCache.recentHubs.Count); while(this.chCount > 0) { Setllen(sck.sendBuff, buffIndex, 1); Setnlen(sck.sendBuff, buffIndex, 2); SetRest(sck.sendBuff, buffIndex, false); buffIndex++; Endian.VarBytesFromInt(sck.sendBuff, buffIndex, 10, 1); buffIndex++; sck.sendBuff[buffIndex] = (byte)'C'; buffIndex++; sck.sendBuff[buffIndex] = (byte)'H'; buffIndex++; Array.Copy(Endian.GetBytes((IPAddress)HostCache.recentHubs.GetKey(pos)), 0, sck.sendBuff, buffIndex, 4); buffIndex += 4; Array.Copy(Endian.GetBytes(((HubInfo)HostCache.recentHubs.GetByIndex(pos)).port, !Stats.Updated.le), 0, sck.sendBuff, buffIndex, 2); buffIndex += 2; Array.Copy(Endian.GetBytes(Stats.Updated.timestamp - ((HubInfo)HostCache.recentHubs.GetByIndex(pos)).timeKnown, !Stats.Updated.le), 0, sck.sendBuff, buffIndex, 4); buffIndex += 4; pos++; if(pos == HostCache.recentHubs.Count) pos = 0; this.chCount--; } return true; } } int SizeTimestamp() { return (1+1+2+4); } int SizeNHs() { int eachNH = 1+1+2+6;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -