rubtella 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|