p2p2 0.14.0 → 0.18.0

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