serverengine 1.5.11 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -3
- data/Changelog +9 -0
- data/README.md +108 -51
- data/appveyor.yml +18 -0
- data/lib/serverengine/config_loader.rb +2 -3
- data/lib/serverengine/daemon.rb +4 -1
- data/lib/serverengine/multi_spawn_server.rb +15 -6
- data/lib/serverengine/process_manager.rb +51 -29
- data/lib/serverengine/server.rb +9 -5
- data/lib/serverengine/socket_manager.rb +170 -0
- data/lib/serverengine/socket_manager_unix.rb +96 -0
- data/lib/serverengine/socket_manager_win.rb +147 -0
- data/lib/serverengine/supervisor.rb +4 -1
- data/lib/serverengine/utils.rb +7 -0
- data/lib/serverengine/version.rb +1 -1
- data/lib/serverengine/winsock.rb +128 -0
- data/lib/serverengine.rb +1 -0
- data/spec/signal_thread_spec.rb +10 -5
- data/spec/socket_manager_spec.rb +115 -0
- data/spec/spec_helper.rb +4 -1
- data/spec/supervisor_spec.rb +57 -0
- metadata +10 -3
data/lib/serverengine/utils.rb
CHANGED
@@ -17,6 +17,13 @@
|
|
17
17
|
#
|
18
18
|
module ServerEngine
|
19
19
|
|
20
|
+
IS_WINDOWS = /mswin|mingw/ === RUBY_PLATFORM
|
21
|
+
private_constant :IS_WINDOWS
|
22
|
+
|
23
|
+
def self.windows?
|
24
|
+
IS_WINDOWS
|
25
|
+
end
|
26
|
+
|
20
27
|
module ClassMethods
|
21
28
|
def dump_uncaught_error(e)
|
22
29
|
STDERR.write "Unexpected error #{e}\n"
|
data/lib/serverengine/version.rb
CHANGED
@@ -0,0 +1,128 @@
|
|
1
|
+
#
|
2
|
+
# ServerEngine
|
3
|
+
#
|
4
|
+
# Copyright (C) 2012-2013 Sadayuki Furuhashi
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
module ServerEngine
|
19
|
+
module WinSock
|
20
|
+
|
21
|
+
require 'fiddle/import'
|
22
|
+
require 'fiddle/types'
|
23
|
+
require 'socket'
|
24
|
+
|
25
|
+
extend Fiddle::Importer
|
26
|
+
|
27
|
+
dlload "ws2_32.dll"
|
28
|
+
include Fiddle::Win32Types
|
29
|
+
|
30
|
+
extern "int WSASocketA(int, int, int, void *, int, DWORD)"
|
31
|
+
extern "long inet_addr(char *)"
|
32
|
+
extern "int bind(int, void *, int)"
|
33
|
+
extern "int listen(int, int)"
|
34
|
+
extern "int WSADuplicateSocketA(int, DWORD, void *)"
|
35
|
+
extern "int WSAGetLastError()"
|
36
|
+
extern "BOOL CloseHandle(int)"
|
37
|
+
|
38
|
+
SockaddrIn = struct(["short sin_family",
|
39
|
+
"short sin_port",
|
40
|
+
"long sin_addr",
|
41
|
+
"char sin_zero[8]",
|
42
|
+
])
|
43
|
+
|
44
|
+
WSAPROTOCOL_INFO = struct(["DWORD dwServiceFlags1",
|
45
|
+
"DWORD dwServiceFlags2",
|
46
|
+
"DWORD dwServiceFlags3",
|
47
|
+
"DWORD dwServiceFlags4",
|
48
|
+
"DWORD dwProviderFlags",
|
49
|
+
"DWORD Data1",
|
50
|
+
"WORD Data2",
|
51
|
+
"WORD Data3",
|
52
|
+
"BYTE Data4[8]",
|
53
|
+
"DWORD dwCatalogEntryId",
|
54
|
+
"int ChainLen",
|
55
|
+
"DWORD ChainEntries[7]",
|
56
|
+
"int iVersion",
|
57
|
+
"int iAddressFamily",
|
58
|
+
"int iMaxSockAddr",
|
59
|
+
"int iMinSockAddr",
|
60
|
+
"int iSocketType",
|
61
|
+
"int iProtocol",
|
62
|
+
"int iProtocolMaxOffset",
|
63
|
+
"int iNetworkByteOrder",
|
64
|
+
"int iSecurityScheme",
|
65
|
+
"DWORD dwMessageSize",
|
66
|
+
"DWORD dwProviderReserved",
|
67
|
+
"char szProtocol[256]",
|
68
|
+
])
|
69
|
+
|
70
|
+
class WSAPROTOCOL_INFO
|
71
|
+
def self.from_bin(bin)
|
72
|
+
proto = malloc
|
73
|
+
proto.to_ptr.ref.ptr[0, size] = bin
|
74
|
+
proto
|
75
|
+
end
|
76
|
+
|
77
|
+
def to_bin
|
78
|
+
to_ptr.to_s
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
INVALID_SOCKET = -1
|
83
|
+
end
|
84
|
+
|
85
|
+
module RbWinSock
|
86
|
+
extend Fiddle::Importer
|
87
|
+
|
88
|
+
dlload "kernel32"
|
89
|
+
extern "int GetModuleFileNameA(int, char *, int)"
|
90
|
+
|
91
|
+
ruby_bin_path_buf = Fiddle::Pointer.malloc(1000)
|
92
|
+
GetModuleFileNameA(0, ruby_bin_path_buf, ruby_bin_path_buf.size)
|
93
|
+
|
94
|
+
ruby_bin_path = ruby_bin_path_buf.to_s.gsub(/\\/, '/')
|
95
|
+
ruby_dll_paths = File.dirname(ruby_bin_path) + '/msvcr*ruby*.dll'
|
96
|
+
ruby_dll_path = Dir.glob(ruby_dll_paths).first
|
97
|
+
dlload ruby_dll_path
|
98
|
+
|
99
|
+
extern "int rb_w32_map_errno(int)"
|
100
|
+
extern "void rb_syserr_fail(int, char *)"
|
101
|
+
|
102
|
+
def self.raise_last_error(name)
|
103
|
+
errno = rb_w32_map_errno(WinSock.WSAGetLastError)
|
104
|
+
rb_syserr_fail(errno, name)
|
105
|
+
end
|
106
|
+
|
107
|
+
extern "int rb_w32_wrap_io_handle(int, int)"
|
108
|
+
|
109
|
+
def self.wrap_io_handle(sock_class, handle, flags)
|
110
|
+
begin
|
111
|
+
fd = rb_w32_wrap_io_handle(handle, flags)
|
112
|
+
if fd < 0
|
113
|
+
raise_last_error("rb_w32_wrap_io_handle(3)")
|
114
|
+
end
|
115
|
+
|
116
|
+
sock = sock_class.for_fd(fd)
|
117
|
+
wrapped = true
|
118
|
+
sock.define_singleton_method(:handle) { handle }
|
119
|
+
|
120
|
+
return sock
|
121
|
+
ensure
|
122
|
+
unless wrapped
|
123
|
+
WinSock.CloseHandle(handle)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
data/lib/serverengine.rb
CHANGED
@@ -35,6 +35,7 @@ module ServerEngine
|
|
35
35
|
:MultiThreadServer => 'serverengine/multi_thread_server',
|
36
36
|
:MultiSpawnServer => 'serverengine/multi_spawn_server',
|
37
37
|
:ProcessManager => 'serverengine/process_manager',
|
38
|
+
:SocketManager => 'serverengine/socket_manager',
|
38
39
|
:Worker => 'serverengine/worker',
|
39
40
|
:VERSION => 'serverengine/version',
|
40
41
|
}.each_pair {|k,v|
|
data/spec/signal_thread_spec.rb
CHANGED
@@ -22,13 +22,18 @@ describe ServerEngine::SignalThread do
|
|
22
22
|
end
|
23
23
|
|
24
24
|
it 'SIG_IGN' do
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
# IGNORE signal handler has possible race condition in Ruby 2.1
|
26
|
+
# https://bugs.ruby-lang.org/issues/9835
|
27
|
+
# That's why ignore this test in Ruby2.1
|
28
|
+
if RUBY_VERSION >= '2.2'
|
29
|
+
t = SignalThread.new do |st|
|
30
|
+
st.trap('QUIT', 'SIG_IGN')
|
31
|
+
end
|
28
32
|
|
29
|
-
|
33
|
+
Process.kill('QUIT', Process.pid)
|
30
34
|
|
31
|
-
|
35
|
+
t.stop.join
|
36
|
+
end
|
32
37
|
end
|
33
38
|
|
34
39
|
it 'signal in handler' do
|
@@ -0,0 +1,115 @@
|
|
1
|
+
|
2
|
+
describe ServerEngine::SocketManager do
|
3
|
+
include_context 'test server and worker'
|
4
|
+
|
5
|
+
let(:server_path) do
|
6
|
+
'tmp/socket_manager_test.sock'
|
7
|
+
end
|
8
|
+
|
9
|
+
after(:each) do
|
10
|
+
File.unlink(server_path) if File.exists?(server_path)
|
11
|
+
end
|
12
|
+
|
13
|
+
if ServerEngine.windows?
|
14
|
+
let(:server_port) do
|
15
|
+
24223
|
16
|
+
end
|
17
|
+
|
18
|
+
let(:test_port) do
|
19
|
+
9101
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'is windows' do
|
23
|
+
SocketManager::Client.is_a?(SocketManagerWin::ClientModule)
|
24
|
+
SocketManager::Server.is_a?(SocketManagerWin::ServerModule)
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'with thread' do
|
28
|
+
it 'works' do
|
29
|
+
server = SocketManager::Server.open(server_port)
|
30
|
+
|
31
|
+
thread = Thread.new do
|
32
|
+
|
33
|
+
client = ServerEngine::SocketManager::Client.new(server_port)
|
34
|
+
tcp = client.listen_tcp('127.0.0.1', test_port)
|
35
|
+
udp = client.listen_udp('127.0.0.1', test_port)
|
36
|
+
|
37
|
+
incr_test_state(:is_tcp_server) if tcp.is_a?(TCPServer)
|
38
|
+
incr_test_state(:is_udp_socket) if udp.is_a?(UDPSocket)
|
39
|
+
|
40
|
+
data, from = udp.recvfrom(10)
|
41
|
+
incr_test_state(:udp_data_sent) if data == "ok"
|
42
|
+
|
43
|
+
s = tcp.accept
|
44
|
+
s.write("ok")
|
45
|
+
s.close
|
46
|
+
end
|
47
|
+
|
48
|
+
sleep 1
|
49
|
+
|
50
|
+
u = UDPSocket.new
|
51
|
+
u.send "ok", 0, '127.0.0.1', test_port
|
52
|
+
u.close
|
53
|
+
|
54
|
+
t = TCPSocket.open('127.0.0.1', test_port)
|
55
|
+
t.read.should == "ok"
|
56
|
+
t.close
|
57
|
+
|
58
|
+
server.close
|
59
|
+
thread.join
|
60
|
+
|
61
|
+
test_state(:is_tcp_server).should == 1
|
62
|
+
test_state(:is_udp_socket).should == 1
|
63
|
+
test_state(:udp_data_sent).should == 1
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
else
|
68
|
+
it 'is unix' do
|
69
|
+
SocketManager::Client.is_a?(SocketManagerUnix::ClientModule)
|
70
|
+
SocketManager::Server.is_a?(SocketManagerUnix::ServerModule)
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'with fork' do
|
74
|
+
it 'works' do
|
75
|
+
server = SocketManager::Server.open(server_path)
|
76
|
+
|
77
|
+
fork do
|
78
|
+
server.close
|
79
|
+
|
80
|
+
client = server.new_client
|
81
|
+
|
82
|
+
tcp = client.listen_tcp('127.0.0.1', test_port)
|
83
|
+
udp = client.listen_udp('127.0.0.1', test_port)
|
84
|
+
|
85
|
+
incr_test_state(:is_tcp_server) if tcp.is_a?(TCPServer)
|
86
|
+
incr_test_state(:is_udp_socket) if udp.is_a?(UDPSocket)
|
87
|
+
|
88
|
+
data, from = udp.recvfrom(10)
|
89
|
+
incr_test_state(:udp_data_sent) if data == "ok"
|
90
|
+
|
91
|
+
s = tcp.accept
|
92
|
+
s.write("ok")
|
93
|
+
s.close
|
94
|
+
end
|
95
|
+
|
96
|
+
wait_for_fork
|
97
|
+
|
98
|
+
u = UDPSocket.new
|
99
|
+
u.send "ok", 0, '127.0.0.1', test_port
|
100
|
+
u.close
|
101
|
+
|
102
|
+
t = TCPSocket.open('127.0.0.1', test_port)
|
103
|
+
t.read.should == "ok"
|
104
|
+
t.close
|
105
|
+
|
106
|
+
server.close
|
107
|
+
|
108
|
+
test_state(:is_tcp_server).should == 1
|
109
|
+
test_state(:is_udp_socket).should == 1
|
110
|
+
test_state(:udp_data_sent).should == 1
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'bundler'
|
2
|
-
require 'sigdump/setup'
|
3
2
|
|
4
3
|
begin
|
5
4
|
Bundler.setup(:default, :test)
|
@@ -12,5 +11,9 @@ end
|
|
12
11
|
require 'serverengine'
|
13
12
|
include ServerEngine
|
14
13
|
|
14
|
+
# require sigdump only in unix, because there is no suport for SIGCONT in windows.
|
15
|
+
unless ServerEngine.windows?
|
16
|
+
require 'sigdump/setup'
|
17
|
+
end
|
15
18
|
require 'server_worker_context'
|
16
19
|
|
data/spec/supervisor_spec.rb
CHANGED
@@ -9,6 +9,63 @@ describe ServerEngine::Supervisor do
|
|
9
9
|
return sv, t
|
10
10
|
end
|
11
11
|
|
12
|
+
def start_daemon(config={})
|
13
|
+
daemon = Daemon.new(nil, TestWorker, config)
|
14
|
+
t = Thread.new { daemon.main }
|
15
|
+
|
16
|
+
return daemon, t
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'when :log=IO option is given' do
|
20
|
+
it 'can start' do
|
21
|
+
daemon, t = start_daemon(log: STDOUT)
|
22
|
+
|
23
|
+
begin
|
24
|
+
wait_for_fork
|
25
|
+
ensure
|
26
|
+
daemon.server.stop(true)
|
27
|
+
t.join
|
28
|
+
end
|
29
|
+
|
30
|
+
test_state(:worker_run).should == 1
|
31
|
+
daemon.server.logger.should be_an_instance_of(ServerEngine::DaemonLogger)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'when :logger option is given' do
|
36
|
+
it 'uses specified logger instance' do
|
37
|
+
logger = ServerEngine::DaemonLogger.new(STDOUT)
|
38
|
+
daemon, t = start_daemon(logger: logger)
|
39
|
+
|
40
|
+
begin
|
41
|
+
wait_for_fork
|
42
|
+
ensure
|
43
|
+
daemon.server.stop(true)
|
44
|
+
t.join
|
45
|
+
end
|
46
|
+
|
47
|
+
test_state(:worker_run).should == 1
|
48
|
+
daemon.server.logger.should == logger
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'when both :logger and :log options are given' do
|
53
|
+
it 'start ignoring :log' do
|
54
|
+
logger = ServerEngine::DaemonLogger.new(STDOUT)
|
55
|
+
daemon, t = start_daemon(logger: logger, log: STDERR)
|
56
|
+
|
57
|
+
begin
|
58
|
+
wait_for_fork
|
59
|
+
ensure
|
60
|
+
daemon.server.stop(true)
|
61
|
+
t.join
|
62
|
+
end
|
63
|
+
|
64
|
+
test_state(:worker_run).should == 1
|
65
|
+
daemon.server.logger.should == logger
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
12
69
|
it 'start and graceful stop' do
|
13
70
|
sv, t = start_supervisor
|
14
71
|
|
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: 1.
|
4
|
+
version: 1.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sadayuki Furuhashi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-01-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sigdump
|
@@ -68,6 +68,7 @@ files:
|
|
68
68
|
- NOTICE
|
69
69
|
- README.md
|
70
70
|
- Rakefile
|
71
|
+
- appveyor.yml
|
71
72
|
- lib/serverengine.rb
|
72
73
|
- lib/serverengine/blocking_flag.rb
|
73
74
|
- lib/serverengine/config_loader.rb
|
@@ -81,9 +82,13 @@ files:
|
|
81
82
|
- lib/serverengine/process_manager.rb
|
82
83
|
- lib/serverengine/server.rb
|
83
84
|
- lib/serverengine/signal_thread.rb
|
85
|
+
- lib/serverengine/socket_manager.rb
|
86
|
+
- lib/serverengine/socket_manager_unix.rb
|
87
|
+
- lib/serverengine/socket_manager_win.rb
|
84
88
|
- lib/serverengine/supervisor.rb
|
85
89
|
- lib/serverengine/utils.rb
|
86
90
|
- lib/serverengine/version.rb
|
91
|
+
- lib/serverengine/winsock.rb
|
87
92
|
- lib/serverengine/worker.rb
|
88
93
|
- serverengine.gemspec
|
89
94
|
- spec/blocking_flag_spec.rb
|
@@ -92,6 +97,7 @@ files:
|
|
92
97
|
- spec/multi_process_server_spec.rb
|
93
98
|
- spec/server_worker_context.rb
|
94
99
|
- spec/signal_thread_spec.rb
|
100
|
+
- spec/socket_manager_spec.rb
|
95
101
|
- spec/spec_helper.rb
|
96
102
|
- spec/supervisor_spec.rb
|
97
103
|
homepage: https://github.com/fluent/serverengine
|
@@ -114,7 +120,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
114
120
|
version: '0'
|
115
121
|
requirements: []
|
116
122
|
rubyforge_project:
|
117
|
-
rubygems_version: 2.
|
123
|
+
rubygems_version: 2.4.5
|
118
124
|
signing_key:
|
119
125
|
specification_version: 4
|
120
126
|
summary: ServerEngine - multiprocess server framework
|
@@ -125,5 +131,6 @@ test_files:
|
|
125
131
|
- spec/multi_process_server_spec.rb
|
126
132
|
- spec/server_worker_context.rb
|
127
133
|
- spec/signal_thread_spec.rb
|
134
|
+
- spec/socket_manager_spec.rb
|
128
135
|
- spec/spec_helper.rb
|
129
136
|
- spec/supervisor_spec.rb
|