VirtualBox

source: vbox/trunk/src/libs/curl-7.87.0/lib/ws.c@ 98339

Last change on this file since 98339 was 98339, checked in by vboxsync, 2 years ago

curl-7.87.0: EOL style fixing, bit more irrelevant export fixing

  • Property svn:eol-style set to native
File size: 22.6 KB
Line 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2022, 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#include "curl_setup.h"
25#include <curl/curl.h>
26
27#ifdef USE_WEBSOCKETS
28
29#include "urldata.h"
30#include "dynbuf.h"
31#include "rand.h"
32#include "curl_base64.h"
33#include "sendf.h"
34#include "multiif.h"
35#include "ws.h"
36#include "easyif.h"
37#include "transfer.h"
38#include "nonblock.h"
39
40/* The last 3 #include files should be in this order */
41#include "curl_printf.h"
42#include "curl_memory.h"
43#include "memdebug.h"
44
45struct wsfield {
46 const char *name;
47 const char *val;
48};
49
50CURLcode Curl_ws_request(struct Curl_easy *data, REQTYPE *req)
51{
52 unsigned int i;
53 CURLcode result = CURLE_OK;
54 unsigned char rand[16];
55 char *randstr;
56 size_t randlen;
57 char keyval[40];
58 struct SingleRequest *k = &data->req;
59 struct wsfield heads[]= {
60 {
61 /* The request MUST contain an |Upgrade| header field whose value
62 MUST include the "websocket" keyword. */
63 "Upgrade:", "websocket"
64 },
65 {
66 /* The request MUST contain a |Connection| header field whose value
67 MUST include the "Upgrade" token. */
68 "Connection:", "Upgrade",
69 },
70 {
71 /* The request MUST include a header field with the name
72 |Sec-WebSocket-Version|. The value of this header field MUST be
73 13. */
74 "Sec-WebSocket-Version:", "13",
75 },
76 {
77 /* The request MUST include a header field with the name
78 |Sec-WebSocket-Key|. The value of this header field MUST be a nonce
79 consisting of a randomly selected 16-byte value that has been
80 base64-encoded (see Section 4 of [RFC4648]). The nonce MUST be
81 selected randomly for each connection. */
82 "Sec-WebSocket-Key:", NULL,
83 }
84 };
85 heads[3].val = &keyval[0];
86
87 /* 16 bytes random */
88 result = Curl_rand(data, (unsigned char *)rand, sizeof(rand));
89 if(result)
90 return result;
91 result = Curl_base64_encode((char *)rand, sizeof(rand), &randstr, &randlen);
92 if(result)
93 return result;
94 DEBUGASSERT(randlen < sizeof(keyval));
95 if(randlen >= sizeof(keyval))
96 return CURLE_FAILED_INIT;
97 strcpy(keyval, randstr);
98 free(randstr);
99 for(i = 0; !result && (i < sizeof(heads)/sizeof(heads[0])); i++) {
100 if(!Curl_checkheaders(data, STRCONST(heads[i].name))) {
101#ifdef USE_HYPER
102 char field[128];
103 msnprintf(field, sizeof(field), "%s %s", heads[i].name,
104 heads[i].val);
105 result = Curl_hyper_header(data, req, field);
106#else
107 (void)data;
108 result = Curl_dyn_addf(req, "%s %s\r\n", heads[i].name,
109 heads[i].val);
110#endif
111 }
112 }
113 k->upgr101 = UPGR101_WS;
114 Curl_dyn_init(&data->req.p.http->ws.buf, MAX_WS_SIZE * 2);
115 return result;
116}
117
118CURLcode Curl_ws_accept(struct Curl_easy *data)
119{
120 struct SingleRequest *k = &data->req;
121 struct HTTP *ws = data->req.p.http;
122 struct connectdata *conn = data->conn;
123 struct websocket *wsp = &data->req.p.http->ws;
124 CURLcode result;
125
126 /* Verify the Sec-WebSocket-Accept response.
127
128 The sent value is the base64 encoded version of a SHA-1 hash done on the
129 |Sec-WebSocket-Key| header field concatenated with
130 the string "258EAFA5-E914-47DA-95CA-C5AB0DC85B11".
131 */
132
133 /* If the response includes a |Sec-WebSocket-Extensions| header field and
134 this header field indicates the use of an extension that was not present
135 in the client's handshake (the server has indicated an extension not
136 requested by the client), the client MUST Fail the WebSocket Connection.
137 */
138
139 /* If the response includes a |Sec-WebSocket-Protocol| header field
140 and this header field indicates the use of a subprotocol that was
141 not present in the client's handshake (the server has indicated a
142 subprotocol not requested by the client), the client MUST Fail
143 the WebSocket Connection. */
144
145 /* 4 bytes random */
146 result = Curl_rand(data, (unsigned char *)&ws->ws.mask, sizeof(ws->ws.mask));
147 if(result)
148 return result;
149
150 infof(data, "Received 101, switch to WebSocket; mask %02x%02x%02x%02x",
151 ws->ws.mask[0], ws->ws.mask[1], ws->ws.mask[2], ws->ws.mask[3]);
152 k->upgr101 = UPGR101_RECEIVED;
153
154 if(data->set.connect_only)
155 /* switch off non-blocking sockets */
156 (void)curlx_nonblock(conn->sock[FIRSTSOCKET], FALSE);
157
158 wsp->oleft = 0;
159 return result;
160}
161
162#define WSBIT_FIN 0x80
163#define WSBIT_OPCODE_CONT 0
164#define WSBIT_OPCODE_TEXT (1)
165#define WSBIT_OPCODE_BIN (2)
166#define WSBIT_OPCODE_CLOSE (8)
167#define WSBIT_OPCODE_PING (9)
168#define WSBIT_OPCODE_PONG (0xa)
169#define WSBIT_OPCODE_MASK (0xf)
170
171#define WSBIT_MASK 0x80
172
173/* remove the spent bytes from the beginning of the buffer as that part has
174 now been delivered to the application */
175static void ws_decode_shift(struct Curl_easy *data, size_t spent)
176{
177 struct websocket *wsp = &data->req.p.http->ws;
178 size_t len = Curl_dyn_len(&wsp->buf);
179 size_t keep = len - spent;
180 DEBUGASSERT(len >= spent);
181 Curl_dyn_tail(&wsp->buf, keep);
182}
183
184/* ws_decode() decodes a binary frame into structured WebSocket data,
185
186 wpkt - the incoming raw data. If NULL, work on the already buffered data.
187 ilen - the size of the provided data, perhaps too little, perhaps too much
188 out - stored pointed to extracted data
189 olen - stored length of the extracted data
190 oleft - number of unread bytes pending to that belongs to this frame
191 more - if there is more data in there
192 flags - stored bitmask about the frame
193
194 Returns CURLE_AGAIN if there is only a partial frame in the buffer. Then it
195 stores the first part in the ->extra buffer to be used in the next call
196 when more data is provided.
197*/
198
199static CURLcode ws_decode(struct Curl_easy *data,
200 unsigned char *inbuf, size_t inlen,
201 size_t *headlen, size_t *olen,
202 curl_off_t *oleft,
203 unsigned int *flags)
204{
205 bool fin;
206 unsigned char opcode;
207 curl_off_t total;
208 size_t dataindex = 2;
209 curl_off_t payloadsize;
210
211 *olen = *headlen = 0;
212
213 if(inlen < 2) {
214 /* the smallest possible frame is two bytes */
215 infof(data, "WS: plen == %u, EAGAIN", (int)inlen);
216 return CURLE_AGAIN;
217 }
218
219 fin = inbuf[0] & WSBIT_FIN;
220 opcode = inbuf[0] & WSBIT_OPCODE_MASK;
221 infof(data, "WS:%d received FIN bit %u", __LINE__, (int)fin);
222 *flags = 0;
223 switch(opcode) {
224 case WSBIT_OPCODE_CONT:
225 if(!fin)
226 *flags |= CURLWS_CONT;
227 infof(data, "WS: received OPCODE CONT");
228 break;
229 case WSBIT_OPCODE_TEXT:
230 infof(data, "WS: received OPCODE TEXT");
231 *flags |= CURLWS_TEXT;
232 break;
233 case WSBIT_OPCODE_BIN:
234 infof(data, "WS: received OPCODE BINARY");
235 *flags |= CURLWS_BINARY;
236 break;
237 case WSBIT_OPCODE_CLOSE:
238 infof(data, "WS: received OPCODE CLOSE");
239 *flags |= CURLWS_CLOSE;
240 break;
241 case WSBIT_OPCODE_PING:
242 infof(data, "WS: received OPCODE PING");
243 *flags |= CURLWS_PING;
244 break;
245 case WSBIT_OPCODE_PONG:
246 infof(data, "WS: received OPCODE PONG");
247 *flags |= CURLWS_PONG;
248 break;
249 }
250
251 if(inbuf[1] & WSBIT_MASK) {
252 /* A client MUST close a connection if it detects a masked frame. */
253 failf(data, "WS: masked input frame");
254 return CURLE_RECV_ERROR;
255 }
256 payloadsize = inbuf[1];
257 if(payloadsize == 126) {
258 if(inlen < 4) {
259 infof(data, "WS:%d plen == %u, EAGAIN", __LINE__, (int)inlen);
260 return CURLE_AGAIN; /* not enough data available */
261 }
262 payloadsize = (inbuf[2] << 8) | inbuf[3];
263 dataindex += 2;
264 }
265 else if(payloadsize == 127) {
266 /* 64 bit payload size */
267 if(inlen < 10)
268 return CURLE_AGAIN;
269 if(inbuf[2] & 80) {
270 failf(data, "WS: too large frame");
271 return CURLE_RECV_ERROR;
272 }
273 dataindex += 8;
274 payloadsize = ((curl_off_t)inbuf[2] << 56) |
275 (curl_off_t)inbuf[3] << 48 |
276 (curl_off_t)inbuf[4] << 40 |
277 (curl_off_t)inbuf[5] << 32 |
278 (curl_off_t)inbuf[6] << 24 |
279 (curl_off_t)inbuf[7] << 16 |
280 (curl_off_t)inbuf[8] << 8 |
281 inbuf[9];
282 }
283
284 /* point to the payload */
285 *headlen = dataindex;
286 total = dataindex + payloadsize;
287 if(total > (curl_off_t)inlen) {
288 /* buffer contains partial frame */
289 *olen = inlen - dataindex; /* bytes to write out */
290 *oleft = total - inlen; /* bytes yet to come (for this frame) */
291 payloadsize = total - dataindex;
292 }
293 else {
294 /* we have the complete frame (`total` bytes) in buffer */
295 *olen = payloadsize; /* bytes to write out */
296 *oleft = 0; /* bytes yet to come (for this frame) */
297 }
298
299 infof(data, "WS: received %zu bytes payload (%zu left, buflen was %zu)",
300 payloadsize, *oleft, inlen);
301 return CURLE_OK;
302}
303
304/* Curl_ws_writecb() is the write callback for websocket traffic. The
305 websocket data is provided to this raw, in chunks. This function should
306 handle/decode the data and call the "real" underlying callback accordingly.
307*/
308size_t Curl_ws_writecb(char *buffer, size_t size /* 1 */,
309 size_t nitems, void *userp)
310{
311 struct HTTP *ws = (struct HTTP *)userp;
312 struct Curl_easy *data = ws->ws.data;
313 struct websocket *wsp = &data->req.p.http->ws;
314 void *writebody_ptr = data->set.out;
315 if(data->set.ws_raw_mode)
316 return data->set.fwrite_func(buffer, size, nitems, writebody_ptr);
317 else if(nitems) {
318 size_t wrote = 0, headlen;
319 CURLcode result;
320
321 if(buffer) {
322 result = Curl_dyn_addn(&wsp->buf, buffer, nitems);
323 if(result) {
324 infof(data, "WS: error adding data to buffer %d", (int)result);
325 return nitems - 1;
326 }
327 buffer = NULL;
328 }
329
330 while(Curl_dyn_len(&wsp->buf)) {
331 unsigned char *wsbuf = Curl_dyn_uptr(&wsp->buf);
332 size_t buflen = Curl_dyn_len(&wsp->buf);
333 size_t write_len = 0;
334 size_t consumed = 0;
335
336 if(!ws->ws.frame.bytesleft) {
337 unsigned int recvflags;
338 curl_off_t fb_left;
339
340 result = ws_decode(data, wsbuf, buflen,
341 &headlen, &write_len, &fb_left, &recvflags);
342 consumed += headlen;
343 wsbuf += headlen;
344 buflen -= headlen;
345 if(result == CURLE_AGAIN)
346 /* insufficient amount of data, keep it for later.
347 * we pretend to have written all since we have a copy */
348 return nitems;
349 else if(result) {
350 infof(data, "WS: decode error %d", (int)result);
351 return nitems - 1;
352 }
353 /* New frame. store details about the frame to be reachable with
354 curl_ws_meta() from within the write callback */
355 ws->ws.frame.age = 0;
356 ws->ws.frame.offset = 0;
357 ws->ws.frame.flags = recvflags;
358 ws->ws.frame.bytesleft = fb_left;
359 }
360 else {
361 /* continuing frame */
362 write_len = (size_t)ws->ws.frame.bytesleft;
363 if(write_len > buflen)
364 write_len = buflen;
365 ws->ws.frame.offset += write_len;
366 ws->ws.frame.bytesleft -= write_len;
367 }
368 if((ws->ws.frame.flags & CURLWS_PING) && !ws->ws.frame.bytesleft) {
369 /* auto-respond to PINGs, only works for single-frame payloads atm */
370 size_t bytes;
371 infof(data, "WS: auto-respond to PING with a PONG");
372 /* send back the exact same content as a PONG */
373 result = curl_ws_send(data, wsbuf, write_len,
374 &bytes, 0, CURLWS_PONG);
375 if(result)
376 return result;
377 }
378 else if(write_len || !wsp->frame.bytesleft) {
379 /* deliver the decoded frame to the user callback */
380 Curl_set_in_callback(data, true);
381 wrote = data->set.fwrite_func((char *)wsbuf, 1,
382 write_len, writebody_ptr);
383 Curl_set_in_callback(data, false);
384 if(wrote != write_len)
385 return 0;
386 }
387 /* get rid of the buffered data consumed */
388 consumed += write_len;
389 ws_decode_shift(data, consumed);
390 }
391 }
392 return nitems;
393}
394
395
396CURL_EXTERN CURLcode curl_ws_recv(struct Curl_easy *data, void *buffer,
397 size_t buflen, size_t *nread,
398 struct curl_ws_frame **metap)
399{
400 CURLcode result;
401 struct websocket *wsp = &data->req.p.http->ws;
402 bool done = FALSE; /* not filled passed buffer yet */
403
404 *nread = 0;
405 *metap = NULL;
406 /* get a download buffer */
407 result = Curl_preconnect(data);
408 if(result)
409 return result;
410
411 while(!done) {
412 size_t write_len;
413 unsigned int recvflags;
414
415 if(!wsp->stillblen) {
416 /* try to get more data */
417 size_t n;
418 result = curl_easy_recv(data, data->state.buffer,
419 data->set.buffer_size, &n);
420 if(result)
421 return result;
422 if(!n)
423 /* connection closed */
424 return CURLE_GOT_NOTHING;
425 wsp->stillb = data->state.buffer;
426 wsp->stillblen = n;
427 }
428
429 infof(data, "WS: got %u websocket bytes to decode",
430 (int)wsp->stillblen);
431 if(!wsp->frame.bytesleft) {
432 size_t headlen;
433 curl_off_t oleft;
434 /* detect new frame */
435 result = ws_decode(data, (unsigned char *)wsp->stillb, wsp->stillblen,
436 &headlen, &write_len, &oleft, &recvflags);
437 if(result == CURLE_AGAIN)
438 /* a packet fragment only */
439 break;
440 else if(result)
441 return result;
442 wsp->stillb += headlen;
443 wsp->stillblen -= headlen;
444 wsp->frame.offset = 0;
445 wsp->frame.bytesleft = oleft;
446 wsp->frame.flags = recvflags;
447 }
448 else {
449 /* existing frame, remaining payload handling */
450 write_len = wsp->frame.bytesleft;
451 if(write_len > wsp->stillblen)
452 write_len = wsp->stillblen;
453 }
454
455 /* auto-respond to PINGs */
456 if((wsp->frame.flags & CURLWS_PING) && !wsp->frame.bytesleft) {
457 infof(data, "WS: auto-respond to PING with a PONG");
458 /* send back the exact same content as a PONG */
459 result = curl_ws_send(data, wsp->stillb, write_len,
460 &write_len, 0, CURLWS_PONG);
461 if(result)
462 return result;
463 }
464 else if(write_len || !wsp->frame.bytesleft) {
465 if(write_len > buflen)
466 write_len = buflen;
467 /* copy the payload to the user buffer */
468 memcpy(buffer, wsp->stillb, write_len);
469 *nread = write_len;
470 done = TRUE;
471 }
472 if(write_len) {
473 /* update buffer and frame info */
474 wsp->frame.offset += write_len;
475 DEBUGASSERT(wsp->frame.bytesleft >= (curl_off_t)write_len);
476 if(wsp->frame.bytesleft)
477 wsp->frame.bytesleft -= write_len;
478 DEBUGASSERT(write_len <= wsp->stillblen);
479 wsp->stillblen -= write_len;
480 if(wsp->stillblen)
481 wsp->stillb += write_len;
482 else
483 wsp->stillb = NULL;
484 }
485 }
486 *metap = &wsp->frame;
487 return CURLE_OK;
488}
489
490static void ws_xor(struct Curl_easy *data,
491 const unsigned char *source,
492 unsigned char *dest,
493 size_t len)
494{
495 struct websocket *wsp = &data->req.p.http->ws;
496 size_t i;
497 /* append payload after the mask, XOR appropriately */
498 for(i = 0; i < len; i++) {
499 dest[i] = source[i] ^ wsp->mask[wsp->xori];
500 wsp->xori++;
501 wsp->xori &= 3;
502 }
503}
504
505/***
506 RFC 6455 Section 5.2
507
508 0 1 2 3
509 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
510 +-+-+-+-+-------+-+-------------+-------------------------------+
511 |F|R|R|R| opcode|M| Payload len | Extended payload length |
512 |I|S|S|S| (4) |A| (7) | (16/64) |
513 |N|V|V|V| |S| | (if payload len==126/127) |
514 | |1|2|3| |K| | |
515 +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
516 | Extended payload length continued, if payload len == 127 |
517 + - - - - - - - - - - - - - - - +-------------------------------+
518 | |Masking-key, if MASK set to 1 |
519 +-------------------------------+-------------------------------+
520 | Masking-key (continued) | Payload Data |
521 +-------------------------------- - - - - - - - - - - - - - - - +
522 : Payload Data continued ... :
523 + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
524 | Payload Data continued ... |
525 +---------------------------------------------------------------+
526*/
527
528static size_t ws_packethead(struct Curl_easy *data,
529 size_t len, unsigned int flags)
530{
531 struct HTTP *ws = data->req.p.http;
532 unsigned char *out = (unsigned char *)data->state.ulbuf;
533 unsigned char firstbyte = 0;
534 int outi;
535 unsigned char opcode;
536 if(flags & CURLWS_TEXT) {
537 opcode = WSBIT_OPCODE_TEXT;
538 infof(data, "WS: send OPCODE TEXT");
539 }
540 else if(flags & CURLWS_CLOSE) {
541 opcode = WSBIT_OPCODE_CLOSE;
542 infof(data, "WS: send OPCODE CLOSE");
543 }
544 else if(flags & CURLWS_PING) {
545 opcode = WSBIT_OPCODE_PING;
546 infof(data, "WS: send OPCODE PING");
547 }
548 else if(flags & CURLWS_PONG) {
549 opcode = WSBIT_OPCODE_PONG;
550 infof(data, "WS: send OPCODE PONG");
551 }
552 else {
553 opcode = WSBIT_OPCODE_BIN;
554 infof(data, "WS: send OPCODE BINARY");
555 }
556
557 if(!(flags & CURLWS_CONT)) {
558 /* if not marked as continuing, assume this is the final fragment */
559 firstbyte |= WSBIT_FIN | opcode;
560 ws->ws.contfragment = FALSE;
561 }
562 else if(ws->ws.contfragment) {
563 /* the previous fragment was not a final one and this isn't either, keep a
564 CONT opcode and no FIN bit */
565 firstbyte |= WSBIT_OPCODE_CONT;
566 }
567 else {
568 ws->ws.contfragment = TRUE;
569 }
570 out[0] = firstbyte;
571 if(len > 65535) {
572 out[1] = 127 | WSBIT_MASK;
573 out[2] = (len >> 8) & 0xff;
574 out[3] = len & 0xff;
575 outi = 10;
576 }
577 else if(len > 126) {
578 out[1] = 126 | WSBIT_MASK;
579 out[2] = (len >> 8) & 0xff;
580 out[3] = len & 0xff;
581 outi = 4;
582 }
583 else {
584 out[1] = (unsigned char)len | WSBIT_MASK;
585 outi = 2;
586 }
587
588 infof(data, "WS: send FIN bit %u (byte %02x)",
589 firstbyte & WSBIT_FIN ? 1 : 0,
590 firstbyte);
591 infof(data, "WS: send payload len %u", (int)len);
592
593 /* 4 bytes mask */
594 memcpy(&out[outi], &ws->ws.mask, 4);
595
596 if(data->set.upload_buffer_size < (len + 10))
597 return 0;
598
599 /* pass over the mask */
600 outi += 4;
601
602 ws->ws.xori = 0;
603 /* return packet size */
604 return outi;
605}
606
607CURL_EXTERN CURLcode curl_ws_send(struct Curl_easy *data, const void *buffer,
608 size_t buflen, size_t *sent,
609 curl_off_t totalsize,
610 unsigned int sendflags)
611{
612 CURLcode result;
613 size_t headlen;
614 char *out;
615 ssize_t written;
616 struct websocket *wsp = &data->req.p.http->ws;
617
618 if(!data->set.ws_raw_mode) {
619 result = Curl_get_upload_buffer(data);
620 if(result)
621 return result;
622 }
623 else {
624 if(totalsize || sendflags)
625 return CURLE_BAD_FUNCTION_ARGUMENT;
626 }
627
628 if(data->set.ws_raw_mode) {
629 if(!buflen)
630 /* nothing to do */
631 return CURLE_OK;
632 /* raw mode sends exactly what was requested, and this is from within
633 the write callback */
634 if(Curl_is_in_callback(data)) {
635 if(!data->conn) {
636 failf(data, "No associated connection");
637 return CURLE_SEND_ERROR;
638 }
639 result = Curl_write(data, data->conn->writesockfd, buffer, buflen,
640 &written);
641 }
642 else
643 result = Curl_senddata(data, buffer, buflen, &written);
644
645 infof(data, "WS: wanted to send %zu bytes, sent %zu bytes",
646 buflen, written);
647 *sent = written;
648 return result;
649 }
650
651 if(buflen > (data->set.upload_buffer_size - 10))
652 /* don't do more than this in one go */
653 buflen = data->set.upload_buffer_size - 10;
654
655 if(sendflags & CURLWS_OFFSET) {
656 if(totalsize) {
657 /* a frame series 'totalsize' bytes big, this is the first */
658 headlen = ws_packethead(data, totalsize, sendflags);
659 wsp->sleft = totalsize - buflen;
660 }
661 else {
662 headlen = 0;
663 if((curl_off_t)buflen > wsp->sleft) {
664 infof(data, "WS: unaligned frame size (sending %zu instead of %zu)",
665 buflen, wsp->sleft);
666 wsp->sleft = 0;
667 }
668 else
669 wsp->sleft -= buflen;
670 }
671 }
672 else
673 headlen = ws_packethead(data, buflen, sendflags);
674
675 /* headlen is the size of the frame header */
676 out = data->state.ulbuf;
677 if(buflen)
678 /* for PING and PONG etc there might not be a payload */
679 ws_xor(data, buffer, (unsigned char *)out + headlen, buflen);
680
681 if(data->set.connect_only)
682 result = Curl_senddata(data, out, buflen + headlen, &written);
683 else
684 result = Curl_write(data, data->conn->writesockfd, out,
685 buflen + headlen, &written);
686
687 infof(data, "WS: wanted to send %zu bytes, sent %zu bytes",
688 headlen + buflen, written);
689 *sent = written;
690
691 return result;
692}
693
694void Curl_ws_done(struct Curl_easy *data)
695{
696 struct websocket *wsp = &data->req.p.http->ws;
697 DEBUGASSERT(wsp);
698 Curl_dyn_free(&wsp->buf);
699}
700
701CURL_EXTERN struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data)
702{
703 /* we only return something for websocket, called from within the callback
704 when not using raw mode */
705 if(GOOD_EASY_HANDLE(data) && Curl_is_in_callback(data) && data->req.p.http &&
706 !data->set.ws_raw_mode)
707 return &data->req.p.http->ws.frame;
708 return NULL;
709}
710
711#else
712
713CURL_EXTERN CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen,
714 size_t *nread,
715 struct curl_ws_frame **metap)
716{
717 (void)curl;
718 (void)buffer;
719 (void)buflen;
720 (void)nread;
721 (void)metap;
722 return CURLE_NOT_BUILT_IN;
723}
724
725CURL_EXTERN CURLcode curl_ws_send(CURL *curl, const void *buffer,
726 size_t buflen, size_t *sent,
727 curl_off_t framesize,
728 unsigned int sendflags)
729{
730 (void)curl;
731 (void)buffer;
732 (void)buflen;
733 (void)sent;
734 (void)framesize;
735 (void)sendflags;
736 return CURLE_NOT_BUILT_IN;
737}
738
739CURL_EXTERN struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data)
740{
741 (void)data;
742 return NULL;
743}
744#endif /* USE_WEBSOCKETS */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette