diff options
Diffstat (limited to 'src/deps/c_ares.zig')
-rw-r--r-- | src/deps/c_ares.zig | 134 |
1 files changed, 122 insertions, 12 deletions
diff --git a/src/deps/c_ares.zig b/src/deps/c_ares.zig index 457fcef0e..5290ffcc8 100644 --- a/src/deps/c_ares.zig +++ b/src/deps/c_ares.zig @@ -181,7 +181,7 @@ pub const struct_hostent = extern struct { h_length: c_int, h_addr_list: [*c][*c]u8, - pub fn toJSReponse(this: *struct_hostent, _: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime lookup_name: []const u8) JSC.JSValue { + pub fn toJSResponse(this: *struct_hostent, _: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime lookup_name: []const u8) JSC.JSValue { // A cname lookup always returns a single record but we follow the common API here. if (comptime strings.eqlComptime(lookup_name, "cname")) { @@ -284,6 +284,55 @@ pub const struct_hostent = extern struct { ares_free_hostent(this); } }; + +pub const struct_nameinfo = extern struct { + node: [*c]u8, + service: [*c]u8, + + pub fn toJSResponse(this: *struct_nameinfo, _: std.mem.Allocator, globalThis: *JSC.JSGlobalObject) JSC.JSValue { + const array = JSC.JSValue.createEmptyArray(globalThis, 2); // [node, service] + + if (this.node != null) { + const node_len = bun.len(this.node); + const node_slice = this.node[0..node_len]; + array.putIndex(globalThis, 0, JSC.ZigString.fromUTF8(node_slice).toValueGC(globalThis)); + } else { + array.putIndex(globalThis, 0, JSC.JSValue.jsUndefined()); + } + + if (this.service != null) { + const service_len = bun.len(this.service); + const service_slice = this.service[0..service_len]; + array.putIndex(globalThis, 1, JSC.ZigString.fromUTF8(service_slice).toValueGC(globalThis)); + } else { + array.putIndex(globalThis, 1, JSC.JSValue.jsUndefined()); + } + + return array; + } + + pub fn Callback(comptime Type: type) type { + return fn (*Type, status: ?Error, timeouts: i32, node: ?struct_nameinfo) void; + } + + pub fn CallbackWrapper( + comptime Type: type, + comptime function: Callback(Type), + ) ares_nameinfo_callback { + return &struct { + pub fn handle(ctx: ?*anyopaque, status: c_int, timeouts: c_int, node: [*c]u8, service: [*c]u8) callconv(.C) void { + var this = bun.cast(*Type, ctx.?); + if (status != ARES_SUCCESS) { + function(this, Error.get(status), timeouts, null); + return; + } + function(this, null, timeouts, .{ .node = node, .service = service }); + return; + } + }.handle; + } +}; + pub const struct_timeval = opaque {}; pub const struct_Channeldata = opaque {}; pub const AddrInfo_cname = extern struct { @@ -524,11 +573,12 @@ pub const Channel = opaque { } pub fn resolve(this: *Channel, name: []const u8, comptime lookup_name: []const u8, comptime Type: type, ctx: *Type, comptime cares_type: type, comptime callback: cares_type.Callback(Type)) void { + if (name.len >= 1023 or (name.len == 0 and !(bun.strings.eqlComptime(lookup_name, "ns") or bun.strings.eqlComptime(lookup_name, "soa")))) { + return cares_type.callbackWrapper(lookup_name, Type, callback).?(ctx, ARES_EBADNAME, 0, null, 0); + } + var name_buf: [1024]u8 = undefined; - const name_ptr: ?[*:0]const u8 = brk: { - if (name.len == 0 or name.len >= 1023) { - break :brk null; - } + const name_ptr: [*:0]const u8 = brk: { const len = @min(name.len, name_buf.len - 1); @memcpy(name_buf[0..len], name[0..len]); @@ -571,6 +621,20 @@ pub const Channel = opaque { struct_hostent.hostCallbackWrapper(Type, callback).?(ctx, ARES_ENOTIMP, 0, null); } + // https://c-ares.org/ares_getnameinfo.html + pub fn getNameInfo(this: *Channel, sa: *std.os.sockaddr, comptime Type: type, ctx: *Type, comptime callback: struct_nameinfo.Callback(Type)) void { + return ares_getnameinfo( + this, + sa, + if (sa.*.family == std.os.AF.INET) @sizeOf(std.os.sockaddr.in) else @sizeOf(std.os.sockaddr.in6), + // node returns ENOTFOUND for addresses like 255.255.255.255:80 + // So, it requires setting the ARES_NI_NAMEREQD flag + ARES_NI_NAMEREQD | ARES_NI_LOOKUPHOST | ARES_NI_LOOKUPSERVICE, + struct_nameinfo.CallbackWrapper(Type, callback), + ctx, + ); + } + pub inline fn process(this: *Channel, fd: i32, readable: bool, writable: bool) void { ares_process_fd( this, @@ -669,7 +733,7 @@ pub const struct_ares_caa_reply = extern struct { value: [*c]u8, length: usize, - pub fn toJSReponse(this: *struct_ares_caa_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue { + pub fn toJSResponse(this: *struct_ares_caa_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue { var stack = std.heap.stackFallback(2048, parent_allocator); var arena = @import("root").bun.ArenaAllocator.init(stack.get()); defer arena.deinit(); @@ -747,7 +811,7 @@ pub const struct_ares_srv_reply = extern struct { weight: c_ushort, port: c_ushort, - pub fn toJSReponse(this: *struct_ares_srv_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue { + pub fn toJSResponse(this: *struct_ares_srv_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue { var stack = std.heap.stackFallback(2048, parent_allocator); var arena = @import("root").bun.ArenaAllocator.init(stack.get()); defer arena.deinit(); @@ -830,7 +894,7 @@ pub const struct_ares_mx_reply = extern struct { host: [*c]u8, priority: c_ushort, - pub fn toJSReponse(this: *struct_ares_mx_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue { + pub fn toJSResponse(this: *struct_ares_mx_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue { var stack = std.heap.stackFallback(2048, parent_allocator); var arena = @import("root").bun.ArenaAllocator.init(stack.get()); defer arena.deinit(); @@ -904,7 +968,7 @@ pub const struct_ares_txt_reply = extern struct { txt: [*c]u8, length: usize, - pub fn toJSReponse(this: *struct_ares_txt_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue { + pub fn toJSResponse(this: *struct_ares_txt_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue { var stack = std.heap.stackFallback(2048, parent_allocator); var arena = @import("root").bun.ArenaAllocator.init(stack.get()); defer arena.deinit(); @@ -984,7 +1048,7 @@ pub const struct_ares_naptr_reply = extern struct { order: c_ushort, preference: c_ushort, - pub fn toJSReponse(this: *struct_ares_naptr_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue { + pub fn toJSResponse(this: *struct_ares_naptr_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue { var stack = std.heap.stackFallback(2048, parent_allocator); var arena = @import("root").bun.ArenaAllocator.init(stack.get()); defer arena.deinit(); @@ -1076,7 +1140,7 @@ pub const struct_ares_soa_reply = extern struct { expire: c_uint, minttl: c_uint, - pub fn toJSReponse(this: *struct_ares_soa_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue { + pub fn toJSResponse(this: *struct_ares_soa_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue { var stack = std.heap.stackFallback(2048, parent_allocator); var arena = @import("root").bun.ArenaAllocator.init(stack.get()); defer arena.deinit(); @@ -1188,7 +1252,7 @@ pub extern fn ares_set_servers_csv(channel: *Channel, servers: [*c]const u8) c_i pub extern fn ares_set_servers_ports_csv(channel: *Channel, servers: [*c]const u8) c_int; pub extern fn ares_get_servers(channel: *Channel, servers: *?*struct_ares_addr_port_node) c_int; pub extern fn ares_get_servers_ports(channel: *Channel, servers: *?*struct_ares_addr_port_node) c_int; -pub extern fn ares_inet_ntop(af: c_int, src: ?*const anyopaque, dst: [*c]u8, size: ares_socklen_t) [*c]const u8; +pub extern fn ares_inet_ntop(af: c_int, src: ?*const anyopaque, dst: [*c]u8, size: ares_socklen_t) ?[*:0]const u8; pub extern fn ares_inet_pton(af: c_int, src: [*c]const u8, dst: ?*anyopaque) c_int; pub const ARES_SUCCESS = 0; pub const ARES_ENODATA = 1; @@ -1470,6 +1534,52 @@ pub export fn Bun__canonicalizeIP( return .zero; } } + +/// Creates a sockaddr structure from an address, port. +/// +/// # Parameters +/// - `addr`: A byte slice representing the IP address. +/// - `port`: A 16-bit unsigned integer representing the port number. +/// - `sa`: A pointer to a sockaddr structure where the result will be stored. +/// +/// # Returns +/// +/// This function returns 0 on success. +pub fn getSockaddr(addr: []const u8, port: u16, sa: *std.os.sockaddr) c_int { + const buf_size = 128; + + var buf: [buf_size]u8 = undefined; + const addr_ptr: [*:0]const u8 = brk: { + if (addr.len == 0 or addr.len >= buf_size) { + return -1; + } + const len = @min(addr.len, buf.len - 1); + @memcpy(buf[0..len], addr[0..len]); + + buf[len] = 0; + break :brk buf[0..len :0]; + }; + + { + const in: *std.os.sockaddr.in = @as(*std.os.sockaddr.in, @alignCast(@ptrCast(sa))); + if (ares_inet_pton(std.os.AF.INET, addr_ptr, &in.addr) == 1) { + in.*.family = std.os.AF.INET; + in.*.port = std.mem.nativeToBig(u16, port); + return 0; + } + } + { + const in6: *std.os.sockaddr.in6 = @as(*std.os.sockaddr.in6, @alignCast(@ptrCast(sa))); + if (ares_inet_pton(std.os.AF.INET6, addr_ptr, &in6.addr) == 1) { + in6.*.family = std.os.AF.INET6; + in6.*.port = std.mem.nativeToBig(u16, port); + return 0; + } + } + + return -1; +} + comptime { if (!JSC.is_bindgen) { _ = Bun__canonicalizeIP; |