win32: enable 64-bit file lengths
[platform/upstream/libwebsockets.git] / lib / lws-plat-win.c
index cdf37e9..9f50cda 100644 (file)
@@ -6,7 +6,9 @@
 unsigned long long
 time_in_microseconds()
 {
+#ifndef DELTA_EPOCH_IN_MICROSECS
 #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
+#endif
        FILETIME filetime;
        ULARGE_INTEGER datetime;
 
@@ -48,7 +50,7 @@ wsi_from_fd(const struct lws_context *context, lws_sockfd_type fd)
        int n = 0;
 
        for (n = 0; n < context->fd_hashtable[h].length; n++)
-               if (context->fd_hashtable[h].wsi[n]->sock == fd)
+               if (context->fd_hashtable[h].wsi[n]->desc.sockfd == fd)
                        return context->fd_hashtable[h].wsi[n];
 
        return NULL;
@@ -57,7 +59,7 @@ wsi_from_fd(const struct lws_context *context, lws_sockfd_type fd)
 int
 insert_wsi(struct lws_context *context, struct lws *wsi)
 {
-       int h = LWS_FD_HASH(wsi->sock);
+       int h = LWS_FD_HASH(wsi->desc.sockfd);
 
        if (context->fd_hashtable[h].length == (getdtablesize() - 1)) {
                lwsl_err("hash table overflow\n");
@@ -76,7 +78,7 @@ delete_from_fd(struct lws_context *context, lws_sockfd_type fd)
        int n = 0;
 
        for (n = 0; n < context->fd_hashtable[h].length; n++)
-               if (context->fd_hashtable[h].wsi[n]->sock == fd) {
+               if (context->fd_hashtable[h].wsi[n]->desc.sockfd == fd) {
                        while (n < context->fd_hashtable[h].length) {
                                context->fd_hashtable[h].wsi[n] =
                                                context->fd_hashtable[h].wsi[n + 1];
@@ -106,6 +108,10 @@ LWS_VISIBLE int lws_get_random(struct lws_context *context,
 
 LWS_VISIBLE int lws_send_pipe_choked(struct lws *wsi)
 {
+       /* treat the fact we got a truncated send pending as if we're choked */
+       if (wsi->trunc_len)
+               return 1;
+
        return (int)wsi->sock_send_blocking;
 }
 
@@ -146,10 +152,10 @@ LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)
        lwsl_emit_stderr(level, line);
 }
 
-LWS_VISIBLE int
-lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
+LWS_VISIBLE LWS_EXTERN int
+_lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
 {
-       struct lws_context_per_thread *pt = &context->pt[tsi];
+       struct lws_context_per_thread *pt;
        WSANETWORKEVENTS networkevents;
        struct lws_pollfd *pfd;
        struct lws *wsi;
@@ -161,6 +167,8 @@ lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
        if (context == NULL)
                return 1;
 
+       pt = &context->pt[tsi];
+
        if (!context->service_tid_detected) {
                struct lws _lws;
 
@@ -212,15 +220,25 @@ lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
                        i--;
        }
 
-       /* if we know something needs service already, don't wait in poll */
-       timeout_ms = lws_service_adjust_timeout(context, timeout_ms, tsi);
+       /*
+        * is there anybody with pending stuff that needs service forcing?
+        */
+       if (!lws_service_adjust_timeout(context, 1, tsi)) {
+               /* -1 timeout means just do forced service */
+               _lws_plat_service_tsi(context, -1, pt->tid);
+               /* still somebody left who wants forced service? */
+               if (!lws_service_adjust_timeout(context, 1, pt->tid))
+                       /* yes... come back again quickly */
+                       timeout_ms = 0;
+       }
 
        ev = WSAWaitForMultipleEvents( 1,  pt->events , FALSE, timeout_ms, FALSE);
        if (ev == WSA_WAIT_EVENT_0) {
+               unsigned int eIdx;
 
                WSAResetEvent(pt->events[0]);
 
-               for(unsigned int eIdx = 0; eIdx < pt->fds_count; ++eIdx) {
+               for (eIdx = 0; eIdx < pt->fds_count; ++eIdx) {
                        if (WSAEnumNetworkEvents(pt->fds[eIdx].fd, 0, &networkevents) == SOCKET_ERROR) {
                                lwsl_err("WSAEnumNetworkEvents() failed with error %d\n", LWS_ERRNO);
                                return -1;
@@ -268,7 +286,7 @@ lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
 LWS_VISIBLE int
 lws_plat_service(struct lws_context *context, int timeout_ms)
 {
-       return lws_plat_service_tsi(context, timeout_ms, 0);
+       return _lws_plat_service_tsi(context, timeout_ms, 0);
 }
 
 LWS_VISIBLE int
@@ -380,6 +398,16 @@ LWS_VISIBLE LWS_EXTERN int
 lws_interface_to_sa(int ipv6,
                const char *ifname, struct sockaddr_in *addr, size_t addrlen)
 {
+#ifdef LWS_USE_IPV6
+       struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
+
+       if (ipv6) {
+               if (lws_plat_inet_pton(AF_INET6, ifname, &addr6->sin6_addr) == 1) {
+                       return 0;
+               }
+       }
+#endif
+
        long long address = inet_addr(ifname);
 
        if (address == INADDR_NONE) {
@@ -403,7 +431,7 @@ lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
 
        pt->fds[pt->fds_count++].revents = 0;
        pt->events[pt->fds_count] = pt->events[0];
-       WSAEventSelect(wsi->sock, pt->events[0],
+       WSAEventSelect(wsi->desc.sockfd, pt->events[0],
                           LWS_POLLIN | LWS_POLLHUP | FD_CONNECT);
 }
 
@@ -427,7 +455,7 @@ lws_plat_check_connection_error(struct lws *wsi)
        int optVal;
        int optLen = sizeof(int);
 
-       if (getsockopt(wsi->sock, SOL_SOCKET, SO_ERROR,
+       if (getsockopt(wsi->desc.sockfd, SOL_SOCKET, SO_ERROR,
                           (char*)&optVal, &optLen) != SOCKET_ERROR && optVal &&
                optVal != LWS_EALREADY && optVal != LWS_EINPROGRESS &&
                optVal != LWS_EWOULDBLOCK && optVal != WSAEINVAL) {
@@ -451,7 +479,7 @@ lws_plat_change_pollfd(struct lws_context *context,
        if ((pfd->events & LWS_POLLOUT))
                networkevents |= LWS_POLLOUT;
 
-       if (WSAEventSelect(wsi->sock,
+       if (WSAEventSelect(wsi->desc.sockfd,
                        pt->events[0],
                                                   networkevents) != SOCKET_ERROR)
                return 0;
@@ -468,7 +496,7 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
        DWORD bufferlen = cnt;
        BOOL ok = FALSE;
 
-       buffer = lws_malloc(bufferlen);
+       buffer = lws_malloc(bufferlen * 2);
        if (!buffer) {
                lwsl_err("Out of memory\n");
                return NULL;
@@ -507,78 +535,156 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
        return ok ? dst : NULL;
 }
 
-static lws_filefd_type
-_lws_plat_file_open(struct lws *wsi, const char *filename,
-                       unsigned long *filelen, int flags)
+LWS_VISIBLE int
+lws_plat_inet_pton(int af, const char *src, void *dst)
+{
+       WCHAR *buffer;
+       DWORD bufferlen = strlen(src) + 1;
+       BOOL ok = FALSE;
+
+       buffer = lws_malloc(bufferlen * 2);
+       if (!buffer) {
+               lwsl_err("Out of memory\n");
+               return -1;
+       }
+
+       if (MultiByteToWideChar(CP_ACP, 0, src, bufferlen, buffer, bufferlen) <= 0) {
+               lwsl_err("Failed to convert multi byte to wide char\n");
+               lws_free(buffer);
+               return -1;
+       }
+
+       if (af == AF_INET) {
+               struct sockaddr_in dstaddr;
+               int dstaddrlen = sizeof(dstaddr);
+               bzero(&dstaddr, sizeof(dstaddr));
+               dstaddr.sin_family = AF_INET;
+
+               if (!WSAStringToAddressW(buffer, af, 0, (struct sockaddr *) &dstaddr, &dstaddrlen)) {
+                       ok = TRUE;
+                       memcpy(dst, &dstaddr.sin_addr, sizeof(dstaddr.sin_addr));
+               }
+#ifdef LWS_USE_IPV6
+       } else if (af == AF_INET6) {
+               struct sockaddr_in6 dstaddr;
+               int dstaddrlen = sizeof(dstaddr);
+               bzero(&dstaddr, sizeof(dstaddr));
+               dstaddr.sin6_family = AF_INET6;
+
+               if (!WSAStringToAddressW(buffer, af, 0, (struct sockaddr *) &dstaddr, &dstaddrlen)) {
+                       ok = TRUE;
+                       memcpy(dst, &dstaddr.sin6_addr, sizeof(dstaddr.sin6_addr));
+               }
+#endif
+       } else
+               lwsl_err("Unsupported type\n");
+
+       if (!ok) {
+               int rv = WSAGetLastError();
+               lwsl_err("WSAAddressToString() : %d\n", rv);
+       }
+
+       lws_free(buffer);
+       return ok ? 1 : -1;
+}
+
+LWS_VISIBLE lws_fop_fd_t
+_lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
+                   const char *vpath, lws_fop_flags_t *flags)
 {
        HANDLE ret;
        WCHAR buf[MAX_PATH];
+       lws_fop_fd_t fop_fd;
+       LARGE_INTEGER llFileSize = {0};
 
-       (void)wsi;
        MultiByteToWideChar(CP_UTF8, 0, filename, -1, buf, ARRAY_SIZE(buf));
-       if ((flags & 7) == _O_RDONLY) {
+       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;
+               ret = CreateFileW(buf, GENERIC_WRITE, 0, NULL,
+                         CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
        }
 
-       if (ret != LWS_INVALID_FILE)
-               *filelen = GetFileSize(ret, NULL);
+       if (ret == LWS_INVALID_FILE)
+               goto bail;
 
-       return ret;
+       fop_fd = malloc(sizeof(*fop_fd));
+       if (!fop_fd)
+               goto bail;
+
+       fop_fd->fops = fops;
+       fop_fd->fd = ret;
+       fop_fd->filesystem_priv = NULL; /* we don't use it */
+       fop_fd->flags = *flags;
+       fop_fd->len = GetFileSize(ret, NULL);
+       if(GetFileSizeEx(ret, &llFileSize))
+               fop_fd->len = llFileSize.QuadPart;
+
+       fop_fd->pos = 0;
+
+       return fop_fd;
+
+bail:
+       return NULL;
 }
 
-static int
-_lws_plat_file_close(struct lws *wsi, lws_filefd_type fd)
+LWS_VISIBLE int
+_lws_plat_file_close(lws_fop_fd_t *fop_fd)
 {
-       (void)wsi;
+       HANDLE fd = (*fop_fd)->fd;
+
+       free(*fop_fd);
+       *fop_fd = NULL;
 
        CloseHandle((HANDLE)fd);
 
        return 0;
 }
 
-static unsigned long
-_lws_plat_file_seek_cur(struct lws *wsi, lws_filefd_type fd, long offset)
+LWS_VISIBLE lws_fileofs_t
+_lws_plat_file_seek_cur(lws_fop_fd_t fop_fd, lws_fileofs_t offset)
 {
-       (void)wsi;
+       LARGE_INTEGER l;
 
-       return SetFilePointer((HANDLE)fd, offset, NULL, FILE_CURRENT);
+       l.QuadPart = offset;
+       return SetFilePointerEx((HANDLE)fop_fd->fd, l, 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)
+LWS_VISIBLE int
+_lws_plat_file_read(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
+                   uint8_t *buf, lws_filepos_t len)
 {
        DWORD _amount;
 
-       if (!ReadFile((HANDLE)fd, buf, (DWORD)len, &_amount, NULL)) {
+       if (!ReadFile((HANDLE)fop_fd->fd, buf, (DWORD)len, &_amount, NULL)) {
                *amount = 0;
 
                return 1;
        }
 
+       fop_fd->pos += _amount;
        *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)
+LWS_VISIBLE int
+_lws_plat_file_write(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
+                        uint8_t* buf, lws_filepos_t len)
 {
-       (void)wsi;
-       (void)fd;
-       (void)amount;
-       (void)buf;
-       (void)len;
+       DWORD _amount;
+
+       if (!WriteFile((HANDLE)fop_fd->fd, buf, (DWORD)len, &_amount, NULL)) {
+               *amount = 0;
 
-       lwsl_err("%s: not implemented yet on this platform\n", __func__);
+               return 1;
+       }
 
-       return -1;
+       fop_fd->pos += _amount;
+       *amount = (unsigned long)_amount;
+
+       return 0;
 }
 
 LWS_VISIBLE int
@@ -613,12 +719,6 @@ lws_plat_init(struct lws_context *context,
 
        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;
-
 #ifdef LWS_WITH_PLUGINS
        if (info->plugin_dirs)
                lws_plat_plugins_init(context, info->plugin_dirs);
@@ -626,3 +726,17 @@ lws_plat_init(struct lws_context *context,
 
        return 0;
 }
+
+
+int kill(int pid, int sig)
+{
+       lwsl_err("Sorry Windows doesn't support kill().");
+       exit(0);
+}
+
+int fork(void)
+{
+       lwsl_err("Sorry Windows doesn't support fork().");
+       exit(0);
+}
+