p2p2 0.13.2 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,969 +1,112 @@
1
+ require 'json'
1
2
  require 'p2p2/head'
2
- require 'p2p2/hex'
3
+ require 'p2p2/p2_custom'
4
+ require 'p2p2/p2_worker'
3
5
  require 'p2p2/version'
4
6
  require 'socket'
5
7
 
6
8
  ##
7
9
  # P2p2::P2 - 内网里的任意应用,访问另一个内网里的应用服务端。p2端。
8
10
  #
9
- # 两套关闭
10
- # ========
11
- #
12
- # 1-1. app.close -> ext.is_shadow_closed ? no -> send fin1 loop
13
- # 1-2. recv got_fin1 -> break loop
14
- # 1-3. recv fin2 -> send got_fin2 -> del ext
15
- #
16
- # 2-1. recv fin1 -> send got_fin1 -> ext.is_shadow_closed = true
17
- # 2-2. all sent && ext.biggest_shadow_pack_id == ext.continue_shadow_pack_id -> add closing app
18
- # 2-3. app.close -> ext.is_shadow_closed ? yes -> del ext -> loop send fin2
19
- # 2-4. recv got_fin2 -> break loop
20
- #
21
11
  module P2p2
22
12
  class P2
23
13
 
24
- ##
25
- # p2pd_host 配对服务器ip
26
- # p2pd_port 配对服务器端口
27
- # appd_host 代理地址 不限制访问:'0.0.0.0',或者只允许本地访问:'127.0.0.1'
28
- # appd_port 代理端口
29
- # title 约定的房间名
30
- # app_chunk_dir 文件缓存目录,缓存app来不及写的流量
31
- # p2_chunk_dir 文件缓存目录,缓存p2来不及写的流量
32
- #
33
- def initialize( p2pd_host, p2pd_port, appd_host, appd_port, title, app_chunk_dir = '/tmp', p2_chunk_dir = '/tmp' )
34
- @p2pd_sockaddr = Socket.sockaddr_in( p2pd_port, p2pd_host )
35
- @appd_sockaddr = Socket.sockaddr_in( appd_port, appd_host )
36
- @title = title
37
- @app_chunk_dir = app_chunk_dir
38
- @p2_chunk_dir = p2_chunk_dir
39
- @hex = P2p2::Hex.new
40
- @mutex = Mutex.new
41
- @reads = []
42
- @writes = []
43
- @closings = []
44
- @socks = {} # object_id => sock
45
- @roles = {} # sock => :ctlr / :appd / :app / :p2
46
- @infos = {} # sock => {}
47
-
48
- ctlr, ctlw = IO.pipe
49
- @ctlw = ctlw
50
- @roles[ ctlr ] = :ctlr
51
- @reads << ctlr
52
- end
53
-
54
- def looping
55
- puts 'looping'
56
-
57
- new_appd
58
-
59
- loop do
60
- rs, ws = IO.select( @reads, @writes )
61
-
62
- @mutex.synchronize do
63
- rs.each do | sock |
64
- case @roles[ sock ]
65
- when :ctlr
66
- read_ctlr( sock )
67
- when :appd
68
- read_appd( sock )
69
- when :app
70
- read_app( sock )
71
- when :p2
72
- read_p2( sock )
73
- end
74
- end
75
-
76
- ws.each do | sock |
77
- case @roles[ sock ]
78
- when :app
79
- write_app( sock )
80
- when :p2
81
- write_p2( sock )
82
- end
83
- end
84
- end
85
- end
86
- rescue Interrupt => e
87
- puts e.class
88
- quit!
89
- end
90
-
91
- def quit!
92
- if @p2 && !@p2.closed? && @p2_info[ :p1_addr ]
93
- ctlmsg = [ 0, P2_FIN ].pack( 'Q>C' )
94
- send_pack( @p2, ctlmsg, @p2_info[ :p1_addr ] )
95
- end
96
-
97
- exit
98
- end
99
-
100
- private
101
-
102
- ##
103
- # read ctlr
104
- #
105
- def read_ctlr( ctlr )
106
- case ctlr.read( 1 ).unpack( 'C' ).first
107
- when CTL_CLOSE
108
- sock_id = ctlr.read( 8 ).unpack( 'Q>' ).first
109
- sock = @socks[ sock_id ]
110
-
111
- if sock
112
- # puts "debug ctlr close #{ sock_id } #{ Time.new }"
113
- add_closing( sock )
114
- end
115
- when CTL_RESUME
116
- sock_id = ctlr.read( 8 ).unpack( 'Q>' ).first
117
- sock = @socks[ sock_id ]
118
-
119
- if sock
120
- puts "ctlr resume #{ sock_id } #{ Time.new }"
121
- add_write( sock )
122
- end
123
- end
124
- end
125
-
126
- ##
127
- # read appd
128
- #
129
- def read_appd( appd )
130
- begin
131
- app, _ = appd.accept_nonblock
132
- rescue IO::WaitReadable, Errno::EINTR
133
- return
134
- end
135
-
136
- if @p2.nil? || @p2.closed?
137
- new_p2
138
- end
139
-
140
- app_id = app.object_id
141
-
142
- @socks[ app_id ] = app
143
- @roles[ app ] = :app
144
- @infos[ app ] = {
145
- p2: @p2
146
- }
147
-
148
- @p2_info[ :waitings ][ app_id ] = []
149
- @p2_info[ :app_exts ][ app_id ] = {
150
- app: app,
151
- wbuff: '', # 写前缓存
152
- cache: '', # 块读出缓存
153
- chunks: [], # 块队列,写前达到块大小时结一个块 filename
154
- spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
155
- wmems: {}, # 写后缓存 pack_id => data
156
- send_ats: {}, # 上一次发出时间 pack_id => send_at
157
- biggest_pack_id: 0, # 发到几
158
- continue_shadow_pack_id: 0, # 收到几
159
- pieces: {}, # 跳号包 shadow_pack_id => data
160
- is_shadow_closed: false, # 对面是否已关闭
161
- biggest_shadow_pack_id: 0, # 对面发到几
162
- completed_pack_id: 0, # 完成到几(对面收到几)
163
- last_traffic_at: nil # 收到有效流量,或者发出流量的时间戳
164
- }
165
-
166
- add_read( app )
167
- loop_send_a_new_app( app )
168
- end
169
-
170
- ##
171
- # read app
172
- #
173
- def read_app( app )
174
- begin
175
- data = app.read_nonblock( PACK_SIZE )
176
- rescue IO::WaitReadable, Errno::EINTR
177
- return
178
- rescue Exception => e
179
- add_closing( app )
180
- return
181
- end
182
-
183
- info = @infos[ app ]
184
- p2 = info[ :p2 ]
185
-
186
- if p2.closed?
187
- add_closing( app )
188
- return
189
- end
190
-
191
- app_id = app.object_id
192
- p2_info = @infos[ p2 ]
193
- shadow_id = p2_info[ :app_ids ][ app_id ]
194
-
195
- if p2_info[ :p1_addr ].nil? || shadow_id.nil?
196
- p2_info[ :waitings ][ app_id ] << data
197
- return
198
- end
199
-
200
- p2_info[ :wbuffs ] << [ app_id, data ]
201
-
202
- if p2_info[ :wbuffs ].size >= WBUFFS_LIMIT
203
- spring = p2_info[ :chunks ].size > 0 ? ( p2_info[ :spring ] + 1 ) : 0
204
- filename = "#{ p2.object_id }.#{ spring }"
205
- chunk_path = File.join( @p2_chunk_dir, filename )
206
- IO.binwrite( chunk_path, p2_info[ :wbuffs ].map{ | app_id, data | "#{ [ app_id, data.bytesize ].pack( 'Q>n' ) }#{ data }" }.join )
207
- p2_info[ :chunks ] << filename
208
- p2_info[ :spring ] = spring
209
- p2_info[ :wbuffs ].clear
210
- end
211
-
212
- unless p2_info[ :paused ]
213
- add_write( p2 )
214
- end
215
- end
216
-
217
- ##
218
- # read p2
219
- #
220
- def read_p2( p2 )
221
- data, addrinfo, rflags, *controls = p2.recvmsg
222
- sockaddr = addrinfo.to_sockaddr
223
- now = Time.new
224
- info = @infos[ p2 ]
225
- shadow_id = data[ 0, 8 ].unpack( 'Q>' ).first
226
-
227
- if shadow_id == 0
228
- case data[ 8 ].unpack( 'C' ).first
229
- when PEER_ADDR
230
- return if info[ :peer_addr ] || ( sockaddr != @p2pd_sockaddr )
231
-
232
- info[ :peer_addr ] = data[ 9..-1 ]
233
- # puts "debug peer addr #{ Addrinfo.new( info[ :peer_addr ] ).ip_unpack.inspect } #{ Time.new }"
234
- loop_punch_peer( p2 )
235
- when HEARTBEAT
236
- return if info[ :p1_addr ] || ( sockaddr != info[ :peer_addr ] )
237
-
238
- info[ :p1_addr ] = sockaddr
239
- # puts "debug p1 addr #{ Addrinfo.new( info[ :p1_addr ] ).ip_unpack.inspect } #{ Time.new }"
240
- info[ :last_traffic_at ] = now
241
- loop_send_heartbeat( p2 )
242
- loop_send_status( p2 )
243
- when PAIRED
244
- return if sockaddr != info[ :p1_addr ]
245
-
246
- app_id, shadow_id = data[ 9, 16 ].unpack( 'Q>Q>' )
247
- return if info[ :app_ids ].include?( app_id )
248
-
249
- # puts "debug got PAIRED #{ app_id } #{ shadow_id } #{ Time.new }"
250
- info[ :app_ids ][ app_id ] = shadow_id
251
- info[ :shadow_ids ][ shadow_id ] = app_id
252
- buffs = info[ :waitings ][ app_id ]
253
-
254
- if buffs.any?
255
- # puts "debug move #{ buffs.size } waiting buffs to wbuffs #{ Time.new } p#{ Process.pid }"
256
-
257
- buffs.each do | buff |
258
- info[ :wbuffs ] << [ app_id, buff ]
259
- end
260
-
261
- buffs.clear
262
- add_write( p2 )
263
- end
264
- when SHADOW_STATUS
265
- return if sockaddr != info[ :p1_addr ]
266
-
267
- shadow_id, biggest_shadow_pack_id, continue_app_pack_id = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
268
- app_id = info[ :shadow_ids ][ shadow_id ]
269
- return unless app_id
270
-
271
- ext = info[ :app_exts ][ app_id ]
272
- return unless ext
273
-
274
- # 更新对面发到几
275
- if biggest_shadow_pack_id > ext[ :biggest_shadow_pack_id ]
276
- ext[ :biggest_shadow_pack_id ] = biggest_shadow_pack_id
277
- end
278
-
279
- # 更新对面收到几,释放写后
280
- if continue_app_pack_id > ext[ :completed_pack_id ]
281
- pack_ids = ext[ :wmems ].keys.select { | pack_id | pack_id <= continue_app_pack_id }
282
-
283
- pack_ids.each do | pack_id |
284
- ext[ :wmems ].delete( pack_id )
285
- ext[ :send_ats ].delete( pack_id )
286
- end
287
-
288
- ext[ :completed_pack_id ] = continue_app_pack_id
289
- end
290
-
291
- if ext[ :is_shadow_closed ] && ( ext[ :biggest_shadow_pack_id ] == ext[ :continue_shadow_pack_id ] )
292
- add_write( ext[ :app ] )
293
- return
294
- end
295
-
296
- # 发miss
297
- if !ext[ :app ].closed? && ( ext[ :continue_shadow_pack_id ] < ext[ :biggest_shadow_pack_id ] )
298
- ranges = []
299
- curr_pack_id = ext[ :continue_shadow_pack_id ] + 1
300
-
301
- ext[ :pieces ].keys.sort.each do | pack_id |
302
- if pack_id > curr_pack_id
303
- ranges << [ curr_pack_id, pack_id - 1 ]
304
- end
305
-
306
- curr_pack_id = pack_id + 1
307
- end
308
-
309
- if curr_pack_id <= ext[ :biggest_shadow_pack_id ]
310
- ranges << [ curr_pack_id, ext[ :biggest_shadow_pack_id ] ]
311
- end
312
-
313
- # puts "debug #{ ext[ :continue_shadow_pack_id ] }/#{ ext[ :biggest_shadow_pack_id ] } send MISS #{ ranges.size }"
314
- ranges.each do | pack_id_begin, pack_id_end |
315
- ctlmsg = [
316
- 0,
317
- MISS,
318
- shadow_id,
319
- pack_id_begin,
320
- pack_id_end
321
- ].pack( 'Q>CQ>Q>Q>' )
322
-
323
- send_pack( p2, ctlmsg, info[ :p1_addr ] )
324
- end
325
- end
326
- when MISS
327
- return if sockaddr != info[ :p1_addr ]
328
-
329
- app_id, pack_id_begin, pack_id_end = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
330
- ext = info[ :app_exts ][ app_id ]
331
- return unless ext
332
-
333
- ( pack_id_begin..pack_id_end ).each do | pack_id |
334
- send_at = ext[ :send_ats ][ pack_id ]
335
-
336
- if send_at
337
- break if now - send_at < STATUS_INTERVAL
338
-
339
- info[ :resendings ] << [ app_id, pack_id ]
340
- end
341
- end
342
-
343
- add_write( p2 )
344
- when FIN1
345
- return if sockaddr != info[ :p1_addr ]
346
-
347
- shadow_id = data[ 9, 8 ].unpack( 'Q>' ).first
348
- ctlmsg = [
349
- 0,
350
- GOT_FIN1,
351
- shadow_id
352
- ].pack( 'Q>CQ>' )
353
-
354
- # puts "debug 2-1. recv fin1 -> send got_fin1 -> ext.is_shadow_closed = true #{ shadow_id } #{ Time.new }"
355
- send_pack( p2, ctlmsg, info[ :p1_addr ] )
356
-
357
- app_id = info[ :shadow_ids ][ shadow_id ]
358
- return unless app_id
359
-
360
- ext = info[ :app_exts ][ app_id ]
361
- return unless ext
362
-
363
- ext[ :is_shadow_closed ] = true
364
- when GOT_FIN1
365
- return if sockaddr != info[ :p1_addr ]
366
-
367
- # puts "debug 1-2. recv got_fin1 -> break loop #{ Time.new }"
368
- app_id = data[ 9, 8 ].unpack( 'Q>' ).first
369
- info[ :fin1s ].delete( app_id )
370
- when FIN2
371
- return if sockaddr != info[ :p1_addr ]
372
-
373
- # puts "debug 1-3. recv fin2 -> send got_fin2 -> del ext #{ Time.new }"
374
- shadow_id = data[ 9, 8 ].unpack( 'Q>' ).first
375
- ctlmsg = [
376
- 0,
377
- GOT_FIN2,
378
- shadow_id
379
- ].pack( 'Q>CQ>' )
380
-
381
- send_pack( p2, ctlmsg, info[ :p1_addr ] )
382
-
383
- app_id = info[ :shadow_ids ][ shadow_id ]
384
- return unless app_id
385
-
386
- del_app_ext( info, app_id )
387
- when GOT_FIN2
388
- return if sockaddr != info[ :p1_addr ]
389
-
390
- # puts "debug 2-4. recv got_fin2 -> break loop #{ Time.new }"
391
- app_id = data[ 9, 8 ].unpack( 'Q>' ).first
392
- info[ :fin2s ].delete( app_id )
393
- when P1_FIN
394
- return if sockaddr != info[ :p1_addr ]
395
- puts "recv p1 fin #{ Time.new }"
396
- add_closing( p2 )
397
- end
398
-
399
- return
400
- end
401
-
402
- return if sockaddr != info[ :p1_addr ]
403
-
404
- app_id = info[ :shadow_ids ][ shadow_id ]
405
- return unless app_id
406
-
407
- ext = info[ :app_exts ][ app_id ]
408
- return if ext.nil? || ext[ :app ].closed?
409
-
410
- pack_id = data[ 8, 8 ].unpack( 'Q>' ).first
411
- return if ( pack_id <= ext[ :continue_shadow_pack_id ] ) || ext[ :pieces ].include?( pack_id )
412
-
413
- data = data[ 16..-1 ]
414
-
415
- # 解混淆
416
- if pack_id == 1
417
- data = @hex.decode( data )
418
- end
419
-
420
- # 放进shadow的写前缓存,跳号放碎片缓存
421
- if pack_id - ext[ :continue_shadow_pack_id ] == 1
422
- while ext[ :pieces ].include?( pack_id + 1 )
423
- data << ext[ :pieces ].delete( pack_id + 1 )
424
- pack_id += 1
425
- end
426
-
427
- ext[ :continue_shadow_pack_id ] = pack_id
428
- ext[ :wbuff ] << data
429
-
430
- if ext[ :wbuff ].bytesize >= CHUNK_SIZE
431
- spring = ext[ :chunks ].size > 0 ? ( ext[ :spring ] + 1 ) : 0
432
- filename = "#{ app_id }.#{ spring }"
433
- chunk_path = File.join( @app_chunk_dir, filename )
434
- IO.binwrite( chunk_path, ext[ :wbuff ] )
435
- ext[ :chunks ] << filename
436
- ext[ :spring ] = spring
437
- ext[ :wbuff ].clear
438
- end
439
-
440
- add_write( ext[ :app ] )
441
- ext[ :last_traffic_at ] = now
442
- info[ :last_traffic_at ] = now
443
- else
444
- ext[ :pieces ][ pack_id ] = data
445
- end
446
- end
447
-
448
- ##
449
- # write app
450
- #
451
- def write_app( app )
452
- if @closings.include?( app )
453
- close_app( app )
454
- return
455
- end
456
-
457
- info = @infos[ app ]
458
- p2 = info[ :p2 ]
459
-
460
- if p2.closed?
461
- add_closing( app )
462
- return
463
- end
464
-
465
- p2_info = @infos[ p2 ]
466
- ext = p2_info[ :app_exts ][ app.object_id ]
467
-
468
- # 取写前
469
- data = ext[ :cache ]
470
- from = :cache
471
-
472
- if data.empty?
473
- if ext[ :chunks ].any?
474
- path = File.join( @app_chunk_dir, ext[ :chunks ].shift )
475
-
476
- begin
477
- data = IO.binread( path )
478
- File.delete( path )
479
- rescue Errno::ENOENT
480
- add_closing( app )
481
- return
482
- end
483
- else
484
- data = ext[ :wbuff ]
485
- from = :wbuff
486
- end
487
- end
488
-
489
- if data.empty?
490
- if ext[ :is_shadow_closed ] && ( ext[ :biggest_shadow_pack_id ] == ext[ :continue_shadow_pack_id ] )
491
- # puts "debug 2-2. all sent && ext.biggest_shadow_pack_id == ext.continue_shadow_pack_id -> add closing app #{ Time.new }"
492
- add_closing( app )
493
- return
494
- end
495
-
496
- @writes.delete( app )
497
- return
14
+ def initialize( config_path = nil )
15
+ unless config_path
16
+ config_path = File.expand_path( '../p2p2.conf.json', __FILE__ )
498
17
  end
