From be1c7e50e1e8809ea56f2c9d472eccd8ffd73a97 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 04:57:58 +0200 Subject: Adding upstream version 1.44.3. Signed-off-by: Daniel Baumann --- web/server/h2o/libh2o/lib/common/hostinfo.c | 229 ++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 web/server/h2o/libh2o/lib/common/hostinfo.c (limited to 'web/server/h2o/libh2o/lib/common/hostinfo.c') diff --git a/web/server/h2o/libh2o/lib/common/hostinfo.c b/web/server/h2o/libh2o/lib/common/hostinfo.c new file mode 100644 index 00000000..7b481e29 --- /dev/null +++ b/web/server/h2o/libh2o/lib/common/hostinfo.c @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2015 DeNA Co., Ltd., Kazuho Oku + * + * 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 "h2o/hostinfo.h" + +struct st_h2o_hostinfo_getaddr_req_t { + h2o_multithread_receiver_t *_receiver; + h2o_hostinfo_getaddr_cb _cb; + void *cbdata; + h2o_linklist_t _pending; + union { + struct { + char *name; + char *serv; + struct addrinfo hints; + } _in; + struct { + h2o_multithread_message_t message; + const char *errstr; + struct addrinfo *ai; + } _out; + }; +}; + +static struct { + pthread_mutex_t mutex; + pthread_cond_t cond; + h2o_linklist_t pending; /* anchor of h2o_hostinfo_getaddr_req_t::_pending */ + size_t num_threads; + size_t num_threads_idle; +} queue = {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, {&queue.pending, &queue.pending}, 0, 0}; + +size_t h2o_hostinfo_max_threads = 1; + +static void lookup_and_respond(h2o_hostinfo_getaddr_req_t *req) +{ + struct addrinfo *res; + + int ret = getaddrinfo(req->_in.name, req->_in.serv, &req->_in.hints, &res); + req->_out.message = (h2o_multithread_message_t){{NULL}}; + if (ret != 0) { + req->_out.errstr = gai_strerror(ret); + req->_out.ai = NULL; + } else { + req->_out.errstr = NULL; + req->_out.ai = res; + } + + h2o_multithread_send_message(req->_receiver, &req->_out.message); +} + +static void *lookup_thread_main(void *_unused) +{ + pthread_mutex_lock(&queue.mutex); + + while (1) { + --queue.num_threads_idle; + while (!h2o_linklist_is_empty(&queue.pending)) { + h2o_hostinfo_getaddr_req_t *req = H2O_STRUCT_FROM_MEMBER(h2o_hostinfo_getaddr_req_t, _pending, queue.pending.next); + h2o_linklist_unlink(&req->_pending); + pthread_mutex_unlock(&queue.mutex); + lookup_and_respond(req); + pthread_mutex_lock(&queue.mutex); + } + ++queue.num_threads_idle; + pthread_cond_wait(&queue.cond, &queue.mutex); + } + + h2o_fatal("unreachable"); + return NULL; +} + +static void create_lookup_thread(void) +{ + pthread_t tid; + pthread_attr_t attr; + int ret; + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, 1); + pthread_attr_setstacksize(&attr, 100 * 1024); + if ((ret = pthread_create(&tid, NULL, lookup_thread_main, NULL)) != 0) { + if (queue.num_threads == 0) { + fprintf(stderr, "failed to start first thread for getaddrinfo:%s\n", strerror(ret)); + abort(); + } else { + perror("pthread_create(for getaddrinfo)"); + } + return; + } + + ++queue.num_threads; + ++queue.num_threads_idle; +} + +h2o_hostinfo_getaddr_req_t *h2o_hostinfo_getaddr(h2o_multithread_receiver_t *receiver, h2o_iovec_t name, h2o_iovec_t serv, + int family, int socktype, int protocol, int flags, h2o_hostinfo_getaddr_cb cb, + void *cbdata) +{ + h2o_hostinfo_getaddr_req_t *req = h2o_mem_alloc(sizeof(*req) + name.len + 1 + serv.len + 1); + req->_receiver = receiver; + req->_cb = cb; + req->cbdata = cbdata; + req->_pending = (h2o_linklist_t){NULL}; + req->_in.name = (char *)req + sizeof(*req); + memcpy(req->_in.name, name.base, name.len); + req->_in.name[name.len] = '\0'; + req->_in.serv = req->_in.name + name.len + 1; + memcpy(req->_in.serv, serv.base, serv.len); + req->_in.serv[serv.len] = '\0'; + memset(&req->_in.hints, 0, sizeof(req->_in.hints)); + req->_in.hints.ai_family = family; + req->_in.hints.ai_socktype = socktype; + req->_in.hints.ai_protocol = protocol; + req->_in.hints.ai_flags = flags; + + h2o__hostinfo_getaddr_dispatch(req); + + return req; +} + +void h2o__hostinfo_getaddr_dispatch(h2o_hostinfo_getaddr_req_t *req) +{ + pthread_mutex_lock(&queue.mutex); + + h2o_linklist_insert(&queue.pending, &req->_pending); + + if (queue.num_threads_idle == 0 && queue.num_threads < h2o_hostinfo_max_threads) + create_lookup_thread(); + + pthread_cond_signal(&queue.cond); + pthread_mutex_unlock(&queue.mutex); +} + +void h2o_hostinfo_getaddr_cancel(h2o_hostinfo_getaddr_req_t *req) +{ + int should_free = 0; + + pthread_mutex_lock(&queue.mutex); + + if (h2o_linklist_is_linked(&req->_pending)) { + h2o_linklist_unlink(&req->_pending); + should_free = 1; + } else { + req->_cb = NULL; + } + + pthread_mutex_unlock(&queue.mutex); + + if (should_free) + free(req); +} + +void h2o_hostinfo_getaddr_receiver(h2o_multithread_receiver_t *receiver, h2o_linklist_t *messages) +{ + while (!h2o_linklist_is_empty(messages)) { + h2o_hostinfo_getaddr_req_t *req = H2O_STRUCT_FROM_MEMBER(h2o_hostinfo_getaddr_req_t, _out.message.link, messages->next); + h2o_linklist_unlink(&req->_out.message.link); + h2o_hostinfo_getaddr_cb cb = req->_cb; + if (cb != NULL) { + req->_cb = NULL; + cb(req, req->_out.errstr, req->_out.ai, req->cbdata); + } + if (req->_out.ai != NULL) + freeaddrinfo(req->_out.ai); + free(req); + } +} + +static const char *fetch_aton_digit(const char *p, const char *end, unsigned char *value) +{ + size_t ndigits = 0; + int v = 0; + + while (p != end && ('0' <= *p && *p <= '9')) { + v = v * 10 + *p++ - '0'; + ++ndigits; + } + if (!(1 <= ndigits && ndigits <= 3)) + return NULL; + if (v > 255) + return NULL; + *value = (unsigned char)v; + return p; +} + +int h2o_hostinfo_aton(h2o_iovec_t host, struct in_addr *addr) +{ + union { + int32_t n; + unsigned char c[4]; + } value; + const char *p = host.base, *end = p + host.len; + size_t ndots = 0; + + while (1) { + if ((p = fetch_aton_digit(p, end, value.c + ndots)) == NULL) + return -1; + if (ndots == 3) + break; + if (p == end || !(*p == '.')) + return -1; + ++p; + ++ndots; + } + if (p != end) + return -1; + + addr->s_addr = value.n; + return 0; +} -- cgit v1.2.3