| #include "private-libwebsockets.h" |
| |
| unsigned long long |
| time_in_microseconds() |
| { |
| #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL |
| FILETIME filetime; |
| ULARGE_INTEGER datetime; |
| |
| #ifdef _WIN32_WCE |
| GetCurrentFT(&filetime); |
| #else |
| GetSystemTimeAsFileTime(&filetime); |
| #endif |
| |
| /* |
| * As per Windows documentation for FILETIME, copy the resulting FILETIME structure to a |
| * ULARGE_INTEGER structure using memcpy (using memcpy instead of direct assignment can |
| * prevent alignment faults on 64-bit Windows). |
| */ |
| memcpy(&datetime, &filetime, sizeof(datetime)); |
| |
| /* Windows file times are in 100s of nanoseconds. */ |
| return (datetime.QuadPart - DELTA_EPOCH_IN_MICROSECS) / 10; |
| } |
| |
| #ifdef _WIN32_WCE |
| time_t time(time_t *t) |
| { |
| time_t ret = time_in_microseconds() / 1000000; |
| *t = ret; |
| return ret; |
| } |
| #endif |
| |
| LWS_VISIBLE int libwebsockets_get_random(struct libwebsocket_context *context, |
| void *buf, int len) |
| { |
| int n; |
| char *p = (char *)buf; |
| |
| for (n = 0; n < len; n++) |
| p[n] = (unsigned char)rand(); |
| |
| return n; |
| } |
| |
| LWS_VISIBLE int lws_send_pipe_choked(struct libwebsocket *wsi) |
| { |
| return wsi->sock_send_blocking; |
| } |
| |
| static int lws_poll_listen_fd(struct libwebsocket_pollfd *fd) |
| { |
| fd_set readfds; |
| struct timeval tv = { 0, 0 }; |
| |
| assert(fd->events == LWS_POLLIN); |
| |
| FD_ZERO(&readfds); |
| FD_SET(fd->fd, &readfds); |
| |
| return select(fd->fd + 1, &readfds, NULL, NULL, &tv); |
| } |
| |
| /** |
| * libwebsocket_cancel_service() - Cancel servicing of pending websocket activity |
| * @context: Websocket context |
| * |
| * This function let a call to libwebsocket_service() waiting for a timeout |
| * immediately return. |
| */ |
| LWS_VISIBLE void |
| libwebsocket_cancel_service(struct libwebsocket_context *context) |
| { |
| WSASetEvent(context->events[0]); |
| } |
| |
| LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line) |
| { |
| lwsl_emit_stderr(level, line); |
| } |
| |
| LWS_VISIBLE int |
| lws_plat_service(struct libwebsocket_context *context, int timeout_ms) |
| { |
| int n; |
| int i; |
| DWORD ev; |
| WSANETWORKEVENTS networkevents; |
| struct libwebsocket_pollfd *pfd; |
| |
| /* stay dead once we are dead */ |
| |
| if (context == NULL) |
| return 1; |
| |
| context->service_tid = context->protocols[0].callback(context, NULL, |
| LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0); |
| |
| for (i = 0; i < context->fds_count; ++i) { |
| pfd = &context->fds[i]; |
| if (pfd->fd == context->listen_service_fd) |
| continue; |
| |
| if (pfd->events & LWS_POLLOUT) { |
| if (context->lws_lookup[pfd->fd]->sock_send_blocking) |
| continue; |
| pfd->revents = LWS_POLLOUT; |
| n = libwebsocket_service_fd(context, pfd); |
| if (n < 0) |
| return n; |
| } |
| } |
| |
| ev = WSAWaitForMultipleEvents(context->fds_count + 1, |
| context->events, FALSE, timeout_ms, FALSE); |
| context->service_tid = 0; |
| |
| if (ev == WSA_WAIT_TIMEOUT) { |
| libwebsocket_service_fd(context, NULL); |
| return 0; |
| } |
| |
| if (ev == WSA_WAIT_EVENT_0) { |
| WSAResetEvent(context->events[0]); |
| return 0; |
| } |
| |
| if (ev < WSA_WAIT_EVENT_0 || ev > WSA_WAIT_EVENT_0 + context->fds_count) |
| return -1; |
| |
| pfd = &context->fds[ev - WSA_WAIT_EVENT_0 - 1]; |
| |
| if (WSAEnumNetworkEvents(pfd->fd, |
| context->events[ev - WSA_WAIT_EVENT_0], |
| &networkevents) == SOCKET_ERROR) { |
| lwsl_err("WSAEnumNetworkEvents() failed with error %d\n", |
| LWS_ERRNO); |
| return -1; |
| } |
| |
| pfd->revents = networkevents.lNetworkEvents; |
| |
| if (pfd->revents & LWS_POLLOUT) |
| context->lws_lookup[pfd->fd]->sock_send_blocking = FALSE; |
| |
| return libwebsocket_service_fd(context, pfd); |
| } |
| |
| LWS_VISIBLE int |
| lws_plat_set_socket_options(struct libwebsocket_context *context, int fd) |
| { |
| int optval = 1; |
| socklen_t optlen = sizeof(optval); |
| u_long optl = 1; |
| DWORD dwBytesRet; |
| struct tcp_keepalive alive; |
| |
| if (context->ka_time) { |
| /* enable keepalive on this socket */ |
| optval = 1; |
| if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, |
| (const void *)&optval, optlen) < 0) |
| return 1; |
| |
| alive.onoff = TRUE; |
| alive.keepalivetime = context->ka_time; |
| alive.keepaliveinterval = context->ka_interval; |
| |
| if (WSAIoctl(fd, SIO_KEEPALIVE_VALS, &alive, sizeof(alive), |
| NULL, 0, &dwBytesRet, NULL, NULL)) |
| return 1; |
| } |
| |
| /* Disable Nagle */ |
| optval = 1; |
| tcp_proto = getprotobyname("TCP"); |
| setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, &optval, optlen); |
| |
| /* We are nonblocking... */ |
| ioctlsocket(fd, FIONBIO, &optl); |
| |
| return 0; |
| } |
| |
| LWS_VISIBLE void |
| lws_plat_drop_app_privileges(struct lws_context_creation_info *info) |
| { |
| } |
| |
| LWS_VISIBLE int |
| lws_plat_init_fd_tables(struct libwebsocket_context *context) |
| { |
| context->events = (WSAEVENT *)malloc(sizeof(WSAEVENT) * |
| (context->max_fds + 1)); |
| if (context->events == NULL) { |
| lwsl_err("Unable to allocate events array for %d connections\n", |
| context->max_fds); |
| return 1; |
| } |
| |
| context->fds_count = 0; |
| context->events[0] = WSACreateEvent(); |
| |
| context->fd_random = 0; |
| |
| return 0; |
| } |
| |
| LWS_VISIBLE int |
| lws_plat_context_early_init(void) |
| { |
| WORD wVersionRequested; |
| WSADATA wsaData; |
| int err; |
| |
| /* Use the MAKEWORD(lowbyte, highbyte) macro from Windef.h */ |
| wVersionRequested = MAKEWORD(2, 2); |
| |
| err = WSAStartup(wVersionRequested, &wsaData); |
| if (!err) |
| return 0; |
| /* |
| * Tell the user that we could not find a usable |
| * Winsock DLL |
| */ |
| lwsl_err("WSAStartup failed with error: %d\n", err); |
| |
| return 1; |
| } |
| |
| LWS_VISIBLE void |
| lws_plat_context_early_destroy(struct libwebsocket_context *context) |
| { |
| if (context->events) { |
| WSACloseEvent(context->events[0]); |
| free(context->events); |
| } |
| } |
| |
| LWS_VISIBLE void |
| lws_plat_context_late_destroy(struct libwebsocket_context *context) |
| { |
| WSACleanup(); |
| } |
| |
| LWS_VISIBLE int |
| interface_to_sa(struct libwebsocket_context *context, |
| const char *ifname, struct sockaddr_in *addr, size_t addrlen) |
| { |
| return -1; |
| } |
| |
| LWS_VISIBLE void |
| lws_plat_insert_socket_into_fds(struct libwebsocket_context *context, |
| struct libwebsocket *wsi) |
| { |
| context->fds[context->fds_count++].revents = 0; |
| context->events[context->fds_count] = WSACreateEvent(); |
| WSAEventSelect(wsi->sock, context->events[context->fds_count], LWS_POLLIN); |
| } |
| |
| LWS_VISIBLE void |
| lws_plat_delete_socket_from_fds(struct libwebsocket_context *context, |
| struct libwebsocket *wsi, int m) |
| { |
| WSACloseEvent(context->events[m + 1]); |
| context->events[m + 1] = context->events[context->fds_count + 1]; |
| } |
| |
| LWS_VISIBLE void |
| lws_plat_service_periodic(struct libwebsocket_context *context) |
| { |
| } |
| |
| LWS_VISIBLE int |
| lws_plat_change_pollfd(struct libwebsocket_context *context, |
| struct libwebsocket *wsi, struct libwebsocket_pollfd *pfd) |
| { |
| long networkevents = LWS_POLLOUT | LWS_POLLHUP; |
| |
| if ((pfd->events & LWS_POLLIN)) |
| networkevents |= LWS_POLLIN; |
| |
| if (WSAEventSelect(wsi->sock, |
| context->events[wsi->position_in_fds_table + 1], |
| networkevents) != SOCKET_ERROR) |
| return 0; |
| |
| lwsl_err("WSAEventSelect() failed with error %d\n", LWS_ERRNO); |
| |
| return 1; |
| } |
| |
| LWS_VISIBLE HANDLE |
| lws_plat_open_file(const char* filename, unsigned long* filelen) |
| { |
| HANDLE ret; |
| WCHAR buffer[MAX_PATH]; |
| |
| MultiByteToWideChar(CP_UTF8, 0, filename, -1, buffer, |
| sizeof(buffer) / sizeof(buffer[0])); |
| ret = CreateFileW(buffer, GENERIC_READ, FILE_SHARE_READ, |
| NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); |
| |
| if (ret != LWS_INVALID_FILE) |
| *filelen = GetFileSize(ret, NULL); |
| |
| return ret; |
| } |
| |
| /* |
| * Windows doesn't have an "inet_top" |
| * This came from http://memset.wordpress.com/2010/10/09/inet_ntop-for-win32/ |
| * suggested by Joakim Soderberg |
| */ |
| |
| LWS_VISIBLE |
| const char *inet_ntop(int af, const void *src, char *dst, int cnt) |
| { |
| struct sockaddr_in srcaddr; |
| DWORD rv; |
| |
| memset(&srcaddr, 0, sizeof(struct sockaddr_in)); |
| memcpy(&(srcaddr.sin_addr), src, sizeof(srcaddr.sin_addr)); |
| |
| srcaddr.sin_family = af; |
| if (!WSAAddressToString((struct sockaddr*) &srcaddr, |
| sizeof(struct sockaddr_in), 0, dst, (LPDWORD) &cnt)) |
| return dst; |
| |
| rv = WSAGetLastError(); |
| lwsl_err("WSAAddressToString() : %d\n",rv); |
| |
| return NULL; |
| } |