p2p2 0.14.0 → 0.18.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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