p2p2 0.14.0 → 0.18.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,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