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-2019 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 1.9.6
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
63  memset(webSocketTable, 0, sizeof(webSocketTable));
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  memset(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  {
572  //Check whether the basic authentication scheme is allowed
573  if(webSocket->authContext.allowedAuthModes & WS_AUTH_MODE_BASIC)
574  {
575  //Do not try to connect again if the credentials are not valid...
576  if(webSocket->authContext.selectedAuthMode == WS_AUTH_MODE_NONE)
577  {
578  //Catch exception
579  error = NO_ERROR;
580  //Force the WebSocket client to use basic authentication
581  webSocket->authContext.selectedAuthMode = WS_AUTH_MODE_BASIC;
582  //Read response body, if any
584  }
585  }
586  }
587 #endif
588 #if (WEB_SOCKET_DIGEST_AUTH_SUPPORT == ENABLED)
589  //Digest authentication?
590  if(webSocket->authContext.requiredAuthMode == WS_AUTH_MODE_DIGEST)
591  {
592  //Check whether the digest authentication scheme is allowed
593  if(webSocket->authContext.allowedAuthModes & WS_AUTH_MODE_DIGEST)
594  {
595  //Do not try to connect again if the credentials are not valid...
596  if(webSocket->authContext.selectedAuthMode == WS_AUTH_MODE_NONE)
597  {
598  //Force the WebSocket client to use digest authentication
599  webSocket->authContext.selectedAuthMode = WS_AUTH_MODE_DIGEST;
600 
601  //Make sure that the RNG callback function has been registered
602  if(webSockRandCallback != NULL)
603  {
604  //Generate a random cnonce
605  error = webSockRandCallback(txContext->buffer,
607  }
608  else
609  {
610  //A cryptographically strong random number generator
611  //must be used to generate the cnonce
612  error = ERROR_PRNG_NOT_READY;
613  }
614 
615  //Convert the byte array to hex string
617  WEB_SOCKET_CNONCE_SIZE, webSocket->authContext.cnonce);
618 
619  //Read response body, if any
621  }
622  }
623  }
624 #endif
625  }
626 
627  //If an error occurred, then the client must fail the WebSocket
628  //connection
629  if(error)
630  {
631 #if (NET_RTOS_SUPPORT == DISABLED)
632  //Timeout error?
633  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
634  break;
635 #endif
636  //Close connection
637  webSocketCloseConnection(webSocket);
638 
639  //Switch to the CLOSED state
641  //Exit immediately
642  break;
643  }
644  }
645 
646  //Return status code
647  return error;
648 }
649 
650 
651 /**
652  * @brief Set client's key
653  * @param[in] webSocket Handle to a WebSocket
654  * @param[in] clientKey NULL-terminated string that holds the the client's key
655  * @return Error code
656  **/
657 
658 error_t webSocketSetClientKey(WebSocket *webSocket, const char_t *clientKey)
659 {
660  error_t error;
661  size_t n;
662 
663  //Check parameters
664  if(webSocket == NULL || clientKey == NULL)
666 
667  //Get the length of the client's key
668  n = strlen(clientKey);
669 
670  //Check the length of the key
672  return ERROR_INVALID_LENGTH;
673 
674  //Copy client's key
675  strcpy(webSocket->handshakeContext.clientKey, clientKey);
676 
677  //a WebSocket server is a WebSocket endpoint that awaits
678  //connections from peers
679  webSocket->endpoint = WS_ENDPOINT_SERVER;
680 
681  //Initialize status code
682  webSocket->statusCode = WS_STATUS_CODE_NO_STATUS_RCVD;
683 
684  //Initialize handshake parameters
685  webSocket->handshakeContext.version = WS_HTTP_VERSION_1_1;
686  webSocket->handshakeContext.connectionUpgrade = TRUE;
687  webSocket->handshakeContext.upgradeWebSocket = TRUE;
688 
689  //Initialize FIN flag
690  webSocket->rxContext.fin = TRUE;
691 
692  //Verify client's key
693  error = webSocketVerifyClientKey(webSocket);
694  //Any error to report?
695  if(error)
696  return error;
697 
698  //Generate server's key
699  error = webSocketGenerateServerKey(webSocket);
700  //Any error to report?
701  if(error)
702  return error;
703 
704  //Format server handshake
705  error = webSocketFormatServerHandshake(webSocket);
706  //Any error to report?
707  if(error)
708  return error;
709 
710  //Update FSM state
711  webSocket->state = WS_STATE_SERVER_HANDSHAKE;
712 
713  //Successful processing
714  return NO_ERROR;
715 }
716 
717 
718 /**
719  * @brief Parse client's handshake
720  * @param[in] webSocket Handle that identifies a WebSocket
721  * @return Error code
722  **/
723 
725 {
726  error_t error;
727 
728  //Make sure the WebSocket handle is valid
729  if(webSocket == NULL)
731 
732  //a WebSocket server is a WebSocket endpoint that awaits
733  //connections from peers
734  webSocket->endpoint = WS_ENDPOINT_SERVER;
735 
736  //Initialize status code
737  error = NO_ERROR;
738 
739  //Establish connection
740  while(webSocket->state != WS_STATE_SERVER_HANDSHAKE)
741  {
742  //Check current state
743  if(webSocket->state == WS_STATE_INIT)
744  {
745  //Open network connection
746  error = webSocketOpenConnection(webSocket);
747 
748  //Check status code
749  if(!error)
750  {
751  //Establish connection
753  }
754  }
755  else if(webSocket->state == WS_STATE_CONNECTING)
756  {
757 #if (WEB_SOCKET_TLS_SUPPORT == ENABLED)
758  //TLS-secured connection?
759  if(webSocket->tlsInitCallback != NULL)
760  {
761  //Establish TLS connection
762  error = tlsConnect(webSocket->tlsContext);
763  }
764 #endif
765  //Check status code
766  if(!error)
767  {
768  //Parse client handshake
770  }
771  }
772  else if(webSocket->state == WS_STATE_CLIENT_HANDSHAKE)
773  {
774  //Parse the client handshake
775  error = webSocketParseHandshake(webSocket);
776 
777  //Check status code
778  if(!error)
779  {
780  //Generate server's key
781  error = webSocketGenerateServerKey(webSocket);
782  }
783 
784  //Check status code
785  if(!error)
786  {
787  //Format server handshake
788  error = webSocketFormatServerHandshake(webSocket);
789  }
790  }
791  else
792  {
793  //Invalid state
794  error = ERROR_WRONG_STATE;
795  }
796 
797  //Any error to report?
798  if(error)
799  break;
800  }
801 
802  //Return status code
803  return error;
804 }
805 
806 
807 /**
808  * @brief Send server's handshake
809  * @param[in] webSocket Handle that identifies a WebSocket
810  * @return Error code
811  **/
812 
814 {
815  error_t error;
816  size_t n;
817  WebSocketFrameContext *txContext;
818 
819  //Make sure the WebSocket handle is valid
820  if(webSocket == NULL)
822 
823  //Point to the TX context
824  txContext = &webSocket->txContext;
825 
826  //Initialize status code
827  error = NO_ERROR;
828 
829  //Establish connection
830  while(webSocket->state != WS_STATE_OPEN)
831  {
832  //Check current state
833  if(webSocket->state == WS_STATE_SERVER_HANDSHAKE)
834  {
835  //Any remaining data to be sent?
836  if(txContext->bufferPos < txContext->bufferLen)
837  {
838  //Send more data
839  error = webSocketSendData(webSocket,
840  txContext->buffer + txContext->bufferPos,
841  txContext->bufferLen - txContext->bufferPos, &n, 0);
842 
843  //Advance data pointer
844  txContext->bufferPos += n;
845  }
846  else
847  {
848  //The WebSocket connection is established
850  }
851  }
852  else
853  {
854  //Invalid state
855  error = ERROR_WRONG_STATE;
856  }
857 
858  //Any error to report?
859  if(error)
860  break;
861  }
862 
863  //Return status code
864  return error;
865 }
866 
867 
868 /**
869  * @brief Send HTTP error response to the client
870  * @param[in] webSocket Handle that identifies a WebSocket
871  * @param[in] statusCode HTTP status code
872  * @param[in] message Text message
873  * @return Error code
874  **/
875 
878 {
879  error_t error;
880  size_t n;
881  WebSocketFrameContext *txContext;
882 
883  //Make sure the WebSocket handle is valid
884  if(webSocket == NULL)
886 
887  //Point to the TX context
888  txContext = &webSocket->txContext;
889 
890  //Initialize status code
891  error = NO_ERROR;
892 
893  //Send HTTP error message
894  while(1)
895  {
896  //Check current state
897  if(txContext->state == WS_SUB_STATE_INIT)
898  {
899  //Format HTTP error response
900  error = webSocketFormatErrorResponse(webSocket, statusCode, message);
901 
902  //Send the response
903  txContext->state = WS_SUB_STATE_FRAME_PAYLOAD;
904  }
905  else if(txContext->state == WS_SUB_STATE_FRAME_PAYLOAD)
906  {
907  //Any remaining data to be sent?
908  if(txContext->bufferPos < txContext->bufferLen)
909  {
910  //Send more data
911  error = webSocketSendData(webSocket,
912  txContext->buffer + txContext->bufferPos,
913  txContext->bufferLen - txContext->bufferPos, &n, 0);
914 
915  //Advance data pointer
916  txContext->bufferPos += n;
917  }
918  else
919  {
920  //We are done
922  break;
923  }
924  }
925  else
926  {
927  //Invalid state
928  error = ERROR_WRONG_STATE;
929  }
930 
931  //Any error to report?
932  if(error)
933  break;
934  }
935 
936  //Return status code
937  return error;
938 }
939 
940 
941 /**
942  * @brief Transmit data over the WebSocket connection
943  * @param[in] webSocket Handle that identifies a WebSocket
944  * @param[in] data Pointer to a buffer containing the data to be transmitted
945  * @param[in] length Number of data bytes to send
946  * @param[in] type Frame type
947  * @param[out] written Actual number of bytes written (optional parameter)
948  * @return Error code
949  **/
950 
951 error_t webSocketSend(WebSocket *webSocket, const void *data,
952  size_t length, WebSocketFrameType type, size_t *written)
953 {
954  //An unfragmented message consists of a single frame with the FIN bit
955  //set and an opcode other than 0
956  return webSocketSendEx(webSocket, data, length,
957  type, written, TRUE, TRUE);
958 }
959 
960 
961 /**
962  * @brief Transmit data over the WebSocket connection
963  * @param[in] webSocket Handle that identifies a WebSocket
964  * @param[in] data Pointer to a buffer containing the data to be transmitted
965  * @param[in] length Number of data bytes to send
966  * @param[in] type Frame type
967  * @param[out] written Actual number of bytes written (optional parameter)
968  * @param[in] firstFrag First fragment of the message
969  * @param[in] lastFrag Last fragment of the message
970  **/
971 
972 error_t webSocketSendEx(WebSocket *webSocket, const void *data, size_t length,
973  WebSocketFrameType type, size_t *written, bool_t firstFrag, bool_t lastFrag)
974 {
975  error_t error;
976  size_t i;
977  size_t j;
978  size_t k;
979  size_t n;
980  const uint8_t *p;
981  WebSocketFrameContext *txContext;
982 
983  //Check parameters
984  if(webSocket == NULL || data == NULL)
986 
987  //A data frame may be transmitted by either the client or the server at
988  //any time after opening handshake completion and before that endpoint
989  //has sent a Close frame
990  if(webSocket->state != WS_STATE_OPEN)
991  return ERROR_NOT_CONNECTED;
992 
993  //Point to the TX context
994  txContext = &webSocket->txContext;
995 
996  //Initialize status code
997  error = NO_ERROR;
998 
999  //Point to the application data to be written
1000  p = (const uint8_t *) data;
1001  //No data has been transmitted yet
1002  i = 0;
1003 
1004  //Send as much data as possible
1005  while(1)
1006  {
1007  //Check current sub-state
1008  if(txContext->state == WS_SUB_STATE_INIT)
1009  {
1010  //A fragmented message consists of a single frame with the FIN bit
1011  //clear and an opcode other than 0, followed by zero or more frames
1012  //with the FIN bit clear and the opcode set to 0, and terminated by
1013  //a single frame with the FIN bit set and an opcode of 0
1014  if(!firstFrag)
1016 
1017  //Format WebSocket frame header
1018  error = webSocketFormatFrameHeader(webSocket, lastFrag, type, length - i);
1019 
1020  //Send the frame header
1021  txContext->state = WS_SUB_STATE_FRAME_HEADER;
1022  }
1023  else if(txContext->state == WS_SUB_STATE_FRAME_HEADER)
1024  {
1025  //Any remaining data to be sent?
1026  if(txContext->bufferPos < txContext->bufferLen)
1027  {
1028  //Send more data
1029  error = webSocketSendData(webSocket,
1030  txContext->buffer + txContext->bufferPos,
1031  txContext->bufferLen - txContext->bufferPos, &n, 0);
1032 
1033  //Advance data pointer
1034  txContext->bufferPos += n;
1035  }
1036  else
1037  {
1038  //Flush the transmit buffer
1039  txContext->payloadPos = 0;
1040  txContext->bufferPos = 0;
1041  txContext->bufferLen = 0;
1042 
1043  //Send the payload of the WebSocket frame
1044  txContext->state = WS_SUB_STATE_FRAME_PAYLOAD;
1045  }
1046  }
1047  else if(txContext->state == WS_SUB_STATE_FRAME_PAYLOAD)
1048  {
1049  //Any remaining data to be sent?
1050  if(txContext->bufferPos < txContext->bufferLen)
1051  {
1052  //Send more data
1053  error = webSocketSendData(webSocket,
1054  txContext->buffer + txContext->bufferPos,
1055  txContext->bufferLen - txContext->bufferPos, &n, 0);
1056 
1057  //Advance data pointer
1058  txContext->payloadPos += n;
1059  txContext->bufferPos += n;
1060 
1061  //Total number of data that have been written
1062  i += n;
1063  }
1064  else
1065  {
1066  //Send as much data as possible
1067  if(txContext->payloadPos < txContext->payloadLen)
1068  {
1069  //Calculate the number of bytes that are pending
1070  n = MIN(length - i, txContext->payloadLen - txContext->payloadPos);
1071  //Limit the number of bytes to be copied at a time
1073 
1074  //Copy application data to the transmit buffer
1075  memcpy(txContext->buffer, p, n);
1076 
1077  //All frames sent from the client to the server are masked
1078  if(webSocket->endpoint == WS_ENDPOINT_CLIENT)
1079  {
1080  //Apply masking
1081  for(j = 0; j < n; j++)
1082  {
1083  //Index of the masking key to be applied
1084  k = (txContext->payloadPos + j) % 4;
1085  //Convert unmasked data into masked data
1086  txContext->buffer[j] = p[i + j] ^ txContext->maskingKey[k];
1087  }
1088  }
1089 
1090  //Rewind to the beginning of the buffer
1091  txContext->bufferPos = 0;
1092  //Update the number of data buffered but not yet sent
1093  txContext->bufferLen = n;
1094  }
1095  else
1096  {
1097  //Prepare to send a new WebSocket frame
1098  txContext->state = WS_SUB_STATE_INIT;
1099 
1100  //Write operation complete?
1101  if(i >= length)
1102  break;
1103  }
1104  }
1105  }
1106  else
1107  {
1108  //Invalid state
1109  error = ERROR_WRONG_STATE;
1110  }
1111 
1112  //Any error to report?
1113  if(error)
1114  break;
1115  }
1116 
1117  //Total number of data that have been written
1118  if(written != NULL)
1119  *written = i;
1120 
1121  //Return status code
1122  return error;
1123 }
1124 
1125 
1126 /**
1127  * @brief Receive data from a WebSocket connection
1128  * @param[in] webSocket Handle that identifies a WebSocket
1129  * @param[out] data Buffer where to store the incoming data
1130  * @param[in] size Maximum number of bytes that can be received
1131  * @param[out] type Frame type
1132  * @param[out] received Number of bytes that have been received
1133  * @return Error code
1134  **/
1135 
1137  size_t size, WebSocketFrameType *type, size_t *received)
1138 {
1139  bool_t firstFrag;
1140  bool_t lastFrag;
1141 
1142  return webSocketReceiveEx(webSocket, data, size,
1143  type, received, &firstFrag, &lastFrag);
1144 }
1145 
1146 
1147 /**
1148  * @brief Receive data from a WebSocket connection
1149  * @param[in] webSocket Handle that identifies a WebSocket
1150  * @param[out] data Buffer where to store the incoming data
1151  * @param[in] size Maximum number of bytes that can be received
1152  * @param[out] type Frame type
1153  * @param[out] received Number of bytes that have been received
1154  * @param[out] firstFrag First fragment of the message
1155  * @param[out] lastFrag Last fragment of the message
1156  * @return Error code
1157  **/
1158 
1159 error_t webSocketReceiveEx(WebSocket *webSocket, void *data, size_t size,
1160  WebSocketFrameType *type, size_t *received, bool_t *firstFrag, bool_t *lastFrag)
1161 {
1162  error_t error;
1163  size_t i;
1164  size_t j;
1165  size_t k;
1166  size_t n;
1167  WebSocketFrame *frame;
1168  WebSocketFrameContext *rxContext;
1169 
1170  //Make sure the WebSocket handle is valid
1171  if(webSocket == NULL)
1172  return ERROR_INVALID_PARAMETER;
1173 
1174  //Check the state of the WebSocket connection
1175  if(webSocket->state != WS_STATE_OPEN &&
1176  webSocket->state != WS_STATE_CLOSING_RX)
1177  return ERROR_NOT_CONNECTED;
1178 
1179  //Point to the RX context
1180  rxContext = &webSocket->rxContext;
1181  //Point to the WebSocket frame header
1182  frame = (WebSocketFrame *) rxContext->buffer;
1183 
1184  //Initialize status code
1185  error = NO_ERROR;
1186 
1187  //Initialize flags
1188  if(type != NULL)
1190  if(firstFrag != NULL)
1191  *firstFrag = FALSE;
1192  if(lastFrag != NULL)
1193  *lastFrag = FALSE;
1194 
1195  //No data has been read yet
1196  i = 0;
1197 
1198  //Read as much data as possible
1199  while(i < size)
1200  {
1201  //Check current sub-state
1202  if(rxContext->state == WS_SUB_STATE_INIT)
1203  {
1204  //Flush the receive buffer
1205  rxContext->bufferPos = 0;
1206  rxContext->bufferLen = sizeof(WebSocketFrame);
1207 
1208  //Decode the frame header
1209  rxContext->state = WS_SUB_STATE_FRAME_HEADER;
1210  }
1211  else if(rxContext->state == WS_SUB_STATE_FRAME_HEADER)
1212  {
1213  //Incomplete frame header?
1214  if(rxContext->bufferPos < rxContext->bufferLen)
1215  {
1216  //Read more data
1217  error = webSocketReceiveData(webSocket,
1218  rxContext->buffer + rxContext->bufferPos,
1219  rxContext->bufferLen - rxContext->bufferPos, &n, 0);
1220 
1221  //Advance data pointer
1222  rxContext->bufferPos += n;
1223  }
1224  else
1225  {
1226  //Check the Payload Length field
1227  if(frame->payloadLen == 126)
1228  rxContext->bufferLen += sizeof(uint16_t);
1229  else if(frame->payloadLen == 127)
1230  rxContext->bufferLen += sizeof(uint64_t);
1231 
1232  //Check whether the masking key is present
1233  if(frame->mask)
1234  rxContext->bufferLen += sizeof(uint32_t);
1235 
1236  //The Opcode field defines the interpretation of the payload data
1237  if(frame->opcode == WS_FRAME_TYPE_CLOSE)
1238  {
1239  //All control frames must have a payload length of 125 bytes or less
1240  if(frame->payloadLen <= 125)
1241  {
1242  //Retrieve the length of the WebSocket frame
1243  rxContext->bufferLen += frame->payloadLen;
1244  }
1245  else
1246  {
1247  //Report a protocol error
1248  webSocket->statusCode = WS_STATUS_CODE_PROTOCOL_ERROR;
1249  //Terminate the WebSocket connection
1250  error = ERROR_INVALID_FRAME;
1251  }
1252  }
1253 
1254  //Decode the extended payload length and the masking key, if any
1255  rxContext->state = WS_SUB_STATE_FRAME_EXT_HEADER;
1256  }
1257  }
1258  else if(rxContext->state == WS_SUB_STATE_FRAME_EXT_HEADER)
1259  {
1260  //Incomplete frame header?
1261  if(rxContext->bufferPos < rxContext->bufferLen)
1262  {
1263  //Read more data
1264  error = webSocketReceiveData(webSocket,
1265  rxContext->buffer + rxContext->bufferPos,
1266  rxContext->bufferLen - rxContext->bufferPos, &n, 0);
1267 
1268  //Advance data pointer
1269  rxContext->bufferPos += n;
1270  }
1271  else
1272  {
1273  //Parse the header of the WebSocket frame
1274  error = webSocketParseFrameHeader(webSocket, frame, type);
1275 
1276  //Check status code
1277  if(error == ERROR_UNEXPECTED_MESSAGE)
1278  {
1279  error = NO_ERROR;
1280  break;
1281  }
1282  else if(error == NO_ERROR)
1283  {
1284  if(firstFrag != NULL)
1285  *firstFrag = TRUE;
1286  }
1287 
1288  //Flush the receive buffer
1289  rxContext->payloadPos = 0;
1290  rxContext->bufferPos = 0;
1291  rxContext->bufferLen = 0;
1292 
1293  //Decode the payload of the WebSocket frame
1294  rxContext->state = WS_SUB_STATE_FRAME_PAYLOAD;
1295  }
1296  }
1297  else if(rxContext->state == WS_SUB_STATE_FRAME_PAYLOAD)
1298  {
1299  if(rxContext->payloadPos < rxContext->payloadLen)
1300  {
1301  //Limit the number of bytes to read at a time
1302  n = MIN(size - i, rxContext->payloadLen - rxContext->payloadPos);
1303  //Limit the number of bytes to be copied at a time
1305 
1306  //Read more data
1307  error = webSocketReceiveData(webSocket, rxContext->buffer, n, &n, 0);
1308 
1309  //All frames sent from the client to the server are masked
1310  if(rxContext->mask)
1311  {
1312  //Unmask the data
1313  for(j = 0; j < n; j++)
1314  {
1315  //Index of the masking key to be applied
1316  k = (rxContext->payloadPos + j) % 4;
1317  //Convert masked data into unmasked data
1318  rxContext->buffer[j] ^= rxContext->maskingKey[k];
1319  }
1320  }
1321 
1322  //Text frame?
1323  if(rxContext->dataFrameType == WS_FRAME_TYPE_TEXT &&
1325  {
1326  //Compute the number of remaining data bytes in the UTF-8 stream
1327  if(rxContext->fin)
1328  k = rxContext->payloadLen - rxContext->payloadPos;
1329  else
1330  k = 0;
1331 
1332  //Invalid UTF-8 sequence?
1333  if(!webSocketCheckUtf8Stream(&webSocket->utf8Context,
1334  rxContext->buffer, n, k))
1335  {
1336  //The received data is not consistent with the type of the message
1337  webSocket->statusCode = WS_STATUS_CODE_INVALID_PAYLOAD_DATA;
1338  //The endpoint must fail the WebSocket connection
1339  error = ERROR_INVALID_FRAME;
1340  }
1341  }
1342 
1343  //Sanity check
1344  if(data != NULL)
1345  {
1346  //Copy application data
1347  memcpy((uint8_t *) data + i, rxContext->buffer, n);
1348  }
1349 
1350  //Advance data pointer
1351  rxContext->payloadPos += n;
1352 
1353  //Total number of data that have been read
1354  i += n;
1355  }
1356 
1357  if(rxContext->payloadPos == rxContext->payloadLen)
1358  {
1359  //Decode the next WebSocket frame
1360  rxContext->state = WS_SUB_STATE_INIT;
1361 
1362  //Last fragment of the message?
1363  if(rxContext->fin || rxContext->controlFrameType != WS_FRAME_TYPE_CONTINUATION)
1364  {
1365  if(lastFrag != NULL)
1366  *lastFrag = TRUE;
1367 
1368  //Exit immediately
1369  break;
1370  }
1371  }
1372  }
1373  else
1374  {
1375  //Invalid state
1376  error = ERROR_WRONG_STATE;
1377  }
1378 
1379  //Any error to report?
1380  if(error)
1381  break;
1382  }
1383 
1384  //Check status code
1385  if(!error)
1386  {
1387  //Return the frame type
1388  if(type != NULL)
1389  {
1390  //Control or data frame?
1392  *type = rxContext->controlFrameType;
1393  else
1394  *type = rxContext->dataFrameType;
1395  }
1396  }
1397 
1398  //Return the total number of data that have been read
1399  if(received != NULL)
1400  *received = i;
1401 
1402  //Return status code
1403  return error;
1404 }
1405 
1406 
1407 /**
1408  * @brief Check whether some data is available in the receive buffer
1409  * @param[in] webSocket Handle to a WebSocket
1410  * @return The function returns TRUE if some data is pending and can be read
1411  * immediately without blocking. Otherwise, FALSE is returned
1412  **/
1413 
1415 {
1416  bool_t available = FALSE;
1417 
1418 #if (WEB_SOCKET_TLS_SUPPORT == ENABLED)
1419  //Check whether a secure connection is being used
1420  if(webSocket->tlsContext != NULL)
1421  {
1422  //Check whether some data is pending in the receive buffer
1423  if(webSocket->tlsContext->rxBufferLen > 0)
1424  available = TRUE;
1425  }
1426 #endif
1427 
1428  //The function returns TRUE if some data can be read immediately
1429  //without blocking
1430  return available;
1431 }
1432 
1433 
1434 /**
1435  * @brief Gracefully close a WebSocket connection
1436  * @param[in] webSocket Handle to a WebSocket
1437  **/
1438 
1440 {
1441  error_t error;
1442  size_t n;
1443  WebSocketFrameContext *txContext;
1444 
1445  //Make sure the WebSocket handle is valid
1446  if(webSocket == NULL)
1447  return ERROR_INVALID_PARAMETER;
1448 
1449  //Point to the TX context
1450  txContext = &webSocket->txContext;
1451 
1452  //Initialize status code
1453  error = NO_ERROR;
1454 
1455  //Closing handshake
1456  while(webSocket->state != WS_STATE_CLOSED)
1457  {
1458  //Check current state
1459  if(webSocket->state == WS_STATE_OPEN)
1460  {
1461  //Check whether the latest frame has been completely transmitted
1462  if(txContext->payloadPos == txContext->payloadLen)
1463  {
1464  //Format Close frame
1465  error = webSocketFormatCloseFrame(webSocket);
1466  //Send Close frame
1467  webSocket->state = WS_STATE_CLOSING_TX;
1468  }
1469  else
1470  {
1471  //The WebSocket connection cannot be closed until the
1472  //transmission of the frame is complete...
1473  error = ERROR_FAILURE;
1474  }
1475  }
1476  else if(webSocket->state == WS_STATE_CLOSING_TX)
1477  {
1478  //Any remaining data to be sent?
1479  if(txContext->bufferPos < txContext->bufferLen)
1480  {
1481  //Send more data
1482  error = webSocketSendData(webSocket,
1483  txContext->buffer + txContext->bufferPos,
1484  txContext->bufferLen - txContext->bufferPos, &n, 0);
1485 
1486  //Advance data pointer
1487  txContext->bufferPos += n;
1488  }
1489  else
1490  {
1491  //Check whether a Close frame has been received from the peer
1492  if(webSocket->handshakeContext.closingFrameReceived)
1493  webSocket->state = WS_STATE_SHUTDOWN;
1494  else
1495  webSocket->state = WS_STATE_CLOSING_RX;
1496  }
1497  }
1498  else if(webSocket->state == WS_STATE_CLOSING_RX)
1499  {
1500  //After receiving a control frame indicating the connection should
1501  //be closed, a peer discards any further data received
1502  error = webSocketReceive(webSocket, NULL, WEB_SOCKET_BUFFER_SIZE, NULL, 0);
1503 
1504  //Check status code
1505  if(error == NO_ERROR)
1506  {
1507  //Close frame received?
1508  if(webSocket->handshakeContext.closingFrameReceived)
1509  {
1510  //Properly shutdown the network connection
1511  webSocket->state = WS_STATE_SHUTDOWN;
1512  }
1513  }
1514  else if(error == ERROR_INVALID_FRAME || error == ERROR_END_OF_STREAM)
1515  {
1516  //Catch exception
1517  error = NO_ERROR;
1518  //Properly shutdown the network connection
1519  webSocket->state = WS_STATE_SHUTDOWN;
1520  }
1521  }
1522  else if(webSocket->state == WS_STATE_SHUTDOWN)
1523  {
1524  //Properly dispose the network connection
1525  error = webSocketShutdownConnection(webSocket);
1526 
1527  //Check status code
1528  if(!error)
1529  {
1530  //The connection has been properly closed
1531  webSocket->state = WS_STATE_CLOSED;
1532  }
1533  }
1534  else
1535  {
1536  //Invalid state
1537  error = ERROR_WRONG_STATE;
1538  }
1539 
1540  //Any error to report?
1541  if(error)
1542  break;
1543  }
1544 
1545  //Return status code
1546  return error;
1547 }
1548 
1549 
1550 /**
1551  * @brief Close a WebSocket connection
1552  * @param[in] webSocket Handle identifying the WebSocket to close
1553  **/
1554 
1555 void webSocketClose(WebSocket *webSocket)
1556 {
1557  //Make sure the WebSocket handle is valid
1558  if(webSocket != NULL)
1559  {
1560  //Close connection
1561  webSocketCloseConnection(webSocket);
1562 
1563 #if (WEB_SOCKET_TLS_SUPPORT == ENABLED)
1564  //Release TLS session state
1565  tlsFreeSessionState(&webSocket->tlsSession);
1566 #endif
1567 
1568  //Release the WebSocket
1570  }
1571 }
1572 
1573 #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: dtls_misc.h:149
String manipulation helper functions.
int bool_t
Definition: compiler_port.h:49
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:1136
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:95
#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:71
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:192
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: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.
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 @300 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:951
@ ERROR_AUTH_REQUIRED
Definition: error.h:148
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:876
#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:208
#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:2711
@ ERROR_PRNG_NOT_READY
Definition: error.h:245
@ 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:207
@ WS_AUTH_MODE_BASIC
Definition: web_socket.h:215
@ ERROR_OPEN_FAILED
Definition: error.h:74
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: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:380
@ ERROR_INVALID_FRAME
Definition: error.h:85
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:42
Frame encoding/decoding context.
Definition: web_socket.h:394
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:658
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:1159
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:108
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:262
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:972
char_t username[WEB_SOCKET_USERNAME_MAX_LEN+1]
Definition: web_socket.h:358
@ ERROR_INVALID_LENGTH
Definition: error.h:109
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
OsMutex netMutex
Definition: net.c:75
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:724
#define MIN(a, b)
Definition: os_port.h:62
@ WS_ENDPOINT_CLIENT
Definition: web_socket.h:191
#define WebSocket
Definition: web_socket.h:177
Authentication context.
Definition: web_socket.h:353
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
@ WS_SUB_STATE_INIT
Definition: web_socket.h:246
@ ERROR_TIMEOUT
Definition: error.h:94
char char_t
Definition: compiler_port.h:43
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:167
#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:79
@ 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:1414
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:1555
@ 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:813
@ 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:1439
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:45
TCP/IP stack core.
@ WS_HTTP_VERSION_1_1
Definition: web_socket.h:204
uint8_t data[]
Definition: dtls_misc.h:176
#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:2406
error_t socketSetTimeout(Socket *socket, systime_t timeout)
Set timeout value for blocking operations.
Definition: socket.c:219
error_t tlsConnect(TlsContext *context)
Initiate the TLS handshake.
Definition: tls.c:1572
uint32_t systime_t
Definition: compiler_port.h:46
#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:74
void webSocketChangeState(WebSocket *webSocket, WebSocketState newState)
Update WebSocket state.