p2p2 0.8.0 → 0.8.1
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 +4 -4
- data/lib/p2p2.rb +3 -3
- data/lib/p2p2/head.rb +25 -28
- data/lib/p2p2/p1.rb +806 -820
- data/lib/p2p2/p2.rb +845 -860
- data/lib/p2p2/p2pd.rb +135 -135
- data/lib/p2p2/version.rb +3 -3
- data/p2p2.gemspec +29 -29
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f1973bcbd5f9620457f208e44cd08ae4cf3fbc07039175e8b3fe9a583a08b638
|
4
|
+
data.tar.gz: 259a151940d2eaf37d9b1e37a8be36cf90a3f1f82930cc0876fba3b42e4957bf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 680631e11a05fd28156b52a8a08f63ef9511e26a701a72548c1f1eb6f106024b1ed3c0a1584fc15c96d83115f2db34f08e98b11d21042d9f93ea06d37eb0c126
|
7
|
+
data.tar.gz: 114000b65c1fb31e6e4a3b2d7e986b0723ba81bc0db63d2f39d9d2d0cb01928acf258bf990ff026aff623b89923d4053f7ac1dbf7239fd5982ea68069de32649
|
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'
|
data/lib/p2p2/head.rb
CHANGED
@@ -1,28 +1,25 @@
|
|
1
|
-
module P2p2
|
2
|
-
PACK_SIZE = 1328 # 包大小 1400(console MTU) - 8(PPPoE header) - 40(IPv6 header) - 8(UDP header) - 8(app/shadow id) - 8(pack id) = 1328
|
3
|
-
CHUNK_SIZE = PACK_SIZE * 1000 # 块大小
|
4
|
-
WBUFFS_LIMIT = 1000 # 写前上限,超过上限结一个块
|
5
|
-
WMEMS_LIMIT = 100_000 # 写后上限,到达上限暂停写
|
6
|
-
RESUME_BELOW = 50_000 # 降到多少以下恢复写
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
CTL_CLOSE_SOCK = [ 1 ].pack( 'C' )
|
27
|
-
CTL_RESUME = [ 2 ].pack( 'C' )
|
28
|
-
end
|
1
|
+
module P2p2
|
2
|
+
PACK_SIZE = 1328 # 包大小 1400(console MTU) - 8(PPPoE header) - 40(IPv6 header) - 8(UDP header) - 8(app/shadow id) - 8(pack id) = 1328
|
3
|
+
CHUNK_SIZE = PACK_SIZE * 1000 # 块大小
|
4
|
+
WBUFFS_LIMIT = 1000 # 写前上限,超过上限结一个块
|
5
|
+
WMEMS_LIMIT = 100_000 # 写后上限,到达上限暂停写
|
6
|
+
RESUME_BELOW = 50_000 # 降到多少以下恢复写
|
7
|
+
EXPIRE_AFTER = 1800 # 多久过期
|
8
|
+
STATUS_INTERVAL = 0.3 # 发送状态间隔
|
9
|
+
SEND_STATUS_UNTIL = 20 # 持续的告之对面状态,直到没有流量往来,持续多少秒
|
10
|
+
PEER_ADDR = 1
|
11
|
+
HEARTBEAT = 2
|
12
|
+
A_NEW_APP = 3
|
13
|
+
PAIRED = 4
|
14
|
+
SHADOW_STATUS = 5
|
15
|
+
APP_STATUS = 6
|
16
|
+
MISS = 7
|
17
|
+
FIN1 = 8
|
18
|
+
GOT_FIN1 = 9
|
19
|
+
FIN2 = 10
|
20
|
+
GOT_FIN2 = 11
|
21
|
+
P1_FIN = 12
|
22
|
+
P2_FIN = 13
|
23
|
+
CTL_CLOSE_SOCK = [ 1 ].pack( 'C' )
|
24
|
+
CTL_RESUME = [ 2 ].pack( 'C' )
|
25
|
+
end
|
data/lib/p2p2/p1.rb
CHANGED
@@ -1,820 +1,806 @@
|
|
1
|
-
require 'p2p2/head'
|
2
|
-
require 'p2p2/hex'
|
3
|
-
require 'p2p2/version'
|
4
|
-
require 'socket'
|
5
|
-
|
6
|
-
##
|
7
|
-
# P2p2::P1 - 内网里的任意应用,访问另一个内网里的应用服务端。p1端。
|
8
|
-
#
|
9
|
-
# 两套关闭
|
10
|
-
# ========
|
11
|
-
#
|
12
|
-
# 1-1. shadow.close -> ext.is_app_closed ? no -> send fin1 loop
|
13
|
-
# 1-2. recv got_fin1 -> break loop
|
14
|
-
# 1-3. recv fin2 -> send got_fin2 -> del ext
|
15
|
-
#
|
16
|
-
# 2-1. recv fin1 -> send got_fin1 -> ext.is_app_closed = true
|
17
|
-
# 2-2. all sent && ext.biggest_app_pack_id == ext.continue_app_pack_id -> add closing shadow
|
18
|
-
# 2-3. shadow.close -> ext.is_app_closed ? yes -> del ext -> loop send fin2
|
19
|
-
# 2-4. recv got_fin2 -> break loop
|
20
|
-
#
|
21
|
-
module P2p2
|
22
|
-
class P1
|
23
|
-
|
24
|
-
##
|
25
|
-
# p2pd_host 配对服务器ip
|
26
|
-
# p2pd_port 配对服务器端口
|
27
|
-
# appd_host 任意的一个应用的ip
|
28
|
-
# appd_port 应用端口
|
29
|
-
# title 约定的房间名
|
30
|
-
# shadow_chunk_dir 文件缓存目录,缓存shadow来不及写的流量
|
31
|
-
# p1_chunk_dir 文件缓存目录,缓存p1来不及写的流量
|
32
|
-
#
|
33
|
-
def initialize( p2pd_host, p2pd_port, appd_host, appd_port, title, shadow_chunk_dir = '/tmp', p1_chunk_dir = '/tmp' )
|
34
|
-
@p2pd_sockaddr = Socket.sockaddr_in( p2pd_port, p2pd_host )
|
35
|
-
@appd_sockaddr = Socket.sockaddr_in( appd_port, appd_host )
|
36
|
-
@title = title
|
37
|
-
@shadow_chunk_dir = shadow_chunk_dir
|
38
|
-
@p1_chunk_dir = p1_chunk_dir
|
39
|
-
@hex = P2p2::Hex.new
|
40
|
-
@mutex = Mutex.new
|
41
|
-
@reads = []
|
42
|
-
@writes = []
|
43
|
-
@closings = []
|
44
|
-
@socks = {} # object_id => sock
|
45
|
-
@roles = {} # sock => :ctlr / :shadow / :p1
|
46
|
-
@infos = {}
|
47
|
-
|
48
|
-
ctlr, ctlw = IO.pipe
|
49
|
-
@ctlw = ctlw
|
50
|
-
@roles[ ctlr ] = :ctlr
|
51
|
-
add_read( ctlr )
|
52
|
-
end
|
53
|
-
|
54
|
-
def looping
|
55
|
-
puts 'looping'
|
56
|
-
|
57
|
-
new_p1
|
58
|
-
|
59
|
-
loop do
|
60
|
-
rs, ws = IO.select( @reads, @writes )
|
61
|
-
|
62
|
-
@mutex.synchronize do
|
63
|
-
rs.each do | sock |
|
64
|
-
case @roles[ sock ]
|
65
|
-
when :ctlr
|
66
|
-
read_ctlr( sock )
|
67
|
-
when :shadow
|
68
|
-
read_shadow( sock )
|
69
|
-
when :p1
|
70
|
-
read_p1( sock )
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
ws.each do | sock |
|
75
|
-
case @roles[ sock ]
|
76
|
-
when :shadow
|
77
|
-
write_shadow( sock )
|
78
|
-
when :p1
|
79
|
-
write_p1( sock )
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
rescue Interrupt => e
|
85
|
-
puts e.class
|
86
|
-
quit!
|
87
|
-
end
|
88
|
-
|
89
|
-
def quit!
|
90
|
-
if @p1 && !@p1.closed? && @p1_info[ :p2_addr ]
|
91
|
-
ctlmsg = [ 0, P1_FIN ].pack( 'Q>C' )
|
92
|
-
send_pack( @p1, ctlmsg, @p1_info[ :p2_addr ] )
|
93
|
-
end
|
94
|
-
|
95
|
-
exit
|
96
|
-
end
|
97
|
-
|
98
|
-
private
|
99
|
-
|
100
|
-
##
|
101
|
-
# read ctlr
|
102
|
-
#
|
103
|
-
def read_ctlr( ctlr )
|
104
|
-
case ctlr.read( 1 )
|
105
|
-
when CTL_CLOSE_SOCK
|
106
|
-
sock_id = ctlr.read( 8 ).unpack( 'Q>' ).first
|
107
|
-
sock = @socks[ sock_id ]
|
108
|
-
|
109
|
-
if sock
|
110
|
-
puts "expire p1 #{ sock_id } #{ Time.new }"
|
111
|
-
add_closing( sock )
|
112
|
-
end
|
113
|
-
when CTL_RESUME
|
114
|
-
p1_id = ctlr.read( 8 ).unpack( 'Q>' ).first
|
115
|
-
|
116
|
-
puts "resume #{ p1_id } #{ Time.new }"
|
117
|
-
p1 = @socks[ p1_id ]
|
118
|
-
|
119
|
-
if p1
|
120
|
-
add_write( p1 )
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
##
|
126
|
-
# read shadow
|
127
|
-
#
|
128
|
-
def read_shadow( shadow )
|
129
|
-
begin
|
130
|
-
data = shadow.read_nonblock( PACK_SIZE )
|
131
|
-
rescue IO::WaitReadable, Errno::EINTR
|
132
|
-
return
|
133
|
-
rescue Exception => e
|
134
|
-
add_closing( shadow )
|
135
|
-
return
|
136
|
-
end
|
137
|
-
|
138
|
-
info = @infos[ shadow ]
|
139
|
-
p1 = info[ :p1 ]
|
140
|
-
|
141
|
-
if p1.closed?
|
142
|
-
add_closing( shadow )
|
143
|
-
return
|
144
|
-
end
|
145
|
-
|
146
|
-
p1_info = @infos[ p1 ]
|
147
|
-
p1_info[ :wbuffs ] << [ shadow.object_id, data ]
|
148
|
-
|
149
|
-
if p1_info[ :wbuffs ].size >= WBUFFS_LIMIT
|
150
|
-
spring = p1_info[ :chunks ].size > 0 ? ( p1_info[ :spring ] + 1 ) : 0
|
151
|
-
filename = "#{ p1.object_id }.#{ spring }"
|
152
|
-
chunk_path = File.join( @p1_chunk_dir, filename )
|
153
|
-
IO.binwrite( chunk_path, p1_info[ :wbuffs ].map{ | shadow_id, data | "#{ [ shadow_id, data.bytesize ].pack( 'Q>n' ) }#{ data }" }.join )
|
154
|
-
p1_info[ :chunks ] << filename
|
155
|
-
p1_info[ :spring ] = spring
|
156
|
-
p1_info[ :wbuffs ].clear
|
157
|
-
end
|
158
|
-
|
159
|
-
unless p1_info[ :paused ]
|
160
|
-
add_write( p1 )
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
##
|
165
|
-
# read p1
|
166
|
-
#
|
167
|
-
def read_p1( p1 )
|
168
|
-
data, addrinfo, rflags, *controls = p1.recvmsg
|
169
|
-
now = Time.new
|
170
|
-
info = @infos[ p1 ]
|
171
|
-
info[ :last_coming_at ] = now
|
172
|
-
app_id = data[ 0, 8 ].unpack( 'Q>' ).first
|
173
|
-
|
174
|
-
if app_id == 0
|
175
|
-
case data[ 8 ].unpack( 'C' ).first
|
176
|
-
when PEER_ADDR
|
177
|
-
return if addrinfo.to_sockaddr != @p2pd_sockaddr
|
178
|
-
|
179
|
-
unless info[ :p2_addr ]
|
180
|
-
# puts "debug peer addr #{ data[ 9..-1 ].inspect } #{ Time.new }"
|
181
|
-
info[ :p2_addr ] = data[ 9..-1 ]
|
182
|
-
loop_send_status( p1 )
|
183
|
-
end
|
184
|
-
|
185
|
-
ctlmsg = [ 0, HEARTBEAT, rand( 128 ) ].pack( 'Q>CC' )
|
186
|
-
send_pack( p1, ctlmsg, info[ :p2_addr ] )
|
187
|
-
when A_NEW_APP
|
188
|
-
return unless info[ :p2_addr ]
|
189
|
-
|
190
|
-
app_id = data[ 9, 8 ].unpack( 'Q>' ).first
|
191
|
-
shadow_id = info[ :app_ids ][ app_id ]
|
192
|
-
|
193
|
-
unless shadow_id
|
194
|
-
shadow = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
|
195
|
-
shadow.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 )
|
196
|
-
|
197
|
-
begin
|
198
|
-
shadow.connect_nonblock( @appd_sockaddr )
|
199
|
-
rescue IO::WaitWritable, Errno::EINTR
|
200
|
-
end
|
201
|
-
|
202
|
-
shadow_id = shadow.object_id
|
203
|
-
|
204
|
-
@socks[ shadow_id ] = shadow
|
205
|
-
@roles[ shadow ] = :shadow
|
206
|
-
@infos[ shadow ] = {
|
207
|
-
wbuff: '', # 写前缓存
|
208
|
-
cache: '', # 块读出缓存
|
209
|
-
chunks: [], # 块队列,写前达到块大小时结一个块 filename
|
210
|
-
spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
|
211
|
-
p1: p1
|
212
|
-
}
|
213
|
-
|
214
|
-
info[ :shadows ] << shadow
|
215
|
-
info[ :shadow_exts ][ shadow_id ] = {
|
216
|
-
shadow: shadow,
|
217
|
-
wmems: {}, # 写后缓存 pack_id => data
|
218
|
-
send_ats: {}, # 上一次发出时间 pack_id => send_at
|
219
|
-
biggest_pack_id: 0, # 发到几
|
220
|
-
continue_app_pack_id: 0, # 收到几
|
221
|
-
pieces: {}, # 跳号包 app_pack_id => data
|
222
|
-
app_id: app_id, # 对面id
|
223
|
-
is_app_closed: false, # 对面是否已关闭
|
224
|
-
biggest_app_pack_id: 0, # 对面发到几
|
225
|
-
completed_pack_id: 0, # 完成到几(对面收到几)
|
226
|
-
last_traffic_at: nil # 有流量发出,或者有更新收到几,时间戳
|
227
|
-
}
|
228
|
-
info[ :app_ids ][ app_id ] = shadow_id
|
229
|
-
add_read( shadow )
|
230
|
-
end
|
231
|
-
|
232
|
-
ctlmsg = [
|
233
|
-
0,
|
234
|
-
PAIRED,
|
235
|
-
app_id,
|
236
|
-
shadow_id
|
237
|
-
].pack( 'Q>CQ>Q>' )
|
238
|
-
|
239
|
-
# puts "debug send PAIRED #{ app_id } #{ shadow_id } #{ Time.new }"
|
240
|
-
send_pack( p1, ctlmsg, info[ :p2_addr ] )
|
241
|
-
when APP_STATUS
|
242
|
-
app_id, biggest_app_pack_id, continue_shadow_pack_id = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
|
243
|
-
shadow_id = info[ :app_ids ][ app_id ]
|
244
|
-
return unless shadow_id
|
245
|
-
|
246
|
-
ext = info[ :shadow_exts ][ shadow_id ]
|
247
|
-
return unless ext
|
248
|
-
|
249
|
-
# 更新对面发到几
|
250
|
-
if biggest_app_pack_id > ext[ :biggest_app_pack_id ]
|
251
|
-
ext[ :biggest_app_pack_id ] = biggest_app_pack_id
|
252
|
-
end
|
253
|
-
|
254
|
-
# 更新对面收到几,释放写后
|
255
|
-
if continue_shadow_pack_id > ext[ :completed_pack_id ]
|
256
|
-
pack_ids = ext[ :wmems ].keys.select { | pack_id | pack_id <= continue_shadow_pack_id }
|
257
|
-
|
258
|
-
pack_ids.each do | pack_id |
|
259
|
-
ext[ :wmems ].delete( pack_id )
|
260
|
-
ext[ :send_ats ].delete( pack_id )
|
261
|
-
end
|
262
|
-
|
263
|
-
ext[ :completed_pack_id ] = continue_shadow_pack_id
|
264
|
-
end
|
265
|
-
|
266
|
-
if ext[ :is_app_closed ] && ( ext[ :biggest_app_pack_id ] == ext[ :continue_app_pack_id ] )
|
267
|
-
add_write( ext[ :shadow ] )
|
268
|
-
return
|
269
|
-
end
|
270
|
-
|
271
|
-
# 发miss
|
272
|
-
if !ext[ :shadow ].closed? && ( ext[ :continue_app_pack_id ] < ext[ :biggest_app_pack_id ] )
|
273
|
-
ranges = []
|
274
|
-
curr_pack_id = ext[ :continue_app_pack_id ] + 1
|
275
|
-
|
276
|
-
ext[ :pieces ].keys.sort.each do | pack_id |
|
277
|
-
if pack_id > curr_pack_id
|
278
|
-
ranges << [ curr_pack_id, pack_id - 1 ]
|
279
|
-
end
|
280
|
-
|
281
|
-
curr_pack_id = pack_id + 1
|
282
|
-
end
|
283
|
-
|
284
|
-
if curr_pack_id <= ext[ :biggest_app_pack_id ]
|
285
|
-
ranges << [ curr_pack_id, ext[ :biggest_app_pack_id ] ]
|
286
|
-
end
|
287
|
-
|
288
|
-
# puts "debug #{ ext[ :continue_app_pack_id ] }/#{ ext[ :biggest_app_pack_id ] } send MISS #{ ranges.size }"
|
289
|
-
ranges.each do | pack_id_begin, pack_id_end |
|
290
|
-
ctlmsg = [
|
291
|
-
0,
|
292
|
-
MISS,
|
293
|
-
app_id,
|
294
|
-
pack_id_begin,
|
295
|
-
pack_id_end
|
296
|
-
].pack( 'Q>CQ>Q>Q>' )
|
297
|
-
|
298
|
-
send_pack( p1, ctlmsg, info[ :p2_addr ] )
|
299
|
-
end
|
300
|
-
end
|
301
|
-
when MISS
|
302
|
-
shadow_id, pack_id_begin, pack_id_end = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
|
303
|
-
ext = info[ :shadow_exts ][ shadow_id ]
|
304
|
-
return unless ext
|
305
|
-
|
306
|
-
( pack_id_begin..pack_id_end ).each do | pack_id |
|
307
|
-
send_at = ext[ :send_ats ][ pack_id ]
|
308
|
-
|
309
|
-
if send_at
|
310
|
-
break if now - send_at < STATUS_INTERVAL
|
311
|
-
|
312
|
-
info[ :resendings ] << [ shadow_id, pack_id ]
|
313
|
-
end
|
314
|
-
end
|
315
|
-
|
316
|
-
add_write( p1 )
|
317
|
-
when FIN1
|
318
|
-
app_id = data[ 9, 8 ].unpack( 'Q>' ).first
|
319
|
-
ctlmsg = [
|
320
|
-
0,
|
321
|
-
GOT_FIN1,
|
322
|
-
app_id
|
323
|
-
].pack( 'Q>CQ>' )
|
324
|
-
|
325
|
-
# puts "debug 2-1. recv fin1 -> send got_fin1 -> ext.is_app_closed = true #{ app_id } #{ Time.new }"
|
326
|
-
send_pack( p1, ctlmsg, info[ :p2_addr ] )
|
327
|
-
|
328
|
-
shadow_id = info[ :app_ids ][ app_id ]
|
329
|
-
return unless shadow_id
|
330
|
-
|
331
|
-
ext = info[ :shadow_exts ][ shadow_id ]
|
332
|
-
return unless ext
|
333
|
-
|
334
|
-
ext[ :is_app_closed ] = true
|
335
|
-
when GOT_FIN1
|
336
|
-
# puts "debug 1-2. recv got_fin1 -> break loop #{ Time.new }"
|
337
|
-
shadow_id = data[ 9, 8 ].unpack( 'Q>' ).first
|
338
|
-
info[ :fin1s ].delete( shadow_id )
|
339
|
-
when FIN2
|
340
|
-
# puts "debug 1-3. recv fin2 -> send got_fin2 -> del ext #{ Time.new }"
|
341
|
-
app_id = data[ 9, 8 ].unpack( 'Q>' ).first
|
342
|
-
ctlmsg = [
|
343
|
-
0,
|
344
|
-
GOT_FIN2,
|
345
|
-
app_id
|
346
|
-
].pack( 'Q>CQ>' )
|
347
|
-
|
348
|
-
send_pack( p1, ctlmsg, info[ :p2_addr ] )
|
349
|
-
|
350
|
-
shadow_id = info[ :app_ids ].delete( app_id )
|
351
|
-
return unless shadow_id
|
352
|
-
|
353
|
-
info[ :shadow_exts ].delete( shadow_id )
|
354
|
-
when GOT_FIN2
|
355
|
-
# puts "debug 2-4. recv got_fin2 -> break loop #{ Time.new }"
|
356
|
-
shadow_id = data[ 9, 8 ].unpack( 'Q>' ).first
|
357
|
-
info[ :fin2s ].delete( shadow_id )
|
358
|
-
when P2_FIN
|
359
|
-
puts "p2 fin #{ Time.new }"
|
360
|
-
add_closing( p1 )
|
361
|
-
end
|
362
|
-
|
363
|
-
return
|
364
|
-
end
|
365
|
-
|
366
|
-
shadow_id = info[ :app_ids ][ app_id ]
|
367
|
-
return unless shadow_id
|
368
|
-
|
369
|
-
ext = info[ :shadow_exts ][ shadow_id ]
|
370
|
-
return if ext.nil? || ext[ :shadow ].closed?
|
371
|
-
|
372
|
-
pack_id = data[ 8, 8 ].unpack( 'Q>' ).first
|
373
|
-
return if ( pack_id <= ext[ :continue_app_pack_id ] ) || ext[ :pieces ].include?( pack_id )
|
374
|
-
|
375
|
-
data = data[ 16..-1 ]
|
376
|
-
|
377
|
-
# 解混淆
|
378
|
-
if pack_id == 1
|
379
|
-
data = @hex.decode( data )
|
380
|
-
end
|
381
|
-
|
382
|
-
# 放进shadow的写前缓存,跳号放碎片缓存
|
383
|
-
if pack_id - ext[ :continue_app_pack_id ] == 1
|
384
|
-
while ext[ :pieces ].include?( pack_id + 1 )
|
385
|
-
data << ext[ :pieces ].delete( pack_id + 1 )
|
386
|
-
pack_id += 1
|
387
|
-
end
|
388
|
-
|
389
|
-
ext[ :continue_app_pack_id ] = pack_id
|
390
|
-
ext[ :last_traffic_at ] = now
|
391
|
-
|
392
|
-
shadow_info = @infos[ ext[ :shadow ] ]
|
393
|
-
shadow_info[ :wbuff ] << data
|
394
|
-
|
395
|
-
if shadow_info[ :wbuff ].bytesize >= CHUNK_SIZE
|
396
|
-
spring = shadow_info[ :chunks ].size > 0 ? ( shadow_info[ :spring ] + 1 ) : 0
|
397
|
-
filename = "#{ shadow_id }.#{ spring }"
|
398
|
-
chunk_path = File.join( @shadow_chunk_dir, filename )
|
399
|
-
IO.binwrite( chunk_path, shadow_info[ :wbuff ] )
|
400
|
-
shadow_info[ :chunks ] << filename
|
401
|
-
shadow_info[ :spring ] = spring
|
402
|
-
shadow_info[ :wbuff ].clear
|
403
|
-
end
|
404
|
-
|
405
|
-
add_write( ext[ :shadow ] )
|
406
|
-
else
|
407
|
-
ext[ :pieces ][ pack_id ] = data
|
408
|
-
end
|
409
|
-
end
|
410
|
-
|
411
|
-
##
|
412
|
-
# write shadow
|
413
|
-
#
|
414
|
-
def write_shadow( shadow )
|
415
|
-
if @closings.include?( shadow )
|
416
|
-
close_shadow( shadow )
|
417
|
-
return
|
418
|
-
end
|
419
|
-
|
420
|
-
info = @infos[ shadow ]
|
421
|
-
|
422
|
-
# 取写前
|
423
|
-
data = info[ :cache ]
|
424
|
-
from = :cache
|
425
|
-
|
426
|
-
if data.empty?
|
427
|
-
if info[ :chunks ].any?
|
428
|
-
path = File.join( @shadow_chunk_dir, info[ :chunks ].shift )
|
429
|
-
|
430
|
-
begin
|
431
|
-
data = IO.binread( path )
|
432
|
-
File.delete( path )
|
433
|
-
rescue Errno::ENOENT
|
434
|
-
add_closing( shadow )
|
435
|
-
return
|
436
|
-
end
|
437
|
-
else
|
438
|
-
data = info[ :wbuff ]
|
439
|
-
from = :wbuff
|
440
|
-
end
|
441
|
-
end
|
442
|
-
|
443
|
-
if data.empty?
|
444
|
-
p1 = info[ :p1 ]
|
445
|
-
|
446
|
-
if p1.closed?
|
447
|
-
add_closing( shadow )
|
448
|
-
return
|
449
|
-
end
|
450
|
-
|
451
|
-
p1_info = @infos[ p1 ]
|
452
|
-
ext = p1_info[ :shadow_exts ][ shadow.object_id ]
|
453
|
-
|
454
|
-
if ext[ :is_app_closed ] && ( ext[ :biggest_app_pack_id ] == ext[ :continue_app_pack_id ] )
|
455
|
-
# puts "debug 2-2. all sent && ext.biggest_app_pack_id == ext.continue_app_pack_id -> add closing shadow #{ Time.new }"
|
456
|
-
add_closing( shadow )
|
457
|
-
return
|
458
|
-
end
|
459
|
-
|
460
|
-
@writes.delete( shadow )
|
461
|
-
return
|
462
|
-
end
|
463
|
-
|
464
|
-
begin
|
465
|
-
written = shadow.write_nonblock( data )
|
466
|
-
rescue IO::WaitWritable, Errno::EINTR => e
|
467
|
-
info[ from ] = data
|
468
|
-
return
|
469
|
-
rescue Exception => e
|
470
|
-
add_closing( shadow )
|
471
|
-
return
|
472
|
-
end
|
473
|
-
|
474
|
-
data = data[ written..-1 ]
|
475
|
-
info[ from ] = data
|
476
|
-
end
|
477
|
-
|
478
|
-
##
|
479
|
-
# write p1
|
480
|
-
#
|
481
|
-
def write_p1( p1 )
|
482
|
-
if @closings.include?( p1 )
|
483
|
-
close_p1( p1 )
|
484
|
-
new_p1
|
485
|
-
return
|
486
|
-
end
|
487
|
-
|
488
|
-
now = Time.new
|
489
|
-
info = @infos[ p1 ]
|
490
|
-
|
491
|
-
# 重传
|
492
|
-
while info[ :resendings ].any?
|
493
|
-
shadow_id, pack_id = info[ :resendings ].shift
|
494
|
-
ext = info[ :shadow_exts ][ shadow_id ]
|
495
|
-
|
496
|
-
if ext
|
497
|
-
pack = ext[ :wmems ][ pack_id ]
|
498
|
-
|
499
|
-
if pack
|
500
|
-
send_pack( p1, pack, info[ :p2_addr ] )
|
501
|
-
ext[ :last_traffic_at ] = now
|
502
|
-
return
|
503
|
-
end
|
504
|
-
end
|
505
|
-
end
|
506
|
-
|
507
|
-
# 若写后到达上限,暂停取写前
|
508
|
-
if info[ :shadow_exts ].map{ | _, ext | ext[ :wmems ].size }.sum >= WMEMS_LIMIT
|
509
|
-
unless info[ :paused ]
|
510
|
-
puts "pause #{ Time.new }"
|
511
|
-
info[ :paused ] = true
|
512
|
-
end
|
513
|
-
|
514
|
-
@writes.delete( p1 )
|
515
|
-
return
|
516
|
-
end
|
517
|
-
|
518
|
-
# 取写前
|
519
|
-
if info[ :caches ].any?
|
520
|
-
shadow_id, data = info[ :caches ].shift
|
521
|
-
elsif info[ :chunks ].any?
|
522
|
-
path = File.join( @p1_chunk_dir, info[ :chunks ].shift )
|
523
|
-
|
524
|
-
begin
|
525
|
-
data = IO.binread( path )
|
526
|
-
File.delete( path )
|
527
|
-
rescue Errno::ENOENT
|
528
|
-
add_closing( p1 )
|
529
|
-
return
|
530
|
-
end
|
531
|
-
|
532
|
-
caches = []
|
533
|
-
|
534
|
-
until data.empty?
|
535
|
-
shadow_id, pack_size = data[ 0, 10 ].unpack( 'Q>n' )
|
536
|
-
caches << [ shadow_id, data[ 10, pack_size ] ]
|
537
|
-
data = data[ ( 10 + pack_size )..-1 ]
|
538
|
-
end
|
539
|
-
|
540
|
-
shadow_id, data = caches.shift
|
541
|
-
info[ :caches ] = caches
|
542
|
-
elsif info[ :wbuffs ].any?
|
543
|
-
shadow_id, data = info[ :wbuffs ].shift
|
544
|
-
else
|
545
|
-
@writes.delete( p1 )
|
546
|
-
return
|
547
|
-
end
|
548
|
-
|
549
|
-
ext = info[ :shadow_exts ][ shadow_id ]
|
550
|
-
|
551
|
-
if ext
|
552
|
-
pack_id = ext[ :biggest_pack_id ] + 1
|
553
|
-
|
554
|
-
if pack_id == 1
|
555
|
-
data = @hex.encode( data )
|
556
|
-
end
|
557
|
-
|
558
|
-
pack = "#{ [ shadow_id, pack_id ].pack( 'Q>Q>' ) }#{ data }"
|
559
|
-
send_pack( p1, pack, info[ :p2_addr ] )
|
560
|
-
ext[ :biggest_pack_id ] = pack_id
|
561
|
-
ext[ :wmems ][ pack_id ] = pack
|
562
|
-
ext[ :send_ats ][ pack_id ] = now
|
563
|
-
ext[ :last_traffic_at ] = now
|
564
|
-
end
|
565
|
-
end
|
566
|
-
|
567
|
-
def new_p1
|
568
|
-
p1 = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
|
569
|
-
p1.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
|
570
|
-
p1.bind( Socket.sockaddr_in( 0, '0.0.0.0' ) )
|
571
|
-
|
572
|
-
p1_info = {
|
573
|
-
wbuffs: [], # 写前缓存 [ shadow_id, data ]
|
574
|
-
caches: [], # 块读出缓存 [ shadow_id, data ]
|
575
|
-
chunks: [], # 块队列 filename
|
576
|
-
spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
|
577
|
-
p2_addr: nil, # 远端地址
|
578
|
-
app_ids: {}, # app_id => shadow_id
|
579
|
-
shadows: [], # 开着的shadow
|
580
|
-
shadow_exts: {}, # 传输相关 shadow_id => {}
|
581
|
-
fin1s: [], # fin1: shadow已关闭,等待对面收完流量 shadow_id
|
582
|
-
fin2s: [], # fin2: 流量已收完 shadow_id
|
583
|
-
last_coming_at: nil, # 上一次来流量的时间
|
584
|
-
paused: false, # 是否暂停写
|
585
|
-
resendings: [] # 重传队列 [ shadow_id, pack_id ]
|
586
|
-
}
|
587
|
-
|
588
|
-
@p1 = p1
|
589
|
-
@p1_info = p1_info
|
590
|
-
@socks[ p1.object_id ] = p1
|
591
|
-
@roles[ p1 ] = :p1
|
592
|
-
@infos[ p1 ] = p1_info
|
593
|
-
|
594
|
-
send_pack( p1, @title, @p2pd_sockaddr )
|
595
|
-
add_read( p1 )
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
if
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
end
|
732
|
-
|
733
|
-
def
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
end
|
746
|
-
|
747
|
-
def
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
@
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
info[ :chunks ].each do | filename |
|
809
|
-
begin
|
810
|
-
File.delete( File.join( chunk_dir, filename ) )
|
811
|
-
rescue Errno::ENOENT
|
812
|
-
end
|
813
|
-
end
|
814
|
-
end
|
815
|
-
|
816
|
-
info
|
817
|
-
end
|
818
|
-
|
819
|
-
end
|
820
|
-
end
|
1
|
+
require 'p2p2/head'
|
2
|
+
require 'p2p2/hex'
|
3
|
+
require 'p2p2/version'
|
4
|
+
require 'socket'
|
5
|
+
|
6
|
+
##
|
7
|
+
# P2p2::P1 - 内网里的任意应用,访问另一个内网里的应用服务端。p1端。
|
8
|
+
#
|
9
|
+
# 两套关闭
|
10
|
+
# ========
|
11
|
+
#
|
12
|
+
# 1-1. shadow.close -> ext.is_app_closed ? no -> send fin1 loop
|
13
|
+
# 1-2. recv got_fin1 -> break loop
|
14
|
+
# 1-3. recv fin2 -> send got_fin2 -> del ext
|
15
|
+
#
|
16
|
+
# 2-1. recv fin1 -> send got_fin1 -> ext.is_app_closed = true
|
17
|
+
# 2-2. all sent && ext.biggest_app_pack_id == ext.continue_app_pack_id -> add closing shadow
|
18
|
+
# 2-3. shadow.close -> ext.is_app_closed ? yes -> del ext -> loop send fin2
|
19
|
+
# 2-4. recv got_fin2 -> break loop
|
20
|
+
#
|
21
|
+
module P2p2
|
22
|
+
class P1
|
23
|
+
|
24
|
+
##
|
25
|
+
# p2pd_host 配对服务器ip
|
26
|
+
# p2pd_port 配对服务器端口
|
27
|
+
# appd_host 任意的一个应用的ip
|
28
|
+
# appd_port 应用端口
|
29
|
+
# title 约定的房间名
|
30
|
+
# shadow_chunk_dir 文件缓存目录,缓存shadow来不及写的流量
|
31
|
+
# p1_chunk_dir 文件缓存目录,缓存p1来不及写的流量
|
32
|
+
#
|
33
|
+
def initialize( p2pd_host, p2pd_port, appd_host, appd_port, title, shadow_chunk_dir = '/tmp', p1_chunk_dir = '/tmp' )
|
34
|
+
@p2pd_sockaddr = Socket.sockaddr_in( p2pd_port, p2pd_host )
|
35
|
+
@appd_sockaddr = Socket.sockaddr_in( appd_port, appd_host )
|
36
|
+
@title = title
|
37
|
+
@shadow_chunk_dir = shadow_chunk_dir
|
38
|
+
@p1_chunk_dir = p1_chunk_dir
|
39
|
+
@hex = P2p2::Hex.new
|
40
|
+
@mutex = Mutex.new
|
41
|
+
@reads = []
|
42
|
+
@writes = []
|
43
|
+
@closings = []
|
44
|
+
@socks = {} # object_id => sock
|
45
|
+
@roles = {} # sock => :ctlr / :shadow / :p1
|
46
|
+
@infos = {}
|
47
|
+
|
48
|
+
ctlr, ctlw = IO.pipe
|
49
|
+
@ctlw = ctlw
|
50
|
+
@roles[ ctlr ] = :ctlr
|
51
|
+
add_read( ctlr )
|
52
|
+
end
|
53
|
+
|
54
|
+
def looping
|
55
|
+
puts 'looping'
|
56
|
+
|
57
|
+
new_p1
|
58
|
+
|
59
|
+
loop do
|
60
|
+
rs, ws = IO.select( @reads, @writes )
|
61
|
+
|
62
|
+
@mutex.synchronize do
|
63
|
+
rs.each do | sock |
|
64
|
+
case @roles[ sock ]
|
65
|
+
when :ctlr
|
66
|
+
read_ctlr( sock )
|
67
|
+
when :shadow
|
68
|
+
read_shadow( sock )
|
69
|
+
when :p1
|
70
|
+
read_p1( sock )
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
ws.each do | sock |
|
75
|
+
case @roles[ sock ]
|
76
|
+
when :shadow
|
77
|
+
write_shadow( sock )
|
78
|
+
when :p1
|
79
|
+
write_p1( sock )
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
rescue Interrupt => e
|
85
|
+
puts e.class
|
86
|
+
quit!
|
87
|
+
end
|
88
|
+
|
89
|
+
def quit!
|
90
|
+
if @p1 && !@p1.closed? && @p1_info[ :p2_addr ]
|
91
|
+
ctlmsg = [ 0, P1_FIN ].pack( 'Q>C' )
|
92
|
+
send_pack( @p1, ctlmsg, @p1_info[ :p2_addr ] )
|
93
|
+
end
|
94
|
+
|
95
|
+
exit
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
##
|
101
|
+
# read ctlr
|
102
|
+
#
|
103
|
+
def read_ctlr( ctlr )
|
104
|
+
case ctlr.read( 1 )
|
105
|
+
when CTL_CLOSE_SOCK
|
106
|
+
sock_id = ctlr.read( 8 ).unpack( 'Q>' ).first
|
107
|
+
sock = @socks[ sock_id ]
|
108
|
+
|
109
|
+
if sock
|
110
|
+
puts "expire p1 #{ sock_id } #{ Time.new }"
|
111
|
+
add_closing( sock )
|
112
|
+
end
|
113
|
+
when CTL_RESUME
|
114
|
+
p1_id = ctlr.read( 8 ).unpack( 'Q>' ).first
|
115
|
+
|
116
|
+
puts "resume #{ p1_id } #{ Time.new }"
|
117
|
+
p1 = @socks[ p1_id ]
|
118
|
+
|
119
|
+
if p1
|
120
|
+
add_write( p1 )
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
##
|
126
|
+
# read shadow
|
127
|
+
#
|
128
|
+
def read_shadow( shadow )
|
129
|
+
begin
|
130
|
+
data = shadow.read_nonblock( PACK_SIZE )
|
131
|
+
rescue IO::WaitReadable, Errno::EINTR
|
132
|
+
return
|
133
|
+
rescue Exception => e
|
134
|
+
add_closing( shadow )
|
135
|
+
return
|
136
|
+
end
|
137
|
+
|
138
|
+
info = @infos[ shadow ]
|
139
|
+
p1 = info[ :p1 ]
|
140
|
+
|
141
|
+
if p1.closed?
|
142
|
+
add_closing( shadow )
|
143
|
+
return
|
144
|
+
end
|
145
|
+
|
146
|
+
p1_info = @infos[ p1 ]
|
147
|
+
p1_info[ :wbuffs ] << [ shadow.object_id, data ]
|
148
|
+
|
149
|
+
if p1_info[ :wbuffs ].size >= WBUFFS_LIMIT
|
150
|
+
spring = p1_info[ :chunks ].size > 0 ? ( p1_info[ :spring ] + 1 ) : 0
|
151
|
+
filename = "#{ p1.object_id }.#{ spring }"
|
152
|
+
chunk_path = File.join( @p1_chunk_dir, filename )
|
153
|
+
IO.binwrite( chunk_path, p1_info[ :wbuffs ].map{ | shadow_id, data | "#{ [ shadow_id, data.bytesize ].pack( 'Q>n' ) }#{ data }" }.join )
|
154
|
+
p1_info[ :chunks ] << filename
|
155
|
+
p1_info[ :spring ] = spring
|
156
|
+
p1_info[ :wbuffs ].clear
|
157
|
+
end
|
158
|
+
|
159
|
+
unless p1_info[ :paused ]
|
160
|
+
add_write( p1 )
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
##
|
165
|
+
# read p1
|
166
|
+
#
|
167
|
+
def read_p1( p1 )
|
168
|
+
data, addrinfo, rflags, *controls = p1.recvmsg
|
169
|
+
now = Time.new
|
170
|
+
info = @infos[ p1 ]
|
171
|
+
info[ :last_coming_at ] = now
|
172
|
+
app_id = data[ 0, 8 ].unpack( 'Q>' ).first
|
173
|
+
|
174
|
+
if app_id == 0
|
175
|
+
case data[ 8 ].unpack( 'C' ).first
|
176
|
+
when PEER_ADDR
|
177
|
+
return if addrinfo.to_sockaddr != @p2pd_sockaddr
|
178
|
+
|
179
|
+
unless info[ :p2_addr ]
|
180
|
+
# puts "debug peer addr #{ data[ 9..-1 ].inspect } #{ Time.new }"
|
181
|
+
info[ :p2_addr ] = data[ 9..-1 ]
|
182
|
+
loop_send_status( p1 )
|
183
|
+
end
|
184
|
+
|
185
|
+
ctlmsg = [ 0, HEARTBEAT, rand( 128 ) ].pack( 'Q>CC' )
|
186
|
+
send_pack( p1, ctlmsg, info[ :p2_addr ] )
|
187
|
+
when A_NEW_APP
|
188
|
+
return unless info[ :p2_addr ]
|
189
|
+
|
190
|
+
app_id = data[ 9, 8 ].unpack( 'Q>' ).first
|
191
|
+
shadow_id = info[ :app_ids ][ app_id ]
|
192
|
+
|
193
|
+
unless shadow_id
|
194
|
+
shadow = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
|
195
|
+
shadow.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 )
|
196
|
+
|
197
|
+
begin
|
198
|
+
shadow.connect_nonblock( @appd_sockaddr )
|
199
|
+
rescue IO::WaitWritable, Errno::EINTR
|
200
|
+
end
|
201
|
+
|
202
|
+
shadow_id = shadow.object_id
|
203
|
+
|
204
|
+
@socks[ shadow_id ] = shadow
|
205
|
+
@roles[ shadow ] = :shadow
|
206
|
+
@infos[ shadow ] = {
|
207
|
+
wbuff: '', # 写前缓存
|
208
|
+
cache: '', # 块读出缓存
|
209
|
+
chunks: [], # 块队列,写前达到块大小时结一个块 filename
|
210
|
+
spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
|
211
|
+
p1: p1
|
212
|
+
}
|
213
|
+
|
214
|
+
info[ :shadows ] << shadow
|
215
|
+
info[ :shadow_exts ][ shadow_id ] = {
|
216
|
+
shadow: shadow,
|
217
|
+
wmems: {}, # 写后缓存 pack_id => data
|
218
|
+
send_ats: {}, # 上一次发出时间 pack_id => send_at
|
219
|
+
biggest_pack_id: 0, # 发到几
|
220
|
+
continue_app_pack_id: 0, # 收到几
|
221
|
+
pieces: {}, # 跳号包 app_pack_id => data
|
222
|
+
app_id: app_id, # 对面id
|
223
|
+
is_app_closed: false, # 对面是否已关闭
|
224
|
+
biggest_app_pack_id: 0, # 对面发到几
|
225
|
+
completed_pack_id: 0, # 完成到几(对面收到几)
|
226
|
+
last_traffic_at: nil # 有流量发出,或者有更新收到几,时间戳
|
227
|
+
}
|
228
|
+
info[ :app_ids ][ app_id ] = shadow_id
|
229
|
+
add_read( shadow )
|
230
|
+
end
|
231
|
+
|
232
|
+
ctlmsg = [
|
233
|
+
0,
|
234
|
+
PAIRED,
|
235
|
+
app_id,
|
236
|
+
shadow_id
|
237
|
+
].pack( 'Q>CQ>Q>' )
|
238
|
+
|
239
|
+
# puts "debug send PAIRED #{ app_id } #{ shadow_id } #{ Time.new }"
|
240
|
+
send_pack( p1, ctlmsg, info[ :p2_addr ] )
|
241
|
+
when APP_STATUS
|
242
|
+
app_id, biggest_app_pack_id, continue_shadow_pack_id = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
|
243
|
+
shadow_id = info[ :app_ids ][ app_id ]
|
244
|
+
return unless shadow_id
|
245
|
+
|
246
|
+
ext = info[ :shadow_exts ][ shadow_id ]
|
247
|
+
return unless ext
|
248
|
+
|
249
|
+
# 更新对面发到几
|
250
|
+
if biggest_app_pack_id > ext[ :biggest_app_pack_id ]
|
251
|
+
ext[ :biggest_app_pack_id ] = biggest_app_pack_id
|
252
|
+
end
|
253
|
+
|
254
|
+
# 更新对面收到几,释放写后
|
255
|
+
if continue_shadow_pack_id > ext[ :completed_pack_id ]
|
256
|
+
pack_ids = ext[ :wmems ].keys.select { | pack_id | pack_id <= continue_shadow_pack_id }
|
257
|
+
|
258
|
+
pack_ids.each do | pack_id |
|
259
|
+
ext[ :wmems ].delete( pack_id )
|
260
|
+
ext[ :send_ats ].delete( pack_id )
|
261
|
+
end
|
262
|
+
|
263
|
+
ext[ :completed_pack_id ] = continue_shadow_pack_id
|
264
|
+
end
|
265
|
+
|
266
|
+
if ext[ :is_app_closed ] && ( ext[ :biggest_app_pack_id ] == ext[ :continue_app_pack_id ] )
|
267
|
+
add_write( ext[ :shadow ] )
|
268
|
+
return
|
269
|
+
end
|
270
|
+
|
271
|
+
# 发miss
|
272
|
+
if !ext[ :shadow ].closed? && ( ext[ :continue_app_pack_id ] < ext[ :biggest_app_pack_id ] )
|
273
|
+
ranges = []
|
274
|
+
curr_pack_id = ext[ :continue_app_pack_id ] + 1
|
275
|
+
|
276
|
+
ext[ :pieces ].keys.sort.each do | pack_id |
|
277
|
+
if pack_id > curr_pack_id
|
278
|
+
ranges << [ curr_pack_id, pack_id - 1 ]
|
279
|
+
end
|
280
|
+
|
281
|
+
curr_pack_id = pack_id + 1
|
282
|
+
end
|
283
|
+
|
284
|
+
if curr_pack_id <= ext[ :biggest_app_pack_id ]
|
285
|
+
ranges << [ curr_pack_id, ext[ :biggest_app_pack_id ] ]
|
286
|
+
end
|
287
|
+
|
288
|
+
# puts "debug #{ ext[ :continue_app_pack_id ] }/#{ ext[ :biggest_app_pack_id ] } send MISS #{ ranges.size }"
|
289
|
+
ranges.each do | pack_id_begin, pack_id_end |
|
290
|
+
ctlmsg = [
|
291
|
+
0,
|
292
|
+
MISS,
|
293
|
+
app_id,
|
294
|
+
pack_id_begin,
|
295
|
+
pack_id_end
|
296
|
+
].pack( 'Q>CQ>Q>Q>' )
|
297
|
+
|
298
|
+
send_pack( p1, ctlmsg, info[ :p2_addr ] )
|
299
|
+
end
|
300
|
+
end
|
301
|
+
when MISS
|
302
|
+
shadow_id, pack_id_begin, pack_id_end = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
|
303
|
+
ext = info[ :shadow_exts ][ shadow_id ]
|
304
|
+
return unless ext
|
305
|
+
|
306
|
+
( pack_id_begin..pack_id_end ).each do | pack_id |
|
307
|
+
send_at = ext[ :send_ats ][ pack_id ]
|
308
|
+
|
309
|
+
if send_at
|
310
|
+
break if now - send_at < STATUS_INTERVAL
|
311
|
+
|
312
|
+
info[ :resendings ] << [ shadow_id, pack_id ]
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
add_write( p1 )
|
317
|
+
when FIN1
|
318
|
+
app_id = data[ 9, 8 ].unpack( 'Q>' ).first
|
319
|
+
ctlmsg = [
|
320
|
+
0,
|
321
|
+
GOT_FIN1,
|
322
|
+
app_id
|
323
|
+
].pack( 'Q>CQ>' )
|
324
|
+
|
325
|
+
# puts "debug 2-1. recv fin1 -> send got_fin1 -> ext.is_app_closed = true #{ app_id } #{ Time.new }"
|
326
|
+
send_pack( p1, ctlmsg, info[ :p2_addr ] )
|
327
|
+
|
328
|
+
shadow_id = info[ :app_ids ][ app_id ]
|
329
|
+
return unless shadow_id
|
330
|
+
|
331
|
+
ext = info[ :shadow_exts ][ shadow_id ]
|
332
|
+
return unless ext
|
333
|
+
|
334
|
+
ext[ :is_app_closed ] = true
|
335
|
+
when GOT_FIN1
|
336
|
+
# puts "debug 1-2. recv got_fin1 -> break loop #{ Time.new }"
|
337
|
+
shadow_id = data[ 9, 8 ].unpack( 'Q>' ).first
|
338
|
+
info[ :fin1s ].delete( shadow_id )
|
339
|
+
when FIN2
|
340
|
+
# puts "debug 1-3. recv fin2 -> send got_fin2 -> del ext #{ Time.new }"
|
341
|
+
app_id = data[ 9, 8 ].unpack( 'Q>' ).first
|
342
|
+
ctlmsg = [
|
343
|
+
0,
|
344
|
+
GOT_FIN2,
|
345
|
+
app_id
|
346
|
+
].pack( 'Q>CQ>' )
|
347
|
+
|
348
|
+
send_pack( p1, ctlmsg, info[ :p2_addr ] )
|
349
|
+
|
350
|
+
shadow_id = info[ :app_ids ].delete( app_id )
|
351
|
+
return unless shadow_id
|
352
|
+
|
353
|
+
info[ :shadow_exts ].delete( shadow_id )
|
354
|
+
when GOT_FIN2
|
355
|
+
# puts "debug 2-4. recv got_fin2 -> break loop #{ Time.new }"
|
356
|
+
shadow_id = data[ 9, 8 ].unpack( 'Q>' ).first
|
357
|
+
info[ :fin2s ].delete( shadow_id )
|
358
|
+
when P2_FIN
|
359
|
+
puts "p2 fin #{ Time.new }"
|
360
|
+
add_closing( p1 )
|
361
|
+
end
|
362
|
+
|
363
|
+
return
|
364
|
+
end
|
365
|
+
|
366
|
+
shadow_id = info[ :app_ids ][ app_id ]
|
367
|
+
return unless shadow_id
|
368
|
+
|
369
|
+
ext = info[ :shadow_exts ][ shadow_id ]
|
370
|
+
return if ext.nil? || ext[ :shadow ].closed?
|
371
|
+
|
372
|
+
pack_id = data[ 8, 8 ].unpack( 'Q>' ).first
|
373
|
+
return if ( pack_id <= ext[ :continue_app_pack_id ] ) || ext[ :pieces ].include?( pack_id )
|
374
|
+
|
375
|
+
data = data[ 16..-1 ]
|
376
|
+
|
377
|
+
# 解混淆
|
378
|
+
if pack_id == 1
|
379
|
+
data = @hex.decode( data )
|
380
|
+
end
|
381
|
+
|
382
|
+
# 放进shadow的写前缓存,跳号放碎片缓存
|
383
|
+
if pack_id - ext[ :continue_app_pack_id ] == 1
|
384
|
+
while ext[ :pieces ].include?( pack_id + 1 )
|
385
|
+
data << ext[ :pieces ].delete( pack_id + 1 )
|
386
|
+
pack_id += 1
|
387
|
+
end
|
388
|
+
|
389
|
+
ext[ :continue_app_pack_id ] = pack_id
|
390
|
+
ext[ :last_traffic_at ] = now
|
391
|
+
|
392
|
+
shadow_info = @infos[ ext[ :shadow ] ]
|
393
|
+
shadow_info[ :wbuff ] << data
|
394
|
+
|
395
|
+
if shadow_info[ :wbuff ].bytesize >= CHUNK_SIZE
|
396
|
+
spring = shadow_info[ :chunks ].size > 0 ? ( shadow_info[ :spring ] + 1 ) : 0
|
397
|
+
filename = "#{ shadow_id }.#{ spring }"
|
398
|
+
chunk_path = File.join( @shadow_chunk_dir, filename )
|
399
|
+
IO.binwrite( chunk_path, shadow_info[ :wbuff ] )
|
400
|
+
shadow_info[ :chunks ] << filename
|
401
|
+
shadow_info[ :spring ] = spring
|
402
|
+
shadow_info[ :wbuff ].clear
|
403
|
+
end
|
404
|
+
|
405
|
+
add_write( ext[ :shadow ] )
|
406
|
+
else
|
407
|
+
ext[ :pieces ][ pack_id ] = data
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
411
|
+
##
|
412
|
+
# write shadow
|
413
|
+
#
|
414
|
+
def write_shadow( shadow )
|
415
|
+
if @closings.include?( shadow )
|
416
|
+
close_shadow( shadow )
|
417
|
+
return
|
418
|
+
end
|
419
|
+
|
420
|
+
info = @infos[ shadow ]
|
421
|
+
|
422
|
+
# 取写前
|
423
|
+
data = info[ :cache ]
|
424
|
+
from = :cache
|
425
|
+
|
426
|
+
if data.empty?
|
427
|
+
if info[ :chunks ].any?
|
428
|
+
path = File.join( @shadow_chunk_dir, info[ :chunks ].shift )
|
429
|
+
|
430
|
+
begin
|
431
|
+
data = IO.binread( path )
|
432
|
+
File.delete( path )
|
433
|
+
rescue Errno::ENOENT
|
434
|
+
add_closing( shadow )
|
435
|
+
return
|
436
|
+
end
|
437
|
+
else
|
438
|
+
data = info[ :wbuff ]
|
439
|
+
from = :wbuff
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
if data.empty?
|
444
|
+
p1 = info[ :p1 ]
|
445
|
+
|
446
|
+
if p1.closed?
|
447
|
+
add_closing( shadow )
|
448
|
+
return
|
449
|
+
end
|
450
|
+
|
451
|
+
p1_info = @infos[ p1 ]
|
452
|
+
ext = p1_info[ :shadow_exts ][ shadow.object_id ]
|
453
|
+
|
454
|
+
if ext[ :is_app_closed ] && ( ext[ :biggest_app_pack_id ] == ext[ :continue_app_pack_id ] )
|
455
|
+
# puts "debug 2-2. all sent && ext.biggest_app_pack_id == ext.continue_app_pack_id -> add closing shadow #{ Time.new }"
|
456
|
+
add_closing( shadow )
|
457
|
+
return
|
458
|
+
end
|
459
|
+
|
460
|
+
@writes.delete( shadow )
|
461
|
+
return
|
462
|
+
end
|
463
|
+
|
464
|
+
begin
|
465
|
+
written = shadow.write_nonblock( data )
|
466
|
+
rescue IO::WaitWritable, Errno::EINTR => e
|
467
|
+
info[ from ] = data
|
468
|
+
return
|
469
|
+
rescue Exception => e
|
470
|
+
add_closing( shadow )
|
471
|
+
return
|
472
|
+
end
|
473
|
+
|
474
|
+
data = data[ written..-1 ]
|
475
|
+
info[ from ] = data
|
476
|
+
end
|
477
|
+
|
478
|
+
##
|
479
|
+
# write p1
|
480
|
+
#
|
481
|
+
def write_p1( p1 )
|
482
|
+
if @closings.include?( p1 )
|
483
|
+
close_p1( p1 )
|
484
|
+
new_p1
|
485
|
+
return
|
486
|
+
end
|
487
|
+
|
488
|
+
now = Time.new
|
489
|
+
info = @infos[ p1 ]
|
490
|
+
|
491
|
+
# 重传
|
492
|
+
while info[ :resendings ].any?
|
493
|
+
shadow_id, pack_id = info[ :resendings ].shift
|
494
|
+
ext = info[ :shadow_exts ][ shadow_id ]
|
495
|
+
|
496
|
+
if ext
|
497
|
+
pack = ext[ :wmems ][ pack_id ]
|
498
|
+
|
499
|
+
if pack
|
500
|
+
send_pack( p1, pack, info[ :p2_addr ] )
|
501
|
+
ext[ :last_traffic_at ] = now
|
502
|
+
return
|
503
|
+
end
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
507
|
+
# 若写后到达上限,暂停取写前
|
508
|
+
if info[ :shadow_exts ].map{ | _, ext | ext[ :wmems ].size }.sum >= WMEMS_LIMIT
|
509
|
+
unless info[ :paused ]
|
510
|
+
puts "pause #{ Time.new }"
|
511
|
+
info[ :paused ] = true
|
512
|
+
end
|
513
|
+
|
514
|
+
@writes.delete( p1 )
|
515
|
+
return
|
516
|
+
end
|
517
|
+
|
518
|
+
# 取写前
|
519
|
+
if info[ :caches ].any?
|
520
|
+
shadow_id, data = info[ :caches ].shift
|
521
|
+
elsif info[ :chunks ].any?
|
522
|
+
path = File.join( @p1_chunk_dir, info[ :chunks ].shift )
|
523
|
+
|
524
|
+
begin
|
525
|
+
data = IO.binread( path )
|
526
|
+
File.delete( path )
|
527
|
+
rescue Errno::ENOENT
|
528
|
+
add_closing( p1 )
|
529
|
+
return
|
530
|
+
end
|
531
|
+
|
532
|
+
caches = []
|
533
|
+
|
534
|
+
until data.empty?
|
535
|
+
shadow_id, pack_size = data[ 0, 10 ].unpack( 'Q>n' )
|
536
|
+
caches << [ shadow_id, data[ 10, pack_size ] ]
|
537
|
+
data = data[ ( 10 + pack_size )..-1 ]
|
538
|
+
end
|
539
|
+
|
540
|
+
shadow_id, data = caches.shift
|
541
|
+
info[ :caches ] = caches
|
542
|
+
elsif info[ :wbuffs ].any?
|
543
|
+
shadow_id, data = info[ :wbuffs ].shift
|
544
|
+
else
|
545
|
+
@writes.delete( p1 )
|
546
|
+
return
|
547
|
+
end
|
548
|
+
|
549
|
+
ext = info[ :shadow_exts ][ shadow_id ]
|
550
|
+
|
551
|
+
if ext
|
552
|
+
pack_id = ext[ :biggest_pack_id ] + 1
|
553
|
+
|
554
|
+
if pack_id == 1
|
555
|
+
data = @hex.encode( data )
|
556
|
+
end
|
557
|
+
|
558
|
+
pack = "#{ [ shadow_id, pack_id ].pack( 'Q>Q>' ) }#{ data }"
|
559
|
+
send_pack( p1, pack, info[ :p2_addr ] )
|
560
|
+
ext[ :biggest_pack_id ] = pack_id
|
561
|
+
ext[ :wmems ][ pack_id ] = pack
|
562
|
+
ext[ :send_ats ][ pack_id ] = now
|
563
|
+
ext[ :last_traffic_at ] = now
|
564
|
+
end
|
565
|
+
end
|
566
|
+
|
567
|
+
def new_p1
|
568
|
+
p1 = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
|
569
|
+
p1.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
|
570
|
+
p1.bind( Socket.sockaddr_in( 0, '0.0.0.0' ) )
|
571
|
+
|
572
|
+
p1_info = {
|
573
|
+
wbuffs: [], # 写前缓存 [ shadow_id, data ]
|
574
|
+
caches: [], # 块读出缓存 [ shadow_id, data ]
|
575
|
+
chunks: [], # 块队列 filename
|
576
|
+
spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
|
577
|
+
p2_addr: nil, # 远端地址
|
578
|
+
app_ids: {}, # app_id => shadow_id
|
579
|
+
shadows: [], # 开着的shadow
|
580
|
+
shadow_exts: {}, # 传输相关 shadow_id => {}
|
581
|
+
fin1s: [], # fin1: shadow已关闭,等待对面收完流量 shadow_id
|
582
|
+
fin2s: [], # fin2: 流量已收完 shadow_id
|
583
|
+
last_coming_at: nil, # 上一次来流量的时间
|
584
|
+
paused: false, # 是否暂停写
|
585
|
+
resendings: [] # 重传队列 [ shadow_id, pack_id ]
|
586
|
+
}
|
587
|
+
|
588
|
+
@p1 = p1
|
589
|
+
@p1_info = p1_info
|
590
|
+
@socks[ p1.object_id ] = p1
|
591
|
+
@roles[ p1 ] = :p1
|
592
|
+
@infos[ p1 ] = p1_info
|
593
|
+
|
594
|
+
send_pack( p1, @title, @p2pd_sockaddr )
|
595
|
+
add_read( p1 )
|
596
|
+
loop_expire( p1 )
|
597
|
+
end
|
598
|
+
|
599
|
+
def loop_expire( p1 )
|
600
|
+
Thread.new do
|
601
|
+
loop do
|
602
|
+
sleep 30
|
603
|
+
|
604
|
+
break if p1.closed?
|
605
|
+
|
606
|
+
p1_info = @infos[ p1 ]
|
607
|
+
|
608
|
+
if p1_info[ :p2_addr ].nil? || ( Time.new - p1_info[ :last_coming_at ] > EXPIRE_AFTER )
|
609
|
+
@mutex.synchronize do
|
610
|
+
puts "expire p1 #{ p1.object_id } #{ Time.new }"
|
611
|
+
@ctlw.write( [ CTL_CLOSE_SOCK, [ p1.object_id ].pack( 'Q>' ) ].join )
|
612
|
+
end
|
613
|
+
else
|
614
|
+
ctlmsg = [ 0, HEARTBEAT, rand( 128 ) ].pack( 'Q>CC' )
|
615
|
+
send_pack( p1, ctlmsg, p1_info[ :p2_addr ] )
|
616
|
+
end
|
617
|
+
end
|
618
|
+
end
|
619
|
+
end
|
620
|
+
|
621
|
+
def loop_send_status( p1 )
|
622
|
+
Thread.new do
|
623
|
+
loop do
|
624
|
+
sleep STATUS_INTERVAL
|
625
|
+
|
626
|
+
if p1.closed?
|
627
|
+
# puts "debug p1 is closed, break send status loop #{ Time.new }"
|
628
|
+
break
|
629
|
+
end
|
630
|
+
|
631
|
+
p1_info = @infos[ p1 ]
|
632
|
+
|
633
|
+
if p1_info[ :shadow_exts ].any?
|
634
|
+
@mutex.synchronize do
|
635
|
+
now = Time.new
|
636
|
+
|
637
|
+
p1_info[ :shadow_exts ].each do | shadow_id, ext |
|
638
|
+
if ext[ :last_traffic_at ] && ( now - ext[ :last_traffic_at ] < SEND_STATUS_UNTIL )
|
639
|
+
ctlmsg = [
|
640
|
+
0,
|
641
|
+
SHADOW_STATUS,
|
642
|
+
shadow_id,
|
643
|
+
ext[ :biggest_pack_id ],
|
644
|
+
ext[ :continue_app_pack_id ]
|
645
|
+
].pack( 'Q>CQ>Q>Q>' )
|
646
|
+
|
647
|
+
send_pack( p1, ctlmsg, p1_info[ :p2_addr ] )
|
648
|
+
end
|
649
|
+
end
|
650
|
+
end
|
651
|
+
end
|
652
|
+
|
653
|
+
if p1_info[ :paused ] && ( p1_info[ :shadow_exts ].map{ | _, ext | ext[ :wmems ].size }.sum < RESUME_BELOW )
|
654
|
+
@mutex.synchronize do
|
655
|
+
@ctlw.write( [ CTL_RESUME, [ p1.object_id ].pack( 'Q>' ) ].join )
|
656
|
+
p1_info[ :paused ] = false
|
657
|
+
end
|
658
|
+
end
|
659
|
+
end
|
660
|
+
end
|
661
|
+
end
|
662
|
+
|
663
|
+
def loop_send_fin1( p1, shadow_id )
|
664
|
+
Thread.new do
|
665
|
+
100.times do
|
666
|
+
break if p1.closed?
|
667
|
+
|
668
|
+
p1_info = @infos[ p1 ]
|
669
|
+
|
670
|
+
unless p1_info[ :fin1s ].include?( shadow_id )
|
671
|
+
# puts "debug break send fin1 loop #{ Time.new }"
|
672
|
+
break
|
673
|
+
end
|
674
|
+
|
675
|
+
@mutex.synchronize do
|
676
|
+
ctlmsg = [
|
677
|
+
0,
|
678
|
+
FIN1,
|
679
|
+
shadow_id
|
680
|
+
].pack( 'Q>CQ>' )
|
681
|
+
|
682
|
+
# puts "debug send FIN1 #{ shadow_id } #{ Time.new }"
|
683
|
+
send_pack( p1, ctlmsg, p1_info[ :p2_addr ] )
|
684
|
+
end
|
685
|
+
|
686
|
+
sleep 1
|
687
|
+
end
|
688
|
+
end
|
689
|
+
end
|
690
|
+
|
691
|
+
def loop_send_fin2( p1, shadow_id )
|
692
|
+
Thread.new do
|
693
|
+
100.times do
|
694
|
+
break if p1.closed?
|
695
|
+
|
696
|
+
p1_info = @infos[ p1 ]
|
697
|
+
|
698
|
+
unless p1_info[ :fin2s ].include?( shadow_id )
|
699
|
+
# puts "debug break send fin2 loop #{ Time.new }"
|
700
|
+
break
|
701
|
+
end
|
702
|
+
|
703
|
+
@mutex.synchronize do
|
704
|
+
ctlmsg = [
|
705
|
+
0,
|
706
|
+
FIN2,
|
707
|
+
shadow_id
|
708
|
+
].pack( 'Q>CQ>' )
|
709
|
+
|
710
|
+
# puts "debug send FIN2 #{ shadow_id } #{ Time.new }"
|
711
|
+
send_pack( p1, ctlmsg, p1_info[ :p2_addr ] )
|
712
|
+
end
|
713
|
+
|
714
|
+
sleep 1
|
715
|
+
end
|
716
|
+
end
|
717
|
+
end
|
718
|
+
|
719
|
+
def send_pack( sock, data, target_sockaddr )
|
720
|
+
begin
|
721
|
+
sock.sendmsg( data, 0, target_sockaddr )
|
722
|
+
rescue IO::WaitWritable, Errno::EINTR => e
|
723
|
+
puts "sendmsg #{ e.class } #{ Time.new }"
|
724
|
+
end
|
725
|
+
end
|
726
|
+
|
727
|
+
def add_read( sock )
|
728
|
+
return if sock.closed? || @reads.include?( sock )
|
729
|
+
|
730
|
+
@reads << sock
|
731
|
+
end
|
732
|
+
|
733
|
+
def add_write( sock, data = nil )
|
734
|
+
return if sock.closed? || @writes.include?( sock )
|
735
|
+
|
736
|
+
@writes << sock
|
737
|
+
end
|
738
|
+
|
739
|
+
def add_closing( sock )
|
740
|
+
return if sock.closed? || @closings.include?( sock )
|
741
|
+
|
742
|
+
@reads.delete( sock )
|
743
|
+
@closings << sock
|
744
|
+
add_write( sock )
|
745
|
+
end
|
746
|
+
|
747
|
+
def close_p1( p1 )
|
748
|
+
info = close_sock( p1 )
|
749
|
+
info[ :shadows ].each { | shadow | add_closing( shadow ) }
|
750
|
+
end
|
751
|
+
|
752
|
+
def close_shadow( shadow )
|
753
|
+
info = close_sock( shadow )
|
754
|
+
p1 = info[ :p1 ]
|
755
|
+
return if p1.closed?
|
756
|
+
|
757
|
+
p1_info = @infos[ p1 ]
|
758
|
+
p1_info[ :shadows ].delete( shadow )
|
759
|
+
shadow_id = shadow.object_id
|
760
|
+
ext = p1_info[ :shadow_exts ][ shadow_id ]
|
761
|
+
return unless ext
|
762
|
+
|
763
|
+
if ext[ :is_app_closed ]
|
764
|
+
# puts "debug 2-3. shadow.close -> ext.is_app_closed ? yes -> del ext -> loop send fin2 #{ Time.new }"
|
765
|
+
p1_info[ :app_ids ].delete( ext[ :app_id ] )
|
766
|
+
p1_info[ :shadow_exts ].delete( shadow_id )
|
767
|
+
|
768
|
+
unless p1_info[ :fin2s ].include?( shadow_id )
|
769
|
+
p1_info[ :fin2s ] << shadow_id
|
770
|
+
loop_send_fin2( p1, shadow_id )
|
771
|
+
end
|
772
|
+
else
|
773
|
+
# puts "debug 1-1. shadow.close -> ext.is_app_closed ? no -> send fin1 loop #{ Time.new }"
|
774
|
+
|
775
|
+
if p1_info[ :p2_addr ] && !p1_info[ :fin1s ].include?( shadow_id )
|
776
|
+
p1_info[ :fin1s ] << shadow_id
|
777
|
+
loop_send_fin1( p1, shadow_id )
|
778
|
+
end
|
779
|
+
end
|
780
|
+
end
|
781
|
+
|
782
|
+
def close_sock( sock )
|
783
|
+
sock.close
|
784
|
+
@reads.delete( sock )
|
785
|
+
@writes.delete( sock )
|
786
|
+
@closings.delete( sock )
|
787
|
+
@socks.delete( sock.object_id )
|
788
|
+
role = @roles.delete( sock )
|
789
|
+
info = @infos.delete( sock )
|
790
|
+
|
791
|
+
if info
|
792
|
+
chunk_dir = ( role == :shadow ? @shadow_chunk_dir : @p1_chunk_dir )
|
793
|
+
|
794
|
+
info[ :chunks ].each do | filename |
|
795
|
+
begin
|
796
|
+
File.delete( File.join( chunk_dir, filename ) )
|
797
|
+
rescue Errno::ENOENT
|
798
|
+
end
|
799
|
+
end
|
800
|
+
end
|
801
|
+
|
802
|
+
info
|
803
|
+
end
|
804
|
+
|
805
|
+
end
|
806
|
+
end
|