···11+# zaprus
22+33+This is an implementation of the [Saprus protocol](https://gitlab.com/c2-games/red-team/saprus) in Zig.
44+It is useful for developing clients either in Zig, or in any other language using the C bindings.
55+66+Binary releases can be downloaded [here](https://cloud.zambito.xyz/s/cNaLeDz38W5ZcZs).
+19
build.zig
···2121 // target and optimize options) will be listed when running `zig build --help`
2222 // in this directory.
23232424+ // Get default install step (called with `zig build` or `zig build install`)
2525+ const install_step = b.getInstallStep();
2626+2427 // This creates a module, which represents a collection of source files alongside
2528 // some compilation options, such as optimization mode and linked system libraries.
2629 // Zig modules are the preferred way of making Zig code available to consumers.
···4043 // which requires us to specify a target.
4144 .target = target,
4245 });
4646+4747+ // Only used to generate the documentation
4848+ const zaprus_lib = b.addLibrary(.{
4949+ .name = "zaprus",
5050+ .root_module = mod,
5151+ });
5252+5353+ const docs_step = b.step("doc", "Emit documentation");
5454+ const docs_install = b.addInstallDirectory(.{
5555+ .install_dir = .prefix,
5656+ .install_subdir = "docs",
5757+ .source_dir = zaprus_lib.getEmittedDocs(),
5858+ });
5959+6060+ docs_step.dependOn(&docs_install.step);
6161+ install_step.dependOn(docs_step);
43624463 // Create static library
4564 const lib = b.addLibrary(.{
+12-3
src/Client.zig
···1414// You should have received a copy of the GNU General Public License along with
1515// Zaprus. If not, see <https://www.gnu.org/licenses/>.
16161717+//! A client is used to handle interactions with the network.
1818+1719const base64_enc = std.base64.standard.Encoder;
1820const base64_dec = std.base64.standard.Decoder;
1921···3739 self.* = undefined;
3840}
39414242+/// Sends a fire and forget message over the network.
4343+/// This function asserts that `payload` fits within a single packet.
4044pub fn sendRelay(self: *Client, io: Io, payload: []const u8, dest: [4]u8) !void {
4145 const io_source: std.Random.IoSource = .{ .io = io };
4246 const rand = io_source.interface();
···7680 try self.socket.send(full_msg);
7781}
78827979-pub fn connect(self: Client, io: Io, payload: []const u8) !SaprusConnection {
8383+/// Attempts to establish a new connection with the sentinel.
8484+pub fn connect(self: Client, io: Io, payload: []const u8) (error{ BpfAttachFailed, Timeout } || SaprusMessage.ParseError)!SaprusConnection {
8085 const io_source: std.Random.IoSource = .{ .io = io };
8186 const rand = io_source.interface();
8287···157162158163 try self.socket.send(full_msg);
159164160160- return .init(self.socket, headers, connection);
165165+ return .{
166166+ .socket = self.socket,
167167+ .headers = headers,
168168+ .connection = connection,
169169+ };
161170}
162171163172const RawSocket = @import("./RawSocket.zig");
164173165174const SaprusMessage = @import("message.zig").Message;
166166-const saprusParse = @import("message.zig").parse;
175175+const saprusParse = SaprusMessage.parse;
167176const SaprusConnection = @import("Connection.zig");
168177const EthIpUdp = @import("./EthIpUdp.zig").EthIpUdp;
169178
+11-8
src/Connection.zig
···20202121const Connection = @This();
22222323-pub fn init(socket: RawSocket, headers: EthIpUdp, connection: SaprusMessage) Connection {
2424- return .{
2525- .socket = socket,
2626- .headers = headers,
2727- .connection = connection,
2828- };
2929-}
3030-3123// 'p' as base64
3224const pong = "cA==";
33252626+/// Attempts to read from the network, and returns the next message, if any.
2727+///
2828+/// Asserts that `buf` is large enough to store the message that is received.
2929+///
3030+/// This will internally process management messages, and return the message
3131+/// payload for the next non management connection message.
3232+/// This function is ignorant to the message encoding.
3433pub fn next(self: *Connection, io: Io, buf: []u8) ![]const u8 {
3534 while (true) {
3635 log.debug("Awaiting connection message", .{});
···6564 }
6665}
67666767+/// Attempts to write a message to the network.
6868+///
6969+/// Clients should pass `.{}` for options unless you know what you are doing.
7070+/// `buf` will be sent over the network as-is; this function is ignorant of encoding.
6871pub fn send(self: *Connection, io: Io, options: SaprusMessage.Connection.Options, buf: []const u8) !void {
6972 const io_source: std.Random.IoSource = .{ .io = io };
7073 const rand = io_source.interface();
···1414// You should have received a copy of the GNU General Public License along with
1515// Zaprus. If not, see <https://www.gnu.org/licenses/>.
16161717+//! The Zaprus library is useful for implementing clients that interact with the [Saprus Protocol](https://gitlab.com/c2-games/red-team/saprus).
1818+//!
1919+//! The main entrypoint into this library is the `Client` type.
2020+//! It can be used to send fire and forget messages, and establish persistent connections.
2121+//! It is up to the consumer of this library to handle non-management message payloads.
2222+//! The library handles management messages automatically (right now, just ping).
2323+1724pub const Client = @import("Client.zig");
1825pub const Connection = @import("Connection.zig");
1919-2020-const msg = @import("message.zig");
2121-2222-pub const MessageTypeError = msg.MessageTypeError;
2323-pub const MessageParseError = msg.MessageParseError;
2424-pub const Message = msg.Message;
2626+pub const Message = @import("message.zig").Message;
25272628test {
2729 @import("std").testing.refAllDecls(@This());