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