-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #12975 from miri64/posix/feat/select
posix: initial import of select() function (only support sockets for now)
- Loading branch information
Showing
13 changed files
with
797 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 \ | ||
# |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.