source: azure_iot_hub_f767zi/trunk/azure_iot_sdk/c-utility/src/uws_client.c@ 457

Last change on this file since 457 was 457, checked in by coas-nagasima, 4 years ago

ファイルを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 126.1 KB
Line 
1 // Copyright (c) Microsoft. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
4#include <stdlib.h>
5#include <stdint.h>
6#include <limits.h>
7#include <ctype.h>
8#include <limits.h>
9#include "azure_c_shared_utility/gballoc.h"
10#include "azure_c_shared_utility/uws_client.h"
11#include "azure_c_shared_utility/optimize_size.h"
12#include "azure_c_shared_utility/xlogging.h"
13#include "azure_c_shared_utility/xio.h"
14#include "azure_c_shared_utility/singlylinkedlist.h"
15#include "azure_c_shared_utility/socketio.h"
16#include "azure_c_shared_utility/platform.h"
17#include "azure_c_shared_utility/tlsio.h"
18#include "azure_c_shared_utility/crt_abstractions.h"
19#include "azure_c_shared_utility/buffer_.h"
20#include "azure_c_shared_utility/uws_frame_encoder.h"
21#include "azure_c_shared_utility/crt_abstractions.h"
22#include "azure_c_shared_utility/utf8_checker.h"
23#include "azure_c_shared_utility/gb_rand.h"
24#include "azure_c_shared_utility/azure_base64.h"
25#include "azure_c_shared_utility/optionhandler.h"
26#include "azure_c_shared_utility/map.h"
27#include "azure_c_shared_utility/shared_util_options.h"
28
29static const char* UWS_CLIENT_OPTIONS = "uWSClientOptions";
30
31static const char* HTTP_HEADER_KEY_VALUE_SEPARATOR = ": ";
32static const size_t HTTP_HEADER_KEY_VALUE_SEPARATOR_LENGTH = 2;
33static const char* HTTP_HEADER_TERMINATOR = "\r\n";
34static const size_t HTTP_HEADER_TERMINATOR_LENGTH = 2;
35
36/* Requirements not needed as they are optional:
37Codes_SRS_UWS_CLIENT_01_254: [ If an endpoint receives a Ping frame and has not yet sent Pong frame(s) in response to previous Ping frame(s), the endpoint MAY elect to send a Pong frame for only the most recently processed Ping frame. ]
38Codes_SRS_UWS_CLIENT_01_255: [ A Pong frame MAY be sent unsolicited. ]
39Codes_SRS_UWS_CLIENT_01_256: [ A response to an unsolicited Pong frame is not expected. ]
40*/
41
42/* Requirements satisfied by the underlying TLS/socket stack
43Codes_SRS_UWS_CLIENT_01_362: [ To achieve reasonable levels of protection, clients should use only Strong TLS algorithms. ]
44Codes_SRS_UWS_CLIENT_01_289: [ An endpoint SHOULD use a method that cleanly closes the TCP connection, as well as the TLS session, if applicable, discarding any trailing bytes that may have been received. ]
45Codes_SRS_UWS_CLIENT_01_078: [ Otherwise, all further communication on this channel MUST run through the encrypted tunnel [RFC5246]. ]
46Codes_SRS_UWS_CLIENT_01_141: [ masking is done whether or not the WebSocket Protocol is running over TLS. ]
47*/
48
49/* Requirements satisfied by the way the APIs are designed:
50Codes_SRS_UWS_CLIENT_01_211: [One implication of this is that in absence of extensions, senders and receivers must not depend on the presence of specific frame boundaries.]
51*/
52
53typedef enum UWS_STATE_TAG
54{
55 UWS_STATE_CLOSED,
56 UWS_STATE_OPENING_UNDERLYING_IO,
57 UWS_STATE_WAITING_FOR_UPGRADE_RESPONSE,
58 UWS_STATE_OPEN,
59 UWS_STATE_CLOSING_WAITING_FOR_CLOSE,
60 UWS_STATE_CLOSING_SENDING_CLOSE,
61 UWS_STATE_CLOSING_UNDERLYING_IO,
62 UWS_STATE_ERROR
63} UWS_STATE;
64
65typedef struct WS_INSTANCE_PROTOCOL_TAG
66{
67 char* protocol;
68} WS_INSTANCE_PROTOCOL;
69
70typedef struct WS_PENDING_SEND_TAG
71{
72 ON_WS_SEND_FRAME_COMPLETE on_ws_send_frame_complete;
73 void* context;
74 UWS_CLIENT_HANDLE uws_client;
75} WS_PENDING_SEND;
76
77typedef struct UWS_CLIENT_INSTANCE_TAG
78{
79 SINGLYLINKEDLIST_HANDLE pending_sends;
80 XIO_HANDLE underlying_io;
81 char* hostname;
82 char* resource_name;
83 WS_INSTANCE_PROTOCOL* protocols;
84 size_t protocol_count;
85 int port;
86 MAP_HANDLE request_headers;
87 UWS_STATE uws_state;
88 ON_WS_OPEN_COMPLETE on_ws_open_complete;
89 void* on_ws_open_complete_context;
90 ON_WS_FRAME_RECEIVED on_ws_frame_received;
91 void* on_ws_frame_received_context;
92 ON_WS_PEER_CLOSED on_ws_peer_closed;
93 void* on_ws_peer_closed_context;
94 ON_WS_ERROR on_ws_error;
95 void* on_ws_error_context;
96 ON_WS_CLOSE_COMPLETE on_ws_close_complete;
97 void* on_ws_close_complete_context;
98 unsigned char* stream_buffer;
99 size_t stream_buffer_count;
100 unsigned char* fragment_buffer;
101 size_t fragment_buffer_count;
102 unsigned char fragmented_frame_type;
103} UWS_CLIENT_INSTANCE;
104
105/* Codes_SRS_UWS_CLIENT_01_360: [ Connection confidentiality and integrity is provided by running the WebSocket Protocol over TLS (wss URIs). ]*/
106/* Codes_SRS_UWS_CLIENT_01_361: [ WebSocket implementations MUST support TLS and SHOULD employ it when communicating with their peers. ]*/
107/* Codes_SRS_UWS_CLIENT_01_063: [ A client will need to supply a /host/, /port/, /resource name/, and a /secure/ flag, which are the components of a WebSocket URI as discussed in Section 3, along with a list of /protocols/ and /extensions/ to be used. ]*/
108UWS_CLIENT_HANDLE uws_client_create(const char* hostname, unsigned int port, const char* resource_name, bool use_ssl, const WS_PROTOCOL* protocols, size_t protocol_count)
109{
110 UWS_CLIENT_HANDLE result;
111
112 /* Codes_SRS_UWS_CLIENT_01_002: [ If any of the arguments hostname and resource_name is NULL then uws_client_create shall return NULL. ]*/
113 if ((hostname == NULL) ||
114 (resource_name == NULL) ||
115 /* Codes_SRS_UWS_CLIENT_01_411: [ If protocol_count is non zero and protocols is NULL then uws_client_create shall fail and return NULL. ]*/
116 ((protocols == NULL) && (protocol_count > 0)))
117 {
118 LogError("Invalid arguments: hostname = %p, resource_name = %p, protocols = %p, protocol_count = %lu", hostname, resource_name, protocols, (unsigned long)protocol_count);
119 result = NULL;
120 }
121 else
122 {
123 /* Codes_SRS_UWS_CLIENT_01_412: [ If the protocol member of any of the items in the protocols argument is NULL, then uws_client_create shall fail and return NULL. ]*/
124 size_t i;
125 for (i = 0; i < protocol_count; i++)
126 {
127 if (protocols[i].protocol == NULL)
128 {
129 break;
130 }
131 }
132
133 if (i < protocol_count)
134 {
135 LogError("Protocol index %lu has NULL name", (unsigned long)i);
136 result = NULL;
137 }
138 else
139 {
140 /* Codes_SRS_UWS_CLIENT_01_001: [uws_client_create shall create an instance of uws and return a non-NULL handle to it.]*/
141 result = (UWS_CLIENT_HANDLE)malloc(sizeof(UWS_CLIENT_INSTANCE));
142 if (result == NULL)
143 {
144 /* Codes_SRS_UWS_CLIENT_01_003: [ If allocating memory for the new uws instance fails then uws_client_create shall return NULL. ]*/
145 LogError("Could not allocate uWS instance");
146 }
147 else
148 {
149 (void)memset(result, 0, sizeof(UWS_CLIENT_INSTANCE));
150
151 /* Codes_SRS_UWS_CLIENT_01_004: [ The argument hostname shall be copied for later use. ]*/
152 if (mallocAndStrcpy_s(&result->hostname, hostname) != 0)
153 {
154 /* Codes_SRS_UWS_CLIENT_01_392: [ If allocating memory for the copy of the hostname argument fails, then uws_client_create shall return NULL. ]*/
155 LogError("Could not copy hostname.");
156 free(result);
157 result = NULL;
158 }
159 else
160 {
161 /* Codes_SRS_UWS_CLIENT_01_404: [ The argument resource_name shall be copied for later use. ]*/
162 if (mallocAndStrcpy_s(&result->resource_name, resource_name) != 0)
163 {
164 /* Codes_SRS_UWS_CLIENT_01_405: [ If allocating memory for the copy of the resource argument fails, then uws_client_create shall return NULL. ]*/
165 LogError("Could not copy resource.");
166 free(result->hostname);
167 free(result);
168 result = NULL;
169 }
170 else if ((result->request_headers = Map_Create(NULL)) == NULL)
171 {
172 LogError("Failed allocating MAP for request headers");
173 free(result->resource_name);
174 free(result->hostname);
175 free(result);
176 result = NULL;
177 }
178 else
179 {
180 /* Codes_SRS_UWS_CLIENT_01_017: [ uws_client_create shall create a pending send IO list that is to be used to queue send packets by calling singlylinkedlist_create. ]*/
181 result->pending_sends = singlylinkedlist_create();
182 if (result->pending_sends == NULL)
183 {
184 /* Codes_SRS_UWS_CLIENT_01_018: [ If singlylinkedlist_create fails then uws_client_create shall fail and return NULL. ]*/
185 LogError("Could not allocate pending send frames list");
186 Map_Destroy(result->request_headers);
187 free(result->resource_name);
188 free(result->hostname);
189 free(result);
190 result = NULL;
191 }
192 else
193 {
194 if (use_ssl == true)
195 {
196 TLSIO_CONFIG tlsio_config;
197
198 /* Codes_SRS_UWS_CLIENT_01_006: [ If use_ssl is true then uws_client_create shall obtain the interface used to create a tlsio instance by calling platform_get_default_tlsio. ]*/
199 /* Codes_SRS_UWS_CLIENT_01_076: [ If /secure/ is true, the client MUST perform a TLS handshake over the connection after opening the connection and before sending the handshake data [RFC2818]. ]*/
200 const IO_INTERFACE_DESCRIPTION* tlsio_interface = platform_get_default_tlsio();
201 if (tlsio_interface == NULL)
202 {
203 /* Codes_SRS_UWS_CLIENT_01_007: [ If obtaining the underlying IO interface fails, then uws_client_create shall fail and return NULL. ]*/
204 LogError("NULL TLSIO interface description");
205 result->underlying_io = NULL;
206 }
207 else
208 {
209 SOCKETIO_CONFIG socketio_config;
210
211 /* Codes_SRS_UWS_CLIENT_01_013: [ The create arguments for the tls IO (when use_ssl is 1) shall have: ]*/
212 /* Codes_SRS_UWS_CLIENT_01_014: [ - hostname set to the hostname argument passed to uws_client_create. ]*/
213 /* Codes_SRS_UWS_CLIENT_01_015: [ - port set to the port argument passed to uws_client_create. ]*/
214 socketio_config.hostname = hostname;
215 socketio_config.port = port;
216 socketio_config.accepted_socket = NULL;
217
218 tlsio_config.hostname = hostname;
219 tlsio_config.port = port;
220 tlsio_config.underlying_io_interface = socketio_get_interface_description();
221 tlsio_config.underlying_io_parameters = &socketio_config;
222
223 result->underlying_io = xio_create(tlsio_interface, &tlsio_config);
224 if (result->underlying_io == NULL)
225 {
226 LogError("Cannot create underlying TLS IO.");
227 }
228 else
229 {
230 // Set the underlying socket to turn on renegotiation
231 bool set_renegotiation = true;
232 xio_setoption(result->underlying_io, OPTION_SET_TLS_RENEGOTIATION, &set_renegotiation);
233 }
234 }
235 }
236 else
237 {
238 SOCKETIO_CONFIG socketio_config;
239 /* Codes_SRS_UWS_CLIENT_01_005: [ If use_ssl is false then uws_client_create shall obtain the interface used to create a socketio instance by calling socketio_get_interface_description. ]*/
240 const IO_INTERFACE_DESCRIPTION* socketio_interface = socketio_get_interface_description();
241 if (socketio_interface == NULL)
242 {
243 /* Codes_SRS_UWS_CLIENT_01_007: [ If obtaining the underlying IO interface fails, then uws_client_create shall fail and return NULL. ]*/
244 LogError("NULL socketio interface description");
245 result->underlying_io = NULL;
246 }
247 else
248 {
249 /* Codes_SRS_UWS_CLIENT_01_010: [ The create arguments for the socket IO (when use_ssl is 0) shall have: ]*/
250 /* Codes_SRS_UWS_CLIENT_01_011: [ - hostname set to the hostname argument passed to uws_client_create. ]*/
251 /* Codes_SRS_UWS_CLIENT_01_012: [ - port set to the port argument passed to uws_client_create. ]*/
252 socketio_config.hostname = hostname;
253 socketio_config.port = port;
254 socketio_config.accepted_socket = NULL;
255
256 /* Codes_SRS_UWS_CLIENT_01_008: [ The obtained interface shall be used to create the IO used as underlying IO by the newly created uws instance. ]*/
257 /* Codes_SRS_UWS_CLIENT_01_009: [ The underlying IO shall be created by calling xio_create. ]*/
258 result->underlying_io = xio_create(socketio_interface, &socketio_config);
259 if (result->underlying_io == NULL)
260 {
261 LogError("Cannot create underlying socket IO.");
262 }
263 }
264 }
265
266 if (result->underlying_io == NULL)
267 {
268 /* Codes_SRS_UWS_CLIENT_01_016: [ If xio_create fails, then uws_client_create shall fail and return NULL. ]*/
269 singlylinkedlist_destroy(result->pending_sends);
270 Map_Destroy(result->request_headers);
271 free(result->resource_name);
272 free(result->hostname);
273 free(result);
274 result = NULL;
275 }
276 else
277 {
278 result->uws_state = UWS_STATE_CLOSED;
279 /* Codes_SRS_UWS_CLIENT_01_403: [ The argument port shall be copied for later use. ]*/
280 result->port = port;
281
282 result->fragmented_frame_type = WS_FRAME_TYPE_UNKNOWN;
283
284 result->protocol_count = protocol_count;
285
286 /* Codes_SRS_UWS_CLIENT_01_410: [ The protocols argument shall be allowed to be NULL, in which case no protocol is to be specified by the client in the upgrade request. ]*/
287 if (protocols == NULL)
288 {
289 result->protocols = NULL;
290 }
291 else
292 {
293 result->protocols = (WS_INSTANCE_PROTOCOL*)malloc(sizeof(WS_INSTANCE_PROTOCOL) * protocol_count);
294 if (result->protocols == NULL)
295 {
296 /* Codes_SRS_UWS_CLIENT_01_414: [ If allocating memory for the copied protocol information fails then uws_client_create shall fail and return NULL. ]*/
297 LogError("Cannot allocate memory for the protocols array.");
298 xio_destroy(result->underlying_io);
299 singlylinkedlist_destroy(result->pending_sends);
300 Map_Destroy(result->request_headers);
301 free(result->resource_name);
302 free(result->hostname);
303 free(result);
304 result = NULL;
305 }
306 else
307 {
308 /* Codes_SRS_UWS_CLIENT_01_413: [ The protocol information indicated by protocols and protocol_count shall be copied for later use (for constructing the upgrade request). ]*/
309 for (i = 0; i < protocol_count; i++)
310 {
311 if (mallocAndStrcpy_s(&result->protocols[i].protocol, protocols[i].protocol) != 0)
312 {
313 /* Codes_SRS_UWS_CLIENT_01_414: [ If allocating memory for the copied protocol information fails then uws_client_create shall fail and return NULL. ]*/
314 LogError("Cannot allocate memory for the protocol index %u.", (unsigned int)i);
315 break;
316 }
317 }
318
319 if (i < protocol_count)
320 {
321 size_t j;
322
323 for (j = 0; j < i; j++)
324 {
325 free(result->protocols[j].protocol);
326 }
327
328 free(result->protocols);
329 xio_destroy(result->underlying_io);
330 singlylinkedlist_destroy(result->pending_sends);
331 Map_Destroy(result->request_headers);
332 free(result->resource_name);
333 free(result->hostname);
334 free(result);
335 result = NULL;
336 }
337 else
338 {
339 result->protocol_count = protocol_count;
340 }
341 }
342 }
343 }
344 }
345 }
346 }
347 }
348 }
349 }
350
351 return result;
352}
353
354UWS_CLIENT_HANDLE uws_client_create_with_io(const IO_INTERFACE_DESCRIPTION* io_interface, void* io_create_parameters, const char* hostname, unsigned int port, const char* resource_name, const WS_PROTOCOL* protocols, size_t protocol_count)
355{
356 UWS_CLIENT_HANDLE result;
357
358 /* Codes_SRS_UWS_CLIENT_01_516: [ If any of the arguments io_interface, hostname and resource_name is NULL then uws_client_create_with_io shall return NULL. ]*/
359 if ((hostname == NULL) ||
360 (io_interface == NULL) ||
361 (resource_name == NULL) ||
362 /* Codes_SRS_UWS_CLIENT_01_525: [ If protocol_count is non zero and protocols is NULL then uws_client_create_with_io shall fail and return NULL. ]*/
363 ((protocols == NULL) && (protocol_count > 0)))
364 {
365 LogError("Invalid arguments: io_interface = %p, resource_name = %p, protocols = %p, protocol_count = %lu", io_interface, resource_name, protocols, (unsigned long)protocol_count);
366 result = NULL;
367 }
368 else
369 {
370 size_t i;
371 for (i = 0; i < protocol_count; i++)
372 {
373 if (protocols[i].protocol == NULL)
374 {
375 break;
376 }
377 }
378
379 if (i < protocol_count)
380 {
381 /* Codes_SRS_UWS_CLIENT_01_526: [ If the protocol member of any of the items in the protocols argument is NULL, then uws_client_create_with_io shall fail and return NULL. ]*/
382 LogError("Protocol index %lu has NULL name", (unsigned long)i);
383 result = NULL;
384 }
385 else
386 {
387 /* Codes_SRS_UWS_CLIENT_01_515: [ uws_client_create_with_io shall create an instance of uws and return a non-NULL handle to it. ]*/
388 result = (UWS_CLIENT_HANDLE)malloc(sizeof(UWS_CLIENT_INSTANCE));
389 if (result == NULL)
390 {
391 /* Codes_SRS_UWS_CLIENT_01_517: [ If allocating memory for the new uws instance fails then uws_client_create_with_io shall return NULL. ]*/
392 LogError("Could not allocate uWS instance");
393 }
394 else
395 {
396 memset(result, 0, sizeof(UWS_CLIENT_INSTANCE));
397
398 /* Codes_SRS_UWS_CLIENT_01_518: [ The argument hostname shall be copied for later use. ]*/
399 if (mallocAndStrcpy_s(&result->hostname, hostname) != 0)
400 {
401 /* Codes_SRS_UWS_CLIENT_01_519: [ If allocating memory for the copy of the hostname argument fails, then uws_client_create shall return NULL. ]*/
402 LogError("Could not copy hostname.");
403 free(result);
404 result = NULL;
405 }
406 else
407 {
408 /* Codes_SRS_UWS_CLIENT_01_523: [ The argument resource_name shall be copied for later use. ]*/
409 if (mallocAndStrcpy_s(&result->resource_name, resource_name) != 0)
410 {
411 /* Codes_SRS_UWS_CLIENT_01_529: [ If allocating memory for the copy of the resource_name argument fails, then uws_client_create_with_io shall return NULL. ]*/
412 LogError("Could not copy resource.");
413 free(result->hostname);
414 free(result);
415 result = NULL;
416 }
417 else if ((result->request_headers = Map_Create(NULL)) == NULL)
418 {
419 LogError("Failed allocating MAP for request headers");
420 free(result->resource_name);
421 free(result->hostname);
422 free(result);
423 result = NULL;
424 }
425 else
426 {
427 /* Codes_SRS_UWS_CLIENT_01_530: [ uws_client_create_with_io shall create a pending send IO list that is to be used to queue send packets by calling singlylinkedlist_create. ]*/
428 result->pending_sends = singlylinkedlist_create();
429 if (result->pending_sends == NULL)
430 {
431 /* Codes_SRS_UWS_CLIENT_01_531: [ If singlylinkedlist_create fails then uws_client_create_with_io shall fail and return NULL. ]*/
432 LogError("Could not allocate pending send frames list");
433 Map_Destroy(result->request_headers);
434 free(result->resource_name);
435 free(result->hostname);
436 free(result);
437 result = NULL;
438 }
439 else
440 {
441 /* Codes_SRS_UWS_CLIENT_01_521: [ The underlying IO shall be created by calling xio_create, while passing as arguments the io_interface and io_create_parameters argument values. ]*/
442 result->underlying_io = xio_create(io_interface, io_create_parameters);
443 if (result->underlying_io == NULL)
444 {
445 /* Codes_SRS_UWS_CLIENT_01_522: [ If xio_create fails, then uws_client_create_with_io shall fail and return NULL. ]*/
446 LogError("Cannot create underlying IO.");
447 singlylinkedlist_destroy(result->pending_sends);
448 Map_Destroy(result->request_headers);
449 free(result->resource_name);
450 free(result->hostname);
451 free(result);
452 result = NULL;
453 }
454 else
455 {
456 // Set the underlying socket to turn on renegotiation
457 bool set_renegotiation = true;
458 (void)xio_setoption(result->underlying_io, OPTION_SET_TLS_RENEGOTIATION, &set_renegotiation);
459
460 result->uws_state = UWS_STATE_CLOSED;
461
462 /* Codes_SRS_UWS_CLIENT_01_520: [ The argument port shall be copied for later use. ]*/
463 result->port = port;
464
465 result->fragmented_frame_type = WS_FRAME_TYPE_UNKNOWN;
466
467 result->protocol_count = protocol_count;
468
469 /* Codes_SRS_UWS_CLIENT_01_524: [ The protocols argument shall be allowed to be NULL, in which case no protocol is to be specified by the client in the upgrade request. ]*/
470 if (protocols == NULL)
471 {
472 result->protocols = NULL;
473 }
474 else
475 {
476 result->protocols = (WS_INSTANCE_PROTOCOL*)malloc(sizeof(WS_INSTANCE_PROTOCOL) * protocol_count);
477 if (result->protocols == NULL)
478 {
479 /* Codes_SRS_UWS_CLIENT_01_414: [ If allocating memory for the copied protocol information fails then uws_client_create shall fail and return NULL. ]*/
480 LogError("Cannot allocate memory for the protocols array.");
481 xio_destroy(result->underlying_io);
482 singlylinkedlist_destroy(result->pending_sends);
483 Map_Destroy(result->request_headers);
484 free(result->resource_name);
485 free(result->hostname);
486 free(result);
487 result = NULL;
488 }
489 else
490 {
491 /* Codes_SRS_UWS_CLIENT_01_527: [ The protocol information indicated by protocols and protocol_count shall be copied for later use (for constructing the upgrade request). ]*/
492 for (i = 0; i < protocol_count; i++)
493 {
494 if (mallocAndStrcpy_s(&result->protocols[i].protocol, protocols[i].protocol) != 0)
495 {
496 /* Codes_SRS_UWS_CLIENT_01_528: [ If allocating memory for the copied protocol information fails then uws_client_create_with_io shall fail and return NULL. ]*/
497 LogError("Cannot allocate memory for the protocol index %u.", (unsigned int)i);
498 break;
499 }
500 }
501
502 if (i < protocol_count)
503 {
504 size_t j;
505
506 for (j = 0; j < i; j++)
507 {
508 free(result->protocols[j].protocol);
509 }
510
511 free(result->protocols);
512 xio_destroy(result->underlying_io);
513 singlylinkedlist_destroy(result->pending_sends);
514 Map_Destroy(result->request_headers);
515 free(result->resource_name);
516 free(result->hostname);
517 free(result);
518 result = NULL;
519 }
520 else
521 {
522 result->protocol_count = protocol_count;
523 }
524 }
525 }
526 }
527 }
528 }
529 }
530 }
531 }
532 }
533
534 return result;
535}
536
537void uws_client_destroy(UWS_CLIENT_HANDLE uws_client)
538{
539 /* Codes_SRS_UWS_CLIENT_01_020: [ If uws_client is NULL, uws_client_destroy shall do nothing. ]*/
540 if (uws_client == NULL)
541 {
542 LogError("NULL uws handle");
543 }
544 else
545 {
546 free(uws_client->stream_buffer);
547 free(uws_client->fragment_buffer);
548
549 /* Codes_SRS_UWS_CLIENT_01_021: [ uws_client_destroy shall perform a close action if the uws instance has already been open. ]*/
550 switch (uws_client->uws_state)
551 {
552 default:
553 break;
554
555 case UWS_STATE_OPEN:
556 case UWS_STATE_ERROR:
557 uws_client_close_async(uws_client, NULL, NULL);
558 break;
559 }
560
561 if (uws_client->protocol_count > 0)
562 {
563 size_t i;
564
565 /* Codes_SRS_UWS_CLIENT_01_437: [ uws_client_destroy shall free the protocols array allocated in uws_client_create. ]*/
566 for (i = 0; i < uws_client->protocol_count; i++)
567 {
568 free(uws_client->protocols[i].protocol);
569 }
570
571 free(uws_client->protocols);
572 }
573
574 /* Codes_SRS_UWS_CLIENT_01_019: [ uws_client_destroy shall free all resources associated with the uws instance. ]*/
575 /* Codes_SRS_UWS_CLIENT_01_023: [ uws_client_destroy shall ensure the underlying IO created in uws_client_open_async is destroyed by calling xio_destroy. ]*/
576 if (uws_client->underlying_io != NULL)
577 {
578 xio_destroy(uws_client->underlying_io);
579 uws_client->underlying_io = NULL;
580 }
581
582 /* Codes_SRS_UWS_CLIENT_01_024: [ uws_client_destroy shall free the list used to track the pending sends by calling singlylinkedlist_destroy. ]*/
583 singlylinkedlist_destroy(uws_client->pending_sends);
584 free(uws_client->resource_name);
585 free(uws_client->hostname);
586 Map_Destroy(uws_client->request_headers);
587 free(uws_client);
588 }
589}
590
591static void indicate_ws_open_complete_error(UWS_CLIENT_INSTANCE* uws_client, WS_OPEN_RESULT ws_open_result)
592{
593 /* Codes_SRS_UWS_CLIENT_01_409: [ After any error is indicated by on_ws_open_complete, a subsequent uws_client_open_async shall be possible. ]*/
594 uws_client->uws_state = UWS_STATE_CLOSED;
595 uws_client->on_ws_open_complete(uws_client->on_ws_open_complete_context, ws_open_result);
596}
597
598static void indicate_ws_open_complete_error_and_close(UWS_CLIENT_INSTANCE* uws_client, WS_OPEN_RESULT ws_open_result)
599{
600 (void)xio_close(uws_client->underlying_io, NULL, NULL);
601 indicate_ws_open_complete_error(uws_client, ws_open_result);
602}
603
604static void indicate_ws_error(UWS_CLIENT_INSTANCE* uws_client, WS_ERROR error_code)
605{
606 uws_client->uws_state = UWS_STATE_ERROR;
607 uws_client->on_ws_error(uws_client->on_ws_error_context, error_code);
608}
609
610static void indicate_ws_close_complete(UWS_CLIENT_INSTANCE* uws_client)
611{
612 uws_client->uws_state = UWS_STATE_CLOSED;
613
614 /* Codes_SRS_UWS_CLIENT_01_496: [ If the close was initiated by the peer no on_ws_close_complete shall be called. ]*/
615 if (uws_client->on_ws_close_complete != NULL)
616 {
617 /* Codes_SRS_UWS_CLIENT_01_491: [ When calling on_ws_close_complete callback, the on_ws_close_complete_context argument shall be passed to it. ]*/
618 uws_client->on_ws_close_complete(uws_client->on_ws_close_complete_context);
619 }
620}
621
622// This callback usage needs to be either verified and commented or integrated into
623// the state machine.
624static void unchecked_on_send_complete(void* context, IO_SEND_RESULT send_result)
625{
626 (void)context;
627 (void)send_result;
628}
629
630static int send_close_frame(UWS_CLIENT_INSTANCE* uws_client, unsigned int close_error_code)
631{
632 unsigned char* close_frame;
633 unsigned char close_frame_payload[2];
634 size_t close_frame_length;
635 int result;
636 BUFFER_HANDLE close_frame_buffer;
637
638 close_frame_payload[0] = (unsigned char)(close_error_code >> 8);
639 close_frame_payload[1] = (unsigned char)(close_error_code & 0xFF);
640
641 /* Codes_SRS_UWS_CLIENT_01_140: [ To avoid confusing network intermediaries (such as intercepting proxies) and for security reasons that are further discussed in Section 10.3, a client MUST mask all frames that it sends to the server (see Section 5.3 for further details). ]*/
642 close_frame_buffer = uws_frame_encoder_encode(WS_CLOSE_FRAME, close_frame_payload, sizeof(close_frame_payload), true, true, 0);
643 if (close_frame_buffer == NULL)
644 {
645 LogError("Encoding of CLOSE failed.");
646 result = MU_FAILURE;
647 }
648 else
649 {
650 close_frame = BUFFER_u_char(close_frame_buffer);
651 close_frame_length = BUFFER_length(close_frame_buffer);
652
653 /* Codes_SRS_UWS_CLIENT_01_471: [ The callback on_underlying_io_close_sent shall be passed as argument to xio_send. ]*/
654 if (xio_send(uws_client->underlying_io, close_frame, close_frame_length, unchecked_on_send_complete, NULL) != 0)
655 {
656 LogError("Sending CLOSE frame failed.");
657 result = MU_FAILURE;
658 }
659 else
660 {
661 result = 0;
662 }
663
664 BUFFER_delete(close_frame_buffer);
665 }
666
667 return result;
668}
669
670static void indicate_ws_error_and_close(UWS_CLIENT_INSTANCE* uws_client, WS_ERROR error_code, unsigned int close_error_code)
671{
672 uws_client->uws_state = UWS_STATE_ERROR;
673
674 (void)send_close_frame(uws_client, close_error_code);
675
676 uws_client->on_ws_error(uws_client->on_ws_error_context, error_code);
677}
678
679static char* get_request_headers(MAP_HANDLE headers)
680{
681 char* result;
682 const char* const* keys;
683 const char* const* values;
684 size_t count;
685
686 if (Map_GetInternals(headers, &keys, &values, &count) != MAP_OK)
687 {
688 LogError("Failed getting the request headers");
689 result = NULL;
690 }
691 else
692 {
693 size_t length = 0;
694 size_t i;
695
696 for (i = 0; i < count; i++)
697 {
698 // 4 = 2 (": ") + 2 ("\r\n")
699 length += strlen(keys[i]) + strlen(values[i]) + 4;
700 }
701
702 if ((result = (char*)malloc(sizeof(char) * (length + 1))) == NULL)
703 {
704 LogError("Failed allocating string for request headers");
705 result = NULL;
706 }
707 else
708 {
709 size_t position = 0;
710
711 for (i = 0; i < count; i++)
712 {
713 size_t key_length = strlen(keys[i]);
714 size_t value_length = strlen(values[i]);
715
716 (void)memcpy(result + position, keys[i], key_length);
717 position += key_length;
718 (void)memcpy(result + position, HTTP_HEADER_KEY_VALUE_SEPARATOR, HTTP_HEADER_KEY_VALUE_SEPARATOR_LENGTH);
719 position += HTTP_HEADER_KEY_VALUE_SEPARATOR_LENGTH;
720 (void)memcpy(result + position, values[i], value_length);
721 position += value_length;
722 (void)memcpy(result + position, HTTP_HEADER_TERMINATOR, HTTP_HEADER_TERMINATOR_LENGTH);
723 position += HTTP_HEADER_TERMINATOR_LENGTH;
724 }
725
726 result[position] = '\0';
727 }
728 }
729
730 return result;
731}
732
733static void on_underlying_io_open_complete(void* context, IO_OPEN_RESULT open_result)
734{
735 UWS_CLIENT_HANDLE uws_client = (UWS_CLIENT_HANDLE)context;
736 /* Codes_SRS_UWS_CLIENT_01_401: [ If on_underlying_io_open_complete is called with a NULL context, on_underlying_io_open_complete shall do nothing. ]*/
737 if (uws_client == NULL)
738 {
739 LogError("NULL context");
740 }
741 else
742 {
743 switch (uws_client->uws_state)
744 {
745 default:
746 case UWS_STATE_WAITING_FOR_UPGRADE_RESPONSE:
747 /* Codes_SRS_UWS_CLIENT_01_407: [ When on_underlying_io_open_complete is called when the uws instance has send the upgrade request but it is waiting for the response, an error shall be reported to the user by calling the on_ws_open_complete with WS_OPEN_ERROR_MULTIPLE_UNDERLYING_IO_OPEN_EVENTS. ]*/
748 LogError("underlying on_io_open_complete was called again after upgrade request was sent.");
749 indicate_ws_open_complete_error_and_close(uws_client, WS_OPEN_ERROR_MULTIPLE_UNDERLYING_IO_OPEN_EVENTS);
750 break;
751 case UWS_STATE_OPENING_UNDERLYING_IO:
752 switch (open_result)
753 {
754 default:
755 case IO_OPEN_ERROR:
756 /* Codes_SRS_UWS_CLIENT_01_369: [ When on_underlying_io_open_complete is called with IO_OPEN_ERROR while uws is OPENING (uws_client_open_async was called), uws shall report that the open failed by calling the on_ws_open_complete callback passed to uws_client_open_async with WS_OPEN_ERROR_UNDERLYING_IO_OPEN_FAILED. ]*/
757 indicate_ws_open_complete_error(uws_client, WS_OPEN_ERROR_UNDERLYING_IO_OPEN_FAILED);
758 break;
759
760 case IO_OPEN_CANCELLED:
761 /* Codes_SRS_UWS_CLIENT_01_402: [ When on_underlying_io_open_complete is called with IO_OPEN_CANCELLED while uws is OPENING (uws_client_open_async was called), uws shall report that the open failed by calling the on_ws_open_complete callback passed to uws_client_open_async with WS_OPEN_ERROR_UNDERLYING_IO_OPEN_CANCELLED. ]*/
762 indicate_ws_open_complete_error(uws_client, WS_OPEN_ERROR_UNDERLYING_IO_OPEN_CANCELLED);
763 break;
764
765 case IO_OPEN_OK:
766 {
767 int upgrade_request_length;
768 char* upgrade_request;
769 size_t i;
770 unsigned char nonce[16];
771 STRING_HANDLE base64_nonce;
772 char* request_headers = NULL;
773
774 /* Codes_SRS_UWS_CLIENT_01_089: [ The value of this header field MUST be a nonce consisting of a randomly selected 16-byte value that has been base64-encoded (see Section 4 of [RFC4648]). ]*/
775 /* Codes_SRS_UWS_CLIENT_01_090: [ The nonce MUST be selected randomly for each connection. ]*/
776 for (i = 0; i < sizeof(nonce); i++)
777 {
778 nonce[i] = (unsigned char)gb_rand();
779 }
780
781 /* Codes_SRS_UWS_CLIENT_01_497: [ The nonce needed for the upgrade request shall be Base64 encoded with Azure_Base64_Encode_Bytes. ]*/
782 base64_nonce = Azure_Base64_Encode_Bytes(nonce, sizeof(nonce));
783 if (base64_nonce == NULL)
784 {
785 /* Codes_SRS_UWS_CLIENT_01_498: [ If Base64 encoding the nonce for the upgrade request fails, then the uws client shall report that the open failed by calling the on_ws_open_complete callback passed to uws_client_open_async with WS_OPEN_ERROR_BASE64_ENCODE_FAILED. ]*/
786 LogError("Cannot construct the WebSocket upgrade request");
787 indicate_ws_open_complete_error(uws_client, WS_OPEN_ERROR_BASE64_ENCODE_FAILED);
788 }
789 else if ((request_headers = get_request_headers(uws_client->request_headers)) == NULL)
790 {
791 LogError("Cannot construct the WebSocket request headers");
792 indicate_ws_open_complete_error(uws_client, WS_OPEN_ERROR_CONSTRUCTING_UPGRADE_REQUEST);
793 }
794 else
795 {
796 /* Codes_SRS_UWS_CLIENT_01_371: [ When on_underlying_io_open_complete is called with IO_OPEN_OK while uws is OPENING (uws_client_open_async was called), uws shall prepare the WebSockets upgrade request. ]*/
797 /* Codes_SRS_UWS_CLIENT_01_081: [ The handshake consists of an HTTP Upgrade request, along with a list of required and optional header fields. ]*/
798 /* Codes_SRS_UWS_CLIENT_01_082: [ The handshake MUST be a valid HTTP request as specified by [RFC2616]. ]*/
799 /* Codes_SRS_UWS_CLIENT_01_083: [ The method of the request MUST be GET, and the HTTP version MUST be at least 1.1. ]*/
800 /* Codes_SRS_UWS_CLIENT_01_084: [ The "Request-URI" part of the request MUST match the /resource name/ defined in Section 3 (a relative URI) or be an absolute http/https URI that, when parsed, has a /resource name/, /host/, and /port/ that match the corresponding ws/wss URI. ]*/
801 /* Codes_SRS_UWS_CLIENT_01_085: [ The request MUST contain a |Host| header field whose value contains /host/ plus optionally ":" followed by /port/ (when not using the default port). ]*/
802 /* Codes_SRS_UWS_CLIENT_01_086: [ The request MUST contain an |Upgrade| header field whose value MUST include the "websocket" keyword. ]*/
803 /* Codes_SRS_UWS_CLIENT_01_087: [ The request MUST contain a |Connection| header field whose value MUST include the "Upgrade" token. ]*/
804 /* Codes_SRS_UWS_CLIENT_01_088: [ The request MUST include a header field with the name |Sec-WebSocket-Key|. ]*/
805 /* Codes_SRS_UWS_CLIENT_01_094: [ The request MUST include a header field with the name |Sec-WebSocket-Version|. ]*/
806 /* Codes_SRS_UWS_CLIENT_01_095: [ The value of this header field MUST be 13. ]*/
807 /* Codes_SRS_UWS_CLIENT_01_096: [ The request MAY include a header field with the name |Sec-WebSocket-Protocol|. ]*/
808 /* Codes_SRS_UWS_CLIENT_01_100: [ The request MAY include a header field with the name |Sec-WebSocket-Extensions|. ]*/
809 /* Codes_SRS_UWS_CLIENT_01_101: [ The request MAY include any other header fields, for example, cookies [RFC6265] and/or authentication-related header fields such as the |Authorization| header field [RFC2616], which are processed according to documents that define them. ] */
810 const char upgrade_request_format[] = "GET %s HTTP/1.1\r\n"
811 "Host: %s:%d\r\n"
812 "Upgrade: websocket\r\n"
813 "Connection: Upgrade\r\n"
814 "Sec-WebSocket-Key: %s\r\n"
815 "Sec-WebSocket-Protocol: %s\r\n"
816 "Sec-WebSocket-Version: 13\r\n"
817 "%s"
818 "\r\n";
819
820 const char* base64_nonce_chars = STRING_c_str(base64_nonce);
821
822 upgrade_request_length = (int)(strlen(upgrade_request_format) + strlen(uws_client->resource_name)+strlen(uws_client->hostname) + strlen(base64_nonce_chars) + strlen(uws_client->protocols[0].protocol) + strlen(request_headers) + 5);
823 if (upgrade_request_length < 0)
824 {
825 /* Codes_SRS_UWS_CLIENT_01_408: [ If constructing of the WebSocket upgrade request fails, uws shall report that the open failed by calling the on_ws_open_complete callback passed to uws_client_open_async with WS_OPEN_ERROR_CONSTRUCTING_UPGRADE_REQUEST. ]*/
826 LogError("Cannot construct the WebSocket upgrade request");
827 indicate_ws_open_complete_error_and_close(uws_client, WS_OPEN_ERROR_CONSTRUCTING_UPGRADE_REQUEST);
828 }
829 else
830 {
831 upgrade_request = (char*)malloc(upgrade_request_length + 1);
832 if (upgrade_request == NULL)
833 {
834 /* Codes_SRS_UWS_CLIENT_01_406: [ If not enough memory can be allocated to construct the WebSocket upgrade request, uws shall report that the open failed by calling the on_ws_open_complete callback passed to uws_client_open_async with WS_OPEN_ERROR_NOT_ENOUGH_MEMORY. ]*/
835 LogError("Cannot allocate memory for the WebSocket upgrade request");
836 indicate_ws_open_complete_error_and_close(uws_client, WS_OPEN_ERROR_NOT_ENOUGH_MEMORY);
837 }
838 else
839 {
840
841 upgrade_request_length = sprintf(upgrade_request, upgrade_request_format,
842 uws_client->resource_name,
843 uws_client->hostname,
844 uws_client->port,
845 base64_nonce_chars,
846 uws_client->protocols[0].protocol,
847 request_headers);
848
849 /* No need to have any send complete here, as we are monitoring the received bytes */
850 /* Codes_SRS_UWS_CLIENT_01_372: [ Once prepared the WebSocket upgrade request shall be sent by calling xio_send. ]*/
851 /* Codes_SRS_UWS_CLIENT_01_080: [ Once a connection to the server has been established (including a connection via a proxy or over a TLS-encrypted tunnel), the client MUST send an opening handshake to the server. ]*/
852 if (xio_send(uws_client->underlying_io, upgrade_request, upgrade_request_length, unchecked_on_send_complete, NULL) != 0)
853 {
854 /* Codes_SRS_UWS_CLIENT_01_373: [ If xio_send fails then uws shall report that the open failed by calling the on_ws_open_complete callback passed to uws_client_open_async with WS_OPEN_ERROR_CANNOT_SEND_UPGRADE_REQUEST. ]*/
855 LogError("Cannot send upgrade request");
856 indicate_ws_open_complete_error_and_close(uws_client, WS_OPEN_ERROR_CANNOT_SEND_UPGRADE_REQUEST);
857 }
858 else
859 {
860 /* Codes_SRS_UWS_CLIENT_01_102: [ Once the client's opening handshake has been sent, the client MUST wait for a response from the server before sending any further data. ]*/
861 uws_client->uws_state = UWS_STATE_WAITING_FOR_UPGRADE_RESPONSE;
862 }
863
864 free(upgrade_request);
865 }
866 }
867
868 STRING_delete(base64_nonce);
869 free(request_headers);
870 }
871
872 break;
873 }
874 }
875 }
876 }
877}
878
879static void consume_stream_buffer_bytes(UWS_CLIENT_INSTANCE* uws_client, size_t consumed_bytes)
880{
881 if (consumed_bytes < uws_client->stream_buffer_count)
882 {
883 (void)memmove(uws_client->stream_buffer, uws_client->stream_buffer + consumed_bytes, uws_client->stream_buffer_count - consumed_bytes);
884 }
885
886 uws_client->stream_buffer_count -= consumed_bytes;
887}
888
889static void on_underlying_io_close_complete(void* context)
890{
891 if (context == NULL)
892 {
893 /* Codes_SRS_UWS_CLIENT_01_477: [ When on_underlying_io_close_complete is called with a NULL context, it shall do nothing. ]*/
894 LogError("NULL context for on_underlying_io_close_complete");
895 }
896 else
897 {
898 UWS_CLIENT_HANDLE uws_client = (UWS_CLIENT_HANDLE)context;
899 if (uws_client->uws_state == UWS_STATE_CLOSING_UNDERLYING_IO)
900 {
901 /* Codes_SRS_UWS_CLIENT_01_475: [ When on_underlying_io_close_complete is called while closing the underlying IO a subsequent uws_client_open_async shall succeed. ]*/
902 indicate_ws_close_complete(uws_client);
903 uws_client->uws_state = UWS_STATE_CLOSED;
904 }
905 }
906}
907
908static void on_underlying_io_close_sent(void* context, IO_SEND_RESULT io_send_result)
909{
910 if (context == NULL)
911 {
912 /* Codes_SRS_UWS_CLIENT_01_489: [ When on_underlying_io_close_sent is called with NULL context, it shall do nothing. ] */
913 LogError("NULL context in ");
914 }
915 else
916 {
917 UWS_CLIENT_INSTANCE* uws_client = (UWS_CLIENT_HANDLE)context;
918
919 switch (io_send_result)
920 {
921 default:
922 LogError("Unknown enum value: %d", io_send_result);
923 break;
924
925 case IO_SEND_OK:
926 case IO_SEND_CANCELLED:
927 if (uws_client->uws_state == UWS_STATE_CLOSING_SENDING_CLOSE)
928 {
929 uws_client->uws_state = UWS_STATE_CLOSING_UNDERLYING_IO;
930
931 /* Codes_SRS_UWS_CLIENT_01_490: [ When on_underlying_io_close_sent is called while the uws client is CLOSING, on_underlying_io_close_sent shall close the underlying IO by calling xio_close. ]*/
932 if (xio_close(uws_client->underlying_io, on_underlying_io_close_complete, uws_client) != 0)
933 {
934 /* Codes_SRS_UWS_CLIENT_01_496: [ If the close was initiated by the peer no on_ws_close_complete shall be called. ]*/
935 indicate_ws_close_complete(uws_client);
936 }
937 }
938
939 case IO_SEND_ERROR:
940 break;
941 }
942 }
943}
944
945/*the following function does the same as sscanf(pos2, "%d", &sec)*/
946/*this function only exists because some of platforms do not have sscanf. */
947static int ParseStringToDecimal(const char *src, int* dst)
948{
949 int result;
950 char* next;
951
952 (*dst) = (int)strtol(src, &next, 0);
953 if ((src == next) || ((((*dst) == INT_MAX) || ((*dst) == INT_MIN)) && (errno != 0)))
954 {
955 result = MU_FAILURE;
956 }
957 else
958 {
959 result = 0;
960 }
961
962 return result;
963}
964
965/*the following function does the same as sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &ret) */
966/*this function only exists because some of platforms do not have sscanf. This is not a full implementation; it only works with well-defined HTTP response. */
967static int ParseHttpResponse(const char* src, int* dst)
968{
969 int result;
970 static const char HTTPPrefix[] = "HTTP/";
971 bool fail;
972 const char* runPrefix;
973
974 if ((src == NULL) || (dst == NULL))
975 {
976 result = MU_FAILURE;
977 }
978 else
979 {
980 fail = false;
981 runPrefix = HTTPPrefix;
982
983 while ((*runPrefix) != '\0')
984 {
985 if ((*runPrefix) != (*src))
986 {
987 fail = true;
988 break;
989 }
990 src++;
991 runPrefix++;
992 }
993
994 if (!fail)
995 {
996 while ((*src) != '.')
997 {
998 if ((*src) == '\0')
999 {
1000 fail = true;
1001 break;
1002 }
1003 src++;
1004 }
1005 }
1006
1007 if (!fail)
1008 {
1009 while ((*src) != ' ')
1010 {
1011 if ((*src) == '\0')
1012 {
1013 fail = true;
1014 break;
1015 }
1016 src++;
1017 }
1018 }
1019
1020 if (fail)
1021 {
1022 result = MU_FAILURE;
1023 }
1024 else
1025 {
1026 if (ParseStringToDecimal(src, dst) != 0)
1027 {
1028 result = MU_FAILURE;
1029 }
1030 else
1031 {
1032 result = 0;
1033 }
1034 }
1035 }
1036
1037 return result;
1038}
1039
1040static int process_frame_fragment(UWS_CLIENT_INSTANCE *uws_client, size_t length, size_t needed_bytes)
1041{
1042 int result;
1043 unsigned char *new_fragment_bytes = (unsigned char *)realloc(uws_client->fragment_buffer, uws_client->fragment_buffer_count + length);
1044 if (new_fragment_bytes == NULL)
1045 {
1046 /* Codes_SRS_UWS_CLIENT_01_379: [ If allocating memory for accumulating the bytes fails, uws shall report that the open failed by calling the on_ws_open_complete callback passed to uws_client_open_async with WS_OPEN_ERROR_NOT_ENOUGH_MEMORY. ]*/
1047 LogError("Cannot allocate memory for received data");
1048 indicate_ws_error(uws_client, WS_ERROR_NOT_ENOUGH_MEMORY);
1049 result = MU_FAILURE;
1050 }
1051 else
1052 {
1053 uws_client->fragment_buffer = new_fragment_bytes;
1054 (void)memcpy(uws_client->fragment_buffer + uws_client->fragment_buffer_count, uws_client->stream_buffer + needed_bytes - length, length);
1055 uws_client->fragment_buffer_count += length;
1056 result = 0;
1057 }
1058
1059 return result;
1060}
1061
1062static void on_underlying_io_bytes_received(void* context, const unsigned char* buffer, size_t size)
1063{
1064 /* Codes_SRS_UWS_CLIENT_01_415: [ If called with a NULL context argument, on_underlying_io_bytes_received shall do nothing. ]*/
1065 if (context != NULL)
1066 {
1067 UWS_CLIENT_HANDLE uws_client = (UWS_CLIENT_HANDLE)context;
1068
1069 if ((buffer == NULL) ||
1070 (size == 0))
1071 {
1072 /* Codes_SRS_UWS_CLIENT_01_416: [ If called with NULL buffer or zero size and the state of the iws is OPENING, uws shall report that the open failed by calling the on_ws_open_complete callback passed to uws_client_open_async with WS_OPEN_ERROR_INVALID_BYTES_RECEIVED_ARGUMENTS. ]*/
1073 indicate_ws_open_complete_error_and_close(uws_client, WS_OPEN_ERROR_INVALID_BYTES_RECEIVED_ARGUMENTS);
1074 }
1075 else
1076 {
1077 unsigned char decode_stream = 1;
1078
1079 switch (uws_client->uws_state)
1080 {
1081 default:
1082 case UWS_STATE_CLOSED:
1083 decode_stream = 0;
1084 break;
1085
1086 case UWS_STATE_OPENING_UNDERLYING_IO:
1087 /* Codes_SRS_UWS_CLIENT_01_417: [ When on_underlying_io_bytes_received is called while OPENING but before the on_underlying_io_open_complete has been called, uws shall report that the open failed by calling the on_ws_open_complete callback passed to uws_client_open_async with WS_OPEN_ERROR_BYTES_RECEIVED_BEFORE_UNDERLYING_OPEN. ]*/
1088 indicate_ws_open_complete_error_and_close(uws_client, WS_OPEN_ERROR_BYTES_RECEIVED_BEFORE_UNDERLYING_OPEN);
1089 decode_stream = 0;
1090 break;
1091
1092 case UWS_STATE_WAITING_FOR_UPGRADE_RESPONSE:
1093 {
1094 /* Codes_SRS_UWS_CLIENT_01_378: [ When on_underlying_io_bytes_received is called while the uws is OPENING, the received bytes shall be accumulated in order to attempt parsing the WebSocket Upgrade response. ]*/
1095 unsigned char* new_received_bytes = (unsigned char*)realloc(uws_client->stream_buffer, uws_client->stream_buffer_count + size + 1);
1096 if (new_received_bytes == NULL)
1097 {
1098 /* Codes_SRS_UWS_CLIENT_01_379: [ If allocating memory for accumulating the bytes fails, uws shall report that the open failed by calling the on_ws_open_complete callback passed to uws_client_open_async with WS_OPEN_ERROR_NOT_ENOUGH_MEMORY. ]*/
1099 indicate_ws_open_complete_error_and_close(uws_client, WS_OPEN_ERROR_NOT_ENOUGH_MEMORY);
1100 decode_stream = 0;
1101 }
1102 else
1103 {
1104 uws_client->stream_buffer = new_received_bytes;
1105 (void)memcpy(uws_client->stream_buffer + uws_client->stream_buffer_count, buffer, size);
1106 uws_client->stream_buffer_count += size;
1107
1108 decode_stream = 1;
1109 }
1110
1111 break;
1112 }
1113
1114 case UWS_STATE_OPEN:
1115 case UWS_STATE_CLOSING_WAITING_FOR_CLOSE:
1116 {
1117 /* Codes_SRS_UWS_CLIENT_01_385: [ If the state of the uws instance is OPEN, the received bytes shall be used for decoding WebSocket frames. ]*/
1118 unsigned char* new_received_bytes = (unsigned char*)realloc(uws_client->stream_buffer, uws_client->stream_buffer_count + size + 1);
1119 if (new_received_bytes == NULL)
1120 {
1121 /* Codes_SRS_UWS_CLIENT_01_418: [ If allocating memory for the bytes accumulated for decoding WebSocket frames fails, an error shall be indicated by calling the on_ws_error callback with WS_ERROR_NOT_ENOUGH_MEMORY. ]*/
1122 LogError("Cannot allocate memory for received data");
1123 indicate_ws_error(uws_client, WS_ERROR_NOT_ENOUGH_MEMORY);
1124
1125 decode_stream = 0;
1126 }
1127 else
1128 {
1129 uws_client->stream_buffer = new_received_bytes;
1130 (void)memcpy(uws_client->stream_buffer + uws_client->stream_buffer_count, buffer, size);
1131 uws_client->stream_buffer_count += size;
1132
1133 decode_stream = 1;
1134 }
1135
1136 break;
1137 }
1138 }
1139
1140 while (decode_stream)
1141 {
1142 decode_stream = 0;
1143
1144 switch (uws_client->uws_state)
1145 {
1146 default:
1147 case UWS_STATE_CLOSED:
1148 break;
1149
1150 case UWS_STATE_OPENING_UNDERLYING_IO:
1151 /* Codes_SRS_UWS_CLIENT_01_417: [ When on_underlying_io_bytes_received is called while OPENING but before the on_underlying_io_open_complete has been called, uws shall report that the open failed by calling the on_ws_open_complete callback passed to uws_client_open_async with WS_OPEN_ERROR_BYTES_RECEIVED_BEFORE_UNDERLYING_OPEN. ]*/
1152 indicate_ws_open_complete_error_and_close(uws_client, WS_OPEN_ERROR_BYTES_RECEIVED_BEFORE_UNDERLYING_OPEN);
1153 break;
1154
1155 case UWS_STATE_WAITING_FOR_UPGRADE_RESPONSE:
1156 {
1157 const char* request_end_ptr;
1158
1159 /* Make sure it is zero terminated */
1160 uws_client->stream_buffer[uws_client->stream_buffer_count] = '\0';
1161
1162 /* Codes_SRS_UWS_CLIENT_01_380: [ If an WebSocket Upgrade request can be parsed from the accumulated bytes, the status shall be read from the WebSocket upgrade response. ]*/
1163 /* Codes_SRS_UWS_CLIENT_01_381: [ If the status is 101, uws shall be considered OPEN and this shall be indicated by calling the on_ws_open_complete callback passed to uws_client_open_async with IO_OPEN_OK. ]*/
1164 if ((uws_client->stream_buffer_count >= 4) &&
1165 ((request_end_ptr = strstr((const char*)uws_client->stream_buffer, "\r\n\r\n")) != NULL))
1166 {
1167 int status_code;
1168
1169 /* This part should really be done with the HTTPAPI, but that has to be done as a separate step
1170 as the HTTPAPI has to expose somehow the underlying IO and currently this would be a too big of a change. */
1171
1172 /* Codes_SRS_UWS_CLIENT_01_382: [ If a negative status is decoded from the WebSocket upgrade request, an error shall be indicated by calling the on_ws_open_complete callback passed to uws_client_open_async with WS_OPEN_ERROR_BAD_RESPONSE_STATUS. ]*/
1173 /* Codes_SRS_UWS_CLIENT_01_478: [ A Status-Line with a 101 response code as per RFC 2616 [RFC2616]. ]*/
1174 if (ParseHttpResponse((const char*)uws_client->stream_buffer, &status_code) != 0)
1175 {
1176 /* Codes_SRS_UWS_CLIENT_01_383: [ If the WebSocket upgrade request cannot be decoded an error shall be indicated by calling the on_ws_open_complete callback passed to uws_client_open_async with WS_OPEN_ERROR_BAD_UPGRADE_RESPONSE. ]*/
1177 LogError("Cannot decode HTTP response");
1178 indicate_ws_open_complete_error_and_close(uws_client, WS_OPEN_ERROR_BAD_UPGRADE_RESPONSE);
1179 }
1180 else if (status_code != 101)
1181 {
1182 /* Codes_SRS_UWS_CLIENT_01_382: [ If a negative status is decoded from the WebSocket upgrade request, an error shall be indicated by calling the on_ws_open_complete callback passed to uws_client_open_async with WS_OPEN_ERROR_BAD_RESPONSE_STATUS. ]*/
1183 LogError("Bad status (%d) received in WebSocket Upgrade response", status_code);
1184 indicate_ws_open_complete_error_and_close(uws_client, WS_OPEN_ERROR_BAD_RESPONSE_STATUS);
1185 }
1186 else
1187 {
1188 /* Codes_SRS_UWS_CLIENT_01_384: [ Any extra bytes that are left unconsumed after decoding a succesfull WebSocket upgrade response shall be used for decoding WebSocket frames ]*/
1189 consume_stream_buffer_bytes(uws_client, request_end_ptr - (char*)uws_client->stream_buffer + 4);
1190
1191 /* Codes_SRS_UWS_CLIENT_01_381: [ If the status is 101, uws shall be considered OPEN and this shall be indicated by calling the on_ws_open_complete callback passed to uws_client_open_async with IO_OPEN_OK. ]*/
1192 uws_client->uws_state = UWS_STATE_OPEN;
1193
1194 /* Codes_SRS_UWS_CLIENT_01_065: [ When the client is to _Establish a WebSocket Connection_ given a set of (/host/, /port/, /resource name/, and /secure/ flag), along with a list of /protocols/ and /extensions/ to be used, and an /origin/ in the case of web browsers, it MUST open a connection, send an opening handshake, and read the server's handshake in response. ]*/
1195 /* Codes_SRS_UWS_CLIENT_01_115: [ If the server's response is validated as provided for above, it is said that _The WebSocket Connection is Established_ and that the WebSocket Connection is in the OPEN state. ]*/
1196 uws_client->on_ws_open_complete(uws_client->on_ws_open_complete_context, WS_OPEN_OK);
1197
1198 decode_stream = 1;
1199 }
1200 }
1201
1202 break;
1203 }
1204
1205 case UWS_STATE_OPEN:
1206 case UWS_STATE_CLOSING_WAITING_FOR_CLOSE:
1207 {
1208 size_t needed_bytes = 2;
1209 size_t length;
1210
1211 /* Codes_SRS_UWS_CLIENT_01_277: [ To receive WebSocket data, an endpoint listens on the underlying network connection. ]*/
1212 /* Codes_SRS_UWS_CLIENT_01_278: [ Incoming data MUST be parsed as WebSocket frames as defined in Section 5.2. ]*/
1213 if (uws_client->stream_buffer_count >= needed_bytes)
1214 {
1215 unsigned char has_error = 0;
1216
1217 /* Codes_SRS_UWS_CLIENT_01_160: [ Defines whether the "Payload data" is masked. ]*/
1218 if ((uws_client->stream_buffer[1] & 0x80) != 0)
1219 {
1220 /* Codes_SRS_UWS_CLIENT_01_144: [ A client MUST close a connection if it detects a masked frame. ]*/
1221 /* Codes_SRS_UWS_CLIENT_01_145: [ In this case, it MAY use the status code 1002 (protocol error) as defined in Section 7.4.1. (These rules might be relaxed in a future specification.) ]*/
1222 LogError("Masked frame detected by WebSocket client");
1223 indicate_ws_error_and_close(uws_client, WS_ERROR_BAD_FRAME_RECEIVED, 1002);
1224 }
1225
1226 /* Codes_SRS_UWS_CLIENT_01_163: [ The length of the "Payload data", in bytes: ]*/
1227 /* Codes_SRS_UWS_CLIENT_01_164: [ if 0-125, that is the payload length. ]*/
1228 length = uws_client->stream_buffer[1];
1229
1230 if (length == 126)
1231 {
1232 /* Codes_SRS_UWS_CLIENT_01_165: [ If 126, the following 2 bytes interpreted as a 16-bit unsigned integer are the payload length. ]*/
1233 needed_bytes += 2;
1234 if (uws_client->stream_buffer_count >= needed_bytes)
1235 {
1236 /* Codes_SRS_UWS_CLIENT_01_167: [ Multibyte length quantities are expressed in network byte order. ]*/
1237 length = ((size_t)(uws_client->stream_buffer[2]) << 8) + (size_t)uws_client->stream_buffer[3];
1238
1239 if (length < 126)
1240 {
1241 /* Codes_SRS_UWS_CLIENT_01_168: [ Note that in all cases, the minimal number of bytes MUST be used to encode the length, for example, the length of a 124-byte-long string can't be encoded as the sequence 126, 0, 124. ]*/
1242 LogError("Bad frame: received a %u length on the 16 bit length", (unsigned int)length);
1243
1244 /* Codes_SRS_UWS_CLIENT_01_419: [ If there is an error decoding the WebSocket frame, an error shall be indicated by calling the on_ws_error callback with WS_ERROR_BAD_FRAME_RECEIVED. ]*/
1245 indicate_ws_error(uws_client, WS_ERROR_BAD_FRAME_RECEIVED);
1246 has_error = 1;
1247 }
1248 else
1249 {
1250 needed_bytes += (size_t)length;
1251 }
1252 }
1253 }
1254 else if (length == 127)
1255 {
1256 /* Codes_SRS_UWS_CLIENT_01_166: [ If 127, the following 8 bytes interpreted as a 64-bit unsigned integer (the most significant bit MUST be 0) are the payload length. ]*/
1257 needed_bytes += 8;
1258 if (uws_client->stream_buffer_count >= needed_bytes)
1259 {
1260 if ((uws_client->stream_buffer[2] & 0x80) != 0)
1261 {
1262 LogError("Bad frame: received a 64 bit length frame with the highest bit set");
1263
1264 /* Codes_SRS_UWS_CLIENT_01_419: [ If there is an error decoding the WebSocket frame, an error shall be indicated by calling the on_ws_error callback with WS_ERROR_BAD_FRAME_RECEIVED. ]*/
1265 indicate_ws_error(uws_client, WS_ERROR_BAD_FRAME_RECEIVED);
1266 has_error = 1;
1267 }
1268 else
1269 {
1270 /* Codes_SRS_UWS_CLIENT_01_167: [ Multibyte length quantities are expressed in network byte order. ]*/
1271 length = (size_t)(((uint64_t)(uws_client->stream_buffer[2]) << 56) +
1272 (((uint64_t)uws_client->stream_buffer[3]) << 48) +
1273 (((uint64_t)uws_client->stream_buffer[4]) << 40) +
1274 (((uint64_t)uws_client->stream_buffer[5]) << 32) +
1275 (((uint64_t)uws_client->stream_buffer[6]) << 24) +
1276 (((uint64_t)uws_client->stream_buffer[7]) << 16) +
1277 (((uint64_t)uws_client->stream_buffer[8]) << 8) +
1278 (uint64_t)(uws_client->stream_buffer[9]));
1279
1280 if (length < 65536)
1281 {
1282 /* Codes_SRS_UWS_CLIENT_01_168: [ Note that in all cases, the minimal number of bytes MUST be used to encode the length, for example, the length of a 124-byte-long string can't be encoded as the sequence 126, 0, 124. ]*/
1283 LogError("Bad frame: received a %u length on the 64 bit length", (unsigned int)length);
1284
1285 /* Codes_SRS_UWS_CLIENT_01_419: [ If there is an error decoding the WebSocket frame, an error shall be indicated by calling the on_ws_error callback with WS_ERROR_BAD_FRAME_RECEIVED. ]*/
1286 indicate_ws_error(uws_client, WS_ERROR_BAD_FRAME_RECEIVED);
1287 has_error = 1;
1288 }
1289 else
1290 {
1291 needed_bytes += length;
1292 }
1293 }
1294 }
1295 }
1296 else
1297 {
1298 needed_bytes += length;
1299 }
1300
1301 if ((has_error == 0) &&
1302 (uws_client->stream_buffer_count >= needed_bytes))
1303 {
1304 unsigned char opcode = uws_client->stream_buffer[0] & 0xF;
1305
1306 /* Codes_SRS_UWS_CLIENT_01_147: [ Indicates that this is the final fragment in a message. ]*/
1307 bool is_final = (uws_client->stream_buffer[0] & 0x80) != 0;
1308
1309 switch (opcode)
1310 {
1311 default:
1312 break;
1313 /* Codes_SRS_UWS_CLIENT_01_152: [* * %x0 denotes a continuation frame *]*/
1314 case (unsigned char)WS_CONTINUATION_FRAME:
1315 {
1316 /* Codes_SRS_UWS_CLIENT_01_213: [ A fragmented message consists of a single frame with the FIN bit clear and an opcode other than 0, followed by zero or more frames with the FIN bit clear and the opcode set to 0, and terminated by a single frame with the FIN bit set and an opcode of 0. ]*/
1317 /* Codes_SRS_UWS_CLIENT_01_216: [ Message fragments MUST be delivered to the recipient in the order sent by the sender. ]*/
1318 /* Codes_SRS_UWS_CLIENT_01_219: [ A sender MAY create fragments of any size for non-control messages. ]*/
1319 if (process_frame_fragment(uws_client, length, needed_bytes) != 0)
1320 {
1321 break;
1322 }
1323
1324 if (is_final)
1325 {
1326 /* Codes_SRS_UWS_CLIENT_01_225: [ As a consequence of these rules, all fragments of a message are of the same type, as set by the first fragment's opcode. ]*/
1327 if (uws_client->fragmented_frame_type == WS_FRAME_TYPE_UNKNOWN)
1328 {
1329 LogError("Continuation fragment received without initial fragment specifying frame data type");
1330 indicate_ws_error(uws_client, WS_ERROR_BAD_FRAME_RECEIVED);
1331 decode_stream = 1;
1332 break;
1333 }
1334 uws_client->on_ws_frame_received(uws_client->on_ws_frame_received_context, uws_client->fragmented_frame_type, uws_client->fragment_buffer, uws_client->fragment_buffer_count);
1335 uws_client->fragment_buffer_count = 0;
1336 uws_client->fragmented_frame_type = WS_FRAME_TYPE_UNKNOWN;
1337 }
1338 decode_stream = 1;
1339 break;
1340 }
1341 /* Codes_SRS_UWS_CLIENT_01_153: [ * %x1 denotes a text frame ]*/
1342 /* Codes_SRS_UWS_CLIENT_01_258: [** Currently defined opcodes for data frames include 0x1 (Text), 0x2 (Binary). ]*/
1343 case (unsigned char)WS_TEXT_FRAME:
1344 {
1345 /* Codes_SRS_UWS_CLIENT_01_386: [ When a WebSocket data frame is decoded succesfully it shall be indicated via the callback on_ws_frame_received. ]*/
1346 /* Codes_SRS_UWS_CLIENT_01_169: [ The payload length is the length of the "Extension data" + the length of the "Application data". ]*/
1347 /* Codes_SRS_UWS_CLIENT_01_173: [ The "Payload data" is defined as "Extension data" concatenated with "Application data". ]*/
1348 /* Codes_SRS_UWS_CLIENT_01_280: [ Upon receiving a data frame (Section 5.6), the endpoint MUST note the /type/ of the data as defined by the opcode (frame-opcode) from Section 5.2. ]*/
1349 /* Codes_SRS_UWS_CLIENT_01_281: [ The "Application data" from this frame is defined as the /data/ of the message. ]*/
1350 /* Codes_SRS_UWS_CLIENT_01_282: [ If the frame comprises an unfragmented message (Section 5.4), it is said that _A WebSocket Message Has Been Received_ with type /type/ and data /data/. ]*/
1351 if (is_final)
1352 {
1353 uws_client->on_ws_frame_received(uws_client->on_ws_frame_received_context, WS_FRAME_TYPE_TEXT, uws_client->stream_buffer + needed_bytes - length, length);
1354 }
1355 else
1356 {
1357 /* Codes_SRS_UWS_CLIENT_01_217: [ The fragments of one message MUST NOT be interleaved between the fragments of another message unless an extension has been negotiated that can interpret the interleaving. ]*/
1358 if (uws_client->fragmented_frame_type != WS_FRAME_TYPE_UNKNOWN)
1359 {
1360 LogError("Fragmented frame received interleaved between the fragments of another message");
1361 indicate_ws_error(uws_client, WS_ERROR_BAD_FRAME_RECEIVED);
1362 decode_stream = 1;
1363 break;
1364 }
1365 /* Codes_SRS_UWS_CLIENT_01_213: [ A fragmented message consists of a single frame with the FIN bit clear and an opcode other than 0, followed by zero or more frames with the FIN bit clear and the opcode set to 0, and terminated by a single frame with the FIN bit set and an opcode of 0. ]*/
1366 /* Codes_SRS_UWS_CLIENT_01_216: [ Message fragments MUST be delivered to the recipient in the order sent by the sender. ]*/
1367 /* Codes_SRS_UWS_CLIENT_01_219: [ A sender MAY create fragments of any size for non-control messages. ]*/
1368 if (process_frame_fragment(uws_client, length, needed_bytes) != 0)
1369 {
1370 break;
1371 }
1372
1373 /* Codes_SRS_UWS_CLIENT_01_225: [ As a consequence of these rules, all fragments of a message are of the same type, as set by the first fragment's opcode. ]*/
1374 /* Codes_SRS_UWS_CLIENT_01_226: [ Since control frames cannot be fragmented, the type for all fragments in a message MUST be either text, binary, or one of the reserved opcodes. ]*/
1375 uws_client->fragmented_frame_type = WS_FRAME_TYPE_TEXT;
1376 }
1377 decode_stream = 1;
1378 break;
1379 }
1380
1381 /* Codes_SRS_UWS_CLIENT_01_154: [ * %x2 denotes a binary frame ]*/
1382 case (unsigned char)WS_BINARY_FRAME:
1383 {
1384 /* Codes_SRS_UWS_CLIENT_01_386: [ When a WebSocket data frame is decoded succesfully it shall be indicated via the callback on_ws_frame_received. ]*/
1385 /* Codes_SRS_UWS_CLIENT_01_169: [ The payload length is the length of the "Extension data" + the length of the "Application data". ]*/
1386 /* Codes_SRS_UWS_CLIENT_01_173: [ The "Payload data" is defined as "Extension data" concatenated with "Application data". ]*/
1387 /* Codes_SRS_UWS_CLIENT_01_264: [ The "Payload data" is arbitrary binary data whose interpretation is solely up to the application layer. ]*/
1388 /* Codes_SRS_UWS_CLIENT_01_280: [ Upon receiving a data frame (Section 5.6), the endpoint MUST note the /type/ of the data as defined by the opcode (frame-opcode) from Section 5.2. ]*/
1389 /* Codes_SRS_UWS_CLIENT_01_281: [ The "Application data" from this frame is defined as the /data/ of the message. ]*/
1390 /* Codes_SRS_UWS_CLIENT_01_282: [ If the frame comprises an unfragmented message (Section 5.4), it is said that _A WebSocket Message Has Been Received_ with type /type/ and data /data/. ]*/
1391 if (is_final)
1392 {
1393 uws_client->on_ws_frame_received(uws_client->on_ws_frame_received_context, WS_FRAME_TYPE_BINARY, uws_client->stream_buffer + needed_bytes - length, length);
1394 }
1395 else
1396 {
1397 /* Codes_SRS_UWS_CLIENT_01_217: [ The fragments of one message MUST NOT be interleaved between the fragments of another message unless an extension has been negotiated that can interpret the interleaving. ]*/
1398 if (uws_client->fragmented_frame_type != WS_FRAME_TYPE_UNKNOWN)
1399 {
1400 LogError("Fragmented frame received interleaved between the fragments of another message");
1401 indicate_ws_error(uws_client, WS_ERROR_BAD_FRAME_RECEIVED);
1402 decode_stream = 1;
1403 break;
1404 }
1405 /* Codes_SRS_UWS_CLIENT_01_213: [ A fragmented message consists of a single frame with the FIN bit clear and an opcode other than 0, followed by zero or more frames with the FIN bit clear and the opcode set to 0, and terminated by a single frame with the FIN bit set and an opcode of 0. ]*/
1406 /* Codes_SRS_UWS_CLIENT_01_216: [ Message fragments MUST be delivered to the recipient in the order sent by the sender. ]*/
1407 /* Codes_SRS_UWS_CLIENT_01_219: [ A sender MAY create fragments of any size for non-control messages. ]*/
1408 if (process_frame_fragment(uws_client, length, needed_bytes) != 0)
1409 {
1410 break;
1411 }
1412
1413 /* Codes_SRS_UWS_CLIENT_01_225: [ As a consequence of these rules, all fragments of a message are of the same type, as set by the first fragment's opcode. ]*/
1414 /* Codes_SRS_UWS_CLIENT_01_226: [ Since control frames cannot be fragmented, the type for all fragments in a message MUST be either text, binary, or one of the reserved opcodes. ]*/
1415 uws_client->fragmented_frame_type = WS_FRAME_TYPE_BINARY;
1416 }
1417 decode_stream = 1;
1418 break;
1419 }
1420
1421 /* Codes_SRS_UWS_CLIENT_01_156: [ * %x8 denotes a connection close ]*/
1422 /* Codes_SRS_UWS_CLIENT_01_234: [ The Close frame contains an opcode of 0x8. ]*/
1423 /* Codes_SRS_UWS_CLIENT_01_214: [ Control frames (see Section 5.5) MAY be injected in the middle of a fragmented message. ]*/
1424 case (unsigned char)WS_CLOSE_FRAME:
1425 {
1426 uint16_t close_code;
1427 uint16_t* close_code_ptr;
1428 const unsigned char* data_ptr = uws_client->stream_buffer + needed_bytes - length;
1429 const unsigned char* extra_data_ptr;
1430 size_t extra_data_length;
1431 unsigned char* close_frame_bytes;
1432 size_t close_frame_length;
1433 bool utf8_error = false;
1434
1435 /* Codes_SRS_UWS_CLIENT_01_215: [ Control frames themselves MUST NOT be fragmented. ]*/
1436 if (!is_final)
1437 {
1438 LogError("Fragmented control frame received.");
1439 indicate_ws_error(uws_client, WS_ERROR_BAD_FRAME_RECEIVED);
1440 break;
1441 }
1442
1443 /* Codes_SRS_UWS_CLIENT_01_235: [ The Close frame MAY contain a body (the "Application data" portion of the frame) that indicates a reason for closing, such as an endpoint shutting down, an endpoint having received a frame too large, or an endpoint having received a frame that does not conform to the format expected by the endpoint. ]*/
1444 if (length >= 2)
1445 {
1446 /* Codes_SRS_UWS_CLIENT_01_236: [ If there is a body, the first two bytes of the body MUST be a 2-byte unsigned integer (in network byte order) representing a status code with value /code/ defined in Section 7.4. ]*/
1447 close_code = (data_ptr[0] << 8) + data_ptr[1];
1448
1449 /* Codes_SRS_UWS_CLIENT_01_461: [ The argument close_code shall be set to point to the code extracted from the CLOSE frame. ]*/
1450 close_code_ptr = &close_code;
1451 }
1452 else
1453 {
1454 /* Codes_SRS_UWS_CLIENT_01_462: [ If no code can be extracted then close_code shall be NULL. ]*/
1455 close_code_ptr = NULL;
1456 }
1457
1458 if (length > 2)
1459 {
1460 /* Codes_SRS_UWS_CLIENT_01_463: [ The extra bytes (besides the close code) shall be passed to the on_ws_peer_closed callback by using extra_data and extra_data_length. ]*/
1461 extra_data_ptr = data_ptr + 2;
1462 extra_data_length = length - 2;
1463
1464 /* Codes_SRS_UWS_CLIENT_01_238: [ As the data is not guaranteed to be human readable, clients MUST NOT show it to end users. ]*/
1465 /* Codes_SRS_UWS_CLIENT_01_237: [ Following the 2-byte integer, the body MAY contain UTF-8-encoded data with value /reason/, the interpretation of which is not defined by this specification. ]*/
1466 if (utf8_checker_is_valid_utf8(extra_data_ptr, extra_data_length) != true)
1467 {
1468 LogError("Reason in CLOSE frame is not UTF-8.");
1469 extra_data_ptr = NULL;
1470 extra_data_length = 0;
1471 utf8_error = true;
1472 }
1473 }
1474 else
1475 {
1476 extra_data_ptr = NULL;
1477 extra_data_length = 0;
1478 }
1479
1480 if (utf8_error)
1481 {
1482 uws_client->uws_state = UWS_STATE_CLOSING_UNDERLYING_IO;
1483 if (xio_close(uws_client->underlying_io, on_underlying_io_close_complete, uws_client) != 0)
1484 {
1485 LogError("Could not close underlying IO");
1486 indicate_ws_error(uws_client, WS_ERROR_CANNOT_CLOSE_UNDERLYING_IO);
1487 uws_client->uws_state = UWS_STATE_CLOSED;
1488 }
1489 }
1490 else
1491 {
1492 BUFFER_HANDLE close_frame_buffer;
1493
1494 if (uws_client->uws_state == UWS_STATE_CLOSING_WAITING_FOR_CLOSE)
1495 {
1496 uws_client->uws_state = UWS_STATE_CLOSING_UNDERLYING_IO;
1497 if (xio_close(uws_client->underlying_io, on_underlying_io_close_complete, uws_client) != 0)
1498 {
1499 indicate_ws_close_complete(uws_client);
1500 uws_client->uws_state = UWS_STATE_CLOSED;
1501 }
1502 }
1503 else
1504 {
1505 /* Codes_SRS_UWS_CLIENT_01_296: [ Upon either sending or receiving a Close control frame, it is said that _The WebSocket Closing Handshake is Started_ and that the WebSocket connection is in the CLOSING state. ]*/
1506 /* Codes_SRS_UWS_CLIENT_01_240: [ The application MUST NOT send any more data frames after sending a Close frame. ]*/
1507 uws_client->uws_state = UWS_STATE_CLOSING_SENDING_CLOSE;
1508 }
1509
1510 /* Codes_SRS_UWS_CLIENT_01_241: [ If an endpoint receives a Close frame and did not previously send a Close frame, the endpoint MUST send a Close frame in response. ]*/
1511 /* Codes_SRS_UWS_CLIENT_01_242: [ It SHOULD do so as soon as practical. ]*/
1512 /* Codes_SRS_UWS_CLIENT_01_239: [ Close frames sent from client to server must be masked as per Section 5.3. ]*/
1513 /* Codes_SRS_UWS_CLIENT_01_140: [ To avoid confusing network intermediaries (such as intercepting proxies) and for security reasons that are further discussed in Section 10.3, a client MUST mask all frames that it sends to the server (see Section 5.3 for further details). ]*/
1514 close_frame_buffer = uws_frame_encoder_encode(WS_CLOSE_FRAME, NULL, 0, true, true, 0);
1515 if (close_frame_buffer == NULL)
1516 {
1517 LogError("Cannot encode the response CLOSE frame");
1518
1519 /* Codes_SRS_UWS_CLIENT_01_288: [ To _Close the WebSocket Connection_, an endpoint closes the underlying TCP connection. ]*/
1520 /* Codes_SRS_UWS_CLIENT_01_290: [ An endpoint MAY close the connection via any means available when necessary, such as when under attack. ]*/
1521 uws_client->uws_state = UWS_STATE_CLOSING_UNDERLYING_IO;
1522 if (xio_close(uws_client->underlying_io, on_underlying_io_close_complete, uws_client) != 0)
1523 {
1524 indicate_ws_error(uws_client, WS_ERROR_CANNOT_CLOSE_UNDERLYING_IO);
1525 uws_client->uws_state = UWS_STATE_CLOSED;
1526 }
1527 }
1528 else
1529 {
1530 close_frame_bytes = BUFFER_u_char(close_frame_buffer);
1531 close_frame_length = BUFFER_length(close_frame_buffer);
1532 if (xio_send(uws_client->underlying_io, close_frame_bytes, close_frame_length, on_underlying_io_close_sent, uws_client) != 0)
1533 {
1534 LogError("Cannot send the response CLOSE frame");
1535
1536 /* Codes_SRS_UWS_CLIENT_01_288: [ To _Close the WebSocket Connection_, an endpoint closes the underlying TCP connection. ]*/
1537 /* Codes_SRS_UWS_CLIENT_01_290: [ An endpoint MAY close the connection via any means available when necessary, such as when under attack. ]*/
1538 uws_client->uws_state = UWS_STATE_CLOSING_UNDERLYING_IO;
1539 if (xio_close(uws_client->underlying_io, on_underlying_io_close_complete, uws_client) != 0)
1540 {
1541 indicate_ws_error(uws_client, WS_ERROR_CANNOT_CLOSE_UNDERLYING_IO);
1542 uws_client->uws_state = UWS_STATE_CLOSED;
1543 }
1544 }
1545
1546 BUFFER_delete(close_frame_buffer);
1547 }
1548 }
1549
1550 /* Codes_SRS_UWS_CLIENT_01_460: [ When a CLOSE frame is received the callback on_ws_peer_closed passed to uws_client_open_async shall be called, while passing to it the argument on_ws_peer_closed_context. ]*/
1551 uws_client->on_ws_peer_closed(uws_client->on_ws_peer_closed_context, close_code_ptr, extra_data_ptr, extra_data_length);
1552
1553 break;
1554 }
1555
1556 /* Codes_SRS_UWS_CLIENT_01_157: [ * %x9 denotes a ping ]*/
1557 /* Codes_SRS_UWS_CLIENT_01_247: [ The Ping frame contains an opcode of 0x9. ]*/
1558 /* Codes_SRS_UWS_CLIENT_01_251: [ An endpoint MAY send a Ping frame any time after the connection is established and before the connection is closed. ]*/
1559 /* Codes_SRS_UWS_CLIENT_01_214: [ Control frames (see Section 5.5) MAY be injected in the middle of a fragmented message. ]*/
1560 case (unsigned char)WS_PING_FRAME:
1561 {
1562 /* Codes_SRS_UWS_CLIENT_01_249: [ Upon receipt of a Ping frame, an endpoint MUST send a Pong frame in response ]*/
1563 /* Codes_SRS_UWS_CLIENT_01_250: [ It SHOULD respond with Pong frame as soon as is practical. ]*/
1564 unsigned char* pong_frame;
1565 size_t pong_frame_length;
1566 BUFFER_HANDLE pong_frame_buffer;
1567
1568 /* Codes_SRS_UWS_CLIENT_01_215: [ Control frames themselves MUST NOT be fragmented. ]*/
1569 if (!is_final)
1570 {
1571 LogError("Fragmented control frame received.");
1572 indicate_ws_error(uws_client, WS_ERROR_BAD_FRAME_RECEIVED);
1573 break;
1574 }
1575
1576 /* Codes_SRS_UWS_CLIENT_01_140: [ To avoid confusing network intermediaries (such as intercepting proxies) and for security reasons that are further discussed in Section 10.3, a client MUST mask all frames that it sends to the server (see Section 5.3 for further details). ]*/
1577 pong_frame_buffer = uws_frame_encoder_encode(WS_PONG_FRAME, uws_client->stream_buffer + needed_bytes - length, length, true, true, 0);
1578 if (pong_frame_buffer == NULL)
1579 {
1580 LogError("Encoding of PONG failed.");
1581 }
1582 else
1583 {
1584 /* Codes_SRS_UWS_CLIENT_01_248: [ A Ping frame MAY include "Application data". ]*/
1585 pong_frame = BUFFER_u_char(pong_frame_buffer);
1586 pong_frame_length = BUFFER_length(pong_frame_buffer);
1587 if (xio_send(uws_client->underlying_io, pong_frame, pong_frame_length, unchecked_on_send_complete, NULL) != 0)
1588 {
1589 LogError("Sending PONG frame failed.");
1590 }
1591
1592 BUFFER_delete(pong_frame_buffer);
1593 }
1594
1595 break;
1596 }
1597 /* Codes_SRS_UWS_CLIENT_01_252: [ The Pong frame contains an opcode of 0xA. ]*/
1598 case (unsigned char)WS_PONG_FRAME:
1599 break;
1600 }
1601
1602 consume_stream_buffer_bytes(uws_client, needed_bytes);
1603 }
1604 }
1605
1606 break;
1607 }
1608 }
1609 }
1610 }
1611 }
1612}
1613
1614static void on_underlying_io_error(void* context)
1615{
1616 UWS_CLIENT_HANDLE uws_client = (UWS_CLIENT_HANDLE)context;
1617
1618 switch (uws_client->uws_state)
1619 {
1620 default:
1621 break;
1622
1623 case UWS_STATE_CLOSING_WAITING_FOR_CLOSE:
1624 case UWS_STATE_CLOSING_SENDING_CLOSE:
1625 case UWS_STATE_CLOSING_UNDERLYING_IO:
1626 /* Codes_SRS_UWS_CLIENT_01_500: [ The callback on_ws_close_complete shall be called, while passing the on_ws_close_complete_context argument to it. ]*/
1627 /* Codes_SRS_UWS_CLIENT_01_377: [ When on_underlying_io_error is called while the uws instance is CLOSING the underlying IO shall be closed by calling xio_close. ]*/
1628 (void)xio_close(uws_client->underlying_io, NULL, NULL);
1629
1630 /* Codes_SRS_UWS_CLIENT_01_499: [ If the CLOSE was due to the peer closing, the callback on_ws_close_complete shall not be called. ]*/
1631 indicate_ws_close_complete(uws_client);
1632 break;
1633
1634 case UWS_STATE_OPENING_UNDERLYING_IO:
1635 case UWS_STATE_WAITING_FOR_UPGRADE_RESPONSE:
1636 /* Codes_SRS_UWS_CLIENT_01_375: [ When on_underlying_io_error is called while uws is OPENING, uws shall report that the open failed by calling the on_ws_open_complete callback passed to uws_client_open_async with WS_OPEN_ERROR_UNDERLYING_IO_ERROR. ]*/
1637 /* Codes_SRS_UWS_CLIENT_01_077: [ If this fails (e.g., the server's certificate could not be verified), then the client MUST _Fail the WebSocket Connection_ and abort the connection. ]*/
1638 indicate_ws_open_complete_error_and_close(uws_client, WS_OPEN_ERROR_UNDERLYING_IO_ERROR);
1639 break;
1640
1641 case UWS_STATE_OPEN:
1642 /* Codes_SRS_UWS_CLIENT_01_376: [ When on_underlying_io_error is called while the uws instance is OPEN, an error shall be reported to the user by calling the on_ws_error callback that was passed to uws_client_open_async with the argument WS_ERROR_UNDERLYING_IO_ERROR. ]*/
1643 /* Codes_SRS_UWS_CLIENT_01_318: [ Servers MAY close the WebSocket connection whenever desired. ]*/
1644 /* Codes_SRS_UWS_CLIENT_01_269: [ If at any point the state of the WebSocket connection changes, the endpoint MUST abort the following steps. ]*/
1645 indicate_ws_error(uws_client, WS_ERROR_UNDERLYING_IO_ERROR);
1646 break;
1647 }
1648}
1649
1650int uws_client_open_async(UWS_CLIENT_HANDLE uws_client, ON_WS_OPEN_COMPLETE on_ws_open_complete, void* on_ws_open_complete_context, ON_WS_FRAME_RECEIVED on_ws_frame_received, void* on_ws_frame_received_context, ON_WS_PEER_CLOSED on_ws_peer_closed, void* on_ws_peer_closed_context, ON_WS_ERROR on_ws_error, void* on_ws_error_context)
1651{
1652 int result;
1653
1654 /* Codes_SRS_UWS_CLIENT_01_393: [ The context arguments for the callbacks shall be allowed to be NULL. ]*/
1655 if ((uws_client == NULL) ||
1656 (on_ws_open_complete == NULL) ||
1657 (on_ws_frame_received == NULL) ||
1658 (on_ws_peer_closed == NULL) ||
1659 (on_ws_error == NULL))
1660 {
1661 /* Codes_SRS_UWS_CLIENT_01_027: [ If uws_client, on_ws_open_complete, on_ws_frame_received, on_ws_peer_closed or on_ws_error is NULL, uws_client_open_async shall fail and return a non-zero value. ]*/
1662 LogError("Invalid arguments: uws=%p, on_ws_open_complete=%p, on_ws_frame_received=%p, on_ws_error=%p",
1663 uws_client, on_ws_open_complete, on_ws_frame_received, on_ws_error);
1664 result = MU_FAILURE;
1665 }
1666 else
1667 {
1668 if (uws_client->uws_state != UWS_STATE_CLOSED)
1669 {
1670 /* Codes_SRS_UWS_CLIENT_01_400: [ uws_client_open_async while CLOSING shall fail and return a non-zero value. ]*/
1671 /* Codes_SRS_UWS_CLIENT_01_394: [ uws_client_open_async while the uws instance is already OPEN or OPENING shall fail and return a non-zero value. ]*/
1672 LogError("Invalid uWS state while trying to open: %d", (int)uws_client->uws_state);
1673 result = MU_FAILURE;
1674 }
1675 else
1676 {
1677 uws_client->uws_state = UWS_STATE_OPENING_UNDERLYING_IO;
1678
1679 uws_client->stream_buffer_count = 0;
1680 uws_client->fragment_buffer_count = 0;
1681 uws_client->fragmented_frame_type = WS_FRAME_TYPE_UNKNOWN;
1682
1683 uws_client->on_ws_open_complete = on_ws_open_complete;
1684 uws_client->on_ws_open_complete_context = on_ws_open_complete_context;
1685 uws_client->on_ws_frame_received = on_ws_frame_received;
1686 uws_client->on_ws_frame_received_context = on_ws_frame_received_context;
1687 uws_client->on_ws_peer_closed = on_ws_peer_closed;
1688 uws_client->on_ws_peer_closed_context = on_ws_peer_closed_context;
1689 uws_client->on_ws_error = on_ws_error;
1690 uws_client->on_ws_error_context = on_ws_error_context;
1691
1692 /* Codes_SRS_UWS_CLIENT_01_025: [ uws_client_open_async shall open the underlying IO by calling xio_open and providing the IO handle created in uws_client_create as argument. ]*/
1693 /* Codes_SRS_UWS_CLIENT_01_367: [ The callbacks on_underlying_io_open_complete, on_underlying_io_bytes_received and on_underlying_io_error shall be passed as arguments to xio_open. ]*/
1694 /* Codes_SRS_UWS_CLIENT_01_061: [ To _Establish a WebSocket Connection_, a client opens a connection and sends a handshake as defined in this section. ]*/
1695 if (xio_open(uws_client->underlying_io, on_underlying_io_open_complete, uws_client, on_underlying_io_bytes_received, uws_client, on_underlying_io_error, uws_client) != 0)
1696 {
1697 /* Codes_SRS_UWS_CLIENT_01_028: [ If opening the underlying IO fails then uws_client_open_async shall fail and return a non-zero value. ]*/
1698 /* Codes_SRS_UWS_CLIENT_01_075: [ If the connection could not be opened, either because a direct connection failed or because any proxy used returned an error, then the client MUST _Fail the WebSocket Connection_ and abort the connection attempt. ]*/
1699 LogError("Opening the underlying IO failed");
1700 uws_client->uws_state = UWS_STATE_CLOSED;
1701 result = MU_FAILURE;
1702 }
1703 else
1704 {
1705 /* Codes_SRS_UWS_CLIENT_01_026: [ On success, uws_client_open_async shall return 0. ]*/
1706 result = 0;
1707 }
1708 }
1709 }
1710
1711 return result;
1712}
1713
1714static int complete_send_frame(WS_PENDING_SEND* ws_pending_send, LIST_ITEM_HANDLE pending_send_frame_item, WS_SEND_FRAME_RESULT ws_send_frame_result)
1715{
1716 int result;
1717 UWS_CLIENT_INSTANCE* uws_client = ws_pending_send->uws_client;
1718
1719 /* Codes_SRS_UWS_CLIENT_01_432: [ The indicated sent frame shall be removed from the list by calling singlylinkedlist_remove. ]*/
1720 if (singlylinkedlist_remove(uws_client->pending_sends, pending_send_frame_item) != 0)
1721 {
1722 LogError("Failed removing item from list");
1723 result = MU_FAILURE;
1724 }
1725 else
1726 {
1727 if (ws_pending_send->on_ws_send_frame_complete != NULL)
1728 {
1729 /* Codes_SRS_UWS_CLIENT_01_037: [ When indicating pending send frames as cancelled the callback context passed to the on_ws_send_frame_complete callback shall be the context given to uws_client_send_frame_async. ]*/
1730 ws_pending_send->on_ws_send_frame_complete(ws_pending_send->context, ws_send_frame_result);
1731 }
1732
1733 /* Codes_SRS_UWS_CLIENT_01_434: [ The memory associated with the sent frame shall be freed. ]*/
1734 free(ws_pending_send);
1735
1736 result = 0;
1737 }
1738
1739 return result;
1740}
1741
1742/* Codes_SRS_UWS_CLIENT_01_029: [ uws_client_close_async shall close the uws instance connection if an open action is either pending or has completed successfully (if the IO is open). ]*/
1743/* Codes_SRS_UWS_CLIENT_01_317: [ Clients SHOULD NOT close the WebSocket connection arbitrarily. ]*/
1744int uws_client_close_async(UWS_CLIENT_HANDLE uws_client, ON_WS_CLOSE_COMPLETE on_ws_close_complete, void* on_ws_close_complete_context)
1745{
1746 int result;
1747
1748 /* Codes_SRS_UWS_CLIENT_01_397: [ The on_ws_close_complete argument shall be allowed to be NULL, in which case no callback shall be called when the close is complete. ]*/
1749 /* Codes_SRS_UWS_CLIENT_01_398: [ on_ws_close_complete_context shall also be allows to be NULL. ]*/
1750 if (uws_client == NULL)
1751 {
1752 /* Codes_SRS_UWS_CLIENT_01_030: [ if uws_client is NULL, uws_client_close_async shall return a non-zero value. ]*/
1753 LogError("NULL uWS handle.");
1754 result = MU_FAILURE;
1755 }
1756 else
1757 {
1758 if ((uws_client->uws_state == UWS_STATE_CLOSED) ||
1759 (uws_client->uws_state == UWS_STATE_CLOSING_SENDING_CLOSE) ||
1760 (uws_client->uws_state == UWS_STATE_CLOSING_WAITING_FOR_CLOSE) ||
1761 (uws_client->uws_state == UWS_STATE_CLOSING_UNDERLYING_IO))
1762 {
1763 /* Codes_SRS_UWS_CLIENT_01_032: [ uws_client_close_async when no open action has been issued shall fail and return a non-zero value. ]*/
1764 LogError("close has been called when already CLOSED");
1765 result = MU_FAILURE;
1766 }
1767 else
1768 {
1769 /* Codes_SRS_UWS_CLIENT_01_399: [ on_ws_close_complete and on_ws_close_complete_context shall be saved and the callback on_ws_close_complete shall be triggered when the close is complete. ]*/
1770 uws_client->on_ws_close_complete = on_ws_close_complete;
1771 uws_client->on_ws_close_complete_context = on_ws_close_complete_context;
1772
1773 uws_client->uws_state = UWS_STATE_CLOSING_UNDERLYING_IO;
1774
1775 /* Codes_SRS_UWS_CLIENT_01_031: [ uws_client_close_async shall close the connection by calling xio_close while passing as argument the IO handle created in uws_client_create. ]*/
1776 /* Codes_SRS_UWS_CLIENT_01_368: [ The callback on_underlying_io_close shall be passed as argument to xio_close. ]*/
1777 if (xio_close(uws_client->underlying_io, (on_ws_close_complete == NULL) ? NULL : on_underlying_io_close_complete, (on_ws_close_complete == NULL) ? NULL : uws_client) != 0)
1778 {
1779 /* Codes_SRS_UWS_CLIENT_01_395: [ If xio_close fails, uws_client_close_async shall fail and return a non-zero value. ]*/
1780 LogError("Closing the underlying IO failed.");
1781 result = MU_FAILURE;
1782 }
1783 else
1784 {
1785 /* Codes_SRS_UWS_CLIENT_01_034: [ uws_client_close_async shall obtain all the pending send frames by repetitively querying for the head of the pending IO list and freeing that head item. ]*/
1786 LIST_ITEM_HANDLE first_pending_send;
1787
1788 /* Codes_SRS_UWS_CLIENT_01_035: [ Obtaining the head of the pending send frames list shall be done by calling singlylinkedlist_get_head_item. ]*/
1789 while ((first_pending_send = singlylinkedlist_get_head_item(uws_client->pending_sends)) != NULL)
1790 {
1791 WS_PENDING_SEND* ws_pending_send = (WS_PENDING_SEND*)singlylinkedlist_item_get_value(first_pending_send);
1792
1793 /* Codes_SRS_UWS_CLIENT_01_036: [ For each pending send frame the send complete callback shall be called with UWS_SEND_FRAME_CANCELLED. ]*/
1794 complete_send_frame(ws_pending_send, first_pending_send, WS_SEND_FRAME_CANCELLED);
1795 }
1796
1797 /* Codes_SRS_UWS_CLIENT_01_396: [ On success uws_client_close_async shall return 0. ]*/
1798 result = 0;
1799 }
1800 }
1801 }
1802
1803 return result;
1804}
1805
1806/* Codes_SRS_UWS_CLIENT_01_317: [ Clients SHOULD NOT close the WebSocket connection arbitrarily. ]*/
1807int uws_client_close_handshake_async(UWS_CLIENT_HANDLE uws_client, uint16_t close_code, const char* close_reason, ON_WS_CLOSE_COMPLETE on_ws_close_complete, void* on_ws_close_complete_context)
1808{
1809 int result;
1810
1811 if (uws_client == NULL)
1812 {
1813 /* Codes_SRS_UWS_CLIENT_01_467: [ if uws_client is NULL, uws_client_close_handshake_async shall return a non-zero value. ]*/
1814 LogError("NULL uws_client");
1815 result = MU_FAILURE;
1816 }
1817 else
1818 {
1819 if ((uws_client->uws_state == UWS_STATE_CLOSED) ||
1820 /* Codes_SRS_UWS_CLIENT_01_474: [ uws_client_close_handshake_async when already CLOSING shall fail and return a non-zero value. ]*/
1821 (uws_client->uws_state == UWS_STATE_CLOSING_WAITING_FOR_CLOSE) ||
1822 (uws_client->uws_state == UWS_STATE_CLOSING_SENDING_CLOSE) ||
1823 (uws_client->uws_state == UWS_STATE_CLOSING_UNDERLYING_IO))
1824 {
1825 /* Codes_SRS_UWS_CLIENT_01_473: [ uws_client_close_handshake_async when no open action has been issued shall fail and return a non-zero value. ]*/
1826 LogError("uws_client_close_handshake_async has been called when already CLOSED");
1827 result = MU_FAILURE;
1828 }
1829 else
1830 {
1831 (void)close_reason;
1832
1833 /* Codes_SRS_UWS_CLIENT_01_468: [ on_ws_close_complete and on_ws_close_complete_context shall be saved and the callback on_ws_close_complete shall be triggered when the close is complete. ]*/
1834 /* Codes_SRS_UWS_CLIENT_01_469: [ The on_ws_close_complete argument shall be allowed to be NULL, in which case no callback shall be called when the close is complete. ]*/
1835 /* Codes_SRS_UWS_CLIENT_01_470: [ on_ws_close_complete_context shall also be allowed to be NULL. ]*/
1836 uws_client->on_ws_close_complete = on_ws_close_complete;
1837 uws_client->on_ws_close_complete_context = on_ws_close_complete_context;
1838
1839 uws_client->uws_state = UWS_STATE_CLOSING_WAITING_FOR_CLOSE;
1840
1841 /* Codes_SRS_UWS_CLIENT_01_465: [ uws_client_close_handshake_async shall initiate the close handshake by sending a close frame to the peer. ]*/
1842 if (send_close_frame(uws_client, close_code) != 0)
1843 {
1844 /* Codes_SRS_UWS_CLIENT_01_472: [ If xio_send fails, uws_client_close_handshake_async shall fail and return a non-zero value. ]*/
1845 LogError("Sending CLOSE frame failed");
1846 result = MU_FAILURE;
1847 }
1848 else
1849 {
1850 LIST_ITEM_HANDLE first_pending_send;
1851
1852 while ((first_pending_send = singlylinkedlist_get_head_item(uws_client->pending_sends)) != NULL)
1853 {
1854 WS_PENDING_SEND* ws_pending_send = (WS_PENDING_SEND*)singlylinkedlist_item_get_value(first_pending_send);
1855
1856 complete_send_frame(ws_pending_send, first_pending_send, WS_SEND_FRAME_CANCELLED);
1857 }
1858
1859 /* Codes_SRS_UWS_CLIENT_01_466: [ On success uws_client_close_handshake_async shall return 0. ]*/
1860 result = 0;
1861 }
1862 }
1863 }
1864
1865 return result;
1866}
1867
1868static void on_underlying_io_send_complete(void* context, IO_SEND_RESULT send_result)
1869{
1870 if (context == NULL)
1871 {
1872 /* Codes_SRS_UWS_CLIENT_01_435: [ When on_underlying_io_send_complete is called with a NULL context, it shall do nothing. ]*/
1873 LogError("on_underlying_io_send_complete called with NULL context");
1874 }
1875 else
1876 {
1877 LIST_ITEM_HANDLE ws_pending_send_list_item = (LIST_ITEM_HANDLE)context;
1878 WS_PENDING_SEND* ws_pending_send = (WS_PENDING_SEND*)singlylinkedlist_item_get_value(ws_pending_send_list_item);
1879 if (ws_pending_send != NULL)
1880 {
1881 UWS_CLIENT_HANDLE uws_client = ws_pending_send->uws_client;
1882 WS_SEND_FRAME_RESULT ws_send_frame_result;
1883
1884 switch (send_result)
1885 {
1886 /* Codes_SRS_UWS_CLIENT_01_436: [ When on_underlying_io_send_complete is called with any other error code, the send shall be indicated to the uws user by calling on_ws_send_frame_complete with WS_SEND_FRAME_ERROR. ]*/
1887 default:
1888 case IO_SEND_ERROR:
1889 /* Codes_SRS_UWS_CLIENT_01_390: [ When on_underlying_io_send_complete is called with IO_SEND_ERROR as a result of sending a WebSocket frame to the underlying IO, the send shall be indicated to the uws user by calling on_ws_send_frame_complete with WS_SEND_FRAME_ERROR. ]*/
1890 ws_send_frame_result = WS_SEND_FRAME_ERROR;
1891 break;
1892
1893 case IO_SEND_OK:
1894 /* Codes_SRS_UWS_CLIENT_01_389: [ When on_underlying_io_send_complete is called with IO_SEND_OK as a result of sending a WebSocket frame to the underlying IO, the send shall be indicated to the uws user by calling on_ws_send_frame_complete with WS_SEND_FRAME_OK. ]*/
1895 ws_send_frame_result = WS_SEND_FRAME_OK;
1896 break;
1897
1898 case IO_SEND_CANCELLED:
1899 /* Codes_SRS_UWS_CLIENT_01_391: [ When on_underlying_io_send_complete is called with IO_SEND_CANCELLED as a result of sending a WebSocket frame to the underlying IO, the send shall be indicated to the uws user by calling on_ws_send_frame_complete with WS_SEND_FRAME_CANCELLED. ]*/
1900 ws_send_frame_result = WS_SEND_FRAME_CANCELLED;
1901 break;
1902 }
1903
1904 if (complete_send_frame(ws_pending_send, ws_pending_send_list_item, ws_send_frame_result) != 0)
1905 {
1906 /* Codes_SRS_UWS_CLIENT_01_433: [ If singlylinkedlist_remove fails an error shall be indicated by calling the on_ws_error callback with WS_ERROR_CANNOT_REMOVE_SENT_ITEM_FROM_LIST. ]*/
1907 indicate_ws_error(uws_client, WS_ERROR_CANNOT_REMOVE_SENT_ITEM_FROM_LIST);
1908 }
1909 }
1910 else
1911 {
1912 LogError("Failing getting singlylinkedlist_item_get_value on_underlying_io_send_complete");
1913 }
1914 }
1915}
1916
1917static bool find_list_node(LIST_ITEM_HANDLE list_item, const void* match_context)
1918{
1919 return list_item == (LIST_ITEM_HANDLE)match_context;
1920}
1921
1922int uws_client_send_frame_async(UWS_CLIENT_HANDLE uws_client, unsigned char frame_type, const unsigned char* buffer, size_t size, bool is_final, ON_WS_SEND_FRAME_COMPLETE on_ws_send_frame_complete, void* on_ws_send_frame_complete_context)
1923{
1924 int result;
1925
1926 if (uws_client == NULL)
1927 {
1928 /* Codes_SRS_UWS_CLIENT_01_044: [ If any the arguments uws_client is NULL, uws_client_send_frame_async shall fail and return a non-zero value. ]*/
1929 LogError("NULL uws handle.");
1930 result = MU_FAILURE;
1931 }
1932 else if ((buffer == NULL) &&
1933 (size > 0))
1934 {
1935 /* Codes_SRS_UWS_CLIENT_01_045: [ If size is non-zero and buffer is NULL then uws_client_send_frame_async shall fail and return a non-zero value. ]*/
1936 LogError("NULL buffer with %u size.", (unsigned int)size);
1937 result = MU_FAILURE;
1938 }
1939 /* Codes_SRS_UWS_CLIENT_01_146: [ A data frame MAY be transmitted by either the client or the server at any time after opening handshake completion and before that endpoint has sent a Close frame (Section 5.5.1). ]*/
1940 /* Codes_SRS_UWS_CLIENT_01_268: [ The endpoint MUST ensure the WebSocket connection is in the OPEN state ]*/
1941 else if (uws_client->uws_state != UWS_STATE_OPEN)
1942 {
1943 /* Codes_SRS_UWS_CLIENT_01_043: [ If the uws instance is not OPEN (open has not been called or is still in progress) then uws_client_send_frame_async shall fail and return a non-zero value. ]*/
1944 LogError("uws not in OPEN state.");
1945 result = MU_FAILURE;
1946 }
1947 else
1948 {
1949 WS_PENDING_SEND* ws_pending_send = (WS_PENDING_SEND*)malloc(sizeof(WS_PENDING_SEND));
1950 if (ws_pending_send == NULL)
1951 {
1952 /* Codes_SRS_UWS_CLIENT_01_047: [ If allocating memory for the newly queued item fails, uws_client_send_frame_async shall fail and return a non-zero value. ]*/
1953 LogError("Cannot allocate memory for frame to be sent.");
1954 result = MU_FAILURE;
1955 }
1956 else
1957 {
1958 BUFFER_HANDLE non_control_frame_buffer;
1959
1960 /* Codes_SRS_UWS_CLIENT_01_425: [ Encoding shall be done by calling uws_frame_encoder_encode and passing to it the buffer and size argument for payload, the is_final flag and setting is_masked to true. ]*/
1961 /* Codes_SRS_UWS_CLIENT_01_270: [ An endpoint MUST encapsulate the /data/ in a WebSocket frame as defined in Section 5.2. ]*/
1962 /* Codes_SRS_UWS_CLIENT_01_272: [ The opcode (frame-opcode) of the first frame containing the data MUST be set to the appropriate value from Section 5.2 for data that is to be interpreted by the recipient as text or binary data. ]*/
1963 /* Codes_SRS_UWS_CLIENT_01_274: [ If the data is being sent by the client, the frame(s) MUST be masked as defined in Section 5.3. ]*/
1964 non_control_frame_buffer = uws_frame_encoder_encode((WS_FRAME_TYPE)frame_type, buffer, size, true, is_final, 0);
1965 if (non_control_frame_buffer == NULL)
1966 {
1967 /* Codes_SRS_UWS_CLIENT_01_426: [ If uws_frame_encoder_encode fails, uws_client_send_frame_async shall fail and return a non-zero value. ]*/
1968 LogError("Failed encoding WebSocket frame");
1969 free(ws_pending_send);
1970 result = MU_FAILURE;
1971 }
1972 else
1973 {
1974 const unsigned char* encoded_frame;
1975 size_t encoded_frame_length;
1976 LIST_ITEM_HANDLE new_pending_send_list_item;
1977
1978 /* Codes_SRS_UWS_CLIENT_01_428: [ The encoded frame buffer memory shall be obtained by calling BUFFER_u_char on the encode buffer. ]*/
1979 encoded_frame = BUFFER_u_char(non_control_frame_buffer);
1980 /* Codes_SRS_UWS_CLIENT_01_429: [ The encoded frame size shall be obtained by calling BUFFER_length on the encode buffer. ]*/
1981 encoded_frame_length = BUFFER_length(non_control_frame_buffer);
1982
1983 /* Codes_SRS_UWS_CLIENT_01_038: [ uws_client_send_frame_async shall create and queue a structure that contains: ]*/
1984 /* Codes_SRS_UWS_CLIENT_01_050: [ The argument on_ws_send_frame_complete shall be optional, if NULL is passed by the caller then no send complete callback shall be triggered. ]*/
1985 /* Codes_SRS_UWS_CLIENT_01_040: [ - the send complete callback on_ws_send_frame_complete ]*/
1986 /* Codes_SRS_UWS_CLIENT_01_041: [ - the send complete callback context on_ws_send_frame_complete_context ]*/
1987 ws_pending_send->on_ws_send_frame_complete = on_ws_send_frame_complete;
1988 ws_pending_send->context = on_ws_send_frame_complete_context;
1989 ws_pending_send->uws_client = uws_client;
1990
1991 /* Codes_SRS_UWS_CLIENT_01_048: [ Queueing shall be done by calling singlylinkedlist_add. ]*/
1992 new_pending_send_list_item = singlylinkedlist_add(uws_client->pending_sends, ws_pending_send);
1993 if (new_pending_send_list_item == NULL)
1994 {
1995 /* Codes_SRS_UWS_CLIENT_01_049: [ If singlylinkedlist_add fails, uws_client_send_frame_async shall fail and return a non-zero value. ]*/
1996 LogError("Could not allocate memory for pending frames");
1997 free(ws_pending_send);
1998 result = MU_FAILURE;
1999 }
2000 else
2001 {
2002 /* Codes_SRS_UWS_CLIENT_01_431: [ Once encoded the frame shall be sent by using xio_send with the following arguments: ]*/
2003 /* Codes_SRS_UWS_CLIENT_01_053: [ - the io handle shall be the underlyiong IO handle created in uws_client_create. ]*/
2004 /* Codes_SRS_UWS_CLIENT_01_054: [ - the buffer argument shall point to the complete websocket frame to be sent. ]*/
2005 /* Codes_SRS_UWS_CLIENT_01_055: [ - the size argument shall indicate the websocket frame length. ]*/
2006 /* Codes_SRS_UWS_CLIENT_01_056: [ - the send_complete callback shall be the on_underlying_io_send_complete function. ]*/
2007 /* Codes_SRS_UWS_CLIENT_01_057: [ - the send_complete_context argument shall identify the pending send. ]*/
2008 /* Codes_SRS_UWS_CLIENT_01_276: [ The frame(s) that have been formed MUST be transmitted over the underlying network connection. ]*/
2009 if (xio_send(uws_client->underlying_io, encoded_frame, encoded_frame_length, on_underlying_io_send_complete, new_pending_send_list_item) != 0)
2010 {
2011 /* Codes_SRS_UWS_CLIENT_01_058: [ If xio_send fails, uws_client_send_frame_async shall fail and return a non-zero value. ]*/
2012 LogError("Could not send bytes through the underlying IO");
2013
2014 /* Codes_SRS_UWS_CLIENT_09_001: [ If xio_send fails and the message is still queued, it shall be de-queued and destroyed. ] */
2015 if (singlylinkedlist_find(uws_client->pending_sends, find_list_node, new_pending_send_list_item) != NULL)
2016 {
2017 // Guards against double free in case the underlying I/O invoked 'on_underlying_io_send_complete' within xio_send.
2018 (void)singlylinkedlist_remove(uws_client->pending_sends, new_pending_send_list_item);
2019 free(ws_pending_send);
2020 }
2021
2022 result = MU_FAILURE;
2023 }
2024 else
2025 {
2026 /* Codes_SRS_UWS_CLIENT_01_042: [ On success, uws_client_send_frame_async shall return 0. ]*/
2027 result = 0;
2028 }
2029 }
2030
2031 BUFFER_delete(non_control_frame_buffer);
2032 }
2033 }
2034 }
2035
2036 return result;
2037}
2038
2039void uws_client_dowork(UWS_CLIENT_HANDLE uws_client)
2040{
2041 if (uws_client == NULL)
2042 {
2043 /* Codes_SRS_UWS_CLIENT_01_059: [ If the uws_client argument is NULL, uws_client_dowork shall do nothing. ]*/
2044 LogError("NULL uws handle.");
2045 }
2046 else
2047 {
2048 /* Codes_SRS_UWS_CLIENT_01_060: [ If the IO is not yet open, uws_client_dowork shall do nothing. ]*/
2049 if (uws_client->uws_state != UWS_STATE_CLOSED)
2050 {
2051 /* Codes_SRS_UWS_CLIENT_01_430: [ uws_client_dowork shall call xio_dowork with the IO handle argument set to the underlying IO created in uws_client_create. ]*/
2052 xio_dowork(uws_client->underlying_io);
2053 }
2054 }
2055}
2056
2057int uws_client_set_option(UWS_CLIENT_HANDLE uws_client, const char* option_name, const void* value)
2058{
2059 int result;
2060
2061 if (
2062 (uws_client == NULL) ||
2063 (option_name == NULL)
2064 )
2065 {
2066 /* Codes_SRS_UWS_CLIENT_01_440: [ If any of the arguments uws_client or option_name is NULL uws_client_set_option shall return a non-zero value. ]*/
2067 LogError("invalid parameter (NULL) passed to uws_client_set_option");
2068 result = MU_FAILURE;
2069 }
2070 else
2071 {
2072 if (strcmp(UWS_CLIENT_OPTIONS, option_name) == 0)
2073 {
2074 /* Codes_SRS_UWS_CLIENT_01_510: [ If the option name is uWSClientOptions then uws_client_set_option shall call OptionHandler_FeedOptions and pass to it the underlying IO handle and the value argument. ]*/
2075 if (OptionHandler_FeedOptions((OPTIONHANDLER_HANDLE)value, uws_client->underlying_io) != OPTIONHANDLER_OK)
2076 {
2077 /* Codes_SRS_UWS_CLIENT_01_511: [ If OptionHandler_FeedOptions fails, uws_client_set_option shall fail and return a non-zero value. ]*/
2078 LogError("OptionHandler_FeedOptions failed");
2079 result = MU_FAILURE;
2080 }
2081 else
2082 {
2083 /* Codes_SRS_UWS_CLIENT_01_442: [ On success, uws_client_set_option shall return 0. ]*/
2084 result = 0;
2085 }
2086 }
2087 else
2088 {
2089 /* Codes_SRS_UWS_CLIENT_01_441: [ Otherwise all options shall be passed as they are to the underlying IO by calling xio_setoption. ]*/
2090 if (xio_setoption(uws_client->underlying_io, option_name, value) != 0)
2091 {
2092 /* Codes_SRS_UWS_CLIENT_01_443: [ If xio_setoption fails, uws_client_set_option shall fail and return a non-zero value. ]*/
2093 LogError("xio_setoption failed.");
2094 result = MU_FAILURE;
2095 }
2096 else
2097 {
2098 /* Codes_SRS_UWS_CLIENT_01_442: [ On success, uws_client_set_option shall return 0. ]*/
2099 result = 0;
2100 }
2101 }
2102 }
2103
2104 return result;
2105}
2106
2107static void* uws_client_clone_option(const char* name, const void* value)
2108{
2109 void* result;
2110
2111 if (
2112 (name == NULL) ||
2113 (value == NULL)
2114 )
2115 {
2116 /* Codes_SRS_UWS_CLIENT_01_506: [ If uws_client_clone_option is called with NULL name or value it shall return NULL. ]*/
2117 LogError("invalid argument detected: const char* name=%p, const void* value=%p", name, value);
2118 result = NULL;
2119 }
2120 else
2121 {
2122 if (strcmp(name, UWS_CLIENT_OPTIONS) == 0)
2123 {
2124 /* Codes_SRS_UWS_CLIENT_01_507: [ uws_client_clone_option called with name being uWSClientOptions shall return the same value. ]*/
2125 result = (void*)value;
2126 }
2127 else
2128 {
2129 /* Codes_SRS_UWS_CLIENT_01_512: [ uws_client_clone_option called with any other option name than uWSClientOptions shall return NULL. ]*/
2130 LogError("unknown option: %s", name);
2131 result = NULL;
2132 }
2133 }
2134
2135 return result;
2136}
2137
2138static void uws_client_destroy_option(const char* name, const void* value)
2139{
2140 if (
2141 (name == NULL) ||
2142 (value == NULL)
2143 )
2144 {
2145 /* Codes_SRS_UWS_CLIENT_01_509: [ If uws_client_destroy_option is called with NULL name or value it shall do nothing. ]*/
2146 LogError("invalid argument detected: const char* name=%p, const void* value=%p", name, value);
2147 }
2148 else
2149 {
2150 if (strcmp(name, UWS_CLIENT_OPTIONS) == 0)
2151 {
2152 /* Codes_SRS_UWS_CLIENT_01_508: [ uws_client_destroy_option called with the option name being uWSClientOptions shall destroy the value by calling OptionHandler_Destroy. ]*/
2153 OptionHandler_Destroy((OPTIONHANDLER_HANDLE)value);
2154 }
2155 else
2156 {
2157 /* Codes_SRS_UWS_CLIENT_01_513: [ If uws_client_destroy_option is called with any other name it shall do nothing. ]*/
2158 LogError("unknown option: %s", name);
2159 }
2160 }
2161}
2162
2163OPTIONHANDLER_HANDLE uws_client_retrieve_options(UWS_CLIENT_HANDLE uws_client)
2164{
2165 OPTIONHANDLER_HANDLE result;
2166
2167 if (uws_client == NULL)
2168 {
2169 /* Codes_SRS_UWS_CLIENT_01_444: [ If parameter uws_client is NULL then uws_client_retrieve_options shall fail and return NULL. ]*/
2170 LogError("NULL uws handle.");
2171 result = NULL;
2172 }
2173 else
2174 {
2175 /* Codes_SRS_UWS_CLIENT_01_445: [ uws_client_retrieve_options shall call OptionHandler_Create to produce an OPTIONHANDLER_HANDLE and on success return the new OPTIONHANDLER_HANDLE handle. ]*/
2176 result = OptionHandler_Create(uws_client_clone_option, uws_client_destroy_option, (pfSetOption)uws_client_set_option);
2177 if (result == NULL)
2178 {
2179 /* Codes_SRS_UWS_CLIENT_01_446: [ If OptionHandler_Create fails then uws_client_retrieve_options shall fail and return NULL. ]*/
2180 LogError("OptionHandler_Create failed");
2181 }
2182 else
2183 {
2184 /* Codes_SRS_UWS_CLIENT_01_502: [ When calling xio_retrieveoptions the underlying IO handle shall be passed to it. ]*/
2185 OPTIONHANDLER_HANDLE underlying_io_options = xio_retrieveoptions(uws_client->underlying_io);
2186 if (underlying_io_options == NULL)
2187 {
2188 /* Codes_SRS_UWS_CLIENT_01_503: [ If xio_retrieveoptions fails, uws_client_retrieve_options shall fail and return NULL. ]*/
2189 LogError("unable to concrete_io_retrieveoptions");
2190 OptionHandler_Destroy(result);
2191 result = NULL;
2192 }
2193 else
2194 {
2195 /* Codes_SRS_UWS_CLIENT_01_501: [ uws_client_retrieve_options shall add to the option handler one option, whose name shall be uWSClientOptions and the value shall be queried by calling xio_retrieveoptions. ]*/
2196 /* Codes_SRS_UWS_CLIENT_01_504: [ Adding the option shall be done by calling OptionHandler_AddOption. ]*/
2197 if (OptionHandler_AddOption(result, UWS_CLIENT_OPTIONS, underlying_io_options) != OPTIONHANDLER_OK)
2198 {
2199 /* Codes_SRS_UWS_CLIENT_01_505: [ If OptionHandler_AddOption fails, uws_client_retrieve_options shall fail and return NULL. ]*/
2200 LogError("OptionHandler_AddOption failed");
2201 OptionHandler_Destroy(underlying_io_options);
2202 OptionHandler_Destroy(result);
2203 result = NULL;
2204 }
2205 }
2206 }
2207
2208 }
2209
2210 return result;
2211}
2212
2213int uws_client_set_request_header(UWS_CLIENT_HANDLE uws_client, const char* name, const char* value)
2214{
2215 int result;
2216
2217 if (uws_client == NULL || name == NULL || value == NULL)
2218 {
2219 // Codes_SRS_UWS_CLIENT_09_002: [ If any of the arguments uws_client or name or value is NULL uws_client_set_request_header shall fail and return a non-zero value. ]
2220 LogError("invalid parameter (uws_client=%p, name=%p, value=%p)", uws_client, name, value);
2221 result = MU_FAILURE;
2222 }
2223 // Codes_SRS_UWS_CLIENT_09_003: [ A copy of name and value shall be stored for later sending in the request message. ]
2224 else if (Map_AddOrUpdate(uws_client->request_headers, name, value) != MAP_OK)
2225 {
2226 // Codes_SRS_UWS_CLIENT_09_004: [ If name or value fail to be stored the function shall fail and return a non-zero value. ]
2227 LogError("Failed adding request header %s", name);
2228 result = MU_FAILURE;
2229 }
2230 else
2231 {
2232 // Codes_SRS_UWS_CLIENT_09_005: [ If no failures occur the function shall return zero. ]
2233 result = 0;
2234 }
2235
2236 return result;
2237}
Note: See TracBrowser for help on using the repository browser.