1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * lws-minimal-ws-client-binance 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Written in 2010-2020 by Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * Kutoga <kutoga@user.github.invalid> 6d4afb5ceSopenharmony_ci * 7d4afb5ceSopenharmony_ci * This file is made available under the Creative Commons CC0 1.0 8d4afb5ceSopenharmony_ci * Universal Public Domain Dedication. 9d4afb5ceSopenharmony_ci * 10d4afb5ceSopenharmony_ci * This demonstrates a ws client that connects to binance ws server efficiently 11d4afb5ceSopenharmony_ci */ 12d4afb5ceSopenharmony_ci 13d4afb5ceSopenharmony_ci#include <libwebsockets.h> 14d4afb5ceSopenharmony_ci#include <string.h> 15d4afb5ceSopenharmony_ci#include <signal.h> 16d4afb5ceSopenharmony_ci#include <ctype.h> 17d4afb5ceSopenharmony_ci 18d4afb5ceSopenharmony_citypedef struct range { 19d4afb5ceSopenharmony_ci uint64_t sum; 20d4afb5ceSopenharmony_ci uint64_t lowest; 21d4afb5ceSopenharmony_ci uint64_t highest; 22d4afb5ceSopenharmony_ci 23d4afb5ceSopenharmony_ci unsigned int samples; 24d4afb5ceSopenharmony_ci} range_t; 25d4afb5ceSopenharmony_ci 26d4afb5ceSopenharmony_ci/* 27d4afb5ceSopenharmony_ci * This represents your object that "contains" the client connection and has 28d4afb5ceSopenharmony_ci * the client connection bound to it 29d4afb5ceSopenharmony_ci */ 30d4afb5ceSopenharmony_ci 31d4afb5ceSopenharmony_cistatic struct my_conn { 32d4afb5ceSopenharmony_ci lws_sorted_usec_list_t sul; /* schedule connection retry */ 33d4afb5ceSopenharmony_ci lws_sorted_usec_list_t sul_hz; /* 1hz summary */ 34d4afb5ceSopenharmony_ci 35d4afb5ceSopenharmony_ci range_t e_lat_range; 36d4afb5ceSopenharmony_ci range_t price_range; 37d4afb5ceSopenharmony_ci 38d4afb5ceSopenharmony_ci struct lws *wsi; /* related wsi if any */ 39d4afb5ceSopenharmony_ci uint16_t retry_count; /* count of consequetive retries */ 40d4afb5ceSopenharmony_ci} mco; 41d4afb5ceSopenharmony_ci 42d4afb5ceSopenharmony_cistatic struct lws_context *context; 43d4afb5ceSopenharmony_cistatic int interrupted; 44d4afb5ceSopenharmony_ci 45d4afb5ceSopenharmony_ci#if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL) 46d4afb5ceSopenharmony_ci/* 47d4afb5ceSopenharmony_ci * OpenSSL uses the system trust store. mbedTLS / WolfSSL have to be told which 48d4afb5ceSopenharmony_ci * CA to trust explicitly. 49d4afb5ceSopenharmony_ci */ 50d4afb5ceSopenharmony_cistatic const char * const ca_pem_digicert_global_root = 51d4afb5ceSopenharmony_ci "-----BEGIN CERTIFICATE-----\n" 52d4afb5ceSopenharmony_ci "MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\n" 53d4afb5ceSopenharmony_ci "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" 54d4afb5ceSopenharmony_ci "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n" 55d4afb5ceSopenharmony_ci "QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT\n" 56d4afb5ceSopenharmony_ci "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n" 57d4afb5ceSopenharmony_ci "b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG\n" 58d4afb5ceSopenharmony_ci "9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB\n" 59d4afb5ceSopenharmony_ci "CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97\n" 60d4afb5ceSopenharmony_ci "nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt\n" 61d4afb5ceSopenharmony_ci "43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P\n" 62d4afb5ceSopenharmony_ci "T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4\n" 63d4afb5ceSopenharmony_ci "gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO\n" 64d4afb5ceSopenharmony_ci "BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR\n" 65d4afb5ceSopenharmony_ci "TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw\n" 66d4afb5ceSopenharmony_ci "DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr\n" 67d4afb5ceSopenharmony_ci "hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg\n" 68d4afb5ceSopenharmony_ci "06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF\n" 69d4afb5ceSopenharmony_ci "PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls\n" 70d4afb5ceSopenharmony_ci "YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\n" 71d4afb5ceSopenharmony_ci "CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n" 72d4afb5ceSopenharmony_ci "-----END CERTIFICATE-----\n"; 73d4afb5ceSopenharmony_ci#endif 74d4afb5ceSopenharmony_ci 75d4afb5ceSopenharmony_ci/* 76d4afb5ceSopenharmony_ci * The retry and backoff policy we want to use for our client connections 77d4afb5ceSopenharmony_ci */ 78d4afb5ceSopenharmony_ci 79d4afb5ceSopenharmony_cistatic const uint32_t backoff_ms[] = { 1000, 2000, 3000, 4000, 5000 }; 80d4afb5ceSopenharmony_ci 81d4afb5ceSopenharmony_cistatic const lws_retry_bo_t retry = { 82d4afb5ceSopenharmony_ci .retry_ms_table = backoff_ms, 83d4afb5ceSopenharmony_ci .retry_ms_table_count = LWS_ARRAY_SIZE(backoff_ms), 84d4afb5ceSopenharmony_ci .conceal_count = LWS_ARRAY_SIZE(backoff_ms), 85d4afb5ceSopenharmony_ci 86d4afb5ceSopenharmony_ci .secs_since_valid_ping = 400, /* force PINGs after secs idle */ 87d4afb5ceSopenharmony_ci .secs_since_valid_hangup = 400, /* hangup after secs idle */ 88d4afb5ceSopenharmony_ci 89d4afb5ceSopenharmony_ci .jitter_percent = 0, 90d4afb5ceSopenharmony_ci}; 91d4afb5ceSopenharmony_ci 92d4afb5ceSopenharmony_ci/* 93d4afb5ceSopenharmony_ci * If we don't enable permessage-deflate ws extension, during times when there 94d4afb5ceSopenharmony_ci * are many ws messages per second the server coalesces them inside a smaller 95d4afb5ceSopenharmony_ci * number of larger ssl records, for >100 mps typically >2048 records. 96d4afb5ceSopenharmony_ci * 97d4afb5ceSopenharmony_ci * This is a problem, because the coalesced record cannot be send nor decrypted 98d4afb5ceSopenharmony_ci * until the last part of the record is received, meaning additional latency 99d4afb5ceSopenharmony_ci * for the earlier members of the coalesced record that have just been sitting 100d4afb5ceSopenharmony_ci * there waiting for the last one to go out and be decrypted. 101d4afb5ceSopenharmony_ci * 102d4afb5ceSopenharmony_ci * permessage-deflate reduces the data size before the tls layer, for >100mps 103d4afb5ceSopenharmony_ci * reducing the colesced records to ~1.2KB. 104d4afb5ceSopenharmony_ci */ 105d4afb5ceSopenharmony_ci 106d4afb5ceSopenharmony_cistatic const struct lws_extension extensions[] = { 107d4afb5ceSopenharmony_ci { 108d4afb5ceSopenharmony_ci "permessage-deflate", 109d4afb5ceSopenharmony_ci lws_extension_callback_pm_deflate, 110d4afb5ceSopenharmony_ci "permessage-deflate" 111d4afb5ceSopenharmony_ci "; client_no_context_takeover" 112d4afb5ceSopenharmony_ci "; client_max_window_bits" 113d4afb5ceSopenharmony_ci }, 114d4afb5ceSopenharmony_ci { NULL, NULL, NULL /* terminator */ } 115d4afb5ceSopenharmony_ci}; 116d4afb5ceSopenharmony_ci/* 117d4afb5ceSopenharmony_ci * Scheduled sul callback that starts the connection attempt 118d4afb5ceSopenharmony_ci */ 119d4afb5ceSopenharmony_ci 120d4afb5ceSopenharmony_cistatic void 121d4afb5ceSopenharmony_ciconnect_client(lws_sorted_usec_list_t *sul) 122d4afb5ceSopenharmony_ci{ 123d4afb5ceSopenharmony_ci struct my_conn *mco = lws_container_of(sul, struct my_conn, sul); 124d4afb5ceSopenharmony_ci struct lws_client_connect_info i; 125d4afb5ceSopenharmony_ci 126d4afb5ceSopenharmony_ci memset(&i, 0, sizeof(i)); 127d4afb5ceSopenharmony_ci 128d4afb5ceSopenharmony_ci i.context = context; 129d4afb5ceSopenharmony_ci i.port = 443; 130d4afb5ceSopenharmony_ci i.address = "fstream.binance.com"; 131d4afb5ceSopenharmony_ci i.path = "/stream?" 132d4afb5ceSopenharmony_ci "streams=btcusdt@depth@0ms/btcusdt@bookTicker/btcusdt@aggTrade"; 133d4afb5ceSopenharmony_ci i.host = i.address; 134d4afb5ceSopenharmony_ci i.origin = i.address; 135d4afb5ceSopenharmony_ci i.ssl_connection = LCCSCF_USE_SSL | LCCSCF_PRIORITIZE_READS; 136d4afb5ceSopenharmony_ci i.protocol = NULL; 137d4afb5ceSopenharmony_ci i.local_protocol_name = "lws-minimal-client"; 138d4afb5ceSopenharmony_ci i.pwsi = &mco->wsi; 139d4afb5ceSopenharmony_ci i.retry_and_idle_policy = &retry; 140d4afb5ceSopenharmony_ci i.userdata = mco; 141d4afb5ceSopenharmony_ci 142d4afb5ceSopenharmony_ci if (!lws_client_connect_via_info(&i)) 143d4afb5ceSopenharmony_ci /* 144d4afb5ceSopenharmony_ci * Failed... schedule a retry... we can't use the _retry_wsi() 145d4afb5ceSopenharmony_ci * convenience wrapper api here because no valid wsi at this 146d4afb5ceSopenharmony_ci * point. 147d4afb5ceSopenharmony_ci */ 148d4afb5ceSopenharmony_ci if (lws_retry_sul_schedule(context, 0, sul, &retry, 149d4afb5ceSopenharmony_ci connect_client, &mco->retry_count)) { 150d4afb5ceSopenharmony_ci lwsl_err("%s: connection attempts exhausted\n", __func__); 151d4afb5ceSopenharmony_ci interrupted = 1; 152d4afb5ceSopenharmony_ci } 153d4afb5ceSopenharmony_ci} 154d4afb5ceSopenharmony_ci 155d4afb5ceSopenharmony_cistatic void 156d4afb5ceSopenharmony_cirange_reset(range_t *r) 157d4afb5ceSopenharmony_ci{ 158d4afb5ceSopenharmony_ci r->sum = r->highest = 0; 159d4afb5ceSopenharmony_ci r->lowest = 999999999999ull; 160d4afb5ceSopenharmony_ci r->samples = 0; 161d4afb5ceSopenharmony_ci} 162d4afb5ceSopenharmony_ci 163d4afb5ceSopenharmony_cistatic uint64_t 164d4afb5ceSopenharmony_ciget_us_timeofday(void) 165d4afb5ceSopenharmony_ci{ 166d4afb5ceSopenharmony_ci struct timeval tv; 167d4afb5ceSopenharmony_ci 168d4afb5ceSopenharmony_ci gettimeofday(&tv, NULL); 169d4afb5ceSopenharmony_ci 170d4afb5ceSopenharmony_ci return (uint64_t)((lws_usec_t)tv.tv_sec * LWS_US_PER_SEC) + (uint64_t)tv.tv_usec; 171d4afb5ceSopenharmony_ci} 172d4afb5ceSopenharmony_ci 173d4afb5ceSopenharmony_cistatic void 174d4afb5ceSopenharmony_cisul_hz_cb(lws_sorted_usec_list_t *sul) 175d4afb5ceSopenharmony_ci{ 176d4afb5ceSopenharmony_ci struct my_conn *mco = lws_container_of(sul, struct my_conn, sul_hz); 177d4afb5ceSopenharmony_ci 178d4afb5ceSopenharmony_ci /* 179d4afb5ceSopenharmony_ci * We are called once a second to dump statistics on the connection 180d4afb5ceSopenharmony_ci */ 181d4afb5ceSopenharmony_ci 182d4afb5ceSopenharmony_ci lws_sul_schedule(lws_get_context(mco->wsi), 0, &mco->sul_hz, 183d4afb5ceSopenharmony_ci sul_hz_cb, LWS_US_PER_SEC); 184d4afb5ceSopenharmony_ci 185d4afb5ceSopenharmony_ci if (mco->price_range.samples) 186d4afb5ceSopenharmony_ci lwsl_notice("%s: price: min: %llu¢, max: %llu¢, avg: %llu¢, " 187d4afb5ceSopenharmony_ci "(%d prices/s)\n", 188d4afb5ceSopenharmony_ci __func__, 189d4afb5ceSopenharmony_ci (unsigned long long)mco->price_range.lowest, 190d4afb5ceSopenharmony_ci (unsigned long long)mco->price_range.highest, 191d4afb5ceSopenharmony_ci (unsigned long long)(mco->price_range.sum / mco->price_range.samples), 192d4afb5ceSopenharmony_ci mco->price_range.samples); 193d4afb5ceSopenharmony_ci if (mco->e_lat_range.samples) 194d4afb5ceSopenharmony_ci lwsl_notice("%s: elatency: min: %llums, max: %llums, " 195d4afb5ceSopenharmony_ci "avg: %llums, (%d msg/s)\n", __func__, 196d4afb5ceSopenharmony_ci (unsigned long long)mco->e_lat_range.lowest / 1000, 197d4afb5ceSopenharmony_ci (unsigned long long)mco->e_lat_range.highest / 1000, 198d4afb5ceSopenharmony_ci (unsigned long long)(mco->e_lat_range.sum / 199d4afb5ceSopenharmony_ci mco->e_lat_range.samples) / 1000, 200d4afb5ceSopenharmony_ci mco->e_lat_range.samples); 201d4afb5ceSopenharmony_ci 202d4afb5ceSopenharmony_ci range_reset(&mco->e_lat_range); 203d4afb5ceSopenharmony_ci range_reset(&mco->price_range); 204d4afb5ceSopenharmony_ci} 205d4afb5ceSopenharmony_ci 206d4afb5ceSopenharmony_cistatic uint64_t 207d4afb5ceSopenharmony_cipennies(const char *s) 208d4afb5ceSopenharmony_ci{ 209d4afb5ceSopenharmony_ci uint64_t price = (uint64_t)atoll(s) * 100; 210d4afb5ceSopenharmony_ci 211d4afb5ceSopenharmony_ci s = strchr(s, '.'); 212d4afb5ceSopenharmony_ci 213d4afb5ceSopenharmony_ci if (s && isdigit(s[1]) && isdigit(s[2])) 214d4afb5ceSopenharmony_ci price = price + (uint64_t)((10 * (s[1] - '0')) + (s[2] - '0')); 215d4afb5ceSopenharmony_ci 216d4afb5ceSopenharmony_ci return price; 217d4afb5ceSopenharmony_ci} 218d4afb5ceSopenharmony_ci 219d4afb5ceSopenharmony_cistatic int 220d4afb5ceSopenharmony_cicallback_minimal(struct lws *wsi, enum lws_callback_reasons reason, 221d4afb5ceSopenharmony_ci void *user, void *in, size_t len) 222d4afb5ceSopenharmony_ci{ 223d4afb5ceSopenharmony_ci struct my_conn *mco = (struct my_conn *)user; 224d4afb5ceSopenharmony_ci uint64_t latency_us, now_us; 225d4afb5ceSopenharmony_ci uint64_t price; 226d4afb5ceSopenharmony_ci char numbuf[16]; 227d4afb5ceSopenharmony_ci const char *p; 228d4afb5ceSopenharmony_ci size_t alen; 229d4afb5ceSopenharmony_ci 230d4afb5ceSopenharmony_ci switch (reason) { 231d4afb5ceSopenharmony_ci 232d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: 233d4afb5ceSopenharmony_ci lwsl_err("CLIENT_CONNECTION_ERROR: %s\n", 234d4afb5ceSopenharmony_ci in ? (char *)in : "(null)"); 235d4afb5ceSopenharmony_ci goto do_retry; 236d4afb5ceSopenharmony_ci break; 237d4afb5ceSopenharmony_ci 238d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLIENT_RECEIVE: 239d4afb5ceSopenharmony_ci /* 240d4afb5ceSopenharmony_ci * The messages are a few 100 bytes of JSON each 241d4afb5ceSopenharmony_ci */ 242d4afb5ceSopenharmony_ci 243d4afb5ceSopenharmony_ci // lwsl_hexdump_notice(in, len); 244d4afb5ceSopenharmony_ci 245d4afb5ceSopenharmony_ci now_us = (uint64_t)get_us_timeofday(); 246d4afb5ceSopenharmony_ci 247d4afb5ceSopenharmony_ci p = lws_json_simple_find((const char *)in, len, 248d4afb5ceSopenharmony_ci "\"depthUpdate\"", &alen); 249d4afb5ceSopenharmony_ci /* 250d4afb5ceSopenharmony_ci * Only the JSON with depthUpdate init has the numbers we care 251d4afb5ceSopenharmony_ci * about as well 252d4afb5ceSopenharmony_ci */ 253d4afb5ceSopenharmony_ci if (!p) 254d4afb5ceSopenharmony_ci break; 255d4afb5ceSopenharmony_ci 256d4afb5ceSopenharmony_ci p = lws_json_simple_find((const char *)in, len, "\"E\":", &alen); 257d4afb5ceSopenharmony_ci if (!p) { 258d4afb5ceSopenharmony_ci lwsl_err("%s: no E JSON\n", __func__); 259d4afb5ceSopenharmony_ci break; 260d4afb5ceSopenharmony_ci } 261d4afb5ceSopenharmony_ci lws_strnncpy(numbuf, p, alen, sizeof(numbuf)); 262d4afb5ceSopenharmony_ci latency_us = now_us - 263d4afb5ceSopenharmony_ci ((uint64_t)atoll(numbuf) * LWS_US_PER_MS); 264d4afb5ceSopenharmony_ci 265d4afb5ceSopenharmony_ci if (latency_us < mco->e_lat_range.lowest) 266d4afb5ceSopenharmony_ci mco->e_lat_range.lowest = latency_us; 267d4afb5ceSopenharmony_ci if (latency_us > mco->e_lat_range.highest) 268d4afb5ceSopenharmony_ci mco->e_lat_range.highest = latency_us; 269d4afb5ceSopenharmony_ci 270d4afb5ceSopenharmony_ci mco->e_lat_range.sum += latency_us; 271d4afb5ceSopenharmony_ci mco->e_lat_range.samples++; 272d4afb5ceSopenharmony_ci 273d4afb5ceSopenharmony_ci p = lws_json_simple_find((const char *)in, len, 274d4afb5ceSopenharmony_ci "\"a\":[[\"", &alen); 275d4afb5ceSopenharmony_ci if (p) { 276d4afb5ceSopenharmony_ci lws_strnncpy(numbuf, p, alen, sizeof(numbuf)); 277d4afb5ceSopenharmony_ci price = pennies(numbuf); 278d4afb5ceSopenharmony_ci 279d4afb5ceSopenharmony_ci if (price < mco->price_range.lowest) 280d4afb5ceSopenharmony_ci mco->price_range.lowest = price; 281d4afb5ceSopenharmony_ci if (price > mco->price_range.highest) 282d4afb5ceSopenharmony_ci mco->price_range.highest = price; 283d4afb5ceSopenharmony_ci 284d4afb5ceSopenharmony_ci mco->price_range.sum += price; 285d4afb5ceSopenharmony_ci mco->price_range.samples++; 286d4afb5ceSopenharmony_ci } 287d4afb5ceSopenharmony_ci break; 288d4afb5ceSopenharmony_ci 289d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLIENT_ESTABLISHED: 290d4afb5ceSopenharmony_ci lwsl_user("%s: established\n", __func__); 291d4afb5ceSopenharmony_ci lws_sul_schedule(lws_get_context(wsi), 0, &mco->sul_hz, 292d4afb5ceSopenharmony_ci sul_hz_cb, LWS_US_PER_SEC); 293d4afb5ceSopenharmony_ci mco->wsi = wsi; 294d4afb5ceSopenharmony_ci range_reset(&mco->e_lat_range); 295d4afb5ceSopenharmony_ci range_reset(&mco->price_range); 296d4afb5ceSopenharmony_ci break; 297d4afb5ceSopenharmony_ci 298d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLIENT_CLOSED: 299d4afb5ceSopenharmony_ci lws_sul_cancel(&mco->sul_hz); 300d4afb5ceSopenharmony_ci goto do_retry; 301d4afb5ceSopenharmony_ci 302d4afb5ceSopenharmony_ci default: 303d4afb5ceSopenharmony_ci break; 304d4afb5ceSopenharmony_ci } 305d4afb5ceSopenharmony_ci 306d4afb5ceSopenharmony_ci return lws_callback_http_dummy(wsi, reason, user, in, len); 307d4afb5ceSopenharmony_ci 308d4afb5ceSopenharmony_cido_retry: 309d4afb5ceSopenharmony_ci /* 310d4afb5ceSopenharmony_ci * retry the connection to keep it nailed up 311d4afb5ceSopenharmony_ci * 312d4afb5ceSopenharmony_ci * For this example, we try to conceal any problem for one set of 313d4afb5ceSopenharmony_ci * backoff retries and then exit the app. 314d4afb5ceSopenharmony_ci * 315d4afb5ceSopenharmony_ci * If you set retry.conceal_count to be larger than the number of 316d4afb5ceSopenharmony_ci * elements in the backoff table, it will never give up and keep 317d4afb5ceSopenharmony_ci * retrying at the last backoff delay plus the random jitter amount. 318d4afb5ceSopenharmony_ci */ 319d4afb5ceSopenharmony_ci if (lws_retry_sul_schedule_retry_wsi(wsi, &mco->sul, connect_client, 320d4afb5ceSopenharmony_ci &mco->retry_count)) { 321d4afb5ceSopenharmony_ci lwsl_err("%s: connection attempts exhausted\n", __func__); 322d4afb5ceSopenharmony_ci interrupted = 1; 323d4afb5ceSopenharmony_ci } 324d4afb5ceSopenharmony_ci 325d4afb5ceSopenharmony_ci return 0; 326d4afb5ceSopenharmony_ci} 327d4afb5ceSopenharmony_ci 328d4afb5ceSopenharmony_cistatic const struct lws_protocols protocols[] = { 329d4afb5ceSopenharmony_ci { "lws-minimal-client", callback_minimal, 0, 0, 0, NULL, 0 }, 330d4afb5ceSopenharmony_ci LWS_PROTOCOL_LIST_TERM 331d4afb5ceSopenharmony_ci}; 332d4afb5ceSopenharmony_ci 333d4afb5ceSopenharmony_cistatic void 334d4afb5ceSopenharmony_cisigint_handler(int sig) 335d4afb5ceSopenharmony_ci{ 336d4afb5ceSopenharmony_ci interrupted = 1; 337d4afb5ceSopenharmony_ci} 338d4afb5ceSopenharmony_ci 339d4afb5ceSopenharmony_ciint main(int argc, const char **argv) 340d4afb5ceSopenharmony_ci{ 341d4afb5ceSopenharmony_ci struct lws_context_creation_info info; 342d4afb5ceSopenharmony_ci int n = 0; 343d4afb5ceSopenharmony_ci 344d4afb5ceSopenharmony_ci signal(SIGINT, sigint_handler); 345d4afb5ceSopenharmony_ci memset(&info, 0, sizeof info); 346d4afb5ceSopenharmony_ci lws_cmdline_option_handle_builtin(argc, argv, &info); 347d4afb5ceSopenharmony_ci 348d4afb5ceSopenharmony_ci lwsl_user("LWS minimal binance client\n"); 349d4afb5ceSopenharmony_ci 350d4afb5ceSopenharmony_ci info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; 351d4afb5ceSopenharmony_ci info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */ 352d4afb5ceSopenharmony_ci info.protocols = protocols; 353d4afb5ceSopenharmony_ci info.fd_limit_per_thread = 1 + 1 + 1; 354d4afb5ceSopenharmony_ci info.extensions = extensions; 355d4afb5ceSopenharmony_ci 356d4afb5ceSopenharmony_ci#if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL) 357d4afb5ceSopenharmony_ci /* 358d4afb5ceSopenharmony_ci * OpenSSL uses the system trust store. mbedTLS / WolfSSL have to be 359d4afb5ceSopenharmony_ci * told which CA to trust explicitly. 360d4afb5ceSopenharmony_ci */ 361d4afb5ceSopenharmony_ci info.client_ssl_ca_mem = ca_pem_digicert_global_root; 362d4afb5ceSopenharmony_ci info.client_ssl_ca_mem_len = (unsigned int)strlen(ca_pem_digicert_global_root); 363d4afb5ceSopenharmony_ci#endif 364d4afb5ceSopenharmony_ci 365d4afb5ceSopenharmony_ci context = lws_create_context(&info); 366d4afb5ceSopenharmony_ci if (!context) { 367d4afb5ceSopenharmony_ci lwsl_err("lws init failed\n"); 368d4afb5ceSopenharmony_ci return 1; 369d4afb5ceSopenharmony_ci } 370d4afb5ceSopenharmony_ci 371d4afb5ceSopenharmony_ci /* schedule the first client connection attempt to happen immediately */ 372d4afb5ceSopenharmony_ci lws_sul_schedule(context, 0, &mco.sul, connect_client, 1); 373d4afb5ceSopenharmony_ci 374d4afb5ceSopenharmony_ci while (n >= 0 && !interrupted) 375d4afb5ceSopenharmony_ci n = lws_service(context, 0); 376d4afb5ceSopenharmony_ci 377d4afb5ceSopenharmony_ci lws_context_destroy(context); 378d4afb5ceSopenharmony_ci lwsl_user("Completed\n"); 379d4afb5ceSopenharmony_ci 380d4afb5ceSopenharmony_ci return 0; 381d4afb5ceSopenharmony_ci} 382d4afb5ceSopenharmony_ci 383