diff options
author | Jan Huwald <jh@sotun.de> | 2012-06-06 13:07:14 (GMT) |
---|---|---|
committer | Jan Huwald <jh@sotun.de> | 2012-06-06 13:07:14 (GMT) |
commit | fb4ff27d8d9ff00a10d9ee52b2e0404323186fc2 (patch) | |
tree | 9382a498782d187c36c858e381c49e49e6a4776a | |
parent | f33aa706efbcfd0663a9bda060972081ea47e8f4 (diff) |
correctly handle half-open connections
-rw-r--r-- | ereproxy_server.erl | 25 |
1 files changed, 15 insertions, 10 deletions
diff --git a/ereproxy_server.erl b/ereproxy_server.erl index ef59144..a6e9803 100644 --- a/ereproxy_server.erl +++ b/ereproxy_server.erl @@ -1,6 +1,6 @@ -module(ereproxy_server). -behavior(supervisor). --export([start_link/1, init/1, start_link_acceptor/2, acceptor/2, con/2, pass_through/1]). +-export([start_link/1, init/1, start_link_acceptor/2, acceptor/2, con/2, pass_through/2]). -include("ereproxy_config.hrl"). @@ -36,7 +36,8 @@ tp_t2c(ssl) -> ssl_closed. %%% listen and accept on a single port start_link_acceptor(CfgMod, {Method, ListenPort}) -> - DefaultOpts = [binary, {packet, 0}, {active, false}, {reuseaddr, true}], + DefaultOpts = [binary, {packet, 0}, {active, false}, + {exit_on_close, false}, {reuseaddr, true}], {TP, Opts} = case Method of http -> {tcp, DefaultOpts}; @@ -67,7 +68,8 @@ con(CfgMod, ClientCon = {TP, ClientSock}) -> {ConHead, HostName} = parse_header(MaxCache, ClientCon), {Host, Port} = CfgMod:select_destination(HostName), % connect to destination - {ok, ServerSock} = gen_tcp:connect(Host, Port, [binary, {packet, 0}, {active, once}]), + TCPOpts = [binary, {packet, 0}, {active, once}, {exit_on_close, false}], + {ok, ServerSock} = gen_tcp:connect(Host, Port, TCPOpts), % log redirection details {ok, {SrcAddr, SrcPort}} = tp(TP, peername, [ClientSock]), {ok, {RedAddr, RedPort}} = inet:sockname(ServerSock), @@ -75,7 +77,7 @@ con(CfgMod, ClientCon = {TP, ClientSock}) -> ereproxy_log ! {{SrcAddr, SrcPort}, {RedAddr, RedPort}, {DstAddr, DstPort}}, % pass through connection gen_tcp:send(ServerSock, ConHead), - pass_through([ClientCon, {tcp, ServerSock}]). + pass_through([ClientCon, {tcp, ServerSock}], 2). %% parse_header: search for the "^Host: " field @@ -114,18 +116,21 @@ parse_header(MaxCache, Con) -> parse_header(MaxCache, Con, <<>>, <<>>, <<>>). %% connect client and destination server -pass_through(Cons) -> +pass_through(_Cons, 0) -> + connections_closed; +pass_through(Cons, NumOpen) -> receive {STP, Src, Data} -> [{DTP, Dst}] = lists:subtract(Cons, [{STP, Src}]), ok = tp(STP, setopts, [Src, [{active, once}]]), ok = tp(DTP, send, [Dst, Data]), - ?MODULE:pass_through(Cons); % allow code update + ?MODULE:pass_through(Cons, NumOpen); % allow code update {STP_Closed, Src} -> STP = tp_c2t(STP_Closed), [{DTP, Dst}] = lists:subtract(Cons, [{STP, Src}]), - ok = tp(DTP, close, [Dst]), - connections_closed - % TODO: check if this is standart compliant; we close both - % sides if one side closes one channel! + ok = case NumOpen of + 2 -> tp(DTP, shutdown, [Dst, write]); + 1 -> ok + end, + ?MODULE:pass_through(Cons, NumOpen-1) end. |