puma-simon 3.7.1

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.
Files changed (157) hide show
  1. checksums.yaml +7 -0
  2. data/.github/issue_template.md +20 -0
  3. data/.gitignore +18 -0
  4. data/.hoeignore +12 -0
  5. data/.travis.yml +29 -0
  6. data/DEPLOYMENT.md +91 -0
  7. data/Gemfile +12 -0
  8. data/History.md +1254 -0
  9. data/LICENSE +26 -0
  10. data/Manifest.txt +78 -0
  11. data/README.md +353 -0
  12. data/Rakefile +158 -0
  13. data/Release.md +9 -0
  14. data/bin/puma +10 -0
  15. data/bin/puma-wild +31 -0
  16. data/bin/pumactl +12 -0
  17. data/docs/nginx.md +80 -0
  18. data/docs/signals.md +43 -0
  19. data/docs/systemd.md +197 -0
  20. data/examples/CA/cacert.pem +23 -0
  21. data/examples/CA/newcerts/cert_1.pem +19 -0
  22. data/examples/CA/newcerts/cert_2.pem +19 -0
  23. data/examples/CA/private/cakeypair.pem +30 -0
  24. data/examples/CA/serial +1 -0
  25. data/examples/config.rb +200 -0
  26. data/examples/plugins/redis_stop_puma.rb +46 -0
  27. data/examples/puma/cert_puma.pem +19 -0
  28. data/examples/puma/client-certs/ca.crt +19 -0
  29. data/examples/puma/client-certs/ca.key +27 -0
  30. data/examples/puma/client-certs/client.crt +19 -0
  31. data/examples/puma/client-certs/client.key +27 -0
  32. data/examples/puma/client-certs/client_expired.crt +19 -0
  33. data/examples/puma/client-certs/client_expired.key +27 -0
  34. data/examples/puma/client-certs/client_unknown.crt +19 -0
  35. data/examples/puma/client-certs/client_unknown.key +27 -0
  36. data/examples/puma/client-certs/generate.rb +78 -0
  37. data/examples/puma/client-certs/keystore.jks +0 -0
  38. data/examples/puma/client-certs/server.crt +19 -0
  39. data/examples/puma/client-certs/server.key +27 -0
  40. data/examples/puma/client-certs/server.p12 +0 -0
  41. data/examples/puma/client-certs/unknown_ca.crt +19 -0
  42. data/examples/puma/client-certs/unknown_ca.key +27 -0
  43. data/examples/puma/csr_puma.pem +11 -0
  44. data/examples/puma/keystore.jks +0 -0
  45. data/examples/puma/puma_keypair.pem +15 -0
  46. data/examples/qc_config.rb +13 -0
  47. data/ext/puma_http11/PumaHttp11Service.java +17 -0
  48. data/ext/puma_http11/ext_help.h +15 -0
  49. data/ext/puma_http11/extconf.rb +15 -0
  50. data/ext/puma_http11/http11_parser.c +1069 -0
  51. data/ext/puma_http11/http11_parser.h +65 -0
  52. data/ext/puma_http11/http11_parser.java.rl +161 -0
  53. data/ext/puma_http11/http11_parser.rl +147 -0
  54. data/ext/puma_http11/http11_parser_common.rl +54 -0
  55. data/ext/puma_http11/io_buffer.c +155 -0
  56. data/ext/puma_http11/mini_ssl.c +457 -0
  57. data/ext/puma_http11/org/jruby/puma/Http11.java +234 -0
  58. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +473 -0
  59. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +339 -0
  60. data/ext/puma_http11/puma_http11.c +500 -0
  61. data/gemfiles/2.1-Gemfile +12 -0
  62. data/lib/puma.rb +15 -0
  63. data/lib/puma/accept_nonblock.rb +23 -0
  64. data/lib/puma/app/status.rb +66 -0
  65. data/lib/puma/binder.rb +402 -0
  66. data/lib/puma/cli.rb +220 -0
  67. data/lib/puma/client.rb +434 -0
  68. data/lib/puma/cluster.rb +510 -0
  69. data/lib/puma/commonlogger.rb +106 -0
  70. data/lib/puma/compat.rb +14 -0
  71. data/lib/puma/configuration.rb +364 -0
  72. data/lib/puma/const.rb +224 -0
  73. data/lib/puma/control_cli.rb +259 -0
  74. data/lib/puma/convenient.rb +23 -0
  75. data/lib/puma/daemon_ext.rb +31 -0
  76. data/lib/puma/delegation.rb +11 -0
  77. data/lib/puma/detect.rb +13 -0
  78. data/lib/puma/dsl.rb +486 -0
  79. data/lib/puma/events.rb +152 -0
  80. data/lib/puma/io_buffer.rb +7 -0
  81. data/lib/puma/java_io_buffer.rb +45 -0
  82. data/lib/puma/jruby_restart.rb +83 -0
  83. data/lib/puma/launcher.rb +410 -0
  84. data/lib/puma/minissl.rb +221 -0
  85. data/lib/puma/null_io.rb +42 -0
  86. data/lib/puma/plugin.rb +115 -0
  87. data/lib/puma/plugin/tmp_restart.rb +35 -0
  88. data/lib/puma/rack/backports/uri/common_193.rb +33 -0
  89. data/lib/puma/rack/builder.rb +298 -0
  90. data/lib/puma/rack/urlmap.rb +91 -0
  91. data/lib/puma/rack_default.rb +7 -0
  92. data/lib/puma/reactor.rb +210 -0
  93. data/lib/puma/runner.rb +171 -0
  94. data/lib/puma/server.rb +949 -0
  95. data/lib/puma/single.rb +112 -0
  96. data/lib/puma/state_file.rb +29 -0
  97. data/lib/puma/tcp_logger.rb +39 -0
  98. data/lib/puma/thread_pool.rb +297 -0
  99. data/lib/puma/util.rb +128 -0
  100. data/lib/rack/handler/puma.rb +78 -0
  101. data/puma.gemspec +52 -0
  102. data/test/ab_rs.rb +22 -0
  103. data/test/config.rb +2 -0
  104. data/test/config/app.rb +9 -0
  105. data/test/config/plugin.rb +1 -0
  106. data/test/config/settings.rb +2 -0
  107. data/test/config/state_file_testing_config.rb +14 -0
  108. data/test/hello-bind.ru +2 -0
  109. data/test/hello-delay.ru +3 -0
  110. data/test/hello-map.ru +3 -0
  111. data/test/hello-post.ru +4 -0
  112. data/test/hello-stuck.ru +1 -0
  113. data/test/hello-tcp.ru +5 -0
  114. data/test/hello.ru +1 -0
  115. data/test/hijack.ru +6 -0
  116. data/test/hijack2.ru +5 -0
  117. data/test/lobster.ru +4 -0
  118. data/test/shell/run.sh +24 -0
  119. data/test/shell/t1.rb +19 -0
  120. data/test/shell/t1_conf.rb +3 -0
  121. data/test/shell/t2.rb +17 -0
  122. data/test/shell/t2_conf.rb +6 -0
  123. data/test/shell/t3.rb +25 -0
  124. data/test/shell/t3_conf.rb +5 -0
  125. data/test/slow.ru +4 -0
  126. data/test/ssl_config.rb +4 -0
  127. data/test/test_app_status.rb +93 -0
  128. data/test/test_binder.rb +31 -0
  129. data/test/test_cli.rb +209 -0
  130. data/test/test_config.rb +95 -0
  131. data/test/test_events.rb +161 -0
  132. data/test/test_helper.rb +50 -0
  133. data/test/test_http10.rb +27 -0
  134. data/test/test_http11.rb +186 -0
  135. data/test/test_integration.rb +247 -0
  136. data/test/test_iobuffer.rb +39 -0
  137. data/test/test_minissl.rb +29 -0
  138. data/test/test_null_io.rb +49 -0
  139. data/test/test_persistent.rb +245 -0
  140. data/test/test_puma_server.rb +626 -0
  141. data/test/test_puma_server_ssl.rb +222 -0
  142. data/test/test_rack_handler.rb +57 -0
  143. data/test/test_rack_server.rb +138 -0
  144. data/test/test_tcp_logger.rb +39 -0
  145. data/test/test_tcp_rack.rb +36 -0
  146. data/test/test_thread_pool.rb +250 -0
  147. data/test/test_unix_socket.rb +35 -0
  148. data/test/test_web_server.rb +88 -0
  149. data/tools/jungle/README.md +9 -0
  150. data/tools/jungle/init.d/README.md +59 -0
  151. data/tools/jungle/init.d/puma +421 -0
  152. data/tools/jungle/init.d/run-puma +18 -0
  153. data/tools/jungle/upstart/README.md +61 -0
  154. data/tools/jungle/upstart/puma-manager.conf +31 -0
  155. data/tools/jungle/upstart/puma.conf +69 -0
  156. data/tools/trickletest.rb +45 -0
  157. metadata +297 -0
