girl 4.8.0 → 4.9.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 +4 -4
- data/girl.gemspec +0 -2
- data/lib/girl/head.rb +1 -0
- data/lib/girl/proxy_worker.rb +24 -4
- data/lib/girl/proxyd_worker.rb +7 -1
- data/lib/girl/relay_worker.rb +9 -2
- data/lib/girl/resolvd_worker.rb +5 -5
- data/lib/girl/version.rb +1 -1
- metadata +2 -4
- data/lib/girl/ssl.rb +0 -79
- data/lib/girl/ssl_worker.rb +0 -874
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 011aa472a00bf6cb2d5c73af7f5a9f685897bcafa782cb5080c53f830775738a
|
4
|
+
data.tar.gz: 05a8c74a0a96a65f77432c2b64fe384283ed0a15178f4e09f820ce1b2d82f706
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 10e71a4842eb5ab95edb29411607502e073ae0c7f7f371163d42d9ac85dcb5fcda39363c572ddef67565e6eefa17706f836bec0eb48c16f31422d34838691277
|
7
|
+
data.tar.gz: facd9596a3518f80d587e436cbbb8fe76da4f7be6657b75d40cf076b11fa4f92c8ea0cb1fde9d8c0a496c3e8667d231a29e47da0ae463cf2a2d06e53ef8f1c07
|
data/girl.gemspec
CHANGED
data/lib/girl/head.rb
CHANGED
data/lib/girl/proxy_worker.rb
CHANGED
@@ -644,13 +644,20 @@ module Girl
|
|
644
644
|
src_info = @src_infos[ src ]
|
645
645
|
domain = src_info[ :destination_domain ]
|
646
646
|
destination_addr = Socket.sockaddr_in( src_info[ :destination_port ], ip_info.ip_address )
|
647
|
-
|
647
|
+
|
648
|
+
begin
|
649
|
+
dst = Socket.new( ip_info.ipv4? ? Socket::AF_INET : Socket::AF_INET6, Socket::SOCK_STREAM, 0 )
|
650
|
+
rescue Exception => e
|
651
|
+
puts "p#{ Process.pid } #{ Time.new } new a dst #{ src_info[ :destination_domain ] } #{ src_info[ :destination_port ] } #{ e.class }"
|
652
|
+
add_closing_src( src )
|
653
|
+
return
|
654
|
+
end
|
655
|
+
|
648
656
|
dst.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1 )
|
649
657
|
|
650
658
|
begin
|
651
659
|
dst.connect_nonblock( destination_addr )
|
652
660
|
rescue IO::WaitWritable
|
653
|
-
# connect nonblock 必抛 wait writable
|
654
661
|
rescue Exception => e
|
655
662
|
puts "p#{ Process.pid } #{ Time.new } dst connect destination #{ domain } #{ src_info[ :destination_port ] } #{ ip_info.ip_address } #{ e.class }"
|
656
663
|
dst.close
|
@@ -1200,9 +1207,18 @@ module Girl
|
|
1200
1207
|
src_info[ :rbuff ] << data
|
1201
1208
|
end
|
1202
1209
|
|
1203
|
-
|
1204
|
-
|
1210
|
+
colon_idx = domain_port.rindex( ':' )
|
1211
|
+
close_idx = domain_port.rindex( ']' )
|
1205
1212
|
|
1213
|
+
if colon_idx && ( close_idx.nil? || ( colon_idx > close_idx ) ) then
|
1214
|
+
domain = domain_port[ 0...colon_idx ]
|
1215
|
+
port = domain_port[ ( colon_idx + 1 )..-1 ].to_i
|
1216
|
+
else
|
1217
|
+
domain = domain_port
|
1218
|
+
port = 80
|
1219
|
+
end
|
1220
|
+
|
1221
|
+
domain = domain.gsub( /\[|\]/, '' )
|
1206
1222
|
src_info[ :proxy_proto ] = :http
|
1207
1223
|
src_info[ :destination_domain ] = domain
|
1208
1224
|
src_info[ :destination_port ] = port
|
@@ -1243,9 +1259,13 @@ module Girl
|
|
1243
1259
|
# puts "debug DOMAINNAME #{ domain } #{ port }"
|
1244
1260
|
resolve_domain( src, domain )
|
1245
1261
|
end
|
1262
|
+
else
|
1263
|
+
puts "p#{ Process.pid } #{ Time.new } socks5 atyp #{ atyp } not implement"
|
1264
|
+
add_closing_src( src )
|
1246
1265
|
end
|
1247
1266
|
else
|
1248
1267
|
puts "p#{ Process.pid } #{ Time.new } socks5 cmd #{ cmd } not implement"
|
1268
|
+
add_closing_src( src )
|
1249
1269
|
end
|
1250
1270
|
when :tunnel then
|
1251
1271
|
atun = src_info[ :atun ]
|
data/lib/girl/proxyd_worker.rb
CHANGED
@@ -305,7 +305,13 @@ module Girl
|
|
305
305
|
# deal with destination addr
|
306
306
|
#
|
307
307
|
def deal_with_destination_addr( ctl_addr, src_id, destination_addr, domain_port )
|
308
|
-
|
308
|
+
begin
|
309
|
+
dst = Socket.new( Addrinfo.new( destination_addr ).ipv4? ? Socket::AF_INET : Socket::AF_INET6, Socket::SOCK_STREAM, 0 )
|
310
|
+
rescue Exception => e
|
311
|
+
puts "p#{ Process.pid } #{ Time.new } new a dst #{ destination_addr.inspect } #{ domain_port } #{ e.class }"
|
312
|
+
return
|
313
|
+
end
|
314
|
+
|
309
315
|
dst.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1 )
|
310
316
|
|
311
317
|
begin
|
data/lib/girl/relay_worker.rb
CHANGED
@@ -665,13 +665,20 @@ module Girl
|
|
665
665
|
src_info = @src_infos[ src ]
|
666
666
|
domain = src_info[ :destination_domain ]
|
667
667
|
destination_addr = Socket.sockaddr_in( src_info[ :destination_port ], ip_info.ip_address )
|
668
|
-
|
668
|
+
|
669
|
+
begin
|
670
|
+
dst = Socket.new( ip_info.ipv4? ? Socket::AF_INET : Socket::AF_INET6, Socket::SOCK_STREAM, 0 )
|
671
|
+
rescue Exception => e
|
672
|
+
puts "p#{ Process.pid } #{ Time.new } new a dst #{ src_info[ :destination_domain ] } #{ src_info[ :destination_port ] } #{ e.class }"
|
673
|
+
add_closing_src( src )
|
674
|
+
return
|
675
|
+
end
|
676
|
+
|
669
677
|
dst.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1 )
|
670
678
|
|
671
679
|
begin
|
672
680
|
dst.connect_nonblock( destination_addr )
|
673
681
|
rescue IO::WaitWritable
|
674
|
-
# connect nonblock 必抛 wait writable
|
675
682
|
rescue Exception => e
|
676
683
|
puts "p#{ Process.pid } #{ Time.new } dst connect destination #{ domain } #{ src_info[ :destination_port ] } #{ ip_info.ip_address } #{ e.class }"
|
677
684
|
dst.close
|
data/lib/girl/resolvd_worker.rb
CHANGED
@@ -49,7 +49,7 @@ module Girl
|
|
49
49
|
# quit!
|
50
50
|
#
|
51
51
|
def quit!
|
52
|
-
# puts "
|
52
|
+
# puts "debug exit"
|
53
53
|
exit
|
54
54
|
end
|
55
55
|
|
@@ -82,7 +82,7 @@ module Girl
|
|
82
82
|
# close dst
|
83
83
|
#
|
84
84
|
def close_dst( dst )
|
85
|
-
# puts "
|
85
|
+
# puts "debug close dst"
|
86
86
|
dst.close
|
87
87
|
@reads.delete( dst )
|
88
88
|
@roles.delete( dst )
|
@@ -116,7 +116,7 @@ module Girl
|
|
116
116
|
dst.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 )
|
117
117
|
dst.bind( Socket.sockaddr_in( 0, '0.0.0.0' ) )
|
118
118
|
|
119
|
-
puts "
|
119
|
+
# puts "debug new a dst"
|
120
120
|
@dst_infos[ dst ] = {
|
121
121
|
resolvd: resolvd,
|
122
122
|
src_addr: src_addr,
|
@@ -178,7 +178,7 @@ module Girl
|
|
178
178
|
#
|
179
179
|
def read_resolvd( resolvd )
|
180
180
|
data, addrinfo, rflags, *controls = resolvd.recvmsg
|
181
|
-
# puts "
|
181
|
+
# puts "debug resolvd recvmsg #{ addrinfo.ip_unpack.inspect } #{ data.inspect }"
|
182
182
|
data = @custom.decode( data )
|
183
183
|
new_a_dst( resolvd, addrinfo.to_sockaddr, data )
|
184
184
|
end
|
@@ -188,7 +188,7 @@ module Girl
|
|
188
188
|
#
|
189
189
|
def read_dst( dst )
|
190
190
|
data, addrinfo, rflags, *controls = dst.recvmsg
|
191
|
-
# puts "
|
191
|
+
# puts "debug dst recvmsg #{ addrinfo.ip_unpack.inspect } #{ data.inspect }"
|
192
192
|
dst_info = @dst_infos[ dst ]
|
193
193
|
data = @custom.encode( data )
|
194
194
|
send_data( dst_info[ :resolvd ], dst_info[ :src_addr ], data )
|
data/lib/girl/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: girl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- takafan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-05-07 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: escape evil.
|
14
14
|
email:
|
@@ -33,8 +33,6 @@ files:
|
|
33
33
|
- lib/girl/resolv_custom.rb
|
34
34
|
- lib/girl/resolvd.rb
|
35
35
|
- lib/girl/resolvd_worker.rb
|
36
|
-
- lib/girl/ssl.rb
|
37
|
-
- lib/girl/ssl_worker.rb
|
38
36
|
- lib/girl/version.rb
|
39
37
|
homepage: https://github.com/takafan/girl
|
40
38
|
licenses:
|
data/lib/girl/ssl.rb
DELETED
@@ -1,79 +0,0 @@
|
|
1
|
-
require 'etc'
|
2
|
-
require 'girl/concurrent_hash'
|
3
|
-
require 'girl/head'
|
4
|
-
require 'girl/ssl_worker'
|
5
|
-
require 'girl/version'
|
6
|
-
require 'json'
|
7
|
-
require 'openssl'
|
8
|
-
require 'socket'
|
9
|
-
|
10
|
-
##
|
11
|
-
# Girl::Ssl
|
12
|
-
#
|
13
|
-
module Girl
|
14
|
-
class Ssl
|
15
|
-
|
16
|
-
def initialize( config_path = nil )
|
17
|
-
unless config_path then
|
18
|
-
config_path = File.expand_path( '../girl.conf.json', __FILE__ )
|
19
|
-
end
|
20
|
-
|
21
|
-
raise "missing config file #{ config_path }" unless File.exist?( config_path )
|
22
|
-
|
23
|
-
conf = JSON.parse( IO.binread( config_path ), symbolize_names: true )
|
24
|
-
redir_port = conf[ :ssl_port ]
|
25
|
-
worker_count = conf[ :worker_count ]
|
26
|
-
|
27
|
-
unless redir_port then
|
28
|
-
redir_port = 1080
|
29
|
-
end
|
30
|
-
|
31
|
-
nprocessors = Etc.nprocessors
|
32
|
-
|
33
|
-
if worker_count.nil? || worker_count <= 0 || worker_count > nprocessors then
|
34
|
-
worker_count = nprocessors
|
35
|
-
end
|
36
|
-
|
37
|
-
len = CONSTS.map{ | name | name.size }.max
|
38
|
-
|
39
|
-
CONSTS.each do | name |
|
40
|
-
puts "#{ name.gsub( '_', ' ' ).ljust( len ) } #{ Girl.const_get( name ) }"
|
41
|
-
end
|
42
|
-
|
43
|
-
title = "girl ssl #{ Girl::VERSION }"
|
44
|
-
puts title
|
45
|
-
puts "redir port #{ redir_port } worker count #{ worker_count }"
|
46
|
-
|
47
|
-
$0 = title
|
48
|
-
workers = []
|
49
|
-
|
50
|
-
worker_count.times do | i |
|
51
|
-
workers << fork do
|
52
|
-
$0 = 'girl ssl worker'
|
53
|
-
worker = Girl::SslWorker.new( redir_port )
|
54
|
-
|
55
|
-
Signal.trap( :TERM ) do
|
56
|
-
puts "w#{ i } exit"
|
57
|
-
worker.quit!
|
58
|
-
end
|
59
|
-
|
60
|
-
worker.looping
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
Signal.trap( :TERM ) do
|
65
|
-
puts 'trap TERM'
|
66
|
-
workers.each do | pid |
|
67
|
-
begin
|
68
|
-
Process.kill( :TERM, pid )
|
69
|
-
rescue Errno::ESRCH => e
|
70
|
-
puts e.class
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
Process.waitall
|
76
|
-
end
|
77
|
-
|
78
|
-
end
|
79
|
-
end
|
data/lib/girl/ssl_worker.rb
DELETED
@@ -1,874 +0,0 @@
|
|
1
|
-
module Girl
|
2
|
-
class SslWorker
|
3
|
-
|
4
|
-
##
|
5
|
-
# initialize
|
6
|
-
#
|
7
|
-
def initialize( redir_port )
|
8
|
-
@redir_port = redir_port
|
9
|
-
@reads = []
|
10
|
-
@writes = []
|
11
|
-
@closing_srcs = []
|
12
|
-
@paused_srcs = []
|
13
|
-
@paused_dsts = []
|
14
|
-
@resume_srcs = []
|
15
|
-
@resume_dsts = []
|
16
|
-
@roles = ConcurrentHash.new # sock => :dotr / :redir / :src / :dst
|
17
|
-
@src_infos = ConcurrentHash.new # src => {}
|
18
|
-
@dst_infos = ConcurrentHash.new # dst => {}
|
19
|
-
@resolv_caches = ConcurrentHash.new # domain => [ ip, created_at ]
|
20
|
-
|
21
|
-
dotr, dotw = IO.pipe
|
22
|
-
@dotw = dotw
|
23
|
-
add_read( dotr, :dotr )
|
24
|
-
new_a_redir
|
25
|
-
end
|
26
|
-
|
27
|
-
##
|
28
|
-
# looping
|
29
|
-
#
|
30
|
-
def looping
|
31
|
-
puts "p#{ Process.pid } #{ Time.new } looping"
|
32
|
-
loop_check_expire
|
33
|
-
loop_check_resume
|
34
|
-
|
35
|
-
loop do
|
36
|
-
rs, ws = IO.select( @reads, @writes )
|
37
|
-
|
38
|
-
rs.each do | sock |
|
39
|
-
case @roles[ sock ]
|
40
|
-
when :dotr then
|
41
|
-
read_dotr( sock )
|
42
|
-
when :redir then
|
43
|
-
read_redir( sock )
|
44
|
-
when :src then
|
45
|
-
read_src( sock )
|
46
|
-
when :dst then
|
47
|
-
read_dst( sock )
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
ws.each do | sock |
|
52
|
-
case @roles[ sock ]
|
53
|
-
when :src then
|
54
|
-
write_src( sock )
|
55
|
-
when :dst then
|
56
|
-
write_dst( sock )
|
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
|
-
# puts "debug exit"
|
70
|
-
exit
|
71
|
-
end
|
72
|
-
|
73
|
-
private
|
74
|
-
|
75
|
-
##
|
76
|
-
# add closing src
|
77
|
-
#
|
78
|
-
def add_closing_src( src )
|
79
|
-
return if src.closed? || @closing_srcs.include?( src )
|
80
|
-
@closing_srcs << src
|
81
|
-
next_tick
|
82
|
-
end
|
83
|
-
|
84
|
-
##
|
85
|
-
# add dst wbuff
|
86
|
-
#
|
87
|
-
def add_dst_wbuff( dst, data )
|
88
|
-
return if dst.closed?
|
89
|
-
dst_info = @dst_infos[ dst ]
|
90
|
-
dst_info[ :wbuff ] << data
|
91
|
-
add_write( dst )
|
92
|
-
|
93
|
-
if dst_info[ :wbuff ].bytesize >= WBUFF_LIMIT then
|
94
|
-
puts "p#{ Process.pid } #{ Time.new } pause direct src #{ dst_info[ :domain ] }"
|
95
|
-
add_paused_src( dst_info[ :src ] )
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
##
|
100
|
-
# add paused dst
|
101
|
-
#
|
102
|
-
def add_paused_dst( dst )
|
103
|
-
return if dst.closed? || @paused_dsts.include?( dst )
|
104
|
-
@reads.delete( dst )
|
105
|
-
@paused_dsts << dst
|
106
|
-
end
|
107
|
-
|
108
|
-
##
|
109
|
-
# add paused src
|
110
|
-
#
|
111
|
-
def add_paused_src( src )
|
112
|
-
return if src.closed? || @paused_srcs.include?( src )
|
113
|
-
@reads.delete( src )
|
114
|
-
@paused_srcs << src
|
115
|
-
end
|
116
|
-
|
117
|
-
##
|
118
|
-
# add read
|
119
|
-
#
|
120
|
-
def add_read( sock, role = nil )
|
121
|
-
return if sock.closed? || @reads.include?( sock )
|
122
|
-
@reads << sock
|
123
|
-
|
124
|
-
if role then
|
125
|
-
@roles[ sock ] = role
|
126
|
-
end
|
127
|
-
|
128
|
-
next_tick
|
129
|
-
end
|
130
|
-
|
131
|
-
##
|
132
|
-
# add resume dst
|
133
|
-
#
|
134
|
-
def add_resume_dst( dst )
|
135
|
-
return if @resume_dsts.include?( dst )
|
136
|
-
@resume_dsts << dst
|
137
|
-
next_tick
|
138
|
-
end
|
139
|
-
|
140
|
-
##
|
141
|
-
# add resume src
|
142
|
-
#
|
143
|
-
def add_resume_src( src )
|
144
|
-
return if @resume_srcs.include?( src )
|
145
|
-
@resume_srcs << src
|
146
|
-
next_tick
|
147
|
-
end
|
148
|
-
|
149
|
-
##
|
150
|
-
# add socks5 conn reply
|
151
|
-
#
|
152
|
-
def add_socks5_conn_reply( src )
|
153
|
-
# +----+-----+-------+------+----------+----------+
|
154
|
-
# |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
|
155
|
-
# +----+-----+-------+------+----------+----------+
|
156
|
-
# | 1 | 1 | X'00' | 1 | Variable | 2 |
|
157
|
-
# +----+-----+-------+------+----------+----------+
|
158
|
-
redir_ip, redir_port = @redir_local_address.ip_unpack
|
159
|
-
data = [ [ 5, 0, 0, 1 ].pack( 'C4' ), IPAddr.new( redir_ip ).hton, [ redir_port ].pack( 'n' ) ].join
|
160
|
-
# puts "debug add src.wbuff socks5 conn reply #{ data.inspect }"
|
161
|
-
add_src_wbuff( src, data )
|
162
|
-
end
|
163
|
-
|
164
|
-
##
|
165
|
-
# add src rbuff
|
166
|
-
#
|
167
|
-
def add_src_rbuff( src, data )
|
168
|
-
src_info = @src_infos[ src ]
|
169
|
-
src_info[ :rbuff ] << data
|
170
|
-
|
171
|
-
if src_info[ :rbuff ].bytesize >= WBUFF_LIMIT then
|
172
|
-
# puts "debug src.rbuff full"
|
173
|
-
add_closing_src( src )
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
##
|
178
|
-
# add src wbuff
|
179
|
-
#
|
180
|
-
def add_src_wbuff( src, data )
|
181
|
-
return if src.closed? || @closing_srcs.include?( src )
|
182
|
-
src_info = @src_infos[ src ]
|
183
|
-
src_info[ :wbuff ] << data
|
184
|
-
src_info[ :last_recv_at ] = Time.new
|
185
|
-
add_write( src )
|
186
|
-
|
187
|
-
if src_info[ :wbuff ].bytesize >= WBUFF_LIMIT then
|
188
|
-
dst = src_info[ :dst ]
|
189
|
-
|
190
|
-
if dst then
|
191
|
-
puts "p#{ Process.pid } #{ Time.new } pause dst #{ src_info[ :destination_domain ] }"
|
192
|
-
add_paused_dst( dst )
|
193
|
-
end
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
##
|
198
|
-
# add write
|
199
|
-
#
|
200
|
-
def add_write( sock )
|
201
|
-
return if sock.closed? || @writes.include?( sock )
|
202
|
-
@writes << sock
|
203
|
-
next_tick
|
204
|
-
end
|
205
|
-
|
206
|
-
##
|
207
|
-
# close read dst
|
208
|
-
#
|
209
|
-
def close_read_dst( dst )
|
210
|
-
return if dst.closed?
|
211
|
-
# puts "debug close read dst"
|
212
|
-
dst.close_read
|
213
|
-
@reads.delete( dst )
|
214
|
-
|
215
|
-
if dst.closed? then
|
216
|
-
@writes.delete( dst )
|
217
|
-
@roles.delete( dst )
|
218
|
-
del_dst_info( dst )
|
219
|
-
end
|
220
|
-
end
|
221
|
-
|
222
|
-
##
|
223
|
-
# close read src
|
224
|
-
#
|
225
|
-
def close_read_src( src )
|
226
|
-
return if src.closed?
|
227
|
-
# puts "debug close read src"
|
228
|
-
src_info = @src_infos[ src ]
|
229
|
-
src_info[ :close_read ] = true
|
230
|
-
|
231
|
-
if src_info[ :close_write ] then
|
232
|
-
close_sock( src )
|
233
|
-
del_src_info( src )
|
234
|
-
else
|
235
|
-
@reads.delete( src )
|
236
|
-
end
|
237
|
-
end
|
238
|
-
|
239
|
-
##
|
240
|
-
# close redir
|
241
|
-
#
|
242
|
-
def close_redir( redir )
|
243
|
-
return if redir.closed?
|
244
|
-
redir.close
|
245
|
-
@roles.delete( redir )
|
246
|
-
@reads.delete( redir )
|
247
|
-
@src_infos.keys.each { | src | close_src( src ) }
|
248
|
-
end
|
249
|
-
|
250
|
-
##
|
251
|
-
# close sock
|
252
|
-
#
|
253
|
-
def close_sock( sock )
|
254
|
-
sock.close
|
255
|
-
@reads.delete( sock )
|
256
|
-
@writes.delete( sock )
|
257
|
-
@roles.delete( sock )
|
258
|
-
end
|
259
|
-
|
260
|
-
##
|
261
|
-
# close src
|
262
|
-
#
|
263
|
-
def close_src( src )
|
264
|
-
return if src.closed?
|
265
|
-
# puts "debug close src"
|
266
|
-
close_sock( src )
|
267
|
-
src_info = del_src_info( src )
|
268
|
-
dst = src_info[ :dst ]
|
269
|
-
|
270
|
-
if dst then
|
271
|
-
close_sock( dst )
|
272
|
-
del_dst_info( dst )
|
273
|
-
end
|
274
|
-
end
|
275
|
-
|
276
|
-
##
|
277
|
-
# close write dst
|
278
|
-
#
|
279
|
-
def close_write_dst( dst )
|
280
|
-
return if dst.closed?
|
281
|
-
# puts "debug close write dst"
|
282
|
-
dst.close_write
|
283
|
-
@writes.delete( dst )
|
284
|
-
|
285
|
-
if dst.closed? then
|
286
|
-
@reads.delete( dst )
|
287
|
-
@roles.delete( dst )
|
288
|
-
del_dst_info( dst )
|
289
|
-
end
|
290
|
-
end
|
291
|
-
|
292
|
-
##
|
293
|
-
# close write src
|
294
|
-
#
|
295
|
-
def close_write_src( src )
|
296
|
-
return if src.closed?
|
297
|
-
# puts "debug close write src"
|
298
|
-
src_info = @src_infos[ src ]
|
299
|
-
src_info[ :close_write ] = true
|
300
|
-
|
301
|
-
if src_info[ :close_read ] then
|
302
|
-
close_sock( src )
|
303
|
-
del_src_info( src )
|
304
|
-
else
|
305
|
-
@writes.delete( src )
|
306
|
-
end
|
307
|
-
end
|
308
|
-
|
309
|
-
##
|
310
|
-
# del dst info
|
311
|
-
#
|
312
|
-
def del_dst_info( dst )
|
313
|
-
# puts "debug delete dst info"
|
314
|
-
dst_info = @dst_infos.delete( dst )
|
315
|
-
@paused_dsts.delete( dst )
|
316
|
-
@resume_dsts.delete( dst )
|
317
|
-
dst_info
|
318
|
-
end
|
319
|
-
|
320
|
-
##
|
321
|
-
# del src info
|
322
|
-
#
|
323
|
-
def del_src_info( src )
|
324
|
-
# puts "debug delete src info"
|
325
|
-
src_info = @src_infos.delete( src )
|
326
|
-
@paused_srcs.delete( src )
|
327
|
-
@resume_srcs.delete( src )
|
328
|
-
src_info
|
329
|
-
end
|
330
|
-
|
331
|
-
##
|
332
|
-
# loop check expire
|
333
|
-
#
|
334
|
-
def loop_check_expire
|
335
|
-
Thread.new do
|
336
|
-
loop do
|
337
|
-
sleep CHECK_EXPIRE_INTERVAL
|
338
|
-
now = Time.new
|
339
|
-
|
340
|
-
@src_infos.each do | src, src_info |
|
341
|
-
last_recv_at = src_info[ :last_recv_at ] || src_info[ :created_at ]
|
342
|
-
last_sent_at = src_info[ :last_sent_at ] || src_info[ :created_at ]
|
343
|
-
|
344
|
-
if src_info[ :dst ] then
|
345
|
-
if src_info[ :dst_connected ] then
|
346
|
-
expire_after = EXPIRE_AFTER
|
347
|
-
is_expire = ( now - last_recv_at >= expire_after ) && ( now - last_sent_at >= expire_after )
|
348
|
-
else
|
349
|
-
expire_after = EXPIRE_CONNECTING
|
350
|
-
is_expire = ( now - src_info[ :dst_created_at ] >= expire_after )
|
351
|
-
end
|
352
|
-
else
|
353
|
-
expire_after = EXPIRE_NEW
|
354
|
-
is_expire = ( now - last_recv_at >= expire_after ) && ( now - last_sent_at >= expire_after )
|
355
|
-
end
|
356
|
-
|
357
|
-
if is_expire then
|
358
|
-
puts "p#{ Process.pid } #{ Time.new } expire src #{ expire_after } #{ src_info[ :id ] } #{ src_info[ :destination_domain ] }"
|
359
|
-
add_closing_src( src )
|
360
|
-
|
361
|
-
unless src_info[ :rbuff ].empty? then
|
362
|
-
puts "p#{ Process.pid } #{ Time.new } lost rbuff #{ src_info[ :rbuff ].inspect }"
|
363
|
-
end
|
364
|
-
end
|
365
|
-
end
|
366
|
-
end
|
367
|
-
end
|
368
|
-
end
|
369
|
-
|
370
|
-
##
|
371
|
-
# loop check resume
|
372
|
-
#
|
373
|
-
def loop_check_resume
|
374
|
-
Thread.new do
|
375
|
-
loop do
|
376
|
-
sleep CHECK_RESUME_INTERVAL
|
377
|
-
|
378
|
-
@paused_srcs.each do | src |
|
379
|
-
src_info = @src_infos[ src ]
|
380
|
-
dst = src_info[ :dst ]
|
381
|
-
|
382
|
-
if dst && !dst.closed? then
|
383
|
-
dst_info = @dst_infos[ dst ]
|
384
|
-
|
385
|
-
if dst_info[ :wbuff ].bytesize < RESUME_BELOW then
|
386
|
-
puts "p#{ Process.pid } #{ Time.new } resume direct src #{ src_info[ :destination_domain ] }"
|
387
|
-
add_resume_src( src )
|
388
|
-
end
|
389
|
-
end
|
390
|
-
end
|
391
|
-
|
392
|
-
@paused_dsts.each do | dst |
|
393
|
-
dst_info = @dst_infos[ dst ]
|
394
|
-
src = dst_info[ :src ]
|
395
|
-
|
396
|
-
if src && !src.closed? then
|
397
|
-
src_info = @src_infos[ src ]
|
398
|
-
|
399
|
-
if src_info[ :wbuff ].bytesize < RESUME_BELOW then
|
400
|
-
puts "p#{ Process.pid } #{ Time.new } resume dst #{ dst_info[ :domain ] }"
|
401
|
-
add_resume_dst( dst )
|
402
|
-
end
|
403
|
-
end
|
404
|
-
end
|
405
|
-
end
|
406
|
-
end
|
407
|
-
end
|
408
|
-
|
409
|
-
##
|
410
|
-
# new a dst
|
411
|
-
#
|
412
|
-
def new_a_dst( src, ip_info )
|
413
|
-
return if src.closed?
|
414
|
-
src_info = @src_infos[ src ]
|
415
|
-
domain = src_info[ :destination_domain ]
|
416
|
-
destination_addr = Socket.sockaddr_in( src_info[ :destination_port ], ip_info.ip_address )
|
417
|
-
dst = Socket.new( ip_info.ipv4? ? Socket::AF_INET : Socket::AF_INET6, Socket::SOCK_STREAM, 0 )
|
418
|
-
dst.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1 )
|
419
|
-
|
420
|
-
begin
|
421
|
-
dst.connect_nonblock( destination_addr )
|
422
|
-
rescue IO::WaitWritable
|
423
|
-
# connect nonblock 必抛 wait writable
|
424
|
-
rescue Exception => e
|
425
|
-
puts "p#{ Process.pid } #{ Time.new } dst connect destination #{ domain } #{ src_info[ :destination_port ] } #{ ip_info.ip_address } #{ e.class }"
|
426
|
-
dst.close
|
427
|
-
add_closing_src( src )
|
428
|
-
return
|
429
|
-
end
|
430
|
-
|
431
|
-
# puts "debug a new dst #{ dst.local_address.inspect }"
|
432
|
-
dst_info = {
|
433
|
-
src: src, # 对应src
|
434
|
-
domain: domain, # 目的地
|
435
|
-
wbuff: '', # 写前
|
436
|
-
closing_write: false # 准备关闭写
|
437
|
-
}
|
438
|
-
|
439
|
-
@dst_infos[ dst ] = dst_info
|
440
|
-
src_info[ :proxy_type ] = :direct
|
441
|
-
src_info[ :dst ] = dst
|
442
|
-
src_info[ :dst_created_at ] = Time.new
|
443
|
-
add_socks5_conn_reply( src )
|
444
|
-
add_read( dst, :dst )
|
445
|
-
add_write( dst )
|
446
|
-
end
|
447
|
-
|
448
|
-
##
|
449
|
-
# new a redir
|
450
|
-
#
|
451
|
-
def new_a_redir
|
452
|
-
pre = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
|
453
|
-
pre.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1 )
|
454
|
-
pre.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
|
455
|
-
pre.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 )
|
456
|
-
pre.bind( Socket.sockaddr_in( @redir_port, '0.0.0.0' ) )
|
457
|
-
@redir_local_address = pre.local_address
|
458
|
-
puts "p#{ Process.pid } #{ Time.new } pre bind on #{ @redir_port } local address #{ pre.local_address.inspect }"
|
459
|
-
|
460
|
-
now = Time.new
|
461
|
-
name = OpenSSL::X509::Name.new
|
462
|
-
key = OpenSSL::PKey::RSA.new 1024
|
463
|
-
cert = OpenSSL::X509::Certificate.new
|
464
|
-
cert.version = 2
|
465
|
-
cert.serial = 0
|
466
|
-
cert.not_before = now
|
467
|
-
cert.not_after = now + 365 * 24 * 60 * 60
|
468
|
-
cert.public_key = key.public_key
|
469
|
-
cert.subject = name
|
470
|
-
cert.issuer = name
|
471
|
-
cert.sign key, OpenSSL::Digest.new('SHA1')
|
472
|
-
context = OpenSSL::SSL::SSLContext.new
|
473
|
-
context.security_level = 1
|
474
|
-
context.add_certificate( cert, key )
|
475
|
-
redir = OpenSSL::SSL::SSLServer.new pre, context
|
476
|
-
redir.listen( 127 )
|
477
|
-
puts "p#{ Process.pid } #{ Time.new } redir listening"
|
478
|
-
add_read( redir, :redir )
|
479
|
-
end
|
480
|
-
|
481
|
-
##
|
482
|
-
# next tick
|
483
|
-
#
|
484
|
-
def next_tick
|
485
|
-
@dotw.write( '.' )
|
486
|
-
end
|
487
|
-
|
488
|
-
##
|
489
|
-
# resolve domain
|
490
|
-
#
|
491
|
-
def resolve_domain( src, domain )
|
492
|
-
resolv_cache = @resolv_caches[ domain ]
|
493
|
-
|
494
|
-
if resolv_cache then
|
495
|
-
ip_info, created_at = resolv_cache
|
496
|
-
|
497
|
-
if Time.new - created_at < RESOLV_CACHE_EXPIRE then
|
498
|
-
# puts "debug #{ domain } hit resolv cache #{ ip_info.inspect }"
|
499
|
-
new_a_dst( src, ip_info )
|
500
|
-
return
|
501
|
-
end
|
502
|
-
|
503
|
-
# puts "debug expire #{ domain } resolv cache"
|
504
|
-
@resolv_caches.delete( domain )
|
505
|
-
end
|
506
|
-
|
507
|
-
src_info = @src_infos[ src ]
|
508
|
-
src_info[ :proxy_type ] = :checking
|
509
|
-
|
510
|
-
Thread.new do
|
511
|
-
begin
|
512
|
-
ip_info = Addrinfo.ip( domain )
|
513
|
-
rescue Exception => e
|
514
|
-
puts "p#{ Process.pid } #{ Time.new } resolv #{ domain.inspect } #{ e.class }"
|
515
|
-
end
|
516
|
-
|
517
|
-
if ip_info then
|
518
|
-
@resolv_caches[ domain ] = [ ip_info, Time.new ]
|
519
|
-
puts "p#{ Process.pid } #{ Time.new } resolved #{ domain } #{ ip_info.ip_address }"
|
520
|
-
new_a_dst( src, ip_info )
|
521
|
-
else
|
522
|
-
add_closing_src( src )
|
523
|
-
end
|
524
|
-
end
|
525
|
-
end
|
526
|
-
|
527
|
-
##
|
528
|
-
# set dst closing write
|
529
|
-
#
|
530
|
-
def set_dst_closing_write( dst )
|
531
|
-
return if dst.closed?
|
532
|
-
dst_info = @dst_infos[ dst ]
|
533
|
-
return if dst_info[ :closing_write ]
|
534
|
-
dst_info[ :closing_write ] = true
|
535
|
-
add_write( dst )
|
536
|
-
end
|
537
|
-
|
538
|
-
##
|
539
|
-
# set src closing write
|
540
|
-
#
|
541
|
-
def set_src_closing_write( src )
|
542
|
-
return if src.closed? || @closing_srcs.include?( src )
|
543
|
-
src_info = @src_infos[ src ]
|
544
|
-
return if src_info[ :closing_write ]
|
545
|
-
src_info[ :closing_write ] = true
|
546
|
-
add_write( src )
|
547
|
-
end
|
548
|
-
|
549
|
-
##
|
550
|
-
# read dotr
|
551
|
-
#
|
552
|
-
def read_dotr( dotr )
|
553
|
-
dotr.read_nonblock( READ_SIZE )
|
554
|
-
|
555
|
-
if @closing_srcs.any? then
|
556
|
-
@closing_srcs.each { | src | close_src( src ) }
|
557
|
-
@closing_srcs.clear
|
558
|
-
end
|
559
|
-
|
560
|
-
if @resume_srcs.any? then
|
561
|
-
@resume_srcs.each do | src |
|
562
|
-
add_read( src )
|
563
|
-
@paused_srcs.delete( src )
|
564
|
-
end
|
565
|
-
|
566
|
-
@resume_srcs.clear
|
567
|
-
end
|
568
|
-
|
569
|
-
if @resume_dsts.any? then
|
570
|
-
@resume_dsts.each do | dst |
|
571
|
-
add_read( dst )
|
572
|
-
@paused_dsts.delete( dst )
|
573
|
-
end
|
574
|
-
|
575
|
-
@resume_dsts.clear
|
576
|
-
end
|
577
|
-
end
|
578
|
-
|
579
|
-
##
|
580
|
-
# read redir
|
581
|
-
#
|
582
|
-
def read_redir( redir )
|
583
|
-
accepted = false
|
584
|
-
|
585
|
-
Thread.new do
|
586
|
-
sleep 1
|
587
|
-
|
588
|
-
unless accepted then
|
589
|
-
puts "p#{ Process.pid } #{ Time.new } accept timeout"
|
590
|
-
close_redir( redir )
|
591
|
-
new_a_redir
|
592
|
-
end
|
593
|
-
end
|
594
|
-
|
595
|
-
begin
|
596
|
-
src = redir.accept
|
597
|
-
rescue SystemExit => e
|
598
|
-
puts "p#{ Process.pid } #{ Time.new } redir accept #{ e.class }"
|
599
|
-
close_redir( redir )
|
600
|
-
return
|
601
|
-
rescue Exception => e
|
602
|
-
puts "p#{ Process.pid } #{ Time.new } redir accept #{ e.class }"
|
603
|
-
puts e.full_message
|
604
|
-
return
|
605
|
-
end
|
606
|
-
|
607
|
-
accepted = true
|
608
|
-
# puts "debug accept a src"
|
609
|
-
|
610
|
-
@src_infos[ src ] = {
|
611
|
-
proxy_proto: :uncheck, # :uncheck / :socks5
|
612
|
-
proxy_type: :uncheck, # :uncheck / :checking / :direct / :negotiation
|
613
|
-
destination_domain: nil, # 目的地域名
|
614
|
-
destination_port: nil, # 目的地端口
|
615
|
-
is_connect: true, # 代理协议是http的场合,是否是CONNECT
|
616
|
-
rbuff: '', # 读到的流量
|
617
|
-
dst: nil, # 对应的dst
|
618
|
-
dst_created_at: nil, # 对应的dst的创建时间
|
619
|
-
dst_connected: false, # 对应的dst是否已连接
|
620
|
-
wbuff: '', # 从dst读到的流量
|
621
|
-
created_at: Time.new, # 创建时间
|
622
|
-
last_recv_at: nil, # 上一次收到新流量(由dst收到)的时间
|
623
|
-
last_sent_at: nil, # 上一次发出流量(由dst发出)的时间
|
624
|
-
closing_write: false, # 准备关闭写
|
625
|
-
close_read: false, # 已经关闭读
|
626
|
-
close_write: false # 已经关闭写
|
627
|
-
}
|
628
|
-
|
629
|
-
add_read( src, :src )
|
630
|
-
end
|
631
|
-
|
632
|
-
##
|
633
|
-
# read src
|
634
|
-
#
|
635
|
-
def read_src( src )
|
636
|
-
if src.closed? then
|
637
|
-
puts "p#{ Process.pid } #{ Time.new } read src but src closed?"
|
638
|
-
return
|
639
|
-
end
|
640
|
-
|
641
|
-
src_info = @src_infos[ src ]
|
642
|
-
|
643
|
-
begin
|
644
|
-
data = src.read_nonblock( READ_SIZE )
|
645
|
-
rescue IO::WaitReadable
|
646
|
-
return
|
647
|
-
rescue Errno::EINTR => e
|
648
|
-
puts e.class
|
649
|
-
return
|
650
|
-
rescue Exception => e
|
651
|
-
# puts "debug read src #{ e.class }"
|
652
|
-
dst = src_info[ :dst ]
|
653
|
-
close_read_src( src )
|
654
|
-
|
655
|
-
if dst then
|
656
|
-
set_dst_closing_write( dst )
|
657
|
-
end
|
658
|
-
|
659
|
-
return
|
660
|
-
end
|
661
|
-
|
662
|
-
src_info = @src_infos[ src ]
|
663
|
-
proxy_type = src_info[ :proxy_type ]
|
664
|
-
|
665
|
-
case proxy_type
|
666
|
-
when :uncheck then
|
667
|
-
if data[ 0 ].unpack( 'C' ).first != 5 then
|
668
|
-
"p#{ Process.pid } #{ Time.new } unknown data #{ data.inspect }"
|
669
|
-
end
|
670
|
-
|
671
|
-
# puts "debug socks5 #{ data.inspect }"
|
672
|
-
|
673
|
-
# https://tools.ietf.org/html/rfc1928
|
674
|
-
#
|
675
|
-
# +----+----------+----------+
|
676
|
-
# |VER | NMETHODS | METHODS |
|
677
|
-
# +----+----------+----------+
|
678
|
-
# | 1 | 1 | 1 to 255 |
|
679
|
-
# +----+----------+----------+
|
680
|
-
nmethods = data[ 1 ].unpack( 'C' ).first
|
681
|
-
methods = data[ 2, nmethods ].unpack( 'C*' )
|
682
|
-
|
683
|
-
unless methods.include?( 0 ) then
|
684
|
-
puts "p#{ Process.pid } #{ Time.new } miss method 0x00"
|
685
|
-
add_closing_src( src )
|
686
|
-
return
|
687
|
-
end
|
688
|
-
|
689
|
-
# +----+--------+
|
690
|
-
# |VER | METHOD |
|
691
|
-
# +----+--------+
|
692
|
-
# | 1 | 1 |
|
693
|
-
# +----+--------+
|
694
|
-
data2 = [ 5, 0 ].pack( 'CC' )
|
695
|
-
add_src_wbuff( src, data2 )
|
696
|
-
src_info[ :proxy_proto ] = :socks5
|
697
|
-
src_info[ :proxy_type ] = :negotiation
|
698
|
-
when :checking then
|
699
|
-
# puts "debug add src rbuff before resolved #{ data.inspect }"
|
700
|
-
src_info[ :rbuff ] << data
|
701
|
-
when :negotiation then
|
702
|
-
# +----+-----+-------+------+----------+----------+
|
703
|
-
# |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
|
704
|
-
# +----+-----+-------+------+----------+----------+
|
705
|
-
# | 1 | 1 | X'00' | 1 | Variable | 2 |
|
706
|
-
# +----+-----+-------+------+----------+----------+
|
707
|
-
# puts "debug negotiation #{ data.inspect }"
|
708
|
-
ver, cmd, rsv, atyp = data[ 0, 4 ].unpack( 'C4' )
|
709
|
-
|
710
|
-
if cmd == 1 then
|
711
|
-
# puts "debug socks5 CONNECT"
|
712
|
-
|
713
|
-
if atyp == 1 then
|
714
|
-
destination_host, destination_port = data[ 4, 6 ].unpack( 'Nn' )
|
715
|
-
destination_addr = Socket.sockaddr_in( destination_port, destination_host )
|
716
|
-
destination_addrinfo = Addrinfo.new( destination_addr )
|
717
|
-
destination_ip = destination_addrinfo.ip_address
|
718
|
-
src_info[ :destination_domain ] = destination_ip
|
719
|
-
src_info[ :destination_port ] = destination_port
|
720
|
-
# puts "debug IP V4 address #{ destination_addrinfo.ip_unpack.inspect }"
|
721
|
-
new_a_dst( src, destination_addrinfo )
|
722
|
-
elsif atyp == 3 then
|
723
|
-
domain_len = data[ 4 ].unpack( 'C' ).first
|
724
|
-
|
725
|
-
if ( domain_len + 7 ) == data.bytesize then
|
726
|
-
domain = data[ 5, domain_len ]
|
727
|
-
port = data[ ( 5 + domain_len ), 2 ].unpack( 'n' ).first
|
728
|
-
src_info[ :destination_domain ] = domain
|
729
|
-
src_info[ :destination_port ] = port
|
730
|
-
# puts "debug DOMAINNAME #{ domain } #{ port }"
|
731
|
-
resolve_domain( src, domain )
|
732
|
-
end
|
733
|
-
end
|
734
|
-
else
|
735
|
-
puts "p#{ Process.pid } #{ Time.new } socks5 cmd #{ cmd } not implement"
|
736
|
-
end
|
737
|
-
when :direct then
|
738
|
-
dst = src_info[ :dst ]
|
739
|
-
|
740
|
-
if dst then
|
741
|
-
add_dst_wbuff( dst, data )
|
742
|
-
else
|
743
|
-
# puts "debug add src.rbuff #{ data.bytesize }"
|
744
|
-
add_src_rbuff( src, data )
|
745
|
-
end
|
746
|
-
end
|
747
|
-
end
|
748
|
-
|
749
|
-
##
|
750
|
-
# read dst
|
751
|
-
#
|
752
|
-
def read_dst( dst )
|
753
|
-
if dst.closed? then
|
754
|
-
puts "p#{ Process.pid } #{ Time.new } read dst but dst closed?"
|
755
|
-
return
|
756
|
-
end
|
757
|
-
|
758
|
-
dst_info = @dst_infos[ dst ]
|
759
|
-
src = dst_info[ :src ]
|
760
|
-
|
761
|
-
begin
|
762
|
-
data = dst.read_nonblock( READ_SIZE )
|
763
|
-
rescue IO::WaitReadable, Errno::EINTR
|
764
|
-
print 'r'
|
765
|
-
return
|
766
|
-
rescue Exception => e
|
767
|
-
# puts "debug read dst #{ e.class }"
|
768
|
-
close_read_dst( dst )
|
769
|
-
set_src_closing_write( src )
|
770
|
-
return
|
771
|
-
end
|
772
|
-
|
773
|
-
# puts "debug read dst #{ data.bytesize }"
|
774
|
-
add_src_wbuff( src, data )
|
775
|
-
end
|
776
|
-
|
777
|
-
##
|
778
|
-
# write src
|
779
|
-
#
|
780
|
-
def write_src( src )
|
781
|
-
if src.closed? then
|
782
|
-
puts "p#{ Process.pid } #{ Time.new } write src but src closed?"
|
783
|
-
return
|
784
|
-
end
|
785
|
-
|
786
|
-
src_info = @src_infos[ src ]
|
787
|
-
dst = src_info[ :dst ]
|
788
|
-
data = src_info[ :wbuff ]
|
789
|
-
|
790
|
-
# 写前为空,处理关闭写
|
791
|
-
if data.empty? then
|
792
|
-
if src_info[ :closing_write ] then
|
793
|
-
close_write_src( src )
|
794
|
-
else
|
795
|
-
@writes.delete( src )
|
796
|
-
end
|
797
|
-
|
798
|
-
return
|
799
|
-
end
|
800
|
-
|
801
|
-
# 写入
|
802
|
-
begin
|
803
|
-
written = src.write_nonblock( data )
|
804
|
-
rescue IO::WaitWritable, Errno::EINTR
|
805
|
-
print 'w'
|
806
|
-
return
|
807
|
-
rescue Exception => e
|
808
|
-
# puts "debug write src #{ e.class }"
|
809
|
-
close_write_src( src )
|
810
|
-
|
811
|
-
if dst then
|
812
|
-
close_read_dst( dst )
|
813
|
-
end
|
814
|
-
|
815
|
-
return
|
816
|
-
end
|
817
|
-
|
818
|
-
data = data[ written..-1 ]
|
819
|
-
src_info[ :wbuff ] = data
|
820
|
-
end
|
821
|
-
|
822
|
-
##
|
823
|
-
# write dst
|
824
|
-
#
|
825
|
-
def write_dst( dst )
|
826
|
-
if dst.closed? then
|
827
|
-
puts "p#{ Process.pid } #{ Time.new } write dst but dst closed?"
|
828
|
-
return
|
829
|
-
end
|
830
|
-
|
831
|
-
dst_info = @dst_infos[ dst ]
|
832
|
-
src = dst_info[ :src ]
|
833
|
-
src_info = @src_infos[ src ]
|
834
|
-
|
835
|
-
unless src.closed? then
|
836
|
-
src_info[ :dst_connected ] = true
|
837
|
-
end
|
838
|
-
|
839
|
-
data = dst_info[ :wbuff ]
|
840
|
-
|
841
|
-
# 写前为空,处理关闭写
|
842
|
-
if data.empty? then
|
843
|
-
if dst_info[ :closing_write ] then
|
844
|
-
close_write_dst( dst )
|
845
|
-
else
|
846
|
-
@writes.delete( dst )
|
847
|
-
end
|
848
|
-
|
849
|
-
return
|
850
|
-
end
|
851
|
-
|
852
|
-
# 写入
|
853
|
-
begin
|
854
|
-
written = dst.write_nonblock( data )
|
855
|
-
rescue IO::WaitWritable, Errno::EINTR
|
856
|
-
print 'w'
|
857
|
-
return
|
858
|
-
rescue Exception => e
|
859
|
-
# puts "debug write dst #{ e.class }"
|
860
|
-
close_write_dst( dst )
|
861
|
-
close_read_src( src )
|
862
|
-
return
|
863
|
-
end
|
864
|
-
|
865
|
-
data = data[ written..-1 ]
|
866
|
-
dst_info[ :wbuff ] = data
|
867
|
-
|
868
|
-
unless src.closed? then
|
869
|
-
src_info[ :last_sent_at ] = Time.new
|
870
|
-
end
|
871
|
-
end
|
872
|
-
|
873
|
-
end
|
874
|
-
end
|