diff options
author | Micael Karlberg <[email protected]> | 2018-07-04 15:18:18 +0200 |
---|---|---|
committer | Micael Karlberg <[email protected]> | 2018-09-18 14:50:18 +0200 |
commit | e39e25d84405e13ca0ce476e3ba473510e5548de (patch) | |
tree | 217ac95a480968372496b2b3b5d978826860f076 /lib/kernel/test/socket_client.erl | |
parent | dce68cf27f2dd1721bd316594a29ff99a0de7bb9 (diff) | |
download | otp-e39e25d84405e13ca0ce476e3ba473510e5548de.tar.gz otp-e39e25d84405e13ca0ce476e3ba473510e5548de.tar.bz2 otp-e39e25d84405e13ca0ce476e3ba473510e5548de.zip |
[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
Diffstat (limited to 'lib/kernel/test/socket_client.erl')
-rw-r--r-- | lib/kernel/test/socket_client.erl | 252 |
1 files changed, 176 insertions, 76 deletions
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 <[email protected]> -%%% @copyright (C) 2018, Micael Karlberg -%%% @doc -%%% -%%% @end -%%% Created : 27 Jun 2018 by Micael Karlberg <[email protected]> -%%%------------------------------------------------------------------- +%% +%% %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) -> - <<Type:32/integer, N:32/integer, Data/binary>>. +%% 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) -> +%% <<Type:32/integer, N:32/integer, Data/binary>>. -dec_msg(<<?REQ:32/integer, N:32/integer, Data/binary>>) -> - {request, N, Data}; -dec_msg(<<?REP:32/integer, N:32/integer, Data/binary>>) -> - {reply, N, Data}. +%% dec_msg(<<?REQ:32/integer, N:32/integer, Data/binary>>) -> +%% {request, N, Data}; +%% dec_msg(<<?REP:32/integer, N:32/integer, Data/binary>>) -> +%% {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("<ERROR> " ++ 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). |