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.
12- *
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.
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).
1810 */
1911
2012#include "IP/IP.h"
2517#include <stddef.h>
2618#include <string.h>
2719
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-
3220/* Translate a POSIX errno value into the emNET IP_ERR_* space. */
3321static int emnet_errno_to_ip_err (int err )
3422{
@@ -50,54 +38,45 @@ static int emnet_errno_to_ip_err(int err)
5038 }
5139}
5240
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 )
41+ /* IP_SOCK_getsockopt: emulates the emNET ABI on top of POSIX. This is
42+ * the canonical error source for WOLFSSL_EMNET code paths - wolfSSL
43+ * calls it after a negative recv/send return to retrieve the real
44+ * IP_ERR_* value.
45+ *
46+ * For SO_ERROR we deliberately diverge from a pure POSIX pass-through:
47+ * Linux stores sticky socket errors (ECONNRESET etc.) in SO_ERROR but
48+ * does NOT store transient would-block conditions (EAGAIN/EWOULDBLOCK)
49+ * there - those live only in thread-local errno after the failing
50+ * syscall. Real emNET's SO_ERROR does carry would-block. To reproduce
51+ * that contract here, read POSIX SO_ERROR first, fall back to errno
52+ * when SO_ERROR is empty, then translate into the IP_ERR_* space. */
53+ int IP_SOCK_getsockopt (int hSock , int Level , int Name ,
54+ void * pVal , int ValLen )
5855{
59- ssize_t ret = __real_recv ( sd , buf , len , flags );
60- if ( ret < 0 ) {
61- return ( ssize_t ) emnet_errno_to_ip_err ( errno ) ;
56+ if ( pVal == NULL || ValLen <= 0 ) {
57+ errno = EINVAL ;
58+ return -1 ;
6259 }
63- return ret ;
64- }
6560
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- }
61+ if (Level == SOL_SOCKET && Name == SO_ERROR
62+ && ValLen >= (int )sizeof (int )) {
63+ int saved_errno = errno ;
64+ int so_err = 0 ;
65+ socklen_t posix_len = (socklen_t )sizeof (so_err );
66+ int ip_err ;
7467
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 ;
68+ (void )getsockopt (hSock , SOL_SOCKET , SO_ERROR , & so_err , & posix_len );
69+ if (so_err == 0 )
70+ so_err = saved_errno ;
8471
85- if ( optlen == NULL ) {
86- errno = EINVAL ;
87- return -1 ;
72+ ip_err = emnet_errno_to_ip_err ( so_err );
73+ memcpy ( pVal , & ip_err , sizeof ( ip_err )) ;
74+ return 0 ;
8875 }
89- posix_len = (socklen_t )* optlen ;
90- rc = getsockopt (sd , level , optname , optval , & posix_len );
91- * optlen = (int )posix_len ;
9276
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- }
77+ /* Pass-through for other options. */
78+ {
79+ socklen_t posix_len = (socklen_t )ValLen ;
80+ return getsockopt (hSock , Level , Name , pVal , & posix_len );
10181 }
102- return rc ;
10382}
0 commit comments