aboutsummaryrefslogblamecommitdiffstats
path: root/erts/emulator/test/socket_test_lib.erl
blob: 39cbf0c79fae28a5e286dd1a79e32fbb27905361 (plain) (tree)






















                                                                           

                          





                              


                             



                                                  
                            
 





                               

                                                                         




                                                                         















                                                                         

























                                                                         





                                                                         











































































                                                                           
                                




                                   



















                                                               




                                              




                                              


































































                                                                                  
                



                                                   
 




                                                                         







                                                                         
%%
%% %CopyrightBegin%
%% 
%% Copyright Ericsson AB 2018-2018. All Rights Reserved.
%% 
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%%     http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%% 
%% %CopyrightEnd%
%%

-module(socket_test_lib).

-export([
         pi/1, pi/2, pi/3,

         %% Time stuff
         timestamp/0,
         tdiff/2,
         formated_timestamp/0,
         format_timestamp/1,

         %% String and format
         f/2,

         %% Generic 'has support' test function(s)
         has_support_ipv6/0,

         which_local_host_info/1,
         which_local_addr/1,

         %% Skipping
         not_yet_implemented/0,
         skip/1
        ]).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

-define(FAIL(R), exit(R)).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

pi(Item) when is_atom(Item) ->
    pi(self(), Item).

pi(Pid, Item) when is_pid(Pid) andalso is_atom(Item) ->
    {Item, Info} = process_info(Pid, Item),
    Info;
pi(Node, Pid) when is_pid(Pid) ->
    rpc:call(Node, erlang, process_info, [Pid]).

pi(Node, Pid, Item) when is_pid(Pid) andalso is_atom(Item) ->
    rpc:call(Node, erlang, process_info, [Pid, Item]).



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

timestamp() ->
    os:timestamp().


tdiff({A1, B1, C1} = _T1x, {A2, B2, C2} = _T2x) ->
    T1 = A1*1000000000+B1*1000+(C1 div 1000), 
    T2 = A2*1000000000+B2*1000+(C2 div 1000), 
    T2 - T1.


formated_timestamp() ->
    format_timestamp(os:timestamp()).

format_timestamp({_N1, _N2, _N3} = TS) ->
    {_Date, Time}   = calendar:now_to_local_time(TS),
    %% {YYYY,MM,DD}   = Date,
    {Hour,Min,Sec} = Time,
    %% FormatTS = 
    %%     io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w.~w",
    %%                   [YYYY, MM, DD, Hour, Min, Sec, N3]),  
    FormatTS = io_lib:format("~.2.0w:~.2.0w:~.2.0w", [Hour, Min, Sec]),  
    lists:flatten(FormatTS).

   
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

f(F, A) ->
    lists:flatten(io_lib:format(F, A)).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

