Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

posix: initial import of select() function (only support sockets for now) #12975

Merged
merged 6 commits into from
Jul 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,15 @@ ifneq (,$(filter newlib,$(USEMODULE)))
endif
endif

ifneq (,$(filter posix_select,$(USEMODULE)))
ifneq (,$(filter posix_sockets,$(USEMODULE)))
USEMODULE += sock_async
endif
USEMODULE += core_thread_flags
USEMODULE += posix_headers
USEMODULE += xtimer
endif

ifneq (,$(filter posix_sockets,$(USEMODULE)))
USEMODULE += bitfield
USEMODULE += random
Expand Down
32 changes: 32 additions & 0 deletions examples/posix_select/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# name of your application
APPLICATION = posix_sockets_example

# If no BOARD is found in the environment, use this default:
BOARD ?= native

# This has to be the absolute path to the RIOT base directory:
RIOTBASE ?= $(CURDIR)/../..

# Include packages that pull up and auto-init the link layer.
# NOTE: 6LoWPAN will be included if IEEE802.15.4 devices are present
USEMODULE += gnrc_netdev_default
USEMODULE += auto_init_gnrc_netif
# Specify the mandatory networking modules for socket communication via UDP
USEMODULE += gnrc_ipv6_default
# Add stack-specific implementations of sock modules
USEMODULE += gnrc_sock_async
USEMODULE += gnrc_sock_udp
# Add POSIX modules
USEMODULE += posix_select
USEMODULE += posix_sockets
USEMODULE += posix_inet

# Comment this out to disable code in RIOT that does safety checking
# which is not needed in a production environment but helps in the
# development process:
DEVELHELP ?= 1

# Change this to 0 show compiler invocation lines by default:
QUIET ?= 1

include $(RIOTBASE)/Makefile.include
27 changes: 27 additions & 0 deletions examples/posix_select/Makefile.ci
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
BOARD_INSUFFICIENT_MEMORY := \
arduino-duemilanove \
arduino-leonardo \
arduino-mega2560 \
arduino-nano \
arduino-uno \
atmega328p \
chronos \
i-nucleo-lrwan1 \
msb-430 \
msb-430h \
nucleo-f030r8 \
nucleo-f031k6 \
nucleo-f042k6 \
nucleo-f303k8 \
nucleo-f334r8 \
nucleo-l031k6 \
nucleo-l053r8 \
stm32f030f4-demo \
stm32f0discovery \
stm32l0538-disco \
telosb \
waspmote-pro \
wsn430-v1_3b \
wsn430-v1_4 \
z1 \
#
83 changes: 83 additions & 0 deletions examples/posix_select/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
examples/posix_sockets
======================
This application is a showcase for RIOT's POSIX select support. To
keep things simple this application has only one-hop support and
no routing capabilities.

Usage
=====

Build, flash and start the application:
```sh
export BOARD=your_board
make
make flash
make term
```

The `term` make target starts a terminal emulator for your board. It
connects to a default port so you can interact with the shell, usually
that is `/dev/ttyUSB0`. If your port is named differently, the
`PORT=/dev/yourport` (not to be confused with the UDP port) variable can
be used to override this.


Example output
==============

The application starts 4 UDP servers on a selection of different ports that wait
for input simultaneously:
```
2019-12-17 16:36:45,559 # RIOT select example application
2019-12-17 16:36:45,561 # Started UDP server at [fe80::14ac:fb65:106b:1115]:1350
2019-12-17 16:36:45,562 # Started UDP server at [fe80::14ac:fb65:106b:1115]:4973
2019-12-17 16:36:45,562 # Started UDP server at [fe80::14ac:fb65:106b:1115]:6717
2019-12-17 16:36:45,562 # Started UDP server at [fe80::14ac:fb65:106b:1115]:9673
```

If you do not see any output you might need to reset the node. Either, by
pressing the hardware reset button on the board or by running
```sh
make reset
```

There is no shell in this application. You can use the [`posix_sockets` example]
from another board to send a packet to the node:

```
> udp send fe80::14ac:fb65:106b:1115 6717 "Hello World!"
2019-12-17 16:47:01,789 # udp send fe80::14ac:fb65:106b:1115%6 6717 "Hello World!"
2019-12-17 16:47:01,795 # Success: send 12 byte to fe80::14ac:fb65:106b:1115:6717
```

On the board with the `posix_select` example you will see then something like
this:

```
2019-12-17 16:47:01,796 # Received data from [fe80::589d:9386:2208:6579]:192:
2019-12-17 16:47:01,796 # Hello World!
```

Alternatively, with `native` or if your host also can connect to the board, you
can also use [`netcat`][netcat] to send multiple packets simultaneously. E.g.
when the node is connected to the host via the interface `tapbr0`:

```sh
echo -ne "Hello World!" | nc -6u "fe80::78b9:ecff:fe96:8279%tapbr0" 4973 & \
echo -ne "Hello Space!" | nc -6u "fe80::78b9:ecff:fe96:8279%tapbr0" 1350
killall nc
```

This is what the `native` node will then show:

```
Received data from [fe80::3ccc:8dff:fe9f:9991]:14279:
Hello World!

Received data from [fe80::3ccc:8dff:fe9f:9991]:58817:
Hello Space!

```

