ASIO: Remove internal component, examples, test and docs

pull/9357/head
gabsuren 2022-05-28 19:54:53 +04:00
rodzic 3d3447831a
commit 79d3655106
76 zmienionych plików z 11 dodań i 3877 usunięć

Wyświetl plik

@ -69,7 +69,6 @@
/components/app_trace/ @esp-idf-codeowners/tools
/components/app_update/ @esp-idf-codeowners/system @esp-idf-codeowners/app-utilities
/components/asio/ @esp-idf-codeowners/network
/components/bootloader*/ @esp-idf-codeowners/system @esp-idf-codeowners/security
/components/bootloader_support/bootloader_flash/ @esp-idf-codeowners/peripherals
/components/bt/ @esp-idf-codeowners/bluetooth

4
.gitmodules vendored
Wyświetl plik

@ -23,10 +23,6 @@
path = components/mbedtls/mbedtls
url = ../../espressif/mbedtls.git
[submodule "components/asio/asio"]
path = components/asio/asio
url = ../../espressif/asio.git
[submodule "components/lwip/lwip"]
path = components/lwip/lwip
url = ../../espressif/esp-lwip.git

Wyświetl plik

@ -1,44 +0,0 @@
if(NOT CONFIG_LWIP_IPV6 AND NOT CMAKE_BUILD_EARLY_EXPANSION)
# note: the component is still included in the build so it can become visible again in config
# without needing to re-run CMake. However no source or header files are built.
message(STATUS "IPV6 support is disabled so the asio component will not be built")
idf_component_register()
return()
endif()
set(asio_sources "asio/asio/src/asio.cpp")
if(CONFIG_ASIO_SSL_SUPPORT)
if(CONFIG_ASIO_USE_ESP_OPENSSL)
list(APPEND asio_sources
"port/src/asio_ssl_impl.cpp"
"port/mbedtls/src/mbedtls_context.cpp"
"port/mbedtls/src/mbedtls_engine.cpp")
set(asio_priv_includes "port/mbedtls/include")
endif()
if(CONFIG_ASIO_USE_ESP_WOLFSSL)
list(APPEND asio_sources
"asio/asio/src/asio_ssl.cpp")
endif()
endif()
idf_component_register(SRCS ${asio_sources}
INCLUDE_DIRS "asio/asio/include" "port/include"
PRIV_INCLUDE_DIRS ${asio_priv_includes}
REQUIRES lwip)
if(CONFIG_ASIO_SSL_SUPPORT)
if(CONFIG_ASIO_USE_ESP_WOLFSSL)
idf_component_get_property(wolflib esp-wolfssl COMPONENT_LIB)
idf_component_get_property(wolfdir esp-wolfssl COMPONENT_DIR)
target_link_libraries(${COMPONENT_LIB} PUBLIC ${wolflib})
target_include_directories(${COMPONENT_LIB} PUBLIC ${wolfdir}/wolfssl/wolfssl)
endif()
if(CONFIG_ASIO_USE_ESP_OPENSSL)
idf_component_get_property(mbedtls mbedtls COMPONENT_LIB)
target_link_libraries(${COMPONENT_LIB} PUBLIC ${mbedtls})
endif()
endif()

Wyświetl plik

@ -1,36 +0,0 @@
menu "ESP-ASIO"
visible if LWIP_IPV6
config ASIO_SSL_SUPPORT
bool "Enable SSL/TLS support of ASIO"
default n
help
Enable support for basic SSL/TLS features, available for mbedTLS/OpenSSL
as well as wolfSSL TLS library.
choice ASIO_SSL_LIBRARY_CHOICE
prompt "Choose SSL/TLS library for ESP-TLS (See help for more Info)"
default ASIO_USE_ESP_OPENSSL
depends on ASIO_SSL_SUPPORT
help
The ASIO support multiple backend TLS libraries. Currently the mbedTLS with a thin ESP-OpenSSL
port layer (default choice) and WolfSSL are supported.
Different TLS libraries may support different features and have different resource
usage. Consult the ESP-TLS documentation in ESP-IDF Programming guide for more details.
config ASIO_USE_ESP_OPENSSL
bool "esp-openssl"
config ASIO_USE_ESP_WOLFSSL
depends on TLS_STACK_WOLFSSL
bool "wolfSSL (License info in wolfSSL directory README)"
endchoice
config ASIO_SSL_BIO_SIZE
int "Size of BIO object"
default 1024
depends on ASIO_SSL_SUPPORT
help
Size in bytes of SSL-BIO implementation.
Reducing the BIO size saves more RAM, but may slow down input output operations due to
fragmentation.
endmenu

@ -1 +0,0 @@
Subproject commit f31694c9f1746ba189a4bcae2e34db15135ddb22

Wyświetl plik

@ -1,45 +0,0 @@
/*
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _ESP_ASIO_CONFIG_H_
#define _ESP_ASIO_CONFIG_H_
//
// Enabling exceptions only when they are enabled in menuconfig
//
# include <sdkconfig.h>
# ifndef CONFIG_COMPILER_CXX_EXCEPTIONS
# define ASIO_NO_EXCEPTIONS
# endif // CONFIG_COMPILER_CXX_EXCEPTIONS
# ifndef CONFIG_COMPILER_RTTI
# define ASIO_NO_TYPEID
# endif // CONFIG_COMPILER_RTTI
//
// Use system sockets
//
# include "sys/socket.h"
//
// Specific ASIO feature flags
//
# define ASIO_DISABLE_SERIAL_PORT
# define ASIO_SEPARATE_COMPILATION
# define ASIO_STANDALONE
# define ASIO_HAS_PTHREADS
# define ASIO_DISABLE_CONCEPTS
# ifdef CONFIG_ASIO_USE_ESP_OPENSSL
# define ASIO_USE_ESP_OPENSSL
# define OPENSSL_NO_ENGINE
# define ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP
# include "openssl_stub.hpp"
# elif CONFIG_ASIO_USE_ESP_WOLFSSL
# define ASIO_USE_WOLFSSL
# endif // CONFIG_ASIO_USE_ESP_OPENSSL
#endif // _ESP_ASIO_CONFIG_H_

Wyświetl plik

@ -1,30 +0,0 @@
/*
* SPDX-FileCopyrightText: 2018-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _ESP_EXCEPTION_H_
#define _ESP_EXCEPTION_H_
//
// This exception stub is enabled only if exceptions are disabled in menuconfig
//
#if !defined(CONFIG_COMPILER_CXX_EXCEPTIONS) && defined (ASIO_NO_EXCEPTIONS)
#include "esp_log.h"
//
// asio exception stub
//
namespace asio {
namespace detail {
template <typename Exception>
void throw_exception(const Exception& e)
{
ESP_LOGE("esp32_asio_exception", "Caught exception: %s!", e.what());
abort();
}
}}
#endif // CONFIG_COMPILER_CXX_EXCEPTIONS==1 && defined (ASIO_NO_EXCEPTIONS)
#endif // _ESP_EXCEPTION_H_

Wyświetl plik

@ -1,46 +0,0 @@
//
// SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
//
// SPDX-License-Identifier: BSL-1.0
//
#pragma once
//
// Supply OpenSSL macros and flags for asio-ssl header files
//
#define OPENSSL_VERSION_NUMBER 0x10100001L
#define SSL_R_SHORT_READ 219
#define SSL_OP_ALL 0
#define SSL_OP_SINGLE_DH_USE 0
#define SSL_OP_NO_COMPRESSION 0
#define SSL_OP_NO_SSLv2 0x01000000L
#define SSL_OP_NO_SSLv3 0x02000000L
#define SSL_OP_NO_TLSv1 0x04000000L
#define SSL_VERIFY_NONE 0x00
#define SSL_VERIFY_PEER 0x01
#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT 0x02
#define SSL_VERIFY_CLIENT_ONCE 0x04
//
// Implement asio-ssl layer with these three classes in asio::ssl::mbedtls
//
namespace asio {
namespace ssl {
namespace mbedtls {
class engine;
class bio;
class shared_ctx;
} } } // namespace asio::ssl::mbedtls
//
// Supply OpenSSL types as aliases to mbedtls classes
//
using X509_STORE_CTX=void;
using BIO=asio::ssl::mbedtls::bio;
using SSL_CTX=asio::ssl::mbedtls::shared_ctx;
using SSL=asio::ssl::mbedtls::engine;

Wyświetl plik

@ -1,113 +0,0 @@
//
// SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
//
// SPDX-License-Identifier: BSL-1.0
//
#pragma once
#include "asio/ssl/context_base.hpp"
#include "asio/ssl/context.hpp"
#include "sdkconfig.h"
namespace asio {
namespace ssl {
namespace mbedtls {
class bio {
static constexpr int BIO_SIZE = CONFIG_ASIO_SSL_BIO_SIZE;
static constexpr int BIO_FLAGS_READ = 1;
static constexpr int BIO_FLAGS_WRITE = 2;
public:
int write(const void *buf, int len)
{
if (buf == nullptr || len <= 0) {
// not an error, just empty operation (as in openssl/bio)
return 0;
}
int remaining = size_ - offset_;
if (remaining <= 0) {
flags_ |= BIO_FLAGS_WRITE;
return -1;
}
int len_to_write = len > remaining ? remaining : len;
std::memcpy(&data_[offset_], buf, len_to_write);
offset_ += len_to_write;
dlen_ = offset_;
if (len_to_write == len) {
flags_ &= ~BIO_FLAGS_WRITE;
}
return len_to_write;
}
int read(void *buf, int len)
{
if (buf == nullptr || len <= 0) {
// not an error, just empty operation (as in openssl/bio)
return 0;
}
int remaining = peer_->dlen_ - peer_->roffset_;
if (remaining <= 0) {
flags_ |= BIO_FLAGS_READ;
return -1;
}
int len_to_read = remaining > len ? len : remaining;
std::memcpy(buf, &peer_->data_[peer_->roffset_], len_to_read);
peer_->roffset_ += len_to_read;
if (len_to_read == len) {
flags_ &= ~BIO_FLAGS_READ;
}
if (peer_->offset_) {
// shift data back to the beginning of the buffer
std::memmove(&peer_->data_[0], &peer_->data_[peer_->roffset_], peer_->offset_ - peer_->roffset_);
peer_->offset_ -= peer_->roffset_;
peer_->roffset_ = 0;
peer_->dlen_ = peer_->offset_;
}
return len_to_read;
}
size_t wpending() const
{
return dlen_ - roffset_;
}
size_t ctrl_pending()
{
return peer_->dlen_ - peer_->roffset_;
}
bool should_write() const
{
return flags_ & BIO_FLAGS_WRITE;
}
bool should_read() const
{
return flags_ & BIO_FLAGS_READ;
}
static std::pair<std::shared_ptr<bio>, std::shared_ptr<bio>> new_pair(const char* error_location)
{
auto b1 = std::shared_ptr<bio>(new (std::nothrow) bio);
auto b2 = std::shared_ptr<bio>(new (std::nothrow) bio);
if (b1 == nullptr || b2 == nullptr) {
throw_alloc_failure(error_location);
} else {
b1->peer_ = b2;
b2->peer_ = b1;
}
return std::make_pair(b1, b2);
}
private:
std::array<uint8_t, BIO_SIZE> data_ {};
size_t size_ {BIO_SIZE};
std::shared_ptr<bio> peer_ {nullptr};
int dlen_ {0};
size_t offset_ {0};
size_t roffset_ {0};
size_t flags_ {0};
};
} } } // namespace asio::ssl::mbedtls

Wyświetl plik

@ -1,105 +0,0 @@
//
// SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
//
// SPDX-License-Identifier: BSL-1.0
//
#pragma once
#include "asio/ssl/context_base.hpp"
#include "asio/ssl/context.hpp"
namespace asio {
namespace error {
const asio::error_category& get_mbedtls_category();
} // namespace error
namespace ssl {
namespace mbedtls {
void throw_alloc_failure(const char* location);
const char *error_message(int error_code);
enum class container {
CERT, CA_CERT, PRIVKEY
};
template <typename T, typename... Args>
inline T* create(const char * location, Args &&... args)
{
T* t = new (std::nothrow) T(std::forward<Args>(args)...);
if (t == nullptr)
{
throw_alloc_failure(location);
}
return t;
}
class context {
public:
explicit context(context_base::method m): method_(m), options_(0) {}
const unsigned char *data(container c) const
{
switch (c) {
case container::CERT:
return static_cast<const unsigned char *>(cert_chain_.data());
case container::CA_CERT:
return static_cast<const unsigned char *>(ca_cert_.data());
case container::PRIVKEY:
return static_cast<const unsigned char *>(private_key_.data());
}
return nullptr;
}
std::size_t size(container c) const
{
switch (c) {
case container::CERT:
return cert_chain_.size();
case container::CA_CERT:
return ca_cert_.size();
case container::PRIVKEY:
return private_key_.size();
}
return 0;
}
context_base::method method_;
asio::ssl::context::options options_;
const_buffer cert_chain_;
const_buffer private_key_;
const_buffer ca_cert_;
};
/**
* @brief Wrapper class around SSL_CTX so we can easily create
* a shared pointer to the context without throwing the default exception.
* This is useful, as we can use asio::detail::throw_error for allocation errors.
*/
class shared_ctx {
public:
static SSL_CTX *create(const char* location, context_base::method m)
{
auto wrapped = asio::ssl::mbedtls::create<shared_ctx>(location, m);
if (wrapped->ctx_ == nullptr)
{
throw_alloc_failure(location);
}
return wrapped;
}
std::shared_ptr<mbedtls::context> get() const
{
return ctx_;
}
explicit shared_ctx(context_base::method m)
:ctx_(std::shared_ptr<context>(new (std::nothrow) context(m))) { }
private:
std::shared_ptr<mbedtls::context> ctx_;
};
} } } // namespace asio::ssl::mbedtls

Wyświetl plik

