ry / ebb fork watch download tarball
public this repo is viewable by everyone
Description: web server
Homepage: http://ebb.rubyforge.org
Clone URL: git://github.com/ry/ebb.git
ruby binding clean-up

1. Because you will never need to run two servers per RubyVM, I have 
removed
the Ebb::Server class. It is replaced with Ebb.start_server. This has 
allowed
me to simplify ebb_ruby.c much.

2. Two allow for ebb_merb or other executables I've moved the option 
parsing
into Ebb::Runner. Check out bin/ebb_rails to see the cute API (if i do say 
so
myself) for adding options to the runner.

3. I've done away with the Daemonizable include and moved the logic into 
the
the new Runner class.
Ryan Dahl (author)
2 months ago
commit  c023fa46c39157b09728f57fa5014d71bfcb935f
tree    2d95b7e535a3a582df6cc4b67e46d87ef0f06b36
parent  b938ce438686fab63851b0d2b5752ab066b4f305
...
1
 
...
 
1
0
@@ -1 +1 @@
0
-0.0.4
0
+0.0.5
...
78
79
80
81
82
83
 
84
85
...
78
79
80
 
81
 
82
83
84
0
@@ -78,7 +78,6 @@ if $0 == __FILE__
0
   require 'ruby-debug'
0
   Debugger.start
0
   
0
- server = Ebb::Server.new(SimpleApp.new, :port => 4001)
0
   puts "Ebb started on http://0.0.0.0:4001/"
0
- server.start
0
+ server = Ebb::start_server(SimpleApp.new, :port => 4001)
0
 end
0
\ No newline at end of file
...
114
115
116
117
 
118
119
120
...
114
115
116
 
117
118
119
120
0
@@ -114,7 +114,7 @@ class ServerTest
0
   
0
   def start_ebb
0
     require File.dirname(__FILE__) + '/../ruby_lib/ebb'
0
- server = Ebb::Server.run(app, :port => @port)
0
+ server = Ebb::start_server(app, :port => @port)
0
   end
0
   
0
   def start_mongrel
...
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 
 
 
 
 
 
 
 
 
 
 
 
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
 
 
 
 
80
...
10
11
12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
14
15
16
17
18
19
20
21
22
23
24
25
 
 
 
 
 
 
 
 
 
 
26
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
28
29
30
31
0
@@ -10,70 +10,21 @@ module Rack
0
   end
0
 end
0
 
0
-options = {
0
- :root => Dir.pwd,
0
- :environment => 'development',
0
- :hort => '0.0.0.0',
0
- :port => 3000,
0
- :timeout => 60
0
-}
0
-
0
-
0
-opts = OptionParser.new do |opts|
0
- opts.banner = "Usage: ebb_rails [options] start|stop"
0
-
0
- opts.separator ""
0
- opts.separator "Server options:"
0
-
0
-# opts.on("-s", "--socket SOCKET", "listen on socket") { |socket| options[:socket] = socket }
0
- opts.on("-p", "--port PORT", "use PORT (default: 3000)") { |port| options[:port] = port }
0
- opts.on("-e", "--env ENV", "Rails environment (default: development)") { |env| options[:environment] = env }
0
- opts.on("-c", "--chdir PATH", "Rails root dir (default: current dir)") { |dir| options[:root] = dir }
0
- opts.on("-d", "--daemonize", "Daemonize") { options[:daemonize] = true }
0
- opts.on("-l", "--log-file FILE", "File to redirect output") { |file| options[:log_file] = file }
0
- opts.on("-P", "--pid-file FILE", "File to store PID") { |file| options[:pid_file] = file }
0
- opts.on("-t", "--timeout SEC", "Request or command timeout in sec",
0
- "(default: #{options[:timeout]})") { |sec| options[:timeout] = sec }
0
-
0
- opts.separator ""
0
- opts.separator "Common options:"
0
-
0
- opts.on_tail("-h", "--help", "Show this message") do
0
- puts opts
0
- exit
0
+Ebb::Runner.new('ebb_rails') do
0
+ def add_extra_options(parser, options)
0
+ # defaults for ebb_rails
0
+ options.update(
0
+ :environment => 'development',
0
+ :port => 3000
0
+ )
0
+
0
+ parser.on("-e", "--env ENV",
0
+ "Rails environment (default: development)") do |env|
0
+ options[:environment] = env
0
+ end
0
   end
