Webserver+3d print
Embed:
(wiki syntax)
Show/hide line numbers
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
Generated on Tue Jul 12 2022 17:10:17 by
