summaryrefslogtreecommitdiffstats
path: root/src/xua_codec.erl
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2012-04-01 19:52:01 +0200
committerHarald Welte <laforge@gnumonks.org>2012-04-01 19:54:20 +0200
commit92e783d1098e99161401ab08cccd3a08356749cd (patch)
tree514413efb1a8bb953169f1d6d8c57e3280a03eb7 /src/xua_codec.erl
parent7aff8fb62be1422016ec92df5d1cbec0c738b75c (diff)
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.
Diffstat (limited to 'src/xua_codec.erl')
-rw-r--r--src/xua_codec.erl92
1 files changed, 92 insertions, 0 deletions
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 <laforge@gnumonks.org>
+%
+% 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 <http://www.gnu.org/licenses/>.
+
+-module(xua_codec).
+-author('Harald Welte <laforge@gnumonks.org>').
+-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) ->
+ <<Version:8, _Reserved:8, MsgClass:8, MsgType:8, MsgLen:32/big, Remain/binary>> = 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) ->
+ <<Tag:16/big, LengthIncHdr:16/big, Remain/binary>> = 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]),
+ <<Value:Length/binary, PadNextOpts/binary>> = Remain,
+ % this is ridiculous, we cannot use "<<Value:Length/binary,
+ % 0:PadLength, Remain/binary>>" 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,
+ <<Version:8, 0:8, MsgClass:8, MsgType:8, MsgLen:32/big, OptBin/binary>>.
+
+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, <<Bin/binary, OptBin/binary>>).
+
+encode_xua_opt(Iei, {LenIn, Data}) when is_integer(Iei), is_binary(Data) ->
+ Length = LenIn + 4,
+ PadLen = get_num_pad_bytes(Length),
+ <<Iei:16/big, Length:16/big, Data/binary, 0:PadLen/integer-unit:8>>;
+encode_xua_opt(Iei, Data) when is_integer(Iei), is_binary(Data) ->
+ Length = byte_size(Data) + 4,
+ PadLen = get_num_pad_bytes(Length),
+ <<Iei:16/big, Length:16/big, Data/binary, 0:PadLen/integer-unit:8>>.
+
+% 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.