Toyomasa Watarai / simple-mbed-cloud-client

Dependents:  

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?

UserRevisionLine numberNew 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 }