├── utils ├── restyle.sh └── astyle_library.conf ├── .codespellrc ├── .github ├── workflows │ ├── auto-github-actions.yml │ ├── report-size-deltas.yml │ ├── spell-check.yml │ └── check-arduino.yml ├── dependabot.yml ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── stale.yml ├── .gitignore ├── library.properties ├── examples └── multiFileProject │ ├── multiFileProject.cpp │ ├── multiFileProject.h │ └── multiFileProject.ino ├── library.json ├── CONTRIBUTING.md ├── changelog.md ├── src ├── AsyncTCP_SSL.h ├── tcp_mbedtls.h ├── AsyncTCP_SSL_Debug.h ├── AsyncTCP_SSL.hpp ├── tcp_mbedtls.c └── AsyncTCP_SSL_Impl.h ├── LICENSE ├── platformio └── platformio.ini └── README.md /utils/restyle.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for dir in . ; do 4 | find $dir -type f \( -name "*.c" -o -name "*.h" -o -name "*.cpp" -o -name "*.ino" \) -exec astyle --suffix=none --options=./utils/astyle_library.conf \{\} \; 5 | done 6 | 7 | -------------------------------------------------------------------------------- /.codespellrc: -------------------------------------------------------------------------------- 1 | # See: https://github.com/codespell-project/codespell#using-a-config-file 2 | [codespell] 3 | # In the event of a false positive, add the problematic word, in all lowercase, to a comma-separated list here: 4 | ignore-words-list = , 5 | check-filenames = 6 | check-hidden = 7 | skip = ./.git,./src,./examples,./Packages_Patches,./LibraryPatches 8 | -------------------------------------------------------------------------------- /.github/workflows/auto-github-actions.yml: -------------------------------------------------------------------------------- 1 | name: auto-github-actions 2 | on: [push] 3 | jobs: 4 | check-bats-version: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v3 8 | - uses: actions/setup-node@v3 9 | with: 10 | node-version: '14' 11 | - run: npm install -g bats 12 | - run: bats -v 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /.github/workflows/report-size-deltas.yml: -------------------------------------------------------------------------------- 1 | name: Report Size Deltas 2 | 3 | on: 4 | schedule: 5 | - cron: '*/5 * * * *' 6 | 7 | jobs: 8 | report: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Comment size deltas reports to PRs 13 | uses: arduino/report-size-deltas@v1 14 | with: 15 | # The name of the workflow artifact created by the "Compile Examples" workflow 16 | sketches-reports-source: sketches-reports 17 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # See: https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates#about-the-dependabotyml-file 2 | version: 2 3 | 4 | updates: 5 | # Configure check for outdated GitHub Actions actions in workflows. 6 | # See: https://docs.github.com/en/github/administering-a-repository/keeping-your-actions-up-to-date-with-dependabot 7 | - package-ecosystem: github-actions 8 | directory: / # Check the repository's workflows under /.github/workflows/ 9 | schedule: 10 | interval: daily 11 | -------------------------------------------------------------------------------- /.github/workflows/spell-check.yml: -------------------------------------------------------------------------------- 1 | name: Spell Check 2 | 3 | on: 4 | pull_request: 5 | push: 6 | schedule: 7 | # run every Tuesday at 3 AM UTC 8 | - cron: "0 3 * * 2" 9 | workflow_dispatch: 10 | repository_dispatch: 11 | 12 | jobs: 13 | spellcheck: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v3 19 | 20 | # See: https://github.com/codespell-project/actions-codespell/blob/master/README.md 21 | - name: Spell check 22 | uses: codespell-project/actions-codespell@master 23 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=AsyncTCP_SSL 2 | version=1.3.1 3 | author=Hristo Gochkov, Maarten Fremouw, Thorsten von Eicken, Khoi Hoang 4 | maintainer=Khoi Hoang 5 | sentence=Asynchronous SSL TCP Library for ESP32. 6 | paragraph=This library is the base for future and more advanced Async SSL libraries, such as AsyncSSLWebServer, AsyncHTTPSRequest, etc. 7 | category=Communication 8 | url=https://github.com/khoih-prog/AsyncTCP_SSL 9 | architectures=esp32 10 | repository=https://github.com/khoih-prog/AsyncTCP_SSL 11 | license=LGPLv3 12 | includes=AsyncTCP_SSL.h,AsyncTCP_SSL.hpp 13 | -------------------------------------------------------------------------------- /examples/multiFileProject/multiFileProject.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************************************************************** 2 | multiFileProject.cpp 3 | For ESP32 4 | 5 | AsyncTCP_SSL is a library for the ESP32 6 | 7 | Built by Khoi Hoang https://github.com/khoih-prog/AsyncTCP_SSL 8 | Licensed under MIT license 9 | *****************************************************************************************************************************/ 10 | 11 | // To demo how to include files in multi-file Projects 12 | 13 | #include "multiFileProject.h" 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Is your feature request related to a problem? Please describe. 11 | 12 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 13 | 14 | ### Describe the solution you'd like 15 | 16 | A clear and concise description of what you want to happen. 17 | 18 | ### Describe alternatives you've considered 19 | A clear and concise description of any alternative solutions or features you've considered. 20 | 21 | ### Additional context 22 | 23 | Add any other context or screenshots about the feature request here. 24 | -------------------------------------------------------------------------------- /.github/workflows/check-arduino.yml: -------------------------------------------------------------------------------- 1 | name: Check Arduino 2 | 3 | # See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows 4 | on: 5 | push: 6 | pull_request: 7 | schedule: 8 | # Run every Tuesday at 8 AM UTC to catch breakage caused by new rules added to Arduino Lint. 9 | - cron: "0 8 * * TUE" 10 | workflow_dispatch: 11 | repository_dispatch: 12 | 13 | jobs: 14 | lint: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout repository 19 | uses: actions/checkout@v3 20 | 21 | - name: Arduino Lint 22 | uses: arduino/arduino-lint-action@v1 23 | with: 24 | compliance: specification 25 | library-manager: update 26 | # Always use this setting for official repositories. Remove for 3rd party projects. 27 | official: true 28 | project-type: library 29 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-stale - https://github.com/probot/stale 2 | 3 | daysUntilStale: 60 4 | daysUntilClose: 14 5 | limitPerRun: 30 6 | staleLabel: stale 7 | exemptLabels: 8 | - pinned 9 | - security 10 | - "to be implemented" 11 | - "for reference" 12 | - "move to PR" 13 | - "enhancement" 14 | 15 | only: issues 16 | onlyLabels: [] 17 | exemptProjects: false 18 | exemptMilestones: false 19 | exemptAssignees: false 20 | 21 | markComment: > 22 | [STALE_SET] This issue has been automatically marked as stale because it has not had 23 | recent activity. It will be closed in 14 days if no further activity occurs. Thank you 24 | for your contributions. 25 | 26 | unmarkComment: > 27 | [STALE_CLR] This issue has been removed from the stale queue. Please ensure activity to keep it opening the future. 28 | 29 | closeComment: > 30 | [STALE_DEL] This stale issue has been automatically closed. Thank you for your contributions. 31 | 32 | -------------------------------------------------------------------------------- /examples/multiFileProject/multiFileProject.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************************************************************** 2 | multiFileProject.h 3 | For ESP32 4 | 5 | AsyncTCP_SSL is a library for the ESP32 6 | 7 | Built by Khoi Hoang https://github.com/khoih-prog/AsyncTCP_SSL 8 | Licensed under MIT license 9 | *****************************************************************************************************************************/ 10 | 11 | // To demo how to include files in multi-file Projects 12 | 13 | #pragma once 14 | 15 | // Use larger queue size if necessary for large data transfer. Default is 512 bytes if not defined here 16 | #define ASYNC_QUEUE_LENGTH 512 17 | 18 | // Use larger priority if necessary. Default is 10 if not defined here. Must be > 4 or adjusted to 4 19 | #define CONFIG_ASYNC_TCP_PRIORITY (12) 20 | 21 | // Can be included as many times as necessary, without `Multiple Definitions` Linker Error 22 | #include "AsyncTCP_SSL.hpp" 23 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"AsyncTCP_SSL", 3 | "version": "1.3.1", 4 | "keywords":"communication, async, tcp, ssl, tls, mbed, free-rtos", 5 | "description":"Asynchronous SSL TCP Library for ESP32. This library is the base for future and more advanced Async SSL libraries, such as AsyncSSLWebServer, AsyncHTTPSRequest, etc", 6 | "authors": 7 | [ 8 | { 9 | "name": "Hristo Gochkov", 10 | "url": "https://github.com/me-no-dev" 11 | }, 12 | { 13 | "name": "Maarten Fremouw", 14 | "url": "https://github.com/fremouw" 15 | }, 16 | { 17 | "name": "Thorsten von Eicken", 18 | "url": "https://github.com/tve" 19 | }, 20 | { 21 | "name": "Khoi Hoang", 22 | "url": "https://github.com/khoih-prog", 23 | "email": "khoih.prog@gmail.com", 24 | "maintainer": true 25 | } 26 | ], 27 | "repository": 28 | { 29 | "type": "git", 30 | "url": "https://github.com/khoih-prog/AsyncTCP_SSL.git" 31 | }, 32 | "homepage": "https://github.com/khoih-prog/AsyncTCP_SSL", 33 | "export": { 34 | "exclude": [ 35 | "linux", 36 | "extras", 37 | "tests" 38 | ] 39 | }, 40 | "license": "LGPL-3.0", 41 | "frameworks": "*", 42 | "platforms": "espressif32", 43 | "examples": "examples/*/*/*.ino", 44 | "headers": ["AsyncTCP_SSL.h", "AsyncTCP_SSL.hpp"] 45 | } 46 | -------------------------------------------------------------------------------- /utils/astyle_library.conf: -------------------------------------------------------------------------------- 1 | # Code formatting rules for Arduino libraries, modified from for KH libraries: 2 | # 3 | # https://github.com/arduino/Arduino/blob/master/build/shared/examples_formatter.conf 4 | # 5 | 6 | # astyle --style=allman -s2 -t2 -C -S -xW -Y -M120 -f -p -xg -H -xb -c --xC120 -xL *.h *.cpp *.ino 7 | 8 | --mode=c 9 | --lineend=linux 10 | --style=allman 11 | 12 | # -r or -R 13 | #--recursive 14 | 15 | # -c => Converts tabs into spaces 16 | convert-tabs 17 | 18 | # -s2 => 2 spaces indentation 19 | --indent=spaces=2 20 | 21 | # -t2 => tab =2 spaces 22 | #--indent=tab=2 23 | 24 | # -C 25 | --indent-classes 26 | 27 | # -S 28 | --indent-switches 29 | 30 | # -xW 31 | --indent-preproc-block 32 | 33 | # -Y => indent classes, switches (and cases), comments starting at column 1 34 | --indent-col1-comments 35 | 36 | # -M120 => maximum of 120 spaces to indent a continuation line 37 | --max-continuation-indent=120 38 | 39 | # -xC120 => max‑code‑length will break a line if the code exceeds # characters 40 | --max-code-length=120 41 | 42 | # -f => 43 | --break-blocks 44 | 45 | # -p => put a space around operators 46 | --pad-oper 47 | 48 | # -xg => Insert space padding after commas 49 | --pad-comma 50 | 51 | # -H => put a space after if/for/while 52 | pad-header 53 | 54 | # -xb => Break one line headers (e.g. if/for/while) 55 | --break-one-line-headers 56 | 57 | # -c => Converts tabs into spaces 58 | #--convert-tabs 59 | 60 | # if you like one-liners, keep them 61 | #keep-one-line-statements 62 | 63 | # -xV 64 | --attach-closing-while 65 | 66 | #unpad-paren 67 | 68 | # -xp 69 | remove-comment-prefix 70 | 71 | -------------------------------------------------------------------------------- /examples/multiFileProject/multiFileProject.ino: -------------------------------------------------------------------------------- 1 | /**************************************************************************************************************************** 2 | multiFileProject.ino 3 | For ESP32 4 | 5 | AsyncTCP_SSL is a library for the ESP32 6 | 7 | Built by Khoi Hoang https://github.com/khoih-prog/AsyncTCP_SSL 8 | Licensed under MIT license 9 | *****************************************************************************************************************************/ 10 | 11 | // To demo how to include files in multi-file Projects 12 | 13 | #if !( defined(ESP32) ) 14 | #error This code is intended to run on the ESP32 platform! Please check your Tools->Board setting. 15 | #endif 16 | 17 | #define ASYNC_TCP_SSL_VERSION_MIN_TARGET "AsyncTCP_SSL v1.3.1" 18 | #define ASYNC_TCP_SSL_VERSION_MIN 1003001 19 | 20 | #include "multiFileProject.h" 21 | 22 | #include 23 | 24 | // To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error 25 | #include "AsyncTCP_SSL.h" 26 | 27 | void setup() 28 | { 29 | Serial.begin(115200); 30 | 31 | while (!Serial && millis() < 5000); 32 | 33 | Serial.println("\nStart multiFileProject on "); 34 | Serial.println(ARDUINO_BOARD); 35 | Serial.println(ASYNC_TCP_SSL_VERSION); 36 | 37 | #if defined(ASYNC_TCP_SSL_VERSION_MIN) 38 | 39 | if (ASYNC_TCP_SSL_VERSION_INT < ASYNC_TCP_SSL_VERSION_MIN) 40 | { 41 | Serial.print("Warning. Must use this example on Version equal or later than : "); 42 | Serial.println(ASYNC_TCP_SSL_VERSION_MIN_TARGET); 43 | } 44 | 45 | #endif 46 | 47 | Serial.print("You're OK now"); 48 | } 49 | 50 | void loop() 51 | { 52 | // put your main code here, to run repeatedly: 53 | } 54 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing to AsyncTCP_SSL 2 | 3 | ### Reporting Bugs 4 | 5 | Please report bugs in [AsyncTCP_SSL Issues](https://github.com/khoih-prog/AsyncTCP_SSL/issues) if you find them. 6 | 7 | However, before reporting a bug please check through the following: 8 | 9 | * [Existing Open Issues](https://github.com/khoih-prog/AsyncTCP_SSL/issues) - someone might have already encountered this. 10 | 11 | If you don't find anything, please [open a new issue](https://github.com/khoih-prog/AsyncTCP_SSL/issues/new). 12 | 13 | ### How to submit a bug report 14 | 15 | Please ensure to specify the following: 16 | 17 | * Arduino IDE version (e.g. 1.8.19) or Platform.io version 18 | * `ESP32` Core Version (e.g. ESP32 core v2.0.5) 19 | * `ESP32` Board type (e.g. ESP32_DEV, ESP32_S2, ESP32_S3, ESP32_C3, etc.) 20 | * Contextual information (e.g. what you were trying to achieve) 21 | * Simplest possible steps to reproduce 22 | * Anything that might be relevant in your opinion, such as: 23 | * Operating system (Windows, Ubuntu, etc.) and the output of `uname -a` for Linux / Ubuntu 24 | * Network configuration 25 | 26 | 27 | ### Example 28 | 29 | ``` 30 | Arduino IDE version: 1.8.19 31 | ESP32 core v2.0.5 32 | ESP32_DEV Module 33 | OS: Ubuntu 20.04 LTS 34 | Linux xy-Inspiron-3593 5.15.0-53-generic #59~20.04.1-Ubuntu SMP Thu Oct 20 15:10:22 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux 35 | 36 | Context: 37 | I encountered a crash while using this library 38 | 39 | Steps to reproduce: 40 | 1. ... 41 | 2. ... 42 | 3. ... 43 | 4. ... 44 | ``` 45 | 46 | --- 47 | 48 | ### Sending Feature Requests 49 | 50 | Feel free to post feature requests. It's helpful if you can explain exactly why the feature would be useful. 51 | 52 | There are usually some outstanding feature requests in the [existing issues list](https://github.com/khoih-prog/AsyncTCP_SSL/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement), feel free to add comments to them. 53 | 54 | --- 55 | 56 | ### Sending Pull Requests 57 | 58 | Pull Requests with changes and fixes are also welcome! 59 | 60 | Please use the `astyle` to reformat the updated library code as follows (demo for Ubuntu Linux) 61 | 62 | 1. Change directory to the library GitHub 63 | 64 | ``` 65 | xy@xy-Inspiron-3593:~$ cd Arduino/xy/AsyncTCP_SSL_GitHub/ 66 | xy@xy-Inspiron-3593:~/Arduino/xy/AsyncTCP_SSL_GitHub$ 67 | ``` 68 | 69 | 2. Issue astyle command 70 | 71 | ``` 72 | xy@xy-Inspiron-3593:~/Arduino/xy/AsyncTCP_SSL_GitHub$ bash utils/restyle.sh 73 | ``` 74 | 75 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # AsyncTCP_SSL Library 2 | 3 | [![arduino-library-badge](https://www.ardu-badge.com/badge/AsyncTCP_SSL.svg?)](https://www.ardu-badge.com/AsyncTCP_SSL) 4 | [![GitHub release](https://img.shields.io/github/release/khoih-prog/AsyncTCP_SSL.svg)](https://github.com/khoih-prog/AsyncTCP_SSL/releases) 5 | [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](#Contributing) 6 | [![GitHub issues](https://img.shields.io/github/issues/khoih-prog/AsyncTCP_SSL.svg)](http://github.com/khoih-prog/AsyncTCP_SSL/issues) 7 | 8 | 9 | Donate to my libraries using BuyMeACoffee 10 | 11 | 12 | --- 13 | --- 14 | 15 | ## Table of Contents 16 | 17 | * [Changelog](#changelog) 18 | * [Releases v1.3.1](#Releases-v131) 19 | * [Releases v1.3.0](#Releases-v130) 20 | * [Releases v1.2.0](#Releases-v120) 21 | * [Releases v1.1.0](#Releases-v110) 22 | * [Initial Releases v1.0.0](#Initial-Releases-v100) 23 | 24 | --- 25 | --- 26 | 27 | ## Changelog 28 | 29 | ### Releases v1.3.1 30 | 31 | 1. Increase `ASYNC_QUEUE_LENGTH` to default 512 from 32 and make it user-configurable 32 | 2. Increase `ASYNC_TCP_PRIORITY` to default 10 from 3, and make it user-configurable 33 | 34 | 35 | ### Releases v1.3.0 36 | 37 | 1. Remove hard-code if possible 38 | 2. Improve debug messages by adding functions to display `error/state messages` instead of `cryptic error/state number` 39 | 3. Clean up 40 | 4. Add support to `ESP32_S3`, using ESP32 core `v2.0.3`. **Don't use `ESP32_S3` with core v2.0.4**. Check [ESP32-S3 Powercycling right after uploading a sketch using Arduino IDE and Arduino Core 2.0.4 #7165](https://github.com/espressif/arduino-esp32/issues/7165) 41 | 42 | ### Releases v1.2.0 43 | 44 | 1. Fix `multiple-definitions` linker error. Drop `src_cpp` and `src_h` directories 45 | 2. Add example [multiFileProject](examples/multiFileProject) to demo for multiple-file project. 46 | 3. Add `platformio.ini` 47 | 48 | ### Releases v1.1.0 49 | 50 | 1. Fix duplication bug when using `src_h` 51 | 2. Enable coexistence with AsyncTCP 52 | 53 | ### Initial Releases v1.0.0 54 | 55 | 1. Initial coding to support **ESP32** 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /src/AsyncTCP_SSL.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************************************************************** 2 | AsyncTCP_SSL.h 3 | 4 | AsyncTCP_SSL is a library for ESP32 5 | 6 | Based on and modified from : 7 | 8 | 1) AsyncTCP (https://github.com/me-no-dev/ESPAsyncTCP) 9 | 2) AsyncTCP (https://github.com/tve/AsyncTCP) 10 | 11 | Built by Khoi Hoang https://github.com/khoih-prog/AsyncTCP_SSL 12 | 13 | This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License 14 | as published bythe Free Software Foundation, either version 3 of the License, or (at your option) any later version. 15 | This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 17 | 18 | Version: 1.3.1 19 | 20 | Version Modified By Date Comments 21 | ------- ----------- ---------- ----------- 22 | 1.0.0 K Hoang 21/10/2021 Initial coding to support only ESP32 23 | 1.1.0 K Hoang 22/10/2021 Fix bug. Enable coexistence with AsyncTCP 24 | 1.2.0 K Hoang 23/01/2022 Fix `multiple-definitions` linker error 25 | 1.3.0 K Hoang 04/09/2022 Clean up. Remove hard-code if possible 26 | 1.3.1 K Hoang 18/09/2022 Improve stability. Make queue length user-configurable 27 | *****************************************************************************************************************************/ 28 | 29 | /* 30 | Asynchronous TCP library for Espressif MCUs 31 | 32 | Copyright (c) 2016 Hristo Gochkov. All rights reserved. 33 | This file is part of the esp8266 core for Arduino environment. 34 | 35 | This library is free software; you can redistribute it and/or 36 | modify it under the terms of the GNU Lesser General Public 37 | License as published by the Free Software Foundation; either 38 | version 2.1 of the License, or (at your option) any later version. 39 | 40 | This library is distributed in the hope that it will be useful, 41 | but WITHOUT ANY WARRANTY; without even the implied warranty of 42 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 43 | Lesser General Public License for more details. 44 | 45 | You should have received a copy of the GNU Lesser General Public 46 | License along with this library; if not, write to the Free Software 47 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 48 | */ 49 | 50 | #ifndef ASYNCTCP_SSL_H_ 51 | #define ASYNCTCP_SSL_H_ 52 | 53 | #include "AsyncTCP_SSL.hpp" 54 | #include "AsyncTCP_SSL_Impl.h" 55 | 56 | #endif /* ASYNCTCP_SSL_H_ */ 57 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Describe the bug 11 | 12 | A clear and concise description of what the bug is. 13 | 14 | ### Steps to Reproduce 15 | 16 | Steps to reproduce the behavior. Including the [MRE](https://stackoverflow.com/help/minimal-reproducible-example) sketches 17 | 18 | ### Expected behavior 19 | 20 | A clear and concise description of what you expected to happen. 21 | 22 | ### Actual behavior 23 | 24 | A clear and concise description of what you expected to happen. 25 | 26 | ### Debug and AT-command log (if applicable) 27 | 28 | A clear and concise description of what you expected to happen. 29 | 30 | ### Screenshots 31 | 32 | If applicable, add screenshots to help explain your problem. 33 | 34 | ### Information 35 | 36 | Please ensure to specify the following: 37 | 38 | * Arduino IDE version (e.g. 1.8.19) or Platform.io version 39 | * `ESP32` Core Version (e.g. ESP32 core v2.0.5) 40 | * `ESP32` Board type (e.g. ESP32_DEV, ESP32_S2, ESP32_S3, ESP32_C3, etc.) 41 | * Contextual information (e.g. what you were trying to achieve) 42 | * Simplest possible steps to reproduce 43 | * Anything that might be relevant in your opinion, such as: 44 | * Operating system (Windows, Ubuntu, etc.) and the output of `uname -a` for Linux / Ubuntu 45 | * Network configuration 46 | 47 | 48 | ### Example 49 | 50 | ``` 51 | Arduino IDE version: 1.8.19 52 | ESP32 core v2.0.5 53 | ESP32_DEV Module 54 | OS: Ubuntu 20.04 LTS 55 | Linux xy-Inspiron-3593 5.15.0-53-generic #59~20.04.1-Ubuntu SMP Thu Oct 20 15:10:22 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux 56 | 57 | Context: 58 | I encountered a crash while using this library 59 | 60 | Steps to reproduce: 61 | 1. ... 62 | 2. ... 63 | 3. ... 64 | 4. ... 65 | ``` 66 | 67 | --- 68 | 69 | ### Sending Feature Requests 70 | 71 | Feel free to post feature requests. It's helpful if you can explain exactly why the feature would be useful. 72 | 73 | There are usually some outstanding feature requests in the [existing issues list](https://github.com/khoih-prog/AsyncTCP_SSL/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement), feel free to add comments to them. 74 | 75 | --- 76 | 77 | ### Sending Pull Requests 78 | 79 | Pull Requests with changes and fixes are also welcome! 80 | 81 | Please use the `astyle` to reformat the updated library code as follows (demo for Ubuntu Linux) 82 | 83 | 1. Change directory to the library GitHub 84 | 85 | ``` 86 | xy@xy-Inspiron-3593:~$ cd Arduino/xy/AsyncTCP_SSL_GitHub/ 87 | xy@xy-Inspiron-3593:~/Arduino/xy/AsyncTCP_SSL_GitHub$ 88 | ``` 89 | 90 | 2. Issue astyle command 91 | 92 | ``` 93 | xy@xy-Inspiron-3593:~/Arduino/xy/AsyncTCP_SSL_GitHub$ bash utils/restyle.sh 94 | ``` 95 | 96 | -------------------------------------------------------------------------------- /src/tcp_mbedtls.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************************************************************** 2 | tcp_mbedtls.h 3 | 4 | AsyncTCP_SSL is a library for ESP32 5 | 6 | Based on and modified from : 7 | 8 | 1) AsyncTCP (https://github.com/me-no-dev/ESPAsyncTCP) 9 | 2) AsyncTCP (https://github.com/tve/AsyncTCP) 10 | 11 | Built by Khoi Hoang https://github.com/khoih-prog/AsyncTCP_SSL 12 | 13 | This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License 14 | as published bythe Free Software Foundation, either version 3 of the License, or (at your option) any later version. 15 | This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 17 | 18 | Version: 1.3.1 19 | 20 | Version Modified By Date Comments 21 | ------- ----------- ---------- ----------- 22 | 1.0.0 K Hoang 21/10/2021 Initial coding to support only ESP32 23 | 1.1.0 K Hoang 22/10/2021 Fix bug. Enable coexistence with AsyncTCP 24 | 1.2.0 K Hoang 23/01/2022 Fix `multiple-definitions` linker error 25 | 1.3.0 K Hoang 04/09/2022 Clean up. Remove hard-code if possible 26 | 1.3.1 K Hoang 18/09/2022 Improve stability. Make queue length user-configurable 27 | *****************************************************************************************************************************/ 28 | 29 | #ifndef LWIPR_MBEDTLS_H 30 | #define LWIPR_MBEDTLS_H 31 | 32 | ///////////////////////////////////////////// 33 | 34 | #include "mbedtls/platform.h" 35 | #include "mbedtls/net.h" 36 | #include "mbedtls/debug.h" 37 | #include "mbedtls/ssl.h" 38 | #include "mbedtls/entropy.h" 39 | #include "mbedtls/ctr_drbg.h" 40 | #include "mbedtls/error.h" 41 | 42 | ///////////////////////////////////////////// 43 | 44 | #ifdef __cplusplus 45 | extern "C" { 46 | #endif 47 | 48 | #define ERR_TCP_SSL_INVALID_SSL -101 49 | #define ERR_TCP_SSL_INVALID_TCP -102 50 | #define ERR_TCP_SSL_INVALID_CLIENTFD -103 51 | #define ERR_TCP_SSL_INVALID_CLIENTFD_DATA -104 52 | #define ERR_TCP_SSL_INVALID_DATA -105 53 | 54 | ///////////////////////////////////////////// 55 | 56 | struct tcp_pcb; 57 | struct pbuf; 58 | struct tcp_ssl_pcb; 59 | 60 | ///////////////////////////////////////////// 61 | 62 | typedef void (* tcp_ssl_data_cb_t)(void *arg, struct tcp_pcb *tcp, uint8_t * data, size_t len); 63 | typedef void (* tcp_ssl_handshake_cb_t)(void *arg, struct tcp_pcb *tcp, struct tcp_ssl_pcb* ssl); 64 | typedef void (* tcp_ssl_error_cb_t)(void *arg, struct tcp_pcb *tcp, int8_t error); 65 | 66 | ///////////////////////////////////////////// 67 | 68 | uint8_t tcp_ssl_has_client(); 69 | int tcp_ssl_new_client(struct tcp_pcb *tcp, void *arg, const char* hostname, const char* root_ca, 70 | const size_t root_ca_len, 71 | const char* cli_cert, const size_t cli_cert_len, const char* cli_key, const size_t cli_key_len); 72 | int tcp_ssl_new_psk_client(struct tcp_pcb *tcp, void *arg, const char* psk_ident, const char* psk); 73 | int tcp_ssl_write(struct tcp_pcb *tcp, uint8_t *data, size_t len); 74 | int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p); 75 | int tcp_ssl_handshake_step(struct tcp_pcb *tcp); 76 | int tcp_ssl_free(struct tcp_pcb *tcp); 77 | bool tcp_ssl_has(struct tcp_pcb *tcp); 78 | void tcp_ssl_arg(struct tcp_pcb *tcp, void * arg); 79 | void tcp_ssl_data(struct tcp_pcb *tcp, tcp_ssl_data_cb_t arg); 80 | void tcp_ssl_handshake(struct tcp_pcb *tcp, tcp_ssl_handshake_cb_t arg); 81 | void tcp_ssl_err(struct tcp_pcb *tcp, tcp_ssl_error_cb_t arg); 82 | 83 | ///////////////////////////////////////////// 84 | 85 | #ifdef __cplusplus 86 | } 87 | #endif 88 | 89 | #endif // LWIPR_MBEDTLS_H 90 | 91 | -------------------------------------------------------------------------------- /src/AsyncTCP_SSL_Debug.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************************************************************** 2 | AsyncTCP_SSL_Debug.h 3 | 4 | AsyncTCP_SSL is a library for ESP32 5 | 6 | Based on and modified from : 7 | 8 | 1) AsyncTCP (https://github.com/me-no-dev/ESPAsyncTCP) 9 | 2) AsyncTCP (https://github.com/tve/AsyncTCP) 10 | 11 | Built by Khoi Hoang https://github.com/khoih-prog/AsyncTCP_SSL 12 | 13 | This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License 14 | as published bythe Free Software Foundation, either version 3 of the License, or (at your option) any later version. 15 | This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 17 | 18 | Version: 1.3.1 19 | 20 | Version Modified By Date Comments 21 | ------- ----------- ---------- ----------- 22 | 1.0.0 K Hoang 21/10/2021 Initial coding to support only ESP32 23 | 1.1.0 K Hoang 22/10/2021 Fix bug. Enable coexistence with AsyncTCP 24 | 1.2.0 K Hoang 23/01/2022 Fix `multiple-definitions` linker error 25 | 1.3.0 K Hoang 04/09/2022 Clean up. Remove hard-code if possible 26 | 1.3.1 K Hoang 18/09/2022 Improve stability. Make queue length user-configurable 27 | *****************************************************************************************************************************/ 28 | 29 | #pragma once 30 | 31 | #ifndef ASYNC_TCP_SSL_DEBUG_H 32 | #define ASYNC_TCP_SSL_DEBUG_H 33 | 34 | #ifdef ASYNC_TCP_SSL_DEBUG_PORT 35 | #define DBG_PORT_ATCP ASYNC_TCP_SSL_DEBUG_PORT 36 | #else 37 | #define DBG_PORT_ATCP Serial 38 | #endif 39 | 40 | // Change _ASYNC_TCP_SSL_LOGLEVEL_ to set tracing and logging verbosity 41 | // 0: DISABLED: no logging 42 | // 1: ERROR: errors 43 | // 2: WARN: errors and warnings 44 | // 3: INFO: errors, warnings and informational (default) 45 | // 4: DEBUG: errors, warnings, informational and debug 46 | 47 | #ifndef _ASYNC_TCP_SSL_LOGLEVEL_ 48 | #define _ASYNC_TCP_SSL_LOGLEVEL_ 1 49 | #endif 50 | 51 | ///////////////////////////////////////////////////////// 52 | 53 | #define ATCP_PRINT_MARK ATCP_PRINT("[ATCP] ") 54 | #define ATCP_PRINT_SP DBG_PORT_ATCP.print(" ") 55 | #define ATCP_PRINT_SP0X DBG_PORT_ATCP.print(" 0x") 56 | 57 | #define ATCP_PRINT DBG_PORT_ATCP.print 58 | #define ATCP_PRINTLN DBG_PORT_ATCP.println 59 | 60 | ///////////////////////////////////////////////////////// 61 | 62 | #define ATCP_LOGERROR(x) if(_ASYNC_TCP_SSL_LOGLEVEL_>0) { ATCP_PRINT_MARK; ATCP_PRINTLN(x); } 63 | #define ATCP_LOGERROR0(x) if(_ASYNC_TCP_SSL_LOGLEVEL_>0) { ATCP_PRINT(x); } 64 | #define ATCP_LOGERROR1(x,y) if(_ASYNC_TCP_SSL_LOGLEVEL_>0) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINTLN(y); } 65 | #define ATCP_HEXLOGERROR1(x,y) if(_ASYNC_TCP_SSL_LOGLEVEL_>0) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP0X; ATCP_PRINTLN(y, HEX); } 66 | #define ATCP_LOGERROR2(x,y,z) if(_ASYNC_TCP_SSL_LOGLEVEL_>0) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINT(y); ATCP_PRINT_SP; ATCP_PRINTLN(z); } 67 | #define ATCP_HEXLOGERROR2(x,y,z) if(_ASYNC_TCP_SSL_LOGLEVEL_>0) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP0X; ATCP_PRINT(y, HEX); ATCP_PRINT_SP0X; ATCP_PRINTLN(z, HEX); } 68 | #define ATCP_LOGERROR3(x,y,z,w) if(_ASYNC_TCP_SSL_LOGLEVEL_>0) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINT(y); ATCP_PRINT_SP; ATCP_PRINT(z); ATCP_PRINT_SP; ATCP_PRINTLN(w); } 69 | #define ATCP_LOGERROR5(x,y,z,w,xx,yy) if(_ASYNC_TCP_SSL_LOGLEVEL_>0) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINT(y); ATCP_PRINT_SP; ATCP_PRINT(z); ATCP_PRINT_SP; ATCP_PRINT(w); ATCP_PRINT_SP; ATCP_PRINT(xx); ATCP_PRINT_SP; ATCP_PRINTLN(yy); } 70 | 71 | ///////////////////////////////////////////////////////// 72 | 73 | #define ATCP_LOGWARN(x) if(_ASYNC_TCP_SSL_LOGLEVEL_>1) { ATCP_PRINT_MARK; ATCP_PRINTLN(x); } 74 | #define ATCP_LOGWARN0(x) if(_ASYNC_TCP_SSL_LOGLEVEL_>1) { ATCP_PRINT(x); } 75 | #define ATCP_LOGWARN1(x,y) if(_ASYNC_TCP_SSL_LOGLEVEL_>1) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINTLN(y); } 76 | #define ATCP_HEXLOGWARN1(x,y) if(_ASYNC_TCP_SSL_LOGLEVEL_>1) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP0X; ATCP_PRINTLN(y, HEX); } 77 | #define ATCP_LOGWARN2(x,y,z) if(_ASYNC_TCP_SSL_LOGLEVEL_>1) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINT(y); ATCP_PRINT_SP; ATCP_PRINTLN(z); } 78 | #define ATCP_HEXLOGWARN2(x,y,z) if(_ASYNC_TCP_SSL_LOGLEVEL_>1) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP0X; ATCP_PRINT(y, HEX); ATCP_PRINT_SP0X; ATCP_PRINTLN(z, HEX); } 79 | #define ATCP_LOGWARN3(x,y,z,w) if(_ASYNC_TCP_SSL_LOGLEVEL_>1) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINT(y); ATCP_PRINT_SP; ATCP_PRINT(z); ATCP_PRINT_SP; ATCP_PRINTLN(w); } 80 | #define ATCP_LOGWARN5(x,y,z,w,xx,yy) if(_ASYNC_TCP_SSL_LOGLEVEL_>1) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINT(y); ATCP_PRINT_SP; ATCP_PRINT(z); ATCP_PRINT_SP; ATCP_PRINT(w); ATCP_PRINT_SP; ATCP_PRINT(xx); ATCP_PRINT_SP; ATCP_PRINTLN(yy); } 81 | 82 | ///////////////////////////////////////////////////////// 83 | 84 | #define ATCP_LOGINFO(x) if(_ASYNC_TCP_SSL_LOGLEVEL_>2) { ATCP_PRINT_MARK; ATCP_PRINTLN(x); } 85 | #define ATCP_LOGINFO0(x) if(_ASYNC_TCP_SSL_LOGLEVEL_>2) { ATCP_PRINT(x); } 86 | #define ATCP_LOGINFO1(x,y) if(_ASYNC_TCP_SSL_LOGLEVEL_>2) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINTLN(y); } 87 | #define ATCP_HEXLOGINFO1(x,y) if(_ASYNC_TCP_SSL_LOGLEVEL_>2) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP0X; ATCP_PRINTLN(y, HEX); } 88 | #define ATCP_LOGINFO2(x,y,z) if(_ASYNC_TCP_SSL_LOGLEVEL_>2) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINT(y); ATCP_PRINT_SP; ATCP_PRINTLN(z); } 89 | #define ATCP_HEXLOGINFO2(x,y,z) if(_ASYNC_TCP_SSL_LOGLEVEL_>2) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP0X; ATCP_PRINT(y, HEX); ATCP_PRINT_SP0X; ATCP_PRINTLN(z, HEX); } 90 | #define ATCP_LOGINFO3(x,y,z,w) if(_ASYNC_TCP_SSL_LOGLEVEL_>2) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINT(y); ATCP_PRINT_SP; ATCP_PRINT(z); ATCP_PRINT_SP; ATCP_PRINTLN(w); } 91 | #define ATCP_LOGINFO5(x,y,z,w,xx,yy) if(_ASYNC_TCP_SSL_LOGLEVEL_>2) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINT(y); ATCP_PRINT_SP; ATCP_PRINT(z); ATCP_PRINT_SP; ATCP_PRINT(w); ATCP_PRINT_SP; ATCP_PRINT(xx); ATCP_PRINT_SP; ATCP_PRINTLN(yy); } 92 | 93 | ///////////////////////////////////////////////////////// 94 | 95 | #define ATCP_LOGDEBUG(x) if(_ASYNC_TCP_SSL_LOGLEVEL_>3) { ATCP_PRINT_MARK; ATCP_PRINTLN(x); } 96 | #define ATCP_LOGDEBUG0(x) if(_ASYNC_TCP_SSL_LOGLEVEL_>3) { ATCP_PRINT(x); } 97 | #define ATCP_LOGDEBUG1(x,y) if(_ASYNC_TCP_SSL_LOGLEVEL_>3) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINTLN(y); } 98 | #define ATCP_HEXLOGDEBUG1(x,y) if(_ASYNC_TCP_SSL_LOGLEVEL_>3) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP0X; ATCP_PRINTLN(y, HEX); } 99 | #define ATCP_LOGDEBUG2(x,y,z) if(_ASYNC_TCP_SSL_LOGLEVEL_>3) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINT(y); ATCP_PRINT_SP; ATCP_PRINTLN(z); } 100 | #define ATCP_HEXLOGDEBUG2(x,y,z) if(_ASYNC_TCP_SSL_LOGLEVEL_>3) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP0X; ATCP_PRINT(y, HEX); ATCP_PRINT_SP0X; ATCP_PRINTLN(z, HEX); } 101 | #define ATCP_LOGDEBUG3(x,y,z,w) if(_ASYNC_TCP_SSL_LOGLEVEL_>3) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINT(y); ATCP_PRINT_SP; ATCP_PRINT(z); ATCP_PRINT_SP; ATCP_PRINTLN(w); } 102 | #define ATCP_LOGDEBUG5(x,y,z,w,xx,yy) if(_ASYNC_TCP_SSL_LOGLEVEL_>3) { ATCP_PRINT_MARK; ATCP_PRINT(x); ATCP_PRINT_SP; ATCP_PRINT(y); ATCP_PRINT_SP; ATCP_PRINT(z); ATCP_PRINT_SP; ATCP_PRINT(w); ATCP_PRINT_SP; ATCP_PRINT(xx); ATCP_PRINT_SP; ATCP_PRINTLN(yy); } 103 | 104 | ///////////////////////////////////////////////////////// 105 | 106 | #endif //ASYNC_TCP_SSL_DEBUG_H 107 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /platformio/platformio.ini: -------------------------------------------------------------------------------- 1 | ;PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [platformio] 12 | ; ============================================================ 13 | ; chose environment: 14 | ; ESP8266 15 | ; ESP32 16 | ; SAMD 17 | ; NRF52 18 | ; STM32 19 | ; ============================================================ 20 | ;default_envs = ESP8266 21 | default_envs = ESP32 22 | ;default_envs = SAMD 23 | ;default_envs = NRF52 24 | ;default_envs = STM32 25 | 26 | [env] 27 | ; ============================================================ 28 | ; Serial configuration 29 | ; choose upload speed, serial-monitor speed 30 | ; ============================================================ 31 | upload_speed = 921600 32 | ;upload_port = COM11 33 | ;monitor_speed = 9600 34 | ;monitor_port = COM11 35 | 36 | ; Checks for the compatibility with frameworks and dev/platforms 37 | lib_compat_mode = strict 38 | lib_ldf_mode = chain+ 39 | ;lib_ldf_mode = deep+ 40 | 41 | lib_deps = 42 | 43 | build_flags = 44 | ; set your debug output (default=Serial) 45 | ; -D DEBUG_ESP_PORT=Serial 46 | ; comment the following line to enable WiFi debugging 47 | ; -D NDEBUG 48 | 49 | [env:ESP8266] 50 | platform = espressif8266 51 | framework = arduino 52 | ; ============================================================ 53 | ; Board configuration 54 | ; choose your board by uncommenting one of the following lines 55 | ; ============================================================ 56 | ;board = gen4iod 57 | ;board = huzzah 58 | ;board = oak 59 | ;board = esp_wroom_02 60 | ;board = espduino 61 | ;board = espectro 62 | ;board = espino 63 | ;board = espresso_lite_v1 64 | ;board = espresso_lite_v2 65 | ;board = esp12e 66 | ;board = esp01_1m 67 | ;board = esp01 68 | ;board = esp07 69 | ;board = esp8285 70 | ;board = heltec_wifi_kit_8 71 | ;board = inventone 72 | ;board = nodemcu 73 | board = nodemcuv2 74 | ;board = modwifi 75 | ;board = phoenix_v1 76 | ;board = phoenix_v2 77 | ;board = sparkfunBlynk 78 | ;board = thing 79 | ;board = thingdev 80 | ;board = esp210 81 | ;board = espinotee 82 | ;board = d1 83 | ;board = d1_mini 84 | ;board = d1_mini_lite 85 | ;board = d1_mini_pro 86 | ;board = wifi_slot 87 | ;board = wifiduino 88 | ;board = wifinfo 89 | ;board = wio_link 90 | ;board = wio_node 91 | ;board = xinabox_cw01 92 | ;board = esp32doit-devkit-v1 93 | 94 | [env:ESP32] 95 | platform = espressif32 96 | framework = arduino 97 | ; ============================================================ 98 | ; Board configuration 99 | ; choose your board by uncommenting one of the following lines 100 | ; ============================================================ 101 | ;board = esp32cam 102 | ;board = alksesp32 103 | ;board = featheresp32 104 | ;board = espea32 105 | ;board = bpi-bit 106 | ;board = d-duino-32 107 | board = esp32doit-devkit-v1 108 | ;board = pocket_32 109 | ;board = fm-devkit 110 | ;board = pico32 111 | ;board = esp32-evb 112 | ;board = esp32-gateway 113 | ;board = esp32-pro 114 | ;board = esp32-poe 115 | ;board = oroca_edubot 116 | ;board = onehorse32dev 117 | ;board = lopy 118 | ;board = lopy4 119 | ;board = wesp32 120 | ;board = esp32thing 121 | ;board = sparkfun_lora_gateway_1-channel 122 | ;board = ttgo-lora32-v1 123 | ;board = ttgo-t-beam 124 | ;board = turta_iot_node 125 | ;board = lolin_d32 126 | ;board = lolin_d32_pro 127 | ;board = lolin32 128 | ;board = wemosbat 129 | ;board = widora-air 130 | ;board = xinabox_cw02 131 | ;board = iotbusio 132 | ;board = iotbusproteus 133 | ;board = nina_w10 134 | 135 | [env:SAMD] 136 | platform = atmelsam 137 | framework = arduino 138 | ; ============================================================ 139 | ; Choose your board by uncommenting one of the following lines 140 | ; ============================================================ 141 | ; ============================================================ 142 | ; Board configuration Adafruit SAMD 143 | ; ============================================================ 144 | 145 | ;board = adafruit_feather_m0 146 | ;board = adafruit_feather_m0_express 147 | ;board = adafruit_metro_m0 148 | ;board = adafruit_circuitplayground_m0 149 | ;board = adafruit_gemma_m0 150 | ;board = adafruit_trinket_m0 151 | ;board = adafruit_itsybitsy_m0 152 | ;board = adafruit_pirkey 153 | ;board = adafruit_hallowing 154 | ;board = adafruit_crickit_m0 155 | ;board = adafruit_metro_m4 156 | ;board = adafruit_grandcentral_m4 157 | board = adafruit_itsybitsy_m4 158 | ;board = adafruit_feather_m4 159 | ;board = adafruit_trellis_m4 160 | ;board = adafruit_pyportal_m4 161 | ;board = adafruit_pyportal_m4_titano 162 | ;board = adafruit_pybadge_m4 163 | ;board = adafruit_metro_m4_airliftlite 164 | ;board = adafruit_pygamer_m4 165 | ;board = adafruit_pygamer_advance_m4 166 | ;board = adafruit_pybadge_airlift_m4 167 | ;board = adafruit_monster_m4sk 168 | ;board = adafruit_hallowing_m4 169 | 170 | ; ============================================================ 171 | ; Board configuration Arduino SAMD and SAM 172 | ; ============================================================ 173 | 174 | ;board = arduino_zero_edbg 175 | ;board = arduino_zero_native 176 | ;board = mkr1000 177 | ;board = mkrzero 178 | ;board = mkrwifi1010 179 | ;board = nano_33_iot 180 | ;board = mkrfox1200 181 | ;board = mkrwan1300 182 | ;board = mkrwan1310 183 | ;board = mkrgsm1400 184 | ;board = mkrnb1500 185 | ;board = mkrvidor4000 186 | ;board = adafruit_circuitplayground_m0 187 | ;board = mzero_pro_bl_dbg 188 | ;board = mzero_pro_bl 189 | ;board = mzero_bl 190 | ;board = tian 191 | ;board = tian_cons 192 | ;board = arduino_due_x_dbg 193 | ;board = arduino_due_x 194 | 195 | ; ============================================================ 196 | ; Board configuration Seeeduino SAMD 197 | ; ============================================================ 198 | 199 | ;board = seeed_wio_terminal 200 | ;board = Seeed_femto_m0 201 | ;board = seeed_XIAO_m0 202 | ;board = Wio_Lite_MG126 203 | ;board = WioGPS 204 | ;board = zero 205 | ;board = rolawan 206 | ;board = seeed_grove_ui_wireless 207 | 208 | 209 | [env:NRF52] 210 | platform = nordicnrf52 211 | framework = arduino 212 | ; ============================================================ 213 | ; Board configuration Adafruit nRF52 214 | ; choose your board by uncommenting one of the following lines 215 | ; ============================================================ 216 | ;board = feather52832 217 | board = feather52840 218 | ;board = feather52840sense 219 | ;board = itsybitsy52840 220 | ;board = cplaynrf52840 221 | ;board = cluenrf52840 222 | ;board = metro52840 223 | ;board = pca10056 224 | ;board = particle_xenon 225 | ;board = mdbt50qrx 226 | ;board = ninab302 227 | ;board = ninab112 228 | 229 | [env:STM32] 230 | platform = ststm32 231 | framework = arduino 232 | 233 | ; ============================================================ 234 | ; Choose your board by uncommenting one of the following lines 235 | ; ============================================================ 236 | 237 | ; ============================================================ 238 | ; Board configuration Nucleo-144 239 | ; ============================================================ 240 | 241 | ;board = nucleo_f207zg 242 | ;board = nucleo_f429zi 243 | ;board = nucleo_f746zg 244 | ;board = nucleo_f756zg 245 | ;board = nucleo_f767zi 246 | ;board = nucleo_h743zi 247 | ;board = nucleo_l496zg 248 | ;board = nucleo_l496zg-p 249 | ;board = nucleo_l4r5zi 250 | ;board = nucleo_l4r5zi-p 251 | 252 | ; ============================================================ 253 | ; Board configuration Nucleo-64 254 | ; ============================================================ 255 | 256 | ;board = nucleo_f030r8 257 | ;board = nucleo_f072rb 258 | 259 | ;board = nucleo_f091rc 260 | ;board = nucleo_f103rb 261 | ;board = nucleo_f302r8 262 | ;board = nucleo_f303re 263 | ;board = nucleo_f401re 264 | ;board = nucleo_f411re 265 | ;board = nucleo_f446re 266 | ;board = nucleo_g071rb 267 | ;board = nucleo_g431rb 268 | ;board = nucleo_g474re 269 | ;board = nucleo_l053r8 270 | ;board = nucleo_l073rz 271 | ;board = nucleo_l152re 272 | ;board = nucleo_l433rc_p 273 | ;board = nucleo_l452re 274 | ;board = nucleo_l452re-p 275 | ;board = nucleo_l476rg 276 | ;board = pnucleo_wb55rg 277 | 278 | ; ============================================================ 279 | ; Board configuration Nucleo-32 280 | ; ============================================================ 281 | 282 | ;board = nucleo_f031k6 283 | ;board = nucleo_l031k6 284 | ;board = nucleo_l412kb 285 | ;board = nucleo_l432lc 286 | ;board = nucleo_f303k8 287 | ;board = nucleo_g431kb 288 | 289 | ; ============================================================ 290 | ; Board configuration Discovery Boards 291 | ; ============================================================ 292 | 293 | ;board = disco_f030r8 294 | ;board = disco_f072rb 295 | ;board = disco_f030r8 296 | ;board = disco_f100rb 297 | ;board = disco_f407vg 298 | ;board = disco_f413zh 299 | ;board = disco_f746ng 300 | ;board = disco_g0316 301 | ;board = disco_l475vg_iot 302 | ;board = disco_f072cz-lrwan1 303 | 304 | ; ============================================================ 305 | ; Board configuration STM32MP1 Boards 306 | ; ============================================================ 307 | 308 | ;board = stm32mp157a-dk1 309 | ;board = stm32mp157c-dk2 310 | 311 | ; ============================================================ 312 | ; Board configuration Generic Boards 313 | ; ============================================================ 314 | 315 | ;board = bluepill_f103c6 316 | ;board = bluepill_f103c8 317 | ;board = blackpill_f103c8 318 | ;board = stm32f103cx 319 | ;board = stm32f103rx 320 | ;board = stm32f103tx 321 | ;board = stm32f103vx 322 | ;board = stm32f103zx 323 | ;board = stm32f103zet6 324 | ;board = maplemini_f103cb 325 | ;board = blackpill_f303cc 326 | ;board = black_f407ve 327 | ;board = black_f407vg 328 | ;board = black_f407ze 329 | ;board = black_f407zg 330 | ;board = blue_f407ve_mini 331 | ;board = blackpill_f401cc 332 | ;board = blackpill_f411ce 333 | ;board = coreboard_f401rc 334 | ;board = feather_f405 335 | 336 | ; ============================================================ 337 | ; Board configuration Many more Boards to be filled 338 | ; ============================================================ 339 | 340 | -------------------------------------------------------------------------------- /src/AsyncTCP_SSL.hpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************************************************************** 2 | AsyncTCP_SSL.hpp 3 | 4 | AsyncTCP_SSL is a library for ESP32 5 | 6 | Based on and modified from : 7 | 8 | 1) AsyncTCP (https://github.com/me-no-dev/ESPAsyncTCP) 9 | 2) AsyncTCP (https://github.com/tve/AsyncTCP) 10 | 11 | Built by Khoi Hoang https://github.com/khoih-prog/AsyncTCP_SSL 12 | 13 | This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License 14 | as published bythe Free Software Foundation, either version 3 of the License, or (at your option) any later version. 15 | This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 17 | 18 | Version: 1.3.1 19 | 20 | Version Modified By Date Comments 21 | ------- ----------- ---------- ----------- 22 | 1.0.0 K Hoang 21/10/2021 Initial coding to support only ESP32 23 | 1.1.0 K Hoang 22/10/2021 Fix bug. Enable coexistence with AsyncTCP 24 | 1.2.0 K Hoang 23/01/2022 Fix `multiple-definitions` linker error 25 | 1.3.0 K Hoang 04/09/2022 Clean up. Remove hard-code if possible 26 | 1.3.1 K Hoang 18/09/2022 Improve stability. Make queue length user-configurable 27 | *****************************************************************************************************************************/ 28 | 29 | /* 30 | Asynchronous TCP library for Espressif MCUs 31 | 32 | Copyright (c) 2016 Hristo Gochkov. All rights reserved. 33 | This file is part of the esp8266 core for Arduino environment. 34 | 35 | This library is free software; you can redistribute it and/or 36 | modify it under the terms of the GNU Lesser General Public 37 | License as published by the Free Software Foundation; either 38 | version 2.1 of the License, or (at your option) any later version. 39 | 40 | This library is distributed in the hope that it will be useful, 41 | but WITHOUT ANY WARRANTY; without even the implied warranty of 42 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 43 | Lesser General Public License for more details. 44 | 45 | You should have received a copy of the GNU Lesser General Public 46 | License along with this library; if not, write to the Free Software 47 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 48 | */ 49 | 50 | #ifndef ASYNCTCP_SSL_HPP 51 | #define ASYNCTCP_SSL_HPP 52 | 53 | #if !defined(ESP32) 54 | #error This AsyncTCP_SSL library is supporting only ESP32 55 | #endif 56 | 57 | ///////////////////////////////////////////////// 58 | 59 | #define ASYNC_TCP_SSL_VERSION "AsyncTCP_SSL v1.3.1" 60 | 61 | #define ASYNC_TCP_SSL_VERSION_MAJOR 1 62 | #define ASYNC_TCP_SSL_VERSION_MINOR 3 63 | #define ASYNC_TCP_SSL_VERSION_PATCH 1 64 | 65 | #define ASYNC_TCP_SSL_VERSION_INT 1003001 66 | 67 | ///////////////////////////////////////////////// 68 | 69 | #include "Arduino.h" 70 | 71 | #include "IPAddress.h" 72 | #include "sdkconfig.h" 73 | #include 74 | #include 75 | 76 | // in ./libraries/WiFiClientSecure/src/ssl_client.h for ESP32 77 | #include 78 | 79 | #include "tcp_mbedtls.h" 80 | 81 | extern "C" 82 | { 83 | #include "freertos/FreeRTOS.h" 84 | #include "freertos/semphr.h" 85 | #include "lwip/pbuf.h" 86 | } 87 | 88 | #include "AsyncTCP_SSL_Debug.h" 89 | 90 | /***************************************************** 91 | // Defined in tools/sdk/esp32s3/include/lwip/lwip/src/include/lwip/tcpbase.h 92 | enum tcp_state 93 | { 94 | CLOSED = 0, 95 | LISTEN = 1, 96 | SYN_SENT = 2, 97 | SYN_RCVD = 3, 98 | ESTABLISHED = 4, 99 | FIN_WAIT_1 = 5, 100 | FIN_WAIT_2 = 6, 101 | CLOSE_WAIT = 7, 102 | CLOSING = 8, 103 | LAST_ACK = 9, 104 | TIME_WAIT = 10 105 | }; 106 | *****************************************************/ 107 | 108 | #define INVALID_CLOSED_SLOT -1 109 | 110 | ////////////////////////////////////////////////////////////////////////////////////////// 111 | 112 | //If core is not defined, then we are running in Arduino or PIO 113 | #ifndef CONFIG_ASYNC_TCP_RUNNING_CORE 114 | #define CONFIG_ASYNC_TCP_RUNNING_CORE -1 //any available core 115 | #define CONFIG_ASYNC_TCP_USE_WDT 1 //if enabled, adds between 33us and 200us per event 116 | #endif 117 | 118 | ///////////////////////////////////////////////// 119 | 120 | // Make ASYNC_QUEUE_LENGTH adjustable in sketch. Default 512 121 | #ifndef ASYNC_QUEUE_LENGTH 122 | #define ASYNC_QUEUE_LENGTH 512 123 | #endif 124 | 125 | // Make ASYNC_TCP_PRIORITY user-adjustable in sketch. Default 10, can't be less than 4 126 | #if !defined(CONFIG_ASYNC_TCP_PRIORITY) 127 | #define CONFIG_ASYNC_TCP_PRIORITY (10) 128 | #elif (CONFIG_ASYNC_TCP_PRIORITY < 4) 129 | #undef CONFIG_ASYNC_TCP_PRIORITY 130 | #define CONFIG_ASYNC_TCP_PRIORITY (4) 131 | #warning Adjust CONFIG_ASYNC_TCP_PRIORITY to 4 132 | #endif 133 | 134 | ///////////////////////////////////////////////// 135 | 136 | #define ASYNC_MAX_ACK_TIME 5000 137 | #define ASYNC_WRITE_FLAG_COPY 0x01 //will allocate new buffer to hold the data while sending (else will hold reference to the data given) 138 | #define ASYNC_WRITE_FLAG_MORE 0x02 //will not send PSH flag, meaning that there should be more data to be sent before the application should react. 139 | #define SSL_HANDSHAKE_TIMEOUT 5000 // timeout to complete SSL handshake 140 | 141 | ////////////////////////////////////////////////////////////////////////////////////////////// 142 | 143 | class AsyncSSLClient; 144 | 145 | typedef std::function AcConnectHandlerSSL; 146 | typedef std::function AcAckHandlerSSL; 147 | typedef std::function AcErrorHandlerSSL; 148 | typedef std::function AcDataHandlerSSL; 149 | typedef std::function AcPacketHandlerSSL; 150 | typedef std::function AcTimeoutHandlerSSL; 151 | 152 | ///////////////////////////////////////////////// 153 | 154 | struct tcp_pcb; 155 | struct ip_addr; 156 | 157 | ////////////////////////////////////////////////////////////////////////////////////////////// 158 | 159 | class AsyncSSLClient 160 | { 161 | public: 162 | AsyncSSLClient(tcp_pcb* pcb = 0); 163 | virtual ~AsyncSSLClient(); 164 | 165 | AsyncSSLClient & operator=(const AsyncSSLClient &other); 166 | AsyncSSLClient & operator+=(const AsyncSSLClient &other); 167 | 168 | bool operator==(const AsyncSSLClient &other); 169 | 170 | bool operator!=(const AsyncSSLClient &other) 171 | { 172 | return !(*this == other); 173 | } 174 | 175 | bool connect(IPAddress ip, uint16_t port, bool secure = false); 176 | bool connect(const char* host, uint16_t port, bool secure = false); 177 | void setRootCa(const char* rootca, const size_t len); 178 | void setClientCert(const char* cli_cert, const size_t len); 179 | void setClientKey(const char* cli_key, const size_t len); 180 | void setPsk(const char* psk_ident, const char* psk); 181 | 182 | void close(bool now = false); 183 | void stop(); 184 | int8_t abort(); 185 | bool free(); 186 | 187 | bool canSend(); //ack is not pending 188 | size_t add(const char* data, size_t size, uint8_t apiflags = ASYNC_WRITE_FLAG_COPY); //add for sending 189 | bool send(); //send all data added with the method above 190 | 191 | virtual size_t space(); //space available in the TCP window 192 | //write equals add()+send() 193 | virtual size_t write(const char* data); 194 | virtual size_t write(const char* data, size_t size, uint8_t apiflags = ASYNC_WRITE_FLAG_COPY); //only when canSend() == true 195 | 196 | uint8_t state(); 197 | bool connecting(); 198 | bool connected(); 199 | bool disconnecting(); 200 | bool disconnected(); 201 | bool freeable(); //disconnected or disconnecting 202 | 203 | uint16_t getMss(); 204 | 205 | uint32_t getRxTimeout(); 206 | void setRxTimeout(uint32_t timeout); //no RX data timeout for the connection in seconds 207 | 208 | uint32_t getAckTimeout(); 209 | void setAckTimeout(uint32_t timeout); //no ACK timeout for the last sent packet in milliseconds 210 | 211 | void setNoDelay(bool nodelay); 212 | bool getNoDelay(); 213 | 214 | uint32_t getRemoteAddress(); 215 | uint16_t getRemotePort(); 216 | uint32_t getLocalAddress(); 217 | uint16_t getLocalPort(); 218 | 219 | //compatibility 220 | IPAddress remoteIP(); 221 | uint16_t remotePort(); 222 | IPAddress localIP(); 223 | uint16_t localPort(); 224 | 225 | void onConnect(AcConnectHandlerSSL cb, void* arg = 0); //on successful connect 226 | void onDisconnect(AcConnectHandlerSSL cb, void* arg = 0); //disconnected 227 | void onAck(AcAckHandlerSSL cb, void* arg = 0); //ack received 228 | void onError(AcErrorHandlerSSL cb, void* arg = 0); //unsuccessful connect or error 229 | void onData(AcDataHandlerSSL cb, void* arg = 0); //data received (called if onPacket is not used) 230 | void onPacket(AcPacketHandlerSSL cb, void* arg = 0); //data received 231 | void onTimeout(AcTimeoutHandlerSSL cb, void* arg = 0); //ack timeout 232 | void onPoll(AcConnectHandlerSSL cb, void* arg = 0); //every 125ms when connected 233 | 234 | void ackPacket(struct pbuf * pb);//ack pbuf from onPacket 235 | size_t ack(size_t len); //ack data that you have not acked using the method below 236 | 237 | void ackLater() 238 | { 239 | _ack_pcb = false; //will not ack the current packet. Call from onData 240 | } 241 | 242 | const char * errorToString(int8_t error); 243 | const char * stateToString(); 244 | 245 | //Do not use any of the functions below! 246 | static int8_t _s_poll(void *arg, struct tcp_pcb *tpcb); 247 | static int8_t _s_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *pb, int8_t err); 248 | static int8_t _s_fin(void *arg, struct tcp_pcb *tpcb, int8_t err); 249 | static int8_t _s_lwip_fin(void *arg, struct tcp_pcb *tpcb, int8_t err); 250 | static void _s_error(void *arg, int8_t err); 251 | static int8_t _s_sent(void *arg, struct tcp_pcb *tpcb, uint16_t len); 252 | static int8_t _s_connected(void* arg, void* tpcb, int8_t err); 253 | static void _s_dns_found(const char *name, struct ip_addr *ipaddr, void *arg); 254 | 255 | static void _s_data(void *arg, struct tcp_pcb *tcp, uint8_t * data, size_t len); 256 | static void _s_handshake(void *arg, struct tcp_pcb *tcp, struct tcp_ssl_pcb* ssl); 257 | static void _s_ssl_error(void *arg, struct tcp_pcb *tcp, int8_t err); 258 | 259 | int8_t _recv(tcp_pcb* pcb, pbuf* pb, int8_t err); 260 | 261 | tcp_pcb * pcb() 262 | { 263 | return _pcb; 264 | } 265 | 266 | //KH 267 | int8_t getClosed_Slot() 268 | { 269 | return _closed_slot; 270 | } 271 | ////// 272 | 273 | protected: 274 | tcp_pcb* _pcb; 275 | std::string _hostname; 276 | int8_t _closed_slot; 277 | 278 | AcConnectHandlerSSL _connect_cb; 279 | void* _connect_cb_arg; 280 | AcConnectHandlerSSL _discard_cb; 281 | void* _discard_cb_arg; 282 | AcAckHandlerSSL _sent_cb; 283 | void* _sent_cb_arg; 284 | AcErrorHandlerSSL _error_cb; 285 | void* _error_cb_arg; 286 | AcDataHandlerSSL _recv_cb; 287 | void* _recv_cb_arg; 288 | AcPacketHandlerSSL _pb_cb; 289 | void* _pb_cb_arg; 290 | AcTimeoutHandlerSSL _timeout_cb; 291 | void* _timeout_cb_arg; 292 | AcConnectHandlerSSL _poll_cb; 293 | void* _poll_cb_arg; 294 | 295 | bool _pcb_busy; 296 | uint32_t _pcb_sent_at; 297 | bool _ack_pcb; 298 | uint32_t _rx_ack_len; 299 | uint32_t _rx_last_packet; 300 | uint32_t _rx_since_timeout; 301 | uint32_t _ack_timeout; 302 | uint16_t _connect_port; 303 | 304 | ////// SSL 305 | size_t _root_ca_len; 306 | char* _root_ca; 307 | size_t _cli_cert_len; 308 | char* _cli_cert; 309 | size_t _cli_key_len; 310 | char* _cli_key; 311 | bool _pcb_secure; 312 | bool _handshake_done; 313 | 314 | const char* _psk_ident; 315 | const char* _psk; 316 | ////// 317 | 318 | int8_t _close(); 319 | void _free_closed_slot(); 320 | void _allocate_closed_slot(); 321 | int8_t _connected(void* pcb, int8_t err); 322 | void _error(int8_t err); 323 | int8_t _poll(tcp_pcb* pcb); 324 | int8_t _sent(tcp_pcb* pcb, uint16_t len); 325 | int8_t _fin(tcp_pcb* pcb, int8_t err); 326 | int8_t _lwip_fin(tcp_pcb* pcb, int8_t err); 327 | void _dns_found(struct ip_addr *ipaddr); 328 | 329 | ////// SSL 330 | void _ssl_error(int8_t err); 331 | ////// 332 | 333 | public: 334 | AsyncSSLClient* prev; 335 | AsyncSSLClient* next; 336 | }; 337 | 338 | typedef std::function AcSSlFileHandlerSSL; 339 | 340 | ////////////////////////////////////////////////////////////////////////////////////////////// 341 | 342 | class AsyncSSLServer 343 | { 344 | public: 345 | AsyncSSLServer(IPAddress addr, uint16_t port); 346 | AsyncSSLServer(uint16_t port); 347 | ~AsyncSSLServer(); 348 | 349 | void onClient(AcConnectHandlerSSL cb, void* arg); 350 | 351 | // Dummy, so it compiles with ESP Async WebServer library enabled. 352 | void onSslFileRequest(AcSSlFileHandlerSSL cb, void* arg) {}; 353 | void beginSecure(const char *cert, const char *private_key_file, const char *password) {}; 354 | 355 | void begin(); 356 | void end(); 357 | void setNoDelay(bool nodelay); 358 | bool getNoDelay(); 359 | uint8_t status(); 360 | 361 | //Do not use any of the functions below! 362 | static int8_t _s_accept(void *arg, tcp_pcb* newpcb, int8_t err); 363 | static int8_t _s_accepted(void *arg, AsyncSSLClient* client); 364 | 365 | protected: 366 | uint16_t _port; 367 | IPAddress _addr; 368 | bool _noDelay; 369 | 370 | tcp_pcb* _pcb; 371 | 372 | AcConnectHandlerSSL _connect_cb; 373 | void* _connect_cb_arg; 374 | 375 | int8_t _accept(tcp_pcb* newpcb, int8_t err); 376 | int8_t _accepted(AsyncSSLClient* client); 377 | }; 378 | 379 | ////////////////////////////////////////////////////////////////////////////////////////////// 380 | 381 | #endif /* ASYNCTCP_SSL_HPP */ 382 | -------------------------------------------------------------------------------- /src/tcp_mbedtls.c: -------------------------------------------------------------------------------- 1 | /**************************************************************************************************************************** 2 | tcp_mbedtls.c 3 | 4 | AsyncTCP_SSL is a library for ESP32 5 | 6 | Based on and modified from : 7 | 8 | 1) AsyncTCP (https://github.com/me-no-dev/ESPAsyncTCP) 9 | 2) AsyncTCP (https://github.com/tve/AsyncTCP) 10 | 11 | Built by Khoi Hoang https://github.com/khoih-prog/AsyncTCP_SSL 12 | 13 | This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License 14 | as published bythe Free Software Foundation, either version 3 of the License, or (at your option) any later version. 15 | This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 17 | 18 | Version: 1.3.1 19 | 20 | Version Modified By Date Comments 21 | ------- ----------- ---------- ----------- 22 | 1.0.0 K Hoang 21/10/2021 Initial coding to support only ESP32 23 | 1.1.0 K Hoang 22/10/2021 Fix bug. Enable coexistence with AsyncTCP 24 | 1.2.0 K Hoang 23/01/2022 Fix `multiple-definitions` linker error 25 | 1.3.0 K Hoang 04/09/2022 Clean up. Remove hard-code if possible 26 | 1.3.1 K Hoang 18/09/2022 Improve stability. Make queue length user-configurable 27 | *****************************************************************************************************************************/ 28 | 29 | #ifndef _ASYNC_TCP_SSL_LOGLEVEL_ 30 | #define _ASYNC_TCP_SSL_LOGLEVEL_ 1 31 | #endif 32 | 33 | #include "tcp_mbedtls.h" 34 | #include "lwip/tcp.h" 35 | #include "mbedtls/debug.h" 36 | #include "mbedtls/esp_debug.h" 37 | #include 38 | 39 | // stubs to call LwIP's tcp functions on the LwIP thread itself, implemented in AsyncTCP.cpp 40 | extern esp_err_t _tcp_output4ssl(struct tcp_pcb * pcb, void* client); 41 | extern esp_err_t _tcp_write4ssl(struct tcp_pcb * pcb, const char* data, size_t size, uint8_t apiflags, void* client); 42 | 43 | #define TCP_SSL_DEBUG(...) 44 | 45 | static const char pers[] = "esp32-tls"; 46 | 47 | static int handle_error(int err) 48 | { 49 | if (err == -30848) 50 | { 51 | return err; 52 | } 53 | 54 | #ifdef MBEDTLS_ERROR_C 55 | char error_buf[100]; 56 | mbedtls_strerror(err, error_buf, 100); 57 | #endif 58 | 59 | return err; 60 | } 61 | 62 | /** 63 | Certificate verification callback for mbed TLS 64 | Here we only use it to display information on each cert in the chain 65 | */ 66 | // static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags) { 67 | // const uint32_t buf_size = 1024; 68 | // char buf[buf_size]; 69 | // (void) data; 70 | 71 | // mbedtls_printf("\nVerifying certificate at depth %d:\n", depth); 72 | // mbedtls_x509_crt_info(buf, buf_size - 1, " ", crt); 73 | // mbedtls_printf("%s", buf); 74 | 75 | // if (*flags == 0) 76 | // mbedtls_printf("No verification issue for this certificate\n"); 77 | // else 78 | // { 79 | // mbedtls_x509_crt_verify_info(buf, buf_size, " ! ", *flags); 80 | // mbedtls_printf("%s\n", buf); 81 | // } 82 | 83 | // return 0; 84 | // } 85 | 86 | static uint8_t _tcp_ssl_has_client = 0; 87 | 88 | struct tcp_ssl_pcb 89 | { 90 | struct tcp_pcb *tcp; 91 | int fd; 92 | mbedtls_ssl_context ssl_ctx; 93 | mbedtls_ssl_config ssl_conf; 94 | mbedtls_x509_crt ca_cert; 95 | bool has_ca_cert; 96 | mbedtls_x509_crt client_cert; 97 | bool has_client_cert; 98 | mbedtls_pk_context client_key; 99 | mbedtls_ctr_drbg_context drbg_ctx; 100 | mbedtls_entropy_context entropy_ctx; 101 | uint8_t type; 102 | void *arg; 103 | tcp_ssl_data_cb_t on_data; 104 | tcp_ssl_handshake_cb_t on_handshake; 105 | tcp_ssl_error_cb_t on_error; 106 | size_t last_wr; 107 | struct pbuf *tcp_pbuf; 108 | int pbuf_offset; 109 | struct tcp_ssl_pcb *next; 110 | }; 111 | 112 | typedef struct tcp_ssl_pcb tcp_ssl_t; 113 | 114 | static tcp_ssl_t * tcp_ssl_array = NULL; 115 | static int tcp_ssl_next_fd = 0; 116 | 117 | ///////////////////////////////////////////// 118 | 119 | // tcp_ssl_recv attempts to read up to len bytes into buf from data already received. 120 | // It is called by mbedtls. 121 | int tcp_ssl_recv(void *ctx, unsigned char *buf, size_t len) 122 | { 123 | tcp_ssl_t *tcp_ssl = (tcp_ssl_t*)ctx; 124 | u16_t recv_len = 0; 125 | 126 | if (tcp_ssl->tcp_pbuf == NULL || tcp_ssl->tcp_pbuf->tot_len == 0) 127 | { 128 | //TCP_SSL_DEBUG("tcp_ssl_recv: not yet ready to read: tcp_pbuf: 0x%X.\n", tcp_ssl->tcp_pbuf); 129 | 130 | return MBEDTLS_ERR_SSL_WANT_READ; 131 | } 132 | 133 | recv_len = pbuf_copy_partial(tcp_ssl->tcp_pbuf, buf, len, tcp_ssl->pbuf_offset); 134 | 135 | tcp_ssl->pbuf_offset += recv_len; 136 | 137 | if (recv_len == 0) 138 | { 139 | return MBEDTLS_ERR_SSL_WANT_READ; 140 | } 141 | 142 | return recv_len; 143 | } 144 | 145 | ///////////////////////////////////////////// 146 | 147 | // tcp_ssl_send attempts to send len bytes from buf. 148 | // It is called by mbedtls. 149 | int tcp_ssl_send(void *ctx, const unsigned char *buf, size_t len) 150 | { 151 | //TCP_SSL_DEBUG("tcp_ssl_send: ctx: 0x%X, buf: 0x%X, len: %d\n", ctx, buf, len); 152 | 153 | if (ctx == NULL) 154 | { 155 | //TCP_SSL_DEBUG("tcp_ssl_send: no context set\n"); 156 | 157 | return -1; 158 | } 159 | 160 | if (buf == NULL) 161 | { 162 | //TCP_SSL_DEBUG("tcp_ssl_send: buf not set\n"); 163 | 164 | return -1; 165 | } 166 | 167 | tcp_ssl_t *tcp_ssl = (tcp_ssl_t*)ctx; 168 | size_t tcp_len = 0; 169 | int err = ERR_OK; 170 | 171 | if (tcp_sndbuf(tcp_ssl->tcp) < len) 172 | { 173 | tcp_len = tcp_sndbuf(tcp_ssl->tcp); 174 | 175 | if (tcp_len == 0) 176 | { 177 | //TCP_SSL_DEBUG("tcp_ssl_send: tcp_sndbuf is zero: %d\n", len); 178 | 179 | return ERR_MEM; 180 | } 181 | } 182 | else 183 | { 184 | tcp_len = len; 185 | } 186 | 187 | if (tcp_len > 2 * tcp_ssl->tcp->mss) 188 | { 189 | tcp_len = 2 * tcp_ssl->tcp->mss; 190 | } 191 | 192 | //TCP_SSL_DEBUG("tcp_ssl_send: tcp_write(%x, %x, %d, %x)\n", tcp_ssl->tcp, (char *)buf, tcp_len, tcp_ssl->arg); 193 | 194 | err = _tcp_write4ssl(tcp_ssl->tcp, (char *)buf, tcp_len, TCP_WRITE_FLAG_COPY, tcp_ssl->arg); 195 | 196 | if (err < ERR_OK) 197 | { 198 | if (err == ERR_MEM) 199 | { 200 | //TCP_SSL_DEBUG("tcp_ssl_send: No memory %d (%d)\n", tcp_len, len); 201 | 202 | return err; 203 | } 204 | 205 | //TCP_SSL_DEBUG("tcp_ssl_send: tcp_write error: %d\n", err); 206 | 207 | return err; 208 | } 209 | else if (err == ERR_OK) 210 | { 211 | //TCP_SSL_DEBUG("tcp_ssl_send: tcp_output: %d / %d\n", tcp_len, len); 212 | 213 | err = _tcp_output4ssl(tcp_ssl->tcp, tcp_ssl->arg); 214 | 215 | if (err != ERR_OK) 216 | { 217 | //TCP_SSL_DEBUG("tcp_ssl_send: tcp_output err: %d\n", err); 218 | 219 | return err; 220 | } 221 | } 222 | 223 | tcp_ssl->last_wr += tcp_len; 224 | 225 | return tcp_len; 226 | } 227 | 228 | ///////////////////////////////////////////// 229 | 230 | uint8_t tcp_ssl_has_client() 231 | { 232 | return _tcp_ssl_has_client; 233 | } 234 | 235 | ///////////////////////////////////////////// 236 | 237 | tcp_ssl_t * tcp_ssl_new(struct tcp_pcb *tcp, void* arg) 238 | { 239 | 240 | if (tcp_ssl_next_fd < 0) 241 | { 242 | tcp_ssl_next_fd = 0; //overflow 243 | } 244 | 245 | tcp_ssl_t * new_item = (tcp_ssl_t*)malloc(sizeof(tcp_ssl_t)); 246 | 247 | if (!new_item) 248 | { 249 | //TCP_SSL_DEBUG("tcp_ssl_new: failed to allocate tcp_ssl\n"); 250 | 251 | return NULL; 252 | } 253 | 254 | new_item->tcp = tcp; 255 | new_item->arg = arg; 256 | new_item->on_data = NULL; 257 | new_item->on_handshake = NULL; 258 | new_item->on_error = NULL; 259 | new_item->tcp_pbuf = NULL; 260 | new_item->pbuf_offset = 0; 261 | new_item->next = NULL; 262 | new_item->has_ca_cert = false; 263 | new_item->has_client_cert = false; 264 | 265 | if (tcp_ssl_array == NULL) 266 | { 267 | tcp_ssl_array = new_item; 268 | } 269 | else 270 | { 271 | tcp_ssl_t * item = tcp_ssl_array; 272 | 273 | while (item->next != NULL) 274 | item = item->next; 275 | 276 | item->next = new_item; 277 | } 278 | 279 | return new_item; 280 | } 281 | 282 | ///////////////////////////////////////////// 283 | 284 | tcp_ssl_t* tcp_ssl_get(struct tcp_pcb *tcp) 285 | { 286 | if (tcp == NULL) 287 | { 288 | return NULL; 289 | } 290 | 291 | tcp_ssl_t * item = tcp_ssl_array; 292 | 293 | while (item && item->tcp != tcp) 294 | { 295 | item = item->next; 296 | } 297 | 298 | return item; 299 | } 300 | 301 | ///////////////////////////////////////////// 302 | 303 | int tcp_ssl_new_client(struct tcp_pcb *tcp, void *arg, const char* hostname, const char* root_ca, 304 | const size_t root_ca_len, 305 | const char* cli_cert, const size_t cli_cert_len, const char* cli_key, const size_t cli_key_len) 306 | { 307 | tcp_ssl_t* tcp_ssl; 308 | 309 | if (tcp == NULL) 310 | { 311 | return -1; 312 | } 313 | 314 | if (tcp_ssl_get(tcp) != NULL) 315 | { 316 | return -1; 317 | } 318 | 319 | tcp_ssl = tcp_ssl_new(tcp, arg); 320 | 321 | if (tcp_ssl == NULL) 322 | { 323 | return -1; 324 | } 325 | 326 | mbedtls_entropy_init(&tcp_ssl->entropy_ctx); 327 | mbedtls_ctr_drbg_init(&tcp_ssl->drbg_ctx); 328 | mbedtls_ssl_init(&tcp_ssl->ssl_ctx); 329 | mbedtls_ssl_config_init(&tcp_ssl->ssl_conf); 330 | 331 | if (root_ca != NULL) 332 | { 333 | mbedtls_x509_crt_init(&tcp_ssl->ca_cert); 334 | tcp_ssl->has_ca_cert = true; 335 | } 336 | 337 | if (cli_cert != NULL && cli_key != NULL) 338 | { 339 | mbedtls_x509_crt_init(&tcp_ssl->client_cert); 340 | mbedtls_pk_init(&tcp_ssl->client_key); 341 | tcp_ssl->has_client_cert = true; 342 | } 343 | 344 | mbedtls_ctr_drbg_seed(&tcp_ssl->drbg_ctx, mbedtls_entropy_func, 345 | &tcp_ssl->entropy_ctx, (const unsigned char*)pers, sizeof(pers)); 346 | 347 | if (mbedtls_ssl_config_defaults(&tcp_ssl->ssl_conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, 348 | MBEDTLS_SSL_PRESET_DEFAULT)) 349 | { 350 | //TCP_SSL_DEBUG("error setting SSL config.\n"); 351 | 352 | tcp_ssl_free(tcp); 353 | 354 | return -1; 355 | } 356 | 357 | int ret = 0; 358 | 359 | if (tcp_ssl->has_ca_cert) 360 | { 361 | //TCP_SSL_DEBUG("setting the root ca.\n"); 362 | 363 | mbedtls_x509_crt_init(&tcp_ssl->ca_cert); 364 | 365 | mbedtls_ssl_conf_authmode(&tcp_ssl->ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED); 366 | 367 | ret = mbedtls_x509_crt_parse(&tcp_ssl->ca_cert, (const unsigned char *)root_ca, root_ca_len); 368 | 369 | if ( ret < 0 ) 370 | { 371 | //TCP_SSL_DEBUG(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret); 372 | 373 | tcp_ssl_free(tcp); 374 | 375 | return handle_error(ret); 376 | } 377 | 378 | mbedtls_ssl_conf_ca_chain(&tcp_ssl->ssl_conf, &tcp_ssl->ca_cert, NULL); 379 | } 380 | else 381 | { 382 | mbedtls_ssl_conf_authmode(&tcp_ssl->ssl_conf, MBEDTLS_SSL_VERIFY_OPTIONAL); 383 | } 384 | 385 | if (tcp_ssl->has_client_cert) 386 | { 387 | //TCP_SSL_DEBUG("loading client cert"); 388 | 389 | ret = mbedtls_x509_crt_parse(&tcp_ssl->client_cert, (const unsigned char *) cli_cert, cli_cert_len); 390 | 391 | if (ret < 0) 392 | { 393 | tcp_ssl_free(tcp); 394 | 395 | return handle_error(ret); 396 | } 397 | 398 | //TCP_SSL_DEBUG("loading private key"); 399 | 400 | ret = mbedtls_pk_parse_key(&tcp_ssl->client_key, (const unsigned char *) cli_key, cli_key_len, NULL, 0); 401 | 402 | if (ret != 0) 403 | { 404 | tcp_ssl_free(tcp); 405 | 406 | return handle_error(ret); 407 | } 408 | 409 | mbedtls_ssl_conf_own_cert(&tcp_ssl->ssl_conf, &tcp_ssl->client_cert, &tcp_ssl->client_key); 410 | } 411 | 412 | if (hostname != NULL) 413 | { 414 | //TCP_SSL_DEBUG("setting the hostname: %s\n", hostname); 415 | 416 | if ((ret = mbedtls_ssl_set_hostname(&tcp_ssl->ssl_ctx, hostname)) != 0) 417 | { 418 | tcp_ssl_free(tcp); 419 | 420 | return handle_error(ret); 421 | } 422 | } 423 | 424 | mbedtls_ssl_conf_rng(&tcp_ssl->ssl_conf, mbedtls_ctr_drbg_random, &tcp_ssl->drbg_ctx); 425 | 426 | if ((ret = mbedtls_ssl_setup(&tcp_ssl->ssl_ctx, &tcp_ssl->ssl_conf)) != 0) 427 | { 428 | tcp_ssl_free(tcp); 429 | 430 | return handle_error(ret); 431 | } 432 | 433 | mbedtls_ssl_set_bio(&tcp_ssl->ssl_ctx, (void*)tcp_ssl, tcp_ssl_send, tcp_ssl_recv, NULL); 434 | 435 | // Start handshake. 436 | ret = mbedtls_ssl_handshake(&tcp_ssl->ssl_ctx); 437 | 438 | if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) 439 | { 440 | //TCP_SSL_DEBUG("handshake error!\n"); 441 | 442 | tcp_ssl_free(tcp); 443 | 444 | return handle_error(ret); 445 | } 446 | 447 | return ERR_OK; 448 | } 449 | 450 | ///////////////////////////////////////////// 451 | 452 | // Open an SSL connection using a PSK (pre-shared-key) cipher suite. 453 | int tcp_ssl_new_psk_client(struct tcp_pcb *tcp, void *arg, const char* psk_ident, const char* pskey) 454 | { 455 | tcp_ssl_t* tcp_ssl; 456 | 457 | if (pskey == NULL || psk_ident == NULL) 458 | { 459 | //TCP_SSL_DEBUG(" failed\n ! pre-shared key or identity is NULL\n\n"); 460 | 461 | return -1; 462 | } 463 | 464 | if (tcp == NULL) 465 | return -1; 466 | 467 | if (tcp_ssl_get(tcp) != NULL) 468 | return -1; 469 | 470 | int pskey_len = strnlen(pskey, 2 * MBEDTLS_PSK_MAX_LEN + 1); 471 | 472 | if ((pskey_len > 2 * MBEDTLS_PSK_MAX_LEN) || (pskey_len & 1) != 0) 473 | { 474 | //TCP_SSL_DEBUG(" failed\n ! pre-shared key not valid hex or too long\n\n"); 475 | 476 | return -1; 477 | } 478 | 479 | tcp_ssl = tcp_ssl_new(tcp, arg); 480 | 481 | if (tcp_ssl == NULL) 482 | return -1; 483 | 484 | mbedtls_entropy_init(&tcp_ssl->entropy_ctx); 485 | mbedtls_ctr_drbg_init(&tcp_ssl->drbg_ctx); 486 | mbedtls_ssl_init(&tcp_ssl->ssl_ctx); 487 | mbedtls_ssl_config_init(&tcp_ssl->ssl_conf); 488 | 489 | mbedtls_ctr_drbg_seed(&tcp_ssl->drbg_ctx, mbedtls_entropy_func, 490 | &tcp_ssl->entropy_ctx, (const uint8_t*)pers, sizeof(pers)); 491 | 492 | if (mbedtls_ssl_config_defaults(&tcp_ssl->ssl_conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, 493 | MBEDTLS_SSL_PRESET_DEFAULT)) 494 | { 495 | //TCP_SSL_DEBUG("error setting SSL config.\n"); 496 | 497 | tcp_ssl_free(tcp); 498 | 499 | return -1; 500 | } 501 | 502 | //mbedtls_esp_enable_debug_log(&tcp_ssl->ssl_conf, 4); // 4=verbose 503 | 504 | int ret = 0; 505 | 506 | //TCP_SSL_DEBUG("setting the pre-shared key.\n"); 507 | // convert PSK from hex string to binary 508 | 509 | ////// 510 | //if ((strlen(pskey) & 1) != 0 || strlen(pskey) > 2*MBEDTLS_PSK_MAX_LEN) { 511 | // //TCP_SSL_DEBUG(" failed\n ! pre-shared key not valid hex or too long\n\n"); 512 | // return -1; 513 | //} 514 | ////// 515 | 516 | unsigned char psk[MBEDTLS_PSK_MAX_LEN]; 517 | size_t psk_len = strlen(pskey) / 2; 518 | 519 | for (int j = 0; j < strlen(pskey); j += 2) 520 | { 521 | char c = pskey[j]; 522 | 523 | if (c >= '0' && c <= '9') 524 | c -= '0'; 525 | else if (c >= 'A' && c <= 'F') 526 | c -= 'A' - 10; 527 | else if (c >= 'a' && c <= 'f') 528 | c -= 'a' - 10; 529 | else 530 | return -1; 531 | 532 | psk[j / 2] = c << 4; 533 | c = pskey[j + 1]; 534 | 535 | if (c >= '0' && c <= '9') 536 | c -= '0'; 537 | else if (c >= 'A' && c <= 'F') 538 | c -= 'A' - 10; 539 | else if (c >= 'a' && c <= 'f') 540 | c -= 'a' - 10; 541 | else 542 | return -1; 543 | 544 | psk[j / 2] |= c; 545 | } 546 | 547 | // set mbedtls config 548 | ret = mbedtls_ssl_conf_psk(&tcp_ssl->ssl_conf, psk, psk_len, (const unsigned char *)psk_ident, 549 | strnlen(psk_ident, 64)); 550 | 551 | if (ret != 0) 552 | { 553 | //TCP_SSL_DEBUG(" failed\n ! mbedtls_ssl_conf_psk returned -0x%x\n\n", -ret); 554 | 555 | return handle_error(ret); 556 | } 557 | 558 | mbedtls_ssl_conf_rng(&tcp_ssl->ssl_conf, mbedtls_ctr_drbg_random, &tcp_ssl->drbg_ctx); 559 | 560 | if ((ret = mbedtls_ssl_setup(&tcp_ssl->ssl_ctx, &tcp_ssl->ssl_conf)) != 0) 561 | { 562 | tcp_ssl_free(tcp); 563 | 564 | return handle_error(ret); 565 | } 566 | 567 | mbedtls_ssl_set_bio(&tcp_ssl->ssl_ctx, (void*)tcp_ssl, tcp_ssl_send, tcp_ssl_recv, NULL); 568 | 569 | // Start handshake. 570 | ret = mbedtls_ssl_handshake(&tcp_ssl->ssl_ctx); 571 | 572 | if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) 573 | { 574 | //TCP_SSL_DEBUG("handshake error!\n"); 575 | 576 | return handle_error(ret); 577 | } 578 | 579 | return ERR_OK; 580 | } 581 | 582 | ///////////////////////////////////////////// 583 | 584 | // tcp_ssl_write writes len bytes from data into the TLS connection. I.e., data is plaintext, gets 585 | // encrypted, and then transmitted on the TCP connection. 586 | int tcp_ssl_write(struct tcp_pcb *tcp, uint8_t *data, size_t len) 587 | { 588 | //TCP_SSL_DEBUG("tcp_ssl_write(%x, %x, len=%d)\n", tcp, data, len); 589 | 590 | if (tcp == NULL) 591 | { 592 | return -1; 593 | } 594 | 595 | tcp_ssl_t * tcp_ssl = tcp_ssl_get(tcp); 596 | 597 | if (tcp_ssl == NULL) 598 | { 599 | return 0; 600 | } 601 | 602 | tcp_ssl->last_wr = 0; 603 | 604 | int rc = mbedtls_ssl_write(&tcp_ssl->ssl_ctx, data, len); 605 | 606 | if (rc < 0) 607 | { 608 | if (rc != MBEDTLS_ERR_SSL_WANT_READ && rc != MBEDTLS_ERR_SSL_WANT_WRITE) 609 | { 610 | //TCP_SSL_DEBUG("about to call mbedtls_ssl_write\n"); 611 | 612 | return handle_error(rc); 613 | } 614 | 615 | if (rc != MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) 616 | { 617 | //TCP_SSL_DEBUG("tcp_ssl_write error: %d\r\n", rc); 618 | } 619 | 620 | return rc; 621 | } 622 | 623 | return tcp_ssl->last_wr; 624 | } 625 | 626 | ///////////////////////////////////////////// 627 | 628 | /* 629 | typedef enum 630 | { 631 | MBEDTLS_SSL_HELLO_REQUEST, 632 | MBEDTLS_SSL_CLIENT_HELLO, 633 | MBEDTLS_SSL_SERVER_HELLO, 634 | MBEDTLS_SSL_SERVER_CERTIFICATE, 635 | MBEDTLS_SSL_SERVER_KEY_EXCHANGE, 636 | MBEDTLS_SSL_CERTIFICATE_REQUEST, 637 | MBEDTLS_SSL_SERVER_HELLO_DONE, 638 | MBEDTLS_SSL_CLIENT_CERTIFICATE, 639 | MBEDTLS_SSL_CLIENT_KEY_EXCHANGE, 640 | MBEDTLS_SSL_CERTIFICATE_VERIFY, 641 | MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC, 642 | MBEDTLS_SSL_CLIENT_FINISHED, 643 | MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC, 644 | MBEDTLS_SSL_SERVER_FINISHED, 645 | MBEDTLS_SSL_FLUSH_BUFFERS, 646 | MBEDTLS_SSL_HANDSHAKE_WRAPUP, 647 | MBEDTLS_SSL_HANDSHAKE_OVER, 648 | MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET, 649 | MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT, 650 | } 651 | mbedtls_ssl_states; 652 | */ 653 | 654 | ///////////////////////////////////////////// 655 | 656 | // tcp_ssl_read is a callback that reads from the TLS connection, i.e., it calls mbedtls, which then 657 | // tries to read from the TCP connection and decrypts it, tcp_ssl_read then calls the application's 658 | // onData callback with the decrypted data. 659 | int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) 660 | { 661 | //TCP_SSL_DEBUG("tcp_ssl_read(%x, %x)\n", tcp, p); 662 | 663 | if (tcp == NULL) 664 | { 665 | return -1; 666 | } 667 | 668 | int read_bytes = 0; 669 | int total_bytes = 0; 670 | 671 | static const size_t read_buf_size = 1024; 672 | 673 | uint8_t read_buf[read_buf_size]; 674 | 675 | tcp_ssl_t *tcp_ssl = tcp_ssl_get(tcp); 676 | 677 | if (tcp_ssl == NULL) 678 | { 679 | return ERR_TCP_SSL_INVALID_CLIENTFD_DATA; 680 | } 681 | 682 | if (p == NULL) 683 | { 684 | return ERR_TCP_SSL_INVALID_DATA; 685 | } 686 | 687 | // TCP_SSL_DEBUG("READY TO READ SOME DATA\n"); 688 | 689 | tcp_ssl->tcp_pbuf = p; 690 | tcp_ssl->pbuf_offset = 0; 691 | 692 | bool debugPrinted = false; 693 | 694 | do 695 | { 696 | if (tcp_ssl->ssl_ctx.state != MBEDTLS_SSL_HANDSHAKE_OVER) 697 | { 698 | //KH to print once 699 | if (!debugPrinted) 700 | { 701 | //TCP_SSL_DEBUG("start handshake: %d\n", tcp_ssl->ssl_ctx.state); 702 | 703 | debugPrinted = true; 704 | } 705 | 706 | int ret = mbedtls_ssl_handshake(&tcp_ssl->ssl_ctx); 707 | //handle_error(ret); 708 | 709 | if (ret == 0) 710 | { 711 | //TCP_SSL_DEBUG("Protocol is %s, Ciphersuite is %s\n", mbedtls_ssl_get_version(&tcp_ssl->ssl_ctx), mbedtls_ssl_get_ciphersuite(&tcp_ssl->ssl_ctx)); 712 | 713 | ////// 714 | //TCP_SSL_DEBUG("Verifying peer X.509 certificate..."); 715 | 716 | if ((mbedtls_ssl_get_verify_result(&tcp_ssl->ssl_ctx)) != 0) 717 | { 718 | //TCP_SSL_DEBUG("handshake error: %d\n", ret); 719 | 720 | handle_error(ret); 721 | 722 | if (tcp_ssl->on_error) 723 | tcp_ssl->on_error(tcp_ssl->arg, tcp_ssl->tcp, ret); 724 | } 725 | else 726 | { 727 | //TCP_SSL_DEBUG("Certificate verified."); 728 | } 729 | 730 | ////// 731 | 732 | if (tcp_ssl->on_handshake) 733 | tcp_ssl->on_handshake(tcp_ssl->arg, tcp_ssl->tcp, tcp_ssl); 734 | } 735 | else if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) 736 | { 737 | //TCP_SSL_DEBUG("handshake error: %d\n", ret); 738 | 739 | handle_error(ret); 740 | 741 | if (tcp_ssl->on_error) 742 | tcp_ssl->on_error(tcp_ssl->arg, tcp_ssl->tcp, ret); 743 | 744 | break; 745 | } 746 | } 747 | else 748 | { 749 | read_bytes = mbedtls_ssl_read(&tcp_ssl->ssl_ctx, (unsigned char *)&read_buf, read_buf_size); 750 | //TCP_SSL_DEBUG("tcp_ssl_read: read_bytes: %d, total_bytes: %d, tot_len: %d, pbuf_offset: %d\r\n", 751 | // read_bytes, total_bytes, p->tot_len, tcp_ssl->pbuf_offset); 752 | 753 | if (read_bytes < 0) 754 | { 755 | // SSL_OK 756 | if (read_bytes == MBEDTLS_ERR_SSL_WANT_READ) 757 | { 758 | break; 759 | } 760 | else if (read_bytes != MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) 761 | { 762 | //TCP_SSL_DEBUG("tcp_ssl_read: read error: %d\n", read_bytes); 763 | } 764 | 765 | total_bytes = read_bytes; 766 | 767 | break; 768 | } 769 | else if (read_bytes > 0) 770 | { 771 | if (tcp_ssl->on_data) 772 | { 773 | tcp_ssl->on_data(tcp_ssl->arg, tcp, read_buf, read_bytes); 774 | } 775 | 776 | total_bytes += read_bytes; 777 | } 778 | } 779 | 780 | //KH 781 | vTaskDelay(1 / portTICK_PERIOD_MS); 782 | ////// 783 | 784 | } while (p->tot_len - tcp_ssl->pbuf_offset > 0 || read_bytes > 0); 785 | 786 | tcp_ssl->tcp_pbuf = NULL; 787 | 788 | return (total_bytes >= 0 ? 0 : total_bytes); // return error code 789 | } 790 | 791 | ///////////////////////////////////////////// 792 | 793 | int tcp_ssl_free(struct tcp_pcb *tcp) 794 | { 795 | //TCP_SSL_DEBUG("tcp_ssl_free(%x)\n", tcp); 796 | 797 | if (tcp == NULL) 798 | { 799 | return -1; 800 | } 801 | 802 | tcp_ssl_t * item = tcp_ssl_array; 803 | 804 | if (item->tcp == tcp) 805 | { 806 | tcp_ssl_array = tcp_ssl_array->next; 807 | 808 | if (item->tcp_pbuf != NULL) 809 | { 810 | pbuf_free(item->tcp_pbuf); 811 | } 812 | 813 | mbedtls_ssl_free(&item->ssl_ctx); 814 | mbedtls_ssl_config_free(&item->ssl_conf); 815 | mbedtls_ctr_drbg_free(&item->drbg_ctx); 816 | mbedtls_entropy_free(&item->entropy_ctx); 817 | 818 | if (item->has_ca_cert) 819 | { 820 | mbedtls_x509_crt_free(&item->ca_cert); 821 | } 822 | 823 | if (item->has_client_cert) 824 | { 825 | mbedtls_x509_crt_free(&item->client_cert); 826 | mbedtls_pk_free(&item->client_key); 827 | } 828 | 829 | free(item); 830 | 831 | return 0; 832 | } 833 | 834 | while (item->next && item->next->tcp != tcp) 835 | item = item->next; 836 | 837 | if (item->next == NULL) 838 | { 839 | return ERR_TCP_SSL_INVALID_CLIENTFD_DATA;//item not found 840 | } 841 | 842 | tcp_ssl_t * i = item->next; 843 | item->next = i->next; 844 | 845 | if (i->tcp_pbuf != NULL) 846 | { 847 | pbuf_free(i->tcp_pbuf); 848 | } 849 | 850 | mbedtls_ssl_free(&i->ssl_ctx); 851 | mbedtls_ssl_config_free(&i->ssl_conf); 852 | mbedtls_ctr_drbg_free(&i->drbg_ctx); 853 | mbedtls_entropy_free(&i->entropy_ctx); 854 | free(i); 855 | 856 | return 0; 857 | } 858 | 859 | ///////////////////////////////////////////// 860 | 861 | bool tcp_ssl_has(struct tcp_pcb *tcp) 862 | { 863 | return tcp_ssl_get(tcp) != NULL; 864 | } 865 | 866 | ///////////////////////////////////////////// 867 | 868 | void tcp_ssl_arg(struct tcp_pcb *tcp, void * arg) 869 | { 870 | tcp_ssl_t * item = tcp_ssl_get(tcp); 871 | 872 | if (item) 873 | { 874 | item->arg = arg; 875 | } 876 | } 877 | 878 | ///////////////////////////////////////////// 879 | 880 | void tcp_ssl_data(struct tcp_pcb *tcp, tcp_ssl_data_cb_t arg) 881 | { 882 | tcp_ssl_t * item = tcp_ssl_get(tcp); 883 | 884 | if (item) 885 | { 886 | item->on_data = arg; 887 | } 888 | } 889 | 890 | ///////////////////////////////////////////// 891 | 892 | void tcp_ssl_handshake(struct tcp_pcb *tcp, tcp_ssl_handshake_cb_t arg) 893 | { 894 | tcp_ssl_t * item = tcp_ssl_get(tcp); 895 | 896 | if (item) 897 | { 898 | item->on_handshake = arg; 899 | } 900 | } 901 | 902 | ///////////////////////////////////////////// 903 | 904 | void tcp_ssl_err(struct tcp_pcb *tcp, tcp_ssl_error_cb_t arg) 905 | { 906 | tcp_ssl_t * item = tcp_ssl_get(tcp); 907 | 908 | if (item) 909 | { 910 | item->on_error = arg; 911 | } 912 | } 913 | 914 | ///////////////////////////////////////////// 915 | 916 | //#endif // ASYNC_TCP_SSL_ENABLED 917 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AsyncTCP_SSL Library 2 | 3 | [![arduino-library-badge](https://www.ardu-badge.com/badge/AsyncTCP_SSL.svg?)](https://www.ardu-badge.com/AsyncTCP_SSL) 4 | [![GitHub release](https://img.shields.io/github/release/khoih-prog/AsyncTCP_SSL.svg)](https://github.com/khoih-prog/AsyncTCP_SSL/releases) 5 | [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](#Contributing) 6 | [![GitHub issues](https://img.shields.io/github/issues/khoih-prog/AsyncTCP_SSL.svg)](http://github.com/khoih-prog/AsyncTCP_SSL/issues) 7 | 8 | 9 | Donate to my libraries using BuyMeACoffee 10 | 11 | 12 | --- 13 | --- 14 | 15 | ## Table of contents 16 | 17 | * [Important Note for ESP32_S3](#Important-Note-for-ESP32_S3) 18 | * [Important Change from v1.2.0](#Important-Change-from-v120) 19 | * [Why do we need this AsyncTCP_SSL library](#why-do-we-need-this-AsyncTCP_SSL-library) 20 | * [Features](#features) 21 | * [Why Async is better](#why-async-is-better) 22 | * [Currently supported Boards](#currently-supported-boards) 23 | * [Changelog](changelog.md) 24 | * [Prerequisites](#prerequisites) 25 | * [Installation](#installation) 26 | * [Use Arduino Library Manager](#use-arduino-library-manager) 27 | * [Manual Install](#manual-install) 28 | * [VS Code & PlatformIO](#vs-code--platformio) 29 | * [Note for Platform IO using ESP32 LittleFS](#note-for-platform-io-using-esp32-littlefs) 30 | * [HOWTO Fix `Multiple Definitions` Linker Error](#howto-fix-multiple-definitions-linker-error) 31 | * [Note for Platform IO using ESP32 LittleFS](#note-for-platform-io-using-esp32-littlefs) 32 | * [HOWTO Use analogRead() with ESP32 running WiFi and/or BlueTooth (BT/BLE)](#howto-use-analogread-with-esp32-running-wifi-andor-bluetooth-btble) 33 | * [1. ESP32 has 2 ADCs, named ADC1 and ADC2](#1--esp32-has-2-adcs-named-adc1-and-adc2) 34 | * [2. ESP32 ADCs functions](#2-esp32-adcs-functions) 35 | * [3. ESP32 WiFi uses ADC2 for WiFi functions](#3-esp32-wifi-uses-adc2-for-wifi-functions) 36 | * [Original documentation](#Original-documentation) 37 | * [AsyncSSLClient](#AsyncSSLClient) 38 | * [Examples](#examples) 39 | * [1. multiFileProject](examples/multiFileProject) 40 | * [Debug Terminal Output Samples](#debug-terminal-output-samples) 41 | * [1. AsyncHTTPSRequest_ESP on ESP32_DEV](#1-AsyncHTTPSRequest_ESP-on-ESP32_DEV) 42 | * [2. AsyncHTTPSRequest_ESP on ESP32S2_DEV](#2-AsyncHTTPSRequest_ESP-on-ESP32S2_DEV) 43 | * [3. AsyncHTTPSRequest_ESP on ESP32C3_DEV](#3-AsyncHTTPSRequest_ESP-on-ESP32C3_DEV) 44 | * [4. AsyncHTTPSRequest_ESP_WiFiManager on ESP32_DEV](#4-AsyncHTTPSRequest_ESP_WiFiManager-on-ESP32_DEV) 45 | * [5. AsyncHTTPSRequest_ESP_Multi on ESP32S3_DEV](#5-AsyncHTTPSRequest_ESP_Multi-on-ESP32S3_DEV) 46 | * [Debug](#debug) 47 | * [Troubleshooting](#troubleshooting) 48 | * [Issues](#issues) 49 | * [TO DO](#to-do) 50 | * [DONE](#done) 51 | * [Contributions and Thanks](#contributions-and-thanks) 52 | * [Contributing](#contributing) 53 | * [License](#license) 54 | * [Copyright](#copyright) 55 | 56 | --- 57 | --- 58 | 59 | ### Important Note for ESP32_S3 60 | 61 | **Don't use `ESP32_S3` with core v2.0.4**. Check `already fixed` [ESP32-S3 Powercycling right after uploading a sketch using Arduino IDE and Arduino Core 2.0.4 #7165](https://github.com/espressif/arduino-esp32/issues/7165) 62 | 63 | **ESP32_S3 is OK now with core v2.0.5** 64 | 65 | --- 66 | 67 | ### Important Change from v1.2.0 68 | 69 | Please have a look at [HOWTO Fix `Multiple Definitions` Linker Error](#howto-fix-multiple-definitions-linker-error) 70 | 71 | --- 72 | 73 | ### Why do we need this [AsyncTCP_SSL library](https://github.com/khoih-prog/AsyncTCP_SSL) 74 | 75 | #### Features 76 | 77 | This library is based on, modified from: 78 | 79 | 1. [Hristo Gochkov's AsyncTCP](https://github.com/me-no-dev/AsyncTCP) 80 | 2. [Maarten Fremouw's AsyncTCP](https://github.com/fremouw/AsyncTCP). 81 | 3. [Thorsten von Eicken's AsyncTCP](https://github.com/tve/AsyncTCP) 82 | 83 | to apply the better and faster **asynchronous** feature of the **powerful** [AsyncTCP Library](https://github.com/me-no-dev/AsyncTCP) with SSL, and will be the base for future and more advanced Async libraries for ESP32, such as AsyncSSLWebServer, AsyncHTTPSRequest, etc. 84 | 85 | 86 | #### Why Async is better 87 | 88 | - Using asynchronous network means that you can handle **more than one connection at the same time** 89 | - **You are called once the request is ready and parsed** 90 | - When you send the response, you are **immediately ready** to handle other connections while the server is taking care of sending the response in the background 91 | - **Speed is OMG** 92 | - **Easy to use API, HTTP Basic and Digest MD5 Authentication (default), ChunkedResponse** 93 | - Easily extensible to handle **any type of content** 94 | - Supports Continue 100 95 | - **Async WebSocket plugin offering different locations without extra servers or ports** 96 | - Async EventSource (Server-Sent Events) plugin to send events to the browser 97 | - URL Rewrite plugin for conditional and permanent url rewrites 98 | - ServeStatic plugin that supports cache, Last-Modified, default index and more 99 | - Simple template processing engine to handle templates 100 | 101 | 102 | ### Currently supported Boards 103 | 104 | 1. `ESP32` boards, such as ESP32_DEV, etc. 105 | 2. `ESP32_S2`-based boards, such as ESP32S2_DEV, ESP32_S2 Saola, etc. 106 | 3. `ESP32_C3`-based boards, such as ESP32C3_DEV, etc. 107 | 4. `ESP32_S3`-based boards, such as ESP32S3_DEV, etc., using ESP32 core `v2.0.3` or `v2.0.5+` 108 | 109 | 110 | --- 111 | --- 112 | 113 | ## Prerequisites 114 | 115 | 1. [`Arduino IDE 1.8.19+` for Arduino](https://github.com/arduino/Arduino). [![GitHub release](https://img.shields.io/github/release/arduino/Arduino.svg)](https://github.com/arduino/Arduino/releases/latest) 116 | 2. [`ESP32 Core 2.0.5+`](https://github.com/espressif/arduino-esp32) for ESP32-based boards. [![Latest release](https://img.shields.io/github/release/espressif/arduino-esp32.svg)](https://github.com/espressif/arduino-esp32/releases/latest/) for ESP32, ESP32_S2, ESP32_C3 117 | 3. [`ESP32 Core 2.0.4`](https://github.com/espressif/arduino-esp32) can't be used for ESP32_S3-based boards. Check `already fixed` [ESP32-S3 Powercycling right after uploading a sketch using Arduino IDE and Arduino Core 2.0.4 #7165](https://github.com/espressif/arduino-esp32/issues/7165) 118 | 119 | --- 120 | --- 121 | 122 | ## Installation 123 | 124 | ### Use Arduino Library Manager 125 | 126 | The best and easiest way is to use `Arduino Library Manager`. Search for [**AsyncTCP_SSL**](https://github.com/khoih-prog/AsyncTCP_SSL), then select / install the latest version. 127 | You can also use this link [![arduino-library-badge](https://www.ardu-badge.com/badge/AsyncTCP_SSL.svg?)](https://www.ardu-badge.com/AsyncTCP_SSL) for more detailed instructions. 128 | 129 | ### Manual Install 130 | 131 | Another way to install is to: 132 | 133 | 1. Navigate to [**AsyncTCP_SSL**](https://github.com/khoih-prog/AsyncTCP_SSL) page. 134 | 2. Download the latest release `AsyncTCP_SSL-main.zip`. 135 | 3. Extract the zip file to `AsyncTCP_SSL-main` directory 136 | 4. Copy whole `AsyncTCP_SSL-main` folder to Arduino libraries' directory such as `~/Arduino/libraries/`. 137 | 138 | ### VS Code & PlatformIO 139 | 140 | 1. Install [VS Code](https://code.visualstudio.com/) 141 | 2. Install [PlatformIO](https://platformio.org/platformio-ide) 142 | 3. Install [**AsyncTCP_SSL** library](https://registry.platformio.org/libraries/khoih-prog/AsyncTCP_SSL) by using [Library Manager](https://registry.platformio.org/libraries/khoih-prog/AsyncTCP_SSL/installation). Search for **AsyncTCP_SSL** in [Platform.io Author's Libraries](https://platformio.org/lib/search?query=author:%22Khoi%20Hoang%22) 143 | 4. Use included [platformio.ini](platformio/platformio.ini) file from examples to ensure that all dependent libraries will installed automatically. Please visit documentation for the other options and examples at [Project Configuration File](https://docs.platformio.org/page/projectconf.html) 144 | 145 | --- 146 | --- 147 | 148 | 149 | ### Note for Platform IO using ESP32 LittleFS 150 | 151 | In Platform IO, to fix the error when using [`LittleFS_esp32 v1.0`](https://github.com/lorol/LITTLEFS) for ESP32-based boards with ESP32 core v1.0.4- (ESP-IDF v3.2-), uncomment the following line 152 | 153 | from 154 | 155 | ```cpp 156 | //#define CONFIG_LITTLEFS_FOR_IDF_3_2 /* For old IDF - like in release 1.0.4 */ 157 | ``` 158 | 159 | to 160 | 161 | ```cpp 162 | #define CONFIG_LITTLEFS_FOR_IDF_3_2 /* For old IDF - like in release 1.0.4 */ 163 | ``` 164 | 165 | It's advisable to use the latest [`LittleFS_esp32 v1.0.5+`](https://github.com/lorol/LITTLEFS) to avoid the issue. 166 | 167 | Thanks to [Roshan](https://github.com/solroshan) to report the issue in [Error esp_littlefs.c 'utime_p'](https://github.com/khoih-prog/ESPAsync_WiFiManager/issues/28) 168 | 169 | --- 170 | --- 171 | 172 | ### HOWTO Fix `Multiple Definitions` Linker Error 173 | 174 | The current library implementation, using `xyz-Impl.h` instead of standard `xyz.cpp`, possibly creates certain `Multiple Definitions` Linker error in certain use cases. 175 | 176 | You can include this `.hpp` file 177 | 178 | ```cpp 179 | // Can be included as many times as necessary, without `Multiple Definitions` Linker Error 180 | #include "AsyncTCP_SSL.hpp" //https://github.com/khoih-prog/AsyncTCP_SSL 181 | ``` 182 | 183 | in many files. But be sure to use the following `.h` file **in just 1 `.h`, `.cpp` or `.ino` file**, which must **not be included in any other file**, to avoid `Multiple Definitions` Linker Error 184 | 185 | ```cpp 186 | // To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error 187 | #include "AsyncTCP_SSL.h" //https://github.com/khoih-prog/AsyncTCP_SSL 188 | ``` 189 | 190 | Check the new [**multiFileProject** example](examples/multiFileProject) for a `HOWTO` demo. 191 | 192 | --- 193 | --- 194 | 195 | ### Note for Platform IO using ESP32 LittleFS 196 | 197 | In Platform IO, to fix the error when using [`LittleFS_esp32 v1.0`](https://github.com/lorol/LITTLEFS) for ESP32-based boards with ESP32 core v1.0.4- (ESP-IDF v3.2-), uncomment the following line 198 | 199 | from 200 | 201 | ```cpp 202 | //#define CONFIG_LITTLEFS_FOR_IDF_3_2 /* For old IDF - like in release 1.0.4 */ 203 | ``` 204 | 205 | to 206 | 207 | ```cpp 208 | #define CONFIG_LITTLEFS_FOR_IDF_3_2 /* For old IDF - like in release 1.0.4 */ 209 | ``` 210 | 211 | It's advisable to use the latest [`LittleFS_esp32 v1.0.5+`](https://github.com/lorol/LITTLEFS) to avoid the issue. 212 | 213 | Thanks to [Roshan](https://github.com/solroshan) to report the issue in [Error esp_littlefs.c 'utime_p'](https://github.com/khoih-prog/ESPAsync_WiFiManager/issues/28) 214 | 215 | --- 216 | --- 217 | 218 | ### HOWTO Use analogRead() with ESP32 running WiFi and/or BlueTooth (BT/BLE) 219 | 220 | Please have a look at [**ESP_WiFiManager Issue 39: Not able to read analog port when using the autoconnect example**](https://github.com/khoih-prog/ESP_WiFiManager/issues/39) to have more detailed description and solution of the issue. 221 | 222 | #### 1. ESP32 has 2 ADCs, named ADC1 and ADC2 223 | 224 | #### 2. ESP32 ADCs functions 225 | 226 | - ADC1 controls ADC function for pins **GPIO32-GPIO39** 227 | - ADC2 controls ADC function for pins **GPIO0, 2, 4, 12-15, 25-27** 228 | 229 | #### 3.. ESP32 WiFi uses ADC2 for WiFi functions 230 | 231 | Look in file [**adc_common.c**](https://github.com/espressif/esp-idf/blob/master/components/driver/adc_common.c#L61) 232 | 233 | > In ADC2, there're two locks used for different cases: 234 | > 1. lock shared with app and Wi-Fi: 235 | > ESP32: 236 | > When Wi-Fi using the ADC2, we assume it will never stop, so app checks the lock and returns immediately if failed. 237 | > ESP32S2: 238 | > The controller's control over the ADC is determined by the arbiter. There is no need to control by lock. 239 | > 240 | > 2. lock shared between tasks: 241 | > when several tasks sharing the ADC2, we want to guarantee 242 | > all the requests will be handled. 243 | > Since conversions are short (about 31us), app returns the lock very soon, 244 | > we use a spinlock to stand there waiting to do conversions one by one. 245 | > 246 | > adc2_spinlock should be acquired first, then adc2_wifi_lock or rtc_spinlock. 247 | 248 | 249 | - In order to use ADC2 for other functions, we have to **acquire complicated firmware locks and very difficult to do** 250 | - So, it's not advisable to use ADC2 with WiFi/BlueTooth (BT/BLE). 251 | - Use ADC1, and pins GPIO32-GPIO39 252 | - If somehow it's a must to use those pins serviced by ADC2 (**GPIO0, 2, 4, 12, 13, 14, 15, 25, 26 and 27**), use the **fix mentioned at the end** of [**ESP_WiFiManager Issue 39: Not able to read analog port when using the autoconnect example**](https://github.com/khoih-prog/ESP_WiFiManager/issues/39) to work with ESP32 WiFi/BlueTooth (BT/BLE). 253 | 254 | --- 255 | --- 256 | 257 | 258 | ## Original documentation 259 | 260 | For ESP32, check [AsyncTCP Library](https://github.com/me-no-dev/AsyncTCP) 261 | 262 | This is a fully asynchronous SSL TCP library, aimed at enabling trouble-free, multi-connection network environment for Espressif's ESP32 MCUs. 263 | 264 | ### AsyncSSLClient 265 | 266 | The base classes on which everything else is built. They expose all possible scenarios, but are really raw and require more skills to use. 267 | 268 | --- 269 | --- 270 | 271 | ### Examples 272 | 273 | 1. [multiFileProject](examples/multiFileProject). **New** 274 | 275 | --- 276 | --- 277 | 278 | ### Debug Terminal Output Samples 279 | 280 | #### 1. AsyncHTTPSRequest_ESP on ESP32_DEV 281 | 282 | Following is the debug terminal when running example [AsyncHTTPSRequest_ESP](https://github.com/khoih-prog/AsyncHTTPSRequest_Generic/tree/main/examples/AsyncHTTPSRequest_ESP) on ESP32_DEV to demonstrate the operation of SSL Async HTTPS request, using [AsyncTCP_SSL Library](https://github.com/khoih-prog/AsyncTCP_SSL). 283 | 284 | ```cpp 285 | Starting AsyncHTTPSRequest_ESP using ESP32_DEV 286 | AsyncTCP_SSL v1.3.1 287 | AsyncHTTPSRequest_Generic v2.1.2 288 | Connecting to WiFi SSID: HueNet1 289 | ....... 290 | AsyncHTTPSRequest @ IP : 192.168.2.133 291 | 292 | ************************************** 293 | abbreviation: EDT 294 | client_ip: aaa.bbb.ccc.ddd 295 | datetime: 2022-09-18T01:35:32.451975-04:00 296 | day_of_week: 0 297 | day_of_year: 261 298 | dst: true 299 | dst_from: 2022-03-13T07:00:00+00:00 300 | dst_offset: 3600 301 | dst_until: 2022-11-06T06:00:00+00:00 302 | raw_offset: -18000 303 | timezone: America/Toronto 304 | unixtime: 1663479332 305 | utc_datetime: 2022-09-18T05:35:32.451975+00:00 306 | utc_offset: -04:00 307 | week_number: 37 308 | ************************************** 309 | HHHHHH 310 | ************************************** 311 | abbreviation: EDT 312 | client_ip: aaa.bbb.ccc.ddd 313 | datetime: 2022-09-18T01:36:31.992595-04:00 314 | day_of_week: 0 315 | day_of_year: 261 316 | dst: true 317 | dst_from: 2022-03-13T07:00:00+00:00 318 | dst_offset: 3600 319 | dst_until: 2022-11-06T06:00:00+00:00 320 | raw_offset: -18000 321 | timezone: America/Toronto 322 | unixtime: 1663479391 323 | utc_datetime: 2022-09-18T05:36:31.992595+00:00 324 | utc_offset: -04:00 325 | week_number: 37 326 | ``` 327 | --- 328 | 329 | #### 2. AsyncHTTPSRequest_ESP on ESP32S2_DEV 330 | 331 | Following is the debug terminal when running example [AsyncHTTPSRequest_ESP](https://github.com/khoih-prog/AsyncHTTPSRequest_Generic/tree/main/examples/AsyncHTTPSRequest_ESP) on ESP32S2_DEV to demonstrate the operation of SSL Async HTTPS request, using [AsyncTCP_SSL Library](https://github.com/khoih-prog/AsyncTCP_SSL). 332 | 333 | ```cpp 334 | Starting AsyncHTTPSRequest_ESP using ESP32S2_DEV 335 | AsyncTCP_SSL v1.3.1 336 | AsyncHTTPSRequest_Generic v2.1.2 337 | Connecting to WiFi SSID: HueNet1 338 | ....... 339 | AsyncHTTPSRequest @ IP : 192.168.2.79 340 | [ATCP] _handle_async_event: LWIP_TCP_DNS = 0x3FFE4E24 341 | [ATCP] _handle_async_event: LWIP_TCP_DNS, name = worldtimeapi.org , IP = 213.188.196.246 342 | [ATCP] _handle_async_event: LWIP_TCP_CONNECTED = 0x3FFE4E24 0x3FFE5024 343 | [ATCP] _handle_async_event: LWIP_TCP_CONNECTED = 0 344 | [ATCP] _handle_async_event: LWIP_TCP_SENT = 0x3FFE5024 345 | [ATCP] _sent: len = 305 346 | [ATCP] _handle_async_event: LWIP_TCP_RECV = 0x3FFE5024 347 | [ATCP] _recv: tot_len = 1436 348 | [ATCP] _handle_async_event: LWIP_TCP_RECV = 0x3FFE5024 349 | [ATCP] _recv: tot_len = 1436 350 | [ATCP] _handle_async_event: LWIP_TCP_RECV = 0x3FFE5024 351 | [ATCP] _recv: tot_len = 1242 352 | [ATCP] _handle_async_event: LWIP_TCP_SENT = 0x3FFE5024 353 | [ATCP] _sent: len = 107 354 | [ATCP] _handle_async_event: LWIP_TCP_SENT = 0x3FFE5024 355 | [ATCP] _sent: len = 6 356 | [ATCP] _handle_async_event: LWIP_TCP_SENT = 0x3FFE5024 357 | [ATCP] _sent: len = 45 358 | [ATCP] _handle_async_event: LWIP_TCP_RECV = 0x3FFE5024 359 | [ATCP] _recv: tot_len = 51 360 | [ATCP] _handle_async_event: LWIP_TCP_SENT = 0x3FFE5024 361 | [ATCP] _sent: len = 106 362 | [ATCP] _handle_async_event: LWIP_TCP_RECV = 0x3FFE5024 363 | [ATCP] _recv: tot_len = 1016 364 | ************************************** 365 | abbreviation: EDT 366 | client_ip: aaa.bbb.ccc.ddd 367 | datetime: 2022-09-18T01:46:31.858783-04:00 368 | day_of_week: 0 369 | day_of_year: 261 370 | dst: true 371 | dst_from: 2022-03-13T07:00:00+00:00 372 | dst_offset: 3600 373 | dst_until: 2022-11-06T06:00:00+00:00 374 | raw_offset: -18000 375 | timezone: America/Toronto 376 | unixtime: 1663479991 377 | utc_datetime: 2022-09-18T05:46:31.858783+00:00 378 | utc_offset: -04:00 379 | week_number: 37 380 | ************************************** 381 | ``` 382 | 383 | --- 384 | 385 | #### 3. AsyncHTTPSRequest_ESP on ESP32C3_DEV 386 | 387 | Following is the debug terminal when running example [AsyncHTTPSRequest_ESP](https://github.com/khoih-prog/AsyncHTTPSRequest_Generic/tree/main/examples/AsyncHTTPSRequest_ESP) on ESP32C3_DEV to demonstrate the operation of SSL Async HTTPS request, using [AsyncTCP_SSL Library](https://github.com/khoih-prog/AsyncTCP_SSL). 388 | 389 | ```cpp 390 | Starting AsyncHTTPSRequest_ESP using ESP32C3_DEV 391 | AsyncTCP_SSL v1.3.1 392 | AsyncHTTPSRequest_Generic v2.1.2 393 | Connecting to WiFi SSID: HueNet1 394 | ......... 395 | AsyncHTTPSRequest @ IP : 192.168.2.80 396 | ************************************** 397 | abbreviation: EDT 398 | client_ip: aaa.bbb.ccc.ddd 399 | datetime: 2022-09-18T01:35:32.451975-04:00 400 | day_of_week: 0 401 | day_of_year: 261 402 | dst: true 403 | dst_from: 2022-03-13T07:00:00+00:00 404 | dst_offset: 3600 405 | dst_until: 2022-11-06T06:00:00+00:00 406 | raw_offset: -18000 407 | timezone: America/Toronto 408 | unixtime: 1663479332 409 | utc_datetime: 2022-09-18T05:35:32.451975+00:00 410 | utc_offset: -04:00 411 | week_number: 37 412 | ************************************** 413 | ``` 414 | 415 | --- 416 | 417 | #### 4. AsyncHTTPSRequest_ESP_WiFiManager on ESP32_DEV 418 | 419 | Following is the debug terminal when running example [AsyncHTTPSRequest_ESP_WiFiManager](https://github.com/khoih-prog/AsyncHTTPSRequest_Generic/tree/main/examples/AsyncHTTPSRequest_ESP_WiFiManager) on ESP32_DEV to demonstrate the operation of SSL Async HTTPS request, using [AsyncTCP_SSL Library](https://github.com/khoih-prog/AsyncTCP_SSL), and [ESPAsync_WiFiManager Library](https://github.com/khoih-prog/ESPAsync_WiFiManager) 420 | 421 | ```cpp 422 | Starting AsyncHTTPSRequest_ESP_WiFiManager using LittleFS on ESP32_DEV 423 | ESPAsync_WiFiManager v1.14.1 424 | AsyncTCP_SSL v1.3.1 425 | AsyncHTTPSRequest_Generic v2.1.2 426 | Stored: SSID = HueNet1, Pass = 12345678 427 | Got stored Credentials. Timeout 120s 428 | ConnectMultiWiFi in setup 429 | After waiting 11.38 secs more in setup(), connection result is connected. Local IP: 192.168.2.232 430 | H 431 | ************************************** 432 | abbreviation: EDT 433 | client_ip: aaa.bbb.ccc.ddd 434 | datetime: 2022-09-18T01:36:31.992595-04:00 435 | day_of_week: 0 436 | day_of_year: 261 437 | dst: true 438 | dst_from: 2022-03-13T07:00:00+00:00 439 | dst_offset: 3600 440 | dst_until: 2022-11-06T06:00:00+00:00 441 | raw_offset: -18000 442 | timezone: America/Toronto 443 | unixtime: 1663479391 444 | utc_datetime: 2022-09-18T05:36:31.992595+00:00 445 | utc_offset: -04:00 446 | week_number: 37 447 | ************************************** 448 | H 449 | ``` 450 | 451 | --- 452 | 453 | #### 5. AsyncHTTPSRequest_ESP_Multi on ESP32S3_DEV 454 | 455 | Following is the debug terminal when running example [AsyncHTTPSRequest_ESP_Multi](https://github.com/khoih-prog/AsyncHTTPSRequest_Generic/tree/main/examples/AsyncHTTPSRequest_ESP_Multi) on **ESP32S3_DEV on ESP32 core v2.0.5** to demonstrate the operation of SSL Async HTTPS request, using [AsyncTCP_SSL Library](https://github.com/khoih-prog/AsyncTCP_SSL) 456 | 457 | 458 | ```cpp 459 | Starting AsyncHTTPSRequest_ESP_Multi on ESP32S3_DEV 460 | AsyncTCP_SSL v1.3.1 461 | AsyncHTTPSRequest_Generic v2.1.2 462 | Connecting to WiFi SSID: HueNet1 463 | ... 464 | AsyncHTTPSRequest @ IP : 192.168.2.187 465 | 466 | Sending request: https://worldtimeapi.org/api/timezone/Europe/Prague.txt 467 | 468 | Sending request: https://www.myexternalip.com/raw 469 | [AHTTPS] _onError handler SSL error = OK 470 | [AHTTPS] _onError handler SSL error = OK 471 | 472 | ************************************** 473 | [AHTTPS] Response Code = HTTP OK 474 | 475 | ************************************** 476 | aaa.bbb.ccc.ddd 477 | ************************************** 478 | 479 | ************************************** 480 | [AHTTPS] Response Code = HTTP OK 481 | 482 | ************************************** 483 | abbreviation: CEST 484 | client_ip: aaa.bbb.ccc.ddd 485 | datetime: 2022-09-18T07:50:04.395849+02:00 486 | day_of_week: 0 487 | day_of_year: 261 488 | dst: true 489 | dst_from: 2022-03-27T01:00:00+00:00 490 | dst_offset: 3600 491 | dst_until: 2022-10-30T01:00:00+00:00 492 | raw_offset: 3600 493 | timezone: Europe/Prague 494 | unixtime: 1663480204 495 | utc_datetime: 2022-09-18T05:50:04.395849+00:00 496 | utc_offset: +02:00 497 | week_number: 37 498 | ************************************** 499 | 500 | Sending request: https://worldtimeapi.org/api/timezone/America/Toronto.txt 501 | 502 | ************************************** 503 | [AHTTPS] Response Code = HTTP OK 504 | 505 | ************************************** 506 | abbreviation: EDT 507 | client_ip: aaa.bbb.ccc.ddd 508 | datetime: 2022-09-18T01:50:05.382100-04:00 509 | day_of_week: 0 510 | day_of_year: 261 511 | dst: true 512 | dst_from: 2022-03-13T07:00:00+00:00 513 | dst_offset: 3600 514 | dst_until: 2022-11-06T06:00:00+00:00 515 | raw_offset: -18000 516 | timezone: America/Toronto 517 | unixtime: 1663480205 518 | utc_datetime: 2022-09-18T05:50:05.382100+00:00 519 | utc_offset: -04:00 520 | week_number: 37 521 | ************************************** 522 | H 523 | ``` 524 | 525 | --- 526 | --- 527 | 528 | ### Debug 529 | 530 | Debug is enabled by default on Serial. 531 | 532 | You can also change the debugging level `_ASYNC_TCP_SSL_LOGLEVEL_` from 0 to 4 in the sketch 533 | 534 | 535 | ```cpp 536 | #define _ASYNC_TCP_SSL_LOGLEVEL_ 1 537 | ``` 538 | 539 | --- 540 | 541 | ### Troubleshooting 542 | 543 | If you get compilation errors, more often than not, you may need to install a newer version of the core for Arduino boards. 544 | 545 | Sometimes, the library will only work if you update the board core to the latest version because I am using newly added functions. 546 | 547 | 548 | --- 549 | --- 550 | 551 | ### Issues 552 | 553 | Submit issues to: [AsyncTCP_SSL issues](https://github.com/khoih-prog/AsyncTCP_SSL/issues) 554 | 555 | --- 556 | 557 | ## TO DO 558 | 559 | 1. Search for bug and improvement. 560 | 2. Similar Async SSL libraries for ESP8266, STM32, Portenta_H7 and many other boards 561 | 3. Permit both HTTP and HTTPS 562 | 563 | --- 564 | 565 | ## DONE 566 | 567 | 1. Add support to ESP32 using SSL 568 | 2. Add Table of Contents 569 | 3. Add debug feature 570 | 4. Fix `multiple-definitions` linker error 571 | 5. Add examples 572 | 6. Remove hard-code if possible 573 | 7. Improve debug messages by adding functions to display `error/state messages` instead of `cryptic error/state number` 574 | 8. Add support to `ESP32_S3`, using ESP32 core `v2.0.3` or `v2.0.5+`. **Don't use `ESP32_S3` with core v2.0.4**. Check `already fixed` [ESP32-S3 Powercycling right after uploading a sketch using Arduino IDE and Arduino Core 2.0.4 #7165](https://github.com/espressif/arduino-esp32/issues/7165) 575 | 9. Increase `ASYNC_QUEUE_LENGTH` to default **512 from 32** and make it user-configurable 576 | 10. Increase `ASYNC_TCP_PRIORITY` to default **10 from 3**, and make it user-configurable 577 | 578 | 579 | --- 580 | --- 581 | 582 | ### Contributions and Thanks 583 | 584 | Many thanks for everyone for bug reporting, new feature suggesting, testing and contributing to the development of this library. 585 | 586 | ### Contributions and Thanks 587 | 588 | 1. Based on and modified from [Hristo Gochkov's AsyncTCP](https://github.com/me-no-dev/AsyncTCP). Many thanks to [Hristo Gochkov](https://github.com/me-no-dev) for great [AsyncTCP Library](https://github.com/me-no-dev/AsyncTCP) 589 | 2. Based on [Maarten Fremouw's AsyncTCP Library](https://github.com/fremouw/AsyncTCP). 590 | 3. Based on [Thorsten von Eicken's AsyncTCP Library](https://github.com/tve/AsyncTCP). 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 |
me-no-dev
⭐️⭐️ Hristo Gochkov

