p2p2 0.6.5 → 0.6.6

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