Xirsys.Sockets.Socket (xturn_sockets v1.2.0)

View Source

Socket protocol helpers optimized for TURN server usage.

This module provides a unified interface for handling different socket types including UDP, TCP, TLS, DTLS, and SCTP protocols. It's specifically optimized for TURN server operations with features like:

  • Rate limiting and connection management
  • Enhanced error handling and telemetry
  • Multi-protocol support with consistent API
  • Performance optimizations for media relay
  • Security features and validation

Socket Types

  • :udp - User Datagram Protocol for connectionless communication
  • :tcp - Transmission Control Protocol for reliable connections
  • :tls - Transport Layer Security over TCP
  • :dtls - Datagram Transport Layer Security over UDP
  • :sctp - Stream Control Transmission Protocol with multi-streaming

Examples

# Open a UDP socket
{:ok, socket} = Socket.open_port({127, 0, 0, 1}, :random, [])

# Send a message
:ok = Socket.send(socket, "Hello", {192, 168, 1, 1}, 5000)

# Perform handshake for connection-oriented protocols
{:ok, client_socket} = Socket.handshake(tcp_socket)

Summary

Functions

Enhanced rate limiting check for TURN server protection.

Returns the client message hooks from configuration.

Enhanced socket close with proper logging and cleanup.

Returns the configured connection timeout in milliseconds

Emit telemetry events for monitoring TURN server performance.

Returns TURN server configuration values.

Gets socket options with protocol-aware handling.

Enhanced handshake with timeout and better error handling.

Returns the maximum connections allowed per IP address

Opens a new port for UDP TURN transport with enhanced options.

Returns the peer message hooks from configuration.

Returns the peer address and port number for a socket.

Returns the port number for a UDP socket.

Returns whether rate limiting is enabled

Registers a socket with the inet database.

Sends a message over an open socket with enhanced error handling.

Sends data to client hooks with error handling.

Sends data to peer hooks with error handling.

Returns the server IP address from configuration.

Returns the server's local IP address from configuration.

Enhanced socket option setting with better error handling.

Sets one or more options for a socket.

Returns the local address and port number for a socket.

Returns the configured SSL handshake timeout in milliseconds

Types

ip_address()

@type ip_address() :: tuple()

policy()

@type policy() ::
  :random | {:preferred, port_number()} | {:range, port_number(), port_number()}

port_number()

@type port_number() :: non_neg_integer()

socket_options()

@type socket_options() :: list()

socket_type()

@type socket_type() :: :udp | :tcp | :dtls | :tls | :sctp

t()

@type t() :: %Xirsys.Sockets.Socket{
  sock: port(),
  type: :udp | :tcp | :dtls | :tls | :sctp
}

Functions

check_rate_limit(client_ip)

@spec check_rate_limit(ip_address()) :: :ok | {:error, :rate_limited}

Enhanced rate limiting check for TURN server protection.

Checks if a client IP is within the rate limit thresholds. Creates an ETS table for tracking if it doesn't exist.

Parameters

  • client_ip - The client's IP address tuple

Returns

  • :ok - Request is within rate limits
  • {:error, :rate_limited} - Client has exceeded rate limits

Examples

iex> Xirsys.Sockets.Socket.check_rate_limit({192, 168, 1, 1})
:ok

client_hooks()

@spec client_hooks() :: [module()]

Returns the client message hooks from configuration.

Client hooks are GenServer processes that receive client messages for processing or logging.

close(sock, reason \\ "")

@spec close(t() | any(), any()) :: :ok

Enhanced socket close with proper logging and cleanup.

Closes sockets with protocol-specific handling and telemetry emission. Includes graceful error handling for unsupported protocols.

Parameters

  • socket - Socket to close
  • reason - Reason for closing (for logging)

Returns

  • :ok - Socket closed successfully

Examples

# Socket.close(socket, "connection_timeout")

connection_timeout()

@spec connection_timeout() :: pos_integer()

Returns the configured connection timeout in milliseconds

emit_telemetry(event_name, measurements, metadata)

@spec emit_telemetry(atom(), map(), map()) :: :ok

