mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 22:20:49 +02:00
3720a9496c
Merging TranslateReturnCode into wolfSSL_LastError dropped the IP_SOCK_getsockopt(SO_ERROR) lookup emNET integrations need to retrieve the canonical IP_ERR_* for a failed recv/send, leaving a broken branch that returned the raw value and mishandled the POSIX-facade convention. Restore the historic lookup (fixing the optlen pointer-vs-int typo along the way) and add a CI test that builds wolfSSL with -DWOLFSSL_EMNET against a clean-room shim providing an emNET-faithful IP_SOCK_getsockopt (SO_ERROR-then-errno fallback, since Linux does not stash EAGAIN in SO_ERROR); recv/send fall through to glibc.
83 lines
2.8 KiB
C
83 lines
2.8 KiB
C
/* emnet_shim.c -- POSIX-backed shim for the emNET (embOS/IP) socket ABI
|
|
* used by wolfSSL when WOLFSSL_EMNET is defined.
|
|
*
|
|
* Provides the canonical error lookup path wolfSSL's wolfSSL_LastError
|
|
* relies on: IP_SOCK_getsockopt(SO_ERROR) returns the pending IP_ERR_*
|
|
* for a socket, as required by UM07001's emNET API contract. On top of
|
|
* Linux BSD sockets this is emulated by consulting POSIX SO_ERROR plus
|
|
* the thread-local errno (because Linux does not store transient
|
|
* would-block conditions in SO_ERROR).
|
|
*/
|
|
|
|
#include "IP/IP.h"
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <errno.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
|
|
/* Translate a POSIX errno value into the emNET IP_ERR_* space. */
|
|
static int emnet_errno_to_ip_err(int err)
|
|
{
|
|
/* Linux, where this shim runs in CI, defines EWOULDBLOCK == EAGAIN,
|
|
* so EAGAIN covers both. */
|
|
switch (err) {
|
|
case EAGAIN:
|
|
return IP_ERR_WOULD_BLOCK;
|
|
case ECONNRESET:
|
|
return IP_ERR_CONN_RESET;
|
|
case ECONNREFUSED:
|
|
return IP_ERR_CONN_REFUSED;
|
|
case ECONNABORTED:
|
|
return IP_ERR_CONN_ABORTED;
|
|
case EPIPE:
|
|
return IP_ERR_PIPE;
|
|
default:
|
|
return IP_ERR_FAULT;
|
|
}
|
|
}
|
|
|
|
/* IP_SOCK_getsockopt: emulates the emNET ABI on top of POSIX. This is
|
|
* the canonical error source for WOLFSSL_EMNET code paths - wolfSSL
|
|
* calls it after a negative recv/send return to retrieve the real
|
|
* IP_ERR_* value.
|
|
*
|
|
* For SO_ERROR we deliberately diverge from a pure POSIX pass-through:
|
|
* Linux stores sticky socket errors (ECONNRESET etc.) in SO_ERROR but
|
|
* does NOT store transient would-block conditions (EAGAIN/EWOULDBLOCK)
|
|
* there - those live only in thread-local errno after the failing
|
|
* syscall. Real emNET's SO_ERROR does carry would-block. To reproduce
|
|
* that contract here, read POSIX SO_ERROR first, fall back to errno
|
|
* when SO_ERROR is empty, then translate into the IP_ERR_* space. */
|
|
int IP_SOCK_getsockopt(int hSock, int Level, int Name,
|
|
void *pVal, int ValLen)
|
|
{
|
|
if (pVal == NULL || ValLen <= 0) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
if (Level == SOL_SOCKET && Name == SO_ERROR
|
|
&& ValLen >= (int)sizeof(int)) {
|
|
int saved_errno = errno;
|
|
int so_err = 0;
|
|
socklen_t posix_len = (socklen_t)sizeof(so_err);
|
|
int ip_err;
|
|
|
|
(void)getsockopt(hSock, SOL_SOCKET, SO_ERROR, &so_err, &posix_len);
|
|
if (so_err == 0)
|
|
so_err = saved_errno;
|
|
|
|
ip_err = emnet_errno_to_ip_err(so_err);
|
|
memcpy(pVal, &ip_err, sizeof(ip_err));
|
|
return 0;
|
|
}
|
|
|
|
/* Pass-through for other options. */
|
|
{
|
|
socklen_t posix_len = (socklen_t)ValLen;
|
|
return getsockopt(hSock, Level, Name, pVal, &posix_len);
|
|
}
|
|
}
|