p2p2 0.22.0 → 0.27.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 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