1*1c60b9acSAndroid Build Coastguard Worker /*
2*1c60b9acSAndroid Build Coastguard Worker * lws-minimal-http-client-multi
3*1c60b9acSAndroid Build Coastguard Worker *
4*1c60b9acSAndroid Build Coastguard Worker * Written in 2010-2021 by Andy Green <[email protected]>
5*1c60b9acSAndroid Build Coastguard Worker *
6*1c60b9acSAndroid Build Coastguard Worker * This file is made available under the Creative Commons CC0 1.0
7*1c60b9acSAndroid Build Coastguard Worker * Universal Public Domain Dedication.
8*1c60b9acSAndroid Build Coastguard Worker *
9*1c60b9acSAndroid Build Coastguard Worker * This demonstrates the a minimal http client using lws, which makes
10*1c60b9acSAndroid Build Coastguard Worker * 8 downloads simultaneously from warmcat.com.
11*1c60b9acSAndroid Build Coastguard Worker *
12*1c60b9acSAndroid Build Coastguard Worker * Currently that takes the form of 8 individual simultaneous tcp and
13*1c60b9acSAndroid Build Coastguard Worker * tls connections, which happen concurrently. Notice that the ordering
14*1c60b9acSAndroid Build Coastguard Worker * of the returned payload may be intermingled for the various connections.
15*1c60b9acSAndroid Build Coastguard Worker *
16*1c60b9acSAndroid Build Coastguard Worker * By default the connections happen all together at the beginning and operate
17*1c60b9acSAndroid Build Coastguard Worker * concurrently, which is fast. However this is resource-intenstive, there are
18*1c60b9acSAndroid Build Coastguard Worker * 8 tcp connections, 8 tls tunnels on both the client and server. You can
19*1c60b9acSAndroid Build Coastguard Worker * instead opt to have the connections happen one after the other inside a
20*1c60b9acSAndroid Build Coastguard Worker * single tcp connection and tls tunnel, using HTTP/1.1 pipelining. To be
21*1c60b9acSAndroid Build Coastguard Worker * eligible to be pipelined on another existing connection to the same server,
22*1c60b9acSAndroid Build Coastguard Worker * the client connection must have the LCCSCF_PIPELINE flag on its
23*1c60b9acSAndroid Build Coastguard Worker * info.ssl_connection member (this is independent of whether the connection
24*1c60b9acSAndroid Build Coastguard Worker * is in ssl mode or not).
25*1c60b9acSAndroid Build Coastguard Worker *
26*1c60b9acSAndroid Build Coastguard Worker * HTTP/1.0: Pipelining only possible if Keep-Alive: yes sent by server
27*1c60b9acSAndroid Build Coastguard Worker * HTTP/1.1: always possible... serializes requests
28*1c60b9acSAndroid Build Coastguard Worker * HTTP/2: always possible... all requests sent as individual streams in parallel
29*1c60b9acSAndroid Build Coastguard Worker *
30*1c60b9acSAndroid Build Coastguard Worker * Note: stats are kept on tls session reuse and checked depending on mode
31*1c60b9acSAndroid Build Coastguard Worker *
32*1c60b9acSAndroid Build Coastguard Worker * - default: no reuse expected (connections made too quickly at once)
33*1c60b9acSAndroid Build Coastguard Worker * - staggered, no pipeline: n - 1 reuse expected
34*1c60b9acSAndroid Build Coastguard Worker * - staggered, pipelined: no reuse expected
35*1c60b9acSAndroid Build Coastguard Worker */
36*1c60b9acSAndroid Build Coastguard Worker
37*1c60b9acSAndroid Build Coastguard Worker #include <libwebsockets.h>
38*1c60b9acSAndroid Build Coastguard Worker #include <string.h>
39*1c60b9acSAndroid Build Coastguard Worker #include <signal.h>
40*1c60b9acSAndroid Build Coastguard Worker #include <assert.h>
41*1c60b9acSAndroid Build Coastguard Worker #include <time.h>
42*1c60b9acSAndroid Build Coastguard Worker #if !defined(WIN32)
43*1c60b9acSAndroid Build Coastguard Worker #include <sys/stat.h>
44*1c60b9acSAndroid Build Coastguard Worker #include <fcntl.h>
45*1c60b9acSAndroid Build Coastguard Worker #include <unistd.h>
46*1c60b9acSAndroid Build Coastguard Worker #endif
47*1c60b9acSAndroid Build Coastguard Worker
48*1c60b9acSAndroid Build Coastguard Worker #define COUNT 8
49*1c60b9acSAndroid Build Coastguard Worker
50*1c60b9acSAndroid Build Coastguard Worker struct cliuser {
51*1c60b9acSAndroid Build Coastguard Worker int index;
52*1c60b9acSAndroid Build Coastguard Worker };
53*1c60b9acSAndroid Build Coastguard Worker
54*1c60b9acSAndroid Build Coastguard Worker static int completed, failed, numbered, stagger_idx, posting, count = COUNT,
55*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_TLS_SESSIONS)
56*1c60b9acSAndroid Build Coastguard Worker reuse,
57*1c60b9acSAndroid Build Coastguard Worker #endif
58*1c60b9acSAndroid Build Coastguard Worker staggered;
59*1c60b9acSAndroid Build Coastguard Worker static lws_sorted_usec_list_t sul_stagger;
60*1c60b9acSAndroid Build Coastguard Worker static struct lws_client_connect_info i;
61*1c60b9acSAndroid Build Coastguard Worker static struct lws *client_wsi[COUNT];
62*1c60b9acSAndroid Build Coastguard Worker static char urlpath[64], intr;
63*1c60b9acSAndroid Build Coastguard Worker static struct lws_context *context;
64*1c60b9acSAndroid Build Coastguard Worker
65*1c60b9acSAndroid Build Coastguard Worker /* we only need this for tracking POST emit state */
66*1c60b9acSAndroid Build Coastguard Worker
67*1c60b9acSAndroid Build Coastguard Worker struct pss {
68*1c60b9acSAndroid Build Coastguard Worker char body_part;
69*1c60b9acSAndroid Build Coastguard Worker };
70*1c60b9acSAndroid Build Coastguard Worker
71*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_TLS_SESSIONS) && !defined(LWS_WITH_MBEDTLS) && !defined(WIN32)
72*1c60b9acSAndroid Build Coastguard Worker
73*1c60b9acSAndroid Build Coastguard Worker /* this should work OK on win32, but not adapted for non-posix file apis */
74*1c60b9acSAndroid Build Coastguard Worker
75*1c60b9acSAndroid Build Coastguard Worker static int
sess_save_cb(struct lws_context * cx,struct lws_tls_session_dump * info)76*1c60b9acSAndroid Build Coastguard Worker sess_save_cb(struct lws_context *cx, struct lws_tls_session_dump *info)
77*1c60b9acSAndroid Build Coastguard Worker {
78*1c60b9acSAndroid Build Coastguard Worker char path[128];
79*1c60b9acSAndroid Build Coastguard Worker int fd, n;
80*1c60b9acSAndroid Build Coastguard Worker
81*1c60b9acSAndroid Build Coastguard Worker lws_snprintf(path, sizeof(path), "%s/lws_tls_sess_%s", (const char *)info->opaque,
82*1c60b9acSAndroid Build Coastguard Worker info->tag);
83*1c60b9acSAndroid Build Coastguard Worker fd = open(path, LWS_O_WRONLY | O_CREAT | O_TRUNC, 0600);
84*1c60b9acSAndroid Build Coastguard Worker if (fd < 0) {
85*1c60b9acSAndroid Build Coastguard Worker lwsl_warn("%s: cannot open %s\n", __func__, path);
86*1c60b9acSAndroid Build Coastguard Worker return 1;
87*1c60b9acSAndroid Build Coastguard Worker }
88*1c60b9acSAndroid Build Coastguard Worker
89*1c60b9acSAndroid Build Coastguard Worker n = (int)write(fd, info->blob, info->blob_len);
90*1c60b9acSAndroid Build Coastguard Worker
91*1c60b9acSAndroid Build Coastguard Worker close(fd);
92*1c60b9acSAndroid Build Coastguard Worker
93*1c60b9acSAndroid Build Coastguard Worker return n != (int)info->blob_len;
94*1c60b9acSAndroid Build Coastguard Worker }
95*1c60b9acSAndroid Build Coastguard Worker
96*1c60b9acSAndroid Build Coastguard Worker static int
sess_load_cb(struct lws_context * cx,struct lws_tls_session_dump * info)97*1c60b9acSAndroid Build Coastguard Worker sess_load_cb(struct lws_context *cx, struct lws_tls_session_dump *info)
98*1c60b9acSAndroid Build Coastguard Worker {
99*1c60b9acSAndroid Build Coastguard Worker struct stat sta;
100*1c60b9acSAndroid Build Coastguard Worker char path[128];
101*1c60b9acSAndroid Build Coastguard Worker int fd, n;
102*1c60b9acSAndroid Build Coastguard Worker
103*1c60b9acSAndroid Build Coastguard Worker lws_snprintf(path, sizeof(path), "%s/lws_tls_sess_%s", (const char *)info->opaque,
104*1c60b9acSAndroid Build Coastguard Worker info->tag);
105*1c60b9acSAndroid Build Coastguard Worker fd = open(path, LWS_O_RDONLY);
106*1c60b9acSAndroid Build Coastguard Worker if (fd < 0)
107*1c60b9acSAndroid Build Coastguard Worker return 1;
108*1c60b9acSAndroid Build Coastguard Worker
109*1c60b9acSAndroid Build Coastguard Worker if (fstat(fd, &sta) || !sta.st_size)
110*1c60b9acSAndroid Build Coastguard Worker goto bail;
111*1c60b9acSAndroid Build Coastguard Worker
112*1c60b9acSAndroid Build Coastguard Worker info->blob = malloc((size_t)sta.st_size);
113*1c60b9acSAndroid Build Coastguard Worker /* caller will free this */
114*1c60b9acSAndroid Build Coastguard Worker if (!info->blob)
115*1c60b9acSAndroid Build Coastguard Worker goto bail;
116*1c60b9acSAndroid Build Coastguard Worker
117*1c60b9acSAndroid Build Coastguard Worker info->blob_len = (size_t)sta.st_size;
118*1c60b9acSAndroid Build Coastguard Worker
119*1c60b9acSAndroid Build Coastguard Worker n = (int)read(fd, info->blob, info->blob_len);
120*1c60b9acSAndroid Build Coastguard Worker close(fd);
121*1c60b9acSAndroid Build Coastguard Worker
122*1c60b9acSAndroid Build Coastguard Worker return n != (int)info->blob_len;
123*1c60b9acSAndroid Build Coastguard Worker
124*1c60b9acSAndroid Build Coastguard Worker bail:
125*1c60b9acSAndroid Build Coastguard Worker close(fd);
126*1c60b9acSAndroid Build Coastguard Worker
127*1c60b9acSAndroid Build Coastguard Worker return 1;
128*1c60b9acSAndroid Build Coastguard Worker }
129*1c60b9acSAndroid Build Coastguard Worker #endif
130*1c60b9acSAndroid Build Coastguard Worker
131*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_CONMON)
132*1c60b9acSAndroid Build Coastguard Worker void
dump_conmon_data(struct lws * wsi)133*1c60b9acSAndroid Build Coastguard Worker dump_conmon_data(struct lws *wsi)
134*1c60b9acSAndroid Build Coastguard Worker {
135*1c60b9acSAndroid Build Coastguard Worker const struct addrinfo *ai;
136*1c60b9acSAndroid Build Coastguard Worker struct lws_conmon cm;
137*1c60b9acSAndroid Build Coastguard Worker char ads[48];
138*1c60b9acSAndroid Build Coastguard Worker
139*1c60b9acSAndroid Build Coastguard Worker lws_conmon_wsi_take(wsi, &cm);
140*1c60b9acSAndroid Build Coastguard Worker
141*1c60b9acSAndroid Build Coastguard Worker lws_sa46_write_numeric_address(&cm.peer46, ads, sizeof(ads));
142*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: peer %s, dns: %uus, sockconn: %uus, tls: %uus, txn_resp: %uus\n",
143*1c60b9acSAndroid Build Coastguard Worker __func__, ads,
144*1c60b9acSAndroid Build Coastguard Worker (unsigned int)cm.ciu_dns,
145*1c60b9acSAndroid Build Coastguard Worker (unsigned int)cm.ciu_sockconn,
146*1c60b9acSAndroid Build Coastguard Worker (unsigned int)cm.ciu_tls,
147*1c60b9acSAndroid Build Coastguard Worker (unsigned int)cm.ciu_txn_resp);
148*1c60b9acSAndroid Build Coastguard Worker
149*1c60b9acSAndroid Build Coastguard Worker ai = cm.dns_results_copy;
150*1c60b9acSAndroid Build Coastguard Worker while (ai) {
151*1c60b9acSAndroid Build Coastguard Worker lws_sa46_write_numeric_address((lws_sockaddr46 *)ai->ai_addr, ads, sizeof(ads));
152*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: DNS %s\n", __func__, ads);
153*1c60b9acSAndroid Build Coastguard Worker ai = ai->ai_next;
154*1c60b9acSAndroid Build Coastguard Worker }
155*1c60b9acSAndroid Build Coastguard Worker
156*1c60b9acSAndroid Build Coastguard Worker /*
157*1c60b9acSAndroid Build Coastguard Worker * This destroys the DNS list in the lws_conmon that we took
158*1c60b9acSAndroid Build Coastguard Worker * responsibility for when we used lws_conmon_wsi_take()
159*1c60b9acSAndroid Build Coastguard Worker */
160*1c60b9acSAndroid Build Coastguard Worker
161*1c60b9acSAndroid Build Coastguard Worker lws_conmon_release(&cm);
162*1c60b9acSAndroid Build Coastguard Worker }
163*1c60b9acSAndroid Build Coastguard Worker #endif
164*1c60b9acSAndroid Build Coastguard Worker
165*1c60b9acSAndroid Build Coastguard Worker static int
callback_http(struct lws * wsi,enum lws_callback_reasons reason,void * user,void * in,size_t len)166*1c60b9acSAndroid Build Coastguard Worker callback_http(struct lws *wsi, enum lws_callback_reasons reason,
167*1c60b9acSAndroid Build Coastguard Worker void *user, void *in, size_t len)
168*1c60b9acSAndroid Build Coastguard Worker {
169*1c60b9acSAndroid Build Coastguard Worker char buf[LWS_PRE + 1024], *start = &buf[LWS_PRE], *p = start,
170*1c60b9acSAndroid Build Coastguard Worker *end = &buf[sizeof(buf) - LWS_PRE - 1];
171*1c60b9acSAndroid Build Coastguard Worker int n, idx = (int)(intptr_t)lws_get_opaque_user_data(wsi);
172*1c60b9acSAndroid Build Coastguard Worker struct pss *pss = (struct pss *)user;
173*1c60b9acSAndroid Build Coastguard Worker
174*1c60b9acSAndroid Build Coastguard Worker switch (reason) {
175*1c60b9acSAndroid Build Coastguard Worker
176*1c60b9acSAndroid Build Coastguard Worker case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
177*1c60b9acSAndroid Build Coastguard Worker lwsl_user("LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: idx: %d, resp %u\n",
178*1c60b9acSAndroid Build Coastguard Worker idx, lws_http_client_http_response(wsi));
179*1c60b9acSAndroid Build Coastguard Worker
180*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_TLS_SESSIONS) && !defined(LWS_WITH_MBEDTLS) && !defined(WIN32)
181*1c60b9acSAndroid Build Coastguard Worker if (lws_tls_session_is_reused(wsi))
182*1c60b9acSAndroid Build Coastguard Worker reuse++;
183*1c60b9acSAndroid Build Coastguard Worker else
184*1c60b9acSAndroid Build Coastguard Worker /*
185*1c60b9acSAndroid Build Coastguard Worker * Attempt to store any new session into
186*1c60b9acSAndroid Build Coastguard Worker * external storage
187*1c60b9acSAndroid Build Coastguard Worker */
188*1c60b9acSAndroid Build Coastguard Worker if (lws_tls_session_dump_save(lws_get_vhost_by_name(context, "default"),
189*1c60b9acSAndroid Build Coastguard Worker i.host, (uint16_t)i.port,
190*1c60b9acSAndroid Build Coastguard Worker sess_save_cb, "/tmp"))
191*1c60b9acSAndroid Build Coastguard Worker lwsl_warn("%s: session save failed\n", __func__);
192*1c60b9acSAndroid Build Coastguard Worker #endif
193*1c60b9acSAndroid Build Coastguard Worker break;
194*1c60b9acSAndroid Build Coastguard Worker
195*1c60b9acSAndroid Build Coastguard Worker /* because we are protocols[0] ... */
196*1c60b9acSAndroid Build Coastguard Worker case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
197*1c60b9acSAndroid Build Coastguard Worker lwsl_err("CLIENT_CONNECTION_ERROR: %s\n",
198*1c60b9acSAndroid Build Coastguard Worker in ? (char *)in : "(null)");
199*1c60b9acSAndroid Build Coastguard Worker client_wsi[idx] = NULL;
200*1c60b9acSAndroid Build Coastguard Worker failed++;
201*1c60b9acSAndroid Build Coastguard Worker
202*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_CONMON)
203*1c60b9acSAndroid Build Coastguard Worker dump_conmon_data(wsi);
204*1c60b9acSAndroid Build Coastguard Worker #endif
205*1c60b9acSAndroid Build Coastguard Worker
206*1c60b9acSAndroid Build Coastguard Worker goto finished;
207*1c60b9acSAndroid Build Coastguard Worker
208*1c60b9acSAndroid Build Coastguard Worker /* chunks of chunked content, with header removed */
209*1c60b9acSAndroid Build Coastguard Worker case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
210*1c60b9acSAndroid Build Coastguard Worker lwsl_user("RECEIVE_CLIENT_HTTP_READ: conn %d: read %d\n", idx, (int)len);
211*1c60b9acSAndroid Build Coastguard Worker lwsl_hexdump_info(in, len);
212*1c60b9acSAndroid Build Coastguard Worker return 0; /* don't passthru */
213*1c60b9acSAndroid Build Coastguard Worker
214*1c60b9acSAndroid Build Coastguard Worker case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
215*1c60b9acSAndroid Build Coastguard Worker
216*1c60b9acSAndroid Build Coastguard Worker /*
217*1c60b9acSAndroid Build Coastguard Worker * Tell lws we are going to send the body next...
218*1c60b9acSAndroid Build Coastguard Worker */
219*1c60b9acSAndroid Build Coastguard Worker if (posting && !lws_http_is_redirected_to_get(wsi)) {
220*1c60b9acSAndroid Build Coastguard Worker lwsl_user("%s: conn %d, doing POST flow\n", __func__, idx);
221*1c60b9acSAndroid Build Coastguard Worker lws_client_http_body_pending(wsi, 1);
222*1c60b9acSAndroid Build Coastguard Worker lws_callback_on_writable(wsi);
223*1c60b9acSAndroid Build Coastguard Worker } else
224*1c60b9acSAndroid Build Coastguard Worker lwsl_user("%s: conn %d, doing GET flow\n", __func__, idx);
225*1c60b9acSAndroid Build Coastguard Worker break;
226*1c60b9acSAndroid Build Coastguard Worker
227*1c60b9acSAndroid Build Coastguard Worker /* uninterpreted http content */
228*1c60b9acSAndroid Build Coastguard Worker case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
229*1c60b9acSAndroid Build Coastguard Worker {
230*1c60b9acSAndroid Build Coastguard Worker char buffer[1024 + LWS_PRE];
231*1c60b9acSAndroid Build Coastguard Worker char *px = buffer + LWS_PRE;
232*1c60b9acSAndroid Build Coastguard Worker int lenx = sizeof(buffer) - LWS_PRE;
233*1c60b9acSAndroid Build Coastguard Worker
234*1c60b9acSAndroid Build Coastguard Worker if (lws_http_client_read(wsi, &px, &lenx) < 0)
235*1c60b9acSAndroid Build Coastguard Worker return -1;
236*1c60b9acSAndroid Build Coastguard Worker }
237*1c60b9acSAndroid Build Coastguard Worker return 0; /* don't passthru */
238*1c60b9acSAndroid Build Coastguard Worker
239*1c60b9acSAndroid Build Coastguard Worker case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
240*1c60b9acSAndroid Build Coastguard Worker lwsl_user("LWS_CALLBACK_COMPLETED_CLIENT_HTTP %s: idx %d\n",
241*1c60b9acSAndroid Build Coastguard Worker lws_wsi_tag(wsi), idx);
242*1c60b9acSAndroid Build Coastguard Worker client_wsi[idx] = NULL;
243*1c60b9acSAndroid Build Coastguard Worker goto finished;
244*1c60b9acSAndroid Build Coastguard Worker
245*1c60b9acSAndroid Build Coastguard Worker case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
246*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: closed: %s\n", __func__, lws_wsi_tag(client_wsi[idx]));
247*1c60b9acSAndroid Build Coastguard Worker
248*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_CONMON)
249*1c60b9acSAndroid Build Coastguard Worker dump_conmon_data(wsi);
250*1c60b9acSAndroid Build Coastguard Worker #endif
251*1c60b9acSAndroid Build Coastguard Worker
252*1c60b9acSAndroid Build Coastguard Worker if (client_wsi[idx]) {
253*1c60b9acSAndroid Build Coastguard Worker /*
254*1c60b9acSAndroid Build Coastguard Worker * If it completed normally, it will have been set to
255*1c60b9acSAndroid Build Coastguard Worker * NULL then already. So we are dealing with an
256*1c60b9acSAndroid Build Coastguard Worker * abnormal, failing, close
257*1c60b9acSAndroid Build Coastguard Worker */
258*1c60b9acSAndroid Build Coastguard Worker client_wsi[idx] = NULL;
259*1c60b9acSAndroid Build Coastguard Worker failed++;
260*1c60b9acSAndroid Build Coastguard Worker goto finished;
261*1c60b9acSAndroid Build Coastguard Worker }
262*1c60b9acSAndroid Build Coastguard Worker break;
263*1c60b9acSAndroid Build Coastguard Worker
264*1c60b9acSAndroid Build Coastguard Worker case LWS_CALLBACK_CLIENT_HTTP_WRITEABLE:
265*1c60b9acSAndroid Build Coastguard Worker if (!posting)
266*1c60b9acSAndroid Build Coastguard Worker break;
267*1c60b9acSAndroid Build Coastguard Worker if (lws_http_is_redirected_to_get(wsi))
268*1c60b9acSAndroid Build Coastguard Worker break;
269*1c60b9acSAndroid Build Coastguard Worker lwsl_info("LWS_CALLBACK_CLIENT_HTTP_WRITEABLE: %s, idx %d,"
270*1c60b9acSAndroid Build Coastguard Worker " part %d\n", lws_wsi_tag(wsi), idx, pss->body_part);
271*1c60b9acSAndroid Build Coastguard Worker
272*1c60b9acSAndroid Build Coastguard Worker n = LWS_WRITE_HTTP;
273*1c60b9acSAndroid Build Coastguard Worker
274*1c60b9acSAndroid Build Coastguard Worker /*
275*1c60b9acSAndroid Build Coastguard Worker * For a small body like this, we could prepare it in memory and
276*1c60b9acSAndroid Build Coastguard Worker * send it all at once. But to show how to handle, eg,
277*1c60b9acSAndroid Build Coastguard Worker * arbitrary-sized file payloads, or huge form-data fields, the
278*1c60b9acSAndroid Build Coastguard Worker * sending is done in multiple passes through the event loop.
279*1c60b9acSAndroid Build Coastguard Worker */
280*1c60b9acSAndroid Build Coastguard Worker
281*1c60b9acSAndroid Build Coastguard Worker switch (pss->body_part++) {
282*1c60b9acSAndroid Build Coastguard Worker case 0:
283*1c60b9acSAndroid Build Coastguard Worker if (lws_client_http_multipart(wsi, "text", NULL, NULL,
284*1c60b9acSAndroid Build Coastguard Worker &p, end))
285*1c60b9acSAndroid Build Coastguard Worker return -1;
286*1c60b9acSAndroid Build Coastguard Worker /* notice every usage of the boundary starts with -- */
287*1c60b9acSAndroid Build Coastguard Worker p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "my text field\xd\xa");
288*1c60b9acSAndroid Build Coastguard Worker break;
289*1c60b9acSAndroid Build Coastguard Worker case 1:
290*1c60b9acSAndroid Build Coastguard Worker if (lws_client_http_multipart(wsi, "file", "myfile.txt",
291*1c60b9acSAndroid Build Coastguard Worker "text/plain", &p, end))
292*1c60b9acSAndroid Build Coastguard Worker return -1;
293*1c60b9acSAndroid Build Coastguard Worker p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
294*1c60b9acSAndroid Build Coastguard Worker "This is the contents of the "
295*1c60b9acSAndroid Build Coastguard Worker "uploaded file.\xd\xa"
296*1c60b9acSAndroid Build Coastguard Worker "\xd\xa");
297*1c60b9acSAndroid Build Coastguard Worker break;
298*1c60b9acSAndroid Build Coastguard Worker case 2:
299*1c60b9acSAndroid Build Coastguard Worker if (lws_client_http_multipart(wsi, NULL, NULL, NULL,
300*1c60b9acSAndroid Build Coastguard Worker &p, end))
301*1c60b9acSAndroid Build Coastguard Worker return -1;
302*1c60b9acSAndroid Build Coastguard Worker lws_client_http_body_pending(wsi, 0);
303*1c60b9acSAndroid Build Coastguard Worker /* necessary to support H2, it means we will write no
304*1c60b9acSAndroid Build Coastguard Worker * more on this stream */
305*1c60b9acSAndroid Build Coastguard Worker n = LWS_WRITE_HTTP_FINAL;
306*1c60b9acSAndroid Build Coastguard Worker break;
307*1c60b9acSAndroid Build Coastguard Worker
308*1c60b9acSAndroid Build Coastguard Worker default:
309*1c60b9acSAndroid Build Coastguard Worker /*
310*1c60b9acSAndroid Build Coastguard Worker * We can get extra callbacks here, if nothing to do,
311*1c60b9acSAndroid Build Coastguard Worker * then do nothing.
312*1c60b9acSAndroid Build Coastguard Worker */
313*1c60b9acSAndroid Build Coastguard Worker return 0;
314*1c60b9acSAndroid Build Coastguard Worker }
315*1c60b9acSAndroid Build Coastguard Worker
316*1c60b9acSAndroid Build Coastguard Worker if (lws_write(wsi, (uint8_t *)start, lws_ptr_diff_size_t(p, start), (enum lws_write_protocol)n)
317*1c60b9acSAndroid Build Coastguard Worker != lws_ptr_diff(p, start))
318*1c60b9acSAndroid Build Coastguard Worker return 1;
319*1c60b9acSAndroid Build Coastguard Worker
320*1c60b9acSAndroid Build Coastguard Worker if (n != LWS_WRITE_HTTP_FINAL)
321*1c60b9acSAndroid Build Coastguard Worker lws_callback_on_writable(wsi);
322*1c60b9acSAndroid Build Coastguard Worker
323*1c60b9acSAndroid Build Coastguard Worker break;
324*1c60b9acSAndroid Build Coastguard Worker
325*1c60b9acSAndroid Build Coastguard Worker default:
326*1c60b9acSAndroid Build Coastguard Worker break;
327*1c60b9acSAndroid Build Coastguard Worker }
328*1c60b9acSAndroid Build Coastguard Worker
329*1c60b9acSAndroid Build Coastguard Worker return lws_callback_http_dummy(wsi, reason, user, in, len);
330*1c60b9acSAndroid Build Coastguard Worker
331*1c60b9acSAndroid Build Coastguard Worker finished:
332*1c60b9acSAndroid Build Coastguard Worker if (++completed == count) {
333*1c60b9acSAndroid Build Coastguard Worker if (!failed)
334*1c60b9acSAndroid Build Coastguard Worker lwsl_user("Done: all OK\n");
335*1c60b9acSAndroid Build Coastguard Worker else
336*1c60b9acSAndroid Build Coastguard Worker lwsl_err("Done: failed: %d\n", failed);
337*1c60b9acSAndroid Build Coastguard Worker intr = 1;
338*1c60b9acSAndroid Build Coastguard Worker /*
339*1c60b9acSAndroid Build Coastguard Worker * This is how we can exit the event loop even when it's an
340*1c60b9acSAndroid Build Coastguard Worker * event library backing it... it will start and stage the
341*1c60b9acSAndroid Build Coastguard Worker * destroy to happen after we exited this service for each pt
342*1c60b9acSAndroid Build Coastguard Worker */
343*1c60b9acSAndroid Build Coastguard Worker lws_context_destroy(lws_get_context(wsi));
344*1c60b9acSAndroid Build Coastguard Worker }
345*1c60b9acSAndroid Build Coastguard Worker
346*1c60b9acSAndroid Build Coastguard Worker return 0;
347*1c60b9acSAndroid Build Coastguard Worker }
348*1c60b9acSAndroid Build Coastguard Worker
349*1c60b9acSAndroid Build Coastguard Worker static const struct lws_protocols protocols[] = {
350*1c60b9acSAndroid Build Coastguard Worker { "http", callback_http, sizeof(struct pss), 0, 0, NULL, 0 },
351*1c60b9acSAndroid Build Coastguard Worker LWS_PROTOCOL_LIST_TERM
352*1c60b9acSAndroid Build Coastguard Worker };
353*1c60b9acSAndroid Build Coastguard Worker
354*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_SYS_METRICS)
355*1c60b9acSAndroid Build Coastguard Worker
356*1c60b9acSAndroid Build Coastguard Worker static int
my_metric_report(lws_metric_pub_t * mp)357*1c60b9acSAndroid Build Coastguard Worker my_metric_report(lws_metric_pub_t *mp)
358*1c60b9acSAndroid Build Coastguard Worker {
359*1c60b9acSAndroid Build Coastguard Worker lws_metric_bucket_t *sub = mp->u.hist.head;
360*1c60b9acSAndroid Build Coastguard Worker char buf[192];
361*1c60b9acSAndroid Build Coastguard Worker
362*1c60b9acSAndroid Build Coastguard Worker do {
363*1c60b9acSAndroid Build Coastguard Worker if (lws_metrics_format(mp, &sub, buf, sizeof(buf)))
364*1c60b9acSAndroid Build Coastguard Worker lwsl_user("%s: %s\n", __func__, buf);
365*1c60b9acSAndroid Build Coastguard Worker } while ((mp->flags & LWSMTFL_REPORT_HIST) && sub);
366*1c60b9acSAndroid Build Coastguard Worker
367*1c60b9acSAndroid Build Coastguard Worker /* 0 = leave metric to accumulate, 1 = reset the metric */
368*1c60b9acSAndroid Build Coastguard Worker
369*1c60b9acSAndroid Build Coastguard Worker return 1;
370*1c60b9acSAndroid Build Coastguard Worker }
371*1c60b9acSAndroid Build Coastguard Worker
372*1c60b9acSAndroid Build Coastguard Worker static const lws_system_ops_t system_ops = {
373*1c60b9acSAndroid Build Coastguard Worker .metric_report = my_metric_report,
374*1c60b9acSAndroid Build Coastguard Worker };
375*1c60b9acSAndroid Build Coastguard Worker
376*1c60b9acSAndroid Build Coastguard Worker #endif
377*1c60b9acSAndroid Build Coastguard Worker
378*1c60b9acSAndroid Build Coastguard Worker static void
379*1c60b9acSAndroid Build Coastguard Worker stagger_cb(lws_sorted_usec_list_t *sul);
380*1c60b9acSAndroid Build Coastguard Worker
381*1c60b9acSAndroid Build Coastguard Worker static void
lws_try_client_connection(struct lws_client_connect_info * i,int m)382*1c60b9acSAndroid Build Coastguard Worker lws_try_client_connection(struct lws_client_connect_info *i, int m)
383*1c60b9acSAndroid Build Coastguard Worker {
384*1c60b9acSAndroid Build Coastguard Worker char path[128];
385*1c60b9acSAndroid Build Coastguard Worker
386*1c60b9acSAndroid Build Coastguard Worker if (numbered) {
387*1c60b9acSAndroid Build Coastguard Worker lws_snprintf(path, sizeof(path), "/%d.png", m + 1);
388*1c60b9acSAndroid Build Coastguard Worker i->path = path;
389*1c60b9acSAndroid Build Coastguard Worker } else
390*1c60b9acSAndroid Build Coastguard Worker i->path = urlpath;
391*1c60b9acSAndroid Build Coastguard Worker
392*1c60b9acSAndroid Build Coastguard Worker i->pwsi = &client_wsi[m];
393*1c60b9acSAndroid Build Coastguard Worker i->opaque_user_data = (void *)(intptr_t)m;
394*1c60b9acSAndroid Build Coastguard Worker
395*1c60b9acSAndroid Build Coastguard Worker if (!lws_client_connect_via_info(i)) {
396*1c60b9acSAndroid Build Coastguard Worker failed++;
397*1c60b9acSAndroid Build Coastguard Worker lwsl_user("%s: failed: conn idx %d\n", __func__, m);
398*1c60b9acSAndroid Build Coastguard Worker if (++completed == count) {
399*1c60b9acSAndroid Build Coastguard Worker lwsl_user("Done: failed: %d\n", failed);
400*1c60b9acSAndroid Build Coastguard Worker lws_context_destroy(context);
401*1c60b9acSAndroid Build Coastguard Worker }
402*1c60b9acSAndroid Build Coastguard Worker } else
403*1c60b9acSAndroid Build Coastguard Worker lwsl_user("started connection %s: idx %d (%s)\n",
404*1c60b9acSAndroid Build Coastguard Worker lws_wsi_tag(client_wsi[m]), m, i->path);
405*1c60b9acSAndroid Build Coastguard Worker }
406*1c60b9acSAndroid Build Coastguard Worker
407*1c60b9acSAndroid Build Coastguard Worker
408*1c60b9acSAndroid Build Coastguard Worker static int
system_notify_cb(lws_state_manager_t * mgr,lws_state_notify_link_t * link,int current,int target)409*1c60b9acSAndroid Build Coastguard Worker system_notify_cb(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
410*1c60b9acSAndroid Build Coastguard Worker int current, int target)
411*1c60b9acSAndroid Build Coastguard Worker {
412*1c60b9acSAndroid Build Coastguard Worker struct lws_context *context = mgr->parent;
413*1c60b9acSAndroid Build Coastguard Worker int m;
414*1c60b9acSAndroid Build Coastguard Worker
415*1c60b9acSAndroid Build Coastguard Worker if (current != LWS_SYSTATE_OPERATIONAL || target != LWS_SYSTATE_OPERATIONAL)
416*1c60b9acSAndroid Build Coastguard Worker return 0;
417*1c60b9acSAndroid Build Coastguard Worker
418*1c60b9acSAndroid Build Coastguard Worker /* all the system prerequisites are ready */
419*1c60b9acSAndroid Build Coastguard Worker
420*1c60b9acSAndroid Build Coastguard Worker if (!staggered)
421*1c60b9acSAndroid Build Coastguard Worker /*
422*1c60b9acSAndroid Build Coastguard Worker * just pile on all the connections at once, testing the
423*1c60b9acSAndroid Build Coastguard Worker * pipeline queuing before the first is connected
424*1c60b9acSAndroid Build Coastguard Worker */
425*1c60b9acSAndroid Build Coastguard Worker for (m = 0; m < count; m++)
426*1c60b9acSAndroid Build Coastguard Worker lws_try_client_connection(&i, m);
427*1c60b9acSAndroid Build Coastguard Worker else
428*1c60b9acSAndroid Build Coastguard Worker /*
429*1c60b9acSAndroid Build Coastguard Worker * delay the connections slightly
430*1c60b9acSAndroid Build Coastguard Worker */
431*1c60b9acSAndroid Build Coastguard Worker lws_sul_schedule(context, 0, &sul_stagger, stagger_cb,
432*1c60b9acSAndroid Build Coastguard Worker 50 * LWS_US_PER_MS);
433*1c60b9acSAndroid Build Coastguard Worker
434*1c60b9acSAndroid Build Coastguard Worker return 0;
435*1c60b9acSAndroid Build Coastguard Worker }
436*1c60b9acSAndroid Build Coastguard Worker
437*1c60b9acSAndroid Build Coastguard Worker static void
signal_cb(void * handle,int signum)438*1c60b9acSAndroid Build Coastguard Worker signal_cb(void *handle, int signum)
439*1c60b9acSAndroid Build Coastguard Worker {
440*1c60b9acSAndroid Build Coastguard Worker switch (signum) {
441*1c60b9acSAndroid Build Coastguard Worker case SIGTERM:
442*1c60b9acSAndroid Build Coastguard Worker case SIGINT:
443*1c60b9acSAndroid Build Coastguard Worker break;
444*1c60b9acSAndroid Build Coastguard Worker default:
445*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: signal %d\n", __func__, signum);
446*1c60b9acSAndroid Build Coastguard Worker break;
447*1c60b9acSAndroid Build Coastguard Worker }
448*1c60b9acSAndroid Build Coastguard Worker lws_context_destroy(context);
449*1c60b9acSAndroid Build Coastguard Worker }
450*1c60b9acSAndroid Build Coastguard Worker
451*1c60b9acSAndroid Build Coastguard Worker static void
sigint_handler(int sig)452*1c60b9acSAndroid Build Coastguard Worker sigint_handler(int sig)
453*1c60b9acSAndroid Build Coastguard Worker {
454*1c60b9acSAndroid Build Coastguard Worker signal_cb(NULL, sig);
455*1c60b9acSAndroid Build Coastguard Worker }
456*1c60b9acSAndroid Build Coastguard Worker
457*1c60b9acSAndroid Build Coastguard Worker #if defined(WIN32)
gettimeofday(struct timeval * tp,struct timezone * tzp)458*1c60b9acSAndroid Build Coastguard Worker int gettimeofday(struct timeval * tp, struct timezone * tzp)
459*1c60b9acSAndroid Build Coastguard Worker {
460*1c60b9acSAndroid Build Coastguard Worker // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's
461*1c60b9acSAndroid Build Coastguard Worker // This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC)
462*1c60b9acSAndroid Build Coastguard Worker // until 00:00:00 January 1, 1970
463*1c60b9acSAndroid Build Coastguard Worker static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL);
464*1c60b9acSAndroid Build Coastguard Worker
465*1c60b9acSAndroid Build Coastguard Worker SYSTEMTIME system_time;
466*1c60b9acSAndroid Build Coastguard Worker FILETIME file_time;
467*1c60b9acSAndroid Build Coastguard Worker uint64_t time;
468*1c60b9acSAndroid Build Coastguard Worker
469*1c60b9acSAndroid Build Coastguard Worker GetSystemTime( &system_time );
470*1c60b9acSAndroid Build Coastguard Worker SystemTimeToFileTime( &system_time, &file_time );
471*1c60b9acSAndroid Build Coastguard Worker time = ((uint64_t)file_time.dwLowDateTime ) ;
472*1c60b9acSAndroid Build Coastguard Worker time += ((uint64_t)file_time.dwHighDateTime) << 32;
473*1c60b9acSAndroid Build Coastguard Worker
474*1c60b9acSAndroid Build Coastguard Worker tp->tv_sec = (long) ((time - EPOCH) / 10000000L);
475*1c60b9acSAndroid Build Coastguard Worker tp->tv_usec = (long) (system_time.wMilliseconds * 1000);
476*1c60b9acSAndroid Build Coastguard Worker return 0;
477*1c60b9acSAndroid Build Coastguard Worker }
478*1c60b9acSAndroid Build Coastguard Worker #endif
479*1c60b9acSAndroid Build Coastguard Worker
us(void)480*1c60b9acSAndroid Build Coastguard Worker unsigned long long us(void)
481*1c60b9acSAndroid Build Coastguard Worker {
482*1c60b9acSAndroid Build Coastguard Worker struct timeval t;
483*1c60b9acSAndroid Build Coastguard Worker
484*1c60b9acSAndroid Build Coastguard Worker gettimeofday(&t, NULL);
485*1c60b9acSAndroid Build Coastguard Worker
486*1c60b9acSAndroid Build Coastguard Worker return ((unsigned long long)t.tv_sec * 1000000ull) + (unsigned long long)t.tv_usec;
487*1c60b9acSAndroid Build Coastguard Worker }
488*1c60b9acSAndroid Build Coastguard Worker
489*1c60b9acSAndroid Build Coastguard Worker static void
stagger_cb(lws_sorted_usec_list_t * sul)490*1c60b9acSAndroid Build Coastguard Worker stagger_cb(lws_sorted_usec_list_t *sul)
491*1c60b9acSAndroid Build Coastguard Worker {
492*1c60b9acSAndroid Build Coastguard Worker lws_usec_t next;
493*1c60b9acSAndroid Build Coastguard Worker
494*1c60b9acSAndroid Build Coastguard Worker /*
495*1c60b9acSAndroid Build Coastguard Worker * open the connections at 100ms intervals, with the
496*1c60b9acSAndroid Build Coastguard Worker * last one being after 1s, testing both queuing, and
497*1c60b9acSAndroid Build Coastguard Worker * direct H2 stream addition stability
498*1c60b9acSAndroid Build Coastguard Worker */
499*1c60b9acSAndroid Build Coastguard Worker lws_try_client_connection(&i, stagger_idx++);
500*1c60b9acSAndroid Build Coastguard Worker
501*1c60b9acSAndroid Build Coastguard Worker if (stagger_idx == count)
502*1c60b9acSAndroid Build Coastguard Worker return;
503*1c60b9acSAndroid Build Coastguard Worker
504*1c60b9acSAndroid Build Coastguard Worker next = 150 * LWS_US_PER_MS;
505*1c60b9acSAndroid Build Coastguard Worker if (stagger_idx == count - 1)
506*1c60b9acSAndroid Build Coastguard Worker next += 400 * LWS_US_PER_MS;
507*1c60b9acSAndroid Build Coastguard Worker
508*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_TLS_SESSIONS)
509*1c60b9acSAndroid Build Coastguard Worker if (stagger_idx == 1)
510*1c60b9acSAndroid Build Coastguard Worker next += 600 * LWS_US_PER_MS;
511*1c60b9acSAndroid Build Coastguard Worker #endif
512*1c60b9acSAndroid Build Coastguard Worker
513*1c60b9acSAndroid Build Coastguard Worker lws_sul_schedule(context, 0, &sul_stagger, stagger_cb, next);
514*1c60b9acSAndroid Build Coastguard Worker }
515*1c60b9acSAndroid Build Coastguard Worker
main(int argc,const char ** argv)516*1c60b9acSAndroid Build Coastguard Worker int main(int argc, const char **argv)
517*1c60b9acSAndroid Build Coastguard Worker {
518*1c60b9acSAndroid Build Coastguard Worker lws_state_notify_link_t notifier = { { NULL, NULL, NULL },
519*1c60b9acSAndroid Build Coastguard Worker system_notify_cb, "app" };
520*1c60b9acSAndroid Build Coastguard Worker lws_state_notify_link_t *na[] = { ¬ifier, NULL };
521*1c60b9acSAndroid Build Coastguard Worker struct lws_context_creation_info info;
522*1c60b9acSAndroid Build Coastguard Worker unsigned long long start;
523*1c60b9acSAndroid Build Coastguard Worker const char *p;
524*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_TLS_SESSIONS)
525*1c60b9acSAndroid Build Coastguard Worker int pl = 0;
526*1c60b9acSAndroid Build Coastguard Worker #endif
527*1c60b9acSAndroid Build Coastguard Worker
528*1c60b9acSAndroid Build Coastguard Worker memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
529*1c60b9acSAndroid Build Coastguard Worker memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
530*1c60b9acSAndroid Build Coastguard Worker
531*1c60b9acSAndroid Build Coastguard Worker lws_cmdline_option_handle_builtin(argc, argv, &info);
532*1c60b9acSAndroid Build Coastguard Worker
533*1c60b9acSAndroid Build Coastguard Worker info.signal_cb = signal_cb;
534*1c60b9acSAndroid Build Coastguard Worker info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
535*1c60b9acSAndroid Build Coastguard Worker
536*1c60b9acSAndroid Build Coastguard Worker if (lws_cmdline_option(argc, argv, "--uv"))
537*1c60b9acSAndroid Build Coastguard Worker info.options |= LWS_SERVER_OPTION_LIBUV;
538*1c60b9acSAndroid Build Coastguard Worker else
539*1c60b9acSAndroid Build Coastguard Worker if (lws_cmdline_option(argc, argv, "--event"))
540*1c60b9acSAndroid Build Coastguard Worker info.options |= LWS_SERVER_OPTION_LIBEVENT;
541*1c60b9acSAndroid Build Coastguard Worker else
542*1c60b9acSAndroid Build Coastguard Worker if (lws_cmdline_option(argc, argv, "--ev"))
543*1c60b9acSAndroid Build Coastguard Worker info.options |= LWS_SERVER_OPTION_LIBEV;
544*1c60b9acSAndroid Build Coastguard Worker else
545*1c60b9acSAndroid Build Coastguard Worker if (lws_cmdline_option(argc, argv, "--glib"))
546*1c60b9acSAndroid Build Coastguard Worker info.options |= LWS_SERVER_OPTION_GLIB;
547*1c60b9acSAndroid Build Coastguard Worker else
548*1c60b9acSAndroid Build Coastguard Worker signal(SIGINT, sigint_handler);
549*1c60b9acSAndroid Build Coastguard Worker
550*1c60b9acSAndroid Build Coastguard Worker staggered = !!lws_cmdline_option(argc, argv, "-s");
551*1c60b9acSAndroid Build Coastguard Worker
552*1c60b9acSAndroid Build Coastguard Worker lwsl_user("LWS minimal http client [-s (staggered)] [-p (pipeline)]\n");
553*1c60b9acSAndroid Build Coastguard Worker lwsl_user(" [--h1 (http/1 only)] [-l (localhost)] [-d <logs>]\n");
554*1c60b9acSAndroid Build Coastguard Worker lwsl_user(" [-n (numbered)] [--post]\n");
555*1c60b9acSAndroid Build Coastguard Worker
556*1c60b9acSAndroid Build Coastguard Worker info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
557*1c60b9acSAndroid Build Coastguard Worker info.protocols = protocols;
558*1c60b9acSAndroid Build Coastguard Worker /*
559*1c60b9acSAndroid Build Coastguard Worker * since we know this lws context is only ever going to be used with
560*1c60b9acSAndroid Build Coastguard Worker * COUNT client wsis / fds / sockets at a time, let lws know it doesn't
561*1c60b9acSAndroid Build Coastguard Worker * have to use the default allocations for fd tables up to ulimit -n.
562*1c60b9acSAndroid Build Coastguard Worker * It will just allocate for 1 internal and COUNT + 1 (allowing for h2
563*1c60b9acSAndroid Build Coastguard Worker * network wsi) that we will use.
564*1c60b9acSAndroid Build Coastguard Worker */
565*1c60b9acSAndroid Build Coastguard Worker info.fd_limit_per_thread = 1 + COUNT + 1;
566*1c60b9acSAndroid Build Coastguard Worker info.register_notifier_list = na;
567*1c60b9acSAndroid Build Coastguard Worker info.pcontext = &context;
568*1c60b9acSAndroid Build Coastguard Worker
569*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_SYS_METRICS)
570*1c60b9acSAndroid Build Coastguard Worker info.system_ops = &system_ops;
571*1c60b9acSAndroid Build Coastguard Worker #endif
572*1c60b9acSAndroid Build Coastguard Worker
573*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL)
574*1c60b9acSAndroid Build Coastguard Worker /*
575*1c60b9acSAndroid Build Coastguard Worker * OpenSSL uses the system trust store. mbedTLS has to be told which
576*1c60b9acSAndroid Build Coastguard Worker * CA to trust explicitly.
577*1c60b9acSAndroid Build Coastguard Worker */
578*1c60b9acSAndroid Build Coastguard Worker info.client_ssl_ca_filepath = "./warmcat.com.cer";
579*1c60b9acSAndroid Build Coastguard Worker #endif
580*1c60b9acSAndroid Build Coastguard Worker
581*1c60b9acSAndroid Build Coastguard Worker /* vhost option allowing tls session reuse, requires
582*1c60b9acSAndroid Build Coastguard Worker * LWS_WITH_TLS_SESSIONS build option */
583*1c60b9acSAndroid Build Coastguard Worker if (lws_cmdline_option(argc, argv, "--no-tls-session-reuse"))
584*1c60b9acSAndroid Build Coastguard Worker info.options |= LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE;
585*1c60b9acSAndroid Build Coastguard Worker
586*1c60b9acSAndroid Build Coastguard Worker if ((p = lws_cmdline_option(argc, argv, "--limit")))
587*1c60b9acSAndroid Build Coastguard Worker info.simultaneous_ssl_restriction = atoi(p);
588*1c60b9acSAndroid Build Coastguard Worker
589*1c60b9acSAndroid Build Coastguard Worker if ((p = lws_cmdline_option(argc, argv, "--ssl-handshake-serialize")))
590*1c60b9acSAndroid Build Coastguard Worker /* We only consider simultaneous_ssl_restriction > 1 use cases.
591*1c60b9acSAndroid Build Coastguard Worker * If ssl isn't limited or only 1 is allowed, we don't care.
592*1c60b9acSAndroid Build Coastguard Worker */
593*1c60b9acSAndroid Build Coastguard Worker info.simultaneous_ssl_handshake_restriction = atoi(p);
594*1c60b9acSAndroid Build Coastguard Worker
595*1c60b9acSAndroid Build Coastguard Worker context = lws_create_context(&info);
596*1c60b9acSAndroid Build Coastguard Worker if (!context) {
597*1c60b9acSAndroid Build Coastguard Worker lwsl_err("lws init failed\n");
598*1c60b9acSAndroid Build Coastguard Worker return 1;
599*1c60b9acSAndroid Build Coastguard Worker }
600*1c60b9acSAndroid Build Coastguard Worker
601*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_ROLE_H2) && defined(LWS_ROLE_H1)
602*1c60b9acSAndroid Build Coastguard Worker i.alpn = "h2,http/1.1";
603*1c60b9acSAndroid Build Coastguard Worker #elif defined(LWS_ROLE_H2)
604*1c60b9acSAndroid Build Coastguard Worker i.alpn = "h2";
605*1c60b9acSAndroid Build Coastguard Worker #elif defined(LWS_ROLE_H1)
606*1c60b9acSAndroid Build Coastguard Worker i.alpn = "http/1.1";
607*1c60b9acSAndroid Build Coastguard Worker #endif
608*1c60b9acSAndroid Build Coastguard Worker
609*1c60b9acSAndroid Build Coastguard Worker i.context = context;
610*1c60b9acSAndroid Build Coastguard Worker i.ssl_connection = LCCSCF_USE_SSL |
611*1c60b9acSAndroid Build Coastguard Worker LCCSCF_H2_QUIRK_OVERFLOWS_TXCR |
612*1c60b9acSAndroid Build Coastguard Worker LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM;
613*1c60b9acSAndroid Build Coastguard Worker
614*1c60b9acSAndroid Build Coastguard Worker if (lws_cmdline_option(argc, argv, "--post")) {
615*1c60b9acSAndroid Build Coastguard Worker posting = 1;
616*1c60b9acSAndroid Build Coastguard Worker i.method = "POST";
617*1c60b9acSAndroid Build Coastguard Worker i.ssl_connection |= LCCSCF_HTTP_MULTIPART_MIME;
618*1c60b9acSAndroid Build Coastguard Worker } else
619*1c60b9acSAndroid Build Coastguard Worker i.method = "GET";
620*1c60b9acSAndroid Build Coastguard Worker
621*1c60b9acSAndroid Build Coastguard Worker /* enables h1 or h2 connection sharing */
622*1c60b9acSAndroid Build Coastguard Worker if (lws_cmdline_option(argc, argv, "-p")) {
623*1c60b9acSAndroid Build Coastguard Worker i.ssl_connection |= LCCSCF_PIPELINE;
624*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_TLS_SESSIONS)
625*1c60b9acSAndroid Build Coastguard Worker pl = 1;
626*1c60b9acSAndroid Build Coastguard Worker #endif
627*1c60b9acSAndroid Build Coastguard Worker }
628*1c60b9acSAndroid Build Coastguard Worker
629*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_CONMON)
630*1c60b9acSAndroid Build Coastguard Worker if (lws_cmdline_option(argc, argv, "--conmon"))
631*1c60b9acSAndroid Build Coastguard Worker i.ssl_connection |= LCCSCF_CONMON;
632*1c60b9acSAndroid Build Coastguard Worker #endif
633*1c60b9acSAndroid Build Coastguard Worker
634*1c60b9acSAndroid Build Coastguard Worker /* force h1 even if h2 available */
635*1c60b9acSAndroid Build Coastguard Worker if (lws_cmdline_option(argc, argv, "--h1"))
636*1c60b9acSAndroid Build Coastguard Worker i.alpn = "http/1.1";
637*1c60b9acSAndroid Build Coastguard Worker
638*1c60b9acSAndroid Build Coastguard Worker strcpy(urlpath, "/");
639*1c60b9acSAndroid Build Coastguard Worker
640*1c60b9acSAndroid Build Coastguard Worker if (lws_cmdline_option(argc, argv, "-l")) {
641*1c60b9acSAndroid Build Coastguard Worker i.port = 7681;
642*1c60b9acSAndroid Build Coastguard Worker i.address = "localhost";
643*1c60b9acSAndroid Build Coastguard Worker i.ssl_connection |= LCCSCF_ALLOW_SELFSIGNED;
644*1c60b9acSAndroid Build Coastguard Worker if (posting)
645*1c60b9acSAndroid Build Coastguard Worker strcpy(urlpath, "/formtest");
646*1c60b9acSAndroid Build Coastguard Worker } else {
647*1c60b9acSAndroid Build Coastguard Worker i.port = 443;
648*1c60b9acSAndroid Build Coastguard Worker i.address = "libwebsockets.org";
649*1c60b9acSAndroid Build Coastguard Worker if (posting)
650*1c60b9acSAndroid Build Coastguard Worker strcpy(urlpath, "/testserver/formtest");
651*1c60b9acSAndroid Build Coastguard Worker }
652*1c60b9acSAndroid Build Coastguard Worker
653*1c60b9acSAndroid Build Coastguard Worker if (lws_cmdline_option(argc, argv, "--no-tls"))
654*1c60b9acSAndroid Build Coastguard Worker i.ssl_connection &= ~(LCCSCF_USE_SSL);
655*1c60b9acSAndroid Build Coastguard Worker
656*1c60b9acSAndroid Build Coastguard Worker if (lws_cmdline_option(argc, argv, "-n"))
657*1c60b9acSAndroid Build Coastguard Worker numbered = 1;
658*1c60b9acSAndroid Build Coastguard Worker
659*1c60b9acSAndroid Build Coastguard Worker if ((p = lws_cmdline_option(argc, argv, "--server")))
660*1c60b9acSAndroid Build Coastguard Worker i.address = p;
661*1c60b9acSAndroid Build Coastguard Worker
662*1c60b9acSAndroid Build Coastguard Worker if ((p = lws_cmdline_option(argc, argv, "--port")))
663*1c60b9acSAndroid Build Coastguard Worker i.port = atoi(p);
664*1c60b9acSAndroid Build Coastguard Worker
665*1c60b9acSAndroid Build Coastguard Worker if ((p = lws_cmdline_option(argc, argv, "--path")))
666*1c60b9acSAndroid Build Coastguard Worker lws_strncpy(urlpath, p, sizeof(urlpath));
667*1c60b9acSAndroid Build Coastguard Worker
668*1c60b9acSAndroid Build Coastguard Worker if ((p = lws_cmdline_option(argc, argv, "-c")))
669*1c60b9acSAndroid Build Coastguard Worker if (atoi(p) <= COUNT && atoi(p))
670*1c60b9acSAndroid Build Coastguard Worker count = atoi(p);
671*1c60b9acSAndroid Build Coastguard Worker
672*1c60b9acSAndroid Build Coastguard Worker i.host = i.address;
673*1c60b9acSAndroid Build Coastguard Worker i.origin = i.address;
674*1c60b9acSAndroid Build Coastguard Worker i.protocol = protocols[0].name;
675*1c60b9acSAndroid Build Coastguard Worker
676*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_TLS_SESSIONS) && !defined(LWS_WITH_MBEDTLS) && !defined(WIN32)
677*1c60b9acSAndroid Build Coastguard Worker /*
678*1c60b9acSAndroid Build Coastguard Worker * Attempt to preload a session from external storage
679*1c60b9acSAndroid Build Coastguard Worker */
680*1c60b9acSAndroid Build Coastguard Worker if (lws_tls_session_dump_load(lws_get_vhost_by_name(context, "default"),
681*1c60b9acSAndroid Build Coastguard Worker i.host, (uint16_t)i.port, sess_load_cb, "/tmp"))
682*1c60b9acSAndroid Build Coastguard Worker lwsl_warn("%s: session load failed\n", __func__);
683*1c60b9acSAndroid Build Coastguard Worker #endif
684*1c60b9acSAndroid Build Coastguard Worker
685*1c60b9acSAndroid Build Coastguard Worker start = us();
686*1c60b9acSAndroid Build Coastguard Worker while (!intr && !lws_service(context, 0))
687*1c60b9acSAndroid Build Coastguard Worker ;
688*1c60b9acSAndroid Build Coastguard Worker
689*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_TLS_SESSIONS)
690*1c60b9acSAndroid Build Coastguard Worker lwsl_user("%s: session reuse count %d\n", __func__, reuse);
691*1c60b9acSAndroid Build Coastguard Worker
692*1c60b9acSAndroid Build Coastguard Worker if (staggered && !pl && !reuse) {
693*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: failing, expected 1 .. %d reused\n", __func__, count - 1);
694*1c60b9acSAndroid Build Coastguard Worker // too difficult to reproduce in CI
695*1c60b9acSAndroid Build Coastguard Worker // failed = 1;
696*1c60b9acSAndroid Build Coastguard Worker }
697*1c60b9acSAndroid Build Coastguard Worker #endif
698*1c60b9acSAndroid Build Coastguard Worker
699*1c60b9acSAndroid Build Coastguard Worker lwsl_user("Duration: %lldms\n", (us() - start) / 1000);
700*1c60b9acSAndroid Build Coastguard Worker lws_context_destroy(context);
701*1c60b9acSAndroid Build Coastguard Worker
702*1c60b9acSAndroid Build Coastguard Worker lwsl_user("Exiting with %d\n", failed || completed != count);
703*1c60b9acSAndroid Build Coastguard Worker
704*1c60b9acSAndroid Build Coastguard Worker return failed || completed != count;
705*1c60b9acSAndroid Build Coastguard Worker }
706