0
-
0
- opts.on_tail('-v', '--version', "Show version") do
0
- puts "Ebb #{Ebb::VERSION}"
0
- exit
0
- end
0
-
0
- opts.parse! ARGV
0
-end
0
-
0
-case ARGV[0]
0
   
0
-when 'start'
0
- app = Rack::Adapter::Rails.new(options)
0
- server = Ebb::Server.new(app, options)
0
-
0
- server.pid_file = options[:pid_file]
0
- server.log_file = options[:log_file]
0
- server.timeout = options[:timeout]
0
-
0
- server.daemonize if options[:daemonize]
0
-
0
- server.start
0
-
0
-when 'stop'
0
- Ebb::Server.kill options[:pid_file], options[:timeout]
0
-
0
-when nil
0
- puts "Command required"
0
- puts opts
0
- exit 1
0
-
0
-else
0
- abort "Invalid command : #{ARGV[0]}"
0
-
0
-end
0
+ def app(options)
0
+ Rack::Adapter::Rails.new(options)
0
+ end
0
+end
0
\ No newline at end of file
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
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
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0
@@ -1,98 +0,0 @@
0
-# Simplified version of Thin::Daemonizable by Marc-André Cournoyer
0
-
0
-module Kernel
0
- unless respond_to? :daemonize # Already part of Ruby 1.9, yeah!
0
- # Turns the current script into a daemon process that detaches from the console.
0
- # It can be shut down with a TERM signal. Taken from ActiveSupport.
0
- def daemonize
0
- exit if fork # Parent exits, child continues.
0
- Process.setsid # Become session leader.
0
- exit if fork # Zap session leader. See [1].
0
- Dir.chdir "/" # Release old working directory.
0
- File.umask 0000 # Ensure sensible umask. Adjust as needed.
0
- STDIN.reopen "/dev/null" # Free file descriptors and
0
- STDOUT.reopen "/dev/null", "a" # point them somewhere sensible.
0
- STDERR.reopen STDOUT # STDOUT/ERR should better go to a logfile.
0
- trap("TERM") { exit }
0
- end
0
- end
0
-end
0
-
0
-module Process
0
- # Returns +true+ the process identied by +pid+ is running.
0
- def running?(pid)
0
- Process.getpgid(pid) != -1
0
- rescue Errno::ESRCH
0
- false
0
- end
0
- module_function :running?
0
-end
0
-
0
-# Moadule included in classes that can be turned into a daemon.
0
-# Handle stuff like:
0
-# * storing the PID in a file
0
-# * redirecting output to the log file
0
-# * killing the process gracefully
0
-module Daemonizable
0
- attr_accessor :pid_file, :log_file, :timeout
0
-
0
- def self.included(base)
0
- base.extend(ClassMethods)
0
- end
0
-
0
- def pid
0
- File.exist?(pid_file) ? open(pid_file).read : nil
0
- end
0
-
0
- # Turns the current script into a daemon process that detaches from the console.
0
- def daemonize
0
- raise ArgumentError, 'You must specify a pid_file to deamonize' unless @pid_file
0
-
0
- pwd = Dir.pwd # Current directory is changed during daemonization, so store it
0
- Kernel.daemonize
0
- Dir.chdir pwd
0
-
0
- trap('HUP', 'IGNORE') # Don't die upon logout
0
-
0
- # Redirect output to the logfile
0
- [STDOUT, STDERR].each { |f| f.reopen @log_file, 'a' } if @log_file
0
-
0
- write_pid_file
0
- at_exit do
0
- log ">> Exiting!"
0
- remove_pid_file
0
- end
0
- end
0
-
0
- module ClassMethods
0
- # Kill the process which PID is stored in +pid_file+.
0
- def kill(pid_file, timeout=60)
0
- raise ArgumentError, 'You must specify a pid_file to stop deamonized server' unless pid_file
0
-
0
- if pid = File.read(pid_file)
0
- pid = pid.to_i
0
-
0
- Process.kill('KILL', pid)
0
- puts "stopped!"
0
- else
0
- puts "Can't stop process, no PID found in #{@pid_file}"
0
- end
0
- rescue Errno::ESRCH # No such process
0
- puts "process not found!"
0
- ensure
0
- File.delete(pid_file) rescue nil
0
- end
0
- end
0
-
0
- private
0
-
0
- def remove_pid_file
0
- File.delete(@pid_file) if @pid_file && File.exists?(@pid_file) && Process.pid == File.read(@pid_file)
0
- end
0
-
0
- def write_pid_file
0
- log ">> Writing PID to #{@pid_file}"
0
- open(@pid_file,"w+") { |f| f.write(Process.pid) }
0
- File.chmod(0644, @pid_file)
0
- end
0
-end
...
4
5
6
 
