diff options
Diffstat (limited to 'p11p-daemon/src/p11p_server.erl')
-rw-r--r-- | p11p-daemon/src/p11p_server.erl | 81 |
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)}. |