2 // This file is part of the aMule Project.
4 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2003-2008 Froenchenko Leonid ( lfroen@gmail.com / http://www.amule.org )
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 using System
.Security
.Cryptography
;
29 using System
.Collections
.Generic
;
34 public enum EcTagTypes
{
35 EC_TAGTYPE_UNKNOWN
= 0,
36 EC_TAGTYPE_CUSTOM
= 1,
38 EC_TAGTYPE_UINT16
= 3,
39 EC_TAGTYPE_UINT32
= 4,
40 EC_TAGTYPE_UINT64
= 5,
41 EC_TAGTYPE_STRING
= 6,
42 EC_TAGTYPE_DOUBLE
= 7,
47 public class ecProto
{
51 protected EcTagTypes m_type
;
52 protected ECTagNames m_name
;
53 protected LinkedList
<ecTag
> m_subtags
;
55 public ecTag(ECTagNames n
, EcTagTypes t
)
59 m_subtags
= new LinkedList
<ecTag
>();
61 public ecTag(ECTagNames n
, EcTagTypes t
, LinkedList
<ecTag
> subtags
)
65 m_subtags
= subtags
; ;
70 m_subtags
= new LinkedList
<ecTag
>();
73 public int SubtagCount()
75 return m_subtags
.Count
;
78 protected void WriteSubtags(BinaryWriter wr
)
80 Int16 count16
= (Int16
)m_subtags
.Count
;
82 wr
.Write(System
.Net
.IPAddress
.HostToNetworkOrder(count16
));
83 foreach (ecTag t
in m_subtags
)
90 public ECTagNames
Name()
95 public virtual void Write(BinaryWriter wr
)
97 Int16 name16
= (Int16
)(m_name
);
99 byte type8
= (byte)m_type
;
100 Int32 size32
= (Int32
)Size();
101 if (m_subtags
.Count
!= 0) {
104 wr
.Write(System
.Net
.IPAddress
.HostToNetworkOrder(name16
));
106 wr
.Write(System
.Net
.IPAddress
.HostToNetworkOrder(size32
));
110 // here derived class will put actual data
116 int total_size
= m_size
;
117 foreach (ecTag t
in m_subtags
) {
118 total_size
+= t
.Size();
119 // name + type + size for each tag
120 total_size
+= (2 + 1 + 4);
121 if (t
.HaveSubtags()) {
128 public LinkedList
<ecTag
>.Enumerator
GetTagIterator()
130 return m_subtags
.GetEnumerator();
133 public void AddSubtag(ecTag t
)
135 m_subtags
.AddLast(t
);
140 return (m_subtags
.Count
!= 0);
143 public ecTag
SubTag(ECTagNames name
)
145 foreach (ecTag t
in m_subtags
) {
146 if (t
.m_name
== name
) {
154 public class ecTagInt
: ecTag
{
155 protected Int64 m_val
;
156 public ecTagInt(ECTagNames n
, byte v
)
157 : base(n
, EcTagTypes
.EC_TAGTYPE_UINT8
)
163 public ecTagInt(ECTagNames n
, Int16 v
)
164 : base(n
, EcTagTypes
.EC_TAGTYPE_UINT16
)
170 public ecTagInt(ECTagNames n
, Int32 v
)
171 : base(n
, EcTagTypes
.EC_TAGTYPE_UINT32
)
177 public ecTagInt(ECTagNames n
, Int64 v
)
178 : base(n
, EcTagTypes
.EC_TAGTYPE_UINT64
)
184 public ecTagInt(ECTagNames n
, Int32 tag_size
, BinaryReader br
, LinkedList
<ecTag
> subtags
)
185 : base(n
, EcTagTypes
.EC_TAGTYPE_UINT8
, subtags
)
193 m_type
= EcTagTypes
.EC_TAGTYPE_UINT64
;
194 lo
= System
.Net
.IPAddress
.NetworkToHostOrder(br
.ReadInt32());
195 hi
= System
.Net
.IPAddress
.NetworkToHostOrder(br
.ReadInt32());
196 raw_val
= ((UInt64
)hi
) << 32 | (UInt32
)lo
;
199 m_type
= EcTagTypes
.EC_TAGTYPE_UINT32
;
200 v32
= (System
.Net
.IPAddress
.NetworkToHostOrder(br
.ReadInt32()));
201 raw_val
= (UInt32
)v32
;
204 m_type
= EcTagTypes
.EC_TAGTYPE_UINT16
;
205 v16
= System
.Net
.IPAddress
.NetworkToHostOrder(br
.ReadInt16());
206 raw_val
= (UInt16
)v16
;
209 m_type
= EcTagTypes
.EC_TAGTYPE_UINT8
;
210 raw_val
= (UInt64
)br
.ReadByte();
213 throw new Exception("Unexpected size of data in integer tag");
215 m_val
= (Int64
)raw_val
;
217 throw new Exception("WTF - typecasting is broken?!");
221 public int ValueInt()
226 public Int64
Value64()
231 public override void Write(BinaryWriter wr
)
237 Int32 val32
= (Int32
)(m_val
>> 32);
238 wr
.Write(System
.Net
.IPAddress
.HostToNetworkOrder(val32
));
240 val32
= (Int32
)(m_val
& 0xffffffff);
241 wr
.Write(System
.Net
.IPAddress
.HostToNetworkOrder(val32
));
244 val32
= (Int32
)(m_val
& 0xffffffff);
245 wr
.Write(System
.Net
.IPAddress
.HostToNetworkOrder(val32
));
248 Int16 val16
= (Int16
)(m_val
& 0xffff);
249 wr
.Write(System
.Net
.IPAddress
.HostToNetworkOrder(val16
));
252 wr
.Write((byte)(m_val
& 0xff));
259 public class ecMD5
: IComparable
<ecMD5
>, IEquatable
<ecMD5
> {
261 public ecMD5(Int64 lo
, Int64 hi
)
268 // actual byte order doesn't matter, but conversion must be consistant
270 public ecMD5(byte [] v
)
272 m_lo
= ((Int64
)v
[0] << 0) | ((Int64
)v
[1] << 8) | ((Int64
)v
[2] << 16) | ((Int64
)v
[3] << 24) |
273 ((Int64
)v
[4] << 32) | ((Int64
)v
[5] << 40) | ((Int64
)v
[6] << 48) | ((Int64
)v
[7] << 56);
274 m_hi
= ((Int64
)v
[8] << 0) | ((Int64
)v
[9] << 8) | ((Int64
)v
[10] << 16) | ((Int64
)v
[11] << 24) |
275 ((Int64
)v
[12] << 32) | ((Int64
)v
[13] << 40) | ((Int64
)v
[14] << 48) | ((Int64
)v
[15] << 56);
278 public byte [] ByteValue()
281 (byte)(m_lo
>> 0), (byte)(m_lo
>> 8), (byte)(m_lo
>> 16), (byte)(m_lo
>> 24),
282 (byte)(m_lo
>> 32), (byte)(m_lo
>> 40), (byte)(m_lo
>> 48), (byte)(m_lo
>> 56),
283 (byte)(m_hi
>> 0), (byte)(m_hi
>> 8), (byte)(m_hi
>> 16), (byte)(m_hi
>> 24),
284 (byte)(m_hi
>> 32), (byte)(m_hi
>> 40), (byte)(m_hi
>> 48), (byte)(m_hi
>> 56),
289 public override int GetHashCode()
291 return (int)m_lo ^
(int)m_hi
;
294 public bool Equals(ecMD5 i
)
296 return (m_hi
== i
.m_hi
) && (m_lo
== i
.m_lo
);
299 public int CompareTo(ecMD5 i
)
301 Int64 r
= ((m_hi
== i
.m_hi
) ? (m_lo
- i
.m_lo
) : (m_hi
- i
.m_hi
));
302 return r
> 0 ? 1 : (r
< 0 ? -1 : 0);
306 public class ecTagMD5
: ecTag
{
309 public ecTagMD5(ECTagNames n
, ecMD5
value)
310 : base(n
, EcTagTypes
.EC_TAGTYPE_HASH16
)
312 m_val
= value.ByteValue();
316 public ecTagMD5(ECTagNames n
, string s
, bool string_is_hash
)
317 : base(n
, EcTagTypes
.EC_TAGTYPE_HASH16
)
319 if ( string_is_hash
) {
320 // in this case hash is passed as hex string
321 if ( s
.Length
!= 16*2 ) {
322 throw new Exception("md5 hash of proto version have incorrect length");
324 //byte[] hash_str = s.ToCharArray();
325 for (int i
= 0; i
< 16; i
++) {
326 string v
= s
.Substring(i
* 2, 2);
329 m_val
= new byte[16];
331 MD5CryptoServiceProvider p
= new MD5CryptoServiceProvider();
332 byte[] bs
= System
.Text
.Encoding
.UTF8
.GetBytes(s
);
333 m_val
= p
.ComputeHash(bs
);
338 public ecTagMD5(ECTagNames name
, byte[] hash_data
)
339 : base(name
, EcTagTypes
.EC_TAGTYPE_HASH16
)
345 public ecTagMD5(ECTagNames name
, BinaryReader br
, LinkedList
<ecTag
> subtags
)
346 : base(name
, EcTagTypes
.EC_TAGTYPE_HASH16
, subtags
)
349 m_val
= br
.ReadBytes(16);
352 public override void Write(BinaryWriter wr
)
358 public ecMD5
ValueMD5()
360 return new ecMD5(m_val
);
364 public class ecTagIPv4
: ecTag
{
367 public ecTagIPv4(ECTagNames name
, BinaryReader br
, LinkedList
<ecTag
> subtags
)
368 : base(name
, EcTagTypes
.EC_TAGTYPE_IPV4
, subtags
)
371 m_addr
= System
.Net
.IPAddress
.NetworkToHostOrder(br
.ReadInt32());
372 m_port
= System
.Net
.IPAddress
.NetworkToHostOrder(br
.ReadInt16());
376 public class ecTagCustom
: ecTag
{
378 public ecTagCustom(ECTagNames n
, Int32 tag_size
, BinaryReader br
, LinkedList
<ecTag
> subtags
)
379 : base(n
, EcTagTypes
.EC_TAGTYPE_CUSTOM
, subtags
)
381 m_val
= br
.ReadBytes(tag_size
);
384 public byte [] Value()
391 public class ecTagString
: ecTag
{
393 public ecTagString(ECTagNames n
, string s
)
394 : base(n
, EcTagTypes
.EC_TAGTYPE_STRING
)
396 m_val
= System
.Text
.Encoding
.UTF8
.GetBytes(s
);
397 m_size
= m_val
.GetLength(0) + 1;
400 public ecTagString(ECTagNames n
, Int32 tag_size
, BinaryReader br
, LinkedList
<ecTag
> subtags
)
401 : base(n
, EcTagTypes
.EC_TAGTYPE_STRING
, subtags
)
403 byte[] buf
= br
.ReadBytes(tag_size
-1);
404 // discard trailing '0'
411 public override void Write(BinaryWriter wr
)
418 public string StringValue()
420 Encoding u8
= Encoding
.UTF8
;
421 string s
= u8
.GetString(m_val
);
426 public class ecPacket
: ecTag
{
427 // since I have no zlib here, effectively disable compression
428 const int MaxUncompressedPacket
= 0x6666;
430 private ECOpCodes m_opcode
;
431 protected Int32 m_flags
;
436 ecTag
ReadTag(BinaryReader br
)
439 Int16 tag_name16
= System
.Net
.IPAddress
.NetworkToHostOrder(br
.ReadInt16());
440 bool have_subtags
= ((tag_name16
& 1) != 0);
441 ECTagNames tag_name
= (ECTagNames
)(tag_name16
>> 1);
443 byte tag_type8
= br
.ReadByte();
444 Int32 tag_size32
= System
.Net
.IPAddress
.NetworkToHostOrder(br
.ReadInt32());
445 LinkedList
<ecTag
> subtags
= null;
446 if ( have_subtags
) {
447 subtags
= ReadSubtags(br
);
449 EcTagTypes tag_type
= (EcTagTypes
)tag_type8
;
451 case EcTagTypes
.EC_TAGTYPE_UNKNOWN
:
453 case EcTagTypes
.EC_TAGTYPE_CUSTOM
:
454 t
= new ecTagCustom(tag_name
, tag_size32
, br
, subtags
);
457 case EcTagTypes
.EC_TAGTYPE_UINT8
:
458 t
= new ecTagInt(tag_name
, 1, br
, subtags
);
460 case EcTagTypes
.EC_TAGTYPE_UINT16
:
461 t
= new ecTagInt(tag_name
, 2, br
, subtags
);
463 case EcTagTypes
.EC_TAGTYPE_UINT32
:
464 t
= new ecTagInt(tag_name
, 4, br
, subtags
);
466 case EcTagTypes
.EC_TAGTYPE_UINT64
:
467 t
= new ecTagInt(tag_name
, 8, br
, subtags
);
470 case EcTagTypes
.EC_TAGTYPE_STRING
:
471 t
= new ecTagString(tag_name
, tag_size32
, br
, subtags
);
473 case EcTagTypes
.EC_TAGTYPE_DOUBLE
:
475 case EcTagTypes
.EC_TAGTYPE_IPV4
:
476 t
= new ecTagIPv4(tag_name
, br
, subtags
);
478 case EcTagTypes
.EC_TAGTYPE_HASH16
:
479 t
= new ecTagMD5(tag_name
, br
, subtags
);
485 throw new Exception("Unexpected tag type");
490 LinkedList
<ecTag
> ReadSubtags(BinaryReader br
)
492 Int16 count16
= System
.Net
.IPAddress
.NetworkToHostOrder(br
.ReadInt16());
493 LinkedList
<ecTag
> taglist
= new LinkedList
<ecTag
>();
494 for (int i
= 0; i
< count16
;i
++) {
495 ecTag st
= ReadTag(br
);
506 public ecPacket(BinaryReader br
)
508 m_flags
= System
.Net
.IPAddress
.NetworkToHostOrder(br
.ReadInt32());
509 Int32 packet_size
= System
.Net
.IPAddress
.NetworkToHostOrder(br
.ReadInt32());
510 m_opcode
= (ECOpCodes
)br
.ReadByte();
512 Int16 tags_count
= System
.Net
.IPAddress
.NetworkToHostOrder(br
.ReadInt16());
514 if ( tags_count
!= 0 ) {
515 for (int i
= 0; i
< tags_count
; i
++) {
516 ecTag t
= ReadTag(br
);
523 // Default ctor - for tx packets
524 public ecPacket(ECOpCodes cmd
)
530 public ecPacket(ECOpCodes cmd
, EC_DETAIL_LEVEL detail_level
)
534 if ( detail_level
!= EC_DETAIL_LEVEL
.EC_DETAIL_FULL
) {
535 AddSubtag(new ecTagInt(ECTagNames
.EC_TAG_DETAIL_LEVEL
, (Int64
)detail_level
));
540 // Size of data for TX, not of payload
542 public int PacketSize()
544 int packet_size
= Size();
545 if ((m_flags
& (UInt32
)ECFlags
.EC_FLAG_ACCEPTS
) != 0) {
548 // 1 (command) + 2 (tag count) + 4 (flags) + 4 (total size)
549 return packet_size
+ 1 + 2 + 4 + 4;
552 public ECOpCodes
Opcode()
557 public override void Write(BinaryWriter wr
)
559 // 1 (command) + 2 (tag count)
560 int packet_size
= Size() + 1 + 2;
561 if ( packet_size
> MaxUncompressedPacket
) {
562 m_flags
|= (Int32
)ECFlags
.EC_FLAG_ZLIB
;
565 if ((m_flags
& (UInt32
)ECFlags
.EC_FLAG_ZLIB
) != 0) {
566 throw new NotImplementedException("no zlib compression yet");
570 wr
.Write(System
.Net
.IPAddress
.HostToNetworkOrder((Int32
)(m_flags
)));
571 if ((m_flags
& (UInt32
)ECFlags
.EC_FLAG_ACCEPTS
) != 0) {
572 wr
.Write(System
.Net
.IPAddress
.HostToNetworkOrder((Int32
)(m_flags
)));
575 wr
.Write(System
.Net
.IPAddress
.HostToNetworkOrder((Int32
)(packet_size
)));
576 wr
.Write((byte)m_opcode
);
577 if ( m_subtags
.Count
!= 0 ) {
580 wr
.Write((Int16
)(0));
587 // Specific - purpose tags
590 public class ecLoginPacket
: ecPacket
{
591 public ecLoginPacket(string client_name
, string version
, string pass
)
592 : base(ECOpCodes
.EC_OP_AUTH_REQ
)
594 m_flags
|= 0x20 | (Int32
)ECFlags
.EC_FLAG_ACCEPTS
;
596 AddSubtag(new ecTagString(ECTagNames
.EC_TAG_CLIENT_NAME
, client_name
));
597 AddSubtag(new ecTagString(ECTagNames
.EC_TAG_CLIENT_VERSION
, version
));
598 AddSubtag(new ecTagInt(ECTagNames
.EC_TAG_PROTOCOL_VERSION
,
599 (Int64
)ProtocolVersion
.EC_CURRENT_PROTOCOL_VERSION
));
601 AddSubtag(new ecTagMD5(ECTagNames
.EC_TAG_PASSWD_HASH
, pass
, false));
603 // discussion is ongoing
604 //AddSubtag(new ecTagMD5(ECTagNames.EC_TAG_VERSION_ID, EC_VERSION_ID, true));
608 public class ecDownloadsInfoReq
: ecPacket
{
609 public ecDownloadsInfoReq() : base(ECOpCodes
.EC_OP_GET_DLOAD_QUEUE
)
615 // Class exists only for parsing purpose
617 public class ecConnStateTag
{
620 public ecConnStateTag(ecTagInt tag
)
623 //m_tag_val = (Int32)tag.Value64();
627 //public static explicit operator ecConnStateTag(ecTagInt t)
629 // return new ecConnStateTag(t.ValueInt64());
632 public bool IsConnected()
634 return IsConnectedED2K() || IsConnectedKademlia();
637 public bool IsConnectedED2K()
639 return (m_tag_val
& 0x01) != 0;
642 public bool IsConnectingED2K()
644 return (m_tag_val
& 0x02) != 0;
647 public bool IsConnectedKademlia()
649 return (m_tag_val
& 0x04) != 0;
652 public bool IsKadFirewalled()
654 return (m_tag_val
& 0x08) != 0;
657 public bool IsKadRunning()
659 return (m_tag_val
& 0x10) != 0;
662 public ecProto
.ecTag
Server()
664 return m_tag
.SubTag(ECTagNames
.EC_TAG_SERVER
);