+#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
+#define _WINSOCK_DEPRECATED_NO_WARNINGS
+#endif
#include "private-libwebsockets.h"
unsigned long long
time_t time(time_t *t)
{
time_t ret = time_in_microseconds() / 1000000;
- *t = ret;
+
+ if(t != NULL)
+ *t = ret;
+
return ret;
}
#endif
/* file descriptor hash management */
struct lws *
-wsi_from_fd(struct lws_context *context, lws_sockfd_type fd)
+wsi_from_fd(const struct lws_context *context, lws_sockfd_type fd)
{
int h = LWS_FD_HASH(fd);
int n = 0;
LWS_VISIBLE int lws_send_pipe_choked(struct lws *wsi)
{
- return wsi->sock_send_blocking;
+ return (int)wsi->sock_send_blocking;
}
LWS_VISIBLE int lws_poll_listen_fd(struct lws_pollfd *fd)
fd_set readfds;
struct timeval tv = { 0, 0 };
- assert(fd->events == LWS_POLLIN);
+ assert((fd->events & LWS_POLLIN) == LWS_POLLIN);
FD_ZERO(&readfds);
FD_SET(fd->fd, &readfds);
LWS_VISIBLE void
lws_cancel_service(struct lws_context *context)
{
- WSASetEvent(context->events[0]);
+ struct lws_context_per_thread *pt = &context->pt[0];
+ int n = context->count_threads;
+
+ while (n--) {
+ WSASetEvent(pt->events[0]);
+ pt++;
+ }
+}
+
+LWS_VISIBLE void
+lws_cancel_service_pt(struct lws *wsi)
+{
+ struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+ WSASetEvent(pt->events[0]);
}
LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)
}
LWS_VISIBLE int
-lws_plat_service(struct lws_context *context, int timeout_ms)
+lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
{
- int n;
- int i;
- DWORD ev;
+ struct lws_context_per_thread *pt = &context->pt[tsi];
WSANETWORKEVENTS networkevents;
struct lws_pollfd *pfd;
struct lws *wsi;
+ unsigned int i;
+ DWORD ev;
+ int n, m;
/* 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);
+ if (!context->service_tid_detected) {
+ struct lws _lws;
+
+ memset(&_lws, 0, sizeof(_lws));
+ _lws.context = context;
+
+ context->service_tid_detected = context->vhost_list->
+ protocols[0].callback(&_lws, LWS_CALLBACK_GET_THREAD_ID,
+ NULL, NULL, 0);
+ }
+ context->service_tid = context->service_tid_detected;
+
+ if (timeout_ms < 0)
+ goto faked_service;
+
+ for (i = 0; i < pt->fds_count; ++i) {
+ pfd = &pt->fds[i];
- for (i = 0; i < context->fds_count; ++i) {
- pfd = &context->fds[i];
- if (pfd->fd == context->listen_service_fd)
+ if (!(pfd->events & LWS_POLLOUT))
continue;
- if (pfd->events & LWS_POLLOUT) {
- wsi = wsi_from_fd(context, pfd->fd);
- if (!wsi || wsi->sock_send_blocking)
- continue;
- pfd->revents = LWS_POLLOUT;
- n = lws_service_fd(context, pfd);
- if (n < 0)
- return -1;
- /* if something closed, retry this slot */
- if (n)
- i--;
- }
+ wsi = wsi_from_fd(context, pfd->fd);
+ if (wsi->listener)
+ continue;
+ if (!wsi || wsi->sock_send_blocking)
+ continue;
+ pfd->revents = LWS_POLLOUT;
+ n = lws_service_fd(context, pfd);
+ if (n < 0)
+ return -1;
+ /* if something closed, retry this slot */
+ if (n)
+ i--;
}
- ev = WSAWaitForMultipleEvents(context->fds_count + 1,
- context->events, FALSE, timeout_ms, FALSE);
+ /* if we know something needs service already, don't wait in poll */
+ timeout_ms = lws_service_adjust_timeout(context, timeout_ms, tsi);
+
+ ev = WSAWaitForMultipleEvents(pt->fds_count + 1, pt->events,
+ FALSE, timeout_ms, FALSE);
context->service_tid = 0;
if (ev == WSA_WAIT_TIMEOUT) {
}
if (ev == WSA_WAIT_EVENT_0) {
- WSAResetEvent(context->events[0]);
+ WSAResetEvent(pt->events[0]);
return 0;
}
- if (ev < WSA_WAIT_EVENT_0 || ev > WSA_WAIT_EVENT_0 + context->fds_count)
+ if (ev < WSA_WAIT_EVENT_0 || ev > WSA_WAIT_EVENT_0 + pt->fds_count)
return -1;
- pfd = &context->fds[ev - WSA_WAIT_EVENT_0 - 1];
+ pfd = &pt->fds[ev - WSA_WAIT_EVENT_0 - 1];
- if (WSAEnumNetworkEvents(pfd->fd,
- context->events[ev - WSA_WAIT_EVENT_0],
- &networkevents) == SOCKET_ERROR) {
+ /* eh... is one event at a time the best windows can do? */
+
+ if (WSAEnumNetworkEvents(pfd->fd, pt->events[ev - WSA_WAIT_EVENT_0],
+ &networkevents) == SOCKET_ERROR) {
lwsl_err("WSAEnumNetworkEvents() failed with error %d\n",
LWS_ERRNO);
return -1;
if (pfd->revents & LWS_POLLOUT) {
wsi = wsi_from_fd(context, pfd->fd);
if (wsi)
- wsi->sock_send_blocking = FALSE;
+ wsi->sock_send_blocking = 0;
+ }
+
+faked_service:
+
+ /* if someone faked their LWS_POLLIN, then go through all active fds */
+
+ if (lws_service_flag_pending(context, tsi)) {
+ /* any socket with events to service? */
+ for (n = 0; n < (int)pt->fds_count; n++) {
+ if (!pt->fds[n].revents)
+ continue;
+
+ m = lws_service_fd_tsi(context, &pt->fds[n], tsi);
+ if (m < 0)
+ return -1;
+ /* if something closed, retry this slot */
+ if (m)
+ n--;
+ }
+ return 0;
}
- return lws_service_fd(context, pfd);
+ if (timeout_ms < 0)
+ return 0;
+
+ /* otherwise just do the one... must be a way to improve that... */
+
+ return lws_service_fd_tsi(context, pfd, tsi);
+}
+
+LWS_VISIBLE int
+lws_plat_service(struct lws_context *context, int timeout_ms)
+{
+ return lws_plat_service_tsi(context, timeout_ms, 0);
}
LWS_VISIBLE int
-lws_plat_set_socket_options(struct lws_context *context, lws_sockfd_type fd)
+lws_plat_set_socket_options(struct lws_vhost *vhost, lws_sockfd_type fd)
{
int optval = 1;
int optlen = sizeof(optval);
u_long optl = 1;
DWORD dwBytesRet;
struct tcp_keepalive alive;
+ int protonbr;
+#ifndef _WIN32_WCE
struct protoent *tcp_proto;
-
- if (context->ka_time) {
+#endif
+
+ if (vhost->ka_time) {
/* enable keepalive on this socket */
optval = 1;
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
return 1;
alive.onoff = TRUE;
- alive.keepalivetime = context->ka_time;
- alive.keepaliveinterval = context->ka_interval;
+ alive.keepalivetime = vhost->ka_time;
+ alive.keepaliveinterval = vhost->ka_interval;
- if (WSAIoctl(fd, SIO_KEEPALIVE_VALS, &alive, sizeof(alive),
+ if (WSAIoctl(fd, SIO_KEEPALIVE_VALS, &alive, sizeof(alive),
NULL, 0, &dwBytesRet, NULL, NULL))
return 1;
}
/* Disable Nagle */
optval = 1;
+#ifndef _WIN32_WCE
tcp_proto = getprotobyname("TCP");
if (!tcp_proto) {
lwsl_err("getprotobyname() failed with error %d\n", LWS_ERRNO);
return 1;
}
+ protonbr = tcp_proto->p_proto;
+#else
+ protonbr = 6;
+#endif
- setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, (const char *)&optval, optlen);
+ setsockopt(fd, protonbr, TCP_NODELAY, (const char *)&optval, optlen);
/* We are nonblocking... */
ioctlsocket(fd, FIONBIO, &optl);
}
LWS_VISIBLE int
-lws_plat_init(struct lws_context *context,
- struct lws_context_creation_info *info)
-{
- int i;
-
- for (i = 0; i < FD_HASHTABLE_MODULUS; i++) {
- context->fd_hashtable[i].wsi = lws_zalloc(sizeof(struct lws*) * context->max_fds);
-
- if (!context->fd_hashtable[i].wsi) {
- return -1;
- }
- }
-
- context->events = lws_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;
LWS_VISIBLE void
lws_plat_context_early_destroy(struct lws_context *context)
{
- if (context->events) {
- WSACloseEvent(context->events[0]);
- lws_free(context->events);
+ struct lws_context_per_thread *pt = &context->pt[0];
+ int n = context->count_threads;
+
+ while (n--) {
+ if (pt->events) {
+ WSACloseEvent(pt->events[0]);
+ lws_free(pt->events);
+ }
+ pt++;
}
}
WSACleanup();
}
-LWS_VISIBLE int
-interface_to_sa(struct lws_context *context,
+LWS_VISIBLE LWS_EXTERN int
+lws_interface_to_sa(int ipv6,
const char *ifname, struct sockaddr_in *addr, size_t addrlen)
{
long long address = inet_addr(ifname);
}
LWS_VISIBLE void
-lws_plat_insert_socket_into_fds(struct lws_context *context,
- struct lws *wsi)
+lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
{
- context->fds[context->fds_count++].revents = 0;
- context->events[context->fds_count] = WSACreateEvent();
- WSAEventSelect(wsi->sock, context->events[context->fds_count], LWS_POLLIN);
+ struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
+
+ pt->fds[pt->fds_count++].revents = 0;
+ pt->events[pt->fds_count] = WSACreateEvent();
+ WSAEventSelect(wsi->sock, pt->events[pt->fds_count],
+ LWS_POLLIN | LWS_POLLHUP);
}
LWS_VISIBLE void
lws_plat_delete_socket_from_fds(struct lws_context *context,
struct lws *wsi, int m)
{
- WSACloseEvent(context->events[m + 1]);
- context->events[m + 1] = context->events[context->fds_count + 1];
+ struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
+
+ WSACloseEvent(pt->events[m + 1]);
+ pt->events[m + 1] = pt->events[pt->fds_count--];
}
LWS_VISIBLE void
lws_plat_change_pollfd(struct lws_context *context,
struct lws *wsi, struct lws_pollfd *pfd)
{
+ struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
long networkevents = LWS_POLLHUP;
-
+
if ((pfd->events & LWS_POLLIN))
networkevents |= LWS_POLLIN;
-
+
if ((pfd->events & LWS_POLLOUT))
networkevents |= LWS_POLLOUT;
if (WSAEventSelect(wsi->sock,
- context->events[wsi->position_in_fds_table + 1],
+ pt->events[wsi->position_in_fds_table + 1],
networkevents) != SOCKET_ERROR)
return 0;
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;
-}
-
LWS_VISIBLE const char *
lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
-{
+{
WCHAR *buffer;
DWORD bufferlen = cnt;
BOOL ok = FALSE;
lws_free(buffer);
return ok ? dst : NULL;
}
+
+static lws_filefd_type
+_lws_plat_file_open(struct lws *wsi, const char *filename,
+ unsigned long *filelen, int flags)
+{
+ HANDLE ret;
+ WCHAR buf[MAX_PATH];
+
+ (void)wsi;
+ MultiByteToWideChar(CP_UTF8, 0, filename, -1, buf, ARRAY_SIZE(buf));
+ if ((flags & 7) == _O_RDONLY) {
+ ret = CreateFileW(buf, GENERIC_READ, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ } else {
+ lwsl_err("%s: open for write not implemented\n", __func__);
+ *filelen = 0;
+ return LWS_INVALID_FILE;
+ }
+
+ if (ret != LWS_INVALID_FILE)
+ *filelen = GetFileSize(ret, NULL);
+
+ return ret;
+}
+
+static int
+_lws_plat_file_close(struct lws *wsi, lws_filefd_type fd)
+{
+ (void)wsi;
+
+ CloseHandle((HANDLE)fd);
+
+ return 0;
+}
+
+static unsigned long
+_lws_plat_file_seek_cur(struct lws *wsi, lws_filefd_type fd, long offset)
+{
+ (void)wsi;
+
+ return SetFilePointer((HANDLE)fd, offset, NULL, FILE_CURRENT);
+}
+
+static int
+_lws_plat_file_read(struct lws *wsi, lws_filefd_type fd, unsigned long *amount,
+ unsigned char* buf, unsigned long len)
+{
+ DWORD _amount;
+
+ if (!ReadFile((HANDLE)fd, buf, (DWORD)len, &_amount, NULL)) {
+ *amount = 0;
+
+ return 1;
+ }
+
+ *amount = (unsigned long)_amount;
+
+ return 0;
+}
+
+static int
+_lws_plat_file_write(struct lws *wsi, lws_filefd_type fd, unsigned long *amount,
+ unsigned char* buf, unsigned long len)
+{
+ (void)wsi;
+ (void)fd;
+ (void)amount;
+ (void)buf;
+ (void)len;
+
+ lwsl_err("%s: not implemented yet on this platform\n", __func__);
+
+ return -1;
+}
+
+LWS_VISIBLE int
+lws_plat_init(struct lws_context *context,
+ struct lws_context_creation_info *info)
+{
+ struct lws_context_per_thread *pt = &context->pt[0];
+ int i, n = context->count_threads;
+
+ for (i = 0; i < FD_HASHTABLE_MODULUS; i++) {
+ context->fd_hashtable[i].wsi =
+ lws_zalloc(sizeof(struct lws*) * context->max_fds);
+
+ if (!context->fd_hashtable[i].wsi)
+ return -1;
+ }
+
+ while (n--) {
+ pt->events = lws_malloc(sizeof(WSAEVENT) *
+ (context->fd_limit_per_thread + 1));
+ if (pt->events == NULL) {
+ lwsl_err("Unable to allocate events array for %d connections\n",
+ context->fd_limit_per_thread + 1);
+ return 1;
+ }
+
+ pt->fds_count = 0;
+ pt->events[0] = WSACreateEvent();
+
+ pt++;
+ }
+
+ context->fd_random = 0;
+
+ context->fops.open = _lws_plat_file_open;
+ context->fops.close = _lws_plat_file_close;
+ context->fops.seek_cur = _lws_plat_file_seek_cur;
+ context->fops.read = _lws_plat_file_read;
+ context->fops.write = _lws_plat_file_write;
+
+ return 0;
+}