From 64e0dbd8f002d076f5d6c079f9166840c5fb17e3 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 7 Aug 2017 02:59:49 +0200 Subject: Simplify extraction of incoming Diameter messages in diameter_tcp Appending to a binary is efficient, so just append message fragments Only match out the length once per message since doing so for every packet from TCP causes the binary to be copied. --- lib/diameter/src/transport/diameter_tcp.erl | 78 ++++++++++------------------- 1 file changed, 26 insertions(+), 52 deletions(-) (limited to 'lib/diameter') diff --git a/lib/diameter/src/transport/diameter_tcp.erl b/lib/diameter/src/transport/diameter_tcp.erl index a2f393d5d4..e6168652de 100644 --- a/lib/diameter/src/transport/diameter_tcp.erl +++ b/lib/diameter/src/transport/diameter_tcp.erl @@ -87,8 +87,7 @@ module :: module() | undefined}). -type length() :: 0..16#FFFFFF. %% message length from Diameter header --type size() :: non_neg_integer(). %% accumulated binary size --type frag() :: {length(), size(), binary(), list(binary())} +-type frag() :: maybe_improper_list(length(), binary()) | binary(). -type connect_option() :: {raddr, inet:ip_address()} @@ -721,7 +720,7 @@ tls(accept, Sock, Opts) -> %% Receive packets until a full message is received, recv(Bin, #transport{frag = Head} = S) -> - case rcv(Head, Bin) of + case acc(Head, Bin) of {Msg, B} -> %% have a complete message ... message(recv, Msg, S#transport{frag = B}); Frag -> %% read more on the socket @@ -729,77 +728,52 @@ recv(Bin, #transport{frag = Head} = S) -> flush = false})) end. -%% rcv/2 +%% acc/2 -%% No previous fragment. -rcv(<<>>, Bin) -> - rcv(Bin); +%% Know how many bytes to extract. +acc([Len | Acc], Bin) -> + acc1(Len, <>); -%% Not even the first four bytes of the header. -rcv(Head, Bin) - when is_binary(Head) -> - rcv(<>); +%% Or not. +acc(Head, Bin) -> + acc(<>). -%% Or enough to know how many bytes to extract. -rcv({Len, N, Head, Acc}, Bin) -> - rcv(Len, N + size(Bin), Head, [Bin | Acc]). - -%% rcv/4 +%% acc1/3 %% Extract a message for which we have all bytes. -rcv(Len, N, Head, Acc) - when Len =< N -> - recv1(Len, bin(Head, Acc)); +acc1(Len, Bin) + when Len =< byte_size(Bin) -> + <> = Bin, + {Msg, Rest}; %% Wait for more packets. -rcv(Len, N, Head, Acc) -> - {Len, N, Head, Acc}. - -%% rcv/1 +acc1(Len, Bin) -> + [Len | Bin]. -%% Nothing left. -rcv(<<>> = Bin) -> - Bin; +%% acc/1 %% The Message Length isn't even sufficient for a header. Chances are %% things will go south from here but if we're lucky then the bytes we %% have extend to an intended message boundary and we can recover by %% simply receiving them. Make it so. -rcv(<<_:1/binary, Len:24, _/binary>> = Bin) +acc(<<_:1/binary, Len:24, _/binary>> = Bin) when Len < 20 -> {Bin, <<>>}; -%% Enough bytes to extract a message. -rcv(<<_:1/binary, Len:24, _/binary>> = Bin) - when Len =< size(Bin) -> - recv1(Len, Bin); - -%% Or not: wait for more packets. -rcv(<<_:1/binary, Len:24, _/binary>> = Head) -> - {Len, size(Head), Head, []}; +%% Know the message length. +acc(<<_:1/binary, Len:24, _/binary>> = Bin) -> + acc1(Len, Bin); %% Not even 4 bytes yet. -rcv(Head) -> - Head. - -%% recv1/2 - -recv1(Len, Bin) -> - <> = Bin, - {Msg, Rest}. - -%% bin/2 - -bin(Head, Acc) -> - list_to_binary([Head | lists:reverse(Acc)]). +acc(Bin) -> + Bin. %% bin/1 -bin({_, _, Head, Acc}) -> - bin(Head, Acc); +bin([_ | Bin]) -> + Bin; -bin(Bin) - when is_binary(Bin) -> +bin(Bin) -> Bin. %% flush/1 -- cgit v1.2.3