From e39e25d84405e13ca0ce476e3ba473510e5548de Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 4 Jul 2018 15:18:18 +0200 Subject: [socket-nif] Fixed (dgram) recv Fixed handling of recvfrom (used by dgram sockets). Had forgot to do select(read) when we got block from the call to recvfrom. Argh! Also updated the (simple) test server and client to to be able to use udp (dgram+udp). OTP-14831 --- lib/kernel/test/Makefile | 1 + lib/kernel/test/socket_client.erl | 252 ++++++++++++++++++++++++++------------ lib/kernel/test/socket_lib.erl | 129 +++++++++++++++++++ lib/kernel/test/socket_server.erl | 237 +++++++++++++++++++++++------------ 4 files changed, 462 insertions(+), 157 deletions(-) create mode 100644 lib/kernel/test/socket_lib.erl (limited to 'lib') diff --git a/lib/kernel/test/Makefile b/lib/kernel/test/Makefile index 07e7922d3d..051fac25af 100644 --- a/lib/kernel/test/Makefile +++ b/lib/kernel/test/Makefile @@ -25,6 +25,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk # ---------------------------------------------------- SOCKET_MODULES = \ + socket_lib \ socket_server \ socket_client diff --git a/lib/kernel/test/socket_client.erl b/lib/kernel/test/socket_client.erl index a284777046..0b570e1f71 100644 --- a/lib/kernel/test/socket_client.erl +++ b/lib/kernel/test/socket_client.erl @@ -1,17 +1,34 @@ -%%%------------------------------------------------------------------- -%%% @author Micael Karlberg -%%% @copyright (C) 2018, Micael Karlberg -%%% @doc -%%% -%%% @end -%%% Created : 27 Jun 2018 by Micael Karlberg -%%%------------------------------------------------------------------- +%% +%% %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_client). --export([start/1]). +-export([ + start/1, + start_tcp/1, start_tcp/2, + start_udp/1, start_udp/2 + ]). + +-define(LIB, socket_lib). --define(REQ, 0). --define(REP, 1). +-record(client, {socket, type, dest, msg_id = 1}). start(Port) -> start_tcp(Port). @@ -19,22 +36,77 @@ start(Port) -> start_tcp(Port) -> start(inet, stream, tcp, Port). +start_tcp(Addr, Port) when (size(Addr) =:= 4) -> + start(inet, stream, tcp, Addr, Port); +start_tcp(Addr, Port) when (size(Addr) =:= 8) -> + start(inet6, stream, tcp, Addr, Port). + + +start_udp(Port) -> + start(inet, dgram, udp, Port). + +start_udp(Addr, Port) when (size(Addr) =:= 4) -> + start(inet, dgram, udp, Addr, Port); +start_udp(Addr, Port) when (size(Addr) =:= 8) -> + start(inet6, dgram, udp, Addr, Port). + + start(Domain, Type, Proto, Port) -> + start(Domain, Type, Proto, which_addr(Domain), Port). + +start(Domain, Type, Proto, Addr, Port) -> + put(sname, "starter"), + SA = #{family => Domain, + addr => Addr, + port => Port}, + do_start(Domain, Type, Proto, SA). + +do_start(Domain, stream = Type, Proto, SA) -> try do_init(Domain, Type, Proto) of Sock -> - connect(Sock, Domain, Port), + connect(Sock, SA), + i("connected: " + "~n From: ~p" + "~n To: ~p", + [ + case socket:sockname(Sock) of + {ok, Name} -> Name; + {error, _} = NE -> NE + end, + case socket:peername(Sock) of + {ok, Name} -> Name; + {error, _} = PE -> PE + end + ]), %% Give the server some time... - p("wait some", []), - %% sleep(5000), + i("wait some", []), + ?LIB:sleep(5000), %% ok = socket:close(Sock), - send_loop(Sock) + send_loop(#client{socket = Sock, + type = Type}) + catch + throw:E -> + e("Failed initiate: " + "~n Error: ~p", [E]) + end; +do_start(Domain, dgram = Type, Proto, SA) -> + try do_init(Domain, Type, Proto) of + Sock -> + %% Give the server some time... + i("wait some", []), + ?LIB:sleep(5000), + %% ok = socket:close(Sock), + send_loop(#client{socket = Sock, + type = Type, + dest = SA}) catch throw:E -> e("Failed initiate: " "~n Error: ~p", [E]) end. -do_init(Domain, Type, Proto) -> + +do_init(Domain, stream = Type, Proto) -> i("try (socket) open"), Sock = case socket:open(Domain, Type, Proto) of {ok, S} -> @@ -48,8 +120,23 @@ do_init(Domain, Type, Proto) -> Sock; {error, BReason} -> throw({bind, BReason}) + end; +do_init(Domain, dgram = Type, Proto) -> + i("try (socket) open"), + Sock = case socket:open(Domain, Type, Proto) of + {ok, S} -> + S; + {error, OReason} -> + throw({open, OReason}) + end, + case socket:bind(Sock, any) of + {ok, _} -> + Sock; + {error, BReason} -> + throw({bind, BReason}) end. + which_addr(Domain) -> Iflist = case inet:getifaddrs() of {ok, IFL} -> @@ -60,16 +147,11 @@ which_addr(Domain) -> which_addr(Domain, Iflist). -connect(Sock, Domain, Port) -> - Addr = which_addr(Domain), - SA = #{family => Domain, - addr => Addr, - port => Port}, +connect(Sock, SA) -> i("try (socket) connect to:" "~n ~p", [SA]), case socket:connect(Sock, SA) of ok -> - i("connected"), ok; {error, Reason} -> e("connect failure: " @@ -78,22 +160,23 @@ connect(Sock, Domain, Port) -> end. -send_loop(Sock) -> - send_loop(Sock, 1). - -send_loop(Sock, N) when (N =< 10) -> +send_loop(#client{msg_id = N} = C) when (N =< 10) -> i("try send request ~w", [N]), - Req = enc_req_msg(N, "hejsan"), - case socket:send(Sock, Req) of + Req = ?LIB:enc_req_msg(N, "hejsan"), + case send(C, Req) of ok -> i("request ~w sent - now try read answer", [N]), - case socket:recv(Sock, 0) of - {ok, Msg} -> - i("received ~w bytes of data", [size(Msg)]), - case dec_msg(Msg) of + case recv(C) of + {ok, {Source, Msg}} -> + i("received ~w bytes of data~s", + [size(Msg), case Source of + undefined -> ""; + _ -> ?LIB:f(" from:~n ~p", [Source]) + end]), + case ?LIB:dec_msg(Msg) of {reply, N, Reply} -> i("received reply ~w: ~p", [N, Reply]), - send_loop(Sock, N+1) + send_loop(C#client{msg_id = N+1}) end; {error, RReason} -> e("Failed recv response for request ~w: " @@ -105,7 +188,7 @@ send_loop(Sock, N) when (N =< 10) -> "~n ~p", [SReason]), exit({failed_send, SReason}) end; -send_loop(Sock, _N) -> +send_loop(#client{socket = Sock}) -> i("we are done - close the socket when: " "~n ~p", [socket:info()]), ok = socket:close(Sock), @@ -113,6 +196,25 @@ send_loop(Sock, _N) -> "~n ~p", [socket:info()]). +send(#client{socket = Sock, type = stream}, Msg) -> + socket:send(Sock, Msg); +send(#client{socket = Sock, type = dgram, dest = Dest}, Msg) -> + %% i("try send to: " + %% "~n ~p", [Dest]), + %% ok = socket:setopt(Sock, otp, debug, true), + socket:sendto(Sock, Msg, Dest). + +recv(#client{socket = Sock, type = stream}) -> + case socket:recv(Sock) of + {ok, Msg} -> + {ok, {undefined, Msg}}; + {error, _} = ERROR -> + ERROR + end; +recv(#client{socket = Sock, type = dgram}) -> + socket:recvfrom(Sock). + + which_addr(_Domain, []) -> throw(no_address); which_addr(Domain, [{Name, IFO}|_IFL]) when (Name =/= "lo") -> @@ -130,68 +232,66 @@ which_addr2(Domain, [_|IFO]) -> %% --- -enc_req_msg(N, Data) -> - enc_msg(?REQ, N, Data). +%% enc_req_msg(N, Data) -> +%% enc_msg(?REQ, N, Data). -enc_rep_msg(N, Data) -> - enc_msg(?REP, N, Data). +%% enc_rep_msg(N, Data) -> +%% enc_msg(?REP, N, Data). -enc_msg(Type, N, Data) when is_list(Data) -> - enc_msg(Type, N, list_to_binary(Data)); -enc_msg(Type, N, Data) - when is_integer(Type) andalso is_integer(N) andalso is_binary(Data) -> - <>. +%% enc_msg(Type, N, Data) when is_list(Data) -> +%% enc_msg(Type, N, list_to_binary(Data)); +%% enc_msg(Type, N, Data) +%% when is_integer(Type) andalso is_integer(N) andalso is_binary(Data) -> +%% <>. -dec_msg(<>) -> - {request, N, Data}; -dec_msg(<>) -> - {reply, N, Data}. +%% dec_msg(<>) -> +%% {request, N, Data}; +%% dec_msg(<>) -> +%% {reply, N, Data}. %% --- -sleep(T) -> - receive after T -> ok end. +%% sleep(T) -> +%% receive after T -> ok end. %% --- -formated_timestamp() -> - format_timestamp(os:timestamp()). +%% formated_timestamp() -> +%% format_timestamp(os:timestamp()). -format_timestamp(Now) -> - N2T = fun(N) -> calendar:now_to_local_time(N) end, - format_timestamp(Now, N2T, true). +%% format_timestamp(Now) -> +%% N2T = fun(N) -> calendar:now_to_local_time(N) end, +%% format_timestamp(Now, N2T, true). -format_timestamp({_N1, _N2, N3} = N, N2T, true) -> - FormatExtra = ".~.2.0w", - ArgsExtra = [N3 div 10000], - format_timestamp(N, N2T, FormatExtra, ArgsExtra); -format_timestamp({_N1, _N2, _N3} = N, N2T, false) -> - FormatExtra = "", - ArgsExtra = [], - format_timestamp(N, N2T, FormatExtra, ArgsExtra). +%% format_timestamp({_N1, _N2, N3} = N, N2T, true) -> +%% FormatExtra = ".~.2.0w", +%% ArgsExtra = [N3 div 10000], +%% format_timestamp(N, N2T, FormatExtra, ArgsExtra); +%% format_timestamp({_N1, _N2, _N3} = N, N2T, false) -> +%% FormatExtra = "", +%% ArgsExtra = [], +%% format_timestamp(N, N2T, FormatExtra, ArgsExtra). -format_timestamp(N, N2T, FormatExtra, ArgsExtra) -> - {Date, Time} = N2T(N), - {YYYY,MM,DD} = Date, - {Hour,Min,Sec} = Time, - FormatDate = - io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w" ++ FormatExtra, - [YYYY, MM, DD, Hour, Min, Sec] ++ ArgsExtra), - lists:flatten(FormatDate). +%% format_timestamp(N, N2T, FormatExtra, ArgsExtra) -> +%% {Date, Time} = N2T(N), +%% {YYYY,MM,DD} = Date, +%% {Hour,Min,Sec} = Time, +%% FormatDate = +%% io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w" ++ FormatExtra, +%% [YYYY, MM, DD, Hour, Min, Sec] ++ ArgsExtra), +%% lists:flatten(FormatDate). %% --- e(F, A) -> - p(" " ++ F, A). + ?LIB:e(F, A). i(F) -> - i(F, []). + ?LIB:i(F). + i(F, A) -> - p("*** " ++ F, A). - -p(F, A) -> - io:format("[client,~p][~s] " ++ F ++ "~n", [self(),formated_timestamp()|A]). + ?LIB:i(F, A). diff --git a/lib/kernel/test/socket_lib.erl b/lib/kernel/test/socket_lib.erl new file mode 100644 index 0000000000..0eed81d61a --- /dev/null +++ b/lib/kernel/test/socket_lib.erl @@ -0,0 +1,129 @@ +%% +%% %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_lib). + +-export([ + sleep/1, + enc_req_msg/2, enc_rep_msg/2, + enc_msg/3, dec_msg/1, + request/3, reply/4, + f/2, + i/1, i/2, + e/2 + ]). + + +-define(REQ, 0). +-define(REP, 1). + + +%% --- + +sleep(T) -> + receive after T -> ok end. + + +%% --- + +enc_req_msg(N, Data) -> + enc_msg(?REQ, N, Data). + +enc_rep_msg(N, Data) -> + enc_msg(?REP, N, Data). + +enc_msg(Type, N, Data) when is_list(Data) -> + enc_msg(Type, N, list_to_binary(Data)); +enc_msg(Type, N, Data) + when is_integer(Type) andalso is_integer(N) andalso is_binary(Data) -> + <>. + +dec_msg(<>) -> + {request, N, Data}; +dec_msg(<>) -> + {reply, N, Data}. + + +%% --- + +request(Tag, Pid, Request) -> + Ref = make_ref(), + Pid ! {Tag, self(), Ref, Request}, + receive + {Tag, Pid, Ref, Reply} -> + Reply + end. + +reply(Tag, Pid, Ref, Reply) -> + Pid ! {Tag, self(), Ref, Reply}. + + +%% --- + +f(F, A) -> + lists:flatten(io_lib:format(F, A)). + + +%% --- + +e(F, A) -> + p(" " ++ F, A). + +i(F) -> + i(F, []). +i(F, A) -> + p("*** " ++ F, A). + +p(F, A) -> + p(get(sname), F, A). + +p(SName, F, A) -> + io:format("[~s,~p][~s] " ++ F ++ "~n", + [SName,self(),formated_timestamp()|A]). + + +%% --- + +formated_timestamp() -> + format_timestamp(os:timestamp()). + +format_timestamp(Now) -> + N2T = fun(N) -> calendar:now_to_local_time(N) end, + format_timestamp(Now, N2T, true). + +format_timestamp({_N1, _N2, N3} = N, N2T, true) -> + FormatExtra = ".~.2.0w", + ArgsExtra = [N3 div 10000], + format_timestamp(N, N2T, FormatExtra, ArgsExtra); +format_timestamp({_N1, _N2, _N3} = N, N2T, false) -> + FormatExtra = "", + ArgsExtra = [], + format_timestamp(N, N2T, FormatExtra, ArgsExtra). + +format_timestamp(N, N2T, FormatExtra, ArgsExtra) -> + {Date, Time} = N2T(N), + {YYYY,MM,DD} = Date, + {Hour,Min,Sec} = Time, + FormatDate = + io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w" ++ FormatExtra, + [YYYY, MM, DD, Hour, Min, Sec] ++ ArgsExtra), + lists:flatten(FormatDate). + + diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index dde605b624..702f040434 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -1,21 +1,34 @@ -%%%------------------------------------------------------------------- -%%% @author Micael Karlberg -%%% @copyright (C) 2018, Micael Karlberg -%%% @doc -%%% -%%% @end -%%% Created : 27 Jun 2018 by Micael Karlberg -%%%------------------------------------------------------------------- +%% +%% %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_server). --export([start/0]). +-export([start/0, + start_tcp/0, + start_udp/0]). --define(REQ, 0). --define(REP, 1). +-define(LIB, socket_lib). --record(manager, {acceptor, handler_id, handlers}). +-record(manager, {acceptor, handler_id, handlers}). -record(acceptor, {socket, manager}). --record(handler, {socket, manager}). +-record(handler, {socket, type, manager}). start() -> start_tcp(). @@ -23,6 +36,9 @@ start() -> start_tcp() -> start(inet, stream, tcp). +start_udp() -> + start(inet, dgram, udp). + start(Domain, Type, Proto) -> put(sname, "starter"), i("try start manager"), @@ -51,13 +67,13 @@ manager_stop(Pid, Reason) -> manager_request(Pid, {stop, Reason}). manager_request(Pid, Request) -> - request(manager, Pid, Request). + ?LIB:request(manager, Pid, Request). manager_reply(Pid, Ref, Reply) -> - reply(manager, Pid, Ref, Reply). + ?LIB:reply(manager, Pid, Ref, Reply). -manager_init(Domain, Type, Proto) -> +manager_init(Domain, stream = Type, Proto) -> put(sname, "manager"), i("try start acceptor"), case acceptor_start(Domain, Type, Proto) of @@ -68,8 +84,44 @@ manager_init(Domain, Type, Proto) -> handlers = []}); {error, Reason} -> exit({failed_starting_acceptor, Reason}) + end; +manager_init(Domain, dgram = Type, Proto) -> + put(sname, "manager"), + i("try open socket"), + case socket:open(Domain, Type, Proto) of + {ok, Sock} -> + Addr = which_addr(Domain), + SA = #{family => Domain, + addr => Addr}, + case socket:bind(Sock, SA) of + {ok, _P} -> + ok; + {error, BReason} -> + throw({bind, BReason}) + end, + i("try start handler for" + "~n ~p", [case socket:sockname(Sock) of + {ok, Name} -> Name; + {error, _} = E -> E + end]), + case handler_start(1, Sock) of + {ok, {Pid, MRef}} -> + i("handler (~p) started", [Pid]), + handler_continue(Pid), + manager_loop(#manager{handler_id = 2, % Just in case + handlers = [{Pid, MRef, 1}]}); + {error, SReason} -> + e("Failed starting handler: " + "~n ~p", [SReason]), + exit({failed_start_handler, SReason}) + end; + {error, OReason} -> + e("Failed open socket: " + "~n ~p", [OReason]), + exit({failed_open_socket, OReason}) end. + manager_loop(M) -> receive {'DOWN', MRef, process, Pid, Reason} -> @@ -262,7 +314,11 @@ acceptor_loop(#acceptor{socket = LSock} = A) -> end. acceptor_handle_accept_success(#acceptor{manager = Manager}, Sock) -> - i("try start handler"), + i("try start handler for peer" + "~n ~p", [case socket:peername(Sock) of + {ok, Peer} -> Peer; + {error, _} = E -> E + end]), case manager_start_handler(Manager, Sock) of {ok, Pid} -> i("handler (~p) started - now change 'ownership'", [Pid]), @@ -309,10 +365,10 @@ handler_continue(Pid) -> handler_request(Pid, continue). handler_request(Pid, Request) -> - request(handler, Pid, Request). + ?LIB:request(handler, Pid, Request). handler_reply(Pid, Ref, Reply) -> - reply(handler, Pid, Ref, Reply). + ?LIB:reply(handler, Pid, Ref, Reply). handler_init(Manager, ID, Sock) -> @@ -321,23 +377,30 @@ handler_init(Manager, ID, Sock) -> Manager ! {handler, self(), ok}, receive {handler, Pid, Ref, continue} -> - i("continue"), + i("got continue"), handler_reply(Pid, Ref, ok), + {ok, Type} = socket:getopt(Sock, socket, type), %% socket:setopt(Socket, otp, debug, true), handler_loop(#handler{manager = Manager, + type = Type, socket = Sock}) end. -handler_loop(#handler{socket = Socket} = H) -> - case socket:recv(Socket) of - {ok, Msg} -> - i("received ~w bytes of data", [size(Msg)]), - case dec_msg(Msg) of +handler_loop(H) -> + i("try read message"), + case recv(H) of + {ok, {Source, Msg}} -> + i("received ~w bytes of data~s", + [size(Msg), case Source of + undefined -> ""; + _ -> f(" from:~n ~p", [Source]) + end]), + case ?LIB:dec_msg(Msg) of {request, N, Req} -> i("received request ~w: " "~n ~p", [N, Req]), - Reply = enc_rep_msg(N, "hoppsan"), - case socket:send(Socket, Reply) of + Reply = ?LIB:enc_rep_msg(N, "hoppsan"), + case send(H, Reply, Source) of ok -> i("successfully sent reply ~w", [N]), handler_loop(H); @@ -360,87 +423,99 @@ handler_loop(#handler{socket = Socket} = H) -> end. +recv(#handler{socket = Sock, type = stream}) -> + case socket:recv(Sock) of + {ok, Msg} -> + {ok, {undefined, Msg}}; + {error, _} = ERROR -> + ERROR + end; +recv(#handler{socket = Sock, type = dgram}) -> + %% ok = socket:setopt(Sock, otp, debug, true), + socket:recvfrom(Sock). + + +send(#handler{socket = Sock, type = stream}, Msg, _) -> + socket:send(Sock, Msg); +send(#handler{socket = Sock, type = dgram}, Msg, Dest) -> + socket:sendto(Sock, Msg, Dest). + + %% ========================================================================= -enc_req_msg(N, Data) -> - enc_msg(?REQ, N, Data). +%% enc_req_msg(N, Data) -> +%% enc_msg(?REQ, N, Data). -enc_rep_msg(N, Data) -> - enc_msg(?REP, N, Data). +%% enc_rep_msg(N, Data) -> +%% enc_msg(?REP, N, Data). -enc_msg(Type, N, Data) when is_list(Data) -> - enc_msg(Type, N, list_to_binary(Data)); -enc_msg(Type, N, Data) - when is_integer(Type) andalso is_integer(N) andalso is_binary(Data) -> - <>. +%% enc_msg(Type, N, Data) when is_list(Data) -> +%% enc_msg(Type, N, list_to_binary(Data)); +%% enc_msg(Type, N, Data) +%% when is_integer(Type) andalso is_integer(N) andalso is_binary(Data) -> +%% <>. -dec_msg(<>) -> - {request, N, Data}; -dec_msg(<>) -> - {reply, N, Data}. +%% dec_msg(<>) -> +%% {request, N, Data}; +%% dec_msg(<>) -> +%% {reply, N, Data}. %% --- -request(Tag, Pid, Request) -> - Ref = make_ref(), - Pid ! {Tag, self(), Ref, Request}, - receive - {Tag, Pid, Ref, Reply} -> - Reply - end. +%% request(Tag, Pid, Request) -> +%% Ref = make_ref(), +%% Pid ! {Tag, self(), Ref, Request}, +%% receive +%% {Tag, Pid, Ref, Reply} -> +%% Reply +%% end. -reply(Tag, Pid, Ref, Reply) -> - Pid ! {Tag, self(), Ref, Reply}. +%% reply(Tag, Pid, Ref, Reply) -> +%% Pid ! {Tag, self(), Ref, Reply}. %% --- -formated_timestamp() -> - format_timestamp(os:timestamp()). +%% formated_timestamp() -> +%% format_timestamp(os:timestamp()). -format_timestamp(Now) -> - N2T = fun(N) -> calendar:now_to_local_time(N) end, - format_timestamp(Now, N2T, true). +%% format_timestamp(Now) -> +%% N2T = fun(N) -> calendar:now_to_local_time(N) end, +%% format_timestamp(Now, N2T, true). -format_timestamp({_N1, _N2, N3} = N, N2T, true) -> - FormatExtra = ".~.2.0w", - ArgsExtra = [N3 div 10000], - format_timestamp(N, N2T, FormatExtra, ArgsExtra); -format_timestamp({_N1, _N2, _N3} = N, N2T, false) -> - FormatExtra = "", - ArgsExtra = [], - format_timestamp(N, N2T, FormatExtra, ArgsExtra). +%% format_timestamp({_N1, _N2, N3} = N, N2T, true) -> +%% FormatExtra = ".~.2.0w", +%% ArgsExtra = [N3 div 10000], +%% format_timestamp(N, N2T, FormatExtra, ArgsExtra); +%% format_timestamp({_N1, _N2, _N3} = N, N2T, false) -> +%% FormatExtra = "", +%% ArgsExtra = [], +%% format_timestamp(N, N2T, FormatExtra, ArgsExtra). -format_timestamp(N, N2T, FormatExtra, ArgsExtra) -> - {Date, Time} = N2T(N), - {YYYY,MM,DD} = Date, - {Hour,Min,Sec} = Time, - FormatDate = - io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w" ++ FormatExtra, - [YYYY, MM, DD, Hour, Min, Sec] ++ ArgsExtra), - lists:flatten(FormatDate). +%% format_timestamp(N, N2T, FormatExtra, ArgsExtra) -> +%% {Date, Time} = N2T(N), +%% {YYYY,MM,DD} = Date, +%% {Hour,Min,Sec} = Time, +%% FormatDate = +%% io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w" ++ FormatExtra, +%% [YYYY, MM, DD, Hour, Min, Sec] ++ ArgsExtra), +%% lists:flatten(FormatDate). %% --- f(F, A) -> - lists:flatten(io_lib:format(F, A)). + ?LIB:f(F, A). e(F, A) -> - p(" " ++ F, A). + ?LIB:e(F, A). i(F) -> - i(F, []). -i(F, A) -> - p("*** " ++ F, A). + ?LIB:i(F). -p(F, A) -> - p(get(sname), F, A). +i(F, A) -> + ?LIB:i(F, A). -p(SName, F, A) -> - io:format("[~s,~p][~s] " ++ F ++ "~n", - [SName,self(),formated_timestamp()|A]). - -- cgit v1.2.3