use memio;
use io;
use os;
// All error types which the SSH agent may return.
export type error = !(invalid | io::error);
// Converts an [[error]] to its human-friendly representation.
export fn strerror(err: error) const str = {
match (err) {
case invalid =>
return "Invalid SSH agent protocol message";
case let err: io::error =>
return io::strerror(err);
};
};
export type agent = struct {
fd: io::handle,
buf: memio::stream,
};
// Creates a new SSH agent for the given socket. The user must call
// [[agent_finish]] to free resources associated with the agent after use.
export fn new(fd: io::handle) agent = {
return agent {
fd = fd,
buf = memio::dynamic(),
};
};
// Frees resources associated with an [[agent]]. Closes the underlying socket.
export fn agent_finish(agent: *agent) void = {
io::close(agent.fd)!;
io::close(&agent.buf)!;
};
// Reads the next message from an SSH agent socket, returning either a message,
// an error, or void if more data is required to read the full message.
export fn readmsg(agent: *agent) (message | io::EOF | void | error) = {
let buf: [os::BUFSZ]u8 = [0...];
const z = match (io::read(agent.fd, buf)?) {
case let sz: size =>
yield sz;
case io::EOF =>
return io::EOF;
};
io::write(&agent.buf, buf[..z])!;
const msg = match (parse(memio::buffer(&agent.buf))?) {
case size =>
return;
case let msg: message =>
memio::reset(&agent.buf);
yield msg;
};
return msg;
};
// Writes a message to the SSH agent socket. Blocks until the message is sent.
// For non-blocking operation, use [[serialize]] to obtain a buffer and write it
// yourself.
export fn writemsg(agent: *agent, msg: *message) (void | error) = {
const buf = serialize(msg);
defer free(buf);
io::writeall(agent.fd, buf)?;
};