1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1999-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: Interface to the UDP transport module for Megaco/H.248 24%%----------------------------------------------------------------- 25-module(megaco_udp). 26 27-include_lib("megaco/include/megaco.hrl"). 28-include_lib("megaco/src/udp/megaco_udp.hrl"). 29 30-record(send_handle, {socket, addr, port}). 31 32 33%%----------------------------------------------------------------- 34%% External exports 35%%----------------------------------------------------------------- 36-export([ 37 start_transport/0, stop_transport/1, 38 open/2, 39 socket/1, 40 create_send_handle/3, 41 send_message/2, 42 close/1, 43 block/1, 44 unblock/1, 45 46 upgrade_receive_handle/2 47 ]). 48 49%% Statistics exports 50-export([get_stats/0, get_stats/1, get_stats/2, 51 reset_stats/0, reset_stats/1]). 52 53 54%%----------------------------------------------------------------- 55%% External interface functions 56%%----------------------------------------------------------------- 57 58%%----------------------------------------------------------------- 59%% Func: get_stats/0, get_stats/1, get_stats/2 60%% Description: Retreive statistics (counters) for TCP 61%%----------------------------------------------------------------- 62get_stats() -> 63 megaco_stats:get_stats(megaco_udp_stats). 64 65get_stats(SH) when is_record(SH, send_handle) -> 66 megaco_stats:get_stats(megaco_udp_stats, SH). 67 68get_stats(SH, Counter) 69 when is_record(SH, send_handle) andalso is_atom(Counter) -> 70 megaco_stats:get_stats(megaco_udp_stats, SH, Counter). 71 72 73%%----------------------------------------------------------------- 74%% Func: reset_stats/0, reaet_stats/1 75%% Description: Reset statistics (counters) for TCP 76%%----------------------------------------------------------------- 77reset_stats() -> 78 megaco_stats:reset_stats(megaco_udp_stats). 79 80reset_stats(SH) when is_record(SH, send_handle) -> 81 megaco_stats:reset_stats(megaco_udp_stats, SH). 82 83 84 85%%----------------------------------------------------------------- 86%% Func: start_transport 87%% Description: Starts the UDP transport service 88%%----------------------------------------------------------------- 89start_transport() -> 90 (catch megaco_stats:init(megaco_udp_stats)), 91 megaco_udp_sup:start_link(). 92 93 94%%----------------------------------------------------------------- 95%% Func: stop_transport 96%% Description: Stop the UDP transport service 97%%----------------------------------------------------------------- 98stop_transport(Pid) -> 99 (catch unlink(Pid)), 100 stop_transport(Pid, shutdown). 101 102stop_transport(Pid, Reason) -> 103 exit(Pid, Reason). 104 105 106%%----------------------------------------------------------------- 107%% Func: open 108%% Description: Function is used when opening an UDP socket 109%%----------------------------------------------------------------- 110open(SupPid, Options) -> 111 Mand = [port, receive_handle], 112 case parse_options(Options, #megaco_udp{}, Mand) of 113 {ok, UdpRec} -> 114 115 %%------------------------------------------------------ 116 %% Setup the socket 117 IpOpts = [binary, {reuseaddr, true}, {active, once} | 118 UdpRec#megaco_udp.options], 119 120 case (catch gen_udp:open(UdpRec#megaco_udp.port, IpOpts)) of 121 {ok, Socket} -> 122 ?udp_debug(UdpRec, "udp open", []), 123 NewUdpRec = UdpRec#megaco_udp{socket = Socket}, 124 case start_udp_server(SupPid, NewUdpRec) of 125 {ok, ControlPid} -> 126 gen_udp:controlling_process(Socket, ControlPid), 127 {ok, Socket, ControlPid}; 128 {error, Reason} -> 129 Error = {error, {could_not_start_udp_server, Reason}}, 130 ?udp_debug({socket, Socket}, "udp close", []), 131 gen_udp:close(Socket), 132 Error 133 134 end; 135 {'EXIT', Reason} -> 136 Error = {error, {could_not_open_udp_port, Reason}}, 137 ?udp_debug(UdpRec, "udp open exited", [Error]), 138 Error; 139 {error, Reason} -> 140 Error = {error, {could_not_open_udp_port, Reason}}, 141 ?udp_debug(UdpRec, "udp open failed", [Error]), 142 Error 143 end; 144 {error, Reason} = Error -> 145 ?udp_debug(#megaco_udp{}, "udp open failed", 146 [Error, {options, Options}]), 147 {error, Reason} 148 end. 149 150 151%%----------------------------------------------------------------- 152%% Func: socket 153%% Description: Returns the inet socket 154%%----------------------------------------------------------------- 155socket(SH) when is_record(SH, send_handle) -> 156 SH#send_handle.socket; 157socket(Socket) -> 158 Socket. 159 160 161upgrade_receive_handle(Pid, NewHandle) 162 when is_pid(Pid) andalso is_record(NewHandle, megaco_receive_handle) -> 163 megaco_udp_server:upgrade_receive_handle(Pid, NewHandle). 164 165 166%%----------------------------------------------------------------- 167%% Func: create_send_handle 168%% Description: Function is used for creating the handle used when 169%% sending data on the UDP socket 170%%----------------------------------------------------------------- 171create_send_handle(Socket, {_, _, _, _} = Addr, Port) -> 172 do_create_send_handle(Socket, Addr, Port); 173create_send_handle(Socket, Addr0, Port) -> 174 {ok, Addr} = inet:getaddr(Addr0, inet), 175 do_create_send_handle(Socket, Addr, Port). 176 177do_create_send_handle(Socket, Addr, Port) -> 178 %% If neccessary create snmp counter's 179 SH = #send_handle{socket = Socket, addr = Addr, port = Port}, 180 maybe_create_snmp_counters(SH), 181 SH. 182 183 184maybe_create_snmp_counters(SH) -> 185 Counters = [medGwyGatewayNumInMessages, 186 medGwyGatewayNumInOctets, 187 medGwyGatewayNumOutMessages, 188 medGwyGatewayNumOutOctets, 189 medGwyGatewayNumErrors], 190 %% Only need to check one of them, since either all of them exist 191 %% or none of them exist: 192 Key = {SH, medGwyGatewayNumInMessages}, 193 case (catch ets:lookup(megaco_udp_stats, Key)) of 194 [] -> 195 create_snmp_counters(SH, Counters); 196 [_] -> 197 ok; 198 _ -> 199 ok 200 end. 201 202create_snmp_counters(_SH, []) -> 203 ok; 204create_snmp_counters(SH, [Counter|Counters]) -> 205 Key = {SH, Counter}, 206 ets:insert(megaco_udp_stats, {Key, 0}), 207 create_snmp_counters(SH, Counters). 208 209 210%%----------------------------------------------------------------- 211%% Func: send_message 212%% Description: Function is used for sending data on the UDP socket 213%%----------------------------------------------------------------- 214send_message(SH, Data) when is_record(SH, send_handle) -> 215 #send_handle{socket = Socket, addr = Addr, port = Port} = SH, 216 Res = gen_udp:send(Socket, Addr, Port, Data), 217 case Res of 218 ok -> 219 incNumOutMessages(SH), 220 incNumOutOctets(SH, size(Data)); 221 _ -> 222 ok 223 end, 224 Res; 225send_message(SH, _Data) -> 226 {error, {bad_send_handle, SH}}. 227 228 229%%----------------------------------------------------------------- 230%% Func: block 231%% Description: Function is used for blocking incomming messages 232%% on the TCP socket 233%%----------------------------------------------------------------- 234block(SH) when is_record(SH, send_handle) -> 235 block(SH#send_handle.socket); 236block(Socket) -> 237 ?udp_debug({socket, Socket}, "udp block", []), 238 inet:setopts(Socket, [{active, false}]). 239 240 241%%----------------------------------------------------------------- 242%% Func: unblock 243%% Description: Function is used for blocking incomming messages 244%% on the TCP socket 245%%----------------------------------------------------------------- 246unblock(SH) when is_record(SH, send_handle) -> 247 unblock(SH#send_handle.socket); 248unblock(Socket) -> 249 ?udp_debug({socket, Socket}, "udp unblock", []), 250 inet:setopts(Socket, [{active, once}]). 251 252 253%%----------------------------------------------------------------- 254%% Func: close 255%% Description: Function is used for closing the UDP socket 256%%----------------------------------------------------------------- 257close(#send_handle{socket = Socket}) -> 258 close(Socket); 259close(Socket) -> 260 ?udp_debug({socket, Socket}, "udp close", []), 261 case erlang:port_info(Socket, connected) of 262 {connected, ControlPid} -> 263 megaco_udp_server:stop(ControlPid); 264 undefined -> 265 {error, already_closed} 266 end. 267 268 269%%----------------------------------------------------------------- 270%% Internal functions 271%%----------------------------------------------------------------- 272%%----------------------------------------------------------------- 273%% Func: start_udp_server/1 274%% Description: Function is used for starting up a connection 275%% process 276%%----------------------------------------------------------------- 277start_udp_server(SupPid, UdpRec) -> 278 megaco_udp_sup:start_child(SupPid, UdpRec). 279 280 281%%----------------------------------------------------------------- 282%% Func: parse_options 283%% Description: Function that parses the options sent to the UDP 284%% module. 285%%----------------------------------------------------------------- 286parse_options([{Tag, Val} | T], UdpRec, Mand) -> 287 Mand2 = Mand -- [Tag], 288 case Tag of 289 port -> 290 parse_options(T, UdpRec#megaco_udp{port = Val}, Mand2); 291 udp_options when is_list(Val) -> 292 parse_options(T, UdpRec#megaco_udp{options = Val}, Mand2); 293 receive_handle -> 294 parse_options(T, UdpRec#megaco_udp{receive_handle = Val}, Mand2); 295 module when is_atom(Val) -> 296 parse_options(T, UdpRec#megaco_udp{module = Val}, Mand2); 297 serialize when (Val =:= true) orelse (Val =:= false) -> 298 parse_options(T, UdpRec#megaco_udp{serialize = Val}, Mand2); 299 Bad -> 300 {error, {bad_option, Bad}} 301 end; 302parse_options([], UdpRec, []) -> 303 {ok, UdpRec}; 304parse_options([], _UdpRec, Mand) -> 305 {error, {missing_options, Mand}}; 306parse_options(BadList, _UdpRec, _Mand) -> 307 {error, {bad_option_list, BadList}}. 308 309 310%%----------------------------------------------------------------- 311%% Func: incNumOutMessages/1, incNumOutOctets/2, incNumErrors/1 312%% Description: SNMP counter increment functions 313%% 314%%----------------------------------------------------------------- 315incNumOutMessages(SH) -> 316 incCounter({SH, medGwyGatewayNumOutMessages}, 1). 317 318incNumOutOctets(SH, NumOctets) -> 319 incCounter({SH, medGwyGatewayNumOutOctets}, NumOctets). 320 321incCounter(Key, Inc) -> 322 ets:update_counter(megaco_udp_stats, Key, Inc). 323 324% incNumErrors(SH) -> 325% incCounter({SH, medGwyGatewayNumErrors}, 1). 326