girl 9.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/girl.gemspec +30 -0
- data/lib/girl/dns.rb +137 -0
- data/lib/girl/head.rb +20 -0
- data/lib/girl/proxy.rb +191 -0
- data/lib/girl/proxy_worker.rb +1860 -0
- data/lib/girl/proxyd.rb +173 -0
- data/lib/girl/proxyd_worker.rb +1409 -0
- data/lib/girl/version.rb +3 -0
- data/lib/girl.rb +2 -0
- metadata +52 -0
@@ -0,0 +1,1409 @@
|
|
1
|
+
module Girl
|
2
|
+
class ProxydWorker
|
3
|
+
include Dns
|
4
|
+
|
5
|
+
def initialize(
|
6
|
+
proxyd_port,
|
7
|
+
memd_port,
|
8
|
+
nameservers,
|
9
|
+
reset_traff_day,
|
10
|
+
ims,
|
11
|
+
p2d_host,
|
12
|
+
p2d_port,
|
13
|
+
head_len,
|
14
|
+
h_a_new_source,
|
15
|
+
h_a_new_p2,
|
16
|
+
h_dst_close,
|
17
|
+
h_heartbeat,
|
18
|
+
h_p1_close,
|
19
|
+
h_p2_close,
|
20
|
+
h_p2_traffic,
|
21
|
+
h_p1_overflow,
|
22
|
+
h_p1_underhalf,
|
23
|
+
h_p2_overflow,
|
24
|
+
h_p2_underhalf,
|
25
|
+
h_query,
|
26
|
+
h_response,
|
27
|
+
h_src_close,
|
28
|
+
h_traffic,
|
29
|
+
h_src_overflow,
|
30
|
+
h_src_underhalf,
|
31
|
+
h_dst_overflow,
|
32
|
+
h_dst_underhalf,
|
33
|
+
expire_connecting,
|
34
|
+
expire_long_after,
|
35
|
+
expire_proxy_after,
|
36
|
+
expire_resolv_cache,
|
37
|
+
expire_short_after,
|
38
|
+
is_debug,
|
39
|
+
is_server_fastopen )
|
40
|
+
|
41
|
+
@nameserver_addrs = nameservers.map{ | n | Socket.sockaddr_in( 53, n ) }
|
42
|
+
@reset_traff_day = reset_traff_day
|
43
|
+
@update_roles = [ :dns, :dst, :mem, :p2, :proxy, :rsv ] # 参与淘汰的角色
|
44
|
+
@updates_limit = 1011 - ims.size # 淘汰池上限,1015(mac) - info, infod, memd, proxyd, p2ds(=ims)
|
45
|
+
@eliminate_count = 0 # 淘汰次数
|
46
|
+
@reads = [] # 读池
|
47
|
+
@writes = [] # 写池
|
48
|
+
@roles = {} # sock => :dns / :dst / :infod / :mem / :memd / :p2 / :p2d / :proxy / :proxyd / :rsv
|
49
|
+
@updates = {} # sock => updated_at
|
50
|
+
@proxy_infos = {} # proxy => { :addrinfo :im :paused_dsts :paused_p2s :rbuff :src_infos :wbuff }
|
51
|
+
@im_infos = {} # im => { :addrinfo :in :out :p2d :p2d_host :p2d_port :proxy }
|
52
|
+
@mem_infos = {} # mem => { :wbuff }
|
53
|
+
@dst_infos = {} # dst => { :closing :connected :domain :im :ip :overflowing :port :proxy :rbuffs :src_id :wbuff }
|
54
|
+
@dns_infos = {} # dns => { :domain :im :port :proxy :src_id }
|
55
|
+
@rsv_infos = {} # rsv => { :domain :im :near_id :proxy }
|
56
|
+
@resolv_caches = {} # domain => [ ip, created_at, im ]
|
57
|
+
@p2d_infos = {} # p2d => { :im }
|
58
|
+
@p2_infos = {} # p2 => { :addrinfo :closing :im :overflowing :p2_id :wbuff }
|
59
|
+
|
60
|
+
@head_len = head_len
|
61
|
+
@h_a_new_source = h_a_new_source
|
62
|
+
@h_a_new_p2 = h_a_new_p2
|
63
|
+
@h_dst_close = h_dst_close
|
64
|
+
@h_heartbeat = h_heartbeat
|
65
|
+
@h_p1_close = h_p1_close
|
66
|
+
@h_p2_close = h_p2_close
|
67
|
+
@h_p2_traffic = h_p2_traffic
|
68
|
+
@h_p1_overflow = h_p1_overflow
|
69
|
+
@h_p1_underhalf = h_p1_underhalf
|
70
|
+
@h_p2_overflow = h_p2_overflow
|
71
|
+
@h_p2_underhalf = h_p2_underhalf
|
72
|
+
@h_query = h_query
|
73
|
+
@h_response = h_response
|
74
|
+
@h_src_close = h_src_close
|
75
|
+
@h_traffic = h_traffic
|
76
|
+
@h_src_overflow = h_src_overflow
|
77
|
+
@h_src_underhalf = h_src_underhalf
|
78
|
+
@h_dst_overflow = h_dst_overflow
|
79
|
+
@h_dst_underhalf = h_dst_underhalf
|
80
|
+
@expire_connecting = expire_connecting
|
81
|
+
@expire_long_after = expire_long_after
|
82
|
+
@expire_proxy_after = expire_proxy_after
|
83
|
+
@expire_resolv_cache = expire_resolv_cache
|
84
|
+
@expire_short_after = expire_short_after
|
85
|
+
@is_debug = is_debug
|
86
|
+
@is_server_fastopen = is_server_fastopen
|
87
|
+
|
88
|
+
init_im_infos( ims, p2d_host, p2d_port )
|
89
|
+
new_a_proxyd( proxyd_port )
|
90
|
+
new_a_infod( proxyd_port )
|
91
|
+
new_a_memd( memd_port )
|
92
|
+
end
|
93
|
+
|
94
|
+
def looping
|
95
|
+
puts "looping"
|
96
|
+
loop_heartbeat
|
97
|
+
loop_check_traff
|
98
|
+
|
99
|
+
loop do
|
100
|
+
rs, ws = IO.select( @reads, @writes )
|
101
|
+
|
102
|
+
rs.each do | sock |
|
103
|
+
role = @roles[ sock ]
|
104
|
+
|
105
|
+
case role
|
106
|
+
when :dns then
|
107
|
+
read_dns( sock )
|
108
|
+
when :dst then
|
109
|
+
read_dst( sock )
|
110
|
+
when :infod then
|
111
|
+
read_infod( sock )
|
112
|
+
when :mem then
|
113
|
+
read_mem( sock )
|
114
|
+
when :memd then
|
115
|
+
read_memd( sock )
|
116
|
+
when :p2 then
|
117
|
+
read_p2( sock )
|
118
|
+
when :p2d then
|
119
|
+
read_p2d( sock )
|
120
|
+
when :rsv then
|
121
|
+
read_rsv( sock )
|
122
|
+
when :proxy then
|
123
|
+
read_proxy( sock )
|
124
|
+
when :proxyd then
|
125
|
+
read_proxyd( sock )
|
126
|
+
else
|
127
|
+
close_sock( sock )
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
ws.each do | sock |
|
132
|
+
role = @roles[ sock ]
|
133
|
+
|
134
|
+
case role
|
135
|
+
when :dst then
|
136
|
+
write_dst( sock )
|
137
|
+
when :mem then
|
138
|
+
write_mem( sock )
|
139
|
+
when :p2 then
|
140
|
+
write_p2( sock )
|
141
|
+
when :proxy then
|
142
|
+
write_proxy( sock )
|
143
|
+
else
|
144
|
+
close_sock( sock )
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
rescue Interrupt => e
|
149
|
+
puts e.class
|
150
|
+
quit!
|
151
|
+
end
|
152
|
+
|
153
|
+
def quit!
|
154
|
+
exit
|
155
|
+
end
|
156
|
+
|
157
|
+
private
|
158
|
+
|
159
|
+
def add_dst_wbuff( dst, data )
|
160
|
+
return if dst.nil? || dst.closed? || data.nil? || data.empty?
|
161
|
+
dst_info = @dst_infos[ dst ]
|
162
|
+
dst_info[ :wbuff ] << data
|
163
|
+
bytesize = dst_info[ :wbuff ].bytesize
|
164
|
+
im = dst_info[ :im ]
|
165
|
+
src_id = dst_info[ :src_id ]
|
166
|
+
domain = dst_info[ :domain ]
|
167
|
+
|
168
|
+
if bytesize >= CLOSE_ABOVE then
|
169
|
+
puts "close overflow dst #{ src_id } #{ domain }"
|
170
|
+
close_dst( dst )
|
171
|
+
return
|
172
|
+
end
|
173
|
+
|
174
|
+
if !dst_info[ :overflowing ] && ( bytesize >= WBUFF_LIMIT ) then
|
175
|
+
proxy = dst_info[ :proxy ]
|
176
|
+
puts "add h_dst_overflow #{ im } #{ src_id } #{ domain }"
|
177
|
+
msg = "#{ @h_dst_overflow }#{ [ src_id ].pack( 'Q>' ) }"
|
178
|
+
add_proxy_wbuff( proxy, pack_a_chunk( msg ) )
|
179
|
+
dst_info[ :overflowing ] = true
|
180
|
+
end
|
181
|
+
|
182
|
+
add_write( dst )
|
183
|
+
end
|
184
|
+
|
185
|
+
def add_mem_wbuff( mem, data )
|
186
|
+
return if mem.nil? || mem.closed? || data.nil? || data.empty?
|
187
|
+
mem_info = @mem_infos[ mem ]
|
188
|
+
mem_info[ :wbuff ] << data
|
189
|
+
add_write( mem )
|
190
|
+
end
|
191
|
+
|
192
|
+
def add_p2_wbuff( p2, data )
|
193
|
+
return if p2.nil? || p2.closed? || data.nil? || data.empty?
|
194
|
+
p2_info = @p2_infos[ p2 ]
|
195
|
+
im = p2_info[ :im ]
|
196
|
+
im_info = @im_infos[ im ]
|
197
|
+
|
198
|
+
unless im_info then
|
199
|
+
close_p2( p2 )
|
200
|
+
return
|
201
|
+
end
|
202
|
+
|
203
|
+
p2_info[ :wbuff ] << data
|
204
|
+
bytesize = p2_info[ :wbuff ].bytesize
|
205
|
+
p2_id = p2_info[ :p2_id ]
|
206
|
+
|
207
|
+
if bytesize >= CLOSE_ABOVE then
|
208
|
+
puts "close overflow p2 #{ p2_id }"
|
209
|
+
close_p2( p2 )
|
210
|
+
return
|
211
|
+
end
|
212
|
+
|
213
|
+
if !p2_info[ :overflowing ] && ( bytesize >= WBUFF_LIMIT ) then
|
214
|
+
proxy = im_info[ :proxy ]
|
215
|
+
puts "add h_p2_overflow #{ im } #{ p2_id }"
|
216
|
+
msg = "#{ @h_p2_overflow }#{ [ p2_id ].pack( 'Q>' ) }"
|
217
|
+
add_proxy_wbuff( proxy, pack_a_chunk( msg ) )
|
218
|
+
p2_info[ :overflowing ] = true
|
219
|
+
end
|
220
|
+
|
221
|
+
add_write( p2 )
|
222
|
+
end
|
223
|
+
|
224
|
+
def add_proxy_wbuff( proxy, data )
|
225
|
+
return if proxy.nil? || proxy.closed? || data.nil? || data.empty?
|
226
|
+
proxy_info = @proxy_infos[ proxy ]
|
227
|
+
proxy_info[ :wbuff ] << data
|
228
|
+
bytesize = proxy_info[ :wbuff ].bytesize
|
229
|
+
|
230
|
+
if bytesize >= CLOSE_ABOVE then
|
231
|
+
puts "close overflow proxy #{ proxy_info[ :im ] }"
|
232
|
+
close_proxy( proxy )
|
233
|
+
return
|
234
|
+
end
|
235
|
+
|
236
|
+
add_write( proxy )
|
237
|
+
end
|
238
|
+
|
239
|
+
def add_read( sock, role = nil )
|
240
|
+
return if sock.nil? || sock.closed? || @reads.include?( sock )
|
241
|
+
@reads << sock
|
242
|
+
|
243
|
+
if role then
|
244
|
+
@roles[ sock ] = role
|
245
|
+
else
|
246
|
+
role = @roles[ sock ]
|
247
|
+
end
|
248
|
+
|
249
|
+
if @update_roles.include?( role ) then
|
250
|
+
set_update( sock )
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
def add_write( sock )
|
255
|
+
return if sock.nil? || sock.closed? || @writes.include?( sock )
|
256
|
+
@writes << sock
|
257
|
+
role = @roles[ sock ]
|
258
|
+
|
259
|
+
if @update_roles.include?( role ) then
|
260
|
+
set_update( sock )
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
def check_expire_dnses
|
265
|
+
now = Time.new
|
266
|
+
|
267
|
+
@dns_infos.select{ | dns, _ | now.to_i - @updates[ dns ].to_i >= @expire_short_after }.each do | dns, info |
|
268
|
+
puts "expire dns #{ info[ :im ] } #{ info[ :domain ] }" if @is_debug
|
269
|
+
close_dns( dns )
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
def check_expire_dsts
|
274
|
+
now = Time.new
|
275
|
+
|
276
|
+
@dst_infos.select{ | dst, info | info[ :connected ] ? ( now.to_i - @updates[ dst ].to_i >= @expire_long_after ) : ( now.to_i - @updates[ dst ].to_i >= @expire_connecting ) }.each do | dst, info |
|
277
|
+
puts "expire dst #{ info[ :im ] } #{ info[ :domain ] }" if @is_debug
|
278
|
+
close_dst( dst )
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
def check_expire_mems
|
283
|
+
now = Time.new
|
284
|
+
|
285
|
+
@mem_infos.select{ | mem, _ | now.to_i - @updates[ mem ].to_i >= @expire_short_after }.each do | mem, _ |
|
286
|
+
puts "expire mem" if @is_debug
|
287
|
+
close_mem( mem )
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
def check_expire_p2s
|
292
|
+
now = Time.new
|
293
|
+
|
294
|
+
@p2_infos.select{ | p2, _ | now.to_i - @updates[ p2 ].to_i >= @expire_long_after }.each do | p2, info |
|
295
|
+
puts "expire p2 #{ info[ :im ] } #{ info[ :p2_id ] }" if @is_debug
|
296
|
+
close_p2( p2 )
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
def check_expire_proxies
|
301
|
+
now = Time.new
|
302
|
+
|
303
|
+
@proxy_infos.select{ | proxy, _ | now.to_i - @updates[ proxy ].to_i >= @expire_long_after }.each do | proxy, info |
|
304
|
+
puts "expire proxy #{ info[ :im ] }"
|
305
|
+
close_proxy( proxy )
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
def check_expire_rsvs
|
310
|
+
now = Time.new
|
311
|
+
|
312
|
+
@rsv_infos.select{ | rsv, _ | now.to_i - @updates[ rsv ].to_i >= @expire_short_after }.each do | rsv, info |
|
313
|
+
puts "expire rsv #{ info[ :im ] } #{ info[ :domain ] }" if @is_debug
|
314
|
+
close_rsv( rsv )
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
def check_expire_srcs( proxy )
|
319
|
+
return if proxy.nil? || proxy.closed?
|
320
|
+
proxy_info = @proxy_infos[ proxy ]
|
321
|
+
im = proxy_info[ :im ]
|
322
|
+
now = Time.new
|
323
|
+
|
324
|
+
proxy_info[ :src_infos ].select{ | _, info | info[ :dst ].nil? && ( now.to_i - info[ :created_at ].to_i >= @expire_short_after ) }.each do | src_id, _ |
|
325
|
+
puts "expire src info #{ im } #{ src_id }" if @is_debug
|
326
|
+
proxy_info[ :src_infos ].delete( src_id )
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
def close_dns( dns )
|
331
|
+
return nil if dns.nil? || dns.closed?
|
332
|
+
close_sock( dns )
|
333
|
+
dns_info = @dns_infos.delete( dns )
|
334
|
+
puts "close dns #{ dns_info[ :im ] } #{ dns_info[ :domain ] }" if @is_debug
|
335
|
+
dns_info
|
336
|
+
end
|
337
|
+
|
338
|
+
def close_dst( dst )
|
339
|
+
return nil if dst.nil? || dst.closed?
|
340
|
+
close_sock( dst )
|
341
|
+
dst_info = @dst_infos.delete( dst )
|
342
|
+
im = dst_info[ :im ]
|
343
|
+
src_id = dst_info[ :src_id ]
|
344
|
+
domain = dst_info[ :domain ]
|
345
|
+
puts "close dst #{ im } #{ src_id } #{ domain }" if @is_debug
|
346
|
+
proxy = dst_info[ :proxy ]
|
347
|
+
|
348
|
+
unless proxy.closed? then
|
349
|
+
proxy_info = @proxy_infos[ proxy ]
|
350
|
+
proxy_info[ :paused_dsts ].delete( dst )
|
351
|
+
proxy_info[ :src_infos ].delete( src_id )
|
352
|
+
puts "add h_dst_close #{ im } #{ src_id }" if @is_debug
|
353
|
+
msg = "#{ @h_dst_close }#{ [ src_id ].pack( 'Q>' ) }"
|
354
|
+
add_proxy_wbuff( proxy, pack_a_chunk( msg ) )
|
355
|
+
end
|
356
|
+
|
357
|
+
dst_info
|
358
|
+
end
|
359
|
+
|
360
|
+
def close_mem( mem )
|
361
|
+
return nil if mem.nil? || mem.closed?
|
362
|
+
close_sock( mem )
|
363
|
+
@mem_infos.delete( mem )
|
364
|
+
end
|
365
|
+
|
366
|
+
def close_p2( p2 )
|
367
|
+
return nil if p2.nil? || p2.closed?
|
368
|
+
close_sock( p2 )
|
369
|
+
p2_info = @p2_infos.delete( p2 )
|
370
|
+
im = p2_info[ :im ]
|
371
|
+
p2_id = p2_info[ :p2_id ]
|
372
|
+
puts "close p2 #{ im } #{ p2_id }"
|
373
|
+
im_info = @im_infos[ im ]
|
374
|
+
|
375
|
+
if im_info then
|
376
|
+
proxy = im_info[ :proxy ]
|
377
|
+
|
378
|
+
if proxy && !proxy.closed? then
|
379
|
+
proxy_info = @proxy_infos[ proxy ]
|
380
|
+
proxy_info[ :paused_p2s ].delete( p2 )
|
381
|
+
puts "add h_p2_close #{ im } #{ p2_id }"
|
382
|
+
msg = "#{ @h_p2_close }#{ [ p2_id ].pack( 'Q>' ) }"
|
383
|
+
add_proxy_wbuff( proxy, pack_a_chunk( msg ) )
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
p2_info
|
388
|
+
end
|
389
|
+
|
390
|
+
def close_proxy( proxy )
|
391
|
+
return nil if proxy.nil? || proxy.closed?
|
392
|
+
close_sock( proxy )
|
393
|
+
proxy_info = @proxy_infos.delete( proxy )
|
394
|
+
im = proxy_info[ :im ]
|
395
|
+
puts "close proxy #{ proxy_info[ :addrinfo ].ip_unpack.inspect } #{ im }" if @is_debug
|
396
|
+
@dst_infos.select{ | _, info | info[ :proxy ] == proxy }.each{ | dst, _ | close_dst( dst ) }
|
397
|
+
@p2_infos.select{ | _, info | info[ :im ] == im }.each{ | p2, _ | close_p2( p2 ) }
|
398
|
+
proxy_info
|
399
|
+
end
|
400
|
+
|
401
|
+
def close_rsv( rsv )
|
402
|
+
return nil if rsv.nil? || rsv.closed?
|
403
|
+
close_sock( rsv )
|
404
|
+
rsv_info = @rsv_infos.delete( rsv )
|
405
|
+
puts "close rsv #{ rsv_info[ :im ] } #{ rsv_info[ :domain ] }" if @is_debug
|
406
|
+
rsv_info
|
407
|
+
end
|
408
|
+
|
409
|
+
def close_sock( sock )
|
410
|
+
return if sock.nil? || sock.closed?
|
411
|
+
sock.close
|
412
|
+
@reads.delete( sock )
|
413
|
+
@writes.delete( sock )
|
414
|
+
@updates.delete( sock )
|
415
|
+
@roles.delete( sock )
|
416
|
+
end
|
417
|
+
|
418
|
+
def deal_msg( data, proxy )
|
419
|
+
return if data.nil? || data.empty? || proxy.nil? || proxy.closed?
|
420
|
+
proxy_info = @proxy_infos[ proxy ]
|
421
|
+
im = proxy_info[ :im ]
|
422
|
+
return unless im
|
423
|
+
h = data[ 0 ]
|
424
|
+
|
425
|
+
case h
|
426
|
+
when @h_a_new_source then
|
427
|
+
return if data.bytesize < 9
|
428
|
+
check_expire_srcs( proxy )
|
429
|
+
src_id = data[ 1, 8 ].unpack( 'Q>' ).first
|
430
|
+
domain_port = data[ 9..-1 ]
|
431
|
+
puts "got h_a_new_source #{ im } #{ src_id } #{ domain_port.inspect }" if @is_debug
|
432
|
+
|
433
|
+
src_info = {
|
434
|
+
created_at: Time.new,
|
435
|
+
dst: nil,
|
436
|
+
rbuff: ''
|
437
|
+
}
|
438
|
+
|
439
|
+
proxy_info[ :src_infos ][ src_id ] = src_info
|
440
|
+
resolve_domain_port( domain_port, src_id, proxy, im )
|
441
|
+
when @h_p1_close then
|
442
|
+
return if data.bytesize < 9
|
443
|
+
p2_id = data[ 1, 8 ].unpack( 'Q>' ).first
|
444
|
+
puts "got h_p1_close #{ im } #{ p2_id }"
|
445
|
+
p2, _ = @p2_infos.find{ | _, info | ( info[ :im ] == im ) && ( info[ :p2_id ] == p2_id ) }
|
446
|
+
set_p2_closing( p2 )
|
447
|
+
when @h_p2_traffic then
|
448
|
+
return if data.bytesize < 9
|
449
|
+
p2_id = data[ 1, 8 ].unpack( 'Q>' ).first
|
450
|
+
data = data[ 9..-1 ]
|
451
|
+
# puts "got h_p2_traffic #{ im } #{ p2_id } #{ data.bytesize }" if @is_debug
|
452
|
+
p2, _ = @p2_infos.find{ | _, info | ( info[ :im ] == im ) && ( info[ :p2_id ] == p2_id ) }
|
453
|
+
add_p2_wbuff( p2, data )
|
454
|
+
when @h_p1_overflow then
|
455
|
+
return if data.bytesize < 9
|
456
|
+
p2_id = data[ 1, 8 ].unpack( 'Q>' ).first
|
457
|
+
puts "got h_p1_overflow pause p2 #{ im } #{ p2_id }"
|
458
|
+
p2, _ = @p2_infos.find{ | _, info | ( info[ :im ] == im ) && ( info[ :p2_id ] == p2_id ) }
|
459
|
+
@reads.delete( p2 )
|
460
|
+
proxy_info[ :paused_p2s ].delete( p2 )
|
461
|
+
when @h_p1_underhalf then
|
462
|
+
return if data.bytesize < 9
|
463
|
+
p2_id = data[ 1, 8 ].unpack( 'Q>' ).first
|
464
|
+
puts "got h_p1_underhalf #{ im } #{ p2_id }"
|
465
|
+
p2, _ = @p2_infos.find{ | _, info | ( info[ :im ] == im ) && ( info[ :p2_id ] == p2_id ) }
|
466
|
+
add_read( p2 )
|
467
|
+
when @h_query then
|
468
|
+
return if data.bytesize < 10
|
469
|
+
near_id, type = data[ 1, 9 ].unpack( 'Q>C' )
|
470
|
+
return unless [ 1, 28 ].include?( type )
|
471
|
+
domain = data[ 10..-1 ]
|
472
|
+
return if domain.nil? || domain.empty?
|
473
|
+
puts "got h_query #{ im } #{ near_id } #{ type } #{ domain.inspect }" if @is_debug
|
474
|
+
new_a_rsv( domain, near_id, type, proxy, im )
|
475
|
+
when @h_src_close then
|
476
|
+
return if data.bytesize < 9
|
477
|
+
src_id = data[ 1, 8 ].unpack( 'Q>' ).first
|
478
|
+
puts "got h_src_close #{ im } #{ src_id }" if @is_debug
|
479
|
+
src_info = proxy_info[ :src_infos ].delete( src_id )
|
480
|
+
set_dst_closing( src_info[ :dst ] ) if src_info
|
481
|
+
when @h_traffic then
|
482
|
+
return if data.bytesize < 9
|
483
|
+
src_id = data[ 1, 8 ].unpack( 'Q>' ).first
|
484
|
+
data = data[ 9..-1 ]
|
485
|
+
# puts "got h_traffic #{ im } #{ src_id } #{ data.bytesize }" if @is_debug
|
486
|
+
src_info = proxy_info[ :src_infos ][ src_id ]
|
487
|
+
|
488
|
+
if src_info then
|
489
|
+
dst = src_info[ :dst ]
|
490
|
+
|
491
|
+
if dst then
|
492
|
+
add_dst_wbuff( dst, data )
|
493
|
+
else
|
494
|
+
puts "add src rbuff #{ im } #{ data.bytesize }" if @is_debug
|
495
|
+
src_info[ :rbuff ] << data
|
496
|
+
|
497
|
+
if src_info[ :rbuff ].bytesize >= WBUFF_LIMIT then
|
498
|
+
puts "src rbuff full"
|
499
|
+
close_proxy( proxy )
|
500
|
+
end
|
501
|
+
end
|
502
|
+
end
|
503
|
+
when @h_src_overflow then
|
504
|
+
return if data.bytesize < 9
|
505
|
+
src_id = data[ 1, 8 ].unpack( 'Q>' ).first
|
506
|
+
puts "got h_src_overflow pause dst #{ im } #{ src_id }"
|
507
|
+
src_info = proxy_info[ :src_infos ][ src_id ]
|
508
|
+
|
509
|
+
if src_info then
|
510
|
+
dst = src_info[ :dst ]
|
511
|
+
@reads.delete( dst )
|
512
|
+
# 远端收取目的地比传给近端快,近端收取远端又比传给客户端快(2g wifi),流量即在远端proxy堆积,又在近端src堆积
|
513
|
+
# 这种情况只等待近端src降半,等到降半消息才恢复读dst,忽略proxy降半
|
514
|
+
proxy_info[ :paused_dsts ].delete( dst )
|
515
|
+
end
|
516
|
+
when @h_src_underhalf then
|
517
|
+
return if data.bytesize < 9
|
518
|
+
src_id = data[ 1, 8 ].unpack( 'Q>' ).first
|
519
|
+
puts "got h_src_underhalf #{ im } #{ src_id }"
|
520
|
+
src_info = proxy_info[ :src_infos ][ src_id ]
|
521
|
+
add_read( src_info[ :dst ] ) if src_info
|
522
|
+
end
|
523
|
+
end
|
524
|
+
|
525
|
+
def decode_to_msgs( data )
|
526
|
+
msgs = []
|
527
|
+
part = ''
|
528
|
+
|
529
|
+
loop do
|
530
|
+
if data.bytesize <= 2 then
|
531
|
+
part = data
|
532
|
+
break
|
533
|
+
end
|
534
|
+
|
535
|
+
len = data[ 0, 2 ].unpack( 'n' ).first
|
536
|
+
|
537
|
+
if len == 0 then
|
538
|
+
puts "msg zero len?"
|
539
|
+
break
|
540
|
+
end
|
541
|
+
|
542
|
+
if data.bytesize < ( 2 + len ) then
|
543
|
+
part = data
|
544
|
+
break
|
545
|
+
end
|
546
|
+
|
547
|
+
msgs << data[ 2, len ]
|
548
|
+
data = data[ ( 2 + len )..-1 ]
|
549
|
+
break if data.empty?
|
550
|
+
end
|
551
|
+
|
552
|
+
[ msgs, part ]
|
553
|
+
end
|
554
|
+
|
555
|
+
def init_im_infos( ims, p2d_host, p2d_port )
|
556
|
+
ims.sort.each_with_index do | im, i |
|
557
|
+
@im_infos[ im ] = {
|
558
|
+
addrinfo: nil,
|
559
|
+
in: 0,
|
560
|
+
out: 0,
|
561
|
+
p2d: nil,
|
562
|
+
p2d_host: p2d_host,
|
563
|
+
p2d_port: p2d_port + i,
|
564
|
+
proxy: nil
|
565
|
+
}
|
566
|
+
end
|
567
|
+
end
|
568
|
+
|
569
|
+
def loop_check_traff
|
570
|
+
if @reset_traff_day > 0 then
|
571
|
+
Thread.new do
|
572
|
+
loop do
|
573
|
+
sleep CHECK_TRAFF_INTERVAL
|
574
|
+
now = Time.new
|
575
|
+
|
576
|
+
if ( now.day == @reset_traff_day ) && ( now.hour == 0 ) then
|
577
|
+
msg = { message_type: 'reset-traffic' }
|
578
|
+
send_data( @info, JSON.generate( msg ), @infod_addr )
|
579
|
+
end
|
580
|
+
end
|
581
|
+
end
|
582
|
+
end
|
583
|
+
end
|
584
|
+
|
585
|
+
def loop_heartbeat
|
586
|
+
Thread.new do
|
587
|
+
loop do
|
588
|
+
sleep HEARTBEAT_INTERVAL
|
589
|
+
msg = { message_type: 'heartbeat' }
|
590
|
+
send_data( @info, JSON.generate( msg ), @infod_addr )
|
591
|
+
end
|
592
|
+
end
|
593
|
+
end
|
594
|
+
|
595
|
+
def new_a_dst( domain, ip, port, src_id, proxy )
|
596
|
+
return if proxy.nil? || proxy.closed?
|
597
|
+
proxy_info = @proxy_infos[ proxy ]
|
598
|
+
im = proxy_info[ :im ]
|
599
|
+
src_info = proxy_info[ :src_infos ][ src_id ]
|
600
|
+
return unless src_info
|
601
|
+
|
602
|
+
check_expire_dsts
|
603
|
+
|
604
|
+
begin
|
605
|
+
dst = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
|
606
|
+
rescue Exception => e
|
607
|
+
puts "new a dst #{ e.class } #{ im } #{ domain }:#{ port }"
|
608
|
+
return
|
609
|
+
end
|
610
|
+
|
611
|
+
dst.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1 )
|
612
|
+
|
613
|
+
begin
|
614
|
+
destination_addr = Socket.sockaddr_in( port, ip )
|
615
|
+
dst.connect_nonblock( destination_addr )
|
616
|
+
rescue IO::WaitWritable
|
617
|
+
rescue Exception => e
|
618
|
+
puts "connect destination #{ e.class } #{ im } #{ domain }:#{ port }"
|
619
|
+
dst.close
|
620
|
+
return
|
621
|
+
end
|
622
|
+
|
623
|
+
dst_info = {
|
624
|
+
closing: false,
|
625
|
+
connected: false,
|
626
|
+
domain: domain,
|
627
|
+
im: im,
|
628
|
+
ip: ip,
|
629
|
+
overflowing: false,
|
630
|
+
port: port,
|
631
|
+
proxy: proxy,
|
632
|
+
rbuffs: [],
|
633
|
+
src_id: src_id,
|
634
|
+
wbuff: src_info[ :rbuff ].dup
|
635
|
+
}
|
636
|
+
|
637
|
+
@dst_infos[ dst ] = dst_info
|
638
|
+
add_read( dst, :dst )
|
639
|
+
add_write( dst )
|
640
|
+
src_info[ :dst ] = dst
|
641
|
+
end
|
642
|
+
|
643
|
+
def new_a_infod( infod_port )
|
644
|
+
infod_ip = '127.0.0.1'
|
645
|
+
infod_addr = Socket.sockaddr_in( infod_port, infod_ip )
|
646
|
+
infod = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
|
647
|
+
infod.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 ) if RUBY_PLATFORM.include?( 'linux' )
|
648
|
+
infod.bind( infod_addr )
|
649
|
+
puts "infod bind on #{ infod_ip } #{ infod_port }"
|
650
|
+
add_read( infod, :infod )
|
651
|
+
info = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
|
652
|
+
@infod_addr = infod_addr
|
653
|
+
@infod = infod
|
654
|
+
@info = info
|
655
|
+
end
|
656
|
+
|
657
|
+
def new_a_memd( memd_port )
|
658
|
+
memd_ip = '127.0.0.1'
|
659
|
+
memd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
|
660
|
+
memd.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1 )
|
661
|
+
memd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 ) if RUBY_PLATFORM.include?( 'linux' )
|
662
|
+
memd.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_FASTOPEN, 5 ) if @is_server_fastopen
|
663
|
+
memd.bind( Socket.sockaddr_in( memd_port, memd_ip ) )
|
664
|
+
memd.listen( 5 )
|
665
|
+
puts "memd listen on #{ memd_ip } #{ memd_port }"
|
666
|
+
add_read( memd, :memd )
|
667
|
+
end
|
668
|
+
|
669
|
+
def new_a_rsv( domain, near_id, type, proxy, im )
|
670
|
+
check_expire_rsvs
|
671
|
+
rsv = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
|
672
|
+
|
673
|
+
begin
|
674
|
+
data = pack_a_query( domain, type )
|
675
|
+
rescue Exception => e
|
676
|
+
puts "rsv pack a query #{ e.class } #{ e.message } #{ domain }" if @is_debug
|
677
|
+
return
|
678
|
+
end
|
679
|
+
|
680
|
+
begin
|
681
|
+
@nameserver_addrs.each{ | addr | rsv.sendmsg( data, 0, addr ) }
|
682
|
+
rescue Exception => e
|
683
|
+
puts "rsv send data #{ e.class }"
|
684
|
+
rsv.close
|
685
|
+
return
|
686
|
+
end
|
687
|
+
|
688
|
+
rsv_info = {
|
689
|
+
domain: domain,
|
690
|
+
im: im,
|
691
|
+
near_id: near_id,
|
692
|
+
proxy: proxy
|
693
|
+
}
|
694
|
+
|
695
|
+
@rsv_infos[ rsv ] = rsv_info
|
696
|
+
add_read( rsv, :rsv )
|
697
|
+
end
|
698
|
+
|
699
|
+
def new_a_p2d( p2d_host, p2d_port, im, proxy )
|
700
|
+
begin
|
701
|
+
p2d = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
|
702
|
+
p2d.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1 )
|
703
|
+
p2d.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 ) if RUBY_PLATFORM.include?( 'linux' )
|
704
|
+
p2d.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_FASTOPEN, 5 ) if @is_server_fastopen
|
705
|
+
p2d.bind( Socket.sockaddr_in( p2d_port, p2d_host ) )
|
706
|
+
p2d.listen( 5 )
|
707
|
+
puts "p2d listen on #{ p2d_host } #{ p2d_port } #{ im }"
|
708
|
+
@p2d_infos[ p2d ] = { im: im }
|
709
|
+
add_read( p2d, :p2d )
|
710
|
+
rescue Exception => e
|
711
|
+
puts "new a p2d #{ e.class }"
|
712
|
+
end
|
713
|
+
|
714
|
+
p2d
|
715
|
+
end
|
716
|
+
|
717
|
+
def new_a_proxyd( proxyd_port )
|
718
|
+
proxyd_ip = '0.0.0.0'
|
719
|
+
proxyd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
|
720
|
+
proxyd.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1 )
|
721
|
+
proxyd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 ) if RUBY_PLATFORM.include?( 'linux' )
|
722
|
+
proxyd.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_FASTOPEN, BACKLOG ) if @is_server_fastopen
|
723
|
+
proxyd.bind( Socket.sockaddr_in( proxyd_port, proxyd_ip ) )
|
724
|
+
proxyd.listen( BACKLOG )
|
725
|
+
puts "proxyd listen on #{ proxyd_ip } #{ proxyd_port }"
|
726
|
+
add_read( proxyd, :proxyd )
|
727
|
+
end
|
728
|
+
|
729
|
+
def pack_a_chunk( msg )
|
730
|
+
"#{ [ msg.bytesize ].pack( 'n' ) }#{ msg }"
|
731
|
+
end
|
732
|
+
|
733
|
+
def pack_p2_traffic( p2_id, data )
|
734
|
+
chunks = ''
|
735
|
+
|
736
|
+
loop do
|
737
|
+
part = data[ 0, 65526 ]
|
738
|
+
# puts "add h_p2_traffic #{ p2_id } #{ part.bytesize }" if @is_debug
|
739
|
+
msg = "#{ @h_p2_traffic }#{ [ p2_id ].pack( 'Q>' ) }#{ part }"
|
740
|
+
chunks << pack_a_chunk( msg )
|
741
|
+
data = data[ part.bytesize..-1 ]
|
742
|
+
break if data.empty?
|
743
|
+
end
|
744
|
+
|
745
|
+
chunks
|
746
|
+
end
|
747
|
+
|
748
|
+
def pack_traffic( src_id, data )
|
749
|
+
chunks = ''
|
750
|
+
|
751
|
+
loop do
|
752
|
+
part = data[ 0, 65526 ]
|
753
|
+
# puts "add h_traffic #{ src_id } #{ part.bytesize }" if @is_debug
|
754
|
+
msg = "#{ @h_traffic }#{ [ src_id ].pack( 'Q>' ) }#{ part }"
|
755
|
+
chunks << pack_a_chunk( msg )
|
756
|
+
data = data[ part.bytesize..-1 ]
|
757
|
+
break if data.empty?
|
758
|
+
end
|
759
|
+
|
760
|
+
chunks
|
761
|
+
end
|
762
|
+
|
763
|
+
def read_dns( dns )
|
764
|
+
begin
|
765
|
+
data, addrinfo, rflags, *controls = dns.recvmsg
|
766
|
+
rescue Exception => e
|
767
|
+
puts "dns recvmsg #{ e.class }"
|
768
|
+
close_dns( dns )
|
769
|
+
return
|
770
|
+
end
|
771
|
+
|
772
|
+
return if data.empty?
|
773
|
+
|
774
|
+
begin
|
775
|
+
ip = seek_ip( data )
|
776
|
+
rescue Exception => e
|
777
|
+
puts "seek ip #{ e.class } #{ e.message }"
|
778
|
+
close_dns( dns )
|
779
|
+
return
|
780
|
+
end
|
781
|
+
|
782
|
+
dns_info = @dns_infos[ dns ]
|
783
|
+
domain = dns_info[ :domain ]
|
784
|
+
|
785
|
+
if ip then
|
786
|
+
port = dns_info[ :port ]
|
787
|
+
src_id = dns_info[ :src_id ]
|
788
|
+
proxy = dns_info[ :proxy ]
|
789
|
+
im = dns_info[ :im ]
|
790
|
+
puts "got ip #{ im } #{ domain } #{ ip }" if @is_debug
|
791
|
+
new_a_dst( domain, ip, port, src_id, proxy )
|
792
|
+
@resolv_caches[ domain ] = [ ip, Time.new, im ]
|
793
|
+
else
|
794
|
+
puts "no ip in answer #{ domain }" if @is_debug
|
795
|
+
end
|
796
|
+
|
797
|
+
close_dns( dns )
|
798
|
+
end
|
799
|
+
|
800
|
+
def read_dst( dst )
|
801
|
+
begin
|
802
|
+
data = dst.read_nonblock( READ_SIZE )
|
803
|
+
rescue Errno::ENOTCONN => e
|
804
|
+
return
|
805
|
+
rescue Exception => e
|
806
|
+
close_dst( dst )
|
807
|
+
return
|
808
|
+
end
|
809
|
+
|
810
|
+
set_update( dst )
|
811
|
+
dst_info = @dst_infos[ dst ]
|
812
|
+
proxy = dst_info[ :proxy ]
|
813
|
+
|
814
|
+
if proxy.closed? then
|
815
|
+
close_dst( dst )
|
816
|
+
return
|
817
|
+
end
|
818
|
+
|
819
|
+
im = dst_info[ :im ]
|
820
|
+
im_info = @im_infos[ im ]
|
821
|
+
im_info[ :in ] += data.bytesize if im_info
|
822
|
+
src_id = dst_info[ :src_id ]
|
823
|
+
add_proxy_wbuff( proxy, pack_traffic( src_id, data ) )
|
824
|
+
|
825
|
+
unless proxy.closed? then
|
826
|
+
proxy_info = @proxy_infos[ proxy ]
|
827
|
+
bytesize = proxy_info[ :wbuff ].bytesize
|
828
|
+
|
829
|
+
if ( bytesize >= WBUFF_LIMIT ) && !proxy_info[ :paused_dsts ].include?( dst ) then
|
830
|
+
puts "proxy overflow pause dst #{ im } #{ src_id } #{ dst_info[ :domain ] }"
|
831
|
+
@reads.delete( dst )
|
832
|
+
proxy_info[ :paused_dsts ] << dst
|
833
|
+
end
|
834
|
+
end
|
835
|
+
end
|
836
|
+
|
837
|
+
def read_infod( infod )
|
838
|
+
begin
|
839
|
+
data, addrinfo, rflags, *controls = infod.recvmsg
|
840
|
+
rescue Exception => e
|
841
|
+
puts "infod recvmsg #{ e.class }"
|
842
|
+
return
|
843
|
+
end
|
844
|
+
|
845
|
+
return if data.empty?
|
846
|
+
|
847
|
+
begin
|
848
|
+
msg = JSON.parse( data, symbolize_names: true )
|
849
|
+
rescue JSON::ParserError, EncodingError => e
|
850
|
+
puts "read infod #{ e.class }"
|
851
|
+
return
|
852
|
+
end
|
853
|
+
|
854
|
+
message_type = msg[ :message_type ]
|
855
|
+
|
856
|
+
case message_type
|
857
|
+
when 'heartbeat' then
|
858
|
+
@proxy_infos.select{ | _, info | info[ :im ] }.each{ | proxy, _ | add_proxy_wbuff( proxy, pack_a_chunk( @h_heartbeat ) ) }
|
859
|
+
when 'reset-traffic' then
|
860
|
+
puts "reset traffic"
|
861
|
+
@im_infos.each{ | _, info | info[ :in ] = info[ :out ] = 0 }
|
862
|
+
end
|
863
|
+
end
|
864
|
+
|
865
|
+
def read_mem( mem )
|
866
|
+
begin
|
867
|
+
mem.read_nonblock( READ_SIZE )
|
868
|
+
rescue Errno::ENOTCONN => e
|
869
|
+
return
|
870
|
+
rescue Exception => e
|
871
|
+
close_mem( mem )
|
872
|
+
return
|
873
|
+
end
|
874
|
+
|
875
|
+
set_update( mem )
|
876
|
+
im_arr = []
|
877
|
+
|
878
|
+
@im_infos.select{ | _, info | info[ :addrinfo ] }.sort.each do | im, info |
|
879
|
+
im_arr << {
|
880
|
+
im: im,
|
881
|
+
addrinfo: info[ :addrinfo ].ip_unpack,
|
882
|
+
in: info[ :in ],
|
883
|
+
out: info[ :out ],
|
884
|
+
p2d_host: info[ :p2d_host ],
|
885
|
+
p2d_port: info[ :p2d_port ]
|
886
|
+
}
|
887
|
+
end
|
888
|
+
|
889
|
+
msg = {
|
890
|
+
resolv_caches: @resolv_caches.sort,
|
891
|
+
sizes: {
|
892
|
+
reads: @reads.size,
|
893
|
+
writes: @writes.size,
|
894
|
+
roles: @roles.size,
|
895
|
+
updates: @updates.size,
|
896
|
+
proxy_infos: @proxy_infos.size,
|
897
|
+
im_infos: @im_infos.size,
|
898
|
+
mem_infos: @mem_infos.size,
|
899
|
+
dst_infos: @dst_infos.size,
|
900
|
+
dns_infos: @dns_infos.size,
|
901
|
+
rsv_infos: @rsv_infos.size,
|
902
|
+
resolv_caches: @resolv_caches.size,
|
903
|
+
p2d_infos: @p2d_infos.size,
|
904
|
+
p2_infos: @p2_infos.size
|
905
|
+
},
|
906
|
+
updates_limit: @updates_limit,
|
907
|
+
eliminate_count: @eliminate_count,
|
908
|
+
im_arr: im_arr
|
909
|
+
}
|
910
|
+
|
911
|
+
add_mem_wbuff( mem, JSON.generate( msg ) )
|
912
|
+
end
|
913
|
+
|
914
|
+
def read_memd( memd )
|
915
|
+
check_expire_mems
|
916
|
+
|
917
|
+
begin
|
918
|
+
mem, addrinfo = memd.accept_nonblock
|
919
|
+
rescue Exception => e
|
920
|
+
puts "memd accept #{ e.class }"
|
921
|
+
return
|
922
|
+
end
|
923
|
+
|
924
|
+
mem_info = {
|
925
|
+
wbuff: ''
|
926
|
+
}
|
927
|
+
|
928
|
+
@mem_infos[ mem ] = mem_info
|
929
|
+
add_read( mem, :mem )
|
930
|
+
end
|
931
|
+
|
932
|
+
def read_p2( p2 )
|
933
|
+
begin
|
934
|
+
data = p2.read_nonblock( READ_SIZE )
|
935
|
+
rescue Errno::ENOTCONN => e
|
936
|
+
return
|
937
|
+
rescue Exception => e
|
938
|
+
close_p2( p2 )
|
939
|
+
return
|
940
|
+
end
|
941
|
+
|
942
|
+
set_update( p2 )
|
943
|
+
p2_info = @p2_infos[ p2 ]
|
944
|
+
im = p2_info[ :im ]
|
945
|
+
# puts "read p2 #{ im } #{ data.bytesize }" if @is_debug
|
946
|
+
im_info = @im_infos[ im ]
|
947
|
+
|
948
|
+
unless im_info then
|
949
|
+
close_p2( p2 )
|
950
|
+
return
|
951
|
+
end
|
952
|
+
|
953
|
+
proxy = im_info[ :proxy ]
|
954
|
+
p2_id = p2_info[ :p2_id ]
|
955
|
+
add_proxy_wbuff( proxy, pack_p2_traffic( p2_id, data ) )
|
956
|
+
|
957
|
+
unless proxy.closed? then
|
958
|
+
proxy_info = @proxy_infos[ proxy ]
|
959
|
+
bytesize = proxy_info[ :wbuff ].bytesize
|
960
|
+
|
961
|
+
if ( bytesize >= WBUFF_LIMIT ) && !proxy_info[ :paused_p2s ].include?( p2 ) then
|
962
|
+
puts "proxy overflow pause p2 #{ im } #{ p2_id }"
|
963
|
+
@reads.delete( p2 )
|
964
|
+
proxy_info[ :paused_p2s ] << p2
|
965
|
+
end
|
966
|
+
end
|
967
|
+
end
|
968
|
+
|
969
|
+
def read_p2d( p2d )
|
970
|
+
check_expire_p2s
|
971
|
+
|
972
|
+
begin
|
973
|
+
p2, addrinfo = p2d.accept_nonblock
|
974
|
+
rescue Exception => e
|
975
|
+
puts "p2d accept #{ e.class }"
|
976
|
+
return
|
977
|
+
end
|
978
|
+
|
979
|
+
p2d_info = @p2d_infos[ p2d ]
|
980
|
+
im = p2d_info[ :im ]
|
981
|
+
p2_id = rand( ( 2 ** 64 ) - 2 ) + 1
|
982
|
+
|
983
|
+
p2_info = {
|
984
|
+
addrinfo: addrinfo,
|
985
|
+
closing: false,
|
986
|
+
im: im,
|
987
|
+
overflowing: false,
|
988
|
+
p2_id: p2_id,
|
989
|
+
wbuff: ''
|
990
|
+
}
|
991
|
+
|
992
|
+
@p2_infos[ p2 ] = p2_info
|
993
|
+
add_read( p2, :p2 )
|
994
|
+
im_info = @im_infos[ im ]
|
995
|
+
return unless im_info
|
996
|
+
proxy = im_info[ :proxy ]
|
997
|
+
puts "add h_a_new_p2 #{ im } #{ p2_id }"
|
998
|
+
msg = "#{ @h_a_new_p2 }#{ [ p2_id ].pack( 'Q>' ) }"
|
999
|
+
add_proxy_wbuff( proxy, pack_a_chunk( msg ) )
|
1000
|
+
end
|
1001
|
+
|
1002
|
+
def read_rsv( rsv )
|
1003
|
+
begin
|
1004
|
+
data, addrinfo, rflags, *controls = rsv.recvmsg
|
1005
|
+
rescue Exception => e
|
1006
|
+
puts "rsv recvmsg #{ e.class }"
|
1007
|
+
close_rsv( rsv )
|
1008
|
+
return
|
1009
|
+
end
|
1010
|
+
|
1011
|
+
return if data.empty?
|
1012
|
+
|
1013
|
+
if data.bytesize <= 65526 then
|
1014
|
+
rsv_info = @rsv_infos[ rsv ]
|
1015
|
+
proxy = rsv_info[ :proxy ]
|
1016
|
+
near_id = rsv_info[ :near_id ]
|
1017
|
+
puts "add h_response #{ rsv_info[ :im ] } #{ near_id } #{ rsv_info[ :domain ] } #{ data.bytesize }" if @is_debug
|
1018
|
+
msg = "#{ @h_response }#{ [ near_id ].pack( 'Q>' ) }#{ data }"
|
1019
|
+
add_proxy_wbuff( proxy, pack_a_chunk( msg ) )
|
1020
|
+
else
|
1021
|
+
puts "response too big? #{ data.bytesize }"
|
1022
|
+
end
|
1023
|
+
|
1024
|
+
close_rsv( rsv )
|
1025
|
+
end
|
1026
|
+
|
1027
|
+
def read_proxy( proxy )
|
1028
|
+
begin
|
1029
|
+
data = proxy.read_nonblock( READ_SIZE )
|
1030
|
+
rescue Errno::ENOTCONN => e
|
1031
|
+
return
|
1032
|
+
rescue Exception => e
|
1033
|
+
close_proxy( proxy )
|
1034
|
+
return
|
1035
|
+
end
|
1036
|
+
|
1037
|
+
set_update( proxy )
|
1038
|
+
proxy_info = @proxy_infos[ proxy ]
|
1039
|
+
im = proxy_info[ :im ]
|
1040
|
+
data = "#{ proxy_info[ :rbuff ] }#{ data }"
|
1041
|
+
|
1042
|
+
unless im then
|
1043
|
+
if data.bytesize < @head_len + 1 then
|
1044
|
+
proxy_info[ :rbuff ] = data
|
1045
|
+
return
|
1046
|
+
end
|
1047
|
+
|
1048
|
+
len = data[ @head_len ].unpack( 'C' ).first
|
1049
|
+
|
1050
|
+
if len == 0 then
|
1051
|
+
puts "im zero len?"
|
1052
|
+
return
|
1053
|
+
end
|
1054
|
+
|
1055
|
+
if data.bytesize < @head_len + 1 + len then
|
1056
|
+
proxy_info[ :rbuff ] = data
|
1057
|
+
return
|
1058
|
+
end
|
1059
|
+
|
1060
|
+
im = data[ @head_len + 1, len ]
|
1061
|
+
|
1062
|
+
if @im_infos.any? && !@im_infos.include?( im ) then
|
1063
|
+
puts "unknown im #{ im.inspect }"
|
1064
|
+
return
|
1065
|
+
end
|
1066
|
+
|
1067
|
+
puts "got im #{ im }"
|
1068
|
+
proxy_info[ :im ] = im
|
1069
|
+
im_info = @im_infos[ im ]
|
1070
|
+
|
1071
|
+
if im_info then
|
1072
|
+
im_info[ :proxy ] = proxy
|
1073
|
+
im_info[ :addrinfo ] = proxy_info[ :addrinfo ]
|
1074
|
+
im_info[ :p2d ] = new_a_p2d( im_info[ :p2d_host ], im_info[ :p2d_port ], im, proxy ) unless im_info[ :p2d ]
|
1075
|
+
end
|
1076
|
+
|
1077
|
+
add_proxy_wbuff( proxy, pack_a_chunk( @h_heartbeat ) )
|
1078
|
+
data = data[ ( @head_len + 1 + len )..-1 ]
|
1079
|
+
return if data.empty?
|
1080
|
+
end
|
1081
|
+
|
1082
|
+
im_info = @im_infos[ im ]
|
1083
|
+
im_info[ :in ] += data.bytesize if im_info
|
1084
|
+
msgs, part = decode_to_msgs( data )
|
1085
|
+
msgs.each{ | msg | deal_msg( msg, proxy ) }
|
1086
|
+
proxy_info[ :rbuff ] = part
|
1087
|
+
end
|
1088
|
+
|
1089
|
+
def read_proxyd( proxyd )
|
1090
|
+
check_expire_proxies
|
1091
|
+
|
1092
|
+
begin
|
1093
|
+
proxy, addrinfo = proxyd.accept_nonblock
|
1094
|
+
rescue Exception => e
|
1095
|
+
puts "accept a proxy #{ e.class }"
|
1096
|
+
return
|
1097
|
+
end
|
1098
|
+
|
1099
|
+
puts "accept a proxy #{ addrinfo.ip_unpack.inspect }"
|
1100
|
+
|
1101
|
+
proxy_info = {
|
1102
|
+
addrinfo: addrinfo,
|
1103
|
+
im: nil,
|
1104
|
+
paused_dsts: [],
|
1105
|
+
paused_p2s: [],
|
1106
|
+
rbuff: '',
|
1107
|
+
src_infos: {}, # src_id => { :created_at :dst :rbuff }
|
1108
|
+
wbuff: ''
|
1109
|
+
}
|
1110
|
+
|
1111
|
+
@proxy_infos[ proxy ] = proxy_info
|
1112
|
+
add_read( proxy, :proxy )
|
1113
|
+
end
|
1114
|
+
|
1115
|
+
def resolve_domain_port( domain_port, src_id, proxy, im )
|
1116
|
+
return if domain_port.nil? || domain_port.empty?
|
1117
|
+
colon_idx = domain_port.rindex( ':' )
|
1118
|
+
return unless colon_idx
|
1119
|
+
|
1120
|
+
domain = domain_port[ 0...colon_idx ]
|
1121
|
+
port = domain_port[ ( colon_idx + 1 )..-1 ].to_i
|
1122
|
+
|
1123
|
+
if ( domain !~ /^[0-9a-zA-Z\-\.]{1,63}$/ ) || ( domain =~ /^((0\.\d{1,3}\.\d{1,3}\.\d{1,3})|(10\.\d{1,3}\.\d{1,3}\.\d{1,3})|(127\.\d{1,3}\.\d{1,3}\.\d{1,3})|(169\.254\.\d{1,3}\.\d{1,3})|(172\.((1[6-9])|(2\d)|(3[01]))\.\d{1,3}\.\d{1,3})|(192\.168\.\d{1,3}\.\d{1,3})|(255\.255\.255\.255)|(localhost))$/ ) then
|
1124
|
+
# 忽略非法域名,内网地址
|
1125
|
+
puts "ignore #{ domain }"
|
1126
|
+
return
|
1127
|
+
end
|
1128
|
+
|
1129
|
+
if domain =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}.\d{1,3}$/ then
|
1130
|
+
# ipv4
|
1131
|
+
new_a_dst( domain, domain, port, src_id, proxy )
|
1132
|
+
return
|
1133
|
+
end
|
1134
|
+
|
1135
|
+
resolv_cache = @resolv_caches[ domain ]
|
1136
|
+
|
1137
|
+
if resolv_cache then
|
1138
|
+
ip, created_at, im = resolv_cache
|
1139
|
+
|
1140
|
+
if Time.new - created_at < @expire_resolv_cache then
|
1141
|
+
new_a_dst( domain, ip, port, src_id, proxy )
|
1142
|
+
return
|
1143
|
+
end
|
1144
|
+
|
1145
|
+
@resolv_caches.delete( domain )
|
1146
|
+
end
|
1147
|
+
|
1148
|
+
begin
|
1149
|
+
data = pack_a_query( domain )
|
1150
|
+
rescue Exception => e
|
1151
|
+
puts "dns pack a query #{ e.class } #{ e.message } #{ domain }" if @is_debug
|
1152
|
+
return
|
1153
|
+
end
|
1154
|
+
|
1155
|
+
check_expire_dnses
|
1156
|
+
dns = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
|
1157
|
+
|
1158
|
+
begin
|
1159
|
+
@nameserver_addrs.each{ | addr | dns.sendmsg( data, 0, addr ) }
|
1160
|
+
rescue Exception => e
|
1161
|
+
puts "dns send data #{ e.class } #{ domain }"
|
1162
|
+
dns.close
|
1163
|
+
return
|
1164
|
+
end
|
1165
|
+
|
1166
|
+
dns_info = {
|
1167
|
+
domain: domain,
|
1168
|
+
im: im,
|
1169
|
+
port: port,
|
1170
|
+
proxy: proxy,
|
1171
|
+
src_id: src_id
|
1172
|
+
}
|
1173
|
+
|
1174
|
+
@dns_infos[ dns ] = dns_info
|
1175
|
+
add_read( dns, :dns )
|
1176
|
+
end
|
1177
|
+
|
1178
|
+
def send_data( sock, data, target_addr )
|
1179
|
+
begin
|
1180
|
+
sock.sendmsg( data, 0, target_addr )
|
1181
|
+
rescue Exception => e
|
1182
|
+
puts "sendmsg #{ e.class }"
|
1183
|
+
end
|
1184
|
+
end
|
1185
|
+
|
1186
|
+
def set_dst_closing( dst )
|
1187
|
+
return if dst.nil? || dst.closed?
|
1188
|
+
dst_info = @dst_infos[ dst ]
|
1189
|
+
return if dst_info.nil? || dst_info[ :closing ]
|
1190
|
+
dst_info[ :closing ] = true
|
1191
|
+
add_write( dst )
|
1192
|
+
end
|
1193
|
+
|
1194
|
+
def set_p2_closing( p2 )
|
1195
|
+
return if p2.nil? || p2.closed?
|
1196
|
+
p2_info = @p2_infos[ p2 ]
|
1197
|
+
return if p2_info.nil? || p2_info[ :closing ]
|
1198
|
+
p2_info[ :closing ] = true
|
1199
|
+
add_write( p2 )
|
1200
|
+
end
|
1201
|
+
|
1202
|
+
def set_update( sock )
|
1203
|
+
@updates[ sock ] = Time.new
|
1204
|
+
|
1205
|
+
if @updates_limit - @updates.size <= 20 then
|
1206
|
+
puts "updates #{ @updates.size }"
|
1207
|
+
end
|
1208
|
+
|
1209
|
+
if @updates.size >= @updates_limit then
|
1210
|
+
puts "eliminate updates"
|
1211
|
+
|
1212
|
+
@updates.keys.each do | _sock |
|
1213
|
+
case @roles[ _sock ]
|
1214
|
+
when :dns
|
1215
|
+
close_dns( _sock )
|
1216
|
+
when :dst
|
1217
|
+
close_dst( _sock )
|
1218
|
+
when :mem
|
1219
|
+
close_mem( _sock )
|
1220
|
+
when :p2
|
1221
|
+
close_p2( _sock )
|
1222
|
+
when :proxy
|
1223
|
+
close_proxy( _sock )
|
1224
|
+
when :rsv
|
1225
|
+
close_rsv( _sock )
|
1226
|
+
else
|
1227
|
+
close_sock( _sock )
|
1228
|
+
end
|
1229
|
+
end
|
1230
|
+
|
1231
|
+
@eliminate_count += 1
|
1232
|
+
end
|
1233
|
+
end
|
1234
|
+
|
1235
|
+
def write_dst( dst )
|
1236
|
+
if dst.closed? then
|
1237
|
+
puts "write closed dst?"
|
1238
|
+
return
|
1239
|
+
end
|
1240
|
+
|
1241
|
+
dst_info = @dst_infos[ dst ]
|
1242
|
+
dst_info[ :connected ] = true
|
1243
|
+
data = dst_info[ :wbuff ]
|
1244
|
+
|
1245
|
+
if data.empty? then
|
1246
|
+
if dst_info[ :closing ] then
|
1247
|
+
close_dst( dst )
|
1248
|
+
else
|
1249
|
+
@writes.delete( dst )
|
1250
|
+
end
|
1251
|
+
|
1252
|
+
return
|
1253
|
+
end
|
1254
|
+
|
1255
|
+
begin
|
1256
|
+
written = dst.write_nonblock( data )
|
1257
|
+
rescue Errno::EINPROGRESS
|
1258
|
+
return
|
1259
|
+
rescue Exception => e
|
1260
|
+
close_dst( dst )
|
1261
|
+
return
|
1262
|
+
end
|
1263
|
+
|
1264
|
+
set_update( dst )
|
1265
|
+
im = dst_info[ :im ]
|
1266
|
+
im_info = @im_infos[ im ]
|
1267
|
+
im_info[ :out ] += written if im_info
|
1268
|
+
data = data[ written..-1 ]
|
1269
|
+
dst_info[ :wbuff ] = data
|
1270
|
+
bytesize = dst_info[ :wbuff ].bytesize
|
1271
|
+
|
1272
|
+
if dst_info[ :overflowing ] && ( bytesize < RESUME_BELOW ) then
|
1273
|
+
proxy = dst_info[ :proxy ]
|
1274
|
+
src_id = dst_info[ :src_id ]
|
1275
|
+
puts "add h_dst_underhalf #{ im } #{ src_id } #{ dst_info[ :domain ] }"
|
1276
|
+
msg = "#{ @h_dst_underhalf }#{ [ src_id ].pack( 'Q>' ) }"
|
1277
|
+
add_proxy_wbuff( proxy, pack_a_chunk( msg ) )
|
1278
|
+
dst_info[ :overflowing ] = false
|
1279
|
+
end
|
1280
|
+
end
|
1281
|
+
|
1282
|
+
def write_mem( mem )
|
1283
|
+
if mem.closed? then
|
1284
|
+
puts "write closed mem?"
|
1285
|
+
return
|
1286
|
+
end
|
1287
|
+
|
1288
|
+
mem_info = @mem_infos[ mem ]
|
1289
|
+
data = mem_info[ :wbuff ]
|
1290
|
+
|
1291
|
+
if data.empty? then
|
1292
|
+
@writes.delete( mem )
|
1293
|
+
close_mem( mem )
|
1294
|
+
return
|
1295
|
+
end
|
1296
|
+
|
1297
|
+
begin
|
1298
|
+
written = mem.write_nonblock( data )
|
1299
|
+
rescue Errno::EINPROGRESS
|
1300
|
+
return
|
1301
|
+
rescue Exception => e
|
1302
|
+
close_mem( mem )
|
1303
|
+
return
|
1304
|
+
end
|
1305
|
+
|
1306
|
+
set_update( mem )
|
1307
|
+
data = data[ written..-1 ]
|
1308
|
+
mem_info[ :wbuff ] = data
|
1309
|
+
end
|
1310
|
+
|
1311
|
+
def write_p2( p2 )
|
1312
|
+
if p2.closed? then
|
1313
|
+
puts "write closed p2?"
|
1314
|
+
return
|
1315
|
+
end
|
1316
|
+
|
1317
|
+
p2_info = @p2_infos[ p2 ]
|
1318
|
+
im = p2_info[ :im ]
|
1319
|
+
im_info = @im_infos[ im ]
|
1320
|
+
|
1321
|
+
unless im_info then
|
1322
|
+
close_p2( p2 )
|
1323
|
+
return
|
1324
|
+
end
|
1325
|
+
|
1326
|
+
data = p2_info[ :wbuff ]
|
1327
|
+
|
1328
|
+
if data.empty? then
|
1329
|
+
if p2_info[ :closing ] then
|
1330
|
+
close_p2( p2 )
|
1331
|
+
else
|
1332
|
+
@writes.delete( p2 )
|
1333
|
+
end
|
1334
|
+
|
1335
|
+
return
|
1336
|
+
end
|
1337
|
+
|
1338
|
+
begin
|
1339
|
+
written = p2.write_nonblock( data )
|
1340
|
+
rescue Errno::EINPROGRESS
|
1341
|
+
return
|
1342
|
+
rescue Exception => e
|
1343
|
+
close_p2( p2 )
|
1344
|
+
return
|
1345
|
+
end
|
1346
|
+
|
1347
|
+
set_update( p2 )
|
1348
|
+
data = data[ written..-1 ]
|
1349
|
+
p2_info[ :wbuff ] = data
|
1350
|
+
bytesize = p2_info[ :wbuff ].bytesize
|
1351
|
+
|
1352
|
+
if p2_info[ :overflowing ] && ( bytesize < RESUME_BELOW ) then
|
1353
|
+
proxy = im_info[ :proxy ]
|
1354
|
+
p2_id = p2_info[ :p2_id ]
|
1355
|
+
puts "add h_p2_underhalf #{ im } #{ p2_id }"
|
1356
|
+
msg = "#{ @h_p2_underhalf }#{ [ p2_id ].pack( 'Q>' ) }"
|
1357
|
+
add_proxy_wbuff( proxy, pack_a_chunk( msg ) )
|
1358
|
+
p2_info[ :overflowing ] = false
|
1359
|
+
end
|
1360
|
+
end
|
1361
|
+
|
1362
|
+
def write_proxy( proxy )
|
1363
|
+
if proxy.closed? then
|
1364
|
+
puts "write closed proxy?"
|
1365
|
+
return
|
1366
|
+
end
|
1367
|
+
|
1368
|
+
proxy_info = @proxy_infos[ proxy ]
|
1369
|
+
data = proxy_info[ :wbuff ]
|
1370
|
+
|
1371
|
+
if data.empty? then
|
1372
|
+
@writes.delete( proxy )
|
1373
|
+
return
|
1374
|
+
end
|
1375
|
+
|
1376
|
+
begin
|
1377
|
+
written = proxy.write_nonblock( data )
|
1378
|
+
rescue Errno::EINPROGRESS
|
1379
|
+
return
|
1380
|
+
rescue Exception => e
|
1381
|
+
close_proxy( proxy )
|
1382
|
+
return
|
1383
|
+
end
|
1384
|
+
|
1385
|
+
set_update( proxy )
|
1386
|
+
im = proxy_info[ :im ]
|
1387
|
+
im_info = @im_infos[ im ]
|
1388
|
+
im_info[ :out ] += written if im_info
|
1389
|
+
data = data[ written..-1 ]
|
1390
|
+
proxy_info[ :wbuff ] = data
|
1391
|
+
bytesize = proxy_info[ :wbuff ].bytesize
|
1392
|
+
|
1393
|
+
if bytesize < RESUME_BELOW then
|
1394
|
+
if proxy_info[ :paused_dsts ].any? then
|
1395
|
+
puts "proxy underhalf resume dsts #{ im } #{ proxy_info[ :paused_dsts ].size }"
|
1396
|
+
proxy_info[ :paused_dsts ].each{ | dst | add_read( dst ) }
|
1397
|
+
proxy_info[ :paused_dsts ].clear
|
1398
|
+
end
|
1399
|
+
|
1400
|
+
if proxy_info[ :paused_p2s ].any? then
|
1401
|
+
puts "proxy underhalf resume p2s #{ im } #{ proxy_info[ :paused_p2s ].size }"
|
1402
|
+
proxy_info[ :paused_p2s ].each{ | p2 | add_read( p2 ) }
|
1403
|
+
proxy_info[ :paused_p2s ].clear
|
1404
|
+
end
|
1405
|
+
end
|
1406
|
+
end
|
1407
|
+
|
1408
|
+
end
|
1409
|
+
end
|