@ -1,293 +0,0 @@
//
// SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
//
// SPDX-License-Identifier: BSL-1.0
//
#pragma once
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/error.h"
#include "mbedtls/esp_debug.h"
#include "esp_log.h"
namespace asio {
namespace ssl {
namespace mbedtls {
const char *error_message(int error_code)
{
static char error_buf[100];
mbedtls_strerror(error_code, error_buf, sizeof(error_buf));
return error_buf;
}
void throw_alloc_failure(const char* location)
{
asio::error_code ec( MBEDTLS_ERR_SSL_ALLOC_FAILED, asio::error::get_mbedtls_category());
asio::detail::throw_error(ec, location);
}
namespace error_codes {
bool is_error(int ret)
{
return ret < 0 && ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE;
}
static bool want_write(int ret)
{
return ret == MBEDTLS_ERR_SSL_WANT_WRITE;
}
static bool want_read(int ret)
{
return ret == MBEDTLS_ERR_SSL_WANT_READ;
}
} // namespace error_codes
enum rw_state {
IDLE, READING, WRITING, CLOSED
};
class engine {
public:
explicit engine(std::shared_ptr<context> ctx): ctx_(std::move(ctx)),
bio_(bio::new_pair("mbedtls-engine")), state_(IDLE), verify_mode_(0) {}
void set_verify_mode(asio::ssl::verify_mode mode)
{
verify_mode_ = mode;
}
bio* ext_bio() const
{
return bio_.second.get();
}
rw_state get_state() const
{
return state_;
}
int shutdown()
{
int ret = mbedtls_ssl_close_notify(&impl_.ssl_);
if (ret) {
impl::print_error("mbedtls_ssl_close_notify", ret);
}
state_ = CLOSED;
return ret;
}
int connect()
{
return handshake(true);
}
int accept()
{
return handshake(false);
}
int write(const void *buffer, int len)
{
int ret = impl_.write(buffer, len);
state_ = ret == len ? IDLE: WRITING;
return ret;
}
int read(void *buffer, int len)
{
int ret = impl_.read(buffer, len);
state_ = ret == len ? IDLE: READING;
return ret;
}
private:
int handshake(bool is_client_not_server)
{
if (impl_.before_handshake()) {
impl_.configure(ctx_.get(), is_client_not_server, impl_verify_mode(is_client_not_server));
}
return do_handshake();
}
static int bio_read(void *ctx, unsigned char *buf, size_t len)
{
auto bio = static_cast<BIO*>(ctx);
int read = bio->read(buf, len);
if (read <= 0 && bio->should_read()) {
return MBEDTLS_ERR_SSL_WANT_READ;
}
return read;
}
static int bio_write(void *ctx, const unsigned char *buf, size_t len)
{
auto bio = static_cast<BIO*>(ctx);
int written = bio->write(buf, len);
if (written <= 0 && bio->should_write()) {
return MBEDTLS_ERR_SSL_WANT_WRITE;
}
return written;
}
int do_handshake()
{
int ret = 0;
mbedtls_ssl_set_bio(&impl_.ssl_, bio_.first.get(), bio_write, bio_read, nullptr);
while (impl_.ssl_.MBEDTLS_PRIVATE(state) != MBEDTLS_SSL_HANDSHAKE_OVER) {
ret = mbedtls_ssl_handshake_step(&impl_.ssl_);
if (ret != 0) {
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
impl::print_error("mbedtls_ssl_handshake_step", ret);
}
if (ret == MBEDTLS_ERR_SSL_WANT_READ) {
state_ = READING;
} else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
state_ = WRITING;
}
break;
}
}
return ret;
}
// Converts OpenSSL verification mode to mbedtls enum
int impl_verify_mode(bool is_client_not_server) const
{
int mode = MBEDTLS_SSL_VERIFY_UNSET;
if (is_client_not_server) {
if (verify_mode_ & SSL_VERIFY_PEER)
mode = MBEDTLS_SSL_VERIFY_REQUIRED;
else if (verify_mode_ == SSL_VERIFY_NONE)
mode = MBEDTLS_SSL_VERIFY_NONE;
} else {
if (verify_mode_ & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
mode = MBEDTLS_SSL_VERIFY_REQUIRED;
else if (verify_mode_ & SSL_VERIFY_PEER)
mode = MBEDTLS_SSL_VERIFY_OPTIONAL;
else if (verify_mode_ == SSL_VERIFY_NONE)
mode = MBEDTLS_SSL_VERIFY_NONE;
}
return mode;
}
struct impl {
static void print_error(const char* function, int error_code)
{
constexpr const char *TAG="mbedtls-engine-impl";
ESP_LOGE(TAG, "%s() returned -0x%04X", function, -error_code);
ESP_LOGI(TAG, "-0x%04X: %s", -error_code, error_message(error_code));
}
bool before_handshake() const
{
return ssl_.MBEDTLS_PRIVATE(state) == 0;
}
int write(const void *buffer, int len)
{
int ret = mbedtls_ssl_write(&ssl_, static_cast<const unsigned char *>(buffer), len);
if (ret < 0 && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
print_error("mbedtls_ssl_write", ret);
}
return ret;
}
int read(void *buffer, int len)
{
int ret = mbedtls_ssl_read(&ssl_, static_cast<unsigned char *>(buffer), len);
if (ret < 0 && ret != MBEDTLS_ERR_SSL_WANT_READ) {
print_error("mbedtls_ssl_read", ret);
}
return ret;
}
impl()
{
const unsigned char pers[] = "asio ssl";
mbedtls_ssl_init(&ssl_);
mbedtls_ssl_config_init(&conf_);
mbedtls_ctr_drbg_init(&ctr_drbg_);
#ifdef CONFIG_MBEDTLS_DEBUG
mbedtls_esp_enable_debug_log(&conf_, CONFIG_MBEDTLS_DEBUG_LEVEL);
#endif
mbedtls_entropy_init(&entropy_);
mbedtls_ctr_drbg_seed(&ctr_drbg_, mbedtls_entropy_func, &entropy_, pers, sizeof(pers));
mbedtls_x509_crt_init(&public_cert_);
mbedtls_pk_init(&pk_key_);
mbedtls_x509_crt_init(&ca_cert_);
}
bool configure(context *ctx, bool is_client_not_server, int mbedtls_verify_mode)
{
mbedtls_x509_crt_init(&public_cert_);
mbedtls_pk_init(&pk_key_);
mbedtls_x509_crt_init(&ca_cert_);
int ret = mbedtls_ssl_config_defaults(&conf_, is_client_not_server ? MBEDTLS_SSL_IS_CLIENT: MBEDTLS_SSL_IS_SERVER,
MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
if (ret) {
print_error("mbedtls_ssl_config_defaults", ret);
return false;
}
mbedtls_ssl_conf_rng(&conf_, mbedtls_ctr_drbg_random, &ctr_drbg_);
mbedtls_ssl_conf_authmode(&conf_, mbedtls_verify_mode);
if (ctx->cert_chain_.size() > 0 && ctx->private_key_.size() > 0) {
ret = mbedtls_x509_crt_parse(&public_cert_, ctx->data(container::CERT), ctx->size(container::CERT));
if (ret < 0) {
print_error("mbedtls_x509_crt_parse", ret);
return false;
}
ret = mbedtls_pk_parse_key(&pk_key_, ctx->data(container::PRIVKEY), ctx->size(container::PRIVKEY),
nullptr, 0, mbedtls_ctr_drbg_random, &ctr_drbg_);
if (ret < 0) {
print_error("mbedtls_pk_parse_keyfile", ret);
return false;
}
ret = mbedtls_ssl_conf_own_cert(&conf_, &public_cert_, &pk_key_);
if (ret) {
print_error("mbedtls_ssl_conf_own_cert", ret);
return false;
}
}
if (ctx->ca_cert_.size() > 0) {
ret = mbedtls_x509_crt_parse(&ca_cert_, ctx->data(container::CA_CERT), ctx->size(container::CA_CERT));
if (ret < 0) {
print_error("mbedtls_x509_crt_parse", ret);
return false;
}
mbedtls_ssl_conf_ca_chain(&conf_, &ca_cert_, nullptr);
} else {
mbedtls_ssl_conf_ca_chain(&conf_, nullptr, nullptr);
}
ret = mbedtls_ssl_setup(&ssl_, &conf_);
if (ret) {
print_error("mbedtls_ssl_setup", ret);
return false;
}
return true;
}
mbedtls_ssl_context ssl_{};
mbedtls_entropy_context entropy_{};
mbedtls_ctr_drbg_context ctr_drbg_{};
mbedtls_ssl_config conf_{};
mbedtls_x509_crt public_cert_{};
mbedtls_pk_context pk_key_{};
mbedtls_x509_crt ca_cert_{};
};
impl impl_{};
std::shared_ptr<context> ctx_;
std::pair<std::shared_ptr<bio>, std::shared_ptr<bio>> bio_;
enum rw_state state_;
asio::ssl::verify_mode verify_mode_;
};
} } } // namespace asio::ssl::mbedtls

Wyświetl plik

@ -1,55 +0,0 @@
//
// SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
//
// SPDX-License-Identifier: BSL-1.0
//
#pragma once
#include "asio/detail/config.hpp"
#include "asio/ssl/error.hpp"
#include "asio/ssl/detail/openssl_init.hpp"
#include "mbedtls_context.hpp"
namespace asio {
namespace error {
namespace detail {
class mbedtls_category : public asio::error_category
{
public:
const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT
{
return "asio.ssl";
}
std::string message(int value) const
{
const char* s = asio::ssl::mbedtls::error_message(value);
return s ? s : "asio.mbedtls error";
}
};
} // namespace detail
const asio::error_category& get_mbedtls_category()
{
static detail::mbedtls_category instance;
return instance;
}
const asio::error_category& get_ssl_category()
{
return asio::error::get_mbedtls_category();
}
} // namespace error
namespace ssl {
namespace error {
const asio::error_category& get_stream_category()
{
return asio::error::get_mbedtls_category();
}
} } } // namespace asio::ssl::error

Wyświetl plik

@ -1,6 +0,0 @@
//
// SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
//
// SPDX-License-Identifier: BSL-1.0
//
#pragma once

Wyświetl plik

@ -1,6 +0,0 @@
//
// SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
//
// SPDX-License-Identifier: BSL-1.0
//
#pragma once

Wyświetl plik

@ -1,6 +0,0 @@
//
// SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
//
// SPDX-License-Identifier: BSL-1.0
//
#pragma once

Wyświetl plik

@ -1,6 +0,0 @@
//
// SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
//
// SPDX-License-Identifier: BSL-1.0
//
#pragma once

Wyświetl plik

@ -1,8 +0,0 @@
//
// SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
//
// SPDX-License-Identifier: BSL-1.0
//
#pragma once
#include "openssl_stub.hpp"

Wyświetl plik

@ -1,6 +0,0 @@
//
// SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
//
// SPDX-License-Identifier: BSL-1.0
//
#pragma once

Wyświetl plik

@ -1,115 +0,0 @@
//
// SPDX-FileCopyrightText: 2005 Voipster / Indrek dot Juhani at voipster dot com
// SPDX-FileCopyrightText: 2005-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// SPDX-License-Identifier: BSL-1.0
//
// SPDX-FileContributor: 2021 Espressif Systems (Shanghai) CO LTD
//
#include "asio/detail/config.hpp"
#include "openssl_stub.hpp"
#include <cstring>
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/ssl/context.hpp"
#include "asio/ssl/error.hpp"
#include "mbedtls_context.hpp"
namespace asio {
namespace ssl {
context::context(context::method m)
: handle_(0)
{
handle_ = mbedtls::shared_ctx::create("mbedtls-context", m);
set_options(no_compression);
}
context::context(context&& other)
{
handle_ = other.handle_;
other.handle_ = 0;
}
context& context::operator=(context&& other)
{
context tmp(ASIO_MOVE_CAST(context)(*this));
handle_ = other.handle_;
other.handle_ = 0;
return *this;
}
context::~context()
{
delete handle_;
}
context::native_handle_type context::native_handle()
{
return handle_;
}
void context::set_options(context::options o)
{
asio::error_code ec;
set_options(o, ec);
asio::detail::throw_error(ec, "set_options");
}
ASIO_SYNC_OP_VOID context::set_options(
context::options o, asio::error_code& ec)
{
handle_->get()->options_ = o;
ec = asio::error_code();
ASIO_SYNC_OP_VOID_RETURN(ec);
}
void context::add_certificate_authority(const const_buffer& ca)
{
asio::error_code ec;
add_certificate_authority(ca, ec);
asio::detail::throw_error(ec, "add_certificate_authority");
}
ASIO_SYNC_OP_VOID context::add_certificate_authority(
const const_buffer& ca, asio::error_code& ec)
{
handle_->get()->ca_cert_ = ca;
ASIO_SYNC_OP_VOID_RETURN(asio::error_code());
}
void context::use_certificate_chain(const const_buffer& chain)
{
asio::error_code ec;
use_certificate_chain(chain, ec);
asio::detail::throw_error(ec, "use_certificate_chain");
}
ASIO_SYNC_OP_VOID context::use_certificate_chain(
const const_buffer& chain, asio::error_code& ec)
{
handle_->get()->cert_chain_ = chain;
ASIO_SYNC_OP_VOID_RETURN(asio::error_code());
}
void context::use_private_key(
const const_buffer& private_key, context::file_format format)
{
asio::error_code ec;
use_private_key(private_key, format, ec);
asio::detail::throw_error(ec, "use_private_key");
}
ASIO_SYNC_OP_VOID context::use_private_key(
const const_buffer& private_key, context::file_format format,
asio::error_code& ec)
{
handle_->get()->private_key_ = private_key;
ASIO_SYNC_OP_VOID_RETURN(asio::error_code());
}
} // namespace ssl
} // namespace asio

Wyświetl plik

@ -1,208 +0,0 @@
//
// SPDX-FileCopyrightText: 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// SPDX-License-Identifier: BSL-1.0
//
// SPDX-FileContributor: 2021 Espressif Systems (Shanghai) CO LTD
//
#include "asio/detail/config.hpp"
#include "openssl_stub.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/ssl/detail/engine.hpp"
#include "asio/ssl/error.hpp"
#include "asio/ssl/verify_context.hpp"
#include "mbedtls_context.hpp"
#include "mbedtls_bio.hpp"
#include "mbedtls_error.hpp"
#include "mbedtls_engine.hpp"
namespace asio {
namespace ssl {
namespace detail {
engine::engine(SSL_CTX* context)
: ssl_(nullptr)
{
ssl_ = mbedtls::create<mbedtls::engine>("mbedtls-engine", context->get());
}
engine::~engine()
{
delete ssl_;
}
SSL* engine::native_handle()
{
return ssl_;
}
asio::error_code engine::set_verify_mode(
verify_mode v, asio::error_code& ec)
{
ssl_->set_verify_mode(v);
return {};
}
engine::want engine::handshake(
stream_base::handshake_type type, asio::error_code& ec)
{
return perform((type == asio::ssl::stream_base::client)
? &engine::do_connect : &engine::do_accept, 0, 0, ec, 0);
}
engine::want engine::shutdown(asio::error_code& ec)
{
return perform(&engine::do_shutdown, 0, 0, ec, 0);
}
engine::want engine::write(const asio::const_buffer& data,
asio::error_code& ec, std::size_t& bytes_transferred)
{
if (data.size() == 0)
{
ec = asio::error_code();
return engine::want_nothing;
}
return perform(&engine::do_write,
const_cast<void*>(data.data()),
data.size(), ec, &bytes_transferred);
}
engine::want engine::read(const asio::mutable_buffer& data,
asio::error_code& ec, std::size_t& bytes_transferred)
{
if (data.size() == 0)
{
ec = asio::error_code();
return engine::want_nothing;
}
return perform(&engine::do_read, data.data(),
data.size(), ec, &bytes_transferred);
}
asio::mutable_buffer engine::get_output(
const asio::mutable_buffer& data)
{
int length = ssl_->ext_bio()->read(data.data(), static_cast<int>(data.size()));
return asio::buffer(data,
length > 0 ? static_cast<std::size_t>(length) : 0);
}
asio::const_buffer engine::put_input(
const asio::const_buffer& data)
{
int length = ssl_->ext_bio()->write(data.data(), static_cast<int>(data.size()));
return asio::buffer(data +
(length > 0 ? static_cast<std::size_t>(length) : 0));
}
const asio::error_code& engine::map_error_code(
asio::error_code& ec) const
{
// We only want to map the error::eof code.
if (ec != asio::error::eof)
return ec;
// If there's data yet to be read, it's an error.
if (ssl_->ext_bio()->wpending())
{
ec = asio::ssl::error::stream_truncated;
return ec;
}
// Otherwise, the peer should have negotiated a proper shutdown.
if (ssl_->shutdown() != 0)
{
ec = asio::ssl::error::stream_truncated;
}
return ec;
}
// This is a simplified implementation of a generic ssl io operation
// original implementation using openssl's SSL object is in asio/include/asio/ssl/detail/impl/engine.ipp
engine::want engine::perform(int (engine::* op)(void*, std::size_t),
void* data, std::size_t length, asio::error_code& ec,
std::size_t* bytes_transferred)
{
std::size_t pending_output_before = ssl_->ext_bio()->ctrl_pending();
int result = (this->*op)(data, length);
std::size_t pending_output_after = ssl_->ext_bio()->ctrl_pending();
if (mbedtls::error_codes::is_error(result))
{
ec = asio::error_code(result, asio::error::get_mbedtls_category());
return pending_output_after > pending_output_before ? want_output : want_nothing;
}
if (result == 0)
{
return pending_output_after > pending_output_before
? want_output : want_nothing;
}
if (result > 0 && bytes_transferred)
*bytes_transferred = static_cast<std::size_t>(result);
if (mbedtls::error_codes::want_write(result))
{
ec = asio::error_code();
return want_output_and_retry;
}
else if (pending_output_after > pending_output_before)
{
ec = asio::error_code();
return result > 0 ? want_output : want_output_and_retry;
}
else if (mbedtls::error_codes::want_read(result))
{
ec = asio::error_code();
return want_input_and_retry;
}
else if (ssl_->get_state() == mbedtls::CLOSED)
{
ec = asio::error::eof;
return want_nothing;
}
ec = asio::error_code();
return want_nothing;
}
int engine::do_accept(void*, std::size_t)
{
return ssl_->accept();
}
int engine::do_connect(void*, std::size_t)
{
return ssl_->connect();
}
int engine::do_shutdown(void*, std::size_t)
{
return ssl_->shutdown();
}
int engine::do_read(void* data, std::size_t length)
{
return ssl_->read(data, length < INT_MAX ? static_cast<int>(length) : INT_MAX);
}
int engine::do_write(void* data, std::size_t length)
{
return ssl_->write(data, length < INT_MAX ? static_cast<int>(length) : INT_MAX);
}
} // namespace detail
} // namespace ssl
} // namespace asio

Wyświetl plik

@ -1,20 +0,0 @@
//
// SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
//
// SPDX-License-Identifier: Apache-2.0
//
#include "asio/detail/config.hpp"
#include "asio/ssl/detail/openssl_init.hpp"
namespace asio {
namespace ssl {
namespace detail {
// No OpenSSL in this implementation, instance is nullptr
asio::detail::shared_ptr<openssl_init_base::do_init> openssl_init_base::instance()
{
return nullptr;
}
} } } // namespace asio::ssl::detail

Wyświetl plik

@ -49,8 +49,6 @@ These third party libraries can be included into the application (firmware) prod
* :component_file:`SD/MMC driver <sdmmc/sdmmc_cmd.c>` is derived from `OpenBSD SD/MMC driver`_, Copyright (c) 2006 Uwe Stuehler, and is licensed under BSD license.
* :component:`Asio <asio>`, Copyright (c) 2003-2018 Christopher M. Kohlhoff is licensed under the Boost Software License as described in :component_file:`COPYING file<asio/asio/asio/COPYING>`.
* :component:`ESP-MQTT <mqtt>` MQTT Package (contiki-mqtt) - Copyright (c) 2014, Stephen Robinson, MQTT-ESP - Tuan PM <tuanpm at live dot com> is licensed under Apache License 2.0 as described in :component_file:`LICENSE file <mqtt/esp-mqtt/LICENSE>`.
* :component:`BLE Mesh <bt/esp_ble_mesh>` is adapted from Zephyr Project, Copyright (c) 2017-2018 Intel Corporation and licensed under Apache License 2.0

Wyświetl plik

@ -1,42 +1,15 @@
ASIO port
=========
Overview
--------
Asio is a cross-platform C++ library, see https://think-async.com/Asio/. It provides a consistent asynchronous model using a modern C++ approach.
The ESP-IDF component `ASIO` has been moved from ESP-IDF since version v5.0 to a separate repository:
ASIO documentation
^^^^^^^^^^^^^^^^^^
Please refer to the original asio documentation at https://think-async.com/Asio/Documentation.
Asio also comes with a number of examples which could be find under Documentation/Examples on that web site.
* `ASIO component on GitHub <https://github.com/espressif/esp-protocols/components/asio>`__
Supported features
^^^^^^^^^^^^^^^^^^
ESP platform port currently supports only network asynchronous socket operations; does not support serial port.
SSL/TLS support is disabled by default and could be enabled in component configuration menu by choosing TLS library from
Hosted Documentation
--------------------
- mbedTLS with OpenSSL translation layer (default option)
- wolfSSL
The documentation can be found on the link below:
SSL support is very basic at this stage and it does include following features:
- Verification callbacks
- DH property files
- Certificates/private keys file APIs
Internal asio settings for ESP include
- EXCEPTIONS are enabled in ASIO if enabled in menuconfig
- TYPEID is enabled in ASIO if enabled in menuconfig
Application Example
-------------------
ESP examples are based on standard asio :example:`protocols/asio`:
- :example:`protocols/asio/udp_echo_server`
- :example:`protocols/asio/tcp_echo_server`
- :example:`protocols/asio/asio_chat`
- :example:`protocols/asio/ssl_client_server`
Please refer to the specific example README.md for details
* `ASIO documentation (English) <https://espressif.github.io/esp-protocols/asio/index.html>`__

Wyświetl plik

@ -94,8 +94,11 @@ ESP-Protocols components:
* `esp_websocket_client <https://components.espressif.com/component/espressif/esp_websocket_client>`_ is a managed component for `esp-idf` that contains implementation of [WebSocket protocol client](https://datatracker.ietf.org/doc/html/rfc6455) for ESP32, see the `esp_websocket_client documentation <https://espressif.github.io/esp-protocols/esp_websocket_client/index.html>`_.
* `asio <https://components.espressif.com/component/espressif/asio>`_ is a cross-platform C++ library, see https://think-async.com/Asio/. It provides a consistent asynchronous model using a modern C++ approach. , see the `asio documentation <https://espressif.github.io/esp-protocols/asio/index.html>`_.
ESP-BSP
-------
`ESP-BSP <https://github.com/espressif/esp-bsp>`_ repository contains Board Support Packages (BSPs) for various Espressif's and 3rd party development boards. BSPs are useful for quick start on a supported board. Usually they contain pinout definition and helper functions, that will initialize peripherals for the specific board. Additionally, the BSP would contain drivers for external chips populated on the development board, such as sensors, displays, audio codecs etc.

Wyświetl plik

@ -13,6 +13,7 @@ Following components are removed from ESP-IDF and moved to `IDF Component Regist
* `nghttp <https://components.espressif.com/component/espressif/nghttp>`_
* `mdns <https://components.espressif.com/component/espressif/mdns>`_
* `esp_websocket_client <https://components.espressif.com/component/espressif/esp_websocket_client>`_
* `asio <https://components.espressif.com/component/espressif/asio>`_
* `freemodbus <https://components.espressif.com/component/espressif/esp-modbus>`_
.. note:: Please note that http parser functionality which was previously part of ``nghttp`` component is now part of :component:`http_parser <http_parser>` component.

Wyświetl plik

@ -1 +1 @@
.. include:: ../../../en/api-reference/protocols/asio.rst
.. include:: ../../../en/api-reference/protocols/asio.rst

Wyświetl plik

@ -1,10 +0,0 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
# (Not part of the boilerplate)
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(asio_chat)

Wyświetl plik

@ -1,65 +0,0 @@
| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 | ESP32-C3 |
| ----------------- | ----- | -------- | -------- | -------- |
# Asio chat client and server examples
(See the README.md file in the upper level 'examples' directory for more information about examples.)
The application aims to demonstrate a simple use of Asio library in different modes.
In project settings it could be configured to run either a Asio chat server, a Asio chat client, or both.
## How to use example
The example is configured by default as an Asio chat client.
Note that the example uses string representation of IP addresses and ports.
You can find the upstream asio chat implementation [here] https://github.com/chriskohlhoff/asio/tree/master/asio/src/examples/cpp11/chat
### Asio Client
In the client mode, the example connects to the configured address, sends the message, which was inserted as an input in the terminal, and receives a response.
### Asio Server
In the server mode, Asio chat server with a specified port number is created and being polled till a connection request from the client arrives.
Chat server echoes a message (received from any client) to all connected clients.
## Configure the project
```
idf.py menuconfig
```
Set following parameters under Example Configuration Options:
* Set `EXAMPLE_CHAT_SERVER` to use the example as an ASIO chat server
* Configure `EXAMPLE_CHAT_SERVER_BIND_PORT` to the port number.
* Set `EXAMPLE_CHAT_CLIENT` to use the example as an ASIO chat client
* Configure `EXAMPLE_CHAT_CLIENT_CONNECT_ADDRESS` to a string representation of the address to connect the client to.
* Configure `EXAMPLE_CHAT_CLIENT_CONNECT_PORT` to the port number.
* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more d etails.
## Running the example in server mode
- Configure the example according "Configure the project" section.
- Run `idf.py -p PORT flash monitor` to build and upload the example to your board and connect to it's serial terminal.
- Wait for the board to connect to WiFi or Ethernet (note the IP address).
- Connect to the server using multiple clients, for example using any option below.
- build and run asio chat client on your host machine
- run chat_client asio example on ESP platform
- since chat messages consists of ASCII size and message, it is possible to
netcat `nc IP PORT` and type for example ` 4ABC<CR>` to transmit 'ABC\n'
## Running the example in client mode
- Configure the example according "Configure the project" section.
- Start chat server either on host machine or as another ESP device running chat_server example.
- Run `idf.py -p PORT flash monitor` to build and upload the example to your board and connect to it's serial terminal.
- Wait for the board to connect to WiFi or Ethernet.
- Receive and send messages to/from other clients on stdin/stdout via serial terminal.
See the README.md file in the upper level 'examples' directory for more information about examples.

Wyświetl plik

@ -1,29 +0,0 @@
# This example code is in the Public Domain (or CC0 licensed, at your option.)
# Unless required by applicable law or agreed to in writing, this
# software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied.
# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals
import re
import ttfw_idf
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC')
def test_examples_asio_chat(env, _): # type: (ttfw_idf.TinyFW.Env, None) -> None
msg = 'asio-chat: received hi'
dut = env.get_dut('asio_chat', 'examples/protocols/asio/asio_chat')
# start the test and expect the client to receive back it's original data
dut.start_app()
dut.expect(re.compile(r'{}'.format('Waiting for input')), timeout=30)
dut.write(msg)
dut.write('exit')
dut.expect(re.compile(r'{}'.format(msg)), timeout=30)
if __name__ == '__main__':
test_examples_asio_chat()

Wyświetl plik

@ -1,2 +0,0 @@
idf_component_register(SRCS "asio_chat.cpp"
INCLUDE_DIRS ".")

Wyświetl plik

@ -1,39 +0,0 @@
menu "Example Configuration"
config EXAMPLE_CHAT_SERVER
bool "Asio example chat server"
default n
help
This example will setup a chat server, binds it to the specified address
and starts listening.
if EXAMPLE_CHAT_SERVER
config EXAMPLE_CHAT_SERVER_BIND_PORT
string "Asio example server bind port"
default "3344"
help
Server listener's socket would be bound to this port.
endif
config EXAMPLE_CHAT_CLIENT
bool "Asio example chat client"
default y
help
This example will setup an asio chat client.
and sends the data.
if EXAMPLE_CHAT_CLIENT
config EXAMPLE_CHAT_CLIENT_CONNECT_ADDRESS
string "Client connection address"
default "192.168.0.1"
help
Client's socket would connect to this address/host.
config EXAMPLE_CHAT_CLIENT_CONNECT_PORT
string "Client connection port"
default "3344"
help
Client's connection port.
endif
endmenu

Wyświetl plik

@ -1,119 +0,0 @@
/* ASIO chat server client example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include "protocol_examples_common.h"
#include "esp_log.h"
#include "esp_event.h"
#include "nvs_flash.h"
#include "server.hpp"
#include "client.hpp"
#include <thread>
#include <pthread.h>
using asio::ip::tcp;
static const char *TAG = "asio-chat";
// This variable is necessary for `python test` execution, it provides synchronisation between server/client(as server should be started before client)
std::mutex server_ready;
#ifdef CONFIG_EXAMPLE_CHAT_CLIENT
static void get_string(char *line, size_t size)
{
int count = 0;
while (count < size) {
int c = fgetc(stdin);
if (c == '\n') {
line[count] = '\0';
break;
} else if (c > 0 && c < 127) {
line[count] = c;
++count;
}
vTaskDelay(10 / portTICK_PERIOD_MS);
}
}
void start_client(void)
{
const std::string port(CONFIG_EXAMPLE_CHAT_CLIENT_CONNECT_PORT);
const std::string name(CONFIG_EXAMPLE_CHAT_CLIENT_CONNECT_ADDRESS);
asio::io_context io_context;
char line[128];
tcp::resolver resolver(io_context);
auto endpoints = resolver.resolve(name, port);
chat_client c(io_context, endpoints);
#ifdef CONFIG_EXAMPLE_CHAT_SERVER
std::lock_guard<std::mutex> guard(server_ready);
#endif
std::thread t([&io_context]() { try {
io_context.run();
} catch (const std::exception &e) {
ESP_LOGE(TAG, "Exception occured during client thread execution %s", e.what());
}
catch (...) {
ESP_LOGE(TAG, "Unknown exception");
}});
do {
ESP_LOGI(TAG, "CLIENT: Waiting for input");
get_string(line, sizeof(line));
chat_message msg;
msg.body_length(std::strlen(line));
std::memcpy(msg.body(), line, msg.body_length());
msg.encode_header();
c.write(msg);
sleep(1);
} while (strcmp(line, "exit") != 0);
c.close();
t.join();
}
#endif // CONFIG_EXAMPLE_CHAT_CLIENT
extern "C" void app_main(void)
{
ESP_ERROR_CHECK(nvs_flash_init());
esp_netif_init();
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
try {
#ifdef CONFIG_EXAMPLE_CHAT_SERVER
asio::io_context io_context;
chat_server server(io_context, tcp::endpoint(tcp::v4(), std::atoi(CONFIG_EXAMPLE_CHAT_SERVER_BIND_PORT)));
std::thread t = std::thread([&io_context]() { // Chat server starting here
try {
io_context.run();
} catch (const std::exception &e) {
ESP_LOGE(TAG, "Exception occured during server thread execution %s", e.what());
}
catch (...) {
ESP_LOGE(TAG, "Unknown exception");
}});;
#endif
#ifdef CONFIG_EXAMPLE_CHAT_CLIENT
start_client();
#endif
#ifdef CONFIG_EXAMPLE_CHAT_SERVER
t.join();
#endif
} catch (const std::exception &e) {
ESP_LOGE(TAG, "Exception occured during run %s", e.what());
} catch (...) {
ESP_LOGE(TAG, "Unknown exception");
}
ESP_ERROR_CHECK(example_disconnect());
}

Wyświetl plik

@ -1,91 +0,0 @@
//
// chat_message.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef CHAT_MESSAGE_HPP
#define CHAT_MESSAGE_HPP
#include <cstdio>
#include <cstdlib>
#include <cstring>
class chat_message
{
public:
static constexpr std::size_t header_length = 4;
static constexpr std::size_t max_body_length = 512;
chat_message()
: body_length_(0)
{
}
const char* data() const
{
return data_;
}
char* data()
{
return data_;
}
std::size_t length() const
{
return header_length + body_length_;
}
const char* body() const
{
return data_ + header_length;
}
char* body()
{
return data_ + header_length;
}
std::size_t body_length() const
{
return body_length_;
}
void body_length(std::size_t new_length)
{
body_length_ = new_length;
if (body_length_ > max_body_length)
body_length_ = max_body_length;
}
bool decode_header()
{
char header[header_length + 1] = "";
std::strncat(header, data_, header_length);
body_length_ = std::atoi(header);
if (body_length_ > max_body_length)
{
body_length_ = 0;
return false;
}
return true;
}
void encode_header()
{
char header[header_length + 1] = "";
std::sprintf(header, "%4d", static_cast<int>(body_length_));
std::memcpy(data_, header, header_length);
}
private:
char data_[header_length + max_body_length];
std::size_t body_length_;
};
#endif // CHAT_MESSAGE_HPP

Wyświetl plik

@ -1,126 +0,0 @@
//
// client.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef CHAT_CLIENT_HPP
#define CHAT_CLIENT_HPP
#include <deque>
#include "asio.hpp"
#include "chat_message.hpp"
typedef std::deque<chat_message> chat_message_queue;
class chat_client
{
public:
chat_client(asio::io_context& io_context,
const asio::ip::tcp::resolver::results_type& endpoints)
: io_context_(io_context),
socket_(io_context)
{
do_connect(endpoints);
}
void write(const chat_message& msg)
{
asio::post(io_context_,
[this, msg]()
{
bool write_in_progress = !write_msgs_.empty();
write_msgs_.push_back(msg);
if (!write_in_progress)
{
do_write();
}
});
}
void close()
{
asio::post(io_context_, [this]() { socket_.close(); });
}
private:
void do_connect(const asio::ip::tcp::resolver::results_type& endpoints)
{
asio::async_connect(socket_, endpoints,
[this](std::error_code ec, asio::ip::tcp::endpoint)
{
if (!ec)
{
do_read_header();
}
});
}
void do_read_header()
{
asio::async_read(socket_,
asio::buffer(read_msg_.data(), chat_message::header_length),
[this](std::error_code ec, std::size_t /*length*/)
{
if (!ec && read_msg_.decode_header())
{
do_read_body();
}
else
{
socket_.close();
}
});
}
void do_read_body()
{
asio::async_read(socket_,
asio::buffer(read_msg_.body(), read_msg_.body_length()),
[this](std::error_code ec, std::size_t /*length*/)
{
if (!ec)
{
do_read_header();
}
else
{
socket_.close();
}
});
}
void do_write()
{
asio::async_write(socket_,
asio::buffer(write_msgs_.front().data(),
write_msgs_.front().length()),
[this](std::error_code ec, std::size_t /*length*/)
{
if (!ec)
{
write_msgs_.pop_front();
if (!write_msgs_.empty())
{
do_write();
}
}
else
{
socket_.close();
}
});
}
private:
asio::io_context& io_context_;
asio::ip::tcp::socket socket_;
chat_message read_msg_;
chat_message_queue write_msgs_;
};
#endif // CHAT_CLIENT_HPP

Wyświetl plik

@ -1,202 +0,0 @@
//
// server.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef CHAT_SERVER_HPP
#define CHAT_SERVER_HPP
#include <list>
#include <set>
#include <deque>
#include <utility>
#include "asio.hpp"
#include "chat_message.hpp"
//----------------------------------------------------------------------
typedef std::deque<chat_message> chat_message_queue;
extern std::mutex server_ready;
//----------------------------------------------------------------------
class chat_participant
{
public:
virtual ~chat_participant() {}
virtual void deliver(const chat_message& msg) = 0;
};
typedef std::shared_ptr<chat_participant> chat_participant_ptr;
//----------------------------------------------------------------------
class chat_room
{
public:
void join(chat_participant_ptr participant)
{
participants_.insert(participant);
for (auto msg: recent_msgs_)
participant->deliver(msg);
}
void leave(chat_participant_ptr participant)
{
participants_.erase(participant);
}
void deliver(const chat_message& msg)
{
recent_msgs_.push_back(msg);
while (recent_msgs_.size() > max_recent_msgs)
recent_msgs_.pop_front();
for (auto participant: participants_)
participant->deliver(msg);
}
private:
std::set<chat_participant_ptr> participants_;
enum { max_recent_msgs = 100 };
chat_message_queue recent_msgs_;
};
//----------------------------------------------------------------------
class chat_session
: public chat_participant,
public std::enable_shared_from_this<chat_session>
{
public:
chat_session(asio::ip::tcp::socket socket, chat_room& room)
: socket_(std::move(socket)),
room_(room)
{
}
void start()
{
room_.join(shared_from_this());
do_read_header();
}
void deliver(const chat_message& msg)
{
bool write_in_progress = !write_msgs_.empty();
write_msgs_.push_back(msg);
if (!write_in_progress)
{
do_write();
}
}
private:
void do_read_header()
{
auto self(shared_from_this());
asio::async_read(socket_,
asio::buffer(read_msg_.data(), chat_message::header_length),
[this, self](std::error_code ec, std::size_t /*length*/)
{
if (!ec && read_msg_.decode_header())
{
do_read_body();
}
else
{
room_.leave(shared_from_this());
}
});
}
void do_read_body()
{
auto self(shared_from_this());
asio::async_read(socket_,
asio::buffer(read_msg_.body(), read_msg_.body_length()),
[this, self](std::error_code ec, std::size_t /*length*/)
{
if (!ec)
{
ESP_LOGD("asio-chat:", "%s", read_msg_.body());
room_.deliver(read_msg_);
do_read_header();
}
else
{
room_.leave(shared_from_this());
}
});
}
void do_write()
{
auto self(shared_from_this());
asio::async_write(socket_,
asio::buffer(write_msgs_.front().data(),
write_msgs_.front().length()),
[this, self](std::error_code ec, std::size_t /*length*/)
{
if (!ec)
{
write_msgs_.pop_front();
if (!write_msgs_.empty())
{
do_write();
}
}
else
{
room_.leave(shared_from_this());
}
});
}
asio::ip::tcp::socket socket_;
chat_room& room_;
chat_message read_msg_;
chat_message_queue write_msgs_;
};
//----------------------------------------------------------------------
class chat_server
{
public:
chat_server(asio::io_context& io_context,
const asio::ip::tcp::endpoint& endpoint)
: acceptor_(io_context, endpoint)
{
do_accept();
}
private:
void do_accept()
{
std::lock_guard<std::mutex> guard(server_ready);
acceptor_.async_accept(
[this](std::error_code ec, asio::ip::tcp::socket socket)
{
if (!ec)
{
std::make_shared<chat_session>(std::move(socket), room_)->start();
}
do_accept();
});
}
asio::ip::tcp::acceptor acceptor_;
chat_room room_;
};
#endif // CHAT_SERVER_HPP

Wyświetl plik

@ -1,6 +0,0 @@
CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_CONNECT_ETHERNET=n
CONFIG_EXAMPLE_CHAT_CLIENT=y
CONFIG_EXAMPLE_CHAT_SERVER=y
CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y
CONFIG_EXAMPLE_CHAT_CLIENT_CONNECT_ADDRESS="localhost"

Wyświetl plik

@ -1,2 +0,0 @@
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
CONFIG_COMPILER_CXX_EXCEPTIONS=y

Wyświetl plik

@ -1,10 +0,0 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
# (Not part of the boilerplate)
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(async_http_request)

Wyświetl plik

@ -1,52 +0,0 @@
| Supported Targets | ESP32 |
| ----------------- | ----- |
# Async request using ASIO
(See the README.md file in the upper level 'examples' directory for more information about examples.)
The application aims to show how to compose async operations using ASIO to build network protocols and operations.
# Configure and Building example
This example doesn't require any configuration, just build it with
```
idf.py build
```
# Async operations composition and automatic lifetime control
On this example we compose the operation by starting the next step in the chain inside the completion handler of the
previous operation. Also we pass the `Connection` class itself as the parameter of its final handler to be owned by
the following operation. This is possible due to the control of lifetime by the usage of `std::shared_ptr`.
The control of lifetime of the class, done by `std::shared_ptr` usage, guarantee that the data will be available for
async operations until it's not needed any more. This makes necessary that all of the async operation class must start
its lifetime as a `std::shared_ptr` due to the usage of `std::enable_shared_from_this`.
User creates a shared_ptr──┐
of AddressResolution and │
ask for resolve. │
The handler for the ┌▼─────────────────────┐
complete operation is sent│ AddressResolution │ In the completion of resolve a connection is created.
└─────────────────┬────┘ AddressResolution is automaticly destroyed since it's
│ no longer needed
┌─▼────────────────────────────────────┐
│ Connection │
└──────┬───────────────────────────────┘
Http::Session is created once we have a Connection. │
Connection is passed to Http::Session that holds it │
avoiding it's destruction. │
┌─▼───────────────────────────────┐
│ Http::Session │
└────────┬────────────────────────┘
After the HTTP request is │
sent the completion handler │
is called. │
└────►Completion Handler()
The previous diagram shows the process and the life span of each of the tasks in this examples. At each stage the
object responsible for the last action inject itself to the completion handler of the next stage for reuse.

Wyświetl plik

@ -1,2 +0,0 @@
idf_component_register(SRCS "async_http_request.cpp"
INCLUDE_DIRS ".")

Wyświetl plik

@ -1,369 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*
* ASIO HTTP request example
*/
#include <string>
#include <array>
#include <asio.hpp>
#include <memory>
#include <system_error>
#include <utility>
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_event.h"
#include "protocol_examples_common.h"
constexpr auto TAG = "async_request";
using asio::ip::tcp;
namespace {
void esp_init()
{
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_log_level_set("async_request", ESP_LOG_DEBUG);
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
}
/**
* @brief Simple class to add the resolver to a chain of actions
*
*/
class AddressResolution : public std::enable_shared_from_this<AddressResolution> {
public:
explicit AddressResolution(asio::io_context &context) : ctx(context), resolver(ctx) {}
/**
* @brief Initiator function for the address resolution
*
* @tparam CompletionToken callable responsible to use the results.
*
* @param host Host address
* @param port Port for the target, must be number due to a limitation on lwip.
*/
template<class CompletionToken>
void resolve(const std::string &host, const std::string &port, CompletionToken &&completion_handler)
{
auto self(shared_from_this());
resolver.async_resolve(host, port, [self, completion_handler](const asio::error_code & error, tcp::resolver::results_type results) {
if (error) {
ESP_LOGE(TAG, "Failed to resolve: %s", error.message().c_str());
return;
}
completion_handler(self, results);
});
}
private:
asio::io_context &ctx;
tcp::resolver resolver;
};
/**
* @brief Connection class
*
* The lowest level dependency on our asynchronous task, Connection provide an interface to TCP sockets.
* A similar class could be provided for a TLS connection.
*
* @note: All read and write operations are written on an explicit strand, even though an implicit strand
* occurs in this example since we run the io context in a single task.
*
*/
class Connection : public std::enable_shared_from_this<Connection> {
public:
explicit Connection(asio::io_context &context) : ctx(context), strand(context), socket(ctx) {}
/**
* @brief Start the connection
*
* Async operation to start a connection. As the final act of the process the Connection class pass a
* std::shared_ptr of itself to the completion_handler.
* Since it uses std::shared_ptr as an automatic control of its lifetime this class must be created
* through a std::make_shared call.
*
* @tparam completion_handler A callable to act as the final handler for the process.
* @param host host address
* @param port port number - due to a limitation on lwip implementation this should be the number not the
* service name typically seen in ASIO examples.
*
* @note The class could be modified to store the completion handler, as a member variable, instead of
* pass it along asynchronous calls to allow the process to run again completely.
*
*/
template<class CompletionToken>
void start(tcp::resolver::results_type results, CompletionToken &&completion_handler)
{
connect(results, completion_handler);
}
/**
* @brief Start an async write on the socket
*
* @tparam data
* @tparam completion_handler A callable to act as the final handler for the process.
*
*/
template<class DataType, class CompletionToken>
void write_async(const DataType &data, CompletionToken &&completion_handler)
{
asio::async_write(socket, data, asio::bind_executor(strand, completion_handler));
}
/**
* @brief Start an async read on the socket
*
* @tparam data
* @tparam completion_handler A callable to act as the final handler for the process.
*
*/
template<class DataBuffer, class CompletionToken>
void read_async(DataBuffer &&in_data, CompletionToken &&completion_handler)
{
asio::async_read(socket, in_data, asio::bind_executor(strand, completion_handler));
}
private:
template<class CompletionToken>
void connect(tcp::resolver::results_type results, CompletionToken &&completion_handler)
{
auto self(shared_from_this());
asio::async_connect(socket, results, [self, completion_handler](const asio::error_code & error, [[maybe_unused]] const tcp::endpoint & endpoint) {
if (error) {
ESP_LOGE(TAG, "Failed to connect: %s", error.message().c_str());
return;
}
completion_handler(self);
});
}
asio::io_context &ctx;
asio::io_context::strand strand;
tcp::socket socket;
};
} // namespace
namespace Http {
enum class Method { GET };
/**
* @brief Simple HTTP request class
*
* The user needs to write the request information direct to header and body fields.
*
* Only GET verb is provided.
*
*/
class Request {
public:
Request(Method method, std::string host, std::string port, const std::string &target) : host_data(std::move(host)), port_data(std::move(port))
{
header_data.append("GET ");
header_data.append(target);
header_data.append(" HTTP/1.1");
header_data.append("\r\n");
header_data.append("Host: ");
header_data.append(host_data);
header_data.append("\r\n");
header_data.append("\r\n");
};
void set_header_field(std::string const &field)
{
header_data.append(field);
}
void append_to_body(std::string const &data)
{
body_data.append(data);
};
const std::string &host() const
{
return host_data;
}
const std::string &service_port() const
{
return port_data;
}
const std::string &header() const
{
return header_data;
}
const std::string &body() const
{
return body_data;
}
private:
std::string host_data;
std::string port_data;
std::string header_data;
std::string body_data;
};
/**
* @brief Simple HTTP response class
*
* The response is built from received data and only parsed to split header and body.
*
* A copy of the received data is kept.
*
*/
struct Response {
/**
* @brief Construct a response from a contiguous buffer.
*
* Simple http parsing.
*
*/
template<class DataIt>
explicit Response(DataIt data, size_t size)
{
raw_response = std::string(data, size);
auto header_last = raw_response.find("\r\n\r\n");
if (header_last != std::string::npos) {
header = raw_response.substr(0, header_last);
}
body = raw_response.substr(header_last + 3);
}
/**
* @brief Print response content.
*/
void print()
{
ESP_LOGI(TAG, "Header :\n %s", header.c_str());
ESP_LOGI(TAG, "Body : \n %s", body.c_str());
}
std::string raw_response;
std::string header;
std::string body;
};
/** @brief HTTP Session
*
* Session class to handle HTTP protocol implementation.
*
*/
class Session : public std::enable_shared_from_this<Session> {
public:
explicit Session(std::shared_ptr<Connection> connection_in) : connection(std::move(connection_in))
{
}
template<class CompletionToken>
void send_request(const Request &request, CompletionToken &&completion_handler)
{
auto self = shared_from_this();
send_data = { asio::buffer(request.header()), asio::buffer(request.body()) };
connection->write_async(send_data, [self, &completion_handler](std::error_code error, std::size_t bytes_transfered) {
if (error) {
ESP_LOGE(TAG, "Request write error: %s", error.message().c_str());
return;
}
ESP_LOGD(TAG, "Bytes Transfered: %d", bytes_transfered);
self->get_response(completion_handler);
});
}
private:
template<class CompletionToken>
void get_response(CompletionToken &&completion_handler)
{
auto self = shared_from_this();
connection->read_async(asio::buffer(receive_buffer), [self, &completion_handler](std::error_code error, std::size_t bytes_received) {
if (error and error.value() != asio::error::eof) {
return;
}
ESP_LOGD(TAG, "Bytes Received: %d", bytes_received);
if (bytes_received == 0) {
return;
}
Response response(std::begin(self->receive_buffer), bytes_received);
completion_handler(self, response);
});
}
/*
* For this example we assumed 2048 to be enough for the receive_buffer
*/
std::array<char, 2048> receive_buffer;
/*
* The hardcoded 2 below is related to the type we receive the data to send. We gather the parts from Request, header
* and body, to send avoiding the copy.
*/
std::array<asio::const_buffer, 2> send_data;
std::shared_ptr<Connection> connection;
};
/** @brief Execute a fully async HTTP request
*
* @tparam completion_handler
* @param ctx io context
* @param request
*
* @note : We build this function as a simpler interface to compose the operations of connecting to
* the address and running the HTTP session. The Http::Session class is injected to the completion handler
* for further use.
*/
template<class CompletionToken>
void request_async(asio::io_context &context, const Request &request, CompletionToken &&completion_handler)
{
/*
* The first step is to resolve the address we want to connect to.
* The AddressResolution itself is injected to the completion handler.
*
* This shared_ptr is destroyed by the end of the scope. Pay attention that this is a non blocking function
* the lifetime of the object is extended by the resolve call
*/
std::make_shared<AddressResolution>(context)->resolve(request.host(), request.service_port(),
[&context, &request, completion_handler](std::shared_ptr<AddressResolution> resolver, tcp::resolver::results_type results) {
/* After resolution we create a Connection.
* The completion handler gets a shared_ptr<Connection> to receive the connection, once the
* connection process is complete.
*/
std::make_shared<Connection>(context)->start(results,
[&request, completion_handler](std::shared_ptr<Connection> connection) {
// Now we create a HTTP::Session and inject the necessary connection.
std::make_shared<Session>(connection)->send_request(request, completion_handler);
});
});
}
}// namespace Http
extern "C" void app_main(void)
{
// Basic initialization of ESP system
esp_init();
asio::io_context io_context;
Http::Request request(Http::Method::GET, "www.httpbin.org", "80", "/get");
Http::request_async(io_context, request, [](std::shared_ptr<Http::Session> session, Http::Response response) {
/*
* We only print the response here but could reuse session for other requests.
*/
response.print();
});
// io_context.run will block until all the tasks on the context are done.
io_context.run();
ESP_LOGI(TAG, "Context run done");
ESP_ERROR_CHECK(example_disconnect());
}

Wyświetl plik

@ -1,10 +0,0 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
# (Not part of the boilerplate)
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(asio_sock4)

Wyświetl plik

@ -1,73 +0,0 @@
| Supported Targets | ESP32 | ESP32-S2 |
| ----------------- | ----- | ----- |
# Async request using ASIO
(See the README.md file in the upper level 'examples' directory for more information about examples.)
The application aims to show how to connect to a Socks4 proxy using async operations with ASIO. The SOCKS protocol is
briefly described by the diagram below.
┌──────┐ ┌─────┐ ┌──────┐
│Client│ │Proxy│ │Target│
└──┬───┘ └──┬──┘ └──┬───┘
│ │ │
│ ╔═╧══════════════╗ │
══════════════════════╪════════════════════════╣ Initialization ╠═══╪════════════════════════════════════════════
│ ╚═╤══════════════╝ │
│ │ │
╔══════════════════╗│ │ │
║We establish a ░║│ Socket Connection │ │
║TCP connection ║│ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ > │
║and get a socket ║│ │ │
╚══════════════════╝│ │ │
│ │ │
│ ╔═╧══════════════╗ │
══════════════════════╪════════════════════════╣ Socks Protocol ╠═══╪════════════════════════════════════════════
│ ╚═╤══════════════╝ │
│ │ │
│ Client Connection Request│ │
│ ─────────────────────────> │
│ │ │
│ │ │
│ ╔════════════╪═══════╤══════════╪════════════════════════════════╗
│ ║ TARGET CONNECTION │ │ ║
│ ╟────────────────────┘ │ ╔═══════════════════╗ ║
│ ║ │ Socket Connection│ ║Proxy establishes ░║ ║
│ ║ │ <─ ─ ─ ─ ─ ─ ─ ─ > ║ TCPconnection ║ ║
│ ║ │ │ ║ with target host ║ ║
│ ╚════════════╪══════════════════╪══╚═══════════════════╝═════════╝
│ │ │
│ Response packet │ │
<───────────────────────── │
│ │ │
│ │ │
│ │ ╔═══════╗ │
══════════════════════╪══════════════════════════╪══╣ Usage ╠═══════╪════════════════════════════════════════════
│ │ ╚═══════╝ │
│ │ │
╔═════════════════╗│ │ │
║Client uses the ░║│ │ │
║ socket opened ║│ │ │
║ with proxy ║│ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─>
║to communicate ║│ │ │
║ ║│ │ │
╚═════════════════╝┴───┐ ┌──┴──┐ ┌──┴───┐
│Client│ │Proxy│ │Target│
└──────┘ └─────┘ └──────┘
# Configure and Building example
This example requires the proxy address to be configured. You can do this using the menuconfig option.
Proxy address and port must be configured in order for this example to work.
If using Linux ssh can be used as a proxy for testing.
```
ssh -N -v -D 0.0.0.0:1080 localhost
```
# Async operations composition and automatic lifetime control
For documentation about the structure of this example look into [async\_request README](../async_request/README.md).

Wyświetl plik

@ -1,2 +0,0 @@
idf_component_register(SRCS "socks4.cpp"
INCLUDE_DIRS ".")

Wyświetl plik

@ -1,16 +0,0 @@
menu "Example Configuration"
config EXAMPLE_PROXY_ADDRESS
string "Proxy address"
default "myproxy"
help
Address of the proxy to be used.
config EXAMPLE_PROXY_SERVICE
string "Proxy Service Type"
default "myport"
help
Service type. Due to a limitation of lwip, must
be the port number e.g. "1080".
endmenu

Wyświetl plik