Emit telemetry events for monitoring TURN server performance.

Emits telemetry events with the :xturn_sockets prefix for monitoring and observability. Gracefully handles cases where telemetry is unavailable.

Parameters

  • event_name - Name of the event to emit
  • measurements - Map of numeric measurements
  • metadata - Map of additional metadata

Returns

  • :ok - Event emitted successfully

Examples

iex> Xirsys.Sockets.Socket.emit_telemetry(:connection_opened, %{count: 1}, %{ip: {127, 0, 0, 1}})
:ok

get_config(key, default \\ nil)

@spec get_config(atom(), any()) :: any()

Returns TURN server configuration values.

Looks up configuration values in the following order:

  1. :xturn_sockets application config
  2. :xturn application config
  3. Default value

Parameters

  • key - Configuration key to lookup
  • default - Default value if key not found

Examples

iex> Xirsys.Sockets.Socket.get_config(:connection_timeout, 5000)
30000

getopts(socket)

@spec getopts(t()) :: {:ok, socket_options()} | {:error, term()}

Gets socket options with protocol-aware handling.

Retrieves current socket options based on the socket type. Different protocols expose different option sets.

Parameters

  • socket - Socket to query options from

Returns

  • {:ok, options} - Successfully retrieved options
  • {:error, reason} - Failed to retrieve options

Examples

# {:ok, opts} = Socket.getopts(socket)

handshake(socket)

@spec handshake(t()) :: {:ok, t()} | {:error, any()}

Enhanced handshake with timeout and better error handling.

Performs protocol-specific handshakes for connection-oriented sockets. Includes proper timeout handling and telemetry emission.

Parameters

  • socket - The listening socket to accept connections on

Returns

  • {:ok, client_socket} - Successfully accepted connection
  • {:error, reason} - Failed to accept or handshake

Examples

# TCP handshake example (requires actual socket)
# {:ok, client_socket} = Socket.handshake(tcp_listening_socket)

max_connections_per_ip()

@spec max_connections_per_ip() :: pos_integer()

Returns the maximum connections allowed per IP address

open_port(sip, policy, opts)

@spec open_port(ip_address(), policy(), socket_options()) ::
  {:ok, t()} | {:error, atom()}

Opens a new port for UDP TURN transport with enhanced options.

Creates a UDP socket with optimized buffer sizes and TURN-specific configuration. Supports different port allocation policies.

Parameters

  • sip - Server IP address tuple (IPv4)
  • policy - Port allocation policy (:random, {:preferred, port}, {:range, min, max})
  • opts - Additional socket options

Returns

  • {:ok, socket} - Successfully opened socket
  • {:error, reason} - Failed to open socket

Examples

# Open a UDP socket (returns actual socket struct)
# Xirsys.Sockets.Socket.open_port({127, 0, 0, 1}, :random, [])

peer_hooks()

@spec peer_hooks() :: [module()]

Returns the peer message hooks from configuration.

Peer hooks are GenServer processes that receive peer messages for processing or logging.

peername(socket)

@spec peername(t()) ::
  {:ok, {ip_address(), port_number()}}
  | {:local, binary()}
  | {:unspec, <<_::0>>}
  | {:undefined, any()}
  | {:error, term()}

Returns the peer address and port number for a socket.

Gets the remote peer information for connected sockets with protocol-aware handling.

Parameters

  • socket - Socket to query

Returns

  • {:ok, {ip, port}} - Successfully retrieved peer address
  • {:local, path} - Unix domain socket path
  • {:unspec, <<>>} - Unspecified address
  • {:undefined, term} - Undefined address
  • {:error, reason} - Failed to get peer address

Examples

# {:ok, {ip, port}} = Socket.peername(socket)

port(socket)

@spec port(t()) :: {:ok, port_number()} | {:error, term()}

Returns the port number for a UDP socket.

Gets the local port number that the socket is bound to.

Parameters

  • socket - UDP socket to query

Returns

  • {:ok, port} - Successfully retrieved port number
  • {:error, reason} - Failed to get port

Examples

# {:ok, port} = Socket.port(udp_socket)

