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