rtunnel 0.2.3 → 0.3.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/lib/client.rb CHANGED
@@ -3,10 +3,18 @@ require 'optparse'
3
3
  require 'timeout'
4
4
  require 'resolv'
5
5
 
6
+ require 'facets'
7
+ require 'synchash'
8
+
6
9
  require 'core'
10
+ require 'cmds'
11
+
12
+ $debug = true
7
13
 
8
14
  module RTunnel
9
15
  class Client
16
+ CONNECTIONS = SyncHash.new
17
+
10
18
  def initialize(options = {})
11
19
  @control_address = options[:control_address]
12
20
  @control_address << ":#{DEFAULT_CONTROL_PORT}" if @control_address !~ /:\d+$/
@@ -18,9 +26,7 @@ module RTunnel
18
26
  @tunnel_to_address = options[:tunnel_to_address]
19
27
  @tunnel_to_address.insert 0, "localhost:" if @tunnel_to_address =~ /^\d+$/
20
28
 
21
- @tunnel_from_address = @control_host + ":#{options[:tunnel_port] || DEFAULT_TUNNEL_PORT}"
22
-
23
- [@control_address, @remote_listen_address, @tunnel_to_address, @tunnel_from_address].each do |addr|
29
+ [@control_address, @remote_listen_address, @tunnel_to_address].each do |addr|
24
30
  addr.replace_with_ip!
25
31
  end
26
32
 
@@ -43,6 +49,39 @@ module RTunnel
43
49
  end
44
50
  end
45
51
 
52
+ =begin
53
+ # Memory leak testing
54
+ Thread.safe do
55
+ sleep 10
56
+ begin
57
+ objects = Hash.new 0
58
+
59
+ while true
60
+ last_objects = objects.dup
61
+ ObjectSpace.each_object do |o|
62
+ next if ! o.respond_to? :class
63
+ objects[o.class] += 1
64
+ end
65
+
66
+ objects.reject!{|k,v| ! last_objects.has_key? k } unless last_objects.empty?
67
+
68
+ new_objects = objects.dup
69
+ objects.each do |(klass, count)|
70
+ new_objects.delete klass if count < last_objects[klass] # has been GC'ed, "cant be leaking"
71
+ end
72
+ objects = new_objects
73
+
74
+ PP.pp objects.sort_by{|(k,cnt)| cnt }.reverse[0..10], STDERR
75
+
76
+ sleep 10
77
+ end
78
+ rescue Object
79
+ STDERR.puts $!.inspect
80
+ STDERR.puts $!.backtrace.join("\n")
81
+ end
82
+ end
83
+ =end
84
+
46
85
  @main_thread = Thread.safe do
47
86
  while true
48
87
  stop_ping_check
@@ -57,46 +96,50 @@ module RTunnel
57
96
 
58
97
  start_ping_check
59
98
 
60
- @control_sock.sync
61
- @control_sock.puts "remote_listen #{@remote_listen_address}"
62
-
63
- while cmd = (@control_sock.readline.strip rescue (D "#{$!.inspect}"; nil))
64
- case cmd
65
- when "ping"
66
- @last_ping = Time.now
67
-
68
- when "new_tunnel"
69
- @threads << Thread.safe do
70
- D "connecting to to tunnel"
71
- to = TCPSocket.new(*@tunnel_to_address.split(/:/))
72
- D "connecting to from tunnel"
73
- from = TCPSocket.new(*@tunnel_from_address.split(/:/))
74
-
75
- while ready = (IO.select([to, from], nil, nil, 0.5).first rescue [])
76
- if ready.include? to
77
- begin
78
- from.write(to.readpartial(1024))
79
- rescue EOFError
80
- D "to tunnel closed, closing from tunnel"
81
- from.close
82
- to.close
83
-
84
- Thread.exit
85
- end
86
- end
87
-
88
- if ready.include? from
89
- begin
90
- to.write(from.readpartial(1024))
91
- rescue EOFError
92
- D "from tunnel close, closing to tunnel"
93
- from.close
94
- to.close
95
-
96
- Thread.exit
99
+ write_to_control_sock RemoteListenCommand.new(@remote_listen_address)
100
+
101
+ cmd_queue = ""
102
+ while data = (@control_sock.readpartial(16384) rescue (D "#{$!.inspect}"; nil))
103
+ cmd_queue << data
104
+ while Command.match(cmd_queue)
105
+ case command = Command.parse(cmd_queue)
106
+ when PingCommand
107
+ @last_ping = Time.now
108
+ when CreateConnectionCommand
109
+ # TODO: this currently blocks, but if we put it in thread, a SendDataCommand may try to get run for this connection before the connection exists
110
+ CONNECTIONS[command.conn_id] = TCPSocket.new(*@tunnel_to_address.split(/:/))
111
+ Thread.safe do
112
+ cmd = command
113
+ conn = CONNECTIONS[cmd.conn_id]
114
+
115
+ begin
116
+ D "reading local data"
117
+ while localdata = conn.readpartial(16834)
118
+ D "sending data back to server: #{localdata.size}"
119
+ write_to_control_sock SendDataCommand.new(cmd.conn_id, localdata)
97
120
  end
