diff --git a/include/libwebsockets/lws-context-vhost.h b/include/libwebsockets/lws-context-vhost.h index e0b71bf4e..09c2b126c 100644 --- a/include/libwebsockets/lws-context-vhost.h +++ b/include/libwebsockets/lws-context-vhost.h @@ -237,6 +237,10 @@ struct lws_ss_plugin; typedef int (*lws_context_ready_cb_t)(struct lws_context *context); +typedef int (*lws_peer_limits_notify_t)(struct lws_context *ctx, + lws_sockfd_type sockfd, + lws_sockaddr46 *sa46); + /** struct lws_context_creation_info - parameters to create context and /or vhost with * * This is also used to create vhosts.... if LWS_SERVER_OPTION_EXPLICIT_VHOSTS @@ -738,6 +742,15 @@ struct lws_context_creation_info { /**< 0 = inherit the initial ulimit for files / sockets from the startup * environment. Nonzero = try to set the limit for this process. */ +#if defined(LWS_WITH_PEER_LIMITS) + lws_peer_limits_notify_t pl_notify_cb; + /**< CONTEXT: NULL, or a callback to receive notifications each time a + * connection is being dropped because of peer limits. + * + * The callback provides the context, and an lws_sockaddr46 with the + * peer address and port. + */ +#endif /* Add new things just above here ---^ * This is part of the ABI, don't needlessly break compatibility diff --git a/lib/core-net/adopt.c b/lib/core-net/adopt.c index 0c6a69df8..5d95f63cf 100644 --- a/lib/core-net/adopt.c +++ b/lib/core-net/adopt.c @@ -338,11 +338,16 @@ lws_adopt_descriptor_vhost_via_info(const lws_adopt_desc_t *info) if (peer && info->vh->context->ip_limit_wsi && peer->count_wsi >= info->vh->context->ip_limit_wsi) { - lwsl_notice("Peer reached wsi limit %d\n", + lwsl_info("Peer reached wsi limit %d\n", info->vh->context->ip_limit_wsi); lws_stats_bump(&info->vh->context->pt[0], LWSSTATS_C_PEER_LIMIT_WSI_DENIED, 1); + if (info->vh->context->pl_notify_cb) + info->vh->context->pl_notify_cb( + info->vh->context, + info->fd.sockfd, + &peer->sa46); compatible_close(info->fd.sockfd); return NULL; } diff --git a/lib/core-net/private-lib-core-net.h b/lib/core-net/private-lib-core-net.h index 57c0c605a..cb04c32ad 100644 --- a/lib/core-net/private-lib-core-net.h +++ b/lib/core-net/private-lib-core-net.h @@ -187,10 +187,11 @@ struct lws_peer { struct lws_peer *next; struct lws_peer *peer_wait_list; + lws_sockaddr46 sa46; + time_t time_created; time_t time_closed_all; - uint8_t addr[32]; uint32_t hash; uint32_t count_wsi; uint32_t total_wsi; @@ -198,8 +199,6 @@ struct lws_peer { #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) struct lws_peer_role_http http; #endif - - uint8_t af; }; #endif diff --git a/lib/core/context.c b/lib/core/context.c index b3cc7f8e4..6358f88f2 100644 --- a/lib/core/context.c +++ b/lib/core/context.c @@ -661,6 +661,7 @@ lws_create_context(const struct lws_context_creation_info *info) context->ip_limit_ah = info->ip_limit_ah; context->ip_limit_wsi = info->ip_limit_wsi; + context->pl_notify_cb = info->pl_notify_cb; #endif lwsl_info(" mem: context: %5lu B (%ld ctx + (%ld thr x %d))\n", diff --git a/lib/core/private-lib-core.h b/lib/core/private-lib-core.h index 9a11eccaa..feb54351d 100644 --- a/lib/core/private-lib-core.h +++ b/lib/core/private-lib-core.h @@ -432,9 +432,10 @@ struct lws_context { #endif #if defined(LWS_WITH_PEER_LIMITS) - struct lws_peer **pl_hash_table; - struct lws_peer *peer_wait_list; - time_t next_cull; + struct lws_peer **pl_hash_table; + struct lws_peer *peer_wait_list; + lws_peer_limits_notify_t pl_notify_cb; + time_t next_cull; #endif const lws_system_ops_t *system_ops; diff --git a/lib/misc/peer-limits.c b/lib/misc/peer-limits.c index 796e6c9ed..d2e38176b 100644 --- a/lib/misc/peer-limits.c +++ b/lib/misc/peer-limits.c @@ -1,7 +1,7 @@ /* * libwebsockets - small server side websockets and web server implementation * - * Copyright (C) 2010 - 2019 Andy Green + * Copyright (C) 2010 - 2020 Andy Green * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -60,42 +60,32 @@ struct lws_peer * lws_get_or_create_peer(struct lws_vhost *vhost, lws_sockfd_type sockfd) { struct lws_context *context = vhost->context; - socklen_t rlen = 0; - void *q; - uint8_t *q8; struct lws_peer *peer; + lws_sockaddr46 sa46; + socklen_t rlen = 0; uint32_t hash = 0; - int n, af = AF_INET; - struct sockaddr_storage addr; + uint8_t *q8; + void *q; + int n; if (vhost->options & LWS_SERVER_OPTION_UNIX_SOCK) return NULL; -#ifdef LWS_WITH_IPV6 - if (LWS_IPV6_ENABLED(vhost)) { - af = AF_INET6; - } -#endif - rlen = sizeof(addr); - if (getpeername(sockfd, (struct sockaddr*)&addr, &rlen)) + rlen = sizeof(sa46); + if (getpeername(sockfd, (struct sockaddr*)&sa46, &rlen)) /* eg, udp doesn't have to have a peer */ return NULL; #ifdef LWS_WITH_IPV6 - if (af == AF_INET) + if (sa46.sa4.sin_family == AF_INET6) { + q = &sa46.sa6.sin6_addr; + rlen = sizeof(sa46.sa6.sin6_addr); + } else #endif { - struct sockaddr_in *s = (struct sockaddr_in *)&addr; - q = &s->sin_addr; - rlen = sizeof(s->sin_addr); + q = &sa46.sa4.sin_addr; + rlen = sizeof(sa46.sa4.sin_addr); } -#ifdef LWS_WITH_IPV6 - else { - struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr; - q = &s->sin6_addr; - rlen = sizeof(s->sin6_addr); - } -#endif q8 = q; for (n = 0; n < (int)rlen; n++) @@ -107,9 +97,21 @@ lws_get_or_create_peer(struct lws_vhost *vhost, lws_sockfd_type sockfd) lws_start_foreach_ll(struct lws_peer *, peerx, context->pl_hash_table[hash]) { - if (peerx->af == af && !memcmp(q, peerx->addr, rlen)) { - lws_context_unlock(context); /* === */ - return peerx; + if (peerx->sa46.sa4.sin_family == sa46.sa4.sin_family) { +#if defined(LWS_WITH_IPV6) + if (sa46.sa4.sin_family == AF_INET6 && + !memcmp(q, &peerx->sa46.sa6.sin6_addr, rlen)) + goto hit; +#endif + if (sa46.sa4.sin_family == AF_INET && + !memcmp(q, &peerx->sa46.sa4.sin_addr, rlen)) { +#if defined(LWS_WITH_IPV6) +hit: +#endif + lws_context_unlock(context); /* === */ + + return peerx; + } } } lws_end_foreach_ll(peerx, next); @@ -125,9 +127,8 @@ lws_get_or_create_peer(struct lws_vhost *vhost, lws_sockfd_type sockfd) context->count_peers++; peer->next = context->pl_hash_table[hash]; peer->hash = hash; - peer->af = af; + peer->sa46 = sa46; context->pl_hash_table[hash] = peer; - memcpy(peer->addr, q, rlen); time(&peer->time_created); /* * On creation, the peer has no wsi attached, so is created on the