summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Nordberg <linus@sunet.se>2019-06-24 16:04:53 +0200
committerLinus Nordberg <linus@sunet.se>2019-06-24 16:04:53 +0200
commit5ce12907073082be03c25707e2d6fc0703db9f1f (patch)
treef4990c0d09688d06b68fb947c1e9148b38ae1735
parent6e90bceab4a3a6e4b9d4496b810324867d533ce1 (diff)
start one sock_server per token; give servers a chance to clean up
still not rm'ing the socket file though. wonder where that should happen.
-rw-r--r--p11p-daemon/src/p11p_server.erl62
-rw-r--r--p11p-daemon/src/p11p_server_sup.erl32
2 files changed, 63 insertions, 31 deletions
diff --git a/p11p-daemon/src/p11p_server.erl b/p11p-daemon/src/p11p_server.erl
index 726e97b..c2422dc 100644
--- a/p11p-daemon/src/p11p_server.erl
+++ b/p11p-daemon/src/p11p_server.erl
@@ -1,7 +1,5 @@
%% Create an AF_UNIX socket and accept connections. On connect, spawn
-%% a p11p_server process.
-
-%% FIXME: Run _one_ socket per instance of this server!
+%% another p11p_server process.
-module(p11p_server).
-behaviour(gen_server).
@@ -15,41 +13,69 @@
%% Records and types.
-include("p11p_defs.hrl").
--record(state, {socket :: gen_tcp:socket()}).
+-record(state, {
+ sockpath :: string(), % FIXME: filename(3erl)
+ socket :: gen_tcp:socket()
+ }).
%% API.
-spec start_link(gen_tcp:socket()) -> {ok, pid()} | {error, term()}.
-start_link(Socket) ->
- gen_server:start_link(?MODULE, Socket, []).
+start_link(Args) ->
+ lager:debug("~p: p11p_server:start_link enter", [self()]),
+ gen_server:start_link(?MODULE, Args, []).
%% Genserver callbacks.
-init(Socket) ->
+init([SocketPath, Socket]) ->
+ lager:debug("~p: p11p_server:init: ~s", [self(), SocketPath]),
+ process_flag(trap_exit, true), % We want terminate().
gen_server:cast(self(), accept), % Perform accept in gen-server loop.
- {ok, #state{socket = Socket}}.
+ {ok, #state{sockpath = SocketPath, socket = Socket}}.
handle_call(Request, _From, State) ->
lager:debug("Unhandled call: ~p~n", [Request]),
{reply, unhandled, State}.
-handle_cast(accept, State = #state{socket = ListenSocket}) ->
- {ok, Sock} = gen_tcp:accept(ListenSocket),
- %% TODO: authz
- lager:debug("new connection accepted: ~p", [Sock]),
- p11p_server_sup:start_server(), % New acceptor.
- {noreply, State#state{socket = Sock}};
+handle_cast(accept, State = #state{sockpath = SocketPath, socket = ListenSocket}) ->
+ %% Blocking until client connects or timeout fires. Without a
+ %% timeout our supervisor cannot terminate us.
+ case gen_tcp:accept(ListenSocket, 900) of
+ {ok, Sock} ->
+ %% TODO: authz
+ lager:debug("~p: ~p: new connection accepted", [self(), Sock]),
+ p11p_server_sup:start_server([SocketPath, ListenSocket]), % Start a new acceptor.
+ {noreply, State#state{socket = Sock}}; % Use the new socket.
+ {error, timeout} ->
+ gen_server:cast(self(), accept), % Try again.
+ {noreply, State};
+ {error, closed} ->
+ lager:debug("~p: listening socket closed", [self()]),
+ {stop, normal, State}
+ end;
handle_cast(Request, State) ->
lager:debug("Unhandled cast: ~p~n", [Request]),
{noreply, State}.
-handle_info({tcp, _Socket, Data}, State) ->
+handle_info({tcp, Port, Data}, State) ->
lager:debug("~p: received: ~s", [self(), Data]),
- {noreply, State};
+ case Data of
+ <<"q\n">> ->
+ gen_tcp:send(Port, "ok, bye\n"), %DEBUG
+ {stop, {shutdown, quit_by_client}, State};
+ _ ->
+ gen_tcp:send(Port, "ok, thanks: " ++ Data), %DEBUG
+ {noreply, State}
+ end;
+handle_info({tcp_closed, Port}, State) ->
+ lager:debug("~p: ~p: closed", [self(), Port]),
+ {stop, {shutdown, close_by_client}, State};
handle_info(Info, State) ->
lager:debug("Unhandled info: ~p~n", [Info]),
{noreply, State}.
-terminate(_Reason, #state{socket = Socket}) ->
- gen_tcp:close(Socket), % FIXME: correct?
+terminate(_Reason, #state{sockpath = _SocketPath, socket = Socket}) ->
+ lager:debug("~p: ~p: terminated", [self(), Socket]),
+ gen_tcp:close(Socket),
+ %%FIXME: clean up socket file where? file:delete(SocketPath),
ok.
code_change(_OldVersion, State, _Extra) ->
diff --git a/p11p-daemon/src/p11p_server_sup.erl b/p11p-daemon/src/p11p_server_sup.erl
index 924123b..18f1247 100644
--- a/p11p-daemon/src/p11p_server_sup.erl
+++ b/p11p-daemon/src/p11p_server_sup.erl
@@ -1,28 +1,34 @@
-module(p11p_server_sup).
-behaviour(supervisor).
--export([start_link/0, start_server/0]).
+-export([start_link/0, start_server/1]).
-export([init/1]).
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([]) ->
- Name = "vtoken0", % FIXME
- SocketPath = socket_path(mkdir_socket_basepath(), Name),
- file:delete(SocketPath),
- % TODO: consider flow control through {active, once}
- {ok, ListenSocket} = gen_tcp:listen(0, [{ifaddr, {local, SocketPath}},
- binary]),
- spawn_link(fun start_server/0),
- {ok, {{simple_one_for_one, 60, 3600},
- [{sock_server,
- {p11p_server, start_link, [ListenSocket]},
+ Names = ["vtoken0", "vtoken1"], % FIXME: get from config
+ ok = start_servers(Names),
+ {ok, {{simple_one_for_one, 1, 5},
+ [{sock_server, % Ignored childspec id.
+ {p11p_server, start_link, []},
temporary, 1000, worker, [p11p_server]}
]}}.
-start_server() ->
- supervisor:start_child(?MODULE, []).
+start_servers([]) ->
+ ok;
+start_servers([Name|T]) ->
+ Path = socket_path(mkdir_socket_basepath(), Name),
+ file:delete(Path),
+ % TODO: consider flow control through {active, once}, don't forget activating after read!
+ {ok, Socket} = gen_tcp:listen(0, [{ifaddr, {local, Path}}, binary]),
+ spawn_link(?MODULE, start_server, [[Path, Socket]]),
+ start_servers(T).
+
+start_server(Args) ->
+ {ok, Pid} = supervisor:start_child(?MODULE, [Args]),
+ Pid.
%% Private functions.
mkdir_socket_basepath() ->