121
+ rescue EOFError
122
+ D "to tunnel closed, closing from tunnel"
123
+ conn.close
124
+ CONNECTIONS.delete cmd.conn_id
125
+ write_to_control_sock CloseConnectionCommand.new(cmd.conn_id)
98
126
  end
99
127
  end
128
+ when CloseConnectionCommand
129
+ D "close " + command.conn_id
130
+ if connection = CONNECTIONS[command.conn_id]
131
+ # TODO: how the hell do u catch a .close error?
132
+ connection.close_read
133
+ #connection.close unless connection.closed?
134
+ CONNECTIONS.delete(command.conn_id)
135
+ end
136
+ when SendDataCommand
137
+ D "send to local " + command.conn_id + " " + command.inspect
138
+ if connection = CONNECTIONS[command.conn_id]
139
+ connection.write(command.data)
140
+ else
141
+ puts "WARNING: received data for non existant connection!"
142
+ end
100
143
  end
101
144
  end
102
145
  end
@@ -117,6 +160,12 @@ module RTunnel
117
160
 
118
161
  private
119
162
 
163
+ def write_to_control_sock(data)
164
+ (@control_sock_mutex ||= Mutex.new).synchronize do
165
+ @control_sock.write data
166
+ end
167
+ end
168
+
120
169
  def start_ping_check
121
170
  @last_ping = Time.now
122
171
  @check_ping = true
data/lib/core.rb CHANGED
@@ -1,13 +1,11 @@
1
1
  module RTunnel
2
- VERSION = '0.2.3'
2
+ VERSION = '0.3.0'
3
3
 
4
4
  DEFAULT_CONTROL_PORT = 19050
5
- DEFAULT_TUNNEL_PORT = 19051
6
5
  PING_TIMEOUT = 10
7
6
  end
8
7
 
9
8
 
10
-
11
9
  def D(msg)
12
10
  puts msg if $debug
13
11
  end
@@ -47,3 +45,9 @@ class IO
47
45
  nil
48
46
  end
49
47
  end
48
+
49
+ class UUID
50
+ def self.t
51
+ timestamp_create.hexdigest
52
+ end
53
+ end
@@ -11,7 +11,6 @@ control_address = tunnel_from_address = tunnel_to_address = remote_listen_addres
11
11
  (opts = OptionParser.new do |o|
12
12
  o.on("-c", "--control-address ADDRESS") { |a| control_address = a }
13
13
  o.on("-f", "--remote-listen-port ADDRESS") { |a| remote_listen_address = a }
14
- o.on("-p", "--tunnel-port ADDRESS") { |a| tunnel_port = a }
15
14
  o.on("-t", "--tunnel-to ADDRESS") { |a| tunnel_to_address = a }
16
15
  end).parse! rescue (puts opts; exit)
17
16
 
@@ -10,12 +10,10 @@ control_address = tunnel_port = nil
10
10
 
11
11
  (opts = OptionParser.new do |o|
12
12
  o.on("-c", "--control ADDRESS") { |a| control_address = a }
13
- o.on("-t", "--tunnel-port PORT") { |a| tunnel_port = a }
14
13
  end).parse! rescue (puts opts; exit)
15
14
 
16
15
  server = RTunnel::Server.new(
17
- :control_address => control_address,
18
- :tunnel_port => tunnel_port
16
+ :control_address => control_address
19
17
  )
20
18
 
21
19
  server.start
data/lib/server.rb CHANGED
@@ -1,7 +1,12 @@
1
1
  require 'gserver'
2
2
  require 'optparse'
3
+ require 'uuidtools'
4
+
5
+ require 'facets'
6
+ require 'synchash'
3
7
 
4
8
  require 'core'
9
+ require 'cmds'
5
10
 
6
11
  Socket.do_not_reverse_lookup = true
7
12
 
@@ -10,36 +15,29 @@ $debug = true
10
15
  module RTunnel
11
16
  # listens for incoming connections to tunnel
12
17
  class RemoteListenServer < GServer
13
- @@m = Mutex.new
14
- @@incoming_connections = []
15
- @@cnt = 0
18
+ CONNECTIONS = SyncHash.new
16
19
 
