p2p2 0.6.3 → 0.6.4

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.
@@ -1,222 +1,222 @@
1
- require 'p2p2/head'
2
- require 'p2p2/version'
3
- require 'socket'
4
-
5
- ##
6
- # P2p2::P2pd - 处于各自nat里的两端p2p。匹配服务器端。
7
- #
8
- #```
9
- # p2pd p2pd
10
- # ^ ^
11
- # ^ ^
12
- # ssh --> p2 --> encode --> nat --> nat --> p1 --> decode --> sshd
13
- #
14
- #```
15
- #
16
- # usage
17
- # =====
18
- #
19
- # 1. Girl::P2pd.new( 5050 ).looping # @server
20
- #
21
- # 2. Girl::P1.new( 'your.server.ip', 5050, '127.0.0.1', 22, '周立波' ).looping # @home1
22
- #
23
- # 3. Girl::P2.new( 'your.server.ip', 5050, '0.0.0.0', 2222, '周立波' ).looping # @home2
24
- #
25
- # 4. ssh -p2222 libo@localhost
26
- #
27
- module P2p2
28
- class P2pd
29
-
30
- ##
31
- # roomd_port 配对服务器端口
32
- # roomd_dir 可在该目录下看到所有的p1
33
- def initialize( roomd_port = 5050, roomd_dir = '/tmp' )
34
- @roomd_port = roomd_port
35
- @roomd_dir = roomd_dir
36
- @mutex = Mutex.new
37
- @roles = {} # sock => :roomd / :room
38
- @pending_p1s = {} # title => room
39
- @pending_p2s = {} # title => room
40
- @infos = {}
41
- @reads = []
42
-
43
- new_roomd
44
- end
45
-
46
- def looping
47
- puts 'looping'
48
-
49
- loop_expire
50
-
51
- loop do
52
- rs, _ = IO.select( @reads )
53
-
54
- @mutex.synchronize do
55
- rs.each do | sock |
56
- case @roles[ sock ]
57
- when :roomd
58
- read_roomd( sock )
59
- when :room
60
- read_room( sock )
61
- end
62
- end
63
- end
64
- end
65
- rescue Interrupt => e
66
- puts e.class
67
- quit!
68
- end
69
-
70
- def quit!
71
- exit
72
- end
73
-
74
- private
75
-
76
- def loop_expire
77
- Thread.new do
78
- loop do
79
- sleep 900
80
-
81
- if @infos.any?
82
- @mutex.synchronize do
83
- now = Time.new
84
-
85
- @infos.select{ | _, info | info[ :last_coming_at ] && ( now - info[ :last_coming_at ] > 1800 ) }.each do | room, _ |
86
- close_sock( room )
87
- end
88
- end
89
- end
90
- end
91
- end
92
- end
93
-
94
- def read_roomd( sock )
95
- begin
96
- room, addr = sock.accept_nonblock
97
- rescue IO::WaitReadable, Errno::EINTR
98
- return
99
- end
100
-
101
- @roles[ room ] = :room
102
- @infos[ room ] = {
103
- title: nil,
104
- last_coming_at: nil,
105
- sockaddr: addr.to_sockaddr
106
- }
107
- @reads << room
108
- end
109
-
110
- def read_room( sock )
111
- begin
112
- data = sock.read_nonblock( PACK_SIZE )
113
- rescue IO::WaitReadable, Errno::EINTR, IO::WaitWritable
114
- return
115
- rescue Exception => e
116
- close_sock( sock )
117
- return
118
- end
119
-
120
- info = @infos[ sock ]
121
- info[ :last_coming_at ] = Time.new
122
-
123
- until data.empty?
124
- ctl_num = data[ 0 ].unpack( 'C' ).first
125
-
126
- case ctl_num
127
- when HEARTBEAT
128
- data = data[ 1..-1 ]
129
- when SET_TITLE
130
- len = data[ 1, 2 ].unpack( 'n' ).first
131
-
132
- if len > 255
133
- puts "title too long"
134
- close_sock( sock )
135
- return
136
- end
137
-
138
- title = data[ 3, len ]
139
-
140
- if @pending_p2s.include?( title )
141
- p2 = @pending_p2s[ title ]
142
- p2_info = @infos[ p2 ]
143
- sock.write( p2_info[ :sockaddr ] )
144
- p2.write( info[ :sockaddr ] )
145
- elsif @pending_p1s.include?( title )
146
- puts "pending p1 #{ title.inspect } already exist"
147
- close_sock( sock )
148
- return
149
- else
150
- @pending_p1s[ title ] = sock
151
- info[ :title ] = title
152
-
153
- begin
154
- File.open( File.join( @roomd_dir, title ), 'w' )
155
- rescue Errno::ENOENT, ArgumentError => e
156
- puts "open title path #{ e.class }"
157
- close_sock( sock )
158
- return
159
- end
160
- end
161
-
162
- data = data[ ( 3 + len )..-1 ]
163
- when PAIRING
164
- len = data[ 1, 2 ].unpack( 'n' ).first
165
-
166
- if len > 255
167
- puts 'pairing title too long'
168
- close_sock( sock )
169
- return
170
- end
171
-
172
- title = data[ 3, len ]
173
-
174
- if @pending_p1s.include?( title )
175
- p1 = @pending_p1s[ title ]
176
- p1_info = @infos[ p1 ]
177
- sock.write( p1_info[ :sockaddr ] )
178
- p1.write( info[ :sockaddr ] )
179
- elsif @pending_p2s.include?( title )
180
- puts "pending p2 #{ title.inspect } already exist"
181
- close_sock( sock )
182
- return
183
- else
184
- @pending_p2s[ title ] = sock
185
- info[ :title ] = title
186
- end
187
-
188
- data = data[ ( 3 + len )..-1 ]
189
- end
190
- end
191
- end
192
-
193
- def close_sock( sock )
194
- sock.close
195
- @roles.delete( sock )
196
- @reads.delete( sock )
197
- info = @infos.delete( sock )
198
-
199
- if info && info[ :title ]
200
- @pending_p1s.delete( info[ :title ] )
201
- @pending_p2s.delete( info[ :title ] )
202
-
203
- begin
204
- File.delete( File.join( @roomd_dir, info[ :title ] ) )
205
- rescue Errno::ENOENT
206
- end
207
- end
208
-
209
- info
210
- end
211
-
212
- def new_roomd
213
- roomd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
214
- roomd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
215
- roomd.bind( Socket.pack_sockaddr_in( @roomd_port, '0.0.0.0' ) )
216
- roomd.listen( 511 )
217
-
218
- @roles[ roomd ] = :roomd
219
- @reads << roomd
220
- end
221
- end
222
- end
1
+ require 'p2p2/head'
2
+ require 'p2p2/version'
3
+ require 'socket'
4
+
5
+ ##
6
+ # P2p2::P2pd - 处于各自nat里的两端p2p。匹配服务器端。
7
+ #
8
+ #```
9
+ # p2pd p2pd
10
+ # ^ ^
11
+ # ^ ^
12
+ # ssh --> p2 --> encode --> nat --> nat --> p1 --> decode --> sshd
13
+ #
14
+ #```
15
+ #
16
+ # usage
17
+ # =====
18
+ #
19
+ # 1. Girl::P2pd.new( 5050 ).looping # @server
20
+ #
21
+ # 2. Girl::P1.new( 'your.server.ip', 5050, '127.0.0.1', 22, '周立波' ).looping # @home1
22
+ #
23
+ # 3. Girl::P2.new( 'your.server.ip', 5050, '0.0.0.0', 2222, '周立波' ).looping # @home2
24
+ #
25
+ # 4. ssh -p2222 libo@localhost
26
+ #
27
+ module P2p2
28
+ class P2pd
29
+
30
+ ##
31
+ # roomd_port 配对服务器端口
32
+ # roomd_dir 可在该目录下看到所有的p1
33
+ def initialize( roomd_port = 5050, roomd_dir = '/tmp' )
34
+ @roomd_port = roomd_port
35
+ @roomd_dir = roomd_dir
36
+ @mutex = Mutex.new
37
+ @roles = {} # sock => :roomd / :room
38
+ @pending_p1s = {} # title => room
39
+ @pending_p2s = {} # title => room
40
+ @infos = {}
41
+ @reads = []
42
+
43
+ new_roomd
44
+ end
45
+
46
+ def looping
47
+ puts 'looping'
48
+
49
+ loop_expire
50
+
51
+ loop do
52
+ rs, _ = IO.select( @reads )
53
+
54
+ @mutex.synchronize do
55
+ rs.each do | sock |
56
+ case @roles[ sock ]
57
+ when :roomd
58
+ read_roomd( sock )
59
+ when :room
60
+ read_room( sock )
61
+ end
62
+ end
63
+ end
64
+ end
65
+ rescue Interrupt => e
66
+ puts e.class
67
+ quit!
68
+ end
69
+
70
+ def quit!
71
+ exit
72
+ end
73
+
74
+ private
75
+
76
+ def loop_expire
77
+ Thread.new do
78
+ loop do
79
+ sleep 900
80
+
81
+ if @infos.any?
82
+ @mutex.synchronize do
83
+ now = Time.new
84
+
85
+ @infos.select{ | _, info | info[ :last_coming_at ] && ( now - info[ :last_coming_at ] > 1800 ) }.each do | room, _ |
86
+ close_sock( room )
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ def read_roomd( sock )
95
+ begin
96
+ room, addr = sock.accept_nonblock
97
+ rescue IO::WaitReadable, Errno::EINTR
98
+ return
99
+ end
100
+
101
+ @roles[ room ] = :room
102
+ @infos[ room ] = {
103
+ title: nil,
104
+ last_coming_at: nil,
105
+ sockaddr: addr.to_sockaddr
106
+ }
107
+ @reads << room
108
+ end
109
+
110
+ def read_room( sock )
111
+ begin
112
+ data = sock.read_nonblock( PACK_SIZE )
113
+ rescue IO::WaitReadable, Errno::EINTR, IO::WaitWritable
114
+ return
115
+ rescue Exception => e
116
+ close_sock( sock )
117
+ return
118
+ end
119
+
120
+ info = @infos[ sock ]
121
+ info[ :last_coming_at ] = Time.new
122
+
123
+ until data.empty?
124
+ ctl_num = data[ 0 ].unpack( 'C' ).first
125
+
126
+ case ctl_num
127
+ when HEARTBEAT
128
+ data = data[ 1..-1 ]
129
+ when SET_TITLE
130
+ len = data[ 1, 2 ].unpack( 'n' ).first
131
+
132
+ if len > 255
133
+ puts "title too long"
134
+ close_sock( sock )
135
+ return
136
+ end
137
+
138
+ title = data[ 3, len ]
139
+
140
+ if @pending_p2s.include?( title )
141
+ p2 = @pending_p2s[ title ]
142
+ p2_info = @infos[ p2 ]
143
+ sock.write( p2_info[ :sockaddr ] )
144
+ p2.write( info[ :sockaddr ] )
145
+ elsif @pending_p1s.include?( title )
146
+ puts "pending p1 #{ title.inspect } already exist"
147
+ close_sock( sock )
148
+ return
149
+ else
150
+ @pending_p1s[ title ] = sock
151
+ info[ :title ] = title
152
+
153
+ begin
154
+ File.open( File.join( @roomd_dir, title ), 'w' )
155
+ rescue Errno::ENOENT, ArgumentError => e
156
+ puts "open title path #{ e.class }"
157
+ close_sock( sock )
158
+ return
159
+ end
160
+ end
161
+
162
+ data = data[ ( 3 + len )..-1 ]
163
+ when PAIRING
164
+ len = data[ 1, 2 ].unpack( 'n' ).first
165
+
166
+ if len > 255
167
+ puts 'pairing title too long'
168
+ close_sock( sock )
169
+ return
170
+ end
171
+
172
+ title = data[ 3, len ]
173
+
174
+ if @pending_p1s.include?( title )
175
+ p1 = @pending_p1s[ title ]
176
+ p1_info = @infos[ p1 ]
177
+ sock.write( p1_info[ :sockaddr ] )
178
+ p1.write( info[ :sockaddr ] )
179
+ elsif @pending_p2s.include?( title )
180
+ puts "pending p2 #{ title.inspect } already exist"
181
+ close_sock( sock )
182
+ return
183
+ else
184
+ @pending_p2s[ title ] = sock
185
+ info[ :title ] = title
186
+ end
187
+
188
+ data = data[ ( 3 + len )..-1 ]
189
+ end
190
+ end
191
+ end
192
+
193
+ def close_sock( sock )
194
+ sock.close
195
+ @roles.delete( sock )
196
+ @reads.delete( sock )
197
+ info = @infos.delete( sock )
198
+
199
+ if info && info[ :title ]
200
+ @pending_p1s.delete( info[ :title ] )
201
+ @pending_p2s.delete( info[ :title ] )
202
+
203
+ begin
204
+ File.delete( File.join( @roomd_dir, info[ :title ] ) )
205
+ rescue Errno::ENOENT
206
+ end
207
+ end
208
+
209
+ info
210
+ end
211
+
212
+ def new_roomd
213
+ roomd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
214
+ roomd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
215
+ roomd.bind( Socket.pack_sockaddr_in( @roomd_port, '0.0.0.0' ) )
216
+ roomd.listen( 511 )
217
+
218
+ @roles[ roomd ] = :roomd
219
+ @reads << roomd
220
+ end
221
+ end
222
+ end
@@ -1,3 +1,3 @@
1
- module P2p2
2
- VERSION = "0.6.3"
3
- end
1
+ module P2p2
2
+ VERSION = "0.6.4"
3
+ end
@@ -1,29 +1,29 @@
1
-
2
- lib = File.expand_path("../lib", __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "p2p2/version"
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "p2p2"
8
- spec.version = P2p2::VERSION
9
- spec.authors = ["takafan"]
10
- spec.email = ["qqtakafan@gmail.com"]
11
-
12
- spec.summary = %q{p2p}
13
- spec.description = %q{p2p even both sides under its nat.}
14
- spec.homepage = "https://github.com/takafan/p2p2"
15
- spec.license = "MIT"
16
-
17
- spec.files = %w[
18
- p2p2.gemspec
19
- lib/p2p2.rb
20
- lib/p2p2/head.rb
21
- lib/p2p2/hex.rb
22
- lib/p2p2/p1.rb
23
- lib/p2p2/p2.rb
24
- lib/p2p2/p2pd.rb
25
- lib/p2p2/version.rb
26
- ]
27
-
28
- spec.require_paths = ["lib"]
29
- end
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "p2p2/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "p2p2"
8
+ spec.version = P2p2::VERSION
9
+ spec.authors = ["takafan"]
10
+ spec.email = ["qqtakafan@gmail.com"]
11
+
12
+ spec.summary = %q{p2p}
13
+ spec.description = %q{p2p even both sides under its nat.}
14
+ spec.homepage = "https://github.com/takafan/p2p2"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = %w[
18
+ p2p2.gemspec
19
+ lib/p2p2.rb
20
+ lib/p2p2/head.rb
21
+ lib/p2p2/hex.rb
22
+ lib/p2p2/p1.rb
23
+ lib/p2p2/p2.rb
24
+ lib/p2p2/p2pd.rb
25
+ lib/p2p2/version.rb
26
+ ]
27
+
28
+ spec.require_paths = ["lib"]
29
+ end