serverengine 2.0.2 → 2.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Changelog +4 -0
- data/lib/serverengine/socket_manager.rb +32 -29
- data/lib/serverengine/socket_manager_unix.rb +15 -5
- data/lib/serverengine/socket_manager_win.rb +42 -39
- data/lib/serverengine/version.rb +1 -1
- data/spec/socket_manager_spec.rb +130 -46
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9e23d663095d365596482cfc7e95d2263b6c5d64
|
4
|
+
data.tar.gz: 723275d864b001541c2dc7534320483e79d19c60
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 346188cb66f8e835afde847163f0266caad0154e92da190c2e307ed472aacceed4e9fe20b067f1e5422ef7d281237854e8bfaa941f8243b45917db43f9d6d733
|
7
|
+
data.tar.gz: 122f579082a0792539aa79e1d864f144454243bcdb7091c6962e3350bd738ff049fd282ad61c5f314b14b948c6d3d4ec59343970653d994f1573536d60742747
|
data/Changelog
CHANGED
@@ -26,34 +26,36 @@ module ServerEngine
|
|
26
26
|
@path = path
|
27
27
|
end
|
28
28
|
|
29
|
-
def
|
29
|
+
def listen(proto, bind, port)
|
30
|
+
bind_ip = IPAddr.new(IPSocket.getaddress(bind))
|
31
|
+
family = bind_ip.ipv6? ? Socket::AF_INET6 : Socket::AF_INET
|
32
|
+
|
33
|
+
listen_method = case proto
|
34
|
+
when :tcp then :listen_tcp
|
35
|
+
when :udp then :listen_udp
|
36
|
+
else
|
37
|
+
raise ArgumentError, "unknown protocol: #{proto}"
|
38
|
+
end
|
30
39
|
peer = connect_peer(@path)
|
31
40
|
begin
|
32
|
-
SocketManager.send_peer(peer, [Process.pid,
|
41
|
+
SocketManager.send_peer(peer, [Process.pid, listen_method, bind, port])
|
33
42
|
res = SocketManager.recv_peer(peer)
|
34
43
|
if res.is_a?(Exception)
|
35
44
|
raise res
|
36
45
|
else
|
37
|
-
return
|
46
|
+
return send(:recv, family, proto, peer, res)
|
38
47
|
end
|
39
48
|
ensure
|
40
49
|
peer.close
|
41
50
|
end
|
42
51
|
end
|
43
52
|
|
53
|
+
def listen_tcp(bind, port)
|
54
|
+
listen(:tcp, bind, port)
|
55
|
+
end
|
56
|
+
|
44
57
|
def listen_udp(bind, port)
|
45
|
-
|
46
|
-
begin
|
47
|
-
SocketManager.send_peer(peer, [Process.pid, :listen_udp, bind, port])
|
48
|
-
res = SocketManager.recv_peer(peer)
|
49
|
-
if res.is_a?(Exception)
|
50
|
-
raise res
|
51
|
-
else
|
52
|
-
return recv_udp(peer, res)
|
53
|
-
end
|
54
|
-
ensure
|
55
|
-
peer.close
|
56
|
-
end
|
58
|
+
listen(:udp, bind, port)
|
57
59
|
end
|
58
60
|
end
|
59
61
|
|
@@ -94,28 +96,29 @@ module ServerEngine
|
|
94
96
|
|
95
97
|
private
|
96
98
|
|
97
|
-
def
|
99
|
+
def listen(proto, bind, port)
|
100
|
+
sockets, new_method = case proto
|
101
|
+
when :tcp then [@tcp_sockets, :listen_tcp_new]
|
102
|
+
when :udp then [@udp_sockets, :listen_udp_new]
|
103
|
+
else
|
104
|
+
raise ArgumentError, "invalid protocol: #{proto}"
|
105
|
+
end
|
98
106
|
key, bind_ip = resolve_bind_key(bind, port)
|
99
107
|
|
100
108
|
@mutex.synchronize do
|
101
|
-
|
102
|
-
|
103
|
-
else
|
104
|
-
return @tcp_sockets[key] = listen_tcp_new(bind_ip, port)
|
109
|
+
unless sockets.has_key?(key)
|
110
|
+
sockets[key] = send(new_method, bind_ip, port)
|
105
111
|
end
|
112
|
+
return sockets[key]
|
106
113
|
end
|
107
114
|
end
|
108
115
|
|
109
|
-
def
|
110
|
-
|
116
|
+
def listen_tcp(bind, port)
|
117
|
+
listen(:tcp, bind, port)
|
118
|
+
end
|
111
119
|
|
112
|
-
|
113
|
-
|
114
|
-
return @udp_sockets[key]
|
115
|
-
else
|
116
|
-
return @udp_sockets[key] = listen_udp_new(bind_ip, port)
|
117
|
-
end
|
118
|
-
end
|
120
|
+
def listen_udp(bind, port)
|
121
|
+
listen(:udp, bind, port)
|
119
122
|
end
|
120
123
|
|
121
124
|
def resolve_bind_key(bind, port)
|
@@ -27,12 +27,22 @@ module ServerEngine
|
|
27
27
|
return UNIXSocket.new(path)
|
28
28
|
end
|
29
29
|
|
30
|
-
def
|
31
|
-
|
30
|
+
def recv(family, proto, peer, sent)
|
31
|
+
server_class = case proto
|
32
|
+
when :tcp then TCPServer
|
33
|
+
when :udp then UDPSocket
|
34
|
+
else
|
35
|
+
raise ArgumentError, "invalid protocol: #{proto}"
|
36
|
+
end
|
37
|
+
peer.recv_io(server_class)
|
32
38
|
end
|
33
39
|
|
34
|
-
def
|
35
|
-
|
40
|
+
def recv_tcp(family, peer, sent)
|
41
|
+
recv(family, :tcp, peer, sent)
|
42
|
+
end
|
43
|
+
|
44
|
+
def recv_udp(family, peer, sent)
|
45
|
+
recv(family, :udp, peer, sent)
|
36
46
|
end
|
37
47
|
end
|
38
48
|
|
@@ -49,7 +59,7 @@ module ServerEngine
|
|
49
59
|
if bind_ip.ipv6?
|
50
60
|
sock = UDPSocket.new(Socket::AF_INET6)
|
51
61
|
else
|
52
|
-
sock = UDPSocket.new
|
62
|
+
sock = UDPSocket.new(Socket::AF_INET)
|
53
63
|
end
|
54
64
|
sock.bind(bind_ip.to_s, port)
|
55
65
|
return sock
|
@@ -30,74 +30,77 @@ module ServerEngine
|
|
30
30
|
return TCPSocket.open("127.0.0.1", addr)
|
31
31
|
end
|
32
32
|
|
33
|
-
def
|
34
|
-
|
33
|
+
def recv(family, proto, peer, sent)
|
34
|
+
server_class, protocol = case proto
|
35
|
+
when :tcp then [TCPServer, Socket::SOCK_STREAM]
|
36
|
+
when :udp then [UDPSocket, Socket::SOCK_DGRAM]
|
37
|
+
else
|
38
|
+
raise ArgumentError, "invalid protocol: #{proto}"
|
39
|
+
end
|
35
40
|
|
36
|
-
|
41
|
+
proto_info = WinSock::WSAPROTOCOL_INFO.from_bin(sent)
|
42
|
+
|
43
|
+
handle = WinSock.WSASocketA(family, protocol, 0, proto_info, 0, 1)
|
37
44
|
if handle == WinSock::INVALID_SOCKET
|
38
45
|
RbWinSock.raise_last_error("WSASocketA(2)")
|
39
46
|
end
|
40
47
|
|
41
|
-
return RbWinSock.wrap_io_handle(
|
48
|
+
return RbWinSock.wrap_io_handle(server_class, handle, 0)
|
42
49
|
end
|
43
50
|
|
44
|
-
def
|
45
|
-
|
46
|
-
|
47
|
-
handle = WinSock.WSASocketA(Socket::AF_INET, Socket::SOCK_DGRAM, 0, proto, 0, 1)
|
48
|
-
if handle == WinSock::INVALID_SOCKET
|
49
|
-
RbWinSock.raise_last_error("WSASocketA(2)")
|
50
|
-
end
|
51
|
+
def recv_tcp(family, peer, sent)
|
52
|
+
recv(family, :tcp, peer, sent)
|
53
|
+
end
|
51
54
|
|
52
|
-
|
55
|
+
def recv_udp(family, peer, sent)
|
56
|
+
recv(family, :udp, peer, sent)
|
53
57
|
end
|
54
58
|
end
|
55
59
|
|
56
60
|
module ServerModule
|
57
61
|
private
|
58
62
|
|
59
|
-
|
63
|
+
TCP_OPTIONS = [Socket::SOCK_STREAM, Socket::IPPROTO_TCP, TCPServer, true]
|
64
|
+
UDP_OPTIONS = [Socket::SOCK_DGRAM, Socket::IPPROTO_UDP, UDPSocket, false]
|
65
|
+
|
66
|
+
def listen_new(proto, bind_ip, port)
|
67
|
+
protocol, proto_info, klass, listen = case proto
|
68
|
+
when :tcp then TCP_OPTIONS
|
69
|
+
when :udp then UDP_OPTIONS
|
70
|
+
else
|
71
|
+
raise ArgumentError, "invalid protocol: #{proto}"
|
72
|
+
end
|
73
|
+
family = bind_ip.ipv6? ? Socket::AF_INET6 : Socket::AF_INET
|
74
|
+
|
60
75
|
sock_addr = Socket.pack_sockaddr_in(port, bind_ip.to_s)
|
61
76
|
|
62
|
-
handle = WinSock.WSASocketA(
|
77
|
+
handle = WinSock.WSASocketA(family, protocol, proto_info, nil, 0, 1)
|
63
78
|
if handle == WinSock::INVALID_SOCKET
|
64
79
|
RbWinSock.raise_last_error("WSASocketA(2)")
|
65
80
|
end
|
66
81
|
|
67
|
-
# wrap in TCPServer immediately so that its finalizer safely closes the handle
|
68
|
-
sock = RbWinSock.wrap_io_handle(
|
82
|
+
# wrap in TCPServer/UDPSocket immediately so that its finalizer safely closes the handle
|
83
|
+
sock = RbWinSock.wrap_io_handle(klass, handle, 0)
|
69
84
|
|
70
85
|
unless WinSock.bind(sock.handle, sock_addr, sock_addr.bytesize) == 0
|
71
86
|
RbWinSock.raise_last_error("bind(2)")
|
72
87
|
end
|
73
|
-
unless WinSock.listen(sock.handle, Socket::SOMAXCONN) == 0
|
74
|
-
RbWinSock.raise_last_error("listen(2)")
|
75
|
-
end
|
76
|
-
|
77
|
-
return sock
|
78
|
-
end
|
79
|
-
|
80
|
-
def listen_udp_new(bind_ip, port)
|
81
|
-
sock_addr = Socket.pack_sockaddr_in(port, bind_ip.to_s)
|
82
|
-
|
83
|
-
if IPAddr.new(IPSocket.getaddress(bind_ip.to_s)).ipv4?
|
84
|
-
handle = WinSock.WSASocketA(Socket::AF_INET, Socket::SOCK_DGRAM, Socket::IPPROTO_UDP, nil, 0, 1)
|
85
|
-
else
|
86
|
-
handle = WinSock.WSASocketA(Socket::AF_INET6, Socket::SOCK_DGRAM, Socket::IPPROTO_UDP, nil, 0, 1)
|
87
|
-
end
|
88
88
|
|
89
|
-
if
|
90
|
-
|
89
|
+
if listen
|
90
|
+
unless WinSock.listen(sock.handle, Socket::SOMAXCONN) == 0
|
91
|
+
RbWinSock.raise_last_error("listen(2)")
|
92
|
+
end
|
91
93
|
end
|
92
94
|
|
93
|
-
|
94
|
-
|
95
|
+
sock
|
96
|
+
end
|
95
97
|
|
96
|
-
|
97
|
-
|
98
|
-
|
98
|
+
def listen_tcp_new(bind_ip, port)
|
99
|
+
listen_new(:tcp, bind_ip, port)
|
100
|
+
end
|
99
101
|
|
100
|
-
|
102
|
+
def listen_udp_new(bind_ip, port)
|
103
|
+
listen_new(:udp, bind_ip, port)
|
101
104
|
end
|
102
105
|
|
103
106
|
def htons(h)
|
data/lib/serverengine/version.rb
CHANGED
data/spec/socket_manager_spec.rb
CHANGED
@@ -1,57 +1,134 @@
|
|
1
|
+
require 'socket'
|
1
2
|
|
2
3
|
describe ServerEngine::SocketManager do
|
3
4
|
include_context 'test server and worker'
|
4
5
|
|
5
6
|
let(:server_path) do
|
6
|
-
|
7
|
+
if ServerEngine.windows?
|
8
|
+
24223
|
9
|
+
else
|
10
|
+
'tmp/socket_manager_test.sock'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:test_port) do
|
15
|
+
9101
|
7
16
|
end
|
8
17
|
|
9
18
|
after(:each) do
|
10
|
-
File.unlink(server_path) if File.exist?(server_path)
|
19
|
+
File.unlink(server_path) if server_path.is_a?(String) && File.exist?(server_path)
|
11
20
|
end
|
12
21
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
22
|
+
context 'with thread' do
|
23
|
+
context 'using ipv4' do
|
24
|
+
it 'works' do
|
25
|
+
server = SocketManager::Server.open(server_path)
|
17
26
|
|
18
|
-
|
19
|
-
|
20
|
-
end
|
27
|
+
mutex = Mutex.new
|
28
|
+
server_thread_started = false
|
21
29
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
30
|
+
thread = Thread.new do
|
31
|
+
mutex.lock
|
32
|
+
server_thread_started = true
|
33
|
+
|
34
|
+
begin
|
35
|
+
client = ServerEngine::SocketManager::Client.new(server_path)
|
36
|
+
|
37
|
+
tcp = client.listen_tcp('127.0.0.1', test_port)
|
38
|
+
udp = client.listen_udp('127.0.0.1', test_port)
|
39
|
+
|
40
|
+
incr_test_state(:is_tcp_server) if tcp.is_a?(TCPServer)
|
41
|
+
incr_test_state(:is_udp_socket) if udp.is_a?(UDPSocket)
|
42
|
+
|
43
|
+
mutex.unlock
|
44
|
+
|
45
|
+
data, _from = udp.recvfrom(10)
|
46
|
+
incr_test_state(:udp_data_sent) if data == "ok"
|
47
|
+
|
48
|
+
s = tcp.accept
|
49
|
+
s.write("ok")
|
50
|
+
s.close
|
51
|
+
rescue => e
|
52
|
+
p(here: "rescue in server thread", error: e)
|
53
|
+
e.backtrace.each do |bt|
|
54
|
+
STDERR.puts bt
|
55
|
+
end
|
56
|
+
raise
|
57
|
+
ensure
|
58
|
+
tcp.close
|
59
|
+
udp.close
|
60
|
+
end
|
61
|
+
end
|
26
62
|
|
27
|
-
|
28
|
-
|
29
|
-
server = SocketManager::Server.open(server_port)
|
63
|
+
sleep 0.1 until server_thread_started
|
64
|
+
sleep 0.1 while mutex.locked?
|
30
65
|
|
31
|
-
|
66
|
+
u = UDPSocket.new(Socket::AF_INET)
|
67
|
+
u.send "ok", 0, '127.0.0.1', test_port
|
68
|
+
u.close
|
32
69
|
|
33
|
-
|
34
|
-
|
35
|
-
|
70
|
+
t = TCPSocket.open('127.0.0.1', test_port)
|
71
|
+
t.read.should == "ok"
|
72
|
+
t.close
|
36
73
|
|
37
|
-
|
38
|
-
|
74
|
+
server.close
|
75
|
+
thread.join
|
39
76
|
|
40
|
-
|
41
|
-
|
77
|
+
test_state(:is_tcp_server).should == 1
|
78
|
+
test_state(:is_udp_socket).should == 1
|
79
|
+
test_state(:udp_data_sent).should == 1
|
80
|
+
end
|
81
|
+
end
|
42
82
|
|
43
|
-
|
44
|
-
|
45
|
-
|
83
|
+
context 'using ipv6' do
|
84
|
+
it 'works' do
|
85
|
+
server = SocketManager::Server.open(server_path)
|
86
|
+
|
87
|
+
mutex = Mutex.new
|
88
|
+
server_thread_started = false
|
89
|
+
|
90
|
+
thread = Thread.new do
|
91
|
+
Thread.current.abort_on_exception = true
|
92
|
+
mutex.lock
|
93
|
+
server_thread_started = true
|
94
|
+
|
95
|
+
begin
|
96
|
+
client = ServerEngine::SocketManager::Client.new(server_path)
|
97
|
+
|
98
|
+
tcp = client.listen_tcp('::1', test_port)
|
99
|
+
udp = client.listen_udp('::1', test_port)
|
100
|
+
|
101
|
+
incr_test_state(:is_tcp_server) if tcp.is_a?(TCPServer)
|
102
|
+
incr_test_state(:is_udp_socket) if udp.is_a?(UDPSocket)
|
103
|
+
|
104
|
+
mutex.unlock
|
105
|
+
|
106
|
+
data, _from = udp.recvfrom(10)
|
107
|
+
incr_test_state(:udp_data_sent) if data == "ok"
|
108
|
+
|
109
|
+
s = tcp.accept
|
110
|
+
s.write("ok")
|
111
|
+
s.close
|
112
|
+
rescue => e
|
113
|
+
p(here: "rescue in server thread", error: e)
|
114
|
+
e.backtrace.each do |bt|
|
115
|
+
STDERR.puts bt
|
116
|
+
end
|
117
|
+
raise
|
118
|
+
ensure
|
119
|
+
tcp.close
|
120
|
+
udp.close
|
121
|
+
end
|
46
122
|
end
|
47
123
|
|
48
|
-
sleep 1
|
124
|
+
sleep 0.1 until server_thread_started
|
125
|
+
sleep 0.1 while mutex.locked?
|
49
126
|
|
50
|
-
u = UDPSocket.new
|
51
|
-
u.send "ok", 0, '
|
127
|
+
u = UDPSocket.new(Socket::AF_INET6)
|
128
|
+
u.send "ok", 0, '::1', test_port
|
52
129
|
u.close
|
53
130
|
|
54
|
-
t = TCPSocket.open('
|
131
|
+
t = TCPSocket.open('::1', test_port)
|
55
132
|
t.read.should == "ok"
|
56
133
|
t.close
|
57
134
|
|
@@ -62,13 +139,15 @@ describe ServerEngine::SocketManager do
|
|
62
139
|
test_state(:is_udp_socket).should == 1
|
63
140
|
test_state(:udp_data_sent).should == 1
|
64
141
|
end
|
65
|
-
end
|
142
|
+
end if (TCPServer.open("::1",0) rescue nil)
|
143
|
+
end
|
66
144
|
|
67
|
-
|
68
|
-
|
69
|
-
|
145
|
+
if ServerEngine.windows?
|
146
|
+
it 'is windows' do
|
147
|
+
SocketManager::Client.is_a?(SocketManagerWin::ClientModule)
|
148
|
+
SocketManager::Server.is_a?(SocketManagerWin::ServerModule)
|
70
149
|
end
|
71
|
-
|
150
|
+
else
|
72
151
|
it 'is unix' do
|
73
152
|
SocketManager::Client.is_a?(SocketManagerUnix::ClientModule)
|
74
153
|
SocketManager::Server.is_a?(SocketManagerUnix::ServerModule)
|
@@ -81,20 +160,25 @@ describe ServerEngine::SocketManager do
|
|
81
160
|
fork do
|
82
161
|
server.close
|
83
162
|
|
84
|
-
|
163
|
+
begin
|
164
|
+
client = server.new_client
|
85
165
|
|
86
|
-
|
87
|
-
|
166
|
+
tcp = client.listen_tcp('127.0.0.1', test_port)
|
167
|
+
udp = client.listen_udp('127.0.0.1', test_port)
|
88
168
|
|
89
|
-
|
90
|
-
|
169
|
+
incr_test_state(:is_tcp_server) if tcp.is_a?(TCPServer)
|
170
|
+
incr_test_state(:is_udp_socket) if udp.is_a?(UDPSocket)
|
91
171
|
|
92
|
-
|
93
|
-
|
172
|
+
data, _from = udp.recvfrom(10)
|
173
|
+
incr_test_state(:udp_data_sent) if data == "ok"
|
94
174
|
|
95
|
-
|
96
|
-
|
97
|
-
|
175
|
+
s = tcp.accept
|
176
|
+
s.write("ok")
|
177
|
+
s.close
|
178
|
+
ensure
|
179
|
+
tcp.close
|
180
|
+
udp.close
|
181
|
+
end
|
98
182
|
end
|
99
183
|
|
100
184
|
wait_for_fork
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: serverengine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sadayuki Furuhashi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-11-
|
11
|
+
date: 2016-11-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sigdump
|