| Andy Green | e40aa9b | 2014-04-02 21:02:54 +0800 | [diff] [blame] | 1 | #include "private-libwebsockets.h" |
| 2 | |
| Andy Green | bfaea95 | 2014-03-31 11:01:32 +0800 | [diff] [blame] | 3 | /* |
| 4 | * included from libwebsockets.c for unix builds |
| 5 | */ |
| 6 | |
| Andy Green | e40aa9b | 2014-04-02 21:02:54 +0800 | [diff] [blame] | 7 | unsigned long long time_in_microseconds(void) |
| Andy Green | bfaea95 | 2014-03-31 11:01:32 +0800 | [diff] [blame] | 8 | { |
| 9 | struct timeval tv; |
| 10 | gettimeofday(&tv, NULL); |
| 11 | return (tv.tv_sec * 1000000) + tv.tv_usec; |
| 12 | } |
| 13 | |
| 14 | LWS_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 | |
| 20 | LWS_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 Green | e40aa9b | 2014-04-02 21:02:54 +0800 | [diff] [blame] | 43 | LWS_VISIBLE int |
| 44 | lws_poll_listen_fd(struct libwebsocket_pollfd *fd) |
| Andy Green | bfaea95 | 2014-03-31 11:01:32 +0800 | [diff] [blame] | 45 | { |
| 46 | return poll(fd, 1, 0); |
| 47 | } |
| 48 | |
| Andy Green | e40aa9b | 2014-04-02 21:02:54 +0800 | [diff] [blame] | 49 | /* |
| 50 | * This is just used to interrupt poll waiting |
| 51 | * we don't have to do anything with it. |
| 52 | */ |
| Andy Green | e40aa9b | 2014-04-02 21:02:54 +0800 | [diff] [blame] | 53 | static void lws_sigusr2(int sig) |
| 54 | { |
| 55 | } |
| Andy Green | bfaea95 | 2014-03-31 11:01:32 +0800 | [diff] [blame] | 56 | |
| Andy Green | bfaea95 | 2014-03-31 11:01:32 +0800 | [diff] [blame] | 57 | /** |
| 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 | */ |
| 64 | LWS_VISIBLE void |
| 65 | libwebsocket_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 | |
| 73 | LWS_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 Green | 158e804 | 2014-04-02 14:25:10 +0800 | [diff] [blame] | 92 | } |
| 93 | |
| 94 | LWS_VISIBLE int |
| 95 | lws_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 Green | a717df2 | 2014-04-11 13:14:37 +0800 | [diff] [blame] | 103 | if (!context) |
| Andy Green | 158e804 | 2014-04-02 14:25:10 +0800 | [diff] [blame] | 104 | return 1; |
| 105 | |
| Andy Green | a717df2 | 2014-04-11 13:14:37 +0800 | [diff] [blame] | 106 | lws_libev_run(context); |
| 107 | |
| Andy Green | 158e804 | 2014-04-02 14:25:10 +0800 | [diff] [blame] | 108 | 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 Green | e40aa9b | 2014-04-02 21:02:54 +0800 | [diff] [blame] | 148 | LWS_VISIBLE int |
| 149 | lws_plat_set_socket_options(struct libwebsocket_context *context, int fd) |
| Andy Green | 158e804 | 2014-04-02 14:25:10 +0800 | [diff] [blame] | 150 | { |
| 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 Green | e40aa9b | 2014-04-02 21:02:54 +0800 | [diff] [blame] | 205 | LWS_VISIBLE void |
| 206 | lws_plat_drop_app_privileges(struct lws_context_creation_info *info) |
| Andy Green | 158e804 | 2014-04-02 14:25:10 +0800 | [diff] [blame] | 207 | { |
| 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 Green | e40aa9b | 2014-04-02 21:02:54 +0800 | [diff] [blame] | 216 | LWS_VISIBLE int |
| 217 | lws_plat_init_fd_tables(struct libwebsocket_context *context) |
| Andy Green | 158e804 | 2014-04-02 14:25:10 +0800 | [diff] [blame] | 218 | { |
| Andy Green | a717df2 | 2014-04-11 13:14:37 +0800 | [diff] [blame] | 219 | if (lws_libev_init_fd_table(context)) |
| 220 | /* libev handled it instead */ |
| Andy Green | 158e804 | 2014-04-02 14:25:10 +0800 | [diff] [blame] | 221 | return 0; |
| Andy Green | a717df2 | 2014-04-11 13:14:37 +0800 | [diff] [blame] | 222 | |
| Andy Green | 158e804 | 2014-04-02 14:25:10 +0800 | [diff] [blame] | 223 | 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 | |
| 244 | static void sigpipe_handler(int x) |
| 245 | { |
| 246 | } |
| 247 | |
| 248 | |
| Andy Green | e40aa9b | 2014-04-02 21:02:54 +0800 | [diff] [blame] | 249 | LWS_VISIBLE int |
| 250 | lws_plat_context_early_init(void) |
| Andy Green | 158e804 | 2014-04-02 14:25:10 +0800 | [diff] [blame] | 251 | { |
| 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 Green | e40aa9b | 2014-04-02 21:02:54 +0800 | [diff] [blame] | 265 | LWS_VISIBLE void |
| 266 | lws_plat_context_early_destroy(struct libwebsocket_context *context) |
| Andy Green | 158e804 | 2014-04-02 14:25:10 +0800 | [diff] [blame] | 267 | { |
| 268 | } |
| 269 | |
| Andy Green | e40aa9b | 2014-04-02 21:02:54 +0800 | [diff] [blame] | 270 | LWS_VISIBLE void |
| 271 | lws_plat_context_late_destroy(struct libwebsocket_context *context) |
| Andy Green | 158e804 | 2014-04-02 14:25:10 +0800 | [diff] [blame] | 272 | { |
| 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 Green | e40aa9b | 2014-04-02 21:02:54 +0800 | [diff] [blame] | 280 | LWS_VISIBLE int |
| Andy Green | 158e804 | 2014-04-02 14:25:10 +0800 | [diff] [blame] | 281 | interface_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 Green | e40aa9b | 2014-04-02 21:02:54 +0800 | [diff] [blame] | 340 | LWS_VISIBLE void |
| 341 | lws_plat_insert_socket_into_fds(struct libwebsocket_context *context, |
| Andy Green | 158e804 | 2014-04-02 14:25:10 +0800 | [diff] [blame] | 342 | struct libwebsocket *wsi) |
| 343 | { |
| Andy Green | a717df2 | 2014-04-11 13:14:37 +0800 | [diff] [blame] | 344 | lws_libev_io(context, wsi, LWS_EV_START | LWS_EV_READ); |
| Andy Green | 158e804 | 2014-04-02 14:25:10 +0800 | [diff] [blame] | 345 | context->fds[context->fds_count++].revents = 0; |
| 346 | } |
| 347 | |
| Andy Green | e40aa9b | 2014-04-02 21:02:54 +0800 | [diff] [blame] | 348 | LWS_VISIBLE void |
| 349 | lws_plat_delete_socket_from_fds(struct libwebsocket_context *context, |
| Andy Green | 158e804 | 2014-04-02 14:25:10 +0800 | [diff] [blame] | 350 | struct libwebsocket *wsi, int m) |
| 351 | { |
| 352 | } |
| 353 | |
| Andy Green | e40aa9b | 2014-04-02 21:02:54 +0800 | [diff] [blame] | 354 | LWS_VISIBLE void |
| 355 | lws_plat_service_periodic(struct libwebsocket_context *context) |
| Andy Green | 158e804 | 2014-04-02 14:25:10 +0800 | [diff] [blame] | 356 | { |
| 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 Green | e40aa9b | 2014-04-02 21:02:54 +0800 | [diff] [blame] | 363 | LWS_VISIBLE int |
| 364 | lws_plat_change_pollfd(struct libwebsocket_context *context, |
| Andy Green | 158e804 | 2014-04-02 14:25:10 +0800 | [diff] [blame] | 365 | struct libwebsocket *wsi, struct libwebsocket_pollfd *pfd) |
| 366 | { |
| 367 | return 0; |
| 368 | } |
| 369 | |
| Andy Green | e40aa9b | 2014-04-02 21:02:54 +0800 | [diff] [blame] | 370 | LWS_VISIBLE int |
| 371 | lws_plat_open_file(const char* filename, unsigned long* filelen) |
| Andy Green | 158e804 | 2014-04-02 14:25:10 +0800 | [diff] [blame] | 372 | { |
| 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 Green | 1cd3ba6 | 2014-04-02 23:03:23 +0800 | [diff] [blame] | 382 | } |
| Andy Green | a654fc0 | 2014-04-03 07:16:40 +0800 | [diff] [blame] | 383 | |
| Andy Green | 1cd3ba6 | 2014-04-02 23:03:23 +0800 | [diff] [blame] | 384 | #ifdef LWS_USE_IPV6 |
| 385 | LWS_VISIBLE const char * |
| 386 | lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt) |
| 387 | { |
| 388 | return inet_ntop(af, src, dst, cnt); |
| 389 | } |
| vpeter4 | 4dd8ada | 2014-04-27 13:28:22 +0200 | [diff] [blame^] | 390 | #endif |