p2p2 0.13.3 → 0.17.0

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