~sircmpwn/hare-ev

554723c96f63e1f109a87cfb2e9d79a8ba2804a2 — Drew DeVault 2 months ago ed023be
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 <sir@cmpwn.com>
1 files changed, 38 insertions(+), 12 deletions(-)

M ev/dial/ip.ha
M ev/dial/ip.ha => ev/dial/ip.ha +38 -12
@@ 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;
		};
	};
};