%%
%% %CopyrightBegin%
%% 
%% Copyright Ericsson AB 1999-2021. All Rights Reserved.
%% 
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%%     http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%% 
%% %CopyrightEnd%
%%

%%
%%-----------------------------------------------------------------
%% Purpose: Waiting in accept for new connections.
%%-----------------------------------------------------------------
-module(megaco_tcp_accept).

%%-----------------------------------------------------------------
%% Include files
%%-----------------------------------------------------------------
-include_lib("megaco/src/tcp/megaco_tcp.hrl").
-include_lib("megaco/src/app/megaco_internal.hrl"). 


-define(d1(F, A), ?d("~p " ++ F, [self()|A])).
-define(d2(F),    ?d1(F, [])).


%%-----------------------------------------------------------------
%% External exports
%%-----------------------------------------------------------------
-export([
	 start_link/1
	]).


%%-----------------------------------------------------------------
%% Internal exports
%%-----------------------------------------------------------------
-export([
	 net_accept/4
	]).


%%-----------------------------------------------------------------
%% External interface functions
%%-----------------------------------------------------------------
%%-----------------------------------------------------------------
%% Func: start
%% Description: Starts the proces that makes the accept call.
%%-----------------------------------------------------------------
start_link({TcpRec, SupPid, Listen}) ->
    Args = [TcpRec, SupPid, Listen, self()],
    Pid  = proc_lib:spawn_link(?MODULE, net_accept, Args),
    {ok, Pid}.

%%-----------------------------------------------------------------
%% Internal Interface Functions
%%-----------------------------------------------------------------
%%-----------------------------------------------------------------
%% Func: net_accept
%% Description: Loop function which calls accept and
%%              spawns a connection process when there is an initial
%%              contact.
%%-----------------------------------------------------------------
net_accept(TcpRec, SupPid, ListenFd, Parent) ->
    do_accept(TcpRec, SupPid, ListenFd), 
    net_accept(TcpRec, SupPid, ListenFd, Parent).

do_accept(Tcp, Sup, Fd) ->
    case gen_tcp:accept(Fd) of
	{ok, S} ->
	    ?d1("do_accept -> accepted: "
		"~n   S: ~p", [S]),
	    case megaco_tcp:start_connection(Sup, Tcp#megaco_tcp{socket = S}) of
		{ok, Pid} ->
		    ?d1("do_accept -> connection started"
			"~n   Pid: ~p", [Pid]),
		    case gen_tcp:controlling_process(S, Pid) of
			ok ->
			    ?d2("do_accept -> control transferred"),
			    ok;
			{error, _Reason} ->
			    ?d1("do_accept -> "
				"failed changing controlling process: "
				"n   _Reason: ~p", [_Reason]),
			    tcp_clear(S),
			    gen_tcp:close(S)	
		    end;
			    
		{error, _Reason} ->
		    ?d1("do_accept -> failed starting connection: "
			"~n   _Reason: ~p", [_Reason]),
		    tcp_clear(S),
		    gen_tcp:close(S)	
	    end;
	{error, _Reason} ->
	    ?d1("do_accept -> accept failed: "
		"~n   _Reason: ~p", [_Reason]),
	    ok
    end.
    

tcp_clear(Socket) ->
    receive
        {tcp, Socket, _Data} ->
            tcp_clear(Socket);
        {tcp_closed, Socket} ->
            tcp_clear(Socket);
        {tcp_error, Socket} ->
            tcp_clear(Socket)
    after 0 -> 
            ok
    end.



%%-----------------------------------------------------------------

%% formated_timestamp() ->
%%     format_timestamp(os:timestamp()).

%% format_timestamp(TS) ->
%%     megaco:format_timestamp(TS).

%% d(F) ->
%%     d(F, []).

%% d(F, A) ->
%%     io:format("*** [~s] ~p ~w " ++ F ++ "~n",
%%               [formated_timestamp(), self(), ?MODULE | A]).
