p2p2 0.26.0 → 0.27.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 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