girl 0.86.0 → 0.90.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.

@@ -13,61 +13,41 @@ module Girl
13
13
  class Proxyd
14
14
 
15
15
  def initialize( config_path = nil )
16
- if config_path
17
- unless File.exist?( config_path )
18
- raise "not found config file #{ config_path }"
19
- end
20
-
16
+ if config_path then
17
+ raise "not found config file #{ config_path }" unless File.exist?( config_path )
21
18
  conf = JSON.parse( IO.binread( config_path ), symbolize_names: true )
22
19
  proxyd_port = conf[ :proxyd_port ]
23
- proxyd_tmp_dir = conf[ :proxyd_tmp_dir ]
24
20
  worker_count = conf[ :worker_count ]
25
21
  end
26
22
 
27
- unless proxyd_port
23
+ unless proxyd_port then
28
24
  proxyd_port = 6060
29
25
  end
30
26
 
31
- unless proxyd_tmp_dir
32
- proxyd_tmp_dir = '/tmp/girl.proxyd'
33
- end
34
-
35
- unless File.exist?( proxyd_tmp_dir )
36
- Dir.mkdir( proxyd_tmp_dir )
37
- end
38
-
39
- dst_chunk_dir = File.join( proxyd_tmp_dir, 'dst.chunk' )
40
-
41
- unless Dir.exist?( dst_chunk_dir )
42
- Dir.mkdir( dst_chunk_dir )
43
- end
44
-
45
- tund_chunk_dir = File.join( proxyd_tmp_dir, 'tund.chunk' )
46
-
47
- unless Dir.exist?( tund_chunk_dir )
48
- Dir.mkdir( tund_chunk_dir )
49
- end
50
-
51
27
  nprocessors = Etc.nprocessors
52
28
 
53
- if worker_count.nil? || worker_count <= 0 || worker_count > nprocessors
29
+ if worker_count.nil? || worker_count <= 0 || worker_count > nprocessors then
54
30
  worker_count = nprocessors
55
31
  end
56
32
 
57
33
  title = "girl proxyd #{ Girl::VERSION }"
58
34
  puts title
59
35
  puts "proxyd port #{ proxyd_port }"
60
- puts "dst chunk dir #{ dst_chunk_dir }"
61
- puts "tund chunk dir #{ tund_chunk_dir }"
62
36
  puts "worker count #{ worker_count }"
63
37
 
38
+ len = CONSTS.map{ | name | name.size }.max
39
+
40
+ CONSTS.each do | name |
41
+ puts "#{ name.gsub( '_', ' ' ).ljust( len ) } #{ Girl.const_get( name ) }"
42
+ end
43
+
64
44
  $0 = title
65
45
  workers = []
66
46
 
67
47
  worker_count.times do | i |
68
48
  workers << fork do
69
49
  $0 = 'girl proxyd worker'
70
- worker = Girl::ProxydWorker.new( proxyd_port, dst_chunk_dir, tund_chunk_dir )
50
+ worker = Girl::ProxydWorker.new( proxyd_port )
71
51
 
72
52
  Signal.trap( :TERM ) do
73
53
  puts "w#{ i } exit"
@@ -4,17 +4,16 @@ module Girl
4
4
  ##
5
5
  # initialize
6
6
  #
7
- def initialize( proxyd_port, dst_chunk_dir, tund_chunk_dir )
8
- @dst_chunk_dir = dst_chunk_dir
9
- @tund_chunk_dir = tund_chunk_dir
7
+ def initialize( proxyd_port )
10
8
  @custom = Girl::ProxydCustom.new
11
9
  @mutex = Mutex.new
12
10
  @reads = []
13
11
  @writes = []
14
- @roles = {} # sock => :dotr / :proxyd / :dst / :tund
15
- @dst_infos = {} # dst => {}
16
- @tunds = {} # port => tund
12
+ @roles = {} # sock => :dotr / :proxyd / :dst / :tund / :tcpd / :streamd
17
13
  @tund_infos = {} # tund => {}
14
+ @tcpd_infos = {} # tcpd => {}
15
+ @dst_infos = {} # dst => {}
16
+ @streamd_infos = {} # streamd => {}
18
17
  @tunneling_tunds = {} # tunneling_addr => tund
19
18
  @resolv_caches = {} # domain => [ ip, created_at ]
20
19
 
@@ -30,34 +29,40 @@ module Girl
30
29
  def looping
31
30
  puts "p#{ Process.pid } #{ Time.new } looping"
32
31
  loop_check_expire
33
- loop_check_status
32
+ loop_check_resume
34
33
 
35
34
  loop do
36
35
  rs, ws = IO.select( @reads, @writes )
37
36
 
38
37
  @mutex.synchronize do
39
- # 先写,再读
40
- ws.each do | sock |
41
- case @roles[ sock ]
42
- when :proxyd
43
- write_proxyd( sock )
44
- when :dst
45
- write_dst( sock )
46
- when :tund
47
- write_tund( sock )
48
- end
49
- end
50
-
38
+ # 先读,再写,避免打上关闭标记后读到
51
39
  rs.each do | sock |
52
40
  case @roles[ sock ]
53
- when :dotr
41
+ when :dotr then
54
42
  read_dotr( sock )
55
- when :proxyd
43
+ when :proxyd then
56
44
  read_proxyd( sock )
57
- when :dst
58
- read_dst( sock )
59
- when :tund
45
+ when :tund then
60
46
  read_tund( sock )
47
+ when :tcpd then
48
+ read_tcpd( sock )
49
+ when :dst then
50
+ read_dst( sock )
51
+ when :streamd then
52
+ read_streamd( sock )
53
+ end
54
+ end
55
+
56
+ ws.each do | sock |
57
+ case @roles[ sock ]
58
+ when :proxyd then
59
+ write_proxyd( sock )
60
+ when :tund then
61
+ write_tund( sock )
62
+ when :dst then
63
+ write_dst( sock )
64
+ when :streamd then
65
+ write_streamd( sock )
61
66
  end
62
67
  end
63
68
  end
@@ -74,7 +79,7 @@ module Girl
74
79
  data = [ 0, TUND_FIN ].pack( 'Q>C' )
75
80
 
76
81
  @tund_infos.each do | tund, tund_info |
77
- if !tund.closed? && tund_info[ :tun_addr ]
82
+ if !tund.closed? && tund_info[ :tun_addr ] then
78
83
  # puts "debug1 send tund fin"
79
84
  tund.sendmsg( data, 0, tund_info[ :tun_addr ] )
80
85
  end
@@ -87,153 +92,172 @@ module Girl
87
92
  private
88
93
 
89
94
  ##
90
- # loop check expire
95
+ # add proxyd ctlmsg
91
96
  #
92
- def loop_check_expire
93
- Thread.new do
94
- loop do
95
- sleep CHECK_EXPIRE_INTERVAL
96
-
97
- @mutex.synchronize do
98
- need_trigger = false
99
- now = Time.new
97
+ def add_proxyd_ctlmsg_tund_port( tund_info )
98
+ data = [ 0, TUND_PORT, tund_info[ :port ], tund_info[ :tcpd_port ] ].pack( 'Q>Cnn' )
99
+ @proxyd_info[ :ctlmsgs ] << [ data, tund_info[ :tun_addr ] ]
100
+ add_write( @proxyd )
101
+ end
100
102
 
101
- @tund_infos.each do | tund, tund_info |
102
- unless tund.closed?
103
- is_expired = tund_info[ :last_recv_at ] ? ( now - tund_info[ :last_recv_at ] > EXPIRE_AFTER ) : ( now - tund_info[ :created_at ] > EXPIRE_NEW )
104
-
105
- if is_expired
106
- puts "p#{ Process.pid } #{ Time.new } expire tund #{ tund_info[ :port ] }"
107
- set_is_closing( tund )
108
- else
109
- data = [ 0, HEARTBEAT, rand( 128 ) ].pack( 'Q>CC' )
110
- # puts "debug1 #{ Time.new } #{ tund_info[ :port ] } heartbeat"
111
- add_tund_ctlmsg( tund, data )
112
-
113
- tund_info[ :dst_exts ].each do | dst_local_port, dst_ext |
114
- if dst_ext[ :dst ].closed? && ( now - dst_ext[ :last_continue_at ] > EXPIRE_AFTER )
115
- puts "p#{ Process.pid } #{ Time.new } expire dst ext #{ dst_ext[ :domain_port ] }"
116
- del_dst_ext( tund, dst_local_port )
117
- end
118
- end
119
- end
120
-
121
- need_trigger = true
122
- end
123
- end
103
+ ##
104
+ # add ctlmsg
105
+ #
106
+ def add_ctlmsg( tund, data )
107
+ tund_info = @tund_infos[ tund ]
108
+ tund_info[ :ctlmsgs ] << data
109
+ add_write( tund )
110
+ end
124
111
 
