Skip to content

Commit 3422dfd

Browse files
committed
std: Decouple network streams from fs.File
The overlap between files and sockets is minimal and lumping them together means supporting only a small subset of the functionalities provided by the OS. Moreover the socket and file handles are not always interchangeable: on Windows one should use Winsock's close() call rather than the one used for common files.
1 parent ab4b34f commit 3422dfd

File tree

2 files changed

+57
-7
lines changed

2 files changed

+57
-7
lines changed

lib/std/net.zig

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const net = @This();
1010
const mem = std.mem;
1111
const os = std.os;
1212
const fs = std.fs;
13+
const io = std.io;
1314

1415
pub const has_unix_sockets = @hasDecl(os, "sockaddr_un");
1516

@@ -651,7 +652,7 @@ pub const AddressList = struct {
651652
};
652653

653654
/// All memory allocated with `allocator` will be freed before this function returns.
654-
pub fn tcpConnectToHost(allocator: *mem.Allocator, name: []const u8, port: u16) !fs.File {
655+
pub fn tcpConnectToHost(allocator: *mem.Allocator, name: []const u8, port: u16) !Stream {
655656
const list = try getAddressList(allocator, name, port);
656657
defer list.deinit();
657658

@@ -668,7 +669,7 @@ pub fn tcpConnectToHost(allocator: *mem.Allocator, name: []const u8, port: u16)
668669
return std.os.ConnectError.ConnectionRefused;
669670
}
670671

671-
pub fn tcpConnectToAddress(address: Address) !fs.File {
672+
pub fn tcpConnectToAddress(address: Address) !Stream {
672673
const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0;
673674
const sock_flags = os.SOCK_STREAM | nonblock |
674675
(if (builtin.os.tag == .windows) 0 else os.SOCK_CLOEXEC);
@@ -682,7 +683,7 @@ pub fn tcpConnectToAddress(address: Address) !fs.File {
682683
try os.connect(sockfd, &address.any, address.getOsSockLen());
683684
}
684685

685-
return fs.File{ .handle = sockfd };
686+
return Stream{ .handle = sockfd };
686687
}
687688

688689
/// Call `AddressList.deinit` on the result.
@@ -1565,6 +1566,55 @@ fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8)
15651566
}
15661567
}
15671568

1569+
pub const Stream = struct {
1570+
// Underlying socket descriptor.
1571+
// Note that on some platforms this may not be interchangeable with a
1572+
// regular files descriptor.
1573+
handle: os.socket_t,
1574+
1575+
pub fn close(self: Stream) void {
1576+
os.closeSocket(self.handle);
1577+
}
1578+
1579+
pub const ReadError = os.ReadError;
1580+
pub const WriteError = os.WriteError;
1581+
1582+
pub const Reader = io.Reader(Stream, ReadError, read);
1583+
pub const Writer = io.Writer(Stream, WriteError, write);
1584+
1585+
pub fn reader(self: Stream) Reader {
1586+
return .{ .context = self };
1587+
}
1588+
1589+
pub fn writer(self: Stream) Writer {
1590+
return .{ .context = self };
1591+
}
1592+
1593+
pub fn read(self: Stream, buffer: []u8) ReadError!usize {
1594+
if (std.Target.current.os.tag == .windows) {
1595+
return os.windows.ReadFile(self.handle, buffer, null, io.default_mode);
1596+
}
1597+
1598+
if (std.io.is_async) {
1599+
return std.event.Loop.instance.?.read(self.handle, buffer, false);
1600+
} else {
1601+
return os.read(self.handle, buffer);
1602+
}
1603+
}
1604+
1605+
pub fn write(self: Stream, buffer: []const u8) WriteError!usize {
1606+
if (std.Target.current.os.tag == .windows) {
1607+
return os.windows.WriteFile(self.handle, buffer, null, io.default_mode);
1608+
}
1609+
1610+
if (std.io.is_async) {
1611+
return std.event.Loop.instance.?.write(self.handle, buffer, false);
1612+
} else {
1613+
return os.write(self.handle, buffer);
1614+
}
1615+
}
1616+
};
1617+
15681618
pub const StreamServer = struct {
15691619
/// Copied from `Options` on `init`.
15701620
kernel_backlog: u31,
@@ -1675,7 +1725,7 @@ pub const StreamServer = struct {
16751725
} || os.UnexpectedError;
16761726

16771727
pub const Connection = struct {
1678-
file: fs.File,
1728+
stream: Stream,
16791729
address: Address,
16801730
};
16811731

@@ -1694,7 +1744,7 @@ pub const StreamServer = struct {
16941744

16951745
if (accept_result) |fd| {
16961746
return Connection{
1697-
.file = fs.File{ .handle = fd },
1747+
.stream = Stream{ .handle = fd },
16981748
.address = accepted_addr,
16991749
};
17001750
} else |err| switch (err) {

lib/std/net/test.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ test "listen on a port, send bytes, receive bytes" {
166166

167167
var client = try server.accept();
168168
var buf: [16]u8 = undefined;
169-
const n = try client.file.reader().read(&buf);
169+
const n = try client.stream.reader().read(&buf);
170170

171171
testing.expectEqual(@as(usize, 12), n);
172172
testing.expectEqualSlices(u8, "Hello world!", buf[0..n]);
@@ -249,6 +249,6 @@ fn testServer(server: *net.StreamServer) anyerror!void {
249249

250250
var client = try server.accept();
251251

252-
const stream = client.file.outStream();
252+
const stream = client.stream.writer();
253253
try stream.print("hello from server\n", .{});
254254
}

0 commit comments

Comments
 (0)