aboutsummaryrefslogblamecommitdiffstats
path: root/erts/emulator/test/socket_test_lib.erl
blob: 2ded82ae1385c24b67050a91033a4aafb9353cd0 (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,

         %% 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, {_Name, _Flags, Addr}} ->
            {ok, Addr};
        {error, _Reason} = ERROR ->
            ERROR
    end.
    
%%     case inet:getifaddrs() of
%%         {ok, IFL} ->
%%             which_addr(Domain, IFL);
%%         {error, Reason} ->
%%             ?FAIL({inet, getifaddrs, Reason})
%%     end.

%% which_addr(_Domain, []) ->
%%     ?FAIL(no_address);
%% which_addr(Domain, [{"lo" ++ _, _}|IFL]) ->
%%     which_addr(Domain, IFL);
%% which_addr(Domain, [{_Name, IFO}|IFL]) ->
%%     case which_addr2(Domain, IFO) of
%%         {ok, Addr} ->
%%             Addr;
%%         {error, no_address} ->
%%             which_addr(Domain, IFL)
%%     end;
%% which_addr(Domain, [_|IFL]) ->
%%     which_addr(Domain, IFL).

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


%% 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]) ->
    case which_local_host_info2(Domain, IFO) of
        {ok, {Flags, Addr}} ->
            {ok, {Name, Flags, Addr}};
        {error, _} ->
            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).



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

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

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


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