1 #include "private-libwebsockets.h"
5 /* forced into this because new espconn accepted callbacks carry no context ptr */
6 static struct lws_context *hacky_context;
7 static unsigned int time_high, ot;
10 * included from libwebsockets.c for esp8266 builds
13 unsigned long long time_in_microseconds(void)
15 unsigned int t = system_get_time();
21 return (((long long)time_high) << 32) | t;
24 int gettimeofday(struct timeval *tv, void *tz)
26 unsigned long long t = time_in_microseconds();
28 tv->tv_sec = t / 1000000;
29 tv->tv_usec = t % 1000000;
34 time_t time(time_t *tloc)
36 unsigned long long t = time_in_microseconds();
45 lws_get_random(struct lws_context *context, void *buf, int len)
47 // return read(context->fd_random, (char *)buf, len);
52 lws_send_pipe_choked(struct lws *wsi)
54 return wsi->pending_send_completion;
57 LWS_VISIBLE struct lws *
58 wsi_from_fd(const struct lws_context *context, lws_sockfd_type fd)
62 for (n = 0; n < context->max_fds; n++)
63 if (context->connpool[n] == fd)
64 return (struct lws *)context->connpool[n + context->max_fds];
70 lws_ssl_capable_write_no_ssl(struct lws *wsi, unsigned char *buf, int len)
72 //lwsl_notice("%s: wsi %p: len %d\n", __func__, wsi, len);
74 wsi->pending_send_completion++;
75 espconn_send(wsi->desc.sockfd, buf, len);
95 insert_wsi(struct lws_context *context, struct lws *wsi)
104 delete_from_fd(struct lws_context *context, lws_sockfd_type fd)
112 struct tm *localtime(const time_t *timep)
116 struct tm *localtime_r(const time_t *timep, struct tm *t)
121 int atoi(const char *s)
125 while (*s && (*s >= '0' && *s <= '9'))
126 n = (n * 10) + ((*s++) - '0');
134 if (c >= 'A' && c <= 'F')
137 if (c >= 'a' && c <= 'f')
140 if (c >= '0' && c <= '9')
146 int strcasecmp(const char *s1, const char *s2)
156 if (a >= 'a' && a <= 'z')
158 if (b >= 'a' && b <= 'z')
169 lws_poll_listen_fd(struct lws_pollfd *fd)
175 lws_cancel_service_pt(struct lws *wsi)
180 lws_cancel_service(struct lws_context *context)
184 LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)
186 extern void output_redirect(const char *str);
187 output_redirect(line);
190 LWS_VISIBLE LWS_EXTERN int
191 _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
197 lws_plat_check_connection_error(struct lws *wsi)
203 lws_plat_service(struct lws_context *context, int timeout_ms)
205 // return _lws_plat_service_tsi(context, timeout_ms, 0);
210 esp8266_find_free_conn(struct lws_context *context)
214 for (n = 0; n < context->max_fds; n++)
215 if (!context->connpool[n]) {
216 lwsl_info(" using connpool %d\n", n);
220 lwsl_err("%s: no free conns\n", __func__);
226 esp8266_create_tcp_listen_socket(struct lws_vhost *vh)
228 int n = esp8266_find_free_conn(vh->context);
229 struct espconn *conn;
234 conn = lws_zalloc(sizeof *conn);
238 vh->context->connpool[n] = conn;
240 conn->type = ESPCONN_TCP;
241 conn->state = ESPCONN_NONE;
242 conn->proto.tcp = &vh->tcp;
248 lws_plat_get_peer_simple(struct lws *wsi, char *name, int namelen)
250 unsigned char *p = wsi->desc.sockfd->proto.tcp->remote_ip;
252 lws_snprintf(name, namelen, "%u.%u.%u.%u", p[0], p[1], p[2], p[3]);
258 lws_ssl_capable_read_no_ssl(struct lws *wsi, unsigned char *buf, int len)
260 //lwsl_notice("%s\n", __func__);
262 if (!wsi->context->rxd)
265 if (len < wsi->context->rxd_len)
266 lwsl_err("trunc read (%d vs %d)\n", len, wsi->context->rxd_len);
268 len = wsi->context->rxd_len;
270 ets_memcpy(buf, wsi->context->rxd, len);
272 wsi->context->rxd = NULL;
280 struct lws_context *context = arg;
281 struct lws_context_per_thread *pt = &context->pt[0];
283 struct lws_pollfd *pollfd;
286 /* Service any ah that has pending rx */
287 for (n = 0; n < context->max_http_header_pool; n++)
288 if (pt->ah_pool[n].rxpos != pt->ah_pool[n].rxlen) {
289 wsi = pt->ah_pool[n].wsi;
290 pollfd = &pt->fds[wsi->position_in_fds_table];
291 if (pollfd->events & LWS_POLLIN) {
292 pollfd->revents |= LWS_POLLIN;
293 lws_service_fd(context, pollfd);
297 /* handle timeouts */
299 lws_service_fd(context, NULL);
303 esp8266_cb_rx(void *arg, char *data, unsigned short len)
305 struct espconn *conn = arg;
306 struct lws *wsi = conn->reverse;
307 struct lws_context_per_thread *pt = &wsi->context->pt[0];
308 struct lws_pollfd pollfd;
312 * if we're doing HTTP headers, and we have no ah, check if there is
313 * a free ah, if not, have to buffer it
315 if (!wsi->hdr_parsing_completed && !wsi->u.hdr.ah) {
316 for (n = 0; n < wsi->context->max_http_header_pool; n++)
317 if (!pt->ah_pool[n].in_use)
320 n = n == wsi->context->max_http_header_pool;
323 if (!(pt->fds[wsi->position_in_fds_table].events & LWS_POLLIN) || n) {
324 wsi->premature_rx = realloc(wsi->premature_rx,
325 wsi->prem_rx_size + len);
326 if (!wsi->premature_rx)
328 os_memcpy((char *)wsi->premature_rx + wsi->prem_rx_size, data, len);
329 wsi->prem_rx_size += len;
330 // lwsl_notice("%s: wsi %p: len %d BUFFERING\n", __func__, wsi, len);
332 if (n) /* we know it will fail, but we will get on the wait list */
333 n = lws_header_table_attach(wsi, 0);
339 //lwsl_err("%s: wsi %p. len %d\n", __func__, wsi, len);
342 pollfd.events = LWS_POLLIN;
343 pollfd.revents = LWS_POLLIN;
345 wsi->context->rxd = data;
346 wsi->context->rxd_len = len;
348 lws_service_fd(lws_get_context(wsi), &pollfd);
353 esp8266_cb_sent(void *arg)
355 struct espconn *conn = arg;
356 struct lws *wsi = conn->reverse;
357 struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
359 // lwsl_err("%s: wsi %p (psc %d) wsi->position_in_fds_table=%d\n", __func__, wsi, wsi->pending_send_completion, wsi->position_in_fds_table);
361 wsi->pending_send_completion--;
362 if (wsi->close_is_pending_send_completion &&
363 !wsi->pending_send_completion &&
364 !lws_partial_buffered(wsi)) {
365 lwsl_notice("doing delayed close\n");
366 lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
369 if (pt->fds[wsi->position_in_fds_table].events & LWS_POLLOUT) {
370 struct lws_pollfd pollfd;
373 pollfd.events = LWS_POLLOUT;
374 pollfd.revents = LWS_POLLOUT;
376 // lwsl_notice("informing POLLOUT\n");
378 lws_service_fd(lws_get_context(wsi), &pollfd);
383 esp8266_cb_disconnected(void *arg)
385 struct espconn *conn = arg;
386 struct lws *wsi = conn->reverse;
389 lwsl_notice("%s: %p\n", __func__, wsi);
391 for (n = 0; n < hacky_context->max_fds; n++)
392 if (hacky_context->connpool[n] == arg) {
393 hacky_context->connpool[n] = NULL;
394 lwsl_info(" freed connpool %d\n", n);
398 conn->reverse = NULL;
399 lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
400 lwsl_notice("closed ok\n");
405 esp8266_cb_recon(void *arg, signed char err)
407 struct espconn *conn = arg;
409 lwsl_err("%s: wsi %p. err %d\n", __func__, conn->reverse, err);
411 conn->state = ESPCONN_CLOSE;
413 esp8266_cb_disconnected(arg);
417 * there is no reliable indication of which listen socket we were accepted on.
421 esp8266_cb_connect(void *arg)
423 struct espconn *cs = arg;
424 // struct ip_addr *ipa = (struct ip_addr *)cs->proto.tcp->remote_ip;
425 struct lws_vhost *vh = hacky_context->vhost_list;
426 // struct ip_info info;
430 lwsl_notice("%s: (wsi coming): %p\n", __func__, cs->reverse);
432 wifi_get_ip_info(0, &info);
433 if (ip_addr_netcmp(ipa, &info.ip, &info.netmask)) {
434 /* we are on the same subnet as the AP, ie, connected to AP */
435 while (vh && strcmp(vh->name, "ap"))
438 while (vh && !strcmp(vh->name, "ap"))
444 n = esp8266_find_free_conn(hacky_context);
448 hacky_context->connpool[n] = cs;
450 espconn_recv_hold(cs);
452 wsi = lws_adopt_socket_vhost(vh, cs);
456 lwsl_err("%s: wsi %p (using free_conn %d): vh %s\n", __func__, wsi, n, vh->name);
458 espconn_regist_recvcb(cs, esp8266_cb_rx);
459 espconn_regist_reconcb(cs, esp8266_cb_recon);
460 espconn_regist_disconcb(cs, esp8266_cb_disconnected);
461 espconn_regist_sentcb(cs, esp8266_cb_sent);
463 espconn_set_opt(cs, ESPCONN_NODELAY | ESPCONN_REUSEADDR);
464 espconn_regist_time(cs, 7200, 1);
469 lwsl_err("%s: bailed]n", __func__);
470 espconn_disconnect(cs);
474 esp8266_tcp_stream_bind(lws_sockfd_type fd, int port, struct lws *wsi)
476 fd->proto.tcp->local_port = port;
479 hacky_context = wsi->context;
481 espconn_regist_connectcb(fd, esp8266_cb_connect);
482 /* hmmm it means, listen() + accept() */
485 espconn_tcp_set_max_con_allow(fd, 10);
489 esp8266_tcp_stream_accept(lws_sockfd_type fd, struct lws *wsi)
495 for (n = 0; n < wsi->context->max_fds ; n++)
496 if (wsi->context->connpool[n] == wsi->desc.sockfd)
497 wsi->position_in_fds_table = n;
501 lws_plat_set_socket_options(struct lws_vhost *vhost, lws_sockfd_type fd)
507 lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
512 lws_plat_context_early_init(void)
514 espconn_tcp_set_max_con(12);
520 lws_plat_context_early_destroy(struct lws_context *context)
525 lws_plat_context_late_destroy(struct lws_context *context)
528 struct lws_context_per_thread *pt = &context->pt[0];
529 int m = context->count_threads;
531 if (context->lws_lookup)
532 lws_free(context->lws_lookup);
535 close(pt->dummy_pipe_fds[0]);
536 close(pt->dummy_pipe_fds[1]);
540 // close(context->fd_random);
543 /* cast a struct sockaddr_in6 * into addr for ipv6 */
546 lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,
553 lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
555 struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
557 context->connpool[wsi->position_in_fds_table + context->max_fds] = (lws_sockfd_type)wsi;
558 wsi->desc.sockfd->reverse = wsi;
563 lws_plat_delete_socket_from_fds(struct lws_context *context,
564 struct lws *wsi, int m)
566 struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
569 for (n = 0; n < wsi->context->max_fds; n++)
570 if (wsi->context->connpool[n] == wsi->desc.sockfd) {
571 wsi->context->connpool[n] = NULL;
572 wsi->context->connpool[n + wsi->context->max_fds] = NULL;
573 lwsl_notice(" freed connpool %d\n", n);
576 wsi->desc.sockfd->reverse = NULL;
581 lws_plat_service_periodic(struct lws_context *context)
586 lws_plat_change_pollfd(struct lws_context *context,
587 struct lws *wsi, struct lws_pollfd *pfd)
591 //lwsl_notice("%s: %p: wsi->pift=%d, events %d\n",
592 // __func__, wsi, wsi->position_in_fds_table, pfd->events);
594 if (pfd->events & LWS_POLLIN) {
595 if (wsi->premature_rx) {
596 lwsl_notice("replaying buffered rx: wsi %p\n", wsi);
597 p = wsi->premature_rx;
598 wsi->premature_rx = NULL;
599 esp8266_cb_rx(wsi->desc.sockfd,
600 (char *)p + wsi->prem_rx_pos,
601 wsi->prem_rx_size - wsi->prem_rx_pos);
602 wsi->prem_rx_size = 0;
603 wsi->prem_rx_pos = 0;
606 if (espconn_recv_unhold(wsi->desc.sockfd) < 0)
609 if (espconn_recv_hold(wsi->desc.sockfd) < 0)
612 if (!(pfd->events & LWS_POLLOUT))
615 if (!wsi->pending_send_completion) {
616 pfd->revents |= LWS_POLLOUT;
618 // lwsl_notice("doing POLLOUT\n");
619 lws_service_fd(lws_get_context(wsi), pfd);
621 //lwsl_notice("pending sc\n");
626 LWS_VISIBLE const char *
627 lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
629 // return inet_ntop(af, src, dst, cnt);
634 lws_plat_inet_pton(int af, const char *src, void *dst)
636 //return inet_pton(af, src, dst);
641 lws_plat_init(struct lws_context *context,
642 struct lws_context_creation_info *info)
644 // struct lws_context_per_thread *pt = &context->pt[0];
645 // int n = context->count_threads, fd;
647 /* master context has the global fd lookup array */
648 context->connpool = lws_zalloc(sizeof(struct espconn *) *
649 context->max_fds * 2);
650 if (context->connpool == NULL) {
651 lwsl_err("OOM on lws_lookup array for %d connections\n",
656 lwsl_notice(" mem: platform fd map: %5u bytes\n",
657 sizeof(struct espconn *) * context->max_fds);
658 // fd = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
660 // context->fd_random = fd;
661 // if (context->fd_random < 0) {
662 // lwsl_err("Unable to open random device %s %d\n",
663 // SYSTEM_RANDOM_FILEPATH, context->fd_random);
667 os_memset(&context->to_timer, 0, sizeof(os_timer_t));
668 os_timer_disarm(&context->to_timer);
669 os_timer_setfn(&context->to_timer, (os_timer_func_t *)cb_1Hz, context);
670 os_timer_arm(&context->to_timer, 1000, 1);
672 if (!lws_libev_init_fd_table(context) &&
673 !lws_libuv_init_fd_table(context) &&
674 !lws_libevent_init_fd_table(context)) {
675 /* otherwise libev handled it instead */
678 if (pipe(pt->dummy_pipe_fds)) {
679 lwsl_err("Unable to create pipe\n");
683 /* use the read end of pipe as first item */
684 pt->fds[0].fd = pt->dummy_pipe_fds[0];
685 pt->fds[0].events = LWS_POLLIN;
686 pt->fds[0].revents = 0;
694 #ifdef LWS_WITH_PLUGINS
695 if (info->plugin_dirs)
696 lws_plat_plugins_init(context, info->plugin_dirs);