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.
@@ -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