WebSocketsServer.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948
  1. /**
  2. * @file WebSocketsServer.cpp
  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. #include "WebSockets.h"
  25. #include "WebSocketsServer.h"
  26. WebSocketsServerCore::WebSocketsServerCore(const String & origin, const String & protocol) {
  27. _origin = origin;
  28. _protocol = protocol;
  29. _runnning = false;
  30. _pingInterval = 0;
  31. _pongTimeout = 0;
  32. _disconnectTimeoutCount = 0;
  33. _cbEvent = NULL;
  34. _httpHeaderValidationFunc = NULL;
  35. _mandatoryHttpHeaders = NULL;
  36. _mandatoryHttpHeaderCount = 0;
  37. }
  38. WebSocketsServer::WebSocketsServer(uint16_t port, const String & origin, const String & protocol)
  39. : WebSocketsServerCore(origin, protocol) {
  40. _port = port;
  41. _server = new WEBSOCKETS_NETWORK_SERVER_CLASS(port);
  42. #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
  43. _server->onClient([](void * s, AsyncClient * c) {
  44. ((WebSocketsServerCore *)s)->newClient(new AsyncTCPbuffer(c));
  45. },
  46. this);
  47. #endif
  48. }
  49. WebSocketsServerCore::~WebSocketsServerCore() {
  50. // disconnect all clients
  51. close();
  52. if(_mandatoryHttpHeaders)
  53. delete[] _mandatoryHttpHeaders;
  54. _mandatoryHttpHeaderCount = 0;
  55. }
  56. WebSocketsServer::~WebSocketsServer() {
  57. }
  58. /**
  59. * called to initialize the Websocket server
  60. */
  61. void WebSocketsServerCore::begin(void) {
  62. // adjust clients storage:
  63. // _clients[i]'s constructor are already called,
  64. // all its members are initialized to their default value,
  65. // except the ones explicitly detailed in WSclient_t() constructor.
  66. // Then we need to initialize some members to non-trivial values:
  67. for(int i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
  68. _clients[i].init(i, _pingInterval, _pongTimeout, _disconnectTimeoutCount);
  69. }
  70. #ifdef ESP8266
  71. randomSeed(RANDOM_REG32);
  72. #elif defined(ESP32)
  73. #define DR_REG_RNG_BASE 0x3ff75144
  74. randomSeed(READ_PERI_REG(DR_REG_RNG_BASE));
  75. #else
  76. // TODO find better seed
  77. randomSeed(millis());
  78. #endif
  79. _runnning = true;
  80. DEBUG_WEBSOCKETS("[WS-Server] Websocket Version: " WEBSOCKETS_VERSION "\n");
  81. }
  82. void WebSocketsServerCore::close(void) {
  83. _runnning = false;
  84. disconnect();
  85. // restore _clients[] to their initial state
  86. // before next call to ::begin()
  87. for(int i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
  88. _clients[i] = WSclient_t();
  89. }
  90. }
  91. /**
  92. * set callback function
  93. * @param cbEvent WebSocketServerEvent
  94. */
  95. void WebSocketsServerCore::onEvent(WebSocketServerEvent cbEvent) {
  96. _cbEvent = cbEvent;
  97. }
  98. /*
  99. * Sets the custom http header validator function
  100. * @param httpHeaderValidationFunc WebSocketServerHttpHeaderValFunc ///< pointer to the custom http header validation function
  101. * @param mandatoryHttpHeaders[] const char* ///< the array of named http headers considered to be mandatory / must be present in order for websocket upgrade to succeed
  102. * @param mandatoryHttpHeaderCount size_t ///< the number of items in the mandatoryHttpHeaders array
  103. */
  104. void WebSocketsServerCore::onValidateHttpHeader(
  105. WebSocketServerHttpHeaderValFunc validationFunc,
  106. const char * mandatoryHttpHeaders[],
  107. size_t mandatoryHttpHeaderCount) {
  108. _httpHeaderValidationFunc = validationFunc;
  109. if(_mandatoryHttpHeaders)
  110. delete[] _mandatoryHttpHeaders;
  111. _mandatoryHttpHeaderCount = mandatoryHttpHeaderCount;
  112. _mandatoryHttpHeaders = new String[_mandatoryHttpHeaderCount];
  113. for(size_t i = 0; i < _mandatoryHttpHeaderCount; i++) {
  114. _mandatoryHttpHeaders[i] = mandatoryHttpHeaders[i];
  115. }
  116. }
  117. /*
  118. * send text data to client
  119. * @param num uint8_t client id
  120. * @param payload uint8_t *
  121. * @param length size_t
  122. * @param headerToPayload bool (see sendFrame for more details)
  123. * @return true if ok
  124. */
  125. bool WebSocketsServerCore::sendTXT(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload) {
  126. if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
  127. return false;
  128. }
  129. if(length == 0) {
  130. length = strlen((const char *)payload);
  131. }
  132. WSclient_t * client = &_clients[num];
  133. if(clientIsConnected(client)) {
  134. return sendFrame(client, WSop_text, payload, length, true, headerToPayload);
  135. }
  136. return false;
  137. }
  138. bool WebSocketsServerCore::sendTXT(uint8_t num, const uint8_t * payload, size_t length) {
  139. return sendTXT(num, (uint8_t *)payload, length);
  140. }
  141. bool WebSocketsServerCore::sendTXT(uint8_t num, char * payload, size_t length, bool headerToPayload) {
  142. return sendTXT(num, (uint8_t *)payload, length, headerToPayload);
  143. }
  144. bool WebSocketsServerCore::sendTXT(uint8_t num, const char * payload, size_t length) {
  145. return sendTXT(num, (uint8_t *)payload, length);
  146. }
  147. bool WebSocketsServerCore::sendTXT(uint8_t num, String & payload) {
  148. return sendTXT(num, (uint8_t *)payload.c_str(), payload.length());
  149. }
  150. /**
  151. * send text data to client all
  152. * @param payload uint8_t *
  153. * @param length size_t
  154. * @param headerToPayload bool (see sendFrame for more details)
  155. * @return true if ok
  156. */
  157. bool WebSocketsServerCore::broadcastTXT(uint8_t * payload, size_t length, bool headerToPayload) {
  158. WSclient_t * client;
  159. bool ret = true;
  160. if(length == 0) {
  161. length = strlen((const char *)payload);
  162. }
  163. for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
  164. client = &_clients[i];
  165. if(clientIsConnected(client)) {
  166. if(!sendFrame(client, WSop_text, payload, length, true, headerToPayload)) {
  167. ret = false;
  168. }
  169. }
  170. WEBSOCKETS_YIELD();
  171. }
  172. return ret;
  173. }
  174. bool WebSocketsServerCore::broadcastTXT(const uint8_t * payload, size_t length) {
  175. return broadcastTXT((uint8_t *)payload, length);
  176. }
  177. bool WebSocketsServerCore::broadcastTXT(char * payload, size_t length, bool headerToPayload) {
  178. return broadcastTXT((uint8_t *)payload, length, headerToPayload);
  179. }
  180. bool WebSocketsServerCore::broadcastTXT(const char * payload, size_t length) {
  181. return broadcastTXT((uint8_t *)payload, length);
  182. }
  183. bool WebSocketsServerCore::broadcastTXT(String & payload) {
  184. return broadcastTXT((uint8_t *)payload.c_str(), payload.length());
  185. }
  186. /**
  187. * send binary data to client
  188. * @param num uint8_t client id
  189. * @param payload uint8_t *
  190. * @param length size_t
  191. * @param headerToPayload bool (see sendFrame for more details)
  192. * @return true if ok
  193. */
  194. bool WebSocketsServerCore::sendBIN(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload) {
  195. if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
  196. return false;
  197. }
  198. WSclient_t * client = &_clients[num];
  199. if(clientIsConnected(client)) {
  200. return sendFrame(client, WSop_binary, payload, length, true, headerToPayload);
  201. }
  202. return false;
  203. }
  204. bool WebSocketsServerCore::sendBIN(uint8_t num, const uint8_t * payload, size_t length) {
  205. return sendBIN(num, (uint8_t *)payload, length);
  206. }
  207. /**
  208. * send binary data to client all
  209. * @param payload uint8_t *
  210. * @param length size_t
  211. * @param headerToPayload bool (see sendFrame for more details)
  212. * @return true if ok
  213. */
  214. bool WebSocketsServerCore::broadcastBIN(uint8_t * payload, size_t length, bool headerToPayload) {
  215. WSclient_t * client;
  216. bool ret = true;
  217. for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
  218. client = &_clients[i];
  219. if(clientIsConnected(client)) {
  220. if(!sendFrame(client, WSop_binary, payload, length, true, headerToPayload)) {
  221. ret = false;
  222. }
  223. }
  224. WEBSOCKETS_YIELD();
  225. }
  226. return ret;
  227. }
  228. bool WebSocketsServerCore::broadcastBIN(const uint8_t * payload, size_t length) {
  229. return broadcastBIN((uint8_t *)payload, length);
  230. }
  231. /**
  232. * sends a WS ping to Client
  233. * @param num uint8_t client id
  234. * @param payload uint8_t *
  235. * @param length size_t
  236. * @return true if ping is send out
  237. */
  238. bool WebSocketsServerCore::sendPing(uint8_t num, uint8_t * payload, size_t length) {
  239. if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
  240. return false;
  241. }
  242. WSclient_t * client = &_clients[num];
  243. if(clientIsConnected(client)) {
  244. return sendFrame(client, WSop_ping, payload, length);
  245. }
  246. return false;
  247. }
  248. bool WebSocketsServerCore::sendPing(uint8_t num, String & payload) {
  249. return sendPing(num, (uint8_t *)payload.c_str(), payload.length());
  250. }
  251. /**
  252. * sends a WS ping to all Client
  253. * @param payload uint8_t *
  254. * @param length size_t
  255. * @return true if ping is send out
  256. */
  257. bool WebSocketsServerCore::broadcastPing(uint8_t * payload, size_t length) {
  258. WSclient_t * client;
  259. bool ret = true;
  260. for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
  261. client = &_clients[i];
  262. if(clientIsConnected(client)) {
  263. if(!sendFrame(client, WSop_ping, payload, length)) {
  264. ret = false;
  265. }
  266. }
  267. WEBSOCKETS_YIELD();
  268. }
  269. return ret;
  270. }
  271. bool WebSocketsServerCore::broadcastPing(String & payload) {
  272. return broadcastPing((uint8_t *)payload.c_str(), payload.length());
  273. }
  274. /**
  275. * disconnect all clients
  276. */
  277. void WebSocketsServerCore::disconnect(void) {
  278. WSclient_t * client;
  279. for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
  280. client = &_clients[i];
  281. if(clientIsConnected(client)) {
  282. WebSockets::clientDisconnect(client, 1000);
  283. }
  284. }
  285. }
  286. /**
  287. * disconnect one client
  288. * @param num uint8_t client id
  289. */
  290. void WebSocketsServerCore::disconnect(uint8_t num) {
  291. if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
  292. return;
  293. }
  294. WSclient_t * client = &_clients[num];
  295. if(clientIsConnected(client)) {
  296. WebSockets::clientDisconnect(client, 1000);
  297. }
  298. }
  299. /*
  300. * set the Authorization for the http request
  301. * @param user const char *
  302. * @param password const char *
  303. */
  304. void WebSocketsServerCore::setAuthorization(const char * user, const char * password) {
  305. if(user && password) {
  306. String auth = user;
  307. auth += ":";
  308. auth += password;
  309. _base64Authorization = base64_encode((uint8_t *)auth.c_str(), auth.length());
  310. }
  311. }
  312. /**
  313. * set the Authorizatio for the http request
  314. * @param auth const char * base64
  315. */
  316. void WebSocketsServerCore::setAuthorization(const char * auth) {
  317. if(auth) {
  318. _base64Authorization = auth;
  319. }
  320. }
  321. /**
  322. * count the connected clients (optional ping them)
  323. * @param ping bool ping the connected clients
  324. */
  325. int WebSocketsServerCore::connectedClients(bool ping) {
  326. WSclient_t * client;
  327. int count = 0;
  328. for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
  329. client = &_clients[i];
  330. if(client->status == WSC_CONNECTED) {
  331. if(ping != true || sendPing(i)) {
  332. count++;
  333. }
  334. }
  335. }
  336. return count;
  337. }
  338. /**
  339. * see if one client is connected
  340. * @param num uint8_t client id
  341. */
  342. bool WebSocketsServerCore::clientIsConnected(uint8_t num) {
  343. if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
  344. return false;
  345. }
  346. WSclient_t * client = &_clients[num];
  347. return clientIsConnected(client);
  348. }
  349. #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
  350. /**
  351. * get an IP for a client
  352. * @param num uint8_t client id
  353. * @return IPAddress
  354. */
  355. IPAddress WebSocketsServerCore::remoteIP(uint8_t num) {
  356. if(num < WEBSOCKETS_SERVER_CLIENT_MAX) {
  357. WSclient_t * client = &_clients[num];
  358. if(clientIsConnected(client)) {
  359. return client->tcp->remoteIP();
  360. }
  361. }
  362. return IPAddress();
  363. }
  364. #endif
  365. //#################################################################################
  366. //#################################################################################
  367. //#################################################################################
  368. /**
  369. * handle new client connection
  370. * @param client
  371. */
  372. WSclient_t * WebSocketsServerCore::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient) {
  373. WSclient_t * client;
  374. // search free list entry for client
  375. for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
  376. client = &_clients[i];
  377. // state is not connected or tcp connection is lost
  378. if(!clientIsConnected(client)) {
  379. client->tcp = TCPclient;
  380. #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
  381. client->isSSL = false;
  382. client->tcp->setNoDelay(true);
  383. #endif
  384. #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
  385. // set Timeout for readBytesUntil and readStringUntil
  386. client->tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT);
  387. #endif
  388. client->status = WSC_HEADER;
  389. #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
  390. #ifndef NODEBUG_WEBSOCKETS
  391. IPAddress ip = client->tcp->remoteIP();
  392. #endif
  393. DEBUG_WEBSOCKETS("[WS-Server][%d] new client from %d.%d.%d.%d\n", client->num, ip[0], ip[1], ip[2], ip[3]);
  394. #else
  395. DEBUG_WEBSOCKETS("[WS-Server][%d] new client\n", client->num);
  396. #endif
  397. #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
  398. client->tcp->onDisconnect(std::bind([](WebSocketsServerCore * server, AsyncTCPbuffer * obj, WSclient_t * client) -> bool {
  399. DEBUG_WEBSOCKETS("[WS-Server][%d] Disconnect client\n", client->num);
  400. AsyncTCPbuffer ** sl = &server->_clients[client->num].tcp;
  401. if(*sl == obj) {
  402. client->status = WSC_NOT_CONNECTED;
  403. *sl = NULL;
  404. }
  405. return true;
  406. },
  407. this, std::placeholders::_1, client));
  408. client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsServerCore::handleHeader, this, client, &(client->cHttpLine)));
  409. #endif
  410. client->pingInterval = _pingInterval;
  411. client->pongTimeout = _pongTimeout;
  412. client->disconnectTimeoutCount = _disconnectTimeoutCount;
  413. client->lastPing = millis();
  414. client->pongReceived = false;
  415. return client;
  416. break;
  417. }
  418. }
  419. return nullptr;
  420. }
  421. /**
  422. *
  423. * @param client WSclient_t * ptr to the client struct
  424. * @param opcode WSopcode_t
  425. * @param payload uint8_t *
  426. * @param length size_t
  427. */
  428. void WebSocketsServerCore::messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin) {
  429. WStype_t type = WStype_ERROR;
  430. switch(opcode) {
  431. case WSop_text:
  432. type = fin ? WStype_TEXT : WStype_FRAGMENT_TEXT_START;
  433. break;
  434. case WSop_binary:
  435. type = fin ? WStype_BIN : WStype_FRAGMENT_BIN_START;
  436. break;
  437. case WSop_continuation:
  438. type = fin ? WStype_FRAGMENT_FIN : WStype_FRAGMENT;
  439. break;
  440. case WSop_ping:
  441. type = WStype_PING;
  442. break;
  443. case WSop_pong:
  444. type = WStype_PONG;
  445. break;
  446. case WSop_close:
  447. default:
  448. break;
  449. }
  450. runCbEvent(client->num, type, payload, length);
  451. }
  452. /**
  453. * Discard a native client
  454. * @param client WSclient_t * ptr to the client struct contaning the native client "->tcp"
  455. */
  456. void WebSocketsServerCore::dropNativeClient(WSclient_t * client) {
  457. if(client->tcp) {
  458. if(client->tcp->connected()) {
  459. #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) && (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP32)
  460. client->tcp->flush();
  461. #endif
  462. client->tcp->stop();
  463. }
  464. #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
  465. client->status = WSC_NOT_CONNECTED;
  466. #else
  467. delete client->tcp;
  468. #endif
  469. client->tcp = NULL;
  470. }
  471. }
  472. /**
  473. * Disconnect an client
  474. * @param client WSclient_t * ptr to the client struct
  475. */
  476. void WebSocketsServerCore::clientDisconnect(WSclient_t * client) {
  477. #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
  478. if(client->isSSL && client->ssl) {
  479. if(client->ssl->connected()) {
  480. client->ssl->flush();
  481. client->ssl->stop();
  482. }
  483. delete client->ssl;
  484. client->ssl = NULL;
  485. client->tcp = NULL;
  486. }
  487. #endif
  488. dropNativeClient(client);
  489. client->cUrl = "";
  490. client->cKey = "";
  491. client->cProtocol = "";
  492. client->cVersion = 0;
  493. client->cIsUpgrade = false;
  494. client->cIsWebsocket = false;
  495. client->cWsRXsize = 0;
  496. #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
  497. client->cHttpLine = "";
  498. #endif
  499. client->status = WSC_NOT_CONNECTED;
  500. DEBUG_WEBSOCKETS("[WS-Server][%d] client disconnected.\n", client->num);
  501. runCbEvent(client->num, WStype_DISCONNECTED, NULL, 0);
  502. }
  503. /**
  504. * get client state
  505. * @param client WSclient_t * ptr to the client struct
  506. * @return true = connected
  507. */
  508. bool WebSocketsServerCore::clientIsConnected(WSclient_t * client) {
  509. if(!client->tcp) {
  510. return false;
  511. }
  512. if(client->tcp->connected()) {
  513. if(client->status != WSC_NOT_CONNECTED) {
  514. return true;
  515. }
  516. } else {
  517. // client lost
  518. if(client->status != WSC_NOT_CONNECTED) {
  519. DEBUG_WEBSOCKETS("[WS-Server][%d] client connection lost.\n", client->num);
  520. // do cleanup
  521. clientDisconnect(client);
  522. }
  523. }
  524. if(client->tcp) {
  525. // do cleanup
  526. DEBUG_WEBSOCKETS("[WS-Server][%d] client list cleanup.\n", client->num);
  527. clientDisconnect(client);
  528. }
  529. return false;
  530. }
  531. #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
  532. /**
  533. * Handle incoming Connection Request
  534. */
  535. WSclient_t * WebSocketsServerCore::handleNewClient(WEBSOCKETS_NETWORK_CLASS * tcpClient) {
  536. WSclient_t * client = newClient(tcpClient);
  537. if(!client) {
  538. // no free space to handle client
  539. #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
  540. #ifndef NODEBUG_WEBSOCKETS
  541. IPAddress ip = tcpClient->remoteIP();
  542. #endif
  543. DEBUG_WEBSOCKETS("[WS-Server] no free space new client from %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
  544. #else
  545. DEBUG_WEBSOCKETS("[WS-Server] no free space new client\n");
  546. #endif
  547. dropNativeClient(client);
  548. }
  549. WEBSOCKETS_YIELD();
  550. return client;
  551. }
  552. /**
  553. * Handle incoming Connection Request
  554. */
  555. void WebSocketsServer::handleNewClients(void) {
  556. #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
  557. while(_server->hasClient()) {
  558. #endif
  559. // store new connection
  560. WEBSOCKETS_NETWORK_CLASS * tcpClient = new WEBSOCKETS_NETWORK_CLASS(_server->available());
  561. if(!tcpClient) {
  562. DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!");
  563. return;
  564. }
  565. handleNewClient(tcpClient);
  566. #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
  567. }
  568. #endif
  569. }
  570. /**
  571. * Handel incomming data from Client
  572. */
  573. void WebSocketsServerCore::handleClientData(void) {
  574. WSclient_t * client;
  575. for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
  576. client = &_clients[i];
  577. if(clientIsConnected(client)) {
  578. int len = client->tcp->available();
  579. if(len > 0) {
  580. //DEBUG_WEBSOCKETS("[WS-Server][%d][handleClientData] len: %d\n", client->num, len);
  581. switch(client->status) {
  582. case WSC_HEADER: {
  583. String headerLine = client->tcp->readStringUntil('\n');
  584. handleHeader(client, &headerLine);
  585. } break;
  586. case WSC_CONNECTED:
  587. WebSockets::handleWebsocket(client);
  588. break;
  589. default:
  590. DEBUG_WEBSOCKETS("[WS-Server][%d][handleClientData] unknown client status %d\n", client->num, client->status);
  591. WebSockets::clientDisconnect(client, 1002);
  592. break;
  593. }
  594. }
  595. handleHBPing(client);
  596. handleHBTimeout(client);
  597. }
  598. WEBSOCKETS_YIELD();
  599. }
  600. }
  601. #endif
  602. /*
  603. * returns an indicator whether the given named header exists in the configured _mandatoryHttpHeaders collection
  604. * @param headerName String ///< the name of the header being checked
  605. */
  606. bool WebSocketsServerCore::hasMandatoryHeader(String headerName) {
  607. for(size_t i = 0; i < _mandatoryHttpHeaderCount; i++) {
  608. if(_mandatoryHttpHeaders[i].equalsIgnoreCase(headerName))
  609. return true;
  610. }
  611. return false;
  612. }
  613. /**
  614. * handles http header reading for WebSocket upgrade
  615. * @param client WSclient_t * ///< pointer to the client struct
  616. * @param headerLine String ///< the header being read / processed
  617. */
  618. void WebSocketsServerCore::handleHeader(WSclient_t * client, String * headerLine) {
  619. static const char * NEW_LINE = "\r\n";
  620. headerLine->trim(); // remove \r
  621. if(headerLine->length() > 0) {
  622. DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] RX: %s\n", client->num, headerLine->c_str());
  623. // websocket requests always start with GET see rfc6455
  624. if(headerLine->startsWith("GET ")) {
  625. // cut URL out
  626. client->cUrl = headerLine->substring(4, headerLine->indexOf(' ', 4));
  627. //reset non-websocket http header validation state for this client
  628. client->cHttpHeadersValid = true;
  629. client->cMandatoryHeadersCount = 0;
  630. } else if(headerLine->indexOf(':') >= 0) {
  631. String headerName = headerLine->substring(0, headerLine->indexOf(':'));
  632. String headerValue = headerLine->substring(headerLine->indexOf(':') + 1);
  633. // remove space in the beginning (RFC2616)
  634. if(headerValue[0] == ' ') {
  635. headerValue.remove(0, 1);
  636. }
  637. if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Connection"))) {
  638. headerValue.toLowerCase();
  639. if(headerValue.indexOf(WEBSOCKETS_STRING("upgrade")) >= 0) {
  640. client->cIsUpgrade = true;
  641. }
  642. } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Upgrade"))) {
  643. if(headerValue.equalsIgnoreCase(WEBSOCKETS_STRING("websocket"))) {
  644. client->cIsWebsocket = true;
  645. }
  646. } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Version"))) {
  647. client->cVersion = headerValue.toInt();
  648. } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Key"))) {
  649. client->cKey = headerValue;
  650. client->cKey.trim(); // see rfc6455
  651. } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Protocol"))) {
  652. client->cProtocol = headerValue;
  653. } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Extensions"))) {
  654. client->cExtensions = headerValue;
  655. } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Authorization"))) {
  656. client->base64Authorization = headerValue;
  657. } else {
  658. client->cHttpHeadersValid &= execHttpHeaderValidation(headerName, headerValue);
  659. if(_mandatoryHttpHeaderCount > 0 && hasMandatoryHeader(headerName)) {
  660. client->cMandatoryHeadersCount++;
  661. }
  662. }
  663. } else {
  664. DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header error (%s)\n", headerLine->c_str());
  665. }
  666. (*headerLine) = "";
  667. #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
  668. client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsServerCore::handleHeader, this, client, &(client->cHttpLine)));
  669. #endif
  670. } else {
  671. DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] Header read fin.\n", client->num);
  672. DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cURL: %s\n", client->num, client->cUrl.c_str());
  673. DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cIsUpgrade: %d\n", client->num, client->cIsUpgrade);
  674. DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cIsWebsocket: %d\n", client->num, client->cIsWebsocket);
  675. DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cKey: %s\n", client->num, client->cKey.c_str());
  676. DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cProtocol: %s\n", client->num, client->cProtocol.c_str());
  677. DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cExtensions: %s\n", client->num, client->cExtensions.c_str());
  678. DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cVersion: %d\n", client->num, client->cVersion);
  679. DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - base64Authorization: %s\n", client->num, client->base64Authorization.c_str());
  680. DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cHttpHeadersValid: %d\n", client->num, client->cHttpHeadersValid);
  681. DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cMandatoryHeadersCount: %d\n", client->num, client->cMandatoryHeadersCount);
  682. bool ok = (client->cIsUpgrade && client->cIsWebsocket);
  683. if(ok) {
  684. if(client->cUrl.length() == 0) {
  685. ok = false;
  686. }
  687. if(client->cKey.length() == 0) {
  688. ok = false;
  689. }
  690. if(client->cVersion != 13) {
  691. ok = false;
  692. }
  693. if(!client->cHttpHeadersValid) {
  694. ok = false;
  695. }
  696. if(client->cMandatoryHeadersCount != _mandatoryHttpHeaderCount) {
  697. ok = false;
  698. }
  699. }
  700. if(_base64Authorization.length() > 0) {
  701. String auth = WEBSOCKETS_STRING("Basic ");
  702. auth += _base64Authorization;
  703. if(auth != client->base64Authorization) {
  704. DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] HTTP Authorization failed!\n", client->num);
  705. handleAuthorizationFailed(client);
  706. return;
  707. }
  708. }
  709. if(ok) {
  710. DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] Websocket connection incoming.\n", client->num);
  711. // generate Sec-WebSocket-Accept key
  712. String sKey = acceptKey(client->cKey);
  713. DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - sKey: %s\n", client->num, sKey.c_str());
  714. client->status = WSC_CONNECTED;
  715. String handshake = WEBSOCKETS_STRING(
  716. "HTTP/1.1 101 Switching Protocols\r\n"
  717. "Server: arduino-WebSocketsServer\r\n"
  718. "Upgrade: websocket\r\n"
  719. "Connection: Upgrade\r\n"
  720. "Sec-WebSocket-Version: 13\r\n"
  721. "Sec-WebSocket-Accept: ");
  722. handshake += sKey + NEW_LINE;
  723. if(_origin.length() > 0) {
  724. handshake += WEBSOCKETS_STRING("Access-Control-Allow-Origin: ");
  725. handshake += _origin + NEW_LINE;
  726. }
  727. if(client->cProtocol.length() > 0) {
  728. handshake += WEBSOCKETS_STRING("Sec-WebSocket-Protocol: ");
  729. handshake += _protocol + NEW_LINE;
  730. }
  731. // header end
  732. handshake += NEW_LINE;
  733. DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] handshake %s", client->num, (uint8_t *)handshake.c_str());
  734. write(client, (uint8_t *)handshake.c_str(), handshake.length());
  735. headerDone(client);
  736. // send ping
  737. WebSockets::sendFrame(client, WSop_ping);
  738. runCbEvent(client->num, WStype_CONNECTED, (uint8_t *)client->cUrl.c_str(), client->cUrl.length());
  739. } else {
  740. handleNonWebsocketConnection(client);
  741. }
  742. }
  743. }
  744. /**
  745. * send heartbeat ping to server in set intervals
  746. */
  747. void WebSocketsServerCore::handleHBPing(WSclient_t * client) {
  748. if(client->pingInterval == 0)
  749. return;
  750. uint32_t pi = millis() - client->lastPing;
  751. if(pi > client->pingInterval) {
  752. DEBUG_WEBSOCKETS("[WS-Server][%d] sending HB ping\n", client->num);
  753. if(sendPing(client->num)) {
  754. client->lastPing = millis();
  755. client->pongReceived = false;
  756. }
  757. }
  758. }
  759. /**
  760. * enable ping/pong heartbeat process
  761. * @param pingInterval uint32_t how often ping will be sent
  762. * @param pongTimeout uint32_t millis after which pong should timout if not received
  763. * @param disconnectTimeoutCount uint8_t how many timeouts before disconnect, 0=> do not disconnect
  764. */
  765. void WebSocketsServerCore::enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount) {
  766. _pingInterval = pingInterval;
  767. _pongTimeout = pongTimeout;
  768. _disconnectTimeoutCount = disconnectTimeoutCount;
  769. WSclient_t * client;
  770. for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
  771. client = &_clients[i];
  772. WebSockets::enableHeartbeat(client, pingInterval, pongTimeout, disconnectTimeoutCount);
  773. }
  774. }
  775. /**
  776. * disable ping/pong heartbeat process
  777. */
  778. void WebSocketsServerCore::disableHeartbeat() {
  779. _pingInterval = 0;
  780. WSclient_t * client;
  781. for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
  782. client = &_clients[i];
  783. client->pingInterval = 0;
  784. }
  785. }
  786. ////////////////////
  787. // WebSocketServer
  788. /**
  789. * called to initialize the Websocket server
  790. */
  791. void WebSocketsServer::begin(void) {
  792. WebSocketsServerCore::begin();
  793. _server->begin();
  794. DEBUG_WEBSOCKETS("[WS-Server] Server Started.\n");
  795. }
  796. void WebSocketsServer::close(void) {
  797. WebSocketsServerCore::close();
  798. #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
  799. _server->close();
  800. #elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
  801. _server->end();
  802. #else
  803. // TODO how to close server?
  804. #endif
  805. }
  806. #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
  807. /**
  808. * called in arduino loop
  809. */
  810. void WebSocketsServerCore::loop(void) {
  811. if(_runnning) {
  812. WEBSOCKETS_YIELD();
  813. handleClientData();
  814. }
  815. }
  816. /**
  817. * called in arduino loop
  818. */
  819. void WebSocketsServer::loop(void) {
  820. if(_runnning) {
  821. WEBSOCKETS_YIELD();
  822. handleNewClients();
  823. WebSocketsServerCore::loop();
  824. }
  825. }
  826. #endif