1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1999-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%%-----------------------------------------------------------------
23%%
24%% Purpose: Handles the Megaco/H.248 TCP connections.
25%%
26%%-----------------------------------------------------------------
27-module(megaco_tcp_connection).
28
29-behaviour(gen_server).
30
31
32%%-----------------------------------------------------------------
33%% Include files
34%%-----------------------------------------------------------------
35
36-include_lib("megaco/src/tcp/megaco_tcp.hrl").
37-include_lib("megaco/src/app/megaco_internal.hrl").
38
39
40%%-----------------------------------------------------------------
41%% External exports
42%%-----------------------------------------------------------------
43-export([
44	 start_link/1,
45	 stop/1,
46
47	 upgrade_receive_handle/2
48	]).
49
50%%-----------------------------------------------------------------
51%% Internal exports
52%%-----------------------------------------------------------------
53
54-export([
55	 init/1,
56	 handle_call/3,
57	 handle_cast/2,
58	 handle_info/2,
59	 code_change/3,
60	 terminate/2,
61
62	 handle_received_message/5
63	]).
64
65
66%%-----------------------------------------------------------------
67%% External interface functions
68%%-----------------------------------------------------------------
69
70%%-----------------------------------------------------------------
71%% Func: start_link/1
72%% Description: Starts the proces that keeps track of an TCP
73%%              connection.
74%%-----------------------------------------------------------------
75
76start_link(Arg) ->
77    gen_server:start_link(?MODULE, Arg, []).
78
79
80stop(Pid) ->
81    call(Pid, stop).
82
83
84upgrade_receive_handle(Pid, NewHandle) ->
85    call(Pid, {upgrade_receive_handle, NewHandle}).
86
87
88%%-----------------------------------------------------------------
89%% Internal interface functions
90%%-----------------------------------------------------------------
91
92%%-----------------------------------------------------------------
93%% Server functions
94%%-----------------------------------------------------------------
95
96%%-----------------------------------------------------------------
97%% Func: init/1
98%% Description: Init funcion for the generic server
99%%-----------------------------------------------------------------
100init(Arg) ->
101    %% process_flag(trap_exit, true),
102    ?tcp_debug(Arg, "tcp connection handler starting", [self()]),
103%%     info_msg("starting with"
104%% 	     "~n   Arg: ~p", [Arg]),
105    {ok, Arg}.
106
107
108%%-----------------------------------------------------------------
109%% Func: handle_call/3
110%% Description: Handling call messages (really just stop and garbage)
111%%-----------------------------------------------------------------
112handle_call(stop, _From, TcpRec) ->
113    {stop, shutdown, ok, TcpRec};
114handle_call({upgrade_receive_handle, NewHandle}, _From, TcpRec) ->
115    {reply, ok, TcpRec#megaco_tcp{receive_handle = NewHandle}};
116handle_call(Req, From, TcpRec) ->
117    warning_msg("received unexpected request from ~p: "
118		"~n~w", [From, Req]),
119    {reply, {error, {invalid_request, Req}}, TcpRec}.
120
121
122%%-----------------------------------------------------------------
123%% Func: handle_cast/2
124%% Description: Handling cast messages (really just stop and garbage)
125%%-----------------------------------------------------------------
126handle_cast(stop, TcpRec) ->
127    {stop, shutdown, TcpRec};
128handle_cast(Msg, TcpRec) ->
129    warning_msg("received unexpected message: "
130		"~n~w", [Msg]),
131    {noreply, TcpRec}.
132
133%%-----------------------------------------------------------------
134%% Func: handle_info/2
135%% Description: Handling non call/cast messages. Incomming messages
136%%              from the socket and exit messages.
137%%-----------------------------------------------------------------
138handle_info({tcp_closed, _Socket}, TcpRec) ->
139    {stop, shutdown, TcpRec};
140handle_info({tcp_error, _Socket}, TcpRec) ->
141    {stop, shutdown, TcpRec};
142handle_info({tcp, Socket, <<3:8, _X:8, Length:16, Msg/binary>>},
143	    #megaco_tcp{socket = Socket, serialize = false} = TcpRec)
144  when Length < ?GC_MSG_LIMIT ->
145    #megaco_tcp{module = Mod, receive_handle = RH} = TcpRec,
146    incNumInMessages(Socket),
147    incNumInOctets(Socket, 4+size(Msg)),
148    apply(Mod, receive_message, [RH, self(), Socket, Msg]),
149    inet:setopts(Socket, [{active, once}]),
150    {noreply, TcpRec};
151handle_info({tcp, Socket, <<3:8, _X:8, Length:16, Msg/binary>>},
152	    #megaco_tcp{socket = Socket, serialize = false} = TcpRec) ->
153    #megaco_tcp{module = Mod, receive_handle = RH} = TcpRec,
154    incNumInMessages(Socket),
155    incNumInOctets(Socket, 4+size(Msg)),
156    receive_message(Mod, RH, Socket, Length, Msg),
157    inet:setopts(Socket, [{active, once}]),
158    {noreply, TcpRec};
159handle_info({tcp, Socket, <<3:8, _X:8, _Length:16, Msg/binary>>},
160            #megaco_tcp{socket = Socket, serialize = true} = TcpRec) ->
161    #megaco_tcp{module = Mod, receive_handle = RH} = TcpRec,
162    incNumInMessages(Socket),
163    incNumInOctets(Socket, 4+size(Msg)),
164    process_received_message(Mod, RH, Socket, Msg),
165    inet:setopts(Socket, [{active, once}]),
166    {noreply, TcpRec};
167handle_info({tcp, Socket, Msg}, TcpRec) ->
168    incNumErrors(Socket),
169    error_msg("received bad tpkt packet: "
170	      "~n~w", [Msg]),
171    {noreply, TcpRec};
172handle_info(Info, TcpRec) ->
173    warning_msg("received unexpected info: "
174		"~n~p", [Info]),
175    {noreply, TcpRec}.
176
177
178process_received_message(Mod, RH, SH, Msg) ->
179    case (catch Mod:process_received_message(RH, self(), SH, Msg)) of
180	ok ->
181	    ok;
182	Error ->
183	    error_msg("failed processing received message: "
184		      "~n~p", [Error]),
185	    ok
186    end.
187
188
189receive_message(Mod, RH, SendHandle, Length, Msg) ->
190    Opts = [link , {min_heap_size, ?HEAP_SIZE(Length)}],
191    spawn_opt(?MODULE, handle_received_message,
192	      [Mod, RH, self(), SendHandle, Msg], Opts),
193    ok.
194
195
196handle_received_message(Mod, RH, Parent, SH, Msg) ->
197    Mod:process_received_message(RH, Parent, SH, Msg),
198    unlink(Parent),
199    exit(normal).
200
201
202%%-----------------------------------------------------------------
203%% Func: terminate/2
204%% Description: Termination function for the generic server
205%%-----------------------------------------------------------------
206terminate(shutdown = _Reason, TcpRec) ->
207    ?tcp_debug(TcpRec, "tcp connection handler terminating", [self(),_Reason]),
208    ok;
209
210terminate(Reason, TcpRec) ->
211    ?tcp_debug(TcpRec, "tcp connection handler terminating", [self(), Reason]),
212    SchedId      = erlang:system_info(scheduler_id),
213    SchedNum     = erlang:system_info(schedulers),
214    ProcCount    = erlang:system_info(process_count),
215    ProcLimit    = erlang:system_info(process_limit),
216    ProcMemUsed  = erlang:memory(processes_used),
217    ProcMemAlloc = erlang:memory(processes),
218    MemTot       = erlang:memory(total),
219    error_msg("abormal termination: "
220	      "~n   Scheduler id:                         ~p"
221	      "~n   Num scheduler:                        ~p"
222	      "~n   Process count:                        ~p"
223	      "~n   Process limit:                        ~p"
224	      "~n   Memory used by erlang processes:      ~p"
225	      "~n   Memory allocated by erlang processes: ~p"
226	      "~n   The total amount of memory allocated: ~p"
227	      "~n~p",
228	      [SchedId, SchedNum, ProcCount, ProcLimit,
229	       ProcMemUsed, ProcMemAlloc, MemTot, Reason]),
230    ok.
231
232
233%%-----------------------------------------------------------------
234%% Func: code_change/3
235%% Descrition: Handles code change messages during upgrade.
236%%-----------------------------------------------------------------
237code_change(_OldVsn, S, _Extra) ->
238    ?d("code_change -> entry with"
239	"~n   OldVsn: ~p"
240	"~n   S:      ~p"
241	"~n   Extra:  ~p", [_OldVsn, S, _Extra]),
242    {ok, S}.
243
244
245
246%%-----------------------------------------------------------------
247%% Func: incNumInMessages/1, incNumInOctets/2, incNumErrors/1
248%% Description: SNMP counter increment functions
249%%
250%%-----------------------------------------------------------------
251incNumInMessages(Socket) ->
252    incCounter({Socket, medGwyGatewayNumInMessages}, 1).
253
254incNumInOctets(Socket, NumOctets) ->
255    incCounter({Socket, medGwyGatewayNumInOctets}, NumOctets).
256
257incNumErrors(Socket) ->
258    incCounter({Socket, medGwyGatewayNumErrors}, 1).
259
260incCounter(Key, Inc) ->
261    ets:update_counter(megaco_tcp_stats, Key, Inc).
262
263
264%% info_msg(F, A) ->
265%%     ?megaco_info("TCP connection handler " ++ F, A).
266
267warning_msg(F, A) ->
268    ?megaco_warning("TCP connection handler: " ++ F, A).
269
270error_msg(F, A) ->
271    ?megaco_error("TCP connection handler: " ++ F, A).
272
273
274call(Pid, Req) ->
275    gen_server:call(Pid, Req, infinity).
276
277