1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21%%----------------------------------------------------------------------
22%% Purpose: Utility functions for the (snmp manager) user test(s).
23%%----------------------------------------------------------------------
24
25-module(snmp_manager_user).
26
27-behaviour(snmpm_user).
28%% -behaviour(snmpm_user_old).
29
30
31%%----------------------------------------------------------------------
32%% Include files
33%%----------------------------------------------------------------------
34-include_lib("common_test/include/ct.hrl").
35-include("snmp_test_lib.hrl").
36
37
38%%----------------------------------------------------------------------
39%% External exports
40%%----------------------------------------------------------------------
41-export([
42         start_link/0, start_link/1, start_link/2,
43	 start/0, start/1, start/2,
44	 stop/0,
45	 info/0,
46	 system_info/0,
47	 simulate_crash/1,
48	 register_agent/2,
49	 unregister_agent/1,
50	 agent_info/2,
51	 update_agent_info/3,
52	 which_all_agents/0, which_own_agents/0,
53	 load_mib/1, unload_mib/1,
54         sync_get2/3,
55         async_get2/3,
56         sync_get_next2/3,
57         async_get_next2/3,
58         sync_set2/3,
59         async_set2/3,
60         sync_get_bulk2/5,
61         async_get_bulk2/5,
62	 name_to_oid/1, oid_to_name/1,
63	 purify_oid/1
64        ]).
65
66
67%%----------------------------------------------------------------------
68%% Internal exports
69%%----------------------------------------------------------------------
70
71-export([
72	 main/4
73        ]).
74
75-export([
76	 handle_error/3,
77         handle_agent/5,
78         handle_pdu/4,
79         handle_trap/3,
80         handle_inform/3,
81         handle_report/3
82	]).
83
84
85-define(SERVER, ?MODULE).
86
87-record(state, {parent, id, reqs = []}).
88%% -record(request, {from, ref, tmr, req_id, type}).
89
90
91%%----------------------------------------------------------------------
92%% The user API
93%%----------------------------------------------------------------------
94
95start() ->
96    start(self()).
97
98start(Parent) ->
99    start(Parent, test_user).
100
101start(Parent, Id) ->
102    proc_lib:start(?MODULE, main, [true, Parent, self(), Id]).
103
104start_link() ->
105    start_link(self()).
106start_link(Parent) ->
107    start_link(Parent, test_user).
108
109start_link(Parent, Id) ->
110    proc_lib:start_link(?MODULE, main, [true, Parent, self(), Id]).
111
112stop() ->
113    MRef = erlang:monitor(process, ?SERVER),
114    cast(stop),
115    receive {'DOWN', MRef, _, _, Info} ->
116	    case Info of
117		noproc ->
118		    ok;
119		noconnection ->
120		    ok;
121		normal ->
122		    ok
123	    end
124    end.
125
126info() ->
127    call(info).
128
129system_info() ->
130    call(system_info).
131
132simulate_crash(Reason) ->
133    call({simulate_crash, Reason}).
134
135register_agent(TargetName, Config)
136  when is_list(TargetName) andalso is_list(Config) ->
137    call({register_agent, TargetName, Config}).
138
139unregister_agent(TargetName) ->
140    call({unregister_agent, TargetName}).
141
142agent_info(TargetName, Item) ->
143    call({agent_info, TargetName, Item}).
144
145update_agent_info(TargetName, Item, Val) ->
146    call({update_agent_info, TargetName, Item, Val}).
147
148which_all_agents() ->
149    call(which_all_agents).
150
151which_own_agents() ->
152    call(which_own_agents).
153
154load_mib(Mib) ->
155    call({load_mib, Mib}).
156
157unload_mib(Mib) ->
158    call({unload_mib, Mib}).
159
160%% --
161
162sync_get2(TargetName, Oids, SendOpts) ->
163    call({sync_get2, TargetName, Oids, SendOpts}).
164
165
166%% --
167
168async_get2(TargetName, Oids, SendOpts) ->
169    call({async_get2, TargetName, Oids, SendOpts}).
170
171%% --
172
173sync_get_next2(TargetName, Oids, SendOpts) ->
174    call({sync_get_next2, TargetName, Oids, SendOpts}).
175
176%% --
177
178async_get_next2(TargetName, Oids, SendOpts) ->
179    call({async_get_next2, TargetName, Oids, SendOpts}).
180
181%% --
182
183sync_set2(TargetName, VAV, SendOpts) ->
184    call({sync_set2, TargetName, VAV, SendOpts}).
185
186%% --
187
188async_set2(TargetName, VAV, SendOpts) ->
189    call({async_set2, TargetName, VAV, SendOpts}).
190
191%% --
192
193sync_get_bulk2(TargetName, NonRep, MaxRep, Oids, SendOpts) ->
194    call({sync_get_bulk2, TargetName, NonRep, MaxRep, Oids, SendOpts}).
195
196%% --
197
198async_get_bulk2(TargetName, NonRep, MaxRep, Oids, SendOpts) ->
199    call({async_get_bulk2, TargetName, NonRep, MaxRep, Oids, SendOpts}).
200
201%% --
202
203name_to_oid(Name) ->
204    call({name_to_oid, Name}).
205
206oid_to_name(Oid) ->
207    call({oid_to_name, Oid}).
208
209purify_oid(Oid) ->
210    call({purify_oid, Oid}).
211
212
213%%----------------------------------------------------------------------
214
215main(Debug, Parent, Starter, Id) ->
216    put(debug, Debug),
217    d("main -> entry with"
218      "~n   Parent:  ~p"
219      "~n   Starter: ~p"
220      "~n   Id:      ~p", [Parent, Starter, Id]),
221    case (catch do_init(Id)) of
222	ok ->
223	    proc_lib:init_ack(Starter, {ok, self()}),
224	    loop(#state{parent = Parent, id = Id});
225	Error ->
226	    d("main -> error: "
227	      "~p", [Error]),
228	    proc_lib:init_ack(Starter, Error)
229    end.
230
231do_init(Id) ->
232    erlang:register(?SERVER, self()),
233    snmpm:register_user(Id, ?MODULE, self()).
234
235
236%%----------------------------------------------------------------------
237
238loop(#state{parent = Parent, id = Id} = S) ->
239    d("loop -> entry"),
240    receive
241	{stop, _From} ->
242	    d("loop -> received stop request"),
243	    exit(normal);
244
245	{{simulate_crash, Reason}, From, Ref} ->
246	    d("loop -> received simulate_crash request"),
247	    reply(From, ok, Ref),
248	    exit(Reason);
249
250	{info, From, Ref} ->
251	    d("loop -> received info request"),
252	    Res = snmpm:info(),
253	    reply(From, Res, Ref),
254	    loop(S);
255
256	{system_info, From, Ref} ->
257	    d("loop -> received system_info request"),
258	    Res = snmpm_config:system_info(),
259	    reply(From, Res, Ref),
260	    loop(S);
261
262	{{register_agent, TargetName, Conf}, From, Ref} ->
263	    d("loop -> received register_agent request"),
264	    Res = snmpm:register_agent(Id, TargetName, Conf),
265	    reply(From, Res, Ref),
266	    loop(S);
267
268	{{unregister_agent, TargetName}, From, Ref} ->
269	    d("loop -> received unregister_agent request"),
270	    Res = snmpm:unregister_agent(Id, TargetName),
271	    reply(From, Res, Ref),
272	    loop(S);
273
274	{{agent_info, TargetName, Item}, From, Ref} ->
275	   d("loop -> received agent_info request with"
276	     "~n   TargetName: ~p"
277	     "~n   Item:       ~p", [TargetName, Item]),
278	    Res = snmpm:agent_info(TargetName, Item),
279	   d("loop -> agent_info for ~p"
280	     "~n   Res: ~p", [Item, Res]),
281	    reply(From, Res, Ref),
282	    loop(S);
283
284	{{update_agent_info, TargetName, Item, Val}, From, Ref} ->
285	   d("loop -> received update_agent_info request with"
286	     "~n   TargetName: ~p"
287	     "~n   Item:       ~p"
288	     "~n   Val:        ~p", [TargetName, Item, Val]),
289	    Res = snmpm:update_agent_info(Id, TargetName, Item, Val),
290	    reply(From, Res, Ref),
291	    loop(S);
292
293	{which_all_agents, From, Ref} ->
294	    d("loop -> received which_all_agents request"),
295	    Res = snmpm:which_agents(),
296	    reply(From, Res, Ref),
297	    loop(S);
298
299	{which_own_agents, From, Ref} ->
300	    d("loop -> received which_own_agents request"),
301	    Res = snmpm:which_agents(Id),
302	    reply(From, Res, Ref),
303	    loop(S);
304
305	{{load_mib, Mib}, From, Ref} ->
306	    d("loop -> received load_mib request"),
307	    Res = snmpm:load_mib(Mib),
308	    reply(From, Res, Ref),
309	    loop(S);
310
311	{{unload_mib, Mib}, From, Ref} ->
312	    d("loop -> received unload_mib request"),
313	    Res = snmpm:unload_mib(Mib),
314	    reply(From, Res, Ref),
315	    loop(S);
316
317
318	%%
319	%% -- (sync) get-request --
320	%%
321
322	{{sync_get2, TargetName, Oids, SendOpts}, From, Ref}
323	  when is_list(TargetName) ->
324            snmpm:verbosity(server, trace),
325	    d("loop -> received sync_get2 request with"
326	      "~n   TargetName: ~p"
327	      "~n   Oids:       ~p"
328	      "~n   SendOpts:   ~p", [TargetName, Oids, SendOpts]),
329	    Res = snmpm:sync_get2(Id, TargetName, Oids, SendOpts),
330            d("loop -> result:"
331              "~n   ~p", [Res]),
332	    reply(From, Res, Ref),
333	    loop(S);
334
335
336	%%
337	%% -- (async) get-request --
338	%%
339
340	{{async_get2, TargetName, Oids, SendOpts}, From, Ref}
341	  when is_list(TargetName) ->
342	    d("loop -> received async_get2 request with"
343	      "~n   TargetName: ~p"
344	      "~n   Oids:       ~p"
345	      "~n   SendOpts:   ~p", [TargetName, Oids, SendOpts]),
346	    Res = snmpm:async_get2(Id, TargetName, Oids, SendOpts),
347	    reply(From, Res, Ref),
348	    loop(S);
349
350
351	%%
352	%% -- (sync) get_next-request --
353	%%
354
355	{{sync_get_next2, TargetName, Oids, SendOpts}, From, Ref}
356	  when is_list(TargetName) ->
357	    d("loop -> received sync_get_next2 request with"
358	      "~n   TargetName: ~p"
359	      "~n   Oids:       ~p"
360	      "~n   SendOpts:   ~p", [TargetName, Oids, SendOpts]),
361	    Res = snmpm:sync_get_next2(Id, TargetName, Oids, SendOpts),
362	    reply(From, Res, Ref),
363	    loop(S);
364
365
366	%%
367	%% -- (async) get_next-request --
368	%%
369
370	{{async_get_next2, TargetName, Oids, SendOpts}, From, Ref}
371	  when is_list(TargetName) ->
372	    d("loop -> received async_get_next2 request with"
373	      "~n   TargetName: ~p"
374	      "~n   Oids:       ~p"
375	      "~n   SendOpts:   ~p", [TargetName, Oids, SendOpts]),
376	    Res = snmpm:async_get_next2(Id, TargetName, Oids, SendOpts),
377	    reply(From, Res, Ref),
378	    loop(S);
379
380
381	%%
382	%% -- (sync) set-request --
383	%%
384
385	{{sync_set2, TargetName, VAV, SendOpts}, From, Ref}
386	  when is_list(TargetName) ->
387	    d("loop -> received sync_set2 request with"
388	      "~n   TargetName: ~p"
389	      "~n   VAV:        ~p"
390	      "~n   SendOpts:   ~p", [TargetName, VAV, SendOpts]),
391	    Res = snmpm:sync_set2(Id, TargetName, VAV, SendOpts),
392	    reply(From, Res, Ref),
393	    loop(S);
394
395
396	%%
397	%% -- (async) set-request --
398	%%
399
400	{{async_set2, TargetName, VAV, SendOpts}, From, Ref}
401	  when is_list(TargetName) ->
402	    d("loop -> received async_set2 request with"
403	      "~n   TargetName: ~p"
404	      "~n   VAV:        ~p"
405	      "~n   SendOpts:   ~p", [TargetName, VAV, SendOpts]),
406	    Res = snmpm:async_set2(Id, TargetName, VAV, SendOpts),
407	    reply(From, Res, Ref),
408	    loop(S);
409
410
411	%%
412	%% -- (sync) get-bulk-request --
413	%%
414
415	{{sync_get_bulk2, TargetName, NonRep, MaxRep, Oids, SendOpts}, From, Ref}
416	  when is_list(TargetName) ->
417	    d("loop -> received sync_get_bulk request with"
418	      "~n   TargetName: ~p"
419	      "~n   NonRep:     ~w"
420	      "~n   MaxRep:     ~w"
421	      "~n   Oids:       ~p"
422	      "~n   SendOpts:   ~p",
423	      [TargetName, NonRep, MaxRep, Oids, SendOpts]),
424	    Res = snmpm:sync_get_bulk2(Id, TargetName,
425				       NonRep, MaxRep, Oids, SendOpts),
426	    reply(From, Res, Ref),
427	    loop(S);
428
429
430	%%
431	%% -- (async) get-bulk-request --
432	%%
433
434	{{async_get_bulk2, TargetName, NonRep, MaxRep, Oids, SendOpts},
435	 From, Ref} when is_list(TargetName) ->
436	    d("loop -> received async_get_bulk2 request with"
437	      "~n   TargetName: ~p"
438	      "~n   NonRep:     ~w"
439	      "~n   MaxRep:     ~w"
440	      "~n   Oids:       ~p"
441	      "~n   SendOpts:   ~p",
442	      [TargetName, NonRep, MaxRep, Oids, SendOpts]),
443	    Res = snmpm:async_get_bulk2(Id, TargetName,
444					NonRep, MaxRep, Oids, SendOpts),
445	    reply(From, Res, Ref),
446	    loop(S);
447
448
449	%%
450	%% -- logical name translation --
451	%%
452
453	{{name_to_oid, Name}, From, Ref} ->
454	    d("loop -> received name_to_oid request for"
455	      "~n   Name: ~p", [Name]),
456	    Res = snmpm:name_to_oid(Name),
457	    reply(From, Res, Ref),
458	    loop(S);
459
460	{{oid_to_name, Oid}, From, Ref} ->
461	    d("loop -> received oid_to_name request for"
462	      "~n   Oid: ~p", [Oid]),
463	    Res = snmpm:oid_to_name(Oid),
464	    reply(From, Res, Ref),
465	    loop(S);
466
467	{{purify_oid, Oid}, From, Ref} ->
468	    d("loop -> received purify_oid request for"
469	      "~n   Oid: ~p", [Oid]),
470	    Res = do_purify_oid(Oid),
471	    reply(From, Res, Ref),
472	    loop(S);
473
474
475	%% SNMP manager callback messages (from our callback API):
476
477	{handle_error, _Pid, ReqId, Reason} ->
478	    d("loop -> received error callback from manager for ~w:"
479	      "~n   ~p", [ReqId, Reason]),
480	    Parent ! {async_event, ReqId, {error, Reason}},
481	    loop(S);
482
483	{handle_agent, _Pid, Addr, Port, SnmpInfo} ->
484	    d("loop -> received agent callback from manager for ~n   ~p:~w",
485	      [Addr, Port]),
486	    Parent ! {async_event, {Addr, Port}, {agent, SnmpInfo}},
487	    loop(S);
488
489	{handle_pdu, _Pid, _TargetName, ReqId, SnmpResponse} ->
490	    d("loop -> received pdu callback from manager for ~w", [ReqId]),
491	    Parent ! {async_event, ReqId, {pdu, SnmpResponse}},
492	    loop(S);
493
494	{handle_trap, _Pid, TargetName, SnmpTrap} ->
495	    d("loop -> received trap callback from manager for "
496	      "~n   ~p",
497	      "~n   ~p",
498	      [TargetName, SnmpTrap]),
499	    Parent ! {async_event, TargetName, {trap, SnmpTrap}},
500	    loop(S);
501
502	{handle_inform, Pid, TargetName, SnmpInform} ->
503	    d("loop -> received inform callback from manager for "
504	      "~n   ~p",
505	      "~n   ~p",
506	      [TargetName, SnmpInform]),
507	    Parent ! {async_event, TargetName, {inform, Pid, SnmpInform}},
508	    loop(S);
509
510	{handle_report, _Pid, TargetName, SnmpReport} ->
511	    d("loop -> received report callback from manager for "
512	      "~n   ~p",
513	      "~n   ~p",
514	      [TargetName, SnmpReport]),
515	    Parent ! {async_event, TargetName, {report, SnmpReport}},
516	    loop(S);
517
518	{handle_invalid_result, _Pid, In, Out} ->
519	    d("loop -> received invalid result callback from manager for "
520	      "~n   In:  ~p",
521	      "~n   Out: ~p", [In, Out]),
522	    info("received invalid result message: "
523		 "~n   In:  ~p"
524		 "~n   Out: ~p", [In, Out]),
525	    loop(S);
526
527	{'EXIT', Parent, Reason} ->
528	    d("received exit signal from parent: ~n~p", [Reason]),
529	    info("received exit signal from parent: ~n~p", [Reason]),
530	    exit(Reason);
531
532	Unknown ->
533	    d("received unknown message: ~n~p", [Unknown]),
534	    info("received unknown message: ~n~p", [Unknown]),
535	    loop(S)
536    end.
537
538
539%% -------------
540
541do_purify_oid([A|T]) when is_atom(A) ->
542    case snmpm:name_to_oid(A) of
543	{ok, [Oid|_]} ->
544	    verify_pure_oid(lists:flatten([Oid|T]));
545	{error, not_found} ->
546	    {error, {not_found, A}};
547	{error, _} = Error ->
548	    Error
549    end;
550do_purify_oid(L) when is_list(L) ->
551    verify_pure_oid(lists:flatten(L));
552do_purify_oid(X) ->
553    {error, {unpure_oid, X}}.
554
555verify_pure_oid([]) ->
556    [];
557verify_pure_oid([H | T]) when is_integer(H) andalso (H >= 0) ->
558    [H | verify_pure_oid(T)];
559verify_pure_oid([H | _]) ->
560    throw({error, {not_pure_oid, H}}).
561
562
563%% -------------
564
565info(F, A) ->
566    error_logger:info_msg("TEST MGR USER " ++ F ++ "~n", A).
567
568
569%% -------------
570
571call(Req) ->
572    call(Req, 5000).
573
574call(Req, To) when is_integer(To) ->
575    Ref = make_ref(),
576    ?SERVER ! {Req, self(), Ref},
577    receive
578	{Reply, Ref} ->
579	    Reply
580    after To ->
581	    {error, timeout}
582    end.
583
584reply(Pid, Reply, Ref) ->
585    d("reply -> entry with"
586      "~n   Pid:   ~p"
587      "~n   Reply: ~p"
588      "~n   Ref:   ~p", [Pid, Reply, Ref]),
589    Pid ! {Reply, Ref}.
590
591cast(Msg) ->
592    ?SERVER ! {Msg, self()},
593    ok.
594
595
596%%----------------------------------------------------------------------
597%% User callback functions:
598%%----------------------------------------------------------------------
599
600handle_error(ReqId, Reason, UserPid) ->
601    UserPid ! {handle_error, self(), ReqId, Reason},
602    ignore.
603
604
605handle_agent(Addr, Port, SnmpInfo, UserPid, UserData) ->
606    UserPid ! {handle_agent, self(), Addr, Port, SnmpInfo, UserData},
607    ignore.
608
609
610handle_pdu(TargetName, ReqId, SnmpResponse, UserPid) ->
611    UserPid ! {handle_pdu, self(), TargetName, ReqId, SnmpResponse},
612    ignore.
613
614handle_trap(TargetName, SnmpTrap, UserPid) ->
615    UserPid ! {handle_trap, self(), TargetName, SnmpTrap},
616    ignore.
617
618handle_inform(TargetName, SnmpInform, UserPid) ->
619    UserPid ! {handle_inform, self(), TargetName, SnmpInform},
620    receive
621	{handle_inform_no_response, TargetName} ->
622	    no_reply;
623	{handle_inform_response, TargetName} ->
624	    ignore
625    end.
626
627handle_report(TargetName, SnmpReport, UserPid) ->
628    UserPid ! {handle_report, self(), TargetName, SnmpReport},
629    ignore.
630
631
632%%----------------------------------------------------------------------
633%% Debug
634%%----------------------------------------------------------------------
635
636d(F) ->
637    d(F, []).
638
639d(F, A) ->
640    d(get(debug), F, A).
641
642d(true, F, A) ->
643    ?IPRINT("~w:" ++ F, [?SERVER|A]);
644d(_, _, _) ->
645    ok.
646