125
- @dst_infos.each do | dst, dst_info |
126
- if now - dst_info[ :last_continue_at ] > EXPIRE_AFTER
127
- puts "p#{ Process.pid } #{ Time.new } expire dst #{ dst_info[ :domain_port ] }"
128
- set_is_closing( dst )
129
- need_trigger = true
130
- end
131
- end
112
+ ##
113
+ # add read
114
+ #
115
+ def add_read( sock, role = nil )
116
+ unless @reads.include?( sock ) then
117
+ @reads << sock
132
118
 
133
- if need_trigger
134
- next_tick
135
- end
136
- end
119
+ if role then
120
+ @roles[ sock ] = role
137
121
  end
138
122
  end
139
123
  end
140
124
 
141
125
  ##
142
- # loop check status
126
+ # add write
143
127
  #
144
- def loop_check_status
145
- Thread.new do
146
- loop do
147
- sleep CHECK_STATUS_INTERVAL
148
-
149
- if @tunds.any?
150
- @mutex.synchronize do
151
- need_trigger = false
152
-
153
- @tunds.each do | tund_port, tund |
154
- tund_info = @tund_infos[ tund ]
155
-
156
- if tund_info[ :dst_exts ].any?
157
- now = Time.new
158
-
159
- tund_info[ :dst_exts ].each do | dst_local_port, dst_ext |
160
- if now - dst_ext[ :last_continue_at ] < SEND_STATUS_UNTIL
161
- data = [ 0, DEST_STATUS, dst_local_port, dst_ext[ :relay_pack_id ], dst_ext[ :continue_src_pack_id ] ].pack( 'Q>CnQ>Q>' )
162
- add_tund_ctlmsg( tund, data )
163
- need_trigger = true
164
- end
165
- end
166
- end
167
-
168
- if tund_info[ :paused ] && ( tund_info[ :dst_exts ].map{ | _, dst_ext | dst_ext[ :wmems ].size }.sum < RESUME_BELOW )
169
- puts "p#{ Process.pid } #{ Time.new } resume tund"
170
- tund_info[ :paused ] = false
171
- add_write( tund )
172
- need_trigger = true
173
- end
174
- end
175
-
176
- if need_trigger
177
- next_tick
178
- end
179
- end
180
- end
181
- end
128
+ def add_write( sock )
129
+ unless @writes.include?( sock ) then
130
+ @writes << sock
182
131
  end
183
132
  end
184
133
 
185
134
  ##
186
- # resolve domain
135
+ # close dst
187
136
  #
188
- def resolve_domain( tund, src_id, destination_domain_port )
189
- resolv_cache = @resolv_caches[ destination_domain_port ]
137
+ def close_dst( dst )
138
+ # puts "debug1 close dst"
139
+ close_sock( dst )
140
+ del_dst_info( dst )
141
+ end
190
142
 
191
- if resolv_cache
192
- destination_addr, created_at = resolv_cache
143
+ ##
144
+ # close read dst
145
+ #
146
+ def close_read_dst( dst )
147
+ return if dst.closed?
148
+ # puts "debug1 close read dst"
149
+ dst.close_read
150
+ @reads.delete( dst )
151
+
152
+ if dst.closed? then
153
+ # puts "debug1 delete dst info"
154
+ @roles.delete( dst )
155
+ dst_info = del_dst_info( dst )
156
+ else
157
+ dst_info = @dst_infos[ dst ]
158
+ end
193
159
 
194
- if Time.new - created_at < RESOLV_CACHE_EXPIRE
195
- # puts "debug1 #{ destination_domain_port } hit resolv cache #{ Addrinfo.new( destination_addr ).inspect }"
196
- deal_with_destination_addr( tund, src_id, destination_addr, destination_domain_port )
197
- return
198
- end
160
+ dst_info[ :paused ] = false
161
+ dst_info
162
+ end
199
163
 
200
- # puts "debug1 expire #{ destination_domain_port } resolv cache"
201
- @resolv_caches.delete( destination_domain_port )
164
+ ##
165
+ # close read streamd
166
+ #
167
+ def close_read_streamd( streamd )
168
+ return if streamd.closed?
169
+ # puts "debug1 close read streamd"
170
+ streamd.close_read
171
+ @reads.delete( streamd )
172
+
173
+ if streamd.closed? then
174
+ # puts "debug1 delete streamd info"
175
+ @roles.delete( streamd )
176
+ streamd_info = @streamd_infos.delete( streamd )
177
+ else
178
+ streamd_info = @streamd_infos[ streamd ]
202
179
  end
203
180
 
204
- Thread.new do
205
- colon_idx = destination_domain_port.rindex( ':' )
181
+ streamd_info
182
+ end
206
183
 
207
- if colon_idx
208
- destination_domain = destination_domain_port[ 0...colon_idx ]
209
- destination_port = destination_domain_port[ ( colon_idx + 1 )..-1 ].to_i
184
+ ##
185
+ # close sock
186
+ #
187
+ def close_sock( sock )
188
+ sock.close
189
+ @reads.delete( sock )
190
+ @writes.delete( sock )
191
+ @roles.delete( sock )
192
+ end
210
193
 
211
- begin
212
- destination_addr = Socket.sockaddr_in( destination_port, destination_domain )
213
- rescue Exception => e
214
- puts "p#{ Process.pid } #{ Time.new } sockaddr in #{ destination_domain_port } #{ e.class }"
215
- end
216
- end
194
+ ##
195
+ # close streamd
196
+ #
197
+ def close_streamd( streamd )
198
+ # puts "debug1 close streamd"
199
+ close_sock( streamd )
200
+ @streamd_infos.delete( streamd )
201
+ end
217
202
 
218
- @mutex.synchronize do
219
- if destination_addr
220
- # puts "debug1 resolved #{ destination_domain_port } #{ Addrinfo.new( destination_addr ).inspect }"
221
- @resolv_caches[ destination_domain_port ] = [ destination_addr, Time.new ]
203
+ ##
204
+ # close tund
205
+ #
206
+ def close_tund( tund )
207
+ # puts "debug1 close tund"
208
+ close_sock( tund )
209
+ tund_info = @tund_infos.delete( tund )
210
+ tcpd = tund_info[ :tcpd ]
211
+ close_sock( tcpd )
212
+ @tcpd_infos.delete( tcpd )
213
+ tund_info[ :dsts ].each{ | _, dst | set_dst_closing( dst ) }
214
+ @tunneling_tunds.delete( tund_info[ :tun_addr ] )
215
+ end
222
216
 
223
- unless tund.closed?
224
- if deal_with_destination_addr( tund, src_id, destination_addr, destination_domain_port )
225
- next_tick
226
- end
227
- end
228
- end
229
- end
217
+ ##
218
+ # close write dst
219
+ #
220
+ def close_write_dst( dst )
221
+ return if dst.closed?
222
+ # puts "debug1 close write dst"
223
+ dst.close_write
224
+ @writes.delete( dst )
225
+
226
+ if dst.closed? then
227
+ # puts "debug1 delete dst info"
228
+ @roles.delete( dst )
229
+ dst_info = del_dst_info( dst )
230
+ else
231
+ dst_info = @dst_infos[ dst ]
232
+ end
233
+
234
+ dst_info
235
+ end
236
+
237
+ ##
238
+ # close write streamd
239
+ #
240
+ def close_write_streamd( streamd )
241
+ return if streamd.closed?
242
+ # puts "debug1 close write streamd"
243
+ streamd.close_write
244
+ @writes.delete( streamd )
245
+
246
+ if streamd.closed? then
247
+ # puts "debug1 delete streamd info"
248
+ @roles.delete( streamd )
249
+ streamd_info = @streamd_infos.delete( streamd )
250
+ else
251
+ streamd_info = @streamd_infos[ streamd ]
230
252
  end
253
+
254
+ streamd_info
231
255
  end
232
256
 
233
257
  ##
234
258
  # deal with destination addr
235
259
  #
236
- def deal_with_destination_addr( tund, src_id, destination_addr, destination_domain_port )
260
+ def deal_with_destination_addr( tund, src_id, destination_addr, domain_port )
237
261
  dst = Socket.new( Addrinfo.new( destination_addr ).ipv4? ? Socket::AF_INET : Socket::AF_INET6, Socket::SOCK_STREAM, 0 )
238
262
  dst.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 )
239
263
 
