NEAT Sockets API
Internet-Draft draft-dreibholz-taps-neat-socketapi-14
Thomas Dreibholz
Simula Metropolitan Centre for Digital Engineering
Pilestredet 52
0167 Oslo
Norway
dreibh@simula.no
https://www.simula.no/people/dreibh
Internet-Draft
This document describes a BSD Sockets-like API on top of the callback-based NEAT User API. This facilitates porting existing applications to use a subset of NEAT's functionality.
Introduction
The NEAT project [ANRW2017], [NEAT-D1.1], [I-D.ietf-taps-transports-usage], [I-D.gjessing-taps-minset], [NEAT-Website] wants to achieve a complete redesign of the way in which Internet applications interact with the network. Our goal is to allow network "services" offered to applications - such as reliability, low-delay communication or security - to be dynamically tailored based on application demands, current network conditions, hardware capabilities or local policies, and also to support the integration of new network functionality in an evolutionary fashion.
This document describes the NEAT Sockets API on top of the callback-based NEAT User API [I-D.fairhurst-taps-neat]. It provides a BSD Sockets-like API that facilitates porting existing applications to use a subset of NEAT's functionality. For further information on NEAT, see also [ANRW2017], [NEAT-D1.1], [NEAT-D1.3], [NEAT-D2.2], [NEAT-D2.3].
Conventions
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119].
Initialisation and Clean-Up
nsa_init()
nsa_init() is used to explicitly initialise the NEAT Sockets API. In the usual case, however, the NEAT Sockets API is automatically initialized when creating a NEAT socket. Explicit initialisation may only be necessary in a multi-threaded program, in order to avoid parallel initialisation calls.
Function Prototype:

int nsa_init()

Return Value:
nsa_init() returns the new NEAT socket descriptor, or -1 in case of error. The error code will be set in the errno variable.
nsa_cleanup()
nsa_cleanup() is used to free all resources allocated by NEAT. Note, that the NEAT Sockets API is automatically initialized when creating a NEAT socket.
Function Prototype:

void nsa_cleanup()

nsa_map_socket()
nsa_map_socket() is used to map a system socket descriptor into the NEAT socket descriptor space. This is useful for using NEAT API functions as wrapper to calls on non-NEAT sockets. Mapped socket descriptors can be unmapped by using nsa_unmap_socket().
Function Prototype:

int nsa_map_socket(int systemSD, int neatSD)

Arguments:
systemSD:
System socket descriptor.
neatSD:
Desired NEAT socket descriptor; -1 for automatic allocation.
Return Value:
nsa_map_socket() returns the new NEAT socket descriptor, or -1 in case of error. The error code will be set in the errno variable.
nsa_unmap_socket()
nsa_unmap_socket() is used to unmap a system socket descriptor from the NEAT socket descriptor space.
Function Prototype:

int nsa_unmap_socket(int neatSD)
Arguments:
neatSD:
NEAT socket descriptor.
Connection Establishment and Teardown
nsa_socket()
nsa_socket() creates a new NEAT socket. The NEAT socket can either be a wrapper around the NEAT User API (if properties are specified) or be a wrapper around a system socket (if no properties are specified).
Function Prototype:

int nsa_socket(int domain, int type, int protocol,
               const char* properties)
Arguments:
domain:
Domain for system socket (e.g. AF_INET).
type:
Type for system socket (SOCK_SEQPACKET).
protocol:
Protocol for system socket (IPPROTO_SCTP).
properties:
Properties for NEAT Core socket.
Return Value:
nsa_socket() returns the NEAT socket descriptor in case of success, or -1 in case of error. The error code will be set in the errno variable.
See the socket() documentation for details.
nsa_socketpair()
nsa_socketpair() is a wrapper around the socketpair() call, returning NEAT socket descriptors instead. Note, that socketpair() only supports AF_UNIX sockets, i.e. this function is just a wrapper for the system function.
Function Prototype:

int nsa_socketpair(int domain, int type, int protocol,
                   const char* properties)
See the socketpair() documentation for details.
nsa_close()
nsa_close() closes a given NEAT socket.
Function Prototype:

int nsa_close(int sockfd)
Arguments:
sockfd:
NEAT socket descriptor.
nsa_close() returns 0 in case of success, or -1 in case of error. The error code will be set in the errno variable.
See the close() documentation for details.
nsa_fcntl()
nsa_fcntl() manipulates a given NEAT socket.
Function Prototype:

int nsa_fcntl(int sockfd, int cmd, ...)
Arguments:
sockfd:
NEAT socket descriptor.
cmd:
Command.
...:
Command-specific arguments.
nsa_fcntl() returns a command-specific value.
For NEAT sockets, the following commands are specified:
F_GETFL:
Obtain value of the socket descriptor status flags. For NEAT sockets, the flag O_NONBLOCK specifies whether the socket is non-blocking. By default, it is blocking (i.e. O_NONBLOCK is not set).
F_SETFL:
Set value of the socket descriptor status flags. For NEAT sockets, the flag O_NONBLOCK specifies whether the socket is non-blocking. By default, it is blocking (i.e. O_NONBLOCK is not set). F_SETFL can then be used to change the blocking mode.
See the fcntl() documentation for details.
nsa_bind()
nsa_bind() binds a given NEAT socket to a given address. Note: this function is provided as legacy wrapper, and it is RECOMMENDED to use nsa_bindn() instead. Note further, that nsa_bind() also supports a single address only (i.e. no multi-homing). nsa_bindx() SHOULD be used instead to support multi-homing.
Function Prototype:

