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