p2p2 0.15.1 → 0.20.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,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