Storing inner structures, adding TODOs.

master
Philippe Pittoli 2022-02-08 05:59:18 +01:00
parent a0dbd66fd2
commit 382dcc07d7
1 changed files with 57 additions and 12 deletions

View File

@ -2,16 +2,20 @@ const std = @import("std");
const testing = std.testing;
const net = std.net;
// TODO: file descriptors should have a specific type
// (however, usize is pointer size).
// TODO: file descriptors should have a specific type (but i32 is used in std.net...).
// TODO: path => std.XXX.YYY, not simple [] const u8
// TODO: both ConnectionInfos and pollfd store file descriptors.
// ConnectionInfos stores either Stream (server) or Address (client).
// TODO: API should completely obfuscate the inner structures.
// Only structures in this file should be necessary.
pub const RUNDIR = "/run/ipc/";
pub const IPC_HEADER_SIZE = 6;
pub const IPC_BASE_SIZE = 2000000; // 2 MB, plenty enough space for messages
pub const IPC_MAX_MESSAGE_SIZE = IPC_BASE_SIZE-IPC_HEADER_SIZE;
pub const IPC_MAX_MESSAGE_SIZE = IPC_BASE_SIZE-IPC_HEADER_SIZE;
pub const IPC_VERSION = 4;
const print = std.debug.print;
@ -193,18 +197,13 @@ pub const ConnectionType = enum {
SWITCHED, // IO operations should go through registered callbacks.
};
// RATIONALE: a connection is mostly a file descriptor,
// but with a few other pieces of information.
// Storing all data related to a connection in a single place
// would be logical but very inefficient.
// File descriptors are stored elsewhere (in the context),
// packed together, in a single dedicated structure.
pub const ConnectionInfos = struct {
@"type": ConnectionType,
more_to_read: bool,
path: ?[] const u8, // Not always needed.
// TODO: socket: ?net.Stream, // Not always needed.
server: ?net.StreamServer = null,
client: ?net.StreamServer.Connection = null,
const Self = @This();
@ -216,6 +215,10 @@ pub const ConnectionInfos = struct {
};
}
pub fn deinit(self: *Self) void {
if (self.server) |s| { s.deinit(); }
}
pub fn format(
self: Self,
comptime _: []const u8, // No need.
@ -225,6 +228,12 @@ pub const ConnectionInfos = struct {
try std.fmt.format(out_stream
, "connection type {}, more_to_read {}, path {s}"
, .{ self.@"type", self.more_to_read, self.path} );
if (self.server) |s| {
try std.fmt.format(out_stream, "{}" , .{s});
}
if (self.client) |c| {
try std.fmt.format(out_stream, "{}" , .{c});
}
}
};
@ -328,6 +337,7 @@ pub const Context = struct {
const newfd = stream.handle;
errdefer std.os.closeSocket(newfd);
var newcon = ConnectionInfos.init(ctype, path);
newcon.client = stream;
try self.connections.append(newcon);
try self.pollfd.append(newfd);
return newfd;
@ -358,6 +368,7 @@ pub const Context = struct {
const newfd = server.sockfd orelse return error.SocketLOL;
var newcon = ConnectionInfos.init(ConnectionType.SERVER, path);
newcon.server = server;
try self.connections.append(newcon);
try self.pollfd.append(newfd);
return server;
@ -382,6 +393,11 @@ pub const Context = struct {
return m;
}
// TODO: this shouldn't be available in the API.
pub fn read_ (_: *Self, client: net.StreamServer.Connection, buf: [] u8) !usize {
return try client.stream.reader().read(buf);
}
pub fn read_fd (_: *Self, fd: i32) !Message {
// TODO: read the actual content.
print("read fd {}\n", .{fd});
@ -494,7 +510,7 @@ test "Context - creation, display and memory check" {
const t = try std.Thread.spawn(.{}, S.clientFn, .{});
defer t.join();
// Server.accept returns a net.Connection (handle = fd, addr = net.Address).
// Server.accept returns a net.StreamServer.Connection.
var client = try server.accept();
defer client.stream.close();
var buf: [16]u8 = undefined;
@ -504,7 +520,36 @@ test "Context - creation, display and memory check" {
try testing.expectEqualSlices(u8, "Hello world!", buf[0..n]);
}
pub fn main() u8 {
// FIRST
fn create_service() !void {
const config = .{.safety = true};
var gpa = std.heap.GeneralPurposeAllocator(config){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var ctx = Context.init(allocator);
defer ctx.deinit(); // There. Can't leak. Isn't Zig wonderful?
const path = "/tmp/.TEST_USOCK";
// SERVER SIDE: creating a service.
var server = try ctx.server_init(path);
defer server.deinit();
defer std.fs.cwd().deleteFile(path) catch {}; // Once done, remove file.
// Server.accept returns a net.Connection (handle = fd, addr = net.Address).
var client = try server.accept();
defer client.stream.close();
var buf: [4096]u8 = undefined;
const n = try ctx.read_ (client, &buf);
print("new client: {}\n", .{client});
print("{} bytes: {s}\n", .{n, buf});
}
pub fn main() !u8 {
try create_service();
return 0;
}