@@ -245,173 +269,191 @@ module Girl
245
269
  return false
246
270
  end
247
271
 
248
- local_port = dst.local_address.ip_port
272
+ dst_id = dst.local_address.ip_port
249
273
 
250
274
  @dst_infos[ dst ] = {
251
- local_port: local_port, # 本地端口
252
- tund: tund, # 对应tund
253
- domain_port: destination_domain_port, # 域名和端口
254
- biggest_pack_id: 0, # 最大包号码
255
- wbuff: '', # 写前
256
- cache: '', # 块读出缓存
257
- chunks: [], # 块队列,写前达到块大小时结一个块 filename
258
- spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
259
- last_continue_at: Time.new, # 上一次发生流量的时间
260
- is_closing: false # 是否准备关闭
275
+ id: dst_id, # id
276
+ tund: tund, # 对应tund
277
+ domain_port: domain_port, # 域名和端口
278
+ rbuff: '', # 对应的streamd没准备好,暂存读到的流量
279
+ streamd: nil, # 对应的streamd
280
+ wbuff: '', # 从streamd读到的流量
281
+ src_id: src_id, # 近端src id
282
+ created_at: Time.new, # 创建时间
283
+ last_recv_at: nil, # 上一次收到新流量(由streamd收到)的时间
284
+ last_sent_at: nil, # 上一次发出流量(由streamd发出)的时间
285
+ paused: false, # 是否已暂停
286
+ closing: false, # 准备关闭
287
+ closing_read: false, # 准备关闭读
288
+ closing_write: false # 准备关闭写
261
289
  }
290
+
262
291
  add_read( dst, :dst )
263
292
 
264
293
  tund_info = @tund_infos[ tund ]
265
- tund_info[ :dst_local_ports ][ src_id ] = local_port
266
- tund_info[ :dst_exts ][ local_port ] = {
267
- dst: dst, # dst
268
- src_id: src_id, # 近端src id
269
- domain_port: destination_domain_port, # 域名和端口
270
- wmems: {}, # 写后 pack_id => data
271
- send_ats: {}, # 上一次发出时间 pack_id => send_at
272
- relay_pack_id: 0, # 转发到几
273
- continue_src_pack_id: 0, # 收到几
274
- pieces: {}, # 跳号包 src_pack_id => data
275
- is_src_closed: false, # src是否已关闭
276
- biggest_src_pack_id: 0, # src最大包号码
277
- completed_pack_id: 0, # 完成到几(对面收到几)
278
- last_continue_at: Time.new # 上一次发生流量的时间
279
- }
280
-
281
- data = [ 0, PAIRED, src_id, local_port ].pack( 'Q>CQ>n' )
282
- # puts "debug1 add ctlmsg paired #{ data.inspect }"
283
- add_tund_ctlmsg( tund, data )
294
+ tund_info[ :dst_ids ][ src_id ] = dst_id
295
+ tund_info[ :dsts ][ dst_id ] = dst
284
296
 
297
+ data = [ 0, PAIRED, src_id, dst_id ].pack( 'Q>CQ>n' )
298
+ # puts "debug1 add ctlmsg paired #{ src_id } #{ dst_id }"
299
+ add_ctlmsg( tund, data )
285
300
  true
286
301
  end
287
302
 
288
303
  ##
289
- # new a proxyd
304
+ # del dst info
290
305
  #
291
- def new_a_proxyd( proxyd_port )
292
- proxyd = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
293
- proxyd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 )
294
- proxyd.bind( Socket.sockaddr_in( proxyd_port, '0.0.0.0' ) )
306
+ def del_dst_info( dst )
307
+ dst_info = @dst_infos.delete( dst )
308
+ tund = dst_info[ :tund ]
295
309
 
296
- puts "p#{ Process.pid } #{ Time.new } proxyd bind on #{ proxyd_port }"
297
- @proxyd = proxyd
298
- @proxyd_ctlmsgs = [] # [ to_addr, data ]
299
- add_read( proxyd, :proxyd )
300
- end
310
+ unless tund.closed? then
311
+ tund_info = @tund_infos[ tund ]
312
+ tund_info[ :dsts ].delete( dst_info[ :id ] )
313
+ tund_info[ :dst_ids ].delete( dst_info[ :src_id ] )
314
+ end
301
315
 
302
- ##
303
- # add proxyd ctlmsg
304
- #
305
- def add_proxyd_ctlmsg( data, to_addr )
306
- @proxyd_ctlmsgs << [ to_addr, data ]
307
- add_write( @proxyd )
316
+ dst_info
308
317
  end
309
318
 
310
319
  ##
311
- # add tund ctlmsg
320
+ # loop check expire
312
321
  #
313
- def add_tund_ctlmsg( tund, data )
314
- tund_info = @tund_infos[ tund ]
315
- tund_info[ :ctlmsgs ] << data
316
- add_write( tund )
317
- end
322
+ def loop_check_expire
323
+ Thread.new do
324
+ loop do
325
+ sleep CHECK_EXPIRE_INTERVAL
318
326
 
319
- ##
320
- # add tund wbuff
321
- #
322
- def add_tund_wbuff( tund, dst_local_port, pack_id, data )
323
- tund_info = @tund_infos[ tund ]
324
- tund_info[ :wbuffs ] << [ dst_local_port, pack_id, data ]
325
-
326
- if tund_info[ :wbuffs ].size >= WBUFFS_LIMIT
327
- spring = tund_info[ :chunks ].size > 0 ? ( tund_info[ :spring ] + 1 ) : 0
328
- filename = "#{ Process.pid }-#{ tund_info[ :port ] }.#{ spring }"
329
- chunk_path = File.join( @tund_chunk_dir, filename )
330
- datas = tund_info[ :wbuffs ].map{ | _dst_local_port, _pack_id, _data | [ [ _dst_local_port, _pack_id, _data.bytesize ].pack( 'nQ>n' ), _data ].join }
331
-
332
- begin
333
- IO.binwrite( chunk_path, datas.join )
334
- rescue Errno::ENOSPC => e
335
- puts "p#{ Process.pid } #{ Time.new } #{ e.class }, close tund"
336
- set_is_closing( tund )
337
- return
338
- end
327
+ @mutex.synchronize do
328
+ trigger = false
329
+ now = Time.new
339
330
 
340
- tund_info[ :chunks ] << filename
341
- tund_info[ :spring ] = spring
342
- tund_info[ :wbuffs ].clear
343
- end
331
+ @tund_infos.each do | tund, tund_info |
332
+ last_recv_at = tund_info[ :last_recv_at ] || tund_info[ :created_at ]
333
+ last_sent_at = tund_info[ :last_sent_at ] || tund_info[ :created_at ]
344
334
 
345
- add_write( tund )
335
+ if tund_info[ :dsts ].empty? && ( now - last_recv_at >= EXPIRE_AFTER ) && ( now - last_sent_at >= EXPIRE_AFTER ) then
336
+ puts "p#{ Process.pid } #{ Time.new } expire tund #{ tund_info[ :port ] }"
337
+ set_tund_closing( tund )
338
+ trigger = true
339
+ end
340
+ end
341
+
342
+ @dst_infos.each do | dst, dst_info |
343
+ last_recv_at = dst_info[ :last_recv_at ] || dst_info[ :created_at ]
344
+ last_sent_at = dst_info[ :last_sent_at ] || dst_info[ :created_at ]
345
+
346
+ if ( now - last_recv_at >= EXPIRE_AFTER ) && ( now - last_sent_at >= EXPIRE_AFTER ) then
347
+ puts "p#{ Process.pid } #{ Time.new } expire dst #{ dst_info[ :domain_port ] }"
348
+ set_dst_closing( dst )
349
+ trigger = true
350
+ end
351
+ end
352
+
353
+ next_tick if trigger
354
+ end
355
+ end
356
+ end
346
357
  end
347
358
 
348
359
  ##
349
- # add dst wbuff
360
+ # loop check resume
350
361
  #
351
- def add_dst_wbuff( dst, data )
352
- dst_info = @dst_infos[ dst ]
353
- dst_info[ :wbuff ] << data
354
-
355
- if dst_info[ :wbuff ].bytesize >= CHUNK_SIZE
356
- spring = dst_info[ :chunks ].size > 0 ? ( dst_info[ :spring ] + 1 ) : 0
357
- filename = "#{ Process.pid }-#{ dst_info[ :local_port ] }.#{ spring }"
358
- chunk_path = File.join( @dst_chunk_dir, filename )
359
-
360
- begin
361
- IO.binwrite( chunk_path, dst_info[ :wbuff ] )
362
- rescue Errno::ENOSPC => e
363
- puts "p#{ Process.pid } #{ Time.new } #{ e.class }, close dst"
364
- set_is_closing( dst )
365
- return
366
- end
362
+ def loop_check_resume
363
+ Thread.new do
364
+ loop do
365
+ sleep CHECK_RESUME_INTERVAL
367
366
 