has_support_ipv6() ->
    case socket:supports(ipv6) of
        true ->
            ok;
        false ->
            skip("IPv6 Not Supported")
    end,
    Domain = inet6,
    LocalAddr =
        case which_local_addr(Domain) of
            {ok, Addr} ->
                Addr;
            {error, R1} ->
                skip(f("Local Address eval failed: ~p", [R1]))
        end,
    ServerSock =
        case socket:open(Domain, dgram, udp) of
            {ok, SS} ->
                SS;
            {error, R2} ->
                skip(f("(server) socket open failed: ~p", [R2]))
        end,
    LocalSA = #{family => Domain, addr => LocalAddr},
    ServerPort =
        case socket:bind(ServerSock, LocalSA) of
            {ok, P1} ->
                P1;
            {error, R3} ->
                socket:close(ServerSock),
                skip(f("(server) socket bind failed: ~p", [R3]))
        end,
    ServerSA = LocalSA#{port => ServerPort},
    ClientSock =
        case socket:open(Domain, dgram, udp) of
            {ok, CS} ->
                CS;
            {error, R4} ->
                skip(f("(client) socket open failed: ~p", [R4]))
        end,
    case socket:bind(ClientSock, LocalSA) of
        {ok, _} ->
            ok;
        {error, R5} ->
            socket:close(ServerSock),
            socket:close(ClientSock),
            skip(f("(client) socket bind failed: ~p", [R5]))
    end,
    case socket:sendto(ClientSock, <<"hejsan">>, ServerSA) of
        ok ->
            ok;
        {error, R6} ->
            socket:close(ServerSock),
            socket:close(ClientSock),
            skip(f("failed socket sendto test: ~p", [R6]))
    end,
    case socket:recvfrom(ServerSock) of
        {ok, {_, <<"hejsan">>}} ->
            socket:close(ServerSock),
            socket:close(ClientSock),
            ok;
        {error, R7} ->
            socket:close(ServerSock),
            socket:close(ClientSock),
            skip(f("failed socket recvfrom test: ~p", [R7]))
   end.
            
            


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% This gets the local address (not {127, _} or {0, ...} or {16#fe80, ...})
%% We should really implement this using the (new) net module,
%% but until that gets the necessary functionality...
which_local_addr(Domain) ->
    case which_local_host_info(Domain) of
        {ok, #{addr := Addr}} ->
            {ok, Addr};
        {error, _Reason} = ERROR ->
            ERROR
    end.
    

%% Returns the interface (name), flags and address (not 127...)
%% of the local host.
which_local_host_info(Domain) ->
    case inet:getifaddrs() of
        {ok, IFL} ->
            which_local_host_info(Domain, IFL);
        {error, _} = ERROR ->
            ERROR
    end.

which_local_host_info(_Domain, []) ->
    {error, no_address};
which_local_host_info(Domain, [{"lo" ++ _, _}|IFL]) ->
    which_local_host_info(Domain, IFL);
which_local_host_info(Domain, [{"docker" ++ _, _}|IFL]) ->
    which_local_host_info(Domain, IFL);
which_local_host_info(Domain, [{"br-" ++ _, _}|IFL]) ->
    which_local_host_info(Domain, IFL);
which_local_host_info(Domain, [{Name, IFO}|IFL]) ->
    try which_local_host_info2(Domain, IFO) of
        Info ->
            {ok, Info#{name => Name}}
    catch
        throw:_:_ ->
            which_local_host_info(Domain, IFL)
    end;
which_local_host_info(Domain, [_|IFL]) ->
    which_local_host_info(Domain, IFL).

%% which_local_host_info2(Domain, IFO) ->
%%     case lists:keysearch(flags, 1, IFO) of
%%         {value, {flags, Flags}} ->
%%             which_local_host_info2(Domain, IFO, Flags);
%%         false ->
%%             {error, no_flags}
%%     end.


%% which_local_host_info2(_Domain, [], _Flags) ->
%%     {error, no_address};
%% which_local_host_info2(inet = _Domain, [{addr, Addr}|_IFO], Flags)
%%   when (size(Addr) =:= 4) andalso (element(1, Addr) =/= 127) ->
%%     {ok, {Flags, Addr}};
%% which_local_host_info2(inet6 = _Domain, [{addr, Addr}|_IFO], Flags)
%%   when (size(Addr) =:= 8) andalso 
%%        (element(1, Addr) =/= 0) andalso
%%        (element(1, Addr) =/= 16#fe80) ->
%%     {ok, {Flags, Addr}};
%% which_local_host_info2(Domain, [_|IFO], Flags) ->
%%     which_local_host_info2(Domain, IFO, Flags).

%% foo(Info, inet = Domain, IFO) ->
%%     foo(Info, Domain, IFO, [flags, addr, netmask, broadaddr, hwaddr]);
%% foo(Info, inet6 = Domain, IFO) ->
%%     foo(Info, Domain, IFO, [flags, addr, netmask, hwaddr]).

which_local_host_info2(inet = _Domain, IFO) ->
    Addr      = which_local_host_info3(addr,  IFO,
                                       fun({A, _, _, _}) when (A =/= 127) -> true;
                                          (_) -> false
                                       end),
    NetMask   = which_local_host_info3(netmask,  IFO,
                                       fun({_, _, _, _}) -> true;
                                          (_) -> false
                                       end),
    BroadAddr = which_local_host_info3(broadaddr,  IFO,
                                       fun({_, _, _, _}) -> true;
                                          (_) -> false
                                       end),
    Flags     = which_local_host_info3(flags, IFO, fun(_) -> true end),
    #{flags     => Flags,
      addr      => Addr,
      broadaddr => BroadAddr,
      netmask   => NetMask};
which_local_host_info2(inet6 = _Domain, IFO) ->
    Addr    = which_local_host_info3(addr,  IFO,
                                     fun({A, _, _, _, _, _, _, _}) 
                                           when (A =/= 0) andalso 
                                                (A =/= 16#fe80) -> true;
                                        (_) -> false
                                     end),
    NetMask = which_local_host_info3(netmask,  IFO,
                                       fun({_, _, _, _, _, _, _, _}) -> true;
                                          (_) -> false
                                       end),
    Flags   = which_local_host_info3(flags, IFO, fun(_) -> true end),
    #{flags   => Flags,
      addr    => Addr,
      netmask => NetMask}.

which_local_host_info3(_Key, [], _) ->
    throw({error, no_address});
which_local_host_info3(Key, [{Key, Val}|IFO], Check) ->
    case Check(Val) of
        true ->
            Val;
        false ->
            which_local_host_info3(Key, IFO, Check)
    end;
which_local_host_info3(Key, [_|IFO], Check) ->
    which_local_host_info3(Key, IFO, Check).




%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

not_yet_implemented() ->
    skip("not yet implemented").

skip(Reason) ->
    throw({skip, Reason}).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%