Skip to content

Commit f5a19c4

Browse files
committed
fix timeout issue: ensure to use proper timeout
1 parent 5166973 commit f5a19c4

File tree

1 file changed

+40
-27
lines changed

1 file changed

+40
-27
lines changed

src/hackney_happy.erl

+40-27
Original file line numberDiff line numberDiff line change
@@ -29,41 +29,54 @@ do_connect(Hostname, Port, Opts, Timeout) when is_tuple(Hostname) ->
2929
end
3030
end;
3131
do_connect(Hostname, Port, Opts, Timeout) ->
32-
?report_debug("happy eyeballs, try to connect using IPv6", [{hostname, Hostname}, {port, Port}]),
32+
?report_debug("happy eyeballs, try to connect using IPv6", [{hostname, Hostname}, {port, Port}, {timeout, Timeout}]),
3333
Self = self(),
34-
{Ipv6Addrs, IPv4Addrs} = getaddrs(Hostname),
35-
{Pid6, MRef6} = spawn_monitor(fun() -> try_connect(Ipv6Addrs, Port, Opts, Self) end),
36-
TRef = erlang:start_timer(?TIMEOUT, self(), try_ipv4),
37-
receive
38-
{'DOWN', MRef6, _Type, _Pid, {happy_connect, OK}} ->
39-
_ = erlang:cancel_timer(TRef, []),
40-
OK;
41-
{'DOWN', MRef6, _Type, _Pid, _Info} ->
42-
_ = erlang:cancel_timer(TRef, []),
43-
{Pid4, MRef4} = spawn_monitor(fun() -> try_connect(IPv4Addrs, Port, Opts, Self) end),
34+
case getaddrs(Hostname) of
35+
{[], []} -> {error, nxdomain};
36+
{[], IPv4Addrs} ->
37+
?report_trace("happy connect: try IPv4 only", []),
38+
{Pid4, MRef4} = spawn_monitor(fun() -> try_connect(IPv4Addrs, Port, Opts, Timeout, Self) end),
4439
do_connect_2(Pid4, MRef4, Timeout);
45-
{timeout, TRef, try_ipv4} ->
46-
PidRef4 = spawn_monitor(fun() -> try_connect(IPv4Addrs, Port, Opts, Self) end),
47-
do_connect_1(PidRef4, {Pid6, MRef6}, Timeout)
48-
after Timeout ->
40+
{Ipv6Addrs, []} ->
41+
?report_trace("happy connect: try IPv6 only", []),
42+
{Pid6, MRef6} = spawn_monitor(fun() -> try_connect(Ipv6Addrs, Port, Opts, Timeout, Self) end),
43+
do_connect_2(Pid6, MRef6, Timeout);
44+
{Ipv6Addrs, IPv4Addrs} ->
45+
{Pid6, MRef6} = spawn_monitor(fun() -> try_connect(Ipv6Addrs, Port, Opts, Timeout, Self) end),
46+
TRef = erlang:start_timer(?TIMEOUT, self(), try_ipv4),
47+
receive
48+
{'DOWN', MRef6, _Type, _Pid, {happy_connect, OK}} ->
4949
_ = erlang:cancel_timer(TRef, []),
50-
erlang:demonitor(MRef6, [flush]),
51-
{error, connect_timeout}
50+
OK;
51+
{'DOWN', MRef6, _Type, _Pid, _Info} ->
52+
_ = erlang:cancel_timer(TRef, []),
53+
{Pid4, MRef4} = spawn_monitor(fun() -> try_connect(IPv4Addrs, Port, Opts, Timeout, Self) end),
54+
do_connect_2(Pid4, MRef4, Timeout);
55+
{timeout, TRef, try_ipv4} ->
56+
?report_trace("happy connect: try IPv4", []),
57+
PidRef4 = spawn_monitor(fun() -> try_connect(IPv4Addrs, Port, Opts, Timeout, Self) end),
58+
do_connect_1(PidRef4, {Pid6, MRef6}, Timeout)
59+
after Timeout ->
60+
?report_trace("happy, connect timeout", []),
61+
_ = erlang:cancel_timer(TRef, []),
62+
erlang:demonitor(MRef6, [flush]),
63+
{error, connect_timeout}
64+
end
5265
end.
5366

5467

5568
do_connect_1({Pid4, MRef4}, {Pid6, MRef6}, Timeout) ->
5669
receive
5770
{'DOWN', MRef4, _Type, _Pid, {happy_connect, OK}} ->
58-
?report_trace("happy_connect ~p", [OK]),
71+
?report_trace("happy_connect: ~p", [OK]),
5972
connect_gc(Pid6, MRef6),
6073
OK;
61-
{'DOWN', MRef4, _Type, _Pid, _Info} ->
62-
do_connect_2(Pid6, MRef6, Timeout);
63-
{'DOWN', MRef6, _Type, _Pid, {happy_connect, OK}} ->
74+
{'DOWN', MRef6, _Type, _Pid, {happy_connect, OK}} ->
6475
?report_trace("happy_connect ~p", [OK]),
6576
connect_gc(Pid4, MRef4),
6677
OK;
78+
{'DOWN', MRef4, _Type, _Pid, _Info} ->
79+
do_connect_2(Pid6, MRef6, Timeout);
6780
{'DOWN', MRef6, _Type, _Pid, _Info} ->
6881
do_connect_2(Pid4, MRef4, Timeout)
6982
after Timeout ->
@@ -122,19 +135,19 @@ getbyname(Hostname, Type) ->
122135
[]
123136
end.
124137

125-
try_connect(Ipv6Addrs, Port, Opts, Self) ->
126-
try_connect(Ipv6Addrs, Port, Opts, Self, {error, nxdomain}).
138+
try_connect(Ipv6Addrs, Port, Opts, Timeout, Self) ->
139+
try_connect(Ipv6Addrs, Port, Opts, Timeout, Self, {error, nxdomain}).
127140

128-
try_connect([], _Port, _Opts, _ServerPid, LastError) ->
141+
try_connect([], _Port, _Opts, _Timeout, _ServerPid, LastError) ->
129142
?report_trace("happy eyeball: failed to connect", [{error, LastError}]),
130143
exit(LastError);
131-
try_connect([{IP, Type} | Rest], Port, Opts, ServerPid, _LastError) ->
144+
try_connect([{IP, Type} | Rest], Port, Opts, Timeout, ServerPid, _LastError) ->
132145
?report_trace("try to connect", [{ip, IP}, {type, Type}]),
133-
case gen_tcp:connect(IP, Port, [Type | Opts], ?TIMEOUT) of
146+
case gen_tcp:connect(IP, Port, [Type | Opts], Timeout) of
134147
{ok, Socket} = OK ->
135148
?report_trace("success to connect", [{ip, IP}, {type, Type}]),
136149
ok = gen_tcp:controlling_process(Socket, ServerPid),
137150
exit({happy_connect, OK});
138151
Error ->
139-
try_connect(Rest, Port, Opts, ServerPid, Error)
152+
try_connect(Rest, Port, Opts, Timeout, ServerPid, Error)
140153
end.

0 commit comments

Comments
 (0)