blob: 4e1f6fc507dc5a9997f06dce05f384c8f87e1e24 [file] [log] [blame]
Christopher Piro094823a2007-07-18 00:26:12 +00001%%% Copyright (c) 2007- Facebook
2%%% Distributed under the Thrift Software License
3%%%
4%%% See accompanying file LICENSE or visit the Thrift site at:
5%%% http://developers.facebook.com/thrift/
6
7-module(tErlServer).
8
9-include("oop.hrl").
10
11-include("thrift.hrl").
12-include("transport/tTransportException.hrl").
13-include("server/tErlServer.hrl").
14
15-behavior(oop).
16
17-export([attr/4, super/0, inspect/1]).
18
19-export([new/6, new/5, new/4, effectful_serve/1, effectful_new_acceptor/1, catches/3]).
20
21%%%
22%%% define attributes
23%%% 'super' is required unless ?MODULE is a base class
24%%%
25
26?DEFINE_ATTR(super);
27?DEFINE_ATTR(acceptor);
28?DEFINE_ATTR(listenSocket);
29?DEFINE_ATTR(port).
30
31%%%
32%%% behavior callbacks
33%%%
34
35%%% super() -> SuperModule = atom()
36%%% | none
37
38super() ->
39 tServer.
40
41%%% inspect(This) -> string()
42
43inspect(This) ->
44 ?FORMAT_ATTR(acceptor) ++ ", " ++
45 ?FORMAT_ATTR(listenSocket) ++ ", " ++
46 ?FORMAT_ATTR(port).
47
48%%%
49%%% class methods
50%%%
51
52new(Port, Handler, Processor, ServerTransport, TransportFactory, ProtocolFactory) ->
53 Super = (super()):new(Handler, Processor, ServerTransport, TransportFactory, ProtocolFactory),
54 #?MODULE{super=Super, port=Port, listenSocket=nil, acceptor=nil}.
55
56new(Port, Handler, Processor, ServerTransport) ->
57 new(Port, Handler, Processor, ServerTransport, nil, nil).
58
59new(Port, Handler, Processor, ServerTransport, TransportFactory) ->
60 new(Port, Handler, Processor, ServerTransport, TransportFactory, nil).
61
62% listenSocket, acceptor, port
63
64effectful_serve(This) ->
65 Port = oop:get(This, port),
66
67 Options = [binary, {packet, 0}, {active, false}],
68
69 %% listen
70 case gen_tcp:listen(Port, Options) of
71 {ok, ListenSocket} ->
Christopher Piro3b63fe42007-10-19 21:34:31 +000072 ?INFO("thrift server listening on port ~p", [Port]),
Christopher Piro094823a2007-07-18 00:26:12 +000073
74 This1 = oop:set(This, listenSocket, ListenSocket),
75
76 %% spawn acceptor
77 {_Acceptor, This2} = effectful_new_acceptor(This1),
78
Christopher Piro5b3a8f72007-08-01 22:27:37 +000079 {ok, This2};
80
81 {error, eaddrinuse} ->
Christopher Piro3b63fe42007-10-19 21:34:31 +000082 ?ERROR("thrift couldn't bind port ~p, address in use", [Port]),
Christopher Piro5b3a8f72007-08-01 22:27:37 +000083 {{error, eaddrinuse}, This} %% state before the accept
Christopher Piro094823a2007-07-18 00:26:12 +000084 end.
85
86effectful_new_acceptor(This) ->
87 ListenSocket = oop:get(This, listenSocket),
88 Processor = oop:get(This, processor), %% cpiro: generated processor, not the "actual" processor
89 Handler = oop:get(This, handler),
90
91 TF = oop:get(This, transportFactory),
92 PF = oop:get(This, protocolFactory),
93
94 tErlAcceptor = oop:get(This, serverTransport), %% cpiro: only supported ServerTransport
95
96 ServerPid = self(),
97 Acceptor = oop:start_new(tErlAcceptor, [ServerPid, TF, PF]),
98 ?C3(Acceptor, accept, ListenSocket, Processor, Handler),
99
100 This1 = oop:set(This, acceptor, Acceptor),
101
102 {Acceptor, This1}.
103
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000104catches(_This, _Pid, normal) ->
Christopher Piro094823a2007-07-18 00:26:12 +0000105 ok.
106
107%% %% The current acceptor has died, wait a little and try again %%
108%% handle_info({'EXIT', Pid, _Abnormal}, #state{acceptor=Pid} = State) -> %%
109%% timer:sleep(2000), %%
110%% iserve_socket:start_link(self(), State#state.listen_socket, State#state.port), %%
111%% {noreply,State}; %%
112
113%% terminate(Reason, State) -> %%
Christopher Piro3b63fe42007-10-19 21:34:31 +0000114%% ?INFO( "Terminating error: ~p~n", [Reason]), % added %%
Christopher Piro094823a2007-07-18 00:26:12 +0000115%% gen_tcp:close(State#state.listen_socket), %%
116%% ok. %%
117%% %%