gagent_httpc.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. /*
  2. * File : gagent_httpc.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2018, RT-Thread Development Team
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program; if not, write to the Free Software Foundation, Inc.,
  18. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. *
  20. * Change Logs:
  21. * Date Author Notes
  22. * 2018-01-03 flyingcys first version
  23. */
  24. #include "gagent_def.h"
  25. #include "gagent_cloud.h"
  26. #include "aes.h"
  27. #define MAX_HTTPC_URL_LEN 1024
  28. #define MAX_HTTPC_RECV_LEN 2048
  29. struct cloud_httpc
  30. {
  31. char *recv_buf;
  32. int recv_len;
  33. };
  34. static struct cloud_httpc httpc;
  35. typedef int (*WEBCLIENT_CUSTOM_RESPONSE_CB)(size_t total, size_t offset, char *from, size_t from_len);
  36. static int webclient_common(int method, const char *URI,
  37. const char * data, size_t data_sz,
  38. WEBCLIENT_CUSTOM_RESPONSE_CB webclient_custom_response_cb)
  39. {
  40. struct webclient_session *session = RT_NULL;
  41. char *header = RT_NULL, *header_ptr;
  42. size_t header_sz = 0;
  43. int rc = WEBCLIENT_OK;
  44. int length = 0;
  45. size_t total = 0, offset = 0;
  46. rt_uint8_t *buffer = RT_NULL;
  47. header = (char *)rt_malloc(WEBCLIENT_HEADER_BUFSZ);
  48. if(RT_NULL == header)
  49. {
  50. gagent_err("malloc failed!\n");
  51. rc = -WEBCLIENT_NOMEM;
  52. goto __exit;
  53. }
  54. rt_memset(header, 0, WEBCLIENT_HEADER_BUFSZ);
  55. header_ptr = header;
  56. header_ptr += rt_snprintf(header_ptr,
  57. WEBCLIENT_HEADER_BUFSZ - (header_ptr - header),
  58. "Content-Type: application/x-www-form-urlencoded;charset:UTF-8\r\n");
  59. if(data)
  60. {
  61. header_ptr += rt_snprintf(header_ptr,
  62. WEBCLIENT_HEADER_BUFSZ - (header_ptr - header),
  63. "Content-Length:%d\r\n", strlen(data));
  64. }
  65. header_sz = header_ptr - header;
  66. session = webclient_open_custom(URI, method, header, header_sz, data, data_sz);
  67. if(RT_NULL == session)
  68. {
  69. gagent_err("webclient_open_custom failed!\n");
  70. rc = -WEBCLIENT_OK;
  71. goto __exit;
  72. }
  73. gagent_dbg("response:%d\n",session->response);
  74. buffer = (rt_uint8_t *)rt_malloc(WEBCLIENT_RESPONSE_BUFSZ);
  75. if(RT_NULL == buffer)
  76. {
  77. gagent_err("malloc failed!\n");
  78. rc = -WEBCLIENT_NOMEM;
  79. goto __exit;
  80. }
  81. if(session->chunk_sz > 0)
  82. {
  83. gagent_dbg("chunk_sz:%d\n", session->chunk_sz);
  84. total = session->chunk_sz;
  85. }
  86. else if(session->content_length > 0)
  87. {
  88. gagent_dbg("content_length:%d content_length_remainder:%d\n", session->content_length, session->content_length_remainder);
  89. total = session->content_length;
  90. }
  91. while(total != offset)
  92. {
  93. memset(buffer, 0, WEBCLIENT_RESPONSE_BUFSZ);
  94. length = webclient_read(session, buffer, WEBCLIENT_RESPONSE_BUFSZ);
  95. if(length <= 0)
  96. {
  97. rc = length;
  98. break;
  99. }
  100. if(webclient_custom_response_cb)
  101. webclient_custom_response_cb(total, offset, (char *)buffer, (int)length);
  102. offset += length;
  103. }
  104. __exit:
  105. if(RT_NULL != buffer)
  106. {
  107. rt_free(buffer);
  108. buffer = RT_NULL;
  109. }
  110. if(RT_NULL != header)
  111. {
  112. rt_free(header);
  113. header = RT_NULL;
  114. }
  115. if(RT_NULL != session)
  116. {
  117. webclient_close(session);
  118. session = RT_NULL;
  119. }
  120. return rc;
  121. }
  122. int webclient_get(const char *URI, WEBCLIENT_CUSTOM_RESPONSE_CB webclient_custom_response_cb)
  123. {
  124. return webclient_common(WEBCLIENT_GET, URI, NULL, 0, webclient_custom_response_cb);
  125. }
  126. int webclient_post(const char *URI, const char * data, size_t data_sz,
  127. WEBCLIENT_CUSTOM_RESPONSE_CB webclient_custom_response_cb)
  128. {
  129. return webclient_common(WEBCLIENT_POST, URI, data, data_sz, webclient_custom_response_cb);
  130. }
  131. int gagent_cloud_httpc_cb(size_t total, size_t offset, char *from, size_t from_len)
  132. {
  133. extern cloud_st *cloud;
  134. gagent_dbg("total:%d offset:%d len:%d\n", total, offset, from_len);
  135. gagent_dbg("buf:%s\n", from);
  136. rt_memset(httpc.recv_buf, 0, MAX_HTTPC_RECV_LEN);
  137. rt_memcpy(httpc.recv_buf, from, from_len);
  138. httpc.recv_len = from_len;
  139. return RT_EOK;
  140. }
  141. int gagent_cloud_register(cloud_st *cloud)
  142. {
  143. int rc = RT_EOK;
  144. int content_len, aes_len, i;
  145. //
  146. char *content = RT_NULL;
  147. char *url = RT_NULL;
  148. char *ptr = RT_NULL;
  149. uint8_t aes_key[16];
  150. char *aes_buf = RT_NULL;
  151. aes_context *aes_ctx = RT_NULL;
  152. content = (char *)rt_malloc(256);
  153. if(RT_NULL == content)
  154. {
  155. gagent_err("malloc faield!\n");
  156. rc = -RT_ENOMEM;
  157. goto __exit;
  158. }
  159. aes_buf = (char *)rt_malloc(256);
  160. if(RT_NULL == aes_buf)
  161. {
  162. rc = -RT_ENOMEM;
  163. goto __exit;
  164. }
  165. //data
  166. rt_memset(content, 0, 256);
  167. rt_snprintf((char *)content, 256, "mac=%02x%02x%02x%02x%02x%02x&passcode=%s&type=%s", \
  168. cloud->con->mac[0], cloud->con->mac[1], cloud->con->mac[2], cloud->con->mac[3], cloud->con->mac[4], cloud->con->mac[5], \
  169. cloud->con->passcode, "normal");
  170. content_len = strlen(content);
  171. rt_memset(aes_key, 0, sizeof(aes_key));
  172. gagent_strtohex((char *)aes_key, cloud->con->pk_secret, strlen(cloud->con->pk_secret) > 32 ? 32 : strlen(cloud->con->pk_secret));
  173. gagent_dbg("content:%s, pk_secret:%s\n", content, cloud->con->pk_secret);
  174. aes_ctx = (aes_context *)rt_malloc(sizeof(aes_context));
  175. if(RT_NULL == aes_ctx)
  176. {
  177. rc = -RT_ENOMEM;
  178. goto __exit;
  179. }
  180. rt_memset(aes_ctx, 0, sizeof(aes_context));
  181. aes_setkey_enc(aes_ctx, aes_key, 128);
  182. //
  183. rt_memset(aes_buf, 0, 256);
  184. content_len = strlen(content);
  185. if(content_len % 16)
  186. content_len = gagent_add_pkcs(content, content_len);
  187. aes_len = 0;
  188. for(i = 0; i < content_len; i += 16)
  189. {
  190. aes_crypt_ecb(aes_ctx, AES_ENCRYPT, (uint8_t *)content + i, (uint8_t *)aes_buf + i);
  191. aes_len += 16;
  192. }
  193. ptr = content;
  194. rt_memset(ptr, 0, 256);
  195. strcpy(ptr, "data=");
  196. ptr += strlen("data=");
  197. if(aes_len > 0)
  198. {
  199. for(i = 0; i < aes_len; i ++)
  200. {
  201. ptr += rt_snprintf(ptr, 256 - (ptr - content), "%02x", aes_buf[i]);
  202. }
  203. }
  204. gagent_dbg("content:%s\n", content);
  205. url = (char *)rt_malloc(MAX_HTTPC_URL_LEN);
  206. if(RT_NULL == url)
  207. {
  208. rc = -RT_ENOMEM;
  209. goto __exit;
  210. }
  211. ptr = url;
  212. memset(ptr, 0, MAX_HTTPC_URL_LEN);
  213. //url
  214. ptr += rt_snprintf(ptr, MAX_HTTPC_URL_LEN - (ptr - url), "http://%s:%s", G_SERVICE_DOMAIN, G_SERVICE_PORT);
  215. ptr += rt_snprintf(ptr, MAX_HTTPC_URL_LEN - (ptr - url), "/dev/%s/device", cloud->con->pk);
  216. gagent_dbg("url:%s\n", url);
  217. httpc.recv_buf = RT_NULL;
  218. httpc.recv_buf = (char *)rt_malloc(MAX_HTTPC_RECV_LEN);
  219. if(RT_NULL == httpc.recv_buf)
  220. {
  221. rc = -RT_ENOMEM;
  222. goto __exit;
  223. }
  224. rc = webclient_post((const char *)url, (const char *)content, strlen(content), gagent_cloud_httpc_cb);
  225. if(rc != RT_EOK)
  226. {
  227. gagent_err("weblient_post failed!\n");
  228. goto __exit;
  229. }
  230. //
  231. rt_memset(content, 0, 256);
  232. aes_len = gagent_strtohex((char *)content, (char *)httpc.recv_buf, httpc.recv_len);
  233. rt_memset(aes_ctx, 0, sizeof(aes_context));
  234. aes_setkey_dec(aes_ctx, aes_key, 128);
  235. rt_memset(aes_buf, 0, 256);
  236. for(i = 0; i < aes_len; i += 16)
  237. aes_crypt_ecb(aes_ctx, AES_DECRYPT, (uint8_t *)content + i, (uint8_t *)aes_buf + i);
  238. gagent_dbg("%s\n", aes_buf);
  239. if(strstr(aes_buf, "did=") != NULL)
  240. rt_memcpy(cloud->con->did, aes_buf + strlen("did="), DID_LENGTH);
  241. __exit:
  242. if(RT_NULL != httpc.recv_buf)
  243. {
  244. rt_free(httpc.recv_buf);
  245. httpc.recv_buf = RT_NULL;
  246. }
  247. if(RT_NULL != url)
  248. {
  249. rt_free(url);
  250. url = RT_NULL;
  251. }
  252. if(RT_NULL != aes_ctx)
  253. {
  254. rt_free(aes_ctx);
  255. aes_ctx = RT_NULL;
  256. }
  257. if(RT_NULL != aes_buf)
  258. {
  259. rt_free(aes_buf);
  260. aes_buf = RT_NULL;
  261. }
  262. if(RT_NULL != content)
  263. {
  264. rt_free(content);
  265. content = RT_NULL;
  266. }
  267. return rc;
  268. }
  269. int gagent_cloud_provision(cloud_st *cloud)
  270. {
  271. int rc = RT_EOK;
  272. int content_len, aes_len, i;
  273. char *url = RT_NULL;
  274. char *content = RT_NULL;
  275. char *ptr = RT_NULL;
  276. char *ptr_tail = RT_NULL;
  277. char aes_key[16];
  278. char *aes_buf = RT_NULL;
  279. aes_context *aes_ctx = RT_NULL;
  280. content = (char *)rt_malloc(256);
  281. if(RT_NULL == content)
  282. {
  283. rc = -RT_ENOMEM;
  284. goto __exit;
  285. }
  286. aes_buf = (char *)rt_malloc(256);
  287. if(RT_NULL == aes_buf)
  288. {
  289. rc = -RT_ENOMEM;
  290. goto __exit;
  291. }
  292. //data
  293. rt_memset(content, 0, 256);
  294. strcpy(content, cloud->con->did);
  295. rt_memset(aes_key, 0, sizeof(aes_key));
  296. gagent_strtohex((char *)aes_key, cloud->con->pk_secret, strlen(cloud->con->pk_secret) > 32 ? 32 : strlen(cloud->con->pk_secret));
  297. gagent_dbg("content:%s, pk_secret:%s\n", content, cloud->con->pk_secret);
  298. aes_ctx = (aes_context *)rt_malloc(sizeof(aes_context));
  299. if(RT_NULL == aes_ctx)
  300. {
  301. rc = -RT_ENOMEM;
  302. goto __exit;
  303. }
  304. rt_memset(aes_ctx, 0, sizeof(aes_context));
  305. aes_setkey_enc(aes_ctx, (uint8_t *)aes_key, 128);
  306. //
  307. rt_memset(aes_buf, 0, 256);
  308. content_len = strlen(content);
  309. if(content_len % 16)
  310. content_len = gagent_add_pkcs(content, content_len);
  311. aes_len = 0;
  312. for(i = 0; i < content_len; i += 16)
  313. {
  314. aes_crypt_ecb(aes_ctx, AES_ENCRYPT, (uint8_t *)content + i, (uint8_t *)aes_buf + i);
  315. aes_len += 16;
  316. }
  317. ptr = content;
  318. if(aes_len > 0)
  319. {
  320. for(i = 0; i < aes_len; i ++)
  321. {
  322. ptr += rt_snprintf(ptr, 256 - (ptr - content), "%02x", aes_buf[i]);
  323. }
  324. }
  325. gagent_dbg("content:%s\n", content);
  326. url = (char *)rt_malloc(MAX_HTTPC_URL_LEN);
  327. if(RT_NULL == url)
  328. {
  329. rc = -RT_ENOMEM;
  330. return rc;
  331. }
  332. ptr = url;
  333. rt_memset(url, 0, MAX_HTTPC_URL_LEN);
  334. //url
  335. ptr += rt_snprintf(ptr, MAX_HTTPC_URL_LEN - (ptr - url), "http://%s:%s", G_SERVICE_DOMAIN, G_SERVICE_PORT);
  336. ptr += rt_snprintf(ptr, MAX_HTTPC_URL_LEN - (ptr - url), "/dev/%s/device?", cloud->con->pk);
  337. ptr += rt_snprintf(ptr, MAX_HTTPC_URL_LEN - (ptr - url), "did=%s", content);
  338. gagent_dbg("url:%s\n", url);
  339. //
  340. rt_memset(cloud->mqtt_server, 0, sizeof(cloud->mqtt_server));
  341. rt_memcpy(cloud->mqtt_server, G_M2M_DOMAIN, sizeof(G_M2M_DOMAIN));
  342. //
  343. cloud->mqtt_port = 0;
  344. cloud->mqtt_port = atoi(G_M2M_PORT);
  345. httpc.recv_buf = RT_NULL;
  346. httpc.recv_buf = (char *)rt_malloc(MAX_HTTPC_RECV_LEN);
  347. if(RT_NULL == httpc.recv_buf)
  348. {
  349. rc = -RT_ENOMEM;
  350. goto __exit;
  351. }
  352. rc = webclient_get((const char *)url, gagent_cloud_httpc_cb);
  353. if(rc != RT_EOK)
  354. {
  355. rt_kprintf("weblient_post failed!\n");
  356. goto __exit;
  357. }
  358. rt_memset(content, 0, 256);
  359. aes_len = gagent_strtohex(content, httpc.recv_buf, httpc.recv_len);
  360. rt_memset(aes_ctx, 0, sizeof(aes_context));
  361. aes_setkey_dec(aes_ctx, (uint8_t *)aes_key, 128);
  362. rt_memset(aes_buf, 0, 256);
  363. for(i = 0; i < aes_len; i += 16)
  364. aes_crypt_ecb(aes_ctx, AES_DECRYPT, (uint8_t *)content + i, (uint8_t *)aes_buf + i);
  365. gagent_dbg("%s\n", aes_buf);
  366. //mqtt_server
  367. ptr = strstr(aes_buf, "host=");
  368. if(ptr > 0)
  369. {
  370. ptr += strlen("host=");
  371. ptr_tail = strchr(ptr, '&');
  372. if(ptr_tail > 0)
  373. {
  374. rt_memset(cloud->mqtt_server, 0, sizeof(cloud->mqtt_server));
  375. rt_memcpy(cloud->mqtt_server, ptr, (ptr_tail - ptr));
  376. }
  377. }
  378. //mqtt_port
  379. ptr = strstr(aes_buf, "port=");
  380. if(ptr > 0)
  381. {
  382. ptr += strlen("port=");
  383. ptr_tail = strchr(ptr, '&');
  384. if(ptr_tail > 0)
  385. {
  386. *ptr_tail = '\0';
  387. cloud->mqtt_port = 0;
  388. cloud->mqtt_port = atoi(ptr);
  389. }
  390. }
  391. gagent_dbg("mqtt_server:%s port:%d\n", cloud->mqtt_server, cloud->mqtt_port);
  392. __exit:
  393. if(RT_NULL != httpc.recv_buf)
  394. {
  395. rt_free(httpc.recv_buf);
  396. httpc.recv_buf = RT_NULL;
  397. }
  398. if(RT_NULL != url)
  399. {
  400. rt_free(url);
  401. url = RT_NULL;
  402. }
  403. if(RT_NULL != aes_ctx)
  404. {
  405. rt_free(aes_ctx);
  406. aes_ctx = RT_NULL;
  407. }
  408. if(RT_NULL != aes_buf)
  409. {
  410. rt_free(aes_buf);
  411. aes_buf = RT_NULL;
  412. }
  413. if(RT_NULL != content)
  414. {
  415. rt_free(content);
  416. content = RT_NULL;
  417. }
  418. return rc;
  419. }
  420. int gagent_cloud_check_ota(cloud_st *cloud)
  421. {
  422. int rc = RT_EOK;
  423. char *url = RT_NULL;
  424. char *content = RT_NULL;
  425. char *ptr = RT_NULL;
  426. content = (char *)rt_malloc(256);
  427. if(RT_NULL == content)
  428. {
  429. gagent_err("malloc faield!\n");
  430. rc = -RT_ENOMEM;
  431. goto __exit;
  432. }
  433. //data
  434. rt_memset(content, 0, 256);
  435. rt_snprintf((char *)content, 256, "passcode=%s&type=%d&hard_version=%s&soft_version=%s", \
  436. cloud->con->passcode, GAGENT_HARD_SOC, cloud->con->hard_version, cloud->con->soft_version);
  437. gagent_dbg("content:%s\n", content);
  438. url = (char *)rt_malloc(MAX_HTTPC_URL_LEN);
  439. if(RT_NULL == url)
  440. {
  441. rc = -RT_ENOMEM;
  442. return rc;
  443. }
  444. ptr = url;
  445. rt_memset(url, 0, MAX_HTTPC_URL_LEN);
  446. //url
  447. ptr += rt_snprintf(ptr, MAX_HTTPC_URL_LEN - (ptr - url), "http://%s:%s", G_SERVICE_DOMAIN, G_SERVICE_PORT);
  448. ptr += rt_snprintf(ptr, MAX_HTTPC_URL_LEN - (ptr - url), "/dev/ota/v4.1/update_and_check/%s", cloud->con->did);
  449. gagent_dbg("url:%s\n", url);
  450. httpc.recv_buf = RT_NULL;
  451. httpc.recv_buf = (char *)rt_malloc(MAX_HTTPC_RECV_LEN);
  452. if(RT_NULL != httpc.recv_buf)
  453. {
  454. rc = -RT_ENOMEM;
  455. goto __exit;
  456. }
  457. rc = webclient_post((const char *)url, (const char *)content, strlen(content), gagent_cloud_httpc_cb);
  458. if(rc != RT_EOK)
  459. {
  460. gagent_err("weblient_post failed!\n");
  461. goto __exit;
  462. }
  463. __exit:
  464. if(RT_NULL != httpc.recv_buf)
  465. rt_free(httpc.recv_buf);
  466. if(RT_NULL != url)
  467. rt_free(url);
  468. if(RT_NULL != content)
  469. rt_free(content);
  470. return rc;
  471. }