girl 4.0.0 → 4.5.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of girl might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 826fa8949af020a9cf2e9158d0c95630f9ad0495370c22fd058542926e27dd72
4
- data.tar.gz: b880ce49e5c125fb819626d0c124d7cae52b9da59627cfa7f87b6098fbd075c9
3
+ metadata.gz: 2631d53d8c27dfb593364dc65b8d84cfbcad3e27f231c906f1b5ae6ceeea44fd
4
+ data.tar.gz: 6bef34c3cf545b9851038dcd630f62afd5117402ac4955ecadf6bdda3f633e68
5
5
  SHA512:
6
- metadata.gz: a06cb288a4f42d3ad1f73c9e6effe6e3c85ba5485f24940b9a6f36fec254be990b313922273ae28308ef9ef7f9e339797a2b79ed4a4ff8607717da4911edd47e
7
- data.tar.gz: f8c6f735a2553134112885bbb2462d2d1eed44ac7cd1bc4873881644393e7a861cd7345a006b898692ea8036f0d87a81901343658e674b4be23ebe49369facd2
6
+ metadata.gz: 221343c8278bea0f825adee69c7bc392005c637a787e6561004607ce5529105e9ecb5cdfd88d9b6523caff23b05cd0dcf4085d523e873f44c80e37a6360b3947
7
+ data.tar.gz: c1efea95b6fb2d91111abd3d97d36b557a40b6261361209abf39f9a645452afdadf85014ae338229a2b8333efb32c773456c169cc9fc9c015614b9decf8f7cd4
data/girl.gemspec CHANGED
@@ -18,7 +18,6 @@ Gem::Specification.new do |spec|
18
18
  girl.gemspec
19
19
  lib/girl.rb
20
20
  lib/girl/concurrent_hash.rb
21
- lib/girl/custom_dns_query.rb
22
21
  lib/girl/custom.rb
23
22
  lib/girl/head.rb
24
23
  lib/girl/proxy_custom.rb
data/lib/girl/head.rb CHANGED
@@ -1,13 +1,15 @@
1
1
  module Girl
2
- READ_SIZE = 1024 * 1024 # atun, btun一次读多少
2
+ READ_SIZE = 1024 * 1024 # 一次读多少
3
3
  WBUFF_LIMIT = 50 * 1024 * 1024 # 写前上限,超过上限暂停读
4
4
  RESUME_BELOW = WBUFF_LIMIT / 2 # 降到多少以下恢复读
5
+ CHUNK_SIZE = 65535 # 按块加解密,块尺寸上限,不超过65535
5
6
  EXPIRE_NEW = 5 # 多久没有建立通道,过期
7
+ EXPIRE_CONNECTING = 2 # 连接中,多久没连上过期
6
8
  EXPIRE_AFTER = 300 # 多久没有新流量,过期
7
9
  EXPIRE_CTL = 86400 # 多久没有ctlmsg来,过期
8
10
  RESET_TRAFF_DAY = 1 # 流量计数重置日,0为不重置
9
11
  CHECK_TRAFF_INTERVAL = 86400 # 检查今天是否是流量计数重置日间隔
10
- CHECK_EXPIRE_INTERVAL = 5 # 检查过期间隔
12
+ CHECK_EXPIRE_INTERVAL = 1 # 检查过期间隔
11
13
  CHECK_RESUME_INTERVAL = 1 # 检查恢复读间隔
12
14
  RESOLV_CACHE_EXPIRE = 300 # dns查询结果缓存多久过期
13
15
  RESEND_LIMIT = 5 # ctlmsg重传次数
@@ -52,7 +54,9 @@ EOF
52
54
  READ_SIZE
53
55
  WBUFF_LIMIT
54
56
  RESUME_BELOW
57
+ CHUNK_SIZE
55
58
  EXPIRE_NEW
59
+ EXPIRE_CONNECTING
56
60
  EXPIRE_AFTER
57
61
  EXPIRE_CTL