499
18
 
500
- begin
501
- written = app.write_nonblock( data )
502
- rescue IO::WaitWritable, Errno::EINTR => e
503
- ext[ from ] = data
504
- return
505
- rescue Exception => e
506
- add_closing( app )
507
- return
19
+ unless File.exist?( config_path )
20
+ raise "missing config file #{ config_path }"
508
21
  end
509
22
 
510
- data = data[ written..-1 ]
511
- ext[ from ] = data
512
- end
23
+ conf = JSON.parse( IO.binread( config_path ), symbolize_names: true )
24
+ p2pd_host = conf[ :p2pd_host ]
25
+ p2pd_port = conf[ :p2pd_port ]
26
+ room = conf[ :room ]
27
+ sdwd_host = conf[ :sdwd_host ]
28
+ sdwd_port = conf[ :sdwd_port ]
29
+ p2_tmp_dir = conf[ :p2_tmp_dir ]
513
30
 
514
- ##
515
- # write p2
516
- #
517
- def write_p2( p2 )
518
- if @closings.include?( p2 )
519
- close_p2( p2 )
520
- return
31
+ unless p2pd_host
32
+ raise "missing p2pd host"
521
33
  end
522
34
 
523
- now = Time.new
524
- info = @infos[ p2 ]
525
-
526
- # 重传
527
- while info[ :resendings ].any?
528
- app_id, pack_id = info[ :resendings ].shift
529
- ext = info[ :app_exts ][ app_id ]
530
-
531
- if ext
532
- pack = ext[ :wmems ][ pack_id ]
533
-
534
- if pack
535
- send_pack( p2, pack, info[ :p1_addr ] )
536
- ext[ :last_traffic_at ] = now
537
- info[ :last_traffic_at ] = now
538
- return
539
- end
540
- end
35
+ unless room
36
+ raise "missing room"
541
37
  end