int nsa_bind(int sockfd,
             const struct sockaddr* addr, socklen_t addrlen,
             struct neat_tlv* opt, const int optcnt)
Arguments:
sockfd:
NEAT socket descriptor.
addr:
Address to bind to.
addrlen:
Length of the address structure "addr".
opt:
NEAT options (NULL, if there are none).
optcnt:
Number of NEAT options provided by "opt".
nsa_bind() returns 0 in case of success, or -1 in case of error. The error code will be set in the errno variable.
See the bind() documentation for details.
nsa_bindx()
nsa_bindx() binds a given NEAT socket to a given set of addresses. Note: this function is provided as legacy wrapper, and it is RECOMMENDED to use nsa_bindn() instead.
Function Prototype:

int nsa_bindx(int sockfd, const struct sockaddr* addrs, int addrcnt,
              int flags,
              struct neat_tlv* opt, const int optcnt)
Arguments:
sockfd:
NEAT socket descriptor.
addrs:
Addresses to bind to.
addrcnt:
Number of addresses in "addr".
flags:
Optional flags (0, if there are none).
opt:
NEAT options (NULL, if there are none).
optcnt:
Number of NEAT options provided by "opt".
nsa_bindx() returns 0 in case of success, or -1 in case of error. The error code will be set in the errno variable.
See the sctp_bindx() documentation for details.
nsa_bindn()
nsa_bindn() binds a given NEAT socket to a given port. NEAT takes care of handling local addresses.
Function Prototype:

int nsa_bindn(int sockfd, uint16_t port, int flags,
              struct neat_tlv* opt, const int optcnt)
Arguments:
sockfd:
NEAT socket descriptor.
port:
Port number to bind to.
flags:
Optional flags (0, if there are none).
opt:
NEAT options (NULL, if there are none).
optcnt:
Number of NEAT options provided by "opt".
nsa_bindn() returns 0 in case of success, or -1 in case of error. The error code will be set in the errno variable.
nsa_connect()
nsa_connect() connects a given NEAT socket to a given remote address. Note: this function is provided as legacy wrapper, and it is RECOMMENDED to use nsa_connectn() instead. Note further, that nsa_connect() also supports a single address only (i.e. no multi-homing). nsa_connectx() SHOULD be used instead to support multi-homing.
Function Prototype:

int nsa_connect(int sockfd,
                const struct sockaddr* addr, socklen_t addrlen,
                struct neat_tlv* opt, const int optcnt)
Arguments:
sockfd:
NEAT socket descriptor.
addr:
Address to connect to.
addrlen:
Length of the address structure "addr".
opt:
NEAT options (NULL, if there are none).
optcnt:
Number of NEAT options provided by "opt".
nsa_connect() returns 0 in case of success, or -1 in case of error. The error code will be set in the errno variable.
See the connect() documentation for details.
nsa_connectx()
nsa_connectx() connects a given NEAT socket to a given set of remote addresses. Note: this function is provided as legacy wrapper, and it is RECOMMENDED to use nsa_connectn() instead.
Function Prototype:

int nsa_connectx(int sockfd,
                 const struct sockaddr* addrs, int addrcnt,
                 neat_assoc_t* id,
                 struct neat_tlv* opt, const int optcnt)
Arguments:
sockfd:
NEAT socket descriptor.
addrs:
Addresses to connect to.
addrcnt:
Number of addresses in "addr".
id
Pointer to store association ID to (not used yet, use NULL!).
opt:
NEAT options (NULL, if there are none).
optcnt:
Number of NEAT options provided by "opt".
nsa_connectx() returns 0 in case of success, or -1 in case of error. The error code will be set in the errno variable.
See the sctp_connectx() documentation for details.
nsa_connectn()
nsa_connectn() connects a given NEAT socket to a given remote name and port. The remote name is resolved by NEAT to corresponding remote addresses.
Function Prototype:

int nsa_connectn(int sockfd, const char* name, const uint16_t port,
                 neat_assoc_t* id,
                 struct neat_tlv* opt, const int optcnt)
Arguments:
sockfd:
NEAT socket descriptor.
name:
Remote name to connect to.
port:
Remote port number to connect to.
id
Pointer to store association ID to (not used yet, use NULL!).
opt:
NEAT options (NULL, if there are none).
optcnt:
Number of NEAT options provided by "opt".
nsa_connectn() returns 0 in case of success, or -1 in case of error. The error code will be set in the errno variable.
nsa_listen()
nsa_listen() marks a given NEAT socket as listening socket, i.e. accepting incoming connections.
Function Prototype:

