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_tcpneeds 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_queueneeds 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) == 0andlocal_portis already used elsewhere - -EAFNOSUPPORT, if
sock.h::_sock_tl_ep::familyofremoteis not supported. - -ECONNREFUSED, if no-one is listening on the
remoteend point. - -EINVAL, if
sock.h::_sock_tl_ep::addrofremoteis an invalid address. - -EINVAL, if
sock.h::_sock_tl_ep::netifofremoteis not a valid interface. - -ENETUNREACH, if network defined by
remoteis not reachable. - -ENOMEM, if system was not able to allocate sufficient memory to establish connection.
- -EPERM, if connections to
remoteare not permitted on the system (e.g. by firewall rules). - -ETIMEDOUT, if the connection attempt to
remotetimed 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
localend 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) == 0andlocalis already used elsewhere - -EAFNOSUPPORT, if
sock.h::_sock_tl_ep::familyoflocalis not supported. - -EINVAL, if
sock.h::_sock_tl_ep::netifoflocalis 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
sockhas 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
sockis 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
queuehas 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_TIMEOUTfor no timeout (wait until data is available).Return values
- 0 on success.
- -EAGAIN, if
timeoutis0and no data is available. - -ECONNABORTED, if the connection to
sockhas been aborted while in this function - -EINVAL, if
queuewas 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
queueare not permitted on this system (e.g. by firewall rules). - -ETIMEDOUT, if the operation timed out internally.
-
msp430_types.h::ssize_tsock_tcp_read(sock/tcp.h::sock_tcp_t* sock, void * data,msp430_types.h::size_tmax_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_lenthe 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_TIMEOUTfor 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
timeoutis0and 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
sockis not connected to a remote end point. - -ETIMEDOUT, if
timeoutexpired.
-
msp430_types.h::ssize_tsock_tcp_write(sock/tcp.h::sock_tcp_t* sock, const void * data,msp430_types.h::size_tlen)¶ 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
sockis not connected to a remote end point.