Globalize the etorrent_t_peer_group_mgr and rename it to etorrent_choker while here.
[etorrent.git] / lib / etorrent-1.0 / src / etorrent_acceptor.erl
blobeb487ff9e2217a45d91d2810c377265dafc93ce7
1 %%%-------------------------------------------------------------------
2 %%% File : acceptor.erl
3 %%% Author : Jesper Louis Andersen <jesper.louis.andersen@gmail.com>
4 %%% Description : Accept new connections from the network.
5 %%%
6 %%% Created : 30 Jul 2007 by Jesper Louis Andersen <jesper.louis.andersen@gmail.com>
7 %%%-------------------------------------------------------------------
8 -module(etorrent_acceptor).
10 -behaviour(gen_server).
12 -include("etorrent_mnesia_table.hrl").
14 %% API
15 -export([start_link/0]).
17 %% gen_server callbacks
18 -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
19 terminate/2, code_change/3]).
21 -record(state, { listen_socket = none}).
23 %%====================================================================
24 %% API
25 %%====================================================================
26 %%--------------------------------------------------------------------
27 %% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
28 %% Description: Starts the server
29 %%--------------------------------------------------------------------
30 start_link() ->
31 gen_server:start_link(?MODULE, [], []).
33 %%====================================================================
34 %% gen_server callbacks
35 %%====================================================================
37 %%--------------------------------------------------------------------
38 %% Function: init(Args) -> {ok, State} |
39 %% {ok, State, Timeout} |
40 %% ignore |
41 %% {stop, Reason}
42 %% Description: Initiates the server
43 %%--------------------------------------------------------------------
44 init([]) ->
45 {ok, ListenSocket} = etorrent_listener:get_socket(),
46 {ok, #state{ listen_socket = ListenSocket}, 0}.
48 %%--------------------------------------------------------------------
49 %% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
50 %% {reply, Reply, State, Timeout} |
51 %% {noreply, State} |
52 %% {noreply, State, Timeout} |
53 %% {stop, Reason, Reply, State} |
54 %% {stop, Reason, State}
55 %% Description: Handling call messages
56 %%--------------------------------------------------------------------
57 handle_call(_Request, _From, State) ->
58 Reply = ok,
59 {reply, Reply, State}.
61 %%--------------------------------------------------------------------
62 %% Function: handle_cast(Msg, State) -> {noreply, State} |
63 %% {noreply, State, Timeout} |
64 %% {stop, Reason, State}
65 %% Description: Handling cast messages
66 %%--------------------------------------------------------------------
67 handle_cast(_Msg, State) ->
68 {noreply, State}.
70 %%--------------------------------------------------------------------
71 %% Function: handle_info(Info, State) -> {noreply, State} |
72 %% {noreply, State, Timeout} |
73 %% {stop, Reason, State}
74 %% Description: Handling all non call/cast messages
75 %%--------------------------------------------------------------------
76 handle_info(timeout, S) ->
77 case gen_tcp:accept(S#state.listen_socket) of
78 {ok, Socket} -> handshake(Socket),
79 {noreply, S, 0};
80 {error, closed} -> {noreply, S, 0};
81 {error, econnaborted} -> {noreply, S, 0};
82 {error, enotconn} -> {noreply, S, 0};
83 {error, E} -> {stop, E, S}
84 end.
86 %%--------------------------------------------------------------------
87 %% Function: terminate(Reason, State) -> void()
88 %% Description: This function is called by a gen_server when it is about to
89 %% terminate. It should be the opposite of Module:init/1 and do any necessary
90 %% cleaning up. When it returns, the gen_server terminates with Reason.
91 %% The return value is ignored.
92 %%--------------------------------------------------------------------
93 terminate(_Reason, _State) ->
94 ok.
96 %%--------------------------------------------------------------------
97 %% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
98 %% Description: Convert process state when code is changed
99 %%--------------------------------------------------------------------
100 code_change(_OldVsn, State, _Extra) ->
101 {ok, State}.
103 %%--------------------------------------------------------------------
104 %%% Internal functions
105 %%--------------------------------------------------------------------
107 handshake(Socket) ->
108 case etorrent_peer_communication:recieve_handshake(Socket) of
109 {ok, ReservedBytes, InfoHash, PeerId} ->
110 lookup_infohash(Socket, ReservedBytes, InfoHash, PeerId);
111 {error, _Reason} ->
112 gen_tcp:close(Socket),
114 end.
116 lookup_infohash(Socket, ReservedBytes, InfoHash, PeerId) ->
117 case etorrent_tracking_map:select({infohash, InfoHash}) of
118 {atomic, [#tracking_map { _ = _}]} ->
119 start_peer(Socket, ReservedBytes, PeerId, InfoHash);
120 {atomic, []} ->
121 gen_tcp:close(Socket),
123 end.
125 start_peer(Socket, ReservedBytes, PeerId, InfoHash) ->
126 {ok, {Address, Port}} = inet:peername(Socket),
127 case etorrent_choker:new_incoming_peer(Address, Port, PeerId, InfoHash) of
128 {ok, PeerProcessPid} ->
129 case gen_tcp:controlling_process(Socket, PeerProcessPid) of
130 ok -> etorrent_t_peer_recv:complete_handshake(PeerProcessPid,
131 ReservedBytes,
132 Socket,
133 PeerId),
135 {error, enotconn} ->
136 etorrent_t_peer_recv:stop(PeerProcessPid),
138 end;
139 already_enough_connections ->
141 connect_to_ourselves ->
142 gen_tcp:close(Socket),
144 bad_peer ->
145 error_logger:info_report([peer_id_is_bad, PeerId]),
146 gen_tcp:close(Socket),
148 end.