summaryrefslogtreecommitdiff
path: root/p11p-daemon/src/p11p_server.erl
diff options
context:
space:
mode:
Diffstat (limited to 'p11p-daemon/src/p11p_server.erl')
-rw-r--r--p11p-daemon/src/p11p_server.erl81
1 files changed, 57 insertions, 24 deletions
diff --git a/p11p-daemon/src/p11p_server.erl b/p11p-daemon/src/p11p_server.erl
index cbc00df..ef8877d 100644
--- a/p11p-daemon/src/p11p_server.erl
+++ b/p11p-daemon/src/p11p_server.erl
@@ -11,7 +11,7 @@
%% API.
-export([start_link/1]).
--export([reply/2]).
+-export([reply/2, token_gone/2]).
%% Genserver callbacks.
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
@@ -22,10 +22,10 @@
tokname :: string(),
client :: pid() | undefined,
socket :: gen_tcp:socket(),
- msg :: p11rpc_msg() | undefined,
- recv_count = 0 :: non_neg_integer(),
- send_count = 0 :: non_neg_integer()
- %%clientbuf = <<>> :: binary()
+ req_in :: p11rpc_msg() | undefined,
+ req_out :: p11rpc_msg() | undefined,
+ recv_count = 0 :: non_neg_integer(), % received from app
+ send_count = 0 :: non_neg_integer() % sent to token
}).
%% API.
@@ -37,22 +37,24 @@ start_link(Args) ->
reply(Pid, Response) ->
gen_server:call(Pid, {respond, Response}).
+-spec token_gone(pid(), boolean()) -> ok.
+token_gone(Pid, Hangup) ->
+ case process_info(Pid) of undefined -> error(bad_server_pid); _ -> nop end,
+ gen_server:cast(Pid, {token_gone, Hangup}).
+
+
%% Genserver callbacks.
init([Token, Socket]) ->
- lager:debug("~p: p11p_server:init", [self()]),
+ lager:debug("~p: p11p_server starting for ~s", [self(), Token]),
process_flag(trap_exit, true), % Need terminate/2.
gen_server:cast(self(), accept), % Invoke accept, returning a socket in state.
{ok, #state{tokname = Token, socket = Socket}}.
-handle_call({respond, R}, _, #state{socket = Sock, send_count = Sent} = S) ->
- D = p11p_rpc:serialise(R),
- Buf = case Sent of
- 0 -> <<?RPC_VERSION:8, D/binary>>;
- _ -> D
- end,
- %%lager:debug("~p: sending ~B octets as response", [self(), size(Buf)]),
- ok = gen_tcp:send(Sock, Buf), % TODO: what about short writes?
- {reply, {ok, size(Buf)}, S#state{send_count = Sent + 1}};
+%% FIXME: make this a cast
+handle_call({respond, Resp}, _, State = #state{send_count = Sent}) ->
+ N = send_response(State#state.socket, p11p_rpc:serialise(Resp), Sent),
+ {reply, {ok, N}, State#state{req_out = undefined,
+ send_count = Sent + 1}};
handle_call(Call, _, S) ->
lager:debug("~p: Unhandled call: ~p~n", [self(), Call]),
@@ -77,6 +79,21 @@ handle_cast(accept, State = #state{tokname = TokName, socket = ListenSocket}) ->
{stop, normal, State}
end;
+
+handle_cast({token_gone, Hangup}, State = #state{send_count = Sent}) ->
+ Resp = p11p_rpc:error(State#state.req_out#p11rpc_msg.call_code,
+ ?CKR_DEVICE_ERROR),
+ {ok, _} = send_response(State#state.socket, p11p_rpc:serialise(Resp), Sent),
+ NewState = State#state{client = undefined,
+ req_out = undefined,
+ send_count = Sent + 1},
+ case Hangup of
+ true ->
+ {close, NewState};
+ false ->
+ {noreply, NewState}
+ end;
+
handle_cast(Cast, State) ->
lager:debug("~p: Unhandled cast: ~p~n", [self(), Cast]),
{noreply, State}.
@@ -89,7 +106,7 @@ handle_info({tcp, Port, DataIn}, #state{tokname = TokName} = S)
case RPCVersion of
?RPC_VERSION ->
{noreply,
- p11_client_data(
+ p11_app_data(
S#state{client = p11p_manager:client_for_token(TokName)},
p11p_rpc:new(),
Data)};
@@ -100,9 +117,9 @@ handle_info({tcp, Port, DataIn}, #state{tokname = TokName} = S)
end;
%% Subsequent packages from P11 client.
-handle_info({tcp, _Port, DataIn}, #state{msg = Msg} = S) ->
+handle_info({tcp, _Port, DataIn}, #state{req_in = Msg} = S) ->
%%lager:debug("~p: received ~B octets from client on socket ~p, with ~B octets already in buffer", [self(), size(Data), Port, size(Msg#p11rpc_msg.buffer)]),
- {noreply, p11_client_data(S, Msg, DataIn)};
+ {noreply, p11_app_data(S, Msg, DataIn)};
handle_info({tcp_closed, Port}, S) ->
lager:debug("~p: socket ~p closed", [self(), Port]),
@@ -112,9 +129,14 @@ handle_info(Info, S) ->
lager:debug("~p: Unhandled info: ~p~n", [self(), Info]),
{noreply, S}.
-terminate(Reason, #state{socket = Sock, tokname = TokName, client = Client}) ->
- gen_tcp:close(Sock),
- p11p_manager:client_event(client_gone, [TokName, Client]),
+terminate(Reason, #state{socket = Sock, tokname = TokName}) ->
+ ok = gen_tcp:close(Sock),
+
+ %% FIXME: tell manager, so that the client can be stopped. we
+ %% don't want to risk that another app (socket client) uses it
+
+ p11p_manager:server_event(server_gone, TokName),
+
lager:debug("~p: terminated with reason ~p", [self(), Reason]),
ignored.
@@ -122,13 +144,24 @@ code_change(_OldVersion, State, _Extra) ->
{ok, State}.
%% Private functions.
-p11_client_data(#state{client = Client, recv_count = Recv} = S, MsgIn,
+p11_app_data(#state{client = Client, recv_count = Recv} = S, MsgIn,
DataIn) ->
case p11p_rpc:parse(MsgIn, DataIn) of
{needmore, Msg} ->
- S#state{msg = Msg};
+ S#state{req_in = Msg};
{done, Msg} ->
+ lager:debug("~p: -> ~s", [self(), p11p_rpc:dump(Msg)]),
{ok, _BytesSent} = p11p_client:request(Client, Msg),
- S#state{msg = p11p_rpc:new(Msg#p11rpc_msg.buffer),
+ S#state{req_out = Msg,
+ req_in = p11p_rpc:new(Msg#p11rpc_msg.buffer),
recv_count = Recv + 1}
end.
+
+send_response(Sock, Inbuf, Sent) ->
+ Buf = case Sent of
+ 0 -> <<?RPC_VERSION:8, Inbuf/binary>>;
+ _ -> Inbuf
+ end,
+ %%lager:debug("~p: sending ~B octets as response", [self(), size(Inbuf)]),
+ ok = gen_tcp:send(Sock, Buf),
+ {ok, size(Inbuf)}.