1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886
|
(*
AS PRESENTED BY GNUCLEUS (BUT WE ARE IMPLEMENTING LIMEWIRE CURRENTLY !!!)
Gnutella Protocol : Connections
Connection is what make the gnutella network work. All data through
the network flow through these connections. As a developer you strive
to have a connection process that holds on to nodes for a long period
of time and hence creating a stronger gnutella network as a whole.
Connecting Version 0.4
This is the most typical way connections are made over gnutella. It is
how all the clients have been connecting since the initial release of
the 0.56 client by Nullsoft. Who ever initiates the connection sends
this.
GNUTELLA CONNECT/0.4\n\n
In response if the host accepts the connection it sends this. Right
after the statement normal gnutella packet flow begins.
GNUTELLA OK\n\n
Connecting Version 0.6
The new connect process is supported by most clients now and is
backwards compatible with the old version 0.4 style. The main reason
for this was to get more information out of the connect string, for
debugging purposes and adding new features to the protocol. The client
that initiates the connection sends this.
GNUTELLA CONNECT/0.6\r\n
User-Agent: Gnucleus 1.4.5.0\r\n
\r\n
In response, if the host accepts the connection it sends this.
GNUTELLA/0.6 200 OK\r\n
User-Agent: Gnucleus 1.4.5.2\r\n
\r\n
At this point the host that initiated the connection determines if it
also accepts the connection based on the header information from the
server. If all is a go it sends this and normal packet flow begins.
GNUTELLA/0.6 200 OK\r\n
\r\n
Gnutella Protocol : Packets
There are only five packet types that run over the network. Every
packet has a header and payload, the last four bytes of the header
describes the size of the payload in bytes.
Network Byte Order (NBO) means for some reason the bytes are reversed.
So before you use them in a variable reverse the order of the bytes.
Same when you are building a packet, make sure the bytes are switched
into NBO.
Packet Type
Byte Description Value
Header
Payload
Size: Total packet size (bytes)
Flow: Direction to send packet
Ping - Used to discover other hosts on network
Byte Description Value
0 - 15 GUID Random 16 bytes
16 Function 0x00 (hex), 0 (dec)
17 TTL 7
18 Hops 0
19 - 22 Payload (NBO) 0
Total Size: 23 bytes
Flow: Broadcasted
Pong - Reply to a ping, contains info on host
Byte Description Value
0 - 15 GUID GUID of the Ping being replied to
16 Function 0x01 (hex), 1 (dec)
17 TTL Hops value of the Ping being replied to
18 Hops 0
19 - 22 Payload (NBO) 14
23 - 24 Port Port Client is listening on
25 - 28 Host Four byte IP address of Client
29 - 32 File Count (NBO) Total number of files shared
33 - 36 File Size (NBO) Total size of files shared (kilobytes)
Total Size: 37 bytes
Flow: Routed
Query - A file search
Byte Description Value
0 - 15 GUID Random 16 bytes
16 Function 0x80 (hex), 128 (dec)
17 TTL 7
18 Hops 0
19 - 22 Payload (NBO) Greater than 2 and less than 256
23 - 24 Minimum Speed Minimum Speed Client must be to respond
(kilobits)
25 + Query Keywords being Searched for
Total Size: 23 bytes + Payload
Flow: Broadcasted
Query Hit - Reply to a file search, contains set of results
Byte Description Value
0 - 15 GUID GUID of the Query being replied to
16 Function 0x81 (hex), 129 (dec)
17 TTL Hops value of the Query being replied to
18 Hops 0
19 - 22 Payload (NBO) Greater than 26 and less than 65536
23 Total Hits Number or results listed in packet
24 - 25 Port Port Client is listening on
26 - 29 Host Four byte IP address of Client
30 - 33 Speed (NBO) Speed of client (kilobits)
34 + Results Results one after the other, number of results should
match the value of Total Hits
Result
Byte Description Value
0 - 3 Index (NBO) Index of the file in the client
4 - 7 Size (NBO) Size of the file (bytes)
8 + Filename Name of the file, terminated by a NULL
NULL - NULL Extended Data Results always end with two NULLs, sometimes
there is extra data between them
After Results QHD Query Hit Descriptor - Extended Client information
QHD
Byte Description Value
0 - 3 Vendor Identifier A unique four character code identifying the
vendor
4 Public Sector Length 2 - Length of Public Sector (bytes)
5, bit 0 Push Behind a firewall, dont bother connecting
5, bit 1 Flag Bad A screw up, always set to 1
5, bit 2 Flag Busy Value tells if busy bit is set
5, bit 3 Flag Stable Value tells if stable bit is set
5, bit 4 Flag Speed Value tells if speed bit is set
5, bit 5 - 7 Unused Just set to all zeros
6, bit 0 Flag Push Value tells if push bit is set
6, bit 1 Bad A screw up, always set to 0
6, bit 2 Busy Client is currently busy
6, bit 3 Stable Client has successfully transmitted at least one
upload
6, bit 4 Speed Speed byte is set to maximum achieved speed during an
upload
6, bit 5 - 7 Unused Just set to all zeros
variable Private Sector Used on a per vendor basis to send proprietary
info
last 16 Client GUID A Static random 16 bytes unique to each Gnutella
Client
Total Size: 23 bytes + Payload
Flow: Routed
Push - Reply to a Query Hit from a client behind a firewall
Byte Description Value
0 - 15 GUID Random 16 bytes
16 Function 0x40 (hex), 64 (dec)
17 TTL Hops value of the Query Hit being replied to
18 Hops 0
19 - 22 Payload (NBO) 26
23 - 38 Client GUID Client GUID from Query Hit packet
39 - 42 Index (NBO) Index of file from Query Hit packet
43 - 46 Host Four byte IP address of Client
47 - 48 Port Port Client is listening on
Total Size: 49 bytes
Flow: Routed
Gnutella Protocol : Transfer
File transfers over Gnutella happen over a direct connection between
two nodes. The syntax of the code is similar to HTTP, but is not
actually to the standard. It has been modified slightly. Use the
examples on this page as a guide.
Gnutella also has a file transfer mechanism called 'push' to assist
nodes behind firewalls share files. If you are unable to connect to a
node to get a file, you can request the node to 'push' the file to you
be connecting to you instead. Push does not work if both nodes are
behind a firewall.
File Request
On connect to the host you want to download from, you send the file
request header. The first line is the GET statement, the number
between the slashes is the index of the file from the query hit
packet. Following that is the name of the file. The next line
describes what client is requesting the file. The range statement
tells the host what position in the file to start sending from in case
the client is resuming the download. A new download starts at the
postion of zero. Each line is terminated with a '\r\n' or in ASCII a
'13,10' pair.
GET /get/2975/How Towels Work.txt HTTP/1.0\r\n
User-Agent: LimeWire 1.8\r\n
Range: bytes=0-\r\n
\r\n
Server Reply
After the server receives the File Request it returns a HTTP 200 OK to
the client unless it is busy or the file isnt found. In that case use
HTTP specs to return the correct HTTP error code. To make things easy
always send files with a content type of application/binary. Following
that is the total length of the file in bytes. After sending the last
'\r\n' proceed in sending the actual file.
HTTP 200 OK\r\n
Server: Gnucleus 1.4.5.2\r\n
Content-type:application/binary\r\n
Content-length: 2894894\r\n
\r\n
Resuming
If a client sends a GET request with a byte range other than zero that
means the client is resuming the transfer. In that case the reply is
modified a bit. Instead of the Content-length: statement,
Accept-Ranges: and Content-range is used. Accept-Ranges: is always
bytes. Content-range: is followed by byte= and then the postion the
transfer is resuming from. After the dash is the positoin of the last
byte in the file, and after the slash is the total bytes in the file.
HTTP 200 OK\r\n
Server: Gnucleus 1.5.0.0\r\n
Content-type:application/binary\r\n
Accept-Ranges: bytes\r\n
Content-range: bytes=565768-1947689/1947690\r\n
\r\n
Pushing
Instead of connecting to a host to send a GET request you send a push
packet out over the gnutella network. The reason you do this is
because the host you want the file from has an unreachable IP address
such as 192.168.0.67. The push packet tells the host to connect to you
instead (you having a reachable IP address). On connect of the host to
you, that host sends you a GIV request. The GIV request is three
parts, the file index, the GUID of the server and the name of the
file. Take note the give request ends with \n\n and not \r\n.
GIV 446:72814A49E69D0F43FF288B3E6AAAB400/Paint Drying.mpg\n\n
After the GIV, the client and server act normally as before and send
each other the proper headers in order the get the file transfer
moving.
GET /get/446/Paint Drying.mpg HTTP/1.0\r\n
User-Agent: Bearshare 2.3.0\r\n
Range: bytes=0-\r\n
\r\n
HTTP 200 OK\r\n
Server: Gnucleus 1.3.3.1\r\n
Content-type:application/binary\r\n
Content-length: 56763485\r\n
\r\n
PROTOCOL
public static final byte F_PING=(byte)0x0;
public static final byte F_PING_REPLY=(byte)0x1;
public static final byte F_PUSH=(byte)0x40;
public static final byte F_QUERY=(byte)0x80;
public static final byte F_QUERY_REPLY=(byte)0x81;
public static final byte F_ROUTE_TABLE_UPDATE=(byte)0x30;
The GnutellaNet protocol
Last update: 2001 Nov 28
Original version was by gene@wego.com.
This verson is updated to correct the endian-ness errors, and clarify
and update the situation with the network size and TTL values.
Notes
Everything is in network byte order unless otherwise noted. Byte order
of the GUID is not important.
Apparently, there is some confusion as to what "\r" and "\n" are.
Well, \r is carriage return, or 0x0d, and \n is newline, or 0x0a. This
is standard ASCII, but there it is, from "man ascii".
Keep in mind that every message you send can be replied by multiple servers.
Hence, PING is used to discover servers, as the PONG (Ping reply) contains
server information.
Throughout this document, the term server and client is interchangeable.
Gnutella clients are Gnutella servers.
Thanks to capnbry for his efforts in decoding the protocol and posting it.
How GnutellaNet works
General description
GnutellaNet works by "viral propagation". I send a message to you, and
you send it to all clients connected to you. That way, I only need to
know about you to know about the entire rest of the network.
A simple glance at this message delivery mechanism will tell you that
it generates inordinate amounts of traffic. Take for example the
defaults for Gnutella 0.54. It defaults to maintaining 25 active
connections with a TTL (TTL means Time To Live, or the number of times
a message can be passed on before it "dies"). In the worst of worlds,
this means 2524^6, or 4,777,574,400 messages resulting from just
one message!
Well, okay. In truth it isn't that bad. In reality, there are usually
only a few thousand Gnutella clients on the GnutellaNet at any one
time (and there have never been more than about 30,000). That means
that long before the TTL expires on our hypothetical message, every
client on the GnutellaNet will have seen our message.
During 2000, many Gnutella clients used smaller defaults for the TTL
and the number of active connections. Some went so far as to lower
both to 4. However, this is much too low. Even if the network were
"connected" in the most perfect manner, 4 links per node and a TTL of
4 is only enough to connect 96 clients. Another popular combination is
4 links per node and a TTL of 7, which can connect 1155 clients, but
again only if the network is "wired" perfectly. If all the nodes hd 4
links per node and the network connections changed purely at random,
the TTL would have to be about 12 to 15 in order for most messages to
be able to reach all nodes.
However, some network structure has evolved. Smarter clients and
higher-bandwidth clients have formed a "backbone", with older clients
and low- bandwidth users pushed off to the edges. If the backbone
clients maintain a higher number of connections, the GnutellaNet can
work even with a TTL of 7 to 10 even when most of the clients only
maintain 4 connections.
GUIDs
Obviously, once a client sees a message, it's unnecessary for it to
process the message again. The original Gnutella designers, in
recognition of this, engineered each message to contain a GUID
(Globally Unique Identifier) which allows Gnutella clients to uniquely
identify each message on the network.
So how do Gnutella clients take advantage of the GUID? Each Gnutella
client maintains a short memory of the GUIDs it has seen. For example,
I will remember each message I have received. I forward each message I
receive as appropriate, unless I have already seen the message. If I
have seen the message, that means I have already forwarded it, so
everyone I forwarded it to has already seen it, and so on. So I just
forget about the duplicate and save everyone the trouble.
Topology
The GnutellaNet has no hierarchy. Every server is equal. Every server
is also a client.
Each Gnutella server only knows about the servers that it is directly
connected to. All other servers are invisible, unless they announce
themselves by answering to a PING or by replying to a QUERY. This
provides amazing anonymity.
Unfortunately, the combination of having no hierarchy and the lack of
a definitive source for a server list means that the network is not
easily described. It is not a tree (since there is no hierarchy) and
it is cyclic. Being cyclic means that every message a client sends out will
arrive back multiple times unless all (or at least most) of the
clients are careful to use the GUIDs to drop the duplicates.
Connecting to a server
After making the initial connection to the server, you must handshake.
Currently, the handshake is very simple. The connecting client says:
GNUTELLA CONNECT/0.4\n\n The accepting server responds:
GNUTELLA OK\n\n After that, it's all data.
Header
bytes
summary
description
0-15
Message identifier
16 bytes that will identify this
message and distinguish it from all others sent on the network.
Windows clients use a Windows GUID (which is 16 bytes). Other
clients should generate 16 bytes based on something that will make it unique
(like your local IP address, the current time, and some random numbers)
16
Payload descriptor
(function identifier)
Value Function
0x00 PING
0x01 PONG (Ping reply)
0x40 PUSH request
0x80 QUERY
0x81 HITS (Query reply)
17
TTL
Time to live. Each time a message is forwarded its TTL is
decremented by one. If a message is received with TTL
less than one (1), it should not be forwarded.
18
Hops
Number of times this message has been forwarded.
19- 22
Payload length
The length of the ensuing payload.
Payload: PING (function 0x00)
No payload
Routing instructions for PING
Forward PING packets to all connected clients. Most other documents
state that you should not forward packets to their originators. I
think that's a good optimization, but not a real requirement. A server
should be smart enough to know not to forward a packet that it
originated.
A cursory analysis of GnutellaNet traffic shows that PING comprises
roughly 50% of the network traffic. Clearly, this needs to be
optimized. One of the problems with clients today is that they seem to
PING the network periodically. That is indeed necessary, but the
frequency of these "update" PINGs can be drastically reduced. Simply
watching the PONG messages that your client routes is enough to
capture lots of server addresses.
One possible way to really reduce the number of PINGs is to alter the
protocol to support PING messages which includes PONG data. That way
you need only wait for servers to announce themselves, rather than
discovering them yourself.
Payload: PONG (query reply) (function 0x01)
bytes
summary
description
0-1
Port
IPv4 port number, using little-endian byte order:
The low byte comes first. For example, if the port number is 6346, the
first byte is 202 and the second byte is 24 (because 24256+202=6346)
2
IP address
IPv4 address, first byte
3
IP address
IPv4 address, second byte
4
IP address
IPv4 address, third byte
5
IP address
IPv4 address, last byte. Please note
this byte ordering not little-endian. For example, if the
IP address is 10.23.45.67, byte 2 will be 10, byte 3 will be 23, etc.
6-9
Number of files
Number of files the server is sharing.
10- 13
Number of kilobytes
Number of kilobytes the server is sharing.
Routing instructions for PONG
Like all replies, PONG packets are "routed". In other words, you need
to forward this packet only back down the path its PING came from. If
you didn't see its PING, then you have an interesting situation that
should never arise. Why? If you didn't see the PING that corresponds
with this PONG, then the server sending this PONG routed it
incorrectly.
Payload: QUERY (function 0x80)
bytes
summary
description
0-1
Minimum speed
The minimum speed, in kilobytes/sec, of servers which should reply to
this request.
2+
Search criteria
Search keywords or other criteria. NULL terminated.
Routing instructions for QUERY
Forward QUERY messages to all connected servers.
Payload: HITS (query reply) (function 0x81)
bytes
summary
description
0
Number of hits (N)
The number of hits in this set.
See "Result set" below.
1-2
Port
IPv4 port number.
3-6
IP address
IPv4 address. Same byte ordering as in PONG
payload description above
7-10
Speed
Speed, in kilobits/sec, of the responding server.
11+
Result set
There are N of these (see "Number of hits" above).
bytes summary, description
0-3 Index: Index number of file.
4-7 Size: Size of file in bytes.
8+ File name: Name of file. Terminated by double-NULL.
N bytes
EQHD
Extended QueryHit Descriptor (not always present).
To determine if this data is present and to measure its size, you must
count from the beginning through all the result sets to find the end
of the last result set, and then compare that to the total payload length minus 16 (for the GUID). Any extra data between the last result
and the GUID is EQHD.
Last
16 bytes
Client identifier
GUID of the responding server. Used in PUSH.
Routing instructions for HITS
HITS are routed, the same way PONGs are -- send these messages back on
their inbound path. That means, send them only to the connection from which you recieved the corresponding QUERY. The corresponding QUERY is
the one with the same message identifier (GUID) in its header as this reply.
Extended QueryHit Descriptor
This field is not always present. To determine if it is
present and to measure its size, you must
count from the beginning through all the result sets to find the end
of the last result set, and then compare that to the total payload
length minus 16 (for the GUID). Any extra data between the last result
and the GUID is EQHD.
A valie EQHD must contain at least 5 bytes of data:
bytes
summary
description
0-3
Vendor Code
A 4-byte code (probably 4 ASCII characters) representing
the name of the program that originated this QueryHit. See table below.
4
Open Data Size
Number of bytes of open-protocol (publicly
documented) data. In practice, this is usually 2.
N bytes
Open Data
Publicly-documented data. This is usually 2 bytes long,
see below for description of format.
M bytes
Private Data
Any additional data in the EQHD is of a
format defined privately by the vendor. Use Vendor Code to determine
whether this data is in a format you can understand (some vendors,
notably Cultiv8r, have publicly-documented private data formats)
Here is a table of known vendor codes. More are added from time to
time as new clients are written.
Code
Who or what
BEAR
BearShare
LIME
LimeWire
CULT
Cultiv8r
GNOT
Gnotella
GNUC
Gnucleus
GNUT
gnut
GTKG
Gtk-Gnutella
HSLG
Hagelslag
MACT
Mactella
NAPS
NapShare
OCFG
OpenCola
TOAD
ToadNode
The OpenData usually contains two bytes:
bits:
7
6
5
4
3
2
1
0
1st byte:
r
r
r
validUploadSpeed
validHaveUploaded
validBusy
r
flagPush
bits:
7
6
5
4
3
2
1
0
2nd byte:
r
r
r
flagUploadSpeed
flagHaveUploaded
flagBusy
r
validPush
r = reserved for future use.
flagUploadSpeed = 1 if and only if the Speed field of this
QueryHit descriptor contains the highest average transfer rate (in
kbps) of the last 10 uploads.
validUploadSpeed = 1 if and only if the flagUploadSpeed bit is
meaningful.
flagHaveUploaded = 1 if and only if the servent has successfully
uploaded at least one file.
validHaveUploaded = 1 if and only if the flagHaveUploaded bit is
meaningful.
flagBusy = 1 if and only if all of the servent's upload slots are
full (at the time this QueryHit was generated)
validBusy = 1 if and only if the flagBusy bit is meaningful.
flagPush = 1 if and only if the servent is firewalled or has not yet
accepted an incoming connection.
validPush = 1 if and only if the flagPush bit is meaningful.
PLEASE NOTE: the first byte contains 3 valid bits and one flag
bit, and vice-versa for the second byte. That is deliberate, it's
actually implemented that way in BearShare. (The description in the
Cultiv8r version of this document is wrong regarding the placement of
flagPush and validPush.)
Payload: PUSH request (function 0x40)
bytes
summary
description
0-15
Client identifier
GUID of the server which should push.
16-19
Index
Index number of file (given in query hit).
20-23
IP address
IPv4 address to push to.
24-25
Port
IPv4 port number to push to.
Routing instructions for PUSH
Forward PUSH messages only along the path on which the query hit was
delivered. If you missed the query hit then drop the packet, since you
are not instrumental in the delivery of the PUSH request.
Downloading from a server
Downloading files from a server is extremely easy. It's HTTP. The
downloading client makes a new connection (a TCP connection)
directly to the IP address of the server with the file to be
downloaded. It then requests the file by sending an HTTP header:
GET /get/1234/strawberry-rhubarb-pies.rcp HTTP/1.0\r\n
Connection: Keep-Alive\r\n
Range: bytes=0-\r\n
\r\n As you can see, Gnutella supports the range parameter for resuming
partial downloads. The 1234 is the file index (from HITS packet
described above), and "strawberry-rhubarb-pies.rcp" is the filename.
The server will respond with normal HTTP headers. For example:
HTTP 200 OK\r\n
Server: Gnutella\r\n
Content-type:application/binary\r\n
Content-length: 948\r\n
\r\n
ds*GKh:RkFk@)gjGLgK\Gh@+$L__^KVU-`D@:`/:#%KfTYJ^Y(BWDFL$#:rltyh... The important bit is the "Content-Length" header. That tells you how
much data to expect. After you get your fill, close the socket. Also
note the double \r\n before the beginning of the data. No special
encoding is used -- if the file is bonary, the data will be binary.
PUSH Downloads
A PUSH download is initiated by a server that has received a PUSH
request packet as described above. The server connects to the
requesting server, that is, the server that sent the PUSH request (the
requester's address is in the PUSH request packet) and writes a line
of the following format:
GIV 1234:1F340601AE6B60911956D022ECA8A045/strawberry-rhubarb-pies.rcp This line tells the requesting server that it is recieving a PUSH
connection to download the file it wants. The format is:
"GIV"
" " (a blank space)
"1234": The file index
":"
"1F3406..." the 16-byte GUID from the PUSH request as 32 hexadecimal digits
"/"
"strawberry..." the filename or pathname The requesting server will respond by sending back a GET header in the
same format as described above, and from there on the transfer
proceeds the same way it would have if the requester had established
the connection.
The gnut pages are hosted by
gnutelliums.com and
gnutelanews.com
Permission is granted to copy, distribute and/or modify this text
under the terms of the
GNU Free Documentation License, Version 1.1
or any later version published by the Free Software Foundation; with
no Invariant Sections, with no Front-Cover Texts and with no
Back-Cover Texts.
Use of the gnut source code is subject to the terms and conditions
of the
GNU General Public License.
gnut is provided in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
gnut is currently maintained by Robert Munafo, mrob at mrob com
Back to main gnut page
QUERY:
(17)(119)(46)(2)(0)(156)(202)(71)(255)(123)(244)(89)(248)(200)(172)(0) UID
(128) RECHERCHE
(7) TTL
(0) HOPS
(168)(0)(0)(0) PAYLOAD
(0)(0)
f a r m e r m y l e n e (0) < ? x m l v e r s i o n = " 1 . 0 " ? > < a u d i o s x s i : n o N a m e s p a c e S c h e m a L o c a t i o n = " h t t p : / / w w w . l i m e w i r e . c o m / s c h e m a s / a u d i o . x s d " > < a u d i o a r t i s t = " f a r m e r m y l e n e " > < / a u d i o > < / a u d i o s >(0)
QUERY REPLY:
(17)(119)(46)(2)(0)(156)(202)(71)(255)(123)(244)(89)(248)(200)(172)(0)
(129)
(0)
(7)
(199)(1)(0)(0)
(2)(202)(24)(192)(168)(0)(3)(64)(5)(0)(0)(154)(1)(0)(0)(124)(26)(60)(0)
M y l e n e F a r m e r - M a m a n a T o 1 . m p 3
(0)(0)(155)(1)(0)(0)(206)(181)(114)(0)
M y l e n e F a r m e r - M a m a n A T o r . m p 3
(0)(0)
L I M E
(4)(28)(25)(80)(1)(0)
{ p l a i n t e x t } < ? x m l v e r s i o n = " 1 . 0 " ? > < a u d i o s n o N a m e s p a c e S c h e m a L o c a t i o n = " h t t
p : / / w w w . l i m e w i r e . c o m / s c h e m a s / a u d i o . x s d " > < a u d i o b i t r a t e = " 1 2 8 " s e c o n d
s = " 2 4 6 " i n d e x = " 0 " / > < a u d i o t i t l e = " M a m a n A T o r t " a r t i s t = " M y l e n e F a r m e
r " a l b u m = " D a n c e R e m i x e s 2 " g e n r e = " P o p " y e a r = " 2 0 0 0 " c o m m e n t s = " , A G # 8 5 1
E A 3 B 7 " b i t r a t e = " 1 6 0 " s e c o n d s = " 3 7 5 " i n d e x = " 1 " / > < / a u d i o s >
(0)
(122)(93)(63)(134)(108)(83)(239)(129)(255)(75)(235)(24)(150)(226)(201)(0)
(54)(77)(175)(208)(60)(71)(78)(116)(255)(162)(94)(196)(115)(169)(160)(0)(1)(3)(4)(14)(0)(0)(0)]
private QueryReply(byte[] guid, byte ttl,
int port, byte[] ip, long speed, Response[] responses,
byte[] clientGUID, byte[] xmlBytes,
boolean includeQHD, boolean needsPush, boolean isBusy,
boolean finishedUpload, boolean measuredSpeed,
boolean supportsChat) {
super(guid, Message.F_QUERY_REPLY, ttl, (byte)0,
11 + // 11 bytes of header
rLength(responses) + // file records size
qhdLength(includeQHD, xmlBytes) +
// conditional xml-style QHD len
16); // 16-byte footer
// you aren't going to send this. it will throw an exception above in
// the appropriate constructor....
if (xmlBytes.length > XML_MAX_SIZE)
return;
Assert.that((port&0xFFFF0000)==0);
Assert.that(ip.length==4);
Assert.that((speed&0xFFFFFFFF00000000l)==0);
final int n=responses.length;
Assert.that(n<256);
payload=new byte[getLength()];
//Write beginning of payload.
//Downcasts are ok, even if they go negative
payload[0]=(byte)n;
ByteOrder.short2leb((short)port,payload,1);
payload[3]=ip[0];
payload[4]=ip[1];
payload[5]=ip[2];
payload[6]=ip[3];
ByteOrder.int2leb((int)speed,payload,7);
//Write each response at index i
int i=11;
for (int left=n; left>0; left--) {
Response r=responses[n-left];
ByteOrder.int2leb((int)r.getIndex(),payload,i);
ByteOrder.int2leb((int)r.getSize(),payload,i+4);
i+=8;
byte[] nameBytes = r.getNameBytes();
System.arraycopy(nameBytes, 0, payload, i, nameBytes.length);
i+=nameBytes.length;
//Write first null terminator.
payload[i++]=(byte)0;
//add the second null terminator
payload[i++]=(byte)0;
}
//Write QHD if desired
if (includeQHD) {
//a) vendor code. This is hardcoded here for simplicity,
//efficiency, and to prevent character decoding problems.
payload[i++]=(byte)76; //'L'
payload[i++]=(byte)73; //'I'
payload[i++]=(byte)77; //'M'
payload[i++]=(byte)69; //'E'
//b) payload length
payload[i++]=(byte)COMMON_PAYLOAD_LEN;
//c) PART 1: common area flags and controls. See format in
//parseResults2.
payload[i++]=(byte)((needsPush ? PUSH_MASK : 0)
| BUSY_MASK
| UPLOADED_MASK
| SPEED_MASK);
payload[i++]=(byte)(PUSH_MASK
| (isBusy ? BUSY_MASK : 0)
| (finishedUpload ? UPLOADED_MASK : 0)
| (measuredSpeed ? SPEED_MASK : 0));
//d) PART 2: size of xmlBytes + 1.
int xmlSize = xmlBytes.length + 1;
if (xmlSize > XML_MAX_SIZE)
xmlSize = XML_MAX_SIZE; // yes, truncate!
ByteOrder.short2leb(((short) xmlSize), payload, i);
i += 2;
//e) private area: one flag that says whether we support chat
payload[i++]=(byte)(supportsChat ? 0x1 : 0);
//f) actual xml.
System.arraycopy(xmlBytes, 0,
payload, i, xmlSize-1);
// adjust i...
i += xmlSize-1;
// write null after xml, as specified
payload[i++] = (byte)0;
}
//Write footer at payload[i...i+16-1]
for (int j=0; j<16; j++) {
payload[i+j]=clientGUID[j];
}
}
//2. Extract BearShare-style metainformation, if any. Any exceptions
//are silently caught. The definitive reference for this format is at
//http://www.clip2.com/GnutellaProtocol04.pdf. Briefly, the format is
// vendor code (4 bytes, case insensitive)
// common payload length (4 byte, unsigned, always>0)
// common payload (length given above. See below.)
// vendor payload (length until clientGUID)
//The normal 16 byte clientGUID follows, of course.
//
//The first byte of the common payload has a one in its 0'th bit* if we
//should try a push. However, if there is a second byte, and if the
//0'th bit of this byte is zero, the 0'th bit of the first byte should
//actually be interpreted as MAYBE. Unfortunately LimeWire 1.4 failed
//to set this bit in the second byte, so it should be ignored when
//parsing, though set on writing.
//
//The remaining bits of the first byte of the common payload area tell
//whether the corresponding bits in the optional second byte is defined.
//The idea behind having two bits per flag is to distinguish between
//YES, NO, and MAYBE. These bits are as followed:
// bit 1* undefined, for historical reasons
// bit 2 1 iff server is busy
// bit 3 1 iff server has successfully completed an upload
// bit 4 1 iff server's reported speed was actually measured, not
// simply set by the user.
//
//*Here, we use 0-(N-1) numbering. So "0'th bit" refers to the least
//significant bit.
/* ----------------------------------------------------------------
* QHD UPDATE 8/17/01
* Here is an updated QHD spec.
*
* Byte 0-3 : Vendor Code
* Byte 4 : Public area size (COMMON_PAYLOAD_LEN)
* Byte 5-6 : Public area (as described above)
* Byte 7-8 : Size of XML + 1 (for a null), you need to count backward
* from the client GUID.
* Byte 9-beginning of xml : (new) private area
* Byte (payload.length - 16 - xmlSize (above)) -
(payload.length - 16 - 1) : XML!!
* Byte (payload.length - 16 - 1) : NULL
* Last 16 Bytes: client GUID.
*/
*)
|