pagoda-tunnel 0.1.0

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