diff --git a/include/ovsdb_definitions.hrl b/include/ovsdb_definitions.hrl index 135ac5c..70e4503 100644 --- a/include/ovsdb_definitions.hrl +++ b/include/ovsdb_definitions.hrl @@ -52,6 +52,7 @@ -record (ap_client, { id :: ets_dont_care() | binary() | string(), % this is the index position and must be there ca_name :: ets_dont_care() | string() | binary(), + redirector = <<"">> :: ets_dont_care() | binary(), status :: ets_dont_care() | client_status(), process :: ets_dont_care() | none | pid(), transitions :: ets_dont_care() | [{client_status(), TimeStamp::integer()}] diff --git a/src/ovsdb_ap.erl b/src/ovsdb_ap.erl index 22e8186..74a84b6 100644 --- a/src/ovsdb_ap.erl +++ b/src/ovsdb_ap.erl @@ -372,12 +372,13 @@ prepare_state (CAName, ID, Options) -> Stats = ets:new(ovsdb_ap_stats,[ordered_set,private,{keypos, 2}]), {'ok', Tref} = timer:apply_interval(proplists:get_value(report_int,Options,?AP_REPORT_INTERVAL), gen_server,cast,[self(),send_report]), + Redirector = proplists:get_value(redirector,Options,<<"">>), update_statistics({report_mark,{},<<>>},Stats), ets:insert(Stats,#stats_vars{}), #ap_state{ id = ID, ca_name = CAName, - config = ovsdb_ap_config:new(CAName,ID,Store), + config = ovsdb_ap_config:new(CAName,ID,Store,Redirector), status = init, store = Store, req_queue = ets:new(ovsdb_ap_req,[ordered_set,private,{keypos, 1}]), diff --git a/src/ovsdb_ap_config.erl b/src/ovsdb_ap_config.erl index 0b012ef..afc759e 100644 --- a/src/ovsdb_ap_config.erl +++ b/src/ovsdb_ap_config.erl @@ -18,6 +18,7 @@ -record (cfg, { ca_name :: string() | binary(), + redirector :: binary(), id :: string(), store_ref :: ets:tid(), ca_certs = <<"">> :: binary(), % pem file (in memory) of the server certificate chain @@ -28,7 +29,7 @@ -export_type([cfg/0]). --export([new/3,configure/1]). +-export([new/4,configure/1]). -export ([id/1,ca_certs/1,client_cert/1,tip_redirector/2,tip_manager/2]). @@ -36,28 +37,44 @@ %% API --spec new (CAName :: string() | binary(), Id :: string(), Store :: ets:tid()) -> Config :: cfg(). -new (CAName,Id,Store) -> - #cfg{ca_name=CAName, id=Id, store_ref = Store}. +-spec new (CAName :: string() | binary(), Id :: string(), Store :: ets:tid(), Redirector :: binary()) -> Config :: cfg(). +new (CAName,Id,Store,Redirector) -> + #cfg{ca_name=CAName, id=Id, store_ref = Store, redirector=Redirector}. -spec configure (Config :: cfg()) -> NewConfig :: cfg(). -configure (#cfg{ca_name=CAName, id=ID}=Config) -> +configure (#cfg{ca_name=CAName, id=ID, redirector=R}=Config) -> {ok,Info} = inventory:get_client(CAName,ID), - File = filename:join([code:priv_dir(?OWLS_APP),"templates","default_ap.cfg"]), - {ok, [Defaults]} = file:consult(File), {KeyType,KeyData} = Info#client_info.decrypt, CA = Info#client_info.cacert, Cert = Info#client_info.cert, - APC1 = lists:keyreplace(serial,1,Defaults,{serial,Info#client_info.serial}), - APC2 = lists:keyreplace(type,1,APC1,{type,Info#client_info.type}), - APC3 = lists:keyreplace(wan_mac,1,APC2,{wan_mac,Info#client_info.wan_mac0}), - APC4 = lists:keyreplace(lan_mac,1,APC3,{lan_mac,Info#client_info.lan_mac0}), - initialize_ap_tables(Config#cfg.store_ref,APC4), + APC = [ + {serial,Info#client_info.serial}, + {type,Info#client_info.type}, + {wan_mac,Info#client_info.wan_mac0}, + {lan_mac,Info#client_info.lan_mac0}, + {tip_redirector,R} + ], + initialize_ap_tables(Config#cfg.store_ref,validate_config(APC)), Config#cfg{ ca_certs = public_key:pem_encode([{'Certificate',CA,not_encrypted}]), client_cert = public_key:pem_encode([{'Certificate',Cert,not_encrypted},{KeyType,KeyData,not_encrypted}]) }. +-spec validate_config(APC :: [{atom(),term()}]) -> CorrAPC :: [{atom(),term()}]. +validate_config (APC) -> + File = filename:join([code:priv_dir(?OWLS_APP),"templates","default_ap.cfg"]), + {ok, [Defaults]} = file:consult(File), + F = fun({K,V}) -> + case V of + <<"">> -> + {K,proplists:get_value(K,Defaults)}; + _ -> + {K,V} + end + end, + [F(X)||X<-APC]. + + -spec initialize_ap_tables (Store :: ets:tid(), Config :: proplists:proplist()) -> true. initialize_ap_tables (Store, APC) -> create_table('AWLAN_Node',APC,Store), diff --git a/src/ovsdb_client_handler.erl b/src/ovsdb_client_handler.erl index 689dfd1..aae5edc 100644 --- a/src/ovsdb_client_handler.erl +++ b/src/ovsdb_client_handler.erl @@ -22,7 +22,7 @@ %% API -export([start_link/0]). -export([set_configuration/1, start/1, stop/1, pause/1, resume/1, cancel/1, report/0]). --export([ap_status/2,push_ap_stats/2,dump_clients/0,list_ids/0]). +-export([ap_status/2,push_ap_stats/2,dump_clients/0,list_ids/0,all_ready/0]). %% gen_server callbacks -export([init/1, handle_cast/2, handle_call/3, handle_info/2, terminate/2, code_change/3]). @@ -72,6 +72,9 @@ dump_clients () -> list_ids() -> gen_server:call(?SERVER,list_ids). +all_ready() -> + gen_server:call(?SERVER,all_ready). + %%% gen_sim_clients behaviour @@ -228,14 +231,24 @@ handle_call (update_stats, _From, #hdl_state{clients=C, ap_statistics=S}=State) {reply, ok, State#hdl_state{ap_statistics=[]}}; handle_call (dump_clients,_From, #hdl_state{clients=Clients}=State) -> - C = ets:match_object(Clients,'$1'), + C = ets:match_object(Clients,#ap_client{_='_'}), {reply,C,State}; handle_call (list_ids,_From, #hdl_state{clients=Clients}=State) -> - C = ets:match_object(Clients,'$1'), + C = ets:match_object(Clients,#ap_client{_='_'}), [io:format("~s~n",[X])||#ap_client{id=X}<-C], {reply,ok,State}; +handle_call (all_ready,_From, #hdl_state{clients=Clients}=State) -> + C = length(ets:match_object(Clients,#ap_client{_='_'})), + R = length(get_client_ids_in_state(Clients,{ready},all)), + if + (C > 0) and (C == R) -> + {reply,true,State}; + true -> + {reply,false,State} + end; + handle_call (_, _, State) -> {reply, invalid, State}. @@ -383,11 +396,12 @@ apply_config (Cfg, #hdl_state{clients=Clients}=State) when is_map_key(internal,C ?L_E(?DBGSTR("there are no clients in the inventory for simulation '~s'",[SimName])), State end; -apply_config (#{sim_name:=SimName, client_ids:=IDs}=Cfg, +apply_config (#{sim_name:=SimName, client_ids:=IDs, ovsdb_srv:=R}=Cfg, #hdl_state{clients=Clients}=State) -> F = fun (X) -> #ap_client{ id=X, ca_name=SimName, + redirector=R, status=available, process=none, transitions=[{available,erlang:system_time()}] @@ -395,7 +409,7 @@ apply_config (#{sim_name:=SimName, client_ids:=IDs}=Cfg, end, C = [F(X)||X<-IDs], ets:insert(Clients,C), - State#hdl_state{config=Cfg}. + cmd_launch_clients(IDs,State#hdl_state{config=Cfg}). @@ -422,7 +436,7 @@ update_client_status (ClS, Id, #hdl_state{clients=Clients}=State) -> get_client_ids_in_state (Tid, State, Refs) when is_atom(State) -> get_client_ids_in_state (Tid,{State},Refs); get_client_ids_in_state (Tid, States, Refs) -> - MSpec = [{{ap_client,'_','_',X,'_','_'},[],['$_']}||X<-tuple_to_list(States)], + MSpec = [{#ap_client{status=X,_='_'},[],['$_']}||X<-tuple_to_list(States)], Clients = ets:select(Tid,MSpec), Cids = [ID||#ap_client{id=ID}<-Clients], %io:format("MSPEC: ~p~nCLIENTS: ~p~nREFS: ~p~n, CIDS: ~p~n",[MSpec,Clients,Refs,Cids]), @@ -440,7 +454,7 @@ get_clients_with_ids (CTid, Ids) -> get_clients_with_ids (_,[],Acc) -> Acc; get_clients_with_ids (CTid,[ID|Rest],Acc) -> - case ets:match_object(CTid,{ap_client,ID,'_','_','_','_'}) of + case ets:match_object(CTid,#ap_client{id=ID,_='_'}) of [R] -> get_clients_with_ids (CTid,Rest,[R|Acc]); _ -> @@ -461,7 +475,7 @@ get_client_with_pid (Tid, Pid) -> -spec get_client_with_id (Clients :: ets:tid(), Id :: string()) -> {ok, #ap_client{}} | {error, not_found}. get_client_with_id (Tid, Id) -> - case ets:match_object(Tid,{ap_client,Id,'_','_','_','_'}) of + case ets:match_object(Tid,#ap_client{id=Id,_='_'}) of [] -> {error, not_found}; [R|_] -> @@ -502,8 +516,8 @@ cmd_startup_sim (#hdl_state{timer=T, clients=Clients}=State, Which) -> NewState :: #hdl_state{}. cmd_launch_clients (ToLauch, #hdl_state{clients=Clients}=State) -> Opt = [{report_int,?AP_REPORT_INTERVAL},{stats_int,?AP_STATS_INTERVAL}], - F = fun (#ap_client{id=ID,ca_name=CAName}=C) -> - {ok, Pid} = ovsdb_ap:launch(CAName,ID,Opt), + F = fun (#ap_client{id=ID,ca_name=CAName,redirector=R}=C) -> + {ok, Pid} = ovsdb_ap:launch(CAName,ID,[{redirector,R}|Opt]), [#ap_proc_map{id=ID, process=Pid},C#ap_client{process=Pid}] end, L = [F(C) || C <- get_clients_with_ids(Clients,ToLauch)],