p2p2 0.15.1 → 0.20.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ require 'p2p2/custom'
2
+
3
+ module P2p2
4
+ class 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_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 :dst
42
+ write_dst( sock )
43
+ when :tund
44
+ write_tund( sock )
45
+ end
46
+ end
47
+
48
+ rs.each do | sock |
49
+ case @roles[ sock ]
50
+ when :dotr
51
+ read_dotr( sock )
52
+ when :dst
53
+ read_dst( sock )
54
+ when :tund
55
+ read_tund( sock )
56
+ end
57
+ end
58
+ end
59
+ end
60
+ rescue Interrupt => e
61
+ puts e.class
62
+ quit!
63
+ end
64
+
65
+ ##
66
+ # quit!
67
+ #
68
+ def quit!
69
+ if !@tund.closed? && @tund_info[ :tun_addr ]
70
+ # puts "debug1 send tund fin"
71
+ data = [ 0, TUND_FIN ].pack( 'Q>C' )
72
+ @tund.sendmsg( data, 0, @tund_info[ :tun_addr ] )
73
+ end
74
+
75
+ # puts "debug1 exit"
76
+ exit
77
+ end
78
+
79
+ private
80
+
81
+ ##
82
+ # loop heartbeat
83
+ #
84
+ def loop_heartbeat( check_at = Time.new )
85
+ Thread.new do
86
+ loop do
87
+ sleep HEARTBEAT_INTERVAL
88
+
89
+ @mutex.synchronize do
90
+ now = Time.new
91
+
92
+ unless @tund.closed?
93
+ if @tund_info[ :peer_addr ]
94
+ if @tund_info[ :tun_addr ]
95
+ if now - check_at >= CHECK_EXPIRE_INTERVAL
96
+ if now - @tund_info[ :last_recv_at ] > EXPIRE_AFTER
97
+ puts "#{ Time.new } expire tund"
98
+ set_is_closing( @tund )
99
+ else
100
+ @tund_info[ :dst_exts ].each do | dst_local_port, dst_ext |
101
+ if dst_ext[ :dst ].closed? && ( now - dst_ext[ :last_continue_at ] > EXPIRE_AFTER )
102
+ puts "#{ Time.new } expire dst ext #{ dst_local_port }"
103
+ del_dst_ext( dst_local_port )
104
+ end
105
+ end
106
+ end
107
+
108
+ @dst_infos.each do | dst, dst_info |
109
+ if dst_info[ :last_recv_at ].nil? && ( now - dst_info[ :created_at ] > EXPIRE_NEW )
110
+ puts "#{ Time.new } expire dst"
111
+ set_is_closing( dst )
112
+ end
113
+ end
114
+
115
+ check_at = now
116
+ end
117
+
118
+ # puts "debug2 heartbeat"
119
+ add_tund_ctlmsg( pack_a_heartbeat )
120
+ next_tick
121
+ elsif now - @tund_info[ :last_recv_at ] > EXPIRE_NEW
122
+ # no tun addr
123
+ puts "#{ Time.new } expire new tund"
124
+ set_is_closing( @tund )
125
+ next_tick
126
+ end
127
+ else
128
+ # no peer addr
129
+ if now - check_at >= UPDATE_ROOM_INTERVAL
130
+ data = @room
131
+ check_at = now
132
+ else
133
+ data = [ rand( 128 ) ].pack( 'C' )
134
+ end
135
+
136
+ # puts "debug2 update room"
137
+ add_tund_ctlmsg( data, @p2pd_addr )
138
+ next_tick
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
145
+
146
+ ##
147
+ # loop check status
148
+ #
149
+ def loop_check_status
150
+ Thread.new do
151
+ loop do
152
+ sleep STATUS_INTERVAL
153
+
154
+ @mutex.synchronize do
155
+ if !@tund.closed? && @tund_info[ :tun_addr ]
156
+ need_trigger = false
157
+
158
+ if @tund_info[ :dst_exts ].any?
159
+ now = Time.new
160
+
161
+ @tund_info[ :dst_exts ].each do | dst_local_port, dst_ext |
162
+ if now - dst_ext[ :last_continue_at ] < SEND_STATUS_UNTIL
163
+ data = [ 0, DEST_STATUS, dst_local_port, dst_ext[ :relay_pack_id ], dst_ext[ :continue_src_pack_id ] ].pack( 'Q>CnQ>Q>' )
164
+ add_tund_ctlmsg( data )
165
+ need_trigger = true
166
+ end
167
+ end
168
+ end
169
+
170
+ if @tund_info[ :paused ] && ( @tund_info[ :dst_exts ].map{ | _, dst_ext | dst_ext[ :wmems ].size }.sum < RESUME_BELOW )
171
+ puts "#{ Time.new } resume tund"
172
+ @tund_info[ :paused ] = false
173
+ add_write( @tund )
174
+ need_trigger = true
175
+ end
176
+
177
+ if need_trigger
178
+ next_tick
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end
184
+ end
185
+
186
+ ##
187
+ # loop punch peer
188
+ #
189
+ def loop_punch_peer
190
+ Thread.new do
191
+ EXPIRE_NEW.times do
192
+ if @tund.closed?
193
+ # puts "debug1 break loop punch peer"
194
+ break
195
+ end
196
+
197
+ @mutex.synchronize do
198
+ # puts "debug1 punch peer"
199
+ add_tund_ctlmsg( pack_a_heartbeat, @tund_info[ :peer_addr ] )
200
+ next_tick
201
+ end
202
+
203
+ sleep 1
204
+ end
205
+ end
206
+ end
207
+
208
+ ##
209
+ # new a tund
210
+ #
211
+ def new_a_tund
212
+ tund = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
213
+ tund.bind( Socket.sockaddr_in( 0, '0.0.0.0' ) )
214
+ port = tund.local_address.ip_port
215
+ puts "#{ Time.new } tund bind on #{ port }"
216
+
217
+ tund_info = {
218
+ port: port, # 端口
219
+ ctlmsgs: [], # [ to_addr, data ]
220
+ wbuffs: [], # 写前缓存 [ dst_local_port, pack_id, data ]
221
+ caches: [], # 块读出缓存 [ dst_local_port, pack_id, data ]
222
+ chunks: [], # 块队列 filename
223
+ spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
224
+ peer_addr: nil, # 对面地址
225
+ tun_addr: nil, # 连通后的tun地址
226
+ dst_exts: {}, # dst额外信息 dst_local_port => {}
227
+ dst_local_ports: {}, # src_id => dst_local_port
228
+ paused: false, # 是否暂停写
229
+ resendings: [], # 重传队列 [ dst_local_port, pack_id ]
230
+ created_at: Time.new, # 创建时间
231
+ last_recv_at: nil, # 上一次收到流量的时间,过期关闭
232
+ is_closing: false # 是否准备关闭
233
+ }
234
+
235
+ @tund = tund
236
+ @tund_info = tund_info
237
+ add_read( tund, :tund )
238
+ add_tund_ctlmsg( @room, @p2pd_addr )
239
+ end
240
+
241
+ ##
242
+ # pack a heartbeat
243
+ #
244
+ def pack_a_heartbeat
245
+ [ 0, HEARTBEAT, rand( 128 ) ].pack( 'Q>CC' )
246
+ end
247
+
248
+ ##
249
+ # is match tun addr
250
+ #
251
+ def is_match_tun_addr( addrinfo )
252
+ return false unless @tund_info[ :tun_addr ]
253
+
254
+ from_addr = addrinfo.to_sockaddr
255
+
256
+ if from_addr != @tund_info[ :tun_addr ]
257
+ puts "#{ Time.new } #{ addrinfo.inspect } not match #{ Addrinfo.new( @tund_info[ :tun_addr ] ).inspect }"
258
+ return false
259
+ end
260
+
261
+ @tund_info[ :last_recv_at ] = Time.new
262
+
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