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