win32 use hashtable for fd management
authorBud Davis <bdavis9659@gmail.com>
Fri, 30 Jan 2015 02:13:01 +0000 (10:13 +0800)
committerAndy Green <andy.green@linaro.org>
Fri, 30 Jan 2015 02:48:57 +0000 (10:48 +0800)
At least some win32 uses an opaque pointer for fd that is not
an ordinal like it is in unix.

Resurrect the old hashtable management for that platform to use
instead, and introduce a helper to get the wsi from the fd "somehow".

Signed-off-by: Bud Davis <bdavis9659@gmail.com>
lib/context.c
lib/libwebsockets.c
lib/lws-plat-win.c
lib/pollfd.c
lib/private-libwebsockets.h
lib/service.c

index 2ea9c60..fa62f83 100644 (file)
@@ -76,7 +76,9 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
 {
        struct libwebsocket_context *context = NULL;
        char *p;
-
+#ifdef _WIN32
+       int i;
+#endif
        int pid_daemon = get_daemonize_pid();
 
        lwsl_notice("Initial logging level %d\n", log_level);
@@ -145,6 +147,11 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
                return NULL;
        }
 
+#ifdef _WIN32
+       for (i = 0; i < FD_HASHTABLE_MODULUS; i++) {
+               context->fd_hashtable[i].wsi = lws_zalloc(sizeof(struct libwebsocket*) * context->max_fds);
+       }
+#else
        context->lws_lookup = lws_zalloc(sizeof(struct libwebsocket *) * context->max_fds);
        if (context->lws_lookup == NULL) {
                lwsl_err(
@@ -154,9 +161,12 @@ libwebsocket_create_context(struct lws_context_creation_info *info)
                lws_free(context);
                return NULL;
        }
+#endif
 
        if (lws_plat_init_fd_tables(context)) {
+#ifndef _WIN32
                lws_free(context->lws_lookup);
+#endif
                lws_free(context->fds);
                lws_free(context);
                return NULL;
@@ -292,7 +302,7 @@ libwebsocket_context_destroy(struct libwebsocket_context *context)
 
        for (n = 0; n < context->fds_count; n++) {
                struct libwebsocket *wsi =
-                                       context->lws_lookup[context->fds[n].fd];
+                                       wsi_from_fd(context, context->fds[n].fd);
                if (!wsi)
                        continue;
                libwebsocket_close_and_free_session(context,
@@ -329,8 +339,9 @@ libwebsocket_context_destroy(struct libwebsocket_context *context)
        lws_ssl_context_destroy(context);
 
        lws_free(context->fds);
+#ifndef _WIN32
        lws_free(context->lws_lookup);
-
+#endif
        lws_plat_context_late_destroy(context);
 
        lws_free(context);
index 1d8af8d..d32269f 100644 (file)
@@ -37,7 +37,6 @@ static const char * const log_level_names[] = {
        "LATENCY",
 };
 
-
 void
 libwebsocket_close_and_free_session(struct libwebsocket_context *context,
                         struct libwebsocket *wsi, enum lws_close_status reason)
@@ -451,7 +450,7 @@ libwebsocket_callback_all_protocol(
        struct libwebsocket *wsi;
 
        for (n = 0; n < context->fds_count; n++) {
-               wsi = context->lws_lookup[context->fds[n].fd];
+               wsi = wsi_from_fd(context, context->fds[n].fd);
                if (!wsi)
                        continue;
                if (wsi->protocol == protocol)
@@ -584,7 +583,7 @@ libwebsocket_rx_flow_allow_all_protocol(
        struct libwebsocket *wsi;
 
        for (n = 0; n < context->fds_count; n++) {
-               wsi = context->lws_lookup[context->fds[n].fd];
+               wsi = wsi_from_fd(context, context->fds[n].fd);
                if (!wsi)
                        continue;
                if (wsi->protocol == protocol)
index 2503fc0..63e3bcb 100644 (file)
@@ -33,6 +33,59 @@ time_t time(time_t *t)
 }
 #endif
 
+/* file descriptor hash management */
+
+struct libwebsocket *
+wsi_from_fd(struct libwebsocket_context *context, int fd)
+{
+       int h = LWS_FD_HASH(fd);
+       int n = 0;
+
+       for (n = 0; n < context->fd_hashtable[h].length; n++)
+               if (context->fd_hashtable[h].wsi[n]->sock == fd)
+                       return context->fd_hashtable[h].wsi[n];
+
+       return NULL;
+}
+
+int
+insert_wsi(struct libwebsocket_context *context, struct libwebsocket *wsi)
+{
+       int h = LWS_FD_HASH(wsi->sock);
+
+       if (context->fd_hashtable[h].length == (getdtablesize() - 1)) {
+               lwsl_err("hash table overflow\n");
+               return 1;
+       }
+
+       context->fd_hashtable[h].wsi[context->fd_hashtable[h].length++] = wsi;
+
+       return 0;
+}
+
+int
+delete_from_fd(struct libwebsocket_context *context, int fd)
+{
+       int h = LWS_FD_HASH(fd);
+       int n = 0;
+
+       for (n = 0; n < context->fd_hashtable[h].length; n++)
+               if (context->fd_hashtable[h].wsi[n]->sock == fd) {
+                       while (n < context->fd_hashtable[h].length) {
+                               context->fd_hashtable[h].wsi[n] =
+                                           context->fd_hashtable[h].wsi[n + 1];
+                               n++;
+                       }
+                       context->fd_hashtable[h].length--;
+
+                       return 0;
+               }
+
+       lwsl_err("Failed to find fd %d requested for "
+                "delete in hashtable\n", fd);
+       return 1;
+}
+
 LWS_VISIBLE int libwebsockets_get_random(struct libwebsocket_context *context,
                                                             void *buf, int len)
 {
@@ -104,7 +157,7 @@ lws_plat_service(struct libwebsocket_context *context, int timeout_ms)
                        continue;
 
                if (pfd->events & LWS_POLLOUT) {
-                       if (context->lws_lookup[pfd->fd]->sock_send_blocking)
+                       if (wsi_from_fd(context,pfd->fd)->sock_send_blocking)
                                continue;
                        pfd->revents = LWS_POLLOUT;
                        n = libwebsocket_service_fd(context, pfd);
@@ -143,7 +196,7 @@ lws_plat_service(struct libwebsocket_context *context, int timeout_ms)
        pfd->revents = networkevents.lNetworkEvents;
 
        if (pfd->revents & LWS_POLLOUT)
-               context->lws_lookup[pfd->fd]->sock_send_blocking = FALSE;
+               wsi_from_fd(context,pfd->fd)->sock_send_blocking = FALSE;
 
        return libwebsocket_service_fd(context, pfd);
 }
index b09127e..19905ef 100644 (file)
@@ -32,11 +32,13 @@ insert_wsi_socket_into_fds(struct libwebsocket_context *context,
                return 1;
        }
 
+#ifndef _WIN32
        if (wsi->sock >= context->max_fds) {
                lwsl_err("Socket fd %d is too high (%d)\n",
                                                wsi->sock, context->max_fds);
                return 1;
        }
+#endif
 
        assert(wsi);
        assert(wsi->sock >= 0);
@@ -48,7 +50,7 @@ insert_wsi_socket_into_fds(struct libwebsocket_context *context,
                LWS_CALLBACK_LOCK_POLL,
                wsi->user_space, (void *) &pa, 0);
 
-       context->lws_lookup[wsi->sock] = wsi;
+       insert_wsi(context, wsi);
        wsi->position_in_fds_table = context->fds_count;
        context->fds[context->fds_count].fd = wsi->sock;
        context->fds[context->fds_count].events = LWS_POLLIN;
@@ -108,10 +110,10 @@ remove_wsi_socket_from_fds(struct libwebsocket_context *context,
         * (still same fd pointing to same wsi)
         */
        /* end guy's "position in fds table" changed */
-       context->lws_lookup[context->fds[context->fds_count].fd]->
-                                               position_in_fds_table = m;
+       wsi_from_fd(context,context->fds[context->fds_count].fd)-> 
+                                       position_in_fds_table = m;
        /* deletion guy's lws_lookup entry needs nuking */
-       context->lws_lookup[wsi->sock] = NULL;
+       delete_from_fd(context,wsi->sock);
        /* removed wsi has no position any more */
        wsi->position_in_fds_table = -1;
 
@@ -282,7 +284,7 @@ libwebsocket_callback_on_writable_all_protocol(
        struct libwebsocket *wsi;
 
        for (n = 0; n < context->fds_count; n++) {
-               wsi = context->lws_lookup[context->fds[n].fd];
+               wsi = wsi_from_fd(context,context->fds[n].fd);
                if (!wsi)
                        continue;
                if (wsi->protocol == protocol)
index 34667b4..5e0a6a3 100755 (executable)
@@ -249,6 +249,12 @@ typedef unsigned __int64 u_int64_t;
 #define MSG_NOSIGNAL SO_NOSIGPIPE
 #endif
 
+#ifdef _WIN32
+#ifndef FD_HASHTABLE_MODULUS
+#define FD_HASHTABLE_MODULUS 32
+#endif
+#endif
+
 #ifndef LWS_MAX_HEADER_LEN
 #define LWS_MAX_HEADER_LEN 1024
 #endif
@@ -412,12 +418,25 @@ struct lws_signal_watcher {
 };
 #endif /* LWS_USE_LIBEV */
 
+#ifdef _WIN32
+#define LWS_FD_HASH(fd) ((fd ^ (fd >> 8) ^ (fd >> 16)) % FD_HASHTABLE_MODULUS)
+struct libwebsocket_fd_hashtable {
+       struct libwebsocket **wsi;
+       int length;
+};
+#endif
+
 struct libwebsocket_context {
 #ifdef _WIN32
        WSAEVENT *events;
 #endif
        struct libwebsocket_pollfd *fds;
-       struct libwebsocket **lws_lookup; /* fd to wsi */
+#ifdef _WIN32
+/* different implementation between unix and windows */
+       struct libwebsocket_fd_hashtable fd_hashtable[FD_HASHTABLE_MODULUS];
+#else
+       struct libwebsocket **lws_lookup;  /* fd to wsi */
+#endif
        int fds_count;
 #ifdef LWS_USE_LIBEV
        struct ev_loop* io_loop;
@@ -808,7 +827,6 @@ struct libwebsocket {
 
        char pending_timeout; /* enum pending_timeout */
        time_t pending_timeout_limit;
-
        int sock;
        int position_in_fds_table;
 #ifdef LWS_LATENCY
@@ -895,9 +913,21 @@ lws_http_action(struct libwebsocket_context *context, struct libwebsocket *wsi);
 LWS_EXTERN int
 lws_b64_selftest(void);
 
+#ifdef _WIN32
 LWS_EXTERN struct libwebsocket *
 wsi_from_fd(struct libwebsocket_context *context, int fd);
 
+LWS_EXTERN int 
+insert_wsi(struct libwebsocket_context *context, struct libwebsocket *wsi);
+
+LWS_EXTERN int
+delete_from_fd(struct libwebsocket_context *context, int fd);
+#else
+#define wsi_from_fd(A,B)  A->lws_lookup[B] 
+#define insert_wsi(A,B)   A->lws_lookup[B->sock]=B
+#define delete_from_fd(A,B) A->lws_lookup[B]=0
+#endif
+
 LWS_EXTERN int
 insert_wsi_socket_into_fds(struct libwebsocket_context *context,
                                                      struct libwebsocket *wsi);
index f905a60..bf968b7 100644 (file)
@@ -348,10 +348,9 @@ libwebsocket_service_fd(struct libwebsocket_context *context,
        struct lws_tokens eff_buf;
 
        if (context->listen_service_fd)
-               listen_socket_fds_index = context->lws_lookup[
-                            context->listen_service_fd]->position_in_fds_table;
+               listen_socket_fds_index = wsi_from_fd(context,context->listen_service_fd)->position_in_fds_table;
 
-       /*
+         /*
         * you can call us with pollfd = NULL to just allow the once-per-second
         * global timeout checks; if less than a second since the last check
         * it returns immediately then.
@@ -372,7 +371,7 @@ libwebsocket_service_fd(struct libwebsocket_context *context,
 
                for (n = 0; n < context->fds_count; n++) {
                        m = context->fds[n].fd;
-                       wsi = context->lws_lookup[m];
+                       wsi = wsi_from_fd(context,m);
                        if (!wsi)
                                continue;
 
@@ -397,7 +396,7 @@ libwebsocket_service_fd(struct libwebsocket_context *context,
                return 0;
 
        /* no, here to service a socket descriptor */
-       wsi = context->lws_lookup[pollfd->fd];
+       wsi = wsi_from_fd(context,pollfd->fd);
        if (wsi == NULL)
                /* not lws connection ... leave revents alone and return */
                return 0;