1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2000-2020. 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: Externalize/internalize Megaco/H.248 messages 24%%---------------------------------------------------------------------- 25 26-module(megaco_erl_dist_encoder). 27 28-behaviour(megaco_encoder). 29 30-export([encode_message/3, decode_message/3, 31 decode_mini_message/3, 32 33 encode_transaction/3, 34 encode_action_requests/3, 35 encode_action_request/3, 36 encode_command_request/3, 37 encode_action_reply/3 38 ]). 39-export([version_of/2]). 40 41%% Backward compatible funcs: 42-export([encode_message/2, decode_message/2]). 43 44 45-include("megaco_message_internal.hrl"). 46 47-define(MC_MOD, megaco_erl_dist_encoder_mc). 48 49 50%%---------------------------------------------------------------------- 51%% Convert a 'MegacoMessage' record into a binary 52%% Return {ok, DeepIoList} | {error, Reason} 53%%---------------------------------------------------------------------- 54 55encode_message(Config, 56 #'MegacoMessage'{mess = #'Message'{version = V}} = MegaMsg) -> 57 encode_message(Config, V, MegaMsg). 58 59%% <BACKWARD-COMPAT-CLAUSE> 60encode_message([{version3, _}|EC], Vsn, MegaMsg) -> 61 encode_message(EC, Vsn, MegaMsg); 62%% </BACKWARD-COMPAT-CLAUSE> 63 64encode_message([megaco_compressed|Config], Vsn, MegaMsg) 65 when is_record(MegaMsg, 'MegacoMessage') -> 66 {ok, erlang:term_to_binary(?MC_MOD:encode(MegaMsg, Vsn), Config)}; 67encode_message([{megaco_compressed, Mod}|Config], Vsn, MegaMsg) 68 when is_atom(Mod) and is_record(MegaMsg, 'MegacoMessage') -> 69 {ok, erlang:term_to_binary(Mod:encode(MegaMsg, Vsn), Config)}; 70encode_message(Config, _Vsn, MegaMsg) 71 when is_record(MegaMsg, 'MegacoMessage') -> 72 {ok, erlang:term_to_binary(MegaMsg, Config)}; 73encode_message(_Config, _Vsn, _MegaMsg) -> 74 {error, not_a_megaco_message}. 75 76 77%%---------------------------------------------------------------------- 78%% Convert a transaction record into a binary 79%% Return {ok, Bin} | {error, Reason} 80%%---------------------------------------------------------------------- 81 82%% <BACKWARD-COMPAT-CLAUSE> 83encode_transaction([{version3, _}|EC], Vsn, Trans) -> 84 encode_transaction(EC, Vsn, Trans); 85%% </BACKWARD-COMPAT-CLAUSE> 86 87encode_transaction([megaco_compressed|Config], _Vsn, Trans) -> 88 {ok, erlang:term_to_binary(?MC_MOD:encode(Trans), Config)}; 89encode_transaction([{megaco_compressed, Mod}|Config], _Vsn, Trans) -> 90 {ok, erlang:term_to_binary(Mod:encode(Trans), Config)}; 91encode_transaction(Config, _Vsn, Trans) -> 92 {ok, erlang:term_to_binary(Trans, Config)}. 93 94 95%%---------------------------------------------------------------------- 96%% Convert a list of ActionRequest record's into a binary 97%% Return {ok, Binary} | {error, Reason} 98%%---------------------------------------------------------------------- 99 100%% <BACKWARD-COMPAT-CLAUSE> 101encode_action_requests([{version3, _}|EC], Vsn, ActReqs) -> 102 encode_action_requests(EC, Vsn, ActReqs); 103%% </BACKWARD-COMPAT-CLAUSE> 104 105encode_action_requests([megaco_compressed|Config], Vsn, ActReqs0) 106 when is_list(ActReqs0) -> 107 ActReqs = [?MC_MOD:encode(AR, Vsn) || AR <- ActReqs0], 108 {ok, erlang:term_to_binary(ActReqs, Config)}; 109encode_action_requests([{megaco_compressed, Mod}|Config], Vsn, ActReqs0) 110 when is_list(ActReqs0) -> 111 ActReqs = [Mod:encode(AR, Vsn) || AR <- ActReqs0], 112 {ok, erlang:term_to_binary(ActReqs, Config)}; 113encode_action_requests(Config, _Vsn, ActReqs) 114 when is_list(ActReqs) -> 115 {ok, erlang:term_to_binary(ActReqs, Config)}. 116 117 118 119%%---------------------------------------------------------------------- 120%% Convert a ActionRequest record into a binary 121%% Return {ok, Binary} | {error, Reason} 122%%---------------------------------------------------------------------- 123 124%% <BACKWARD-COMPAT-CLAUSE> 125encode_action_request([{version3, _}|EC], Vsn, ActReq) -> 126 encode_action_request(EC, Vsn, ActReq); 127%% </BACKWARD-COMPAT-CLAUSE> 128 129encode_action_request([megaco_compressed|Config], Vsn, ActReq) 130 when is_tuple(ActReq) -> 131 {ok, erlang:term_to_binary(?MC_MOD:encode(ActReq, Vsn), Config)}; 132encode_action_request([{megaco_compressed, Mod}|Config], Vsn, ActReq) 133 when is_tuple(ActReq) -> 134 {ok, erlang:term_to_binary(Mod:encode(ActReq, Vsn), Config)}; 135encode_action_request(Config, _Vsn, ActReq) 136 when is_tuple(ActReq) -> 137 {ok, erlang:term_to_binary(ActReq, Config)}. 138 139 140 141%%---------------------------------------------------------------------- 142%% Convert a CommandRequest record into a binary 143%% Return {ok, DeepIoList} | {error, Reason} 144%%---------------------------------------------------------------------- 145 146%% <BACKWARD-COMPAT-CLAUSE> 147encode_command_request([{version3, _}|EC], Vsn, CmdReq) -> 148 encode_command_request(EC, Vsn, CmdReq); 149%% </BACKWARD-COMPAT-CLAUSE> 150 151encode_command_request([megaco_compressed|Config], Vsn, CmdReq) 152 when is_tuple(CmdReq) -> 153 {ok, erlang:term_to_binary(?MC_MOD:encode(CmdReq, Vsn), Config)}; 154encode_command_request([{megaco_compressed, Mod}|Config], Vsn, CmdReq) 155 when is_tuple(CmdReq) -> 156 {ok, erlang:term_to_binary(Mod:encode(CmdReq, Vsn), Config)}; 157encode_command_request(Config, _Vsn, CmdReq) 158 when is_tuple(CmdReq) -> 159 {ok, erlang:term_to_binary(CmdReq, Config)}. 160 161 162%%---------------------------------------------------------------------- 163%% Convert a action reply into a binary 164%% Return {ok, DeepIoList} | {error, Reason} 165%%---------------------------------------------------------------------- 166 167%% <BACKWARD-COMPAT-CLAUSE> 168encode_action_reply([{version3, _}|EC], Vsn, ActRep) -> 169 encode_action_reply(EC, Vsn, ActRep); 170%% </BACKWARD-COMPAT-CLAUSE> 171 172encode_action_reply([megaco_compressed|Config], Vsn, ActRep) 173 when is_tuple(ActRep) -> 174 {ok, erlang:term_to_binary(?MC_MOD:encode(ActRep, Vsn), Config)}; 175encode_action_reply([{megaco_compressed, Mod}|Config], Vsn, ActRep) 176 when is_tuple(ActRep) -> 177 {ok, erlang:term_to_binary(Mod:encode(ActRep, Vsn), Config)}; 178encode_action_reply(Config, _Vsn, ActRep) 179 when is_tuple(ActRep) -> 180 {ok, erlang:term_to_binary(ActRep, Config)}. 181 182 183%%---------------------------------------------------------------------- 184%% Get the megaco version of the message 185%% Return {ok, Version} | {error, Reason} 186%%---------------------------------------------------------------------- 187 188version_of(Config, Bin) when is_binary(Bin) -> 189 case decode_message(Config, 1, Bin) of 190 {ok, M} -> 191 V = (M#'MegacoMessage'.mess)#'Message'.version, 192 {ok, V}; 193 Error -> 194 Error 195 end. 196 197decode_message(Config, Bin) -> 198 decode_message(Config, 1, Bin). 199 200%% <BACKWARD-COMPAT-CLAUSE> 201decode_message([{version3, _}|EC], V, Bin) -> 202 decode_message(EC, V, Bin); 203%% </BACKWARD-COMPAT-CLAUSE> 204 205decode_message([megaco_compressed = MC|_Config], Vsn, Bin) -> 206 case catch erlang:binary_to_term(Bin) of 207 Msg when is_tuple(Msg) -> 208 case (?MC_MOD:decode(Msg, Vsn)) of 209 MegaMsg when is_record(MegaMsg, 'MegacoMessage') -> 210 {ok, dm(MegaMsg, MC, Vsn)}; 211 _ -> 212 {error, {bad_message, Msg}} 213 end; 214 {'EXIT', _Reason} -> 215 {error, bad_binary} 216 end; 217decode_message([{megaco_compressed, Mod} = MC|_Config], Vsn, Bin) 218 when is_atom(Mod) -> 219 case catch erlang:binary_to_term(Bin) of 220 Msg when is_tuple(Msg) -> 221 case (Mod:decode(Msg, Vsn)) of 222 MegaMsg when is_record(MegaMsg, 'MegacoMessage') -> 223 {ok, dm(MegaMsg, MC, Vsn)}; 224 _ -> 225 {error, {bad_message, Msg}} 226 end; 227 {'EXIT', _Reason} -> 228 {error, bad_binary} 229 end; 230decode_message(_Config, Vsn, Bin) -> 231 case catch erlang:binary_to_term(Bin) of 232 MegaMsg when is_record(MegaMsg, 'MegacoMessage') -> 233 {ok, dm(MegaMsg, undefined, Vsn)}; 234 {'EXIT', _Reason} -> 235 {error, bad_binary} 236 end. 237 238 239decode_mini_message(EC, Vsn, Bin) when is_binary(Bin) -> 240 decode_message(EC, Vsn, Bin). 241 242 243%% This crap is because the transactions or the action-requests 244%% might have been encoded separetely 245 246dm(#'MegacoMessage'{mess = Mess} = M, MC, Vsn) -> 247 #'Message'{messageBody = Body} = Mess, 248 case Body of 249 {transactions, Transactions} -> 250 Body2 = {transactions, dmt(Transactions, [], MC, Vsn)}, 251 Mess2 = Mess#'Message'{messageBody = Body2}, 252 M#'MegacoMessage'{mess = Mess2}; 253 _ -> 254 M 255 end. 256 257dmt([], Acc, _, _Vsn) -> 258 lists:reverse(Acc); 259dmt([Trans0|Transactions], Acc, MC, Vsn) when is_binary(Trans0) -> 260 Trans1 = erlang:binary_to_term(Trans0), 261 Trans2 = dmt1(Trans1, MC, Vsn), 262 dmt(Transactions, [Trans2|Acc], MC, Vsn); 263dmt([{Tag, Trans0}|Transactions], Acc, MC, Vsn) when is_binary(Trans0) -> 264 Trans1 = erlang:binary_to_term(Trans0), 265 Trans2 = dmt1(Trans1, MC, Vsn), 266 dmt(Transactions, [{Tag, Trans2}|Acc], MC, Vsn); 267dmt([{transactionRequest, 268 #'TransactionRequest'{actions = Acts0} = TR0}|Transactions], 269 Acc, MC, Vsn) 270 when is_binary(Acts0) -> 271 Acts1 = erlang:binary_to_term(Acts0), 272 Acts2 = dmt1(Acts1, MC, Vsn), 273 TR1 = TR0#'TransactionRequest'{actions = Acts2}, 274 dmt(Transactions, [{transactionRequest, TR1}|Acc], MC, Vsn); 275dmt([{transactionRequest, 276 #'TransactionRequest'{actions = Acts0} = TR0}|Transactions], 277 Acc, MC, Vsn) -> 278 Acts2 = [dmt2(AR, MC, Vsn) || AR <- Acts0], 279 TR1 = TR0#'TransactionRequest'{actions = Acts2}, 280 dmt(Transactions, [{transactionRequest, TR1}|Acc], MC, Vsn); 281dmt([Trans|Transactions], Acc, MC, Vsn) -> 282 dmt(Transactions, [Trans|Acc], MC, Vsn). 283 284dmt1(L, megaco_compressed, Vsn) when is_list(L) -> 285 [?MC_MOD:decode(E, Vsn) || E <- L]; 286dmt1(L, {megaco_compressed, Mod}, Vsn) when is_list(L) -> 287 [Mod:decode(E, Vsn) || E <- L]; 288dmt1(T, megaco_compressed, Vsn) when is_tuple(T) -> 289 ?MC_MOD:decode(T, Vsn); 290dmt1(T, {megaco_compressed, Mod}, Vsn) when is_tuple(T) -> 291 Mod:decode(T, Vsn); 292dmt1(Else, _, _Vsn) -> 293 Else. 294 295dmt2(Bin, MC, Vsn) when is_binary(Bin) -> 296 AR = erlang:binary_to_term(Bin), 297 dmt1(AR, MC, Vsn); 298dmt2(AR, _MC, _Vsn) -> 299 AR. 300 301 302