542
38
 
543
- # 若写后到达上限,暂停取写前
544
- if info[ :app_exts ].map{ | _, ext | ext[ :wmems ].size }.sum >= WMEMS_LIMIT
545
- unless info[ :paused ]
546
- puts "pause #{ Time.new }"
547
- info[ :paused ] = true
548
- end
549
-
550
- @writes.delete( p2 )
551
- return
39
+ unless p2pd_port
40
+ p2pd_port = 2020
552
41
  end
553
42
 
554
- # 取写前
555
- if info[ :caches ].any?
556
- app_id, data = info[ :caches ].shift
557
- elsif info[ :chunks ].any?
558
- path = File.join( @p2_chunk_dir, info[ :chunks ].shift )
559
-
560
- begin
561
- data = IO.binread( path )
562
- File.delete( path )
563
- rescue Errno::ENOENT
564
- add_closing( p2 )
565
- return
566
- end
567
-
568
- caches = []
569
-
570
- until data.empty?
571
- app_id, pack_size = data[ 0, 10 ].unpack( 'Q>n' )
572
- caches << [ app_id, data[ 10, pack_size ] ]
573
- data = data[ ( 10 + pack_size )..-1 ]
574
- end
575
-
576
- app_id, data = caches.shift
577
- info[ :caches ] = caches
578
- elsif info[ :wbuffs ].any?
579
- app_id, data = info[ :wbuffs ].shift
580
- else
581
- @writes.delete( p2 )
582
- return
43
+ unless sdwd_host
44
+ sdwd_host = '0.0.0.0'
583
45
  end
