rubtella 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +2 -0
- data/README +5 -0
- data/VERSION +1 -0
- data/config/config.rb +19 -0
- data/lib/errors.rb +4 -0
- data/lib/http_data.rb +53 -0
- data/lib/logger.rb +36 -0
- data/lib/peer.rb +11 -0
- data/lib/rubtella.rb +154 -0
- data/lib/tcp_data.rb +155 -0
- data/rubtella.rb +6 -0
- data/rubtellad.rb +24 -0
- metadata +66 -0
data/.gitignore
ADDED
data/README
ADDED
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.0
|
data/config/config.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Rubtella
|
2
|
+
module Config
|
3
|
+
|
4
|
+
# generating guid
|
5
|
+
def self.generate_guid
|
6
|
+
guid = Array.new
|
7
|
+
16.times { guid << rand(255)}
|
8
|
+
|
9
|
+
guid
|
10
|
+
end
|
11
|
+
|
12
|
+
IP_ADDRESS = "195.150.93.207"
|
13
|
+
PORT = 54321
|
14
|
+
GUID = generate_guid
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
data/lib/errors.rb
ADDED
data/lib/http_data.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
module Rubtella
|
2
|
+
module HTTPData
|
3
|
+
class Builder
|
4
|
+
attr_accessor :status, :headers, :data
|
5
|
+
|
6
|
+
def initialize status = "", headers = nil, data = ""
|
7
|
+
@status = String.new status
|
8
|
+
@headers = headers
|
9
|
+
@data = String.new data
|
10
|
+
end
|
11
|
+
|
12
|
+
def build
|
13
|
+
@http_data = Array.new
|
14
|
+
@http_data << @status
|
15
|
+
@http_data << "\r\n"
|
16
|
+
@headers.each {|k,v| @http_data << "#{k}: #{v}\r\n"}
|
17
|
+
@http_data << "\r\n"
|
18
|
+
@http_data << @data
|
19
|
+
@http_data.to_s
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class Parser
|
24
|
+
|
25
|
+
|
26
|
+
attr_accessor :status, :headers, :data, :http_data, :peers
|
27
|
+
|
28
|
+
def initialize http_data
|
29
|
+
@http_data = http_data
|
30
|
+
parse
|
31
|
+
end
|
32
|
+
|
33
|
+
def parse
|
34
|
+
@headers = Hash.new
|
35
|
+
@peers = Array.new
|
36
|
+
|
37
|
+
headers, @data = @http_data.split("\r\n\r\n")
|
38
|
+
headers = headers.split("\r\n")
|
39
|
+
@status = headers.shift
|
40
|
+
headers.each {|h| k,v = h.split(": "); @headers[k] = v}
|
41
|
+
if up = @headers["X-Try-Ultrapeers"]
|
42
|
+
up.split(",").each {|u| ip,port = u.split(":"); @peers << Peer.new(ip,port)}
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
def ok?
|
49
|
+
@status =~ /200 OK/
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/logger.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'ruby-growl'
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
class RubtellaLogger
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@rubylogger = init_logger
|
9
|
+
@growl = init_growl
|
10
|
+
end
|
11
|
+
|
12
|
+
def init_logger
|
13
|
+
log = Logger.new('log/rubtella.log')
|
14
|
+
log.level = Logger::INFO
|
15
|
+
log.formatter = proc{|s,t,p,m|"%5s [%s] (%s) %s :: %s\n" % [s, t.strftime("%Y-%m-%d %H:%M:%S"), $$, p, m]}
|
16
|
+
return log
|
17
|
+
end
|
18
|
+
|
19
|
+
def init_growl
|
20
|
+
g = Growl.new "localhost", "rubtela",
|
21
|
+
["rubtella log"]
|
22
|
+
return g
|
23
|
+
end
|
24
|
+
|
25
|
+
def info(message)
|
26
|
+
begin
|
27
|
+
@rubylogger.info message
|
28
|
+
@growl.notify "rubtella log", "Rubtella", message
|
29
|
+
rescue
|
30
|
+
puts 'logger error'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
@@logger = RubtellaLogger.new
|
data/lib/peer.rb
ADDED
data/lib/rubtella.rb
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# ruby gnutella client
|
3
|
+
|
4
|
+
require 'socket'
|
5
|
+
require 'timeout'
|
6
|
+
require 'lib/logger'
|
7
|
+
require 'rubygems'
|
8
|
+
require 'ruby-debug'
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
module Rubtella
|
13
|
+
|
14
|
+
GNUTELLA_REQUEST = "GNUTELLA CONNECT/0.6"
|
15
|
+
GNUTELLA_RESPONSE_OK = "GNUTELLA/0.6 200 OK"
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
class Listener
|
20
|
+
|
21
|
+
include Socket::Constants
|
22
|
+
|
23
|
+
#listen for connection
|
24
|
+
def listen
|
25
|
+
server = TCPServer.new("0.0.0.0", PORT)
|
26
|
+
|
27
|
+
|
28
|
+
while (session = server.accept)
|
29
|
+
|
30
|
+
|
31
|
+
Thread.start do
|
32
|
+
|
33
|
+
begin
|
34
|
+
parse_request session
|
35
|
+
rescue => e
|
36
|
+
session.puts "Rubtella Server Error: " + e.to_s
|
37
|
+
puts "Rubtella Server Error: " + e.to_s
|
38
|
+
ensure
|
39
|
+
session.close
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end #end loop
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
def parse_request request
|
48
|
+
req = request.recv 1000
|
49
|
+
|
50
|
+
puts req
|
51
|
+
request.send Sender.pong, 0
|
52
|
+
puts 'response send!'
|
53
|
+
req = request.recv 1000
|
54
|
+
puts 'received content:'
|
55
|
+
|
56
|
+
puts req
|
57
|
+
puts 'received!'
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
class Sender
|
63
|
+
|
64
|
+
|
65
|
+
attr_accessor :peer, :connected
|
66
|
+
|
67
|
+
def initialize peer
|
68
|
+
@peer = peer
|
69
|
+
@standard_headers = {"User-Agent" => "Rubtella",
|
70
|
+
"X-Ultrapeer" => "False",
|
71
|
+
"X-Query-Routing" => "0.1"}
|
72
|
+
end
|
73
|
+
|
74
|
+
def connect
|
75
|
+
begin
|
76
|
+
puts "connecting to: #{@peer.ip}:#{@peer.port}"
|
77
|
+
stream = TCPSocket.new @peer.ip, @peer.port
|
78
|
+
timeout(5) do
|
79
|
+
stream.send handshake_req, 0
|
80
|
+
end
|
81
|
+
@response = stream.recv 1000
|
82
|
+
|
83
|
+
resp = HTTPData::Parser.new @response
|
84
|
+
stream.send handshake_resp, 0
|
85
|
+
|
86
|
+
if resp.ok?
|
87
|
+
#connection established
|
88
|
+
puts 'connection established'
|
89
|
+
@connected = @peer
|
90
|
+
puts "Connected with #{@connected.ip} #{@connected.port}"
|
91
|
+
@@logger.info "Connected with #{@connected.ip} #{@connected.port}"
|
92
|
+
|
93
|
+
manage_connection stream
|
94
|
+
else
|
95
|
+
puts 'failed to connect'
|
96
|
+
@peer = resp.peers.shift
|
97
|
+
connect
|
98
|
+
end
|
99
|
+
rescue Timeout::Error
|
100
|
+
@peer = resp.peers.shift
|
101
|
+
connect
|
102
|
+
rescue => e
|
103
|
+
@@logger.info e.to_s
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def handshake_req
|
108
|
+
req = HTTPData::Builder.new GNUTELLA_REQUEST, @standard_headers
|
109
|
+
req.build
|
110
|
+
end
|
111
|
+
|
112
|
+
def handshake_resp
|
113
|
+
resp = HTTPData::Builder.new GNUTELLA_RESPONSE_OK, @standard_headers
|
114
|
+
resp.build
|
115
|
+
end
|
116
|
+
|
117
|
+
def manage_connection stream
|
118
|
+
loop do
|
119
|
+
puts 'we\'re listening..'
|
120
|
+
resp = stream.recv 1000
|
121
|
+
if parse(resp) == "ping"
|
122
|
+
pong = TCPData::Builder::Pong.new
|
123
|
+
stream.send pong.build , 0
|
124
|
+
puts 'pong send..'
|
125
|
+
stream.close
|
126
|
+
puts 'connection closed'
|
127
|
+
break
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
def parse message
|
136
|
+
parsed = TCPData::Parser.new message
|
137
|
+
puts parsed.message
|
138
|
+
|
139
|
+
parsed.message
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
def send_query(text)
|
144
|
+
stream = TCPSocket.new @connected.ip, @connected.port
|
145
|
+
query = TCPData::Builder::Query.new(:criteria => text)
|
146
|
+
@@logger.info "sending query - #{text}"
|
147
|
+
stream.send query.build, 0
|
148
|
+
puts 'we\'re listening..'
|
149
|
+
resp = stream.recv 1000
|
150
|
+
parse(resp)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
data/lib/tcp_data.rb
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
require 'config/config'
|
2
|
+
|
3
|
+
module Rubtella
|
4
|
+
module TCPData
|
5
|
+
class Base
|
6
|
+
include Rubtella::Config
|
7
|
+
attr_accessor :guid, :payload_type, :ttl, :hops, :payload_lenght, :binary_data, :messages, :messages_codes, :rest
|
8
|
+
|
9
|
+
@messages ={"\000" => "ping",
|
10
|
+
"\001" => "pong",
|
11
|
+
"\100" => "push",
|
12
|
+
"\200" => "query",
|
13
|
+
"\201" => "query_hit"}
|
14
|
+
|
15
|
+
@messages.default = "Unknown Payload Type"
|
16
|
+
|
17
|
+
@messages_codes = {"ping" => 0,
|
18
|
+
"pong" => 1,
|
19
|
+
"push" => 64,
|
20
|
+
"query" => 128,
|
21
|
+
"query_hit" =>129}
|
22
|
+
|
23
|
+
@messages_codes.default = "Unknown Payload Type"
|
24
|
+
end
|
25
|
+
|
26
|
+
class Builder < Base
|
27
|
+
def init_messages_codes
|
28
|
+
@messages_codes = {"ping" => 0,
|
29
|
+
"pong" => 1,
|
30
|
+
"push" => 64,
|
31
|
+
"query" => 128,
|
32
|
+
"query_hit" =>129}
|
33
|
+
|
34
|
+
@messages_codes.default = "Unknown Payload Type"
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def initialize
|
39
|
+
#initailze all stuff
|
40
|
+
init_messages_codes
|
41
|
+
|
42
|
+
@guid = GUID
|
43
|
+
@ttl = 5
|
44
|
+
@hops = 0
|
45
|
+
@payload_length = 0
|
46
|
+
end
|
47
|
+
|
48
|
+
def build
|
49
|
+
@data = Array.new
|
50
|
+
@guid = GUID
|
51
|
+
|
52
|
+
build_message
|
53
|
+
|
54
|
+
@data = [@guid, @payload_type, @ttl, @hops, @payload_length, @payload]
|
55
|
+
|
56
|
+
@binary_data = @data.flatten.pack("C*")
|
57
|
+
@binary_data
|
58
|
+
end
|
59
|
+
|
60
|
+
def build_message
|
61
|
+
# this method needs to be implemented by a child class
|
62
|
+
@payload = []
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
class Ping < Builder
|
67
|
+
def initialize args = nil
|
68
|
+
super()
|
69
|
+
|
70
|
+
@payload_type = @messages_codes["ping"]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class Pong < Builder
|
75
|
+
|
76
|
+
attr_accessor :ip_address , :port
|
77
|
+
|
78
|
+
def initialize args = nil
|
79
|
+
super()
|
80
|
+
|
81
|
+
@payload_type = @messages_codes["pong"]
|
82
|
+
@port = build_port PORT
|
83
|
+
@ip_address = build_ip IP_ADDRESS
|
84
|
+
@files_amount = [0,0,0]
|
85
|
+
@files_size = [0,0,0]
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
def build_message
|
90
|
+
@payload = [@port, @ip_address, @files_amount, @files_size]
|
91
|
+
end
|
92
|
+
|
93
|
+
def build_port(port)
|
94
|
+
[port%256, port/256]# .pack("C*")
|
95
|
+
end
|
96
|
+
|
97
|
+
def build_ip(ip_address)
|
98
|
+
ip_address.split(".").collect {|b| b.to_i} # .pack("C*")
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class Query < Builder
|
103
|
+
|
104
|
+
def initialize args = nil
|
105
|
+
|
106
|
+
super()
|
107
|
+
|
108
|
+
@payload_type = @messages_codes["query"]
|
109
|
+
@speed = 0
|
110
|
+
@criteria = args.is_a?(Hash) ? args[:criteria] : ""
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
def build_message
|
115
|
+
@payload = [@speed, @criteria.unpack("C*")]
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
class Parser < Base
|
122
|
+
|
123
|
+
def initialize data
|
124
|
+
@binary_data = data
|
125
|
+
parse
|
126
|
+
end
|
127
|
+
|
128
|
+
def parse
|
129
|
+
@guid = @binary_data[0..15]
|
130
|
+
@payload_type = @binary_data[16..16]
|
131
|
+
@ttl = @binary_data[17..17]
|
132
|
+
@hops = @binary_data[18..18]
|
133
|
+
@payload_lenght = @binary_data[19..22]
|
134
|
+
@payload = @binary_data[23..-1]
|
135
|
+
end
|
136
|
+
|
137
|
+
def message
|
138
|
+
case @payload_type
|
139
|
+
when "\000"
|
140
|
+
"ping"
|
141
|
+
when "\001"
|
142
|
+
"pong"
|
143
|
+
when "\100"
|
144
|
+
"push"
|
145
|
+
when "\200"
|
146
|
+
"query"
|
147
|
+
when "\201"
|
148
|
+
"query"
|
149
|
+
else
|
150
|
+
raise "Unknown Payload Type"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
data/rubtella.rb
ADDED
data/rubtellad.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rubtella'
|
2
|
+
|
3
|
+
$0 = 'rubtella-base'
|
4
|
+
|
5
|
+
@p = fork do
|
6
|
+
$0 = 'rubtella'
|
7
|
+
Thread.new do
|
8
|
+
server = Rubtella::Listener.new
|
9
|
+
server.listen
|
10
|
+
end
|
11
|
+
|
12
|
+
Thread.new do
|
13
|
+
gnutella = Rubtella::Sender.new Rubtella::Peer.new("70.188.16.73",38093)
|
14
|
+
gnutella.connect
|
15
|
+
gnutella.send_query("doors")
|
16
|
+
end
|
17
|
+
|
18
|
+
while true
|
19
|
+
sleep 100
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
Process.detach(@p)
|
24
|
+
|
metadata
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rubtella
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mateusz Zawisza
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-01-10 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Library for Gnuttale in Ruby
|
17
|
+
email: mateusz.zawisza@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
files:
|
25
|
+
- .gitignore
|
26
|
+
- README
|
27
|
+
- VERSION
|
28
|
+
- config/config.rb
|
29
|
+
- lib/errors.rb
|
30
|
+
- lib/http_data.rb
|
31
|
+
- lib/logger.rb
|
32
|
+
- lib/peer.rb
|
33
|
+
- lib/rubtella.rb
|
34
|
+
- lib/tcp_data.rb
|
35
|
+
- rubtella.rb
|
36
|
+
- rubtellad.rb
|
37
|
+
has_rdoc: true
|
38
|
+
homepage: http://github.com/mateuszzawisza/rubtella/
|
39
|
+
licenses: []
|
40
|
+
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options:
|
43
|
+
- --charset=UTF-8
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: "0"
|
51
|
+
version:
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
version:
|
58
|
+
requirements: []
|
59
|
+
|
60
|
+
rubyforge_project:
|
61
|
+
rubygems_version: 1.3.5
|
62
|
+
signing_key:
|
63
|
+
specification_version: 3
|
64
|
+
summary: Library for Gnuttale in Ruby
|
65
|
+
test_files: []
|
66
|
+
|