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