p2p2 0.6.8 → 0.6.9

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,286 +1,286 @@
1
- require 'p2p2/head'
2
- require 'p2p2/version'
3
- require 'socket'
4
-
5
- ##
6
- # P2p2::P2pd - 处于nat里的任意应用,访问处于另一个nat里的应用服务端,借助一根p2p管道。配对服务器端。
7
- #
8
- # 1.
9
- #
10
- # ```
11
- # p2pd
12
- # ^ ^
13
- # ^ ^
14
- # “周立波的房间” “周立波的房间”
15
- # ^ ^
16
- # ^ ^
17
- # p1 --> nat --><-- nat <-- p2
18
- #
19
- # ```
20
- #
21
- # 2.
22
- #
23
- # ```
24
- # ssh --> p2 --> (encode) --> p1 --> (decode) --> sshd
25
- # ```
26
- #
27
- # usage
28
- # =====
29
- #
30
- # 1. Girl::P2pd.new( 5050 ).looping # @server
31
- #
32
- # 2. Girl::P1.new( 'your.server.ip', 5050, '127.0.0.1', 22, '周立波' ).looping # @home1
33
- #
34
- # 3. Girl::P2.new( 'your.server.ip', 5050, '0.0.0.0', 2222, '周立波' ).looping # @home2
35
- #
36
- # 4. ssh -p2222 libo@localhost
37
- #
38
- module P2p2
39
- class P2pd
40
-
41
- ##
42
- # roomd_port 配对服务器端口
43
- # roomd_dir 可在该目录下看到所有的p1
44
- def initialize( roomd_port = 5050, roomd_dir = '/tmp' )
45
- @roomd_port = roomd_port
46
- @roomd_dir = roomd_dir
47
- @mutex = Mutex.new
48
- @reads = []
49
- @writes = []
50
- @closings = []
51
- @roles = {} # sock => :roomd / :room
52
- @infos = {}
53
- @rooms = {} # object_id => room
54
- @p1s = {} # title => room
55
- @p2s = {} # title => room
56
-
57
- ctlr, ctlw = IO.pipe
58
- @ctlw = ctlw
59
- @roles[ ctlr ] = :ctlr
60
- @reads << ctlr
61
-
62
- roomd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
63
- roomd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
64
- roomd.bind( Socket.pack_sockaddr_in( @roomd_port, '0.0.0.0' ) )
65
- roomd.listen( 511 )
66
-
67
- @roles[ roomd ] = :roomd
68
- @reads << roomd
69
- end
70
-
71
- def looping
72
- puts 'looping'
73
-
74
- loop_expire
75
-
76
- loop do
77
- rs, ws = IO.select( @reads, @writes )
78
-
79
- @mutex.synchronize do
80
- rs.each do | sock |
81
- case @roles[ sock ]
82
- when :ctlr
83
- read_ctlr( sock )
84
- when :roomd
85
- read_roomd( sock )
86
- when :room
87
- read_room( sock )
88
- end
89
- end
90
-
91
- ws.each do | sock |
92
- case @roles[ sock ]
93
- when :room
94
- write_room( sock )
95
- end
96
- end
97
- end
98
- end
99
- rescue Interrupt => e
100
- puts e.class
101
- quit!
102
- end
103
-
104
- def quit!
105
- exit
106
- end
107
-
108
- private
109
-
110
- def loop_expire
111
- Thread.new do
112
- loop do
113
- sleep 3600
114
-
115
- if @infos.any?
116
- @mutex.synchronize do
117
- now = Time.new
118
-
119
- @infos.select{ | _, info | now - info[ :updated_at ] > 86400 }.each do | room, _ |
120
- @ctlw.write( [ CTL_CLOSE_ROOM, [ room.object_id ].pack( 'N' ) ].join )
121
- end
122
- end
123
- end
124
- end
125
- end
126
- end
127
-
128
- def read_ctlr( ctlr )
129
- case ctlr.read( 1 )
130
- when CTL_CLOSE_ROOM
131
- room_id = ctlr.read( 4 ).unpack( 'N' ).first
132
- room = @rooms[ room_id ]
133
-
134
- if room
135
- add_closing( room )
136
- end
137
- end
138
- end
139
-
140
- def read_roomd( roomd )
141
- begin
142
- room, addrinfo = roomd.accept_nonblock
143
- rescue IO::WaitReadable, Errno::EINTR
144
- return
145
- end
146
-
147
- @rooms[ room.object_id ] = room
148
- @roles[ room ] = :room
149
- @infos[ room ] = {
150
- title: nil,
151
- wbuff: '',
152
- sockaddr: addrinfo.to_sockaddr,
153
- updated_at: Time.new
154
- }
155
- @reads << room
156
- end
157
-
158
- def read_room( room )
159
- begin
160
- data = room.read_nonblock( PACK_SIZE )
161
- rescue IO::WaitReadable, Errno::EINTR, IO::WaitWritable
162
- return
163
- rescue Exception => e
164
- add_closing( room )
165
- return
166
- end
167
-
168
- info = @infos[ room ]
169
- info[ :updated_at ] = Time.new
170
- ctl_num = data[ 0 ].unpack( 'C' ).first
171
-
172
- case ctl_num
173
- when SET_TITLE
174
- title = data[ 1..-1 ]
175
-
176
- if title.size > 255
177
- puts 'title too long'
178
- add_closing( room )
179
- return
180
- end
181
-
182
- if @p1s.include?( title )
183
- puts "p1 #{ title.inspect } already exist"
184
- add_closing( room )
185
- return
186
- end
187
-
188
- if @p2s.include?( title )
189
- p2 = @p2s[ title ]
190
- p2_info = @infos[ p2 ]
191
- add_write( room, p2_info[ :sockaddr ] )
192
- add_write( p2, info[ :sockaddr ] )
193
- return
194
- end
195
-
196
- begin
197
- File.open( File.join( @roomd_dir, title ), 'w' )
198
- rescue Errno::ENOENT, ArgumentError => e
199
- puts "open title path #{ e.class }"
200
- add_closing( room )
201
- return
202
- end
203
-
204
- info[ :title ] = title
205
- @p1s[ title ] = room
206
- when PAIRING
207
- title = data[ 1..-1 ]
208
-
209
- if title.size > 255
210
- puts 'pairing title too long'
211
- add_closing( room )
212
- return
213
- end
214
-
215
- if @p2s.include?( title )
216
- puts "p2 #{ title.inspect } already exist"
217
- add_closing( room )
218
- return
219
- end
220
-
221
- if @p1s.include?( title )
222
- p1 = @p1s[ title ]
223
- p1_info = @infos[ p1 ]
224
- add_write( room, p1_info[ :sockaddr ] )
225
- add_write( p1, info[ :sockaddr ] )
226
- return
227
- end
228
-
229
- info[ :title ] = title
230
- @p2s[ title ] = room
231
- end
232
- end
233
-
234
- def write_room( room )
235
- if @closings.include?( room )
236
- close_room( room )
237
- return
238
- end
239
-
240
- info = @infos[ room ]
241
- room.write( info[ :wbuff ] )
242
- @writes.delete( room )
243
- end
244
-
245
- def add_closing( sock )
246
- unless @closings.include?( sock )
247
- @reads.delete( sock )
248
- @closings << sock
249
- end
250
-
251
- add_write( sock )
252
- end
253
-
254
- def add_write( sock, data = nil )
255
- if data
256
- info = @infos[ sock ]
257
- info[ :wbuff ] = data
258
- end
259
-
260
- unless @writes.include?( sock )
261
- @writes << sock
262
- end
263
- end
264
-
265
- def close_room( room )
266
- room.close
267
- @rooms.delete( room.object_id )
268
- @reads.delete( room )
269
- @writes.delete( room )
270
- @closings.delete( room )
271
- @roles.delete( room )
272
- info = @infos.delete( room )
273
-
274
- if info && info[ :title ]
275
- title_path = File.join( @roomd_dir, info[ :title ] )
276
-
277
- if File.exist?( title_path )
278
- File.delete( title_path )
279
- @p1s.delete( info[ :title ] )
280
- else
281
- @p2s.delete( info[ :title ] )
282
- end
283
- end
284
- end
285
- end
286
- end
1
+ require 'p2p2/head'
2
+ require 'p2p2/version'
3
+ require 'socket'
4
+
5
+ ##
6
+ # P2p2::P2pd - 处于nat里的任意应用,访问处于另一个nat里的应用服务端,借助一根p2p管道。配对服务器端。
7
+ #
8
+ # 1.
9
+ #
10
+ # ```
11
+ # p2pd
12
+ # ^ ^
13
+ # ^ ^
14
+ # “周立波的房间” “周立波的房间”
15
+ # ^ ^
16
+ # ^ ^
17
+ # p1 --> nat --><-- nat <-- p2
18
+ #
19
+ # ```
20
+ #
21
+ # 2.
22
+ #
23
+ # ```
24
+ # ssh --> p2 --> (encode) --> p1 --> (decode) --> sshd
25
+ # ```
26
+ #
27
+ # usage
28
+ # =====
29
+ #
30
+ # 1. Girl::P2pd.new( 5050 ).looping # @server
31
+ #
32
+ # 2. Girl::P1.new( 'your.server.ip', 5050, '127.0.0.1', 22, '周立波' ).looping # @home1
33
+ #
34
+ # 3. Girl::P2.new( 'your.server.ip', 5050, '0.0.0.0', 2222, '周立波' ).looping # @home2
35
+ #
36
+ # 4. ssh -p2222 libo@localhost
37
+ #
38
+ module P2p2
39
+ class P2pd
40
+
41
+ ##
42
+ # roomd_port 配对服务器端口
43
+ # roomd_dir 可在该目录下看到所有的p1
44
+ def initialize( roomd_port = 5050, roomd_dir = '/tmp' )
45
+ @roomd_port = roomd_port
46
+ @roomd_dir = roomd_dir
47
+ @mutex = Mutex.new
48
+ @reads = []
49
+ @writes = []
50
+ @closings = []
51
+ @roles = {} # sock => :roomd / :room
52
+ @infos = {}
53
+ @rooms = {} # object_id => room
54
+ @p1s = {} # title => room
55
+ @p2s = {} # title => room
56
+
57
+ ctlr, ctlw = IO.pipe
58
+ @ctlw = ctlw
59
+ @roles[ ctlr ] = :ctlr
60
+ @reads << ctlr
61
+
62
+ roomd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
63
+ roomd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
64
+ roomd.bind( Socket.pack_sockaddr_in( @roomd_port, '0.0.0.0' ) )
65
+ roomd.listen( 511 )
66
+
67
+ @roles[ roomd ] = :roomd
68
+ @reads << roomd
69
+ end
70
+
71
+ def looping
72
+ puts 'looping'
73
+
74
+ loop_expire
75
+
76
+ loop do
77
+ rs, ws = IO.select( @reads, @writes )
78
+
79
+ @mutex.synchronize do
80
+ rs.each do | sock |
81
+ case @roles[ sock ]
82
+ when :ctlr
83
+ read_ctlr( sock )
84
+ when :roomd
85
+ read_roomd( sock )
86
+ when :room
87
+ read_room( sock )
88
+ end
89
+ end
90
+
91
+ ws.each do | sock |
92
+ case @roles[ sock ]
93
+ when :room
94
+ write_room( sock )
95
+ end
96
+ end
97
+ end
98
+ end
99
+ rescue Interrupt => e
100
+ puts e.class
101
+ quit!
102
+ end
103
+
104
+ def quit!
105
+ exit
106
+ end
107
+
108
+ private
109
+
110
+ def loop_expire
111
+ Thread.new do
112
+ loop do
113
+ sleep 3600
114
+
115
+ if @infos.any?
116
+ @mutex.synchronize do
117
+ now = Time.new
118
+
119
+ @infos.select{ | _, info | now - info[ :updated_at ] > 86400 }.each do | room, _ |
120
+ @ctlw.write( [ CTL_CLOSE_ROOM, [ room.object_id ].pack( 'N' ) ].join )
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ def read_ctlr( ctlr )
129
+ case ctlr.read( 1 )
130
+ when CTL_CLOSE_ROOM
131
+ room_id = ctlr.read( 4 ).unpack( 'N' ).first
132
+ room = @rooms[ room_id ]
133
+
134
+ if room
135
+ add_closing( room )
136
+ end
137
+ end
138
+ end
139
+
140
+ def read_roomd( roomd )
141
+ begin
142
+ room, addrinfo = roomd.accept_nonblock
143
+ rescue IO::WaitReadable, Errno::EINTR
144
+ return
145
+ end
146
+
147
+ @rooms[ room.object_id ] = room
148
+ @roles[ room ] = :room
149
+ @infos[ room ] = {
150
+ title: nil,
151
+ wbuff: '',
152
+ sockaddr: addrinfo.to_sockaddr,
153
+ updated_at: Time.new
154
+ }
155
+ @reads << room
156
+ end
157
+
158
+ def read_room( room )
159
+ begin
160
+ data = room.read_nonblock( PACK_SIZE )
161
+ rescue IO::WaitReadable, Errno::EINTR, IO::WaitWritable
162
+ return
163
+ rescue Exception => e
164
+ add_closing( room )
165
+ return
166
+ end
167
+
168
+ info = @infos[ room ]
169
+ info[ :updated_at ] = Time.new
170
+ ctl_num = data[ 0 ].unpack( 'C' ).first
171
+
172
+ case ctl_num
173
+ when SET_TITLE
174
+ title = data[ 1..-1 ]
175
+
176
+ if title.size > 255
177
+ puts 'title too long'
178
+ add_closing( room )
179
+ return
180
+ end
181
+
182
+ if @p1s.include?( title )
183
+ puts "p1 #{ title.inspect } already exist"
184
+ add_closing( room )
185
+ return
186
+ end
187
+
188
+ if @p2s.include?( title )
189
+ p2 = @p2s[ title ]
190
+ p2_info = @infos[ p2 ]
191
+ add_write( room, p2_info[ :sockaddr ] )
192
+ add_write( p2, info[ :sockaddr ] )
193
+ return
194
+ end
195
+
196
+ begin
197
+ File.open( File.join( @roomd_dir, title ), 'w' )
198
+ rescue Errno::ENOENT, ArgumentError => e
199
+ puts "open title path #{ e.class }"
200
+ add_closing( room )
201
+ return
202
+ end
203
+
204
+ info[ :title ] = title
205
+ @p1s[ title ] = room
206
+ when PAIRING
207
+ title = data[ 1..-1 ]
208
+
209
+ if title.size > 255
210
+ puts 'pairing title too long'
211
+ add_closing( room )
212
+ return
213
+ end
214
+
215
+ if @p2s.include?( title )
216
+ puts "p2 #{ title.inspect } already exist"
217
+ add_closing( room )
218
+ return
219
+ end
220
+
221
+ if @p1s.include?( title )
222
+ p1 = @p1s[ title ]
223
+ p1_info = @infos[ p1 ]
224
+ add_write( room, p1_info[ :sockaddr ] )
225
+ add_write( p1, info[ :sockaddr ] )
226
+ return
227
+ end
228
+
229
+ info[ :title ] = title
230
+ @p2s[ title ] = room
231
+ end
232
+ end
233
+
234
+ def write_room( room )
235
+ if @closings.include?( room )
236
+ close_room( room )
237
+ return
238
+ end
239
+
240
+ info = @infos[ room ]
241
+ room.write( info[ :wbuff ] )
242
+ @writes.delete( room )
243
+ end
244
+
245
+ def add_closing( sock )
246
+ unless @closings.include?( sock )
247
+ @reads.delete( sock )
248
+ @closings << sock
249
+ end
250
+
251
+ add_write( sock )
252
+ end
253
+
254
+ def add_write( sock, data = nil )
255
+ if data
256
+ info = @infos[ sock ]
257
+ info[ :wbuff ] = data
258
+ end
259
+
260
+ unless @writes.include?( sock )
261
+ @writes << sock
262
+ end
263
+ end
264
+
265
+ def close_room( room )
266
+ room.close
267
+ @rooms.delete( room.object_id )
268
+ @reads.delete( room )
269
+ @writes.delete( room )
270
+ @closings.delete( room )
271
+ @roles.delete( room )
272
+ info = @infos.delete( room )
273
+
274
+ if info && info[ :title ]
275
+ title_path = File.join( @roomd_dir, info[ :title ] )
276
+
277
+ if File.exist?( title_path )
278
+ File.delete( title_path )
279
+ @p1s.delete( info[ :title ] )
280
+ else
281
+ @p2s.delete( info[ :title ] )
282
+ end
283
+ end
284
+ end
285
+ end
286
+ end