584
46
 
585
- ext = info[ :app_exts ][ app_id ]
586
-
587
- if ext
588
- pack_id = ext[ :biggest_pack_id ] + 1
589
-
590
- if pack_id == 1
591
- data = @hex.encode( data )
592
- end
593
-
594
- pack = "#{ [ app_id, pack_id ].pack( 'Q>Q>' ) }#{ data }"
595
- send_pack( p2, pack, info[ :p1_addr ] )
596
- ext[ :biggest_pack_id ] = pack_id
597
- ext[ :wmems ][ pack_id ] = pack
598
- ext[ :send_ats ][ pack_id ] = now
599
- ext[ :last_traffic_at ] = now
600
- info[ :last_traffic_at ] = now
47
+ unless sdwd_port
48
+ sdwd_port = 2222
601
49
  end
602
- end
603
-
604
- def new_appd
605
- appd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
606
- appd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
607
- appd.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 )
608
- appd.bind( @appd_sockaddr )
609
- appd.listen( 511 )
610
-
611
- @roles[ appd ] = :appd
612
- add_read( appd )
613
- end
614
-
615
- def new_p2
616
- p2 = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
617
- p2.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
618
- p2.bind( Socket.sockaddr_in( 0, '0.0.0.0' ) )
619
-
620
- p2_info = {
621
- waitings: {}, # 还没连上p1,或者还没配上shadow,暂存流量 app_id => buffs[]
622
- wbuffs: [], # 写前缓存 [ app_id, data ]
623
- caches: [], # 块读出缓存 [ app_id, data ]
624
- chunks: [], # 块队列 filename
625
- spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
626
- peer_addr: nil, # 对面地址,连发心跳包打洞,离p2pd近的一方通常会撞死几个直到对面出来
627
- p1_addr: nil, # p1地址
628
- app_exts: {}, # 传输相关 app_id => {}
629
- app_ids: {}, # app_id => shadow_id
630
- shadow_ids: {}, # shadow_id => app_id
631
- fin1s: [], # fin1: app已关闭,等待对面收完流量 app_id
632
- fin2s: [], # fin2: 流量已收完 app_id
633
- paused: false, # 是否暂停写
634
- resendings: [], # 重传队列 [ app_id, pack_id ]
635
- last_traffic_at: nil # 收到有效流量,或者发出流量的时间戳
636
- }
637
-
638
- @p2 = p2
639
- @p2_info = p2_info
640
- @socks[ p2.object_id ] = p2
641
- @roles[ p2 ] = :p2
642
- @infos[ p2 ] = p2_info
643
-
644
- send_pack( p2, @title, @p2pd_sockaddr )
645
- add_read( p2 )
646
- loop_send_char( p2 )
647
- end
648
-
649
- def loop_send_char( p2 )
650
- Thread.new do
651
- is_timeout = true
652
-
653
- 20.times do
654
- sleep HEARTBEAT_INTERVAL
655
-
656
- if p2.closed?
657
- is_timeout = false
658
- break
659
- end
660
-
661
- p2_info = @infos[ p2 ]
662
50
 
