Skip to content

Commit 46753ab

Browse files
NTARelixkarlseguin
andauthored
Fix Test Utilities on Windows (karlseguin#95)
* On windows, setup a fake socket pair karlseguin#93 * close the temp socketpair listener * use standard posix socket type for testing socket pair closes karlseguin#93 --------- Co-authored-by: Karl Seguin <[email protected]>
1 parent 8debcde commit 46753ab

File tree

1 file changed

+47
-14
lines changed

1 file changed

+47
-14
lines changed

src/t.zig

+47-14
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
const std = @import("std");
66
const httpz = @import("httpz.zig");
77

8+
const posix = std.posix;
89
const Allocator = std.mem.Allocator;
910

1011
const Conn = @import("worker.zig").HTTPConn;
@@ -26,7 +27,7 @@ pub fn reset() void {
2627

2728
pub fn getRandom() std.Random.DefaultPrng {
2829
var seed: u64 = undefined;
29-
std.posix.getrandom(std.mem.asBytes(&seed)) catch unreachable;
30+
posix.getrandom(std.mem.asBytes(&seed)) catch unreachable;
3031
return std.Random.DefaultPrng.init(seed);
3132
}
3233

@@ -49,25 +50,34 @@ pub const Context = struct {
4950
_random: ?std.Random.DefaultPrng = null,
5051

5152
pub fn allocInit(ctx_allocator: Allocator, config_: httpz.Config) Context {
52-
var pair: [2]c_int = undefined;
53-
const rc = std.c.socketpair(std.posix.AF.LOCAL, std.posix.SOCK.STREAM, 0, &pair);
54-
if (rc != 0) {
55-
@panic("socketpair fail");
53+
var pair: [2]posix.socket_t = undefined;
54+
if (@import("builtin").os.tag == .windows) {
55+
// create the socket pair manually on Windows because `socketpair` does not exist on Windows
56+
// use INET instead of LOCAL because LOCAL is an alias for UNIX, which does not exist on Windows
57+
setupFakeSocketPair(&pair[0], &pair[1]) catch |err| {
58+
std.debug.print("Failed to setup local client<->server: {}", .{err});
59+
@panic(@errorName(err));
60+
};
61+
} else {
62+
const rc = std.c.socketpair(posix.AF.LOCAL, posix.SOCK.STREAM, 0, &pair);
63+
if (rc != 0) {
64+
@panic("socketpair fail");
65+
}
5666
}
5767

5868
{
59-
const timeout = std.mem.toBytes(std.posix.timeval{
69+
const timeout = std.mem.toBytes(posix.timeval{
6070
.sec = 0,
6171
.usec = 20_000,
6272
});
63-
std.posix.setsockopt(pair[0], std.posix.SOL.SOCKET, std.posix.SO.RCVTIMEO, &timeout) catch unreachable;
64-
std.posix.setsockopt(pair[0], std.posix.SOL.SOCKET, std.posix.SO.SNDTIMEO, &timeout) catch unreachable;
65-
std.posix.setsockopt(pair[1], std.posix.SOL.SOCKET, std.posix.SO.RCVTIMEO, &timeout) catch unreachable;
66-
std.posix.setsockopt(pair[1], std.posix.SOL.SOCKET, std.posix.SO.SNDTIMEO, &timeout) catch unreachable;
73+
posix.setsockopt(pair[0], posix.SOL.SOCKET, posix.SO.RCVTIMEO, &timeout) catch unreachable;
74+
posix.setsockopt(pair[0], posix.SOL.SOCKET, posix.SO.SNDTIMEO, &timeout) catch unreachable;
75+
posix.setsockopt(pair[1], posix.SOL.SOCKET, posix.SO.RCVTIMEO, &timeout) catch unreachable;
76+
posix.setsockopt(pair[1], posix.SOL.SOCKET, posix.SO.SNDTIMEO, &timeout) catch unreachable;
6777

6878
// for request.fuzz, which does up to an 8K write. Not sure why this has
6979
// to be so much more but on linux, even a 10K SNDBUF results in WOULD_BLOCK.
70-
std.posix.setsockopt(pair[1], std.posix.SOL.SOCKET, std.posix.SO.SNDBUF, &std.mem.toBytes(@as(c_int, 20_000))) catch unreachable;
80+
posix.setsockopt(pair[1], posix.SOL.SOCKET, posix.SO.SNDBUF, &std.mem.toBytes(@as(c_int, 20_000))) catch unreachable;
7181
}
7282

7383
const server = std.net.Stream{ .handle = pair[0] };
@@ -141,6 +151,29 @@ pub const Context = struct {
141151
ctx_allocator.destroy(self.arena);
142152
}
143153

154+
fn setupFakeSocketPair(server: *posix.socket_t, client: *posix.socket_t) !void {
155+
const listener = posix.socket(posix.AF.INET, posix.SOCK.STREAM, 0) catch unreachable;
156+
defer posix.close(listener);
157+
158+
var address = try std.net.Address.parseIp("127.0.0.1", 0);
159+
try posix.setsockopt(listener, posix.SOL.SOCKET, posix.SO.REUSEADDR, &std.mem.toBytes(@as(c_int, 1)));
160+
try posix.bind(listener, &address.any, address.getOsSockLen());
161+
try posix.listen(listener, 0);
162+
163+
var len: posix.socklen_t = @sizeOf(std.net.Address);
164+
try posix.getsockname(listener, &address.any, &len);
165+
166+
var thread = try std.Thread.spawn(.{}, struct {
167+
fn accept(l: posix.socket_t, server_side: *posix.socket_t) !void {
168+
server_side.* = try posix.accept(l, null, null, 0);
169+
}
170+
}.accept, .{ listener, server });
171+
172+
client.* = posix.socket(posix.AF.INET, posix.SOCK.STREAM, 0) catch unreachable;
173+
try posix.connect(client.*, &address.any, address.getOsSockLen());
174+
thread.join();
175+
}
176+
144177
// force the server side socket to be closed, which helps our reading-test
145178
// know that there's no more data.
146179
pub fn close(self: *Context) void {
@@ -187,7 +220,7 @@ pub const Context = struct {
187220
// should have no extra data
188221
// let's check, with a shor timeout, which could let things slip, but
189222
// else we slow down fuzz tests too much
190-
std.posix.setsockopt(self.client.handle, std.posix.SOL.SOCKET, std.posix.SO.RCVTIMEO, &std.mem.toBytes(std.posix.timeval{
223+
posix.setsockopt(self.client.handle, posix.SOL.SOCKET, posix.SO.RCVTIMEO, &std.mem.toBytes(posix.timeval{
191224
.sec = 0,
192225
.usec = 1_000,
193226
})) catch unreachable;
@@ -200,7 +233,7 @@ pub const Context = struct {
200233
};
201234
try expectEqual(0, n);
202235

203-
std.posix.setsockopt(self.client.handle, std.posix.SOL.SOCKET, std.posix.SO.RCVTIMEO, &std.mem.toBytes(std.posix.timeval{
236+
posix.setsockopt(self.client.handle, posix.SOL.SOCKET, posix.SO.RCVTIMEO, &std.mem.toBytes(posix.timeval{
204237
.sec = 0,
205238
.usec = 20_000,
206239
})) catch unreachable;
@@ -209,7 +242,7 @@ pub const Context = struct {
209242
fn random(self: *Context) std.Random {
210243
if (self._random == null) {
211244
var seed: u64 = undefined;
212-
std.posix.getrandom(std.mem.asBytes(&seed)) catch unreachable;
245+
posix.getrandom(std.mem.asBytes(&seed)) catch unreachable;
213246
self._random = std.Random.DefaultPrng.init(seed);
214247
}
215248
return self._random.?.random();

0 commit comments

Comments
 (0)