p2p2 0.15.1 → 0.16.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: 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