int nsa_listen(int sockfd, int backlog)
Arguments:
sockfd:
NEAT socket descriptor.
backlog:
Defines the maximum length to which the queue of pending connections for "sockfd" may grow.
nsa_listen() returns 0 in case of success, or -1 in case of error. The error code will be set in the errno variable.
See the listen() documentation for details.
nsa_accept()
nsa_accept() extracts the first connection request in the queue of pending connections for a listening NEAT socket, creates a new connected socket, and returns a new NEAT socket descriptor referring to that socket.
Function Prototype:

int nsa_accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen)
Arguments:
sockfd:
NEAT socket descriptor.
addr:
Pointer to storage space to store the peer's primary address to (or NULL, if address is not needed).
addrlen:
Pointer to variable with size of the storage in "addr" (or NULL, if address is not needed).
nsa_accept() returns the new NEAT socket descriptor in case of success, or -1 in case of error. The error code will be set in the errno variable. In case of success, the peer's primary address is stored in "addr", if there is sufficient space. The variable pointer to by "addrlen" will then contain the actual address size.
See the accept() documentation for details.
nsa_accept4()
nsa_accept4() extracts the first connection request in the queue of pending connections for a listening NEAT socket, creates a new connected socket, and returns a new NEAT socket descriptor referring to that socket. If successful, and flags!=0, nsa_accept4() furthermore makes the new socket non-blocking (SOCK_NONBLOCK flag) and/or close-on-exec (SOCK_CLOEXEC flag). For flags==0, the behaviour is identical to nsa_accept().
Function Prototype:

int nsa_accept4(int sockfd,
                struct sockaddr* addr, socklen_t* addrlen,
                int flags)
Arguments:
sockfd:
NEAT socket descriptor.
addr:
Pointer to storage space to store the peer's primary address to (or NULL, if address is not needed).
addrlen:
Pointer to variable with size of the storage in "addr" (or NULL, if address is not needed).
nsa_accept4() returns the new NEAT socket descriptor in case of success, or -1 in case of error. The error code will be set in the errno variable. In case of success, the peer's primary address is stored in "addr", if there is sufficient space. The variable pointer to by "addrlen" will then contain the actual address size.
See the accept() documentation for details.
nsa_shutdown()
nsa_shutdown() shuts down the connection of a given NEAT socket.
Function Prototype:

int nsa_shutdown(int sockfd, int how)
Arguments:
sockfd:
NEAT socket descriptor.
how:
Not used for NEAT sockets (set to SHUT_RDWR).
nsa_shutdown() returns 0 in case of success, or -1 in case of error. The error code will be set in the errno variable.
See the shutdown() documentation for details.
Options Handling
nsa_getsockopt()
nsa_getsockopt() gets a socket option of a given NEAT socket.
Function Prototype:

int nsa_getsockopt(int sockfd, int level, int optname,
                   void* optval, socklen_t* optlen)
Arguments:
sockfd:
NEAT socket descriptor.
level:
Option level.
optname:
Option number.
optval:
Buffer to store option value to.
optlen:
Pointer to variable with length of the buffer in "optval".
nsa_getsockopt() returns 0 in case of success, or -1 in case of error. The error code will be set in the errno variable.
See the getsockopt() documentation for details.
nsa_setsockopt()
nsa_getsockopt() sets a socket option of a given NEAT socket.
Function Prototype:

int nsa_setsockopt(int sockfd, int level, int optname,
                   const void* optval, socklen_t optlen)
Arguments:
sockfd:
NEAT socket descriptor.
level:
Option level.
optname:
Option number.
optval:
Buffer with option value to set.
optlen:
Length of buffer with option value.
nsa_setsockopt() returns 0 in case of success, or -1 in case of error. The error code will be set in the errno variable.
See the setsockopt() documentation for details.
nsa_opt_info()
nsa_opt_info() gets a socket option of a given NEAT socket.
Function Prototype:

int nsa_opt_info(int sockfd, neat_assoc_t id,
                 int opt, void* arg, socklen_t* size)
Arguments:
sockfd:
NEAT socket descriptor.
id:
Association identifier (0 in case of 1:1-style sockets).
opt:
Option number.
arg:
Buffer to store option value to.
size:
Pointer to variable with length of the buffer in "arg".
nsa_opt_info() returns 0 in case of success, or -1 in case of error. The error code will be set in the errno variable.
See the sctp_opt_info() documentation for details.
Security
nsa_set_secure_identity()
TBD.
... TBD.
Input/Output Handling
nsa_write()
nsa_write() sends data over a given connected NEAT socket. For NEAT sockets, nsa_write() is equal to nsa_send() with "flags" set to 0.
Function Prototype:

