public
Description: Phusion Passenger (mod_rails)
Homepage: http://www.modrails.com/
Clone URL: git://github.com/FooBarWidget/passenger.git
Click here to lend your support to: passenger and make a donation at www.pledgie.com !
Get rid of the support for abstract Unix sockets, but add basic infrastructure 
for supporting other kinds of listener sockets in the future (e.g. TCP 
sockets).
Hongli Lai (Phusion) (author)
Thu Nov 20 10:50:56 -0800 2008
commit  8e305273f505214c4f1efe7db1b1633fb29f41e4
tree    e5498170a742c214bddfe6642022be3a235ed7d0
parent  ba851417590bcd7e86fb0b13a438a1186cee15b4
...
316
317
318
319
 
320
321
322
...
328
329
330
331
332
333
 
 
334
335
336
337
338
 
339
340
341
342
 
343
344
345
...
353
354
355
356
 
357
358
359
...
425
426
427
 
 
 
 
428
429
430
...
437
438
439
440
441
442
443
444
445
 
446
447
448
...
316
317
318
 
319
320
321
322
...
328
329
330
 
 
 
331
332
333
334
335
336
 
337
338
339
340
 
341
342
343
344
...
352
353
354
 
355
356
357
358
...
424
425
426
427
428
429
430
431
432
433
...
440
441
442
 
 
 
 
 
 
443
444
445
446
0
@@ -316,7 +316,7 @@ private:
0
   string appRoot;
0
   pid_t pid;
0
   string listenSocketName;
0
-  bool usingAbstractNamespace;
0
+  string listenSocketType;
0
   int ownerPipe;
0
 
0
 public:
0
@@ -328,18 +328,17 @@ public:
0
    *             This must be a valid directory, but the path does not have to be absolute.
0
    * @param pid The process ID of this application instance.
0
    * @param listenSocketName The name of the listener socket of this application instance.
0
-   * @param usingAbstractNamespace Whether <tt>listenSocketName</tt> refers to a Unix
0
-   *        socket on the abstract namespace. Note that listenSocketName must not
0
-   *        contain the leading null byte, even if it's an abstract namespace socket.
0
+   * @param listenSocketType The type of the listener socket, e.g. "unix" for Unix
0
+   *                         domain sockets.
0
    * @param ownerPipe The owner pipe of this application instance.
0
    * @post getAppRoot() == theAppRoot && getPid() == pid
0
    */
0
   Application(const string &theAppRoot, pid_t pid, const string &listenSocketName,
0
-              bool usingAbstractNamespace, int ownerPipe) {
0
+              const string &listenSocketType, int ownerPipe) {
0
     appRoot = theAppRoot;
0
     this->pid = pid;
0
     this->listenSocketName = listenSocketName;
0
-    this->usingAbstractNamespace = usingAbstractNamespace;
0
+    this->listenSocketType = listenSocketType;
0
     this->ownerPipe = ownerPipe;
0
     P_TRACE(3, "Application " << this << ": created.");
0
   }
0
@@ -353,7 +352,7 @@ public:
0
         ret = close(ownerPipe);
0
       } while (ret == -1 && errno == EINTR);
0
     }
