distribustream 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,11 +1,23 @@
1
1
  #--
2
2
  # Copyright (C) 2006-07 ClickCaster, Inc. (info@clickcaster.com)
3
- # All rights reserved. See COPYING for permissions.
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
4
16
  #
5
17
  # This source file is distributed as part of the
6
18
  # DistribuStream file transfer system.
7
19
  #
8
- # See http://distribustream.rubyforge.org/
20
+ # See http://distribustream.org/
9
21
  #++
10
22
 
11
23
  require "uri"
@@ -55,6 +67,9 @@ module PDTP
55
67
  @default_chunk_size = 512
56
68
  end
57
69
 
70
+ # Retrieve information about a file. This should really be persistent
71
+ # FIXME the only authentication regarding registered files is performed
72
+ # by checking whether the registered file exists
58
73
  def get_info(url)
59
74
  begin
60
75
  host = URI.split(url)[2]
@@ -1,18 +1,30 @@
1
- #!/usr/bin/env ruby
2
1
  #--
3
2
  # Copyright (C) 2006-07 ClickCaster, Inc. (info@clickcaster.com)
4
- # All rights reserved. See COPYING for permissions.
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
5
16
  #
6
17
  # This source file is distributed as part of the
7
18
  # DistribuStream file transfer system.
8
19
  #
9
- # See http://distribustream.rubyforge.org/
20
+ # See http://distribustream.org/
10
21
  #++
11
22
 
12
23
  require 'digest/md5'
13
- require 'thread'
14
24
 
25
+ require File.dirname(__FILE__) + '/../common'
15
26
  require File.dirname(__FILE__) + '/../common/protocol'
27
+ require File.dirname(__FILE__) + '/../common/http_server'
16
28
  require File.dirname(__FILE__) + '/../server/file_service'
17
29
  require File.dirname(__FILE__) + '/../client/connection'
18
30
  require File.dirname(__FILE__) + '/../client/http_handler'
@@ -26,64 +38,35 @@ module PDTP
26
38
 
27
39
  def initialize *args
28
40
  @transfers = []
29
- @lock = Mutex.new
30
41
  @client = self
31
42
  @connection = self
32
43
  @client_id = Digest::MD5.hexdigest "#{Time.now.to_f}#{$$}"
33
44
 
45
+ @listen_addr = '0.0.0.0'
46
+ @listen_port = 60860
47
+ @vhost = @listen_addr
34
48
  super
35
49
  end
36
50
 
37
51
  # Called after a connection to the server has been established
38
52
  def connection_completed
39
53
  begin
40
- @listen_addr = '0.0.0.0'
41
- @listen_port = @@config[:listen_port]
42
-
43
- #create the client
44
- #client = PDTP::Client.new
45
- #PDTP::Protocol.listener = client
46
- #client.server_connection = self
47
- #client.generate_client_id listen_port
48
-
49
- # Start a mongrel server on the specified port. If it isnt available, keep trying higher ports
50
- begin
51
- mongrel_server = Mongrel::HttpServer.new @listen_addr, @listen_port
52
- rescue Exception => e
53
- @listen_port += 1
54
- retry
55
- end
56
-
57
- #@@log.info "listening on port #{@listen_port}"
58
- @http_handler = Client::HttpHandler.new(self)
59
-
60
- @@log.info "listening on port #{@listen_port}"
61
- mongrel_server.register "/", @http_handler
62
- mongrel_server.run
54
+ @http_server.register "/", Client::HttpHandler.new(self)
63
55
 
64
56
  # Register our client_id and listen_port
65
57
  send_message :register, :listen_port => @listen_port, :client_id => @client_id
66
58
 
67
- @@log.info 'This client is providing'
68
59
  @file_service = PDTP::Server::FileService.new
69
60
  @file_service.root = @base_path
70
- #client.file_service = sfs #give this client access to all data
71
-
72
- hostname = @@config[:vhost]
73
61
 
74
62
  # Provide all the files in the root directory
75
63
  files = find_files @base_path
76
- files.each { |file| send_message :provide, :url => "http://#{hostname}/#{file}" }
64
+ files.each { |file| send_message :provide, :url => "http://#{@vhost}/#{file}" }
77
65
  rescue Exception => e
78
66
  puts "Exception in connection_completed: #{e}"
79
67
  puts e.backtrace.join("\n")
80
68
  exit
81
69
  end
82
- end
83
-
84
- def unbind
85
- super
86
- puts "Disconnected from PDTP server."
87
70
  end
88
71
 
89
72
  #########
@@ -91,6 +74,8 @@ module PDTP
91
74
  #########
92
75
 
93
76
  # Fine all suitable files in the give path
77
+ # FIXME This should really be moved to a lazy approach where we look
78
+ # for files as they're requested by clients
94
79
  def find_files(base_path)
95
80
  require 'find'
96
81
 
