aboutsummaryrefslogtreecommitdiff
path: root/lib/std/net.zig
diff options
context:
space:
mode:
authorLemonBoy <thatlemon@gmail.com>2020-11-16 10:19:00 +0100
committerLemonBoy <thatlemon@gmail.com>2021-01-11 21:43:09 +0100
commit89d6317b93bbe5aac00c6af5833b3e74211ab37f (patch)
tree4cffb9731dc8522e46c95c58813a94af66187ae6 /lib/std/net.zig
parentcc2981edfc4c0e36d3ce6d564f7a36caae9b61b7 (diff)
downloadzig-89d6317b93bbe5aac00c6af5833b3e74211ab37f.tar.gz
zig-89d6317b93bbe5aac00c6af5833b3e74211ab37f.zip
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.
Diffstat (limited to 'lib/std/net.zig')
-rw-r--r--lib/std/net.zig64
1 files changed, 57 insertions, 7 deletions
diff --git a/lib/std/net.zig b/lib/std/net.zig
index 037df76907..41da4a2c46 100644
--- a/lib/std/net.zig
+++ b/lib/std/net.zig
@@ -10,6 +10,7 @@ const net = @This();
const mem = std.mem;
const os = std.os;
const fs = std.fs;
+const io = std.io;
pub const has_unix_sockets = @hasDecl(os, "sockaddr_un");
@@ -596,7 +597,7 @@ pub const Ip6Address = extern struct {
}
};
-pub fn connectUnixSocket(path: []const u8) !fs.File {
+pub fn connectUnixSocket(path: []const u8) !Stream {
const opt_non_block = if (std.io.is_async) os.SOCK_NONBLOCK else 0;
const sockfd = try os.socket(
os.AF_UNIX,
@@ -614,7 +615,7 @@ pub fn connectUnixSocket(path: []const u8) !fs.File {
try os.connect(sockfd, &addr.any, addr.getOsSockLen());
}
- return fs.File{
+ return Stream{
.handle = sockfd,
};
}
@@ -648,7 +649,7 @@ pub const AddressList = struct {
};
/// All memory allocated with `allocator` will be freed before this function returns.
-pub fn tcpConnectToHost(allocator: *mem.Allocator, name: []const u8, port: u16) !fs.File {
+pub fn tcpConnectToHost(allocator: *mem.Allocator, name: []const u8, port: u16) !Stream {
const list = try getAddressList(allocator, name, port);
defer list.deinit();
@@ -665,7 +666,7 @@ pub fn tcpConnectToHost(allocator: *mem.Allocator, name: []const u8, port: u16)
return std.os.ConnectError.ConnectionRefused;
}
-pub fn tcpConnectToAddress(address: Address) !fs.File {
+pub fn tcpConnectToAddress(address: Address) !Stream {
const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0;
const sock_flags = os.SOCK_STREAM | nonblock |
(if (builtin.os.tag == .windows) 0 else os.SOCK_CLOEXEC);
@@ -679,7 +680,7 @@ pub fn tcpConnectToAddress(address: Address) !fs.File {
try os.connect(sockfd, &address.any, address.getOsSockLen());
}
- return fs.File{ .handle = sockfd };
+ return Stream{ .handle = sockfd };
}
/// Call `AddressList.deinit` on the result.
@@ -1580,6 +1581,55 @@ fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8)
}
}
+pub const Stream = struct {
+ // Underlying socket descriptor.
+ // Note that on some platforms this may not be interchangeable with a
+ // regular files descriptor.
+ handle: os.socket_t,
+
+ pub fn close(self: Stream) void {
+ os.closeSocket(self.handle);
+ }
+
+ pub const ReadError = os.ReadError;
+ pub const WriteError = os.WriteError;
+
+ pub const Reader = io.Reader(Stream, ReadError, read);
+ pub const Writer = io.Writer(Stream, WriteError, write);
+
+ pub fn reader(self: Stream) Reader {
+ return .{ .context = self };
+ }
+
+ pub fn writer(self: Stream) Writer {
+ return .{ .context = self };
+ }
+
+ pub fn read(self: Stream, buffer: []u8) ReadError!usize {
+ if (std.Target.current.os.tag == .windows) {
+ return os.windows.ReadFile(self.handle, buffer, null, io.default_mode);
+ }
+
+ if (std.io.is_async) {
+ return std.event.Loop.instance.?.read(self.handle, buffer, false);
+ } else {
+ return os.read(self.handle, buffer);
+ }
+ }
+
+ pub fn write(self: Stream, buffer: []const u8) WriteError!usize {
+ if (std.Target.current.os.tag == .windows) {
+ return os.windows.WriteFile(self.handle, buffer, null, io.default_mode);
+ }
+
+ if (std.io.is_async) {
+ return std.event.Loop.instance.?.write(self.handle, buffer, false);
+ } else {
+ return os.write(self.handle, buffer);
+ }
+ }
+};
+
pub const StreamServer = struct {
/// Copied from `Options` on `init`.
kernel_backlog: u31,
@@ -1686,7 +1736,7 @@ pub const StreamServer = struct {
} || os.UnexpectedError;
pub const Connection = struct {
- file: fs.File,
+ stream: Stream,
address: Address,
};
@@ -1705,7 +1755,7 @@ pub const StreamServer = struct {
if (accept_result) |fd| {
return Connection{
- .file = fs.File{ .handle = fd },
+ .stream = Stream{ .handle = fd },
.address = accepted_addr,
};
} else |err| switch (err) {