p2p2 0.14.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/p2p2.rb +3 -3
- data/lib/p2p2/{hex.rb → custom.rb} +2 -5
- data/lib/p2p2/head.rb +28 -26
- data/lib/p2p2/p1.rb +114 -945
- data/lib/p2p2/p1_custom.rb +7 -0
- data/lib/p2p2/p1_worker.rb +924 -0
- data/lib/p2p2/p2.rb +114 -1013
- data/lib/p2p2/p2_custom.rb +7 -0
- data/lib/p2p2/p2_worker.rb +963 -0
- data/lib/p2p2/p2pd.rb +120 -135
- data/lib/p2p2/p2pd_worker.rb +78 -0
- data/lib/p2p2/version.rb +3 -3
- data/p2p2.gemspec +34 -29
- metadata +10 -4
@@ -0,0 +1,963 @@
|
|
1
|
+
module P2p2
|
2
|
+
class P2Worker
|
3
|
+
|
4
|
+
##
|
5
|
+
# initialize
|
6
|
+
#
|
7
|
+
def initialize( p2pd_host, p2pd_port, room, sdwd_host, sdwd_port, src_chunk_dir, tun_chunk_dir )
|
8
|
+
@p2pd_addr = Socket.sockaddr_in( p2pd_port, p2pd_host )
|
9
|
+
@room = room
|
10
|
+
@sdwd_addr = Socket.sockaddr_in( sdwd_port, sdwd_host )
|
11
|
+
@src_chunk_dir = src_chunk_dir
|
12
|
+
@tun_chunk_dir = tun_chunk_dir
|
13
|
+
@custom = P2p2::P2Custom.new
|
14
|
+
@mutex = Mutex.new
|
15
|
+
@reads = []
|
16
|
+
@writes = []
|
17
|
+
@roles = {} # sock => :dotr / :sdwd / :src / :tun
|
18
|
+
@src_infos = {} # src => {}
|
19
|
+
|
20
|
+
dotr, dotw = IO.pipe
|
21
|
+
@dotw = dotw
|
22
|
+
add_read( dotr, :dotr )
|
23
|
+
new_a_sdwd
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# looping
|
28
|
+
#
|
29
|
+
def looping
|
30
|
+
puts "#{ Time.new } looping"
|
31
|
+
loop_check_expire
|
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 :src
|
42
|
+
write_src( sock )
|
43
|
+
when :tun
|
44
|
+
write_tun( sock )
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
rs.each do | sock |
|
49
|
+
case @roles[ sock ]
|
50
|
+
when :dotr
|
51
|
+
read_dotr( sock )
|
52
|
+
when :sdwd
|
53
|
+
read_sdwd( sock )
|
54
|
+
when :src
|
55
|
+
read_src( sock )
|
56
|
+
when :tun
|
57
|
+
read_tun( sock )
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
rescue Interrupt => e
|
63
|
+
puts e.class
|
64
|
+
quit!
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# quit!
|
69
|
+
#
|
70
|
+
def quit!
|
71
|
+
if @tun && !@tun.closed? && @tun_info[ :tund_addr ]
|
72
|
+
# puts "debug1 send tun fin"
|
73
|
+
data = [ 0, TUN_FIN ].pack( 'Q>C' )
|
74
|
+
@tun.sendmsg( data, 0, @tun_info[ :tund_addr ] )
|
75
|
+
end
|
76
|
+
|
77
|
+
# puts "debug1 exit"
|
78
|
+
exit
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
##
|
84
|
+
# loop check expire
|
85
|
+
#
|
86
|
+
def loop_check_expire
|
87
|
+
Thread.new do
|
88
|
+
loop do
|
89
|
+
sleep CHECK_EXPIRE_INTERVAL
|
90
|
+
|
91
|
+
@mutex.synchronize do
|
92
|
+
need_trigger = false
|
93
|
+
now = Time.new
|
94
|
+
|
95
|
+
if @tun && !@tun.closed? && @tun_info[ :tund_addr ]
|
96
|
+
if now - @tun_info[ :last_recv_at ] > EXPIRE_AFTER
|
97
|
+
puts "#{ Time.new } expire tun"
|
98
|
+
set_is_closing( @tun )
|
99
|
+
else
|
100
|
+
# puts "debug1 #{ Time.new } heartbeat"
|
101
|
+
add_tun_ctlmsg( pack_a_heartbeat )
|
102
|
+
|
103
|
+
@tun_info[ :src_exts ].each do | src_id, src_ext |
|
104
|
+
if src_ext[ :src ].closed? && ( now - src_ext[ :last_continue_at ] > EXPIRE_AFTER )
|
105
|
+
puts "#{ Time.new } expire src ext #{ src_id }"
|
106
|
+
del_src_ext( src_id )
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
need_trigger = true
|
112
|
+
end
|
113
|
+
|
114
|
+
@src_infos.each do | src, src_info |
|
115
|
+
is_expired = src_info[ :last_recv_at ].nil? && ( now - src_info[ :created_at ] > EXPIRE_NEW )
|
116
|
+
|
117
|
+
if is_expired
|
118
|
+
puts "#{ Time.new } expire src"
|
119
|
+
set_is_closing( src )
|
120
|
+
need_trigger = true
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
if need_trigger
|
125
|
+
next_tick
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
##
|
133
|
+
# loop check status
|
134
|
+
#
|
135
|
+
def loop_check_status
|
136
|
+
Thread.new do
|
137
|
+
loop do
|
138
|
+
sleep STATUS_INTERVAL
|
139
|
+
|
140
|
+
@mutex.synchronize do
|
141
|
+
if @tun && !@tun.closed? && @tun_info[ :tund_addr ]
|
142
|
+
need_trigger = false
|
143
|
+
|
144
|
+
if @tun_info[ :src_exts ].any?
|
145
|
+
now = Time.new
|
146
|
+
|
147
|
+
@tun_info[ :src_exts ].each do | src_id, src_ext |
|
148
|
+
if now - src_ext[ :last_continue_at ] < SEND_STATUS_UNTIL
|
149
|
+
data = [ 0, SOURCE_STATUS, src_id, src_ext[ :relay_pack_id ], src_ext[ :continue_dst_pack_id ] ].pack( 'Q>CQ>Q>Q>' )
|
150
|
+
add_tun_ctlmsg( data )
|
151
|
+
need_trigger = true
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
if @tun_info[ :paused ] && ( @tun_info[ :src_exts ].map{ | _, src_ext | src_ext[ :wmems ].size }.sum < RESUME_BELOW )
|
157
|
+
puts "#{ Time.new } resume tun"
|
158
|
+
@tun_info[ :paused ] = false
|
159
|
+
add_write( @tun )
|
160
|
+
need_trigger = true
|
161
|
+
end
|
162
|
+
|
163
|
+
if need_trigger
|
164
|
+
next_tick
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
##
|
173
|
+
# loop punch peer
|
174
|
+
#
|
175
|
+
def loop_punch_peer
|
176
|
+
Thread.new do
|
177
|
+
EXPIRE_NEW.times do
|
178
|
+
if @tun.closed?
|
179
|
+
# puts "debug1 break loop punch peer"
|
180
|
+
break
|
181
|
+
end
|
182
|
+
|
183
|
+
@mutex.synchronize do
|
184
|
+
# puts "debug1 punch peer"
|
185
|
+
add_tun_ctlmsg( pack_a_heartbeat, @tun_info[ :peer_addr ] )
|
186
|
+
next_tick
|
187
|
+
end
|
188
|
+
|
189
|
+
sleep 1
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
##
|
195
|
+
# loop send a new source
|
196
|
+
#
|
197
|
+
def loop_send_a_new_source( src_ext, data )
|
198
|
+
Thread.new do
|
199
|
+
EXPIRE_NEW.times do
|
200
|
+
if src_ext[ :src ].closed? || src_ext[ :dst_port ]
|
201
|
+
# puts "debug1 break loop send a new source #{ src_ext[ :dst_port ] }"
|
202
|
+
break
|
203
|
+
end
|
204
|
+
|
205
|
+
@mutex.synchronize do
|
206
|
+
# puts "debug1 send a new source #{ data.inspect }"
|
207
|
+
add_tun_ctlmsg( data )
|
208
|
+
next_tick
|
209
|
+
end
|
210
|
+
|
211
|
+
sleep 1
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
##
|
217
|
+
# new a sdwd
|
218
|
+
#
|
219
|
+
def new_a_sdwd
|
220
|
+
sdwd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
|
221
|
+
sdwd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
|
222
|
+
|
223
|
+
if RUBY_PLATFORM.include?( 'linux' )
|
224
|
+
sdwd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 )
|
225
|
+
sdwd.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 )
|
226
|
+
end
|
227
|
+
|
228
|
+
sdwd.bind( @sdwd_addr )
|
229
|
+
sdwd.listen( 511 )
|
230
|
+
puts "#{ Time.new } sdwd listen on #{ sdwd.local_address.ip_port }"
|
231
|
+
add_read( sdwd, :sdwd )
|
232
|
+
end
|
233
|
+
|
234
|
+
##
|
235
|
+
# new a tun
|
236
|
+
#
|
237
|
+
def new_a_tun
|
238
|
+
tun = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
|
239
|
+
tun.bind( Socket.sockaddr_in( 0, '0.0.0.0' ) )
|
240
|
+
port = tun.local_address.ip_port
|
241
|
+
puts "#{ Time.new } tun bind on #{ port }"
|
242
|
+
|
243
|
+
tun_info = {
|
244
|
+
port: port, # 端口
|
245
|
+
ctlmsgs: [], # [ to_addr, data ]
|
246
|
+
wbuffs: [], # 写前缓存 [ src_id, pack_id, data ]
|
247
|
+
caches: [], # 块读出缓存 [ src_id, pack_id, data ]
|
248
|
+
chunks: [], # 块队列 filename
|
249
|
+
spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
|
250
|
+
peer_addr: nil, # 对面地址
|
251
|
+
tund_addr: nil, # 连通后的tund地址
|
252
|
+
src_exts: {}, # src额外信息 src_id => {}
|
253
|
+
src_ids: {}, # dst_port => src_id
|
254
|
+
paused: false, # 是否暂停写
|
255
|
+
resendings: [], # 重传队列 [ src_id, pack_id ]
|
256
|
+
created_at: Time.new, # 创建时间
|
257
|
+
last_recv_at: nil, # 上一次收到流量的时间,过期关闭
|
258
|
+
is_closing: false # 是否准备关闭
|
259
|
+
}
|
260
|
+
|
261
|
+
@tun = tun
|
262
|
+
@tun_info = tun_info
|
263
|
+
add_read( tun, :tun )
|
264
|
+
add_tun_ctlmsg( @room, @p2pd_addr )
|
265
|
+
end
|
266
|
+
|
267
|
+
##
|
268
|
+
# pack a heartbeat
|
269
|
+
#
|
270
|
+
def pack_a_heartbeat
|
271
|
+
[ 0, HEARTBEAT, rand( 128 ) ].pack( 'Q>CC' )
|
272
|
+
end
|
273
|
+
|
274
|
+
##
|
275
|
+
# is match tund addr
|
276
|
+
#
|
277
|
+
def is_match_tund_addr( addrinfo )
|
278
|
+
from_addr = addrinfo.to_sockaddr
|
279
|
+
|
280
|
+
if from_addr != @tun_info[ :tund_addr ]
|
281
|
+
puts "#{ Time.new } #{ addrinfo.inspect } not match #{ Addrinfo.new( @tun_info[ :tund_addr ] ).inspect }"
|
282
|
+
return false
|
283
|
+
end
|
284
|
+
|
285
|
+
@tun_info[ :last_recv_at ] = Time.new
|
286
|
+
true
|
287
|
+
end
|
288
|
+
|
289
|
+
##
|
290
|
+
# add tun ctlmsg
|
291
|
+
#
|
292
|
+
def add_tun_ctlmsg( data, to_addr = nil )
|
293
|
+
unless to_addr
|
294
|
+
to_addr = @tun_info[ :tund_addr ]
|
295
|
+
end
|
296
|
+
|
297
|
+
if to_addr
|
298
|
+
@tun_info[ :ctlmsgs ] << [ to_addr, data ]
|
299
|
+
add_write( @tun )
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
##
|
304
|
+
# add tun wbuff
|
305
|
+
#
|
306
|
+
def add_tun_wbuff( src_id, pack_id, data )
|
307
|
+
@tun_info[ :wbuffs ] << [ src_id, pack_id, data ]
|
308
|
+
|
309
|
+
if @tun_info[ :wbuffs ].size >= WBUFFS_LIMIT
|
310
|
+
spring = @tun_info[ :chunks ].size > 0 ? ( @tun_info[ :spring ] + 1 ) : 0
|
311
|
+
filename = "#{ Process.pid }-#{ @tun_info[ :port ] }.#{ spring }"
|
312
|
+
chunk_path = File.join( @tun_chunk_dir, filename )
|
313
|
+
datas = @tun_info[ :wbuffs ].map{ | _src_id, _pack_id, _data | [ [ _src_id, _pack_id, _data.bytesize ].pack( 'Q>Q>n' ), _data ].join }
|
314
|
+
|
315
|
+
begin
|
316
|
+
IO.binwrite( chunk_path, datas.join )
|
317
|
+
rescue Errno::ENOSPC => e
|
318
|
+
puts "#{ Time.new } #{ e.class }, close tun"
|
319
|
+
set_is_closing( @tun )
|
320
|
+
return
|
321
|
+
end
|
322
|
+
|
323
|
+
@tun_info[ :chunks ] << filename
|
324
|
+
@tun_info[ :spring ] = spring
|
325
|
+
@tun_info[ :wbuffs ].clear
|
326
|
+
end
|
327
|
+
|
328
|
+
add_write( @tun )
|
329
|
+
end
|
330
|
+
|
331
|
+
##
|
332
|
+
# add src wbuff
|
333
|
+
#
|
334
|
+
def add_src_wbuff( src, data )
|
335
|
+
src_info = @src_infos[ src ]
|
336
|
+
src_info[ :wbuff ] << data
|
337
|
+
|
338
|
+
if src_info[ :wbuff ].bytesize >= CHUNK_SIZE
|
339
|
+
spring = src_info[ :chunks ].size > 0 ? ( src_info[ :spring ] + 1 ) : 0
|
340
|
+
filename = "#{ Process.pid }-#{ src_info[ :id ] }.#{ spring }"
|
341
|
+
chunk_path = File.join( @src_chunk_dir, filename )
|
342
|
+
|
343
|
+
begin
|
344
|
+
IO.binwrite( chunk_path, src_info[ :wbuff ] )
|
345
|
+
rescue Errno::ENOSPC => e
|
346
|
+
puts "#{ Time.new } #{ e.class }, close src"
|
347
|
+
set_is_closing( src )
|
348
|
+
return
|
349
|
+
end
|
350
|
+
|
351
|
+
src_info[ :chunks ] << filename
|
352
|
+
src_info[ :spring ] = spring
|
353
|
+
src_info[ :wbuff ].clear
|
354
|
+
end
|
355
|
+
|
356
|
+
add_write( src )
|
357
|
+
end
|
358
|
+
|
359
|
+
##
|
360
|
+
# add read
|
361
|
+
#
|
362
|
+
def add_read( sock, role )
|
363
|
+
unless @reads.include?( sock )
|
364
|
+
@reads << sock
|
365
|
+
end
|
366
|
+
|
367
|
+
@roles[ sock ] = role
|
368
|
+
end
|
369
|
+
|
370
|
+
##
|
371
|
+
# add write
|
372
|
+
#
|
373
|
+
def add_write( sock )
|
374
|
+
if sock && !sock.closed? && !@writes.include?( sock )
|
375
|
+
@writes << sock
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
##
|
380
|
+
# set is closing
|
381
|
+
#
|
382
|
+
def set_is_closing( sock )
|
383
|
+
if sock && !sock.closed?
|
384
|
+
role = @roles[ sock ]
|
385
|
+
# puts "debug1 set #{ role.to_s } is closing"
|
386
|
+
|
387
|
+
case role
|
388
|
+
when :src
|
389
|
+
src_info = @src_infos[ sock ]
|
390
|
+
src_info[ :is_closing ] = true
|
391
|
+
when :tun
|
392
|
+
@tun_info[ :is_closing ] = true
|
393
|
+
end
|
394
|
+
|
395
|
+
@reads.delete( sock )
|
396
|
+
add_write( sock )
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
##
|
401
|
+
# close src
|
402
|
+
#
|
403
|
+
def close_src( src )
|
404
|
+
# puts "debug1 close src"
|
405
|
+
close_sock( src )
|
406
|
+
src_info = @src_infos.delete( src )
|
407
|
+
|
408
|
+
src_info[ :chunks ].each do | filename |
|
409
|
+
begin
|
410
|
+
File.delete( File.join( @src_chunk_dir, filename ) )
|
411
|
+
rescue Errno::ENOENT
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
return if @tun.closed?
|
416
|
+
|
417
|
+
src_id = src_info[ :id ]
|
418
|
+
src_ext = @tun_info[ :src_exts ][ src_id ]
|
419
|
+
return unless src_ext
|
420
|
+
|
421
|
+
if src_ext[ :is_dst_closed ]
|
422
|
+
# puts "debug1 2-3. after close src -> dst closed ? yes -> del src ext -> send fin2"
|
423
|
+
del_src_ext( src_id )
|
424
|
+
data = [ 0, FIN2, src_id ].pack( 'Q>CQ>' )
|
425
|
+
add_tun_ctlmsg( data )
|
426
|
+
else
|
427
|
+
# puts "debug1 1-1. after close src -> dst closed ? no -> send fin1"
|
428
|
+
data = [ 0, FIN1, src_id, src_info[ :biggest_pack_id ], src_ext[ :continue_dst_pack_id ] ].pack( 'Q>CQ>Q>Q>' )
|
429
|
+
add_tun_ctlmsg( data )
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
##
|
434
|
+
# close tun
|
435
|
+
#
|
436
|
+
def close_tun( tun )
|
437
|
+
# puts "debug1 close tun"
|
438
|
+
close_sock( tun )
|
439
|
+
|
440
|
+
@tun_info[ :chunks ].each do | filename |
|
441
|
+
begin
|
442
|
+
File.delete( File.join( @tun_chunk_dir, filename ) )
|
443
|
+
rescue Errno::ENOENT
|
444
|
+
end
|
445
|
+
end
|
446
|
+
|
447
|
+
@tun_info[ :src_exts ].each{ | _, src_ext | set_is_closing( src_ext[ :src ] ) }
|
448
|
+
end
|
449
|
+
|
450
|
+
##
|
451
|
+
# close sock
|
452
|
+
#
|
453
|
+
def close_sock( sock )
|
454
|
+
sock.close
|
455
|
+
@reads.delete( sock )
|
456
|
+
@writes.delete( sock )
|
457
|
+
@roles.delete( sock )
|
458
|
+
end
|
459
|
+
|
460
|
+
##
|
461
|
+
# del src ext
|
462
|
+
#
|
463
|
+
def del_src_ext( src_id )
|
464
|
+
src_ext = @tun_info[ :src_exts ].delete( src_id )
|
465
|
+
|
466
|
+
if src_ext
|
467
|
+
@tun_info[ :src_ids ].delete( src_ext[ :dst_port ] )
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
##
|
472
|
+
# release wmems
|
473
|
+
#
|
474
|
+
def release_wmems( src_ext, completed_pack_id )
|
475
|
+
if completed_pack_id > src_ext[ :completed_pack_id ]
|
476
|
+
# puts "debug2 update completed pack #{ completed_pack_id }"
|
477
|
+
|
478
|
+
pack_ids = src_ext[ :wmems ].keys.select { | pack_id | pack_id <= completed_pack_id }
|
479
|
+
|
480
|
+
pack_ids.each do | pack_id |
|
481
|
+
src_ext[ :wmems ].delete( pack_id )
|
482
|
+
src_ext[ :send_ats ].delete( pack_id )
|
483
|
+
end
|
484
|
+
|
485
|
+
src_ext[ :completed_pack_id ] = completed_pack_id
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
##
|
490
|
+
# next tick
|
491
|
+
#
|
492
|
+
def next_tick
|
493
|
+
@dotw.write( '.' )
|
494
|
+
end
|
495
|
+
|
496
|
+
##
|
497
|
+
# write src
|
498
|
+
#
|
499
|
+
def write_src( src )
|
500
|
+
src_info = @src_infos[ src ]
|
501
|
+
data = src_info[ :cache ]
|
502
|
+
from = :cache
|
503
|
+
|
504
|
+
if data.empty?
|
505
|
+
if src_info[ :chunks ].any?
|
506
|
+
path = File.join( @src_chunk_dir, src_info[ :chunks ].shift )
|
507
|
+
|
508
|
+
begin
|
509
|
+
src_info[ :cache ] = data = IO.binread( path )
|
510
|
+
File.delete( path )
|
511
|
+
rescue Errno::ENOENT => e
|
512
|
+
puts "#{ Time.new } read #{ path } #{ e.class }"
|
513
|
+
close_src( src )
|
514
|
+
return
|
515
|
+
end
|
516
|
+
else
|
517
|
+
data = src_info[ :wbuff ]
|
518
|
+
from = :wbuff
|
519
|
+
end
|
520
|
+
end
|
521
|
+
|
522
|
+
if data.empty?
|
523
|
+
if src_info[ :is_closing ]
|
524
|
+
close_src( src )
|
525
|
+
else
|
526
|
+
@writes.delete( src )
|
527
|
+
end
|
528
|
+
|
529
|
+
return
|
530
|
+
end
|
531
|
+
|
532
|
+
begin
|
533
|
+
written = src.write_nonblock( data )
|
534
|
+
rescue IO::WaitWritable, Errno::EINTR
|
535
|
+
return
|
536
|
+
rescue Exception => e
|
537
|
+
close_src( src )
|
538
|
+
return
|
539
|
+
end
|
540
|
+
|
541
|
+
# puts "debug2 write src #{ written }"
|
542
|
+
data = data[ written..-1 ]
|
543
|
+
src_info[ from ] = data
|
544
|
+
end
|
545
|
+
|
546
|
+
##
|
547
|
+
# write tun
|
548
|
+
#
|
549
|
+
def write_tun( tun )
|
550
|
+
if @tun_info[ :is_closing ]
|
551
|
+
close_tun( tun )
|
552
|
+
return
|
553
|
+
end
|
554
|
+
|
555
|
+
# 传ctlmsg
|
556
|
+
while @tun_info[ :ctlmsgs ].any?
|
557
|
+
to_addr, data = @tun_info[ :ctlmsgs ].first
|
558
|
+
|
559
|
+
begin
|
560
|
+
tun.sendmsg( data, 0, to_addr )
|
561
|
+
rescue IO::WaitWritable, Errno::EINTR
|
562
|
+
return
|
563
|
+
end
|
564
|
+
|
565
|
+
@tun_info[ :ctlmsgs ].shift
|
566
|
+
end
|
567
|
+
|
568
|
+
# 重传
|
569
|
+
while @tun_info[ :resendings ].any?
|
570
|
+
src_id, pack_id = @tun_info[ :resendings ].first
|
571
|
+
src_ext = @tun_info[ :src_exts ][ src_id ]
|
572
|
+
|
573
|
+
if src_ext
|
574
|
+
data = src_ext[ :wmems ][ pack_id ]
|
575
|
+
|
576
|
+
if data
|
577
|
+
begin
|
578
|
+
tun.sendmsg( data, 0, @tun_info[ :tund_addr ] )
|
579
|
+
rescue IO::WaitWritable, Errno::EINTR
|
580
|
+
return
|
581
|
+
end
|
582
|
+
end
|
583
|
+
end
|
584
|
+
|
585
|
+
@tun_info[ :resendings ].shift
|
586
|
+
return
|
587
|
+
end
|
588
|
+
|
589
|
+
# 若写后达到上限,暂停取写前
|
590
|
+
if @tun_info[ :src_exts ].map{ | _, src_ext | src_ext[ :wmems ].size }.sum >= WMEMS_LIMIT
|
591
|
+
unless @tun_info[ :paused ]
|
592
|
+
puts "#{ Time.new } pause tun #{ @tun_info[ :port ] }"
|
593
|
+
@tun_info[ :paused ] = true
|
594
|
+
end
|
595
|
+
|
596
|
+
@writes.delete( tun )
|
597
|
+
return
|
598
|
+
end
|
599
|
+
|
600
|
+
# 取写前
|
601
|
+
if @tun_info[ :caches ].any?
|
602
|
+
src_id, pack_id, data = @tun_info[ :caches ].first
|
603
|
+
from = :caches
|
604
|
+
elsif @tun_info[ :chunks ].any?
|
605
|
+
path = File.join( @tun_chunk_dir, @tun_info[ :chunks ].shift )
|
606
|
+
|
607
|
+
begin
|
608
|
+
data = IO.binread( path )
|
609
|
+
File.delete( path )
|
610
|
+
rescue Errno::ENOENT => e
|
611
|
+
puts "#{ Time.new } read #{ path } #{ e.class }"
|
612
|
+
close_tun( tun )
|
613
|
+
return
|
614
|
+
end
|
615
|
+
|
616
|
+
caches = []
|
617
|
+
|
618
|
+
until data.empty?
|
619
|
+
_src_id, _pack_id, pack_size = data[ 0, 18 ].unpack( 'Q>Q>n' )
|
620
|
+
caches << [ _src_id, _pack_id, data[ 18, pack_size ] ]
|
621
|
+
data = data[ ( 18 + pack_size )..-1 ]
|
622
|
+
end
|
623
|
+
|
624
|
+
@tun_info[ :caches ] = caches
|
625
|
+
src_id, pack_id, data = caches.first
|
626
|
+
from = :caches
|
627
|
+
elsif @tun_info[ :wbuffs ].any?
|
628
|
+
src_id, pack_id, data = @tun_info[ :wbuffs ].first
|
629
|
+
from = :wbuffs
|
630
|
+
else
|
631
|
+
@writes.delete( tun )
|
632
|
+
return
|
633
|
+
end
|
634
|
+
|
635
|
+
src_ext = @tun_info[ :src_exts ][ src_id ]
|
636
|
+
|
637
|
+
if src_ext
|
638
|
+
if pack_id <= CONFUSE_UNTIL
|
639
|
+
data = @custom.encode( data )
|
640
|
+
# puts "debug1 encoded pack #{ pack_id }"
|
641
|
+
end
|
642
|
+
|
643
|
+
data = [ [ pack_id, src_id ].pack( 'Q>Q>' ), data ].join
|
644
|
+
|
645
|
+
begin
|
646
|
+
tun.sendmsg( data, 0, @tun_info[ :tund_addr ] )
|
647
|
+
rescue IO::WaitWritable, Errno::EINTR
|
648
|
+
return
|
649
|
+
end
|
650
|
+
|
651
|
+
# puts "debug2 written pack #{ pack_id }"
|
652
|
+
now = Time.new
|
653
|
+
src_ext[ :relay_pack_id ] = pack_id
|
654
|
+
src_ext[ :wmems ][ pack_id ] = data
|
655
|
+
src_ext[ :send_ats ][ pack_id ] = now
|
656
|
+
src_ext[ :last_continue_at ] = now
|
657
|
+
end
|
658
|
+
|
659
|
+
@tun_info[ from ].shift
|
660
|
+
end
|
661
|
+
|
662
|
+
##
|
663
|
+
# read dotr
|
664
|
+
#
|
665
|
+
def read_dotr( dotr )
|
666
|
+
dotr.read( 1 )
|
667
|
+
end
|
668
|
+
|
669
|
+
##
|
670
|
+
# read sdwd
|
671
|
+
#
|
672
|
+
def read_sdwd( sdwd )
|
673
|
+
begin
|
674
|
+
src, addrinfo = sdwd.accept_nonblock
|
675
|
+
rescue IO::WaitReadable, Errno::EINTR
|
676
|
+
return
|
677
|
+
end
|
678
|
+
|
679
|
+
id = rand( ( 2 ** 64 ) - 1 ) + 1
|
680
|
+
# puts "debug1 accept a src #{ addrinfo.inspect } #{ id }"
|
681
|
+
|
682
|
+
@src_infos[ src ] = {
|
683
|
+
id: id, # id
|
684
|
+
biggest_pack_id: 0, # 最大包号码
|
685
|
+
rbuffs: [], # p1端dst未准备好,暂存流量 [ pack_id, data ]
|
686
|
+
wbuff: '', # 写前
|
687
|
+
cache: '', # 块读出缓存
|
688
|
+
chunks: [], # 块队列,写前达到块大小时结一个块 filename
|
689
|
+
spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
|
690
|
+
created_at: Time.new, # 创建时间
|
691
|
+
last_recv_at: nil, # 上一次收到流量的时间,过期关闭
|
692
|
+
is_closing: false # 是否准备关闭
|
693
|
+
}
|
694
|
+
|
695
|
+
add_read( src, :src )
|
696
|
+
|
697
|
+
if @tun.nil? || @tun.closed?
|
698
|
+
new_a_tun
|
699
|
+
end
|
700
|
+
|
701
|
+
src_ext = {
|
702
|
+
src: src, # src
|
703
|
+
dst_port: nil, # p1端dst端口
|
704
|
+
wmems: {}, # 写后 pack_id => data
|
705
|
+
send_ats: {}, # 上一次发出时间 pack_id => send_at
|
706
|
+
relay_pack_id: 0, # 转发到几
|
707
|
+
continue_dst_pack_id: 0, # 收到几
|
708
|
+
pieces: {}, # 跳号包 dst_pack_id => data
|
709
|
+
is_dst_closed: false, # dst是否已关闭
|
710
|
+
biggest_dst_pack_id: 0, # dst最大包号码
|
711
|
+
completed_pack_id: 0, # 完成到几(对面收到几)
|
712
|
+
last_continue_at: Time.new # 创建,或者上一次收到连续流量,或者发出新包的时间
|
713
|
+
}
|
714
|
+
|
715
|
+
@tun_info[ :src_exts ][ id ] = src_ext
|
716
|
+
data = [ 0, A_NEW_SOURCE, id ].pack( 'Q>CQ>' )
|
717
|
+
loop_send_a_new_source( src_ext, data )
|
718
|
+
end
|
719
|
+
|
720
|
+
##
|
721
|
+
# read src
|
722
|
+
#
|
723
|
+
def read_src( src )
|
724
|
+
begin
|
725
|
+
data = src.read_nonblock( PACK_SIZE )
|
726
|
+
rescue IO::WaitReadable, Errno::EINTR
|
727
|
+
return
|
728
|
+
rescue Exception => e
|
729
|
+
# puts "debug1 read src #{ e.class }"
|
730
|
+
set_is_closing( src )
|
731
|
+
return
|
732
|
+
end
|
733
|
+
|
734
|
+
# puts "debug2 read src #{ data.inspect }"
|
735
|
+
src_info = @src_infos[ src ]
|
736
|
+
src_info[ :last_recv_at ] = Time.new
|
737
|
+
src_id = src_info[ :id ]
|
738
|
+
src_ext = @tun_info[ :src_exts ][ src_id ]
|
739
|
+
|
740
|
+
unless src_ext
|
741
|
+
# puts "debug1 not found src ext"
|
742
|
+
set_is_closing( src )
|
743
|
+
return
|
744
|
+
end
|
745
|
+
|
746
|
+
if @tun.closed?
|
747
|
+
puts "#{ Time.new } tun closed, close src"
|
748
|
+
set_is_closing( src )
|
749
|
+
return
|
750
|
+
end
|
751
|
+
|
752
|
+
pack_id = src_info[ :biggest_pack_id ] + 1
|
753
|
+
src_info[ :biggest_pack_id ] = pack_id
|
754
|
+
|
755
|
+
if src_ext[ :dst_port ]
|
756
|
+
add_tun_wbuff( src_info[ :id ], pack_id, data )
|
757
|
+
else
|
758
|
+
# puts "debug1 p1 dst not ready, save data to src rbuff"
|
759
|
+
src_info[ :rbuffs ] << [ pack_id, data ]
|
760
|
+
end
|
761
|
+
end
|
762
|
+
|
763
|
+
##
|
764
|
+
# read tun
|
765
|
+
#
|
766
|
+
def read_tun( tun )
|
767
|
+
data, addrinfo, rflags, *controls = tun.recvmsg
|
768
|
+
now = Time.new
|
769
|
+
pack_id = data[ 0, 8 ].unpack( 'Q>' ).first
|
770
|
+
|
771
|
+
if pack_id == 0
|
772
|
+
ctl_num = data[ 8 ].unpack( 'C' ).first
|
773
|
+
|
774
|
+
case ctl_num
|
775
|
+
when PEER_ADDR
|
776
|
+
return if @tun_info[ :peer_addr ] || ( addrinfo.to_sockaddr != @p2pd_addr )
|
777
|
+
|
778
|
+
peer_addr = data[ 9..-1 ]
|
779
|
+
puts "#{ Time.new } got peer addr #{ Addrinfo.new( peer_addr ).inspect }"
|
780
|
+
|
781
|
+
@tun_info[ :peer_addr ] = peer_addr
|
782
|
+
loop_punch_peer
|
783
|
+
when HEARTBEAT
|
784
|
+
from_addr = addrinfo.to_sockaddr
|
785
|
+
return if from_addr != @tun_info[ :peer_addr ]
|
786
|
+
|
787
|
+
# puts "debug1 set tun addr #{ Addrinfo.new( from_addr ).inspect }"
|
788
|
+
@tun_info[ :tund_addr ] = from_addr
|
789
|
+
@tun_info[ :last_recv_at ] = now
|
790
|
+
when PAIRED
|
791
|
+
return unless is_match_tund_addr( addrinfo )
|
792
|
+
|
793
|
+
src_id, dst_port = data[ 9, 10 ].unpack( 'Q>n' )
|
794
|
+
|
795
|
+
src_ext = @tun_info[ :src_exts ][ src_id ]
|
796
|
+
return if src_ext.nil? || src_ext[ :dst_port ]
|
797
|
+
|
798
|
+
src = src_ext[ :src ]
|
799
|
+
return if src.closed?
|
800
|
+
|
801
|
+
# puts "debug1 got paired #{ src_id } #{ dst_port }"
|
802
|
+
|
803
|
+
if dst_port == 0
|
804
|
+
set_is_closing( src )
|
805
|
+
return
|
806
|
+
end
|
807
|
+
|
808
|
+
src_ext[ :dst_port ] = dst_port
|
809
|
+
@tun_info[ :src_ids ][ dst_port ] = src_id
|
810
|
+
|
811
|
+
src_info = @src_infos[ src ]
|
812
|
+
|
813
|
+
src_info[ :rbuffs ].each do | _pack_id, _data |
|
814
|
+
add_tun_wbuff( src_id, _pack_id, _data )
|
815
|
+
end
|
816
|
+
when DEST_STATUS
|
817
|
+
return unless is_match_tund_addr( addrinfo )
|
818
|
+
|
819
|
+
dst_port, relay_dst_pack_id, continue_src_pack_id = data[ 9, 18 ].unpack( 'nQ>Q>' )
|
820
|
+
|
821
|
+
src_id = @tun_info[ :src_ids ][ dst_port ]
|
822
|
+
return unless src_id
|
823
|
+
|
824
|
+
src_ext = @tun_info[ :src_exts ][ src_id ]
|
825
|
+
return unless src_ext
|
826
|
+
|
827
|
+
# puts "debug2 got dest status"
|
828
|
+
|
829
|
+
release_wmems( src_ext, continue_src_pack_id )
|
830
|
+
|
831
|
+
# 发miss
|
832
|
+
if !src_ext[ :src ].closed? && ( src_ext[ :continue_dst_pack_id ] < relay_dst_pack_id )
|
833
|
+
ranges = []
|
834
|
+
curr_pack_id = src_ext[ :continue_dst_pack_id ] + 1
|
835
|
+
|
836
|
+
src_ext[ :pieces ].keys.sort.each do | pack_id |
|
837
|
+
if pack_id > curr_pack_id
|
838
|
+
ranges << [ curr_pack_id, pack_id - 1 ]
|
839
|
+
end
|
840
|
+
|
841
|
+
curr_pack_id = pack_id + 1
|
842
|
+
end
|
843
|
+
|
844
|
+
if curr_pack_id <= relay_dst_pack_id
|
845
|
+
ranges << [ curr_pack_id, relay_dst_pack_id ]
|
846
|
+
end
|
847
|
+
|
848
|
+
pack_count = 0
|
849
|
+
# puts "debug1 continue/relay #{ src_ext[ :continue_dst_pack_id ] }/#{ relay_dst_pack_id } send MISS #{ ranges.size }"
|
850
|
+
|
851
|
+
ranges.each do | pack_id_begin, pack_id_end |
|
852
|
+
if pack_count >= BREAK_SEND_MISS
|
853
|
+
puts "#{ Time.new } break send miss at #{ pack_id_begin }"
|
854
|
+
break
|
855
|
+
end
|
856
|
+
|
857
|
+
data2 = [ 0, MISS, dst_port, pack_id_begin, pack_id_end ].pack( 'Q>CnQ>Q>' )
|
858
|
+
add_tun_ctlmsg( data2 )
|
859
|
+
pack_count += ( pack_id_end - pack_id_begin + 1 )
|
860
|
+
end
|
861
|
+
end
|
862
|
+
when MISS
|
863
|
+
return unless is_match_tund_addr( addrinfo )
|
864
|
+
|
865
|
+
src_id, pack_id_begin, pack_id_end = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
|
866
|
+
|
867
|
+
src_ext = @tun_info[ :src_exts ][ src_id ]
|
868
|
+
return unless src_ext
|
869
|
+
|
870
|
+
( pack_id_begin..pack_id_end ).each do | pack_id |
|
871
|
+
send_at = src_ext[ :send_ats ][ pack_id ]
|
872
|
+
|
873
|
+
if send_at
|
874
|
+
break if now - send_at < STATUS_INTERVAL
|
875
|
+
@tun_info[ :resendings ] << [ src_id, pack_id ]
|
876
|
+
end
|
877
|
+
end
|
878
|
+
|
879
|
+
add_write( tun )
|
880
|
+
when FIN1
|
881
|
+
return unless is_match_tund_addr( addrinfo )
|
882
|
+
|
883
|
+
dst_port, biggest_dst_pack_id, continue_src_pack_id = data[ 9, 18 ].unpack( 'nQ>Q>' )
|
884
|
+
|
885
|
+
src_id = @tun_info[ :src_ids ][ dst_port ]
|
886
|
+
return unless src_id
|
887
|
+
|
888
|
+
src_ext = @tun_info[ :src_exts ][ src_id ]
|
889
|
+
return unless src_ext
|
890
|
+
|
891
|
+
# puts "debug1 got fin1 #{ dst_port } biggest dst pack #{ biggest_dst_pack_id } completed src pack #{ continue_src_pack_id }"
|
892
|
+
src_ext[ :is_dst_closed ] = true
|
893
|
+
src_ext[ :biggest_dst_pack_id ] = biggest_dst_pack_id
|
894
|
+
release_wmems( src_ext, continue_src_pack_id )
|
895
|
+
|
896
|
+
if ( biggest_dst_pack_id == src_ext[ :continue_dst_pack_id ] )
|
897
|
+
# puts "debug1 2-1. tun recv fin1 -> all traffic received ? -> close src after write"
|
898
|
+
set_is_closing( src_ext[ :src ] )
|
899
|
+
end
|
900
|
+
when FIN2
|
901
|
+
return unless is_match_tund_addr( addrinfo )
|
902
|
+
|
903
|
+
dst_port = data[ 9, 2 ].unpack( 'n' ).first
|
904
|
+
|
905
|
+
src_id = @tun_info[ :src_ids ][ dst_port ]
|
906
|
+
return unless src_id
|
907
|
+
|
908
|
+
# puts "debug1 1-2. tun recv fin2 -> del src ext"
|
909
|
+
del_src_ext( src_id )
|
910
|
+
when TUND_FIN
|
911
|
+
return unless is_match_tund_addr( addrinfo )
|
912
|
+
|
913
|
+
puts "#{ Time.new } recv tund fin"
|
914
|
+
set_is_closing( tun )
|
915
|
+
end
|
916
|
+
|
917
|
+
return
|
918
|
+
end
|
919
|
+
|
920
|
+
return unless is_match_tund_addr( addrinfo )
|
921
|
+
|
922
|
+
dst_port = data[ 8, 2 ].unpack( 'n' ).first
|
923
|
+
|
924
|
+
src_id = @tun_info[ :src_ids ][ dst_port ]
|
925
|
+
return unless src_id
|
926
|
+
|
927
|
+
src_ext = @tun_info[ :src_exts ][ src_id ]
|
928
|
+
return if src_ext.nil? || src_ext[ :src ].closed?
|
929
|
+
return if ( pack_id <= src_ext[ :continue_dst_pack_id ] ) || src_ext[ :pieces ].include?( pack_id )
|
930
|
+
|
931
|
+
data = data[ 10..-1 ]
|
932
|
+
# puts "debug2 got pack #{ pack_id }"
|
933
|
+
|
934
|
+
if pack_id <= CONFUSE_UNTIL
|
935
|
+
# puts "debug2 #{ data.inspect }"
|
936
|
+
data = @custom.decode( data )
|
937
|
+
# puts "debug1 decoded pack #{ pack_id }"
|
938
|
+
end
|
939
|
+
|
940
|
+
# 放进写前,跳号放碎片缓存
|
941
|
+
if pack_id - src_ext[ :continue_dst_pack_id ] == 1
|
942
|
+
while src_ext[ :pieces ].include?( pack_id + 1 )
|
943
|
+
data << src_ext[ :pieces ].delete( pack_id + 1 )
|
944
|
+
pack_id += 1
|
945
|
+
end
|
946
|
+
|
947
|
+
src_ext[ :continue_dst_pack_id ] = pack_id
|
948
|
+
src_ext[ :last_continue_at ] = now
|
949
|
+
add_src_wbuff( src_ext[ :src ], data )
|
950
|
+
# puts "debug2 update continue dst pack #{ pack_id }"
|
951
|
+
|
952
|
+
# 接到流量,若对面已关闭,且流量正好收全,关闭src
|
953
|
+
if src_ext[ :is_dst_closed ] && ( pack_id == src_ext[ :biggest_dst_pack_id ] )
|
954
|
+
# puts "debug1 2-2. tun recv traffic -> dst closed and all traffic received ? -> close src after write"
|
955
|
+
set_is_closing( src_ext[ :src ] )
|
956
|
+
end
|
957
|
+
else
|
958
|
+
src_ext[ :pieces ][ pack_id ] = data
|
959
|
+
end
|
960
|
+
end
|
961
|
+
|
962
|
+
end
|
963
|
+
end
|