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-2023 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.2.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  //Save the hostname
289  strSafeCopy(webSocket->host, host, WEB_SOCKET_HOST_MAX_LEN);
290 
291  //Successful processing
292  return NO_ERROR;
293 }
294 
295 
296 /**
297  * @brief Set the origin header field
298  * @param[in] webSocket Handle to a WebSocket
299  * @param[in] origin NULL-terminated string containing the origin
300  * @return Error code
301  **/
302 
303 error_t webSocketSetOrigin(WebSocket *webSocket, const char_t *origin)
304 {
305  //Check parameters
306  if(webSocket == NULL || origin == NULL)
308 
309  //Save origin
310  strSafeCopy(webSocket->origin, origin, WEB_SOCKET_ORIGIN_MAX_LEN);
311 
312  //Successful processing
313  return NO_ERROR;
314 }
315 
316 
317 /**
318  * @brief Set the sub-protocol header field
319  * @param[in] webSocket Handle to a WebSocket
320  * @param[in] subProtocol NULL-terminated string containing the sub-protocol
321  * @return Error code
322  **/
323 
324 error_t webSocketSetSubProtocol(WebSocket *webSocket, const char_t *subProtocol)
325 {
326  //Check parameters
327  if(webSocket == NULL || subProtocol == NULL)
329 
330  //Save sub-protocol
331  strSafeCopy(webSocket->subProtocol, subProtocol, WEB_SOCKET_SUB_PROTOCOL_MAX_LEN);
332 
333  //Successful processing
334  return NO_ERROR;
335 }
336 
337 
338 /**
339  * @brief Set authentication information
340  * @param[in] webSocket Handle to a WebSocket
341  * @param[in] username NULL-terminated string containing the user name to be used
342  * @param[in] password NULL-terminated string containing the password to be used
343  * @param[in] allowedAuthModes Logic OR of allowed HTTP authentication schemes
344  * @return Error code
345  **/
346 
347 error_t webSocketSetAuthInfo(WebSocket *webSocket, const char_t *username,
348  const char_t *password, uint_t allowedAuthModes)
349 {
350 #if (WEB_SOCKET_BASIC_AUTH_SUPPORT == ENABLED || WEB_SOCKET_DIGEST_AUTH_SUPPORT == ENABLED)
351  WebSocketAuthContext *authContext;
352 
353  //Check parameters
354  if(webSocket == NULL || username == NULL || password == NULL)
356 
357  //Point to the authentication context
358  authContext = &webSocket->authContext;
359 
360  //Save user name
361  strSafeCopy(authContext->username, username, WEB_SOCKET_USERNAME_MAX_LEN);
362  //Save password
363  strSafeCopy(authContext->password, password, WEB_SOCKET_PASSWORD_MAX_LEN);
364  //Save the list of allowed HTTP authentication schemes
365  authContext->allowedAuthModes = allowedAuthModes;
366 #endif
367 
368  //Successful processing
369  return NO_ERROR;
370 }
371 
372 
373 /**
374  * @brief Bind the WebSocket to a particular network interface
375  * @param[in] webSocket Handle to a WebSocket
376  * @param[in] interface Network interface to be used
377  * @return Error code
378  **/
379 
381 {
382  //Make sure the WebSocket handle is valid
383  if(webSocket == NULL)
385 
386  //Explicitly associate the WebSocket with the specified interface
387  webSocket->interface = interface;
388 
389  //Successful processing
390  return NO_ERROR;
391 }
392 
393 
394 /**
395  * @brief Establish a WebSocket connection
396  * @param[in] webSocket Handle to a WebSocket
397  * @param[in] serverIpAddr IP address of the WebSocket server to connect to
398  * @param[in] serverPort TCP port number that will be used to establish the
399  * connection
400  * @param[in] uri NULL-terminated string that contains the resource name
401  * @return Error code
402  **/
403 
404 error_t webSocketConnect(WebSocket *webSocket, const IpAddr *serverIpAddr,
405  uint16_t serverPort, const char_t *uri)
406 {
407  error_t error;
408  size_t n;
409  WebSocketFrameContext *txContext;
410 
411  //Make sure the WebSocket handle is valid
412  if(webSocket == NULL)
414 
415  //Point to the TX context
416  txContext = &webSocket->txContext;
417 
418  //Initialize status code
419  error = NO_ERROR;
420 
421  //Establish connection
422  while(webSocket->state != WS_STATE_OPEN)
423  {
424  //Check current state
425  if(webSocket->state == WS_STATE_CLOSED)
426  {
427  //Check parameters
428  if(serverIpAddr == NULL || uri == NULL)
429  {
430  //Report an error
431  error = ERROR_INVALID_PARAMETER;
432  }
433  else
434  {
435  //A WebSocket client is a WebSocket endpoint that initiates a
436  //connection to a peer
437  webSocket->endpoint = WS_ENDPOINT_CLIENT;
438 
439  //Save the URI
440  strSafeCopy(webSocket->uri, uri, WEB_SOCKET_URI_MAX_LEN);
441  //Reset retry counter
442  webSocket->retryCount = 0;
443 
444 #if (WEB_SOCKET_BASIC_AUTH_SUPPORT == ENABLED || WEB_SOCKET_DIGEST_AUTH_SUPPORT == ENABLED)
445  //HTTP authentication is not used for the first connection attempt
446  webSocket->authContext.requiredAuthMode = WS_AUTH_MODE_NONE;
447  webSocket->authContext.selectedAuthMode = WS_AUTH_MODE_NONE;
448 #endif
449  //Initialize the WebSocket connection
451  }
452  }
453  else if(webSocket->state == WS_STATE_INIT)
454  {
455  //Increment retry counter
456  webSocket->retryCount++;
457 
458  //Limit the number of connection attempts
459  if(webSocket->retryCount > WEB_SOCKET_MAX_CONN_RETRIES)
460  {
461  //Report an error
462  error = ERROR_OPEN_FAILED;
463  }
464  else
465  {
466  //Open network connection
467  error = webSocketOpenConnection(webSocket);
468  }
469 
470  //Check status code
471  if(!error)
472  {
473  //Establish connection
475  }
476  }
477  else if(webSocket->state == WS_STATE_CONNECTING)
478  {
479  //Establish connection
480  error = webSocketEstablishConnection(webSocket,
481  serverIpAddr, serverPort);
482 
483  //Check status code
484  if(!error)
485  {
486  //Generate client's key
487  error = webSocketGenerateClientKey(webSocket);
488  }
489 
490  //Check status code
491  if(!error)
492  {
493  //Format client handshake
494  error = webSocketFormatClientHandshake(webSocket, serverPort);
495  }
496 
497  //Check status code
498  if(!error)
499  {
500  //Send client handshake
502  }
503  }
504  else if(webSocket->state == WS_STATE_CLIENT_HANDSHAKE)
505  {
506  //Any remaining data to be sent?
507  if(txContext->bufferPos < txContext->bufferLen)
508  {
509  //Send more data
510  error = webSocketSendData(webSocket,
511  txContext->buffer + txContext->bufferPos,
512  txContext->bufferLen - txContext->bufferPos, &n, 0);
513 
514  //Advance data pointer
515  txContext->bufferPos += n;
516  }
517  else
518  {
519  //Wait for server handshake
521  }
522  }
523  else if(webSocket->state == WS_STATE_SERVER_HANDSHAKE)
524  {
525  //Parse the server handshake
526  error = webSocketParseHandshake(webSocket);
527  }
528  else if(webSocket->state == WS_STATE_SERVER_RESP_BODY)
529  {
530  //Check Connection header field
531  if(webSocket->handshakeContext.connectionClose)
532  {
533  //Close connection
534  webSocketCloseConnection(webSocket);
535  //Try to connect again
537  }
538  else
539  {
540  //Any remaining data to read in the response body?
541  if(webSocket->handshakeContext.contentLength > 0)
542  {
543  //Limit the number of bytes to read at a time
544  n = MIN(webSocket->handshakeContext.contentLength, WEB_SOCKET_BUFFER_SIZE);
545  //Discard any received data
546  error = webSocketReceiveData(webSocket, txContext->buffer, n, &n, 0);
547  //Decrement byte counter
548  webSocket->handshakeContext.contentLength -= n;
549  }
550  else
551  {
552  //Format client handshake
553  error = webSocketFormatClientHandshake(webSocket, serverPort);
554  //Try to authenticate again
556  }
557  }
558  }
559  else
560  {
561  //Invalid state
562  error = ERROR_WRONG_STATE;
563  }
564 
565  //Check whether authentication is required
566  if(error == ERROR_AUTH_REQUIRED)
567  {
568 #if (WEB_SOCKET_BASIC_AUTH_SUPPORT == ENABLED)
569  //Basic authentication?
570  if(webSocket->authContext.requiredAuthMode == WS_AUTH_MODE_BASIC ||
571  webSocket->authContext.requiredAuthMode == WS_AUTH_MODE_NONE)
572  {
573  //Check whether the basic authentication scheme is allowed
574  if(webSocket->authContext.allowedAuthModes & WS_AUTH_MODE_BASIC)
575  {
576  //Do not try to connect again if the credentials are not valid...
577  if(webSocket->authContext.selectedAuthMode == WS_AUTH_MODE_NONE)
578  {
579  //Catch exception
580  error = NO_ERROR;
581  //Force the WebSocket client to use basic authentication
582  webSocket->authContext.selectedAuthMode = WS_AUTH_MODE_BASIC;
583  //Read response body, if any
585  }
586  }
587  }
588 #endif
589 #if (WEB_SOCKET_DIGEST_AUTH_SUPPORT == ENABLED)
590  //Digest authentication?
591  if(webSocket->authContext.requiredAuthMode == WS_AUTH_MODE_DIGEST)
592  {
593  //Check whether the digest authentication scheme is allowed
594  if(webSocket->authContext.allowedAuthModes & WS_AUTH_MODE_DIGEST)
595  {
596  //Do not try to connect again if the credentials are not valid...
597  if(webSocket->authContext.selectedAuthMode == WS_AUTH_MODE_NONE)
598  {
599  //Force the WebSocket client to use digest authentication
600  webSocket->authContext.selectedAuthMode = WS_AUTH_MODE_DIGEST;
601 
602  //Make sure that the RNG callback function has been registered
603  if(webSockRandCallback != NULL)
604  {
605  //Generate a random cnonce
606  error = webSockRandCallback(txContext->buffer,
608  }
609  else
610  {
611  //A cryptographically strong random number generator
612  //must be used to generate the cnonce
613  error = ERROR_PRNG_NOT_READY;
614  }
615 
616  //Convert the byte array to hex string
618  WEB_SOCKET_CNONCE_SIZE, webSocket->authContext.cnonce);
619 
620  //Read response body, if any
622  }
623  }
624  }
625 #endif
626  }
627 
628  //If an error occurred, then the client must fail the WebSocket
629  //connection
630  if(error)
631  {
632 #if (NET_RTOS_SUPPORT == DISABLED)
633  //Timeout error?
634  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
635  break;
636 #endif
637  //Close connection
638  webSocketCloseConnection(webSocket);
639 
640  //Switch to the CLOSED state
642  //Exit immediately
643  break;
644  }
645  }
646 
647  //Return status code
648  return error;
649 }
650 
651 
652 /**
653  * @brief Set client's key
654  * @param[in] webSocket Handle to a WebSocket
655  * @param[in] clientKey NULL-terminated string that holds the client's key
656  * @return Error code
657  **/
658 
659 error_t webSocketSetClientKey(WebSocket *webSocket, const char_t *clientKey)
660 {
661  error_t error;
662  size_t n;
663 
664  //Check parameters
665  if(webSocket == NULL || clientKey == NULL)
667 
668  //Get the length of the client's key
669  n = osStrlen(clientKey);
670 
671  //Check the length of the key
673  return ERROR_INVALID_LENGTH;
674 
675  //Copy client's key
676  osStrcpy(webSocket->handshakeContext.clientKey, clientKey);
677 
678  //a WebSocket server is a WebSocket endpoint that awaits
679  //connections from peers
680  webSocket->endpoint = WS_ENDPOINT_SERVER;
681 
682  //Initialize status code
683  webSocket->statusCode = WS_STATUS_CODE_NO_STATUS_RCVD;
684 
685  //Initialize handshake parameters
686  webSocket->handshakeContext.version = WS_HTTP_VERSION_1_1;
687  webSocket->handshakeContext.connectionUpgrade = TRUE;
688  webSocket->handshakeContext.upgradeWebSocket = TRUE;
689 
690  //Initialize FIN flag
691  webSocket->rxContext.fin = TRUE;
692 
693  //Verify client's key
694  error = webSocketVerifyClientKey(webSocket);
695  //Any error to report?
696  if(error)
697  return error;
698 
699  //Generate server's key
700  error = webSocketGenerateServerKey(webSocket);
701  //Any error to report?
702  if(error)
703  return error;
704 
705  //Format server handshake
706  error = webSocketFormatServerHandshake(webSocket);
707  //Any error to report?
708  if(error)
709  return error;
710 
711  //Update FSM state
712  webSocket->state = WS_STATE_SERVER_HANDSHAKE;
713 
714  //Successful processing
715  return NO_ERROR;
716 }
717 
718 
719 /**
720  * @brief Parse client's handshake
721  * @param[in] webSocket Handle that identifies a WebSocket
722  * @return Error code
723  **/
724 
726 {
727  error_t error;
728 
729  //Make sure the WebSocket handle is valid
730  if(webSocket == NULL)
732 
733  //a WebSocket server is a WebSocket endpoint that awaits
734  //connections from peers
735  webSocket->endpoint = WS_ENDPOINT_SERVER;
736 
737  //Initialize status code
738  error = NO_ERROR;
739 
740  //Establish connection
741  while(webSocket->state != WS_STATE_SERVER_HANDSHAKE)
742  {
743  //Check current state
744  if(webSocket->state == WS_STATE_INIT)
745  {
746  //Open network connection
747  error = webSocketOpenConnection(webSocket);
748 
749  //Check status code
750  if(!error)
751  {
752  //Establish connection
754  }
755  }
756  else if(webSocket->state == WS_STATE_CONNECTING)
757  {
758 #if (WEB_SOCKET_TLS_SUPPORT == ENABLED)
759  //TLS-secured connection?
760  if(webSocket->tlsInitCallback != NULL)
761  {
762  //Establish TLS connection
763  error = tlsConnect(webSocket->tlsContext);
764  }
765 #endif
766  //Check status code
767  if(!error)
768  {
769  //Parse client handshake
771  }
772  }
773  else if(webSocket->state == WS_STATE_CLIENT_HANDSHAKE)
774  {
775  //Parse the client handshake
776  error = webSocketParseHandshake(webSocket);
777 
778  //Check status code
779  if(!error)
780  {
781  //Generate server's key
782  error = webSocketGenerateServerKey(webSocket);
783  }
784 
785  //Check status code
786  if(!error)
787  {
788  //Format server handshake
789  error = webSocketFormatServerHandshake(webSocket);
790  }
791  }
792  else
793  {
794  //Invalid state
795  error = ERROR_WRONG_STATE;
796  }
797 
798  //Any error to report?
799  if(error)
800  break;
801  }
802 
803  //Return status code
804  return error;
805 }
806 
807 
808 /**
809  * @brief Send server's handshake
810  * @param[in] webSocket Handle that identifies a WebSocket
811  * @return Error code
812  **/
813 
815 {
816  error_t error;
817  size_t n;
818  WebSocketFrameContext *txContext;
819 
820  //Make sure the WebSocket handle is valid
821  if(webSocket == NULL)
823 
824  //Point to the TX context
825  txContext = &webSocket->txContext;
826 
827  //Initialize status code
828  error = NO_ERROR;
829 
830  //Establish connection
831  while(webSocket->state != WS_STATE_OPEN)
832  {
833  //Check current state
834  if(webSocket->state == WS_STATE_SERVER_HANDSHAKE)
835  {
836  //Any remaining data to be sent?
837  if(txContext->bufferPos < txContext->bufferLen)
838  {
839  //Send more data
840  error = webSocketSendData(webSocket,
841  txContext->buffer + txContext->bufferPos,
842  txContext->bufferLen - txContext->bufferPos, &n, 0);
843 
844  //Advance data pointer
845  txContext->bufferPos += n;
846  }
847  else
848  {
849  //The WebSocket connection is established
851  }
852  }
853  else
854  {
855  //Invalid state
856  error = ERROR_WRONG_STATE;
857  }
858 
859  //Any error to report?
860  if(error)
861  break;
862  }
863 
864  //Return status code
865  return error;
866 }
867 
868 
869 /**
870  * @brief Send HTTP error response to the client
871  * @param[in] webSocket Handle that identifies a WebSocket
872  * @param[in] statusCode HTTP status code
873  * @param[in] message Text message
874  * @return Error code
875  **/
876 
879 {
880  error_t error;
881  size_t n;
882  WebSocketFrameContext *txContext;
883 
884  //Make sure the WebSocket handle is valid
885  if(webSocket == NULL)
887 
888  //Point to the TX context
889  txContext = &webSocket->txContext;
890 
891  //Initialize status code
892  error = NO_ERROR;
893 
894  //Send HTTP error message
895  while(1)
896  {
897  //Check current state
898  if(txContext->state == WS_SUB_STATE_INIT)
899  {
900  //Format HTTP error response
901  error = webSocketFormatErrorResponse(webSocket, statusCode, message);
902 
903  //Send the response
904  txContext->state = WS_SUB_STATE_FRAME_PAYLOAD;
905  }
906  else if(txContext->state == WS_SUB_STATE_FRAME_PAYLOAD)
907  {
908  //Any remaining data to be sent?
909  if(txContext->bufferPos < txContext->bufferLen)
910  {
911  //Send more data
912  error = webSocketSendData(webSocket,
913  txContext->buffer + txContext->bufferPos,
914  txContext->bufferLen - txContext->bufferPos, &n, 0);
915 
916  //Advance data pointer
917  txContext->bufferPos += n;
918  }
919  else
920  {
921  //We are done
923  break;
924  }
925  }
926  else
927  {
928  //Invalid state
929  error = ERROR_WRONG_STATE;
930  }
931 
932  //Any error to report?
933  if(error)
934  break;
935  }
936 
937  //Return status code
938  return error;
939 }
940 
941 
942 /**
943  * @brief Transmit data over the WebSocket connection
944  * @param[in] webSocket Handle that identifies a WebSocket
945  * @param[in] data Pointer to a buffer containing the data to be transmitted
946  * @param[in] length Number of data bytes to send
947  * @param[in] type Frame type
948  * @param[out] written Actual number of bytes written (optional parameter)
949  * @return Error code
950  **/
951 
952 error_t webSocketSend(WebSocket *webSocket, const void *data,
953  size_t length, WebSocketFrameType type, size_t *written)
954 {
955  //An unfragmented message consists of a single frame with the FIN bit
956  //set and an opcode other than 0
957  return webSocketSendEx(webSocket, data, length,
958  type, written, TRUE, TRUE);
959 }
960 
961 
962 /**
963  * @brief Transmit data over the WebSocket connection
964  * @param[in] webSocket Handle that identifies a WebSocket
965  * @param[in] data Pointer to a buffer containing the data to be transmitted
966  * @param[in] length Number of data bytes to send
967  * @param[in] type Frame type
968  * @param[out] written Actual number of bytes written (optional parameter)
969  * @param[in] firstFrag First fragment of the message
970  * @param[in] lastFrag Last fragment of the message
971  **/
972 
973 error_t webSocketSendEx(WebSocket *webSocket, const void *data, size_t length,
974  WebSocketFrameType type, size_t *written, bool_t firstFrag, bool_t lastFrag)
975 {
976  error_t error;
977  size_t i;
978  size_t j;
979  size_t k;
980  size_t n;
981  const uint8_t *p;
982  WebSocketFrameContext *txContext;
983 
984  //Check parameters
985  if(webSocket == NULL || data == NULL)
987 
988  //A data frame may be transmitted by either the client or the server at
989  //any time after opening handshake completion and before that endpoint
990  //has sent a Close frame
991  if(webSocket->state != WS_STATE_OPEN)
992  return ERROR_NOT_CONNECTED;
993 
994  //Point to the TX context
995  txContext = &webSocket->txContext;
996 
997  //Initialize status code
998  error = NO_ERROR;
999 
1000  //Point to the application data to be written
1001  p = (const uint8_t *) data;
1002  //No data has been transmitted yet
1003  i = 0;
1004 
1005  //Send as much data as possible
1006  while(1)
1007  {
1008  //Check current sub-state
1009  if(txContext->state == WS_SUB_STATE_INIT)
1010  {
1011  //A fragmented message consists of a single frame with the FIN bit
1012  //clear and an opcode other than 0, followed by zero or more frames
1013  //with the FIN bit clear and the opcode set to 0, and terminated by
1014  //a single frame with the FIN bit set and an opcode of 0
1015  if(!firstFrag)
1017 
1018  //Format WebSocket frame header
1019  error = webSocketFormatFrameHeader(webSocket, lastFrag, type, length - i);
1020 
1021  //Send the frame header
1022  txContext->state = WS_SUB_STATE_FRAME_HEADER;
1023  }
1024  else if(txContext->state == WS_SUB_STATE_FRAME_HEADER)
1025  {
1026  //Any remaining data to be sent?
1027  if(txContext->bufferPos < txContext->bufferLen)
1028  {
1029  //Send more data
1030  error = webSocketSendData(webSocket,
1031  txContext->buffer + txContext->bufferPos,
1032  txContext->bufferLen - txContext->bufferPos, &n, 0);
1033 
1034  //Advance data pointer
1035  txContext->bufferPos += n;
1036  }
1037  else
1038  {
1039  //Flush the transmit buffer
1040  txContext->payloadPos = 0;
1041  txContext->bufferPos = 0;
1042  txContext->bufferLen = 0;
1043 
1044  //Send the payload of the WebSocket frame
1045  txContext->state = WS_SUB_STATE_FRAME_PAYLOAD;
1046  }
1047  }
1048  else if(txContext->state == WS_SUB_STATE_FRAME_PAYLOAD)
1049  {
1050  //Any remaining data to be sent?
1051  if(txContext->bufferPos < txContext->bufferLen)
1052  {
1053  //Send more data
1054  error = webSocketSendData(webSocket,
1055  txContext->buffer + txContext->bufferPos,
1056  txContext->bufferLen - txContext->bufferPos, &n, 0);
1057 
1058  //Advance data pointer
1059  txContext->payloadPos += n;
1060  txContext->bufferPos += n;
1061 
1062  //Total number of data that have been written
1063  i += n;
1064  }
1065  else
1066  {
1067  //Send as much data as possible
1068  if(txContext->payloadPos < txContext->payloadLen)
1069  {
1070  //Calculate the number of bytes that are pending
1071  n = MIN(length - i, txContext->payloadLen - txContext->payloadPos);
1072  //Limit the number of bytes to be copied at a time
1074 
1075  //Copy application data to the transmit buffer
1076  osMemcpy(txContext->buffer, p + i, n);
1077 
1078  //All frames sent from the client to the server are masked
1079  if(webSocket->endpoint == WS_ENDPOINT_CLIENT)
1080  {
1081  //Apply masking
1082  for(j = 0; j < n; j++)
1083  {
1084  //Index of the masking key to be applied
1085  k = (txContext->payloadPos + j) % 4;
1086  //Convert unmasked data into masked data
1087  txContext->buffer[j] ^= txContext->maskingKey[k];
1088  }
1089  }
1090 
1091  //Rewind to the beginning of the buffer
1092  txContext->bufferPos = 0;
1093  //Update the number of data buffered but not yet sent
1094  txContext->bufferLen = n;
1095  }
1096  else
1097  {
1098  //Prepare to send a new WebSocket frame
1099  txContext->state = WS_SUB_STATE_INIT;
1100 
1101  //Write operation complete?
1102  if(i >= length)
1103  break;
1104  }
1105  }
1106  }
1107  else
1108  {
1109  //Invalid state
1110  error = ERROR_WRONG_STATE;
1111  }
1112 
1113  //Any error to report?
1114  if(error)
1115  break;
1116  }
1117 
1118  //Total number of data that have been written
1119  if(written != NULL)
1120  *written = i;
1121 
1122  //Return status code
1123  return error;
1124 }
1125 
1126 
1127 /**
1128  * @brief Receive data from a WebSocket connection
1129  * @param[in] webSocket Handle that identifies a WebSocket
1130  * @param[out] data Buffer where to store the incoming data
1131  * @param[in] size Maximum number of bytes that can be received
1132  * @param[out] type Frame type
1133  * @param[out] received Number of bytes that have been received
1134  * @return Error code
1135  **/
1136 
1138  size_t size, WebSocketFrameType *type, size_t *received)
1139 {
1140  bool_t firstFrag;
1141  bool_t lastFrag;
1142 
1143  return webSocketReceiveEx(webSocket, data, size,
1144  type, received, &firstFrag, &lastFrag);
1145 }
1146 
1147 
1148 /**
1149  * @brief Receive data from a WebSocket connection
1150  * @param[in] webSocket Handle that identifies a WebSocket
1151  * @param[out] data Buffer where to store the incoming data
1152  * @param[in] size Maximum number of bytes that can be received
1153  * @param[out] type Frame type
1154  * @param[out] received Number of bytes that have been received
1155  * @param[out] firstFrag First fragment of the message
1156  * @param[out] lastFrag Last fragment of the message
1157  * @return Error code
1158  **/
1159 
1160 error_t webSocketReceiveEx(WebSocket *webSocket, void *data, size_t size,
1161  WebSocketFrameType *type, size_t *received, bool_t *firstFrag, bool_t *lastFrag)
1162 {
1163  error_t error;
1164  size_t i;
1165  size_t j;
1166  size_t k;
1167  size_t n;
1168  WebSocketFrame *frame;
1169  WebSocketFrameContext *rxContext;
1170 
1171  //Make sure the WebSocket handle is valid
1172  if(webSocket == NULL)
1173  return ERROR_INVALID_PARAMETER;
1174 
1175  //Check the state of the WebSocket connection
1176  if(webSocket->state != WS_STATE_OPEN &&
1177  webSocket->state != WS_STATE_CLOSING_RX)
1178  return ERROR_NOT_CONNECTED;
1179 
1180  //Point to the RX context
1181  rxContext = &webSocket->rxContext;
1182  //Point to the WebSocket frame header
1183  frame = (WebSocketFrame *) rxContext->buffer;
1184 
1185  //Initialize status code
1186  error = NO_ERROR;
1187 
1188  //Initialize flags
1189  if(type != NULL)
1191  if(firstFrag != NULL)
1192  *firstFrag = FALSE;
1193  if(lastFrag != NULL)
1194  *lastFrag = FALSE;
1195 
1196  //No data has been read yet
1197  i = 0;
1198 
1199  //Read as much data as possible
1200  while(i < size)
1201  {
1202  //Check current sub-state
1203  if(rxContext->state == WS_SUB_STATE_INIT)
1204  {
1205  //Flush the receive buffer
1206  rxContext->bufferPos = 0;
1207  rxContext->bufferLen = sizeof(WebSocketFrame);
1208 
1209  //Decode the frame header
1210  rxContext->state = WS_SUB_STATE_FRAME_HEADER;
1211  }
1212  else if(rxContext->state == WS_SUB_STATE_FRAME_HEADER)
1213  {
1214  //Incomplete frame header?
1215  if(rxContext->bufferPos < rxContext->bufferLen)
1216  {
1217  //Read more data
1218  error = webSocketReceiveData(webSocket,
1219  rxContext->buffer + rxContext->bufferPos,
1220  rxContext->bufferLen - rxContext->bufferPos, &n, 0);
1221 
1222  //Advance data pointer
1223  rxContext->bufferPos += n;
1224  }
1225  else
1226  {
1227  //Check the Payload Length field
1228  if(frame->payloadLen == 126)
1229  rxContext->bufferLen += sizeof(uint16_t);
1230  else if(frame->payloadLen == 127)
1231  rxContext->bufferLen += sizeof(uint64_t);
1232 
1233  //Check whether the masking key is present
1234  if(frame->mask)
1235  rxContext->bufferLen += sizeof(uint32_t);
1236 
1237  //The Opcode field defines the interpretation of the payload data
1238  if(frame->opcode == WS_FRAME_TYPE_CLOSE)
1239  {
1240  //All control frames must have a payload length of 125 bytes or less
1241  if(frame->payloadLen <= 125)
1242  {
1243  //Retrieve the length of the WebSocket frame
1244  rxContext->bufferLen += frame->payloadLen;
1245  }
1246  else
1247  {
1248  //Report a protocol error
1249  webSocket->statusCode = WS_STATUS_CODE_PROTOCOL_ERROR;
1250  //Terminate the WebSocket connection
1251  error = ERROR_INVALID_FRAME;
1252  }
1253  }
1254 
1255  //Decode the extended payload length and the masking key, if any
1256  rxContext->state = WS_SUB_STATE_FRAME_EXT_HEADER;
1257  }
1258  }
1259  else if(rxContext->state == WS_SUB_STATE_FRAME_EXT_HEADER)
1260  {
1261  //Incomplete frame header?
1262  if(rxContext->bufferPos < rxContext->bufferLen)
1263  {
1264  //Read more data
1265  error = webSocketReceiveData(webSocket,
1266  rxContext->buffer + rxContext->bufferPos,
1267  rxContext->bufferLen - rxContext->bufferPos, &n, 0);
1268 
1269  //Advance data pointer
1270  rxContext->bufferPos += n;
1271  }
1272  else
1273  {
1274  //Parse the header of the WebSocket frame
1275  error = webSocketParseFrameHeader(webSocket, frame, type);
1276 
1277  //Check status code
1278  if(error == ERROR_UNEXPECTED_MESSAGE)
1279  {
1280  error = NO_ERROR;
1281  break;
1282  }
1283  else if(error == NO_ERROR)
1284  {
1285  if(firstFrag != NULL)
1286  *firstFrag = TRUE;
1287  }
1288 
1289  //Flush the receive buffer
1290  rxContext->payloadPos = 0;
1291  rxContext->bufferPos = 0;
1292  rxContext->bufferLen = 0;
1293 
1294  //Decode the payload of the WebSocket frame
1295  rxContext->state = WS_SUB_STATE_FRAME_PAYLOAD;
1296  }
1297  }
1298  else if(rxContext->state == WS_SUB_STATE_FRAME_PAYLOAD)
1299  {
1300  if(rxContext->payloadPos < rxContext->payloadLen)
1301  {
1302  //Limit the number of bytes to read at a time
1303  n = MIN(size - i, rxContext->payloadLen - rxContext->payloadPos);
1304  //Limit the number of bytes to be copied at a time
1306 
1307  //Read more data
1308  error = webSocketReceiveData(webSocket, rxContext->buffer, n, &n, 0);
1309 
1310  //All frames sent from the client to the server are masked
1311  if(rxContext->mask)
1312  {
1313  //Unmask the data
1314  for(j = 0; j < n; j++)
1315  {
1316  //Index of the masking key to be applied
1317  k = (rxContext->payloadPos + j) % 4;
1318  //Convert masked data into unmasked data
1319  rxContext->buffer[j] ^= rxContext->maskingKey[k];
1320  }
1321  }
1322 
1323  //Text frame?
1324  if(rxContext->dataFrameType == WS_FRAME_TYPE_TEXT &&
1326  {
1327  //Compute the number of remaining data bytes in the UTF-8 stream
1328  if(rxContext->fin)
1329  k = rxContext->payloadLen - rxContext->payloadPos;
1330  else
1331  k = 0;
1332 
1333  //Invalid UTF-8 sequence?
1334  if(!webSocketCheckUtf8Stream(&webSocket->utf8Context,
1335  rxContext->buffer, n, k))
1336  {
1337  //The received data is not consistent with the type of the message
1338  webSocket->statusCode = WS_STATUS_CODE_INVALID_PAYLOAD_DATA;
1339  //The endpoint must fail the WebSocket connection
1340  error = ERROR_INVALID_FRAME;
1341  }
1342  }
1343 
1344  //Sanity check
1345  if(data != NULL)
1346  {
1347  //Copy application data
1348  osMemcpy((uint8_t *) data + i, rxContext->buffer, n);
1349  }
1350 
1351  //Advance data pointer
1352  rxContext->payloadPos += n;
1353 
1354  //Total number of data that have been read
1355  i += n;
1356  }
1357 
1358  if(rxContext->payloadPos == rxContext->payloadLen)
1359  {
1360  //Decode the next WebSocket frame
1361  rxContext->state = WS_SUB_STATE_INIT;
1362 
1363  //Last fragment of the message?
1364  if(rxContext->fin || rxContext->controlFrameType != WS_FRAME_TYPE_CONTINUATION)
1365  {
1366  if(lastFrag != NULL)
1367  *lastFrag = TRUE;
1368 
1369  //Exit immediately
1370  break;
1371  }
1372  }
1373  }
1374  else
1375  {
1376  //Invalid state
1377  error = ERROR_WRONG_STATE;
1378  }
1379 
1380  //Any error to report?
1381  if(error)
1382  break;
1383  }
1384 
1385  //Check status code
1386  if(!error)
1387  {
1388  //Return the frame type
1389  if(type != NULL)
1390  {
1391  //Control or data frame?
1393  *type = rxContext->controlFrameType;
1394  else
1395  *type = rxContext->dataFrameType;
1396  }
1397  }
1398 
1399  //Return the total number of data that have been read
1400  if(received != NULL)
1401  *received = i;
1402 
1403  //Return status code
1404  return error;
1405 }
1406 
1407 
1408 /**
1409  * @brief Check whether some data is available in the receive buffer
1410  * @param[in] webSocket Handle to a WebSocket
1411  * @return The function returns TRUE if some data is pending and can be read
1412  * immediately without blocking. Otherwise, FALSE is returned
1413  **/
1414 
1416 {
1417  bool_t available = FALSE;
1418 
1419 #if (WEB_SOCKET_TLS_SUPPORT == ENABLED)
1420  //Check whether a secure connection is being used
1421  if(webSocket->tlsContext != NULL)
1422  {
1423  //Check whether some data is pending in the receive buffer
1424  if(webSocket->tlsContext->rxBufferLen > 0)
1425  available = TRUE;
1426  }
1427 #endif
1428 
1429  //The function returns TRUE if some data can be read immediately
1430  //without blocking
1431  return available;
1432 }
1433 
1434 
1435 /**
1436  * @brief Gracefully close a WebSocket connection
1437  * @param[in] webSocket Handle to a WebSocket
1438  **/
1439 
1441 {
1442  error_t error;
1443  size_t n;
1444  WebSocketFrameContext *txContext;
1445 
1446  //Make sure the WebSocket handle is valid
1447  if(webSocket == NULL)
1448  return ERROR_INVALID_PARAMETER;
1449 
1450  //Point to the TX context
1451  txContext = &webSocket->txContext;
1452 
1453  //Initialize status code
1454  error = NO_ERROR;
1455 
1456  //Closing handshake
1457  while(webSocket->state != WS_STATE_CLOSED)
1458  {
1459  //Check current state
1460  if(webSocket->state == WS_STATE_OPEN)
1461  {
1462  //Check whether the latest frame has been completely transmitted
1463  if(txContext->payloadPos == txContext->payloadLen)
1464  {
1465  //Format Close frame
1466  error = webSocketFormatCloseFrame(webSocket);
1467  //Send Close frame
1468  webSocket->state = WS_STATE_CLOSING_TX;
1469  }
1470  else
1471  {
1472  //The WebSocket connection cannot be closed until the
1473  //transmission of the frame is complete...
1474  error = ERROR_FAILURE;
1475  }
1476  }
1477  else if(webSocket->state == WS_STATE_CLOSING_TX)
1478  {
1479  //Any remaining data to be sent?
1480  if(txContext->bufferPos < txContext->bufferLen)
1481  {
1482  //Send more data
1483  error = webSocketSendData(webSocket,
1484  txContext->buffer + txContext->bufferPos,
1485  txContext->bufferLen - txContext->bufferPos, &n, 0);
1486 
1487  //Advance data pointer
1488  txContext->bufferPos += n;
1489  }
1490  else
1491  {
1492  //Check whether a Close frame has been received from the peer
1493  if(webSocket->handshakeContext.closingFrameReceived)
1494  webSocket->state = WS_STATE_SHUTDOWN;
1495  else
1496  webSocket->state = WS_STATE_CLOSING_RX;
1497  }
1498  }
1499  else if(webSocket->state == WS_STATE_CLOSING_RX)
1500  {
1501  //After receiving a control frame indicating the connection should
1502  //be closed, a peer discards any further data received
1503  error = webSocketReceive(webSocket, NULL, WEB_SOCKET_BUFFER_SIZE, NULL, 0);
1504 
1505  //Check status code
1506  if(error == NO_ERROR)
1507  {
1508  //Close frame received?
1509  if(webSocket->handshakeContext.closingFrameReceived)
1510  {
1511  //Properly shutdown the network connection
1512  webSocket->state = WS_STATE_SHUTDOWN;
1513  }
1514  }
1515  else if(error == ERROR_INVALID_FRAME || error == ERROR_END_OF_STREAM)
1516  {
1517  //Catch exception
1518  error = NO_ERROR;
1519  //Properly shutdown the network connection
1520  webSocket->state = WS_STATE_SHUTDOWN;
1521  }
1522  }
1523  else if(webSocket->state == WS_STATE_SHUTDOWN)
1524  {
1525  //Properly dispose the network connection
1526  error = webSocketShutdownConnection(webSocket);
1527 
1528  //Check status code
1529  if(!error)
1530  {
1531  //The connection has been properly closed
1532  webSocket->state = WS_STATE_CLOSED;
1533  }
1534  }
1535  else
1536  {
1537  //Invalid state
1538  error = ERROR_WRONG_STATE;
1539  }
1540 
1541  //Any error to report?
1542  if(error)
1543  break;
1544  }
1545 
1546  //Return status code
1547  return error;
1548 }
1549 
1550 
1551 /**
1552  * @brief Close a WebSocket connection
1553  * @param[in] webSocket Handle identifying the WebSocket to close
1554  **/
1555 
1556 void webSocketClose(WebSocket *webSocket)
1557 {
1558  //Make sure the WebSocket handle is valid
1559  if(webSocket != NULL)
1560  {
1561  //Close connection
1562  webSocketCloseConnection(webSocket);
1563 
1564 #if (WEB_SOCKET_TLS_SUPPORT == ENABLED)
1565  //Release TLS session state
1566  tlsFreeSessionState(&webSocket->tlsSession);
1567 #endif
1568 
1569  //Release the WebSocket
1571  }
1572 }
1573 
1574 #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
uint8_t length
Definition: coap_common.h:193
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:1137
error_t webSocketFormatCloseFrame(WebSocket *webSocket)
Format a Close frame.
bool_t mask
Defines whether the payload data is masked.
Definition: web_socket.h:400
@ ERROR_WOULD_BLOCK
Definition: error.h:96
uint8_t data[]
Definition: ethernet.h:220
#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:79
error_t webSocketConnect(WebSocket *webSocket, const IpAddr *serverIpAddr, uint16_t serverPort, const char_t *uri)
Establish a WebSocket connection.
Definition: web_socket.c:404
char_t password[WEB_SOCKET_PASSWORD_MAX_LEN+1]
Definition: web_socket.h:359
uint8_t maskingKey[4]
Masking key.
Definition: web_socket.h:401
@ ERROR_UNEXPECTED_MESSAGE
Definition: error.h:194
uint8_t p
Definition: ndp.h:298
error_t webSocketFormatErrorResponse(WebSocket *webSocket, uint_t statusCode, const char_t *message)
Format HTTP error response.
WebSocket API (client and server)
HTTP authentication for WebSockets.
#define TRUE
Definition: os_port.h:52
bool_t webSocketCheckUtf8Stream(WebSocketUtf8Context *context, const uint8_t *data, size_t length, size_t remaining)
Check whether a an UTF-8 stream is valid.
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
__start_packed struct @0 WebSocketFrame
WebSocket frame.
Helper functions for WebSockets.
@ 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:333
#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:952
@ 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:877
#define osStrlen(s)
Definition: os_port.h:164
#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:303
void tlsFreeSessionState(TlsSessionState *session)
Properly dispose a session state.
Definition: tls.c:2698
@ ERROR_PRNG_NOT_READY
Definition: error.h:250
@ 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:398
WebSocket frame parsing and formatting.
error_t webSocketInit(void)
WebSocket related initialization.
Definition: web_socket.c:60
@ 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:324
#define FALSE
Definition: os_port.h:48
@ 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:380
#define osMemcpy(dest, src, length)
Definition: os_port.h:140
@ ERROR_INVALID_FRAME
Definition: error.h:86
char_t type
size_t bufferLen
Length of the data buffer.
Definition: web_socket.h:405
#define TlsContext
Definition: tls.h:36
size_t payloadPos
Current position.
Definition: web_socket.h:403
error_t
Error codes.
Definition: error.h:43
Frame encoding/decoding context.
Definition: web_socket.h:395
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:343
error_t webSocketSetClientKey(WebSocket *webSocket, const char_t *clientKey)
Set client's key.
Definition: web_socket.c:659
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:1160
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:63
error_t webSocketEstablishConnection(WebSocket *webSocket, const IpAddr *serverIpAddr, uint16_t serverPort)
Establish network connection.
uint16_t statusCode
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:347
@ 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:973
char_t username[WEB_SOCKET_USERNAME_MAX_LEN+1]
Definition: web_socket.h:358
@ 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:397
size_t payloadLen
Payload length.
Definition: web_socket.h:402
Base64 encoding scheme.
error_t webSocketParseClientHandshake(WebSocket *webSocket)
Parse client's handshake.
Definition: web_socket.c:725
#define MIN(a, b)
Definition: os_port.h:65
@ WS_ENDPOINT_CLIENT
Definition: web_socket.h:191
#define WebSocket
Definition: web_socket.h:177
Authentication context.
Definition: web_socket.h:354
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:396
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:164
#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
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:1415
uint8_t buffer[WEB_SOCKET_BUFFER_SIZE]
Data buffer.
Definition: web_socket.h:404
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:1556
@ 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:399
@ WS_STATE_SHUTDOWN
Definition: web_socket.h:236
uint8_t message[]
Definition: chap.h:152
error_t webSocketSendServerHandshake(WebSocket *webSocket)
Send server's handshake.
Definition: web_socket.c:814
@ 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:1440
error_t webSocketShutdownConnection(WebSocket *webSocket)
Shutdown network connection.
WebSocket transport layer.
size_t bufferPos
Current position.
Definition: web_socket.h:406
@ 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:134
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:2555
#define osStrcpy(s1, s2)
Definition: os_port.h:206
error_t socketSetTimeout(Socket *socket, systime_t timeout)
Set timeout value for blocking operations.
Definition: socket.c:145
error_t tlsConnect(TlsContext *context)
Initiate the TLS handshake.
Definition: tls.c:1720
#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:77
void webSocketChangeState(WebSocket *webSocket, WebSocketState newState)
Update WebSocket state.