Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
web_socket.c
00001 /** 00002 * @file web_socket.c 00003 * @brief WebSocket API (client and server) 00004 * 00005 * @section License 00006 * 00007 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. 00008 * 00009 * This file is part of CycloneTCP Open. 00010 * 00011 * This program is free software; you can redistribute it and/or 00012 * modify it under the terms of the GNU General Public License 00013 * as published by the Free Software Foundation; either version 2 00014 * of the License, or (at your option) any later version. 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU General Public License 00022 * along with this program; if not, write to the Free Software Foundation, 00023 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00024 * 00025 * @author Oryx Embedded SARL (www.oryx-embedded.com) 00026 * @version 1.7.6 00027 **/ 00028 00029 //Switch to the appropriate trace level 00030 #define TRACE_LEVEL WEB_SOCKET_TRACE_LEVEL 00031 00032 //Dependencies 00033 #include <stdlib.h> 00034 #include "core/net.h" 00035 #include "web_socket/web_socket.h" 00036 #include "web_socket/web_socket_auth.h" 00037 #include "web_socket/web_socket_frame.h" 00038 #include "web_socket/web_socket_transport.h" 00039 #include "web_socket/web_socket_misc.h" 00040 #include "str.h" 00041 #include "base64.h" 00042 #include "debug.h" 00043 00044 //Check TCP/IP stack configuration 00045 #if (WEB_SOCKET_SUPPORT == ENABLED) 00046 00047 //WebSocket table 00048 WebSocket webSocketTable[WEB_SOCKET_MAX_COUNT]; 00049 //Random data generation callback function 00050 WebSocketRandCallback webSockRandCallback; 00051 00052 00053 /** 00054 * @brief WebSocket related initialization 00055 * @return Error code 00056 **/ 00057 00058 error_t webSocketInit(void) 00059 { 00060 //Initialize WebSockets 00061 memset(webSocketTable, 0, sizeof(webSocketTable)); 00062 00063 //Successful initialization 00064 return NO_ERROR; 00065 } 00066 00067 00068 /** 00069 * @brief Register RNG callback function 00070 * @param[in] callback RNG callback function 00071 * @return Error code 00072 **/ 00073 00074 error_t webSocketRegisterRandCallback(WebSocketRandCallback callback) 00075 { 00076 //Check parameter 00077 if(callback == NULL) 00078 return ERROR_INVALID_PARAMETER; 00079 00080 //Save callback function 00081 webSockRandCallback = callback; 00082 00083 //Successful processing 00084 return NO_ERROR; 00085 } 00086 00087 00088 /** 00089 * @brief Create a WebSocket 00090 * @return Handle referencing the new WebSocket 00091 **/ 00092 00093 WebSocket *webSocketOpen(void) 00094 { 00095 uint_t i; 00096 WebSocket *webSocket; 00097 00098 //Initialize WebSocket handle 00099 webSocket = NULL; 00100 00101 //Get exclusive access 00102 osAcquireMutex(&netMutex); 00103 00104 //Loop through WebSocket descriptors 00105 for(i = 0; i < WEB_SOCKET_MAX_COUNT; i++) 00106 { 00107 //Unused WebSocket found? 00108 if(webSocketTable[i].state == WS_STATE_UNUSED) 00109 { 00110 //Save socket handle 00111 webSocket = &webSocketTable[i]; 00112 00113 //Clear associated structure 00114 memset(webSocket, 0, sizeof(WebSocket)); 00115 //Set the default timeout to be used 00116 webSocket->timeout = INFINITE_DELAY; 00117 //Enter the CLOSED state 00118 webSocket->state = WS_STATE_CLOSED; 00119 00120 //We are done 00121 break; 00122 } 00123 } 00124 00125 //Release exclusive access 00126 osReleaseMutex(&netMutex); 00127 00128 //Return a handle to the freshly created WebSocket 00129 return webSocket; 00130 } 00131 00132 00133 /** 00134 * @brief Upgrade a socket to a WebSocket 00135 * @param[in] socket Handle referencing the socket 00136 * @return Handle referencing the new WebSocket 00137 **/ 00138 00139 WebSocket *webSocketUpgradeSocket(Socket *socket) 00140 { 00141 WebSocket *webSocket; 00142 00143 //Valid socket handle? 00144 if(socket != NULL) 00145 { 00146 //Create a new WebSocket 00147 webSocket = webSocketOpen(); 00148 00149 //WebSocket successfully created? 00150 if(webSocket != NULL) 00151 { 00152 //Attach the socket handle 00153 webSocket->socket = socket; 00154 //Initialize state 00155 webSocket->state = WS_STATE_INIT; 00156 } 00157 } 00158 else 00159 { 00160 //The specified socket is not valid... 00161 webSocket = NULL; 00162 } 00163 00164 //Return a handle to the freshly created WebSocket 00165 return webSocket; 00166 } 00167 00168 00169 #if (WEB_SOCKET_TLS_SUPPORT == ENABLED) 00170 00171 /** 00172 * @brief Upgrade a secure socket to a secure WebSocket 00173 * @param[in] socket Handle referencing the socket 00174 * @param[in] tlsContext Pointer to the SSL/TLS context 00175 * @return Handle referencing the new WebSocket 00176 **/ 00177 00178 WebSocket *webSocketUpgradeSecureSocket(Socket *socket, TlsContext *tlsContext) 00179 { 00180 WebSocket *webSocket; 00181 00182 //Valid SSL/TLS context? 00183 if(tlsContext != NULL) 00184 { 00185 //Create a new WebSocket 00186 webSocket = webSocketOpen(); 00187 00188 //WebSocket successfully created? 00189 if(webSocket != NULL) 00190 { 00191 //Attach the socket handle 00192 webSocket->socket = socket; 00193 //Attach the SSL/TLS context 00194 webSocket->tlsContext = tlsContext; 00195 //Initialize state 00196 webSocket->state = WS_STATE_INIT; 00197 } 00198 } 00199 else 00200 { 00201 //The specified socket is not valid... 00202 webSocket = NULL; 00203 } 00204 00205 //Return a handle to the freshly created WebSocket 00206 return webSocket; 00207 } 00208 00209 00210 /** 00211 * @brief Register TLS initialization callback function 00212 * @param[in] webSocket Handle that identifies a WebSocket 00213 * @param[in] callback TLS initialization callback function 00214 * @return Error code 00215 **/ 00216 00217 error_t webSocketRegisterTlsInitCallback(WebSocket *webSocket, 00218 WebSocketTlsInitCallback callback) 00219 { 00220 //Check parameters 00221 if(webSocket == NULL || callback == NULL) 00222 return ERROR_INVALID_PARAMETER; 00223 00224 //Save callback function 00225 webSocket->tlsInitCallback = callback; 00226 00227 //Successful processing 00228 return NO_ERROR; 00229 } 00230 00231 #endif 00232 00233 00234 /** 00235 * @brief Set timeout value for blocking operations 00236 * @param[in] webSocket Handle to a WebSocket 00237 * @param[in] timeout Maximum time to wait 00238 * @return Error code 00239 **/ 00240 00241 error_t webSocketSetTimeout(WebSocket *webSocket, systime_t timeout) 00242 { 00243 //Make sure the WebSocket handle is valid 00244 if(webSocket == NULL) 00245 return ERROR_INVALID_PARAMETER; 00246 00247 //Save timeout value 00248 webSocket->timeout = timeout; 00249 00250 //Valid socket? 00251 if(webSocket->socket != NULL) 00252 socketSetTimeout(webSocket->socket, timeout); 00253 00254 //Successful processing 00255 return NO_ERROR; 00256 } 00257 00258 00259 /** 00260 * @brief Set the hostname of the resource being requested 00261 * @param[in] webSocket Handle to a WebSocket 00262 * @param[in] host NULL-terminated string containing the hostname 00263 * @return Error code 00264 **/ 00265 00266 error_t webSocketSetHost(WebSocket *webSocket, const char_t *host) 00267 { 00268 //Check parameters 00269 if(webSocket == NULL || host == NULL) 00270 return ERROR_INVALID_PARAMETER; 00271 00272 //Save the hostname 00273 strSafeCopy(webSocket->host, host, WEB_SOCKET_HOST_MAX_LEN); 00274 00275 //Successful processing 00276 return NO_ERROR; 00277 } 00278 00279 00280 /** 00281 * @brief Set the origin header field 00282 * @param[in] webSocket Handle to a WebSocket 00283 * @param[in] origin NULL-terminated string containing the origin 00284 * @return Error code 00285 **/ 00286 00287 error_t webSocketSetOrigin(WebSocket *webSocket, const char_t *origin) 00288 { 00289 //Check parameters 00290 if(webSocket == NULL || origin == NULL) 00291 return ERROR_INVALID_PARAMETER; 00292 00293 //Save origin 00294 strSafeCopy(webSocket->origin, origin, WEB_SOCKET_ORIGIN_MAX_LEN); 00295 00296 //Successful processing 00297 return NO_ERROR; 00298 } 00299 00300 00301 /** 00302 * @brief Set the sub-protocol header field 00303 * @param[in] webSocket Handle to a WebSocket 00304 * @param[in] subProtocol NULL-terminated string containing the sub-protocol 00305 * @return Error code 00306 **/ 00307 00308 error_t webSocketSetSubProtocol(WebSocket *webSocket, const char_t *subProtocol) 00309 { 00310 //Check parameters 00311 if(webSocket == NULL || subProtocol == NULL) 00312 return ERROR_INVALID_PARAMETER; 00313 00314 //Save sub-protocol 00315 strSafeCopy(webSocket->subProtocol, subProtocol, WEB_SOCKET_SUB_PROTOCOL_MAX_LEN); 00316 00317 //Successful processing 00318 return NO_ERROR; 00319 } 00320 00321 00322 /** 00323 * @brief Set authentication information 00324 * @param[in] webSocket Handle to a WebSocket 00325 * @param[in] username NULL-terminated string containing the user name to be used 00326 * @param[in] password NULL-terminated string containing the password to be used 00327 * @param[in] allowedAuthModes Logic OR of allowed HTTP authentication modes 00328 * @return Error code 00329 **/ 00330 00331 error_t webSocketSetAuthInfo(WebSocket *webSocket, const char_t *username, 00332 const char_t *password, uint_t allowedAuthModes) 00333 { 00334 #if (WEB_SOCKET_BASIC_AUTH_SUPPORT == ENABLED || WEB_SOCKET_DIGEST_AUTH_SUPPORT == ENABLED) 00335 WebSocketAuthContext *authContext; 00336 00337 //Check parameters 00338 if(webSocket == NULL || username == NULL || password == NULL) 00339 return ERROR_INVALID_PARAMETER; 00340 00341 //Point to the authentication context 00342 authContext = &webSocket->authContext; 00343 00344 //Save user name 00345 strSafeCopy(authContext->username, username, WEB_SOCKET_USERNAME_MAX_LEN); 00346 //Save password 00347 strSafeCopy(authContext->password, password, WEB_SOCKET_PASSWORD_MAX_LEN); 00348 //Save the list of allowed HTTP authentication modes 00349 authContext->allowedAuthModes = allowedAuthModes; 00350 #endif 00351 00352 //Successful processing 00353 return NO_ERROR; 00354 } 00355 00356 00357 /** 00358 * @brief Bind the WebSocket to a particular network interface 00359 * @param[in] webSocket Handle to a WebSocket 00360 * @param[in] interface Network interface to be used 00361 * @return Error code 00362 **/ 00363 00364 error_t webSocketBindToInterface(WebSocket *webSocket, NetInterface *interface) 00365 { 00366 //Make sure the WebSocket handle is valid 00367 if(webSocket == NULL) 00368 return ERROR_INVALID_PARAMETER; 00369 00370 //Explicitly associate the WebSocket with the specified interface 00371 webSocket->interface = interface; 00372 00373 //Successful processing 00374 return NO_ERROR; 00375 } 00376 00377 00378 /** 00379 * @brief Establish a WebSocket connection 00380 * @param[in] webSocket Handle to a WebSocket 00381 * @param[in] serverIpAddr IP address of the WebSocket server to connect to 00382 * @param[in] serverPort TCP port number that will be used to establish the 00383 * connection 00384 * @param[in] uri NULL-terminated string that contains the resource name 00385 * @return Error code 00386 **/ 00387 00388 error_t webSocketConnect(WebSocket *webSocket, const IpAddr *serverIpAddr, 00389 uint16_t serverPort, const char_t *uri) 00390 { 00391 error_t error; 00392 size_t n; 00393 WebSocketFrameContext *txContext; 00394 00395 //Make sure the WebSocket handle is valid 00396 if(webSocket == NULL) 00397 return ERROR_INVALID_PARAMETER; 00398 00399 //Point to the TX context 00400 txContext = &webSocket->txContext; 00401 00402 //Initialize status code 00403 error = NO_ERROR; 00404 00405 //Establish connection 00406 while(webSocket->state != WS_STATE_OPEN) 00407 { 00408 //Check current state 00409 if(webSocket->state == WS_STATE_CLOSED) 00410 { 00411 //Check parameters 00412 if(serverIpAddr == NULL || uri == NULL) 00413 { 00414 //Report an error 00415 error = ERROR_INVALID_PARAMETER; 00416 } 00417 else 00418 { 00419 //A WebSocket client is a WebSocket endpoint that initiates a 00420 //connection to a peer 00421 webSocket->endpoint = WS_ENDPOINT_CLIENT; 00422 00423 //Save the URI 00424 strSafeCopy(webSocket->uri, uri, WEB_SOCKET_URI_MAX_LEN); 00425 //Reset retry counter 00426 webSocket->retryCount = 0; 00427 00428 #if (WEB_SOCKET_BASIC_AUTH_SUPPORT == ENABLED || WEB_SOCKET_DIGEST_AUTH_SUPPORT == ENABLED) 00429 //HTTP authentication is not used for the first connection attempt 00430 webSocket->authContext.requiredAuthMode = WS_AUTH_MODE_NONE; 00431 webSocket->authContext.selectedAuthMode = WS_AUTH_MODE_NONE; 00432 #endif 00433 //Initialize the WebSocket connection 00434 webSocketChangeState(webSocket, WS_STATE_INIT); 00435 } 00436 } 00437 else if(webSocket->state == WS_STATE_INIT) 00438 { 00439 //Increment retry counter 00440 webSocket->retryCount++; 00441 00442 //Limit the number of connection attempts 00443 if(webSocket->retryCount > WEB_SOCKET_MAX_CONN_RETRIES) 00444 { 00445 //Report an error 00446 error = ERROR_OPEN_FAILED; 00447 } 00448 else 00449 { 00450 //Open network connection 00451 error = webSocketOpenConnection(webSocket); 00452 } 00453 00454 //Check status code 00455 if(!error) 00456 { 00457 //Establish connection 00458 webSocketChangeState(webSocket, WS_STATE_CONNECTING); 00459 } 00460 } 00461 else if(webSocket->state == WS_STATE_CONNECTING) 00462 { 00463 //Establish connection 00464 error = webSocketEstablishConnection(webSocket, 00465 serverIpAddr, serverPort); 00466 00467 //Check status code 00468 if(!error) 00469 { 00470 //Generate client's key 00471 error = webSocketGenerateClientKey(webSocket); 00472 } 00473 00474 //Check status code 00475 if(!error) 00476 { 00477 //Format client handshake 00478 error = webSocketFormatClientHandshake(webSocket, serverPort); 00479 } 00480 00481 //Check status code 00482 if(!error) 00483 { 00484 //Send client handshake 00485 webSocketChangeState(webSocket, WS_STATE_CLIENT_HANDSHAKE); 00486 } 00487 } 00488 else if(webSocket->state == WS_STATE_CLIENT_HANDSHAKE) 00489 { 00490 //Any remaining data to be sent? 00491 if(txContext->bufferPos < txContext->bufferLen) 00492 { 00493 //Send more data 00494 error = webSocketSendData(webSocket, 00495 txContext->buffer + txContext->bufferPos, 00496 txContext->bufferLen - txContext->bufferPos, &n, 0); 00497 00498 //Advance data pointer 00499 txContext->bufferPos += n; 00500 } 00501 else 00502 { 00503 //Wait for server handshake 00504 webSocketChangeState(webSocket, WS_STATE_SERVER_HANDSHAKE); 00505 } 00506 } 00507 else if(webSocket->state == WS_STATE_SERVER_HANDSHAKE) 00508 { 00509 //Parse the server handshake 00510 error = webSocketParseHandshake(webSocket); 00511 } 00512 else if(webSocket->state == WS_STATE_SERVER_RESP_BODY) 00513 { 00514 //Check Connection header field 00515 if(webSocket->handshakeContext.connectionClose) 00516 { 00517 //Close connection 00518 webSocketCloseConnection(webSocket); 00519 //Try to connect again 00520 webSocketChangeState(webSocket, WS_STATE_INIT); 00521 } 00522 else 00523 { 00524 //Any remaining data to read in the response body? 00525 if(webSocket->handshakeContext.contentLength > 0) 00526 { 00527 //Limit the number of bytes to read at a time 00528 n = MIN(webSocket->handshakeContext.contentLength, WEB_SOCKET_BUFFER_SIZE); 00529 //Discard any received data 00530 error = webSocketReceiveData(webSocket, txContext->buffer, n, &n, 0); 00531 //Decrement byte counter 00532 webSocket->handshakeContext.contentLength -= n; 00533 } 00534 else 00535 { 00536 //Format client handshake 00537 error = webSocketFormatClientHandshake(webSocket, serverPort); 00538 //Try to authenticate again 00539 webSocketChangeState(webSocket, WS_STATE_CLIENT_HANDSHAKE); 00540 } 00541 } 00542 } 00543 else 00544 { 00545 //Invalid state 00546 error = ERROR_WRONG_STATE; 00547 } 00548 00549 //Check whether authentication is required 00550 if(error == ERROR_AUTH_REQUIRED) 00551 { 00552 #if (WEB_SOCKET_BASIC_AUTH_SUPPORT == ENABLED) 00553 //Basic authentication? 00554 if(webSocket->authContext.requiredAuthMode == WS_AUTH_MODE_BASIC) 00555 { 00556 //Check whether the basic authentication scheme is allowed 00557 if(webSocket->authContext.allowedAuthModes & WS_AUTH_MODE_BASIC) 00558 { 00559 //Do not try to connect again if the credentials are not valid... 00560 if(webSocket->authContext.selectedAuthMode == WS_AUTH_MODE_NONE) 00561 { 00562 //Catch exception 00563 error = NO_ERROR; 00564 //Force the WebSocket client to use basic authentication 00565 webSocket->authContext.selectedAuthMode = WS_AUTH_MODE_BASIC; 00566 //Read response body, if any 00567 webSocketChangeState(webSocket, WS_STATE_SERVER_RESP_BODY); 00568 } 00569 } 00570 } 00571 #endif 00572 #if (WEB_SOCKET_DIGEST_AUTH_SUPPORT == ENABLED) 00573 //Digest authentication? 00574 if(webSocket->authContext.requiredAuthMode == WS_AUTH_MODE_DIGEST) 00575 { 00576 //Check whether the digest authentication scheme is allowed 00577 if(webSocket->authContext.allowedAuthModes & WS_AUTH_MODE_DIGEST) 00578 { 00579 //Do not try to connect again if the credentials are not valid... 00580 if(webSocket->authContext.selectedAuthMode == WS_AUTH_MODE_NONE) 00581 { 00582 //Force the WebSocket client to use digest authentication 00583 webSocket->authContext.selectedAuthMode = WS_AUTH_MODE_DIGEST; 00584 00585 //Make sure that the RNG callback function has been registered 00586 if(webSockRandCallback != NULL) 00587 { 00588 //Generate a random cnonce 00589 error = webSockRandCallback(txContext->buffer, 00590 WEB_SOCKET_CNONCE_SIZE); 00591 } 00592 else 00593 { 00594 //A cryptographically strong random number generator 00595 //must be used to generate the cnonce 00596 error = ERROR_PRNG_NOT_READY; 00597 } 00598 00599 //Convert the byte array to hex string 00600 webSocketConvertArrayToHexString(txContext->buffer, 00601 WEB_SOCKET_CNONCE_SIZE, webSocket->authContext.cnonce); 00602 00603 //Read response body, if any 00604 webSocketChangeState(webSocket, WS_STATE_SERVER_RESP_BODY); 00605 } 00606 } 00607 } 00608 #endif 00609 } 00610 00611 //If an error occurred, then the client must fail the WebSocket 00612 //connection 00613 if(error) 00614 { 00615 #if (NET_RTOS_SUPPORT == DISABLED) 00616 //Timeout error? 00617 if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT) 00618 break; 00619 #endif 00620 //Close connection 00621 webSocketCloseConnection(webSocket); 00622 00623 //Switch to the CLOSED state 00624 webSocketChangeState(webSocket, WS_STATE_CLOSED); 00625 //Exit immediately 00626 break; 00627 } 00628 } 00629 00630 //Return status code 00631 return error; 00632 } 00633 00634 00635 /** 00636 * @brief Set client's key 00637 * @param[in] webSocket Handle to a WebSocket 00638 * @param[in] clientKey NULL-terminated string that holds the the client's key 00639 * @return Error code 00640 **/ 00641 00642 error_t webSocketSetClientKey(WebSocket *webSocket, const char_t *clientKey) 00643 { 00644 error_t error; 00645 size_t n; 00646 00647 //Check parameters 00648 if(webSocket == NULL || clientKey == NULL) 00649 return ERROR_INVALID_PARAMETER; 00650 00651 //Get the length of the client's key 00652 n = strlen(clientKey); 00653 00654 //Check the length of the key 00655 if(n > WEB_SOCKET_CLIENT_KEY_SIZE) 00656 return ERROR_INVALID_LENGTH; 00657 00658 //Copy client's key 00659 strcpy(webSocket->handshakeContext.clientKey, clientKey); 00660 00661 //a WebSocket server is a WebSocket endpoint that awaits 00662 //connections from peers 00663 webSocket->endpoint = WS_ENDPOINT_SERVER; 00664 00665 //Initialize status code 00666 webSocket->statusCode = WS_STATUS_CODE_NO_STATUS_RCVD; 00667 00668 //Initialize handshake parameters 00669 webSocket->handshakeContext.version = WS_HTTP_VERSION_1_1; 00670 webSocket->handshakeContext.connectionUpgrade = TRUE; 00671 webSocket->handshakeContext.upgradeWebSocket = TRUE; 00672 00673 //Initialize FIN flag 00674 webSocket->rxContext.fin = TRUE; 00675 00676 //Verify client's key 00677 error = webSocketVerifyClientKey(webSocket); 00678 //Any error to report? 00679 if(error) 00680 return error; 00681 00682 //Generate server's key 00683 error = webSocketGenerateServerKey(webSocket); 00684 //Any error to report? 00685 if(error) 00686 return error; 00687 00688 //Format server handshake 00689 error = webSocketFormatServerHandshake(webSocket); 00690 //Any error to report? 00691 if(error) 00692 return error; 00693 00694 //Update FSM state 00695 webSocket->state = WS_STATE_SERVER_HANDSHAKE; 00696 00697 //Successful processing 00698 return NO_ERROR; 00699 } 00700 00701 00702 /** 00703 * @brief Parse client's handshake 00704 * @param[in] webSocket Handle that identifies a WebSocket 00705 * @return Error code 00706 **/ 00707 00708 error_t webSocketParseClientHandshake(WebSocket *webSocket) 00709 { 00710 error_t error; 00711 00712 //Make sure the WebSocket handle is valid 00713 if(webSocket == NULL) 00714 return ERROR_INVALID_PARAMETER; 00715 00716 //a WebSocket server is a WebSocket endpoint that awaits 00717 //connections from peers 00718 webSocket->endpoint = WS_ENDPOINT_SERVER; 00719 00720 //Initialize status code 00721 error = NO_ERROR; 00722 00723 //Establish connection 00724 while(webSocket->state != WS_STATE_SERVER_HANDSHAKE) 00725 { 00726 //Check current state 00727 if(webSocket->state == WS_STATE_INIT) 00728 { 00729 //Open network connection 00730 error = webSocketOpenConnection(webSocket); 00731 00732 //Check status code 00733 if(!error) 00734 { 00735 //Establish connection 00736 webSocketChangeState(webSocket, WS_STATE_CONNECTING); 00737 } 00738 } 00739 else if(webSocket->state == WS_STATE_CONNECTING) 00740 { 00741 #if (WEB_SOCKET_TLS_SUPPORT == ENABLED) 00742 //Use SSL/TLS to secure the connection? 00743 if(webSocket->tlsInitCallback != NULL) 00744 { 00745 //Establish a SSL/TLS connection 00746 error = tlsConnect(webSocket->tlsContext); 00747 } 00748 #endif 00749 //Check status code 00750 if(!error) 00751 { 00752 //Parse client handshake 00753 webSocketChangeState(webSocket, WS_STATE_CLIENT_HANDSHAKE); 00754 } 00755 } 00756 else if(webSocket->state == WS_STATE_CLIENT_HANDSHAKE) 00757 { 00758 //Parse the client handshake 00759 error = webSocketParseHandshake(webSocket); 00760 00761 //Check status code 00762 if(!error) 00763 { 00764 //Generate server's key 00765 error = webSocketGenerateServerKey(webSocket); 00766 } 00767 00768 //Check status code 00769 if(!error) 00770 { 00771 //Format server handshake 00772 error = webSocketFormatServerHandshake(webSocket); 00773 } 00774 } 00775 else 00776 { 00777 //Invalid state 00778 error = ERROR_WRONG_STATE; 00779 } 00780 00781 //Any error to report? 00782 if(error) 00783 break; 00784 } 00785 00786 //Return status code 00787 return error; 00788 } 00789 00790 00791 /** 00792 * @brief Send server's handshake 00793 * @param[in] webSocket Handle that identifies a WebSocket 00794 * @return Error code 00795 **/ 00796 00797 error_t webSocketSendServerHandshake(WebSocket *webSocket) 00798 { 00799 error_t error; 00800 size_t n; 00801 WebSocketFrameContext *txContext; 00802 00803 //Make sure the WebSocket handle is valid 00804 if(webSocket == NULL) 00805 return ERROR_INVALID_PARAMETER; 00806 00807 //Point to the TX context 00808 txContext = &webSocket->txContext; 00809 00810 //Initialize status code 00811 error = NO_ERROR; 00812 00813 //Establish connection 00814 while(webSocket->state != WS_STATE_OPEN) 00815 { 00816 //Check current state 00817 if(webSocket->state == WS_STATE_SERVER_HANDSHAKE) 00818 { 00819 //Any remaining data to be sent? 00820 if(txContext->bufferPos < txContext->bufferLen) 00821 { 00822 //Send more data 00823 error = webSocketSendData(webSocket, 00824 txContext->buffer + txContext->bufferPos, 00825 txContext->bufferLen - txContext->bufferPos, &n, 0); 00826 00827 //Advance data pointer 00828 txContext->bufferPos += n; 00829 } 00830 else 00831 { 00832 //The WebSocket connection is established 00833 webSocketChangeState(webSocket, WS_STATE_OPEN); 00834 } 00835 } 00836 else 00837 { 00838 //Invalid state 00839 error = ERROR_WRONG_STATE; 00840 } 00841 00842 //Any error to report? 00843 if(error) 00844 break; 00845 } 00846 00847 //Return status code 00848 return error; 00849 } 00850 00851 00852 /** 00853 * @brief Send HTTP error response to the client 00854 * @param[in] webSocket Handle that identifies a WebSocket 00855 * @param[in] statusCode HTTP status code 00856 * @param[in] message Text message 00857 * @return Error code 00858 **/ 00859 00860 error_t webSocketSendErrorResponse(WebSocket *webSocket, 00861 uint_t statusCode, const char_t *message) 00862 { 00863 error_t error; 00864 size_t n; 00865 WebSocketFrameContext *txContext; 00866 00867 //Make sure the WebSocket handle is valid 00868 if(webSocket == NULL) 00869 return ERROR_INVALID_PARAMETER; 00870 00871 //Point to the TX context 00872 txContext = &webSocket->txContext; 00873 00874 //Initialize status code 00875 error = NO_ERROR; 00876 00877 //Send HTTP error message 00878 while(1) 00879 { 00880 //Check current state 00881 if(txContext->state == WS_SUB_STATE_INIT) 00882 { 00883 //Format HTTP error response 00884 error = webSocketFormatErrorResponse(webSocket, statusCode, message); 00885 00886 //Send the response 00887 txContext->state = WS_SUB_STATE_FRAME_PAYLOAD; 00888 } 00889 else if(txContext->state == WS_SUB_STATE_FRAME_PAYLOAD) 00890 { 00891 //Any remaining data to be sent? 00892 if(txContext->bufferPos < txContext->bufferLen) 00893 { 00894 //Send more data 00895 error = webSocketSendData(webSocket, 00896 txContext->buffer + txContext->bufferPos, 00897 txContext->bufferLen - txContext->bufferPos, &n, 0); 00898 00899 //Advance data pointer 00900 txContext->bufferPos += n; 00901 } 00902 else 00903 { 00904 //We are done 00905 webSocketChangeState(webSocket, WS_STATE_SHUTDOWN); 00906 break; 00907 } 00908 } 00909 else 00910 { 00911 //Invalid state 00912 error = ERROR_WRONG_STATE; 00913 } 00914 00915 //Any error to report? 00916 if(error) 00917 break; 00918 } 00919 00920 //Return status code 00921 return error; 00922 } 00923 00924 00925 /** 00926 * @brief Transmit data over the WebSocket connection 00927 * @param[in] webSocket Handle that identifies a WebSocket 00928 * @param[in] data Pointer to a buffer containing the data to be transmitted 00929 * @param[in] length Number of data bytes to send 00930 * @param[in] type Frame type 00931 * @param[out] written Actual number of bytes written (optional parameter) 00932 * @return Error code 00933 **/ 00934 00935 error_t webSocketSend(WebSocket *webSocket, const void *data, 00936 size_t length, WebSocketFrameType type, size_t *written) 00937 { 00938 //An unfragmented message consists of a single frame with the FIN bit 00939 //set and an opcode other than 0 00940 return webSocketSendEx(webSocket, data, length, 00941 type, written, TRUE, TRUE); 00942 } 00943 00944 00945 /** 00946 * @brief Transmit data over the WebSocket connection 00947 * @param[in] webSocket Handle that identifies a WebSocket 00948 * @param[in] data Pointer to a buffer containing the data to be transmitted 00949 * @param[in] length Number of data bytes to send 00950 * @param[in] type Frame type 00951 * @param[out] written Actual number of bytes written (optional parameter) 00952 * @param[in] firstFrag First fragment of the message 00953 * @param[in] lastFrag Last fragment of the message 00954 **/ 00955 00956 error_t webSocketSendEx(WebSocket *webSocket, const void *data, size_t length, 00957 WebSocketFrameType type, size_t *written, bool_t firstFrag, bool_t lastFrag) 00958 { 00959 error_t error; 00960 size_t i; 00961 size_t j; 00962 size_t k; 00963 size_t n; 00964 const uint8_t *p; 00965 WebSocketFrameContext *txContext; 00966 00967 //Check parameters 00968 if(webSocket == NULL || data == NULL) 00969 return ERROR_INVALID_PARAMETER; 00970 00971 //A data frame may be transmitted by either the client or the server at 00972 //any time after opening handshake completion and before that endpoint 00973 //has sent a Close frame 00974 if(webSocket->state != WS_STATE_OPEN) 00975 return ERROR_NOT_CONNECTED; 00976 00977 //Point to the TX context 00978 txContext = &webSocket->txContext; 00979 00980 //Initialize status code 00981 error = NO_ERROR; 00982 00983 //Point to the application data to be written 00984 p = (const uint8_t *) data; 00985 //No data has been transmitted yet 00986 i = 0; 00987 00988 //Send as much data as possible 00989 while(1) 00990 { 00991 //Check current sub-state 00992 if(txContext->state == WS_SUB_STATE_INIT) 00993 { 00994 //A fragmented message consists of a single frame with the FIN bit 00995 //clear and an opcode other than 0, followed by zero or more frames 00996 //with the FIN bit clear and the opcode set to 0, and terminated by 00997 //a single frame with the FIN bit set and an opcode of 0 00998 if(!firstFrag) 00999 type = WS_FRAME_TYPE_CONTINUATION; 01000 01001 //Format WebSocket frame header 01002 error = webSocketFormatFrameHeader(webSocket, lastFrag, type, length - i); 01003 01004 //Send the frame header 01005 txContext->state = WS_SUB_STATE_FRAME_HEADER; 01006 } 01007 else if(txContext->state == WS_SUB_STATE_FRAME_HEADER) 01008 { 01009 //Any remaining data to be sent? 01010 if(txContext->bufferPos < txContext->bufferLen) 01011 { 01012 //Send more data 01013 error = webSocketSendData(webSocket, 01014 txContext->buffer + txContext->bufferPos, 01015 txContext->bufferLen - txContext->bufferPos, &n, 0); 01016 01017 //Advance data pointer 01018 txContext->bufferPos += n; 01019 } 01020 else 01021 { 01022 //Flush the transmit buffer 01023 txContext->payloadPos = 0; 01024 txContext->bufferPos = 0; 01025 txContext->bufferLen = 0; 01026 01027 //Send the payload of the WebSocket frame 01028 txContext->state = WS_SUB_STATE_FRAME_PAYLOAD; 01029 } 01030 } 01031 else if(txContext->state == WS_SUB_STATE_FRAME_PAYLOAD) 01032 { 01033 //Any remaining data to be sent? 01034 if(txContext->bufferPos < txContext->bufferLen) 01035 { 01036 //Send more data 01037 error = webSocketSendData(webSocket, 01038 txContext->buffer + txContext->bufferPos, 01039 txContext->bufferLen - txContext->bufferPos, &n, 0); 01040 01041 //Advance data pointer 01042 txContext->payloadPos += n; 01043 txContext->bufferPos += n; 01044 01045 //Total number of data that have been written 01046 i += n; 01047 } 01048 else 01049 { 01050 //Send as much data as possible 01051 if(txContext->payloadPos < txContext->payloadLen) 01052 { 01053 //Calculate the number of bytes that are pending 01054 n = MIN(length - i, txContext->payloadLen - txContext->payloadPos); 01055 //Limit the number of bytes to be copied at a time 01056 n = MIN(n, WEB_SOCKET_BUFFER_SIZE); 01057 01058 //Copy application data to the transmit buffer 01059 memcpy(txContext->buffer, p, n); 01060 01061 //All frames sent from the client to the server are masked 01062 if(webSocket->endpoint == WS_ENDPOINT_CLIENT) 01063 { 01064 //Apply masking 01065 for(j = 0; j < n; j++) 01066 { 01067 //Index of the masking key to be applied 01068 k = (txContext->payloadPos + j) % 4; 01069 //Convert unmasked data into masked data 01070 txContext->buffer[j] = p[i + j] ^ txContext->maskingKey[k]; 01071 } 01072 } 01073 01074 //Rewind to the beginning of the buffer 01075 txContext->bufferPos = 0; 01076 //Update the number of data buffered but not yet sent 01077 txContext->bufferLen = n; 01078 } 01079 else 01080 { 01081 //Prepare to send a new WebSocket frame 01082 txContext->state = WS_SUB_STATE_INIT; 01083 01084 //Write operation complete? 01085 if(i >= length) 01086 break; 01087 } 01088 } 01089 } 01090 else 01091 { 01092 //Invalid state 01093 error = ERROR_WRONG_STATE; 01094 } 01095 01096 //Any error to report? 01097 if(error) 01098 break; 01099 } 01100 01101 //Total number of data that have been written 01102 if(written != NULL) 01103 *written = i; 01104 01105 //Return status code 01106 return error; 01107 } 01108 01109 01110 /** 01111 * @brief Receive data from a WebSocket connection 01112 * @param[in] webSocket Handle that identifies a WebSocket 01113 * @param[out] data Buffer where to store the incoming data 01114 * @param[in] size Maximum number of bytes that can be received 01115 * @param[out] type Frame type 01116 * @param[out] received Number of bytes that have been received 01117 * @return Error code 01118 **/ 01119 01120 error_t webSocketReceive(WebSocket *webSocket, void *data, 01121 size_t size, WebSocketFrameType *type, size_t *received) 01122 { 01123 bool_t firstFrag; 01124 bool_t lastFrag; 01125 01126 return webSocketReceiveEx(webSocket, data, size, 01127 type, received, &firstFrag, &lastFrag); 01128 } 01129 01130 01131 /** 01132 * @brief Receive data from a WebSocket connection 01133 * @param[in] webSocket Handle that identifies a WebSocket 01134 * @param[out] data Buffer where to store the incoming data 01135 * @param[in] size Maximum number of bytes that can be received 01136 * @param[out] type Frame type 01137 * @param[out] received Number of bytes that have been received 01138 * @param[out] firstFrag First fragment of the message 01139 * @param[out] lastFrag Last fragment of the message 01140 * @return Error code 01141 **/ 01142 01143 error_t webSocketReceiveEx(WebSocket *webSocket, void *data, size_t size, 01144 WebSocketFrameType *type, size_t *received, bool_t *firstFrag, bool_t *lastFrag) 01145 { 01146 error_t error; 01147 size_t i; 01148 size_t j; 01149 size_t k; 01150 size_t n; 01151 WebSocketFrame *frame; 01152 WebSocketFrameContext *rxContext; 01153 01154 //Make sure the WebSocket handle is valid 01155 if(webSocket == NULL) 01156 return ERROR_INVALID_PARAMETER; 01157 01158 //Check the state of the WebSocket connection 01159 if(webSocket->state != WS_STATE_OPEN && 01160 webSocket->state != WS_STATE_CLOSING_RX) 01161 return ERROR_NOT_CONNECTED; 01162 01163 //Point to the RX context 01164 rxContext = &webSocket->rxContext; 01165 //Point to the WebSocket frame header 01166 frame = (WebSocketFrame *) rxContext->buffer; 01167 01168 //Initialize status code 01169 error = NO_ERROR; 01170 01171 //Initialize flags 01172 if(type != NULL) 01173 *type = WS_FRAME_TYPE_CONTINUATION; 01174 if(firstFrag != NULL) 01175 *firstFrag = FALSE; 01176 if(lastFrag != NULL) 01177 *lastFrag = FALSE; 01178 01179 //No data has been read yet 01180 i = 0; 01181 01182 //Read as much data as possible 01183 while(i < size) 01184 { 01185 //Check current sub-state 01186 if(rxContext->state == WS_SUB_STATE_INIT) 01187 { 01188 //Flush the receive buffer 01189 rxContext->bufferPos = 0; 01190 rxContext->bufferLen = sizeof(WebSocketFrame); 01191 01192 //Decode the frame header 01193 rxContext->state = WS_SUB_STATE_FRAME_HEADER; 01194 } 01195 else if(rxContext->state == WS_SUB_STATE_FRAME_HEADER) 01196 { 01197 //Incomplete frame header? 01198 if(rxContext->bufferPos < rxContext->bufferLen) 01199 { 01200 //Read more data 01201 error = webSocketReceiveData(webSocket, 01202 rxContext->buffer + rxContext->bufferPos, 01203 rxContext->bufferLen - rxContext->bufferPos, &n, 0); 01204 01205 //Advance data pointer 01206 rxContext->bufferPos += n; 01207 } 01208 else 01209 { 01210 //Check the Payload Length field 01211 if(frame->payloadLen == 126) 01212 rxContext->bufferLen += sizeof(uint16_t); 01213 else if(frame->payloadLen == 127) 01214 rxContext->bufferLen += sizeof(uint64_t); 01215 01216 //Check whether the masking key is present 01217 if(frame->mask) 01218 rxContext->bufferLen += sizeof(uint32_t); 01219 01220 //The Opcode field defines the interpretation of the payload data 01221 if(frame->opcode == WS_FRAME_TYPE_CLOSE) 01222 { 01223 //All control frames must have a payload length of 125 bytes or less 01224 if(frame->payloadLen <= 125) 01225 { 01226 //Retrieve the length of the WebSocket frame 01227 rxContext->bufferLen += frame->payloadLen; 01228 } 01229 else 01230 { 01231 //Report a protocol error 01232 webSocket->statusCode = WS_STATUS_CODE_PROTOCOL_ERROR; 01233 //Terminate the WebSocket connection 01234 error = ERROR_INVALID_FRAME; 01235 } 01236 } 01237 01238 //Decode the extended payload length and the masking key, if any 01239 rxContext->state = WS_SUB_STATE_FRAME_EXT_HEADER; 01240 } 01241 } 01242 else if(rxContext->state == WS_SUB_STATE_FRAME_EXT_HEADER) 01243 { 01244 //Incomplete frame header? 01245 if(rxContext->bufferPos < rxContext->bufferLen) 01246 { 01247 //Read more data 01248 error = webSocketReceiveData(webSocket, 01249 rxContext->buffer + rxContext->bufferPos, 01250 rxContext->bufferLen - rxContext->bufferPos, &n, 0); 01251 01252 //Advance data pointer 01253 rxContext->bufferPos += n; 01254 } 01255 else 01256 { 01257 //Parse the header of the WebSocket frame 01258 error = webSocketParseFrameHeader(webSocket, frame, type); 01259 01260 //Check status code 01261 if(error == ERROR_UNEXPECTED_MESSAGE) 01262 { 01263 error = NO_ERROR; 01264 break; 01265 } 01266 else if(error == NO_ERROR) 01267 { 01268 if(firstFrag != NULL) 01269 *firstFrag = TRUE; 01270 } 01271 01272 //Flush the receive buffer 01273 rxContext->payloadPos = 0; 01274 rxContext->bufferPos = 0; 01275 rxContext->bufferLen = 0; 01276 01277 //Decode the payload of the WebSocket frame 01278 rxContext->state = WS_SUB_STATE_FRAME_PAYLOAD; 01279 } 01280 } 01281 else if(rxContext->state == WS_SUB_STATE_FRAME_PAYLOAD) 01282 { 01283 if(rxContext->payloadPos < rxContext->payloadLen) 01284 { 01285 //Limit the number of bytes to read at a time 01286 n = MIN(size - i, rxContext->payloadLen - rxContext->payloadPos); 01287 //Limit the number of bytes to be copied at a time 01288 n = MIN(n, WEB_SOCKET_BUFFER_SIZE); 01289 01290 //Read more data 01291 error = webSocketReceiveData(webSocket, rxContext->buffer, n, &n, 0); 01292 01293 //All frames sent from the client to the server are masked 01294 if(rxContext->mask) 01295 { 01296 //Unmask the data 01297 for(j = 0; j < n; j++) 01298 { 01299 //Index of the masking key to be applied 01300 k = (rxContext->payloadPos + j) % 4; 01301 //Convert masked data into unmasked data 01302 rxContext->buffer[j] ^= rxContext->maskingKey[k]; 01303 } 01304 } 01305 01306 //Text frame? 01307 if(rxContext->dataFrameType == WS_FRAME_TYPE_TEXT && 01308 rxContext->controlFrameType == WS_FRAME_TYPE_CONTINUATION) 01309 { 01310 //Compute the number of remaining data bytes in the UTF-8 stream 01311 if(rxContext->fin) 01312 k = rxContext->payloadLen - rxContext->payloadPos; 01313 else 01314 k = 0; 01315 01316 //Invalid UTF-8 sequence? 01317 if(!webSocketCheckUtf8Stream(&webSocket->utf8Context, 01318 rxContext->buffer, n, k)) 01319 { 01320 //The received data is not consistent with the type of the message 01321 webSocket->statusCode = WS_STATUS_CODE_INVALID_PAYLOAD_DATA; 01322 //The endpoint must fail the WebSocket connection 01323 error = ERROR_INVALID_FRAME; 01324 } 01325 } 01326 01327 //Sanity check 01328 if(data != NULL) 01329 { 01330 //Copy application data 01331 memcpy((uint8_t *) data + i, rxContext->buffer, n); 01332 } 01333 01334 //Advance data pointer 01335 rxContext->payloadPos += n; 01336 01337 //Total number of data that have been read 01338 i += n; 01339 } 01340 01341 if(rxContext->payloadPos == rxContext->payloadLen) 01342 { 01343 //Decode the next WebSocket frame 01344 rxContext->state = WS_SUB_STATE_INIT; 01345 01346 //Last fragment of the message? 01347 if(rxContext->fin || rxContext->controlFrameType != WS_FRAME_TYPE_CONTINUATION) 01348 { 01349 if(lastFrag != NULL) 01350 *lastFrag = TRUE; 01351 01352 //Exit immediately 01353 break; 01354 } 01355 } 01356 } 01357 else 01358 { 01359 //Invalid state 01360 error = ERROR_WRONG_STATE; 01361 } 01362 01363 //Any error to report? 01364 if(error) 01365 break; 01366 } 01367 01368 //Check status code 01369 if(!error) 01370 { 01371 //Return the frame type 01372 if(type != NULL) 01373 { 01374 //Control or data frame? 01375 if(rxContext->controlFrameType != WS_FRAME_TYPE_CONTINUATION) 01376 *type = rxContext->controlFrameType; 01377 else 01378 *type = rxContext->dataFrameType; 01379 } 01380 } 01381 01382 //Return the total number of data that have been read 01383 if(received != NULL) 01384 *received = i; 01385 01386 //Return status code 01387 return error; 01388 } 01389 01390 01391 /** 01392 * @brief Check whether some data is available in the receive buffer 01393 * @param[in] webSocket Handle to a WebSocket 01394 * @return The function returns TRUE if some data is pending and can be read 01395 * immediately without blocking. Otherwise, FALSE is returned 01396 **/ 01397 01398 bool_t webSocketIsRxReady(WebSocket *webSocket) 01399 { 01400 bool_t available = FALSE; 01401 01402 #if (WEB_SOCKET_TLS_SUPPORT == ENABLED) 01403 //Check whether a secure connection is being used 01404 if(webSocket->tlsContext != NULL) 01405 { 01406 //Check whether some data is pending in the receive buffer 01407 if(webSocket->tlsContext->rxBufferLen > 0) 01408 available = TRUE; 01409 } 01410 #endif 01411 01412 //The function returns TRUE if some data can be read immediately 01413 //without blocking 01414 return available; 01415 } 01416 01417 01418 /** 01419 * @brief Gracefully close a WebSocket connection 01420 * @param[in] webSocket Handle to a WebSocket 01421 **/ 01422 01423 error_t webSocketShutdown(WebSocket *webSocket) 01424 { 01425 error_t error; 01426 size_t n; 01427 WebSocketFrameContext *txContext; 01428 01429 //Make sure the WebSocket handle is valid 01430 if(webSocket == NULL) 01431 return ERROR_INVALID_PARAMETER; 01432 01433 //Point to the TX context 01434 txContext = &webSocket->txContext; 01435 01436 //Initialize status code 01437 error = NO_ERROR; 01438 01439 //Closing handshake 01440 while(webSocket->state != WS_STATE_CLOSED) 01441 { 01442 //Check current state 01443 if(webSocket->state == WS_STATE_OPEN) 01444 { 01445 //Check whether the latest frame has been completely transmitted 01446 if(txContext->payloadPos == txContext->payloadLen) 01447 { 01448 //Format Close frame 01449 error = webSocketFormatCloseFrame(webSocket); 01450 //Send Close frame 01451 webSocket->state = WS_STATE_CLOSING_TX; 01452 } 01453 else 01454 { 01455 //The WebSocket connection cannot be closed until the 01456 //transmission of the frame is complete... 01457 error = ERROR_FAILURE; 01458 } 01459 } 01460 else if(webSocket->state == WS_STATE_CLOSING_TX) 01461 { 01462 //Any remaining data to be sent? 01463 if(txContext->bufferPos < txContext->bufferLen) 01464 { 01465 //Send more data 01466 error = webSocketSendData(webSocket, 01467 txContext->buffer + txContext->bufferPos, 01468 txContext->bufferLen - txContext->bufferPos, &n, 0); 01469 01470 //Advance data pointer 01471 txContext->bufferPos += n; 01472 } 01473 else 01474 { 01475 //Check whether a Close frame has been received from the peer 01476 if(webSocket->handshakeContext.closingFrameReceived) 01477 webSocket->state = WS_STATE_SHUTDOWN; 01478 else 01479 webSocket->state = WS_STATE_CLOSING_RX; 01480 } 01481 } 01482 else if(webSocket->state == WS_STATE_CLOSING_RX) 01483 { 01484 //After receiving a control frame indicating the connection should 01485 //be closed, a peer discards any further data received 01486 error = webSocketReceive(webSocket, NULL, WEB_SOCKET_BUFFER_SIZE, NULL, 0); 01487 01488 //Check status code 01489 if(error == NO_ERROR) 01490 { 01491 //Close frame received? 01492 if(webSocket->handshakeContext.closingFrameReceived) 01493 { 01494 //Properly shutdown the network connection 01495 webSocket->state = WS_STATE_SHUTDOWN; 01496 } 01497 } 01498 else if(error == ERROR_INVALID_FRAME || error == ERROR_END_OF_STREAM) 01499 { 01500 //Catch exception 01501 error = NO_ERROR; 01502 //Properly shutdown the network connection 01503 webSocket->state = WS_STATE_SHUTDOWN; 01504 } 01505 } 01506 else if(webSocket->state == WS_STATE_SHUTDOWN) 01507 { 01508 //Properly dispose the network connection 01509 error = webSocketShutdownConnection(webSocket); 01510 01511 //Check status code 01512 if(!error) 01513 { 01514 //The connection has been properly closed 01515 webSocket->state = WS_STATE_CLOSED; 01516 } 01517 } 01518 else 01519 { 01520 //Invalid state 01521 error = ERROR_WRONG_STATE; 01522 } 01523 01524 //Any error to report? 01525 if(error) 01526 break; 01527 } 01528 01529 //Return status code 01530 return error; 01531 } 01532 01533 01534 /** 01535 * @brief Close a WebSocket connection 01536 * @param[in] webSocket Handle identifying the WebSocket to close 01537 **/ 01538 01539 void webSocketClose(WebSocket *webSocket) 01540 { 01541 //Make sure the WebSocket handle is valid 01542 if(webSocket != NULL) 01543 { 01544 //Close connection 01545 webSocketCloseConnection(webSocket); 01546 //Release the WebSocket 01547 webSocketChangeState(webSocket, WS_STATE_UNUSED); 01548 } 01549 } 01550 01551 #endif 01552
Generated on Tue Jul 12 2022 17:10:17 by