@@ -0,0 +1,103 @@
1
+ #--
2
+ # Copyright (C) 2006-07 ClickCaster, Inc. (info@clickcaster.com)
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+ #
17
+ # This source file is distributed as part of the
18
+ # DistribuStream file transfer system.
19
+ #
20
+ # See http://distribustream.org/
21
+ #++
22
+
23
+ require 'rubygems'
24
+ require 'mongrel'
25
+ require 'erb'
26
+
27
+ require File.dirname(__FILE__) + '/../common/http_server'
28
+
29
+ module PDTP
30
+ class Server
31
+ #set up the mongrel server for serving the stats page
32
+ class StatusHandler < Mongrel::HttpHandler
33
+ def initialize(dispatcher)
34
+ @dispatcher = dispatcher
35
+ end
36
+
37
+ # process an incoming request to the admin page
38
+ def process(request, response)
39
+ response.start(200) do |head, out|
40
+ out.write begin
41
+ generate_html_stats
42
+ rescue Exception => e
43
+ "Exception: #{e}\n#{e.backtrace.join("\n")}"
44
+ end
45
+ end
46
+ end
47
+
48
+ #builds an html page with information about the server's internal workings
49
+ def generate_html_stats
50
+ s = ERB.new <<EOF
51
+ <html><head><title>DistribuStream Status</title></head>
52
+ <body>
53
+ <h1>DistribuStream Status</h1>
54
+ Time=<%= Time.now %><br> Connected Clients=<%= @dispatcher.connections.size %>
55
+ <center><table border="1">
56
+ <tr><th>Client</th><th>Transfers</th><th>Files</th></tr>
57
+ <% @dispatcher.connections.each do |c| %>
58
+ <tr><td>
59
+ <% if c.file_service? %>
60
+ <b>File Service</b>
61
+ <% else %>
62
+ <%= @dispatcher.connection_name(c) %>
63
+ <% end %>
64
+ <% host, port = c.get_peer_info %>
65
+ <br><%= host %>:<%= port %>
66
+ </td>
67
+ <td>
68
+ <%
69
+ @dispatcher.client_info(c).transfers.each do |key,t|
70
+ if c==t.giver
71
+ type="UP: "
72
+ peer=t.taker
73
+ else
74
+ type="DOWN: "
75
+ peer=t.giver
76
+ end
77
+ %>
78
+ <%= type %> id=<%= t.transfer_id %><br>
79
+ <%
80
+ end
81
+ %>
82
+ </td>
83
+ <td>
84
+ <%
85
+ @dispatcher.client_info(c).chunk_info.get_file_stats.each do |fs|
86
+ %>
87
+ <%= fs.url %> size=<%= fs.file_chunks %> req=<%= fs.chunks_requested %>
88
+ prov=<%= fs.chunks_provided %> transf=<%= fs.chunks_transferring %><br>
89
+ <%
90
+ end
91
+ %>
92
+ </td></tr>
93
+ <%
94
+ end
95
+ %>
96
+ </table>
97
+ </body></html>
98
+ EOF
99
+ s.result binding
100
+ end
101
+ end
102
+ end
103
+ end
@@ -1,11 +1,23 @@
1
1
  #--
2
2
  # Copyright (C) 2006-07 ClickCaster, Inc. (info@clickcaster.com)
3
- # All rights reserved. See COPYING for permissions.
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
4
16
  #
5
17
  # This source file is distributed as part of the
6
18
  # DistribuStream file transfer system.
7
19
  #
8
- # See http://distribustream.rubyforge.org/
20
+ # See http://distribustream.org/
9
21
  #++
10
22
 
11
23
  module PDTP
@@ -18,6 +30,13 @@ module PDTP
18
30
  attr_accessor :creation_time
19
31
  attr_accessor :verification_asked
20
32
 
33
+ #generates a transfer id based on 2 client ids, a url, and a byte range
34
+ def self.gen_transfer_id(id1,id2,url,byte_range)
35
+ a = id1<id2 ? id1 : id2
36
+ b = id1<id2 ? id2 : id1
37
+ "#{a}$#{b}$#{url}$#{byte_range}"
38
+ end
39
+
21
40
  def initialize(taker,giver,url,chunkid,byte_range,connector_receives=true)
22
41
  @taker,@giver,@url,@chunkid,@byte_range=taker,giver,url,chunkid,byte_range
23
42
 
@@ -41,13 +60,6 @@ module PDTP
41
60
  @transfer_id=Transfer::gen_transfer_id(id1,id2,@url,@byte_range)
42
61
  end
43
62
 
44
- #generates a transfer id based on 2 client ids, a url, and a byte range
45
- def self.gen_transfer_id(id1,id2,url,byte_range)
46
- a = id1<id2 ? id1 : id2
47
- b = id1<id2 ? id2 : id1
48
- "#{a}$#{b}$#{url}$#{byte_range}"
49
- end
50
-
51
63
  def to_s
52
64
  "taker=#{@taker}, giver=#{@giver}, connector=#{@connector}, acceptor=#{@acceptor}, url=#{@url}, chunk_id=#{@chunkid} range=#{@byte_range}"
53
65
  end
@@ -1,11 +1,23 @@
1
1
  #--
2
2
  # Copyright (C) 2006-07 ClickCaster, Inc. (info@clickcaster.com)
3
- # All rights reserved. See COPYING for permissions.
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
4
16
  #
5
17
  # This source file is distributed as part of the
6
18
  # DistribuStream file transfer system.
7
19
  #
8
- # See http://distribustream.rubyforge.org/
20
+ # See http://distribustream.org/
9
21
  #++
10
22
 
11
23
  module PDTP
