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