| ... | @@ -2943,3 +2943,71 @@ test "linkat" { | ... | @@ -2943,3 +2943,71 @@ test "linkat" { |
| 2943 | const read = try second_file.readAll(&second_file_data); | 2943 | const read = try second_file.readAll(&second_file_data); |
| 2944 | try testing.expectEqualStrings("hello", second_file_data[0..read]); | 2944 | try testing.expectEqualStrings("hello", second_file_data[0..read]); |
| 2945 | } | 2945 | } |
| | 2946 | |
| | 2947 | /// Used for testing server/client interactions. |
| | 2948 | const SocketTestHarness = struct { |
| | 2949 | listener: os.socket_t, |
| | 2950 | server: os.socket_t, |
| | 2951 | client: os.socket_t, |
| | 2952 | |
| | 2953 | fn close(self: SocketTestHarness) void { |
| | 2954 | os.closeSocket(self.client); |
| | 2955 | os.closeSocket(self.listener); |
| | 2956 | } |
| | 2957 | }; |
| | 2958 | |
| | 2959 | fn createSocketTestHarness(ring: *IO_Uring) !SocketTestHarness { |
| | 2960 | // Create a TCP server socket |
| | 2961 | |
| | 2962 | const address = try net.Address.parseIp4("127.0.0.1", 3131); |
| | 2963 | const kernel_backlog = 1; |
| | 2964 | const listener_socket = try os.socket(address.any.family, os.SOCK.STREAM | os.SOCK.CLOEXEC, 0); |
| | 2965 | errdefer os.closeSocket(listener_socket); |
| | 2966 | |
| | 2967 | try os.setsockopt(listener_socket, os.SOL.SOCKET, os.SO.REUSEADDR, &mem.toBytes(@as(c_int, 1))); |
| | 2968 | try os.bind(listener_socket, &address.any, address.getOsSockLen()); |
| | 2969 | try os.listen(listener_socket, kernel_backlog); |
| | 2970 | |
| | 2971 | // Submit 1 accept |
| | 2972 | var accept_addr: os.sockaddr = undefined; |
| | 2973 | var accept_addr_len: os.socklen_t = @sizeOf(@TypeOf(accept_addr)); |
| | 2974 | _ = try ring.accept(0xaaaaaaaa, listener_socket, &accept_addr, &accept_addr_len, 0); |
| | 2975 | |
| | 2976 | // Create a TCP client socket |
| | 2977 | const client = try os.socket(address.any.family, os.SOCK.STREAM | os.SOCK.CLOEXEC, 0); |
| | 2978 | errdefer os.closeSocket(client); |
| | 2979 | _ = try ring.connect(0xcccccccc, client, &address.any, address.getOsSockLen()); |
| | 2980 | |
| | 2981 | try testing.expectEqual(@as(u32, 2), try ring.submit()); |
| | 2982 | |
| | 2983 | var cqe_accept = try ring.copy_cqe(); |
| | 2984 | if (cqe_accept.err() == .INVAL) return error.SkipZigTest; |
| | 2985 | var cqe_connect = try ring.copy_cqe(); |
| | 2986 | if (cqe_connect.err() == .INVAL) return error.SkipZigTest; |
| | 2987 | |
| | 2988 | // The accept/connect CQEs may arrive in any order, the connect CQE will sometimes come first: |
| | 2989 | if (cqe_accept.user_data == 0xcccccccc and cqe_connect.user_data == 0xaaaaaaaa) { |
| | 2990 | const a = cqe_accept; |
| | 2991 | const b = cqe_connect; |
| | 2992 | cqe_accept = b; |
| | 2993 | cqe_connect = a; |
| | 2994 | } |
| | 2995 | |
| | 2996 | try testing.expectEqual(@as(u64, 0xaaaaaaaa), cqe_accept.user_data); |
| | 2997 | if (cqe_accept.res <= 0) std.debug.print("\ncqe_accept.res={}\n", .{cqe_accept.res}); |
| | 2998 | try testing.expect(cqe_accept.res > 0); |
| | 2999 | try testing.expectEqual(@as(u32, 0), cqe_accept.flags); |
| | 3000 | try testing.expectEqual(linux.io_uring_cqe{ |
| | 3001 | .user_data = 0xcccccccc, |
| | 3002 | .res = 0, |
| | 3003 | .flags = 0, |
| | 3004 | }, cqe_connect); |
| | 3005 | |
| | 3006 | // All good |
| | 3007 | |
| | 3008 | return SocketTestHarness{ |
| | 3009 | .listener = listener_socket, |
| | 3010 | .server = cqe_accept.res, |
| | 3011 | .client = client, |
| | 3012 | }; |
| | 3013 | } |