Subject: windows: support to bind to a specific IPv6 address
[platform/upstream/libwebsockets.git] / lib / lws-plat-esp8266.c
1 #include "private-libwebsockets.h"
2
3 #include "ip_addr.h"
4
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;
8
9 /*
10  * included from libwebsockets.c for esp8266 builds
11  */
12
13 unsigned long long time_in_microseconds(void)
14 {
15         unsigned int t = system_get_time();
16         
17         if (ot > t)
18                 time_high++;
19         ot = t;
20         
21         return (((long long)time_high) << 32) | t;
22 }
23
24 int gettimeofday(struct timeval *tv, void *tz)
25 {
26         unsigned long long t = time_in_microseconds();
27         
28         tv->tv_sec = t / 1000000;
29         tv->tv_usec = t % 1000000;
30
31         return 0;
32 }
33
34 time_t time(time_t *tloc)
35 {
36         unsigned long long t = time_in_microseconds();
37
38         if (tloc)
39                 *tloc = t / 1000000;
40
41         return 0;
42 }
43
44 LWS_VISIBLE int
45 lws_get_random(struct lws_context *context, void *buf, int len)
46 {
47 //      return read(context->fd_random, (char *)buf, len);
48         return 0;
49 }
50
51 LWS_VISIBLE int
52 lws_send_pipe_choked(struct lws *wsi)
53 {
54         return wsi->pending_send_completion;
55 }
56
57 LWS_VISIBLE struct lws *
58 wsi_from_fd(const struct lws_context *context, lws_sockfd_type fd)
59 {
60         int n;
61
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];
65
66         return NULL;
67 }
68
69 LWS_VISIBLE int
70 lws_ssl_capable_write_no_ssl(struct lws *wsi, unsigned char *buf, int len)
71 {
72         //lwsl_notice("%s: wsi %p: len %d\n", __func__, wsi, len);      
73         
74         wsi->pending_send_completion++;
75         espconn_send(wsi->desc.sockfd, buf, len);
76         
77         return len;
78 }
79
80 void abort(void)
81 {
82         while(1) ;
83 }
84
85 void exit(int n)
86 {
87         abort();
88 }
89
90 void _sint(void *s)
91 {
92 }
93
94 LWS_VISIBLE int
95 insert_wsi(struct lws_context *context, struct lws *wsi)
96 {
97         (void)context;
98         (void)wsi;
99
100         return 0;
101 }
102
103 LWS_VISIBLE int
104 delete_from_fd(struct lws_context *context, lws_sockfd_type fd)
105 {
106         (void)context;
107         (void)fd;
108
109         return 1;
110 }
111
112 struct tm *localtime(const time_t *timep)
113 {
114         return NULL;
115 }
116 struct tm *localtime_r(const time_t *timep, struct tm *t)
117 {
118         return NULL;
119 }
120
121 int atoi(const char *s)
122 {
123         int n = 0;
124
125         while (*s && (*s >= '0' && *s <= '9'))
126                 n = (n * 10) + ((*s++) - '0');
127
128         return n;
129 }
130
131 #undef isxdigit
132 int isxdigit(int c)
133 {
134         if (c >= 'A' && c <= 'F')
135                 return 1;
136
137         if (c >= 'a' && c <= 'f')
138                 return 1;
139
140         if (c >= '0' && c <= '9')
141                 return 1;
142
143         return 0;
144 }
145
146 int strcasecmp(const char *s1, const char *s2)
147 {
148         char a, b;
149         while (*s1 && *s2) {
150                 a = *s1++;
151                 b = *s2++;
152
153                 if (a == b)
154                         continue;
155
156                 if (a >= 'a' && a <= 'z')
157                         a -= 'a' - 'A';
158                 if (b >= 'a' && b <= 'z')
159                         b -= 'a' - 'A';
160
161                 if (a != b)
162                         return 1;
163         }
164
165         return 0;
166 }
167
168 LWS_VISIBLE int
169 lws_poll_listen_fd(struct lws_pollfd *fd)
170 {
171         return 0;
172 }
173
174 LWS_VISIBLE void
175 lws_cancel_service_pt(struct lws *wsi)
176 {
177 }
178
179 LWS_VISIBLE void
180 lws_cancel_service(struct lws_context *context)
181 {
182 }
183
184 LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)
185 {
186         extern void output_redirect(const char *str);
187         output_redirect(line);
188 }
189
190 LWS_VISIBLE LWS_EXTERN int
191 _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
192 {
193         return 0;
194 }
195
196 LWS_VISIBLE int
197 lws_plat_check_connection_error(struct lws *wsi)
198 {
199         return 0;
200 }
201
202 LWS_VISIBLE int
203 lws_plat_service(struct lws_context *context, int timeout_ms)
204 {
205 //      return _lws_plat_service_tsi(context, timeout_ms, 0);
206         return 0;
207 }
208
209 static int
210 esp8266_find_free_conn(struct lws_context *context)
211 {
212         int n;
213
214         for (n = 0; n < context->max_fds; n++)
215                 if (!context->connpool[n]) {
216                         lwsl_info(" using connpool %d\n", n);
217                         return n;
218                 }
219         
220         lwsl_err("%s: no free conns\n", __func__);
221         
222         return -1;
223 }
224
225 lws_sockfd_type
226 esp8266_create_tcp_listen_socket(struct lws_vhost *vh)
227 {
228         int n = esp8266_find_free_conn(vh->context);
229         struct espconn *conn;
230         
231         if (n < 0)
232                 return NULL;
233         
234         conn = lws_zalloc(sizeof *conn);
235         if (!conn)
236                 return NULL;
237         
238         vh->context->connpool[n] = conn;
239         
240         conn->type = ESPCONN_TCP;
241         conn->state = ESPCONN_NONE;
242         conn->proto.tcp = &vh->tcp;
243         
244         return conn;
245 }
246
247 const char *
248 lws_plat_get_peer_simple(struct lws *wsi, char *name, int namelen)
249 {
250         unsigned char *p = wsi->desc.sockfd->proto.tcp->remote_ip;
251
252         lws_snprintf(name, namelen, "%u.%u.%u.%u", p[0], p[1], p[2], p[3]);
253
254         return name;
255 }
256
257 LWS_VISIBLE int
258 lws_ssl_capable_read_no_ssl(struct lws *wsi, unsigned char *buf, int len)
259 {
260         //lwsl_notice("%s\n", __func__);
261         
262         if (!wsi->context->rxd)
263                 return 0;
264
265         if (len < wsi->context->rxd_len)
266                 lwsl_err("trunc read (%d vs %d)\n", len, wsi->context->rxd_len);
267         else
268                 len = wsi->context->rxd_len;
269         
270         ets_memcpy(buf, wsi->context->rxd, len);
271         
272         wsi->context->rxd = NULL;
273         
274         return len;
275 }
276
277 static void
278 cb_1Hz(void *arg)
279 {
280         struct lws_context *context = arg;
281         struct lws_context_per_thread *pt = &context->pt[0];
282         struct lws *wsi;
283         struct lws_pollfd *pollfd;
284         int n;
285
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);
294                         }
295                 }
296
297         /* handle timeouts */
298
299         lws_service_fd(context, NULL);
300 }
301
302 static void
303 esp8266_cb_rx(void *arg, char *data, unsigned short len)
304 {
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;
309         int n = 0;
310
311         /*
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
314          */
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)
318                                 break;
319
320                 n = n == wsi->context->max_http_header_pool;
321         }
322
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)
327                         return;
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);
331
332                 if (n) /* we know it will fail, but we will get on the wait list */
333                         n = lws_header_table_attach(wsi, 0);
334
335                 (void)n;
336                 return;
337         }
338
339         //lwsl_err("%s: wsi %p. len %d\n", __func__, wsi, len);
340
341         pollfd.fd = arg;
342         pollfd.events = LWS_POLLIN;
343         pollfd.revents = LWS_POLLIN;
344         
345         wsi->context->rxd = data;
346         wsi->context->rxd_len = len;
347
348         lws_service_fd(lws_get_context(wsi), &pollfd);
349
350 }
351
352 static void
353 esp8266_cb_sent(void *arg)
354 {
355         struct espconn *conn = arg;
356         struct lws *wsi = conn->reverse;
357         struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
358         
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);
360         
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);
367         }
368         
369         if (pt->fds[wsi->position_in_fds_table].events & LWS_POLLOUT) {
370                 struct lws_pollfd pollfd;
371
372                 pollfd.fd = arg;
373                 pollfd.events = LWS_POLLOUT;
374                 pollfd.revents = LWS_POLLOUT;
375
376 //              lwsl_notice("informing POLLOUT\n");
377                 
378                 lws_service_fd(lws_get_context(wsi), &pollfd);
379         }
380 }
381
382 static void
383 esp8266_cb_disconnected(void *arg)
384 {
385         struct espconn *conn = arg;
386         struct lws *wsi = conn->reverse;
387         int n;
388
389         lwsl_notice("%s: %p\n", __func__, wsi);
390         
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);
395                 }
396         
397         if (wsi) {
398                 conn->reverse = NULL;
399                 lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
400                 lwsl_notice("closed ok\n");
401         }
402 }
403
404 static void
405 esp8266_cb_recon(void *arg, signed char err)
406 {
407         struct espconn *conn = arg;
408
409         lwsl_err("%s: wsi %p. err %d\n", __func__, conn->reverse, err);
410
411         conn->state = ESPCONN_CLOSE;            
412
413         esp8266_cb_disconnected(arg);   
414 }
415
416 /*
417  * there is no reliable indication of which listen socket we were accepted on.
418  */
419
420 static void
421 esp8266_cb_connect(void *arg)
422 {
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;
427         struct lws *wsi;
428         int n;
429
430         lwsl_notice("%s: (wsi coming): %p\n", __func__, cs->reverse);
431 #if 0
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"))
436                         vh = vh->vhost_next;
437         } else
438                 while (vh && !strcmp(vh->name, "ap"))
439                         vh = vh->vhost_next;
440
441         if (!vh)
442                 goto bail;
443 #endif
444         n = esp8266_find_free_conn(hacky_context);
445         if (n < 0)
446                 goto bail;
447         
448         hacky_context->connpool[n] = cs;
449         
450         espconn_recv_hold(cs);
451
452         wsi = lws_adopt_socket_vhost(vh, cs);
453         if (!wsi)
454                 goto bail;
455         
456         lwsl_err("%s: wsi %p (using free_conn %d): vh %s\n", __func__, wsi, n, vh->name);
457
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);
462         
463         espconn_set_opt(cs, ESPCONN_NODELAY | ESPCONN_REUSEADDR);
464         espconn_regist_time(cs, 7200, 1);
465
466         return;
467
468 bail:
469         lwsl_err("%s: bailed]n", __func__);
470         espconn_disconnect(cs);
471 }
472
473 void
474 esp8266_tcp_stream_bind(lws_sockfd_type fd, int port, struct lws *wsi)
475 {
476         fd->proto.tcp->local_port = port;
477         fd->reverse = wsi;
478         
479         hacky_context = wsi->context;
480         
481         espconn_regist_connectcb(fd, esp8266_cb_connect);
482         /* hmmm it means, listen() + accept() */
483         espconn_accept(fd);
484
485         espconn_tcp_set_max_con_allow(fd, 10);
486 }
487
488 void
489 esp8266_tcp_stream_accept(lws_sockfd_type fd, struct lws *wsi)
490 {
491         int n;
492
493         fd->reverse = wsi;
494
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;
498 }
499
500 LWS_VISIBLE int
501 lws_plat_set_socket_options(struct lws_vhost *vhost, lws_sockfd_type fd)
502 {
503         return 0;
504 }
505
506 LWS_VISIBLE void
507 lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
508 {
509 }
510
511 LWS_VISIBLE int
512 lws_plat_context_early_init(void)
513 {
514         espconn_tcp_set_max_con(12);
515
516         return 0;
517 }
518
519 LWS_VISIBLE void
520 lws_plat_context_early_destroy(struct lws_context *context)
521 {
522 }
523
524 LWS_VISIBLE void
525 lws_plat_context_late_destroy(struct lws_context *context)
526 {
527 #if 0
528         struct lws_context_per_thread *pt = &context->pt[0];
529         int m = context->count_threads;
530
531         if (context->lws_lookup)
532                 lws_free(context->lws_lookup);
533
534         while (m--) {
535                 close(pt->dummy_pipe_fds[0]);
536                 close(pt->dummy_pipe_fds[1]);
537                 pt++;
538         }
539 #endif
540 //      close(context->fd_random);
541 }
542
543 /* cast a struct sockaddr_in6 * into addr for ipv6 */
544
545 LWS_VISIBLE int
546 lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,
547                     size_t addrlen)
548 {
549         return 0;
550 }
551
552 LWS_VISIBLE void
553 lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
554 {
555         struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
556
557         context->connpool[wsi->position_in_fds_table + context->max_fds] = (lws_sockfd_type)wsi;
558         wsi->desc.sockfd->reverse = wsi;
559         pt->fds_count++;
560 }
561
562 LWS_VISIBLE void
563 lws_plat_delete_socket_from_fds(struct lws_context *context,
564                                                 struct lws *wsi, int m)
565 {
566         struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];   
567         int n;
568         
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);
574                 }
575         
576         wsi->desc.sockfd->reverse = NULL;
577         pt->fds_count--;
578 }
579
580 LWS_VISIBLE void
581 lws_plat_service_periodic(struct lws_context *context)
582 {
583 }
584
585 LWS_VISIBLE int
586 lws_plat_change_pollfd(struct lws_context *context,
587                        struct lws *wsi, struct lws_pollfd *pfd)
588 {
589         void *p;
590
591         //lwsl_notice("%s: %p: wsi->pift=%d, events %d\n",
592         //              __func__, wsi, wsi->position_in_fds_table, pfd->events);
593         
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;
604                         lws_free(p);
605                 }
606                 if (espconn_recv_unhold(wsi->desc.sockfd) < 0)
607                         return -1;
608         } else
609                 if (espconn_recv_hold(wsi->desc.sockfd) < 0)
610                         return -1;
611         
612         if (!(pfd->events & LWS_POLLOUT))
613                 return 0;
614         
615         if (!wsi->pending_send_completion) {
616                 pfd->revents |= LWS_POLLOUT;
617
618 //              lwsl_notice("doing POLLOUT\n");
619                 lws_service_fd(lws_get_context(wsi), pfd);
620         } //else
621                 //lwsl_notice("pending sc\n");
622
623         return 0;
624 }
625
626 LWS_VISIBLE const char *
627 lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
628 {
629 //      return inet_ntop(af, src, dst, cnt);
630         return 0;
631 }
632
633 LWS_VISIBLE int
634 lws_plat_inet_pton(int af, const char *src, void *dst)
635 {
636         //return inet_pton(af, src, dst);
637         return 1;
638 }
639
640 LWS_VISIBLE int
641 lws_plat_init(struct lws_context *context,
642               struct lws_context_creation_info *info)
643 {
644 //      struct lws_context_per_thread *pt = &context->pt[0];
645 //      int n = context->count_threads, fd;
646
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",
652                          context->max_fds);
653                 return 1;
654         }
655
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);
659
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);
664 //              return 1;
665 //      }
666
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);
671
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 */
676 #if 0
677                 while (n--) {
678                         if (pipe(pt->dummy_pipe_fds)) {
679                                 lwsl_err("Unable to create pipe\n");
680                                 return 1;
681                         }
682
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;
687                         pt->fds_count = 1;
688                         pt++;
689                 }
690 #endif
691         }
692
693
694 #ifdef LWS_WITH_PLUGINS
695         if (info->plugin_dirs)
696                 lws_plat_plugins_init(context, info->plugin_dirs);
697 #endif
698
699         return 0;
700 }