std.net.tls.Client
type pub Client[T: mut + RawSocketOperations]
A type that acts as the client in a TLS session.
Client
values wrap existing sockets such as std.net.socket.TcpClient
and
apply TLS encryption/decryption to IO operations.
Closing TLS connections
When a Client
is dropped, the TLS connection is closed by sending the TLS
close_notify
message.
Examples
import std.net.ip (IpAddress)
import std.net.socket (TcpClient)
import std.net.tls (Client, ClientConfig)
let conf = ClientConfig.new
let sock = TcpClient
.new(ip: IpAddress.v4(127, 0, 0, 1), port: 9000)
.or_panic('failed to connect to the server')
let client = Client
.new(socket, conf, name: 'localhost')
.or_panic('the server name is invalid')
client.write_string('ping').or_panic('failed to write the message')
let response = ByteArray.new
client.read_all(response).or_panic('failed to read the response')
Fields
socket
let pub @socket: T: mut
The socket wrapped by this Client
.
Static methods
new
Show source codeHide source code
fn pub static new(
socket: T,
config: ref ClientConfig,
name: String,
) -> Option[Client[T]] {
let state = match inko_tls_client_connection_new(config.raw, name) {
case { @tag = 0, @value = v } -> v as Pointer[UInt8]
case _ -> return Option.None
}
Option.Some(Client(socket, state))
}
fn pub static new(socket: T: mut, config: ref ClientConfig, name: String) -> Option[Client[T: mut]]
Returns a Client
acting as the client in a TLS session.
The socket
argument is the socket (e.g. std.net.socket.TcpClient
) to
wrap. This can be either an owned socket or a mutable borrow of a socket.
The name
argument is the DNS name to use for Server Name Indication (SNI).
Setting this to an IP address disables the use of SNI. In most cases you'll
want to set this to the DNS name of the server the socket is connecting to.
The config
argument is a ClientConfig
instance to use for configuring
the TLS connection.
Errors
This method returns an Option.None
if the name
argument contains an
invalid value.
Examples
import std.net.ip (IpAddress)
import std.net.socket (TcpClient)
import std.net.tls (Client, ClientConfig)
let conf = ClientConfig.new
let sock = TcpClient
.new(ip: IpAddress.v4(127, 0, 0, 1), port: 9000)
.or_panic('failed to connect to the server')
Client
.new(sock, conf, name: 'localhost')
.or_panic('the server name is invalid')
Instance methods
flush
Show source codeHide source code
fn pub mut flush -> Result[Nil, Error] {
Result.Ok(nil)
}
fn pub mut flush -> Result[Nil, Error]
Flushes any pending writes to the file system.
Flushing writes is a potentially expensive operation, and unnecessarily calling this method may degrade performance.
When flushing data to disk it's important to remember that the actual behaviour may vary based on the type of file system, operating system and storage hardware that's used. In particular, it's possible for one of these components to say "Yup, I totally flushed the data, you're all good!" when in fact they have not fully flushed the data.
Show source codeHide source code
fn pub mut print(string: String) -> Result[Nil, Error] {
write_string(string).then(fn (_) { write_string('\n') })
}
fn pub mut print(string: String) -> Result[Nil, Error]
Writes the entirety of string
to the underlying stream, followed by
writing a Unix newline to the stream.
read
Show source codeHide source code
fn pub mut read(into: mut ByteArray, size: Int) -> Result[Int, Error] {
into.reserve(size)
let len = into.size
let ptr = ptr.add(into.to_pointer, len)
match
inko_tls_client_read(
@socket.raw_socket,
@state,
ptr,
size,
@socket.raw_deadline,
mut read_callback,
mut write_callback,
)
{
case { @tag = 0, @value = v } -> {
into.size = len + v
Result.Ok(v)
}
case { @tag = _, @value = e } -> Result.Error(Error.from_os_error(e))
}
}
fn pub mut read(into: mut ByteArray, size: Int) -> Result[Int, Error]
Reads up to size
bytes from self
into the given ByteArray
, returning
the number of bytes read.
The into
argument is the ByteArray
to read the bytes into. The capacity
of this ByteArray
is increased automatically if necessary.
The size
argument specifies how many bytes are to be read.
The return value is the number of bytes read.
The number of bytes read may be less than size
. This can happen for
different reasons, such as when all input is consumed or not enough data is
available (yet).
read_all
Show source codeHide source code
fn pub mut read_all(bytes: mut ByteArray) -> Result[Int, Error] {
let mut total = 0
let mut read_size = INITIAL_READ_ALL_SIZE
loop {
match read(into: bytes, size: read_size) {
case Ok(0) -> return Result.Ok(total)
case Ok(n) -> {
total += n
# To reduce the number of calls to `Reader.read` when there's lots of
# input to consume, we increase the read size if deemed beneficial.
if read_size < MAX_READ_ALL_SIZE and n == read_size { read_size *= 2 }
}
case Error(e) -> throw e
}
}
}
fn pub mut read_all(bytes: mut ByteArray) -> Result[Int, Error]
Reads from self
into the given ByteArray
, returning when all input is
consumed.
The return value is the number of bytes read.
Errors
This method returns an Error
if the underlying call to Read.read
returns
an Error
.
read_exact
Show source codeHide source code
fn pub mut read_exact(into: mut ByteArray, size: Int) -> Result[Nil, Error] {
let mut pending = size
while pending > 0 {
match read(into, pending) {
case Ok(0) if pending > 0 -> throw Error.EndOfInput
case Ok(n) -> pending -= n
case Error(e) -> throw e
}
}
Result.Ok(nil)
}
fn pub mut read_exact(into: mut ByteArray, size: Int) -> Result[Nil, Error]
Reads exactly size
bytes into into
.
Whereas Read.read
might return early if fewer bytes are available in the
input stream, Read.read_exact
continues reading until the desired amount
of bytes is read.
Errors
If the end of the input stream is encountered before filling the buffer, an
Error.EndOfInput
error is returned.
If an error is returned, no assumption can be made about the state of the
into
buffer, i.e. there's no guarantee data read so far is in the buffer
in the event of an error.
write_bytes
Show source codeHide source code
fn pub mut write_bytes(bytes: ref ByteArray) -> Result[Nil, Error] {
write_all_internal(bytes.to_pointer, bytes.size)
}
fn pub mut write_bytes(bytes: ref ByteArray) -> Result[Nil, Error]
Writes the entirety of bytes
to the underlying stream.
Types implementing this method must guarantee that upon returning from this
method, either all of the data is written and a Ok(Nil)
is returned, or
an Error(Error)
is returned.
write_string
Show source codeHide source code
fn pub mut write_string(string: String) -> Result[Nil, Error] {
write_all_internal(string.to_pointer, string.size)
}
fn pub mut write_string(string: String) -> Result[Nil, Error]
Writes the entirety of string
to the underlying stream.
See Write.write_bytes
for more details.
Implemented traits
Drop
impl Drop for Client
Read
impl Read for Client
Write
impl Write for Client