17
20
  def initialize(port, host = DEFAULT_HOST)
18
21
  super(port, host, 10)
19
22
  end
20
23
 
21
- def self.next_incoming_connection
22
- @@m.synchronize { @@incoming_connections.pop }
23
- end
24
-
25
24
  def serve(sock)
26
- m = Mutex.new
27
- cv = ConditionVariable.new
28
-
29
25
  D "new incoming connection"
30
- incoming = [cv, sock]
31
- @@m.synchronize { @@incoming_connections << incoming }
32
26
 
27
+ conn_id = UUID.t
28
+ CONNECTIONS[conn_id] = sock
33
29
  begin
34
- ControlServer.new_tunnel
35
- rescue
36
- D "error talking on control connection, dropping incoming connection"
30
+ ControlServer.new_tunnel(conn_id)
37
31
 
38
- @@m.synchronize { @@incoming_connections.delete(incoming) }
39
- return
32
+ while data = (sock.readpartial(16384) rescue nil)
33
+ ControlServer.send_data(conn_id, data)
34
+ end
35
+ rescue
36
+ D "error talking on control connection, dropping incoming connection: #{$!.inspect}"
40
37
  end
41
-
42
- m.synchronize { cv.wait(m) }
38
+
39
+ CONNECTIONS.delete conn_id
40
+ ControlServer.close_tunnel(conn_id)
43
41
 
44
42
  D "sock closed"
45
43
  rescue
@@ -47,52 +45,52 @@ module RTunnel
47
45
  puts $!.backtrace.join("\n")
48
46
  end
49
47
  end
50
-
51
- class TunnelListenServer < GServer
52
- @@tunneled_connections = []
53
-
54
- def initialize(port, host = DEFAULT_HOST)
55
- super(port, host, 10)
56
- end
57
-
58
- def serve(sock)
59
- D "new tunneled connection"
60
- cv, incoming_connection = RemoteListenServer.next_incoming_connection
61
- if ! incoming_connection
62
- D "no incoming connections for this tunneled connection, closing"
63
- return
64
- end
65
-
66
- while ready = (IO.select([incoming_connection, sock], nil, nil, 0.5).first rescue [])
67
- if ready.include? incoming_connection
68
- begin
69
- sock.write(incoming_connection.readpartial(1024))
70
- rescue EOFError
71
- D "incoming socket closed, closing tunneled socket"
72
- sock.close
73
- cv.signal
74
-
75
- return
76
- end
77
- end
78
-
79
- if ready.include? sock
80
- begin
81
- incoming_connection.write(sock.readpartial(1024))
82
- rescue EOFError
83
- D "tunneled socket closed, closing incoming connection socket"
84
- incoming_connection.close
85
- cv.signal
86
-
87
- return
88
- end
89
- end
90
- end
91
- rescue Exception
92
- p $!
93
- puts $!.backtrace.join("\n")
94
- end
95
- end
48
+ #
49
+ # class TunnelListenServer < GServer
50
+ # @@tunneled_connections = []
51
+ #
52
+ # def initialize(port, host = DEFAULT_HOST)
53
+ # super(port, host, 10)
54
+ # end
55
+ #
56
+ # def serve(sock)
57
+ # D "new tunneled connection"
58
+ # cv, incoming_connection = RemoteListenServer.next_incoming_connection
59
+ # if ! incoming_connection
60
+ # D "no incoming connections for this tunneled connection, closing"
61
+ # return
62
+ # end
63
+ #
64
+ # while ready = (IO.select([incoming_connection, sock], nil, nil, 0.5).first rescue [])
65
+ # if ready.include? incoming_connection
66
+ # begin
67
+ # sock.write(incoming_connection.readpartial(1024))
68
+ # rescue EOFError
69
+ # D "incoming socket closed, closing tunneled socket"
70
+ # sock.close
71
+ # cv.signal
72
+ #
73
+ # return
74
+ # end
75
+ # end
76
+ #
77
+ # if ready.include? sock
78
+ # begin
79
+ # incoming_connection.write(sock.readpartial(1024))
80
+ # rescue EOFError
81
+ # D "tunneled socket closed, closing incoming connection socket"
82
+ # incoming_connection.close
83
+ # cv.signal
84
+ #
85
+ # return
86
+ # end
87
+ # end
88
+ # end
89
+ # rescue Exception
90
+ # p $!
91
+ # puts $!.backtrace.join("\n")
92
+ # end
93
+ # end
96
94
 
97
95
  class ControlServer < GServer
98
96
  @@control_connection = nil
@@ -102,10 +100,21 @@ module RTunnel
102
100
 
103
101
  attr_accessor :ping_interval
