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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 88edf590d3f97fedd199f51227518ffbd83316fd
4
- data.tar.gz: 43dba794102f403da6535e19883a7d19034449a2
3
+ metadata.gz: 9e23d663095d365596482cfc7e95d2263b6c5d64
4
+ data.tar.gz: 723275d864b001541c2dc7534320483e79d19c60
5
5
  SHA512:
6
- metadata.gz: e71bfefefd9f62d0ec79b6122bb2308b03b8b8da8cc098993e444b3f27ba5daf23b74460ac219424412368db615b383c0fccd97ca48c9045eb6163996e8b4efd
7
- data.tar.gz: ff2a3415ecb2d0f6a35f7e940d7bd9e6a1596aaa7a59c0b3954ca85477e0a6f5cc8015fec8366dce85d2212bd7b83df6834af40653c3712bb3fc38d734940f69
6
+ metadata.gz: 346188cb66f8e835afde847163f0266caad0154e92da190c2e307ed472aacceed4e9fe20b067f1e5422ef7d281237854e8bfaa941f8243b45917db43f9d6d733
7
+ data.tar.gz: 122f579082a0792539aa79e1d864f144454243bcdb7091c6962e3350bd738ff049fd282ad61c5f314b14b948c6d3d4ec59343970653d994f1573536d60742747
data/Changelog CHANGED
@@ -1,3 +1,7 @@
1
+ 2016-11-22 version 2.0.3:
2
+
3
+ * Fix bug about IPv6 handling on Windows
4
+
1
5
  2016-11-17 version 2.0.2:
2
6
 
3
7
  * Fix bug to make busy loop on Windows
@@ -26,34 +26,36 @@ module ServerEngine
26
26
  @path = path
27
27
  end
28
28
 
29
- def listen_tcp(bind, port)
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, :listen_tcp, bind, port])
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 recv_tcp(peer, res)
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
- peer = connect_peer(@path)
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 listen_tcp(bind, port)
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
- if @tcp_sockets.has_key?(key)
102
- return @tcp_sockets[key]
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 listen_udp(bind, port)
110
- key, bind_ip = resolve_bind_key(bind, port)
116
+ def listen_tcp(bind, port)
117
+ listen(:tcp, bind, port)
118
+ end
111
119
 
112
- @mutex.synchronize do
113
- if @udp_sockets.has_key?(key)
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 recv_tcp(peer, sent)
31
- return peer.recv_io(TCPServer)
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 recv_udp(peer, sent)
35
- return peer.recv_io(UDPSocket)
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 recv_tcp(peer, sent)
34
- proto = WinSock::WSAPROTOCOL_INFO.from_bin(sent)
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
- handle = WinSock.WSASocketA(Socket::AF_INET, Socket::SOCK_STREAM, 0, proto, 0, 1)
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(TCPServer, handle, 0)
48
+ return RbWinSock.wrap_io_handle(server_class, handle, 0)
42
49
  end
43
50
 
44
- def recv_udp(peer, sent)
45
- proto = WinSock::WSAPROTOCOL_INFO.from_bin(sent)
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
- return RbWinSock.wrap_io_handle(UDPSocket, handle, 0)
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
- def listen_tcp_new(bind_ip, port)
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(Socket::AF_INET, Socket::SOCK_STREAM, Socket::IPPROTO_TCP, nil, 0, 1)
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(TCPServer, handle, 0)
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 handle == WinSock::INVALID_SOCKET
90
- RbWinSock.raise_last_error("WSASocketA(2)")
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
- # wrap in UDPSocket immediately so that its finalizer safely closes the handle
94
- sock = RbWinSock.wrap_io_handle(UDPSocket, handle, 0)
95
+ sock
96
+ end
95
97
 
96
- unless WinSock.bind(sock.handle, sock_addr, sock_addr.bytesize) == 0
97
- RbWinSock.raise_last_error("bind(2)")
98
- end
98
+ def listen_tcp_new(bind_ip, port)
99
+ listen_new(:tcp, bind_ip, port)
100
+ end
99
101
 
100
- return sock
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)
@@ -1,3 +1,3 @@
1
1
  module ServerEngine
2
- VERSION = "2.0.2"
2
+ VERSION = "2.0.3"
3
3
  end
@@ -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
- 'tmp/socket_manager_test.sock'
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
- if ServerEngine.windows?
14
- let(:server_port) do
15
- 24223
16
- end
22
+ context 'with thread' do
23
+ context 'using ipv4' do
24
+ it 'works' do
25
+ server = SocketManager::Server.open(server_path)
17
26
 
18
- let(:test_port) do
19
- 9101
20
- end
27
+ mutex = Mutex.new
28
+ server_thread_started = false
21
29
 
22
- it 'is windows' do
23
- SocketManager::Client.is_a?(SocketManagerWin::ClientModule)
24
- SocketManager::Server.is_a?(SocketManagerWin::ServerModule)
25
- end
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
- context 'with thread' do
28
- it 'works' do
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
- thread = Thread.new do
66
+ u = UDPSocket.new(Socket::AF_INET)
67
+ u.send "ok", 0, '127.0.0.1', test_port
68
+ u.close
32
69
 
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)
70
+ t = TCPSocket.open('127.0.0.1', test_port)
71
+ t.read.should == "ok"
72
+ t.close
36
73
 
37
- incr_test_state(:is_tcp_server) if tcp.is_a?(TCPServer)
38
- incr_test_state(:is_udp_socket) if udp.is_a?(UDPSocket)
74
+ server.close
75
+ thread.join
39
76
 
40
- data, _from = udp.recvfrom(10)
41
- incr_test_state(:udp_data_sent) if data == "ok"
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
- s = tcp.accept
44
- s.write("ok")
45
- s.close
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.0.0.1', test_port
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('127.0.0.1', test_port)
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
- else
68
- let(:test_port) do
69
- 9102
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
- client = server.new_client
163
+ begin
164
+ client = server.new_client
85
165
 
86
- tcp = client.listen_tcp('127.0.0.1', test_port)
87
- udp = client.listen_udp('127.0.0.1', test_port)
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
- incr_test_state(:is_tcp_server) if tcp.is_a?(TCPServer)
90
- incr_test_state(:is_udp_socket) if udp.is_a?(UDPSocket)
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
- data, _from = udp.recvfrom(10)
93
- incr_test_state(:udp_data_sent) if data == "ok"
172
+ data, _from = udp.recvfrom(10)
173
+ incr_test_state(:udp_data_sent) if data == "ok"
94
174
 
95
- s = tcp.accept
96
- s.write("ok")
97
- s.close
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.2
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-17 00:00:00.000000000 Z
11
+ date: 2016-11-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sigdump