1 #include "private-libwebsockets.h"
4 * included from libwebsockets.c for unix builds
7 unsigned long long time_in_microseconds(void)
10 gettimeofday(&tv, NULL);
11 return (tv.tv_sec * 1000000) + tv.tv_usec;
14 LWS_VISIBLE int libwebsockets_get_random(struct libwebsocket_context *context,
17 return read(context->fd_random, (char *)buf, len);
20 LWS_VISIBLE int lws_send_pipe_choked(struct libwebsocket *wsi)
22 struct libwebsocket_pollfd fds;
24 /* treat the fact we got a truncated send pending as if we're choked */
25 if (wsi->truncated_send_len)
32 if (poll(&fds, 1, 0) != 1)
35 if ((fds.revents & POLLOUT) == 0)
38 /* okay to send another packet without blocking */
44 lws_poll_listen_fd(struct libwebsocket_pollfd *fd)
46 return poll(fd, 1, 0);
50 * This is just used to interrupt poll waiting
51 * we don't have to do anything with it.
53 #ifdef LWS_OPENSSL_SUPPORT
54 static void lws_sigusr2(int sig)
61 libwebsocket_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
63 struct libwebsocket_pollfd eventfd;
64 struct lws_io_watcher *lws_io = (struct lws_io_watcher*)watcher;
65 struct libwebsocket_context *context = lws_io->context;
67 if (revents & EV_ERROR)
70 eventfd.fd = watcher->fd;
71 eventfd.revents = EV_NONE;
72 if (revents & EV_READ)
73 eventfd.revents |= LWS_POLLIN;
75 if (revents & EV_WRITE)
76 eventfd.revents |= LWS_POLLOUT;
78 libwebsocket_service_fd(context,&eventfd);
82 libwebsocket_sigint_cb(
83 struct ev_loop *loop, struct ev_signal* watcher, int revents)
85 ev_break(loop, EVBREAK_ALL);
89 libwebsocket_initloop(
90 struct libwebsocket_context *context,
95 const char * backend_name;
96 struct ev_io *w_accept = (ev_io *)&context->w_accept;
97 struct ev_signal *w_sigint = (ev_signal *)&context->w_sigint;
100 loop = ev_default_loop(0);
102 context->io_loop = loop;
105 * Initialize the accept w_accept with the listening socket
106 * and register a callback for read operations:
108 ev_io_init(w_accept, libwebsocket_accept_cb,
109 context->listen_service_fd, EV_READ);
110 ev_io_start(context->io_loop,w_accept);
111 ev_signal_init(w_sigint, libwebsocket_sigint_cb, SIGINT);
112 ev_signal_start(context->io_loop,w_sigint);
113 backend = ev_backend(loop);
116 case EVBACKEND_SELECT:
117 backend_name = "select";
120 backend_name = "poll";
122 case EVBACKEND_EPOLL:
123 backend_name = "epoll";
125 case EVBACKEND_KQUEUE:
126 backend_name = "kqueue";
128 case EVBACKEND_DEVPOLL:
129 backend_name = "/dev/poll";
132 backend_name = "Solaris 10 \"port\"";
135 backend_name = "Unknown libev backend";
139 lwsl_notice(" libev backend: %s\n", backend_name);
144 #endif /* LWS_USE_LIBEV */
147 * libwebsocket_cancel_service() - Cancel servicing of pending websocket activity
148 * @context: Websocket context
150 * This function let a call to libwebsocket_service() waiting for a timeout
151 * immediately return.
154 libwebsocket_cancel_service(struct libwebsocket_context *context)
158 if (write(context->dummy_pipe_fds[1], &buf, sizeof(buf)) != 1)
159 lwsl_err("Cannot write to dummy pipe");
162 LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)
164 int syslog_level = LOG_DEBUG;
168 syslog_level = LOG_ERR;
171 syslog_level = LOG_WARNING;
174 syslog_level = LOG_NOTICE;
177 syslog_level = LOG_INFO;
180 syslog(syslog_level, "%s", line);
184 lws_plat_service(struct libwebsocket_context *context, int timeout_ms)
190 /* stay dead once we are dead */
196 if (context->io_loop && LWS_LIBEV_ENABLED(context))
197 ev_run(context->io_loop, 0);
198 #endif /* LWS_USE_LIBEV */
199 context->service_tid = context->protocols[0].callback(context, NULL,
200 LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
202 n = poll(context->fds, context->fds_count, timeout_ms);
203 context->service_tid = 0;
205 if (n == 0) /* poll timeout */ {
206 libwebsocket_service_fd(context, NULL);
211 if (LWS_ERRNO != LWS_EINTR)
216 /* any socket with events to service? */
218 for (n = 0; n < context->fds_count; n++) {
219 if (!context->fds[n].revents)
222 if (context->fds[n].fd == context->dummy_pipe_fds[0]) {
223 if (read(context->fds[n].fd, &buf, 1) != 1)
224 lwsl_err("Cannot read from dummy pipe.");
228 m = libwebsocket_service_fd(context, &context->fds[n]);
231 /* if something closed, retry this slot */
240 lws_plat_set_socket_options(struct libwebsocket_context *context, int fd)
243 socklen_t optlen = sizeof(optval);
245 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
246 struct protoent *tcp_proto;
249 if (context->ka_time) {
250 /* enable keepalive on this socket */
252 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
253 (const void *)&optval, optlen) < 0)
256 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__CYGWIN__)
259 * didn't find a way to set these per-socket, need to
260 * tune kernel systemwide values
263 /* set the keepalive conditions we want on it too */
264 optval = context->ka_time;
265 if (setsockopt(fd, IPPROTO_IP, TCP_KEEPIDLE,
266 (const void *)&optval, optlen) < 0)
269 optval = context->ka_interval;
270 if (setsockopt(fd, IPPROTO_IP, TCP_KEEPINTVL,
271 (const void *)&optval, optlen) < 0)
274 optval = context->ka_probes;
275 if (setsockopt(fd, IPPROTO_IP, TCP_KEEPCNT,
276 (const void *)&optval, optlen) < 0)
283 #if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__)
284 setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&optval, optlen);
286 tcp_proto = getprotobyname("TCP");
287 setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, &optval, optlen);
290 /* We are nonblocking... */
291 fcntl(fd, F_SETFL, O_NONBLOCK);
297 lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
300 if (setgid(info->gid))
301 lwsl_warn("setgid: %s\n", strerror(LWS_ERRNO));
303 if (setuid(info->uid))
304 lwsl_warn("setuid: %s\n", strerror(LWS_ERRNO));
308 lws_plat_init_fd_tables(struct libwebsocket_context *context)
311 if (LWS_LIBEV_ENABLED(context)) {
312 context->w_accept.context = context;
313 context->w_sigint.context = context;
317 if (pipe(context->dummy_pipe_fds)) {
318 lwsl_err("Unable to create pipe\n");
322 /* use the read end of pipe as first item */
323 context->fds[0].fd = context->dummy_pipe_fds[0];
324 context->fds[0].events = LWS_POLLIN;
325 context->fds[0].revents = 0;
326 context->fds_count = 1;
328 context->fd_random = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
329 if (context->fd_random < 0) {
330 lwsl_err("Unable to open random device %s %d\n",
331 SYSTEM_RANDOM_FILEPATH, context->fd_random);
338 static void sigpipe_handler(int x)
344 lws_plat_context_early_init(void)
348 signal(SIGUSR2, lws_sigusr2);
350 sigaddset(&mask, SIGUSR2);
352 sigprocmask(SIG_BLOCK, &mask, NULL);
354 signal(SIGPIPE, sigpipe_handler);
360 lws_plat_context_early_destroy(struct libwebsocket_context *context)
365 lws_plat_context_late_destroy(struct libwebsocket_context *context)
367 close(context->dummy_pipe_fds[0]);
368 close(context->dummy_pipe_fds[1]);
369 close(context->fd_random);
372 /* cast a struct sockaddr_in6 * into addr for ipv6 */
375 interface_to_sa(struct libwebsocket_context *context,
376 const char *ifname, struct sockaddr_in *addr, size_t addrlen)
383 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
387 for (ifc = ifr; ifc != NULL && rc; ifc = ifc->ifa_next) {
391 lwsl_info(" interface %s vs %s\n", ifc->ifa_name, ifname);
393 if (strcmp(ifc->ifa_name, ifname))
396 switch (ifc->ifa_addr->sa_family) {
399 if (LWS_IPV6_ENABLED(context)) {
400 /* map IPv4 to IPv6 */
401 bzero((char *)&addr6->sin6_addr,
402 sizeof(struct in6_addr));
403 addr6->sin6_addr.s6_addr[10] = 0xff;
404 addr6->sin6_addr.s6_addr[11] = 0xff;
405 memcpy(&addr6->sin6_addr.s6_addr[12],
406 &((struct sockaddr_in *)ifc->ifa_addr)->sin_addr,
407 sizeof(struct in_addr));
411 (struct sockaddr_in *)ifc->ifa_addr,
412 sizeof(struct sockaddr_in));
418 memcpy(&addr6->sin6_addr,
419 &((struct sockaddr_in6 *)ifc->ifa_addr)->sin6_addr,
420 sizeof(struct in6_addr));
435 lws_plat_insert_socket_into_fds(struct libwebsocket_context *context,
436 struct libwebsocket *wsi)
439 if (context && context->io_loop && LWS_LIBEV_ENABLED(context))
440 ev_io_start(context->io_loop, (struct ev_io *)&wsi->w_read);
441 #endif /* LWS_USE_LIBEV */
442 context->fds[context->fds_count++].revents = 0;
446 lws_plat_delete_socket_from_fds(struct libwebsocket_context *context,
447 struct libwebsocket *wsi, int m)
452 lws_plat_service_periodic(struct libwebsocket_context *context)
454 /* if our parent went down, don't linger around */
455 if (context->started_with_parent &&
456 kill(context->started_with_parent, 0) < 0)
457 kill(getpid(), SIGTERM);
461 lws_plat_change_pollfd(struct libwebsocket_context *context,
462 struct libwebsocket *wsi, struct libwebsocket_pollfd *pfd)
468 lws_plat_open_file(const char* filename, unsigned long* filelen)
470 struct stat stat_buf;
471 int ret = open(filename, O_RDONLY);
474 return LWS_INVALID_FILE;
476 fstat(ret, &stat_buf);
477 *filelen = stat_buf.st_size;
482 LWS_VISIBLE const char *
483 lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
485 return inet_ntop(af, src, dst, cnt);