7
8
9
10
11
12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
14
15
...
66
67
68
69
70
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
...
4
5
6
7
8
9
10
 
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
...
132
133
134
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
136
137
0
@@ -4,12 +4,78 @@
0
 module Ebb
0
   LIBDIR = File.dirname(__FILE__)
0
   VERSION = File.read(LIBDIR + "/../VERSION").gsub(/\s/,'')
0
+ autoload :Runner, LIBDIR + '/ebb/runner'
0
 end
0
 
0
 require Ebb::LIBDIR + '/../src/ebb_ext'
0
-require Ebb::LIBDIR + '/daemonizable'
0
 
0
 module Ebb
0
+ # "Gasp! No Server class! But this is Object Oriented Programming - we
0
+ # classes for servers!", you say. Not when there always will be
0
+ # exactly one server per virtual machine.
0
+ def self.start_server(app, options={})
0
+ port = (options[:port] || 4001).to_i
0
+ #socket = options[:socket]
0
+ timeout = options[:timeout]
0
+
0
+ trap('INT') { @running = false }
0
+
0
+ FFI::server_listen_on_port(port)
0
+
0
+ puts "Ebb listening at http://0.0.0.0:#{port}/"
0
+
0
+ @running = true
0
+ while FFI::server_process_connections() and @running
0
+ unless FFI::waiting_clients.empty?
0
+ if $DEBUG and $ebb_waiting_clients.length > 1
0
+ puts "#{FFI::waiting_clients.length} waiting clients"
0
+ end
0
+ client = FFI::waiting_clients.shift
0
+ process_client(app, client)
0
+ end
0
+ end
0
+ puts "Ebb unlistening"
0
+ FFI::server_unlisten()
0
+ end
0
+
0
+ def self.process_client(app, client)
0
+ #puts "Request: #{client.env.inspect}\n"
0
+ begin
0
+ status, headers, body = app.call(client.env)
0
+ rescue
0
+ raise if $DEBUG
0
+ status = 500
0
+ headers = {'Content-Type' => 'text/plain'}
0
+ body = "Internal Server Error\n"
0
+ end
0
+
0
+ client.write_status(status)
0
+
0
+ if body.respond_to? :length and status != 304
0
+ headers['Connection'] = 'close'
0
+ headers['Content-Length'] = body.length
0
+ end
0
+
0
+ headers.each { |k, v| client.write_header(k,v) }
0
+
0
+ client.write "\r\n"
0
+
0
+ # Not many apps use streaming yet so i'll hold off on that feature
0
+ # until the rest of ebb is more developed.
0
+ if body.kind_of?(String)
0
+ client.write body
0
+ else
0
+ body.each { |p| client.write p }
0
+ end
0
+ client.finished
0
+ end
0
+
0
+ module FFI
0
+ def self.waiting_clients
0
+ @waiting_clients
0
+ end
0
+ end
0
+
0
   class Client
