.. _bsd_sockets_interface:

BSD Sockets
###########

.. contents::
    :local:
    :depth: 2

Overview
********

Zephyr offers an implementation of a subset of the BSD Sockets API (a part
of the POSIX standard). This API allows to reuse existing programming experience
and port existing simple networking applications to Zephyr.

Here are the key requirements and concepts which governed BSD Sockets
compatible API implementation for Zephyr:

* Has minimal overhead, similar to the requirement for other
  Zephyr subsystems.
* Is namespaced by default, to avoid name conflicts with well-known
  names like ``close()``, which may be part of libc or other POSIX
  compatibility libraries.
  If enabled by :kconfig:option:`CONFIG_POSIX_API`, it will also
  expose POSIX compatible APIs.

BSD Sockets compatible API is enabled using :kconfig:option:`CONFIG_NET_SOCKETS`
config option and implements the following operations: ``socket()``, ``close()``,
``recv()``, ``recvfrom()``, ``send()``, ``sendto()``, ``connect()``, ``bind()``,
``listen()``, ``accept()``, ``fcntl()`` (to set non-blocking mode),
``getsockopt()``, ``setsockopt()``, ``poll()``, ``select()``,
``getaddrinfo()``, ``getnameinfo()``.

Based on the namespacing requirements above, these operations are by
default exposed as functions with ``zsock_`` prefix, e.g.
:c:func:`zsock_socket` and :c:func:`zsock_close`. If the config option
:kconfig:option:`CONFIG_POSIX_API` is defined, all the functions
will be also exposed as aliases without the prefix. This includes the
functions like ``close()`` and ``fcntl()`` (which may conflict with
functions in libc or other libraries, for example, with the filesystem
libraries).

Another entailment of the design requirements above is that the Zephyr
API aggressively employs the short-read/short-write property of the POSIX API
whenever possible (to minimize complexity and overheads). POSIX allows
for calls like ``recv()`` and ``send()`` to actually process (receive
or send) less data than requested by the user (on ``SOCK_STREAM`` type
sockets). For example, a call ``recv(sock, 1000, 0)`` may return 100,
meaning that only 100 bytes were read (short read), and the application
needs to retry call(s) to receive the remaining 900 bytes.

The BSD Sockets API uses file descriptors to represent sockets. File
descriptors are small integers, consecutively assigned from zero, shared
among sockets, files, special devices (like stdin/stdout), etc. Internally,
there is a table mapping file descriptors to internal object pointers.
The file descriptor table is used by the BSD Sockets API even if the rest
of the POSIX subsystem (filesystem, stdin/stdout) is not enabled.

Zephyr supports multiple types of BSD sockets, the following table summarizes
what socket types are available:

+--------------+-------------+------------------+---------------------------------------------------------------------------+
| Family       | Type        | Protocol         | Description                                                               |
+==============+=============+==================+===========================================================================+
| AF_INET |br| | SOCK_DGRAM  | IPPROTO_UDP      | Enabled if :kconfig:option:`CONFIG_NET_UDP` is set. |br|                  |
| AF_INET6     |             |                  | Allows to send and receive UDP datagrams.                                 |
|              |             +------------------+---------------------------------------------------------------------------+
|              |             | IPPROTO_DTLS_1_x | Enabled if :kconfig:option:`CONFIG_NET_SOCKETS_ENABLE_DTLS` is set. |br|  |
|              |             |                  | Allows to send and receive DTLS datagrams.                                |
|              +-------------+------------------+---------------------------------------------------------------------------+
|              | SOCK_STREAM | IPPROTO_TCP      | Enabled if :kconfig:option:`CONFIG_NET_TCP` is set. |br|                  |
|              |             |                  | Allows to send and receive TCP data stream.                               |
|              |             +------------------+---------------------------------------------------------------------------+
|              |             | IPPROTO_TLS_1_x  | Enabled if :kconfig:option:`CONFIG_NET_SOCKETS_SOCKOPT_TLS` is set. |br|  |
|              |             |                  | Allows to send and receive TLS data stream.                               |
|              +-------------+------------------+---------------------------------------------------------------------------+
|              | SOCK_RAW    | IPPROTO_IP |br|  | Enabled if :kconfig:option:`CONFIG_NET_SOCKETS_INET_RAW` is set. |br|     |
|              |             | <proto>          | Allows to send and receive IPv4/IPv6 datagrams. |br|                      |
|              |             |                  | Packets are filtered by L4 protocol specified.                            |
|              |             |                  | IPPROTO_IP is a wildcard protocol to receive all IP datagrams.            |
+--------------+-------------+------------------+---------------------------------------------------------------------------+
| AF_PACKET    | SOCK_DGRAM  | ETH_P_ALL |br|   | Enabled if :kconfig:option:`CONFIG_NET_SOCKETS_PACKET_DGRAM` is set. |br| |
|              |             | <proto>          | Allows to send and receive packets without L2 header. |br|                |
|              |             |                  | Packets are filtered by L3 protocol specified.                            |
|              |             |                  | ETH_P_ALL is a wildcard protocol to receive all packets.                  |
|              +-------------+------------------+---------------------------------------------------------------------------+
|              | SOCK_RAW    | ETH_P_ALL        | Enabled if :kconfig:option:`CONFIG_NET_SOCKETS_PACKET` is set. |br|       |
|              |             |                  | Allows to send and receive packets with L2 header included.               |
+--------------+-------------+------------------+---------------------------------------------------------------------------+
| AF_CAN       | SOCK_RAW    | CAN_RAW          | Enabled if :kconfig:option:`CONFIG_NET_SOCKETS_CAN` is set. |br|          |
|              |             |                  | Allows to send and receive CAN packets.                                   |
+--------------+-------------+------------------+---------------------------------------------------------------------------+

