p2p2 0.15.0 → 0.19.0

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