p2p2 0.6.8 → 0.6.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,495 +1,494 @@
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: false,
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 ]
198
- raise e
199
- end
200
-
201
- sleep 5
202
- add_closing( room )
203
- @app_info[ :reconn_room ] = true
204
- return
205
- end
206
-
207
- @app_info[ :reconn_room ] = false
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
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