Gnutella Forums

Gnutella Forums (https://www.gnutellaforums.com/)
-   General Gnutella Development Discussion (https://www.gnutellaforums.com/general-gnutella-development-discussion/)
-   -   Help On Gnutella Protocol (https://www.gnutellaforums.com/general-gnutella-development-discussion/6641-help-gnutella-protocol.html)

Unregistered December 23rd, 2001 02:05 PM

Help On Gnutella Protocol
 
I am trying to make simple component that makes a connection to a Gnutella client. Right now i managed to get a "GNUTELLA OK" reply but when i send back a ping message the connection drops.
I read that i should send a ping after getting the OK from the client. Is this right? What am i doing wrong? :confused:
The component is written in Delphi with the TWsocket component.

Moak December 25th, 2001 08:13 AM

Hmm... which test clients do you use? Did you tried to connect to your own client?

veniamin December 25th, 2001 02:10 PM

I built a simple test program that uses this component and i try to connect to other Gnutella clients, localy on my computer, like Gnotella and Bearshare.
I succeed to send a GNUTELLA CONNECT/0.4 and also i take the right reply (GNUTELLA OK) but when i send a Ping message, i always disconnect.
Any help? :confused:

Moak December 25th, 2001 02:37 PM

Perhaps you did send a bad package/descriptor, maybe ping with payload or a strange TTL? Try to check protocol specifications once more or take a look in existing source code.

Hope it helps, Moak :)

Moak December 25th, 2001 02:56 PM

PS: GodXBlue gave me another hint on IRC. Make sure you follow the protocoll specification for connectiing and send only 'GNUTELLA CONNECT/0.4\n\n'... and NOTHING more! Each extra byte is definitely wrong here and will corrupt your data stream, e.g. any following descriptor will be corrupted.

veniamin December 25th, 2001 04:05 PM

When i send the GNUTELLA CONNECT/0.4\n\n string it is ok because i have tested it and i take a succesful reply (GNUTELLA OK).

The structure of the Ping message that i send is exactly the same with the protocol specifications. The GUID is beeing created with the CoCreateGUID function of the Windows API and the TTL value is 5. Also the HOPs value is 0 and the data length is zero.

When i am trying to connect to Bearshare at the Hosts Screen in the status of the connection writes 'Coming' and when i connect writes 'Temp' and counts about 5 seconds and then i get a disconnect time expired message...
:confused:

Moak December 25th, 2001 04:20 PM

You automatically get a "GNUTELLA OK" after sending the two returns (\n). When you will send extra bytes after the two returns, you will shift your binary data stream and every following descriptor will be corrupted... did you understand this and checked against it? Most existing clients will drop a connection when they receive bad data. Sorry, I have no further idea.... perhaps look inside existing code or test if two of your clients will understand each other?

veniamin December 25th, 2001 04:32 PM

hmmm... i understand...

I will see my source code again and i will inform you... Thank you..:D

Moak December 26th, 2001 04:56 AM

Heyho again! Did you find the problem? *curious* :)

Ramihyn December 28th, 2001 09:39 AM

You may have a problem with variable alignment if you created a structure for the descriptor and fill the members of it. Ofc it depends on the type of variables you used, your compiler and it's alignment.

If you created your own structure (typedef struct {} in C), you may want to add a safety check at the initialisation code which tests for the sizeof() of the struct.

veniamin December 28th, 2001 12:54 PM

I made more tests with my code and after reading Ramihyn's message i found this bug(?)

I declared a record for the header of each message something like:
Header = Record
ID: TGUID;
Function: Byte;
TTL:byte;
Hops:byte;
Datalength: Integer(???)
end;

in the last line i declared the data length as an Integer (it is 4 bytes) which is acceptable for the Gnutella Protocol but when i send a ping message with datalength value as zero the server got a response of 33 00 00 00h instead of 00 00 00 00h. So i declared Datalength as a DWORD (which is also 4 bytes) and the problem fixed. Maybe there are more bugs like this one...

Thak you for your help... :D

cultiv8r December 28th, 2001 09:04 PM

Quote:

Originally posted by veniamin

Header = Record
ID: TGUID;
Function: Byte;
TTL:byte;
Hops:byte;
Datalength: Integer(???)
end;

Ah! Someone's using Delphi (or Pascal)! :)

Well, for that, I will give you the records used in my Cultiv8r client :p

Hopefully you can use them. Keep in mind that the records are packed! I'm using pointers to them, because I can easily reference them from memory that way - I read the entire message before processing.

Code:

Type
  // AKA Descriptor Header
  _PGHeader = ^_TGHeader;
  _TGHeader = packed record
    MsgID  : TGUID;
    Func    : byte;
    TTL    : byte;
    Hops    : byte;
    DataLen : integer;
  end;

  _PPong = ^_TPong;
  _TPong = packed record // 0x01
    Port      : word;
    IP        : integer;
    FileCount : dword;
    TotalSize : dword;
  end;

  // BYE packet - this is a proposal, see the GDF
  _PByeHead = ^_TByeHead;
  _TByeHead = packed record // 0x02
    Code : word;
  end;

  // Query Hit
  _PQueryResultHeader = ^_TQueryResultHeader;
  _TQueryResultHeader = packed record // 0x81
    Results : byte;
    Port    : word;
    IP      : integer;
    Speed  : integer;
  end;

  // Query Hit Result set
  _PQueryResultRecordHeader = ^_TQueryResultRecordHeader;
  _TQueryResultRecordHeader = packed record
    FileIndex : integer;
    FileSize  : integer;
  end;

  // Just the vendor ID m'am!
  _PQueryResultFooterExtensionHeader = ^_TQueryResultFooterExtensionHeader;
  _TQueryResultFooterExtensionHeader = packed record
    VendorID : array[0..3] of char;
  end;

  //  EQHD As used by many clients, ala BearShare
  _PQueryResultFooterExtensionDataOne = ^_TQueryResultFooterExtensionDataOne;
  _TQueryResultFooterExtensionDataOne = packed record
    DataLength : byte;
    Flag1,
    Flag2      : byte;
  end;

  // The GUID at the very end of the Query Hit
  _PQueryResultFooter = ^_TQueryResultFooter;
  _TQueryResultFooter = packed record
    ClientID : TGUID;
  end;

  // Push baby, Push!
  _PPush = ^_TPush;
  _TPush = packed record
    ClientID  : TGUID;
    FileIndex : integer;
    IP        : integer;
    Port      : integer;
  end;

Also, most newer clients use GUID marking. So you could use this snippet for creating your GUIDs:

Code:

function CreateGUID : TGUID;
begin
  CoCreateGUID(Result);

  Result.D4[0] := $FF;
  Result.D4[7] := $0;
end;

-- Mike

Morgwen December 29th, 2001 01:45 AM

Hi Mike!

Nice to see you here! :)

