From 84adefa331c4159d432d22840663c38f155cd4c1 Mon Sep 17 00:00:00 2001 From: Erlang/OTP Date: Fri, 20 Nov 2009 14:54:40 +0000 Subject: The R13B03 release. --- lib/megaco/src/udp/megaco_udp.erl | 324 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 324 insertions(+) create mode 100644 lib/megaco/src/udp/megaco_udp.erl (limited to 'lib/megaco/src/udp/megaco_udp.erl') diff --git a/lib/megaco/src/udp/megaco_udp.erl b/lib/megaco/src/udp/megaco_udp.erl new file mode 100644 index 0000000000..c75b703949 --- /dev/null +++ b/lib/megaco/src/udp/megaco_udp.erl @@ -0,0 +1,324 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-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: Interface to the UDP transport module for Megaco/H.248 +%%----------------------------------------------------------------- +-module(megaco_udp). + +-include_lib("megaco/include/megaco.hrl"). +-include_lib("megaco/src/udp/megaco_udp.hrl"). + +-record(send_handle, {socket, addr, port}). + + +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([ + start_transport/0, stop_transport/1, + open/2, + socket/1, + create_send_handle/3, + send_message/2, + close/1, + block/1, + unblock/1, + + upgrade_receive_handle/2 + ]). + +%% Statistics exports +-export([get_stats/0, get_stats/1, get_stats/2, + reset_stats/0, reset_stats/1]). + + +%%----------------------------------------------------------------- +%% External interface functions +%%----------------------------------------------------------------- + +%%----------------------------------------------------------------- +%% Func: get_stats/0, get_stats/1, get_stats/2 +%% Description: Retreive statistics (counters) for TCP +%%----------------------------------------------------------------- +get_stats() -> + megaco_stats:get_stats(megaco_udp_stats). + +get_stats(SH) when is_record(SH, send_handle) -> + megaco_stats:get_stats(megaco_udp_stats, SH). + +get_stats(SH, Counter) + when is_record(SH, send_handle) andalso is_atom(Counter) -> + megaco_stats:get_stats(megaco_udp_stats, SH, Counter). + + +%%----------------------------------------------------------------- +%% Func: reset_stats/0, reaet_stats/1 +%% Description: Reset statistics (counters) for TCP +%%----------------------------------------------------------------- +reset_stats() -> + megaco_stats:reset_stats(megaco_udp_stats). + +reset_stats(SH) when is_record(SH, send_handle) -> + megaco_stats:reset_stats(megaco_udp_stats, SH). + + + +%%----------------------------------------------------------------- +%% Func: start_transport +%% Description: Starts the UDP transport service +%%----------------------------------------------------------------- +start_transport() -> + (catch megaco_stats:init(megaco_udp_stats)), + megaco_udp_sup:start_link(). + + +%%----------------------------------------------------------------- +%% Func: stop_transport +%% Description: Stop the UDP transport service +%%----------------------------------------------------------------- +stop_transport(Pid) -> + (catch unlink(Pid)), + stop_transport(Pid, shutdown). + +stop_transport(Pid, Reason) -> + exit(Pid, Reason). + + +%%----------------------------------------------------------------- +%% Func: open +%% Description: Function is used when opening an UDP socket +%%----------------------------------------------------------------- +open(SupPid, Options) -> + Mand = [port, receive_handle], + case parse_options(Options, #megaco_udp{}, Mand) of + {ok, UdpRec} -> + + %%------------------------------------------------------ + %% Setup the socket + IpOpts = [binary, {reuseaddr, true}, {active, once} | + UdpRec#megaco_udp.options], + + case (catch gen_udp:open(UdpRec#megaco_udp.port, IpOpts)) of + {ok, Socket} -> + ?udp_debug(UdpRec, "udp open", []), + NewUdpRec = UdpRec#megaco_udp{socket = Socket}, + case start_udp_server(SupPid, NewUdpRec) of + {ok, ControlPid} -> + gen_udp:controlling_process(Socket, ControlPid), + {ok, Socket, ControlPid}; + {error, Reason} -> + Error = {error, {could_not_start_udp_server, Reason}}, + ?udp_debug({socket, Socket}, "udp close", []), + gen_udp:close(Socket), + Error + + end; + {'EXIT', Reason} -> + Error = {error, {could_not_open_udp_port, Reason}}, + ?udp_debug(UdpRec, "udp open exited", [Error]), + Error; + {error, Reason} -> + Error = {error, {could_not_open_udp_port, Reason}}, + ?udp_debug(UdpRec, "udp open failed", [Error]), + Error + end; + {error, Reason} = Error -> + ?udp_debug(#megaco_udp{}, "udp open failed", + [Error, {options, Options}]), + {error, Reason} + end. + + +%%----------------------------------------------------------------- +%% Func: socket +%% Description: Returns the inet socket +%%----------------------------------------------------------------- +socket(SH) when is_record(SH, send_handle) -> + SH#send_handle.socket; +socket(Socket) -> + Socket. + + +upgrade_receive_handle(Pid, NewHandle) + when is_pid(Pid) andalso is_record(NewHandle, megaco_receive_handle) -> + megaco_udp_server:upgrade_receive_handle(Pid, NewHandle). + + +%%----------------------------------------------------------------- +%% Func: create_send_handle +%% Description: Function is used for creating the handle used when +%% sending data on the UDP socket +%%----------------------------------------------------------------- +create_send_handle(Socket, {_, _, _, _} = Addr, Port) -> + do_create_send_handle(Socket, Addr, Port); +create_send_handle(Socket, Addr0, Port) -> + {ok, Addr} = inet:getaddr(Addr0, inet), + do_create_send_handle(Socket, Addr, Port). + +do_create_send_handle(Socket, Addr, Port) -> + %% If neccessary create snmp counter's + SH = #send_handle{socket = Socket, addr = Addr, port = Port}, + maybe_create_snmp_counters(SH), + SH. + + +maybe_create_snmp_counters(SH) -> + Counters = [medGwyGatewayNumInMessages, + medGwyGatewayNumInOctets, + medGwyGatewayNumOutMessages, + medGwyGatewayNumOutOctets, + medGwyGatewayNumErrors], + %% Only need to check one of them, since either all of them exist + %% or none of them exist: + Key = {SH, medGwyGatewayNumInMessages}, + case (catch ets:lookup(megaco_udp_stats, Key)) of + [] -> + create_snmp_counters(SH, Counters); + [_] -> + ok; + _ -> + ok + end. + +create_snmp_counters(_SH, []) -> + ok; +create_snmp_counters(SH, [Counter|Counters]) -> + Key = {SH, Counter}, + ets:insert(megaco_udp_stats, {Key, 0}), + create_snmp_counters(SH, Counters). + + +%%----------------------------------------------------------------- +%% Func: send_message +%% Description: Function is used for sending data on the UDP socket +%%----------------------------------------------------------------- +send_message(SH, Data) when is_record(SH, send_handle) -> + #send_handle{socket = Socket, addr = Addr, port = Port} = SH, + Res = gen_udp:send(Socket, Addr, Port, Data), + case Res of + ok -> + incNumOutMessages(SH), + incNumOutOctets(SH, size(Data)); + _ -> + ok + end, + Res; +send_message(SH, _Data) -> + {error, {bad_send_handle, SH}}. + + +%%----------------------------------------------------------------- +%% Func: block +%% Description: Function is used for blocking incomming messages +%% on the TCP socket +%%----------------------------------------------------------------- +block(SH) when is_record(SH, send_handle) -> + block(SH#send_handle.socket); +block(Socket) -> + ?udp_debug({socket, Socket}, "udp block", []), + inet:setopts(Socket, [{active, false}]). + + +%%----------------------------------------------------------------- +%% Func: unblock +%% Description: Function is used for blocking incomming messages +%% on the TCP socket +%%----------------------------------------------------------------- +unblock(SH) when is_record(SH, send_handle) -> + unblock(SH#send_handle.socket); +unblock(Socket) -> + ?udp_debug({socket, Socket}, "udp unblock", []), + inet:setopts(Socket, [{active, once}]). + + +%%----------------------------------------------------------------- +%% Func: close +%% Description: Function is used for closing the UDP socket +%%----------------------------------------------------------------- +close(#send_handle{socket = Socket}) -> + close(Socket); +close(Socket) -> + ?udp_debug({socket, Socket}, "udp close", []), + case erlang:port_info(Socket, connected) of + {connected, ControlPid} -> + megaco_udp_server:stop(ControlPid); + undefined -> + {error, already_closed} + end. + + +%%----------------------------------------------------------------- +%% Internal functions +%%----------------------------------------------------------------- +%%----------------------------------------------------------------- +%% Func: start_udp_server/1 +%% Description: Function is used for starting up a connection +%% process +%%----------------------------------------------------------------- +start_udp_server(SupPid, UdpRec) -> + megaco_udp_sup:start_child(SupPid, UdpRec). + + +%%----------------------------------------------------------------- +%% Func: parse_options +%% Description: Function that parses the options sent to the UDP +%% module. +%%----------------------------------------------------------------- +parse_options([{Tag, Val} | T], UdpRec, Mand) -> + Mand2 = Mand -- [Tag], + case Tag of + port -> + parse_options(T, UdpRec#megaco_udp{port = Val}, Mand2); + udp_options when is_list(Val) -> + parse_options(T, UdpRec#megaco_udp{options = Val}, Mand2); + receive_handle -> + parse_options(T, UdpRec#megaco_udp{receive_handle = Val}, Mand2); + module when is_atom(Val) -> + parse_options(T, UdpRec#megaco_udp{module = Val}, Mand2); + serialize when (Val =:= true) orelse (Val =:= false) -> + parse_options(T, UdpRec#megaco_udp{serialize = Val}, Mand2); + Bad -> + {error, {bad_option, Bad}} + end; +parse_options([], UdpRec, []) -> + {ok, UdpRec}; +parse_options([], _UdpRec, Mand) -> + {error, {missing_options, Mand}}; +parse_options(BadList, _UdpRec, _Mand) -> + {error, {bad_option_list, BadList}}. + + +%%----------------------------------------------------------------- +%% Func: incNumOutMessages/1, incNumOutOctets/2, incNumErrors/1 +%% Description: SNMP counter increment functions +%% +%%----------------------------------------------------------------- +incNumOutMessages(SH) -> + incCounter({SH, medGwyGatewayNumOutMessages}, 1). + +incNumOutOctets(SH, NumOctets) -> + incCounter({SH, medGwyGatewayNumOutOctets}, NumOctets). + +incCounter(Key, Inc) -> + ets:update_counter(megaco_udp_stats, Key, Inc). + +% incNumErrors(SH) -> +% incCounter({SH, medGwyGatewayNumErrors}, 1). -- cgit v1.2.3