368
- dst_info[ :chunks ] << filename
369
- dst_info[ :spring ] = spring
370
- dst_info[ :wbuff ].clear
371
- end
367
+ @mutex.synchronize do
368
+ trigger = false
372
369
 
373
- add_write( dst )
370
+ @dst_infos.select{ | _, dst_info | dst_info[ :paused ] }.each do | dst, dst_info |
371
+ streamd = dst_info[ :streamd ]
372
+ streamd_info = @streamd_infos[ streamd ]
373
+
374
+ if streamd_info[ :wbuff ].size < RESUME_BELOW then
375
+ puts "p#{ Process.pid } #{ Time.new } resume dst #{ dst_info[ :domain_port ] }"
376
+ dst_info[ :paused ] = false
377
+ add_read( dst )
378
+ trigger = true
379
+ end
380
+ end
381
+
382
+ next_tick if trigger
383
+ end
384
+ end
385
+ end
374
386
  end
375
387
 
376
388
  ##
377
- # add read
389
+ # new a proxyd
378
390
  #
379
- def add_read( sock, role )
380
- unless @reads.include?( sock )
381
- @reads << sock
382
- end
391
+ def new_a_proxyd( proxyd_port )
392
+ proxyd = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
393
+ proxyd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 )
394
+ proxyd.bind( Socket.sockaddr_in( proxyd_port, '0.0.0.0' ) )
395
+
396
+ puts "p#{ Process.pid } #{ Time.new } proxyd bind on #{ proxyd_port }"
397
+ @proxyd = proxyd
398
+ @proxyd_info = {
399
+ ctlmsgs: [] # [ ctlmsg, to_addr ]
400
+ }
383
401
 
384
- @roles[ sock ] = role
402
+ add_read( proxyd, :proxyd )
385
403
  end
386
404
 
387
405
  ##
388
- # add write
406
+ # next tick
389
407
  #
390
- def add_write( sock )
391
- if sock && !sock.closed? && !@writes.include?( sock )
392
- @writes << sock
393
- end
408
+ def next_tick
409
+ @dotw.write( '.' )
394
410
  end
395
411
 
396
412
  ##
397
- # set is closing
413
+ # resolve domain
398
414
  #
399
- def set_is_closing( sock )
400
- if sock && !sock.closed?
401
- role = @roles[ sock ]
402
- # puts "debug1 set #{ role.to_s } is closing"
415
+ def resolve_domain( tund, src_id, domain_port )
416
+ resolv_cache = @resolv_caches[ domain_port ]
417
+
418
+ if resolv_cache then
419
+ destination_addr, created_at = resolv_cache
420
+
421
+ if Time.new - created_at < RESOLV_CACHE_EXPIRE then
422
+ # puts "debug1 #{ domain_port } hit resolv cache #{ Addrinfo.new( destination_addr ).inspect }"
423
+ deal_with_destination_addr( tund, src_id, destination_addr, domain_port )
424
+ return
425
+ end
426
+
427
+ # puts "debug1 expire #{ domain_port } resolv cache"
428
+ @resolv_caches.delete( domain_port )
429
+ end
403
430
 
404
- case role
405
- when :dst
406
- dst_info = @dst_infos[ sock ]
407
- dst_info[ :is_closing ] = true
408
- when :tund
409
- tund_info = @tund_infos[ sock ]
410
- tund_info[ :is_closing ] = true
431
+ Thread.new do
432
+ colon_idx = domain_port.rindex( ':' )
433
+
434
+ if colon_idx then
435
+ destination_domain = domain_port[ 0...colon_idx ]
436
+ destination_port = domain_port[ ( colon_idx + 1 )..-1 ].to_i
437
+
438
+ begin
439
+ destination_addr = Socket.sockaddr_in( destination_port, destination_domain )
440
+ rescue Exception => e
441
+ puts "p#{ Process.pid } #{ Time.new } sockaddr in #{ domain_port } #{ e.class }"
442
+ end
411
443
  end
412
444
 
413
- @reads.delete( sock )
414
- add_write( sock )
445
+ @mutex.synchronize do
446
+ if destination_addr then
447
+ # puts "debug1 resolved #{ domain_port } #{ Addrinfo.new( destination_addr ).inspect }"
448
+ @resolv_caches[ domain_port ] = [ destination_addr, Time.new ]
449
+
450
+ unless tund.closed? then
451
+ if deal_with_destination_addr( tund, src_id, destination_addr, domain_port ) then
452
+ next_tick
453
+ end
454
+ end
455
+ end
456
+ end
415
457
  end
416
458
  end
417
459
 
@@ -420,358 +462,217 @@ module Girl
420
462
  #
421
463
  def send_data( sock, data, to_addr )
422
464
  begin
423
- sock.sendmsg( data, 0, to_addr )
465
+ written = sock.sendmsg_nonblock( data, 0, to_addr )
424
466
  rescue IO::WaitWritable, Errno::EINTR
425
- return false
467
+ return :wait
426
468
  rescue Errno::EHOSTUNREACH, Errno::ENETUNREACH, Errno::ENETDOWN => e
427
- if @roles[ sock ] == :tund
428
- puts "#{ Time.new } #{ e.class }, close tund"
429
- close_tund( sock )
430
- return false
431
- end
469
+ puts "p#{ Process.pid } #{ Time.new } sendmsg #{ e.class }"
470
+ return :fatal
432
471
  end
433
472
 
434
- true
473
+ written
435
474
  end
436
475
 
437
476
  ##
438
- # close dst
477
+ # set dst closing
439
478
  #
440
- def close_dst( dst )
441
- # puts "debug1 close dst"
442
- close_sock( dst )
443
- dst_info = @dst_infos.delete( dst )
444
-
445
- dst_info[ :chunks ].each do | filename |
446
- begin
447
- File.delete( File.join( @dst_chunk_dir, filename ) )
448
- rescue Errno::ENOENT
449
- end
450
- end
479
+ def set_dst_closing( dst )
480
+ return if dst.closed?
481
+ dst_info = @dst_infos[ dst ]
482
+ dst_info[ :closing ] = true
483
+ @reads.delete( dst )
484
+ add_write( dst )
485
+ end
451
486
 
452
- tund = dst_info[ :tund ]
453
- return if tund.closed?
487
+ ##
488
+ # set dst closing write
489
+ #
490
+ def set_dst_closing_write( dst )
491
+ return if dst.closed?
492
+ dst_info = @dst_infos[ dst ]
493
+ dst_info[ :closing_write ] = true
494
+ add_write( dst )
495
+ end
454
496
 
455
- tund_info = @tund_infos[ tund ]
456
- local_port = dst_info[ :local_port ]
457
- dst_ext = tund_info[ :dst_exts ][ local_port ]
458
- return unless dst_ext
459
-
460
- if dst_ext[ :is_src_closed ]
461
- # puts "debug1 4-3. after close dst -> src closed ? yes -> del dst ext -> send fin2"
462
- del_dst_ext( tund, local_port )
463
- data = [ 0, FIN2, local_port ].pack( 'Q>Cn' )
464
- add_tund_ctlmsg( tund, data )
465
- else
466
- # puts "debug1 3-1. after close dst -> src closed ? no -> send fin1"
467
- data = [ 0, FIN1, local_port, dst_info[ :biggest_pack_id ], dst_ext[ :continue_src_pack_id ] ].pack( 'Q>CnQ>Q>' )
468
- add_tund_ctlmsg( tund, data )
469
- end
497
+ ##
498
+ # set streamd closing
499
+ #
500
+ def set_streamd_closing( streamd )
501
+ return if streamd.closed?
502
+ streamd_info = @streamd_infos[ streamd ]
503
+ streamd_info[ :closing ] = true
504
+ @reads.delete( streamd )
505
+ add_write( streamd )
470
506
  end
471
507
 
472
508
  ##
473
- # close tun
509
+ # set streamd closing write
474
510
  #
