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 !
Apparently abstract namespace Unix sockets are only supported on Linux. 
Fallback to regular Unix sockets if abstract namespace sockets are not 
available on the current platform.
Hongli Lai (Phusion) (author)
Tue Feb 26 15:58:28 -0800 2008
commit  37eb17c047f28b44ea7200bedf627839a61cba95
tree    5f4863100139e981de63e697fb452f202706ac00
parent  8ec97a13a3d1015f74d360885276f8b91ae8be16
0
...
30
31
32
33
 
 
 
 
34
35
36
...
30
31
32
 
33
34
35
36
37
38
39
0
@@ -30,7 +30,10 @@ on Apache a breeze. It follows the usual Ruby on Rails conventions, such as
0
     management.
0
   * Passenger makes no use of temporary files or sockets, so even after a hard
0
     system crash, the administrator does not have to manually clean up stale
0
- files.
0
+ files. *
0
+
0
+ <em>* This is only possible on Linux. On systems such as BSD, Passenger
0
+ falls back to using temporary Unix sockets.</em>
0
   * If Passenger encounters an error, and it knows that it can be automatically
0
     recovered, then Passenger will do that. The administrator should not have
0
     to run server monitoring software to monitor Rails applications. Rails
...
267
268
269
270
 
271
272
273
...
315
316
317
318
319
 
320
321
322
...
267
268
269
 
270
271
272
273
...
315
316
317
 
 
318
319
320
321
0
@@ -267,7 +267,7 @@ Rake::RDocTask.new do |rd|
0
   rd.rdoc_files.include("README", "lib/mod_rails/*.rb", "lib/rake/extensions.rb", "ext/mod_rails/*.c")
0
   rd.template = "./doc/template/horo"
0
   rd.title = "Passenger Ruby API"
0
- rd.options << "-S" << "-N" << "-p" << "-d"
0
+ rd.options << "-S" << "-N" << "-p" << "-H" << "-d"
0
 end
0
 
0
 
0
@@ -315,8 +315,7 @@ spec = Gem::Specification.new do |s|
0
   s.has_rdoc = true
0
   s.extra_rdoc_files = ['README']
0
   s.rdoc_options <<
0
- '-S' <<
0
- '-N' <<
0
+ "-S" << "-N" << "-p" << "-H" << "-d" <<
0
     '--main' << 'README' <<
0
     '--template' << './doc/template/horo' <<
0
     '--title' << 'Passenger Ruby API'
...
219
220
221
 
222
223
224
...
230
231
232
 
 
 
233
234
235
236
 
 
237
238
239
 
240
241
242
243
244
245
 
 
 
246
247
248
...
319
320
321
322
323
 
 
 
 
 
 
324
325
326
...
219
220
221
222
223
224
225
...
231
232
233
234
235
236
237
238
239
 
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
...
328
329
330
 
 
331
332
333
334
335
336
337
338
339
0
@@ -219,6 +219,7 @@ private:
0
   string appRoot;
0
   pid_t pid;
0
   string listenSocketName;
0
+ bool usingAbstractNamespace;
0
   int ownerPipe;
0
 
0
 public:
0
@@ -230,19 +231,27 @@ public:
0
    * 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 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, int ownerPipe) {
0
+ Application(const string &theAppRoot, pid_t pid, const string &listenSocketName,
0
+ bool usingAbstractNamespace, int ownerPipe) {
0
     appRoot = theAppRoot;
0
     this->pid = pid;
0
     this->listenSocketName = listenSocketName;
0
+ this->usingAbstractNamespace = usingAbstractNamespace;
0
     this->ownerPipe = ownerPipe;
0
     P_TRACE("Application " << this << ": created.");
0
   }
0
   
0
   virtual ~Application() {
0
     close(ownerPipe);
0
+ if (usingAbstractNamespace) {
0
+ unlink(listenSocketName.c_str());
0
+ }
0
     P_TRACE("Application " << this << ": destroyed.");
0
   }
0
   
0
@@ -319,8 +328,12 @@ public:
0
     
0
     struct sockaddr_un addr;
0
     addr.sun_family = AF_UNIX;
0
- strncpy(addr.sun_path + 1, listenSocketName.c_str(), sizeof(addr.sun_path) - 1);
0
- addr.sun_path[0] = '\0';
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
     addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
0
     do {
0
       ret = ::connect(fd, (const sockaddr *) &addr, sizeof(addr));
...
210
211
212
213
 
214
215
216
 
217
218
 
 
 
 
 
 
 
 
219
220
221
...
210
211
212
 
213
214
215
216
217
218
 
219
220
221
222
223
224
225
226
227
228
229
0
@@ -210,12 +210,20 @@ private:
0
         e.what());
0
     }