fremouw
Maarten Fremouw

tve
Thorsten von Eicken

599 | 600 | --- 601 | 602 | ## Contributing 603 | 604 | If you want to contribute to this project: 605 | 606 | - Report bugs and errors 607 | - Ask for enhancements 608 | - Create issues and pull requests 609 | - Tell other people about this library 610 | 611 | --- 612 | 613 | ### License 614 | 615 | - The library is licensed under [LGPLv3](https://github.com/khoih-prog/AsyncTCP_SSL/blob/main/LICENSE) 616 | 617 | --- 618 | 619 | ## Copyright 620 | 621 | - Copyright (c) 2016- Hristo Gochkov 622 | - Copyright (c) 2019- Maarten Fremouw 623 | - Copyright (c) 2019- Thorsten von Eicken 624 | - Copyright (c) 2021- Khoi Hoang 625 | 626 | 627 | -------------------------------------------------------------------------------- /src/AsyncTCP_SSL_Impl.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************************************************************** 2 | AsyncTCP_SSL_Impl.h 3 | 4 | AsyncTCP_SSL is a library for ESP32 5 | 6 | Based on and modified from : 7 | 8 | 1) AsyncTCP (https://github.com/me-no-dev/ESPAsyncTCP) 9 | 2) AsyncTCP (https://github.com/tve/AsyncTCP) 10 | 11 | Built by Khoi Hoang https://github.com/khoih-prog/AsyncTCP_SSL 12 | 13 | This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License 14 | as published bythe Free Software Foundation, either version 3 of the License, or (at your option) any later version. 15 | This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 17 | 18 | Version: 1.3.1 19 | 20 | Version Modified By Date Comments 21 | ------- ----------- ---------- ----------- 22 | 1.0.0 K Hoang 21/10/2021 Initial coding to support only ESP32 23 | 1.1.0 K Hoang 22/10/2021 Fix bug. Enable coexistence with AsyncTCP 24 | 1.2.0 K Hoang 23/01/2022 Fix `multiple-definitions` linker error 25 | 1.3.0 K Hoang 04/09/2022 Clean up. Remove hard-code if possible 26 | 1.3.1 K Hoang 18/09/2022 Improve stability. Make queue length user-configurable 27 | *****************************************************************************************************************************/ 28 | 29 | /* 30 | Asynchronous TCP library for Espressif MCUs 31 | 32 | Copyright (c) 2016 Hristo Gochkov. All rights reserved. 33 | This file is part of the esp8266 core for Arduino environment. 34 | 35 | This library is free software; you can redistribute it and/or 36 | modify it under the terms of the GNU Lesser General Public 37 | License as published by the Free Software Foundation; either 38 | version 2.1 of the License, or (at your option) any later version. 39 | 40 | This library is distributed in the hope that it will be useful, 41 | but WITHOUT ANY WARRANTY; without even the implied warranty of 42 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 43 | Lesser General Public License for more details. 44 | 45 | You should have received a copy of the GNU Lesser General Public 46 | License along with this library; if not, write to the Free Software 47 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 48 | */ 49 | 50 | #ifndef ASYNCTCP_SSL_IML_H 51 | #define ASYNCTCP_SSL_IML_H 52 | 53 | #include "Arduino.h" 54 | 55 | #include "AsyncTCP_SSL_Debug.h" 56 | 57 | extern "C" 58 | { 59 | #include "lwip/opt.h" 60 | #include "lwip/tcp.h" 61 | #include "lwip/inet.h" 62 | #include "lwip/dns.h" 63 | #include "lwip/err.h" 64 | } 65 | 66 | #include "esp_task_wdt.h" 67 | 68 | #define CONFIG_ASYNC_TCP_STACK (2*8192) 69 | 70 | #define ASYNC_TCP_SSL_DEBUG(...) 71 | 72 | ////////////////////////////////////////////////////////////////////////////////////////// 73 | 74 | /* 75 | TCP/IP Event Task 76 | 77 | This task processes events that correspond to the various callbacks made by LwIP. The callbacks 78 | are handled by _tcp_* functions, which package the info into events, which are processed by this 79 | task. The purpose of this scheme is ??? (to be able to block or spend arbitrary time in the event 80 | handlers without thereby blocking LwIP???). 81 | * */ 82 | 83 | typedef enum 84 | { 85 | LWIP_TCP_SENT, 86 | LWIP_TCP_RECV, 87 | LWIP_TCP_FIN, 88 | LWIP_TCP_ERROR, 89 | LWIP_TCP_POLL, 90 | LWIP_TCP_CLEAR, 91 | LWIP_TCP_ACCEPT, 92 | LWIP_TCP_CONNECTED, 93 | LWIP_TCP_DNS 94 | } lwip_event_t; 95 | 96 | typedef struct 97 | { 98 | lwip_event_t event; 99 | void *arg; 100 | 101 | union 102 | { 103 | struct 104 | { 105 | void * pcb; 106 | int8_t err; 107 | } connected; 108 | 109 | struct 110 | { 111 | int8_t err; 112 | } error; 113 | 114 | struct 115 | { 116 | tcp_pcb * pcb; 117 | uint16_t len; 118 | } sent; 119 | 120 | struct 121 | { 122 | tcp_pcb * pcb; 123 | pbuf * pb; 124 | int8_t err; 125 | } recv; 126 | 127 | struct 128 | { 129 | tcp_pcb * pcb; 130 | int8_t err; 131 | } fin; 132 | 133 | struct 134 | { 135 | tcp_pcb * pcb; 136 | } poll; 137 | 138 | struct 139 | { 140 | AsyncSSLClient * client; 141 | } accept; 142 | 143 | struct 144 | { 145 | const char * name; 146 | ip_addr_t addr; 147 | } dns; 148 | }; 149 | } lwip_event_packet_t; 150 | 151 | ///////////////////////////////////////////////// 152 | 153 | static xQueueHandle _async_queue; 154 | static TaskHandle_t _async_service_task_handle = NULL; 155 | 156 | static SemaphoreHandle_t _slots_lock; 157 | const int _number_of_closed_slots = CONFIG_LWIP_MAX_ACTIVE_TCP; 158 | static int _closed_slots[_number_of_closed_slots]; 159 | 160 | ///////////////////////////////////////////// 161 | 162 | static int _closed_index = []() 163 | { 164 | _slots_lock = xSemaphoreCreateBinary(); 165 | xSemaphoreGive(_slots_lock); 166 | 167 | for (int i = 0; i < _number_of_closed_slots; ++ i) 168 | { 169 | _closed_slots[i] = 1; 170 | } 171 | 172 | return 1; 173 | } 174 | (); 175 | 176 | ///////////////////////////////////////////// 177 | 178 | static inline bool _init_async_event_queue() 179 | { 180 | if (!_async_queue) 181 | { 182 | _async_queue = xQueueCreate(ASYNC_QUEUE_LENGTH, sizeof(lwip_event_packet_t *)); 183 | 184 | if (!_async_queue) 185 | { 186 | return false; 187 | } 188 | } 189 | 190 | return true; 191 | } 192 | 193 | ///////////////////////////////////////////// 194 | 195 | static inline bool _send_async_event(lwip_event_packet_t ** e) 196 | { 197 | return _async_queue && xQueueSend(_async_queue, e, portMAX_DELAY) == pdPASS; 198 | } 199 | 200 | ///////////////////////////////////////////// 201 | 202 | static inline bool _prepend_async_event(lwip_event_packet_t ** e) 203 | { 204 | return _async_queue && xQueueSendToFront(_async_queue, e, portMAX_DELAY) == pdPASS; 205 | } 206 | 207 | ///////////////////////////////////////////// 208 | 209 | static inline bool _get_async_event(lwip_event_packet_t ** e) 210 | { 211 | return _async_queue && xQueueReceive(_async_queue, e, portMAX_DELAY) == pdPASS; 212 | } 213 | 214 | ///////////////////////////////////////////// 215 | 216 | static bool _remove_events_with_arg(void * arg) 217 | { 218 | lwip_event_packet_t * first_packet = NULL; 219 | lwip_event_packet_t * packet = NULL; 220 | 221 | if (!_async_queue) 222 | { 223 | return false; 224 | } 225 | 226 | //figure out which is the first packet so we can keep the order 227 | while (!first_packet) 228 | { 229 | if (xQueueReceive(_async_queue, &first_packet, 0) != pdPASS) 230 | { 231 | return false; 232 | } 233 | 234 | //discard packet if matching 235 | if ((int)first_packet->arg == (int)arg) 236 | { 237 | free(first_packet); 238 | first_packet = NULL; 239 | //return first packet to the back of the queue 240 | } 241 | else if (xQueueSend(_async_queue, &first_packet, portMAX_DELAY) != pdPASS) 242 | { 243 | return false; 244 | } 245 | } 246 | 247 | while (xQueuePeek(_async_queue, &packet, 0) == pdPASS && packet != first_packet) 248 | { 249 | if (xQueueReceive(_async_queue, &packet, 0) != pdPASS) 250 | { 251 | return false; 252 | } 253 | 254 | if ((int)packet->arg == (int)arg) 255 | { 256 | free(packet); 257 | packet = NULL; 258 | } 259 | else if (xQueueSend(_async_queue, &packet, portMAX_DELAY) != pdPASS) 260 | { 261 | return false; 262 | } 263 | } 264 | 265 | return true; 266 | } 267 | 268 | ///////////////////////////////////////////// 269 | 270 | static void _handle_async_event(lwip_event_packet_t * e) 271 | { 272 | ATCP_LOGDEBUG1("_handle_async_event: Task Name = ", pcTaskGetTaskName(xTaskGetCurrentTaskHandle())); 273 | 274 | if (e->event == LWIP_TCP_CLEAR) 275 | { 276 | _remove_events_with_arg(e->arg); 277 | } 278 | else if (e->event == LWIP_TCP_RECV) 279 | { 280 | ATCP_HEXLOGINFO1("_handle_async_event: LWIP_TCP_RECV =", (uint32_t) e->recv.pcb); 281 | AsyncSSLClient::_s_recv(e->arg, e->recv.pcb, e->recv.pb, e->recv.err); 282 | } 283 | else if (e->event == LWIP_TCP_FIN) 284 | { 285 | ATCP_HEXLOGINFO1("_handle_async_event: LWIP_TCP_FIN =", (uint32_t) e->fin.pcb); 286 | AsyncSSLClient::_s_fin(e->arg, e->fin.pcb, e->fin.err); 287 | } 288 | else if (e->event == LWIP_TCP_SENT) 289 | { 290 | ATCP_HEXLOGINFO1("_handle_async_event: LWIP_TCP_SENT =", (uint32_t) e->sent.pcb); 291 | AsyncSSLClient::_s_sent(e->arg, e->sent.pcb, e->sent.len); 292 | } 293 | else if (e->event == LWIP_TCP_POLL) 294 | { 295 | ATCP_HEXLOGDEBUG1("_handle_async_event: LWIP_TCP_POLL =", (uint32_t) e->poll.pcb); 296 | AsyncSSLClient::_s_poll(e->arg, e->poll.pcb); 297 | } 298 | else if (e->event == LWIP_TCP_ERROR) 299 | { 300 | ATCP_HEXLOGINFO1("_handle_async_event: LWIP_TCP_ERROR =", (uint32_t) e->arg); 301 | ATCP_LOGINFO1("_handle_async_event: LWIP_TCP_ERROR = ", e->error.err); 302 | AsyncSSLClient::_s_error(e->arg, e->error.err); 303 | } 304 | else if (e->event == LWIP_TCP_CONNECTED) 305 | { 306 | ATCP_HEXLOGINFO2("_handle_async_event: LWIP_TCP_CONNECTED =", (uint32_t) e->arg, (uint32_t) e->connected.pcb); 307 | ATCP_LOGINFO1("_handle_async_event: LWIP_TCP_CONNECTED = ", e->connected.err); 308 | AsyncSSLClient::_s_connected(e->arg, e->connected.pcb, e->connected.err); 309 | } 310 | else if (e->event == LWIP_TCP_ACCEPT) 311 | { 312 | ATCP_HEXLOGINFO2("_handle_async_event: LWIP_TCP_ACCEPT =", (uint32_t) e->arg, (uint32_t) e->accept.client); 313 | AsyncSSLServer::_s_accepted(e->arg, e->accept.client); 314 | } 315 | else if (e->event == LWIP_TCP_DNS) 316 | { 317 | ATCP_HEXLOGINFO1("_handle_async_event: LWIP_TCP_DNS =", (uint32_t) e->arg); 318 | ATCP_LOGINFO3("_handle_async_event: LWIP_TCP_DNS, name =", e->dns.name, ", IP =", ipaddr_ntoa(&e->dns.addr)); 319 | AsyncSSLClient::_s_dns_found(e->dns.name, &e->dns.addr, e->arg); 320 | } 321 | 322 | free((void*)(e)); 323 | } 324 | 325 | ///////////////////////////////////////////// 326 | 327 | static void _async_service_task(void *pvParameters) 328 | { 329 | lwip_event_packet_t * packet = NULL; 330 | 331 | for (;;) 332 | { 333 | if (_get_async_event(&packet)) 334 | { 335 | #if CONFIG_ASYNC_TCP_USE_WDT 336 | 337 | if (esp_task_wdt_add(NULL) != ESP_OK) 338 | { 339 | ATCP_LOGERROR("Failed to add async task to WDT"); 340 | } 341 | 342 | #endif 343 | 344 | if (packet) 345 | _handle_async_event(packet); 346 | else 347 | { 348 | ATCP_LOGERROR("_async_service_task, NUL packet"); 349 | } 350 | 351 | #if CONFIG_ASYNC_TCP_USE_WDT 352 | 353 | if (esp_task_wdt_delete(NULL) != ESP_OK) 354 | { 355 | ATCP_LOGERROR("Failed to remove loop task from WDT"); 356 | } 357 | 358 | #endif 359 | } 360 | } 361 | 362 | vTaskDelete(NULL); 363 | _async_service_task_handle = NULL; 364 | } 365 | 366 | ///////////////////////////////////////////// 367 | 368 | /* 369 | static void _stop_async_task(){ 370 | if(_async_service_task_handle){ 371 | vTaskDelete(_async_service_task_handle); 372 | _async_service_task_handle = NULL; 373 | } 374 | } 375 | */ 376 | 377 | ///////////////////////////////////////////// 378 | 379 | static bool _start_async_task() 380 | { 381 | if (!_init_async_event_queue()) 382 | { 383 | return false; 384 | } 385 | 386 | if (!_async_service_task_handle) 387 | { 388 | xTaskCreateUniversal(_async_service_task, "async_tcp_ssl", CONFIG_ASYNC_TCP_STACK, NULL, CONFIG_ASYNC_TCP_PRIORITY, 389 | &_async_service_task_handle, CONFIG_ASYNC_TCP_RUNNING_CORE); 390 | 391 | if (!_async_service_task_handle) 392 | { 393 | return false; 394 | } 395 | } 396 | 397 | return true; 398 | } 399 | 400 | ///////////////////////////////////////////// 401 | 402 | /* 403 | LwIP Callbacks 404 | 405 | The following "_tcp_*" functions are called by LwIP on its thread. They all do nothing but 406 | package the callback info into an event, which is queued for the async event task (see above). 407 | * */ 408 | 409 | static int8_t _tcp_clear_events(void * arg) 410 | { 411 | lwip_event_packet_t * e = (lwip_event_packet_t *) malloc(sizeof(lwip_event_packet_t)); 412 | e->event = LWIP_TCP_CLEAR; 413 | e->arg = arg; 414 | 415 | if (!_prepend_async_event(&e)) 416 | { 417 | free((void*)(e)); 418 | } 419 | 420 | return ERR_OK; 421 | } 422 | 423 | ///////////////////////////////////////////// 424 | 425 | static int8_t _tcp_connected(void * arg, tcp_pcb * pcb, int8_t err) 426 | { 427 | ATCP_HEXLOGDEBUG1("_tcp_connected: pcb =", (uint32_t) pcb); 428 | 429 | lwip_event_packet_t * e = (lwip_event_packet_t *) malloc(sizeof(lwip_event_packet_t)); 430 | e->event = LWIP_TCP_CONNECTED; 431 | e->arg = arg; 432 | e->connected.pcb = pcb; 433 | e->connected.err = err; 434 | 435 | if (!_prepend_async_event(&e)) 436 | { 437 | free((void*)(e)); 438 | } 439 | 440 | return ERR_OK; 441 | } 442 | 443 | ///////////////////////////////////////////// 444 | 445 | static int8_t _tcp_poll(void * arg, struct tcp_pcb * pcb) 446 | { 447 | ATCP_HEXLOGDEBUG1("_tcp_poll: pcb =", (uint32_t) pcb); 448 | 449 | lwip_event_packet_t * e = (lwip_event_packet_t *) malloc(sizeof(lwip_event_packet_t)); 450 | e->event = LWIP_TCP_POLL; 451 | e->arg = arg; 452 | e->poll.pcb = pcb; 453 | 454 | if (!_send_async_event(&e)) 455 | { 456 | free((void*)(e)); 457 | } 458 | 459 | return ERR_OK; 460 | } 461 | 462 | ///////////////////////////////////////////// 463 | 464 | static int8_t _tcp_recv(void * arg, struct tcp_pcb * pcb, struct pbuf *pb, int8_t err) 465 | { 466 | lwip_event_packet_t * e = (lwip_event_packet_t *) malloc(sizeof(lwip_event_packet_t)); 467 | e->arg = arg; 468 | 469 | if (pb) 470 | { 471 | ATCP_HEXLOGDEBUG1("_tcp_recv: pcb =", (uint32_t) pcb); 472 | 473 | e->event = LWIP_TCP_RECV; 474 | e->recv.pcb = pcb; 475 | e->recv.pb = pb; 476 | e->recv.err = err; 477 | } 478 | else 479 | { 480 | ATCP_HEXLOGDEBUG1("_tcp_recv: failed, pcb =", (uint32_t) pcb); 481 | 482 | e->event = LWIP_TCP_FIN; 483 | e->fin.pcb = pcb; 484 | e->fin.err = err; 485 | //close the PCB in LwIP thread 486 | AsyncSSLClient::_s_lwip_fin(e->arg, e->fin.pcb, e->fin.err); 487 | } 488 | 489 | if (!_send_async_event(&e)) 490 | { 491 | free((void*)(e)); 492 | } 493 | 494 | return ERR_OK; 495 | } 496 | 497 | ///////////////////////////////////////////// 498 | 499 | static int8_t _tcp_sent(void * arg, struct tcp_pcb * pcb, uint16_t len) 500 | { 501 | ATCP_HEXLOGDEBUG1("_tcp_sent: pcb =", (uint32_t) pcb); 502 | 503 | lwip_event_packet_t * e = (lwip_event_packet_t *) malloc(sizeof(lwip_event_packet_t)); 504 | e->event = LWIP_TCP_SENT; 505 | e->arg = arg; 506 | e->sent.pcb = pcb; 507 | e->sent.len = len; 508 | 509 | if (!_send_async_event(&e)) 510 | { 511 | free((void*)(e)); 512 | } 513 | 514 | return ERR_OK; 515 | } 516 | 517 | ///////////////////////////////////////////// 518 | 519 | static void _tcp_error(void * arg, int8_t err) 520 | { 521 | ATCP_HEXLOGDEBUG1("_tcp_error: arg =", (uint32_t) arg); 522 | 523 | lwip_event_packet_t * e = (lwip_event_packet_t *) malloc(sizeof(lwip_event_packet_t)); 524 | e->event = LWIP_TCP_ERROR; 525 | e->arg = arg; 526 | e->error.err = err; 527 | 528 | if (!_send_async_event(&e)) 529 | { 530 | free((void*)(e)); 531 | } 532 | } 533 | 534 | ///////////////////////////////////////////// 535 | 536 | static void _tcp_dns_found(const char * name, struct ip_addr * ipaddr, void * arg) 537 | { 538 | lwip_event_packet_t * e = (lwip_event_packet_t *) malloc(sizeof(lwip_event_packet_t)); 539 | 540 | ATCP_LOGDEBUG3("_tcp_dns_found: name =", name, ", IP =", ipaddr_ntoa(ipaddr)); 541 | ATCP_HEXLOGDEBUG1("_tcp_dns_found: arg =", (uint32_t) arg); 542 | 543 | e->event = LWIP_TCP_DNS; 544 | e->arg = arg; 545 | e->dns.name = name; 546 | 547 | if (ipaddr) 548 | { 549 | memcpy(&e->dns.addr, ipaddr, sizeof(struct ip_addr)); 550 | } 551 | else 552 | { 553 | memset(&e->dns.addr, 0, sizeof(e->dns.addr)); 554 | } 555 | 556 | if (!_send_async_event(&e)) 557 | { 558 | free((void*)(e)); 559 | } 560 | } 561 | 562 | ///////////////////////////////////////////// 563 | 564 | //Used to switch out from LwIP thread 565 | static int8_t _tcp_accept(void * arg, AsyncSSLClient * client) 566 | { 567 | lwip_event_packet_t * e = (lwip_event_packet_t *) malloc(sizeof(lwip_event_packet_t)); 568 | e->event = LWIP_TCP_ACCEPT; 569 | e->arg = arg; 570 | e->accept.client = client; 571 | 572 | if (!_prepend_async_event(&e)) 573 | { 574 | free((void*)(e)); 575 | 576 | // KH Test Memory Leak 577 | if (client) 578 | { 579 | ATCP_LOGDEBUG("AsyncTCP_SSL: _tcp_accept: Delete Client"); 580 | delete (client); 581 | client = nullptr; 582 | } 583 | 584 | ////// 585 | } 586 | 587 | return ERR_OK; 588 | } 589 | 590 | ////////////////////////////////////////////////////////////////////////////////////////// 591 | 592 | /* 593 | TCP/IP API Calls 594 | 595 | The following functions provide stubs to call into LwIP's TCP api functions on the LwIP thread 596 | itself. This ensures there are no race conditions between the application and LwIP. 597 | The way it works is that the `_tcp_xxx` functions synchronously call the corresponding 598 | `_tcp_xxx_api` functions on the LwIP thread using a `tcp_api_call` mechanism provided by LwIP. 599 | The `_tcp_xxx_api` function then finally calls the actual `tcp_xxx` function in LwIP and returns 600 | the result. 601 | * */ 602 | 603 | #include "lwip/priv/tcpip_priv.h" 604 | 605 | typedef struct 606 | { 607 | struct tcpip_api_call_data call; 608 | tcp_pcb * pcb; 609 | int8_t closed_slot; 610 | int8_t err; 611 | 612 | union 613 | { 614 | struct 615 | { 616 | const char* data; 617 | size_t size; 618 | uint8_t apiflags; 619 | } write; 620 | 621 | size_t received; 622 | 623 | struct 624 | { 625 | ip_addr_t * addr; 626 | uint16_t port; 627 | tcp_connected_fn cb; 628 | } connect; 629 | 630 | struct 631 | { 632 | ip_addr_t * addr; 633 | uint16_t port; 634 | } bind; 635 | 636 | uint8_t backlog; 637 | }; 638 | } tcp_api_call_t; 639 | 640 | ///////////////////////////////////////////// 641 | 642 | static err_t _tcp_output_api(struct tcpip_api_call_data *api_call_msg) 643 | { 644 | tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; 645 | 646 | msg->err = ERR_CONN; 647 | 648 | if (msg->closed_slot == INVALID_CLOSED_SLOT || !_closed_slots[msg->closed_slot]) 649 | { 650 | msg->err = tcp_output(msg->pcb); 651 | } 652 | 653 | return msg->err; 654 | } 655 | 656 | ///////////////////////////////////////////// 657 | 658 | static esp_err_t _tcp_output(tcp_pcb * pcb, int8_t closed_slot) 659 | { 660 | if (!pcb) 661 | { 662 | return ERR_CONN; 663 | } 664 | 665 | tcp_api_call_t msg; 666 | 667 | msg.pcb = pcb; 668 | msg.closed_slot = closed_slot; 669 | 670 | tcpip_api_call(_tcp_output_api, (struct tcpip_api_call_data*)&msg); 671 | 672 | return msg.err; 673 | } 674 | 675 | ///////////////////////////////////////////// 676 | 677 | static err_t _tcp_write_api(struct tcpip_api_call_data *api_call_msg) 678 | { 679 | tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; 680 | 681 | msg->err = ERR_CONN; 682 | 683 | if (msg->closed_slot == INVALID_CLOSED_SLOT || !_closed_slots[msg->closed_slot]) 684 | { 685 | msg->err = tcp_write(msg->pcb, msg->write.data, msg->write.size, msg->write.apiflags); 686 | } 687 | 688 | return msg->err; 689 | } 690 | 691 | ///////////////////////////////////////////// 692 | 693 | static esp_err_t _tcp_write(tcp_pcb * pcb, int8_t closed_slot, const char* data, size_t size, uint8_t apiflags) 694 | { 695 | if (!pcb) 696 | { 697 | return ERR_CONN; 698 | } 699 | 700 | tcp_api_call_t msg; 701 | 702 | msg.pcb = pcb; 703 | msg.closed_slot = closed_slot; 704 | msg.write.data = data; 705 | msg.write.size = size; 706 | msg.write.apiflags = apiflags; 707 | 708 | tcpip_api_call(_tcp_write_api, (struct tcpip_api_call_data*)&msg); 709 | 710 | return msg.err; 711 | } 712 | 713 | ///////////////////////////////////////////// 714 | 715 | static err_t _tcp_recved_api(struct tcpip_api_call_data *api_call_msg) 716 | { 717 | tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; 718 | 719 | msg->err = ERR_CONN; 720 | 721 | if (msg->closed_slot == INVALID_CLOSED_SLOT || !_closed_slots[msg->closed_slot]) 722 | { 723 | msg->err = 0; 724 | 725 | tcp_recved(msg->pcb, msg->received); 726 | } 727 | 728 | return msg->err; 729 | } 730 | 731 | ///////////////////////////////////////////// 732 | 733 | static esp_err_t _tcp_recved(tcp_pcb * pcb, int8_t closed_slot, size_t len) 734 | { 735 | if (!pcb) 736 | { 737 | return ERR_CONN; 738 | } 739 | 740 | tcp_api_call_t msg; 741 | 742 | msg.pcb = pcb; 743 | msg.closed_slot = closed_slot; 744 | msg.received = len; 745 | 746 | tcpip_api_call(_tcp_recved_api, (struct tcpip_api_call_data*)&msg); 747 | 748 | return msg.err; 749 | } 750 | 751 | ///////////////////////////////////////////// 752 | 753 | static err_t _tcp_close_api(struct tcpip_api_call_data *api_call_msg) 754 | { 755 | tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; 756 | 757 | msg->err = ERR_CONN; 758 | 759 | if (msg->closed_slot == INVALID_CLOSED_SLOT || !_closed_slots[msg->closed_slot]) 760 | { 761 | msg->err = tcp_close(msg->pcb); 762 | } 763 | 764 | return msg->err; 765 | } 766 | 767 | ///////////////////////////////////////////// 768 | 769 | static esp_err_t _tcp_close(tcp_pcb * pcb, int8_t closed_slot) 770 | { 771 | if (!pcb) 772 | { 773 | return ERR_CONN; 774 | } 775 | 776 | tcp_api_call_t msg; 777 | 778 | msg.pcb = pcb; 779 | msg.closed_slot = closed_slot; 780 | 781 | tcpip_api_call(_tcp_close_api, (struct tcpip_api_call_data*)&msg); 782 | 783 | return msg.err; 784 | } 785 | 786 | ///////////////////////////////////////////// 787 | 788 | static err_t _tcp_abort_api(struct tcpip_api_call_data *api_call_msg) 789 | { 790 | tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; 791 | 792 | msg->err = ERR_CONN; 793 | 794 | if (msg->closed_slot == INVALID_CLOSED_SLOT || !_closed_slots[msg->closed_slot]) 795 | { 796 | tcp_abort(msg->pcb); 797 | } 798 | 799 | return msg->err; 800 | } 801 | 802 | ///////////////////////////////////////////// 803 | 804 | static esp_err_t _tcp_abort(tcp_pcb * pcb, int8_t closed_slot) 805 | { 806 | if (!pcb) 807 | { 808 | return ERR_CONN; 809 | } 810 | 811 | tcp_api_call_t msg; 812 | 813 | msg.pcb = pcb; 814 | msg.closed_slot = closed_slot; 815 | 816 | tcpip_api_call(_tcp_abort_api, (struct tcpip_api_call_data*)&msg); 817 | 818 | return msg.err; 819 | } 820 | 821 | ///////////////////////////////////////////// 822 | 823 | static err_t _tcp_connect_api(struct tcpip_api_call_data *api_call_msg) 824 | { 825 | tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; 826 | 827 | msg->err = tcp_connect(msg->pcb, msg->connect.addr, msg->connect.port, msg->connect.cb); 828 | 829 | return msg->err; 830 | } 831 | 832 | ///////////////////////////////////////////// 833 | 834 | static esp_err_t _tcp_connect(tcp_pcb * pcb, int8_t closed_slot, ip_addr_t * addr, uint16_t port, tcp_connected_fn cb) 835 | { 836 | if (!pcb) 837 | { 838 | return ESP_FAIL; 839 | } 840 | 841 | tcp_api_call_t msg; 842 | 843 | msg.pcb = pcb; 844 | msg.closed_slot = closed_slot; 845 | msg.connect.addr = addr; 846 | msg.connect.port = port; 847 | msg.connect.cb = cb; 848 | 849 | tcpip_api_call(_tcp_connect_api, (struct tcpip_api_call_data*)&msg); 850 | 851 | return msg.err; 852 | } 853 | 854 | ///////////////////////////////////////////// 855 | 856 | static err_t _tcp_bind_api(struct tcpip_api_call_data *api_call_msg) 857 | { 858 | tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; 859 | 860 | msg->err = tcp_bind(msg->pcb, msg->bind.addr, msg->bind.port); 861 | 862 | return msg->err; 863 | } 864 | 865 | ///////////////////////////////////////////// 866 | 867 | static esp_err_t _tcp_bind(tcp_pcb * pcb, ip_addr_t * addr, uint16_t port) 868 | { 869 | if (!pcb) 870 | { 871 | return ESP_FAIL; 872 | } 873 | 874 | tcp_api_call_t msg; 875 | 876 | msg.pcb = pcb; 877 | msg.closed_slot = INVALID_CLOSED_SLOT; 878 | msg.bind.addr = addr; 879 | msg.bind.port = port; 880 | 881 | tcpip_api_call(_tcp_bind_api, (struct tcpip_api_call_data*)&msg); 882 | 883 | return msg.err; 884 | } 885 | 886 | ///////////////////////////////////////////// 887 | 888 | static err_t _tcp_listen_api(struct tcpip_api_call_data *api_call_msg) 889 | { 890 | tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; 891 | 892 | msg->err = 0; 893 | 894 | msg->pcb = tcp_listen_with_backlog(msg->pcb, msg->backlog); 895 | 896 | return msg->err; 897 | } 898 | 899 | ///////////////////////////////////////////// 900 | 901 | static tcp_pcb * _tcp_listen_with_backlog(tcp_pcb * pcb, uint8_t backlog) 902 | { 903 | if (!pcb) 904 | { 905 | return NULL; 906 | } 907 | 908 | tcp_api_call_t msg; 909 | 910 | msg.pcb = pcb; 911 | msg.closed_slot = INVALID_CLOSED_SLOT; 912 | msg.backlog = backlog ? backlog : 0xFF; 913 | 914 | tcpip_api_call(_tcp_listen_api, (struct tcpip_api_call_data*)&msg); 915 | 916 | return msg.pcb; 917 | } 918 | 919 | ///////////////////////////////////////////// 920 | 921 | // KH 922 | extern "C" 923 | { 924 | // The following API stubs are for use in tcp_mbedtls.c 925 | // They are callable from C and take a void* instead of an AsyncSSLClient*. 926 | 927 | esp_err_t _tcp_output4ssl(tcp_pcb * pcb, void* client) 928 | { 929 | // KH 930 | return _tcp_output(pcb, (reinterpret_cast (client) )->getClosed_Slot() ); 931 | ////// 932 | } 933 | 934 | esp_err_t _tcp_write4ssl(tcp_pcb * pcb, const char* data, size_t size, uint8_t apiflags, void* client) 935 | { 936 | // KH 937 | return _tcp_write(pcb, (reinterpret_cast (client) )->getClosed_Slot(), data, size, apiflags); 938 | ////// 939 | } 940 | 941 | } 942 | 943 | ////////////////////////////////////////////////////////////////////////////////////// 944 | 945 | /* 946 | Async TCP Client 947 | */ 948 | 949 | AsyncSSLClient::AsyncSSLClient(tcp_pcb* pcb) 950 | : _connect_cb(0) 951 | , _connect_cb_arg(0) 952 | , _discard_cb(0) 953 | , _discard_cb_arg(0) 954 | , _sent_cb(0) 955 | , _sent_cb_arg(0) 956 | , _error_cb(0) 957 | , _error_cb_arg(0) 958 | , _recv_cb(0) 959 | , _recv_cb_arg(0) 960 | , _pb_cb(0) 961 | , _pb_cb_arg(0) 962 | , _timeout_cb(0) 963 | , _timeout_cb_arg(0) 964 | , _pcb_busy(false) 965 | , _pcb_sent_at(0) 966 | , _ack_pcb(true) 967 | , _rx_last_packet(0) 968 | , _rx_since_timeout(0) 969 | , _ack_timeout(ASYNC_MAX_ACK_TIME) 970 | , _connect_port(0) 971 | // SSL 972 | , _root_ca_len(0) 973 | , _root_ca(NULL) 974 | , _cli_cert_len(0) 975 | , _cli_cert(NULL) 976 | , _cli_key_len(0) 977 | , _cli_key(NULL) 978 | , _pcb_secure(false) 979 | , _handshake_done(true) 980 | , _psk_ident(0) 981 | , _psk(0) 982 | ////// 983 | , prev(NULL) 984 | , next(NULL) 985 | { 986 | _pcb = pcb; 987 | _closed_slot = INVALID_CLOSED_SLOT; 988 | 989 | if (_pcb) 990 | { 991 | _allocate_closed_slot(); 992 | _rx_last_packet = millis(); 993 | tcp_arg(_pcb, this); 994 | tcp_recv(_pcb, &_tcp_recv); 995 | tcp_sent(_pcb, &_tcp_sent); 996 | tcp_err(_pcb, &_tcp_error); 997 | tcp_poll(_pcb, &_tcp_poll, 1); 998 | } 999 | } 1000 | 1001 | ///////////////////////////////////////////// 1002 | 1003 | AsyncSSLClient::~AsyncSSLClient() 1004 | { 1005 | if (_pcb) 1006 | { 1007 | _close(); 1008 | } 1009 | 1010 | _free_closed_slot(); 1011 | } 1012 | 1013 | ////////////////////////////////////////////////////////////////////////////////////////// 1014 | 1015 | /* 1016 | Operators 1017 | * */ 1018 | 1019 | AsyncSSLClient& AsyncSSLClient::operator=(const AsyncSSLClient& other) 1020 | { 1021 | if (_pcb) 1022 | { 1023 | _close(); 1024 | } 1025 | 1026 | _pcb = other._pcb; 1027 | _closed_slot = other._closed_slot; 1028 | 1029 | if (_pcb) 1030 | { 1031 | _rx_last_packet = millis(); 1032 | tcp_arg(_pcb, this); 1033 | tcp_recv(_pcb, &_tcp_recv); 1034 | tcp_sent(_pcb, &_tcp_sent); 1035 | tcp_err(_pcb, &_tcp_error); 1036 | tcp_poll(_pcb, &_tcp_poll, 1); 1037 | 1038 | // SSL 1039 | if (tcp_ssl_has(_pcb)) 1040 | { 1041 | _pcb_secure = true; 1042 | _handshake_done = false; 1043 | 1044 | tcp_ssl_arg(_pcb, this); 1045 | tcp_ssl_data(_pcb, &_s_data); 1046 | tcp_ssl_handshake(_pcb, &_s_handshake); 1047 | tcp_ssl_err(_pcb, &_s_ssl_error); 1048 | } 1049 | else 1050 | { 1051 | _pcb_secure = false; 1052 | _handshake_done = true; 1053 | } 1054 | 1055 | ////// 1056 | } 1057 | 1058 | return *this; 1059 | } 1060 | 1061 | ///////////////////////////////////////////// 1062 | 1063 | bool AsyncSSLClient::operator==(const AsyncSSLClient &other) 1064 | { 1065 | return (_pcb == other._pcb); 1066 | } 1067 | 1068 | ///////////////////////////////////////////// 1069 | 1070 | AsyncSSLClient & AsyncSSLClient::operator+=(const AsyncSSLClient &other) 1071 | { 1072 | if (next == NULL) 1073 | { 1074 | next = (AsyncSSLClient*)(&other); 1075 | next->prev = this; 1076 | } 1077 | else 1078 | { 1079 | AsyncSSLClient *c = next; 1080 | 1081 | while (c->next != NULL) 1082 | { 1083 | c = c->next; 1084 | } 1085 | 1086 | c->next = (AsyncSSLClient*)(&other); 1087 | c->next->prev = c; 1088 | } 1089 | 1090 | return *this; 1091 | } 1092 | 1093 | ////////////////////////////////////////////////////////////////////////////////////////// 1094 | 1095 | /* 1096 | Callback Setters 1097 | * */ 1098 | 1099 | void AsyncSSLClient::onConnect(AcConnectHandlerSSL cb, void* arg) 1100 | { 1101 | _connect_cb = cb; 1102 | _connect_cb_arg = arg; 1103 | } 1104 | 1105 | ///////////////////////////////////////////// 1106 | 1107 | void AsyncSSLClient::onDisconnect(AcConnectHandlerSSL cb, void* arg) 1108 | { 1109 | _discard_cb = cb; 1110 | _discard_cb_arg = arg; 1111 | } 1112 | 1113 | ///////////////////////////////////////////// 1114 | 1115 | void AsyncSSLClient::onAck(AcAckHandlerSSL cb, void* arg) 1116 | { 1117 | _sent_cb = cb; 1118 | _sent_cb_arg = arg; 1119 | } 1120 | 1121 | ///////////////////////////////////////////// 1122 | 1123 | void AsyncSSLClient::onError(AcErrorHandlerSSL cb, void* arg) 1124 | { 1125 | _error_cb = cb; 1126 | _error_cb_arg = arg; 1127 | } 1128 | 1129 | ///////////////////////////////////////////// 1130 | 1131 | void AsyncSSLClient::onData(AcDataHandlerSSL cb, void* arg) 1132 | { 1133 | _recv_cb = cb; 1134 | _recv_cb_arg = arg; 1135 | } 1136 | 1137 | ///////////////////////////////////////////// 1138 | 1139 | void AsyncSSLClient::onPacket(AcPacketHandlerSSL cb, void* arg) 1140 | { 1141 | _pb_cb = cb; 1142 | _pb_cb_arg = arg; 1143 | } 1144 | 1145 | ///////////////////////////////////////////// 1146 | 1147 | void AsyncSSLClient::onTimeout(AcTimeoutHandlerSSL cb, void* arg) 1148 | { 1149 | _timeout_cb = cb; 1150 | _timeout_cb_arg = arg; 1151 | } 1152 | 1153 | ///////////////////////////////////////////// 1154 | 1155 | void AsyncSSLClient::onPoll(AcConnectHandlerSSL cb, void* arg) 1156 | { 1157 | _poll_cb = cb; 1158 | _poll_cb_arg = arg; 1159 | } 1160 | 1161 | ////////////////////////////////////////////////////////////////////////////////////////// 1162 | 1163 | /* 1164 | Main Public Methods 1165 | * */ 1166 | 1167 | bool AsyncSSLClient::connect(IPAddress ip, uint16_t port, bool secure) 1168 | { 1169 | if (_pcb) 1170 | { 1171 | ATCP_LOGWARN1("connect: already connected, state =", stateToString()); 1172 | 1173 | return false; 1174 | } 1175 | 1176 | if (!_start_async_task()) 1177 | { 1178 | ATCP_LOGERROR("connect: failed to start task"); 1179 | 1180 | return false; 1181 | } 1182 | 1183 | ip_addr_t addr; 1184 | addr.type = IPADDR_TYPE_V4; 1185 | addr.u_addr.ip4.addr = ip; 1186 | 1187 | tcp_pcb* pcb = tcp_new_ip_type(IPADDR_TYPE_V4); 1188 | 1189 | if (!pcb) 1190 | { 1191 | ATCP_LOGERROR("connect: NULL pcb"); 1192 | 1193 | return false; 1194 | } 1195 | 1196 | // SSL 1197 | _pcb_secure = secure; 1198 | _handshake_done = !secure; 1199 | ////// 1200 | 1201 | tcp_arg(pcb, this); 1202 | tcp_err(pcb, &_tcp_error); 1203 | tcp_recv(pcb, &_tcp_recv); 1204 | tcp_sent(pcb, &_tcp_sent); 1205 | tcp_poll(pcb, &_tcp_poll, 1); 1206 | 1207 | _tcp_connect(pcb, _closed_slot, &addr, port, (tcp_connected_fn)&_tcp_connected); 1208 | 1209 | return true; 1210 | } 1211 | 1212 | ///////////////////////////////////////////// 1213 | 1214 | bool AsyncSSLClient::connect(const char* host, uint16_t port, bool secure) 1215 | { 1216 | ip_addr_t addr; 1217 | 1218 | if (!_start_async_task()) 1219 | { 1220 | ATCP_LOGERROR("connect: failed to start task"); 1221 | 1222 | return false; 1223 | } 1224 | 1225 | err_t err = dns_gethostbyname(host, &addr, (dns_found_callback)&_tcp_dns_found, this); 1226 | 1227 | if (err == ERR_OK) 1228 | { 1229 | _hostname = host; 1230 | 1231 | return connect(IPAddress(addr.u_addr.ip4.addr), port, secure); 1232 | } 1233 | else if (err == ERR_INPROGRESS) 1234 | { 1235 | _connect_port = port; 1236 | 1237 | _hostname = host; 1238 | _pcb_secure = secure; 1239 | _handshake_done = !secure; 1240 | 1241 | return true; 1242 | } 1243 | 1244 | ATCP_LOGERROR1("connect: error =", err); 1245 | 1246 | return false; 1247 | } 1248 | 1249 | ///////////////////////////////////////////// 1250 | 1251 | void AsyncSSLClient::close(bool now) 1252 | { 1253 | if (_pcb) 1254 | { 1255 | _tcp_recved(_pcb, _closed_slot, _rx_ack_len); 1256 | } 1257 | 1258 | _close(); 1259 | } 1260 | 1261 | ///////////////////////////////////////////// 1262 | 1263 | int8_t AsyncSSLClient::abort() 1264 | { 1265 | if (_pcb) 1266 | { 1267 | _tcp_abort(_pcb, _closed_slot ); 1268 | _pcb = NULL; 1269 | } 1270 | 1271 | return ERR_ABRT; 1272 | } 1273 | 1274 | ///////////////////////////////////////////// 1275 | 1276 | void AsyncSSLClient::setRootCa(const char* rootca, const size_t len) 1277 | { 1278 | _root_ca = (char*)rootca; 1279 | _root_ca_len = len; 1280 | } 1281 | 1282 | ///////////////////////////////////////////// 1283 | 1284 | void AsyncSSLClient::setClientCert(const char* cli_cert, const size_t len) 1285 | { 1286 | _cli_cert = (char*)cli_cert; 1287 | _cli_cert_len = len; 1288 | } 1289 | 1290 | ///////////////////////////////////////////// 1291 | 1292 | void AsyncSSLClient::setClientKey(const char* cli_key, const size_t len) 1293 | { 1294 | _cli_key = (char*)cli_key; 1295 | _cli_key_len = len; 1296 | } 1297 | 1298 | ///////////////////////////////////////////// 1299 | 1300 | void AsyncSSLClient::setPsk(const char* psk_ident, const char* psk) 1301 | { 1302 | _psk_ident = psk_ident; 1303 | _psk = psk; 1304 | } 1305 | 1306 | 1307 | ///////////////////////////////////////////// 1308 | 1309 | size_t AsyncSSLClient::space() 1310 | { 1311 | if ((_pcb != NULL) && (_pcb->state == ESTABLISHED)) 1312 | { 1313 | return tcp_sndbuf(_pcb); 1314 | } 1315 | 1316 | return 0; 1317 | } 1318 | 1319 | ///////////////////////////////////////////// 1320 | 1321 | size_t AsyncSSLClient::add(const char* data, size_t size, uint8_t apiflags) 1322 | { 1323 | if (!_pcb || size == 0 || data == NULL) 1324 | { 1325 | return 0; 1326 | } 1327 | 1328 | size_t room = space(); 1329 | 1330 | if (!room) 1331 | { 1332 | return 0; 1333 | } 1334 | 1335 | if (_pcb_secure) 1336 | { 1337 | int sent = tcp_ssl_write(_pcb, (uint8_t*)data, size); 1338 | 1339 | ASYNC_TCP_SSL_DEBUG("add() tcp_ssl_write size = %d\n", sent); 1340 | 1341 | if (sent >= 0) 1342 | { 1343 | // @ToDo: ??? 1344 | //_tx_unacked_len += sent; 1345 | return sent; 1346 | } 1347 | 1348 | ATCP_LOGINFO1("add() done, tcp_ssl_write size =", sent); 1349 | 1350 | _close(); 1351 | 1352 | return 0; 1353 | } 1354 | 1355 | size_t will_send = (room < size) ? room : size; 1356 | 1357 | int8_t err = ERR_OK; 1358 | 1359 | err = _tcp_write(_pcb, _closed_slot, data, will_send, apiflags); 1360 | 1361 | if (err != ERR_OK) 1362 | { 1363 | return 0; 1364 | } 1365 | 1366 | return will_send; 1367 | } 1368 | 1369 | ///////////////////////////////////////////// 1370 | 1371 | bool AsyncSSLClient::send() 1372 | { 1373 | // 5 is also OK 1374 | vTaskDelay(1 / portTICK_PERIOD_MS); 1375 | 1376 | int8_t err = ERR_OK; 1377 | 1378 | err = _tcp_output(_pcb, _closed_slot); 1379 | 1380 | if (err == ERR_OK) 1381 | { 1382 | _pcb_busy = true; 1383 | _pcb_sent_at = millis(); 1384 | 1385 | return true; 1386 | } 1387 | 1388 | return false; 1389 | } 1390 | 1391 | ///////////////////////////////////////////// 1392 | 1393 | size_t AsyncSSLClient::ack(size_t len) 1394 | { 1395 | if (len > _rx_ack_len) 1396 | len = _rx_ack_len; 1397 | 1398 | if (len) 1399 | { 1400 | _tcp_recved(_pcb, _closed_slot, len); 1401 | } 1402 | 1403 | _rx_ack_len -= len; 1404 | 1405 | return len; 1406 | } 1407 | 1408 | ///////////////////////////////////////////// 1409 | 1410 | void AsyncSSLClient::ackPacket(struct pbuf * pb) 1411 | { 1412 | if (!pb) 1413 | { 1414 | return; 1415 | } 1416 | 1417 | _tcp_recved(_pcb, _closed_slot, pb->len); 1418 | pbuf_free(pb); 1419 | } 1420 | 1421 | ////////////////////////////////////////////////////////////////////////////////////////// 1422 | 1423 | /* 1424 | Main Private Methods 1425 | * */ 1426 | 1427 | int8_t AsyncSSLClient::_close() 1428 | { 1429 | int8_t err = ERR_OK; 1430 | 1431 | if (_pcb) 1432 | { 1433 | if (_pcb_secure) 1434 | { 1435 | tcp_ssl_free(_pcb); 1436 | } 1437 | 1438 | tcp_arg(_pcb, NULL); 1439 | tcp_sent(_pcb, NULL); 1440 | tcp_recv(_pcb, NULL); 1441 | tcp_err(_pcb, NULL); 1442 | tcp_poll(_pcb, NULL, 0); 1443 | 1444 | _tcp_clear_events(this); 1445 | 1446 | err = _tcp_close(_pcb, _closed_slot); 1447 | 1448 | if (err != ERR_OK) 1449 | { 1450 | err = abort(); 1451 | } 1452 | 1453 | _pcb = NULL; 1454 | 1455 | if (_discard_cb) 1456 | { 1457 | _discard_cb(_discard_cb_arg, this); 1458 | } 1459 | } 1460 | 1461 | return err; 1462 | } 1463 | 1464 | ///////////////////////////////////////////// 1465 | 1466 | void AsyncSSLClient::_allocate_closed_slot() 1467 | { 1468 | xSemaphoreTake(_slots_lock, portMAX_DELAY); 1469 | 1470 | uint32_t closed_slot_min_index = 0; 1471 | 1472 | for (int i = 0; i < _number_of_closed_slots; ++ i) 1473 | { 1474 | if ((_closed_slot == INVALID_CLOSED_SLOT || _closed_slots[i] <= closed_slot_min_index) && _closed_slots[i] != 0) 1475 | { 1476 | closed_slot_min_index = _closed_slots[i]; 1477 | _closed_slot = i; 1478 | } 1479 | } 1480 | 1481 | if (_closed_slot != INVALID_CLOSED_SLOT) 1482 | { 1483 | _closed_slots[_closed_slot] = 0; 1484 | } 1485 | 1486 | xSemaphoreGive(_slots_lock); 1487 | } 1488 | 1489 | ///////////////////////////////////////////// 1490 | 1491 | void AsyncSSLClient::_free_closed_slot() 1492 | { 1493 | if (_closed_slot != INVALID_CLOSED_SLOT) 1494 | { 1495 | _closed_slots[_closed_slot] = _closed_index; 1496 | _closed_slot = INVALID_CLOSED_SLOT; 1497 | _closed_index++; 1498 | } 1499 | } 1500 | 1501 | ////////////////////////////////////////////////////////////////////////////////////////// 1502 | 1503 | /* 1504 | Private Callbacks 1505 | * */ 1506 | 1507 | int8_t AsyncSSLClient::_connected(void* pcb, int8_t err) 1508 | { 1509 | _pcb = reinterpret_cast(pcb); 1510 | 1511 | if (_pcb) 1512 | { 1513 | _rx_last_packet = millis(); 1514 | _pcb_busy = false; 1515 | 1516 | if (_pcb_secure) 1517 | { 1518 | bool err = false; 1519 | 1520 | if (_psk_ident != NULL and _psk != NULL) 1521 | { 1522 | err = tcp_ssl_new_psk_client(_pcb, this, _psk_ident, _psk) < 0; 1523 | } 1524 | else 1525 | { 1526 | err = tcp_ssl_new_client(_pcb, this, _hostname.empty() ? NULL : _hostname.c_str(), 1527 | _root_ca, _root_ca_len, _cli_cert, _cli_cert_len, _cli_key, _cli_key_len) < 0; 1528 | } 1529 | 1530 | if (err) 1531 | { 1532 | ATCP_LOGERROR("_connected: error => closing"); 1533 | 1534 | return _close(); 1535 | } 1536 | 1537 | tcp_ssl_data(_pcb, &_s_data); 1538 | tcp_ssl_handshake(_pcb, &_s_handshake); 1539 | tcp_ssl_err(_pcb, &_s_ssl_error); 1540 | } 1541 | } 1542 | 1543 | // _connect_cb happens after SSL handshake if this is a secure connection 1544 | if (_connect_cb && !_pcb_secure) 1545 | { 1546 | _connect_cb(_connect_cb_arg, this); 1547 | } 1548 | 1549 | return ERR_OK; 1550 | } 1551 | 1552 | ///////////////////////////////////////////// 1553 | 1554 | void AsyncSSLClient::_error(int8_t err) 1555 | { 1556 | if (_pcb) 1557 | { 1558 | if (_pcb_secure) 1559 | { 1560 | tcp_ssl_free(_pcb); 1561 | } 1562 | 1563 | tcp_arg(_pcb, NULL); 1564 | 1565 | if (_pcb->state == LISTEN) 1566 | { 1567 | tcp_sent(_pcb, NULL); 1568 | tcp_recv(_pcb, NULL); 1569 | tcp_err(_pcb, NULL); 1570 | tcp_poll(_pcb, NULL, 0); 1571 | } 1572 | 1573 | _pcb = NULL; 1574 | } 1575 | 1576 | if (_error_cb) 1577 | { 1578 | _error_cb(_error_cb_arg, this, err); 1579 | } 1580 | 1581 | if (_discard_cb) 1582 | { 1583 | _discard_cb(_discard_cb_arg, this); 1584 | } 1585 | } 1586 | 1587 | ///////////////////////////////////////////// 1588 | 1589 | void AsyncSSLClient::_ssl_error(int8_t err) 1590 | { 1591 | if (_error_cb) 1592 | { 1593 | _error_cb(_error_cb_arg, this, err + 64); 1594 | } 1595 | } 1596 | 1597 | ///////////////////////////////////////////// 1598 | 1599 | //In LwIP Thread 1600 | int8_t AsyncSSLClient::_lwip_fin(tcp_pcb* pcb, int8_t err) 1601 | { 1602 | if (!_pcb || pcb != _pcb) 1603 | { 1604 | ATCP_HEXLOGDEBUG2("_lwip_fin: pcb/_pcb =", (uint32_t)pcb, (uint32_t)_pcb); 1605 | 1606 | return ERR_OK; 1607 | } 1608 | 1609 | tcp_arg(_pcb, NULL); 1610 | 1611 | if (_pcb->state == LISTEN) 1612 | { 1613 | tcp_sent(_pcb, NULL); 1614 | tcp_recv(_pcb, NULL); 1615 | tcp_err(_pcb, NULL); 1616 | tcp_poll(_pcb, NULL, 0); 1617 | } 1618 | 1619 | if (tcp_close(_pcb) != ERR_OK) 1620 | { 1621 | tcp_abort(_pcb); 1622 | } 1623 | 1624 | _free_closed_slot(); 1625 | _pcb = NULL; 1626 | 1627 | return ERR_OK; 1628 | } 1629 | 1630 | ///////////////////////////////////////////// 1631 | 1632 | //In Async Thread 1633 | int8_t AsyncSSLClient::_fin(tcp_pcb* pcb, int8_t err) 1634 | { 1635 | _tcp_clear_events(this); 1636 | 1637 | if (_discard_cb) 1638 | { 1639 | _discard_cb(_discard_cb_arg, this); 1640 | } 1641 | 1642 | return ERR_OK; 1643 | } 1644 | 1645 | ///////////////////////////////////////////// 1646 | 1647 | int8_t AsyncSSLClient::_sent(tcp_pcb* pcb, uint16_t len) 1648 | { 1649 | _rx_last_packet = millis(); 1650 | 1651 | ATCP_LOGINFO1("_sent: len =", len); 1652 | 1653 | _pcb_busy = false; 1654 | 1655 | if (_sent_cb) 1656 | { 1657 | _sent_cb(_sent_cb_arg, this, len, (millis() - _pcb_sent_at)); 1658 | } 1659 | 1660 | return ERR_OK; 1661 | } 1662 | 1663 | ///////////////////////////////////////////// 1664 | 1665 | int8_t AsyncSSLClient::_recv(tcp_pcb* pcb, pbuf* pb, int8_t err) 1666 | { 1667 | while (pb != NULL) 1668 | { 1669 | _rx_last_packet = millis(); 1670 | 1671 | pbuf *nxt = pb->next; 1672 | pb->next = NULL; 1673 | 1674 | if (_pcb_secure) 1675 | { 1676 | ATCP_LOGINFO1("_recv: tot_len =", pb->tot_len); 1677 | 1678 | int err = tcp_ssl_read(pcb, pb); 1679 | // tcp_ssl_read always processes the full pbuf, so ack all of it 1680 | 1681 | // KH 1682 | //_tcp_recved(pcb, pb->len); 1683 | _tcp_recved(pcb, _closed_slot, pb->len); 1684 | ////// 1685 | 1686 | pbuf_free(pb); 1687 | 1688 | // handle errors 1689 | if (err < 0) 1690 | { 1691 | if (err != MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) 1692 | { 1693 | ATCP_LOGERROR1("_recv: err =", err); 1694 | 1695 | _close(); 1696 | } 1697 | 1698 | return ERR_BUF; // for lack of a better error value 1699 | } 1700 | 1701 | } 1702 | else 1703 | { 1704 | //we should not ack before we assimilate the data 1705 | _ack_pcb = true; 1706 | 1707 | if (_pb_cb) 1708 | { 1709 | _pb_cb(_pb_cb_arg, this, pb); 1710 | } 1711 | else 1712 | { 1713 | if (_recv_cb) 1714 | { 1715 | _recv_cb(_recv_cb_arg, this, pb->payload, pb->len); 1716 | } 1717 | 1718 | if (!_ack_pcb) 1719 | { 1720 | _rx_ack_len += pb->len; 1721 | } 1722 | else if (_pcb) 1723 | { 1724 | _tcp_recved(_pcb, _closed_slot, pb->len); 1725 | } 1726 | 1727 | pbuf_free(pb); 1728 | } 1729 | } 1730 | 1731 | pb = nxt; 1732 | } 1733 | 1734 | return ERR_OK; 1735 | } 1736 | 1737 | ///////////////////////////////////////////// 1738 | 1739 | int8_t AsyncSSLClient::_poll(tcp_pcb* pcb) 1740 | { 1741 | if (!_pcb) 1742 | { 1743 | ATCP_LOGWARN("_poll: NULL pcb"); 1744 | 1745 | return ERR_OK; 1746 | } 1747 | 1748 | if (pcb != _pcb) 1749 | { 1750 | ATCP_HEXLOGERROR2("_poll: diff pcb/_pcb =", (uint32_t) pcb, (uint32_t) _pcb); 1751 | 1752 | return ERR_OK; 1753 | } 1754 | 1755 | uint32_t now = millis(); 1756 | 1757 | // ACK Timeout 1758 | if (_pcb_busy && _ack_timeout && (now - _pcb_sent_at) >= _ack_timeout) 1759 | { 1760 | _pcb_busy = false; 1761 | 1762 | ATCP_LOGWARN1("_poll: ack timeout, state =", stateToString()); 1763 | 1764 | if (_timeout_cb) 1765 | _timeout_cb(_timeout_cb_arg, this, (now - _pcb_sent_at)); 1766 | 1767 | return ERR_OK; 1768 | } 1769 | 1770 | // RX Timeout 1771 | if (_rx_since_timeout && (now - _rx_last_packet) >= (_rx_since_timeout * 1000)) 1772 | { 1773 | ATCP_LOGWARN1("_poll: rx timeout, state =", stateToString()); 1774 | 1775 | _close(); 1776 | return ERR_OK; 1777 | } 1778 | 1779 | if (_pcb_secure && !_handshake_done && (now - _rx_last_packet) >= SSL_HANDSHAKE_TIMEOUT) 1780 | { 1781 | ATCP_LOGWARN1("_poll: ssl handshake timeout, state =", stateToString()); 1782 | 1783 | _close(); 1784 | 1785 | return ERR_OK; 1786 | } 1787 | 1788 | // Everything is fine 1789 | if (_poll_cb) 1790 | { 1791 | _poll_cb(_poll_cb_arg, this); 1792 | } 1793 | 1794 | return ERR_OK; 1795 | } 1796 | 1797 | ///////////////////////////////////////////// 1798 | 1799 | void AsyncSSLClient::_dns_found(struct ip_addr *ipaddr) 1800 | { 1801 | if (ipaddr && ipaddr->u_addr.ip4.addr) 1802 | { 1803 | connect(IPAddress(ipaddr->u_addr.ip4.addr), _connect_port, _pcb_secure); 1804 | } 1805 | else 1806 | { 1807 | if (_error_cb) 1808 | { 1809 | _error_cb(_error_cb_arg, this, -55); 1810 | } 1811 | 1812 | if (_discard_cb) 1813 | { 1814 | _discard_cb(_discard_cb_arg, this); 1815 | } 1816 | } 1817 | } 1818 | 1819 | ////////////////////////////////////////////////////////////////////////////////////////// 1820 | 1821 | /* 1822 | Public Helper Methods 1823 | * */ 1824 | 1825 | void AsyncSSLClient::stop() 1826 | { 1827 | close(false); 1828 | } 1829 | 1830 | ///////////////////////////////////////////// 1831 | 1832 | bool AsyncSSLClient::free() 1833 | { 1834 | if (!_pcb) 1835 | { 1836 | return true; 1837 | } 1838 | 1839 | if ( (_pcb->state == CLOSED) || (_pcb->state > ESTABLISHED) ) 1840 | { 1841 | return true; 1842 | } 1843 | 1844 | return false; 1845 | } 1846 | 1847 | ///////////////////////////////////////////// 1848 | 1849 | size_t AsyncSSLClient::write(const char* data) 1850 | { 1851 | if (data == NULL) 1852 | { 1853 | return 0; 1854 | } 1855 | 1856 | return write(data, strlen(data)); 1857 | } 1858 | 1859 | ///////////////////////////////////////////// 1860 | 1861 | size_t AsyncSSLClient::write(const char* data, size_t size, uint8_t apiflags) 1862 | { 1863 | size_t will_send = add(data, size, apiflags); 1864 | 1865 | if (!will_send || !send()) 1866 | { 1867 | return 0; 1868 | } 1869 | 1870 | return will_send; 1871 | } 1872 | 1873 | ///////////////////////////////////////////// 1874 | 1875 | void AsyncSSLClient::setRxTimeout(uint32_t timeout) 1876 | { 1877 | _rx_since_timeout = timeout; 1878 | } 1879 | 1880 | ///////////////////////////////////////////// 1881 | 1882 | uint32_t AsyncSSLClient::getRxTimeout() 1883 | { 1884 | return _rx_since_timeout; 1885 | } 1886 | 1887 | ///////////////////////////////////////////// 1888 | 1889 | uint32_t AsyncSSLClient::getAckTimeout() 1890 | { 1891 | return _ack_timeout; 1892 | } 1893 | 1894 | ///////////////////////////////////////////// 1895 | 1896 | void AsyncSSLClient::setAckTimeout(uint32_t timeout) 1897 | { 1898 | _ack_timeout = timeout; 1899 | } 1900 | 1901 | ///////////////////////////////////////////// 1902 | 1903 | void AsyncSSLClient::setNoDelay(bool nodelay) 1904 | { 1905 | if (!_pcb) 1906 | { 1907 | return; 1908 | } 1909 | 1910 | if (nodelay) 1911 | { 1912 | tcp_nagle_disable(_pcb); 1913 | } 1914 | else 1915 | { 1916 | tcp_nagle_enable(_pcb); 1917 | } 1918 | } 1919 | 1920 | ///////////////////////////////////////////// 1921 | 1922 | bool AsyncSSLClient::getNoDelay() 1923 | { 1924 | if (!_pcb) 1925 | { 1926 | return false; 1927 | } 1928 | 1929 | return tcp_nagle_disabled(_pcb); 1930 | } 1931 | 1932 | ///////////////////////////////////////////// 1933 | 1934 | uint16_t AsyncSSLClient::getMss() 1935 | { 1936 | if (!_pcb) 1937 | { 1938 | return 0; 1939 | } 1940 | 1941 | return tcp_mss(_pcb); 1942 | } 1943 | 1944 | ///////////////////////////////////////////// 1945 | 1946 | uint32_t AsyncSSLClient::getRemoteAddress() 1947 | { 1948 | if (!_pcb) 1949 | { 1950 | return 0; 1951 | } 1952 | 1953 | return _pcb->remote_ip.u_addr.ip4.addr; 1954 | } 1955 | 1956 | ///////////////////////////////////////////// 1957 | 1958 | uint16_t AsyncSSLClient::getRemotePort() 1959 | { 1960 | if (!_pcb) 1961 | { 1962 | return 0; 1963 | } 1964 | 1965 | return _pcb->remote_port; 1966 | } 1967 | 1968 | ///////////////////////////////////////////// 1969 | 1970 | uint32_t AsyncSSLClient::getLocalAddress() 1971 | { 1972 | if (!_pcb) 1973 | { 1974 | return 0; 1975 | } 1976 | 1977 | return _pcb->local_ip.u_addr.ip4.addr; 1978 | } 1979 | 1980 | ///////////////////////////////////////////// 1981 | 1982 | uint16_t AsyncSSLClient::getLocalPort() 1983 | { 1984 | if (!_pcb) 1985 | { 1986 | return 0; 1987 | } 1988 | 1989 | return _pcb->local_port; 1990 | } 1991 | 1992 | ///////////////////////////////////////////// 1993 | 1994 | IPAddress AsyncSSLClient::remoteIP() 1995 | { 1996 | return IPAddress(getRemoteAddress()); 1997 | } 1998 | 1999 | ///////////////////////////////////////////// 2000 | 2001 | uint16_t AsyncSSLClient::remotePort() 2002 | { 2003 | return getRemotePort(); 2004 | } 2005 | 2006 | ///////////////////////////////////////////// 2007 | 2008 | IPAddress AsyncSSLClient::localIP() 2009 | { 2010 | return IPAddress(getLocalAddress()); 2011 | } 2012 | 2013 | ///////////////////////////////////////////// 2014 | 2015 | uint16_t AsyncSSLClient::localPort() 2016 | { 2017 | return getLocalPort(); 2018 | } 2019 | 2020 | ///////////////////////////////////////////// 2021 | 2022 | uint8_t AsyncSSLClient::state() 2023 | { 2024 | if (!_pcb) 2025 | { 2026 | return 0; 2027 | } 2028 | 2029 | return (_pcb->state); 2030 | } 2031 | 2032 | ///////////////////////////////////////////// 2033 | 2034 | bool AsyncSSLClient::connected() 2035 | { 2036 | if (!_pcb) 2037 | { 2038 | return false; 2039 | } 2040 | 2041 | return (_pcb->state == ESTABLISHED); 2042 | } 2043 | 2044 | ///////////////////////////////////////////// 2045 | 2046 | bool AsyncSSLClient::connecting() 2047 | { 2048 | if (!_pcb) 2049 | { 2050 | return false; 2051 | } 2052 | 2053 | return (_pcb->state > CLOSED && _pcb->state < ESTABLISHED); 2054 | } 2055 | 2056 | ///////////////////////////////////////////// 2057 | 2058 | bool AsyncSSLClient::disconnecting() 2059 | { 2060 | if (!_pcb) 2061 | { 2062 | return false; 2063 | } 2064 | 2065 | return (_pcb->state > ESTABLISHED && _pcb->state < TIME_WAIT); 2066 | } 2067 | 2068 | ///////////////////////////////////////////// 2069 | 2070 | bool AsyncSSLClient::disconnected() 2071 | { 2072 | if (!_pcb) 2073 | { 2074 | return true; 2075 | } 2076 | 2077 | return (_pcb->state == CLOSED || _pcb->state == TIME_WAIT); 2078 | } 2079 | 2080 | ///////////////////////////////////////////// 2081 | 2082 | bool AsyncSSLClient::freeable() 2083 | { 2084 | if (!_pcb) 2085 | { 2086 | return true; 2087 | } 2088 | 2089 | return (_pcb->state == CLOSED || _pcb->state > ESTABLISHED); 2090 | } 2091 | 2092 | ///////////////////////////////////////////// 2093 | 2094 | bool AsyncSSLClient::canSend() 2095 | { 2096 | return space() > 0; 2097 | } 2098 | 2099 | ///////////////////////////////////////////// 2100 | 2101 | const char * AsyncSSLClient::errorToString(int8_t error) 2102 | { 2103 | switch (error) 2104 | { 2105 | case ERR_OK: 2106 | return "OK"; 2107 | 2108 | case ERR_MEM: 2109 | return "Out of memory error"; 2110 | 2111 | case ERR_BUF: 2112 | return "Buffer error"; 2113 | 2114 | case ERR_TIMEOUT: 2115 | return "Timeout"; 2116 | 2117 | case ERR_RTE: 2118 | return "Routing problem"; 2119 | 2120 | case ERR_INPROGRESS: 2121 | return "Operation in progress"; 2122 | 2123 | case ERR_VAL: 2124 | return "Illegal value"; 2125 | 2126 | case ERR_WOULDBLOCK: 2127 | return "Operation would block"; 2128 | 2129 | case ERR_USE: 2130 | return "Address in use"; 2131 | 2132 | case ERR_ALREADY: 2133 | return "Already connected"; 2134 | 2135 | case ERR_CONN: 2136 | return "Not connected"; 2137 | 2138 | case ERR_IF: 2139 | return "Low-level netif error"; 2140 | 2141 | case ERR_ABRT: 2142 | return "Connection aborted"; 2143 | 2144 | case ERR_RST: 2145 | return "Connection reset"; 2146 | 2147 | case ERR_CLSD: 2148 | return "Connection closed"; 2149 | 2150 | case ERR_ARG: 2151 | return "Illegal argument"; 2152 | 2153 | case -55: 2154 | return "DNS failed"; 2155 | 2156 | default: 2157 | return "UNKNOWN"; 2158 | } 2159 | } 2160 | 2161 | ///////////////////////////////////////////// 2162 | 2163 | const char * AsyncSSLClient::stateToString() 2164 | { 2165 | switch (state()) 2166 | { 2167 | case CLOSED: 2168 | return "Closed"; 2169 | 2170 | case LISTEN: 2171 | return "Listen"; 2172 | 2173 | case SYN_SENT: 2174 | return "SYN Sent"; 2175 | 2176 | case SYN_RCVD: 2177 | return "SYN Received"; 2178 | 2179 | case ESTABLISHED: 2180 | return "Established"; 2181 | 2182 | case FIN_WAIT_1: 2183 | return "FIN Wait 1"; 2184 | 2185 | case FIN_WAIT_2: 2186 | return "FIN Wait 2"; 2187 | 2188 | case CLOSE_WAIT: 2189 | return "Close Wait"; 2190 | 2191 | case CLOSING: 2192 | return "Closing"; 2193 | 2194 | case LAST_ACK: 2195 | return "Last ACK"; 2196 | 2197 | case TIME_WAIT: 2198 | return "Time Wait"; 2199 | 2200 | default: 2201 | return "UNKNOWN"; 2202 | } 2203 | } 2204 | 2205 | ////////////////////////////////////////////////////////////////////////////////////////// 2206 | 2207 | /* 2208 | Static Callbacks (LwIP C2C++ interconnect) 2209 | * */ 2210 | 2211 | void AsyncSSLClient::_s_dns_found(const char * name, struct ip_addr * ipaddr, void * arg) 2212 | { 2213 | reinterpret_cast(arg)->_dns_found(ipaddr); 2214 | } 2215 | 2216 | ///////////////////////////////////////////// 2217 | 2218 | int8_t AsyncSSLClient::_s_poll(void * arg, struct tcp_pcb * pcb) 2219 | { 2220 | return reinterpret_cast(arg)->_poll(pcb); 2221 | } 2222 | 2223 | ///////////////////////////////////////////// 2224 | 2225 | int8_t AsyncSSLClient::_s_recv(void * arg, struct tcp_pcb * pcb, struct pbuf *pb, int8_t err) 2226 | { 2227 | return reinterpret_cast(arg)->_recv(pcb, pb, err); 2228 | } 2229 | 2230 | ///////////////////////////////////////////// 2231 | 2232 | int8_t AsyncSSLClient::_s_fin(void * arg, struct tcp_pcb * pcb, int8_t err) 2233 | { 2234 | return reinterpret_cast(arg)->_fin(pcb, err); 2235 | } 2236 | 2237 | ///////////////////////////////////////////// 2238 | 2239 | int8_t AsyncSSLClient::_s_lwip_fin(void * arg, struct tcp_pcb * pcb, int8_t err) 2240 | { 2241 | return reinterpret_cast(arg)->_lwip_fin(pcb, err); 2242 | } 2243 | 2244 | ///////////////////////////////////////////// 2245 | 2246 | int8_t AsyncSSLClient::_s_sent(void * arg, struct tcp_pcb * pcb, uint16_t len) 2247 | { 2248 | return reinterpret_cast(arg)->_sent(pcb, len); 2249 | } 2250 | 2251 | ///////////////////////////////////////////// 2252 | 2253 | void AsyncSSLClient::_s_error(void * arg, int8_t err) 2254 | { 2255 | reinterpret_cast(arg)->_error(err); 2256 | } 2257 | 2258 | ///////////////////////////////////////////// 2259 | 2260 | int8_t AsyncSSLClient::_s_connected(void * arg, void * pcb, int8_t err) 2261 | { 2262 | return reinterpret_cast(arg)->_connected(pcb, err); 2263 | } 2264 | 2265 | ///////////////////////////////////////////// 2266 | 2267 | void AsyncSSLClient::_s_data(void *arg, struct tcp_pcb *tcp, uint8_t * data, size_t len) 2268 | { 2269 | AsyncSSLClient *c = reinterpret_cast(arg); 2270 | 2271 | if (c->_recv_cb) 2272 | c->_recv_cb(c->_recv_cb_arg, c, data, len); 2273 | } 2274 | 2275 | ///////////////////////////////////////////// 2276 | 2277 | void AsyncSSLClient::_s_handshake(void *arg, struct tcp_pcb *tcp, struct tcp_ssl_pcb* ssl) 2278 | { 2279 | AsyncSSLClient *c = reinterpret_cast(arg); 2280 | c->_handshake_done = true; 2281 | 2282 | if (c->_connect_cb) 2283 | c->_connect_cb(c->_connect_cb_arg, c); 2284 | } 2285 | 2286 | ///////////////////////////////////////////// 2287 | 2288 | void AsyncSSLClient::_s_ssl_error(void *arg, struct tcp_pcb *tcp, int8_t err) 2289 | { 2290 | reinterpret_cast(arg)->_ssl_error(err); 2291 | } 2292 | 2293 | ////////////////////////////////////////////////////////////////////////////////////////// 2294 | 2295 | /* 2296 | Async TCP Server 2297 | */ 2298 | 2299 | AsyncSSLServer::AsyncSSLServer(IPAddress addr, uint16_t port) 2300 | : _port(port) 2301 | , _addr(addr) 2302 | , _noDelay(false) 2303 | , _pcb(0) 2304 | , _connect_cb(0) 2305 | , _connect_cb_arg(0) 2306 | {} 2307 | 2308 | ///////////////////////////////////////////// 2309 | 2310 | AsyncSSLServer::AsyncSSLServer(uint16_t port) 2311 | : _port(port) 2312 | , _addr((uint32_t) IPADDR_ANY) 2313 | , _noDelay(false) 2314 | , _pcb(0) 2315 | , _connect_cb(0) 2316 | , _connect_cb_arg(0) 2317 | {} 2318 | 2319 | ///////////////////////////////////////////// 2320 | 2321 | AsyncSSLServer::~AsyncSSLServer() 2322 | { 2323 | end(); 2324 | } 2325 | 2326 | ///////////////////////////////////////////// 2327 | 2328 | void AsyncSSLServer::onClient(AcConnectHandlerSSL cb, void* arg) 2329 | { 2330 | _connect_cb = cb; 2331 | _connect_cb_arg = arg; 2332 | } 2333 | 2334 | ///////////////////////////////////////////// 2335 | 2336 | void AsyncSSLServer::begin() 2337 | { 2338 | if (_pcb) 2339 | { 2340 | return; 2341 | } 2342 | 2343 | if (!_start_async_task()) 2344 | { 2345 | ATCP_LOGERROR("begin: failed to start task"); 2346 | 2347 | return; 2348 | } 2349 | 2350 | int8_t err; 2351 | 2352 | _pcb = tcp_new_ip_type(IPADDR_TYPE_V4); 2353 | 2354 | if (!_pcb) 2355 | { 2356 | ATCP_LOGERROR("begin: NULL pcb"); 2357 | 2358 | return; 2359 | } 2360 | 2361 | ip_addr_t local_addr; 2362 | 2363 | local_addr.type = IPADDR_TYPE_V4; 2364 | local_addr.u_addr.ip4.addr = (uint32_t) _addr; 2365 | 2366 | err = _tcp_bind(_pcb, &local_addr, _port); 2367 | 2368 | if (err != ERR_OK) 2369 | { 2370 | _tcp_close(_pcb, -1); 2371 | 2372 | ATCP_LOGERROR1("begin: bind error, err =", err); 2373 | 2374 | return; 2375 | } 2376 | 2377 | static uint8_t backlog = 5; 2378 | 2379 | _pcb = _tcp_listen_with_backlog(_pcb, backlog); 2380 | 2381 | if (!_pcb) 2382 | { 2383 | ATCP_LOGERROR("begin: NULL listen_pcb"); 2384 | 2385 | return; 2386 | } 2387 | 2388 | tcp_arg(_pcb, (void*) this); 2389 | tcp_accept(_pcb, &_s_accept); 2390 | } 2391 | 2392 | ///////////////////////////////////////////// 2393 | 2394 | void AsyncSSLServer::end() 2395 | { 2396 | if (_pcb) 2397 | { 2398 | tcp_arg(_pcb, NULL); 2399 | tcp_accept(_pcb, NULL); 2400 | 2401 | if (tcp_close(_pcb) != ERR_OK) 2402 | { 2403 | _tcp_abort(_pcb, -1); 2404 | } 2405 | 2406 | _pcb = NULL; 2407 | } 2408 | } 2409 | 2410 | ///////////////////////////////////////////// 2411 | 2412 | //runs on LwIP thread 2413 | int8_t AsyncSSLServer::_accept(tcp_pcb* pcb, int8_t err) 2414 | { 2415 | ATCP_HEXLOGDEBUG1("_accept: pcb =", (uint32_t) pcb); 2416 | 2417 | if (_connect_cb) 2418 | { 2419 | AsyncSSLClient *c = new AsyncSSLClient(pcb); 2420 | 2421 | if (c) 2422 | { 2423 | c->setNoDelay(_noDelay); 2424 | 2425 | return _tcp_accept(this, c); 2426 | } 2427 | } 2428 | 2429 | if (tcp_close(pcb) != ERR_OK) 2430 | { 2431 | tcp_abort(pcb); 2432 | } 2433 | 2434 | ATCP_LOGERROR("_accept: fail"); 2435 | 2436 | return ERR_OK; 2437 | } 2438 | 2439 | ///////////////////////////////////////////// 2440 | 2441 | int8_t AsyncSSLServer::_accepted(AsyncSSLClient* client) 2442 | { 2443 | if (_connect_cb) 2444 | { 2445 | _connect_cb(_connect_cb_arg, client); 2446 | } 2447 | 2448 | return ERR_OK; 2449 | } 2450 | 2451 | ///////////////////////////////////////////// 2452 | 2453 | void AsyncSSLServer::setNoDelay(bool nodelay) 2454 | { 2455 | _noDelay = nodelay; 2456 | } 2457 | 2458 | ///////////////////////////////////////////// 2459 | 2460 | bool AsyncSSLServer::getNoDelay() 2461 | { 2462 | return _noDelay; 2463 | } 2464 | 2465 | ///////////////////////////////////////////// 2466 | 2467 | uint8_t AsyncSSLServer::status() 2468 | { 2469 | if (!_pcb) 2470 | { 2471 | return 0; 2472 | } 2473 | 2474 | return _pcb->state; 2475 | } 2476 | 2477 | ///////////////////////////////////////////// 2478 | 2479 | int8_t AsyncSSLServer::_s_accept(void * arg, tcp_pcb * pcb, int8_t err) 2480 | { 2481 | return reinterpret_cast(arg)->_accept(pcb, err); 2482 | } 2483 | 2484 | ///////////////////////////////////////////// 2485 | 2486 | int8_t AsyncSSLServer::_s_accepted(void *arg, AsyncSSLClient* client) 2487 | { 2488 | return reinterpret_cast(arg)->_accepted(client); 2489 | } 2490 | 2491 | ///////////////////////////////////////////// 2492 | 2493 | #endif /* ASYNCTCP_SSL_IML_H */ 2494 | --------------------------------------------------------------------------------