Merge pull request #19 from yawaramin/master

feat: allow socket activation
This commit is contained in:
Simon Cruanes 2021-09-25 15:34:26 -04:00 committed by GitHub
commit 70dcf8269a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 24 additions and 10 deletions

View file

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

View file

@ -437,6 +437,7 @@ val create :
?new_thread:((unit -> unit) -> unit) -> ?new_thread:((unit -> unit) -> unit) ->
?addr:string -> ?addr:string ->
?port:int -> ?port:int ->
?sock:Unix.file_descr ->
unit -> unit ->
t t
(** Create a new webserver. (** Create a new webserver.
@ -455,7 +456,10 @@ val create :
@param max_connections maximum number of simultaneous connections. @param max_connections maximum number of simultaneous connections.
@param addr address (IPv4 or IPv6) to listen on. Default ["127.0.0.1"]. @param addr address (IPv4 or IPv6) to listen on. Default ["127.0.0.1"].
@param port to listen on. Default [8080]. @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 val addr : t -> string
(** Address on which the server listens. *) (** Address on which the server listens. *)