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