p2p2 0.6.3 → 0.6.4

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