663
- if p2_info[ :peer_addr ]
664
- is_timeout = false
665
- break
666
- end
667
-
668
- @mutex.synchronize do
669
- send_pack( p2, [ rand( 128 ) ].pack( 'C' ), @p2pd_sockaddr )
670
- end
671
- end
672
-
673
- if is_timeout
674
- @mutex.synchronize do
675
- @ctlw.write( [ CTL_CLOSE, p1.object_id ].pack( 'CQ>' ) )
676
- end
677
- end
51
+ unless p2_tmp_dir
52
+ p2_tmp_dir = '/tmp/p2p2.p2'
678
53
  end
679
- end
680
54
 
681
- def loop_punch_peer( p2 )
682
- Thread.new do
683
- 20.times do
684
- break if p2.closed?
685
-
686
- p2_info = @infos[ p2 ]
687
-
688
- @mutex.synchronize do
689
- send_heartbeat( p2, p2_info[ :peer_addr ] )
690
- end
691
-
692
- sleep STATUS_INTERVAL
693
- end
694
-
695
- if !p2.closed?
696
- p2_info = @infos[ p2 ]
697
-
698
- unless p2_info[ :p1_addr ]
699
- @mutex.synchronize do
700
- @ctlw.write( [ CTL_CLOSE, p2.object_id ].pack( 'CQ>' ) )
701
- end
702
- end
703
- end
55
+ unless File.exist?( p2_tmp_dir )
56
+ Dir.mkdir( p2_tmp_dir )
704
57
  end
