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;