Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers web_socket_frame.c Source File

web_socket_frame.c

Go to the documentation of this file.
00001 /**
00002  * @file web_socket_frame.c
00003  * @brief WebSocket frame parsing and formatting
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 "core/net.h"
00034 #include "web_socket/web_socket.h"
00035 #include "web_socket/web_socket_frame.h"
00036 #include "web_socket/web_socket_transport.h"
00037 #include "web_socket/web_socket_misc.h"
00038 #include "debug.h"
00039 
00040 //Check TCP/IP stack configuration
00041 #if (WEB_SOCKET_SUPPORT == ENABLED)
00042 
00043 
00044 /**
00045  * @brief Format WebSocket frame header
00046  * @param[in] webSocket Handle to a WebSocket
00047  * @param[in] fin FIN flag
00048  * @param[in] type Frame type
00049  * @param[in] payloadLen Length of the payload data
00050  * @return Error code
00051  **/
00052 
00053 error_t webSocketFormatFrameHeader(WebSocket *webSocket,
00054    bool_t fin, WebSocketFrameType type, size_t payloadLen)
00055 {
00056    error_t error;
00057    WebSocketFrameContext *txContext;
00058    WebSocketFrame *frame;
00059 
00060    //Point to the TX context
00061    txContext = &webSocket->txContext;
00062 
00063    //Flush the transmit buffer
00064    txContext->bufferPos = 0;
00065    txContext->bufferLen = 0;
00066 
00067    //The endpoint must encapsulate the data in a WebSocket frame
00068    frame = (WebSocketFrame *) txContext->buffer;
00069 
00070    //The frame needs to be formatted according to the WebSocket framing
00071    //format
00072    frame->fin = fin;
00073    frame->reserved = 0;
00074    frame->opcode = type;
00075 
00076    //All frames sent from the client to the server are masked by a 32-bit
00077    //value that is contained within the frame
00078    if(webSocket->endpoint == WS_ENDPOINT_CLIENT)
00079    {
00080       //All frames sent from client to server have the Mask bit set to 1
00081       frame->mask = TRUE;
00082 
00083       //Make sure that the RNG callback function has been registered
00084       if(webSockRandCallback != NULL)
00085       {
00086          //Generate a random masking key
00087          error = webSockRandCallback(txContext->maskingKey, sizeof(uint32_t));
00088          //Any error to report?
00089          if(error)
00090             return error;
00091       }
00092       else
00093       {
00094          //A cryptographically strong random number generator
00095          //must be used to generate the masking key
00096          return ERROR_PRNG_NOT_READY;
00097       }
00098    }
00099    else
00100    {
00101       //Clear the Mask bit
00102       frame->mask = FALSE;
00103    }
00104 
00105    //Size of the frame header
00106    txContext->bufferLen = sizeof(WebSocketFrame);
00107 
00108    //Compute the number of application data to be transmitted
00109    txContext->payloadLen = payloadLen;
00110 
00111    //Check the length of the payload
00112    if(payloadLen <= 125)
00113    {
00114       //Payload length
00115       frame->payloadLen = payloadLen;
00116    }
00117    else if(payloadLen <= 65535)
00118    {
00119       //If the Payload Length field is set to 126, then the following
00120       //2 bytes are interpreted as a 16-bit unsigned integer
00121       frame->payloadLen = 126;
00122 
00123       //Save the length of the payload data
00124       STORE16BE(payloadLen, frame->extPayloadLen);
00125 
00126       //Adjust the length of the frame header
00127       txContext->bufferLen += sizeof(uint16_t);
00128    }
00129    else
00130    {
00131       //If the Payload Length field is set to 127, then the following
00132       //8 bytes are interpreted as a 64-bit unsigned integer
00133       frame->payloadLen = 127;
00134 
00135       //Save the length of the payload data
00136       STORE64BE(payloadLen, frame->extPayloadLen);
00137 
00138       //Adjust the length of the frame header
00139       txContext->bufferLen += sizeof(uint64_t);
00140    }
00141 
00142    //Debug message
00143    TRACE_DEBUG("WebSocket: Sending frame\r\n");
00144    TRACE_DEBUG("  FIN = %u\r\n", frame->fin);
00145    TRACE_DEBUG("  Reserved = %u\r\n", frame->reserved);
00146    TRACE_DEBUG("  Opcode = %u\r\n", frame->opcode);
00147    TRACE_DEBUG("  Mask = %u\r\n", frame->mask);
00148    TRACE_DEBUG("  Payload Length = %u\r\n", txContext->payloadLen);
00149 
00150    //The Masking Key field is present the mask bit is set to 1
00151    if(frame->mask)
00152    {
00153       //Debug message
00154       TRACE_DEBUG_ARRAY("  Masking Key = ", txContext->maskingKey, sizeof(uint32_t));
00155 
00156       //Copy the masking key
00157       memcpy(txContext->buffer + txContext->bufferLen,
00158          txContext->maskingKey, sizeof(uint32_t));
00159 
00160       //Adjust the length of the frame header
00161       txContext->bufferLen += sizeof(uint32_t);
00162    }
00163 
00164    //Successful processing
00165    return NO_ERROR;
00166 }
00167 
00168 
00169 /**
00170  * @brief Parse WebSocket frame header
00171  * @param[in] webSocket Handle to a WebSocket
00172  * @param[in] frame Pointer to the WebSocket frame header
00173  * @param[out] type Frame type
00174  * @return Error code
00175  **/
00176 
00177 error_t webSocketParseFrameHeader(WebSocket *webSocket,
00178    const WebSocketFrame *frame, WebSocketFrameType *type)
00179 {
00180    size_t j;
00181    size_t k;
00182    size_t n;
00183    uint16_t statusCode;
00184    WebSocketFrameContext *rxContext;
00185 
00186    //Point to the RX context
00187    rxContext = &webSocket->rxContext;
00188 
00189    //Point to the Extended Payload Length
00190    n = sizeof(WebSocketFrame);
00191 
00192    //Check frame type
00193    if(type != NULL)
00194    {
00195       if(*type != WS_FRAME_TYPE_CONTINUATION)
00196       {
00197          if(frame->opcode != WS_FRAME_TYPE_CONTINUATION &&
00198             frame->opcode != *type)
00199          {
00200             return ERROR_UNEXPECTED_MESSAGE;
00201          }
00202       }
00203    }
00204 
00205    //Check the Payload Length field
00206    if(frame->payloadLen == 126)
00207    {
00208       //If the Payload Length field is set to 126, then the following
00209       //2 bytes are interpreted as a 16-bit unsigned integer
00210       rxContext->payloadLen = LOAD16BE(frame->extPayloadLen);
00211 
00212       //Point to the next field
00213       n += sizeof(uint16_t);
00214    }
00215    else if(frame->payloadLen == 127)
00216    {
00217       //If the Payload Length field is set to 127, then the following
00218       //8 bytes are interpreted as a 64-bit unsigned integer
00219       rxContext->payloadLen = LOAD64BE(frame->extPayloadLen);
00220 
00221       //Point to the next field
00222       n += sizeof(uint64_t);
00223    }
00224    else
00225    {
00226       //Retrieve the length of the payload data
00227       rxContext->payloadLen = frame->payloadLen;
00228    }
00229 
00230    //Debug message
00231    TRACE_DEBUG("WebSocket: frame received...\r\n");
00232    TRACE_DEBUG("  FIN = %u\r\n", frame->fin);
00233    TRACE_DEBUG("  Reserved = %u\r\n", frame->reserved);
00234    TRACE_DEBUG("  Opcode = %u\r\n", frame->opcode);
00235    TRACE_DEBUG("  Mask = %u\r\n", frame->mask);
00236    TRACE_DEBUG("  Payload Length = %u\r\n", rxContext->payloadLen);
00237 
00238    //Check whether the payload data is masked
00239    if(frame->mask)
00240    {
00241       //Save the masking key
00242       memcpy(rxContext->maskingKey, (uint8_t *) frame + n, sizeof(uint32_t));
00243       //Debug message
00244       TRACE_DEBUG_ARRAY("  Masking Key = ", rxContext->maskingKey, sizeof(uint32_t));
00245 
00246       //Point to the payload data
00247       n += sizeof(uint32_t);
00248    }
00249 
00250    //Text or Close frame received?
00251    if(frame->opcode == WS_FRAME_TYPE_TEXT ||
00252       frame->opcode == WS_FRAME_TYPE_CLOSE)
00253    {
00254       //Reinitialize UTF-8 decoding context
00255       webSocket->utf8Context.utf8CharSize = 0;
00256       webSocket->utf8Context.utf8CharIndex = 0;
00257       webSocket->utf8Context.utf8CodePoint = 0;
00258    }
00259 
00260    //If the RSV field is a nonzero value and none of the negotiated extensions
00261    //defines the meaning of such a nonzero value, the receiving endpoint must
00262    //fail the WebSocket connection
00263    if(frame->reserved != 0)
00264    {
00265       //Report a protocol error
00266       webSocket->statusCode = WS_STATUS_CODE_PROTOCOL_ERROR;
00267       //Terminate the WebSocket connection
00268       return ERROR_INVALID_FRAME;
00269    }
00270 
00271    //The Opcode field defines the interpretation of the payload data
00272    if(frame->opcode == WS_FRAME_TYPE_CONTINUATION)
00273    {
00274       //A Continuation frame cannot be the first frame of a fragmented message
00275       if(rxContext->fin)
00276          webSocket->statusCode = WS_STATUS_CODE_PROTOCOL_ERROR;
00277 
00278       rxContext->controlFrameType = WS_FRAME_TYPE_CONTINUATION;
00279    }
00280    else if(frame->opcode == WS_FRAME_TYPE_TEXT)
00281    {
00282       //The Opcode must be 0 in subsequent fragmented frames
00283       if(!rxContext->fin)
00284          webSocket->statusCode = WS_STATUS_CODE_PROTOCOL_ERROR;
00285 
00286       //Save the Opcode field
00287       rxContext->dataFrameType = WS_FRAME_TYPE_TEXT;
00288       rxContext->controlFrameType = WS_FRAME_TYPE_CONTINUATION;
00289    }
00290    else if(frame->opcode == WS_FRAME_TYPE_BINARY)
00291    {
00292       //The Opcode must be 0 in subsequent fragmented frames
00293       if(!rxContext->fin)
00294          webSocket->statusCode = WS_STATUS_CODE_PROTOCOL_ERROR;
00295 
00296       //Save the Opcode field
00297       rxContext->dataFrameType = WS_FRAME_TYPE_BINARY;
00298       rxContext->controlFrameType = WS_FRAME_TYPE_CONTINUATION;
00299    }
00300    else if(frame->opcode == WS_FRAME_TYPE_CLOSE)
00301    {
00302       //Check the length of the payload data
00303       if(rxContext->payloadLen == 0)
00304       {
00305          //The Close frame does not contain any body
00306          webSocket->statusCode = WS_STATUS_CODE_NORMAL_CLOSURE;
00307       }
00308       else if(rxContext->payloadLen == 1)
00309       {
00310          //Report a protocol error
00311          webSocket->statusCode = WS_STATUS_CODE_PROTOCOL_ERROR;
00312       }
00313       else
00314       {
00315          //All frames sent from the client to the server are masked
00316          if(frame->mask)
00317          {
00318             //Unmask the data
00319             for(j = 0; j < rxContext->payloadLen; j++)
00320             {
00321                //Index of the masking key to be applied
00322                k = j % 4;
00323                //Convert masked data into unmasked data
00324                *((uint8_t *) frame + n + j) ^= rxContext->maskingKey[k];
00325             }
00326          }
00327 
00328          //If there is a body, the first two bytes of the body must be
00329          //a 2-byte unsigned integer representing a status code
00330          statusCode = LOAD16BE((uint8_t *) frame + n);
00331 
00332          //Debug message
00333          TRACE_DEBUG("  Status Code = %u\r\n", statusCode);
00334 
00335          //When sending a Close frame in response, the endpoint typically
00336          //echos the status code it received
00337          if(webSocketCheckStatusCode(statusCode))
00338             webSocket->statusCode = statusCode;
00339          else
00340             webSocket->statusCode = WS_STATUS_CODE_PROTOCOL_ERROR;
00341 
00342          //The body may contain UTF-8-encoded data
00343          if(rxContext->payloadLen > 2)
00344          {
00345             //Compute the length of the data
00346             k = rxContext->payloadLen - 2;
00347 
00348             //Invalid UTF-8 sequence?
00349             if(!webSocketCheckUtf8Stream(&webSocket->utf8Context,
00350                (uint8_t *) frame + n + 2, k, k))
00351             {
00352                //The received data is not consistent with the type of the message
00353                webSocket->statusCode = WS_STATUS_CODE_INVALID_PAYLOAD_DATA;
00354             }
00355          }
00356       }
00357 
00358       //A Close frame has been received
00359       webSocket->handshakeContext.closingFrameReceived = TRUE;
00360       //Exit immediately
00361       return ERROR_END_OF_STREAM;
00362    }
00363    else if(frame->opcode == WS_FRAME_TYPE_PING)
00364    {
00365       //Save the Opcode field
00366       rxContext->controlFrameType = WS_FRAME_TYPE_PING;
00367 
00368       //Control frames must not be fragmented
00369       if(!frame->fin)
00370          webSocket->statusCode = WS_STATUS_CODE_PROTOCOL_ERROR;
00371 
00372       //All control frames must have a payload length of 125 bytes or less
00373       if(frame->payloadLen > 125)
00374          webSocket->statusCode = WS_STATUS_CODE_PROTOCOL_ERROR;
00375    }
00376    else if(frame->opcode == WS_FRAME_TYPE_PONG)
00377    {
00378       //Save the Opcode field
00379       rxContext->controlFrameType = WS_FRAME_TYPE_PONG;
00380 
00381       //Control frames must not be fragmented
00382       if(!frame->fin)
00383          webSocket->statusCode = WS_STATUS_CODE_PROTOCOL_ERROR;
00384 
00385       //All control frames must have a payload length of 125 bytes or less
00386       if(frame->payloadLen > 125)
00387          webSocket->statusCode = WS_STATUS_CODE_PROTOCOL_ERROR;
00388    }
00389    else
00390    {
00391       //If an unknown opcode is received, the receiving endpoint must fail
00392       //the WebSocket connection
00393       webSocket->statusCode = WS_STATUS_CODE_PROTOCOL_ERROR;
00394    }
00395 
00396    //Save the Mask flag
00397    rxContext->mask = frame->mask;
00398 
00399    //Control frame?
00400    if(rxContext->controlFrameType != WS_FRAME_TYPE_CONTINUATION)
00401    {
00402       //Return frame type
00403       if(type != NULL)
00404          *type = rxContext->controlFrameType;
00405    }
00406    else
00407    {
00408       //Save the FIN flag
00409       rxContext->fin = frame->fin;
00410 
00411       //Return frame type
00412       if(type != NULL)
00413          *type = rxContext->dataFrameType;
00414    }
00415 
00416    //Check status code
00417    if(webSocket->statusCode == WS_STATUS_CODE_NO_STATUS_RCVD)
00418       return NO_ERROR;
00419    else if(webSocket->statusCode == WS_STATUS_CODE_NORMAL_CLOSURE)
00420       return ERROR_END_OF_STREAM;
00421    else if(webSocket->statusCode == WS_STATUS_CODE_PROTOCOL_ERROR)
00422       return ERROR_INVALID_FRAME;
00423    else
00424       return ERROR_FAILURE;
00425 }
00426 
00427 
00428 /**
00429  * @brief Format a Close frame
00430  * @param[in] webSocket Handle to a WebSocket
00431  * @return Error code
00432  **/
00433 
00434 error_t webSocketFormatCloseFrame(WebSocket *webSocket)
00435 {
00436    error_t error;
00437    uint8_t *p;
00438 
00439    //Format Close frame
00440    error = webSocketFormatFrameHeader(webSocket,
00441       TRUE, WS_FRAME_TYPE_CLOSE, sizeof(uint16_t));
00442 
00443    //Check status code
00444    if(!error)
00445    {
00446       //1005 is a reserved value and must not be set as a status code in
00447       //a Close control frame by an endpoint
00448       if(webSocket->statusCode == WS_STATUS_CODE_NO_STATUS_RCVD)
00449          webSocket->statusCode = WS_STATUS_CODE_NORMAL_CLOSURE;
00450 
00451       //Debug message
00452       TRACE_DEBUG("  Status Code = %u\r\n", webSocket->statusCode);
00453 
00454       //Point to end of the WebSocket frame header
00455       p = webSocket->txContext.buffer + webSocket->txContext.bufferLen;
00456 
00457       //Write status code
00458       p[0] = MSB(webSocket->statusCode);
00459       p[1] = LSB(webSocket->statusCode);
00460 
00461       //All frames sent from the client to the server are masked
00462       if(webSocket->endpoint == WS_ENDPOINT_CLIENT)
00463       {
00464          //Apply masking
00465          p[0] ^= webSocket->txContext.maskingKey[0];
00466          p[1] ^= webSocket->txContext.maskingKey[1];
00467       }
00468 
00469       //Adjust the length of the frame
00470       webSocket->txContext.bufferLen += sizeof(uint16_t);
00471    }
00472 
00473    //Return status code
00474    return error;
00475 }
00476 
00477 #endif
00478