p2p2 0.6.9 → 0.7.0

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