58
62
  RESET_TRAFF_DAY
data/lib/girl/proxy.rb CHANGED
@@ -14,8 +14,8 @@ require 'socket'
14
14
  #
15
15
  =begin
16
16
  C: 1 hello -> hello
17
- 2 tund port -> n: tund port
18
- 3 a new source -> Q>: src id -> encoded destination address
17
+ 2 tund port -> n: atund port -> n: btund port
18
+ 3 a new source -> Q>: src id -> destination
19
19
  4 paired -> Q>: src id -> n: dst id
20
20
  5 dest status NOT USE
21
21
  6 source status NOT USE
@@ -32,13 +32,11 @@ C: 1 hello -> hello
32
32
  17 continue NOT USE
33
33
  18 is resend ready NOT USE
34
34
  19 resend ready NOT USE
35
- 20 resolv -> Q>: src id -> encoded domain
36
- 21 resolved -> Q>: src id -> encoded ip
35
+ 20 resolv NOT USE
36
+ 21 resolved NOT USE
37
37
  22 heartbeat NOT USE
38
38
  23 unknown ctl addr
39
39
  24 ctl fin
40
- 25 source eof -> Q>: dst id
41
- 26 dest eof -> Q>: src id
42
40
  101 traff infos
43
41
  101 traff infos -> [ C: im len -> im -> Q>: traff in -> Q>: traff out ]
44
42
  =end
@@ -6,6 +6,7 @@ module Girl
6
6
  #
7
7
  def initialize( redir_port, proxyd_host, proxyd_port, directs, remotes, im )
8
8
  @proxyd_host = proxyd_host
9
+ @proxyd_port = proxyd_port
9
10
  @proxyd_addr = Socket.sockaddr_in( proxyd_port, proxyd_host )
10
11
  @directs = directs
11
12
  @remotes = remotes
@@ -19,7 +20,7 @@ module Girl
19
20
  @resume_srcs = []
20
21
  @resume_dsts = []
21
22
  @resume_btuns = []
22
- @pending_srcs = [] # 还没配到tund,暂存的src
23
+ @pending_srcs = [] # 还没得到atund和btund地址,暂存的src
23
24
  @roles = ConcurrentHash.new # sock => :dotr / :redir / :ctl / :src / :dst / :atun / :btun
24
25
  @src_infos = ConcurrentHash.new # src => {}
25
26
  @dst_infos = ConcurrentHash.new # dst => {}
@@ -45,7 +46,6 @@ module Girl
45
46
  loop_check_resume
46
47
 
47
48
  loop do
48
- # puts "debug select"
49
49
  rs, ws = IO.select( @reads, @writes )
50
50
 
51
51
  rs.each do | sock |
@@ -295,7 +295,12 @@ module Girl
295
295
  return if atun.closed?
296
296
  # puts "debug close atun"
297
297
  close_sock( atun )
298
- @atun_infos.delete( atun )
298
+ atun_info = @atun_infos.delete( atun )
299
+ src = atun_info[ :src ]
300
+
301
+ if src then
302
+ @paused_srcs.delete( src )
303
+ end
299
304
  end
300
305
 
301
306
  ##
@@ -305,9 +310,7 @@ module Girl
305
310
  return if btun.closed?
306
311
  # puts "debug close btun"
307
312
  close_sock( btun )
308
- @btun_infos.delete( btun )
309
- @paused_btuns.delete( btun )
310
- @resume_btuns.delete( btun )
313
+ del_btun_info( btun )
311
314
  end
312
315
 
313
316
  ##
@@ -378,11 +381,13 @@ module Girl
378
381
  btun = src_info[ :btun ]
379
382
 
380
383
  if atun then
381
- close_atun( atun )
384
+ close_sock( atun )
385
+ @atun_infos.delete( atun )
382
386
  end
383
387
 
384
388
  if btun then
385
- close_btun( btun )
389
+ close_sock( btun )
390
+ del_btun_info( btun )
386
391
  end
