Search results

There are no results.

std.net.socket.UnixSocket

type pub UnixSocket

A low-level, non-blocking Unix domain socket.

Static methods

datagram

Show source code
Hide source code
fn pub static datagram -> Result[UnixSocket, Error] {
  UnixSocket.new(libc.SOCK_DGRAM)
}
fn pub static datagram -> Result[UnixSocket, Error]

Returns a new UnixSocket configured as a datagram socket.

Examples

import std.net.socket (UnixSocket)

UnixSocket.datagram

stream

Show source code
Hide source code
fn pub static stream -> Result[UnixSocket, Error] {
  UnixSocket.new(libc.SOCK_STREAM)
}
fn pub static stream -> Result[UnixSocket, Error]

Returns a new UnixSocket configured as a stream socket.

Examples

import std.net.socket (UnixSocket)

UnixSocket.stream

Instance methods

accept

Show source code
Hide source code
fn pub accept -> Result[UnixSocket, Error] {
  let peer = net.raw_socket

  try sys.accept(@socket, mut peer, @deadline)
  Result.Ok(UnixSocket(socket: peer, deadline: net.NO_DEADLINE))
}
fn pub accept -> Result[UnixSocket, Error]

Accepts a new incoming connection from this socket.

This method will not return until a connection is available.

Examples

Accepting a connection and reading data from the connection:

import std.net.socket (UnixSocket)

let listener = UnixSocket.stream.get
let stream = UnixSocket.stream.get

listener.bind('/tmp/test.sock'.to_path).get
listener.listen.get

stream.connect('/tmp/test.sock').get
stream.write('ping').get

let client = listener.accept.get
let buffer = ByteArray.new

client.read(into: buffer, size: 4).get

buffer.to_string # => 'ping'

bind

Show source code
Hide source code
fn pub mut bind(path: ref Path) -> Result[Nil, Error] {
  sys.bind_unix(@socket.inner, path)
}
fn pub mut bind(path: ref Path) -> Result[Nil, Error]

Binds this socket to the specified path or abstract address.

Abstract sockets

