Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
c-utility/src/wsio.c@0:f7f1f0d76dd6, 2018-08-23 (annotated)
- 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?
| User | Revision | Line number | New 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 | } |