blob: 585c61003779903281b535956e1efd4abf08765b [file] [log] [blame]
#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;
}