9953ac7ae8231f60f54e4500daafd5a50202462b
[platform/upstream/libwebsockets.git] / lib / lws-plat-unix.c
1 #include "private-libwebsockets.h"
2
3 #include <pwd.h>
4 #include <grp.h>
5
6 /*
7  * included from libwebsockets.c for unix builds
8  */
9
10 unsigned long long time_in_microseconds(void)
11 {
12         struct timeval tv;
13         gettimeofday(&tv, NULL);
14         return ((unsigned long long)tv.tv_sec * 1000000LL) + tv.tv_usec;
15 }
16
17 LWS_VISIBLE int
18 lws_get_random(struct lws_context *context, void *buf, int len)
19 {
20         return read(context->fd_random, (char *)buf, len);
21 }
22
23 LWS_VISIBLE int
24 lws_send_pipe_choked(struct lws *wsi)
25 {
26         struct lws_pollfd fds;
27
28         /* treat the fact we got a truncated send pending as if we're choked */
29         if (wsi->trunc_len)
30                 return 1;
31
32         fds.fd = wsi->sock;
33         fds.events = POLLOUT;
34         fds.revents = 0;
35
36         if (poll(&fds, 1, 0) != 1)
37                 return 1;
38
39         if ((fds.revents & POLLOUT) == 0)
40                 return 1;
41
42         /* okay to send another packet without blocking */
43
44         return 0;
45 }
46
47 LWS_VISIBLE int
48 lws_poll_listen_fd(struct lws_pollfd *fd)
49 {
50         return poll(fd, 1, 0);
51 }
52
53 /*
54  * This is just used to interrupt poll waiting
55  * we don't have to do anything with it.
56  */
57 static void lws_sigusr2(int sig)
58 {
59 }
60
61 /**
62  * lws_cancel_service_pt() - Cancel servicing of pending socket activity
63  *                              on one thread
64  * @wsi:        Cancel service on the thread this wsi is serviced by
65  *
66  *      This function let a call to lws_service() waiting for a timeout
67  *      immediately return.
68  */
69 LWS_VISIBLE void
70 lws_cancel_service_pt(struct lws *wsi)
71 {
72         struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
73         char buf = 0;
74
75         if (write(pt->dummy_pipe_fds[1], &buf, sizeof(buf)) != 1)
76                 lwsl_err("Cannot write to dummy pipe");
77 }
78
79 /**
80  * lws_cancel_service() - Cancel ALL servicing of pending socket activity
81  * @context:    Websocket context
82  *
83  *      This function let a call to lws_service() waiting for a timeout
84  *      immediately return.
85  */
86 LWS_VISIBLE void
87 lws_cancel_service(struct lws_context *context)
88 {
89         struct lws_context_per_thread *pt = &context->pt[0];
90         char buf = 0, m = context->count_threads;
91
92         while (m--) {
93                 if (write(pt->dummy_pipe_fds[1], &buf, sizeof(buf)) != 1)
94                         lwsl_err("Cannot write to dummy pipe");
95                 pt++;
96         }
97 }
98
99 LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)
100 {
101         int syslog_level = LOG_DEBUG;
102
103         switch (level) {
104         case LLL_ERR:
105                 syslog_level = LOG_ERR;
106                 break;
107         case LLL_WARN:
108                 syslog_level = LOG_WARNING;
109                 break;
110         case LLL_NOTICE:
111                 syslog_level = LOG_NOTICE;
112                 break;
113         case LLL_INFO:
114                 syslog_level = LOG_INFO;
115                 break;
116         }
117         syslog(syslog_level, "%s", line);
118 }
119
120 LWS_VISIBLE int
121 lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
122 {
123         struct lws_context_per_thread *pt = &context->pt[tsi];
124         struct lws *wsi;
125         int n, m, c;
126         char buf;
127 #ifdef LWS_OPENSSL_SUPPORT
128         struct lws *wsi_next;
129 #endif
130
131         /* stay dead once we are dead */
132
133         if (!context)
134                 return 1;
135
136         lws_libev_run(context);
137
138         if (!context->service_tid_detected) {
139                 struct lws _lws;
140
141                 memset(&_lws, 0, sizeof(_lws));
142                 _lws.context = context;
143
144                 context->service_tid_detected = context->protocols[0].callback(
145                         &_lws, LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
146         }
147         context->service_tid = context->service_tid_detected;
148
149         /* if we know we are draining rx ext, do not wait in poll */
150         if (pt->rx_draining_ext_list)
151                 timeout_ms = 0;
152
153 #ifdef LWS_OPENSSL_SUPPORT
154         /* if we know we have non-network pending data, do not wait in poll */
155         if (lws_ssl_anybody_has_buffered_read_tsi(context, tsi)) {
156                 timeout_ms = 0;
157                 lwsl_err("ssl buffered read\n");
158         }
159 #endif
160
161         n = poll(pt->fds, pt->fds_count, timeout_ms);
162
163 #ifdef LWS_OPENSSL_SUPPORT
164         if (!pt->rx_draining_ext_list &&
165             !lws_ssl_anybody_has_buffered_read_tsi(context, tsi) && !n) {
166 #else
167         if (!pt->rx_draining_ext_list && !n) /* poll timeout */ {
168 #endif
169                 lws_service_fd_tsi(context, NULL, tsi);
170                 return 0;
171         }
172
173         if (n < 0) {
174                 if (LWS_ERRNO != LWS_EINTR)
175                         return -1;
176                 return 0;
177         }
178
179         /*
180          * For all guys with already-available ext data to drain, if they are
181          * not flowcontrolled, fake their POLLIN status
182          */
183         wsi = pt->rx_draining_ext_list;
184         while (wsi) {
185                 pt->fds[wsi->position_in_fds_table].revents |=
186                         pt->fds[wsi->position_in_fds_table].events & POLLIN;
187                 wsi = wsi->u.ws.rx_draining_ext_list;
188         }
189
190 #ifdef LWS_OPENSSL_SUPPORT
191         /*
192          * For all guys with buffered SSL read data already saved up, if they
193          * are not flowcontrolled, fake their POLLIN status so they'll get
194          * service to use up the buffered incoming data, even though their
195          * network socket may have nothing
196          */
197
198         wsi = pt->pending_read_list;
199         while (wsi) {
200                 wsi_next = wsi->pending_read_list_next;
201                 pt->fds[wsi->position_in_fds_table].revents |=
202                         pt->fds[wsi->position_in_fds_table].events & POLLIN;
203                 if (pt->fds[wsi->position_in_fds_table].revents & POLLIN)
204                         /*
205                          * he's going to get serviced now, take him off the
206                          * list of guys with buffered SSL.  If he still has some
207                          * at the end of the service, he'll get put back on the
208                          * list then.
209                          */
210                         lws_ssl_remove_wsi_from_buffered_list(wsi);
211
212                 wsi = wsi_next;
213         }
214 #endif
215
216         /* any socket with events to service? */
217
218         c = n;
219         for (n = 0; n < pt->fds_count && c; n++) {
220                 if (!pt->fds[n].revents)
221                         continue;
222
223                 c--;
224
225                 if (pt->fds[n].fd == pt->dummy_pipe_fds[0]) {
226                         if (read(pt->fds[n].fd, &buf, 1) != 1)
227                                 lwsl_err("Cannot read from dummy pipe.");
228                         continue;
229                 }
230
231                 m = lws_service_fd_tsi(context, &pt->fds[n], tsi);
232                 if (m < 0)
233                         return -1;
234                 /* if something closed, retry this slot */
235                 if (m)
236                         n--;
237         }
238
239         return 0;
240 }
241
242 LWS_VISIBLE int
243 lws_plat_service(struct lws_context *context, int timeout_ms)
244 {
245         return lws_plat_service_tsi(context, timeout_ms, 0);
246 }
247
248 LWS_VISIBLE int
249 lws_plat_set_socket_options(struct lws_context *context, int fd)
250 {
251         int optval = 1;
252         socklen_t optlen = sizeof(optval);
253
254 #if defined(__APPLE__) || \
255     defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
256     defined(__NetBSD__) || \
257     defined(__OpenBSD__)
258         struct protoent *tcp_proto;
259 #endif
260
261         if (context->ka_time) {
262                 /* enable keepalive on this socket */
263                 optval = 1;
264                 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
265                                (const void *)&optval, optlen) < 0)
266                         return 1;
267
268 #if defined(__APPLE__) || \
269     defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
270     defined(__NetBSD__) || \
271         defined(__CYGWIN__) || defined(__OpenBSD__)
272
273                 /*
274                  * didn't find a way to set these per-socket, need to
275                  * tune kernel systemwide values
276                  */
277 #else
278                 /* set the keepalive conditions we want on it too */
279                 optval = context->ka_time;
280                 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE,
281                                (const void *)&optval, optlen) < 0)
282                         return 1;
283
284                 optval = context->ka_interval;
285                 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL,
286                                (const void *)&optval, optlen) < 0)
287                         return 1;
288
289                 optval = context->ka_probes;
290                 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT,
291                                (const void *)&optval, optlen) < 0)
292                         return 1;
293 #endif
294         }
295
296         /* Disable Nagle */
297         optval = 1;
298 #if !defined(__APPLE__) && \
299     !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) && \
300     !defined(__NetBSD__) && \
301     !defined(__OpenBSD__)
302         if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&optval, optlen) < 0)
303                 return 1;
304 #else
305         tcp_proto = getprotobyname("TCP");
306         if (setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, &optval, optlen) < 0)
307                 return 1;
308 #endif
309
310         /* We are nonblocking... */
311         if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
312                 return 1;
313
314         return 0;
315 }
316
317 LWS_VISIBLE void
318 lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
319 {
320         if (info->uid != -1) {
321                 struct passwd *p = getpwuid(info->uid);
322
323                 if (p) {
324                         initgroups(p->pw_name, info->gid);
325                         if (setuid(info->uid))
326                                 lwsl_warn("setuid: %s\n", strerror(LWS_ERRNO));
327                         else
328                                 lwsl_notice(" Set privs to user '%s'\n", p->pw_name);
329                 } else
330                         lwsl_warn("getpwuid: unable to find uid %d", info->uid);
331         }
332         if (info->gid != -1)
333                 if (setgid(info->gid))
334                         lwsl_warn("setgid: %s\n", strerror(LWS_ERRNO));
335
336 }
337
338 static void sigpipe_handler(int x)
339 {
340 }
341
342 LWS_VISIBLE int
343 lws_plat_context_early_init(void)
344 {
345         sigset_t mask;
346
347         signal(SIGUSR2, lws_sigusr2);
348         sigemptyset(&mask);
349         sigaddset(&mask, SIGUSR2);
350
351         sigprocmask(SIG_BLOCK, &mask, NULL);
352
353         signal(SIGPIPE, sigpipe_handler);
354
355         return 0;
356 }
357
358 LWS_VISIBLE void
359 lws_plat_context_early_destroy(struct lws_context *context)
360 {
361 }
362
363 LWS_VISIBLE void
364 lws_plat_context_late_destroy(struct lws_context *context)
365 {
366         struct lws_context_per_thread *pt = &context->pt[0];
367         int m = context->count_threads;
368
369         if (context->lws_lookup)
370                 lws_free(context->lws_lookup);
371
372         while (m--) {
373                 close(pt->dummy_pipe_fds[0]);
374                 close(pt->dummy_pipe_fds[1]);
375                 pt++;
376         }
377         close(context->fd_random);
378 }
379
380 /* cast a struct sockaddr_in6 * into addr for ipv6 */
381
382 LWS_VISIBLE int
383 lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr, size_t addrlen)
384 {
385         int rc = -1;
386
387         struct ifaddrs *ifr;
388         struct ifaddrs *ifc;
389 #ifdef LWS_USE_IPV6
390         struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
391 #endif
392
393         getifaddrs(&ifr);
394         for (ifc = ifr; ifc != NULL && rc; ifc = ifc->ifa_next) {
395                 if (!ifc->ifa_addr)
396                         continue;
397
398                 lwsl_info(" interface %s vs %s\n", ifc->ifa_name, ifname);
399
400                 if (strcmp(ifc->ifa_name, ifname))
401                         continue;
402
403                 switch (ifc->ifa_addr->sa_family) {
404                 case AF_INET:
405 #ifdef LWS_USE_IPV6
406                         if (ipv6) {
407                                 /* map IPv4 to IPv6 */
408                                 bzero((char *)&addr6->sin6_addr,
409                                                 sizeof(struct in6_addr));
410                                 addr6->sin6_addr.s6_addr[10] = 0xff;
411                                 addr6->sin6_addr.s6_addr[11] = 0xff;
412                                 memcpy(&addr6->sin6_addr.s6_addr[12],
413                                         &((struct sockaddr_in *)ifc->ifa_addr)->sin_addr,
414                                                         sizeof(struct in_addr));
415                         } else
416 #endif
417                                 memcpy(addr,
418                                         (struct sockaddr_in *)ifc->ifa_addr,
419                                                     sizeof(struct sockaddr_in));
420                         break;
421 #ifdef LWS_USE_IPV6
422                 case AF_INET6:
423                         memcpy(&addr6->sin6_addr,
424                           &((struct sockaddr_in6 *)ifc->ifa_addr)->sin6_addr,
425                                                        sizeof(struct in6_addr));
426                         break;
427 #endif
428                 default:
429                         continue;
430                 }
431                 rc = 0;
432         }
433
434         freeifaddrs(ifr);
435
436         if (rc == -1) {
437                 /* check if bind to IP adddress */
438 #ifdef LWS_USE_IPV6
439                 if (inet_pton(AF_INET6, ifname, &addr6->sin6_addr) == 1)
440                         rc = 0;
441                 else
442 #endif
443                 if (inet_pton(AF_INET, ifname, &addr->sin_addr) == 1)
444                         rc = 0;
445         }
446
447         return rc;
448 }
449
450 LWS_VISIBLE void
451 lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
452 {
453         struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
454
455         lws_libev_io(wsi, LWS_EV_START | LWS_EV_READ);
456         pt->fds[pt->fds_count++].revents = 0;
457 }
458
459 LWS_VISIBLE void
460 lws_plat_delete_socket_from_fds(struct lws_context *context,
461                                                 struct lws *wsi, int m)
462 {
463         struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
464         pt->fds_count--;
465 }
466
467 LWS_VISIBLE void
468 lws_plat_service_periodic(struct lws_context *context)
469 {
470         /* if our parent went down, don't linger around */
471         if (context->started_with_parent &&
472             kill(context->started_with_parent, 0) < 0)
473                 kill(getpid(), SIGTERM);
474 }
475
476 LWS_VISIBLE int
477 lws_plat_change_pollfd(struct lws_context *context,
478                       struct lws *wsi, struct lws_pollfd *pfd)
479 {
480         return 0;
481 }
482
483 LWS_VISIBLE const char *
484 lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
485 {
486         return inet_ntop(af, src, dst, cnt);
487 }
488
489 static lws_filefd_type
490 _lws_plat_file_open(struct lws *wsi, const char *filename,
491                     unsigned long *filelen, int flags)
492 {
493         struct stat stat_buf;
494         int ret = open(filename, flags, 0664);
495
496         if (ret < 0)
497                 return LWS_INVALID_FILE;
498
499         if (fstat(ret, &stat_buf) < 0) {
500                 close(ret);
501                 return LWS_INVALID_FILE;
502         }
503         *filelen = stat_buf.st_size;
504         return ret;
505 }
506
507 static int
508 _lws_plat_file_close(struct lws *wsi, lws_filefd_type fd)
509 {
510         return close(fd);
511 }
512
513 unsigned long
514 _lws_plat_file_seek_cur(struct lws *wsi, lws_filefd_type fd, long offset)
515 {
516         return lseek(fd, offset, SEEK_CUR);
517 }
518
519 static int
520 _lws_plat_file_read(struct lws *wsi, lws_filefd_type fd, unsigned long *amount,
521                     unsigned char *buf, unsigned long len)
522 {
523         long n;
524
525         n = read((int)fd, buf, len);
526         if (n == -1) {
527                 *amount = 0;
528                 return -1;
529         }
530
531         *amount = n;
532
533         return 0;
534 }
535
536 static int
537 _lws_plat_file_write(struct lws *wsi, lws_filefd_type fd, unsigned long *amount,
538                      unsigned char *buf, unsigned long len)
539 {
540         long n;
541
542         n = write((int)fd, buf, len);
543         if (n == -1) {
544                 *amount = 0;
545                 return -1;
546         }
547
548         *amount = n;
549
550         return 0;
551 }
552
553 LWS_VISIBLE int
554 lws_plat_init(struct lws_context *context,
555               struct lws_context_creation_info *info)
556 {
557         struct lws_context_per_thread *pt = &context->pt[0];
558         int n = context->count_threads, fd;
559
560         /* master context has the global fd lookup array */
561         context->lws_lookup = lws_zalloc(sizeof(struct lws *) *
562                                          context->max_fds);
563         if (context->lws_lookup == NULL) {
564                 lwsl_err("OOM on lws_lookup array for %d connections\n",
565                          context->max_fds);
566                 return 1;
567         }
568
569         lwsl_notice(" mem: platform fd map: %5u bytes\n",
570                     sizeof(struct lws *) * context->max_fds);
571         fd = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
572
573         context->fd_random = fd;
574         if (context->fd_random < 0) {
575                 lwsl_err("Unable to open random device %s %d\n",
576                          SYSTEM_RANDOM_FILEPATH, context->fd_random);
577                 return 1;
578         }
579
580         if (!lws_libev_init_fd_table(context)) {
581                 /* otherwise libev handled it instead */
582
583                 while (n--) {
584                         if (pipe(pt->dummy_pipe_fds)) {
585                                 lwsl_err("Unable to create pipe\n");
586                                 return 1;
587                         }
588
589                         /* use the read end of pipe as first item */
590                         pt->fds[0].fd = pt->dummy_pipe_fds[0];
591                         pt->fds[0].events = LWS_POLLIN;
592                         pt->fds[0].revents = 0;
593                         pt->fds_count = 1;
594                         pt++;
595                 }
596         }
597
598         context->fops.open      = _lws_plat_file_open;
599         context->fops.close     = _lws_plat_file_close;
600         context->fops.seek_cur  = _lws_plat_file_seek_cur;
601         context->fops.read      = _lws_plat_file_read;
602         context->fops.write     = _lws_plat_file_write;
603
604         return 0;
605 }