win32 more build fixes
[platform/upstream/libwebsockets.git] / lib / lws-plat-win.c
index 43b7c6a..842423b 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
+#define _WINSOCK_DEPRECATED_NO_WARNINGS
+#endif
 #include "private-libwebsockets.h"
 
 unsigned long long
@@ -28,7 +31,10 @@ time_in_microseconds()
 time_t time(time_t *t)
 {
        time_t ret = time_in_microseconds() / 1000000;
-       *t = ret;
+
+       if(t != NULL)
+               *t = ret;
+
        return ret;
 }
 #endif
@@ -36,7 +42,7 @@ time_t time(time_t *t)
 /* 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;
@@ -100,7 +106,7 @@ LWS_VISIBLE int lws_get_random(struct lws_context *context,
 
 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)
@@ -108,7 +114,7 @@ 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);
@@ -126,7 +132,20 @@ LWS_VISIBLE int lws_poll_listen_fd(struct lws_pollfd *fd)
 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)
@@ -135,44 +154,60 @@ 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) {
@@ -181,18 +216,19 @@ lws_plat_service(struct lws_context *context, int timeout_ms)
        }
 
        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;
@@ -203,23 +239,57 @@ lws_plat_service(struct lws_context *context, int timeout_ms)
        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,
@@ -227,23 +297,28 @@ lws_plat_set_socket_options(struct lws_context *context, lws_sockfd_type fd)
                        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);
@@ -257,35 +332,6 @@ lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
 }
 
 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;
@@ -310,9 +356,15 @@ lws_plat_context_early_init(void)
 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++;
        }
 }
 
@@ -329,8 +381,8 @@ lws_plat_context_late_destroy(struct lws_context *context)
        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);
@@ -350,20 +402,24 @@ interface_to_sa(struct lws_context *context,
 }
 
 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
@@ -375,16 +431,17 @@ LWS_VISIBLE int
 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;
 
@@ -393,26 +450,9 @@ lws_plat_change_pollfd(struct lws_context *context,
        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;
@@ -455,3 +495,118 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
        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;
+}