diff options
Diffstat (limited to 'lib/megaco/src/tcp/megaco_tcp_connection.erl')
-rw-r--r-- | lib/megaco/src/tcp/megaco_tcp_connection.erl | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/lib/megaco/src/tcp/megaco_tcp_connection.erl b/lib/megaco/src/tcp/megaco_tcp_connection.erl new file mode 100644 index 0000000000..614edf513a --- /dev/null +++ b/lib/megaco/src/tcp/megaco_tcp_connection.erl @@ -0,0 +1,275 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-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% +%% + +%% +%%----------------------------------------------------------------- +%% +%% Purpose: Handles the Megaco/H.248 TCP connections. +%% +%%----------------------------------------------------------------- +-module(megaco_tcp_connection). + +-behaviour(gen_server). + + +%%----------------------------------------------------------------- +%% Include files +%%----------------------------------------------------------------- + +-include_lib("megaco/src/tcp/megaco_tcp.hrl"). +-include_lib("megaco/src/app/megaco_internal.hrl"). + + +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([ + start_link/1, + stop/1, + + upgrade_receive_handle/2 + ]). + +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- + +-export([ + init/1, + handle_call/3, + handle_cast/2, + handle_info/2, + code_change/3, + terminate/2, + + handle_received_message/5 + ]). + + +%%----------------------------------------------------------------- +%% External interface functions +%%----------------------------------------------------------------- + +%%----------------------------------------------------------------- +%% Func: start_link/1 +%% Description: Starts the proces that keeps track of an TCP +%% connection. +%%----------------------------------------------------------------- + +start_link(Arg) -> + gen_server:start_link(?MODULE, Arg, []). + + +stop(Pid) -> + call(Pid, stop). + + +upgrade_receive_handle(Pid, NewHandle) -> + call(Pid, {upgrade_receive_handle, NewHandle}). + + +%%----------------------------------------------------------------- +%% Internal interface functions +%%----------------------------------------------------------------- + +%%----------------------------------------------------------------- +%% Server functions +%%----------------------------------------------------------------- + +%%----------------------------------------------------------------- +%% Func: init/1 +%% Description: Init funcion for the generic server +%%----------------------------------------------------------------- +init(Arg) -> + %% process_flag(trap_exit, true), + ?tcp_debug(Arg, "tcp connection handler starting", [self()]), +%% info_msg("starting with" +%% "~n Arg: ~p", [Arg]), + {ok, Arg}. + + +%%----------------------------------------------------------------- +%% Func: handle_call/3 +%% Description: Handling call messages (really just stop and garbage) +%%----------------------------------------------------------------- +handle_call(stop, _From, TcpRec) -> + {stop, shutdown, ok, TcpRec}; +handle_call({upgrade_receive_handle, NewHandle}, _From, TcpRec) -> + {reply, ok, TcpRec#megaco_tcp{receive_handle = NewHandle}}; +handle_call(Req, From, TcpRec) -> + warning_msg("received unexpected request from ~p: " + "~n~w", [From, Req]), + {reply, {error, {invalid_request, Req}}, TcpRec}. + + +%%----------------------------------------------------------------- +%% Func: handle_cast/2 +%% Description: Handling cast messages (really just stop and garbage) +%%----------------------------------------------------------------- +handle_cast(stop, TcpRec) -> + {stop, shutdown, TcpRec}; +handle_cast(Msg, TcpRec) -> + warning_msg("received unexpected message: " + "~n~w", [Msg]), + {noreply, TcpRec}. + +%%----------------------------------------------------------------- +%% Func: handle_info/2 +%% Description: Handling non call/cast messages. Incomming messages +%% from the socket and exit messages. +%%----------------------------------------------------------------- +handle_info({tcp_closed, _Socket}, TcpRec) -> + {stop, shutdown, TcpRec}; +handle_info({tcp_error, _Socket}, TcpRec) -> + {stop, shutdown, TcpRec}; +handle_info({tcp, Socket, <<3:8, _X:8, Length:16, Msg/binary>>}, + #megaco_tcp{socket = Socket, serialize = false} = TcpRec) + when Length < ?GC_MSG_LIMIT -> + #megaco_tcp{module = Mod, receive_handle = RH} = TcpRec, + incNumInMessages(Socket), + incNumInOctets(Socket, 4+size(Msg)), + apply(Mod, receive_message, [RH, self(), Socket, Msg]), + inet:setopts(Socket, [{active, once}]), + {noreply, TcpRec}; +handle_info({tcp, Socket, <<3:8, _X:8, Length:16, Msg/binary>>}, + #megaco_tcp{socket = Socket, serialize = false} = TcpRec) -> + #megaco_tcp{module = Mod, receive_handle = RH} = TcpRec, + incNumInMessages(Socket), + incNumInOctets(Socket, 4+size(Msg)), + receive_message(Mod, RH, Socket, Length, Msg), + inet:setopts(Socket, [{active, once}]), + {noreply, TcpRec}; +handle_info({tcp, Socket, <<3:8, _X:8, _Length:16, Msg/binary>>}, + #megaco_tcp{socket = Socket, serialize = true} = TcpRec) -> + #megaco_tcp{module = Mod, receive_handle = RH} = TcpRec, + incNumInMessages(Socket), + incNumInOctets(Socket, 4+size(Msg)), + process_received_message(Mod, RH, Socket, Msg), + inet:setopts(Socket, [{active, once}]), + {noreply, TcpRec}; +handle_info({tcp, Socket, Msg}, TcpRec) -> + incNumErrors(Socket), + error_msg("received bad tpkt packet: " + "~n~w", [Msg]), + {noreply, TcpRec}; +handle_info(Info, TcpRec) -> + warning_msg("received unexpected info: " + "~n~p", [Info]), + {noreply, TcpRec}. + + +process_received_message(Mod, RH, SH, Msg) -> + case (catch Mod:process_received_message(RH, self(), SH, Msg)) of + ok -> + ok; + Error -> + error_msg("failed processing received message: " + "~n~p", [Error]), + ok + end. + + +receive_message(Mod, RH, SendHandle, Length, Msg) -> + Opts = [link , {min_heap_size, ?HEAP_SIZE(Length)}], + spawn_opt(?MODULE, handle_received_message, + [Mod, RH, self(), SendHandle, Msg], Opts), + ok. + + +handle_received_message(Mod, RH, Parent, SH, Msg) -> + Mod:process_received_message(RH, Parent, SH, Msg), + unlink(Parent), + exit(normal). + + +%%----------------------------------------------------------------- +%% Func: terminate/2 +%% Description: Termination function for the generic server +%%----------------------------------------------------------------- +terminate(shutdown = _Reason, TcpRec) -> + ?tcp_debug(TcpRec, "tcp connection handler terminating", [self(),_Reason]), + ok; + +terminate(Reason, TcpRec) -> + ?tcp_debug(TcpRec, "tcp connection handler terminating", [self(), Reason]), + SchedId = erlang:system_info(scheduler_id), + SchedNum = erlang:system_info(schedulers), + ProcCount = erlang:system_info(process_count), + ProcLimit = erlang:system_info(process_limit), + ProcMemUsed = erlang:memory(processes_used), + ProcMemAlloc = erlang:memory(processes), + MemTot = erlang:memory(total), + error_msg("abormal termination: " + "~n Scheduler id: ~p" + "~n Num scheduler: ~p" + "~n Process count: ~p" + "~n Process limit: ~p" + "~n Memory used by erlang processes: ~p" + "~n Memory allocated by erlang processes: ~p" + "~n The total amount of memory allocated: ~p" + "~n~p", + [SchedId, SchedNum, ProcCount, ProcLimit, + ProcMemUsed, ProcMemAlloc, MemTot, Reason]), + ok. + + +%%----------------------------------------------------------------- +%% Func: code_change/3 +%% Descrition: Handles code change messages during upgrade. +%%----------------------------------------------------------------- +code_change(_OldVsn, S, _Extra) -> + ?d("code_change -> entry with" + "~n OldVsn: ~p" + "~n S: ~p" + "~n Extra: ~p", [_OldVsn, S, _Extra]), + {ok, S}. + + + +%%----------------------------------------------------------------- +%% Func: incNumInMessages/1, incNumInOctets/2, incNumErrors/1 +%% Description: SNMP counter increment functions +%% +%%----------------------------------------------------------------- +incNumInMessages(Socket) -> + incCounter({Socket, medGwyGatewayNumInMessages}, 1). + +incNumInOctets(Socket, NumOctets) -> + incCounter({Socket, medGwyGatewayNumInOctets}, NumOctets). + +incNumErrors(Socket) -> + incCounter({Socket, medGwyGatewayNumErrors}, 1). + +incCounter(Key, Inc) -> + ets:update_counter(megaco_tcp_stats, Key, Inc). + + +%% info_msg(F, A) -> +%% ?megaco_info("TCP connection handler " ++ F, A). + +warning_msg(F, A) -> + ?megaco_warning("TCP connection handler: " ++ F, A). + +error_msg(F, A) -> + ?megaco_error("TCP connection handler: " ++ F, A). + + +call(Pid, Req) -> + gen_server:call(Pid, Req, infinity). + |