serverengine 2.0.7 → 2.2.2
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/.travis.yml +6 -3
- data/Changelog +21 -0
- data/lib/serverengine/multi_process_server.rb +10 -1
- data/lib/serverengine/multi_spawn_server.rb +0 -7
- data/lib/serverengine/process_manager.rb +30 -11
- data/lib/serverengine/signal_thread.rb +1 -1
- data/lib/serverengine/signals.rb +1 -1
- data/lib/serverengine/socket_manager.rb +15 -2
- data/lib/serverengine/socket_manager_unix.rb +35 -12
- data/lib/serverengine/version.rb +1 -1
- data/spec/socket_manager_spec.rb +21 -1
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2daf0f4af407a699df75677a6cdfdaa798b6c870acd77ee75bdaced9c3944eb7
|
4
|
+
data.tar.gz: 40d6299f178209b2207966ceea322f1b36efef63f897a54f0a815fb28a2af71d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 95bd026a937bbf8ab666a9c89832e7c32d7b60c5a88ef91f61d08c6e6bf7595268e73c4eb03f09e972edd328f424304a17eb354d99e2caa7e14182f13bb76dd8
|
7
|
+
data.tar.gz: 0f6a91d444ae252cc232bd1151804c706a43415388a23e65b8861cd53dc5ac3a490f557d14b6aebcda03d12371c5220e2f30859b2300a3124b03781650c8ec7f
|
data/.travis.yml
CHANGED
data/Changelog
CHANGED
@@ -1,3 +1,24 @@
|
|
1
|
+
2020-11-02 version 2.2.2:
|
2
|
+
|
3
|
+
* Fix incomplete Windows support in spawn based multi worker
|
4
|
+
|
5
|
+
2020-01-24 version 2.2.1:
|
6
|
+
|
7
|
+
* Fix IPv6 dual-stack mode issue for UDP
|
8
|
+
* experimental: Add SERVERENGINE_USE_SOCKET_REUSEPORT envvar to enable SO_REUSEPORT
|
9
|
+
|
10
|
+
2019-11-16 version 2.2.0:
|
11
|
+
|
12
|
+
* Fix IPv6 dual-stack mode issue for TCP
|
13
|
+
|
14
|
+
2019-04-22 version 2.1.1:
|
15
|
+
|
16
|
+
* Fix bug to ignore SIGDUMP_SIGNAL
|
17
|
+
|
18
|
+
2018-11-14 version 2.1.0:
|
19
|
+
|
20
|
+
* Improve socket manager security
|
21
|
+
|
1
22
|
2018-07-09 version 2.0.7:
|
2
23
|
|
3
24
|
* Add disable_sigdump option
|
@@ -120,10 +120,19 @@ module ServerEngine
|
|
120
120
|
end
|
121
121
|
|
122
122
|
def send_reload
|
123
|
-
|
123
|
+
return nil unless @pmon
|
124
|
+
if @pmon.command_sender_pipe
|
125
|
+
send_command("RELOAD\n")
|
126
|
+
else
|
127
|
+
@pmon.send_signal(@reload_signal)
|
128
|
+
end
|
124
129
|
nil
|
125
130
|
end
|
126
131
|
|
132
|
+
def send_command(command)
|
133
|
+
@pmon.send_command(command) if @pmon
|
134
|
+
end
|
135
|
+
|
127
136
|
def join
|
128
137
|
@pmon.join if @pmon
|
129
138
|
nil
|
@@ -46,13 +46,6 @@ module ServerEngine
|
|
46
46
|
@pm.command_sender = @command_sender
|
47
47
|
end
|
48
48
|
|
49
|
-
def stop(stop_graceful)
|
50
|
-
if @command_sender == "pipe"
|
51
|
-
@pm.command_sender_pipe.write(stop_graceful ? "GRACEFUL_STOP\n" : "IMMEDIATE_STOP\n")
|
52
|
-
end
|
53
|
-
super
|
54
|
-
end
|
55
|
-
|
56
49
|
def run
|
57
50
|
super
|
58
51
|
ensure
|
@@ -16,6 +16,7 @@
|
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
18
|
require 'fcntl'
|
19
|
+
require 'serverengine/socket_manager'
|
19
20
|
|
20
21
|
module ServerEngine
|
21
22
|
|
@@ -70,7 +71,6 @@ module ServerEngine
|
|
70
71
|
attr_reader :enable_heartbeat, :auto_heartbeat
|
71
72
|
|
72
73
|
attr_accessor :command_sender
|
73
|
-
attr_reader :command_sender_pipe
|
74
74
|
|
75
75
|
CONFIG_PARAMS = {
|
76
76
|
heartbeat_interval: 1,
|
@@ -179,18 +179,21 @@ module ServerEngine
|
|
179
179
|
end
|
180
180
|
end
|
181
181
|
|
182
|
+
command_sender_pipe = nil
|
182
183
|
if @command_sender == "pipe"
|
183
|
-
inpipe,
|
184
|
-
|
185
|
-
|
184
|
+
inpipe, command_sender_pipe = IO.pipe
|
185
|
+
command_sender_pipe.sync = true
|
186
|
+
command_sender_pipe.binmode
|
186
187
|
options[:in] = inpipe
|
187
188
|
end
|
189
|
+
env['SERVERENGINE_SOCKETMANAGER_INTERNAL_TOKEN'] = SocketManager::INTERNAL_TOKEN
|
188
190
|
pid = Process.spawn(env, *args, options)
|
189
191
|
if @command_sender == "pipe"
|
190
192
|
inpipe.close
|
191
193
|
end
|
192
194
|
|
193
195
|
m = Monitor.new(pid, monitor_options)
|
196
|
+
m.command_sender_pipe = command_sender_pipe
|
194
197
|
|
195
198
|
@monitors << m
|
196
199
|
|
@@ -305,9 +308,11 @@ module ServerEngine
|
|
305
308
|
@graceful_kill_start_time = nil
|
306
309
|
@immediate_kill_start_time = nil
|
307
310
|
@kill_count = 0
|
311
|
+
|
312
|
+
@command_sender_pipe = nil
|
308
313
|
end
|
309
314
|
|
310
|
-
attr_accessor :last_heartbeat_time
|
315
|
+
attr_accessor :last_heartbeat_time, :command_sender_pipe
|
311
316
|
attr_reader :pid
|
312
317
|
|
313
318
|
def heartbeat_delay
|
@@ -327,6 +332,10 @@ module ServerEngine
|
|
327
332
|
end
|
328
333
|
end
|
329
334
|
|
335
|
+
def send_command(command)
|
336
|
+
@command_sender_pipe.write(command) if @command_sender_pipe
|
337
|
+
end
|
338
|
+
|
330
339
|
def try_join
|
331
340
|
pid = @pid
|
332
341
|
return true unless pid
|
@@ -364,15 +373,25 @@ module ServerEngine
|
|
364
373
|
end
|
365
374
|
|
366
375
|
def start_graceful_stop!
|
367
|
-
|
368
|
-
|
369
|
-
|
376
|
+
if ServerEngine.windows?
|
377
|
+
# heartbeat isn't supported on Windows
|
378
|
+
send_command("GRACEFUL_STOP\n")
|
379
|
+
else
|
380
|
+
now = Time.now
|
381
|
+
@next_kill_time ||= now
|
382
|
+
@graceful_kill_start_time ||= now
|
383
|
+
end
|
370
384
|
end
|
371
385
|
|
372
386
|
def start_immediate_stop!
|
373
|
-
|
374
|
-
|
375
|
-
|
387
|
+
if ServerEngine.windows?
|
388
|
+
# heartbeat isn't supported on Windows
|
389
|
+
system("taskkill /f /pid #{@pid}")
|
390
|
+
else
|
391
|
+
now = Time.now
|
392
|
+
@next_kill_time ||= now
|
393
|
+
@immediate_kill_start_time ||= now
|
394
|
+
end
|
376
395
|
end
|
377
396
|
|
378
397
|
def tick(now=Time.now)
|
data/lib/serverengine/signals.rb
CHANGED
@@ -18,9 +18,18 @@
|
|
18
18
|
require 'socket'
|
19
19
|
require 'ipaddr'
|
20
20
|
require 'time'
|
21
|
+
require 'securerandom'
|
22
|
+
require 'json'
|
23
|
+
require 'base64'
|
21
24
|
|
22
25
|
module ServerEngine
|
23
26
|
module SocketManager
|
27
|
+
# This token is used for communication between peers. If token is mismatched, messages will be discarded
|
28
|
+
INTERNAL_TOKEN = if ENV.has_key?('SERVERENGINE_SOCKETMANAGER_INTERNAL_TOKEN')
|
29
|
+
ENV['SERVERENGINE_SOCKETMANAGER_INTERNAL_TOKEN']
|
30
|
+
else
|
31
|
+
SecureRandom.hex
|
32
|
+
end
|
24
33
|
|
25
34
|
class Client
|
26
35
|
def initialize(path)
|
@@ -154,7 +163,8 @@ module ServerEngine
|
|
154
163
|
end
|
155
164
|
|
156
165
|
def self.send_peer(peer, obj)
|
157
|
-
data = Marshal.dump(obj)
|
166
|
+
data = [SocketManager::INTERNAL_TOKEN, Base64.strict_encode64(Marshal.dump(obj))]
|
167
|
+
data = JSON.generate(data)
|
158
168
|
peer.write [data.bytesize].pack('N')
|
159
169
|
peer.write data
|
160
170
|
end
|
@@ -165,7 +175,10 @@ module ServerEngine
|
|
165
175
|
|
166
176
|
len = res.unpack('N').first
|
167
177
|
data = peer.read(len)
|
168
|
-
|
178
|
+
data = JSON.parse(data)
|
179
|
+
return nil if SocketManager::INTERNAL_TOKEN != data.first
|
180
|
+
|
181
|
+
Marshal.load(Base64.strict_decode64(data.last))
|
169
182
|
end
|
170
183
|
|
171
184
|
if ServerEngine.windows?
|
@@ -50,19 +50,30 @@ module ServerEngine
|
|
50
50
|
private
|
51
51
|
|
52
52
|
def listen_tcp_new(bind_ip, port)
|
53
|
-
|
54
|
-
|
55
|
-
|
53
|
+
if ENV['SERVERENGINE_USE_SOCKET_REUSEPORT'] == '1'
|
54
|
+
# Based on Addrinfo#listen
|
55
|
+
tsock = Socket.new(bind_ip.ipv6? ? ::Socket::AF_INET6 : ::Socket::AF_INET, ::Socket::SOCK_STREAM, 0)
|
56
|
+
tsock.ipv6only! if bind_ip.ipv6?
|
57
|
+
tsock.setsockopt(:SOCKET, :REUSEPORT, true)
|
58
|
+
tsock.setsockopt(:SOCKET, :REUSEADDR, true)
|
59
|
+
tsock.bind(Addrinfo.tcp(bind_ip.to_s, port))
|
60
|
+
tsock.listen(::Socket::SOMAXCONN)
|
61
|
+
tsock.autoclose = false
|
62
|
+
TCPServer.for_fd(tsock.fileno)
|
63
|
+
else
|
64
|
+
# TCPServer.new doesn't set IPV6_V6ONLY flag, so use Addrinfo class instead.
|
65
|
+
# TODO: make backlog configurable if necessary
|
66
|
+
tsock = Addrinfo.tcp(bind_ip.to_s, port).listen(::Socket::SOMAXCONN)
|
67
|
+
tsock.autoclose = false
|
68
|
+
TCPServer.for_fd(tsock.fileno)
|
69
|
+
end
|
56
70
|
end
|
57
71
|
|
58
72
|
def listen_udp_new(bind_ip, port)
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
end
|
64
|
-
sock.bind(bind_ip.to_s, port)
|
65
|
-
return sock
|
73
|
+
# UDPSocket.new doesn't set IPV6_V6ONLY flag, so use Addrinfo class instead.
|
74
|
+
usock = Addrinfo.udp(bind_ip.to_s, port).bind
|
75
|
+
usock.autoclose = false
|
76
|
+
UDPSocket.for_fd(usock.fileno)
|
66
77
|
end
|
67
78
|
|
68
79
|
def start_server(path)
|
@@ -70,7 +81,12 @@ module ServerEngine
|
|
70
81
|
# when client changed working directory
|
71
82
|
path = File.expand_path(path)
|
72
83
|
|
73
|
-
|
84
|
+
begin
|
85
|
+
old_umask = File.umask(0077) # Protect unix socket from other users
|
86
|
+
@server = UNIXServer.new(path)
|
87
|
+
ensure
|
88
|
+
File.umask(old_umask)
|
89
|
+
end
|
74
90
|
|
75
91
|
@thread = Thread.new do
|
76
92
|
begin
|
@@ -96,7 +112,14 @@ module ServerEngine
|
|
96
112
|
end
|
97
113
|
|
98
114
|
def send_socket(peer, pid, method, bind, port)
|
99
|
-
sock =
|
115
|
+
sock = case method
|
116
|
+
when :listen_tcp
|
117
|
+
listen_tcp(bind, port)
|
118
|
+
when :listen_udp
|
119
|
+
listen_udp(bind, port)
|
120
|
+
else
|
121
|
+
raise ArgumentError, "Unknown method: #{method.inspect}"
|
122
|
+
end
|
100
123
|
|
101
124
|
SocketManager.send_peer(peer, nil)
|
102
125
|
|
data/lib/serverengine/version.rb
CHANGED
data/spec/socket_manager_spec.rb
CHANGED
@@ -155,7 +155,27 @@ describe ServerEngine::SocketManager do
|
|
155
155
|
test_state(:is_udp_socket).should == 1
|
156
156
|
test_state(:udp_data_sent).should == 1
|
157
157
|
end
|
158
|
-
end if (TCPServer.open("::1",0) rescue nil)
|
158
|
+
end if (TCPServer.open("::1", 0) rescue nil)
|
159
|
+
|
160
|
+
unless ServerEngine.windows?
|
161
|
+
context 'using ipv4/ipv6' do
|
162
|
+
it 'can bind ipv4/ipv6 together' do
|
163
|
+
server = SocketManager::Server.open(server_path)
|
164
|
+
client = ServerEngine::SocketManager::Client.new(server_path)
|
165
|
+
|
166
|
+
tcp_v4 = client.listen_tcp('0.0.0.0', test_port)
|
167
|
+
udp_v4 = client.listen_udp('0.0.0.0', test_port)
|
168
|
+
tcp_v6 = client.listen_tcp('::', test_port)
|
169
|
+
udp_v6 = client.listen_udp('::', test_port)
|
170
|
+
|
171
|
+
tcp_v4.close
|
172
|
+
udp_v4.close
|
173
|
+
tcp_v6.close
|
174
|
+
udp_v6.close
|
175
|
+
server.close
|
176
|
+
end
|
177
|
+
end if (TCPServer.open("::", 0) rescue nil)
|
178
|
+
end
|
159
179
|
end
|
160
180
|
|
161
181
|
if ServerEngine.windows?
|
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.
|
4
|
+
version: 2.2.2
|
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: 2020-11-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sigdump
|
@@ -153,8 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
153
153
|
- !ruby/object:Gem::Version
|
154
154
|
version: '0'
|
155
155
|
requirements: []
|
156
|
-
|
157
|
-
rubygems_version: 2.7.6
|
156
|
+
rubygems_version: 3.0.3
|
158
157
|
signing_key:
|
159
158
|
specification_version: 4
|
160
159
|
summary: ServerEngine - multiprocess server framework
|