Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/external/curl/tests/http/clients/ws-data.c
2066 views
1
/***************************************************************************
2
* _ _ ____ _
3
* Project ___| | | | _ \| |
4
* / __| | | | |_) | |
5
* | (__| |_| | _ <| |___
6
* \___|\___/|_| \_\_____|
7
*
8
* Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9
*
10
* This software is licensed as described in the file COPYING, which
11
* you should have received as part of this distribution. The terms
12
* are also available at https://curl.se/docs/copyright.html.
13
*
14
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
* copies of the Software, and permit persons to whom the Software is
16
* furnished to do so, under the terms of the COPYING file.
17
*
18
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
* KIND, either express or implied.
20
*
21
* SPDX-License-Identifier: curl
22
*
23
***************************************************************************/
24
/* <DESC>
25
* WebSockets data echos
26
* </DESC>
27
*/
28
/* curl stuff */
29
#include <curl/curl.h>
30
31
#include <stdio.h>
32
#include <stdlib.h>
33
#include <string.h>
34
35
#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(_MSC_VER)
36
37
#ifndef _MSC_VER
38
/* somewhat Unix-specific */
39
#include <unistd.h> /* getopt() */
40
#endif
41
42
#ifdef _WIN32
43
#include <windows.h>
44
#else
45
#include <sys/time.h>
46
#endif
47
48
49
static
50
void dump(const char *text, unsigned char *ptr, size_t size,
51
char nohex)
52
{
53
size_t i;
54
size_t c;
55
56
unsigned int width = 0x10;
57
58
if(nohex)
59
/* without the hex output, we can fit more on screen */
60
width = 0x40;
61
62
fprintf(stderr, "%s, %lu bytes (0x%lx)\n",
63
text, (unsigned long)size, (unsigned long)size);
64
65
for(i = 0; i < size; i += width) {
66
67
fprintf(stderr, "%4.4lx: ", (unsigned long)i);
68
69
if(!nohex) {
70
/* hex not disabled, show it */
71
for(c = 0; c < width; c++)
72
if(i + c < size)
73
fprintf(stderr, "%02x ", ptr[i + c]);
74
else
75
fputs(" ", stderr);
76
}
77
78
for(c = 0; (c < width) && (i + c < size); c++) {
79
/* check for 0D0A; if found, skip past and start a new line of output */
80
if(nohex && (i + c + 1 < size) && ptr[i + c] == 0x0D &&
81
ptr[i + c + 1] == 0x0A) {
82
i += (c + 2 - width);
83
break;
84
}
85
fprintf(stderr, "%c",
86
(ptr[i + c] >= 0x20) && (ptr[i + c] < 0x80) ? ptr[i + c] : '.');
87
/* check again for 0D0A, to avoid an extra \n if it's at width */
88
if(nohex && (i + c + 2 < size) && ptr[i + c + 1] == 0x0D &&
89
ptr[i + c + 2] == 0x0A) {
90
i += (c + 3 - width);
91
break;
92
}
93
}
94
fputc('\n', stderr); /* newline */
95
}
96
}
97
98
static CURLcode check_recv(const struct curl_ws_frame *frame,
99
size_t r_offset, size_t nread, size_t exp_len)
100
{
101
if(!frame)
102
return CURLE_OK;
103
104
if(frame->flags & CURLWS_CLOSE) {
105
fprintf(stderr, "recv_data: unexpected CLOSE frame from server, "
106
"got %ld bytes, offset=%ld, rflags %x\n",
107
(long)nread, (long)r_offset, frame->flags);
108
return CURLE_RECV_ERROR;
109
}
110
if(!r_offset && !(frame->flags & CURLWS_BINARY)) {
111
fprintf(stderr, "recv_data: wrong frame, got %ld bytes, offset=%ld, "
112
"rflags %x\n",
113
(long)nread, (long)r_offset, frame->flags);
114
return CURLE_RECV_ERROR;
115
}
116
if(frame->offset != (curl_off_t)r_offset) {
117
fprintf(stderr, "recv_data: frame offset, expected %ld, got %ld\n",
118
(long)r_offset, (long)frame->offset);
119
return CURLE_RECV_ERROR;
120
}
121
if(frame->bytesleft != (curl_off_t)(exp_len - r_offset - nread)) {
122
fprintf(stderr, "recv_data: frame bytesleft, expected %ld, got %ld\n",
123
(long)(exp_len - r_offset - nread), (long)frame->bytesleft);
124
return CURLE_RECV_ERROR;
125
}
126
if(r_offset + nread > exp_len) {
127
fprintf(stderr, "recv_data: data length, expected %ld, now at %ld\n",
128
(long)exp_len, (long)(r_offset + nread));
129
return CURLE_RECV_ERROR;
130
}
131
return CURLE_OK;
132
}
133
134
#if defined(__TANDEM)
135
# include <cextdecs.h(PROCESS_DELAY_)>
136
#endif
137
138
/* just close the connection */
139
static void websocket_close(CURL *curl)
140
{
141
size_t sent;
142
CURLcode result =
143
curl_ws_send(curl, "", 0, &sent, 0, CURLWS_CLOSE);
144
fprintf(stderr,
145
"ws: curl_ws_send returned %u, sent %u\n", (int)result, (int)sent);
146
}
147
148
static CURLcode data_echo(CURL *curl, size_t count,
149
size_t plen_min, size_t plen_max)
150
{
151
CURLcode r = CURLE_OK;
152
const struct curl_ws_frame *frame;
153
size_t len;
154
char *send_buf = NULL, *recv_buf = NULL;
155
size_t i, scount = count, rcount = count;
156
int rblock, sblock;
157
158
send_buf = calloc(1, plen_max + 1);
159
recv_buf = calloc(1, plen_max + 1);
160
if(!send_buf || !recv_buf) {
161
r = CURLE_OUT_OF_MEMORY;
162
goto out;
163
}
164
165
for(i = 0; i < plen_max; ++i) {
166
send_buf[i] = (char)('0' + ((int)i % 10));
167
}
168
169
for(len = plen_min; len <= plen_max; ++len) {
170
size_t nwritten, nread, slen = len, rlen = len;
171
char *sbuf = send_buf, *rbuf = recv_buf;
172
173
memset(recv_buf, 0, plen_max);
174
while(slen || rlen || scount || rcount) {
175
sblock = rblock = 1;
176
if(slen) {
177
r = curl_ws_send(curl, sbuf, slen, &nwritten, 0, CURLWS_BINARY);
178
sblock = (r == CURLE_AGAIN);
179
if(!r || (r == CURLE_AGAIN)) {
180
fprintf(stderr, "curl_ws_send(len=%ld) -> %d, %ld (%ld/%ld)\n",
181
(long)slen, r, (long)nwritten,
182
(long)(len - slen), (long)len);
183
sbuf += nwritten;
184
slen -= nwritten;
185
}
186
else
187
goto out;
188
}
189
if(!slen && scount) { /* go again? */
190
scount--;
191
sbuf = send_buf;
192
slen = len;
193
}
194
195
if(rlen) {
196
size_t max_recv = (64 * 1024);
197
r = curl_ws_recv(curl, rbuf, (rlen > max_recv) ? max_recv : rlen,
198
&nread, &frame);
199
if(!r || (r == CURLE_AGAIN)) {
200
rblock = (r == CURLE_AGAIN);
201
fprintf(stderr, "curl_ws_recv(len=%ld) -> %d, %ld (%ld/%ld) \n",
202
(long)rlen, r, (long)nread, (long)(len - rlen), (long)len);
203
if(!r) {
204
r = check_recv(frame, len - rlen, nread, len);
205
if(r)
206
goto out;
207
}
208
rbuf += nread;
209
rlen -= nread;
210
}
211
else
212
goto out;
213
}
214
if(!rlen && rcount) { /* go again? */
215
rcount--;
216
rbuf = recv_buf;
217
rlen = len;
218
}
219
220
if(rblock && sblock) {
221
fprintf(stderr, "EAGAIN, sleep, try again\n");
222
#ifdef _WIN32
223
Sleep(100);
224
#elif defined(__TANDEM)
225
/* NonStop only defines usleep when building for a threading model */
226
# if defined(_PUT_MODEL_) || defined(_KLT_MODEL_)
227
usleep(100*1000);
228
# else
229
PROCESS_DELAY_(100*1000);
230
# endif
231
#else
232
usleep(100*1000);
233
#endif
234
}
235
}
236
237
if(memcmp(send_buf, recv_buf, len)) {
238
fprintf(stderr, "recv_data: data differs\n");
239
dump("expected:", (unsigned char *)send_buf, len, 0);
240
dump("received:", (unsigned char *)recv_buf, len, 0);
241
r = CURLE_RECV_ERROR;
242
goto out;
243
}
244
}
245
246
out:
247
if(!r)
248
websocket_close(curl);
249
free(send_buf);
250
free(recv_buf);
251
return r;
252
}
253
254
static void usage(const char *msg)
255
{
256
if(msg)
257
fprintf(stderr, "%s\n", msg);
258
fprintf(stderr,
259
"usage: [options] url\n"
260
" -m number minimum frame size\n"
261
" -M number maximum frame size\n"
262
);
263
}
264
265
#endif
266
267
int main(int argc, char *argv[])
268
{
269
#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(_MSC_VER)
270
CURL *curl;
271
CURLcode res = CURLE_OK;
272
const char *url;
273
size_t plen_min = 0, plen_max = 0, count = 1;
274
int ch;
275
276
while((ch = getopt(argc, argv, "c:hm:M:")) != -1) {
277
switch(ch) {
278
case 'h':
279
usage(NULL);
280
res = CURLE_BAD_FUNCTION_ARGUMENT;
281
goto cleanup;
282
case 'c':
283
count = (size_t)strtol(optarg, NULL, 10);
284
break;
285
case 'm':
286
plen_min = (size_t)strtol(optarg, NULL, 10);
287
break;
288
case 'M':
289
plen_max = (size_t)strtol(optarg, NULL, 10);
290
break;
291
default:
292
usage("invalid option");
293
res = CURLE_BAD_FUNCTION_ARGUMENT;
294
goto cleanup;
295
}
296
}
297
argc -= optind;
298
argv += optind;
299
300
if(!plen_max)
301
plen_max = plen_min;
302
303
if(plen_max < plen_min) {
304
fprintf(stderr, "maxlen must be >= minlen, got %ld-%ld\n",
305
(long)plen_min, (long)plen_max);
306
res = CURLE_BAD_FUNCTION_ARGUMENT;
307
goto cleanup;
308
}
309
310
if(argc != 1) {
311
usage(NULL);
312
res = CURLE_BAD_FUNCTION_ARGUMENT;
313
goto cleanup;
314
}
315
url = argv[0];
316
317
curl_global_init(CURL_GLOBAL_ALL);
318
319
curl = curl_easy_init();
320
if(curl) {
321
curl_easy_setopt(curl, CURLOPT_URL, url);
322
323
/* use the callback style */
324
curl_easy_setopt(curl, CURLOPT_USERAGENT, "ws-data");
325
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
326
curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 2L); /* websocket style */
327
res = curl_easy_perform(curl);
328
fprintf(stderr, "curl_easy_perform() returned %u\n", (int)res);
329
if(res == CURLE_OK)
330
res = data_echo(curl, count, plen_min, plen_max);
331
332
/* always cleanup */
333
curl_easy_cleanup(curl);
334
}
335
336
cleanup:
337
curl_global_cleanup();
338
return (int)res;
339
340
#else /* !CURL_DISABLE_WEBSOCKETS */
341
(void)argc;
342
(void)argv;
343
fprintf(stderr, "WebSockets not enabled in libcurl\n");
344
return 1;
345
#endif /* CURL_DISABLE_WEBSOCKETS */
346
}
347
348