@@ -0,0 +1,831 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE rfc SYSTEM "http://xml.resource.org/authoring/rfc2629.dtd">
3
+ <?rfc toc='yes' ?>
4
+ <rfc docName="draft-distribustream-pdtp-rfcs-01" ipr="full3978">
5
+ <front>
6
+ <title abbrev="PDTP Specification">Peer Distributed Transfer Protocol Specification</title>
7
+
8
+ <author fullname="Tony Arcieri" initials="T.A." surname="Arcieri">
9
+ <organization>ClickCaster, Inc.</organization>
10
+
11
+ <address>
12
+ <email>tony@clickcaster.com</email>
13
+ </address>
14
+ </author>
15
+
16
+ <author fullname="Ashvin Mysore" initials="A.M." surname="Mysore">
17
+ <organization>ClickCaster, Inc.</organization>
18
+
19
+ <address>
20
+ <email>ashvin@clickcaster.com</email>
21
+ </address>
22
+ </author>
23
+
24
+ <author fullname="Galen Pahlke" initials="G.P." surname="Pahlke">
25
+ <organization>ClickCaster, Inc.</organization>
26
+
27
+ <address>
28
+ <email>galen@clickcaster.com</email>
29
+ </address>
30
+ </author>
31
+
32
+ <author fullname="James Sanders" initials="J.S." surname="Sanders">
33
+ <organization>University of Colorado</organization>
34
+
35
+ <address>
36
+ <email>sanderjd@gmail.com</email>
37
+ </address>
38
+ </author>
39
+
40
+ <author fullname="Tom Stapleton" initials="T.S." surname="Stapleton">
41
+ <organization>University of Colorado</organization>
42
+
43
+ <address>
44
+ <email>tstapleton@gmail.com</email>
45
+ </address>
46
+ </author>
47
+
48
+ <date month="November" year="2007" />
49
+
50
+ <area>Internet</area>
51
+
52
+ <keyword>I-D</keyword>
53
+
54
+ <keyword>Internet-Draft</keyword>
55
+
56
+ <keyword>PDTP</keyword>
57
+
58
+ <keyword>DistribuStream</keyword>
59
+
60
+ <abstract>
61
+ <t>Peer Distributed Transfer Protocol is a high performance peer-to-peer
62
+ file distribution system that provides streaming downloads of files
63
+ originating from a central server. The files are then shared over a peer
64
+ network, allowing the aggregate bandwidth of the network to scale with
65
+ the number of clients.</t>
66
+ </abstract>
67
+ </front>
68
+
69
+ <middle>
70
+ <section title="Introduction">
71
+ <t>This document describes version 2 of PDTP, an enhancement of <xref
72
+ target="refs.PDTP">PDTP version 1</xref>. PDTP currently only allows for
73
+ operation on IPv4 networks, though support for IPv6 networks is
74
+ planned.</t>
75
+
76
+ <t>PDTP is based on an extensible set of asynchronous messages. These
77
+ messages are comprised of a type, and a sequence of key-value pairs. The
78
+ possible data types are described in Appendix A. Due to the structure of
79
+ PDTP, protocol messages can be grouped into two distinct categories:
80
+ <list style="symbols">
81
+ <t><xref target="server-to-client-messages">Server to client
82
+ messages</xref> manage the file transfer process and provide
83
+ infomation of files requested by the client.</t>
84
+
85
+ <t><xref target="client-to-server-messages">Client to server
86
+ messages</xref> handle requests for files by the client, inform the
87
+ server of files the client can provide, and report the status of
88
+ transfers.</t>
89
+
90
+ <t><xref target="client-to-client-communication">Client to client
91
+ communication</xref> makes use of the standard <xref
92
+ target="refs.HTTP">HTTP 1.1</xref> protocol</t>
93
+ </list></t>
94
+ </section>
95
+
96
+ <section title="Message Format">
97
+ <t>All <xref target="client-to-server-messages">client to server</xref>
98
+ and <xref target="server-to-client-messages">server to client</xref>
99
+ communication utilizes a lightweight form of asynchronous messaging over
100
+ TCP with <xref target="refs.JSON">JavaScript Object Notation (JSON)</xref>
101
+ providing underlying data serialization format. Messages are
102
+ length-prefix framed with a JSON message body. The IANA approved TCP
103
+ port for all PDTP client/server intercommunication is 6086.</t>
104
+
105
+ <t>Each frame consists of a 16-bit unsigned integer in network byte order
106
+ representing the length of the message body, followed by the message
107
+ body itself. Because the length prefix is 16-bit, the maximum allowed
108
+ length of the message body is 65,535 bytes, with a maximum frame size
109
+ of 65,537 bytes including the header. Messages are sent in succession
110
+ over a persistent TCP connection.</t>
111
+
112
+ <t>Message bodies consist of JSON messages in the following format:</t>
113
+
114
+ <figure>
115
+ <artwork>["type", {"arg1": "value1", "arg2": "value2", ..., "argN": "valueN"}]</artwork>
116
+ </figure>
117
+
118
+ <t>Each message is composed of an outer JSON array with two members.
119
+ The first member is a string which represents the message type. The second
120
+ member is a JSON object which contains a message-specific collection of
121
+ arguments. Unless otherwise specified, all members are represented as JSON strings.
122
+ </t>
123
+
124
+ <t>To improve the readability of the protocol on the wire, it is recommended that
125
+ CRLF be appended to the end of the JSON message. This is ignored as whitespace by
126
+ JSON parsers, but meaningful to humans who may be reading wire dumps. However, this
127
+ is not an explicit requirement of the protocol, nor should its presence be required
128
+ by any implementation.</t>
129
+ </section>
130
+
131
+ <section anchor="server-to-client-messages"
132
+ title="Server to Client Messages">
133
+ <section title="Overview">
134
+ <t>These messages are sent from the server to the client to respond to
135
+ information requests by the client and manage the file transfer
136
+ process. <list style="symbols">
137
+ <t><xref target="tellinfo">TELLINFO</xref> provides the client
138
+ with information about the object located at the specified
139
+ URL.</t>
140
+
141
+ <t><xref target="transfer">TRANSFER</xref> tells the client to
142
+ initiate a peer-to-peer data transfer.</t>
143
+
144
+ <t><xref target="tellverify">TELLVERIFY</xref> tells the client
145
+ whether the specified transfer is authorized.</t>
146
+
147
+ <t><xref target="hashverify">HASHVERIFY</xref> informs the client
148
+ whether the successful transfer had the correct file hash.</t>
149
+ </list></t>
150
+ </section>
151
+
152
+ <section anchor="tellinfo" title="TELLINFO">
153
+ <figure>
154
+ <artwork>tell_info url [size] [chunkSize] [streaming]</artwork>
155
+ </figure>
156
+
157
+ <t>The tell_info datagram is the expected response from the ask_info
158
+ datagram, and contains information that the client can use to
159
+ determine its chunk request policy and the manner in which a file is
160
+ handled. Since the server only arranges for chunks to be sent when
161
+ they are explicitly requested, a client must know how many chunks are
162
+ in a file so that it knows how many to request. In order to determine
163
+ the number of chunks in a file, the size of each chunk and the total
164
+ size of the file are sent. The number of chunks is then the 'fileSize'
165
+ divided by the 'chunkSize', rounded up to the first integer. The
166
+ 'chunkSize' could also be used to determine a policy on caching or
167
+ memory management and the 'fileSize' could be used to alleviate
168
+ complications arising from the case of incomplete final chunks, and
169
+ perhaps other things.</t>
170
+
171
+ <t>Fields:</t>
172
+
173
+ <figure>
174
+ <artwork>url: String</artwork>
175
+
176
+ <postamble>A unique file identifier. The server uses this field to
177
+ specify which file it is sending information about.</postamble>
178
+ </figure>
179
+
180
+ <figure>
181
+ <artwork>size: Integer (Optional)</artwork>
182
+
183
+ <postamble>The exact size in bytes of the file. Since the last chunk
184
+ in the file might not be completely filled, it is necessary to know
185
+ the total file size as well as the chunk size and the chunk
186
+ count.</postamble>
187
+ </figure>
188
+
189
+ <figure>
190
+ <artwork>chunkSize: Integer (Optional)</artwork>
191
+
192
+ <postamble>The size in bytes of each chunk in the file.</postamble>
193
+ </figure>
194
+
195
+ <figure>
196
+ <artwork>streaming: Boolean (Optional)</artwork>
197
+
198
+ <postamble>If true, the file is assumed to be a streaming media file
199
+ and chunks near the beginning will be sent first. If false, chunks
200
+ from all over the file will have equal priority. Default is
201
+ false.</postamble>
202
+ </figure>
203
+ </section>
204
+
205
+ <section anchor="transfer" title="TRANSFER">
206
+ <figure>
207
+ <artwork>transfer peer port method url range peer_id</artwork>
208
+ </figure>
209
+
210
+ <t>The server controls all data flowing over the network. It uses the
211
+ transfer message to initiate a chunk transfer between two peers. The
212
+ transfer message is always sent to the peer that should initiate the
213
+ connection to the other peer.</t>
214
+
215
+ <t>When a client receives a transfer message, it should connect to the
216
+ specified peer and carry out the transfer as specified in <xref
217
+ target="client-to-client-communication">Section 4</xref> and reply to
218
+ the server with a <xref target="completed">completed</xref> message
219
+ upon success.</t>
220
+
221
+ <t>Fields:</t>
222
+
223
+ <figure>
224
+ <artwork>peer: String</artwork>
225
+
226
+ <postamble>This is the network address of the peer with which the
227
+ transfer should take place.</postamble>
228
+ </figure>
229
+
230
+ <figure>
231
+ <artwork>port: Integer</artwork>
232
+
233
+ <postamble>The port on the peer to connect to.</postamble>
234
+ </figure>
235
+
236
+ <figure>
237
+ <artwork>method: Enumeration</artwork>
238
+
239
+ <postamble>The HTTP method to be used for this transfer. Possible
240
+ values are GET and PUT, with the same semantics as in the HTTP
241
+ protocol. That is, if method is GET, this client is receiving data
242
+ from a peer, and if method is PUT, this client is sending data to a
243
+ peer.</postamble>
244
+ </figure>
245
+
246
+ <figure>
247
+ <artwork>url: String</artwork>
248
+
249
+ <postamble>This is a unique file identifier for the file to
250
+ transfer.</postamble>
251
+ </figure>
252
+
253
+ <figure>
254
+ <artwork>range: Range</artwork>
255
+
256
+ <postamble>This is the byte range being transferred. This, combined
257
+ with the url, provides a unique identifier for the data to
258
+ transfer.</postamble>
259
+ </figure>
260
+
261
+ <figure>
262
+ <artwork>peer_id: Integer</artwork>
263
+
264
+ <postamble>The unique id of the peer in this transfer.</postamble>
265
+ </figure>
266
+ </section>
267
+
268
+ <section anchor="tellverify" title="TELLVERIFY">
269
+ <figure>
270
+ <artwork>tell_verify peer url range peer_id authorized</artwork>
271
+ </figure>
272
+
273
+ <t>The tell_verify datagram is sent to the client in response to an
274
+ <xref target="askverify">ask_verify</xref> message to inform it of the
275
+ authorization status of a transfer.</t>
276
+
277
+ <t>Fields:</t>
278
+
279
+ <figure>
280
+ <artwork>peer: IP Address</artwork>
281
+
282
+ <postamble>The address of the connecting peer.</postamble>
283
+ </figure>
284
+
285
+ <figure>
286
+ <artwork>url: String</artwork>
287
+
288
+ <postamble>A unique file identifier.</postamble>
289
+ </figure>
290
+
291
+ <figure>
292
+ <artwork>range: Range</artwork>
293
+
294
+ <postamble>The byte range to verify.</postamble>
295
+ </figure>
296
+
297
+ <figure>
298
+ <artwork>peer_id: String</artwork>
299
+
300
+ <postamble>The unique identifier of the peer.</postamble>
301
+ </figure>
302
+
303
+ <figure>
304
+ <artwork>authorized: Boolean</artwork>
305
+
306
+ <postamble>A boolean value specifying whether or not the transfer is
307
+ authorized.</postamble>
308
+ </figure>
309
+ </section>
310
+
311
+ <section anchor="hashverify" title="HASHVERIFY">
312
+ <figure>
313
+ <artwork>hash_verify url range hash_ok</artwork>
314
+ </figure>
315
+
316
+ <t>The hash_verify message is sent to a client after a completed
317
+ message with a hash has been received. The value of hash_ok denotes
318
+ whether or not the hash sent in the completed message matches the
319
+ expected hash of the chunk containing the specified range.</t>
320
+
321
+ <t>Fields:</t>
322
+
323
+ <figure>
324
+ <artwork>url: String</artwork>
325
+
326
+ <postamble>The url of the file being transferred.</postamble>
327
+ </figure>
328
+
329
+ <figure>
330
+ <artwork>range: Range</artwork>
331
+
332
+ <postamble>The byte range of the file, which this message refers
333
+ to.</postamble>
334
+ </figure>
335
+
336
+ <figure>
337
+ <artwork>hash_ok: Boolean</artwork>
338
+
339
+ <postamble>If true, the has sent in the completed message matched
340
+ the expected hash of the byte range it referred to.</postamble>
341
+ </figure>
342
+ </section>
343
+
344
+ <section anchor="protocolerror" title="PROTOCOLERROR">
345
+ <figure>
346
+ <artwork>protocol_error message</artwork>
347
+ </figure>
348
+
349
+ <t>The protocol_error message is sent to a client whenever a protocol
350
+ error has occurred. The message field is meant to be read by a human
351
+ to determine what went wrong. In most cases, the error is due to a
352
+ programming error and is fatal. One notable exception to this is the
353
+ case when a client generates a Peer Id that is not unique.</t>
354
+
355
+ <t>Fields:</t>
356
+
357
+ <figure>
358
+ <artwork>message: String</artwork>
359
+
360
+ <postamble>An error message. This error message is not meant to be
361
+ parsed programmatically, but rather to be logged and read as an aid
362
+ to debugging.</postamble>
363
+ </figure>
364
+ </section>
365
+ </section>
366
+
367
+ <section anchor="client-to-server-messages"
368
+ title="Client to Server Messages">
369
+ <section title="Overview">
370
+ <t>These messages are sent from the client to the server to request
371
+ files, inform the server of completed transfers and handle files the
372
+ client can provide to the network. <list style="symbols">
373
+ <t><xref target="register">REGISTER</xref> informs the server
374
+ that the client exists and provides the server with information
375
+ about itself.</t>
376
+
377
+ <t><xref target="request">REQUEST</xref> informs the server that
378
+ the client wants the specified object range.</t>
379
+
380
+ <t><xref target="request">UNREQUEST</xref> informs the server that
381
+ the client no longer needs the specified object range.</t>
382
+
383
+ <t><xref target="provide">PROVIDE</xref> informs the server that
384
+ the client has the specified object range and can provide it to
385
+ peers.</t>
386
+
387
+ <t><xref target="provide">UNPROVIDE</xref> informs the server that
388
+ the client no longer has the specified object range, and therefore
389
+ cannot provide it.</t>
390
+
391
+ <t><xref target="askinfo">ASKINFO</xref> requests information from
392
+ the server about the specified URL.</t>
393
+
394
+ <t><xref target="askverify">ASKVERIFY</xref> asks the server
395
+ whether the specified transfer is authorized.</t>
396
+
397
+ <t><xref target="completed">COMPLETED</xref> informs the server
398
+ that a transfer has successfully completed.</t>
399
+ </list></t>
400
+ </section>
401
+
402
+ <section anchor="register" title="REGISTER">
403
+ <figure>
404
+ <artwork>register client_id listen_port</artwork>
405
+ </figure>
406
+
407
+ <t>The register message is the first message a client sends to the
408
+ server. The client must send this message to alert the server of its
409
+ presence so that it may be included in the server's actions.</t>
410
+
411
+ <t>Fields:</t>
412
+
413
+ <figure>
414
+ <artwork>client_id: String</artwork>
415
+
416
+ <postamble>A unique identifier, which the client generates. The
417
+ server will identify this client on the network based on this
418
+ identifier. The identifier must be a string less than 4 KB in
419
+ length. It is the client's responsibility to generate an identifier
420
+ that is unique. The server should respond with a <xref
421
+ target="protocolerror">protocol_error</xref> message if the
422
+ identifier is too long or not unique.</postamble>
423
+ </figure>
424
+
425
+ <figure>
426
+ <artwork>listen_port: Integer</artwork>
427
+
428
+ <postamble>The port on which the client will listen for incoming
429
+ connections from other peers. The server will pass this information
430
+ along to other clients wishing to connect to this client for peer to
431
+ peer chunk transfers.</postamble>
432
+ </figure>
433
+ </section>
434
+
435
+ <section anchor="request" title="REQUEST and UNREQUEST">
436
+ <figure>
437
+ <artwork>request url [range] unrequest url [range]</artwork>
438
+ </figure>
439
+
440
+ <t>The request and unrequest messages are used by the client to
441
+ indicate what data it needs to receive. A request datagram indicates
442
+ that the client needs the specified object bytes; an unrequest
443
+ datagram indicates that the client no longer needs the specified
444
+ bytes. The completed and provide messages may also be used to cancel a
445
+ request, though they carry additional semantics.</t>
446
+
447
+ <t>If the range of a request or unrequest message isn't specified, it
448
+ is assumed to include all bytes in the file.</t>
449
+
450
+ <t>The server is expected to continuously arrange for the data in the
451
+ client's request set to be delivered to the client through peer to
452
+ peer transfer channels. A request set is informally the set of chunks
453
+ that a client wants. Formally, we may say that a given unique chunk C
454
+ with the URL L and the id K is in a client's request set if and only
455
+ if: <list style="symbols">
456
+ <t>The client has sent at least one request message with a URL
457
+ equivalent to L and a byte range containing chunk K.</t>
458
+
459
+ <t>Since the last such message was sent, the client has not sent
460
+ an unrequest message with a URL equivalent to L and a byte range
461
+ containing chunk K,</t>
462
+
463
+ <t>...nor has it sent a completed message with a URL equivalent to
464
+ L and a byte range containing chunk K,</t>
465
+
466
+ <t>...nor has it sent a provide message with a URL equivalent to L
467
+ and a byte range containing chunk K.</t>
468
+ </list></t>
469
+
470
+ <t>In short, requests are standing and additive; unrequests are
471
+ transient and subtractive. The server is expected to handle any
472
+ possible combination of requests and unrequests that clients can send.
473
+ (For example, a client may request a URL in its entirety, and then
474
+ later unrequest certain parts of the URL. This is useful if, say, a
475
+ client needs to complete a partial download, repair a damaged file, or
476
+ optimize its network usage in response to user actions.)</t>
477
+
478
+ <t>Fields:</t>
479
+
480
+ <figure>
481
+ <artwork>url: String</artwork>
482
+
483
+ <postamble>The object being requested. The server may discard
484
+ requests for URLs it does not understand.</postamble>
485
+ </figure>
486
+
487
+ <figure>
488
+ <artwork>range: Range (Optional)</artwork>
489
+
490
+ <postamble>The range of bytes being requested, inclusive. If
491
+ unspecified, it is taken to be the complete range of bytes in the
492
+ file.</postamble>
493
+ </figure>
494
+ </section>
495
+
496
+ <section anchor="provide" title="PROVIDE and UNPROVIDE">
497
+ <figure>
498
+ <artwork>provide url [range] unprovide url [range]</artwork>
499
+ </figure>
500
+
501
+ <t>The provide and unprovide datagrams are used to tell the server
502
+ which chunks of a file it is able to provide to peers. Each client in
503
+ the system can have a cache of file chunks that it has already
504
+ downloaded and depending on the client's individual capabilities, this
505
+ cache may or may not be empty on startup. If a client has data in a
506
+ cache on startup, the provide message can be used to inform the
507
+ server. If the cache is empty on startup, the provide message is never
508
+ needed because the server is expected to keep track of each chunk that
509
+ has been transferred. On the other hand, if a client evicts one or
510
+ more chunks from its cache, it should immediately send an unprovide
511
+ message. Although there is no firm requirement on a client to send
512
+ appropriate unprovide datagrams, it is in the client's best interest
513
+ to do so, as it could lose standing in the network if it were asked to
514
+ send a chunk it did not have.</t>
515
+
516
+ <t>A client can send as many provide messages as necessary to inform
517
+ the server of its entire chunk cache. These messages should be
518
+ interpreted by the server additively. That is, if a client first sends
519
+ a message specifying that it provides byte range A to B and then
520
+ another specifying that it provides byte range C to D, the server
521
+ should conclude that it has byte range A to B and byte range C to D.
522
+ Furthermore, a client can send provide and unprovide messages for
523
+ multiple files, as specified by the url field.</t>
524
+
525
+ <t>If the range in a provide or unprovide message isn't specified, it
526
+ is taken to include the entire range of bytes in the file specified by
527
+ the url field.</t>
528
+
529
+ <t>Fields:</t>
530
+
531
+ <figure>
532
+ <artwork>url: String</artwork>
533
+
534
+ <postamble>A unique file identifier. The client uses this field to
535
+ specify a file in its cache.</postamble>
536
+ </figure>
537
+
538
+ <figure>
539
+ <artwork>range: Range (Optional)</artwork>
540
+
541
+ <postamble>The range of relevant bytes, inclusive. If unspecified,
542
+ it is taken to be the complete range of chunks in the
543
+ file.</postamble>
544
+ </figure>
545
+ </section>
546
+
547
+ <section anchor="askinfo" title="ASKINFO">
548
+ <figure>
549
+ <artwork>ask_info url</artwork>
550
+ </figure>
551
+
552
+ <t>The ask_info datagram is sent to the server when a client wants
553
+ information about a file. Specifically, the client needs information
554
+ about the file type, the file size, the number of chunks, and the size
555
+ of each chunk in order to successfully receive a file. This
556
+ information is used to determine when a file is finished transferring
557
+ and how to handle a file, among other things.</t>
558
+
559
+ <t>It is expected that the server will always respond to an ask_info
560
+ datagram with a <xref target="tellinfo">tell_info</xref> datagram.</t>
561
+
562
+ <t>Fields:</t>
563
+
564
+ <figure>
565
+ <artwork>url: String</artwork>
566
+
567
+ <postamble>A unique file identifier. The client uses this field to
568
+ specify which file it would like information about.</postamble>
569
+ </figure>
570
+ </section>
571
+
572
+ <section anchor="askverify" title="ASKVERIFY">
573
+ <figure>
574
+ <artwork>ask_verify peer url range peer_id</artwork>
575
+ </figure>
576
+
577
+ <t>The ask_verify datagram is sent to the server when a client wants
578
+ to know whether a transfer is authorized. This is sent upon receipt of
579
+ a put or get from a peer.</t>
580
+
581
+ <t>It is expected that the server will always respond to an ask_verify
582
+ datagram with a <xref target="tellverify">tell_verify</xref>
583
+ datagram.</t>
584
+
585
+ <t>Fields:</t>
586
+
587
+ <figure>
588
+ <artwork>peer: String</artwork>
589
+
590
+ <postamble>The network address of the connecting peer.</postamble>
591
+ </figure>
592
+
593
+ <figure>
594
+ <artwork>url: String</artwork>
595
+
596
+ <postamble>A unique file identifier. The client uses this field to
597
+ specify which file it would like information about.</postamble>
598
+ </figure>
599
+
600
+ <figure>
601
+ <artwork>range: Range</artwork>
602
+
603
+ <postamble>The range of bytes in the file referred to by the url for
604
+ which we are asking verification.</postamble>
605
+ </figure>
606
+
607
+ <figure>
608
+ <artwork>peer_id: String</artwork>
609
+
610
+ <postamble>The unique identifier of the peer.</postamble>
611
+ </figure>
612
+ </section>
613
+
614
+ <section anchor="completed" title="COMPLETED">
615
+ <figure>
616
+ <artwork>completed peer url range peer_id [hash]</artwork>
617
+ </figure>
618
+
619
+ <t>The completed message is used by the client to indicate that a
620
+ transfer has completed in either success or failure. Upon success, a
621
+ completed message will include a hash of the chunk that it has
622
+ received. The lack of a hash field denotes transfer failure. The
623
+ server may use this information to inform its network optimization, so
624
+ the appropriate use of completed messages is highly recommended.
625
+ (Specifically, it is likely that the server will initiate another
626
+ transfer after it has been informed that one has completed.)</t>
627
+
628
+ <t>Fields:</t>
629
+
630
+ <figure>
631
+ <artwork>peer: String</artwork>
632
+
633
+ <postamble>The network address of the peer associated with this
634
+ transfer.</postamble>
635
+ </figure>
636
+
637
+ <figure>
638
+ <artwork>url: String</artwork>
639
+
640
+ <postamble>The url of the transferred chunk.</postamble>
641
+ </figure>
642
+
643
+ <figure>
644
+ <artwork>range: Range</artwork>
645
+
646
+ <postamble>The byte range of the completed transfer.</postamble>
647
+ </figure>
648
+
649
+ <figure>
650
+ <artwork>peer_id: String</artwork>
651
+
652
+ <postamble>A unique identifier of the peer associated with the
653
+ transfer.</postamble>
654
+ </figure>
655
+
656
+ <figure>
657
+ <artwork>hash: String (Optional)</artwork>
658
+
659
+ <postamble>A hash of the transferred chunk. Denotes failure if
660
+ blank.</postamble>
661
+ </figure>
662
+ </section>
663
+ </section>
664
+
665
+ <section anchor="client-to-client-communication"
666
+ title="Client to Client Communication">
667
+ <section title="Overview">
668
+ <t>All client to client communication is done using the <xref
669
+ target="refs.HTTP">HTTP 1.1</xref> protocol. Each client is both an
670
+ HTTP client and server. During a transfer, the connecting peer for
671
+ that particular transfer acts as the client and the listening peer
672
+ acts as the server. While full HTTP functionality may be implemented
673
+ and implementation-specifically desirable, only the subset of the HTTP
674
+ protocol that includes the GET and PUT requests and the full range of
675
+ responses is strictly required for the PDTP protocol.</t>
676
+
677
+ <t>The listening client is truly an HTTP server and the connecting
678
+ client is truly an HTTP client. By this we mean simply that not only
679
+ the syntax but also the semantics of the GET and PUT requests and any
680
+ responses received are identical to that of the HTTP protocol.</t>
681
+
682
+ <t>A connecting peer will include the following information in the
683
+ request sent to a listening peer:</t>
684
+
685
+ <t><list style="symbols">
686
+ <t>A compliant <xref target="refs.HTTP">HTTP</xref> Request-Line
687
+ for either a GET or PUT request. The method to use should be taken
688
+ from the method parameter of the <xref
689
+ target="transfer">transfer</xref> message received from the
690
+ server. Similarly, the Request-URI portion of the Request-Line is
691
+ taken from the url field from the server.</t>
692
+
693
+ <t>A Host header, identifying the host in the url specified by the
694
+ server. This host should be recognized as a virtual host on the
695
+ listening peer. It is important to note that this field does not
696
+ necessarily represent any identifier associated with the listening
697
+ peer, but rather the host in the url field from the server.</t>
698
+
699
+ <t>A Range header, identifying the byte range to be transferred,
700
+ taken from the range field in the transfer message.</t>
701
+
702
+ <t>An X-PDTP-Peer-Id header. The value of this header is the Peer
703
+ Id of the connecting client. That is, it is the Peer Id of the
704
+ client sending this request. It is important to note that this is
705
+ not the peer_id field from the transfer message, which represents
706
+ the Peer Id of the listening peer and is necessary when notifying
707
+ the server of transfer completion.</t>
708
+
709
+ <t>If the method is PUT, a body containing the data is also
710
+ sent</t>
711
+ </list></t>
712
+
713
+ <t>Upon receiving a request from a connecting peer, a listening peer
714
+ processes the request in an appropriate manner and sends an
715
+ appropriate response. The listening client may choose to ask the
716
+ server for verification of this transfer using the <xref
717
+ target="askverify">ask_verify</xref> message. If verification fails, a
718
+ 403 Forbidden response should be sent. Similarly, if the file cannot
719
+ be found, or the range is unsatisfiable, the 404 File Not Found or 416
720
+ Requested Range Unsatisfiable responses should be sent. Upon success,
721
+ either 206 Partial Content, 200 OK, or 201 Created should be sent,
722
+ depending on the situation.</t>
723
+ </section>
724
+ </section>
725
+ </middle>
726
+
727
+ <back>
728
+ <references>
729
+ <reference anchor="refs.PDTP"
730
+ target="http://pdtp.org/specification/draft-arcieri-peer-distributed-transfer-protocol.html">
731
+ <front>
732
+ <title>Peer Distributed Transfer Protocol</title>
733
+
734
+ <author fullname="Anthony Arcieri" initials="A.A." surname="Arcieri">
735
+ <organization>ClickCaster.com</organization>
736
+ </author>
737
+
738
+ <date day="30" month="November" year="2005" />
739
+ </front>
740
+ </reference>
741
+
742
+ <reference anchor="refs.HTTP">
743
+ <front>
744
+ <title>Hypertext Transfer Protocol - HTTP/1.1</title>
745
+
746
+ <author fullname="" initials="R.F." surname="Fielding">
747
+ <organization>UC Irvine</organization>
748
+ </author>
749
+
750
+ <author fullname="" initials="J.G." surname="Gettys">
751
+ <organization>Compaq/W3C</organization>
752
+ </author>
753
+
754
+ <author fullname="" initials="J.M." surname="Mogul">
755
+ <organization>Compaq</organization>
756
+ </author>
757
+
758
+ <author fullname="" initials="H.F." surname="Frystyk">
759
+ <organization>W3C/MIT</organization>
760
+ </author>
761
+
762
+ <author fullname="" initials="L.M." surname="Masinter">
763
+ <organization>Xerox</organization>
764
+ </author>
765
+
766
+ <author fullname="" initials="P.L." surname="Fielding">
767
+ <organization>Microsoft</organization>
768
+ </author>
769
+
770
+ <author fullname="" initials="T.B." surname="Berners-Lee">
771
+ <organization>W3C/MIT</organization>
772
+ </author>
773
+
774
+ <date month="June" year="1999" />
775
+ </front>
776
+
777
+ <seriesInfo name="RFC" value="2616" />
778
+ </reference>
779
+
780
+ <reference anchor="refs.JSON">
781
+ <front>
782
+ <title>The application/json Media Type for JavaScript Object
783
+ Notation (JSON)</title>
784
+
785
+ <author initials="D.C." surname="Crockford">
786
+ <organization>JSON.org</organization>
787
+ </author>
788
+
789
+ <date month="July" year="2006" />
790
+ </front>
791
+
792
+ <seriesInfo name="RFC" value="4627" />
793
+ </reference>
794
+ </references>
795
+
796
+ <section title="Glossary">
797
+ <t><list style="symbols">
798
+ <t>Client: a system that accesses a service on a remote computer via
799
+ a network, equivalent to a 'peer'.</t>
800
+
801
+ <t>Connecting peer: The peer that initiates the connection over
802
+ which a transfer takes place.</t>
803
+
804
+ <t>Enumeration: a set of acceptable values.</t>
805
+
806
+ <t>Integer: a unsigned integer field.</t>
807
+
808
+ <t>Listening peer: The peer that accepts the connection over which a
809
+ transfer takes place.</t>
810
+
811
+ <t>Peer: a system that accesses a service on a remote computer via a
812
+ network, equivalent to a 'client'.</t>
813
+
814
+ <t>Peer Id: a unique identifier generated by a client and sent to
815
+ the server, uniquely identifying the client on the network.</t>
816
+
817
+ <t>Range: a representation of a sequence of indices implemented as a
818
+ tuple containing Integer values for minimum and maximum values. All
819
+ ranges referred to in this document are inclusive.</t>
820
+
821
+ <t>Request Set: the set of all chunks that a client has requested
822
+ and not subsequently unrequested.</t>
823
+
824
+ <t>Server: the system that manages the network and distribution of
825
+ information among clients.</t>
826
+
827
+ <t>String: a string of ASCII characters.</t>
828
+ </list></t>
829
+ </section>
830
+ </back>
831
+ </rfc>