TCP sock API¶
Sock submodule for TCP.
How To Use¶
First you need to 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¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | #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)
{
sock_tcp_ep_t local = SOCK_IPV6_EP_ANY;
sock_tcp_queue_t queue;
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),
SOCK_NO_TIMEOUT);
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;
}
}
}
sock_tcp_disconnect(sock);
}
}
sock_tcp_stop_listen(queue);
return 0;
}
|
Above you see a simple TCP echo server. Don’t forget to also 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/tcp.h::sock_tcp_t
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:
1 2 3 4 5 6 7 | #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:
1 2 3 4 5 6 7 8 9 10 | sock_tcp_ep_t local = SOCK_IPV6_EP_ANY;
sock_tcp_queue_t queue;
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.h::sock_tcp_accept()
to a value != sock.h::SOCK_NO_TIMEOUT
. If an error occurs during that we print an error message but proceed waiting.
1 2 3 4 5 6 7 | 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.h::SOCK_NO_TIMEOUT
with this function. If we error we break the read loop and disconnect the sock
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | int read_res = 0;
puts("Reading data");
while (read_res >= 0) {
read_res = sock_tcp_read(sock, &buf, sizeof(buf),
SOCK_NO_TIMEOUT);
if (read_res < 0) {
puts("Disconnected");
break;
}
else {
...
}
}
sock_tcp_disconnect(sock);
|
Otherwise, we print the received message and write it back to the connected sock
(an again breaking the loop on error).
1 2 3 4 5 6 7 8 9 10 11 | 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.
1 | sock_tcp_stop_listen(queue);
|
A Simple TCP Echo Client¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | #include "net/af.h"
#include "net/ipv6/addr.h"
#include "net/sock/tcp.h"
uint8_t buf[128];
sock_tcp_t sock;
int main(void)
{
int res;
sock_tcp_ep_t remote = SOCK_IPV6_EP_ANY;
remote.port = 12345;
ipv6_addr_from_str((ipv6_addr_t *)&remote.addr,
"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("\"");
}
sock_tcp_disconnect(&sock);
return res;
}
|
Above you see a simple TCP echo client. Again: Don’t forget to also 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
:
1 2 3 4 5 6 7 8 9 | sock_tcp_ep_t remote = SOCK_IPV6_EP_ANY;
remote.port = 12345;
ipv6_addr_from_str((ipv6_addr_t *)&remote.addr,
"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:
1 2 3 | 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):
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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("\"");
}
sock_tcp_disconnect(&sock);
return res;
|
A Simple TCP Echo Server¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | #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)
{
sock_tcp_ep_t local = SOCK_IPV6_EP_ANY;
sock_tcp_queue_t queue;
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),
SOCK_NO_TIMEOUT);
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;
}
}
}
sock_tcp_disconnect(sock);
}
}
sock_tcp_stop_listen(queue);
return 0;
}
|
Above you see a simple TCP echo server. Don’t forget to also 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/tcp.h::sock_tcp_t
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:
1 2 3 4 5 6 7 | #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:
1 2 3 4 5 6 7 8 9 10 | sock_tcp_ep_t local = SOCK_IPV6_EP_ANY;
sock_tcp_queue_t queue;
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.h::sock_tcp_accept()
to a value != sock.h::SOCK_NO_TIMEOUT
. If an error occurs during that we print an error message but proceed waiting.
1 2 3 4 5 6 7 | 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.h::SOCK_NO_TIMEOUT
with this function. If we error we break the read loop and disconnect the sock
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | int read_res = 0;
puts("Reading data");
while (read_res >= 0) {
read_res = sock_tcp_read(sock, &buf, sizeof(buf),
SOCK_NO_TIMEOUT);
if (read_res < 0) {
puts("Disconnected");
break;
}
else {
...
}
}
sock_tcp_disconnect(sock);
|
Otherwise, we print the received message and write it back to the connected sock
(an again breaking the loop on error).
1 2 3 4 5 6 7 8 9 10 11 | 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.
1 | sock_tcp_stop_listen(queue);
|
A Simple TCP Echo Client¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | #include "net/af.h"
#include "net/ipv6/addr.h"
#include "net/sock/tcp.h"
uint8_t buf[128];
sock_tcp_t sock;
int main(void)
{
int res;
sock_tcp_ep_t remote = SOCK_IPV6_EP_ANY;
remote.port = 12345;
ipv6_addr_from_str((ipv6_addr_t *)&remote.addr,
"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("\"");
}
sock_tcp_disconnect(&sock);
return res;
}
|
Above you see a simple TCP echo client. Again: Don’t forget to also 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
:
1 2 3 4 5 6 7 8 9 | sock_tcp_ep_t remote = SOCK_IPV6_EP_ANY;
remote.port = 12345;
ipv6_addr_from_str((ipv6_addr_t *)&remote.addr,
"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:
1 2 3 | 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):
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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("\"");
}
sock_tcp_disconnect(&sock);
return res;
|
-
struct _sock_tl_ep
sock_tcp_ep_t
¶ An end point for a TCP sock object.
-
struct sock_tcp
sock_tcp_t
¶ Type for a TCP sock object.
Note
API implementors:
struct sock_tcp
needs to be defined by implementation-specificsock_types.h
.
-
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-specificsock_types.h
.
-
int
sock_tcp_connect
(sock/tcp.h::sock_tcp_t
* sock, constsock/tcp.h::sock_tcp_ep_t
* remote, uint16_t local_port, uint16_t flags)¶ Establishes a new TCP sock connection.
Parameters
Return values
- 0 on success.
- -EADDRINUSE, if
(flags & SOCK_FLAGS_REUSE_EP) == 0
andlocal_port
is already used elsewhere - -EAFNOSUPPORT, if
sock.h::_sock_tl_ep::family
ofremote
is not supported. - -ECONNREFUSED, if no-one is listening on the
remote
end point. - -EINVAL, if
sock.h::_sock_tl_ep::addr
ofremote
is an invalid address. - -EINVAL, if
sock.h::_sock_tl_ep::netif
ofremote
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.
-
int
sock_tcp_listen
(sock/tcp.h::sock_tcp_queue_t
* queue, constsock/tcp.h::sock_tcp_ep_t
* local,sock/tcp.h::sock_tcp_t
* queue_array, unsigned queue_len, uint16_t flags)¶ Listen for an incoming connection request on
local
end point.Parameters
queue: The resulting listening queue. local: Local end point to listen on. queue_array: Array of sock objects. queue_len: Length of queue_array
.flags: Flags for the listening queue. See also . May be 0. Return values
- 0 on success.
- -EADDRINUSE, if
(flags & SOCK_FLAGS_REUSE_EP) == 0
andlocal
is already used elsewhere - -EAFNOSUPPORT, if
sock.h::_sock_tl_ep::family
oflocal
is not supported. - -EINVAL, if
sock.h::_sock_tl_ep::netif
oflocal
is not a valid interface. - -ENOMEM, if no memory was available to listen on
queue
.
-
void
sock_tcp_disconnect
(sock/tcp.h::sock_tcp_t
* sock)¶ Disconnects a TCP connection.
Parameters
sock: A TCP sock object.
-
void
sock_tcp_stop_listen
(sock/tcp.h::sock_tcp_queue_t
* queue)¶ Stops listening on TCP listening queue.
Parameters
queue: A TCP listening queue.
-
int
sock_tcp_get_local
(sock/tcp.h::sock_tcp_t
* sock,sock/tcp.h::sock_tcp_ep_t
* ep)¶ Gets the local end point of a TCP sock object.
Parameters
sock: A TCP sock object. ep: The local end point. Return values
- 0 on success.
- -EADDRNOTAVAIL, when
sock
has no local end point.
-
int
sock_tcp_get_remote
(sock/tcp.h::sock_tcp_t
* sock,sock/tcp.h::sock_tcp_ep_t
* ep)¶ Gets the remote end point of a TCP sock object.
Parameters
sock: A TCP sock object. ep: The remote end point. Return values
- 0 on success.
- -ENOTCONN, when
sock
is not connected to a remote end point.
-
int
sock_tcp_queue_get_local
(sock/tcp.h::sock_tcp_queue_t
* queue,sock/tcp.h::sock_tcp_ep_t
* ep)¶ Gets the local end point of a TCP sock queue object.
Parameters
queue: A TCP sock queue object. ep: The local end point. Return values
- 0 on success.
- -EADDRNOTAVAIL, when
queue
has no local end point.
-
int
sock_tcp_accept
(sock/tcp.h::sock_tcp_queue_t
* queue,sock/tcp.h::sock_tcp_t
** sock, uint32_t timeout)¶ Receives and handles TCP connection requests from other peers.
Parameters
queue: A TCP listening queue. sock: A new TCP sock object for the established sock object. timeout: Timeout for accept in microseconds. If 0 and no data is available, the function returns immediately. May be sock.h::SOCK_NO_TIMEOUT
for no timeout (wait until data is available).Return values
- 0 on success.
- -EAGAIN, if
timeout
is0
and no data is available. - -ECONNABORTED, if the connection to
sock
has been aborted while in this function - -EINVAL, if
queue
was not initialized usingsock/tcp.h::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.
-
msp430_types.h::ssize_t
sock_tcp_read
(sock/tcp.h::sock_tcp_t
* sock, void * data,msp430_types.h::size_t
max_len, uint32_t timeout)¶ Reads data from an established TCP stream.
Parameters
sock: A TCP sock object. data: Pointer where the read data should be stored. max_len: Maximum space available at data
. If read data exceedsmax_len
the data is truncated and the remaining data can be retrieved later on.timeout: Timeout for receive in microseconds. If 0 and no data is available, the function returns immediately. May be sock.h::SOCK_NO_TIMEOUT
for no timeout (wait until data is available).Note
Function may block.
Return values
- The number of bytes read on success.
- 0, if no read data is available, but everything is in order.
- -EAGAIN, if
timeout
is0
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.
-
msp430_types.h::ssize_t
sock_tcp_write
(sock/tcp.h::sock_tcp_t
* sock, const void * data,msp430_types.h::size_t
len)¶ Writes data to an established TCP stream.
Parameters
sock: A TCP sock object. data: Pointer to the data to be written to the stream. len: Maximum space available at data
.Note
Function may block.
Return values
- 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.