mirror of https://github.com/wolfSSL/wolfssh.git
Merge 3c2eb6cd55 into 2b5855922f
commit
fe9903111a
|
|
@ -0,0 +1,97 @@
|
|||
name: wolfSSH Espressif Build Test
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Weekly: Mondays at 07:00 UTC
|
||||
- cron: '0 7 * * 1'
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
WOLFSSL_REF: v5.9.1-stable
|
||||
|
||||
jobs:
|
||||
build_examples:
|
||||
name: ESP-IDF ${{ matrix.idf-ref }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# release-v5.5 is the current stable line; release-v5.1 is the version
|
||||
# the example READMEs and VisualGDB projects document.
|
||||
idf-ref: [ release-v5.5, release-v5.1 ]
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: espressif/idf:${{ matrix.idf-ref }}
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Checkout wolfSSH
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
path: wolfssh
|
||||
|
||||
- name: Checkout wolfSSL
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: wolfssl/wolfssl
|
||||
ref: ${{ env.WOLFSSL_REF }}
|
||||
path: wolfssl
|
||||
|
||||
- name: Build the Espressif examples
|
||||
env:
|
||||
WOLFSSH_ROOT: ${{ github.workspace }}/wolfssh
|
||||
WOLFSSL_ROOT: ${{ github.workspace }}/wolfssl
|
||||
run: |
|
||||
# The image sets IDF_PATH, but the ESP-IDF tool paths come from
|
||||
# export.sh, which a job step does not get from the entrypoint.
|
||||
. "${IDF_PATH}/export.sh"
|
||||
"${WOLFSSH_ROOT}/ide/Espressif/ESP-IDF/compileAllExamples.sh"
|
||||
|
||||
notify_failure:
|
||||
name: Open issue on scheduled failure
|
||||
needs: [build_examples]
|
||||
if: failure() && github.event_name == 'schedule'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
permissions:
|
||||
issues: write
|
||||
steps:
|
||||
- uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const label = 'espressif-build-failure';
|
||||
const runUrl = `${context.serverUrl}/${context.repo.owner}/` +
|
||||
`${context.repo.repo}/actions/runs/${context.runId}`;
|
||||
const body = [
|
||||
'The weekly Espressif example build failed.',
|
||||
'',
|
||||
`Run: ${runUrl}`,
|
||||
`Commit: ${context.sha}`,
|
||||
].join('\n');
|
||||
const existing = await github.rest.issues.listForRepo({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
state: 'open',
|
||||
labels: label,
|
||||
});
|
||||
if (existing.data.length > 0) {
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: existing.data[0].number,
|
||||
body: body,
|
||||
});
|
||||
} else {
|
||||
await github.rest.issues.create({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
title: 'Weekly Espressif example build failed',
|
||||
body: body,
|
||||
labels: [label],
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Build every wolfSSH ESP-IDF example project under ./examples/
|
||||
#
|
||||
# The examples carry local wolfssh and wolfssl components that compile the
|
||||
# library sources in place, so both source trees have to be on disk. Their
|
||||
# CMakeLists find them through the WOLFSSH_ROOT and WOLFSSL_ROOT environment
|
||||
# variables, which this script fills in when they are not already set.
|
||||
#
|
||||
# Run from an ESP-IDF environment:
|
||||
#
|
||||
# . /opt/esp/idf/export.sh
|
||||
# WOLFSSL_ROOT=/path/to/wolfssl ide/Espressif/ESP-IDF/compileAllExamples.sh
|
||||
#
|
||||
# WOLFSSH_ROOT defaults to the tree holding this script, WOLFSSL_ROOT to a
|
||||
# wolfssl checkout beside it. IDF_TARGET selects the chip; default esp32.
|
||||
|
||||
if [ -z "${IDF_PATH}" ]; then
|
||||
echo "ERROR: IDF_PATH is not set. Source the ESP-IDF export.sh first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
|
||||
|
||||
if [ -z "${WOLFSSH_ROOT}" ]; then
|
||||
WOLFSSH_ROOT=$(cd "${SCRIPT_DIR}/../../.." && pwd)
|
||||
fi
|
||||
|
||||
if [ -z "${WOLFSSL_ROOT}" ]; then
|
||||
WOLFSSL_ROOT="$(dirname "${WOLFSSH_ROOT}")/wolfssl"
|
||||
fi
|
||||
|
||||
export WOLFSSH_ROOT
|
||||
export WOLFSSL_ROOT
|
||||
export IDF_TARGET="${IDF_TARGET:-esp32}"
|
||||
|
||||
if [ ! -f "${WOLFSSH_ROOT}/wolfssh/ssh.h" ]; then
|
||||
echo "ERROR: no wolfSSH source in WOLFSSH_ROOT=${WOLFSSH_ROOT}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "${WOLFSSL_ROOT}/wolfssl/ssl.h" ]; then
|
||||
echo "ERROR: no wolfSSL source in WOLFSSL_ROOT=${WOLFSSL_ROOT}"
|
||||
echo "Clone wolfssl beside wolfssh or set WOLFSSL_ROOT."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "IDF_PATH = ${IDF_PATH}"
|
||||
echo "IDF_TARGET = ${IDF_TARGET}"
|
||||
echo "WOLFSSH_ROOT = ${WOLFSSH_ROOT}"
|
||||
echo "WOLFSSL_ROOT = ${WOLFSSL_ROOT}"
|
||||
|
||||
BUILT=""
|
||||
FAILED=""
|
||||
|
||||
for PROJECT in "${SCRIPT_DIR}"/examples/*/; do
|
||||
# A project directory is one with a top level CMakeLists.txt.
|
||||
if [ ! -f "${PROJECT}/CMakeLists.txt" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
NAME=$(basename "${PROJECT}")
|
||||
|
||||
echo
|
||||
echo "--------------------------------------------------------------"
|
||||
echo "Building ${NAME} for ${IDF_TARGET}"
|
||||
echo "--------------------------------------------------------------"
|
||||
|
||||
if (cd "${PROJECT}" && idf.py fullclean && idf.py build); then
|
||||
BUILT="${BUILT} ${NAME}"
|
||||
else
|
||||
FAILED="${FAILED} ${NAME}"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "${BUILT}" ] && [ -z "${FAILED}" ]; then
|
||||
echo "ERROR: no example projects found in ${SCRIPT_DIR}/examples/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "Built: ${BUILT:- none}"
|
||||
|
||||
if [ -n "${FAILED}" ]; then
|
||||
echo "Failed:${FAILED}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "All wolfSSH Espressif examples built."
|
||||
|
|
@ -510,16 +510,23 @@ static int wolfSSH_FwdDefaultActions(WS_FwdCbAction action, void* vCtx,
|
|||
ctx->state = FWD_STATE_DIRECT;
|
||||
}
|
||||
else if (action == WOLFSSH_FWD_LOCAL_CLEANUP) {
|
||||
WCLOSESOCKET(ctx->appFd);
|
||||
if (ctx->hostName) {
|
||||
WFREE(ctx->hostName, NULL, 0);
|
||||
ctx->hostName = NULL;
|
||||
/* Channel id rides in port. Only its holder may tear the slot down. */
|
||||
if (port == ctx->channelId) {
|
||||
/* The open can fail after setup, before anything connected. */
|
||||
if (ctx->appFd != (WS_SOCKET_T)-1) {
|
||||
WCLOSESOCKET(ctx->appFd);
|
||||
ctx->appFd = -1;
|
||||
}
|
||||
if (ctx->hostName) {
|
||||
WFREE(ctx->hostName, NULL, 0);
|
||||
ctx->hostName = NULL;
|
||||
}
|
||||
if (ctx->originName) {
|
||||
WFREE(ctx->originName, NULL, 0);
|
||||
ctx->originName = NULL;
|
||||
}
|
||||
ctx->state = FWD_STATE_INIT;
|
||||
}
|
||||
if (ctx->originName) {
|
||||
WFREE(ctx->originName, NULL, 0);
|
||||
ctx->originName = NULL;
|
||||
}
|
||||
ctx->state = FWD_STATE_INIT;
|
||||
}
|
||||
else if (action == WOLFSSH_FWD_REMOTE_SETUP) {
|
||||
struct sockaddr_in addr;
|
||||
|
|
@ -1150,20 +1157,35 @@ static int ssh_worker(thread_ctx_t* threadCtx)
|
|||
}
|
||||
else if (rc == WS_CHANNEL_CLOSED) {
|
||||
#ifdef WOLFSSH_FWD
|
||||
if (threadCtx->fwdCbCtx.state == FWD_STATE_CONNECTED &&
|
||||
lastChannel == threadCtx->fwdCbCtx.channelId) {
|
||||
/* Read zero-returned. Socket is closed. Go back
|
||||
to listening. */
|
||||
if (fwdFd != -1) {
|
||||
WCLOSESOCKET(fwdFd);
|
||||
/* wolfSSH_worker() names the channel only for the
|
||||
* data and EOF statuses; DoChannelClose() recorded
|
||||
* the id it retired. */
|
||||
wolfSSH_GetLastRxId(ssh, &lastChannel);
|
||||
if (lastChannel == threadCtx->fwdCbCtx.channelId) {
|
||||
if (threadCtx->fwdCbCtx.appFd == (WS_SOCKET_T)-1) {
|
||||
/* The cleanup handler ran ahead of this and
|
||||
* closed the socket; only this copy of the
|
||||
* descriptor is stale. */
|
||||
fwdFd = -1;
|
||||
}
|
||||
if (threadCtx->fwdCbCtx.originName != NULL) {
|
||||
WFREE(threadCtx->fwdCbCtx.originName,
|
||||
NULL, 0);
|
||||
threadCtx->fwdCbCtx.originName = NULL;
|
||||
else if (threadCtx->fwdCbCtx.state
|
||||
== FWD_STATE_CONNECTED) {
|
||||
/* A locally opened forward is armed by no
|
||||
* LOCAL_SETUP and so draws no cleanup. Its
|
||||
* teardown is still ours: go back to
|
||||
* listening. */
|
||||
if (fwdFd != -1) {
|
||||
WCLOSESOCKET(fwdFd);
|
||||
fwdFd = -1;
|
||||
threadCtx->fwdCbCtx.appFd = -1;
|
||||
}
|
||||
if (threadCtx->fwdCbCtx.originName != NULL) {
|
||||
WFREE(threadCtx->fwdCbCtx.originName,
|
||||
NULL, 0);
|
||||
threadCtx->fwdCbCtx.originName = NULL;
|
||||
}
|
||||
threadCtx->fwdCbCtx.state = FWD_STATE_LISTEN;
|
||||
}
|
||||
threadCtx->fwdCbCtx.state = FWD_STATE_LISTEN;
|
||||
}
|
||||
#endif
|
||||
continue;
|
||||
|
|
@ -1290,6 +1312,7 @@ static int ssh_worker(thread_ctx_t* threadCtx)
|
|||
to listening. */
|
||||
WCLOSESOCKET(fwdFd);
|
||||
fwdFd = -1;
|
||||
threadCtx->fwdCbCtx.appFd = -1;
|
||||
if (threadCtx->fwdCbCtx.hostName != NULL) {
|
||||
WFREE(threadCtx->fwdCbCtx.hostName,
|
||||
NULL, 0);
|
||||
|
|
@ -1310,6 +1333,8 @@ static int ssh_worker(thread_ctx_t* threadCtx)
|
|||
/* Connection reset. Socket is closed.
|
||||
* Go back to listening. */
|
||||
WCLOSESOCKET(fwdFd);
|
||||
fwdFd = -1;
|
||||
threadCtx->fwdCbCtx.appFd = -1;
|
||||
threadCtx->fwdCbCtx.state = FWD_STATE_LISTEN;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -1405,6 +1430,9 @@ static int ssh_worker(thread_ctx_t* threadCtx)
|
|||
threadCtx->fwdCbCtx.hostPort);
|
||||
|
||||
if (fwdFd > 0) {
|
||||
/* The cleanup handler closes what it finds here, so a
|
||||
* direct forward has to record its socket too. */
|
||||
threadCtx->fwdCbCtx.appFd = fwdFd;
|
||||
threadCtx->fwdCbCtx.state = FWD_STATE_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue