p2p2 0.26.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: 8b794e3b18c3c83d28013dc743181bd0f72ff9dc1c692266f68d360ebcc3855b
4
- data.tar.gz: 99ff62c980d909c10d412f076d7aac4e81afe195a824c7fd36b6ac78b2c7e777
3
+ metadata.gz: 707396700d8514b51e69c74e0afe93349dd068cd2748ed3b298e0e41efe8fc8f
4
+ data.tar.gz: f5d8449949b2dc30d3b2013b529938bca812e2a683ae334fb5e9c076f449e484
5
5
  SHA512:
6
- metadata.gz: b6cf3c77031cf3f53d1f8f884daca762140f68ff40c2538618058a2ffa8747d8c722069e432c02b3165ee3451545c82cd43177ba38e80218459c91b5a37bd978
7
- data.tar.gz: 177432a07d6976627d629658dd8e61ac105d538225e43af30842fe05d4378abfd2be28d47b4c2616a0e733b80228a6badcf33f21c9464cfe5ff3ce78a0c16d2a
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 - p2p通道,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,928 +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 ] && @tund_info[ :peer_at ]
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"
103
- del_dst_ext( dst_local_port )
104
- end
105
- end
106
- end
107
-
108
- @dst_infos.each do | dst, dst_info |
109
- if now - dst_info[ :last_continue_at ] > EXPIRE_AFTER
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[ :peer_at ] > EXPIRE_NEW
122
- puts "#{ Time.new } expire new tund"
123
- set_is_closing( @tund )
124
- next_tick
125
- end
126
- else
127
- # no peer addr
128
- if now - check_at >= UPDATE_ROOM_INTERVAL
129
- data = @room
130
- check_at = now
131
- else
132
- data = [ rand( 128 ) ].pack( 'C' )
133
- end
134
-
135
- # puts "debug2 update room"
136
- add_tund_ctlmsg( data, @p2pd_addr )
137
- next_tick
138
- end
139
- end
140
- end
141
- end
142
- end
143
- end
144
-
145
- ##
146
- # loop check status
147
- #
148
- def loop_check_status
149
- Thread.new do
150
- loop do
151
- sleep STATUS_INTERVAL
152
-
153
- @mutex.synchronize do
154
- if !@tund.closed? && @tund_info[ :tun_addr ]
155
- need_trigger = false
156
-
157
- if @tund_info[ :dst_exts ].any?
158
- now = Time.new
159
-
160
- @tund_info[ :dst_exts ].each do | dst_local_port, dst_ext |
161
- if now - dst_ext[ :last_continue_at ] < SEND_STATUS_UNTIL
162
- data = [ 0, DEST_STATUS, dst_local_port, dst_ext[ :relay_pack_id ], dst_ext[ :continue_src_pack_id ] ].pack( 'Q>CnQ>Q>' )
163
- add_tund_ctlmsg( data )
164
- need_trigger = true
165
- end
166
- end
167
- end
168
-
169
- if @tund_info[ :paused ] && ( @tund_info[ :dst_exts ].map{ | _, dst_ext | dst_ext[ :wmems ].size }.sum < RESUME_BELOW )
170
- puts "#{ Time.new } resume tund"
171
- @tund_info[ :paused ] = false
172
- add_write( @tund )
173
- need_trigger = true
174
- end
175
-
176
- if need_trigger
177
- next_tick
178
- end
179
- end
180
- end
181
- end
182
- end
183
- end
184
-
185
- ##
186
- # loop punch peer
187
- #
188
- def loop_punch_peer
189
- Thread.new do
190
- EXPIRE_NEW.times do
191
- if @tund.closed?
192
- # puts "debug1 break loop punch peer"
193
- break
194
- end
195
-
196
- @mutex.synchronize do
197
- # puts "debug1 punch peer"
198
- add_tund_ctlmsg( pack_a_heartbeat, @tund_info[ :peer_addr ] )
199
- next_tick
200
- end
201
-
202
- sleep 1
203
- end
204
- end
205
- end
206
-
207
- ##
208
- # new a tund
209
- #
210
- def new_a_tund
211
- tund = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
212
- tund.bind( Socket.sockaddr_in( 0, '0.0.0.0' ) )
213
- port = tund.local_address.ip_port
214
- puts "#{ Time.new } tund bind on #{ port }"
215
-
216
- tund_info = {
217
- port: port, # 端口
218
- ctlmsgs: [], # [ to_addr, data ]
219
- wbuffs: [], # 写前缓存 [ dst_local_port, pack_id, data ]
220
- caches: [], # 块读出缓存 [ dst_local_port, pack_id, data ]
221
- chunks: [], # 块队列 filename
222
- spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
223
- peer_addr: nil, # 配对地址
224
- peer_at: 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
- # send data
379
- #
380
- def send_data( tund, data, to_addr )
381
- begin
382
- tund.sendmsg( data, 0, to_addr )
383
- rescue IO::WaitWritable, Errno::EINTR
384
- return false
385
- rescue Errno::EHOSTUNREACH, Errno::ENETUNREACH, Errno::ENETDOWN => e
386
- puts "#{ Time.new } #{ e.class }, close tund"
387
- close_tund( tund )
388
- sleep HEARTBEAT_INTERVAL
389
- new_a_tund
390
- return false
391
- end
392
-
393
- true
394
- end
395
-
396
- ##
397
- # close dst
398
- #
399
- def close_dst( dst )
400
- # puts "debug1 close dst"
401
- close_sock( dst )
402
- dst_info = @dst_infos.delete( dst )
403
-
404
- dst_info[ :chunks ].each do | filename |
405
- begin
406
- File.delete( File.join( @dst_chunk_dir, filename ) )
407
- rescue Errno::ENOENT
408
- end
409
- end
410
-
411
- return if @tund.closed?
412
-
413
- local_port = dst_info[ :local_port ]
414
- dst_ext = @tund_info[ :dst_exts ][ local_port ]
415
- return unless dst_ext
416
-
417
- if dst_ext[ :is_src_closed ]
418
- # puts "debug1 4-3. after close dst -> src closed ? yes -> del dst ext -> send fin2"
419
- del_dst_ext( local_port )
420
- data = [ 0, FIN2, local_port ].pack( 'Q>Cn' )
421
- add_tund_ctlmsg( data )
422
- else
423
- # puts "debug1 3-1. after close dst -> src closed ? no -> send fin1"
424
- data = [ 0, FIN1, local_port, dst_info[ :biggest_pack_id ], dst_ext[ :continue_src_pack_id ] ].pack( 'Q>CnQ>Q>' )
425
- add_tund_ctlmsg( data )
426
- end
427
- end
428
-
429
- ##
430
- # close tund
431
- #
432
- def close_tund( tund )
433
- # puts "debug1 close tund"
434
- close_sock( tund )
435
-
436
- @tund_info[ :chunks ].each do | filename |
437
- begin
438
- File.delete( File.join( @tund_chunk_dir, filename ) )
439
- rescue Errno::ENOENT
440
- end
441
- end
442
-
443
- @tund_info[ :dst_exts ].each{ | _, dst_ext | set_is_closing( dst_ext[ :dst ] ) }
444
- end
445
-
446
- ##
447
- # close sock
448
- #
449
- def close_sock( sock )
450
- sock.close
451
- @reads.delete( sock )
452
- @writes.delete( sock )
453
- @roles.delete( sock )
454
- end
455
-
456
- ##
457
- # del dst ext
458
- #
459
- def del_dst_ext( dst_local_port )
460
- dst_ext = @tund_info[ :dst_exts ].delete( dst_local_port )
461
-
462
- if dst_ext
463
- @tund_info[ :dst_local_ports ].delete( dst_ext[ :src_id ] )
464
- end
465
- end
466
-
467
- ##
468
- # release wmems
469
- #
470
- def release_wmems( dst_ext, completed_pack_id )
471
- if completed_pack_id > dst_ext[ :completed_pack_id ]
472
- # puts "debug2 update completed pack #{ completed_pack_id }"
473
-
474
- pack_ids = dst_ext[ :wmems ].keys.select { | pack_id | pack_id <= completed_pack_id }
475
-
476
- pack_ids.each do | pack_id |
477
- dst_ext[ :wmems ].delete( pack_id )
478
- dst_ext[ :send_ats ].delete( pack_id )
479
- end
480
-
481
- dst_ext[ :completed_pack_id ] = completed_pack_id
482
- end
483
- end
484
-
485
- ##
486
- # next tick
487
- #
488
- def next_tick
489
- @dotw.write( '.' )
490
- end
491
-
492
- ##
493
- # write dst
494
- #
495
- def write_dst( dst )
496
- dst_info = @dst_infos[ dst ]
497
- from, data = :cache, dst_info[ :cache ]
498
-
499
- if data.empty?
500
- if dst_info[ :chunks ].any?
501
- path = File.join( @dst_chunk_dir, dst_info[ :chunks ].shift )
502
-
503
- begin
504
- data = dst_info[ :cache ] = IO.binread( path )
505
- File.delete( path )
506
- rescue Errno::ENOENT => e
507
- puts "#{ Time.new } read #{ path } #{ e.class }"
508
- close_dst( dst )
509
- return
510
- end
511
- else
512
- from, data = :wbuff, dst_info[ :wbuff ]
513
- end
514
- end
515
-
516
- if data.empty?
517
- if dst_info[ :is_closing ]
518
- close_dst( dst )
519
- else
520
- @writes.delete( dst )
521
- end
522
-
523
- return
524
- end
525
-
526
- begin
527
- written = dst.write_nonblock( data )
528
- rescue IO::WaitWritable, Errno::EINTR
529
- return
530
- rescue Exception => e
531
- # puts "debug1 write dst #{ e.class }"
532
- close_dst( dst )
533
- return
534
- end
535
-
536
- # puts "debug2 write dst #{ written }"
537
- data = data[ written..-1 ]
538
- dst_info[ from ] = data
539
- dst_info[ :last_continue_at ] = Time.new
540
- end
541
-
542
- ##
543
- # write tund
544
- #
545
- def write_tund( tund )
546
- if @tund_info[ :is_closing ]
547
- close_tund( tund )
548
- new_a_tund
549
- return
550
- end
551
-
552
- now = Time.new
553
-
554
- # 传ctlmsg
555
- while @tund_info[ :ctlmsgs ].any?
556
- to_addr, data = @tund_info[ :ctlmsgs ].first
557
-
558
- unless send_data( tund, data, to_addr )
559
- return
560
- end
561
-
562
- @tund_info[ :ctlmsgs ].shift
563
- end
564
-
565
- # 重传
566
- while @tund_info[ :resendings ].any?
567
- dst_local_port, pack_id = @tund_info[ :resendings ].first
568
- dst_ext = @tund_info[ :dst_exts ][ dst_local_port ]
569
-
570
- if dst_ext
571
- data = dst_ext[ :wmems ][ pack_id ]
572
-
573
- if data
574
- unless send_data( tund, data, @tund_info[ :tun_addr ] )
575
- return
576
- end
577
-
578
- dst_ext[ :last_continue_at ] = now
579
- end
580
- end
581
-
582
- @tund_info[ :resendings ].shift
583
- end
584
-
585
- # 若写后达到上限,暂停取写前
586
- if @tund_info[ :dst_exts ].map{ | _, dst_ext | dst_ext[ :wmems ].size }.sum >= WMEMS_LIMIT
587
- unless @tund_info[ :paused ]
588
- puts "#{ Time.new } pause tund #{ @tund_info[ :port ] }"
589
- @tund_info[ :paused ] = true
590
- end
591
-
592
- @writes.delete( tund )
593
- return
594
- end
595
-
596
- # 取写前
597
- if @tund_info[ :caches ].any?
598
- datas = @tund_info[ :caches ]
599
- elsif @tund_info[ :chunks ].any?
600
- path = File.join( @tund_chunk_dir, @tund_info[ :chunks ].shift )
601
-
602
- begin
603
- data = IO.binread( path )
604
- File.delete( path )
605
- rescue Errno::ENOENT => e
606
- puts "#{ Time.new } read #{ path } #{ e.class }"
607
- close_tund( tund )
608
- return
609
- end
610
-
611
- caches = []
612
-
613
- until data.empty?
614
- _dst_local_port, _pack_id, pack_size = data[ 0, 12 ].unpack( 'nQ>n' )
615
- caches << [ _dst_local_port, _pack_id, data[ 12, pack_size ] ]
616
- data = data[ ( 12 + pack_size )..-1 ]
617
- end
618
-
619
- datas = @tund_info[ :caches ] = caches
620
- elsif @tund_info[ :wbuffs ].any?
621
- datas = @tund_info[ :wbuffs ]
622
- else
623
- @writes.delete( tund )
624
- return
625
- end
626
-
627
- while datas.any?
628
- dst_local_port, pack_id, data = datas.first
629
- dst_ext = @tund_info[ :dst_exts ][ dst_local_port ]
630
-
631
- if dst_ext
632
- if pack_id <= CONFUSE_UNTIL
633
- data = @custom.encode( data )
634
- # puts "debug1 encoded pack #{ pack_id }"
635
- end
636
-
637
- data = [ [ pack_id, dst_local_port ].pack( 'Q>n' ), data ].join
638
-
639
- unless send_data( tund, data, @tund_info[ :tun_addr ] )
640
- return
641
- end
642
-
643
- # puts "debug2 written pack #{ pack_id }"
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
- datas.shift
651
- end
652
- end
653
-
654
- ##
655
- # read dotr
656
- #
657
- def read_dotr( dotr )
658
- dotr.read( 1 )
659
- end
660
-
661
- ##
662
- # read dst
663
- #
664
- def read_dst( dst )
665
- begin
666
- data = dst.read_nonblock( PACK_SIZE )
667
- rescue IO::WaitReadable, Errno::EINTR
668
- return
669
- rescue Exception => e
670
- # puts "debug1 read dst #{ e.class }"
671
- set_is_closing( dst )
672
- return
673
- end
674
-
675
- # puts "debug2 read dst #{ data.inspect }"
676
- dst_info = @dst_infos[ dst ]
677
- dst_info[ :last_continue_at ] = Time.new
678
-
679
- if @tund.closed?
680
- puts "#{ Time.new } tund closed, close dst"
681
- set_is_closing( dst )
682
- return
683
- end
684
-
685
- pack_id = dst_info[ :biggest_pack_id ] + 1
686
- dst_info[ :biggest_pack_id ] = pack_id
687
- add_tund_wbuff( dst_info[ :local_port ], pack_id, data )
688
- end
689
-
690
- ##
691
- # read tund
692
- #
693
- def read_tund( tund )
694
- data, addrinfo, rflags, *controls = tund.recvmsg
695
- now = Time.new
696
- pack_id = data[ 0, 8 ].unpack( 'Q>' ).first
697
-
698
- if pack_id == 0
699
- ctl_num = data[ 8 ].unpack( 'C' ).first
700
-
701
- case ctl_num
702
- when PEER_ADDR
703
- return if @tund_info[ :peer_addr ] || ( addrinfo.to_sockaddr != @p2pd_addr )
704
-
705
- peer_addr = data[ 9..-1 ]
706
- puts "#{ Time.new } got peer addr #{ Addrinfo.new( peer_addr ).inspect }"
707
-
708
- @tund_info[ :peer_addr ] = peer_addr
709
- @tund_info[ :peer_at ] = now
710
- loop_punch_peer
711
- when HEARTBEAT
712
- from_addr = addrinfo.to_sockaddr
713
- return if from_addr != @tund_info[ :peer_addr ]
714
-
715
- # puts "debug1 set tun addr #{ Addrinfo.new( from_addr ).inspect }"
716
- @tund_info[ :tun_addr ] = from_addr
717
- @tund_info[ :last_recv_at ] = now
718
- when A_NEW_SOURCE
719
- return unless is_match_tun_addr( addrinfo )
720
-
721
- src_id = data[ 9, 8 ].unpack( 'Q>' ).first
722
- dst_local_port = @tund_info[ :dst_local_ports ][ src_id ]
723
- # puts "debug1 got a new source #{ src_id }"
724
-
725
- if dst_local_port
726
- dst_ext = @tund_info[ :dst_exts ][ dst_local_port ]
727
- return unless dst_ext
728
-
729
- if dst_ext[ :dst ].closed?
730
- dst_local_port = 0
731
- end
732
- else
733
- dst = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
734
-
735
- if RUBY_PLATFORM.include?( 'linux' )
736
- dst.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 )
737
- end
738
-
739
- begin
740
- dst.connect_nonblock( @appd_addr )
741
- rescue IO::WaitWritable
742
- rescue Exception => e
743
- puts "#{ Time.new } connect appd #{ e.class }"
744
- return
745
- end
746
-
747
- dst_local_port = dst.local_address.ip_port
748
-
749
- @dst_infos[ dst ] = {
750
- local_port: dst_local_port, # 本地端口
751
- biggest_pack_id: 0, # 最大包号码
752
- wbuff: '', # 写前
753
- cache: '', # 块读出缓存
754
- chunks: [], # 块队列,写前达到块大小时结一个块 filename
755
- spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
756
- last_continue_at: Time.new, # 上一次发生流量的时间
757
- is_closing: false # 是否准备关闭
758
- }
759
- add_read( dst, :dst )
760
-
761
- @tund_info[ :dst_local_ports ][ src_id ] = dst_local_port
762
- @tund_info[ :dst_exts ][ dst_local_port ] = {
763
- dst: dst, # dst
764
- src_id: src_id, # 近端src id
765
- wmems: {}, # 写后 pack_id => data
766
- send_ats: {}, # 上一次发出时间 pack_id => send_at
767
- relay_pack_id: 0, # 转发到几
768
- continue_src_pack_id: 0, # 收到几
769
- pieces: {}, # 跳号包 src_pack_id => data
770
- is_src_closed: false, # src是否已关闭
771
- biggest_src_pack_id: 0, # src最大包号码
772
- completed_pack_id: 0, # 完成到几(对面收到几)
773
- last_continue_at: Time.new # 上一次发生流量的时间
774
- }
775
- end
776
-
777
- data2 = [ 0, PAIRED, src_id, dst_local_port ].pack( 'Q>CQ>n' )
778
- # puts "debug1 add ctlmsg paired #{ data2.inspect }"
779
- add_tund_ctlmsg( data2 )
780
- when SOURCE_STATUS
781
- return unless is_match_tun_addr( addrinfo )
782
-
783
- src_id, relay_src_pack_id, continue_dst_pack_id = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
784
-
785
- dst_local_port = @tund_info[ :dst_local_ports ][ src_id ]
786
- return unless dst_local_port
787
-
788
- dst_ext = @tund_info[ :dst_exts ][ dst_local_port ]
789
- return unless dst_ext
790
-
791
- # puts "debug2 got source status"
792
-
793
- release_wmems( dst_ext, continue_dst_pack_id )
794
-
795
- # 发miss
796
- if !dst_ext[ :dst ].closed? && ( dst_ext[ :continue_src_pack_id ] < relay_src_pack_id )
797
- ranges = []
798
- curr_pack_id = dst_ext[ :continue_src_pack_id ] + 1
799
-
800
- dst_ext[ :pieces ].keys.sort.each do | pack_id |
801
- if pack_id > curr_pack_id
802
- ranges << [ curr_pack_id, pack_id - 1 ]
803
- end
804
-
805
- curr_pack_id = pack_id + 1
806
- end
807
-
808
- if curr_pack_id <= relay_src_pack_id
809
- ranges << [ curr_pack_id, relay_src_pack_id ]
810
- end
811
-
812
- pack_count = 0
813
- # puts "debug1 continue/relay #{ dst_ext[ :continue_src_pack_id ] }/#{ relay_src_pack_id } send MISS #{ ranges.size }"
814
-
815
- ranges.each do | pack_id_begin, pack_id_end |
816
- if pack_count >= BREAK_SEND_MISS
817
- puts "#{ Time.new } break send miss at #{ pack_id_begin }"
818
- break
819
- end
820
-
821
- data2 = [ 0, MISS, src_id, pack_id_begin, pack_id_end ].pack( 'Q>CQ>Q>Q>' )
822
- add_tund_ctlmsg( data2 )
823
- pack_count += ( pack_id_end - pack_id_begin + 1 )
824
- end
825
- end
826
- when MISS
827
- return unless is_match_tun_addr( addrinfo )
828
-
829
- dst_local_port, pack_id_begin, pack_id_end = data[ 9, 18 ].unpack( 'nQ>Q>' )
830
-
831
- dst_ext = @tund_info[ :dst_exts ][ dst_local_port ]
832
- return unless dst_ext
833
-
834
- ( pack_id_begin..pack_id_end ).each do | pack_id |
835
- send_at = dst_ext[ :send_ats ][ pack_id ]
836
-
837
- if send_at
838
- break if now - send_at < STATUS_INTERVAL
839
- @tund_info[ :resendings ] << [ dst_local_port, pack_id ]
840
- end
841
- end
842
-
843
- add_write( tund )
844
- when FIN1
845
- return unless is_match_tun_addr( addrinfo )
846
-
847
- src_id, biggest_src_pack_id, continue_dst_pack_id = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
848
-
849
- dst_local_port = @tund_info[ :dst_local_ports ][ src_id ]
850
- return unless dst_local_port
851
-
852
- dst_ext = @tund_info[ :dst_exts ][ dst_local_port ]
853
- return unless dst_ext
854
-
855
- # puts "debug1 got fin1 #{ src_id } biggest src pack #{ biggest_src_pack_id } completed dst pack #{ continue_dst_pack_id }"
856
- dst_ext[ :is_src_closed ] = true
857
- dst_ext[ :biggest_src_pack_id ] = biggest_src_pack_id
858
- release_wmems( dst_ext, continue_dst_pack_id )
859
-
860
- if biggest_src_pack_id == dst_ext[ :continue_src_pack_id ]
861
- # puts "debug1 4-1. tund recv fin1 -> all traffic received ? -> close dst after write"
862
- set_is_closing( dst_ext[ :dst ] )
863
- end
864
- when FIN2
865
- return unless is_match_tun_addr( addrinfo )
866
-
867
- src_id = data[ 9, 8 ].unpack( 'Q>' ).first
868
-
869
- dst_local_port = @tund_info[ :dst_local_ports ][ src_id ]
870
- return unless dst_local_port
871
-
872
- # puts "debug1 3-2. tund recv fin2 -> del dst ext"
873
- del_dst_ext( dst_local_port )
874
- when TUN_FIN
875
- return unless is_match_tun_addr( addrinfo )
876
-
877
- puts "#{ Time.new } recv tun fin"
878
- set_is_closing( tund )
879
- end
880
-
881
- return
882
- end
883
-
884
- return unless is_match_tun_addr( addrinfo )
885
-
886
- src_id = data[ 8, 8 ].unpack( 'Q>' ).first
887
-
888
- dst_local_port = @tund_info[ :dst_local_ports ][ src_id ]
889
- return unless dst_local_port
890
-
891
- dst_ext = @tund_info[ :dst_exts ][ dst_local_port ]
892
- return if dst_ext.nil? || dst_ext[ :dst ].closed?
893
- return if ( pack_id <= dst_ext[ :continue_src_pack_id ] ) || dst_ext[ :pieces ].include?( pack_id )
894
-
895
- data = data[ 16..-1 ]
896
- # puts "debug2 got pack #{ pack_id }"
897
-
898
- if pack_id <= CONFUSE_UNTIL
899
- # puts "debug2 #{ data.inspect }"
900
- data = @custom.decode( data )
901
- # puts "debug1 decoded pack #{ pack_id }"
902
- end
903
-
904
- # 放进写前,跳号放碎片缓存
905
- if pack_id - dst_ext[ :continue_src_pack_id ] == 1
906
- while dst_ext[ :pieces ].include?( pack_id + 1 )
907
- data << dst_ext[ :pieces ].delete( pack_id + 1 )
908
- pack_id += 1
909
- end
910
-
911
- dst_ext[ :continue_src_pack_id ] = pack_id
912
- dst_ext[ :last_continue_at ] = now
913
- add_dst_wbuff( dst_ext[ :dst ], data )
914
- # puts "debug2 update continue src pack #{ pack_id }"
915
-
916
- # 接到流量,若对面已关闭,且流量正好收全,关闭dst
917
- if dst_ext[ :is_src_closed ] && ( pack_id == dst_ext[ :biggest_src_pack_id ] )
918
- # puts "debug1 4-2. tund recv traffic -> src closed and all traffic received ? -> close dst after write"
919
- set_is_closing( dst_ext[ :dst ] )
920
- return
921
- end
922
- else
923
- dst_ext[ :pieces ][ pack_id ] = data
924
- end
925
- end
926
-
927
- end
928
- 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