pagoda-tunnel 0.1.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 ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in pagoda-tunnel.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ desc "Run all specs"
5
+ RSpec::Core::RakeTask.new('spec') do |t|
6
+ t.rspec_opts = ['--colour --format documentation']
7
+ end
8
+
9
+ desc "Create tag v#{Pagoda::Tunnel::VERSION}"
10
+ task :tag do
11
+
12
+ puts "tagging version v#{Pagoda::Tunnel::VERSION}"
13
+ `git tag -a v#{Pagoda::Tunnel::VERSION} -m "Version #{Pagoda::Tunnel::VERSION}"`
14
+ `git push origin --tags`
15
+
16
+ end
@@ -0,0 +1,157 @@
1
+ require 'timeout'
2
+ require 'socket'
3
+ require 'openssl'
4
+
5
+ module Pagoda
6
+ class Tunnel
7
+ VERSION = "0.1.0"
8
+ # Your code goes here...
9
+
10
+ def initialize(type, user, pass, app, instance, port = 3306)
11
+ @type = type
12
+ @user = user
13
+ @pass = pass
14
+ @app = app
15
+ @instance = instance
16
+ @port = port
17
+ end
18
+
19
+ def port_available?(ip, port)
20
+ begin
21
+ Timeout::timeout(1) do
22
+ begin
23
+ s = TCPSocket.new(ip, port)
24
+ s.close
25
+ return false
26
+ rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
27
+ return true
28
+ end
29
+ end
30
+ rescue Timeout::Error
31
+ end
32
+ return true
33
+ end
34
+
35
+ def next_available_port(start_port)
36
+ until port_available?("0.0.0.0", start_port)
37
+ # puts "port #{start_port} was not available"
38
+ start_port += 1
39
+ end
40
+ start_port
41
+ end
42
+
43
+ def start
44
+
45
+ [:INT, :TERM].each do |sig|
46
+ Signal.trap(sig) do
47
+ puts "Tunnel Closed."
48
+ puts "-----------------------------------------------"
49
+ puts
50
+ exit
51
+ end
52
+ end
53
+
54
+ remote_host = "tunnel.pagodabox.com" # switch to tunnel.pagodabox.com
55
+ remote_port = 443
56
+
57
+ max_threads = 20
58
+ threads = []
59
+
60
+ chunk = 4096*4096
61
+
62
+ # puts "start TCP server"
63
+ # puts "+> Opening Tunnel"
64
+ @port = next_available_port(@port)
65
+ retrys = 0
66
+ begin
67
+ proxy_server = TCPServer.new('0.0.0.0', @port)
68
+ rescue Exception => e
69
+ @port += 1
70
+ retry if retrys < 4
71
+ # puts "unable to connect to #{@port}. The algorithm is broken"
72
+ exit
73
+ end
74
+
75
+ puts
76
+ puts "Tunnel Established! Accepting connections on :"
77
+ puts "-----------------------------------------------"
78
+ puts
79
+ puts "HOST : 127.0.0.1 (or localhost)"
80
+ puts "PORT : #{@port}"
81
+ puts "USER : (found in pagodabox dashboard)"
82
+ puts "PASS : (found in pagodabox dashboard)"
83
+ puts
84
+ puts "-----------------------------------------------"
85
+ puts "(note : ctrl-c To close this tunnel)"
86
+
87
+ loop do
88
+
89
+ # puts "start a new thread for every client connection"
90
+ threads << Thread.new(proxy_server.accept) do |client_socket|
91
+ begin
92
+ # puts "client connection"
93
+ begin
94
+ server_socket = TCPSocket.new(remote_host, remote_port)
95
+ ssl_context = OpenSSL::SSL::SSLContext.new()
96
+ ssl_socket = OpenSSL::SSL::SSLSocket.new(server_socket, ssl_context)
97
+ ssl_socket.sync_close = true
98
+ ssl_socket.connect
99
+ rescue Errno::ECONNREFUSED
100
+ # puts "connection refused"
101
+ client_socket.close
102
+ raise
103
+ end
104
+
105
+ # puts "authenticate"
106
+ if ssl_socket.readpartial(chunk) == "auth"
107
+ # puts "authentication"
108
+ # puts "auth=#{@type}:#{@user}:#{@pass}:#{@app}:#{@instance}"
109
+ ssl_socket.write "auth=#{@type}:#{@user}:#{@pass}:#{@app}:#{@instance}"
110
+ if ssl_socket.readpartial(chunk) == "success"
111
+ # puts "successful connection"
112
+ else
113
+ # puts "failed connection"
114
+ end
115
+ else
116
+ # puts "danger will robbinson! abort!"
117
+ end
118
+
119
+ loop do
120
+ # puts "wait for data on either socket"
121
+ (ready_sockets, dummy, dummy) = IO.select([client_socket, ssl_socket])
122
+
123
+ # puts "full duplex connection until data stream ends"
124
+ begin
125
+ ready_sockets.each do |socket|
126
+ data = socket.readpartial(chunk)
127
+ if socket == client_socket
128
+ # puts "SERVER <== CLIENT"
129
+ ssl_socket.write data
130
+ ssl_socket.flush
131
+ else
132
+ # puts "SERVER ==> CLIENT"
133
+ client_socket.write data
134
+ client_socket.flush
135
+ end
136
+ end
137
+ rescue EOFError
138
+ break
139
+ end
140
+ end
141
+
142
+ rescue StandardError => error
143
+ end
144
+ client_socket.close rescue StandardError
145
+ ssl_socket.close rescue StandardError
146
+ end
147
+
148
+ # puts "clean up the dead threads, and wait until we have available threads"
149
+ threads = threads.select { |thread| thread.alive? ? true : (thread.join; false) }
150
+ while threads.size >= max_threads
151
+ sleep 1
152
+ threads = threads.select { |thread| thread.alive? ? true : (thread.join; false) }
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "pagoda-tunnel"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "pagoda-tunnel"
7
+ s.version = Pagoda::Tunnel::VERSION
8
+ s.authors = ["Lyon"]
9
+ s.email = ["lyon@delorum.com"]
10
+ s.homepage = "http://www.pagodabox.com"
11
+ s.summary = %q{Pagodabox Tunnel gem}
12
+ s.description = %q{Pagodabox container tunnel. Allows users to tunnel into pagodabox db's.}
13
+
14
+ s.rubyforge_project = "pagoda-tunnel"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # Development
22
+ s.add_development_dependency "rspec"
23
+ # s.add_development_dependency "simplecov"
24
+
25
+
26
+
27
+ # Production
28
+ s.add_dependency "rest-client"
29
+
30
+
31
+ end
@@ -0,0 +1,34 @@
1
+
2
+ require 'pagoda-tunnel'
3
+
4
+ describe Pagoda::Tunnel do
5
+
6
+ it "can create a connection" do
7
+ tunnel = Pagoda::Tunnel.new(nil,nil,nil,nil,nil)
8
+ end
9
+
10
+ it "cannot find an open port" do
11
+ tunnel = Pagoda::Tunnel.new(nil,nil,nil,nil,nil)
12
+ tunnel.port_available?("0.0.0.0", 3309).should == true
13
+ end
14
+
15
+ it "finds an open port" do
16
+ sock = TCPServer.new("0.0.0.0", 40000)
17
+ tunnel = Pagoda::Tunnel.new(nil,nil,nil,nil,nil)
18
+ tunnel.port_available?("0.0.0.0", 40000).should == false
19
+ sock.close
20
+ end
21
+
22
+ it "searches until it finds an available port" do
23
+ tunnel = Pagoda::Tunnel.new(nil,nil,nil,nil,nil)
24
+ tunnel.should_receive(:port_available?).with("0.0.0.0", 40000).and_return false
25
+ tunnel.should_receive(:port_available?).with("0.0.0.0", 40001).and_return false
26
+ tunnel.should_receive(:port_available?).with("0.0.0.0", 40002).and_return false
27
+ tunnel.should_receive(:port_available?).with("0.0.0.0", 40003).and_return true
28
+ STDOUT.stub(:puts)
29
+ tunnel.next_available_port(40000).should == 40003
30
+ end
31
+
32
+ it "needs more testing"
33
+
34
+ end
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pagoda-tunnel
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Lyon
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-10-12 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &2156757880 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *2156757880
25
+ - !ruby/object:Gem::Dependency
26
+ name: rest-client
27
+ requirement: &2156757260 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *2156757260
36
+ description: Pagodabox container tunnel. Allows users to tunnel into pagodabox db's.
37
+ email:
38
+ - lyon@delorum.com
39
+ executables: []
40
+ extensions: []
41
+ extra_rdoc_files: []
42
+ files:
43
+ - .gitignore
44
+ - Gemfile
45
+ - Rakefile
46
+ - lib/pagoda-tunnel.rb
47
+ - pagoda-tunnel.gemspec
48
+ - spec/tunnel_spec.rb
49
+ homepage: http://www.pagodabox.com
50
+ licenses: []
51
+ post_install_message:
52
+ rdoc_options: []
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubyforge_project: pagoda-tunnel
69
+ rubygems_version: 1.8.10
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: Pagodabox Tunnel gem
73
+ test_files:
74
+ - spec/tunnel_spec.rb