Morgwen

veniamin December 29th, 2001 01:38 PM

Thank you a lot cultiv8r... but i have them... :D

except the snippet for the GUID markink...

my problem is that i cant make my client to connect to another servant.
i send the GNUTELLA CONNECT/0.4, i take the right reply and then nothing...
even if i send a ping message the servant disconnects me.:confused:

cultiv8r December 29th, 2001 01:50 PM

You've got to make sure that the client accepts incoming connections and connections from a local host (local loop for example).

I recommend getting Gnucleus, since this client is following the Gnutella specs quite closely. The more widely spread ones, like BearShare, have a tendency to do things their own way.

It is also very important that you send nothing more for each packet than specified in the descriptor's payload length, hence my use of packed records, etc. The TTL should be > 0 and the Hops should be set at 0.

If that fails, try outputting (like in a Tmemo object) what you and the other side have sent.

-- Mike

veniamin January 2nd, 2002 01:03 PM

I have finally managed to connect to another servant.
I used the Gnotella client and made a connections succesful. I also tried to connect using Bearshare but it always disconnects my client. Thank you people for your help.:D

veniamin January 5th, 2002 01:34 PM

any Delphi Programmers outhere?

I am trying to "understand" the data receiving from a connection. I am using a TMemoryStream as a buffer and i manage to "understand" the first Pong Reply. After that i am getting raw data. Any help? Maybe a pseydo code will help.:D

cultiv8r January 5th, 2002 04:15 PM

Always read the header first. Then read the amount of bytes specified in the Payload Descriptor, whether or not it is too big for that particular message. You then handle the data you DO know (like with a pong, you know where the IP and port is located). For the data that you DON'T know, you dump on screen or in a log file so you can inspect the data (or, say, load it into a hex editor).

-- Mike


All times are GMT -7. The time now is 02:38 AM.

Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
SEO by vBSEO 3.6.0 ©2011, Crawlability, Inc.

Copyright © 2020 Gnutella Forums.
All Rights Reserved.