Sergey Pastor / 1

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers web_socket.c Source File

web_socket.c

Go to the documentation of this file.
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