p2p2 0.14.0 → 0.18.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,963 @@
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
+ from_addr = addrinfo.to_sockaddr
279
+
280
+ if from_addr != @tun_info[ :tund_addr ]
281
+ puts "#{ Time.new } #{ addrinfo.inspect } not match #{ Addrinfo.new( @tun_info[ :tund_addr ] ).inspect }"
282
+ return false
283
+ end
284
+
285
+ @tun_info[ :last_recv_at ] = Time.new
286
+ true
287
+ end
288
+
289
+ ##
290
+ # add tun ctlmsg
291
+ #
292
+ def add_tun_ctlmsg( data, to_addr = nil )
293
+ unless to_addr
294
+ to_addr = @tun_info[ :tund_addr ]
295
+ end
296
+
297
+ if to_addr
298
+ @tun_info[ :ctlmsgs ] << [ to_addr, data ]
299
+ add_write( @tun )
300
+ end
301
+ end
302
+
303
+ ##
304
+ # add tun wbuff
305
+ #
306
+ def add_tun_wbuff( src_id, pack_id, data )
307
+ @tun_info[ :wbuffs ] << [ src_id, pack_id, data ]
308
+
309
+ if @tun_info[ :wbuffs ].size >= WBUFFS_LIMIT
310
+ spring = @tun_info[ :chunks ].size > 0 ? ( @tun_info[ :spring ] + 1 ) : 0
311
+ filename = "#{ Process.pid }-#{ @tun_info[ :port ] }.#{ spring }"
312
+ chunk_path = File.join( @tun_chunk_dir, filename )
313
+ datas = @tun_info[ :wbuffs ].map{ | _src_id, _pack_id, _data | [ [ _src_id, _pack_id, _data.bytesize ].pack( 'Q>Q>n' ), _data ].join }
314
+
315
+ begin
316
+ IO.binwrite( chunk_path, datas.join )
317
+ rescue Errno::ENOSPC => e
318
+ puts "#{ Time.new } #{ e.class }, close tun"
319
+ set_is_closing( @tun )
320
+ return
321
+ end
322
+
323
+ @tun_info[ :chunks ] << filename
324
+ @tun_info[ :spring ] = spring
325
+ @tun_info[ :wbuffs ].clear
326
+ end
327
+
328
+ add_write( @tun )
329
+ end
330
+
331
+ ##
332
+ # add src wbuff
333
+ #
334
+ def add_src_wbuff( src, data )
335
+ src_info = @src_infos[ src ]
336
+ src_info[ :wbuff ] << data
337
+
338
+ if src_info[ :wbuff ].bytesize >= CHUNK_SIZE
339
+ spring = src_info[ :chunks ].size > 0 ? ( src_info[ :spring ] + 1 ) : 0
340
+ filename = "#{ Process.pid }-#{ src_info[ :id ] }.#{ spring }"
341
+ chunk_path = File.join( @src_chunk_dir, filename )
342
+
343
+ begin
344
+ IO.binwrite( chunk_path, src_info[ :wbuff ] )
345
+ rescue Errno::ENOSPC => e
346
+ puts "#{ Time.new } #{ e.class }, close src"
347
+ set_is_closing( src )
348
+ return
349
+ end
350
+
351
+ src_info[ :chunks ] << filename
352
+ src_info[ :spring ] = spring
353
+ src_info[ :wbuff ].clear
354
+ end
355
+
356
+ add_write( src )
357
+ end
358
+
359
+ ##
360
+ # add read
361
+ #
362
+ def add_read( sock, role )
363
+ unless @reads.include?( sock )
364
+ @reads << sock
365
+ end
366
+
367
+ @roles[ sock ] = role
368
+ end
369
+
370
+ ##
371
+ # add write
372
+ #
373
+ def add_write( sock )
374
+ if sock && !sock.closed? && !@writes.include?( sock )
375
+ @writes << sock
376
+ end
377
+ end
378
+
379
+ ##
380
+ # set is closing
381
+ #
382
+ def set_is_closing( sock )
383
+ if sock && !sock.closed?
384
+ role = @roles[ sock ]
385
+ # puts "debug1 set #{ role.to_s } is closing"
386
+
387
+ case role
388
+ when :src
389
+ src_info = @src_infos[ sock ]
390
+ src_info[ :is_closing ] = true
391
+ when :tun
392
+ @tun_info[ :is_closing ] = true
393
+ end
394
+
395
+ @reads.delete( sock )
396
+ add_write( sock )
397
+ end
398
+ end
399
+
400
+ ##
401
+ # close src
402
+ #
403
+ def close_src( src )
404
+ # puts "debug1 close src"
405
+ close_sock( src )
406
+ src_info = @src_infos.delete( src )
407
+
408
+ src_info[ :chunks ].each do | filename |
409
+ begin
410
+ File.delete( File.join( @src_chunk_dir, filename ) )
411
+ rescue Errno::ENOENT
412
+ end
413
+ end
414
+
415
+ return if @tun.closed?
416
+
417
+ src_id = src_info[ :id ]
418
+ src_ext = @tun_info[ :src_exts ][ src_id ]
419
+ return unless src_ext
420
+
421
+ if src_ext[ :is_dst_closed ]
422
+ # puts "debug1 2-3. after close src -> dst closed ? yes -> del src ext -> send fin2"
423
+ del_src_ext( src_id )
424
+ data = [ 0, FIN2, src_id ].pack( 'Q>CQ>' )
425
+ add_tun_ctlmsg( data )
426
+ else
427
+ # puts "debug1 1-1. after close src -> dst closed ? no -> send fin1"
428
+ data = [ 0, FIN1, src_id, src_info[ :biggest_pack_id ], src_ext[ :continue_dst_pack_id ] ].pack( 'Q>CQ>Q>Q>' )
429
+ add_tun_ctlmsg( data )
430
+ end
431
+ end
432
+
433
+ ##
434
+ # close tun
435
+ #
436
+ def close_tun( tun )
437
+ # puts "debug1 close tun"
438
+ close_sock( tun )
439
+
440
+ @tun_info[ :chunks ].each do | filename |
441
+ begin
442
+ File.delete( File.join( @tun_chunk_dir, filename ) )
443
+ rescue Errno::ENOENT
444
+ end
445
+ end
446
+
447
+ @tun_info[ :src_exts ].each{ | _, src_ext | set_is_closing( src_ext[ :src ] ) }
448
+ end
449
+
450
+ ##
451
+ # close sock
452
+ #
453
+ def close_sock( sock )
454
+ sock.close
455
+ @reads.delete( sock )
456
+ @writes.delete( sock )
457
+ @roles.delete( sock )
458
+ end
459
+
460
+ ##
461
+ # del src ext
462
+ #
463
+ def del_src_ext( src_id )
464
+ src_ext = @tun_info[ :src_exts ].delete( src_id )
465
+
466
+ if src_ext
467
+ @tun_info[ :src_ids ].delete( src_ext[ :dst_port ] )
468
+ end
469
+ end
470
+
471
+ ##
472
+ # release wmems
473
+ #
474
+ def release_wmems( src_ext, completed_pack_id )
475
+ if completed_pack_id > src_ext[ :completed_pack_id ]
476
+ # puts "debug2 update completed pack #{ completed_pack_id }"
477
+
478
+ pack_ids = src_ext[ :wmems ].keys.select { | pack_id | pack_id <= completed_pack_id }
479
+
480
+ pack_ids.each do | pack_id |
481
+ src_ext[ :wmems ].delete( pack_id )
482
+ src_ext[ :send_ats ].delete( pack_id )
483
+ end
484
+
485
+ src_ext[ :completed_pack_id ] = completed_pack_id
486
+ end
487
+ end
488
+
489
+ ##
490
+ # next tick
491
+ #
492
+ def next_tick
493
+ @dotw.write( '.' )
494
+ end
495
+
496
+ ##
497
+ # write src
498
+ #
499
+ def write_src( src )
500
+ src_info = @src_infos[ src ]
501
+ data = src_info[ :cache ]
502
+ from = :cache
503
+
504
+ if data.empty?
505
+ if src_info[ :chunks ].any?
506
+ path = File.join( @src_chunk_dir, src_info[ :chunks ].shift )
507
+
508
+ begin
509
+ src_info[ :cache ] = data = IO.binread( path )
510
+ File.delete( path )
511
+ rescue Errno::ENOENT => e
512
+ puts "#{ Time.new } read #{ path } #{ e.class }"
513
+ close_src( src )
514
+ return
515
+ end
516
+ else
517
+ data = src_info[ :wbuff ]
518
+ from = :wbuff
519
+ end
520
+ end
521
+
522
+ if data.empty?
523
+ if src_info[ :is_closing ]
524
+ close_src( src )
525
+ else
526
+ @writes.delete( src )
527
+ end
528
+
529
+ return
530
+ end
531
+
532
+ begin
533
+ written = src.write_nonblock( data )
534
+ rescue IO::WaitWritable, Errno::EINTR
535
+ return
536
+ rescue Exception => e
537
+ close_src( src )
538
+ return
539
+ end
540
+
541
+ # puts "debug2 write src #{ written }"
542
+ data = data[ written..-1 ]
543
+ src_info[ from ] = data
544
+ end
545
+
546
+ ##
547
+ # write tun
548
+ #
549
+ def write_tun( tun )
550
+ if @tun_info[ :is_closing ]
551
+ close_tun( tun )
552
+ return
553
+ end
554
+
555
+ # 传ctlmsg
556
+ while @tun_info[ :ctlmsgs ].any?
557
+ to_addr, data = @tun_info[ :ctlmsgs ].first
558
+
559
+ begin
560
+ tun.sendmsg( data, 0, to_addr )
561
+ rescue IO::WaitWritable, Errno::EINTR
562
+ return
563
+ end
564
+
565
+ @tun_info[ :ctlmsgs ].shift
566
+ end
567
+
568
+ # 重传
569
+ while @tun_info[ :resendings ].any?
570
+ src_id, pack_id = @tun_info[ :resendings ].first
571
+ src_ext = @tun_info[ :src_exts ][ src_id ]
572
+
573
+ if src_ext
574
+ data = src_ext[ :wmems ][ pack_id ]
575
+
576
+ if data
577
+ begin
578
+ tun.sendmsg( data, 0, @tun_info[ :tund_addr ] )
579
+ rescue IO::WaitWritable, Errno::EINTR
580
+ return
581
+ end
582
+ end
583
+ end
584
+
585
+ @tun_info[ :resendings ].shift
586
+ return
587
+ end
588
+
589
+ # 若写后达到上限,暂停取写前
590
+ if @tun_info[ :src_exts ].map{ | _, src_ext | src_ext[ :wmems ].size }.sum >= WMEMS_LIMIT
591
+ unless @tun_info[ :paused ]
592
+ puts "#{ Time.new } pause tun #{ @tun_info[ :port ] }"
593
+ @tun_info[ :paused ] = true
594
+ end
595
+
596
+ @writes.delete( tun )
597
+ return
598
+ end
599
+
600
+ # 取写前
601
+ if @tun_info[ :caches ].any?
602
+ src_id, pack_id, data = @tun_info[ :caches ].first
603
+ from = :caches
604
+ elsif @tun_info[ :chunks ].any?
605
+ path = File.join( @tun_chunk_dir, @tun_info[ :chunks ].shift )
606
+
607
+ begin
608
+ data = IO.binread( path )
609
+ File.delete( path )
610
+ rescue Errno::ENOENT => e
611
+ puts "#{ Time.new } read #{ path } #{ e.class }"
612
+ close_tun( tun )
613
+ return
614
+ end
615
+
616
+ caches = []
617
+
618
+ until data.empty?
619
+ _src_id, _pack_id, pack_size = data[ 0, 18 ].unpack( 'Q>Q>n' )
620
+ caches << [ _src_id, _pack_id, data[ 18, pack_size ] ]
621
+ data = data[ ( 18 + pack_size )..-1 ]
622
+ end
623
+
624
+ @tun_info[ :caches ] = caches
625
+ src_id, pack_id, data = caches.first
626
+ from = :caches
627
+ elsif @tun_info[ :wbuffs ].any?
628
+ src_id, pack_id, data = @tun_info[ :wbuffs ].first
629
+ from = :wbuffs
630
+ else
631
+ @writes.delete( tun )
632
+ return
633
+ end
634
+
635
+ src_ext = @tun_info[ :src_exts ][ src_id ]
636
+
637
+ if src_ext
638
+ if pack_id <= CONFUSE_UNTIL
639
+ data = @custom.encode( data )
640
+ # puts "debug1 encoded pack #{ pack_id }"
641
+ end
642
+
643
+ data = [ [ pack_id, src_id ].pack( 'Q>Q>' ), data ].join
644
+
645
+ begin
646
+ tun.sendmsg( data, 0, @tun_info[ :tund_addr ] )
647
+ rescue IO::WaitWritable, Errno::EINTR
648
+ return
649
+ end
650
+
651
+ # puts "debug2 written pack #{ pack_id }"
652
+ now = Time.new
653
+ src_ext[ :relay_pack_id ] = pack_id
654
+ src_ext[ :wmems ][ pack_id ] = data
655
+ src_ext[ :send_ats ][ pack_id ] = now
656
+ src_ext[ :last_continue_at ] = now
657
+ end
658
+
659
+ @tun_info[ from ].shift
660
+ end
661
+
662
+ ##
663
+ # read dotr
664
+ #
665
+ def read_dotr( dotr )
666
+ dotr.read( 1 )
667
+ end
668
+
669
+ ##
670
+ # read sdwd
671
+ #
672
+ def read_sdwd( sdwd )
673
+ begin
674
+ src, addrinfo = sdwd.accept_nonblock
675
+ rescue IO::WaitReadable, Errno::EINTR
676
+ return
677
+ end
678
+
679
+ id = rand( ( 2 ** 64 ) - 1 ) + 1
680
+ # puts "debug1 accept a src #{ addrinfo.inspect } #{ id }"
681
+
682
+ @src_infos[ src ] = {
683
+ id: id, # id
684
+ biggest_pack_id: 0, # 最大包号码
685
+ rbuffs: [], # p1端dst未准备好,暂存流量 [ pack_id, data ]
686
+ wbuff: '', # 写前
687
+ cache: '', # 块读出缓存
688
+ chunks: [], # 块队列,写前达到块大小时结一个块 filename
689
+ spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
690
+ created_at: Time.new, # 创建时间
691
+ last_recv_at: nil, # 上一次收到流量的时间,过期关闭
692
+ is_closing: false # 是否准备关闭
693
+ }
694
+
695
+ add_read( src, :src )
696
+
697
+ if @tun.nil? || @tun.closed?
698
+ new_a_tun
699
+ end
700
+
701
+ src_ext = {
702
+ src: src, # src
703
+ dst_port: nil, # p1端dst端口
704
+ wmems: {}, # 写后 pack_id => data
705
+ send_ats: {}, # 上一次发出时间 pack_id => send_at
706
+ relay_pack_id: 0, # 转发到几
707
+ continue_dst_pack_id: 0, # 收到几
708
+ pieces: {}, # 跳号包 dst_pack_id => data
709
+ is_dst_closed: false, # dst是否已关闭
710
+ biggest_dst_pack_id: 0, # dst最大包号码
711
+ completed_pack_id: 0, # 完成到几(对面收到几)
712
+ last_continue_at: Time.new # 创建,或者上一次收到连续流量,或者发出新包的时间
713
+ }
714
+
715
+ @tun_info[ :src_exts ][ id ] = src_ext
716
+ data = [ 0, A_NEW_SOURCE, id ].pack( 'Q>CQ>' )
717
+ loop_send_a_new_source( src_ext, data )
718
+ end
719
+
720
+ ##
721
+ # read src
722
+ #
723
+ def read_src( src )
724
+ begin
725
+ data = src.read_nonblock( PACK_SIZE )
726
+ rescue IO::WaitReadable, Errno::EINTR
727
+ return
728
+ rescue Exception => e
729
+ # puts "debug1 read src #{ e.class }"
730
+ set_is_closing( src )
731
+ return
732
+ end
733
+
734
+ # puts "debug2 read src #{ data.inspect }"
735
+ src_info = @src_infos[ src ]
736
+ src_info[ :last_recv_at ] = Time.new
737
+ src_id = src_info[ :id ]
738
+ src_ext = @tun_info[ :src_exts ][ src_id ]
739
+
740
+ unless src_ext
741
+ # puts "debug1 not found src ext"
742
+ set_is_closing( src )
743
+ return
744
+ end
745
+
746
+ if @tun.closed?
747
+ puts "#{ Time.new } tun closed, close src"
748
+ set_is_closing( src )
749
+ return
750
+ end
751
+
752
+ pack_id = src_info[ :biggest_pack_id ] + 1
753
+ src_info[ :biggest_pack_id ] = pack_id
754
+
755
+ if src_ext[ :dst_port ]
756
+ add_tun_wbuff( src_info[ :id ], pack_id, data )
757
+ else
758
+ # puts "debug1 p1 dst not ready, save data to src rbuff"
759
+ src_info[ :rbuffs ] << [ pack_id, data ]
760
+ end
761
+ end
762
+
763
+ ##
764
+ # read tun
765
+ #
766
+ def read_tun( tun )
767
+ data, addrinfo, rflags, *controls = tun.recvmsg
768
+ now = Time.new
769
+ pack_id = data[ 0, 8 ].unpack( 'Q>' ).first
770
+
771
+ if pack_id == 0
772
+ ctl_num = data[ 8 ].unpack( 'C' ).first
773
+
774
+ case ctl_num
775
+ when PEER_ADDR
776
+ return if @tun_info[ :peer_addr ] || ( addrinfo.to_sockaddr != @p2pd_addr )
777
+
778
+ peer_addr = data[ 9..-1 ]
779
+ puts "#{ Time.new } got peer addr #{ Addrinfo.new( peer_addr ).inspect }"
780
+
781
+ @tun_info[ :peer_addr ] = peer_addr
782
+ loop_punch_peer
783
+ when HEARTBEAT
784
+ from_addr = addrinfo.to_sockaddr
785
+ return if from_addr != @tun_info[ :peer_addr ]
786
+
787
+ # puts "debug1 set tun addr #{ Addrinfo.new( from_addr ).inspect }"
788
+ @tun_info[ :tund_addr ] = from_addr
789
+ @tun_info[ :last_recv_at ] = now
790
+ when PAIRED
791
+ return unless is_match_tund_addr( addrinfo )
792
+
793
+ src_id, dst_port = data[ 9, 10 ].unpack( 'Q>n' )
794
+
795
+ src_ext = @tun_info[ :src_exts ][ src_id ]
796
+ return if src_ext.nil? || src_ext[ :dst_port ]
797
+
798
+ src = src_ext[ :src ]
799
+ return if src.closed?
800
+
801
+ # puts "debug1 got paired #{ src_id } #{ dst_port }"
802
+
803
+ if dst_port == 0
804
+ set_is_closing( src )
805
+ return
806
+ end
807
+
808
+ src_ext[ :dst_port ] = dst_port
809
+ @tun_info[ :src_ids ][ dst_port ] = src_id
810
+
811
+ src_info = @src_infos[ src ]
812
+
813
+ src_info[ :rbuffs ].each do | _pack_id, _data |
814
+ add_tun_wbuff( src_id, _pack_id, _data )
815
+ end
816
+ when DEST_STATUS
817
+ return unless is_match_tund_addr( addrinfo )
818
+
819
+ dst_port, relay_dst_pack_id, continue_src_pack_id = data[ 9, 18 ].unpack( 'nQ>Q>' )
820
+
821
+ src_id = @tun_info[ :src_ids ][ dst_port ]
822
+ return unless src_id
823
+
824
+ src_ext = @tun_info[ :src_exts ][ src_id ]
825
+ return unless src_ext
826
+
827
+ # puts "debug2 got dest status"
828
+
829
+ release_wmems( src_ext, continue_src_pack_id )
830
+
831
+ # 发miss
832
+ if !src_ext[ :src ].closed? && ( src_ext[ :continue_dst_pack_id ] < relay_dst_pack_id )
833
+ ranges = []
834
+ curr_pack_id = src_ext[ :continue_dst_pack_id ] + 1
835
+
836
+ src_ext[ :pieces ].keys.sort.each do | pack_id |
837
+ if pack_id > curr_pack_id
838
+ ranges << [ curr_pack_id, pack_id - 1 ]
839
+ end
840
+
841
+ curr_pack_id = pack_id + 1
842
+ end
843
+
844
+ if curr_pack_id <= relay_dst_pack_id
845
+ ranges << [ curr_pack_id, relay_dst_pack_id ]
846
+ end
847
+
848
+ pack_count = 0
849
+ # puts "debug1 continue/relay #{ src_ext[ :continue_dst_pack_id ] }/#{ relay_dst_pack_id } send MISS #{ ranges.size }"
850
+
851
+ ranges.each do | pack_id_begin, pack_id_end |
852
+ if pack_count >= BREAK_SEND_MISS
853
+ puts "#{ Time.new } break send miss at #{ pack_id_begin }"
854
+ break
855
+ end
856
+
857
+ data2 = [ 0, MISS, dst_port, pack_id_begin, pack_id_end ].pack( 'Q>CnQ>Q>' )
858
+ add_tun_ctlmsg( data2 )
859
+ pack_count += ( pack_id_end - pack_id_begin + 1 )
860
+ end
861
+ end
862
+ when MISS
863
+ return unless is_match_tund_addr( addrinfo )
864
+
865
+ src_id, pack_id_begin, pack_id_end = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
866
+
867
+ src_ext = @tun_info[ :src_exts ][ src_id ]
868
+ return unless src_ext
869
+
870
+ ( pack_id_begin..pack_id_end ).each do | pack_id |
871
+ send_at = src_ext[ :send_ats ][ pack_id ]
872
+
873
+ if send_at
874
+ break if now - send_at < STATUS_INTERVAL
875
+ @tun_info[ :resendings ] << [ src_id, pack_id ]
876
+ end
877
+ end
878
+
879
+ add_write( tun )
880
+ when FIN1
881
+ return unless is_match_tund_addr( addrinfo )
882
+
883
+ dst_port, biggest_dst_pack_id, continue_src_pack_id = data[ 9, 18 ].unpack( 'nQ>Q>' )
884
+
885
+ src_id = @tun_info[ :src_ids ][ dst_port ]
886
+ return unless src_id
887
+
888
+ src_ext = @tun_info[ :src_exts ][ src_id ]
889
+ return unless src_ext
890
+
891
+ # puts "debug1 got fin1 #{ dst_port } biggest dst pack #{ biggest_dst_pack_id } completed src pack #{ continue_src_pack_id }"
892
+ src_ext[ :is_dst_closed ] = true
893
+ src_ext[ :biggest_dst_pack_id ] = biggest_dst_pack_id
894
+ release_wmems( src_ext, continue_src_pack_id )
895
+
896
+ if ( biggest_dst_pack_id == src_ext[ :continue_dst_pack_id ] )
897
+ # puts "debug1 2-1. tun recv fin1 -> all traffic received ? -> close src after write"
898
+ set_is_closing( src_ext[ :src ] )
899
+ end
900
+ when FIN2
901
+ return unless is_match_tund_addr( addrinfo )
902
+
903
+ dst_port = data[ 9, 2 ].unpack( 'n' ).first
904
+
905
+ src_id = @tun_info[ :src_ids ][ dst_port ]
906
+ return unless src_id
907
+
908
+ # puts "debug1 1-2. tun recv fin2 -> del src ext"
909
+ del_src_ext( src_id )
910
+ when TUND_FIN
911
+ return unless is_match_tund_addr( addrinfo )
912
+
913
+ puts "#{ Time.new } recv tund fin"
914
+ set_is_closing( tun )
915
+ end
916
+
917
+ return
918
+ end
919
+
920
+ return unless is_match_tund_addr( addrinfo )
921
+
922
+ dst_port = data[ 8, 2 ].unpack( 'n' ).first
923
+
924
+ src_id = @tun_info[ :src_ids ][ dst_port ]
925
+ return unless src_id
926
+
927
+ src_ext = @tun_info[ :src_exts ][ src_id ]
928
+ return if src_ext.nil? || src_ext[ :src ].closed?
929
+ return if ( pack_id <= src_ext[ :continue_dst_pack_id ] ) || src_ext[ :pieces ].include?( pack_id )
930
+
931
+ data = data[ 10..-1 ]
932
+ # puts "debug2 got pack #{ pack_id }"
933
+
934
+ if pack_id <= CONFUSE_UNTIL
935
+ # puts "debug2 #{ data.inspect }"
936
+ data = @custom.decode( data )
937
+ # puts "debug1 decoded pack #{ pack_id }"
938
+ end
939
+
940
+ # 放进写前,跳号放碎片缓存
941
+ if pack_id - src_ext[ :continue_dst_pack_id ] == 1
942
+ while src_ext[ :pieces ].include?( pack_id + 1 )
943
+ data << src_ext[ :pieces ].delete( pack_id + 1 )
944
+ pack_id += 1
945
+ end
946
+
947
+ src_ext[ :continue_dst_pack_id ] = pack_id
948
+ src_ext[ :last_continue_at ] = now
949
+ add_src_wbuff( src_ext[ :src ], data )
950
+ # puts "debug2 update continue dst pack #{ pack_id }"
951
+
952
+ # 接到流量,若对面已关闭,且流量正好收全,关闭src
953
+ if src_ext[ :is_dst_closed ] && ( pack_id == src_ext[ :biggest_dst_pack_id ] )
954
+ # puts "debug1 2-2. tun recv traffic -> dst closed and all traffic received ? -> close src after write"
955
+ set_is_closing( src_ext[ :src ] )
956
+ end
957
+ else
958
+ src_ext[ :pieces ][ pack_id ] = data
959
+ end
960
+ end
961
+
962
+ end
963
+ end