See :zephyr:code-sample:`sockets-echo-server` and :zephyr:code-sample:`sockets-echo-client`
sample applications to learn how to create a simple server or client BSD socket based
application.

.. _secure_sockets_interface:

Secure Sockets
**************

Zephyr provides an extension of standard POSIX socket API, allowing to create
and configure sockets with TLS protocol types, facilitating secure
communication. Secure functions for the implementation are provided by
mbedTLS library. Secure sockets implementation allows use of both TLS and DTLS
protocols with standard socket calls. See :c:enum:`net_ip_protocol_secure` type
for supported secure protocol versions.

To enable secure sockets, set the :kconfig:option:`CONFIG_NET_SOCKETS_SOCKOPT_TLS`
option. To enable DTLS support, use :kconfig:option:`CONFIG_NET_SOCKETS_ENABLE_DTLS`
option.

.. _sockets_tls_credentials_subsys:

TLS credentials subsystem
=========================

TLS credentials must be registered in the system before they can be used with
secure sockets. See :c:func:`tls_credential_add` for more information.

When a specific TLS credential is registered in the system, it is assigned with
numeric value of type :c:type:`sec_tag_t`, called a tag. This value can be used
later on to reference the credential during secure socket configuration with
socket options.

The following TLS credential types can be registered in the system:

- ``TLS_CREDENTIAL_CA_CERTIFICATE``
- ``TLS_CREDENTIAL_PUBLIC_CERTIFICATE``
- ``TLS_CREDENTIAL_PRIVATE_KEY``
- ``TLS_CREDENTIAL_PSK``
- ``TLS_CREDENTIAL_PSK_ID``

An example registration of CA certificate (provided in ``ca_certificate``
array) looks like this:

.. code-block:: c

   ret = tls_credential_add(CA_CERTIFICATE_TAG, TLS_CREDENTIAL_CA_CERTIFICATE,
                            ca_certificate, sizeof(ca_certificate));

By default certificates in DER format are supported. PEM support can be enabled
in mbedTLS settings.

Secure Socket Creation
======================

A secure socket can be created by specifying secure protocol type, for instance:

.. code-block:: c

   sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TLS_1_2);

Once created, it can be configured with socket options. For instance, the
CA certificate and hostname can be set:

.. code-block:: c

   sec_tag_t sec_tag_opt[] = {
           CA_CERTIFICATE_TAG,
   };

   ret = setsockopt(sock, SOL_TLS, TLS_SEC_TAG_LIST,
                    sec_tag_opt, sizeof(sec_tag_opt));

.. code-block:: c

   char host[] = "google.com";

   ret = setsockopt(sock, SOL_TLS, TLS_HOSTNAME, host, sizeof(host));

Once configured, socket can be used just like a regular TCP socket.

.. note::

   Due to mbed TLS internal data buffering and ``mbedtls_ssl_write()`` function
   requirements, when a non-blocking :c:func:`zsock_send` returns ``EAGAIN``, it is
   expected that the consecutive call to :c:func:`zsock_send` will contain the same
   data as the original call.

Several samples in Zephyr use secure sockets for communication. For a sample use
see e.g. :zephyr:code-sample:`echo-server sample application <sockets-echo-server>` or
:zephyr:code-sample:`HTTP GET sample application <sockets-http-get>`.

Secure Sockets options
======================

Secure sockets offer the following options for socket management:

.. doxygengroup:: secure_sockets_options

Socket offloading
*****************

Zephyr allows to register custom socket implementations (called offloaded
sockets). This allows for seamless integration for devices which provide an
external IP stack and expose socket-like API.

