//! Deterministic local robustness probes; reference implementations see valid traffic only. const std = @import("std"); const c9 = @import("cloud9"); pub fn main(init: std.process.Init) !void { const args = try init.minimal.args.toSlice(init.arena.allocator()); const seed = if (args.len > 1) try std.fmt.parseInt(u64, args[1], 10) else 4200; const iterations = if (args.len > 2) try std.fmt.parseInt(u32, args[2], 10) else 100000; if (args.len > 3 or iterations > 10000000) return error.Arguments; var prng: std.Random.DefaultPrng = .init(seed); const random = prng.random(); var accepted: usize = 0; var rejected: usize = 0; var buffer: [8192]u8 = undefined; var encoded: [8192]u8 = undefined; var payload: [4096]u8 = undefined; var server_in: [8192]u8 = undefined; var server_out: [8192]u8 = undefined; for (0..iterations) |_| { random.bytes(&payload); const data = payload[0..random.uintLessThan(usize, payload.len)]; const qid: c9.Qid = .{ .type = random.int(u8), .version = random.int(u32), .path = random.int(u64) }; const stat: c9.Stat = .{ .type = 0, .dev = 0, .qid = qid, .mode = random.int(u32), .atime = 0, .mtime = 0, .length = random.int(u64), .name = "file", .uid = "user", .gid = "group", .muid = "", }; const messages = [_]c9.Msg{ .{ .tversion = .{ .msize = 8192, .version = "9P2000" } }, .{ .twalk = .{ .fid = 0, .newfid = 1, .nwname = 16, .wname = @splat("dir") } }, .{ .rwalk = .{ .nwqid = 16, .wqid = @splat(qid) } }, .{ .twrite = .{ .fid = random.int(u32), .offset = random.int(u64), .data = data } }, .{ .rread = .{ .data = data } }, .{ .rstat = .{ .stat = stat } }, .{ .twstat = .{ .fid = 1, .stat = stat } }, .{ .tflush = .{ .oldtag = random.int(u16) } }, .{ .tread = .{ .fid = 1, .offset = random.int(u64), .count = random.int(u32) } }, }; const msg = messages[random.uintLessThan(usize, messages.len)]; var frame: []u8 = try c9.encode(msg, random.int(u16), &buffer); // Leave some valid seeds unchanged; probe truncation and altered fields locally. switch (random.uintLessThan(u8, 4)) { 0 => {}, 1 => frame = frame[0..random.uintLessThan(usize, frame.len)], 2 => frame[random.uintLessThan(usize, frame.len)] ^= random.int(u8), 3 => std.mem.writeInt(u32, frame[0..4], random.int(u32), .little), else => unreachable, } if (c9.decode(frame)) |decoded| { const output = try c9.encode(decoded.msg, decoded.tag, &encoded); if (!std.mem.eql(u8, frame, output)) return error.RoundTrip; accepted += 1; } else |_| rejected += 1; var server: c9.Server = .init(.{ .in = &server_in, .out = &server_out }); _ = server.push(frame); if (server.receive() catch null) |request| { if (request.msg != .tversion) return error.BeforeVersion; server.negotiate(request.msg.tversion.msize, request.msg.tversion.version) catch {}; server.release(); } } std.debug.print("seed={d} iterations={d} accepted={d} rejected={d}\n", .{ seed, iterations, accepted, rejected }); }