Skip to content

Commit

Permalink
Broken attempt to add recbuf support
Browse files Browse the repository at this point in the history
make test fails.   Perhaps due to issue with Opts being passed into call_loop ... do other things need to change because of this?
  • Loading branch information
martinsumner committed Feb 8, 2019
1 parent 4d38821 commit 449796f
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 36 deletions.
38 changes: 18 additions & 20 deletions src/mochiweb_acceptor.erl
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,26 @@

-include("internal.hrl").

-export([start_link/3, init/3]).
-export([start_link/3, start_link/4, init/4]).

-define(EMFILE_SLEEP_MSEC, 100).

start_link(Server, Listen, Loop) ->
proc_lib:spawn_link(?MODULE, init, [Server, Listen, Loop]).
start_link(Server, Listen, Loop, []).

start_link(Server, Listen, Loop, Opts) ->
proc_lib:spawn_link(?MODULE, init, [Server, Listen, Loop, Opts]).

init(Server, Listen, Loop) ->
init(Server, Listen, Loop, Opts) ->
T1 = os:timestamp(),
case catch mochiweb_socket:accept(Listen) of
{ok, Socket} ->
gen_server:cast(Server, {accepted, self(), timer:now_diff(os:timestamp(), T1)}),
call_loop(Loop, Socket);
call_loop(Loop, Socket, Opts);
{error, closed} ->
exit(normal);
{error, timeout} ->
init(Server, Listen, Loop);
init(Server, Listen, Loop, Opts);
{error, esslaccept} ->
exit(normal);
Other ->
Expand All @@ -33,18 +38,11 @@ init(Server, Listen, Loop) ->
exit({error, accept_failed})
end.

call_loop({M, F}, Socket) ->
M:F(Socket);
call_loop({M, F, [A1]}, Socket) ->
M:F(Socket, A1);
call_loop({M, F, A}, Socket) ->
erlang:apply(M, F, [Socket | A]);
call_loop(Loop, Socket) ->
Loop(Socket).

%%
%% Tests
%%
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.
call_loop({M, F}, Socket, Opts) ->
M:F(Socket, Opts);
call_loop({M, F, [A1]}, Socket, Opts) ->
M:F(Socket, Opts, A1);
call_loop({M, F, A}, Socket, Opts) ->
erlang:apply(M, F, [Socket, Opts | A]);
call_loop(Loop, Socket, Opts) ->
Loop(Socket, Opts).
46 changes: 30 additions & 16 deletions src/mochiweb_socket_server.erl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
ip=any,
listen=null,
nodelay=false,
recbuf=?RECBUF_SIZE,
backlog=128,
active_sockets=0,
acceptor_pool_size=16,
Expand Down Expand Up @@ -116,6 +117,17 @@ parse_options([{backlog, Backlog} | Rest], State) ->
parse_options(Rest, State#mochiweb_socket_server{backlog=Backlog});
parse_options([{nodelay, NoDelay} | Rest], State) ->
parse_options(Rest, State#mochiweb_socket_server{nodelay=NoDelay});
parse_options([{recbuf, RecBuf} | Rest], State) when is_integer(RecBuf) ->
%% XXX: `recbuf' value which is passed to `gen_tcp'
%% and value reported by `inet:getopts(P, [recbuf])' may
%% differ. They depends on underlying OS. From linux mans:
%%
%% The kernel doubles this value (to allow space for
%% bookkeeping overhead) when it is set using setsockopt(2),
%% and this doubled value is returned by getsockopt(2).
%%
%% See: man 7 socket | grep SO_RCVBUF
parse_options(Rest, State#mochiweb_socket_server{recbuf=RecBuf});
parse_options([{acceptor_pool_size, Max} | Rest], State) ->
MaxInt = ensure_int(Max),
parse_options(Rest,
Expand Down Expand Up @@ -162,13 +174,15 @@ ipv6_supported() ->
false
end.

init(State=#mochiweb_socket_server{ip=Ip, port=Port, backlog=Backlog, nodelay=NoDelay}) ->
init(State=#mochiweb_socket_server{ip=Ip, port=Port,
backlog=Backlog, nodelay=NoDelay,
recbuf=RecBuf}) ->
process_flag(trap_exit, true),
BaseOpts = [binary,
{reuseaddr, true},
{packet, 0},
{backlog, Backlog},
{recbuf, ?RECBUF_SIZE},
{recbuf, RecBuf},
{exit_on_close, false},
{active, false},
{nodelay, NoDelay}],
Expand All @@ -185,25 +199,25 @@ init(State=#mochiweb_socket_server{ip=Ip, port=Port, backlog=Backlog, nodelay=No
end,
listen(Port, Opts, State).

new_acceptor_pool(Listen,
State=#mochiweb_socket_server{acceptor_pool=Pool,
acceptor_pool_size=Size,
loop=Loop}) ->
F = fun (_, S) ->
Pid = mochiweb_acceptor:start_link(self(), Listen, Loop),
sets:add_element(Pid, S)
end,
Pool1 = lists:foldl(F, Pool, lists:seq(1, Size)),
State#mochiweb_socket_server{acceptor_pool=Pool1}.
new_acceptor_pool(State=#mochiweb_socket_server{acceptor_pool_size=Size}) ->
lists:foldl(fun (_, S) -> new_acceptor(S) end, State, lists:seq(1, Size)).

new_acceptor(State=#mochiweb_socket_server{acceptor_pool=Pool,
recbuf=RecBuf,
loop=Loop,
listen=Listen}) ->
LoopOpts = [{recbuf, RecBuf}],
Pid = mochiweb_acceptor:start_link(self(), Listen, Loop, LoopOpts),
State#mochiweb_socket_server{
acceptor_pool=sets:add_element(Pid, Pool)}.

listen(Port, Opts, State=#mochiweb_socket_server{ssl=Ssl, ssl_opts=SslOpts}) ->
case mochiweb_socket:listen(Ssl, Port, Opts, SslOpts) of
{ok, Listen} ->
{ok, ListenPort} = mochiweb_socket:port(Listen),
{ok, new_acceptor_pool(
Listen,
State#mochiweb_socket_server{listen=Listen,
port=ListenPort})};
{ok, new_acceptor_pool(State#mochiweb_socket_server{
listen=Listen,
port=ListenPort})};
{error, Reason} ->
{stop, Reason}
end.
Expand Down

0 comments on commit 449796f

Please sign in to comment.