1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * 6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to 8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the 9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is 11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions: 12d4afb5ceSopenharmony_ci * 13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in 14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software. 15d4afb5ceSopenharmony_ci * 16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22d4afb5ceSopenharmony_ci * IN THE SOFTWARE. 23d4afb5ceSopenharmony_ci */ 24d4afb5ceSopenharmony_ci 25d4afb5ceSopenharmony_ci#include <libwebsockets.h> 26d4afb5ceSopenharmony_ci#include "private-lib-core.h" 27d4afb5ceSopenharmony_ci 28d4afb5ceSopenharmony_ci/* requires context->lock */ 29d4afb5ceSopenharmony_cistatic void 30d4afb5ceSopenharmony_ci__lws_peer_remove_from_peer_wait_list(struct lws_context *context, 31d4afb5ceSopenharmony_ci struct lws_peer *peer) 32d4afb5ceSopenharmony_ci{ 33d4afb5ceSopenharmony_ci struct lws_peer *df; 34d4afb5ceSopenharmony_ci 35d4afb5ceSopenharmony_ci lws_start_foreach_llp(struct lws_peer **, p, context->peer_wait_list) { 36d4afb5ceSopenharmony_ci if (*p == peer) { 37d4afb5ceSopenharmony_ci df = *p; 38d4afb5ceSopenharmony_ci 39d4afb5ceSopenharmony_ci *p = df->peer_wait_list; 40d4afb5ceSopenharmony_ci df->peer_wait_list = NULL; 41d4afb5ceSopenharmony_ci 42d4afb5ceSopenharmony_ci if (!context->peer_wait_list) 43d4afb5ceSopenharmony_ci lws_sul_cancel(&context->pt[0].sul_peer_limits); 44d4afb5ceSopenharmony_ci 45d4afb5ceSopenharmony_ci return; 46d4afb5ceSopenharmony_ci } 47d4afb5ceSopenharmony_ci } lws_end_foreach_llp(p, peer_wait_list); 48d4afb5ceSopenharmony_ci} 49d4afb5ceSopenharmony_ci 50d4afb5ceSopenharmony_civoid 51d4afb5ceSopenharmony_cilws_sul_peer_limits_cb(lws_sorted_usec_list_t *sul) 52d4afb5ceSopenharmony_ci{ 53d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = lws_container_of(sul, 54d4afb5ceSopenharmony_ci struct lws_context_per_thread, sul_peer_limits); 55d4afb5ceSopenharmony_ci 56d4afb5ceSopenharmony_ci lws_peer_cull_peer_wait_list(pt->context); 57d4afb5ceSopenharmony_ci 58d4afb5ceSopenharmony_ci lws_sul_schedule(pt->context, 0, &pt->context->pt[0].sul_peer_limits, 59d4afb5ceSopenharmony_ci lws_sul_peer_limits_cb, 10 * LWS_US_PER_SEC); 60d4afb5ceSopenharmony_ci} 61d4afb5ceSopenharmony_ci 62d4afb5ceSopenharmony_ci/* requires context->lock */ 63d4afb5ceSopenharmony_cistatic void 64d4afb5ceSopenharmony_ci__lws_peer_add_to_peer_wait_list(struct lws_context *context, 65d4afb5ceSopenharmony_ci struct lws_peer *peer) 66d4afb5ceSopenharmony_ci{ 67d4afb5ceSopenharmony_ci __lws_peer_remove_from_peer_wait_list(context, peer); 68d4afb5ceSopenharmony_ci 69d4afb5ceSopenharmony_ci peer->peer_wait_list = context->peer_wait_list; 70d4afb5ceSopenharmony_ci context->peer_wait_list = peer; 71d4afb5ceSopenharmony_ci 72d4afb5ceSopenharmony_ci if (!context->pt[0].sul_peer_limits.list.owner) 73d4afb5ceSopenharmony_ci lws_sul_schedule(context, 0, &context->pt[0].sul_peer_limits, 74d4afb5ceSopenharmony_ci lws_sul_peer_limits_cb, 10 * LWS_US_PER_SEC); 75d4afb5ceSopenharmony_ci} 76d4afb5ceSopenharmony_ci 77d4afb5ceSopenharmony_ci 78d4afb5ceSopenharmony_cistruct lws_peer * 79d4afb5ceSopenharmony_cilws_get_or_create_peer(struct lws_vhost *vhost, lws_sockfd_type sockfd) 80d4afb5ceSopenharmony_ci{ 81d4afb5ceSopenharmony_ci struct lws_context *context = vhost->context; 82d4afb5ceSopenharmony_ci struct lws_peer *peer; 83d4afb5ceSopenharmony_ci lws_sockaddr46 sa46; 84d4afb5ceSopenharmony_ci socklen_t rlen = 0; 85d4afb5ceSopenharmony_ci uint32_t hash = 0; 86d4afb5ceSopenharmony_ci uint8_t *q8; 87d4afb5ceSopenharmony_ci void *q; 88d4afb5ceSopenharmony_ci int n; 89d4afb5ceSopenharmony_ci 90d4afb5ceSopenharmony_ci if (vhost->options & LWS_SERVER_OPTION_UNIX_SOCK) 91d4afb5ceSopenharmony_ci return NULL; 92d4afb5ceSopenharmony_ci 93d4afb5ceSopenharmony_ci rlen = sizeof(sa46); 94d4afb5ceSopenharmony_ci if (getpeername(sockfd, (struct sockaddr*)&sa46, &rlen)) 95d4afb5ceSopenharmony_ci /* eg, udp doesn't have to have a peer */ 96d4afb5ceSopenharmony_ci return NULL; 97d4afb5ceSopenharmony_ci 98d4afb5ceSopenharmony_ci#ifdef LWS_WITH_IPV6 99d4afb5ceSopenharmony_ci if (sa46.sa4.sin_family == AF_INET6) { 100d4afb5ceSopenharmony_ci q = &sa46.sa6.sin6_addr; 101d4afb5ceSopenharmony_ci rlen = sizeof(sa46.sa6.sin6_addr); 102d4afb5ceSopenharmony_ci } else 103d4afb5ceSopenharmony_ci#endif 104d4afb5ceSopenharmony_ci { 105d4afb5ceSopenharmony_ci q = &sa46.sa4.sin_addr; 106d4afb5ceSopenharmony_ci rlen = sizeof(sa46.sa4.sin_addr); 107d4afb5ceSopenharmony_ci } 108d4afb5ceSopenharmony_ci 109d4afb5ceSopenharmony_ci q8 = q; 110d4afb5ceSopenharmony_ci for (n = 0; n < (int)rlen; n++) 111d4afb5ceSopenharmony_ci hash = (uint32_t)((((hash << 4) | (hash >> 28)) * (uint32_t)n) ^ q8[n]); 112d4afb5ceSopenharmony_ci 113d4afb5ceSopenharmony_ci if (!context->pl_hash_elements) 114d4afb5ceSopenharmony_ci return NULL; 115d4afb5ceSopenharmony_ci 116d4afb5ceSopenharmony_ci hash = hash % context->pl_hash_elements; 117d4afb5ceSopenharmony_ci 118d4afb5ceSopenharmony_ci lws_context_lock(context, "peer search"); /* <======================= */ 119d4afb5ceSopenharmony_ci 120d4afb5ceSopenharmony_ci lws_start_foreach_ll(struct lws_peer *, peerx, 121d4afb5ceSopenharmony_ci context->pl_hash_table[hash]) { 122d4afb5ceSopenharmony_ci if (peerx->sa46.sa4.sin_family == sa46.sa4.sin_family) { 123d4afb5ceSopenharmony_ci#if defined(LWS_WITH_IPV6) 124d4afb5ceSopenharmony_ci if (sa46.sa4.sin_family == AF_INET6 && 125d4afb5ceSopenharmony_ci !memcmp(q, &peerx->sa46.sa6.sin6_addr, rlen)) 126d4afb5ceSopenharmony_ci goto hit; 127d4afb5ceSopenharmony_ci#endif 128d4afb5ceSopenharmony_ci if (sa46.sa4.sin_family == AF_INET && 129d4afb5ceSopenharmony_ci !memcmp(q, &peerx->sa46.sa4.sin_addr, rlen)) { 130d4afb5ceSopenharmony_ci#if defined(LWS_WITH_IPV6) 131d4afb5ceSopenharmony_cihit: 132d4afb5ceSopenharmony_ci#endif 133d4afb5ceSopenharmony_ci lws_context_unlock(context); /* === */ 134d4afb5ceSopenharmony_ci 135d4afb5ceSopenharmony_ci return peerx; 136d4afb5ceSopenharmony_ci } 137d4afb5ceSopenharmony_ci } 138d4afb5ceSopenharmony_ci } lws_end_foreach_ll(peerx, next); 139d4afb5ceSopenharmony_ci 140d4afb5ceSopenharmony_ci lwsl_info("%s: creating new peer\n", __func__); 141d4afb5ceSopenharmony_ci 142d4afb5ceSopenharmony_ci peer = lws_zalloc(sizeof(*peer), "peer"); 143d4afb5ceSopenharmony_ci if (!peer) { 144d4afb5ceSopenharmony_ci lws_context_unlock(context); /* === */ 145d4afb5ceSopenharmony_ci lwsl_err("%s: OOM for new peer\n", __func__); 146d4afb5ceSopenharmony_ci return NULL; 147d4afb5ceSopenharmony_ci } 148d4afb5ceSopenharmony_ci 149d4afb5ceSopenharmony_ci context->count_peers++; 150d4afb5ceSopenharmony_ci peer->next = context->pl_hash_table[hash]; 151d4afb5ceSopenharmony_ci peer->hash = hash; 152d4afb5ceSopenharmony_ci peer->sa46 = sa46; 153d4afb5ceSopenharmony_ci context->pl_hash_table[hash] = peer; 154d4afb5ceSopenharmony_ci time(&peer->time_created); 155d4afb5ceSopenharmony_ci /* 156d4afb5ceSopenharmony_ci * On creation, the peer has no wsi attached, so is created on the 157d4afb5ceSopenharmony_ci * wait list. When a wsi is added it is removed from the wait list. 158d4afb5ceSopenharmony_ci */ 159d4afb5ceSopenharmony_ci time(&peer->time_closed_all); 160d4afb5ceSopenharmony_ci __lws_peer_add_to_peer_wait_list(context, peer); 161d4afb5ceSopenharmony_ci 162d4afb5ceSopenharmony_ci lws_context_unlock(context); /* ====================================> */ 163d4afb5ceSopenharmony_ci 164d4afb5ceSopenharmony_ci return peer; 165d4afb5ceSopenharmony_ci} 166d4afb5ceSopenharmony_ci 167d4afb5ceSopenharmony_ci/* requires context->lock */ 168d4afb5ceSopenharmony_cistatic int 169d4afb5ceSopenharmony_ci__lws_peer_destroy(struct lws_context *context, struct lws_peer *peer) 170d4afb5ceSopenharmony_ci{ 171d4afb5ceSopenharmony_ci lws_start_foreach_llp(struct lws_peer **, p, 172d4afb5ceSopenharmony_ci context->pl_hash_table[peer->hash]) { 173d4afb5ceSopenharmony_ci if (*p == peer) { 174d4afb5ceSopenharmony_ci struct lws_peer *df = *p; 175d4afb5ceSopenharmony_ci *p = df->next; 176d4afb5ceSopenharmony_ci lws_free(df); 177d4afb5ceSopenharmony_ci context->count_peers--; 178d4afb5ceSopenharmony_ci 179d4afb5ceSopenharmony_ci return 0; 180d4afb5ceSopenharmony_ci } 181d4afb5ceSopenharmony_ci } lws_end_foreach_llp(p, next); 182d4afb5ceSopenharmony_ci 183d4afb5ceSopenharmony_ci return 1; 184d4afb5ceSopenharmony_ci} 185d4afb5ceSopenharmony_ci 186d4afb5ceSopenharmony_civoid 187d4afb5ceSopenharmony_cilws_peer_cull_peer_wait_list(struct lws_context *context) 188d4afb5ceSopenharmony_ci{ 189d4afb5ceSopenharmony_ci struct lws_peer *df; 190d4afb5ceSopenharmony_ci time_t t; 191d4afb5ceSopenharmony_ci 192d4afb5ceSopenharmony_ci time(&t); 193d4afb5ceSopenharmony_ci 194d4afb5ceSopenharmony_ci if (context->next_cull && t < context->next_cull) 195d4afb5ceSopenharmony_ci return; 196d4afb5ceSopenharmony_ci 197d4afb5ceSopenharmony_ci lws_context_lock(context, "peer cull"); /* <========================= */ 198d4afb5ceSopenharmony_ci 199d4afb5ceSopenharmony_ci context->next_cull = t + 5; 200d4afb5ceSopenharmony_ci 201d4afb5ceSopenharmony_ci lws_start_foreach_llp(struct lws_peer **, p, context->peer_wait_list) { 202d4afb5ceSopenharmony_ci if (t - (*p)->time_closed_all > 10) { 203d4afb5ceSopenharmony_ci df = *p; 204d4afb5ceSopenharmony_ci 205d4afb5ceSopenharmony_ci /* remove us from the peer wait list */ 206d4afb5ceSopenharmony_ci *p = df->peer_wait_list; 207d4afb5ceSopenharmony_ci df->peer_wait_list = NULL; 208d4afb5ceSopenharmony_ci 209d4afb5ceSopenharmony_ci __lws_peer_destroy(context, df); 210d4afb5ceSopenharmony_ci continue; /* we already point to next, if any */ 211d4afb5ceSopenharmony_ci } 212d4afb5ceSopenharmony_ci } lws_end_foreach_llp(p, peer_wait_list); 213d4afb5ceSopenharmony_ci 214d4afb5ceSopenharmony_ci lws_context_unlock(context); /* ====================================> */ 215d4afb5ceSopenharmony_ci} 216d4afb5ceSopenharmony_ci 217d4afb5ceSopenharmony_civoid 218d4afb5ceSopenharmony_cilws_peer_add_wsi(struct lws_context *context, struct lws_peer *peer, 219d4afb5ceSopenharmony_ci struct lws *wsi) 220d4afb5ceSopenharmony_ci{ 221d4afb5ceSopenharmony_ci if (!peer) 222d4afb5ceSopenharmony_ci return; 223d4afb5ceSopenharmony_ci 224d4afb5ceSopenharmony_ci lws_context_lock(context, "peer add"); /* <========================== */ 225d4afb5ceSopenharmony_ci 226d4afb5ceSopenharmony_ci peer->count_wsi++; 227d4afb5ceSopenharmony_ci wsi->peer = peer; 228d4afb5ceSopenharmony_ci __lws_peer_remove_from_peer_wait_list(context, peer); 229d4afb5ceSopenharmony_ci 230d4afb5ceSopenharmony_ci lws_context_unlock(context); /* ====================================> */ 231d4afb5ceSopenharmony_ci} 232d4afb5ceSopenharmony_ci 233d4afb5ceSopenharmony_civoid 234d4afb5ceSopenharmony_cilws_peer_dump_from_wsi(struct lws *wsi) 235d4afb5ceSopenharmony_ci{ 236d4afb5ceSopenharmony_ci struct lws_peer *peer; 237d4afb5ceSopenharmony_ci 238d4afb5ceSopenharmony_ci if (!wsi || !wsi->peer) 239d4afb5ceSopenharmony_ci return; 240d4afb5ceSopenharmony_ci 241d4afb5ceSopenharmony_ci peer = wsi->peer; 242d4afb5ceSopenharmony_ci 243d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) 244d4afb5ceSopenharmony_ci lwsl_notice("%s: %s: created %llu: wsi: %d/%d, ah %d/%d\n", 245d4afb5ceSopenharmony_ci __func__, lws_wsi_tag(wsi), 246d4afb5ceSopenharmony_ci (unsigned long long)peer->time_created, 247d4afb5ceSopenharmony_ci peer->count_wsi, peer->total_wsi, 248d4afb5ceSopenharmony_ci peer->http.count_ah, peer->http.total_ah); 249d4afb5ceSopenharmony_ci#else 250d4afb5ceSopenharmony_ci lwsl_notice("%s: %s: created %llu: wsi: %d/%d\n", __func__, 251d4afb5ceSopenharmony_ci lws_wsi_tag(wsi), 252d4afb5ceSopenharmony_ci (unsigned long long)peer->time_created, 253d4afb5ceSopenharmony_ci peer->count_wsi, peer->total_wsi); 254d4afb5ceSopenharmony_ci#endif 255d4afb5ceSopenharmony_ci} 256d4afb5ceSopenharmony_ci 257d4afb5ceSopenharmony_civoid 258d4afb5ceSopenharmony_cilws_peer_track_wsi_close(struct lws_context *context, struct lws_peer *peer) 259d4afb5ceSopenharmony_ci{ 260d4afb5ceSopenharmony_ci if (!peer) 261d4afb5ceSopenharmony_ci return; 262d4afb5ceSopenharmony_ci 263d4afb5ceSopenharmony_ci lws_context_lock(context, "peer wsi close"); /* <==================== */ 264d4afb5ceSopenharmony_ci 265d4afb5ceSopenharmony_ci assert(peer->count_wsi); 266d4afb5ceSopenharmony_ci peer->count_wsi--; 267d4afb5ceSopenharmony_ci 268d4afb5ceSopenharmony_ci if (!peer->count_wsi 269d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) 270d4afb5ceSopenharmony_ci && !peer->http.count_ah 271d4afb5ceSopenharmony_ci#endif 272d4afb5ceSopenharmony_ci ) { 273d4afb5ceSopenharmony_ci /* 274d4afb5ceSopenharmony_ci * in order that we can accumulate peer activity correctly 275d4afb5ceSopenharmony_ci * allowing for periods when the peer has no connections, 276d4afb5ceSopenharmony_ci * we don't synchronously destroy the peer when his last 277d4afb5ceSopenharmony_ci * wsi closes. Instead we mark the time his last wsi 278d4afb5ceSopenharmony_ci * closed and add him to a peer_wait_list to be reaped 279d4afb5ceSopenharmony_ci * later if no further activity is coming. 280d4afb5ceSopenharmony_ci */ 281d4afb5ceSopenharmony_ci time(&peer->time_closed_all); 282d4afb5ceSopenharmony_ci __lws_peer_add_to_peer_wait_list(context, peer); 283d4afb5ceSopenharmony_ci } 284d4afb5ceSopenharmony_ci 285d4afb5ceSopenharmony_ci lws_context_unlock(context); /* ====================================> */ 286d4afb5ceSopenharmony_ci} 287d4afb5ceSopenharmony_ci 288d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) 289d4afb5ceSopenharmony_ciint 290d4afb5ceSopenharmony_cilws_peer_confirm_ah_attach_ok(struct lws_context *context, 291d4afb5ceSopenharmony_ci struct lws_peer *peer) 292d4afb5ceSopenharmony_ci{ 293d4afb5ceSopenharmony_ci if (!peer) 294d4afb5ceSopenharmony_ci return 0; 295d4afb5ceSopenharmony_ci 296d4afb5ceSopenharmony_ci if (context->ip_limit_ah && 297d4afb5ceSopenharmony_ci peer->http.count_ah >= context->ip_limit_ah) { 298d4afb5ceSopenharmony_ci lwsl_info("peer reached ah limit %d, deferring\n", 299d4afb5ceSopenharmony_ci context->ip_limit_ah); 300d4afb5ceSopenharmony_ci 301d4afb5ceSopenharmony_ci return 1; 302d4afb5ceSopenharmony_ci } 303d4afb5ceSopenharmony_ci 304d4afb5ceSopenharmony_ci return 0; 305d4afb5ceSopenharmony_ci} 306d4afb5ceSopenharmony_ci 307d4afb5ceSopenharmony_civoid 308d4afb5ceSopenharmony_cilws_peer_track_ah_detach(struct lws_context *context, struct lws_peer *peer) 309d4afb5ceSopenharmony_ci{ 310d4afb5ceSopenharmony_ci if (!peer) 311d4afb5ceSopenharmony_ci return; 312d4afb5ceSopenharmony_ci 313d4afb5ceSopenharmony_ci lws_context_lock(context, "peer ah detach"); /* <==================== */ 314d4afb5ceSopenharmony_ci assert(peer->http.count_ah); 315d4afb5ceSopenharmony_ci peer->http.count_ah--; 316d4afb5ceSopenharmony_ci lws_context_unlock(context); /* ====================================> */ 317d4afb5ceSopenharmony_ci} 318d4afb5ceSopenharmony_ci#endif 319