@ -1,393 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*
*
* ASIO Socks4 example
*/
#include <string>
#include <array>
#include <asio.hpp>
#include <memory>
#include <system_error>
#include <utility>
#include "esp_log.h"
#include "socks4.hpp"
#include "nvs_flash.h"
#include "esp_event.h"
#include "protocol_examples_common.h"
constexpr auto TAG = "asio_socks4";
using asio::ip::tcp;
namespace {
void esp_init()
{
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_log_level_set("async_request", ESP_LOG_DEBUG);
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
}
/**
* @brief Simple class to add the resolver to a chain of actions
*
*/
class AddressResolution : public std::enable_shared_from_this<AddressResolution> {
public:
explicit AddressResolution(asio::io_context &context) : ctx(context), resolver(ctx) {}
/**
* @brief Initiator function for the address resolution
*
* @tparam CompletionToken callable responsible to use the results.
*
* @param host Host address
* @param port Port for the target, must be number due to a limitation on lwip.
*/
template<class CompletionToken>
void resolve(const std::string &host, const std::string &port, CompletionToken &&completion_handler)
{
auto self(shared_from_this());
resolver.async_resolve(host, port, [self, completion_handler](const asio::error_code & error, tcp::resolver::results_type results) {
if (error) {
ESP_LOGE(TAG, "Failed to resolve: %s", error.message().c_str());
return;
}
completion_handler(self, results);
});
}
private:
asio::io_context &ctx;
tcp::resolver resolver;
};
/**
* @brief Connection class
*
* The lowest level dependency on our asynchronous task, Connection provide an interface to TCP sockets.
* A similar class could be provided for a TLS connection.
*
* @note: All read and write operations are written on an explicit strand, even though an implicit strand
* occurs in this example since we run the io context in a single task.
*
*/
class Connection : public std::enable_shared_from_this<Connection> {
public:
explicit Connection(asio::io_context &context) : ctx(context), strand(context), socket(ctx) {}
/**
* @brief Start the connection
*
* Async operation to start a connection. As the final act of the process the Connection class pass a
* std::shared_ptr of itself to the completion_handler.
* Since it uses std::shared_ptr as an automatic control of its lifetime this class must be created
* through a std::make_shared call.
*
* @tparam completion_handler A callable to act as the final handler for the process.
* @param host host address
* @param port port number - due to a limitation on lwip implementation this should be the number not the
* service name typically seen in ASIO examples.
*
* @note The class could be modified to store the completion handler, as a member variable, instead of
* pass it along asynchronous calls to allow the process to run again completely.
*
*/
template<class CompletionToken>
void start(tcp::resolver::results_type results, CompletionToken &&completion_handler)
{
connect(results, completion_handler);
}
/**
* @brief Start an async write on the socket
*
* @tparam data
* @tparam completion_handler A callable to act as the final handler for the process.
*
*/
template<class DataType, class CompletionToken>
void write_async(const DataType &data, CompletionToken &&completion_handler)
{
asio::async_write(socket, data, asio::bind_executor(strand, completion_handler));
}
/**
* @brief Start an async read on the socket
*
* @tparam data
* @tparam completion_handler A callable to act as the final handler for the process.
*
*/
template<class DataBuffer, class CompletionToken>
void read_async(DataBuffer &&in_data, CompletionToken &&completion_handler)
{
asio::async_read(socket, in_data, asio::bind_executor(strand, completion_handler));
}
private:
template<class CompletionToken>
void connect(tcp::resolver::results_type results, CompletionToken &&completion_handler)
{
auto self(shared_from_this());
asio::async_connect(socket, results, [self, completion_handler](const asio::error_code & error, [[maybe_unused]] const tcp::endpoint & endpoint) {
if (error) {
ESP_LOGE(TAG, "Failed to connect: %s", error.message().c_str());
return;
}
completion_handler(self);
});
}
asio::io_context &ctx;
asio::io_context::strand strand;
tcp::socket socket;
};
}
namespace Socks {
struct ConnectionData {
ConnectionData(socks4::request::command_type cmd, const asio::ip::tcp::endpoint &endpoint,
const std::string &user_id) : request(cmd, endpoint, user_id) {};
socks4::request request;
socks4::reply reply;
};
template<class CompletionToken>
void async_connect(asio::io_context &context, std::string proxy, std::string proxy_port, std::string host, std::string port, CompletionToken &&completion_handler)
{
/*
* The first step is to resolve the address of the proxy we want to connect to.
* The AddressResolution itself is injected to the completion handler.
*/
// Resolve proxy
std::make_shared<AddressResolution>(context)->resolve(proxy, proxy_port,
[&context, host, port, completion_handler](std::shared_ptr<AddressResolution> resolver, tcp::resolver::results_type proxy_resolution) {
// We also need to resolve the target host address
resolver->resolve(host, port, [&context, proxy_resolution, completion_handler](std::shared_ptr<AddressResolution> resolver, tcp::resolver::results_type host_resolution) {
// Make connection with the proxy
ESP_LOGI(TAG, "Startig Proxy Connection");
std::make_shared<Connection>(context)->start(proxy_resolution,
[resolver, host_resolution, completion_handler](std::shared_ptr<Connection> connection) {
auto connect_data = std::make_shared<ConnectionData>(socks4::request::connect, *host_resolution, "");
ESP_LOGI(TAG, "Sending Request to proxy for host connection.");
connection->write_async(connect_data->request.buffers(), [connection, connect_data, completion_handler](std::error_code error, std::size_t bytes_received) {
if (error) {
ESP_LOGE(TAG, "Proxy request write error: %s", error.message().c_str());
return;
}
connection->read_async(connect_data->reply.buffers(), [connection, connect_data, completion_handler](std::error_code error, std::size_t bytes_received) {
if (error) {
ESP_LOGE(TAG, "Proxy response read error: %s", error.message().c_str());
return;
}
if (!connect_data->reply.success()) {
ESP_LOGE(TAG, "Proxy error: %#x", connect_data->reply.status());
}
completion_handler(connection);
});
});
});
});
});
}
} // namespace Socks
namespace Http {
enum class Method { GET };
/**
* @brief Simple HTTP request class
*
* The user needs to write the request information direct to header and body fields.
*
* Only GET verb is provided.
*
*/
class Request {
public:
Request(Method method, std::string host, std::string port, const std::string &target) : host_data(std::move(host)), port_data(std::move(port))
{
header_data.append("GET ");
header_data.append(target);
header_data.append(" HTTP/1.1");
header_data.append("\r\n");
header_data.append("Host: ");
header_data.append(host_data);
header_data.append("\r\n");
header_data.append("\r\n");
};
void set_header_field(std::string const &field)
{
header_data.append(field);
}
void append_to_body(std::string const &data)
{
body_data.append(data);
};
const std::string &host() const
{
return host_data;
}
const std::string &service_port() const
{
return port_data;
}
const std::string &header() const
{
return header_data;
}
const std::string &body() const
{
return body_data;
}
private:
std::string host_data;
std::string port_data;
std::string header_data;
std::string body_data;
};
/**
* @brief Simple HTTP response class
*
* The response is built from received data and only parsed to split header and body.
*
* A copy of the received data is kept.
*
*/
struct Response {
/**
* @brief Construct a response from a contiguous buffer.
*
* Simple http parsing.
*
*/
template<class DataIt>
explicit Response(DataIt data, size_t size)
{
raw_response = std::string(data, size);
auto header_last = raw_response.find("\r\n\r\n");
if (header_last != std::string::npos) {
header = raw_response.substr(0, header_last);
}
body = raw_response.substr(header_last + 3);
}
/**
* @brief Print response content.
*/
void print()
{
ESP_LOGI(TAG, "Header :\n %s", header.c_str());
ESP_LOGI(TAG, "Body : \n %s", body.c_str());
}
std::string raw_response;
std::string header;
std::string body;
};
/** @brief HTTP Session
*
* Session class to handle HTTP protocol implementation.
*
*/
class Session : public std::enable_shared_from_this<Session> {
public:
explicit Session(std::shared_ptr<Connection> connection_in) : connection(std::move(connection_in))
{
}
template<class CompletionToken>
void send_request(const Request &request, CompletionToken &&completion_handler)
{
auto self = shared_from_this();
send_data = { asio::buffer(request.header()), asio::buffer(request.body()) };
connection->write_async(send_data, [self, &completion_handler](std::error_code error, std::size_t bytes_transfered) {
if (error) {
ESP_LOGE(TAG, "Request write error: %s", error.message().c_str());
return;
}
ESP_LOGD(TAG, "Bytes Transfered: %d", bytes_transfered);
self->get_response(completion_handler);
});
}
private:
template<class CompletionToken>
void get_response(CompletionToken &&completion_handler)
{
auto self = shared_from_this();
connection->read_async(asio::buffer(receive_buffer), [self, &completion_handler](std::error_code error, std::size_t bytes_received) {
if (error and error.value() != asio::error::eof) {
return;
}
ESP_LOGD(TAG, "Bytes Received: %d", bytes_received);
if (bytes_received == 0) {
return;
}
Response response(std::begin(self->receive_buffer), bytes_received);
completion_handler(self, response);
});
}
/*
* For this example we assumed 2048 to be enough for the receive_buffer
*/
std::array<char, 2048> receive_buffer;
/*
* The hardcoded 2 below is related to the type we receive the data to send. We gather the parts from Request, header
* and body, to send avoiding the copy.
*/
std::array<asio::const_buffer, 2> send_data;
std::shared_ptr<Connection> connection;
};
}// namespace Http
extern "C" void app_main(void)
{
// Basic initialization of ESP system
esp_init();
asio::io_context io_context;
Http::Request request(Http::Method::GET, "www.httpbin.org", "80", "/get");
Socks::async_connect(io_context, CONFIG_EXAMPLE_PROXY_ADDRESS, CONFIG_EXAMPLE_PROXY_SERVICE, request.host(), request.service_port(),
[&request](std::shared_ptr<Connection> connection) {
// Now we create a HTTP::Session and inject the necessary connection.
std::make_shared<Http::Session>(connection)->send_request(request, [](std::shared_ptr<Http::Session> session, Http::Response response) {
response.print();
});
});
// io_context.run will block until all the tasks on the context are done.
io_context.run();
ESP_LOGI(TAG, "Context run done");
ESP_ERROR_CHECK(example_disconnect());
}

Wyświetl plik

@ -1,143 +0,0 @@
//
// socks4.hpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef SOCKS4_HPP
#define SOCKS4_HPP
#include <array>
#include <string>
#include <asio/buffer.hpp>
#include <asio/ip/tcp.hpp>
namespace socks4 {
const unsigned char version = 0x04;
class request
{
public:
enum command_type
{
connect = 0x01,
bind = 0x02
};
request(command_type cmd, const asio::ip::tcp::endpoint& endpoint,
const std::string& user_id)
: version_(version),
command_(cmd),
user_id_(user_id),
null_byte_(0)
{
// Only IPv4 is supported by the SOCKS 4 protocol.
if (endpoint.protocol() != asio::ip::tcp::v4())
{
throw asio::system_error(
asio::error::address_family_not_supported);
}
// Convert port number to network byte order.
unsigned short port = endpoint.port();
port_high_byte_ = (port >> 8) & 0xff;
port_low_byte_ = port & 0xff;
// Save IP address in network byte order.
address_ = endpoint.address().to_v4().to_bytes();
}
std::array<asio::const_buffer, 7> buffers() const
{
return
{
{
asio::buffer(&version_, 1),
asio::buffer(&command_, 1),
asio::buffer(&port_high_byte_, 1),
asio::buffer(&port_low_byte_, 1),
asio::buffer(address_),
asio::buffer(user_id_),
asio::buffer(&null_byte_, 1)
}
};
}
private:
unsigned char version_;
unsigned char command_;
unsigned char port_high_byte_;
unsigned char port_low_byte_;
asio::ip::address_v4::bytes_type address_;
std::string user_id_;
unsigned char null_byte_;
};
class reply
{
public:
enum status_type
{
request_granted = 0x5a,
request_failed = 0x5b,
request_failed_no_identd = 0x5c,
request_failed_bad_user_id = 0x5d
};
reply()
: null_byte_(0),
status_()
{
}
std::array<asio::mutable_buffer, 5> buffers()
{
return
{
{
asio::buffer(&null_byte_, 1),
asio::buffer(&status_, 1),
asio::buffer(&port_high_byte_, 1),
asio::buffer(&port_low_byte_, 1),
asio::buffer(address_)
}
};
}
bool success() const
{
return null_byte_ == 0 && status_ == request_granted;
}
unsigned char status() const
{
return status_;
}
asio::ip::tcp::endpoint endpoint() const
{
unsigned short port = port_high_byte_;
port = (port << 8) & 0xff00;
port = port | port_low_byte_;
asio::ip::address_v4 address(address_);
return asio::ip::tcp::endpoint(address, port);
}
private:
unsigned char null_byte_;
unsigned char status_;
unsigned char port_high_byte_;
unsigned char port_low_byte_;
asio::ip::address_v4::bytes_type address_;
};
} // namespace socks4
#endif // SOCKS4_HPP

Wyświetl plik

@ -1,3 +0,0 @@
CONFIG_COMPILER_CXX_EXCEPTIONS=y
CONFIG_COMPILER_CXX_RTTI=y
CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=0

Wyświetl plik

@ -1,11 +0,0 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
# (Not part of the boilerplate)
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
set(EXCLUDE_COMPONENTS openssl)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(asio_ssl_client_server)

Wyświetl plik

@ -1,88 +0,0 @@
| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 | ESP32-C3 |
| ----------------- | ----- | -------- | -------- | -------- |
# Asio SSL client/server example
Simple Asio client and server with SSL/TLS transport
## How to Use Example
### Hardware Required
This example can be executed on any ESP platform board. No external connection is required, it is recommended though
to connect to internet or a local network via WiFi or Ethernet to easily exercise features of this example.
### Configure the project
* Open the project configuration menu (`idf.py menuconfig`)
* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
* Enable the ASIO client and set server's host name to examine client's functionality.
The ASIO client connects to the configured server and sends default payload string "GET / HTTP/1.1"
* Enable the ASIO server to examine server's functionality. The ASIO server listens to connection and echos back what was received.
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py -p PORT flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example Output
### Client connecting to public server
The below output illustrates the client connecting to a public https server.
```
I (1267) example_connect: Waiting for IP(s)
I (2587) wifi:new:<11,0>, old:<1,0>, ap:<255,255>, sta:<11,0>, prof:1
I (3367) wifi:state: init -> auth (b0)
I (3377) wifi:state: auth -> assoc (0)
I (3387) wifi:state: assoc -> run (10)
I (3397) wifi:security type: 3, phy: bgn, rssi: -49
I (3397) wifi:pm start, type: 1
I (3457) wifi:AP's beacon interval = 102400 us, DTIM period = 1
I (4747) example_connect: Got IPv6 event: Interface "example_connect: sta" address: fe80:0000:0000:0000:260a:xxxx:xxxx:xxxx, type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (5247) esp_netif_handlers: example_connect: sta ip: 192.168.32.69, mask: 255.255.252.0, gw: 192.168.32.3
I (5247) example_connect: Got IPv4 event: Interface "example_connect: sta" address: 192.168.32.69
I (5257) example_connect: Connected to example_connect: sta
I (5257) example_connect: - IPv4 address: 192.168.32.69
I (5267) example_connect: - IPv6 address: fe80:0000:0000:0000:260a:xxxx:xxxx:xxxx, type: ESP_IP6_ADDR_IS_LINK_LOCAL
W (5277) esp32_asio_pthread: pthread_condattr_setclock: not yet supported!
W (5297) esp32_asio_pthread: pthread_condattr_setclock: not yet supported!
Reply: HTTP/1.1 200 OK
D
```
### Both server and client enabled
The below output demonstrates the client connecting to the ASIO server via loopback interface, so no WiFi, nor Ethernet connection
was established.
```
I (0) cpu_start: App cpu up.
I (495) heap_init: Initializing. RAM available for dynamic allocation:
I (502) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (508) heap_init: At 3FFB5400 len 0002AC00 (171 KiB): DRAM
I (515) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (521) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (527) heap_init: At 4008BB80 len 00014480 (81 KiB): IRAM
I (534) cpu_start: Pro cpu start user code
I (556) spi_flash: detected chip: gd
I (556) spi_flash: flash io: dio
W (556) spi_flash: Detected size(4096k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (566) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (600) example_connect: Waiting for IP(s)
W (600) esp32_asio_pthread: pthread_condattr_setclock: not yet supported!
W (1610) esp32_asio_pthread: pthread_condattr_setclock: not yet supported!
W (1610) esp32_asio_pthread: pthread_condattr_setclock: not yet supported!
Server received: GET / HTTP/1.1
Reply: GET / HTTP/1.1
```
See the README.md file in the upper level 'examples' directory for more information about examples.

Wyświetl plik

@ -1,16 +0,0 @@
from __future__ import unicode_literals
import ttfw_idf
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC', target=['esp32', 'esp32c3'])
def test_examples_asio_ssl(env, extra_data):
dut = env.get_dut('asio_ssl_client_server', 'examples/protocols/asio/ssl_client_server')
dut.start_app()
dut.expect('Reply: GET / HTTP/1.1')
if __name__ == '__main__':
test_examples_asio_ssl()

Wyświetl plik

