| author | |
| committer | |
| log | c53cb65568e80a1d9c20a07373db86377ee9421b |
| tree | ccb31ca66a231b9f78dc908ff05b727f7e244d4a |
| parent | b3e8eb657772e46058ab011eb875b43d181e56c0 |
| signature | Commit is signed but in an unrecognized format. |
5 files changed, 149 insertions(+), 41 deletions(-)
lib/std/Io/net.zig+67-5| ... | ... | @@ -1378,7 +1378,7 @@ pub const Stream = struct { |
| 1378 | 1378 | pub const Reader = struct { |
| 1379 | 1379 | io: Io, |
| 1380 | 1380 | interface: Io.Reader, |
| 1381 | control_buffer: []u8, | |
| 1381 | control_buffer: []align(cmsg_align) u8, | |
| 1382 | 1382 | control_len: usize, |
| 1383 | 1383 | control_truncated: bool, |
| 1384 | 1384 | stream: Stream, |
| ... | ... | @@ -1391,7 +1391,12 @@ pub const Stream = struct { |
| 1391 | 1391 | } |
| 1392 | 1392 | |
| 1393 | 1393 | /// Same as `init`, but also provides a buffer for storing control data. |
| 1394 | pub fn initWithControl(stream: Stream, io: Io, buffer: []u8, control_buffer: []u8) Reader { | |
| 1394 | pub fn initWithControl( | |
| 1395 | stream: Stream, | |
| 1396 | io: Io, | |
| 1397 | buffer: []u8, | |
| 1398 | control_buffer: []align(cmsg_align) u8, | |
| 1399 | ) Reader { | |
| 1395 | 1400 | return .{ |
| 1396 | 1401 | .io = io, |
| 1397 | 1402 | .interface = .{ |
| ... | ... | @@ -1442,11 +1447,16 @@ pub const Stream = struct { |
| 1442 | 1447 | return result.data_len; |
| 1443 | 1448 | } |
| 1444 | 1449 | |
| 1445 | /// Get buffered control data. | |
| 1446 | pub fn controlSlice(r: *const Reader) []u8 { | |
| 1450 | /// Access raw buffered control data. | |
| 1451 | pub fn controlSlice(r: *const Reader) []align(cmsg_align) u8 { | |
| 1447 | 1452 | return r.control_buffer[0..r.control_len]; |
| 1448 | 1453 | } |
| 1449 | 1454 | |
| 1455 | /// Iterate over buffered control messages. | |
| 1456 | pub fn controlIterator(r: *const Reader) cmsg.Iterator { | |
| 1457 | return .{ .control = r.controlSlice() }; | |
| 1458 | } | |
| 1459 | ||
| 1450 | 1460 | /// Clear buffered control data. |
| 1451 | 1461 | pub fn clearControl(r: *Reader) void { |
| 1452 | 1462 | r.control_len = 0; |
| ... | ... | @@ -1542,7 +1552,12 @@ pub const Stream = struct { |
| 1542 | 1552 | } |
| 1543 | 1553 | |
| 1544 | 1554 | /// Same as `reader`, but also provides a buffer for storing control data. |
| 1545 | pub fn readerWithControl(stream: Stream, io: Io, buffer: []u8, control_buffer: []u8) Reader { | |
| 1555 | pub fn readerWithControl( | |
| 1556 | stream: Stream, | |
| 1557 | io: Io, | |
| 1558 | buffer: []u8, | |
| 1559 | control_buffer: []align(cmsg_align) u8, | |
| 1560 | ) Reader { | |
| 1546 | 1561 | return .initWithControl(stream, io, buffer, control_buffer); |
| 1547 | 1562 | } |
| 1548 | 1563 | |
| ... | ... | @@ -1551,6 +1566,53 @@ pub const Stream = struct { |
| 1551 | 1566 | } |
| 1552 | 1567 | }; |
| 1553 | 1568 | |
| 1569 | pub const cmsg_align = if (@TypeOf(std.posix.cmsg_align) == void) 1 else std.posix.cmsg_align; | |
| 1570 | /// Utility Functions for interacting with POSIX socket control messages. | |
| 1571 | /// See also https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_socket.h.html | |
| 1572 | pub const cmsg = struct { | |
| 1573 | const cmsghdr = std.posix.cmsghdr; | |
| 1574 | ||
| 1575 | /// Equivalent to `CMSG_SPACE` in C. | |
| 1576 | pub fn space(data_len: usize) usize { | |
| 1577 | return std.mem.alignForward(usize, @sizeOf(cmsghdr), cmsg_align) + | |
| 1578 | std.mem.alignForward(usize, data_len, cmsg_align); | |
| 1579 | } | |
| 1580 | ||
| 1581 | /// Equivalent to `CMSG_LEN` in C. | |
| 1582 | pub fn len(data_len: @FieldType(cmsghdr, "len")) @TypeOf(data_len) { | |
| 1583 | return std.mem.alignForward(@TypeOf(data_len), @sizeOf(cmsghdr), cmsg_align) + data_len; | |
| 1584 | } | |
| 1585 | ||
| 1586 | /// Equivalent to `CMSG_DATA` in C. | |
| 1587 | pub fn data(header: *align(cmsg_align) cmsghdr) []align(cmsg_align) u8 { | |
| 1588 | const bytes: [*]u8 = @ptrCast(header); | |
| 1589 | return @alignCast(bytes[0..header.len][std.mem.alignForward(usize, @sizeOf(cmsghdr), cmsg_align)..]); | |
| 1590 | } | |
| 1591 | ||
| 1592 | /// Equivalent to `CMSG_FIRSTHDR` and `CMSG_NXTHDR` in C. | |
| 1593 | pub const Iterator = struct { | |
| 1594 | control: []align(cmsg_align) u8, | |
| 1595 | ||
| 1596 | pub const Message = struct { | |
| 1597 | header: *cmsghdr, | |
| 1598 | data: []align(cmsg_align) u8, | |
| 1599 | }; | |
| 1600 | ||
| 1601 | pub fn next(it: *Iterator) ?Message { | |
| 1602 | if (it.control.len < @sizeOf(cmsghdr)) return null; | |
| 1603 | const header: *align(cmsg_align) cmsghdr = @ptrCast(it.control.ptr); | |
| 1604 | if (it.control.len < header.len) return null; | |
| 1605 | const next_header = std.mem.alignForward(usize, header.len, cmsg_align); | |
| 1606 | if (it.control.len < next_header) { | |
| 1607 | it.control = &.{}; | |
| 1608 | } else { | |
| 1609 | it.control = @alignCast(it.control[next_header..]); | |
| 1610 | } | |
| 1611 | return .{ .header = header, .data = data(header) }; | |
| 1612 | } | |
| 1613 | }; | |
| 1614 | }; | |
| 1615 | ||
| 1554 | 1616 | pub const Server = struct { |
| 1555 | 1617 | socket: Socket, |
| 1556 | 1618 | options: AcceptOptions, |
lib/std/Io/net/test.zig+16-36| ... | ... | @@ -4,6 +4,7 @@ const std = @import("std"); |
| 4 | 4 | const Io = std.Io; |
| 5 | 5 | const net = std.Io.net; |
| 6 | 6 | const mem = std.mem; |
| 7 | const posix = std.posix; | |
| 7 | 8 | const testing = std.testing; |
| 8 | 9 | const Allocator = std.mem.Allocator; |
| 9 | 10 | |
| ... | ... | @@ -321,26 +322,6 @@ test "listen on a unix socket, pass file descriptor" { |
| 321 | 322 | }; |
| 322 | 323 | defer server.socket.close(io); |
| 323 | 324 | |
| 324 | const cmsg_alignment = switch (builtin.os.tag) { | |
| 325 | .driverkit, | |
| 326 | .ios, | |
| 327 | .maccatalyst, | |
| 328 | .macos, | |
| 329 | .tvos, | |
| 330 | .visionos, | |
| 331 | .watchos, | |
| 332 | => 4, | |
| 333 | else => @sizeOf(usize), | |
| 334 | }; | |
| 335 | ||
| 336 | const cmsghdr_aligned_len = comptime mem.alignForward(usize, @sizeOf(std.posix.cmsghdr), cmsg_alignment); | |
| 337 | const cmsghdr_align = @alignOf(std.posix.cmsghdr); | |
| 338 | const fd_t_len = @sizeOf(std.posix.fd_t); | |
| 339 | ||
| 340 | const cmsg_buf_len = | |
| 341 | cmsghdr_aligned_len + | |
| 342 | comptime mem.alignForward(usize, fd_t_len, cmsg_alignment); | |
| 343 | ||
| 344 | 325 | const S = struct { |
| 345 | 326 | fn clientFn(path: []const u8, file_path: []const u8) !void { |
| 346 | 327 | const temp_file = try Io.Dir.cwd().createFile(io, file_path, .{}); |
| ... | ... | @@ -350,16 +331,16 @@ test "listen on a unix socket, pass file descriptor" { |
| 350 | 331 | var stream = try server_path.connect(io); |
| 351 | 332 | defer stream.close(io); |
| 352 | 333 | |
| 353 | var cmsg_buf: [cmsg_buf_len]u8 align(cmsghdr_align) = @splat(0); | |
| 334 | var cmsg_buf: [net.cmsg.space(@sizeOf(posix.fd_t))]u8 align(Io.net.cmsg_align) = @splat(0); | |
| 354 | 335 | |
| 355 | const header_ptr: *std.posix.cmsghdr = @ptrCast(&cmsg_buf); | |
| 356 | header_ptr.* = .{ | |
| 357 | .len = @intCast(cmsghdr_aligned_len + fd_t_len), | |
| 358 | .level = std.posix.SOL.SOCKET, | |
| 359 | .type = std.posix.SCM.RIGHTS, | |
| 336 | const header: *align(Io.net.cmsg_align) posix.cmsghdr = @ptrCast(&cmsg_buf); | |
| 337 | header.* = .{ | |
| 338 | .len = net.cmsg.len(@sizeOf(posix.fd_t)), | |
| 339 | .level = posix.SOL.SOCKET, | |
| 340 | .type = posix.SCM.RIGHTS, | |
| 360 | 341 | }; |
| 361 | 342 | |
| 362 | const fds = mem.bytesAsSlice(std.posix.fd_t, cmsg_buf[cmsghdr_aligned_len..]); | |
| 343 | const fds: []posix.fd_t = @ptrCast(net.cmsg.data(header)); | |
| 363 | 344 | fds[0] = temp_file.handle; |
| 364 | 345 | |
| 365 | 346 | var stream_writer = stream.writer(io, &.{}); |
| ... | ... | @@ -376,27 +357,26 @@ test "listen on a unix socket, pass file descriptor" { |
| 376 | 357 | var stream = try server.accept(io); |
| 377 | 358 | defer stream.close(io); |
| 378 | 359 | |
| 379 | var control_buf: [32]u8 align(cmsghdr_align) = undefined; | |
| 360 | var control_buf: [32]u8 align(Io.net.cmsg_align) = undefined; | |
| 380 | 361 | var buf: [16]u8 = undefined; |
| 381 | 362 | var stream_reader = stream.readerWithControl(io, &.{}, &control_buf); |
| 382 | 363 | |
| 383 | 364 | const n = try stream_reader.interface.readSliceShort(&buf); |
| 384 | const cmsg_buf = stream_reader.controlSlice(); | |
| 385 | 365 | |
| 386 | 366 | try testing.expect(!stream_reader.control_truncated); // The control buffer should be big enough to receive the entire control message |
| 387 | 367 | |
| 388 | 368 | try testing.expectEqual(12, n); |
| 389 | 369 | try testing.expectEqualStrings("Hello world!", buf[0..n]); |
| 390 | 370 | |
| 391 | try testing.expect(cmsg_buf.len >= cmsghdr_aligned_len + fd_t_len); | |
| 392 | ||
| 393 | const header_ptr: *const std.posix.cmsghdr = @ptrCast(@alignCast(cmsg_buf)); | |
| 371 | var it = stream_reader.controlIterator(); | |
| 372 | const control = it.next() orelse return error.TestUnexpectedResult; | |
| 373 | try testing.expectEqual(null, it.next()); | |
| 394 | 374 | |
| 395 | try testing.expectEqual(cmsghdr_aligned_len + fd_t_len, header_ptr.len); | |
| 396 | try testing.expectEqual(std.posix.SOL.SOCKET, header_ptr.level); | |
| 397 | try testing.expectEqual(std.posix.SCM.RIGHTS, header_ptr.type); | |
| 375 | try testing.expectEqual(net.cmsg.len(@sizeOf(posix.fd_t)), control.header.len); | |
| 376 | try testing.expectEqual(posix.SOL.SOCKET, control.header.level); | |
| 377 | try testing.expectEqual(posix.SCM.RIGHTS, control.header.type); | |
| 398 | 378 | |
| 399 | const fds = mem.bytesAsSlice(std.posix.fd_t, cmsg_buf[cmsghdr_aligned_len..]); | |
| 379 | const fds: []posix.fd_t = @ptrCast(control.data); | |
| 400 | 380 | |
| 401 | 381 | const temp_file: Io.File = .{ |
| 402 | 382 | .handle = fds[0], |
lib/std/c.zig+62| ... | ... | @@ -4432,6 +4432,68 @@ const posix_cmsghdr = extern struct { |
| 4432 | 4432 | type: c_int, |
| 4433 | 4433 | }; |
| 4434 | 4434 | |
| 4435 | // Alignment used by POSIX specified CMSG_* Macros | |
| 4436 | // https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_socket.h.html | |
| 4437 | pub const cmsg_align = switch (native_os) { | |
| 4438 | .linux => linux.cmsg_align, | |
| 4439 | // https://github.com/emscripten-core/emscripten/blob/96371ed7888fc78c040179f4d4faa82a6a07a116/system/lib/libc/musl/include/sys/socket.h#L362 | |
| 4440 | .emscripten => @sizeOf(usize), | |
| 4441 | // https://github.com/freebsd/freebsd-src/blob/b197d2abcb6895d78bc9df8404e374397aa44748/sys/sys/socket.h#L584 | |
| 4442 | // https://github.com/freebsd/freebsd-src/blob/d2018cedb414ef17e77b7fc2fa19fd81328da46b/sys/sys/_align.h#L30 | |
| 4443 | .freebsd => @sizeOf(*anyopaque), | |
| 4444 | // https://github.com/DragonFlyBSD/DragonFlyBSD/blob/d1f4fb943c73e2b61ddabff6aa48ce7551db72f4/sys/sys/socket.h#L441 | |
| 4445 | // https://github.com/DragonFlyBSD/DragonFlyBSD/blob/d1f4fb943c73e2b61ddabff6aa48ce7551db72f4/sys/cpu/x86_64/include/alignbytes.h#L35 | |
| 4446 | .dragonfly => switch (builtin.cpu.arch) { | |
| 4447 | .x86_64 => @sizeOf(c_long), | |
| 4448 | else => {}, | |
| 4449 | }, | |
| 4450 | // https://github.com/NetBSD/src/blob/ba8e1774fd9c0c26ecca461c07bc95d9ebb69579/sys/sys/socket.h#L544 | |
| 4451 | .netbsd => switch (builtin.cpu.arch) { | |
| 4452 | // https://github.com/NetBSD/src/blob/ac016822f750dc9166c84b6d2657479992622192/sys/arch/arm/include/cdefs.h#L63 | |
| 4453 | .aarch64, .aarch64_be => @sizeOf(i128), | |
| 4454 | .arm, .armeb => @sizeOf(c_longlong), | |
| 4455 | // https://github.com/NetBSD/src/blob/ac016822f750dc9166c84b6d2657479992622192/sys/arch/i386/include/cdefs.h#L9 | |
| 4456 | .x86 => @sizeOf(c_int), | |
| 4457 | // https://github.com/NetBSD/src/blob/ac016822f750dc9166c84b6d2657479992622192/sys/arch/amd64/include/cdefs.h#L6 | |
| 4458 | .x86_64 => @sizeOf(c_long), | |
| 4459 | // https://github.com/NetBSD/src/blob/ac016822f750dc9166c84b6d2657479992622192/sys/arch/mips/include/cdefs.h#L74 | |
| 4460 | .mips, .mips64, .mipsel, .mips64el => 8, | |
| 4461 | // https://github.com/NetBSD/src/blob/ac016822f750dc9166c84b6d2657479992622192/sys/arch/sparc/include/cdefs.h#L8 | |
| 4462 | .sparc64 => 16, | |
| 4463 | // https://github.com/NetBSD/src/blob/ac016822f750dc9166c84b6d2657479992622192/sys/arch/sparc/include/cdefs.h#L10 | |
| 4464 | .sparc => 8, | |
| 4465 | // https://github.com/NetBSD/src/blob/ac016822f750dc9166c84b6d2657479992622192/sys/arch/alpha/include/cdefs.h#L6 | |
| 4466 | .alpha => 8, | |
| 4467 | // https://github.com/NetBSD/src/blob/ac016822f750dc9166c84b6d2657479992622192/sys/arch/m68k/include/cdefs.h#L6 | |
| 4468 | .m68k => @sizeOf(c_int), | |
| 4469 | // https://github.com/NetBSD/src/blob/ac016822f750dc9166c84b6d2657479992622192/sys/arch/hppa/include/cdefs.h#L12 | |
| 4470 | .hppa => 8, | |
| 4471 | // https://github.com/NetBSD/src/blob/ac016822f750dc9166c84b6d2657479992622192/sys/arch/riscv/include/cdefs.h#L5 | |
| 4472 | .riscv32, .riscv32be, .riscv64, .riscv64be => @as(comptime_int, builtin.target.cMaxIntAlignment()), | |
| 4473 | // https://github.com/NetBSD/src/blob/ac016822f750dc9166c84b6d2657479992622192/sys/arch/powerpc/include/cdefs.h#L6 | |
| 4474 | .powerpc, .powerpcle, .powerpc64, .powerpc64le => @sizeOf(f64), | |
| 4475 | // https://github.com/NetBSD/src/blob/ac016822f750dc9166c84b6d2657479992622192/sys/arch/or1k/include/cdefs.h#L6 | |
| 4476 | .or1k => @as(comptime_int, builtin.target.cMaxIntAlignment()), | |
| 4477 | else => {}, | |
| 4478 | }, | |
| 4479 | // https://github.com/openbsd/src/blob/4a7ecdb29021f26ee0ef397afdd2931e20e63071/sys/sys/socket.h#L564 | |
| 4480 | // https://github.com/openbsd/src/blob/4a7ecdb29021f26ee0ef397afdd2931e20e63071/sys/arch/amd64/include/_types.h#L50 | |
| 4481 | .openbsd => @sizeOf(c_long), | |
| 4482 | // https://github.com/illumos/illumos-gate/blob/c1e950d976948602134f0e0e5dadf3d48a7ee996/usr/src/uts/common/sys/socket.h#L469 | |
| 4483 | .illumos => 4, | |
| 4484 | // https://github.com/haiku/haiku/blob/b54f586058fd6623645512e4631468cede9933b9/headers/posix/sys/socket.h#L152 | |
| 4485 | // https://github.com/haiku/haiku/blob/6059d64cb7cd145f0f1eb5b89c383f71e4b6bebf/headers/posix/sys/param.h#L28 | |
| 4486 | .haiku => @sizeOf(c_long), | |
| 4487 | // https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/sys/socket.h#L1077 | |
| 4488 | .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => 4, | |
| 4489 | else => {}, | |
| 4490 | }; | |
| 4491 | comptime { | |
| 4492 | if (@TypeOf(cmsg_align) != void and @TypeOf(cmsghdr) != void) { | |
| 4493 | assert(cmsg_align >= @alignOf(cmsghdr)); | |
| 4494 | } | |
| 4495 | } | |
| 4496 | ||
| 4435 | 4497 | pub const nfds_t = switch (native_os) { |
| 4436 | 4498 | .linux => linux.nfds_t, |
| 4437 | 4499 | .emscripten => emscripten.nfds_t, |
lib/std/os/linux.zig+3| ... | ... | @@ -11244,6 +11244,9 @@ pub const cmsghdr = extern struct { |
| 11244 | 11244 | type: i32, |
| 11245 | 11245 | }; |
| 11246 | 11246 | |
| 11247 | // https://github.com/torvalds/linux/blob/72d3fcf802c45d00b300f25b848a93c3a2bd7c7e/include/linux/socket.h#L133 | |
| 11248 | pub const cmsg_align = @sizeOf(c_long); | |
| 11249 | ||
| 11247 | 11250 | pub const riscv_hwprobe = extern struct { |
| 11248 | 11251 | key: i64, |
| 11249 | 11252 | value: u64, |
lib/std/posix.zig+1| ... | ... | @@ -151,6 +151,7 @@ pub const blksize_t = system.blksize_t; |
| 151 | 151 | pub const clock_t = system.clock_t; |
| 152 | 152 | pub const clockid_t = system.clockid_t; |
| 153 | 153 | pub const cmsghdr = system.cmsghdr; |
| 154 | pub const cmsg_align = system.cmsg_align; | |
| 154 | 155 | pub const timerfd_clockid_t = system.timerfd_clockid_t; |
| 155 | 156 | pub const cpu_set_t = system.cpu_set_t; |
| 156 | 157 | pub const dev_t = system.dev_t; |