Update Files
This commit is contained in:
318
Kinc/Sources/kinc/libs/misc/peer-limits.c
Normal file
318
Kinc/Sources/kinc/libs/misc/peer-limits.c
Normal file
@ -0,0 +1,318 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <libwebsockets.h>
|
||||
#include "private-lib-core.h"
|
||||
|
||||
/* requires context->lock */
|
||||
static void
|
||||
__lws_peer_remove_from_peer_wait_list(struct lws_context *context,
|
||||
struct lws_peer *peer)
|
||||
{
|
||||
struct lws_peer *df;
|
||||
|
||||
lws_start_foreach_llp(struct lws_peer **, p, context->peer_wait_list) {
|
||||
if (*p == peer) {
|
||||
df = *p;
|
||||
|
||||
*p = df->peer_wait_list;
|
||||
df->peer_wait_list = NULL;
|
||||
|
||||
if (!context->peer_wait_list)
|
||||
lws_sul_cancel(&context->pt[0].sul_peer_limits);
|
||||
|
||||
return;
|
||||
}
|
||||
} lws_end_foreach_llp(p, peer_wait_list);
|
||||
}
|
||||
|
||||
void
|
||||
lws_sul_peer_limits_cb(lws_sorted_usec_list_t *sul)
|
||||
{
|
||||
struct lws_context_per_thread *pt = lws_container_of(sul,
|
||||
struct lws_context_per_thread, sul_peer_limits);
|
||||
|
||||
lws_peer_cull_peer_wait_list(pt->context);
|
||||
|
||||
lws_sul_schedule(pt->context, 0, &pt->context->pt[0].sul_peer_limits,
|
||||
lws_sul_peer_limits_cb, 10 * LWS_US_PER_SEC);
|
||||
}
|
||||
|
||||
/* requires context->lock */
|
||||
static void
|
||||
__lws_peer_add_to_peer_wait_list(struct lws_context *context,
|
||||
struct lws_peer *peer)
|
||||
{
|
||||
__lws_peer_remove_from_peer_wait_list(context, peer);
|
||||
|
||||
peer->peer_wait_list = context->peer_wait_list;
|
||||
context->peer_wait_list = peer;
|
||||
|
||||
if (!context->pt[0].sul_peer_limits.list.owner)
|
||||
lws_sul_schedule(context, 0, &context->pt[0].sul_peer_limits,
|
||||
lws_sul_peer_limits_cb, 10 * LWS_US_PER_SEC);
|
||||
}
|
||||
|
||||
|
||||
struct lws_peer *
|
||||
lws_get_or_create_peer(struct lws_vhost *vhost, lws_sockfd_type sockfd)
|
||||
{
|
||||
struct lws_context *context = vhost->context;
|
||||
struct lws_peer *peer;
|
||||
lws_sockaddr46 sa46;
|
||||
socklen_t rlen = 0;
|
||||
uint32_t hash = 0;
|
||||
uint8_t *q8;
|
||||
void *q;
|
||||
int n;
|
||||
|
||||
if (vhost->options & LWS_SERVER_OPTION_UNIX_SOCK)
|
||||
return NULL;
|
||||
|
||||
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 (sa46.sa4.sin_family == AF_INET6) {
|
||||
q = &sa46.sa6.sin6_addr;
|
||||
rlen = sizeof(sa46.sa6.sin6_addr);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
q = &sa46.sa4.sin_addr;
|
||||
rlen = sizeof(sa46.sa4.sin_addr);
|
||||
}
|
||||
|
||||
q8 = q;
|
||||
for (n = 0; n < (int)rlen; n++)
|
||||
hash = (uint32_t)((((hash << 4) | (hash >> 28)) * (uint32_t)n) ^ q8[n]);
|
||||
|
||||
if (!context->pl_hash_elements)
|
||||
return NULL;
|
||||
|
||||
hash = hash % context->pl_hash_elements;
|
||||
|
||||
lws_context_lock(context, "peer search"); /* <======================= */
|
||||
|
||||
lws_start_foreach_ll(struct lws_peer *, peerx,
|
||||
context->pl_hash_table[hash]) {
|
||||
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);
|
||||
|
||||
lwsl_info("%s: creating new peer\n", __func__);
|
||||
|
||||
peer = lws_zalloc(sizeof(*peer), "peer");
|
||||
if (!peer) {
|
||||
lws_context_unlock(context); /* === */
|
||||
lwsl_err("%s: OOM for new peer\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
context->count_peers++;
|
||||
peer->next = context->pl_hash_table[hash];
|
||||
peer->hash = hash;
|
||||
peer->sa46 = sa46;
|
||||
context->pl_hash_table[hash] = peer;
|
||||
time(&peer->time_created);
|
||||
/*
|
||||
* On creation, the peer has no wsi attached, so is created on the
|
||||
* wait list. When a wsi is added it is removed from the wait list.
|
||||
*/
|
||||
time(&peer->time_closed_all);
|
||||
__lws_peer_add_to_peer_wait_list(context, peer);
|
||||
|
||||
lws_context_unlock(context); /* ====================================> */
|
||||
|
||||
return peer;
|
||||
}
|
||||
|
||||
/* requires context->lock */
|
||||
static int
|
||||
__lws_peer_destroy(struct lws_context *context, struct lws_peer *peer)
|
||||
{
|
||||
lws_start_foreach_llp(struct lws_peer **, p,
|
||||
context->pl_hash_table[peer->hash]) {
|
||||
if (*p == peer) {
|
||||
struct lws_peer *df = *p;
|
||||
*p = df->next;
|
||||
lws_free(df);
|
||||
context->count_peers--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
} lws_end_foreach_llp(p, next);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
lws_peer_cull_peer_wait_list(struct lws_context *context)
|
||||
{
|
||||
struct lws_peer *df;
|
||||
time_t t;
|
||||
|
||||
time(&t);
|
||||
|
||||
if (context->next_cull && t < context->next_cull)
|
||||
return;
|
||||
|
||||
lws_context_lock(context, "peer cull"); /* <========================= */
|
||||
|
||||
context->next_cull = t + 5;
|
||||
|
||||
lws_start_foreach_llp(struct lws_peer **, p, context->peer_wait_list) {
|
||||
if (t - (*p)->time_closed_all > 10) {
|
||||
df = *p;
|
||||
|
||||
/* remove us from the peer wait list */
|
||||
*p = df->peer_wait_list;
|
||||
df->peer_wait_list = NULL;
|
||||
|
||||
__lws_peer_destroy(context, df);
|
||||
continue; /* we already point to next, if any */
|
||||
}
|
||||
} lws_end_foreach_llp(p, peer_wait_list);
|
||||
|
||||
lws_context_unlock(context); /* ====================================> */
|
||||
}
|
||||
|
||||
void
|
||||
lws_peer_add_wsi(struct lws_context *context, struct lws_peer *peer,
|
||||
struct lws *wsi)
|
||||
{
|
||||
if (!peer)
|
||||
return;
|
||||
|
||||
lws_context_lock(context, "peer add"); /* <========================== */
|
||||
|
||||
peer->count_wsi++;
|
||||
wsi->peer = peer;
|
||||
__lws_peer_remove_from_peer_wait_list(context, peer);
|
||||
|
||||
lws_context_unlock(context); /* ====================================> */
|
||||
}
|
||||
|
||||
void
|
||||
lws_peer_dump_from_wsi(struct lws *wsi)
|
||||
{
|
||||
struct lws_peer *peer;
|
||||
|
||||
if (!wsi || !wsi->peer)
|
||||
return;
|
||||
|
||||
peer = wsi->peer;
|
||||
|
||||
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
||||
lwsl_notice("%s: %s: created %llu: wsi: %d/%d, ah %d/%d\n",
|
||||
__func__, lws_wsi_tag(wsi),
|
||||
(unsigned long long)peer->time_created,
|
||||
peer->count_wsi, peer->total_wsi,
|
||||
peer->http.count_ah, peer->http.total_ah);
|
||||
#else
|
||||
lwsl_notice("%s: %s: created %llu: wsi: %d/%d\n", __func__,
|
||||
lws_wsi_tag(wsi),
|
||||
(unsigned long long)peer->time_created,
|
||||
peer->count_wsi, peer->total_wsi);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
lws_peer_track_wsi_close(struct lws_context *context, struct lws_peer *peer)
|
||||
{
|
||||
if (!peer)
|
||||
return;
|
||||
|
||||
lws_context_lock(context, "peer wsi close"); /* <==================== */
|
||||
|
||||
assert(peer->count_wsi);
|
||||
peer->count_wsi--;
|
||||
|
||||
if (!peer->count_wsi
|
||||
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
||||
&& !peer->http.count_ah
|
||||
#endif
|
||||
) {
|
||||
/*
|
||||
* in order that we can accumulate peer activity correctly
|
||||
* allowing for periods when the peer has no connections,
|
||||
* we don't synchronously destroy the peer when his last
|
||||
* wsi closes. Instead we mark the time his last wsi
|
||||
* closed and add him to a peer_wait_list to be reaped
|
||||
* later if no further activity is coming.
|
||||
*/
|
||||
time(&peer->time_closed_all);
|
||||
__lws_peer_add_to_peer_wait_list(context, peer);
|
||||
}
|
||||
|
||||
lws_context_unlock(context); /* ====================================> */
|
||||
}
|
||||
|
||||
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
||||
int
|
||||
lws_peer_confirm_ah_attach_ok(struct lws_context *context,
|
||||
struct lws_peer *peer)
|
||||
{
|
||||
if (!peer)
|
||||
return 0;
|
||||
|
||||
if (context->ip_limit_ah &&
|
||||
peer->http.count_ah >= context->ip_limit_ah) {
|
||||
lwsl_info("peer reached ah limit %d, deferring\n",
|
||||
context->ip_limit_ah);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_peer_track_ah_detach(struct lws_context *context, struct lws_peer *peer)
|
||||
{
|
||||
if (!peer)
|
||||
return;
|
||||
|
||||
lws_context_lock(context, "peer ah detach"); /* <==================== */
|
||||
assert(peer->http.count_ah);
|
||||
peer->http.count_ah--;
|
||||
lws_context_unlock(context); /* ====================================> */
|
||||
}
|
||||
#endif
|
Reference in New Issue
Block a user