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