httpd_main.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. // Copyright 2018 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include <string.h>
  15. #include <sys/socket.h>
  16. #include <sys/param.h>
  17. #include <errno.h>
  18. #include <esp_log.h>
  19. #include <esp_err.h>
  20. #include <assert.h>
  21. #include <esp_http_server.h>
  22. #include "esp_httpd_priv.h"
  23. #include "ctrl_sock.h"
  24. static const char *TAG = "httpd";
  25. static esp_err_t httpd_accept_conn(struct httpd_data *hd, int listen_fd)
  26. {
  27. /* If no space is available for new session, close the least recently used one */
  28. if (hd->config.lru_purge_enable == true) {
  29. if (!httpd_is_sess_available(hd)) {
  30. /* Queue asynchronous closure of the least recently used session */
  31. return httpd_sess_close_lru(hd);
  32. /* Returning from this allowes the main server thread to process
  33. * the queued asynchronous control message for closing LRU session.
  34. * Since connection request hasn't been addressed yet using accept()
  35. * therefore httpd_accept_conn() will be called again, but this time
  36. * with space available for one session
  37. */
  38. }
  39. }
  40. struct sockaddr_in addr_from;
  41. socklen_t addr_from_len = sizeof(addr_from);
  42. int new_fd = accept(listen_fd, (struct sockaddr *)&addr_from, &addr_from_len);
  43. if (new_fd < 0) {
  44. ESP_LOGW(TAG, LOG_FMT("error in accept (%d)"), errno);
  45. return ESP_FAIL;
  46. }
  47. ESP_LOGD(TAG, LOG_FMT("newfd = %d"), new_fd);
  48. struct timeval tv;
  49. /* Set recv timeout of this fd as per config */
  50. tv.tv_sec = hd->config.recv_wait_timeout;
  51. tv.tv_usec = 0;
  52. setsockopt(new_fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));
  53. /* Set send timeout of this fd as per config */
  54. tv.tv_sec = hd->config.send_wait_timeout;
  55. tv.tv_usec = 0;
  56. setsockopt(new_fd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&tv, sizeof(tv));
  57. if (ESP_OK != httpd_sess_new(hd, new_fd)) {
  58. ESP_LOGW(TAG, LOG_FMT("session creation failed"));
  59. close(new_fd);
  60. return ESP_FAIL;
  61. }
  62. ESP_LOGD(TAG, LOG_FMT("complete"));
  63. return ESP_OK;
  64. }
  65. struct httpd_ctrl_data {
  66. enum httpd_ctrl_msg {
  67. HTTPD_CTRL_SHUTDOWN,
  68. HTTPD_CTRL_WORK,
  69. } hc_msg;
  70. httpd_work_fn_t hc_work;
  71. void *hc_work_arg;
  72. };
  73. esp_err_t httpd_queue_work(httpd_handle_t handle, httpd_work_fn_t work, void *arg)
  74. {
  75. if (handle == NULL || work == NULL) {
  76. return ESP_ERR_INVALID_ARG;
  77. }
  78. struct httpd_data *hd = (struct httpd_data *) handle;
  79. struct httpd_ctrl_data msg = {
  80. .hc_msg = HTTPD_CTRL_WORK,
  81. .hc_work = work,
  82. .hc_work_arg = arg,
  83. };
  84. int ret = cs_send_to_ctrl_sock(hd->msg_fd, hd->config.ctrl_port, &msg, sizeof(msg));
  85. if (ret < 0) {
  86. ESP_LOGW(TAG, LOG_FMT("failed to queue work"));
  87. return ESP_FAIL;
  88. }
  89. return ESP_OK;
  90. }
  91. void *httpd_get_global_user_ctx(httpd_handle_t handle)
  92. {
  93. return ((struct httpd_data *)handle)->config.global_user_ctx;
  94. }
  95. void *httpd_get_global_transport_ctx(httpd_handle_t handle)
  96. {
  97. return ((struct httpd_data *)handle)->config.global_transport_ctx;
  98. }
  99. static void httpd_close_all_sessions(struct httpd_data *hd)
  100. {
  101. int fd = -1;
  102. while ((fd = httpd_sess_iterate(hd, fd)) != -1) {
  103. ESP_LOGD(TAG, LOG_FMT("cleaning up socket %d"), fd);
  104. httpd_sess_delete(hd, fd);
  105. close(fd);
  106. }
  107. }
  108. static void httpd_process_ctrl_msg(struct httpd_data *hd)
  109. {
  110. struct httpd_ctrl_data msg;
  111. int ret = recv(hd->ctrl_fd, &msg, sizeof(msg), 0);
  112. if (ret <= 0) {
  113. ESP_LOGW(TAG, LOG_FMT("error in recv (%d)"), errno);
  114. return;
  115. }
  116. if (ret != sizeof(msg)) {
  117. ESP_LOGW(TAG, LOG_FMT("incomplete msg"));
  118. return;
  119. }
  120. switch (msg.hc_msg) {
  121. case HTTPD_CTRL_WORK:
  122. if (msg.hc_work) {
  123. ESP_LOGD(TAG, LOG_FMT("work"));
  124. (*msg.hc_work)(msg.hc_work_arg);
  125. }
  126. break;
  127. case HTTPD_CTRL_SHUTDOWN:
  128. ESP_LOGD(TAG, LOG_FMT("shutdown"));
  129. hd->hd_td.status = THREAD_STOPPING;
  130. break;
  131. default:
  132. break;
  133. }
  134. }
  135. /* Manage in-coming connection or data requests */
  136. static esp_err_t httpd_server(struct httpd_data *hd)
  137. {
  138. fd_set read_set;
  139. FD_ZERO(&read_set);
  140. if (hd->config.lru_purge_enable || httpd_is_sess_available(hd)) {
  141. /* Only listen for new connections if server has capacity to
  142. * handle more (or when LRU purge is enabled, in which case
  143. * older connections will be closed) */
  144. FD_SET(hd->listen_fd, &read_set);
  145. }
  146. FD_SET(hd->ctrl_fd, &read_set);
  147. int tmp_max_fd;
  148. httpd_sess_set_descriptors(hd, &read_set, &tmp_max_fd);
  149. int maxfd = MAX(hd->listen_fd, tmp_max_fd);
  150. tmp_max_fd = maxfd;
  151. maxfd = MAX(hd->ctrl_fd, tmp_max_fd);
  152. ESP_LOGD(TAG, LOG_FMT("doing select maxfd+1 = %d"), maxfd + 1);
  153. int active_cnt = select(maxfd + 1, &read_set, NULL, NULL, NULL);
  154. if (active_cnt < 0) {
  155. ESP_LOGE(TAG, LOG_FMT("error in select (%d)"), errno);
  156. httpd_sess_delete_invalid(hd);
  157. return ESP_OK;
  158. }
  159. /* Case0: Do we have a control message? */
  160. if (FD_ISSET(hd->ctrl_fd, &read_set)) {
  161. ESP_LOGD(TAG, LOG_FMT("processing ctrl message"));
  162. httpd_process_ctrl_msg(hd);
  163. if (hd->hd_td.status == THREAD_STOPPING) {
  164. ESP_LOGD(TAG, LOG_FMT("stopping thread"));
  165. return ESP_FAIL;
  166. }
  167. }
  168. /* Case1: Do we have any activity on the current data
  169. * sessions? */
  170. int fd = -1;
  171. while ((fd = httpd_sess_iterate(hd, fd)) != -1) {
  172. if (FD_ISSET(fd, &read_set) || (httpd_sess_pending(hd, fd))) {
  173. ESP_LOGD(TAG, LOG_FMT("processing socket %d"), fd);
  174. if (httpd_sess_process(hd, fd) != ESP_OK) {
  175. ESP_LOGD(TAG, LOG_FMT("closing socket %d"), fd);
  176. close(fd);
  177. /* Delete session and update fd to that
  178. * preceding the one being deleted */
  179. fd = httpd_sess_delete(hd, fd);
  180. }
  181. }
  182. }
  183. /* Case2: Do we have any incoming connection requests to
  184. * process? */
  185. if (FD_ISSET(hd->listen_fd, &read_set)) {
  186. ESP_LOGD(TAG, LOG_FMT("processing listen socket %d"), hd->listen_fd);
  187. if (httpd_accept_conn(hd, hd->listen_fd) != ESP_OK) {
  188. ESP_LOGW(TAG, LOG_FMT("error accepting new connection"));
  189. }
  190. }
  191. return ESP_OK;
  192. }
  193. /* The main HTTPD thread */
  194. static void httpd_thread(void *arg)
  195. {
  196. int ret;
  197. struct httpd_data *hd = (struct httpd_data *) arg;
  198. hd->hd_td.status = THREAD_RUNNING;
  199. ESP_LOGD(TAG, LOG_FMT("web server started"));
  200. while (1) {
  201. ret = httpd_server(hd);
  202. if (ret != ESP_OK) {
  203. break;
  204. }
  205. }
  206. ESP_LOGD(TAG, LOG_FMT("web server exiting"));
  207. close(hd->msg_fd);
  208. cs_free_ctrl_sock(hd->ctrl_fd);
  209. httpd_close_all_sessions(hd);
  210. close(hd->listen_fd);
  211. hd->hd_td.status = THREAD_STOPPED;
  212. httpd_os_thread_delete();
  213. }
  214. static esp_err_t httpd_server_init(struct httpd_data *hd)
  215. {
  216. int fd = socket(PF_INET6, SOCK_STREAM, 0);
  217. if (fd < 0) {
  218. ESP_LOGE(TAG, LOG_FMT("error in socket (%d)"), errno);
  219. return ESP_FAIL;
  220. }
  221. struct in6_addr inaddr_any = IN6ADDR_ANY_INIT;
  222. struct sockaddr_in6 serv_addr = {
  223. .sin6_family = PF_INET6,
  224. .sin6_addr = inaddr_any,
  225. .sin6_port = htons(hd->config.server_port)
  226. };
  227. /* Enable SO_REUSEADDR to allow binding to the same
  228. * address and port when restarting the server */
  229. int enable = 1;
  230. if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) < 0) {
  231. /* This will fail if CONFIG_LWIP_SO_REUSE is not enabled. But
  232. * it does not affect the normal working of the HTTP Server */
  233. ESP_LOGW(TAG, LOG_FMT("error enabling SO_REUSEADDR (%d)"), errno);
  234. }
  235. int ret = bind(fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
  236. if (ret < 0) {
  237. ESP_LOGE(TAG, LOG_FMT("error in bind (%d)"), errno);
  238. close(fd);
  239. return ESP_FAIL;
  240. }
  241. ret = listen(fd, hd->config.backlog_conn);
  242. if (ret < 0) {
  243. ESP_LOGE(TAG, LOG_FMT("error in listen (%d)"), errno);
  244. close(fd);
  245. return ESP_FAIL;
  246. }
  247. int ctrl_fd = cs_create_ctrl_sock(hd->config.ctrl_port);
  248. if (ctrl_fd < 0) {
  249. ESP_LOGE(TAG, LOG_FMT("error in creating ctrl socket (%d)"), errno);
  250. close(fd);
  251. return ESP_FAIL;
  252. }
  253. int msg_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  254. if (msg_fd < 0) {
  255. ESP_LOGE(TAG, LOG_FMT("error in creating msg socket (%d)"), errno);
  256. close(fd);
  257. close(ctrl_fd);
  258. return ESP_FAIL;
  259. }
  260. hd->listen_fd = fd;
  261. hd->ctrl_fd = ctrl_fd;
  262. hd->msg_fd = msg_fd;
  263. return ESP_OK;
  264. }
  265. static struct httpd_data *httpd_create(const httpd_config_t *config)
  266. {
  267. /* Allocate memory for httpd instance data */
  268. struct httpd_data *hd = calloc(1, sizeof(struct httpd_data));
  269. if (!hd) {
  270. ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP server instance"));
  271. return NULL;
  272. }
  273. hd->hd_calls = calloc(config->max_uri_handlers, sizeof(httpd_uri_t *));
  274. if (!hd->hd_calls) {
  275. ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP URI handlers"));
  276. free(hd);
  277. return NULL;
  278. }
  279. hd->hd_sd = calloc(config->max_open_sockets, sizeof(struct sock_db));
  280. if (!hd->hd_sd) {
  281. ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP session data"));
  282. free(hd->hd_calls);
  283. free(hd);
  284. return NULL;
  285. }
  286. struct httpd_req_aux *ra = &hd->hd_req_aux;
  287. ra->resp_hdrs = calloc(config->max_resp_headers, sizeof(struct resp_hdr));
  288. if (!ra->resp_hdrs) {
  289. ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP response headers"));
  290. free(hd->hd_sd);
  291. free(hd->hd_calls);
  292. free(hd);
  293. return NULL;
  294. }
  295. hd->err_handler_fns = calloc(HTTPD_ERR_CODE_MAX, sizeof(httpd_err_handler_func_t));
  296. if (!hd->err_handler_fns) {
  297. ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP error handlers"));
  298. free(ra->resp_hdrs);
  299. free(hd->hd_sd);
  300. free(hd->hd_calls);
  301. free(hd);
  302. return NULL;
  303. }
  304. /* Save the configuration for this instance */
  305. hd->config = *config;
  306. return hd;
  307. }
  308. static void httpd_delete(struct httpd_data *hd)
  309. {
  310. struct httpd_req_aux *ra = &hd->hd_req_aux;
  311. /* Free memory of httpd instance data */
  312. free(hd->err_handler_fns);
  313. free(ra->resp_hdrs);
  314. free(hd->hd_sd);
  315. /* Free registered URI handlers */
  316. httpd_unregister_all_uri_handlers(hd);
  317. free(hd->hd_calls);
  318. free(hd);
  319. }
  320. esp_err_t httpd_start(httpd_handle_t *handle, const httpd_config_t *config)
  321. {
  322. if (handle == NULL || config == NULL) {
  323. return ESP_ERR_INVALID_ARG;
  324. }
  325. /* Sanity check about whether LWIP is configured for providing the
  326. * maximum number of open sockets sufficient for the server. Though,
  327. * this check doesn't guarantee that many sockets will actually be
  328. * available at runtime as other processes may use up some sockets.
  329. * Note that server also uses 3 sockets for its internal use :
  330. * 1) listening for new TCP connections
  331. * 2) for sending control messages over UDP
  332. * 3) for receiving control messages over UDP
  333. * So the total number of required sockets is max_open_sockets + 3
  334. */
  335. if (CONFIG_LWIP_MAX_SOCKETS < config->max_open_sockets + 3) {
  336. ESP_LOGE(TAG, "Configuration option max_open_sockets is too large (max allowed %d)\n\t"
  337. "Either decrease this or configure LWIP_MAX_SOCKETS to a larger value",
  338. CONFIG_LWIP_MAX_SOCKETS - 3);
  339. return ESP_ERR_INVALID_ARG;
  340. }
  341. struct httpd_data *hd = httpd_create(config);
  342. if (hd == NULL) {
  343. /* Failed to allocate memory */
  344. return ESP_ERR_HTTPD_ALLOC_MEM;
  345. }
  346. if (httpd_server_init(hd) != ESP_OK) {
  347. httpd_delete(hd);
  348. return ESP_FAIL;
  349. }
  350. httpd_sess_init(hd);
  351. if (httpd_os_thread_create(&hd->hd_td.handle, "httpd",
  352. hd->config.stack_size,
  353. hd->config.task_priority,
  354. httpd_thread, hd,
  355. hd->config.core_id) != ESP_OK) {
  356. /* Failed to launch task */
  357. httpd_delete(hd);
  358. return ESP_ERR_HTTPD_TASK;
  359. }
  360. *handle = (httpd_handle_t *)hd;
  361. return ESP_OK;
  362. }
  363. esp_err_t httpd_stop(httpd_handle_t handle)
  364. {
  365. struct httpd_data *hd = (struct httpd_data *) handle;
  366. if (hd == NULL) {
  367. return ESP_ERR_INVALID_ARG;
  368. }
  369. struct httpd_ctrl_data msg;
  370. memset(&msg, 0, sizeof(msg));
  371. msg.hc_msg = HTTPD_CTRL_SHUTDOWN;
  372. cs_send_to_ctrl_sock(hd->msg_fd, hd->config.ctrl_port, &msg, sizeof(msg));
  373. ESP_LOGD(TAG, LOG_FMT("sent control msg to stop server"));
  374. while (hd->hd_td.status != THREAD_STOPPED) {
  375. httpd_os_thread_sleep(100);
  376. }
  377. /* Release global user context, if not NULL */
  378. if (hd->config.global_user_ctx) {
  379. if (hd->config.global_user_ctx_free_fn) {
  380. hd->config.global_user_ctx_free_fn(hd->config.global_user_ctx);
  381. } else {
  382. free(hd->config.global_user_ctx);
  383. }
  384. hd->config.global_user_ctx = NULL;
  385. }
  386. /* Release global transport context, if not NULL */
  387. if (hd->config.global_transport_ctx) {
  388. if (hd->config.global_transport_ctx_free_fn) {
  389. hd->config.global_transport_ctx_free_fn(hd->config.global_transport_ctx);
  390. } else {
  391. free(hd->config.global_transport_ctx);
  392. }
  393. hd->config.global_transport_ctx = NULL;
  394. }
  395. ESP_LOGD(TAG, LOG_FMT("server stopped"));
  396. httpd_delete(hd);
  397. return ESP_OK;
  398. }