387
392
  end
388
393
  end
@@ -426,9 +431,8 @@ module Girl
426
431
  return if src.closed?
427
432
  src_info = @src_infos[ src ]
428
433
 
429
- if ip_info.ipv4_loopback? \
430
- || ip_info.ipv6_loopback? \
431
- || ( ( @ip_address_list.any? { | addrinfo | addrinfo.ip_address == ip_info.ip_address } ) && ( src_info[ :destination_port ] == @redir_port ) ) then
434
+ if ( ( @ip_address_list.any? { | addrinfo | addrinfo.ip_address == ip_info.ip_address } ) && ( src_info[ :destination_port ] == @redir_port ) ) \
435
+ || ( ( ip_info.ip_address == @proxyd_host ) && ( src_info[ :destination_port ] == @proxyd_port ) ) then
432
436
  puts "p#{ Process.pid } #{ Time.new } ignore #{ ip_info.ip_address }:#{ src_info[ :destination_port ] }"
433
437
  add_closing_src( src )
434
438
  return
@@ -445,7 +449,6 @@ module Girl
445
449
  is_direct = @is_direct_caches[ ip_info.ip_address ]
446
450
  else
447
451
  is_direct = @directs.any? { | direct | direct.include?( ip_info.ip_address ) }
448
- # 判断直连耗时较长(树莓派 0.27秒),这里可能切去主线程,回来src可能已关闭
449
452
  puts "p#{ Process.pid } #{ Time.new } cache is direct #{ ip_info.ip_address } #{ is_direct }"
450
453
  @is_direct_caches[ ip_info.ip_address ] = is_direct
451
454
  end
@@ -454,12 +457,20 @@ module Girl
454
457
  # puts "debug #{ ip_info.inspect } hit directs"
455
458
  new_a_dst( src, ip_info )
456
459
  else
457
- # 走远端
458
460
  # puts "debug #{ ip_info.inspect } go tunnel"
459
461
  set_proxy_type_tunnel( src )
460
462
  end
461
463
  end
462
464
 
465
+ ##
466
+ # del btun info
467
+ #
468
+ def del_btun_info( btun )
469
+ @btun_infos.delete( btun )
470
+ @paused_btuns.delete( btun )
471
+ @resume_btuns.delete( btun )
472
+ end
473
+
463
474
  ##
464
475
  # del dst info
465
476
  #
@@ -506,9 +517,24 @@ module Girl
506
517
  @src_infos.each do | src, src_info |
507
518
  last_recv_at = src_info[ :last_recv_at ] || src_info[ :created_at ]
508
519
  last_sent_at = src_info[ :last_sent_at ] || src_info[ :created_at ]
509
- expire_after = ( src_info[ :dst ] || src_info[ :atun ] ) ? EXPIRE_AFTER : EXPIRE_NEW
510
520
 
511
- if ( now - last_recv_at >= expire_after ) && ( now - last_sent_at >= expire_after ) then
521
+ if src_info[ :dst ] then
522
+ if src_info[ :dst_connected ] then
523
+ expire_after = EXPIRE_AFTER
524
+ is_expire = ( now - last_recv_at >= expire_after ) && ( now - last_sent_at >= expire_after )
525
+ else
526
+ expire_after = EXPIRE_CONNECTING
527
+ is_expire = ( now - src_info[ :dst_created_at ] >= expire_after )
528
+ end
529
+ elsif src_info[ :atun ] then
530
+ expire_after = EXPIRE_AFTER
531
+ is_expire = ( now - last_recv_at >= expire_after ) && ( now - last_sent_at >= expire_after )
532
+ else
533
+ expire_after = EXPIRE_NEW
534
+ is_expire = ( now - last_recv_at >= expire_after ) && ( now - last_sent_at >= expire_after )
535
+ end
536
+
537
+ if is_expire then
512
538
  puts "p#{ Process.pid } #{ Time.new } expire src #{ expire_after } #{ src_info[ :id ] } #{ src_info[ :destination_domain ] }"