Socket offloading can be enabled with :kconfig:option:`CONFIG_NET_SOCKETS_OFFLOAD`
option. A network driver that wants to register a new socket implementation
should use :c:macro:`NET_SOCKET_OFFLOAD_REGISTER` macro. The macro accepts the
following parameters:

 * ``socket_name``
     An arbitrary name for the socket implementation.

 * ``prio``
     Socket implementation's priority. The higher the priority, the earlier this
     particular implementation will be processed when creating a new socket.
     Lower numeric value indicates higher priority.

 * ``_family``
     Socket family implemented by the offloaded socket. ``AF_UNSPEC`` indicates
     any family.

 * ``_is_supported``
     A filtering function, used to verify whether a particular socket family,
     type and protocol are supported by the offloaded socket implementation.

 * ``_handler``
     A function compatible with :c:func:`socket` API, used to create an
     offloaded socket.

Every offloaded socket implementation should also implement a set of socket
APIs, specified in :c:struct:`socket_op_vtable` struct.

The function registered for socket creation should allocate a new file
descriptor using :c:func:`zvfs_reserve_fd` function. Any additional actions,
specific to the creation of a particular offloaded socket implementation,
should take place after the file descriptor is allocated. As a final step,
if the offloaded socket was created successfully, the file descriptor should
be finalized with :c:func:`zvfs_finalize_typed_fd`, or :c:func:`zvfs_finalize_fd`
functions. The finalize function allows to register a
:c:struct:`socket_op_vtable` structure implementing socket APIs for an
offloaded socket along with an optional socket context data pointer.

Finally, when an offloaded network interface is initialized, it should indicate
that the interface is offloaded with :c:func:`net_if_socket_offload_set`
function. The function registers the function used to create an offloaded socket
(the same as the one provided in :c:macro:`NET_SOCKET_OFFLOAD_REGISTER`) at the
network interface.

Offloaded socket creation
=========================

When application creates a new socket with :c:func:`socket` function, the
network stack iterates over all registered socket implementations (native and
offloaded). Higher priority socket implementations are processed first.
For each registered socket implementation, an address family is verified, and if
it matches (or the socket was registered as ``AF_UNSPEC``), the corresponding
``_is_supported`` function is called to verify the remaining socket parameters.
The first implementation that fulfills the socket requirements (i. e.
``_is_supported`` returns true) will create a new socket with its ``_handler``
function.

The above indicates the importance of the socket priority. If multiple socket
implementations support the same set of socket family/type/protocol, the first
implementation processed by the system will create a socket. Therefore it's
important to give the highest priority to the implementation that should be the
system default.

The socket priority for native socket implementation is configured with Kconfig.
Use :kconfig:option:`CONFIG_NET_SOCKETS_TLS_PRIORITY` to set the priority for
the native TLS sockets.
Use :kconfig:option:`CONFIG_NET_SOCKETS_PRIORITY_DEFAULT` to set the priority
for the remaining native sockets.

Dealing with multiple offloaded interfaces
==========================================

As the :c:func:`socket` function does not allow to specify which network
interface should be used by a socket, it's not possible to choose a specific
implementation in case multiple offloaded socket implementations, supporting the
same type of sockets, are available. The same problem arises when both native
and offloaded sockets are available in the system.

To address this problem, a special socket implementation (called socket
dispatcher) was introduced. The sole reason for this module is to postpone the
socket creation for until the first operation on a socket is performed. This
leaves an opening to use ``SO_BINDTODEVICE`` socket option, to bind a socket to
a particular network interface (and thus offloaded socket implementation).
The socket dispatcher can be enabled with :kconfig:option:`CONFIG_NET_SOCKETS_OFFLOAD_DISPATCHER`
Kconfig option.

When enabled, the application can specify the network interface to use with
:c:func:`setsockopt` function:

.. code-block:: c

   /* A "dispatcher" socket is created */
   sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

   struct ifreq ifreq = {
      .ifr_name = "SimpleLink"
   };

   /* The socket is "dispatched" to a particular network interface
    * (offloaded or not).
    */
   setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &ifreq, sizeof(ifreq));

Similarly, if TLS is supported by both native and offloaded sockets,
``TLS_NATIVE`` socket option can be used to indicate that a native TLS socket
should be created. The underlying socket can then be bound to a particular
network interface:

.. code-block:: c

   /* A "dispatcher" socket is created */
   sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TLS_1_2);

   int tls_native = 1;

   /* The socket is "dispatched" to a native TLS socket implmeentation.
    * The underlying socket is a "dispatcher" socket now.
    */
   setsockopt(sock, SOL_TLS, TLS_NATIVE, &tls_native, sizeof(tls_native));

   struct ifreq ifreq = {
      .ifr_name = "SimpleLink"
   };

   /* The underlying socket is "dispatched" to a particular network interface
    * (offloaded or not).
    */
   setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &ifreq, sizeof(ifreq));

In case no ``SO_BINDTODEVICE`` socket option is used on a socket, the socket
will be dispatched according to the default priority and filtering rules on a
first socket API call.

API Reference
*************

BSD Sockets
===========

.. doxygengroup:: bsd_sockets

TLS Credentials
===============

.. doxygengroup:: tls_credentials