Linux supports the concept of an "abstract" socket. These are sockets that don't use regular file paths, instead the path starts with a NULL byte and is followed by zero or more additional (and optional) bytes. While this method supports creating such sockets, this isn't portable across platforms (e.g. macOS and FreeBSD don't support it).

Unnamed sockets

Linux supports the concept of an "unnamed" socket. These are sockets that don't specify a path to bind to, resulting in the kernel assigning them an address. Such sockets are created by using an empty Path as the argument for this method.

On non-Linux platforms this isn't supported and providing an empty Path will result in an Error.InvalidArgument error.

Path sizes

Different platforms enforce different limits on the maximum size of path. For example, on Linux the path size limit is 108 bytes (including the trailing NULL byte). If the path is too long, this method returns an Error.InvalidArgument error.

Examples

Binding a Unix socket to a path:

import std.net.socket (UnixSocket)

let socket = UnixSocket.datagram.get

socket.bind('/tmp/test.sock'.to_path).get

connect

Show source code
Hide source code
fn pub mut connect(path: ref Path) -> Result[Nil, Error] {
  sys.connect_unix(@socket, path, @deadline)
}
fn pub mut connect(path: ref Path) -> Result[Nil, Error]

Connects this socket to the specified address.

Examples

Connecting a Unix socket:

import std.net.socket (UnixSocket)

let listener = UnixSocket.stream.get
let stream = UnixSocket.stream.get

listener.bind('/tmp/test.sock'.to_path).get
listener.listen.get

stream.connect('/tmp/test.sock').get

flush

Show source code
Hide 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.

listen

Show source code
Hide source code
fn pub mut listen -> Result[Nil, Error] {
  sys.listen(@socket.inner, MAXIMUM_LISTEN_BACKLOG)
}
fn pub mut listen -> Result[Nil, Error]

Marks this socket as being ready to accept incoming connections using accept().

Examples

Marking a socket as a listener:

import std.net.socket (UnixSocket)

let socket = UnixSocket.stream.get

socket.bind('/tmp/test.sock'.to_path).get
socket.listen.get

local_address

Show source code
Hide source code
fn pub local_address -> Result[UnixAddress, Error] {
  match sys.unix_local_address(@socket) {
    case Ok(path) -> Result.Ok(UnixAddress(path))
    case Error(e) -> Result.Error(e)
  }
}
fn pub local_address -> Result[UnixAddress, Error]

Returns the local address of this socket.

peer_address

Show source code
Hide source code
fn pub peer_address -> Result[UnixAddress, Error] {
  match sys.unix_peer_address(@socket) {
    case Ok(path) -> Result.Ok(UnixAddress(path))
    case Error(e) -> Result.Error(e)
  }
}
fn pub peer_address -> Result[UnixAddress, Error]

Returns the peer address of this socket.

print

Show source code
Hide source code
fn pub mut print[B: Bytes](bytes: ref B) -> Result[Nil, E] {
  try write(bytes)
  write('\n')
}
fn pub mut print[B: Bytes](bytes: ref B) -> Result[Nil, E]

Writes the entirety of bytes to the underlying stream, followed by a Unix newline.

read

Show source code
Hide source code
fn pub mut read(into: mut ByteArray, size: Int) -> Result[Int, Error] {
  sys.read(@socket, into, size, @deadline)
}
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 code
Hide source code
fn pub mut read_all(bytes: mut ByteArray) -> Result[Int, E] {
  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, E]

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 code
Hide source code
fn pub mut read_exact(
  into: mut ByteArray,
  size: Int,
) -> Result[Nil, ReadExactError[E]] {
  let mut pending = size

  while pending > 0 {
    match read(into, pending) {
      case Ok(0) if pending > 0 -> throw ReadExactError.EndOfInput
      case Ok(n) -> pending -= n
      case Error(e) -> throw ReadExactError.Read(e)
    }
  }

  Result.Ok(nil)
}
fn pub mut read_exact(into: mut ByteArray, size: Int) -> Result[Nil, ReadExactError[E]]

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.

receive_buffer_size=

Show source code
Hide source code
fn pub mut receive_buffer_size=(value: Int) -> Result[Nil, Error] {
  set_option(libc.SOL_SOCKET, libc.SO_RCVBUF, value.to_int)
}
fn pub mut receive_buffer_size=(value: Int) -> Result[Nil, Error]

Sets the value of the SO_RCVBUF option.

receive_from

Show source code
Hide source code
fn pub mut receive_from(
  bytes: mut ByteArray,
  size: Int,
) -> Result[(Int, UnixAddress), Error] {
  match sys.receive_from_unix(@socket, bytes, size, @deadline) {
    case Ok((read, path)) -> Result.Ok((read, UnixAddress(path)))
    case Error(e) -> Result.Error(e)
  }
}
fn pub mut receive_from(bytes: mut ByteArray, size: Int) -> Result[(Int, UnixAddress), Error]

Receives a single datagram message on the socket, returning the size of the message and the address the message was sent from.

The message is read into the given ByteArray, and up to size bytes will be read.

Examples

Sending a message to ourselves and receiving it:

import std.net.socket (UnixSocket)

let socket = UnixSocket.datagram.get
let bytes = ByteArray.new

socket.send_to('hello', address: '/tmp/test.sock'.to_path).get

let received_from = socket.receive_from(bytes: bytes, size: 5).get

bytes.to_string           # => 'hello'
received_from.0           # => 5
received_from.1.to_string # => '/tmp/test.sock'

reset_deadline

Show source code
Hide source code
fn pub mut reset_deadline {
  @deadline = net.NO_DEADLINE
}
fn pub mut reset_deadline

Resets the deadline.

Examples

import std.net.socket (Socket)
import std.time (Duration)

let socket = Socket.datagram(ipv6: false)

socket.timeout_after = Duration.from_secs(5)
socket.reset_deadline

send_buffer_size=

Show source code
Hide source code
fn pub mut send_buffer_size=(value: Int) -> Result[Nil, Error] {
  set_option(libc.SOL_SOCKET, libc.SO_SNDBUF, value.to_int)
}
fn pub mut send_buffer_size=(value: Int) -> Result[Nil, Error]

Sets the value of the SO_SNDBUF option.

send_file

Show source code
Hide source code
fn pub mut send_file(file: mut ReadOnlyFile) -> Result[Int, Error] {
  sys.send_file_stream(file, self)
}
fn pub mut send_file(file: mut ReadOnlyFile) -> Result[Int, Error]

Sends a read-only file to the other half of self, without the need for an intermediate buffer.

Upon success the number of copied bytes is returned.

Upon returning from this method, the cursor/offset of the source file is the same as it was before calling this method.

Platform differences

The exact mechanism used for sending the file may vary per platform. For example, on FreeBSD, Linux and macOS this method uses the sendfile system call.

Fallbacks

Not all platforms or socket types support zero-copy sending of files. In such cases a userspace copy is performed. Such a fallback is applied to:

  • TLS sockets provided by std.net.tls
  • UdpSocket.send_file and UnixDatagram.send_file on FreeBSD and macOS

The userspace implementation copies data in chunks of 32 KiB and resets the cursor of file to its original position after copying the data. While resetting the cursor incurs a small cost, it ensures behavior is consistent with the kernel implementations of this method.

Examples

import std.fs.file (ReadOnlyFile)
import std.net.ip (IpAddress)
import std.net.socket (UdpSocket)

let file = ReadOnlyFile.new('README.md'.to_path).or_panic
let server = UdpSocket.new(IpAddress.v4(0, 0, 0, 0), port: 9999).or_panic
let client = UdpSocket.new(IpAddress.v4(0, 0, 0, 0), port: 0).or_panic

client.connect(IpAddress.v4(0, 0, 0, 0), port: 9999).or_panic
client.send_file(file).or_panic

let buf = ByteArray.new

server.read(buf, 1024).or_panic
buf.to_string # => '...'

send_to

Show source code
Hide source code
fn pub mut send_to[B: Bytes](
  bytes: ref B,
  address: ref Path,
) -> Result[Int, Error] {
  sys.send_to_unix(@socket, bytes.pointer, bytes.size, address, @deadline)
}
fn pub mut send_to[B: Bytes](bytes: ref B, address: ref Path) -> Result[Int, Error]

Sends a ByteArray to the given address.

The return value is the number of bytes sent.

Examples

import std.net.socket (UnixSocket)

let socket = UnixSocket.datagram.get

socket.bind('/tmp/test.sock'.to_path).get
socket.send_to('hello', address: '/tmp/test.sock'.to_path).get

shutdown

Show source code
Hide source code
fn pub mut shutdown -> Result[Nil, Error] {
  sys.shutdown(@socket, read: true, write: true)
}
fn pub mut shutdown -> Result[Nil, Error]

Shuts down both the reading and writing half of this socket.

shutdown_read

Show source code
Hide source code
fn pub mut shutdown_read -> Result[Nil, Error] {
  sys.shutdown(@socket, read: true, write: false)
}
fn pub mut shutdown_read -> Result[Nil, Error]

Shuts down the reading half of this socket.

shutdown_write

Show source code
Hide source code
fn pub mut shutdown_write -> Result[Nil, Error] {
  sys.shutdown(@socket, read: false, write: true)
}
fn pub mut shutdown_write -> Result[Nil, Error]

Shuts down the writing half of this socket.

timeout_after=

Show source code
Hide source code
fn pub mut timeout_after=[T: ToInstant](deadline: ref T) {
  @deadline = deadline.to_instant.to_int
}
fn pub mut timeout_after=[T: ToInstant](deadline: ref T)

Sets the point in time after which socket operations must time out, known as a "deadline".

Examples

Using a Duration results in this method calculating the absolute time after which operations time out:

import std.net.socket (Socket)
import std.time (Duration)

let socket = Socket.datagram(ipv6: false)

socket.timeout_after = Duration.from_secs(5)

We can also use an Instant:

import std.net.socket (Socket)
import std.time (Duration, Instant)

let socket = Socket.datagram(ipv6: false)

socket.timeout_after = Instant.new + Duration.from_secs(5)

try_clone

Show source code
Hide source code
fn pub try_clone -> Result[UnixSocket, Error] {
  let sock = net.raw_socket

  try sys.try_clone(@socket, mut sock)
  Result.Ok(UnixSocket(socket: sock, deadline: net.NO_DEADLINE))
}
fn pub try_clone -> Result[UnixSocket, Error]

Attempts to clone the socket.

Cloning a socket may fail, such as when the program has too many open file descriptors.

write

Show source code
Hide source code
fn pub mut write[B: Bytes](bytes: ref B) -> Result[Nil, Error] {
  write_all_internal(bytes.pointer, bytes.size)
}
fn pub mut write[B: Bytes](bytes: ref B) -> 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 is returned.

Implemented traits

std.drop.

Drop

impl Drop for UnixSocket
std.io.

Read

impl Read[Error] for UnixSocket
std.io.

Write

impl Write[Error] for UnixSocket