Storing inner structures, adding TODOs.
parent
a0dbd66fd2
commit
382dcc07d7
|
@ -2,16 +2,20 @@ const std = @import("std");
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const net = std.net;
|
const net = std.net;
|
||||||
|
|
||||||
// TODO: file descriptors should have a specific type
|
// TODO: file descriptors should have a specific type (but i32 is used in std.net...).
|
||||||
// (however, usize is pointer size).
|
|
||||||
|
|
||||||
// TODO: path => std.XXX.YYY, not simple [] const u8
|
// 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 RUNDIR = "/run/ipc/";
|
||||||
pub const IPC_HEADER_SIZE = 6;
|
pub const IPC_HEADER_SIZE = 6;
|
||||||
pub const IPC_BASE_SIZE = 2000000; // 2 MB, plenty enough space for messages
|
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;
|
pub const IPC_VERSION = 4;
|
||||||
|
|
||||||
const print = std.debug.print;
|
const print = std.debug.print;
|
||||||
|
@ -193,18 +197,13 @@ pub const ConnectionType = enum {
|
||||||
SWITCHED, // IO operations should go through registered callbacks.
|
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 {
|
pub const ConnectionInfos = struct {
|
||||||
@"type": ConnectionType,
|
@"type": ConnectionType,
|
||||||
more_to_read: bool,
|
more_to_read: bool,
|
||||||
path: ?[] const u8, // Not always needed.
|
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();
|
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(
|
pub fn format(
|
||||||
self: Self,
|
self: Self,
|
||||||
comptime _: []const u8, // No need.
|
comptime _: []const u8, // No need.
|
||||||
|
@ -225,6 +228,12 @@ pub const ConnectionInfos = struct {
|
||||||
try std.fmt.format(out_stream
|
try std.fmt.format(out_stream
|
||||||
, "connection type {}, more_to_read {}, path {s}"
|
, "connection type {}, more_to_read {}, path {s}"
|
||||||
, .{ self.@"type", self.more_to_read, self.path} );
|
, .{ 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;
|
const newfd = stream.handle;
|
||||||
errdefer std.os.closeSocket(newfd);
|
errdefer std.os.closeSocket(newfd);
|
||||||
var newcon = ConnectionInfos.init(ctype, path);
|
var newcon = ConnectionInfos.init(ctype, path);
|
||||||
|
newcon.client = stream;
|
||||||
try self.connections.append(newcon);
|
try self.connections.append(newcon);
|
||||||
try self.pollfd.append(newfd);
|
try self.pollfd.append(newfd);
|
||||||
return newfd;
|
return newfd;
|
||||||
|
@ -358,6 +368,7 @@ pub const Context = struct {
|
||||||
|
|
||||||
const newfd = server.sockfd orelse return error.SocketLOL;
|
const newfd = server.sockfd orelse return error.SocketLOL;
|
||||||
var newcon = ConnectionInfos.init(ConnectionType.SERVER, path);
|
var newcon = ConnectionInfos.init(ConnectionType.SERVER, path);
|
||||||
|
newcon.server = server;
|
||||||
try self.connections.append(newcon);
|
try self.connections.append(newcon);
|
||||||
try self.pollfd.append(newfd);
|
try self.pollfd.append(newfd);
|
||||||
return server;
|
return server;
|
||||||
|
@ -382,6 +393,11 @@ pub const Context = struct {
|
||||||
return m;
|
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 {
|
pub fn read_fd (_: *Self, fd: i32) !Message {
|
||||||
// TODO: read the actual content.
|
// TODO: read the actual content.
|
||||||
print("read fd {}\n", .{fd});
|
print("read fd {}\n", .{fd});
|
||||||
|
@ -494,7 +510,7 @@ test "Context - creation, display and memory check" {
|
||||||
const t = try std.Thread.spawn(.{}, S.clientFn, .{});
|
const t = try std.Thread.spawn(.{}, S.clientFn, .{});
|
||||||
defer t.join();
|
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();
|
var client = try server.accept();
|
||||||
defer client.stream.close();
|
defer client.stream.close();
|
||||||
var buf: [16]u8 = undefined;
|
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]);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in New Issue