From 554723c96f63e1f109a87cfb2e9d79a8ba2804a2 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Thu, 11 Jul 2024 13:16:23 +0200 Subject: [PATCH] ev::dial: attempt resolved IPs in order To handle cases where, for instance, an AAAA record is returned but IPv6 is not available. Signed-off-by: Drew DeVault --- ev/dial/ip.ha | 50 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/ev/dial/ip.ha b/ev/dial/ip.ha index ce718e7..0819889 100644 --- a/ev/dial/ip.ha +++ b/ev/dial/ip.ha @@ -6,10 +6,12 @@ // Provides default dialers for tcp and udp use errors; use ev; -use net; +use math::random; use net::ip; use net::tcp; use net::udp; +use net; +use time; type tcp_dialer = struct { loop: *ev::loop, @@ -17,6 +19,7 @@ type tcp_dialer = struct { user: nullable *opaque, req: ev::req, ip: []ip::addr, + n: uint, port: u16, }; @@ -60,11 +63,9 @@ fn dial_tcp_resolvecb( }; fn dial_tcp_connect(state: *tcp_dialer) void = { - // TODO: Select IPs from a round-robin, or re-attempt on other IPs? - // TODO: Detect supported networks? i.e. v4/v6 const req = match (ev::connect_tcp(state.loop, &dial_tcp_connectcb, - state.ip[0], state.port, + state.ip[state.n], state.port, state)) { case let err: (net::error | errors::error) => dial_tcp_complete(state, err); @@ -84,7 +85,15 @@ fn dial_tcp_connectcb( case let sock: *ev::file => ev::setuser(sock, null); dial_tcp_complete(state, sock); + return; case let err: net::error => + if (err is errors::netunreachable) { + state.n += 1; + if (state.n < len(state.ip)) { + dial_tcp_connect(state); + return; + }; + }; dial_tcp_complete(state, err); }; }; @@ -110,6 +119,7 @@ type udp_dialer = struct { user: nullable *opaque, req: ev::req, ip: []ip::addr, + n: uint, port: u16, }; @@ -153,14 +163,30 @@ fn dial_udp_resolvecb( }; fn dial_udp_connect(state: *udp_dialer) void = { - match (ev::connect_udp(state.loop, - state.ip[0], state.port)) { - case let err: (net::error | errors::error) => - dial_udp_complete(state, err); - return; - case let sock: *ev::file => - dial_udp_complete(state, sock); - return; + for (true) { + match (ev::connect_udp(state.loop, state.ip[state.n], state.port)) { + case let err: net::error => + if (err is errors::netunreachable) { + state.n += 1; + if (state.n < len(state.ip)) { + continue; + }; + }; + dial_udp_complete(state, err); + break; + case let err: errors::error => + dial_udp_complete(state, err); + if (err is errors::netunreachable) { + state.n += 1; + if (state.n < len(state.ip)) { + continue; + }; + }; + break; + case let sock: *ev::file => + dial_udp_complete(state, sock); + break; + }; }; }; -- 2.45.2