Add UDP send functionality
This commit is contained in:
parent
f913dc5506
commit
43c93dc54a
3 changed files with 73 additions and 21 deletions
|
@ -21,6 +21,7 @@ pub fn build(b: *std.Build) void {
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
|
exe.linkLibC();
|
||||||
|
|
||||||
// This declares intent for the executable to be installed into the
|
// This declares intent for the executable to be installed into the
|
||||||
// standard location when the user invokes the "install" step (the default
|
// standard location when the user invokes the "install" step (the default
|
||||||
|
|
74
src/mdns.zig
74
src/mdns.zig
|
@ -1,32 +1,68 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const util = @import("util.zig");
|
const util = @import("util.zig");
|
||||||
|
|
||||||
pub fn get_mdns(domain: util.Domain, ip_ver: util.IP_VER_ENUM) !util.IPs {
|
const MDNSError = error{
|
||||||
var listener = try init(ip_ver);
|
Unimplemented,
|
||||||
try send_query(&listener, domain, ip_ver);
|
SocketInitFail,
|
||||||
return receive_query(&listener);
|
UDPConnectFail,
|
||||||
|
UDPSendFail,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn get_mdns(domain: util.Domain, ip_info: util.IPInfo) !util.IPs {
|
||||||
|
const sock = try send_query(domain, ip_info);
|
||||||
|
return receive_query(sock);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(ip_ver: util.IP_VER_ENUM) !std.net.Server {
|
const socket = c_int;
|
||||||
return try std.net.Address.listen(try std.net.Address.parseIp(switch (ip_ver) {
|
|
||||||
util.IP_VER_ENUM.IPv4 => "0.0.0.0",
|
fn get_mdns_socket(ip_info: util.IPInfo) !socket {
|
||||||
util.IP_VER_ENUM.IPv6 => "::",
|
const target_addr: []const u8 = switch (ip_info.version) {
|
||||||
}, 5353), .{});
|
util.IP_VER_ENUM.IPv4 => "224.0.0.251",
|
||||||
|
util.IP_VER_ENUM.IPv6 => blk: {
|
||||||
|
var buf = [_]u8{0x00} ** 100;
|
||||||
|
var byte_buf = std.io.fixedBufferStream(&buf);
|
||||||
|
const writer = byte_buf.writer();
|
||||||
|
try std.fmt.format(writer, "ff02::fb%{s}", .{ip_info.interface.?});
|
||||||
|
break :blk buf[0..writer.context.pos];
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const addr = try std.net.Address.resolveIp(target_addr, 5353);
|
||||||
|
const sock = std.c.socket(switch (ip_info.version) {
|
||||||
|
util.IP_VER_ENUM.IPv4 => std.posix.AF.INET,
|
||||||
|
util.IP_VER_ENUM.IPv6 => std.posix.AF.INET6,
|
||||||
|
}, std.c.SOCK.DGRAM, std.c.IPPROTO.UDP);
|
||||||
|
if (sock == -1) {
|
||||||
|
return MDNSError.SocketInitFail;
|
||||||
|
}
|
||||||
|
if (std.c.connect(sock, &addr.any, addr.getOsSockLen()) == -1) {
|
||||||
|
return MDNSError.UDPConnectFail;
|
||||||
|
}
|
||||||
|
return sock;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_query(listener: *std.net.Server, domain: util.Domain, ip_ver: util.IP_VER_ENUM) !void {
|
fn construct_mdns_query(domain: util.Domain, ip_info: util.IPInfo, buff: []u8) !usize {
|
||||||
const header =
|
|
||||||
[_]u8{0x00} ** 4 ++ // transaction id + is question
|
|
||||||
[_]u8{ 0x00, 0x01 } ++ // 1 question
|
|
||||||
[_]u8{0x00} ** 6; // misc flags
|
|
||||||
_ = listener;
|
|
||||||
_ = domain;
|
_ = domain;
|
||||||
_ = header;
|
_ = ip_info;
|
||||||
_ = ip_ver;
|
var n: usize = 0;
|
||||||
|
var buff_writer = std.io.fixedBufferStream(buff);
|
||||||
|
n += try buff_writer.write("test");
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive_query(listener: *std.net.Server) !util.IPs {
|
fn send_query(domain: util.Domain, ip_info: util.IPInfo) !socket {
|
||||||
_ = listener;
|
const sock = try get_mdns_socket(ip_info);
|
||||||
|
errdefer _ = std.c.close(sock);
|
||||||
|
var buff = [_]u8{0x00} ** 100;
|
||||||
|
|
||||||
|
const n = try construct_mdns_query(domain, ip_info, &buff);
|
||||||
|
if (std.c.send(sock, &buff, n, 0) == -1) {
|
||||||
|
return MDNSError.UDPSendFail;
|
||||||
|
}
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn receive_query(sock: socket) !util.IPs {
|
||||||
|
_ = sock;
|
||||||
return util.IPs{
|
return util.IPs{
|
||||||
.v4 = "",
|
.v4 = "",
|
||||||
.v6 = "",
|
.v6 = "",
|
||||||
|
|
19
src/util.zig
19
src/util.zig
|
@ -4,6 +4,8 @@ const ArgError = error{
|
||||||
NotEnoughArgs,
|
NotEnoughArgs,
|
||||||
BadDomain,
|
BadDomain,
|
||||||
InvalidAddressVer,
|
InvalidAddressVer,
|
||||||
|
InterfaceRequired,
|
||||||
|
InvalidInterface,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const IP_VER_ENUM = enum(u3) {
|
pub const IP_VER_ENUM = enum(u3) {
|
||||||
|
@ -16,6 +18,11 @@ pub const IPs = struct {
|
||||||
v6: []const u8,
|
v6: []const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const IPInfo = struct {
|
||||||
|
version: IP_VER_ENUM,
|
||||||
|
interface: ?[:0]const u8,
|
||||||
|
};
|
||||||
|
|
||||||
pub const Domain = struct {
|
pub const Domain = struct {
|
||||||
name: [:0]const u8,
|
name: [:0]const u8,
|
||||||
labels: [5][]const u8,
|
labels: [5][]const u8,
|
||||||
|
@ -28,7 +35,7 @@ pub fn check_perms() !void {
|
||||||
|
|
||||||
pub fn get_input() !struct {
|
pub fn get_input() !struct {
|
||||||
Domain,
|
Domain,
|
||||||
IP_VER_ENUM,
|
IPInfo,
|
||||||
} {
|
} {
|
||||||
var args = std.process.args();
|
var args = std.process.args();
|
||||||
_ = args.next(); // consume calling binary arg
|
_ = args.next(); // consume calling binary arg
|
||||||
|
@ -39,7 +46,15 @@ pub fn get_input() !struct {
|
||||||
const ip_ver_str = args.next() orelse return ArgError.NotEnoughArgs;
|
const ip_ver_str = args.next() orelse return ArgError.NotEnoughArgs;
|
||||||
const ip_ver = std.meta.intToEnum(IP_VER_ENUM, std.fmt.parseInt(u3, ip_ver_str, 10) catch return ArgError.InvalidAddressVer) catch return ArgError.InvalidAddressVer;
|
const ip_ver = std.meta.intToEnum(IP_VER_ENUM, std.fmt.parseInt(u3, ip_ver_str, 10) catch return ArgError.InvalidAddressVer) catch return ArgError.InvalidAddressVer;
|
||||||
|
|
||||||
return .{ domain, ip_ver };
|
var iface: ?[:0]const u8 = null;
|
||||||
|
if (ip_ver == IP_VER_ENUM.IPv6) {
|
||||||
|
iface = args.next() orelse return ArgError.InterfaceRequired;
|
||||||
|
if (std.c.if_nametoindex(iface.?) == 0) {
|
||||||
|
return ArgError.InvalidInterface;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{ domain, IPInfo{ .version = ip_ver, .interface = iface } };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_domain(domain_str: [:0]const u8) !Domain {
|
fn check_domain(domain_str: [:0]const u8) !Domain {
|
||||||
|
|
Loading…
Reference in a new issue