475
- def close_tund( tund )
476
- # puts "debug1 close tund"
477
- close_sock( tund )
478
-
479
- tund_info = @tund_infos.delete( tund )
480
- tund_info[ :chunks ].each do | filename |
481
- begin
482
- File.delete( File.join( @tund_chunk_dir, filename ) )
483
- rescue Errno::ENOENT
484
- end
485
- end
486
-
487
- tund_info[ :dst_exts ].each{ | _, dst_ext | set_is_closing( dst_ext[ :dst ] ) }
488
- @tunneling_tunds.delete( tund_info[ :tun_addr ] )
489
- @tunds.delete( tund_info[ :port ] )
511
+ def set_streamd_closing_write( streamd )
512
+ return if streamd.closed?
513
+ streamd_info = @streamd_infos[ streamd ]
514
+ streamd_info[ :closing_write ] = true
515
+ add_write( streamd )
490
516
  end
491
517
 
492
518
  ##
493
- # close sock
519
+ # set tund is closing
494
520
  #
495
- def close_sock( sock )
496
- sock.close
497
- @reads.delete( sock )
498
- @writes.delete( sock )
499
- @roles.delete( sock )
521
+ def set_tund_closing( tund )
522
+ return if tund.closed?
523
+ tund_info = @tund_infos[ tund ]
524
+ tund_info[ :closing ] = true
525
+ @reads.delete( tund )
526
+ add_write( tund )
500
527
  end
501
528
 
502
529
  ##
503
- # del dst ext
530
+ # read dotr
504
531
  #
505
- def del_dst_ext( tund, dst_local_port )
506
- tund_info = @tund_infos[ tund ]
507
- dst_ext = tund_info[ :dst_exts ].delete( dst_local_port )
508
-
509
- if dst_ext
510
- tund_info[ :dst_local_ports ].delete( dst_ext[ :src_id ] )
511
- end
532
+ def read_dotr( dotr )
533
+ dotr.read( 1 )
512
534
  end
513
535
 
514
536
  ##
515
- # release wmems
537
+ # read proxyd
516
538
  #
517
- def release_wmems( dst_ext, completed_pack_id )
518
- if completed_pack_id > dst_ext[ :completed_pack_id ]
519
- # puts "debug2 update completed pack #{ completed_pack_id }"
539
+ def read_proxyd( proxyd )
540
+ data, addrinfo, rflags, *controls = proxyd.recvmsg
541
+ from_addr = addrinfo.to_sockaddr
520
542
 
521
- pack_ids = dst_ext[ :wmems ].keys.select { | pack_id | pack_id <= completed_pack_id }
543
+ if @tunneling_tunds.include?( from_addr ) then
544
+ tund = @tunneling_tunds[ from_addr ]
545
+ tund_info = @tund_infos[ tund ]
546
+ puts "p#{ Process.pid } #{ Time.new } resend tund port #{ tund_info[ :port ] }, #{ tund_info[ :stream_port ] }"
547
+ add_proxyd_ctlmsg_tund_port( tund_info )
548
+ return
549
+ end
522
550
 
523
- pack_ids.each do | pack_id |
524
- dst_ext[ :wmems ].delete( pack_id )
525
- dst_ext[ :send_ats ].delete( pack_id )
526
- end
551
+ result = @custom.check( data, addrinfo )
527
552
 
528
- dst_ext[ :completed_pack_id ] = completed_pack_id
553
+ if result != :success then
554
+ puts "p#{ Process.pid } #{ Time.new } #{ result }"
555
+ return
529
556
  end
530
- end
531
557
 
532
- ##
533
- # next tick
534
- #
535
- def next_tick
536
- @dotw.write( '.' )
537
- end
538
-
539
- ##
540
- # write proxyd
541
- #
542
- def write_proxyd( proxyd )
543
- while @proxyd_ctlmsgs.any?
544
- to_addr, data = @proxyd_ctlmsgs.first
558
+ tund = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
559
+ tund.bind( Socket.sockaddr_in( 0, '0.0.0.0' ) )
560
+ tund_port = tund.local_address.ip_port
561
+ add_read( tund, :tund )
545
562
 
546
- unless send_data( proxyd, data, to_addr )
547
- return
548
- end
563
+ tcpd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
564
+ tcpd.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 ) if RUBY_PLATFORM.include?( 'linux' )
565
+ tcpd.bind( Socket.sockaddr_in( 0, '0.0.0.0' ) )
566
+ tcpd_port = tcpd.local_address.ip_port
567
+ tcpd.listen( 127 )
568
+ add_read( tcpd, :tcpd )
569
+
570
+ tund_info = {
571
+ port: tund_port, # 端口
572
+ tcpd: tcpd, # 对应的tcpd
573
+ tcpd_port: tcpd_port, # tcpd端口
574
+ ctlmsgs: [], # [ ctlmsg, to_addr ]
575
+ tun_addr: from_addr, # tun地址
576
+ dsts: {}, # dst_id => dst
577
+ dst_ids: {}, # src_id => dst_id
578
+ created_at: Time.new, # 创建时间
579
+ last_recv_at: nil, # 上一次收到流量的时间
580
+ last_sent_at: nil, # 上一次发出流量的时间
581
+ closing: false, # 准备关闭
582
+ closing_read: false, # 准备关闭读
583
+ closing_write: false, # 准备关闭写
584
+ changed_tun_addr: nil # 记录到和tun addr不符的来源地址
585
+ }
549
586
 
550
- @proxyd_ctlmsgs.shift
551
- end
587
+ @tunneling_tunds[ from_addr ] = tund
588
+ @tund_infos[ tund ] = tund_info
589
+ @tcpd_infos[ tcpd ] = {
590
+ tund: tund
591
+ }
552
592
 
553
- @writes.delete( proxyd )
593
+ puts "p#{ Process.pid } #{ Time.new } a new tunnel #{ addrinfo.ip_unpack.inspect } - #{ tund_port }, #{ tcpd_port }, #{ @tund_infos.size } tunds"
594
+ add_proxyd_ctlmsg_tund_port( tund_info )
554
595
  end
555
596
 
556
597
  ##
557
- # write dst
598
+ # read tund
558
599
  #
559
- def write_dst( dst )
560
- dst_info = @dst_infos[ dst ]
561
- from, data = :cache, dst_info[ :cache ]
562
-
563
- if data.empty?
564
- if dst_info[ :chunks ].any?
565
- path = File.join( @dst_chunk_dir, dst_info[ :chunks ].shift )
566
-
567
- begin
568
- data = dst_info[ :cache ] = IO.binread( path )
569
- File.delete( path )
570
- rescue Errno::ENOENT => e
571
- puts "p#{ Process.pid } #{ Time.new } read #{ path } #{ e.class }"
572
- close_dst( dst )
573
- return
574
- end
575
- else
576
- from, data = :wbuff, dst_info[ :wbuff ]
577
- end
578
- end
579
-
580
- if data.empty?
581
- if dst_info[ :is_closing ]
582
- close_dst( dst )
583
- else
584
- @writes.delete( dst )
585
- end
586
-
587
- return
588
- end
589
-
600
+ def read_tund( tund )
590
601
  begin
591
- written = dst.write_nonblock( data )
592
- rescue IO::WaitWritable, Errno::EINTR
593
- return
594
- rescue Exception => e
595
- # puts "debug1 write dst #{ e.class }"
596
- close_dst( dst )
602
+ data, addrinfo, rflags, *controls = tund.recvmsg_nonblock
603
+ rescue IO::WaitReadable, Errno::EINTR
604
+ print 'r'
597
605
  return
598
606
  end
599
607
 
600
- # puts "debug2 write dst #{ written }"
601
- data = data[ written..-1 ]
602
- dst_info[ from ] = data
603
- dst_info[ :last_continue_at ] = Time.new
604
- end
605
-
606
- ##
607
- # write tund
608
- #
609
- def write_tund( tund )
610
- now = Time.new
608
+ from_addr = addrinfo.to_sockaddr
611
609
  tund_info = @tund_infos[ tund ]
612
610
 
613
- if tund_info[ :is_closing ]
614
- if tund_info[ :changed_tun_addr ]
615
- data = [ 0, IP_CHANGED ].pack( 'Q>C' )
616
- send_data( tund, data, tund_info[ :changed_tun_addr ] )
617
- end
618
-
619
- close_tund( tund )
611
+ if from_addr != tund_info[ :tun_addr ] then
612
+ # 通常是光猫刷新ip和端口,但万一不是,为了避免脏数据注入,关闭tund
613
+ puts "p#{ Process.pid } #{ Time.new } from #{ addrinfo.inspect } not match tun addr #{ Addrinfo.new( tund_info[ :tun_addr ] ).inspect }"
614
+ tund_info[ :changed_tun_addr ] = from_addr
615
+ set_tund_closing( tund )
620
616
  return
621
617
  end
622
618
 