ssize_t nsa_write(int fd, const void* buf, size_t len)
Arguments:
fd:
NEAT socket descriptor.
buf:
Data to send.
len:
Length of data to send.
nsa_write() returns the number of sent bytes in case of success, or -1 in case of error. The error code will be set in the errno variable.
See the write() documentation for details.
nsa_writev()
nsa_writev() sends data over a given connected NEAT socket. The data is provided by an iovec structure.
Function Prototype:

ssize_t nsa_writev(int fd, const struct iovec* iov, int iovcnt)
Arguments:
sockfd:
NEAT socket descriptor.
iov:
Data to send provided as iovec structures.
iovcnt:
Number of provided iovec structures.
nsa_writev() returns the number of sent bytes in case of success, or -1 in case of error. The error code will be set in the errno variable.
See the writev() documentation for details.
nsa_pwrite()
nsa_pwrite() is a wrapper around the pwrite() call, using a NEAT socket descriptor instead.
Function Prototype:

ssize_t nsa_pwrite(int fd, const void* buf, size_t len, off_t offset)
See the pwrite() documentation for details.
nsa_pwrite64()
nsa_pwrite64() is a wrapper around the pwrite64() call, using a NEAT socket descriptor instead.
Function Prototype:

ssize_t nsa_pwrite(int fd, const void* buf, size_t len,
                   off64_t offset)
See the pwrite64() documentation for details.
nsa_pwritev()
nsa_pwritev() is a wrapper around the pwritev() call, using a NEAT socket descriptor instead.
Function Prototype:

ssize_t nsa_pwritev(int fd, const struct iovec* iov, int iovcnt,
                    off_t offset)
See the pwritev() documentation for details.
nsa_pwritev64()
nsa_pwritev64() is a wrapper around the pwritev64() call, using a NEAT socket descriptor instead.
Function Prototype:

ssize_t nsa_pwritev(int fd, const struct iovec* iov, int iovcnt,
                    off64_t offset)
See the pwritev64() documentation for details.
nsa_send()
nsa_send() sends data over a given connected NEAT socket.
Function Prototype:

ssize_t nsa_send(int sockfd, const void* buf, size_t len, int flags)
Arguments:
sockfd:
NEAT socket descriptor.
buf:
Data to send.
len:
Length of data to send.
flags:
Optional flags (0, if there are none).
nsa_send() returns the number of sent bytes in case of success, or -1 in case of error. The error code will be set in the errno variable.
See the send() documentation for details.
nsa_sendto()
nsa_sendto() is a wrapper around the sendto() call, using NEAT socket descriptors instead. Note: this function is provided as legacy wrapper, and it is RECOMMENDED to use nsa_send() instead. On NEAT sockets, a provided destination address is ignored.
Function Prototype:

ssize_t nsa_sendto(int sockfd, const void* buf, size_t len,
                   int flags,
                   const struct sockaddr* to, socklen_t tolen)
Arguments:
sockfd:
NEAT socket descriptor.
buf:
Data to send.
len:
Length of data to send.
flags:
Optional flags (0, if there are none).
to:
Address to send data to (ignored for NEAT sockets).
tolen:
Length of address to send data to (ignored for NEAT sockets).
nsa_sendto() returns the number of sent bytes in case of success, or -1 in case of error. The error code will be set in the errno variable.
See the send() documentation for details.
nsa_sendmsg()
nsa_sendmsg() sends data over a given connected NEAT socket. The data and control information is provided by a msghdr structure. On NEAT sockets, a provided destination address is ignored.
Function Prototype:

ssize_t nsa_sendmsg(int sockfd, const struct msghdr* msg, int flags)
Arguments:
sockfd:
NEAT socket descriptor.
msg:
Data to send and corresponding control information as msghdr structure.
flags:
Optional flags (0, if there are none).
nsa_sendmsg() returns the number of sent bytes in case of success, or -1 in case of error. The error code will be set in the errno variable.
See the sendmsg() documentation for details.
nsa_sendv()
nsa_sendv() sends data over a given connected NEAT socket. The data and control information is provided by iovec and info structures. On NEAT sockets, a provided destination address is ignored.
Function Prototype:

ssize_t nsa_sendv(int sockfd, struct iovec* iov, int iovcnt,
                  struct sockaddr* to, int tocnt,
                  void* info, socklen_t infolen,
                  unsigned int infotype, int flags)
Arguments:
sockfd:
NEAT socket descriptor.
iov:
Data to send provided as iovec structures.
iovcnt:
Number of provided iovec structures.
to:
Address(es) to send data to (ignored for NEAT sockets).
tocnt:
Number of of addresses to send data to (ignored for NEAT sockets).
info:
Control information.
infolen:
Length of control information.
infotype:
Type of control information.
flags:
Optional flags (0, if there are none).
nsa_sendv() returns the number of sent bytes in case of success, or -1 in case of error. The error code will be set in the errno variable.
See the sctp_sendv() documentation for details.
nsa_read()
nsa_read() reads data from a given connected NEAT socket. For NEAT sockets, nsa_read() is equal to nsa_recv() with "flags" set to 0.
Function Prototype:

