p2p2 0.13.3 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,1000 +1,1013 @@
1
- require 'p2p2/head'
2
- require 'p2p2/hex'
3
- require 'p2p2/version'
4
- require 'socket'
5
-
6
- ##
7
- # P2p2::P2 - 内网里的任意应用,访问另一个内网里的应用服务端。p2端。
8
- #
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
- module P2p2
22
- class P2
23
-
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
524
- end
525
-
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
544
- end
545
-
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
552
-
553
- @writes.delete( p2 )
554
- return
555
- end
556
-
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
586
- end
587
-
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
604
- 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
-
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
681
- end
682
- end
683
-
684
- def loop_punch_peer( p2 )
685
- Thread.new do
686
- 20.times do
687
- break if p2.closed?
688
-
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
707
- 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
-
716
- @mutex.synchronize do
717
- p2_info = @infos[ p2 ]
718
- send_heartbeat( p2, p2_info[ :p1_addr ] )
719
- end
720
- end
721
- 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
-
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
755
- end
756
- end
757
-
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
767
-
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
798
- 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
-
806
- p2_info = @infos[ p2 ]
807
- break unless p2_info[ :p1_addr ]
808
-
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
827
- end
828
- end
829
-
830
- def loop_send_fin2( p2, app_id )
831
- Thread.new do
832
- 100.times do
833
- break if p2.closed?
834
-
835
- p2_info = @infos[ p2 ]
836
- break unless p2_info[ :p1_addr ]
837
-
838
- unless p2_info[ :fin2s ].include?( app_id )
839
- # puts "debug break send fin2 loop #{ Time.new }"
840
- break
841
- end
842
-
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
884
- end
885
-
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
931
- end
932
- end
933
-
934
- info[ :app_exts ].each{ | _, ext | add_closing( ext[ :app ] ) }
935
- end
936
-
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
- begin
986
- File.delete( File.join( @app_chunk_dir, filename ) )
987
- rescue Errno::ENOENT
988
- end
989
- end
990
- end
991
-
992
- shadow_id = p2_info[ :app_ids ].delete( app_id )
993
-
994
- if shadow_id
995
- p2_info[ :shadow_ids ].delete( shadow_id )
996
- end
997
- end
998
-
999
- end
1000
- end
1
+ require 'p2p2/head'
2
+ require 'p2p2/hex'
3
+ require 'p2p2/version'
4
+ require 'socket'
5
+
6
+ ##
7
+ # P2p2::P2 - 内网里的任意应用,访问另一个内网里的应用服务端。p2端。
8
+ #
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
+ module P2p2
22
+ class P2
23
+
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
+ # puts "debug #{ ext[ :continue_shadow_pack_id ] }/#{ ext[ :biggest_shadow_pack_id ] } send MISS #{ ranges.size }"
318
+ ranges.each do | pack_id_begin, pack_id_end |
319
+ ctlmsg = [
320
+ 0,
321
+ MISS,
322
+ shadow_id,
323
+ pack_id_begin,
324
+ pack_id_end
325
+ ].pack( 'Q>CQ>Q>Q>' )
326
+
327
+ send_pack( p2, ctlmsg, info[ :p1_addr ] )
328
+ end
329
+ end
330
+ when MISS
331
+ return if sockaddr != info[ :p1_addr ]
332
+
333
+ app_id, pack_id_begin, pack_id_end = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
334
+ ext = info[ :app_exts ][ app_id ]
335
+ return unless ext
336
+
337
+ ( pack_id_begin..pack_id_end ).each do | pack_id |
338
+ send_at = ext[ :send_ats ][ pack_id ]
339
+
340
+ if send_at
341
+ break if now - send_at < STATUS_INTERVAL
342
+
343
+ info[ :resendings ] << [ app_id, pack_id ]
344
+ end
345
+ end
346
+
347
+ add_write( p2 )
348
+ when FIN1
349
+ return if sockaddr != info[ :p1_addr ]
350
+
351
+ shadow_id = data[ 9, 8 ].unpack( 'Q>' ).first
352
+ ctlmsg = [
353
+ 0,
354
+ GOT_FIN1,
355
+ shadow_id
356
+ ].pack( 'Q>CQ>' )
357
+
358
+ # puts "debug 2-1. recv fin1 -> send got_fin1 -> ext.is_shadow_closed = true #{ shadow_id } #{ Time.new }"
359
+ send_pack( p2, ctlmsg, info[ :p1_addr ] )
360
+
361
+ app_id = info[ :shadow_ids ][ shadow_id ]
362
+ return unless app_id
363
+
364
+ ext = info[ :app_exts ][ app_id ]
365
+ return unless ext
366
+
367
+ ext[ :is_shadow_closed ] = true
368
+ when GOT_FIN1
369
+ return if sockaddr != info[ :p1_addr ]
370
+
371
+ # puts "debug 1-2. recv got_fin1 -> break loop #{ Time.new }"
372
+ app_id = data[ 9, 8 ].unpack( 'Q>' ).first
373
+ info[ :fin1s ].delete( app_id )
374
+ when FIN2
375
+ return if sockaddr != info[ :p1_addr ]
376
+
377
+ # puts "debug 1-3. recv fin2 -> send got_fin2 -> del ext #{ Time.new }"
378
+ shadow_id = data[ 9, 8 ].unpack( 'Q>' ).first
379
+ ctlmsg = [
380
+ 0,
381
+ GOT_FIN2,
382
+ shadow_id
383
+ ].pack( 'Q>CQ>' )
384
+
385
+ send_pack( p2, ctlmsg, info[ :p1_addr ] )
386
+
387
+ app_id = info[ :shadow_ids ][ shadow_id ]
388
+ return unless app_id
389
+
390
+ del_app_ext( info, app_id )
391
+ when GOT_FIN2
392
+ return if sockaddr != info[ :p1_addr ]
393
+
394
+ # puts "debug 2-4. recv got_fin2 -> break loop #{ Time.new }"
395
+ app_id = data[ 9, 8 ].unpack( 'Q>' ).first
396
+ info[ :fin2s ].delete( app_id )
397
+ when P1_FIN
398
+ return if sockaddr != info[ :p1_addr ]
399
+ puts "recv p1 fin #{ Time.new }"
400
+ add_closing( p2 )
401
+ end
402
+
403
+ return
404
+ end
405
+
406
+ return if sockaddr != info[ :p1_addr ]
407
+
408
+ app_id = info[ :shadow_ids ][ shadow_id ]
409
+ return unless app_id
410
+
411
+ ext = info[ :app_exts ][ app_id ]
412
+ return if ext.nil? || ext[ :app ].closed?
413
+
414
+ pack_id = data[ 8, 8 ].unpack( 'Q>' ).first
415
+ return if ( pack_id <= ext[ :continue_shadow_pack_id ] ) || ext[ :pieces ].include?( pack_id )
416
+
417
+ data = data[ 16..-1 ]
418
+
419
+ # 解混淆
420
+ if pack_id == 1
421
+ data = @hex.decode( data )
422
+ end
423
+
424
+ # 放进shadow的写前缓存,跳号放碎片缓存
425
+ if pack_id - ext[ :continue_shadow_pack_id ] == 1
426
+ while ext[ :pieces ].include?( pack_id + 1 )
427
+ data << ext[ :pieces ].delete( pack_id + 1 )
428
+ pack_id += 1
429
+ end
430
+
431
+ ext[ :continue_shadow_pack_id ] = pack_id
432
+ ext[ :wbuff ] << data
433
+
434
+ if ext[ :wbuff ].bytesize >= CHUNK_SIZE
435
+ spring = ext[ :chunks ].size > 0 ? ( ext[ :spring ] + 1 ) : 0
436
+ filename = "#{ app_id }.#{ spring }"
437
+ chunk_path = File.join( @app_chunk_dir, filename )
438
+ IO.binwrite( chunk_path, ext[ :wbuff ] )
439
+ ext[ :chunks ] << filename
440
+ ext[ :spring ] = spring
441
+ ext[ :wbuff ].clear
442
+ end
443
+
444
+ add_write( ext[ :app ] )
445
+ ext[ :last_traffic_at ] = now
446
+ info[ :last_traffic_at ] = now
447
+ else
448
+ ext[ :pieces ][ pack_id ] = data
449
+ end
450
+
451
+ ext[ :last_recv_at ] = now
452
+ end
453
+
454
+ ##
455
+ # write app
456
+ #
457
+ def write_app( app )
458
+ if @closings.include?( app )
459
+ close_app( app )
460
+ return
461
+ end
462
+
463
+ info = @infos[ app ]
464
+ p2 = info[ :p2 ]
465
+
466
+ if p2.closed?
467
+ add_closing( app )
468
+ return
469
+ end
470
+
471
+ p2_info = @infos[ p2 ]
472
+ app_id = @socks[ app ]
473
+ ext = p2_info[ :app_exts ][ app_id ]
474
+
475
+ # 取写前
476
+ data = ext[ :cache ]
477
+ from = :cache
478
+
479
+ if data.empty?
480
+ if ext[ :chunks ].any?
481
+ path = File.join( @app_chunk_dir, ext[ :chunks ].shift )
482
+
483
+ begin
484
+ data = IO.binread( path )
485
+ File.delete( path )
486
+ rescue Errno::ENOENT
487
+ add_closing( app )
488
+ return
489
+ end
490
+ else
491
+ data = ext[ :wbuff ]
492
+ from = :wbuff
493
+ end
494
+ end
495
+
496
+ if data.empty?
497
+ if ext[ :is_shadow_closed ] && ( ext[ :biggest_shadow_pack_id ] == ext[ :continue_shadow_pack_id ] )
498
+ # puts "debug 2-2. all sent && ext.biggest_shadow_pack_id == ext.continue_shadow_pack_id -> add closing app #{ Time.new }"
499
+ add_closing( app )
500
+ return
501
+ end
502
+
503
+ @writes.delete( app )
504
+ return
505
+ end
506
+
507
+ begin
508
+ written = app.write_nonblock( data )
509
+ rescue IO::WaitWritable, Errno::EINTR => e
510
+ ext[ from ] = data
511
+ return
512
+ rescue Exception => e
513
+ add_closing( app )
514
+ return
515
+ end
516
+
517
+ data = data[ written..-1 ]
518
+ ext[ from ] = data
519
+ end
520
+
521
+ ##
522
+ # write p2
523
+ #
524
+ def write_p2( p2 )
525
+ if @closings.include?( p2 )
526
+ close_p2( p2 )
527
+ return
528
+ end
529
+
530
+ now = Time.new
531
+ info = @infos[ p2 ]
532
+
533
+ # 重传
534
+ while info[ :resendings ].any?
535
+ app_id, pack_id = info[ :resendings ].shift
536
+ ext = info[ :app_exts ][ app_id ]
537
+
538
+ if ext
539
+ pack = ext[ :wmems ][ pack_id ]
540
+
541
+ if pack
542
+ send_pack( p2, pack, info[ :p1_addr ] )
543
+ ext[ :last_traffic_at ] = now
544
+ info[ :last_traffic_at ] = now
545
+ return
546
+ end
547
+ end
548
+ end
549
+
550
+ # 若写后到达上限,暂停取写前
551
+ if info[ :app_exts ].map{ | _, ext | ext[ :wmems ].size }.sum >= WMEMS_LIMIT
552
+ unless info[ :paused ]
553
+ puts "pause #{ Time.new }"
554
+ info[ :paused ] = true
555
+ end
556
+
557
+ @writes.delete( p2 )
558
+ return
559
+ end
560
+
561
+ # 取写前
562
+ if info[ :caches ].any?
563
+ app_id, data = info[ :caches ].shift
564
+ elsif info[ :chunks ].any?
565
+ path = File.join( @p2_chunk_dir, info[ :chunks ].shift )
566
+
567
+ begin
568
+ data = IO.binread( path )
569
+ File.delete( path )
570
+ rescue Errno::ENOENT
571
+ add_closing( p2 )
572
+ return
573
+ end
574
+
575
+ caches = []
576
+
577
+ until data.empty?
578
+ app_id, pack_size = data[ 0, 10 ].unpack( 'Q>n' )
579
+ caches << [ app_id, data[ 10, pack_size ] ]
580
+ data = data[ ( 10 + pack_size )..-1 ]
581
+ end
582
+
583
+ app_id, data = caches.shift
584
+ info[ :caches ] = caches
585
+ elsif info[ :wbuffs ].any?
586
+ app_id, data = info[ :wbuffs ].shift
587
+ else
588
+ @writes.delete( p2 )
589
+ return
590
+ end
591
+
592
+ ext = info[ :app_exts ][ app_id ]
593
+
594
+ if ext
595
+ pack_id = ext[ :biggest_pack_id ] + 1
596
+
597
+ if pack_id == 1
598
+ data = @hex.encode( data )
599
+ end
600
+
601
+ pack = "#{ [ app_id, pack_id ].pack( 'Q>Q>' ) }#{ data }"
602
+ send_pack( p2, pack, info[ :p1_addr ] )
603
+ ext[ :biggest_pack_id ] = pack_id
604
+ ext[ :wmems ][ pack_id ] = pack
605
+ ext[ :send_ats ][ pack_id ] = now
606
+ ext[ :last_traffic_at ] = now
607
+ info[ :last_traffic_at ] = now
608
+ end
609
+ end
610
+
611
+ def new_appd
612
+ appd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
613
+ appd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
614
+ appd.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 )
615
+ appd.bind( @appd_sockaddr )
616
+ appd.listen( 511 )
617
+
618
+ @roles[ appd ] = :appd
619
+ add_read( appd )
620
+ end
621
+
622
+ def new_p2
623
+ p2 = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
624
+ p2.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
625
+ p2.bind( Socket.sockaddr_in( 0, '0.0.0.0' ) )
626
+ p2_id = @hex.gen_random_num
627
+ p2_info = {
628
+ id: p2_id,
629
+ waitings: {}, # 还没连上p1,或者还没配上shadow,暂存流量 app_id => buffs[]
630
+ wbuffs: [], # 写前缓存 [ app_id, data ]
631
+ caches: [], # 块读出缓存 [ app_id, data ]
632
+ chunks: [], # 块队列 filename
633
+ spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
634
+ peer_addr: nil, # 对面地址,连发心跳包打洞,离p2pd近的一方通常会撞死几个直到对面出来
635
+ p1_addr: nil, # p1地址
636
+ app_exts: {}, # 传输相关 app_id => {}
637
+ app_ids: {}, # app_id => shadow_id
638
+ shadow_ids: {}, # shadow_id => app_id
639
+ fin1s: [], # fin1: app已关闭,等待对面收完流量 app_id
640
+ fin2s: [], # fin2: 流量已收完 app_id
641
+ paused: false, # 是否暂停写
642
+ resendings: [], # 重传队列 [ app_id, pack_id ]
643
+ last_traffic_at: nil # 收到有效流量,或者发出流量的时间戳
644
+ }
645
+
646
+ @p2 = p2
647
+ @p2_info = p2_info
648
+ @roles[ p2 ] = :p2
649
+ @infos[ p2 ] = p2_info
650
+ @socks[ p2 ] = p2_id
651
+ @sock_ids[ p2_id ] = p2
652
+
653
+ send_pack( p2, @title, @p2pd_sockaddr )
654
+ add_read( p2 )
655
+ loop_send_char( p2 )
656
+ end
657
+
658
+ def loop_send_char( p2 )
659
+ Thread.new do
660
+ is_timeout = true
661
+
662
+ 20.times do
663
+ sleep HEARTBEAT_INTERVAL
664
+
665
+ if p2.closed?
666
+ is_timeout = false
667
+ break
668
+ end
669
+
670
+ p2_info = @infos[ p2 ]
671
+
672
+ if p2_info[ :peer_addr ]
673
+ is_timeout = false
674
+ break
675
+ end
676
+
677
+ @mutex.synchronize do
678
+ send_pack( p2, [ rand( 128 ) ].pack( 'C' ), @p2pd_sockaddr )
679
+ end
680
+ end
681
+
682
+ if is_timeout
683
+ @mutex.synchronize do
684
+ p2_id = @socks[ p2 ]
685
+ @ctlw.write( [ CTL_CLOSE, p2_id ].pack( 'CQ>' ) )
686
+ end
687
+ end
688
+ end
689
+ end
690
+
691
+ def loop_punch_peer( p2 )
692
+ Thread.new do
693
+ 20.times do
694
+ break if p2.closed?
695
+
696
+ p2_info = @infos[ p2 ]
697
+
698
+ @mutex.synchronize do
699
+ send_heartbeat( p2, p2_info[ :peer_addr ] )
700
+ end
701
+
702
+ sleep STATUS_INTERVAL
703
+ end
704
+
705
+ if !p2.closed?
706
+ p2_info = @infos[ p2 ]
707
+
708
+ unless p2_info[ :p1_addr ]
709
+ @mutex.synchronize do
710
+ p2_id = @socks[ p2 ]
711
+ @ctlw.write( [ CTL_CLOSE, p2_id ].pack( 'CQ>' ) )
712
+ end
713
+ end
714
+ end
715
+ end
716
+ end
717
+
718
+ def loop_send_heartbeat( p2 )
719
+ Thread.new do
720
+ loop do
721
+ sleep HEARTBEAT_INTERVAL
722
+ break if p2.closed?
723
+
724
+ @mutex.synchronize do
725
+ p2_info = @infos[ p2 ]
726
+ send_heartbeat( p2, p2_info[ :p1_addr ] )
727
+ end
728
+ end
729
+ end
730
+ end
731
+
732
+ def loop_check_expire( p2 )
733
+ Thread.new do
734
+ loop do
735
+ sleep 60
736
+ break if p2.closed?
737
+
738
+ now = Time.new
739
+ p2_info = @infos[ p2 ]
740
+
741
+ if now - p2_info[ :last_traffic_at ] > EXPIRE_AFTER
742
+ @mutex.synchronize do
743
+ p2_id = @socks[ p2 ]
744
+ # puts "debug ctlw close p2 #{ p2_id } #{ Time.new } p#{ Process.pid }"
745
+ @ctlw.write( [ CTL_CLOSE, p2_id ].pack( 'CQ>' ) )
746
+ end
747
+
748
+ break
749
+ end
750
+
751
+ exts = p2_info[ :app_exts ].select{ | _, ext | now - ext[ :created_at ] > 5 }
752
+
753
+ if exts.any?
754
+ @mutex.synchronize do
755
+ exts.each do | app_id, ext |
756
+ if ext[ :last_recv_at ].nil? || ( now - ext[ :last_recv_at ] > EXPIRE_AFTER )
757
+ # puts "debug ctlw close app #{ app_id } #{ Time.new } p#{ Process.pid }"
758
+ @ctlw.write( [ CTL_CLOSE, app_id ].pack( 'CQ>' ) )
759
+ end
760
+ end
761
+ end
762
+ end
763
+ end
764
+ end
765
+ end
766
+
767
+ def loop_send_status( p2 )
768
+ Thread.new do
769
+ loop do
770
+ sleep STATUS_INTERVAL
771
+
772
+ if p2.closed?
773
+ # puts "debug p2 is closed, break send status loop #{ Time.new }"
774
+ break
775
+ end
776
+
777
+ p2_info = @infos[ p2 ]
778
+
779
+ if p2_info[ :app_exts ].any?
780
+ @mutex.synchronize do
781
+ now = Time.new
782
+
783
+ p2_info[ :app_exts ].each do | app_id, ext |
784
+ if ext[ :last_traffic_at ] && ( now - ext[ :last_traffic_at ] < SEND_STATUS_UNTIL )
785
+ ctlmsg = [
786
+ 0,
787
+ APP_STATUS,
788
+ app_id,
789
+ ext[ :biggest_pack_id ],
790
+ ext[ :continue_shadow_pack_id ]
791
+ ].pack( 'Q>CQ>Q>Q>' )
792
+
793
+ send_pack( p2, ctlmsg, p2_info[ :p1_addr ] )
794
+ end
795
+ end
796
+ end
797
+ end
798
+
799
+ if p2_info[ :paused ] && ( p2_info[ :app_exts ].map{ | _, ext | ext[ :wmems ].size }.sum < RESUME_BELOW )
800
+ @mutex.synchronize do
801
+ p2_id = @socks[ p2 ]
802
+ puts "ctlw resume #{ p2_id } #{ Time.new }"
803
+ @ctlw.write( [ CTL_RESUME, p2_id ].pack( 'CQ>' ) )
804
+ p2_info[ :paused ] = false
805
+ end
806
+ end
807
+ end
808
+ end
809
+ end
810
+
811
+ def loop_send_fin1( p2, app_id )
812
+ Thread.new do
813
+ 100.times do
814
+ break if p2.closed?
815
+
816
+ p2_info = @infos[ p2 ]
817
+ break unless p2_info[ :p1_addr ]
818
+
819
+ unless p2_info[ :fin1s ].include?( app_id )
820
+ # puts "debug break send fin1 loop #{ Time.new }"
821
+ break
822
+ end
823
+
824
+ @mutex.synchronize do
825
+ ctlmsg = [
826
+ 0,
827
+ FIN1,
828
+ app_id
829
+ ].pack( 'Q>CQ>' )
830
+
831
+ # puts "debug send FIN1 #{ app_id } #{ Time.new }"
832
+ send_pack( p2, ctlmsg, p2_info[ :p1_addr ] )
833
+ end
834
+
835
+ sleep 1
836
+ end
837
+ end
838
+ end
839
+
840
+ def loop_send_fin2( p2, app_id )
841
+ Thread.new do
842
+ 100.times do
843
+ break if p2.closed?
844
+
845
+ p2_info = @infos[ p2 ]
846
+ break unless p2_info[ :p1_addr ]
847
+
848
+ unless p2_info[ :fin2s ].include?( app_id )
849
+ # puts "debug break send fin2 loop #{ Time.new }"
850
+ break
851
+ end
852
+
853
+ @mutex.synchronize do
854
+ ctlmsg = [
855
+ 0,
856
+ FIN2,
857
+ app_id
858
+ ].pack( 'Q>CQ>' )
859
+
860
+ # puts "debug send FIN2 #{ app_id } #{ Time.new }"
861
+ send_pack( p2, ctlmsg, p2_info[ :p1_addr ] )
862
+ end
863
+
864
+ sleep 1
865
+ end
866
+ end
867
+ end
868
+
869
+ def loop_send_a_new_app( app )
870
+ Thread.new do
871
+ 100.times do
872
+ break if app.closed?
873
+
874
+ app_info = @infos[ app ]
875
+ p2 = app_info[ :p2 ]
876
+ break if p2.closed?
877
+
878
+ p2_info = @infos[ p2 ]
879
+
880
+ if p2_info[ :p1_addr ]
881
+ app_id = @socks[ app ]
882
+ shadow_id = p2_info[ :app_ids ][ app_id ]
883
+
884
+ if shadow_id
885
+ # puts "debug break a new app loop #{ Time.new }"
886
+ break
887
+ end
888
+
889
+ @mutex.synchronize do
890
+ ctlmsg = [ 0, A_NEW_APP, app_id ].pack( 'Q>CQ>' )
891
+ # puts "debug send a new app #{ Time.new }"
892
+ send_pack( p2, ctlmsg, p2_info[ :p1_addr ] )
893
+ end
894
+ end
895
+
896
+ sleep 1
897
+ end
898
+ end
899
+ end
900
+
901
+ def send_heartbeat( p2, target_addr )
902
+ ctlmsg = [ 0, HEARTBEAT, rand( 128 ) ].pack( 'Q>CC' )
903
+ send_pack( p2, ctlmsg, target_addr )
904
+ end
905
+
906
+ def send_pack( sock, data, target_sockaddr )
907
+ begin
908
+ sock.sendmsg( data, 0, target_sockaddr )
909
+ rescue IO::WaitWritable, Errno::EINTR => e
910
+ puts "sendmsg #{ e.class } #{ Time.new }"
911
+ end
912
+ end
913
+
914
+ def add_read( sock )
915
+ return if sock.closed? || @reads.include?( sock )
916
+
917
+ @reads << sock
918
+ end
919
+
920
+ def add_write( sock, data = nil )
921
+ return if sock.closed? || @writes.include?( sock )
922
+
923
+ @writes << sock
924
+ end
925
+
926
+ def add_closing( sock )
927
+ return if sock.closed? || @closings.include?( sock )
928
+
929
+ @reads.delete( sock )
930
+ @closings << sock
931
+ add_write( sock )
932
+ end
933
+
934
+ def close_p2( p2 )
935
+ info = close_sock( p2 )
936
+
937
+ info[ :chunks ].each do | filename |
938
+ begin
939
+ File.delete( File.join( @p2_chunk_dir, filename ) )
940
+ rescue Errno::ENOENT
941
+ end
942
+ end
943
+
944
+ info[ :app_exts ].each{ | _, ext | add_closing( ext[ :app ] ) }
945
+ end
946
+
947
+ def close_app( app )
948
+ info = close_sock( app )
949
+ p2 = info[ :p2 ]
950
+ return if p2.closed?
951
+
952
+ app_id = info[ :id ]
953
+ p2_info = @infos[ p2 ]
954
+ ext = p2_info[ :app_exts ][ app_id ]
955
+ return unless ext
956
+
957
+ ext[ :chunks ].each do | filename |
958
+ begin
959
+ File.delete( File.join( @app_chunk_dir, filename ) )
960
+ rescue Errno::ENOENT
961
+ end
962
+ end
963
+
964
+ if ext[ :is_shadow_closed ]
965
+ del_app_ext( p2_info, app_id )
966
+
967
+ unless p2_info[ :fin2s ].include?( app_id )
968
+ # puts "debug 2-3. app.close -> ext.is_shadow_closed ? yes -> del ext -> loop send fin2 #{ Time.new }"
969
+ p2_info[ :fin2s ] << app_id
970
+ loop_send_fin2( p2, app_id )
971
+ end
972
+ elsif !p2_info[ :fin1s ].include?( app_id )
973
+ # puts "debug 1-1. app.close -> ext.is_shadow_closed ? no -> send fin1 loop #{ Time.new }"
974
+ p2_info[ :fin1s ] << app_id
975
+ loop_send_fin1( p2, app_id )
976
+ end
977
+ end
978
+
979
+ def close_sock( sock )
980
+ sock.close
981
+ @reads.delete( sock )
982
+ @writes.delete( sock )
983
+ @closings.delete( sock )
984
+ @roles.delete( sock )
985
+ info = @infos.delete( sock )
986
+ sock_id = @socks.delete( sock )
987
+ @sock_ids.delete( sock_id )
988
+
989
+ info
990
+ end
991
+
992
+ def del_app_ext( p2_info, app_id )
993
+ p2_info[ :waitings ].delete( app_id )
994
+ ext = p2_info[ :app_exts ].delete( app_id )
995
+
996
+ if ext
997
+ ext[ :chunks ].each do | filename |
998
+ begin
999
+ File.delete( File.join( @app_chunk_dir, filename ) )
1000
+ rescue Errno::ENOENT
1001
+ end
1002
+ end
1003
+ end
1004
+
1005
+ shadow_id = p2_info[ :app_ids ].delete( app_id )
1006
+
1007
+ if shadow_id
1008
+ p2_info[ :shadow_ids ].delete( shadow_id )
1009
+ end
1010
+ end
1011
+
1012
+ end
1013
+ end