623
- # 传ctlmsg
624
- while tund_info[ :ctlmsgs ].any?
625
- data = tund_info[ :ctlmsgs ].first
626
-
627
- unless send_data( tund, data, tund_info[ :tun_addr ] )
628
- return
629
- end
630
-
631
- tund_info[ :ctlmsgs ].shift
632
- end
619
+ tund_info[ :last_recv_at ] = Time.new
620
+ pack_id = data[ 0, 8 ].unpack( 'Q>' ).first
621
+ return if pack_id != 0
633
622
 
634
- # 重传
635
- while tund_info[ :resendings ].any?
636
- dst_local_port, pack_id = tund_info[ :resendings ].first
637
- dst_ext = tund_info[ :dst_exts ][ dst_local_port ]
623
+ ctl_num = data[ 8 ].unpack( 'C' ).first
638
624
 
639
- if dst_ext
640
- data = dst_ext[ :wmems ][ pack_id ]
625
+ case ctl_num
626
+ when A_NEW_SOURCE then
627
+ src_id = data[ 9, 8 ].unpack( 'Q>' ).first
628
+ dst_id = tund_info[ :dst_ids ][ src_id ]
641
629
 
642
- if data
643
- unless send_data( tund, data, tund_info[ :tun_addr ] )
644
- return
645
- end
630
+ if dst_id then
631
+ dst = tund_info[ :dsts ][ dst_id ]
632
+ return unless dst
646
633
 
647
- dst_ext[ :last_continue_at ] = now
634
+ if dst.closed? then
635
+ dst_id = 0
648
636
  end
649
- end
650
637
 
651
- tund_info[ :resendings ].shift
652
- end
653
-
654
- # 若写后达到上限,暂停取写前
655
- if tund_info[ :dst_exts ].map{ | _, dst_ext | dst_ext[ :wmems ].size }.sum >= WMEMS_LIMIT
656
- unless tund_info[ :paused ]
657
- puts "p#{ Process.pid } #{ Time.new } pause tund #{ tund_info[ :port ] }"
658
- tund_info[ :paused ] = true
659
- end
660
-
661
- @writes.delete( tund )
662
- return
663
- end
664
-
665
- # 取写前
666
- if tund_info[ :caches ].any?
667
- datas = tund_info[ :caches ]
668
- elsif tund_info[ :chunks ].any?
669
- path = File.join( @tund_chunk_dir, tund_info[ :chunks ].shift )
670
-
671
- begin
672
- data = IO.binread( path )
673
- File.delete( path )
674
- rescue Errno::ENOENT => e
675
- puts "p#{ Process.pid } #{ Time.new } read #{ path } #{ e.class }"
676
- close_tund( tund )
638
+ # puts "debug1 resend paired #{ dst_id }"
639
+ data2 = [ 0, PAIRED, src_id, dst_id ].pack( 'Q>CQ>n' )
640
+ add_ctlmsg( tund, data2 )
677
641
  return
678
642
  end
679
643
 
680
- caches = []
681
-
682
- until data.empty?
683
- _dst_local_port, _pack_id, pack_size = data[ 0, 12 ].unpack( 'nQ>n' )
684
- caches << [ _dst_local_port, _pack_id, data[ 12, pack_size ] ]
685
- data = data[ ( 12 + pack_size )..-1 ]
686
- end
687
-
688
- datas = tund_info[ :caches ] = caches
689
- elsif tund_info[ :wbuffs ].any?
690
- datas = tund_info[ :wbuffs ]
691
- else
692
- @writes.delete( tund )
693
- return
644
+ data = data[ 17..-1 ]
645
+ domain_port = @custom.decode( data )
646
+ # puts "debug1 a new source #{ src_id } #{ domain_port }"
647
+ resolve_domain( tund, src_id, domain_port )
648
+ when TUN_FIN then
649
+ puts "p#{ Process.pid } #{ Time.new } recv tun fin"
650
+ set_tund_closing( tund )
694
651
  end
695
-
696
- while datas.any?
697
- dst_local_port, pack_id, data = datas.first
698
- dst_ext = tund_info[ :dst_exts ][ dst_local_port ]
699
-
700
- if dst_ext
701
- if pack_id <= CONFUSE_UNTIL
702
- data = @custom.encode( data )
703
- # puts "debug1 encoded pack #{ pack_id }"
704
- end
705
-
706
- data = [ [ pack_id, dst_local_port ].pack( 'Q>n' ), data ].join
707
-
708
- unless send_data( tund, data, tund_info[ :tun_addr ] )
709
- return
710
- end
711
-
712
- # puts "debug2 written pack #{ pack_id }"
713
- dst_ext[ :relay_pack_id ] = pack_id
714
- dst_ext[ :wmems ][ pack_id ] = data
715
- dst_ext[ :send_ats ][ pack_id ] = now
716
- dst_ext[ :last_continue_at ] = now
717
- end
718
-
719
- datas.shift
720
- end
721
- end
722
-
723
- ##
724
- # read dotr
725
- #
726
- def read_dotr( dotr )
727
- dotr.read( 1 )
728
652
  end
729
653
 
730
654
  ##
731
- # read proxyd
655
+ # read tcpd
732
656
  #
733
- def read_proxyd( proxyd )
734
- data, addrinfo, rflags, *controls = proxyd.recvmsg
735
- from_addr = addrinfo.to_sockaddr
736
-
737
- return if @tunneling_tunds.include?( from_addr )
738
-
739
- result = @custom.check( data, addrinfo )
740
-
741
- if result != :success
742
- puts "p#{ Process.pid } #{ Time.new } #{ result }"
657
+ def read_tcpd( tcpd )
658
+ begin
659
+ streamd, addrinfo = tcpd.accept_nonblock
660
+ rescue IO::WaitReadable, Errno::EINTR
661
+ print 'r'
743
662
  return
744
663
  end
745
664
 
746
- tund = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
747
- tund.bind( Socket.sockaddr_in( 0, '0.0.0.0' ) )
748
- port = tund.local_address.ip_port
665
+ # puts "debug1 accept a streamd"
666
+ tcpd_info = @tcpd_infos[ tcpd ]
667
+ tund = tcpd_info[ :tund ]
749
668
 
