summaryrefslogtreecommitdiff
path: root/tda.erl
blob: 2260f36e3910869b02e47ec2745ed53356dff77a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
-module(tda).

-export([associate_request/0, associate_result/1]).
-export([release_request/0, release_result/1]).
-export([associate_abort/1]).
-export([client/0, stop/1, loop/1, start_client/0]).

-include("acse.hrl").
-include("rose.hrl").

-define(TIMEOUT, 300000).

% A-ASSOCIATE Request
% 60 23                                AARQ-apdu
%    80 02 07 80                       protocol-version { version1 }
%    A1 07                             application-context-name
%       06 05 2B 0C 00 81 5A           { 1 3 12 0 218 }
%    BE 14                             user-information
%       28 12
%          06 07 2B 0C 00 82 1D 81 48  direct-reference { 1 3 12 0 285 200 }
%          A0 07                       single-ASN1-type
%                                      (ACSEUserInfomrationForCSTA)
%             A0 05                    newDefinition
%                03 03 00 08 00        cSTAVersion { versionFive }

associate_request() ->
	{ok, UI} = acse:encode('ACSEUserInformationForCSTA', {newDefinition,
		#'NewACSEUserInformationForCSTA'{cSTAVersion = [versionFive]}}),
	Pdu = #'AARQ-apdu'{
		'protocol-version' = [version1],
		'application-context-name' = {1, 3, 12, 0, 218},
		'user-information' = [#'EXTERNAL'{
			'direct-reference' = {1, 3, 12, 0, 285, 200},
			encoding = {'single-ASN1-type', UI}}]},
	acse:encode('ACSE-apdu', {aarq, Pdu}).

% Request
% 60,23,80,02,07,80,a1,07,06,05,2b,0c,00,81,5a,be,14,28,12,06,07,2b,0c,00,82,1d,81,48,a0,07,a0,05,03,03,00,08,00
% <<96,35,128,2,7,128,161,7,6,5,43,12,0,129,90,190,20,40,18,6,7,43,12,0,130,29,129,72,160,7,160,5,3,3,0,8,0>>
% <<96,30,161,7,6,5,43,12,0,129,90,190,19,40,17,6,7,43,12,0, 130,29,129,72,160,6,160,4,3,...>>
% Accept
% <<97,47,128,2,7,128,161,7,6,5,43,12,0,129,90,162,3,2,1,0,163,5,161,3,2,1,1,190,20,40,18,6,7,43,12,0,130,29,129,72,160,7,160,5,3,3,0,8,0>>
% Reject
% <<97,25,128,2,7,128,161,7,6,5,43,12,0,129,90,162,3,2,1,1,163,5,161,3,2,1,1>>
associate_result(Bin) ->
	case acse:decode('AARE-apdu', Bin) of
		{ok, Pdu} -> Pdu#'AARE-apdu'.result;
		{error, Reason} -> Reason
	end.

release_request() ->
	acse:encode('ACSE-apdu', {rlrq, #'RLRQ-apdu'{}}).

release_result(Bin) ->
	acse:decode('RLRE-apdu', Bin).

% <<100,3,128,1,0>>
associate_abort(Bin) ->
	{ok, Pdu} = acse:decode('ABRT-apdu', Bin),
	{ok, Pdu#'ABRT-apdu'.'abort-source'}.

% ROSE status
% <<161,12,2,1,1,2,2,0,211,48,3,10,1,2>>
% <<162,11,2,1,1,48,6,2,2,0,211,5,0>>

start_client() ->
	register(cl, spawn(?MODULE, client, [])).

client() ->
	Host = "192.168.240.20",
	case gen_tcp:connect(Host, 33333, [binary, {active, true}, {packet, 2}],
			    3000) of
		{ok, Sock} ->
			{ok, Hello} = associate_request(),
			gen_tcp:send(Sock, Hello),
			loop(Sock);
		{error, Reason} -> {error, Reason}
	end.

stop(Sock) -> gen_tcp:close(Sock).

loop(Sock) ->
	%inet:setopts(Sock, [{active, once}]),
	receive
		{tcp, Sock, Msg} ->
			decode(Sock, Msg),
			loop(Sock);
		{tcp_closed, _} ->
			closed
	after ?TIMEOUT ->
		stop(Sock),
		timeout
	end.

decode(Sock, Msg) ->
	case dispatch(Msg) of
		rose ->
			{ok, Rose} = rose:decode('ROS', Msg),
			io:format("ROSE> ~p~n", [Rose]),
			rose_handler(Sock, Rose);
		acse ->
			{ok, Acse} = acse:decode('ACSE-apdu', Msg),
			io:format("ACSE> ~p~n", [Acse]),
			acse_handler(Sock, Acse)
	end.

rose_handler(Sock, {invoke, Rose}) ->
	gen_tcp:send(Sock, invoke_handler(Rose)),
	ok.

invoke_handler(#'Invoke'{invokeId = Id, opcode = Op}) ->
	case Op of
		{_, 211} -> system_status(Id, Op)
	end.

dispatch(<<Head:8,_/binary>>) ->
	case Head of
		 96 -> acse;
		 97 -> acse;
		 98 -> acse;
		 99 -> acse;
		100 -> acse;
		161 -> rose;
		162 -> rose
	end.

system_status(Id, Op) ->
	RR = #'ReturnResult_result'{opcode = Op, result = <<5,0>>},
	R = #'ReturnResult'{invokeId = Id, result = RR},
	case rose:encode('ROS', {returnResult, R}) of
		{ok, Invoke} -> Invoke;
		{error, Reason} -> Reason
	end.

acse_handler(Sock, {aare, Apdu}) -> ok;
acse_handler(Sock, {aarq, Apdu}) -> ok;
acse_handler(Sock, {rlre, _}) -> gen_tcp:close(Sock);
acse_handler(Sock, {rlrq, _}) -> gen_tcp:close(Sock);
acse_handler(Sock, {abrt, _}) -> gen_tcp:close(Sock).