Christopher Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 1 | %%% 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 | |
| 38 | super() -> |
| 39 | tServer. |
| 40 | |
| 41 | %%% inspect(This) -> string() |
| 42 | |
| 43 | inspect(This) -> |
| 44 | ?FORMAT_ATTR(acceptor) ++ ", " ++ |
| 45 | ?FORMAT_ATTR(listenSocket) ++ ", " ++ |
| 46 | ?FORMAT_ATTR(port). |
| 47 | |
| 48 | %%% |
| 49 | %%% class methods |
| 50 | %%% |
| 51 | |
| 52 | new(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 | |
| 56 | new(Port, Handler, Processor, ServerTransport) -> |
| 57 | new(Port, Handler, Processor, ServerTransport, nil, nil). |
| 58 | |
| 59 | new(Port, Handler, Processor, ServerTransport, TransportFactory) -> |
| 60 | new(Port, Handler, Processor, ServerTransport, TransportFactory, nil). |
| 61 | |
| 62 | % listenSocket, acceptor, port |
| 63 | |
| 64 | effectful_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 Piro | 3b63fe4 | 2007-10-19 21:34:31 +0000 | [diff] [blame] | 72 | ?INFO("thrift server listening on port ~p", [Port]), |
Christopher Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 73 | |
| 74 | This1 = oop:set(This, listenSocket, ListenSocket), |
| 75 | |
| 76 | %% spawn acceptor |
| 77 | {_Acceptor, This2} = effectful_new_acceptor(This1), |
| 78 | |
Christopher Piro | 5b3a8f7 | 2007-08-01 22:27:37 +0000 | [diff] [blame] | 79 | {ok, This2}; |
| 80 | |
| 81 | {error, eaddrinuse} -> |
Christopher Piro | 3b63fe4 | 2007-10-19 21:34:31 +0000 | [diff] [blame] | 82 | ?ERROR("thrift couldn't bind port ~p, address in use", [Port]), |
Christopher Piro | 5b3a8f7 | 2007-08-01 22:27:37 +0000 | [diff] [blame] | 83 | {{error, eaddrinuse}, This} %% state before the accept |
Christopher Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 84 | end. |
| 85 | |
| 86 | effectful_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 Piro | 5b3a8f7 | 2007-08-01 22:27:37 +0000 | [diff] [blame] | 104 | catches(_This, _Pid, normal) -> |
Christopher Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 105 | 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 Piro | 3b63fe4 | 2007-10-19 21:34:31 +0000 | [diff] [blame] | 114 | %% ?INFO( "Terminating error: ~p~n", [Reason]), % added %% |
Christopher Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 115 | %% gen_tcp:close(State#state.listen_socket), %% |
| 116 | %% ok. %% |
| 117 | %% %% |