18#if PC_ENABLE_TLS && defined(ARDUINO)
23#include <esp_system.h>
26#include <mbedtls/error.h>
27#include <mbedtls/pk.h>
28#include <mbedtls/platform.h>
29#include <mbedtls/sha256.h>
30#include <mbedtls/ssl.h>
31#include <mbedtls/version.h>
32#include <mbedtls/x509_crt.h>
33#if PC_ENABLE_TLS_RESUMPTION
34#include <mbedtls/ssl_ticket.h>
35#if !defined(MBEDTLS_SSL_TICKET_C) || !defined(MBEDTLS_SSL_SESSION_TICKETS)
36#error "PC_ENABLE_TLS_RESUMPTION needs an mbedTLS build with MBEDTLS_SSL_TICKET_C + MBEDTLS_SSL_SESSION_TICKETS"
68#if PC_TLS_ARENA_IN_PSRAM && defined(ARDUINO)
70#if !defined(CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY)
72 "PC_TLS_ARENA_IN_PSRAM needs a framework built with CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y. The stock arduino-esp32 core ships it OFF, so EXT_RAM_BSS_ATTR silently no-ops and the arena would stay in internal RAM. Rebuild the core (see tools/psram/README.md) or unset PC_TLS_ARENA_IN_PSRAM."
74#if defined(EXT_RAM_BSS_ATTR)
75#define PC_TLS_ARENA_ATTR EXT_RAM_BSS_ATTR
76#elif defined(EXT_RAM_ATTR)
77#define PC_TLS_ARENA_ATTR EXT_RAM_ATTR
79#error "PC_TLS_ARENA_IN_PSRAM: no EXT_RAM_BSS_ATTR/EXT_RAM_ATTR from the framework (unexpected)."
82#define PC_TLS_ARENA_ATTR
86#if defined(PC_TLS_HS_BENCH)
96PC_TLS_ARENA_ATTR
static TlsPoolCtx s_pool;
104static const size_t POOL_HDR = (
sizeof(PoolBlk) + (TLS_ALIGN - 1)) & ~(
size_t)(TLS_ALIGN - 1);
106static void pool_init()
108 PoolBlk *b = (PoolBlk *)s_pool.arena;
109 b->size =
sizeof(s_pool.arena) - POOL_HDR;
113 s_pool.inited =
true;
116static void pool_coalesce()
118 uint8_t *p = s_pool.arena;
119 uint8_t *end = s_pool.arena +
sizeof(s_pool.arena);
122 PoolBlk *b = (PoolBlk *)p;
123 uint8_t *next = p + POOL_HDR + b->size;
124 if (!b->used && next < end)
126 PoolBlk *nb = (PoolBlk *)next;
129 b->size += POOL_HDR + nb->size;
137static void *pool_calloc(
size_t n,
size_t size)
143 if (n != 0 && size > (
size_t)-1 / n)
147 size_t want = n * size;
148 want = (want + (TLS_ALIGN - 1)) & ~(size_t)(TLS_ALIGN - 1);
154 uint8_t *p = s_pool.arena;
155 uint8_t *end = s_pool.arena +
sizeof(s_pool.arena);
158 PoolBlk *b = (PoolBlk *)p;
159 if (!b->used && b->size >= want)
162 if (b->size >= want + POOL_HDR + TLS_ALIGN)
164 PoolBlk *nb = (PoolBlk *)(p + POOL_HDR + want);
165 nb->size = b->size - want - POOL_HDR;
170 s_pool.used += b->size;
171 if (s_pool.used > s_pool.peak)
173 s_pool.peak = s_pool.used;
175 void *payload = p + POOL_HDR;
176 memset(payload, 0, b->size);
179 p += POOL_HDR + b->size;
184static void pool_free(
void *ptr)
190 PoolBlk *b = (PoolBlk *)((uint8_t *)ptr - POOL_HDR);
194 if (s_pool.used >= b->size)
196 s_pool.used -= b->size;
208struct TlsServerReadyCtx
212static TlsServerReadyCtx s_srv_ready;
219 mbedtls_ssl_config conf;
220 mbedtls_x509_crt cert;
221 mbedtls_pk_context key;
225#if PC_ENABLE_TLS_RESUMPTION
226 mbedtls_ssl_ticket_context ticket_ctx;
229static TlsServerCtx s_srv;
233 mbedtls_ssl_context ssl;
238#ifdef PC_TLS_HS_BENCH
240 long long hs_wall0_us;
250static TlsConnsCtx s_conns;
252#ifdef PC_TLS_HS_BENCH
255TlsHsBenchCtx pc_tls_hs_bench = {0, 0, 0};
258static TlsConn *find(uint8_t slot)
262 if (s_conns.conns[i].active && s_conns.conns[i].slot == slot)
264 return &s_conns.conns[i];
273static int tls_rng(
void *ctx,
unsigned char *out,
size_t len)
276 esp_fill_random(out, len);
283static int server_bio_recv(
void *ctx,
unsigned char *buf,
size_t len)
285 TlsConn *e = (TlsConn *)ctx;
286 size_t n = pc_conn_read(e->slot, buf, len);
289 return MBEDTLS_ERR_SSL_WANT_READ;
299static int server_bio_send(
void *ctx,
const unsigned char *buf,
size_t len)
301 TlsConn *e = (TlsConn *)ctx;
304 return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
307 size_t avail = tcp_sndbuf(e->pcb);
310 return MBEDTLS_ERR_SSL_WANT_WRITE;
326 return MBEDTLS_ERR_SSL_WANT_WRITE;
334static void tls_apply_max_frag_len(mbedtls_ssl_config *conf)
336#if PC_TLS_MAX_FRAG_LEN && defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
337#if PC_TLS_MAX_FRAG_LEN <= 512
338 mbedtls_ssl_conf_max_frag_len(conf, MBEDTLS_SSL_MAX_FRAG_LEN_512);
339#elif PC_TLS_MAX_FRAG_LEN <= 1024
340 mbedtls_ssl_conf_max_frag_len(conf, MBEDTLS_SSL_MAX_FRAG_LEN_1024);
341#elif PC_TLS_MAX_FRAG_LEN <= 2048
342 mbedtls_ssl_conf_max_frag_len(conf, MBEDTLS_SSL_MAX_FRAG_LEN_2048);
344 mbedtls_ssl_conf_max_frag_len(conf, MBEDTLS_SSL_MAX_FRAG_LEN_4096);
367static void tls_apply_curve_pref(mbedtls_ssl_config *conf)
369#if MBEDTLS_VERSION_MAJOR >= 3
370 static const uint16_t kGroupPref[] = {
371#if PC_TLS_ECDHE_PREFER_P256 && defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED)
372 MBEDTLS_SSL_IANA_TLS_GROUP_SECP256R1,
374#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED)
375 MBEDTLS_SSL_IANA_TLS_GROUP_X25519,
377#if !PC_TLS_ECDHE_PREFER_P256 && defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED)
378 MBEDTLS_SSL_IANA_TLS_GROUP_SECP256R1,
380#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED)
381 MBEDTLS_SSL_IANA_TLS_GROUP_SECP384R1,
383#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED)
384 MBEDTLS_SSL_IANA_TLS_GROUP_SECP521R1,
388 mbedtls_ssl_conf_groups(conf, kGroupPref);
390 static const mbedtls_ecp_group_id kCurvePref[] = {
391#if PC_TLS_ECDHE_PREFER_P256 && defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED)
392 MBEDTLS_ECP_DP_SECP256R1,
394#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED)
395 MBEDTLS_ECP_DP_CURVE25519,
397#if !PC_TLS_ECDHE_PREFER_P256 && defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED)
398 MBEDTLS_ECP_DP_SECP256R1,
400#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED)
401 MBEDTLS_ECP_DP_SECP384R1,
403#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED)
404 MBEDTLS_ECP_DP_SECP521R1,
408 mbedtls_ssl_conf_curves(conf, kCurvePref);
415bool pc_tls_global_init(
const uint8_t *cert,
size_t cert_len,
const uint8_t *key,
size_t key_len)
417 if (s_srv_ready.ready)
429 mbedtls_platform_set_calloc_free(pool_calloc, pool_free);
431 mbedtls_x509_crt_init(&s_srv.cert);
432 mbedtls_pk_init(&s_srv.key);
433 mbedtls_ssl_config_init(&s_srv.conf);
435 if (mbedtls_x509_crt_parse(&s_srv.cert, cert, cert_len) != 0)
440#if MBEDTLS_VERSION_MAJOR >= 3
441 if (mbedtls_pk_parse_key(&s_srv.key, key, key_len,
nullptr, 0, tls_rng,
nullptr) != 0)
446 if (mbedtls_pk_parse_key(&s_srv.key, key, key_len,
nullptr, 0) != 0)
452 if (mbedtls_ssl_config_defaults(&s_srv.conf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM,
453 MBEDTLS_SSL_PRESET_DEFAULT) != 0)
458 mbedtls_ssl_conf_rng(&s_srv.conf, tls_rng,
nullptr);
459 tls_apply_max_frag_len(&s_srv.conf);
460 tls_apply_curve_pref(&s_srv.conf);
461#if MBEDTLS_VERSION_MAJOR >= 3
462 mbedtls_ssl_conf_min_tls_version(&s_srv.conf, MBEDTLS_SSL_VERSION_TLS1_2);
464 mbedtls_ssl_conf_min_version(&s_srv.conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3);
467 if (mbedtls_ssl_conf_own_cert(&s_srv.conf, &s_srv.cert, &s_srv.key) != 0)
475 static const char *s_alpn[] = {
"h2",
"http/1.1",
nullptr};
476 if (mbedtls_ssl_conf_alpn_protocols(&s_srv.conf, s_alpn) != 0)
482#if PC_ENABLE_TLS_RESUMPTION
487 mbedtls_ssl_ticket_init(&s_srv.ticket_ctx);
488 if (mbedtls_ssl_ticket_setup(&s_srv.ticket_ctx, tls_rng,
nullptr, MBEDTLS_CIPHER_AES_256_GCM,
493 mbedtls_ssl_conf_session_tickets_cb(&s_srv.conf, mbedtls_ssl_ticket_write, mbedtls_ssl_ticket_parse,
499 s_conns.conns[i].active =
false;
502 s_srv_ready.ready =
true;
508 return s_srv_ready.ready;
511const char *pc_tls_alpn(uint8_t slot)
513 TlsConn *c = find(slot);
514 return c ? mbedtls_ssl_get_alpn_protocol(&c->ssl) : nullptr;
517bool pc_tls_conn_begin(uint8_t slot)
519 if (!s_srv_ready.ready)
523 TlsConn *e =
nullptr;
526 if (!s_conns.conns[i].active)
528 e = &s_conns.conns[i];
540 e->established =
false;
541 mbedtls_ssl_init(&e->ssl);
542 if (mbedtls_ssl_setup(&e->ssl, &s_srv.conf) != 0)
544 mbedtls_ssl_free(&e->ssl);
548 mbedtls_ssl_set_bio(&e->ssl, e, server_bio_send, server_bio_recv,
nullptr);
552int pc_tls_handshake(uint8_t slot)
554 TlsConn *e = find(slot);
559#ifdef PC_TLS_HS_BENCH
562 e->hs_started =
true;
564 e->hs_wall0_us = esp_timer_get_time();
565 pc_tls_hs_bench.n_pumps = 0;
567 long long hs_t0 = esp_timer_get_time();
569 int ret = mbedtls_ssl_handshake(&e->ssl);
570#ifdef PC_TLS_HS_BENCH
571 long long hs_d = esp_timer_get_time() - hs_t0;
572 e->hs_cpu_us += hs_d;
573 if (hs_d > 2000 && pc_tls_hs_bench.n_pumps < 8)
575 pc_tls_hs_bench.pumps[pc_tls_hs_bench.n_pumps++] = hs_d;
580 e->established =
true;
581#ifdef PC_TLS_HS_BENCH
582 pc_tls_hs_bench.last_cpu_us = e->hs_cpu_us;
583 pc_tls_hs_bench.last_wall_us = esp_timer_get_time() - e->hs_wall0_us;
584 pc_tls_hs_bench.count++;
585 e->hs_started =
false;
589 if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE)
596bool pc_tls_established(uint8_t slot)
598 TlsConn *e = find(slot);
599 return e && e->established;
602int pc_tls_read(uint8_t slot, uint8_t *buf,
size_t len)
604 TlsConn *e = find(slot);
609 int ret = mbedtls_ssl_read(&e->ssl, buf, len);
614 if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE)
621int pc_tls_write(uint8_t slot,
const void *data,
size_t len)
623 TlsConn *e = find(slot);
628 const unsigned char *p = (
const unsigned char *)data;
633 int ret = mbedtls_ssl_write(&e->ssl, p + sent, len - sent);
640 if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE)
653void pc_tls_conn_end(uint8_t slot)
655 TlsConn *e = find(slot);
660 mbedtls_ssl_close_notify(&e->ssl);
661 mbedtls_ssl_free(&e->ssl);
663 e->established =
false;
667void pc_tls_conn_free(uint8_t slot)
669 TlsConn *e = find(slot);
674 mbedtls_ssl_free(&e->ssl);
676 e->established =
false;
680size_t pc_tls_arena_peak()
686bool pc_tls_set_client_ca(
const uint8_t *ca,
size_t ca_len)
688 if (!s_srv_ready.ready || !ca)
692 mbedtls_x509_crt_init(&s_srv.ca);
693 if (mbedtls_x509_crt_parse(&s_srv.ca, ca, ca_len) != 0)
699 mbedtls_ssl_conf_ca_chain(&s_srv.conf, &s_srv.ca,
nullptr);
700 mbedtls_ssl_conf_authmode(&s_srv.conf, MBEDTLS_SSL_VERIFY_REQUIRED);
704int pc_tls_peer_subject(uint8_t slot,
char *out,
size_t out_len)
706 if (!out || out_len == 0)
711 TlsConn *e = find(slot);
712 if (!e || !e->established)
716 const mbedtls_x509_crt *peer = mbedtls_ssl_get_peer_cert(&e->ssl);
721 int n = mbedtls_x509_dn_gets(out, out_len, &peer->subject);
726#if PC_ENABLE_CLIENT_TLS
736struct TlsClientAuthCtx
741 bool pin_set =
false;
743static TlsClientAuthCtx s_cli;
747static void client_arena_ensure()
752 mbedtls_platform_set_calloc_free(pool_calloc, pool_free);
756void pc_tls_client_set_ca(
const uint8_t *ca,
size_t ca_len)
758 client_arena_ensure();
761 mbedtls_x509_crt_free(&s_cli.ca);
763 s_cli.ca_set =
false;
764 if (!ca || ca_len == 0)
768 mbedtls_x509_crt_init(&s_cli.ca);
769 s_cli.ca_set = (mbedtls_x509_crt_parse(&s_cli.ca, ca, ca_len) == 0);
772 mbedtls_x509_crt_free(&s_cli.ca);
776void pc_tls_client_set_pin(
const uint8_t sha256[32])
780 s_cli.pin_set =
false;
783 memcpy(s_cli.pin, sha256, 32);
784 s_cli.pin_set =
true;
787void pc_tls_client_clear_verify()
791 mbedtls_x509_crt_free(&s_cli.ca);
793 s_cli.ca_set =
false;
794 s_cli.pin_set =
false;
798static bool ct_eq32(
const uint8_t *a,
const uint8_t *b)
801 for (
int i = 0; i < 32; i++)
803 d |= (uint8_t)(a[i] ^ b[i]);
810static int client_conf_apply(mbedtls_ssl_config *conf)
812 if (mbedtls_ssl_config_defaults(conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM,
813 MBEDTLS_SSL_PRESET_DEFAULT) != 0)
817 mbedtls_ssl_conf_rng(conf, tls_rng,
nullptr);
818 tls_apply_max_frag_len(conf);
819 tls_apply_curve_pref(conf);
822 mbedtls_ssl_conf_ca_chain(conf, &s_cli.ca,
nullptr);
823 mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_REQUIRED);
827 mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_NONE);
829#if MBEDTLS_VERSION_MAJOR >= 3
830 mbedtls_ssl_conf_min_tls_version(conf, MBEDTLS_SSL_VERSION_TLS1_2);
832 mbedtls_ssl_conf_min_version(conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3);
834#if PC_ENABLE_TLS_RESUMPTION
837 mbedtls_ssl_conf_session_tickets(conf, MBEDTLS_SSL_SESSION_TICKETS_ENABLED);
844static bool client_pin_ok(mbedtls_ssl_context *ssl)
850 const mbedtls_x509_crt *peer = mbedtls_ssl_get_peer_cert(ssl);
856#if MBEDTLS_VERSION_MAJOR >= 3
857 int hret = mbedtls_sha256(peer->raw.p, peer->raw.len, hash, 0);
859 int hret = mbedtls_sha256_ret(peer->raw.p, peer->raw.len, hash, 0);
861 return (hret == 0) && ct_eq32(hash, s_cli.pin);
864#if PC_ENABLE_HTTP_CLIENT_TLS
873int pc_tls_client_run(
const char *host,
const uint8_t *req,
size_t reqlen, uint8_t *out,
size_t out_cap,
874 size_t *out_len, pc_tls_bio_send_fn send_fn, pc_tls_bio_recv_fn recv_fn, uint32_t deadline_ms)
880 if (!req || !out || out_cap == 0 || !send_fn || !recv_fn)
885 client_arena_ensure();
887 mbedtls_ssl_context ssl;
888 mbedtls_ssl_config conf;
889 mbedtls_ssl_init(&ssl);
890 mbedtls_ssl_config_init(&conf);
896 if (client_conf_apply(&conf) != 0)
900 if (mbedtls_ssl_setup(&ssl, &conf) != 0)
906 mbedtls_ssl_set_hostname(&ssl, host);
908 mbedtls_ssl_set_bio(&ssl,
nullptr, send_fn, recv_fn,
nullptr);
911 while ((ret = mbedtls_ssl_handshake(&ssl)) != 0)
913 if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
917 if ((int32_t)(deadline_ms - millis()) <= 0)
926#ifdef PC_HTTP_CLIENT_DEBUG
927 printf(
"[tls] handshake ret=-0x%04x arena_peak=%u\n", (
unsigned)(-ret), (
unsigned)pc_tls_arena_peak());
933 if (!client_pin_ok(&ssl))
935#ifdef PC_HTTP_CLIENT_DEBUG
936 printf(
"[tls] cert pin mismatch\n");
944 while (sent < reqlen)
946 ret = mbedtls_ssl_write(&ssl, req + sent, reqlen - sent);
952 if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
956 if ((int32_t)(deadline_ms - millis()) <= 0)
969 while (total < out_cap)
971 ret = mbedtls_ssl_read(&ssl, out + total, out_cap - total);
974 total += (size_t)ret;
977 if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE)
979 if ((int32_t)(deadline_ms - millis()) <= 0)
992 rc = (total > 0) ? 0 : -1;
995 mbedtls_ssl_close_notify(&ssl);
996 mbedtls_ssl_free(&ssl);
997 mbedtls_ssl_config_free(&conf);
1010 mbedtls_ssl_context ssl;
1011 mbedtls_ssl_config conf;
1012 bool active =
false;
1013#if PC_ENABLE_TLS_RESUMPTION
1014 mbedtls_ssl_session saved;
1015 bool saved_valid =
false;
1018static TlsCsessCtx s_csess;
1020#if PC_ENABLE_TLS_RESUMPTION
1025void pc_tls_client_session_forget_session()
1027 if (s_csess.saved_valid)
1029 mbedtls_ssl_session_free(&s_csess.saved);
1031 s_csess.saved_valid =
false;
1034void pc_tls_client_session_forget_session()
1039bool pc_tls_client_session_begin(
const char *host, pc_tls_bio_send_fn send_fn, pc_tls_bio_recv_fn recv_fn)
1041 if (!send_fn || !recv_fn)
1047 pc_tls_client_session_end();
1049 client_arena_ensure();
1050 mbedtls_ssl_init(&s_csess.ssl);
1051 mbedtls_ssl_config_init(&s_csess.conf);
1052 if (client_conf_apply(&s_csess.conf) != 0 || mbedtls_ssl_setup(&s_csess.ssl, &s_csess.conf) != 0)
1054 mbedtls_ssl_free(&s_csess.ssl);
1055 mbedtls_ssl_config_free(&s_csess.conf);
1060 mbedtls_ssl_set_hostname(&s_csess.ssl, host);
1062#if PC_ENABLE_TLS_RESUMPTION
1065 if (s_csess.saved_valid)
1067 mbedtls_ssl_set_session(&s_csess.ssl, &s_csess.saved);
1070 mbedtls_ssl_set_bio(&s_csess.ssl,
nullptr, send_fn, recv_fn,
nullptr);
1071 s_csess.active =
true;
1075bool pc_tls_client_session_active()
1077 return s_csess.active;
1080int pc_tls_client_session_handshake()
1082 if (!s_csess.active)
1086 int ret = mbedtls_ssl_handshake(&s_csess.ssl);
1089 if (!client_pin_ok(&s_csess.ssl))
1093#if PC_ENABLE_TLS_RESUMPTION
1095 pc_tls_client_session_forget_session();
1096 mbedtls_ssl_session_init(&s_csess.saved);
1097 s_csess.saved_valid = (mbedtls_ssl_get_session(&s_csess.ssl, &s_csess.saved) == 0);
1101 if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE)
1108int pc_tls_client_session_read(uint8_t *buf,
size_t len)
1110 if (!s_csess.active)
1114 int ret = mbedtls_ssl_read(&s_csess.ssl, buf, len);
1119 if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE)
1126int pc_tls_client_session_write(
const uint8_t *data,
size_t len)
1128 if (!s_csess.active)
1136 int ret = mbedtls_ssl_write(&s_csess.ssl, data + sent, len - sent);
1139 sent += (size_t)ret;
1143 if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE)
1157void pc_tls_client_session_end()
1159 if (!s_csess.active)
1163 mbedtls_ssl_close_notify(&s_csess.ssl);
1164 mbedtls_ssl_free(&s_csess.ssl);
1165 mbedtls_ssl_config_free(&s_csess.conf);
1166 s_csess.active =
false;
Pluggable monotonic clock for all library timing.
void pcdelay(uint32_t ms)
Block for at least ms milliseconds - the library's single delay primitive.
#define PC_TLS_TICKET_LIFETIME_S
Session-ticket lifetime / key-rotation period in seconds (see PC_ENABLE_TLS_RESUMPTION).
#define PC_TLS_ARENA_SIZE
Bytes of the static BSS arena mbedTLS allocates from (PC_ENABLE_TLS).
struct tcp_pcb * pcb
lwIP PCB; null when slot is free.
TcpConn conn_pool[CONN_POOL_SLOTS]
Static pool of connection contexts. Defined in tcp.cpp. Sized CONN_POOL_SLOTS: MAX_CONNS TCP slots pl...
bool pc_conn_raw_send(struct tcp_pcb *pcb, const void *data, u16_t len)
Write raw bytes straight to pcb (no TLS), context-safe.
Layer 4 (Transport) - TCP connection pool, ring buffers, and lwIP integration.
Deterministic TLS engine: mbedTLS over a static memory pool (PC_ENABLE_TLS).