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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 304436e9d7374bc6e93585c3a5eb19e9609de9781847893b86d6c3d4743de621
4
- data.tar.gz: 5fe0577da9088b012a45e48637b867bb0e5a9e008bc7e16d4365dc324a3a42e1
3
+ metadata.gz: ca1bca606c23b34a5ee3a3f73b8e0764f8f965be5724a7e8fafd478c449c5d37
4
+ data.tar.gz: 2afdaf91bc5df9b534d322c1b1e3d46588aeff0369a87badf44e575f60d39c7b
5
5
  SHA512:
6
- metadata.gz: 40543a3591a792096d3b663deb762132fbf15f09c7cc7df2c342e97d1a2aab566a5744bf616005e0a3e3eae15c6479adbfd270ed628145373c6b4354e7790506
7
- data.tar.gz: 730b27755bdd1033e2310ae86f3dab1f6b8e25c2bc42c4ceaa109e2c03cdd2728e64aab553e49abc63f58dfee3befd55c29df4b52f07c6e9ed25b0790790b26a
6
+ metadata.gz: 57e9f9faebd08006a37d7a71529bc2db8b6f445011717652f23a66b5fbe984bdb36e857cc8c379d1dbbba58dda5f20031f9f59083bca11d357c3a471ce7a2af0
7
+ data.tar.gz: b2610f153384a3b6eb4bcfd474072cabb7a95e08bbc1f1340a54c45ad1cab5406cdf533ce0034a244e7085b4542890dba7bcacd4988897f17b835b62978d2630
@@ -1,6 +1,6 @@
1
- require "p2p2/version"
2
-
3
- module P2p2
4
- class Error < StandardError; end
5
- # Your code goes here...
6
- end
1
+ require "p2p2/version"
2
+
3
+ module P2p2
4
+ class Error < StandardError; end
5
+ # Your code goes here...
6
+ end
@@ -1,10 +1,10 @@
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
+ NEED_RENEW = true
10
+ end
@@ -1,413 +1,410 @@
1
- require 'p2p2/head'
2
- require 'p2p2/hex'
3
- require 'p2p2/version'
4
- require 'socket'
5
-
6
- ##
7
- # P2p2::P1 - 处于各自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
- @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
- unless @app
133
- @room_info[ :rep2p ] = 0
134
- app = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
135
- app.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 )
136
-
137
- begin
138
- app.connect_nonblock( @appd_sockaddr )
139
- rescue IO::WaitWritable, Errno::EINTR
140
- end
141
-
142
- app_info = {
143
- wbuff: '',
144
- cache: '',
145
- filename: [ Process.pid, app.object_id ].join( '-' ),
146
- chunk_dir: @app_chunk_dir,
147
- chunks: [],
148
- chunk_seed: 0,
149
- p1: sock,
150
- need_encode: true
151
- }
152
-
153
- @app = app
154
- @app_info = app_info
155
- @roles[ app ] = :app
156
- @infos[ app ] = app_info
157
- @reads << app
158
- end
159
-
160
- info = @infos[ sock ]
161
-
162
- if info[ :need_decode ]
163
- len = data[ 0, 2 ].unpack( 'n' ).first
164
- head = @hex.decode( data[ 2, len ] )
165
- data = head + data[ ( 2 + len )..-1 ]
166
- info[ :need_decode ] = false
167
- end
168
-
169
- add_write( @app, data, NEED_CHUNK )
170
- end
171
-
172
- def read_app( sock )
173
- begin
174
- data = sock.read_nonblock( PACK_SIZE )
175
- rescue IO::WaitReadable, Errno::EINTR, IO::WaitWritable => e
176
- return
177
- rescue Exception => e
178
- add_closing( sock )
179
- return
180
- end
181
-
182
- info = @infos[ sock ]
183
-
184
- if info[ :need_encode ]
185
- data = @hex.encode( data )
186
- data = [ [ data.size ].pack( 'n' ), data ].join
187
- info[ :need_encode ] = false
188
- end
189
-
190
- add_write( @p1, data, NEED_CHUNK )
191
- end
192
-
193
- def write_room( sock )
194
- if @closings.include?( sock )
195
- close_sock( sock )
196
- sleep 5
197
- new_room
198
- @is_renew = true
199
- @closings.delete( sock )
200
-
201
- return
202
- end
203
-
204
- info = @infos[ sock ]
205
- data = info[ :wbuff ]
206
-
207
- if data.empty?
208
- @writes.delete( sock )
209
- return
210
- end
211
-
212
- sock.write( data )
213
- info[ :wbuff ].clear
214
- end
215
-
216
- def write_p1( sock )
217
- if @closings.include?( sock )
218
- close_sock( sock )
219
- @p1 = nil
220
-
221
- if @app && !@app.closed?
222
- add_closing( @app )
223
- end
224
-
225
- need_renew = @closings.delete( sock )
226
-
227
- if need_renew
228
- sleep 1
229
- new_p1
230
- @room_info[ :rep2p ] += 1
231
- end
232
-
233
- return
234
- end
235
-
236
- info = @infos[ sock ]
237
- data, from = get_buff( info )
238
-
239
- if data.empty?
240
- @writes.delete( sock )
241
- return
242
- end
243
-
244
- begin
245
- written = sock.write_nonblock( data )
246
- rescue IO::WaitWritable, Errno::EINTR, IO::WaitReadable
247
- return
248
- rescue Exception => e
249
- add_closing( sock )
250
- return
251
- end
252
-
253
- data = data[ written..-1 ]
254
- info[ from ] = data
255
- end
256
-
257
- def write_app( sock )
258
- if @closings.include?( sock )
259
- close_sock( sock )
260
- @app = nil
261
-
262
- if @p1 && !@p1.closed?
263
- add_closing( @p1 )
264
- end
265
-
266
- @closings.delete( sock )
267
- return
268
- end
269
-
270
- info = @infos[ sock ]
271
- data, from = get_buff( info )
272
-
273
- if data.empty?
274
- @writes.delete( sock )
275
- return
276
- end
277
-
278
- begin
279
- written = sock.write_nonblock( data )
280
- rescue IO::WaitWritable, Errno::EINTR, IO::WaitReadable
281
- return
282
- rescue Exception => e
283
- add_closing( sock )
284
- return
285
- end
286
-
287
- data = data[ written..-1 ]
288
- info[ from ] = data
289
- end
290
-
291
- def get_buff( info )
292
- data, from = info[ :cache ], :cache
293
-
294
- if data.empty?
295
- if info[ :chunks ].any?
296
- path = File.join( info[ :chunk_dir ], info[ :chunks ].shift )
297
- data = info[ :cache ] = IO.binread( path )
298
-
299
- begin
300
- File.delete( path )
301
- rescue Errno::ENOENT
302
- end
303
- else
304
- data, from = info[ :wbuff ], :wbuff
305
- end
306
- end
307
-
308
- [ data, from ]
309
- end
310
-
311
- def add_closing( sock, need_renew = false )
312
- unless @closings.include?( sock )
313
- @closings[ sock ] = need_renew
314
- end
315
-
316
- add_write( sock )
317
- end
318
-
319
- def add_write( sock, data = nil, need_chunk = false )
320
- if data
321
- info = @infos[ sock ]
322
- info[ :wbuff ] << data
323
-
324
- if need_chunk && info[ :wbuff ].size >= CHUNK_SIZE
325
- filename = [ info[ :filename ], info[ :chunk_seed ] ].join( '.' )
326
- chunk_path = File.join( info[ :chunk_dir ], filename )
327
- IO.binwrite( chunk_path, info[ :wbuff ] )
328
- info[ :chunks ] << filename
329
- info[ :chunk_seed ] += 1
330
- info[ :wbuff ].clear
331
- end
332
- end
333
-
334
- unless @writes.include?( sock )
335
- @writes << sock
336
- end
337
- end
338
-
339
- def close_sock( sock )
340
- sock.close
341
- @roles.delete( sock )
342
- @reads.delete( sock )
343
- @writes.delete( sock )
344
- info = @infos.delete( sock )
345
-
346
- if info && info[ :chunks ]
347
- info[ :chunks ].each do | filename |
348
- begin
349
- File.delete( File.join( info[ :chunk_dir ], filename ) )
350
- rescue Errno::ENOENT
351
- end
352
- end
353
- end
354
-
355
- info
356
- end
357
-
358
- def new_room
359
- room = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
360
- room.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
361
- room.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 )
362
-
363
- begin
364
- room.connect_nonblock( @roomd_sockaddr )
365
- rescue IO::WaitWritable, Errno::EINTR
366
- end
367
-
368
- bytes = @title.unpack( "C*" ).map{ | c | c.chr }.join
369
- room_info = {
370
- wbuff: [ [ SET_TITLE, bytes.size ].pack( 'Cn' ), bytes ].join,
371
- p2_sockaddr: nil,
372
- rep2p: 0
373
- }
374
- @room = room
375
- @room_info = room_info
376
- @roles[ room ] = :room
377
- @infos[ room ] = room_info
378
- @reads << room
379
- @writes << room
380
- end
381
-
382
- def new_p1
383
- p1 = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
384
- p1.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
385
- p1.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 )
386
- p1.bind( @room.local_address ) # use the hole
387
-
388
- begin
389
- p1.connect_nonblock( @room_info[ :p2_sockaddr ] )
390
- rescue IO::WaitWritable, Errno::EINTR
391
- rescue Exception => e
392
- puts "connect p2 #{ e.class } #{ Time.new }"
393
- p1.close
394
- return
395
- end
396
-
397
- p1_info = {
398
- wbuff: '',
399
- cache: '',
400
- filename: [ Process.pid, p1.object_id ].join( '-' ),
401
- chunk_dir: @p1_chunk_dir,
402
- chunks: [],
403
- chunk_seed: 0,
404
- need_decode: true
405
- }
406
- @p1 = p1
407
- @p1_info = p1_info
408
- @roles[ p1 ] = :p1
409
- @infos[ p1 ] = p1_info
410
- @reads << p1
411
- end
412
- end
413
- end
1
+ require 'p2p2/head'
2
+ require 'p2p2/hex'
3
+ require 'p2p2/version'
4
+ require 'socket'
5
+
6
+ ##
7
+ # P2p2::P1 - 处于各自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
+ @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