Editing Mod protocol

From EMule Wiki
Jump to: navigation, search

Warning: The database has been locked for maintenance, so you will not be able to save your edits right now. You may wish to cut-n-paste the text into a text file and save it for later.

The administrator who locked it offered this explanation: site maintenance

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then save the changes below to finish undoing the edit.
Latest revision Your text
Line 1: Line 1:
= Under construction =
+
=Under construction =
 
THIS IS NOT FINAL.. feel free to edit.  
 
THIS IS NOT FINAL.. feel free to edit.  
  
 
== Introduction ==
 
== Introduction ==
  
The Modprot is needed for more clean protocol extensions by eMule modders....
+
Modprot is needed for more clean protocol extensions by eMule modders....
  
The main idea is to set a bit in CT_EMULE_MISCOPTIONS2 in the initial hello packet. If that bit is set and received by an eMule mod that is capable of processing extensions, then that mod will send the options it is capable of in the response and the first client will also send back the protocol extensions it is capable of.
 
  
'''Important:'''
+
== Protocol ==
  
Clients that are not capable of processing the mod protocol (like official eMule/aMule)  will not set the mod bit in CT_EMULE_MISCOPTIONS2 and will never receive extended protocol information.
 
 
== Documentation ==
 
 
All mod communication is to be done over the OP_MODPROT/OP_MODPACKEDPROT.
 
When a hello(answer) with a set mod bit is received the ConnectionEstablished has to be delayed. Instead of that the mod info packet with the opcode OP_MODINFOPACKET is to be sent.
 
ConnectionEstablished will be triggered when the mod info packet is received.
 
<pre>
 
A              B
 
Hello  --->    MB Set (see if ModBit is set)
 
MB Set  <---    Hello Answer
 
ConEst  <---    MInfo (Mod Info)
 
MInfo  --->    ConEst (call ConnectionEstablished)
 
</pre>
 
The mod info packet has to contain eMuleTags that announce the supported features. The packet is made up this way:
 
<pre>
 
<uint 32> tag count
 
<emule tag 1>
 
<emule tag 2>
 
...
 
<emule tag n>
 
</pre>
 
It's only allowed to use mod features it their capability was announced by both sides.
 
After the capability exchange via OP_MODINFOPACKET all remaining opcodes are allowed to be used by clients in any way they want.
 
All further communication is not part of this specification.
 
 
== Protocol ==
 
  
=== Sending Hello(answer) packets ===  
+
=== Hello ===  
  
Setting the modbit in CT_EMULE_MISCOPTIONS2
+
Set the modbit ot in in CT_EMULE_MISCOPTIONS2
  
 
in baseclient.cpp,  void CUpDownClient::SendHelloTypePacket(CSafeMemFile* data)
 
in baseclient.cpp,  void CUpDownClient::SendHelloTypePacket(CSafeMemFile* data)
Line 48: Line 20:
 
const UINT uSupportLargeFiles = 1;
 
const UINT uSupportLargeFiles = 1;
 
const UINT uExtMultiPacket = 1;
 
const UINT uExtMultiPacket = 1;
// Set the Mod Bit
+
const UINT uReserved = 1; // mod bit  
const UINT uModProt = 1; // mod bit // NEO: NMP - [NeoModProt] <-- Xanatos --
+
 
const UINT uSupportsCryptLayer = thePrefs.IsClientCryptLayerSupported() ? 1 : 0;
 
const UINT uSupportsCryptLayer = thePrefs.IsClientCryptLayerSupported() ? 1 : 0;
 
const UINT uRequestsCryptLayer = thePrefs.IsClientCryptLayerRequested() ? 1 : 0;
 
const UINT uRequestsCryptLayer = thePrefs.IsClientCryptLayerRequested() ? 1 : 0;
Line 61: Line 32:
 
(uRequestsCryptLayer <<  8) |
 
(uRequestsCryptLayer <<  8) |
 
(uSupportsCryptLayer <<  7) |
 
(uSupportsCryptLayer <<  7) |
(uModProt <<  6) |
+
(uReserved <<  6) |
 
(uExtMultiPacket <<  5) |
 
(uExtMultiPacket <<  5) |
 
(uSupportLargeFiles <<  4) |
 
(uSupportLargeFiles <<  4) |
Line 69: Line 40:
 
</pre>
 
</pre>
  
=== Processing hello(answer) packets ===
 
  
Read out the modbit from CT_EMULE_MISCOPTIONS2
+
=== Process hello. ===
  
 
baseclient.cpp bool CUpDownClient::ProcessHelloTypePacket(CSafeMemFile* data)
 
baseclient.cpp bool CUpDownClient::ProcessHelloTypePacket(CSafeMemFile* data)
Line 90: Line 60:
 
m_fRequestsCryptLayer = (temptag.GetInt() >>  8) & 0x01;
 
m_fRequestsCryptLayer = (temptag.GetInt() >>  8) & 0x01;
 
m_fSupportsCryptLayer = (temptag.GetInt() >>  7) & 0x01;
 
m_fSupportsCryptLayer = (temptag.GetInt() >>  7) & 0x01;
// read the mod bit
+
m_NeoModProtVersion = (temptag.GetInt() >>  6) & 0x01; // modbit NEO: NMP - [NeoModProt] <-- Xanatos --
m_fSupportsModProt = (temptag.GetInt() >>  6) & 0x01; // NEO: NMP - [NeoModProt] <-- Xanatos --
+
 