0
-    if (!usingAbstractNamespace) {
0
+    if (listenSocketType == "unix") {
0
       do {
0
         ret = unlink(listenSocketName.c_str());
0
       } while (ret == -1 && errno == EINTR);
0
@@ -425,6 +424,10 @@ public:
0
    * @throws IOException Something went wrong during the connection process.
0
    */
0
   SessionPtr connect(const function<void()> &closeCallback) const {
0
+    if (listenSocketType != "unix") {
0
+      throw "TODO: implement support for socket types other than 'unix'";
0
+    }
0
+    
0
     TRACE_POINT();
0
     int fd, ret;
0
     
0
@@ -437,12 +440,7 @@ public:
0
     
0
     struct sockaddr_un addr;
0
     addr.sun_family = AF_UNIX;
0
-    if (usingAbstractNamespace) {
0
-      strncpy(addr.sun_path + 1, listenSocketName.c_str(), sizeof(addr.sun_path) - 1);
0
-      addr.sun_path[0] = '\0';
0
-    } else {
0
-      strncpy(addr.sun_path, listenSocketName.c_str(), sizeof(addr.sun_path));
0
-    }
0
+    strncpy(addr.sun_path, listenSocketName.c_str(), sizeof(addr.sun_path));
0
     addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
0
     do {
0
       ret = ::connect(fd, (const sockaddr *) &addr, sizeof(addr));
...
314
315
316
317
318
319
320
 
321
322
323
...
327
328
329
330
 
331
332
333
...
314
315
316
 
317
318
 
319
320
321
322
...
326
327
328
 
329
330
331
332
0
@@ -314,10 +314,9 @@ private:
0
     }
0
     
0
     pid_t pid = atoi(args[0]);
0
-    bool usingAbstractNamespace = args[2] == "true";
0
     
0
     UPDATE_TRACE_POINT();
0
-    if (!usingAbstractNamespace) {
0
+    if (args[2] == "unix") {
0
       int ret;
0
       do {
0
         ret = chmod(args[1].c_str(), S_IRUSR | S_IWUSR);
0
@@ -327,7 +326,7 @@ private:
0
       } while (ret == -1 && errno == EINTR);
0
     }
0
     return ApplicationPtr(new Application(spawnOptions.appRoot,
0
-      pid, args[1], usingAbstractNamespace, ownerPipe));
0
+      pid, args[1], args[2], ownerPipe));
0
   }
0
   
0
   /**
...
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
...
111
112
113
114
115
 
 
116
117
118
119
120
 
121
122
 
 
 
 
123
124
125
...
142
143
144
145
146
147
148
149
150
151
152
 
 
153
154
155
...
174
175
176
177
178
179
180
181
182
183
184
 
185
186
187
...
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
...
432
433
434
435
436
437
438
439
440
441
442
...
39
40
41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
43
44
...
96
97
98
 
 
99
100
101
 
 
 
 
102
103
104
105
106
107
108
109
110
111
...
128
129
130
 
 
 
 
 
 
 
 
131
132
133
134
135
...
154
155
156
 
 
 
 
 
 
 
 
157
158
159
160
...
241
242
243
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244
245
246
...
378
379
380
 
 
 
 
 
381
382
383
0
@@ -39,21 +39,6 @@ module Passenger
0
 # administrator maintenance overhead. These decisions are documented
0
 # in this section.
0
 #
0
-# === Abstract namespace Unix sockets
0
-#
0
-# AbstractRequestHandler listens on a Unix socket for incoming requests. If possible,
0
-# AbstractRequestHandler will try to create a Unix socket on the _abstract namespace_,
0
-# instead of on the filesystem. If the RoR application crashes (segfault),
0
-# or if it gets killed by SIGKILL, or if the system loses power, then there
0
-# will be no stale socket files left on the filesystem.
0
-# Unfortunately, abstract namespace Unix sockets are only supported by Linux.
0
-# On systems that do not support abstract namespace Unix sockets,
0
-# AbstractRequestHandler will automatically fallback to using regular Unix socket files.
0
-#
0
-# It is possible to force AbstractRequestHandler to use regular Unix socket files by
0
-# setting the environment variable PASSENGER_NO_ABSTRACT_NAMESPACE_SOCKETS
0
-# to 1.
0
-#
0
 # === Owner pipes
0
 #
0
 # Because only the web server communicates directly with a request handler,
0
@@ -111,15 +96,16 @@ class AbstractRequestHandler
0
   X_POWERED_BY        = 'X-Powered-By'        # :nodoc:
0
   
0
   # The name of the socket on which the request handler accepts
0
-  # new connections. This is either a Unix socket filename, or
0
-  # the name for an abstract namespace Unix socket.
0
+  # new connections. At this moment, this value is always the filename
0
+  # of a Unix domain socket.
0
   #
0
-  # If +socket_name+ refers to an abstract namespace Unix socket,
0
-  # then the name does _not_ contain a leading null byte.
0
-  #
0
-  # See also using_abstract_namespace?
0
+  # See also #socket_type.
0
   attr_reader :socket_name
0
   
0
+  # The type of socket that #socket_name refers to. At the moment, the
0
+  # value is always 'unix', which indicates a Unix domain socket.
0
+  attr_reader :socket_type
0
+  
0
   # Specifies the maximum allowed memory usage, in MB. If after having processed
0
   # a request AbstractRequestHandler detects that memory usage has risen above
0
   # this limit, then it will gracefully exit (that is, exit after having processed
0
@@ -142,14 +128,8 @@ class AbstractRequestHandler
0
   # Additionally, the following options may be given:
0
   # - memory_limit: Used to set the +memory_limit+ attribute.
0
   def initialize(owner_pipe, options = {})
0
-    if abstract_namespace_sockets_allowed?
0
-      @using_abstract_namespace = create_unix_socket_on_abstract_namespace
0
-    else
0
-      @using_abstract_namespace = false
0
-    end
0
-    if !@using_abstract_namespace
0
-      create_unix_socket_on_filesystem
0
-    end
0
+    @socket_type = 'unix'
0
+    create_unix_socket_on_filesystem
0
     @socket.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
0
     @owner_pipe = owner_pipe
0
     @previous_signal_handlers = {}
0
@@ -174,14 +154,7 @@ class AbstractRequestHandler
0
     end
0
     @socket.close rescue nil
0
     @owner_pipe.close rescue nil
0
-    if !using_abstract_namespace?
0
-      File.unlink(@socket_name) rescue nil
0
-    end
0
-  end
0
-  
0
-  # Returns whether socket_name refers to an abstract namespace Unix socket.
0
-  def using_abstract_namespace?
0
-    return @using_abstract_namespace
0
+    File.unlink(@socket_name) rescue nil
0
   end
0
   
0
   # Check whether the main loop's currently running.
0
@@ -268,33 +241,6 @@ class AbstractRequestHandler
0
 private
0
   include Utils
0
 
0
-  def create_unix_socket_on_abstract_namespace
0
-    while true
0
-      begin
0
-        # I have no idea why, but using base64-encoded IDs
0
-        # don't pass the unit tests. I couldn't find the cause
0
-        # of the problem. The system supports base64-encoded
0
-        # names for abstract namespace unix sockets just fine.
0
-        @socket_name = generate_random_id(:hex)
0
-        @socket_name = @socket_name.slice(0, NativeSupport::UNIX_PATH_MAX - 2)
0
-        fd = NativeSupport.create_unix_socket("\x00#{socket_name}", BACKLOG_SIZE)
0
-        @socket = IO.new(fd)
0
-        @socket.instance_eval do
0
-          def accept
0
-            fd = NativeSupport.accept(fileno)
0
-            return IO.new(fd)
0
-          end
0
-        end
0
-        return true
0
-      rescue Errno::EADDRINUSE
0
-        # Do nothing, try again with another name.
0
-      rescue Errno::ENOENT
0
-        # Abstract namespace sockets not supported on this system.
0
-        return false
0
-      end
0
-    end
0
-  end
0
-  
0
   def create_unix_socket_on_filesystem
0
     done = false
0
     while !done
0
@@ -432,11 +378,6 @@ private
0
     return data
0
   end
0
   
0
-  def abstract_namespace_sockets_allowed?
0
-    value = ENV['PASSENGER_NO_ABSTRACT_NAMESPACE_SOCKETS']
0
-    return value.nil? || value.empty?
0
-  end
0
-
0
   def self.determine_passenger_version
0
     rakefile = "#{File.dirname(__FILE__)}/../../Rakefile"
0
     if File.exist?(rakefile)
...
29
30
31
32
33
 
 
 
34
35
 
 
 
 
 
36
37
38
...
80
81
82
83
 
84
85
86
87
 
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
...
29
30
31
 
 
32
33
34
35
36
37
38
39
40
41
42
43
44
...
86
87
88
 
89
90
91
92
 
93
94
95
96
 
 
 
 
 
 
 
 
 
97
98
99
0
@@ -29,10 +29,16 @@ class Application
0
   # The process ID of this application instance.
0
   attr_reader :pid
0
   
0
-  # The name of the Unix socket on which the application instance will accept
0
-  # new connections.
0
+  # The name of the socket on which the application instance will accept
0
+  # new connections. See #listen_socket_type on how one should interpret
0
+  # this value.
0
   attr_reader :listen_socket_name
0
   
0
+  # The type of socket that #listen_socket_name refers to. Currently this
0
+  # is always 'unix', which means that #listen_socket_name refers to the
0
+  # filename of a Unix domain socket.
0
+  attr_reader :listen_socket_type
0
+  
0
   # The owner pipe of the application instance (an IO object). Please see
0
   # RequestHandler for a description of the owner pipe.
0
   attr_reader :owner_pipe
0
@@ -80,23 +86,14 @@ class Application
0
 
0
   # Creates a new instance of Application. The parameters correspond with the attributes
0
   # of the same names. No exceptions will be thrown.
0
-  def initialize(app_root, pid, listen_socket_name, using_abstract_namespace, owner_pipe)
0
+  def initialize(app_root, pid, listen_socket_name, listen_socket_type, owner_pipe)
0
     @app_root = app_root
0
     @pid = pid
0
     @listen_socket_name = listen_socket_name
0
-    @using_abstract_namespace = using_abstract_namespace
0
+    @listen_socket_type = listen_socket_type
0
     @owner_pipe = owner_pipe
0
   end
0
   
0
-  # Whether _listen_socket_name_ refers to a Unix socket in the abstract namespace.
0
-  # In any case, _listen_socket_name_ does *not* contain the leading null byte.
0
-  #
0
-  # Note that at the moment, only Linux seems to support abstract namespace Unix
0
-  # sockets.
0
-  def using_abstract_namespace?
0
-    return @using_abstract_namespace
0
-  end
0
-  
0
   # Close the connection with the application instance. If there are no other
0
   # processes that have connections to this application instance, then it will
0
   # shutdown as soon as possible.
...
65
66
67
68
 
69
70
71
72
73
74
 
75
76
77
...
94
95
96
97
 
98
99
100
...
65
66
67
 
68
69
70
71
72
73
 
74
75
76
77
...
94
95
96
 
97
98
99
100
0
@@ -65,13 +65,13 @@ class ApplicationSpawner
0
     unmarshal_and_raise_errors(channel, "rack")
0
     
0
     # No exception was raised, so spawning succeeded.
0
-    pid, socket_name, using_abstract_namespace = channel.read
0
+    pid, socket_name, socket_type = channel.read
0
     if pid.nil?
0
       raise IOError, "Connection closed"
0
     end
0
     owner_pipe = channel.recv_io
0
     return Application.new(@app_root, pid, socket_name,
0
-      using_abstract_namespace == "true", owner_pipe)
0
+      socket_type, owner_pipe)
0
   end
0
 
0
 private
0
@@ -94,7 +94,7 @@ private
0
       begin
0
         handler = RequestHandler.new(reader, app, options)
0
         channel.write(Process.pid, handler.socket_name,
0
-          handler.using_abstract_namespace?)
0
+          handler.socket_type)
0
         channel.send_io(writer)
0
         writer.close
0
         channel.close
...
108
109
110
111
 
112
113
114
115
116
117
 
118
119
120
...
171
172
173
174
 
175
176
177
178
179
180
 
181
182
183
...
316
317
318
319
 
320
321
322
...
108
109
110
 
111
112
113
114
115
116
 
117
118
119
120
...
171
172
173
 
174
175
176
177
178
179
 
180
181
182
183
...
316
317
318
 
319
320
321
322
0
@@ -108,13 +108,13 @@ class ApplicationSpawner < AbstractServer
0
   # - ApplicationSpawner::Error: The ApplicationSpawner server exited unexpectedly.
0
   def spawn_application
0
     server.write("spawn_application")
0
-    pid, socket_name, using_abstract_namespace = server.read
0
+    pid, socket_name, socket_type = server.read
0
     if pid.nil?
0
       raise IOError, "Connection closed"
0
     end
0
     owner_pipe = server.recv_io
0
     return Application.new(@app_root, pid, socket_name,
0
-      using_abstract_namespace == "true", owner_pipe)
0
+      socket_type, owner_pipe)
0
   rescue SystemCallError, IOError, SocketError => e
0
     raise Error, "The application spawner server exited unexpectedly"
0
   end
0
@@ -171,13 +171,13 @@ class ApplicationSpawner < AbstractServer
0
     unmarshal_and_raise_errors(channel)
0
     
0
     # No exception was raised, so spawning succeeded.
0
-    pid, socket_name, using_abstract_namespace = channel.read
0
+    pid, socket_name, socket_type = channel.read
0
     if pid.nil?
0
       raise IOError, "Connection closed"
0
     end
0
     owner_pipe = channel.recv_io
0
     return Application.new(@app_root, pid, socket_name,
0
-      using_abstract_namespace == "true", owner_pipe)
0
+      socket_type, owner_pipe)
0
   end
0
   
0
   # Overrided from AbstractServer#start.
0
@@ -316,7 +316,7 @@ private
0
       reader.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
0
       handler = RequestHandler.new(reader, @options)
0
       channel.write(Process.pid, handler.socket_name,
0
-        handler.using_abstract_namespace?)
0
+        handler.socket_type)
0
       channel.send_io(writer)
0
       writer.close
0
       channel.close
...
171
172
173
174
 
175
176
177
178
179
180
 
181
182
183
...
317
318
319
320
 
321
322
323
...
171
172
173
 
174
175
176
177
178
179
 
180
181
182
183
...
317
318
319
 
320
321
322
323
0
@@ -171,13 +171,13 @@ class FrameworkSpawner < AbstractServer
0
         end
0
         raise e
0
       else
0
-        pid, listen_socket_name, using_abstract_namespace = server.read
0
+        pid, listen_socket_name, socket_type = server.read
0
         if pid.nil?
0
           raise IOError, "Connection closed"
0
         end
0
         owner_pipe = server.recv_io
0
         return Application.new(app_root, pid, listen_socket_name,
0
-          using_abstract_namespace == "true", owner_pipe)
0
+          socket_type, owner_pipe)
0
       end
0
     rescue SystemCallError, IOError, SocketError => e
0
       raise Error, "The framework spawner server exited unexpectedly"
0
@@ -317,7 +317,7 @@ private
0
       end
0
     end
0
     client.write('success')
0
-    client.write(app.pid, app.listen_socket_name, app.using_abstract_namespace?)
0
+    client.write(app.pid, app.listen_socket_name, app.listen_socket_type)
0
     client.send_io(app.owner_pipe)
0
     app.close
0
   end
...
330
331
332
333
 
 
334
335
336
...
330
331
332
 
333
334
335
336
337
0
@@ -330,7 +330,8 @@ private
0
     if app
0
       begin
0
         client.write('ok')
0
-        client.write(app.pid, app.listen_socket_name, app.using_abstract_namespace?)
0
+        client.write(app.pid, app.listen_socket_name,
0
+          app.listen_socket_type)
0
         client.send_io(app.owner_pipe)
0
       rescue Errno::EPIPE
0
         # The Apache module may be interrupted during a spawn command,
...
54
55
56
57
 
58
59
60
61
62
63
 
64
65
66
...
76
77
78
79
 
80
81
82
...
54
55
56
 
57
58
59
60
61
62
 
63
64
65
66
...
76
77
78
 
79
80
81
82
0
@@ -54,13 +54,13 @@ class ApplicationSpawner
0
     Process.waitpid(pid) rescue nil
0
     
0
     channel = MessageChannel.new(a)
0
-    pid, socket_name, using_abstract_namespace = channel.read
0
+    pid, socket_name, socket_type = channel.read
0
     if pid.nil?
0
       raise IOError, "Connection closed"
0
     end
0
     owner_pipe = channel.recv_io
0
     return Application.new(@app_root, pid, socket_name,
0
-      using_abstract_namespace == "true", owner_pipe)
0
+      socket_type, owner_pipe)
0
   end
0
 
0
 private
0
@@ -76,7 +76,7 @@ private
0
     server = UNIXServer.new(socket_file)
0
     begin
0
       reader, writer = IO.pipe
0
-      channel.write(Process.pid, socket_file, "false")
0
+      channel.write(Process.pid, socket_file, "unix")
0
       channel.send_io(writer)
0
       writer.close
0
       channel.close
...
8
9
10
11
 
12
13
14
...
19
20
21
 
 
22
23
24
...
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
 
 
68
69
70
...
8
9
10
 
11
12
13
14
...
19
20
21
22
23
24
25
26
...
52
53
54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
56
57
58
59
0
@@ -8,7 +8,7 @@ include Passenger
0
 
0
 describe AbstractRequestHandler do
0
   before :each do
0
-    prepare
0
+    ENV['PHUSION_PASSENGER_TMP'] = "abstract_request_handler_spec.tmp"
0
     @owner_pipe = IO.pipe
0
     @request_handler = AbstractRequestHandler.new(@owner_pipe[1])
0
     def @request_handler.process_request(*args)
0
@@ -19,6 +19,8 @@ describe AbstractRequestHandler do
0
   after :each do
0
     @request_handler.cleanup
0
     @owner_pipe[0].close rescue nil
0
+    ENV.delete('PHUSION_PASSENGER_TMP')
0
+    FileUtils.rm_rf("abstract_request_handler_spec.tmp")
0
   end
0
   
0
   def prepare
0
@@ -50,21 +52,8 @@ describe AbstractRequestHandler do
0
     @request_handler.processed_requests.should == 0
0
   end
0
   
0
-  describe "if abstract namespace sockets are not supported on the current platform" do
0
-    def prepare
0
-      ENV['PASSENGER_NO_ABSTRACT_NAMESPACE_SOCKETS'] = "true"
0
-      ENV['PHUSION_PASSENGER_TMP'] = "abstract_request_handler_spec.tmp"
0
-    end
0
-    
0
-    after :each do
0
-      ENV.delete('PASSENGER_NO_ABSTRACT_NAMESPACE_SOCKETS')
0
-      ENV.delete('PHUSION_PASSENGER_TMP')
0
-      FileUtils.rm_rf("abstract_request_handler_spec.tmp")
0
-    end
0
-    
0
-    it "creates a socket file in the Phusion Passenger temp folder" do
0
-      Dir["abstract_request_handler_spec.tmp/*"].should_not be_empty
0
-    end
0
+  it "creates a socket file in the Phusion Passenger temp folder" do
0
+    Dir["abstract_request_handler_spec.tmp/*"].should_not be_empty
0
   end
0
   
0
   def wait_until

Comments