%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2010-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. %% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. %% %% %CopyrightEnd% %% -module(diameter_lib). -export([report/2, info_report/2, error_report/2, warning_report/2, now_diff/1, time/1, eval/1, ip4address/1, ip6address/1, ipaddr/1, spawn_opts/2, wait/1, fold_tuple/3]). -include("diameter_internal.hrl"). %% --------------------------------------------------------------------------- %% # info_report(Reason, MFA) %% %% Input: Reason = Arbitrary term indicating the reason for the report. %% MFA = {Module, Function, Args} to report. %% %% Output: true %% --------------------------------------------------------------------------- report(Reason, MFA) -> info_report(Reason, MFA). info_report(Reason, {M,F,A}) -> error_logger:info_report(" Reason: ~p~n" " Pid: ~p~n" " Node: ~p~n" " Module: ~p~n" " Function: ~p~n" "Arguments: ~p~n", [Reason, self(), node(), M, F, A]). %%% --------------------------------------------------------------------------- %%% # error_report(Reason, MFA) %%% # warning_report(Reason, MFA) %%% %%% Output: false %%% --------------------------------------------------------------------------- error_report(Reason, MFA) -> report(fun error_logger:error_report/1, Reason, MFA). warning_report(Reason, MFA) -> report(fun error_logger:warning_report/1, Reason, MFA). report(Fun, Reason, MFA) -> Fun([{reason, Reason}, {who, self()}, {where, node()}, {what, MFA}]), false. %%% --------------------------------------------------------------------------- %%% # now_diff(Time) %%% %%% Description: Return timer:now_diff(now(), Time) as an {H, M, S, MicroS} %%% tuple instead of as integer microseconds. %%% --------------------------------------------------------------------------- now_diff({_,_,_} = Time) -> time(timer:now_diff(erlang:now(), Time)). %%% --------------------------------------------------------------------------- %%% # time(Time) %%% %%% Input: Time = {MegaSec, Sec, MicroSec} %%% | MicroSec %%% %%% Output: {H, M, S, MicroS} %%% --------------------------------------------------------------------------- time({_,_,_} = Time) -> %% time of day %% 24 hours = 24*60*60*1000000 = 86400000000 microsec time(timer:now_diff(Time, {0,0,0}) rem 86400000000); time(Micro) -> %% elapsed time Seconds = Micro div 1000000, H = Seconds div 3600, M = (Seconds rem 3600) div 60, S = Seconds rem 60, {H, M, S, Micro rem 1000000}. %%% --------------------------------------------------------------------------- %%% # eval(Func) %%% --------------------------------------------------------------------------- eval({M,F,A}) -> apply(M,F,A); eval([{M,F,A} | X]) -> apply(M, F, X ++ A); eval([[F|A] | X]) -> eval([F | X ++ A]); eval([F|A]) -> apply(F,A); eval({F}) -> eval(F); eval(F) -> F(). %%% --------------------------------------------------------------------------- %%% # ip4address(Addr) %%% %%% Input: string() (eg. "10.0.0.1") %%% | list of integer() %%% | tuple of integer() %%% %%% Output: {_,_,_,_} of integer %%% %%% Exceptions: error: {invalid_address, Addr, erlang:get_stacktrace()} %%% --------------------------------------------------------------------------- ip4address([_,_,_,_] = Addr) -> %% Length 4 string can't be an address. ipaddr(list_to_tuple(Addr)); %% Be brutal. ip4address(Addr) -> try {_,_,_,_} = ipaddr(Addr) catch error: _ -> erlang:error({invalid_address, Addr, ?STACK}) end. %%% --------------------------------------------------------------------------- %%% # ip6address(Addr) %%% %%% Input: string() (eg. "1080::8:800:200C:417A") %%% | list of integer() %%% | tuple of integer() %%% %%% Output: {_,_,_,_,_,_,_,_} of integer %%% %%% Exceptions: error: {invalid_address, Addr, erlang:get_stacktrace()} %%% --------------------------------------------------------------------------- ip6address([_,_,_,_,_,_,_,_] = Addr) -> %% Length 8 string can't be an address. ipaddr(list_to_tuple(Addr)); %% Be brutal. ip6address(Addr) -> try {_,_,_,_,_,_,_,_} = ipaddr(Addr) catch error: _ -> erlang:error({invalid_address, Addr, ?STACK}) end. %%% --------------------------------------------------------------------------- %%% # ipaddr(Addr) %%% %%% Input: string() | tuple of integer() %%% %%% Output: {_,_,_,_} | {_,_,_,_,_,_,_,_} %%% %%% Exceptions: error: {invalid_address, erlang:get_stacktrace()} %%% --------------------------------------------------------------------------- -spec ipaddr(string() | tuple()) -> inet:ip_address(). %% Don't convert lists of integers since a length 8 list like %% [$1,$0,$.,$0,$.,$0,$.,$1] is ambiguous: is it "10.0.0.1" or %% "49:48:46:48:46:48:46:49"? %% %% RFC 2373 defines the format parsed for v6 addresses. %% Be brutal. ipaddr(Addr) -> try ip(Addr) catch error: _ -> erlang:error({invalid_address, ?STACK}) end. %% Already a tuple: ensure non-negative integers of the right size. ip(T) when size(T) == 4; size(T) == 8 -> Bs = 2*size(T), [] = lists:filter(fun(N) when 0 =< N -> 0 < N bsr Bs end, tuple_to_list(T)), T; %% Or not: convert from '.'/':'-separated decimal/hex. ip(Addr) -> {ok, A} = inet_parse:address(Addr), %% documented in inet(3) A. %%% --------------------------------------------------------------------------- %%% # spawn_opts(Type, Opts) %%% --------------------------------------------------------------------------- %% TODO: config variables. spawn_opts(server, Opts) -> opts(75000, Opts); spawn_opts(worker, Opts) -> opts(5000, Opts). opts(HeapSize, Opts) -> [{min_heap_size, HeapSize} | lists:keydelete(min_heap_size, 1, Opts)]. %%% --------------------------------------------------------------------------- %%% # wait(MRefs) %%% --------------------------------------------------------------------------- wait(L) -> w([erlang:monitor(process, P) || P <- L]). w([]) -> ok; w(L) -> receive {'DOWN', MRef, process, _, _} -> w(lists:delete(MRef, L)) end. %%% --------------------------------------------------------------------------- %%% # fold_tuple(N, T0, T) %%% --------------------------------------------------------------------------- %% Replace fields in T0 by those of T starting at index N, unless the %% new value is 'undefined'. %% %% eg. fold_tuple(2, Hdr, #diameter_header{end_to_end_id = 42}) fold_tuple(_, T, undefined) -> T; fold_tuple(N, T0, T) -> element(2, lists:foldl(fun(X, {M,_} = A) -> {M+1, ft(X, A)} end, {N, T0}, lists:nthtail(N-1, tuple_to_list(T)))). ft(undefined, T) -> T; ft(X, {N, T}) -> setelement(N, T, X).