feat: allow socket activation

This enables passing in an existing socket e.g. from systemd,[1] instead
of creating a new socket when running the server.

[1] https://github.com/juergenhoetzel/ocaml-systemd
This commit is contained in:
Yawar Amin 2021-09-25 01:41:32 -04:00
parent 9961bd1b29
commit ce61ac2afd
2 changed files with 22 additions and 8 deletions

View file

@ -809,6 +809,8 @@ type t = {
port: int;
sock: Unix.file_descr option;
sem_max_connections: Sem_.t;
(* semaphore to restrict the number of active concurrent connections *)
@ -947,10 +949,10 @@ let create
?(masksigpipe=true)
?(max_connections=32)
?(new_thread=(fun f -> ignore (Thread.create f () : Thread.t)))
?(addr="127.0.0.1") ?(port=8080) () : t =
?(addr="127.0.0.1") ?(port=8080) ?sock () : t =
let handler _req = Response.fail ~code:404 "no top handler" in
let max_connections = max 4 max_connections in
{ new_thread; addr; port; masksigpipe; handler;
{ new_thread; addr; port; sock; masksigpipe; handler;
running= true; sem_max_connections=Sem_.create max_connections;
path_handlers=[];
cb_encode_resp=[]; cb_decode_req=[];
@ -1065,16 +1067,24 @@ let run (self:t) : (unit,_) result =
if self.masksigpipe then (
ignore (Unix.sigprocmask Unix.SIG_BLOCK [Sys.sigpipe] : _ list);
);
let sock =
Unix.socket (if is_ipv6 self then Unix.PF_INET6 else Unix.PF_INET)
Unix.SOCK_STREAM 0
let sock, should_bind = match self.sock with
| Some s ->
s, false (* Because we're getting a socket from systemd *)
| None ->
Unix.socket
(if is_ipv6 self then Unix.PF_INET6 else Unix.PF_INET)
Unix.SOCK_STREAM
0,
true (* Because we're creating the socket ourselves *)
in
Unix.clear_nonblock sock;
Unix.setsockopt sock Unix.SO_REUSEADDR true;
Unix.setsockopt_optint sock Unix.SO_LINGER None;
let inet_addr = Unix.inet_addr_of_string self.addr in
begin if should_bind then
Unix.bind sock (Unix.ADDR_INET (inet_addr, self.port));
Unix.listen sock (2 * self.sem_max_connections.Sem_.n);
Unix.listen sock (2 * self.sem_max_connections.Sem_.n)
end;
while self.running do
(* limit concurrency *)
Sem_.acquire 1 self.sem_max_connections;

View file

@ -437,6 +437,7 @@ val create :
?new_thread:((unit -> unit) -> unit) ->
?addr:string ->
?port:int ->
?sock:Unix.file_descr ->
unit ->
t
(** Create a new webserver.
@ -455,7 +456,10 @@ val create :
@param max_connections maximum number of simultaneous connections.
@param addr address (IPv4 or IPv6) to listen on. Default ["127.0.0.1"].
@param port to listen on. Default [8080].
*)
@param sock an existing socket given to the server to listen on, e.g. by
systemd on Linux (or launchd on macOS). If passed in, this socket will be
used instead of the [addr] and [port]. If not passed in, those will be
used. *)
val addr : t -> string
(** Address on which the server listens. *)