Few words on the packet format strings used here:
u8 unsigned 8-bit integer u16 unsigned 16-bit integer u32 unsigned 32-bit integer hash 16-bytes md4 checksum string 16-bit integer (specifying string length) followed by the string Taglist 32-bit integer (specifying number of tags) followed by the tags
+--------+--------+--------+--------+--------+--------+--------+--------+---- |protocol| packet length | packet data (length bytes) +--------+--------+--------+--------+--------+--------+--------+--------+----
PR_ED2K = 0xe3, //!< Standard, historical eDonkey2000 protocol PR_EMULE = 0xc5, //!< eMule extended protocol PR_ZLIB = 0xd4 //!< Packet payload is compressed with gzip
OP_LOGINREQUEST = 0x01, //!< <hash>hash<u32>ip<u16>port<TagList>tags
CT_NICK = 0x01, //!< <string>nick CT_VERSION = 0x11, //!< <u8>0x3c CT_PORT = 0x0f, //!< <u16>port CT_MULEVERSION = 0xfb, //!< <u32>ver CT_FLAGS = 0x20, //!< <u8>flags
FL_ZLIB = 0x01, //!< zlib compression support FL_IPINLOGIN = 0x02, //!< Client sends its own ip during login FL_AUXPORT = 0x04, //!< ??? FL_NEWTAGS = 0x08, //!< support for new-styled eMule tags FL_UNICODE = 0x10 //!< support for unicode
On a well-formed OP_LOGINREQUEST packet, the server first attempts to connect to the sending client to its reported listening port as a normal client. If the connection attempt succeeds, and the server receives a wellformed OP_HELLOANSWER packet from the socket, the server assigns the connecting client High ID. If the connection fails for whatever reason, the client is assigned Low ID.
OP_SERVERMESSAGE = 0x38, //!< <u16>len<len>message OP_SERVERSTATUS = 0x34, //!< <u32>users<u32>files OP_IDCHANGE = 0x40 //!< <u32>newid
FL_ZLIB = 0x01, //!< zlib compression support FL_NEWTAGS = 0x08, //!< support for new-styled eMule tags FL_UNICODE = 0x10 //!< support for unicode
OP_GETSERVERLIST = 0x14, //!< (no payload)
OP_SERVERLIST = 0x32, //!< <u8>count[{<u32>ip<u16>port}*count] OP_SERVERIDENT = 0x41, //!< <hash>hash<u32>ip<u16>port<TagList>tags
CT_SERVERNAME = 0x01, //!< <string>name CT_SERVERDESC = 0x0b //!< <string>desc
//! <u32>count[<count>*{<hash>filehash<u32>ip<u16>port<TagList>tags}] OP_OFFERFILES = 0x15,
CT_FILENAME = 0x01, //!< <string>name CT_FILESIZE = 0x02, //!< <u32>size CT_FILETYPE = 0x03, //!< <string>type
#define FT_ED2K_AUDIO "Audio" //!< mp3/ogg/wma etc #define FT_ED2K_VIDEO "Video" //!< avi/mpg/mpeg/wmv etc #define FT_ED2K_IMAGE "Image" //!< png/jpg/gif/tiff etc #define FT_ED2K_DOCUMENT "Doc" //!< txt/doc/rtf etc #define FT_ED2K_PROGRAM "Pro" //!< exe/bin/cue/iso etc
FL_COMPLETE_ID = 0xfcfcfcfc, //!< File is complete - send this as ID FL_COMPLETE_PORT = 0xfcfc, //!< File is complete - send this as port FL_PARTIAL_ID = 0xfbfbfbfb, //!< File is partial - send this as ID FL_PARTIAL_PORT = 0xfbfb //!< File is partial - send this as port
OP_SEARCH = 0x16, //!< <searchexpr> //! <u32>count[<count>*{<Hash>hash<u32>id<u16>port<Taglist>tags}] OP_SEARCHRESULT = 0x33,
CT_FILENAME = 0x01, //!< <string>name CT_FILESIZE = 0x02, //!< <u32>size CT_FILETYPE = 0x03, //!< <string>type CT_SOURCES = 0x15, //!< <u32>numsrc CT_COMPLSRC = 0x30, //!< <u32>numcomplsrc
OP_HELLO = 0x01, //!< <hash>hash<u32>ip<u16>port<TagList>tags
CT_NICK = 0x01, //!< <string>nick CT_PORT = 0x0f, //!< <u16>port CT_MULEVERSION = 0xfb, //!< <u32>ver CT_MODSTR = 0x55, //!< <string>modstring CT_UDPPORTS = 0xf9, //!< <u16>kadudpport<u16>ed2kudpport CT_MISCFEATURES = 0xfa, //!< <u32>features bitset
CT_MULEVERSION contains a 32-bit value with the following bits (and meanings)
1 2 3 4 5 [bytes]
11111111222222233333334445555555 [bits]
00000000000000001010101100000000 eMule 42g version info
| | | | +---- Build version (unused by eMule)
| | | +--------- Update version 6 (a = 0, g = 6)
| | +-------------- Minor version 42
| +--------------------- Major version (unused by eMule)
+---------------------------- Compatible Client ID (CS_EMULE = 0x00)
If both of the clients are eMule-compatible, they also exchange MuleInfo packets.
OP_MULEINFO = 0x01, //!< <u8>clientver<u8>protver<TagList>tags OP_MULEINFOANSWER = 0x02 //!< <u8>clientver<u8>protver<TagList>tags
CT_COMPRESSION = 0x20, //!< u32 compression version CT_UDPPORT = 0x21, //!< u32 udp port CT_UDPVER = 0x22, //!< u32 udp protocol version CT_SOURCEEXCH = 0x23, //!< u32 source exchange version CT_COMMENTS = 0x24, //!< u32 comment version CT_EXTREQ = 0x25, //!< u32 extended request version CT_COMPATCLIENT = 0x26, //!< u32 compatible client ID CT_FEATURES = 0x27, //!< u32 supported features bitset CT_MODVERSION = 0x55, //!< <string>modversion (may also be int) CT_MODPLUS = 0x99, //!< mh? (Source: eMule+ Forums ... ) CT_L2HAC = 0x3e, //!< mh? (Source: eMule+ Forums ... )
12345678123456781234567812345678 00000100000100110011001000011110 eMule 43b 00110100000100110011001000011110 eMule 44b 11123333444455556666777788889abc | | | | | | | | |||+-- Preview | | | | | | | | ||+--- Multipacket | | | | | | | | |+---- No `view shared files' supported | | | | | | | | +----- Peercache | | | | | | | +-------- Comments | | | | | | +----------- Extended requests | | | | | +---------------- Source exchange | | | | +-------------------- Secure ident | | | +----------------------- Data compression version | | +--------------------------- UDP version | +------------------------------ Unicode +-------------------------------- AICH version (0 - not supported)
OP_REQFILE = 0x58, //!< <hash>hash
eMule ExtReqV2 adds <u16>completesources
OP_FILENAME = 0x59, //!< <hash>hash<u32>len<len>name OP_FILEDESC = 0x61, //!< <u8>rating<u32>len<len>comment
FileDesc packet is sent using PR_EMULE, and does NOT contain the file hash the description belongs to, however, since it is always sent along with OP_FILENAME, in response to OP_REQFILE packet, client can thus assume the FileDesc packet belongs to the most recently requested file.
OP_SETREQFILEID = 0x4f, //!< <hash>hash
OP_REQFILE_STATUS = 0x50, //!< <hash>hash<u16>count<count>partmap
OP_REQFILE_NOFILE = 0x48, //!< <hash>hash
OP_REQHASHSET = 0x51, //!< <hash>hash OP_HASHSET = 0x52, //!< <hash>hash<u16>cnt[cnt*<hash>parthash]
OP_STARTUPLOADREQ = 0x54, //!< may contain <hash>hash (emule) OP_ACCEPTUPLOADREQ = 0x55, //!< Empty OP_QUEUERANKING = 0x5c, //!< <u32>queueranking
OP_MULEQUEUERANK = 0x60 //!< <u16>queuerank<u16><u32><u32>empty
OP_REQCHUNKS = 0x47, //!< <hash>hash[3*<u32>begin][3*<u32>end]
Implementors should be warned about different behaviours of different clients when it comes to chunk requests. Namely, eMule (and compatible) clients use "rotational chunkrequest" scheme, where each REQCHUNKS packet contains one new chunk and two older chunks; for example:
Packet1: 0..101, 101..201, 201..301 // initial req Packet2: 101..201, 201..301, 301..401 // sent after completing 0..101 Packet3: 201..301, 301..401, 401..501 // sent after completing 101..201
Packet1: 0..101, 101..201, 201..301 // initial req Packet2: 301..401, 0..0, 0..0 // after completing 0..101 Packet3: 401..501, 0..0, 0..0 // after completing 101..201
OP_SENDINGCHUNK = 0x46, //!< <hash>hash<u32>begin<u32>end<data> OP_PACKEDCHUNK = 0x40, //!< <hash>hash><u32>begin<u32>len<len>data
When the receiver decides it does not want any more data from us, it will send OP_CANCELTRANSFER packet (empty payload) to the uploader.
OP_CANCELTRANSFER = 0x56 //!< empty
In case of compressed data transfer, the entire requested chunk is first compressed, and then transmitted in 10kb chunks over time.
OP_REQCALLBACK = 0x1c, //!< <u32>id
OP_CBREQUESTED = 0x35, //!< <u32>ip<u16>tcpport
OP_CALLBACKFAIL = 0x36 //!< empty
OP_REQSOURCES = 0x81, //!< <hash>hash OP_ANSWERSOURCES = 0x82
SrcExchv3 sends ID's in byteswapped format (also called "Hybrid" format in eMule code) so HighID clients with *.*.*.0 won't be falsely given LowId.
OP_SECIDENTSTATE = 0x87, //!< <u8>state<u32>challenge
OP_PUBLICKEY = 0x85, //!< <u8>len<len>pubkey
OP_SIGNATURE = 0x86 //!< <u8>len<len>signature
The signature message contents are as follows:
<*>pubkey<u32>challenge
OP_MESSAGE = 0x4e, //!< <u16>len<len>message
OP_PORTTEST = 0xfe, //!< Server: <u16>0x12, Client: <u16>1
OP_CHANGEID = 0x4d //!< <u32>oldid<u32>newid
OP_REASKFILEPING = 0x90, //!< <hash>hash
UDPv4 adds availability partmap, as in ReqFile packet.
When UDPv4 is used, the partmap is placed before the complete source count.
OP_REASKACK = 0x91, //!< <u16>queueranking
Similarly to OP_REASKFILEPING packet, when UDPv4 is used, the partmap is placed BEFORE the queue ranking in the packet.
OP_FILENOTFOUND = 0x92, //!< empty
OP_QUEUEFULL = 0x93, //!< empty
OP_GLOBGETSOURCES = 0x9a, //!< cnt*[<hash>hash]
OP_GLOBGETSOURCES2 = 0x94, //!< cnt*[<hash>hash<u32>size]
OP_GLOBFOUNDSOURCES = 0x9b, //!< <hash>hash<u8>cnt*[<u32>id<u16>port]
OP_GLOBSTATREQ = 0x96, //!< <u32>challenge
The first two bytes of the challenge (in network byte order) are always set to 0x55aa, followed by random 16bit integer.
OP_GLOBSTATRES = 0x97