📄 messages.cs
字号:
// Messages.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.Collections;using System.Text;using System.Net;using System.Net.Sockets;namespace FileScope.Gnutella2{ /// <summary> /// Holds shared member variables used in Message and Child classes. /// Also contains the Read function which sets up children and finds the starting point of the payload. /// </summary> public abstract class G2Packet { public bool cf; //compound flag; signifies child packets public int payLen; //length of the payload of this packet public Child children = null; //linked list of children that are mine public Child nextChild = null; //linked list of children that are my parent's public Message root = null; //store a reference to the root packet /// <summary> /// Iterate through all children and determine the beginning location of this packet's payload. /// </summary> public void Read(int buffIndex) { int start = buffIndex; //if we have any child packets if(this.cf) { Child curChild = null; while((start+this.payLen) - buffIndex > 0) { //if there is payload following children, a null byte terminates the set of children if(root.inPayload[buffIndex] == 0x00) { buffIndex++; break; } //control byte int llen = (int)root.inPayload[buffIndex] >> 6; int nlen = ((int)(root.inPayload[buffIndex] & 0x38) >> 3) + 1; buffIndex += 1+llen; //name string name = Encoding.ASCII.GetString(root.inPayload, buffIndex, nlen); if(curChild == null) { //start the linked list children = this.ChildType(ref name); curChild = children; } else { //continue the linked list curChild.nextChild = this.ChildType(ref name); curChild = curChild.nextChild; }#if DEBUG if(curChild.GetType() == typeof(UnknownChild)) {// if(name != "G1" && name != "NOG1" && name != "BH" && name != "UNSTA" && name != "SS")// System.Diagnostics.Debug.WriteLine("unknown G2 child: " + this.GetType().ToString() + "/" + name); }#endif //ref to root curChild.root = root; buffIndex += nlen; curChild.offset = buffIndex; //length if(llen == 0) curChild.payLen = 0; else curChild.payLen = Endian.VarBytesToInt(root.inPayload, buffIndex-(llen+nlen), llen, root.be); //more of control byte curChild.cf = ((root.inPayload[buffIndex-(llen+nlen+1)] & 0x04) == 0x04); //shareaza bug if(curChild.payLen == 10 && curChild.cf && name == "CH") curChild.cf = false; buffIndex += curChild.payLen; } } //process the payload Process(buffIndex, (start+this.payLen) - buffIndex); } public abstract void Process(int offset, int len); public virtual Child ChildType(ref string name) { return new UnknownChild(ref name); } } /// <summary> /// Message is for encapsulating root packets in the Gnutella2 format. /// It is also the base class of many subclasses representing the different root packet types. /// </summary> public abstract class Message : G2Packet { public int sockNum; //store where this message came from public IPEndPoint ipep = null; //store where this message came from (if not over tcp) public bool be; //big endian? public byte[] inPayload = null; //payload of the entire root packet (including children / sub-children) /// <summary> /// Incoming Message. /// </summary> public void GetMsg(Sck sck) { this.root = this; this.sockNum = sck.sockNum; int bytesRec; //fill payload if(this.payLen > 0) { this.inPayload = new byte[this.payLen]; bytesRec = sck.ReceiveData(this.inPayload, 0, this.payLen); if(bytesRec == 0) { sck.Disconnect("nethin' received (G2) GetMsg"); return; } } } /// <summary> /// Incoming UDP Message. /// </summary> public void GetMsg(IncomingPacket udpip) { this.root = this; this.sockNum = -1; //fill payload if(this.payLen > 0) { this.inPayload = new byte[this.payLen]; udpip.GetData(this.inPayload, 0, this.payLen); } } /// <summary> /// This function returns an instance of a subclass of Message. /// </summary> public static Message RootMsgType(ref string name) {//System.Diagnostics.Debug.WriteLine("in: " + name); //ordered generally from most popular to least switch(name) { case "Q2": return new Query(); case "QH2": return new QueryHit(); case "QKR": return new QueryKeyRequest(); case "QKA": return new QueryKeyAnswer(); case "QA": return new QueryAck(); case "PUSH": return new Push(); case "PI": return new Ping(); case "PO": return new Pong(); case "LNI": return new LocalNodeInfo(); case "KHL": return new KnownHubList(); case "QHT": return new QueryHashTable(); case "UPROC": return new UserProfileRequest(); case "UPROD": return new UserProfileAnswer(); default: return null; } } } /// <summary> /// Used to encapsulate child packets. /// This is also the base class for several subclasses representing G2 child packets. /// </summary> public abstract class Child : G2Packet { public int offset; //offset of child payload in original root payload } /* various subclasses of Message and Child */ public class HandshakeMsg : Message { public string handshake = ""; public new void GetMsg(Sck sck) { int bytesRec; while(true) { if(sck.state == Condition.hndshk2 || sck.browseHost) { /* * if we're receiving the last handshake from an incoming connection, then * things are a little different because actual packets may follow right after */ if(!sck.incoming && !sck.browseHost) System.Diagnostics.Debug.WriteLine("G2 incoming final handshake problem"); //we'll get straight up to the \r\n\r\n part, and stop right there int recLen = 4; byte[] hndshk = new byte[4]; int endHndShk; while(true) { bytesRec = sck.ReceiveData(hndshk, 0, recLen); if(bytesRec == 0) { sck.Disconnect("nethin' received during handshake (G2)"); return; } handshake += Encoding.ASCII.GetString(hndshk, 0, bytesRec); endHndShk = handshake.LastIndexOf("\r\n\r\n"); if(endHndShk != -1) return; if(handshake[handshake.Length-1] == '\n') recLen = 2; else if(handshake[handshake.Length-1] == '\r') recLen = 1; else recLen = 4; } } else { //usual handshake receive byte[] hndshk = new byte[32768]; bytesRec = sck.ReceiveData(hndshk); if(bytesRec == 0) { sck.Disconnect("nethin' received during handshake (G2)"); return; } handshake += Encoding.ASCII.GetString(hndshk, 0, bytesRec); int endHndShk = handshake.LastIndexOf("\r\n\r\n"); if(endHndShk != -1) break; else System.Diagnostics.Debug.WriteLine("G2 Handshake GetMsg didn't finish"); } } } public override void Process(int offset, int len) { // } } public class UnknownChild : Child { public string name; public UnknownChild(ref string name) { this.name = name; } public override void Process(int offset, int len) { // } } public class Ping : Message { public override void Process(int offset, int len) { if(this.sockNum != -1) { UDP udp = null; bool relay = false; Child child = this.children; while(child != null) { if(child.GetType() == typeof(UDP)) udp = (UDP)child; else if(child.GetType() == typeof(Relay)) relay = true; child = child.nextChild; } if(!relay) { //add a relay child and forward to all ultrapeers if udp present if(udp != null) { OUdpPingRelay oupr = new OUdpPingRelay(); Array.Copy(root.inPayload, udp.offset, oupr.endpoint, 0, 6); //in case there's an endian-ness difference between this host and us if(root.be != !Stats.Updated.le) { //reverse the byte order of the 16-bit port Array.Reverse(oupr.endpoint, 4, 2); } lock(HostCache.recentHubs) { foreach(ConnectionManager.G2Host g2h in ConnectionManager.ultrapeers.Keys) Sck.scks[g2h.sockNum].SendPacket(oupr); } } else Sck.scks[this.sockNum].SendPacket(new OPong()); } else if(udp != null) { //we'll send a pong over udp with the relay child to the original host udp.Read(udp.offset); if(udp.ipep != null) UDPSR.SendOutgoingPacket(new OPongRelay(), udp.ipep); } } else { //ignoring any children, we'll send a plain pong back over udp UDPSR.SendOutgoingPacket(new OPong(), this.ipep); } } public override Child ChildType(ref string name) { if(name == "RELAY") return new Relay(); else if(name == "UDP") return new UDP(); else return new UnknownChild(ref name); } public class Relay : Child { public override void Process(int offset, int len) { // } } public class UDP : Child { public IPEndPoint ipep = null; public override void Process(int offset, int len) { if(len == 6) this.ipep = new IPEndPoint(Endian.GetIPAddress(root.inPayload, offset), Endian.ToUInt16(root.inPayload, offset+4, root.be)); else System.Diagnostics.Debug.WriteLine("g2 ping udp len: " + len.ToString()); } } } public class Pong : Message { public override void Process(int offset, int len) { // } public override Child ChildType(ref string name) { if(name == "RELAY") return new Relay(); else return new UnknownChild(ref name); } public class Relay : Child { public override void Process(int offset, int len) { // } } } public class LocalNodeInfo : Message { public override void Process(int offset, int len) { if(root.sockNum == -1) return; Child child = this.children; while(child != null) { child.Read(child.offset); child = child.nextChild; } } public override Child ChildType(ref string name) { if(name == "NA") return new NodeAddress(); else if(name == "GU") return new GuIdent(); else if(name == "V") return new VendorCode(); else if(name == "LS") return new LibraryStats(); else if(name == "HS") return new HubStatus(); else return new UnknownChild(ref name); } public class NodeAddress : Child { public override void Process(int offset, int len) { //port is important if(Sck.scks[root.sockNum].incoming && len == 6) Sck.scks[root.sockNum].port = Endian.ToUInt16(root.inPayload, offset+4, root.be); } } public class GuIdent : Child { public override void Process(int offset, int len) { if(!Stats.Updated.Gnutella2.ultrapeer) return; if(len == 16) { if(Sck.scks[root.sockNum].gitem == null) { GUIDitem gitem = new GUIDitem(root.inPayload, offset); lock(Router.htRoutes) { Sck.scks[root.sockNum].gitem = gitem; Router.RouteEntry re = new Router.RouteEntry(); re.gitem_key = gitem; re.ipep = null; re.sckNum = root.sockNum; re.timeLeft = -9000; Router.htRoutes.Add(gitem, re); } } } else System.Diagnostics.Debug.WriteLine("G2 LNI GuIdent wrong length: " + len.ToString()); } } public class VendorCode : Child { public override void Process(int offset, int len) { // } } public class LibraryStats : Child { public override void Process(int offset, int len) { Sck.scks[root.sockNum].numFiles = Endian.ToUInt32(root.inPayload, offset, root.be); Sck.scks[root.sockNum].numKB = Endian.ToUInt32(root.inPayload, offset+4, root.be); } } public class HubStatus : Child { public override void Process(int offset, int len) { Sck.scks[root.sockNum].leaves = Endian.ToUInt16(root.inPayload, offset, root.be); Sck.scks[root.sockNum].maxleaves = Endian.ToUInt16(root.inPayload, offset+2, root.be); } } } public class KnownHubList : Message { public override void Process(int offset, int len) { //since we're expecting neighboring hubs info, we'll clear the old info lock(HostCache.recentHubs) Sck.scks[root.sockNum].neighbors.Clear(); int timeStamp = 0; Child child = this.children; while(child != null) { child.Read(child.offset); if(child.GetType() == typeof(CachedHub)) { CachedHub ch = (CachedHub)child; if(ch.ipa != null) { HubInfo hi = new HubInfo(); hi.port = ch.port; hi.timeKnown = Math.Abs(timeStamp - ch.timeStamp); HostCache.AddRecentAndCache(ch.ipa, hi); } } else if(child.GetType() == typeof(Timestamp)) timeStamp = ((Timestamp)child).timeStamp; child = child.nextChild; } } public override Child ChildType(ref string name) { if(name == "NH") return new NeighborHub(); else if(name == "CH") return new CachedHub(); else if(name == "TS") return new Timestamp(); else return new UnknownChild(ref name); } public class Timestamp : Child { public int timeStamp; public override void Process(int offset, int len) { this.timeStamp = Endian.ToInt32(root.inPayload, offset, root.be); } } public class NeighborHub : Child { public override void Process(int offset, int len) { if(len != 6) { Utils.Diag("G2 KHL/NH wrong length: " + len.ToString()); return; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -