Webserver+3d print

Dependents:   Nucleo

Committer:
Sergunb
Date:
Sat Feb 04 18:15:49 2017 +0000
Revision:
0:8918a71cdbe9
nothing else

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Sergunb 0:8918a71cdbe9 1 /**
Sergunb 0:8918a71cdbe9 2 * @file web_socket.c
Sergunb 0:8918a71cdbe9 3 * @brief WebSocket API (client and server)
Sergunb 0:8918a71cdbe9 4 *
Sergunb 0:8918a71cdbe9 5 * @section License
Sergunb 0:8918a71cdbe9 6 *
Sergunb 0:8918a71cdbe9 7 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
Sergunb 0:8918a71cdbe9 8 *
Sergunb 0:8918a71cdbe9 9 * This file is part of CycloneTCP Open.
Sergunb 0:8918a71cdbe9 10 *
Sergunb 0:8918a71cdbe9 11 * This program is free software; you can redistribute it and/or
Sergunb 0:8918a71cdbe9 12 * modify it under the terms of the GNU General Public License
Sergunb 0:8918a71cdbe9 13 * as published by the Free Software Foundation; either version 2
Sergunb 0:8918a71cdbe9 14 * of the License, or (at your option) any later version.
Sergunb 0:8918a71cdbe9 15 *
Sergunb 0:8918a71cdbe9 16 * This program is distributed in the hope that it will be useful,
Sergunb 0:8918a71cdbe9 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Sergunb 0:8918a71cdbe9 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Sergunb 0:8918a71cdbe9 19 * GNU General Public License for more details.
Sergunb 0:8918a71cdbe9 20 *
Sergunb 0:8918a71cdbe9 21 * You should have received a copy of the GNU General Public License
Sergunb 0:8918a71cdbe9 22 * along with this program; if not, write to the Free Software Foundation,
Sergunb 0:8918a71cdbe9 23 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Sergunb 0:8918a71cdbe9 24 *
Sergunb 0:8918a71cdbe9 25 * @author Oryx Embedded SARL (www.oryx-embedded.com)
Sergunb 0:8918a71cdbe9 26 * @version 1.7.6
Sergunb 0:8918a71cdbe9 27 **/
Sergunb 0:8918a71cdbe9 28
Sergunb 0:8918a71cdbe9 29 //Switch to the appropriate trace level
Sergunb 0:8918a71cdbe9 30 #define TRACE_LEVEL WEB_SOCKET_TRACE_LEVEL
Sergunb 0:8918a71cdbe9 31
Sergunb 0:8918a71cdbe9 32 //Dependencies
Sergunb 0:8918a71cdbe9 33 #include <stdlib.h>
Sergunb 0:8918a71cdbe9 34 #include "core/net.h"
Sergunb 0:8918a71cdbe9 35 #include "web_socket/web_socket.h"
Sergunb 0:8918a71cdbe9 36 #include "web_socket/web_socket_auth.h"
Sergunb 0:8918a71cdbe9 37 #include "web_socket/web_socket_frame.h"
Sergunb 0:8918a71cdbe9 38 #include "web_socket/web_socket_transport.h"
Sergunb 0:8918a71cdbe9 39 #include "web_socket/web_socket_misc.h"
Sergunb 0:8918a71cdbe9 40 #include "str.h"
Sergunb 0:8918a71cdbe9 41 #include "base64.h"
Sergunb 0:8918a71cdbe9 42 #include "debug.h"
Sergunb 0:8918a71cdbe9 43
Sergunb 0:8918a71cdbe9 44 //Check TCP/IP stack configuration
Sergunb 0:8918a71cdbe9 45 #if (WEB_SOCKET_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 46
Sergunb 0:8918a71cdbe9 47 //WebSocket table
Sergunb 0:8918a71cdbe9 48 WebSocket webSocketTable[WEB_SOCKET_MAX_COUNT];
Sergunb 0:8918a71cdbe9 49 //Random data generation callback function
Sergunb 0:8918a71cdbe9 50 WebSocketRandCallback webSockRandCallback;
Sergunb 0:8918a71cdbe9 51
Sergunb 0:8918a71cdbe9 52
Sergunb 0:8918a71cdbe9 53 /**
Sergunb 0:8918a71cdbe9 54 * @brief WebSocket related initialization
Sergunb 0:8918a71cdbe9 55 * @return Error code
Sergunb 0:8918a71cdbe9 56 **/
Sergunb 0:8918a71cdbe9 57
Sergunb 0:8918a71cdbe9 58 error_t webSocketInit(void)
Sergunb 0:8918a71cdbe9 59 {
Sergunb 0:8918a71cdbe9 60 //Initialize WebSockets
Sergunb 0:8918a71cdbe9 61 memset(webSocketTable, 0, sizeof(webSocketTable));
Sergunb 0:8918a71cdbe9 62
Sergunb 0:8918a71cdbe9 63 //Successful initialization
Sergunb 0:8918a71cdbe9 64 return NO_ERROR;
Sergunb 0:8918a71cdbe9 65 }
Sergunb 0:8918a71cdbe9 66
Sergunb 0:8918a71cdbe9 67
Sergunb 0:8918a71cdbe9 68 /**
Sergunb 0:8918a71cdbe9 69 * @brief Register RNG callback function
Sergunb 0:8918a71cdbe9 70 * @param[in] callback RNG callback function
Sergunb 0:8918a71cdbe9 71 * @return Error code
Sergunb 0:8918a71cdbe9 72 **/
Sergunb 0:8918a71cdbe9 73
Sergunb 0:8918a71cdbe9 74 error_t webSocketRegisterRandCallback(WebSocketRandCallback callback)
Sergunb 0:8918a71cdbe9 75 {
Sergunb 0:8918a71cdbe9 76 //Check parameter
Sergunb 0:8918a71cdbe9 77 if(callback == NULL)
Sergunb 0:8918a71cdbe9 78 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 79
Sergunb 0:8918a71cdbe9 80 //Save callback function
Sergunb 0:8918a71cdbe9 81 webSockRandCallback = callback;
Sergunb 0:8918a71cdbe9 82
Sergunb 0:8918a71cdbe9 83 //Successful processing
Sergunb 0:8918a71cdbe9 84 return NO_ERROR;
Sergunb 0:8918a71cdbe9 85 }
Sergunb 0:8918a71cdbe9 86
Sergunb 0:8918a71cdbe9 87
Sergunb 0:8918a71cdbe9 88 /**
Sergunb 0:8918a71cdbe9 89 * @brief Create a WebSocket
Sergunb 0:8918a71cdbe9 90 * @return Handle referencing the new WebSocket
Sergunb 0:8918a71cdbe9 91 **/
Sergunb 0:8918a71cdbe9 92
Sergunb 0:8918a71cdbe9 93 WebSocket *webSocketOpen(void)
Sergunb 0:8918a71cdbe9 94 {
Sergunb 0:8918a71cdbe9 95 uint_t i;
Sergunb 0:8918a71cdbe9 96 WebSocket *webSocket;
Sergunb 0:8918a71cdbe9 97
Sergunb 0:8918a71cdbe9 98 //Initialize WebSocket handle
Sergunb 0:8918a71cdbe9 99 webSocket = NULL;
Sergunb 0:8918a71cdbe9 100
Sergunb 0:8918a71cdbe9 101 //Get exclusive access
Sergunb 0:8918a71cdbe9 102 osAcquireMutex(&netMutex);
Sergunb 0:8918a71cdbe9 103
Sergunb 0:8918a71cdbe9 104 //Loop through WebSocket descriptors
Sergunb 0:8918a71cdbe9 105 for(i = 0; i < WEB_SOCKET_MAX_COUNT; i++)
Sergunb 0:8918a71cdbe9 106 {
Sergunb 0:8918a71cdbe9 107 //Unused WebSocket found?
Sergunb 0:8918a71cdbe9 108 if(webSocketTable[i].state == WS_STATE_UNUSED)
Sergunb 0:8918a71cdbe9 109 {
Sergunb 0:8918a71cdbe9 110 //Save socket handle
Sergunb 0:8918a71cdbe9 111 webSocket = &webSocketTable[i];
Sergunb 0:8918a71cdbe9 112
Sergunb 0:8918a71cdbe9 113 //Clear associated structure
Sergunb 0:8918a71cdbe9 114 memset(webSocket, 0, sizeof(WebSocket));
Sergunb 0:8918a71cdbe9 115 //Set the default timeout to be used
Sergunb 0:8918a71cdbe9 116 webSocket->timeout = INFINITE_DELAY;
Sergunb 0:8918a71cdbe9 117 //Enter the CLOSED state
Sergunb 0:8918a71cdbe9 118 webSocket->state = WS_STATE_CLOSED;
Sergunb 0:8918a71cdbe9 119
Sergunb 0:8918a71cdbe9 120 //We are done
Sergunb 0:8918a71cdbe9 121 break;
Sergunb 0:8918a71cdbe9 122 }
Sergunb 0:8918a71cdbe9 123 }
Sergunb 0:8918a71cdbe9 124
Sergunb 0:8918a71cdbe9 125 //Release exclusive access
Sergunb 0:8918a71cdbe9 126 osReleaseMutex(&netMutex);
Sergunb 0:8918a71cdbe9 127
Sergunb 0:8918a71cdbe9 128 //Return a handle to the freshly created WebSocket
Sergunb 0:8918a71cdbe9 129 return webSocket;
Sergunb 0:8918a71cdbe9 130 }
Sergunb 0:8918a71cdbe9 131
Sergunb 0:8918a71cdbe9 132
Sergunb 0:8918a71cdbe9 133 /**
Sergunb 0:8918a71cdbe9 134 * @brief Upgrade a socket to a WebSocket
Sergunb 0:8918a71cdbe9 135 * @param[in] socket Handle referencing the socket
Sergunb 0:8918a71cdbe9 136 * @return Handle referencing the new WebSocket
Sergunb 0:8918a71cdbe9 137 **/
Sergunb 0:8918a71cdbe9 138
Sergunb 0:8918a71cdbe9 139 WebSocket *webSocketUpgradeSocket(Socket *socket)
Sergunb 0:8918a71cdbe9 140 {
Sergunb 0:8918a71cdbe9 141 WebSocket *webSocket;
Sergunb 0:8918a71cdbe9 142
Sergunb 0:8918a71cdbe9 143 //Valid socket handle?
Sergunb 0:8918a71cdbe9 144 if(socket != NULL)
Sergunb 0:8918a71cdbe9 145 {
Sergunb 0:8918a71cdbe9 146 //Create a new WebSocket
Sergunb 0:8918a71cdbe9 147 webSocket = webSocketOpen();
Sergunb 0:8918a71cdbe9 148
Sergunb 0:8918a71cdbe9 149 //WebSocket successfully created?
Sergunb 0:8918a71cdbe9 150 if(webSocket != NULL)
Sergunb 0:8918a71cdbe9 151 {
Sergunb 0:8918a71cdbe9 152 //Attach the socket handle
Sergunb 0:8918a71cdbe9 153 webSocket->socket = socket;
Sergunb 0:8918a71cdbe9 154 //Initialize state
Sergunb 0:8918a71cdbe9 155 webSocket->state = WS_STATE_INIT;
Sergunb 0:8918a71cdbe9 156 }
Sergunb 0:8918a71cdbe9 157 }
Sergunb 0:8918a71cdbe9 158 else
Sergunb 0:8918a71cdbe9 159 {
Sergunb 0:8918a71cdbe9 160 //The specified socket is not valid...
Sergunb 0:8918a71cdbe9 161 webSocket = NULL;
Sergunb 0:8918a71cdbe9 162 }
Sergunb 0:8918a71cdbe9 163
Sergunb 0:8918a71cdbe9 164 //Return a handle to the freshly created WebSocket
Sergunb 0:8918a71cdbe9 165 return webSocket;
Sergunb 0:8918a71cdbe9 166 }
Sergunb 0:8918a71cdbe9 167
Sergunb 0:8918a71cdbe9 168
Sergunb 0:8918a71cdbe9 169 #if (WEB_SOCKET_TLS_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 170
Sergunb 0:8918a71cdbe9 171 /**
Sergunb 0:8918a71cdbe9 172 * @brief Upgrade a secure socket to a secure WebSocket
Sergunb 0:8918a71cdbe9 173 * @param[in] socket Handle referencing the socket
Sergunb 0:8918a71cdbe9 174 * @param[in] tlsContext Pointer to the SSL/TLS context
Sergunb 0:8918a71cdbe9 175 * @return Handle referencing the new WebSocket
Sergunb 0:8918a71cdbe9 176 **/
Sergunb 0:8918a71cdbe9 177
Sergunb 0:8918a71cdbe9 178 WebSocket *webSocketUpgradeSecureSocket(Socket *socket, TlsContext *tlsContext)
Sergunb 0:8918a71cdbe9 179 {
Sergunb 0:8918a71cdbe9 180 WebSocket *webSocket;
Sergunb 0:8918a71cdbe9 181
Sergunb 0:8918a71cdbe9 182 //Valid SSL/TLS context?
Sergunb 0:8918a71cdbe9 183 if(tlsContext != NULL)
Sergunb 0:8918a71cdbe9 184 {
Sergunb 0:8918a71cdbe9 185 //Create a new WebSocket
Sergunb 0:8918a71cdbe9 186 webSocket = webSocketOpen();
Sergunb 0:8918a71cdbe9 187
Sergunb 0:8918a71cdbe9 188 //WebSocket successfully created?
Sergunb 0:8918a71cdbe9 189 if(webSocket != NULL)
Sergunb 0:8918a71cdbe9 190 {
Sergunb 0:8918a71cdbe9 191 //Attach the socket handle
Sergunb 0:8918a71cdbe9 192 webSocket->socket = socket;
Sergunb 0:8918a71cdbe9 193 //Attach the SSL/TLS context
Sergunb 0:8918a71cdbe9 194 webSocket->tlsContext = tlsContext;
Sergunb 0:8918a71cdbe9 195 //Initialize state
Sergunb 0:8918a71cdbe9 196 webSocket->state = WS_STATE_INIT;
Sergunb 0:8918a71cdbe9 197 }
Sergunb 0:8918a71cdbe9 198 }
Sergunb 0:8918a71cdbe9 199 else
Sergunb 0:8918a71cdbe9 200 {
Sergunb 0:8918a71cdbe9 201 //The specified socket is not valid...
Sergunb 0:8918a71cdbe9 202 webSocket = NULL;
Sergunb 0:8918a71cdbe9 203 }
Sergunb 0:8918a71cdbe9 204
Sergunb 0:8918a71cdbe9 205 //Return a handle to the freshly created WebSocket
Sergunb 0:8918a71cdbe9 206 return webSocket;
Sergunb 0:8918a71cdbe9 207 }
Sergunb 0:8918a71cdbe9 208
Sergunb 0:8918a71cdbe9 209
Sergunb 0:8918a71cdbe9 210 /**
Sergunb 0:8918a71cdbe9 211 * @brief Register TLS initialization callback function
Sergunb 0:8918a71cdbe9 212 * @param[in] webSocket Handle that identifies a WebSocket
Sergunb 0:8918a71cdbe9 213 * @param[in] callback TLS initialization callback function
Sergunb 0:8918a71cdbe9 214 * @return Error code
Sergunb 0:8918a71cdbe9 215 **/
Sergunb 0:8918a71cdbe9 216
Sergunb 0:8918a71cdbe9 217 error_t webSocketRegisterTlsInitCallback(WebSocket *webSocket,
Sergunb 0:8918a71cdbe9 218 WebSocketTlsInitCallback callback)
Sergunb 0:8918a71cdbe9 219 {
Sergunb 0:8918a71cdbe9 220 //Check parameters
Sergunb 0:8918a71cdbe9 221 if(webSocket == NULL || callback == NULL)
Sergunb 0:8918a71cdbe9 222 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 223
Sergunb 0:8918a71cdbe9 224 //Save callback function
Sergunb 0:8918a71cdbe9 225 webSocket->tlsInitCallback = callback;
Sergunb 0:8918a71cdbe9 226
Sergunb 0:8918a71cdbe9 227 //Successful processing
Sergunb 0:8918a71cdbe9 228 return NO_ERROR;
Sergunb 0:8918a71cdbe9 229 }
Sergunb 0:8918a71cdbe9 230
Sergunb 0:8918a71cdbe9 231 #endif
Sergunb 0:8918a71cdbe9 232
Sergunb 0:8918a71cdbe9 233
Sergunb 0:8918a71cdbe9 234 /**
Sergunb 0:8918a71cdbe9 235 * @brief Set timeout value for blocking operations
Sergunb 0:8918a71cdbe9 236 * @param[in] webSocket Handle to a WebSocket
Sergunb 0:8918a71cdbe9 237 * @param[in] timeout Maximum time to wait
Sergunb 0:8918a71cdbe9 238 * @return Error code
Sergunb 0:8918a71cdbe9 239 **/
Sergunb 0:8918a71cdbe9 240
Sergunb 0:8918a71cdbe9 241 error_t webSocketSetTimeout(WebSocket *webSocket, systime_t timeout)
Sergunb 0:8918a71cdbe9 242 {
Sergunb 0:8918a71cdbe9 243 //Make sure the WebSocket handle is valid
Sergunb 0:8918a71cdbe9 244 if(webSocket == NULL)
Sergunb 0:8918a71cdbe9 245 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 246
Sergunb 0:8918a71cdbe9 247 //Save timeout value
Sergunb 0:8918a71cdbe9 248 webSocket->timeout = timeout;
Sergunb 0:8918a71cdbe9 249
Sergunb 0:8918a71cdbe9 250 //Valid socket?
Sergunb 0:8918a71cdbe9 251 if(webSocket->socket != NULL)
Sergunb 0:8918a71cdbe9 252 socketSetTimeout(webSocket->socket, timeout);
Sergunb 0:8918a71cdbe9 253
Sergunb 0:8918a71cdbe9 254 //Successful processing
Sergunb 0:8918a71cdbe9 255 return NO_ERROR;
Sergunb 0:8918a71cdbe9 256 }
Sergunb 0:8918a71cdbe9 257
Sergunb 0:8918a71cdbe9 258
Sergunb 0:8918a71cdbe9 259 /**
Sergunb 0:8918a71cdbe9 260 * @brief Set the hostname of the resource being requested
Sergunb 0:8918a71cdbe9 261 * @param[in] webSocket Handle to a WebSocket
Sergunb 0:8918a71cdbe9 262 * @param[in] host NULL-terminated string containing the hostname
Sergunb 0:8918a71cdbe9 263 * @return Error code
Sergunb 0:8918a71cdbe9 264 **/
Sergunb 0:8918a71cdbe9 265
Sergunb 0:8918a71cdbe9 266 error_t webSocketSetHost(WebSocket *webSocket, const char_t *host)
Sergunb 0:8918a71cdbe9 267 {
Sergunb 0:8918a71cdbe9 268 //Check parameters
Sergunb 0:8918a71cdbe9 269 if(webSocket == NULL || host == NULL)
Sergunb 0:8918a71cdbe9 270 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 271
Sergunb 0:8918a71cdbe9 272 //Save the hostname
Sergunb 0:8918a71cdbe9 273 strSafeCopy(webSocket->host, host, WEB_SOCKET_HOST_MAX_LEN);
Sergunb 0:8918a71cdbe9 274
Sergunb 0:8918a71cdbe9 275 //Successful processing
Sergunb 0:8918a71cdbe9 276 return NO_ERROR;
Sergunb 0:8918a71cdbe9 277 }
Sergunb 0:8918a71cdbe9 278
Sergunb 0:8918a71cdbe9 279
Sergunb 0:8918a71cdbe9 280 /**
Sergunb 0:8918a71cdbe9 281 * @brief Set the origin header field
Sergunb 0:8918a71cdbe9 282 * @param[in] webSocket Handle to a WebSocket
Sergunb 0:8918a71cdbe9 283 * @param[in] origin NULL-terminated string containing the origin
Sergunb 0:8918a71cdbe9 284 * @return Error code
Sergunb 0:8918a71cdbe9 285 **/
Sergunb 0:8918a71cdbe9 286
Sergunb 0:8918a71cdbe9 287 error_t webSocketSetOrigin(WebSocket *webSocket, const char_t *origin)
Sergunb 0:8918a71cdbe9 288 {
Sergunb 0:8918a71cdbe9 289 //Check parameters
Sergunb 0:8918a71cdbe9 290 if(webSocket == NULL || origin == NULL)
Sergunb 0:8918a71cdbe9 291 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 292
Sergunb 0:8918a71cdbe9 293 //Save origin
Sergunb 0:8918a71cdbe9 294 strSafeCopy(webSocket->origin, origin, WEB_SOCKET_ORIGIN_MAX_LEN);
Sergunb 0:8918a71cdbe9 295
Sergunb 0:8918a71cdbe9 296 //Successful processing
Sergunb 0:8918a71cdbe9 297 return NO_ERROR;
Sergunb 0:8918a71cdbe9 298 }
Sergunb 0:8918a71cdbe9 299
Sergunb 0:8918a71cdbe9 300
Sergunb 0:8918a71cdbe9 301 /**
Sergunb 0:8918a71cdbe9 302 * @brief Set the sub-protocol header field
Sergunb 0:8918a71cdbe9 303 * @param[in] webSocket Handle to a WebSocket
Sergunb 0:8918a71cdbe9 304 * @param[in] subProtocol NULL-terminated string containing the sub-protocol
Sergunb 0:8918a71cdbe9 305 * @return Error code
Sergunb 0:8918a71cdbe9 306 **/
Sergunb 0:8918a71cdbe9 307
Sergunb 0:8918a71cdbe9 308 error_t webSocketSetSubProtocol(WebSocket *webSocket, const char_t *subProtocol)
Sergunb 0:8918a71cdbe9 309 {
Sergunb 0:8918a71cdbe9 310 //Check parameters
Sergunb 0:8918a71cdbe9 311 if(webSocket == NULL || subProtocol == NULL)
Sergunb 0:8918a71cdbe9 312 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 313
Sergunb 0:8918a71cdbe9 314 //Save sub-protocol
Sergunb 0:8918a71cdbe9 315 strSafeCopy(webSocket->subProtocol, subProtocol, WEB_SOCKET_SUB_PROTOCOL_MAX_LEN);
Sergunb 0:8918a71cdbe9 316
Sergunb 0:8918a71cdbe9 317 //Successful processing
Sergunb 0:8918a71cdbe9 318 return NO_ERROR;
Sergunb 0:8918a71cdbe9 319 }
Sergunb 0:8918a71cdbe9 320
Sergunb 0:8918a71cdbe9 321
Sergunb 0:8918a71cdbe9 322 /**
Sergunb 0:8918a71cdbe9 323 * @brief Set authentication information
Sergunb 0:8918a71cdbe9 324 * @param[in] webSocket Handle to a WebSocket
Sergunb 0:8918a71cdbe9 325 * @param[in] username NULL-terminated string containing the user name to be used
Sergunb 0:8918a71cdbe9 326 * @param[in] password NULL-terminated string containing the password to be used
Sergunb 0:8918a71cdbe9 327 * @param[in] allowedAuthModes Logic OR of allowed HTTP authentication modes
Sergunb 0:8918a71cdbe9 328 * @return Error code
Sergunb 0:8918a71cdbe9 329 **/
Sergunb 0:8918a71cdbe9 330
Sergunb 0:8918a71cdbe9 331 error_t webSocketSetAuthInfo(WebSocket *webSocket, const char_t *username,
Sergunb 0:8918a71cdbe9 332 const char_t *password, uint_t allowedAuthModes)
Sergunb 0:8918a71cdbe9 333 {
Sergunb 0:8918a71cdbe9 334 #if (WEB_SOCKET_BASIC_AUTH_SUPPORT == ENABLED || WEB_SOCKET_DIGEST_AUTH_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 335 WebSocketAuthContext *authContext;
Sergunb 0:8918a71cdbe9 336
Sergunb 0:8918a71cdbe9 337 //Check parameters
Sergunb 0:8918a71cdbe9 338 if(webSocket == NULL || username == NULL || password == NULL)
Sergunb 0:8918a71cdbe9 339 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 340
Sergunb 0:8918a71cdbe9 341 //Point to the authentication context
Sergunb 0:8918a71cdbe9 342 authContext = &webSocket->authContext;
Sergunb 0:8918a71cdbe9 343
Sergunb 0:8918a71cdbe9 344 //Save user name
Sergunb 0:8918a71cdbe9 345 strSafeCopy(authContext->username, username, WEB_SOCKET_USERNAME_MAX_LEN);
Sergunb 0:8918a71cdbe9 346 //Save password
Sergunb 0:8918a71cdbe9 347 strSafeCopy(authContext->password, password, WEB_SOCKET_PASSWORD_MAX_LEN);
Sergunb 0:8918a71cdbe9 348 //Save the list of allowed HTTP authentication modes
Sergunb 0:8918a71cdbe9 349 authContext->allowedAuthModes = allowedAuthModes;
Sergunb 0:8918a71cdbe9 350 #endif
Sergunb 0:8918a71cdbe9 351
Sergunb 0:8918a71cdbe9 352 //Successful processing
Sergunb 0:8918a71cdbe9 353 return NO_ERROR;
Sergunb 0:8918a71cdbe9 354 }
Sergunb 0:8918a71cdbe9 355
Sergunb 0:8918a71cdbe9 356
Sergunb 0:8918a71cdbe9 357 /**
Sergunb 0:8918a71cdbe9 358 * @brief Bind the WebSocket to a particular network interface
Sergunb 0:8918a71cdbe9 359 * @param[in] webSocket Handle to a WebSocket
Sergunb 0:8918a71cdbe9 360 * @param[in] interface Network interface to be used
Sergunb 0:8918a71cdbe9 361 * @return Error code
Sergunb 0:8918a71cdbe9 362 **/
Sergunb 0:8918a71cdbe9 363
Sergunb 0:8918a71cdbe9 364 error_t webSocketBindToInterface(WebSocket *webSocket, NetInterface *interface)
Sergunb 0:8918a71cdbe9 365 {
Sergunb 0:8918a71cdbe9 366 //Make sure the WebSocket handle is valid
Sergunb 0:8918a71cdbe9 367 if(webSocket == NULL)
Sergunb 0:8918a71cdbe9 368 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 369
Sergunb 0:8918a71cdbe9 370 //Explicitly associate the WebSocket with the specified interface
Sergunb 0:8918a71cdbe9 371 webSocket->interface = interface;
Sergunb 0:8918a71cdbe9 372
Sergunb 0:8918a71cdbe9 373 //Successful processing
Sergunb 0:8918a71cdbe9 374 return NO_ERROR;
Sergunb 0:8918a71cdbe9 375 }
Sergunb 0:8918a71cdbe9 376
Sergunb 0:8918a71cdbe9 377
Sergunb 0:8918a71cdbe9 378 /**
Sergunb 0:8918a71cdbe9 379 * @brief Establish a WebSocket connection
Sergunb 0:8918a71cdbe9 380 * @param[in] webSocket Handle to a WebSocket
Sergunb 0:8918a71cdbe9 381 * @param[in] serverIpAddr IP address of the WebSocket server to connect to
Sergunb 0:8918a71cdbe9 382 * @param[in] serverPort TCP port number that will be used to establish the
Sergunb 0:8918a71cdbe9 383 * connection
Sergunb 0:8918a71cdbe9 384 * @param[in] uri NULL-terminated string that contains the resource name
Sergunb 0:8918a71cdbe9 385 * @return Error code
Sergunb 0:8918a71cdbe9 386 **/
Sergunb 0:8918a71cdbe9 387
Sergunb 0:8918a71cdbe9 388 error_t webSocketConnect(WebSocket *webSocket, const IpAddr *serverIpAddr,
Sergunb 0:8918a71cdbe9 389 uint16_t serverPort, const char_t *uri)
Sergunb 0:8918a71cdbe9 390 {
Sergunb 0:8918a71cdbe9 391 error_t error;
Sergunb 0:8918a71cdbe9 392 size_t n;
Sergunb 0:8918a71cdbe9 393 WebSocketFrameContext *txContext;
Sergunb 0:8918a71cdbe9 394
Sergunb 0:8918a71cdbe9 395 //Make sure the WebSocket handle is valid
Sergunb 0:8918a71cdbe9 396 if(webSocket == NULL)
Sergunb 0:8918a71cdbe9 397 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 398
Sergunb 0:8918a71cdbe9 399 //Point to the TX context
Sergunb 0:8918a71cdbe9 400 txContext = &webSocket->txContext;
Sergunb 0:8918a71cdbe9 401
Sergunb 0:8918a71cdbe9 402 //Initialize status code
Sergunb 0:8918a71cdbe9 403 error = NO_ERROR;
Sergunb 0:8918a71cdbe9 404
Sergunb 0:8918a71cdbe9 405 //Establish connection
Sergunb 0:8918a71cdbe9 406 while(webSocket->state != WS_STATE_OPEN)
Sergunb 0:8918a71cdbe9 407 {
Sergunb 0:8918a71cdbe9 408 //Check current state
Sergunb 0:8918a71cdbe9 409 if(webSocket->state == WS_STATE_CLOSED)
Sergunb 0:8918a71cdbe9 410 {
Sergunb 0:8918a71cdbe9 411 //Check parameters
Sergunb 0:8918a71cdbe9 412 if(serverIpAddr == NULL || uri == NULL)
Sergunb 0:8918a71cdbe9 413 {
Sergunb 0:8918a71cdbe9 414 //Report an error
Sergunb 0:8918a71cdbe9 415 error = ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 416 }
Sergunb 0:8918a71cdbe9 417 else
Sergunb 0:8918a71cdbe9 418 {
Sergunb 0:8918a71cdbe9 419 //A WebSocket client is a WebSocket endpoint that initiates a
Sergunb 0:8918a71cdbe9 420 //connection to a peer
Sergunb 0:8918a71cdbe9 421 webSocket->endpoint = WS_ENDPOINT_CLIENT;
Sergunb 0:8918a71cdbe9 422
Sergunb 0:8918a71cdbe9 423 //Save the URI
Sergunb 0:8918a71cdbe9 424 strSafeCopy(webSocket->uri, uri, WEB_SOCKET_URI_MAX_LEN);
Sergunb 0:8918a71cdbe9 425 //Reset retry counter
Sergunb 0:8918a71cdbe9 426 webSocket->retryCount = 0;
Sergunb 0:8918a71cdbe9 427
Sergunb 0:8918a71cdbe9 428 #if (WEB_SOCKET_BASIC_AUTH_SUPPORT == ENABLED || WEB_SOCKET_DIGEST_AUTH_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 429 //HTTP authentication is not used for the first connection attempt
Sergunb 0:8918a71cdbe9 430 webSocket->authContext.requiredAuthMode = WS_AUTH_MODE_NONE;
Sergunb 0:8918a71cdbe9 431 webSocket->authContext.selectedAuthMode = WS_AUTH_MODE_NONE;
Sergunb 0:8918a71cdbe9 432 #endif
Sergunb 0:8918a71cdbe9 433 //Initialize the WebSocket connection
Sergunb 0:8918a71cdbe9 434 webSocketChangeState(webSocket, WS_STATE_INIT);
Sergunb 0:8918a71cdbe9 435 }
Sergunb 0:8918a71cdbe9 436 }
Sergunb 0:8918a71cdbe9 437 else if(webSocket->state == WS_STATE_INIT)
Sergunb 0:8918a71cdbe9 438 {
Sergunb 0:8918a71cdbe9 439 //Increment retry counter
Sergunb 0:8918a71cdbe9 440 webSocket->retryCount++;
Sergunb 0:8918a71cdbe9 441
Sergunb 0:8918a71cdbe9 442 //Limit the number of connection attempts
Sergunb 0:8918a71cdbe9 443 if(webSocket->retryCount > WEB_SOCKET_MAX_CONN_RETRIES)
Sergunb 0:8918a71cdbe9 444 {
Sergunb 0:8918a71cdbe9 445 //Report an error
Sergunb 0:8918a71cdbe9 446 error = ERROR_OPEN_FAILED;
Sergunb 0:8918a71cdbe9 447 }
Sergunb 0:8918a71cdbe9 448 else
Sergunb 0:8918a71cdbe9 449 {
Sergunb 0:8918a71cdbe9 450 //Open network connection
Sergunb 0:8918a71cdbe9 451 error = webSocketOpenConnection(webSocket);
Sergunb 0:8918a71cdbe9 452 }
Sergunb 0:8918a71cdbe9 453
Sergunb 0:8918a71cdbe9 454 //Check status code
Sergunb 0:8918a71cdbe9 455 if(!error)
Sergunb 0:8918a71cdbe9 456 {
Sergunb 0:8918a71cdbe9 457 //Establish connection
Sergunb 0:8918a71cdbe9 458 webSocketChangeState(webSocket, WS_STATE_CONNECTING);
Sergunb 0:8918a71cdbe9 459 }
Sergunb 0:8918a71cdbe9 460 }
Sergunb 0:8918a71cdbe9 461 else if(webSocket->state == WS_STATE_CONNECTING)
Sergunb 0:8918a71cdbe9 462 {
Sergunb 0:8918a71cdbe9 463 //Establish connection
Sergunb 0:8918a71cdbe9 464 error = webSocketEstablishConnection(webSocket,
Sergunb 0:8918a71cdbe9 465 serverIpAddr, serverPort);
Sergunb 0:8918a71cdbe9 466
Sergunb 0:8918a71cdbe9 467 //Check status code
Sergunb 0:8918a71cdbe9 468 if(!error)
Sergunb 0:8918a71cdbe9 469 {
Sergunb 0:8918a71cdbe9 470 //Generate client's key
Sergunb 0:8918a71cdbe9 471 error = webSocketGenerateClientKey(webSocket);
Sergunb 0:8918a71cdbe9 472 }
Sergunb 0:8918a71cdbe9 473
Sergunb 0:8918a71cdbe9 474 //Check status code
Sergunb 0:8918a71cdbe9 475 if(!error)
Sergunb 0:8918a71cdbe9 476 {
Sergunb 0:8918a71cdbe9 477 //Format client handshake
Sergunb 0:8918a71cdbe9 478 error = webSocketFormatClientHandshake(webSocket, serverPort);
Sergunb 0:8918a71cdbe9 479 }
Sergunb 0:8918a71cdbe9 480
Sergunb 0:8918a71cdbe9 481 //Check status code
Sergunb 0:8918a71cdbe9 482 if(!error)
Sergunb 0:8918a71cdbe9 483 {
Sergunb 0:8918a71cdbe9 484 //Send client handshake
Sergunb 0:8918a71cdbe9 485 webSocketChangeState(webSocket, WS_STATE_CLIENT_HANDSHAKE);
Sergunb 0:8918a71cdbe9 486 }
Sergunb 0:8918a71cdbe9 487 }
Sergunb 0:8918a71cdbe9 488 else if(webSocket->state == WS_STATE_CLIENT_HANDSHAKE)
Sergunb 0:8918a71cdbe9 489 {
Sergunb 0:8918a71cdbe9 490 //Any remaining data to be sent?
Sergunb 0:8918a71cdbe9 491 if(txContext->bufferPos < txContext->bufferLen)
Sergunb 0:8918a71cdbe9 492 {
Sergunb 0:8918a71cdbe9 493 //Send more data
Sergunb 0:8918a71cdbe9 494 error = webSocketSendData(webSocket,
Sergunb 0:8918a71cdbe9 495 txContext->buffer + txContext->bufferPos,
Sergunb 0:8918a71cdbe9 496 txContext->bufferLen - txContext->bufferPos, &n, 0);
Sergunb 0:8918a71cdbe9 497
Sergunb 0:8918a71cdbe9 498 //Advance data pointer
Sergunb 0:8918a71cdbe9 499 txContext->bufferPos += n;
Sergunb 0:8918a71cdbe9 500 }
Sergunb 0:8918a71cdbe9 501 else
Sergunb 0:8918a71cdbe9 502 {
Sergunb 0:8918a71cdbe9 503 //Wait for server handshake
Sergunb 0:8918a71cdbe9 504 webSocketChangeState(webSocket, WS_STATE_SERVER_HANDSHAKE);
Sergunb 0:8918a71cdbe9 505 }
Sergunb 0:8918a71cdbe9 506 }
Sergunb 0:8918a71cdbe9 507 else if(webSocket->state == WS_STATE_SERVER_HANDSHAKE)
Sergunb 0:8918a71cdbe9 508 {
Sergunb 0:8918a71cdbe9 509 //Parse the server handshake
Sergunb 0:8918a71cdbe9 510 error = webSocketParseHandshake(webSocket);
Sergunb 0:8918a71cdbe9 511 }
Sergunb 0:8918a71cdbe9 512 else if(webSocket->state == WS_STATE_SERVER_RESP_BODY)
Sergunb 0:8918a71cdbe9 513 {
Sergunb 0:8918a71cdbe9 514 //Check Connection header field
Sergunb 0:8918a71cdbe9 515 if(webSocket->handshakeContext.connectionClose)
Sergunb 0:8918a71cdbe9 516 {
Sergunb 0:8918a71cdbe9 517 //Close connection
Sergunb 0:8918a71cdbe9 518 webSocketCloseConnection(webSocket);
Sergunb 0:8918a71cdbe9 519 //Try to connect again
Sergunb 0:8918a71cdbe9 520 webSocketChangeState(webSocket, WS_STATE_INIT);
Sergunb 0:8918a71cdbe9 521 }
Sergunb 0:8918a71cdbe9 522 else
Sergunb 0:8918a71cdbe9 523 {
Sergunb 0:8918a71cdbe9 524 //Any remaining data to read in the response body?
Sergunb 0:8918a71cdbe9 525 if(webSocket->handshakeContext.contentLength > 0)
Sergunb 0:8918a71cdbe9 526 {
Sergunb 0:8918a71cdbe9 527 //Limit the number of bytes to read at a time
Sergunb 0:8918a71cdbe9 528 n = MIN(webSocket->handshakeContext.contentLength, WEB_SOCKET_BUFFER_SIZE);
Sergunb 0:8918a71cdbe9 529 //Discard any received data
Sergunb 0:8918a71cdbe9 530 error = webSocketReceiveData(webSocket, txContext->buffer, n, &n, 0);
Sergunb 0:8918a71cdbe9 531 //Decrement byte counter
Sergunb 0:8918a71cdbe9 532 webSocket->handshakeContext.contentLength -= n;
Sergunb 0:8918a71cdbe9 533 }
Sergunb 0:8918a71cdbe9 534 else
Sergunb 0:8918a71cdbe9 535 {
Sergunb 0:8918a71cdbe9 536 //Format client handshake
Sergunb 0:8918a71cdbe9 537 error = webSocketFormatClientHandshake(webSocket, serverPort);
Sergunb 0:8918a71cdbe9 538 //Try to authenticate again
Sergunb 0:8918a71cdbe9 539 webSocketChangeState(webSocket, WS_STATE_CLIENT_HANDSHAKE);
Sergunb 0:8918a71cdbe9 540 }
Sergunb 0:8918a71cdbe9 541 }
Sergunb 0:8918a71cdbe9 542 }
Sergunb 0:8918a71cdbe9 543 else
Sergunb 0:8918a71cdbe9 544 {
Sergunb 0:8918a71cdbe9 545 //Invalid state
Sergunb 0:8918a71cdbe9 546 error = ERROR_WRONG_STATE;
Sergunb 0:8918a71cdbe9 547 }
Sergunb 0:8918a71cdbe9 548
Sergunb 0:8918a71cdbe9 549 //Check whether authentication is required
Sergunb 0:8918a71cdbe9 550 if(error == ERROR_AUTH_REQUIRED)
Sergunb 0:8918a71cdbe9 551 {
Sergunb 0:8918a71cdbe9 552 #if (WEB_SOCKET_BASIC_AUTH_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 553 //Basic authentication?
Sergunb 0:8918a71cdbe9 554 if(webSocket->authContext.requiredAuthMode == WS_AUTH_MODE_BASIC)
Sergunb 0:8918a71cdbe9 555 {
Sergunb 0:8918a71cdbe9 556 //Check whether the basic authentication scheme is allowed
Sergunb 0:8918a71cdbe9 557 if(webSocket->authContext.allowedAuthModes & WS_AUTH_MODE_BASIC)
Sergunb 0:8918a71cdbe9 558 {
Sergunb 0:8918a71cdbe9 559 //Do not try to connect again if the credentials are not valid...
Sergunb 0:8918a71cdbe9 560 if(webSocket->authContext.selectedAuthMode == WS_AUTH_MODE_NONE)
Sergunb 0:8918a71cdbe9 561 {
Sergunb 0:8918a71cdbe9 562 //Catch exception
Sergunb 0:8918a71cdbe9 563 error = NO_ERROR;
Sergunb 0:8918a71cdbe9 564 //Force the WebSocket client to use basic authentication
Sergunb 0:8918a71cdbe9 565 webSocket->authContext.selectedAuthMode = WS_AUTH_MODE_BASIC;
Sergunb 0:8918a71cdbe9 566 //Read response body, if any
Sergunb 0:8918a71cdbe9 567 webSocketChangeState(webSocket, WS_STATE_SERVER_RESP_BODY);
Sergunb 0:8918a71cdbe9 568 }
Sergunb 0:8918a71cdbe9 569 }
Sergunb 0:8918a71cdbe9 570 }
Sergunb 0:8918a71cdbe9 571 #endif
Sergunb 0:8918a71cdbe9 572 #if (WEB_SOCKET_DIGEST_AUTH_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 573 //Digest authentication?
Sergunb 0:8918a71cdbe9 574 if(webSocket->authContext.requiredAuthMode == WS_AUTH_MODE_DIGEST)
Sergunb 0:8918a71cdbe9 575 {
Sergunb 0:8918a71cdbe9 576 //Check whether the digest authentication scheme is allowed
Sergunb 0:8918a71cdbe9 577 if(webSocket->authContext.allowedAuthModes & WS_AUTH_MODE_DIGEST)
Sergunb 0:8918a71cdbe9 578 {
Sergunb 0:8918a71cdbe9 579 //Do not try to connect again if the credentials are not valid...
Sergunb 0:8918a71cdbe9 580 if(webSocket->authContext.selectedAuthMode == WS_AUTH_MODE_NONE)
Sergunb 0:8918a71cdbe9 581 {
Sergunb 0:8918a71cdbe9 582 //Force the WebSocket client to use digest authentication
Sergunb 0:8918a71cdbe9 583 webSocket->authContext.selectedAuthMode = WS_AUTH_MODE_DIGEST;
Sergunb 0:8918a71cdbe9 584
Sergunb 0:8918a71cdbe9 585 //Make sure that the RNG callback function has been registered
Sergunb 0:8918a71cdbe9 586 if(webSockRandCallback != NULL)
Sergunb 0:8918a71cdbe9 587 {
Sergunb 0:8918a71cdbe9 588 //Generate a random cnonce
Sergunb 0:8918a71cdbe9 589 error = webSockRandCallback(txContext->buffer,
Sergunb 0:8918a71cdbe9 590 WEB_SOCKET_CNONCE_SIZE);
Sergunb 0:8918a71cdbe9 591 }
Sergunb 0:8918a71cdbe9 592 else
Sergunb 0:8918a71cdbe9 593 {
Sergunb 0:8918a71cdbe9 594 //A cryptographically strong random number generator
Sergunb 0:8918a71cdbe9 595 //must be used to generate the cnonce
Sergunb 0:8918a71cdbe9 596 error = ERROR_PRNG_NOT_READY;
Sergunb 0:8918a71cdbe9 597 }
Sergunb 0:8918a71cdbe9 598
Sergunb 0:8918a71cdbe9 599 //Convert the byte array to hex string
Sergunb 0:8918a71cdbe9 600 webSocketConvertArrayToHexString(txContext->buffer,
Sergunb 0:8918a71cdbe9 601 WEB_SOCKET_CNONCE_SIZE, webSocket->authContext.cnonce);
Sergunb 0:8918a71cdbe9 602
Sergunb 0:8918a71cdbe9 603 //Read response body, if any
Sergunb 0:8918a71cdbe9 604 webSocketChangeState(webSocket, WS_STATE_SERVER_RESP_BODY);
Sergunb 0:8918a71cdbe9 605 }
Sergunb 0:8918a71cdbe9 606 }
Sergunb 0:8918a71cdbe9 607 }
Sergunb 0:8918a71cdbe9 608 #endif
Sergunb 0:8918a71cdbe9 609 }
Sergunb 0:8918a71cdbe9 610
Sergunb 0:8918a71cdbe9 611 //If an error occurred, then the client must fail the WebSocket
Sergunb 0:8918a71cdbe9 612 //connection
Sergunb 0:8918a71cdbe9 613 if(error)
Sergunb 0:8918a71cdbe9 614 {
Sergunb 0:8918a71cdbe9 615 #if (NET_RTOS_SUPPORT == DISABLED)
Sergunb 0:8918a71cdbe9 616 //Timeout error?
Sergunb 0:8918a71cdbe9 617 if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
Sergunb 0:8918a71cdbe9 618 break;
Sergunb 0:8918a71cdbe9 619 #endif
Sergunb 0:8918a71cdbe9 620 //Close connection
Sergunb 0:8918a71cdbe9 621 webSocketCloseConnection(webSocket);
Sergunb 0:8918a71cdbe9 622
Sergunb 0:8918a71cdbe9 623 //Switch to the CLOSED state
Sergunb 0:8918a71cdbe9 624 webSocketChangeState(webSocket, WS_STATE_CLOSED);
Sergunb 0:8918a71cdbe9 625 //Exit immediately
Sergunb 0:8918a71cdbe9 626 break;
Sergunb 0:8918a71cdbe9 627 }
Sergunb 0:8918a71cdbe9 628 }
Sergunb 0:8918a71cdbe9 629
Sergunb 0:8918a71cdbe9 630 //Return status code
Sergunb 0:8918a71cdbe9 631 return error;
Sergunb 0:8918a71cdbe9 632 }
Sergunb 0:8918a71cdbe9 633
Sergunb 0:8918a71cdbe9 634
Sergunb 0:8918a71cdbe9 635 /**
Sergunb 0:8918a71cdbe9 636 * @brief Set client's key
Sergunb 0:8918a71cdbe9 637 * @param[in] webSocket Handle to a WebSocket
Sergunb 0:8918a71cdbe9 638 * @param[in] clientKey NULL-terminated string that holds the the client's key
Sergunb 0:8918a71cdbe9 639 * @return Error code
Sergunb 0:8918a71cdbe9 640 **/
Sergunb 0:8918a71cdbe9 641
Sergunb 0:8918a71cdbe9 642 error_t webSocketSetClientKey(WebSocket *webSocket, const char_t *clientKey)
Sergunb 0:8918a71cdbe9 643 {
Sergunb 0:8918a71cdbe9 644 error_t error;
Sergunb 0:8918a71cdbe9 645 size_t n;
Sergunb 0:8918a71cdbe9 646
Sergunb 0:8918a71cdbe9 647 //Check parameters
Sergunb 0:8918a71cdbe9 648 if(webSocket == NULL || clientKey == NULL)
Sergunb 0:8918a71cdbe9 649 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 650
Sergunb 0:8918a71cdbe9 651 //Get the length of the client's key
Sergunb 0:8918a71cdbe9 652 n = strlen(clientKey);
Sergunb 0:8918a71cdbe9 653
Sergunb 0:8918a71cdbe9 654 //Check the length of the key
Sergunb 0:8918a71cdbe9 655 if(n > WEB_SOCKET_CLIENT_KEY_SIZE)
Sergunb 0:8918a71cdbe9 656 return ERROR_INVALID_LENGTH;
Sergunb 0:8918a71cdbe9 657
Sergunb 0:8918a71cdbe9 658 //Copy client's key
Sergunb 0:8918a71cdbe9 659 strcpy(webSocket->handshakeContext.clientKey, clientKey);
Sergunb 0:8918a71cdbe9 660
Sergunb 0:8918a71cdbe9 661 //a WebSocket server is a WebSocket endpoint that awaits
Sergunb 0:8918a71cdbe9 662 //connections from peers
Sergunb 0:8918a71cdbe9 663 webSocket->endpoint = WS_ENDPOINT_SERVER;
Sergunb 0:8918a71cdbe9 664
Sergunb 0:8918a71cdbe9 665 //Initialize status code
Sergunb 0:8918a71cdbe9 666 webSocket->statusCode = WS_STATUS_CODE_NO_STATUS_RCVD;
Sergunb 0:8918a71cdbe9 667
Sergunb 0:8918a71cdbe9 668 //Initialize handshake parameters
Sergunb 0:8918a71cdbe9 669 webSocket->handshakeContext.version = WS_HTTP_VERSION_1_1;
Sergunb 0:8918a71cdbe9 670 webSocket->handshakeContext.connectionUpgrade = TRUE;
Sergunb 0:8918a71cdbe9 671 webSocket->handshakeContext.upgradeWebSocket = TRUE;
Sergunb 0:8918a71cdbe9 672
Sergunb 0:8918a71cdbe9 673 //Initialize FIN flag
Sergunb 0:8918a71cdbe9 674 webSocket->rxContext.fin = TRUE;
Sergunb 0:8918a71cdbe9 675
Sergunb 0:8918a71cdbe9 676 //Verify client's key
Sergunb 0:8918a71cdbe9 677 error = webSocketVerifyClientKey(webSocket);
Sergunb 0:8918a71cdbe9 678 //Any error to report?
Sergunb 0:8918a71cdbe9 679 if(error)
Sergunb 0:8918a71cdbe9 680 return error;
Sergunb 0:8918a71cdbe9 681
Sergunb 0:8918a71cdbe9 682 //Generate server's key
Sergunb 0:8918a71cdbe9 683 error = webSocketGenerateServerKey(webSocket);
Sergunb 0:8918a71cdbe9 684 //Any error to report?
Sergunb 0:8918a71cdbe9 685 if(error)
Sergunb 0:8918a71cdbe9 686 return error;
Sergunb 0:8918a71cdbe9 687
Sergunb 0:8918a71cdbe9 688 //Format server handshake
Sergunb 0:8918a71cdbe9 689 error = webSocketFormatServerHandshake(webSocket);
Sergunb 0:8918a71cdbe9 690 //Any error to report?
Sergunb 0:8918a71cdbe9 691 if(error)
Sergunb 0:8918a71cdbe9 692 return error;
Sergunb 0:8918a71cdbe9 693
Sergunb 0:8918a71cdbe9 694 //Update FSM state
Sergunb 0:8918a71cdbe9 695 webSocket->state = WS_STATE_SERVER_HANDSHAKE;
Sergunb 0:8918a71cdbe9 696
Sergunb 0:8918a71cdbe9 697 //Successful processing
Sergunb 0:8918a71cdbe9 698 return NO_ERROR;
Sergunb 0:8918a71cdbe9 699 }
Sergunb 0:8918a71cdbe9 700
Sergunb 0:8918a71cdbe9 701
Sergunb 0:8918a71cdbe9 702 /**
Sergunb 0:8918a71cdbe9 703 * @brief Parse client's handshake
Sergunb 0:8918a71cdbe9 704 * @param[in] webSocket Handle that identifies a WebSocket
Sergunb 0:8918a71cdbe9 705 * @return Error code
Sergunb 0:8918a71cdbe9 706 **/
Sergunb 0:8918a71cdbe9 707
Sergunb 0:8918a71cdbe9 708 error_t webSocketParseClientHandshake(WebSocket *webSocket)
Sergunb 0:8918a71cdbe9 709 {
Sergunb 0:8918a71cdbe9 710 error_t error;
Sergunb 0:8918a71cdbe9 711
Sergunb 0:8918a71cdbe9 712 //Make sure the WebSocket handle is valid
Sergunb 0:8918a71cdbe9 713 if(webSocket == NULL)
Sergunb 0:8918a71cdbe9 714 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 715
Sergunb 0:8918a71cdbe9 716 //a WebSocket server is a WebSocket endpoint that awaits
Sergunb 0:8918a71cdbe9 717 //connections from peers
Sergunb 0:8918a71cdbe9 718 webSocket->endpoint = WS_ENDPOINT_SERVER;
Sergunb 0:8918a71cdbe9 719
Sergunb 0:8918a71cdbe9 720 //Initialize status code
Sergunb 0:8918a71cdbe9 721 error = NO_ERROR;
Sergunb 0:8918a71cdbe9 722
Sergunb 0:8918a71cdbe9 723 //Establish connection
Sergunb 0:8918a71cdbe9 724 while(webSocket->state != WS_STATE_SERVER_HANDSHAKE)
Sergunb 0:8918a71cdbe9 725 {
Sergunb 0:8918a71cdbe9 726 //Check current state
Sergunb 0:8918a71cdbe9 727 if(webSocket->state == WS_STATE_INIT)
Sergunb 0:8918a71cdbe9 728 {
Sergunb 0:8918a71cdbe9 729 //Open network connection
Sergunb 0:8918a71cdbe9 730 error = webSocketOpenConnection(webSocket);
Sergunb 0:8918a71cdbe9 731
Sergunb 0:8918a71cdbe9 732 //Check status code
Sergunb 0:8918a71cdbe9 733 if(!error)
Sergunb 0:8918a71cdbe9 734 {
Sergunb 0:8918a71cdbe9 735 //Establish connection
Sergunb 0:8918a71cdbe9 736 webSocketChangeState(webSocket, WS_STATE_CONNECTING);
Sergunb 0:8918a71cdbe9 737 }
Sergunb 0:8918a71cdbe9 738 }
Sergunb 0:8918a71cdbe9 739 else if(webSocket->state == WS_STATE_CONNECTING)
Sergunb 0:8918a71cdbe9 740 {
Sergunb 0:8918a71cdbe9 741 #if (WEB_SOCKET_TLS_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 742 //Use SSL/TLS to secure the connection?
Sergunb 0:8918a71cdbe9 743 if(webSocket->tlsInitCallback != NULL)
Sergunb 0:8918a71cdbe9 744 {
Sergunb 0:8918a71cdbe9 745 //Establish a SSL/TLS connection
Sergunb 0:8918a71cdbe9 746 error = tlsConnect(webSocket->tlsContext);
Sergunb 0:8918a71cdbe9 747 }
Sergunb 0:8918a71cdbe9 748 #endif
Sergunb 0:8918a71cdbe9 749 //Check status code
Sergunb 0:8918a71cdbe9 750 if(!error)
Sergunb 0:8918a71cdbe9 751 {
Sergunb 0:8918a71cdbe9 752 //Parse client handshake
Sergunb 0:8918a71cdbe9 753 webSocketChangeState(webSocket, WS_STATE_CLIENT_HANDSHAKE);
Sergunb 0:8918a71cdbe9 754 }
Sergunb 0:8918a71cdbe9 755 }
Sergunb 0:8918a71cdbe9 756 else if(webSocket->state == WS_STATE_CLIENT_HANDSHAKE)
Sergunb 0:8918a71cdbe9 757 {
Sergunb 0:8918a71cdbe9 758 //Parse the client handshake
Sergunb 0:8918a71cdbe9 759 error = webSocketParseHandshake(webSocket);
Sergunb 0:8918a71cdbe9 760
Sergunb 0:8918a71cdbe9 761 //Check status code
Sergunb 0:8918a71cdbe9 762 if(!error)
Sergunb 0:8918a71cdbe9 763 {
Sergunb 0:8918a71cdbe9 764 //Generate server's key
Sergunb 0:8918a71cdbe9 765 error = webSocketGenerateServerKey(webSocket);
Sergunb 0:8918a71cdbe9 766 }
Sergunb 0:8918a71cdbe9 767
Sergunb 0:8918a71cdbe9 768 //Check status code
Sergunb 0:8918a71cdbe9 769 if(!error)
Sergunb 0:8918a71cdbe9 770 {
Sergunb 0:8918a71cdbe9 771 //Format server handshake
Sergunb 0:8918a71cdbe9 772 error = webSocketFormatServerHandshake(webSocket);
Sergunb 0:8918a71cdbe9 773 }
Sergunb 0:8918a71cdbe9 774 }
Sergunb 0:8918a71cdbe9 775 else
Sergunb 0:8918a71cdbe9 776 {
Sergunb 0:8918a71cdbe9 777 //Invalid state
Sergunb 0:8918a71cdbe9 778 error = ERROR_WRONG_STATE;
Sergunb 0:8918a71cdbe9 779 }
Sergunb 0:8918a71cdbe9 780
Sergunb 0:8918a71cdbe9 781 //Any error to report?
Sergunb 0:8918a71cdbe9 782 if(error)
Sergunb 0:8918a71cdbe9 783 break;
Sergunb 0:8918a71cdbe9 784 }
Sergunb 0:8918a71cdbe9 785
Sergunb 0:8918a71cdbe9 786 //Return status code
Sergunb 0:8918a71cdbe9 787 return error;
Sergunb 0:8918a71cdbe9 788 }
Sergunb 0:8918a71cdbe9 789
Sergunb 0:8918a71cdbe9 790
Sergunb 0:8918a71cdbe9 791 /**
Sergunb 0:8918a71cdbe9 792 * @brief Send server's handshake
Sergunb 0:8918a71cdbe9 793 * @param[in] webSocket Handle that identifies a WebSocket
Sergunb 0:8918a71cdbe9 794 * @return Error code
Sergunb 0:8918a71cdbe9 795 **/
Sergunb 0:8918a71cdbe9 796
Sergunb 0:8918a71cdbe9 797 error_t webSocketSendServerHandshake(WebSocket *webSocket)
Sergunb 0:8918a71cdbe9 798 {
Sergunb 0:8918a71cdbe9 799 error_t error;
Sergunb 0:8918a71cdbe9 800 size_t n;
Sergunb 0:8918a71cdbe9 801 WebSocketFrameContext *txContext;
Sergunb 0:8918a71cdbe9 802
Sergunb 0:8918a71cdbe9 803 //Make sure the WebSocket handle is valid
Sergunb 0:8918a71cdbe9 804 if(webSocket == NULL)
Sergunb 0:8918a71cdbe9 805 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 806
Sergunb 0:8918a71cdbe9 807 //Point to the TX context
Sergunb 0:8918a71cdbe9 808 txContext = &webSocket->txContext;
Sergunb 0:8918a71cdbe9 809
Sergunb 0:8918a71cdbe9 810 //Initialize status code
Sergunb 0:8918a71cdbe9 811 error = NO_ERROR;
Sergunb 0:8918a71cdbe9 812
Sergunb 0:8918a71cdbe9 813 //Establish connection
Sergunb 0:8918a71cdbe9 814 while(webSocket->state != WS_STATE_OPEN)
Sergunb 0:8918a71cdbe9 815 {
Sergunb 0:8918a71cdbe9 816 //Check current state
Sergunb 0:8918a71cdbe9 817 if(webSocket->state == WS_STATE_SERVER_HANDSHAKE)
Sergunb 0:8918a71cdbe9 818 {
Sergunb 0:8918a71cdbe9 819 //Any remaining data to be sent?
Sergunb 0:8918a71cdbe9 820 if(txContext->bufferPos < txContext->bufferLen)
Sergunb 0:8918a71cdbe9 821 {
Sergunb 0:8918a71cdbe9 822 //Send more data
Sergunb 0:8918a71cdbe9 823 error = webSocketSendData(webSocket,
Sergunb 0:8918a71cdbe9 824 txContext->buffer + txContext->bufferPos,
Sergunb 0:8918a71cdbe9 825 txContext->bufferLen - txContext->bufferPos, &n, 0);
Sergunb 0:8918a71cdbe9 826
Sergunb 0:8918a71cdbe9 827 //Advance data pointer
Sergunb 0:8918a71cdbe9 828 txContext->bufferPos += n;
Sergunb 0:8918a71cdbe9 829 }
Sergunb 0:8918a71cdbe9 830 else
Sergunb 0:8918a71cdbe9 831 {
Sergunb 0:8918a71cdbe9 832 //The WebSocket connection is established
Sergunb 0:8918a71cdbe9 833 webSocketChangeState(webSocket, WS_STATE_OPEN);
Sergunb 0:8918a71cdbe9 834 }
Sergunb 0:8918a71cdbe9 835 }
Sergunb 0:8918a71cdbe9 836 else
Sergunb 0:8918a71cdbe9 837 {
Sergunb 0:8918a71cdbe9 838 //Invalid state
Sergunb 0:8918a71cdbe9 839 error = ERROR_WRONG_STATE;
Sergunb 0:8918a71cdbe9 840 }
Sergunb 0:8918a71cdbe9 841
Sergunb 0:8918a71cdbe9 842 //Any error to report?
Sergunb 0:8918a71cdbe9 843 if(error)
Sergunb 0:8918a71cdbe9 844 break;
Sergunb 0:8918a71cdbe9 845 }
Sergunb 0:8918a71cdbe9 846
Sergunb 0:8918a71cdbe9 847 //Return status code
Sergunb 0:8918a71cdbe9 848 return error;
Sergunb 0:8918a71cdbe9 849 }
Sergunb 0:8918a71cdbe9 850
Sergunb 0:8918a71cdbe9 851
Sergunb 0:8918a71cdbe9 852 /**
Sergunb 0:8918a71cdbe9 853 * @brief Send HTTP error response to the client
Sergunb 0:8918a71cdbe9 854 * @param[in] webSocket Handle that identifies a WebSocket
Sergunb 0:8918a71cdbe9 855 * @param[in] statusCode HTTP status code
Sergunb 0:8918a71cdbe9 856 * @param[in] message Text message
Sergunb 0:8918a71cdbe9 857 * @return Error code
Sergunb 0:8918a71cdbe9 858 **/
Sergunb 0:8918a71cdbe9 859
Sergunb 0:8918a71cdbe9 860 error_t webSocketSendErrorResponse(WebSocket *webSocket,
Sergunb 0:8918a71cdbe9 861 uint_t statusCode, const char_t *message)
Sergunb 0:8918a71cdbe9 862 {
Sergunb 0:8918a71cdbe9 863 error_t error;
Sergunb 0:8918a71cdbe9 864 size_t n;
Sergunb 0:8918a71cdbe9 865 WebSocketFrameContext *txContext;
Sergunb 0:8918a71cdbe9 866
Sergunb 0:8918a71cdbe9 867 //Make sure the WebSocket handle is valid
Sergunb 0:8918a71cdbe9 868 if(webSocket == NULL)
Sergunb 0:8918a71cdbe9 869 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 870
Sergunb 0:8918a71cdbe9 871 //Point to the TX context
Sergunb 0:8918a71cdbe9 872 txContext = &webSocket->txContext;
Sergunb 0:8918a71cdbe9 873
Sergunb 0:8918a71cdbe9 874 //Initialize status code
Sergunb 0:8918a71cdbe9 875 error = NO_ERROR;
Sergunb 0:8918a71cdbe9 876
Sergunb 0:8918a71cdbe9 877 //Send HTTP error message
Sergunb 0:8918a71cdbe9 878 while(1)
Sergunb 0:8918a71cdbe9 879 {
Sergunb 0:8918a71cdbe9 880 //Check current state
Sergunb 0:8918a71cdbe9 881 if(txContext->state == WS_SUB_STATE_INIT)
Sergunb 0:8918a71cdbe9 882 {
Sergunb 0:8918a71cdbe9 883 //Format HTTP error response
Sergunb 0:8918a71cdbe9 884 error = webSocketFormatErrorResponse(webSocket, statusCode, message);
Sergunb 0:8918a71cdbe9 885
Sergunb 0:8918a71cdbe9 886 //Send the response
Sergunb 0:8918a71cdbe9 887 txContext->state = WS_SUB_STATE_FRAME_PAYLOAD;
Sergunb 0:8918a71cdbe9 888 }
Sergunb 0:8918a71cdbe9 889 else if(txContext->state == WS_SUB_STATE_FRAME_PAYLOAD)
Sergunb 0:8918a71cdbe9 890 {
Sergunb 0:8918a71cdbe9 891 //Any remaining data to be sent?
Sergunb 0:8918a71cdbe9 892 if(txContext->bufferPos < txContext->bufferLen)
Sergunb 0:8918a71cdbe9 893 {
Sergunb 0:8918a71cdbe9 894 //Send more data
Sergunb 0:8918a71cdbe9 895 error = webSocketSendData(webSocket,
Sergunb 0:8918a71cdbe9 896 txContext->buffer + txContext->bufferPos,
Sergunb 0:8918a71cdbe9 897 txContext->bufferLen - txContext->bufferPos, &n, 0);
Sergunb 0:8918a71cdbe9 898
Sergunb 0:8918a71cdbe9 899 //Advance data pointer
Sergunb 0:8918a71cdbe9 900 txContext->bufferPos += n;
Sergunb 0:8918a71cdbe9 901 }
Sergunb 0:8918a71cdbe9 902 else
Sergunb 0:8918a71cdbe9 903 {
Sergunb 0:8918a71cdbe9 904 //We are done
Sergunb 0:8918a71cdbe9 905 webSocketChangeState(webSocket, WS_STATE_SHUTDOWN);
Sergunb 0:8918a71cdbe9 906 break;
Sergunb 0:8918a71cdbe9 907 }
Sergunb 0:8918a71cdbe9 908 }
Sergunb 0:8918a71cdbe9 909 else
Sergunb 0:8918a71cdbe9 910 {
Sergunb 0:8918a71cdbe9 911 //Invalid state
Sergunb 0:8918a71cdbe9 912 error = ERROR_WRONG_STATE;
Sergunb 0:8918a71cdbe9 913 }
Sergunb 0:8918a71cdbe9 914
Sergunb 0:8918a71cdbe9 915 //Any error to report?
Sergunb 0:8918a71cdbe9 916 if(error)
Sergunb 0:8918a71cdbe9 917 break;
Sergunb 0:8918a71cdbe9 918 }
Sergunb 0:8918a71cdbe9 919
Sergunb 0:8918a71cdbe9 920 //Return status code
Sergunb 0:8918a71cdbe9 921 return error;
Sergunb 0:8918a71cdbe9 922 }
Sergunb 0:8918a71cdbe9 923
Sergunb 0:8918a71cdbe9 924
Sergunb 0:8918a71cdbe9 925 /**
Sergunb 0:8918a71cdbe9 926 * @brief Transmit data over the WebSocket connection
Sergunb 0:8918a71cdbe9 927 * @param[in] webSocket Handle that identifies a WebSocket
Sergunb 0:8918a71cdbe9 928 * @param[in] data Pointer to a buffer containing the data to be transmitted
Sergunb 0:8918a71cdbe9 929 * @param[in] length Number of data bytes to send
Sergunb 0:8918a71cdbe9 930 * @param[in] type Frame type
Sergunb 0:8918a71cdbe9 931 * @param[out] written Actual number of bytes written (optional parameter)
Sergunb 0:8918a71cdbe9 932 * @return Error code
Sergunb 0:8918a71cdbe9 933 **/
Sergunb 0:8918a71cdbe9 934
Sergunb 0:8918a71cdbe9 935 error_t webSocketSend(WebSocket *webSocket, const void *data,
Sergunb 0:8918a71cdbe9 936 size_t length, WebSocketFrameType type, size_t *written)
Sergunb 0:8918a71cdbe9 937 {
Sergunb 0:8918a71cdbe9 938 //An unfragmented message consists of a single frame with the FIN bit
Sergunb 0:8918a71cdbe9 939 //set and an opcode other than 0
Sergunb 0:8918a71cdbe9 940 return webSocketSendEx(webSocket, data, length,
Sergunb 0:8918a71cdbe9 941 type, written, TRUE, TRUE);
Sergunb 0:8918a71cdbe9 942 }
Sergunb 0:8918a71cdbe9 943
Sergunb 0:8918a71cdbe9 944
Sergunb 0:8918a71cdbe9 945 /**
Sergunb 0:8918a71cdbe9 946 * @brief Transmit data over the WebSocket connection
Sergunb 0:8918a71cdbe9 947 * @param[in] webSocket Handle that identifies a WebSocket
Sergunb 0:8918a71cdbe9 948 * @param[in] data Pointer to a buffer containing the data to be transmitted
Sergunb 0:8918a71cdbe9 949 * @param[in] length Number of data bytes to send
Sergunb 0:8918a71cdbe9 950 * @param[in] type Frame type
Sergunb 0:8918a71cdbe9 951 * @param[out] written Actual number of bytes written (optional parameter)
Sergunb 0:8918a71cdbe9 952 * @param[in] firstFrag First fragment of the message
Sergunb 0:8918a71cdbe9 953 * @param[in] lastFrag Last fragment of the message
Sergunb 0:8918a71cdbe9 954 **/
Sergunb 0:8918a71cdbe9 955
Sergunb 0:8918a71cdbe9 956 error_t webSocketSendEx(WebSocket *webSocket, const void *data, size_t length,
Sergunb 0:8918a71cdbe9 957 WebSocketFrameType type, size_t *written, bool_t firstFrag, bool_t lastFrag)
Sergunb 0:8918a71cdbe9 958 {
Sergunb 0:8918a71cdbe9 959 error_t error;
Sergunb 0:8918a71cdbe9 960 size_t i;
Sergunb 0:8918a71cdbe9 961 size_t j;
Sergunb 0:8918a71cdbe9 962 size_t k;
Sergunb 0:8918a71cdbe9 963 size_t n;
Sergunb 0:8918a71cdbe9 964 const uint8_t *p;
Sergunb 0:8918a71cdbe9 965 WebSocketFrameContext *txContext;
Sergunb 0:8918a71cdbe9 966
Sergunb 0:8918a71cdbe9 967 //Check parameters
Sergunb 0:8918a71cdbe9 968 if(webSocket == NULL || data == NULL)
Sergunb 0:8918a71cdbe9 969 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 970
Sergunb 0:8918a71cdbe9 971 //A data frame may be transmitted by either the client or the server at
Sergunb 0:8918a71cdbe9 972 //any time after opening handshake completion and before that endpoint
Sergunb 0:8918a71cdbe9 973 //has sent a Close frame
Sergunb 0:8918a71cdbe9 974 if(webSocket->state != WS_STATE_OPEN)
Sergunb 0:8918a71cdbe9 975 return ERROR_NOT_CONNECTED;
Sergunb 0:8918a71cdbe9 976
Sergunb 0:8918a71cdbe9 977 //Point to the TX context
Sergunb 0:8918a71cdbe9 978 txContext = &webSocket->txContext;
Sergunb 0:8918a71cdbe9 979
Sergunb 0:8918a71cdbe9 980 //Initialize status code
Sergunb 0:8918a71cdbe9 981 error = NO_ERROR;
Sergunb 0:8918a71cdbe9 982
Sergunb 0:8918a71cdbe9 983 //Point to the application data to be written
Sergunb 0:8918a71cdbe9 984 p = (const uint8_t *) data;
Sergunb 0:8918a71cdbe9 985 //No data has been transmitted yet
Sergunb 0:8918a71cdbe9 986 i = 0;
Sergunb 0:8918a71cdbe9 987
Sergunb 0:8918a71cdbe9 988 //Send as much data as possible
Sergunb 0:8918a71cdbe9 989 while(1)
Sergunb 0:8918a71cdbe9 990 {
Sergunb 0:8918a71cdbe9 991 //Check current sub-state
Sergunb 0:8918a71cdbe9 992 if(txContext->state == WS_SUB_STATE_INIT)
Sergunb 0:8918a71cdbe9 993 {
Sergunb 0:8918a71cdbe9 994 //A fragmented message consists of a single frame with the FIN bit
Sergunb 0:8918a71cdbe9 995 //clear and an opcode other than 0, followed by zero or more frames
Sergunb 0:8918a71cdbe9 996 //with the FIN bit clear and the opcode set to 0, and terminated by
Sergunb 0:8918a71cdbe9 997 //a single frame with the FIN bit set and an opcode of 0
Sergunb 0:8918a71cdbe9 998 if(!firstFrag)
Sergunb 0:8918a71cdbe9 999 type = WS_FRAME_TYPE_CONTINUATION;
Sergunb 0:8918a71cdbe9 1000
Sergunb 0:8918a71cdbe9 1001 //Format WebSocket frame header
Sergunb 0:8918a71cdbe9 1002 error = webSocketFormatFrameHeader(webSocket, lastFrag, type, length - i);
Sergunb 0:8918a71cdbe9 1003
Sergunb 0:8918a71cdbe9 1004 //Send the frame header
Sergunb 0:8918a71cdbe9 1005 txContext->state = WS_SUB_STATE_FRAME_HEADER;
Sergunb 0:8918a71cdbe9 1006 }
Sergunb 0:8918a71cdbe9 1007 else if(txContext->state == WS_SUB_STATE_FRAME_HEADER)
Sergunb 0:8918a71cdbe9 1008 {
Sergunb 0:8918a71cdbe9 1009 //Any remaining data to be sent?
Sergunb 0:8918a71cdbe9 1010 if(txContext->bufferPos < txContext->bufferLen)
Sergunb 0:8918a71cdbe9 1011 {
Sergunb 0:8918a71cdbe9 1012 //Send more data
Sergunb 0:8918a71cdbe9 1013 error = webSocketSendData(webSocket,
Sergunb 0:8918a71cdbe9 1014 txContext->buffer + txContext->bufferPos,
Sergunb 0:8918a71cdbe9 1015 txContext->bufferLen - txContext->bufferPos, &n, 0);
Sergunb 0:8918a71cdbe9 1016
Sergunb 0:8918a71cdbe9 1017 //Advance data pointer
Sergunb 0:8918a71cdbe9 1018 txContext->bufferPos += n;
Sergunb 0:8918a71cdbe9 1019 }
Sergunb 0:8918a71cdbe9 1020 else
Sergunb 0:8918a71cdbe9 1021 {
Sergunb 0:8918a71cdbe9 1022 //Flush the transmit buffer
Sergunb 0:8918a71cdbe9 1023 txContext->payloadPos = 0;
Sergunb 0:8918a71cdbe9 1024 txContext->bufferPos = 0;
Sergunb 0:8918a71cdbe9 1025 txContext->bufferLen = 0;
Sergunb 0:8918a71cdbe9 1026
Sergunb 0:8918a71cdbe9 1027 //Send the payload of the WebSocket frame
Sergunb 0:8918a71cdbe9 1028 txContext->state = WS_SUB_STATE_FRAME_PAYLOAD;
Sergunb 0:8918a71cdbe9 1029 }
Sergunb 0:8918a71cdbe9 1030 }
Sergunb 0:8918a71cdbe9 1031 else if(txContext->state == WS_SUB_STATE_FRAME_PAYLOAD)
Sergunb 0:8918a71cdbe9 1032 {
Sergunb 0:8918a71cdbe9 1033 //Any remaining data to be sent?
Sergunb 0:8918a71cdbe9 1034 if(txContext->bufferPos < txContext->bufferLen)
Sergunb 0:8918a71cdbe9 1035 {
Sergunb 0:8918a71cdbe9 1036 //Send more data
Sergunb 0:8918a71cdbe9 1037 error = webSocketSendData(webSocket,
Sergunb 0:8918a71cdbe9 1038 txContext->buffer + txContext->bufferPos,
Sergunb 0:8918a71cdbe9 1039 txContext->bufferLen - txContext->bufferPos, &n, 0);
Sergunb 0:8918a71cdbe9 1040
Sergunb 0:8918a71cdbe9 1041 //Advance data pointer
Sergunb 0:8918a71cdbe9 1042 txContext->payloadPos += n;
Sergunb 0:8918a71cdbe9 1043 txContext->bufferPos += n;
Sergunb 0:8918a71cdbe9 1044
Sergunb 0:8918a71cdbe9 1045 //Total number of data that have been written
Sergunb 0:8918a71cdbe9 1046 i += n;
Sergunb 0:8918a71cdbe9 1047 }
Sergunb 0:8918a71cdbe9 1048 else
Sergunb 0:8918a71cdbe9 1049 {
Sergunb 0:8918a71cdbe9 1050 //Send as much data as possible
Sergunb 0:8918a71cdbe9 1051 if(txContext->payloadPos < txContext->payloadLen)
Sergunb 0:8918a71cdbe9 1052 {
Sergunb 0:8918a71cdbe9 1053 //Calculate the number of bytes that are pending
Sergunb 0:8918a71cdbe9 1054 n = MIN(length - i, txContext->payloadLen - txContext->payloadPos);
Sergunb 0:8918a71cdbe9 1055 //Limit the number of bytes to be copied at a time
Sergunb 0:8918a71cdbe9 1056 n = MIN(n, WEB_SOCKET_BUFFER_SIZE);
Sergunb 0:8918a71cdbe9 1057
Sergunb 0:8918a71cdbe9 1058 //Copy application data to the transmit buffer
Sergunb 0:8918a71cdbe9 1059 memcpy(txContext->buffer, p, n);
Sergunb 0:8918a71cdbe9 1060
Sergunb 0:8918a71cdbe9 1061 //All frames sent from the client to the server are masked
Sergunb 0:8918a71cdbe9 1062 if(webSocket->endpoint == WS_ENDPOINT_CLIENT)
Sergunb 0:8918a71cdbe9 1063 {
Sergunb 0:8918a71cdbe9 1064 //Apply masking
Sergunb 0:8918a71cdbe9 1065 for(j = 0; j < n; j++)
Sergunb 0:8918a71cdbe9 1066 {
Sergunb 0:8918a71cdbe9 1067 //Index of the masking key to be applied
Sergunb 0:8918a71cdbe9 1068 k = (txContext->payloadPos + j) % 4;
Sergunb 0:8918a71cdbe9 1069 //Convert unmasked data into masked data
Sergunb 0:8918a71cdbe9 1070 txContext->buffer[j] = p[i + j] ^ txContext->maskingKey[k];
Sergunb 0:8918a71cdbe9 1071 }
Sergunb 0:8918a71cdbe9 1072 }
Sergunb 0:8918a71cdbe9 1073
Sergunb 0:8918a71cdbe9 1074 //Rewind to the beginning of the buffer
Sergunb 0:8918a71cdbe9 1075 txContext->bufferPos = 0;
Sergunb 0:8918a71cdbe9 1076 //Update the number of data buffered but not yet sent
Sergunb 0:8918a71cdbe9 1077 txContext->bufferLen = n;
Sergunb 0:8918a71cdbe9 1078 }
Sergunb 0:8918a71cdbe9 1079 else
Sergunb 0:8918a71cdbe9 1080 {
Sergunb 0:8918a71cdbe9 1081 //Prepare to send a new WebSocket frame
Sergunb 0:8918a71cdbe9 1082 txContext->state = WS_SUB_STATE_INIT;
Sergunb 0:8918a71cdbe9 1083
Sergunb 0:8918a71cdbe9 1084 //Write operation complete?
Sergunb 0:8918a71cdbe9 1085 if(i >= length)
Sergunb 0:8918a71cdbe9 1086 break;
Sergunb 0:8918a71cdbe9 1087 }
Sergunb 0:8918a71cdbe9 1088 }
Sergunb 0:8918a71cdbe9 1089 }
Sergunb 0:8918a71cdbe9 1090 else
Sergunb 0:8918a71cdbe9 1091 {
Sergunb 0:8918a71cdbe9 1092 //Invalid state
Sergunb 0:8918a71cdbe9 1093 error = ERROR_WRONG_STATE;
Sergunb 0:8918a71cdbe9 1094 }
Sergunb 0:8918a71cdbe9 1095
Sergunb 0:8918a71cdbe9 1096 //Any error to report?
Sergunb 0:8918a71cdbe9 1097 if(error)
Sergunb 0:8918a71cdbe9 1098 break;
Sergunb 0:8918a71cdbe9 1099 }
Sergunb 0:8918a71cdbe9 1100
Sergunb 0:8918a71cdbe9 1101 //Total number of data that have been written
Sergunb 0:8918a71cdbe9 1102 if(written != NULL)
Sergunb 0:8918a71cdbe9 1103 *written = i;
Sergunb 0:8918a71cdbe9 1104
Sergunb 0:8918a71cdbe9 1105 //Return status code
Sergunb 0:8918a71cdbe9 1106 return error;
Sergunb 0:8918a71cdbe9 1107 }
Sergunb 0:8918a71cdbe9 1108
Sergunb 0:8918a71cdbe9 1109
Sergunb 0:8918a71cdbe9 1110 /**
Sergunb 0:8918a71cdbe9 1111 * @brief Receive data from a WebSocket connection
Sergunb 0:8918a71cdbe9 1112 * @param[in] webSocket Handle that identifies a WebSocket
Sergunb 0:8918a71cdbe9 1113 * @param[out] data Buffer where to store the incoming data
Sergunb 0:8918a71cdbe9 1114 * @param[in] size Maximum number of bytes that can be received
Sergunb 0:8918a71cdbe9 1115 * @param[out] type Frame type
Sergunb 0:8918a71cdbe9 1116 * @param[out] received Number of bytes that have been received
Sergunb 0:8918a71cdbe9 1117 * @return Error code
Sergunb 0:8918a71cdbe9 1118 **/
Sergunb 0:8918a71cdbe9 1119
Sergunb 0:8918a71cdbe9 1120 error_t webSocketReceive(WebSocket *webSocket, void *data,
Sergunb 0:8918a71cdbe9 1121 size_t size, WebSocketFrameType *type, size_t *received)
Sergunb 0:8918a71cdbe9 1122 {
Sergunb 0:8918a71cdbe9 1123 bool_t firstFrag;
Sergunb 0:8918a71cdbe9 1124 bool_t lastFrag;
Sergunb 0:8918a71cdbe9 1125
Sergunb 0:8918a71cdbe9 1126 return webSocketReceiveEx(webSocket, data, size,
Sergunb 0:8918a71cdbe9 1127 type, received, &firstFrag, &lastFrag);
Sergunb 0:8918a71cdbe9 1128 }
Sergunb 0:8918a71cdbe9 1129
Sergunb 0:8918a71cdbe9 1130
Sergunb 0:8918a71cdbe9 1131 /**
Sergunb 0:8918a71cdbe9 1132 * @brief Receive data from a WebSocket connection
Sergunb 0:8918a71cdbe9 1133 * @param[in] webSocket Handle that identifies a WebSocket
Sergunb 0:8918a71cdbe9 1134 * @param[out] data Buffer where to store the incoming data
Sergunb 0:8918a71cdbe9 1135 * @param[in] size Maximum number of bytes that can be received
Sergunb 0:8918a71cdbe9 1136 * @param[out] type Frame type
Sergunb 0:8918a71cdbe9 1137 * @param[out] received Number of bytes that have been received
Sergunb 0:8918a71cdbe9 1138 * @param[out] firstFrag First fragment of the message
Sergunb 0:8918a71cdbe9 1139 * @param[out] lastFrag Last fragment of the message
Sergunb 0:8918a71cdbe9 1140 * @return Error code
Sergunb 0:8918a71cdbe9 1141 **/
Sergunb 0:8918a71cdbe9 1142
Sergunb 0:8918a71cdbe9 1143 error_t webSocketReceiveEx(WebSocket *webSocket, void *data, size_t size,
Sergunb 0:8918a71cdbe9 1144 WebSocketFrameType *type, size_t *received, bool_t *firstFrag, bool_t *lastFrag)
Sergunb 0:8918a71cdbe9 1145 {
Sergunb 0:8918a71cdbe9 1146 error_t error;
Sergunb 0:8918a71cdbe9 1147 size_t i;
Sergunb 0:8918a71cdbe9 1148 size_t j;
Sergunb 0:8918a71cdbe9 1149 size_t k;
Sergunb 0:8918a71cdbe9 1150 size_t n;
Sergunb 0:8918a71cdbe9 1151 WebSocketFrame *frame;
Sergunb 0:8918a71cdbe9 1152 WebSocketFrameContext *rxContext;
Sergunb 0:8918a71cdbe9 1153
Sergunb 0:8918a71cdbe9 1154 //Make sure the WebSocket handle is valid
Sergunb 0:8918a71cdbe9 1155 if(webSocket == NULL)
Sergunb 0:8918a71cdbe9 1156 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 1157
Sergunb 0:8918a71cdbe9 1158 //Check the state of the WebSocket connection
Sergunb 0:8918a71cdbe9 1159 if(webSocket->state != WS_STATE_OPEN &&
Sergunb 0:8918a71cdbe9 1160 webSocket->state != WS_STATE_CLOSING_RX)
Sergunb 0:8918a71cdbe9 1161 return ERROR_NOT_CONNECTED;
Sergunb 0:8918a71cdbe9 1162
Sergunb 0:8918a71cdbe9 1163 //Point to the RX context
Sergunb 0:8918a71cdbe9 1164 rxContext = &webSocket->rxContext;
Sergunb 0:8918a71cdbe9 1165 //Point to the WebSocket frame header
Sergunb 0:8918a71cdbe9 1166 frame = (WebSocketFrame *) rxContext->buffer;
Sergunb 0:8918a71cdbe9 1167
Sergunb 0:8918a71cdbe9 1168 //Initialize status code
Sergunb 0:8918a71cdbe9 1169 error = NO_ERROR;
Sergunb 0:8918a71cdbe9 1170
Sergunb 0:8918a71cdbe9 1171 //Initialize flags
Sergunb 0:8918a71cdbe9 1172 if(type != NULL)
Sergunb 0:8918a71cdbe9 1173 *type = WS_FRAME_TYPE_CONTINUATION;
Sergunb 0:8918a71cdbe9 1174 if(firstFrag != NULL)
Sergunb 0:8918a71cdbe9 1175 *firstFrag = FALSE;
Sergunb 0:8918a71cdbe9 1176 if(lastFrag != NULL)
Sergunb 0:8918a71cdbe9 1177 *lastFrag = FALSE;
Sergunb 0:8918a71cdbe9 1178
Sergunb 0:8918a71cdbe9 1179 //No data has been read yet
Sergunb 0:8918a71cdbe9 1180 i = 0;
Sergunb 0:8918a71cdbe9 1181
Sergunb 0:8918a71cdbe9 1182 //Read as much data as possible
Sergunb 0:8918a71cdbe9 1183 while(i < size)
Sergunb 0:8918a71cdbe9 1184 {
Sergunb 0:8918a71cdbe9 1185 //Check current sub-state
Sergunb 0:8918a71cdbe9 1186 if(rxContext->state == WS_SUB_STATE_INIT)
Sergunb 0:8918a71cdbe9 1187 {
Sergunb 0:8918a71cdbe9 1188 //Flush the receive buffer
Sergunb 0:8918a71cdbe9 1189 rxContext->bufferPos = 0;
Sergunb 0:8918a71cdbe9 1190 rxContext->bufferLen = sizeof(WebSocketFrame);
Sergunb 0:8918a71cdbe9 1191
Sergunb 0:8918a71cdbe9 1192 //Decode the frame header
Sergunb 0:8918a71cdbe9 1193 rxContext->state = WS_SUB_STATE_FRAME_HEADER;
Sergunb 0:8918a71cdbe9 1194 }
Sergunb 0:8918a71cdbe9 1195 else if(rxContext->state == WS_SUB_STATE_FRAME_HEADER)
Sergunb 0:8918a71cdbe9 1196 {
Sergunb 0:8918a71cdbe9 1197 //Incomplete frame header?
Sergunb 0:8918a71cdbe9 1198 if(rxContext->bufferPos < rxContext->bufferLen)
Sergunb 0:8918a71cdbe9 1199 {
Sergunb 0:8918a71cdbe9 1200 //Read more data
Sergunb 0:8918a71cdbe9 1201 error = webSocketReceiveData(webSocket,
Sergunb 0:8918a71cdbe9 1202 rxContext->buffer + rxContext->bufferPos,
Sergunb 0:8918a71cdbe9 1203 rxContext->bufferLen - rxContext->bufferPos, &n, 0);
Sergunb 0:8918a71cdbe9 1204
Sergunb 0:8918a71cdbe9 1205 //Advance data pointer
Sergunb 0:8918a71cdbe9 1206 rxContext->bufferPos += n;
Sergunb 0:8918a71cdbe9 1207 }
Sergunb 0:8918a71cdbe9 1208 else
Sergunb 0:8918a71cdbe9 1209 {
Sergunb 0:8918a71cdbe9 1210 //Check the Payload Length field
Sergunb 0:8918a71cdbe9 1211 if(frame->payloadLen == 126)
Sergunb 0:8918a71cdbe9 1212 rxContext->bufferLen += sizeof(uint16_t);
Sergunb 0:8918a71cdbe9 1213 else if(frame->payloadLen == 127)
Sergunb 0:8918a71cdbe9 1214 rxContext->bufferLen += sizeof(uint64_t);
Sergunb 0:8918a71cdbe9 1215
Sergunb 0:8918a71cdbe9 1216 //Check whether the masking key is present
Sergunb 0:8918a71cdbe9 1217 if(frame->mask)
Sergunb 0:8918a71cdbe9 1218 rxContext->bufferLen += sizeof(uint32_t);
Sergunb 0:8918a71cdbe9 1219
Sergunb 0:8918a71cdbe9 1220 //The Opcode field defines the interpretation of the payload data
Sergunb 0:8918a71cdbe9 1221 if(frame->opcode == WS_FRAME_TYPE_CLOSE)
Sergunb 0:8918a71cdbe9 1222 {
Sergunb 0:8918a71cdbe9 1223 //All control frames must have a payload length of 125 bytes or less
Sergunb 0:8918a71cdbe9 1224 if(frame->payloadLen <= 125)
Sergunb 0:8918a71cdbe9 1225 {
Sergunb 0:8918a71cdbe9 1226 //Retrieve the length of the WebSocket frame
Sergunb 0:8918a71cdbe9 1227 rxContext->bufferLen += frame->payloadLen;
Sergunb 0:8918a71cdbe9 1228 }
Sergunb 0:8918a71cdbe9 1229 else
Sergunb 0:8918a71cdbe9 1230 {
Sergunb 0:8918a71cdbe9 1231 //Report a protocol error
Sergunb 0:8918a71cdbe9 1232 webSocket->statusCode = WS_STATUS_CODE_PROTOCOL_ERROR;
Sergunb 0:8918a71cdbe9 1233 //Terminate the WebSocket connection
Sergunb 0:8918a71cdbe9 1234 error = ERROR_INVALID_FRAME;
Sergunb 0:8918a71cdbe9 1235 }
Sergunb 0:8918a71cdbe9 1236 }
Sergunb 0:8918a71cdbe9 1237
Sergunb 0:8918a71cdbe9 1238 //Decode the extended payload length and the masking key, if any
Sergunb 0:8918a71cdbe9 1239 rxContext->state = WS_SUB_STATE_FRAME_EXT_HEADER;
Sergunb 0:8918a71cdbe9 1240 }
Sergunb 0:8918a71cdbe9 1241 }
Sergunb 0:8918a71cdbe9 1242 else if(rxContext->state == WS_SUB_STATE_FRAME_EXT_HEADER)
Sergunb 0:8918a71cdbe9 1243 {
Sergunb 0:8918a71cdbe9 1244 //Incomplete frame header?
Sergunb 0:8918a71cdbe9 1245 if(rxContext->bufferPos < rxContext->bufferLen)
Sergunb 0:8918a71cdbe9 1246 {
Sergunb 0:8918a71cdbe9 1247 //Read more data
Sergunb 0:8918a71cdbe9 1248 error = webSocketReceiveData(webSocket,
Sergunb 0:8918a71cdbe9 1249 rxContext->buffer + rxContext->bufferPos,
Sergunb 0:8918a71cdbe9 1250 rxContext->bufferLen - rxContext->bufferPos, &n, 0);
Sergunb 0:8918a71cdbe9 1251
Sergunb 0:8918a71cdbe9 1252 //Advance data pointer
Sergunb 0:8918a71cdbe9 1253 rxContext->bufferPos += n;
Sergunb 0:8918a71cdbe9 1254 }
Sergunb 0:8918a71cdbe9 1255 else
Sergunb 0:8918a71cdbe9 1256 {
Sergunb 0:8918a71cdbe9 1257 //Parse the header of the WebSocket frame
Sergunb 0:8918a71cdbe9 1258 error = webSocketParseFrameHeader(webSocket, frame, type);
Sergunb 0:8918a71cdbe9 1259
Sergunb 0:8918a71cdbe9 1260 //Check status code
Sergunb 0:8918a71cdbe9 1261 if(error == ERROR_UNEXPECTED_MESSAGE)
Sergunb 0:8918a71cdbe9 1262 {
Sergunb 0:8918a71cdbe9 1263 error = NO_ERROR;
Sergunb 0:8918a71cdbe9 1264 break;
Sergunb 0:8918a71cdbe9 1265 }
Sergunb 0:8918a71cdbe9 1266 else if(error == NO_ERROR)
Sergunb 0:8918a71cdbe9 1267 {
Sergunb 0:8918a71cdbe9 1268 if(firstFrag != NULL)
Sergunb 0:8918a71cdbe9 1269 *firstFrag = TRUE;
Sergunb 0:8918a71cdbe9 1270 }
Sergunb 0:8918a71cdbe9 1271
Sergunb 0:8918a71cdbe9 1272 //Flush the receive buffer
Sergunb 0:8918a71cdbe9 1273 rxContext->payloadPos = 0;
Sergunb 0:8918a71cdbe9 1274 rxContext->bufferPos = 0;
Sergunb 0:8918a71cdbe9 1275 rxContext->bufferLen = 0;
Sergunb 0:8918a71cdbe9 1276
Sergunb 0:8918a71cdbe9 1277 //Decode the payload of the WebSocket frame
Sergunb 0:8918a71cdbe9 1278 rxContext->state = WS_SUB_STATE_FRAME_PAYLOAD;
Sergunb 0:8918a71cdbe9 1279 }
Sergunb 0:8918a71cdbe9 1280 }
Sergunb 0:8918a71cdbe9 1281 else if(rxContext->state == WS_SUB_STATE_FRAME_PAYLOAD)
Sergunb 0:8918a71cdbe9 1282 {
Sergunb 0:8918a71cdbe9 1283 if(rxContext->payloadPos < rxContext->payloadLen)
Sergunb 0:8918a71cdbe9 1284 {
Sergunb 0:8918a71cdbe9 1285 //Limit the number of bytes to read at a time
Sergunb 0:8918a71cdbe9 1286 n = MIN(size - i, rxContext->payloadLen - rxContext->payloadPos);
Sergunb 0:8918a71cdbe9 1287 //Limit the number of bytes to be copied at a time
Sergunb 0:8918a71cdbe9 1288 n = MIN(n, WEB_SOCKET_BUFFER_SIZE);
Sergunb 0:8918a71cdbe9 1289
Sergunb 0:8918a71cdbe9 1290 //Read more data
Sergunb 0:8918a71cdbe9 1291 error = webSocketReceiveData(webSocket, rxContext->buffer, n, &n, 0);
Sergunb 0:8918a71cdbe9 1292
Sergunb 0:8918a71cdbe9 1293 //All frames sent from the client to the server are masked
Sergunb 0:8918a71cdbe9 1294 if(rxContext->mask)
Sergunb 0:8918a71cdbe9 1295 {
Sergunb 0:8918a71cdbe9 1296 //Unmask the data
Sergunb 0:8918a71cdbe9 1297 for(j = 0; j < n; j++)
Sergunb 0:8918a71cdbe9 1298 {
Sergunb 0:8918a71cdbe9 1299 //Index of the masking key to be applied
Sergunb 0:8918a71cdbe9 1300 k = (rxContext->payloadPos + j) % 4;
Sergunb 0:8918a71cdbe9 1301 //Convert masked data into unmasked data
Sergunb 0:8918a71cdbe9 1302 rxContext->buffer[j] ^= rxContext->maskingKey[k];
Sergunb 0:8918a71cdbe9 1303 }
Sergunb 0:8918a71cdbe9 1304 }
Sergunb 0:8918a71cdbe9 1305
Sergunb 0:8918a71cdbe9 1306 //Text frame?
Sergunb 0:8918a71cdbe9 1307 if(rxContext->dataFrameType == WS_FRAME_TYPE_TEXT &&
Sergunb 0:8918a71cdbe9 1308 rxContext->controlFrameType == WS_FRAME_TYPE_CONTINUATION)
Sergunb 0:8918a71cdbe9 1309 {
Sergunb 0:8918a71cdbe9 1310 //Compute the number of remaining data bytes in the UTF-8 stream
Sergunb 0:8918a71cdbe9 1311 if(rxContext->fin)
Sergunb 0:8918a71cdbe9 1312 k = rxContext->payloadLen - rxContext->payloadPos;
Sergunb 0:8918a71cdbe9 1313 else
Sergunb 0:8918a71cdbe9 1314 k = 0;
Sergunb 0:8918a71cdbe9 1315
Sergunb 0:8918a71cdbe9 1316 //Invalid UTF-8 sequence?
Sergunb 0:8918a71cdbe9 1317 if(!webSocketCheckUtf8Stream(&webSocket->utf8Context,
Sergunb 0:8918a71cdbe9 1318 rxContext->buffer, n, k))
Sergunb 0:8918a71cdbe9 1319 {
Sergunb 0:8918a71cdbe9 1320 //The received data is not consistent with the type of the message
Sergunb 0:8918a71cdbe9 1321 webSocket->statusCode = WS_STATUS_CODE_INVALID_PAYLOAD_DATA;
Sergunb 0:8918a71cdbe9 1322 //The endpoint must fail the WebSocket connection
Sergunb 0:8918a71cdbe9 1323 error = ERROR_INVALID_FRAME;
Sergunb 0:8918a71cdbe9 1324 }
Sergunb 0:8918a71cdbe9 1325 }
Sergunb 0:8918a71cdbe9 1326
Sergunb 0:8918a71cdbe9 1327 //Sanity check
Sergunb 0:8918a71cdbe9 1328 if(data != NULL)
Sergunb 0:8918a71cdbe9 1329 {
Sergunb 0:8918a71cdbe9 1330 //Copy application data
Sergunb 0:8918a71cdbe9 1331 memcpy((uint8_t *) data + i, rxContext->buffer, n);
Sergunb 0:8918a71cdbe9 1332 }
Sergunb 0:8918a71cdbe9 1333
Sergunb 0:8918a71cdbe9 1334 //Advance data pointer
Sergunb 0:8918a71cdbe9 1335 rxContext->payloadPos += n;
Sergunb 0:8918a71cdbe9 1336
Sergunb 0:8918a71cdbe9 1337 //Total number of data that have been read
Sergunb 0:8918a71cdbe9 1338 i += n;
Sergunb 0:8918a71cdbe9 1339 }
Sergunb 0:8918a71cdbe9 1340
Sergunb 0:8918a71cdbe9 1341 if(rxContext->payloadPos == rxContext->payloadLen)
Sergunb 0:8918a71cdbe9 1342 {
Sergunb 0:8918a71cdbe9 1343 //Decode the next WebSocket frame
Sergunb 0:8918a71cdbe9 1344 rxContext->state = WS_SUB_STATE_INIT;
Sergunb 0:8918a71cdbe9 1345
Sergunb 0:8918a71cdbe9 1346 //Last fragment of the message?
Sergunb 0:8918a71cdbe9 1347 if(rxContext->fin || rxContext->controlFrameType != WS_FRAME_TYPE_CONTINUATION)
Sergunb 0:8918a71cdbe9 1348 {
Sergunb 0:8918a71cdbe9 1349 if(lastFrag != NULL)
Sergunb 0:8918a71cdbe9 1350 *lastFrag = TRUE;
Sergunb 0:8918a71cdbe9 1351
Sergunb 0:8918a71cdbe9 1352 //Exit immediately
Sergunb 0:8918a71cdbe9 1353 break;
Sergunb 0:8918a71cdbe9 1354 }
Sergunb 0:8918a71cdbe9 1355 }
Sergunb 0:8918a71cdbe9 1356 }
Sergunb 0:8918a71cdbe9 1357 else
Sergunb 0:8918a71cdbe9 1358 {
Sergunb 0:8918a71cdbe9 1359 //Invalid state
Sergunb 0:8918a71cdbe9 1360 error = ERROR_WRONG_STATE;
Sergunb 0:8918a71cdbe9 1361 }
Sergunb 0:8918a71cdbe9 1362
Sergunb 0:8918a71cdbe9 1363 //Any error to report?
Sergunb 0:8918a71cdbe9 1364 if(error)
Sergunb 0:8918a71cdbe9 1365 break;
Sergunb 0:8918a71cdbe9 1366 }
Sergunb 0:8918a71cdbe9 1367
Sergunb 0:8918a71cdbe9 1368 //Check status code
Sergunb 0:8918a71cdbe9 1369 if(!error)
Sergunb 0:8918a71cdbe9 1370 {
Sergunb 0:8918a71cdbe9 1371 //Return the frame type
Sergunb 0:8918a71cdbe9 1372 if(type != NULL)
Sergunb 0:8918a71cdbe9 1373 {
Sergunb 0:8918a71cdbe9 1374 //Control or data frame?
Sergunb 0:8918a71cdbe9 1375 if(rxContext->controlFrameType != WS_FRAME_TYPE_CONTINUATION)
Sergunb 0:8918a71cdbe9 1376 *type = rxContext->controlFrameType;
Sergunb 0:8918a71cdbe9 1377 else
Sergunb 0:8918a71cdbe9 1378 *type = rxContext->dataFrameType;
Sergunb 0:8918a71cdbe9 1379 }
Sergunb 0:8918a71cdbe9 1380 }
Sergunb 0:8918a71cdbe9 1381
Sergunb 0:8918a71cdbe9 1382 //Return the total number of data that have been read
Sergunb 0:8918a71cdbe9 1383 if(received != NULL)
Sergunb 0:8918a71cdbe9 1384 *received = i;
Sergunb 0:8918a71cdbe9 1385
Sergunb 0:8918a71cdbe9 1386 //Return status code
Sergunb 0:8918a71cdbe9 1387 return error;
Sergunb 0:8918a71cdbe9 1388 }
Sergunb 0:8918a71cdbe9 1389
Sergunb 0:8918a71cdbe9 1390
Sergunb 0:8918a71cdbe9 1391 /**
Sergunb 0:8918a71cdbe9 1392 * @brief Check whether some data is available in the receive buffer
Sergunb 0:8918a71cdbe9 1393 * @param[in] webSocket Handle to a WebSocket
Sergunb 0:8918a71cdbe9 1394 * @return The function returns TRUE if some data is pending and can be read
Sergunb 0:8918a71cdbe9 1395 * immediately without blocking. Otherwise, FALSE is returned
Sergunb 0:8918a71cdbe9 1396 **/
Sergunb 0:8918a71cdbe9 1397
Sergunb 0:8918a71cdbe9 1398 bool_t webSocketIsRxReady(WebSocket *webSocket)
Sergunb 0:8918a71cdbe9 1399 {
Sergunb 0:8918a71cdbe9 1400 bool_t available = FALSE;
Sergunb 0:8918a71cdbe9 1401
Sergunb 0:8918a71cdbe9 1402 #if (WEB_SOCKET_TLS_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 1403 //Check whether a secure connection is being used
Sergunb 0:8918a71cdbe9 1404 if(webSocket->tlsContext != NULL)
Sergunb 0:8918a71cdbe9 1405 {
Sergunb 0:8918a71cdbe9 1406 //Check whether some data is pending in the receive buffer
Sergunb 0:8918a71cdbe9 1407 if(webSocket->tlsContext->rxBufferLen > 0)
Sergunb 0:8918a71cdbe9 1408 available = TRUE;
Sergunb 0:8918a71cdbe9 1409 }
Sergunb 0:8918a71cdbe9 1410 #endif
Sergunb 0:8918a71cdbe9 1411
Sergunb 0:8918a71cdbe9 1412 //The function returns TRUE if some data can be read immediately
Sergunb 0:8918a71cdbe9 1413 //without blocking
Sergunb 0:8918a71cdbe9 1414 return available;
Sergunb 0:8918a71cdbe9 1415 }
Sergunb 0:8918a71cdbe9 1416
Sergunb 0:8918a71cdbe9 1417
Sergunb 0:8918a71cdbe9 1418 /**
Sergunb 0:8918a71cdbe9 1419 * @brief Gracefully close a WebSocket connection
Sergunb 0:8918a71cdbe9 1420 * @param[in] webSocket Handle to a WebSocket
Sergunb 0:8918a71cdbe9 1421 **/
Sergunb 0:8918a71cdbe9 1422
Sergunb 0:8918a71cdbe9 1423 error_t webSocketShutdown(WebSocket *webSocket)
Sergunb 0:8918a71cdbe9 1424 {
Sergunb 0:8918a71cdbe9 1425 error_t error;
Sergunb 0:8918a71cdbe9 1426 size_t n;
Sergunb 0:8918a71cdbe9 1427 WebSocketFrameContext *txContext;
Sergunb 0:8918a71cdbe9 1428
Sergunb 0:8918a71cdbe9 1429 //Make sure the WebSocket handle is valid
Sergunb 0:8918a71cdbe9 1430 if(webSocket == NULL)
Sergunb 0:8918a71cdbe9 1431 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 1432
Sergunb 0:8918a71cdbe9 1433 //Point to the TX context
Sergunb 0:8918a71cdbe9 1434 txContext = &webSocket->txContext;
Sergunb 0:8918a71cdbe9 1435
Sergunb 0:8918a71cdbe9 1436 //Initialize status code
Sergunb 0:8918a71cdbe9 1437 error = NO_ERROR;
Sergunb 0:8918a71cdbe9 1438
Sergunb 0:8918a71cdbe9 1439 //Closing handshake
Sergunb 0:8918a71cdbe9 1440 while(webSocket->state != WS_STATE_CLOSED)
Sergunb 0:8918a71cdbe9 1441 {
Sergunb 0:8918a71cdbe9 1442 //Check current state
Sergunb 0:8918a71cdbe9 1443 if(webSocket->state == WS_STATE_OPEN)
Sergunb 0:8918a71cdbe9 1444 {
Sergunb 0:8918a71cdbe9 1445 //Check whether the latest frame has been completely transmitted
Sergunb 0:8918a71cdbe9 1446 if(txContext->payloadPos == txContext->payloadLen)
Sergunb 0:8918a71cdbe9 1447 {
Sergunb 0:8918a71cdbe9 1448 //Format Close frame
Sergunb 0:8918a71cdbe9 1449 error = webSocketFormatCloseFrame(webSocket);
Sergunb 0:8918a71cdbe9 1450 //Send Close frame
Sergunb 0:8918a71cdbe9 1451 webSocket->state = WS_STATE_CLOSING_TX;
Sergunb 0:8918a71cdbe9 1452 }
Sergunb 0:8918a71cdbe9 1453 else
Sergunb 0:8918a71cdbe9 1454 {
Sergunb 0:8918a71cdbe9 1455 //The WebSocket connection cannot be closed until the
Sergunb 0:8918a71cdbe9 1456 //transmission of the frame is complete...
Sergunb 0:8918a71cdbe9 1457 error = ERROR_FAILURE;
Sergunb 0:8918a71cdbe9 1458 }
Sergunb 0:8918a71cdbe9 1459 }
Sergunb 0:8918a71cdbe9 1460 else if(webSocket->state == WS_STATE_CLOSING_TX)
Sergunb 0:8918a71cdbe9 1461 {
Sergunb 0:8918a71cdbe9 1462 //Any remaining data to be sent?
Sergunb 0:8918a71cdbe9 1463 if(txContext->bufferPos < txContext->bufferLen)
Sergunb 0:8918a71cdbe9 1464 {
Sergunb 0:8918a71cdbe9 1465 //Send more data
Sergunb 0:8918a71cdbe9 1466 error = webSocketSendData(webSocket,
Sergunb 0:8918a71cdbe9 1467 txContext->buffer + txContext->bufferPos,
Sergunb 0:8918a71cdbe9 1468 txContext->bufferLen - txContext->bufferPos, &n, 0);
Sergunb 0:8918a71cdbe9 1469
Sergunb 0:8918a71cdbe9 1470 //Advance data pointer
Sergunb 0:8918a71cdbe9 1471 txContext->bufferPos += n;
Sergunb 0:8918a71cdbe9 1472 }
Sergunb 0:8918a71cdbe9 1473 else
Sergunb 0:8918a71cdbe9 1474 {
Sergunb 0:8918a71cdbe9 1475 //Check whether a Close frame has been received from the peer
Sergunb 0:8918a71cdbe9 1476 if(webSocket->handshakeContext.closingFrameReceived)
Sergunb 0:8918a71cdbe9 1477 webSocket->state = WS_STATE_SHUTDOWN;
Sergunb 0:8918a71cdbe9 1478 else
Sergunb 0:8918a71cdbe9 1479 webSocket->state = WS_STATE_CLOSING_RX;
Sergunb 0:8918a71cdbe9 1480 }
Sergunb 0:8918a71cdbe9 1481 }
Sergunb 0:8918a71cdbe9 1482 else if(webSocket->state == WS_STATE_CLOSING_RX)
Sergunb 0:8918a71cdbe9 1483 {
Sergunb 0:8918a71cdbe9 1484 //After receiving a control frame indicating the connection should
Sergunb 0:8918a71cdbe9 1485 //be closed, a peer discards any further data received
Sergunb 0:8918a71cdbe9 1486 error = webSocketReceive(webSocket, NULL, WEB_SOCKET_BUFFER_SIZE, NULL, 0);
Sergunb 0:8918a71cdbe9 1487
Sergunb 0:8918a71cdbe9 1488 //Check status code
Sergunb 0:8918a71cdbe9 1489 if(error == NO_ERROR)
Sergunb 0:8918a71cdbe9 1490 {
Sergunb 0:8918a71cdbe9 1491 //Close frame received?
Sergunb 0:8918a71cdbe9 1492 if(webSocket->handshakeContext.closingFrameReceived)
Sergunb 0:8918a71cdbe9 1493 {
Sergunb 0:8918a71cdbe9 1494 //Properly shutdown the network connection
Sergunb 0:8918a71cdbe9 1495 webSocket->state = WS_STATE_SHUTDOWN;
Sergunb 0:8918a71cdbe9 1496 }
Sergunb 0:8918a71cdbe9 1497 }
Sergunb 0:8918a71cdbe9 1498 else if(error == ERROR_INVALID_FRAME || error == ERROR_END_OF_STREAM)
Sergunb 0:8918a71cdbe9 1499 {
Sergunb 0:8918a71cdbe9 1500 //Catch exception
Sergunb 0:8918a71cdbe9 1501 error = NO_ERROR;
Sergunb 0:8918a71cdbe9 1502 //Properly shutdown the network connection
Sergunb 0:8918a71cdbe9 1503 webSocket->state = WS_STATE_SHUTDOWN;
Sergunb 0:8918a71cdbe9 1504 }
Sergunb 0:8918a71cdbe9 1505 }
Sergunb 0:8918a71cdbe9 1506 else if(webSocket->state == WS_STATE_SHUTDOWN)
Sergunb 0:8918a71cdbe9 1507 {
Sergunb 0:8918a71cdbe9 1508 //Properly dispose the network connection
Sergunb 0:8918a71cdbe9 1509 error = webSocketShutdownConnection(webSocket);
Sergunb 0:8918a71cdbe9 1510
Sergunb 0:8918a71cdbe9 1511 //Check status code
Sergunb 0:8918a71cdbe9 1512 if(!error)
Sergunb 0:8918a71cdbe9 1513 {
Sergunb 0:8918a71cdbe9 1514 //The connection has been properly closed
Sergunb 0:8918a71cdbe9 1515 webSocket->state = WS_STATE_CLOSED;
Sergunb 0:8918a71cdbe9 1516 }
Sergunb 0:8918a71cdbe9 1517 }
Sergunb 0:8918a71cdbe9 1518 else
Sergunb 0:8918a71cdbe9 1519 {
Sergunb 0:8918a71cdbe9 1520 //Invalid state
Sergunb 0:8918a71cdbe9 1521 error = ERROR_WRONG_STATE;
Sergunb 0:8918a71cdbe9 1522 }
Sergunb 0:8918a71cdbe9 1523
Sergunb 0:8918a71cdbe9 1524 //Any error to report?
Sergunb 0:8918a71cdbe9 1525 if(error)
Sergunb 0:8918a71cdbe9 1526 break;
Sergunb 0:8918a71cdbe9 1527 }
Sergunb 0:8918a71cdbe9 1528
Sergunb 0:8918a71cdbe9 1529 //Return status code
Sergunb 0:8918a71cdbe9 1530 return error;
Sergunb 0:8918a71cdbe9 1531 }
Sergunb 0:8918a71cdbe9 1532
Sergunb 0:8918a71cdbe9 1533
Sergunb 0:8918a71cdbe9 1534 /**
Sergunb 0:8918a71cdbe9 1535 * @brief Close a WebSocket connection
Sergunb 0:8918a71cdbe9 1536 * @param[in] webSocket Handle identifying the WebSocket to close
Sergunb 0:8918a71cdbe9 1537 **/
Sergunb 0:8918a71cdbe9 1538
Sergunb 0:8918a71cdbe9 1539 void webSocketClose(WebSocket *webSocket)
Sergunb 0:8918a71cdbe9 1540 {
Sergunb 0:8918a71cdbe9 1541 //Make sure the WebSocket handle is valid
Sergunb 0:8918a71cdbe9 1542 if(webSocket != NULL)
Sergunb 0:8918a71cdbe9 1543 {
Sergunb 0:8918a71cdbe9 1544 //Close connection
Sergunb 0:8918a71cdbe9 1545 webSocketCloseConnection(webSocket);
Sergunb 0:8918a71cdbe9 1546 //Release the WebSocket
Sergunb 0:8918a71cdbe9 1547 webSocketChangeState(webSocket, WS_STATE_UNUSED);
Sergunb 0:8918a71cdbe9 1548 }
Sergunb 0:8918a71cdbe9 1549 }
Sergunb 0:8918a71cdbe9 1550
Sergunb 0:8918a71cdbe9 1551 #endif
Sergunb 0:8918a71cdbe9 1552