705
- end
706
-
707
- def loop_send_heartbeat( p2 )
708
- Thread.new do
709
- loop do
710
- sleep HEARTBEAT_INTERVAL
711
- break if p2.closed?
712
-
713
- p2_info = @infos[ p2 ]
714
58
 
715
- if Time.new - p2_info[ :last_traffic_at ] > EXPIRE_AFTER
716
- @mutex.synchronize do
717
- @ctlw.write( [ CTL_CLOSE, p2.object_id ].pack( 'CQ>' ) )
718
- end
59
+ src_chunk_dir = File.join( p2_tmp_dir, 'src.chunk' )
719
60
 
720
- break
721
- end
722
-
723
- @mutex.synchronize do
724
- send_heartbeat( p2, p2_info[ :p1_addr ] )
725
- end
726
- end
61
+ unless Dir.exist?( src_chunk_dir )
62
+ Dir.mkdir( src_chunk_dir )
727
63
  end
728
- end
729
-
730
- def loop_send_status( p2 )
731
- Thread.new do
732
- loop do
733
- sleep STATUS_INTERVAL
734
-
735
- if p2.closed?
736
- # puts "debug p2 is closed, break send status loop #{ Time.new }"
737
- break
738
- end
739
64
 
740
- p2_info = @infos[ p2 ]
741
-
742
- if p2_info[ :app_exts ].any?
743
- @mutex.synchronize do
744
- now = Time.new
745
-
746
- p2_info[ :app_exts ].each do | app_id, ext |
747
- if ext[ :last_traffic_at ] && ( now - ext[ :last_traffic_at ] < SEND_STATUS_UNTIL )
748
- ctlmsg = [
749
- 0,
750
- APP_STATUS,
751
- app_id,
752
- ext[ :biggest_pack_id ],
753
- ext[ :continue_shadow_pack_id ]
754
- ].pack( 'Q>CQ>Q>Q>' )
755
-
756
- send_pack( p2, ctlmsg, p2_info[ :p1_addr ] )
757
- end
758
- end
759
- end
760
- end
65
+ tun_chunk_dir = File.join( p2_tmp_dir, 'tun.chunk' )
761
66
 
