p2p2 0.6.5 → 0.6.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fd367a9337387416c03593441c48cba25856400072a2c0ce555a14c5feecc162
4
- data.tar.gz: 952c62110190f7a7fec3ae6a019e53327bac33ce18b02efae22f0dad8c11e713
3
+ metadata.gz: 260396471208a2a26bf462d5715a8b3d19a7376446dd3d5eefdd5018dcd3cf1b
4
+ data.tar.gz: 4a2784bf9e55e8d3318f295901aa269f6dfb6ac6ba7c75f6bcf0197e613a606a
5
5
  SHA512:
6
- metadata.gz: 9a4c5df8310781d84d2291cba5daccd9da77c62eb2f2cfe4f13b5630910704e86128889db7fd69d926ba5a716d35ce4503c98b07d19168f04a868060788a9bec
7
- data.tar.gz: fb079fcdebbca54863563372b239af76563f3f9feb11fec5ef05922b1d6aaee8ee58b5ae2ee9f8505ad1fbeb897e625dd96ce4a55009c2abebf4e0bb9ea2c7af
6
+ metadata.gz: 27bc8ed465e51237c4e5c2c4234d5a983a50a8cdb9a24bc7d473d5d92bb08c36179c4e5f13ab24b790dcd8f117f1a35147a014054dd5a5c8055bcbe161f4605d
7
+ data.tar.gz: 0fbef6c2104a359183f06a87a4121a8d63dae70e4a48ea8055366e55f549299bfec84ae9b0b4a10ae92124e34a31a2c2e1102ae7126db483b7d528c41e09bde6
@@ -1,6 +1,3 @@
1
- require "p2p2/version"
2
-
3
- module P2p2
4
- class Error < StandardError; end
5
- # Your code goes here...
6
- end
1
+ require 'p2p2/p1'
2
+ require 'p2p2/p2'
3
+ require 'p2p2/p2pd'
@@ -1,10 +1,11 @@
1
- module P2p2
2
- PACK_SIZE = 1448 # 包大小
3
- CHUNK_SIZE = PACK_SIZE * 1000 # 块大小
4
- REP2P_LIMIT = 5 # p2p重试次数。到早了另一头还没从洞里出来,会吃ECONNREFUSED,不慌,再来一发。
5
- HEARTBEAT = 1
6
- SET_TITLE = 2
7
- PAIRING = 3
8
- NEED_CHUNK = true
9
- NEED_RENEW = true
10
- end
1
+ module P2p2
2
+ PACK_SIZE = 1448 # 包大小
3
+ CHUNK_SIZE = PACK_SIZE * 1000 # 块大小
4
+ REP2P_LIMIT = 5 # p2p重试次数。到早了另一头还没从洞里出来,会吃ECONNREFUSED,不慌,再来一发。
5
+ HEARTBEAT = 1
6
+ SET_TITLE = 2
7
+ PAIRING = 3
8
+ NEED_CHUNK = true
9
+ CTL_CLOSE_ROOM = [ 1 ].pack( 'C' )
10
+ CTL_RENEW_ROOM = [ 2 ].pack( 'C' )
11
+ end
@@ -1,410 +1,439 @@
1
- require 'p2p2/head'
2
- require 'p2p2/hex'
3
- require 'p2p2/version'
4
- require 'socket'
5
-
6
- ##
7
- # P2p2::P1 - 处于各自nat里的两端p2pp1端。
8
- #
9
- module P2p2
10
- class P1
11
-
12
- ##
13
- # roomd_host 匹配服务器ip
14
- # roomd_port 匹配服务器端口
15
- # appd_host 任意的一个应用的ip
16
- # appd_port 应用端口
17
- # title 约定的房间名
18
- # app_chunk_dir 文件缓存目录,缓存app来不及写的流量
19
- # p1_chunk_dir 文件缓存目录,缓存p1来不及写的流量
20
- def initialize( roomd_host, roomd_port, appd_host, appd_port, title, app_chunk_dir = '/tmp', p1_chunk_dir = '/tmp' )
21
- @roomd_sockaddr = Socket.sockaddr_in( roomd_port, roomd_host )
22
- @appd_sockaddr = Socket.sockaddr_in( appd_port, appd_host )
23
- @title = title
24
- @app_chunk_dir = app_chunk_dir
25
- @p1_chunk_dir = p1_chunk_dir
26
- @hex = P2p2::Hex.new
27
- @mutex = Mutex.new
28
- @roles = {} # sock => :room / :p1 / :app
29
- @infos = {}
30
- @closings = {} # sock => need_renew
31
- @reads = []
32
- @writes = []
33
- @is_renew = false
34
-
35
- new_room
36
- end
37
-
38
- def looping
39
- puts 'looping'
40
-
41
- loop_heartbeat
42
-
43
- loop do
44
- rs, ws = IO.select( @reads, @writes )
45
-
46
- @mutex.synchronize do
47
- rs.each do | sock |
48
- case @roles[ sock ]
49
- when :room
50
- read_room( sock )
51
- when :p1
52
- read_p1( sock )
53
- when :app
54
- read_app( sock )
55
- end
56
- end
57
-
58
- ws.each do | sock |
59
- case @roles[ sock ]
60
- when :room
61
- write_room( sock )
62
- when :p1
63
- write_p1( sock )
64
- when :app
65
- write_app( sock )
66
- end
67
- end
68
- end
69
- end
70
- rescue Interrupt => e
71
- puts e.class
72
- quit!
73
- end
74
-
75
- def quit!
76
- exit
77
- end
78
-
79
- private
80
-
81
- def loop_heartbeat
82
- Thread.new do
83
- loop do
84
- sleep 59
85
-
86
- @mutex.synchronize do
87
- @room.write( [ HEARTBEAT ].pack( 'C' ) )
88
- end
89
- end
90
- end
91
- end
92
-
93
- def read_room( sock )
94
- begin
95
- data = sock.read_nonblock( PACK_SIZE )
96
- rescue IO::WaitReadable, Errno::EINTR, IO::WaitWritable => e
97
- return
98
- rescue Errno::ECONNREFUSED, EOFError, Errno::ECONNRESET => e
99
- puts "read room #{ e.class } #{ Time.new }"
100
-
101
- if @is_renew
102
- raise e
103
- end
104
-
105
- add_closing( sock )
106
- return
107
- end
108
-
109
- @is_renew = false
110
- info = @infos[ sock ]
111
- info[ :p2_sockaddr ] = data
112
- new_p1
113
- end
114
-
115
- def read_p1( sock )
116
- begin
117
- data = sock.read_nonblock( PACK_SIZE )
118
- rescue IO::WaitReadable, Errno::EINTR, IO::WaitWritable => e
119
- return
120
- rescue Errno::ECONNREFUSED => e
121
- if @room_info[ :rep2p ] >= REP2P_LIMIT
122
- raise e
123
- end
124
-
125
- add_closing( sock, NEED_RENEW )
126
- return
127
- rescue Exception => e
128
- add_closing( sock )
129
- return
130
- end
131
-
132
- @room_info[ :rep2p ] = 0
133
- info = @infos[ sock ]
134
-
135
- if info[ :need_decode ]
136
- len = data[ 0, 2 ].unpack( 'n' ).first
137
- head = @hex.decode( data[ 2, len ] )
138
- data = head + data[ ( 2 + len )..-1 ]
139
- info[ :need_decode ] = false
140
- end
141
-
142
- add_write( @app, data, NEED_CHUNK )
143
- end
144
-
145
- def read_app( sock )
146
- begin
147
- data = sock.read_nonblock( PACK_SIZE )
148
- rescue IO::WaitReadable, Errno::EINTR, IO::WaitWritable => e
149
- return
150
- rescue Exception => e
151
- add_closing( sock )
152
- return
153
- end
154
-
155
- info = @infos[ sock ]
156
-
157
- if info[ :need_encode ]
158
- data = @hex.encode( data )
159
- data = [ [ data.size ].pack( 'n' ), data ].join
160
- info[ :need_encode ] = false
161
- end
162
-
163
- add_write( @p1, data, NEED_CHUNK )
164
- end
165
-
166
- def write_room( sock )
167
- if @closings.include?( sock )
168
- close_sock( sock )
169
- sleep 5
170
- new_room
171
- @is_renew = true
172
- @closings.delete( sock )
173
-
174
- return
175
- end
176
-
177
- info = @infos[ sock ]
178
- data = info[ :wbuff ]
179
-
180
- if data.empty?
181
- @writes.delete( sock )
182
- return
183
- end
184
-
185
- sock.write( data )
186
- info[ :wbuff ].clear
187
- end
188
-
189
- def write_p1( sock )
190
- if @closings.include?( sock )
191
- close_sock( sock )
192
- @p1 = nil
193
-
194
- if @app && !@app.closed?
195
- add_closing( @app )
196
- end
197
-
198
- need_renew = @closings.delete( sock )
199
-
200
- if need_renew
201
- sleep 1
202
- new_p1
203
- @room_info[ :rep2p ] += 1
204
- end
205
-
206
- return
207
- end
208
-
209
- info = @infos[ sock ]
210
- data, from = get_buff( info )
211
-
212
- if data.empty?
213
- @writes.delete( sock )
214
- return
215
- end
216
-
217
- begin
218
- written = sock.write_nonblock( data )
219
- rescue IO::WaitWritable, Errno::EINTR, IO::WaitReadable
220
- return
221
- rescue Exception => e
222
- add_closing( sock )
223
- return
224
- end
225
-
226
- data = data[ written..-1 ]
227
- info[ from ] = data
228
- end
229
-
230
- def write_app( sock )
231
- if @closings.include?( sock )
232
- close_sock( sock )
233
- @app = nil
234
-
235
- if @p1 && !@p1.closed?
236
- add_closing( @p1 )
237
- end
238
-
239
- @closings.delete( sock )
240
- return
241
- end
242
-
243
- info = @infos[ sock ]
244
- data, from = get_buff( info )
245
-
246
- if data.empty?
247
- @writes.delete( sock )
248
- return
249
- end
250
-
251
- begin
252
- written = sock.write_nonblock( data )
253
- rescue IO::WaitWritable, Errno::EINTR, IO::WaitReadable
254
- return
255
- rescue Exception => e
256
- add_closing( sock )
257
- return
258
- end
259
-
260
- data = data[ written..-1 ]
261
- info[ from ] = data
262
- end
263
-
264
- def get_buff( info )
265
- data, from = info[ :cache ], :cache
266
-
267
- if data.empty?
268
- if info[ :chunks ].any?
269
- path = File.join( info[ :chunk_dir ], info[ :chunks ].shift )
270
- data = info[ :cache ] = IO.binread( path )
271
-
272
- begin
273
- File.delete( path )
274
- rescue Errno::ENOENT
275
- end
276
- else
277
- data, from = info[ :wbuff ], :wbuff
278
- end
279
- end
280
-
281
- [ data, from ]
282
- end
283
-
284
- def add_closing( sock, need_renew = false )
285
- unless @closings.include?( sock )
286
- @closings[ sock ] = need_renew
287
- end
288
-
289
- add_write( sock )
290
- end
291
-
292
- def add_write( sock, data = nil, need_chunk = false )
293
- if data
294
- info = @infos[ sock ]
295
- info[ :wbuff ] << data
296
-
297
- if need_chunk && info[ :wbuff ].size >= CHUNK_SIZE
298
- filename = [ info[ :filename ], info[ :chunk_seed ] ].join( '.' )
299
- chunk_path = File.join( info[ :chunk_dir ], filename )
300
- IO.binwrite( chunk_path, info[ :wbuff ] )
301
- info[ :chunks ] << filename
302
- info[ :chunk_seed ] += 1
303
- info[ :wbuff ].clear
304
- end
305
- end
306
-
307
- unless @writes.include?( sock )
308
- @writes << sock
309
- end
310
- end
311
-
312
- def close_sock( sock )
313
- sock.close
314
- @roles.delete( sock )
315
- @reads.delete( sock )
316
- @writes.delete( sock )
317
- info = @infos.delete( sock )
318
-
319
- if info && info[ :chunks ]
320
- info[ :chunks ].each do | filename |
321
- begin
322
- File.delete( File.join( info[ :chunk_dir ], filename ) )
323
- rescue Errno::ENOENT
324
- end
325
- end
326
- end
327
-
328
- info
329
- end
330
-
331
- def new_room
332
- room = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
333
- room.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
334
- room.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 )
335
-
336
- begin
337
- room.connect_nonblock( @roomd_sockaddr )
338
- rescue IO::WaitWritable, Errno::EINTR
339
- end
340
-
341
- bytes = @title.unpack( "C*" ).map{ | c | c.chr }.join
342
- room_info = {
343
- wbuff: [ [ SET_TITLE, bytes.size ].pack( 'Cn' ), bytes ].join,
344
- p2_sockaddr: nil,
345
- rep2p: 0
346
- }
347
- @room = room
348
- @room_info = room_info
349
- @roles[ room ] = :room
350
- @infos[ room ] = room_info
351
- @reads << room
352
- @writes << room
353
- end
354
-
355
- def new_p1
356
- p1 = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
357
- p1.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
358
- p1.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 )
359
- p1.bind( @room.local_address ) # use the hole
360
-
361
- begin
362
- p1.connect_nonblock( @room_info[ :p2_sockaddr ] )
363
- rescue IO::WaitWritable, Errno::EINTR
364
- rescue Exception => e
365
- puts "connect p2 #{ e.class } #{ Time.new }"
366
- p1.close
367
- return
368
- end
369
-
370
- p1_info = {
371
- wbuff: '',
372
- cache: '',
373
- filename: [ Process.pid, p1.object_id ].join( '-' ),
374
- chunk_dir: @p1_chunk_dir,
375
- chunks: [],
376
- chunk_seed: 0,
377
- need_decode: true
378
- }
379
- @p1 = p1
380
- @p1_info = p1_info
381
- @roles[ p1 ] = :p1
382
- @infos[ p1 ] = p1_info
383
- @reads << p1
384
-
385
- app = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
386
- app.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 )
387
-
388
- begin
389
- app.connect_nonblock( @appd_sockaddr )
390
- rescue IO::WaitWritable, Errno::EINTR
391
- end
392
-
393
- app_info = {
394
- wbuff: '',
395
- cache: '',
396
- filename: [ Process.pid, app.object_id ].join( '-' ),
397
- chunk_dir: @app_chunk_dir,
398
- chunks: [],
399
- chunk_seed: 0,
400
- need_encode: true
401
- }
402
-
403
- @app = app
404
- @app_info = app_info
405
- @roles[ app ] = :app
406
- @infos[ app ] = app_info
407
- @reads << app
408
- end
409
- end
410
- end
1
+ require 'p2p2/head'
2
+ require 'p2p2/hex'
3
+ require 'p2p2/version'
4
+ require 'socket'
5
+
6
+ ##
7
+ # P2p2::P1 - 处于nat里的任意应用,访问处于另一个nat里的应用服务端,借助一根p2p管道。p1端。
8
+ #
9
+ module P2p2
10
+ class P1
11
+
12
+ ##
13
+ # roomd_host 匹配服务器ip
14
+ # roomd_port 匹配服务器端口
15
+ # appd_host 任意的一个应用的ip
16
+ # appd_port 应用端口
17
+ # title 约定的房间名
18
+ # app_chunk_dir 文件缓存目录,缓存app来不及写的流量
19
+ # p1_chunk_dir 文件缓存目录,缓存p1来不及写的流量
20
+ def initialize( roomd_host, roomd_port, appd_host, appd_port, title, app_chunk_dir = '/tmp', p1_chunk_dir = '/tmp' )
21
+ @roomd_sockaddr = Socket.sockaddr_in( roomd_port, roomd_host )
22
+ @appd_sockaddr = Socket.sockaddr_in( appd_port, appd_host )
23
+ @title = title
24
+ @app_chunk_dir = app_chunk_dir
25
+ @p1_chunk_dir = p1_chunk_dir
26
+ @hex = P2p2::Hex.new
27
+ @mutex = Mutex.new
28
+ @reads = []
29
+ @writes = []
30
+ @closings = []
31
+ @renewings = []
32
+ @roles = {} # sock => :ctlr / :room / :p1 / :app
33
+ @infos = {}
34
+ @retries = 0
35
+
36
+ ctlr, ctlw = IO.pipe
37
+ @ctlw = ctlw
38
+ @reads << ctlr
39
+ @roles[ ctlr ] = :ctlr
40
+
41
+ new_room
42
+ end
43
+
44
+ def looping
45
+ puts 'looping'
46
+
47
+ loop_renew_room
48
+
49
+ loop do
50
+ rs, ws = IO.select( @reads, @writes )
51
+
52
+ @mutex.synchronize do
53
+ rs.each do | sock |
54
+ case @roles[ sock ]
55
+ when :ctlr
56
+ read_ctlr( sock )
57
+ when :room
58
+ read_room( sock )
59
+ when :p1
60
+ read_p1( sock )
61
+ when :app
62
+ read_app( sock )
63
+ end
64
+ end
65
+
66
+ ws.each do | sock |
67
+ case @roles[ sock ]
68
+ when :room
69
+ write_room( sock )
70
+ when :p1
71
+ write_p1( sock )
72
+ when :app
73
+ write_app( sock )
74
+ end
75
+ end
76
+ end
77
+ end
78
+ rescue Interrupt => e
79
+ puts e.class
80
+ quit!
81
+ end
82
+
83
+ def quit!
84
+ exit
85
+ end
86
+
87
+ private
88
+
89
+ def loop_renew_room
90
+ Thread.new do
91
+ loop do
92
+ sleep 60
93
+
94
+ if Time.new - @room_info[ :updated_at ] > 600
95
+ @mutex.synchronize do
96
+ @ctlw.write( CTL_RENEW_ROOM )
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ def read_ctlr( sock )
104
+ case sock.read( 1 )
105
+ when CTL_RENEW_ROOM
106
+ add_renewing( @room )
107
+ end
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 Errno::ECONNREFUSED, EOFError, Errno::ECONNRESET => e
116
+ puts "read room #{ e.class } #{ Time.new }"
117
+
118
+ if @retries >= 2
119
+ raise e
120
+ end
121
+
122
+ sleep 5
123
+ add_renewing( sock )
124
+ @retries += 1
125
+ return
126
+ end
127
+
128
+ @retries = 0
129
+ info = @infos[ sock ]
130
+ info[ :p2_sockaddr ] = data
131
+ info[ :updated_at ] = Time.new
132
+ new_p1
133
+ end
134
+
135
+ def read_p1( sock )
136
+ begin
137
+ data = sock.read_nonblock( PACK_SIZE )
138
+ rescue IO::WaitReadable, Errno::EINTR, IO::WaitWritable
139
+ return
140
+ rescue Errno::ECONNREFUSED => e
141
+ if @room_info[ :rep2p ] >= REP2P_LIMIT
142
+ raise e
143
+ end
144
+
145
+ sleep 1
146
+ add_renewing( sock )
147
+ @room_info[ :rep2p ] += 1
148
+ return
149
+ rescue Exception => e
150
+ add_closing( sock )
151
+ return
152
+ end
153
+
154
+ @room_info[ :rep2p ] = 0
155
+ info = @infos[ sock ]
156
+
157
+ if info[ :need_decode ]
158
+ len = data[ 0, 2 ].unpack( 'n' ).first
159
+ head = @hex.decode( data[ 2, len ] )
160
+ data = head + data[ ( 2 + len )..-1 ]
161
+ info[ :need_decode ] = false
162
+ end
163
+
164
+ add_write( @app, data, NEED_CHUNK )
165
+ end
166
+
167
+ def read_app( sock )
168
+ begin
169
+ data = sock.read_nonblock( PACK_SIZE )
170
+ rescue IO::WaitReadable, Errno::EINTR, IO::WaitWritable
171
+ return
172
+ rescue Exception => e
173
+ add_closing( sock )
174
+ return
175
+ end
176
+
177
+ info = @infos[ sock ]
178
+
179
+ if info[ :need_encode ]
180
+ data = @hex.encode( data )
181
+ data = [ [ data.size ].pack( 'n' ), data ].join
182
+ info[ :need_encode ] = false
183
+ end
184
+
185
+ add_write( @p1, data, NEED_CHUNK )
186
+ end
187
+
188
+ def write_room( sock )
189
+ if @renewings.include?( sock )
190
+ close_sock( sock )
191
+ new_room
192
+ return
193
+ end
194
+
195
+ info = @infos[ sock ]
196
+ data = info[ :wbuff ]
197
+
198
+ if data.empty?
199
+ @writes.delete( sock )
200
+ return
201
+ end
202
+
203
+ sock.write( data )
204
+ info[ :wbuff ].clear
205
+ end
206
+
207
+ def write_p1( sock )
208
+ if @closings.include?( sock )
209
+ close_p1
210
+ return
211
+ end
212
+
213
+ if @renewings.include?( sock )
214
+ close_p1
215
+ new_p1
216
+ return
217
+ end
218
+
219
+ info = @infos[ sock ]
220
+ data, from = get_buff( info )
221
+
222
+ if data.empty?
223
+ @writes.delete( sock )
224
+ return
225
+ end
226
+
227
+ begin
228
+ written = sock.write_nonblock( data )
229
+ rescue IO::WaitWritable, Errno::EINTR, IO::WaitReadable
230
+ return
231
+ rescue Exception => e
232
+ add_closing( sock )
233
+ return
234
+ end
235
+
236
+ data = data[ written..-1 ]
237
+ info[ from ] = data
238
+ end
239
+
240
+ def write_app( sock )
241
+ if @closings.include?( sock )
242
+ close_sock( sock )
243
+
244
+ unless @p1.closed?
245
+ add_closing( @p1 )
246
+ end
247
+
248
+ return
249
+ end
250
+
251
+ info = @infos[ sock ]
252
+ data, from = get_buff( info )
253
+
254
+ if data.empty?
255
+ @writes.delete( sock )
256
+ return
257
+ end
258
+
259
+ begin
260
+ written = sock.write_nonblock( data )
261
+ rescue IO::WaitWritable, Errno::EINTR, IO::WaitReadable
262
+ return
263
+ rescue Exception => e
264
+ add_closing( sock )
265
+ return
266
+ end
267
+
268
+ data = data[ written..-1 ]
269
+ info[ from ] = data
270
+ end
271
+
272
+ def get_buff( info )
273
+ data, from = info[ :cache ], :cache
274
+
275
+ if data.empty?
276
+ if info[ :chunks ].any?
277
+ path = File.join( info[ :chunk_dir ], info[ :chunks ].shift )
278
+ data = info[ :cache ] = IO.binread( path )
279
+
280
+ begin
281
+ File.delete( path )
282
+ rescue Errno::ENOENT
283
+ end
284
+ else
285
+ data, from = info[ :wbuff ], :wbuff
286
+ end
287
+ end
288
+
289
+ [ data, from ]
290
+ end
291
+
292
+ def add_closing( sock )
293
+ unless @closings.include?( sock )
294
+ @reads.delete( sock )
295
+ @closings << sock
296
+ end
297
+
298
+ add_write( sock )
299
+ end
300
+
301
+ def add_renewing( sock )
302
+ unless @renewings.include?( sock )
303
+ @reads.delete( sock )
304
+ @renewings << sock
305
+ end
306
+
307
+ add_write( sock )
308
+ end
309
+
310
+ def add_write( sock, data = nil, need_chunk = false )
311
+ if data
312
+ info = @infos[ sock ]
313
+ info[ :wbuff ] << data
314
+
315
+ if need_chunk && info[ :wbuff ].size >= CHUNK_SIZE
316
+ filename = [ info[ :filename ], info[ :chunk_seed ] ].join( '.' )
317
+ chunk_path = File.join( info[ :chunk_dir ], filename )
318
+ IO.binwrite( chunk_path, info[ :wbuff ] )
319
+ info[ :chunks ] << filename
320
+ info[ :chunk_seed ] += 1
321
+ info[ :wbuff ].clear
322
+ end
323
+ end
324
+
325
+ unless @writes.include?( sock )
326
+ @writes << sock
327
+ end
328
+ end
329
+
330
+ def close_sock( sock )
331
+ sock.close
332
+ @closings.delete( sock )
333
+ @renewings.delete( sock )
334
+ @roles.delete( sock )
335
+ @reads.delete( sock )
336
+ @writes.delete( sock )
337
+ info = @infos.delete( sock )
338
+
339
+ if info && info[ :chunks ]
340
+ info[ :chunks ].each do | filename |
341
+ begin
342
+ File.delete( File.join( info[ :chunk_dir ], filename ) )
343
+ rescue Errno::ENOENT
344
+ end
345
+ end
346
+ end
347
+
348
+ info
349
+ end
350
+
351
+ def close_p1
352
+ close_sock( @p1 )
353
+
354
+ unless @app.closed?
355
+ add_closing( @app )
356
+ end
357
+ end
358
+
359
+ def new_room
360
+ room = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
361
+ room.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
362
+ room.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 )
363
+
364
+ begin
365
+ room.connect_nonblock( @roomd_sockaddr )
366
+ rescue IO::WaitWritable, Errno::EINTR
367
+ end
368
+
369
+ bytes = @title.unpack( "C*" ).map{ | c | c.chr }.join
370
+ room_info = {
371
+ wbuff: [ [ SET_TITLE, bytes.size ].pack( 'Cn' ), bytes ].join,
372
+ p2_sockaddr: nil,
373
+ rep2p: 0,
374
+ updated_at: Time.new
375
+ }
376
+ @room = room
377
+ @room_info = room_info
378
+ @roles[ room ] = :room
379
+ @infos[ room ] = room_info
380
+ @reads << room
381
+ @writes << room
382
+ end
383
+
384
+ def new_p1
385
+ p1 = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
386
+ p1.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
387
+ p1.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 )
388
+ p1.bind( @room.local_address ) # use the hole
389
+
390
+ begin
391
+ p1.connect_nonblock( @room_info[ :p2_sockaddr ] )
392
+ rescue IO::WaitWritable, Errno::EINTR
393
+ rescue Exception => e
394
+ puts "connect p2 #{ e.class } #{ Time.new }"
395
+ p1.close
396
+ return
397
+ end
398
+
399
+ p1_info = {
400
+ wbuff: '',
401
+ cache: '',
402
+ filename: [ Process.pid, p1.object_id ].join( '-' ),
403
+ chunk_dir: @p1_chunk_dir,
404
+ chunks: [],
405
+ chunk_seed: 0,
406
+ need_decode: true
407
+ }
408
+ @p1 = p1
409
+ @p1_info = p1_info
410
+ @roles[ p1 ] = :p1
411
+ @infos[ p1 ] = p1_info
412
+ @reads << p1
413
+
414
+ app = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
415
+ app.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 )
416
+
417
+ begin
418
+ app.connect_nonblock( @appd_sockaddr )
419
+ rescue IO::WaitWritable, Errno::EINTR
420
+ end
421
+
422
+ app_info = {
423
+ wbuff: '',
424
+ cache: '',
425
+ filename: [ Process.pid, app.object_id ].join( '-' ),
426
+ chunk_dir: @app_chunk_dir,
427
+ chunks: [],
428
+ chunk_seed: 0,
429
+ need_encode: true
430
+ }
431
+
432
+ @app = app
433
+ @app_info = app_info
434
+ @roles[ app ] = :app
435
+ @infos[ app ] = app_info
436
+ @reads << app
437
+ end
438
+ end
439
+ end