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