m_fExtMultiPacket = (temptag.GetInt() >>  5) & 0x01;
 
m_fExtMultiPacket = (temptag.GetInt() >>  5) & 0x01;
 
m_fSupportsLargeFiles  = (temptag.GetInt() >>  4) & 0x01;
 
m_fSupportsLargeFiles  = (temptag.GetInt() >>  4) & 0x01;
Line 102: Line 71:
 
</pre>
 
</pre>
  
== Sending hello answer and modprot info ==
+
 
 +
==Send hello answer and modprot info ==
 +
 
  
 
Listensocket.cpp bool CClientReqSocket::ProcessPacket(const BYTE* packet, uint32 size, UINT opcode)
 
Listensocket.cpp bool CClientReqSocket::ProcessPacket(const BYTE* packet, uint32 size, UINT opcode)
Line 118: Line 89:
  
  
Example of SendModInfoPacket:
+
Example of sendmoinfopacket:
  
 
<pre>
 
<pre>
 
void CUpDownClient::SendModInfoPacket(){
 
void CUpDownClient::SendModInfoPacket(){
if (socket == NULL){ // first we check if we have a valid socket, actualy we was called form the socket so this check is rather unnesesery, but in case
+
if (socket == NULL){
 
ASSERT(0);
 
ASSERT(0);
 
return;
 
return;
Line 129: Line 100:
 
CSafeMemFile data(128);
 
CSafeMemFile data(128);
  
// write the amount of emule tags we intent to send
+
uint32 tagcount=2+1;
// !!! this value must be correct !!!
+
 
uint32 tagcount=2;
+
#ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
 +
if(theApp.IsFirewalled() && Kademlia::CKademlia::IsConnected())
 +
tagcount += 1;  
 +
#endif //NATTUNNELING // NEO: NATT END
  
// write the first tag (Nr.1)
 
// in this sample its an normal tag with an uint8 ID, its the modstring 0x55 = 'T'
 
 
data.WriteUInt32(tagcount); // nr. of tags
 
data.WriteUInt32(tagcount); // nr. of tags
CTag tagPartStatus(0x55,_T("TestMod"));
+
 
 +
 
 +
/************************************************************************************
 +
* Note: The meaning of the bit fields in the current sample *
 +
* have to be reworked for the final release version numbers are almost useless, *
 +
* support (or newver version) should be anounced only by single bit flags *
 +
************************************************************************************/
 +
 
 +
#ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
 +
const UINT uNatT = NeoPrefs.IsNatTraversalEnabled();
 +
#endif //NATTUNNELING // NEO: NATT END
 +
uint32 uNeoFeatures =
 +
// ((0 & 0xff) << 24) | // Unused
 +
// ((0 & 0x0f) << 20) | // Reserved
 +
#ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
 +
// ((0 & 0x03) << 18) | // Reserved for nat-t
 +
((1 & 0x01) << 17) | // NEO: RTP - [ReuseTCPPort]
 +
((uNatT & 0x01) << 16) | // Support Nat Traversal
 +
// ((0 & 0x01) << 15) | // NEO: XSB - [XSBuddy]
 +
#endif //NATTUNNELING // NEO: NATT END
 +
((1 & 0x07) << 12) | // NEO: NXS - [NeoXS]
 +
// ((0 & 0x03) << 10) | // Reserved
 +
((1 & 0x01) << 9 ) | // LowID UDP Ping Support (notifyes a fix form xman1 that allow the remote low ID to use udp reasks) // NEO: MOD - [NewUploadState]
 +
((1 & 0x01) << 8 ) | // Unsolicited Part Status (allows our client ro recieve filestatus at any time) // NEO: USPS - [UnSolicitedPartStatus]
 +
// ((0 & 0x0f) << 4 ) | // Reserved
 +
((0 & 0x0f) << 0 ); 
 +
CTag tagNeoModProt(CT_NEO_FEATURES, uNeoFeatures);
 +
tagNeoModProt.WriteTagToFile(&data);
 +
 
 +
uint32 nSCT = NeoPrefs.UseSubChunkTransfer() ? 1 : 0; // version 4 bit
 +
uint32 ICSv2 = NeoPrefs.UseIncompletePartStatus() ? 2 : 0; // version 3 bit
 +
// X-ToDo:
 +
//uint32 RPS = NeoPrefs.UseRealPartStatus() ? 1 : 0; // version 3 bit
 +
//uint32 HPS = NeoPrefs.UseRealPartStatus() ? 1 : 0; // flag 1 bit
 +
//uint32 BPS = NeoPrefs.UseRealPartStatus() ? 1 : 0; // flag 1 bit
 +
 
 +
uint32 uFileStatus =
 +
// ((0    & 0xff) << 24) | // unused
 +
// ((0    & 0xff) << 16) | // reserved
 +
// ((BPS  & 0x01) << 15) | // RPS Flag Blocked Parts
 +
// ((HPS  & 0x01) << 14) | // RPS Flag Hiden Parts
 +
// ((RPS  & 0x07) << 11) | // RPS VErsion
 +
((ICSv2 & 0x07) << 8 ) | // ICSv2 Version
 +
// ((0    & 0x0f) << 4 ) | // reserved
 +
((nSCT  & 0x0f) << 0 );  // SCT version
 +
CTag tagPartStatus(CT_EXT_FILESTATUS,uFileStatus);
 
tagPartStatus.WriteNewEd2kTag(&data);
 
tagPartStatus.WriteNewEd2kTag(&data);
  
// write the secund tag (Nr.2)
+
#ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
// in this sample its an custom named tag with an string as ID
+
if(theApp.IsFirewalled() && Kademlia::CKademlia::IsConnected())
CTag tagMyMail("Mod:eMail",_T("User@Domain.com"));
+
{
 +
// Note: to connect a cleint over his buddy or to request a calback we need not only his buddy IP/Port but also his Buddy ID
 +
// So to get this realy to work we need to transmitt the buddy ID to
 +
Kademlia::CUInt128 uBuddyID(true);
 +
uBuddyID.Xor(Kademlia::CKademlia::GetPrefs()->GetKadID());
 +
byte cID[16];
 +
uBuddyID.ToByteArray(cID);
 +
CTag tagBuddyID(CT_EMULE_BUDDYID, cID);
 +
tagBuddyID.WriteNewEd2kTag(&data);
 +
}
 +
#endif //NATTUNNELING // NEO: NATT END
 +
 
 +
// Named tag test begin
 +
LPCTSTR FunnyStr[3];
 +
FunnyStr[0] = _T("Vote for the Pirate Party of your country");
 +
FunnyStr[1] = _T("Have a nice day ;)");
 +
FunnyStr[2] = _T("Confucius says: If you dont upload 10 GB/day good will punish you");
 +
CTag tagMyMail("Mod:Hello",FunnyStr[rand()%ARRSIZE(FunnyStr)]);
 
tagMyMail.WriteNewEd2kTag(&data);
 
tagMyMail.WriteNewEd2kTag(&data);
+
// Named tag test end
// we are done writing tags
+
  
// now we create a packet and put what we have writen in it
 
 
Packet* packet = new Packet(&data,OP_MODPROT);
 
Packet* packet = new Packet(&data,OP_MODPROT);
 
packet->opcode = OP_MODINFOPACKET;
 
packet->opcode = OP_MODINFOPACKET;
Line 152: Line 184:
 
DebugSend("OP__ModInfoPacket", this);
 
DebugSend("OP__ModInfoPacket", this);
 
theStats.AddUpDataOverheadOther(packet->size);
 
theStats.AddUpDataOverheadOther(packet->size);
socket->SendPacket(packet,true,true); // we send the packet
+
socket->SendPacket(packet,true,true);
 
}
 
}
 
</pre>
 
</pre>
  
=== Delaying ConnectionEstablished & sending the mod info packet ===
+
=== process modinfo packet ===
 
+
listensocket.cpp
+
bool CClientReqSocket::ProcessPacket(const BYTE* packet, uint32 size, UINT opcode)
+
<pre>
+
case OP_HELLOANSWER:
+
{
+
theStats.AddDownDataOverheadOther(size);
+
client->ProcessHelloAnswer(packet,size);
+
if (thePrefs.GetDebugClientTCPLevel() > 0){
+
DebugRecv("OP_HelloAnswer", client);
+
Debug(_T("  %s\n"), client->DbgGetHelloInfo());
+
}
+
 
+
// NEO: NMP - [NeoModProt] -- Xanatos -->
+
if(client->SupportsModProt() == 0) // check for mod prot
+
// we will start the SUI when we recieve the mod info packet
+
// NEO: NMP END <-- Xanatos --
+
{
+
// start secure identification, if
+
//  - we have received OP_EMULEINFO and OP_HELLOANSWER (old eMule)
+
// - we have received eMule-OP_HELLOANSWER (new eMule)
+
if (client->GetInfoPacketsReceived() == IP_BOTH)
+
client->InfoPacketsReceived();
+
}
+
 
+
if (client)
+
{
+
// NEO: NMP - [NeoModProt] -- Xanatos -->
+
if (client->SupportsModProt()) // if this cleint uses mod protocol extensions
+
client->SendModInfoPacket(); // we send him the mod info packet with our rxtensions
+
else // we *dont* call ConnectionEstablished at this point,
+
// when will call ConnectionEstablished when we recieve the Mod Info frm this cleint
+
// NEO: NMP END <-- Xanatos --
+
{
+
client->ConnectionEstablished();
+
theApp.emuledlg->transferwnd->clientlistctrl.RefreshClient(client);
+
}
+
}
+
break;
+
}
+
</pre>
+
 
+
listensocket.cpp
+
bool CClientReqSocket::ProcessPacket(const BYTE* packet, uint32 size, UINT opcode)
+
<pre>
+
case OP_HELLO:
+
{
+
[..................]
+
 
+
if (client)
+
{
+
// NEO: NMP - [NeoModProt] -- Xanatos -->
+
if(client->SupportsModProt()) // if this cleint uses mod protocol extensions
+
client->SendModInfoPacket(); // we send him the mod info packet with our rxtensions
+
else // we *dont* call ConnectionEstablished at this point,
+
// when will call ConnectionEstablished when we recieve the Mod Info frm this cleint
+
// NEO: NMP END <-- Xanatos --
+
client->ConnectionEstablished();
+
}
+
 
+
ASSERT( client );
+
if(client)
+
{
+
// NEO: NMP - [NeoModProt] -- Xanatos -->
+
if(client->SupportsModProt() == 0) // check for mod prot
+
// we will start the SUI when we recieve the mod info packet
+
// NEO: NMP END <-- Xanatos --
+
{
+
 
+
// start secure identification, if
+
// - we have received eMule-OP_HELLO (new eMule)
+
if (client->GetInfoPacketsReceived() == IP_BOTH)
+
client->InfoPacketsReceived();
+
}
+
 
+
if( client->GetKadPort() )
+
Kademlia::CKademlia::Bootstrap(ntohl(client->GetIP()), client->GetKadPort(), (client->GetKadVersion() > 1));
+
}
+
break;
+
}
+
</pre>
+
 
+
=== Processing the modinfo packet ===
+
  
 
listensocket.cpp
 
listensocket.cpp
Line 298: Line 247:
 
CSafeMemFile data(pachPacket, nSize);
 
CSafeMemFile data(pachPacket, nSize);
  
// we read now the amount of tags that the sender put in th epacket
 
 
uint32 tagcount = data.ReadUInt32();
 
uint32 tagcount = data.ReadUInt32();
 
if (bDbgInfo)
 
if (bDbgInfo)
 
m_strModInfo.AppendFormat(_T("  Tags=%u"), (UINT)tagcount);
 
m_strModInfo.AppendFormat(_T("  Tags=%u"), (UINT)tagcount);
// now we are going to read all of them
 
 
for (uint32 i = 0; i < tagcount; i++)
 
for (uint32 i = 0; i < tagcount; i++)
 
{
 
{
 
CTag temptag(&data, false);
 
CTag temptag(&data, false);
switch (temptag.GetNameID()) // here we distinguish only tags with an uint8 ID, all named tags are handled below
+
switch (temptag.GetNameID())
 
{
 
{
case 0x55:
+
case CT_NEO_FEATURES:
if (temptag.IsStr())
+
if (temptag.IsInt()){
Log(_T("ModString %s", temptag.GetStr()));
+
// = (uint8)(temptag.GetInt() >> 24) & 0xff;
else if (bDbgInfo)
+
// = (uint8)(temptag.GetInt() >> 20) & 0x0f;
m_strModInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
+
#ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
 +
// = (uint8)(temptag.GetInt() >> 18) & 0x03;
 +
m_PublicPortReport = (uint8)(temptag.GetInt() >> 17) & 0x01; // NEO: RTP - [ReuseTCPPort]
 +
m_SupportsNatTraversal = (uint8)(temptag.GetInt() >> 16) & 0x01;
 +
// = (uint8)(temptag.GetInt() >> 15) & 0x01; // NEO: XSB - [XSBuddy]
 +
#endif //NATTUNNELING // NEO: NATT END
 +
m_NeoXSVersion = (uint8)(temptag.GetInt() >> 12) & 0x07; // NEO: NXS - [NeoXS]
 +
// = (uint8)(temptag.GetInt() >> 10) & 0x03;
 +
m_LowIDUDPPingSupport = (uint8)(temptag.GetInt() >> 9 ) & 0x01;
 +
m_UnsolicitedPartStatus = (uint8)(temptag.GetInt() >> 8 ) & 0x01;
 +
// = (uint8)(temptag.GetInt() >> 4 ) & 0x0f;
 +
// = (uint8)(temptag.GetInt() >> 0 ) & 0x0f;
 +
}else if (bDbgInfo)
 +
m_strHelloInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
 
break;
 
break;
  
 +
case CT_EXT_FILESTATUS:
 +
if (temptag.IsInt()){
 +
 +
// X-ToDo
 +
// = (uint8)(temptag.GetInt() >> 24) & 0xff;
 +
// = (uint8)(temptag.GetInt() >> 16) & 0xff;
 +
//uint8 BlockedPartStatus = (uint8)(temptag.GetInt() >> 15) & 0x01;
 +
//uint8 HidenPartStatus = (uint8)(temptag.GetInt() >> 14) & 0x01;
 +
//uint8 RealPartStatusVer = (uint8)(temptag.GetInt() >> 11) & 0x07;
 +
m_IncompletePartVer = (uint8)(temptag.GetInt() >> 8 ) & 0x07;
 +
// = (uint8)(temptag.GetInt() >> 4 ) & 0x0f;
 +
m_SubChunksVer = (uint8)(temptag.GetInt() >> 0 ) & 0x0f;
 +
 +
//ASSERT(BlockedPartStatus || HidenPartStatus || !RealPartStatusVer);
 +
// Note: RPC version without one or booth RPS flags is invalid,
 +
//      the cleint must always say wha is he doint gith the parts 'blocking and hiding' or 'only hiding',
 +
//      or he can booth depanding on the situation
 +
// Booth RPS versions have always teh same version as the writing functions are identical
 +
// just other opcodes are used and other part states notifyed
 +
//if(BlockedPartStatus)
 +
// m_BlockedPartStatusVer = RealPartStatusVer;
 +
//if(HidenPartStatus)
 +
// m_HidenPartStatusVer = RealPartStatusVer;
 +
 +
}else if (bDbgInfo)
 +
m_strModInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
 +
break;
 +
#ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
 +
case CT_EMULE_BUDDYID:
 +
if(temptag.IsHash())
 +
{
 +
SetBuddyID(temptag.GetHash());
 +
}
 +
else{
 +
if (bDbgInfo)
 +
m_strModInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
 +
}
 +
break;
 +
#endif //NATTUNNELING // NEO: NATT END
 
default:
 
default:
  
// now we habdle custom named tags, we use a series of (else)if's and strcmp, note: this is *not* unicide!!!
+
// Named tag test begin
 
if(strcmp(temptag.GetName(),"Mod:Hello") == 0)
 
if(strcmp(temptag.GetName(),"Mod:Hello") == 0)
 
{
 
{
Line 324: Line 323:
 
}
 
}
 
else
 
else
 +
// Named tag test end
  
 
if (bDbgInfo)
 
if (bDbgInfo)
Line 329: Line 329:
 
}
 
}
 
}
 
}
 
// some debug output
 
if (bDbgInfo && data.GetPosition() < data.GetLength()){
 
m_strModInfo.AppendFormat(_T("\n  ***AddData: %u bytes"), data.GetLength() - data.GetPosition());
 
}
 
}
 
  
 
</pre>
 
</pre>
  
=== Processing mod data example ===
 
  
EMSocket.cpp
+
 
void CEMSocket::OnReceive(int nErrorCode)
+
 
<pre>
+
 
switch (pendingPacket->prot){
+
 
case OP_EDONKEYPROT:
+
 
case OP_PACKEDPROT:
+
 
case OP_EMULEPROT:
+
 
// NEO: NMP - [NeoModProt] -- Xanatos -->
+
 
// We have to accept also mod packet
+
 
case OP_MODPACKEDPROT:
+
 
case OP_MODPROT:
+
=== proces mod data example ===
// NEO: NMP END <-- Xanatos --
+
 
break;
+
 
default:
+
 
EMTrace("CEMSocket::OnReceive ERROR Wrong header");
+
 
delete pendingPacket;
+
pendingPacket = NULL;
+
OnError(ERR_WRONGHEADER);
+
return;
+
}
+
</pre>
+
  
  
Line 367: Line 354:
 
<pre>
 
<pre>
 
// NEO: NMP - [NeoModProt] -- Xanatos -->
 
// NEO: NMP - [NeoModProt] -- Xanatos -->
// dispatch mod packets to the right processing functions
 
 
case OP_MODPACKEDPROT:
 
case OP_MODPACKEDPROT:
 
if (!packet->UnPackPacket()){
 
if (!packet->UnPackPacket()){
Line 387: Line 373:
 
try
 
try
 
{
 
{
// we must have a cleint at this point !always!
 
 
if (!client)
 
if (!client)
 
{
 
{
Line 396: Line 381:
 
ASSERT_VALID(client);
 
ASSERT_VALID(client);
  
switch(opcode) // dispatch particular packets
+
switch(opcode)
 
{
 
{
// for the mod prot v1 (capability exchange) only this one packet is relevant, the mod info packet
 
 
case OP_MODINFOPACKET:
 
case OP_MODINFOPACKET:
 
{
 
{
Line 405: Line 389:
 
theStats.AddDownDataOverheadOther(uRawSize);
 
theStats.AddDownDataOverheadOther(uRawSize);
  
if(client->SupportsModProt() == 0) // just pure formality
+
if(client->GetNeoModProtVersion() == 0)
 
throw CString(_T("Recieved Neo Mod Info Packet from a cleint whitch doe snot support this feature!"));
 
throw CString(_T("Recieved Neo Mod Info Packet from a cleint whitch doe snot support this feature!"));
  
// Process the packet
 
 
client->ProcessModInfoPacket(packet,size);
 
client->ProcessModInfoPacket(packet,size);
  
Line 421: Line 404:
 
}
 
}
  
default: // handle unknown packets
+
// NEO: NMPm - [NeoModProtMultiPacket]
+
case OP_MODMULTIPACKET:
 +
{
 +
if (thePrefs.GetDebugClientTCPLevel() > 0)
 +
DebugRecv("OP_ModMultiPacket", client, (size >= 24) ? packet : NULL);
 +
 
 +
theStats.AddDownDataOverheadFileRequest(uRawSize);
 +
client->CheckHandshakeFinished();
 +
 
 +
CSafeMemFile data_in(packet, size);
 +
uchar reqfilehash[16];
 +
data_in.ReadHash16(reqfilehash);
 +
CKnownFile* reqfile;
 +
if ( (reqfile = theApp.sharedfiles->GetFileByID(reqfilehash)) == NULL ){
 +
if ( !((reqfile = theApp.downloadqueue->GetFileByID(reqfilehash)) != NULL
 +
&& reqfile->GetFileSize() > (uint64)PARTSIZE) ){
 +
client->CheckFailedFileIdReqs(reqfilehash);
 +
break;
 +
}
 +
}
 +
 
 +
CClientFileStatus* status = client->GetFileStatus(reqfile, true); // NEO: SCFS - [SmartClientFileStatus]
 +
 
 +
client->ReadModMultiPacket(&data_in,reqfile,status);
 +
// NEO: BPS - [BetterPassiveSourceFinding]
 +
//if(reqfile->IsPartFile() && !(client->GetDownloadState()==DS_ONQUEUE && reqfile==client->GetRequestFile()))
 +
// client->ProcessModFileStatus(true, status, (CPartFile*)reqfile, true); // NEO: SCFS - [SmartClientFileStatus]
 +
// NEO: BPS END
 +
 
 +
///////////////////// answer
 +
 
 +
CSafeMemFile data_out(128);
 +
data_out.WriteHash16(reqfile->GetFileHash());
 +
 
 +
client->WriteModMultiPacket(&data_out, reqfile, status, false);
 +
 
 +
if (data_out.GetLength() > 16)
 +
{
 +
if (thePrefs.GetDebugClientTCPLevel() > 0)
 +
DebugSend("OP__ModMultiPacketAns", client, reqfile->GetFileHash());
 +
Packet* reply = new Packet(&data_out, OP_MODPROT);
 +
reply->opcode = OP_MODMULTIPACKETANSWER;
 +
theStats.AddUpDataOverheadFileRequest(reply->size);
 +
SendPacket(reply, true);
 +
}
 +
break;
 +
}
 +
case OP_MODMULTIPACKETANSWER:
 +
{
 +
if (thePrefs.GetDebugClientTCPLevel() > 0)
 +
DebugRecv("OP_ModMultiPacketAns", client, (size >= 16) ? packet : NULL);
 +
 
 +
theStats.AddDownDataOverheadFileRequest(uRawSize);
 +
client->CheckHandshakeFinished();
 +
 
 +
CSafeMemFile data_in(packet, size);
 +
uchar reqfilehash[16];
 +
data_in.ReadHash16(reqfilehash);
 +
CPartFile* reqfile = theApp.downloadqueue->GetFileByID(reqfilehash);
 +
//Make sure we are downloading this file.
 +
if (reqfile==NULL){
 +
client->CheckFailedFileIdReqs(reqfilehash);
 +
throw GetResString(IDS_ERR_WRONGFILEID) + _T(" (OP_MODMULTIPACKETANSWER; reqfile==NULL)");
 +
}
 +
if (client->GetRequestFile()==NULL)
 +
throw GetResString(IDS_ERR_WRONGFILEID) + _T(" (OP_MODMULTIPACKETANSWER; client->GetRequestFile()==NULL)");
 +
if (reqfile != client->GetRequestFile())
 +
throw GetResString(IDS_ERR_WRONGFILEID) + _T(" (OP_MODMULTIPACKETANSWER; reqfile!=client->GetRequestFile())");
 +
 
 +
CClientFileStatus* status = client->GetFileStatus(reqfile, true); // NEO: SCFS - [SmartClientFileStatus]
 +
 
 +
client->ReadModMultiPacket(&data_in,reqfile,status);
 +
client->ProcessModFileStatus(false, status, reqfile);
 +
 
 +
break;
 +
}
 +
// NEO: NMPm END
 +
 
 +
// NEO: SCT - [SubChunkTransfer]
 +
case OP_SUBCHUNKMAPS:
 +
{
 +
if (thePrefs.GetDebugClientTCPLevel() > 0)
 +
DebugRecv("OP_SubChunkMaps", client, (size >= 16) ? packet : NULL);
 +
theStats.AddDownDataOverheadFileRequest(size);
 +
 
 +
CSafeMemFile data(packet, size);
 +
uchar cfilehash[16];
 +
data.ReadHash16(cfilehash);
 +
 
 +
CPartFile* reqfile = theApp.downloadqueue->GetFileByID(cfilehash);
 +
if (reqfile == NULL){
 +
client->CheckFailedFileIdReqs(cfilehash);
 +
break;
 +
}
 +
 
 +
CClientFileStatus* status = client->GetFileStatus(reqfile, true);
 +
status->ReadSubChunkMaps(&data);
 +
if(client->GetDownloadState() == DS_NONEEDEDPARTS) // the file must be NNP or we will perform a secund unned ask
 +
client->ProcessModFileStatus(false, status, reqfile);
 +
break;
 +
}
 +
// NEO: SCT END
 +
 
 +
case OP_FILEINCSTATUS:
 +
//case OP_FILEHIDENSTATUS:
 +
//case OP_FILEBLOCKEDSTATUS:
 +
{
 +
EPartStatus type = CFS_Normal;
 +
switch(opcode){
 +
// NEO: ICS - [InteligentChunkSelection]
 +
case OP_FILEINCSTATUS:
 +
type = CFS_Incomplete;
 +
if (thePrefs.GetDebugClientTCPLevel() > 0)
 +
DebugRecv("OP_FileImcompleteStatus", client, (size >= 16) ? packet : NULL);
 +
break;
 +
// NEO: ICS END
 +
// NEO: RPS - [RealPartStatus]
 +
/*case OP_FILEHIDENSTATUS:
 +
type = CFS_Hiden;
 +
if (thePrefs.GetDebugClientTCPLevel() > 0)
 +
DebugRecv("OP_FileHidenStatus", client, (size >= 16) ? packet : NULL);
 +
break;
 +
case OP_FILEBLOCKEDSTATUS:
 +
type = CFS_Blocked;
 +
if (thePrefs.GetDebugClientTCPLevel() > 0)
 +
DebugRecv("OP_FileBlockedStatus", client, (size >= 16) ? packet : NULL);
 +
break;*/
 +
// NEO: RPS END
 +
}
 +
theStats.AddDownDataOverheadFileRequest(size);
 +
 
 +
CSafeMemFile data(packet, size);
 +
uchar cfilehash[16];
 +
data.ReadHash16(cfilehash);
 +
 
 +
CKnownFile* reqfile = theApp.sharedfiles->GetFileByID(cfilehash);
 +
if(reqfile == NULL)
 +
reqfile = (CKnownFile*)theApp.downloadqueue->GetFileByID(cfilehash);
 +
if (reqfile == NULL){
 +
client->CheckFailedFileIdReqs(cfilehash);
 +
break;
 +
}
 +
 
 +
CClientFileStatus* status = client->GetFileStatus(reqfile, true);
 +
status->ReadFileStatus(&data, type);
 +
reqfile->UpdatePartsInfoEx(type);
 +
//if(reqfile->IsPartFile() && client->GetDownloadState() == DS_NONEEDEDPARTS && opcode == OP_FILEHIDENSTATUS) // only hidden status is interresant
 +
// client->ProcessModFileStatus(false, status, (CPartFile*)reqfile, false, false, true);
 +
break;
 +
}
 +
 
 +
#ifdef NATTUNNELING // NEO: RTP - [ReuseTCPPort]
 +
case OP_PUBLICPORT_ANSWER:
 +
{
 +
if (thePrefs.GetDebugClientTCPLevel() > 0)
 +
DebugRecv("OP_PublicPortAns", client);
 +
theStats.AddDownDataOverheadOther(uRawSize);
 +
 
 +
client->ProcessPublicPortAnswer(packet, size);
 +
break;
 +
}
 +
case OP_PUBLICPORT_REQ:
 +
{
 +
if (thePrefs.GetDebugClientTCPLevel() > 0)
 +
DebugRecv("OP_PublicPortReq", client);
 +
theStats.AddDownDataOverheadOther(uRawSize);
 +
 
 +
if (thePrefs.GetDebugClientTCPLevel() > 0)
 +
DebugSend("OP__PublicPortAns", client);
 +
Packet* pPacket = new Packet(OP_PUBLICPORT_ANSWER, 2, OP_MODPROT);
 +
 
 +
SOCKADDR_IN sockAddr = {0};
 +
int nSockAddrLen = sizeof(sockAddr);
 +
GetPeerName((SOCKADDR*)&sockAddr, &nSockAddrLen);
 +
uint16 Port = ntohs(sockAddr.sin_port);
 +
 
 +
PokeUInt16(pPacket->pBuffer, Port);
 +
theStats.AddUpDataOverheadOther(pPacket->size);
 +
SendPacket(pPacket);
 +
break;
 +
}
 +
#endif //NATTUNNELING // NEO: RTP END
 +
 
 +
// NEO: NXS - [NeoXS]
 +
case OP_ANSWERSOURCES:
 +
ProcessExtPacket(packet, size, opcode, uRawSize); // we use the same propacket processor as for the official XS
 +
break;
 +
// NEO: NXS END
 +
 
 +
default:
 
theStats.AddDownDataOverheadOther(uRawSize);
 
theStats.AddDownDataOverheadOther(uRawSize);
 
PacketToDebugLogLine(_T("ModProt"), packet, size, opcode);
 
PacketToDebugLogLine(_T("ModProt"), packet, size, opcode);
Line 449: Line 620:
 
}
 
}
 
return true;
 
return true;
 
+
}
 
// NEO: NMP END <-- Xanatos --
 
// NEO: NMP END <-- Xanatos --
 
</pre>
 
</pre>
  
=== Additional modifications ===
+
== backward compatibility ==
 
+
Packets.cpp
+
void Packet::PackPacket()
+
<pre>
+
// NEO: NMP - [NeoModProt] -- Xanatos -->
+
if( prot == OP_MODPROT )
+
prot = OP_MODPACKEDPROT;
+
else
+
// NEO: NMP END <-- Xanatos --
+
if( prot == OP_KADEMLIAHEADER )
+
prot = OP_KADEMLIAPACKEDPROT;
+
else
+
prot = OP_PACKEDPROT;
+
</pre>
+
 
+
Packets.cpp
+
bool Packet::UnPackPacket(UINT uMaxDecompressedSize)
+
<pre>
+
// NEO: NMP - [NeoModProt] -- Xanatos -->
+
if( prot == OP_MODPACKEDPROT )
+
prot = OP_MODPROT;
+
else
+
// NEO: NMP END <-- Xanatos --
+
if( prot == OP_KADEMLIAPACKEDPROT )
+
prot = OP_KADEMLIAHEADER;
+
else
+
prot =  OP_EMULEPROT;
+
</pre>
+
 
+
== Backward compatibility ==
+
 
+
The modstring is still send via hello(answer) packets but '''only''' if the remote client is using a mod and does not support the mod prot extension to maintain backward compatibility. Usage of CT_MOD_VERSION is proposed to move it to the mod protocol. A mod using the modbit MUST identify itself either via CT_MOD_VERSION in the hello(answer) packets or via modstring in the modinfo packet.
+
'''NOTE:''' a mod that uses extensions but refuses to identify itself will most likely be considered a bad mod by some antileecher systems
+
 
+
The proposed check to use would be like
+
<pre>
+
void CUpDownClient::SendHelloTypePacket(CSafeMemFile* data)
+
{
+
...
+
...
+
uint32 tagcount = 6;
+
 
+
if( theApp.clientlist->GetBuddy() && theApp.IsFirewalled() )
+
tagcount += 2;
+
 
+
//>>> MODPROT::Send Modstring to old mods only
+
const bool bSendModString = !SupportsModProt() && (!m_strModVersion.IsEmpty() || !m_pszUsername);
+
if(bSendModString)
+
++tagcount;
+
//<<< MODPROT::Send Modstring to old mods only
+
 
+
data->WriteUInt32(tagcount);
+
...
+
...
+
tagMuleVersion.WriteTagToFile(data);
+
 
+
//>>> MODPROT::Send Modstring to old mods only
+
if(bSendModString)
+
{
+
CTag tagMod(CT_MOD_VERSION, L"My Mod String");
+
tagMod.WriteTagToFile(data);
+
}
+
//<<< MODPROT::Send Modstring to old mods only
+
 
+
uint32 dwIP;
+
uint16 nPort;
+
...
+
...
+
</pre>
+
and similar for the info packet.
+
 
+
 
+
== OPCODE defines ==
+
<pre>
+
OP_MODPROT      0x4D
+
OP_MODPACKEDPROT 0x6D
+
OP_MODINFOPACKET 0x01
+
</pre>
+
 
+
== TAG defines ==
+
 
+
Tags used must be reserved in modprot topic at http://forum.emule-project.net/
+
Sources must be published within 3 months after claiming a tag.
+
 
+
The range 0x01 - 0x1F is completely reserved.
+
 
+
Tags in the range from 0x20 - 0x7E are reserved for major features, possible objections can be:
+
#Modder uses too many tags (if you need more than 5 tags you are most likely doing something wrong. Note that string tags are also available - those are not regulated)
+
#Utterly useless or unimplementable feature (no other mod will ever use it)
+
#Illegal feature (should be clear)
+
 
+
The range 0x7F-FF is open and you can claim any free tag you want, only objection can be the usage of too many tags (e.g. someone claims to need a range from 0x80 to 0xAF).
+
 
+
{| style="font-size: 85%; text-align: Left;Border="1";
+
! rowspan=2 | TAGNAME
+
! rowspan=2 | VALUE
+
! rowspan=2 | Meaning
+
! rowspan=2 | Reserved by / source code
+
|-
+
|
+
|-
+
|MISC_PROTOCOL_EXTENSIONS
+
| 'M' 4D
+
| used for full mod extensions like ICS, etc..
+
| basic modprot
+
|-
+
|MISC_PROTOCOL_EXTENSIONS2
+
| 'm' 6D
+
| used for full mod extensions 2, reserved for future use
+
| basic modprot
+
|-
+
|CT_MOD_VERSION
+
| 'U' 0x55
+
| Modstring
+
| basic modprot
+
|-
+
|KAD_EMULE_BUDDYID
+
| '@' 40
+
| [[NatT_protocol|NatT]]
+
| David Xanatos
+
|-
+
|XS_EMULE_BUDDYIP
+
| 'B' 42
+
| [[NatT_protocol|NatT]]
+
| David Xanatos
+
|-
+
|XS_EMULE_BUDDYUDP
+
| 'b' 62
+
| [[NatT_protocol|NatT]]
+
| David Xanatos
+
|-
+
|NEO_PROTOCOL_EXTENSIONS
+
|'N' 4E
+
| etc.
+
| David Xanatos
+
|-
+
|NEO_PROTOCOL_EXTENSIONS2
+
|'n' 6E
+
| reserved for future Neo features
+
| David Xanatos
+
|-
+
|}
+
 
+
 
+
* MISC_PROTOCOL_EXTENSIONS:
+
 
+
  [bit 1]  // Unsolicited Part Status (idea from netfinity, allows our client ro recieve filestatus at any time)
+
  [bit 2]  // LowID UDP Ping Support (notifyes a fix form xman1 that  allow the remote low ID to use udp reasks)
+
  [bit 3]  // [[Mod_Multi_Packet#ICS|ICSv2]] New Official Version
+
  [bit 4]  // UDP Mod File Status*
+
  [bit 5]  // [[NatT_protocol|NATT]] - [NatTraversal], [[NatT_protocol#XS Callback|XSB]] - [XSBuddy], [[NatT_protocol#Port Reporting|RPT]] - [ReuseTCPPort]
+
  [bit 6]  // [[NatT_protocol#Neo XS|NXS]] - [NeoXS]
+
  [bit 7]  // [[CommentsV2|SF comments v2]]
+
  [bit 8]  // [[Mod_Multi_Packet#SCT|SCT]]
+
  [bit 9]  // [[L2HAC|L2HAC]]
+
  
 +
Modstring is still send and replied in hello packet to maintain backward compatibility However a opcode for modstring will be defined for those who alos want to move it to the mod protocol
  
<nowiki>*</nowiki> The UDP Mod File Status bit is not only used for ICS but used in general. It also tells whether Mod Multi Packet with extended mod status should be sent over UDP or not.
 
  
== See also ==
 
  
References to emule protocol...
+
== tags ==
[[category:Mod_protocol_extensions]]
+

Please note that all contributions to EMule Wiki may be edited, altered, or removed by other contributors. If you do not want your writing to be edited mercilessly, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource (see EMule Wiki:Copyrights for details). Do not submit copyrighted work without permission!

Cancel | Editing help (opens in new window)
Personal tools