p2p2 0.15.0 → 0.19.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ require 'p2p2/custom'
2
+
3
+ module P2p2
4
+ class P2Custom
5
+ include Custom
6
+ end
7
+ end
@@ -0,0 +1,966 @@
1
+ module P2p2
2
+ class P2Worker
3
+
4
+ ##
5
+ # initialize
6
+ #
7
+ def initialize( p2pd_host, p2pd_port, room, sdwd_host, sdwd_port, src_chunk_dir, tun_chunk_dir )
8
+ @p2pd_addr = Socket.sockaddr_in( p2pd_port, p2pd_host )
9
+ @room = room
10
+ @sdwd_addr = Socket.sockaddr_in( sdwd_port, sdwd_host )
11
+ @src_chunk_dir = src_chunk_dir
12
+ @tun_chunk_dir = tun_chunk_dir
13
+ @custom = P2p2::P2Custom.new
14
+ @mutex = Mutex.new
15
+ @reads = []
16
+ @writes = []
17
+ @roles = {} # sock => :dotr / :sdwd / :src / :tun
18
+ @src_infos = {} # src => {}
19
+
20
+ dotr, dotw = IO.pipe
21
+ @dotw = dotw
22
+ add_read( dotr, :dotr )
23
+ new_a_sdwd
24
+ end
25
+
26
+ ##
27
+ # looping
28
+ #
29
+ def looping
30
+ puts "#{ Time.new } looping"
31
+ loop_check_expire
32
+ loop_check_status
33
+
34
+ loop do
35
+ rs, ws = IO.select( @reads, @writes )
36
+
37
+ @mutex.synchronize do
38
+ # 先写,再读
39
+ ws.each do | sock |
40
+ case @roles[ sock ]
41
+ when :src
42
+ write_src( sock )
43
+ when :tun
44
+ write_tun( sock )
45
+ end
46
+ end
47
+
48
+ rs.each do | sock |
49
+ case @roles[ sock ]
50
+ when :dotr
51
+ read_dotr( sock )
52
+ when :sdwd
53
+ read_sdwd( sock )
54
+ when :src
55
+ read_src( sock )
56
+ when :tun
57
+ read_tun( sock )
58
+ end
59
+ end
60
+ end
61
+ end
62
+ rescue Interrupt => e
63
+ puts e.class
64
+ quit!
65
+ end
66
+
67
+ ##
68
+ # quit!
69
+ #
70
+ def quit!
71
+ if @tun && !@tun.closed? && @tun_info[ :tund_addr ]
72
+ # puts "debug1 send tun fin"
73
+ data = [ 0, TUN_FIN ].pack( 'Q>C' )
74
+ @tun.sendmsg( data, 0, @tun_info[ :tund_addr ] )
75
+ end
76
+
77
+ # puts "debug1 exit"
78
+ exit
79
+ end
80
+
81
+ private
82
+
83
+ ##
84
+ # loop check expire
85
+ #
86
+ def loop_check_expire
87
+ Thread.new do
88
+ loop do
89
+ sleep CHECK_EXPIRE_INTERVAL
90
+
91
+ @mutex.synchronize do
92
+ need_trigger = false
93
+ now = Time.new
94
+
95
+ if @tun && !@tun.closed? && @tun_info[ :tund_addr ]
96
+ if now - @tun_info[ :last_recv_at ] > EXPIRE_AFTER
97
+ puts "#{ Time.new } expire tun"
98
+ set_is_closing( @tun )
99
+ else
100
+ # puts "debug1 #{ Time.new } heartbeat"
101
+ add_tun_ctlmsg( pack_a_heartbeat )
102
+
103
+ @tun_info[ :src_exts ].each do | src_id, src_ext |
104
+ if src_ext[ :src ].closed? && ( now - src_ext[ :last_continue_at ] > EXPIRE_AFTER )
105
+ puts "#{ Time.new } expire src ext #{ src_id }"
106
+ del_src_ext( src_id )
107
+ end
108
+ end
109
+ end
110
+
111
+ need_trigger = true
112
+ end
113
+
114
+ @src_infos.each do | src, src_info |
115
+ is_expired = src_info[ :last_recv_at ].nil? && ( now - src_info[ :created_at ] > EXPIRE_NEW )
116
+
117
+ if is_expired
118
+ puts "#{ Time.new } expire src"
119
+ set_is_closing( src )
120
+ need_trigger = true
121
+ end
122
+ end
123
+
124
+ if need_trigger
125
+ next_tick
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
131
+
132
+ ##
133
+ # loop check status
134
+ #
135
+ def loop_check_status
136
+ Thread.new do
137
+ loop do
138
+ sleep STATUS_INTERVAL
139
+
140
+ @mutex.synchronize do
141
+ if @tun && !@tun.closed? && @tun_info[ :tund_addr ]
142
+ need_trigger = false
143
+
144
+ if @tun_info[ :src_exts ].any?
145
+ now = Time.new
146
+
147
+ @tun_info[ :src_exts ].each do | src_id, src_ext |
148
+ if now - src_ext[ :last_continue_at ] < SEND_STATUS_UNTIL
149
+ data = [ 0, SOURCE_STATUS, src_id, src_ext[ :relay_pack_id ], src_ext[ :continue_dst_pack_id ] ].pack( 'Q>CQ>Q>Q>' )
150
+ add_tun_ctlmsg( data )
151
+ need_trigger = true
152
+ end
153
+ end
154
+ end
155
+
156
+ if @tun_info[ :paused ] && ( @tun_info[ :src_exts ].map{ | _, src_ext | src_ext[ :wmems ].size }.sum < RESUME_BELOW )
157
+ puts "#{ Time.new } resume tun"
158
+ @tun_info[ :paused ] = false
159
+ add_write( @tun )
160
+ need_trigger = true
161
+ end
162
+
163
+ if need_trigger
164
+ next_tick
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
171
+
172
+ ##
173
+ # loop punch peer
174
+ #
175
+ def loop_punch_peer
176
+ Thread.new do
177
+ EXPIRE_NEW.times do
178
+ if @tun.closed?
179
+ # puts "debug1 break loop punch peer"
180
+ break
181
+ end
182
+
183
+ @mutex.synchronize do
184
+ # puts "debug1 punch peer"
185
+ add_tun_ctlmsg( pack_a_heartbeat, @tun_info[ :peer_addr ] )
186
+ next_tick
187
+ end
188
+
189
+ sleep 1
190
+ end
191
+ end
192
+ end
193
+
194
+ ##
195
+ # loop send a new source
196
+ #
197
+ def loop_send_a_new_source( src_ext, data )
198
+ Thread.new do
199
+ EXPIRE_NEW.times do
200
+ if src_ext[ :src ].closed? || src_ext[ :dst_port ]
201
+ # puts "debug1 break loop send a new source #{ src_ext[ :dst_port ] }"
202
+ break
203
+ end
204
+
205
+ @mutex.synchronize do
206
+ # puts "debug1 send a new source #{ data.inspect }"
207
+ add_tun_ctlmsg( data )
208
+ next_tick
209
+ end
210
+
211
+ sleep 1
212
+ end
213
+ end
214
+ end
215
+
216
+ ##
217
+ # new a sdwd
218
+ #
219
+ def new_a_sdwd
220
+ sdwd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
221
+ sdwd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
222
+
223
+ if RUBY_PLATFORM.include?( 'linux' )
224
+ sdwd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 )
225
+ sdwd.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 )
226
+ end
227
+
228
+ sdwd.bind( @sdwd_addr )
229
+ sdwd.listen( 511 )
230
+ puts "#{ Time.new } sdwd listen on #{ sdwd.local_address.ip_port }"
231
+ add_read( sdwd, :sdwd )
232
+ end
233
+
234
+ ##
235
+ # new a tun
236
+ #
237
+ def new_a_tun
238
+ tun = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
239
+ tun.bind( Socket.sockaddr_in( 0, '0.0.0.0' ) )
240
+ port = tun.local_address.ip_port
241
+ puts "#{ Time.new } tun bind on #{ port }"
242
+
243
+ tun_info = {
244
+ port: port, # 端口
245
+ ctlmsgs: [], # [ to_addr, data ]
246
+ wbuffs: [], # 写前缓存 [ src_id, pack_id, data ]
247
+ caches: [], # 块读出缓存 [ src_id, pack_id, data ]
248
+ chunks: [], # 块队列 filename
249
+ spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
250
+ peer_addr: nil, # 对面地址
251
+ tund_addr: nil, # 连通后的tund地址
252
+ src_exts: {}, # src额外信息 src_id => {}
253
+ src_ids: {}, # dst_port => src_id
254
+ paused: false, # 是否暂停写
255
+ resendings: [], # 重传队列 [ src_id, pack_id ]
256
+ created_at: Time.new, # 创建时间
257
+ last_recv_at: nil, # 上一次收到流量的时间,过期关闭
258
+ is_closing: false # 是否准备关闭
259
+ }
260
+
261
+ @tun = tun
262
+ @tun_info = tun_info
263
+ add_read( tun, :tun )
264
+ add_tun_ctlmsg( @room, @p2pd_addr )
265
+ end
266
+
267
+ ##
268
+ # pack a heartbeat
269
+ #
270
+ def pack_a_heartbeat
271
+ [ 0, HEARTBEAT, rand( 128 ) ].pack( 'Q>CC' )
272
+ end
273
+
274
+ ##
275
+ # is match tund addr
276
+ #
277
+ def is_match_tund_addr( addrinfo )
278
+ return false unless @tun_info[ :tund_addr ]
279
+
280
+ from_addr = addrinfo.to_sockaddr
281
+
282
+ if from_addr != @tun_info[ :tund_addr ]
283
+ puts "#{ Time.new } #{ addrinfo.inspect } not match #{ Addrinfo.new( @tun_info[ :tund_addr ] ).inspect }"
284
+ return false
285
+ end
286
+
287
+ @tun_info[ :last_recv_at ] = Time.new
288
+
289
+ true
290
+ end
291
+
292
+ ##
293
+ # add tun ctlmsg
294
+ #
295
+ def add_tun_ctlmsg( data, to_addr = nil )
296
+ unless to_addr
297
+ to_addr = @tun_info[ :tund_addr ]
298
+ end
299
+
300
+ if to_addr
301
+ @tun_info[ :ctlmsgs ] << [ to_addr, data ]
302
+ add_write( @tun )
303
+ end
304
+ end
305
+
306
+ ##
307
+ # add tun wbuff
308
+ #
309
+ def add_tun_wbuff( src_id, pack_id, data )
310
+ @tun_info[ :wbuffs ] << [ src_id, pack_id, data ]
311
+
312
+ if @tun_info[ :wbuffs ].size >= WBUFFS_LIMIT
313
+ spring = @tun_info[ :chunks ].size > 0 ? ( @tun_info[ :spring ] + 1 ) : 0
314
+ filename = "#{ Process.pid }-#{ @tun_info[ :port ] }.#{ spring }"
315
+ chunk_path = File.join( @tun_chunk_dir, filename )
316
+ datas = @tun_info[ :wbuffs ].map{ | _src_id, _pack_id, _data | [ [ _src_id, _pack_id, _data.bytesize ].pack( 'Q>Q>n' ), _data ].join }
317
+
318
+ begin
319
+ IO.binwrite( chunk_path, datas.join )
320
+ rescue Errno::ENOSPC => e
321
+ puts "#{ Time.new } #{ e.class }, close tun"
322
+ set_is_closing( @tun )
323
+ return
324
+ end
325
+
326
+ @tun_info[ :chunks ] << filename
327
+ @tun_info[ :spring ] = spring
328
+ @tun_info[ :wbuffs ].clear
329
+ end
330
+
331
+ add_write( @tun )
332
+ end
333
+
334
+ ##
335
+ # add src wbuff
336
+ #
337
+ def add_src_wbuff( src, data )
338
+ src_info = @src_infos[ src ]
339
+ src_info[ :wbuff ] << data
340
+
341
+ if src_info[ :wbuff ].bytesize >= CHUNK_SIZE
342
+ spring = src_info[ :chunks ].size > 0 ? ( src_info[ :spring ] + 1 ) : 0
343
+ filename = "#{ Process.pid }-#{ src_info[ :id ] }.#{ spring }"
344
+ chunk_path = File.join( @src_chunk_dir, filename )
345
+
346
+ begin
347
+ IO.binwrite( chunk_path, src_info[ :wbuff ] )
348
+ rescue Errno::ENOSPC => e
349
+ puts "#{ Time.new } #{ e.class }, close src"
350
+ set_is_closing( src )
351
+ return
352
+ end
353
+
354
+ src_info[ :chunks ] << filename
355
+ src_info[ :spring ] = spring
356
+ src_info[ :wbuff ].clear
357
+ end
358
+
359
+ add_write( src )
360
+ end
361
+
362
+ ##
363
+ # add read
364
+ #
365
+ def add_read( sock, role )
366
+ unless @reads.include?( sock )
367
+ @reads << sock
368
+ end
369
+
370
+ @roles[ sock ] = role
371
+ end
372
+
373
+ ##
374
+ # add write
375
+ #
376
+ def add_write( sock )
377
+ if sock && !sock.closed? && !@writes.include?( sock )
378
+ @writes << sock
379
+ end
380
+ end
381
+
382
+ ##
383
+ # set is closing
384
+ #
385
+ def set_is_closing( sock )
386
+ if sock && !sock.closed?
387
+ role = @roles[ sock ]
388
+ # puts "debug1 set #{ role.to_s } is closing"
389
+
390
+ case role
391
+ when :src
392
+ src_info = @src_infos[ sock ]
393
+ src_info[ :is_closing ] = true
394
+ when :tun
395
+ @tun_info[ :is_closing ] = true
396
+ end
397
+
398
+ @reads.delete( sock )
399
+ add_write( sock )
400
+ end
401
+ end
402
+
403
+ ##
404
+ # close src
405
+ #
406
+ def close_src( src )
407
+ # puts "debug1 close src"
408
+ close_sock( src )
409
+ src_info = @src_infos.delete( src )
410
+
411
+ src_info[ :chunks ].each do | filename |
412
+ begin
413
+ File.delete( File.join( @src_chunk_dir, filename ) )
414
+ rescue Errno::ENOENT
415
+ end
416
+ end
417
+
418
+ return if @tun.closed?
419
+
420
+ src_id = src_info[ :id ]
421
+ src_ext = @tun_info[ :src_exts ][ src_id ]
422
+ return unless src_ext
423
+
424
+ if src_ext[ :is_dst_closed ]
425
+ # puts "debug1 2-3. after close src -> dst closed ? yes -> del src ext -> send fin2"
426
+ del_src_ext( src_id )
427
+ data = [ 0, FIN2, src_id ].pack( 'Q>CQ>' )
428
+ add_tun_ctlmsg( data )
429
+ else
430
+ # puts "debug1 1-1. after close src -> dst closed ? no -> send fin1"
431
+ data = [ 0, FIN1, src_id, src_info[ :biggest_pack_id ], src_ext[ :continue_dst_pack_id ] ].pack( 'Q>CQ>Q>Q>' )
432
+ add_tun_ctlmsg( data )
433
+ end
434
+ end
435
+
436
+ ##
437
+ # close tun
438
+ #
439
+ def close_tun( tun )
440
+ # puts "debug1 close tun"
441
+ close_sock( tun )
442
+
443
+ @tun_info[ :chunks ].each do | filename |
444
+ begin
445
+ File.delete( File.join( @tun_chunk_dir, filename ) )
446
+ rescue Errno::ENOENT
447
+ end
448
+ end
449
+
450
+ @tun_info[ :src_exts ].each{ | _, src_ext | set_is_closing( src_ext[ :src ] ) }
451
+ end
452
+
453
+ ##
454
+ # close sock
455
+ #
456
+ def close_sock( sock )
457
+ sock.close
458
+ @reads.delete( sock )
459
+ @writes.delete( sock )
460
+ @roles.delete( sock )
461
+ end
462
+
463
+ ##
464
+ # del src ext
465
+ #
466
+ def del_src_ext( src_id )
467
+ src_ext = @tun_info[ :src_exts ].delete( src_id )
468
+
469
+ if src_ext
470
+ @tun_info[ :src_ids ].delete( src_ext[ :dst_port ] )
471
+ end
472
+ end
473
+
474
+ ##
475
+ # release wmems
476
+ #
477
+ def release_wmems( src_ext, completed_pack_id )
478
+ if completed_pack_id > src_ext[ :completed_pack_id ]
479
+ # puts "debug2 update completed pack #{ completed_pack_id }"
480
+
481
+ pack_ids = src_ext[ :wmems ].keys.select { | pack_id | pack_id <= completed_pack_id }
482
+
483
+ pack_ids.each do | pack_id |
484
+ src_ext[ :wmems ].delete( pack_id )
485
+ src_ext[ :send_ats ].delete( pack_id )
486
+ end
487
+
488
+ src_ext[ :completed_pack_id ] = completed_pack_id
489
+ end
490
+ end
491
+
492
+ ##
493
+ # next tick
494
+ #
495
+ def next_tick
496
+ @dotw.write( '.' )
497
+ end
498
+
499
+ ##
500
+ # write src
501
+ #
502
+ def write_src( src )
503
+ src_info = @src_infos[ src ]
504
+ data = src_info[ :cache ]
505
+ from = :cache
506
+
507
+ if data.empty?
508
+ if src_info[ :chunks ].any?
509
+ path = File.join( @src_chunk_dir, src_info[ :chunks ].shift )
510
+
511
+ begin
512
+ src_info[ :cache ] = data = IO.binread( path )
513
+ File.delete( path )
514
+ rescue Errno::ENOENT => e
515
+ puts "#{ Time.new } read #{ path } #{ e.class }"
516
+ close_src( src )
517
+ return
518
+ end
519
+ else
520
+ data = src_info[ :wbuff ]
521
+ from = :wbuff
522
+ end
523
+ end
524
+
525
+ if data.empty?
526
+ if src_info[ :is_closing ]
527
+ close_src( src )
528
+ else
529
+ @writes.delete( src )
530
+ end
531
+
532
+ return
533
+ end
534
+
535
+ begin
536
+ written = src.write_nonblock( data )
537
+ rescue IO::WaitWritable, Errno::EINTR
538
+ return
539
+ rescue Exception => e
540
+ close_src( src )
541
+ return
542
+ end
543
+
544
+ # puts "debug2 write src #{ written }"
545
+ data = data[ written..-1 ]
546
+ src_info[ from ] = data
547
+ end
548
+
549
+ ##
550
+ # write tun
551
+ #
552
+ def write_tun( tun )
553
+ if @tun_info[ :is_closing ]
554
+ close_tun( tun )
555
+ return
556
+ end
557
+
558
+ # 传ctlmsg
559
+ while @tun_info[ :ctlmsgs ].any?
560
+ to_addr, data = @tun_info[ :ctlmsgs ].first
561
+
562
+ begin
563
+ tun.sendmsg( data, 0, to_addr )
564
+ rescue IO::WaitWritable, Errno::EINTR
565
+ return
566
+ end
567
+
568
+ @tun_info[ :ctlmsgs ].shift
569
+ end
570
+
571
+ # 重传
572
+ while @tun_info[ :resendings ].any?
573
+ src_id, pack_id = @tun_info[ :resendings ].first
574
+ src_ext = @tun_info[ :src_exts ][ src_id ]
575
+
576
+ if src_ext
577
+ data = src_ext[ :wmems ][ pack_id ]
578
+
579
+ if data
580
+ begin
581
+ tun.sendmsg( data, 0, @tun_info[ :tund_addr ] )
582
+ rescue IO::WaitWritable, Errno::EINTR
583
+ return
584
+ end
585
+ end
586
+ end
587
+
588
+ @tun_info[ :resendings ].shift
589
+ return
590
+ end
591
+
592
+ # 若写后达到上限,暂停取写前
593
+ if @tun_info[ :src_exts ].map{ | _, src_ext | src_ext[ :wmems ].size }.sum >= WMEMS_LIMIT
594
+ unless @tun_info[ :paused ]
595
+ puts "#{ Time.new } pause tun #{ @tun_info[ :port ] }"
596
+ @tun_info[ :paused ] = true
597
+ end
598
+
599
+ @writes.delete( tun )
600
+ return
601
+ end
602
+
603
+ # 取写前
604
+ if @tun_info[ :caches ].any?
605
+ src_id, pack_id, data = @tun_info[ :caches ].first
606
+ from = :caches
607
+ elsif @tun_info[ :chunks ].any?
608
+ path = File.join( @tun_chunk_dir, @tun_info[ :chunks ].shift )
609
+
610
+ begin
611
+ data = IO.binread( path )
612
+ File.delete( path )
613
+ rescue Errno::ENOENT => e
614
+ puts "#{ Time.new } read #{ path } #{ e.class }"
615
+ close_tun( tun )
616
+ return
617
+ end
618
+
619
+ caches = []
620
+
621
+ until data.empty?
622
+ _src_id, _pack_id, pack_size = data[ 0, 18 ].unpack( 'Q>Q>n' )
623
+ caches << [ _src_id, _pack_id, data[ 18, pack_size ] ]
624
+ data = data[ ( 18 + pack_size )..-1 ]
625
+ end
626
+
627
+ @tun_info[ :caches ] = caches
628
+ src_id, pack_id, data = caches.first
629
+ from = :caches
630
+ elsif @tun_info[ :wbuffs ].any?
631
+ src_id, pack_id, data = @tun_info[ :wbuffs ].first
632
+ from = :wbuffs
633
+ else
634
+ @writes.delete( tun )
635
+ return
636
+ end
637
+
638
+ src_ext = @tun_info[ :src_exts ][ src_id ]
639
+
640
+ if src_ext
641
+ if pack_id <= CONFUSE_UNTIL
642
+ data = @custom.encode( data )
643
+ # puts "debug1 encoded pack #{ pack_id }"
644
+ end
645
+
646
+ data = [ [ pack_id, src_id ].pack( 'Q>Q>' ), data ].join
647
+
648
+ begin
649
+ tun.sendmsg( data, 0, @tun_info[ :tund_addr ] )
650
+ rescue IO::WaitWritable, Errno::EINTR
651
+ return
652
+ end
653
+
654
+ # puts "debug2 written pack #{ pack_id }"
655
+ now = Time.new
656
+ src_ext[ :relay_pack_id ] = pack_id
657
+ src_ext[ :wmems ][ pack_id ] = data
658
+ src_ext[ :send_ats ][ pack_id ] = now
659
+ src_ext[ :last_continue_at ] = now
660
+ end
661
+
662
+ @tun_info[ from ].shift
663
+ end
664
+
665
+ ##
666
+ # read dotr
667
+ #
668
+ def read_dotr( dotr )
669
+ dotr.read( 1 )
670
+ end
671
+
672
+ ##
673
+ # read sdwd
674
+ #
675
+ def read_sdwd( sdwd )
676
+ begin
677
+ src, addrinfo = sdwd.accept_nonblock
678
+ rescue IO::WaitReadable, Errno::EINTR
679
+ return
680
+ end
681
+
682
+ id = rand( ( 2 ** 64 ) - 1 ) + 1
683
+ # puts "debug1 accept a src #{ addrinfo.inspect } #{ id }"
684
+
685
+ @src_infos[ src ] = {
686
+ id: id, # id
687
+ biggest_pack_id: 0, # 最大包号码
688
+ rbuffs: [], # p1端dst未准备好,暂存流量 [ pack_id, data ]
689
+ wbuff: '', # 写前
690
+ cache: '', # 块读出缓存
691
+ chunks: [], # 块队列,写前达到块大小时结一个块 filename
692
+ spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
693
+ created_at: Time.new, # 创建时间
694
+ last_recv_at: nil, # 上一次收到流量的时间,过期关闭
695
+ is_closing: false # 是否准备关闭
696
+ }
697
+
698
+ add_read( src, :src )
699
+
700
+ if @tun.nil? || @tun.closed?
701
+ new_a_tun
702
+ end
703
+
704
+ src_ext = {
705
+ src: src, # src
706
+ dst_port: nil, # p1端dst端口
707
+ wmems: {}, # 写后 pack_id => data
708
+ send_ats: {}, # 上一次发出时间 pack_id => send_at
709
+ relay_pack_id: 0, # 转发到几
710
+ continue_dst_pack_id: 0, # 收到几
711
+ pieces: {}, # 跳号包 dst_pack_id => data
712
+ is_dst_closed: false, # dst是否已关闭
713
+ biggest_dst_pack_id: 0, # dst最大包号码
714
+ completed_pack_id: 0, # 完成到几(对面收到几)
715
+ last_continue_at: Time.new # 创建,或者上一次收到连续流量,或者发出新包的时间
716
+ }
717
+
718
+ @tun_info[ :src_exts ][ id ] = src_ext
719
+ data = [ 0, A_NEW_SOURCE, id ].pack( 'Q>CQ>' )
720
+ loop_send_a_new_source( src_ext, data )
721
+ end
722
+
723
+ ##
724
+ # read src
725
+ #
726
+ def read_src( src )
727
+ begin
728
+ data = src.read_nonblock( PACK_SIZE )
729
+ rescue IO::WaitReadable, Errno::EINTR
730
+ return
731
+ rescue Exception => e
732
+ # puts "debug1 read src #{ e.class }"
733
+ set_is_closing( src )
734
+ return
735
+ end
736
+
737
+ # puts "debug2 read src #{ data.inspect }"
738
+ src_info = @src_infos[ src ]
739
+ src_info[ :last_recv_at ] = Time.new
740
+ src_id = src_info[ :id ]
741
+ src_ext = @tun_info[ :src_exts ][ src_id ]
742
+
743
+ unless src_ext
744
+ # puts "debug1 not found src ext"
745
+ set_is_closing( src )
746
+ return
747
+ end
748
+
749
+ if @tun.closed?
750
+ puts "#{ Time.new } tun closed, close src"
751
+ set_is_closing( src )
752
+ return
753
+ end
754
+
755
+ pack_id = src_info[ :biggest_pack_id ] + 1
756
+ src_info[ :biggest_pack_id ] = pack_id
757
+
758
+ if src_ext[ :dst_port ]
759
+ add_tun_wbuff( src_info[ :id ], pack_id, data )
760
+ else
761
+ # puts "debug1 p1 dst not ready, save data to src rbuff"
762
+ src_info[ :rbuffs ] << [ pack_id, data ]
763
+ end
764
+ end
765
+
766
+ ##
767
+ # read tun
768
+ #
769
+ def read_tun( tun )
770
+ data, addrinfo, rflags, *controls = tun.recvmsg
771
+ now = Time.new
772
+ pack_id = data[ 0, 8 ].unpack( 'Q>' ).first
773
+
774
+ if pack_id == 0
775
+ ctl_num = data[ 8 ].unpack( 'C' ).first
776
+
777
+ case ctl_num
778
+ when PEER_ADDR
779
+ return if @tun_info[ :peer_addr ] || ( addrinfo.to_sockaddr != @p2pd_addr )
780
+
781
+ peer_addr = data[ 9..-1 ]
782
+ puts "#{ Time.new } got peer addr #{ Addrinfo.new( peer_addr ).inspect }"
783
+
784
+ @tun_info[ :peer_addr ] = peer_addr
785
+ loop_punch_peer
786
+ when HEARTBEAT
787
+ from_addr = addrinfo.to_sockaddr
788
+ return if from_addr != @tun_info[ :peer_addr ]
789
+
790
+ # puts "debug1 set tun addr #{ Addrinfo.new( from_addr ).inspect }"
791
+ @tun_info[ :tund_addr ] = from_addr
792
+ @tun_info[ :last_recv_at ] = now
793
+ when PAIRED
794
+ return unless is_match_tund_addr( addrinfo )
795
+
796
+ src_id, dst_port = data[ 9, 10 ].unpack( 'Q>n' )
797
+
798
+ src_ext = @tun_info[ :src_exts ][ src_id ]
799
+ return if src_ext.nil? || src_ext[ :dst_port ]
800
+
801
+ src = src_ext[ :src ]
802
+ return if src.closed?
803
+
804
+ # puts "debug1 got paired #{ src_id } #{ dst_port }"
805
+
806
+ if dst_port == 0
807
+ set_is_closing( src )
808
+ return
809
+ end
810
+
811
+ src_ext[ :dst_port ] = dst_port
812
+ @tun_info[ :src_ids ][ dst_port ] = src_id
813
+
814
+ src_info = @src_infos[ src ]
815
+
816
+ src_info[ :rbuffs ].each do | _pack_id, _data |
817
+ add_tun_wbuff( src_id, _pack_id, _data )
818
+ end
819
+ when DEST_STATUS
820
+ return unless is_match_tund_addr( addrinfo )
821
+
822
+ dst_port, relay_dst_pack_id, continue_src_pack_id = data[ 9, 18 ].unpack( 'nQ>Q>' )
823
+
824
+ src_id = @tun_info[ :src_ids ][ dst_port ]
825
+ return unless src_id
826
+
827
+ src_ext = @tun_info[ :src_exts ][ src_id ]
828
+ return unless src_ext
829
+
830
+ # puts "debug2 got dest status"
831
+
832
+ release_wmems( src_ext, continue_src_pack_id )
833
+
834
+ # 发miss
835
+ if !src_ext[ :src ].closed? && ( src_ext[ :continue_dst_pack_id ] < relay_dst_pack_id )
836
+ ranges = []
837
+ curr_pack_id = src_ext[ :continue_dst_pack_id ] + 1
838
+
839
+ src_ext[ :pieces ].keys.sort.each do | pack_id |
840
+ if pack_id > curr_pack_id
841
+ ranges << [ curr_pack_id, pack_id - 1 ]
842
+ end
843
+
844
+ curr_pack_id = pack_id + 1
845
+ end
846
+
847
+ if curr_pack_id <= relay_dst_pack_id
848
+ ranges << [ curr_pack_id, relay_dst_pack_id ]
849
+ end
850
+
851
+ pack_count = 0
852
+ # puts "debug1 continue/relay #{ src_ext[ :continue_dst_pack_id ] }/#{ relay_dst_pack_id } send MISS #{ ranges.size }"
853
+
854
+ ranges.each do | pack_id_begin, pack_id_end |
855
+ if pack_count >= BREAK_SEND_MISS
856
+ puts "#{ Time.new } break send miss at #{ pack_id_begin }"
857
+ break
858
+ end
859
+
860
+ data2 = [ 0, MISS, dst_port, pack_id_begin, pack_id_end ].pack( 'Q>CnQ>Q>' )
861
+ add_tun_ctlmsg( data2 )
862
+ pack_count += ( pack_id_end - pack_id_begin + 1 )
863
+ end
864
+ end
865
+ when MISS
866
+ return unless is_match_tund_addr( addrinfo )
867
+
868
+ src_id, pack_id_begin, pack_id_end = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
869
+
870
+ src_ext = @tun_info[ :src_exts ][ src_id ]
871
+ return unless src_ext
872
+
873
+ ( pack_id_begin..pack_id_end ).each do | pack_id |
874
+ send_at = src_ext[ :send_ats ][ pack_id ]
875
+
876
+ if send_at
877
+ break if now - send_at < STATUS_INTERVAL
878
+ @tun_info[ :resendings ] << [ src_id, pack_id ]
879
+ end
880
+ end
881
+
882
+ add_write( tun )
883
+ when FIN1
884
+ return unless is_match_tund_addr( addrinfo )
885
+
886
+ dst_port, biggest_dst_pack_id, continue_src_pack_id = data[ 9, 18 ].unpack( 'nQ>Q>' )
887
+
888
+ src_id = @tun_info[ :src_ids ][ dst_port ]
889
+ return unless src_id
890
+
891
+ src_ext = @tun_info[ :src_exts ][ src_id ]
892
+ return unless src_ext
893
+
894
+ # puts "debug1 got fin1 #{ dst_port } biggest dst pack #{ biggest_dst_pack_id } completed src pack #{ continue_src_pack_id }"
895
+ src_ext[ :is_dst_closed ] = true
896
+ src_ext[ :biggest_dst_pack_id ] = biggest_dst_pack_id
897
+ release_wmems( src_ext, continue_src_pack_id )
898
+
899
+ if ( biggest_dst_pack_id == src_ext[ :continue_dst_pack_id ] )
900
+ # puts "debug1 2-1. tun recv fin1 -> all traffic received ? -> close src after write"
901
+ set_is_closing( src_ext[ :src ] )
902
+ end
903
+ when FIN2
904
+ return unless is_match_tund_addr( addrinfo )
905
+
906
+ dst_port = data[ 9, 2 ].unpack( 'n' ).first
907
+
908
+ src_id = @tun_info[ :src_ids ][ dst_port ]
909
+ return unless src_id
910
+
911
+ # puts "debug1 1-2. tun recv fin2 -> del src ext"
912
+ del_src_ext( src_id )
913
+ when TUND_FIN
914
+ return unless is_match_tund_addr( addrinfo )
915
+
916
+ puts "#{ Time.new } recv tund fin"
917
+ set_is_closing( tun )
918
+ end
919
+
920
+ return
921
+ end
922
+
923
+ return unless is_match_tund_addr( addrinfo )
924
+
925
+ dst_port = data[ 8, 2 ].unpack( 'n' ).first
926
+
927
+ src_id = @tun_info[ :src_ids ][ dst_port ]
928
+ return unless src_id
929
+
930
+ src_ext = @tun_info[ :src_exts ][ src_id ]
931
+ return if src_ext.nil? || src_ext[ :src ].closed?
932
+ return if ( pack_id <= src_ext[ :continue_dst_pack_id ] ) || src_ext[ :pieces ].include?( pack_id )
933
+
934
+ data = data[ 10..-1 ]
935
+ # puts "debug2 got pack #{ pack_id }"
936
+
937
+ if pack_id <= CONFUSE_UNTIL
938
+ # puts "debug2 #{ data.inspect }"
939
+ data = @custom.decode( data )
940
+ # puts "debug1 decoded pack #{ pack_id }"
941
+ end
942
+
943
+ # 放进写前,跳号放碎片缓存
944
+ if pack_id - src_ext[ :continue_dst_pack_id ] == 1
945
+ while src_ext[ :pieces ].include?( pack_id + 1 )
946
+ data << src_ext[ :pieces ].delete( pack_id + 1 )
947
+ pack_id += 1
948
+ end
949
+
950
+ src_ext[ :continue_dst_pack_id ] = pack_id
951
+ src_ext[ :last_continue_at ] = now
952
+ add_src_wbuff( src_ext[ :src ], data )
953
+ # puts "debug2 update continue dst pack #{ pack_id }"
954
+
955
+ # 接到流量,若对面已关闭,且流量正好收全,关闭src
956
+ if src_ext[ :is_dst_closed ] && ( pack_id == src_ext[ :biggest_dst_pack_id ] )
957
+ # puts "debug1 2-2. tun recv traffic -> dst closed and all traffic received ? -> close src after write"
958
+ set_is_closing( src_ext[ :src ] )
959
+ end
960
+ else
961
+ src_ext[ :pieces ][ pack_id ] = data
962
+ end
963
+ end
964
+
965
+ end
966
+ end