ssize_t nsa_read(int fd, void* buf, size_t len)
Arguments:
fd:
NEAT socket descriptor.
buf:
Buffer to store read data to.
len:
Length of the storage buffer.
nsa_read() returns the number of read bytes in case of success, 0 in case of connection shutdown, or -1 in case of error. The error code will be set in the errno variable.
See the read() documentation for details.
nsa_readv()
nsa_readv() reads data from a given connected NEAT socket. The data information buffers are provided by an iovec structure.
Function Prototype:

ssize_t nsa_readv(int fd, const struct iovec* iov, int iovcnt)
Arguments:
fd:
NEAT socket descriptor.
iov:
Data to send provided as iovec structures.
iovcnt:
Number of provided iovec structures.
nsa_readv() returns the number of read bytes in case of success, 0 in case of connection shutdown, or -1 in case of error. The error code will be set in the errno variable.
See the readv() documentation for details.
nsa_pread()
nsa_pread() is a wrapper around the pread() call, using a NEAT socket descriptor instead.
Function Prototype:

ssize_t nsa_pread(int fd, void* buf, size_t len, off_t offset)
See the pread() documentation for details.
nsa_pread64()
nsa_pread64() is a wrapper around the pread64() call, using a NEAT socket descriptor instead.
Function Prototype:

ssize_t nsa_pread(int fd, void* buf, size_t len, off_t offset)
See the pread64() documentation for details.
nsa_preadv()
nsa_preadv() is a wrapper around the preadv() call, using a NEAT socket descriptor instead.
Function Prototype:

ssize_t nsa_preadv(int fd, const struct iovec* iov, int iovcnt,
                   off64_t offset)
See the preadv() documentation for details.
nsa_preadv64()
nsa_preadv64() is a wrapper around the preadv64() call, using a NEAT socket descriptor instead.
Function Prototype:

ssize_t nsa_preadv(int fd, const struct iovec* iov, int iovcnt,
                   off64_t offset)
See the preadv64() documentation for details.
nsa_recv()
nsa_recv() reads data from a given connected NEAT socket.
Function Prototype:

ssize_t nsa_recv(int sockfd, void* buf, size_t len, int flags)
Arguments:
sockfd:
NEAT socket descriptor.
buf:
Buffer to store read data to.
len:
Length of the storage buffer.
flags:
Optional flags (0, if there are none).
nsa_recv() returns the number of read bytes in case of success, 0 in case of connection shutdown, or -1 in case of error. The error code will be set in the errno variable.
See the recv() documentation for details.
nsa_recvfrom()
nsa_recvfrom() reads data from a given connected NEAT socket. The peer's sending address of the data (if possible and useful for underlying transport protocol) is obtained as well. Note: this function is provided as legacy wrapper, and it is RECOMMENDED to use nsa_recv() instead.
Function Prototype:

ssize_t nsa_recvfrom(int sockfd, void* buf, size_t len, int flags,
                     struct sockaddr* from, socklen_t* fromlen)
sockfd:
NEAT socket descriptor.
buf:
Buffer to store read data to.
len:
Length of the storage buffer.
flags:
Optional flags (0, if there are none).
from:
Pointer to storage space to store the peer's primary address to (or NULL, if address is not needed).
fromlen:
Pointer to variable with size of the storage in "from" (or NULL, if address is not needed).
nsa_recvfrom() returns the number of read bytes in case of success, 0 in case of connection shutdown, or -1 in case of error. The error code will be set in the errno variable. In case of success, the peer's sending address (if possible and useful for underlying transport protocol) may be stored in "from", if there is sufficient space. The variable pointer to by "fromlen" will then contain the actual address size.
See the recvfrom() documentation for details.
nsa_recvmsg()
nsa_recvmsg() reads data from a given connected NEAT socket. The data and control information buffers are provided by a msghdr structure.
Function Prototype:

ssize_t nsa_recvmsg(int sockfd, struct msghdr* msg, int flags)
Arguments:
sockfd:
NEAT socket descriptor.
msg:
Data to send and corresponding control information as msghdr structure.
flags:
Optional flags (0, if there are none).
nsa_recvmsg() returns the number of read bytes in case of success, 0 in case of connection shutdown, or -1 in case of error. The error code will be set in the errno variable.
See the recvmsg() documentation for details.
nsa_recvv()
nsa_recvv() reads data from a given connected NEAT socket. The data and control information buffers are provided by iovec and info structures.
Function Prototype:

ssize_t nsa_recvv(int sockfd, struct iovec* iov, int iovcnt,
                  struct sockaddr* from, socklen_t* fromlen,
                  void* info, socklen_t* infolen,
                  unsigned int* infotype, int* msg_flags)
