feat: transparently send fds

dev
Louis Pearson 2024-01-15 22:14:40 -07:00
parent ea4a75cc76
commit 7a9e12abf8
4 changed files with 77 additions and 31 deletions

View File

@ -196,41 +196,16 @@ pub fn main() !void {
const wl_shm_pool_id = id_pool.create(); const wl_shm_pool_id = id_pool.create();
{ {
var buffer: [10]u32 = undefined; std.debug.print("framebuffer_fd: {}\n", .{framebuffer_fd});
const message = try wayland.serialize( try conn.send(
wayland.core.Shm.Request, wayland.core.Shm.Request,
&buffer,
shm_id, shm_id,
.{ .create_pool = .{ .{ .create_pool = .{
.new_id = wl_shm_pool_id, .new_id = wl_shm_pool_id,
.fd = @enumFromInt(framebuffer_fd),
.size = framebuffer_file_len, .size = framebuffer_file_len,
} }, } },
); );
// Send the file descriptor through a control message
const message_bytes = std.mem.sliceAsBytes(message);
const msg_iov = [_]std.os.iovec_const{
.{
.iov_base = message_bytes.ptr,
.iov_len = message_bytes.len,
},
};
const control_message = cmsg(std.os.fd_t){
.level = std.os.SOL.SOCKET,
.type = 0x01, // value of SCM_RIGHTS
.data = framebuffer_fd,
};
const socket_message = std.os.msghdr_const{
.name = null,
.namelen = 0,
.iov = &msg_iov,
.iovlen = msg_iov.len,
// .control = null,
// .controllen = 0,
.control = &control_message,
.controllen = @sizeOf(cmsg(std.os.fd_t)),
.flags = 0,
};
_ = try std.os.sendmsg(conn.socket.handle, &socket_message, 0);
} }
const wl_buffer_id = id_pool.create(); const wl_buffer_id = id_pool.create();

View File

@ -1,3 +1,5 @@
const types = @import("types.zig");
pub const Display = struct { pub const Display = struct {
pub const Request = union(enum) { pub const Request = union(enum) {
sync: struct { sync: struct {
@ -90,7 +92,7 @@ pub const Shm = struct {
create_pool: struct { create_pool: struct {
new_id: u32, new_id: u32,
// file descriptors are sent through a control message // file descriptors are sent through a control message
// fd: u32, fd: types.Fd,
size: u32, size: u32,
}, },
}; };
@ -306,7 +308,7 @@ pub const Keyboard = struct {
pub const Event = union(enum) { pub const Event = union(enum) {
keymap: struct { keymap: struct {
format: KeymapFormat, format: KeymapFormat,
// fd: u32, fd: types.Fd,
size: u32, size: u32,
}, },
enter: struct { enter: struct {

View File

@ -3,6 +3,7 @@ const testing = std.testing;
pub const core = @import("./core.zig"); pub const core = @import("./core.zig");
pub const xdg = @import("./xdg.zig"); pub const xdg = @import("./xdg.zig");
pub const zxdg = @import("./zxdg.zig"); pub const zxdg = @import("./zxdg.zig");
pub const types = @import("./types.zig");
pub fn getDisplayPath(gpa: std.mem.Allocator) ![]u8 { pub fn getDisplayPath(gpa: std.mem.Allocator) ![]u8 {
const xdg_runtime_dir_path = try std.process.getEnvVarOwned(gpa, "XDG_RUNTIME_DIR"); const xdg_runtime_dir_path = try std.process.getEnvVarOwned(gpa, "XDG_RUNTIME_DIR");
@ -112,6 +113,7 @@ pub fn deserializeArguments(comptime Signature: type, buffer: []const u32) !Sign
var result: Signature = undefined; var result: Signature = undefined;
var pos: usize = 0; var pos: usize = 0;
inline for (std.meta.fields(Signature)) |field| { inline for (std.meta.fields(Signature)) |field| {
if (field.type == types.Fd) continue; // Must be handled
switch (@typeInfo(field.type)) { switch (@typeInfo(field.type)) {
.Int => |int_info| switch (int_info.signedness) { .Int => |int_info| switch (int_info.signedness) {
.signed => @field(result, field.name) = try readInt(buffer, &pos), .signed => @field(result, field.name) = try readInt(buffer, &pos),
@ -169,11 +171,36 @@ pub fn calculateSerializedWordLen(comptime Signature: type, message: Signature)
return pos; return pos;
} }
pub fn countFds(comptime Signature: type) usize {
if (Signature == void) return 0;
var count: usize = 0;
inline for (std.meta.fields(Signature)) |field| {
if (field.type == types.Fd) {
count += 1;
}
}
return count;
}
pub fn extractFds(comptime Signature: type, message: *const Signature) [countFds(Signature)]*const types.Fd {
if (Signature == void) return [_]*const types.Fd{};
var fds: [countFds(Signature)]*const types.Fd = undefined;
var i: usize = 0;
inline for (std.meta.fields(Signature)) |field| {
if (field.type == types.Fd) {
fds[i] = &@field(message, field.name);
i += 1;
}
}
return fds;
}
/// Message must live until the iovec array is written. /// Message must live until the iovec array is written.
pub fn serializeArguments(comptime Signature: type, buffer: []u32, message: Signature) ![]u32 { pub fn serializeArguments(comptime Signature: type, buffer: []u32, message: Signature) ![]u32 {
if (Signature == void) return buffer[0..0]; if (Signature == void) return buffer[0..0];
var pos: usize = 0; var pos: usize = 0;
inline for (std.meta.fields(Signature)) |field| { inline for (std.meta.fields(Signature)) |field| {
if (field.type == types.Fd) continue;
switch (@typeInfo(field.type)) { switch (@typeInfo(field.type)) {
.Int => { .Int => {
if (pos >= buffer.len) return error.OutOfMemory; if (pos >= buffer.len) return error.OutOfMemory;
@ -416,6 +443,17 @@ pub fn registerGlobals(alloc: std.mem.Allocator, id_pool: *IdPool, socket: std.n
return ids; return ids;
} }
fn cmsg(comptime T: type) type {
const padding_size = (@sizeOf(T) + @sizeOf(c_long) - 1) & ~(@as(usize, @sizeOf(c_long)) - 1);
return extern struct {
len: c_ulong = @sizeOf(@This()) - padding_size,
level: c_int,
type: c_int,
data: T,
_padding: [padding_size]u8 align(1) = [_]u8{0} ** padding_size,
};
}
pub const Conn = struct { pub const Conn = struct {
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
send_buffer: []u32, send_buffer: []u32,
@ -455,11 +493,40 @@ pub const Conn = struct {
break msg; break msg;
}; };
try conn.socket.writeAll(std.mem.sliceAsBytes(msg)); const msg_bytes = std.mem.sliceAsBytes(msg);
const msg_iov = [_]std.os.iovec_const{
.{
.iov_base = msg_bytes.ptr,
.iov_len = msg_bytes.len,
},
};
const fds = switch (message) {
inline else => |*payload| extractFds(@TypeOf(payload.*), payload),
};
var ctrl_msgs: [fds.len]cmsg(std.os.fd_t) = undefined;
for (fds, 0..) |fdp, i| {
std.debug.print("fd {}: {}\n", .{ i, fdp.* });
ctrl_msgs[i] = .{
.level = std.os.SOL.SOCKET,
.type = 0x01,
.data = @intFromEnum(fdp.*),
};
}
const socket_msg = std.os.msghdr_const{
.name = null,
.namelen = 0,
.iov = &msg_iov,
.iovlen = msg_iov.len,
.control = &ctrl_msgs,
.controllen = @intCast(@sizeOf(cmsg(std.os.fd_t)) * ctrl_msgs.len),
.flags = 0,
};
_ = try std.os.sendmsg(conn.socket.handle, &socket_msg, 0);
} }
pub const Message = struct { Header, []const u32 }; pub const Message = struct { Header, []const u32 };
pub fn recv(conn: *Conn) !Message { pub fn recv(conn: *Conn) !Message {
// TODO: recvmesg and read fds
var header: Header = undefined; var header: Header = undefined;
const header_bytes_read = try conn.socket.readAll(std.mem.asBytes(&header)); const header_bytes_read = try conn.socket.readAll(std.mem.asBytes(&header));
if (header_bytes_read < @sizeOf(Header)) { if (header_bytes_read < @sizeOf(Header)) {

2
src/types.zig Normal file
View File

@ -0,0 +1,2 @@
const std = @import("std");
pub const Fd = enum(std.os.fd_t) { _ };