0
     BASE_ENV = {
0
       'SCRIPT_NAME' => '',
0
@@ -66,86 +132,6 @@ module Ebb
0
     end
0
   end
0
   
0
- class Server
0
- include Daemonizable
0
- def self.run(app, options={})
0
- # port must be an integer
0
- server = self.new(app, options)
0
- yield server if block_given?
0
- server.start
0
- end
0
-
0
- def initialize(app, options={})
0
- @socket = options[:socket]
0
- @port = (options[:port] || 4001).to_i
0
- @timeout = options[:timeout]
0
- @app = app
0
- end
0
-
0
- def start
0
- trap('INT') { @running = false }
0
-
0
- if @socket
0
- raise NotImplemented
0
- FFI::server_listen_on_socket(self, @socket) or raise "Problem listening on socket #{@socket}"
0
- else
0
- FFI::server_listen_on_port(self, @port) or raise "Problem listening on port #{@port}"
0
- end
0
- @waiting_clients = []
0
-
0
- puts "Ebb listening at http://0.0.0.0:#{@port}/"
0
-
0
- @running = true
0
- while FFI::server_process_connections(self) and @running
0
- unless @waiting_clients.empty?
0
- if $DEBUG and @waiting_clients.length > 1
0
- puts "#{@waiting_clients.length} waiting clients"
0
- end
0
- client = @waiting_clients.shift
0
- process_client(client)
0
- end
0
- end
0
- puts "Ebb unlistening"
0
- FFI::server_unlisten(self)
0
- end
0
-
0
- def process_client(client)
0
- #puts "Request: #{client.env.inspect}\n"
0
- begin
0
- status, headers, body = @app.call(client.env)
0
- rescue
0
- raise if $DEBUG
0
- status = 500
0
- headers = {'Content-Type' => 'text/plain'}
0
- body = "Internal Server Error\n"
0
- end
0
-
0
- client.write_status(status)
0
-
0
- if body.respond_to? :length and status != 304
0
- headers['Connection'] = 'close'
0
- headers['Content-Length'] = body.length
0
- end
0
-
0
- headers.each { |k, v| client.write_header(k,v) }
0
-
0
- client.write "\r\n"
0
-
0
- # Not many apps use streaming yet so i'll hold off on that feature
0
- # until the rest of ebb is more developed.
0
- if body.kind_of?(String)
0
- client.write body
0
- else
0
- body.each { |p| client.write p }
0
- end
0
- client.finished
0
- end
0
-
0
- def log(msg)
0
- puts msg
0
- end
0
- end
0
-
0
   HTTP_STATUS_CODES = {
0
     100 => 'Continue',
0
     101 => 'Switching Protocols',
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
0
@@ -0,0 +1,140 @@
0
+require 'optparse'
0
+
0
+module Kernel
0
+ unless respond_to? :daemonize # Already part of Ruby 1.9, yeah!
0
+ # Turns the current script into a daemon process that detaches from the console.
0
+ # It can be shut down with a TERM signal. Taken from ActiveSupport.
0
+ def daemonize
0
+ exit if fork # Parent exits, child continues.
0
+ Process.setsid # Become session leader.
0
+ exit if fork # Zap session leader. See [1].
0
+ Dir.chdir "/" # Release old working directory.
0
+ File.umask 0000 # Ensure sensible umask. Adjust as needed.
0
+ STDIN.reopen "/dev/null" # Free file descriptors and
0
+ STDOUT.reopen "/dev/null", "a" # point them somewhere sensible.
0
+ STDERR.reopen STDOUT # STDOUT/ERR should better go to a logfile.
0
+ trap("TERM") { exit }
0
+ end
0
+ end
0
+end
0
+
0
+module Ebb
0
+ class Runner
0
+ DEFAULT_OPTIONS = {
0
+ :port => 4001,
0
+ :timeout => 60
0
+ }
0
+
0
+ # Kill the process which PID is stored in +pid_file+.
0
+ def self.kill(pid_file, timeout=60)
0
+ raise ArgumentError, 'You must specify a pid_file to stop deamonized server' unless pid_file
0
+
0
+ if pid = File.read(pid_file)
0
+ pid = pid.to_i
0
+
0
+ Process.kill('KILL', pid)
0
+ puts "stopped!"
0
+ else
0
+ puts "Can't stop process, no PID found in #{@pid_file}"
0
+ end
0
+ rescue Errno::ESRCH # No such process
0
+ puts "process not found!"
0
+ ensure
0
+ File.delete(pid_file) rescue nil
0
+ end
0
+
0
+ def self.remove_pid_file(file)
0
+ File.delete(file) if file && File.exists?(file) && Process.pid == File.read(file)
0
+ end
0
+
0
+ def self.write_pid_file(file)
0
+ puts ">> Writing PID to #{file}"
0
+ open(file,"w+") { |f| f.write(Process.pid) }
0
+ File.chmod(0644, file)
0
+ end
0
+
0
+ def initialize(name, &definitions)
0
+ @name = name
0
+ instance_eval(&definitions)
0
+ run
0
+ end
0
+
0
+ def run
0
+ option_parser, options = get_options_from_command_line
0
+
0
+
0
+ case ARGV[0]
0
+ when 'start'
0
+ STDOUT.print("Ebb is loading the application...")
0
+ STDOUT.flush()
0
+ @app = app(options)
0
+ STDOUT.puts("loaded")
0
+
0
+ if options[:daemonize]
0
+ pwd = Dir.pwd # Current directory is changed during daemonization, so store it
0
+ Kernel.daemonize
0
+ Dir.chdir pwd
0
+ trap('HUP', 'IGNORE') # Don't die upon logout
0
+ end
0
+
0
+ if options[:log_file]
0
+ [STDOUT, STDERR].each { |f| f.reopen log_file, 'a' }
0
+ end
0
+
0
+ if options[:pid_file]
0
+ Runner.write_pid_file(options[:pid_file])
0
+ at_exit do
0
+ puts ">> Exiting!"
0
+ Runner.remove_pid_file(options[:pid_file])
0
+ end
0
+ end
0
+
0
+ Ebb::start_server(@app, options)
0
+ when 'stop'
0
+ Ebb::Runner.kill options[:pid_file], options[:timeout]
0
+ when nil
0
+ puts "Command required"
0
+ puts option_parser
0
+ exit 1
0
+ else
0
+ abort "Invalid command : #{ARGV[0]}"
0
+ end
0
+ end
0
+
0
+
0
+ def get_options_from_command_line
0
+ options = DEFAULT_OPTIONS.dup
0
+ option_parser = OptionParser.new do |parser|
0
+ parser.banner = "Usage: #{@name} [options] start | stop"
0
+
0
+ parser.separator ""
0
+
0
+ if respond_to?(:add_extra_options)
0
+ add_extra_options(parser, options)
0
+ end
0
+
0
+ parser.separator ""
0
+
0
+ # opts.on("-s", "--socket SOCKET", "listen on socket") { |socket| options[:socket] = socket }
0
+ parser.on("-p", "--port PORT", "(default: #{options[:port]})") { |options[:port]| }
0
+ parser.on("-d", "--daemonize", "Daemonize") { options[:daemonize] = true }
0
+ parser.on("-l", "--log-file FILE", "File to redirect output") { |options[:port]| }
0
+ parser.on("-P", "--pid-file FILE", "File to store PID") { |options[:pid_file]| }
0
+ parser.on("-t", "--timeout SECONDS", "(default: #{options[:timeout]})") { |options[:timeout]| }
0
+
0
+ parser.on_tail("-h", "--help", "Show this message") do
0
+ puts parser
0
+ exit
0
+ end
0
+
0
+ parser.on_tail('-v', '--version', "Show version") do
0
+ puts "Ebb #{Ebb::VERSION}"
0
+ exit
0
+ end
0
+ end
0
+ option_parser.parse!(ARGV)
0
+ [option_parser, options]
0
+ end
0
+ end
0
+
0
+end
...
446
447
448
449
450
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
451
452
453
454
455
 
 
 
 
456
457
458
...
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
...
446
447
448
 
 
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
 
492
 
493
494
495
496
497
498
499
...
650
651
652
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
653
654
655
0
@@ -446,13 +446,54 @@ void ebb_server_listen(ebb_server *server)
0
 
0
 int ebb_server_listen_on_port(ebb_server *server, const int port)
0
 {
0
- int fd = server_socket(port);
0
- if(fd < 0) return 0;
0
+ int sfd = -1;
0
+ struct linger ling = {0, 0};
0
+ struct sockaddr_in addr;
0
+ int flags = 1;
0
+
0
+ if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
0
+ perror("socket()");
0
+ goto error;
0
+ }
0
+
0
+ flags = fcntl(sfd, F_GETFL, 0);
0
+ if(fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0) {
0
+ perror("setting O_NONBLOCK");
0
+ goto error;
0
+ }
0
+
0
+ flags = 1;
0
+ setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags));
0
+ setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags));
0
+ setsockopt(sfd, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(ling));
0
+ setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags));
0
+
0
+ /*
0
+ * the memset call clears nonstandard fields in some impementations
0
+ * that otherwise mess things up.
0
+ */
0
+ memset(&addr, 0, sizeof(addr));
0
+
0
+ addr.sin_family = AF_INET;
0
+ addr.sin_port = htons(port);
0
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
0
+
0
+ if (bind(sfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
0
+ perror("bind()");
0
+ goto error;
0
+ }
0
+ if (listen(sfd, EBB_MAX_CLIENTS) < 0) {
0
+ perror("listen()");
0
+ goto error;
0
+ }
0
+ server->fd = sfd;
0
   server->port = malloc(sizeof(char)*8); /* for easy access to the port */
0
   sprintf(server->port, "%d", port);
0
- server->fd = fd;
0
   ebb_server_listen(server);
0
- return fd;
0
+ return server->fd;
0
+error:
0
+ if(sfd > 0) close(sfd);
0
+ return -1;
0
 }
