hello / erlang / hf_listener.erl

%% -*- coding: utf-8 -*-
-module(hf_listener).
-author('kuenishi@gmail.com').
-behaviour(gen_server).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, code_change/3, terminate/2 ]).

-export([ start_link/0,	 start_link/1 ]).

-ifdef(UNITTEST).
-include_lib("eunit/include/eunit.hrl").
-endif.

-record( hfsrv, { lsocket, ref } ).

-spec start_link()->{ok, pid()}.
start_link()->   start_link([]).

-spec start_link( list() )->{ok, pid()}.
start_link(Options)->
    gen_server:start_link({local, ?MODULE},?MODULE, [Options], [{debug, [trace,log,statistics]}]).

init(_Options)->
    process_flag(trap_exit, true),
    Options = [binary, {packet, 0}, {reuseaddr, true}, {active,once},
	      {keepalive, true}, {backlog, 30}],
    {ok, ListenSocket} = gen_tcp:listen(8878, Options),
    {ok, Ref} = prim_inet:async_accept(ListenSocket, -1),
    io:format("~p: listening ~p.~n", [?MODULE, 8878]),
    {ok, #hfsrv{lsocket=ListenSocket, ref=Ref}}.

handle_call(stop, _, State)->    {stop, normal, ok, State};
handle_call(_, _From, State)->   {reply, ok, State}.
    
handle_cast(_,State)->    {noreply, State}.

handle_info({inet_async, LSock, Ref, {ok, Socket}}, State)->
    {ok, Mod} = inet_db:lookup_socket(LSock),
    inet_db:register_socket(Socket, Mod),
    {ok, {PeerAddress, PeerPort}} = inet:peername(Socket),
    ChildRef = list_to_atom( lists:flatten(io_lib:format("~p:~p:~p", [inet_parse:ntoa(PeerAddress), PeerPort, Socket]))),
    {ok, Pid} = supervisor:start_child(get_parent(),
				       hf_session:getspec(ChildRef, Socket) ),
    ok = gen_tcp:controlling_process(Socket, Pid),
    ok=gen_server:cast(Pid,go),
    case prim_inet:async_accept(LSock, -1) of
	{ok, NewRef} ->
	    {noreply, State#hfsrv{ref=NewRef}};
	Error ->
	    {stop, {cannot_accept, Error}, none}
    end;
    
handle_info(Msg,State)->
    erlang:display(Msg),
    {noreply, State}.

terminate(Reason,State)-> 
    io:format("~p (~p, ~p) terminating.~n", [?MODULE, self(), State]),
    gen_tcp:close(State#hfsrv.lsocket),
    {shutdown, Reason}.
    
code_change(_,_,State)->
    {ok, State}.

get_parent() ->
    case get('$ancestors') of
 	[Parent | _] when is_pid(Parent) ->
	    Parent;
 	[Parent | _] when is_atom(Parent) ->
 	    case whereis(Parent) of
		Pid when is_pid(Pid)->
		    Pid;
		undefined->
		    none
	    end;
 	_ ->
 	    exit(process_was_not_started_by_proc_lib)
    end.

-ifdef(EUNIT).

my_test()-> % just testing start&stop
    {ok,Pid}=hf_listener:start_link(),
    ?assertMatch(_ when is_pid(Pid), Pid),
    ok=gen_server:call(Pid, stop).

-endif.
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.