%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2001-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
%%
%% %CopyrightEnd%
%%
%%
%%----------------------------------------------------------------------
%% Purpose: Handle the flex scanner
%%----------------------------------------------------------------------
-module(megaco_flex_scanner_handler).
-behaviour(gen_server).
%%-----------------------------------------------------------------
%% Include files
%%-----------------------------------------------------------------
-include_lib("megaco/src/app/megaco_internal.hrl").
%% External exports
-export([
start_link/0, start_link/1,
stop/1,
get_config/1
]).
%% gen_server callbacks
-export([
init/1,
handle_call/3, handle_cast/2, handle_info/2,
terminate/2,
code_change/3
]).
-record(state, {conf}).
%%%----------------------------------------------------------------------
%%% API
%%%----------------------------------------------------------------------
start_link() ->
start_link([]).
start_link(Opts) ->
case gen_server:start_link(?MODULE, Opts, []) of
{ok, Pid} ->
Conf = get_config(Pid),
{ok, Pid, Conf};
Else ->
Else
end.
stop(Pid) ->
gen_server:call(Pid, stop).
get_config(Pid) ->
gen_server:call(Pid, get_config).
%%%----------------------------------------------------------------------
%%% Callback functions from gen_server
%%%----------------------------------------------------------------------
%%----------------------------------------------------------------------
%% Func: init/1
%% Returns: {ok, State} |
%% {ok, State, Timeout} |
%% ignore |
%% {stop, Reason}
%%----------------------------------------------------------------------
init(_Opts) ->
process_flag(trap_exit, true),
case start_flex_scanners() of
{ok, PortOrPorts} ->
{ok, #state{conf = {flex, PortOrPorts}}};
{error, Reason} ->
%% {stop, {failed_starting_scanner, Reason, Opts}};
{stop, {failed_starting_scanner, Reason, []}};
Else ->
{stop, {failed_starting_scanner, Else}}
end.
%%----------------------------------------------------------------------
%% 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(get_config, _From, #state{conf = Conf} = S) ->
{reply, Conf, S};
handle_call(stop, _From, #state{conf = {flex, PortOrPorts}} = S) ->
megaco_flex_scanner:stop(PortOrPorts),
Reason = normal,
Reply = ok,
{stop, Reason, Reply, S};
handle_call(Req, From, S) ->
warning_msg("received unexpected request from ~p: "
"~n~w", [From, Req]),
{reply, {error, {unknown_request, Req}}, S}.
%%----------------------------------------------------------------------
%% Func: handle_cast/2
%% Returns: {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State} (terminate/2 is called)
%%----------------------------------------------------------------------
handle_cast(Msg, S) ->
warning_msg("received unexpected message: "
"~n~w", [Msg]),
{noreply, S}.
%%----------------------------------------------------------------------
%% Func: handle_info/2
%% Returns: {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State} (terminate/2 is called)
%%----------------------------------------------------------------------
handle_info({'EXIT', Port, Error}, #state{conf = {flex, PortOrPorts}} = S) ->
case megaco_flex_scanner:is_scanner_port(Port, PortOrPorts) of
true ->
error_msg("Port [~p] exited:"
"~n~w", [Port, Error]),
{stop, {port_exit, Port, Error}, S};
false ->
{noreply, S}
end;
handle_info({'EXIT', Port, _Error}, S) when is_port(Port) ->
%% This is propably the old flex scanner,
%% terminating after a code change...
{noreply, S};
handle_info({'EXIT', Id, Error}, S) ->
warning_msg("received unexpected 'EXIT' signal from ~p:"
"~n~w", [Id, Error]),
{noreply, S};
handle_info(Info, S) ->
warning_msg("received unexpected info: "
"~n~w", [Info]),
{noreply, S}.
%%----------------------------------------------------------------------
%% Func: terminate/2
%% Purpose: Shutdown the server
%% Returns: any (ignored by gen_server)
%%----------------------------------------------------------------------
terminate(_Reason, _S) ->
ok.
%%----------------------------------------------------------------------
%% Func: code_change/3
%% Purpose: Called to change the internal state
%% Returns: {ok, NewState}
%%----------------------------------------------------------------------
code_change({down, _Vsn}, #state{conf = Conf} = State, downgrade_to_pre_3_16_1) ->
NewPorts = bump_flex_scanner(Conf),
{ok, State#state{conf = {flex, NewPorts}}};
code_change(_Vsn, #state{conf = Conf} = State, upgrade_from_pre_3_16_1) ->
NewPorts = bump_flex_scanner(Conf),
{ok, State#state{conf = {flex, NewPorts}}};
code_change(_Vsn, State, _Extra) ->
{ok, State}.
bump_flex_scanner({flex, Ports}) ->
megaco_flex_scanner:stop(Ports),
case start_flex_scanners() of
{ok, NewPorts} ->
NewPorts;
Error ->
exit(Error)
end;
bump_flex_scanner(BadConfig) ->
exit({invalid_config, BadConfig}).
%%%----------------------------------------------------------------------
%%% Internal functions
%%%----------------------------------------------------------------------
start_flex_scanners() ->
megaco_flex_scanner:start().
%% get_env(Key, Opts, Default) ->
%% case lists:keysearch(Key, 1, Opts) of
%% {value, {Key, Value}} ->
%% Value;
%% false ->
%% Default
%% end.
warning_msg(F, A) ->
?megaco_warning("Flex scanner handler: " ++ F, A).
error_msg(F, A) ->
?megaco_error("Flex scanner handler: " ++ F, A).
% d(F, A) ->
% io:format("~w:" ++ F ++ "~n", [?MODULE|A]).