762
- if p2_info[ :paused ] && ( p2_info[ :app_exts ].map{ | _, ext | ext[ :wmems ].size }.sum < RESUME_BELOW )
763
- @mutex.synchronize do
764
- @ctlw.write( [ CTL_RESUME, p2.object_id ].pack( 'CQ>' ) )
765
- p2_info[ :paused ] = false
766
- end
767
- end
768
- end
769
- end
770
- end
771
-
772
- def loop_send_fin1( p2, app_id )
773
- Thread.new do
774
- 100.times do
775
- break if p2.closed?
776
-
777
- p2_info = @infos[ p2 ]
778
- break unless p2_info[ :p1_addr ]
779
-
780
- unless p2_info[ :fin1s ].include?( app_id )
781
- # puts "debug break send fin1 loop #{ Time.new }"
782
- break
783
- end
784
-
785
- @mutex.synchronize do
786
- ctlmsg = [
787
- 0,
788
- FIN1,
789
- app_id
790
- ].pack( 'Q>CQ>' )
791
-
792
- # puts "debug send FIN1 #{ app_id } #{ Time.new }"
793
- send_pack( p2, ctlmsg, p2_info[ :p1_addr ] )
794
- end
795
-
796
- sleep 1
797
- end
798
- end
799
- end
800
-
801
- def loop_send_fin2( p2, app_id )
802
- Thread.new do
803
- 100.times do
804
- break if p2.closed?
805
-
806
- p2_info = @infos[ p2 ]
807
- break unless p2_info[ :p1_addr ]
808
-
809
- unless p2_info[ :fin2s ].include?( app_id )
810
- # puts "debug break send fin2 loop #{ Time.new }"
811
- break
812
- end
813
-
814
- @mutex.synchronize do
815
- ctlmsg = [
816
- 0,
817
- FIN2,
818
- app_id
819
- ].pack( 'Q>CQ>' )
820
-
821
- # puts "debug send FIN2 #{ app_id } #{ Time.new }"
822
- send_pack( p2, ctlmsg, p2_info[ :p1_addr ] )
823
- end
824
-
825
- sleep 1
826
- end
67
+ unless Dir.exist?( tun_chunk_dir )
68
+ Dir.mkdir( tun_chunk_dir )
827
69
  end
828
- end
829
-
830
- def loop_send_a_new_app( app )
831
- Thread.new do
832
- 100.times do
833
- break if app.closed?
834
70
 
835
- app_info = @infos[ app ]
836
- p2 = app_info[ :p2 ]
837
- break if p2.closed?
71
+ title = "p2p2 p2 #{ P2p2::VERSION }"
72
+ puts title
73
+ puts "p2pd host #{ p2pd_host }"
74
+ puts "p2pd port #{ p2pd_port }"
75
+ puts "room #{ room }"
76
+ puts "sdwd host #{ sdwd_host }"
77
+ puts "sdwd port #{ sdwd_port }"
78
+ puts "p2 tmp dir #{ p2_tmp_dir }"
79
+ puts "src chunk dir #{ src_chunk_dir }"
80
+ puts "tun chunk dir #{ tun_chunk_dir }"
838
81
 
839
- p2_info = @infos[ p2 ]
82
+ if RUBY_PLATFORM.include?( 'linux' )
83
+ $0 = title
840
84
 
841
- if p2_info[ :p1_addr ]
842
- app_id = app.object_id
843
- shadow_id = p2_info[ :app_ids ][ app_id ]
85
+ pid = fork do
86
+ $0 = 'p2p2 p2 worker'
87
+ worker = P2p2::P2Worker.new( p2pd_host, p2pd_port, room, sdwd_host, sdwd_port, src_chunk_dir, tun_chunk_dir )
844
88
 
