p2p2 0.14.0 → 0.18.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 68069e5326b6a25498cf1dd4adb8733fe2ec2bf809126f1f500f9cb734d4ea47
4
- data.tar.gz: 61610f3b5e55f3d42df523e154f277e1a22a87dad56b93d220d4f4a39190b36e
3
+ metadata.gz: 69c08f082bef92a9287f03eb20927a2dbb3913f99c3b7bc76ea9db0a088417d8
4
+ data.tar.gz: c9b9f43b4007240b38521e6f2450220b487309b2bace4456ca1ea281acc93193
5
5
  SHA512:
6
- metadata.gz: a5d286c1091dab33efac9d24e9c9535835420922dba75447b38f264bf3d655cbb5fd9d5cf43a90f9af60a9b1fef63a1c47f162a083e0a67227ffafcf815606a8
7
- data.tar.gz: 18bb9e9992555dc486a25d7f81b1d7e63036be78d5c8b849073a1217dbbbe67442f9486ce5984e6a937abcdf208bfce01d46c98b278c74396ae36f9332dc3367
6
+ metadata.gz: 482067dd01dc0996137473e968396d21420f15bcccc2ede0fbf38e45cf55117925d355d5aebe19b8c88a7cd70dc2f08aa43009b48030a981e256ce8e846f10cb
7
+ data.tar.gz: 57a677e430ba6fd813207e10a5bfa769ec922f8f9759562f40468f4eac08f85bea0635672eda75d2e6578937aa96c0fd3ffb43eb61768cf4a3837518c0117f57
@@ -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'
@@ -1,10 +1,7 @@
1
1
  module P2p2
2
- class Hex
3
- def gen_random_num
4
- rand( ( 2 ** 64 ) - 1 ) + 1
5
- end
6
-
2
+ module Custom
7
3
  def encode( data )
4
+ # overwrite me, you'll be free
8
5
  data
9
6
  end
10
7
 
