WebSocketsClient.cpp 32 KB

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