1 %%% Copyright (c) 2007- Facebook
2 %%% Distributed under the Thrift Software License
4 %%% See accompanying file LICENSE or visit the Thrift site at:
5 %%% http://developers.facebook.com/thrift/
10 -include("thrift.hrl").
11 -include("tApplicationException.hrl").
12 -include("transport/tTransportException.hrl").
13 -include("protocol/tProtocolException.hrl").
14 -include("transport/tServerSocket.hrl").
15 -include("transport/tErlAcceptor.hrl").
17 -include_lib("kernel/include/inet.hrl").
21 -export([attr
/4, super
/0, inspect
/1]).
23 -export([new
/3, accept
/4]).
27 %%% 'super' is required unless ?MODULE is a base class
31 ?
DEFINE_ATTR(serverPid
);
32 ?
DEFINE_ATTR(transportFactory
);
33 ?
DEFINE_ATTR(protocolFactory
).
36 %%% behavior callbacks
39 %%% super() -> SuperModule = atom()
45 %%% inspect(This) -> string()
48 ?
FORMAT_ATTR(serverPid
) ++ ", " ++
49 ?
FORMAT_ATTR(transportFactory
) ++ ", " ++
50 ?
FORMAT_ATTR(protocolFactory
).
56 new(ServerPid
, TF
, PF
) ->
57 Super
= (super()):new(),
58 #?MODULE
{super
= Super
,
59 serverPid
= ServerPid
,
60 transportFactory
= TF
,
68 accept(This
, ListenSocket
, GP
, Handler
) ->
69 ServerPid
= oop:get(This
, serverPid
),
71 case catch gen_tcp:accept(ListenSocket
) of
73 ?
C0(ServerPid
, effectful_new_acceptor
), % cast to create new acceptor
75 AddrString
= render_addr(Socket
),
76 ?
INFO("thrift connection accepted from ~s", [AddrString
]),
78 Client
= oop:start_new(tSocket
, []),
79 ?
R1(Client
, effectful_setHandle
, Socket
),
81 %% cpiro: OPAQUE!! Trans = Client
82 TF
= oop:get(This
, transportFactory
),
83 Trans
= ?
F1(TF
, getTransport
, Client
),
85 %% cpiro: OPAQUE!! Prot = start_new(tBinaryProtocol, [Trans])
86 PF
= oop:get(This
, protocolFactory
),
87 Prot
= ?
F1(PF
, getProtocol
, Trans
),
90 Processor
= oop:start_new(tErlProcessor
, [GP
, Handler
]),
93 receive_loop(This
, Processor
, Prot
, Prot
)
96 ?
INFO("thrift connection timed out from ~s", [AddrString
]);
98 %% cpiro: i think the extra entry on the stack is always from receive_loop
99 %% the below case shouldn't happen then? if we move this catch inside
100 %% we'll probably need this case and not the next one
102 %% exit:{thrift_exception, E} ->
103 %% handle_exception(E, AddrString, no2);
105 exit:{{thrift_exception
, E
}, Stack1
} ->
106 handle_exception(E
, AddrString
, Stack1
);
109 ?
ERROR("some other error ~p in tErlAcceptor: ~p", [Class
, Else
])
114 R
= thrift_utils:sformat("accept() failed: ~p", [Else
]),
115 tException:throw(tTransportException
, [R
])
119 handle_exception(E
, AddrString
, Stack1
) ->
120 case tException:read(E
) of
121 none
-> % not a tException
122 ?
ERROR("not really a tException: ~p", [exit, E
]);
124 {tProtocolException
, ?tProtocolException_BAD_VERSION
, _
} ->
125 ?
INFO("thrift missing version from ~s", [AddrString
]);
127 {tTransportException
, ?tTransportException_NOT_OPEN
, _
} ->
128 ?
INFO("thrift connection closed from ~s", [AddrString
]);
131 Where
= "thrift tErlAcceptor caught a tException",
132 ?
ERROR("~s", [tException:inspect_with_backtrace(E
, Where
, Stack1
)])
135 %% always calls itself ... only way to escape is through an exit
136 receive_loop(This
, Processor
, Iprot
, Oprot
) ->
137 case ?
R2(Processor
, process, Iprot
, Oprot
) of
139 case tException:read(Reason
) of
141 ?
ERROR("thrift handler returned something weird: {error, ~p}", [Reason
]);
143 Where
= "thrift processor/handler caught a tException",
144 ?
ERROR("~s", [tException:inspect_with_backtrace(Reason
, Where
)])
146 receive_loop(This
, Processor
, Iprot
, Oprot
);
148 ?
INFO("thrift request: ~p", [Value
]),
149 receive_loop(This
, Processor
, Iprot
, Oprot
)
154 %% @param Socket the socket in question
155 %% TODO(cpiro): there probably needs to be a switch for DoLookup somewhere prominent and outside the lib,
156 %% probably at the "application" level
157 render_addr(Socket
) ->
159 {ok
, {Peer
, Port
}} = inet:peername(Socket
),
163 case catch inet:gethostbyaddr(Peer
) of
165 thrift_utils:sformat("~s:~p", [Hostent#hostent
.h_name
, Port
]);
170 {A
,B
,C
,D
} when not DoLookup
->
171 thrift_utils:sformat("~p.~p.~p.~p:~p", [A
,B
,C
,D
,Port
])