p2p2 0.6.3 → 0.6.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -1,3 +1,3 @@
1
- module P2p2
2
- VERSION = "0.6.3"
3
- end
1
+ module P2p2
2
+ VERSION = "0.6.4"
3
+ end
@@ -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