Xin Zhang / azure-iot-c-sdk-f767zi

Dependents:   samplemqtt

Committer:
XinZhangMS
Date:
Thu Aug 23 06:52:14 2018 +0000
Revision:
0:f7f1f0d76dd6
azure-c-sdk for mbed os supporting NUCLEO_F767ZI

Who changed what in which revision?

UserRevisionLine numberNew contents of line
XinZhangMS 0:f7f1f0d76dd6 1 // Copyright (c) Microsoft. All rights reserved.
XinZhangMS 0:f7f1f0d76dd6 2 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
XinZhangMS 0:f7f1f0d76dd6 3
XinZhangMS 0:f7f1f0d76dd6 4 #include <stdlib.h>
XinZhangMS 0:f7f1f0d76dd6 5 #include <stddef.h>
XinZhangMS 0:f7f1f0d76dd6 6 #include <stdio.h>
XinZhangMS 0:f7f1f0d76dd6 7 #include <stdbool.h>
XinZhangMS 0:f7f1f0d76dd6 8 #include <stdint.h>
XinZhangMS 0:f7f1f0d76dd6 9 #include "azure_c_shared_utility/gballoc.h"
XinZhangMS 0:f7f1f0d76dd6 10 #include "azure_c_shared_utility/wsio.h"
XinZhangMS 0:f7f1f0d76dd6 11 #include "azure_c_shared_utility/xlogging.h"
XinZhangMS 0:f7f1f0d76dd6 12 #include "azure_c_shared_utility/singlylinkedlist.h"
XinZhangMS 0:f7f1f0d76dd6 13 #include "azure_c_shared_utility/optionhandler.h"
XinZhangMS 0:f7f1f0d76dd6 14 #include "azure_c_shared_utility/xio.h"
XinZhangMS 0:f7f1f0d76dd6 15 #include "azure_c_shared_utility/shared_util_options.h"
XinZhangMS 0:f7f1f0d76dd6 16 #include "azure_c_shared_utility/crt_abstractions.h"
XinZhangMS 0:f7f1f0d76dd6 17 #include "azure_c_shared_utility/uws_client.h"
XinZhangMS 0:f7f1f0d76dd6 18 #include "azure_c_shared_utility/optimize_size.h"
XinZhangMS 0:f7f1f0d76dd6 19
XinZhangMS 0:f7f1f0d76dd6 20 static const char* WSIO_OPTIONS = "WSIOOptions";
XinZhangMS 0:f7f1f0d76dd6 21
XinZhangMS 0:f7f1f0d76dd6 22 typedef enum IO_STATE_TAG
XinZhangMS 0:f7f1f0d76dd6 23 {
XinZhangMS 0:f7f1f0d76dd6 24 IO_STATE_NOT_OPEN,
XinZhangMS 0:f7f1f0d76dd6 25 IO_STATE_OPENING,
XinZhangMS 0:f7f1f0d76dd6 26 IO_STATE_OPEN,
XinZhangMS 0:f7f1f0d76dd6 27 IO_STATE_CLOSING,
XinZhangMS 0:f7f1f0d76dd6 28 IO_STATE_ERROR
XinZhangMS 0:f7f1f0d76dd6 29 } IO_STATE;
XinZhangMS 0:f7f1f0d76dd6 30
XinZhangMS 0:f7f1f0d76dd6 31 typedef struct PENDING_IO_TAG
XinZhangMS 0:f7f1f0d76dd6 32 {
XinZhangMS 0:f7f1f0d76dd6 33 ON_SEND_COMPLETE on_send_complete;
XinZhangMS 0:f7f1f0d76dd6 34 void* callback_context;
XinZhangMS 0:f7f1f0d76dd6 35 void* wsio;
XinZhangMS 0:f7f1f0d76dd6 36 } PENDING_IO;
XinZhangMS 0:f7f1f0d76dd6 37
XinZhangMS 0:f7f1f0d76dd6 38 typedef struct WSIO_INSTANCE_TAG
XinZhangMS 0:f7f1f0d76dd6 39 {
XinZhangMS 0:f7f1f0d76dd6 40 ON_BYTES_RECEIVED on_bytes_received;
XinZhangMS 0:f7f1f0d76dd6 41 void* on_bytes_received_context;
XinZhangMS 0:f7f1f0d76dd6 42 ON_IO_OPEN_COMPLETE on_io_open_complete;
XinZhangMS 0:f7f1f0d76dd6 43 void* on_io_open_complete_context;
XinZhangMS 0:f7f1f0d76dd6 44 ON_IO_ERROR on_io_error;
XinZhangMS 0:f7f1f0d76dd6 45 void* on_io_error_context;
XinZhangMS 0:f7f1f0d76dd6 46 ON_IO_CLOSE_COMPLETE on_io_close_complete;
XinZhangMS 0:f7f1f0d76dd6 47 void* on_io_close_complete_context;
XinZhangMS 0:f7f1f0d76dd6 48 IO_STATE io_state;
XinZhangMS 0:f7f1f0d76dd6 49 SINGLYLINKEDLIST_HANDLE pending_io_list;
XinZhangMS 0:f7f1f0d76dd6 50 UWS_CLIENT_HANDLE uws;
XinZhangMS 0:f7f1f0d76dd6 51 } WSIO_INSTANCE;
XinZhangMS 0:f7f1f0d76dd6 52
XinZhangMS 0:f7f1f0d76dd6 53 static void indicate_error(WSIO_INSTANCE* wsio_instance)
XinZhangMS 0:f7f1f0d76dd6 54 {
XinZhangMS 0:f7f1f0d76dd6 55 wsio_instance->io_state = IO_STATE_ERROR;
XinZhangMS 0:f7f1f0d76dd6 56 wsio_instance->on_io_error(wsio_instance->on_io_error_context);
XinZhangMS 0:f7f1f0d76dd6 57 }
XinZhangMS 0:f7f1f0d76dd6 58
XinZhangMS 0:f7f1f0d76dd6 59 static void indicate_open_complete(WSIO_INSTANCE* ws_io_instance, IO_OPEN_RESULT open_result)
XinZhangMS 0:f7f1f0d76dd6 60 {
XinZhangMS 0:f7f1f0d76dd6 61 ws_io_instance->on_io_open_complete(ws_io_instance->on_io_open_complete_context, open_result);
XinZhangMS 0:f7f1f0d76dd6 62 }
XinZhangMS 0:f7f1f0d76dd6 63
XinZhangMS 0:f7f1f0d76dd6 64 static void complete_send_item(LIST_ITEM_HANDLE pending_io_list_item, IO_SEND_RESULT io_send_result)
XinZhangMS 0:f7f1f0d76dd6 65 {
XinZhangMS 0:f7f1f0d76dd6 66 PENDING_IO* pending_io = (PENDING_IO*)singlylinkedlist_item_get_value(pending_io_list_item);
XinZhangMS 0:f7f1f0d76dd6 67 WSIO_INSTANCE* wsio_instance = (WSIO_INSTANCE*)pending_io->wsio;
XinZhangMS 0:f7f1f0d76dd6 68
XinZhangMS 0:f7f1f0d76dd6 69 /* Codes_SRS_WSIO_01_145: [ Removing it from the list shall be done by calling `singlylinkedlist_remove`. ]*/
XinZhangMS 0:f7f1f0d76dd6 70 if (singlylinkedlist_remove(wsio_instance->pending_io_list, pending_io_list_item) != 0)
XinZhangMS 0:f7f1f0d76dd6 71 {
XinZhangMS 0:f7f1f0d76dd6 72 LogError("Failed removing pending IO from linked list.");
XinZhangMS 0:f7f1f0d76dd6 73 }
XinZhangMS 0:f7f1f0d76dd6 74
XinZhangMS 0:f7f1f0d76dd6 75 /* Codes_SRS_WSIO_01_105: [ The argument `on_send_complete` shall be optional, if NULL is passed by the caller then no send complete callback shall be triggered. ]*/
XinZhangMS 0:f7f1f0d76dd6 76 if (pending_io->on_send_complete != NULL)
XinZhangMS 0:f7f1f0d76dd6 77 {
XinZhangMS 0:f7f1f0d76dd6 78 pending_io->on_send_complete(pending_io->callback_context, io_send_result);
XinZhangMS 0:f7f1f0d76dd6 79 }
XinZhangMS 0:f7f1f0d76dd6 80
XinZhangMS 0:f7f1f0d76dd6 81 /* Codes_SRS_WSIO_01_144: [ Also the pending IO data shall be freed. ]*/
XinZhangMS 0:f7f1f0d76dd6 82 free(pending_io);
XinZhangMS 0:f7f1f0d76dd6 83 }
XinZhangMS 0:f7f1f0d76dd6 84
XinZhangMS 0:f7f1f0d76dd6 85 static void on_underlying_ws_send_frame_complete(void* context, WS_SEND_FRAME_RESULT ws_send_frame_result)
XinZhangMS 0:f7f1f0d76dd6 86 {
XinZhangMS 0:f7f1f0d76dd6 87 if (context == NULL)
XinZhangMS 0:f7f1f0d76dd6 88 {
XinZhangMS 0:f7f1f0d76dd6 89 LogError("NULL context for on_underlying_ws_send_frame_complete");
XinZhangMS 0:f7f1f0d76dd6 90 }
XinZhangMS 0:f7f1f0d76dd6 91 else
XinZhangMS 0:f7f1f0d76dd6 92 {
XinZhangMS 0:f7f1f0d76dd6 93 IO_SEND_RESULT io_send_result;
XinZhangMS 0:f7f1f0d76dd6 94 LIST_ITEM_HANDLE list_item_handle = (LIST_ITEM_HANDLE)context;
XinZhangMS 0:f7f1f0d76dd6 95
XinZhangMS 0:f7f1f0d76dd6 96 /* Codes_SRS_WSIO_01_143: [ When `on_underlying_ws_send_frame_complete` is called after sending a WebSocket frame, the pending IO shall be removed from the list. ]*/
XinZhangMS 0:f7f1f0d76dd6 97 switch (ws_send_frame_result)
XinZhangMS 0:f7f1f0d76dd6 98 {
XinZhangMS 0:f7f1f0d76dd6 99 default:
XinZhangMS 0:f7f1f0d76dd6 100 /* Codes_SRS_WSIO_01_148: [ When `on_underlying_ws_send_frame_complete` is called with any other error code, the callback `on_send_complete` shall be called with `IO_SEND_ERROR`. ]*/
XinZhangMS 0:f7f1f0d76dd6 101 LogError("Frame send error with result %d", (int)ws_send_frame_result);
XinZhangMS 0:f7f1f0d76dd6 102 io_send_result = IO_SEND_ERROR;
XinZhangMS 0:f7f1f0d76dd6 103 break;
XinZhangMS 0:f7f1f0d76dd6 104
XinZhangMS 0:f7f1f0d76dd6 105 case WS_SEND_FRAME_OK:
XinZhangMS 0:f7f1f0d76dd6 106 /* Codes_SRS_WSIO_01_146: [ When `on_underlying_ws_send_frame_complete` is called with `WS_SEND_OK`, the callback `on_send_complete` shall be called with `IO_SEND_OK`. ]*/
XinZhangMS 0:f7f1f0d76dd6 107 io_send_result = IO_SEND_OK;
XinZhangMS 0:f7f1f0d76dd6 108 break;
XinZhangMS 0:f7f1f0d76dd6 109
XinZhangMS 0:f7f1f0d76dd6 110 case WS_SEND_FRAME_CANCELLED:
XinZhangMS 0:f7f1f0d76dd6 111 /* Codes_SRS_WSIO_01_147: [ When `on_underlying_ws_send_frame_complete` is called with `WS_SEND_CANCELLED`, the callback `on_send_complete` shall be called with `IO_SEND_CANCELLED`. ]*/
XinZhangMS 0:f7f1f0d76dd6 112 io_send_result = IO_SEND_CANCELLED;
XinZhangMS 0:f7f1f0d76dd6 113 break;
XinZhangMS 0:f7f1f0d76dd6 114 }
XinZhangMS 0:f7f1f0d76dd6 115
XinZhangMS 0:f7f1f0d76dd6 116 complete_send_item(list_item_handle, io_send_result);
XinZhangMS 0:f7f1f0d76dd6 117 }
XinZhangMS 0:f7f1f0d76dd6 118 }
XinZhangMS 0:f7f1f0d76dd6 119
XinZhangMS 0:f7f1f0d76dd6 120 static void on_underlying_ws_close_complete(void* context)
XinZhangMS 0:f7f1f0d76dd6 121 {
XinZhangMS 0:f7f1f0d76dd6 122 WSIO_INSTANCE* wsio_instance = (WSIO_INSTANCE*)context;
XinZhangMS 0:f7f1f0d76dd6 123 if (wsio_instance == NULL)
XinZhangMS 0:f7f1f0d76dd6 124 {
XinZhangMS 0:f7f1f0d76dd6 125 /* Codes_SRS_WSIO_01_161: [ If the context passed to `on_underlying_ws_close_complete` is NULL, `on_underlying_ws_close_complete` shall do nothing. ]*/
XinZhangMS 0:f7f1f0d76dd6 126 LogError("NULL context passed to on_underlying_ws_close_complete");
XinZhangMS 0:f7f1f0d76dd6 127 }
XinZhangMS 0:f7f1f0d76dd6 128 else
XinZhangMS 0:f7f1f0d76dd6 129 {
XinZhangMS 0:f7f1f0d76dd6 130 wsio_instance->io_state = IO_STATE_NOT_OPEN;
XinZhangMS 0:f7f1f0d76dd6 131
XinZhangMS 0:f7f1f0d76dd6 132 /* Codes_SRS_WSIO_01_160: [ If NULL was passed to `wsio_close` no callback shall be called. ]*/
XinZhangMS 0:f7f1f0d76dd6 133 if (wsio_instance->on_io_close_complete != NULL)
XinZhangMS 0:f7f1f0d76dd6 134 {
XinZhangMS 0:f7f1f0d76dd6 135 /* Codes_SRS_WSIO_01_159: [ When `on_underlying_ws_close_complete` while the IO is closing (after `wsio_close`), the close shall be indicated up by calling the `on_io_close_complete` callback passed to `wsio_close`. ]*/
XinZhangMS 0:f7f1f0d76dd6 136 /* Codes_SRS_WSIO_01_163: [ When `on_io_close_complete` is called, the context passed to `wsio_close` shall be passed as argument to `on_io_close_complete`. ]*/
XinZhangMS 0:f7f1f0d76dd6 137 wsio_instance->on_io_close_complete(wsio_instance->on_io_close_complete_context);
XinZhangMS 0:f7f1f0d76dd6 138 }
XinZhangMS 0:f7f1f0d76dd6 139 }
XinZhangMS 0:f7f1f0d76dd6 140 }
XinZhangMS 0:f7f1f0d76dd6 141
XinZhangMS 0:f7f1f0d76dd6 142 static int internal_close(WSIO_INSTANCE* wsio_instance, ON_IO_CLOSE_COMPLETE on_io_close_complete, void* on_io_close_complete_context)
XinZhangMS 0:f7f1f0d76dd6 143 {
XinZhangMS 0:f7f1f0d76dd6 144 int result;
XinZhangMS 0:f7f1f0d76dd6 145
XinZhangMS 0:f7f1f0d76dd6 146 /* Codes_SRS_WSIO_01_089: [ `wsio_close` after a `wsio_close` shall fail and return a non-zero value. ]*/
XinZhangMS 0:f7f1f0d76dd6 147 /* Codes_SRS_WSIO_01_088: [ `wsio_close` when no open action has been issued shall fail and return a non-zero value. ]*/
XinZhangMS 0:f7f1f0d76dd6 148 if (wsio_instance->io_state == IO_STATE_NOT_OPEN)
XinZhangMS 0:f7f1f0d76dd6 149 {
XinZhangMS 0:f7f1f0d76dd6 150 LogError("wsio_close when not open.");
XinZhangMS 0:f7f1f0d76dd6 151 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 152 }
XinZhangMS 0:f7f1f0d76dd6 153 else
XinZhangMS 0:f7f1f0d76dd6 154 {
XinZhangMS 0:f7f1f0d76dd6 155 if (wsio_instance->io_state == IO_STATE_OPENING)
XinZhangMS 0:f7f1f0d76dd6 156 {
XinZhangMS 0:f7f1f0d76dd6 157 wsio_instance->io_state = IO_STATE_NOT_OPEN;
XinZhangMS 0:f7f1f0d76dd6 158 indicate_open_complete(wsio_instance, IO_OPEN_CANCELLED);
XinZhangMS 0:f7f1f0d76dd6 159 result = 0;
XinZhangMS 0:f7f1f0d76dd6 160 }
XinZhangMS 0:f7f1f0d76dd6 161 else if (wsio_instance->io_state == IO_STATE_CLOSING)
XinZhangMS 0:f7f1f0d76dd6 162 {
XinZhangMS 0:f7f1f0d76dd6 163 LogError("Already closing");
XinZhangMS 0:f7f1f0d76dd6 164 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 165 }
XinZhangMS 0:f7f1f0d76dd6 166 else
XinZhangMS 0:f7f1f0d76dd6 167 {
XinZhangMS 0:f7f1f0d76dd6 168 LIST_ITEM_HANDLE first_pending_io;
XinZhangMS 0:f7f1f0d76dd6 169
XinZhangMS 0:f7f1f0d76dd6 170 wsio_instance->io_state = IO_STATE_CLOSING;
XinZhangMS 0:f7f1f0d76dd6 171
XinZhangMS 0:f7f1f0d76dd6 172 wsio_instance->on_io_close_complete = on_io_close_complete;
XinZhangMS 0:f7f1f0d76dd6 173 wsio_instance->on_io_close_complete_context = on_io_close_complete_context;
XinZhangMS 0:f7f1f0d76dd6 174
XinZhangMS 0:f7f1f0d76dd6 175 /* Codes_SRS_WSIO_01_087: [ `wsio_close` shall call `uws_client_close_async` while passing as argument the IO handle created in `wsio_create`. ]*/
XinZhangMS 0:f7f1f0d76dd6 176 if (uws_client_close_async(wsio_instance->uws, on_underlying_ws_close_complete, wsio_instance) != 0)
XinZhangMS 0:f7f1f0d76dd6 177 {
XinZhangMS 0:f7f1f0d76dd6 178 /* Codes_SRS_WSIO_01_164: [ When uws_client_close_async fails, wsio_close shall call the on_io_close_complete callback and continue. ] */
XinZhangMS 0:f7f1f0d76dd6 179 if (wsio_instance->on_io_close_complete != NULL)
XinZhangMS 0:f7f1f0d76dd6 180 {
XinZhangMS 0:f7f1f0d76dd6 181 wsio_instance->on_io_close_complete(wsio_instance->on_io_close_complete_context);
XinZhangMS 0:f7f1f0d76dd6 182 }
XinZhangMS 0:f7f1f0d76dd6 183 }
XinZhangMS 0:f7f1f0d76dd6 184
XinZhangMS 0:f7f1f0d76dd6 185 /* Codes_SRS_WSIO_01_085: [ `wsio_close` shall close the websockets IO if an open action is either pending or has completed successfully (if the IO is open). ]*/
XinZhangMS 0:f7f1f0d76dd6 186 /* Codes_SRS_WSIO_01_091: [ `wsio_close` shall obtain all the pending IO items by repetitively querying for the head of the pending IO list and freeing that head item. ]*/
XinZhangMS 0:f7f1f0d76dd6 187 /* Codes_SRS_WSIO_01_092: [ Obtaining the head of the pending IO list shall be done by calling `singlylinkedlist_get_head_item`. ]*/
XinZhangMS 0:f7f1f0d76dd6 188 while ((first_pending_io = singlylinkedlist_get_head_item(wsio_instance->pending_io_list)) != NULL)
XinZhangMS 0:f7f1f0d76dd6 189 {
XinZhangMS 0:f7f1f0d76dd6 190 complete_send_item(first_pending_io, IO_SEND_CANCELLED);
XinZhangMS 0:f7f1f0d76dd6 191 }
XinZhangMS 0:f7f1f0d76dd6 192
XinZhangMS 0:f7f1f0d76dd6 193 /* Codes_SRS_WSIO_01_133: [ On success `wsio_close` shall return 0. ]*/
XinZhangMS 0:f7f1f0d76dd6 194 result = 0;
XinZhangMS 0:f7f1f0d76dd6 195 wsio_instance->io_state = IO_STATE_NOT_OPEN;
XinZhangMS 0:f7f1f0d76dd6 196 }
XinZhangMS 0:f7f1f0d76dd6 197 }
XinZhangMS 0:f7f1f0d76dd6 198 return result;
XinZhangMS 0:f7f1f0d76dd6 199 }
XinZhangMS 0:f7f1f0d76dd6 200
XinZhangMS 0:f7f1f0d76dd6 201 CONCRETE_IO_HANDLE wsio_create(void* io_create_parameters)
XinZhangMS 0:f7f1f0d76dd6 202 {
XinZhangMS 0:f7f1f0d76dd6 203 /* Codes_SRS_WSIO_01_066: [ `io_create_parameters` shall be used as a `WSIO_CONFIG*` . ]*/
XinZhangMS 0:f7f1f0d76dd6 204 WSIO_CONFIG* ws_io_config = (WSIO_CONFIG*)io_create_parameters;
XinZhangMS 0:f7f1f0d76dd6 205 WSIO_INSTANCE* result;
XinZhangMS 0:f7f1f0d76dd6 206
XinZhangMS 0:f7f1f0d76dd6 207 /* Codes_SRS_WSIO_01_065: [ If the argument `io_create_parameters` is NULL then `wsio_create` shall return NULL. ]*/
XinZhangMS 0:f7f1f0d76dd6 208 if ((ws_io_config == NULL) ||
XinZhangMS 0:f7f1f0d76dd6 209 /* Codes_SRS_WSIO_01_067: [ If any of the members `hostname`, `resource_name` or `protocol` is NULL in `WSIO_CONFIG` then `wsio_create` shall return NULL. ]*/
XinZhangMS 0:f7f1f0d76dd6 210 (ws_io_config->hostname == NULL) ||
XinZhangMS 0:f7f1f0d76dd6 211 (ws_io_config->resource_name == NULL) ||
XinZhangMS 0:f7f1f0d76dd6 212 (ws_io_config->protocol == NULL))
XinZhangMS 0:f7f1f0d76dd6 213 {
XinZhangMS 0:f7f1f0d76dd6 214 LogError("NULL io_create_parameters.");
XinZhangMS 0:f7f1f0d76dd6 215 result = NULL;
XinZhangMS 0:f7f1f0d76dd6 216 }
XinZhangMS 0:f7f1f0d76dd6 217 else
XinZhangMS 0:f7f1f0d76dd6 218 {
XinZhangMS 0:f7f1f0d76dd6 219 /* Codes_SRS_WSIO_01_001: [`wsio_create` shall create an instance of wsio and return a non-NULL handle to it.] */
XinZhangMS 0:f7f1f0d76dd6 220 result = (WSIO_INSTANCE*)malloc(sizeof(WSIO_INSTANCE));
XinZhangMS 0:f7f1f0d76dd6 221 if (result == NULL)
XinZhangMS 0:f7f1f0d76dd6 222 {
XinZhangMS 0:f7f1f0d76dd6 223 /* Codes_SRS_WSIO_01_068: [ If allocating memory for the new wsio instance fails then `wsio_create` shall return NULL. ]*/
XinZhangMS 0:f7f1f0d76dd6 224 LogError("Cannot allocate memory for the new WSIO instance.");
XinZhangMS 0:f7f1f0d76dd6 225 }
XinZhangMS 0:f7f1f0d76dd6 226 else
XinZhangMS 0:f7f1f0d76dd6 227 {
XinZhangMS 0:f7f1f0d76dd6 228 WS_PROTOCOL protocols;
XinZhangMS 0:f7f1f0d76dd6 229
XinZhangMS 0:f7f1f0d76dd6 230 protocols.protocol = ws_io_config->protocol;
XinZhangMS 0:f7f1f0d76dd6 231
XinZhangMS 0:f7f1f0d76dd6 232 result->on_bytes_received = NULL;
XinZhangMS 0:f7f1f0d76dd6 233 result->on_bytes_received_context = NULL;
XinZhangMS 0:f7f1f0d76dd6 234 result->on_io_open_complete = NULL;
XinZhangMS 0:f7f1f0d76dd6 235 result->on_io_open_complete_context = NULL;
XinZhangMS 0:f7f1f0d76dd6 236 result->on_io_error = NULL;
XinZhangMS 0:f7f1f0d76dd6 237 result->on_io_error_context = NULL;
XinZhangMS 0:f7f1f0d76dd6 238 result->on_io_close_complete = NULL;
XinZhangMS 0:f7f1f0d76dd6 239 result->on_io_close_complete_context = NULL;
XinZhangMS 0:f7f1f0d76dd6 240
XinZhangMS 0:f7f1f0d76dd6 241 /* Codes_SRS_WSIO_01_070: [ The underlying uws instance shall be created by calling `uws_client_create_with_io`. ]*/
XinZhangMS 0:f7f1f0d76dd6 242 /* Codes_SRS_WSIO_01_071: [ The arguments for `uws_client_create_with_io` shall be: ]*/
XinZhangMS 0:f7f1f0d76dd6 243 /* Codes_SRS_WSIO_01_185: [ - `underlying_io_interface` shall be set to the `underlying_io_interface` field in the `io_create_parameters` passed to `wsio_create`. ]*/
XinZhangMS 0:f7f1f0d76dd6 244 /* Codes_SRS_WSIO_01_186: [ - `underlying_io_parameters` shall be set to the `underlying_io_parameters` field in the `io_create_parameters` passed to `wsio_create`. ]*/
XinZhangMS 0:f7f1f0d76dd6 245 /* Codes_SRS_WSIO_01_072: [ - `hostname` set to the `hostname` field in the `io_create_parameters` passed to `wsio_create`. ]*/
XinZhangMS 0:f7f1f0d76dd6 246 /* Codes_SRS_WSIO_01_130: [ - `port` set to the `port` field in the `io_create_parameters` passed to `wsio_create`. ]*/
XinZhangMS 0:f7f1f0d76dd6 247 /* Codes_SRS_WSIO_01_128: [ - `resource_name` set to the `resource_name` field in the `io_create_parameters` passed to `wsio_create`. ]*/
XinZhangMS 0:f7f1f0d76dd6 248 /* Codes_SRS_WSIO_01_129: [ - `protocols` shall be filled with only one structure, that shall have the `protocol` set to the value of the `protocol` field in the `io_create_parameters` passed to `wsio_create`. ]*/
XinZhangMS 0:f7f1f0d76dd6 249 result->uws = uws_client_create_with_io(ws_io_config->underlying_io_interface, ws_io_config->underlying_io_parameters, ws_io_config->hostname, ws_io_config->port, ws_io_config->resource_name, &protocols, 1);
XinZhangMS 0:f7f1f0d76dd6 250 if (result->uws == NULL)
XinZhangMS 0:f7f1f0d76dd6 251 {
XinZhangMS 0:f7f1f0d76dd6 252 /* Codes_SRS_WSIO_01_075: [ If `uws_client_create_with_io` fails, then `wsio_create` shall fail and return NULL. ]*/
XinZhangMS 0:f7f1f0d76dd6 253 LogError("Cannot create uws instance.");
XinZhangMS 0:f7f1f0d76dd6 254 free(result);
XinZhangMS 0:f7f1f0d76dd6 255 result = NULL;
XinZhangMS 0:f7f1f0d76dd6 256 }
XinZhangMS 0:f7f1f0d76dd6 257 else
XinZhangMS 0:f7f1f0d76dd6 258 {
XinZhangMS 0:f7f1f0d76dd6 259 /* Codes_SRS_WSIO_01_076: [ `wsio_create` shall create a pending send IO list that is to be used to queue send packets by calling `singlylinkedlist_create`. ]*/
XinZhangMS 0:f7f1f0d76dd6 260 result->pending_io_list = singlylinkedlist_create();
XinZhangMS 0:f7f1f0d76dd6 261 if (result->pending_io_list == NULL)
XinZhangMS 0:f7f1f0d76dd6 262 {
XinZhangMS 0:f7f1f0d76dd6 263 /* Codes_SRS_WSIO_01_077: [ If `singlylinkedlist_create` fails then `wsio_create` shall fail and return NULL. ]*/
XinZhangMS 0:f7f1f0d76dd6 264 LogError("Cannot create singly linked list.");
XinZhangMS 0:f7f1f0d76dd6 265 uws_client_destroy(result->uws);
XinZhangMS 0:f7f1f0d76dd6 266 free(result);
XinZhangMS 0:f7f1f0d76dd6 267 result = NULL;
XinZhangMS 0:f7f1f0d76dd6 268 }
XinZhangMS 0:f7f1f0d76dd6 269 else
XinZhangMS 0:f7f1f0d76dd6 270 {
XinZhangMS 0:f7f1f0d76dd6 271 result->io_state = IO_STATE_NOT_OPEN;
XinZhangMS 0:f7f1f0d76dd6 272 }
XinZhangMS 0:f7f1f0d76dd6 273 }
XinZhangMS 0:f7f1f0d76dd6 274 }
XinZhangMS 0:f7f1f0d76dd6 275 }
XinZhangMS 0:f7f1f0d76dd6 276
XinZhangMS 0:f7f1f0d76dd6 277 return result;
XinZhangMS 0:f7f1f0d76dd6 278 }
XinZhangMS 0:f7f1f0d76dd6 279
XinZhangMS 0:f7f1f0d76dd6 280 void wsio_destroy(CONCRETE_IO_HANDLE ws_io)
XinZhangMS 0:f7f1f0d76dd6 281 {
XinZhangMS 0:f7f1f0d76dd6 282 /* Codes_SRS_WSIO_01_079: [ If `ws_io` is NULL, `wsio_destroy` shall do nothing. ]*/
XinZhangMS 0:f7f1f0d76dd6 283 if (ws_io == NULL)
XinZhangMS 0:f7f1f0d76dd6 284 {
XinZhangMS 0:f7f1f0d76dd6 285 LogError("NULL handle");
XinZhangMS 0:f7f1f0d76dd6 286 }
XinZhangMS 0:f7f1f0d76dd6 287 else
XinZhangMS 0:f7f1f0d76dd6 288 {
XinZhangMS 0:f7f1f0d76dd6 289 WSIO_INSTANCE* wsio_instance = (WSIO_INSTANCE*)ws_io;
XinZhangMS 0:f7f1f0d76dd6 290
XinZhangMS 0:f7f1f0d76dd6 291 if (wsio_instance->io_state != IO_STATE_NOT_OPEN)
XinZhangMS 0:f7f1f0d76dd6 292 {
XinZhangMS 0:f7f1f0d76dd6 293 internal_close(wsio_instance, NULL, NULL);
XinZhangMS 0:f7f1f0d76dd6 294 }
XinZhangMS 0:f7f1f0d76dd6 295
XinZhangMS 0:f7f1f0d76dd6 296 /* Codes_SRS_WSIO_01_078: [ `wsio_destroy` shall free all resources associated with the wsio instance. ]*/
XinZhangMS 0:f7f1f0d76dd6 297 /* Codes_SRS_WSIO_01_080: [ `wsio_destroy` shall destroy the uws instance created in `wsio_create` by calling `uws_client_destroy`. ]*/
XinZhangMS 0:f7f1f0d76dd6 298 uws_client_destroy(wsio_instance->uws);
XinZhangMS 0:f7f1f0d76dd6 299 /* Codes_SRS_WSIO_01_081: [ `wsio_destroy` shall free the list used to track the pending send IOs by calling `singlylinkedlist_destroy`. ]*/
XinZhangMS 0:f7f1f0d76dd6 300 singlylinkedlist_destroy(wsio_instance->pending_io_list);
XinZhangMS 0:f7f1f0d76dd6 301 free(ws_io);
XinZhangMS 0:f7f1f0d76dd6 302 }
XinZhangMS 0:f7f1f0d76dd6 303 }
XinZhangMS 0:f7f1f0d76dd6 304
XinZhangMS 0:f7f1f0d76dd6 305 static void on_underlying_ws_open_complete(void* context, WS_OPEN_RESULT open_result)
XinZhangMS 0:f7f1f0d76dd6 306 {
XinZhangMS 0:f7f1f0d76dd6 307 if (context == NULL)
XinZhangMS 0:f7f1f0d76dd6 308 {
XinZhangMS 0:f7f1f0d76dd6 309 /* Codes_SRS_WSIO_01_138: [ When `on_underlying_ws_open_complete` is called with a NULL context, it shall do nothing. ]*/
XinZhangMS 0:f7f1f0d76dd6 310 LogError("NULL context in on_underlying_ws_open_complete");
XinZhangMS 0:f7f1f0d76dd6 311 }
XinZhangMS 0:f7f1f0d76dd6 312 else
XinZhangMS 0:f7f1f0d76dd6 313 {
XinZhangMS 0:f7f1f0d76dd6 314 WSIO_INSTANCE* wsio_instance = (WSIO_INSTANCE*)context;
XinZhangMS 0:f7f1f0d76dd6 315
XinZhangMS 0:f7f1f0d76dd6 316 switch (wsio_instance->io_state)
XinZhangMS 0:f7f1f0d76dd6 317 {
XinZhangMS 0:f7f1f0d76dd6 318 default:
XinZhangMS 0:f7f1f0d76dd6 319 /* Codes_SRS_WSIO_01_142: [ When `on_underlying_ws_open_complete` is called while in the CLOSING state an error shall be indicated by calling the `on_io_error` callback passed to `wsio_open`. ]*/
XinZhangMS 0:f7f1f0d76dd6 320 case IO_STATE_CLOSING:
XinZhangMS 0:f7f1f0d76dd6 321 /* Codes_SRS_WSIO_01_141: [ When `on_underlying_ws_open_complete` is called while in the ERROR state it shall indicate an error by calling the `on_io_error` callback passed to `wsio_open`. ]*/
XinZhangMS 0:f7f1f0d76dd6 322 case IO_STATE_ERROR:
XinZhangMS 0:f7f1f0d76dd6 323 /* Codes_SRS_WSIO_01_139: [ When `on_underlying_ws_open_complete` is called while in OPEN state it shall indicate an error by calling the `on_io_error` callback passed to `wsio_open` and switch to the ERROR state. ]*/
XinZhangMS 0:f7f1f0d76dd6 324 case IO_STATE_OPEN:
XinZhangMS 0:f7f1f0d76dd6 325 /* Codes_SRS_WSIO_01_140: [ When calling `on_io_error`, the `on_io_error_context` argument given in `wsio_open` shall be passed to the callback `on_io_error`. ]*/
XinZhangMS 0:f7f1f0d76dd6 326 indicate_error(wsio_instance);
XinZhangMS 0:f7f1f0d76dd6 327 break;
XinZhangMS 0:f7f1f0d76dd6 328
XinZhangMS 0:f7f1f0d76dd6 329 case IO_STATE_OPENING:
XinZhangMS 0:f7f1f0d76dd6 330 wsio_instance->io_state = IO_STATE_OPEN;
XinZhangMS 0:f7f1f0d76dd6 331
XinZhangMS 0:f7f1f0d76dd6 332 switch (open_result)
XinZhangMS 0:f7f1f0d76dd6 333 {
XinZhangMS 0:f7f1f0d76dd6 334 default:
XinZhangMS 0:f7f1f0d76dd6 335 /* Codes_SRS_WSIO_01_137: [ When `on_underlying_ws_open_complete` is called with any other error code while the IO is opening, the callback `on_io_open_complete` shall be called with `IO_OPEN_ERROR`. ]*/
XinZhangMS 0:f7f1f0d76dd6 336 wsio_instance->io_state = IO_STATE_NOT_OPEN;
XinZhangMS 0:f7f1f0d76dd6 337 indicate_open_complete(wsio_instance, IO_OPEN_ERROR);
XinZhangMS 0:f7f1f0d76dd6 338 break;
XinZhangMS 0:f7f1f0d76dd6 339
XinZhangMS 0:f7f1f0d76dd6 340 case WS_OPEN_CANCELLED:
XinZhangMS 0:f7f1f0d76dd6 341 /* Codes_SRS_WSIO_01_149: [ When `on_underlying_ws_open_complete` is called with `WS_OPEN_CANCELLED` while the IO is opening, the callback `on_io_open_complete` shall be called with `IO_OPEN_CANCELLED`. ]*/
XinZhangMS 0:f7f1f0d76dd6 342 wsio_instance->io_state = IO_STATE_NOT_OPEN;
XinZhangMS 0:f7f1f0d76dd6 343 indicate_open_complete(wsio_instance, IO_OPEN_CANCELLED);
XinZhangMS 0:f7f1f0d76dd6 344 break;
XinZhangMS 0:f7f1f0d76dd6 345
XinZhangMS 0:f7f1f0d76dd6 346 case WS_OPEN_OK:
XinZhangMS 0:f7f1f0d76dd6 347 /* Codes_SRS_WSIO_01_136: [ When `on_underlying_ws_open_complete` is called with `WS_OPEN_OK` while the IO is opening, the callback `on_io_open_complete` shall be called with `IO_OPEN_OK`. ]*/
XinZhangMS 0:f7f1f0d76dd6 348 wsio_instance->io_state = IO_STATE_OPEN;
XinZhangMS 0:f7f1f0d76dd6 349 indicate_open_complete(wsio_instance, IO_OPEN_OK);
XinZhangMS 0:f7f1f0d76dd6 350 break;
XinZhangMS 0:f7f1f0d76dd6 351 }
XinZhangMS 0:f7f1f0d76dd6 352
XinZhangMS 0:f7f1f0d76dd6 353 break;
XinZhangMS 0:f7f1f0d76dd6 354 }
XinZhangMS 0:f7f1f0d76dd6 355 }
XinZhangMS 0:f7f1f0d76dd6 356 }
XinZhangMS 0:f7f1f0d76dd6 357
XinZhangMS 0:f7f1f0d76dd6 358 static void on_underlying_ws_frame_received(void* context, unsigned char frame_type, const unsigned char* buffer, size_t size)
XinZhangMS 0:f7f1f0d76dd6 359 {
XinZhangMS 0:f7f1f0d76dd6 360 if (context == NULL)
XinZhangMS 0:f7f1f0d76dd6 361 {
XinZhangMS 0:f7f1f0d76dd6 362 /* Codes_SRS_WSIO_01_150: [ If `on_underlying_ws_frame_received` is called with NULL context it shall do nothing. ]*/
XinZhangMS 0:f7f1f0d76dd6 363 LogError("NULL context for on_underlying_ws_frame_received");
XinZhangMS 0:f7f1f0d76dd6 364 }
XinZhangMS 0:f7f1f0d76dd6 365 else
XinZhangMS 0:f7f1f0d76dd6 366 {
XinZhangMS 0:f7f1f0d76dd6 367 WSIO_INSTANCE* wsio_instance = (WSIO_INSTANCE*)context;
XinZhangMS 0:f7f1f0d76dd6 368
XinZhangMS 0:f7f1f0d76dd6 369 if (wsio_instance->io_state != IO_STATE_OPEN)
XinZhangMS 0:f7f1f0d76dd6 370 {
XinZhangMS 0:f7f1f0d76dd6 371 /* Codes_SRS_WSIO_01_126: [ If `on_underlying_ws_frame_received` is called while the IO is in any state other than OPEN, it shall do nothing. ]*/
XinZhangMS 0:f7f1f0d76dd6 372 LogError("on_underlying_ws_frame_received called in a bad state.");
XinZhangMS 0:f7f1f0d76dd6 373 }
XinZhangMS 0:f7f1f0d76dd6 374 else
XinZhangMS 0:f7f1f0d76dd6 375 {
XinZhangMS 0:f7f1f0d76dd6 376 if (frame_type != WS_FRAME_TYPE_BINARY)
XinZhangMS 0:f7f1f0d76dd6 377 {
XinZhangMS 0:f7f1f0d76dd6 378 /* Codes_SRS_WSIO_01_151: [ If the WebSocket frame type is not binary then an error shall be indicated by calling the `on_io_error` callback passed to `wsio_open`. ]*/
XinZhangMS 0:f7f1f0d76dd6 379 LogError("Invalid non binary WebSocket frame received.");
XinZhangMS 0:f7f1f0d76dd6 380 /* Codes_SRS_WSIO_01_152: [ When calling `on_io_error`, the `on_io_error_context` argument given in `wsio_open` shall be passed to the callback `on_io_error`. ]*/
XinZhangMS 0:f7f1f0d76dd6 381 indicate_error(wsio_instance);
XinZhangMS 0:f7f1f0d76dd6 382 }
XinZhangMS 0:f7f1f0d76dd6 383 else
XinZhangMS 0:f7f1f0d76dd6 384 {
XinZhangMS 0:f7f1f0d76dd6 385 /* Codes_SRS_WSIO_01_153: [ When `on_underlying_ws_frame_received` is called with zero `size`, no bytes shall be indicated up as received. ]*/
XinZhangMS 0:f7f1f0d76dd6 386 if (size > 0)
XinZhangMS 0:f7f1f0d76dd6 387 {
XinZhangMS 0:f7f1f0d76dd6 388 if (buffer == NULL)
XinZhangMS 0:f7f1f0d76dd6 389 {
XinZhangMS 0:f7f1f0d76dd6 390 /* Codes_SRS_WSIO_01_154: [ When `on_underlying_ws_frame_received` is called with a positive `size` and a NULL `buffer`, an error shall be indicated by calling the `on_io_error` callback passed to `wsio_open`. ]*/
XinZhangMS 0:f7f1f0d76dd6 391 LogError("NULL buffer received for Websocket frame with positive payload length.");
XinZhangMS 0:f7f1f0d76dd6 392 indicate_error(wsio_instance);
XinZhangMS 0:f7f1f0d76dd6 393 }
XinZhangMS 0:f7f1f0d76dd6 394 else
XinZhangMS 0:f7f1f0d76dd6 395 {
XinZhangMS 0:f7f1f0d76dd6 396 /* Codes_SRS_WSIO_01_124: [ When `on_underlying_ws_frame_received` is called the bytes in the frame shall be indicated by calling the `on_bytes_received` callback passed to `wsio_open`. ]*/
XinZhangMS 0:f7f1f0d76dd6 397 /* Codes_SRS_WSIO_01_125: [ When calling `on_bytes_received`, the `on_bytes_received_context` argument given in `wsio_open` shall be passed to the callback `on_bytes_received`. ]*/
XinZhangMS 0:f7f1f0d76dd6 398 wsio_instance->on_bytes_received(wsio_instance->on_bytes_received_context, buffer, size);
XinZhangMS 0:f7f1f0d76dd6 399 }
XinZhangMS 0:f7f1f0d76dd6 400 }
XinZhangMS 0:f7f1f0d76dd6 401 }
XinZhangMS 0:f7f1f0d76dd6 402 }
XinZhangMS 0:f7f1f0d76dd6 403 }
XinZhangMS 0:f7f1f0d76dd6 404 }
XinZhangMS 0:f7f1f0d76dd6 405
XinZhangMS 0:f7f1f0d76dd6 406 static void on_underlying_ws_peer_closed(void* context, uint16_t* close_code, const unsigned char* extra_data, size_t extra_data_length)
XinZhangMS 0:f7f1f0d76dd6 407 {
XinZhangMS 0:f7f1f0d76dd6 408 /* Codes_SRS_WSIO_01_168: [ The `close_code`, `extra_data` and `extra_data_length` arguments shall be ignored. ]*/
XinZhangMS 0:f7f1f0d76dd6 409 (void)close_code;
XinZhangMS 0:f7f1f0d76dd6 410 (void)extra_data;
XinZhangMS 0:f7f1f0d76dd6 411 (void)extra_data_length;
XinZhangMS 0:f7f1f0d76dd6 412
XinZhangMS 0:f7f1f0d76dd6 413 if (context == NULL)
XinZhangMS 0:f7f1f0d76dd6 414 {
XinZhangMS 0:f7f1f0d76dd6 415 /* Codes_SRS_WSIO_01_167: [ If `on_underlying_ws_peer_closed` is called with a NULL context it shall do nothing. ]*/
XinZhangMS 0:f7f1f0d76dd6 416 LogError("NULL context for on_underlying_ws_peer_closed");
XinZhangMS 0:f7f1f0d76dd6 417 }
XinZhangMS 0:f7f1f0d76dd6 418 else
XinZhangMS 0:f7f1f0d76dd6 419 {
XinZhangMS 0:f7f1f0d76dd6 420 WSIO_INSTANCE* wsio_instance = (WSIO_INSTANCE*)context;
XinZhangMS 0:f7f1f0d76dd6 421
XinZhangMS 0:f7f1f0d76dd6 422 switch (wsio_instance->io_state)
XinZhangMS 0:f7f1f0d76dd6 423 {
XinZhangMS 0:f7f1f0d76dd6 424 default:
XinZhangMS 0:f7f1f0d76dd6 425 /* Codes_SRS_WSIO_01_166: [ When `on_underlying_ws_peer_closed` and the state of the IO is OPEN an error shall be indicated by calling the `on_io_error` callback passed to `wsio_open`. ]*/
XinZhangMS 0:f7f1f0d76dd6 426 case IO_STATE_OPEN:
XinZhangMS 0:f7f1f0d76dd6 427 /* Codes_SRS_WSIO_01_169: [ When `on_underlying_ws_peer_closed` and the state of the IO is CLOSING an error shall be indicated by calling the `on_io_error` callback passed to `wsio_open`. ]*/
XinZhangMS 0:f7f1f0d76dd6 428 case IO_STATE_CLOSING:
XinZhangMS 0:f7f1f0d76dd6 429 indicate_error(wsio_instance);
XinZhangMS 0:f7f1f0d76dd6 430 break;
XinZhangMS 0:f7f1f0d76dd6 431
XinZhangMS 0:f7f1f0d76dd6 432 case IO_STATE_NOT_OPEN:
XinZhangMS 0:f7f1f0d76dd6 433 // Codes_SRS_WSIO_07_001: [When `on_underlying_ws_peer_closed` and the state of the IO is NOT_OPEN an error will be raised and the io_state will remain as NOT_OPEN]
XinZhangMS 0:f7f1f0d76dd6 434 indicate_error(wsio_instance);
XinZhangMS 0:f7f1f0d76dd6 435 wsio_instance->io_state = IO_STATE_NOT_OPEN;
XinZhangMS 0:f7f1f0d76dd6 436 break;
XinZhangMS 0:f7f1f0d76dd6 437
XinZhangMS 0:f7f1f0d76dd6 438 case IO_STATE_OPENING:
XinZhangMS 0:f7f1f0d76dd6 439 /* Codes_SRS_WSIO_01_170: [ When `on_underlying_ws_peer_closed` and the state of the IO is OPENING an error shall be indicated by calling the `on_io_open_complete` callback passed to `wsio_open` with the error code `IO_OPEN_ERROR`. ]*/
XinZhangMS 0:f7f1f0d76dd6 440 wsio_instance->io_state = IO_STATE_NOT_OPEN;
XinZhangMS 0:f7f1f0d76dd6 441 indicate_open_complete(wsio_instance, IO_OPEN_ERROR);
XinZhangMS 0:f7f1f0d76dd6 442 break;
XinZhangMS 0:f7f1f0d76dd6 443 }
XinZhangMS 0:f7f1f0d76dd6 444 }
XinZhangMS 0:f7f1f0d76dd6 445 }
XinZhangMS 0:f7f1f0d76dd6 446
XinZhangMS 0:f7f1f0d76dd6 447 static void on_underlying_ws_error(void* context, WS_ERROR ws_error)
XinZhangMS 0:f7f1f0d76dd6 448 {
XinZhangMS 0:f7f1f0d76dd6 449 (void)ws_error;
XinZhangMS 0:f7f1f0d76dd6 450 /* Don't have much to do with the error here */
XinZhangMS 0:f7f1f0d76dd6 451 LogError("on_underlying_ws_error called with error code %d", (int)ws_error);
XinZhangMS 0:f7f1f0d76dd6 452
XinZhangMS 0:f7f1f0d76dd6 453 if (context == NULL)
XinZhangMS 0:f7f1f0d76dd6 454 {
XinZhangMS 0:f7f1f0d76dd6 455 /* Codes_SRS_WSIO_01_135: [ When `on_underlying_ws_error` is called with a NULL context, it shall do nothing. ]*/
XinZhangMS 0:f7f1f0d76dd6 456 LogError("NULL context in on_underlying_ws_error");
XinZhangMS 0:f7f1f0d76dd6 457 }
XinZhangMS 0:f7f1f0d76dd6 458 else
XinZhangMS 0:f7f1f0d76dd6 459 {
XinZhangMS 0:f7f1f0d76dd6 460 WSIO_INSTANCE* wsio_instance = (WSIO_INSTANCE*)context;
XinZhangMS 0:f7f1f0d76dd6 461
XinZhangMS 0:f7f1f0d76dd6 462 if (wsio_instance->io_state == IO_STATE_OPENING)
XinZhangMS 0:f7f1f0d76dd6 463 {
XinZhangMS 0:f7f1f0d76dd6 464 /* Codes_SRS_WSIO_01_123: [ When calling `on_io_error`, the `on_io_error_context` argument given in `wsio_open` shall be passed to the callback `on_io_error`. ]*/
XinZhangMS 0:f7f1f0d76dd6 465 wsio_instance->on_io_open_complete(wsio_instance->on_io_open_complete_context, IO_OPEN_ERROR);
XinZhangMS 0:f7f1f0d76dd6 466 wsio_instance->io_state = IO_STATE_NOT_OPEN;
XinZhangMS 0:f7f1f0d76dd6 467 }
XinZhangMS 0:f7f1f0d76dd6 468 else
XinZhangMS 0:f7f1f0d76dd6 469 {
XinZhangMS 0:f7f1f0d76dd6 470 /* Codes_SRS_WSIO_01_123: [ When calling `on_io_error`, the `on_io_error_context` argument given in `wsio_open` shall be passed to the callback `on_io_error`. ]*/
XinZhangMS 0:f7f1f0d76dd6 471 wsio_instance->on_io_error(wsio_instance->on_io_error_context);
XinZhangMS 0:f7f1f0d76dd6 472 }
XinZhangMS 0:f7f1f0d76dd6 473 }
XinZhangMS 0:f7f1f0d76dd6 474 }
XinZhangMS 0:f7f1f0d76dd6 475
XinZhangMS 0:f7f1f0d76dd6 476 int wsio_open(CONCRETE_IO_HANDLE ws_io, ON_IO_OPEN_COMPLETE on_io_open_complete, void* on_io_open_complete_context, ON_BYTES_RECEIVED on_bytes_received, void* on_bytes_received_context, ON_IO_ERROR on_io_error, void* on_io_error_context)
XinZhangMS 0:f7f1f0d76dd6 477 {
XinZhangMS 0:f7f1f0d76dd6 478 int result = 0;
XinZhangMS 0:f7f1f0d76dd6 479
XinZhangMS 0:f7f1f0d76dd6 480 if ((ws_io == NULL) ||
XinZhangMS 0:f7f1f0d76dd6 481 (on_io_open_complete == NULL) ||
XinZhangMS 0:f7f1f0d76dd6 482 (on_bytes_received == NULL) ||
XinZhangMS 0:f7f1f0d76dd6 483 (on_io_error == NULL))
XinZhangMS 0:f7f1f0d76dd6 484 {
XinZhangMS 0:f7f1f0d76dd6 485 /* Codes_SRS_WSIO_01_132: [ If any of the arguments `ws_io`, `on_io_open_complete`, `on_bytes_received`, `on_io_error` is NULL, `wsio_open` shall fail and return a non-zero value. ]*/
XinZhangMS 0:f7f1f0d76dd6 486 LogError("Bad arguments: ws_io=%p, on_io_open_complete=%p, on_bytes_received=%p, on_io_error=%p",
XinZhangMS 0:f7f1f0d76dd6 487 ws_io, on_io_open_complete, on_bytes_received, on_io_error);
XinZhangMS 0:f7f1f0d76dd6 488 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 489 }
XinZhangMS 0:f7f1f0d76dd6 490 else
XinZhangMS 0:f7f1f0d76dd6 491 {
XinZhangMS 0:f7f1f0d76dd6 492 WSIO_INSTANCE* wsio_instance = (WSIO_INSTANCE*)ws_io;
XinZhangMS 0:f7f1f0d76dd6 493
XinZhangMS 0:f7f1f0d76dd6 494 if (wsio_instance->io_state != IO_STATE_NOT_OPEN)
XinZhangMS 0:f7f1f0d76dd6 495 {
XinZhangMS 0:f7f1f0d76dd6 496 /* Codes_SRS_WSIO_01_165: [ `wsio_open` when CLOSING shall fail and return a non-zero value. ]*/
XinZhangMS 0:f7f1f0d76dd6 497 /* Codes_SRS_WSIO_01_131: [ `wsio_open` when already OPEN or OPENING shall fail and return a non-zero value. ]*/
XinZhangMS 0:f7f1f0d76dd6 498 LogError("wsio has already been opened current state: %d", wsio_instance->io_state);
XinZhangMS 0:f7f1f0d76dd6 499 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 500 }
XinZhangMS 0:f7f1f0d76dd6 501 else
XinZhangMS 0:f7f1f0d76dd6 502 {
XinZhangMS 0:f7f1f0d76dd6 503 wsio_instance->on_bytes_received = on_bytes_received;
XinZhangMS 0:f7f1f0d76dd6 504 wsio_instance->on_bytes_received_context = on_bytes_received_context;
XinZhangMS 0:f7f1f0d76dd6 505 wsio_instance->on_io_open_complete = on_io_open_complete;
XinZhangMS 0:f7f1f0d76dd6 506 wsio_instance->on_io_open_complete_context = on_io_open_complete_context;
XinZhangMS 0:f7f1f0d76dd6 507 wsio_instance->on_io_error = on_io_error;
XinZhangMS 0:f7f1f0d76dd6 508 wsio_instance->on_io_error_context = on_io_error_context;
XinZhangMS 0:f7f1f0d76dd6 509
XinZhangMS 0:f7f1f0d76dd6 510 wsio_instance->io_state = IO_STATE_OPENING;
XinZhangMS 0:f7f1f0d76dd6 511
XinZhangMS 0:f7f1f0d76dd6 512 /* Codes_SRS_WSIO_01_082: [ `wsio_open` shall open the underlying uws instance by calling `uws_client_open_async` and providing the uws handle created in `wsio_create` as argument. ] */
XinZhangMS 0:f7f1f0d76dd6 513 if (uws_client_open_async(wsio_instance->uws, on_underlying_ws_open_complete, wsio_instance, on_underlying_ws_frame_received, wsio_instance, on_underlying_ws_peer_closed, wsio_instance, on_underlying_ws_error, wsio_instance) != 0)
XinZhangMS 0:f7f1f0d76dd6 514 {
XinZhangMS 0:f7f1f0d76dd6 515 /* Codes_SRS_WSIO_01_084: [ If opening the underlying uws instance fails then `wsio_open` shall fail and return a non-zero value. ]*/
XinZhangMS 0:f7f1f0d76dd6 516 LogError("Opening the uws instance failed.");
XinZhangMS 0:f7f1f0d76dd6 517 wsio_instance->io_state = IO_STATE_NOT_OPEN;
XinZhangMS 0:f7f1f0d76dd6 518 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 519 }
XinZhangMS 0:f7f1f0d76dd6 520 else
XinZhangMS 0:f7f1f0d76dd6 521 {
XinZhangMS 0:f7f1f0d76dd6 522 /* Codes_SRS_WSIO_01_083: [ On success, `wsio_open` shall return 0. ]*/
XinZhangMS 0:f7f1f0d76dd6 523 result = 0;
XinZhangMS 0:f7f1f0d76dd6 524 }
XinZhangMS 0:f7f1f0d76dd6 525 }
XinZhangMS 0:f7f1f0d76dd6 526 }
XinZhangMS 0:f7f1f0d76dd6 527
XinZhangMS 0:f7f1f0d76dd6 528 return result;
XinZhangMS 0:f7f1f0d76dd6 529 }
XinZhangMS 0:f7f1f0d76dd6 530
XinZhangMS 0:f7f1f0d76dd6 531 int wsio_close(CONCRETE_IO_HANDLE ws_io, ON_IO_CLOSE_COMPLETE on_io_close_complete, void* on_io_close_complete_context)
XinZhangMS 0:f7f1f0d76dd6 532 {
XinZhangMS 0:f7f1f0d76dd6 533 int result = 0;
XinZhangMS 0:f7f1f0d76dd6 534
XinZhangMS 0:f7f1f0d76dd6 535 if (ws_io == NULL)
XinZhangMS 0:f7f1f0d76dd6 536 {
XinZhangMS 0:f7f1f0d76dd6 537 /* Codes_SRS_WSIO_01_086: [ if `ws_io` is NULL, `wsio_close` shall return a non-zero value. ]*/
XinZhangMS 0:f7f1f0d76dd6 538 LogError("NULL handle");
XinZhangMS 0:f7f1f0d76dd6 539 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 540 }
XinZhangMS 0:f7f1f0d76dd6 541 else
XinZhangMS 0:f7f1f0d76dd6 542 {
XinZhangMS 0:f7f1f0d76dd6 543 WSIO_INSTANCE* wsio_instance = (WSIO_INSTANCE*)ws_io;
XinZhangMS 0:f7f1f0d76dd6 544
XinZhangMS 0:f7f1f0d76dd6 545 if (internal_close(wsio_instance, on_io_close_complete, on_io_close_complete_context) != 0)
XinZhangMS 0:f7f1f0d76dd6 546 {
XinZhangMS 0:f7f1f0d76dd6 547 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 548 }
XinZhangMS 0:f7f1f0d76dd6 549 else
XinZhangMS 0:f7f1f0d76dd6 550 {
XinZhangMS 0:f7f1f0d76dd6 551 result = 0;
XinZhangMS 0:f7f1f0d76dd6 552 }
XinZhangMS 0:f7f1f0d76dd6 553 }
XinZhangMS 0:f7f1f0d76dd6 554
XinZhangMS 0:f7f1f0d76dd6 555 return result;
XinZhangMS 0:f7f1f0d76dd6 556 }
XinZhangMS 0:f7f1f0d76dd6 557
XinZhangMS 0:f7f1f0d76dd6 558 int wsio_send(CONCRETE_IO_HANDLE ws_io, const void* buffer, size_t size, ON_SEND_COMPLETE on_send_complete, void* callback_context)
XinZhangMS 0:f7f1f0d76dd6 559 {
XinZhangMS 0:f7f1f0d76dd6 560 int result;
XinZhangMS 0:f7f1f0d76dd6 561
XinZhangMS 0:f7f1f0d76dd6 562 /* Codes_SRS_WSIO_01_100: [ If any of the arguments `ws_io` or `buffer` are NULL, `wsio_send` shall fail and return a non-zero value. ]*/
XinZhangMS 0:f7f1f0d76dd6 563 if ((ws_io == NULL) ||
XinZhangMS 0:f7f1f0d76dd6 564 (buffer == NULL) ||
XinZhangMS 0:f7f1f0d76dd6 565 /* Codes_SRS_WSIO_01_101: [ If `size` is zero then `wsio_send` shall fail and return a non-zero value. ]*/
XinZhangMS 0:f7f1f0d76dd6 566 (size == 0))
XinZhangMS 0:f7f1f0d76dd6 567 {
XinZhangMS 0:f7f1f0d76dd6 568 LogError("Bad arguments: ws_io=%p, buffer=%p, size=%u",
XinZhangMS 0:f7f1f0d76dd6 569 ws_io, buffer, (unsigned int)size);
XinZhangMS 0:f7f1f0d76dd6 570 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 571 }
XinZhangMS 0:f7f1f0d76dd6 572 else
XinZhangMS 0:f7f1f0d76dd6 573 {
XinZhangMS 0:f7f1f0d76dd6 574 WSIO_INSTANCE* wsio_instance = (WSIO_INSTANCE*)ws_io;
XinZhangMS 0:f7f1f0d76dd6 575
XinZhangMS 0:f7f1f0d76dd6 576 if (wsio_instance->io_state != IO_STATE_OPEN)
XinZhangMS 0:f7f1f0d76dd6 577 {
XinZhangMS 0:f7f1f0d76dd6 578 /* Codes_SRS_WSIO_01_099: [ If the wsio is not OPEN (open has not been called or is still in progress) then `wsio_send` shall fail and return a non-zero value. ]*/
XinZhangMS 0:f7f1f0d76dd6 579 LogError("Attempting to send when not open");
XinZhangMS 0:f7f1f0d76dd6 580 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 581 }
XinZhangMS 0:f7f1f0d76dd6 582 else
XinZhangMS 0:f7f1f0d76dd6 583 {
XinZhangMS 0:f7f1f0d76dd6 584 LIST_ITEM_HANDLE new_item;
XinZhangMS 0:f7f1f0d76dd6 585 PENDING_IO* pending_socket_io = (PENDING_IO*)malloc(sizeof(PENDING_IO));
XinZhangMS 0:f7f1f0d76dd6 586 if (pending_socket_io == NULL)
XinZhangMS 0:f7f1f0d76dd6 587 {
XinZhangMS 0:f7f1f0d76dd6 588 /* Codes_SRS_WSIO_01_134: [ If allocating memory for the pending IO data fails, `wsio_send` shall fail and return a non-zero value. ]*/
XinZhangMS 0:f7f1f0d76dd6 589 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 590 }
XinZhangMS 0:f7f1f0d76dd6 591 else
XinZhangMS 0:f7f1f0d76dd6 592 {
XinZhangMS 0:f7f1f0d76dd6 593 /* Codes_SRS_WSIO_01_103: [ The entry shall contain the `on_send_complete` callback and its context. ]*/
XinZhangMS 0:f7f1f0d76dd6 594 pending_socket_io->on_send_complete = on_send_complete;
XinZhangMS 0:f7f1f0d76dd6 595 pending_socket_io->callback_context = callback_context;
XinZhangMS 0:f7f1f0d76dd6 596 pending_socket_io->wsio = wsio_instance;
XinZhangMS 0:f7f1f0d76dd6 597
XinZhangMS 0:f7f1f0d76dd6 598 /* Codes_SRS_WSIO_01_102: [ An entry shall be queued in the singly linked list by calling `singlylinkedlist_add`. ]*/
XinZhangMS 0:f7f1f0d76dd6 599 if ((new_item = singlylinkedlist_add(wsio_instance->pending_io_list, pending_socket_io)) == NULL)
XinZhangMS 0:f7f1f0d76dd6 600 {
XinZhangMS 0:f7f1f0d76dd6 601 /* Codes_SRS_WSIO_01_104: [ If `singlylinkedlist_add` fails, `wsio_send` shall fail and return a non-zero value. ]*/
XinZhangMS 0:f7f1f0d76dd6 602 free(pending_socket_io);
XinZhangMS 0:f7f1f0d76dd6 603 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 604 }
XinZhangMS 0:f7f1f0d76dd6 605 else
XinZhangMS 0:f7f1f0d76dd6 606 {
XinZhangMS 0:f7f1f0d76dd6 607 /* Codes_SRS_WSIO_01_095: [ `wsio_send` shall call `uws_client_send_frame_async`, passing the `buffer` and `size` arguments as they are: ]*/
XinZhangMS 0:f7f1f0d76dd6 608 /* Codes_SRS_WSIO_01_097: [ The `is_final` argument shall be set to true. ]*/
XinZhangMS 0:f7f1f0d76dd6 609 /* Codes_SRS_WSIO_01_096: [ The frame type used shall be `WS_FRAME_TYPE_BINARY`. ]*/
XinZhangMS 0:f7f1f0d76dd6 610 if (uws_client_send_frame_async(wsio_instance->uws, WS_FRAME_TYPE_BINARY, (const unsigned char*)buffer, size, true, on_underlying_ws_send_frame_complete, new_item) != 0)
XinZhangMS 0:f7f1f0d76dd6 611 {
XinZhangMS 0:f7f1f0d76dd6 612 if (singlylinkedlist_remove(wsio_instance->pending_io_list, new_item) != 0)
XinZhangMS 0:f7f1f0d76dd6 613 {
XinZhangMS 0:f7f1f0d76dd6 614 LogError("Failed removing pending IO from linked list.");
XinZhangMS 0:f7f1f0d76dd6 615 }
XinZhangMS 0:f7f1f0d76dd6 616
XinZhangMS 0:f7f1f0d76dd6 617 free(pending_socket_io);
XinZhangMS 0:f7f1f0d76dd6 618 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 619 }
XinZhangMS 0:f7f1f0d76dd6 620 else
XinZhangMS 0:f7f1f0d76dd6 621 {
XinZhangMS 0:f7f1f0d76dd6 622 /* Codes_SRS_WSIO_01_098: [ On success, `wsio_send` shall return 0. ]*/
XinZhangMS 0:f7f1f0d76dd6 623 result = 0;
XinZhangMS 0:f7f1f0d76dd6 624 }
XinZhangMS 0:f7f1f0d76dd6 625 }
XinZhangMS 0:f7f1f0d76dd6 626 }
XinZhangMS 0:f7f1f0d76dd6 627 }
XinZhangMS 0:f7f1f0d76dd6 628 }
XinZhangMS 0:f7f1f0d76dd6 629
XinZhangMS 0:f7f1f0d76dd6 630 return result;
XinZhangMS 0:f7f1f0d76dd6 631 }
XinZhangMS 0:f7f1f0d76dd6 632
XinZhangMS 0:f7f1f0d76dd6 633 void wsio_dowork(CONCRETE_IO_HANDLE ws_io)
XinZhangMS 0:f7f1f0d76dd6 634 {
XinZhangMS 0:f7f1f0d76dd6 635 if (ws_io == NULL)
XinZhangMS 0:f7f1f0d76dd6 636 {
XinZhangMS 0:f7f1f0d76dd6 637 /* Codes_SRS_WSIO_01_107: [ If the `ws_io` argument is NULL, `wsio_dowork` shall do nothing. ]*/
XinZhangMS 0:f7f1f0d76dd6 638 LogError("NULL handle");
XinZhangMS 0:f7f1f0d76dd6 639 }
XinZhangMS 0:f7f1f0d76dd6 640 else
XinZhangMS 0:f7f1f0d76dd6 641 {
XinZhangMS 0:f7f1f0d76dd6 642 WSIO_INSTANCE* wsio_instance = (WSIO_INSTANCE*)ws_io;
XinZhangMS 0:f7f1f0d76dd6 643
XinZhangMS 0:f7f1f0d76dd6 644 /* Codes_SRS_WSIO_01_108: [ If the IO is not yet open, `wsio_dowork` shall do nothing. ]*/
XinZhangMS 0:f7f1f0d76dd6 645 if (wsio_instance->io_state != IO_STATE_NOT_OPEN)
XinZhangMS 0:f7f1f0d76dd6 646 {
XinZhangMS 0:f7f1f0d76dd6 647 /* Codes_SRS_WSIO_01_106: [ `wsio_dowork` shall call `uws_client_dowork` with the uws handle created in `wsio_create`. ]*/
XinZhangMS 0:f7f1f0d76dd6 648 uws_client_dowork(wsio_instance->uws);
XinZhangMS 0:f7f1f0d76dd6 649 }
XinZhangMS 0:f7f1f0d76dd6 650 }
XinZhangMS 0:f7f1f0d76dd6 651 }
XinZhangMS 0:f7f1f0d76dd6 652
XinZhangMS 0:f7f1f0d76dd6 653 int wsio_setoption(CONCRETE_IO_HANDLE ws_io, const char* optionName, const void* value)
XinZhangMS 0:f7f1f0d76dd6 654 {
XinZhangMS 0:f7f1f0d76dd6 655 int result;
XinZhangMS 0:f7f1f0d76dd6 656 if (
XinZhangMS 0:f7f1f0d76dd6 657 /* Codes_SRS_WSIO_01_109: [ If any of the arguments `ws_io` or `option_name` is NULL `wsio_setoption` shall return a non-zero value. ]*/
XinZhangMS 0:f7f1f0d76dd6 658 (ws_io == NULL) ||
XinZhangMS 0:f7f1f0d76dd6 659 (optionName == NULL)
XinZhangMS 0:f7f1f0d76dd6 660 )
XinZhangMS 0:f7f1f0d76dd6 661 {
XinZhangMS 0:f7f1f0d76dd6 662 LogError("Bad parameters: ws_io=%p, optionName=%p",
XinZhangMS 0:f7f1f0d76dd6 663 ws_io, optionName);
XinZhangMS 0:f7f1f0d76dd6 664 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 665 }
XinZhangMS 0:f7f1f0d76dd6 666 else
XinZhangMS 0:f7f1f0d76dd6 667 {
XinZhangMS 0:f7f1f0d76dd6 668 WSIO_INSTANCE* wsio_instance = (WSIO_INSTANCE*)ws_io;
XinZhangMS 0:f7f1f0d76dd6 669
XinZhangMS 0:f7f1f0d76dd6 670 if (strcmp(WSIO_OPTIONS, optionName) == 0)
XinZhangMS 0:f7f1f0d76dd6 671 {
XinZhangMS 0:f7f1f0d76dd6 672 /* Codes_SRS_WSIO_01_183: [ If the option name is `WSIOOptions` then `wsio_setoption` shall call `OptionHandler_FeedOptions` and pass to it the underlying IO handle and the `value` argument. ]*/
XinZhangMS 0:f7f1f0d76dd6 673 if (OptionHandler_FeedOptions((OPTIONHANDLER_HANDLE)value, wsio_instance->uws) != OPTIONHANDLER_OK)
XinZhangMS 0:f7f1f0d76dd6 674 {
XinZhangMS 0:f7f1f0d76dd6 675 /* Codes_SRS_WSIO_01_184: [ If `OptionHandler_FeedOptions` fails, `wsio_setoption` shall fail and return a non-zero value. ]*/
XinZhangMS 0:f7f1f0d76dd6 676 LogError("unable to OptionHandler_FeedOptions");
XinZhangMS 0:f7f1f0d76dd6 677 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 678 }
XinZhangMS 0:f7f1f0d76dd6 679 else
XinZhangMS 0:f7f1f0d76dd6 680 {
XinZhangMS 0:f7f1f0d76dd6 681 /* Codes_SRS_WSIO_01_158: [ On success, `wsio_setoption` shall return 0. ]*/
XinZhangMS 0:f7f1f0d76dd6 682 result = 0;
XinZhangMS 0:f7f1f0d76dd6 683 }
XinZhangMS 0:f7f1f0d76dd6 684 }
XinZhangMS 0:f7f1f0d76dd6 685 else
XinZhangMS 0:f7f1f0d76dd6 686 {
XinZhangMS 0:f7f1f0d76dd6 687 /* Codes_SRS_WSIO_01_156: [ Otherwise all options shall be passed as they are to uws by calling `uws_client_set_option`. ]*/
XinZhangMS 0:f7f1f0d76dd6 688 if (uws_client_set_option(wsio_instance->uws, optionName, value) != 0)
XinZhangMS 0:f7f1f0d76dd6 689 {
XinZhangMS 0:f7f1f0d76dd6 690 /* Codes_SRS_WSIO_01_157: [ If `uws_client_set_option` fails, `wsio_setoption` shall fail and return a non-zero value. ]*/
XinZhangMS 0:f7f1f0d76dd6 691 LogError("Setting the option %s failed", optionName);
XinZhangMS 0:f7f1f0d76dd6 692 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 693 }
XinZhangMS 0:f7f1f0d76dd6 694 else
XinZhangMS 0:f7f1f0d76dd6 695 {
XinZhangMS 0:f7f1f0d76dd6 696 /* Codes_SRS_WSIO_01_158: [ On success, `wsio_setoption` shall return 0. ]*/
XinZhangMS 0:f7f1f0d76dd6 697 result = 0;
XinZhangMS 0:f7f1f0d76dd6 698 }
XinZhangMS 0:f7f1f0d76dd6 699 }
XinZhangMS 0:f7f1f0d76dd6 700 }
XinZhangMS 0:f7f1f0d76dd6 701
XinZhangMS 0:f7f1f0d76dd6 702 return result;
XinZhangMS 0:f7f1f0d76dd6 703 }
XinZhangMS 0:f7f1f0d76dd6 704
XinZhangMS 0:f7f1f0d76dd6 705 static void* wsio_clone_option(const char* name, const void* value)
XinZhangMS 0:f7f1f0d76dd6 706 {
XinZhangMS 0:f7f1f0d76dd6 707 void *result;
XinZhangMS 0:f7f1f0d76dd6 708
XinZhangMS 0:f7f1f0d76dd6 709 if (
XinZhangMS 0:f7f1f0d76dd6 710 (name == NULL) ||
XinZhangMS 0:f7f1f0d76dd6 711 (value == NULL)
XinZhangMS 0:f7f1f0d76dd6 712 )
XinZhangMS 0:f7f1f0d76dd6 713 {
XinZhangMS 0:f7f1f0d76dd6 714 /* Codes_SRS_WSIO_01_174: [ If `wsio_clone_option` is called with NULL `name` or `value` it shall return NULL. ]*/
XinZhangMS 0:f7f1f0d76dd6 715 LogError("invalid argument detected: const char* name=%p, const void* value=%p", name, value);
XinZhangMS 0:f7f1f0d76dd6 716 result = NULL;
XinZhangMS 0:f7f1f0d76dd6 717 }
XinZhangMS 0:f7f1f0d76dd6 718 else
XinZhangMS 0:f7f1f0d76dd6 719 {
XinZhangMS 0:f7f1f0d76dd6 720 if (strcmp(name, WSIO_OPTIONS) == 0)
XinZhangMS 0:f7f1f0d76dd6 721 {
XinZhangMS 0:f7f1f0d76dd6 722 /* Codes_SRS_WSIO_01_171: [** `wsio_clone_option` called with `name` being `WSIOOptions` shall return the same value. ]*/
XinZhangMS 0:f7f1f0d76dd6 723 result = (void*)value;
XinZhangMS 0:f7f1f0d76dd6 724 }
XinZhangMS 0:f7f1f0d76dd6 725 else
XinZhangMS 0:f7f1f0d76dd6 726 {
XinZhangMS 0:f7f1f0d76dd6 727 /* Codes_SRS_WSIO_01_173: [ `wsio_clone_option` called with any other option name than `WSIOOptions` shall return NULL. ]*/
XinZhangMS 0:f7f1f0d76dd6 728 LogError("unknown option: %s", name);
XinZhangMS 0:f7f1f0d76dd6 729 result = NULL;
XinZhangMS 0:f7f1f0d76dd6 730 }
XinZhangMS 0:f7f1f0d76dd6 731 }
XinZhangMS 0:f7f1f0d76dd6 732
XinZhangMS 0:f7f1f0d76dd6 733 return result;
XinZhangMS 0:f7f1f0d76dd6 734 }
XinZhangMS 0:f7f1f0d76dd6 735
XinZhangMS 0:f7f1f0d76dd6 736 static void wsio_destroy_option(const char* name, const void* value)
XinZhangMS 0:f7f1f0d76dd6 737 {
XinZhangMS 0:f7f1f0d76dd6 738 if (
XinZhangMS 0:f7f1f0d76dd6 739 (name == NULL) ||
XinZhangMS 0:f7f1f0d76dd6 740 (value == NULL)
XinZhangMS 0:f7f1f0d76dd6 741 )
XinZhangMS 0:f7f1f0d76dd6 742 {
XinZhangMS 0:f7f1f0d76dd6 743 /* Codes_SRS_WSIO_01_177: [ If `wsio_destroy_option` is called with NULL `name` or `value` it shall do nothing. ]*/
XinZhangMS 0:f7f1f0d76dd6 744 LogError("Bad arguments: const char* name=%p, const void* value=%p", name, value);
XinZhangMS 0:f7f1f0d76dd6 745 }
XinZhangMS 0:f7f1f0d76dd6 746 else
XinZhangMS 0:f7f1f0d76dd6 747 {
XinZhangMS 0:f7f1f0d76dd6 748 if (strcmp(name, WSIO_OPTIONS) == 0)
XinZhangMS 0:f7f1f0d76dd6 749 {
XinZhangMS 0:f7f1f0d76dd6 750 /* Codes_SRS_WSIO_01_175: [ `wsio_destroy_option` called with the option `name` being `WSIOOptions` shall destroy the value by calling `OptionHandler_Destroy`. ]*/
XinZhangMS 0:f7f1f0d76dd6 751 OptionHandler_Destroy((OPTIONHANDLER_HANDLE)value);
XinZhangMS 0:f7f1f0d76dd6 752 }
XinZhangMS 0:f7f1f0d76dd6 753 else
XinZhangMS 0:f7f1f0d76dd6 754 {
XinZhangMS 0:f7f1f0d76dd6 755 /* Codes_SRS_WSIO_01_176: [ If `wsio_destroy_option` is called with any other `name` it shall do nothing. ]*/
XinZhangMS 0:f7f1f0d76dd6 756 LogError("unknown option: %s", name);
XinZhangMS 0:f7f1f0d76dd6 757 }
XinZhangMS 0:f7f1f0d76dd6 758 }
XinZhangMS 0:f7f1f0d76dd6 759 }
XinZhangMS 0:f7f1f0d76dd6 760
XinZhangMS 0:f7f1f0d76dd6 761 OPTIONHANDLER_HANDLE wsio_retrieveoptions(CONCRETE_IO_HANDLE handle)
XinZhangMS 0:f7f1f0d76dd6 762 {
XinZhangMS 0:f7f1f0d76dd6 763 OPTIONHANDLER_HANDLE result;
XinZhangMS 0:f7f1f0d76dd6 764 if (handle == NULL)
XinZhangMS 0:f7f1f0d76dd6 765 {
XinZhangMS 0:f7f1f0d76dd6 766 /* Codes_SRS_WSIO_01_118: [ If parameter `handle` is `NULL` then `wsio_retrieveoptions` shall fail and return NULL. ]*/
XinZhangMS 0:f7f1f0d76dd6 767 LogError("parameter handle is NULL");
XinZhangMS 0:f7f1f0d76dd6 768 result = NULL;
XinZhangMS 0:f7f1f0d76dd6 769 }
XinZhangMS 0:f7f1f0d76dd6 770 else
XinZhangMS 0:f7f1f0d76dd6 771 {
XinZhangMS 0:f7f1f0d76dd6 772 WSIO_INSTANCE* wsio = (WSIO_INSTANCE*)handle;
XinZhangMS 0:f7f1f0d76dd6 773
XinZhangMS 0:f7f1f0d76dd6 774 /* Codes_SRS_WSIO_01_119: [ `wsio_retrieveoptions` shall call `OptionHandler_Create` to produce an `OPTIONHANDLER_HANDLE` and on success return the new `OPTIONHANDLER_HANDLE` handle. ]*/
XinZhangMS 0:f7f1f0d76dd6 775 result = OptionHandler_Create(wsio_clone_option, wsio_destroy_option, wsio_setoption);
XinZhangMS 0:f7f1f0d76dd6 776 if (result == NULL)
XinZhangMS 0:f7f1f0d76dd6 777 {
XinZhangMS 0:f7f1f0d76dd6 778 /* Codes_SRS_WSIO_01_120: [ If `OptionHandler_Create` fails then `wsio_retrieveoptions` shall fail and return NULL. ]*/
XinZhangMS 0:f7f1f0d76dd6 779 LogError("OptionHandler_Create failed");
XinZhangMS 0:f7f1f0d76dd6 780 }
XinZhangMS 0:f7f1f0d76dd6 781 else
XinZhangMS 0:f7f1f0d76dd6 782 {
XinZhangMS 0:f7f1f0d76dd6 783 /* Codes_SRS_WSIO_01_179: [ When calling `uws_client_retrieve_options` the uws client handle shall be passed to it. ]*/
XinZhangMS 0:f7f1f0d76dd6 784 /* Codes_SRS_WSIO_01_178: [ `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 `uws_client_retrieve_options`. ]*/
XinZhangMS 0:f7f1f0d76dd6 785 OPTIONHANDLER_HANDLE concreteOptions = uws_client_retrieve_options(wsio->uws);
XinZhangMS 0:f7f1f0d76dd6 786 if (concreteOptions == NULL)
XinZhangMS 0:f7f1f0d76dd6 787 {
XinZhangMS 0:f7f1f0d76dd6 788 /* Codes_SRS_WSIO_01_180: [ If `uws_client_retrieve_options` fails, `uws_client_retrieve_options` shall fail and return NULL. ]*/
XinZhangMS 0:f7f1f0d76dd6 789 LogError("unable to concrete_io_retrieveoptions");
XinZhangMS 0:f7f1f0d76dd6 790 OptionHandler_Destroy(result);
XinZhangMS 0:f7f1f0d76dd6 791 result = NULL;
XinZhangMS 0:f7f1f0d76dd6 792 }
XinZhangMS 0:f7f1f0d76dd6 793 else
XinZhangMS 0:f7f1f0d76dd6 794 {
XinZhangMS 0:f7f1f0d76dd6 795 /* Codes_SRS_WSIO_01_181: [ Adding the option shall be done by calling `OptionHandler_AddOption`. ]*/
XinZhangMS 0:f7f1f0d76dd6 796 if (OptionHandler_AddOption(result, WSIO_OPTIONS, concreteOptions) != OPTIONHANDLER_OK)
XinZhangMS 0:f7f1f0d76dd6 797 {
XinZhangMS 0:f7f1f0d76dd6 798 /* Codes_SRS_WSIO_01_182: [ If `OptionHandler_AddOption` fails, `uws_client_retrieve_options` shall fail and return NULL. ]*/
XinZhangMS 0:f7f1f0d76dd6 799 LogError("unable to OptionHandler_AddOption");
XinZhangMS 0:f7f1f0d76dd6 800 OptionHandler_Destroy(concreteOptions);
XinZhangMS 0:f7f1f0d76dd6 801 OptionHandler_Destroy(result);
XinZhangMS 0:f7f1f0d76dd6 802 result = NULL;
XinZhangMS 0:f7f1f0d76dd6 803 }
XinZhangMS 0:f7f1f0d76dd6 804 }
XinZhangMS 0:f7f1f0d76dd6 805 }
XinZhangMS 0:f7f1f0d76dd6 806 }
XinZhangMS 0:f7f1f0d76dd6 807
XinZhangMS 0:f7f1f0d76dd6 808 return result;
XinZhangMS 0:f7f1f0d76dd6 809 }
XinZhangMS 0:f7f1f0d76dd6 810
XinZhangMS 0:f7f1f0d76dd6 811 static const IO_INTERFACE_DESCRIPTION ws_io_interface_description =
XinZhangMS 0:f7f1f0d76dd6 812 {
XinZhangMS 0:f7f1f0d76dd6 813 wsio_retrieveoptions,
XinZhangMS 0:f7f1f0d76dd6 814 wsio_create,
XinZhangMS 0:f7f1f0d76dd6 815 wsio_destroy,
XinZhangMS 0:f7f1f0d76dd6 816 wsio_open,
XinZhangMS 0:f7f1f0d76dd6 817 wsio_close,
XinZhangMS 0:f7f1f0d76dd6 818 wsio_send,
XinZhangMS 0:f7f1f0d76dd6 819 wsio_dowork,
XinZhangMS 0:f7f1f0d76dd6 820 wsio_setoption
XinZhangMS 0:f7f1f0d76dd6 821 };
XinZhangMS 0:f7f1f0d76dd6 822
XinZhangMS 0:f7f1f0d76dd6 823 const IO_INTERFACE_DESCRIPTION* wsio_get_interface_description(void)
XinZhangMS 0:f7f1f0d76dd6 824 {
XinZhangMS 0:f7f1f0d76dd6 825 return &ws_io_interface_description;
XinZhangMS 0:f7f1f0d76dd6 826 }