Permalink
Browse files

Allow starting the Ebb server on arbitrary FD

This allows Ebb to attach to any listening file descriptor,
e.g. a Unix socket or an open socket passed down from any kind
of supervisor software
  • Loading branch information...
1 parent 8788861 commit 7b306f2dc60be6209b71f31b92db5a27b62e540f @gnosek committed Mar 24, 2008
Showing with 83 additions and 15 deletions.
  1. +6 −2 ruby_lib/ebb.rb
  2. +24 −12 src/ebb.c
  3. +2 −1 src/ebb.h
  4. +8 −0 src/ebb_ruby.c
  5. +29 −0 test/basic_test_fd.rb
  6. +14 −0 test/helper.rb
View
@@ -16,8 +16,12 @@ def self.start_server(app, options={})
end
Client::BASE_ENV['rack.multithread'] = threaded_processing
-
- FFI::server_listen_on_port(port)
+
+ if options.has_key?(:fileno)
+ FFI::server_listen_on_fd(options[:fileno].to_i)
+ else
+ FFI::server_listen_on_port(port)
+ end
@running = true
trap('INT') { stop_server }
View
@@ -475,6 +475,23 @@ void ebb_server_unlisten(ebb_server *server)
}
}
+int ebb_server_listen_on_fd(ebb_server *server, const int sfd)
+{
+ set_nonblock(sfd);
+
+ server->fd = sfd;
+ server->port = NULL;
+ assert(server->open == FALSE);
+ server->open = TRUE;
+
+ server->request_watcher.data = server;
+ ev_init (&server->request_watcher, on_request);
+ ev_io_set (&server->request_watcher, server->fd, EV_READ | EV_ERROR);
+ ev_io_start (server->loop, &server->request_watcher);
+
+ return server->fd;
+}
+
int ebb_server_listen_on_port(ebb_server *server, const int port)
{
int sfd = -1;
@@ -513,18 +530,13 @@ int ebb_server_listen_on_port(ebb_server *server, const int port)
perror("listen()");
goto error;
}
- server->fd = sfd;
- server->port = malloc(sizeof(char)*8); /* for easy access to the port */
- sprintf(server->port, "%d", port);
- assert(server->open == FALSE);
- server->open = TRUE;
-
- server->request_watcher.data = server;
- ev_init (&server->request_watcher, on_request);
- ev_io_set (&server->request_watcher, server->fd, EV_READ | EV_ERROR);
- ev_io_start (server->loop, &server->request_watcher);
-
- return server->fd;
+
+ int ret = ebb_server_listen_on_fd(server, sfd);
+ if (ret >= 0) {
+ server->port = malloc(sizeof(char)*8); /* for easy access to the port */
+ sprintf(server->port, "%d", port);
+ }
+ return ret;
error:
if(sfd > 0) close(sfd);
return -1;
View
@@ -81,6 +81,7 @@ void ebb_server_init( ebb_server *server
, ebb_request_cb request_cb
, void *request_cb_data
);
+int ebb_server_listen_on_fd(ebb_server*, const int sfd);
int ebb_server_listen_on_port(ebb_server*, const int port);
int ebb_server_listen_on_socket(ebb_server*, const char *socketpath);
void ebb_server_unlisten(ebb_server*);
@@ -96,4 +97,4 @@ struct ebb_server {
ebb_request_cb request_cb;
};
-#endif
+#endif
View
@@ -73,6 +73,13 @@ void request_cb(ebb_client *client, void *data)
attach_idle_watcher();
}
+VALUE server_listen_on_fd(VALUE _, VALUE sfd)
+{
+ if(ebb_server_listen_on_fd(server, FIX2INT(sfd)) < 0)
+ rb_sys_fail("Problem listening on FD");
+ return Qnil;
+}
+
VALUE server_listen_on_port(VALUE _, VALUE port)
{
if(ebb_server_listen_on_port(server, FIX2INT(port)) < 0)
@@ -264,6 +271,7 @@ void Init_ebb_ext()
DEF_GLOBAL(http_version, "HTTP_VERSION");
rb_define_singleton_method(mFFI, "server_process_connections", server_process_connections, 0);
+ rb_define_singleton_method(mFFI, "server_listen_on_fd", server_listen_on_fd, 1);
rb_define_singleton_method(mFFI, "server_listen_on_port", server_listen_on_port, 1);
rb_define_singleton_method(mFFI, "server_unlisten", server_unlisten, 0);
rb_define_singleton_method(mFFI, "server_open?", server_open, 0);
View
@@ -0,0 +1,29 @@
+require File.dirname(__FILE__) + '/helper'
+
+class BasicTestFD < ServerTestFD
+ def test_get_bytes
+ [1,10,1000].each do |i|
+ response = get("/bytes/#{i}")
+ assert_equal "#{'C'*i.to_i}", response['output']
+ end
+ end
+
+ def test_get_unknown
+ response = get('/blah')
+ assert_equal "Undefined url", response['output']
+ end
+
+ def test_small_posts
+ [1,10,321,123,1000].each do |i|
+ response = post("/test_post_length", 'C'*i)
+ assert_equal 200, response['status']
+ end
+ end
+
+ def test_large_post
+ [50,60,100].each do |i|
+ response = post("/test_post_length", 'C'*1024*i)
+ assert_equal 200, response['status']
+ end
+ end
+end
View
@@ -84,3 +84,17 @@ def default_test
assert true
end
end
+
+class ServerTestFD < ServerTest
+ def setup
+ @tcp_server = TCPServer.new('0.0.0.0', TEST_PORT);
+ Thread.new { Ebb.start_server(HelperApp.new, :fileno => @tcp_server.fileno) }
+ sleep 0.1 until Ebb.running?
+ end
+
+ def teardown
+ super
+ @tcp_server = nil
+ end
+end
+

0 comments on commit 7b306f2

Please sign in to comment.