| ... | @@ -1399,15 +1399,18 @@ pub fn listen( | ... | @@ -1399,15 +1399,18 @@ pub fn listen( |
| 1399 | return sqe; | 1399 | return sqe; |
| 1400 | } | 1400 | } |
| 1401 | | 1401 | |
| 1402 | fn cmd_sock( | 1402 | /// Prepares an cmd request for a socket. |
| | 1403 | /// See: https://man7.org/linux/man-pages/man3/io_uring_prep_cmd.3.html |
| | 1404 | /// Available since 6.7. |
| | 1405 | pub fn cmd_sock( |
| 1403 | self: *IoUring, | 1406 | self: *IoUring, |
| 1404 | user_data: u64, | 1407 | user_data: u64, |
| 1405 | cmd_op: linux.IO_URING_SOCKET_OP, | 1408 | cmd_op: linux.IO_URING_SOCKET_OP, |
| 1406 | fd: linux.fd_t, | 1409 | fd: linux.fd_t, |
| 1407 | level: u32, | 1410 | level: u32, // linux.SOL |
| 1408 | optname: u32, | 1411 | optname: u32, // linux.SO |
| 1409 | optval: u64, | 1412 | optval: u64, // pointer to the option value |
| 1410 | optlen: u32, | 1413 | optlen: u32, // size of the option value |
| 1411 | ) !*linux.io_uring_sqe { | 1414 | ) !*linux.io_uring_sqe { |
| 1412 | const sqe = try self.get_sqe(); | 1415 | const sqe = try self.get_sqe(); |
| 1413 | sqe.prep_cmd_sock(cmd_op, fd, level, optname, optval, optlen); | 1416 | sqe.prep_cmd_sock(cmd_op, fd, level, optname, optval, optlen); |
| ... | @@ -1415,6 +1418,50 @@ fn cmd_sock( | ... | @@ -1415,6 +1418,50 @@ fn cmd_sock( |
| 1415 | return sqe; | 1418 | return sqe; |
| 1416 | } | 1419 | } |
| 1417 | | 1420 | |
| | 1421 | /// Prepares set socket option for the optname argument, at the protocol |
| | 1422 | /// level specified by the level argument. |
| | 1423 | /// Available since 6.7.n |
| | 1424 | pub fn setsockopt( |
| | 1425 | self: *IoUring, |
| | 1426 | user_data: u64, |
| | 1427 | fd: linux.fd_t, |
| | 1428 | level: u32, // linux.SOL |
| | 1429 | optname: u32, // linux.SO |
| | 1430 | opt: []const u8, |
| | 1431 | ) !*linux.io_uring_sqe { |
| | 1432 | return try self.cmd_sock( |
| | 1433 | user_data, |
| | 1434 | .SETSOCKOPT, |
| | 1435 | fd, |
| | 1436 | level, |
| | 1437 | optname, |
| | 1438 | @intFromPtr(opt.ptr), |
| | 1439 | @intCast(opt.len), |
| | 1440 | ); |
| | 1441 | } |
| | 1442 | |
| | 1443 | /// Prepares get socket option to retrieve the value for the option specified by |
| | 1444 | /// the option_name argument for the socket specified by the fd argument. |
| | 1445 | /// Available since 6.7. |
| | 1446 | pub fn getsockopt( |
| | 1447 | self: *IoUring, |
| | 1448 | user_data: u64, |
| | 1449 | fd: linux.fd_t, |
| | 1450 | level: u32, // linux.SOL |
| | 1451 | optname: u32, // linux.SO |
| | 1452 | opt: []u8, |
| | 1453 | ) !*linux.io_uring_sqe { |
| | 1454 | return try self.cmd_sock( |
| | 1455 | user_data, |
| | 1456 | .GETSOCKOPT, |
| | 1457 | fd, |
| | 1458 | level, |
| | 1459 | optname, |
| | 1460 | @intFromPtr(opt.ptr), |
| | 1461 | @intCast(opt.len), |
| | 1462 | ); |
| | 1463 | } |
| | 1464 | |
| 1418 | pub const SubmissionQueue = struct { | 1465 | pub const SubmissionQueue = struct { |
| 1419 | head: *u32, | 1466 | head: *u32, |
| 1420 | tail: *u32, | 1467 | tail: *u32, |
| ... | @@ -4391,13 +4438,10 @@ test "bind/listen/connect" { | ... | @@ -4391,13 +4438,10 @@ test "bind/listen/connect" { |
| 4391 | try testing.expect(listen_fd > 2); | 4438 | try testing.expect(listen_fd > 2); |
| 4392 | | 4439 | |
| 4393 | // Prepare: set socket option * 2, bind, listen | 4440 | // Prepare: set socket option * 2, bind, listen |
| 4394 | var sock_opt: u32 = 1; | 4441 | var optval: u32 = 1; |
| 4395 | var sqe = try ring.cmd_sock(2, .SETSOCKOPT, listen_fd, linux.SOL.SOCKET, linux.SO.REUSEADDR, @intFromPtr(&sock_opt), @sizeOf(u32)); | 4442 | (try ring.setsockopt(2, listen_fd, linux.SOL.SOCKET, linux.SO.REUSEADDR, mem.asBytes(&optval))).link_next(); |
| 4396 | sqe.flags |= linux.IOSQE_IO_LINK; | 4443 | (try ring.setsockopt(3, listen_fd, linux.SOL.SOCKET, linux.SO.REUSEPORT, mem.asBytes(&optval))).link_next(); |
| 4397 | sqe = try ring.cmd_sock(3, .SETSOCKOPT, listen_fd, linux.SOL.SOCKET, linux.SO.REUSEPORT, @intFromPtr(&sock_opt), @sizeOf(u32)); | 4444 | (try ring.bind(4, listen_fd, &addr.any, addr.getOsSockLen(), 0)).link_next(); |
| 4398 | sqe.flags |= linux.IOSQE_IO_LINK; | | |
| 4399 | sqe = try ring.bind(4, listen_fd, &addr.any, addr.getOsSockLen(), 0); | | |
| 4400 | sqe.flags |= linux.IOSQE_IO_LINK; | | |
| 4401 | _ = try ring.listen(5, listen_fd, 1, 0); | 4445 | _ = try ring.listen(5, listen_fd, 1, 0); |
| 4402 | // Submit 4 operations | 4446 | // Submit 4 operations |
| 4403 | try testing.expectEqual(4, try ring.submit()); | 4447 | try testing.expectEqual(4, try ring.submit()); |
| ... | @@ -4409,13 +4453,13 @@ test "bind/listen/connect" { | ... | @@ -4409,13 +4453,13 @@ test "bind/listen/connect" { |
| 4409 | } | 4453 | } |
| 4410 | | 4454 | |
| 4411 | // Check that socket option is set | 4455 | // Check that socket option is set |
| 4412 | sock_opt = 0xff; | 4456 | optval = 0; |
| 4413 | _ = try ring.cmd_sock(5, .GETSOCKOPT, listen_fd, linux.SOL.SOCKET, linux.SO.REUSEADDR, @intFromPtr(&sock_opt), @sizeOf(u32)); | 4457 | _ = try ring.getsockopt(5, listen_fd, linux.SOL.SOCKET, linux.SO.REUSEADDR, mem.asBytes(&optval)); |
| 4414 | try testing.expectEqual(1, try ring.submit()); | 4458 | try testing.expectEqual(1, try ring.submit()); |
| 4415 | cqe = try ring.copy_cqe(); | 4459 | cqe = try ring.copy_cqe(); |
| 4416 | try testing.expectEqual(5, cqe.user_data); | 4460 | try testing.expectEqual(5, cqe.user_data); |
| 4417 | try testing.expectEqual(posix.E.SUCCESS, cqe.err()); | 4461 | try testing.expectEqual(posix.E.SUCCESS, cqe.err()); |
| 4418 | try testing.expectEqual(1, sock_opt); | 4462 | try testing.expectEqual(1, optval); |
| 4419 | | 4463 | |
| 4420 | // Read system assigned port into addr | 4464 | // Read system assigned port into addr |
| 4421 | var addr_len: posix.socklen_t = addr.getOsSockLen(); | 4465 | var addr_len: posix.socklen_t = addr.getOsSockLen(); |
| ... | @@ -4460,8 +4504,7 @@ test "bind/listen/connect" { | ... | @@ -4460,8 +4504,7 @@ test "bind/listen/connect" { |
| 4460 | | 4504 | |
| 4461 | // Shutdown and close all sockets | 4505 | // Shutdown and close all sockets |
| 4462 | for ([_]posix.socket_t{ connect_fd, accept_fd, listen_fd }) |fd| { | 4506 | for ([_]posix.socket_t{ connect_fd, accept_fd, listen_fd }) |fd| { |
| 4463 | var sqe = try ring.shutdown(9, fd, posix.SHUT.RDWR); | 4507 | (try ring.shutdown(9, fd, posix.SHUT.RDWR)).link_next(); |
| 4464 | sqe.flags |= linux.IOSQE_IO_LINK; | | |
| 4465 | _ = try ring.close(10, fd); | 4508 | _ = try ring.close(10, fd); |
| 4466 | try testing.expectEqual(2, try ring.submit()); | 4509 | try testing.expectEqual(2, try ring.submit()); |
| 4467 | for (0..2) |i| { | 4510 | for (0..2) |i| { |
| ... | @@ -4477,8 +4520,7 @@ fn testSendRecv(ring: *IoUring, send_fd: posix.socket_t, recv_fd: posix.socket_t | ... | @@ -4477,8 +4520,7 @@ fn testSendRecv(ring: *IoUring, send_fd: posix.socket_t, recv_fd: posix.socket_t |
| 4477 | var buffer_recv: [buffer_send.len * 2]u8 = undefined; | 4520 | var buffer_recv: [buffer_send.len * 2]u8 = undefined; |
| 4478 | | 4521 | |
| 4479 | // 2 sends | 4522 | // 2 sends |
| 4480 | var sqe = try ring.send(1, send_fd, buffer_send, linux.MSG.WAITALL); | 4523 | _ = try ring.send(1, send_fd, buffer_send, linux.MSG.WAITALL); |
| 4481 | sqe.flags |= linux.IOSQE_IO_LINK; | | |
| 4482 | _ = try ring.send(2, send_fd, buffer_send, linux.MSG.WAITALL); | 4524 | _ = try ring.send(2, send_fd, buffer_send, linux.MSG.WAITALL); |
| 4483 | try testing.expectEqual(2, try ring.submit()); | 4525 | try testing.expectEqual(2, try ring.submit()); |
| 4484 | for (0..2) |i| { | 4526 | for (0..2) |i| { |