p2p2 0.6.5 → 0.6.6

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,294 @@
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里的任意应用,访问处于另一个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
+ @reads = []
38
+ @writes = []
39
+ @closings = []
40
+ @rooms = {} # object_id => room
41
+ @pending_p1s = {} # title => room
42
+ @pending_p2s = {} # title => room
43
+ @roles = {} # sock => :roomd / :room
44
+ @infos = {}
45
+
46
+ ctlr, ctlw = IO.pipe
47
+ @ctlw = ctlw
48
+ @reads << ctlr
49
+ @roles[ ctlr ] = :ctlr
50
+
51
+ new_roomd
52
+ end
53
+
54
+ def looping
55
+ puts 'looping'
56
+
57
+ loop_expire
58
+
59
+ loop do
60
+ rs, ws = IO.select( @reads, @writes )
61
+
62
+ @mutex.synchronize do
63
+ rs.each do | sock |
64
+ case @roles[ sock ]
65
+ when :ctlr
66
+ read_ctlr( sock )
67
+ when :roomd
68
+ read_roomd( sock )
69
+ when :room
70
+ read_room( sock )
71
+ end
72
+ end
73
+
74
+ ws.each do | sock |
75
+ case @roles[ sock ]
76
+ when :room
77
+ write_room( sock )
78
+ end
79
+ end
80
+ end
81
+ end
82
+ rescue Interrupt => e
83
+ puts e.class
84
+ quit!
85
+ end
86
+
87
+ def quit!
88
+ exit
89
+ end
90
+
91
+ private
92
+
93
+ def loop_expire
94
+ Thread.new do
95
+ loop do
96
+ sleep 900
97
+
98
+ if @infos.any?
99
+ @mutex.synchronize do
100
+ now = Time.new
101
+
102
+ @infos.select{ | _, info | now - info[ :updated_at ] > 1800 }.each do | room, _ |
103
+ @ctlw.write( [ CTL_CLOSE_ROOM, [ room.object_id ].pack( 'N' ) ].join )
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ def read_ctlr( sock )
112
+ case sock.read( 1 )
113
+ when CTL_CLOSE_ROOM
114
+ room_id = sock.read( 4 ).unpack( 'N' ).first
115
+ room = @rooms[ room_id ]
116
+
117
+ if room
118
+ add_closing( @rooms[ room_id ] )
119
+ end
120
+ end
121
+ end
122
+
123
+ def read_roomd( sock )
124
+ begin
125
+ room, addr = sock.accept_nonblock
126
+ rescue IO::WaitReadable, Errno::EINTR
127
+ return
128
+ end
129
+
130
+ @rooms[ room.object_id ] = room
131
+ @roles[ room ] = :room
132
+ @infos[ room ] = {
133
+ title: nil,
134
+ wbuff: '',
135
+ updated_at: Time.new,
136
+ sockaddr: addr.to_sockaddr
137
+ }
138
+ @reads << room
139
+ end
140
+
141
+ def read_room( sock )
142
+ begin
143
+ data = sock.read_nonblock( PACK_SIZE )
144
+ rescue IO::WaitReadable, Errno::EINTR, IO::WaitWritable
145
+ return
146
+ rescue Exception => e
147
+ add_closing( sock )
148
+ return
149
+ end
150
+
151
+ info = @infos[ sock ]
152
+ info[ :updated_at ] = Time.new
153
+
154
+ until data.empty?
155
+ ctl_num = data[ 0 ].unpack( 'C' ).first
156
+
157
+ case ctl_num
158
+ when HEARTBEAT
159
+ data = data[ 1..-1 ]
160
+ when SET_TITLE
161
+ len = data[ 1, 2 ].unpack( 'n' ).first
162
+
163
+ if len > 255
164
+ puts "title too long"
165
+ add_closing( sock )
166
+ return
167
+ end
168
+
169
+ title = data[ 3, len ]
170
+
171
+ if @pending_p2s.include?( title )
172
+ p2 = @pending_p2s[ title ]
173
+ p2_info = @infos[ p2 ]
174
+ add_write( sock, p2_info[ :sockaddr ] )
175
+ add_write( p2, info[ :sockaddr ] )
176
+ elsif @pending_p1s.include?( title )
177
+ puts "pending p1 #{ title.inspect } already exist"
178
+ add_closing( sock )
179
+ return
180
+ else
181
+ @pending_p1s[ title ] = sock
182
+ info[ :title ] = title
183
+
184
+ begin
185
+ File.open( File.join( @roomd_dir, title ), 'w' )
186
+ rescue Errno::ENOENT, ArgumentError => e
187
+ puts "open title path #{ e.class }"
188
+ add_closing( sock )
189
+ return
190
+ end
191
+ end
192
+
193
+ data = data[ ( 3 + len )..-1 ]
194
+ when PAIRING
195
+ len = data[ 1, 2 ].unpack( 'n' ).first
196
+
197
+ if len > 255
198
+ puts 'pairing title too long'
199
+ add_closing( sock )
200
+ return
201
+ end
202
+
203
+ title = data[ 3, len ]
204
+
205
+ if @pending_p1s.include?( title )
206
+ p1 = @pending_p1s[ title ]
207
+ p1_info = @infos[ p1 ]
208
+ add_write( sock, p1_info[ :sockaddr ] )
209
+ add_write( p1, info[ :sockaddr ] )
210
+ elsif @pending_p2s.include?( title )
211
+ puts "pending p2 #{ title.inspect } already exist"
212
+ add_closing( sock )
213
+ return
214
+ else
215
+ @pending_p2s[ title ] = sock
216
+ info[ :title ] = title
217
+ end
218
+
219
+ data = data[ ( 3 + len )..-1 ]
220
+ end
221
+ end
222
+ end
223
+
224
+ def write_room( sock )
225
+ if @closings.include?( sock )
226
+ close_sock( sock )
227
+ return
228
+ end
229
+
230
+ info = @infos[ sock ]
231
+ data = info[ :wbuff ]
232
+
233
+ if data.empty?
234
+ @writes.delete( sock )
235
+ return
236
+ end
237
+
238
+ sock.write( data )
239
+ info[ :wbuff ].clear
240
+ end
241
+
242
+ def add_closing( sock )
243
+ unless @closings.include?( sock )
244
+ @reads.delete( sock )
245
+ @closings << sock
246
+ end
247
+
248
+ add_write( sock )
249
+ end
250
+
251
+ def add_write( sock, data = nil )
252
+ if data
253
+ info = @infos[ sock ]
254
+ info[ :wbuff ] << data
255
+ end
256
+
257
+ unless @writes.include?( sock )
258
+ @writes << sock
259
+ end
260
+ end
261
+
262
+ def close_sock( sock )
263
+ sock.close
264
+ @reads.delete( sock )
265
+ @writes.delete( sock )
266
+ @closings.delete( sock )
267
+ @rooms.delete( sock.object_id )
268
+ @roles.delete( sock )
269
+ info = @infos.delete( sock )
270
+
271
+ if info && info[ :title ]
272
+ @pending_p1s.delete( info[ :title ] )
273
+ @pending_p2s.delete( info[ :title ] )
274
+
275
+ begin
276
+ File.delete( File.join( @roomd_dir, info[ :title ] ) )
277
+ rescue Errno::ENOENT
278
+ end
279
+ end
280
+
281
+ info
282
+ end
283
+
284
+ def new_roomd
285
+ roomd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
286
+ roomd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
287
+ roomd.bind( Socket.pack_sockaddr_in( @roomd_port, '0.0.0.0' ) )
288
+ roomd.listen( 511 )
289
+
290
+ @roles[ roomd ] = :roomd
291
+ @reads << roomd
292
+ end
293
+ end
294
+ end