[`posix_sockets` example]: ../posix_sockets
[netcat]: https://www.unix.com/man-page/Linux/1/netcat/
141 changes: 141 additions & 0 deletions examples/posix_select/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
* Copyright (C) 2019 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @ingroup examples
* @{
*
* @file
* @brief Example application for demonstrating the RIOT's POSIX select()
* implementation
*
* @author Martine Lenders <[email protected]>
*
* @}
*/

#include <stdbool.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <unistd.h>

#include "od.h"
#include "net/gnrc/netif.h"
#include "thread.h"

#define SERVER_BUFFER_SIZE (128U)
#define SERVER_PORTS { 1350U, 4973U, 6717U, 9673U }
#define SERVER_SOCKETS_NUM (4U)

static char server_buffer[SERVER_BUFFER_SIZE];
static char addr_str[IPV6_ADDR_MAX_STR_LEN];

static int _run_server(void *local_addr)
{
struct sockaddr_in6 server_addr = { .sin6_family = AF_INET6,
.sin6_addr = IN6ADDR_ANY_INIT };
static const uint16_t ports[SERVER_SOCKETS_NUM] = SERVER_PORTS;
int server_sockets[SERVER_SOCKETS_NUM] = { 0 };
int max_fd = -1;
int ret = 0;

/* open SERVER_SOCKETS_NUM sockets with respective port */
for (unsigned i = 0; i < SERVER_SOCKETS_NUM; i++) {
server_sockets[i] = socket(AF_INET6, SOCK_DGRAM, 0);
if (server_sockets[i] < 0) {
puts("error initializing socket");
ret = 1;
goto end;
}
server_addr.sin6_port = htons(ports[i]);
if (bind(server_sockets[i],
(struct sockaddr *)&server_addr,
sizeof(server_addr)) < 0) {
puts("error binding socket");
ret = 1;
goto end;
}
printf("Started UDP server at [%s]:%u\n",
inet_ntop(AF_INET6, local_addr, addr_str, sizeof(addr_str)),
ports[i]);
if (max_fd < server_sockets[i]) {
max_fd = server_sockets[i];
}
}

while (true) {
fd_set readfds;

/* add bound sockets to set of file descriptors to read */
FD_ZERO(&readfds);
for (unsigned i = 0; i < SERVER_SOCKETS_NUM; i++) {
FD_SET(server_sockets[i], &readfds);
}
/* wait for bound sockets to be notified for reading*/
if (select(max_fd + 1, &readfds, NULL, NULL, NULL) < 0) {
puts("error on select");
continue;
}
for (unsigned i = 0; i < SERVER_SOCKETS_NUM; i++) {
/* if socket is in set of file descriptors to check for reading */
if (FD_ISSET(server_sockets[i], &readfds)) {
int res;
struct sockaddr_in6 src;
socklen_t src_len = sizeof(struct sockaddr_in6);

/* receive data from socket */
if ((res = recvfrom(server_sockets[i], server_buffer,
sizeof(server_buffer), 0,
(struct sockaddr *)&src, &src_len)) < 0) {
puts("Error on receive");
}
else if (res == 0) {
puts("Peer did shut down");
}
else {
printf("Received data from [%s]:%u:\n",
inet_ntop(AF_INET6, &src.sin6_addr,
addr_str, sizeof(addr_str)),
src.sin6_port);
res = ((unsigned)res < SERVER_BUFFER_SIZE) ? res : (res - 1);
/* terminate string */
server_buffer[res] = '\0';
printf("%s\n", server_buffer);
}
}
}
}

end:
/* close all open sockets */
for (unsigned i = 0; i < SERVER_SOCKETS_NUM; i++) {
if (server_sockets[i] > 0) {
close(server_sockets[i]);
}
}
return ret;
}

int main(void)
{
/* TODO: use TBD POSIX API to get link-local address */
gnrc_netif_t *netif = gnrc_netif_iter(NULL);
ipv6_addr_t addr;

puts("RIOT select example application");

/* get first address on the interface */
if (gnrc_netif_ipv6_addrs_get(netif, &addr, sizeof(addr)) < 0) {
puts("Unable to get first address of the interface");
return 1;
}
return _run_server(&addr);
}
3 changes: 3 additions & 0 deletions sys/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ endif
ifneq (,$(filter posix_inet,$(USEMODULE)))
DIRS += posix/inet
endif
ifneq (,$(filter posix_select,$(USEMODULE)))
DIRS += posix/select
endif
ifneq (,$(filter posix_semaphore,$(USEMODULE)))
DIRS += posix/semaphore
endif
Expand Down
15 changes: 15 additions & 0 deletions sys/include/vfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,21 @@ int vfs_normalize_path(char *buf, const char *path, size_t buflen);
*/
const vfs_mount_t *vfs_iterate_mounts(const vfs_mount_t *cur);

/**
* @brief Get information about the file for internal purposes
*
* @attention Not thread safe! Do not modify any of the fields in the returned
* struct.
* @note For file descriptor internal usage only.
*
* @internal
* @param[in] fd A file descriptor
*
* @return Pointer to the file information struct if a file with @p fd exists.
* @return NULL, when no file with file descriptor @p fd exists.
*/
const vfs_file_t *vfs_file_get(int fd);

#ifdef __cplusplus
}
#endif
Expand Down
6 changes: 6 additions & 0 deletions sys/posix/doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,9 @@
* </a>
* @ingroup sys
*/

/**
* @defgroup config_posix POSIX wrapper compile configurations
* @ingroup posix
* @ingroup config
*/
Loading