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-2025 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.5.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)
1034  {
1036  }
1037 
1038  //Format WebSocket frame header
1039  error = webSocketFormatFrameHeader(webSocket, lastFrag, type, length - i);
1040 
1041  //Send the frame header
1042  txContext->state = WS_SUB_STATE_FRAME_HEADER;
1043  }
1044  else if(txContext->state == WS_SUB_STATE_FRAME_HEADER)
1045  {
1046  //Any remaining data to be sent?
1047  if(txContext->bufferPos < txContext->bufferLen)
1048  {
1049  //Send more data
1050  error = webSocketSendData(webSocket,
1051  txContext->buffer + txContext->bufferPos,
1052  txContext->bufferLen - txContext->bufferPos, &n,
1054 
1055  //Advance data pointer
1056  txContext->bufferPos += n;
1057  }
1058  else
1059  {
1060  //Flush the transmit buffer
1061  txContext->payloadPos = 0;
1062  txContext->bufferPos = 0;
1063  txContext->bufferLen = 0;
1064 
1065  //Send the payload of the WebSocket frame
1066  txContext->state = WS_SUB_STATE_FRAME_PAYLOAD;
1067  }
1068  }
1069  else if(txContext->state == WS_SUB_STATE_FRAME_PAYLOAD)
1070  {
1071  //Any remaining data to be sent?
1072  if(txContext->bufferPos < txContext->bufferLen)
1073  {
1074  //Send more data
1075  error = webSocketSendData(webSocket,
1076  txContext->buffer + txContext->bufferPos,
1077  txContext->bufferLen - txContext->bufferPos, &n, 0);
1078 
1079  //Advance data pointer
1080  txContext->payloadPos += n;
1081  txContext->bufferPos += n;
1082 
1083  //Total number of data that have been written
1084  i += n;
1085  }
1086  else
1087  {
1088  //Send as much data as possible
1089  if(txContext->payloadPos < txContext->payloadLen)
1090  {
1091  //Calculate the number of bytes that are pending
1092  n = MIN(length - i, txContext->payloadLen - txContext->payloadPos);
1093  //Limit the number of bytes to be copied at a time
1095 
1096  //Copy application data to the transmit buffer
1097  osMemcpy(txContext->buffer, p + i, n);
1098 
1099  //All frames sent from the client to the server are masked
1100  if(webSocket->endpoint == WS_ENDPOINT_CLIENT)
1101  {
1102  //Apply masking
1103  for(j = 0; j < n; j++)
1104  {
1105  //Index of the masking key to be applied
1106  k = (txContext->payloadPos + j) % 4;
1107  //Convert unmasked data into masked data
1108  txContext->buffer[j] ^= txContext->maskingKey[k];
1109  }
1110  }
1111 
1112  //Rewind to the beginning of the buffer
1113  txContext->bufferPos = 0;
1114  //Update the number of data buffered but not yet sent
1115  txContext->bufferLen = n;
1116  }
1117  else
1118  {
1119  //Prepare to send a new WebSocket frame
1120  txContext->state = WS_SUB_STATE_INIT;
1121 
1122  //Write operation complete?
1123  if(i >= length)
1124  {
1125  break;
1126  }
1127  }
1128  }
1129  }
1130  else
1131  {
1132  //Invalid state
1133  error = ERROR_WRONG_STATE;
1134  }
1135 
1136  //Any error to report?
1137  if(error)
1138  {
1139  break;
1140  }
1141  }
1142 
1143  //Total number of data that have been written
1144  if(written != NULL)
1145  {
1146  *written = i;
1147  }
1148 
1149  //Return status code
1150  return error;
1151 }
1152 
1153 
1154 /**
1155  * @brief Receive data from a WebSocket connection
1156  * @param[in] webSocket Handle that identifies a WebSocket
1157  * @param[out] data Buffer where to store the incoming data
1158  * @param[in] size Maximum number of bytes that can be received
1159  * @param[out] type Frame type
1160  * @param[out] received Number of bytes that have been received
1161  * @return Error code
1162  **/
1163 
1165  size_t size, WebSocketFrameType *type, size_t *received)
1166 {
1167  bool_t firstFrag;
1168  bool_t lastFrag;
1169 
1170  return webSocketReceiveEx(webSocket, data, size,
1171  type, received, &firstFrag, &lastFrag);
1172 }
1173 
1174 
1175 /**
1176  * @brief Receive data from a WebSocket connection
1177  * @param[in] webSocket Handle that identifies a WebSocket
1178  * @param[out] data Buffer where to store the incoming data
1179  * @param[in] size Maximum number of bytes that can be received
1180  * @param[out] type Frame type
1181  * @param[out] received Number of bytes that have been received
1182  * @param[out] firstFrag First fragment of the message
1183  * @param[out] lastFrag Last fragment of the message
1184  * @return Error code
1185  **/
1186 
1187 error_t webSocketReceiveEx(WebSocket *webSocket, void *data, size_t size,
1188  WebSocketFrameType *type, size_t *received, bool_t *firstFrag, bool_t *lastFrag)
1189 {
1190  error_t error;
1191  size_t i;
1192  size_t j;
1193  size_t k;
1194  size_t n;
1195  WebSocketFrame *frame;
1196  WebSocketFrameContext *rxContext;
1197 
1198  //Make sure the WebSocket handle is valid
1199  if(webSocket == NULL)
1200  return ERROR_INVALID_PARAMETER;
1201 
1202  //Check the state of the WebSocket connection
1203  if(webSocket->state != WS_STATE_OPEN &&
1204  webSocket->state != WS_STATE_CLOSING_RX)
1205  {
1206  return ERROR_NOT_CONNECTED;
1207  }
1208 
1209  //Point to the RX context
1210  rxContext = &webSocket->rxContext;
1211  //Point to the WebSocket frame header
1212  frame = (WebSocketFrame *) rxContext->buffer;
1213 
1214  //Initialize status code
1215  error = NO_ERROR;
1216 
1217  //Initialize flags
1218  if(type != NULL)
1219  {
1221  }
1222 
1223  if(firstFrag != NULL)
1224  {
1225  *firstFrag = FALSE;
1226  }
1227 
1228  if(lastFrag != NULL)
1229  {
1230  *lastFrag = FALSE;
1231  }
1232 
1233  //No data has been read yet
1234  i = 0;
1235 
1236  //Read as much data as possible
1237  while(i < size)
1238  {
1239  //Check current sub-state
1240  if(rxContext->state == WS_SUB_STATE_INIT)
1241  {
1242  //Flush the receive buffer
1243  rxContext->bufferPos = 0;
1244  rxContext->bufferLen = sizeof(WebSocketFrame);
1245 
1246  //Decode the frame header
1247  rxContext->state = WS_SUB_STATE_FRAME_HEADER;
1248  }
1249  else if(rxContext->state == WS_SUB_STATE_FRAME_HEADER)
1250  {
1251  //Incomplete frame header?
1252  if(rxContext->bufferPos < rxContext->bufferLen)
1253  {
1254  //Read more data
1255  error = webSocketReceiveData(webSocket,
1256  rxContext->buffer + rxContext->bufferPos,
1257  rxContext->bufferLen - rxContext->bufferPos, &n, 0);
1258 
1259  //Advance data pointer
1260  rxContext->bufferPos += n;
1261  }
1262  else
1263  {
1264  //Check the Payload Length field
1265  if(frame->payloadLen == 126)
1266  {
1267  rxContext->bufferLen += sizeof(uint16_t);
1268  }
1269  else if(frame->payloadLen == 127)
1270  {
1271  rxContext->bufferLen += sizeof(uint64_t);
1272  }
1273 
1274  //Check whether the masking key is present
1275  if(frame->mask)
1276  {
1277  rxContext->bufferLen += sizeof(uint32_t);
1278  }
1279 
1280  //The Opcode field defines the interpretation of the payload data
1281  if(frame->opcode == WS_FRAME_TYPE_CLOSE)
1282  {
1283  //All control frames must have a payload length of 125 bytes or less
1284  if(frame->payloadLen <= 125)
1285  {
1286  //Retrieve the length of the WebSocket frame
1287  rxContext->bufferLen += frame->payloadLen;
1288  }
1289  else
1290  {
1291  //Report a protocol error
1292  webSocket->statusCode = WS_STATUS_CODE_PROTOCOL_ERROR;
1293  //Terminate the WebSocket connection
1294  error = ERROR_INVALID_FRAME;
1295  }
1296  }
1297 
1298  //Decode the extended payload length and the masking key, if any
1299  rxContext->state = WS_SUB_STATE_FRAME_EXT_HEADER;
1300  }
1301  }
1302  else if(rxContext->state == WS_SUB_STATE_FRAME_EXT_HEADER)
1303  {
1304  //Incomplete frame header?
1305  if(rxContext->bufferPos < rxContext->bufferLen)
1306  {
1307  //Read more data
1308  error = webSocketReceiveData(webSocket,
1309  rxContext->buffer + rxContext->bufferPos,
1310  rxContext->bufferLen - rxContext->bufferPos, &n, 0);
1311 
1312  //Advance data pointer
1313  rxContext->bufferPos += n;
1314  }
1315  else
1316  {
1317  //Parse the header of the WebSocket frame
1318  error = webSocketParseFrameHeader(webSocket, frame, type);
1319 
1320  //Check status code
1321  if(error == ERROR_UNEXPECTED_MESSAGE)
1322  {
1323  error = NO_ERROR;
1324  break;
1325  }
1326  else if(error == NO_ERROR)
1327  {
1328  if(firstFrag != NULL)
1329  {
1330  *firstFrag = TRUE;
1331  }
1332  }
1333 
1334  //Flush the receive buffer
1335  rxContext->payloadPos = 0;
1336  rxContext->bufferPos = 0;
1337  rxContext->bufferLen = 0;
1338 
1339  //Decode the payload of the WebSocket frame
1340  rxContext->state = WS_SUB_STATE_FRAME_PAYLOAD;
1341  }
1342  }
1343  else if(rxContext->state == WS_SUB_STATE_FRAME_PAYLOAD)
1344  {
1345  if(rxContext->payloadPos < rxContext->payloadLen)
1346  {
1347  //Limit the number of bytes to read at a time
1348  n = MIN(size - i, rxContext->payloadLen - rxContext->payloadPos);
1349  //Limit the number of bytes to be copied at a time
1351 
1352  //Read more data
1353  error = webSocketReceiveData(webSocket, rxContext->buffer, n, &n, 0);
1354 
1355  //All frames sent from the client to the server are masked
1356  if(rxContext->mask)
1357  {
1358  //Unmask the data
1359  for(j = 0; j < n; j++)
1360  {
1361  //Index of the masking key to be applied
1362  k = (rxContext->payloadPos + j) % 4;
1363  //Convert masked data into unmasked data
1364  rxContext->buffer[j] ^= rxContext->maskingKey[k];
1365  }
1366  }
1367 
1368  //Text frame?
1369  if(rxContext->dataFrameType == WS_FRAME_TYPE_TEXT &&
1371  {
1372  //Compute the number of remaining data bytes in the UTF-8 stream
1373  if(rxContext->fin)
1374  {
1375  k = rxContext->payloadLen - rxContext->payloadPos;
1376  }
1377  else
1378  {
1379  k = 0;
1380  }
1381 
1382  //Invalid UTF-8 sequence?
1383  if(!webSocketCheckUtf8Stream(&webSocket->utf8Context,
1384  rxContext->buffer, n, k))
1385  {
1386  //The received data is not consistent with the type of the message
1387  webSocket->statusCode = WS_STATUS_CODE_INVALID_PAYLOAD_DATA;
1388  //The endpoint must fail the WebSocket connection
1389  error = ERROR_INVALID_FRAME;
1390  }
1391  }
1392 
1393  //Sanity check
1394  if(data != NULL)
1395  {
1396  //Copy application data
1397  osMemcpy((uint8_t *) data + i, rxContext->buffer, n);
1398  }
1399 
1400  //Advance data pointer
1401  rxContext->payloadPos += n;
1402 
1403  //Total number of data that have been read
1404  i += n;
1405  }
1406 
1407  if(rxContext->payloadPos == rxContext->payloadLen)
1408  {
1409  //Decode the next WebSocket frame
1410  rxContext->state = WS_SUB_STATE_INIT;
1411 
1412  //Last fragment of the message?
1413  if(rxContext->fin || rxContext->controlFrameType != WS_FRAME_TYPE_CONTINUATION)
1414  {
1415  if(lastFrag != NULL)
1416  {
1417  *lastFrag = TRUE;
1418  }
1419 
1420  //Exit immediately
1421  break;
1422  }
1423  }
1424  }
1425  else
1426  {
1427  //Invalid state
1428  error = ERROR_WRONG_STATE;
1429  }
1430 
1431  //Any error to report?
1432  if(error)
1433  break;
1434  }
1435 
1436  //Check status code
1437  if(!error)
1438  {
1439  //Return the frame type
1440  if(type != NULL)
1441  {
1442  //Control or data frame?
1444  {
1445  *type = rxContext->controlFrameType;
1446  }
1447  else
1448  {
1449  *type = rxContext->dataFrameType;
1450  }
1451  }
1452  }
1453 
1454  //Return the total number of data that have been read
1455  if(received != NULL)
1456  {
1457  *received = i;
1458  }
1459 
1460  //Return status code
1461  return error;
1462 }
1463 
1464 
1465 /**
1466  * @brief Check whether some data is available in the receive buffer
1467  * @param[in] webSocket Handle to a WebSocket
1468  * @return The function returns TRUE if some data is pending and can be read
1469  * immediately without blocking. Otherwise, FALSE is returned
1470  **/
1471 
1473 {
1474  bool_t available = FALSE;
1475 
1476 #if (WEB_SOCKET_TLS_SUPPORT == ENABLED)
1477  //Check whether a secure connection is being used
1478  if(webSocket->tlsContext != NULL)
1479  {
1480  //Check whether some data is pending in the receive buffer
1481  if(webSocket->tlsContext->rxBufferLen > 0)
1482  available = TRUE;
1483  }
1484 #endif
1485 
1486  //The function returns TRUE if some data can be read immediately
1487  //without blocking
1488  return available;
1489 }
1490 
1491 
1492 /**
1493  * @brief Gracefully close a WebSocket connection
1494  * @param[in] webSocket Handle to a WebSocket
1495  **/
1496 
1498 {
1499  error_t error;
1500  size_t n;
1501  WebSocketFrameContext *txContext;
1502 
1503  //Make sure the WebSocket handle is valid
1504  if(webSocket == NULL)
1505  return ERROR_INVALID_PARAMETER;
1506 
1507  //Point to the TX context
1508  txContext = &webSocket->txContext;
1509 
1510  //Initialize status code
1511  error = NO_ERROR;
1512 
1513  //Closing handshake
1514  while(webSocket->state != WS_STATE_CLOSED)
1515  {
1516  //Check current state
1517  if(webSocket->state == WS_STATE_OPEN)
1518  {
1519  //Check whether the latest frame has been completely transmitted
1520  if(txContext->payloadPos == txContext->payloadLen)
1521  {
1522  //Format Close frame
1523  error = webSocketFormatCloseFrame(webSocket);
1524  //Send Close frame
1525  webSocket->state = WS_STATE_CLOSING_TX;
1526  }
1527  else
1528  {
1529  //The WebSocket connection cannot be closed until the
1530  //transmission of the frame is complete...
1531  error = ERROR_FAILURE;
1532  }
1533  }
1534  else if(webSocket->state == WS_STATE_CLOSING_TX)
1535  {
1536  //Any remaining data to be sent?
1537  if(txContext->bufferPos < txContext->bufferLen)
1538  {
1539  //Send more data
1540  error = webSocketSendData(webSocket,
1541  txContext->buffer + txContext->bufferPos,
1542  txContext->bufferLen - txContext->bufferPos, &n, 0);
1543 
1544  //Advance data pointer
1545  txContext->bufferPos += n;
1546  }
1547  else
1548  {
1549  //Check whether a Close frame has been received from the peer
1550  if(webSocket->handshakeContext.closingFrameReceived)
1551  {
1552  webSocket->state = WS_STATE_SHUTDOWN;
1553  }
1554  else
1555  {
1556  webSocket->state = WS_STATE_CLOSING_RX;
1557  }
1558  }
1559  }
1560  else if(webSocket->state == WS_STATE_CLOSING_RX)
1561  {
1562  //After receiving a control frame indicating the connection should
1563  //be closed, a peer discards any further data received
1564  error = webSocketReceive(webSocket, NULL, WEB_SOCKET_BUFFER_SIZE, NULL, 0);
1565 
1566  //Check status code
1567  if(error == NO_ERROR)
1568  {
1569  //Close frame received?
1570  if(webSocket->handshakeContext.closingFrameReceived)
1571  {
1572  //Properly shutdown the network connection
1573  webSocket->state = WS_STATE_SHUTDOWN;
1574  }
1575  }
1576  else if(error == ERROR_INVALID_FRAME || error == ERROR_END_OF_STREAM)
1577  {
1578  //Catch exception
1579  error = NO_ERROR;
1580  //Properly shutdown the network connection
1581  webSocket->state = WS_STATE_SHUTDOWN;
1582  }
1583  }
1584  else if(webSocket->state == WS_STATE_SHUTDOWN)
1585  {
1586  //Properly dispose the network connection
1587  error = webSocketShutdownConnection(webSocket);
1588 
1589  //Check status code
1590  if(!error)
1591  {
1592  //The connection has been properly closed
1593  webSocket->state = WS_STATE_CLOSED;
1594  }
1595  }
1596  else
1597  {
1598  //Invalid state
1599  error = ERROR_WRONG_STATE;
1600  }
1601 
1602  //Any error to report?
1603  if(error)
1604  {
1605  break;
1606  }
1607  }
1608 
1609  //Return status code
1610  return error;
1611 }
1612 
1613 
1614 /**
1615  * @brief Close a WebSocket connection
1616  * @param[in] webSocket Handle identifying the WebSocket to close
1617  **/
1618 
1619 void webSocketClose(WebSocket *webSocket)
1620 {
1621  //Make sure the WebSocket handle is valid
1622  if(webSocket != NULL)
1623  {
1624  //Close connection
1625  webSocketCloseConnection(webSocket);
1626 
1627 #if (WEB_SOCKET_TLS_SUPPORT == ENABLED)
1628  //Release TLS session state
1629  tlsFreeSessionState(&webSocket->tlsSession);
1630 #endif
1631 
1632  //Release the WebSocket
1634  }
1635 }
1636 
1637 #endif
@ WS_STATE_CLOSED
Definition: web_socket.h:227
error_t webSocketFormatFrameHeader(WebSocket *webSocket, bool_t fin, WebSocketFrameType type, size_t payloadLen)
Format WebSocket frame header.
#define WEB_SOCKET_BUFFER_SIZE
Definition: web_socket.h:82
String manipulation helper functions.
int bool_t
Definition: compiler_port.h:61
error_t webSocketOpenConnection(WebSocket *webSocket)
Open network connection.
@ WS_AUTH_MODE_NONE
Definition: web_socket.h:214
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:1164
error_t webSocketFormatCloseFrame(WebSocket *webSocket)
Format a Close frame.
bool_t mask
Defines whether the payload data is masked.
Definition: web_socket.h:404
@ ERROR_WOULD_BLOCK
Definition: error.h:96
#define netMutex
Definition: net_legacy.h:195
#define WEB_SOCKET_CLIENT_KEY_SIZE
Definition: web_socket.h:171
@ WS_SUB_STATE_FRAME_PAYLOAD
Definition: web_socket.h:254
IP network address.
Definition: ip.h:90
error_t webSocketConnect(WebSocket *webSocket, const IpAddr *serverIpAddr, uint16_t serverPort, const char_t *uri)
Establish a WebSocket connection.
Definition: web_socket.c:422
char_t password[WEB_SOCKET_PASSWORD_MAX_LEN+1]
Definition: web_socket.h:363
uint8_t maskingKey[4]
Masking key.
Definition: web_socket.h:405
@ ERROR_UNEXPECTED_MESSAGE
Definition: error.h:195
uint8_t p
Definition: ndp.h:300
error_t webSocketFormatErrorResponse(WebSocket *webSocket, uint_t statusCode, const char_t *message)
Format HTTP error response.
WebSocket API (client and server)
uint8_t message[]
Definition: chap.h:154
HTTP authentication for WebSockets.
#define TRUE
Definition: os_port.h:50
bool_t webSocketCheckUtf8Stream(WebSocketUtf8Context *context, const uint8_t *data, size_t length, size_t remaining)
Check whether a an UTF-8 stream is valid.
uint8_t data[]
Definition: ethernet.h:222
void webSocketConvertArrayToHexString(const uint8_t *input, size_t inputLen, char_t *output)
Convert byte array to hex string.
#define WEB_SOCKET_HOST_MAX_LEN
Definition: web_socket.h:89
Helper functions for WebSockets.
uint8_t type
Definition: coap_common.h:176
@ WS_STATUS_CODE_NO_STATUS_RCVD
Definition: web_socket.h:283
error_t webSocketSetTimeout(WebSocket *webSocket, systime_t timeout)
Set timeout value for blocking operations.
Definition: web_socket.c:257
error_t(* WebSocketRandCallback)(uint8_t *data, size_t length)
Random data generation callback function.
Definition: web_socket.h:337
#define WEB_SOCKET_SUB_PROTOCOL_MAX_LEN
Definition: web_socket.h:103
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
@ ERROR_AUTH_REQUIRED
Definition: error.h:151
WebSocket webSocketTable[WEB_SOCKET_MAX_COUNT]
Definition: web_socket.c:50
error_t webSocketSendErrorResponse(WebSocket *webSocket, uint_t statusCode, const char_t *message)
Send HTTP error response to the client.
Definition: web_socket.c:895
#define osStrlen(s)
Definition: os_port.h:168
#define WEB_SOCKET_ORIGIN_MAX_LEN
Definition: web_socket.h:96
@ WS_STATE_CLOSING_TX
Definition: web_socket.h:234
@ ERROR_END_OF_STREAM
Definition: error.h:211
#define WEB_SOCKET_CNONCE_SIZE
Definition: web_socket.h:159
void webSocketCloseConnection(WebSocket *webSocket)
Close network connection.
error_t webSocketSetOrigin(WebSocket *webSocket, const char_t *origin)
Set the origin header field.
Definition: web_socket.c:307
void tlsFreeSessionState(TlsSessionState *session)
Properly dispose a session state.
Definition: tls.c:2871
@ ERROR_PRNG_NOT_READY
Definition: error.h:252
@ WS_STATE_INIT
Definition: web_socket.h:228
error_t webSocketSendData(WebSocket *webSocket, const void *data, size_t length, size_t *written, uint_t flags)
Send data using the relevant transport protocol.
WebSocketFrameType controlFrameType
Control frame type.
Definition: web_socket.h:402
WebSocket frame parsing and formatting.
error_t webSocketInit(void)
WebSocket related initialization.
Definition: web_socket.c:60
@ SOCKET_FLAG_DELAY
Definition: socket.h:144
@ ERROR_WRONG_STATE
Definition: error.h:210
@ WS_AUTH_MODE_BASIC
Definition: web_socket.h:215
@ ERROR_OPEN_FAILED
Definition: error.h:75
error_t webSocketSetSubProtocol(WebSocket *webSocket, const char_t *subProtocol)
Set the sub-protocol header field.
Definition: web_socket.c:332
#define FALSE
Definition: os_port.h:46
@ WS_SUB_STATE_FRAME_HEADER
Definition: web_socket.h:252
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
error_t webSocketBindToInterface(WebSocket *webSocket, NetInterface *interface)
Bind the WebSocket to a particular network interface.
Definition: web_socket.c:398
#define osMemcpy(dest, src, length)
Definition: os_port.h:144
@ ERROR_INVALID_FRAME
Definition: error.h:86
size_t bufferLen
Length of the data buffer.
Definition: web_socket.h:409
#define TlsContext
Definition: tls.h:36
size_t payloadPos
Current position.
Definition: web_socket.h:407
error_t
Error codes.
Definition: error.h:43
Frame encoding/decoding context.
Definition: web_socket.h:399
WebSocket * webSocketOpen(void)
Create a WebSocket.
Definition: web_socket.c:95
error_t(* WebSocketTlsInitCallback)(WebSocket *webSocket, TlsContext *tlsContext)
TLS initialization callback function.
Definition: web_socket.h:347
error_t webSocketSetClientKey(WebSocket *webSocket, const char_t *clientKey)
Set client's key.
Definition: web_socket.c:677
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:1187
error_t webSocketGenerateClientKey(WebSocket *webSocket)
Generate client's key.
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
error_t webSocketEstablishConnection(WebSocket *webSocket, const IpAddr *serverIpAddr, uint16_t serverPort)
Establish network connection.
WebSocketFrameType
WebSocket frame types.
Definition: web_socket.h:263
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_FAILURE
Generic error code.
Definition: error.h:45
@ WS_STATE_UNUSED
Definition: web_socket.h:226
#define NetInterface
Definition: net.h:36
@ WS_AUTH_MODE_DIGEST
Definition: web_socket.h:216
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 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
char_t username[WEB_SOCKET_USERNAME_MAX_LEN+1]
Definition: web_socket.h:362
@ ERROR_INVALID_LENGTH
Definition: error.h:111
WebSocketRandCallback webSockRandCallback
Definition: web_socket.c:52
@ WS_FRAME_TYPE_TEXT
Definition: web_socket.h:265
@ WS_ENDPOINT_SERVER
Definition: web_socket.h:192
WebSocketFrameType dataFrameType
FSM state.
Definition: web_socket.h:401
size_t payloadLen
Payload length.
Definition: web_socket.h:406
Base64 encoding scheme.
error_t webSocketParseClientHandshake(WebSocket *webSocket)
Parse client's handshake.
Definition: web_socket.c:743
uint8_t length
Definition: tcp.h:375
#define MIN(a, b)
Definition: os_port.h:63
@ WS_ENDPOINT_CLIENT
Definition: web_socket.h:191
#define WebSocket
Definition: web_socket.h:177
Authentication context.
Definition: web_socket.h:358
error_t webSocketFormatClientHandshake(WebSocket *webSocket, uint16_t serverPort)
Format client's handshake.
error_t webSocketParseFrameHeader(WebSocket *webSocket, const WebSocketFrame *frame, WebSocketFrameType *type)
Parse WebSocket frame header.
@ WS_FRAME_TYPE_CLOSE
Definition: web_socket.h:267
WebSocketSubState state
Definition: web_socket.h:400
WebSocket * webSocketUpgradeSocket(Socket *socket)
Upgrade a socket to a WebSocket.
Definition: web_socket.c:155
uint32_t systime_t
System time.
@ WS_SUB_STATE_INIT
Definition: web_socket.h:246
@ ERROR_TIMEOUT
Definition: error.h:95
char char_t
Definition: compiler_port.h:55
error_t webSocketFormatServerHandshake(WebSocket *webSocket)
Format server's handshake.
error_t strSafeCopy(char_t *dest, const char_t *src, size_t destSize)
Copy string.
Definition: str.c:172
#define WEB_SOCKET_PASSWORD_MAX_LEN
Definition: web_socket.h:138
@ WS_STATE_CONNECTING
Definition: web_socket.h:229
#define WEB_SOCKET_MAX_CONN_RETRIES
Definition: web_socket.h:75
WebSocketFrame
Definition: web_socket.h:322
error_t webSocketRegisterTlsInitCallback(WebSocket *webSocket, WebSocketTlsInitCallback callback)
Register TLS initialization callback function.
Definition: web_socket.c:233
WebSocket * webSocketUpgradeSecureSocket(Socket *socket, TlsContext *tlsContext)
Upgrade a secure socket to a secure WebSocket.
Definition: web_socket.c:194
@ ERROR_NOT_CONNECTED
Definition: error.h:80
@ WS_STATUS_CODE_INVALID_PAYLOAD_DATA
Definition: web_socket.h:285
uint8_t n
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
bool_t webSocketIsRxReady(WebSocket *webSocket)
Check whether some data is available in the receive buffer.
Definition: web_socket.c:1472
uint8_t buffer[WEB_SOCKET_BUFFER_SIZE]
Data buffer.
Definition: web_socket.h:408
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
error_t webSocketRegisterRandCallback(WebSocketRandCallback callback)
Register RNG callback function.
Definition: web_socket.c:76
void webSocketClose(WebSocket *webSocket)
Close a WebSocket connection.
Definition: web_socket.c:1619
@ WS_FRAME_TYPE_CONTINUATION
Definition: web_socket.h:264
#define Socket
Definition: socket.h:36
@ WS_STATE_SERVER_RESP_BODY
Definition: web_socket.h:232
bool_t fin
Final fragment in a message.
Definition: web_socket.h:403
@ WS_STATE_SHUTDOWN
Definition: web_socket.h:236
error_t webSocketSendServerHandshake(WebSocket *webSocket)
Send server's handshake.
Definition: web_socket.c:832
@ WS_STATE_CLIENT_HANDSHAKE
Definition: web_socket.h:230
@ WS_SUB_STATE_FRAME_EXT_HEADER
Definition: web_socket.h:253
@ WS_STATE_SERVER_HANDSHAKE
Definition: web_socket.h:231
@ WS_STATUS_CODE_PROTOCOL_ERROR
Definition: web_socket.h:281
error_t webSocketParseHandshake(WebSocket *webSocket)
Parse client or server handshake.
error_t webSocketShutdown(WebSocket *webSocket)
Gracefully close a WebSocket connection.
Definition: web_socket.c:1497
error_t webSocketShutdownConnection(WebSocket *webSocket)
Shutdown network connection.
WebSocket transport layer.
size_t bufferPos
Current position.
Definition: web_socket.h:410
@ WS_STATE_CLOSING_RX
Definition: web_socket.h:235
error_t webSocketSetHost(WebSocket *webSocket, const char_t *host)
Set the domain name of the server (for virtual hosting)
Definition: web_socket.c:282
error_t webSocketVerifyClientKey(WebSocket *webSocket)
Verify client's key.
unsigned int uint_t
Definition: compiler_port.h:57
#define osMemset(p, value, length)
Definition: os_port.h:138
TCP/IP stack core.
@ WS_HTTP_VERSION_1_1
Definition: web_socket.h:204
#define WEB_SOCKET_URI_MAX_LEN
Definition: web_socket.h:110
error_t webSocketGenerateServerKey(WebSocket *webSocket)
Generate server's key.
error_t tlsInitSessionState(TlsSessionState *session)
Initialize session state.
Definition: tls.c:2728
#define osStrcpy(s1, s2)
Definition: os_port.h:210
error_t socketSetTimeout(Socket *socket, systime_t timeout)
Set timeout value for blocking operations.
Definition: socket.c:148
error_t tlsConnect(TlsContext *context)
Initiate the TLS handshake.
Definition: tls.c:1730
#define WEB_SOCKET_USERNAME_MAX_LEN
Definition: web_socket.h:131
#define WEB_SOCKET_MAX_COUNT
Definition: web_socket.h:47
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
@ WS_STATE_OPEN
Definition: web_socket.h:233
#define INFINITE_DELAY
Definition: os_port.h:75
void webSocketChangeState(WebSocket *webSocket, WebSocketState newState)
Update WebSocket state.