104
102
 
105
- def self.new_tunnel
106
- D "sending new tunnel command"
103
+ def self.new_tunnel(conn_id)
104
+ D "sending create connection command: #{conn_id}"
107
105
 
108
- @@m.synchronize { @@control_connection.write "new_tunnel\n" }
106
+ @@m.synchronize { @@control_connection.write CreateConnectionCommand.new(conn_id) }
107
+ end
108
+
109
+ def self.send_data(conn_id, data)
110
+ D "send to client: #{conn_id}"
111
+ @@m.synchronize { @@control_connection.write SendDataCommand.new(conn_id, data) }
112
+ end
113
+
114
+ def self.close_tunnel(conn_id)
115
+ D "sending close connection command"
116
+
117
+ @@m.synchronize { @@control_connection.write CloseConnectionCommand.new(conn_id) }
109
118
  end
110
119
 
111
120
  def serve(sock)
@@ -113,20 +122,32 @@ module RTunnel
113
122
  @@control_connection = sock
114
123
  sock.sync = true
115
124
 
125
+ cmd_queue = ""
116
126
  while true
117
- if IO.select([sock], nil, nil, @ping_interval)
118
- cmd = sock.readline rescue (D "#{$!.inspect}"; break)
119
- case cmd
120
- when /^remote_listen ([^: ]+:\d+)/
121
- remote_listen_address = $1
122
- @@remote_listen_server.stop if @@remote_listen_server
123
- (@@remote_listen_server = RemoteListenServer.new(*remote_listen_address.split(/:/).reverse)).start
124
- D "listening for remote connections on #{remote_listen_address}"
125
- else
126
- D "bad command received: #{cmd.inspect}"
127
+ if r = IO.select([sock], nil, nil, @ping_interval)
128
+ cmd_queue << sock.readpartial(16384) rescue (D "#{$!.inspect}"; break)
129
+ while Command.match(cmd_queue)
130
+ cmd = Command.parse(cmd_queue)
131
+ case cmd
132
+ when RemoteListenCommand
133
+ @@remote_listen_server.stop if @@remote_listen_server
134
+ (@@remote_listen_server = RemoteListenServer.new(*cmd.address.split(/:/).reverse)).start
135
+ D "listening for remote connections on #{cmd.address}"
136
+ when SendDataCommand
137
+ D "send data to remote conn #{cmd.conn_id}"
138
+ RemoteListenServer::CONNECTIONS[cmd.conn_id].write cmd.data
139
+ when CloseConnectionCommand
140
+ if connection = RemoteListenServer::CONNECTIONS[cmd.conn_id]
141
+ D "closing remote connection: #{cmd.conn_id}"
142
+ connection.close
143
+ end
144
+ else
145
+ D "bad command received: #{cmd.inspect}"
146
+ end
127
147
  end
128
148
  end
129
- sock.puts "ping"
149
+ D "ping"
150
+ @@m.synchronize { @@control_connection.write PingCommand.new }
130
151
  end
131
152
  rescue
132
153
  D $!.inspect
@@ -151,8 +172,6 @@ module RTunnel
151
172
  @control_host = @control_address.split(/:/).first
152
173
 
153
174
  @ping_interval = options[:ping_interval] || 2.0
154
-
155
- @tunnel_address = @control_host + ":#{options[:tunnel_port] || DEFAULT_TUNNEL_PORT}"
156
175
  end
157
176
 
158
177
  def start
@@ -160,9 +179,6 @@ module RTunnel
160
179
  @control_server.ping_interval = @ping_interval
161
180
  @control_server.audit = true
162
181
 
163
- @tunnel_server = TunnelListenServer.new(*@tunnel_address.split(/:/).reverse)
164
-
165
- @tunnel_server.start
166
182
  @control_server.start
167
183
  end
168
184
 
@@ -172,9 +188,7 @@ module RTunnel
172
188
 
173
189
  def stop
174
190
  @control_server.shutdown
175
- @tunnel_server.shutdown
176
191
  ControlServer.stop(@control_server.port, @control_server.host)
177
- TunnelListenServer.stop(@tunnel_server.port, @tunnel_server.host)
178
192
  end
179
193
  end
180
194
  end
data/rtunnel_client.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/ruby
2
2
 
3
- load 'lib/rtunnel_client_cmd.rb'
3
+ load 'lib/rtunnel_client_cmd.rb'
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: rtunnel
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.2.3
7
- date: 2007-11-25 00:00:00 +07:00
6
+ version: 0.3.0
7
+ date: 2007-11-27 00:00:00 +07:00
8
8
  summary: The author was too lazy to write a summary
9
9
  require_paths:
10
10
  - lib