750
- @tunneling_tunds[ from_addr ] = tund
751
- @tunds[ port ] = tund
752
- @tund_infos[ tund ] = {
753
- port: port, # 端口
754
- ctlmsgs: [], # data
755
- wbuffs: [], # 写前缓存 [ dst_local_port, pack_id, data ]
756
- caches: [], # 块读出缓存 [ dst_local_port, pack_id, data ]
757
- chunks: [], # 块队列 filename
758
- spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
759
- tun_addr: from_addr, # tun地址
760
- dst_exts: {}, # dst额外信息 dst_local_port => {}
761
- dst_local_ports: {}, # src_id => dst_local_port
762
- paused: false, # 是否暂停写
763
- resendings: [], # 重传队列 [ dst_local_port, pack_id ]
764
- created_at: Time.new, # 创建时间
765
- last_recv_at: nil, # 上一次收到流量的时间,过期关闭
766
- is_closing: false, # 是否准备关闭
767
- changed_tun_addr: nil # 记录到和tun addr不符的来源地址
669
+ @streamd_infos[ streamd ] = {
670
+ tund: tund, # 对应tund
671
+ dst: nil, # 对应dst
672
+ wbuff: '' # 写前,写往近端stream
768
673
  }
769
674
 
770
- add_read( tund, :tund )
771
-
772
- data = [ 0, TUND_PORT, port ].pack( 'Q>Cn' )
773
- puts "p#{ Process.pid } #{ Time.new } a new tunnel #{ addrinfo.ip_unpack.inspect } - #{ port }, #{ @tunds.size } tunds"
774
- add_proxyd_ctlmsg( data, from_addr )
675
+ add_read( streamd, :streamd )
775
676
  end
776
677
 
777
678
  ##
@@ -779,211 +680,271 @@ module Girl
779
680
  #
780
681
  def read_dst( dst )
781
682
  begin
782
- data = dst.read_nonblock( PACK_SIZE )
683
+ data = dst.read_nonblock( READ_SIZE )
783
684
  rescue IO::WaitReadable, Errno::EINTR
685
+ print 'r'
784
686
  return
785
687
  rescue Exception => e
786
688
  # puts "debug1 read dst #{ e.class }"
787
- set_is_closing( dst )
689
+ dst_info = close_read_dst( dst )
690
+ streamd = dst_info[ :streamd ]
691
+ set_streamd_closing_write( streamd ) if streamd
788
692
  return
789
693
  end
790
694
 
791
- # puts "debug2 read dst #{ data.inspect }"
792
695
  dst_info = @dst_infos[ dst ]
793
- dst_info[ :last_continue_at ] = Time.new
794
- tund = dst_info[ :tund ]
696
+ streamd = dst_info[ :streamd ]
697
+
698
+ if streamd then
699
+ unless streamd.closed? then
700
+ streamd_info = @streamd_infos[ streamd ]
701
+ data = @custom.encode( data )
702
+ # puts "debug2 add streamd.wbuff encoded #{ data.bytesize }"
703
+ streamd_info[ :wbuff ] << data
704
+ add_write( streamd )
705
+
706
+ if streamd_info[ :wbuff ].bytesize >= WBUFF_LIMIT then
707
+ puts "p#{ Process.pid } #{ Time.new } pause dst #{ dst_info[ :id ] } #{ dst_info[ :domain_port ] }"
708
+ dst_info[ :paused ] = true
709
+ @reads.delete( dst )
710
+ end
711
+ end
712
+ else
713
+ dst_info[ :rbuff ] << data
795
714
 
796
- if tund.closed?
797
- puts "p#{ Process.pid } #{ Time.new } tund closed, close dst"
798
- set_is_closing( dst )
799
- return
715
+ if dst_info[ :rbuff ].bytesize >= WBUFF_LIMIT then
716
+ # puts "debug1 dst.rbuff full"
717
+ set_dst_closing( dst )
718
+ end
800
719
  end
801
-
802
- pack_id = dst_info[ :biggest_pack_id ] + 1
803
- dst_info[ :biggest_pack_id ] = pack_id
804
- add_tund_wbuff( tund, dst_info[ :local_port ], pack_id, data )
805
720
  end
806
721
 
807
722
  ##
808
- # read tund
723
+ # read streamd
809
724
  #
810
- def read_tund( tund )
811
- data, addrinfo, rflags, *controls = tund.recvmsg
812
- from_addr = addrinfo.to_sockaddr
813
- now = Time.new
814
- tund_info = @tund_infos[ tund ]
815
-
816
- if from_addr != tund_info[ :tun_addr ]
817
- # 通常是光猫刷新ip(端口也会变),但万一不是,为了避免脏数据注入,关闭tund
818
- puts "p#{ Process.pid } #{ Time.new } from #{ addrinfo.inspect } not match tun addr #{ Addrinfo.new( tund_info[ :tun_addr ] ).inspect }"
819
- tund_info[ :changed_tun_addr ] = from_addr
820
- set_is_closing( tund )
725
+ def read_streamd( streamd )
726
+ begin
727
+ data = streamd.read_nonblock( READ_SIZE )
728
+ rescue IO::WaitReadable, Errno::EINTR
729
+ print 'r'
730
+ return
731
+ rescue Exception => e
732
+ # puts "debug1 read streamd #{ e.class }"
733
+ streamd_info = close_read_streamd( streamd )
734
+ dst = streamd_info[ :dst ]
735
+ set_dst_closing_write( dst ) if dst
821
736
  return
822
737
  end
823
738
 
824
- tund_info[ :last_recv_at ] = now
825
- pack_id = data[ 0, 8 ].unpack( 'Q>' ).first
739
+ streamd_info = @streamd_infos[ streamd ]
740
+ dst = streamd_info[ :dst ]
826
741
 
827
- if pack_id == 0
828
- ctl_num = data[ 8 ].unpack( 'C' ).first
742
+ unless dst then
743
+ dst_id = data[ 0, 2 ].unpack( 'n' ).first
744
+ tund = streamd_info[ :tund ]
829
745
 
830
- case ctl_num
831
- when A_NEW_SOURCE
832
- src_id = data[ 9, 8 ].unpack( 'Q>' ).first
833
- dst_local_port = tund_info[ :dst_local_ports ][ src_id ]
834
-
835
- if dst_local_port
836
- dst_ext = tund_info[ :dst_exts ][ dst_local_port ]
837
- return unless dst_ext
838
-
839
- if dst_ext[ :dst ].closed?
840
- dst_local_port = 0
841
- end
746
+ if tund.closed? then
747
+ set_streamd_closing( streamd )
748
+ return
749
+ end
842
750
 
843
- # puts "debug1 readd ctlmsg paired #{ dst_local_port }"
844
- data2 = [ 0, PAIRED, src_id, dst_local_port ].pack( 'Q>CQ>n' )
845
- add_tund_ctlmsg( tund, data2 )
846
- return
847
- end
751
+ tund_info = @tund_infos[ tund ]
752
+ dst = tund_info[ :dsts ][ dst_id ]
848
753
 
849
- data = data[ 17..-1 ]
850
- destination_domain_port = @custom.decode( data )
851
- puts "p#{ Process.pid } #{ Time.new } a new source #{ src_id } #{ destination_domain_port }"
852
- resolve_domain( tund, src_id, destination_domain_port )
853
- when SOURCE_STATUS
854
- src_id, relay_src_pack_id, continue_dst_pack_id = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
754
+ unless dst then
755
+ set_streamd_closing( streamd )
756
+ return
757
+ end
855
758
 
856
- dst_local_port = tund_info[ :dst_local_ports ][ src_id ]
857
- return unless dst_local_port
759
+ # puts "debug1 set streamd.dst #{ dst_id }"
760
+ streamd_info[ :dst ] = dst
761
+ dst_info = @dst_infos[ dst ]
858
762
 
859
- dst_ext = tund_info[ :dst_exts ][ dst_local_port ]
860
- return unless dst_ext
763
+ unless dst_info[ :rbuff ].empty? then
764
+ # puts "debug1 encode and move dst.rbuff to streamd.wbuff"
765
+ streamd_info[ :wbuff ] << @custom.encode( dst_info[ :rbuff ] )
766
+ end
861
767
 
862
- # puts "debug2 got source status"
768
+ dst_info[ :streamd ] = streamd
769
+ data = data[ 2..-1 ]
863
770
 
864
- release_wmems( dst_ext, continue_dst_pack_id )
771
+ return if data.empty?
772
+ end
865
773
 
866
- # 发miss
867
- if !dst_ext[ :dst ].closed? && ( dst_ext[ :continue_src_pack_id ] < relay_src_pack_id )
868
- ranges = []
869
- ignored = false
870
- curr_pack_id = dst_ext[ :continue_src_pack_id ] + 1
774
+ unless dst.closed? then
775
+ dst_info = @dst_infos[ dst ]
776
+ data = @custom.decode( data )
777
+ # puts "debug2 add dst.wbuff decoded #{ data.bytesize }"
778
+ dst_info[ :wbuff ] << data
779
+ dst_info[ :last_recv_at ] = Time.new
780
+ add_write( dst )
781
+ end
782
+ end
871
783
 
872
- dst_ext[ :pieces ].keys.sort.each do | pack_id |
873
- if pack_id > curr_pack_id
874
- ranges << [ curr_pack_id, pack_id - 1 ]
784
+ ##
785
+ # write proxyd
786
+ #
787
+ def write_proxyd( proxyd )
788
+ # 发ctlmsg
789
+ while @proxyd_info[ :ctlmsgs ].any? do
790
+ data, to_addr = @proxyd_info[ :ctlmsgs ].first
791
+ sent = send_data( proxyd, data, to_addr )
875
792
 
876
- if ranges.size >= MISS_RANGE_LIMIT
877
- puts "p#{ Process.pid } #{ Time.new } break add miss range at #{ pack_id }"
878
- ignored = true
879
- break
880
- end
881
- end
793
+ if sent == :wait then
794
+ puts "p#{ Process.pid } #{ Time.new } wait proxyd send ctlmsg, left #{ @proxyd_info[ :ctlmsgs ].size }"
795
+ return
796
+ else
797
+ @proxyd_info[ :ctlmsgs ].shift
798
+ end
799
+ end
882
800
 
883
- curr_pack_id = pack_id + 1
884
- end
801
+ @writes.delete( proxyd )
802
+ end
885
803
 
886
- if !ignored && ( curr_pack_id <= relay_src_pack_id )
887
- ranges << [ curr_pack_id, relay_src_pack_id ]
888
- end
804
+ ##
805
+ # write tund
806
+ #
807
+ def write_tund( tund )
808
+ tund_info = @tund_infos[ tund ]
889
809
 
890
- # puts "debug1 continue/relay #{ dst_ext[ :continue_src_pack_id ] }/#{ relay_src_pack_id } send MISS #{ ranges.size }"
810
+ # 处理关闭
811
+ if tund_info[ :closing ] then
812
+ if tund_info[ :changed_tun_addr ] then
813
+ data = [ 0, IP_CHANGED ].pack( 'Q>C' )
814
+ send_data( tund, data, tund_info[ :changed_tun_addr ] )
815
+ end
891
816
 
892
- ranges.each do | pack_id_begin, pack_id_end |
893
- data2 = [ 0, MISS, src_id, pack_id_begin, pack_id_end ].pack( 'Q>CQ>Q>Q>' )
894
- add_tund_ctlmsg( tund, data2 )
895
- end
896
- end
897
- when MISS
898
- return if tund_info[ :resendings ].size >= RESENDING_LIMIT
817
+ close_tund( tund )
818
+ return
819
+ end
899
820
 
900
- dst_local_port, pack_id_begin, pack_id_end = data[ 9, 18 ].unpack( 'nQ>Q>' )
821
+ now = Time.new
901
822
 
902
- dst_ext = tund_info[ :dst_exts ][ dst_local_port ]
903
- return unless dst_ext
823
+ # 发ctlmsg
824
+ while tund_info[ :ctlmsgs ].any? do
825
+ data = tund_info[ :ctlmsgs ].first
826
+ sent = send_data( tund, data, tund_info[ :tun_addr ] )
904
827
 
905
- ( pack_id_begin..pack_id_end ).each do | pack_id |
906
- send_at = dst_ext[ :send_ats ][ pack_id ]
828
+ if sent == :fatal then
829
+ close_tund( tund )
830
+ return
831
+ elsif sent == :wait then
832
+ puts "p#{ Process.pid } #{ Time.new } wait tund #{ tund_info[ :port ] } send ctlmsg, left #{ tund_info[ :ctlmsgs ].size }"
833
+ tund_info[ :last_sent_at ] = now
834
+ return
835
+ end
907
836
 
908
- if send_at
909
- break if now - send_at < CHECK_STATUS_INTERVAL
910
- tund_info[ :resendings ] << [ dst_local_port, pack_id ]
911
- end
912
- end
837
+ tund_info[ :ctlmsgs ].shift
838
+ end
913
839
 
914
- add_write( tund )
915
- when FIN1
916
- src_id, biggest_src_pack_id, continue_dst_pack_id = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
840
+ tund_info[ :last_sent_at ] = now
841
+ @writes.delete( tund )
842
+ end
917
843
 
918
- dst_local_port = tund_info[ :dst_local_ports ][ src_id ]
919
- return unless dst_local_port
844
+ ##
845
+ # write dst
846
+ #
847
+ def write_dst( dst )
848
+ return if dst.closed?
849
+ dst_info = @dst_infos[ dst ]
850
+ streamd = dst_info[ :streamd ]
920
851
 
921
- dst_ext = tund_info[ :dst_exts ][ dst_local_port ]
922
- return unless dst_ext
852
+ # 处理关闭
853
+ if dst_info[ :closing ] then
854
+ close_dst( dst )
923
855
 
924
- # puts "debug1 got fin1 #{ src_id } biggest src pack #{ biggest_src_pack_id } completed dst pack #{ continue_dst_pack_id }"
925
- dst_ext[ :is_src_closed ] = true
926
- dst_ext[ :biggest_src_pack_id ] = biggest_src_pack_id
927
- release_wmems( dst_ext, continue_dst_pack_id )
856
+ if streamd then
857
+ close_read_streamd( streamd )
858
+ set_streamd_closing_write( streamd )
859
+ end
928
860
 
929
- if biggest_src_pack_id == dst_ext[ :continue_src_pack_id ]
930
- # puts "debug1 4-1. tund recv fin1 -> all traffic received ? -> close dst after write"
931
- set_is_closing( dst_ext[ :dst ] )
932
- end
933
- when FIN2
934
- src_id = data[ 9, 8 ].unpack( 'Q>' ).first
861
+ return
862
+ end
935
863
 
936
- dst_local_port = tund_info[ :dst_local_ports ][ src_id ]
937
- return unless dst_local_port
864
+ data = dst_info[ :wbuff ]
938
865
 
939
- # puts "debug1 3-2. tund recv fin2 -> del dst ext"
940
- del_dst_ext( tund, dst_local_port )
941
- when TUN_FIN
942
- puts "p#{ Process.pid } #{ Time.new } recv tun fin"
943
- set_is_closing( tund )
866
+ # 写前为空,处理关闭写
867
+ if data.empty? then
868
+ if dst_info[ :closing_write ] then
869
+ close_write_dst( dst )
870
+ else
871
+ @writes.delete( dst )
944
872
  end
945
873
 
946
874
  return
947
875
  end
948
876
 
949
- src_id = data[ 8, 8 ].unpack( 'Q>' ).first
950
-
951
- dst_local_port = tund_info[ :dst_local_ports ][ src_id ]
952
- return unless dst_local_port
877
+ # 写入
878
+ begin
879
+ written = dst.write_nonblock( data )
880
+ rescue IO::WaitWritable, Errno::EINTR
881
+ print 'w'
882
+ return
883
+ rescue Exception => e
884
+ # puts "debug1 write dst #{ e.class }"
885
+ close_write_dst( dst )
886
+ close_read_streamd( streamd ) if streamd
887
+ return
888
+ end
953
889
 
954
- dst_ext = tund_info[ :dst_exts ][ dst_local_port ]
955
- return if dst_ext.nil? || dst_ext[ :dst ].closed?
956
- return if ( pack_id <= dst_ext[ :continue_src_pack_id ] ) || dst_ext[ :pieces ].include?( pack_id )
890
+ # puts "debug2 written dst #{ written }"
891
+ data = data[ written..-1 ]
892
+ dst_info[ :wbuff ] = data
893
+ end
957
894
 
958
- data = data[ 16..-1 ]
959
- # puts "debug2 got pack #{ pack_id }"
895
+ ##
896
+ # write streamd
897
+ #
898
+ def write_streamd( streamd )
899
+ return if streamd.closed?
900
+ streamd_info = @streamd_infos[ streamd ]
901
+ dst = streamd_info[ :dst ]
902
+
903
+ # 处理关闭
904
+ if streamd_info[ :closing ] then
905
+ close_streamd( streamd )
906
+
907
+ if dst then
908
+ close_read_dst( dst )
909
+ set_dst_closing_write( dst )
910
+ end
960
911
 
961
- if pack_id <= CONFUSE_UNTIL
962
- # puts "debug2 #{ data.inspect }"
963
- data = @custom.decode( data )
964
- # puts "debug1 decoded pack #{ pack_id }"
912
+ return
965
913
  end
966
914
 
967
- # 放进写前,跳号放碎片缓存
968
- if pack_id - dst_ext[ :continue_src_pack_id ] == 1
969
- while dst_ext[ :pieces ].include?( pack_id + 1 )
970
- data << dst_ext[ :pieces ].delete( pack_id + 1 )
971
- pack_id += 1
915
+ data = streamd_info[ :wbuff ]
916
+
917
+ # 写前为空,处理关闭写
918
+ if data.empty? then
919
+ if streamd_info[ :closing_write ] then
920
+ close_write_streamd( streamd )
921
+ else
922
+ @writes.delete( streamd )
972
923
  end
973
924
 
974
- dst_ext[ :continue_src_pack_id ] = pack_id
975
- dst_ext[ :last_continue_at ] = now
976
- add_dst_wbuff( dst_ext[ :dst ], data )
977
- # puts "debug2 update continue src pack #{ pack_id }"
925
+ return
926
+ end
978
927
 
979
- # 接到流量,若对面已关闭,且流量正好收全,关闭dst
980
- if dst_ext[ :is_src_closed ] && ( pack_id == dst_ext[ :biggest_src_pack_id ] )
981
- # puts "debug1 4-2. tund recv traffic -> src closed and all traffic received ? -> close dst after write"
982
- set_is_closing( dst_ext[ :dst ] )
983
- return
984
- end
985
- else
986
- dst_ext[ :pieces ][ pack_id ] = data
928
+ # 写入
929
+ begin
930
+ written = streamd.write_nonblock( data )
931
+ rescue IO::WaitWritable, Errno::EINTR
932
+ print 'w'
933
+ return
934
+ rescue Exception => e
935
+ # puts "debug1 write streamd #{ e.class }"
936
+ close_write_streamd( streamd )
937
+ close_read_dst( dst ) if dst
938
+ return
939
+ end
940
+
941
+ # puts "debug2 written streamd #{ written }"
942
+ data = data[ written..-1 ]
943
+ streamd_info[ :wbuff ] = data
944
+
945
+ if dst && !dst.closed? then
946
+ dst_info = @dst_infos[ dst ]
947
+ dst_info[ :last_sent_at ] = Time.new
987
948
  end
988
949
  end
989
950