1/* 2 * lws-minimal-secure-streams-post 3 * 4 * Written in 2010-2020 by Andy Green <andy@warmcat.com> 5 * 6 * This file is made available under the Creative Commons CC0 1.0 7 * Universal Public Domain Dedication. 8 * 9 * 10 * This demonstrates a minimal http client using secure streams api. 11 * 12 * It visits https://warmcat.com/ and receives the html page there. 13 * 14 * This example is built two different ways from the same source... one includes 15 * the policy everything needed to fulfil the stream directly. The other -client 16 * variant has no policy itself and some other minor init changes, and connects 17 * to the -proxy example to actually get the connection done. 18 * 19 * In the -client build case, the example does not even init the tls libraries 20 * since the proxy part will take care of all that. 21 */ 22 23#include <libwebsockets.h> 24#include <string.h> 25#include <signal.h> 26#include <assert.h> 27 28/* 29 * uncomment to force network traffic through 127.0.0.1:1080 30 * 31 * On your local machine, you can run a SOCKS5 proxy like this 32 * 33 * $ ssh -N -D 0.0.0.0:1080 localhost -v 34 * 35 * If enabled, this also fetches a remote policy that also 36 * specifies that all traffic should go through the remote 37 * proxy. 38 */ 39// #define VIA_LOCALHOST_SOCKS 40 41static int interrupted, bad = 1, force_cpd_fail_portal, 42 force_cpd_fail_no_internet; 43static unsigned int timeout_ms = 3000; 44static lws_state_notify_link_t nl; 45 46static const char * const postbody = 47 "--boundary\r\n" 48 "Content-Disposition: form-data; name=\"text\"\r\n" 49 "\r\n" 50 "value1\r\n" 51 "--boundary\r\n" 52 "Content-Disposition: form-data; " 53 "name=\"field2\"; filename=\"example.txt\"\r\n" 54 "\r\n" 55 "value2\r\n" 56 "00-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 57 "01-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 58 "02-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 59 "03-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 60 "04-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 61 "05-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 62 "06-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 63 "07-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 64 "08-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 65 "09-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 66 "0a-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 67 "0b-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 68 "0c-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 69 "0d-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 70 "0e-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 71 "0f-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 72 "10-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 73 "11-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 74 "12-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 75 "13-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 76 "14-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 77 "15-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 78 "16-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 79 "17-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 80 "18-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 81 "19-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 82 "1a-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 83 "1b-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 84 "1c-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 85 "1d-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 86 "1e-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 87 "1f-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 88 "20-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 89 "21-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 90 "22-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 91 "23-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 92 "24-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 93 "25-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 94 "26-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 95 "27-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 96 "28-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 97 "29-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 98 "2a-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 99 "2b-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 100 "2c-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 101 "2d-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 102 "2e-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 103 "2f-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 104 "30-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 105 "31-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 106 "32-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 107 "33-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 108 "34-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 109 "35-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 110 "36-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 111 "37-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 112 "38-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 113 "39-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 114 "3a-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 115 "3b-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 116 "3c-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 117 "3d-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 118 "3e-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 119 "3f-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 120 "40-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 121 "41-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 122 "42-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 123 "43-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 124 "44-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 125 "45-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 126 "46-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 127 "47-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 128 "48-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 129 "49-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 130 "4a-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 131 "4b-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 132 "4c-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 133 "4d-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 134 "4e-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 135 "4f-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n" 136 "--boundary--\r\n"; 137 138/* 139 * If the -proxy app is fulfilling our connection, then we don't need to have 140 * the policy in the client. 141 * 142 * When we build with LWS_SS_USE_SSPC, the apis hook up to a proxy process over 143 * a Unix Domain Socket. To test that, you need to separately run the 144 * ./lws-minimal-secure-streams-proxy test app on the same machine. 145 */ 146 147#if !defined(LWS_SS_USE_SSPC) 148static const char * const default_ss_policy = 149 "{" 150 "\"release\":" "\"01234567\"," 151 "\"product\":" "\"myproduct\"," 152 "\"schema-version\":" "1," 153#if defined(VIA_LOCALHOST_SOCKS) 154 "\"via-socks5\":" "\"127.0.0.1:1080\"," 155#endif 156 157 "\"retry\": [" /* named backoff / retry strategies */ 158 "{\"default\": {" 159 "\"backoff\": [" "1000," 160 "2000," 161 "3000," 162 "5000," 163 "10000" 164 "]," 165 "\"conceal\":" "5," 166 "\"jitterpc\":" "20," 167 "\"svalidping\":" "30," 168 "\"svalidhup\":" "35" 169 "}}" 170 "]," 171 "\"certs\": [" /* named individual certificates in BASE64 DER */ 172 /* 173 * Let's Encrypt certs for warmcat.com / libwebsockets.org 174 * 175 * We fetch the real policy from there using SS and switch to 176 * using that. 177 */ 178 "{\"isrg_root_x1\": \"" 179 "MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw" 180 "TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh" 181 "cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4" 182 "WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu" 183 "ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY" 184 "MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc" 185 "h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+" 186 "0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U" 187 "A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW" 188 "T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH" 189 "B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC" 190 "B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv" 191 "KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn" 192 "OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn" 193 "jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw" 194 "qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI" 195 "rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV" 196 "HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq" 197 "hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL" 198 "ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ" 199 "3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK" 200 "NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5" 201 "ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur" 202 "TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC" 203 "jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc" 204 "oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq" 205 "4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA" 206 "mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d" 207 "emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=" 208 "\"}" 209 "]," 210 "\"trust_stores\": [" /* named cert chains */ 211 "{" 212 "\"name\": \"le_via_isrg\"," 213 "\"stack\": [" 214 "\"isrg_root_x1\"" 215 "]" 216 "}" 217 "]," 218 "\"s\": [" 219 /* 220 * "fetch_policy" decides from where the real policy 221 * will be fetched, if present. Otherwise the initial 222 * policy is treated as the whole, hardcoded, policy. 223 */ 224 "{\"fetch_policy\": {" 225 "\"endpoint\":" "\"warmcat.com\"," 226 "\"port\":" "443," 227 "\"protocol\":" "\"h1\"," 228 "\"http_method\":" "\"GET\"," 229#if defined(VIA_LOCALHOST_SOCKS) 230 "\"http_url\":" "\"policy/minimal-proxy-socks.json\"," 231#else 232 "\"http_url\":" "\"policy/minimal-proxy.json\"," 233#endif 234 "\"tls\":" "true," 235 "\"opportunistic\":" "true," 236 "\"retry\":" "\"default\"," 237 "\"tls_trust_store\":" "\"le_via_isrg\"" 238 "}},{" 239 /* 240 * "captive_portal_detect" describes 241 * what to do in order to check if the path to 242 * the Internet is being interrupted by a 243 * captive portal. If there's a larger policy 244 * fetched from elsewhere, it should also include 245 * this since it needs to be done at least after 246 * every DHCP acquisition 247 */ 248 "\"captive_portal_detect\": {" 249 "\"endpoint\": \"connectivitycheck.android.com\"," 250 "\"http_url\": \"generate_204\"," 251 "\"port\": 80," 252 "\"protocol\": \"h1\"," 253 "\"http_method\": \"GET\"," 254 "\"opportunistic\": true," 255 "\"http_expect\": 204," 256 "\"http_fail_redirect\": true" 257 "}}" 258 "]}" 259; 260 261#endif 262 263typedef struct myss { 264 struct lws_ss_handle *ss; 265 void *opaque_data; 266 /* ... application specific state ... */ 267 lws_sorted_usec_list_t sul; 268 269 size_t pos; 270 size_t len; 271} myss_t; 272 273#if !defined(LWS_SS_USE_SSPC) 274 275static const char *canned_root_token_payload = 276 "grant_type=refresh_token" 277 "&refresh_token=Atzr|IwEBIJedGXjDqsU_vMxykqOMg" 278 "SHfYe3CPcedueWEMWSDMaDnEmiW8RlR1Kns7Cb4B-TOSnqp7ifVsY4BMY2B8tpHfO39XP" 279 "zfu9HapGjTR458IyHX44FE71pWJkGZ79uVBpljP4sazJuk8XS3Oe_yLnm_DIO6fU1nU3Y" 280 "0flYmsOiOAQE_gRk_pdlmEtHnpMA-9rLw3mkY5L89Ty9kUygBsiFaYatouROhbsTn8-jW" 281 "k1zZLUDpT6ICtBXSnrCIg0pUbZevPFhTwdXd6eX-u4rq0W-XaDvPWFO7au-iPb4Zk5eZE" 282 "iX6sissYrtNmuEXc2uHu7MnQO1hHCaTdIO2CANVumf-PHSD8xseamyh04sLV5JgFzY45S" 283 "KvKMajiUZuLkMokOx86rjC2Hdkx5DO7G-dbG1ufBDG-N79pFMSs7Ck5pc283IdLoJkCQc" 284 "AGvTX8o8I29QqkcGou-9TKhOJmpX8As94T61ok0UqqEKPJ7RhfQHHYdCtsdwxgvfVr9qI" 285 "xL_hDCcTho8opCVX-6QhJHl6SQFlTw13" 286 "&client_id=" 287 "amzn1.application-oa2-client.4823334c434b4190a2b5a42c07938a2d"; 288 289#endif 290 291/* secure streams payload interface */ 292 293static lws_ss_state_return_t 294myss_rx(void *userobj, const uint8_t *buf, size_t len, int flags) 295{ 296// myss_t *m = (myss_t *)userobj; 297 298 lwsl_user("%s: len %d, flags: %d\n", __func__, (int)len, flags); 299 lwsl_hexdump_info(buf, len); 300 301 /* 302 * If we received the whole message, for our example it means 303 * we are done. 304 */ 305 if (flags & LWSSS_FLAG_EOM) { 306 bad = 0; 307 interrupted = 1; 308 } 309 310 return 0; 311} 312 313static lws_ss_state_return_t 314myss_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len, 315 int *flags) 316{ 317 myss_t *m = (myss_t *)userobj; 318 319 if (m->pos == m->len) 320 return LWSSSSRET_TX_DONT_SEND; 321 322 if (m->len - m->pos < *len) 323 *len = m->len - m->pos; 324 325 *flags = 0; 326 if (!m->pos) 327 *flags |= LWSSS_FLAG_SOM; 328 329 memcpy(buf, postbody + m->pos, *len); 330 331 m->pos += *len; 332 333 if (m->pos == m->len) 334 *flags |= LWSSS_FLAG_EOM; 335 336 lwsl_notice("%s: write %d flags %d\n", __func__, (int)*len, (int)*flags); 337 338 if (m->pos != m->len) 339 return lws_ss_request_tx(m->ss); 340 341 return 0; 342} 343 344static lws_ss_state_return_t 345myss_state(void *userobj, void *sh, lws_ss_constate_t state, 346 lws_ss_tx_ordinal_t ack) 347{ 348 myss_t *m = (myss_t *)userobj; 349 350 lwsl_user("%s: h %p, %s, ord 0x%x\n", __func__, m->ss, 351 lws_ss_state_name((int)state), (unsigned int)ack); 352 353 switch (state) { 354 case LWSSSCS_CREATING: 355 356 /* 357 * CREATING is only coming after we have asked the upstream 358 * proxy to create the stream and it has been allowed. 359 */ 360 361 if (lws_ss_set_metadata(m->ss, "ctype", 362 "multipart/form-data;boundary=\"boundary\"", 363 39)) 364 return LWSSSSRET_DISCONNECT_ME; 365 366 /* provide a hint about the payload size */ 367 m->pos = 0; 368 m->len = strlen(postbody); 369 370 return lws_ss_request_tx_len(m->ss, (unsigned long)strlen(postbody)); 371 372 case LWSSSCS_CONNECTED: 373 return lws_ss_request_tx(m->ss); 374 375 case LWSSSCS_ALL_RETRIES_FAILED: 376 /* if we're out of retries, we want to close the app and FAIL */ 377 interrupted = 1; 378 break; 379 case LWSSSCS_QOS_ACK_REMOTE: 380 lwsl_notice("%s: LWSSSCS_QOS_ACK_REMOTE\n", __func__); 381 break; 382 383 case LWSSSCS_TIMEOUT: 384 lwsl_notice("%s: LWSSSCS_TIMEOUT\n", __func__); 385 break; 386 default: 387 break; 388 } 389 390 return 0; 391} 392 393static int 394app_system_state_nf(lws_state_manager_t *mgr, lws_state_notify_link_t *link, 395 int current, int target) 396{ 397 struct lws_context *context = lws_system_context_from_system_mgr(mgr); 398#if !defined(LWS_SS_USE_SSPC) 399 400 lws_system_blob_t *ab = lws_system_get_blob(context, 401 LWS_SYSBLOB_TYPE_AUTH, 1 /* AUTH_IDX_ROOT */); 402 size_t size; 403#endif 404 405 /* 406 * For the things we care about, let's notice if we are trying to get 407 * past them when we haven't solved them yet, and make the system 408 * state wait while we trigger the dependent action. 409 */ 410 switch (target) { 411 412#if !defined(LWS_SS_USE_SSPC) 413 414 case LWS_SYSTATE_REGISTERED: 415 size = lws_system_blob_get_size(ab); 416 if (size) 417 break; 418 419 /* let's register our canned root token so auth can use it */ 420 lws_system_blob_direct_set(ab, 421 (const uint8_t *)canned_root_token_payload, 422 strlen(canned_root_token_payload)); 423 break; 424 425#endif 426 427 case LWS_SYSTATE_OPERATIONAL: 428 if (current == LWS_SYSTATE_OPERATIONAL) { 429 lws_ss_info_t ssi; 430 431 /* We're making an outgoing secure stream ourselves */ 432 433 memset(&ssi, 0, sizeof(ssi)); 434 ssi.handle_offset = offsetof(myss_t, ss); 435 ssi.opaque_user_data_offset = offsetof(myss_t, 436 opaque_data); 437 ssi.rx = myss_rx; 438 ssi.tx = myss_tx; 439 ssi.state = myss_state; 440 ssi.user_alloc = sizeof(myss_t); 441 ssi.streamtype = "minpost"; 442 443 if (lws_ss_create(context, 0, &ssi, NULL, NULL, 444 NULL, NULL)) { 445 lwsl_err("%s: failed to create secure stream\n", 446 __func__); 447 return -1; 448 } 449 } 450 break; 451 } 452 453 return 0; 454} 455 456static lws_state_notify_link_t * const app_notifier_list[] = { 457 &nl, NULL 458}; 459 460static void 461sigint_handler(int sig) 462{ 463 interrupted = 1; 464} 465 466int main(int argc, const char **argv) 467{ 468 struct lws_context_creation_info info; 469 struct lws_context *context; 470 const char *p; 471 int n = 0; 472 473 signal(SIGINT, sigint_handler); 474 475 memset(&info, 0, sizeof info); 476 lws_cmdline_option_handle_builtin(argc, argv, &info); 477 478 lwsl_user("LWS secure streams test client [-d<verb>]\n"); 479 480 /* these options are mutually exclusive if given */ 481 482 if (lws_cmdline_option(argc, argv, "--force-portal")) 483 force_cpd_fail_portal = 1; 484 485 if (lws_cmdline_option(argc, argv, "--force-no-internet")) 486 force_cpd_fail_no_internet = 1; 487 488 if ((p = lws_cmdline_option(argc, argv, "--timeout_ms"))) 489 timeout_ms = (unsigned int)atoi(p); 490 491 info.fd_limit_per_thread = 1 + 6 + 1; 492 info.port = CONTEXT_PORT_NO_LISTEN; 493#if defined(LWS_SS_USE_SSPC) 494 info.protocols = lws_sspc_protocols; 495 { 496 const char *p; 497 498 /* connect to ssproxy via UDS by default, else via 499 * tcp connection to this port */ 500 if ((p = lws_cmdline_option(argc, argv, "-p"))) 501 info.ss_proxy_port = (uint16_t)atoi(p); 502 503 /* UDS "proxy.ss.lws" in abstract namespace, else this socket 504 * path; when -p given this can specify the network interface 505 * to bind to */ 506 if ((p = lws_cmdline_option(argc, argv, "-i"))) 507 info.ss_proxy_bind = p; 508 509 /* if -p given, -a specifies the proxy address to connect to */ 510 if ((p = lws_cmdline_option(argc, argv, "-a"))) 511 info.ss_proxy_address = p; 512 } 513#else 514 info.pss_policies_json = default_ss_policy; 515 info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS | 516 LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; 517#endif 518 519 /* integrate us with lws system state management when context created */ 520 521 nl.name = "app"; 522 nl.notify_cb = app_system_state_nf; 523 info.register_notifier_list = app_notifier_list; 524 525 /* create the context */ 526 527 context = lws_create_context(&info); 528 if (!context) { 529 lwsl_err("lws init failed\n"); 530 return 1; 531 } 532 533#if !defined(LWS_SS_USE_SSPC) 534 /* 535 * If we're being a proxied client, the proxy does all this 536 */ 537 538 /* 539 * Set the related lws_system blobs 540 * 541 * ...direct_set() sets a pointer, so the thing pointed to has to have 542 * a suitable lifetime, eg, something that already exists on the heap or 543 * a const string in .rodata like this 544 */ 545 546 lws_system_blob_direct_set(lws_system_get_blob(context, 547 LWS_SYSBLOB_TYPE_DEVICE_SERIAL, 0), 548 (const uint8_t *)"SN12345678", 10); 549 lws_system_blob_direct_set(lws_system_get_blob(context, 550 LWS_SYSBLOB_TYPE_DEVICE_FW_VERSION, 0), 551 (const uint8_t *)"v0.01", 5); 552 553 /* 554 * ..._heap_append() appends to a buflist kind of arrangement on heap, 555 * just one block is fine, otherwise it will concatenate the fragments 556 * in the order they were appended (and take care of freeing them at 557 * context destroy time). ..._heap_empty() is also available to remove 558 * everything that was already allocated. 559 * 560 * Here we use _heap_append() just so it's tested as well as direct set. 561 */ 562 563 lws_system_blob_heap_append(lws_system_get_blob(context, 564 LWS_SYSBLOB_TYPE_DEVICE_TYPE, 0), 565 (const uint8_t *)"spacerocket", 11); 566#endif 567 568 /* the event loop */ 569 570 while (n >= 0 && !interrupted) 571 n = lws_service(context, 0); 572 573 lws_context_destroy(context); 574 575 lwsl_user("Completed: %s\n", bad ? "failed" : "OK"); 576 577 return bad; 578} 579