1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-23 00:00:06 +01:00
libwebsockets/minimal-examples/secure-streams/minimal-secure-streams-testsfail/minimal-secure-streams-testsfail.c
Andy Green 0ceba15d9c lws_lifecycle
This adds some new objects and helpers for keeping and logging
info on grouped allocations, a group is, eg, SS handles or client
wsis.

Allocated objects get a context-unique "tag" string intended to replace
%p / wsi pointers etc.  Pointers quickly become confusing when
allocations are freed and reused, the tag string won't repeat
until you produce 2^64 objects in a context.

In addition the tag string documents the object group, with prefixes
like "wsi-" or "vh-" and contain object-specific additional
information like the vhost name, address / port  or the role of the wsi.
At creation time the lws code can use a format string and args
to add whatever group-specific info makes sense, eg, a wsi bound
to a secure stream can also append the guid of the secure stream,
it's copied into the new object tag and so is still available
cleanly after the stream is destroyed if the wsi outlives it.
2021-01-04 05:26:50 +00:00

806 lines
25 KiB
C

/*
* lws-minimal-secure-streams
*
* Written in 2010-2020 by Andy Green <andy@warmcat.com>
*
* 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 <libwebsockets.h>
#include <string.h>
#include <signal.h>
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: %s len %d, fl %d, received %u bytes\n",
__func__, lws_ss_tag(m->ss), (int)len, flags,
(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: %s: %s (%d), ord 0x%x\n", __func__, lws_ss_tag(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_warn("%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_warn("%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);
}
return lws_ss_client_connect(m->ss);
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) {
lwsl_info("%s: destroying previous stream\n", __func__);
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__);
tests_fail++;
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<verb>]\n");
info.fd_limit_per_thread = 1 + 16 + 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);
}