TCP sock API

Sock submodule for TCP. More...

Detailed Description

Sock submodule for TCP.

How To Use

First you need to include a module that implements this API in your application's Makefile. For example the implementation for GNRC is called gnrc_sock_tcp.

A Simple TCP Echo Server

#include "net/sock/tcp.h"
#define SOCK_QUEUE_LEN (1U)
sock_tcp_t sock_queue[SOCK_QUEUE_LEN];
uint8_t buf[128];
int main(void)
{
local.port = 12345;
if (sock_tcp_listen(&queue, &local, sock_queue, SOCK_QUEUE_LEN, 0) < 0) {
puts("Error creating listening queue");
return 1;
}
puts("Listening on port 12345");
while (1) {
sock_tcp_t *sock;
if (sock_tcp_accept(&queue, &sock) < 0) {
puts("Error accepting new sock");
}
else {
int read_res = 0;
puts("Reading data");
while (read_res >= 0) {
read_res = sock_tcp_read(sock, &buf, sizeof(buf),
if (read_res < 0) {
puts("Disconnected");
break;
}
else {
int write_res;
printf("Read: \"");
for (int i = 0; i < read_res; i++) {
printf("%c", buf[i]);
}
puts("\"");
if ((write_res = sock_tcp_write(sock, &buf,
read_res)) < 0) {
puts("Errored on write, finished server loop");
break;
}
}
}
}
}
return 0;
}

Above you see a simple TCP echo server. Don't forget to also include the IPv6 module of your networking implementation (e.g. gnrc_ipv6_default for Generic (GNRC) network stack GNRC) and at least one network device.

After including header files for the address families and the TCP `sock`s and `queue`s themselves, we create an array of sock objects sock_queue as our listen queue (for simplicity of length 1 in our example) and some buffer space buf to store the data received by the server:

#include "net/af.h"
#include "net/sock/tcp.h"
#define SOCK_QUEUE_LEN (1U)
sock_tcp_t sock_queue[SOCK_QUEUE_LEN];
uint8_t buf[128];

We want to listen for incoming connections on a specific port, so we set a local end point with that port (12345 in this case).

We then proceed to creating the listen queue queue. Since it is bound to local it waits for incoming connections to port 12345. We don't need any further configuration so we set the flags to 0. In case of an error we stop the program:

local.port = 12345;
if (sock_tcp_listen(&queue, &local, sock_queue, SOCK_QUEUE_LEN, 0) < 0) {
puts("Error creating listening queue");
return 1;
}
puts("Listening on port 12345");

The application then waits indefinitely for an incoming connection with sock_tcp_accept(). If we want to timeout this wait period we could alternatively set the timeout parameter of sock_tcp_accept() to a value != SOCK_NO_TIMEOUT. If an error occurs during that we print an error message but proceed waiting.

while (1) {
sock_tcp_t *sock;
if (sock_tcp_accept(&queue, &sock, SOCK_NO_TIMEOUT) < 0) {
puts("Error accepting new sock");
}
else {

On successful connection establishment with a client we get a connected sock object and we try to read the incoming stream into buf using sock_tcp_read() on that sock. Again, we could use another timeout period than SOCK_NO_TIMEOUT with this function. If we error we break the read loop and disconnect the sock.

int read_res = 0;
puts("Reading data");
while (read_res >= 0) {
read_res = sock_tcp_read(sock, &buf, sizeof(buf),
if (read_res < 0) {
puts("Disconnected");
break;
}
else {
...
}
}

Otherwise, we print the received message and write it back to the connected sock (an again breaking the loop on error).

int write_res;
printf("Read: \"");
for (int i = 0; i < read_res; i++) {
printf("%c", buf[i]);
}
puts("\"");
if ((write_res = sock_tcp_write(sock, &buf,
read_res)) < 0) {
puts("Errored on write, finished server loop");
break;
}

In the case of we somehow manage to break the infinite accepting loop we stop the listening queue appropriately.

A Simple TCP Echo Client

#include "net/af.h"
#include "net/ipv6/addr.h"
#include "net/sock/tcp.h"
uint8_t buf[128];
int main(void)
{
int res;
remote.port = 12345;
"fe80::d8fa:55ff:fedf:4523");
if (sock_tcp_connect(&sock, &remote, 0, 0) < 0) {
puts("Error connecting sock");
return 1;
}
puts("Sending \"Hello!\"");
if ((res = sock_tcp_write(&sock, "Hello!", sizeof("Hello!"))) < 0) {
puts("Errored on write");
}
else {
if ((res = sock_tcp_read(&sock, &buf, sizeof(buf),
SOCK_NO_TIMEOUT)) < 0) {
puts("Disconnected");
}
printf("Read: \"");
for (int i = 0; i < res; i++) {
printf("%c", buf[i]);
}
puts("\"");
}
return res;
}

Above you see a simple TCP echo client. Again: Don't forget to also include the IPv6 module of your networking implementation (e.g. gnrc_ipv6_default for GNRC) and at least one network device. Ad0)ditionally, for the IPv6 address parsing you need the IPv6 address module.

This time instead of creating a listening queue we create a connected sock object directly. To connect it to a port at a host we setup a remote end-point first (with port 12345 and address fe80::d8fa:55ff:fedf:4523 in this case; your IP address may differ of course) and connect to it using sock_tcp_connect(). We neither care about the local port nor additional configuration so we set both the local_port and flags parameter of sock_tcp_connect() to 0:

remote.port = 12345;
"fe80::d8fa:55ff:fedf:4523");
if (sock_tcp_connect(&sock, &remote, 0, 0) < 0) {
puts("Error connecting sock");
return 1;
}

On error we just terminate the program, on success we send a message (Hello!) and again terminate the program on error:

if ((res = sock_tcp_write(&sock, "Hello!", sizeof("Hello!"))) < 0) {
puts("Errored on write");
}

Otherwise, we wait for the reply and print it in case of success (and terminate in case of error):

else {
if ((res = sock_tcp_read(&sock, &buf, sizeof(buf),
SOCK_NO_TIMEOUT)) < 0) {
puts("Disconnected");
}
printf("Read: \"");
for (int i = 0; i < res; i++) {
printf("%c", buf[i]);
}
puts("\"");
}
return res;

Files

file  sock/tcp.h
 TCP sock definitions.
 

Typedefs

typedef struct _sock_tl_ep sock_tcp_ep_t
 An end point for a TCP sock object.
 
typedef struct sock_tcp sock_tcp_t
 Type for a TCP sock object. More...
 
typedef struct sock_tcp_queue sock_tcp_queue_t
 Type for a TCP listening queue. More...
 

Functions

int sock_tcp_connect (sock_tcp_t *sock, const sock_tcp_ep_t *remote, uint16_t local_port, uint16_t flags)
 Establishes a new TCP sock connection. More...
 
int sock_tcp_listen (sock_tcp_queue_t *queue, const sock_tcp_ep_t *local, sock_tcp_t *queue_array, unsigned queue_len, uint16_t flags)
 Listen for an incoming connection request on local end point. More...
 
void sock_tcp_disconnect (sock_tcp_t *sock)
 Disconnects a TCP connection. More...
 
void sock_tcp_stop_listen (sock_tcp_queue_t *queue)
 Stops listening on TCP listening queue. More...
 
int sock_tcp_get_local (sock_tcp_t *sock, sock_tcp_ep_t *ep)
 Gets the local end point of a TCP sock object. More...
 
int sock_tcp_get_remote (sock_tcp_t *sock, sock_tcp_ep_t *ep)
 Gets the remote end point of a TCP sock object. More...
 
int sock_tcp_queue_get_local (sock_tcp_queue_t *queue, sock_tcp_ep_t *ep)
 Gets the local end point of a TCP sock queue object. More...
 
int sock_tcp_accept (sock_tcp_queue_t *queue, sock_tcp_t **sock, uint32_t timeout)
 Receives and handles TCP connection requests from other peers. More...
 
ssize_t sock_tcp_read (sock_tcp_t *sock, void *data, size_t max_len, uint32_t timeout)
 Reads data from an established TCP stream. More...
 
ssize_t sock_tcp_write (sock_tcp_t *sock, const void *data, size_t len)
 Writes data to an established TCP stream. More...
 

Typedef Documentation

◆ sock_tcp_queue_t

typedef struct sock_tcp_queue sock_tcp_queue_t

Type for a TCP listening queue.

Note
API implementors: struct sock_tcp_queue needs to be defined by implementation-specific sock_types.h.

Definition at line 328 of file sock/tcp.h.

◆ sock_tcp_t

typedef struct sock_tcp sock_tcp_t

Type for a TCP sock object.

Note
API implementors: struct sock_tcp needs to be defined by implementation-specific sock_types.h.

Definition at line 320 of file sock/tcp.h.

Function Documentation

◆ sock_tcp_accept()

int sock_tcp_accept ( sock_tcp_queue_t queue,
sock_tcp_t **  sock,
uint32_t  timeout 
)

Receives and handles TCP connection requests from other peers.

Precondition
(queue != NULL) && (sock != NULL)
Parameters
[in]queueA TCP listening queue.
[out]sockA new TCP sock object for the established sock object.
[in]timeoutTimeout for accept in microseconds. If 0 and no data is available, the function returns immediately. May be SOCK_NO_TIMEOUT for no timeout (wait until data is available).
Returns
0 on success.
-EAGAIN, if timeout is 0 and no data is available.
-ECONNABORTED, if the connection to sock has been aborted while in this function
-EINVAL, if queue was not initialized using sock_tcp_listen().
-ENOMEM, if system was not able to allocate sufficient memory to establish connection.
-EPERM, if connections on local end point of queue are not permitted on this system (e.g. by firewall rules).
-ETIMEDOUT, if the operation timed out internally.

◆ sock_tcp_connect()

int sock_tcp_connect ( sock_tcp_t sock,
const sock_tcp_ep_t remote,
uint16_t  local_port,
uint16_t  flags 
)

Establishes a new TCP sock connection.

Precondition
sock != NULL
(remote != NULL) && (remote->port != 0)
Parameters
[out]sockThe resulting sock object.
[in]remoteRemote end point for the sock object.
[in]local_portLocal port for the connection. May be 0. * If local_port == 0 the connection is bound to a random port.
[in]flagsFlags for the sock object. See also net_sock_flags. May be 0.
Returns
0 on success.
-EADDRINUSE, if (flags & SOCK_FLAGS_REUSE_EP) == 0 and local_port is already used elsewhere
-EAFNOSUPPORT, if sock_tcp_ep_t::family of remote is not supported.
-ECONNREFUSED, if no-one is listening on the remote end point.
-EINVAL, if sock_tcp_ep_t::addr of remote is an invalid address.
-EINVAL, if sock_tcp_ep_t::netif of remote is not a valid interface.
-ENETUNREACH, if network defined by remote is not reachable.
-ENOMEM, if system was not able to allocate sufficient memory to establish connection.
-EPERM, if connections to remote are not permitted on the system (e.g. by firewall rules).
-ETIMEDOUT, if the connection attempt to remote timed out.

◆ sock_tcp_disconnect()

void sock_tcp_disconnect ( sock_tcp_t sock)

Disconnects a TCP connection.

Precondition
sock != NULL If we want to timeout this wait period we could alternatively set the timeout parameter of sock_tcp_accept() to a value != SOCK_NO_TIMEOUT.
Parameters
[in]sockA TCP sock object.

◆ sock_tcp_get_local()

int sock_tcp_get_local ( sock_tcp_t sock,
sock_tcp_ep_t ep 
)

Gets the local end point of a TCP sock object.

Precondition
(sock != NULL) && (ep != NULL)
Parameters
[in]sockA TCP sock object.
[out]epThe local end point.
Returns
0 on success.
-EADDRNOTAVAIL, when sock has no local end point.

◆ sock_tcp_get_remote()

int sock_tcp_get_remote ( sock_tcp_t sock,
sock_tcp_ep_t ep 
)

Gets the remote end point of a TCP sock object.

Precondition
(sock != NULL) && (ep != NULL)
Parameters
[in]sockA TCP sock object.
[out]epThe remote end point.
Returns
0 on success.
-ENOTCONN, when sock is not connected to a remote end point.

◆ sock_tcp_listen()

int sock_tcp_listen ( sock_tcp_queue_t queue,
const sock_tcp_ep_t local,
sock_tcp_t queue_array,
unsigned  queue_len,
uint16_t  flags 
)

Listen for an incoming connection request on local end point.

Precondition
queue != NULL
(local != NULL) && (local->port != 0)
(queue_array != NULL) && (queue_len != 0)
Parameters
[in]queueThe resulting listening queue.
[in]localLocal end point to listen on.
[in]queue_arrayArray of sock objects.
[in]queue_lenLength of queue_array.
[in]flagsFlags for the listening queue. See also net_sock_flags. May be 0.
Returns
0 on success.
-EADDRINUSE, if (flags & SOCK_FLAGS_REUSE_EP) == 0 and local is already used elsewhere
-EAFNOSUPPORT, if sock_tcp_ep_t::family of local is not supported.
-EINVAL, if sock_tcp_ep_t::netif of local is not a valid interface.
-ENOMEM, if no memory was available to listen on queue.

◆ sock_tcp_queue_get_local()

int sock_tcp_queue_get_local ( sock_tcp_queue_t queue,
sock_tcp_ep_t ep 
)

Gets the local end point of a TCP sock queue object.

Precondition
(sock != NULL) && (ep != NULL)
Parameters
[in]queueA TCP sock queue object.
[out]epThe local end point.
Returns
0 on success.
-EADDRNOTAVAIL, when queue has no local end point.

◆ sock_tcp_read()

ssize_t sock_tcp_read ( sock_tcp_t sock,
void *  data,
size_t  max_len,
uint32_t  timeout 
)

Reads data from an established TCP stream.

Precondition
(sock != NULL) && (data != NULL) && (max_len > 0)
Parameters
[in]sockA TCP sock object.
[out]dataPointer where the read data should be stored.
[in]max_lenMaximum space available at data. If read data exceeds max_len the data is truncated and the remaining data can be retrieved later on.
[in]timeoutTimeout for receive in microseconds. If 0 and no data is available, the function returns immediately. May be SOCK_NO_TIMEOUT for no timeout (wait until data is available).
Note
Function may block.
Returns
The number of bytes read on success.
0, if no read data is available, but everything is in order.
-EAGAIN, if timeout is 0 and no data is available.
-ECONNABORTED, if the connection is aborted while waiting for the next data.
-ECONNRESET, if the connection was forcibly closed by remote end point of sock.
-ENOTCONN, when sock is not connected to a remote end point.
-ETIMEDOUT, if timeout expired.

◆ sock_tcp_stop_listen()

void sock_tcp_stop_listen ( sock_tcp_queue_t queue)

Stops listening on TCP listening queue.

Precondition
queue != NULL
Parameters
[in]queueA TCP listening queue.

◆ sock_tcp_write()

ssize_t sock_tcp_write ( sock_tcp_t sock,
const void *  data,
size_t  len 
)

Writes data to an established TCP stream.

Precondition
(sock != NULL)
if (len != NULL): (data != NULL)
Parameters
[in]sockA TCP sock object.
[in]dataPointer to the data to be written to the stream.
[in]lenMaximum space available at data.
Note
Function may block.
Returns
The number of bytes written on success.
-ECONNABORTED, if the connection is aborted while waiting for the next data.
-ECONNRESET, if the connection was forcibly closed by remote end point of sock.
-ENOMEM, if no memory was available to written data.
-ENOTCONN, if sock is not connected to a remote end point.