Arguments:
sockfd:
NEAT socket descriptor.
iov:
Data to send provided as iovec structures.
iovcnt:
Number of provided iovec structures.
from:
Pointer to storage space to store the peer's primary address to (or NULL, if address is not needed).
fromlen:
Pointer to variable with size of the storage in "from" (or NULL, if address is not needed).
info:
Pointer to storage space for control information.
infolen:
Pointer to variable with length of control information.
infotype:
Pointer to variable for storing the control information type to.
flags:
Pointer to variable with optional flags.
nsa_recvv() returns the number of sent received in case of success, or -1 in case of error. The error code will be set in the errno variable.
See the sctp_recvv() documentation for details.
Poll and Select
nsa_poll()
nsa_poll() waits for activity (input/output/error/...) on a set of given NEAT sockets.
Function Prototype:

int nsa_poll(struct pollfd* ufds, const nfds_t nfds, int timeout)
Arguments:
ufds:
NEAT socket descriptor and requested activity for each NEAT socket.
nfds:
Number of sockets given by "ufds".
timeout:
Timeout in milliseconds.
nsa_poll() returns the number of NEAT sockets with activity in case of success, 0 in case of timeout, or -1 in case of error. The error code will be set in the errno variable.
See the poll() documentation for details.
nsa_select()
nsa_select() is a wrapper around the select() call, using NEAT socket descriptors instead. Note: this function is provided as legacy wrapper, and it is RECOMMENDED to use nsa_poll() instead.
Function Prototype:

int nsa_select(int n,
               fd_set* readfds, fd_set* writefds, fd_set* exceptfds,
               struct timeval* timeout)
See the select() documentation for details.
Address Handling
nsa_getsockname()
nsa_getsockname() obtains the first local address of a socket. Note: this function is provided as legacy wrapper, and it is RECOMMENDED to use nsa_getladdrs() instead to support multi-homed transport protocols!
Function Prototype:

int nsa_getsockname(int sockfd,
                    struct sockaddr* name, socklen_t* namelen)
Arguments:
sockfd:
NEAT socket descriptor.
name:
Storage space for the address.
namelen:
Pointer to variable with the storage space's size.
Return Value:
nsa_getsockname() returns 0 in case of success (with the actual address size stored into the "namelen" variable), or -1 in case of error. The error code will be set in the errno variable.
See the getsockname() documentation for details.
nsa_getpeername()
nsa_getpeername() obtains the first remote address of a connected socket. Note: this function is provided as legacy wrapper, and it is RECOMMENDED to use nsa_getpaddrs() instead to support multi-homed transport protocols!
Function Prototype:

int nsa_getpeername(int sockfd,
                    struct sockaddr* name, socklen_t* namelen)
Arguments:
sockfd:
NEAT socket descriptor.
name:
Storage space for the address.
namelen:
Pointer to variable with the storage space's size.
Return Value:
nsa_getpeername() returns 0 in case of success (with the actual address size stored into the "namelen" variable), or -1 in case of error. The error code will be set in the errno variable.
See the getpeername() documentation for details.
nsa_getladdrs()
nsa_getladdrs() obtains the local addresses of a socket. The storage space for the addresses will be automatically allocated and needs to be freed by nsa_freeladdrs().
Function Prototype:

int nsa_getladdrs(int sockfd, neat_assoc_t id,
                  struct sockaddr** addrs)
Arguments:
sockfd:
NEAT socket descriptor.
id:
Association identifier (0 in case of 1:1-style sockets).
addrs:
Pointer to variable to store pointer to addresses to.
nsa_getladdrs() returns the number of addresses stored into a newly allocated space. The pointer to this space is stored into the variable provided by "addrs". In case of error, -1 is returned, and the error code will be set in the errno variable.
nsa_freeladdrs()
nsa_freeladdrs() frees addresses obtained by nsa_getladdrs().
Function Prototype:

void nsa_freeladdrs(struct sockaddr* addrs)
Arguments:
addrs:
Pointer to addresses to be freed.
nsa_getpaddrs()
nsa_getpaddrs() obtains the remote addresses of a connected socket. The storage space for the addresses will be automatically allocated and needs to be freed by nsa_freepaddrs().
Function Prototype:

int nsa_getpaddrs(int sockfd, neat_assoc_t id,
                  struct sockaddr** addrs)
Arguments:
sockfd:
NEAT socket descriptor.
id:
Association identifier (0 in case of 1:1-style sockets).
addrs:
Pointer to variable to store pointer to addresses to.
nsa_getpaddrs() returns the number of addresses stored into a newly allocated space. The pointer to this space is stored into the variable provided by "addrs". In case of error, -1 is returned, and the error code will be set in the errno variable.
nsa_freepaddrs()
nsa_freepaddrs() frees addresses obtained by nsa_getpaddrs().
Function Prototype:

void nsa_freepaddrs(struct sockaddr* addrs)
Arguments:
addrs:
Pointer to addresses to be freed.
Miscellaneous
This section contains miscellaneous wrapper functions, mostly around file I/O. Since Unix file descriptors are used together with socket descriptors in functions like poll(), select(), etc., it is necessary to wrap functions handling file descriptors as well.
nsa_open()
nsa_open() is a wrapper around the open() call, returning a NEAT socket descriptor instead.
Function Prototype:

int nsa_open(const char* pathname, int flags, mode_t mode)
See the open() documentation for details.
nsa_creat()
nsa_creat() is a wrapper around the creat() call, returning a NEAT socket descriptor instead.
Function Prototype:

int nsa_creat(const char* pathname, mode_t mode)
See the creat() documentation for details.
nsa_lockf()
nsa_lockf() is a wrapper around the lockf() call, using a NEAT socket descriptor instead.
Function Prototype:

int nsa_lockf(int fd, int cmd, off_t len)
See the lockf() documentation for details.
nsa_lockf64()
nsa_lockf64() is a wrapper around the lockf64() call, using a NEAT socket descriptor instead.
Function Prototype:

int nsa_lockf(int fd, int cmd, off64_t len)
See the lockf64() documentation for details.
nsa_flock()
nsa_flock() is a wrapper around the flock() call, using a NEAT socket descriptor instead.
Function Prototype:

int nsa_flock(int fd, int operation)
See the flock() documentation for details.
nsa_fstat()
nsa_fstat() is a wrapper around the fstat() call, using a NEAT socket descriptor instead.
Function Prototype:

int nsa_fstat(int fd, struct stat* buf)
See the fstat() documentation for details.
nsa_fpathconf()
nsa_fpathconf() is a wrapper around the fpathconf() call, using a NEAT socket descriptor instead.
Function Prototype:

long nsa_fpathconf(int fd, int name)
See the fpathconf() documentation for details.
nsa_fchown()
nsa_fchown() is a wrapper around the fchown() call, using a NEAT socket descriptor instead.
Function Prototype:

int nsa_fchown(int fd, uid_t owner, gid_t group)
See the fchown() documentation for details.
nsa_fsync()
nsa_fsync() is a wrapper around the fsync() call, using a NEAT socket descriptor instead.
Function Prototype:

int nsa_fsync(int fd)
See the fsync() documentation for details.
nsa_fdatasync()
nsa_fdatasync() is a wrapper around the fdatasync() call, using a NEAT socket descriptor instead.
Function Prototype:

int nsa_fdatasync(int fd)
See the fdatasync() documentation for details.
nsa_syncfs()
nsa_syncfs() is a wrapper around the syncfs() call, using a NEAT socket descriptor instead.
Function Prototype:

int nsa_syncfs(int fd)
See the syncfs() documentation for details.
nsa_dup2()
nsa_dup2() is a wrapper around the dup2() call, using a NEAT socket descriptor instead.
Function Prototype:

int nsa_dup2(int oldfd, int newfd)
See the dup2() documentation for details.
nsa_dup3()
nsa_dup3() is a wrapper around the dup3() call, using a NEAT socket descriptor instead.
Function Prototype:

int nsa_dup3(int oldfd, int newfd, int flags)
See the dup3() documentation for details.
nsa_dup()
nsa_dup() is a wrapper around the dup() call, using a NEAT socket descriptor instead.
Function Prototype:

int nsa_dup(int oldfd)
See the dup() documentation for details.
nsa_lseek()
nsa_lseek() is a wrapper around the lseek() call, using a NEAT socket descriptor instead.
Function Prototype:

off_t nsa_lseek(int fd, off_t offset, int whence)
See the lseek() documentation for details.
nsa_lseek64()
nsa_lseek64() is a wrapper around the lseek64() call, using a NEAT socket descriptor instead.
Function Prototype:

off_t nsa_lseek(int fd, off64_t offset, int whence)
See the lseek64() documentation for details.
nsa_truncate()
nsa_truncate() is a wrapper around the truncate() call, using a NEAT socket descriptor instead.
Function Prototype:

int nsa_ftruncate(int fd, off_t length)
See the truncate() documentation for details.
nsa_truncate64()
nsa_truncate64() is a wrapper around the truncate64() call, using a NEAT socket descriptor instead.
Function Prototype:

int nsa_ftruncate(int fd, off64_t length)
See the truncate64() documentation for details.
nsa_pipe()
nsa_pipe() is a wrapper around the pipe() call, returning NEAT socket descriptors instead.
Function Prototype:

int nsa_pipe(int fds[2])
See the pipe() documentation for details.
nsa_ioctl()
nsa_ioctl() is a wrapper around the ioctl() call, using a NEAT socket descriptor instead.
Function Prototype:

int nsa_ioctl(int fd, int request, const void* argp)
See the ioctl() documentation for details.
Code Examples
Running code examples can be found in the NEAT Git repository, with some tutorial material in [Haikou2017-2-NEAT-Tutorial], [Haikou2017-NEAT]:
URL: https://github.com/NEAT-project/neat
Branch: dreibh/neat-socketapi
Directory: socketapi/examples/
Testbed Platform
A large-scale and realistic Internet testbed platform with support for the multi-homing feature of the underlying SCTP and MPTCP protocols is NorNet. A description of NorNet is provided in [LinuxCon2016], [ComNets2013-Core], some further information can be found on the project website [NorNet-Website].
Security Considerations
Security considerations for the SCTP sockets API are described in [RFC6458].
IANA Considerations
This document does not require IANA actions.
Acknowledgments
This work was partially funded by the European Union's Horizon 2020 research and innovation programme under grant agreement No. 644334 (NEAT). The views expressed are solely those of the author(s).
The author would like to thank David Ros, Michael Welzl, and Xing Zhou for their support.
References
Normative References
[RFC2119]