0
     
0
- if (args.size() != 2) {
0
+ if (args.size() != 3) {
0
       close(ownerPipe);
0
       throw SpawnException("The spawn server sent an unknown message.");
0
     }
0
+
0
     pid_t pid = atoi(args[0]);
0
- return ApplicationPtr(new Application(appRoot, pid, args[1], ownerPipe));
0
+ bool usingAbstractNamespace = args[2] == "true";
0
+
0
+ if (!usingAbstractNamespace) {
0
+ chmod(args[1].c_str(), S_IRUSR | S_IWUSR);
0
+ chown(args[1].c_str(), getuid(), getgid());
0
+ }
0
+ return ApplicationPtr(new Application(appRoot, pid, args[1],
0
+ usingAbstractNamespace, ownerPipe));
0
   }
0
   
0
   ApplicationPtr
...
148
149
150
 
 
151
152
...
148
149
150
151
152
153
154
0
@@ -148,5 +148,7 @@ Init_native_support() {
0
   rb_define_singleton_method(mNativeSupport, "recv_fd", recv_fd, 1);
0
   rb_define_singleton_method(mNativeSupport, "create_unix_socket", create_unix_socket, 2);
0
   rb_define_singleton_method(mNativeSupport, "accept", f_accept, 1);
0
+
0
+ /* The maximum length of a Unix socket path, including terminating null. */
0
   rb_define_const(mNativeSupport, "UNIX_PATH_MAX", INT2NUM(sizeof(addr.sun_path)));
0
 }
...
10
11
12
13
14
 
15
16
17
...
28
29
30
31
 
32
33
34
 
35
36
37
 
 
 
 
 
 
 
 
 
38
39
40
...
10
11
12
 
 
13
14
15
16
...
27
28
29
 
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
0
@@ -10,8 +10,7 @@ class Application
0
   attr_reader :pid
0
   
0
   # The name of the Unix socket on which the application instance will accept
0
- # new connections. This name refers to a socket in the abstract namespace,
0
- # but does not contain the leading null byte.
0
+ # new connections.
0
   attr_reader :listen_socket_name
0
   
0
   attr_reader :owner_pipe
