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.4
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,
1052 
1053  //Advance data pointer
1054  txContext->bufferPos += n;
1055  }
1056  else
1057  {
1058  //Flush the transmit buffer
1059  txContext->payloadPos = 0;
1060  txContext->bufferPos = 0;
1061  txContext->bufferLen = 0;
1062 
1063  //Send the payload of the WebSocket frame
1064  txContext->state = WS_SUB_STATE_FRAME_PAYLOAD;
1065  }
1066  }
1067  else if(txContext->state == WS_SUB_STATE_FRAME_PAYLOAD)
1068  {
1069  //Any remaining data to be sent?
1070  if(txContext->bufferPos < txContext->bufferLen)
1071  {
1072  //Send more data
1073  error = webSocketSendData(webSocket,
1074  txContext->buffer + txContext->bufferPos,
1075  txContext->bufferLen - txContext->bufferPos, &n, 0);
1076 
1077  //Advance data pointer
1078  txContext->payloadPos += n;
1079  txContext->bufferPos += n;
1080 
1081  //Total number of data that have been written
1082  i += n;
1083  }
1084  else
1085  {
1086  //Send as much data as possible
1087  if(txContext->payloadPos < txContext->payloadLen)
1088  {
1089  //Calculate the number of bytes that are pending
1090  n = MIN(length - i, txContext->payloadLen - txContext->payloadPos);
1091  //Limit the number of bytes to be copied at a time
1093 
1094  //Copy application data to the transmit buffer
1095  osMemcpy(txContext->buffer, p + i, n);
1096 
1097  //All frames sent from the client to the server are masked
1098  if(webSocket->endpoint == WS_ENDPOINT_CLIENT)
1099  {
1100  //Apply masking
1101  for(j = 0; j < n; j++)
1102  {
1103  //Index of the masking key to be applied
1104  k = (txContext->payloadPos + j) % 4;
1105  //Convert unmasked data into masked data
1106  txContext->buffer[j] ^= txContext->maskingKey[k];
1107  }
1108  }
1109 
1110  //Rewind to the beginning of the buffer
1111  txContext->bufferPos = 0;
1112  //Update the number of data buffered but not yet sent
1113  txContext->bufferLen = n;
1114  }
1115  else
1116  {
1117  //Prepare to send a new WebSocket frame
1118  txContext->state = WS_SUB_STATE_INIT;
1119 
1120  //Write operation complete?
1121  if(i >= length)
1122  break;
1123  }
1124  }
1125  }
1126  else
1127  {
1128  //Invalid state
1129  error = ERROR_WRONG_STATE;
1130  }
1131 
1132  //Any error to report?
1133  if(error)
1134  break;
1135  }
1136 
1137  //Total number of data that have been written
1138  if(written != NULL)
1139  *written = i;
1140 
1141  //Return status code
1142  return error;
1143 }
1144 
1145 
1146 /**
1147  * @brief Receive data from a WebSocket connection
1148  * @param[in] webSocket Handle that identifies a WebSocket
1149  * @param[out] data Buffer where to store the incoming data
1150  * @param[in] size Maximum number of bytes that can be received
1151  * @param[out] type Frame type
1152  * @param[out] received Number of bytes that have been received
1153  * @return Error code
1154  **/
1155 
1157  size_t size, WebSocketFrameType *type, size_t *received)
1158 {
1159  bool_t firstFrag;
1160  bool_t lastFrag;
1161 
1162  return webSocketReceiveEx(webSocket, data, size,
1163  type, received, &firstFrag, &lastFrag);
1164 }
1165 
1166 
1167 /**
1168  * @brief Receive data from a WebSocket connection
1169  * @param[in] webSocket Handle that identifies a WebSocket
1170  * @param[out] data Buffer where to store the incoming data
1171  * @param[in] size Maximum number of bytes that can be received
1172  * @param[out] type Frame type
1173  * @param[out] received Number of bytes that have been received
1174  * @param[out] firstFrag First fragment of the message
1175  * @param[out] lastFrag Last fragment of the message
1176  * @return Error code
1177  **/
1178 
1179 error_t webSocketReceiveEx(WebSocket *webSocket, void *data, size_t size,
1180  WebSocketFrameType *type, size_t *received, bool_t *firstFrag, bool_t *lastFrag)
1181 {
1182  error_t error;
1183  size_t i;
1184  size_t j;
1185  size_t k;
1186  size_t n;
1187  WebSocketFrame *frame;
1188  WebSocketFrameContext *rxContext;
1189 
1190  //Make sure the WebSocket handle is valid
1191  if(webSocket == NULL)
1192  return ERROR_INVALID_PARAMETER;
1193 
1194  //Check the state of the WebSocket connection
1195  if(webSocket->state != WS_STATE_OPEN &&
1196  webSocket->state != WS_STATE_CLOSING_RX)
1197  return ERROR_NOT_CONNECTED;
1198 
1199  //Point to the RX context
1200  rxContext = &webSocket->rxContext;
1201  //Point to the WebSocket frame header
1202  frame = (WebSocketFrame *) rxContext->buffer;
1203 
1204  //Initialize status code
1205  error = NO_ERROR;
1206 
1207  //Initialize flags
1208  if(type != NULL)
1210  if(firstFrag != NULL)
1211  *firstFrag = FALSE;
1212  if(lastFrag != NULL)
1213  *lastFrag = FALSE;
1214 
1215  //No data has been read yet
1216  i = 0;
1217 
1218  //Read as much data as possible
1219  while(i < size)
1220  {
1221  //Check current sub-state
1222  if(rxContext->state == WS_SUB_STATE_INIT)
1223  {
1224  //Flush the receive buffer
1225  rxContext->bufferPos = 0;
1226  rxContext->bufferLen = sizeof(WebSocketFrame);
1227 
1228  //Decode the frame header
1229  rxContext->state = WS_SUB_STATE_FRAME_HEADER;
1230  }
1231  else if(rxContext->state == WS_SUB_STATE_FRAME_HEADER)
1232  {
1233  //Incomplete frame header?
1234  if(rxContext->bufferPos < rxContext->bufferLen)
1235  {
1236  //Read more data
1237  error = webSocketReceiveData(webSocket,
1238  rxContext->buffer + rxContext->bufferPos,
1239  rxContext->bufferLen - rxContext->bufferPos, &n, 0);
1240 
1241  //Advance data pointer
1242  rxContext->bufferPos += n;
1243  }
1244  else
1245  {
1246  //Check the Payload Length field
1247  if(frame->payloadLen == 126)
1248  {
1249  rxContext->bufferLen += sizeof(uint16_t);
1250  }
1251  else if(frame->payloadLen == 127)
1252  {
1253  rxContext->bufferLen += sizeof(uint64_t);
1254  }
1255 
1256  //Check whether the masking key is present
1257  if(frame->mask)
1258  rxContext->bufferLen += sizeof(uint32_t);
1259 
1260  //The Opcode field defines the interpretation of the payload data
1261  if(frame->opcode == WS_FRAME_TYPE_CLOSE)
1262  {
1263  //All control frames must have a payload length of 125 bytes or less
1264  if(frame->payloadLen <= 125)
1265  {
1266  //Retrieve the length of the WebSocket frame
1267  rxContext->bufferLen += frame->payloadLen;
1268  }
1269  else
1270  {
1271  //Report a protocol error
1272  webSocket->statusCode = WS_STATUS_CODE_PROTOCOL_ERROR;
1273  //Terminate the WebSocket connection
1274  error = ERROR_INVALID_FRAME;
1275  }
1276  }
1277 
1278  //Decode the extended payload length and the masking key, if any
1279  rxContext->state = WS_SUB_STATE_FRAME_EXT_HEADER;
1280  }
1281  }
1282  else if(rxContext->state == WS_SUB_STATE_FRAME_EXT_HEADER)
1283  {
1284  //Incomplete frame header?
1285  if(rxContext->bufferPos < rxContext->bufferLen)
1286  {
1287  //Read more data
1288  error = webSocketReceiveData(webSocket,
1289  rxContext->buffer + rxContext->bufferPos,
1290  rxContext->bufferLen - rxContext->bufferPos, &n, 0);
1291 
1292  //Advance data pointer
1293  rxContext->bufferPos += n;
1294  }
1295  else
1296  {
1297  //Parse the header of the WebSocket frame
1298  error = webSocketParseFrameHeader(webSocket, frame, type);
1299 
1300  //Check status code
1301  if(error == ERROR_UNEXPECTED_MESSAGE)
1302  {
1303  error = NO_ERROR;
1304  break;
1305  }
1306  else if(error == NO_ERROR)
1307  {
1308  if(firstFrag != NULL)
1309  *firstFrag = TRUE;
1310  }
1311 
1312  //Flush the receive buffer
1313  rxContext->payloadPos = 0;
1314  rxContext->bufferPos = 0;
1315  rxContext->bufferLen = 0;
1316 
1317  //Decode the payload of the WebSocket frame
1318  rxContext->state = WS_SUB_STATE_FRAME_PAYLOAD;
1319  }
1320  }
1321  else if(rxContext->state == WS_SUB_STATE_FRAME_PAYLOAD)
1322  {
1323  if(rxContext->payloadPos < rxContext->payloadLen)
1324  {
1325  //Limit the number of bytes to read at a time
1326  n = MIN(size - i, rxContext->payloadLen - rxContext->payloadPos);
1327  //Limit the number of bytes to be copied at a time
1329 
1330  //Read more data
1331  error = webSocketReceiveData(webSocket, rxContext->buffer, n, &n, 0);
1332 
1333  //All frames sent from the client to the server are masked
1334  if(rxContext->mask)
1335  {
1336  //Unmask the data
1337  for(j = 0; j < n; j++)
1338  {
1339  //Index of the masking key to be applied
1340  k = (rxContext->payloadPos + j) % 4;
1341  //Convert masked data into unmasked data
1342  rxContext->buffer[j] ^= rxContext->maskingKey[k];
1343  }
1344  }
1345 
1346  //Text frame?
1347  if(rxContext->dataFrameType == WS_FRAME_TYPE_TEXT &&
1349  {
1350  //Compute the number of remaining data bytes in the UTF-8 stream
1351  if(rxContext->fin)
1352  {
1353  k = rxContext->payloadLen - rxContext->payloadPos;
1354  }
1355  else
1356  {
1357  k = 0;
1358  }
1359 
1360  //Invalid UTF-8 sequence?
1361  if(!webSocketCheckUtf8Stream(&webSocket->utf8Context,
1362  rxContext->buffer, n, k))
1363  {
1364  //The received data is not consistent with the type of the message
1365  webSocket->statusCode = WS_STATUS_CODE_INVALID_PAYLOAD_DATA;
1366  //The endpoint must fail the WebSocket connection
1367  error = ERROR_INVALID_FRAME;
1368  }
1369  }
1370 
1371  //Sanity check
1372  if(data != NULL)
1373  {
1374  //Copy application data
1375  osMemcpy((uint8_t *) data + i, rxContext->buffer, n);
1376  }
1377 
1378  //Advance data pointer
1379  rxContext->payloadPos += n;
1380 
1381  //Total number of data that have been read
1382  i += n;
1383  }
1384 
1385  if(rxContext->payloadPos == rxContext->payloadLen)
1386  {
1387  //Decode the next WebSocket frame
1388  rxContext->state = WS_SUB_STATE_INIT;
1389 
1390  //Last fragment of the message?
1391  if(rxContext->fin || rxContext->controlFrameType != WS_FRAME_TYPE_CONTINUATION)
1392  {
1393  if(lastFrag != NULL)
1394  *lastFrag = TRUE;
1395 
1396  //Exit immediately
1397  break;
1398  }
1399  }
1400  }
1401  else
1402  {
1403  //Invalid state
1404  error = ERROR_WRONG_STATE;
1405  }
1406 
1407  //Any error to report?
1408  if(error)
1409  break;
1410  }
1411 
1412  //Check status code
1413  if(!error)
1414  {
1415  //Return the frame type
1416  if(type != NULL)
1417  {
1418  //Control or data frame?
1420  {
1421  *type = rxContext->controlFrameType;
1422  }
1423  else
1424  {
1425  *type = rxContext->dataFrameType;
1426  }
1427  }
1428  }
1429 
1430  //Return the total number of data that have been read
1431  if(received != NULL)
1432  *received = i;
1433 
1434  //Return status code
1435  return error;
1436 }
1437 
1438 
1439 /**
1440  * @brief Check whether some data is available in the receive buffer
1441  * @param[in] webSocket Handle to a WebSocket
1442  * @return The function returns TRUE if some data is pending and can be read
1443  * immediately without blocking. Otherwise, FALSE is returned
1444  **/
1445 
1447 {
1448  bool_t available = FALSE;
1449 
1450 #if (WEB_SOCKET_TLS_SUPPORT == ENABLED)
1451  //Check whether a secure connection is being used
1452  if(webSocket->tlsContext != NULL)
1453  {
1454  //Check whether some data is pending in the receive buffer
1455  if(webSocket->tlsContext->rxBufferLen > 0)
1456  available = TRUE;
1457  }
1458 #endif
1459 
1460  //The function returns TRUE if some data can be read immediately
1461  //without blocking
1462  return available;
1463 }
1464 
1465 
1466 /**
1467  * @brief Gracefully close a WebSocket connection
1468  * @param[in] webSocket Handle to a WebSocket
1469  **/
1470 
1472 {
1473  error_t error;
1474  size_t n;
1475  WebSocketFrameContext *txContext;
1476 
1477  //Make sure the WebSocket handle is valid
1478  if(webSocket == NULL)
1479  return ERROR_INVALID_PARAMETER;
1480 
1481  //Point to the TX context
1482  txContext = &webSocket->txContext;
1483 
1484  //Initialize status code
1485  error = NO_ERROR;
1486 
1487  //Closing handshake
1488  while(webSocket->state != WS_STATE_CLOSED)
1489  {
1490  //Check current state
1491  if(webSocket->state == WS_STATE_OPEN)
1492  {
1493  //Check whether the latest frame has been completely transmitted
1494  if(txContext->payloadPos == txContext->payloadLen)
1495  {
1496  //Format Close frame
1497  error = webSocketFormatCloseFrame(webSocket);
1498  //Send Close frame
1499  webSocket->state = WS_STATE_CLOSING_TX;
1500  }
1501  else
1502  {
1503  //The WebSocket connection cannot be closed until the
1504  //transmission of the frame is complete...
1505  error = ERROR_FAILURE;
1506  }
1507  }
1508  else if(webSocket->state == WS_STATE_CLOSING_TX)
1509  {
1510  //Any remaining data to be sent?
1511  if(txContext->bufferPos < txContext->bufferLen)
1512  {
1513  //Send more data
1514  error = webSocketSendData(webSocket,
1515  txContext->buffer + txContext->bufferPos,
1516  txContext->bufferLen - txContext->bufferPos, &n, 0);
1517 
1518  //Advance data pointer
1519  txContext->bufferPos += n;
1520  }
1521  else
1522  {
1523  //Check whether a Close frame has been received from the peer
1524  if(webSocket->handshakeContext.closingFrameReceived)
1525  {
1526  webSocket->state = WS_STATE_SHUTDOWN;
1527  }
1528  else
1529  {
1530  webSocket->state = WS_STATE_CLOSING_RX;
1531  }
1532  }
1533  }
1534  else if(webSocket->state == WS_STATE_CLOSING_RX)
1535  {
1536  //After receiving a control frame indicating the connection should
1537  //be closed, a peer discards any further data received
1538  error = webSocketReceive(webSocket, NULL, WEB_SOCKET_BUFFER_SIZE, NULL, 0);
1539 
1540  //Check status code
1541  if(error == NO_ERROR)
1542  {
1543  //Close frame received?
1544  if(webSocket->handshakeContext.closingFrameReceived)
1545  {
1546  //Properly shutdown the network connection
1547  webSocket->state = WS_STATE_SHUTDOWN;
1548  }
1549  }
1550  else if(error == ERROR_INVALID_FRAME || error == ERROR_END_OF_STREAM)
1551  {
1552  //Catch exception
1553  error = NO_ERROR;
1554  //Properly shutdown the network connection
1555  webSocket->state = WS_STATE_SHUTDOWN;
1556  }
1557  }
1558  else if(webSocket->state == WS_STATE_SHUTDOWN)
1559  {
1560  //Properly dispose the network connection
1561  error = webSocketShutdownConnection(webSocket);
1562 
1563  //Check status code
1564  if(!error)
1565  {
1566  //The connection has been properly closed
1567  webSocket->state = WS_STATE_CLOSED;
1568  }
1569  }
1570  else
1571  {
1572  //Invalid state
1573  error = ERROR_WRONG_STATE;
1574  }
1575 
1576  //Any error to report?
1577  if(error)
1578  break;
1579  }
1580 
1581  //Return status code
1582  return error;
1583 }
1584 
1585 
1586 /**
1587  * @brief Close a WebSocket connection
1588  * @param[in] webSocket Handle identifying the WebSocket to close
1589  **/
1590 
1591 void webSocketClose(WebSocket *webSocket)
1592 {
1593  //Make sure the WebSocket handle is valid
1594  if(webSocket != NULL)
1595  {
1596  //Close connection
1597  webSocketCloseConnection(webSocket);
1598 
1599 #if (WEB_SOCKET_TLS_SUPPORT == ENABLED)
1600  //Release TLS session state
1601  tlsFreeSessionState(&webSocket->tlsSession);
1602 #endif
1603 
1604  //Release the WebSocket
1606  }
1607 }
1608 
1609 #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:53
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:1156
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:194
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:150
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:165
#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:210
#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:2753
@ ERROR_PRNG_NOT_READY
Definition: error.h:251
@ 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:209
@ 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:141
@ 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:1179
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:368
#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:48
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:1446
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:1591
@ 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:1471
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:50
#define osMemset(p, value, length)
Definition: os_port.h:135
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:2610
#define osStrcpy(s1, s2)
Definition: os_port.h:207
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:1763
#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.