forked from espressif/esp-protocols
feat(lws): Add initial support libwebsockets component
This commit is contained in:
86
.github/workflows/lws_build.yml
vendored
Normal file
86
.github/workflows/lws_build.yml
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
name: "lws: build-tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled]
|
||||
|
||||
jobs:
|
||||
build_lws:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'lws') || github.event_name == 'push'
|
||||
name: Libwebsockets build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.3", "release-v5.4"]
|
||||
test: [ { app: example, path: "examples/client" }]
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
env:
|
||||
TEST_DIR: components/libwebsockets/${{ matrix.test.path }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
python -m pip install idf-build-apps
|
||||
python ./ci/build_apps.py ${TEST_DIR}
|
||||
cd ${TEST_DIR}
|
||||
for dir in `ls -d build_esp32_*`; do
|
||||
$GITHUB_WORKSPACE/ci/clean_build_artifacts.sh `pwd`/$dir
|
||||
zip -qur artifacts.zip $dir
|
||||
done
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: lws_target_esp32_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ env.TEST_DIR }}/artifacts.zip
|
||||
if-no-files-found: error
|
||||
|
||||
run-target-lws:
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
if: |
|
||||
github.repository == 'espressif/esp-protocols' &&
|
||||
( contains(github.event.pull_request.labels.*.name, 'lws') || github.event_name == 'push' )
|
||||
name: Target test
|
||||
needs: build_lws
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.3", "release-v5.4"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: example, path: "examples/client" }]
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ESP32-ETHERNET-KIT
|
||||
env:
|
||||
TEST_DIR: components/libwebsockets/${{ matrix.test.path }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: lws_target_esp32_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ env.TEST_DIR }}/ci/
|
||||
- name: Install Python packages
|
||||
env:
|
||||
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
|
||||
run: |
|
||||
pip install --only-binary cryptography --extra-index-url https://dl.espressif.com/pypi/ -r $GITHUB_WORKSPACE/ci/requirements.txt
|
||||
- name: Run Example Test on target
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
run: |
|
||||
unzip ci/artifacts.zip -d ci
|
||||
for dir in `ls -d ci/build_*`; do
|
||||
rm -rf build sdkconfig.defaults
|
||||
mv $dir build
|
||||
python -m pytest --log-cli-level DEBUG --junit-xml=./results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${dir#"ci/build_"}.xml --target=${{ matrix.idf_target }}
|
||||
done
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml
|
||||
path: components/libwebsockets/${{ matrix.test.path }}/*.xml
|
1
.github/workflows/publish-docs-component.yml
vendored
1
.github/workflows/publish-docs-component.yml
vendored
@ -102,5 +102,6 @@ jobs:
|
||||
components/mbedtls_cxx;
|
||||
components/mosquitto;
|
||||
components/sock_utils;
|
||||
components/libwebsockets;
|
||||
namespace: "espressif"
|
||||
api_token: ${{ secrets.IDF_COMPONENT_API_TOKEN }}
|
||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -4,3 +4,6 @@
|
||||
[submodule "components/mosquitto/mosquitto"]
|
||||
path = components/mosquitto/mosquitto
|
||||
url = https://github.com/eclipse/mosquitto
|
||||
[submodule "components/libwebsockets/libwebsockets"]
|
||||
path = components/libwebsockets/libwebsockets
|
||||
url = https://github.com/warmcat/libwebsockets.git
|
||||
|
@ -61,8 +61,8 @@ repos:
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: commit message scopes
|
||||
name: "commit message must be scoped with: mdns, modem, websocket, asio, mqtt_cxx, console, common, eppp, tls_cxx, mosq, sockutls"
|
||||
entry: '\A(?!(feat|fix|ci|bump|test|docs|chore)\((mdns|modem|common|console|websocket|asio|mqtt_cxx|examples|eppp|tls_cxx|mosq|sockutls)\)\:)'
|
||||
name: "commit message must be scoped with: mdns, modem, websocket, asio, mqtt_cxx, console, common, eppp, tls_cxx, mosq, sockutls, lws"
|
||||
entry: '\A(?!(feat|fix|ci|bump|test|docs|chore)\((mdns|modem|common|console|websocket|asio|mqtt_cxx|examples|eppp|tls_cxx|mosq|sockutls|lws)\)\:)'
|
||||
language: pygrep
|
||||
args: [--multiline]
|
||||
stages: [commit-msg]
|
||||
|
@ -66,3 +66,7 @@ Please refer to instructions in [ESP-IDF](https://github.com/espressif/esp-idf)
|
||||
### Socket helpers (sock-utils)
|
||||
|
||||
* Brief introduction [README](components/sock_utils/README.md)
|
||||
|
||||
### libwebsockets
|
||||
|
||||
* Brief introduction [README](components/libwebsockets/README.md)
|
||||
|
20
components/libwebsockets/CMakeLists.txt
Normal file
20
components/libwebsockets/CMakeLists.txt
Normal file
@ -0,0 +1,20 @@
|
||||
idf_component_register(REQUIRES mbedtls)
|
||||
|
||||
set(LWS_WITH_EXPORT_LWSTARGETS OFF CACHE BOOL "Export libwebsockets CMake targets. Disable if they conflict with an outer cmake project.")
|
||||
set(LWS_WITH_MBEDTLS ON CACHE BOOL "Use mbedTLS (>=2.0) replacement for OpenSSL.")
|
||||
set(LWS_WITH_JPEG OFF CACHE BOOL "Enable stateful JPEG stream decoder")
|
||||
|
||||
|
||||
set(WRAP_FUNCTIONS mbedtls_ssl_handshake_step
|
||||
lws_adopt_descriptor_vhost)
|
||||
|
||||
foreach(wrap ${WRAP_FUNCTIONS})
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=${wrap}")
|
||||
endforeach()
|
||||
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE websockets)
|
||||
|
||||
target_sources(${COMPONENT_LIB} INTERFACE "port/lws_port.c")
|
||||
|
||||
|
||||
add_subdirectory(libwebsockets)
|
24
components/libwebsockets/README.md
Normal file
24
components/libwebsockets/README.md
Normal file
@ -0,0 +1,24 @@
|
||||
# ESP32 libwebsockets Port
|
||||
|
||||
This is a lightweight port of the libwebsockets library designed to run on the ESP32. It provides WebSocket client functionalities.
|
||||
|
||||
## Supported Options
|
||||
|
||||
The ESP-IDF port of libwebsockets supports a set of common WebSocket configurations for clients. These options can be configured through a structure passed to the `lws_create_context()` function.
|
||||
|
||||
Key features supported:
|
||||
- WebSocket with optional SSL/TLS
|
||||
- HTTP/1.1 client support
|
||||
|
||||
## Memory Footprint Considerations
|
||||
|
||||
The memory consumption primarily depends on the number of concurrent connections and the selected options for WebSocket frames, protocol handling, and SSL/TLS features. It consumes approximately 300 kB of program memory.
|
||||
|
||||
### Client:
|
||||
The values bellow were extracted from the client example (./examples/client/main/lws-client.c)
|
||||
- **Initial Memory Usage**: ~8 kB of heap on startup
|
||||
- **Connected Memory Usage Over TLS**: ~35.3 kB of heap after connected to a server
|
||||
- **Connected Memory Usage Over TCP (Plain)**: ~4.5 kB of heap after connected to a server
|
||||
|
||||
#### When configuring a WebSocket client, ensure that you have enough heap space to handle the desired number of concurrent client connections.
|
||||
#### SSL/TLS configurations may require additional memory overhead, depending on the certificate size and cryptographic settings.
|
6
components/libwebsockets/examples/client/CMakeLists.txt
Normal file
6
components/libwebsockets/examples/client/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
# 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)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(client_example)
|
311
components/libwebsockets/examples/client/LICENSE
Normal file
311
components/libwebsockets/examples/client/LICENSE
Normal file
@ -0,0 +1,311 @@
|
||||
Libwebsockets and included programs are provided under the terms of the
|
||||
MIT license shown below, with the exception that some sources are under
|
||||
a similar permissive license like BSD, or are explicitly CC0 / public
|
||||
domain to remove any obstacles from basing differently-licensed code on
|
||||
them.
|
||||
|
||||
Original liberal license retained:
|
||||
|
||||
- lib/misc/sha-1.c - 3-clause BSD license retained, link to original [BSD3]
|
||||
- win32port/zlib
|
||||
- lib/drivers/display/upng.* - ZLIB license (see zlib.h) [ZLIB]
|
||||
- lib/tls/mbedtls/wrapper - Apache 2.0 (only built if linked against mbedtls) [APACHE2]
|
||||
- lib/tls/mbedtls/mbedtls-extensions.c
|
||||
- lib/misc/base64-decode.c - already MIT
|
||||
- contrib/mcufont/encoder
|
||||
- lib/misc/ieeehalfprecision.c - 2-clause BSD license retained [BSD2]
|
||||
- contrib/mcufont/fonts - Open Font License [OFL]
|
||||
|
||||
Relicensed to MIT:
|
||||
|
||||
- lib/misc/daemonize.c - relicensed from Public Domain to MIT,
|
||||
link to original Public Domain version
|
||||
- lib/plat/windows/windows-resolv.c - relicensed from "Beerware v42" to MIT
|
||||
|
||||
Public Domain (CC-zero) to simplify reuse:
|
||||
|
||||
- test-apps/*.c
|
||||
- test-apps/*.h
|
||||
- minimal-examples/*
|
||||
- lwsws/*
|
||||
|
||||
Although libwebsockets is available under a permissive license, it does not
|
||||
change the reality of dealing with large lumps of external code... if your
|
||||
copy diverges it is guaranteed to contain security problems after a while
|
||||
and can be very painful to pick backports (especially since historically,
|
||||
we are very hot on cleaning and refactoring the codebase). The least
|
||||
painful and lowest risk way remains sending your changes and fixes upstream
|
||||
to us so you can easily use later releases and fixes.
|
||||
|
||||
## MIT License applied to libwebsockets
|
||||
|
||||
https://opensource.org/licenses/MIT
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
|
||||
## BSD2
|
||||
|
||||
```
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the distribution
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
```
|
||||
|
||||
## BSD3
|
||||
|
||||
For convenience, a copy of the license on `./lib/misc/sha-1.c`. In binary
|
||||
distribution, this applies to builds with ws support enabled, and without
|
||||
`LWS_WITHOUT_BUILTIN_SHA1` at cmake.
|
||||
|
||||
```
|
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH
|
||||
```
|
||||
|
||||
## ZLIB
|
||||
|
||||
For convenience, a copy of the license on zlib. In binary distribution,
|
||||
this applies for win32 builds with internal zlib only. You can avoid
|
||||
building any zlib usage or copy at all with `-DLWS_WITH_ZLIB=0` (the
|
||||
default), and so avoid needing to observe the license for binary
|
||||
distribution that doesn't include the related code.
|
||||
|
||||
```
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jean-loup Gailly Mark Adler
|
||||
jloup@gzip.org madler@alumni.caltech.edu
|
||||
```
|
||||
|
||||
|
||||
## APACHE2
|
||||
|
||||
For convenience, a copy of the license on the mbedtls wrapper part. In binary
|
||||
distribution, this applies only when building lws against mbedtls.
|
||||
|
||||
The canonical license application to source files uses the URL reference, so the
|
||||
whole is not reproduced here.
|
||||
|
||||
```
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
```
|
||||
|
||||
## CC0
|
||||
|
||||
For convenience,the full text of CC0 dedication found on the lws examples.
|
||||
The intention of this is to dedicate the examples to the public domain, so
|
||||
users can build off and modify them without any constraint.
|
||||
|
||||
```
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following:
|
||||
|
||||
the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work;
|
||||
moral rights retained by the original author(s) and/or performer(s);
|
||||
publicity and privacy rights pertaining to a person's image or likeness depicted in a Work;
|
||||
rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below;
|
||||
rights protecting the extraction, dissemination, use and reuse of data in a Work;
|
||||
database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and
|
||||
other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document.
|
||||
Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law.
|
||||
Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work.
|
||||
Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work.
|
||||
```
|
||||
|
||||
## OFL: Open Font License
|
||||
|
||||
```
|
||||
Copyright (c) 2012-2015, The Mozilla Foundation and Telefonica S.A.
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
```
|
87
components/libwebsockets/examples/client/README.md
Normal file
87
components/libwebsockets/examples/client/README.md
Normal file
@ -0,0 +1,87 @@
|
||||
# Websocket LWS client example
|
||||
|
||||
This example will shows how to set up and communicate over a websocket.
|
||||
|
||||
## How to Use Example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
This example can be executed on any ESP32 board, the only required interface is WiFi and connection to internet or a local server.
|
||||
|
||||
### Configure the project
|
||||
|
||||
* Open the project configuration menu (`idf.py menuconfig`)
|
||||
* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu.
|
||||
* Configure the websocket endpoint URI under "Example Configuration"
|
||||
|
||||
### Server Certificate Verification
|
||||
|
||||
* Mutual Authentication: When `CONFIG_WS_OVER_TLS_MUTUAL_AUTH=y` is enabled, it's essential to provide valid certificates for both the server and client.
|
||||
This ensures a secure two-way verification process.
|
||||
* Server-Only Authentication: To perform verification of the server's certificate only (without requiring a client certificate), set `CONFIG_WS_OVER_TLS_SERVER_AUTH=y`.
|
||||
This method skips client certificate verification.
|
||||
* Example below demonstrates how to generate a new self signed certificates for the server and client using the OpenSSL command line tool
|
||||
|
||||
Please note: This example represents an extremely simplified approach to generating self-signed certificates/keys with a single common CA, devoid of CN checks, lacking password protection, and featuring hardcoded key sizes and types. It is intended solely for testing purposes.
|
||||
In the outlined steps, we are omitting the configuration of the CN (Common Name) field due to the context of a testing environment. However, it's important to recognize that the CN field is a critical element of SSL/TLS certificates, significantly influencing the security and efficacy of HTTPS communications. This field facilitates the verification of a website's identity, enhancing trust and security in web interactions. In practical deployments beyond testing scenarios, ensuring the CN field is accurately set is paramount for maintaining the integrity and reliability of secure communications
|
||||
|
||||
It is **strongly recommended** to not reuse the example certificate in your application;
|
||||
it is included only for demonstration.
|
||||
|
||||
|
||||
### 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
|
||||
|
||||
```
|
||||
I (18208) lws-client: LWS minimal ws client echo
|
||||
|
||||
219868: lws_create_context: LWS: 4.3.99-v4.3.0-424-ga74362ff, MbedTLS-3.6.2 NET CLI SRV H1 H2 WS SS-JSON-POL ConMon IPv6-absent
|
||||
219576: mem: platform fd map: 20 bytes
|
||||
217880: __lws_lc_tag: ++ [wsi|0|pipe] (1)
|
||||
216516: __lws_lc_tag: ++ [vh|0|default||-1] (1)
|
||||
I (18248) lws-client: connect_cb: connecting
|
||||
|
||||
210112: __lws_lc_tag: ++ [wsicli|0|WS/h1/default/echo.websocket.events] (1)
|
||||
204800: [wsicli|0|WS/h1/default/echo.websocket.events]: lws_client_connect_3_connect: trying 13.248.241.119
|
||||
180776: lws_ssl_client_bio_create: allowing selfsigned
|
||||
I (19998) wifi:<ba-add>idx:0 (ifx:0, b4:89:01:63:9d:08), tid:0, ssn:321, winSize:64
|
||||
I (20768) lws-client: WEBSOCKET_EVENT_CONNECTED
|
||||
I (20768) lws-client: Sending hello 0000
|
||||
I (20778) lws-client: WEBSOCKET_EVENT_DATA
|
||||
W (20778) lws-client: Received=echo.websocket.events sponsored by Lob.com
|
||||
|
||||
|
||||
I (20968) lws-client: WEBSOCKET_EVENT_DATA
|
||||
W (20968) lws-client: Received=hello 0000
|
||||
|
||||
|
||||
I (22978) lws-client: Sending hello 0001
|
||||
I (23118) lws-client: WEBSOCKET_EVENT_DATA
|
||||
W (23118) lws-client: Received=hello 0001
|
||||
|
||||
|
||||
I (23778) lws-client: Sending hello 0002
|
||||
I (23938) lws-client: WEBSOCKET_EVENT_DATA
|
||||
W (23938) lws-client: Received=hello 0002
|
||||
|
||||
|
||||
I (25948) lws-client: Sending hello 0003
|
||||
I (26088) lws-client: WEBSOCKET_EVENT_DATA
|
||||
W (26088) lws-client: Received=hello 0003
|
||||
|
||||
|
||||
I (26948) lws-client: Sending hello 0004
|
||||
I (27118) lws-client: WEBSOCKET_EVENT_DATA
|
||||
W (27118) lws-client: Received=hello 0004
|
||||
```
|
12
components/libwebsockets/examples/client/main/CMakeLists.txt
Normal file
12
components/libwebsockets/examples/client/main/CMakeLists.txt
Normal file
@ -0,0 +1,12 @@
|
||||
set(SRC_FILES "lws-client.c") # Define source files
|
||||
set(INCLUDE_DIRS ".") # Define include directories
|
||||
set(EMBED_FILES "") # Initialize an empty list for files to embed
|
||||
|
||||
list(APPEND EMBED_FILES
|
||||
"certs/client_cert.pem"
|
||||
"certs/ca_cert.pem"
|
||||
"certs/client_key.pem")
|
||||
|
||||
idf_component_register(SRCS "${SRC_FILES}"
|
||||
INCLUDE_DIRS "${INCLUDE_DIRS}"
|
||||
EMBED_TXTFILES "${EMBED_FILES}")
|
@ -0,0 +1,45 @@
|
||||
menu "Example Configuration"
|
||||
choice WEBSOCKET_URI_SOURCE
|
||||
prompt "Websocket URI source"
|
||||
default WEBSOCKET_URI_FROM_STRING
|
||||
help
|
||||
Selects the source of the URI used in the example.
|
||||
|
||||
config WEBSOCKET_URI_FROM_STRING
|
||||
bool "From string"
|
||||
|
||||
config WEBSOCKET_URI_FROM_STDIN
|
||||
bool "From stdin"
|
||||
endchoice
|
||||
|
||||
config WEBSOCKET_URI
|
||||
string "Websocket endpoint URI"
|
||||
default "echo.websocket.events"
|
||||
help
|
||||
URL or IP of websocket endpoint this example connects to and sends echo
|
||||
config WEBSOCKET_PORT
|
||||
int "Websocket endpoint PORT"
|
||||
default 443
|
||||
help
|
||||
Port of websocket endpoint this example connects to and sends echo
|
||||
|
||||
config WS_OVER_TLS_SERVER_AUTH
|
||||
bool "Enable WebSocket over TLS with Server Certificate Verification Only"
|
||||
default n
|
||||
help
|
||||
Enables WebSocket connections over TLS (WSS) with server certificate verification.
|
||||
This setting mandates the client to verify the servers certificate, while the server
|
||||
does not require client certificate verification.
|
||||
|
||||
config WS_OVER_TLS_MUTUAL_AUTH
|
||||
bool "Enable WebSocket over TLS with Server Client Mutual Authentification"
|
||||
default y
|
||||
help
|
||||
Enables WebSocket connections over TLS (WSS) with server and client mutual certificate verification.
|
||||
|
||||
config WS_OVER_TLS_SKIP_COMMON_NAME_CHECK
|
||||
bool "Skip common name(CN) check during TLS authentification"
|
||||
default n
|
||||
help
|
||||
Skipping Common Name(CN) check during TLS(WSS) authentification
|
||||
endmenu
|
@ -0,0 +1,21 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDazCCAlOgAwIBAgIUL04QhbSEt5oNbV4f7CeLLqTCw2gwDQYJKoZIhvcNAQEL
|
||||
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
|
||||
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDAyMjMwODA2MjVaFw0zNDAy
|
||||
MjAwODA2MjVaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
|
||||
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
|
||||
AQUAA4IBDwAwggEKAoIBAQDjc78SuXAmJeBc0el2/m+2lwtk3J/VrNxHYkhjHa8K
|
||||
/ybU89VvKGuv9+L3IP67WMguFTaMgivJYUePjfMchtNJLJ+4cR9BkBKH4JnyXDae
|
||||
s0a5181LxRo8rqcaOw9hmJTgt9R4dIRTR3GN2/VLhlR+L9OTYA54RUtMyMMpyk5M
|
||||
YIJbcOwiwkVLsIYnexXDfgz9vQGl/2vBQ/RBtDBvbSyBiWox9SuzOrya1HUBzJkM
|
||||
Iu5L0bSa0LAeXHT3i3P1Y4WPt9ub70OhUNfJtHC+XbGFSEkkQG+lfbXU75XLoMWa
|
||||
iATMREOcb3Mq+pn1G8o1ZHVc6lBHUkfrNfxs5P/GQcSvAgMBAAGjUzBRMB0GA1Ud
|
||||
DgQWBBQGkdK2gR2HrQTnZnbuWO7I1+wdxDAfBgNVHSMEGDAWgBQGkdK2gR2HrQTn
|
||||
ZnbuWO7I1+wdxDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBx
|
||||
G0hFtMwV/agIwC3ZaYC36ZWiijFzWkJSZG+fqAy32mSoVL2uQvOT8vEfF0ZnAcPc
|
||||
JI4oI059dBhAVlwqv6uLHyD4Gf2bF4oSLljdTz3X23llF+/wrTC2LLqMrm09aUC0
|
||||
ac74Q0FVwVJJcqH1HgemCMVjna5MkwNA6B+q7uR3eQ692VqXk6vjd4fRLBg1bBO1
|
||||
hXjasfNxA8A9quORF5+rjYrwyUZHuzcs0FfSClckIt4tHKtt4moLufOW6/PM4fRe
|
||||
AgdDfiTupxYLJFz4hFPhfgCh4TjQ+f9+uP4IAjW42dJmTVZjLEku/hm5lxCFObAq
|
||||
RgfaNwH8Ug1r1xswjSZG
|
||||
-----END CERTIFICATE-----
|
@ -0,0 +1,20 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDWjCCAkKgAwIBAgIUUPCOgMA2v09E29fCkogx3RUBRtEwDQYJKoZIhvcNAQEL
|
||||
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
|
||||
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDAyMjMwODA3MzFaFw0zNDAy
|
||||
MjAwODA3MzFaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
|
||||
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
|
||||
AQUAA4IBDwAwggEKAoIBAQCrNeomxI2aoP+4iUy5SiA+41oHUDZDFeJOBjv5JCsK
|
||||
mlvFqxE9zynmPOVpuABErOJwzerPTa4NYKvuvs5CxVJUV5CXtWANuu9majioZNzj
|
||||
f877MDNX/GnZHK2gnkxVrZCPaDmx9yiMsFMXgmfdrDhwoUpXbdgSyeU/al9Ds2kF
|
||||
0hrHOH2LBWt/mVeLbONU5CC1HOdVVw+uRlhVlxnfhTPd/Nru3rJx7R0sN7qXcZpJ
|
||||
PL87WvrszLVOux24DeaOz9oiD2b7egFyUuq1BM25iCwi8s/Ths8xd0Ca1d8mEcHW
|
||||
FVd4w2+nUMXFE+IbP+wo6FXuiSaOBNri3rztpvCCMaWjAgMBAAGjQjBAMB0GA1Ud
|
||||
DgQWBBSOlA+9Vfbcfy8iS4HSd4V0KPtm4jAfBgNVHSMEGDAWgBQGkdK2gR2HrQTn
|
||||
ZnbuWO7I1+wdxDANBgkqhkiG9w0BAQsFAAOCAQEAOmzm/MwowKTrSpMSrmfA3MmW
|
||||
ULzsfa25WyAoTl90ATlg4653Y7pRaNfdvVvyi2V2LlPcmc7E0rfD53t1NxjDH1uM
|
||||
LgFMTNEaZ9nMRSW0kMiwaRpvmXS8Eb9PXfvIM/Mw0co/aMOtAQnfTGIqsgkQwKyk
|
||||
1GG7QKQq3p4QGu5ZaTnjnaoa79hODt+0xQDD1wp6C9xwBY0M4gndAi3wkOeFkGv+
|
||||
OmGPtaCBu5V9tJCZ9dfZvjkaK44NGwDw0urAcYRK2h7asnlflu7cnlGMBB0qY4kQ
|
||||
BX5WI8UjN6rECBHbtNRvEh06ogDdHbxYV+TibrqkkeDRw6HX1qqiEJ+iCgWEDQ==
|
||||
-----END CERTIFICATE-----
|
@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCrNeomxI2aoP+4
|
||||
iUy5SiA+41oHUDZDFeJOBjv5JCsKmlvFqxE9zynmPOVpuABErOJwzerPTa4NYKvu
|
||||
vs5CxVJUV5CXtWANuu9majioZNzjf877MDNX/GnZHK2gnkxVrZCPaDmx9yiMsFMX
|
||||
gmfdrDhwoUpXbdgSyeU/al9Ds2kF0hrHOH2LBWt/mVeLbONU5CC1HOdVVw+uRlhV
|
||||
lxnfhTPd/Nru3rJx7R0sN7qXcZpJPL87WvrszLVOux24DeaOz9oiD2b7egFyUuq1
|
||||
BM25iCwi8s/Ths8xd0Ca1d8mEcHWFVd4w2+nUMXFE+IbP+wo6FXuiSaOBNri3rzt
|
||||
pvCCMaWjAgMBAAECggEAOTWjz16AXroLmRMv8v5E9h6sN6Ni7lnCrAXDRoYCZ+Ga
|
||||
Ztu5wCiYPJn+oqvcUxZd+Ammu6yeS1QRP468h20+DHbSFw+BUDU1x8gYtJQ3h0Fu
|
||||
3VqG3ZC3odfGYNRkd4CuvGy8Uq5e+1vz9/gYUuc4WNJccAiBWg3ir6UQviOWJV46
|
||||
LGfdEd9hVvIGl5pmArMBVYdpj9+JHunDtG4uQxiWla5pdLjlkC2mGexD18T9d718
|
||||
6I+o3YHv1Y9RPT1d4rNhYQWx6YdTTD2rmS7nTrzroj/4fXsblpXzR+/l7crlNERY
|
||||
67RMPwgDR1NiAbCAJKsSbMS66lRCNlhTM4YffGAN6QKBgQDkIdcNm9j49SK5Wbl5
|
||||
j8U6UbcVYPzPG+2ea+fDfUIafA0VQHIuX6FgA17Kp7BDX9ldKtSBpr0Z8vetVswr
|
||||
agmXVMR/7QdvnZ9NpL66YA/BRs67CvsryVu4AVAzThFGySmlcXGlPq47doWDQ3B9
|
||||
0BOEnVoeDXR3SabaNsEbhDYn1wKBgQDAIAUyhJcgz+LcgaAtBwdnEN57y66JlRVZ
|
||||
bsb6cEG/MNmnLjQYsplJjNbz4yrB5ukTChPTGRF/JQRqHoXh6DGQFHvobukwwA6x
|
||||
RAIIq0NLJ5HUipfOi+VpCbWUHdoUNhwjAB2qVtD4LXE2Lyn46C8ET5eRtRjUKpzV
|
||||
lpsq63KHFQKBgFB+cDbpCoGtXPcxZXQy+lA9jPAKLKmXHRyMzlX32F8n7iXVe3RJ
|
||||
YdNS3Rt8V4EuTK/G8PxeLNL/G80ZlyiqXX/79Ol+ZOVJJHBs9K8mPejgZwkwMrec
|
||||
cLRYIkg3/3iOehdaE9NOboOkqi9KmGKMDJb6PlXkQXflkO3l6/UdjU45AoGAen0v
|
||||
sxiTncjMU1eVfn+nuY8ouXaPbYoOFXmqBItDb5i+e3baohBj6F+Rv+ZKIVuNp6Ta
|
||||
JNErtYstOFcDdpbp2nkk0ni71WftNhkszsgZ3DV7JS3DQV0xwvj8ulUZ757b63is
|
||||
cShujHu0XR5OvTGSoEX6VVxHWyVb3lTp0sBPwU0CgYBe2Ieuya0X8mAbputFN64S
|
||||
Kv++dqktTUT8i+tp07sIrpDeYwO3D89x9kVSJj4ImlmhiBVGkxFWPkpGyBLotdse
|
||||
Ai/E6f5I7CDSZZC0ZucgcItNd4Yy459QY+dFwFtT3kIaD9ml8fnqQ83J9W8DWtv9
|
||||
6mY9FnUUufbJcpHxN58RTw==
|
||||
-----END PRIVATE KEY-----
|
@ -0,0 +1,20 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDWjCCAkKgAwIBAgIUUPCOgMA2v09E29fCkogx3RUBRtAwDQYJKoZIhvcNAQEL
|
||||
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
|
||||
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDAyMjMwODA2NTlaFw0zNDAy
|
||||
MjAwODA2NTlaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
|
||||
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
|
||||
AQUAA4IBDwAwggEKAoIBAQC8WWbDxnLzTSfuQaO+kQnnzbwjhUHWn58s+BIEaO8M
|
||||
GG6bX+8r/SH9XjMfFS36qAN3qxgRun3YoRTaHc2QByiGjf5IL4EAPDnLN+NzUIL5
|
||||
7Gi2QPQP/GksAsOGKWk/nMRPk1vcMptkFVIWSp474SQ0A92Z9z0dUIqBpjRa34kr
|
||||
HsAIcT59/EG7YBBadMk0fQIxQVLh3Vosky85q+0waFihe47Ef5U2UftexoUx4Vcz
|
||||
6EtP60Wx+4qN+FLsr+n2B7Oz2ITqfwgqLzjNLZwm9bMjcLZ0fWm1A/W1C989MXwI
|
||||
w6DAPEZv7pbgp8r9phyrNieSDuuRaCvFsaXh6troAjLxAgMBAAGjQjBAMB0GA1Ud
|
||||
DgQWBBRJCYAQG2+1FN5P/wyAR1AsrAyb4DAfBgNVHSMEGDAWgBQGkdK2gR2HrQTn
|
||||
ZnbuWO7I1+wdxDANBgkqhkiG9w0BAQsFAAOCAQEAmllul/GIH7RVq85mM/SxP47J
|
||||
M7Z7T032KuR3n/Psyv2iq/uEV2CUje3XrKNwR2PaJL4Q6CtoWy7xgIP+9CBbjddR
|
||||
M7sdNQab8P2crAUtBKnkNOl/na/5KnXnjwi/PmWJJ9i2Cqt0PPkaykTWp/MLfYIw
|
||||
RPkY2Yo8f8gEiqXQd+0qTuMgumbgkPq3V8Lk1ocy62F5/qUhXxH+ifAXEoUQS6EG
|
||||
8DlgwdZlfUY+jeM6N56WzYmxD1syjNW7faPio+qXINfpYatROhqphaMQ5SA6TRj6
|
||||
jcnLa31TdDdWmWYDcYgZntAv6yGi3rh0MdYqeNS0FKlMKmaH81VHs7V1UUXwUQ==
|
||||
-----END CERTIFICATE-----
|
@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC8WWbDxnLzTSfu
|
||||
QaO+kQnnzbwjhUHWn58s+BIEaO8MGG6bX+8r/SH9XjMfFS36qAN3qxgRun3YoRTa
|
||||
Hc2QByiGjf5IL4EAPDnLN+NzUIL57Gi2QPQP/GksAsOGKWk/nMRPk1vcMptkFVIW
|
||||
Sp474SQ0A92Z9z0dUIqBpjRa34krHsAIcT59/EG7YBBadMk0fQIxQVLh3Vosky85
|
||||
q+0waFihe47Ef5U2UftexoUx4Vcz6EtP60Wx+4qN+FLsr+n2B7Oz2ITqfwgqLzjN
|
||||
LZwm9bMjcLZ0fWm1A/W1C989MXwIw6DAPEZv7pbgp8r9phyrNieSDuuRaCvFsaXh
|
||||
6troAjLxAgMBAAECggEACNVCggTxCCMCr+RJKxs/NS1LWPkbZNbYjrHVmnpXV6Bf
|
||||
s460t0HoUasUx6zlGp+9heOyvcYat8maIj6KkOodBu5q0fTUXm/0n+ivlI1ejxz8
|
||||
ritupr9GKWe5xrVzd6XA+SBmivWenvt2/Y+jSxica4oQ3vMe3RyVWk4yn15jXu+9
|
||||
7B9lNyNeZtOBr6OozHGLYw4dwWcBNv2S6wevRKfHPwn/Ch5yTH1uAskgoMxUuyK2
|
||||
ynNVHWUhyS4pFU7Tex5ENDel15VYdbxV/2lQ2W6fHMLtC5GWKJXXbigCX7pfOpzC
|
||||
BFJEfZl7ze/qptE9AR7DkLFYyMtrS7OlebYbLDOM9wKBgQD+rTdwULZibpKwlI3a
|
||||
9Y22d4N/EDFvuu8LnuEiVQnXgwg9M+tlaa2liP18j1a7y/FCfoXf5sjUWCsdYR6d
|
||||
C0TuiOGI59hYGI94NvVLAmOutR+vJ/3jhbv5wyqEQLhJ42Yz9kWBrDCI+V3q3TdO
|
||||
H7wcH6suUIZpeLEJF4qHzY/1dwKBgQC9U/Pvswiww8sfysmd5shUNo4ofAZnTM1A
|
||||
ak6pWE3lSyiOkSm+3B2GqxYWLRoo1v+pTyhhXDtRRmxGtMNrKCsmlHef/o3c6kkG
|
||||
cuC2h/DiSmoITHy3BYKJoDeE54E8ubXUUKqHo41LYUs+D7M/IGxeiO13MUoIrEtF
|
||||
AwzVWPBU1wKBgH8barD2x6Bm+XWCHy6qIZlxGsMfDN1r2gTdvhWJhcj3D/Sj5heO
|
||||
X+lfbsxtKee+yOHcDesK3y8D9jjKkSHmTvgSfyX6OML3NxvTqidOwPugUHj2J8QX
|
||||
qhLk8mJhftj50reacWRf0TV76ADhecnXEuaic6hA7mTTpOAZzL0svm3PAoGBALWF
|
||||
r6VLX3KzVqZVtLb7FWmAoQ35093pCgXPpznAW3cTd4Axd/fxbTG4CUYb2i/760X2
|
||||
ij3Gw2yqe5fTKmYsLisgQA2bb4K28msHa6I2dmNQe5cXVp/X3Y98mJ6JpCSH3ekB
|
||||
qm7ABfGXCCApx28n9B8zY5JbJKNqJgS15vELA+ojAoGAAkaV2w46+3iQ6gJtQepr
|
||||
zGNybiYBx/Wo5fDdTS5u0xN+ZdC9fl2Zs0n7sMmUT8bWdDLcMnntHHO+oDIKyRHs
|
||||
TQh1n68vQ4JoegQv3Z9Z/TLEKqr9gyJC1Ao6M4bZpPhUWQwupfHColtsr2TskcnJ
|
||||
Nf2FpJZ7z6fQEShGlK1yTXM=
|
||||
-----END PRIVATE KEY-----
|
@ -0,0 +1,6 @@
|
||||
dependencies:
|
||||
espressif/libwebsockets:
|
||||
version: "*"
|
||||
override_path: "../../../"
|
||||
protocol_examples_common:
|
||||
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
|
323
components/libwebsockets/examples/client/main/lws-client.c
Normal file
323
components/libwebsockets/examples/client/main/lws-client.c
Normal file
@ -0,0 +1,323 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
/* ESP libwebsockets 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 <libwebsockets.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_system.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "protocol_examples_common.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_task_wdt.h"
|
||||
|
||||
#include <cJSON.h>
|
||||
|
||||
static uint32_t disconnect_timeout = 5000000; // microseconds
|
||||
static uint8_t message_count = 0;
|
||||
static const char *TAG = "lws-client";
|
||||
|
||||
static struct lws_context *context;
|
||||
static struct lws *client_wsi;
|
||||
|
||||
static lws_sorted_usec_list_t sul;
|
||||
static unsigned char msg[LWS_PRE + 128];
|
||||
|
||||
static const lws_retry_bo_t retry = {
|
||||
.secs_since_valid_ping = 3,
|
||||
.secs_since_valid_hangup = 10,
|
||||
};
|
||||
|
||||
#if CONFIG_WEBSOCKET_URI_FROM_STDIN
|
||||
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);
|
||||
esp_task_wdt_reset();
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_WEBSOCKET_URI_FROM_STDIN */
|
||||
|
||||
static void send_data(struct lws *wsi, const char *data, size_t len, enum lws_write_protocol type)
|
||||
{
|
||||
unsigned char buf[LWS_PRE + len];
|
||||
unsigned char *p = &buf[LWS_PRE];
|
||||
memcpy(p, data, len);
|
||||
|
||||
int n = lws_write(wsi, p, len, type);
|
||||
if (n < len) {
|
||||
ESP_LOGE(TAG, "ERROR %d writing ws\n", n);
|
||||
}
|
||||
}
|
||||
|
||||
static void send_large_text_data(struct lws *wsi)
|
||||
{
|
||||
const int size = 2000;
|
||||
char *long_data = malloc(size);
|
||||
memset(long_data, 'a', size);
|
||||
send_data(wsi, long_data, size, LWS_WRITE_TEXT);
|
||||
free(long_data);
|
||||
}
|
||||
|
||||
static void send_fragmented_text_data(struct lws *wsi)
|
||||
{
|
||||
char data[32];
|
||||
memset(data, 'a', sizeof(data));
|
||||
send_data(wsi, data, sizeof(data), LWS_WRITE_TEXT | LWS_WRITE_NO_FIN);
|
||||
memset(data, 'b', sizeof(data));
|
||||
send_data(wsi, data, sizeof(data), LWS_WRITE_CONTINUATION);
|
||||
}
|
||||
|
||||
static void send_fragmented_binary_data(struct lws *wsi)
|
||||
{
|
||||
char binary_data[5];
|
||||
memset(binary_data, 0, sizeof(binary_data));
|
||||
send_data(wsi, binary_data, sizeof(binary_data), LWS_WRITE_BINARY | LWS_WRITE_NO_FIN);
|
||||
memset(binary_data, 1, sizeof(binary_data));
|
||||
send_data(wsi, binary_data, sizeof(binary_data), LWS_WRITE_CONTINUATION);
|
||||
}
|
||||
|
||||
static void connect_cb(lws_sorted_usec_list_t *_sul)
|
||||
{
|
||||
struct lws_client_connect_info connect_info;
|
||||
|
||||
ESP_LOGI(TAG, "%s: connecting\n", __func__);
|
||||
|
||||
memset(&connect_info, 0, sizeof(connect_info));
|
||||
#if CONFIG_WEBSOCKET_URI_FROM_STDIN
|
||||
char line[128];
|
||||
|
||||
ESP_LOGI(TAG, "Please enter uri of websocket endpoint");
|
||||
get_string(line, sizeof(line));
|
||||
|
||||
connect_info.address = line;
|
||||
ESP_LOGI(TAG, "Endpoint uri: %s\n", line);
|
||||
|
||||
#else
|
||||
connect_info.address = CONFIG_WEBSOCKET_URI;
|
||||
#endif /* CONFIG_WEBSOCKET_URI_FROM_STDIN */
|
||||
|
||||
|
||||
connect_info.context = context;
|
||||
connect_info.port = CONFIG_WEBSOCKET_PORT;
|
||||
connect_info.host = connect_info.address;
|
||||
connect_info.origin = connect_info.address;
|
||||
connect_info.local_protocol_name = "lws-echo";
|
||||
connect_info.pwsi = &client_wsi;
|
||||
connect_info.retry_and_idle_policy = &retry;
|
||||
|
||||
#if defined(CONFIG_WS_OVER_TLS_MUTUAL_AUTH) || defined(CONFIG_WS_OVER_TLS_SERVER_AUTH)
|
||||
connect_info.ssl_connection = LCCSCF_USE_SSL | LCCSCF_ALLOW_SELFSIGNED;
|
||||
|
||||
#if defined(CONFIG_WS_OVER_TLS_SKIP_COMMON_NAME_CHECK) && defined(CONFIG_WS_OVER_TLS_SERVER_AUTH)
|
||||
connect_info.ssl_connection |= LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;
|
||||
#endif
|
||||
#else
|
||||
connect_info.ssl_connection = LCCSCF_ALLOW_INSECURE;
|
||||
#endif
|
||||
|
||||
if (!lws_client_connect_via_info(&connect_info)) {
|
||||
lws_sul_schedule(context, 0, _sul, connect_cb, 5 * LWS_USEC_PER_SEC);
|
||||
}
|
||||
}
|
||||
|
||||
static int callback_minimal_echo(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
switch (reason) {
|
||||
|
||||
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
|
||||
ESP_LOGE(TAG, "CLIENT_CONNECTION_ERROR: %s\n",
|
||||
in ? (char *)in : "(null)");
|
||||
lws_sul_schedule(context, 0, &sul, connect_cb, 5 * LWS_USEC_PER_SEC);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLIENT_ESTABLISHED:
|
||||
ESP_LOGI(TAG, "WEBSOCKET_EVENT_CONNECTED");
|
||||
lws_callback_on_writable(wsi);
|
||||
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLIENT_WRITEABLE:
|
||||
if (message_count < 5) {
|
||||
char text_data[32];
|
||||
sprintf(text_data, "hello %04d", message_count++);
|
||||
ESP_LOGI(TAG, "Sending text: %s", text_data);
|
||||
send_data(wsi, text_data, strlen(text_data), LWS_WRITE_TEXT);
|
||||
} else if (message_count == 5) {
|
||||
ESP_LOGI(TAG, "Sending fragmented text message");
|
||||
send_fragmented_text_data(wsi);
|
||||
ESP_LOGI(TAG, "Sending fragmented binary message");
|
||||
send_fragmented_binary_data(wsi);
|
||||
ESP_LOGI(TAG, "Sending text longer than ws buffer (1024)");
|
||||
send_large_text_data(wsi);
|
||||
message_count++;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLIENT_RECEIVE:
|
||||
ESP_LOGI(TAG, "WEBSOCKET_EVENT_DATA");
|
||||
|
||||
if (lws_frame_is_binary(wsi)) {
|
||||
ESP_LOGI(TAG, "Received binary data");
|
||||
ESP_LOG_BUFFER_HEX("Received binary data", in, len);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Received=%.*s\n\n", len, (char *)in);
|
||||
}
|
||||
|
||||
size_t remain = lws_remaining_packet_payload(wsi);
|
||||
|
||||
// If received data is larger than the ws buffer
|
||||
if (remain > 0) {
|
||||
ESP_LOGW(TAG, "Total payload length=%u, data_len=%u\n\n", remain + len, len);
|
||||
}
|
||||
|
||||
// If received data contains json structure it succeed to parse
|
||||
cJSON *root = cJSON_Parse(in);
|
||||
if (root) {
|
||||
for (int i = 0 ; i < cJSON_GetArraySize(root) ; i++) {
|
||||
cJSON *elem = cJSON_GetArrayItem(root, i);
|
||||
cJSON *id = cJSON_GetObjectItem(elem, "id");
|
||||
cJSON *name = cJSON_GetObjectItem(elem, "name");
|
||||
ESP_LOGW(TAG, "Json={'id': '%s', 'name': '%s'}", id->valuestring, name->valuestring);
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
/* Reset the timeout*/
|
||||
lws_set_timer_usecs(wsi, disconnect_timeout);
|
||||
break;
|
||||
case LWS_CALLBACK_TIMER:
|
||||
ESP_LOGW(TAG, "Closing connection");
|
||||
lws_close_reason(wsi, LWS_CLOSE_STATUS_NORMAL, (unsigned char *)"bye", 3);
|
||||
/* Return non-null to close the connection. */
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return lws_callback_http_dummy(wsi, reason, user, in, len);
|
||||
}
|
||||
|
||||
static const struct lws_protocols protocols[] = {
|
||||
{
|
||||
.name = "lws-echo",
|
||||
.callback = callback_minimal_echo,
|
||||
.per_session_data_size = 1024,
|
||||
.rx_buffer_size = 1024,
|
||||
.id = 0,
|
||||
.user = NULL,
|
||||
.tx_packet_size = 0
|
||||
},
|
||||
LWS_PROTOCOL_LIST_TERM
|
||||
};
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "[APP] Startup..");
|
||||
ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size());
|
||||
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
|
||||
esp_log_level_set("*", ESP_LOG_INFO);
|
||||
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(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());
|
||||
|
||||
/* Configure WDT. */
|
||||
TaskHandle_t handle = xTaskGetCurrentTaskHandle();
|
||||
esp_task_wdt_add(handle);
|
||||
|
||||
/* Create LWS Context - Client. */
|
||||
struct lws_context_creation_info info;
|
||||
int logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
|
||||
|
||||
memset(msg, 'x', sizeof(msg));
|
||||
|
||||
lws_set_log_level(logs, NULL);
|
||||
ESP_LOGI(TAG, "LWS minimal ws client echo\n");
|
||||
|
||||
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
|
||||
info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
|
||||
info.protocols = protocols;
|
||||
info.fd_limit_per_thread = 1 + 1 + 1;
|
||||
|
||||
#if CONFIG_WS_OVER_TLS_MUTUAL_AUTH
|
||||
info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
||||
|
||||
/* Configuring client certificates for mutual authentification */
|
||||
extern const char cert_start[] asm("_binary_client_cert_pem_start"); // Client certificate
|
||||
extern const char cert_end[] asm("_binary_client_cert_pem_end");
|
||||
extern const char key_start[] asm("_binary_client_key_pem_start"); // Client private key
|
||||
extern const char key_end[] asm("_binary_client_key_pem_end");
|
||||
|
||||
info.client_ssl_cert_mem = cert_start;
|
||||
info.client_ssl_cert_mem_len = cert_end - cert_start;
|
||||
info.client_ssl_key_mem = key_start;
|
||||
info.client_ssl_key_mem_len = key_end - key_start;
|
||||
#elif CONFIG_WS_OVER_TLS_SERVER_AUTH
|
||||
info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
||||
|
||||
extern const char cacert_start[] asm("_binary_ca_cert_pem_start"); // CA certificate
|
||||
extern const char cacert_end[] asm("_binary_ca_cert_pem_end");
|
||||
|
||||
info.client_ssl_ca_mem = cacert_start;
|
||||
info.client_ssl_ca_mem_len = cacert_end - cacert_start;
|
||||
#endif
|
||||
|
||||
context = lws_create_context(&info);
|
||||
if (!context) {
|
||||
ESP_LOGE(TAG, "lws init failed");
|
||||
} else {
|
||||
lws_sul_schedule(context, 0, &sul, connect_cb, 100);
|
||||
/*
|
||||
* Holds the result of the lws_service call:
|
||||
* = 0 -> service succeeded and events were processed,
|
||||
* < 0 -> an error occurred or the event loop should stop
|
||||
*/
|
||||
int service_result = 0;
|
||||
while (service_result >= 0) {
|
||||
service_result = lws_service(context, 0);
|
||||
}
|
||||
|
||||
lws_context_destroy(context);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
//Should not get here, Spin undefinitely.
|
||||
vTaskDelay(10);
|
||||
taskYIELD();
|
||||
}
|
||||
}
|
237
components/libwebsockets/examples/client/pytest_websocket.py
Normal file
237
components/libwebsockets/examples/client/pytest_websocket.py
Normal file
@ -0,0 +1,237 @@
|
||||
# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import json
|
||||
import random
|
||||
import re
|
||||
import socket
|
||||
import ssl
|
||||
import string
|
||||
import sys
|
||||
from threading import Event, Thread
|
||||
|
||||
from SimpleWebSocketServer import (SimpleSSLWebSocketServer,
|
||||
SimpleWebSocketServer, WebSocket)
|
||||
|
||||
|
||||
def get_my_ip():
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
try:
|
||||
# doesn't even have to be reachable
|
||||
s.connect(('8.8.8.8', 1))
|
||||
IP = s.getsockname()[0]
|
||||
except Exception:
|
||||
IP = '127.0.0.1'
|
||||
finally:
|
||||
s.close()
|
||||
return IP
|
||||
|
||||
|
||||
class WebsocketTestEcho(WebSocket):
|
||||
def handleMessage(self):
|
||||
if isinstance(self.data, bytes):
|
||||
print(f'\n Server received binary data: {self.data.hex()}\n')
|
||||
self.sendMessage(self.data, binary=True)
|
||||
else:
|
||||
print(f'\n Server received: {self.data}\n')
|
||||
self.sendMessage(self.data)
|
||||
|
||||
def handleConnected(self):
|
||||
print('Connection from: {}'.format(self.address))
|
||||
|
||||
def handleClose(self):
|
||||
print('{} closed the connection'.format(self.address))
|
||||
|
||||
|
||||
# Simple Websocket server for testing purposes
|
||||
class Websocket(object):
|
||||
|
||||
def send_data(self, data):
|
||||
for nr, conn in self.server.connections.items():
|
||||
conn.sendMessage(data)
|
||||
|
||||
def run(self):
|
||||
if self.use_tls is True:
|
||||
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
||||
ssl_context.load_cert_chain(certfile='main/certs/server/server_cert.pem', keyfile='main/certs/server/server_key.pem')
|
||||
if self.client_verify is True:
|
||||
ssl_context.load_verify_locations(cafile='main/certs/ca_cert.pem')
|
||||
ssl_context.verify = ssl.CERT_REQUIRED
|
||||
ssl_context.check_hostname = False
|
||||
self.server = SimpleSSLWebSocketServer('', self.port, WebsocketTestEcho, ssl_context=ssl_context)
|
||||
else:
|
||||
self.server = SimpleWebSocketServer('', self.port, WebsocketTestEcho)
|
||||
while not self.exit_event.is_set():
|
||||
self.server.serveonce()
|
||||
|
||||
def __init__(self, port, use_tls, verify):
|
||||
self.port = port
|
||||
self.use_tls = use_tls
|
||||
self.client_verify = verify
|
||||
self.exit_event = Event()
|
||||
self.thread = Thread(target=self.run)
|
||||
self.thread.start()
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self.exit_event.set()
|
||||
self.thread.join(10)
|
||||
if self.thread.is_alive():
|
||||
print('Thread cannot be joined', 'orange')
|
||||
|
||||
|
||||
def test_examples_protocol_websocket(dut):
|
||||
"""
|
||||
steps:
|
||||
1. obtain IP address
|
||||
2. connect to uri specified in the config
|
||||
3. send and receive data
|
||||
"""
|
||||
|
||||
# Test for echo functionality:
|
||||
# Sends a series of simple "hello" messages to the WebSocket server and verifies that each one is echoed back correctly.
|
||||
# This tests the basic responsiveness and correctness of the WebSocket connection.
|
||||
def test_echo(dut):
|
||||
dut.expect('WEBSOCKET_EVENT_CONNECTED')
|
||||
for i in range(0, 5):
|
||||
dut.expect(re.compile(b'Received=hello (\\d)'))
|
||||
print('All echos received')
|
||||
sys.stdout.flush()
|
||||
|
||||
# Test for clean closure of the WebSocket connection:
|
||||
# Ensures that the WebSocket can correctly receive a close frame and terminate the connection without issues.
|
||||
def test_close(dut):
|
||||
dut.expect('__lws_lc_untag')
|
||||
|
||||
# Test for JSON message handling:
|
||||
# Sends a JSON formatted string and verifies that the received message matches the expected JSON structure.
|
||||
def test_json(dut, websocket):
|
||||
json_string = """
|
||||
[
|
||||
{
|
||||
"id":"1",
|
||||
"name":"user1"
|
||||
},
|
||||
{
|
||||
"id":"2",
|
||||
"name":"user2"
|
||||
}
|
||||
]
|
||||
"""
|
||||
websocket.send_data(json_string)
|
||||
data = json.loads(json_string)
|
||||
|
||||
match = dut.expect(
|
||||
re.compile(b'Json=({[a-zA-Z0-9]*).*}')).group(0).decode()[5:]
|
||||
if match == str(data[0]):
|
||||
print('\n Sent message and received message are equal \n')
|
||||
sys.stdout.flush()
|
||||
else:
|
||||
raise ValueError(
|
||||
'DUT received string do not match sent string, \nexpected: {}\nwith length {}\
|
||||
\nreceived: {}\nwith length {}'.format(
|
||||
data[0], len(data[0]), match, len(match)))
|
||||
|
||||
# Test for receiving long messages:
|
||||
# This sends a message with a specified length (2000 characters) to ensure the WebSocket can handle large data payloads. Repeated 3 times for reliability.
|
||||
def test_recv_long_msg(dut, websocket, msg_len, repeats):
|
||||
|
||||
send_msg = ''.join(
|
||||
random.choice(string.ascii_uppercase + string.ascii_lowercase +
|
||||
string.digits) for _ in range(msg_len))
|
||||
|
||||
for _ in range(repeats):
|
||||
websocket.send_data(send_msg)
|
||||
|
||||
recv_msg = ''
|
||||
while len(recv_msg) < msg_len:
|
||||
match = dut.expect(re.compile(
|
||||
b'Received=([a-zA-Z0-9]*).*\n')).group(1).decode()
|
||||
recv_msg += match
|
||||
|
||||
if recv_msg == send_msg:
|
||||
print('\n Sent message and received message are equal \n')
|
||||
sys.stdout.flush()
|
||||
else:
|
||||
raise ValueError(
|
||||
'DUT received string do not match sent string, \nexpected: {}\nwith length {}\
|
||||
\nreceived: {}\nwith length {}'.format(
|
||||
send_msg, len(send_msg), recv_msg, len(recv_msg)))
|
||||
|
||||
# Test for receiving the first fragment of a large message:
|
||||
# Verifies the WebSocket's ability to correctly process the initial segment of a fragmented message.
|
||||
def test_recv_fragmented_msg1(dut):
|
||||
dut.expect('Total payload length=2000, data_len=1024')
|
||||
|
||||
# Test for receiving fragmented text messages:
|
||||
# Checks if the WebSocket can accurately reconstruct a message sent in several smaller parts.
|
||||
def test_fragmented_txt_msg(dut):
|
||||
dut.expect('Received=' + 32 * 'a' + 32 * 'b')
|
||||
print('\nFragmented data received\n')
|
||||
|
||||
# Extract the hexdump portion of the log line
|
||||
def parse_hexdump(line):
|
||||
match = re.search(r'\(.*\) Received binary data: ([0-9A-Fa-f ]+)', line)
|
||||
if match:
|
||||
hexdump = match.group(1).strip().replace(' ', '')
|
||||
# Convert the hexdump string to a bytearray
|
||||
return bytearray.fromhex(hexdump)
|
||||
return bytearray()
|
||||
|
||||
# Capture the binary log output from the DUT
|
||||
def test_fragmented_binary_msg(dut):
|
||||
match = dut.expect(r'\(.*\) Received binary data: .*')
|
||||
if match:
|
||||
line = match.group(0).strip()
|
||||
if isinstance(line, bytes):
|
||||
line = line.decode('utf-8')
|
||||
|
||||
# Parse the hexdump from the log line
|
||||
received_data = parse_hexdump(line)
|
||||
|
||||
# Create the expected bytearray with the specified pattern
|
||||
expected_data = bytearray([0, 0, 0, 0, 0, 1, 1, 1, 1, 1])
|
||||
|
||||
# Validate the received data
|
||||
assert received_data == expected_data, f'Received data does not match expected data. Received: {received_data}, Expected: {expected_data}'
|
||||
print('\nFragmented data received\n')
|
||||
else:
|
||||
assert False, 'Log line with binary data not found'
|
||||
|
||||
# Starting of the test
|
||||
try:
|
||||
if dut.app.sdkconfig.get('WEBSOCKET_URI_FROM_STDIN') is True:
|
||||
uri_from_stdin = True
|
||||
else:
|
||||
uri = dut.app.sdkconfig['WEBSOCKET_URI']
|
||||
uri_from_stdin = False
|
||||
|
||||
if dut.app.sdkconfig.get('WS_OVER_TLS_MUTUAL_AUTH') is True:
|
||||
use_tls = True
|
||||
client_verify = True
|
||||
else:
|
||||
use_tls = False
|
||||
client_verify = False
|
||||
|
||||
except Exception:
|
||||
print('ENV_TEST_FAILURE: Cannot find uri settings in sdkconfig')
|
||||
raise
|
||||
|
||||
if uri_from_stdin:
|
||||
server_port = 8080
|
||||
with Websocket(server_port, use_tls, client_verify) as ws:
|
||||
uri = '{}'.format(get_my_ip())
|
||||
print('DUT connecting to {}'.format(uri))
|
||||
dut.expect('Please enter uri of websocket endpoint', timeout=30)
|
||||
dut.write(uri)
|
||||
test_echo(dut)
|
||||
test_recv_long_msg(dut, ws, 2000, 3)
|
||||
test_json(dut, ws)
|
||||
test_fragmented_txt_msg(dut)
|
||||
test_fragmented_binary_msg(dut)
|
||||
test_recv_fragmented_msg1(dut)
|
||||
test_close(dut)
|
||||
else:
|
||||
print('DUT connecting to {}'.format(uri))
|
||||
test_echo(dut)
|
13
components/libwebsockets/examples/client/sdkconfig.ci
Normal file
13
components/libwebsockets/examples/client/sdkconfig.ci
Normal file
@ -0,0 +1,13 @@
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_IDF_TARGET_LINUX=n
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
|
||||
CONFIG_EXAMPLE_ETH_PHY_IP101=y
|
||||
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
|
||||
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
|
||||
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
|
||||
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=y
|
||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=5120
|
@ -0,0 +1,18 @@
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_IDF_TARGET_LINUX=n
|
||||
CONFIG_WEBSOCKET_URI_FROM_STDIN=y
|
||||
CONFIG_WEBSOCKET_URI_FROM_STRING=n
|
||||
CONFIG_WEBSOCKET_PORT=8080
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
|
||||
CONFIG_EXAMPLE_ETH_PHY_IP101=y
|
||||
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
|
||||
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
|
||||
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
|
||||
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=y
|
||||
CONFIG_WS_OVER_TLS_MUTUAL_AUTH=y
|
||||
CONFIG_WS_OVER_TLS_SKIP_COMMON_NAME_CHECK=y
|
||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=5120
|
@ -0,0 +1,18 @@
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_IDF_TARGET_LINUX=n
|
||||
CONFIG_WEBSOCKET_URI_FROM_STDIN=y
|
||||
CONFIG_WEBSOCKET_URI_FROM_STRING=n
|
||||
CONFIG_WEBSOCKET_PORT=8080
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
|
||||
CONFIG_EXAMPLE_ETH_PHY_IP101=y
|
||||
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
|
||||
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
|
||||
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
|
||||
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=y
|
||||
CONFIG_WS_OVER_TLS_MUTUAL_AUTH=n
|
||||
CONFIG_WS_OVER_TLS_SERVER_AUTH=n
|
||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=5120
|
5
components/libwebsockets/idf_component.yml
Normal file
5
components/libwebsockets/idf_component.yml
Normal file
@ -0,0 +1,5 @@
|
||||
version: "0.1.0"
|
||||
url: https://github.com/espressif/esp-protocols/tree/master/components/libwebsockets
|
||||
description: The component provides a simple ESP-IDF port of libwebsockets client.
|
||||
dependencies:
|
||||
idf: '>=5.3'
|
1
components/libwebsockets/libwebsockets
Submodule
1
components/libwebsockets/libwebsockets
Submodule
Submodule components/libwebsockets/libwebsockets added at a74362ffdd
57
components/libwebsockets/port/lws_port.c
Normal file
57
components/libwebsockets/port/lws_port.c
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "stdio.h"
|
||||
#include <libwebsockets.h>
|
||||
|
||||
/*
|
||||
* External function prototype for the wrapped 'mbedtls_ssl_handshake_step'.
|
||||
* The "real" function is not being called, this prototype is just to improve
|
||||
* the code readability.
|
||||
*/
|
||||
extern int __real_mbedtls_ssl_handshake_step(mbedtls_ssl_context *ssl);
|
||||
|
||||
int __wrap_mbedtls_ssl_handshake_step( mbedtls_ssl_context *ssl )
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
while (ssl->MBEDTLS_PRIVATE(state) != MBEDTLS_SSL_HANDSHAKE_OVER) {
|
||||
ret = __real_mbedtls_ssl_handshake_step(ssl);
|
||||
|
||||
if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* External function prototype for the wrapped 'lws_adopt_descriptor_vhost'.
|
||||
* The "real" function is not being called, this prototype is just to improve
|
||||
* the code readability.
|
||||
*/
|
||||
extern struct lws *__real_lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type, lws_sock_file_fd_type fd, const char *vh_prot_name, struct lws *parent);
|
||||
|
||||
struct lws *__wrap_lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type, lws_sock_file_fd_type fd, const char *vh_prot_name, struct lws *parent)
|
||||
{
|
||||
lws_adopt_desc_t info;
|
||||
char nullstr[] = "(null)";
|
||||
memset(&info, 0, sizeof(info));
|
||||
|
||||
info.vh = vh;
|
||||
info.type = type;
|
||||
info.fd = fd;
|
||||
info.vh_prot_name = vh_prot_name;
|
||||
info.parent = parent;
|
||||
info.fi_wsi_name = nullstr;
|
||||
|
||||
return lws_adopt_descriptor_vhost_via_info(&info);
|
||||
}
|
@ -15,6 +15,7 @@ set(EXTRA_COMPONENT_DIRS
|
||||
../components/console_simple_init
|
||||
../components/mbedtls_cxx
|
||||
../components/sock_utils
|
||||
../components/libwebsockets
|
||||
../components/mdns)
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user