@ -1,3 +0,0 @@
idf_component_register(SRCS "asio_ssl_main.cpp"
INCLUDE_DIRS "."
EMBED_TXTFILES ca.crt server.key srv.crt)

Wyświetl plik

@ -1,36 +0,0 @@
menu "Example Configuration"
config EXAMPLE_CLIENT
bool "Enable TLS client"
default y
help
Choose this option to use ASIO TLS/SSL client functionality
config EXAMPLE_PORT
string "ASIO port number"
default "443"
help
Port number used by ASIO example.
config EXAMPLE_SERVER
bool "Enable TLS server"
default n
help
Choose this option to use ASIO TLS/SSL server functionality
config EXAMPLE_SERVER_NAME
string "ASIO server name or IP"
default "www.google.com"
depends on EXAMPLE_CLIENT
help
Asio example server ip for the ASIO client to connect to.
config EXAMPLE_CLIENT_VERIFY_PEER
bool "Client to verify peer"
default n
depends on EXAMPLE_CLIENT
help
This option sets client's mode to verify peer, default is
verify-none
endmenu

Wyświetl plik

@ -1,272 +0,0 @@
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <string>
#include "protocol_examples_common.h"
#include "esp_event.h"
#include "nvs_flash.h"
#include <cstdlib>
#include <iostream>
#include <chrono>
#include <thread>
#include "asio.hpp"
#include "asio/ssl.hpp"
#include "asio/buffer.hpp"
#include "esp_pthread.h"
extern const unsigned char server_pem_start[] asm("_binary_srv_crt_start");
extern const unsigned char server_pem_end[] asm("_binary_srv_crt_end");
extern const unsigned char cacert_pem_start[] asm("_binary_ca_crt_start");
extern const unsigned char cacert_pem_end[] asm("_binary_ca_crt_end");
extern const unsigned char prvtkey_pem_start[] asm("_binary_server_key_start");
extern const unsigned char prvtkey_pem_end[] asm("_binary_server_key_end");
static const asio::const_buffer cert_chain(cacert_pem_start, cacert_pem_end - cacert_pem_start);
static const asio::const_buffer privkey(prvtkey_pem_start, prvtkey_pem_end - prvtkey_pem_start);
static const asio::const_buffer server_cert(server_pem_start, server_pem_end - server_pem_start);
using asio::ip::tcp;
static const std::size_t max_length = 1024;
class Client {
public:
Client(asio::io_context &io_context,
asio::ssl::context &context,
const tcp::resolver::results_type &endpoints)
: socket_(io_context, context)
{
#if CONFIG_EXAMPLE_CLIENT_VERIFY_PEER
socket_.set_verify_mode(asio::ssl::verify_peer);
#else
socket_.set_verify_mode(asio::ssl::verify_none);
#endif // CONFIG_EXAMPLE_CLIENT_VERIFY_PEER
connect(endpoints);
}
private:
void connect(const tcp::resolver::results_type &endpoints)
{
asio::async_connect(socket_.lowest_layer(), endpoints,
[this](const std::error_code & error,
const tcp::endpoint & /*endpoint*/) {
if (!error) {
handshake();
} else {
std::cout << "Connect failed: " << error.message() << "\n";
}
});
}
void handshake()
{
socket_.async_handshake(asio::ssl::stream_base::client,
[this](const std::error_code & error) {
if (!error) {
send_request();
} else {
std::cout << "Handshake failed: " << error.message() << "\n";
}
});
}
void send_request()
{
size_t request_length = std::strlen(request_);
asio::async_write(socket_,
asio::buffer(request_, request_length),
[this](const std::error_code & error, std::size_t length) {
if (!error) {
receive_response(length);
} else {
std::cout << "Write failed: " << error.message() << "\n";
}
});
}
void receive_response(std::size_t length)
{
asio::async_read(socket_,
asio::buffer(reply_, length),
[this](const std::error_code & error, std::size_t length) {
if (!error) {
std::cout << "Reply: ";
std::cout.write(reply_, length);
std::cout << "\n";
} else {
std::cout << "Read failed: " << error.message() << "\n";
}
});
}
asio::ssl::stream<tcp::socket> socket_;
char request_[max_length] = "GET / HTTP/1.1\r\n\r\n";
char reply_[max_length];
};
class Session : public std::enable_shared_from_this<Session> {
public:
Session(tcp::socket socket, asio::ssl::context &context)
: socket_(std::move(socket), context)
{
}
void start()
{
do_handshake();
}
private:
void do_handshake()
{
auto self(shared_from_this());
socket_.async_handshake(asio::ssl::stream_base::server,
[this, self](const std::error_code & error) {
if (!error) {
do_read();
}
});
}
void do_read()
{
auto self(shared_from_this());
socket_.async_read_some(asio::buffer(data_),
[this, self](const std::error_code & ec, std::size_t length) {
if (!ec) {
std::cout << "Server received: ";
std::cout.write(data_, length);
std::cout << std::endl;
do_write(length);
}
});
}
void do_write(std::size_t length)
{
auto self(shared_from_this());
asio::async_write(socket_, asio::buffer(data_, length),
[this, self](const std::error_code & ec,
std::size_t /*length*/) {
if (!ec) {
do_read();
}
});
}
asio::ssl::stream<tcp::socket> socket_;
char data_[max_length];
};
class Server {
public:
Server(asio::io_context &io_context, unsigned short port)
: acceptor_(io_context, tcp::endpoint(tcp::v4(), port)),
context_(asio::ssl::context::tls_server)
{
context_.set_options(
asio::ssl::context::default_workarounds
| asio::ssl::context::no_sslv2);
context_.use_certificate_chain(server_cert);
context_.use_private_key(privkey, asio::ssl::context::pem);
do_accept();
}
private:
void do_accept()
{
acceptor_.async_accept(
[this](const std::error_code & error, tcp::socket socket) {
if (!error) {
std::make_shared<Session>(std::move(socket), context_)->start();
}
do_accept();
});
}
tcp::acceptor acceptor_;
asio::ssl::context context_;
};
void set_thread_config(const char *name, int stack, int prio)
{
auto cfg = esp_pthread_get_default_config();
cfg.thread_name = name;
cfg.stack_size = stack;
cfg.prio = prio;
esp_pthread_set_cfg(&cfg);
}
void ssl_server_thread()
{
asio::io_context io_context;
Server s(io_context, 443);
io_context.run();
}
void ssl_client_thread()
{
asio::io_context io_context;
tcp::resolver resolver(io_context);
std::string server_ip = CONFIG_EXAMPLE_SERVER_NAME;
std::string server_port = CONFIG_EXAMPLE_PORT;
auto endpoints = resolver.resolve(server_ip, server_port);
asio::ssl::context ctx(asio::ssl::context::tls_client);
#if CONFIG_EXAMPLE_CLIENT_VERIFY_PEER
ctx.add_certificate_authority(cert_chain);
#endif // CONFIG_EXAMPLE_CLIENT_VERIFY_PEER
Client c(io_context, ctx, endpoints);
io_context.run();
}
extern "C" void app_main(void)
{
ESP_ERROR_CHECK(nvs_flash_init());
esp_netif_init();
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
/* This helper function configures blocking UART I/O */
ESP_ERROR_CHECK(example_configure_stdin_stdout());
std::vector<std::thread> work_threads;
#if CONFIG_EXAMPLE_SERVER
set_thread_config("Server", 16 * 1024, 5);
work_threads.emplace_back(std::thread(ssl_server_thread));
std::this_thread::sleep_for(std::chrono::seconds(1));
#endif // CONFIG_EXAMPLE_SERVER
#if CONFIG_EXAMPLE_CLIENT
set_thread_config("Client", 16 * 1024, 5);
work_threads.emplace_back(ssl_client_thread);
#endif // CONFIG_EXAMPLE_CLIENT
for (auto &t : work_threads) {
t.join();
}
}

Wyświetl plik

@ -1,22 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDkzCCAnugAwIBAgIUNI5wldYysh6rtCzYmda6H414aRswDQYJKoZIhvcNAQEL
BQAwWTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJRXNwcmVzc2lmMB4X
DTIwMDEyMTA5MDk0NloXDTI1MDEyMDA5MDk0NlowWTELMAkGA1UEBhMCQVUxEzAR
BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5
IEx0ZDESMBAGA1UEAwwJRXNwcmVzc2lmMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAyadSpRnIQBVbEAsbpkrKrOMlBOMIUmA8AfNyOYPLfv0Oa5lBiMAV
3OQDu5tYyFYKwkCUqq65iAm50fPbSH71w1tkja6nZ1yAIM+TvpMlM/WiFGrhY+Tc
kAcLcKUJyPxrv/glzoVslbqUgIhuhCSKA8uk1+ILcn3nWzPcbcowLx31+AHeZj8h
bIAdj6vjqxMCFStp4IcA+ikmCk75LCN4vkkifdkebb/ZDNYCZZhpCBnCHyFAjPc4
7C+FDVGT3/UUeeTy+Mtn+MqUAhB+W0sPDm1n2h59D4Z/MFm0hl6GQCAKeMJPzssU
BBsRm6zoyPQ4VTqG0uwfNNbORyIfKONMUwIDAQABo1MwUTAdBgNVHQ4EFgQUGYLV
EkgWzxjpltE6texha7zZVxowHwYDVR0jBBgwFoAUGYLVEkgWzxjpltE6texha7zZ
VxowDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAb2EF4Zg2XWNb
eZHnzupCDd9jAhwPqkt7F1OXvxJa/RFUSB9+2izGvikGGhuKY4f0iLuqF+bhExD9
sapDcdFO2Suh4J3onbwEvmKvsv56K3xhapYg8WwPofpkVirnkwFjpQXGzrYxPujg
BPmSy3psQrhvOr/WH7SefJv2qr4ikaugfE+3enY4PL+C1dSQAuNo1QGgWsZIu0c8
TZybNZ13vNVMA+tgj2CM8FR3Etaabwtu3TTcAnO7aoBTix/bLBTuZoczhN8/MhG3
GylmDzFI8a6aKxQL3Fi4PsM82hRKWu3gfs39sR1Ci4V22v8uO5EWBPK0QZvDSc1a
KwwxI4zA0w==
-----END CERTIFICATE-----

Wyświetl plik

@ -1,27 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAlUCywNhVv4RO2y9h/XGKZ1azzk3jzHpSBzIGO9LoiA8trC/p
1ykGaUfYPJllYK4HMhC4fUyE3J7tVL2Eskzl26LNPLbEoaBWZM9NhV3iA1/1EtOu
p6umLx+y3sDfvK35YAOUbjdAlBfhnJ4r8h7oTsxl3J5jZ18zgjJnJi2NEFq/yTpO
MiwHLWPjy25fDFixfV9UzSvbgt1JaGPmC7c4QkhHzjyp0+ikuvRIw0p9BBNeqBV2
da3qBMB5FtodUJTAz6o6OKWbTalLjQi6C1H6z9TnY7IrJBUOy/FWkQH/sEsLdscD
hHa1Dz2oT203QjhzyOSfnNF95D/1MdNcMt6l0wIDAQABAoIBAC1JJTOoMFRc48RT
myrYQYNbZlEphv3q+2qdfhC2zMFDwbrmCtCy7PQSzYSNkpoEE8DYG/JAvmtmeWJl
4pZrCK9ctWM/nWfhC3WpBL97nfEiM20T94F+bn0L5Cz8XqaULv839th+QUTt/hGU
WIctY5VNJXcMQ+MAmtNdUbjex1d3iuxiKHUo4nDoZ8digKFNdtdP5B5nlMq5chCL
mxNRcsGsx2dDAxbGUapdTVPWHPJKpLOBoSkluDsfd2KZADFU2R1SJpAX9+RYh3HM
5FTUdHTUaISxbKkgeDKlEM0lqk2TtGUwCyEj098ewi7Wzsu9w60IplPPUJx5FRG6
jp3wzLkCgYEAxKp5T20rf/7ysX7x053I7VCjDXUxAaWOEj1uS3AhOkl0NaZg7Di+
y53fWNkcHdkt2n2LqMt/43UgMYq3TVVcq2eunPNF11e1bJw8CjDafwDs4omwwyVn
lYhPuB4dK2OAib+vU5Zqpp0kZMoxk2MZVgon8z+s8DW/zmB6aFqAWeUCgYEAwkhC
OgmXKMdjOCVy5t2f5UbY8Y9rV3w8eUATuJ47MMwLr4pGYnKoEn9JB4ltWrHv/u5S
fOv3tIrrCEvnCoCbOILwCsY5LqTNXgqova8FB6RpMUQCzhDd8LHuvdHv0WMnMzX1
3PKuqwh8JS55m4WqZRhzr5BFKG4fHPVs4IcaJVcCgYAzzCaJSdqUKqTnJOUydDNQ
ddWMHNqccWs62J0tF0pZHLGT089hSAzQejMyJnSmU+Ykzr4y5e44DUg+ZCelIZ93
saYmxlgVwI8THQ8fLADQRIEfpV4996MRmkZM2vmZzOo03Zyi6lIKsga82Rg3lnk8
1Q3ynknBNpbfF0AGLhfyFQKBgBYlxJ73HutAJ5hr9HhLBYJOnEaVUehMOlycKGNg
bmD2sdJWEgYBChXpurqIORYguLo4EuE4ySkkuPxeIr14wbkkfBbOWBBwKxUwY+IT
xKAFZxR9q1AwbgyVTCEJgKw/AGX/HcMNS0omEnjunmBTUYRq0C1QZgHg490aQUor
PJjLAoGAevzdTpFlVeuKeYh1oDubGO1LinyXpBv7fPFjl+zu4AVbjojcU6yC4OO6
QvqopE6SyAECKy8kAOFcESPsGc9Lta2XUvI203z7pIVlNVEcJ0+90mQh3Mn1U46l
sZ49PdRvNwNb5wvkh1UqNsMlGFbRlzMbIk45ou4311kCobowZek=
-----END RSA PRIVATE KEY-----

Wyświetl plik

