Commit b69282a759 for openssl.org

commit b69282a759b0ae83385c99a540be5ab2af069586
Author: Jakub Zelenka <jakub.zelenka@openssl.foundation>
Date:   Fri Jun 12 13:53:26 2026 +0200

    Add BIO bss_acpt test

    Assisted-by: Claude:claude-opus-4-8

    Reviewed-by: Richard Levitte <levitte@openssl.org>
    Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
    MergeDate: Thu Jul  9 17:39:20 2026
    (Merged from https://github.com/openssl/openssl/pull/30788)

diff --git a/crypto/bio/bio_local.h b/crypto/bio/bio_local.h
index d272eb1861..4e2e974039 100644
--- a/crypto/bio/bio_local.h
+++ b/crypto/bio/bio_local.h
@@ -154,6 +154,26 @@ typedef struct bio_connect_st {
     BIO *dgram_bio;
 } BIO_CONNECT;

+typedef struct bio_accept_st {
+    int state;
+    int accept_family;
+    int bind_mode; /* Socket mode for BIO_listen */
+    int accepted_mode; /* Socket mode for BIO_accept (set on accepted sock) */
+    char *param_addr;
+    char *param_serv;
+
+    int accept_sock;
+
+    BIO_ADDRINFO *addr_first;
+    const BIO_ADDRINFO *addr_iter;
+    BIO_ADDR cache_accepting_addr; /* Useful if we asked for port 0 */
+    char *cache_accepting_name, *cache_accepting_serv;
+    BIO_ADDR cache_peer_addr;
+    char *cache_peer_name, *cache_peer_serv;
+
+    BIO *bio_chain;
+} BIO_ACCEPT;
+
 #define BIO_CONN_S_BEFORE 1
 #define BIO_CONN_S_GET_ADDR 2
 #define BIO_CONN_S_CREATE_SOCKET 3
@@ -162,6 +182,13 @@ typedef struct bio_connect_st {
 #define BIO_CONN_S_BLOCKED_CONNECT 6
 #define BIO_CONN_S_CONNECT_ERROR 7

+#define BIO_ACPT_S_BEFORE 1
+#define BIO_ACPT_S_GET_ADDR 2
+#define BIO_ACPT_S_CREATE_SOCKET 3
+#define BIO_ACPT_S_LISTEN 4
+#define BIO_ACPT_S_ACCEPT 5
+#define BIO_ACPT_S_OK 6
+
 #ifdef OPENSSL_SYS_VMS
 typedef unsigned int socklen_t;
 #endif
diff --git a/crypto/bio/bss_acpt.c b/crypto/bio/bss_acpt.c
index 1ba91c6592..c9cdba041a 100644
--- a/crypto/bio/bss_acpt.c
+++ b/crypto/bio/bss_acpt.c
@@ -15,26 +15,6 @@

 #ifndef OPENSSL_NO_SOCK

-typedef struct bio_accept_st {
-    int state;
-    int accept_family;
-    int bind_mode; /* Socket mode for BIO_listen */
-    int accepted_mode; /* Socket mode for BIO_accept (set on accepted sock) */
-    char *param_addr;
-    char *param_serv;
-
-    int accept_sock;
-
-    BIO_ADDRINFO *addr_first;
-    const BIO_ADDRINFO *addr_iter;
-    BIO_ADDR cache_accepting_addr; /* Useful if we asked for port 0 */
-    char *cache_accepting_name, *cache_accepting_serv;
-    BIO_ADDR cache_peer_addr;
-    char *cache_peer_name, *cache_peer_serv;
-
-    BIO *bio_chain;
-} BIO_ACCEPT;
-
 static int acpt_write(BIO *h, const char *buf, int num);
 static int acpt_read(BIO *h, char *buf, int size);
 static int acpt_puts(BIO *h, const char *str);
@@ -46,13 +26,6 @@ static void acpt_close_socket(BIO *data);
 static BIO_ACCEPT *BIO_ACCEPT_new(void);
 static void BIO_ACCEPT_free(BIO_ACCEPT *a);

-#define ACPT_S_BEFORE 1
-#define ACPT_S_GET_ADDR 2
-#define ACPT_S_CREATE_SOCKET 3
-#define ACPT_S_LISTEN 4
-#define ACPT_S_ACCEPT 5
-#define ACPT_S_OK 6
-
 static const BIO_METHOD methods_acceptp = {
     BIO_TYPE_ACCEPT,
     "socket accept",
@@ -83,7 +56,7 @@ static int acpt_new(BIO *bi)
     if ((ba = BIO_ACCEPT_new()) == NULL)
         return 0;
     bi->ptr = (char *)ba;
-    ba->state = ACPT_S_BEFORE;
+    ba->state = BIO_ACPT_S_BEFORE;
     bi->shutdown = 1;
     return 1;
 }
@@ -152,7 +125,7 @@ static int acpt_state(BIO *b, BIO_ACCEPT *c)

     for (;;) {
         switch (c->state) {
-        case ACPT_S_BEFORE:
+        case BIO_ACPT_S_BEFORE:
             if (c->param_addr == NULL && c->param_serv == NULL) {
                 ERR_raise_data(ERR_LIB_BIO,
                     BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED,
@@ -174,10 +147,10 @@ static int acpt_state(BIO *b, BIO_ACCEPT *c)
             OPENSSL_free(c->cache_peer_serv);
             c->cache_peer_serv = NULL;

-            c->state = ACPT_S_GET_ADDR;
+            c->state = BIO_ACPT_S_GET_ADDR;
             break;

-        case ACPT_S_GET_ADDR: {
+        case BIO_ACPT_S_GET_ADDR: {
             int family = AF_UNSPEC;
             switch (c->accept_family) {
             case BIO_FAMILY_IPV6:
@@ -213,10 +186,10 @@ static int acpt_state(BIO *b, BIO_ACCEPT *c)
                 goto exit_loop;
             }
             c->addr_iter = c->addr_first;
-            c->state = ACPT_S_CREATE_SOCKET;
+            c->state = BIO_ACPT_S_CREATE_SOCKET;
             break;

-        case ACPT_S_CREATE_SOCKET:
+        case BIO_ACPT_S_CREATE_SOCKET:
             ERR_set_mark();
             s = BIO_socket(BIO_ADDRINFO_family(c->addr_iter),
                 BIO_ADDRINFO_socktype(c->addr_iter),
@@ -238,11 +211,11 @@ static int acpt_state(BIO *b, BIO_ACCEPT *c)
             }
             c->accept_sock = s;
             b->num = s;
-            c->state = ACPT_S_LISTEN;
+            c->state = BIO_ACPT_S_LISTEN;
             s = -1;
             break;

-        case ACPT_S_LISTEN: {
+        case BIO_ACPT_S_LISTEN: {
             if (!BIO_listen(c->accept_sock,
                     BIO_ADDRINFO_address(c->addr_iter),
                     c->bind_mode)) {
@@ -271,14 +244,14 @@ static int acpt_state(BIO *b, BIO_ACCEPT *c)
             OPENSSL_free(c->cache_accepting_serv);
             c->cache_accepting_name = BIO_ADDR_hostname_string(&c->cache_accepting_addr, 1);
             c->cache_accepting_serv = BIO_ADDR_service_string(&c->cache_accepting_addr, 1);
-            c->state = ACPT_S_ACCEPT;
+            c->state = BIO_ACPT_S_ACCEPT;
             s = -1;
             ret = 1;
             goto end;

-        case ACPT_S_ACCEPT:
+        case BIO_ACPT_S_ACCEPT:
             if (b->next_bio != NULL) {
-                c->state = ACPT_S_OK;
+                c->state = BIO_ACPT_S_OK;
                 break;
             }
             BIO_clear_retry_flags(b);
@@ -334,14 +307,14 @@ static int acpt_state(BIO *b, BIO_ACCEPT *c)

             c->cache_peer_name = BIO_ADDR_hostname_string(&c->cache_peer_addr, 1);
             c->cache_peer_serv = BIO_ADDR_service_string(&c->cache_peer_addr, 1);
-            c->state = ACPT_S_OK;
+            c->state = BIO_ACPT_S_OK;
             bio = NULL;
             ret = 1;
             goto end;

-        case ACPT_S_OK:
+        case BIO_ACPT_S_OK:
             if (b->next_bio == NULL) {
-                c->state = ACPT_S_ACCEPT;
+                c->state = BIO_ACPT_S_ACCEPT;
                 break;
             }
             ret = 1;
@@ -412,7 +385,7 @@ static long acpt_ctrl(BIO *b, int cmd, long num, void *ptr)
     switch (cmd) {
     case BIO_CTRL_RESET:
         ret = 0;
-        data->state = ACPT_S_BEFORE;
+        data->state = BIO_ACPT_S_BEFORE;
         acpt_close_socket(b);
         BIO_ADDRINFO_free(data->addr_first);
         data->addr_first = NULL;
@@ -474,7 +447,7 @@ static long acpt_ctrl(BIO *b, int cmd, long num, void *ptr)
     case BIO_C_SET_FD:
         b->num = *((int *)ptr);
         data->accept_sock = b->num;
-        data->state = ACPT_S_ACCEPT;
+        data->state = BIO_ACPT_S_ACCEPT;
         b->shutdown = (int)num;
         b->init = 1;
         break;
diff --git a/test/unit/build.info b/test/unit/build.info
index cf2a748418..ae53ad8d61 100644
--- a/test/unit/build.info
+++ b/test/unit/build.info
@@ -6,6 +6,14 @@ INCLUDE[crypto/bio/test_bio_addr]=../../include ../../crypto/bio
 DEPEND[crypto/bio/test_bio_addr]=../../libcrypto.a
 WRAP[crypto/bio/test_bio_addr]=BIO_sock_init getnameinfo freeaddrinfo

+PROGRAMS{noinst}=crypto/bio/test_bss_acpt
+SOURCE[crypto/bio/test_bss_acpt]=crypto/bio/test_bss_acpt.c
+WRAP[crypto/bio/test_bss_acpt]=BIO_lookup BIO_socket BIO_listen \
+    BIO_accept_ex BIO_sock_info BIO_sock_should_retry BIO_closesocket \
+    BIO_ADDR_hostname_string BIO_ADDR_service_string
+INCLUDE[crypto/bio/test_bss_acpt]=../../include ../../crypto/bio
+DEPEND[crypto/bio/test_bss_acpt]=../../libcrypto.a
+
 PROGRAMS{noinst}=crypto/bio/test_bss_conn
 SOURCE[crypto/bio/test_bss_conn]=crypto/bio/test_bss_conn.c
 WRAP[crypto/bio/test_bss_conn]=BIO_lookup BIO_socket BIO_connect \
diff --git a/test/unit/crypto/bio/test_bss_acpt.c b/test/unit/crypto/bio/test_bss_acpt.c
new file mode 100644
index 0000000000..4a51c27373
--- /dev/null
+++ b/test/unit/crypto/bio/test_bss_acpt.c
@@ -0,0 +1,1054 @@
+/*
+ * Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "internal/sockets.h"
+
+#ifndef OPENSSL_NO_SOCK
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <netinet/in.h>
+#include <cmocka.h>
+#include "bio_local.h"
+
+#define FAKE_SOCKET 42
+
+/*
+ * Fake addrinfo used across state machine tests.  g_addrinfo1.bai_next is
+ * NULL by default.  Tests needing a second address temporarily set it to
+ * &g_addrinfo2 and restore it afterwards.
+ */
+static struct sockaddr_in g_sin;
+static BIO_ADDRINFO g_addrinfo1;
+static BIO_ADDRINFO g_addrinfo2;
+
+/* prototypes for __wrap_* (required by -Wmissing-prototypes) */
+int __wrap_BIO_lookup(const char *host, const char *service,
+    enum BIO_lookup_type lookup_type,
+    int family, int socktype, BIO_ADDRINFO **res);
+int __wrap_BIO_socket(int domain, int socktype, int protocol, int options);
+int __wrap_BIO_listen(int sock, const BIO_ADDR *addr, int options);
+int __wrap_BIO_accept_ex(int accept_sock, BIO_ADDR *addr, int options);
+int __wrap_BIO_sock_info(int sock, enum BIO_sock_info_type type,
+    union BIO_sock_info_u *info);
+int __wrap_BIO_sock_should_retry(int i);
+int __wrap_BIO_closesocket(int sock);
+char *__wrap_BIO_ADDR_hostname_string(const BIO_ADDR *ap, int numeric);
+char *__wrap_BIO_ADDR_service_string(const BIO_ADDR *ap, int numeric);
+
+/* wraps */
+
+int __wrap_BIO_lookup(const char *host, const char *service,
+    enum BIO_lookup_type lookup_type,
+    int family, int socktype, BIO_ADDRINFO **res)
+{
+    int rc;
+
+    function_called();
+    check_expected(host);
+    check_expected(service);
+    check_expected(lookup_type);
+    check_expected(family);
+    check_expected(socktype);
+    rc = mock_type(int);
+    if (rc == 1)
+        *res = mock_ptr_type(BIO_ADDRINFO *);
+    return rc;
+}
+
+int __wrap_BIO_socket(int domain, int socktype, int protocol, int options)
+{
+    function_called();
+    check_expected(domain);
+    check_expected(socktype);
+    check_expected(protocol);
+    check_expected(options);
+    return mock_type(int);
+}
+
+int __wrap_BIO_listen(int sock, const BIO_ADDR *addr, int options)
+{
+    function_called();
+    check_expected(sock);
+    check_expected_ptr(addr);
+    check_expected(options);
+    return mock_type(int);
+}
+
+int __wrap_BIO_accept_ex(int accept_sock, BIO_ADDR *addr, int options)
+{
+    function_called();
+    check_expected(accept_sock);
+    check_expected_ptr(addr);
+    check_expected(options);
+    return mock_type(int);
+}
+
+int __wrap_BIO_sock_info(int sock, enum BIO_sock_info_type type,
+    union BIO_sock_info_u *info)
+{
+    function_called();
+    check_expected(sock);
+    check_expected(type);
+    (void)info; /* addr field left untouched; cache addr is zeroed already */
+    return mock_type(int);
+}
+
+int __wrap_BIO_sock_should_retry(int i)
+{
+    function_called();
+    check_expected(i);
+    return mock_type(int);
+}
+
+int __wrap_BIO_closesocket(int sock)
+{
+    function_called();
+    check_expected(sock);
+    return mock_type(int);
+}
+
+/*
+ * The cache_*_name / cache_*_serv pointers get OPENSSL_free()d in
+ * BIO_ACCEPT_free and when a new bind starts, so these wraps must return
+ * heap pointers (or NULL).
+ */
+char *__wrap_BIO_ADDR_hostname_string(const BIO_ADDR *ap, int numeric)
+{
+    function_called();
+    (void)ap;
+    (void)numeric;
+    return mock_ptr_type(char *);
+}
+
+char *__wrap_BIO_ADDR_service_string(const BIO_ADDR *ap, int numeric)
+{
+    function_called();
+    (void)ap;
+    (void)numeric;
+    return mock_ptr_type(char *);
+}
+
+/*
+ * A minimal fake sink BIO.  The accept BIO forwards reads/writes to its
+ * next_bio once a connection is established, so I/O tests push one of these
+ * instead of a real socket BIO.  This keeps acpt_read/acpt_write under test
+ * in isolation: no dependency on sock_read/sock_write, on the libc read/write
+ * syscalls, or on BIO_sock_should_retry.
+ *
+ * The fake read/write return mock_type and, on a non-positive result, set
+ * their own retry flag when asked, so acpt_read/acpt_write's
+ * BIO_copy_next_retry has a real source-of-truth to propagate upward.
+ */
+
+static int fake_sink_read(BIO *b, char *buf, size_t size, size_t *readbytes);
+static int fake_sink_write(BIO *b, const char *buf, size_t size,
+    size_t *written);
+static long fake_sink_ctrl(BIO *b, int cmd, long arg1, void *arg2);
+
+static int fake_sink_read(BIO *b, char *buf, size_t size, size_t *readbytes)
+{
+    int ret;
+
+    function_called();
+    check_expected_ptr(buf);
+    check_expected(size);
+    BIO_clear_retry_flags(b);
+    ret = mock_type(int);
+    if (ret > 0) {
+        *readbytes = (size_t)ret;
+        return 1;
+    }
+    if (mock_type(int))
+        BIO_set_retry_read(b);
+    *readbytes = 0;
+    return ret;
+}
+
+static int fake_sink_write(BIO *b, const char *buf, size_t size,
+    size_t *written)
+{
+    int ret;
+
+    function_called();
+    check_expected_ptr(buf);
+    check_expected(size);
+    BIO_clear_retry_flags(b);
+    ret = mock_type(int);
+    if (ret > 0) {
+        *written = (size_t)ret;
+        return 1;
+    }
+    if (mock_type(int))
+        BIO_set_retry_write(b);
+    *written = 0;
+    return ret;
+}
+
+static long fake_sink_ctrl(BIO *b, int cmd, long arg1, void *arg2)
+{
+    (void)b;
+    (void)arg1;
+    (void)arg2;
+    if (cmd == BIO_CTRL_FLUSH)
+        return 1;
+    return 0;
+}
+
+static BIO_METHOD *fake_sink_method = NULL;
+
+static BIO_METHOD *make_fake_sink_method(void)
+{
+    BIO_METHOD *m = BIO_meth_new(BIO_TYPE_SOURCE_SINK | 0xff, "fake sink");
+
+    assert_non_null(m);
+    assert_true(BIO_meth_set_read_ex(m, fake_sink_read));
+    assert_true(BIO_meth_set_write_ex(m, fake_sink_write));
+    assert_true(BIO_meth_set_ctrl(m, fake_sink_ctrl));
+    return m;
+}
+
+static BIO *make_fake_sink(void)
+{
+    BIO *b = BIO_new(fake_sink_method);
+
+    assert_non_null(b);
+    BIO_set_init(b, 1);
+    return b;
+}
+
+/* expectations */
+
+static void expect_BIO_lookup(BIO_ADDRINFO *res, int rc)
+{
+    expect_function_call(__wrap_BIO_lookup);
+    expect_any(__wrap_BIO_lookup, host);
+    expect_any(__wrap_BIO_lookup, service);
+    expect_value(__wrap_BIO_lookup, lookup_type, BIO_LOOKUP_SERVER);
+    expect_any(__wrap_BIO_lookup, family);
+    expect_any(__wrap_BIO_lookup, socktype);
+    will_return(__wrap_BIO_lookup, rc);
+    if (rc == 1)
+        will_return(__wrap_BIO_lookup, res);
+}
+
+/* options is the literal the state machine passes (always 0 here) */
+static void expect_BIO_socket(int domain, int socktype, int protocol,
+    int options, int rc)
+{
+    expect_function_call(__wrap_BIO_socket);
+    expect_value(__wrap_BIO_socket, domain, domain);
+    expect_value(__wrap_BIO_socket, socktype, socktype);
+    expect_value(__wrap_BIO_socket, protocol, protocol);
+    expect_value(__wrap_BIO_socket, options, options);
+    will_return(__wrap_BIO_socket, rc);
+}
+
+static void expect_BIO_listen(int sock, const BIO_ADDR *addr, int options,
+    int rc)
+{
+    expect_function_call(__wrap_BIO_listen);
+    expect_value(__wrap_BIO_listen, sock, sock);
+    expect_value(__wrap_BIO_listen, addr, addr);
+    expect_value(__wrap_BIO_listen, options, options);
+    will_return(__wrap_BIO_listen, rc);
+}
+
+static void expect_BIO_accept_ex(int sock, int options, int rc)
+{
+    expect_function_call(__wrap_BIO_accept_ex);
+    expect_value(__wrap_BIO_accept_ex, accept_sock, sock);
+    expect_any(__wrap_BIO_accept_ex, addr);
+    expect_value(__wrap_BIO_accept_ex, options, options);
+    will_return(__wrap_BIO_accept_ex, rc);
+}
+
+static void expect_BIO_sock_info(int sock, int rc)
+{
+    expect_function_call(__wrap_BIO_sock_info);
+    expect_value(__wrap_BIO_sock_info, sock, sock);
+    expect_value(__wrap_BIO_sock_info, type, BIO_SOCK_INFO_ADDRESS);
+    will_return(__wrap_BIO_sock_info, rc);
+}
+
+static void expect_BIO_sock_should_retry(int i, int rc)
+{
+    expect_function_call(__wrap_BIO_sock_should_retry);
+    expect_value(__wrap_BIO_sock_should_retry, i, i);
+    will_return(__wrap_BIO_sock_should_retry, rc);
+}
+
+static void expect_BIO_closesocket(int sock, int rc)
+{
+    expect_function_call(__wrap_BIO_closesocket);
+    expect_value(__wrap_BIO_closesocket, sock, sock);
+    will_return(__wrap_BIO_closesocket, rc);
+}
+
+/* The returned pointer is heap allocated; ownership passes to the BIO. */
+static void expect_BIO_ADDR_hostname_string(const char *val)
+{
+    expect_function_call(__wrap_BIO_ADDR_hostname_string);
+    will_return(__wrap_BIO_ADDR_hostname_string,
+        val == NULL ? NULL : OPENSSL_strdup(val));
+}
+
+static void expect_BIO_ADDR_service_string(const char *val)
+{
+    expect_function_call(__wrap_BIO_ADDR_service_string);
+    will_return(__wrap_BIO_ADDR_service_string,
+        val == NULL ? NULL : OPENSSL_strdup(val));
+}
+
+/*
+ * rc is the byte count (>0) or the non-positive result; retry tells the sink
+ * whether to set its own retry flag when rc <= 0.
+ */
+static void expect_fake_sink_read(const void *buf, size_t size, int rc,
+    int retry)
+{
+    expect_function_call(fake_sink_read);
+    expect_value(fake_sink_read, buf, buf);
+    expect_value(fake_sink_read, size, size);
+    will_return(fake_sink_read, rc);
+    if (rc <= 0)
+        will_return(fake_sink_read, retry);
+}
+
+static void expect_fake_sink_write(const void *buf, size_t size, int rc,
+    int retry)
+{
+    expect_function_call(fake_sink_write);
+    expect_value(fake_sink_write, buf, buf);
+    expect_value(fake_sink_write, size, size);
+    will_return(fake_sink_write, rc);
+    if (rc <= 0)
+        will_return(fake_sink_write, retry);
+}
+
+/*
+ * The LISTEN state always emits, in order: BIO_listen, BIO_sock_info, then a
+ * hostname_string + service_string pair for the accepting address cache.
+ */
+static void expect_listen_sequence(int sock)
+{
+    expect_BIO_listen(sock, (const BIO_ADDR *)&g_sin, 0, 1);
+    expect_BIO_sock_info(sock, 1);
+    expect_BIO_ADDR_hostname_string("127.0.0.1");
+    expect_BIO_ADDR_service_string("443");
+}
+
+/* helpers */
+
+static BIO_ACCEPT *get_data(BIO *bio)
+{
+    return (BIO_ACCEPT *)bio->ptr;
+}
+
+/*
+ * Reset socket bookkeeping so acpt_close_socket is a no-op during free, and
+ * clear the address iterators that point at static storage.
+ */
+static void reset_for_teardown(BIO *bio)
+{
+    BIO_ACCEPT *data = get_data(bio);
+
+    bio->num = (int)INVALID_SOCKET;
+    data->accept_sock = (int)INVALID_SOCKET;
+    data->addr_first = NULL;
+    data->addr_iter = NULL;
+    data->state = BIO_ACPT_S_BEFORE;
+}
+
+/* setup / teardown */
+
+static int setup(void **state)
+{
+    BIO *bio = BIO_new(BIO_s_accept());
+
+    assert_non_null(bio);
+    *state = bio;
+    return 0;
+}
+
+static int teardown(void **state)
+{
+    if (*state != NULL)
+        BIO_free(*state);
+    return 0;
+}
+
+/*
+ * I/O tests pre-establish state=OK and push a fake sink BIO so the state
+ * machine exits immediately and reads/writes are forwarded to next_bio.
+ */
+static int setup_io(void **state)
+{
+    BIO *bio, *sink;
+    BIO_ACCEPT *data;
+
+    if (setup(state) != 0)
+        return -1;
+    bio = *state;
+    data = get_data(bio);
+    data->state = BIO_ACPT_S_OK;
+    data->accept_sock = FAKE_SOCKET;
+    bio->num = FAKE_SOCKET;
+    bio->init = 1;
+
+    sink = make_fake_sink();
+    assert_non_null(BIO_push(bio, sink));
+    return 0;
+}
+
+static int teardown_io(void **state)
+{
+    if (*state != NULL) {
+        reset_for_teardown(*state);
+        /* BIO_free_all to also release the pushed fake sink BIO. */
+        BIO_free_all(*state);
+        *state = NULL;
+    }
+    return 0;
+}
+
+static int group_setup(void **state)
+{
+    (void)state;
+
+    fake_sink_method = make_fake_sink_method();
+
+    memset(&g_sin, 0, sizeof(g_sin));
+    g_sin.sin_family = AF_INET;
+    g_sin.sin_port = htons(443);
+    g_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+    memset(&g_addrinfo1, 0, sizeof(g_addrinfo1));
+    g_addrinfo1.bai_family = AF_INET;
+    g_addrinfo1.bai_socktype = SOCK_STREAM;
+    g_addrinfo1.bai_protocol = IPPROTO_TCP;
+    g_addrinfo1.bai_addrlen = sizeof(g_sin);
+    g_addrinfo1.bai_addr = (struct sockaddr *)&g_sin;
+    g_addrinfo1.bai_next = NULL;
+
+    memcpy(&g_addrinfo2, &g_addrinfo1, sizeof(g_addrinfo1));
+    g_addrinfo2.bai_next = NULL;
+
+    return 0;
+}
+
+static int group_teardown(void **state)
+{
+    (void)state;
+    BIO_meth_free(fake_sink_method);
+    fake_sink_method = NULL;
+    return 0;
+}
+
+/* acpt_new */
+
+static void test_acpt_new(void **state)
+{
+    BIO *bio = *state;
+    BIO_ACCEPT *data = get_data(bio);
+
+    assert_non_null(data);
+    assert_int_equal(data->state, BIO_ACPT_S_BEFORE);
+    assert_int_equal(data->accept_family, BIO_FAMILY_IPANY);
+    assert_int_equal(data->accept_sock, (int)INVALID_SOCKET);
+    assert_null(data->param_addr);
+    assert_null(data->param_serv);
+    assert_null(data->addr_first);
+    assert_null(data->bio_chain);
+    assert_int_equal(bio->num, (int)INVALID_SOCKET);
+    assert_int_equal(bio->init, 0);
+    assert_int_equal(bio->shutdown, 1);
+}
+
+/* acpt_free */
+
+static void test_acpt_free_no_shutdown(void **state)
+{
+    /* shutdown=0: acpt_close_socket and BIO_ACCEPT_free are both skipped */
+    BIO *bio = BIO_new(BIO_s_accept());
+
+    assert_non_null(bio);
+    bio->shutdown = BIO_NOCLOSE;
+    BIO_free(bio);
+    *state = NULL;
+}
+
+/* acpt_close_socket (via BIO_CTRL_RESET) */
+
+static void test_close_socket_none(void **state)
+{
+    /* accept_sock == INVALID_SOCKET: no closesocket expected */
+    assert_int_equal(BIO_ctrl(*state, BIO_CTRL_RESET, 0, NULL), 0);
+    assert_int_equal(get_data(*state)->state, BIO_ACPT_S_BEFORE);
+}
+
+/* acpt_state via BIO_C_DO_STATE_MACHINE (BIO_do_accept) */
+
+static void test_acpt_state_no_addr(void **state)
+{
+    /* BEFORE with no addr and no serv -> error */
+    assert_true(BIO_do_accept(*state) <= 0);
+}
+
+static void test_acpt_state_unsupported_family(void **state)
+{
+    BIO *bio = *state;
+    BIO_ACCEPT *data = get_data(bio);
+
+    data->param_serv = OPENSSL_strdup("443");
+    data->accept_family = 9999;
+
+    assert_true(BIO_do_accept(bio) <= 0);
+}
+
+static void test_acpt_state_lookup_fails(void **state)
+{
+    BIO *bio = *state;
+    BIO_ACCEPT *data = get_data(bio);
+
+    data->param_serv = OPENSSL_strdup("443");
+
+    expect_BIO_lookup(NULL, 0);
+    assert_true(BIO_do_accept(bio) <= 0);
+}
+
+static void test_acpt_state_lookup_empty(void **state)
+{
+    /* BIO_lookup succeeds but returns no addresses */
+    BIO *bio = *state;
+    BIO_ACCEPT *data = get_data(bio);
+
+    data->param_serv = OPENSSL_strdup("443");
+
+    expect_BIO_lookup(NULL, 1); /* rc==1 but res stays NULL */
+    assert_true(BIO_do_accept(bio) <= 0);
+}
+
+static void test_acpt_state_socket_fails(void **state)
+{
+    /* Pre-set CREATE_SOCKET, single address: BIO_socket fails -> error */
+    BIO *bio = *state;
+    BIO_ACCEPT *data = get_data(bio);
+
+    data->state = BIO_ACPT_S_CREATE_SOCKET;
+    data->addr_iter = &g_addrinfo1; /* bai_next == NULL */
+
+    expect_BIO_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0,
+        (int)INVALID_SOCKET);
+    assert_true(BIO_do_accept(bio) <= 0);
+
+    reset_for_teardown(bio);
+}
+
+static void test_acpt_state_socket_next_addr(void **state)
+{
+    /*
+     * Two addresses: first BIO_socket fails, iterator advances, second
+     * BIO_socket also fails -> clean error exit.
+     */
+    BIO *bio = *state;
+    BIO_ACCEPT *data = get_data(bio);
+
+    g_addrinfo1.bai_next = &g_addrinfo2;
+    data->state = BIO_ACPT_S_CREATE_SOCKET;
+    data->addr_iter = &g_addrinfo1;
+
+    expect_BIO_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0,
+        (int)INVALID_SOCKET);
+    expect_BIO_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0,
+        (int)INVALID_SOCKET);
+    assert_true(BIO_do_accept(bio) <= 0);
+
+    g_addrinfo1.bai_next = NULL;
+    reset_for_teardown(bio);
+}
+
+static void test_acpt_state_listen_fails(void **state)
+{
+    /* CREATE_SOCKET succeeds, BIO_listen fails -> closesocket, error */
+    BIO *bio = *state;
+    BIO_ACCEPT *data = get_data(bio);
+
+    data->state = BIO_ACPT_S_CREATE_SOCKET;
+    data->addr_iter = &g_addrinfo1;
+
+    expect_BIO_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, FAKE_SOCKET);
+    expect_BIO_listen(FAKE_SOCKET, (const BIO_ADDR *)&g_sin, 0, 0);
+    expect_BIO_closesocket(FAKE_SOCKET, 0);
+
+    assert_true(BIO_do_accept(bio) <= 0);
+    assert_int_equal(data->accept_sock, (int)INVALID_SOCKET);
+
+    reset_for_teardown(bio);
+}
+
+static void test_acpt_state_sock_info_fails(void **state)
+{
+    /* listen ok, BIO_sock_info fails -> closesocket, error */
+    BIO *bio = *state;
+    BIO_ACCEPT *data = get_data(bio);
+
+    data->state = BIO_ACPT_S_CREATE_SOCKET;
+    data->addr_iter = &g_addrinfo1;
+
+    expect_BIO_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, FAKE_SOCKET);
+    expect_BIO_listen(FAKE_SOCKET, (const BIO_ADDR *)&g_sin, 0, 1);
+    expect_BIO_sock_info(FAKE_SOCKET, 0);
+    expect_BIO_closesocket(FAKE_SOCKET, 0);
+
+    assert_true(BIO_do_accept(bio) <= 0);
+    assert_int_equal(data->accept_sock, (int)INVALID_SOCKET);
+
+    reset_for_teardown(bio);
+}
+
+static void test_acpt_state_bind_ok(void **state)
+{
+    /*
+     * Full bind path: BEFORE -> GET_ADDR -> CREATE_SOCKET -> LISTEN returns 1
+     * and the machine stops at BIO_ACPT_S_ACCEPT (next_bio is NULL).
+     */
+    BIO *bio = *state;
+    BIO_ACCEPT *data = get_data(bio);
+
+    data->param_serv = OPENSSL_strdup("443");
+
+    expect_BIO_lookup(&g_addrinfo1, 1);
+    expect_BIO_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, FAKE_SOCKET);
+    expect_listen_sequence(FAKE_SOCKET);
+
+    assert_int_equal(BIO_do_accept(bio), 1);
+    assert_int_equal(data->state, BIO_ACPT_S_ACCEPT);
+    assert_int_equal(data->accept_sock, FAKE_SOCKET);
+    assert_string_equal(data->cache_accepting_name, "127.0.0.1");
+    assert_string_equal(data->cache_accepting_serv, "443");
+
+    reset_for_teardown(bio);
+}
+
+static void test_acpt_state_accept_retry(void **state)
+{
+    /* Pre-set ACCEPT, no next_bio: BIO_accept_ex retryable -> special flag */
+    BIO *bio = *state;
+    BIO_ACCEPT *data = get_data(bio);
+
+    data->state = BIO_ACPT_S_ACCEPT;
+    data->accept_sock = FAKE_SOCKET;
+    bio->num = FAKE_SOCKET;
+
+    expect_BIO_accept_ex(FAKE_SOCKET, 0, -1);
+    expect_BIO_sock_should_retry(-1, 1);
+
+    assert_true(BIO_do_accept(bio) <= 0);
+    assert_true(BIO_should_io_special(bio));
+    assert_int_equal(bio->retry_reason, BIO_RR_ACCEPT);
+
+    reset_for_teardown(bio);
+}
+
+static void test_acpt_state_accept_error(void **state)
+{
+    /* Pre-set ACCEPT: BIO_accept_ex fails, not retryable -> error */
+    BIO *bio = *state;
+    BIO_ACCEPT *data = get_data(bio);
+
+    data->state = BIO_ACPT_S_ACCEPT;
+    data->accept_sock = FAKE_SOCKET;
+    bio->num = FAKE_SOCKET;
+
+    expect_BIO_accept_ex(FAKE_SOCKET, 0, -1);
+    expect_BIO_sock_should_retry(-1, 0);
+
+    assert_true(BIO_do_accept(bio) <= 0);
+
+    reset_for_teardown(bio);
+}
+
+static void test_acpt_state_already_ok_no_next(void **state)
+{
+    /*
+     * State OK but next_bio NULL: machine drops back to ACCEPT and tries to
+     * accept. We make that accept fail non-retryably for a clean exit.
+     */
+    BIO *bio = *state;
+    BIO_ACCEPT *data = get_data(bio);
+
+    data->state = BIO_ACPT_S_OK;
+    data->accept_sock = FAKE_SOCKET;
+    bio->num = FAKE_SOCKET;
+
+    expect_BIO_accept_ex(FAKE_SOCKET, 0, -1);
+    expect_BIO_sock_should_retry(-1, 0);
+
+    assert_true(BIO_do_accept(bio) <= 0);
+
+    reset_for_teardown(bio);
+}
+
+/* acpt_read / acpt_write (state already OK with a pushed fake sink BIO) */
+
+static void test_acpt_read_forwards(void **state)
+{
+    BIO *bio = *state;
+    char buf[8] = { 0 };
+
+    expect_fake_sink_read(buf, 8, 8, 0);
+    assert_int_equal(BIO_read(bio, buf, 8), 8);
+    assert_false(BIO_should_retry(bio));
+}
+
+static void test_acpt_read_forwards_retry(void **state)
+{
+    /*
+     * The fake sink returns a retryable read and sets its own retry-read
+     * flag; acpt_read must propagate it onto the accept BIO via
+     * BIO_copy_next_retry.
+     */
+    BIO *bio = *state;
+    char buf[8] = { 0 };
+
+    expect_fake_sink_read(buf, 8, -1, 1);
+    assert_true(BIO_read(bio, buf, 8) <= 0);
+    assert_true(BIO_should_read(bio));
+    assert_true(BIO_should_retry(bio));
+}
+
+static void test_acpt_write_forwards(void **state)
+{
+    BIO *bio = *state;
+    const char buf[] = "hello";
+
+    expect_fake_sink_write(buf, 5, 5, 0);
+    assert_int_equal(BIO_write(bio, buf, 5), 5);
+    assert_false(BIO_should_retry(bio));
+}
+
+static void test_acpt_write_forwards_retry(void **state)
+{
+    BIO *bio = *state;
+    const char buf[] = "hello";
+
+    expect_fake_sink_write(buf, 5, -1, 1);
+    assert_true(BIO_write(bio, buf, 5) <= 0);
+    assert_true(BIO_should_write(bio));
+    assert_true(BIO_should_retry(bio));
+}
+
+static void test_acpt_puts_forwards(void **state)
+{
+    BIO *bio = *state;
+    const char *str = "hello";
+
+    expect_fake_sink_write(str, 5, 5, 0);
+    assert_int_equal(BIO_puts(bio, str), 5);
+}
+
+/* acpt_ctrl */
+
+static void test_acpt_ctrl_reset_clears_addrs(void **state)
+{
+    BIO *bio = *state;
+    BIO_ACCEPT *data = get_data(bio);
+
+    data->addr_first = NULL; /* keep BIO_ADDRINFO_free a no-op */
+    data->addr_iter = &g_addrinfo1;
+    bio->flags = BIO_FLAGS_SHOULD_RETRY;
+
+    assert_int_equal(BIO_ctrl(bio, BIO_CTRL_RESET, 0, NULL), 0);
+    assert_null(data->addr_first);
+    assert_null(data->addr_iter);
+    assert_int_equal(bio->flags, 0);
+    assert_int_equal(data->state, BIO_ACPT_S_BEFORE);
+}
+
+static void test_acpt_ctrl_set_accept_name(void **state)
+{
+    BIO *bio = *state;
+    BIO_ACCEPT *data = get_data(bio);
+
+    assert_true(BIO_set_accept_name(bio, "host.example:443") > 0);
+    assert_int_equal(bio->init, 1);
+    assert_string_equal(data->param_addr, "host.example");
+    assert_string_equal(data->param_serv, "443");
+}
+
+static void test_acpt_ctrl_set_accept_port(void **state)
+{
+    BIO *bio = *state;
+    BIO_ACCEPT *data = get_data(bio);
+
+    assert_true(BIO_set_accept_port(bio, "8443") > 0);
+    assert_int_equal(bio->init, 1);
+    assert_string_equal(data->param_serv, "8443");
+}
+
+static void test_acpt_ctrl_set_nbio_accept(void **state)
+{
+    /* toggles BIO_SOCK_NONBLOCK in bind_mode */
+    BIO *bio = *state;
+    BIO_ACCEPT *data = get_data(bio);
+
+    BIO_set_nbio_accept(bio, 1);
+    assert_true(data->bind_mode & BIO_SOCK_NONBLOCK);
+
+    BIO_set_nbio_accept(bio, 0);
+    assert_false(data->bind_mode & BIO_SOCK_NONBLOCK);
+}
+
+static void test_acpt_ctrl_set_accept_bios(void **state)
+{
+    BIO *bio = *state;
+    BIO_ACCEPT *data = get_data(bio);
+    BIO *chain = BIO_new(BIO_s_mem());
+
+    assert_non_null(chain);
+    assert_true(BIO_set_accept_bios(bio, chain) > 0);
+    assert_ptr_equal(data->bio_chain, chain);
+    /* freed by BIO_ACCEPT_free in teardown */
+}
+
+static void test_acpt_ctrl_set_accept_ip_family(void **state)
+{
+    BIO *bio = *state;
+    BIO_ACCEPT *data = get_data(bio);
+
+    assert_true(BIO_set_accept_ip_family(bio, BIO_FAMILY_IPV4) > 0);
+    assert_int_equal(data->accept_family, BIO_FAMILY_IPV4);
+}
+
+static void test_acpt_ctrl_set_tfo_accept(void **state)
+{
+    /* toggles BIO_SOCK_TFO in bind_mode */
+    BIO *bio = *state;
+    BIO_ACCEPT *data = get_data(bio);
+
+    BIO_set_tfo_accept(bio, 1);
+    assert_true(data->bind_mode & BIO_SOCK_TFO);
+
+    BIO_set_tfo_accept(bio, 0);
+    assert_false(data->bind_mode & BIO_SOCK_TFO);
+}
+
+static void test_acpt_ctrl_set_nbio(void **state)
+{
+    /* BIO_C_SET_NBIO: toggles BIO_SOCK_NONBLOCK in accepted_mode */
+    BIO *bio = *state;
+    BIO_ACCEPT *data = get_data(bio);
+
+    BIO_set_nbio(bio, 1);
+    assert_true(data->accepted_mode & BIO_SOCK_NONBLOCK);
+
+    BIO_set_nbio(bio, 0);
+    assert_false(data->accepted_mode & BIO_SOCK_NONBLOCK);
+}
+
+static void test_acpt_ctrl_set_fd(void **state)
+{
+    BIO *bio = *state;
+    BIO_ACCEPT *data = get_data(bio);
+
+    BIO_set_fd(bio, FAKE_SOCKET, BIO_NOCLOSE);
+    assert_int_equal(bio->num, FAKE_SOCKET);
+    assert_int_equal(data->accept_sock, FAKE_SOCKET);
+    assert_int_equal(data->state, BIO_ACPT_S_ACCEPT);
+    assert_int_equal(bio->init, 1);
+    assert_int_equal(bio->shutdown, BIO_NOCLOSE);
+
+    reset_for_teardown(bio);
+}
+
+static void test_acpt_ctrl_get_fd(void **state)
+{
+    BIO *bio = *state;
+    BIO_ACCEPT *data = get_data(bio);
+    int fd = -1;
+
+    /* init==0 -> -1 */
+    assert_int_equal(BIO_get_fd(bio, &fd), -1);
+
+    bio->init = 1;
+    data->accept_sock = FAKE_SOCKET;
+    assert_int_equal(BIO_get_fd(bio, &fd), FAKE_SOCKET);
+    assert_int_equal(fd, FAKE_SOCKET);
+
+    bio->init = 0;
+    data->accept_sock = (int)INVALID_SOCKET;
+}
+
+static void test_acpt_ctrl_get_accept_names(void **state)
+{
+    BIO *bio = *state;
+    BIO_ACCEPT *data = get_data(bio);
+    const char *out;
+
+    assert_int_equal(BIO_ctrl(bio, BIO_C_GET_ACCEPT, 0, &out), -1);
+
+    bio->init = 1;
+    data->cache_accepting_name = OPENSSL_strdup("accept.host");
+    data->cache_accepting_serv = OPENSSL_strdup("443");
+    data->cache_peer_name = OPENSSL_strdup("peer.host");
+    data->cache_peer_serv = OPENSSL_strdup("55000");
+
+    assert_string_equal(BIO_get_accept_name(bio), "accept.host");
+    assert_string_equal(BIO_get_accept_port(bio), "443");
+    assert_string_equal(BIO_get_peer_name(bio), "peer.host");
+    assert_string_equal(BIO_get_peer_port(bio), "55000");
+
+    bio->init = 0;
+}
+
+static void test_acpt_ctrl_get_accept_family(void **state)
+{
+    /* AF_INET addr_iter maps to BIO_FAMILY_IPV4 */
+    BIO *bio = *state;
+    BIO_ACCEPT *data = get_data(bio);
+
+    bio->init = 1;
+    data->addr_iter = &g_addrinfo1;
+    assert_int_equal(BIO_get_accept_ip_family(bio), BIO_FAMILY_IPV4);
+    data->addr_iter = NULL;
+    bio->init = 0;
+}
+
+static void test_acpt_ctrl_get_set_close(void **state)
+{
+    BIO *bio = *state;
+
+    bio->shutdown = BIO_NOCLOSE;
+    assert_int_equal(BIO_get_close(bio), BIO_NOCLOSE);
+
+    assert_int_equal(BIO_set_close(bio, BIO_CLOSE), 1);
+    assert_int_equal(bio->shutdown, BIO_CLOSE);
+}
+
+static void test_acpt_ctrl_bind_mode(void **state)
+{
+    BIO *bio = *state;
+    BIO_ACCEPT *data = get_data(bio);
+
+    BIO_set_bind_mode(bio, BIO_SOCK_REUSEADDR);
+    assert_int_equal(data->bind_mode, BIO_SOCK_REUSEADDR);
+    assert_int_equal(BIO_get_bind_mode(bio), BIO_SOCK_REUSEADDR);
+}
+
+static void test_acpt_ctrl_pending_flush(void **state)
+{
+    BIO *bio = *state;
+
+    assert_int_equal(BIO_ctrl(bio, BIO_CTRL_PENDING, 0, NULL), 0);
+    assert_int_equal(BIO_ctrl(bio, BIO_CTRL_WPENDING, 0, NULL), 0);
+    assert_int_equal(BIO_ctrl(bio, BIO_CTRL_FLUSH, 0, NULL), 1);
+}
+
+static void test_acpt_ctrl_eof_no_next(void **state)
+{
+    /* next_bio == NULL -> 0 */
+    assert_int_equal(BIO_ctrl(*state, BIO_CTRL_EOF, 0, NULL), 0);
+}
+
+static void test_acpt_ctrl_default(void **state)
+{
+    assert_int_equal(BIO_ctrl(*state, 9999, 0, NULL), 0);
+}
+
+/* BIO_new_accept convenience constructor */
+
+static void test_bio_new_accept(void **state)
+{
+    BIO *bio = BIO_new_accept("localhost:443");
+    BIO_ACCEPT *data;
+
+    assert_non_null(bio);
+    data = (BIO_ACCEPT *)bio->ptr;
+    assert_string_equal(data->param_addr, "localhost");
+    assert_string_equal(data->param_serv, "443");
+    BIO_free(bio);
+    (void)state;
+}
+
+/* main */
+
+#define ACPT_TEST(name) \
+    cmocka_unit_test_setup_teardown(name, setup, teardown)
+
+#define ACPT_TEST_IO(name) \
+    cmocka_unit_test_setup_teardown(name, setup_io, teardown_io)
+
+int main(void)
+{
+    const struct CMUnitTest tests[] = {
+        /* acpt_new */
+        ACPT_TEST(test_acpt_new),
+        /* acpt_free */
+        ACPT_TEST(test_acpt_free_no_shutdown),
+        /* acpt_close_socket */
+        ACPT_TEST(test_close_socket_none),
+        /* acpt_state */
+        ACPT_TEST(test_acpt_state_no_addr),
+        ACPT_TEST(test_acpt_state_unsupported_family),
+        ACPT_TEST(test_acpt_state_lookup_fails),
+        ACPT_TEST(test_acpt_state_lookup_empty),
+        ACPT_TEST(test_acpt_state_socket_fails),
+        ACPT_TEST(test_acpt_state_socket_next_addr),
+        ACPT_TEST(test_acpt_state_listen_fails),
+        ACPT_TEST(test_acpt_state_sock_info_fails),
+        ACPT_TEST(test_acpt_state_bind_ok),
+        ACPT_TEST(test_acpt_state_accept_retry),
+        ACPT_TEST(test_acpt_state_accept_error),
+        ACPT_TEST(test_acpt_state_already_ok_no_next),
+        /* acpt_read / acpt_write / acpt_puts */
+        ACPT_TEST_IO(test_acpt_read_forwards),
+        ACPT_TEST_IO(test_acpt_read_forwards_retry),
+        ACPT_TEST_IO(test_acpt_write_forwards),
+        ACPT_TEST_IO(test_acpt_write_forwards_retry),
+        ACPT_TEST_IO(test_acpt_puts_forwards),
+        /* acpt_ctrl */
+        ACPT_TEST(test_acpt_ctrl_reset_clears_addrs),
+        ACPT_TEST(test_acpt_ctrl_set_accept_name),
+        ACPT_TEST(test_acpt_ctrl_set_accept_port),
+        ACPT_TEST(test_acpt_ctrl_set_nbio_accept),
+        ACPT_TEST(test_acpt_ctrl_set_accept_bios),
+        ACPT_TEST(test_acpt_ctrl_set_accept_ip_family),
+        ACPT_TEST(test_acpt_ctrl_set_tfo_accept),
+        ACPT_TEST(test_acpt_ctrl_set_nbio),
+        ACPT_TEST(test_acpt_ctrl_set_fd),
+        ACPT_TEST(test_acpt_ctrl_get_fd),
+        ACPT_TEST(test_acpt_ctrl_get_accept_names),
+        ACPT_TEST(test_acpt_ctrl_get_accept_family),
+        ACPT_TEST(test_acpt_ctrl_get_set_close),
+        ACPT_TEST(test_acpt_ctrl_bind_mode),
+        ACPT_TEST(test_acpt_ctrl_pending_flush),
+        ACPT_TEST(test_acpt_ctrl_eof_no_next),
+        ACPT_TEST(test_acpt_ctrl_default),
+        /* BIO_new_accept */
+        ACPT_TEST(test_bio_new_accept),
+    };
+
+    cmocka_set_message_output(CM_OUTPUT_TAP);
+
+    return cmocka_run_group_tests(tests, group_setup, group_teardown);
+}
+
+#else
+
+int main(void)
+{
+    return 0;
+}
+
+#endif /* OPENSSL_NO_SOCK */