serverengine 1.5.11 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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