@@ -1,26 +1,28 @@
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
- HEARTBEAT_INTERVAL = 3 # 心跳间隔
9
- STATUS_INTERVAL = 0.3 # 发送状态间隔
10
- SEND_STATUS_UNTIL = 20 # 持续的告之对面状态,直到没有流量往来,持续多少秒
11
- PEER_ADDR = 1
12
- HEARTBEAT = 2
13
- A_NEW_APP = 3
14
- PAIRED = 4
15
- SHADOW_STATUS = 5
16
- APP_STATUS = 6
17
- MISS = 7
18
- FIN1 = 8
19
- GOT_FIN1 = 9
20
- FIN2 = 10
21
- GOT_FIN2 = 11
22
- P1_FIN = 12
23
- P2_FIN = 13
24
- CTL_CLOSE = 1
25
- CTL_RESUME = 2
26
- end
1
+ module P2p2
2
+ PACK_SIZE = 1328 # 包大小 1400(console MTU) - 8(PPPoE header) - 40(IPv6 header) - 8(UDP header) - 8(pack id) - 8(src id) = 1328
3
+ CHUNK_SIZE = PACK_SIZE * 1000 # 块大小
4
+ WBUFFS_LIMIT = 1000 # 写前上限,超过上限结一个块
5
+ WMEMS_LIMIT = 100_000 # 写后上限,达到上限暂停写
6
+ RESUME_BELOW = 50_000 # 降到多少以下恢复写
7
+ EXPIRE_NEW = 10 # 创建之后多久没有流量进来,过期
8
+ EXPIRE_AFTER = 300 # 多久没有新流量,过期
9
+ CHECK_EXPIRE_INTERVAL = 30 # 检查过期间隔
10
+ STATUS_INTERVAL = 0.5 # 发送状态间隔
11
+ SEND_STATUS_UNTIL = 10 # 持续的告之对面状态,直到没有流量往来,持续多少秒
12
+ BREAK_SEND_MISS = 10_000 # miss包个数上限,达到上限忽略要后面的段,可控碎片缓存
13
+ CONFUSE_UNTIL = 5 # 混淆前几个包
14
+ UPDATE_ROOM_INTERVAL = 5 # 刷新房间间隔
15
+ PEER_ADDR = 1
16
+ HEARTBEAT = 2
17
+ A_NEW_SOURCE = 3
18
+ PAIRED = 4
19
+ DEST_STATUS = 5
20
+ SOURCE_STATUS = 6
21
+ MISS = 7
22
+ FIN1 = 8
23
+ GOT_FIN1 = 9
24
+ FIN2 = 10
25
+ GOT_FIN2 = 11
26
+ TUND_FIN = 12
27
+ TUN_FIN = 13
28
+ end
@@ -1,945 +1,114 @@
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
- @roles = {} # sock => :ctlr / :shadow / :p1
45
- @infos = {} # sock => {}
46
- @socks = {} # sock => sock_id
47
- @sock_ids = {} # sock_id => sock
48
-
49
- ctlr, ctlw = IO.pipe
50
- @ctlw = ctlw
51
- @roles[ ctlr ] = :ctlr
52
- @reads << ctlr
53
- end
54
-
55
- def looping
56
- puts 'looping'
57
-
58
- new_p1
59
-
60
- loop do
61
- rs, ws = IO.select( @reads, @writes )
62
-
63
- @mutex.synchronize do
64
- rs.each do | sock |
65
- case @roles[ sock ]
66
- when :ctlr
67
- read_ctlr( sock )
68
- when :shadow
69
- read_shadow( sock )
70
- when :p1
71
- read_p1( sock )
72
- end
73
- end
74
-
75
- ws.each do | sock |
76
- case @roles[ sock ]
77
- when :shadow
78
- write_shadow( sock )
79
- when :p1
80
- write_p1( sock )
81
- end
82
- end
83
- end
84
- end
85
- rescue Interrupt => e
86
- puts e.class
87
- quit!
88
- end
89
-
90
- def quit!
91
- if @p1 && !@p1.closed? && @p1_info[ :p2_addr ]
92
- ctlmsg = [ 0, P1_FIN ].pack( 'Q>C' )
93
- send_pack( @p1, ctlmsg, @p1_info[ :p2_addr ] )
94
- end
95
-
96
- exit
97
- end
98
-
99
- private
100
-
101
- ##
102
- # read ctlr
103
- #
104
- def read_ctlr( ctlr )
105
- case ctlr.read( 1 ).unpack( 'C' ).first
106
- when CTL_CLOSE
107
- sock_id = ctlr.read( 8 ).unpack( 'Q>' ).first
108
- sock = @sock_ids[ sock_id ]
109
-
110
- if sock
111
- add_closing( sock )
112
- end
113
- when CTL_RESUME
114
- sock_id = ctlr.read( 8 ).unpack( 'Q>' ).first
115
- sock = @sock_ids[ sock_id ]
116
-
117
- if sock
118
- add_write( sock )
119
- end
120
- end
121
- end
122
-
123
- ##
124
- # read shadow
125
- #
126
- def read_shadow( shadow )
127
- begin
128
- data = shadow.read_nonblock( PACK_SIZE )
129
- rescue IO::WaitReadable, Errno::EINTR
130
- return
131
- rescue Exception => e
132
- add_closing( shadow )
133
- return
134
- end
135
-
136
- info = @infos[ shadow ]
137
- p1 = info[ :p1 ]
138
-
139
- if p1.closed?
140
- add_closing( shadow )
141
- return
142
- end
143
-
144
- p1_info = @infos[ p1 ]
145
- shadow_id = @socks[ shadow ]
146
- p1_info[ :wbuffs ] << [ shadow_id, data ]
147
-
148
- if p1_info[ :wbuffs ].size >= WBUFFS_LIMIT
149
- p1_id = @socks[ p1 ]
150
- spring = p1_info[ :chunks ].size > 0 ? ( p1_info[ :spring ] + 1 ) : 0
151
- filename = "#{ p1_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
- sockaddr = addrinfo.to_sockaddr
170
- now = Time.new
171
- info = @infos[ p1 ]
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 info[ :peer_addr ] || ( sockaddr != @p2pd_sockaddr )
178
-
179
- peer_addr = data[ 9..-1 ]
180
- info[ :peer_addr ] = data[ 9..-1 ]
181
- # puts "debug peer addr #{ Addrinfo.new( info[ :peer_addr ] ).ip_unpack.inspect } #{ Time.new }"
182
- loop_punch_peer( p1 )
183
- when HEARTBEAT
184
- return if info[ :p2_addr ] || ( sockaddr != info[ :peer_addr ] )
185
-
186
- info[ :p2_addr ] = sockaddr
187
- # puts "debug p2 addr #{ Addrinfo.new( info[ :p2_addr ] ).ip_unpack.inspect } #{ Time.new }"
188
- info[ :last_traffic_at ] = now
189
- loop_send_heartbeat( p1 )
190
- loop_check_expire( p1 )
191
- loop_send_status( p1 )
192
- when A_NEW_APP
193
- return if sockaddr != info[ :p2_addr ]
194
-
195
- app_id = data[ 9, 8 ].unpack( 'Q>' ).first
196
- shadow_id = info[ :app_ids ][ app_id ]
197
-
198
- unless shadow_id
199
- shadow = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
200
- shadow.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 )
201
-
202
- begin
203
- shadow.connect_nonblock( @appd_sockaddr )
204
- rescue IO::WaitWritable, Errno::EINTR
205
- end
206
-
207
- shadow_id = @hex.gen_random_num
208
- @roles[ shadow ] = :shadow
209
- @infos[ shadow ] = {
210
- id: shadow_id,
211
- p1: p1
212
- }
213
- @socks[ shadow ] = shadow_id
214
- @sock_ids[ shadow_id ] = shadow
215
-
216
- info[ :shadow_exts ][ shadow_id ] = {
217
- shadow: shadow,
218
- created_at: now,
219
- last_recv_at: nil, # 上一次收到流量的时间
220
- wbuff: '', # 写前缓存
221
- cache: '', # 块读出缓存
222
- chunks: [], # 块队列,写前达到块大小时结一个块 filename
223
- spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
224
- wmems: {}, # 写后缓存 pack_id => data
225
- send_ats: {}, # 上一次发出时间 pack_id => send_at
226
- biggest_pack_id: 0, # 发到几
227
- continue_app_pack_id: 0, # 收到几
228
- pieces: {}, # 跳号包 app_pack_id => data
229
- is_app_closed: false, # 对面是否已关闭
230
- biggest_app_pack_id: 0, # 对面发到几
231
- completed_pack_id: 0, # 完成到几(对面收到几)
232
- last_traffic_at: nil # 收到有效流量,或者发出流量的时间戳
233
- }
234
-
235
- info[ :shadow_ids ][ shadow_id ] = app_id
236
- info[ :app_ids ][ app_id ] = shadow_id
237
- add_read( shadow )
238
- end
239
-
240
- ctlmsg = [
241
- 0,
242
- PAIRED,
243
- app_id,
244
- shadow_id
245
- ].pack( 'Q>CQ>Q>' )
246
-
247
- # puts "debug send PAIRED #{ app_id } #{ shadow_id } #{ Time.new }"
248
- send_pack( p1, ctlmsg, info[ :p2_addr ] )
249
- when APP_STATUS
250
- return if sockaddr != info[ :p2_addr ]
251
-
252
- app_id, biggest_app_pack_id, continue_shadow_pack_id = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
253
- shadow_id = info[ :app_ids ][ app_id ]
254
- return unless shadow_id
255
-
256
- ext = info[ :shadow_exts ][ shadow_id ]
257
- return unless ext
258
-
259
- # 更新对面发到几
260
- if biggest_app_pack_id > ext[ :biggest_app_pack_id ]
261
- ext[ :biggest_app_pack_id ] = biggest_app_pack_id
262
- end
263
-
264
- # 更新对面收到几,释放写后
265
- if continue_shadow_pack_id > ext[ :completed_pack_id ]
266
- pack_ids = ext[ :wmems ].keys.select { | pack_id | pack_id <= continue_shadow_pack_id }
267
-
268
- pack_ids.each do | pack_id |
269
- ext[ :wmems ].delete( pack_id )
270
- ext[ :send_ats ].delete( pack_id )
271
- end
272
-
273
- ext[ :completed_pack_id ] = continue_shadow_pack_id
274
- end
275
-
276
- if ext[ :is_app_closed ] && ( ext[ :biggest_app_pack_id ] == ext[ :continue_app_pack_id ] )
277
- add_write( ext[ :shadow ] )
278
- return
279
- end
280
-
281
- # 发miss
282
- if !ext[ :shadow ].closed? && ( ext[ :continue_app_pack_id ] < ext[ :biggest_app_pack_id ] )
283
- ranges = []
284
- curr_pack_id = ext[ :continue_app_pack_id ] + 1
285
-
286
- ext[ :pieces ].keys.sort.each do | pack_id |
287
- if pack_id > curr_pack_id
288
- ranges << [ curr_pack_id, pack_id - 1 ]
289
- end
290
-
291
- curr_pack_id = pack_id + 1
292
- end
293
-
294
- if curr_pack_id <= ext[ :biggest_app_pack_id ]
295
- ranges << [ curr_pack_id, ext[ :biggest_app_pack_id ] ]
296
- end
297
-
298
- # puts "debug #{ ext[ :continue_app_pack_id ] }/#{ ext[ :biggest_app_pack_id ] } send MISS #{ ranges.size }"
299
- ranges.each do | pack_id_begin, pack_id_end |
300
- ctlmsg = [
301
- 0,
302
- MISS,
303
- app_id,
304
- pack_id_begin,
305
- pack_id_end
306
- ].pack( 'Q>CQ>Q>Q>' )
307
-
308
- send_pack( p1, ctlmsg, info[ :p2_addr ] )
309
- end
310
- end
311
- when MISS
312
- return if sockaddr != info[ :p2_addr ]
313
-
314
- shadow_id, pack_id_begin, pack_id_end = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
315
- ext = info[ :shadow_exts ][ shadow_id ]
316
- return unless ext
317
-
318
- ( pack_id_begin..pack_id_end ).each do | pack_id |
319
- send_at = ext[ :send_ats ][ pack_id ]
320
-
321
- if send_at
322
- break if now - send_at < STATUS_INTERVAL
323
-
324
- info[ :resendings ] << [ shadow_id, pack_id ]
325
- end
326
- end
327
-
328
- add_write( p1 )
329
- when FIN1
330
- return if sockaddr != info[ :p2_addr ]
331
-
332
- app_id = data[ 9, 8 ].unpack( 'Q>' ).first
333
- ctlmsg = [
334
- 0,
335
- GOT_FIN1,
336
- app_id
337
- ].pack( 'Q>CQ>' )
338
-
339
- # puts "debug 2-1. recv fin1 -> send got_fin1 -> ext.is_app_closed = true #{ app_id } #{ Time.new }"
340
- send_pack( p1, ctlmsg, info[ :p2_addr ] )
341
-
342
- shadow_id = info[ :app_ids ][ app_id ]
343
- return unless shadow_id
344
-
345
- ext = info[ :shadow_exts ][ shadow_id ]
346
- return unless ext
347
-
348
- ext[ :is_app_closed ] = true
349
- when GOT_FIN1
350
- return if sockaddr != info[ :p2_addr ]
351
-
352
- # puts "debug 1-2. recv got_fin1 -> break loop #{ Time.new }"
353
- shadow_id = data[ 9, 8 ].unpack( 'Q>' ).first
354
- info[ :fin1s ].delete( shadow_id )
355
- when FIN2
356
- return if sockaddr != info[ :p2_addr ]
357
-
358
- # puts "debug 1-3. recv fin2 -> send got_fin2 -> del ext #{ Time.new }"
359
- app_id = data[ 9, 8 ].unpack( 'Q>' ).first
360
- ctlmsg = [
361
- 0,
362
- GOT_FIN2,
363
- app_id
364
- ].pack( 'Q>CQ>' )
365
-
366
- send_pack( p1, ctlmsg, info[ :p2_addr ] )
367
-
368
- shadow_id = info[ :app_ids ][ app_id ]
369
- return unless shadow_id
370
-
371
- del_shadow_ext( info, shadow_id )
372
- when GOT_FIN2
373
- return if sockaddr != info[ :p2_addr ]
374
-
375
- # puts "debug 2-4. recv got_fin2 -> break loop #{ Time.new }"
376
- shadow_id = data[ 9, 8 ].unpack( 'Q>' ).first
377
- info[ :fin2s ].delete( shadow_id )
378
- when P2_FIN
379
- return if sockaddr != info[ :p2_addr ]
380
-
381
- puts "recv p2 fin #{ Time.new }"
382
- add_closing( p1 )
383
- end
384
-
385
- return
386
- end
387
-
388
- return if sockaddr != info[ :p2_addr ]
389
-
390
- shadow_id = info[ :app_ids ][ app_id ]
391
- return unless shadow_id
392
-
393
- ext = info[ :shadow_exts ][ shadow_id ]
394
- return if ext.nil? || ext[ :shadow ].closed?
395
-
396
- pack_id = data[ 8, 8 ].unpack( 'Q>' ).first
397
- return if ( pack_id <= ext[ :continue_app_pack_id ] ) || ext[ :pieces ].include?( pack_id )
398
-
399
- data = data[ 16..-1 ]
400
-
401
- # 解混淆
402
- if pack_id == 1
403
- data = @hex.decode( data )
404
- end
405
-
406
- # 放进shadow的写前缓存,跳号放碎片缓存
407
- if pack_id - ext[ :continue_app_pack_id ] == 1
408
- while ext[ :pieces ].include?( pack_id + 1 )
409
- data << ext[ :pieces ].delete( pack_id + 1 )
410
- pack_id += 1
411
- end
412
-
413
- ext[ :continue_app_pack_id ] = pack_id
414
- ext[ :wbuff ] << data
415
-
416
- if ext[ :wbuff ].bytesize >= CHUNK_SIZE
417
- spring = ext[ :chunks ].size > 0 ? ( ext[ :spring ] + 1 ) : 0
418
- filename = "#{ shadow_id }.#{ spring }"
419
- chunk_path = File.join( @shadow_chunk_dir, filename )
420
- IO.binwrite( chunk_path, ext[ :wbuff ] )
421
- ext[ :chunks ] << filename
422
- ext[ :spring ] = spring
423
- ext[ :wbuff ].clear
424
- end
425
-
426
- add_write( ext[ :shadow ] )
427
- ext[ :last_traffic_at ] = now
428
- info[ :last_traffic_at ] = now
429
- else
430
- ext[ :pieces ][ pack_id ] = data
431
- end
432
-
433
- ext[ :last_recv_at ] = now
434
- end
435
-
436
- ##
437
- # write shadow
438
- #
439
- def write_shadow( shadow )
440
- if @closings.include?( shadow )
441
- close_shadow( shadow )
442
- return
443
- end
444
-
445
- info = @infos[ shadow ]
446
- p1 = info[ :p1 ]
447
-
448
- if p1.closed?
449
- add_closing( shadow )
450
- return
451
- end
452
-
453
- p1_info = @infos[ p1 ]
454
- shadow_id = @socks[ shadow ]
455
- ext = p1_info[ :shadow_exts ][ shadow_id ]
456
-
457
- # 取写前
458
- data = ext[ :cache ]
459
- from = :cache
460
-
461
- if data.empty?
462
- if ext[ :chunks ].any?
463
- path = File.join( @shadow_chunk_dir, ext[ :chunks ].shift )
464
-
465
- begin
466
- data = IO.binread( path )
467
- File.delete( path )
468
- rescue Errno::ENOENT
469
- add_closing( shadow )
470
- return
471
- end
472
- else
473
- data = ext[ :wbuff ]
474
- from = :wbuff
475
- end
476
- end
477
-
478
- if data.empty?
479
- if ext[ :is_app_closed ] && ( ext[ :biggest_app_pack_id ] == ext[ :continue_app_pack_id ] )
480
- # puts "debug 2-2. all sent && ext.biggest_app_pack_id == ext.continue_app_pack_id -> add closing shadow #{ Time.new }"
481
- add_closing( shadow )
482
- return
483
- end
484
-
485
- @writes.delete( shadow )
486
- return
487
- end
488
-
489
- begin
490
- written = shadow.write_nonblock( data )
491
- rescue IO::WaitWritable, Errno::EINTR => e
492
- ext[ from ] = data
493
- return
494
- rescue Exception => e
495
- add_closing( shadow )
496
- return
497
- end
498
-
499
- data = data[ written..-1 ]
500
- ext[ from ] = data
501
- end
502
-
503
- ##
504
- # write p1
505
- #
506
- def write_p1( p1 )
507
- if @closings.include?( p1 )
508
- close_p1( p1 )
509
- new_p1
510
- return
511
- end
512
-
513
- now = Time.new
514
- info = @infos[ p1 ]
515
-
516
- # 重传
517
- while info[ :resendings ].any?
518
- shadow_id, pack_id = info[ :resendings ].shift
519
- ext = info[ :shadow_exts ][ shadow_id ]
520
-
521
- if ext
522
- pack = ext[ :wmems ][ pack_id ]
523
-
524
- if pack
525
- send_pack( p1, pack, info[ :p2_addr ] )
526
- ext[ :last_traffic_at ] = now
527
- info[ :last_traffic_at ] = now
528
- return
529
- end
530
- end
531
- end
532
-
533
- # 若写后到达上限,暂停取写前
534
- if info[ :shadow_exts ].map{ | _, ext | ext[ :wmems ].size }.sum >= WMEMS_LIMIT
535
- unless info[ :paused ]
536
- puts "pause #{ Time.new }"
537
- info[ :paused ] = true
538
- end
539
-
540
- @writes.delete( p1 )
541
- return
542
- end
543
-
544
- # 取写前
545
- if info[ :caches ].any?
546
- shadow_id, data = info[ :caches ].shift
547
- elsif info[ :chunks ].any?
548
- path = File.join( @p1_chunk_dir, info[ :chunks ].shift )
549
-
550
- begin
551
- data = IO.binread( path )
552
- File.delete( path )
553
- rescue Errno::ENOENT
554
- add_closing( p1 )
555
- return
556
- end
557
-
558
- caches = []
559
-
560
- until data.empty?
561
- shadow_id, pack_size = data[ 0, 10 ].unpack( 'Q>n' )
562
- caches << [ shadow_id, data[ 10, pack_size ] ]
563
- data = data[ ( 10 + pack_size )..-1 ]
564
- end
565
-
566
- shadow_id, data = caches.shift
567
- info[ :caches ] = caches
568
- elsif info[ :wbuffs ].any?
569
- shadow_id, data = info[ :wbuffs ].shift
570
- else
571
- @writes.delete( p1 )
572
- return
573
- end
574
-
575
- ext = info[ :shadow_exts ][ shadow_id ]
576
-
577
- if ext
578
- pack_id = ext[ :biggest_pack_id ] + 1
579
-
580
- if pack_id == 1
581
- data = @hex.encode( data )
582
- end
583
-
584
- pack = "#{ [ shadow_id, pack_id ].pack( 'Q>Q>' ) }#{ data }"
585
- send_pack( p1, pack, info[ :p2_addr ] )
586
- ext[ :biggest_pack_id ] = pack_id
587
- ext[ :wmems ][ pack_id ] = pack
588
- ext[ :send_ats ][ pack_id ] = now
589
- ext[ :last_traffic_at ] = now
590
- info[ :last_traffic_at ] = now
591
- end
592
- end
593
-
594
- def new_p1
595
- p1 = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
596
- p1.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
597
- p1.bind( Socket.sockaddr_in( 0, '0.0.0.0' ) )
598
-
599
- p1_id = @hex.gen_random_num
600
- p1_info = {
601
- id: p1_id,
602
- wbuffs: [], # 写前缓存 [ shadow_id, data ]
603
- caches: [], # 块读出缓存 [ shadow_id, data ]
604
- chunks: [], # 块队列 filename
605
- spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
606
- peer_addr: nil, # 对面地址,连发心跳包打洞,离p2pd近的一方通常会撞死几个直到对面出来
607
- p2_addr: nil, # p2地址
608
- shadow_exts: {}, # 长命信息 shadow_id => {}
609
- shadow_ids: {}, # shadow_id => app_id
610
- app_ids: {}, # app_id => shadow_id
611
- fin1s: [], # fin1: shadow已关闭,等待对面收完流量 shadow_id
612
- fin2s: [], # fin2: 流量已收完 shadow_id
613
- paused: false, # 是否暂停写
614
- resendings: [], # 重传队列 [ shadow_id, pack_id ]
615
- last_traffic_at: nil # 收到有效流量,或者发出流量的时间戳
616
- }
617
-
618
- @p1 = p1
619
- @p1_info = p1_info
620
- @roles[ p1 ] = :p1
621
- @infos[ p1 ] = p1_info
622
- @socks[ p1 ] = p1_id
623
- @sock_ids[ p1_id ] = p1
624
-
625
- send_pack( p1, @title, @p2pd_sockaddr )
626
- add_read( p1 )
627
- loop_send_char( p1 )
628
- end
629
-
630
- def loop_send_char( p1 )
631
- Thread.new do
632
- is_timeout = true
633
-
634
- 20.times do
635
- sleep HEARTBEAT_INTERVAL
636
-
637
- if p1.closed?
638
- is_timeout = false
639
- break
640
- end
641
-
642
- p1_info = @infos[ p1 ]
643
-
644
- if p1_info[ :peer_addr ]
645
- is_timeout = false
646
- break
647
- end
648
-
649
- @mutex.synchronize do
650
- send_pack( p1, [ rand( 128 ) ].pack( 'C' ), @p2pd_sockaddr )
651
- end
652
- end
653
-
654
- if is_timeout
655
- @mutex.synchronize do
656
- p1_id = @socks[ p1 ]
657
- @ctlw.write( [ CTL_CLOSE, p1_id ].pack( 'CQ>' ) )
658
- end
659
- end
660
- end
661
- end
662
-
663
- def loop_punch_peer( p1 )
664
- Thread.new do
665
- 20.times do
666
- break if p1.closed?
667
-
668
- p1_info = @infos[ p1 ]
669
-
670
- @mutex.synchronize do
671
- send_heartbeat( p1, p1_info[ :peer_addr ] )
672
- end
673
-
674
- sleep STATUS_INTERVAL
675
- end
676
-
677
- if !p1.closed?
678
- p1_info = @infos[ p1 ]
679
-
680
- unless p1_info[ :p2_addr ]
681
- @mutex.synchronize do
682
- p1_id = @socks[ p1 ]
683
- @ctlw.write( [ CTL_CLOSE, p1_id ].pack( 'CQ>' ) )
684
- end
685
- end
686
- end
687
- end
688
- end
689
-
690
- def loop_send_heartbeat( p1 )
691
- Thread.new do
692
- loop do
693
- sleep HEARTBEAT_INTERVAL
694
- break if p1.closed?
695
-
696
- @mutex.synchronize do
697
- p1_info = @infos[ p1 ]
698
- send_heartbeat( p1, p1_info[ :p2_addr ] )
699
- end
700
- end
701
- end
702
- end
703
-
704
- def loop_check_expire( p1 )
705
- Thread.new do
706
- loop do
707
- sleep 60
708
- break if p1.closed?
709
-
710
- now = Time.new
711
- p1_info = @infos[ p1 ]
712
-
713
- if now - p1_info[ :last_traffic_at ] > EXPIRE_AFTER
714
- @mutex.synchronize do
715
- p1_id = @socks[ p1 ]
716
- # puts "debug ctlw close p1 #{ p1_id } #{ Time.new } p#{ Process.pid }"
717
- @ctlw.write( [ CTL_CLOSE, p1_id ].pack( 'CQ>' ) )
718
- end
719
-
720
- break
721
- end
722
-
723
- exts = p1_info[ :shadow_exts ].select{ | _, ext | now - ext[ :created_at ] > 5 }
724
-
725
- if exts.any?
726
- @mutex.synchronize do
727
- exts.each do | shadow_id, ext |
728
- if ext[ :last_recv_at ].nil? || ( now - ext[ :last_recv_at ] > EXPIRE_AFTER )
729
- # puts "debug ctlw close shadow #{ shadow_id } #{ Time.new } p#{ Process.pid }"
730
- @ctlw.write( [ CTL_CLOSE, shadow_id ].pack( 'CQ>' ) )
731
- end
732
- end
733
- end
734
- end
735
- end
736
- end
737
- end
738
-
739
- def loop_send_status( p1 )
740
- Thread.new do
741
- loop do
742
- sleep STATUS_INTERVAL
743
-
744
- if p1.closed?
745
- # puts "debug p1 is closed, break send status loop #{ Time.new }"
746
- break
747
- end
748
-
749
- p1_info = @infos[ p1 ]
750
-
751
- if p1_info[ :shadow_exts ].any?
752
- @mutex.synchronize do
753
- now = Time.new
754
-
755
- p1_info[ :shadow_exts ].each do | shadow_id, ext |
756
- if ext[ :last_traffic_at ] && ( now - ext[ :last_traffic_at ] < SEND_STATUS_UNTIL )
757
- ctlmsg = [
758
- 0,
759
- SHADOW_STATUS,
760
- shadow_id,
761
- ext[ :biggest_pack_id ],
762
- ext[ :continue_app_pack_id ]
763
- ].pack( 'Q>CQ>Q>Q>' )
764
-
765
- send_pack( p1, ctlmsg, p1_info[ :p2_addr ] )
766
- end
767
- end
768
- end
769
- end
770
-
771
- if p1_info[ :paused ] && ( p1_info[ :shadow_exts ].map{ | _, ext | ext[ :wmems ].size }.sum < RESUME_BELOW )
772
- @mutex.synchronize do
773
- p1_id = @socks[ p1 ]
774
- puts "ctlw resume #{ p1_id } #{ Time.new }"
775
- @ctlw.write( [ CTL_RESUME, p1_id ].pack( 'CQ>' ) )
776
- p1_info[ :paused ] = false
777
- end
778
- end
779
- end
780
- end
781
- end
782
-
783
- def loop_send_fin1( p1, shadow_id )
784
- Thread.new do
785
- 100.times do
786
- break if p1.closed?
787
-
788
- p1_info = @infos[ p1 ]
789
- break unless p1_info[ :p2_addr ]
790
-
791
- unless p1_info[ :fin1s ].include?( shadow_id )
792
- # puts "debug break send fin1 loop #{ Time.new }"
793
- break
794
- end
795
-
796
- @mutex.synchronize do
797
- ctlmsg = [
798
- 0,
799
- FIN1,
800
- shadow_id
801
- ].pack( 'Q>CQ>' )
802
-
803
- # puts "debug send FIN1 #{ shadow_id } #{ Time.new }"
804
- send_pack( p1, ctlmsg, p1_info[ :p2_addr ] )
805
- end
806
-
807
- sleep 1
808
- end
809
- end
810
- end
811
-
812
- def loop_send_fin2( p1, shadow_id )
813
- Thread.new do
814
- 100.times do
815
- break if p1.closed?
816
-
817
- p1_info = @infos[ p1 ]
818
- break unless p1_info[ :p2_addr ]
819
-
820
- unless p1_info[ :fin2s ].include?( shadow_id )
821
- # puts "debug break send fin2 loop #{ Time.new }"
822
- break
823
- end
824
-
825
- @mutex.synchronize do
826
- ctlmsg = [
827
- 0,
828
- FIN2,
829
- shadow_id
830
- ].pack( 'Q>CQ>' )
831
-
832
- # puts "debug send FIN2 #{ shadow_id } #{ Time.new }"
833
- send_pack( p1, ctlmsg, p1_info[ :p2_addr ] )
834
- end
835
-
836
- sleep 1
837
- end
838
- end
839
- end
840
-
841
- def send_heartbeat( p1, target_addr )
842
- ctlmsg = [ 0, HEARTBEAT, rand( 128 ) ].pack( 'Q>CC' )
843
- send_pack( p1, ctlmsg, target_addr )
844
- end
845
-
846
- def send_pack( sock, data, target_sockaddr )
847
- begin
848
- sock.sendmsg( data, 0, target_sockaddr )
849
- rescue IO::WaitWritable, Errno::EINTR => e
850
- puts "sendmsg #{ e.class } #{ Time.new }"
851
- end
852
- end
853
-
854
- def add_read( sock )
855
- return if sock.closed? || @reads.include?( sock )
856
-
857
- @reads << sock
858
- end
859
-
860
- def add_write( sock, data = nil )
861
- return if sock.closed? || @writes.include?( sock )
862
-
863
- @writes << sock
864
- end
865
-
866
- def add_closing( sock )
867
- return if sock.closed? || @closings.include?( sock )
868
-
869
- @reads.delete( sock )
870
- @closings << sock
871
- add_write( sock )
872
- end
873
-
874
- def close_p1( p1 )
875
- info = close_sock( p1 )
876
-
877
- info[ :chunks ].each do | filename |
878
- begin
879
- File.delete( File.join( @p1_chunk_dir, filename ) )
880
- rescue Errno::ENOENT
881
- end
882
- end
883
-
884
- info[ :shadow_exts ].each{ | _, ext | add_closing( ext[ :shadow ] ) }
885
- end
886
-
887
- def close_shadow( shadow )
888
- info = close_sock( shadow )
889
- p1 = info[ :p1 ]
890
- return if p1.closed?
891
-
892
- shadow_id = info[ :id ]
893
- p1_info = @infos[ p1 ]
894
- ext = p1_info[ :shadow_exts ][ shadow_id ]
895
- return unless ext
896
-
897
- if ext[ :is_app_closed ]
898
- del_shadow_ext( p1_info, shadow_id )
899
-
900
- unless p1_info[ :fin2s ].include?( shadow_id )
901
- # puts "debug 2-3. shadow.close -> ext.is_app_closed ? yes -> del ext -> loop send fin2 #{ Time.new }"
902
- p1_info[ :fin2s ] << shadow_id
903
- loop_send_fin2( p1, shadow_id )
904
- end
905
- elsif !p1_info[ :fin1s ].include?( shadow_id )
906
- # puts "debug 1-1. shadow.close -> ext.is_app_closed ? no -> send fin1 loop #{ Time.new }"
907
- p1_info[ :fin1s ] << shadow_id
908
- loop_send_fin1( p1, shadow_id )
909
- end
910
- end
911
-
912
- def close_sock( sock )
913
- sock.close
914
- @reads.delete( sock )
915
- @writes.delete( sock )
916
- @closings.delete( sock )
917
- @roles.delete( sock )
918
- info = @infos.delete( sock )
919
- sock_id = @socks.delete( sock )
920
- @sock_ids.delete( sock_id )
921
-
922
- info
923
- end
924
-
925
- def del_shadow_ext( p1_info, shadow_id )
926
- ext = p1_info[ :shadow_exts ].delete( shadow_id )
927
-
928
- if ext
929
- ext[ :chunks ].each do | filename |
930
- begin
931
- File.delete( File.join( @shadow_chunk_dir, filename ) )
932
- rescue Errno::ENOENT
933
- end
934
- end
935
- end
936
-
937
- app_id = p1_info[ :shadow_ids ].delete( shadow_id )
938
-
939
- if app_id
940
- p1_info[ :app_ids ].delete( app_id )
941
- end
942
- end
943
-
944
- end
945
- end
1
+ require 'json'
2
+ require 'p2p2/head'
3
+ require 'p2p2/p1_custom'
4
+ require 'p2p2/p1_worker'
5
+ require 'p2p2/version'
6
+ require 'socket'
7
+
8
+ ##
9
+ # P2p2::P1 - 内网里的任意应用,访问另一个内网里的应用服务端。p1端。
10
+ #
11
+ module P2p2
12
+ class P1
13
+
14
+ def initialize( config_path = nil )
15
+ unless config_path
16
+ config_path = File.expand_path( '../p2p2.conf.json', __FILE__ )
17
+ end
18
+
19
+ unless File.exist?( config_path )
20
+ raise "missing config file #{ config_path }"
21
+ end
22
+
23
+ conf = JSON.parse( IO.binread( config_path ), symbolize_names: true )
24
+ p2pd_host = conf[ :p2pd_host ]
25
+ p2pd_port = conf[ :p2pd_port ]
26
+ room = conf[ :room ]
27
+ appd_host = conf[ :appd_host ]
28
+ appd_port = conf[ :appd_port ]
29
+ p1_tmp_dir = conf[ :p1_tmp_dir ]
30
+
31
+ unless p2pd_host
32
+ raise "missing p2pd host"
33
+ end
34
+
35
+ unless room
36
+ raise "missing room"
37
+ end
38
+
39
+ unless p2pd_port
40
+ p2pd_port = 2020
41
+ end
42
+
43
+ unless appd_host
44
+ appd_host = '127.0.0.1'
45
+ end
46
+
47
+ unless appd_port
48
+ appd_port = 22
49
+ end
50
+
51
+ unless p1_tmp_dir
52
+ p1_tmp_dir = '/tmp/p2p2.p1'
53
+ end
54
+
55
+ unless File.exist?( p1_tmp_dir )
56
+ Dir.mkdir( p1_tmp_dir )
57
+ end
58
+
59
+ dst_chunk_dir = File.join( p1_tmp_dir, 'dst.chunk' )
60
+
61
+ unless Dir.exist?( dst_chunk_dir )
62
+ Dir.mkdir( dst_chunk_dir )
63
+ end
64
+
65
+ tund_chunk_dir = File.join( p1_tmp_dir, 'tund.chunk' )
66
+
67
+ unless Dir.exist?( tund_chunk_dir )
68
+ Dir.mkdir( tund_chunk_dir )
69
+ end
70
+
71
+ title = "p2p2 p1 #{ P2p2::VERSION }"
72
+ puts title
73
+ puts "p2pd host #{ p2pd_host }"
74
+ puts "p2pd port #{ p2pd_port }"
75
+ puts "room #{ room }"
76
+ puts "appd host #{ appd_host }"
77
+ puts "appd port #{ appd_port }"
78
+ puts "p1 tmp dir #{ p1_tmp_dir }"
79
+ puts "dst chunk dir #{ dst_chunk_dir }"
80
+ puts "tund chunk dir #{ tund_chunk_dir }"
81
+
82
+ if RUBY_PLATFORM.include?( 'linux' )
83
+ $0 = title
84
+
85
+ pid = fork do
86
+ $0 = 'p2p2 p1 worker'
87
+ worker = P2p2::P1Worker.new( p2pd_host, p2pd_port, room, appd_host, appd_port, dst_chunk_dir, tund_chunk_dir )
88
+
89
+ Signal.trap( :TERM ) do
90
+ puts 'exit'
91
+ worker.quit!
92
+ end
93
+
94
+ worker.looping
95
+ end
96
+
97
+ Signal.trap( :TERM ) do
98
+ puts 'trap TERM'
99
+
100
+ begin
101
+ Process.kill( :TERM, pid )
102
+ rescue Errno::ESRCH => e
103
+ puts e.class
104
+ end
105
+ end
106
+
107
+ Process.waitall
108
+ else
109
+ P2p2::P1Worker.new( p2pd_host, p2pd_port, room, appd_host, appd_port, dst_chunk_dir, tund_chunk_dir ).looping
110
+ end
111
+ end
112
+
113
+ end
114
+ end