rate_limit_enabled?()

@spec rate_limit_enabled?() :: boolean()

Returns whether rate limiting is enabled

register_socket(socket)

@spec register_socket(t()) :: boolean()

Registers a socket with the inet database.

Required for proper socket management in the Erlang inet system.

Parameters

  • socket - Socket to register

Returns

  • true - Socket registered successfully
  • false - Failed to register socket

send(socket, msg, ip \\ nil, port \\ nil)

@spec send(t(), binary(), ip_address() | nil, port_number() | nil) ::
  :ok | {:error, term()}

Sends a message over an open socket with enhanced error handling.

Supports all socket types (UDP, TCP, TLS, DTLS, SCTP) with protocol-specific optimizations. Includes telemetry emission for monitoring.

Parameters

  • socket - The socket to send over
  • msg - Binary message to send
  • ip - Destination IP (for UDP only)
  • port - Destination port (for UDP only)

Returns

  • :ok - Message sent successfully
  • {:error, reason} - Failed to send message

Examples

# UDP send
# Socket.send(udp_socket, "hello", {192, 168, 1, 1}, 5000)

# TCP send
# Socket.send(tcp_socket, "hello")

send_to_client_hooks(data)

@spec send_to_client_hooks(any()) :: :ok

Sends data to client hooks with error handling.

Dispatches messages to configured client hook processes for processing or logging. Includes error recovery.

Parameters

  • data - The data to send to client hooks

Examples

iex> Xirsys.Sockets.Socket.send_to_client_hooks(%{message: "hello"})
:ok

send_to_peer_hooks(data)

@spec send_to_peer_hooks(any()) :: :ok

Sends data to peer hooks with error handling.

Dispatches messages to configured peer hook processes for processing or logging. Includes error recovery.

Parameters

  • data - The data to send to peer hooks

Examples

iex> Xirsys.Sockets.Socket.send_to_peer_hooks(%{message: "hello"})
:ok

server_ip()

@spec server_ip() :: ip_address()

Returns the server IP address from configuration.

Used for packet processing and response generation.

server_local_ip()

@spec server_local_ip() :: ip_address()

Returns the server's local IP address from configuration.

Used for binding sockets to specific network interfaces.

set_sockopt(list_sock, cli_socket)

@spec set_sockopt(t(), t()) :: :ok | {:error, term()}

Enhanced socket option setting with better error handling.

Transfers socket options from a listening socket to a client socket. Includes protocol-specific handling and proper error recovery.

Parameters

  • list_sock - The listening socket to copy options from
  • cli_socket - The client socket to apply options to

Returns

  • :ok - Options transferred successfully
  • {:error, reason} - Failed to transfer options

Examples

# Socket.set_sockopt(listening_socket, client_socket)

setopts(socket, opts \\ [{:active, :once}, :binary])

@spec setopts(port() | t(), socket_options()) :: :ok | {:error, term()}

Sets one or more options for a socket.

Configures socket options with protocol-aware handling. Supports both raw ports and Socket structs.

Parameters

  • socket - Socket or port to configure
  • opts - List of socket options to set

Returns

  • :ok - Options set successfully
  • {:error, reason} - Failed to set options

Examples

# Socket.setopts(socket, [{:active, :once}, :binary])

sockname(socket)

@spec sockname(t()) ::
  {:ok, {ip_address(), port_number()}}
  | {:local, binary()}
  | {:unspec, <<_::0>>}
  | {:undefined, any()}
  | {:error, term()}

Returns the local address and port number for a socket.

Gets the local binding information for the socket with protocol-aware handling.

Parameters

  • socket - Socket to query

Returns

  • {:ok, {ip, port}} - Successfully retrieved local address
  • {:local, path} - Unix domain socket path
  • {:unspec, <<>>} - Unspecified address
  • {:undefined, term} - Undefined address
  • {:error, reason} - Failed to get address

Examples

# {:ok, {ip, port}} = Socket.sockname(socket)

ssl_handshake_timeout()

@spec ssl_handshake_timeout() :: pos_integer()

Returns the configured SSL handshake timeout in milliseconds