513
539
  add_closing_src( src )
514
540
 
@@ -534,19 +560,24 @@ module Girl
534
560
  dst = src_info[ :dst ]
535
561
 
536
562
  if dst then
537
- dst_info = @dst_infos[ dst ]
563
+ if !dst.closed? then
564
+ dst_info = @dst_infos[ dst ]
538
565
 
539
- if dst_info[ :wbuff ].size < RESUME_BELOW then
540
- puts "p#{ Process.pid } #{ Time.new } resume direct src #{ src_info[ :destination_domain ] }"
541
- add_resume_src( src )
566
+ if dst_info[ :wbuff ].size < RESUME_BELOW then
567
+ puts "p#{ Process.pid } #{ Time.new } resume direct src #{ src_info[ :destination_domain ] }"
568
+ add_resume_src( src )
569
+ end
542
570
  end
543
571
  else
544
- btun = src_info[ :btun ]
545
- btun_info = @btun_infos[ btun ]
572
+ atun = src_info[ :atun ]
546
573
 
547
- if btun_info[ :wbuff ].size < RESUME_BELOW then
548
- puts "p#{ Process.pid } #{ Time.new } resume tunnel src #{ src_info[ :destination_domain ] }"
549
- add_resume_src( src )
574
+ if atun && !atun.closed? then
575
+ atun_info = @atun_infos[ atun ]
576
+
577
+ if atun_info[ :wbuff ].size < RESUME_BELOW then
578
+ puts "p#{ Process.pid } #{ Time.new } resume tunnel src #{ src_info[ :destination_domain ] }"
579
+ add_resume_src( src )
580
+ end
550
581
  end
551
582
  end
552
583
  end
@@ -554,22 +585,28 @@ module Girl
554
585
  @paused_dsts.each do | dst |
555
586
  dst_info = @dst_infos[ dst ]
556
587
  src = dst_info[ :src ]
557
- src_info = @src_infos[ src ]
558
588
 
559
- if src_info[ :wbuff ].size < RESUME_BELOW then
560
- puts "p#{ Process.pid } #{ Time.new } resume dst #{ dst_info[ :domain ] }"
561
- add_resume_dst( dst )
589
+ if src && !src.closed? then
590
+ src_info = @src_infos[ src ]
591
+
592
+ if src_info[ :wbuff ].size < RESUME_BELOW then
593
+ puts "p#{ Process.pid } #{ Time.new } resume dst #{ dst_info[ :domain ] }"
594
+ add_resume_dst( dst )
595
+ end
562
596
  end
563
597
  end
564
598
 
565
599
  @paused_btuns.each do | btun |
566
600
  btun_info = @btun_infos[ btun ]
567
601
  src = btun_info[ :src ]
568
- src_info = @src_infos[ src ]
569
602
 
570
- if src_info[ :wbuff ].size < RESUME_BELOW then
571
- puts "p#{ Process.pid } #{ Time.new } resume btun #{ btun_info[ :domain ] }"
572
- add_resume_btun( btun )
603
+ if src && !src.closed? then
604
+ src_info = @src_infos[ src ]
605
+
606
+ if src_info[ :wbuff ].size < RESUME_BELOW then
607
+ puts "p#{ Process.pid } #{ Time.new } resume btun #{ btun_info[ :domain ] }"
608
+ add_resume_btun( btun )
609
+ end
573
610
  end
574
611
  end
575
612
  end
@@ -631,9 +668,9 @@ module Girl
631
668
  }
632
669
 
633
670
  @dst_infos[ dst ] = dst_info
634
- add_read( dst, :dst )
635
671
  src_info[ :proxy_type ] = :direct
636
672
  src_info[ :dst ] = dst
673
+ src_info[ :dst_created_at ] = Time.new
637
674
 
638
675
  if src_info[ :proxy_proto ] == :http then
