1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2007-2019. 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: Generic megaco transport simulator module 24%%---------------------------------------------------------------------- 25 26-module(megaco_test_generic_transport). 27 28-behaviour(gen_server). 29-behaviour(megaco_transport). 30 31-export([ 32 start_transport/0, 33 listen/2, 34 connect/2, 35 start/1, 36 stop/0, 37 incomming_message/2 38 ]). 39 40%% gen_server callbacks 41-export([ 42 init/1, 43 handle_call/3, 44 handle_cast/2, 45 handle_info/2, 46 terminate/2, 47 code_change/3 48 ]). 49 50%% megaco_transport callbacks 51-export([ 52 send_message/2, 53 send_message/3, 54 resend_message/2 55 ]). 56 57-record(state, {parent, 58 controller, 59 receive_handle}). 60 61-include_lib("megaco/include/megaco.hrl"). 62-include("megaco_test_lib.hrl"). 63-define(SERVER, ?MODULE). 64 65 66%%------------------------------------------------------------------- 67%% API 68%%------------------------------------------------------------------- 69 70start(RH) -> 71 {ok, Pid} = start_transport(), 72 {ok, SendHandle, _} = connect(Pid, [{receive_handle, RH}]), 73 {ok, SendHandle}. 74 75start_transport() -> 76 %% GS_ARGS = [{debug,[trace]}], 77 GS_ARGS = [], 78 {ok, Pid} = gen_server:start_link({local, ?SERVER}, ?MODULE, [self()], GS_ARGS), 79 unlink(Pid), 80 {ok, Pid}. 81 82connect(Sup, Opts) -> 83 call({connect, Sup, Opts}). 84 85listen(Sup, Opts) -> 86 call({listen, Sup, Opts}). 87 88stop() -> 89 call(stop). 90 91 92%%---------------------------------------------------------------------- 93%% Megaco transport callback 94%%---------------------------------------------------------------------- 95 96send_message(SendHandle, Bin) -> 97 call({transport, {send_message, SendHandle, Bin}}). 98 99send_message(SendHandle, Bin, Resend) -> 100 call({transport, {send_message, SendHandle, Bin, Resend}}). 101 102resend_message(SendHandle, Bin) -> 103 call({transport, {resend_message, SendHandle, Bin}}). 104 105incomming_message(Pid, Msg) -> 106 cast(Pid, {incomming_message, Msg}). 107 108 109%%%------------------------------------------------------------------- 110%%% Callback functions from gen_server 111%%%------------------------------------------------------------------- 112 113%%-------------------------------------------------------------------- 114%% Func: init/1 115%% Returns: {ok, State} | 116%% {ok, State, Timeout} | 117%% ignore | 118%% {stop, Reason} 119%%-------------------------------------------------------------------- 120init([Parent]) -> 121 {ok, #state{parent = Parent}}. 122 123 124%%-------------------------------------------------------------------- 125%% Func: handle_call/3 126%% Returns: {reply, Reply, State} | 127%% {reply, Reply, State, Timeout} | 128%% {noreply, State} | 129%% {noreply, State, Timeout} | 130%% {stop, Reason, Reply, State} | (terminate/2 is called) 131%% {stop, Reason, State} (terminate/2 is called) 132%%-------------------------------------------------------------------- 133handle_call({connect, _Sup, Opts}, _From, State) -> 134 d("handle_call(connect) -> entry with" 135 "~n Opts: ~p", [Opts]), 136 {value, {_, ReceiveHandle}} = lists:keysearch(receive_handle, 1, Opts), 137 {value, {_, Controller}} = lists:keysearch(port, 1, Opts), 138 SendHandle = self(), 139 ControlPid = self(), 140 Reply = {ok, SendHandle, ControlPid}, 141 {reply, Reply, State#state{controller = Controller, 142 receive_handle = ReceiveHandle}}; 143 144handle_call({listen, _Sup, Opts}, _From, State) -> 145 d("handle_call(listen) -> entry with" 146 "~n Opts: ~p", [Opts]), 147 {value, {_, ReceiveHandle}} = lists:keysearch(receive_handle, 1, Opts), 148 {value, {_, Controller}} = lists:keysearch(port, 1, Opts), 149 SendHandle = self(), 150 ControlPid = self(), 151 Reply = {ok, SendHandle, ControlPid}, 152 Controller ! {listen, ReceiveHandle, SendHandle, ControlPid}, 153 {reply, Reply, State#state{controller = Controller, 154 receive_handle = ReceiveHandle}}; 155 156handle_call(stop, _From, State) -> 157 d("handle_call(stop) -> entry"), 158 Reply = ok, 159 Reason = normal, 160 {stop, Reason, Reply, State}; 161 162handle_call({transport, Event}, _From, 163 #state{controller = Pid, receive_handle = RH} = State) -> 164 d("handle_call(transport) -> entry with" 165 "~n Event: ~p", [Event]), 166 Reply = handle_transport(Pid, RH, Event), 167 {reply, Reply, State}; 168 169handle_call(Req, From, State) -> 170 d("handle_call -> entry with" 171 "~n Req: ~p", [Req]), 172 Reply = {error, {unknown_request, Req}}, 173 Reason = {received_unexpected_request, Req, From}, 174 {stop, Reason, Reply, State}. 175 176 177%%-------------------------------------------------------------------- 178%% Func: handle_cast/2 179%% Returns: {noreply, State} | 180%% {noreply, State, Timeout} | 181%% {stop, Reason, State} (terminate/2 is called) 182%%-------------------------------------------------------------------- 183handle_cast({incomming_message, Msg}, 184 #state{receive_handle = RH} = State) -> 185 d("handle_cast(incomming_message) -> entry with" 186 "~n Msg: ~p", [Msg]), 187 handle_incomming_message(Msg, RH), 188 {noreply, State}; 189 190handle_cast(Msg, State) -> 191 d("handle_cast -> entry with" 192 "~n Msg: ~p", [Msg]), 193 Reason = {received_unexpected_message, Msg}, 194 {stop, Reason, State}. 195 196 197%%-------------------------------------------------------------------- 198%% Func: handle_info/2 199%% Returns: {noreply, State} | 200%% {noreply, State, Timeout} | 201%% {stop, Reason, State} (terminate/2 is called) 202%%-------------------------------------------------------------------- 203handle_info(Info, State) -> 204 d("handle_info -> entry with" 205 "~n Info: ~p", [Info]), 206 Reason = {received_unexpected_info, Info}, 207 {stop, Reason, State}. 208 209 210%%-------------------------------------------------------------------- 211%% Func: terminate/2 212%% Purpose: Shutdown the server 213%% Returns: any (ignored by gen_server) 214%%-------------------------------------------------------------------- 215terminate(_Reason, _State) -> 216 ok. 217 218 219%%---------------------------------------------------------------------- 220%% Func: code_change/3 221%% Purpose: Convert process state when code is changed 222%% Returns: {ok, NewState} 223%%---------------------------------------------------------------------- 224 225code_change(_Vsn, State, _Extra) -> 226 {ok, State}. 227 228 229%%%------------------------------------------------------------------- 230%%% Internal functions 231%%%------------------------------------------------------------------- 232 233handle_transport(Pid, 234 #megaco_receive_handle{encoding_mod = EM, 235 encoding_config = EC}, 236 {Event, SendHandle, Bin, Resend}) -> 237 Info = 238 case (catch EM:decode_message(EC, Bin)) of 239 {ok, MegMsg} -> 240 {message, MegMsg, Resend}; 241 Error -> 242 d("handle_transport -> decode failed" 243 "~n Error: ~p", [Error]), 244 {bad_message, Error, Bin} 245 end, 246 handle_transport(Pid, Event, SendHandle, Info); 247handle_transport(Pid, 248 #megaco_receive_handle{encoding_mod = EM, 249 encoding_config = EC}, 250 {Event, SendHandle, Bin}) -> 251 Info = 252 case (catch EM:decode_message(EC, Bin)) of 253 {ok, MegMsg} -> 254 {message, MegMsg}; 255 Error -> 256 d("handle_transport -> decode failed" 257 "~n Error: ~p", [Error]), 258 {bad_message, Error, Bin} 259 end, 260 handle_transport(Pid, Event, SendHandle, Info). 261 262handle_transport(Pid, Event, SendHandle, Info) -> 263 Pid ! {transport_event, {Event, SendHandle, Info}, self()}, 264 receive 265 {transport_reply, Reply, Pid} -> 266 d("handle_transport -> received reply" 267 "~n Reply: ~p", [Reply]), 268 Reply 269 after 10000 -> 270 receive 271 Any -> 272 d("handle_transport -> received crap after timeout" 273 "~n Any: ~p", [Any]), 274 exit({timeout, Any}) 275 after 0 -> 276 d("handle_transport -> timeout"), 277 exit(timeout) 278 end 279 end. 280 281 282%% This function is used to simulate incomming messages 283handle_incomming_message(Msg, 284 #megaco_receive_handle{encoding_mod = EM, 285 encoding_config = EC} = RH) -> 286 Self = self(), 287 case EM:encode_message(EC, Msg) of 288 {ok, Bin} -> 289 ProcessMessage = 290 fun() -> 291 megaco:process_received_message(RH, Self, Self, Bin) 292 end, 293 spawn(ProcessMessage), 294 ok; 295 Error -> 296 d("handle_incomming_message -> encode failed" 297 "~n Error: ~p", [Error]), 298 exit(Error) 299 end. 300 301 302%%------------------------------------------------------------------- 303 304call(Req) -> 305 call(Req, infinity). 306 307call(Req, Timeout) -> 308 case (catch gen_server:call(?SERVER, Req, Timeout)) of 309 {'EXIT', _} -> 310 {error, not_started}; 311 Res -> 312 Res 313 end. 314 315%% cast(Msg) -> 316%% cast(whereis(?SERVER), Msg). 317 318cast(Pid, Msg) -> 319 d("cast -> entry with" 320 "~n Pid: ~p" 321 "~n Msg: ~p", [Pid, Msg]), 322 case (catch gen_server:cast(Pid, Msg)) of 323 {'EXIT', Reason} -> 324 d("cast -> failed casting" 325 "~n Reason: ~p", [Reason]), 326 {error, not_started}; 327 Res -> 328 Res 329 end. 330 331 332%%------------------------------------------------------------------- 333 334d(F) -> 335 d(F, []). 336 337d(F, A) -> 338 print(F, A). 339 340 341print(F, A) -> 342 io:format("*** [~s] GENERIC TRANSPORT [~p] ***" 343 "~n " ++ F ++ "~n", 344 [?FTS(), self() | A]). 345 346