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