This document describes the eDonkey2000 (ED2K
) P2P protocol and eMule Extended Protocol (EMEP).
- 1. Introduction
2. Header specification
3. Client-Server communication
4. Client <-> Client communication
5 LowID Clients
6 Source Exchange
7 Secure Identification
8 Miscellaneous TCP packets
9 UDP packets
protocol is used for communication between compatible clients to form a server-based peer-to-peer file-sharing network. EMEP is only used between eMule (and compatible) clients, but not by official eDonkey2000 clients.
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
- part is a region of a file of (up to) 9500kb in length, for which there is a corresponding MD4 PartHash.
- chunk is a region of a file of (up to) 180kb in length, which can be requested from a remote client.
- block is a region of a chunk which is sent as single packet during data transfer between clients. Chunks are split into block packets for transmitting.
- See also:
- eDonkey2000 Tag System Overview
|protocol| packet length | packet data (length bytes)
Each eDonkey2000 packet begins with protocol opcode, followed by 32-bit unsigned integer indicating the packet length. Currently, three protocol opcodes are in use:
Packed data always begins with 8-bit opcode, which indicates the packet content. When sending packets using PR_ZLIB protocol, the packet data (excluding the opcode) is compressed.
In order to connect to an eDonkey2000 Server, Client
sends OP_LOGINREQUEST to server.
The packet may contain the following tags:
Flags is a bitfield containing the following information:
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.
- See also:
- 5 LowID Clients
The following packets are sent by the server to inform the client that the connection has been established, as well as to provide up2date information about the server:
- Lugdunum 16.44+ servers send additional u32 in ID_CHANGE packet containing bitfield of supported features. Those include:
After establishing connection with the server, the client may request additional information from the server, as well as known servers list.
The server answers with the following packets:
The latter contains the following tags:
After establishing connection with the server, the client must publish it's shared files using OP_OFFERFILES packet. The packet should be compressed if the server supports it to save bandwidth.
The packet may contain the following tags:
- File type is sent in ed2k network as string. The following strings are recognized:
#define FT_ED2K_AUDIO "Audio"
#define FT_ED2K_VIDEO "Video"
#define FT_ED2K_IMAGE "Image"
#define FT_ED2K_DOCUMENT "Doc"
#define FT_ED2K_PROGRAM "Pro" //!< exe/bin/cue/iso etc
This packet should be sent on the following occasions:
- With full shared files list when connecting to server
- With single file whenever new shared file is added
- As empty packet, as server keep-alive packet at regular intervals Additionally, it is possible to indicate whether the file being shared is partial or complete using two special ip/port values:
- Only use these ID's on newer eservers. eMule uses zlib-support to detect whether the server supports these id's too.
Searching in eDonkey2000 network is server-based. Client
sends SEARCHR packet to server, which in turn returns one (or more) SEARCHRESULT packets. This is done over TCP, and with currently connected server only. However, optionally, the client may also send the same search request packet over UDP sockets to all known servers using GLOBSEARCH opcode, which in turn reply (over UDP) with GLOBSEARCHRES packets. <searchexpr> format specifi- cation is beyond the scope of this document. Refer to ED2KPacket::Search
implementation for more information (packets.cpp
SearchResult may contain the following tags:
In order to initialize a connection to a remote client, first the client sends Hello packet.
Hello packet may contain the following tags:
The correct answer to OP_HELLO is OP_HELLOANSWER. The HelloAnswer packet format is identical to OP_HELLO, except that HelloAnswer also includes 8-bit hash length before hash. The value of the field must be 0x0f.
CT_MULEVERSION contains a 32-bit value with the following bits (and meanings)
1 2 3 4 5 [bytes]
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.
- Both of these packets are sent using PR_EMULE.
Tags contained in MuleInfo packets:
CT_COMPRESSION = 0x20,
CT_UDPPORT = 0x21,
CT_UDPVER = 0x22,
CT_SOURCEEXCH = 0x23,
CT_COMMENTS = 0x24,
CT_EXTREQ = 0x25,
CT_COMPATCLIENT = 0x26,
CT_FEATURES = 0x27,
CT_MODVERSION = 0x55,
CT_MODPLUS = 0x99,
CT_L2HAC = 0x3e,
Feature set bitfield is 32-bit value with following bits and meanings:
00000100000100110011001000011110 eMule 43b
00110100000100110011001000011110 eMule 44b
| | | | | | | | |||+-- 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)
After completing the handshaking described in section 4.1, the client may now request a file. This is done using ReqFile packet.
- eMule ExtReqV1 adds <u16>count<count>bitarray partmap
eMule ExtReqV2 adds <u16>completesources
ReqFile is replied by OP_FILENAME and OP_FILEDESC
After receiving the above packets, the downloading client sends SETREQFILEID to bind the reqested file to the hash. This means the client is now bound to the requested hash, until it receives it.
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.
- Actually, eMule extended protocol allows changing the reqested file while waiting in the queue by resending OP_SETREQFILEID at any time.
The expected response to this packet is OP_FILESTATUS
If at any point during the above packets the uploading client realizes it doesn't share the file requested, it may send OP_REQFILE_NOFILE. File status packet contains a part map of the available parts. This is defined as a bitfield, one bit per each ED2K
part (defined by ED2K_PARTSIZE). Extra bits needed to fill up the byte are padded with zeros. The count prior to the bitset indicates the number of total parts, and thus also the number of total bits in the bitset (note: NOT the number of bytes following!). Also note that sending partmap is completely optional, and should only be sent if the file is indeed partial - if the sender has the entire file, the partmap shall be omitted.
If the downloading client needs a hashset of the file, it may ask the uploader for it using OP_REQHASHSET. The expected response is OP_HASHSET.
After that, the requesting client sends OP_STARTUPLOADREQ, which must be replied either by OP_ACCEPTUPLOADREQ (if we can start uploading right away), or OP_QUEUERANKING, in case the client has been inserted into our upload queue.
There is another queue ranking packet used by eMule - denoted by opcode OP_MULEQUEUERANK.
This packet contains 16-bit value as queue rank, and 10 empty bytes, such as the full packet size must be 12 bytes. This size requirement is enforced by eMule packet parser, and the sender will be disconnected if those extra bytes are not sent. Why are there those 10 extra empty bytes, and why is it enforced so strongly remains unclear. This packet is also sent using PR_EMULE protocol opcode. Note that if you'r thinking to skip over this packet and not use it, you'r so out of luck, since eMule considers clients who send OP_QUEUERANKING simply QueueFull (altough it seems to parse the packet). So if you want eMule compatibility, you need to use this half-empty packet.
After receiving OP_ACCEPTUPLOADREQ, the remote client will proceed to request chunks from us. In eDonkey2000 network, a chunk size is 180k (notice the difference from partsize). The chunks are requested using OP_REQCHUNKS packet:
The packet contains three begin offsets and three end offsets of the requested chunks. ED2K
data ranges logic defines that the end offset is exclusive, thus range (0, 0) is considered as invalidrange
. If the client wishes less than three chunks, it may set the remaining ranges to (0, 0) to indicate that.
- This is slightly different from HydraNode Range API, where end offset is considered inclusive.
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:
MLDonkeys, and some other clients, however, only send single requests:
Packet1: 0..101, 101..201, 201..301
Packet2: 101..201, 201..301, 301..401
Packet3: 201..301, 301..401, 401..501
This can lead to duplicate data being sent by mldonkeys, if a rotational chunkrequest scheme is used when communicating with them. For that reason, HydraNode uses non-rotational request scheme with all clients, since all clients handle it properly.
Packet1: 0..101, 101..201, 201..301
Packet2: 301..401, 0..0, 0..0
Packet3: 401..501, 0..0, 0..0
After receiving OP_REQCHUNKS, the uploading clients starts sending data. The requested chunks are split into (up to) 10kb blocks, each transmitted as a separate packet, using OP_SENDINGCHUNK opcode. Optionally, clients supporting eMule extended protocol may use OP_PACKEDCHUNK packet (which is sent using PR_EMULE). In compressed packet, the data part of the packet is compressed using zlib (but not the packet header - this is different from OfferFiles packet, where everything after the opcode is compressed). Also, in case of a compressed packet, the end offset bytes in the packet header indicate the length of the compressed data, not the end offset of the uncompressed data. Note that compression is not required - if data compression results in larger amount of data, data should be sent uncompressed instead, using OP_SENDINGCHUNK packet.
When the receiver decides it does not want any more data from us, it will send OP_CANCELTRANSFER packet (empty payload) to the uploader.
In case of compressed data transfer, the entire requested chunk is first compressed, and then transmitted in 10kb chunks over time.
LowID client is defined in ed2k network as a client who cannot receive external connection. The client can only make external connections itself. The only way to connect to a client is through a server callback, since the client is connected to a server. It is only possible to contact LowID clients that are on same server as the connecter is. LowID client's are identifier in the network using client ID less than 0x00ffffff. This is also the reason why everywhere where there should be client IP we say it is ID. For clients with ID > 0x00ffffff, the ID indicates the IP of the remote client (in network byte order), for lower ID's, it indicates the client callback ID, as assigned by the server.
Connecting to LowID client is done by sending OP_REQCALLBACK to currently connected server, including the ID of the remote client we wish to connect.
If the client with the specified ID is connected to the server, the server sends OP_CBREQUESTED packet to the client, after which the client will attempt to contact the requester.
If the client in question is not connected to this server, the server will respond with OP_CALLBACKFAIL.
Extended protocol feature added by eMule, Source Exchange allows clients to share their known sources for files.
- SrcExchv2 adds 16-byte user-hash to each source.
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.
Normally, this packet is sent using PR_EMULE, but if possible, it should be compressed and sent using PR_ZLIB.
- ED2K netiquette specifies that you should not request mosources from clients at intervals exceeding these:
- No more than once per 40 minutes per client in case of rare files (less than 10 sources)
- No more than once per 2 hours per client in case of common files
Secure Identification provides means of determining the client's identity in a secure manner, and avoid the former problems regarding hash/credit stealers. In the protocol, three packets implement SecIdent:
Request signature and/or publickey from remote client
Includes the senders public key
Includes the senders signature
The signature message contents are as follows:
- SecIdentv2 adds u32 ip and u8 iptype The pubkey is the signature requesters public key. The message is signed with the senders own private key. The receiver can then verify the message with the senders public key.
Sample implementation of this scheme, using CryptoPP library, CreditsDb::createCryptKey CreditsDb::loadCryptKey CreditsDb::createSignature CreditsDb::verifySignature
Message packets can be used to perform simple chatting between clients.
Not actually part of ed2k protocol, OP_PORTTEST can be used (by a website, for example) to verify correct firewall configuration. Note that OP_PORTTEST may be sent both via TCP and UDP.
Sent when client changes it's ip address, or in case of LowID clients, changes it's ID (sent by server). Mules seem to only handle this packet, but not send it themselves.
- The actual format of this packet has not yet been fully verified.
The format of UDP packets header differs slightly from TCP packet headers, namely, the size field is omitted, and opcode follows the protocol code.
As an eMule extended feature, UDP packets are used to "ping" sources every now and then to verify queue status, reask queue rankings and so on. In current implementation, eMule (and compatible) clients seem to drop clients from their queues if they haven't pinged at least once per hour. The following packets are currently in use, and are sent using protocol PR_EMULE:
By default, this packet only contains filehash the source was interested in.
- UDPv3 adds 2-bytes complete-source-count.
UDPv4 adds availability partmap, as in ReqFile packet.
When UDPv4 is used, the partmap is placed before the complete source count.
Expected response to OP_REASKFILEPING, this indicates that the asking client is indeed in queue, and contains it's current queue ranking.
- UDPv4 adds availability partmap, as in ReqFile packet
Similarly to OP_REASKFILEPING packet, when UDPv4 is used, the partmap is placed BEFORE the queue ranking in the packet.
Sent as response to OP_REASKFILEPING, indicates that the remote client is not sharing the requested file (anymore at least).
Sent as response to OP_REASKFILEPING, indicates that the remote queue is full.
<-> Global Server communication, UDP is used for global searches, as well as global source queries. The following packets are being used, and sent using protocol PR_ED2K:
All servers support this packet, but if the ServerUDPFlags includes FL_GETSOURCES, the server allows requesting sources for multiple files at same time. When sending more than one hash, care must be taken to limit the packet size to 512 bytes, anything above that will be ignored by server.
Modified version of the above packet, this also includes file-size in the request. This can only be used with servers, which support FL_GETSOURCES2 flag.
- You shouldn't query any server twice for sources during 20-minute- interval, or you might get banned.
The expected response to OP_GLOBGETSOURCES or GLOBGETSOURCES2 packets, this packet contains the list of sources the server knows.
Used for "pinging" global servers, this packet requests the remote server to return info about it's current state. Servers always respond to this packet (if alive), so this can be used to determine whether the server is alive or not. As with GlobGetSources, no server should be queried more often than once every 20 minutes.
The first two bytes of the challenge (in network byte order) are always set to 0x55aa, followed by random 16bit integer.
The expected response to OP_GLOBSTATREQ, this packet contains bunch of information about the server. Only the first three fields (challenge, users, files) are always present, the remainder of fields are optional (only implemented by newer server versions, and can possibly be omitted even by newer servers). The challenge is equal to the challenge sent in OP_GLOBSTATREQ packet.