websocketclient.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875
  1. /* Websocket client implementation
  2. *
  3. * Copyright (c) 2016 Luís Fonseca <miguelluisfonseca@gmail.com>
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining
  6. * a copy of this software and associated documentation files (the
  7. * "Software"), to deal in the Software without restriction, including
  8. * without limitation the rights to use, copy, modify, merge, publish,
  9. * distribute, sublicense, and/or sell copies of the Software, and to
  10. * permit persons to whom the Software is furnished to do so, subject to
  11. * the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be
  14. * included in all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  17. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  18. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  19. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  20. * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  21. * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  22. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  23. */
  24. #include "osapi.h"
  25. #include "user_interface.h"
  26. #include "espconn.h"
  27. #include "mem.h"
  28. #include <stdint.h>
  29. #include <stddef.h>
  30. #include <string.h>
  31. #include <stdlib.h>
  32. #include <stdio.h>
  33. #include "websocketclient.h"
  34. // Depends on 'crypto' module for sha1
  35. #include "../crypto/digests.h"
  36. #include "../crypto/mech.h"
  37. #include "pm/swtimer.h"
  38. #define PROTOCOL_SECURE "wss://"
  39. #define PROTOCOL_INSECURE "ws://"
  40. #define PORT_SECURE 443
  41. #define PORT_INSECURE 80
  42. #define PORT_MAX_VALUE 65535
  43. #define WS_INIT_REQUEST "GET %s HTTP/1.1\r\n"\
  44. "Host: %s:%d\r\n"
  45. #define WS_INIT_REQUEST_LENGTH 30
  46. #define WS_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
  47. #define WS_GUID_LENGTH 36
  48. #define WS_HTTP_SWITCH_PROTOCOL_HEADER "HTTP/1.1 101"
  49. #define WS_HTTP_SEC_WEBSOCKET_ACCEPT "Sec-WebSocket-Accept:"
  50. #define WS_CONNECT_TIMEOUT_MS 10 * 1000
  51. #define WS_PING_INTERVAL_MS 30 * 1000
  52. #define WS_FORCE_CLOSE_TIMEOUT_MS 5 * 1000
  53. #define WS_UNHEALTHY_THRESHOLD 2
  54. #define WS_OPCODE_CONTINUATION 0x0
  55. #define WS_OPCODE_TEXT 0x1
  56. #define WS_OPCODE_BINARY 0x2
  57. #define WS_OPCODE_CLOSE 0x8
  58. #define WS_OPCODE_PING 0x9
  59. #define WS_OPCODE_PONG 0xA
  60. static const header_t DEFAULT_HEADERS[] = {
  61. {"User-Agent", "ESP8266"},
  62. {"Sec-WebSocket-Protocol", "chat"},
  63. {0}
  64. };
  65. static const header_t *EMPTY_HEADERS = DEFAULT_HEADERS + sizeof(DEFAULT_HEADERS) / sizeof(header_t) - 1;
  66. static char *cryptoSha1(char *data, unsigned int len) {
  67. SHA1_CTX ctx;
  68. SHA1Init(&ctx);
  69. SHA1Update(&ctx, data, len);
  70. uint8_t *digest = (uint8_t *) calloc(1,20);
  71. SHA1Final(digest, &ctx);
  72. return (char *) digest; // Requires free
  73. }
  74. static const char *bytes64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  75. static char *base64Encode(char *data, unsigned int len) {
  76. int blen = (len + 2) / 3 * 4;
  77. char *out = (char *) calloc(1,blen + 1);
  78. out[blen] = '\0';
  79. int j = 0, i;
  80. for (i = 0; i < len; i += 3) {
  81. int a = data[i];
  82. int b = (i + 1 < len) ? data[i + 1] : 0;
  83. int c = (i + 2 < len) ? data[i + 2] : 0;
  84. out[j++] = bytes64[a >> 2];
  85. out[j++] = bytes64[((a & 3) << 4) | (b >> 4)];
  86. out[j++] = (i + 1 < len) ? bytes64[((b & 15) << 2) | (c >> 6)] : 61;
  87. out[j++] = (i + 2 < len) ? bytes64[(c & 63)] : 61;
  88. }
  89. return out; // Requires free
  90. }
  91. static void generateSecKeys(char **key, char **expectedKey) {
  92. char rndData[16];
  93. int i;
  94. for (i = 0; i < 16; i++) {
  95. rndData[i] = (char) os_random();
  96. }
  97. *key = base64Encode(rndData, 16);
  98. // expectedKey = b64(sha1(keyB64 + GUID))
  99. char keyWithGuid[24 + WS_GUID_LENGTH];
  100. memcpy(keyWithGuid, *key, 24);
  101. memcpy(keyWithGuid + 24, WS_GUID, WS_GUID_LENGTH);
  102. char *keyEncrypted = cryptoSha1(keyWithGuid, 24 + WS_GUID_LENGTH);
  103. *expectedKey = base64Encode(keyEncrypted, 20);
  104. os_free(keyEncrypted);
  105. }
  106. static char *_strcpy(char *dst, char *src) {
  107. while(*dst++ = *src++);
  108. return dst - 1;
  109. }
  110. static int headers_length(const header_t *headers) {
  111. int length = 0;
  112. for(; headers->key; headers++)
  113. length += strlen(headers->key) + strlen(headers->value) + 4;
  114. return length;
  115. }
  116. static char *sprintf_headers(char *buf, ...) {
  117. char *dst = buf;
  118. va_list args;
  119. va_start(args, buf);
  120. for(header_t *header_set = va_arg(args, header_t *); header_set; header_set = va_arg(args, header_t *))
  121. for(header_t *header = header_set; header->key; header++) {
  122. va_list args2;
  123. va_start(args2, buf);
  124. for(header_t *header_set2 = va_arg(args2, header_t *); header_set2; header_set2 = va_arg(args2, header_t *))
  125. for(header_t *header2 = header_set2; header2->key; header2++) {
  126. if(header == header2)
  127. goto ok;
  128. if(!strcasecmp(header->key, header2->key))
  129. goto skip;
  130. }
  131. ok:
  132. dst = _strcpy(dst, header->key);
  133. dst = _strcpy(dst, ": ");
  134. dst = _strcpy(dst, header->value);
  135. dst = _strcpy(dst, "\r\n");
  136. skip:;
  137. }
  138. dst = _strcpy(dst, "\r\n");
  139. return dst;
  140. }
  141. static void ws_closeSentCallback(void *arg) {
  142. NODE_DBG("ws_closeSentCallback \n");
  143. struct espconn *conn = (struct espconn *) arg;
  144. ws_info *ws = (ws_info *) conn->reverse;
  145. if (ws == NULL) {
  146. NODE_DBG("ws is unexpectly null\n");
  147. return;
  148. }
  149. ws->knownFailureCode = -6;
  150. if (ws->isSecure)
  151. espconn_secure_disconnect(conn);
  152. else
  153. espconn_disconnect(conn);
  154. }
  155. static void ws_sendFrame(struct espconn *conn, int opCode, const char *data, unsigned short len) {
  156. NODE_DBG("ws_sendFrame %d %d\n", opCode, len);
  157. ws_info *ws = (ws_info *) conn->reverse;
  158. if (ws->connectionState == 4) {
  159. NODE_DBG("already in closing state\n");
  160. return;
  161. } else if (ws->connectionState != 3) {
  162. NODE_DBG("can't send message while not in a connected state\n");
  163. return;
  164. }
  165. char *b = calloc(1,10 + len); // 10 bytes = worst case scenario for framming
  166. if (b == NULL) {
  167. NODE_DBG("Out of memory when receiving message, disconnecting...\n");
  168. ws->knownFailureCode = -16;
  169. if (ws->isSecure)
  170. espconn_secure_disconnect(conn);
  171. else
  172. espconn_disconnect(conn);
  173. return;
  174. }
  175. b[0] = 1 << 7; // has fin
  176. b[0] += opCode;
  177. b[1] = 1 << 7; // has mask
  178. int bufOffset;
  179. if (len < 126) {
  180. b[1] += len;
  181. bufOffset = 2;
  182. } else if (len < 0x10000) {
  183. b[1] += 126;
  184. b[2] = len >> 8;
  185. b[3] = len;
  186. bufOffset = 4;
  187. } else {
  188. b[1] += 127;
  189. b[2] = len >> 24;
  190. b[3] = len >> 16;
  191. b[4] = len >> 8;
  192. b[5] = len;
  193. bufOffset = 6;
  194. }
  195. // Random mask:
  196. b[bufOffset] = (char) os_random();
  197. b[bufOffset + 1] = (char) os_random();
  198. b[bufOffset + 2] = (char) os_random();
  199. b[bufOffset + 3] = (char) os_random();
  200. bufOffset += 4;
  201. // Copy data to buffer
  202. memcpy(b + bufOffset, data, len);
  203. // Apply mask to encode payload
  204. int i;
  205. for (i = 0; i < len; i++) {
  206. b[bufOffset + i] ^= b[bufOffset - 4 + i % 4];
  207. }
  208. bufOffset += len;
  209. NODE_DBG("b[0] = %d \n", b[0]);
  210. NODE_DBG("b[1] = %d \n", b[1]);
  211. NODE_DBG("b[2] = %d \n", b[2]);
  212. NODE_DBG("b[3] = %d \n", b[3]);
  213. NODE_DBG("b[4] = %d \n", b[4]);
  214. NODE_DBG("b[5] = %d \n", b[5]);
  215. NODE_DBG("b[6] = %d \n", b[6]);
  216. NODE_DBG("b[7] = %d \n", b[7]);
  217. NODE_DBG("b[8] = %d \n", b[8]);
  218. NODE_DBG("b[9] = %d \n", b[9]);
  219. NODE_DBG("sending message\n");
  220. if (ws->isSecure)
  221. espconn_secure_send(conn, (uint8_t *) b, bufOffset);
  222. else
  223. espconn_send(conn, (uint8_t *) b, bufOffset);
  224. os_free(b);
  225. }
  226. static void ws_sendPingTimeout(void *arg) {
  227. NODE_DBG("ws_sendPingTimeout \n");
  228. struct espconn *conn = (struct espconn *) arg;
  229. ws_info *ws = (ws_info *) conn->reverse;
  230. if (ws->unhealthyPoints == WS_UNHEALTHY_THRESHOLD) {
  231. // several pings were sent but no pongs nor messages
  232. ws->knownFailureCode = -19;
  233. if (ws->isSecure)
  234. espconn_secure_disconnect(conn);
  235. else
  236. espconn_disconnect(conn);
  237. return;
  238. }
  239. ws_sendFrame(conn, WS_OPCODE_PING, NULL, 0);
  240. ws->unhealthyPoints += 1;
  241. }
  242. static void ws_receiveCallback(void *arg, char *buf, unsigned short len) {
  243. NODE_DBG("ws_receiveCallback %d \n", len);
  244. struct espconn *conn = (struct espconn *) arg;
  245. ws_info *ws = (ws_info *) conn->reverse;
  246. ws->unhealthyPoints = 0; // received data, connection is healthy
  247. os_timer_disarm(&ws->timeoutTimer); // reset ping check
  248. os_timer_arm(&ws->timeoutTimer, WS_PING_INTERVAL_MS, true);
  249. char *b = buf;
  250. if (ws->frameBuffer != NULL) { // Append previous frameBuffer with new content
  251. NODE_DBG("Appending new frameBuffer to old one \n");
  252. ws->frameBuffer = realloc(ws->frameBuffer, ws->frameBufferLen + len);
  253. if (ws->frameBuffer == NULL) {
  254. NODE_DBG("Failed to allocate new framebuffer, disconnecting...\n");
  255. ws->knownFailureCode = -8;
  256. if (ws->isSecure)
  257. espconn_secure_disconnect(conn);
  258. else
  259. espconn_disconnect(conn);
  260. return;
  261. }
  262. memcpy(ws->frameBuffer + ws->frameBufferLen, b, len);
  263. ws->frameBufferLen += len;
  264. len = ws->frameBufferLen;
  265. b = ws->frameBuffer;
  266. NODE_DBG("New frameBufferLen: %d\n", len);
  267. }
  268. while (b != NULL) { // several frames can be present, b pointer will be moved to the next frame
  269. NODE_DBG("b[0] = %d \n", b[0]);
  270. NODE_DBG("b[1] = %d \n", b[1]);
  271. NODE_DBG("b[2] = %d \n", b[2]);
  272. NODE_DBG("b[3] = %d \n", b[3]);
  273. NODE_DBG("b[4] = %d \n", b[4]);
  274. NODE_DBG("b[5] = %d \n", b[5]);
  275. NODE_DBG("b[6] = %d \n", b[6]);
  276. NODE_DBG("b[7] = %d \n", b[7]);
  277. int isFin = b[0] & 0x80 ? 1 : 0;
  278. int opCode = b[0] & 0x0f;
  279. int hasMask = b[1] & 0x80 ? 1 : 0;
  280. uint64_t payloadLength = b[1] & 0x7f;
  281. int bufOffset = 2;
  282. if (payloadLength == 126) {
  283. payloadLength = (b[2] << 8) + b[3];
  284. bufOffset = 4;
  285. } else if (payloadLength == 127) { // this will clearly not hold in heap, abort??
  286. payloadLength = (b[2] << 24) + (b[3] << 16) + (b[4] << 8) + b[5];
  287. bufOffset = 6;
  288. }
  289. if (hasMask) {
  290. int maskOffset = bufOffset;
  291. bufOffset += 4;
  292. int i;
  293. for (i = 0; i < payloadLength; i++) {
  294. b[bufOffset + i] ^= b[maskOffset + i % 4]; // apply mask to decode payload
  295. }
  296. }
  297. if (payloadLength > len - bufOffset) {
  298. NODE_DBG("INCOMPLETE Frame \n");
  299. if (ws->frameBuffer == NULL) {
  300. NODE_DBG("Allocing new frameBuffer \n");
  301. ws->frameBuffer = calloc(1,len);
  302. if (ws->frameBuffer == NULL) {
  303. NODE_DBG("Failed to allocate framebuffer, disconnecting... \n");
  304. ws->knownFailureCode = -9;
  305. if (ws->isSecure)
  306. espconn_secure_disconnect(conn);
  307. else
  308. espconn_disconnect(conn);
  309. return;
  310. }
  311. memcpy(ws->frameBuffer, b, len);
  312. ws->frameBufferLen = len;
  313. }
  314. break; // since the buffer were already concat'ed, wait for the next receive
  315. }
  316. if (!isFin) {
  317. NODE_DBG("PARTIAL frame! Should concat payload and later restore opcode\n");
  318. if(ws->payloadBuffer == NULL) {
  319. NODE_DBG("Allocing new payloadBuffer \n");
  320. ws->payloadBuffer = calloc(1,payloadLength);
  321. if (ws->payloadBuffer == NULL) {
  322. NODE_DBG("Failed to allocate payloadBuffer, disconnecting...\n");
  323. ws->knownFailureCode = -10;
  324. if (ws->isSecure)
  325. espconn_secure_disconnect(conn);
  326. else
  327. espconn_disconnect(conn);
  328. return;
  329. }
  330. memcpy(ws->payloadBuffer, b + bufOffset, payloadLength);
  331. ws->frameBufferLen = payloadLength;
  332. ws->payloadOriginalOpCode = opCode;
  333. } else {
  334. NODE_DBG("Appending new payloadBuffer to old one \n");
  335. ws->payloadBuffer = realloc(ws->payloadBuffer, ws->payloadBufferLen + payloadLength);
  336. if (ws->payloadBuffer == NULL) {
  337. NODE_DBG("Failed to allocate new framebuffer, disconnecting...\n");
  338. ws->knownFailureCode = -11;
  339. if (ws->isSecure)
  340. espconn_secure_disconnect(conn);
  341. else
  342. espconn_disconnect(conn);
  343. return;
  344. }
  345. memcpy(ws->payloadBuffer + ws->payloadBufferLen, b + bufOffset, payloadLength);
  346. ws->payloadBufferLen += payloadLength;
  347. }
  348. } else {
  349. char *payload;
  350. if (opCode == WS_OPCODE_CONTINUATION) {
  351. NODE_DBG("restoring original opcode\n");
  352. if (ws->payloadBuffer == NULL) {
  353. NODE_DBG("Got FIN continuation frame but didn't receive any beforehand, disconnecting...\n");
  354. ws->knownFailureCode = -15;
  355. if (ws->isSecure)
  356. espconn_secure_disconnect(conn);
  357. else
  358. espconn_disconnect(conn);
  359. return;
  360. }
  361. // concat buffer with payload
  362. payload = calloc(1,ws->payloadBufferLen + payloadLength);
  363. if (payload == NULL) {
  364. NODE_DBG("Failed to allocate new framebuffer, disconnecting...\n");
  365. ws->knownFailureCode = -12;
  366. if (ws->isSecure)
  367. espconn_secure_disconnect(conn);
  368. else
  369. espconn_disconnect(conn);
  370. return;
  371. }
  372. memcpy(payload, ws->payloadBuffer, ws->payloadBufferLen);
  373. memcpy(payload + ws->payloadBufferLen, b + bufOffset, payloadLength);
  374. os_free(ws->payloadBuffer); // free previous buffer
  375. ws->payloadBuffer = NULL;
  376. payloadLength += ws->payloadBufferLen;
  377. ws->payloadBufferLen = 0;
  378. opCode = ws->payloadOriginalOpCode;
  379. ws->payloadOriginalOpCode = 0;
  380. } else {
  381. int extensionDataOffset = 0;
  382. if (opCode == WS_OPCODE_CLOSE && payloadLength > 0) {
  383. unsigned int reasonCode = b[bufOffset] << 8 + b[bufOffset + 1];
  384. NODE_DBG("Closing due to: %d\n", reasonCode); // Must not be shown to client as per spec
  385. extensionDataOffset += 2;
  386. }
  387. payload = calloc(1,payloadLength - extensionDataOffset + 1);
  388. if (payload == NULL) {
  389. NODE_DBG("Failed to allocate payload, disconnecting...\n");
  390. ws->knownFailureCode = -13;
  391. if (ws->isSecure)
  392. espconn_secure_disconnect(conn);
  393. else
  394. espconn_disconnect(conn);
  395. return;
  396. }
  397. memcpy(payload, b + bufOffset + extensionDataOffset, payloadLength - extensionDataOffset);
  398. payload[payloadLength - extensionDataOffset] = '\0';
  399. }
  400. NODE_DBG("isFin %d \n", isFin);
  401. NODE_DBG("opCode %d \n", opCode);
  402. NODE_DBG("hasMask %d \n", hasMask);
  403. NODE_DBG("payloadLength %d \n", payloadLength);
  404. NODE_DBG("len %d \n", len);
  405. NODE_DBG("bufOffset %d \n", bufOffset);
  406. if (opCode == WS_OPCODE_CLOSE) {
  407. NODE_DBG("Closing message: %s\n", payload); // Must not be shown to client as per spec
  408. espconn_regist_sentcb(conn, ws_closeSentCallback);
  409. ws_sendFrame(conn, WS_OPCODE_CLOSE, (const char *) (b + bufOffset), (unsigned short) payloadLength);
  410. ws->connectionState = 4;
  411. } else if (opCode == WS_OPCODE_PING) {
  412. ws_sendFrame(conn, WS_OPCODE_PONG, (const char *) (b + bufOffset), (unsigned short) payloadLength);
  413. } else if (opCode == WS_OPCODE_PONG) {
  414. // ping alarm was already reset...
  415. } else {
  416. if (ws->onReceive) ws->onReceive(ws, payloadLength, payload, opCode);
  417. }
  418. os_free(payload);
  419. }
  420. bufOffset += payloadLength;
  421. NODE_DBG("bufOffset %d \n", bufOffset);
  422. if (bufOffset == len) { // (bufOffset > len) won't happen here because it's being checked earlier
  423. b = NULL;
  424. if (ws->frameBuffer != NULL) { // the last frame inside buffer was processed
  425. os_free(ws->frameBuffer);
  426. ws->frameBuffer = NULL;
  427. ws->frameBufferLen = 0;
  428. }
  429. } else {
  430. len -= bufOffset;
  431. b += bufOffset; // move b to next frame
  432. if (ws->frameBuffer != NULL) {
  433. NODE_DBG("Reallocing frameBuffer to remove consumed frame\n");
  434. ws->frameBuffer = realloc(ws->frameBuffer, ws->frameBufferLen + len);
  435. if (ws->frameBuffer == NULL) {
  436. NODE_DBG("Failed to allocate new frame buffer, disconnecting...\n");
  437. ws->knownFailureCode = -14;
  438. if (ws->isSecure)
  439. espconn_secure_disconnect(conn);
  440. else
  441. espconn_disconnect(conn);
  442. return;
  443. }
  444. memcpy(ws->frameBuffer + ws->frameBufferLen, b, len);
  445. ws->frameBufferLen += len;
  446. b = ws->frameBuffer;
  447. }
  448. }
  449. }
  450. }
  451. static void ws_initReceiveCallback(void *arg, char *buf, unsigned short len) {
  452. NODE_DBG("ws_initReceiveCallback %d \n", len);
  453. struct espconn *conn = (struct espconn *) arg;
  454. ws_info *ws = (ws_info *) conn->reverse;
  455. // Check server is switch protocols
  456. if (strstr(buf, WS_HTTP_SWITCH_PROTOCOL_HEADER) == NULL) {
  457. NODE_DBG("Server is not switching protocols\n");
  458. ws->knownFailureCode = -17;
  459. if (ws->isSecure)
  460. espconn_secure_disconnect(conn);
  461. else
  462. espconn_disconnect(conn);
  463. return;
  464. }
  465. // Check server has valid sec key
  466. if (strstr(buf, ws->expectedSecKey) == NULL) {
  467. NODE_DBG("Server has invalid response\n");
  468. ws->knownFailureCode = -7;
  469. if (ws->isSecure)
  470. espconn_secure_disconnect(conn);
  471. else
  472. espconn_disconnect(conn);
  473. return;
  474. }
  475. NODE_DBG("Server response is valid, it's now a websocket!\n");
  476. os_timer_disarm(&ws->timeoutTimer);
  477. os_timer_setfn(&ws->timeoutTimer, (os_timer_func_t *) ws_sendPingTimeout, conn);
  478. SWTIMER_REG_CB(ws_sendPingTimeout, SWTIMER_RESUME)
  479. os_timer_arm(&ws->timeoutTimer, WS_PING_INTERVAL_MS, true);
  480. espconn_regist_recvcb(conn, ws_receiveCallback);
  481. if (ws->onConnection) ws->onConnection(ws);
  482. char *data = strstr(buf, "\r\n\r\n");
  483. unsigned short dataLength = len - (data - buf) - 4;
  484. NODE_DBG("dataLength = %d\n", len - (data - buf) - 4);
  485. if (data != NULL && dataLength > 0) { // handshake already contained a frame
  486. ws_receiveCallback(arg, data + 4, dataLength);
  487. }
  488. }
  489. static void connect_callback(void *arg) {
  490. NODE_DBG("Connected\n");
  491. struct espconn *conn = (struct espconn *) arg;
  492. ws_info *ws = (ws_info *) conn->reverse;
  493. ws->connectionState = 3;
  494. espconn_regist_recvcb(conn, ws_initReceiveCallback);
  495. char *key;
  496. generateSecKeys(&key, &ws->expectedSecKey);
  497. header_t headers[] = {
  498. {"Upgrade", "websocket"},
  499. {"Connection", "Upgrade"},
  500. {"Sec-WebSocket-Key", key},
  501. {"Sec-WebSocket-Version", "13"},
  502. {0}
  503. };
  504. const header_t *extraHeaders = ws->extraHeaders ? ws->extraHeaders : EMPTY_HEADERS;
  505. char buf[WS_INIT_REQUEST_LENGTH + strlen(ws->path) + strlen(ws->hostname) +
  506. headers_length(DEFAULT_HEADERS) + headers_length(headers) + headers_length(extraHeaders) + 2];
  507. int len = os_sprintf(
  508. buf,
  509. WS_INIT_REQUEST,
  510. ws->path,
  511. ws->hostname,
  512. ws->port
  513. );
  514. len = sprintf_headers(buf + len, headers, extraHeaders, DEFAULT_HEADERS, 0) - buf;
  515. os_free(key);
  516. NODE_DBG("request: %s", buf);
  517. if (ws->isSecure)
  518. espconn_secure_send(conn, (uint8_t *) buf, len);
  519. else
  520. espconn_send(conn, (uint8_t *) buf, len);
  521. }
  522. static void disconnect_callback(void *arg) {
  523. NODE_DBG("disconnect_callback\n");
  524. struct espconn *conn = (struct espconn *) arg;
  525. ws_info *ws = (ws_info *) conn->reverse;
  526. ws->connectionState = 4;
  527. os_timer_disarm(&ws->timeoutTimer);
  528. NODE_DBG("ws->hostname %d\n", ws->hostname);
  529. os_free(ws->hostname);
  530. NODE_DBG("ws->path %d\n ", ws->path);
  531. os_free(ws->path);
  532. if (ws->expectedSecKey != NULL) {
  533. os_free(ws->expectedSecKey);
  534. }
  535. if (ws->frameBuffer != NULL) {
  536. os_free(ws->frameBuffer);
  537. }
  538. if (ws->payloadBuffer != NULL) {
  539. os_free(ws->payloadBuffer);
  540. }
  541. if (conn->proto.tcp != NULL) {
  542. os_free(conn->proto.tcp);
  543. }
  544. NODE_DBG("conn %d\n", conn);
  545. espconn_delete(conn);
  546. NODE_DBG("freeing conn1 \n");
  547. os_free(conn);
  548. ws->conn = NULL;
  549. if (ws->onFailure) {
  550. if (ws->knownFailureCode) ws->onFailure(ws, ws->knownFailureCode);
  551. else ws->onFailure(ws, -99);
  552. }
  553. }
  554. static void ws_connectTimeout(void *arg) {
  555. NODE_DBG("ws_connectTimeout\n");
  556. struct espconn *conn = (struct espconn *) arg;
  557. ws_info *ws = (ws_info *) conn->reverse;
  558. ws->knownFailureCode = -18;
  559. disconnect_callback(arg);
  560. }
  561. static void error_callback(void * arg, sint8 errType) {
  562. NODE_DBG("error_callback %d\n", errType);
  563. struct espconn *conn = (struct espconn *) arg;
  564. ws_info *ws = (ws_info *) conn->reverse;
  565. ws->knownFailureCode = ((int) errType) - 100;
  566. disconnect_callback(arg);
  567. }
  568. static void dns_callback(const char *hostname, ip_addr_t *addr, void *arg) {
  569. NODE_DBG("dns_callback\n");
  570. struct espconn *conn = (struct espconn *) arg;
  571. ws_info *ws = (ws_info *) conn->reverse;
  572. if (ws->conn == NULL || ws->connectionState == 4) {
  573. return;
  574. }
  575. if (addr == NULL) {
  576. ws->knownFailureCode = -5;
  577. disconnect_callback(arg);
  578. return;
  579. }
  580. ws->connectionState = 2;
  581. os_memcpy(conn->proto.tcp->remote_ip, addr, 4);
  582. espconn_regist_connectcb(conn, connect_callback);
  583. espconn_regist_disconcb(conn, disconnect_callback);
  584. espconn_regist_reconcb(conn, error_callback);
  585. // Set connection timeout timer
  586. os_timer_disarm(&ws->timeoutTimer);
  587. os_timer_setfn(&ws->timeoutTimer, (os_timer_func_t *) ws_connectTimeout, conn);
  588. SWTIMER_REG_CB(ws_connectTimeout, SWTIMER_RESUME)
  589. os_timer_arm(&ws->timeoutTimer, WS_CONNECT_TIMEOUT_MS, false);
  590. if (ws->isSecure) {
  591. NODE_DBG("secure connecting \n");
  592. espconn_secure_connect(conn);
  593. }
  594. else {
  595. NODE_DBG("insecure connecting \n");
  596. espconn_connect(conn);
  597. }
  598. NODE_DBG("DNS found %s " IPSTR " \n", hostname, IP2STR(addr));
  599. }
  600. void ws_connect(ws_info *ws, const char *url) {
  601. NODE_DBG("ws_connect called\n");
  602. if (ws == NULL) {
  603. NODE_DBG("ws_connect ws_info argument is null!");
  604. return;
  605. }
  606. if (url == NULL) {
  607. NODE_DBG("url is null!");
  608. return;
  609. }
  610. // Extract protocol - either ws or wss
  611. bool isSecure = strncasecmp(url, PROTOCOL_SECURE, strlen(PROTOCOL_SECURE)) == 0;
  612. if (isSecure) {
  613. url += strlen(PROTOCOL_SECURE);
  614. } else {
  615. if (strncasecmp(url, PROTOCOL_INSECURE, strlen(PROTOCOL_INSECURE)) != 0) {
  616. NODE_DBG("Failed to extract protocol from: %s\n", url);
  617. if (ws->onFailure) ws->onFailure(ws, -1);
  618. return;
  619. }
  620. url += strlen(PROTOCOL_INSECURE);
  621. }
  622. // Extract path - it should start with '/'
  623. char *path = strchr(url, '/');
  624. // Extract hostname, possibly including port
  625. char hostname[256];
  626. if (path) {
  627. if (path - url >= sizeof(hostname)) {
  628. NODE_DBG("Hostname too large");
  629. if (ws->onFailure) ws->onFailure(ws, -2);
  630. return;
  631. }
  632. memcpy(hostname, url, path - url);
  633. hostname[path - url] = '\0';
  634. } else {
  635. // no path found, assuming the url only refers to the hostname and possibly the port
  636. memcpy(hostname, url, strlen(url));
  637. hostname[strlen(url)] = '\0';
  638. path = "/";
  639. }
  640. // Extract port from hostname, if available
  641. char *portInHostname = strchr(hostname, ':');
  642. int port;
  643. if (portInHostname) {
  644. port = atoi(portInHostname + 1);
  645. if (port <= 0 || port > PORT_MAX_VALUE) {
  646. NODE_DBG("Invalid port number\n");
  647. if (ws->onFailure) ws->onFailure(ws, -3);
  648. return;
  649. }
  650. hostname[strlen(hostname) - strlen(portInHostname)] = '\0'; // remove port from hostname
  651. } else {
  652. port = isSecure ? PORT_SECURE : PORT_INSECURE;
  653. }
  654. if (strlen(hostname) == 0) {
  655. NODE_DBG("Failed to extract hostname\n");
  656. if (ws->onFailure) ws->onFailure(ws, -4);
  657. return;
  658. }
  659. NODE_DBG("secure protocol = %d\n", isSecure);
  660. NODE_DBG("hostname = %s\n", hostname);
  661. NODE_DBG("port = %d\n", port);
  662. NODE_DBG("path = %s\n", path);
  663. // Prepare internal ws_info
  664. ws->connectionState = 1;
  665. ws->isSecure = isSecure;
  666. ws->hostname = strdup(hostname);
  667. ws->port = port;
  668. ws->path = strdup(path);
  669. ws->expectedSecKey = NULL;
  670. ws->knownFailureCode = 0;
  671. ws->frameBuffer = NULL;
  672. ws->frameBufferLen = 0;
  673. ws->payloadBuffer = NULL;
  674. ws->payloadBufferLen = 0;
  675. ws->payloadOriginalOpCode = 0;
  676. ws->unhealthyPoints = 0;
  677. // Prepare espconn
  678. struct espconn *conn = (struct espconn *) calloc(1,sizeof(struct espconn));
  679. conn->type = ESPCONN_TCP;
  680. conn->state = ESPCONN_NONE;
  681. conn->proto.tcp = (esp_tcp *) calloc(1,sizeof(esp_tcp));
  682. conn->proto.tcp->local_port = espconn_port();
  683. conn->proto.tcp->remote_port = ws->port;
  684. conn->reverse = ws;
  685. ws->conn = conn;
  686. // Attempt to resolve hostname address
  687. ip_addr_t addr;
  688. err_t result = dns_gethostbyname(hostname, &addr, dns_callback, conn);
  689. if (result == ERR_INPROGRESS) {
  690. NODE_DBG("DNS pending\n");
  691. } else {
  692. dns_callback(hostname, &addr, conn);
  693. }
  694. return;
  695. }
  696. void ws_send(ws_info *ws, int opCode, const char *message, unsigned short length) {
  697. NODE_DBG("ws_send\n");
  698. ws_sendFrame(ws->conn, opCode, message, length);
  699. }
  700. static void ws_forceCloseTimeout(void *arg) {
  701. NODE_DBG("ws_forceCloseTimeout\n");
  702. struct espconn *conn = (struct espconn *) arg;
  703. ws_info *ws = (ws_info *) conn->reverse;
  704. if (ws->connectionState == 0 || ws->connectionState == 4) {
  705. return;
  706. }
  707. if (ws->isSecure)
  708. espconn_secure_disconnect(ws->conn);
  709. else
  710. espconn_disconnect(ws->conn);
  711. }
  712. void ws_close(ws_info *ws) {
  713. NODE_DBG("ws_close\n");
  714. if (ws->connectionState == 0 || ws->connectionState == 4) {
  715. return;
  716. }
  717. ws->knownFailureCode = 0; // no error as user requested to close
  718. if (ws->connectionState == 1) {
  719. disconnect_callback(ws->conn);
  720. } else {
  721. ws_sendFrame(ws->conn, WS_OPCODE_CLOSE, NULL, 0);
  722. os_timer_disarm(&ws->timeoutTimer);
  723. os_timer_setfn(&ws->timeoutTimer, (os_timer_func_t *) ws_forceCloseTimeout, ws->conn);
  724. SWTIMER_REG_CB(ws_forceCloseTimeout, SWTIMER_RESUME);
  725. os_timer_arm(&ws->timeoutTimer, WS_FORCE_CLOSE_TIMEOUT_MS, false);
  726. }
  727. }