╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ─────────────────╮ │src/serve_ssh_protocol.zig│ ╰──────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │299 const chunk_len: u32 = @intCast(cap); │ │300 │ │301 self.write_scratch.clearRetainingCapacity(); │ │294 - try self.write_scratch.append(self.allocator, if (extended) SSH_MSG_CHANNEL_EXTENDED_DATA else SSH_MSG_CHANNEL_DATA);│ │295 - try writeU32(&self.write_scratch, self.allocator, self.channel.remote_id); │ │296 - if (extended) try writeU32(&self.write_scratch, self.allocator, SSH_EXTENDED_DATA_STDERR); │ │297 - try writeStringField(&self.write_scratch, self.allocator, rest[0..chunk_len]); │ │298 - try self.sc_cipher.writePacket(self.io, self.writer, self.write_scratch.items); │ │302 + try self.write_scratch.append(conn.allocator, if (extended) SSH_MSG_CHANNEL_EXTENDED_DATA else SSH_MSG_CHANNEL_DATA);│ │303 + try writeU32(&self.write_scratch, conn.allocator, self.channel.remote_id); │ │304 + if (extended) try writeU32(&self.write_scratch, conn.allocator, SSH_EXTENDED_DATA_STDERR); │ │305 + try writeStringField(&self.write_scratch, conn.allocator, rest[0..chunk_len]); │ │306 + try conn.sc_cipher.writePacket(conn.io, conn.writer, self.write_scratch.items); │ │307 │ │308 self.channel.remote_window -= chunk_len; │ │309 rest = rest[chunk_len..]; │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │317 /// channel/global requests get a polite failure. driven by nextEvent, │ │318 /// SessionReader, and writeBytes (waiting for send-window). │ │319 fn processOneBackgroundPacket(self: *SessionCtx) !void { │ │312 - const packet = readSessionPacket(self.io, self.allocator, self.reader, self.writer, self.cs_cipher, self.sc_cipher, self.rekey) catch |err| switch (err) {│ │320 + const conn = self.conn; │ │321 + const packet = readSessionPacket(conn) catch |err| switch (err) { │ │322 error.EndOfStream => { │ │323 self.incoming_eof = true; │ │324 return; │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────╮ │325 }, │ │326 else => return err, │ │327 }; │ │319 - defer self.allocator.free(packet);│ │328 + defer conn.allocator.free(packet);│ │329 if (packet.len < 1) return; │ │330 │ │331 switch (packet[0]) { │ ╰───────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │338 try self.maybeRefillRecvWindowForBufferedInput(); │ │339 }, │ │340 SSH_MSG_CHANNEL_EXTENDED_DATA => { │ │332 - try discardChannelData(self.io, self.allocator, self.sc_cipher, self.writer, self.channel, packet, true);│ │341 + try discardChannelData(conn, self.channel, packet, true); │ │342 }, │ │343 SSH_MSG_CHANNEL_WINDOW_ADJUST => try handleWindowAdjust(self.channel, packet), │ │344 SSH_MSG_CHANNEL_REQUEST => { │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────╮ │345 var r = std.Io.Reader.fixed(packet[1..]); │ │346 const recipient_channel = try r.takeInt(u32, .big); │ │347 if (recipient_channel != self.channel.local_id) return error.UnknownChannel;│ │339 - const req_type = try takeStringField(self.allocator, &r, 64); │ │340 - defer self.allocator.free(req_type); │ │348 + const req_type = try takeStringField(conn.allocator, &r, 64); │ │349 + defer conn.allocator.free(req_type); │ │350 const want_reply = (try r.takeByte()) != 0; │ │351 if (std.mem.eql(u8, req_type, "window-change")) { │ │352 const sz = try takePtySize(&r); │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │353 if (self.channel.pty != null) self.channel.pty = sz; │ │354 self.pending_resize = sz; │ │346 - try replyChannelRequest(self.io, self.allocator, self.sc_cipher, self.writer, self.channel, want_reply, true); │ │355 + try replyChannelRequest(conn, self.channel, want_reply, true); │ │356 } else { │ │357 // other mid-session channel requests aren't honored — fail them │ │349 - try replyChannelRequest(self.io, self.allocator, self.sc_cipher, self.writer, self.channel, want_reply, false);│ │358 + try replyChannelRequest(conn, self.channel, want_reply, false); │ │359 } │ │360 }, │ │361 SSH_MSG_CHANNEL_EOF, SSH_MSG_CHANNEL_CLOSE => { │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │362 try parseChannelId(packet, self.channel.local_id); │ │363 self.incoming_eof = true; │ │364 }, │ │356 - SSH_MSG_GLOBAL_REQUEST => try handleGlobalRequest(self.io, self.allocator, self.sc_cipher, self.writer, packet),│ │365 + SSH_MSG_GLOBAL_REQUEST => try handleGlobalRequest(conn, packet), │ │366 else => {}, │ │367 } │ │368 } │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │369 │ │370 fn maybeRefillRecvWindowForBufferedInput(self: *SessionCtx) !void { │ │371 if (self.incomingBytes().len >= incoming_refill_threshold) return; │ │363 - try maybeRefillRecvWindow(self.io, self.allocator, self.sc_cipher, self.writer, self.channel);│ │372 + try maybeRefillRecvWindow(self.conn, self.channel); │ │373 } │ │374 │ │375 /// signal the consumer's exit status and tear the channel down. │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────╮ │376 pub fn exit(self: *SessionCtx, status: u32) !void { │ │377 if (self.closed) return; │ │378 self.closed = true; │ │379 + const conn = self.conn; │ │380 │ │381 // exit-status request (informational; client uses it as the│ │382 // command's exit code) │ ╰─────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────╮ │383 { │ │384 var req: std.ArrayList(u8) = .empty; │ │375 - defer req.deinit(self.allocator); │ │376 - try req.append(self.allocator, SSH_MSG_CHANNEL_REQUEST); │ │377 - try writeU32(&req, self.allocator, self.channel.remote_id); │ │378 - try writeStringField(&req, self.allocator, "exit-status"); │ │379 - try req.append(self.allocator, 0); // want_reply MUST be false │ │380 - try writeU32(&req, self.allocator, status); │ │381 - try self.sc_cipher.writePacket(self.io, self.writer, req.items);│ │385 + defer req.deinit(conn.allocator); │ │386 + try req.append(conn.allocator, SSH_MSG_CHANNEL_REQUEST); │ │387 + try writeU32(&req, conn.allocator, self.channel.remote_id); │ │388 + try writeStringField(&req, conn.allocator, "exit-status"); │ │389 + try req.append(conn.allocator, 0); // want_reply MUST be false │ │390 + try writeU32(&req, conn.allocator, status); │ │391 + try conn.sc_cipher.writePacket(conn.io, conn.writer, req.items);│ │392 } │ │393 │ │394 // EOF then CLOSE │ ╰─────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