blob: 279a3be4ad2b3a327aceacfcef8282f57de992c7 [file] [log] [blame]
Andy Greene40aa9b2014-04-02 21:02:54 +08001#include "private-libwebsockets.h"
2
Andy Greenbfaea952014-03-31 11:01:32 +08003/*
4 * included from libwebsockets.c for unix builds
5 */
6
Andy Greene40aa9b2014-04-02 21:02:54 +08007unsigned long long time_in_microseconds(void)
Andy Greenbfaea952014-03-31 11:01:32 +08008{
9 struct timeval tv;
10 gettimeofday(&tv, NULL);
11 return (tv.tv_sec * 1000000) + tv.tv_usec;
12}
13
14LWS_VISIBLE int libwebsockets_get_random(struct libwebsocket_context *context,
15 void *buf, int len)
16{
17 return read(context->fd_random, (char *)buf, len);
18}
19
20LWS_VISIBLE int lws_send_pipe_choked(struct libwebsocket *wsi)
21{
22 struct libwebsocket_pollfd fds;
23
24 /* treat the fact we got a truncated send pending as if we're choked */
25 if (wsi->truncated_send_len)
26 return 1;
27
28 fds.fd = wsi->sock;
29 fds.events = POLLOUT;
30 fds.revents = 0;
31
32 if (poll(&fds, 1, 0) != 1)
33 return 1;
34
35 if ((fds.revents & POLLOUT) == 0)
36 return 1;
37
38 /* okay to send another packet without blocking */
39
40 return 0;
41}
42
Andy Greene40aa9b2014-04-02 21:02:54 +080043LWS_VISIBLE int
44lws_poll_listen_fd(struct libwebsocket_pollfd *fd)
Andy Greenbfaea952014-03-31 11:01:32 +080045{
46 return poll(fd, 1, 0);
47}
48
Andy Greene40aa9b2014-04-02 21:02:54 +080049/*
50 * This is just used to interrupt poll waiting
51 * we don't have to do anything with it.
52 */
Andy Greene40aa9b2014-04-02 21:02:54 +080053static void lws_sigusr2(int sig)
54{
55}
Andy Greenbfaea952014-03-31 11:01:32 +080056
Andy Greenbfaea952014-03-31 11:01:32 +080057/**
58 * libwebsocket_cancel_service() - Cancel servicing of pending websocket activity
59 * @context: Websocket context
60 *
61 * This function let a call to libwebsocket_service() waiting for a timeout
62 * immediately return.
63 */
64LWS_VISIBLE void
65libwebsocket_cancel_service(struct libwebsocket_context *context)
66{
67 char buf = 0;
68
69 if (write(context->dummy_pipe_fds[1], &buf, sizeof(buf)) != 1)
70 lwsl_err("Cannot write to dummy pipe");
71}
72
73LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)
74{
75 int syslog_level = LOG_DEBUG;
76
77 switch (level) {
78 case LLL_ERR:
79 syslog_level = LOG_ERR;
80 break;
81 case LLL_WARN:
82 syslog_level = LOG_WARNING;
83 break;
84 case LLL_NOTICE:
85 syslog_level = LOG_NOTICE;
86 break;
87 case LLL_INFO:
88 syslog_level = LOG_INFO;
89 break;
90 }
91 syslog(syslog_level, "%s", line);
Andy Green158e8042014-04-02 14:25:10 +080092}
93
94LWS_VISIBLE int
95lws_plat_service(struct libwebsocket_context *context, int timeout_ms)
96{
97 int n;
98 int m;
99 char buf;
100
101 /* stay dead once we are dead */
102
Andy Greena717df22014-04-11 13:14:37 +0800103 if (!context)
Andy Green158e8042014-04-02 14:25:10 +0800104 return 1;
105
Andy Greena717df22014-04-11 13:14:37 +0800106 lws_libev_run(context);
107
Andy Green158e8042014-04-02 14:25:10 +0800108 context->service_tid = context->protocols[0].callback(context, NULL,
109 LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
110
111 n = poll(context->fds, context->fds_count, timeout_ms);
112 context->service_tid = 0;
113
114 if (n == 0) /* poll timeout */ {
115 libwebsocket_service_fd(context, NULL);
116 return 0;
117 }
118
119 if (n < 0) {
120 if (LWS_ERRNO != LWS_EINTR)
121 return -1;
122 return 0;
123 }
124
125 /* any socket with events to service? */
126
127 for (n = 0; n < context->fds_count; n++) {
128 if (!context->fds[n].revents)
129 continue;
130
131 if (context->fds[n].fd == context->dummy_pipe_fds[0]) {
132 if (read(context->fds[n].fd, &buf, 1) != 1)
133 lwsl_err("Cannot read from dummy pipe.");
134 continue;
135 }
136
137 m = libwebsocket_service_fd(context, &context->fds[n]);
138 if (m < 0)
139 return -1;
140 /* if something closed, retry this slot */
141 if (m)
142 n--;
143 }
144
145 return 0;
146}
147
Andy Greene40aa9b2014-04-02 21:02:54 +0800148LWS_VISIBLE int
149lws_plat_set_socket_options(struct libwebsocket_context *context, int fd)
Andy Green158e8042014-04-02 14:25:10 +0800150{
151 int optval = 1;
152 socklen_t optlen = sizeof(optval);
153
154#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
155 struct protoent *tcp_proto;
156#endif
157
158 if (context->ka_time) {
159 /* enable keepalive on this socket */
160 optval = 1;
161 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
162 (const void *)&optval, optlen) < 0)
163 return 1;
164
165#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__CYGWIN__)
166
167 /*
168 * didn't find a way to set these per-socket, need to
169 * tune kernel systemwide values
170 */
171#else
172 /* set the keepalive conditions we want on it too */
173 optval = context->ka_time;
174 if (setsockopt(fd, IPPROTO_IP, TCP_KEEPIDLE,
175 (const void *)&optval, optlen) < 0)
176 return 1;
177
178 optval = context->ka_interval;
179 if (setsockopt(fd, IPPROTO_IP, TCP_KEEPINTVL,
180 (const void *)&optval, optlen) < 0)
181 return 1;
182
183 optval = context->ka_probes;
184 if (setsockopt(fd, IPPROTO_IP, TCP_KEEPCNT,
185 (const void *)&optval, optlen) < 0)
186 return 1;
187#endif
188 }
189
190 /* Disable Nagle */
191 optval = 1;
192#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__)
193 setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&optval, optlen);
194#else
195 tcp_proto = getprotobyname("TCP");
196 setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, &optval, optlen);
197#endif
198
199 /* We are nonblocking... */
200 fcntl(fd, F_SETFL, O_NONBLOCK);
201
202 return 0;
203}
204
Andy Greene40aa9b2014-04-02 21:02:54 +0800205LWS_VISIBLE void
206lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
Andy Green158e8042014-04-02 14:25:10 +0800207{
208 if (info->gid != -1)
209 if (setgid(info->gid))
210 lwsl_warn("setgid: %s\n", strerror(LWS_ERRNO));
211 if (info->uid != -1)
212 if (setuid(info->uid))
213 lwsl_warn("setuid: %s\n", strerror(LWS_ERRNO));
214}
215
Andy Greene40aa9b2014-04-02 21:02:54 +0800216LWS_VISIBLE int
217lws_plat_init_fd_tables(struct libwebsocket_context *context)
Andy Green158e8042014-04-02 14:25:10 +0800218{
Andy Greena717df22014-04-11 13:14:37 +0800219 if (lws_libev_init_fd_table(context))
220 /* libev handled it instead */
Andy Green158e8042014-04-02 14:25:10 +0800221 return 0;
Andy Greena717df22014-04-11 13:14:37 +0800222
Andy Green158e8042014-04-02 14:25:10 +0800223 if (pipe(context->dummy_pipe_fds)) {
224 lwsl_err("Unable to create pipe\n");
225 return 1;
226 }
227
228 /* use the read end of pipe as first item */
229 context->fds[0].fd = context->dummy_pipe_fds[0];
230 context->fds[0].events = LWS_POLLIN;
231 context->fds[0].revents = 0;
232 context->fds_count = 1;
233
234 context->fd_random = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
235 if (context->fd_random < 0) {
236 lwsl_err("Unable to open random device %s %d\n",
237 SYSTEM_RANDOM_FILEPATH, context->fd_random);
238 return 1;
239 }
240
241 return 0;
242}
243
244static void sigpipe_handler(int x)
245{
246}
247
248
Andy Greene40aa9b2014-04-02 21:02:54 +0800249LWS_VISIBLE int
250lws_plat_context_early_init(void)
Andy Green158e8042014-04-02 14:25:10 +0800251{
252 sigset_t mask;
253
254 signal(SIGUSR2, lws_sigusr2);
255 sigemptyset(&mask);
256 sigaddset(&mask, SIGUSR2);
257
258 sigprocmask(SIG_BLOCK, &mask, NULL);
259
260 signal(SIGPIPE, sigpipe_handler);
261
262 return 0;
263}
264
Andy Greene40aa9b2014-04-02 21:02:54 +0800265LWS_VISIBLE void
266lws_plat_context_early_destroy(struct libwebsocket_context *context)
Andy Green158e8042014-04-02 14:25:10 +0800267{
268}
269
Andy Greene40aa9b2014-04-02 21:02:54 +0800270LWS_VISIBLE void
271lws_plat_context_late_destroy(struct libwebsocket_context *context)
Andy Green158e8042014-04-02 14:25:10 +0800272{
273 close(context->dummy_pipe_fds[0]);
274 close(context->dummy_pipe_fds[1]);
275 close(context->fd_random);
276}
277
278/* cast a struct sockaddr_in6 * into addr for ipv6 */
279
Andy Greene40aa9b2014-04-02 21:02:54 +0800280LWS_VISIBLE int
Andy Green158e8042014-04-02 14:25:10 +0800281interface_to_sa(struct libwebsocket_context *context,
282 const char *ifname, struct sockaddr_in *addr, size_t addrlen)
283{
284 int rc = -1;
285
286 struct ifaddrs *ifr;
287 struct ifaddrs *ifc;
288#ifdef LWS_USE_IPV6
289 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
290#endif
291
292 getifaddrs(&ifr);
293 for (ifc = ifr; ifc != NULL && rc; ifc = ifc->ifa_next) {
294 if (!ifc->ifa_addr)
295 continue;
296
297 lwsl_info(" interface %s vs %s\n", ifc->ifa_name, ifname);
298
299 if (strcmp(ifc->ifa_name, ifname))
300 continue;
301
302 switch (ifc->ifa_addr->sa_family) {
303 case AF_INET:
304#ifdef LWS_USE_IPV6
305 if (LWS_IPV6_ENABLED(context)) {
306 /* map IPv4 to IPv6 */
307 bzero((char *)&addr6->sin6_addr,
308 sizeof(struct in6_addr));
309 addr6->sin6_addr.s6_addr[10] = 0xff;
310 addr6->sin6_addr.s6_addr[11] = 0xff;
311 memcpy(&addr6->sin6_addr.s6_addr[12],
312 &((struct sockaddr_in *)ifc->ifa_addr)->sin_addr,
313 sizeof(struct in_addr));
314 } else
315#endif
316 memcpy(addr,
317 (struct sockaddr_in *)ifc->ifa_addr,
318 sizeof(struct sockaddr_in));
319 break;
320#ifdef LWS_USE_IPV6
321 case AF_INET6:
322 if (rc >= 0)
323 break;
324 memcpy(&addr6->sin6_addr,
325 &((struct sockaddr_in6 *)ifc->ifa_addr)->sin6_addr,
326 sizeof(struct in6_addr));
327 break;
328#endif
329 default:
330 continue;
331 }
332 rc = 0;
333 }
334
335 freeifaddrs(ifr);
336
337 return rc;
338}
339
Andy Greene40aa9b2014-04-02 21:02:54 +0800340LWS_VISIBLE void
341lws_plat_insert_socket_into_fds(struct libwebsocket_context *context,
Andy Green158e8042014-04-02 14:25:10 +0800342 struct libwebsocket *wsi)
343{
Andy Greena717df22014-04-11 13:14:37 +0800344 lws_libev_io(context, wsi, LWS_EV_START | LWS_EV_READ);
Andy Green158e8042014-04-02 14:25:10 +0800345 context->fds[context->fds_count++].revents = 0;
346}
347
Andy Greene40aa9b2014-04-02 21:02:54 +0800348LWS_VISIBLE void
349lws_plat_delete_socket_from_fds(struct libwebsocket_context *context,
Andy Green158e8042014-04-02 14:25:10 +0800350 struct libwebsocket *wsi, int m)
351{
352}
353
Andy Greene40aa9b2014-04-02 21:02:54 +0800354LWS_VISIBLE void
355lws_plat_service_periodic(struct libwebsocket_context *context)
Andy Green158e8042014-04-02 14:25:10 +0800356{
357 /* if our parent went down, don't linger around */
358 if (context->started_with_parent &&
359 kill(context->started_with_parent, 0) < 0)
360 kill(getpid(), SIGTERM);
361}
362
Andy Greene40aa9b2014-04-02 21:02:54 +0800363LWS_VISIBLE int
364lws_plat_change_pollfd(struct libwebsocket_context *context,
Andy Green158e8042014-04-02 14:25:10 +0800365 struct libwebsocket *wsi, struct libwebsocket_pollfd *pfd)
366{
367 return 0;
368}
369
Andy Greene40aa9b2014-04-02 21:02:54 +0800370LWS_VISIBLE int
371lws_plat_open_file(const char* filename, unsigned long* filelen)
Andy Green158e8042014-04-02 14:25:10 +0800372{
373 struct stat stat_buf;
374 int ret = open(filename, O_RDONLY);
375
376 if (ret < 0)
377 return LWS_INVALID_FILE;
378
379 fstat(ret, &stat_buf);
380 *filelen = stat_buf.st_size;
381 return ret;
Andy Green1cd3ba62014-04-02 23:03:23 +0800382}
Andy Greena654fc02014-04-03 07:16:40 +0800383
Andy Green1cd3ba62014-04-02 23:03:23 +0800384#ifdef LWS_USE_IPV6
385LWS_VISIBLE const char *
386lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
387{
388 return inet_ntop(af, src, dst, cnt);
389}
390#endif