diff options
| author | Nathan Reiner <nathan@nathanreiner.xyz> | 2025-08-27 09:02:43 +0200 |
|---|---|---|
| committer | Nathan Reiner <nathan@nathanreiner.xyz> | 2025-08-27 09:03:21 +0200 |
| commit | 8a7392dea729d3ed49a8bf8eee25906c4fd616ac (patch) | |
| tree | 09e0b2fa96c60a2e0c8b0cae9e631bd2dc66f52f /src/wl/display.zig | |
| parent | c217e7ec5cddfc002c4582fb5d52727aee843a7d (diff) | |
Add ancillary data mechanism to send fds to compositor.
Currently we are just attaching the fds to the object id.
In theory this is not a valid implementation, since if we
have more than MAX_FD file descriptors this will not work.
But since this wont be the case in basically all cases of
the wayland protocol, we can just ignore that for now.
Diffstat (limited to 'src/wl/display.zig')
| -rw-r--r-- | src/wl/display.zig | 87 |
1 files changed, 60 insertions, 27 deletions
diff --git a/src/wl/display.zig b/src/wl/display.zig index 3b5087d..c9e2e6e 100644 --- a/src/wl/display.zig +++ b/src/wl/display.zig @@ -86,7 +86,7 @@ pub fn request(self: *Self, object: anytype, args: @TypeOf(object.*).Request) !v const id: u32 = @truncate(object.handle); var size: u32 = 8; - comptime var fds: []std.posix.fd_t = &.{}; + comptime var count_fds = 0; inline for (data) |value| { switch (@TypeOf(value)) { @@ -97,7 +97,7 @@ pub fn request(self: *Self, object: anytype, args: @TypeOf(object.*).Request) !v const padding_size: usize = padding_len(u8, value.len + 1); size += @as(u32, @intCast(@sizeOf(u32) + (value.len + 1) + padding_size)); }, - wayland.types.Fd => |fd| fds = fds ++ .{ fd }, + wayland.types.Fd => count_fds += 1, else => |t| switch (@typeInfo(t)) { .pointer => |ptr| if (ptr.size == .slice) { const padding_size: usize = padding_len(ptr.child, value.len); @@ -108,14 +108,30 @@ pub fn request(self: *Self, object: anytype, args: @TypeOf(object.*).Request) !v } } - _ = try self.stream.writeAll(&std.mem.toBytes(id)); + { + var fds: [count_fds]std.posix.fd_t = undefined; + comptime var current_fd_index = 0; + + inline for (data) |value| { + switch (@TypeOf(value)) { + wayland.types.Fd => { + fds[current_fd_index] = value.fd; + current_fd_index += 1; + }, + else => {}, + } + } + + try ancillary_data.send_fds(self.stream.handle, &fds, std.mem.asBytes(&id)); + } + _ = try self.stream.writeAll(&std.mem.toBytes((size << 16) | opcode)); inline for (data) |value| { switch (@TypeOf(value)) { u32, i32 => _ = try self.stream.writeAll(std.mem.asBytes(&value)), wayland.Object.Ref => try self.stream.writeAll(std.mem.asBytes(&(@as(u32, @truncate(value))))), - ?wayland.Object.Ref => try self.stream.writeAll(std.mem.asBytes(&(@as(u32, 0)))), + ?wayland.Object.Ref => try self.stream.writeAll(std.mem.asBytes(&(@as(u32, @truncate(if (value) |v| v else 0))))), []const u8, []u8 => { const padding_size: usize = padding_len(u8, value.len + 1); _ = try self.stream.writeAll(std.mem.asBytes(&@as(u32, @truncate(value.len + 1)))); @@ -124,10 +140,10 @@ pub fn request(self: *Self, object: anytype, args: @TypeOf(object.*).Request) !v _ = try self.stream.writeAll(std.mem.asBytes(&@as(u8, 0))); } }, - wayland.types.Fd => {}, + wayland.types.Fd => { }, else => |t| switch (@typeInfo(t)) { .pointer => |ptr| if (ptr.size == .slice) { - const padding_size: usize = @mod(@as(usize, @bitCast(-@as(isize, @intCast(value.len * @sizeOf(ptr.child))))), 4); + const padding_size: usize = padding_len(ptr.child, value.len); _ = try self.stream.writeAll(std.mem.asBytes(&@as(u32, @truncate(value.len)))); _ = try self.stream.writeAll(std.mem.sliceAsBytes(value)); for (0..padding_size) |_| { @@ -139,10 +155,6 @@ pub fn request(self: *Self, object: anytype, args: @TypeOf(object.*).Request) !v } } - if (fds.len > 0) { - try ancillary_data.send_fds(self.stream.handle, fds); - } - return; } } @@ -150,7 +162,7 @@ pub fn request(self: *Self, object: anytype, args: @TypeOf(object.*).Request) !v return error.InvalidOpcode; } -fn read_event(self: *Self, ctx: *wayland.Context) !void { +fn read_event(self: *Self, ctx: *const wayland.Context) !void { const endian = @import("builtin").target.cpu.arch.endian(); const reader = self.stream.reader(); @@ -200,7 +212,7 @@ pub fn roundtrip(self: *Self, allocator: std.mem.Allocator) !void { fn err( self: *Self, - ctx: *wayland.Context, + ctx: *const wayland.Context, object: *wayland.Object, code: u32, message: []const u8, @@ -212,7 +224,7 @@ fn err( fn delete_id( self: *Self, - ctx: *wayland.Context, + ctx: *const wayland.Context, id: u32, ) void { _ = ctx; @@ -226,6 +238,7 @@ test "request" { req2: struct { wayland.Object.Ref }, req3: struct { []const u8 }, req4: struct { []const u16 }, + req5: struct { wayland.types.Fd }, }; pub const Events = wayland.EventSet(@This(), .{}); @@ -237,66 +250,86 @@ test "request" { } }; - const in, const out = try std.posix.pipe(); - defer std.posix.close(in); + var tmpdir = std.testing.tmpDir(.{}); + defer tmpdir.cleanup(); + + var pathbuf: [std.fs.max_path_bytes]u8 = undefined; + var dirbuf: [std.fs.max_path_bytes]u8 = undefined; + const path = try std.fmt.bufPrint(&pathbuf, "{s}/testing", .{try tmpdir.dir.realpath(".", &dirbuf)}); + + const address = try std.net.Address.initUnix(path); + var server = try address.listen(.{}); { var sample: Sample = .init(); - var displ: Self = .from_fd(out); + var displ: Self = try .open(path); defer displ.deinit(std.testing.allocator); try displ.init(std.testing.allocator, &.{}); try displ.request(&sample, .{ .req1 = .{432} }); try displ.request(&sample, .{ .req2 = .{sample.handle} }); try displ.request(&sample, .{ .req3 = .{"abcd"} }); try displ.request(&sample, .{ .req4 = .{&[_]u16{ 1, 32, 4, 5, 5 }} }); + try displ.request(&sample, .{ .req5 = .{ .{ .fd = displ.stream.handle } } }); } - const file = std.fs.File{ .handle = in }; + const conn = try server.accept(); + const file = conn.stream; var test_buffer: [64]u8 = undefined; - _ = try file.readAll(test_buffer[0..12]); + var size = try file.readAll(test_buffer[0..12]); try std.testing.expectEqualSlices( u8, &(std.mem.toBytes(@as(u32, 1)) ++ std.mem.toBytes(@as(u32, (12 << 16) | 1)) ++ std.mem.toBytes(@as(u32, 2))), - test_buffer[0..12], + test_buffer[0..size], ); - _ = try file.readAll(test_buffer[0..12]); + size = try file.readAll(test_buffer[0..12]); try std.testing.expectEqualSlices( u8, &(std.mem.toBytes(@as(u32, 42)) ++ std.mem.toBytes(@as(u32, (12 << 16) | 0)) ++ std.mem.toBytes(@as(u32, 432))), - test_buffer[0..12], + test_buffer[0..size], ); - _ = try file.readAll(test_buffer[0..12]); + size = try file.readAll(test_buffer[0..12]); try std.testing.expectEqualSlices( u8, &(std.mem.toBytes(@as(u32, 42)) ++ std.mem.toBytes(@as(u32, (12 << 16) | 1)) ++ std.mem.toBytes(@as(u32, 42))), - test_buffer[0..12], + test_buffer[0..size], ); - _ = try file.readAll(test_buffer[0..20]); + size = try file.readAll(test_buffer[0..20]); try std.testing.expectEqualSlices( u8, &(std.mem.toBytes(@as(u32, 42)) ++ std.mem.toBytes(@as(u32, (20 << 16) | 2)) ++ std.mem.toBytes(@as(u32, 5))) ++ "abcd\x00\x00\x00\x00", - test_buffer[0..20], + test_buffer[0..size], ); - _ = try file.readAll(test_buffer[0..24]); + size = try file.readAll(test_buffer[0..24]); try std.testing.expectEqualSlices( u8, &(std.mem.toBytes(@as(u32, 42)) ++ std.mem.toBytes(@as(u32, (24 << 16) | 3)) ++ std.mem.toBytes(@as(u32, 5))) ++ std.mem.toBytes([_]u16{ 1, 32, 4, 5, 5, 0 }), - test_buffer[0..24], + test_buffer[0..size], + ); + + size = try file.readAll(test_buffer[0..8]); + try std.testing.expectEqualSlices( + u8, + &(std.mem.toBytes(@as(u32, 42)) ++ + std.mem.toBytes(@as(u32, (8 << 16) | 4))), + test_buffer[0..size], ); + + size = try file.readAll(test_buffer[0..]); + try std.testing.expectEqual(0, size); } |