WebSocketsClient.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854
  1. /**
  2. * @file WebSocketsClient.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 "WebSocketsClient.h"
  26. WebSocketsClient::WebSocketsClient() {
  27. _cbEvent = NULL;
  28. _client.num = 0;
  29. _client.cIsClient = true;
  30. _client.extraHeaders = WEBSOCKETS_STRING("Origin: file://");
  31. }
  32. WebSocketsClient::~WebSocketsClient() {
  33. disconnect();
  34. }
  35. /**
  36. * calles to init the Websockets server
  37. */
  38. void WebSocketsClient::begin(const char * host, uint16_t port, const char * url, const char * protocol) {
  39. _host = host;
  40. _port = port;
  41. #if defined(HAS_SSL)
  42. _fingerprint = "";
  43. _CA_cert = NULL;
  44. #endif
  45. _client.num = 0;
  46. _client.status = WSC_NOT_CONNECTED;
  47. _client.tcp = NULL;
  48. #if defined(HAS_SSL)
  49. _client.isSSL = false;
  50. _client.ssl = NULL;
  51. #endif
  52. _client.cUrl = url;
  53. _client.cCode = 0;
  54. _client.cIsUpgrade = false;
  55. _client.cIsWebsocket = true;
  56. _client.cKey = "";
  57. _client.cAccept = "";
  58. _client.cProtocol = protocol;
  59. _client.cExtensions = "";
  60. _client.cVersion = 0;
  61. _client.base64Authorization = "";
  62. _client.plainAuthorization = "";
  63. _client.isSocketIO = false;
  64. _client.lastPing = 0;
  65. _client.pongReceived = false;
  66. _client.pongTimeoutCount = 0;
  67. #ifdef ESP8266
  68. randomSeed(RANDOM_REG32);
  69. #else
  70. // todo find better seed
  71. randomSeed(millis());
  72. #endif
  73. #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
  74. asyncConnect();
  75. #endif
  76. _lastConnectionFail = 0;
  77. _reconnectInterval = 500;
  78. }
  79. void WebSocketsClient::begin(String host, uint16_t port, String url, String protocol) {
  80. begin(host.c_str(), port, url.c_str(), protocol.c_str());
  81. }
  82. void WebSocketsClient::begin(IPAddress host, uint16_t port, const char * url, const char * protocol) {
  83. return begin(host.toString().c_str(), port, url, protocol);
  84. }
  85. #if defined(HAS_SSL)
  86. void WebSocketsClient::beginSSL(const char * host, uint16_t port, const char * url, const char * fingerprint, const char * protocol) {
  87. begin(host, port, url, protocol);
  88. _client.isSSL = true;
  89. _fingerprint = fingerprint;
  90. _CA_cert = NULL;
  91. }
  92. void WebSocketsClient::beginSSL(String host, uint16_t port, String url, String fingerprint, String protocol) {
  93. beginSSL(host.c_str(), port, url.c_str(), fingerprint.c_str(), protocol.c_str());
  94. }
  95. void WebSocketsClient::beginSslWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) {
  96. begin(host, port, url, protocol);
  97. _client.isSSL = true;
  98. _fingerprint = "";
  99. _CA_cert = CA_cert;
  100. }
  101. #endif
  102. void WebSocketsClient::beginSocketIO(const char * host, uint16_t port, const char * url, const char * protocol) {
  103. begin(host, port, url, protocol);
  104. _client.isSocketIO = true;
  105. }
  106. void WebSocketsClient::beginSocketIO(String host, uint16_t port, String url, String protocol) {
  107. beginSocketIO(host.c_str(), port, url.c_str(), protocol.c_str());
  108. }
  109. #if defined(HAS_SSL)
  110. void WebSocketsClient::beginSocketIOSSL(const char * host, uint16_t port, const char * url, const char * protocol) {
  111. begin(host, port, url, protocol);
  112. _client.isSocketIO = true;
  113. _client.isSSL = true;
  114. _fingerprint = "";
  115. }
  116. void WebSocketsClient::beginSocketIOSSL(String host, uint16_t port, String url, String protocol) {
  117. beginSocketIOSSL(host.c_str(), port, url.c_str(), protocol.c_str());
  118. }
  119. void WebSocketsClient::beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) {
  120. begin(host, port, url, protocol);
  121. _client.isSocketIO = true;
  122. _client.isSSL = true;
  123. _fingerprint = "";
  124. _CA_cert = CA_cert;
  125. }
  126. #endif
  127. #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
  128. /**
  129. * called in arduino loop
  130. */
  131. void WebSocketsClient::loop(void) {
  132. if(!clientIsConnected(&_client)) {
  133. // do not flood the server
  134. if((millis() - _lastConnectionFail) < _reconnectInterval) {
  135. return;
  136. }
  137. #if defined(HAS_SSL)
  138. if(_client.isSSL) {
  139. DEBUG_WEBSOCKETS("[WS-Client] connect wss...\n");
  140. if(_client.ssl) {
  141. delete _client.ssl;
  142. _client.ssl = NULL;
  143. _client.tcp = NULL;
  144. }
  145. _client.ssl = new WEBSOCKETS_NETWORK_SSL_CLASS();
  146. _client.tcp = _client.ssl;
  147. if(_CA_cert) {
  148. DEBUG_WEBSOCKETS("[WS-Client] setting CA certificate");
  149. #if defined(ESP32)
  150. _client.ssl->setCACert(_CA_cert);
  151. #elif defined(ESP8266)
  152. _client.ssl->setCACert((const uint8_t *)_CA_cert, strlen(_CA_cert) + 1);
  153. #else
  154. #error setCACert not implemented
  155. #endif
  156. }
  157. } else {
  158. DEBUG_WEBSOCKETS("[WS-Client] connect ws...\n");
  159. if(_client.tcp) {
  160. delete _client.tcp;
  161. _client.tcp = NULL;
  162. }
  163. _client.tcp = new WEBSOCKETS_NETWORK_CLASS();
  164. }
  165. #else
  166. _client.tcp = new WEBSOCKETS_NETWORK_CLASS();
  167. #endif
  168. if(!_client.tcp) {
  169. DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!");
  170. return;
  171. }
  172. #if defined(ESP32)
  173. if(_client.tcp->connect(_host.c_str(), _port, WEBSOCKETS_TCP_TIMEOUT)) {
  174. #else
  175. if(_client.tcp->connect(_host.c_str(), _port)) {
  176. #endif
  177. connectedCb();
  178. _lastConnectionFail = 0;
  179. } else {
  180. connectFailedCb();
  181. _lastConnectionFail = millis();
  182. }
  183. } else {
  184. handleClientData();
  185. if(_client.status == WSC_CONNECTED) {
  186. handleHBPing();
  187. handleHBTimeout(&_client);
  188. }
  189. }
  190. }
  191. #endif
  192. /**
  193. * set callback function
  194. * @param cbEvent WebSocketServerEvent
  195. */
  196. void WebSocketsClient::onEvent(WebSocketClientEvent cbEvent) {
  197. _cbEvent = cbEvent;
  198. }
  199. /**
  200. * send text data to client
  201. * @param num uint8_t client id
  202. * @param payload uint8_t *
  203. * @param length size_t
  204. * @param headerToPayload bool (see sendFrame for more details)
  205. * @return true if ok
  206. */
  207. bool WebSocketsClient::sendTXT(uint8_t * payload, size_t length, bool headerToPayload) {
  208. if(length == 0) {
  209. length = strlen((const char *)payload);
  210. }
  211. if(clientIsConnected(&_client)) {
  212. return sendFrame(&_client, WSop_text, payload, length, true, headerToPayload);
  213. }
  214. return false;
  215. }
  216. bool WebSocketsClient::sendTXT(const uint8_t * payload, size_t length) {
  217. return sendTXT((uint8_t *)payload, length);
  218. }
  219. bool WebSocketsClient::sendTXT(char * payload, size_t length, bool headerToPayload) {
  220. return sendTXT((uint8_t *)payload, length, headerToPayload);
  221. }
  222. bool WebSocketsClient::sendTXT(const char * payload, size_t length) {
  223. return sendTXT((uint8_t *)payload, length);
  224. }
  225. bool WebSocketsClient::sendTXT(String & payload) {
  226. return sendTXT((uint8_t *)payload.c_str(), payload.length());
  227. }
  228. bool WebSocketsClient::sendTXT(char payload) {
  229. uint8_t buf[WEBSOCKETS_MAX_HEADER_SIZE + 2] = { 0x00 };
  230. buf[WEBSOCKETS_MAX_HEADER_SIZE] = payload;
  231. return sendTXT(buf, 1, true);
  232. }
  233. /**
  234. * send binary data to client
  235. * @param num uint8_t client id
  236. * @param payload uint8_t *
  237. * @param length size_t
  238. * @param headerToPayload bool (see sendFrame for more details)
  239. * @return true if ok
  240. */
  241. bool WebSocketsClient::sendBIN(uint8_t * payload, size_t length, bool headerToPayload) {
  242. if(clientIsConnected(&_client)) {
  243. return sendFrame(&_client, WSop_binary, payload, length, true, headerToPayload);
  244. }
  245. return false;
  246. }
  247. bool WebSocketsClient::sendBIN(const uint8_t * payload, size_t length) {
  248. return sendBIN((uint8_t *)payload, length);
  249. }
  250. /**
  251. * sends a WS ping to Server
  252. * @param payload uint8_t *
  253. * @param length size_t
  254. * @return true if ping is send out
  255. */
  256. bool WebSocketsClient::sendPing(uint8_t * payload, size_t length) {
  257. if(clientIsConnected(&_client)) {
  258. bool sent = sendFrame(&_client, WSop_ping, payload, length);
  259. if(sent)
  260. _client.lastPing = millis();
  261. return sent;
  262. }
  263. return false;
  264. }
  265. bool WebSocketsClient::sendPing(String & payload) {
  266. return sendPing((uint8_t *)payload.c_str(), payload.length());
  267. }
  268. /**
  269. * disconnect one client
  270. * @param num uint8_t client id
  271. */
  272. void WebSocketsClient::disconnect(void) {
  273. if(clientIsConnected(&_client)) {
  274. WebSockets::clientDisconnect(&_client, 1000);
  275. }
  276. }
  277. /**
  278. * set the Authorizatio for the http request
  279. * @param user const char *
  280. * @param password const char *
  281. */
  282. void WebSocketsClient::setAuthorization(const char * user, const char * password) {
  283. if(user && password) {
  284. String auth = user;
  285. auth += ":";
  286. auth += password;
  287. _client.base64Authorization = base64_encode((uint8_t *)auth.c_str(), auth.length());
  288. }
  289. }
  290. /**
  291. * set the Authorizatio for the http request
  292. * @param auth const char * base64
  293. */
  294. void WebSocketsClient::setAuthorization(const char * auth) {
  295. if(auth) {
  296. //_client.base64Authorization = auth;
  297. _client.plainAuthorization = auth;
  298. }
  299. }
  300. /**
  301. * set extra headers for the http request;
  302. * separate headers by "\r\n"
  303. * @param extraHeaders const char * extraHeaders
  304. */
  305. void WebSocketsClient::setExtraHeaders(const char * extraHeaders) {
  306. _client.extraHeaders = extraHeaders;
  307. }
  308. /**
  309. * set the reconnect Interval
  310. * how long to wait after a connection initiate failed
  311. * @param time in ms
  312. */
  313. void WebSocketsClient::setReconnectInterval(unsigned long time) {
  314. _reconnectInterval = time;
  315. }
  316. bool WebSocketsClient::isConnected(void) {
  317. return (_client.status == WSC_CONNECTED);
  318. }
  319. //#################################################################################
  320. //#################################################################################
  321. //#################################################################################
  322. /**
  323. *
  324. * @param client WSclient_t * ptr to the client struct
  325. * @param opcode WSopcode_t
  326. * @param payload uint8_t *
  327. * @param length size_t
  328. */
  329. void WebSocketsClient::messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin) {
  330. WStype_t type = WStype_ERROR;
  331. UNUSED(client);
  332. switch(opcode) {
  333. case WSop_text:
  334. type = fin ? WStype_TEXT : WStype_FRAGMENT_TEXT_START;
  335. break;
  336. case WSop_binary:
  337. type = fin ? WStype_BIN : WStype_FRAGMENT_BIN_START;
  338. break;
  339. case WSop_continuation:
  340. type = fin ? WStype_FRAGMENT_FIN : WStype_FRAGMENT;
  341. break;
  342. case WSop_ping:
  343. type = WStype_PING;
  344. break;
  345. case WSop_pong:
  346. type = WStype_PONG;
  347. break;
  348. case WSop_close:
  349. default:
  350. break;
  351. }
  352. runCbEvent(type, payload, length);
  353. }
  354. /**
  355. * Disconnect an client
  356. * @param client WSclient_t * ptr to the client struct
  357. */
  358. void WebSocketsClient::clientDisconnect(WSclient_t * client) {
  359. bool event = false;
  360. #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
  361. if(client->isSSL && client->ssl) {
  362. if(client->ssl->connected()) {
  363. client->ssl->flush();
  364. client->ssl->stop();
  365. }
  366. event = true;
  367. delete client->ssl;
  368. client->ssl = NULL;
  369. client->tcp = NULL;
  370. }
  371. #endif
  372. if(client->tcp) {
  373. if(client->tcp->connected()) {
  374. #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
  375. client->tcp->flush();
  376. #endif
  377. client->tcp->stop();
  378. }
  379. event = true;
  380. #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
  381. client->status = WSC_NOT_CONNECTED;
  382. #else
  383. delete client->tcp;
  384. #endif
  385. client->tcp = NULL;
  386. }
  387. client->cCode = 0;
  388. client->cKey = "";
  389. client->cAccept = "";
  390. client->cVersion = 0;
  391. client->cIsUpgrade = false;
  392. client->cIsWebsocket = false;
  393. client->cSessionId = "";
  394. client->status = WSC_NOT_CONNECTED;
  395. DEBUG_WEBSOCKETS("[WS-Client] client disconnected.\n");
  396. if(event) {
  397. runCbEvent(WStype_DISCONNECTED, NULL, 0);
  398. }
  399. }
  400. /**
  401. * get client state
  402. * @param client WSclient_t * ptr to the client struct
  403. * @return true = conneted
  404. */
  405. bool WebSocketsClient::clientIsConnected(WSclient_t * client) {
  406. if(!client->tcp) {
  407. return false;
  408. }
  409. if(client->tcp->connected()) {
  410. if(client->status != WSC_NOT_CONNECTED) {
  411. return true;
  412. }
  413. } else {
  414. // client lost
  415. if(client->status != WSC_NOT_CONNECTED) {
  416. DEBUG_WEBSOCKETS("[WS-Client] connection lost.\n");
  417. // do cleanup
  418. clientDisconnect(client);
  419. }
  420. }
  421. if(client->tcp) {
  422. // do cleanup
  423. clientDisconnect(client);
  424. }
  425. return false;
  426. }
  427. #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
  428. /**
  429. * Handel incomming data from Client
  430. */
  431. void WebSocketsClient::handleClientData(void) {
  432. int len = _client.tcp->available();
  433. if(len > 0) {
  434. switch(_client.status) {
  435. case WSC_HEADER: {
  436. String headerLine = _client.tcp->readStringUntil('\n');
  437. handleHeader(&_client, &headerLine);
  438. } break;
  439. case WSC_CONNECTED:
  440. WebSockets::handleWebsocket(&_client);
  441. break;
  442. default:
  443. WebSockets::clientDisconnect(&_client, 1002);
  444. break;
  445. }
  446. }
  447. #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
  448. delay(0);
  449. #endif
  450. }
  451. #endif
  452. /**
  453. * send the WebSocket header to Server
  454. * @param client WSclient_t * ptr to the client struct
  455. */
  456. void WebSocketsClient::sendHeader(WSclient_t * client) {
  457. static const char * NEW_LINE = "\r\n";
  458. DEBUG_WEBSOCKETS("[WS-Client][sendHeader] sending header...\n");
  459. uint8_t randomKey[16] = { 0 };
  460. for(uint8_t i = 0; i < sizeof(randomKey); i++) {
  461. randomKey[i] = random(0xFF);
  462. }
  463. client->cKey = base64_encode(&randomKey[0], 16);
  464. #ifndef NODEBUG_WEBSOCKETS
  465. unsigned long start = micros();
  466. #endif
  467. String handshake;
  468. bool ws_header = true;
  469. String url = client->cUrl;
  470. if(client->isSocketIO) {
  471. if(client->cSessionId.length() == 0) {
  472. url += WEBSOCKETS_STRING("&transport=polling");
  473. ws_header = false;
  474. } else {
  475. url += WEBSOCKETS_STRING("&transport=websocket&sid=");
  476. url += client->cSessionId;
  477. }
  478. }
  479. handshake = WEBSOCKETS_STRING("GET ");
  480. handshake += url + WEBSOCKETS_STRING(
  481. " HTTP/1.1\r\n"
  482. "Host: ");
  483. handshake += _host + ":" + _port + NEW_LINE;
  484. if(ws_header) {
  485. handshake += WEBSOCKETS_STRING(
  486. "Connection: Upgrade\r\n"
  487. "Upgrade: websocket\r\n"
  488. "Sec-WebSocket-Version: 13\r\n"
  489. "Sec-WebSocket-Key: ");
  490. handshake += client->cKey + NEW_LINE;
  491. if(client->cProtocol.length() > 0) {
  492. handshake += WEBSOCKETS_STRING("Sec-WebSocket-Protocol: ");
  493. handshake += client->cProtocol + NEW_LINE;
  494. }
  495. if(client->cExtensions.length() > 0) {
  496. handshake += WEBSOCKETS_STRING("Sec-WebSocket-Extensions: ");
  497. handshake += client->cExtensions + NEW_LINE;
  498. }
  499. } else {
  500. handshake += WEBSOCKETS_STRING("Connection: keep-alive\r\n");
  501. }
  502. // add extra headers; by default this includes "Origin: file://"
  503. if(client->extraHeaders) {
  504. handshake += client->extraHeaders + NEW_LINE;
  505. }
  506. handshake += WEBSOCKETS_STRING("User-Agent: arduino-WebSocket-Client\r\n");
  507. if(client->base64Authorization.length() > 0) {
  508. handshake += WEBSOCKETS_STRING("Authorization: Basic ");
  509. handshake += client->base64Authorization + NEW_LINE;
  510. }
  511. if(client->plainAuthorization.length() > 0) {
  512. handshake += WEBSOCKETS_STRING("Authorization: ");
  513. handshake += client->plainAuthorization + NEW_LINE;
  514. }
  515. handshake += NEW_LINE;
  516. DEBUG_WEBSOCKETS("[WS-Client][sendHeader] handshake %s", (uint8_t *)handshake.c_str());
  517. write(client, (uint8_t *)handshake.c_str(), handshake.length());
  518. #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
  519. client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsClient::handleHeader, this, client, &(client->cHttpLine)));
  520. #endif
  521. DEBUG_WEBSOCKETS("[WS-Client][sendHeader] sending header... Done (%luus).\n", (micros() - start));
  522. }
  523. /**
  524. * handle the WebSocket header reading
  525. * @param client WSclient_t * ptr to the client struct
  526. */
  527. void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
  528. headerLine->trim(); // remove \r
  529. if(headerLine->length() > 0) {
  530. DEBUG_WEBSOCKETS("[WS-Client][handleHeader] RX: %s\n", headerLine->c_str());
  531. if(headerLine->startsWith(WEBSOCKETS_STRING("HTTP/1."))) {
  532. // "HTTP/1.1 101 Switching Protocols"
  533. client->cCode = headerLine->substring(9, headerLine->indexOf(' ', 9)).toInt();
  534. } else if(headerLine->indexOf(':') >= 0) {
  535. String headerName = headerLine->substring(0, headerLine->indexOf(':'));
  536. String headerValue = headerLine->substring(headerLine->indexOf(':') + 1);
  537. // remove space in the beginning (RFC2616)
  538. if(headerValue[0] == ' ') {
  539. headerValue.remove(0, 1);
  540. }
  541. if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Connection"))) {
  542. if(headerValue.equalsIgnoreCase(WEBSOCKETS_STRING("upgrade"))) {
  543. client->cIsUpgrade = true;
  544. }
  545. } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Upgrade"))) {
  546. if(headerValue.equalsIgnoreCase(WEBSOCKETS_STRING("websocket"))) {
  547. client->cIsWebsocket = true;
  548. }
  549. } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Accept"))) {
  550. client->cAccept = headerValue;
  551. client->cAccept.trim(); // see rfc6455
  552. } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Protocol"))) {
  553. client->cProtocol = headerValue;
  554. } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Extensions"))) {
  555. client->cExtensions = headerValue;
  556. } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Version"))) {
  557. client->cVersion = headerValue.toInt();
  558. } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Set-Cookie"))) {
  559. if(headerValue.indexOf(WEBSOCKETS_STRING("HttpOnly")) > -1) {
  560. client->cSessionId = headerValue.substring(headerValue.indexOf('=') + 1, headerValue.indexOf(";"));
  561. } else {
  562. client->cSessionId = headerValue.substring(headerValue.indexOf('=') + 1);
  563. }
  564. }
  565. } else {
  566. DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header error (%s)\n", headerLine->c_str());
  567. }
  568. (*headerLine) = "";
  569. #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
  570. client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsClient::handleHeader, this, client, &(client->cHttpLine)));
  571. #endif
  572. } else {
  573. DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header read fin.\n");
  574. DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Client settings:\n");
  575. DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cURL: %s\n", client->cUrl.c_str());
  576. DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cKey: %s\n", client->cKey.c_str());
  577. DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Server header:\n");
  578. DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cCode: %d\n", client->cCode);
  579. DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cIsUpgrade: %d\n", client->cIsUpgrade);
  580. DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cIsWebsocket: %d\n", client->cIsWebsocket);
  581. DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cAccept: %s\n", client->cAccept.c_str());
  582. DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cProtocol: %s\n", client->cProtocol.c_str());
  583. DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cExtensions: %s\n", client->cExtensions.c_str());
  584. DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cVersion: %d\n", client->cVersion);
  585. DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cSessionId: %s\n", client->cSessionId.c_str());
  586. bool ok = (client->cIsUpgrade && client->cIsWebsocket);
  587. if(ok) {
  588. switch(client->cCode) {
  589. case 101: ///< Switching Protocols
  590. break;
  591. case 200:
  592. if(client->isSocketIO) {
  593. break;
  594. }
  595. case 403: ///< Forbidden
  596. // todo handle login
  597. default: ///< Server dont unterstand requrst
  598. ok = false;
  599. DEBUG_WEBSOCKETS("[WS-Client][handleHeader] serverCode is not 101 (%d)\n", client->cCode);
  600. clientDisconnect(client);
  601. _lastConnectionFail = millis();
  602. break;
  603. }
  604. }
  605. if(ok) {
  606. if(client->cAccept.length() == 0) {
  607. ok = false;
  608. } else {
  609. // generate Sec-WebSocket-Accept key for check
  610. String sKey = acceptKey(client->cKey);
  611. if(sKey != client->cAccept) {
  612. DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Sec-WebSocket-Accept is wrong\n");
  613. ok = false;
  614. }
  615. }
  616. }
  617. if(ok) {
  618. DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Websocket connection init done.\n");
  619. headerDone(client);
  620. runCbEvent(WStype_CONNECTED, (uint8_t *)client->cUrl.c_str(), client->cUrl.length());
  621. } else if(clientIsConnected(client) && client->isSocketIO && client->cSessionId.length() > 0) {
  622. if(_client.tcp->available()) {
  623. // read not needed data
  624. DEBUG_WEBSOCKETS("[WS-Client][handleHeader] still data in buffer (%d), clean up.\n", _client.tcp->available());
  625. while(_client.tcp->available() > 0) {
  626. _client.tcp->read();
  627. }
  628. }
  629. sendHeader(client);
  630. } else {
  631. DEBUG_WEBSOCKETS("[WS-Client][handleHeader] no Websocket connection close.\n");
  632. _lastConnectionFail = millis();
  633. if(clientIsConnected(client)) {
  634. write(client, "This is a webSocket client!");
  635. }
  636. clientDisconnect(client);
  637. }
  638. }
  639. }
  640. void WebSocketsClient::connectedCb() {
  641. DEBUG_WEBSOCKETS("[WS-Client] connected to %s:%u.\n", _host.c_str(), _port);
  642. #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
  643. _client.tcp->onDisconnect(std::bind([](WebSocketsClient * c, AsyncTCPbuffer * obj, WSclient_t * client) -> bool {
  644. DEBUG_WEBSOCKETS("[WS-Server][%d] Disconnect client\n", client->num);
  645. client->status = WSC_NOT_CONNECTED;
  646. client->tcp = NULL;
  647. // reconnect
  648. c->asyncConnect();
  649. return true;
  650. },
  651. this, std::placeholders::_1, &_client));
  652. #endif
  653. _client.status = WSC_HEADER;
  654. #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
  655. // set Timeout for readBytesUntil and readStringUntil
  656. _client.tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT);
  657. #endif
  658. #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
  659. _client.tcp->setNoDelay(true);
  660. #endif
  661. #if defined(HAS_SSL)
  662. if(_client.isSSL && _fingerprint.length()) {
  663. if(!_client.ssl->verify(_fingerprint.c_str(), _host.c_str())) {
  664. DEBUG_WEBSOCKETS("[WS-Client] certificate mismatch\n");
  665. WebSockets::clientDisconnect(&_client, 1000);
  666. return;
  667. }
  668. } else if(_client.isSSL && !_CA_cert) {
  669. #if defined(wificlientbearssl_h) && !defined(USING_AXTLS) && !defined(wificlientsecure_h)
  670. _client.ssl->setInsecure();
  671. #endif
  672. }
  673. #endif
  674. // send Header to Server
  675. sendHeader(&_client);
  676. }
  677. void WebSocketsClient::connectFailedCb() {
  678. DEBUG_WEBSOCKETS("[WS-Client] connection to %s:%u Failed\n", _host.c_str(), _port);
  679. }
  680. #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
  681. void WebSocketsClient::asyncConnect() {
  682. DEBUG_WEBSOCKETS("[WS-Client] asyncConnect...\n");
  683. AsyncClient * tcpclient = new AsyncClient();
  684. if(!tcpclient) {
  685. DEBUG_WEBSOCKETS("[WS-Client] creating AsyncClient class failed!\n");
  686. return;
  687. }
  688. tcpclient->onDisconnect([](void * obj, AsyncClient * c) {
  689. c->free();
  690. delete c;
  691. });
  692. tcpclient->onConnect(std::bind([](WebSocketsClient * ws, AsyncClient * tcp) {
  693. ws->_client.tcp = new AsyncTCPbuffer(tcp);
  694. if(!ws->_client.tcp) {
  695. DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!\n");
  696. ws->connectFailedCb();
  697. return;
  698. }
  699. ws->connectedCb();
  700. },
  701. this, std::placeholders::_2));
  702. tcpclient->onError(std::bind([](WebSocketsClient * ws, AsyncClient * tcp) {
  703. ws->connectFailedCb();
  704. // reconnect
  705. ws->asyncConnect();
  706. },
  707. this, std::placeholders::_2));
  708. if(!tcpclient->connect(_host.c_str(), _port)) {
  709. connectFailedCb();
  710. delete tcpclient;
  711. }
  712. }
  713. #endif
  714. /**
  715. * send heartbeat ping to server in set intervals
  716. */
  717. void WebSocketsClient::handleHBPing() {
  718. if(_client.pingInterval == 0)
  719. return;
  720. uint32_t pi = millis() - _client.lastPing;
  721. if(pi > _client.pingInterval) {
  722. DEBUG_WEBSOCKETS("[WS-Client] sending HB ping\n");
  723. if(sendPing()) {
  724. _client.lastPing = millis();
  725. _client.pongReceived = false;
  726. }
  727. }
  728. }
  729. /**
  730. * enable ping/pong heartbeat process
  731. * @param pingInterval uint32_t how often ping will be sent
  732. * @param pongTimeout uint32_t millis after which pong should timout if not received
  733. * @param disconnectTimeoutCount uint8_t how many timeouts before disconnect, 0=> do not disconnect
  734. */
  735. void WebSocketsClient::enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount) {
  736. WebSockets::enableHeartbeat(&_client, pingInterval, pongTimeout, disconnectTimeoutCount);
  737. }
  738. /**
  739. * disable ping/pong heartbeat process
  740. */
  741. void WebSocketsClient::disableHeartbeat() {
  742. _client.pingInterval = 0;
  743. }