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