845
- if shadow_id
846
- # puts "debug break a new app loop #{ Time.new }"
847
- break
848
- end
849
-
850
- @mutex.synchronize do
851
- ctlmsg = [ 0, A_NEW_APP, app_id ].pack( 'Q>CQ>' )
852
- # puts "debug send a new app #{ Time.new }"
853
- send_pack( p2, ctlmsg, p2_info[ :p1_addr ] )
854
- end
89
+ Signal.trap( :TERM ) do
90
+ puts 'exit'
91
+ worker.quit!
855
92
  end
856
93
 
857
- sleep 1
858
- end
859
- end
860
- end
861
-
862
- def send_heartbeat( p2, target_addr )
863
- ctlmsg = [ 0, HEARTBEAT, rand( 128 ) ].pack( 'Q>CC' )
864
- send_pack( p2, ctlmsg, target_addr )
865
- end
866
-
867
- def send_pack( sock, data, target_sockaddr )
868
- begin
869
- sock.sendmsg( data, 0, target_sockaddr )
870
- rescue IO::WaitWritable, Errno::EINTR => e
871
- puts "sendmsg #{ e.class } #{ Time.new }"
872
- end
873
- end
874
-
875
- def add_read( sock )
876
- return if sock.closed? || @reads.include?( sock )
877
-
878
- @reads << sock
879
- end
880
-
881
- def add_write( sock, data = nil )
882
- return if sock.closed? || @writes.include?( sock )
883
-
884
- @writes << sock
885
- end
886
-
887
- def add_closing( sock )
888
- return if sock.closed? || @closings.include?( sock )
889
-
890
- @reads.delete( sock )
891
- @closings << sock
892
- add_write( sock )
893
- end
894
-
895
- def close_p2( p2 )
896
- info = close_sock( p2 )
897
-
898
- info[ :chunks ].each do | filename |
899
- begin
900
- File.delete( File.join( @p2_chunk_dir, filename ) )
901
- rescue Errno::ENOENT
902
- end
903
- end
904
-
905
- info[ :app_exts ].each{ | _, ext | add_closing( ext[ :app ] ) }
906
- end
907
-
908
- def close_app( app )
909
- info = close_sock( app )
910
- p2 = info[ :p2 ]
911
- return if p2.closed?
912
-
913
- app_id = app.object_id
914
- p2_info = @infos[ p2 ]
915
- ext = p2_info[ :app_exts ][ app_id ]
916
- return unless ext
917
-
918
- ext[ :chunks ].each do | filename |
919
- begin
920
- File.delete( File.join( @app_chunk_dir, filename ) )
921
- rescue Errno::ENOENT
922
- end
923
- end
924
-
925
- if ext[ :is_shadow_closed ]
926
- del_app_ext( p2_info, app_id )
927
-
928
- unless p2_info[ :fin2s ].include?( app_id )
929
- # puts "debug 2-3. app.close -> ext.is_shadow_closed ? yes -> del ext -> loop send fin2 #{ Time.new }"
930
- p2_info[ :fin2s ] << app_id
931
- loop_send_fin2( p2, app_id )
94
+ worker.looping
932
95
  end
933
- elsif !p2_info[ :fin1s ].include?( app_id )
934
- # puts "debug 1-1. app.close -> ext.is_shadow_closed ? no -> send fin1 loop #{ Time.new }"
935
- p2_info[ :fin1s ] << app_id
936
- loop_send_fin1( p2, app_id )
937
- end
938
- end
939
-
940
- def close_sock( sock )
941
- sock.close
942
- @reads.delete( sock )
943
- @writes.delete( sock )
944
- @closings.delete( sock )
945
- @socks.delete( sock.object_id )
946
- @roles.delete( sock )
947
- @infos.delete( sock )
948
- end
949
96
 
950
- def del_app_ext( p2_info, app_id )
951
- p2_info[ :waitings ].delete( app_id )
952
- ext = p2_info[ :app_exts ].delete( app_id )
97
+ Signal.trap( :TERM ) do
98
+ puts 'trap TERM'
953
99
 
954
- if ext
955
- ext[ :chunks ].each do | filename |
956
100
  begin
957
- File.delete( File.join( @app_chunk_dir, filename ) )
958
- rescue Errno::ENOENT
101
+ Process.kill( :TERM, pid )
102
+ rescue Errno::ESRCH => e
103
+ puts e.class
959
104
  end
960
105
  end
961
- end
962
106
 
963
- shadow_id = p2_info[ :app_ids ].delete( app_id )
964
-
965
- if shadow_id
966
- p2_info[ :shadow_ids ].delete( shadow_id )
107
+ Process.waitall
108
+ else
109
+ P2p2::P2Worker.new( p2pd_host, p2pd_port, room, sdwd_host, sdwd_port, src_chunk_dir, tun_chunk_dir ).looping
967
110
  end
968
111
  end
969
112