%%%---------------------------------------------------------------------- %%% File : rpc_socket.erl %%% Author : ottuser local account %%% Purpose : Accept a tcp/ip connection and then handle in and ivr protocols %%% Created : 26 May 1999 by ottuser local account %%%---------------------------------------------------------------------- %%% This gen_server exists for the life of a socket connection %%% It is spawned by tcp_listen, which send it it's own PID %%% so we can ask it to set up a new listener if/when this one accepts %%% a socket connection. %%%---------------------------------------------------------------------- -module(rpc_socket). -vsn(1). -author('shinde@one2one.co.uk'). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -export([start/2, get_connection/1, worker/5]). -behaviour(gen_server). % Internal state for this socket process -record(state,{listen_pid, % Pid of Listener lis_socket, % Listener Socket socket = undefined}). % Socket ref %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- start(ListenPid, ListenSocket) -> gen_server:start_link(rpc_socket, {ListenPid, ListenSocket},[]). get_connection(Pid) -> gen_server:cast(Pid, get_conn). %%%---------------------------------------------------------------------- %%% Callback functions from gen_server %%%---------------------------------------------------------------------- %%---------------------------------------------------------------------- %% Func: init/1 %% Returns: {ok, State} | %% {ok, State, Timeout} | %% ignore | %% {stop, Reason} %%---------------------------------------------------------------------- init({ListenPid, ListenSocket}) -> {ok, #state{listen_pid = ListenPid, lis_socket = ListenSocket}}. %%---------------------------------------------------------------------- %% Func: handle_call/3 %% Returns: {reply, Reply, State} | %% {reply, Reply, State, Timeout} | %% {noreply, State} | %% {noreply, State, Timeout} | %% {stop, Reason, Reply, State} | (terminate/2 is called) %% {stop, Reason, State} (terminate/2 is called) %%---------------------------------------------------------------------- handle_call(Request,From,State) -> {reply,ok,State}. %%---------------------------------------------------------------------- %% Func: handle_cast/2 %% Returns: {noreply, State} | %% {noreply, State, Timeout} | %% {stop, Reason, State} (terminate/2 is called) %%---------------------------------------------------------------------- handle_cast(get_conn, State) -> case catch gen_tcp:accept(State#state.lis_socket) of {error, closed} -> {stop, {error, accept_failed}, State}; {error, Reason} -> {stop, {error, accept_failed}, State}; {'EXIT', Reason} -> {stop, {error, accept_failed}, State}; {ok, Socket} -> rpc_listen:create(State#state.listen_pid, self()), {noreply, State#state{socket = Socket}} end; handle_cast(_Reply ,State) -> {noreply, State}. %%---------------------------------------------------------------------- %% Func: handle_info/2 %% Returns: {noreply, State} | %% {noreply, State, Timeout} | %% {stop, Reason, State} (terminate/2 is called) %%---------------------------------------------------------------------- handle_info({tcp, Socket, Packet}, State) -> case catch binary_to_term(Packet) of {heartbeat, Ref} -> % io:format("Heartbeat Received~n"), gen_tcp:send(Socket, term_to_binary({heart_reply, Ref})), {noreply, State}; {apply, M, F, A, Ref} -> Pid = spawn_link(?MODULE, worker, [M, F, A, Ref, Socket]), {noreply, State}; Else -> io:format("Socket Received Else: ~p~n",[Else]), {noreply, State} end; handle_info({tcp_closed, Socket}, State) -> {stop, rpc_skt_closed, State}; handle_info({tcp_error, Socket, Reason}, State) -> gen_tcp:close(State#state.socket), {stop, rpc_skt_error, State}; handle_info(Anymessage, State) -> {noreply, State}. %%---------------------------------------------------------------------- %% Func: terminate/2 %% Purpose: Shutdown the server %% Returns: any (ignored by gen_server) %%---------------------------------------------------------------------- terminate(Reason, #state{socket = undefined}) -> ok; terminate(Reason, #state{socket = Socket}) -> gen_tcp:close(Socket), ok. %%---------------------------------------------------------------------- %% Func: code_change/3 %% Purpose: Convert process state when code is changed %% Returns: {ok, NewState} %%---------------------------------------------------------------------- code_change(OldVsn, State, Extra) -> {ok, State}. %%%---------------------------------------------------------------------- %%% Internal functions %%%---------------------------------------------------------------------- worker(M, F, A, Ref, Socket) -> Reply = (catch apply(M, F, A)), % io:format("Reply: ~p~n", [Reply]), gen_tcp:send(Socket, term_to_binary({reply, Ref, Reply})).