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