diff --git a/lib/core/context.c b/lib/core/context.c index 87582b935..79987ff74 100644 --- a/lib/core/context.c +++ b/lib/core/context.c @@ -1745,7 +1745,7 @@ next: vh = context->vhost_list; while (vh) { vh1 = vh->vhost_next; - lwsl_debug("%s: vh %s destroy2\n", __func__, vh->name); + // lwsl_debug("%s: vh %s destroy2\n", __func__, vh->name); __lws_vhost_destroy2(vh); vh = vh1; } diff --git a/lib/roles/http/client/client-http.c b/lib/roles/http/client/client-http.c index 3a706a5e8..fc50615e3 100644 --- a/lib/roles/http/client/client-http.c +++ b/lib/roles/http/client/client-http.c @@ -1426,7 +1426,7 @@ spin_chunks: completed: if (lws_http_transaction_completed_client(wsi)) { - lwsl_notice("%s: transaction completed says -1\n", __func__); + lwsl_info("%s: transaction completed says -1\n", __func__); return -1; } diff --git a/lib/secure-streams/protocols/ss-h1.c b/lib/secure-streams/protocols/ss-h1.c index 8b8b5ffb7..a594a6062 100644 --- a/lib/secure-streams/protocols/ss-h1.c +++ b/lib/secure-streams/protocols/ss-h1.c @@ -404,8 +404,8 @@ secstream_h1(struct lws *wsi, enum lws_callback_reasons reason, void *user, break; lws_sul_cancel(&h->sul_timeout); - lwsl_info("%s: h: %p, %s LWS_CALLBACK_CLOSED_CLIENT_HTTP\n", - __func__, h, + lwsl_notice("%s: wsi: %p, h: %p, %s LWS_CALLBACK_CLOSED_CLIENT_HTTP\n", + __func__, wsi, h, h->policy ? h->policy->streamtype : "no policy"); h->wsi = NULL; diff --git a/lib/secure-streams/secure-streams-client.c b/lib/secure-streams/secure-streams-client.c index 70d7ff785..1a61c8b38 100644 --- a/lib/secure-streams/secure-streams-client.c +++ b/lib/secure-streams/secure-streams-client.c @@ -152,7 +152,7 @@ callback_sspc_client(struct lws *wsi, enum lws_callback_reasons reason, /* * our ss proxy Unix Domain socket has closed... */ - lwsl_notice("%s: LWS_CALLBACK_RAW_CLOSE: proxy conn down\n", + lwsl_info("%s: LWS_CALLBACK_RAW_CLOSE: proxy conn down\n", __func__); if (h) { h->cwsi = NULL; diff --git a/lib/secure-streams/secure-streams.c b/lib/secure-streams/secure-streams.c index 13dfacc47..d1e41a99e 100644 --- a/lib/secure-streams/secure-streams.c +++ b/lib/secure-streams/secure-streams.c @@ -116,8 +116,17 @@ _lws_ss_handle_state_ret(lws_ss_state_return_t r, struct lws *wsi, lws_ss_handle_t **ph) { if (r == LWSSSSRET_DESTROY_ME) { - if (wsi) + lwsl_info("%s: DESTROY ME: wsi %p, h->wsi %p\n", __func__, + wsi, (*ph)->wsi); + if (wsi) { lws_set_opaque_user_data(wsi, NULL); + lws_set_timeout(wsi, 1, LWS_TO_KILL_ASYNC); + } else { + if ((*ph)->wsi) { + lws_set_opaque_user_data((*ph)->wsi, NULL); + lws_set_timeout((*ph)->wsi, 1, LWS_TO_KILL_ASYNC); + } + } (*ph)->wsi = NULL; lws_ss_destroy(ph); } @@ -911,6 +920,8 @@ lws_ss_destroy(lws_ss_handle_t **ppss) lws_vhost_destroy(v); #endif + lws_sul_cancel(&h->sul_timeout); + /* confirm no sul left scheduled in handle or user allocation object */ lws_sul_debug_zombies(h->context, h, sizeof(*h) + h->info.user_alloc, __func__); diff --git a/lib/system/async-dns/async-dns.c b/lib/system/async-dns/async-dns.c index 378583d73..a8c3ae14c 100644 --- a/lib/system/async-dns/async-dns.c +++ b/lib/system/async-dns/async-dns.c @@ -94,7 +94,7 @@ lws_async_dns_complete(lws_adns_q_t *q, lws_adns_cache_t *c) */ if (w->adns_cb(w, (const char *)&q[1], c ? c->results : NULL, 0, q->opaque) == NULL) - lwsl_notice("%s: failed\n", __func__); + lwsl_info("%s: failed\n", __func__); // lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS, // "adopt udp2 fail"); diff --git a/minimal-examples/secure-streams/minimal-secure-streams-proxy/main.c b/minimal-examples/secure-streams/minimal-secure-streams-proxy/main.c index 4d2c7a70e..d0e865841 100644 --- a/minimal-examples/secure-streams/minimal-secure-streams-proxy/main.c +++ b/minimal-examples/secure-streams/minimal-secure-streams-proxy/main.c @@ -261,6 +261,7 @@ int main(int argc, const char **argv) memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS | + LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW | LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; info.fd_limit_per_thread = 1 + 6 + 1; info.pss_policies_json = default_ss_policy; diff --git a/minimal-examples/secure-streams/minimal-secure-streams-testsfail/CMakeLists.txt b/minimal-examples/secure-streams/minimal-secure-streams-testsfail/CMakeLists.txt new file mode 100644 index 000000000..01de9e99a --- /dev/null +++ b/minimal-examples/secure-streams/minimal-secure-streams-testsfail/CMakeLists.txt @@ -0,0 +1,88 @@ +project(lws-minimal-secure-streams-testsfail C) +cmake_minimum_required(VERSION 2.8.12) +find_package(libwebsockets CONFIG REQUIRED) +list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR}) +include(CheckCSourceCompiles) +include(LwsCheckRequirements) + +set(SAMP lws-minimal-secure-streams-testsfail) + +set(requirements 1) +require_lws_config(LWS_ROLE_H1 1 requirements) +require_lws_config(LWS_WITHOUT_CLIENT 0 requirements) +require_lws_config(LWS_WITH_SECURE_STREAMS 1 requirements) +require_lws_config(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY 0 requirements) +require_lws_config(LWS_WITH_SYS_STATE 1 requirements) + +if (requirements) + add_executable(${SAMP} minimal-secure-streams-testsfail.c) + + if (LWS_CTEST_INTERNET_AVAILABLE AND NOT WIN32) + add_test(NAME ss-tf COMMAND lws-minimal-secure-streams-testsfail) + set_tests_properties(ss-tf + PROPERTIES + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/secure-streams/minimal-secure-streams-testsfail + TIMEOUT 240) + + if (HAS_LWS_WITH_SECURE_STREAMS_PROXY_API OR LWS_WITH_SECURE_STREAMS_PROXY_API) + + # + # Define test dep to bring up and take down the test + # proxy + # + + if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + # uds abstract namespace for linux + set(CTEST_SOCKET_PATH "@ctest-ssptf-$ENV{SAI_PROJECT}-$ENV{SAI_OVN}") + else() + # filesystem socket for others + set(CTEST_SOCKET_PATH "/tmp/ctest-ssptf-$ENV{SAI_PROJECT}-$ENV{SAI_OVN}") + endif() + add_test(NAME st_sstfproxy COMMAND + ${CMAKE_SOURCE_DIR}/scripts/ctest-background.sh + sstfproxy $ + -i ${CTEST_SOCKET_PATH} --ignore-sigterm) + set_tests_properties(st_sstfproxy PROPERTIES WORKING_DIRECTORY . FIXTURES_SETUP sstfproxy TIMEOUT 800) + + add_test(NAME ki_ssproxy COMMAND + ${CMAKE_SOURCE_DIR}/scripts/ctest-background-kill.sh + sstfproxy $ + -i ${CTEST_SOCKET_PATH}) + set_tests_properties(ki_ssproxy PROPERTIES FIXTURES_CLEANUP sstfproxy) + + # + # the client part that will connect to the proxy + # + + add_test(NAME sspc-minimaltf COMMAND lws-minimal-secure-streams-testsfail-client -i +${CTEST_SOCKET_PATH}) + set_tests_properties(sspc-minimaltf PROPERTIES + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/secure-streams/minimal-secure-streams-testsfail + FIXTURES_REQUIRED "sstfproxy" + TIMEOUT 240) + + endif() + + endif() + + if (websockets_shared) + target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS}) + add_dependencies(${SAMP} websockets_shared) + else() + target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS}) + endif() + + CHECK_C_SOURCE_COMPILES("#include \nint main(void) {\ni#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)\n return 0;\n #else\n fail\n #endif\n return 0;\n}\n" HAS_LWS_WITH_SECURE_STREAMS_PROXY_API) + + if (HAS_LWS_WITH_SECURE_STREAMS_PROXY_API OR LWS_WITH_SECURE_STREAMS_PROXY_API) + add_compile_options(-DLWS_SS_USE_SSPC) + + add_executable(${SAMP}-client minimal-secure-streams-testsfail.c) + if (websockets_shared) + target_link_libraries(${SAMP}-client websockets_shared ${LIBWEBSOCKETS_DEP_LIBS}) + add_dependencies(${SAMP}-client websockets_shared) + else() + target_link_libraries(${SAMP}-client websockets ${LIBWEBSOCKETS_DEP_LIBS}) + endif() + endif() + +endif() diff --git a/minimal-examples/secure-streams/minimal-secure-streams-testsfail/README.md b/minimal-examples/secure-streams/minimal-secure-streams-testsfail/README.md new file mode 100644 index 000000000..70a1b0f37 --- /dev/null +++ b/minimal-examples/secure-streams/minimal-secure-streams-testsfail/README.md @@ -0,0 +1,17 @@ +# lws minimal secure streams + +The application runs some bulk and failure path tests on Secure Streams + +## build + +``` + $ cmake . && make +``` + +## usage + +Commandline option|Meaning +---|--- +-d |Debug verbosity in decimal, eg, -d15 +--amount | Set the amount of bulk data expected, eg, --amount 23456 + diff --git a/minimal-examples/secure-streams/minimal-secure-streams-testsfail/minimal-secure-streams-testsfail.c b/minimal-examples/secure-streams/minimal-secure-streams-testsfail/minimal-secure-streams-testsfail.c new file mode 100644 index 000000000..981851852 --- /dev/null +++ b/minimal-examples/secure-streams/minimal-secure-streams-testsfail/minimal-secure-streams-testsfail.c @@ -0,0 +1,803 @@ +/* + * lws-minimal-secure-streams + * + * Written in 2010-2020 by Andy Green + * + * This file is made available under the Creative Commons CC0 1.0 + * Universal Public Domain Dedication. + * + * + * This demonstrates various kinds of successful and failed connection + * situations in order to confirm the correct states are coming. + * + * You can control how much bulk data is requested from the peer using + * --amount xxx, the default without that is 12345 bytes. + */ + +#include +#include +#include + +static int interrupted, tests, tests_pass, tests_fail; +static lws_sorted_usec_list_t sul_next_test; +static lws_state_notify_link_t nl; +struct lws_context *context; +size_t amount = 12345; + +static void +tests_start_next(lws_sorted_usec_list_t *sul); + +/* + * If the -proxy app is fulfilling our connection, then we don't need to have + * the policy in the client. + * + * When we build with LWS_SS_USE_SSPC, the apis hook up to a proxy process over + * a Unix Domain Socket. To test that, you need to separately run the + * ./lws-minimal-secure-streams-proxy test app on the same machine. + */ + +#if !defined(LWS_SS_USE_SSPC) +static const char * const default_ss_policy = + "{" + "\"release\":" "\"01234567\"," + "\"product\":" "\"myproduct\"," + "\"schema-version\":" "1," +#if defined(VIA_LOCALHOST_SOCKS) + "\"via-socks5\":" "\"127.0.0.1:1080\"," +#endif + + "\"retry\": [" /* named backoff / retry strategies */ + "{\"default\": {" + "\"backoff\": [ 1000, 1000, 1000, 1000, 1000" + "]," + "\"conceal\":" "5," + "\"jitterpc\":" "20," + "\"svalidping\":" "30," + "\"svalidhup\":" "35" + "}}" + "]," + "\"certs\": [" /* named individual certificates in BASE64 DER */ + /* + * Let's Encrypt certs for warmcat.com / libwebsockets.org + * + * We fetch the real policy from there using SS and switch to + * using that. + */ + "{\"isrg_root_x1\": \"" /* ISRG ROOT X1 */ + "MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw" + "TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh" + "cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4" + "WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu" + "ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY" + "MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc" + "h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+" + "0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U" + "A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW" + "T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH" + "B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC" + "B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv" + "KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn" + "OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn" + "jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw" + "qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI" + "rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV" + "HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq" + "hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL" + "ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ" + "3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK" + "NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5" + "ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur" + "TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC" + "jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc" + "oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq" + "4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA" + "mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d" + "emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=" + "\"}," + "{\"LEX3_isrg_root_x1\": \"" /* LE X3 signed by ISRG X1 root */ + "MIIFjTCCA3WgAwIBAgIRANOxciY0IzLc9AUoUSrsnGowDQYJKoZIhvcNAQELBQAw" + "TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh" + "cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTYxMDA2MTU0MzU1" + "WhcNMjExMDA2MTU0MzU1WjBKMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg" + "RW5jcnlwdDEjMCEGA1UEAxMaTGV0J3MgRW5jcnlwdCBBdXRob3JpdHkgWDMwggEi" + "MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCc0wzwWuUuR7dyXTeDs2hjMOrX" + "NSYZJeG9vjXxcJIvt7hLQQWrqZ41CFjssSrEaIcLo+N15Obzp2JxunmBYB/XkZqf" + "89B4Z3HIaQ6Vkc/+5pnpYDxIzH7KTXcSJJ1HG1rrueweNwAcnKx7pwXqzkrrvUHl" + "Npi5y/1tPJZo3yMqQpAMhnRnyH+lmrhSYRQTP2XpgofL2/oOVvaGifOFP5eGr7Dc" + "Gu9rDZUWfcQroGWymQQ2dYBrrErzG5BJeC+ilk8qICUpBMZ0wNAxzY8xOJUWuqgz" + "uEPxsR/DMH+ieTETPS02+OP88jNquTkxxa/EjQ0dZBYzqvqEKbbUC8DYfcOTAgMB" + "AAGjggFnMIIBYzAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADBU" + "BgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEBATAwMC4GCCsGAQUFBwIB" + "FiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQub3JnMB0GA1UdDgQWBBSo" + "SmpjBH3duubRObemRWXv86jsoTAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3Js" + "LnJvb3QteDEubGV0c2VuY3J5cHQub3JnMHIGCCsGAQUFBwEBBGYwZDAwBggrBgEF" + "BQcwAYYkaHR0cDovL29jc3Aucm9vdC14MS5sZXRzZW5jcnlwdC5vcmcvMDAGCCsG" + "AQUFBzAChiRodHRwOi8vY2VydC5yb290LXgxLmxldHNlbmNyeXB0Lm9yZy8wHwYD" + "VR0jBBgwFoAUebRZ5nu25eQBc4AIiMgaWPbpm24wDQYJKoZIhvcNAQELBQADggIB" + "ABnPdSA0LTqmRf/Q1eaM2jLonG4bQdEnqOJQ8nCqxOeTRrToEKtwT++36gTSlBGx" + "A/5dut82jJQ2jxN8RI8L9QFXrWi4xXnA2EqA10yjHiR6H9cj6MFiOnb5In1eWsRM" + "UM2v3e9tNsCAgBukPHAg1lQh07rvFKm/Bz9BCjaxorALINUfZ9DD64j2igLIxle2" + "DPxW8dI/F2loHMjXZjqG8RkqZUdoxtID5+90FgsGIfkMpqgRS05f4zPbCEHqCXl1" + "eO5HyELTgcVlLXXQDgAWnRzut1hFJeczY1tjQQno6f6s+nMydLN26WuU4s3UYvOu" + "OsUxRlJu7TSRHqDC3lSE5XggVkzdaPkuKGQbGpny+01/47hfXXNB7HntWNZ6N2Vw" + "p7G6OfY+YQrZwIaQmhrIqJZuigsrbe3W+gdn5ykE9+Ky0VgVUsfxo52mwFYs1JKY" + "2PGDuWx8M6DlS6qQkvHaRUo0FMd8TsSlbF0/v965qGFKhSDeQoMpYnwcmQilRh/0" + "ayLThlHLN81gSkJjVrPI0Y8xCVPB4twb1PFUd2fPM3sA1tJ83sZ5v8vgFv2yofKR" + "PB0t6JzUA81mSqM3kxl5e+IZwhYAyO0OTg3/fs8HqGTNKd9BqoUwSRBzp06JMg5b" + "rUCGwbCUDI0mxadJ3Bz4WxR6fyNpBK2yAinWEsikxqEt" + "\"},{" + "\"digicert_global_root_g2\": \"MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7K" + "GSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMR" + "GlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDE" + "xdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxM" + "TUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxG" + "TAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb" + "2JhbCBSb290IEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNN" + "Nx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpim" + "n7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kq" + "bitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauVB" + "JVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdz" + "XOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FD" + "KZJobq7nMWxM4MphQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/" + "wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNA" + "QELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQ" + "oQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98" + "kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8" + "PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgR" + "PTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3f" + "e0Dkhvld1927jyNxF1WW6LZZm6zNTflMrY=\"" + "}, {" + "\"digicert_global_ca_g2\": \"MIIEizCCA3OgAwIBAgIQDI7gyQ1" + "qiRWIBAYe4kH5rzANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJVUzEVMBMGA1U" + "EChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgY" + "DVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0" + "yODA4MDExMjAwMDBaMEQxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCB" + "JbmMxHjAcBgNVBAMTFURpZ2lDZXJ0IEdsb2JhbCBDQSBHMjCCASIwDQYJKoZIhvc" + "NAQEBBQADggEPADCCAQoCggEBANNIfL7zBYZdW9UvhU5L4IatFaxhz1uvPmoKR/u" + "adpFgC4przc/cV35gmAvkVNlW7SHMArZagV+Xau4CLyMnuG3UsOcGAngLH1ypmTb" + "+u6wbBfpXzYEQQGfWMItYNdSWYb7QjHqXnxr5IuYUL6nG6AEfq/gmD6yOTSwyOR2" + "Bm40cZbIc22GoiS9g5+vCShjEbyrpEJIJ7RfRACvmfe8EiRROM6GyD5eHn7OgzS+" + "8LOy4g2gxPR/VSpAQGQuBldYpdlH5NnbQtwl6OErXb4y/E3w57bqukPyV93t4CTZ" + "edJMeJfD/1K2uaGvG/w/VNfFVbkhJ+Pi474j48V4Rd6rfArMCAwEAAaOCAVowggF" + "WMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMDQGCCsGAQUFBwE" + "BBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMHsGA1U" + "dHwR0MHIwN6A1oDOGMWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEd" + "sb2JhbFJvb3RHMi5jcmwwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9" + "EaWdpQ2VydEdsb2JhbFJvb3RHMi5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAY" + "IKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwHQYDVR0OBBY" + "EFCRuKy3QapJRUSVpAaqaR6aJ50AgMB8GA1UdIwQYMBaAFE4iVCAYlebjbuYP+vq" + "5Eu0GF485MA0GCSqGSIb3DQEBCwUAA4IBAQALOYSR+ZfrqoGvhOlaOJL84mxZvzb" + "IRacxAxHhBsCsMsdaVSnaT0AC9aHesO3ewPj2dZ12uYf+QYB6z13jAMZbAuabeGL" + "J3LhimnftiQjXS8X9Q9ViIyfEBFltcT8jW+rZ8uckJ2/0lYDblizkVIvP6hnZf1W" + "ZUXoOLRg9eFhSvGNoVwvdRLNXSmDmyHBwW4coatc7TlJFGa8kBpJIERqLrqwYEle" + "sA8u49L3KJg6nwd3jM+/AVTANlVlOnAM2BvjAjxSZnE0qnsHhfTuvcqdFuhOWKU4" + "Z0BqYBvQ3lBetoxi6PrABDJXWKTUgNX31EGDk92hiHuwZ4STyhxGs6QiA\"" + "}," + "{\"amazon_root_ca_1\": \"MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikP" + "mljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1" + "hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFo" + "XDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjE" + "ZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggE" + "PADCCAQoCggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtO" + "gQ3pOsqTQNroBvo3bSMgHFzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peV" + "KVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+Uh" + "nMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4c" + "X8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34Gf" + "ID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAU" + "wAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7I" + "QTgoIMA0GCSqGSIb3DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5" + "IpDB/G/wkjUu0yKGX9rbxenDIU5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZ" + "ERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2" + "V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR" + "1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob" + "2xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5\"}" + "]," + "\"trust_stores\": [" /* named cert chains */ + "{" + "\"name\": \"api_amazon_com\"," + "\"stack\": [\"digicert_global_ca_g2\", \"digicert_global_root_g2\"]" + "}, { \"name\": \"arca1\", \"stack\": [\"amazon_root_ca_1\"]}," + "{" + "\"name\": \"le_via_isrg\"," + "\"stack\": [" + "\"isrg_root_x1\"," + "\"LEX3_isrg_root_x1\"" + "]" + "}" + "]," + "\"s\": [" + + "{\"api_amazon_com_auth\": {" + "\"endpoint\": \"api.amazon.com\"," + "\"port\": 443," + "\"protocol\": \"h1\"," + "\"http_method\": \"POST\"," + "\"http_url\": \"auth/o2/token\"," + "\"plugins\": []," + "\"opportunistic\": true," + "\"tls\": true," + "\"h2q_oflow_txcr\": true," + "\"http_www_form_urlencoded\": true," + "\"http_no_content_length\": true," + "\"retry\": \"default\"," + "\"tls_trust_store\": \"api_amazon_com\"" + "}},{" + + /* + * Just get a 200 from httpbin.org + * on h1:80, h1:443 and h2:443 + * + * sanity check that we're working at all + */ + + "\"t_h1\": {" + "\"endpoint\": \"httpbin.org\"," + "\"port\": 80," + "\"protocol\": \"h1\"," + "\"http_method\": \"GET\"," + "\"http_url\": \"/status/200\"," + "\"opportunistic\": true," + "\"retry\": \"default\"" + "}},{" + "\"t_h1_tls\": {" + "\"endpoint\": \"httpbin.org\"," + "\"port\": 443," + "\"protocol\": \"h1\"," + "\"http_method\": \"GET\"," + "\"http_url\": \"/status/200\"," + "\"tls\": true," + "\"opportunistic\": true," + "\"retry\": \"default\"," + "\"tls_trust_store\": \"arca1\"" + "}},{" + "\"t_h2_tls\": {" + "\"endpoint\": \"httpbin.org\"," + "\"port\": 443," + "\"protocol\": \"h2\"," + "\"http_method\": \"GET\"," + "\"http_url\": \"/status/200\"," + "\"tls\": true," + "\"nghttp2_quirk_end_stream\": true," + "\"h2q_oflow_txcr\": true," + "\"opportunistic\": true," + "\"retry\": \"default\"," + "\"tls_trust_store\": \"arca1\"" + "}},{" + + /* + * 10s delayed response from httpbin.org + * on h1:80, h1:443 and h2:443 + * + * used to trigger timeout testing + */ + + "\"d_h1\": {" + "\"endpoint\": \"httpbin.org\"," + "\"port\": 80," + "\"protocol\": \"h1\"," + "\"http_method\": \"GET\"," + "\"http_url\": \"/delay/10\"," + "\"opportunistic\": true," + "\"retry\": \"default\"" + "}},{" + "\"d_h1_tls\": {" + "\"endpoint\": \"httpbin.org\"," + "\"port\": 443," + "\"protocol\": \"h1\"," + "\"http_method\": \"GET\"," + "\"http_url\": \"/delay/10\"," + "\"tls\": true," + "\"opportunistic\": true," + "\"retry\": \"default\"," + "\"tls_trust_store\": \"arca1\"" + "}},{" + "\"d_h2_tls\": {" + "\"endpoint\": \"httpbin.org\"," + "\"port\": 443," + "\"protocol\": \"h2\"," + "\"http_method\": \"GET\"," + "\"http_url\": \"/delay/10\"," + "\"tls\": true," + "\"nghttp2_quirk_end_stream\": true," + "\"h2q_oflow_txcr\": true," + "\"opportunistic\": true," + "\"retry\": \"default\"," + "\"tls_trust_store\": \"arca1\"" + "}},{" + + /* + * get NXDOMAIN for bogus.nope + * on h1:80, h1:443 and h2:443 + * + * Triggers unreachable and eventually all_retries_failed + */ + + "\"nxd_h1\": {" + "\"endpoint\": \"bogus.nope\"," + "\"port\": 80," + "\"protocol\": \"h1\"," + "\"http_method\": \"GET\"," + "\"http_url\": \"/status/200\"," + "\"opportunistic\": true," + "\"retry\": \"default\"" + "}},{" + "\"nxd_h1_tls\": {" + "\"endpoint\": \"bogus.nope\"," + "\"port\": 443," + "\"protocol\": \"h1\"," + "\"http_method\": \"GET\"," + "\"http_url\": \"/status/200\"," + "\"tls\": true," + "\"opportunistic\": true," + "\"retry\": \"default\"," + "\"tls_trust_store\": \"arca1\"" + "}},{" + "\"nxd_h2_tls\": {" + "\"endpoint\": \"bogus.nope\"," + "\"port\": 443," + "\"protocol\": \"h2\"," + "\"http_method\": \"GET\"," + "\"http_url\": \"/status/200\"," + "\"tls\": true," + "\"nghttp2_quirk_end_stream\": true," + "\"h2q_oflow_txcr\": true," + "\"opportunistic\": true," + "\"retry\": \"default\"," + "\"tls_trust_store\": \"arca1\"" + "}},{" + + /* + * bulk payload transfer from httpbin.org + * on h1:80, h1:443 and h2:443 + * + * Sanity check larger payload + */ + + "\"bulk_h1\": {" + "\"endpoint\": \"httpbin.org\"," + "\"port\": 80," + "\"protocol\": \"h1\"," + "\"http_method\": \"GET\"," + "\"http_url\": \"range/${amount}\"," + "\"metadata\": [{" + "\"amount\": \"\"" + "}]," + "\"opportunistic\": true," + "\"retry\": \"default\"" + "}},{" + "\"bulk_h1_tls\": {" + "\"endpoint\": \"httpbin.org\"," + "\"port\": 443," + "\"protocol\": \"h1\"," + "\"http_method\": \"GET\"," + "\"http_url\": \"range/${amount}\"," + "\"metadata\": [{" + "\"amount\": \"\"" + "}]," + "\"tls\": true," + "\"opportunistic\": true," + "\"retry\": \"default\"," + "\"tls_trust_store\": \"arca1\"" + "}},{" + "\"bulk_h2_tls\": {" + "\"endpoint\": \"httpbin.org\"," + "\"port\": 443," + "\"protocol\": \"h2\"," + "\"http_method\": \"GET\"," + "\"http_url\": \"range/${amount}\"," + "\"metadata\": [{" + "\"amount\": \"\"" + "}]," + "\"tls\": true," + "\"nghttp2_quirk_end_stream\": true," + "\"h2q_oflow_txcr\": true," + "\"opportunistic\": true," + "\"retry\": \"default\"," + "\"tls_trust_store\": \"arca1\"" + "}}" + "]}" +; + +#endif + +/* + * This is the sequence of test streams we are going to create, the ss timeout, + * and a description of what we want to see to understand the test passed, or + * failed. If the test hits destruction without making a explicit pass or fail + * decision before, that's a fail. Or, depending on what state we put in + * .must_see, we can count a state like UNREACHABLE as a pass. + */ + +struct tests_seq { + const char *name; + const char *streamtype; + uint64_t timeout_us; + lws_ss_constate_t must_see; + unsigned int mask_unexpected; + size_t eom_pass; +} tests_seq[] = { + + /* + * We just get a 200 from httpbin.org as a sanity check first + */ + + { + "h1:80 just get 200", + "t_h1", 5 * LWS_US_PER_SEC, LWSSSCS_QOS_ACK_REMOTE, + (1 << LWSSSCS_TIMEOUT) | (1 << LWSSSCS_QOS_NACK_REMOTE) | + (1 << LWSSSCS_ALL_RETRIES_FAILED) + }, + { + "h1:443 just get 200", + "t_h1_tls", 5 * LWS_US_PER_SEC, LWSSSCS_QOS_ACK_REMOTE, + (1 << LWSSSCS_TIMEOUT) | (1 << LWSSSCS_QOS_NACK_REMOTE) | + (1 << LWSSSCS_ALL_RETRIES_FAILED) + }, + { + "h2:443 just get 200", + "t_h2_tls", 5 * LWS_US_PER_SEC, LWSSSCS_QOS_ACK_REMOTE, + (1 << LWSSSCS_TIMEOUT) | (1 << LWSSSCS_QOS_NACK_REMOTE) | + (1 << LWSSSCS_ALL_RETRIES_FAILED) + }, + + /* + * We arranged that the server will delay 10s before sending the + * response, but set our ss timeout for 5s. So we expect to see + * our timeout and not an ACK / 200. + */ + + { + "h1:80 timeout after connection", + "d_h1", 5 * LWS_US_PER_SEC, LWSSSCS_TIMEOUT, + (1 << LWSSSCS_QOS_ACK_REMOTE) | (1 << LWSSSCS_QOS_NACK_REMOTE) | + (1 << LWSSSCS_ALL_RETRIES_FAILED) + }, + { + "h1:443 timeout after connection", + "d_h1_tls", 5 * LWS_US_PER_SEC, LWSSSCS_TIMEOUT, + (1 << LWSSSCS_QOS_ACK_REMOTE) | (1 << LWSSSCS_QOS_NACK_REMOTE) | + (1 << LWSSSCS_ALL_RETRIES_FAILED) + }, + { + "h2:443 timeout after connection", + "d_h2_tls", 5 * LWS_US_PER_SEC, LWSSSCS_TIMEOUT, + (1 << LWSSSCS_QOS_ACK_REMOTE) | (1 << LWSSSCS_QOS_NACK_REMOTE) | + (1 << LWSSSCS_ALL_RETRIES_FAILED) + }, + + /* + * We are talking to a nonexistant dns address "bogus.nope". We expect + * in each case to hear that is unreachable, before any ss timeout. + */ + + { + "h1:80 NXDOMAIN", + "nxd_h1", 35 * LWS_US_PER_SEC, LWSSSCS_UNREACHABLE, + (1 << LWSSSCS_QOS_ACK_REMOTE) | (1 << LWSSSCS_QOS_NACK_REMOTE) | + (1 << LWSSSCS_TIMEOUT) | (1 << LWSSSCS_ALL_RETRIES_FAILED) + }, + { + "h1:443 NXDOMAIN", + "nxd_h1_tls", 35 * LWS_US_PER_SEC, LWSSSCS_UNREACHABLE, + (1 << LWSSSCS_QOS_ACK_REMOTE) | (1 << LWSSSCS_QOS_NACK_REMOTE) | + (1 << LWSSSCS_TIMEOUT) | (1 << LWSSSCS_ALL_RETRIES_FAILED) + }, + { + "h2:443 NXDOMAIN", + "nxd_h2_tls", 35 * LWS_US_PER_SEC, LWSSSCS_UNREACHABLE, + (1 << LWSSSCS_QOS_ACK_REMOTE) | (1 << LWSSSCS_QOS_NACK_REMOTE) | + (1 << LWSSSCS_TIMEOUT) | (1 << LWSSSCS_ALL_RETRIES_FAILED) + }, + + /* + * We are talking to a nonexistant dns address "bogus.nope". We expect + * that if we stick around longer, retries will also end up all failing + */ + + { + "h1:80 NXDOMAIN exhaust retries", + "nxd_h1", 35 * LWS_US_PER_SEC, LWSSSCS_ALL_RETRIES_FAILED, + (1 << LWSSSCS_QOS_ACK_REMOTE) | (1 << LWSSSCS_QOS_NACK_REMOTE) | + (1 << LWSSSCS_TIMEOUT) + }, + { + "h1:443 NXDOMAIN exhaust retries", + "nxd_h1_tls", 35 * LWS_US_PER_SEC, LWSSSCS_ALL_RETRIES_FAILED, + (1 << LWSSSCS_QOS_ACK_REMOTE) | (1 << LWSSSCS_QOS_NACK_REMOTE) | + (1 << LWSSSCS_TIMEOUT) + }, + { + "h2:443 NXDOMAIN exhaust retries", + "nxd_h2_tls", 35 * LWS_US_PER_SEC, LWSSSCS_ALL_RETRIES_FAILED, + (1 << LWSSSCS_QOS_ACK_REMOTE) | (1 << LWSSSCS_QOS_NACK_REMOTE) | + (1 << LWSSSCS_TIMEOUT) + }, + + /* + * Let's request some bulk data from httpbin.org + */ + + { + "h1:80 read bulk", + "bulk_h1", 5 * LWS_US_PER_SEC, LWSSSCS_QOS_ACK_REMOTE, + (1 << LWSSSCS_TIMEOUT) | (1 << LWSSSCS_QOS_NACK_REMOTE) | + (1 << LWSSSCS_ALL_RETRIES_FAILED), + 12345 + }, + { + "h1:443 read bulk", + "bulk_h1_tls", 5 * LWS_US_PER_SEC, LWSSSCS_QOS_ACK_REMOTE, + (1 << LWSSSCS_TIMEOUT) | (1 << LWSSSCS_QOS_NACK_REMOTE) | + (1 << LWSSSCS_ALL_RETRIES_FAILED), + 12345 + }, + { + "h2:443 read bulk", + "bulk_h2_tls", 5 * LWS_US_PER_SEC, LWSSSCS_QOS_ACK_REMOTE, + (1 << LWSSSCS_TIMEOUT) | (1 << LWSSSCS_QOS_NACK_REMOTE) | + (1 << LWSSSCS_ALL_RETRIES_FAILED), + 12345 + }, + +}; + +typedef struct myss { + struct lws_ss_handle *ss; + void *opaque_data; + + size_t rx_seen; + char result_reported; +} myss_t; + + +/* secure streams payload interface */ + +static lws_ss_state_return_t +myss_rx(void *userobj, const uint8_t *buf, size_t len, int flags) +{ + myss_t *m = (myss_t *)userobj; + + m->rx_seen += len; + + if (flags & LWSSS_FLAG_EOM) + lwsl_notice("%s: received %u bytes\n", __func__, + (unsigned int)m->rx_seen); + + return 0; +} + +static lws_ss_state_return_t +myss_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len, + int *flags) +{ + //myss_t *m = (myss_t *)userobj; + + /* in this example, we don't send stuff */ + + return LWSSSSRET_TX_DONT_SEND; +} + +static lws_ss_state_return_t +myss_state(void *userobj, void *sh, lws_ss_constate_t state, + lws_ss_tx_ordinal_t ack) +{ + myss_t *m = (myss_t *)userobj; + struct tests_seq *curr_test = ( struct tests_seq *)m->opaque_data; + char buf[8]; + size_t sl; + + lwsl_info("%s: ss %p: %s (%d), ord 0x%x\n", __func__, m->ss, + lws_ss_state_name((int)state), state, (unsigned int)ack); + + if (curr_test->mask_unexpected & (1u << state)) { + /* + * We have definitively failed on an unexpected state received + */ + + lwsl_user("%s: failing on unexpected state %s\n", + __func__, lws_ss_state_name((int)state)); + +fail: + m->result_reported = 1; + tests_fail++; + /* we'll start the next test next time around the event loop */ + lws_sul_schedule(context, 0, &sul_next_test, tests_start_next, 1); + + return LWSSSSRET_OK; + } + + if (state == curr_test->must_see) { + + if (curr_test->eom_pass != m->rx_seen) { + lwsl_notice("%s: failing on rx %d, expected %d\n", + __func__, (int)m->rx_seen, + (int)curr_test->eom_pass); + goto fail; + } + + lwsl_notice("%s: saw expected state %s\n", + __func__, lws_ss_state_name((int)state)); + m->result_reported = 1; + tests_pass++; + /* we'll start the next test next time around the event loop */ + lws_sul_schedule(context, 0, &sul_next_test, tests_start_next, 1); + + return LWSSSSRET_OK; + } + + switch (state) { + case LWSSSCS_CREATING: + lws_ss_start_timeout(m->ss, + (unsigned int)(curr_test->timeout_us / LWS_US_PER_MS)); + if (curr_test->eom_pass) { + sl = (size_t)lws_snprintf(buf, sizeof(buf), "%u", + (unsigned int)curr_test->eom_pass); + lws_ss_set_metadata(m->ss, "amount", buf, sl); + } + lws_ss_client_connect(m->ss); + break; + case LWSSSCS_DESTROYING: + if (!m->result_reported) { + lwsl_user("%s: failing on unexpected destruction\n", + __func__); + + tests_fail++; + /* we'll start the next test next time around the event loop */ + lws_sul_schedule(context, 0, &sul_next_test, tests_start_next, 1); + } + break; + + default: + break; + } + + return LWSSSSRET_OK; +} + +static void +tests_start_next(lws_sorted_usec_list_t *sul) +{ + struct tests_seq *ts; + lws_ss_info_t ssi; + static struct lws_ss_handle *h; + + /* destroy the old one */ + + if (h) + lws_ss_destroy(&h); + + if ((unsigned int)tests >= LWS_ARRAY_SIZE(tests_seq)) { + lwsl_notice("Completed all tests\n"); + interrupted = 1; + return; + } + + ts = &tests_seq[tests++]; + + /* Create the next test stream */ + + memset(&ssi, 0, sizeof(ssi)); + ssi.handle_offset = offsetof(myss_t, ss); + ssi.opaque_user_data_offset = offsetof(myss_t, opaque_data); + ssi.rx = myss_rx; + ssi.tx = myss_tx; + ssi.state = myss_state; + ssi.user_alloc = sizeof(myss_t); + ssi.streamtype = ts->streamtype; + + lwsl_user("%s: %d: %s\n", __func__, tests, ts->name); + + if (lws_ss_create(context, 0, &ssi, ts, &h, NULL, NULL)) { + lwsl_err("%s: failed to create secure stream\n", + __func__); + interrupted = 1; + return; + } +} + +static int +app_system_state_nf(lws_state_manager_t *mgr, lws_state_notify_link_t *link, + int current, int target) +{ + switch (target) { + + case LWS_SYSTATE_OPERATIONAL: + if (current == LWS_SYSTATE_OPERATIONAL) + /* we'll start the next test next time around the event loop */ + lws_sul_schedule(context, 0, &sul_next_test, tests_start_next, 1); + break; + } + + return 0; +} + +static lws_state_notify_link_t * const app_notifier_list[] = { + &nl, NULL +}; + +static void +sigint_handler(int sig) +{ + interrupted = 1; +} + +int +main(int argc, const char **argv) +{ + struct lws_context_creation_info info; + const char *pp; + + signal(SIGINT, sigint_handler); + + memset(&info, 0, sizeof info); + lws_cmdline_option_handle_builtin(argc, argv, &info); + + if ((pp = lws_cmdline_option(argc, argv, "--amount"))) + amount = (size_t)atoi(pp); + + /* set the expected payload for the bulk-related tests to amount */ + + tests_seq[12].eom_pass = tests_seq[13].eom_pass = + tests_seq[14].eom_pass = amount; +#if !defined(LWS_SS_USE_SSPC) + // puts(default_ss_policy); +#endif + + lwsl_user("LWS secure streams error path tests [-d]\n"); + + info.fd_limit_per_thread = 1 + 6 + 1; + info.port = CONTEXT_PORT_NO_LISTEN; +#if defined(LWS_SS_USE_SSPC) + info.protocols = lws_sspc_protocols; + { + const char *p; + + /* connect to ssproxy via UDS by default, else via + * tcp connection to this port */ + if ((p = lws_cmdline_option(argc, argv, "-p"))) + info.ss_proxy_port = (uint16_t)atoi(p); + + /* UDS "proxy.ss.lws" in abstract namespace, else this socket + * path; when -p given this can specify the network interface + * to bind to */ + if ((p = lws_cmdline_option(argc, argv, "-i"))) + info.ss_proxy_bind = p; + + /* if -p given, -a specifies the proxy address to connect to */ + if ((p = lws_cmdline_option(argc, argv, "-a"))) + info.ss_proxy_address = p; + } +#else + info.pss_policies_json = default_ss_policy; + info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS | + LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW | + LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; +#endif + + /* integrate us with lws system state management when context created */ + + nl.name = "app"; + nl.notify_cb = app_system_state_nf; + info.register_notifier_list = app_notifier_list; + + /* create the context */ + + context = lws_create_context(&info); + if (!context) { + lwsl_err("lws init failed\n"); + return 1; + } + + /* the event loop */ + + do { + } while(lws_service(context, 0) >= 0 && !interrupted); + + lws_context_destroy(context); + + lwsl_user("Completed: %s (pass %d, fail %d)\n", + tests_pass == tests && !tests_fail ? "OK" : "failed", + tests_pass, tests_fail); + + return !(tests_pass == tests && !tests_fail); +}