mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-05-20 00:27:19 +08:00
feat(coap): Add coap multicast client and server example
This commit is contained in:
@ -68,11 +68,33 @@ published under EPL+EDL: http://www.eclipse.org/californium/
|
||||
...
|
||||
```
|
||||
|
||||
You can use example coap_server together with coap_client example.
|
||||
First, make coap_server and coap_client in the same local network by connecting to the same Wifi.
|
||||
Then, configure the coap_client uri to `coap://232.10.11.12/Espressif ` or `coap://[ff02::fc]/Espressif`.
|
||||
The coap_server will listen to ipv4 multicast ip address 232.10.11.12 and ipv6 multicast address ff02::fc.
|
||||
You will see the following log:
|
||||
|
||||
```
|
||||
...
|
||||
I (468) example_connect: Connecting to HUAWEI_888...
|
||||
I (1658) wifi:state: 0 -> 2 (b0)
|
||||
I (1668) wifi:state: 2 -> 3 (0)
|
||||
I (1675) wifi:state: 3 -> 5 (10)
|
||||
I (1701) wifi:connected with HUAWEI_888, aid = 2, channel 1, HT20, bssid = 34:29:12:43:c5:40
|
||||
I (3654) tcpip_adapter: sta ip: 192.168.3.3, mask: 255.255.255.0, gw: 192.168.3.1
|
||||
I (3658) example_connect: Connected to HUAWEI_888
|
||||
I (3662) example_connect: IPv4 address: 192.168.3.3
|
||||
I (3671) example_connect: IPv6 address: fe80:0000:0000:0000:860d:8eff:fe9d:cd90
|
||||
I (3684) CoAP_client: Resolve the IP address is IPV6, FF02::FC
|
||||
Received: no data
|
||||
...
|
||||
```
|
||||
|
||||
## libcoap Documentation
|
||||
This can be found at https://libcoap.net/doc/reference/4.2.0/
|
||||
|
||||
## Troubleshooting
|
||||
* Please make sure Target Url includes valid `host`, optional `port`, optional `path`, and begins
|
||||
* Please make sure Target Url includes valid `host` or `ip`, optional `port`, optional `path`, and begins
|
||||
with `coap://` or `coap+tcp://` for a coap server that supports TCP
|
||||
(not all do including coap+tcp://californium.eclipse.org).
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
#define COAP_DEFAULT_TIME_SEC 5
|
||||
|
||||
/* Set this to 9 to get verbose logging from within libcoap */
|
||||
/* If want to change log level num to open log, don't forget to enlarge coap_example_task size*/
|
||||
#define COAP_LOGGING_LEVEL 0
|
||||
|
||||
/* The examples use uri "coap://californium.eclipse.org" that
|
||||
@ -39,7 +40,7 @@
|
||||
#define COAP_DEFAULT_DEMO_URI CONFIG_TARGET_DOMAIN_URI
|
||||
|
||||
const static char *TAG = "CoAP_client";
|
||||
|
||||
static char addr_str[64] = {0};
|
||||
static int resp_wait = 1;
|
||||
static coap_optlist_t *optlist = NULL;
|
||||
static int wait_ms;
|
||||
@ -126,9 +127,8 @@ clean_up:
|
||||
|
||||
static void coap_example_task(void *p)
|
||||
{
|
||||
struct hostent *hp;
|
||||
struct ip4_addr *ip4_addr;
|
||||
|
||||
struct addrinfo *ainfo;
|
||||
struct addrinfo hints;
|
||||
coap_address_t dst_addr, src_addr;
|
||||
static coap_uri_t uri;
|
||||
const char* server_uri = COAP_DEFAULT_DEMO_URI;
|
||||
@ -165,26 +165,43 @@ static void coap_example_task(void *p)
|
||||
}
|
||||
|
||||
memcpy(phostname, uri.host.s, uri.host.length);
|
||||
hp = gethostbyname(phostname);
|
||||
free(phostname);
|
||||
|
||||
if (hp == NULL) {
|
||||
ESP_LOGE(TAG, "DNS lookup failed");
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
if (getaddrinfo(phostname, NULL, &hints, &ainfo) != 0) {
|
||||
ESP_LOGE(TAG, "getaddrinfo failed");
|
||||
free(phostname);
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Code to print the resolved IP.
|
||||
|
||||
Note: inet_ntoa is non-reentrant, look at ipaddr_ntoa_r for "real" code */
|
||||
ip4_addr = (struct ip4_addr *)hp->h_addr;
|
||||
ESP_LOGI(TAG, "DNS lookup succeeded. IP=%s", inet_ntoa(*ip4_addr));
|
||||
free(phostname);
|
||||
|
||||
coap_address_init(&src_addr);
|
||||
src_addr.addr.sin.sin_family = AF_INET;
|
||||
src_addr.addr.sin.sin_port = htons(0);
|
||||
src_addr.addr.sin.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
if (ainfo->ai_family == AF_INET) {
|
||||
struct sockaddr_in *p = (struct sockaddr_in *)ainfo->ai_addr;
|
||||
inet_ntop(AF_INET, &p->sin_addr, addr_str, sizeof(addr_str));
|
||||
ESP_LOGI(TAG, "Resolve the IP address is IPV4, %s",addr_str);
|
||||
src_addr.addr.sin.sin_family = AF_INET;
|
||||
src_addr.addr.sin.sin_port = htons(0);
|
||||
src_addr.addr.sin.sin_addr.s_addr = INADDR_ANY;
|
||||
} else if (ainfo->ai_family == AF_INET6) {
|
||||
struct sockaddr_in6 *p = (struct sockaddr_in6 *)ainfo->ai_addr;
|
||||
inet_ntop(AF_INET6, &p->sin6_addr, addr_str, sizeof(addr_str));
|
||||
ESP_LOGI(TAG, "Resolve the IP address is IPV6, %s",addr_str);
|
||||
struct in6_addr if_inaddr = { 0 };
|
||||
struct ip6_addr if_ipaddr = { 0 };
|
||||
src_addr.addr.sin6.sin6_port = htons(0);
|
||||
src_addr.addr.sin6.sin6_family = AF_INET6;
|
||||
src_addr.size = sizeof(struct sockaddr_in6);
|
||||
bzero(&src_addr.addr.sin6.sin6_addr.un, sizeof(src_addr.addr.sin6.sin6_addr.un));
|
||||
tcpip_adapter_get_ip6_linklocal(TCPIP_ADAPTER_IF_STA, &if_ipaddr);
|
||||
inet6_addr_from_ip6addr(&if_inaddr, &if_ipaddr);
|
||||
src_addr.addr.sin6.sin6_addr = if_inaddr;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "ai_family is error %d", ainfo->ai_family);
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
if (uri.path.length) {
|
||||
buflen = BUFSIZE;
|
||||
@ -223,9 +240,15 @@ static void coap_example_task(void *p)
|
||||
}
|
||||
|
||||
coap_address_init(&dst_addr);
|
||||
dst_addr.addr.sin.sin_family = AF_INET;
|
||||
dst_addr.addr.sin.sin_port = htons(uri.port);
|
||||
dst_addr.addr.sin.sin_addr.s_addr = ip4_addr->addr;
|
||||
dst_addr.size = ainfo->ai_addrlen;
|
||||
memcpy(&dst_addr.addr, ainfo->ai_addr, ainfo->ai_addrlen);
|
||||
if (ainfo->ai_family == AF_INET6) {
|
||||
dst_addr.addr.sin6.sin6_family = AF_INET6;
|
||||
dst_addr.addr.sin6.sin6_port = htons(uri.port);
|
||||
} else {
|
||||
dst_addr.addr.sin.sin_family = AF_INET;
|
||||
dst_addr.addr.sin.sin_port = htons(uri.port);
|
||||
}
|
||||
|
||||
session = coap_new_client_session(ctx, &src_addr, &dst_addr,
|
||||
uri.scheme==COAP_URI_SCHEME_COAP_TCP ? COAP_PROTO_TCP :
|
||||
@ -272,6 +295,7 @@ clean_up:
|
||||
if (session) coap_session_release(session);
|
||||
if (ctx) coap_free_context(ctx);
|
||||
coap_cleanup();
|
||||
freeaddrinfo(ainfo);
|
||||
/* Only send the request off once */
|
||||
break;
|
||||
}
|
||||
|
@ -1 +1,2 @@
|
||||
CONFIG_ENABLE_COAP=y
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=y
|
||||
|
@ -22,6 +22,8 @@ idf.py menuconfig
|
||||
* Set default serial port under Serial Flasher config
|
||||
* Set WiFi SSID under Example Configuration
|
||||
* Set WiFi Password under Example Configuration
|
||||
* Set IPv4 multicast ip address for server to listen to
|
||||
* Set IPv6 multicast ip address for server to listen to
|
||||
|
||||
### Build and Flash
|
||||
|
||||
@ -41,16 +43,16 @@ and the log is such as the following:
|
||||
|
||||
```
|
||||
...
|
||||
I (332) wifi: mode : sta (30:ae:a4:04:1b:7c)
|
||||
I (1672) wifi: n:11 0, o:1 0, ap:255 255, sta:11 0, prof:1
|
||||
I (1672) wifi: state: init -> auth (b0)
|
||||
I (1682) wifi: state: auth -> assoc (0)
|
||||
I (1692) wifi: state: assoc -> run (10)
|
||||
I (1692) wifi: connected with huawei_cw, channel 11
|
||||
I (1692) wifi: pm start, type: 1
|
||||
|
||||
I (2622) event: sta ip: 192.168.3.84, mask: 255.255.255.0, gw: 192.168.3.1
|
||||
I (2622) CoAP_server: Connected to AP
|
||||
I (1828) wifi:state: 0 -> 2 (b0)
|
||||
I (1838) wifi:state: 2 -> 3 (0)
|
||||
I (1849) wifi:state: 3 -> 5 (10)
|
||||
I (1868) wifi:connected with HUAWEI_888, aid = 1, channel 1, HT20, bssid = 34:29:12:43:c5:40
|
||||
I (3829) tcpip_adapter: sta ip: 192.168.3.2, mask: 255.255.255.0, gw: 192.168.3.1
|
||||
I (3834) example_connect: Connected to HUAWEI_888
|
||||
I (3837) example_connect: IPv4 address: 192.168.3.2
|
||||
I (3846) example_connect: IPv6 address: fe80:0000:0000:0000:a6cf:12ff:fee8:733b
|
||||
I (3864) CoAP_server: Configured IPV4 Multicast address 232.10.11.12
|
||||
I (3875) CoAP_server: Configured IPV6 Multicast address ff02::fc
|
||||
...
|
||||
```
|
||||
|
||||
|
13
examples/protocols/coap_server/main/Kconfig.projbuild
Normal file
13
examples/protocols/coap_server/main/Kconfig.projbuild
Normal file
@ -0,0 +1,13 @@
|
||||
menu "Example Configuration"
|
||||
config TARGET_MULTICAST_IPV4
|
||||
string "IPv4 multicast address"
|
||||
default "232.10.11.12"
|
||||
help
|
||||
Target IP for the example to listen.
|
||||
|
||||
config TARGET_MULTICAST_IPV6
|
||||
string "IPv6 multicast address"
|
||||
default "ff02::fc"
|
||||
help
|
||||
Target IP for the example to listen.
|
||||
endmenu
|
@ -21,12 +21,17 @@
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#include "protocol_examples_common.h"
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sockets.h"
|
||||
#include "lwip/sys.h"
|
||||
#include <lwip/netdb.h>
|
||||
|
||||
#include "coap.h"
|
||||
|
||||
/* Set this to 9 to get verbose logging from within libcoap */
|
||||
/* If want to change log level num to open log, don't forget to enlarge coap_example_task size*/
|
||||
#define COAP_LOGGING_LEVEL 0
|
||||
|
||||
const static char *TAG = "CoAP_server";
|
||||
static char espressif_data[100];
|
||||
static int espressif_data_len = 0;
|
||||
|
||||
@ -93,6 +98,85 @@ hnd_espressif_delete(coap_context_t *ctx,
|
||||
response->code = COAP_RESPONSE_CODE(202);
|
||||
}
|
||||
|
||||
static int coap_example_join_ipv6(int sock, char *group_name)
|
||||
{
|
||||
struct ipv6_mreq mreq = {0};
|
||||
int netif_index = 0, err = 0;
|
||||
|
||||
netif_index = tcpip_adapter_get_netif_index(TCPIP_ADAPTER_IF_STA);
|
||||
if (netif_index < 0) {
|
||||
ESP_LOGE(TAG, "Failed to get netif index");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
err = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &netif_index, sizeof(uint8_t));
|
||||
if (err < 0) {
|
||||
ESP_LOGE(TAG, "Failed to set IPV6_MULTICAST_IF. Error %d", errno);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
err = inet6_aton(group_name, &mreq.ipv6mr_multiaddr);
|
||||
if (err != 1) {
|
||||
ESP_LOGE(TAG, "Configured IPV6 multicast address '%s' is invalid.", group_name);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (!IN6_IS_ADDR_MULTICAST(&mreq.ipv6mr_multiaddr)) {
|
||||
ESP_LOGW(TAG, "Configured IPV6 multicast address '%s' is not a valid multicast address. This will probably not work.", group_name);
|
||||
}
|
||||
mreq.ipv6mr_interface = (unsigned int)netif_index;
|
||||
|
||||
err = setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(struct ipv6_mreq));
|
||||
if (err < 0) {
|
||||
ESP_LOGE(TAG, "Failed to set IPV6_ADD_MEMBERSHIP. Error %d", errno);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
ESP_LOGI(TAG, "Configured IPV6 Multicast address %s", group_name);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static int coap_example_join_ipv4(int sock, char *group_name)
|
||||
{
|
||||
struct ip_mreq imreq = { 0 };
|
||||
struct in_addr iaddr = { 0 };
|
||||
int err = 0;
|
||||
// Configure source interface
|
||||
|
||||
tcpip_adapter_ip_info_t ip_info = { 0 };
|
||||
err = tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to get IP address info. Error 0x%x", err);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
inet_addr_from_ip4addr(&iaddr, &ip_info.ip);
|
||||
|
||||
// Configure multicast address to listen to
|
||||
err = inet_aton(group_name, &imreq.imr_multiaddr.s_addr);
|
||||
if (err != 1) {
|
||||
ESP_LOGE(TAG, "Configured IPV4 multicast address '%s' is invalid.", group_name);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (!IP_MULTICAST(ntohl(imreq.imr_multiaddr.s_addr))) {
|
||||
ESP_LOGW(TAG, "Configured IPV4 multicast address '%s' is not a valid multicast address. This will probably not work.", group_name);
|
||||
}
|
||||
|
||||
// Assign the IPv4 multicast source interface, via its IP
|
||||
// (only necessary if this socket is IPV4 only)
|
||||
err = setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &iaddr, sizeof(struct in_addr));
|
||||
if (err < 0) {
|
||||
ESP_LOGE(TAG, "Failed to set IP_MULTICAST_IF. Error %d", errno);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
err = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imreq, sizeof(struct ip_mreq));
|
||||
if (err < 0) {
|
||||
ESP_LOGE(TAG, "Failed to set IP_ADD_MEMBERSHIP. Error %d", errno);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Configured IPV4 Multicast address %s", inet_ntoa(imreq.imr_multiaddr.s_addr));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void coap_example_thread(void *p)
|
||||
{
|
||||
coap_context_t *ctx = NULL;
|
||||
@ -107,24 +191,41 @@ static void coap_example_thread(void *p)
|
||||
coap_endpoint_t *ep_tcp = NULL;
|
||||
unsigned wait_ms;
|
||||
|
||||
ctx = coap_new_context(NULL);
|
||||
if (!ctx) {
|
||||
continue;
|
||||
}
|
||||
/* Prepare the CoAP server socket */
|
||||
coap_address_init(&serv_addr);
|
||||
serv_addr.addr.sin.sin_family = AF_INET;
|
||||
serv_addr.addr.sin.sin_addr.s_addr = INADDR_ANY;
|
||||
serv_addr.addr.sin.sin_port = htons(COAP_DEFAULT_PORT);
|
||||
|
||||
ctx = coap_new_context(NULL);
|
||||
if (!ctx) {
|
||||
continue;
|
||||
}
|
||||
ep_udp = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_UDP);
|
||||
ep_udp = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_UDP); //Add IPv4 endpoint
|
||||
if (!ep_udp) {
|
||||
goto clean_up;
|
||||
}
|
||||
coap_example_join_ipv4(ep_udp->sock.fd, CONFIG_TARGET_MULTICAST_IPV4);
|
||||
ep_tcp = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_TCP);
|
||||
if (!ep_tcp) {
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
/* Prepare the CoAP server socket */
|
||||
coap_address_init(&serv_addr);
|
||||
serv_addr.addr.sin6.sin6_port = htons(COAP_DEFAULT_PORT);
|
||||
serv_addr.addr.sin6.sin6_family = AF_INET6;
|
||||
serv_addr.size = sizeof(struct sockaddr_in6);
|
||||
bzero(&serv_addr.addr.sin6.sin6_addr.un, sizeof(serv_addr.addr.sin6.sin6_addr.un));
|
||||
ep_udp = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_UDP); //Add IPv6 endpoint
|
||||
if (!ep_udp) {
|
||||
goto clean_up;
|
||||
}
|
||||
coap_example_join_ipv6(ep_udp->sock.fd, CONFIG_TARGET_MULTICAST_IPV6);
|
||||
ep_tcp = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_TCP);
|
||||
if (!ep_tcp) {
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
resource = coap_resource_init(coap_make_str_const("Espressif"), 0);
|
||||
if (!resource) {
|
||||
goto clean_up;
|
||||
|
@ -1 +1,2 @@
|
||||
CONFIG_ENABLE_COAP=y
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=y
|
||||
|
Reference in New Issue
Block a user