-behaviour(gen_server).
%% API
--export([start_link/3, stop/1]).
+-export([start_link/3, stop/1, take_socket/2]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
-define(SERVER, ?MODULE).
--record(state, {listen_socket, acceptor, service}).
+-record(state, {listen_socket, acceptor_ref, service, handler}).
%%====================================================================
%% API
gen_server:call(Pid, stop).
+take_socket(Server, Socket) ->
+ gen_server:call(Server, {take_socket, Socket}).
+
+
%%====================================================================
%% gen_server callbacks
%%====================================================================
{active, false},
{nodelay, true},
{reuseaddr, true}]),
- Acceptor = spawn_link(fun () -> acceptor(Socket, Service, Handler) end),
+ {ok, Ref} = prim_inet:async_accept(Socket, -1),
{ok, #state{listen_socket = Socket,
- acceptor = Acceptor,
- service = Service}}.
+ acceptor_ref = Ref,
+ service = Service,
+ handler = Handler}}.
%%--------------------------------------------------------------------
%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
%% Description: Handling call messages
%%--------------------------------------------------------------------
handle_call(stop, _From, State) ->
- State#state.acceptor ! stop,
- {stop, stopped, ok, State}.
+ {stop, stopped, ok, State};
+
+handle_call({take_socket, Socket}, {FromPid, _Tag}, State) ->
+ Result = gen_tcp:controlling_process(Socket, FromPid),
+ {reply, Result, State}.
%%--------------------------------------------------------------------
%% Function: handle_cast(Msg, State) -> {noreply, State} |
%% {stop, Reason, State}
%% Description: Handling all non call/cast messages
%%--------------------------------------------------------------------
+handle_info({inet_async, ListenSocket, Ref, {ok, ClientSocket}},
+ State = #state{listen_socket = ListenSocket,
+ acceptor_ref = Ref,
+ service = Service,
+ handler = Handler}) ->
+ case set_sockopt(ListenSocket, ClientSocket) of
+ ok ->
+ %% New client connected - start processor
+ start_processor(ClientSocket, Service, Handler),
+ {ok, NewRef} = prim_inet:async_accept(ListenSocket, -1),
+ {noreply, State#state{acceptor_ref = NewRef}};
+ {error, Reason} ->
+ error_logger:error_msg("Couldn't set socket opts: ~p~n",
+ [Reason]),
+ {stop, Reason, State}
+ end;
+
+handle_info({inet_async, ListenSocket, Ref, Error}, State) ->
+ error_logger:error_msg("Error in acceptor: ~p~n", [Error]),
+ {stop, Error, State};
+
handle_info(_Info, State) ->
{noreply, State}.
%% Description: Convert process state when code is changed
%%--------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
- State#state.acceptor ! refresh,
{ok, State}.
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+set_sockopt(ListenSocket, ClientSocket) ->
+ true = inet_db:register_socket(ClientSocket, inet_tcp),
+ case prim_inet:getopts(ListenSocket,
+ [active, nodelay, keepalive, delay_send, priority, tos]) of
+ {ok, Opts} ->
+ case prim_inet:setopts(ClientSocket, Opts) of
+ ok -> ok;
+ Error -> gen_tcp:close(ClientSocket),
+ Error
+ end;
+ Error ->
+ gen_tcp:close(ClientSocket),
+ Error
+ end.
-acceptor(ListenSocket, Service, Handler)
- when is_port(ListenSocket), is_atom(Handler) ->
- {ok, Socket} = gen_tcp:accept(ListenSocket),
-% error_logger:info_msg("Accepted client"),
+
+
+start_processor(Socket, Service, Handler) ->
+ Server = self(),
ProtoGen = fun() ->
+ % Become the controlling process
+ ok = take_socket(Server, Socket),
{ok, SocketTransport} = thrift_socket_transport:new(Socket),
{ok, BufferedTransport} = thrift_buffered_transport:new(SocketTransport),
{ok, Protocol} = thrift_binary_protocol:new(BufferedTransport),
{ok, Protocol, Protocol}
end,
-
- thrift_processor:start(ProtoGen, Service, Handler),
- receive
- refresh ->
- error_logger:info_msg("Acceptor refreshing~n"),
- ?MODULE:acceptor(ListenSocket, Service, Handler);
- stop ->
- ok
- after 0 -> acceptor(ListenSocket, Service, Handler)
- end.
+
+ thrift_processor:start(ProtoGen, Service, Handler).