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 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