p2p2 0.15.0 → 0.19.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,1020 +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
- pack_count = 0
318
- # puts "debug #{ ext[ :continue_shadow_pack_id ] }/#{ ext[ :biggest_shadow_pack_id ] } send MISS #{ ranges.size }"
319
- ranges.each do | pack_id_begin, pack_id_end |
320
- if pack_count >= BREAK_SEND_MISS
321
- puts "break send miss at #{ pack_id_begin } #{ Time.new }"
322
- break
323
- end
324
-
325
- ctlmsg = [
326
- 0,
327
- MISS,
328
- shadow_id,
329
- pack_id_begin,
330
- pack_id_end
331
- ].pack( 'Q>CQ>Q>Q>' )
332
-
333
- send_pack( p2, ctlmsg, info[ :p1_addr ] )
334
- pack_count += ( pack_id_end - pack_id_begin + 1 )
335
- end
336
- end
337
- when MISS
338
- return if sockaddr != info[ :p1_addr ]
339
-
340
- app_id, pack_id_begin, pack_id_end = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
341
- ext = info[ :app_exts ][ app_id ]
342
- return unless ext
343
-
344
- ( pack_id_begin..pack_id_end ).each do | pack_id |
345
- send_at = ext[ :send_ats ][ pack_id ]
346
-
347
- if send_at
348
- break if now - send_at < STATUS_INTERVAL
349
-
350
- info[ :resendings ] << [ app_id, pack_id ]
351
- end
352
- end
353
-
354
- add_write( p2 )
355
- when FIN1
356
- return if sockaddr != info[ :p1_addr ]
357
-
358
- shadow_id = data[ 9, 8 ].unpack( 'Q>' ).first
359
- ctlmsg = [
360
- 0,
361
- GOT_FIN1,
362
- shadow_id
363
- ].pack( 'Q>CQ>' )
364
-
365
- # puts "debug 2-1. recv fin1 -> send got_fin1 -> ext.is_shadow_closed = true #{ shadow_id } #{ Time.new }"
366
- send_pack( p2, ctlmsg, info[ :p1_addr ] )
367
-
368
- app_id = info[ :shadow_ids ][ shadow_id ]
369
- return unless app_id
370
-
371
- ext = info[ :app_exts ][ app_id ]
372
- return unless ext
373
-
374
- ext[ :is_shadow_closed ] = true
375
- when GOT_FIN1
376
- return if sockaddr != info[ :p1_addr ]
377
-
378
- # puts "debug 1-2. recv got_fin1 -> break loop #{ Time.new }"
379
- app_id = data[ 9, 8 ].unpack( 'Q>' ).first
380
- info[ :fin1s ].delete( app_id )
381
- when FIN2
382
- return if sockaddr != info[ :p1_addr ]
383
-
384
- # puts "debug 1-3. recv fin2 -> send got_fin2 -> del ext #{ Time.new }"
385
- shadow_id = data[ 9, 8 ].unpack( 'Q>' ).first
386
- ctlmsg = [
387
- 0,
388
- GOT_FIN2,
389
- shadow_id
390
- ].pack( 'Q>CQ>' )
391
-
392
- send_pack( p2, ctlmsg, info[ :p1_addr ] )
393
-
394
- app_id = info[ :shadow_ids ][ shadow_id ]
395
- return unless app_id
396
-
397
- del_app_ext( info, app_id )
398
- when GOT_FIN2
399
- return if sockaddr != info[ :p1_addr ]
400
-
401
- # puts "debug 2-4. recv got_fin2 -> break loop #{ Time.new }"
402
- app_id = data[ 9, 8 ].unpack( 'Q>' ).first
403
- info[ :fin2s ].delete( app_id )
404
- when P1_FIN
405
- return if sockaddr != info[ :p1_addr ]
406
- puts "recv p1 fin #{ Time.new }"
407
- add_closing( p2 )
408
- end
409
-
410
- return
411
- end
412
-
413
- return if sockaddr != info[ :p1_addr ]
414
-
415
- app_id = info[ :shadow_ids ][ shadow_id ]
416
- return unless app_id
417
-
418
- ext = info[ :app_exts ][ app_id ]
419
- return if ext.nil? || ext[ :app ].closed?
420
-
421
- pack_id = data[ 8, 8 ].unpack( 'Q>' ).first
422
- return if ( pack_id <= ext[ :continue_shadow_pack_id ] ) || ext[ :pieces ].include?( pack_id )
423
-
424
- data = data[ 16..-1 ]
425
-
426
- # 解混淆
427
- if pack_id == 1
428
- data = @hex.decode( data )
429
- end
430
-
431
- # 放进shadow的写前缓存,跳号放碎片缓存
432
- if pack_id - ext[ :continue_shadow_pack_id ] == 1
433
- while ext[ :pieces ].include?( pack_id + 1 )
434
- data << ext[ :pieces ].delete( pack_id + 1 )
435
- pack_id += 1
436
- end
437
-
438
- ext[ :continue_shadow_pack_id ] = pack_id
439
- ext[ :wbuff ] << data
440
-
441
- if ext[ :wbuff ].bytesize >= CHUNK_SIZE
442
- spring = ext[ :chunks ].size > 0 ? ( ext[ :spring ] + 1 ) : 0
443
- filename = "#{ app_id }.#{ spring }"
444
- chunk_path = File.join( @app_chunk_dir, filename )
445
- IO.binwrite( chunk_path, ext[ :wbuff ] )
446
- ext[ :chunks ] << filename
447
- ext[ :spring ] = spring
448
- ext[ :wbuff ].clear
449
- end
450
-
451
- add_write( ext[ :app ] )
452
- ext[ :last_traffic_at ] = now
453
- info[ :last_traffic_at ] = now
454
- else
455
- ext[ :pieces ][ pack_id ] = data
456
- end
457
-
458
- ext[ :last_recv_at ] = now
459
- end
460
-
461
- ##
462
- # write app
463
- #
464
- def write_app( app )
465
- if @closings.include?( app )
466
- close_app( app )
467
- return
468
- end
469
-
470
- info = @infos[ app ]
471
- p2 = info[ :p2 ]
472
-
473
- if p2.closed?
474
- add_closing( app )
475
- return
476
- end
477
-
478
- p2_info = @infos[ p2 ]
479
- app_id = @socks[ app ]
480
- ext = p2_info[ :app_exts ][ app_id ]
481
-
482
- # 取写前
483
- data = ext[ :cache ]
484
- from = :cache
485
-
486
- if data.empty?
487
- if ext[ :chunks ].any?
488
- path = File.join( @app_chunk_dir, ext[ :chunks ].shift )
489
-
490
- begin
491
- data = IO.binread( path )
492
- File.delete( path )
493
- rescue Errno::ENOENT
494
- add_closing( app )
495
- return
496
- end
497
- else
498
- data = ext[ :wbuff ]
499
- from = :wbuff
500
- end
501
- end
502
-
503
- if data.empty?
504
- if ext[ :is_shadow_closed ] && ( ext[ :biggest_shadow_pack_id ] == ext[ :continue_shadow_pack_id ] )
505
- # puts "debug 2-2. all sent && ext.biggest_shadow_pack_id == ext.continue_shadow_pack_id -> add closing app #{ Time.new }"
506
- add_closing( app )
507
- return
508
- end
509
-
510
- @writes.delete( app )
511
- return
512
- end
513
-
514
- begin
515
- written = app.write_nonblock( data )
516
- rescue IO::WaitWritable, Errno::EINTR => e
517
- ext[ from ] = data
518
- return
519
- rescue Exception => e
520
- add_closing( app )
521
- return
522
- end
523
-
524
- data = data[ written..-1 ]
525
- ext[ from ] = data
526
- end
527
-
528
- ##
529
- # write p2
530
- #
531
- def write_p2( p2 )
532
- if @closings.include?( p2 )
533
- close_p2( p2 )
534
- return
535
- end
536
-
537
- now = Time.new
538
- info = @infos[ p2 ]
539
-
540
- # 重传
541
- while info[ :resendings ].any?
542
- app_id, pack_id = info[ :resendings ].shift
543
- ext = info[ :app_exts ][ app_id ]
544
-
545
- if ext
546
- pack = ext[ :wmems ][ pack_id ]
547
-
548
- if pack
549
- send_pack( p2, pack, info[ :p1_addr ] )
550
- ext[ :last_traffic_at ] = now
551
- info[ :last_traffic_at ] = now
552
- return
553
- end
554
- end
555
- end
556
-
557
- # 若写后达到上限,暂停取写前
558
- if info[ :app_exts ].map{ | _, ext | ext[ :wmems ].size }.sum >= WMEMS_LIMIT
559
- unless info[ :paused ]
560
- puts "pause #{ Time.new }"
561
- info[ :paused ] = true
562
- end
563
-
564
- @writes.delete( p2 )
565
- return
566
- end
567
-
568
- # 取写前
569
- if info[ :caches ].any?
570
- app_id, data = info[ :caches ].shift
571
- elsif info[ :chunks ].any?
572
- path = File.join( @p2_chunk_dir, info[ :chunks ].shift )
573
-
574
- begin
575
- data = IO.binread( path )
576
- File.delete( path )
577
- rescue Errno::ENOENT
578
- add_closing( p2 )
579
- return
580
- end
581
-
582
- caches = []
583
-
584
- until data.empty?
585
- app_id, pack_size = data[ 0, 10 ].unpack( 'Q>n' )
586
- caches << [ app_id, data[ 10, pack_size ] ]
587
- data = data[ ( 10 + pack_size )..-1 ]
588
- end
589
-
590
- app_id, data = caches.shift
591
- info[ :caches ] = caches
592
- elsif info[ :wbuffs ].any?
593
- app_id, data = info[ :wbuffs ].shift
594
- else
595
- @writes.delete( p2 )
596
- return
597
- end
598
-
599
- ext = info[ :app_exts ][ app_id ]
600
-
601
- if ext
602
- pack_id = ext[ :biggest_pack_id ] + 1
603
-
604
- if pack_id == 1
605
- data = @hex.encode( data )
606
- end
607
-
608
- pack = "#{ [ app_id, pack_id ].pack( 'Q>Q>' ) }#{ data }"
609
- send_pack( p2, pack, info[ :p1_addr ] )
610
- ext[ :biggest_pack_id ] = pack_id
611
- ext[ :wmems ][ pack_id ] = pack
612
- ext[ :send_ats ][ pack_id ] = now
613
- ext[ :last_traffic_at ] = now
614
- info[ :last_traffic_at ] = now
615
- end
616
- end
617
-
618
- def new_appd
619
- appd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
620
- appd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
621
- appd.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 )
622
- appd.bind( @appd_sockaddr )
623
- appd.listen( 511 )
624
-
625
- @roles[ appd ] = :appd
626
- add_read( appd )
627
- end
628
-
629
- def new_p2
630
- p2 = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
631
- p2.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
632
- p2.bind( Socket.sockaddr_in( 0, '0.0.0.0' ) )
633
- p2_id = @hex.gen_random_num
634
- p2_info = {
635
- id: p2_id,
636
- waitings: {}, # 还没连上p1,或者还没配上shadow,暂存流量 app_id => buffs[]
637
- wbuffs: [], # 写前缓存 [ app_id, data ]
638
- caches: [], # 块读出缓存 [ app_id, data ]
639
- chunks: [], # 块队列 filename
640
- spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
641
- peer_addr: nil, # 对面地址,连发心跳包打洞,离p2pd近的一方通常会撞死几个直到对面出来
642
- p1_addr: nil, # p1地址
643
- app_exts: {}, # 传输相关 app_id => {}
644
- app_ids: {}, # app_id => shadow_id
645
- shadow_ids: {}, # shadow_id => app_id
646
- fin1s: [], # fin1: app已关闭,等待对面收完流量 app_id
647
- fin2s: [], # fin2: 流量已收完 app_id
648
- paused: false, # 是否暂停写
649
- resendings: [], # 重传队列 [ app_id, pack_id ]
650
- last_traffic_at: nil # 收到有效流量,或者发出流量的时间戳
651
- }
652
-
653
- @p2 = p2
654
- @p2_info = p2_info
655
- @roles[ p2 ] = :p2
656
- @infos[ p2 ] = p2_info
657
- @socks[ p2 ] = p2_id
658
- @sock_ids[ p2_id ] = p2
659
-
660
- send_pack( p2, @title, @p2pd_sockaddr )
661
- add_read( p2 )
662
- loop_send_char( p2 )
663
- end
664
-
665
- def loop_send_char( p2 )
666
- Thread.new do
667
- is_timeout = true
668
-
669
- 20.times do
670
- sleep HEARTBEAT_INTERVAL
671
-
672
- if p2.closed?
673
- is_timeout = false
674
- break
675
- end
676
-
677
- p2_info = @infos[ p2 ]
678
-
679
- if p2_info[ :peer_addr ]
680
- is_timeout = false
681
- break
682
- end
683
-
684
- @mutex.synchronize do
685
- send_pack( p2, [ rand( 128 ) ].pack( 'C' ), @p2pd_sockaddr )
686
- end
687
- end
688
-
689
- if is_timeout
690
- @mutex.synchronize do
691
- p2_id = @socks[ p2 ]
692
- @ctlw.write( [ CTL_CLOSE, p2_id ].pack( 'CQ>' ) )
693
- end
694
- end
695
- end
696
- end
697
-
698
- def loop_punch_peer( p2 )
699
- Thread.new do
700
- 20.times do
701
- break if p2.closed?
702
-
703
- p2_info = @infos[ p2 ]
704
-
705
- @mutex.synchronize do
706
- send_heartbeat( p2, p2_info[ :peer_addr ] )
707
- end
708
-
709
- sleep STATUS_INTERVAL
710
- end
711
-
712
- if !p2.closed?
713
- p2_info = @infos[ p2 ]
714
-
715
- unless p2_info[ :p1_addr ]
716
- @mutex.synchronize do
717
- p2_id = @socks[ p2 ]
718
- @ctlw.write( [ CTL_CLOSE, p2_id ].pack( 'CQ>' ) )
719
- end
720
- end
721
- end
722
- end
723
- end
724
-
725
- def loop_send_heartbeat( p2 )
726
- Thread.new do
727
- loop do
728
- sleep HEARTBEAT_INTERVAL
729
- break if p2.closed?
730
-
731
- @mutex.synchronize do
732
- p2_info = @infos[ p2 ]
733
- send_heartbeat( p2, p2_info[ :p1_addr ] )
734
- end
735
- end
736
- end
737
- end
738
-
739
- def loop_check_expire( p2 )
740
- Thread.new do
741
- loop do
742
- sleep 60
743
- break if p2.closed?
744
-
745
- now = Time.new
746
- p2_info = @infos[ p2 ]
747
-
748
- if now - p2_info[ :last_traffic_at ] > EXPIRE_AFTER
749
- @mutex.synchronize do
750
- p2_id = @socks[ p2 ]
751
- # puts "debug ctlw close p2 #{ p2_id } #{ Time.new } p#{ Process.pid }"
752
- @ctlw.write( [ CTL_CLOSE, p2_id ].pack( 'CQ>' ) )
753
- end
754
-
755
- break
756
- end
757
-
758
- exts = p2_info[ :app_exts ].select{ | _, ext | now - ext[ :created_at ] > 5 }
759
-
760
- if exts.any?
761
- @mutex.synchronize do
762
- exts.each do | app_id, ext |
763
- if ext[ :last_recv_at ].nil? || ( now - ext[ :last_recv_at ] > EXPIRE_AFTER )
764
- # puts "debug ctlw close app #{ app_id } #{ Time.new } p#{ Process.pid }"
765
- @ctlw.write( [ CTL_CLOSE, app_id ].pack( 'CQ>' ) )
766
- end
767
- end
768
- end
769
- end
770
- end
771
- end
772
- end
773
-
774
- def loop_send_status( p2 )
775
- Thread.new do
776
- loop do
777
- sleep STATUS_INTERVAL
778
-
779
- if p2.closed?
780
- # puts "debug p2 is closed, break send status loop #{ Time.new }"
781
- break
782
- end
783
-
784
- p2_info = @infos[ p2 ]
785
-
786
- if p2_info[ :app_exts ].any?
787
- @mutex.synchronize do
788
- now = Time.new
789
-
790
- p2_info[ :app_exts ].each do | app_id, ext |
791
- if ext[ :last_traffic_at ] && ( now - ext[ :last_traffic_at ] < SEND_STATUS_UNTIL )
792
- ctlmsg = [
793
- 0,
794
- APP_STATUS,
795
- app_id,
796
- ext[ :biggest_pack_id ],
797
- ext[ :continue_shadow_pack_id ]
798
- ].pack( 'Q>CQ>Q>Q>' )
799
-
800
- send_pack( p2, ctlmsg, p2_info[ :p1_addr ] )
801
- end
802
- end
803
- end
804
- end
805
-
806
- if p2_info[ :paused ] && ( p2_info[ :app_exts ].map{ | _, ext | ext[ :wmems ].size }.sum < RESUME_BELOW )
807
- @mutex.synchronize do
808
- p2_id = @socks[ p2 ]
809
- puts "ctlw resume #{ p2_id } #{ Time.new }"
810
- @ctlw.write( [ CTL_RESUME, p2_id ].pack( 'CQ>' ) )
811
- p2_info[ :paused ] = false
812
- end
813
- end
814
- end
815
- end
816
- end
817
-
818
- def loop_send_fin1( p2, app_id )
819
- Thread.new do
820
- 100.times do
821
- break if p2.closed?
822
-
823
- p2_info = @infos[ p2 ]
824
- break unless p2_info[ :p1_addr ]
825
-
826
- unless p2_info[ :fin1s ].include?( app_id )
827
- # puts "debug break send fin1 loop #{ Time.new }"
828
- break
829
- end
830
-
831
- @mutex.synchronize do
832
- ctlmsg = [
833
- 0,
834
- FIN1,
835
- app_id
836
- ].pack( 'Q>CQ>' )
837
-
838
- # puts "debug send FIN1 #{ app_id } #{ Time.new }"
839
- send_pack( p2, ctlmsg, p2_info[ :p1_addr ] )
840
- end
841
-
842
- sleep 1
843
- end
844
- end
845
- end
846
-
847
- def loop_send_fin2( p2, app_id )
848
- Thread.new do
849
- 100.times do
850
- break if p2.closed?
851
-
852
- p2_info = @infos[ p2 ]
853
- break unless p2_info[ :p1_addr ]
854
-
855
- unless p2_info[ :fin2s ].include?( app_id )
856
- # puts "debug break send fin2 loop #{ Time.new }"
857
- break
858
- end
859
-
860
- @mutex.synchronize do
861
- ctlmsg = [
862
- 0,
863
- FIN2,
864
- app_id
865
- ].pack( 'Q>CQ>' )
866
-
867
- # puts "debug send FIN2 #{ app_id } #{ Time.new }"
868
- send_pack( p2, ctlmsg, p2_info[ :p1_addr ] )
869
- end
870
-
871
- sleep 1
872
- end
873
- end
874
- end
875
-
876
- def loop_send_a_new_app( app )
877
- Thread.new do
878
- 100.times do
879
- break if app.closed?
880
-
881
- app_info = @infos[ app ]
882
- p2 = app_info[ :p2 ]
883
- break if p2.closed?
884
-
885
- p2_info = @infos[ p2 ]
886
-
887
- if p2_info[ :p1_addr ]
888
- app_id = @socks[ app ]
889
- shadow_id = p2_info[ :app_ids ][ app_id ]
890
-
891
- if shadow_id
892
- # puts "debug break a new app loop #{ Time.new }"
893
- break
894
- end
895
-
896
- @mutex.synchronize do
897
- ctlmsg = [ 0, A_NEW_APP, app_id ].pack( 'Q>CQ>' )
898
- # puts "debug send a new app #{ Time.new }"
899
- send_pack( p2, ctlmsg, p2_info[ :p1_addr ] )
900
- end
901
- end
902
-
903
- sleep 1
904
- end
905
- end
906
- end
907
-
908
- def send_heartbeat( p2, target_addr )
909
- ctlmsg = [ 0, HEARTBEAT, rand( 128 ) ].pack( 'Q>CC' )
910
- send_pack( p2, ctlmsg, target_addr )
911
- end
912
-
913
- def send_pack( sock, data, target_sockaddr )
914
- begin
915
- sock.sendmsg( data, 0, target_sockaddr )
916
- rescue IO::WaitWritable, Errno::EINTR => e
917
- puts "sendmsg #{ e.class } #{ Time.new }"
918
- end
919
- end
920
-
921
- def add_read( sock )
922
- return if sock.closed? || @reads.include?( sock )
923
-
924
- @reads << sock
925
- end
926
-
927
- def add_write( sock, data = nil )
928
- return if sock.closed? || @writes.include?( sock )
929
-
930
- @writes << sock
931
- end
932
-
933
- def add_closing( sock )
934
- return if sock.closed? || @closings.include?( sock )
935
-
936
- @reads.delete( sock )
937
- @closings << sock
938
- add_write( sock )
939
- end
940
-
941
- def close_p2( p2 )
942
- info = close_sock( p2 )
943
-
944
- info[ :chunks ].each do | filename |
945
- begin
946
- File.delete( File.join( @p2_chunk_dir, filename ) )
947
- rescue Errno::ENOENT
948
- end
949
- end
950
-
951
- info[ :app_exts ].each{ | _, ext | add_closing( ext[ :app ] ) }
952
- end
953
-
954
- def close_app( app )
955
- info = close_sock( app )
956
- p2 = info[ :p2 ]
957
- return if p2.closed?
958
-
959
- app_id = info[ :id ]
960
- p2_info = @infos[ p2 ]
961
- ext = p2_info[ :app_exts ][ app_id ]
962
- return unless ext
963
-
964
- ext[ :chunks ].each do | filename |
965
- begin
966
- File.delete( File.join( @app_chunk_dir, filename ) )
967
- rescue Errno::ENOENT
968
- end
969
- end
970
-
971
- if ext[ :is_shadow_closed ]
972
- del_app_ext( p2_info, app_id )
973
-
974
- unless p2_info[ :fin2s ].include?( app_id )
975
- # puts "debug 2-3. app.close -> ext.is_shadow_closed ? yes -> del ext -> loop send fin2 #{ Time.new }"
976
- p2_info[ :fin2s ] << app_id
977
- loop_send_fin2( p2, app_id )
978
- end
979
- elsif !p2_info[ :fin1s ].include?( app_id )
980
- # puts "debug 1-1. app.close -> ext.is_shadow_closed ? no -> send fin1 loop #{ Time.new }"
981
- p2_info[ :fin1s ] << app_id
982
- loop_send_fin1( p2, app_id )
983
- end
984
- end
985
-
986
- def close_sock( sock )
987
- sock.close
988
- @reads.delete( sock )
989
- @writes.delete( sock )
990
- @closings.delete( sock )
991
- @roles.delete( sock )
992
- info = @infos.delete( sock )
993
- sock_id = @socks.delete( sock )
994
- @sock_ids.delete( sock_id )
995
-
996
- info
997
- end
998
-
999
- def del_app_ext( p2_info, app_id )
1000
- p2_info[ :waitings ].delete( app_id )
1001
- ext = p2_info[ :app_exts ].delete( app_id )
1002
-
1003
- if ext
1004
- ext[ :chunks ].each do | filename |
1005
- begin
1006
- File.delete( File.join( @app_chunk_dir, filename ) )
1007
- rescue Errno::ENOENT
1008
- end
1009
- end
1010
- end
1011
-
1012
- shadow_id = p2_info[ :app_ids ].delete( app_id )
1013
-
1014
- if shadow_id
1015
- p2_info[ :shadow_ids ].delete( shadow_id )
1016
- end
1017
- end
1018
-
1019
- end
1020
- 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