_esp_httpd_main.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  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_http_server.h>
  23. #include "esp_httpd_priv.h"
  24. #include "ctrl_sock.h"
  25. #include "globdefs.h"
  26. static const char *TAG = "_httpd";
  27. struct httpd_ctrl_data {
  28. enum httpd_ctrl_msg {
  29. HTTPD_CTRL_SHUTDOWN,
  30. HTTPD_CTRL_WORK,
  31. } hc_msg;
  32. httpd_work_fn_t hc_work;
  33. void *hc_work_arg;
  34. };
  35. static esp_err_t _httpd_server_init(struct httpd_data *hd)
  36. {
  37. int fd = socket(PF_INET6, SOCK_STREAM, 0);
  38. if (fd < 0) {
  39. ESP_LOGE(TAG, LOG_FMT("error in socket (%d)"), errno);
  40. return ESP_FAIL;
  41. }
  42. struct in6_addr inaddr_any = IN6ADDR_ANY_INIT;
  43. struct sockaddr_in6 serv_addr = {
  44. .sin6_family = PF_INET6,
  45. .sin6_addr = inaddr_any,
  46. .sin6_port = htons(hd->config.server_port)
  47. };
  48. /* Enable SO_REUSEADDR to allow binding to the same
  49. * address and port when restarting the server */
  50. int enable = 1;
  51. if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) < 0) {
  52. /* This will fail if CONFIG_LWIP_SO_REUSE is not enabled. But
  53. * it does not affect the normal working of the HTTP Server */
  54. ESP_LOGW(TAG, LOG_FMT("error enabling SO_REUSEADDR (%d)"), errno);
  55. }
  56. int ret = bind(fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
  57. if (ret < 0) {
  58. ESP_LOGE(TAG, LOG_FMT("error in bind (%d)"), errno);
  59. close(fd);
  60. return ESP_FAIL;
  61. }
  62. ret = listen(fd, hd->config.backlog_conn);
  63. if (ret < 0) {
  64. ESP_LOGE(TAG, LOG_FMT("error in listen (%d)"), errno);
  65. close(fd);
  66. return ESP_FAIL;
  67. }
  68. int ctrl_fd = cs_create_ctrl_sock(hd->config.ctrl_port);
  69. if (ctrl_fd < 0) {
  70. ESP_LOGE(TAG, LOG_FMT("error in creating ctrl socket (%d)"), errno);
  71. close(fd);
  72. return ESP_FAIL;
  73. }
  74. int msg_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  75. if (msg_fd < 0) {
  76. ESP_LOGE(TAG, LOG_FMT("error in creating msg socket (%d)"), errno);
  77. close(fd);
  78. close(ctrl_fd);
  79. return ESP_FAIL;
  80. }
  81. hd->listen_fd = fd;
  82. hd->ctrl_fd = ctrl_fd;
  83. hd->msg_fd = msg_fd;
  84. return ESP_OK;
  85. }
  86. static void _httpd_process_ctrl_msg(struct httpd_data *hd)
  87. {
  88. struct httpd_ctrl_data msg;
  89. int ret = recv(hd->ctrl_fd, &msg, sizeof(msg), 0);
  90. if (ret <= 0) {
  91. ESP_LOGW(TAG, LOG_FMT("error in recv (%d)"), errno);
  92. return;
  93. }
  94. if (ret != sizeof(msg)) {
  95. ESP_LOGW(TAG, LOG_FMT("incomplete msg"));
  96. return;
  97. }
  98. switch (msg.hc_msg) {
  99. case HTTPD_CTRL_WORK:
  100. if (msg.hc_work) {
  101. ESP_LOGD(TAG, LOG_FMT("work"));
  102. (*msg.hc_work)(msg.hc_work_arg);
  103. }
  104. break;
  105. case HTTPD_CTRL_SHUTDOWN:
  106. ESP_LOGD(TAG, LOG_FMT("shutdown"));
  107. hd->hd_td.status = THREAD_STOPPING;
  108. break;
  109. default:
  110. break;
  111. }
  112. }
  113. static esp_err_t _httpd_accept_conn(struct httpd_data *hd, int listen_fd)
  114. {
  115. /* If no space is available for new session, close the least recently used one */
  116. if (hd->config.lru_purge_enable == true) {
  117. if (!httpd_is_sess_available(hd)) {
  118. /* Queue asynchronous closure of the least recently used session */
  119. return httpd_sess_close_lru(hd);
  120. /* Returning from this allowes the main server thread to process
  121. * the queued asynchronous control message for closing LRU session.
  122. * Since connection request hasn't been addressed yet using accept()
  123. * therefore _httpd_accept_conn() will be called again, but this time
  124. * with space available for one session
  125. */
  126. }
  127. }
  128. struct sockaddr_in addr_from;
  129. socklen_t addr_from_len = sizeof(addr_from);
  130. int new_fd = accept(listen_fd, (struct sockaddr *)&addr_from, &addr_from_len);
  131. if (new_fd < 0) {
  132. ESP_LOGW(TAG, LOG_FMT("error in accept (%d)"), errno);
  133. return ESP_FAIL;
  134. }
  135. ESP_LOGD(TAG, LOG_FMT("newfd = %d"), new_fd);
  136. struct timeval tv;
  137. /* Set recv timeout of this fd as per config */
  138. tv.tv_sec = hd->config.recv_wait_timeout;
  139. tv.tv_usec = 0;
  140. setsockopt(new_fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));
  141. /* Set send timeout of this fd as per config */
  142. tv.tv_sec = hd->config.send_wait_timeout;
  143. tv.tv_usec = 0;
  144. setsockopt(new_fd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&tv, sizeof(tv));
  145. if (ESP_OK != httpd_sess_new(hd, new_fd)) {
  146. ESP_LOGW(TAG, LOG_FMT("session creation failed"));
  147. close(new_fd);
  148. return ESP_FAIL;
  149. }
  150. ESP_LOGD(TAG, LOG_FMT("complete"));
  151. return ESP_OK;
  152. }
  153. /* Manage in-coming connection or data requests */
  154. static esp_err_t _httpd_server(struct httpd_data *hd)
  155. {
  156. fd_set read_set;
  157. FD_ZERO(&read_set);
  158. if (hd->config.lru_purge_enable || httpd_is_sess_available(hd)) {
  159. /* Only listen for new connections if server has capacity to
  160. * handle more (or when LRU purge is enabled, in which case
  161. * older connections will be closed) */
  162. FD_SET(hd->listen_fd, &read_set);
  163. }
  164. FD_SET(hd->ctrl_fd, &read_set);
  165. int tmp_max_fd;
  166. httpd_sess_set_descriptors(hd, &read_set, &tmp_max_fd);
  167. int maxfd = MAX(hd->listen_fd, tmp_max_fd);
  168. tmp_max_fd = maxfd;
  169. maxfd = MAX(hd->ctrl_fd, tmp_max_fd);
  170. ESP_LOGD(TAG, LOG_FMT("doing select maxfd+1 = %d"), maxfd + 1);
  171. int active_cnt = select(maxfd + 1, &read_set, NULL, NULL, NULL);
  172. if (active_cnt < 0) {
  173. ESP_LOGE(TAG, LOG_FMT("error in select (%d)"), errno);
  174. httpd_sess_delete_invalid(hd);
  175. return ESP_OK;
  176. }
  177. /* Case0: Do we have a control message? */
  178. if (FD_ISSET(hd->ctrl_fd, &read_set)) {
  179. ESP_LOGD(TAG, LOG_FMT("processing ctrl message"));
  180. _httpd_process_ctrl_msg(hd);
  181. if (hd->hd_td.status == THREAD_STOPPING) {
  182. ESP_LOGD(TAG, LOG_FMT("stopping thread"));
  183. return ESP_FAIL;
  184. }
  185. }
  186. /* Case1: Do we have any activity on the current data
  187. * sessions? */
  188. int fd = -1;
  189. while ((fd = httpd_sess_iterate(hd, fd)) != -1) {
  190. if (FD_ISSET(fd, &read_set) || (httpd_sess_pending(hd, fd))) {
  191. ESP_LOGD(TAG, LOG_FMT("processing socket %d"), fd);
  192. if (httpd_sess_process(hd, fd) != ESP_OK) {
  193. ESP_LOGD(TAG, LOG_FMT("closing socket %d"), fd);
  194. close(fd);
  195. /* Delete session and update fd to that
  196. * preceding the one being deleted */
  197. fd = httpd_sess_delete(hd, fd);
  198. }
  199. }
  200. }
  201. /* Case2: Do we have any incoming connection requests to
  202. * process? */
  203. if (FD_ISSET(hd->listen_fd, &read_set)) {
  204. ESP_LOGD(TAG, LOG_FMT("processing listen socket %d"), hd->listen_fd);
  205. if (_httpd_accept_conn(hd, hd->listen_fd) != ESP_OK) {
  206. ESP_LOGW(TAG, LOG_FMT("error accepting new connection"));
  207. }
  208. }
  209. return ESP_OK;
  210. }
  211. static void _httpd_close_all_sessions(struct httpd_data *hd)
  212. {
  213. int fd = -1;
  214. while ((fd = httpd_sess_iterate(hd, fd)) != -1) {
  215. ESP_LOGD(TAG, LOG_FMT("cleaning up socket %d"), fd);
  216. httpd_sess_delete(hd, fd);
  217. close(fd);
  218. }
  219. }
  220. /* The main HTTPD thread */
  221. static void _httpd_thread(void *arg)
  222. {
  223. int ret;
  224. struct httpd_data *hd = (struct httpd_data *) arg;
  225. hd->hd_td.status = THREAD_RUNNING;
  226. ESP_LOGD(TAG, LOG_FMT("web server started"));
  227. while (1) {
  228. ret = _httpd_server(hd);
  229. if (ret != ESP_OK) {
  230. break;
  231. }
  232. }
  233. ESP_LOGD(TAG, LOG_FMT("web server exiting"));
  234. close(hd->msg_fd);
  235. cs_free_ctrl_sock(hd->ctrl_fd);
  236. _httpd_close_all_sessions(hd);
  237. close(hd->listen_fd);
  238. hd->hd_td.status = THREAD_STOPPED;
  239. httpd_os_thread_delete();
  240. }
  241. static struct httpd_data *__httpd_create(const httpd_config_t *config)
  242. {
  243. /* Allocate memory for httpd instance data */
  244. struct httpd_data *hd = malloc_init_external(sizeof(struct httpd_data));
  245. if (!hd) {
  246. ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP server instance"));
  247. return NULL;
  248. }
  249. hd->hd_calls = malloc_init_external(config->max_uri_handlers* sizeof(httpd_uri_t *));
  250. if (!hd->hd_calls) {
  251. ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP URI handlers"));
  252. free(hd);
  253. return NULL;
  254. }
  255. hd->hd_sd = malloc_init_external(config->max_open_sockets* sizeof(struct sock_db));
  256. if (!hd->hd_sd) {
  257. ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP session data"));
  258. free(hd->hd_calls);
  259. free(hd);
  260. return NULL;
  261. }
  262. struct httpd_req_aux *ra = &hd->hd_req_aux;
  263. ra->resp_hdrs = malloc_init_external(config->max_resp_headers* sizeof(struct resp_hdr));
  264. if (!ra->resp_hdrs) {
  265. ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP response headers"));
  266. free(hd->hd_sd);
  267. free(hd->hd_calls);
  268. free(hd);
  269. return NULL;
  270. }
  271. hd->err_handler_fns = malloc_init_external(HTTPD_ERR_CODE_MAX* sizeof(httpd_err_handler_func_t));
  272. if (!hd->err_handler_fns) {
  273. ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP error handlers"));
  274. free(ra->resp_hdrs);
  275. free(hd->hd_sd);
  276. free(hd->hd_calls);
  277. free(hd);
  278. return NULL;
  279. }
  280. /* Save the configuration for this instance */
  281. hd->config = *config;
  282. return hd;
  283. }
  284. static void _httpd_delete(struct httpd_data *hd)
  285. {
  286. struct httpd_req_aux *ra = &hd->hd_req_aux;
  287. /* Free memory of httpd instance data */
  288. free(hd->err_handler_fns);
  289. free(ra->resp_hdrs);
  290. free(hd->hd_sd);
  291. /* Free registered URI handlers */
  292. httpd_unregister_all_uri_handlers(hd);
  293. free(hd->hd_calls);
  294. free(hd);
  295. }
  296. esp_err_t __httpd_start(httpd_handle_t *handle, const httpd_config_t *config)
  297. {
  298. if (handle == NULL || config == NULL) {
  299. return ESP_ERR_INVALID_ARG;
  300. }
  301. /* Sanity check about whether LWIP is configured for providing the
  302. * maximum number of open sockets sufficient for the server. Though,
  303. * this check doesn't guarantee that many sockets will actually be
  304. * available at runtime as other processes may use up some sockets.
  305. * Note that server also uses 3 sockets for its internal use :
  306. * 1) listening for new TCP connections
  307. * 2) for sending control messages over UDP
  308. * 3) for receiving control messages over UDP
  309. * So the total number of required sockets is max_open_sockets + 3
  310. */
  311. if (CONFIG_LWIP_MAX_SOCKETS < config->max_open_sockets + 3) {
  312. ESP_LOGE(TAG, "Configuration option max_open_sockets is too large (max allowed %d)\n\t"
  313. "Either decrease this or configure LWIP_MAX_SOCKETS to a larger value",
  314. CONFIG_LWIP_MAX_SOCKETS - 3);
  315. return ESP_ERR_INVALID_ARG;
  316. }
  317. struct httpd_data *hd = __httpd_create(config);
  318. if (hd == NULL) {
  319. /* Failed to allocate memory */
  320. return ESP_ERR_HTTPD_ALLOC_MEM;
  321. }
  322. if (_httpd_server_init(hd) != ESP_OK) {
  323. _httpd_delete(hd);
  324. return ESP_FAIL;
  325. }
  326. httpd_sess_init(hd);
  327. if (__httpd_os_thread_create_static(&hd->hd_td.handle, "httpd",
  328. hd->config.stack_size,
  329. hd->config.task_priority,
  330. _httpd_thread, hd,
  331. hd->config.core_id) != ESP_OK) {
  332. /* Failed to launch task */
  333. _httpd_delete(hd);
  334. return ESP_ERR_HTTPD_TASK;
  335. }
  336. *handle = (httpd_handle_t *)hd;
  337. return ESP_OK;
  338. }