639
676
  if src_info[ :is_connect ] then
@@ -642,11 +679,13 @@ module Girl
642
679
  elsif src_info[ :rbuff ] then
643
680
  # puts "debug move src.rbuff to dst.wbuff"
644
681
  dst_info[ :wbuff ] << src_info[ :rbuff ]
645
- add_write( dst )
646
682
  end
647
683
  elsif src_info[ :proxy_proto ] == :socks5 then
648
684
  add_socks5_conn_reply( src )
649
685
  end
686
+
687
+ add_read( dst, :dst )
688
+ add_write( dst )
650
689
  end
651
690
 
652
691
  ##
@@ -700,6 +739,7 @@ module Girl
700
739
  # new tuns
701
740
  #
702
741
  def new_tuns( src_id, dst_id )
742
+ return if @ctl_info[ :atund_addr ].nil? || @ctl_info[ :btund_addr ].nil?
703
743
  src = @srcs[ src_id ]
704
744
  return if src.nil? || src.closed?
705
745
  src_info = @src_infos[ src ]
@@ -732,7 +772,7 @@ module Girl
732
772
  atun_wbuff = [ dst_id ].pack( 'n' )
733
773
 
734
774
  until src_info[ :rbuff ].empty? do
735
- data = src_info[ :rbuff ][ 0, 65535 ]
775
+ data = src_info[ :rbuff ][ 0, CHUNK_SIZE ]
736
776
  data_size = data.bytesize
737
777
  # puts "debug move src.rbuff #{ data_size } to atun.wbuff"
738
778
  atun_wbuff << pack_a_chunk( data )
@@ -753,7 +793,8 @@ module Girl
753
793
  domain: domain, # 目的地
754
794
  wbuff: btun_wbuff, # 写前
755
795
  rbuff: '', # 暂存当前块没收全的流量
756
- wait_bytes: 0 # 还差多少字节收全当前块
796
+ wait_bytes: 0, # 还差多少字节收全当前块
797
+ lbuff: '' # 流量截断在长度前缀处
757
798
  }
758
799
 
759
800
  src_info[ :dst_id ] = dst_id
@@ -785,7 +826,6 @@ module Girl
785
826
  # pack a chunk
786
827
  #
787
828
  def pack_a_chunk( data )
788
- # puts "debug pack a chunk"
789
829
  data = @custom.encode( data )
790
830
  "#{ [ data.bytesize ].pack( 'n' ) }#{ data }"
791
831
  end
@@ -840,6 +880,7 @@ module Girl
840
880
  #
841
881
  def send_ctlmsg( data )
842
882
  return if @ctl.nil? || @ctl.closed?
883
+ data = @custom.encode( data )
843
884
 
844
885
  begin
845
886
  @ctl.sendmsg( data, 0, @proxyd_addr )
@@ -901,30 +942,11 @@ module Girl
901
942
  add_write( src )
902
943
  end
903
944
 
904
- ##
905
- # sub http request
906
- #
907
- def sub_http_request( data )
908
- lines = data.split( "\r\n" )
909
-
910
- return [ data, nil ] if lines.empty?
911
-
912
- method, url, proto = lines.first.split( ' ' )
913
-
914
- if proto && url && proto[ 0, 4 ] == 'HTTP' && url[ 0, 7 ] == 'http://' then
915
- domain_port = url.split( '/' )[ 2 ]
916
- data = data.sub( "http://#{ domain_port }", '' )
917
- # puts "debug subed #{ data.inspect } #{ domain_port }"
918
- end
919
-
920
- [ data, domain_port ]
921
- end
922
-
923
945
  ##
924
946
  # read dotr
925
947
  #
926
948
  def read_dotr( dotr )
927
- dotr.read_nonblock( 65535 )
949
+ dotr.read_nonblock( READ_SIZE )
928
950
 
929
951
  if @ctl_info && @ctl_info[ :closing ] then
