rendezvous-socket 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+ ruby "1.9.3"
3
+
4
+ # Specify your gem's dependencies in rendezvous-socket.gemspec
5
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Michael Hale
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,59 @@
1
+ # Rendezvous::Socket
2
+
3
+ Using the help of a well known rendezvous endpoint establish a peer to
4
+ peer connection between clients which may be behind NAT firewalls. In
5
+ the event that NAT traversal techniques are not successful fallback to
6
+ relaying the connection through the rendezvous server. All connections
7
+ are SSL encrypted. Sessions are managed by the server.
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'rendezvous-socket'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install rendezvous-socket
22
+
23
+ ## Usage
24
+
25
+ 1. On a server with a known IP address run the server.
26
+
27
+ ```bash
28
+ rendezvous-server
29
+ ```
30
+ 2. On 2 peer machines that wish to establish a direct connection with each other run the client.
31
+
32
+ ```bash
33
+ RENDEZVOUS_SERVER=n.n.n.n:5000 rendezvous-client
34
+ ```
35
+
36
+ You will know it worked when you see the hostname of each peer in the
37
+ output of it's peer.
38
+
39
+ ## Contributing
40
+
41
+ 1. Fork it
42
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
43
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
44
+ 4. Push to the branch (`git push origin my-new-feature`)
45
+ 5. Create new Pull Request
46
+
47
+ ## TODO
48
+
49
+ * Speed. Can a connection be established in < 4 seconds?
50
+ * Server managed sessions
51
+ * SSL
52
+ * Clean interface (as similar to socket interface as possible)
53
+ * Fallback to relay mode
54
+
55
+ ## Inspiration
56
+
57
+ * http://www.brynosaurus.com/pub/net/p2pnat/
58
+ * https://github.com/dceballos/tcpnatr
59
+ * http://stackoverflow.com/a/14388707
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path('../../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'rendezvous/socket'
6
+
7
+ $DEBUG = true if ENV['DEBUG']
8
+
9
+ s = Rendezvous::Socket.new(ENV['RENDEZVOUS_SERVER']).open
10
+ s.close
11
+ s.puts Socket.gethostname
12
+ puts s.gets
13
+
14
+ i = 0
15
+ while true
16
+ s.puts i = i + 1
17
+ puts s.gets
18
+ sleep 1
19
+ end
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'socket'
4
+ require 'thread'
5
+ semaphore = Mutex.new
6
+
7
+ PEERS = []
8
+
9
+ def peer(c)
10
+ [c.peeraddr[3], c.peeraddr[1]].join(":")
11
+ end
12
+
13
+ def handle_client(client)
14
+ puts peer(client)
15
+
16
+ #semaphore.synchronize do
17
+ PEERS << client
18
+
19
+ case PEERS.size
20
+ when 0,1
21
+ #noop
22
+ when 2
23
+ peer_a = PEERS[0]
24
+ peer_b = PEERS[1]
25
+ peer_a.puts peer(peer_b)
26
+ peer_b.puts peer(peer_a)
27
+ peer_a.close
28
+ peer_b.close
29
+ PEERS.clear
30
+ else
31
+ PEERS.clear
32
+ end
33
+ #end
34
+ end
35
+
36
+ s = TCPServer.new('0.0.0.0', 5000)
37
+ loop do
38
+ Thread.start(s.accept) do |client|
39
+ handle_client(client)
40
+ end
41
+ end
42
+ s.close
@@ -0,0 +1,55 @@
1
+ require "rendezvous/socket/version"
2
+ require "rendezvous/socket/custom_socket"
3
+
4
+ module Rendezvous
5
+ module Socket
6
+
7
+ def self.new(server)
8
+ RendezvousSocket.new(server)
9
+ end
10
+
11
+ class RendezvousSocket
12
+ attr_reader :rendezvous_server
13
+
14
+ def initialize(rendezvous_server)
15
+ @rendezvous_server = rendezvous_server
16
+ super()
17
+ end
18
+
19
+ def log(args={})
20
+ start = Time.now
21
+ puts args.merge(at: :start)
22
+ result = yield
23
+ elapsed = Time.now - start
24
+ puts args.merge(at: :finish, elapsed: elapsed)
25
+ result
26
+ end
27
+
28
+ # lport=0 causes OS to select a random high port
29
+ def get_peer_endpoint(lport=0)
30
+ socket = CustomSocket.new
31
+ socket.bind(lport)
32
+ socket.connect(*rendezvous_server.split(":"))
33
+
34
+ rhost, rport = socket.gets.chomp.split(":")
35
+ [socket.local_port, rhost, rport.to_i]
36
+ end
37
+
38
+ def peer_socket(lport, rhost, rport)
39
+ peer = CustomSocket.new
40
+ peer.bind(lport)
41
+ peer if peer.connect(rhost, rport)
42
+ end
43
+
44
+ def open
45
+ lport, rhost, rport = nil
46
+ log(step: :get_peer_endpoint) {
47
+ lport, rhost, rport = get_peer_endpoint
48
+ }
49
+ log(step: :connect) {
50
+ peer_socket(lport, rhost, rport)
51
+ }
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,45 @@
1
+ require 'socket'
2
+
3
+ module Rendezvous
4
+ module Socket
5
+ class CustomSocket < ::Socket
6
+ def initialize
7
+ super(AF_INET, SOCK_STREAM, 0)
8
+ setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
9
+ if defined?(SO_REUSEPORT)
10
+ setsockopt(SOL_SOCKET, SO_REUSEPORT, 1)
11
+ end
12
+ end
13
+
14
+ def listen(buf)
15
+ $stderr.puts "attempting to listen" if $DEBUG
16
+ super(buf)
17
+ end
18
+
19
+ def bind(port = 0)
20
+ ip = ::Socket.ip_address_list.detect{|a| a.ipv4_private? }.ip_address
21
+ $stderr.puts "attempting to bind to #{ip}:#{port}" if $DEBUG
22
+ addr_local = ::Socket.pack_sockaddr_in(port, ip)
23
+ super(addr_local)
24
+ end
25
+
26
+ def connect(ip, port)
27
+ $stderr.puts "attempting to connect to #{ip}:#{port}" if $DEBUG
28
+ addr_remote = ::Socket.pack_sockaddr_in(port, ip)
29
+ super(addr_remote)
30
+ end
31
+
32
+ def accept
33
+ super[0]
34
+ end
35
+
36
+ def addr
37
+ ::Socket.unpack_sockaddr_in(getsockname)
38
+ end
39
+
40
+ def local_port
41
+ addr[0]
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,5 @@
1
+ module Rendezvous
2
+ module Socket
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rendezvous/socket/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rendezvous-socket"
8
+ spec.version = Rendezvous::Socket::VERSION
9
+ spec.authors = ["Michael Hale"]
10
+ spec.email = ["mike@hales.ws"]
11
+ spec.description = File.read('README.md').match(/\A#\s+[^\n]+\n+([\W\w]+?)\n+##/)[1].chomp # http://rubular.com/r/vzsBvug0GC
12
+ spec.summary = %q{A ruby socket object which attempts to establish a P2P connection}
13
+ spec.homepage = "https://github.com/mikehale/rendezvous-socket/"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rendezvous-socket
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Michael Hale
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-12-15 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: ! 'Using the help of a well known rendezvous endpoint establish a peer
47
+ to
48
+
49
+ peer connection between clients which may be behind NAT firewalls. In
50
+
51
+ the event that NAT traversal techniques are not successful fallback to
52
+
53
+ relaying the connection through the rendezvous server. All connections
54
+
55
+ are SSL encrypted. Sessions are managed by the server.'
56
+ email:
57
+ - mike@hales.ws
58
+ executables:
59
+ - rendezvous-client
60
+ - rendezvous-server
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - .gitignore
65
+ - Gemfile
66
+ - LICENSE.txt
67
+ - README.md
68
+ - Rakefile
69
+ - bin/rendezvous-client
70
+ - bin/rendezvous-server
71
+ - lib/rendezvous/socket.rb
72
+ - lib/rendezvous/socket/custom_socket.rb
73
+ - lib/rendezvous/socket/version.rb
74
+ - rendezvous-socket.gemspec
75
+ homepage: https://github.com/mikehale/rendezvous-socket/
76
+ licenses:
77
+ - MIT
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 1.8.23
97
+ signing_key:
98
+ specification_version: 3
99
+ summary: A ruby socket object which attempts to establish a P2P connection
100
+ test_files: []