libipc/src/root.zig
Philippe Pittoli 76e3144436 Ready for Zig v0.15.2. Details in commit message.
The library jumped to Zig v0.15.2 which implies a new build system.
`build.zig` now compiles libipc as both static and dynamic libraries,
and provides an entry point to use `libipc` as-is for Zig applications.

Some examples have been added to help new users play with the library.

Thanks to these fairly complete examples, two (very small) leaks related
to sentinel values (in arrays containing paths) were fixed.
2025-10-25 16:35:02 +02:00

158 lines
5.2 KiB
Zig

const std = @import("std");
const log = std.log.scoped(.libipc_bindings);
const Context = @import("./context.zig").Context;
const Message = @import("./message.zig").Message;
const CBEventType = @import("./callback.zig").CBEvent.Type;
export fn ipc_context_init(ptr: **Context) callconv(.c) i32 {
ptr.* = std.heap.c_allocator.create(Context) catch return -1;
ptr.*.* = Context.init(std.heap.c_allocator) catch |err| {
log.warn("error while init context: {}\n", .{err});
return -1;
};
return 0;
}
/// Start a libipc service.
export fn ipc_service_init(ctx: *Context, servicefd: *i32, service_name: [*]const u8, service_name_len: u16) callconv(.c) i32 {
const streamserver = ctx.server_init(service_name[0..service_name_len]) catch return -1;
servicefd.* = streamserver.stream.handle;
return 0;
}
/// Connect to a libipc service, possibly through IPCd.
export fn ipc_connect_service(ctx: *Context, servicefd: *i32, service_name: [*]const u8, service_name_len: u16) callconv(.c) i32 {
const fd = ctx.connect_ipc(service_name[0..service_name_len]) catch return -1;
servicefd.* = fd;
return 0;
}
export fn ipc_context_deinit(ctx: **Context) callconv(.c) void {
var ptr: *Context = ctx.*;
ptr.deinit();
std.heap.c_allocator.destroy(ptr);
}
/// Write a message (no waiting).
export fn ipc_write(ctx: *Context, servicefd: i32, mcontent: [*]const u8, mlen: usize) callconv(.c) i32 {
// TODO: better default length.
var buffer = [_]u8{0} ** 100000;
var fba = std.heap.FixedBufferAllocator.init(&buffer);
const message = Message.init(servicefd, fba.allocator(), mcontent[0..mlen]) catch return -1;
ctx.write(message) catch return -1;
return 0;
}
/// Schedule a message.
/// Use the same allocator as the context.
export fn ipc_schedule(ctx: *Context, servicefd: i32, mcontent: [*]const u8, mlen: usize) callconv(.c) i32 {
const message = Message.init(servicefd, ctx.allocator, mcontent[0..mlen]) catch return -1;
ctx.schedule(message) catch return -2;
return 0;
}
/// Read a message from a file descriptor.
/// Buffer length will be changed to the size of the received message.
export fn ipc_read_fd(ctx: *Context, fd: i32, buffer: [*]u8, buflen: *usize) callconv(.c) i32 {
var m = ctx.read_fd(fd) catch {
return -1;
} orelse return -2;
if (m.payload.len > buflen.*) return -3;
buflen.* = m.payload.len;
var fbs = std.io.fixedBufferStream(buffer[0..buflen.*]);
var writer = fbs.writer();
_ = writer.write(m.payload) catch return -4;
m.deinit();
return 0;
}
/// Read a message.
/// Buffer length will be changed to the size of the received message.
export fn ipc_read(ctx: *Context, index: usize, buffer: [*]u8, buflen: *usize) callconv(.c) i32 {
var m = ctx.read(index) catch {
return -1;
} orelse return -2;
if (m.payload.len > buflen.*) return -3;
buflen.* = m.payload.len;
var fbs = std.io.fixedBufferStream(buffer[0..buflen.*]);
var writer = fbs.writer();
_ = writer.write(m.payload) catch return -4;
m.deinit();
return 0;
}
/// Wait for an event.
/// Buffer length will be changed to the size of the received message.
export fn ipc_wait_event(ctx: *Context, t: *u8, index: *usize, originfd: *i32, newfd: *i32, buffer: [*]u8, buflen: *usize) callconv(.c) i32 {
const event = ctx.wait_event() catch |err| switch (err) {
else => {
log.warn("error while waiting for an event: {}\n", .{err});
return -1;
},
};
t.* = @intFromEnum(event.t);
index.* = event.index;
originfd.* = event.origin;
newfd.* = event.newfd;
if (event.m) |m| {
var fbs = std.io.fixedBufferStream(buffer[0..buflen.*]);
var writer = fbs.writer();
_ = writer.write(m.payload) catch return -4;
buflen.* = m.payload.len;
switch (event.t) {
.SWITCH_RX => {},
else => m.deinit(),
}
} else {
buflen.* = 0;
}
return 0;
}
/// Change the timer (ms).
export fn ipc_context_timer(ctx: *Context, timer: i32) callconv(.c) void {
ctx.timer = timer;
}
export fn ipc_close_fd(ctx: *Context, fd: i32) callconv(.c) i32 {
ctx.close_fd(fd) catch return -1;
return 0;
}
export fn ipc_close(ctx: *Context, index: usize) callconv(.c) i32 {
ctx.close(index) catch return -1;
return 0;
}
export fn ipc_close_all(ctx: *Context) callconv(.c) i32 {
ctx.close_all() catch return -1;
return 0;
}
/// Add a new file descriptor to listen to.
/// The FD is marked as "external"; it isn't a simple libipc connection.
/// You may want to handle any operation on it by yourself.
export fn ipc_add_external(ctx: *Context, newfd: i32) callconv(.c) i32 {
ctx.add_external(newfd) catch return -1;
return 0;
}
export fn ipc_add_switch(ctx: *Context, fd1: i32, fd2: i32) callconv(.c) i32 {
ctx.add_switch(fd1, fd2) catch return -1;
return 0;
}
export fn ipc_set_switch_callbacks(ctx: *Context, fd: i32,
in: ?*const fn (origin: i32, mcontent: [*]u8, mlen: *usize) callconv(.c) u8,
out: ?*const fn (origin: i32, mcontent: [*]const u8, mlen: usize) callconv(.c) u8) callconv(.c) i32 {
ctx.set_switch_callbacks(fd, in, out) catch return -1;
return 0;
}