p2p2 0.6.5 → 0.6.6

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,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