930
952
  send_ctlmsg( [ CTL_FIN ].pack( 'C' ) )
@@ -988,6 +1010,8 @@ module Girl
988
1010
  is_connect: true, # 代理协议是http的场合,是否是CONNECT
989
1011
  rbuff: '', # 读到的流量
990
1012
  dst: nil, # :direct的场合,对应的dst
1013
+ dst_created_at: nil, # :direct的场合,对应的dst的创建时间
1014
+ dst_connected: false, # :direct的场合,对应的dst是否已连接
991
1015
  ctl: nil, # :tunnel的场合,对应的ctl
992
1016
  atun: nil, # :tunnel的场合,对应的atun
993
1017
  btun: nil, # :tunnel的场合,对应的btun
@@ -1018,6 +1042,7 @@ module Girl
1018
1042
  return
1019
1043
  end
1020
1044
 
1045
+ data = @custom.decode( data )
1021
1046
  ctl_num = data[ 0 ].unpack( 'C' ).first
1022
1047
 
1023
1048
  case ctl_num
@@ -1036,7 +1061,7 @@ module Girl
1036
1061
  @pending_srcs.clear
1037
1062
  end
1038
1063
  when PAIRED then
1039
- return if @ctl_info[ :atund_addr ].nil? || @ctl_info[ :btund_addr ].nil? || data.size != 11
1064
+ return if data.size != 11
1040
1065
  src_id, dst_id = data[ 1, 10 ].unpack( 'Q>n' )
1041
1066
  # puts "debug got paired #{ src_id } #{ dst_id }"
1042
1067
  @ctl_info[ :resends ].delete( [ A_NEW_SOURCE, src_id ].pack( 'CQ>' ) )
@@ -1060,7 +1085,7 @@ module Girl
1060
1085
  src_info = @src_infos[ src ]
1061
1086
 
1062
1087
  begin
1063
- data = src.read_nonblock( 65535 )
1088
+ data = src.read_nonblock( CHUNK_SIZE )
1064
1089
  rescue IO::WaitReadable
1065
1090
  print 'r'
1066
1091
  return
@@ -1135,7 +1160,16 @@ module Girl
1135
1160
  return
1136
1161
  end
1137
1162
 
1138
- data, domain_port = sub_http_request( data )
1163
+ lines = data.split( "\r\n" )
1164
+
1165
+ unless lines.empty? then
1166
+ method, url, proto = lines.first.split( ' ' )
1167
+
1168
+ if proto && url && proto[ 0, 4 ] == 'HTTP' && url[ 0, 7 ] == 'http://' then
1169
+ domain_port = url.split( '/' )[ 2 ]
1170
+ # puts "debug domain port #{ domain_port }"
1171
+ end
1172
+ end
1139
1173
 
1140
1174
  unless domain_port then
1141
1175
  # puts "debug not HTTP"
@@ -1202,10 +1236,6 @@ module Girl
1202
1236
  when :tunnel then
1203
1237
  atun = src_info[ :atun ]
1204
1238
 
1205
- if atun && !src_info[ :is_connect ] then
1206
- data, _ = sub_http_request( data )
1207
- end
1208
-
1209
1239
  if atun then
1210
1240
  add_atun_wbuff( atun, pack_a_chunk( data ) )
1211
1241
  else
@@ -1216,10 +1246,6 @@ module Girl
1216
1246
  dst = src_info[ :dst ]
1217
1247
 
1218
1248
  if dst then
1219
- unless src_info[ :is_connect ] then
1220
- data, _ = sub_http_request( data )
1221
- end
1222
-
1223
1249
  add_dst_wbuff( dst, data )
1224
1250
  else
1225
1251
  # puts "debug add src.rbuff #{ data.bytesize }"
@@ -1241,7 +1267,7 @@ module Girl
1241
1267
  src = dst_info[ :src ]
1242
1268
 
1243
1269
  begin
