我正在尝试让HTTPS与我的端点一起使用;可以与esp8266 / Arduino堆栈配合使用,但是HW WDT可以通过esp-open-sdk堆栈触发,因此HTTPS连接失败。
我已经重建了mbedtls库,并发现我陷入了以下代码中。喂食SW看门狗(而不是完全停止SW看门狗)没有什么区别。
这是ESP所卡住的部分代码:
int __attribute__((weak)) mbedtls_parse_internal(int socket, sint8 error)
{
...
// Getting stuck in this loop!
system_soft_wdt_stop();
while ((ret = mbedtls_ssl_handshake(&TLSmsg->ssl)) != 0) {
if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
ret = ESPCONN_OK;
break;
} else{
break;
}
}
system_soft_wdt_restart();
...
}
以上循环运行了很长时间,并且在触发HW WDT之前没有完成。然后,ESP重新启动,我发现RST原因为4,这对应于WDT故障。
相同的端点可以在Arduino堆栈上正常工作(尽管使用BearSSL / axTLS)。但是,我怀疑是因为它具有神奇的yield()函数,该函数允许后台任务每隔一段时间运行一次:
size_t WiFiClientSecure::_write(const uint8_t *buf, size_t size, bool pmem) {
size_t sent_bytes = 0;
if (!connected() || !size || !_handshake_done) {
return 0;
}
do {
// Ensure we yield if we need multiple fragments to avoid WDT
if (sent_bytes) {
//*** MAGIC YIELD FUNCTION TO ALLOW BACKGROUND TASKS TO RUN ***
optimistic_yield(1000);
}
// Get BearSSL to a state where we can send
if (_run_until(BR_SSL_SENDAPP) < 0) {
break;
}
if (br_ssl_engine_current_state(_eng) & BR_SSL_SENDAPP) {
size_t sendapp_len;
unsigned char *sendapp_buf = br_ssl_engine_sendapp_buf(_eng, &sendapp_len);
int to_send = size > sendapp_len ? sendapp_len : size;
if (pmem) {
memcpy_P(sendapp_buf, buf, to_send);
} else {
memcpy(sendapp_buf, buf, to_send);
}
br_ssl_engine_sendapp_ack(_eng, to_send);
br_ssl_engine_flush(_eng, 0);
flush();
buf += to_send;
sent_bytes += to_send;
size -= to_send;
} else {
break;
}
} while (size);
return sent_bytes;
}
yield()函数就是这样的汇编,由于我缺乏汇编技巧,因此我很难理解:
.text
.align 4
.literal_position
.global cont_yield
.type cont_yield, @function
cont_yield:
/* a1: sp */
/* a2: void* cont_ctx */
/* adjust stack and save registers */
addi a1, a1, -24
s32i a12, a1, 0
s32i a13, a1, 4
s32i a14, a1, 8
s32i a15, a1, 12
s32i a0, a1, 16
s32i a2, a1, 20
/* &cont_continue -> cont_ctx.pc_yield */
movi a3, cont_continue
s32i a3, a2, 8
/* sp -> cont_ctx.sp_yield */
s32i a1, a2, 12
/* a0 <- cont_ctx.pc_ret */
l32i a0, a2, 0
/* sp <- cont_ctx.sp_ret */
l32i a1, a2, 4
jx a0
cont_continue:
l32i a12, a1, 0
l32i a13, a1, 4
l32i a14, a1, 8
l32i a15, a1, 12
l32i a0, a1, 16
l32i a2, a1, 20
addi a1, a1, 24
ret
.size cont_yield, . - cont_yield
////////////////////////////////////////////////////
/*
The purpose of cont_wrapper is to signal to xtensa-gdb
that we want to treat this function as the outermost one.
From: binutils-gdb-xtensa/gdb/xtensa-tdep.c:2677 <https://git.io/vA8Ps>
"Special case for terminating backtrace at a function that wants to
be seen as the outermost one. Such a function will clear it's RA (A0)
register to 0 in the prologue instead of saving its original value."
*/
.text
.align 4
.literal_position
.global cont_wrapper
.type cont_wrapper, @function
cont_wrapper:
movi a0, 0
callx0 a3
movi a2, cont_norm
jx a2
.size cont_wrapper, . - cont_wrapper
////////////////////////////////////////////////////
.text
.align 4
.literal_position
.global cont_run
.type cont_run, @function
cont_run:
/* a1: sp */
/* a2: void* cont_ctx */
/* a3: void (*pfn) */
/* adjust stack and save registers */
addi a1, a1, -20
s32i a12, a1, 0
s32i a13, a1, 4
s32i a14, a1, 8
s32i a15, a1, 12
s32i a0, a1, 16
/* cont_ret -> a4 -> cont_ctx.pc_ret*/
movi a4, cont_ret
s32i a4, a2, 0
/* sp -> cont_ctx.sp_ret */
s32i a1, a2, 4
/* if cont_ctx.pc_yield != 0, goto cont_resume */
l32i a4, a2, 8
bnez a4, cont_resume
/* else */
/* set new stack*/
l32i a1, a2, 16;
/* goto pfn */
movi a2, cont_wrapper
jx a2
cont_resume:
/* a1 <- cont_ctx.sp_yield */
l32i a1, a2, 12
/* reset yield flag, 0 -> cont_ctx.pc_yield */
movi a3, 0
s32i a3, a2, 8
/* jump to saved cont_ctx.pc_yield */
movi a0, cont_ret
jx a4
cont_norm:
/* calculate pointer to cont_ctx.struct_start from sp */
l32i a2, a1, 4
/* sp <- cont_ctx.sp_ret */
l32i a1, a2, 4
/* 0 -> cont_ctx.pc_ret */
movi a4, 0
s32i a4, a2, 0
cont_ret:
/* restore registers */
l32i a12, a1, 0
l32i a13, a1, 4
l32i a14, a1, 8
l32i a15, a1, 12
l32i a0, a1, 16
/* adjust stack and return */
addi a1, a1, 20
ret
.size cont_run, . - cont_run
所以,我对ESP8266 / Arduino专家的问题是是否可以将上述代码移植到esp-open-sdk堆栈中。或者,如果ESP8266 / Arduino堆栈有一些特殊之处,导致无法使用该端口。