diff options
Diffstat (limited to 'lib/test_server/src/vxworks_client.erl')
-rw-r--r-- | lib/test_server/src/vxworks_client.erl | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/lib/test_server/src/vxworks_client.erl b/lib/test_server/src/vxworks_client.erl new file mode 100644 index 0000000000..ca65eca02a --- /dev/null +++ b/lib/test_server/src/vxworks_client.erl @@ -0,0 +1,243 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2002-2009. 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(vxworks_client). + +-export([open/1, close/1, send_data/2, send_data/3, send_data_wait_for_close/2, reboot/1]). +-export([init/2]). + +-include("ts.hrl"). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% This is a client talking to a test server daemon on a VxWorks card. +%%% +%%% User interface: +%%% +%%% open/1 +%%% Start a client and establish the connection with the test server daemon +%%% +%%% send_data/2 +%%% Send data/command to the test server daemon, don't wait for any return +%%% +%%% send_data/3 +%%% Send data/command to the test server daemon and wait for the given +%%% return value. +%%% +%%% send_data_wait_for_close/2 +%%% Send data/command to the test server daemon and wait for the daemon to +%%% close the connection. +%%% +%%% close/1 +%%% Close the client. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +%% +%% User interface +%% + +reboot(Target) -> + {ok, {_,_,_,_,_,[Addr|_]}} = inet:gethostbyname(Target), + Fun = fun({ok, Socket}) -> + gen_tcp:send(Socket, "q\n"), + receive + {tcp_closed, Socket} -> + gen_tcp:close(Socket), + {ok, socket_closed} + after 5000 -> + exit({timeout, tryagain}) + end + end, + io:format("Stopping (rebooting) ~p ",[Target]), + case fun_target(Addr, Fun) of + {ok, socket_closed} -> + ok; + _Else -> + io:format("No contact with ts daemon - exiting ...~n"), + exit({stop, no_ts_daemon_contact}) + end. + + +%% open(Target) -> {ok,Client} | {error, Reason} +open(Target) -> + {ok, {_,_,_,_,_,[Addr|_]}} = inet:gethostbyname(Target), + Fun = fun({ok, Socket}) -> + P = spawn(?MODULE,init,[Target,Socket]), + inet_tcp:controlling_process(Socket,P), + {ok,P} + end, + case fun_target(Addr,Fun) of + {ok, Pid} -> + {ok, Pid}; + {error,Reason} -> + {error, Reason} + end. + +%% send_data(Client,Data) -> ok +send_data(Pid,Data) -> + Pid ! {send_data,Data++"\n"}, + ok. + +%% send_data(Client,Data,ExpectedReturn) -> {ok,ExpectedReturn} | {error,Reason} +send_data(Pid,Data,Return) -> + Pid ! {send_data,Data++"\n",Return,self()}, + receive {Pid,Result} -> Result end. + +%% send_data_wait_for_close(Client,Data) -> ok | {error,Reason} +send_data_wait_for_close(Pid,Data) -> + send_data(Pid,Data,tcp_closed). + +%% close(Client) -> ok +close(Pid) -> + Pid ! close, + ok. + + +%% +%% Internal +%% + +init(Target,Socket) -> + process_flag(trap_exit,true), + loop(Target,Socket). + +loop(Target,Socket) -> + receive + {send_data,Data} -> + %% io:format("vx client sending: ~p~n", [Data]), + gen_tcp:send(Socket, Data), + loop(Socket,Target); + {send_data,Data,tcp_closed,From} -> + %% io:format("vx client sending: ~p~n", [Data]), + gen_tcp:send(Socket, Data), + receive + {tcp_closed, Socket} -> + From ! {self(),ok} + after 5000 -> + From ! {self(),{error,timeout}} + end, + closed(Socket,normal); + {send_data,Data,Return,From} -> + %% io:format("vx client sending: ~p~n", [Data]), + gen_tcp:send(Socket, Data), + case receive_line(Socket,[],Return,200) of + {tcp_closed, Socket} -> + From ! {self(),{error,{socket_closed,Target}}}, + closed(Socket,{socket_closed,Target}); + {tcp,Socket,_Rest} -> + From ! {self(),{ok,Data}}, + got_data(Target,Socket,Data); + error -> + From ! {self(),{error,{catatonic,Target}}} + end; + close -> + closed(Socket,normal); + {tcp_closed, Socket} -> + closed(Socket,{socket_closed,Target}); + {tcp,Socket,Data} -> + got_data(Target,Socket,Data) + end. + + + +closed(Socket,Reason) -> + gen_tcp:close(Socket), + exit(Reason). + +got_data(Target,Socket,Data) -> + if is_atom(Target) -> + io:format("~w: ~s",[Target,uncr(Data)]); + true -> + io:format("~s: ~s",[Target,uncr(Data)]) + end, + loop(Target,Socket). + +uncr([]) -> + []; +uncr([$\r | T]) -> + uncr(T); +uncr([H | T]) -> + [H | uncr(T)]. + +strip_line(Line) -> + RPos = string:rchr(Line, $\n), + string:substr(Line,RPos+1). + +maybe_done_receive(Socket,Ack,Match,C) -> + case string:str(Ack,Match) of + 0 -> + receive_line(Socket,strip_line(Ack),Match,C); + _ -> + {tcp,Socket,strip_line(Ack)} + end. + + +receive_line(_Socket,_Ack,_Match,0) -> + error; +receive_line(Socket,Ack,Match,Counter) -> + receive + {tcp_closed, Socket} -> + {tcp_closed, Socket}; + {tcp,Socket,Data} -> + NewAck = Ack ++ Data, + case {string:str(NewAck,"\r") > 0, + string:str(NewAck,"\n") > 0} of + {true,_} -> + maybe_done_receive(Socket,NewAck,Match,Counter-1); + {_,true} -> + maybe_done_receive(Socket,NewAck,Match,Counter-1); + _ -> + receive_line(Socket,NewAck,Match,Counter) + end + after 20000 -> + error + end. + + +%% Misc functions +fun_target(Addr, Fun) -> + io:format("["), + fun_target(Addr, Fun, 60). %Vx-cards need plenty of time. + +fun_target(_Addr, _Fun, 0) -> + io:format(" no contact with ts daemon]~n"), + {error,failed_to_connect}; +fun_target(Addr, Fun, Tries_left) -> + receive after 1 -> ok end, + case do_connect(Addr, Fun) of + {ok, Value} -> + io:format(" ok]~n"), + {ok, Value}; + _Error -> % typical {error, econnrefused} + io:format("."), + receive after 10000 -> ok end, + fun_target(Addr, Fun, Tries_left-1) + end. + +do_connect(Addr, Fun) -> + case gen_tcp:connect(Addr, ?TS_PORT, [{reuseaddr, true}], 60000) of + {ok, Socket} -> + Fun({ok, Socket}); + Error -> + Error + end. + + + |