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