surro-gate 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 23723ea57a4d00802173cfd2f9701b79a5815385
4
+ data.tar.gz: f9f596cea08d8bcf926823ccfc3599e0d5c618c9
5
+ SHA512:
6
+ metadata.gz: 6660ec99537aa1994670ea471d8b4df099cfa376b22d5bd403dcd2652d302374824d3ef22b16ea177ee62b17a5d169a0ef9eb97c4a8d8dfe6e30a37d17f2b943
7
+ data.tar.gz: 9666acf2ab83171d83f997f80d784b740a499ad6458cd57c9887562c4f6cc94822b7eefd8d4302c379ea921ea282095ffe6a5ebf4b1b1f3bcebca9246da5a773
data/.codeclimate.yml ADDED
@@ -0,0 +1,25 @@
1
+ ---
2
+ engines:
3
+ duplication:
4
+ enabled: true
5
+ config:
6
+ languages:
7
+ - ruby
8
+ - javascript
9
+ - python
10
+ - php
11
+ fixme:
12
+ enabled: true
13
+ rubocop:
14
+ enabled: true
15
+ ratings:
16
+ paths:
17
+ - "**.inc"
18
+ - "**.js"
19
+ - "**.jsx"
20
+ - "**.module"
21
+ - "**.php"
22
+ - "**.py"
23
+ - "**.rb"
24
+ exclude_paths:
25
+ - spec/
data/.gitignore ADDED
@@ -0,0 +1,28 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+
13
+ ## Documentation cache and generated files:
14
+ /.yardoc/
15
+ /_yardoc/
16
+ /doc/
17
+ /rdoc/
18
+
19
+ ## Environment normalization:
20
+ /.bundle/
21
+ /vendor/bundle
22
+ /lib/bundler/man/
23
+
24
+ # for a library or gem, you might want to ignore these files since the code is
25
+ # intended to run in multiple environments; otherwise, check them in:
26
+ Gemfile.lock
27
+ .ruby-version
28
+ .ruby-gemset
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,22 @@
1
+ Metrics/PerceivedComplexity:
2
+ Enabled: false
3
+ Metrics/CyclomaticComplexity:
4
+ Enabled: false
5
+ Metrics/AbcSize:
6
+ Enabled: false
7
+ Style/RedundantFreeze:
8
+ Enabled: false
9
+ Style/IndentationConsistency:
10
+ EnforcedStyle: normal
11
+ Metrics/LineLength:
12
+ Max: 140
13
+ Style/HashSyntax:
14
+ EnforcedStyle: hash_rockets
15
+ Documentation:
16
+ Enabled: false
17
+ Metrics/MethodLength:
18
+ Max: 20
19
+ Style/FileName:
20
+ Exclude:
21
+ - lib/surro-gate.rb
22
+ - spec/surro-gate_spec.rb
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ sudo: false
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.3.1
6
+ before_install:
7
+ - "echo 'gem: --no-ri --no-rdoc --no-document' > ~/.gemrc"
8
+ - "gem install bundler -v 1.13.0"
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in surro-gate.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2016 Dávid Halász
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Dávid Halász
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # SurroGate
2
+
3
+ [![Build Status](https://travis-ci.org/skateman/surro-gate.svg?branch=master)](https://travis-ci.org/skateman/surro-gate)
4
+ [![Dependency Status](https://gemnasium.com/skateman/surro-gate.svg)](https://gemnasium.com/skateman/surro-gate)
5
+ [![Inline docs](http://inch-ci.org/github/skateman/surro-gate.svg?branch=master)](http://inch-ci.org/github/skateman/surro-gate)
6
+ [![Code Climate](https://codeclimate.com/github/skateman/surro-gate/badges/gpa.svg)](https://codeclimate.com/github/skateman/surro-gate)
7
+ [![codecov](https://codecov.io/gh/skateman/surro-gate/branch/master/graph/badge.svg)](https://codecov.io/gh/skateman/surro-gate)
8
+
9
+ SurroGate is a general purpose TCP-to-TCP proxy implemented in Ruby.
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ ```ruby
16
+ gem 'surro-gate'
17
+ ```
18
+
19
+ And then execute:
20
+
21
+ $ bundle
22
+
23
+ Or install it yourself as:
24
+
25
+ $ gem install surro-gate
26
+
27
+ ## Usage
28
+
29
+ ```ruby
30
+ require 'surro-gate'
31
+
32
+ proxy = SurroGate.new
33
+
34
+ # Create two TCP socket connections
35
+ left = TCPSocket.new('localhost', 3333)
36
+ right = TCPSocket.new('localhost', 2222)
37
+
38
+ # Push the sockets to the proxy
39
+ proxy.push(left, right)
40
+
41
+ # Wait for the communication to finish
42
+ proxy.wait
43
+
44
+ ```
45
+
46
+ ## Development
47
+
48
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
49
+
50
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
51
+
52
+ ## Contributing
53
+
54
+ Bug reports and pull requests are welcome on GitHub at https://github.com/skateman/surro-gate.
55
+
56
+
57
+ ## License
58
+
59
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
60
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'surro-gate'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require 'irb'
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/lib/surro-gate.rb ADDED
@@ -0,0 +1,14 @@
1
+ require 'surro-gate/version'
2
+ require 'surro-gate/proxy_error'
3
+ require 'surro-gate/proxy'
4
+
5
+ # A generic purpose TCP-to-TCP proxy
6
+ module SurroGate
7
+ class << self
8
+ # Initializes a new Proxy instance
9
+ # @return [Proxy]
10
+ def new
11
+ Proxy.new
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,110 @@
1
+ require 'nio'
2
+
3
+ module SurroGate
4
+ # This class is responsible for connecting TCP socket pairs and proxying between them.
5
+ #
6
+ # It uses a lazily-forked thread to handle the non blocking read and write operations.
7
+ # If one of the sockets get closed, the proxy automatically cleans up by deregistering
8
+ # and closing its pair. When the last socket pair gets cleaned up, the internal thread
9
+ # is killed automatically.
10
+ #
11
+ # The proxy was designed to be highly reusable and it can handle multiple socket pairs.
12
+ class Proxy
13
+ def initialize
14
+ @mutex = Mutex.new
15
+ @selector = NIO::Selector.new
16
+ end
17
+
18
+ # Registers a pair of socket for proxying.
19
+ #
20
+ # It also forks the internal thread if it is not running yet.
21
+ #
22
+ # @raise [ProxyError] when at least one of the pushed sockets is already registered
23
+ # @param left [TCPSocket]
24
+ # @param right [TCPSocket]
25
+ # @return the registered socket pair as an array
26
+ def push(left, right)
27
+ raise ProxyError, 'Socket already handled by the proxy' if includes?(left, right)
28
+
29
+ @mutex.synchronize do
30
+ proxy(left, right)
31
+ end
32
+
33
+ [left, right]
34
+ end
35
+
36
+ # Blocking wait until the internal thread is doing something useful.
37
+ def wait
38
+ @thread.join if alive?
39
+ end
40
+
41
+ # Determine if the internal thread is currently running or not.
42
+ def alive?
43
+ !@thread.nil? && @thread.alive?
44
+ end
45
+
46
+ private
47
+
48
+ def proxy(left, right)
49
+ # Pass boths sockets to the Nio4r selector
50
+ monitors = [left, right].map { |socket| @selector.register(socket, :rw) }
51
+
52
+ # Set up handlers for both monitors
53
+ monitors.each do |src|
54
+ # Get the destination paired with the source
55
+ dst = monitors.reject { |m| m == src }.first
56
+ # Set up a proc for future transmissions
57
+ src.value = proc do
58
+ transmit(src.io, dst.io) if src.readable? && dst.writable?
59
+ end
60
+ end
61
+
62
+ # Make sure that the internal thread is started
63
+ thread_start unless @selector.empty?
64
+ end
65
+
66
+ def transmit(src, dst)
67
+ dst.write_nonblock(src.read_nonblock(4096))
68
+ rescue # Clean up both sockets if something bad happens
69
+ cleanup(src, dst)
70
+ end
71
+
72
+ def cleanup(*sockets)
73
+ # Deregister and close the sockets
74
+ sockets.each do |socket|
75
+ @selector.deregister(socket) if @selector.registered?(socket)
76
+ socket.close unless socket.closed?
77
+ end
78
+
79
+ # Make sure that the internal thread is stopped if no sockets remain
80
+ thread_stop if @selector.empty?
81
+ end
82
+
83
+ def thread_start
84
+ @thread ||= Thread.new do
85
+ loop do
86
+ reactor
87
+ end
88
+ end
89
+ end
90
+
91
+ def thread_stop
92
+ return if @thread.nil?
93
+ @thread.kill
94
+ @thread = nil
95
+ end
96
+
97
+ def reactor
98
+ # Atomically get an array of readable/writable monitors
99
+ monitors = @mutex.synchronize { @selector.select(0.1) || [] }
100
+ # Call each transmission proc and collect the results
101
+ callers = monitors.map { |m| m.value.call }
102
+ # Sleep for a short time if there was no transmission
103
+ sleep(0.1) if callers.none? && monitors.any?
104
+ end
105
+
106
+ def includes?(*sockets)
107
+ sockets.map { |socket| @selector.registered?(socket) }.any?
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,5 @@
1
+ module SurroGate
2
+ # This error is raised when at least one of the pushed sockets is already registered
3
+ class ProxyError < StandardError
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ module SurroGate
2
+ VERSION = '0.1.0'.freeze
3
+ end
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'surro-gate/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'surro-gate'
8
+ spec.version = SurroGate::VERSION
9
+ spec.authors = ['Dávid Halász']
10
+ spec.email = ['skateman@skateman.eu']
11
+
12
+ spec.summary = 'A general purrpose TCP-to-TCP proxy written in Ruby'
13
+ spec.description = 'A general purrpose TCP-to-TCP proxy written in Ruby'
14
+ spec.homepage = 'https://github.com/skateman/surro-gate'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = 'exe'
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ['lib']
23
+
24
+ spec.add_dependency 'nio4r', '~> 1.2.0'
25
+
26
+ spec.add_development_dependency 'bundler', '~> 1.13'
27
+ spec.add_development_dependency 'codecov', '~> 0.1.0'
28
+ spec.add_development_dependency 'nyan-cat-formatter', '~> 0.11'
29
+ spec.add_development_dependency 'rake', '~> 10.0'
30
+ spec.add_development_dependency 'rspec', '~> 3.0'
31
+ spec.add_development_dependency 'simplecov', '~> 0.12'
32
+ end
metadata ADDED
@@ -0,0 +1,159 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: surro-gate
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Dávid Halász
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-11-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nio4r
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 1.2.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.13'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.13'
41
+ - !ruby/object:Gem::Dependency
42
+ name: codecov
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.1.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.1.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: nyan-cat-formatter
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.11'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.11'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '10.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '10.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: simplecov
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.12'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.12'
111
+ description: A general purrpose TCP-to-TCP proxy written in Ruby
112
+ email:
113
+ - skateman@skateman.eu
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".codeclimate.yml"
119
+ - ".gitignore"
120
+ - ".rspec"
121
+ - ".rubocop.yml"
122
+ - ".travis.yml"
123
+ - Gemfile
124
+ - LICENSE
125
+ - LICENSE.txt
126
+ - README.md
127
+ - Rakefile
128
+ - bin/console
129
+ - bin/setup
130
+ - lib/surro-gate.rb
131
+ - lib/surro-gate/proxy.rb
132
+ - lib/surro-gate/proxy_error.rb
133
+ - lib/surro-gate/version.rb
134
+ - surro-gate.gemspec
135
+ homepage: https://github.com/skateman/surro-gate
136
+ licenses:
137
+ - MIT
138
+ metadata: {}
139
+ post_install_message:
140
+ rdoc_options: []
141
+ require_paths:
142
+ - lib
143
+ required_ruby_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ required_rubygems_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ requirements: []
154
+ rubyforge_project:
155
+ rubygems_version: 2.5.1
156
+ signing_key:
157
+ specification_version: 4
158
+ summary: A general purrpose TCP-to-TCP proxy written in Ruby
159
+ test_files: []