1244
- data = dst.read_nonblock( 65535 )
1270
+ data = dst.read_nonblock( CHUNK_SIZE )
1245
1271
  rescue IO::WaitReadable
1246
1272
  print 'r'
1247
1273
  return
@@ -1282,22 +1308,44 @@ module Girl
1282
1308
  end
1283
1309
 
1284
1310
  until data.empty? do
1285
- rbuff = btun_info[ :rbuff ]
1286
1311
  wait_bytes = btun_info[ :wait_bytes ]
1287
1312
 
1288
1313
  if wait_bytes > 0 then
1289
1314
  len = wait_bytes
1290
1315
  # puts "debug wait bytes #{ len }"
1291
1316
  else
1292
- if data.bytesize <= 2 then
1293
- # puts "debug unexpect data length #{ data.bytesize }"
1294
- close_btun( btun )
1295
- return
1296
- end
1317
+ lbuff = btun_info[ :lbuff ]
1318
+
1319
+ if lbuff.empty? then
1320
+ # 长度缓存为空,从读到的流量里取长度
1321
+ # 两个字节以下,记进长度缓存
1322
+ if data.bytesize <= 2 then
1323
+ # puts "debug set btun.lbuff #{ data.inspect }"
1324
+ btun_info[ :lbuff ] = data
1325
+ return
1326
+ end
1327
+
1328
+ len = data[ 0, 2 ].unpack( 'n' ).first
1329
+ data = data[ 2..-1 ]
1330
+ elsif lbuff.bytesize == 1 then
1331
+ # 长度缓存记有一个字节,补一个字节
1332
+ lbuff = "#{ lbuff }#{ data[ 0 ] }"
1333
+
1334
+ if data.bytesize == 1 then
1335
+ # puts "debug add btun.lbuff a byte #{ data.inspect }"
1336
+ btun_info[ :lbuff ] = lbuff
1337
+ return
1338
+ end
1297
1339
 
1298
- len = data[ 0, 2 ].unpack( 'n' ).first
1299
- # puts "debug read len #{ len }"
1300
- data = data[ 2..-1 ]
1340
+ # 使用长度缓存
1341
+ len = lbuff.unpack( 'n' ).first
1342
+ btun_info[ :lbuff ].clear
1343
+ data = data[ 1..-1 ]
1344
+ else
1345
+ # 使用长度缓存
1346
+ len = lbuff.unpack( 'n' ).first
1347
+ btun_info[ :lbuff ].clear
1348
+ end
1301
1349
  end
1302
1350
 
1303
1351
  chunk = data[ 0, len ]
@@ -1305,7 +1353,7 @@ module Girl
1305
1353
 
1306
1354
  if chunk_size == len then
1307
1355
  # 取完整了
1308
- chunk = @custom.decode( "#{ rbuff }#{ chunk }" )
1356
+ chunk = @custom.decode( "#{ btun_info[ :rbuff ] }#{ chunk }" )
1309
1357
  # puts "debug decode and add src.wbuff #{ chunk.bytesize }"
1310
1358
  add_src_wbuff( src, chunk )
1311
1359
  btun_info[ :rbuff ].clear
@@ -1384,6 +1432,12 @@ module Girl
1384
1432
 
1385
1433
  dst_info = @dst_infos[ dst ]
1386
1434
  src = dst_info[ :src ]
1435
+ src_info = @src_infos[ src ]
1436
+
1437
+ unless src.closed? then
1438
+ src_info[ :dst_connected ] = true
1439
+ end
1440
+
1387
1441
  data = dst_info[ :wbuff ]
1388
1442
 
1389
1443
  # 写前为空,处理关闭写
@@ -1414,7 +1468,6 @@ module Girl
1414
1468
  dst_info[ :wbuff ] = data
1415
1469
 
1416
1470
  unless src.closed? then
1417
- src_info = @src_infos[ src ]
1418
1471
  src_info[ :last_sent_at ] = Time.new
1419
1472
  end
1420
1473
  end