p2p2 0.6.3 → 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/p2p2.rb +6 -6
- data/lib/p2p2/head.rb +10 -10
- data/lib/p2p2/p1.rb +410 -413
- data/lib/p2p2/p2.rb +447 -447
- data/lib/p2p2/p2pd.rb +222 -222
- data/lib/p2p2/version.rb +3 -3
- data/p2p2.gemspec +29 -29
- metadata +3 -2
data/lib/p2p2/p2pd.rb
CHANGED
@@ -1,222 +1,222 @@
|
|
1
|
-
require 'p2p2/head'
|
2
|
-
require 'p2p2/version'
|
3
|
-
require 'socket'
|
4
|
-
|
5
|
-
##
|
6
|
-
# P2p2::P2pd - 处于各自nat里的两端p2p。匹配服务器端。
|
7
|
-
#
|
8
|
-
#```
|
9
|
-
# p2pd p2pd
|
10
|
-
# ^ ^
|
11
|
-
# ^ ^
|
12
|
-
# ssh --> p2 --> encode --> nat --> nat --> p1 --> decode --> sshd
|
13
|
-
#
|
14
|
-
#```
|
15
|
-
#
|
16
|
-
# usage
|
17
|
-
# =====
|
18
|
-
#
|
19
|
-
# 1. Girl::P2pd.new( 5050 ).looping # @server
|
20
|
-
#
|
21
|
-
# 2. Girl::P1.new( 'your.server.ip', 5050, '127.0.0.1', 22, '周立波' ).looping # @home1
|
22
|
-
#
|
23
|
-
# 3. Girl::P2.new( 'your.server.ip', 5050, '0.0.0.0', 2222, '周立波' ).looping # @home2
|
24
|
-
#
|
25
|
-
# 4. ssh -p2222 libo@localhost
|
26
|
-
#
|
27
|
-
module P2p2
|
28
|
-
class P2pd
|
29
|
-
|
30
|
-
##
|
31
|
-
# roomd_port 配对服务器端口
|
32
|
-
# roomd_dir 可在该目录下看到所有的p1
|
33
|
-
def initialize( roomd_port = 5050, roomd_dir = '/tmp' )
|
34
|
-
@roomd_port = roomd_port
|
35
|
-
@roomd_dir = roomd_dir
|
36
|
-
@mutex = Mutex.new
|
37
|
-
@roles = {} # sock => :roomd / :room
|
38
|
-
@pending_p1s = {} # title => room
|
39
|
-
@pending_p2s = {} # title => room
|
40
|
-
@infos = {}
|
41
|
-
@reads = []
|
42
|
-
|
43
|
-
new_roomd
|
44
|
-
end
|
45
|
-
|
46
|
-
def looping
|
47
|
-
puts 'looping'
|
48
|
-
|
49
|
-
loop_expire
|
50
|
-
|
51
|
-
loop do
|
52
|
-
rs, _ = IO.select( @reads )
|
53
|
-
|
54
|
-
@mutex.synchronize do
|
55
|
-
rs.each do | sock |
|
56
|
-
case @roles[ sock ]
|
57
|
-
when :roomd
|
58
|
-
read_roomd( sock )
|
59
|
-
when :room
|
60
|
-
read_room( sock )
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
rescue Interrupt => e
|
66
|
-
puts e.class
|
67
|
-
quit!
|
68
|
-
end
|
69
|
-
|
70
|
-
def quit!
|
71
|
-
exit
|
72
|
-
end
|
73
|
-
|
74
|
-
private
|
75
|
-
|
76
|
-
def loop_expire
|
77
|
-
Thread.new do
|
78
|
-
loop do
|
79
|
-
sleep 900
|
80
|
-
|
81
|
-
if @infos.any?
|
82
|
-
@mutex.synchronize do
|
83
|
-
now = Time.new
|
84
|
-
|
85
|
-
@infos.select{ | _, info | info[ :last_coming_at ] && ( now - info[ :last_coming_at ] > 1800 ) }.each do | room, _ |
|
86
|
-
close_sock( room )
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
def read_roomd( sock )
|
95
|
-
begin
|
96
|
-
room, addr = sock.accept_nonblock
|
97
|
-
rescue IO::WaitReadable, Errno::EINTR
|
98
|
-
return
|
99
|
-
end
|
100
|
-
|
101
|
-
@roles[ room ] = :room
|
102
|
-
@infos[ room ] = {
|
103
|
-
title: nil,
|
104
|
-
last_coming_at: nil,
|
105
|
-
sockaddr: addr.to_sockaddr
|
106
|
-
}
|
107
|
-
@reads << room
|
108
|
-
end
|
109
|
-
|
110
|
-
def read_room( sock )
|
111
|
-
begin
|
112
|
-
data = sock.read_nonblock( PACK_SIZE )
|
113
|
-
rescue IO::WaitReadable, Errno::EINTR, IO::WaitWritable
|
114
|
-
return
|
115
|
-
rescue Exception => e
|
116
|
-
close_sock( sock )
|
117
|
-
return
|
118
|
-
end
|
119
|
-
|
120
|
-
info = @infos[ sock ]
|
121
|
-
info[ :last_coming_at ] = Time.new
|
122
|
-
|
123
|
-
until data.empty?
|
124
|
-
ctl_num = data[ 0 ].unpack( 'C' ).first
|
125
|
-
|
126
|
-
case ctl_num
|
127
|
-
when HEARTBEAT
|
128
|
-
data = data[ 1..-1 ]
|
129
|
-
when SET_TITLE
|
130
|
-
len = data[ 1, 2 ].unpack( 'n' ).first
|
131
|
-
|
132
|
-
if len > 255
|
133
|
-
puts "title too long"
|
134
|
-
close_sock( sock )
|
135
|
-
return
|
136
|
-
end
|
137
|
-
|
138
|
-
title = data[ 3, len ]
|
139
|
-
|
140
|
-
if @pending_p2s.include?( title )
|
141
|
-
p2 = @pending_p2s[ title ]
|
142
|
-
p2_info = @infos[ p2 ]
|
143
|
-
sock.write( p2_info[ :sockaddr ] )
|
144
|
-
p2.write( info[ :sockaddr ] )
|
145
|
-
elsif @pending_p1s.include?( title )
|
146
|
-
puts "pending p1 #{ title.inspect } already exist"
|
147
|
-
close_sock( sock )
|
148
|
-
return
|
149
|
-
else
|
150
|
-
@pending_p1s[ title ] = sock
|
151
|
-
info[ :title ] = title
|
152
|
-
|
153
|
-
begin
|
154
|
-
File.open( File.join( @roomd_dir, title ), 'w' )
|
155
|
-
rescue Errno::ENOENT, ArgumentError => e
|
156
|
-
puts "open title path #{ e.class }"
|
157
|
-
close_sock( sock )
|
158
|
-
return
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
data = data[ ( 3 + len )..-1 ]
|
163
|
-
when PAIRING
|
164
|
-
len = data[ 1, 2 ].unpack( 'n' ).first
|
165
|
-
|
166
|
-
if len > 255
|
167
|
-
puts 'pairing title too long'
|
168
|
-
close_sock( sock )
|
169
|
-
return
|
170
|
-
end
|
171
|
-
|
172
|
-
title = data[ 3, len ]
|
173
|
-
|
174
|
-
if @pending_p1s.include?( title )
|
175
|
-
p1 = @pending_p1s[ title ]
|
176
|
-
p1_info = @infos[ p1 ]
|
177
|
-
sock.write( p1_info[ :sockaddr ] )
|
178
|
-
p1.write( info[ :sockaddr ] )
|
179
|
-
elsif @pending_p2s.include?( title )
|
180
|
-
puts "pending p2 #{ title.inspect } already exist"
|
181
|
-
close_sock( sock )
|
182
|
-
return
|
183
|
-
else
|
184
|
-
@pending_p2s[ title ] = sock
|
185
|
-
info[ :title ] = title
|
186
|
-
end
|
187
|
-
|
188
|
-
data = data[ ( 3 + len )..-1 ]
|
189
|
-
end
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
def close_sock( sock )
|
194
|
-
sock.close
|
195
|
-
@roles.delete( sock )
|
196
|
-
@reads.delete( sock )
|
197
|
-
info = @infos.delete( sock )
|
198
|
-
|
199
|
-
if info && info[ :title ]
|
200
|
-
@pending_p1s.delete( info[ :title ] )
|
201
|
-
@pending_p2s.delete( info[ :title ] )
|
202
|
-
|
203
|
-
begin
|
204
|
-
File.delete( File.join( @roomd_dir, info[ :title ] ) )
|
205
|
-
rescue Errno::ENOENT
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
info
|
210
|
-
end
|
211
|
-
|
212
|
-
def new_roomd
|
213
|
-
roomd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
|
214
|
-
roomd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
|
215
|
-
roomd.bind( Socket.pack_sockaddr_in( @roomd_port, '0.0.0.0' ) )
|
216
|
-
roomd.listen( 511 )
|
217
|
-
|
218
|
-
@roles[ roomd ] = :roomd
|
219
|
-
@reads << roomd
|
220
|
-
end
|
221
|
-
end
|
222
|
-
end
|
1
|
+
require 'p2p2/head'
|
2
|
+
require 'p2p2/version'
|
3
|
+
require 'socket'
|
4
|
+
|
5
|
+
##
|
6
|
+
# P2p2::P2pd - 处于各自nat里的两端p2p。匹配服务器端。
|
7
|
+
#
|
8
|
+
#```
|
9
|
+
# p2pd p2pd
|
10
|
+
# ^ ^
|
11
|
+
# ^ ^
|
12
|
+
# ssh --> p2 --> encode --> nat --> nat --> p1 --> decode --> sshd
|
13
|
+
#
|
14
|
+
#```
|
15
|
+
#
|
16
|
+
# usage
|
17
|
+
# =====
|
18
|
+
#
|
19
|
+
# 1. Girl::P2pd.new( 5050 ).looping # @server
|
20
|
+
#
|
21
|
+
# 2. Girl::P1.new( 'your.server.ip', 5050, '127.0.0.1', 22, '周立波' ).looping # @home1
|
22
|
+
#
|
23
|
+
# 3. Girl::P2.new( 'your.server.ip', 5050, '0.0.0.0', 2222, '周立波' ).looping # @home2
|
24
|
+
#
|
25
|
+
# 4. ssh -p2222 libo@localhost
|
26
|
+
#
|
27
|
+
module P2p2
|
28
|
+
class P2pd
|
29
|
+
|
30
|
+
##
|
31
|
+
# roomd_port 配对服务器端口
|
32
|
+
# roomd_dir 可在该目录下看到所有的p1
|
33
|
+
def initialize( roomd_port = 5050, roomd_dir = '/tmp' )
|
34
|
+
@roomd_port = roomd_port
|
35
|
+
@roomd_dir = roomd_dir
|
36
|
+
@mutex = Mutex.new
|
37
|
+
@roles = {} # sock => :roomd / :room
|
38
|
+
@pending_p1s = {} # title => room
|
39
|
+
@pending_p2s = {} # title => room
|
40
|
+
@infos = {}
|
41
|
+
@reads = []
|
42
|
+
|
43
|
+
new_roomd
|
44
|
+
end
|
45
|
+
|
46
|
+
def looping
|
47
|
+
puts 'looping'
|
48
|
+
|
49
|
+
loop_expire
|
50
|
+
|
51
|
+
loop do
|
52
|
+
rs, _ = IO.select( @reads )
|
53
|
+
|
54
|
+
@mutex.synchronize do
|
55
|
+
rs.each do | sock |
|
56
|
+
case @roles[ sock ]
|
57
|
+
when :roomd
|
58
|
+
read_roomd( sock )
|
59
|
+
when :room
|
60
|
+
read_room( sock )
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
rescue Interrupt => e
|
66
|
+
puts e.class
|
67
|
+
quit!
|
68
|
+
end
|
69
|
+
|
70
|
+
def quit!
|
71
|
+
exit
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def loop_expire
|
77
|
+
Thread.new do
|
78
|
+
loop do
|
79
|
+
sleep 900
|
80
|
+
|
81
|
+
if @infos.any?
|
82
|
+
@mutex.synchronize do
|
83
|
+
now = Time.new
|
84
|
+
|
85
|
+
@infos.select{ | _, info | info[ :last_coming_at ] && ( now - info[ :last_coming_at ] > 1800 ) }.each do | room, _ |
|
86
|
+
close_sock( room )
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def read_roomd( sock )
|
95
|
+
begin
|
96
|
+
room, addr = sock.accept_nonblock
|
97
|
+
rescue IO::WaitReadable, Errno::EINTR
|
98
|
+
return
|
99
|
+
end
|
100
|
+
|
101
|
+
@roles[ room ] = :room
|
102
|
+
@infos[ room ] = {
|
103
|
+
title: nil,
|
104
|
+
last_coming_at: nil,
|
105
|
+
sockaddr: addr.to_sockaddr
|
106
|
+
}
|
107
|
+
@reads << room
|
108
|
+
end
|
109
|
+
|
110
|
+
def read_room( sock )
|
111
|
+
begin
|
112
|
+
data = sock.read_nonblock( PACK_SIZE )
|
113
|
+
rescue IO::WaitReadable, Errno::EINTR, IO::WaitWritable
|
114
|
+
return
|
115
|
+
rescue Exception => e
|
116
|
+
close_sock( sock )
|
117
|
+
return
|
118
|
+
end
|
119
|
+
|
120
|
+
info = @infos[ sock ]
|
121
|
+
info[ :last_coming_at ] = Time.new
|
122
|
+
|
123
|
+
until data.empty?
|
124
|
+
ctl_num = data[ 0 ].unpack( 'C' ).first
|
125
|
+
|
126
|
+
case ctl_num
|
127
|
+
when HEARTBEAT
|
128
|
+
data = data[ 1..-1 ]
|
129
|
+
when SET_TITLE
|
130
|
+
len = data[ 1, 2 ].unpack( 'n' ).first
|
131
|
+
|
132
|
+
if len > 255
|
133
|
+
puts "title too long"
|
134
|
+
close_sock( sock )
|
135
|
+
return
|
136
|
+
end
|
137
|
+
|
138
|
+
title = data[ 3, len ]
|
139
|
+
|
140
|
+
if @pending_p2s.include?( title )
|
141
|
+
p2 = @pending_p2s[ title ]
|
142
|
+
p2_info = @infos[ p2 ]
|
143
|
+
sock.write( p2_info[ :sockaddr ] )
|
144
|
+
p2.write( info[ :sockaddr ] )
|
145
|
+
elsif @pending_p1s.include?( title )
|
146
|
+
puts "pending p1 #{ title.inspect } already exist"
|
147
|
+
close_sock( sock )
|
148
|
+
return
|
149
|
+
else
|
150
|
+
@pending_p1s[ title ] = sock
|
151
|
+
info[ :title ] = title
|
152
|
+
|
153
|
+
begin
|
154
|
+
File.open( File.join( @roomd_dir, title ), 'w' )
|
155
|
+
rescue Errno::ENOENT, ArgumentError => e
|
156
|
+
puts "open title path #{ e.class }"
|
157
|
+
close_sock( sock )
|
158
|
+
return
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
data = data[ ( 3 + len )..-1 ]
|
163
|
+
when PAIRING
|
164
|
+
len = data[ 1, 2 ].unpack( 'n' ).first
|
165
|
+
|
166
|
+
if len > 255
|
167
|
+
puts 'pairing title too long'
|
168
|
+
close_sock( sock )
|
169
|
+
return
|
170
|
+
end
|
171
|
+
|
172
|
+
title = data[ 3, len ]
|
173
|
+
|
174
|
+
if @pending_p1s.include?( title )
|
175
|
+
p1 = @pending_p1s[ title ]
|
176
|
+
p1_info = @infos[ p1 ]
|
177
|
+
sock.write( p1_info[ :sockaddr ] )
|
178
|
+
p1.write( info[ :sockaddr ] )
|
179
|
+
elsif @pending_p2s.include?( title )
|
180
|
+
puts "pending p2 #{ title.inspect } already exist"
|
181
|
+
close_sock( sock )
|
182
|
+
return
|
183
|
+
else
|
184
|
+
@pending_p2s[ title ] = sock
|
185
|
+
info[ :title ] = title
|
186
|
+
end
|
187
|
+
|
188
|
+
data = data[ ( 3 + len )..-1 ]
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def close_sock( sock )
|
194
|
+
sock.close
|
195
|
+
@roles.delete( sock )
|
196
|
+
@reads.delete( sock )
|
197
|
+
info = @infos.delete( sock )
|
198
|
+
|
199
|
+
if info && info[ :title ]
|
200
|
+
@pending_p1s.delete( info[ :title ] )
|
201
|
+
@pending_p2s.delete( info[ :title ] )
|
202
|
+
|
203
|
+
begin
|
204
|
+
File.delete( File.join( @roomd_dir, info[ :title ] ) )
|
205
|
+
rescue Errno::ENOENT
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
info
|
210
|
+
end
|
211
|
+
|
212
|
+
def new_roomd
|
213
|
+
roomd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
|
214
|
+
roomd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
|
215
|
+
roomd.bind( Socket.pack_sockaddr_in( @roomd_port, '0.0.0.0' ) )
|
216
|
+
roomd.listen( 511 )
|
217
|
+
|
218
|
+
@roles[ roomd ] = :roomd
|
219
|
+
@reads << roomd
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
data/lib/p2p2/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
module P2p2
|
2
|
-
VERSION = "0.6.
|
3
|
-
end
|
1
|
+
module P2p2
|
2
|
+
VERSION = "0.6.4"
|
3
|
+
end
|
data/p2p2.gemspec
CHANGED
@@ -1,29 +1,29 @@
|
|
1
|
-
|
2
|
-
lib = File.expand_path("../lib", __FILE__)
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require "p2p2/version"
|
5
|
-
|
6
|
-
Gem::Specification.new do |spec|
|
7
|
-
spec.name = "p2p2"
|
8
|
-
spec.version = P2p2::VERSION
|
9
|
-
spec.authors = ["takafan"]
|
10
|
-
spec.email = ["qqtakafan@gmail.com"]
|
11
|
-
|
12
|
-
spec.summary = %q{p2p}
|
13
|
-
spec.description = %q{p2p even both sides under its nat.}
|
14
|
-
spec.homepage = "https://github.com/takafan/p2p2"
|
15
|
-
spec.license = "MIT"
|
16
|
-
|
17
|
-
spec.files = %w[
|
18
|
-
p2p2.gemspec
|
19
|
-
lib/p2p2.rb
|
20
|
-
lib/p2p2/head.rb
|
21
|
-
lib/p2p2/hex.rb
|
22
|
-
lib/p2p2/p1.rb
|
23
|
-
lib/p2p2/p2.rb
|
24
|
-
lib/p2p2/p2pd.rb
|
25
|
-
lib/p2p2/version.rb
|
26
|
-
]
|
27
|
-
|
28
|
-
spec.require_paths = ["lib"]
|
29
|
-
end
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "p2p2/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "p2p2"
|
8
|
+
spec.version = P2p2::VERSION
|
9
|
+
spec.authors = ["takafan"]
|
10
|
+
spec.email = ["qqtakafan@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{p2p}
|
13
|
+
spec.description = %q{p2p even both sides under its nat.}
|
14
|
+
spec.homepage = "https://github.com/takafan/p2p2"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = %w[
|
18
|
+
p2p2.gemspec
|
19
|
+
lib/p2p2.rb
|
20
|
+
lib/p2p2/head.rb
|
21
|
+
lib/p2p2/hex.rb
|
22
|
+
lib/p2p2/p1.rb
|
23
|
+
lib/p2p2/p2.rb
|
24
|
+
lib/p2p2/p2pd.rb
|
25
|
+
lib/p2p2/version.rb
|
26
|
+
]
|
27
|
+
|
28
|
+
spec.require_paths = ["lib"]
|
29
|
+
end
|