11/* emnet_shim.c -- POSIX-backed shim for the emNET (embOS/IP) socket ABI
22 * used by wolfSSL when WOLFSSL_EMNET is defined.
33 *
4- * The goal is to reproduce the error-reporting contract of emNET on top
5- * of stock Linux BSD sockets: when the underlying socket signals
6- * would-block, connection reset, etc., the shim surfaces the
7- * corresponding IP_ERR_* negative constant (emNET convention) instead
8- * of -1/errno (POSIX convention). This is exactly what wolfSSL's
9- * WOLFSSL_EMNET branch in wolfio.h/wolfio.c was written to consume, so
10- * CI can drive the non-blocking handshake paths without the real
11- * SEGGER stack.
4+ * Provides the canonical error lookup path wolfSSL's wolfSSL_LastError
5+ * relies on: IP_SOCK_getsockopt(SO_ERROR) returns the pending IP_ERR_*
6+ * for a socket, as required by UM07001's emNET API contract. On top of
7+ * Linux BSD sockets this is emulated by consulting POSIX SO_ERROR plus
8+ * the thread-local errno (because Linux does not store transient
9+ * would-block conditions in SO_ERROR).
1210 *
13- * Linker wrapping:
14- * -Wl,--wrap=recv,--wrap=send
15- * hooks wolfSSL's RECV_FUNCTION/SEND_FUNCTION (which are the
16- * unqualified POSIX send/recv on the WOLFSSL_EMNET build) without
17- * patching any wolfSSL source .
11+ * The paired native-convention wrapper (emnet_shim_wrap.c) hooks
12+ * recv/send via -Wl,--wrap to also make the raw return value match
13+ * the native emNET ABI; that file is only linked into the native test
14+ * binary, whereas this translation unit is shared by both test
15+ * variants .
1816 */
1917
2018#include "IP/IP.h"
2523#include <stddef.h>
2624#include <string.h>
2725
28- /* Forward declarations for the linker's --wrap mechanism. */
29- ssize_t __real_recv (int sd , void * buf , size_t len , int flags );
30- ssize_t __real_send (int sd , const void * buf , size_t len , int flags );
31-
32- /* Translate a POSIX errno value into the emNET IP_ERR_* space. */
33- static int emnet_errno_to_ip_err (int err )
26+ /* Translate a POSIX errno value into the emNET IP_ERR_* space. Shared
27+ * with the --wrap wrappers in emnet_shim_wrap.c, so not static. */
28+ int emnet_errno_to_ip_err (int err )
3429{
3530 /* Linux, where this shim runs in CI, defines EWOULDBLOCK == EAGAIN,
3631 * so EAGAIN covers both. */
@@ -50,54 +45,45 @@ static int emnet_errno_to_ip_err(int err)
5045 }
5146}
5247
53- /* recv wrapper: preserve success/close semantics; on error return the
54- * emNET-style negative error code in place of -1/errno. wolfSSL's
55- * TranslateIoReturnCode uses err < 0 to branch into error handling and
56- * then compares against SOCKET_EWOULDBLOCK == IP_ERR_WOULD_BLOCK. */
57- ssize_t __wrap_recv (int sd , void * buf , size_t len , int flags )
48+ /* IP_SOCK_getsockopt: emulates the emNET ABI on top of POSIX. This is
49+ * the canonical error source for WOLFSSL_EMNET code paths — wolfSSL
50+ * calls it after a negative recv/send return to retrieve the real
51+ * IP_ERR_* value.
52+ *
53+ * For SO_ERROR we deliberately diverge from a pure POSIX pass-through:
54+ * Linux stores sticky socket errors (ECONNRESET etc.) in SO_ERROR but
55+ * does NOT store transient would-block conditions (EAGAIN/EWOULDBLOCK)
56+ * there — those live only in thread-local errno after the failing
57+ * syscall. Real emNET's SO_ERROR does carry would-block. To reproduce
58+ * that contract here, read POSIX SO_ERROR first, fall back to errno
59+ * when SO_ERROR is empty, then translate into the IP_ERR_* space. */
60+ int IP_SOCK_getsockopt (int hSock , int Level , int Name ,
61+ void * pVal , int ValLen )
5862{
59- ssize_t ret = __real_recv ( sd , buf , len , flags );
60- if ( ret < 0 ) {
61- return ( ssize_t ) emnet_errno_to_ip_err ( errno ) ;
63+ if ( pVal == NULL || ValLen <= 0 ) {
64+ errno = EINVAL ;
65+ return -1 ;
6266 }
63- return ret ;
64- }
6567
66- ssize_t __wrap_send (int sd , const void * buf , size_t len , int flags )
67- {
68- ssize_t ret = __real_send (sd , buf , len , flags );
69- if (ret < 0 ) {
70- return (ssize_t )emnet_errno_to_ip_err (errno );
71- }
72- return ret ;
73- }
68+ if (Level == SOL_SOCKET && Name == SO_ERROR
69+ && ValLen >= (int )sizeof (int )) {
70+ int saved_errno = errno ;
71+ int so_err = 0 ;
72+ socklen_t posix_len = (socklen_t )sizeof (so_err );
73+ int ip_err ;
7474
75- /* IP_SOCK_getsockopt: kept to satisfy the emNET ABI surface expected
76- * by WOLFSSL_EMNET-linked code. Delegates to POSIX getsockopt and, for
77- * SO_ERROR, maps the returned POSIX errno value into emNET's IP_ERR_*
78- * space so callers see emNET-style error reporting. */
79- int IP_SOCK_getsockopt (int sd , int level , int optname ,
80- void * optval , int * optlen )
81- {
82- socklen_t posix_len ;
83- int rc ;
75+ (void )getsockopt (hSock , SOL_SOCKET , SO_ERROR , & so_err , & posix_len );
76+ if (so_err == 0 )
77+ so_err = saved_errno ;
8478
85- if ( optlen == NULL ) {
86- errno = EINVAL ;
87- return -1 ;
79+ ip_err = emnet_errno_to_ip_err ( so_err );
80+ memcpy ( pVal , & ip_err , sizeof ( ip_err )) ;
81+ return 0 ;
8882 }
89- posix_len = (socklen_t )* optlen ;
90- rc = getsockopt (sd , level , optname , optval , & posix_len );
91- * optlen = (int )posix_len ;
9283
93- if (rc == 0 && level == SOL_SOCKET && optname == SO_ERROR
94- && optval != NULL && posix_len >= (socklen_t )sizeof (int )) {
95- int so_err ;
96- memcpy (& so_err , optval , sizeof (so_err ));
97- if (so_err != 0 ) {
98- so_err = emnet_errno_to_ip_err (so_err );
99- memcpy (optval , & so_err , sizeof (so_err ));
100- }
84+ /* Pass-through for other options. */
85+ {
86+ socklen_t posix_len = (socklen_t )ValLen ;
87+ return getsockopt (hSock , Level , Name , pVal , & posix_len );
10188 }
102- return rc ;
10389}
0 commit comments