source: azure_iot_hub/trunk/azure_iohub/c-utility/src/uws_client.c@ 388

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

Azure IoT Hub Device C SDK を使ったサンプルの追加

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