DoxigAlpha

resolve

Function parameters

Parameters

#
buf:[]const u8
port:u16

Type definitions in this namespace

Types

#

Functions in this namespace

Functions

#
tcpConnectToHost
All memory allocated with `allocator` will be freed before this function returns.
getAddressList
Call `AddressList.deinit` on the result.

Error sets in this namespace

Error Sets

#

= switch (native_os) { .windows => builtin.os.version_range.windows.isAtLeast(.win10_rs4) orelse false, .wasi => false, else => true, }

Values

#
has_unix_sockets
= switch (native_os) { .windows => builtin.os.version_range.windows.isAtLeast(.win10_rs4) orelse false, .wasi => false, else => true, }

Source

Implementation

#
pub fn resolve(buf: []const u8, port: u16) IPv6ResolveError!Ip6Address {
    // TODO: Unify the implementations of resolveIp6 and parseIp6.
    var result = Ip6Address{
        .sa = posix.sockaddr.in6{
            .scope_id = 0,
            .port = mem.nativeToBig(u16, port),
            .flowinfo = 0,
            .addr = undefined,
        },
    };
    var ip_slice: *[16]u8 = result.sa.addr[0..];

    var tail: [16]u8 = undefined;

    var x: u16 = 0;
    var saw_any_digits = false;
    var index: u8 = 0;
    var abbrv = false;

    var scope_id = false;
    var scope_id_value: [posix.IFNAMESIZE - 1]u8 = undefined;
    var scope_id_index: usize = 0;

    for (buf, 0..) |c, i| {
        if (scope_id) {
            // Handling of percent-encoding should be for an URI library.
            if ((c >= '0' and c <= '9') or
                (c >= 'A' and c <= 'Z') or
                (c >= 'a' and c <= 'z') or
                (c == '-') or (c == '.') or (c == '_') or (c == '~'))
            {
                if (scope_id_index >= scope_id_value.len) {
                    return error.Overflow;
                }

                scope_id_value[scope_id_index] = c;
                scope_id_index += 1;
            } else {
                return error.InvalidCharacter;
            }
        } else if (c == ':') {
            if (!saw_any_digits) {
                if (abbrv) return error.InvalidCharacter; // ':::'
                if (i != 0) abbrv = true;
                @memset(ip_slice[index..], 0);
                ip_slice = tail[0..];
                index = 0;
                continue;
            }
            if (index == 14) {
                return error.InvalidEnd;
            }
            ip_slice[index] = @as(u8, @truncate(x >> 8));
            index += 1;
            ip_slice[index] = @as(u8, @truncate(x));
            index += 1;

            x = 0;
            saw_any_digits = false;
        } else if (c == '%') {
            if (!saw_any_digits) {
                return error.InvalidCharacter;
            }
            scope_id = true;
            saw_any_digits = false;
        } else if (c == '.') {
            if (!abbrv or ip_slice[0] != 0xff or ip_slice[1] != 0xff) {
                // must start with '::ffff:'
                return error.InvalidIpv4Mapping;
            }
            const start_index = mem.lastIndexOfScalar(u8, buf[0..i], ':').? + 1;
            const addr = (Ip4Address.parse(buf[start_index..], 0) catch {
                return error.InvalidIpv4Mapping;
            }).sa.addr;
            ip_slice = result.sa.addr[0..];
            ip_slice[10] = 0xff;
            ip_slice[11] = 0xff;

            const ptr = mem.sliceAsBytes(@as(*const [1]u32, &addr)[0..]);

            ip_slice[12] = ptr[0];
            ip_slice[13] = ptr[1];
            ip_slice[14] = ptr[2];
            ip_slice[15] = ptr[3];
            return result;
        } else {
            const digit = try std.fmt.charToDigit(c, 16);
            {
                const ov = @mulWithOverflow(x, 16);
                if (ov[1] != 0) return error.Overflow;
                x = ov[0];
            }
            {
                const ov = @addWithOverflow(x, digit);
                if (ov[1] != 0) return error.Overflow;
                x = ov[0];
            }
            saw_any_digits = true;
        }
    }

    if (!saw_any_digits and !abbrv) {
        return error.Incomplete;
    }

    if (scope_id and scope_id_index == 0) {
        return error.Incomplete;
    }

    var resolved_scope_id: u32 = 0;
    if (scope_id_index > 0) {
        const scope_id_str = scope_id_value[0..scope_id_index];
        resolved_scope_id = std.fmt.parseInt(u32, scope_id_str, 10) catch |err| blk: {
            if (err != error.InvalidCharacter) return err;
            break :blk try if_nametoindex(scope_id_str);
        };
    }

    result.sa.scope_id = resolved_scope_id;

    if (index == 14) {
        ip_slice[14] = @as(u8, @truncate(x >> 8));
        ip_slice[15] = @as(u8, @truncate(x));
        return result;
    } else {
        ip_slice[index] = @as(u8, @truncate(x >> 8));
        index += 1;
        ip_slice[index] = @as(u8, @truncate(x));
        index += 1;
        @memcpy(result.sa.addr[16 - index ..][0..index], ip_slice[0..index]);
        return result;
    }
}