2 * included from libwebsockets.c for unix builds
5 static unsigned long long time_in_microseconds(void)
8 gettimeofday(&tv, NULL);
9 return (tv.tv_sec * 1000000) + tv.tv_usec;
12 LWS_VISIBLE int libwebsockets_get_random(struct libwebsocket_context *context,
15 return read(context->fd_random, (char *)buf, len);
18 LWS_VISIBLE int lws_send_pipe_choked(struct libwebsocket *wsi)
20 struct libwebsocket_pollfd fds;
22 /* treat the fact we got a truncated send pending as if we're choked */
23 if (wsi->truncated_send_len)
30 if (poll(&fds, 1, 0) != 1)
33 if ((fds.revents & POLLOUT) == 0)
36 /* okay to send another packet without blocking */
41 static int lws_poll_listen_fd(struct libwebsocket_pollfd *fd)
43 return poll(fd, 1, 0);
49 libwebsocket_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
51 struct libwebsocket_pollfd eventfd;
52 struct lws_io_watcher *lws_io = (struct lws_io_watcher*)watcher;
53 struct libwebsocket_context *context = lws_io->context;
55 if (revents & EV_ERROR)
58 eventfd.fd = watcher->fd;
59 eventfd.revents = EV_NONE;
60 if (revents & EV_READ)
61 eventfd.revents |= LWS_POLLIN;
63 if (revents & EV_WRITE)
64 eventfd.revents |= LWS_POLLOUT;
66 libwebsocket_service_fd(context,&eventfd);
70 libwebsocket_sigint_cb(
71 struct ev_loop *loop, struct ev_signal* watcher, int revents)
73 ev_break(loop, EVBREAK_ALL);
77 libwebsocket_initloop(
78 struct libwebsocket_context *context,
83 const char * backend_name;
84 struct ev_io *w_accept = (ev_io *)&context->w_accept;
85 struct ev_signal *w_sigint = (ev_signal *)&context->w_sigint;
88 loop = ev_default_loop(0);
90 context->io_loop = loop;
93 * Initialize the accept w_accept with the listening socket
94 * and register a callback for read operations:
96 ev_io_init(w_accept, libwebsocket_accept_cb,
97 context->listen_service_fd, EV_READ);
98 ev_io_start(context->io_loop,w_accept);
99 ev_signal_init(w_sigint, libwebsocket_sigint_cb, SIGINT);
100 ev_signal_start(context->io_loop,w_sigint);
101 backend = ev_backend(loop);
104 case EVBACKEND_SELECT:
105 backend_name = "select";
108 backend_name = "poll";
110 case EVBACKEND_EPOLL:
111 backend_name = "epoll";
113 case EVBACKEND_KQUEUE:
114 backend_name = "kqueue";
116 case EVBACKEND_DEVPOLL:
117 backend_name = "/dev/poll";
120 backend_name = "Solaris 10 \"port\"";
123 backend_name = "Unknown libev backend";
127 lwsl_notice(" libev backend: %s\n", backend_name);
132 #endif /* LWS_USE_LIBEV */
135 * libwebsocket_cancel_service() - Cancel servicing of pending websocket activity
136 * @context: Websocket context
138 * This function let a call to libwebsocket_service() waiting for a timeout
139 * immediately return.
142 libwebsocket_cancel_service(struct libwebsocket_context *context)
146 if (write(context->dummy_pipe_fds[1], &buf, sizeof(buf)) != 1)
147 lwsl_err("Cannot write to dummy pipe");
150 LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)
152 int syslog_level = LOG_DEBUG;
156 syslog_level = LOG_ERR;
159 syslog_level = LOG_WARNING;
162 syslog_level = LOG_NOTICE;
165 syslog_level = LOG_INFO;
168 syslog(syslog_level, "%s", line);
172 lws_plat_service(struct libwebsocket_context *context, int timeout_ms)
178 /* stay dead once we are dead */
184 if (context->io_loop && LWS_LIBEV_ENABLED(context))
185 ev_run(context->io_loop, 0);
186 #endif /* LWS_USE_LIBEV */
187 context->service_tid = context->protocols[0].callback(context, NULL,
188 LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
190 n = poll(context->fds, context->fds_count, timeout_ms);
191 context->service_tid = 0;
193 if (n == 0) /* poll timeout */ {
194 libwebsocket_service_fd(context, NULL);
199 if (LWS_ERRNO != LWS_EINTR)
204 /* any socket with events to service? */
206 for (n = 0; n < context->fds_count; n++) {
207 if (!context->fds[n].revents)
210 if (context->fds[n].fd == context->dummy_pipe_fds[0]) {
211 if (read(context->fds[n].fd, &buf, 1) != 1)
212 lwsl_err("Cannot read from dummy pipe.");
216 m = libwebsocket_service_fd(context, &context->fds[n]);
219 /* if something closed, retry this slot */
227 int lws_plat_set_socket_options(struct libwebsocket_context *context, int fd)
230 socklen_t optlen = sizeof(optval);
232 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
233 struct protoent *tcp_proto;
236 if (context->ka_time) {
237 /* enable keepalive on this socket */
239 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
240 (const void *)&optval, optlen) < 0)
243 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__CYGWIN__)
246 * didn't find a way to set these per-socket, need to
247 * tune kernel systemwide values
250 /* set the keepalive conditions we want on it too */
251 optval = context->ka_time;
252 if (setsockopt(fd, IPPROTO_IP, TCP_KEEPIDLE,
253 (const void *)&optval, optlen) < 0)
256 optval = context->ka_interval;
257 if (setsockopt(fd, IPPROTO_IP, TCP_KEEPINTVL,
258 (const void *)&optval, optlen) < 0)
261 optval = context->ka_probes;
262 if (setsockopt(fd, IPPROTO_IP, TCP_KEEPCNT,
263 (const void *)&optval, optlen) < 0)
270 #if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__)
271 setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&optval, optlen);
273 tcp_proto = getprotobyname("TCP");
274 setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, &optval, optlen);
277 /* We are nonblocking... */
278 fcntl(fd, F_SETFL, O_NONBLOCK);
283 static void lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
286 if (setgid(info->gid))
287 lwsl_warn("setgid: %s\n", strerror(LWS_ERRNO));
289 if (setuid(info->uid))
290 lwsl_warn("setuid: %s\n", strerror(LWS_ERRNO));
293 static int lws_plat_init_fd_tables(struct libwebsocket_context *context)
296 if (LWS_LIBEV_ENABLED(context)) {
297 context->w_accept.context = context;
298 context->w_sigint.context = context;
302 if (pipe(context->dummy_pipe_fds)) {
303 lwsl_err("Unable to create pipe\n");
307 /* use the read end of pipe as first item */
308 context->fds[0].fd = context->dummy_pipe_fds[0];
309 context->fds[0].events = LWS_POLLIN;
310 context->fds[0].revents = 0;
311 context->fds_count = 1;
313 context->fd_random = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
314 if (context->fd_random < 0) {
315 lwsl_err("Unable to open random device %s %d\n",
316 SYSTEM_RANDOM_FILEPATH, context->fd_random);
323 static void sigpipe_handler(int x)
328 static int lws_plat_context_early_init(void)
332 signal(SIGUSR2, lws_sigusr2);
334 sigaddset(&mask, SIGUSR2);
336 sigprocmask(SIG_BLOCK, &mask, NULL);
338 signal(SIGPIPE, sigpipe_handler);
343 static void lws_plat_context_early_destroy(struct libwebsocket_context *context)
347 static void lws_plat_context_late_destroy(struct libwebsocket_context *context)
349 close(context->dummy_pipe_fds[0]);
350 close(context->dummy_pipe_fds[1]);
351 close(context->fd_random);
354 /* cast a struct sockaddr_in6 * into addr for ipv6 */
357 interface_to_sa(struct libwebsocket_context *context,
358 const char *ifname, struct sockaddr_in *addr, size_t addrlen)
365 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
369 for (ifc = ifr; ifc != NULL && rc; ifc = ifc->ifa_next) {
373 lwsl_info(" interface %s vs %s\n", ifc->ifa_name, ifname);
375 if (strcmp(ifc->ifa_name, ifname))
378 switch (ifc->ifa_addr->sa_family) {
381 if (LWS_IPV6_ENABLED(context)) {
382 /* map IPv4 to IPv6 */
383 bzero((char *)&addr6->sin6_addr,
384 sizeof(struct in6_addr));
385 addr6->sin6_addr.s6_addr[10] = 0xff;
386 addr6->sin6_addr.s6_addr[11] = 0xff;
387 memcpy(&addr6->sin6_addr.s6_addr[12],
388 &((struct sockaddr_in *)ifc->ifa_addr)->sin_addr,
389 sizeof(struct in_addr));
393 (struct sockaddr_in *)ifc->ifa_addr,
394 sizeof(struct sockaddr_in));
400 memcpy(&addr6->sin6_addr,
401 &((struct sockaddr_in6 *)ifc->ifa_addr)->sin6_addr,
402 sizeof(struct in6_addr));
416 void lws_plat_insert_socket_into_fds(struct libwebsocket_context *context,
417 struct libwebsocket *wsi)
420 if (context && context->io_loop && LWS_LIBEV_ENABLED(context))
421 ev_io_start(context->io_loop, (struct ev_io *)&wsi->w_read);
422 #endif /* LWS_USE_LIBEV */
423 context->fds[context->fds_count++].revents = 0;
426 void lws_plat_delete_socket_from_fds(struct libwebsocket_context *context,
427 struct libwebsocket *wsi, int m)
431 static void lws_plat_service_periodic(struct libwebsocket_context *context)
433 /* if our parent went down, don't linger around */
434 if (context->started_with_parent &&
435 kill(context->started_with_parent, 0) < 0)
436 kill(getpid(), SIGTERM);
439 static int lws_plat_change_pollfd(struct libwebsocket_context *context,
440 struct libwebsocket *wsi, struct libwebsocket_pollfd *pfd)
445 int lws_plat_open_file(const char* filename, unsigned long* filelen)
447 struct stat stat_buf;
448 int ret = open(filename, O_RDONLY);
451 return LWS_INVALID_FILE;
453 fstat(ret, &stat_buf);
454 *filelen = stat_buf.st_size;