@ -1,18 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIC9DCCAdwCFA1lSIcHwYKdB2UqOrZxZnVgPObTMA0GCSqGSIb3DQEBCwUAMFkx
CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl
cm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMMCUVzcHJlc3NpZjAeFw0yMDA2
MTIwNjA0MTNaFw0yMjA2MDIwNjA0MTNaMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDCC
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJVAssDYVb+ETtsvYf1ximdW
s85N48x6UgcyBjvS6IgPLawv6dcpBmlH2DyZZWCuBzIQuH1MhNye7VS9hLJM5dui
zTy2xKGgVmTPTYVd4gNf9RLTrqerpi8fst7A37yt+WADlG43QJQX4ZyeK/Ie6E7M
ZdyeY2dfM4IyZyYtjRBav8k6TjIsBy1j48tuXwxYsX1fVM0r24LdSWhj5gu3OEJI
R848qdPopLr0SMNKfQQTXqgVdnWt6gTAeRbaHVCUwM+qOjilm02pS40IugtR+s/U
52OyKyQVDsvxVpEB/7BLC3bHA4R2tQ89qE9tN0I4c8jkn5zRfeQ/9THTXDLepdMC
AwEAATANBgkqhkiG9w0BAQsFAAOCAQEAnMYGW+idt37bEE4WPgrRorKWuplR+zHD
wJFz53DQzyIZJHmJ2hR5U0jNcHy/nMq7tbdz9LZPrVF4lZJ3TJhnmkOKjMFPCQE8
YcmsP3il6eXgtGqg53InOi/uJqEQ9TfM54cbpp6xKbnmpwk4uprISBRQt7u2ZLk2
40ED6zgjFPDTYmSjSpb2AN6KUB6PflgVs+4p9ViHNq4U3AlYV/BM0+3G4aMX2wNl
ZIpQfOyuaYD5MU50mY+O+gDiiypkpYf6a6S4YJ1sMbavDsP7bW5UMnP0jKYR549q
5hF1fdkXq52DfJ9ya2kl3mANFkKssQV+1KCBMxGoeqfakmJfa03xXA==
-----END CERTIFICATE-----

Wyświetl plik

@ -1,5 +0,0 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1400000,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 1400000,

Wyświetl plik

@ -1,6 +0,0 @@
CONFIG_EXAMPLE_CLIENT=y
CONFIG_EXAMPLE_SERVER=y
CONFIG_EXAMPLE_SERVER_NAME="localhost"
CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_CONNECT_ETHERNET=n
CONFIG_EXAMPLE_CLIENT_VERIFY_PEER=y

Wyświetl plik

@ -1,10 +0,0 @@
CONFIG_ASIO_SSL_SUPPORT=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
#
# Partition Table
#
# Leave some room for larger apps without needing to reduce other features
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y

Wyświetl plik

@ -1,10 +0,0 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
# (Not part of the boilerplate)
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(asio_tcp_echo_server)

Wyświetl plik

@ -1,22 +0,0 @@
| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 | ESP32-C3 |
| ----------------- | ----- | -------- | -------- | -------- |
# Asio TCP echo server example
Simple Asio TCP echo server using WiFi STA or Ethernet.
## Example workflow
- Wi-Fi or Ethernet connection is established, and IP address is obtained.
- Asio TCP server is started on port number defined through the project configuration.
- Server receives and echoes back messages transmitted from client.
## Running the example
- Open the project configuration menu (`idf.py menuconfig`) to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
- Set server port number in menuconfig, "Example configuration".
- Run `idf.py -p PORT flash monitor` to build and upload the example to your board and connect to it's serial terminal.
- Wait for the board to connect to WiFi or Ethernet (note the IP address).
- You can now send a TCP message and check it is repeated, for example using netcat `nc IP PORT`.
See the README.md file in the upper level 'examples' directory for more information about examples.

Wyświetl plik

@ -1,47 +0,0 @@
import os
import re
import socket
import ttfw_idf
@ttfw_idf.idf_example_test(env_tag='Example_WIFI_Protocols')
def test_examples_protocol_asio_tcp_server(env, extra_data):
"""
steps: |
1. join AP
2. Start server
3. Test connects to server and sends a test message
4. Test evaluates received test message from server
5. Test evaluates received test message on server stdout
"""
test_msg = b'echo message from client to server'
dut1 = env.get_dut('tcp_echo_server', 'examples/protocols/asio/tcp_echo_server', dut_class=ttfw_idf.ESP32DUT)
# check and log bin size
binary_file = os.path.join(dut1.app.binary_path, 'asio_tcp_echo_server.bin')
bin_size = os.path.getsize(binary_file)
ttfw_idf.log_performance('asio_tcp_echo_server_bin_size', '{}KB'.format(bin_size // 1024))
# 1. start test
dut1.start_app()
# 2. get the server IP address
data = dut1.expect(re.compile(r' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), timeout=30)
# 3. create tcp client and connect to server
dut1.expect('ASIO engine is up and running', timeout=1)
cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
cli.settimeout(30)
cli.connect((data[0], 2222))
cli.send(test_msg)
data = cli.recv(1024)
# 4. check the message received back from the server
if (data == test_msg):
print('PASS: Received correct message')
pass
else:
print('Failure!')
raise ValueError('Wrong data received from asi tcp server: {} (expected:{})'.format(data, test_msg))
# 5. check the client message appears also on server terminal
dut1.expect(test_msg.decode())
if __name__ == '__main__':
test_examples_protocol_asio_tcp_server()

Wyświetl plik

@ -1,2 +0,0 @@
idf_component_register(SRCS "echo_server.cpp"
INCLUDE_DIRS ".")

Wyświetl plik

@ -1,9 +0,0 @@
menu "Example Configuration"
config EXAMPLE_PORT
string "Asio example port number"
default "2222"
help
Port number used by Asio example.
endmenu

Wyświetl plik

@ -1,108 +0,0 @@
#include "asio.hpp"
#include <string>
#include <iostream>
#include "protocol_examples_common.h"
#include "esp_event.h"
#include "nvs_flash.h"
using asio::ip::tcp;
class session
: public std::enable_shared_from_this<session>
{
public:
session(tcp::socket socket)
: socket_(std::move(socket))
{
}
void start()
{
do_read();
}
private:
void do_read()
{
auto self(shared_from_this());
socket_.async_read_some(asio::buffer(data_, max_length),
[this, self](std::error_code ec, std::size_t length)
{
if (!ec)
{
data_[length] = 0;
std::cout << data_ << std::endl;
do_write(length);
}
});
}
void do_write(std::size_t length)
{
auto self(shared_from_this());
asio::async_write(socket_, asio::buffer(data_, length),
[this, self](std::error_code ec, std::size_t length)
{
if (!ec)
{
do_read();
}
});
}
tcp::socket socket_;
enum { max_length = 1024 };
char data_[max_length];
};
class server
{
public:
server(asio::io_context& io_context, short port)
: acceptor_(io_context, tcp::endpoint(tcp::v4(), port))
{
do_accept();
}
private:
void do_accept()
{
acceptor_.async_accept(
[this](std::error_code ec, tcp::socket socket)
{
if (!ec)
{
std::make_shared<session>(std::move(socket))->start();
}
do_accept();
});
}
tcp::acceptor acceptor_;
};
extern "C" void app_main(void)
{
ESP_ERROR_CHECK(nvs_flash_init());
esp_netif_init();
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
/* This helper function configures blocking UART I/O */
ESP_ERROR_CHECK(example_configure_stdin_stdout());
asio::io_context io_context;
server s(io_context, std::atoi(CONFIG_EXAMPLE_PORT));
std::cout << "ASIO engine is up and running" << std::endl;
io_context.run();
}

Wyświetl plik

@ -1,7 +0,0 @@
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
#
# Partition Table
#
# Leave some room for larger apps without needing to reduce other features
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y

Wyświetl plik

@ -1,10 +0,0 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
# (Not part of the boilerplate)
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(asio_udp_echo_server)

Wyświetl plik

@ -1,22 +0,0 @@
| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 | ESP32-C3 |
| ----------------- | ----- | -------- | -------- | -------- |
# Asio UDP echo server example
Simple Asio UDP echo server using WiFi STA or Ethernet.
## Example workflow
- Wi-Fi or Ethernet connection is established, and IP address is obtained.
- Asio UDP server is started on port number defined through the project configuration
- Server receives and echoes back messages transmitted from client
## Running the example
- Open the project configuration menu (`idf.py menuconfig`) to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
- Set server port number in menuconfig, "Example configuration".
- Run `idf.py -p PORT flash monitor` to build and upload the example to your board and connect to it's serial terminal.
- Wait for the board to connect to WiFi or Ethernet (note the IP address).
- You can now send a UDP message and check it is repeated, for example using netcat `nc -u IP PORT`.
See the README.md file in the upper level 'examples' directory for more information about examples.

Wyświetl plik

@ -1,47 +0,0 @@
import os
import re
import socket
import ttfw_idf
@ttfw_idf.idf_example_test(env_tag='Example_WIFI_Protocols')
def test_examples_protocol_asio_udp_server(env, extra_data):
"""
steps: |
1. join AP
2. Start server
3. Test connects to server and sends a test message
4. Test evaluates received test message from server
5. Test evaluates received test message on server stdout
"""
test_msg = b'echo message from client to server'
dut1 = env.get_dut('udp_echo_server', 'examples/protocols/asio/udp_echo_server', dut_class=ttfw_idf.ESP32DUT)
# check and log bin size
binary_file = os.path.join(dut1.app.binary_path, 'asio_udp_echo_server.bin')
bin_size = os.path.getsize(binary_file)
ttfw_idf.log_performance('asio_udp_echo_server_bin_size', '{}KB'.format(bin_size // 1024))
# 1. start test
dut1.start_app()
# 2. get the server IP address
data = dut1.expect(re.compile(r' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), timeout=30)
# 3. create tcp client and connect to server
dut1.expect('ASIO engine is up and running', timeout=1)
cli = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
cli.settimeout(30)
cli.connect((data[0], 2222))
cli.send(test_msg)
data = cli.recv(1024)
# 4. check the message received back from the server
if (data == test_msg):
print('PASS: Received correct message')
pass
else:
print('Failure!')
raise ValueError('Wrong data received from asio udp server: {} (expected:{})'.format(data, test_msg))
# 5. check the client message appears also on server terminal
dut1.expect(test_msg.decode())
if __name__ == '__main__':
test_examples_protocol_asio_udp_server()

Wyświetl plik

@ -1,2 +0,0 @@
idf_component_register(SRCS "udp_echo_server.cpp"
INCLUDE_DIRS ".")

Wyświetl plik

@ -1,9 +0,0 @@
menu "Example Configuration"
config EXAMPLE_PORT
string "Asio example port number"
default "2222"
help
Port number used by Asio example.
endmenu

Wyświetl plik

@ -1,90 +0,0 @@
//
// async_udp_echo_server.cpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <cstdlib>
#include <iostream>
#include "asio.hpp"
#include "protocol_examples_common.h"
#include "esp_event.h"
#include "nvs_flash.h"
using asio::ip::udp;
class server
{
public:
server(asio::io_context& io_context, short port)
: socket_(io_context, udp::endpoint(udp::v4(), port))
{
do_receive();
}
void do_receive()
{
socket_.async_receive_from(
asio::buffer(data_, max_length), sender_endpoint_,
[this](std::error_code ec, std::size_t bytes_recvd)
{
if (!ec && bytes_recvd > 0)
{
data_[bytes_recvd] = 0;
std::cout << data_ << std::endl;
do_send(bytes_recvd);
}
else
{
do_receive();
}
});
}
void do_send(std::size_t length)
{
socket_.async_send_to(
asio::buffer(data_, length), sender_endpoint_,
[this](std::error_code /*ec*/, std::size_t bytes /*bytes_sent*/)
{
do_receive();
});
}
private:
udp::socket socket_;
udp::endpoint sender_endpoint_;
enum { max_length = 1024 };
char data_[max_length];
};
extern "C" void app_main(void)
{
ESP_ERROR_CHECK(nvs_flash_init());
esp_netif_init();
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
/* This helper function configures blocking UART I/O */
ESP_ERROR_CHECK(example_configure_stdin_stdout());
asio::io_context io_context;
server s(io_context, std::atoi(CONFIG_EXAMPLE_PORT));
std::cout << "ASIO engine is up and running" << std::endl;
io_context.run();
}

Wyświetl plik

@ -1,7 +0,0 @@
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
#
# Partition Table
#
# Leave some room for larger apps without needing to reduce other features
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y

Wyświetl plik

@ -1889,18 +1889,6 @@ examples/peripherals/uart/uart_repl/main/uart_repl_example_main.c
examples/peripherals/uart/uart_select/main/uart_select_example_main.c
examples/peripherals/usb/host/msc/components/msc/test/msc_device.c
examples/peripherals/wave_gen/main/wave_gen_example_main.c
examples/protocols/asio/asio_chat/example_test.py
examples/protocols/asio/asio_chat/main/asio_chat.cpp
examples/protocols/asio/asio_chat/main/chat_message.hpp
examples/protocols/asio/asio_chat/main/client.hpp
examples/protocols/asio/asio_chat/main/server.hpp
examples/protocols/asio/socks4/main/socks4.hpp
examples/protocols/asio/ssl_client_server/example_test.py
examples/protocols/asio/ssl_client_server/main/asio_ssl_main.cpp
examples/protocols/asio/tcp_echo_server/asio_tcp_server_test.py
examples/protocols/asio/tcp_echo_server/main/echo_server.cpp
examples/protocols/asio/udp_echo_server/asio_udp_server_test.py
examples/protocols/asio/udp_echo_server/main/udp_echo_server.cpp
examples/protocols/coap_client/main/coap_client_example_main.c
examples/protocols/coap_server/main/coap_server_example_main.c
examples/protocols/esp_http_client/esp_http_client_test.py

Wyświetl plik

@ -62,11 +62,6 @@ examples/peripherals/sdio/sdio_test.py
examples/peripherals/twai/twai_alert_and_recovery/example_test.py
examples/peripherals/twai/twai_network/example_test.py
examples/peripherals/twai/twai_self_test/example_test.py
examples/protocols/asio/chat_client/asio_chat_client_test.py
examples/protocols/asio/chat_server/asio_chat_server_test.py
examples/protocols/asio/ssl_client_server/example_test.py
examples/protocols/asio/tcp_echo_server/asio_tcp_server_test.py
examples/protocols/asio/udp_echo_server/asio_udp_server_test.py
examples/protocols/cbor/example_test.py
examples/protocols/esp_http_client/esp_http_client_test.py
examples/protocols/esp_local_ctrl/example_test.py