Key words for use in RFCs to Indicate Requirement Levels
S. Bradner
March 1997
BCP 14
RFC 2119
DOI 10.17487/RFC2119
[RFC6458]

Sockets API Extensions for the Stream Control Transmission Protocol (SCTP)
R. Stewart
M. Tuexen
K. Poon
P. Lei
V. Yasevich
December 2011
RFC 6458
DOI 10.17487/RFC6458
[I-D.gjessing-taps-minset]

A Minimal Set of Transport Services for TAPS Systems
Stein Gjessing
University of Oslo
Michael Welzl
University of Oslo
20 June 2017
Internet-Draft draft-gjessing-taps-minset-05
[I-D.fairhurst-taps-neat]

The NEAT Interface to Transport Services
Gorry Fairhurst
30 October 2017
Internet-Draft draft-fairhurst-taps-neat-00
[I-D.ietf-taps-transports-usage]

On the Usage of Transport Features Provided by IETF Transport Protocols
Michael Welzl
University of Oslo
Michael Tuexen
Muenster University of Applied Sciences
Naeem Khademi
University of Oslo
26 October 2017
Internet-Draft draft-ietf-taps-transports-usage-09
Informative References
[LinuxCon2016]

NorNet – Building an Inter-Continental Internet Testbed based on Open Source Software
ThomasDreibholz
5 October 2016
Proceedings of the LinuxCon Europe
[ComNets2013-Core]

NorNet Core – A Multi-Homed Research Testbed
Ernst GunnarGran
ThomasDreibholz
AmundKvalbein
14 March 2014
Computer Networks, Special Issue on Future Internet Testbeds Volume 61, Pages 75-87, ISSN1389-1286, DOI10.1016/j.bjp.2013.12.035
[NEAT-Website]

NEAT – A New, Evolutive API and Transport-Layer Architecture for the Internet
Thomas Dreibholz
2022
[NorNet-Website]

NorNet – A Real-World, Large-Scale Multi-Homing Testbed
Thomas Dreibholz
2022
[Haikou2017-2-NEAT-Tutorial]

NEAT Tutorial at Hainan University: Getting Started with NEAT
ThomasDreibholz
18 December 2017
Invited Talk at Hainan University, College of Information Science and Technology(CIST)
[Haikou2017-NEAT]

A Practical Introduction to NEAT at Hainan University
ThomasDreibholz
17 April 2017
Invited Talk at Hainan University, College of Information Science and Technology(CIST)
[ANRW2017]

A NEAT Way to Browse the Web
FelixWeinrank
Karl-JohanGrinnemo
ZdravkoBozakov
AnnaBrunström
ThomasDreibholz
PerHurtig
NaeemKhademi
MichaelTüxen
15 July 2017
Proceedings of the ACM, IRTF and ISOC Applied Networking Research Workshop(ANRW) Pages 33-34, ISBN978-1-4503-5108-9, DOI10.1145/3106328.3106335
[NEAT-D1.1]

NEAT Architecture
GorryFairhurst
TomJones
ZdravkoBozakov
AnnaBrunström
DraganaDamjanović
Kristian Riktor Evensen ToerlessEckert
Karl-JohanGrinnemo
Audun FosselieHansen
NaeemKhademi
SimoneMangiante
PatrickMcManus
GiorgosPapastergiou
DavidRos
MichaelTüxen
EricVyncke
MichaelWelzl
1 December 2015
Number D1.1
[NEAT-D1.3]

Final Version of Services and APIs
MichaelWelzl
DraganaDamjanović
GorryFairhurst
DavidHayes
TomJones
DavidRos
MichaelTüxen
FelixWeinrank
30 October 2017
Deliverable D1.3
[NEAT-D2.2]

NEAT – Core Transport System, with both Low-level and High-level Components
NaeemKhademi
ZdravkoBozakov
AnnaBrunström
ØysteinDale
DraganaDamjanović
Kristian RiktorEvensen
GorryFairhurst
Karl-JohanGrinnemo
TomJones
SimoneMangiante
AndreasPetlund
DavidRos
DanielStenberg
MichaelTüxen
FelixWeinrank
MichaelWelzl
14 March 2017
Number D2.2
[NEAT-D2.3]

Final Version of Core Transport System
NaeemKhademi
ZdravkoBozakov
AnnaBrunström
ØysteinDale
DraganaDamjanović
Kristian RiktorEvensen
GorryFairhurst
AndreasFischer
Karl-JohanGrinnemo
TomJones
SimoneMangiante
AndreasPetlund
DavidRos
IreneRüngeler
DanielStenberg
MichaelTüxen
FelixWeinrank
MichaelWelzl
31 August 2017
Deliverable D2.3