0
@@ -28,13 +27,23 @@ 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, owner_pipe)
0
+ def initialize(app_root, pid, listen_socket_name, using_abstract_namespace, 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
     @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 abstract namespace Unix sockets are only supported on Linux
0
+ # at the moment.
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.
...
59
60
61
62
 
63
64
 
 
65
66
67
...
154
155
156
157
 
 
158
159
160
...
59
60
61
 
62
63
 
64
65
66
67
68
...
155
156
157
 
158
159
160
161
162
0
@@ -59,9 +59,10 @@ class ApplicationSpawner < AbstractServer
0
   # application's exception message will be printed to standard error.
0
   def spawn_application
0
     server.write("spawn_application")
0
- pid, socket_name = server.read
0
+ pid, socket_name, using_abstract_namespace = server.read
0
     owner_pipe = server.recv_io
0
- return Application.new(@app_root, pid, socket_name, owner_pipe)
0
+ return Application.new(@app_root, pid, socket_name,
0
+ using_abstract_namespace == "true", owner_pipe)
0
   rescue SystemCallError, IOError, SocketError
0
     raise SpawnError, "Unable to spawn the application: application died unexpectedly during initialization."
0
   end
0
@@ -154,7 +155,8 @@ private
0
     reader, writer = IO.pipe
0
     begin
0
       handler = RequestHandler.new(reader)
0
- client.write(Process.pid, handler.socket_name)
0
+ client.write(Process.pid, handler.socket_name,
0
+ handler.using_abstract_namespace?)
0
       client.send_io(writer)
0
       writer.close
0
       client.close
...
72
73
74
75
 
76
77
 
 
78
79
80
...
179
180
181
182
 
183
184
185
...
72
73
74
 
75
76
 
77
78
79
80
81
...
180
181
182
 
183
184
185
186
0
@@ -72,9 +72,10 @@ class FrameworkSpawner < AbstractServer
0
     assert_valid_app_root(app_root)
0
     begin
0
       server.write("spawn_application", app_root, lower_privilege, lowest_user)
0
- pid, listen_socket_name = server.read
0
+ pid, listen_socket_name, using_abstract_namespace = server.read
0
       owner_pipe = server.recv_io
0
- return Application.new(app_root, pid, listen_socket_name, owner_pipe)
0
+ return Application.new(app_root, pid, listen_socket_name,
0
+ using_abstract_namespace == "true", owner_pipe)
0
     rescue SystemCallError, IOError, SocketError
0
       raise ApplicationSpawner::SpawnError, "Unable to spawn the application: " <<
0
         "either the Ruby on Rails framework failed to load, " <<
0
@@ -179,7 +180,7 @@ private
0
       end
0
       spawner.time = Time.now
0
       app = spawner.spawn_application
0
- client.write(app.pid, app.listen_socket_name)
0
+ client.write(app.pid, app.listen_socket_name, app.using_abstract_namespace?)
0
       client.send_io(app.owner_pipe)
0
       app.close
0
     end
...
 
1
2
3
...
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
 
 
 
35
36
37
...
40
41
42
 
 
 
 
 
 
 
43
44
45
...
72
73
74
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
76
77
...
1
2
3
4
...
21
22
23
 
 
 
 
 
 
 
 
 
 
 
 
24
25
26
27
28
29
...
32
33
34
35
36
37
38
39
40
41
42
43
44
...
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
0
@@ -1,3 +1,4 @@
0
+require 'socket'
0
 require 'mod_rails/message_channel'
0
 require 'mod_rails/cgi_fixed'
0
 require 'mod_rails/utils'
0
@@ -20,18 +21,9 @@ class RequestHandler
0
   attr_reader :socket_name
0
 
0
   def initialize(owner_pipe)
0
- # This Unix socket is in the abstract namespace.
0
- done = false
0
- while !done
0
- begin
0
- @socket_name = "/tmp/passenger.#{generate_random_id}"
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
- done = true
0
- rescue Errno::EADDRINUSE
0
- done = false
0
- end
0
+ @using_abstract_namespace = create_unix_socket_on_abstract_namespace
0
+ if !@using_abstract_namespace
0
+ create_unix_socket_on_filesystem
0
     end
0
     @owner_pipe = owner_pipe
0
     @previous_signal_handlers = {}
0
@@ -40,6 +32,13 @@ class RequestHandler
0
   def cleanup
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
+ def using_abstract_namespace?
0
+ return @using_abstract_namespace
0
   end
0
   
0
   def main_loop
0
@@ -72,6 +71,37 @@ class RequestHandler
0
   end
0
 
0
 private
0
+ def create_unix_socket_on_abstract_namespace
0
+ while true
0
+ begin
0
+ @socket_name = generate_random_id
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
+ 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
+ begin
0
+ @socket_name = "/tmp/#{generate_random_id}"
0
+ @socket_name = @socket_name.slice(0, NativeSupport::UNIX_PATH_MAX - 1)
0
+ @socket = UNIXServer.new(@socket_name)
0
+ done = true
0
+ rescue Errno::EADDRINUSE
0
+ # Do nothing, try again with another name.
0
+ end
0
+ end
0
+ end
0
+
0
   def reset_signal_handlers
0
     Signal.list.each_key do |signal|
0
       begin
...
75
76
77
78
 
79
80
81
...
75
76
77
 
78
79
80
81
0
@@ -75,7 +75,7 @@ private
0
   def handle_spawn_application(app_root, lower_privilege, lowest_user)
0
     lower_privilege = lower_privilege == "true"
0
     app = spawn_application(app_root, lower_privilege, lowest_user)
0
- client.write(app.pid, app.listen_socket_name)
0
+ client.write(app.pid, app.listen_socket_name, app.using_abstract_namespace?)
0
     client.send_io(app.owner_pipe)
0
     app.close
0
   end
...
5
6
7
8
 
9
10
11
...
5
6
7
 
8
9
10
11
0
@@ -5,7 +5,7 @@ require 'mod_rails/spawn_manager'
0
 include ModRails
0
 class SpawnManager
0
   def handle_spawn_application(app_root, user, group)
0
- client.write(1234, "/tmp/nonexistant.socket")
0
+ client.write(1234, "/tmp/nonexistant.socket", false)
0
     client.send_io(STDERR)
0
   end
0
 end

Comments

    No one has commented yet.