p2p2 0.15.1 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ require 'p2p2/custom'
2
+
3
+ module P2p2
4
+ class 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