WebSocketsServer.h 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /**
  2. * @file WebSocketsServer.h
  3. * @date 20.05.2015
  4. * @author Markus Sattler
  5. *
  6. * Copyright (c) 2015 Markus Sattler. All rights reserved.
  7. * This file is part of the WebSockets for Arduino.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation; either
  12. * version 2.1 of the License, or (at your option) any later version.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. */
  24. #ifndef WEBSOCKETSSERVER_H_
  25. #define WEBSOCKETSSERVER_H_
  26. #include "WebSockets.h"
  27. #ifndef WEBSOCKETS_SERVER_CLIENT_MAX
  28. #define WEBSOCKETS_SERVER_CLIENT_MAX (5)
  29. #endif
  30. class WebSocketsServerCore : protected WebSockets {
  31. public:
  32. WebSocketsServerCore(const String & origin = "", const String & protocol = "arduino");
  33. virtual ~WebSocketsServerCore(void);
  34. void begin(void);
  35. void close(void);
  36. #ifdef __AVR__
  37. typedef void (*WebSocketServerEvent)(uint8_t num, WStype_t type, uint8_t * payload, size_t length);
  38. typedef bool (*WebSocketServerHttpHeaderValFunc)(String headerName, String headerValue);
  39. #else
  40. typedef std::function<void(uint8_t num, WStype_t type, uint8_t * payload, size_t length)> WebSocketServerEvent;
  41. typedef std::function<bool(String headerName, String headerValue)> WebSocketServerHttpHeaderValFunc;
  42. #endif
  43. void onEvent(WebSocketServerEvent cbEvent);
  44. void onValidateHttpHeader(
  45. WebSocketServerHttpHeaderValFunc validationFunc,
  46. const char * mandatoryHttpHeaders[],
  47. size_t mandatoryHttpHeaderCount);
  48. bool sendTXT(uint8_t num, uint8_t * payload, size_t length = 0, bool headerToPayload = false);
  49. bool sendTXT(uint8_t num, const uint8_t * payload, size_t length = 0);
  50. bool sendTXT(uint8_t num, char * payload, size_t length = 0, bool headerToPayload = false);
  51. bool sendTXT(uint8_t num, const char * payload, size_t length = 0);
  52. bool sendTXT(uint8_t num, String & payload);
  53. bool broadcastTXT(uint8_t * payload, size_t length = 0, bool headerToPayload = false);
  54. bool broadcastTXT(const uint8_t * payload, size_t length = 0);
  55. bool broadcastTXT(char * payload, size_t length = 0, bool headerToPayload = false);
  56. bool broadcastTXT(const char * payload, size_t length = 0);
  57. bool broadcastTXT(String & payload);
  58. bool sendBIN(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload = false);
  59. bool sendBIN(uint8_t num, const uint8_t * payload, size_t length);
  60. bool broadcastBIN(uint8_t * payload, size_t length, bool headerToPayload = false);
  61. bool broadcastBIN(const uint8_t * payload, size_t length);
  62. bool sendPing(uint8_t num, uint8_t * payload = NULL, size_t length = 0);
  63. bool sendPing(uint8_t num, String & payload);
  64. bool broadcastPing(uint8_t * payload = NULL, size_t length = 0);
  65. bool broadcastPing(String & payload);
  66. void disconnect(void);
  67. void disconnect(uint8_t num);
  68. void setAuthorization(const char * user, const char * password);
  69. void setAuthorization(const char * auth);
  70. int connectedClients(bool ping = false);
  71. bool clientIsConnected(uint8_t num);
  72. void enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount);
  73. void disableHeartbeat();
  74. #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
  75. IPAddress remoteIP(uint8_t num);
  76. #endif
  77. #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
  78. void loop(void); // handle client data only
  79. #endif
  80. WSclient_t * newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient);
  81. protected:
  82. String _origin;
  83. String _protocol;
  84. String _base64Authorization; ///< Base64 encoded Auth request
  85. String * _mandatoryHttpHeaders;
  86. size_t _mandatoryHttpHeaderCount;
  87. WSclient_t _clients[WEBSOCKETS_SERVER_CLIENT_MAX];
  88. WebSocketServerEvent _cbEvent;
  89. WebSocketServerHttpHeaderValFunc _httpHeaderValidationFunc;
  90. bool _runnning;
  91. uint32_t _pingInterval;
  92. uint32_t _pongTimeout;
  93. uint8_t _disconnectTimeoutCount;
  94. void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin);
  95. void clientDisconnect(WSclient_t * client);
  96. bool clientIsConnected(WSclient_t * client);
  97. #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
  98. void handleClientData(void);
  99. #endif
  100. void handleHeader(WSclient_t * client, String * headerLine);
  101. void handleHBPing(WSclient_t * client); // send ping in specified intervals
  102. /**
  103. * called if a non Websocket connection is coming in.
  104. * Note: can be override
  105. * @param client WSclient_t * ptr to the client struct
  106. */
  107. virtual void handleNonWebsocketConnection(WSclient_t * client) {
  108. DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] no Websocket connection close.\n", client->num);
  109. client->tcp->write(
  110. "HTTP/1.1 400 Bad Request\r\n"
  111. "Server: arduino-WebSocket-Server\r\n"
  112. "Content-Type: text/plain\r\n"
  113. "Content-Length: 32\r\n"
  114. "Connection: close\r\n"
  115. "Sec-WebSocket-Version: 13\r\n"
  116. "\r\n"
  117. "This is a Websocket server only!");
  118. clientDisconnect(client);
  119. }
  120. /**
  121. * called if a non Authorization connection is coming in.
  122. * Note: can be override
  123. * @param client WSclient_t * ptr to the client struct
  124. */
  125. virtual void handleAuthorizationFailed(WSclient_t * client) {
  126. client->tcp->write(
  127. "HTTP/1.1 401 Unauthorized\r\n"
  128. "Server: arduino-WebSocket-Server\r\n"
  129. "Content-Type: text/plain\r\n"
  130. "Content-Length: 45\r\n"
  131. "Connection: close\r\n"
  132. "Sec-WebSocket-Version: 13\r\n"
  133. "WWW-Authenticate: Basic realm=\"WebSocket Server\""
  134. "\r\n"
  135. "This Websocket server requires Authorization!");
  136. clientDisconnect(client);
  137. }
  138. /**
  139. * called for sending a Event to the app
  140. * @param num uint8_t
  141. * @param type WStype_t
  142. * @param payload uint8_t *
  143. * @param length size_t
  144. */
  145. virtual void runCbEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
  146. if(_cbEvent) {
  147. _cbEvent(num, type, payload, length);
  148. }
  149. }
  150. /*
  151. * Called at client socket connect handshake negotiation time for each http header that is not
  152. * a websocket specific http header (not Connection, Upgrade, Sec-WebSocket-*)
  153. * If the custom httpHeaderValidationFunc returns false for any headerName / headerValue passed, the
  154. * socket negotiation is considered invalid and the upgrade to websockets request is denied / rejected
  155. * This mechanism can be used to enable custom authentication schemes e.g. test the value
  156. * of a session cookie to determine if a user is logged on / authenticated
  157. */
  158. virtual bool execHttpHeaderValidation(String headerName, String headerValue) {
  159. if(_httpHeaderValidationFunc) {
  160. //return the value of the custom http header validation function
  161. return _httpHeaderValidationFunc(headerName, headerValue);
  162. }
  163. //no custom http header validation so just assume all is good
  164. return true;
  165. }
  166. #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
  167. WSclient_t * handleNewClient(WEBSOCKETS_NETWORK_CLASS * tcpClient);
  168. #endif
  169. /**
  170. * drop native tcp connection (client->tcp)
  171. */
  172. void dropNativeClient(WSclient_t * client);
  173. private:
  174. /*
  175. * returns an indicator whether the given named header exists in the configured _mandatoryHttpHeaders collection
  176. * @param headerName String ///< the name of the header being checked
  177. */
  178. bool hasMandatoryHeader(String headerName);
  179. };
  180. class WebSocketsServer : public WebSocketsServerCore {
  181. public:
  182. WebSocketsServer(uint16_t port, const String & origin = "", const String & protocol = "arduino");
  183. virtual ~WebSocketsServer(void);
  184. void begin(void);
  185. void close(void);
  186. #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
  187. void loop(void); // handle incoming client and client data
  188. #else
  189. // Async interface not need a loop call
  190. void loop(void) __attribute__((deprecated)) {}
  191. #endif
  192. protected:
  193. #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
  194. void handleNewClients(void);
  195. #endif
  196. uint16_t _port;
  197. WEBSOCKETS_NETWORK_SERVER_CLASS * _server;
  198. };
  199. #endif /* WEBSOCKETSSERVER_H_ */