p2p2 0.22.0 → 0.27.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ed5928f54a6129f64cc843748d5f337d9f5fdccfed90239b9a594bf6ecd577bc
4
- data.tar.gz: 1ec20b3e82bf69b5e371ceb89dcc666b97f0a2407072647271e481c7a3166e4e
3
+ metadata.gz: 707396700d8514b51e69c74e0afe93349dd068cd2748ed3b298e0e41efe8fc8f
4
+ data.tar.gz: f5d8449949b2dc30d3b2013b529938bca812e2a683ae334fb5e9c076f449e484
5
5
  SHA512:
6
- metadata.gz: 2b35b3bc6a54ceb236aee2f9258580c381397619dcdfbe4dfd3ea61c8c6deeda1e6e188a64b6921794d801fd2838f5db3c7e00462be3cebfe5158e589356a8ff
7
- data.tar.gz: 9bd26990e4e3aff5285a10b011c322251ba3c64f5379e02172d70f16d9624355c8a9ec3f194b108c3681b966b38749d4bded464a9c9588bf3aca4e7645026e3f
6
+ metadata.gz: a87a15f1bf1281bb961f2b87d88b6a1ae33e3dc85bc37eb955ba1eb6ae9ec407c9333d7ea3891599f9f8dd061e6cb1a854f246a9edfe13060886fdd4c1cbc4b7
7
+ data.tar.gz: 0b56adf766ed041c1aa87d927c0e71e04cf58264da61531c39c1e3d27fa7b25e2710561d613c6bd10be33cd914c5cd45de32f78dc1e0e33247bbdade309c1621
data/lib/p2p2.rb CHANGED
@@ -1,3 +1,3 @@
1
- require 'p2p2/p1'
2
- require 'p2p2/p2'
3
- require 'p2p2/p2pd'
1
+ require 'p2p2/p1'
2
+ require 'p2p2/p2'
3
+ require 'p2p2/p2pd'
@@ -0,0 +1,36 @@
1
+ module P2p2
2
+ class ConcurrentHash < Hash
3
+ def initialize
4
+ super
5
+ @mutex = Mutex.new
6
+ end
7
+
8
+ def []( *args )
9
+ @mutex.synchronize { super }
10
+ end
11
+
12
+ def []=( *args )
13
+ @mutex.synchronize { super }
14
+ end
15
+
16
+ def clear( *args )
17
+ @mutex.synchronize { super }
18
+ end
19
+
20
+ def delete( *args )
21
+ @mutex.synchronize { super }
22
+ end
23
+
24
+ def each( *args )
25
+ @mutex.synchronize { super }
26
+ end
27
+
28
+ def include?( *args )
29
+ @mutex.synchronize { super }
30
+ end
31
+
32
+ def select( *args )
33
+ @mutex.synchronize { super }
34
+ end
35
+ end
36
+ end
data/lib/p2p2/head.rb CHANGED
@@ -1,29 +1,11 @@
1
- module P2p2
2
- PACK_SIZE = 1328 # 包大小 1400(console MTU) - 8(PPPoE header) - 40(IPv6 header) - 8(UDP header) - 8(pack id) - 8(src id) = 1328
3
- CHUNK_SIZE = PACK_SIZE * 1000 # 块大小
4
- WBUFFS_LIMIT = 1000 # 写前上限,超过上限结一个块
5
- WMEMS_LIMIT = 100_000 # 写后上限,达到上限暂停写
6
- RESUME_BELOW = 50_000 # 降到多少以下恢复写
7
- EXPIRE_NEW = 10 # 创建之后多久没有流量进来,过期
8
- EXPIRE_AFTER = 300 # 多久没有新流量,过期
9
- CHECK_EXPIRE_INTERVAL = 60 # 检查过期间隔
10
- STATUS_INTERVAL = 0.5 # 发送状态间隔
11
- SEND_STATUS_UNTIL = 10 # 持续的告之对面状态,直到没有流量往来,持续多少秒
12
- BREAK_SEND_MISS = 10_000 # miss包个数上限,达到上限忽略要后面的段,可控碎片缓存
13
- CONFUSE_UNTIL = 5 # 混淆前几个包
14
- HEARTBEAT_INTERVAL = 5 # 心跳间隔
15
- UPDATE_ROOM_INTERVAL = 60 # 刷新房间间隔
16
- PEER_ADDR = 1
17
- HEARTBEAT = 2
18
- A_NEW_SOURCE = 3
19
- PAIRED = 4
20
- DEST_STATUS = 5
21
- SOURCE_STATUS = 6
22
- MISS = 7
23
- FIN1 = 8
24
- GOT_FIN1 = 9
25
- FIN2 = 10
26
- GOT_FIN2 = 11
27
- TUND_FIN = 12
28
- TUN_FIN = 13
29
- end
1
+ module P2p2
2
+ READ_SIZE = 1024 * 1024 # 一次读多少
3
+ WBUFF_LIMIT = 50 * 1024 * 1024 # 写前上限,超过上限暂停读
4
+ RESUME_BELOW = WBUFF_LIMIT / 2 # 降到多少以下恢复读
5
+ RENEW_CTL_INTERVAL = 10 # p1心跳间隔,部分光猫udp端口映射过期时间只有10秒
6
+ CHECK_STATE_INTERVAL = 1 # 检查过期,恢复读间隔
7
+ EXPIRE_AFTER = 86400 # 多久没有新流量,过期
8
+ ROOM_TITLE_LIMIT = 16 # 房间名称字数
9
+ PUNCH_LIMIT = 5 # p2p重试次数
10
+ TO = ':' # 找房间前缀
11
+ end
data/lib/p2p2/p1.rb CHANGED
@@ -1,114 +1,57 @@
1
- require 'json'
2
- require 'p2p2/head'
3
- require 'p2p2/p1_custom'
4
- require 'p2p2/p1_worker'
5
- require 'p2p2/version'
6
- require 'socket'
7
-
8
- ##
9
- # P2p2::P1 - 内网里的任意应用,访问另一个内网里的应用服务端。p1端。
10
- #
11
- module P2p2
12
- class P1
13
-
14
- def initialize( config_path = nil )
15
- unless config_path
16
- config_path = File.expand_path( '../p2p2.conf.json', __FILE__ )
17
- end
18
-
19
- unless File.exist?( config_path )
20
- raise "missing config file #{ config_path }"
21
- end
22
-
23
- conf = JSON.parse( IO.binread( config_path ), symbolize_names: true )
24
- p2pd_host = conf[ :p2pd_host ]
25
- p2pd_port = conf[ :p2pd_port ]
26
- room = conf[ :room ]
27
- appd_host = conf[ :appd_host ]
28
- appd_port = conf[ :appd_port ]
29
- p1_tmp_dir = conf[ :p1_tmp_dir ]
30
-
31
- unless p2pd_host
32
- raise "missing p2pd host"
33
- end
34
-
35
- unless room
36
- raise "missing room"
37
- end
38
-
39
- unless p2pd_port
40
- p2pd_port = 2020
41
- end
42
-
43
- unless appd_host
44
- appd_host = '127.0.0.1'
45
- end
46
-
47
- unless appd_port
48
- appd_port = 22
49
- end
50
-
51
- unless p1_tmp_dir
52
- p1_tmp_dir = '/tmp/p2p2.p1'
53
- end
54
-
55
- unless File.exist?( p1_tmp_dir )
56
- Dir.mkdir( p1_tmp_dir )
57
- end
58
-
59
- dst_chunk_dir = File.join( p1_tmp_dir, 'dst.chunk' )
60
-
61
- unless Dir.exist?( dst_chunk_dir )
62
- Dir.mkdir( dst_chunk_dir )
63
- end
64
-
65
- tund_chunk_dir = File.join( p1_tmp_dir, 'tund.chunk' )
66
-
67
- unless Dir.exist?( tund_chunk_dir )
68
- Dir.mkdir( tund_chunk_dir )
69
- end
70
-
71
- title = "p2p2 p1 #{ P2p2::VERSION }"
72
- puts title
73
- puts "p2pd host #{ p2pd_host }"
74
- puts "p2pd port #{ p2pd_port }"
75
- puts "room #{ room }"
76
- puts "appd host #{ appd_host }"
77
- puts "appd port #{ appd_port }"
78
- puts "p1 tmp dir #{ p1_tmp_dir }"
79
- puts "dst chunk dir #{ dst_chunk_dir }"
80
- puts "tund chunk dir #{ tund_chunk_dir }"
81
-
82
- if RUBY_PLATFORM.include?( 'linux' )
83
- $0 = title
84
-
85
- pid = fork do
86
- $0 = 'p2p2 p1 worker'
87
- worker = P2p2::P1Worker.new( p2pd_host, p2pd_port, room, appd_host, appd_port, dst_chunk_dir, tund_chunk_dir )
88
-
89
- Signal.trap( :TERM ) do
90
- puts 'exit'
91
- worker.quit!
92
- end
93
-
94
- worker.looping
95
- end
96
-
97
- Signal.trap( :TERM ) do
98
- puts 'trap TERM'
99
-
100
- begin
101
- Process.kill( :TERM, pid )
102
- rescue Errno::ESRCH => e
103
- puts e.class
104
- end
105
- end
106
-
107
- Process.waitall
108
- else
109
- P2p2::P1Worker.new( p2pd_host, p2pd_port, room, appd_host, appd_port, dst_chunk_dir, tund_chunk_dir ).looping
110
- end
111
- end
112
-
113
- end
114
- end
1
+ require 'json'
2
+ require 'p2p2/concurrent_hash'
3
+ require 'p2p2/head'
4
+ require 'p2p2/p1_worker'
5
+ require 'p2p2/version'
6
+ require 'socket'
7
+
8
+ ##
9
+ # P2p2::P1 - p1
10
+ #
11
+ module P2p2
12
+ class P1
13
+
14
+ def initialize( config_path = nil )
15
+ unless config_path then
16
+ config_path = File.expand_path( '../p2p2.conf.json', __FILE__ )
17
+ end
18
+
19
+ raise "missing config file #{ config_path }" unless File.exist?( config_path )
20
+
21
+ conf = JSON.parse( IO.binread( config_path ), symbolize_names: true )
22
+ paird_host = conf[ :paird_host ]
23
+ paird_port = conf[ :paird_port ]
24
+ room = conf[ :room ]
25
+ appd_host = conf[ :appd_host ]
26
+ appd_port = conf[ :appd_port ]
27
+
28
+ raise 'missing paird host' unless paird_host
29
+ raise 'missing room' unless room
30
+
31
+ unless paird_port then
32
+ paird_port = 4040
33
+ end
34
+
35
+ unless appd_host then
36
+ appd_host = '127.0.0.1'
37
+ end
38
+
39
+ unless appd_port then
40
+ appd_port = 22
41
+ end
42
+
43
+ puts "p2p2 p1 #{ P2p2::VERSION }"
44
+ puts "paird #{ paird_host } #{ paird_port } room #{ room } appd #{ appd_host } #{ appd_port }"
45
+
46
+ worker = P2p2::P1Worker.new( paird_host, paird_port, room, appd_host, appd_port )
47
+
48
+ Signal.trap( :TERM ) do
49
+ puts 'exit'
50
+ worker.quit!
51
+ end
52
+
53
+ worker.looping
54
+ end
55
+
56
+ end
57
+ end
@@ -1,927 +1,727 @@
1
- module P2p2
2
- class P1Worker
3
-
4
- ##
5
- # initialize
6
- #
7
- def initialize( p2pd_host, p2pd_port, room, appd_host, appd_port, dst_chunk_dir, tund_chunk_dir )
8
- @p2pd_addr = Socket.sockaddr_in( p2pd_port, p2pd_host )
9
- @room = room
10
- @appd_addr = Socket.sockaddr_in( appd_port, appd_host )
11
- @dst_chunk_dir = dst_chunk_dir
12
- @tund_chunk_dir = tund_chunk_dir
13
- @custom = P2p2::P1Custom.new
14
- @mutex = Mutex.new
15
- @reads = []
16
- @writes = []
17
- @roles = {} # sock => :dotr / :dst / :tund
18
- @dst_infos = {} # dst => {}
19
-
20
- dotr, dotw = IO.pipe
21
- @dotw = dotw
22
- add_read( dotr, :dotr )
23
- new_a_tund
24
- end
25
-
26
- ##
27
- # looping
28
- #
29
- def looping
30
- puts "#{ Time.new } looping"
31
- loop_heartbeat
32
- loop_check_status
33
-
34
- loop do
35
- rs, ws = IO.select( @reads, @writes )
36
-
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
-
48
- rs.each do | sock |
49
- case @roles[ sock ]
50
- when :dotr
51
- read_dotr( sock )
52
- when :dst
53
- read_dst( sock )
54
- when :tund
55
- read_tund( sock )
56
- end
57
- end
58
- end
59
- end
60
- rescue Interrupt => e
61
- puts e.class
62
- quit!
63
- end
64
-
65
- ##
66
- # quit!
67
- #
68
- def quit!
69
- if !@tund.closed? && @tund_info[ :tun_addr ]
70
- # puts "debug1 send tund fin"
71
- data = [ 0, TUND_FIN ].pack( 'Q>C' )
72
- @tund.sendmsg( data, 0, @tund_info[ :tun_addr ] )
73
- end
74
-
75
- # puts "debug1 exit"
76
- exit
77
- end
78
-
79
- private
80
-
81
- ##
82
- # loop heartbeat
83
- #
84
- def loop_heartbeat( check_at = Time.new )
85
- Thread.new do
86
- loop do
87
- sleep HEARTBEAT_INTERVAL
88
-
89
- @mutex.synchronize do
90
- now = Time.new
91
-
92
- unless @tund.closed?
93
- if @tund_info[ :peer_addr ]
94
- if @tund_info[ :tun_addr ]
95
- if now - check_at >= CHECK_EXPIRE_INTERVAL
96
- if now - @tund_info[ :last_recv_at ] > EXPIRE_AFTER
97
- puts "#{ Time.new } expire tund"
98
- set_is_closing( @tund )
99
- else
100
- @tund_info[ :dst_exts ].each do | dst_local_port, dst_ext |
101
- if dst_ext[ :dst ].closed? && ( now - dst_ext[ :last_continue_at ] > EXPIRE_AFTER )
102
- puts "#{ Time.new } expire dst ext #{ dst_local_port }"
103
- del_dst_ext( dst_local_port )
104
- end
105
- end
106
- end
107
-
108
- @dst_infos.each do | dst, dst_info |
109
- if dst_info[ :last_recv_at ].nil? && ( now - dst_info[ :created_at ] > EXPIRE_NEW )
110
- puts "#{ Time.new } expire dst"
111
- set_is_closing( dst )
112
- end
113
- end
114
-
115
- check_at = now
116
- end
117
-
118
- # puts "debug2 heartbeat"
119
- add_tund_ctlmsg( pack_a_heartbeat )
120
- next_tick
121
- elsif now - @tund_info[ :created_at ] > EXPIRE_NEW
122
- # no tun addr
123
- puts "#{ Time.new } expire new tund"
124
- set_is_closing( @tund )
125
- next_tick
126
- end
127
- else
128
- # no peer addr
129
- if now - check_at >= UPDATE_ROOM_INTERVAL
130
- data = @room
131
- check_at = now
132
- else
133
- data = [ rand( 128 ) ].pack( 'C' )
134
- end
135
-
136
- # puts "debug2 update room"
137
- add_tund_ctlmsg( data, @p2pd_addr )
138
- next_tick
139
- end
140
- end
141
- end
142
- end
143
- end
144
- end
145
-
146
- ##
147
- # loop check status
148
- #
149
- def loop_check_status
150
- Thread.new do
151
- loop do
152
- sleep STATUS_INTERVAL
153
-
154
- @mutex.synchronize do
155
- if !@tund.closed? && @tund_info[ :tun_addr ]
156
- need_trigger = false
157
-
158
- if @tund_info[ :dst_exts ].any?
159
- now = Time.new
160
-
161
- @tund_info[ :dst_exts ].each do | dst_local_port, dst_ext |
162
- if now - dst_ext[ :last_continue_at ] < SEND_STATUS_UNTIL
163
- data = [ 0, DEST_STATUS, dst_local_port, dst_ext[ :relay_pack_id ], dst_ext[ :continue_src_pack_id ] ].pack( 'Q>CnQ>Q>' )
164
- add_tund_ctlmsg( data )
165
- need_trigger = true
166
- end
167
- end
168
- end
169
-
170
- if @tund_info[ :paused ] && ( @tund_info[ :dst_exts ].map{ | _, dst_ext | dst_ext[ :wmems ].size }.sum < RESUME_BELOW )
171
- puts "#{ Time.new } resume tund"
172
- @tund_info[ :paused ] = false
173
- add_write( @tund )
174
- need_trigger = true
175
- end
176
-
177
- if need_trigger
178
- next_tick
179
- end
180
- end
181
- end
182
- end
183
- end
184
- end
185
-
186
- ##
187
- # loop punch peer
188
- #
189
- def loop_punch_peer
190
- Thread.new do
191
- EXPIRE_NEW.times do
192
- if @tund.closed?
193
- # puts "debug1 break loop punch peer"
194
- break
195
- end
196
-
197
- @mutex.synchronize do
198
- # puts "debug1 punch peer"
199
- add_tund_ctlmsg( pack_a_heartbeat, @tund_info[ :peer_addr ] )
200
- next_tick
201
- end
202
-
203
- sleep 1
204
- end
205
- end
206
- end
207
-
208
- ##
209
- # new a tund
210
- #
211
- def new_a_tund
212
- tund = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
213
- tund.bind( Socket.sockaddr_in( 0, '0.0.0.0' ) )
214
- port = tund.local_address.ip_port
215
- puts "#{ Time.new } tund bind on #{ port }"
216
-
217
- tund_info = {
218
- port: port, # 端口
219
- ctlmsgs: [], # [ to_addr, data ]
220
- wbuffs: [], # 写前缓存 [ dst_local_port, pack_id, data ]
221
- caches: [], # 块读出缓存 [ dst_local_port, pack_id, data ]
222
- chunks: [], # 块队列 filename
223
- spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
224
- peer_addr: nil, # 对面地址
225
- tun_addr: nil, # 连通后的tun地址
226
- dst_exts: {}, # dst额外信息 dst_local_port => {}
227
- dst_local_ports: {}, # src_id => dst_local_port
228
- paused: false, # 是否暂停写
229
- resendings: [], # 重传队列 [ dst_local_port, pack_id ]
230
- created_at: Time.new, # 创建时间
231
- last_recv_at: nil, # 上一次收到流量的时间,过期关闭
232
- is_closing: false # 是否准备关闭
233
- }
234
-
235
- @tund = tund
236
- @tund_info = tund_info
237
- add_read( tund, :tund )
238
- add_tund_ctlmsg( @room, @p2pd_addr )
239
- end
240
-
241
- ##
242
- # pack a heartbeat
243
- #
244
- def pack_a_heartbeat
245
- [ 0, HEARTBEAT, rand( 128 ) ].pack( 'Q>CC' )
246
- end
247
-
248
- ##
249
- # is match tun addr
250
- #
251
- def is_match_tun_addr( addrinfo )
252
- return false unless @tund_info[ :tun_addr ]
253
-
254
- from_addr = addrinfo.to_sockaddr
255
-
256
- if from_addr != @tund_info[ :tun_addr ]
257
- puts "#{ Time.new } #{ addrinfo.inspect } not match #{ Addrinfo.new( @tund_info[ :tun_addr ] ).inspect }"
258
- return false
259
- end
260
-
261
- @tund_info[ :last_recv_at ] = Time.new
262
-
263
- true
264
- end
265
-
266
- ##
267
- # add tund ctlmsg
268
- #
269
- def add_tund_ctlmsg( data, to_addr = nil )
270
- unless to_addr
271
- to_addr = @tund_info[ :tun_addr ]
272
- end
273
-
274
- if to_addr
275
- @tund_info[ :ctlmsgs ] << [ to_addr, data ]
276
- add_write( @tund )
277
- end
278
- end
279
-
280
- ##
281
- # add tund wbuff
282
- #
283
- def add_tund_wbuff( dst_local_port, pack_id, data )
284
- @tund_info[ :wbuffs ] << [ dst_local_port, pack_id, data ]
285
-
286
- if @tund_info[ :wbuffs ].size >= WBUFFS_LIMIT
287
- spring = @tund_info[ :chunks ].size > 0 ? ( @tund_info[ :spring ] + 1 ) : 0
288
- filename = "#{ Process.pid }-#{ @tund_info[ :port ] }.#{ spring }"
289
- chunk_path = File.join( @tund_chunk_dir, filename )
290
- datas = @tund_info[ :wbuffs ].map{ | _dst_local_port, _pack_id, _data | [ [ _dst_local_port, _pack_id, _data.bytesize ].pack( 'nQ>n' ), _data ].join }
291
-
292
- begin
293
- IO.binwrite( chunk_path, datas.join )
294
- rescue Errno::ENOSPC => e
295
- puts "#{ Time.new } #{ e.class }, close tund"
296
- set_is_closing( @tund )
297
- return
298
- end
299
-
300
- @tund_info[ :chunks ] << filename
301
- @tund_info[ :spring ] = spring
302
- @tund_info[ :wbuffs ].clear
303
- end
304
-
305
- add_write( @tund )
306
- end
307
-
308
- ##
309
- # add dst wbuff
310
- #
311
- def add_dst_wbuff( dst, data )
312
- dst_info = @dst_infos[ dst ]
313
- dst_info[ :wbuff ] << data
314
-
315
- if dst_info[ :wbuff ].bytesize >= CHUNK_SIZE
316
- spring = dst_info[ :chunks ].size > 0 ? ( dst_info[ :spring ] + 1 ) : 0
317
- filename = "#{ Process.pid }-#{ dst_info[ :local_port ] }.#{ spring }"
318
- chunk_path = File.join( @dst_chunk_dir, filename )
319
-
320
- begin
321
- IO.binwrite( chunk_path, dst_info[ :wbuff ] )
322
- rescue Errno::ENOSPC => e
323
- puts "#{ Time.new } #{ e.class }, close dst"
324
- set_is_closing( dst )
325
- return
326
- end
327
-
328
- dst_info[ :chunks ] << filename
329
- dst_info[ :spring ] = spring
330
- dst_info[ :wbuff ].clear
331
- end
332
-
333
- add_write( dst )
334
- end
335
-
336
- ##
337
- # add read
338
- #
339
- def add_read( sock, role )
340
- unless @reads.include?( sock )
341
- @reads << sock
342
- end
343
-
344
- @roles[ sock ] = role
345
- end
346
-
347
- ##
348
- # add write
349
- #
350
- def add_write( sock )
351
- if sock && !sock.closed? && !@writes.include?( sock )
352
- @writes << sock
353
- end
354
- end
355
-
356
- ##
357
- # set is closing
358
- #
359
- def set_is_closing( sock )
360
- if sock && !sock.closed?
361
- role = @roles[ sock ]
362
- # puts "debug1 set #{ role.to_s } is closing"
363
-
364
- case role
365
- when :dst
366
- dst_info = @dst_infos[ sock ]
367
- dst_info[ :is_closing ] = true
368
- when :tund
369
- @tund_info[ :is_closing ] = true
370
- end
371
-
372
- @reads.delete( sock )
373
- add_write( sock )
374
- end
375
- end
376
-
377
- ##
378
- # close dst
379
- #
380
- def close_dst( dst )
381
- # puts "debug1 close dst"
382
- close_sock( dst )
383
- dst_info = @dst_infos.delete( dst )
384
-
385
- dst_info[ :chunks ].each do | filename |
386
- begin
387
- File.delete( File.join( @dst_chunk_dir, filename ) )
388
- rescue Errno::ENOENT
389
- end
390
- end
391
-
392
- return if @tund.closed?
393
-
394
- local_port = dst_info[ :local_port ]
395
- dst_ext = @tund_info[ :dst_exts ][ local_port ]
396
- return unless dst_ext
397
-
398
- if dst_ext[ :is_src_closed ]
399
- # puts "debug1 4-3. after close dst -> src closed ? yes -> del dst ext -> send fin2"
400
- del_dst_ext( local_port )
401
- data = [ 0, FIN2, local_port ].pack( 'Q>Cn' )
402
- add_tund_ctlmsg( data )
403
- else
404
- # puts "debug1 3-1. after close dst -> src closed ? no -> send fin1"
405
- data = [ 0, FIN1, local_port, dst_info[ :biggest_pack_id ], dst_ext[ :continue_src_pack_id ] ].pack( 'Q>CnQ>Q>' )
406
- add_tund_ctlmsg( data )
407
- end
408
- end
409
-
410
- ##
411
- # close tund
412
- #
413
- def close_tund( tund )
414
- # puts "debug1 close tund"
415
- close_sock( tund )
416
-
417
- @tund_info[ :chunks ].each do | filename |
418
- begin
419
- File.delete( File.join( @tund_chunk_dir, filename ) )
420
- rescue Errno::ENOENT
421
- end
422
- end
423
-
424
- @tund_info[ :dst_exts ].each{ | _, dst_ext | set_is_closing( dst_ext[ :dst ] ) }
425
- end
426
-
427
- ##
428
- # close sock
429
- #
430
- def close_sock( sock )
431
- sock.close
432
- @reads.delete( sock )
433
- @writes.delete( sock )
434
- @roles.delete( sock )
435
- end
436
-
437
- ##
438
- # del dst ext
439
- #
440
- def del_dst_ext( dst_local_port )
441
- dst_ext = @tund_info[ :dst_exts ].delete( dst_local_port )
442
-
443
- if dst_ext
444
- @tund_info[ :dst_local_ports ].delete( dst_ext[ :src_id ] )
445
- end
446
- end
447
-
448
- ##
449
- # release wmems
450
- #
451
- def release_wmems( dst_ext, completed_pack_id )
452
- if completed_pack_id > dst_ext[ :completed_pack_id ]
453
- # puts "debug2 update completed pack #{ completed_pack_id }"
454
-
455
- pack_ids = dst_ext[ :wmems ].keys.select { | pack_id | pack_id <= completed_pack_id }
456
-
457
- pack_ids.each do | pack_id |
458
- dst_ext[ :wmems ].delete( pack_id )
459
- dst_ext[ :send_ats ].delete( pack_id )
460
- end
461
-
462
- dst_ext[ :completed_pack_id ] = completed_pack_id
463
- end
464
- end
465
-
466
- ##
467
- # next tick
468
- #
469
- def next_tick
470
- @dotw.write( '.' )
471
- end
472
-
473
- ##
474
- # write dst
475
- #
476
- def write_dst( dst )
477
- dst_info = @dst_infos[ dst ]
478
- data = dst_info[ :cache ]
479
- from = :cache
480
-
481
- if data.empty?
482
- if dst_info[ :chunks ].any?
483
- path = File.join( @dst_chunk_dir, dst_info[ :chunks ].shift )
484
-
485
- begin
486
- dst_info[ :cache ] = data = IO.binread( path )
487
- File.delete( path )
488
- rescue Errno::ENOENT => e
489
- puts "#{ Time.new } read #{ path } #{ e.class }"
490
- close_dst( dst )
491
- return
492
- end
493
- else
494
- data = dst_info[ :wbuff ]
495
- from = :wbuff
496
- end
497
- end
498
-
499
- if data.empty?
500
- if dst_info[ :is_closing ]
501
- close_dst( dst )
502
- else
503
- @writes.delete( dst )
504
- end
505
-
506
- return
507
- end
508
-
509
- begin
510
- written = dst.write_nonblock( data )
511
- rescue IO::WaitWritable, Errno::EINTR
512
- return
513
- rescue Exception => e
514
- # puts "debug1 write dst #{ e.class }"
515
- close_dst( dst )
516
- return
517
- end
518
-
519
- # puts "debug2 write dst #{ written }"
520
- data = data[ written..-1 ]
521
- dst_info[ from ] = data
522
- end
523
-
524
- ##
525
- # write tund
526
- #
527
- def write_tund( tund )
528
- if @tund_info[ :is_closing ]
529
- close_tund( tund )
530
- new_a_tund
531
- return
532
- end
533
-
534
- # 传ctlmsg
535
- while @tund_info[ :ctlmsgs ].any?
536
- to_addr, data = @tund_info[ :ctlmsgs ].first
537
-
538
- begin
539
- tund.sendmsg( data, 0, to_addr )
540
- rescue IO::WaitWritable, Errno::EINTR
541
- return
542
- rescue Errno::EHOSTUNREACH, Errno::ENETUNREACH => e
543
- puts "#{ Time.new } #{ e.class }, close tund"
544
- close_tund( tund )
545
- return
546
- end
547
-
548
- @tund_info[ :ctlmsgs ].shift
549
- end
550
-
551
- # 重传
552
- while @tund_info[ :resendings ].any?
553
- dst_local_port, pack_id = @tund_info[ :resendings ].first
554
- dst_ext = @tund_info[ :dst_exts ][ dst_local_port ]
555
-
556
- if dst_ext
557
- data = dst_ext[ :wmems ][ pack_id ]
558
-
559
- if data
560
- begin
561
- tund.sendmsg( data, 0, @tund_info[ :tun_addr ] )
562
- rescue IO::WaitWritable, Errno::EINTR
563
- return
564
- rescue Errno::EHOSTUNREACH, Errno::ENETUNREACH => e
565
- puts "#{ Time.new } #{ e.class }, close tund"
566
- close_tund( tund )
567
- return
568
- end
569
- end
570
- end
571
-
572
- @tund_info[ :resendings ].shift
573
- return
574
- end
575
-
576
- # 若写后达到上限,暂停取写前
577
- if @tund_info[ :dst_exts ].map{ | _, dst_ext | dst_ext[ :wmems ].size }.sum >= WMEMS_LIMIT
578
- unless @tund_info[ :paused ]
579
- puts "#{ Time.new } pause tund #{ @tund_info[ :port ] }"
580
- @tund_info[ :paused ] = true
581
- end
582
-
583
- @writes.delete( tund )
584
- return
585
- end
586
-
587
- # 取写前
588
- if @tund_info[ :caches ].any?
589
- dst_local_port, pack_id, data = @tund_info[ :caches ].first
590
- from = :caches
591
- elsif @tund_info[ :chunks ].any?
592
- path = File.join( @tund_chunk_dir, @tund_info[ :chunks ].shift )
593
-
594
- begin
595
- data = IO.binread( path )
596
- File.delete( path )
597
- rescue Errno::ENOENT => e
598
- puts "#{ Time.new } read #{ path } #{ e.class }"
599
- close_tund( tund )
600
- return
601
- end
602
-
603
- caches = []
604
-
605
- until data.empty?
606
- _dst_local_port, _pack_id, pack_size = data[ 0, 12 ].unpack( 'nQ>n' )
607
- caches << [ _dst_local_port, _pack_id, data[ 12, pack_size ] ]
608
- data = data[ ( 12 + pack_size )..-1 ]
609
- end
610
-
611
- @tund_info[ :caches ] = caches
612
- dst_local_port, pack_id, data = caches.first
613
- from = :caches
614
- elsif @tund_info[ :wbuffs ].any?
615
- dst_local_port, pack_id, data = @tund_info[ :wbuffs ].first
616
- from = :wbuffs
617
- else
618
- @writes.delete( tund )
619
- return
620
- end
621
-
622
- dst_ext = @tund_info[ :dst_exts ][ dst_local_port ]
623
-
624
- if dst_ext
625
- if pack_id <= CONFUSE_UNTIL
626
- data = @custom.encode( data )
627
- # puts "debug1 encoded pack #{ pack_id }"
628
- end
629
-
630
- data = [ [ pack_id, dst_local_port ].pack( 'Q>n' ), data ].join
631
-
632
- begin
633
- tund.sendmsg( data, 0, @tund_info[ :tun_addr ] )
634
- rescue IO::WaitWritable, Errno::EINTR
635
- return
636
- rescue Errno::EHOSTUNREACH, Errno::ENETUNREACH => e
637
- puts "#{ Time.new } #{ e.class }, close tund"
638
- close_tund( tund )
639
- return
640
- end
641
-
642
- # puts "debug2 written pack #{ pack_id }"
643
- now = Time.new
644
- dst_ext[ :relay_pack_id ] = pack_id
645
- dst_ext[ :wmems ][ pack_id ] = data
646
- dst_ext[ :send_ats ][ pack_id ] = now
647
- dst_ext[ :last_continue_at ] = now
648
- end
649
-
650
- @tund_info[ from ].shift
651
- end
652
-
653
- ##
654
- # read dotr
655
- #
656
- def read_dotr( dotr )
657
- dotr.read( 1 )
658
- end
659
-
660
- ##
661
- # read dst
662
- #
663
- def read_dst( dst )
664
- begin
665
- data = dst.read_nonblock( PACK_SIZE )
666
- rescue IO::WaitReadable, Errno::EINTR
667
- return
668
- rescue Exception => e
669
- # puts "debug1 read dst #{ e.class }"
670
- set_is_closing( dst )
671
- return
672
- end
673
-
674
- # puts "debug2 read dst #{ data.inspect }"
675
- dst_info = @dst_infos[ dst ]
676
- dst_info[ :last_recv_at ] = Time.new
677
-
678
- if @tund.closed?
679
- puts "#{ Time.new } tund closed, close dst"
680
- set_is_closing( dst )
681
- return
682
- end
683
-
684
- pack_id = dst_info[ :biggest_pack_id ] + 1
685
- dst_info[ :biggest_pack_id ] = pack_id
686
- add_tund_wbuff( dst_info[ :local_port ], pack_id, data )
687
- end
688
-
689
- ##
690
- # read tund
691
- #
692
- def read_tund( tund )
693
- data, addrinfo, rflags, *controls = tund.recvmsg
694
- now = Time.new
695
- pack_id = data[ 0, 8 ].unpack( 'Q>' ).first
696
-
697
- if pack_id == 0
698
- ctl_num = data[ 8 ].unpack( 'C' ).first
699
-
700
- case ctl_num
701
- when PEER_ADDR
702
- return if @tund_info[ :peer_addr ] || ( addrinfo.to_sockaddr != @p2pd_addr )
703
-
704
- peer_addr = data[ 9..-1 ]
705
- puts "#{ Time.new } got peer addr #{ Addrinfo.new( peer_addr ).inspect }"
706
-
707
- @tund_info[ :peer_addr ] = peer_addr
708
- loop_punch_peer
709
- when HEARTBEAT
710
- from_addr = addrinfo.to_sockaddr
711
- return if from_addr != @tund_info[ :peer_addr ]
712
-
713
- # puts "debug1 set tun addr #{ Addrinfo.new( from_addr ).inspect }"
714
- @tund_info[ :tun_addr ] = from_addr
715
- @tund_info[ :last_recv_at ] = now
716
- when A_NEW_SOURCE
717
- return unless is_match_tun_addr( addrinfo )
718
-
719
- src_id = data[ 9, 8 ].unpack( 'Q>' ).first
720
- dst_local_port = @tund_info[ :dst_local_ports ][ src_id ]
721
- # puts "debug1 got a new source #{ src_id }"
722
-
723
- if dst_local_port
724
- dst_ext = @tund_info[ :dst_exts ][ dst_local_port ]
725
- return unless dst_ext
726
-
727
- if dst_ext[ :dst ].closed?
728
- dst_local_port = 0
729
- end
730
- else
731
- dst = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
732
-
733
- if RUBY_PLATFORM.include?( 'linux' )
734
- dst.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 )
735
- end
736
-
737
- begin
738
- dst.connect_nonblock( @appd_addr )
739
- rescue IO::WaitWritable
740
- rescue Exception => e
741
- puts "#{ Time.new } connect appd #{ e.class }"
742
- return
743
- end
744
-
745
- dst_local_port = dst.local_address.ip_port
746
-
747
- @dst_infos[ dst ] = {
748
- local_port: dst_local_port, # 本地端口
749
- biggest_pack_id: 0, # 最大包号码
750
- wbuff: '', # 写前
751
- cache: '', # 块读出缓存
752
- chunks: [], # 块队列,写前达到块大小时结一个块 filename
753
- spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
754
- created_at: Time.new, # 创建时间
755
- last_recv_at: nil, # 上一次收到流量的时间,过期关闭
756
- is_closing: false # 是否准备关闭
757
- }
758
- add_read( dst, :dst )
759
-
760
- @tund_info[ :dst_local_ports ][ src_id ] = dst_local_port
761
- @tund_info[ :dst_exts ][ dst_local_port ] = {
762
- dst: dst, # dst
763
- src_id: src_id, # 近端src id
764
- wmems: {}, # 写后 pack_id => data
765
- send_ats: {}, # 上一次发出时间 pack_id => send_at
766
- relay_pack_id: 0, # 转发到几
767
- continue_src_pack_id: 0, # 收到几
768
- pieces: {}, # 跳号包 src_pack_id => data
769
- is_src_closed: false, # src是否已关闭
770
- biggest_src_pack_id: 0, # src最大包号码
771
- completed_pack_id: 0, # 完成到几(对面收到几)
772
- last_continue_at: Time.new # 创建,或者上一次收到连续流量,或者发出新包的时间
773
- }
774
- end
775
-
776
- data2 = [ 0, PAIRED, src_id, dst_local_port ].pack( 'Q>CQ>n' )
777
- # puts "debug1 add ctlmsg paired #{ data2.inspect }"
778
- add_tund_ctlmsg( data2 )
779
- when SOURCE_STATUS
780
- return unless is_match_tun_addr( addrinfo )
781
-
782
- src_id, relay_src_pack_id, continue_dst_pack_id = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
783
-
784
- dst_local_port = @tund_info[ :dst_local_ports ][ src_id ]
785
- return unless dst_local_port
786
-
787
- dst_ext = @tund_info[ :dst_exts ][ dst_local_port ]
788
- return unless dst_ext
789
-
790
- # puts "debug2 got source status"
791
-
792
- release_wmems( dst_ext, continue_dst_pack_id )
793
-
794
- # 发miss
795
- if !dst_ext[ :dst ].closed? && ( dst_ext[ :continue_src_pack_id ] < relay_src_pack_id )
796
- ranges = []
797
- curr_pack_id = dst_ext[ :continue_src_pack_id ] + 1
798
-
799
- dst_ext[ :pieces ].keys.sort.each do | pack_id |
800
- if pack_id > curr_pack_id
801
- ranges << [ curr_pack_id, pack_id - 1 ]
802
- end
803
-
804
- curr_pack_id = pack_id + 1
805
- end
806
-
807
- if curr_pack_id <= relay_src_pack_id
808
- ranges << [ curr_pack_id, relay_src_pack_id ]
809
- end
810
-
811
- pack_count = 0
812
- # puts "debug1 continue/relay #{ dst_ext[ :continue_src_pack_id ] }/#{ relay_src_pack_id } send MISS #{ ranges.size }"
813
-
814
- ranges.each do | pack_id_begin, pack_id_end |
815
- if pack_count >= BREAK_SEND_MISS
816
- puts "#{ Time.new } break send miss at #{ pack_id_begin }"
817
- break
818
- end
819
-
820
- data2 = [ 0, MISS, src_id, pack_id_begin, pack_id_end ].pack( 'Q>CQ>Q>Q>' )
821
- add_tund_ctlmsg( data2 )
822
- pack_count += ( pack_id_end - pack_id_begin + 1 )
823
- end
824
- end
825
- when MISS
826
- return unless is_match_tun_addr( addrinfo )
827
-
828
- dst_local_port, pack_id_begin, pack_id_end = data[ 9, 18 ].unpack( 'nQ>Q>' )
829
-
830
- dst_ext = @tund_info[ :dst_exts ][ dst_local_port ]
831
- return unless dst_ext
832
-
833
- ( pack_id_begin..pack_id_end ).each do | pack_id |
834
- send_at = dst_ext[ :send_ats ][ pack_id ]
835
-
836
- if send_at
837
- break if now - send_at < STATUS_INTERVAL
838
- @tund_info[ :resendings ] << [ dst_local_port, pack_id ]
839
- end
840
- end
841
-
842
- add_write( tund )
843
- when FIN1
844
- return unless is_match_tun_addr( addrinfo )
845
-
846
- src_id, biggest_src_pack_id, continue_dst_pack_id = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
847
-
848
- dst_local_port = @tund_info[ :dst_local_ports ][ src_id ]
849
- return unless dst_local_port
850
-
851
- dst_ext = @tund_info[ :dst_exts ][ dst_local_port ]
852
- return unless dst_ext
853
-
854
- # puts "debug1 got fin1 #{ src_id } biggest src pack #{ biggest_src_pack_id } completed dst pack #{ continue_dst_pack_id }"
855
- dst_ext[ :is_src_closed ] = true
856
- dst_ext[ :biggest_src_pack_id ] = biggest_src_pack_id
857
- release_wmems( dst_ext, continue_dst_pack_id )
858
-
859
- if biggest_src_pack_id == dst_ext[ :continue_src_pack_id ]
860
- # puts "debug1 4-1. tund recv fin1 -> all traffic received ? -> close dst after write"
861
- set_is_closing( dst_ext[ :dst ] )
862
- end
863
- when FIN2
864
- return unless is_match_tun_addr( addrinfo )
865
-
866
- src_id = data[ 9, 8 ].unpack( 'Q>' ).first
867
-
868
- dst_local_port = @tund_info[ :dst_local_ports ][ src_id ]
869
- return unless dst_local_port
870
-
871
- # puts "debug1 3-2. tund recv fin2 -> del dst ext"
872
- del_dst_ext( dst_local_port )
873
- when TUN_FIN
874
- return unless is_match_tun_addr( addrinfo )
875
-
876
- puts "#{ Time.new } recv tun fin"
877
- set_is_closing( tund )
878
- end
879
-
880
- return
881
- end
882
-
883
- return unless is_match_tun_addr( addrinfo )
884
-
885
- src_id = data[ 8, 8 ].unpack( 'Q>' ).first
886
-
887
- dst_local_port = @tund_info[ :dst_local_ports ][ src_id ]
888
- return unless dst_local_port
889
-
890
- dst_ext = @tund_info[ :dst_exts ][ dst_local_port ]
891
- return if dst_ext.nil? || dst_ext[ :dst ].closed?
892
- return if ( pack_id <= dst_ext[ :continue_src_pack_id ] ) || dst_ext[ :pieces ].include?( pack_id )
893
-
894
- data = data[ 16..-1 ]
895
- # puts "debug2 got pack #{ pack_id }"
896
-
897
- if pack_id <= CONFUSE_UNTIL
898
- # puts "debug2 #{ data.inspect }"
899
- data = @custom.decode( data )
900
- # puts "debug1 decoded pack #{ pack_id }"
901
- end
902
-
903
- # 放进写前,跳号放碎片缓存
904
- if pack_id - dst_ext[ :continue_src_pack_id ] == 1
905
- while dst_ext[ :pieces ].include?( pack_id + 1 )
906
- data << dst_ext[ :pieces ].delete( pack_id + 1 )
907
- pack_id += 1
908
- end
909
-
910
- dst_ext[ :continue_src_pack_id ] = pack_id
911
- dst_ext[ :last_continue_at ] = now
912
- add_dst_wbuff( dst_ext[ :dst ], data )
913
- # puts "debug2 update continue src pack #{ pack_id }"
914
-
915
- # 接到流量,若对面已关闭,且流量正好收全,关闭dst
916
- if dst_ext[ :is_src_closed ] && ( pack_id == dst_ext[ :biggest_src_pack_id ] )
917
- # puts "debug1 4-2. tund recv traffic -> src closed and all traffic received ? -> close dst after write"
918
- set_is_closing( dst_ext[ :dst ] )
919
- return
920
- end
921
- else
922
- dst_ext[ :pieces ][ pack_id ] = data
923
- end
924
- end
925
-
926
- end
927
- end
1
+ module P2p2
2
+ class P1Worker
3
+
4
+ ##
5
+ # initialize
6
+ #
7
+ def initialize( paird_host, paird_port, title, appd_host, appd_port )
8
+ @paird_host = paird_host
9
+ @paird_port = paird_port
10
+ @title = title
11
+ @appd_addr = Socket.sockaddr_in( appd_port, appd_host )
12
+ @reads = []
13
+ @writes = []
14
+ @roles = {} # sock => :dotr / :ctl / :tun / :dst
15
+ @dst_infos = ConcurrentHash.new
16
+ @tun_infos = ConcurrentHash.new
17
+
18
+ new_a_pipe
19
+ new_a_ctl
20
+ end
21
+
22
+ ##
23
+ # looping
24
+ #
25
+ def looping
26
+ puts "#{ Time.new } looping"
27
+ loop_renew_ctl
28
+ loop_check_state
29
+
30
+ loop do
31
+ rs, ws = IO.select( @reads, @writes )
32
+
33
+ rs.each do | sock |
34
+ role = @roles[ sock ]
35
+
36
+ case role
37
+ when :dotr then
38
+ read_dotr( sock )
39
+ when :ctl then
40
+ read_ctl( sock )
41
+ when :tun then
42
+ read_tun( sock )
43
+ when :dst then
44
+ read_dst( sock )
45
+ else
46
+ puts "#{ Time.new } read unknown role #{ role }"
47
+ close_sock( sock )
48
+ end
49
+ end
50
+
51
+ ws.each do | sock |
52
+ role = @roles[ sock ]
53
+
54
+ case role
55
+ when :tun then
56
+ write_tun( sock )
57
+ when :dst then
58
+ write_dst( sock )
59
+ else
60
+ puts "#{ Time.new } write unknown role #{ role }"
61
+ close_sock( sock )
62
+ end
63
+ end
64
+ end
65
+ rescue Interrupt => e
66
+ puts e.class
67
+ quit!
68
+ end
69
+
70
+ ##
71
+ # quit!
72
+ #
73
+ def quit!
74
+ # puts "debug exit"
75
+ exit
76
+ end
77
+
78
+ private
79
+
80
+ ##
81
+ # add dst rbuff
82
+ #
83
+ def add_dst_rbuff( dst, data )
84
+ return if dst.nil? || dst.closed?
85
+ dst_info = @dst_infos[ dst ]
86
+ dst_info[ :rbuff ] << data
87
+
88
+ if dst_info[ :rbuff ].bytesize >= WBUFF_LIMIT then
89
+ puts "#{ Time.new } dst.rbuff full"
90
+ close_dst( dst )
91
+ end
92
+ end
93
+
94
+ ##
95
+ # add dst wbuff
96
+ #
97
+ def add_dst_wbuff( dst, data )
98
+ return if dst.nil? || dst.closed?
99
+ dst_info = @dst_infos[ dst ]
100
+ dst_info[ :wbuff ] << data
101
+ dst_info[ :last_recv_at ] = Time.new
102
+ add_write( dst )
103
+
104
+ if dst_info[ :wbuff ].bytesize >= WBUFF_LIMIT then
105
+ tun = dst_info[ :tun ]
106
+
107
+ if tun && !tun.closed? then
108
+ puts "#{ Time.new } pause tun"
109
+ @reads.delete( tun )
110
+ tun_info = @tun_infos[ tun ]
111
+ tun_info[ :paused ] = true
112
+ end
113
+ end
114
+ end
115
+
116
+ ##
117
+ # add read
118
+ #
119
+ def add_read( sock, role = nil )
120
+ return if sock.nil? || sock.closed? || @reads.include?( sock )
121
+ @reads << sock
122
+
123
+ if role then
124
+ @roles[ sock ] = role
125
+ end
126
+ end
127
+
128
+ ##
129
+ # add tun wbuff
130
+ #
131
+ def add_tun_wbuff( tun, data )
132
+ return if tun.nil? || tun.closed?
133
+ tun_info = @tun_infos[ tun ]
134
+ tun_info[ :wbuff ] << data
135
+ add_write( tun )
136
+
137
+ if tun_info[ :wbuff ].bytesize >= WBUFF_LIMIT then
138
+ dst = tun_info[ :dst ]
139
+
140
+ if dst && !dst.closed? then
141
+ puts "#{ Time.new } pause dst"
142
+ @reads.delete( dst )
143
+ dst_info = @dst_infos[ dst ]
144
+ dst_info[ :paused ] = true
145
+ end
146
+ end
147
+ end
148
+
149
+ ##
150
+ # add write
151
+ #
152
+ def add_write( sock )
153
+ return if sock.nil? || sock.closed? || @writes.include?( sock )
154
+ @writes << sock
155
+ end
156
+
157
+ ##
158
+ # close ctl
159
+ #
160
+ def close_ctl
161
+ return if @ctl.nil? || @ctl.closed?
162
+ close_sock( @ctl )
163
+ end
164
+
165
+ ##
166
+ # close dst
167
+ #
168
+ def close_dst( dst )
169
+ return if dst.nil? || dst.closed?
170
+ puts "#{ Time.new } close dst"
171
+ close_sock( dst )
172
+ @dst_infos.delete( dst )
173
+ end
174
+
175
+ ##
176
+ # close read dst
177
+ #
178
+ def close_read_dst( dst )
179
+ return if dst.nil? || dst.closed?
180
+ # puts "debug close read dst"
181
+ dst.close_read
182
+ @reads.delete( dst )
183
+
184
+ if dst.closed? then
185
+ # puts "debug dst closed"
186
+ @writes.delete( dst )
187
+ @roles.delete( dst )
188
+ @dst_infos.delete( dst )
189
+ end
190
+ end
191
+
192
+ ##
193
+ # close read tun
194
+ #
195
+ def close_read_tun( tun )
196
+ return if tun.nil? || tun.closed?
197
+ # puts "debug close read tun"
198
+ tun.close_read
199
+ @reads.delete( tun )
200
+
201
+ if tun.closed? then
202
+ # puts "debug tun closed"
203
+ @writes.delete( tun )
204
+ @roles.delete( tun )
205
+ @tun_infos.delete( tun )
206
+ end
207
+ end
208
+
209
+ ##
210
+ # close sock
211
+ #
212
+ def close_sock( sock )
213
+ return if sock.nil? || sock.closed?
214
+ sock.close
215
+ @reads.delete( sock )
216
+ @writes.delete( sock )
217
+ @roles.delete( sock )
218
+ end
219
+
220
+ ##
221
+ # close tun
222
+ #
223
+ def close_tun( tun )
224
+ return if tun.nil? || tun.closed?
225
+ puts "#{ Time.new } close tun"
226
+ close_sock( tun )
227
+ @tun_infos.delete( tun )
228
+ end
229
+
230
+ ##
231
+ # close write dst
232
+ #
233
+ def close_write_dst( dst )
234
+ return if dst.nil? || dst.closed?
235
+ # puts "debug close write dst"
236
+ dst.close_write
237
+ @writes.delete( dst )
238
+
239
+ if dst.closed? then
240
+ # puts "debug dst closed"
241
+ @reads.delete( dst )
242
+ @roles.delete( dst )
243
+ @dst_infos.delete( dst )
244
+ end
245
+ end
246
+
247
+ ##
248
+ # close write tun
249
+ #
250
+ def close_write_tun( tun )
251
+ return if tun.nil? || tun.closed?
252
+ # puts "debug close write tun"
253
+ tun.close_write
254
+ @writes.delete( tun )
255
+
256
+ if tun.closed? then
257
+ # puts "debug tun closed"
258
+ @reads.delete( tun )
259
+ @roles.delete( tun )
260
+ @tun_infos.delete( tun )
261
+ end
262
+ end
263
+
264
+ ##
265
+ # loop check state
266
+ #
267
+ def loop_check_state
268
+ Thread.new do
269
+ loop do
270
+ sleep CHECK_STATE_INTERVAL
271
+ now = Time.new
272
+
273
+ @dst_infos.select{ | dst, _ | !dst.closed? }.each do | dst, dst_info |
274
+ last_recv_at = dst_info[ :last_recv_at ] || dst_info[ :created_at ]
275
+ last_sent_at = dst_info[ :last_sent_at ] || dst_info[ :created_at ]
276
+ is_expire = ( now - last_recv_at >= EXPIRE_AFTER ) && ( now - last_sent_at >= EXPIRE_AFTER )
277
+
278
+ if is_expire then
279
+ puts "#{ Time.new } expire dst"
280
+ dst_info[ :closing ] = true
281
+ next_tick
282
+ elsif dst_info[ :paused ] then
283
+ tun = dst_info[ :tun ]
284
+
285
+ if tun && !tun.closed? then
286
+ tun_info = @tun_infos[ tun ]
287
+
288
+ if tun_info[ :wbuff ].bytesize < RESUME_BELOW then
289
+ puts "#{ Time.new } resume dst"
290
+ add_read( dst )
291
+ dst_info[ :paused ] = false
292
+ next_tick
293
+ end
294
+ end
295
+ end
296
+ end
297
+
298
+ @tun_infos.select{ | tun, info | !tun.closed? && info[ :paused ] }.each do | tun, tun_info |
299
+ dst = tun_info[ :dst ]
300
+
301
+ if dst && !dst.closed? then
302
+ dst_info = @dst_infos[ dst ]
303
+
304
+ if dst_info[ :wbuff ].bytesize < RESUME_BELOW then
305
+ puts "#{ Time.new } resume tun"
306
+ add_read( tun )
307
+ tun_info[ :paused ] = false
308
+ next_tick
309
+ end
310
+ end
311
+ end
312
+ end
313
+ end
314
+ end
315
+
316
+ ##
317
+ # loop renew ctl
318
+ #
319
+ def loop_renew_ctl
320
+ Thread.new do
321
+ loop do
322
+ sleep RENEW_CTL_INTERVAL
323
+ set_ctl_closing
324
+ end
325
+ end
326
+ end
327
+
328
+ ##
329
+ # new a ctl
330
+ #
331
+ def new_a_ctl
332
+ ctl = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
333
+ ctl.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
334
+
335
+ if RUBY_PLATFORM.include?( 'linux' ) then
336
+ ctl.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 )
337
+ end
338
+
339
+ paird_port = @paird_port + 10.times.to_a.sample
340
+ paird_addr = Socket.sockaddr_in( paird_port, @paird_host )
341
+
342
+ @ctl = ctl
343
+ @ctl_info = {
344
+ paird_addr: paird_addr,
345
+ peer_addr: nil,
346
+ dst: nil,
347
+ closing: false
348
+ }
349
+
350
+ add_read( ctl, :ctl )
351
+
352
+ puts "#{ Time.new } #{ @title.inspect } #{ Addrinfo.new( @ctl_info[ :paird_addr ] ).inspect }"
353
+ send_title
354
+ end
355
+
356
+ ##
357
+ # new a dst
358
+ #
359
+ def new_a_dst
360
+ dst = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
361
+ dst.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1 )
362
+
363
+ begin
364
+ dst.connect_nonblock( @appd_addr )
365
+ rescue IO::WaitWritable
366
+ rescue Exception => e
367
+ puts "#{ Time.new } dst connect appd addr #{ e.class }"
368
+ dst.close
369
+ renew_ctl
370
+ return nil
371
+ end
372
+
373
+ @dst_infos[ dst ] = {
374
+ rbuff: '',
375
+ wbuff: '',
376
+ closing_write: false,
377
+ closing: false,
378
+ paused: false,
379
+ created_at: Time.new,
380
+ last_recv_at: nil,
381
+ last_sent_at: nil,
382
+ tun: nil,
383
+ punch_times: 0
384
+ }
385
+
386
+ puts "#{ Time.new } dst infos #{ @dst_infos.size }"
387
+ add_read( dst, :dst )
388
+ dst
389
+ end
390
+
391
+ ##
392
+ # new a pipe
393
+ #
394
+ def new_a_pipe
395
+ dotr, dotw = IO.pipe
396
+ @dotw = dotw
397
+ add_read( dotr, :dotr )
398
+ end
399
+
400
+ ##
401
+ # new a tun
402
+ #
403
+ def new_a_tun
404
+ return if @ctl.nil? || @ctl.closed? || @ctl_info[ :peer_addr ].nil?
405
+ dst = @ctl_info[ :dst ]
406
+ return if dst.nil? || dst.closed?
407
+ tun = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
408
+ tun.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1 )
409
+ tun.bind( @ctl.local_address )
410
+
411
+ begin
412
+ tun.connect_nonblock( @ctl_info[ :peer_addr ] )
413
+ rescue IO::WaitWritable
414
+ rescue Exception => e
415
+ puts "#{ Time.new } connect peer addr #{ e.class }"
416
+ tun.close
417
+ renew_ctl
418
+ return nil
419
+ end
420
+
421
+ @tun_infos[ tun ] = {
422
+ connected: false,
423
+ wbuff: '',
424
+ closing_write: false,
425
+ paused: false,
426
+ dst: dst
427
+ }
428
+
429
+ add_read( tun, :tun )
430
+ add_write( tun )
431
+ dst_info = @dst_infos[ dst ]
432
+ dst_info[ :tun ] = tun
433
+ dst_info[ :punch_times ] += 1
434
+ puts "#{ Time.new } #{ tun.local_address.inspect } connect #{ Addrinfo.new( @ctl_info[ :peer_addr ] ).inspect } tun infos #{ @tun_infos.size }"
435
+ tun
436
+ end
437
+
438
+ ##
439
+ # next tick
440
+ #
441
+ def next_tick
442
+ @dotw.write( '.' )
443
+ end
444
+
445
+ ##
446
+ # renew ctl
447
+ #
448
+ def renew_ctl
449
+ close_ctl
450
+ new_a_ctl
451
+ end
452
+
453
+ ##
454
+ # renew paired ctl
455
+ #
456
+ def renew_paired_ctl
457
+ if @ctl && !@ctl.closed? && @ctl_info[ :peer_addr ] then
458
+ puts "#{ Time.new } renew paired ctl"
459
+ renew_ctl
460
+ end
461
+ end
462
+
463
+ ##
464
+ # send title
465
+ #
466
+ def send_title
467
+ begin
468
+ @ctl.sendmsg( @title, 0, @ctl_info[ :paird_addr ] )
469
+ rescue Exception => e
470
+ puts "#{ Time.new } ctl sendmsg #{ e.class }"
471
+ set_ctl_closing
472
+ end
473
+ end
474
+
475
+ ##
476
+ # set ctl closing
477
+ #
478
+ def set_ctl_closing
479
+ return if @ctl.nil? || @ctl.closed? || @ctl_info[ :closing ]
480
+ @ctl_info[ :closing ] = true
481
+ next_tick
482
+ end
483
+
484
+ ##
485
+ # set dst closing write
486
+ #
487
+ def set_dst_closing_write( dst )
488
+ return if dst.nil? || dst.closed?
489
+ dst_info = @dst_infos[ dst ]
490
+ return if dst_info[ :closing_write ]
491
+ dst_info[ :closing_write ] = true
492
+ add_write( dst )
493
+ end
494
+
495
+ ##
496
+ # set tun closing write
497
+ #
498
+ def set_tun_closing_write( tun )
499
+ return if tun.nil? || tun.closed?
500
+ tun_info = @tun_infos[ tun ]
501
+ return if tun_info[ :closing_write ]
502
+ tun_info[ :closing_write ] = true
503
+ add_write( tun )
504
+ end
505
+
506
+ ##
507
+ # read dotr
508
+ #
509
+ def read_dotr( dotr )
510
+ dotr.read_nonblock( READ_SIZE )
511
+
512
+ if @ctl && !@ctl.closed? && @ctl_info[ :closing ] then
513
+ renew_ctl
514
+ end
515
+
516
+ @dst_infos.select{ | _, info | info[ :closing ] }.keys.each do | dst |
517
+ dst_info = close_dst( dst )
518
+
519
+ if dst_info then
520
+ close_tun( dst_info[ :tun ] )
521
+ end
522
+ end
523
+ end
524
+
525
+ ##
526
+ # read ctl
527
+ #
528
+ def read_ctl( ctl )
529
+ if ctl.closed? then
530
+ puts "#{ Time.new } read ctl but ctl closed?"
531
+ return
532
+ end
533
+
534
+ data, addrinfo, rflags, *controls = ctl.recvmsg
535
+
536
+ if @ctl_info[ :peer_addr ] then
537
+ puts "#{ Time.new } peer addr already exist"
538
+ return
539
+ end
540
+
541
+ if addrinfo.to_sockaddr != @ctl_info[ :paird_addr ] then
542
+ puts "#{ Time.new } paird addr not match #{ addrinfo.inspect } #{ Addrinfo.new( @ctl_info[ :paird_addr ] ).inspect }"
543
+ return
544
+ end
545
+
546
+ puts "#{ Time.new } read ctl #{ data.inspect }"
547
+ @ctl_info[ :peer_addr ] = data
548
+ @ctl_info[ :dst ] = new_a_dst
549
+ new_a_tun
550
+ end
551
+
552
+ ##
553
+ # read tun
554
+ #
555
+ def read_tun( tun )
556
+ if tun.closed? then
557
+ puts "#{ Time.new } read tun but tun closed?"
558
+ return
559
+ end
560
+
561
+ tun_info = @tun_infos[ tun ]
562
+ dst = tun_info[ :dst ]
563
+
564
+ if dst.nil? || dst.closed? then
565
+ puts "#{ Time.new } read tun but dst already closed"
566
+ close_tun( tun )
567
+ return
568
+ end
569
+
570
+ begin
571
+ data = tun.read_nonblock( READ_SIZE )
572
+ rescue Errno::ECONNREFUSED => e
573
+ dst_info = @dst_infos[ dst ]
574
+
575
+ if dst_info[ :punch_times ] >= PUNCH_LIMIT then
576
+ puts "#{ Time.new } out of limit"
577
+ close_tun( tun )
578
+ close_dst( dst )
579
+ renew_ctl
580
+ return
581
+ end
582
+
583
+ puts "#{ Time.new } read tun #{ e.class } #{ dst_info[ :punch_times ] }"
584
+ close_tun( tun )
585
+
586
+ unless new_a_tun then
587
+ close_dst( dst )
588
+ renew_ctl
589
+ end
590
+
591
+ return
592
+ rescue Exception => e
593
+ puts "#{ Time.new } read tun #{ e.class }"
594
+ close_read_tun( tun )
595
+ set_dst_closing_write( dst )
596
+ renew_paired_ctl
597
+ return
598
+ end
599
+
600
+ add_dst_wbuff( dst, data )
601
+ end
602
+
603
+ ##
604
+ # read dst
605
+ #
606
+ def read_dst( dst )
607
+ if dst.closed? then
608
+ puts "#{ Time.new } read dst but dst closed?"
609
+ return
610
+ end
611
+
612
+ dst_info = @dst_infos[ dst ]
613
+ tun = dst_info[ :tun ]
614
+
615
+ begin
616
+ data = dst.read_nonblock( READ_SIZE )
617
+ rescue Exception => e
618
+ puts "#{ Time.new } read dst #{ e.class }"
619
+ close_read_dst( dst )
620
+ set_tun_closing_write( tun )
621
+ renew_paired_ctl
622
+ return
623
+ end
624
+
625
+ if tun && !tun.closed? && @tun_infos[ tun ][ :connected ] then
626
+ add_tun_wbuff( tun, data )
627
+ else
628
+ puts "#{ Time.new } tun not connected, save data to dst.rbuff #{ data.inspect }"
629
+ add_dst_rbuff( dst, data )
630
+ end
631
+ end
632
+
633
+ ##
634
+ # write tun
635
+ #
636
+ def write_tun( tun )
637
+ if tun.closed? then
638
+ puts "#{ Time.new } write tun but tun closed?"
639
+ return
640
+ end
641
+
642
+ tun_info = @tun_infos[ tun ]
643
+ dst = tun_info[ :dst ]
644
+ dst_info = @dst_infos[ dst ]
645
+
646
+ unless tun_info[ :connected ] then
647
+ puts "#{ Time.new } connected"
648
+ tun_info[ :connected ] = true
649
+
650
+ if dst && !dst.closed? then
651
+ tun_info[ :wbuff ] << dst_info[ :rbuff ]
652
+ end
653
+
654
+ renew_ctl
655
+ end
656
+
657
+ data = tun_info[ :wbuff ]
658
+
659
+ # 写前为空,处理关闭写
660
+ if data.empty? then
661
+ if tun_info[ :closing_write ] then
662
+ close_write_tun( tun )
663
+ else
664
+ @writes.delete( tun )
665
+ end
666
+
667
+ return
668
+ end
669
+
670
+ # 写入
671
+ begin
672
+ written = tun.write_nonblock( data )
673
+ rescue Exception => e
674
+ puts "#{ Time.new } write tun #{ e.class }"
675
+ close_write_tun( tun )
676
+ close_read_dst( dst )
677
+ renew_paired_ctl
678
+ return
679
+ end
680
+
681
+ data = data[ written..-1 ]
682
+ tun_info[ :wbuff ] = data
683
+
684
+ if dst && !dst.closed? then
685
+ dst_info[ :last_sent_at ] = Time.new
686
+ end
687
+ end
688
+
689
+ ##
690
+ # write dst
691
+ #
692
+ def write_dst( dst )
693
+ if dst.closed? then
694
+ puts "#{ Time.new } write dst but dst closed?"
695
+ return
696
+ end
697
+
698
+ dst_info = @dst_infos[ dst ]
699
+ data = dst_info[ :wbuff ]
700
+
701
+ # 写前为空,处理关闭写
702
+ if data.empty? then
703
+ if dst_info[ :closing_write ] then
704
+ close_write_dst( dst )
705
+ else
706
+ @writes.delete( dst )
707
+ end
708
+
709
+ return
710
+ end
711
+
712
+ # 写入
713
+ begin
714
+ written = dst.write_nonblock( data )
715
+ rescue Exception => e
716
+ puts "#{ Time.new } write dst #{ e.class }"
717
+ close_write_dst( dst )
718
+ close_read_tun( dst_info[ :tun ] )
719
+ renew_paired_ctl
720
+ return
721
+ end
722
+
723
+ data = data[ written..-1 ]
724
+ dst_info[ :wbuff ] = data
725
+ end
726
+ end
727
+ end