p2p2 0.14.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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