@@ -0,0 +1,12 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "hoe"
4
+ gem "hoe-git"
5
+ gem "hoe-ignore"
6
+ gem "rdoc"
7
+ gem "rake-compiler"
8
+
9
+ gem "rack", "~> 1.6"
10
+ gem "minitest", '~> 5.9'
11
+
12
+ gem "jruby-openssl", :platform => "jruby"
@@ -0,0 +1,15 @@
1
+ # Standard libraries
2
+ require 'socket'
3
+ require 'tempfile'
4
+ require 'time'
5
+ require 'etc'
6
+ require 'uri'
7
+ require 'stringio'
8
+
9
+ require 'thread'
10
+
11
+ module Puma
12
+ autoload :Const, 'puma/const'
13
+ autoload :Server, 'puma/server'
14
+ autoload :Launcher, 'puma/launcher'
15
+ end
@@ -0,0 +1,23 @@
1
+ require 'openssl'
2
+
3
+ module OpenSSL
4
+ module SSL
5
+ class SSLServer
6
+ unless public_method_defined? :accept_nonblock
7
+ def accept_nonblock
8
+ sock = @svr.accept_nonblock
9
+
10
+ begin
11
+ ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx)
12
+ ssl.sync_close = true
13
+ ssl.accept if @start_immediately
14
+ ssl
15
+ rescue SSLError => ex
16
+ sock.close
17
+ raise ex
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,66 @@
1
+ module Puma
2
+ module App
3
+ class Status
4
+ def initialize(cli)
5
+ @cli = cli
6
+ @auth_token = nil
7
+ end
8
+ OK_STATUS = '{ "status": "ok" }'.freeze
9
+
10
+ attr_accessor :auth_token
11
+
12
+ def authenticate(env)
13
+ return true unless @auth_token
14
+ env['QUERY_STRING'].to_s.split(/&;/).include?("token=#{@auth_token}")
15
+ end
16
+
17
+ def rack_response(status, body, content_type='application/json')
18
+ headers = {
19
+ 'Content-Type' => content_type,
20
+ 'Content-Length' => body.bytesize.to_s
21
+ }
22
+
23
+ [status, headers, [body]]
24
+ end
25
+
26
+ def call(env)
27
+ unless authenticate(env)
28
+ return rack_response(403, 'Invalid auth token', 'text/plain')
29
+ end
30
+
31
+ case env['PATH_INFO']
32
+ when /\/stop$/
33
+ @cli.stop
34
+ return rack_response(200, OK_STATUS)
35
+
36
+ when /\/halt$/
37
+ @cli.halt
38
+ return rack_response(200, OK_STATUS)
39
+
40
+ when /\/restart$/
41
+ @cli.restart
42
+ return rack_response(200, OK_STATUS)
43
+
44
+ when /\/phased-restart$/
45
+ if !@cli.phased_restart
46
+ return rack_response(404, '{ "error": "phased restart not available" }')
47
+ else
48
+ return rack_response(200, OK_STATUS)
49
+ end
50
+
51
+ when /\/reload-worker-directory$/
52
+ if !@cli.send(:reload_worker_directory)
53
+ return rack_response(404, '{ "error": "reload_worker_directory not available" }')
54
+ else
55
+ return rack_response(200, OK_STATUS)
56
+ end
57
+
58
+ when /\/stats$/
59
+ return rack_response(200, @cli.stats)
60
+ else
61
+ rack_response 404, "Unsupported action", 'text/plain'
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,402 @@
1
+ require 'uri'
2
+ require 'socket'
3
+
4
+ require 'puma/const'
5
+ require 'puma/util'
6
+
7
+ module Puma
8
+ class Binder
9
+ include Puma::Const
10
+
11
+ RACK_VERSION = [1,3].freeze
12
+
13
+ def initialize(events)
14
+ @events = events
15
+ @listeners = []
16
+ @inherited_fds = {}
17
+ @activated_sockets = {}
18
+ @unix_paths = []
19
+
20
+ @proto_env = {
21
+ "rack.version".freeze => RACK_VERSION,
22
+ "rack.errors".freeze => events.stderr,
23
+ "rack.multithread".freeze => true,
24
+ "rack.multiprocess".freeze => false,
25
+ "rack.run_once".freeze => false,
26
+ "SCRIPT_NAME".freeze => ENV['SCRIPT_NAME'] || "",
27
+
28
+ # I'd like to set a default CONTENT_TYPE here but some things
29
+ # depend on their not being a default set and inferring
30
+ # it from the content. And so if i set it here, it won't
31
+ # infer properly.
32
+
33
+ "QUERY_STRING".freeze => "",
34
+ SERVER_PROTOCOL => HTTP_11,
35
+ SERVER_SOFTWARE => PUMA_SERVER_STRING,
36
+ GATEWAY_INTERFACE => CGI_VER
37
+ }
38
+
39
+ @envs = {}
40
+ @ios = []
41
+ end
42
+
43
+ attr_reader :listeners, :ios
44
+
45
+ def env(sock)
46
+ @envs.fetch(sock, @proto_env)
47
+ end
48
+
49
+ def close
50
+ @ios.each { |i| i.close }
51
+ @unix_paths.each { |i| File.unlink i }
52
+ end
53
+
54
+ def import_from_env
55
+ remove = []
56
+
57
+ ENV.each do |k,v|
58
+ if k =~ /PUMA_INHERIT_\d+/
59
+ fd, url = v.split(":", 2)
60
+ @inherited_fds[url] = fd.to_i
61
+ remove << k
62
+ elsif k == 'LISTEN_FDS' && ENV['LISTEN_PID'].to_i == $$
63
+ v.to_i.times do |num|
64
+ fd = num + 3
65
+ sock = TCPServer.for_fd(fd)
66
+ begin
67
+ key = [ :unix, Socket.unpack_sockaddr_un(sock.getsockname) ]
68
+ rescue ArgumentError
69
+ port, addr = Socket.unpack_sockaddr_in(sock.getsockname)
70
+ if addr =~ /\:/
71
+ addr = "[#{addr}]"
72
+ end
73
+ key = [ :tcp, addr, port ]
74
+ end
75
+ @activated_sockets[key] = sock
76
+ @events.debug "Registered #{key.join ':'} for activation from LISTEN_FDS"
77
+ end
78
+ remove << k << 'LISTEN_PID'
79
+ end
80
+ end
81
+
82
+ remove.each do |k|
83
+ ENV.delete k
84
+ end
85
+ end
86
+
87
+ def parse(binds, logger)
88
+ binds.each do |str|
89
+ uri = URI.parse str
90
+ case uri.scheme
91
+ when "tcp"
92
+ if fd = @inherited_fds.delete(str)
93
+ logger.log "* Inherited #{str}"
94
+ io = inherit_tcp_listener uri.host, uri.port, fd
95
+ elsif sock = @activated_sockets.delete([ :tcp, uri.host, uri.port ])
96
+ logger.log "* Activated #{str}"
97
+ io = inherit_tcp_listener uri.host, uri.port, sock
98
+ else
99
+ params = Util.parse_query uri.query
100
+
101
+ opt = params.key?('low_latency')
102
+ bak = params.fetch('backlog', 1024).to_i
103
+
104
+ logger.log "* Listening on #{str}"
105
+ io = add_tcp_listener uri.host, uri.port, opt, bak
106
+ end
107
+
108
+ @listeners << [str, io] if io
109
+ when "unix"
110
+ path = "#{uri.host}#{uri.path}".gsub("%20", " ")
111
+
112
+ if fd = @inherited_fds.delete(str)
113
+ logger.log "* Inherited #{str}"
114
+ io = inherit_unix_listener path, fd
115
+ elsif sock = @activated_sockets.delete([ :unix, path ])
116
+ logger.log "* Activated #{str}"
117
+ io = inherit_unix_listener path, sock
118
+ else
119
+ logger.log "* Listening on #{str}"
120
+
121
+ umask = nil
122
+ mode = nil
123
+ backlog = nil
124
+
125
+ if uri.query
126
+ params = Util.parse_query uri.query
127
+ if u = params['umask']
128
+ # Use Integer() to respect the 0 prefix as octal
129
+ umask = Integer(u)
130
+ end
131
+
132
+ if u = params['mode']
133
+ mode = Integer('0'+u)
134
+ end
135
+
136
+ if u = params['backlog']
137
+ backlog = Integer(u)
138
+ end
139
+ end
140
+
141
+ io = add_unix_listener path, umask, mode, backlog
142
+ end
143
+
144
+ @listeners << [str, io]
145
+ when "ssl"
146
+ params = Util.parse_query uri.query
147
+ require 'puma/minissl'
148
+
149
+ MiniSSL.check
150
+
151
+ ctx = MiniSSL::Context.new
152
+
153
+ if defined?(JRUBY_VERSION)
154
+ unless params['keystore']
155
+ @events.error "Please specify the Java keystore via 'keystore='"
156
+ end
157
+
158
+ ctx.keystore = params['keystore']
159
+
160
+ unless params['keystore-pass']
161
+ @events.error "Please specify the Java keystore password via 'keystore-pass='"
162
+ end
163
+
164
+ ctx.keystore_pass = params['keystore-pass']
165
+ else
166
+ unless params['key']
167
+ @events.error "Please specify the SSL key via 'key='"
168
+ end
169
+
170
+ ctx.key = params['key']
171
+
172
+ unless params['cert']
173
+ @events.error "Please specify the SSL cert via 'cert='"
174
+ end
175
+
176
+ ctx.cert = params['cert']
177
+
178
+ if ['peer', 'force_peer'].include?(params['verify_mode'])
179
+ unless params['ca']
180
+ @events.error "Please specify the SSL ca via 'ca='"
181
+ end
182
+ end
183
+
184
+ ctx.ca = params['ca'] if params['ca']
185
+ end
186
+
187
+ if params['verify_mode']
188
+ ctx.verify_mode = case params['verify_mode']
189
+ when "peer"
190
+ MiniSSL::VERIFY_PEER
191
+ when "force_peer"
192
+ MiniSSL::VERIFY_PEER | MiniSSL::VERIFY_FAIL_IF_NO_PEER_CERT
193
+ when "none"
194
+ MiniSSL::VERIFY_NONE
195
+ else
196
+ @events.error "Please specify a valid verify_mode="
197
+ MiniSSL::VERIFY_NONE
198
+ end
199
+ end
200
+
201
+ if fd = @inherited_fds.delete(str)
202
+ logger.log "* Inherited #{str}"
203
+ io = inherit_ssl_listener fd, ctx
204
+ elsif sock = @activated_sockets.delete([ :tcp, uri.host, uri.port ])
205
+ logger.log "* Activated #{str}"
206
+ io = inherit_ssl_listener sock, ctx
207
+ else
208
+ logger.log "* Listening on #{str}"
209
+ io = add_ssl_listener uri.host, uri.port, ctx
210
+ end
211
+
212
+ @listeners << [str, io] if io
213
+ else
214
+ logger.error "Invalid URI: #{str}"
215
+ end
216
+ end
217
+
218
+ # If we inherited fds but didn't use them (because of a
219
+ # configuration change), then be sure to close them.
220
+ @inherited_fds.each do |str, fd|
221
+ logger.log "* Closing unused inherited connection: #{str}"
222
+
223
+ begin
224
+ IO.for_fd(fd).close
225
+ rescue SystemCallError
226
+ end
227
+
228
+ # We have to unlink a unix socket path that's not being used
229
+ uri = URI.parse str
230
+ if uri.scheme == "unix"
231
+ path = "#{uri.host}#{uri.path}"
232
+ File.unlink path
233
+ end
234
+ end
235
+
236
+ # Also close any unused activated sockets
237
+ @activated_sockets.each do |key, sock|
238
+ logger.log "* Closing unused activated socket: #{key.join ':'}"
239
+ begin
240
+ sock.close
241
+ rescue SystemCallError
242
+ end
243
+ # We have to unlink a unix socket path that's not being used
244
+ File.unlink key[1] if key[0] == :unix
245
+ end
246
+ end
247
+
248
+ def localhost_addresses
249
+ addrs = TCPSocket.gethostbyname "localhost"
250
+ addrs[3..-1].uniq
251
+ end
252
+
253
+ # Tell the server to listen on host +host+, port +port+.
254
+ # If +optimize_for_latency+ is true (the default) then clients connecting
255
+ # will be optimized for latency over throughput.
256
+ #
257
+ # +backlog+ indicates how many unaccepted connections the kernel should
258
+ # allow to accumulate before returning connection refused.
259
+ #
260
+ def add_tcp_listener(host, port, optimize_for_latency=true, backlog=1024)
261
+ if host == "localhost"
262
+ localhost_addresses.each do |addr|
263
+ add_tcp_listener addr, port, optimize_for_latency, backlog
264
+ end
265
+ return
266
+ end
267
+
268
+ host = host[1..-2] if host and host[0..0] == '['
269
+ s = TCPServer.new(host, port)
270
+ if optimize_for_latency
271
+ s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
272
+ end
273
+ s.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
274
+ s.listen backlog
275
+ @connected_port = s.addr[1]
276
+
277
+ @ios << s
278
+ s
279
+ end
280
+
281
+ attr_reader :connected_port
282
+
283
+ def inherit_tcp_listener(host, port, fd)
284
+ if fd.kind_of? TCPServer
285
+ s = fd
286
+ else
287
+ s = TCPServer.for_fd(fd)
288
+ end
289
+
290
+ @ios << s
291
+ s
292
+ end
293
+
294
+ def add_ssl_listener(host, port, ctx,
295
+ optimize_for_latency=true, backlog=1024)
296
+ require 'puma/minissl'
297
+
298
+ MiniSSL.check
299
+
300
+ if host == "localhost"
301
+ localhost_addresses.each do |addr|
302
+ add_ssl_listener addr, port, ctx, optimize_for_latency, backlog
303
+ end
304
+ return
305
+ end
306
+
307
+ host = host[1..-2] if host[0..0] == '['
308
+ s = TCPServer.new(host, port)
309
+ if optimize_for_latency
310
+ s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
311
+ end
312
+ s.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
313
+ s.listen backlog
314
+
315
+ ssl = MiniSSL::Server.new s, ctx
316
+ env = @proto_env.dup
317
+ env[HTTPS_KEY] = HTTPS
318
+ @envs[ssl] = env
319
+
320
+ @ios << ssl
321
+ s
322
+ end
323
+
324
+ def inherit_ssl_listener(fd, ctx)
325
+ require 'puma/minissl'
326
+ MiniSSL.check
327
+
328
+ if fd.kind_of? TCPServer
329
+ s = fd
330
+ else
331
+ s = TCPServer.for_fd(fd)
332
+ end
333
+ ssl = MiniSSL::Server.new(s, ctx)
334
+
335
+ env = @proto_env.dup
336
+ env[HTTPS_KEY] = HTTPS
337
+ @envs[ssl] = env
338
+
339
+ @ios << ssl
340
+
341
+ s
342
+ end
343
+
344
+ # Tell the server to listen on +path+ as a UNIX domain socket.
345
+ #
346
+ def add_unix_listener(path, umask=nil, mode=nil, backlog=nil)
347
+ @unix_paths << path
348
+
349
+ # Let anyone connect by default
350
+ umask ||= 0
351
+
352
+ begin
353
+ old_mask = File.umask(umask)
354
+
355
+ if File.exist? path
356
+ begin
357
+ old = UNIXSocket.new path
358
+ rescue SystemCallError, IOError
359
+ File.unlink path
360
+ else
361
+ old.close
362
+ raise "There is already a server bound to: #{path}"
363
+ end
364
+ end
365
+
366
+ s = UNIXServer.new(path)
367
+ s.listen backlog if backlog
368
+ @ios << s
369
+ ensure
370
+ File.umask old_mask
371
+ end
372
+
373
+ if mode
374
+ File.chmod mode, path
375
+ end
376
+
377
+ env = @proto_env.dup
378
+ env[REMOTE_ADDR] = "127.0.0.1"
379
+ @envs[s] = env
380
+
381
+ s
382
+ end
383
+
384
+ def inherit_unix_listener(path, fd)
385
+ @unix_paths << path
386
+
387
+ if fd.kind_of? TCPServer
388
+ s = fd
389
+ else
390
+ s = UNIXServer.for_fd fd
391
+ end
392
+ @ios << s
393
+
394
+ env = @proto_env.dup
395
+ env[REMOTE_ADDR] = "127.0.0.1"
396
+ @envs[s] = env
397
+
398
+ s
399
+ end
400
+
401
+ end
402
+ end