From 229bfec9486d239fe82487a50c7e0ae1e6c5a0f1 Mon Sep 17 00:00:00 2001 From: Bud Davis Date: Fri, 30 Jan 2015 10:13:01 +0800 Subject: [PATCH] win32 use hashtable for fd management 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 --- lib/context.c | 17 +++++++++-- lib/libwebsockets.c | 5 ++-- lib/lws-plat-win.c | 57 +++++++++++++++++++++++++++++++++++-- lib/pollfd.c | 12 ++++---- lib/private-libwebsockets.h | 34 ++++++++++++++++++++-- lib/service.c | 9 +++--- 6 files changed, 114 insertions(+), 20 deletions(-) diff --git a/lib/context.c b/lib/context.c index 2ea9c60d..fa62f837 100644 --- a/lib/context.c +++ b/lib/context.c @@ -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); diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index 1d8af8d6..d32269ff 100644 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -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) diff --git a/lib/lws-plat-win.c b/lib/lws-plat-win.c index 2503fc00..63e3bcb1 100644 --- a/lib/lws-plat-win.c +++ b/lib/lws-plat-win.c @@ -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); } diff --git a/lib/pollfd.c b/lib/pollfd.c index b09127e0..19905eff 100644 --- a/lib/pollfd.c +++ b/lib/pollfd.c @@ -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) diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 34667b4f..5e0a6a32 100755 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -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); diff --git a/lib/service.c b/lib/service.c index f905a605..bf968b77 100644 --- a/lib/service.c +++ b/lib/service.c @@ -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;