girl 0.50.0 → 0.50.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of girl might be problematic. Click here for more details.

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