aboutsummaryrefslogtreecommitdiffstats
path: root/lib/megaco/src/flex/megaco_flex_scanner.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/megaco/src/flex/megaco_flex_scanner.erl')
-rw-r--r--lib/megaco/src/flex/megaco_flex_scanner.erl230
1 files changed, 230 insertions, 0 deletions
diff --git a/lib/megaco/src/flex/megaco_flex_scanner.erl b/lib/megaco/src/flex/megaco_flex_scanner.erl
new file mode 100644
index 0000000000..e471412c13
--- /dev/null
+++ b/lib/megaco/src/flex/megaco_flex_scanner.erl
@@ -0,0 +1,230 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2009. 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 : Scanner for text encoded Megaco/H.248 messages
+%%----------------------------------------------------------------------
+
+-module(megaco_flex_scanner).
+
+-export([is_enabled/0, is_reentrant_enabled/0, is_scanner_port/2]).
+-export([start/0, start/1, stop/1, scan/2]).
+
+-define(NUM_SCHED(), erlang:system_info(schedulers)).
+-define(SCHED_ID(), erlang:system_info(scheduler_id)).
+-define(SMP_SUPPORT_DEFAULT(), erlang:system_info(smp_support)).
+
+is_enabled() ->
+ case ?ENABLE_MEGACO_FLEX_SCANNER of
+ true ->
+ true;
+ _ ->
+ false
+ end.
+
+is_reentrant_enabled() ->
+ case ?MEGACO_REENTRANT_FLEX_SCANNER of
+ true ->
+ true;
+ _ ->
+ false
+ end.
+
+is_scanner_port(Port, Port) when is_port(Port) ->
+ true;
+is_scanner_port(Port, Ports) when is_tuple(Ports) ->
+ is_own_port(Port, Ports);
+is_scanner_port(_, _) ->
+ false.
+
+is_own_port(Port, Ports) ->
+ is_own_port(Port, size(Ports), Ports).
+
+is_own_port(_Port, 0, _Ports) ->
+ false;
+is_own_port(Port, N, Ports) when (N > 0) ->
+ case element(N, Ports) of
+ Port ->
+ true;
+ _ ->
+ is_own_port(Port, N-1, Ports)
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Start the flex scanner
+%%----------------------------------------------------------------------
+
+start() ->
+ start(?SMP_SUPPORT_DEFAULT()).
+
+start(SMP) when ((SMP =:= true) orelse (SMP =:= false)) ->
+ (catch do_start(is_reentrant_enabled() andalso SMP)).
+
+do_start(SMP) ->
+ Path = lib_dir(),
+ erl_ddll:start(),
+ load_driver(Path),
+ PortOrPorts = open_drv_port(SMP),
+ {ok, PortOrPorts}.
+
+
+lib_dir() ->
+ case code:priv_dir(megaco) of
+ {error, Reason} ->
+ throw({error, {priv_dir, Reason}});
+ P when is_list(P) ->
+ P ++ "/lib"
+ end.
+
+
+load_driver(Path) ->
+ case erl_ddll:load_driver(Path, drv_name()) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ case (catch erl_ddll:format_error(Reason)) of
+ FormatReason when is_list(FormatReason) ->
+ throw({error, {load_driver, FormatReason}});
+ _ ->
+ throw({error, {load_driver, Reason}})
+ end
+ end.
+
+
+open_drv_port(true) ->
+ open_drv_ports(?NUM_SCHED(), []);
+open_drv_port(_) ->
+ open_drv_port().
+
+open_drv_ports(0, Acc) ->
+ list_to_tuple(Acc);
+open_drv_ports(N, Acc) when is_integer(N) andalso (N > 0) ->
+ Port = open_drv_port(),
+ open_drv_ports(N-1, [Port | Acc]).
+
+open_drv_port() ->
+ case (catch erlang:open_port({spawn, drv_name()}, [binary])) of
+ Port when is_port(Port) ->
+ Port;
+ {'EXIT', Reason} ->
+ erl_ddll:unload_driver(drv_name()),
+ throw({error, {open_port, Reason}})
+ end.
+
+drv_name() ->
+ case erlang:system_info(threads) of
+ true ->
+ "megaco_flex_scanner_drv_mt";
+ false ->
+ "megaco_flex_scanner_drv"
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Stop the flex scanner
+%%----------------------------------------------------------------------
+
+stop(Port) when is_port(Port) ->
+ erlang:port_close(Port),
+ erl_ddll:unload_driver(drv_name()),
+ stopped;
+stop(Ports) when is_tuple(Ports) ->
+ stop(tuple_to_list(Ports));
+stop(Ports) when is_list(Ports) ->
+ lists:foreach(fun(Port) -> erlang:port_close(Port) end, Ports),
+ erl_ddll:unload_driver(drv_name()),
+ stopped.
+
+
+%%----------------------------------------------------------------------
+%% Scan a message
+%%----------------------------------------------------------------------
+
+scan(Binary, Port) when is_port(Port) ->
+ do_scan(Binary, Port);
+scan(Binary, Ports) when is_tuple(Ports) ->
+%% p("scan -> entry with"
+%% "~n Ports: ~p", [Ports]),
+ do_scan(Binary, select_port(Ports)).
+
+do_scan(Binary, Port) ->
+%% p("do_scan -> entry with"
+%% "~n Port: ~p", [Port]),
+ case erlang:port_control(Port, $s, Binary) of
+ [] ->
+ receive
+ {tokens, Tokens, LatestLine} ->
+%% p("do_scan -> OK with:"
+%% "~n length(Tokens): ~p"
+%% "~n LatestLine: ~p", [length(Tokens), LatestLine]),
+ Vsn = version(Tokens),
+ {ok, Tokens, Vsn, LatestLine}
+ after 5000 ->
+%% p("do_scan -> ERROR", []),
+ {error, "Driver term send failure", 1}
+ end;
+ Reason ->
+%% p("do_scan -> port control failed: "
+%% "~n Reason: ~p", [Reason]),
+ {error, Reason, 1}
+ end.
+
+select_port(Ports) ->
+ SchedId = ?SCHED_ID(),
+ %% lists:nth(SchedId, Ports).
+ element(SchedId, Ports).
+
+version([]) ->
+ 99; % Let the parser deal with this
+version([{'SafeChars',_,"!/1"}|_]) ->
+ 1;
+version([{'SafeChars',_,"megaco/1"}|_]) ->
+ 1;
+version([{'SafeChars',_,"!/2"}|_]) ->
+ 2;
+version([{'SafeChars',_,"megaco/2"}|_]) ->
+ 2;
+version([{'SafeChars',_,"!/3"}|_]) ->
+ 3;
+version([{'SafeChars',_,"megaco/3"}|_]) ->
+ 3;
+version([{'SafeChars',_,[$!, $/ | Vstr]}|_]) ->
+ guess_version(Vstr);
+version([{'SafeChars',_,[$m, $e, $g, $a, $c, $o, $/ | Vstr]}|_]) ->
+ guess_version(Vstr);
+version([_|T]) ->
+ version(T).
+
+
+guess_version([C]) when (48 =< C) and (C =< 57) ->
+ C-48;
+guess_version(Str) when is_list(Str) ->
+ case (catch list_to_integer(Str)) of
+ I when is_integer(I) ->
+ I;
+ _ ->
+ 99 % Let the parser deal with this
+ end;
+guess_version(_) ->
+ 99. % Let the parser deal with this
+
+
+%% p(F, A) ->
+%% io:format("~w [~p,~p] " ++ F ++ "~n", [?MODULE, self(), ?SCHED_ID() | A]).