p2p2 0.15.1 → 0.20.0

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