~sircmpwn/hare-ssh

5daf8fb1d368717668a417776c2cab87331f2f54 — Drew DeVault a month ago eb9ca3c
net::ssh: improve packet decoder memory use
2 files changed, 11 insertions(+), 19 deletions(-)

M net/ssh/packet.ha
M net/ssh/proto.ha
M net/ssh/packet.ha => net/ssh/packet.ha +2 -2
@@ 50,7 50,7 @@ export type disconnect = struct {
export type newkeys = void;

// Decodes an SSH packet.
fn decode(src: io::handle) (packet | protoerror) = {
fn decode(src: *bufio::memstream) (packet | protoerror) = {
	switch (readbyte(src)?) {
	case SSH_MSG_KEXINIT =>
		return kexinit_decode(src);


@@ 63,7 63,7 @@ fn decode(src: io::handle) (packet | protoerror) = {
	};
};

fn kexinit_decode(src: io::handle) (packet | protoerror) = {
fn kexinit_decode(src: *bufio::memstream) (packet | protoerror) = {
	let pkt = kexinit { ... };
	match (io::readall(src, pkt.cookie)!) {
	case io::EOF =>

M net/ssh/proto.ha => net/ssh/proto.ha +9 -17
@@ 3,7 3,7 @@ use endian;
use io;
use strings;

fn readbyte(src: io::handle) (u8 | protoerror) = {
fn readbyte(src: *bufio::memstream) (u8 | protoerror) = {
	match (bufio::scanbyte(src)!) {
	case let u: u8 =>
		return u;


@@ 12,11 12,11 @@ fn readbyte(src: io::handle) (u8 | protoerror) = {
	};
};

fn readbool(src: io::handle) (bool | protoerror) = {
fn readbool(src: *bufio::memstream) (bool | protoerror) = {
	return readbyte(src)? != 0;
};

fn readu32(src: io::handle) (u32 | protoerror) = {
fn readu32(src: *bufio::memstream) (u32 | protoerror) = {
	let buf: [4]u8 = [0...];
	match (io::readall(src, buf)!) {
	case io::EOF =>


@@ 27,9 27,7 @@ fn readu32(src: io::handle) (u32 | protoerror) = {
	return endian::begetu32(buf);
};

// Reads a slice from the stream. The caller must free the return value.
fn readslice(src: io::handle) ([]u8 | protoerror) = {
	// XXX: Would be quite nice to borrow the return value from the input
fn readslice(src: *bufio::memstream) ([]u8 | protoerror) = {
	const length = readu32(src)?;
	if (length > MAX_PACKETSIZE) {
		return protoerror;


@@ 37,31 35,25 @@ fn readslice(src: io::handle) ([]u8 | protoerror) = {
	if (length == 0) {
		return [];
	};
	let slice: []u8 = alloc([0...], length);
	match (io::readall(src, slice)!) {
	match (bufio::borrowedread(src, length)) {
	case io::EOF =>
		free(slice);
		return protoerror;
	case let z: size =>
		return slice;
	case let buf: []u8 =>
		return buf;
	};
};

// Reads a string from the stream. The caller must free the return value.
fn readstr(src: io::handle) (str | protoerror) = {
fn readstr(src: *bufio::memstream) (str | protoerror) = {
	const slice = readslice(src)?;
	match (strings::try_fromutf8(slice)) {
	case let s: str =>
		return s;
	case =>
		free(slice);
		return protoerror;
	};
};

// XXX: Freeing the return value here is annoying, should borrow strings from
// the input
fn readnamelist(src: io::handle) ([]str | protoerror) = {
fn readnamelist(src: *bufio::memstream) ([]str | protoerror) = {
	const list = readstr(src)?;
	const tok = strings::tokenize(list, ",");
	let items: []str = [];