p2p2 0.22.0 → 0.27.0

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