1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21%%
22%%----------------------------------------------------------------------
23%% Purpose: Handle the flex scanner
24%%----------------------------------------------------------------------
25
26-module(megaco_flex_scanner_handler).
27
28-behaviour(gen_server).
29
30
31%%-----------------------------------------------------------------
32%% Include files
33%%-----------------------------------------------------------------
34-include_lib("megaco/src/app/megaco_internal.hrl").
35
36
37%% External exports
38-export([
39	 start_link/0, start_link/1,
40	 stop/1,
41	 get_config/1
42	]).
43
44%% gen_server callbacks
45-export([
46	 init/1,
47	 handle_call/3, handle_cast/2, handle_info/2,
48	 terminate/2,
49	 code_change/3
50	]).
51
52-record(state, {conf}).
53
54
55%%%----------------------------------------------------------------------
56%%% API
57%%%----------------------------------------------------------------------
58
59start_link() ->
60    start_link([]).
61
62start_link(Opts) ->
63    case gen_server:start_link(?MODULE, Opts, []) of
64	{ok, Pid} ->
65	    Conf = get_config(Pid),
66	    {ok, Pid, Conf};
67	Else ->
68	    Else
69    end.
70
71stop(Pid) ->
72    gen_server:call(Pid, stop).
73
74get_config(Pid) ->
75    gen_server:call(Pid, get_config).
76
77
78%%%----------------------------------------------------------------------
79%%% Callback functions from gen_server
80%%%----------------------------------------------------------------------
81
82%%----------------------------------------------------------------------
83%% Func: init/1
84%% Returns: {ok, State}          |
85%%          {ok, State, Timeout} |
86%%          ignore               |
87%%          {stop, Reason}
88%%----------------------------------------------------------------------
89init(_Opts) ->
90    process_flag(trap_exit, true),
91    case start_flex_scanners() of
92	{ok, PortOrPorts} ->
93	    {ok, #state{conf = {flex, PortOrPorts}}};
94	{error, Reason} ->
95	    %% {stop, {failed_starting_scanner, Reason, Opts}};
96	    {stop, {failed_starting_scanner, Reason, []}};
97	Else ->
98	    {stop, {failed_starting_scanner, Else}}
99    end.
100
101
102%%----------------------------------------------------------------------
103%% Func: handle_call/3
104%% Returns: {reply, Reply, State}          |
105%%          {reply, Reply, State, Timeout} |
106%%          {noreply, State}               |
107%%          {noreply, State, Timeout}      |
108%%          {stop, Reason, Reply, State}   | (terminate/2 is called)
109%%          {stop, Reason, State}            (terminate/2 is called)
110%%----------------------------------------------------------------------
111handle_call(get_config, _From, #state{conf = Conf} = S) ->
112    {reply, Conf, S};
113
114handle_call(stop, _From, #state{conf = {flex, PortOrPorts}} = S) ->
115    megaco_flex_scanner:stop(PortOrPorts),
116    Reason = normal,
117    Reply  = ok,
118    {stop, Reason, Reply, S};
119
120handle_call(Req, From, S) ->
121    warning_msg("received unexpected request from ~p: "
122		"~n~w", [From, Req]),
123    {reply, {error, {unknown_request, Req}}, S}.
124
125
126%%----------------------------------------------------------------------
127%% Func: handle_cast/2
128%% Returns: {noreply, State}          |
129%%          {noreply, State, Timeout} |
130%%          {stop, Reason, State}            (terminate/2 is called)
131%%----------------------------------------------------------------------
132handle_cast(Msg, S) ->
133    warning_msg("received unexpected message: "
134		"~n~w", [Msg]),
135    {noreply, S}.
136
137
138%%----------------------------------------------------------------------
139%% Func: handle_info/2
140%% Returns: {noreply, State}          |
141%%          {noreply, State, Timeout} |
142%%          {stop, Reason, State}            (terminate/2 is called)
143%%----------------------------------------------------------------------
144handle_info({'EXIT', Port, Error}, #state{conf = {flex, PortOrPorts}} = S) ->
145    case megaco_flex_scanner:is_scanner_port(Port, PortOrPorts) of
146	true ->
147	    error_msg("Port [~p] exited:"
148		      "~n~w", [Port, Error]),
149	    {stop, {port_exit, Port, Error}, S};
150	false ->
151	    {noreply, S}
152    end;
153
154handle_info({'EXIT', Port, _Error}, S) when is_port(Port) ->
155    %% This is propably the old flex scanner,
156    %% terminating after a code change...
157    {noreply, S};
158
159handle_info({'EXIT', Id, Error}, S) ->
160    warning_msg("received unexpected 'EXIT' signal from ~p:"
161		"~n~w", [Id, Error]),
162    {noreply, S};
163
164handle_info(Info, S) ->
165    warning_msg("received unexpected info: "
166		"~n~w", [Info]),
167    {noreply, S}.
168
169
170%%----------------------------------------------------------------------
171%% Func: terminate/2
172%% Purpose: Shutdown the server
173%% Returns: any (ignored by gen_server)
174%%----------------------------------------------------------------------
175terminate(_Reason, _S) ->
176    ok.
177
178
179%%----------------------------------------------------------------------
180%% Func: code_change/3
181%% Purpose: Called to change the internal state
182%% Returns: {ok, NewState}
183%%----------------------------------------------------------------------
184
185code_change({down, _Vsn}, #state{conf = Conf} = State, downgrade_to_pre_3_17) ->
186    NewPorts = bump_flex_scanner(Conf),
187    {ok, State#state{conf = {flex, NewPorts}}};
188
189code_change(_Vsn, #state{conf = Conf} = State, upgrade_from_pre_3_17) ->
190    NewPorts = bump_flex_scanner(Conf),
191    {ok, State#state{conf = {flex, NewPorts}}};
192
193code_change(_Vsn, State, _Extra) ->
194    {ok, State}.
195
196bump_flex_scanner({flex, Ports}) ->
197    megaco_flex_scanner:stop(Ports),
198    case start_flex_scanners() of
199	{ok, NewPorts} ->
200	    NewPorts;
201	Error ->
202	    exit(Error)
203    end;
204bump_flex_scanner(BadConfig) ->
205    exit({invalid_config, BadConfig}).
206
207
208%%%----------------------------------------------------------------------
209%%% Internal functions
210%%%----------------------------------------------------------------------
211
212start_flex_scanners() ->
213    megaco_flex_scanner:start().
214
215
216%% get_env(Key, Opts, Default) ->
217%%     case lists:keysearch(Key, 1, Opts) of
218%% 	{value, {Key, Value}} ->
219%% 	    Value;
220%% 	false ->
221%% 	    Default
222%%     end.
223
224warning_msg(F, A) ->
225    ?megaco_warning("Flex scanner handler: " ++ F, A).
226
227error_msg(F, A) ->
228    ?megaco_error("Flex scanner handler: " ++ F, A).
229
230
231
232% d(F, A) ->
233%     io:format("~w:" ++ F ++ "~n", [?MODULE|A]).
234
235