serverengine 1.5.11 → 1.6.0

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.
@@ -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"
@@ -1,3 +1,3 @@
1
1
  module ServerEngine
2
- VERSION = "1.5.11"
2
+ VERSION = "1.6.0"
3
3
  end
@@ -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|
@@ -22,13 +22,18 @@ describe ServerEngine::SignalThread do
22
22
  end
23
23
 
24
24
  it 'SIG_IGN' do
25
- t = SignalThread.new do |st|
26
- st.trap('QUIT', 'SIG_IGN')
27
- end
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
- Process.kill('QUIT', Process.pid)
33
+ Process.kill('QUIT', Process.pid)
30
34
 
31
- t.stop.join
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
 
@@ -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.5.11
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: 2015-09-28 00:00:00.000000000 Z
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.2.3
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