From 92e783d1098e99161401ab08cccd3a08356749cd Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 1 Apr 2012 19:52:01 +0200 Subject: rename sua_codec to generic xua_codec SUA/M3UA/M2UA/M2PA actaully all uses almost the same message format, so it makes sense to write one generic xua_codec and derive from that. The current SUA implementation didn't actually contain anything SUA specific, so we can just rename it and use xua_codec directly from the users. --- src/xua_codec.erl | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 src/xua_codec.erl (limited to 'src/xua_codec.erl') diff --git a/src/xua_codec.erl b/src/xua_codec.erl new file mode 100644 index 0000000..8da94a2 --- /dev/null +++ b/src/xua_codec.erl @@ -0,0 +1,92 @@ +% RFC 3868 SUA SCCP Adaption Layer coding / decoding + +% (C) 2012 by Harald Welte +% +% All Rights Reserved +% +% This program is free software; you can redistribute it and/or modify +% it under the terms of the GNU Affero General Public License as +% published by the Free Software Foundation; either version 3 of the +% License, or (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU Affero General Public License +% along with this program. If not, see . + +-module(xua_codec). +-author('Harald Welte '). +-include("xua.hrl"). + +-export([parse_msg/1, encode_msg/1, parse_xua_opts/1, encode_xua_opts/1]). + +parse_msg(DataBin) when is_binary(DataBin) -> + <> = DataBin, + RemainLen = MsgLen - 4, + OptList = parse_xua_opts(Remain), + #xua_msg{version = Version, msg_class = MsgClass, msg_type = MsgType, + payload = OptList}; +parse_msg(Data) when is_list(Data) -> + parse_msg(list_to_binary(Data)). + +parse_xua_opts(OptBin) when is_binary(OptBin) -> + parse_xua_opts(OptBin, []). + +parse_xua_opts(<<>>, OptList) when is_list(OptList) -> + OptList; +parse_xua_opts(OptBin, OptList) when is_binary(OptBin), is_list(OptList) -> + <> = OptBin, + Length = LengthIncHdr - 4, + PadLength = get_num_pad_bytes(Length), + %io:format("Tag ~w, LenInHdr ~w, Len ~w, PadLen ~w, Remain ~w(~p)~n", + % [Tag, LengthIncHdr, Length, PadLength, byte_size(Remain), Remain]), + <> = Remain, + % this is ridiculous, we cannot use "<>" as the last part would not match an + % empty binary <<>> anymore. Without the "0:PadLengh" this works + % perfectly fine. Now we need some complicated construct and check if + % the resulting list would be empty :(( + if + byte_size(PadNextOpts) > PadLength -> + <<0:PadLength/integer-unit:8, NextOpts/binary>> = PadNextOpts; + true -> + NextOpts = <<>> + end, + NewOpt = {Tag, {Length, Value}}, + parse_xua_opts(NextOpts, OptList ++ [NewOpt]). + + + +encode_msg(#xua_msg{version = Version, msg_class = MsgClass, + msg_type = MsgType, payload = OptList}) -> + OptBin = encode_xua_opts(OptList), + MsgLen = byte_size(OptBin) + 8, + <>. + +encode_xua_opts(OptList) when is_list(OptList) -> + encode_xua_opts(OptList, <<>>). + +encode_xua_opts([], Bin) -> + Bin; +encode_xua_opts([{Iei, Attr}|Tail], Bin) -> + OptBin = encode_xua_opt(Iei, Attr), + encode_xua_opts(Tail, <>). + +encode_xua_opt(Iei, {LenIn, Data}) when is_integer(Iei), is_binary(Data) -> + Length = LenIn + 4, + PadLen = get_num_pad_bytes(Length), + <>; +encode_xua_opt(Iei, Data) when is_integer(Iei), is_binary(Data) -> + Length = byte_size(Data) + 4, + PadLen = get_num_pad_bytes(Length), + <>. + +% compute the number of pad bits required after a binary parameter +get_num_pad_bytes(BinLenBytes) -> + case BinLenBytes rem 4 of + 0 -> 0; + Val -> 4 - Val + end. -- cgit v1.2.3