0
 
0
 
0
@@ -609,53 +650,6 @@ int ebb_client_read(ebb_client *client, char *buffer, int length)
0
 
0
 /* The following socket creation routines are modified and stolen from memcached */
0
 
0
-static int server_socket(const int port) {
0
- int sfd;
0
- struct linger ling = {0, 0};
0
- struct sockaddr_in addr;
0
- int flags =1;
0
-
0
- if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
0
- perror("socket()");
0
- return -1;
0
- }
0
-
0
- if ((flags = fcntl(sfd, F_GETFL, 0)) < 0 ||
0
- fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0) {
0
- perror("setting O_NONBLOCK");
0
- close(sfd);
0
- return -1;
0
- }
0
-
0
- flags = 1;
0
- setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags));
0
- setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags));
0
- setsockopt(sfd, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(ling));
0
- setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags));
0
-
0
- /*
0
- * the memset call clears nonstandard fields in some impementations
0
- * that otherwise mess things up.
0
- */
0
- memset(&addr, 0, sizeof(addr));
0
-
0
- addr.sin_family = AF_INET;
0
- addr.sin_port = htons(port);
0
- addr.sin_addr.s_addr = htonl(INADDR_ANY);
0
-
0
- if (bind(sfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
0
- perror("bind()");
0
- close(sfd);
0
- return -1;
0
- }
0
- if (listen(sfd, EBB_MAX_CLIENTS) == -1) {
0
- perror("listen()");
0
- close(sfd);
0
- return -1;
0
- }
0
- return sfd;
0
-}
0
-
0
 
0
 static int server_socket_unix(const char *path, int access_mask) {
0
     int sfd;