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.
mbed-cloud-client/update-client-hub/modules/source-http-socket/source/arm_uc_http_socket_private.c@2:bf2124b482f9, 2018-07-02 (annotated)
- Committer:
- MACRUM
- Date:
- Mon Jul 02 08:06:37 2018 +0000
- Revision:
- 2:bf2124b482f9
- Parent:
- 0:276e7a263c35
Update library
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
MACRUM | 0:276e7a263c35 | 1 | // ---------------------------------------------------------------------------- |
MACRUM | 0:276e7a263c35 | 2 | // Copyright 2016-2017 ARM Ltd. |
MACRUM | 0:276e7a263c35 | 3 | // |
MACRUM | 0:276e7a263c35 | 4 | // SPDX-License-Identifier: Apache-2.0 |
MACRUM | 0:276e7a263c35 | 5 | // |
MACRUM | 0:276e7a263c35 | 6 | // Licensed under the Apache License, Version 2.0 (the "License"); |
MACRUM | 0:276e7a263c35 | 7 | // you may not use this file except in compliance with the License. |
MACRUM | 0:276e7a263c35 | 8 | // You may obtain a copy of the License at |
MACRUM | 0:276e7a263c35 | 9 | // |
MACRUM | 0:276e7a263c35 | 10 | // http://www.apache.org/licenses/LICENSE-2.0 |
MACRUM | 0:276e7a263c35 | 11 | // |
MACRUM | 0:276e7a263c35 | 12 | // Unless required by applicable law or agreed to in writing, software |
MACRUM | 0:276e7a263c35 | 13 | // distributed under the License is distributed on an "AS IS" BASIS, |
MACRUM | 0:276e7a263c35 | 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
MACRUM | 0:276e7a263c35 | 15 | // See the License for the specific language governing permissions and |
MACRUM | 0:276e7a263c35 | 16 | // limitations under the License. |
MACRUM | 0:276e7a263c35 | 17 | // ---------------------------------------------------------------------------- |
MACRUM | 0:276e7a263c35 | 18 | |
MACRUM | 0:276e7a263c35 | 19 | #include "arm_uc_http_socket_private.h" |
MACRUM | 0:276e7a263c35 | 20 | |
MACRUM | 0:276e7a263c35 | 21 | #include "arm_uc_socket_help.h" |
MACRUM | 0:276e7a263c35 | 22 | |
MACRUM | 0:276e7a263c35 | 23 | #include <pal.h> |
MACRUM | 0:276e7a263c35 | 24 | |
MACRUM | 0:276e7a263c35 | 25 | #include <stdio.h> |
MACRUM | 0:276e7a263c35 | 26 | #include <string.h> |
MACRUM | 0:276e7a263c35 | 27 | #include <inttypes.h> |
MACRUM | 0:276e7a263c35 | 28 | |
MACRUM | 0:276e7a263c35 | 29 | #if !defined(ARM_UC_SOCKET_TIMEOUT_MS) |
MACRUM | 0:276e7a263c35 | 30 | #define ARM_UC_SOCKET_TIMEOUT_MS 10000 /* 10 seconds */ |
MACRUM | 0:276e7a263c35 | 31 | #endif |
MACRUM | 0:276e7a263c35 | 32 | |
MACRUM | 0:276e7a263c35 | 33 | /* Pointer to struct containing all global variables. |
MACRUM | 0:276e7a263c35 | 34 | Can be dynamically allocated and deallocated. |
MACRUM | 0:276e7a263c35 | 35 | */ |
MACRUM | 0:276e7a263c35 | 36 | static arm_uc_http_socket_context_t* context = NULL; |
MACRUM | 0:276e7a263c35 | 37 | |
MACRUM | 0:276e7a263c35 | 38 | /** |
MACRUM | 0:276e7a263c35 | 39 | * @brief Initialize Http module. |
MACRUM | 0:276e7a263c35 | 40 | * @details A memory struct is passed as well as a function pointer for event |
MACRUM | 0:276e7a263c35 | 41 | * handling. |
MACRUM | 0:276e7a263c35 | 42 | * |
MACRUM | 0:276e7a263c35 | 43 | * @param context Struct holding all global variables. |
MACRUM | 0:276e7a263c35 | 44 | * @param handler Event handler for signaling when each operation is complete. |
MACRUM | 0:276e7a263c35 | 45 | * @return Error code. |
MACRUM | 0:276e7a263c35 | 46 | */ |
MACRUM | 0:276e7a263c35 | 47 | arm_uc_error_t arm_uc_socket_initialize(arm_uc_http_socket_context_t* _context, |
MACRUM | 0:276e7a263c35 | 48 | void (*handler)(uint32_t)) |
MACRUM | 0:276e7a263c35 | 49 | { |
MACRUM | 0:276e7a263c35 | 50 | UC_SRCE_TRACE("arm_uc_socket_initialize"); |
MACRUM | 0:276e7a263c35 | 51 | |
MACRUM | 0:276e7a263c35 | 52 | /* default return value */ |
MACRUM | 0:276e7a263c35 | 53 | arm_uc_error_t result = (arm_uc_error_t){ SRCE_ERR_FAILED }; |
MACRUM | 0:276e7a263c35 | 54 | |
MACRUM | 0:276e7a263c35 | 55 | /* save global context */ |
MACRUM | 0:276e7a263c35 | 56 | context = _context; |
MACRUM | 0:276e7a263c35 | 57 | |
MACRUM | 0:276e7a263c35 | 58 | if (context) |
MACRUM | 0:276e7a263c35 | 59 | { |
MACRUM | 0:276e7a263c35 | 60 | /* initialize global variables */ |
MACRUM | 0:276e7a263c35 | 61 | context->callback_handler = handler; |
MACRUM | 0:276e7a263c35 | 62 | |
MACRUM | 0:276e7a263c35 | 63 | context->request_uri = NULL; |
MACRUM | 0:276e7a263c35 | 64 | context->request_buffer = NULL; |
MACRUM | 0:276e7a263c35 | 65 | context->request_offset = 0; |
MACRUM | 0:276e7a263c35 | 66 | context->request_type = RQST_TYPE_NONE; |
MACRUM | 0:276e7a263c35 | 67 | |
MACRUM | 0:276e7a263c35 | 68 | context->socket_state = STATE_DISCONNECTED; |
MACRUM | 0:276e7a263c35 | 69 | context->expected_event = SOCKET_EVENT_UNDEFINED; |
MACRUM | 0:276e7a263c35 | 70 | context->expected_remaining = 0; |
MACRUM | 0:276e7a263c35 | 71 | |
MACRUM | 0:276e7a263c35 | 72 | context->socket = NULL; |
MACRUM | 0:276e7a263c35 | 73 | |
MACRUM | 0:276e7a263c35 | 74 | context->isr_callback_counter = 0; |
MACRUM | 0:276e7a263c35 | 75 | |
MACRUM | 0:276e7a263c35 | 76 | context->timeout_timer_id = 0; |
MACRUM | 0:276e7a263c35 | 77 | |
MACRUM | 0:276e7a263c35 | 78 | context->cache_address.addressType = 0; |
MACRUM | 0:276e7a263c35 | 79 | memset(context->cache_address.addressData, 0, PAL_NET_MAX_ADDR_SIZE); |
MACRUM | 0:276e7a263c35 | 80 | context->cache_address_length = 0; |
MACRUM | 0:276e7a263c35 | 81 | |
MACRUM | 0:276e7a263c35 | 82 | /* set return value to success */ |
MACRUM | 0:276e7a263c35 | 83 | result = (arm_uc_error_t){ SRCE_ERR_NONE }; |
MACRUM | 0:276e7a263c35 | 84 | } |
MACRUM | 0:276e7a263c35 | 85 | |
MACRUM | 0:276e7a263c35 | 86 | return result; |
MACRUM | 0:276e7a263c35 | 87 | } |
MACRUM | 0:276e7a263c35 | 88 | |
MACRUM | 0:276e7a263c35 | 89 | /** |
MACRUM | 0:276e7a263c35 | 90 | * @brief Resets HTTP socket to uninitialized state and clears memory struct. |
MACRUM | 0:276e7a263c35 | 91 | * @details HTTP sockets must be initialized again before use. |
MACRUM | 0:276e7a263c35 | 92 | * @return Error code. |
MACRUM | 0:276e7a263c35 | 93 | */ |
MACRUM | 0:276e7a263c35 | 94 | arm_uc_error_t arm_uc_socket_terminate() |
MACRUM | 0:276e7a263c35 | 95 | { |
MACRUM | 0:276e7a263c35 | 96 | /* default return value */ |
MACRUM | 0:276e7a263c35 | 97 | arm_uc_error_t result = (arm_uc_error_t){ SRCE_ERR_FAILED }; |
MACRUM | 0:276e7a263c35 | 98 | |
MACRUM | 0:276e7a263c35 | 99 | if (context) |
MACRUM | 0:276e7a263c35 | 100 | { |
MACRUM | 0:276e7a263c35 | 101 | /* close socket */ |
MACRUM | 0:276e7a263c35 | 102 | arm_uc_socket_close(); |
MACRUM | 0:276e7a263c35 | 103 | |
MACRUM | 0:276e7a263c35 | 104 | /* reset all global variables */ |
MACRUM | 0:276e7a263c35 | 105 | context->request_uri = NULL; |
MACRUM | 0:276e7a263c35 | 106 | context->request_buffer = NULL; |
MACRUM | 0:276e7a263c35 | 107 | context->request_offset = 0; |
MACRUM | 0:276e7a263c35 | 108 | context->request_type = RQST_TYPE_NONE; |
MACRUM | 0:276e7a263c35 | 109 | |
MACRUM | 0:276e7a263c35 | 110 | context->socket_state = STATE_DISCONNECTED; |
MACRUM | 0:276e7a263c35 | 111 | context->expected_event = SOCKET_EVENT_UNDEFINED; |
MACRUM | 0:276e7a263c35 | 112 | context->expected_remaining = 0; |
MACRUM | 0:276e7a263c35 | 113 | |
MACRUM | 0:276e7a263c35 | 114 | context->socket = NULL; |
MACRUM | 0:276e7a263c35 | 115 | |
MACRUM | 0:276e7a263c35 | 116 | context = NULL; |
MACRUM | 0:276e7a263c35 | 117 | |
MACRUM | 0:276e7a263c35 | 118 | result = (arm_uc_error_t){ SRCE_ERR_NONE }; |
MACRUM | 0:276e7a263c35 | 119 | } |
MACRUM | 0:276e7a263c35 | 120 | |
MACRUM | 0:276e7a263c35 | 121 | return result; |
MACRUM | 0:276e7a263c35 | 122 | } |
MACRUM | 0:276e7a263c35 | 123 | |
MACRUM | 0:276e7a263c35 | 124 | /** |
MACRUM | 0:276e7a263c35 | 125 | * @brief Get resource at URI. |
MACRUM | 0:276e7a263c35 | 126 | * @details Download resource at URI from given offset and store in buffer. |
MACRUM | 0:276e7a263c35 | 127 | * Events are generated when download finish or on error |
MACRUM | 0:276e7a263c35 | 128 | * |
MACRUM | 0:276e7a263c35 | 129 | * @param uri Pointer to structure with resource location. |
MACRUM | 0:276e7a263c35 | 130 | * @param buffer Pointer to structure with buffer location, maxSize, and size. |
MACRUM | 0:276e7a263c35 | 131 | * @param offset Offset in resource to begin download from. |
MACRUM | 0:276e7a263c35 | 132 | * @param type Indicate what type of request that was initiated. |
MACRUM | 0:276e7a263c35 | 133 | * @return Error code. |
MACRUM | 0:276e7a263c35 | 134 | */ |
MACRUM | 0:276e7a263c35 | 135 | arm_uc_error_t arm_uc_socket_get(arm_uc_uri_t* uri, |
MACRUM | 0:276e7a263c35 | 136 | arm_uc_buffer_t* buffer, |
MACRUM | 0:276e7a263c35 | 137 | uint32_t offset, |
MACRUM | 0:276e7a263c35 | 138 | arm_uc_rqst_t type) |
MACRUM | 0:276e7a263c35 | 139 | { |
MACRUM | 0:276e7a263c35 | 140 | UC_SRCE_TRACE("arm_uc_socket_get"); |
MACRUM | 0:276e7a263c35 | 141 | |
MACRUM | 0:276e7a263c35 | 142 | /* default return value */ |
MACRUM | 0:276e7a263c35 | 143 | arm_uc_error_t result = (arm_uc_error_t){ SRCE_ERR_INVALID_PARAMETER }; |
MACRUM | 0:276e7a263c35 | 144 | |
MACRUM | 0:276e7a263c35 | 145 | /* check for NULL pointers */ |
MACRUM | 0:276e7a263c35 | 146 | if (uri && |
MACRUM | 0:276e7a263c35 | 147 | uri->scheme && |
MACRUM | 0:276e7a263c35 | 148 | uri->host && |
MACRUM | 0:276e7a263c35 | 149 | uri->path && |
MACRUM | 0:276e7a263c35 | 150 | buffer && |
MACRUM | 0:276e7a263c35 | 151 | buffer->ptr && |
MACRUM | 0:276e7a263c35 | 152 | context) |
MACRUM | 0:276e7a263c35 | 153 | { |
MACRUM | 0:276e7a263c35 | 154 | /* parameters are valid */ |
MACRUM | 0:276e7a263c35 | 155 | result.code = SRCE_ERR_NONE; |
MACRUM | 0:276e7a263c35 | 156 | |
MACRUM | 0:276e7a263c35 | 157 | /* store request */ |
MACRUM | 0:276e7a263c35 | 158 | context->request_uri = uri; |
MACRUM | 0:276e7a263c35 | 159 | context->request_buffer = buffer; |
MACRUM | 0:276e7a263c35 | 160 | context->request_offset = offset; |
MACRUM | 0:276e7a263c35 | 161 | context->request_type = type; |
MACRUM | 0:276e7a263c35 | 162 | |
MACRUM | 0:276e7a263c35 | 163 | /* clear buffer */ |
MACRUM | 0:276e7a263c35 | 164 | context->request_buffer->size = 0; |
MACRUM | 0:276e7a263c35 | 165 | |
MACRUM | 0:276e7a263c35 | 166 | UC_SRCE_TRACE("Socket State: %d", context->socket_state); |
MACRUM | 0:276e7a263c35 | 167 | |
MACRUM | 0:276e7a263c35 | 168 | /* connect socket if not already connected */ |
MACRUM | 0:276e7a263c35 | 169 | result = arm_uc_socket_connect(); |
MACRUM | 0:276e7a263c35 | 170 | } |
MACRUM | 0:276e7a263c35 | 171 | |
MACRUM | 0:276e7a263c35 | 172 | return result; |
MACRUM | 0:276e7a263c35 | 173 | } |
MACRUM | 0:276e7a263c35 | 174 | |
MACRUM | 0:276e7a263c35 | 175 | /** |
MACRUM | 0:276e7a263c35 | 176 | * @brief Connect to server set in the global URI struct. |
MACRUM | 0:276e7a263c35 | 177 | * @details Connecting generates a socket event, which automatically processes |
MACRUM | 0:276e7a263c35 | 178 | * the request passed in arm_uc_socket_get. |
MACRUM | 0:276e7a263c35 | 179 | * @return Error code. |
MACRUM | 0:276e7a263c35 | 180 | */ |
MACRUM | 0:276e7a263c35 | 181 | arm_uc_error_t arm_uc_socket_connect() |
MACRUM | 0:276e7a263c35 | 182 | { |
MACRUM | 0:276e7a263c35 | 183 | /* default return value */ |
MACRUM | 0:276e7a263c35 | 184 | arm_uc_error_t result = (arm_uc_error_t){ SRCE_ERR_FAILED }; |
MACRUM | 0:276e7a263c35 | 185 | |
MACRUM | 0:276e7a263c35 | 186 | /* NULL pointer check */ |
MACRUM | 0:276e7a263c35 | 187 | if (context && context->request_uri) |
MACRUM | 0:276e7a263c35 | 188 | { |
MACRUM | 0:276e7a263c35 | 189 | if (context->socket_state == STATE_DISCONNECTED) |
MACRUM | 0:276e7a263c35 | 190 | { |
MACRUM | 0:276e7a263c35 | 191 | result = (arm_uc_error_t){ SRCE_ERR_NONE }; |
MACRUM | 0:276e7a263c35 | 192 | |
MACRUM | 0:276e7a263c35 | 193 | /* dns loopup */ |
MACRUM | 0:276e7a263c35 | 194 | palStatus_t pal_inner = pal_getAddressInfo(context->request_uri->host, |
MACRUM | 0:276e7a263c35 | 195 | &context->cache_address, |
MACRUM | 0:276e7a263c35 | 196 | &context->cache_address_length); |
MACRUM | 0:276e7a263c35 | 197 | |
MACRUM | 0:276e7a263c35 | 198 | if (pal_inner != PAL_SUCCESS) |
MACRUM | 0:276e7a263c35 | 199 | { |
MACRUM | 0:276e7a263c35 | 200 | UC_SRCE_ERR_MSG("pal_getAddressInfo (DNS) failed"); |
MACRUM | 0:276e7a263c35 | 201 | arm_uc_socket_close(); |
MACRUM | 0:276e7a263c35 | 202 | result = (arm_uc_error_t){ SRCE_ERR_INVALID_PARAMETER }; |
MACRUM | 0:276e7a263c35 | 203 | } |
MACRUM | 0:276e7a263c35 | 204 | else { |
MACRUM | 0:276e7a263c35 | 205 | |
MACRUM | 0:276e7a263c35 | 206 | UC_SRCE_TRACE("socket: address type is: %u", context->cache_address.addressType); |
MACRUM | 0:276e7a263c35 | 207 | /* create new async PAL socket */ |
MACRUM | 0:276e7a263c35 | 208 | pal_inner = pal_asynchronousSocket((palSocketDomain_t)context->cache_address.addressType, |
MACRUM | 0:276e7a263c35 | 209 | PAL_SOCK_STREAM, |
MACRUM | 0:276e7a263c35 | 210 | true, |
MACRUM | 0:276e7a263c35 | 211 | 0, |
MACRUM | 0:276e7a263c35 | 212 | arm_uc_socket_isr, |
MACRUM | 0:276e7a263c35 | 213 | &context->socket); |
MACRUM | 0:276e7a263c35 | 214 | } |
MACRUM | 0:276e7a263c35 | 215 | |
MACRUM | 0:276e7a263c35 | 216 | if (pal_inner != PAL_SUCCESS) |
MACRUM | 0:276e7a263c35 | 217 | { |
MACRUM | 0:276e7a263c35 | 218 | UC_SRCE_ERR_MSG("socket creation failed with pal status: 0x%" PRIX32, |
MACRUM | 0:276e7a263c35 | 219 | (uint32_t) pal_inner); |
MACRUM | 0:276e7a263c35 | 220 | arm_uc_socket_close(); |
MACRUM | 0:276e7a263c35 | 221 | result = (arm_uc_error_t){ SRCE_ERR_FAILED }; |
MACRUM | 0:276e7a263c35 | 222 | } |
MACRUM | 0:276e7a263c35 | 223 | else |
MACRUM | 0:276e7a263c35 | 224 | { |
MACRUM | 0:276e7a263c35 | 225 | UC_SRCE_TRACE("socket: create success"); |
MACRUM | 0:276e7a263c35 | 226 | } |
MACRUM | 0:276e7a263c35 | 227 | |
MACRUM | 0:276e7a263c35 | 228 | /* create socket timeout timer */ |
MACRUM | 0:276e7a263c35 | 229 | if (result.code == SRCE_ERR_NONE) |
MACRUM | 0:276e7a263c35 | 230 | { |
MACRUM | 0:276e7a263c35 | 231 | pal_inner = pal_osTimerCreate(arm_uc_timeout_timer_callback, |
MACRUM | 0:276e7a263c35 | 232 | NULL, |
MACRUM | 0:276e7a263c35 | 233 | palOsTimerOnce, |
MACRUM | 0:276e7a263c35 | 234 | &context->timeout_timer_id); |
MACRUM | 0:276e7a263c35 | 235 | |
MACRUM | 0:276e7a263c35 | 236 | if (pal_inner != PAL_SUCCESS) |
MACRUM | 0:276e7a263c35 | 237 | { |
MACRUM | 0:276e7a263c35 | 238 | UC_SRCE_ERR_MSG("socket timeout timer creation failed"); |
MACRUM | 0:276e7a263c35 | 239 | arm_uc_socket_close(); |
MACRUM | 0:276e7a263c35 | 240 | result = (arm_uc_error_t){ SRCE_ERR_FAILED }; |
MACRUM | 0:276e7a263c35 | 241 | } |
MACRUM | 0:276e7a263c35 | 242 | else |
MACRUM | 0:276e7a263c35 | 243 | { |
MACRUM | 0:276e7a263c35 | 244 | /* start socket timeout timer */ |
MACRUM | 0:276e7a263c35 | 245 | pal_inner = pal_osTimerStart(context->timeout_timer_id, |
MACRUM | 0:276e7a263c35 | 246 | ARM_UC_SOCKET_TIMEOUT_MS); |
MACRUM | 0:276e7a263c35 | 247 | |
MACRUM | 0:276e7a263c35 | 248 | if (pal_inner != PAL_SUCCESS) |
MACRUM | 0:276e7a263c35 | 249 | { |
MACRUM | 0:276e7a263c35 | 250 | UC_SRCE_ERR_MSG("Start socket timeout timer failed"); |
MACRUM | 0:276e7a263c35 | 251 | arm_uc_socket_close(); |
MACRUM | 0:276e7a263c35 | 252 | result = (arm_uc_error_t){ SRCE_ERR_FAILED }; |
MACRUM | 0:276e7a263c35 | 253 | } |
MACRUM | 0:276e7a263c35 | 254 | } |
MACRUM | 0:276e7a263c35 | 255 | } |
MACRUM | 0:276e7a263c35 | 256 | |
MACRUM | 0:276e7a263c35 | 257 | /* convert URI to PAL address if cache is not empty */ |
MACRUM | 0:276e7a263c35 | 258 | if ((result.code == SRCE_ERR_NONE) && |
MACRUM | 0:276e7a263c35 | 259 | (context->cache_address_length != 0)) |
MACRUM | 0:276e7a263c35 | 260 | { |
MACRUM | 0:276e7a263c35 | 261 | /* set PAL port */ |
MACRUM | 0:276e7a263c35 | 262 | pal_inner = pal_setSockAddrPort(&context->cache_address, |
MACRUM | 0:276e7a263c35 | 263 | context->request_uri->port); |
MACRUM | 0:276e7a263c35 | 264 | |
MACRUM | 0:276e7a263c35 | 265 | if (pal_inner != PAL_SUCCESS) |
MACRUM | 0:276e7a263c35 | 266 | { |
MACRUM | 0:276e7a263c35 | 267 | UC_SRCE_ERR_MSG("pal_setSockAddrPort returned: 0x%" PRIX32, |
MACRUM | 0:276e7a263c35 | 268 | (uint32_t) pal_inner); |
MACRUM | 0:276e7a263c35 | 269 | arm_uc_socket_close(); |
MACRUM | 0:276e7a263c35 | 270 | result = (arm_uc_error_t){ SRCE_ERR_INVALID_PARAMETER }; |
MACRUM | 0:276e7a263c35 | 271 | } |
MACRUM | 0:276e7a263c35 | 272 | } |
MACRUM | 0:276e7a263c35 | 273 | |
MACRUM | 0:276e7a263c35 | 274 | /* connect to server */ |
MACRUM | 0:276e7a263c35 | 275 | if (result.code == SRCE_ERR_NONE) |
MACRUM | 0:276e7a263c35 | 276 | { |
MACRUM | 0:276e7a263c35 | 277 | pal_inner = pal_connect(context->socket, |
MACRUM | 0:276e7a263c35 | 278 | &context->cache_address, |
MACRUM | 0:276e7a263c35 | 279 | context->cache_address_length); |
MACRUM | 0:276e7a263c35 | 280 | UC_SRCE_TRACE("pal_connect returned: 0x%" PRIX32, |
MACRUM | 0:276e7a263c35 | 281 | (uint32_t) pal_inner); |
MACRUM | 0:276e7a263c35 | 282 | |
MACRUM | 0:276e7a263c35 | 283 | if (pal_inner == PAL_SUCCESS) /* synchronous finish */ |
MACRUM | 0:276e7a263c35 | 284 | { |
MACRUM | 0:276e7a263c35 | 285 | context->socket_state = STATE_CONNECTED_IDLE; |
MACRUM | 0:276e7a263c35 | 286 | context->expected_event = SOCKET_EVENT_CONNECT_DONE; |
MACRUM | 0:276e7a263c35 | 287 | result = (arm_uc_error_t){ SRCE_ERR_NONE }; |
MACRUM | 0:276e7a263c35 | 288 | arm_uc_socket_isr(NULL); |
MACRUM | 0:276e7a263c35 | 289 | } |
MACRUM | 0:276e7a263c35 | 290 | else if (pal_inner == PAL_ERR_SOCKET_IN_PROGRES) /* asynchronous finish */ |
MACRUM | 0:276e7a263c35 | 291 | { |
MACRUM | 0:276e7a263c35 | 292 | context->expected_event = SOCKET_EVENT_CONNECT_DONE; |
MACRUM | 0:276e7a263c35 | 293 | result = (arm_uc_error_t){ SRCE_ERR_NONE }; |
MACRUM | 0:276e7a263c35 | 294 | } |
MACRUM | 0:276e7a263c35 | 295 | else |
MACRUM | 0:276e7a263c35 | 296 | { |
MACRUM | 0:276e7a263c35 | 297 | UC_SRCE_ERR_MSG("Error: socket connection failed"); |
MACRUM | 0:276e7a263c35 | 298 | result = (arm_uc_error_t){ SRCE_ERR_FAILED }; |
MACRUM | 0:276e7a263c35 | 299 | arm_uc_socket_close(); |
MACRUM | 0:276e7a263c35 | 300 | } |
MACRUM | 0:276e7a263c35 | 301 | } |
MACRUM | 0:276e7a263c35 | 302 | } |
MACRUM | 0:276e7a263c35 | 303 | else if (context->socket_state == STATE_CONNECTED_IDLE) /* already connected */ |
MACRUM | 0:276e7a263c35 | 304 | { |
MACRUM | 0:276e7a263c35 | 305 | /* Socket already connected, progress state machine */ |
MACRUM | 0:276e7a263c35 | 306 | palStatus_t pal_inner = pal_osTimerStart(context->timeout_timer_id, |
MACRUM | 0:276e7a263c35 | 307 | ARM_UC_SOCKET_TIMEOUT_MS); |
MACRUM | 0:276e7a263c35 | 308 | |
MACRUM | 0:276e7a263c35 | 309 | if (pal_inner != PAL_SUCCESS) |
MACRUM | 0:276e7a263c35 | 310 | { |
MACRUM | 0:276e7a263c35 | 311 | UC_SRCE_ERR_MSG("Start socket timeout timer failed"); |
MACRUM | 0:276e7a263c35 | 312 | arm_uc_socket_close(); |
MACRUM | 0:276e7a263c35 | 313 | return (arm_uc_error_t){ SRCE_ERR_FAILED }; |
MACRUM | 0:276e7a263c35 | 314 | } |
MACRUM | 0:276e7a263c35 | 315 | |
MACRUM | 0:276e7a263c35 | 316 | UC_SRCE_TRACE("Socket already connected, progress state machine"); |
MACRUM | 0:276e7a263c35 | 317 | context->expected_event = SOCKET_EVENT_CONNECT_DONE; |
MACRUM | 0:276e7a263c35 | 318 | result = (arm_uc_error_t){ SRCE_ERR_NONE }; |
MACRUM | 0:276e7a263c35 | 319 | arm_uc_socket_isr(NULL); |
MACRUM | 0:276e7a263c35 | 320 | } |
MACRUM | 0:276e7a263c35 | 321 | else /* socket busy */ |
MACRUM | 0:276e7a263c35 | 322 | { |
MACRUM | 0:276e7a263c35 | 323 | UC_SRCE_TRACE("Socket Busy"); |
MACRUM | 0:276e7a263c35 | 324 | result = (arm_uc_error_t){ SRCE_ERR_BUSY }; |
MACRUM | 0:276e7a263c35 | 325 | } |
MACRUM | 0:276e7a263c35 | 326 | } |
MACRUM | 0:276e7a263c35 | 327 | |
MACRUM | 0:276e7a263c35 | 328 | UC_SRCE_TRACE("arm_uc_socket_connect returning %s", ARM_UC_err2Str(result)); |
MACRUM | 0:276e7a263c35 | 329 | |
MACRUM | 0:276e7a263c35 | 330 | return result; |
MACRUM | 0:276e7a263c35 | 331 | } |
MACRUM | 0:276e7a263c35 | 332 | |
MACRUM | 0:276e7a263c35 | 333 | /** |
MACRUM | 0:276e7a263c35 | 334 | * @brief Send request passed in arm_uc_socket_get. |
MACRUM | 0:276e7a263c35 | 335 | * @details This call assumes the HTTP socket is already connected to server. |
MACRUM | 0:276e7a263c35 | 336 | * @return Error code. |
MACRUM | 0:276e7a263c35 | 337 | */ |
MACRUM | 0:276e7a263c35 | 338 | arm_uc_error_t arm_uc_socket_send_request() |
MACRUM | 0:276e7a263c35 | 339 | { |
MACRUM | 0:276e7a263c35 | 340 | /* default return value */ |
MACRUM | 0:276e7a263c35 | 341 | arm_uc_error_t result = (arm_uc_error_t){ SRCE_ERR_FAILED }; |
MACRUM | 0:276e7a263c35 | 342 | |
MACRUM | 0:276e7a263c35 | 343 | /* NULL pointer check */ |
MACRUM | 0:276e7a263c35 | 344 | if (context) |
MACRUM | 0:276e7a263c35 | 345 | { |
MACRUM | 0:276e7a263c35 | 346 | /* get local references */ |
MACRUM | 0:276e7a263c35 | 347 | arm_uc_buffer_t* request_buffer = context->request_buffer; |
MACRUM | 0:276e7a263c35 | 348 | arm_uc_uri_t* request_uri = context->request_uri; |
MACRUM | 0:276e7a263c35 | 349 | arm_uc_rqst_t request_type = context->request_type; |
MACRUM | 0:276e7a263c35 | 350 | |
MACRUM | 0:276e7a263c35 | 351 | /* template for generating HTTP requests */ |
MACRUM | 0:276e7a263c35 | 352 | static const char HTTP_HEADER_TEMPLATE[] = |
MACRUM | 0:276e7a263c35 | 353 | "%s %s HTTP/1.1\r\n" // status line |
MACRUM | 0:276e7a263c35 | 354 | "Host: %s\r\n"; // mandated for http 1.1 |
MACRUM | 0:276e7a263c35 | 355 | |
MACRUM | 0:276e7a263c35 | 356 | if (request_type == RQST_TYPE_HASH_ETAG || |
MACRUM | 0:276e7a263c35 | 357 | request_type == RQST_TYPE_HASH_DATE) |
MACRUM | 0:276e7a263c35 | 358 | { |
MACRUM | 0:276e7a263c35 | 359 | /* construct ETag and Date request header */ |
MACRUM | 0:276e7a263c35 | 360 | request_buffer->size = snprintf((char *) request_buffer->ptr, |
MACRUM | 0:276e7a263c35 | 361 | request_buffer->size_max, |
MACRUM | 0:276e7a263c35 | 362 | HTTP_HEADER_TEMPLATE, |
MACRUM | 0:276e7a263c35 | 363 | "HEAD", |
MACRUM | 0:276e7a263c35 | 364 | request_uri->path, |
MACRUM | 0:276e7a263c35 | 365 | request_uri->host); |
MACRUM | 0:276e7a263c35 | 366 | } |
MACRUM | 0:276e7a263c35 | 367 | else |
MACRUM | 0:276e7a263c35 | 368 | { |
MACRUM | 0:276e7a263c35 | 369 | /* construct download header */ |
MACRUM | 0:276e7a263c35 | 370 | request_buffer->size = snprintf((char *) request_buffer->ptr, |
MACRUM | 0:276e7a263c35 | 371 | request_buffer->size_max, |
MACRUM | 0:276e7a263c35 | 372 | HTTP_HEADER_TEMPLATE, |
MACRUM | 0:276e7a263c35 | 373 | "GET", |
MACRUM | 0:276e7a263c35 | 374 | request_uri->path, |
MACRUM | 0:276e7a263c35 | 375 | request_uri->host); |
MACRUM | 0:276e7a263c35 | 376 | } |
MACRUM | 0:276e7a263c35 | 377 | |
MACRUM | 0:276e7a263c35 | 378 | if (request_type == RQST_TYPE_GET_FRAG) |
MACRUM | 0:276e7a263c35 | 379 | { |
MACRUM | 0:276e7a263c35 | 380 | /* construct the Range field that makes this a partial content request */ |
MACRUM | 0:276e7a263c35 | 381 | request_buffer->size += snprintf((char *) request_buffer->ptr + request_buffer->size, |
MACRUM | 0:276e7a263c35 | 382 | request_buffer->size_max - request_buffer->size, |
MACRUM | 0:276e7a263c35 | 383 | "Range: bytes=%" PRIu32 "-%" PRIu32 "\r\n", |
MACRUM | 0:276e7a263c35 | 384 | context->request_offset, |
MACRUM | 0:276e7a263c35 | 385 | context->request_offset + request_buffer->size_max - 1); |
MACRUM | 0:276e7a263c35 | 386 | } |
MACRUM | 0:276e7a263c35 | 387 | |
MACRUM | 0:276e7a263c35 | 388 | /* terminate request with a carriage return and newline */ |
MACRUM | 0:276e7a263c35 | 389 | request_buffer->size += snprintf((char *) request_buffer->ptr + request_buffer->size, |
MACRUM | 0:276e7a263c35 | 390 | request_buffer->size_max - request_buffer->size, |
MACRUM | 0:276e7a263c35 | 391 | "\r\n"); |
MACRUM | 0:276e7a263c35 | 392 | |
MACRUM | 0:276e7a263c35 | 393 | /* terminate string */ |
MACRUM | 0:276e7a263c35 | 394 | request_buffer->ptr[request_buffer->size] = '\0'; |
MACRUM | 0:276e7a263c35 | 395 | UC_SRCE_TRACE("%s", request_buffer->ptr); |
MACRUM | 0:276e7a263c35 | 396 | |
MACRUM | 0:276e7a263c35 | 397 | /*************************************************************************/ |
MACRUM | 0:276e7a263c35 | 398 | |
MACRUM | 0:276e7a263c35 | 399 | size_t bytes_sent = 0; |
MACRUM | 0:276e7a263c35 | 400 | |
MACRUM | 0:276e7a263c35 | 401 | /* send HTTP request */ |
MACRUM | 0:276e7a263c35 | 402 | palStatus_t pal_result = pal_send(context->socket, |
MACRUM | 0:276e7a263c35 | 403 | request_buffer->ptr, |
MACRUM | 0:276e7a263c35 | 404 | request_buffer->size, |
MACRUM | 0:276e7a263c35 | 405 | &bytes_sent); |
MACRUM | 0:276e7a263c35 | 406 | |
MACRUM | 0:276e7a263c35 | 407 | if (pal_result == PAL_SUCCESS) /* asynchronous finish */ |
MACRUM | 0:276e7a263c35 | 408 | { |
MACRUM | 0:276e7a263c35 | 409 | UC_SRCE_TRACE("send success"); |
MACRUM | 0:276e7a263c35 | 410 | |
MACRUM | 0:276e7a263c35 | 411 | /* reset buffer and prepare to receive header */ |
MACRUM | 0:276e7a263c35 | 412 | request_buffer->size = 0; |
MACRUM | 0:276e7a263c35 | 413 | context->socket_state = STATE_PROCESS_HEADER; |
MACRUM | 0:276e7a263c35 | 414 | context->expected_event = SOCKET_EVENT_SEND_DONE; |
MACRUM | 0:276e7a263c35 | 415 | |
MACRUM | 0:276e7a263c35 | 416 | result = (arm_uc_error_t){ SRCE_ERR_NONE }; |
MACRUM | 0:276e7a263c35 | 417 | } |
MACRUM | 0:276e7a263c35 | 418 | else if(pal_result == PAL_ERR_SOCKET_WOULD_BLOCK) |
MACRUM | 0:276e7a263c35 | 419 | { |
MACRUM | 0:276e7a263c35 | 420 | UC_SRCE_TRACE("send would block, will retry"); |
MACRUM | 0:276e7a263c35 | 421 | |
MACRUM | 0:276e7a263c35 | 422 | /* keep current state and force callback to retry sending */ |
MACRUM | 0:276e7a263c35 | 423 | request_buffer->size = 0; |
MACRUM | 0:276e7a263c35 | 424 | arm_uc_socket_isr(NULL); |
MACRUM | 0:276e7a263c35 | 425 | |
MACRUM | 0:276e7a263c35 | 426 | result = (arm_uc_error_t){ SRCE_ERR_NONE }; |
MACRUM | 0:276e7a263c35 | 427 | } |
MACRUM | 0:276e7a263c35 | 428 | else |
MACRUM | 0:276e7a263c35 | 429 | { |
MACRUM | 0:276e7a263c35 | 430 | UC_SRCE_TRACE("send error 0x%" PRIX32, (uint32_t) pal_result); |
MACRUM | 0:276e7a263c35 | 431 | |
MACRUM | 0:276e7a263c35 | 432 | /* clean up */ |
MACRUM | 0:276e7a263c35 | 433 | arm_uc_socket_error(UCS_HTTP_EVENT_ERROR); |
MACRUM | 0:276e7a263c35 | 434 | } |
MACRUM | 0:276e7a263c35 | 435 | } |
MACRUM | 0:276e7a263c35 | 436 | |
MACRUM | 0:276e7a263c35 | 437 | return result; |
MACRUM | 0:276e7a263c35 | 438 | } |
MACRUM | 0:276e7a263c35 | 439 | |
MACRUM | 0:276e7a263c35 | 440 | /** |
MACRUM | 0:276e7a263c35 | 441 | * @brief Receive data from HTTP socket. |
MACRUM | 0:276e7a263c35 | 442 | * @details Data is stored in global buffer. The call will automatically retry |
MACRUM | 0:276e7a263c35 | 443 | * if the socket is busy. |
MACRUM | 0:276e7a263c35 | 444 | */ |
MACRUM | 0:276e7a263c35 | 445 | void arm_uc_socket_receive() |
MACRUM | 0:276e7a263c35 | 446 | { |
MACRUM | 0:276e7a263c35 | 447 | /* NULL pointer check */ |
MACRUM | 0:276e7a263c35 | 448 | if (context) |
MACRUM | 0:276e7a263c35 | 449 | { |
MACRUM | 0:276e7a263c35 | 450 | /* get local references */ |
MACRUM | 0:276e7a263c35 | 451 | arm_uc_buffer_t* request_buffer = context->request_buffer; |
MACRUM | 0:276e7a263c35 | 452 | |
MACRUM | 0:276e7a263c35 | 453 | size_t received_bytes = 0; |
MACRUM | 0:276e7a263c35 | 454 | palStatus_t pal_result = PAL_SUCCESS; |
MACRUM | 0:276e7a263c35 | 455 | |
MACRUM | 0:276e7a263c35 | 456 | while ( (context->socket_state != STATE_DISCONNECTED) && |
MACRUM | 0:276e7a263c35 | 457 | (pal_result == PAL_SUCCESS) && |
MACRUM | 0:276e7a263c35 | 458 | context->request_buffer ) |
MACRUM | 0:276e7a263c35 | 459 | { |
MACRUM | 0:276e7a263c35 | 460 | if (request_buffer->size >= request_buffer->size_max) |
MACRUM | 0:276e7a263c35 | 461 | { |
MACRUM | 0:276e7a263c35 | 462 | UC_SRCE_ERR_MSG("There is no space in the buffer left"); |
MACRUM | 0:276e7a263c35 | 463 | arm_uc_socket_error(UCS_HTTP_EVENT_ERROR_BUFFER_SIZE); |
MACRUM | 0:276e7a263c35 | 464 | break; |
MACRUM | 0:276e7a263c35 | 465 | } |
MACRUM | 0:276e7a263c35 | 466 | |
MACRUM | 0:276e7a263c35 | 467 | /* append data from socket receive buffer to request buffer. */ |
MACRUM | 0:276e7a263c35 | 468 | pal_result = pal_recv(context->socket, |
MACRUM | 0:276e7a263c35 | 469 | &(request_buffer->ptr[request_buffer->size]), |
MACRUM | 0:276e7a263c35 | 470 | request_buffer->size_max - request_buffer->size, |
MACRUM | 0:276e7a263c35 | 471 | &received_bytes); |
MACRUM | 0:276e7a263c35 | 472 | |
MACRUM | 0:276e7a263c35 | 473 | if (pal_result == PAL_SUCCESS && received_bytes > 0) |
MACRUM | 0:276e7a263c35 | 474 | { |
MACRUM | 0:276e7a263c35 | 475 | /* Note: the proper formatter %zu is not supported on mbed's libc, |
MACRUM | 0:276e7a263c35 | 476 | * hence the casts to difference type. |
MACRUM | 0:276e7a263c35 | 477 | */ |
MACRUM | 0:276e7a263c35 | 478 | UC_SRCE_TRACE("recv success: %lu bytes received", |
MACRUM | 0:276e7a263c35 | 479 | (unsigned long)received_bytes); |
MACRUM | 0:276e7a263c35 | 480 | |
MACRUM | 0:276e7a263c35 | 481 | if (request_buffer->size + received_bytes > request_buffer->size_max) |
MACRUM | 0:276e7a263c35 | 482 | { |
MACRUM | 0:276e7a263c35 | 483 | UC_SRCE_ERR_MSG("Got more data than available space in the buffer"); |
MACRUM | 0:276e7a263c35 | 484 | arm_uc_socket_error(UCS_HTTP_EVENT_ERROR_BUFFER_SIZE); |
MACRUM | 0:276e7a263c35 | 485 | break; |
MACRUM | 0:276e7a263c35 | 486 | } |
MACRUM | 0:276e7a263c35 | 487 | |
MACRUM | 0:276e7a263c35 | 488 | /* update buffer size with received bytes */ |
MACRUM | 0:276e7a263c35 | 489 | request_buffer->size += received_bytes; |
MACRUM | 0:276e7a263c35 | 490 | |
MACRUM | 0:276e7a263c35 | 491 | /* update expected event to signal receive done */ |
MACRUM | 0:276e7a263c35 | 492 | context->expected_event = SOCKET_EVENT_RECEIVE_CONTINUE; |
MACRUM | 0:276e7a263c35 | 493 | |
MACRUM | 0:276e7a263c35 | 494 | /* received data */ |
MACRUM | 0:276e7a263c35 | 495 | if (context->socket_state == STATE_PROCESS_HEADER) |
MACRUM | 0:276e7a263c35 | 496 | { |
MACRUM | 0:276e7a263c35 | 497 | /* expecting HTTP header */ |
MACRUM | 0:276e7a263c35 | 498 | arm_uc_socket_process_header(); |
MACRUM | 0:276e7a263c35 | 499 | } |
MACRUM | 0:276e7a263c35 | 500 | else if (context->socket_state == STATE_PROCESS_BODY) |
MACRUM | 0:276e7a263c35 | 501 | { |
MACRUM | 0:276e7a263c35 | 502 | /* expecting body */ |
MACRUM | 0:276e7a263c35 | 503 | arm_uc_socket_process_body(); |
MACRUM | 0:276e7a263c35 | 504 | } |
MACRUM | 0:276e7a263c35 | 505 | else |
MACRUM | 0:276e7a263c35 | 506 | { |
MACRUM | 0:276e7a263c35 | 507 | /* unexpected data, generate error and clean up */ |
MACRUM | 0:276e7a263c35 | 508 | arm_uc_socket_error(UCS_HTTP_EVENT_ERROR); |
MACRUM | 0:276e7a263c35 | 509 | } |
MACRUM | 0:276e7a263c35 | 510 | } |
MACRUM | 0:276e7a263c35 | 511 | else if (pal_result == PAL_ERR_SOCKET_WOULD_BLOCK) |
MACRUM | 0:276e7a263c35 | 512 | { |
MACRUM | 0:276e7a263c35 | 513 | /* Note: at least on mbed os the pal_recv() returns garbage on recievedDataSize |
MACRUM | 0:276e7a263c35 | 514 | * if the socket call returns anything but PAL_SUCCESS, so this needs to |
MACRUM | 0:276e7a263c35 | 515 | * recalculate the remaining bytes count. |
MACRUM | 0:276e7a263c35 | 516 | */ |
MACRUM | 0:276e7a263c35 | 517 | UC_SRCE_TRACE("recv: pending: %" PRIu32, |
MACRUM | 0:276e7a263c35 | 518 | (request_buffer->size_max - request_buffer->size)); |
MACRUM | 0:276e7a263c35 | 519 | |
MACRUM | 0:276e7a263c35 | 520 | /* update expected event to retry receiving */ |
MACRUM | 0:276e7a263c35 | 521 | context->expected_event = SOCKET_EVENT_RECEIVE_CONTINUE; |
MACRUM | 0:276e7a263c35 | 522 | } |
MACRUM | 0:276e7a263c35 | 523 | else |
MACRUM | 0:276e7a263c35 | 524 | { |
MACRUM | 0:276e7a263c35 | 525 | UC_SRCE_ERR_MSG("Error: socket receive failed"); |
MACRUM | 0:276e7a263c35 | 526 | |
MACRUM | 0:276e7a263c35 | 527 | /* clean up */ |
MACRUM | 0:276e7a263c35 | 528 | arm_uc_socket_error(UCS_HTTP_EVENT_ERROR); |
MACRUM | 0:276e7a263c35 | 529 | } |
MACRUM | 0:276e7a263c35 | 530 | } |
MACRUM | 0:276e7a263c35 | 531 | } |
MACRUM | 0:276e7a263c35 | 532 | } |
MACRUM | 0:276e7a263c35 | 533 | |
MACRUM | 0:276e7a263c35 | 534 | /** |
MACRUM | 0:276e7a263c35 | 535 | * @brief Function is called when some data has been received but an HTTP |
MACRUM | 0:276e7a263c35 | 536 | * header has yet to be processed. |
MACRUM | 0:276e7a263c35 | 537 | * @details Function is called repeatedly until a header is found or the buffer |
MACRUM | 0:276e7a263c35 | 538 | * is full. Once a header is found, the ETag, date, or content length |
MACRUM | 0:276e7a263c35 | 539 | * is parsed. For file and fragment downloads the receive process is |
MACRUM | 0:276e7a263c35 | 540 | * restarted and the header is erased. |
MACRUM | 0:276e7a263c35 | 541 | */ |
MACRUM | 0:276e7a263c35 | 542 | void arm_uc_socket_process_header() |
MACRUM | 0:276e7a263c35 | 543 | { |
MACRUM | 0:276e7a263c35 | 544 | /* NULL pointer check */ |
MACRUM | 0:276e7a263c35 | 545 | if (context) |
MACRUM | 0:276e7a263c35 | 546 | { |
MACRUM | 0:276e7a263c35 | 547 | /* get local references */ |
MACRUM | 0:276e7a263c35 | 548 | arm_uc_buffer_t* request_buffer = context->request_buffer; |
MACRUM | 0:276e7a263c35 | 549 | arm_uc_uri_t* request_uri = context->request_uri; |
MACRUM | 0:276e7a263c35 | 550 | arm_uc_rqst_t request_type = context->request_type; |
MACRUM | 0:276e7a263c35 | 551 | |
MACRUM | 0:276e7a263c35 | 552 | /* setup default return to be failure */ |
MACRUM | 0:276e7a263c35 | 553 | bool request_successfully_processed = false; |
MACRUM | 0:276e7a263c35 | 554 | |
MACRUM | 0:276e7a263c35 | 555 | uint32_t index = arm_uc_strnstrn(request_buffer->ptr, |
MACRUM | 0:276e7a263c35 | 556 | request_buffer->size, |
MACRUM | 0:276e7a263c35 | 557 | (const uint8_t*) "\r\n\r\n", |
MACRUM | 0:276e7a263c35 | 558 | 4); |
MACRUM | 0:276e7a263c35 | 559 | |
MACRUM | 0:276e7a263c35 | 560 | /* Continue receiving if full header is not found. */ |
MACRUM | 0:276e7a263c35 | 561 | if (index > request_buffer->size) |
MACRUM | 0:276e7a263c35 | 562 | { |
MACRUM | 0:276e7a263c35 | 563 | request_successfully_processed = true; |
MACRUM | 0:276e7a263c35 | 564 | arm_uc_socket_receive(); |
MACRUM | 0:276e7a263c35 | 565 | } |
MACRUM | 0:276e7a263c35 | 566 | else |
MACRUM | 0:276e7a263c35 | 567 | { |
MACRUM | 0:276e7a263c35 | 568 | /* process header */ |
MACRUM | 0:276e7a263c35 | 569 | UC_SRCE_TRACE("HTTP header found"); |
MACRUM | 0:276e7a263c35 | 570 | |
MACRUM | 0:276e7a263c35 | 571 | const char header_tag[] = "HTTP/1.1 "; |
MACRUM | 0:276e7a263c35 | 572 | |
MACRUM | 0:276e7a263c35 | 573 | uint32_t header_start = arm_uc_strnstrn(request_buffer->ptr, |
MACRUM | 0:276e7a263c35 | 574 | request_buffer->size, |
MACRUM | 0:276e7a263c35 | 575 | (const uint8_t*) header_tag, |
MACRUM | 0:276e7a263c35 | 576 | sizeof(header_tag) - 1); |
MACRUM | 0:276e7a263c35 | 577 | |
MACRUM | 0:276e7a263c35 | 578 | /* found beginning of header */ |
MACRUM | 0:276e7a263c35 | 579 | if (header_start < request_buffer->size) |
MACRUM | 0:276e7a263c35 | 580 | { |
MACRUM | 0:276e7a263c35 | 581 | /* status code is after the header tag */ |
MACRUM | 0:276e7a263c35 | 582 | header_start = header_start + sizeof(header_tag) - 1; |
MACRUM | 0:276e7a263c35 | 583 | } |
MACRUM | 0:276e7a263c35 | 584 | |
MACRUM | 0:276e7a263c35 | 585 | /* buffer size check */ |
MACRUM | 0:276e7a263c35 | 586 | if (header_start < request_buffer->size) |
MACRUM | 0:276e7a263c35 | 587 | { |
MACRUM | 0:276e7a263c35 | 588 | /* parse status code */ |
MACRUM | 0:276e7a263c35 | 589 | bool header_parsed = false; |
MACRUM | 0:276e7a263c35 | 590 | uint32_t status_code = arm_uc_str2uint32( |
MACRUM | 0:276e7a263c35 | 591 | &(request_buffer->ptr[header_start]), |
MACRUM | 0:276e7a263c35 | 592 | request_buffer->size - header_start, |
MACRUM | 0:276e7a263c35 | 593 | &header_parsed); |
MACRUM | 0:276e7a263c35 | 594 | |
MACRUM | 0:276e7a263c35 | 595 | if (header_parsed == true) |
MACRUM | 0:276e7a263c35 | 596 | { |
MACRUM | 0:276e7a263c35 | 597 | UC_SRCE_TRACE("HTTP status code %" PRIu32, status_code); |
MACRUM | 0:276e7a263c35 | 598 | |
MACRUM | 0:276e7a263c35 | 599 | /* Redirect status codes: |
MACRUM | 0:276e7a263c35 | 600 | 301: Moved Permanently |
MACRUM | 0:276e7a263c35 | 601 | 302: Found [Elsewhere] |
MACRUM | 0:276e7a263c35 | 602 | 303: See Other |
MACRUM | 0:276e7a263c35 | 603 | 307: Temporary Redirect |
MACRUM | 0:276e7a263c35 | 604 | */ |
MACRUM | 0:276e7a263c35 | 605 | if ((status_code >= 301 && status_code <= 303) || |
MACRUM | 0:276e7a263c35 | 606 | (status_code == 307)) |
MACRUM | 0:276e7a263c35 | 607 | { |
MACRUM | 0:276e7a263c35 | 608 | /* move location to front of buffer */ |
MACRUM | 0:276e7a263c35 | 609 | const char tag[] = "Location"; |
MACRUM | 0:276e7a263c35 | 610 | bool found = arm_uc_socket_trim_value(request_buffer, |
MACRUM | 0:276e7a263c35 | 611 | tag, |
MACRUM | 0:276e7a263c35 | 612 | sizeof(tag) - 1); |
MACRUM | 0:276e7a263c35 | 613 | |
MACRUM | 0:276e7a263c35 | 614 | if (found) |
MACRUM | 0:276e7a263c35 | 615 | { |
MACRUM | 0:276e7a263c35 | 616 | /* NULL terminate string */ |
MACRUM | 0:276e7a263c35 | 617 | request_buffer->ptr[request_buffer->size] = '\0'; |
MACRUM | 0:276e7a263c35 | 618 | |
MACRUM | 0:276e7a263c35 | 619 | /* parse location and store in URI */ |
MACRUM | 0:276e7a263c35 | 620 | arm_uc_error_t err = arm_uc_str2uri(request_buffer->ptr, |
MACRUM | 0:276e7a263c35 | 621 | request_buffer->size, |
MACRUM | 0:276e7a263c35 | 622 | request_uri); |
MACRUM | 0:276e7a263c35 | 623 | |
MACRUM | 0:276e7a263c35 | 624 | if ((err.error == ERR_NONE) && |
MACRUM | 0:276e7a263c35 | 625 | (request_uri->scheme == URI_SCHEME_HTTP)) |
MACRUM | 0:276e7a263c35 | 626 | { |
MACRUM | 0:276e7a263c35 | 627 | UC_SRCE_TRACE("HTTP redirecting to http://%s:%" PRIu16 "/%s", |
MACRUM | 0:276e7a263c35 | 628 | request_uri->host, |
MACRUM | 0:276e7a263c35 | 629 | request_uri->port, |
MACRUM | 0:276e7a263c35 | 630 | request_uri->path); |
MACRUM | 0:276e7a263c35 | 631 | |
MACRUM | 0:276e7a263c35 | 632 | /* close socket */ |
MACRUM | 0:276e7a263c35 | 633 | pal_close(&context->socket); |
MACRUM | 0:276e7a263c35 | 634 | |
MACRUM | 0:276e7a263c35 | 635 | /* reset buffer */ |
MACRUM | 0:276e7a263c35 | 636 | request_buffer->size = 0; |
MACRUM | 0:276e7a263c35 | 637 | |
MACRUM | 0:276e7a263c35 | 638 | /* reconnect to new uri location */ |
MACRUM | 0:276e7a263c35 | 639 | err = arm_uc_socket_connect(); |
MACRUM | 0:276e7a263c35 | 640 | if (err.error == ERR_NONE) |
MACRUM | 0:276e7a263c35 | 641 | { |
MACRUM | 0:276e7a263c35 | 642 | /* send the request to the new uri */ |
MACRUM | 0:276e7a263c35 | 643 | err = arm_uc_socket_send_request(); |
MACRUM | 0:276e7a263c35 | 644 | } |
MACRUM | 0:276e7a263c35 | 645 | |
MACRUM | 0:276e7a263c35 | 646 | if (err.error == ERR_NONE) |
MACRUM | 0:276e7a263c35 | 647 | { |
MACRUM | 0:276e7a263c35 | 648 | request_successfully_processed = true; |
MACRUM | 0:276e7a263c35 | 649 | } |
MACRUM | 0:276e7a263c35 | 650 | else |
MACRUM | 0:276e7a263c35 | 651 | { |
MACRUM | 0:276e7a263c35 | 652 | UC_SRCE_ERR_MSG("Error: HTTP redirect failed"); |
MACRUM | 0:276e7a263c35 | 653 | } |
MACRUM | 0:276e7a263c35 | 654 | } |
MACRUM | 0:276e7a263c35 | 655 | else |
MACRUM | 0:276e7a263c35 | 656 | { |
MACRUM | 0:276e7a263c35 | 657 | UC_SRCE_ERR_MSG("Error: unable to parse URI string"); |
MACRUM | 0:276e7a263c35 | 658 | } |
MACRUM | 0:276e7a263c35 | 659 | } |
MACRUM | 0:276e7a263c35 | 660 | else |
MACRUM | 0:276e7a263c35 | 661 | { |
MACRUM | 0:276e7a263c35 | 662 | UC_SRCE_ERR_MSG("Error: unable to find redirect location"); |
MACRUM | 0:276e7a263c35 | 663 | } |
MACRUM | 0:276e7a263c35 | 664 | } |
MACRUM | 0:276e7a263c35 | 665 | /* All remaining codes outside 200-226 are treated as errors */ |
MACRUM | 0:276e7a263c35 | 666 | else if (status_code < 200 || status_code > 226) |
MACRUM | 0:276e7a263c35 | 667 | { |
MACRUM | 0:276e7a263c35 | 668 | UC_SRCE_ERR_MSG("Error: server returned HTTP status code %" PRIu32, |
MACRUM | 0:276e7a263c35 | 669 | status_code); |
MACRUM | 0:276e7a263c35 | 670 | } |
MACRUM | 0:276e7a263c35 | 671 | /* All codes between 200 to 226 */ |
MACRUM | 0:276e7a263c35 | 672 | else |
MACRUM | 0:276e7a263c35 | 673 | { |
MACRUM | 0:276e7a263c35 | 674 | /* NOTE: HTTP 1.1 Code 206 with Header "Connection:close" is not |
MACRUM | 0:276e7a263c35 | 675 | handled here, instead the execution falls trough to error- |
MACRUM | 0:276e7a263c35 | 676 | handling in http_socket (ARM_UCS_HTTPEVent with UCS_HTTP_EVENT_ERROR) |
MACRUM | 0:276e7a263c35 | 677 | where the retry-mechanism will resume firmware download if |
MACRUM | 0:276e7a263c35 | 678 | the server closed the connection. |
MACRUM | 0:276e7a263c35 | 679 | */ |
MACRUM | 0:276e7a263c35 | 680 | if (request_type == RQST_TYPE_HASH_ETAG) |
MACRUM | 0:276e7a263c35 | 681 | { |
MACRUM | 0:276e7a263c35 | 682 | /* look for ETag and move to front of buffer */ |
MACRUM | 0:276e7a263c35 | 683 | const char tag[] = "ETag"; |
MACRUM | 0:276e7a263c35 | 684 | bool found = arm_uc_socket_trim_value(request_buffer, |
MACRUM | 0:276e7a263c35 | 685 | tag, |
MACRUM | 0:276e7a263c35 | 686 | sizeof(tag) - 1); |
MACRUM | 0:276e7a263c35 | 687 | |
MACRUM | 0:276e7a263c35 | 688 | if (found) |
MACRUM | 0:276e7a263c35 | 689 | { |
MACRUM | 0:276e7a263c35 | 690 | /* ETag successfully read - post callback */ |
MACRUM | 0:276e7a263c35 | 691 | if (context->callback_handler) |
MACRUM | 0:276e7a263c35 | 692 | { |
MACRUM | 0:276e7a263c35 | 693 | palStatus_t status = pal_osTimerStop(context->timeout_timer_id); |
MACRUM | 0:276e7a263c35 | 694 | if (status != PAL_SUCCESS) |
MACRUM | 0:276e7a263c35 | 695 | { |
MACRUM | 0:276e7a263c35 | 696 | UC_SRCE_ERR_MSG("pal_osTimerStop returned 0x%" PRIX32, |
MACRUM | 0:276e7a263c35 | 697 | (uint32_t) status); |
MACRUM | 0:276e7a263c35 | 698 | arm_uc_socket_close(); |
MACRUM | 0:276e7a263c35 | 699 | } |
MACRUM | 0:276e7a263c35 | 700 | |
MACRUM | 0:276e7a263c35 | 701 | ARM_UC_PostCallback(&context->event_callback_struct, |
MACRUM | 0:276e7a263c35 | 702 | context->callback_handler, |
MACRUM | 0:276e7a263c35 | 703 | UCS_HTTP_EVENT_HASH); |
MACRUM | 0:276e7a263c35 | 704 | } |
MACRUM | 0:276e7a263c35 | 705 | |
MACRUM | 0:276e7a263c35 | 706 | /* request complete - close socket */ |
MACRUM | 0:276e7a263c35 | 707 | arm_uc_socket_close(); |
MACRUM | 0:276e7a263c35 | 708 | |
MACRUM | 0:276e7a263c35 | 709 | /* success - no clean up needed */ |
MACRUM | 0:276e7a263c35 | 710 | request_successfully_processed = true; |
MACRUM | 0:276e7a263c35 | 711 | } |
MACRUM | 0:276e7a263c35 | 712 | else |
MACRUM | 0:276e7a263c35 | 713 | { |
MACRUM | 0:276e7a263c35 | 714 | UC_SRCE_ERR_MSG("Error: unable to find ETag"); |
MACRUM | 0:276e7a263c35 | 715 | } |
MACRUM | 0:276e7a263c35 | 716 | } |
MACRUM | 0:276e7a263c35 | 717 | else if (request_type == RQST_TYPE_HASH_DATE) |
MACRUM | 0:276e7a263c35 | 718 | { |
MACRUM | 0:276e7a263c35 | 719 | /* look for date and move to front of buffer */ |
MACRUM | 0:276e7a263c35 | 720 | const char tag[] = "Last-Modified"; |
MACRUM | 0:276e7a263c35 | 721 | bool found = arm_uc_socket_trim_value(request_buffer, |
MACRUM | 0:276e7a263c35 | 722 | tag, |
MACRUM | 0:276e7a263c35 | 723 | sizeof(tag) - 1); |
MACRUM | 0:276e7a263c35 | 724 | |
MACRUM | 0:276e7a263c35 | 725 | if (found) |
MACRUM | 0:276e7a263c35 | 726 | { |
MACRUM | 0:276e7a263c35 | 727 | /* date successfully read - post callback */ |
MACRUM | 0:276e7a263c35 | 728 | if (context->callback_handler) |
MACRUM | 0:276e7a263c35 | 729 | { |
MACRUM | 0:276e7a263c35 | 730 | palStatus_t status = pal_osTimerStop(context->timeout_timer_id); |
MACRUM | 0:276e7a263c35 | 731 | if (status != PAL_SUCCESS) |
MACRUM | 0:276e7a263c35 | 732 | { |
MACRUM | 0:276e7a263c35 | 733 | UC_SRCE_ERR_MSG("pal_osTimerStop returned 0x%" PRIX32, |
MACRUM | 0:276e7a263c35 | 734 | (uint32_t) status); |
MACRUM | 0:276e7a263c35 | 735 | arm_uc_socket_close(); |
MACRUM | 0:276e7a263c35 | 736 | } |
MACRUM | 0:276e7a263c35 | 737 | |
MACRUM | 0:276e7a263c35 | 738 | ARM_UC_PostCallback(&context->event_callback_struct, |
MACRUM | 0:276e7a263c35 | 739 | context->callback_handler, |
MACRUM | 0:276e7a263c35 | 740 | UCS_HTTP_EVENT_DATE); |
MACRUM | 0:276e7a263c35 | 741 | } |
MACRUM | 0:276e7a263c35 | 742 | |
MACRUM | 0:276e7a263c35 | 743 | /* request complete - close socket */ |
MACRUM | 0:276e7a263c35 | 744 | arm_uc_socket_close(); |
MACRUM | 0:276e7a263c35 | 745 | |
MACRUM | 0:276e7a263c35 | 746 | /* signal clean up is not needed */ |
MACRUM | 0:276e7a263c35 | 747 | request_successfully_processed = true; |
MACRUM | 0:276e7a263c35 | 748 | } |
MACRUM | 0:276e7a263c35 | 749 | else |
MACRUM | 0:276e7a263c35 | 750 | { |
MACRUM | 0:276e7a263c35 | 751 | UC_SRCE_ERR_MSG("Error: unable to find last modified date"); |
MACRUM | 0:276e7a263c35 | 752 | } |
MACRUM | 0:276e7a263c35 | 753 | } |
MACRUM | 0:276e7a263c35 | 754 | /* request is GetFile or GetFragment */ |
MACRUM | 0:276e7a263c35 | 755 | else |
MACRUM | 0:276e7a263c35 | 756 | { |
MACRUM | 0:276e7a263c35 | 757 | /* save current buffer size so we can recover body after |
MACRUM | 0:276e7a263c35 | 758 | the content length has been read. */ |
MACRUM | 0:276e7a263c35 | 759 | uint32_t current_size = request_buffer->size; |
MACRUM | 0:276e7a263c35 | 760 | |
MACRUM | 0:276e7a263c35 | 761 | /* find content length and move value to front of buffer */ |
MACRUM | 0:276e7a263c35 | 762 | const char tag[] = "Content-Length"; |
MACRUM | 0:276e7a263c35 | 763 | bool found = arm_uc_socket_trim_value(request_buffer, |
MACRUM | 0:276e7a263c35 | 764 | tag, |
MACRUM | 0:276e7a263c35 | 765 | sizeof(tag) - 1); |
MACRUM | 0:276e7a263c35 | 766 | |
MACRUM | 0:276e7a263c35 | 767 | if (found) |
MACRUM | 0:276e7a263c35 | 768 | { |
MACRUM | 0:276e7a263c35 | 769 | /* NULL terminate string */ |
MACRUM | 0:276e7a263c35 | 770 | request_buffer->ptr[request_buffer->size] = '\0'; |
MACRUM | 0:276e7a263c35 | 771 | |
MACRUM | 0:276e7a263c35 | 772 | /* parse full length of content */ |
MACRUM | 0:276e7a263c35 | 773 | int parsed = sscanf((char *) request_buffer->ptr, |
MACRUM | 0:276e7a263c35 | 774 | "%10" SCNu32, |
MACRUM | 0:276e7a263c35 | 775 | &context->expected_remaining); |
MACRUM | 0:276e7a263c35 | 776 | |
MACRUM | 0:276e7a263c35 | 777 | /* only continue if exactly one argument was parsed */ |
MACRUM | 0:276e7a263c35 | 778 | if (parsed == 1) |
MACRUM | 0:276e7a263c35 | 779 | { |
MACRUM | 0:276e7a263c35 | 780 | UC_SRCE_TRACE("content: %" PRIu32, |
MACRUM | 0:276e7a263c35 | 781 | context->expected_remaining); |
MACRUM | 0:276e7a263c35 | 782 | |
MACRUM | 0:276e7a263c35 | 783 | /* replace HTTP header with body */ |
MACRUM | 0:276e7a263c35 | 784 | memmove(request_buffer->ptr, |
MACRUM | 0:276e7a263c35 | 785 | &(request_buffer->ptr[index + 4]), |
MACRUM | 0:276e7a263c35 | 786 | current_size - (index + 4)); |
MACRUM | 0:276e7a263c35 | 787 | |
MACRUM | 0:276e7a263c35 | 788 | /* set size of partial body */ |
MACRUM | 0:276e7a263c35 | 789 | request_buffer->size = current_size - (index + 4); |
MACRUM | 0:276e7a263c35 | 790 | |
MACRUM | 0:276e7a263c35 | 791 | /* */ |
MACRUM | 0:276e7a263c35 | 792 | if (request_buffer->size >= context->expected_remaining) |
MACRUM | 0:276e7a263c35 | 793 | { |
MACRUM | 0:276e7a263c35 | 794 | /* all data received - process data */ |
MACRUM | 0:276e7a263c35 | 795 | arm_uc_socket_process_body(); |
MACRUM | 0:276e7a263c35 | 796 | } |
MACRUM | 0:276e7a263c35 | 797 | else |
MACRUM | 0:276e7a263c35 | 798 | { |
MACRUM | 0:276e7a263c35 | 799 | /* expecting more data - continue receiving */ |
MACRUM | 0:276e7a263c35 | 800 | UC_SRCE_TRACE("expecting more data %" PRIu32 "/%" PRIu32 "\r\n", |
MACRUM | 0:276e7a263c35 | 801 | request_buffer->size, |
MACRUM | 0:276e7a263c35 | 802 | context->expected_remaining); |
MACRUM | 0:276e7a263c35 | 803 | } |
MACRUM | 0:276e7a263c35 | 804 | |
MACRUM | 0:276e7a263c35 | 805 | /* signal clean up is not needed */ |
MACRUM | 0:276e7a263c35 | 806 | request_successfully_processed = true; |
MACRUM | 0:276e7a263c35 | 807 | |
MACRUM | 0:276e7a263c35 | 808 | /* continue processing body */ |
MACRUM | 0:276e7a263c35 | 809 | context->socket_state = STATE_PROCESS_BODY; |
MACRUM | 0:276e7a263c35 | 810 | } |
MACRUM | 0:276e7a263c35 | 811 | else |
MACRUM | 0:276e7a263c35 | 812 | { |
MACRUM | 0:276e7a263c35 | 813 | UC_SRCE_ERR_MSG("Error: unable to parse content length"); |
MACRUM | 0:276e7a263c35 | 814 | } |
MACRUM | 0:276e7a263c35 | 815 | } |
MACRUM | 0:276e7a263c35 | 816 | else |
MACRUM | 0:276e7a263c35 | 817 | { |
MACRUM | 0:276e7a263c35 | 818 | UC_SRCE_ERR_MSG("Error: unable find content length"); |
MACRUM | 0:276e7a263c35 | 819 | } |
MACRUM | 0:276e7a263c35 | 820 | } |
MACRUM | 0:276e7a263c35 | 821 | } |
MACRUM | 0:276e7a263c35 | 822 | } |
MACRUM | 0:276e7a263c35 | 823 | else |
MACRUM | 0:276e7a263c35 | 824 | { |
MACRUM | 0:276e7a263c35 | 825 | UC_SRCE_ERR_MSG("Error: unable to read status code"); |
MACRUM | 0:276e7a263c35 | 826 | } |
MACRUM | 0:276e7a263c35 | 827 | } |
MACRUM | 0:276e7a263c35 | 828 | else |
MACRUM | 0:276e7a263c35 | 829 | { |
MACRUM | 0:276e7a263c35 | 830 | UC_SRCE_ERR_MSG("Error: HTTP header not found"); |
MACRUM | 0:276e7a263c35 | 831 | } |
MACRUM | 0:276e7a263c35 | 832 | } |
MACRUM | 0:276e7a263c35 | 833 | |
MACRUM | 0:276e7a263c35 | 834 | /* clean up */ |
MACRUM | 0:276e7a263c35 | 835 | if (request_successfully_processed == false) |
MACRUM | 0:276e7a263c35 | 836 | { |
MACRUM | 0:276e7a263c35 | 837 | arm_uc_socket_error(UCS_HTTP_EVENT_ERROR); |
MACRUM | 0:276e7a263c35 | 838 | } |
MACRUM | 0:276e7a263c35 | 839 | } |
MACRUM | 0:276e7a263c35 | 840 | } |
MACRUM | 0:276e7a263c35 | 841 | |
MACRUM | 0:276e7a263c35 | 842 | /** |
MACRUM | 0:276e7a263c35 | 843 | * @brief Function is called when file or fragment is being downloaded. |
MACRUM | 0:276e7a263c35 | 844 | * @details Function drives the download and continues until the buffer is full |
MACRUM | 0:276e7a263c35 | 845 | * or the expected amount of data has been downloaded. |
MACRUM | 0:276e7a263c35 | 846 | */ |
MACRUM | 0:276e7a263c35 | 847 | void arm_uc_socket_process_body() |
MACRUM | 0:276e7a263c35 | 848 | { |
MACRUM | 0:276e7a263c35 | 849 | /* NULL pointer check */ |
MACRUM | 0:276e7a263c35 | 850 | if (context) |
MACRUM | 0:276e7a263c35 | 851 | { |
MACRUM | 0:276e7a263c35 | 852 | /* check if all expected bytes have been received */ |
MACRUM | 0:276e7a263c35 | 853 | if (context->request_buffer->size >= context->expected_remaining) |
MACRUM | 0:276e7a263c35 | 854 | { |
MACRUM | 0:276e7a263c35 | 855 | UC_SRCE_TRACE("process body done"); |
MACRUM | 0:276e7a263c35 | 856 | |
MACRUM | 0:276e7a263c35 | 857 | /* fragment or file successfully received - post callback */ |
MACRUM | 0:276e7a263c35 | 858 | if (context->callback_handler) |
MACRUM | 0:276e7a263c35 | 859 | { |
MACRUM | 0:276e7a263c35 | 860 | palStatus_t status = pal_osTimerStop(context->timeout_timer_id); |
MACRUM | 0:276e7a263c35 | 861 | if (status != PAL_SUCCESS) |
MACRUM | 0:276e7a263c35 | 862 | { |
MACRUM | 0:276e7a263c35 | 863 | UC_SRCE_ERR_MSG("pal_osTimerStop returned 0x%" PRIX32, |
MACRUM | 0:276e7a263c35 | 864 | (uint32_t) status); |
MACRUM | 0:276e7a263c35 | 865 | arm_uc_socket_close(); |
MACRUM | 0:276e7a263c35 | 866 | } |
MACRUM | 0:276e7a263c35 | 867 | |
MACRUM | 0:276e7a263c35 | 868 | ARM_UC_PostCallback(&context->event_callback_struct, |
MACRUM | 0:276e7a263c35 | 869 | context->callback_handler, |
MACRUM | 0:276e7a263c35 | 870 | UCS_HTTP_EVENT_DOWNLOAD); |
MACRUM | 0:276e7a263c35 | 871 | } |
MACRUM | 0:276e7a263c35 | 872 | |
MACRUM | 0:276e7a263c35 | 873 | /* reset buffers and state */ |
MACRUM | 0:276e7a263c35 | 874 | context->socket_state = STATE_CONNECTED_IDLE; |
MACRUM | 0:276e7a263c35 | 875 | context->request_buffer = NULL; |
MACRUM | 0:276e7a263c35 | 876 | context->expected_event = SOCKET_EVENT_UNDEFINED; |
MACRUM | 0:276e7a263c35 | 877 | } |
MACRUM | 0:276e7a263c35 | 878 | } |
MACRUM | 0:276e7a263c35 | 879 | } |
MACRUM | 0:276e7a263c35 | 880 | |
MACRUM | 0:276e7a263c35 | 881 | /** |
MACRUM | 0:276e7a263c35 | 882 | * @brief Close socket and set internal state to disconnected. |
MACRUM | 0:276e7a263c35 | 883 | */ |
MACRUM | 0:276e7a263c35 | 884 | void arm_uc_socket_close() |
MACRUM | 0:276e7a263c35 | 885 | { |
MACRUM | 0:276e7a263c35 | 886 | /* NULL pointer check */ |
MACRUM | 0:276e7a263c35 | 887 | if (context) |
MACRUM | 0:276e7a263c35 | 888 | { |
MACRUM | 0:276e7a263c35 | 889 | /* close socket if not NULL */ |
MACRUM | 0:276e7a263c35 | 890 | if (context->socket) |
MACRUM | 0:276e7a263c35 | 891 | { |
MACRUM | 0:276e7a263c35 | 892 | pal_close(&context->socket); |
MACRUM | 0:276e7a263c35 | 893 | } |
MACRUM | 0:276e7a263c35 | 894 | |
MACRUM | 0:276e7a263c35 | 895 | /* delete socket timeout timer */ |
MACRUM | 0:276e7a263c35 | 896 | if (context->timeout_timer_id != (palTimerID_t) NULL) |
MACRUM | 0:276e7a263c35 | 897 | { |
MACRUM | 0:276e7a263c35 | 898 | pal_osTimerDelete(&context->timeout_timer_id); |
MACRUM | 0:276e7a263c35 | 899 | } |
MACRUM | 0:276e7a263c35 | 900 | |
MACRUM | 0:276e7a263c35 | 901 | /* reset buffers and state */ |
MACRUM | 0:276e7a263c35 | 902 | context->request_buffer = NULL; |
MACRUM | 0:276e7a263c35 | 903 | context->expected_event = SOCKET_EVENT_UNDEFINED; |
MACRUM | 0:276e7a263c35 | 904 | context->socket_state = STATE_DISCONNECTED; |
MACRUM | 0:276e7a263c35 | 905 | context->timeout_timer_id = 0; |
MACRUM | 0:276e7a263c35 | 906 | } |
MACRUM | 0:276e7a263c35 | 907 | } |
MACRUM | 0:276e7a263c35 | 908 | |
MACRUM | 0:276e7a263c35 | 909 | /** |
MACRUM | 0:276e7a263c35 | 910 | * @brief Close socket, set internal state to disconnected and generate error |
MACRUM | 0:276e7a263c35 | 911 | * event. |
MACRUM | 0:276e7a263c35 | 912 | */ |
MACRUM | 0:276e7a263c35 | 913 | void arm_uc_socket_error(arm_ucs_http_event_t error) |
MACRUM | 0:276e7a263c35 | 914 | { |
MACRUM | 0:276e7a263c35 | 915 | /* NULL pointer check */ |
MACRUM | 0:276e7a263c35 | 916 | if (context) |
MACRUM | 0:276e7a263c35 | 917 | { |
MACRUM | 0:276e7a263c35 | 918 | if (context->socket_state != STATE_DISCONNECTED) |
MACRUM | 0:276e7a263c35 | 919 | { |
MACRUM | 0:276e7a263c35 | 920 | /* close socket */ |
MACRUM | 0:276e7a263c35 | 921 | arm_uc_socket_close(); |
MACRUM | 0:276e7a263c35 | 922 | } |
MACRUM | 0:276e7a263c35 | 923 | |
MACRUM | 0:276e7a263c35 | 924 | /* clear DNS cache */ |
MACRUM | 0:276e7a263c35 | 925 | context->cache_address.addressType = 0; |
MACRUM | 0:276e7a263c35 | 926 | memset(context->cache_address.addressData, 0, PAL_NET_MAX_ADDR_SIZE); |
MACRUM | 0:276e7a263c35 | 927 | context->cache_address_length = 0; |
MACRUM | 0:276e7a263c35 | 928 | |
MACRUM | 0:276e7a263c35 | 929 | /* if callback handler is set, generate error event */ |
MACRUM | 0:276e7a263c35 | 930 | if (context->callback_handler) |
MACRUM | 0:276e7a263c35 | 931 | { |
MACRUM | 0:276e7a263c35 | 932 | UC_SRCE_ERR_MSG("posting to callback with event %d", error); |
MACRUM | 0:276e7a263c35 | 933 | ARM_UC_PostCallback(&context->event_callback_struct, |
MACRUM | 0:276e7a263c35 | 934 | context->callback_handler, |
MACRUM | 0:276e7a263c35 | 935 | error); |
MACRUM | 0:276e7a263c35 | 936 | } |
MACRUM | 0:276e7a263c35 | 937 | } |
MACRUM | 0:276e7a263c35 | 938 | } |
MACRUM | 0:276e7a263c35 | 939 | |
MACRUM | 0:276e7a263c35 | 940 | /** |
MACRUM | 0:276e7a263c35 | 941 | * @brief PAL socket event handler. |
MACRUM | 0:276e7a263c35 | 942 | * @param unused PAL API doesn't support parameters. |
MACRUM | 0:276e7a263c35 | 943 | */ |
MACRUM | 0:276e7a263c35 | 944 | void arm_uc_socket_callback(uint32_t unused) |
MACRUM | 0:276e7a263c35 | 945 | { |
MACRUM | 0:276e7a263c35 | 946 | (void) unused; |
MACRUM | 0:276e7a263c35 | 947 | |
MACRUM | 0:276e7a263c35 | 948 | UC_SRCE_TRACE("arm_uc_socket_callback"); |
MACRUM | 0:276e7a263c35 | 949 | |
MACRUM | 0:276e7a263c35 | 950 | /* NULL pointer check */ |
MACRUM | 0:276e7a263c35 | 951 | if (context) |
MACRUM | 0:276e7a263c35 | 952 | { |
MACRUM | 0:276e7a263c35 | 953 | /* unlock posting callbacks to the queue */ |
MACRUM | 0:276e7a263c35 | 954 | pal_osAtomicIncrement(&context->isr_callback_counter, -1); |
MACRUM | 0:276e7a263c35 | 955 | |
MACRUM | 0:276e7a263c35 | 956 | switch (context->expected_event) |
MACRUM | 0:276e7a263c35 | 957 | { |
MACRUM | 0:276e7a263c35 | 958 | case SOCKET_EVENT_CONNECT_DONE: |
MACRUM | 0:276e7a263c35 | 959 | UC_SRCE_TRACE("Connect done"); |
MACRUM | 0:276e7a263c35 | 960 | |
MACRUM | 0:276e7a263c35 | 961 | context->socket_state = STATE_CONNECTED_IDLE; |
MACRUM | 0:276e7a263c35 | 962 | { |
MACRUM | 0:276e7a263c35 | 963 | arm_uc_error_t result = arm_uc_socket_send_request(); |
MACRUM | 0:276e7a263c35 | 964 | if (result.code != SRCE_ERR_NONE) |
MACRUM | 0:276e7a263c35 | 965 | { |
MACRUM | 0:276e7a263c35 | 966 | UC_SRCE_ERR_MSG("arm_uc_socket_send_request failed: %s", |
MACRUM | 0:276e7a263c35 | 967 | ARM_UC_err2Str(result)); |
MACRUM | 0:276e7a263c35 | 968 | arm_uc_socket_error(UCS_HTTP_EVENT_ERROR); |
MACRUM | 0:276e7a263c35 | 969 | } |
MACRUM | 0:276e7a263c35 | 970 | } |
MACRUM | 0:276e7a263c35 | 971 | break; |
MACRUM | 0:276e7a263c35 | 972 | |
MACRUM | 0:276e7a263c35 | 973 | case SOCKET_EVENT_SEND_DONE: |
MACRUM | 0:276e7a263c35 | 974 | UC_SRCE_TRACE("send done"); |
MACRUM | 0:276e7a263c35 | 975 | |
MACRUM | 0:276e7a263c35 | 976 | /* request send, receive response */ |
MACRUM | 0:276e7a263c35 | 977 | context->expected_event = SOCKET_EVENT_RECEIVE_CONTINUE; |
MACRUM | 0:276e7a263c35 | 978 | arm_uc_socket_receive(); |
MACRUM | 0:276e7a263c35 | 979 | break; |
MACRUM | 0:276e7a263c35 | 980 | |
MACRUM | 0:276e7a263c35 | 981 | case SOCKET_EVENT_RECEIVE_CONTINUE: |
MACRUM | 0:276e7a263c35 | 982 | UC_SRCE_TRACE("recv continue"); |
MACRUM | 0:276e7a263c35 | 983 | |
MACRUM | 0:276e7a263c35 | 984 | /* outstanding data, continue receiving */ |
MACRUM | 0:276e7a263c35 | 985 | arm_uc_socket_receive(); |
MACRUM | 0:276e7a263c35 | 986 | break; |
MACRUM | 0:276e7a263c35 | 987 | |
MACRUM | 0:276e7a263c35 | 988 | case SOCKET_EVENT_TIMER_FIRED: |
MACRUM | 0:276e7a263c35 | 989 | UC_SRCE_TRACE("socket timeout timer fired"); |
MACRUM | 0:276e7a263c35 | 990 | |
MACRUM | 0:276e7a263c35 | 991 | arm_uc_socket_error(UCS_HTTP_EVENT_ERROR); |
MACRUM | 0:276e7a263c35 | 992 | break; |
MACRUM | 0:276e7a263c35 | 993 | |
MACRUM | 0:276e7a263c35 | 994 | case SOCKET_EVENT_UNDEFINED: |
MACRUM | 0:276e7a263c35 | 995 | default: |
MACRUM | 0:276e7a263c35 | 996 | UC_SRCE_TRACE("event: undefined"); |
MACRUM | 0:276e7a263c35 | 997 | break; |
MACRUM | 0:276e7a263c35 | 998 | } |
MACRUM | 0:276e7a263c35 | 999 | } |
MACRUM | 0:276e7a263c35 | 1000 | } |
MACRUM | 0:276e7a263c35 | 1001 | |
MACRUM | 0:276e7a263c35 | 1002 | /** |
MACRUM | 0:276e7a263c35 | 1003 | * @brief Callback handler for PAL socket events. Callbacks go through the task |
MACRUM | 0:276e7a263c35 | 1004 | * queue because we don't know what context we are running from. |
MACRUM | 0:276e7a263c35 | 1005 | */ |
MACRUM | 0:276e7a263c35 | 1006 | void arm_uc_socket_isr(void* unused) |
MACRUM | 0:276e7a263c35 | 1007 | { |
MACRUM | 0:276e7a263c35 | 1008 | /* NULL pointer check */ |
MACRUM | 0:276e7a263c35 | 1009 | if (context) |
MACRUM | 0:276e7a263c35 | 1010 | { |
MACRUM | 0:276e7a263c35 | 1011 | /* ensure we only have one callback in flight */ |
MACRUM | 0:276e7a263c35 | 1012 | int32_t count = pal_osAtomicIncrement(&context->isr_callback_counter, 0); |
MACRUM | 0:276e7a263c35 | 1013 | |
MACRUM | 0:276e7a263c35 | 1014 | if (count == 0) |
MACRUM | 0:276e7a263c35 | 1015 | { |
MACRUM | 0:276e7a263c35 | 1016 | pal_osAtomicIncrement(&context->isr_callback_counter, 1); |
MACRUM | 0:276e7a263c35 | 1017 | |
MACRUM | 0:276e7a263c35 | 1018 | /* post callback to de-escalate event */ |
MACRUM | 0:276e7a263c35 | 1019 | ARM_UC_PostCallback(&context->isr_callback_struct, |
MACRUM | 0:276e7a263c35 | 1020 | arm_uc_socket_callback, |
MACRUM | 0:276e7a263c35 | 1021 | 0); |
MACRUM | 0:276e7a263c35 | 1022 | } |
MACRUM | 0:276e7a263c35 | 1023 | } |
MACRUM | 0:276e7a263c35 | 1024 | } |
MACRUM | 0:276e7a263c35 | 1025 | |
MACRUM | 0:276e7a263c35 | 1026 | /** |
MACRUM | 0:276e7a263c35 | 1027 | * @brief Callback handler for the socket timeout timer callback. |
MACRUM | 0:276e7a263c35 | 1028 | * Callbacks go through the task queue because we don't know |
MACRUM | 0:276e7a263c35 | 1029 | * what context we are running from. |
MACRUM | 0:276e7a263c35 | 1030 | */ |
MACRUM | 0:276e7a263c35 | 1031 | void arm_uc_timeout_timer_callback(void const *unused) |
MACRUM | 0:276e7a263c35 | 1032 | { |
MACRUM | 0:276e7a263c35 | 1033 | (void) unused; |
MACRUM | 0:276e7a263c35 | 1034 | |
MACRUM | 0:276e7a263c35 | 1035 | context->expected_event = SOCKET_EVENT_TIMER_FIRED; |
MACRUM | 0:276e7a263c35 | 1036 | /* push event to the socket event queue */ |
MACRUM | 0:276e7a263c35 | 1037 | arm_uc_socket_isr(NULL); |
MACRUM | 0:276e7a263c35 | 1038 | } |