summaryrefslogtreecommitdiffstats
path: root/web/server/h2o/libh2o/lib/common
diff options
context:
space:
mode:
Diffstat (limited to 'web/server/h2o/libh2o/lib/common')
-rw-r--r--web/server/h2o/libh2o/lib/common/cache.c273
-rw-r--r--web/server/h2o/libh2o/lib/common/file.c68
-rw-r--r--web/server/h2o/libh2o/lib/common/filecache.c170
-rw-r--r--web/server/h2o/libh2o/lib/common/hostinfo.c229
-rw-r--r--web/server/h2o/libh2o/lib/common/http1client.c582
-rw-r--r--web/server/h2o/libh2o/lib/common/memcached.c429
-rw-r--r--web/server/h2o/libh2o/lib/common/memory.c400
-rw-r--r--web/server/h2o/libh2o/lib/common/multithread.c274
-rw-r--r--web/server/h2o/libh2o/lib/common/serverutil.c317
-rw-r--r--web/server/h2o/libh2o/lib/common/socket.c1433
-rw-r--r--web/server/h2o/libh2o/lib/common/socket/evloop.c.h624
-rw-r--r--web/server/h2o/libh2o/lib/common/socket/evloop/epoll.c.h203
-rw-r--r--web/server/h2o/libh2o/lib/common/socket/evloop/kqueue.c.h186
-rw-r--r--web/server/h2o/libh2o/lib/common/socket/evloop/poll.c.h178
-rw-r--r--web/server/h2o/libh2o/lib/common/socket/uv-binding.c.h283
-rw-r--r--web/server/h2o/libh2o/lib/common/socketpool.c342
-rw-r--r--web/server/h2o/libh2o/lib/common/string.c594
-rw-r--r--web/server/h2o/libh2o/lib/common/time.c175
-rw-r--r--web/server/h2o/libh2o/lib/common/timeout.c90
-rw-r--r--web/server/h2o/libh2o/lib/common/url.c409
20 files changed, 0 insertions, 7259 deletions
diff --git a/web/server/h2o/libh2o/lib/common/cache.c b/web/server/h2o/libh2o/lib/common/cache.c
deleted file mode 100644
index cc8d8f007..000000000
--- a/web/server/h2o/libh2o/lib/common/cache.c
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Copyright (c) 2014-2016 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 <assert.h>
-#include <pthread.h>
-#include "khash.h"
-#include "h2o/cache.h"
-#include "h2o/linklist.h"
-#include "h2o/memory.h"
-#include "h2o/string_.h"
-
-static h2o_cache_hashcode_t get_keyhash(h2o_cache_ref_t *ref);
-static int is_equal(h2o_cache_ref_t *x, h2o_cache_ref_t *y);
-
-KHASH_INIT(cache, h2o_cache_ref_t *, char, 0, get_keyhash, is_equal)
-
-struct st_h2o_cache_t {
- int flags;
- khash_t(cache) * table;
- size_t size;
- size_t capacity;
- h2o_linklist_t lru;
- h2o_linklist_t age;
- uint64_t duration;
- void (*destroy_cb)(h2o_iovec_t value);
- pthread_mutex_t mutex; /* only used if (flags & H2O_CACHE_FLAG_MULTITHREADED) != 0 */
-};
-
-static h2o_cache_hashcode_t get_keyhash(h2o_cache_ref_t *ref)
-{
- return ref->keyhash;
-}
-
-static int is_equal(h2o_cache_ref_t *x, h2o_cache_ref_t *y)
-{
- return x->key.len == y->key.len && memcmp(x->key.base, y->key.base, x->key.len) == 0;
-}
-
-static void lock_cache(h2o_cache_t *cache)
-{
- if ((cache->flags & H2O_CACHE_FLAG_MULTITHREADED) != 0)
- pthread_mutex_lock(&cache->mutex);
-}
-
-static void unlock_cache(h2o_cache_t *cache)
-{
- if ((cache->flags & H2O_CACHE_FLAG_MULTITHREADED) != 0)
- pthread_mutex_unlock(&cache->mutex);
-}
-
-static void erase_ref(h2o_cache_t *cache, khiter_t iter, int reuse)
-{
- h2o_cache_ref_t *ref = kh_key(cache->table, iter);
-
- if (!reuse)
- kh_del(cache, cache->table, iter);
- h2o_linklist_unlink(&ref->_lru_link);
- h2o_linklist_unlink(&ref->_age_link);
- cache->size -= ref->value.len;
-
- h2o_cache_release(cache, ref);
-}
-
-static int64_t get_timeleft(h2o_cache_t *cache, h2o_cache_ref_t *ref, uint64_t now)
-{
- return (int64_t)(ref->at + cache->duration) - now;
-}
-
-static void purge(h2o_cache_t *cache, uint64_t now)
-{
- /* by cache size */
- while (cache->capacity < cache->size) {
- h2o_cache_ref_t *last;
- assert(!h2o_linklist_is_empty(&cache->lru));
- last = H2O_STRUCT_FROM_MEMBER(h2o_cache_ref_t, _lru_link, cache->lru.next);
- erase_ref(cache, kh_get(cache, cache->table, last), 0);
- }
- /* by TTL */
- while (!h2o_linklist_is_empty(&cache->age)) {
- h2o_cache_ref_t *oldest = H2O_STRUCT_FROM_MEMBER(h2o_cache_ref_t, _age_link, cache->age.next);
- if (get_timeleft(cache, oldest, now) >= 0)
- break;
- erase_ref(cache, kh_get(cache, cache->table, oldest), 0);
- }
-}
-
-h2o_cache_hashcode_t h2o_cache_calchash(const char *s, size_t l)
-{
- h2o_cache_hashcode_t h = 0;
- for (; l != 0; --l)
- h = (h << 5) - h + ((unsigned char *)s)[l - 1];
- return h;
-}
-
-h2o_cache_t *h2o_cache_create(int flags, size_t capacity, uint64_t duration, void (*destroy_cb)(h2o_iovec_t value))
-{
- h2o_cache_t *cache = h2o_mem_alloc(sizeof(*cache));
-
- cache->flags = flags;
- cache->table = kh_init(cache);
- cache->size = 0;
- cache->capacity = capacity;
- h2o_linklist_init_anchor(&cache->lru);
- h2o_linklist_init_anchor(&cache->age);
- cache->duration = duration;
- cache->destroy_cb = destroy_cb;
- if ((cache->flags & H2O_CACHE_FLAG_MULTITHREADED) != 0)
- pthread_mutex_init(&cache->mutex, NULL);
-
- return cache;
-}
-
-void h2o_cache_destroy(h2o_cache_t *cache)
-{
- h2o_cache_clear(cache);
- kh_destroy(cache, cache->table);
- if ((cache->flags & H2O_CACHE_FLAG_MULTITHREADED) != 0)
- pthread_mutex_destroy(&cache->mutex);
- free(cache);
-}
-
-void h2o_cache_clear(h2o_cache_t *cache)
-{
- lock_cache(cache);
-
- while (!h2o_linklist_is_empty(&cache->lru)) {
- h2o_cache_ref_t *ref = H2O_STRUCT_FROM_MEMBER(h2o_cache_ref_t, _lru_link, cache->lru.next);
- erase_ref(cache, kh_get(cache, cache->table, ref), 0);
- }
- assert(h2o_linklist_is_linked(&cache->age));
- assert(kh_size(cache->table) == 0);
- assert(cache->size == 0);
-
- unlock_cache(cache);
-}
-
-h2o_cache_ref_t *h2o_cache_fetch(h2o_cache_t *cache, uint64_t now, h2o_iovec_t key, h2o_cache_hashcode_t keyhash)
-{
- h2o_cache_ref_t search_key, *ref;
- khiter_t iter;
- int64_t timeleft;
-
- if (keyhash == 0)
- keyhash = h2o_cache_calchash(key.base, key.len);
- search_key.key = key;
- search_key.keyhash = keyhash;
-
- lock_cache(cache);
-
- purge(cache, now);
-
- if ((iter = kh_get(cache, cache->table, &search_key)) == kh_end(cache->table))
- goto NotFound;
-
- /* found */
- ref = kh_key(cache->table, iter);
- timeleft = get_timeleft(cache, ref, now);
- if (timeleft < 0)
- goto NotFound;
- if ((cache->flags & H2O_CACHE_FLAG_EARLY_UPDATE) != 0 && timeleft < 10 && !ref->_requested_early_update) {
- ref->_requested_early_update = 1;
- goto NotFound;
- }
- /* move the entry to the top of LRU */
- h2o_linklist_unlink(&ref->_lru_link);
- h2o_linklist_insert(&cache->lru, &ref->_lru_link);
- __sync_fetch_and_add(&ref->_refcnt, 1);
-
- /* unlock and return the found entry */
- unlock_cache(cache);
- return ref;
-
-NotFound:
- unlock_cache(cache);
- return NULL;
-}
-
-void h2o_cache_release(h2o_cache_t *cache, h2o_cache_ref_t *ref)
-{
- if (__sync_fetch_and_sub(&ref->_refcnt, 1) == 1) {
- assert(!h2o_linklist_is_linked(&ref->_lru_link));
- assert(!h2o_linklist_is_linked(&ref->_age_link));
- if (cache->destroy_cb != NULL)
- cache->destroy_cb(ref->value);
- free(ref->key.base);
- free(ref);
- }
-}
-
-int h2o_cache_set(h2o_cache_t *cache, uint64_t now, h2o_iovec_t key, h2o_cache_hashcode_t keyhash, h2o_iovec_t value)
-{
- h2o_cache_ref_t *newref;
- khiter_t iter;
- int existed;
-
- if (keyhash == 0)
- keyhash = h2o_cache_calchash(key.base, key.len);
-
- /* create newref */
- newref = h2o_mem_alloc(sizeof(*newref));
- *newref = (h2o_cache_ref_t){h2o_strdup(NULL, key.base, key.len), keyhash, now, value, 0, {NULL}, {NULL}, 1};
-
- lock_cache(cache);
-
- /* set or replace the named value */
- iter = kh_get(cache, cache->table, newref);
- if (iter != kh_end(cache->table)) {
- erase_ref(cache, iter, 1);
- kh_key(cache->table, iter) = newref;
- existed = 1;
- } else {
- int unused;
- kh_put(cache, cache->table, newref, &unused);
- existed = 0;
- }
- h2o_linklist_insert(&cache->lru, &newref->_lru_link);
- h2o_linklist_insert(&cache->age, &newref->_age_link);
- cache->size += newref->value.len;
-
- purge(cache, now);
-
- unlock_cache(cache);
-
- return existed;
-}
-
-void h2o_cache_delete(h2o_cache_t *cache, uint64_t now, h2o_iovec_t key, h2o_cache_hashcode_t keyhash)
-{
- h2o_cache_ref_t search_key;
- khiter_t iter;
-
- if (keyhash == 0)
- keyhash = h2o_cache_calchash(key.base, key.len);
- search_key.key = key;
- search_key.keyhash = keyhash;
-
- lock_cache(cache);
-
- purge(cache, now);
-
- if ((iter = kh_get(cache, cache->table, &search_key)) != kh_end(cache->table))
- erase_ref(cache, iter, 0);
-
- unlock_cache(cache);
-}
-
-size_t h2o_cache_get_capacity(h2o_cache_t *cache)
-{
- return cache->capacity;
-}
-
-uint64_t h2o_cache_get_duration(h2o_cache_t *cache)
-{
- return cache->duration;
-}
diff --git a/web/server/h2o/libh2o/lib/common/file.c b/web/server/h2o/libh2o/lib/common/file.c
deleted file mode 100644
index 3cf5ac5d1..000000000
--- a/web/server/h2o/libh2o/lib/common/file.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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 <errno.h>
-#include <fcntl.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <unistd.h>
-#include "h2o/file.h"
-
-h2o_iovec_t h2o_file_read(const char *fn)
-{
- int fd;
- struct stat st;
- h2o_iovec_t ret = {NULL};
-
- /* open */
- if ((fd = open(fn, O_RDONLY | O_CLOEXEC)) == -1)
- goto Error;
- if (fstat(fd, &st))
- goto Error;
- /* allocate memory */
- if (st.st_size > SIZE_MAX) {
- errno = ENOMEM;
- goto Error;
- }
- if ((ret.base = malloc((size_t)st.st_size)) == NULL)
- goto Error;
- /* read */
- while (ret.len != (size_t)st.st_size) {
- ssize_t r;
- while ((r = read(fd, ret.base + ret.len, (size_t)st.st_size - ret.len)) == -1 && errno == EINTR)
- ;
- if (r <= 0)
- goto Error;
- ret.len += r;
- }
- /* close */
- close(fd);
- return ret;
-
-Error:
- if (fd != -1)
- close(fd);
- free(ret.base);
- return (h2o_iovec_t){NULL};
-}
diff --git a/web/server/h2o/libh2o/lib/common/filecache.c b/web/server/h2o/libh2o/lib/common/filecache.c
deleted file mode 100644
index 747a1ffa6..000000000
--- a/web/server/h2o/libh2o/lib/common/filecache.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * 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 <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stddef.h>
-#include <unistd.h>
-#include "khash.h"
-#include "h2o/memory.h"
-#include "h2o/filecache.h"
-
-KHASH_SET_INIT_STR(opencache_set)
-
-struct st_h2o_filecache_t {
- khash_t(opencache_set) * hash;
- h2o_linklist_t lru;
- size_t capacity;
-};
-
-static inline void release_from_cache(h2o_filecache_t *cache, khiter_t iter)
-{
- const char *path = kh_key(cache->hash, iter);
- h2o_filecache_ref_t *ref = H2O_STRUCT_FROM_MEMBER(h2o_filecache_ref_t, _path, path);
-
- /* detach from list */
- kh_del(opencache_set, cache->hash, iter);
- h2o_linklist_unlink(&ref->_lru);
-
- /* and close */
- h2o_filecache_close_file(ref);
-}
-
-h2o_filecache_t *h2o_filecache_create(size_t capacity)
-{
- h2o_filecache_t *cache = h2o_mem_alloc(sizeof(*cache));
-
- cache->hash = kh_init(opencache_set);
- h2o_linklist_init_anchor(&cache->lru);
- cache->capacity = capacity;
-
- return cache;
-}
-
-void h2o_filecache_destroy(h2o_filecache_t *cache)
-{
- h2o_filecache_clear(cache);
- assert(kh_size(cache->hash) == 0);
- assert(h2o_linklist_is_empty(&cache->lru));
- kh_destroy(opencache_set, cache->hash);
- free(cache);
-}
-
-void h2o_filecache_clear(h2o_filecache_t *cache)
-{
- khiter_t iter;
- for (iter = kh_begin(cache->hash); iter != kh_end(cache->hash); ++iter) {
- if (!kh_exist(cache->hash, iter))
- continue;
- release_from_cache(cache, iter);
- }
- assert(kh_size(cache->hash) == 0);
-}
-
-h2o_filecache_ref_t *h2o_filecache_open_file(h2o_filecache_t *cache, const char *path, int oflag)
-{
- khiter_t iter = kh_get(opencache_set, cache->hash, path);
- h2o_filecache_ref_t *ref;
- int dummy;
-
- /* lookup cache, and return the one if found */
- if (iter != kh_end(cache->hash)) {
- ref = H2O_STRUCT_FROM_MEMBER(h2o_filecache_ref_t, _path, kh_key(cache->hash, iter));
- ++ref->_refcnt;
- goto Exit;
- }
-
- /* create a new cache entry */
- ref = h2o_mem_alloc(offsetof(h2o_filecache_ref_t, _path) + strlen(path) + 1);
- ref->_refcnt = 1;
- ref->_lru = (h2o_linklist_t){NULL};
- strcpy(ref->_path, path);
-
- /* if cache is used, then... */
- if (cache->capacity != 0) {
- /* purge one entry from LRU if cache is full */
- if (kh_size(cache->hash) == cache->capacity) {
- h2o_filecache_ref_t *purge_ref = H2O_STRUCT_FROM_MEMBER(h2o_filecache_ref_t, _lru, cache->lru.prev);
- khiter_t purge_iter = kh_get(opencache_set, cache->hash, purge_ref->_path);
- assert(purge_iter != kh_end(cache->hash));
- release_from_cache(cache, purge_iter);
- }
- /* assign the new entry */
- ++ref->_refcnt;
- kh_put(opencache_set, cache->hash, ref->_path, &dummy);
- h2o_linklist_insert(cache->lru.next, &ref->_lru);
- }
-
- /* open the file, or memoize the error */
- if ((ref->fd = open(path, oflag)) != -1 && fstat(ref->fd, &ref->st) == 0) {
- ref->_last_modified.str[0] = '\0';
- ref->_etag.len = 0;
- } else {
- ref->open_err = errno;
- if (ref->fd != -1) {
- close(ref->fd);
- ref->fd = -1;
- }
- }
-
-Exit:
- /* if the cache entry retains an error, return it instead of the reference */
- if (ref->fd == -1) {
- errno = ref->open_err;
- h2o_filecache_close_file(ref);
- ref = NULL;
- }
- return ref;
-}
-
-void h2o_filecache_close_file(h2o_filecache_ref_t *ref)
-{
- if (--ref->_refcnt != 0)
- return;
- assert(!h2o_linklist_is_linked(&ref->_lru));
- if (ref->fd != -1) {
- close(ref->fd);
- ref->fd = -1;
- }
- free(ref);
-}
-
-struct tm *h2o_filecache_get_last_modified(h2o_filecache_ref_t *ref, char *outbuf)
-{
- assert(ref->fd != -1);
- if (ref->_last_modified.str[0] == '\0') {
- gmtime_r(&ref->st.st_mtime, &ref->_last_modified.gm);
- h2o_time2str_rfc1123(ref->_last_modified.str, &ref->_last_modified.gm);
- }
- if (outbuf != NULL)
- memcpy(outbuf, ref->_last_modified.str, H2O_TIMESTR_RFC1123_LEN + 1);
- return &ref->_last_modified.gm;
-}
-
-size_t h2o_filecache_get_etag(h2o_filecache_ref_t *ref, char *outbuf)
-{
- assert(ref->fd != -1);
- if (ref->_etag.len == 0)
- ref->_etag.len = sprintf(ref->_etag.buf, "\"%08x-%zx\"", (unsigned)ref->st.st_mtime, (size_t)ref->st.st_size);
- memcpy(outbuf, ref->_etag.buf, ref->_etag.len + 1);
- return ref->_etag.len;
-}
diff --git a/web/server/h2o/libh2o/lib/common/hostinfo.c b/web/server/h2o/libh2o/lib/common/hostinfo.c
deleted file mode 100644
index 7b481e296..000000000
--- a/web/server/h2o/libh2o/lib/common/hostinfo.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * 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;
-}
diff --git a/web/server/h2o/libh2o/lib/common/http1client.c b/web/server/h2o/libh2o/lib/common/http1client.c
deleted file mode 100644
index 8547ea817..000000000
--- a/web/server/h2o/libh2o/lib/common/http1client.c
+++ /dev/null
@@ -1,582 +0,0 @@
-/*
- * Copyright (c) 2014 DeNA Co., Ltd.
- *
- * 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 <arpa/inet.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include "picohttpparser.h"
-#include "h2o.h"
-
-struct st_h2o_http1client_private_t {
- h2o_http1client_t super;
- union {
- h2o_http1client_connect_cb on_connect;
- h2o_http1client_head_cb on_head;
- h2o_http1client_body_cb on_body;
- } _cb;
- h2o_timeout_entry_t _timeout;
- int _method_is_head;
- h2o_hostinfo_getaddr_req_t *_getaddr_req;
- int _can_keepalive;
- union {
- struct {
- size_t bytesleft;
- } content_length;
- struct {
- struct phr_chunked_decoder decoder;
- size_t bytes_decoded_in_buf;
- } chunked;
- } _body_decoder;
-};
-
-static void close_client(struct st_h2o_http1client_private_t *client)
-{
- if (client->_getaddr_req != NULL) {
- h2o_hostinfo_getaddr_cancel(client->_getaddr_req);
- client->_getaddr_req = NULL;
- }
- if (client->super.ssl.server_name != NULL)
- free(client->super.ssl.server_name);
- if (client->super.sock != NULL) {
- if (client->super.sockpool.pool != NULL && client->_can_keepalive) {
- /* we do not send pipelined requests, and thus can trash all the received input at the end of the request */
- h2o_buffer_consume(&client->super.sock->input, client->super.sock->input->size);
- h2o_socketpool_return(client->super.sockpool.pool, client->super.sock);
- } else {
- h2o_socket_close(client->super.sock);
- }
- } else {
- if (client->super.sockpool.connect_req != NULL) {
- h2o_socketpool_cancel_connect(client->super.sockpool.connect_req);
- client->super.sockpool.connect_req = NULL;
- }
- }
- if (h2o_timeout_is_linked(&client->_timeout))
- h2o_timeout_unlink(&client->_timeout);
- free(client);
-}
-
-static void on_body_error(struct st_h2o_http1client_private_t *client, const char *errstr)
-{
- client->_can_keepalive = 0;
- client->_cb.on_body(&client->super, errstr);
- close_client(client);
-}
-
-static void on_body_timeout(h2o_timeout_entry_t *entry)
-{
- struct st_h2o_http1client_private_t *client = H2O_STRUCT_FROM_MEMBER(struct st_h2o_http1client_private_t, _timeout, entry);
- on_body_error(client, "I/O timeout");
-}
-
-static void on_body_until_close(h2o_socket_t *sock, const char *err)
-{
- struct st_h2o_http1client_private_t *client = sock->data;
-
- h2o_timeout_unlink(&client->_timeout);
-
- if (err != NULL) {
- client->_cb.on_body(&client->super, h2o_http1client_error_is_eos);
- close_client(client);
- return;
- }
-
- if (sock->bytes_read != 0) {
- if (client->_cb.on_body(&client->super, NULL) != 0) {
- close_client(client);
- return;
- }
- }
-
- h2o_timeout_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->_timeout);
-}
-
-static void on_body_content_length(h2o_socket_t *sock, const char *err)
-{
- struct st_h2o_http1client_private_t *client = sock->data;
-
- h2o_timeout_unlink(&client->_timeout);
-
- if (err != NULL) {
- on_body_error(client, "I/O error (body; content-length)");
- return;
- }
-
- if (sock->bytes_read != 0 || client->_body_decoder.content_length.bytesleft == 0) {
- const char *errstr;
- int ret;
- if (client->_body_decoder.content_length.bytesleft <= sock->bytes_read) {
- if (client->_body_decoder.content_length.bytesleft < sock->bytes_read) {
- /* remove the trailing garbage from buf, and disable keepalive */
- client->super.sock->input->size -= sock->bytes_read - client->_body_decoder.content_length.bytesleft;
- client->_can_keepalive = 0;
- }
- client->_body_decoder.content_length.bytesleft = 0;
- errstr = h2o_http1client_error_is_eos;
- } else {
- client->_body_decoder.content_length.bytesleft -= sock->bytes_read;
- errstr = NULL;
- }
- ret = client->_cb.on_body(&client->super, errstr);
- if (errstr == h2o_http1client_error_is_eos) {
- close_client(client);
- return;
- } else if (ret != 0) {
- client->_can_keepalive = 0;
- close_client(client);
- return;
- }
- }
-
- h2o_timeout_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->_timeout);
-}
-
-static void on_body_chunked(h2o_socket_t *sock, const char *err)
-{
- struct st_h2o_http1client_private_t *client = sock->data;
- h2o_buffer_t *inbuf;
-
- h2o_timeout_unlink(&client->_timeout);
-
- if (err != NULL) {
- if (err == h2o_socket_error_closed && !phr_decode_chunked_is_in_data(&client->_body_decoder.chunked.decoder)) {
- /*
- * if the peer closed after a full chunk, treat this
- * as if the transfer had complete, browsers appear to ignore
- * a missing 0\r\n chunk
- */
- client->_can_keepalive = 0;
- client->_cb.on_body(&client->super, h2o_http1client_error_is_eos);
- close_client(client);
- } else {
- on_body_error(client, "I/O error (body; chunked)");
- }
- return;
- }
-
- inbuf = client->super.sock->input;
- if (sock->bytes_read != 0) {
- const char *errstr;
- int cb_ret;
- size_t newsz = sock->bytes_read;
- switch (phr_decode_chunked(&client->_body_decoder.chunked.decoder, inbuf->bytes + inbuf->size - newsz, &newsz)) {
- case -1: /* error */
- newsz = sock->bytes_read;
- client->_can_keepalive = 0;
- errstr = "failed to parse the response (chunked)";
- break;
- case -2: /* incomplete */
- errstr = NULL;
- break;
- default: /* complete, with garbage on tail; should disable keepalive */
- client->_can_keepalive = 0;
- /* fallthru */
- case 0: /* complete */
- errstr = h2o_http1client_error_is_eos;
- break;
- }
- inbuf->size -= sock->bytes_read - newsz;
- cb_ret = client->_cb.on_body(&client->super, errstr);
- if (errstr != NULL) {
- close_client(client);
- return;
- } else if (cb_ret != 0) {
- client->_can_keepalive = 0;
- close_client(client);
- return;
- }
- }
-
- h2o_timeout_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->_timeout);
-}
-
-static void on_error_before_head(struct st_h2o_http1client_private_t *client, const char *errstr)
-{
- assert(!client->_can_keepalive);
- client->_cb.on_head(&client->super, errstr, 0, 0, h2o_iovec_init(NULL, 0), NULL, 0, 0);
- close_client(client);
-}
-
-static void on_head(h2o_socket_t *sock, const char *err)
-{
- struct st_h2o_http1client_private_t *client = sock->data;
- int minor_version, http_status, rlen, is_eos;
- const char *msg;
-#define MAX_HEADERS 100
- h2o_header_t *headers;
- h2o_iovec_t *header_names;
- size_t msg_len, num_headers, i;
- h2o_socket_cb reader;
- h2o_mem_pool_t pool;
-
- h2o_timeout_unlink(&client->_timeout);
-
- if (err != NULL) {
- on_error_before_head(client, "I/O error (head)");
- return;
- }
-
- h2o_mem_init_pool(&pool);
-
- headers = h2o_mem_alloc_pool(&pool, sizeof(*headers) * MAX_HEADERS);
- header_names = h2o_mem_alloc_pool(&pool, sizeof(*header_names) * MAX_HEADERS);
-
- /* continue parsing the responses until we see a final one */
- while (1) {
- /* parse response */
- struct phr_header src_headers[MAX_HEADERS];
- num_headers = MAX_HEADERS;
- rlen = phr_parse_response(sock->input->bytes, sock->input->size, &minor_version, &http_status, &msg, &msg_len, src_headers,
- &num_headers, 0);
- switch (rlen) {
- case -1: /* error */
- on_error_before_head(client, "failed to parse the response");
- goto Exit;
- case -2: /* incomplete */
- h2o_timeout_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->_timeout);
- goto Exit;
- }
- /* fill-in the headers */
- for (i = 0; i != num_headers; ++i) {
- const h2o_token_t *token;
- char *orig_name = h2o_strdup(&pool, src_headers[i].name, src_headers[i].name_len).base;
- h2o_strtolower((char *)src_headers[i].name, src_headers[i].name_len);
- token = h2o_lookup_token(src_headers[i].name, src_headers[i].name_len);
- if (token != NULL) {
- headers[i].name = (h2o_iovec_t *)&token->buf;
- } else {
- header_names[i] = h2o_iovec_init(src_headers[i].name, src_headers[i].name_len);
- headers[i].name = &header_names[i];
- }
- headers[i].value = h2o_iovec_init(src_headers[i].value, src_headers[i].value_len);
- headers[i].orig_name = orig_name;
- }
-
- if (!(100 <= http_status && http_status <= 199 && http_status != 101))
- break;
-
- if (client->super.informational_cb != NULL &&
- client->super.informational_cb(&client->super, minor_version, http_status, h2o_iovec_init(msg, msg_len), headers,
- num_headers) != 0) {
- close_client(client);
- goto Exit;
- }
- h2o_buffer_consume(&client->super.sock->input, rlen);
- if (client->super.sock->input->size == 0) {
- h2o_timeout_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->_timeout);
- goto Exit;
- }
- }
-
- /* parse the headers */
- reader = on_body_until_close;
- client->_can_keepalive = minor_version >= 1;
- for (i = 0; i != num_headers; ++i) {
- if (headers[i].name == &H2O_TOKEN_CONNECTION->buf) {
- if (h2o_contains_token(headers[i].value.base, headers[i].value.len, H2O_STRLIT("keep-alive"), ',')) {
- client->_can_keepalive = 1;
- } else {
- client->_can_keepalive = 0;
- }
- } else if (headers[i].name == &H2O_TOKEN_TRANSFER_ENCODING->buf) {
- if (h2o_memis(headers[i].value.base, headers[i].value.len, H2O_STRLIT("chunked"))) {
- /* precond: _body_decoder.chunked is zero-filled */
- client->_body_decoder.chunked.decoder.consume_trailer = 1;
- reader = on_body_chunked;
- } else if (h2o_memis(headers[i].value.base, headers[i].value.len, H2O_STRLIT("identity"))) {
- /* continue */
- } else {
- on_error_before_head(client, "unexpected type of transfer-encoding");
- goto Exit;
- }
- } else if (headers[i].name == &H2O_TOKEN_CONTENT_LENGTH->buf) {
- if ((client->_body_decoder.content_length.bytesleft = h2o_strtosize(headers[i].value.base, headers[i].value.len)) ==
- SIZE_MAX) {
- on_error_before_head(client, "invalid content-length");
- goto Exit;
- }
- if (reader != on_body_chunked)
- reader = on_body_content_length;
- }
- }
-
- /* RFC 2616 4.4 */
- if (client->_method_is_head || http_status == 101 || http_status == 204 || http_status == 304) {
- is_eos = 1;
- } else {
- is_eos = 0;
- /* close the connection if impossible to determine the end of the response (RFC 7230 3.3.3) */
- if (reader == on_body_until_close)
- client->_can_keepalive = 0;
- }
-
- /* call the callback. sock may be stealed and stealed sock need rlen.*/
- client->_cb.on_body = client->_cb.on_head(&client->super, is_eos ? h2o_http1client_error_is_eos : NULL, minor_version,
- http_status, h2o_iovec_init(msg, msg_len), headers, num_headers, rlen);
-
- if (is_eos) {
- close_client(client);
- goto Exit;
- } else if (client->_cb.on_body == NULL) {
- client->_can_keepalive = 0;
- close_client(client);
- goto Exit;
- }
-
- h2o_buffer_consume(&client->super.sock->input, rlen);
- client->super.sock->bytes_read = client->super.sock->input->size;
-
- client->_timeout.cb = on_body_timeout;
- h2o_socket_read_start(sock, reader);
- reader(client->super.sock, 0);
-
-Exit:
- h2o_mem_clear_pool(&pool);
-#undef MAX_HEADERS
-}
-
-static void on_head_timeout(h2o_timeout_entry_t *entry)
-{
- struct st_h2o_http1client_private_t *client = H2O_STRUCT_FROM_MEMBER(struct st_h2o_http1client_private_t, _timeout, entry);
- on_error_before_head(client, "I/O timeout");
-}
-
-static void on_send_request(h2o_socket_t *sock, const char *err)
-{
- struct st_h2o_http1client_private_t *client = sock->data;
-
- h2o_timeout_unlink(&client->_timeout);
-
- if (err != NULL) {
- on_error_before_head(client, "I/O error (send request)");
- return;
- }
-
- h2o_socket_read_start(client->super.sock, on_head);
- client->_timeout.cb = on_head_timeout;
- h2o_timeout_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->_timeout);
-}
-
-static void on_send_timeout(h2o_timeout_entry_t *entry)
-{
- struct st_h2o_http1client_private_t *client = H2O_STRUCT_FROM_MEMBER(struct st_h2o_http1client_private_t, _timeout, entry);
- on_error_before_head(client, "I/O timeout");
-}
-
-static void on_connect_error(struct st_h2o_http1client_private_t *client, const char *errstr)
-{
- assert(errstr != NULL);
- client->_cb.on_connect(&client->super, errstr, NULL, NULL, NULL);
- close_client(client);
-}
-
-static void on_connection_ready(struct st_h2o_http1client_private_t *client)
-{
- h2o_iovec_t *reqbufs;
- size_t reqbufcnt;
-
- if ((client->_cb.on_head = client->_cb.on_connect(&client->super, NULL, &reqbufs, &reqbufcnt, &client->_method_is_head)) ==
- NULL) {
- close_client(client);
- return;
- }
- h2o_socket_write(client->super.sock, reqbufs, reqbufcnt, on_send_request);
- /* TODO no need to set the timeout if all data has been written into TCP sendbuf */
- client->_timeout.cb = on_send_timeout;
- h2o_timeout_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->_timeout);
-}
-
-static void on_handshake_complete(h2o_socket_t *sock, const char *err)
-{
- struct st_h2o_http1client_private_t *client = sock->data;
-
- h2o_timeout_unlink(&client->_timeout);
-
- if (err == NULL) {
- /* success */
- } else if (err == h2o_socket_error_ssl_cert_name_mismatch &&
- (SSL_CTX_get_verify_mode(client->super.ctx->ssl_ctx) & SSL_VERIFY_PEER) == 0) {
- /* peer verification skipped */
- } else {
- on_connect_error(client, err);
- return;
- }
-
- on_connection_ready(client);
-}
-
-static void on_connect(h2o_socket_t *sock, const char *err)
-{
- struct st_h2o_http1client_private_t *client = sock->data;
-
- if (err != NULL) {
- h2o_timeout_unlink(&client->_timeout);
- on_connect_error(client, err);
- return;
- }
- if (client->super.ssl.server_name != NULL && client->super.sock->ssl == NULL) {
- h2o_socket_ssl_handshake(client->super.sock, client->super.ctx->ssl_ctx, client->super.ssl.server_name,
- on_handshake_complete);
- return;
- }
-
- h2o_timeout_unlink(&client->_timeout);
-
- on_connection_ready(client);
-}
-
-static void on_pool_connect(h2o_socket_t *sock, const char *errstr, void *data)
-{
- struct st_h2o_http1client_private_t *client = data;
-
- client->super.sockpool.connect_req = NULL;
-
- if (sock == NULL) {
- assert(errstr != NULL);
- on_connect_error(client, errstr);
- return;
- }
-
- client->super.sock = sock;
- sock->data = client;
- on_connect(sock, NULL);
-}
-
-static void on_connect_timeout(h2o_timeout_entry_t *entry)
-{
- struct st_h2o_http1client_private_t *client = H2O_STRUCT_FROM_MEMBER(struct st_h2o_http1client_private_t, _timeout, entry);
- on_connect_error(client, "connection timeout");
-}
-
-static void start_connect(struct st_h2o_http1client_private_t *client, struct sockaddr *addr, socklen_t addrlen)
-{
- if ((client->super.sock = h2o_socket_connect(client->super.ctx->loop, addr, addrlen, on_connect)) == NULL) {
- on_connect_error(client, "socket create error");
- return;
- }
- client->super.sock->data = client;
-}
-
-static void on_getaddr(h2o_hostinfo_getaddr_req_t *getaddr_req, const char *errstr, struct addrinfo *res, void *_client)
-{
- struct st_h2o_http1client_private_t *client = _client;
-
- assert(getaddr_req == client->_getaddr_req);
- client->_getaddr_req = NULL;
-
- if (errstr != NULL) {
- on_connect_error(client, errstr);
- return;
- }
-
- /* start connecting */
- struct addrinfo *selected = h2o_hostinfo_select_one(res);
- start_connect(client, selected->ai_addr, selected->ai_addrlen);
-}
-
-static struct st_h2o_http1client_private_t *create_client(h2o_http1client_t **_client, void *data, h2o_http1client_ctx_t *ctx,
- h2o_iovec_t ssl_server_name, h2o_http1client_connect_cb cb)
-{
- struct st_h2o_http1client_private_t *client = h2o_mem_alloc(sizeof(*client));
-
- *client = (struct st_h2o_http1client_private_t){{ctx}};
- if (ssl_server_name.base != NULL)
- client->super.ssl.server_name = h2o_strdup(NULL, ssl_server_name.base, ssl_server_name.len).base;
- client->super.data = data;
- client->_cb.on_connect = cb;
- /* caller needs to setup _cb, timeout.cb, sock, and sock->data */
-
- if (_client != NULL)
- *_client = &client->super;
- return client;
-}
-
-const char *const h2o_http1client_error_is_eos = "end of stream";
-
-void h2o_http1client_connect(h2o_http1client_t **_client, void *data, h2o_http1client_ctx_t *ctx, h2o_iovec_t host, uint16_t port,
- int is_ssl, h2o_http1client_connect_cb cb)
-{
- struct st_h2o_http1client_private_t *client;
- char serv[sizeof("65536")];
-
- /* setup */
- client = create_client(_client, data, ctx, is_ssl ? host : h2o_iovec_init(NULL, 0), cb);
- client->_timeout.cb = on_connect_timeout;
- h2o_timeout_link(ctx->loop, ctx->io_timeout, &client->_timeout);
-
- { /* directly call connect(2) if `host` is an IP address */
- struct sockaddr_in sin;
- memset(&sin, 0, sizeof(sin));
- if (h2o_hostinfo_aton(host, &sin.sin_addr) == 0) {
- sin.sin_family = AF_INET;
- sin.sin_port = htons(port);
- start_connect(client, (void *)&sin, sizeof(sin));
- return;
- }
- }
- { /* directly call connect(2) if `host` refers to an UNIX-domain socket */
- struct sockaddr_un sa;
- const char *to_sa_err;
- if ((to_sa_err = h2o_url_host_to_sun(host, &sa)) != h2o_url_host_to_sun_err_is_not_unix_socket) {
- if (to_sa_err != NULL) {
- on_connect_error(client, to_sa_err);
- return;
- }
- start_connect(client, (void *)&sa, sizeof(sa));
- return;
- }
- }
- /* resolve destination and then connect */
- client->_getaddr_req =
- h2o_hostinfo_getaddr(ctx->getaddr_receiver, host, h2o_iovec_init(serv, sprintf(serv, "%u", (unsigned)port)), AF_UNSPEC,
- SOCK_STREAM, IPPROTO_TCP, AI_ADDRCONFIG | AI_NUMERICSERV, on_getaddr, client);
-}
-
-void h2o_http1client_connect_with_pool(h2o_http1client_t **_client, void *data, h2o_http1client_ctx_t *ctx,
- h2o_socketpool_t *sockpool, h2o_http1client_connect_cb cb)
-{
- struct st_h2o_http1client_private_t *client =
- create_client(_client, data, ctx, sockpool->is_ssl ? sockpool->peer.host : h2o_iovec_init(NULL, 0), cb);
- client->super.sockpool.pool = sockpool;
- client->_timeout.cb = on_connect_timeout;
- h2o_timeout_link(ctx->loop, ctx->io_timeout, &client->_timeout);
- h2o_socketpool_connect(&client->super.sockpool.connect_req, sockpool, ctx->loop, ctx->getaddr_receiver, on_pool_connect,
- client);
-}
-
-void h2o_http1client_cancel(h2o_http1client_t *_client)
-{
- struct st_h2o_http1client_private_t *client = (void *)_client;
- client->_can_keepalive = 0;
- close_client(client);
-}
-
-h2o_socket_t *h2o_http1client_steal_socket(h2o_http1client_t *_client)
-{
- struct st_h2o_http1client_private_t *client = (void *)_client;
- h2o_socket_t *sock = client->super.sock;
- h2o_socket_read_stop(sock);
- client->super.sock = NULL;
- return sock;
-}
diff --git a/web/server/h2o/libh2o/lib/common/memcached.c b/web/server/h2o/libh2o/lib/common/memcached.c
deleted file mode 100644
index 752ea2fcb..000000000
--- a/web/server/h2o/libh2o/lib/common/memcached.c
+++ /dev/null
@@ -1,429 +0,0 @@
-/*
- * 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 <errno.h>
-#include <inttypes.h>
-#include <unistd.h>
-#include "yrmcds.h"
-#include "h2o/linklist.h"
-#include "h2o/memcached.h"
-#include "h2o/rand.h"
-#include "h2o/string_.h"
-
-struct st_h2o_memcached_context_t {
- pthread_mutex_t mutex;
- pthread_cond_t cond;
- h2o_linklist_t pending;
- size_t num_threads_connected;
- char *host;
- uint16_t port;
- int text_protocol;
- h2o_iovec_t prefix;
-};
-
-struct st_h2o_memcached_conn_t {
- h2o_memcached_context_t *ctx;
- yrmcds yrmcds;
- pthread_mutex_t mutex;
- h2o_linklist_t inflight;
- int writer_exit_requested;
-};
-
-enum en_h2o_memcached_req_type_t { REQ_TYPE_GET, REQ_TYPE_SET, REQ_TYPE_DELETE };
-
-struct st_h2o_memcached_req_t {
- enum en_h2o_memcached_req_type_t type;
- h2o_linklist_t pending;
- h2o_linklist_t inflight;
- union {
- struct {
- h2o_multithread_receiver_t *receiver;
- h2o_multithread_message_t message;
- h2o_memcached_get_cb cb;
- void *cb_data;
- int value_is_encoded;
- h2o_iovec_t value;
- uint32_t serial;
- } get;
- struct {
- h2o_iovec_t value;
- uint32_t expiration;
- } set;
- } data;
- struct {
- size_t len;
- char base[1];
- } key;
-};
-
-static h2o_memcached_req_t *create_req(h2o_memcached_context_t *ctx, enum en_h2o_memcached_req_type_t type, h2o_iovec_t key,
- int encode_key)
-{
- h2o_memcached_req_t *req = h2o_mem_alloc(offsetof(h2o_memcached_req_t, key.base) + ctx->prefix.len +
- (encode_key ? (key.len + 2) / 3 * 4 + 1 : key.len));
- req->type = type;
- req->pending = (h2o_linklist_t){NULL};
- req->inflight = (h2o_linklist_t){NULL};
- memset(&req->data, 0, sizeof(req->data));
- if (ctx->prefix.len != 0)
- memcpy(req->key.base, ctx->prefix.base, ctx->prefix.len);
- req->key.len = ctx->prefix.len;
- if (encode_key) {
- req->key.len += h2o_base64_encode(req->key.base + req->key.len, key.base, key.len, 1);
- } else {
- memcpy(req->key.base + req->key.len, key.base, key.len);
- req->key.len += key.len;
- }
- return req;
-}
-
-static void free_req(h2o_memcached_req_t *req)
-{
- assert(!h2o_linklist_is_linked(&req->pending));
- switch (req->type) {
- case REQ_TYPE_GET:
- assert(!h2o_linklist_is_linked(&req->data.get.message.link));
- h2o_mem_set_secure(req->data.get.value.base, 0, req->data.get.value.len);
- free(req->data.get.value.base);
- break;
- case REQ_TYPE_SET:
- h2o_mem_set_secure(req->data.set.value.base, 0, req->data.set.value.len);
- free(req->data.set.value.base);
- break;
- case REQ_TYPE_DELETE:
- break;
- default:
- assert(!"FIXME");
- break;
- }
- free(req);
-}
-
-static void discard_req(h2o_memcached_req_t *req)
-{
- switch (req->type) {
- case REQ_TYPE_GET:
- h2o_multithread_send_message(req->data.get.receiver, &req->data.get.message);
- break;
- default:
- free_req(req);
- break;
- }
-}
-
-static h2o_memcached_req_t *pop_inflight(struct st_h2o_memcached_conn_t *conn, uint32_t serial)
-{
- h2o_memcached_req_t *req;
-
- pthread_mutex_lock(&conn->mutex);
-
- if (conn->yrmcds.text_mode) {
- /* in text mode, responses are returned in order (and we may receive responses for commands other than GET) */
- if (!h2o_linklist_is_empty(&conn->inflight)) {
- req = H2O_STRUCT_FROM_MEMBER(h2o_memcached_req_t, inflight, conn->inflight.next);
- assert(req->type == REQ_TYPE_GET);
- if (req->data.get.serial == serial)
- goto Found;
- }
- } else {
- /* in binary mode, responses are received out-of-order (and we would only recieve responses for GET) */
- h2o_linklist_t *node;
- for (node = conn->inflight.next; node != &conn->inflight; node = node->next) {
- req = H2O_STRUCT_FROM_MEMBER(h2o_memcached_req_t, inflight, node);
- assert(req->type == REQ_TYPE_GET);
- if (req->data.get.serial == serial)
- goto Found;
- }
- }
-
- /* not found */
- pthread_mutex_unlock(&conn->mutex);
- return NULL;
-
-Found:
- h2o_linklist_unlink(&req->inflight);
- pthread_mutex_unlock(&conn->mutex);
- return req;
-}
-
-static void *writer_main(void *_conn)
-{
- struct st_h2o_memcached_conn_t *conn = _conn;
- yrmcds_error err;
-
- pthread_mutex_lock(&conn->ctx->mutex);
-
- while (!__sync_add_and_fetch(&conn->writer_exit_requested, 0)) {
- while (!h2o_linklist_is_empty(&conn->ctx->pending)) {
- h2o_memcached_req_t *req = H2O_STRUCT_FROM_MEMBER(h2o_memcached_req_t, pending, conn->ctx->pending.next);
- h2o_linklist_unlink(&req->pending);
- pthread_mutex_unlock(&conn->ctx->mutex);
-
- switch (req->type) {
- case REQ_TYPE_GET:
- pthread_mutex_lock(&conn->mutex);
- h2o_linklist_insert(&conn->inflight, &req->inflight);
- pthread_mutex_unlock(&conn->mutex);
- if ((err = yrmcds_get(&conn->yrmcds, req->key.base, req->key.len, 0, &req->data.get.serial)) != YRMCDS_OK)
- goto Error;
- break;
- case REQ_TYPE_SET:
- err = yrmcds_set(&conn->yrmcds, req->key.base, req->key.len, req->data.set.value.base, req->data.set.value.len, 0,
- req->data.set.expiration, 0, !conn->yrmcds.text_mode, NULL);
- discard_req(req);
- if (err != YRMCDS_OK)
- goto Error;
- break;
- case REQ_TYPE_DELETE:
- err = yrmcds_remove(&conn->yrmcds, req->key.base, req->key.len, !conn->yrmcds.text_mode, NULL);
- discard_req(req);
- if (err != YRMCDS_OK)
- goto Error;
- break;
- default:
- fprintf(stderr, "[lib/common/memcached.c] unknown type:%d\n", (int)req->type);
- err = YRMCDS_NOT_IMPLEMENTED;
- goto Error;
- }
-
- pthread_mutex_lock(&conn->ctx->mutex);
- }
- pthread_cond_wait(&conn->ctx->cond, &conn->ctx->mutex);
- }
-
- pthread_mutex_unlock(&conn->ctx->mutex);
- return NULL;
-
-Error:
- fprintf(stderr, "[lib/common/memcached.c] failed to send request; %s\n", yrmcds_strerror(err));
- /* doc says the call can be used to interrupt yrmcds_recv */
- yrmcds_shutdown(&conn->yrmcds);
-
- return NULL;
-}
-
-static void connect_to_server(h2o_memcached_context_t *ctx, yrmcds *yrmcds)
-{
- size_t failcnt;
- yrmcds_error err;
-
- for (failcnt = 0; (err = yrmcds_connect(yrmcds, ctx->host, ctx->port)) != YRMCDS_OK; ++failcnt) {
- if (failcnt == 0) {
- fprintf(stderr, "[lib/common/memcached.c] failed to connect to memcached at %s:%" PRIu16 ", %s\n", ctx->host, ctx->port,
- yrmcds_strerror(err));
- }
- ++failcnt;
- usleep(2000000 + h2o_rand() % 3000000); /* sleep 2 to 5 seconds */
- }
- /* connected */
- if (ctx->text_protocol)
- yrmcds_text_mode(yrmcds);
- fprintf(stderr, "[lib/common/memcached.c] connected to memcached at %s:%" PRIu16 "\n", ctx->host, ctx->port);
-}
-
-static void reader_main(h2o_memcached_context_t *ctx)
-{
- struct st_h2o_memcached_conn_t conn = {ctx, {0}, PTHREAD_MUTEX_INITIALIZER, {&conn.inflight, &conn.inflight}, 0};
- pthread_t writer_thread;
- yrmcds_response resp;
- yrmcds_error err;
-
- /* connect to server and start the writer thread */
- connect_to_server(conn.ctx, &conn.yrmcds);
- if (pthread_create(&writer_thread, NULL, writer_main, &conn) != 0) {
- perror("pthread_create");
- abort();
- }
-
- pthread_mutex_lock(&conn.ctx->mutex);
- ++conn.ctx->num_threads_connected;
- pthread_mutex_unlock(&conn.ctx->mutex);
-
- /* receive data until an error occurs */
- while (1) {
- if ((err = yrmcds_recv(&conn.yrmcds, &resp)) != YRMCDS_OK) {
- fprintf(stderr, "[lib/common/memcached.c] yrmcds_recv:%s\n", yrmcds_strerror(err));
- break;
- }
- h2o_memcached_req_t *req = pop_inflight(&conn, resp.serial);
- if (req == NULL) {
- if (conn.yrmcds.text_mode)
- continue;
- fprintf(stderr, "[lib/common/memcached.c] received unexpected serial\n");
- break;
- }
- if (resp.status == YRMCDS_STATUS_OK) {
- req->data.get.value = h2o_iovec_init(h2o_mem_alloc(resp.data_len), resp.data_len);
- memcpy(req->data.get.value.base, resp.data, resp.data_len);
- h2o_mem_set_secure((void *)resp.data, 0, resp.data_len);
- }
- h2o_multithread_send_message(req->data.get.receiver, &req->data.get.message);
- }
-
- /* send error to all the reqs in-flight */
- pthread_mutex_lock(&conn.mutex);
- while (!h2o_linklist_is_empty(&conn.inflight)) {
- h2o_memcached_req_t *req = H2O_STRUCT_FROM_MEMBER(h2o_memcached_req_t, inflight, conn.inflight.next);
- h2o_linklist_unlink(&req->inflight);
- assert(req->type == REQ_TYPE_GET);
- h2o_multithread_send_message(req->data.get.receiver, &req->data.get.message);
- }
- pthread_mutex_unlock(&conn.mutex);
-
- /* stop the writer thread */
- __sync_add_and_fetch(&conn.writer_exit_requested, 1);
- pthread_mutex_lock(&conn.ctx->mutex);
- pthread_cond_broadcast(&conn.ctx->cond);
- pthread_mutex_unlock(&conn.ctx->mutex);
- pthread_join(writer_thread, NULL);
-
- /* decrement num_threads_connected, and discard all the pending requests if no connections are alive */
- pthread_mutex_lock(&conn.ctx->mutex);
- if (--conn.ctx->num_threads_connected == 0) {
- while (!h2o_linklist_is_empty(&conn.ctx->pending)) {
- h2o_memcached_req_t *req = H2O_STRUCT_FROM_MEMBER(h2o_memcached_req_t, pending, conn.ctx->pending.next);
- h2o_linklist_unlink(&req->pending);
- discard_req(req);
- }
- }
- pthread_mutex_unlock(&conn.ctx->mutex);
-
- /* close the connection */
- yrmcds_close(&conn.yrmcds);
-}
-
-static void *thread_main(void *_ctx)
-{
- h2o_memcached_context_t *ctx = _ctx;
-
- while (1)
- reader_main(ctx);
- return NULL;
-}
-
-static void dispatch(h2o_memcached_context_t *ctx, h2o_memcached_req_t *req)
-{
- pthread_mutex_lock(&ctx->mutex);
-
- if (ctx->num_threads_connected != 0) {
- h2o_linklist_insert(&ctx->pending, &req->pending);
- pthread_cond_signal(&ctx->cond);
- } else {
- discard_req(req);
- }
-
- pthread_mutex_unlock(&ctx->mutex);
-}
-
-void h2o_memcached_receiver(h2o_multithread_receiver_t *receiver, h2o_linklist_t *messages)
-{
- while (!h2o_linklist_is_empty(messages)) {
- h2o_memcached_req_t *req = H2O_STRUCT_FROM_MEMBER(h2o_memcached_req_t, data.get.message.link, messages->next);
- h2o_linklist_unlink(&req->data.get.message.link);
- assert(req->type == REQ_TYPE_GET);
- if (req->data.get.cb != NULL) {
- if (req->data.get.value_is_encoded && req->data.get.value.len != 0) {
- h2o_iovec_t decoded = h2o_decode_base64url(NULL, req->data.get.value.base, req->data.get.value.len);
- h2o_mem_set_secure(req->data.get.value.base, 0, req->data.get.value.len);
- free(req->data.get.value.base);
- req->data.get.value = decoded;
- }
- req->data.get.cb(req->data.get.value, req->data.get.cb_data);
- }
- free_req(req);
- }
-}
-
-h2o_memcached_req_t *h2o_memcached_get(h2o_memcached_context_t *ctx, h2o_multithread_receiver_t *receiver, h2o_iovec_t key,
- h2o_memcached_get_cb cb, void *cb_data, int flags)
-{
- h2o_memcached_req_t *req = create_req(ctx, REQ_TYPE_GET, key, (flags & H2O_MEMCACHED_ENCODE_KEY) != 0);
- req->data.get.receiver = receiver;
- req->data.get.cb = cb;
- req->data.get.cb_data = cb_data;
- req->data.get.value_is_encoded = (flags & H2O_MEMCACHED_ENCODE_VALUE) != 0;
- dispatch(ctx, req);
- return req;
-}
-
-void h2o_memcached_cancel_get(h2o_memcached_context_t *ctx, h2o_memcached_req_t *req)
-{
- int do_free = 0;
-
- pthread_mutex_lock(&ctx->mutex);
- req->data.get.cb = NULL;
- if (h2o_linklist_is_linked(&req->pending)) {
- h2o_linklist_unlink(&req->pending);
- do_free = 1;
- }
- pthread_mutex_unlock(&ctx->mutex);
-
- if (do_free)
- free_req(req);
-}
-
-void h2o_memcached_set(h2o_memcached_context_t *ctx, h2o_iovec_t key, h2o_iovec_t value, uint32_t expiration, int flags)
-{
- h2o_memcached_req_t *req = create_req(ctx, REQ_TYPE_SET, key, (flags & H2O_MEMCACHED_ENCODE_KEY) != 0);
- if ((flags & H2O_MEMCACHED_ENCODE_VALUE) != 0) {
- req->data.set.value.base = h2o_mem_alloc((value.len + 2) / 3 * 4 + 1);
- req->data.set.value.len = h2o_base64_encode(req->data.set.value.base, value.base, value.len, 1);
- } else {
- req->data.set.value = h2o_iovec_init(h2o_mem_alloc(value.len), value.len);
- memcpy(req->data.set.value.base, value.base, value.len);
- }
- req->data.set.expiration = expiration;
- dispatch(ctx, req);
-}
-
-void h2o_memcached_delete(h2o_memcached_context_t *ctx, h2o_iovec_t key, int flags)
-{
- h2o_memcached_req_t *req = create_req(ctx, REQ_TYPE_DELETE, key, (flags & H2O_MEMCACHED_ENCODE_KEY) != 0);
- dispatch(ctx, req);
-}
-
-h2o_memcached_context_t *h2o_memcached_create_context(const char *host, uint16_t port, int text_protocol, size_t num_threads,
- const char *prefix)
-{
- h2o_memcached_context_t *ctx = h2o_mem_alloc(sizeof(*ctx));
-
- pthread_mutex_init(&ctx->mutex, NULL);
- pthread_cond_init(&ctx->cond, NULL);
- h2o_linklist_init_anchor(&ctx->pending);
- ctx->num_threads_connected = 0;
- ctx->host = h2o_strdup(NULL, host, SIZE_MAX).base;
- ctx->port = port;
- ctx->text_protocol = text_protocol;
- ctx->prefix = h2o_strdup(NULL, prefix, SIZE_MAX);
-
- { /* start the threads */
- pthread_t tid;
- pthread_attr_t attr;
- size_t i;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, 1);
- for (i = 0; i != num_threads; ++i)
- h2o_multithread_create_thread(&tid, &attr, thread_main, ctx);
- pthread_attr_destroy(&attr);
- }
-
- return ctx;
-}
diff --git a/web/server/h2o/libh2o/lib/common/memory.c b/web/server/h2o/libh2o/lib/common/memory.c
deleted file mode 100644
index ba9f2dba2..000000000
--- a/web/server/h2o/libh2o/lib/common/memory.c
+++ /dev/null
@@ -1,400 +0,0 @@
-/*
- * Copyright (c) 2014 DeNA Co., Ltd.
- *
- * 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 <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <unistd.h>
-#include "h2o/memory.h"
-
-#if defined(__linux__)
-#define USE_POSIX_FALLOCATE 1
-#elif __FreeBSD__ >= 9
-#define USE_POSIX_FALLOCATE 1
-#elif __NetBSD__ >= 7
-#define USE_POSIX_FALLOCATE 1
-#else
-#define USE_POSIX_FALLOCATE 0
-#endif
-
-struct st_h2o_mem_recycle_chunk_t {
- struct st_h2o_mem_recycle_chunk_t *next;
-};
-
-struct st_h2o_mem_pool_chunk_t {
- struct st_h2o_mem_pool_chunk_t *next;
- size_t _dummy; /* align to 2*sizeof(void*) */
- char bytes[4096 - sizeof(void *) * 2];
-};
-
-struct st_h2o_mem_pool_direct_t {
- struct st_h2o_mem_pool_direct_t *next;
- size_t _dummy; /* align to 2*sizeof(void*) */
- char bytes[1];
-};
-
-struct st_h2o_mem_pool_shared_ref_t {
- struct st_h2o_mem_pool_shared_ref_t *next;
- struct st_h2o_mem_pool_shared_entry_t *entry;
-};
-
-void *(*h2o_mem__set_secure)(void *, int, size_t) = memset;
-
-static __thread h2o_mem_recycle_t mempool_allocator = {16};
-
-void h2o__fatal(const char *msg)
-{
- fprintf(stderr, "fatal:%s\n", msg);
- abort();
-}
-
-void *h2o_mem_alloc_recycle(h2o_mem_recycle_t *allocator, size_t sz)
-{
- struct st_h2o_mem_recycle_chunk_t *chunk;
- if (allocator->cnt == 0)
- return h2o_mem_alloc(sz);
- /* detach and return the pooled pointer */
- chunk = allocator->_link;
- assert(chunk != NULL);
- allocator->_link = chunk->next;
- --allocator->cnt;
- return chunk;
-}
-
-void h2o_mem_free_recycle(h2o_mem_recycle_t *allocator, void *p)
-{
- struct st_h2o_mem_recycle_chunk_t *chunk;
- if (allocator->cnt == allocator->max) {
- free(p);
- return;
- }
- /* register the pointer to the pool */
- chunk = p;
- chunk->next = allocator->_link;
- allocator->_link = chunk;
- ++allocator->cnt;
-}
-
-void h2o_mem_init_pool(h2o_mem_pool_t *pool)
-{
- pool->chunks = NULL;
- pool->chunk_offset = sizeof(pool->chunks->bytes);
- pool->directs = NULL;
- pool->shared_refs = NULL;
-}
-
-void h2o_mem_clear_pool(h2o_mem_pool_t *pool)
-{
- /* release the refcounted chunks */
- if (pool->shared_refs != NULL) {
- struct st_h2o_mem_pool_shared_ref_t *ref = pool->shared_refs;
- do {
- h2o_mem_release_shared(ref->entry->bytes);
- } while ((ref = ref->next) != NULL);
- pool->shared_refs = NULL;
- }
- /* release the direct chunks */
- if (pool->directs != NULL) {
- struct st_h2o_mem_pool_direct_t *direct = pool->directs, *next;
- do {
- next = direct->next;
- free(direct);
- } while ((direct = next) != NULL);
- pool->directs = NULL;
- }
- /* free chunks, and reset the first chunk */
- while (pool->chunks != NULL) {
- struct st_h2o_mem_pool_chunk_t *next = pool->chunks->next;
- h2o_mem_free_recycle(&mempool_allocator, pool->chunks);
- pool->chunks = next;
- }
- pool->chunk_offset = sizeof(pool->chunks->bytes);
-}
-
-void *h2o_mem_alloc_pool(h2o_mem_pool_t *pool, size_t sz)
-{
- void *ret;
-
- if (sz >= sizeof(pool->chunks->bytes) / 4) {
- /* allocate large requests directly */
- struct st_h2o_mem_pool_direct_t *newp = h2o_mem_alloc(offsetof(struct st_h2o_mem_pool_direct_t, bytes) + sz);
- newp->next = pool->directs;
- pool->directs = newp;
- return newp->bytes;
- }
-
- /* return a valid pointer even for 0 sized allocs */
- if (sz == 0)
- sz = 1;
-
- /* 16-bytes rounding */
- sz = (sz + 15) & ~15;
- if (sizeof(pool->chunks->bytes) - pool->chunk_offset < sz) {
- /* allocate new chunk */
- struct st_h2o_mem_pool_chunk_t *newp = h2o_mem_alloc_recycle(&mempool_allocator, sizeof(*newp));
- newp->next = pool->chunks;
- pool->chunks = newp;
- pool->chunk_offset = 0;
- }
-
- ret = pool->chunks->bytes + pool->chunk_offset;
- pool->chunk_offset += sz;
- return ret;
-}
-
-static void link_shared(h2o_mem_pool_t *pool, struct st_h2o_mem_pool_shared_entry_t *entry)
-{
- struct st_h2o_mem_pool_shared_ref_t *ref = h2o_mem_alloc_pool(pool, sizeof(struct st_h2o_mem_pool_shared_ref_t));
- ref->entry = entry;
- ref->next = pool->shared_refs;
- pool->shared_refs = ref;
-}
-
-void *h2o_mem_alloc_shared(h2o_mem_pool_t *pool, size_t sz, void (*dispose)(void *))
-{
- struct st_h2o_mem_pool_shared_entry_t *entry = h2o_mem_alloc(offsetof(struct st_h2o_mem_pool_shared_entry_t, bytes) + sz);
- entry->refcnt = 1;
- entry->dispose = dispose;
- if (pool != NULL)
- link_shared(pool, entry);
- return entry->bytes;
-}
-
-void h2o_mem_link_shared(h2o_mem_pool_t *pool, void *p)
-{
- h2o_mem_addref_shared(p);
- link_shared(pool, H2O_STRUCT_FROM_MEMBER(struct st_h2o_mem_pool_shared_entry_t, bytes, p));
-}
-
-static size_t topagesize(size_t capacity)
-{
- size_t pagesize = getpagesize();
- return (offsetof(h2o_buffer_t, _buf) + capacity + pagesize - 1) / pagesize * pagesize;
-}
-
-void h2o_buffer__do_free(h2o_buffer_t *buffer)
-{
- /* caller should assert that the buffer is not part of the prototype */
- if (buffer->capacity == buffer->_prototype->_initial_buf.capacity) {
- h2o_mem_free_recycle(&buffer->_prototype->allocator, buffer);
- } else if (buffer->_fd != -1) {
- close(buffer->_fd);
- munmap((void *)buffer, topagesize(buffer->capacity));
- } else {
- free(buffer);
- }
-}
-
-h2o_iovec_t h2o_buffer_reserve(h2o_buffer_t **_inbuf, size_t min_guarantee)
-{
- h2o_buffer_t *inbuf = *_inbuf;
- h2o_iovec_t ret;
-
- if (inbuf->bytes == NULL) {
- h2o_buffer_prototype_t *prototype = H2O_STRUCT_FROM_MEMBER(h2o_buffer_prototype_t, _initial_buf, inbuf);
- if (min_guarantee <= prototype->_initial_buf.capacity) {
- min_guarantee = prototype->_initial_buf.capacity;
- inbuf = h2o_mem_alloc_recycle(&prototype->allocator, offsetof(h2o_buffer_t, _buf) + min_guarantee);
- } else {
- inbuf = h2o_mem_alloc(offsetof(h2o_buffer_t, _buf) + min_guarantee);
- }
- *_inbuf = inbuf;
- inbuf->size = 0;
- inbuf->bytes = inbuf->_buf;
- inbuf->capacity = min_guarantee;
- inbuf->_prototype = prototype;
- inbuf->_fd = -1;
- } else {
- if (min_guarantee <= inbuf->capacity - inbuf->size - (inbuf->bytes - inbuf->_buf)) {
- /* ok */
- } else if ((inbuf->size + min_guarantee) * 2 <= inbuf->capacity) {
- /* the capacity should be less than or equal to 2 times of: size + guarantee */
- memmove(inbuf->_buf, inbuf->bytes, inbuf->size);
- inbuf->bytes = inbuf->_buf;
- } else {
- size_t new_capacity = inbuf->capacity;
- do {
- new_capacity *= 2;
- } while (new_capacity - inbuf->size < min_guarantee);
- if (inbuf->_prototype->mmap_settings != NULL && inbuf->_prototype->mmap_settings->threshold <= new_capacity) {
- size_t new_allocsize = topagesize(new_capacity);
- int fd;
- h2o_buffer_t *newp;
- if (inbuf->_fd == -1) {
- char *tmpfn = alloca(strlen(inbuf->_prototype->mmap_settings->fn_template) + 1);
- strcpy(tmpfn, inbuf->_prototype->mmap_settings->fn_template);
- if ((fd = mkstemp(tmpfn)) == -1) {
- fprintf(stderr, "failed to create temporary file:%s:%s\n", tmpfn, strerror(errno));
- goto MapError;
- }
- unlink(tmpfn);
- } else {
- fd = inbuf->_fd;
- }
- int fallocate_ret;
-#if USE_POSIX_FALLOCATE
- fallocate_ret = posix_fallocate(fd, 0, new_allocsize);
-#else
- fallocate_ret = ftruncate(fd, new_allocsize);
-#endif
- if (fallocate_ret != 0) {
- perror("failed to resize temporary file");
- goto MapError;
- }
- if ((newp = (void *)mmap(NULL, new_allocsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
- perror("mmap failed");
- goto MapError;
- }
- if (inbuf->_fd == -1) {
- /* copy data (moving from malloc to mmap) */
- newp->size = inbuf->size;
- newp->bytes = newp->_buf;
- newp->capacity = new_capacity;
- newp->_prototype = inbuf->_prototype;
- newp->_fd = fd;
- memcpy(newp->_buf, inbuf->bytes, inbuf->size);
- h2o_buffer__do_free(inbuf);
- *_inbuf = inbuf = newp;
- } else {
- /* munmap */
- size_t offset = inbuf->bytes - inbuf->_buf;
- munmap((void *)inbuf, topagesize(inbuf->capacity));
- *_inbuf = inbuf = newp;
- inbuf->capacity = new_capacity;
- inbuf->bytes = newp->_buf + offset;
- }
- } else {
- h2o_buffer_t *newp = h2o_mem_alloc(offsetof(h2o_buffer_t, _buf) + new_capacity);
- newp->size = inbuf->size;
- newp->bytes = newp->_buf;
- newp->capacity = new_capacity;
- newp->_prototype = inbuf->_prototype;
- newp->_fd = -1;
- memcpy(newp->_buf, inbuf->bytes, inbuf->size);
- h2o_buffer__do_free(inbuf);
- *_inbuf = inbuf = newp;
- }
- }
- }
-
- ret.base = inbuf->bytes + inbuf->size;
- ret.len = inbuf->_buf + inbuf->capacity - ret.base;
-
- return ret;
-
-MapError:
- ret.base = NULL;
- ret.len = 0;
- return ret;
-}
-
-void h2o_buffer_consume(h2o_buffer_t **_inbuf, size_t delta)
-{
- h2o_buffer_t *inbuf = *_inbuf;
-
- if (delta != 0) {
- assert(inbuf->bytes != NULL);
- if (inbuf->size == delta) {
- *_inbuf = &inbuf->_prototype->_initial_buf;
- h2o_buffer__do_free(inbuf);
- } else {
- inbuf->size -= delta;
- inbuf->bytes += delta;
- }
- }
-}
-
-void h2o_buffer__dispose_linked(void *p)
-{
- h2o_buffer_t **buf = p;
- h2o_buffer_dispose(buf);
-}
-
-void h2o_vector__expand(h2o_mem_pool_t *pool, h2o_vector_t *vector, size_t element_size, size_t new_capacity)
-{
- void *new_entries;
- assert(vector->capacity < new_capacity);
- if (vector->capacity == 0)
- vector->capacity = 4;
- while (vector->capacity < new_capacity)
- vector->capacity *= 2;
- if (pool != NULL) {
- new_entries = h2o_mem_alloc_pool(pool, element_size * vector->capacity);
- h2o_memcpy(new_entries, vector->entries, element_size * vector->size);
- } else {
- new_entries = h2o_mem_realloc(vector->entries, element_size * vector->capacity);
- }
- vector->entries = new_entries;
-}
-
-void h2o_mem_swap(void *_x, void *_y, size_t len)
-{
- char *x = _x, *y = _y;
- char buf[256];
-
- while (len != 0) {
- size_t blocksz = len < sizeof(buf) ? len : sizeof(buf);
- memcpy(buf, x, blocksz);
- memcpy(x, y, blocksz);
- memcpy(y, buf, blocksz);
- len -= blocksz;
- x += blocksz;
- y += blocksz;
- }
-}
-
-void h2o_dump_memory(FILE *fp, const char *buf, size_t len)
-{
- size_t i, j;
-
- for (i = 0; i < len; i += 16) {
- fprintf(fp, "%08zx", i);
- for (j = 0; j != 16; ++j) {
- if (i + j < len)
- fprintf(fp, " %02x", (int)(unsigned char)buf[i + j]);
- else
- fprintf(fp, " ");
- }
- fprintf(fp, " ");
- for (j = 0; j != 16 && i + j < len; ++j) {
- int ch = buf[i + j];
- fputc(' ' <= ch && ch < 0x7f ? ch : '.', fp);
- }
- fprintf(fp, "\n");
- }
-}
-
-void h2o_append_to_null_terminated_list(void ***list, void *element)
-{
- size_t cnt;
-
- for (cnt = 0; (*list)[cnt] != NULL; ++cnt)
- ;
- *list = h2o_mem_realloc(*list, (cnt + 2) * sizeof(void *));
- (*list)[cnt++] = element;
- (*list)[cnt] = NULL;
-}
diff --git a/web/server/h2o/libh2o/lib/common/multithread.c b/web/server/h2o/libh2o/lib/common/multithread.c
deleted file mode 100644
index b4e8ba836..000000000
--- a/web/server/h2o/libh2o/lib/common/multithread.c
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright (c) 2015-2016 DeNA Co., Ltd., Kazuho Oku, Tatsuhiko Kubo,
- * Chul-Woong Yang
- *
- * 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 <assert.h>
-#include <pthread.h>
-#include "cloexec.h"
-#include "h2o/multithread.h"
-
-struct st_h2o_multithread_queue_t {
-#if H2O_USE_LIBUV
- uv_async_t async;
-#else
- struct {
- int write;
- h2o_socket_t *read;
- } async;
-#endif
- pthread_mutex_t mutex;
- struct {
- h2o_linklist_t active;
- h2o_linklist_t inactive;
- } receivers;
-};
-
-static void queue_cb(h2o_multithread_queue_t *queue)
-{
- pthread_mutex_lock(&queue->mutex);
-
- while (!h2o_linklist_is_empty(&queue->receivers.active)) {
- h2o_multithread_receiver_t *receiver =
- H2O_STRUCT_FROM_MEMBER(h2o_multithread_receiver_t, _link, queue->receivers.active.next);
- /* detach all the messages from the receiver */
- h2o_linklist_t messages;
- h2o_linklist_init_anchor(&messages);
- h2o_linklist_insert_list(&messages, &receiver->_messages);
- /* relink the receiver to the inactive list */
- h2o_linklist_unlink(&receiver->_link);
- h2o_linklist_insert(&queue->receivers.inactive, &receiver->_link);
-
- /* dispatch the messages */
- pthread_mutex_unlock(&queue->mutex);
- receiver->cb(receiver, &messages);
- assert(h2o_linklist_is_empty(&messages));
- pthread_mutex_lock(&queue->mutex);
- }
-
- pthread_mutex_unlock(&queue->mutex);
-}
-
-#ifdef H2O_NO_64BIT_ATOMICS
-pthread_mutex_t h2o_conn_id_mutex = PTHREAD_MUTEX_INITIALIZER;
-#endif
-
-#if H2O_USE_LIBUV
-#else
-
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-static void on_read(h2o_socket_t *sock, const char *err)
-{
- if (err != NULL) {
- fprintf(stderr, "pipe error\n");
- abort();
- }
-
- h2o_buffer_consume(&sock->input, sock->input->size);
- queue_cb(sock->data);
-}
-
-static void init_async(h2o_multithread_queue_t *queue, h2o_loop_t *loop)
-{
- int fds[2];
-
- if (cloexec_pipe(fds) != 0) {
- perror("pipe");
- abort();
- }
- fcntl(fds[1], F_SETFL, O_NONBLOCK);
- queue->async.write = fds[1];
- queue->async.read = h2o_evloop_socket_create(loop, fds[0], 0);
- queue->async.read->data = queue;
- h2o_socket_read_start(queue->async.read, on_read);
-}
-
-#endif
-
-h2o_multithread_queue_t *h2o_multithread_create_queue(h2o_loop_t *loop)
-{
- h2o_multithread_queue_t *queue = h2o_mem_alloc(sizeof(*queue));
- memset(queue, 0, sizeof(*queue));
-
-#if H2O_USE_LIBUV
- uv_async_init(loop, &queue->async, (uv_async_cb)queue_cb);
-#else
- init_async(queue, loop);
-#endif
- pthread_mutex_init(&queue->mutex, NULL);
- h2o_linklist_init_anchor(&queue->receivers.active);
- h2o_linklist_init_anchor(&queue->receivers.inactive);
-
- return queue;
-}
-
-void h2o_multithread_destroy_queue(h2o_multithread_queue_t *queue)
-{
- assert(h2o_linklist_is_empty(&queue->receivers.active));
- assert(h2o_linklist_is_empty(&queue->receivers.inactive));
-#if H2O_USE_LIBUV
- uv_close((uv_handle_t *)&queue->async, (uv_close_cb)free);
-#else
- h2o_socket_read_stop(queue->async.read);
- h2o_socket_close(queue->async.read);
- close(queue->async.write);
-#endif
- pthread_mutex_destroy(&queue->mutex);
-}
-
-void h2o_multithread_register_receiver(h2o_multithread_queue_t *queue, h2o_multithread_receiver_t *receiver,
- h2o_multithread_receiver_cb cb)
-{
- receiver->queue = queue;
- receiver->_link = (h2o_linklist_t){NULL};
- h2o_linklist_init_anchor(&receiver->_messages);
- receiver->cb = cb;
-
- pthread_mutex_lock(&queue->mutex);
- h2o_linklist_insert(&queue->receivers.inactive, &receiver->_link);
- pthread_mutex_unlock(&queue->mutex);
-}
-
-void h2o_multithread_unregister_receiver(h2o_multithread_queue_t *queue, h2o_multithread_receiver_t *receiver)
-{
- assert(queue == receiver->queue);
- assert(h2o_linklist_is_empty(&receiver->_messages));
- pthread_mutex_lock(&queue->mutex);
- h2o_linklist_unlink(&receiver->_link);
- pthread_mutex_unlock(&queue->mutex);
-}
-
-void h2o_multithread_send_message(h2o_multithread_receiver_t *receiver, h2o_multithread_message_t *message)
-{
- int do_send = 0;
-
- pthread_mutex_lock(&receiver->queue->mutex);
- if (message != NULL) {
- assert(!h2o_linklist_is_linked(&message->link));
- if (h2o_linklist_is_empty(&receiver->_messages)) {
- h2o_linklist_unlink(&receiver->_link);
- h2o_linklist_insert(&receiver->queue->receivers.active, &receiver->_link);
- do_send = 1;
- }
- h2o_linklist_insert(&receiver->_messages, &message->link);
- } else {
- if (h2o_linklist_is_empty(&receiver->_messages))
- do_send = 1;
- }
- pthread_mutex_unlock(&receiver->queue->mutex);
-
- if (do_send) {
-#if H2O_USE_LIBUV
- uv_async_send(&receiver->queue->async);
-#else
- while (write(receiver->queue->async.write, "", 1) == -1 && errno == EINTR)
- ;
-#endif
- }
-}
-
-void h2o_multithread_create_thread(pthread_t *tid, const pthread_attr_t *attr, void *(*func)(void *), void *arg)
-{
- if (pthread_create(tid, attr, func, arg) != 0) {
- perror("pthread_create");
- abort();
- }
-}
-
-void h2o_sem_init(h2o_sem_t *sem, ssize_t capacity)
-{
- pthread_mutex_init(&sem->_mutex, NULL);
- pthread_cond_init(&sem->_cond, NULL);
- sem->_cur = capacity;
- sem->_capacity = capacity;
-}
-
-void h2o_sem_destroy(h2o_sem_t *sem)
-{
- assert(sem->_cur == sem->_capacity);
- pthread_cond_destroy(&sem->_cond);
- pthread_mutex_destroy(&sem->_mutex);
-}
-
-void h2o_sem_wait(h2o_sem_t *sem)
-{
- pthread_mutex_lock(&sem->_mutex);
- while (sem->_cur <= 0)
- pthread_cond_wait(&sem->_cond, &sem->_mutex);
- --sem->_cur;
- pthread_mutex_unlock(&sem->_mutex);
-}
-
-void h2o_sem_post(h2o_sem_t *sem)
-{
- pthread_mutex_lock(&sem->_mutex);
- ++sem->_cur;
- pthread_cond_signal(&sem->_cond);
- pthread_mutex_unlock(&sem->_mutex);
-}
-
-void h2o_sem_set_capacity(h2o_sem_t *sem, ssize_t new_capacity)
-{
- pthread_mutex_lock(&sem->_mutex);
- sem->_cur += new_capacity - sem->_capacity;
- sem->_capacity = new_capacity;
- pthread_cond_broadcast(&sem->_cond);
- pthread_mutex_unlock(&sem->_mutex);
-}
-
-/* barrier */
-
-void h2o_barrier_init(h2o_barrier_t *barrier, size_t count)
-{
- pthread_mutex_init(&barrier->_mutex, NULL);
- pthread_cond_init(&barrier->_cond, NULL);
- barrier->_count = count;
-}
-
-int h2o_barrier_wait(h2o_barrier_t *barrier)
-{
- int ret;
- pthread_mutex_lock(&barrier->_mutex);
- barrier->_count--;
- if (barrier->_count == 0) {
- pthread_cond_broadcast(&barrier->_cond);
- ret = 1;
- } else {
- while (barrier->_count)
- pthread_cond_wait(&barrier->_cond, &barrier->_mutex);
- ret = 0;
- }
- pthread_mutex_unlock(&barrier->_mutex);
- return ret;
-}
-
-int h2o_barrier_done(h2o_barrier_t *barrier)
-{
- return __sync_add_and_fetch(&barrier->_count, 0) == 0;
-}
-
-void h2o_barrier_destroy(h2o_barrier_t *barrier)
-{
- pthread_mutex_destroy(&barrier->_mutex);
- pthread_cond_destroy(&barrier->_cond);
-}
diff --git a/web/server/h2o/libh2o/lib/common/serverutil.c b/web/server/h2o/libh2o/lib/common/serverutil.c
deleted file mode 100644
index 8226f6efc..000000000
--- a/web/server/h2o/libh2o/lib/common/serverutil.c
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku, Nick Desaulniers
- *
- * 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 <errno.h>
-#include <fcntl.h>
-#include <grp.h>
-#include <pthread.h>
-#include <pwd.h>
-#include <signal.h>
-#include <spawn.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#if !defined(_SC_NPROCESSORS_ONLN)
-#include <sys/sysctl.h>
-#endif
-#include "cloexec.h"
-#include "h2o/memory.h"
-#include "h2o/serverutil.h"
-#include "h2o/socket.h"
-#include "h2o/string_.h"
-
-void h2o_set_signal_handler(int signo, void (*cb)(int signo))
-{
- struct sigaction action;
-
- memset(&action, 0, sizeof(action));
- sigemptyset(&action.sa_mask);
- action.sa_handler = cb;
- sigaction(signo, &action, NULL);
-}
-
-int h2o_setuidgid(const char *user)
-{
- struct passwd pwbuf, *pw;
- char buf[65536]; /* should be large enough */
-
- errno = 0;
- if (getpwnam_r(user, &pwbuf, buf, sizeof(buf), &pw) != 0) {
- perror("getpwnam_r");
- return -1;
- }
- if (pw == NULL) {
- fprintf(stderr, "unknown user:%s\n", user);
- return -1;
- }
- if (setgid(pw->pw_gid) != 0) {
- fprintf(stderr, "setgid(%d) failed:%s\n", (int)pw->pw_gid, strerror(errno));
- return -1;
- }
- if (initgroups(pw->pw_name, pw->pw_gid) != 0) {
- fprintf(stderr, "initgroups(%s, %d) failed:%s\n", pw->pw_name, (int)pw->pw_gid, strerror(errno));
- return -1;
- }
- if (setuid(pw->pw_uid) != 0) {
- fprintf(stderr, "setuid(%d) failed:%s\n", (int)pw->pw_uid, strerror(errno));
- return -1;
- }
-
- return 0;
-}
-
-size_t h2o_server_starter_get_fds(int **_fds)
-{
- const char *ports_env, *start, *end, *eq;
- size_t t;
- H2O_VECTOR(int) fds = {NULL};
-
- if ((ports_env = getenv("SERVER_STARTER_PORT")) == NULL)
- return 0;
- if (ports_env[0] == '\0') {
- fprintf(stderr, "$SERVER_STARTER_PORT is empty\n");
- return SIZE_MAX;
- }
-
- /* ports_env example: 127.0.0.1:80=3;/tmp/sock=4 */
- for (start = ports_env; *start != '\0'; start = *end == ';' ? end + 1 : end) {
- if ((end = strchr(start, ';')) == NULL)
- end = start + strlen(start);
- if ((eq = memchr(start, '=', end - start)) == NULL) {
- fprintf(stderr, "invalid $SERVER_STARTER_PORT, an element without `=` in: %s\n", ports_env);
- goto Error;
- }
- if ((t = h2o_strtosize(eq + 1, end - eq - 1)) == SIZE_MAX) {
- fprintf(stderr, "invalid file descriptor number in $SERVER_STARTER_PORT: %s\n", ports_env);
- goto Error;
- }
- h2o_vector_reserve(NULL, &fds, fds.size + 1);
- fds.entries[fds.size++] = (int)t;
- }
-
- *_fds = fds.entries;
- return fds.size;
-Error:
- free(fds.entries);
- return SIZE_MAX;
-}
-
-static char **build_spawn_env(void)
-{
- extern char **environ;
- size_t num;
-
- /* calculate number of envvars, as well as looking for H2O_ROOT= */
- for (num = 0; environ[num] != NULL; ++num)
- if (strncmp(environ[num], "H2O_ROOT=", sizeof("H2O_ROOT=") - 1) == 0)
- return NULL;
-
- /* not found */
- char **newenv = h2o_mem_alloc(sizeof(*newenv) * (num + 2) + sizeof("H2O_ROOT=" H2O_TO_STR(H2O_ROOT)));
- memcpy(newenv, environ, sizeof(*newenv) * num);
- newenv[num] = (char *)(newenv + num + 2);
- newenv[num + 1] = NULL;
- strcpy(newenv[num], "H2O_ROOT=" H2O_TO_STR(H2O_ROOT));
-
- return newenv;
-}
-
-pid_t h2o_spawnp(const char *cmd, char *const *argv, const int *mapped_fds, int cloexec_mutex_is_locked)
-{
-#if defined(__linux__)
-
- /* posix_spawnp of Linux does not return error if the executable does not exist, see
- * https://gist.github.com/kazuho/0c233e6f86d27d6e4f09
- */
- extern char **environ;
- int pipefds[2] = {-1, -1}, errnum;
- pid_t pid;
-
- /* create pipe, used for sending error codes */
- if (pipe2(pipefds, O_CLOEXEC) != 0)
- goto Error;
-
- /* fork */
- if (!cloexec_mutex_is_locked)
- pthread_mutex_lock(&cloexec_mutex);
- if ((pid = fork()) == 0) {
- /* in child process, map the file descriptors and execute; return the errnum through pipe if exec failed */
- if (mapped_fds != NULL) {
- for (; *mapped_fds != -1; mapped_fds += 2) {
- if (mapped_fds[0] != mapped_fds[1]) {
- if (mapped_fds[1] != -1)
- dup2(mapped_fds[0], mapped_fds[1]);
- close(mapped_fds[0]);
- }
- }
- }
- char **env = build_spawn_env();
- if (env != NULL)
- environ = env;
- execvp(cmd, argv);
- errnum = errno;
- write(pipefds[1], &errnum, sizeof(errnum));
- _exit(EX_SOFTWARE);
- }
- if (!cloexec_mutex_is_locked)
- pthread_mutex_unlock(&cloexec_mutex);
- if (pid == -1)
- goto Error;
-
- /* parent process */
- close(pipefds[1]);
- pipefds[1] = -1;
- ssize_t rret;
- errnum = 0;
- while ((rret = read(pipefds[0], &errnum, sizeof(errnum))) == -1 && errno == EINTR)
- ;
- if (rret != 0) {
- /* spawn failed */
- while (waitpid(pid, NULL, 0) != pid)
- ;
- pid = -1;
- errno = errnum;
- goto Error;
- }
-
- /* spawn succeeded */
- close(pipefds[0]);
- return pid;
-
-Error:
- errnum = errno;
- if (pipefds[0] != -1)
- close(pipefds[0]);
- if (pipefds[1] != -1)
- close(pipefds[1]);
- errno = errnum;
- return -1;
-
-#else
-
- posix_spawn_file_actions_t file_actions;
- pid_t pid;
- extern char **environ;
- char **env = build_spawn_env();
- posix_spawn_file_actions_init(&file_actions);
- if (mapped_fds != NULL) {
- for (; *mapped_fds != -1; mapped_fds += 2) {
- if (mapped_fds[1] != -1)
- posix_spawn_file_actions_adddup2(&file_actions, mapped_fds[0], mapped_fds[1]);
- posix_spawn_file_actions_addclose(&file_actions, mapped_fds[0]);
- }
- }
- if (!cloexec_mutex_is_locked)
- pthread_mutex_lock(&cloexec_mutex);
- errno = posix_spawnp(&pid, cmd, &file_actions, NULL, argv, env != NULL ? env : environ);
- if (!cloexec_mutex_is_locked)
- pthread_mutex_unlock(&cloexec_mutex);
- free(env);
- if (errno != 0)
- return -1;
-
- return pid;
-
-#endif
-}
-
-int h2o_read_command(const char *cmd, char **argv, h2o_buffer_t **resp, int *child_status)
-{
- int respfds[2] = {-1, -1};
- pid_t pid = -1;
- int mutex_locked = 0, ret = -1;
-
- h2o_buffer_init(resp, &h2o_socket_buffer_prototype);
-
- pthread_mutex_lock(&cloexec_mutex);
- mutex_locked = 1;
-
- /* create pipe for reading the result */
- if (pipe(respfds) != 0)
- goto Exit;
- if (fcntl(respfds[0], F_SETFD, O_CLOEXEC) < 0)
- goto Exit;
-
- /* spawn */
- int mapped_fds[] = {respfds[1], 1, /* stdout of the child process is read from the pipe */
- -1};
- if ((pid = h2o_spawnp(cmd, argv, mapped_fds, 1)) == -1)
- goto Exit;
- close(respfds[1]);
- respfds[1] = -1;
-
- pthread_mutex_unlock(&cloexec_mutex);
- mutex_locked = 0;
-
- /* read the response from pipe */
- while (1) {
- h2o_iovec_t buf = h2o_buffer_reserve(resp, 8192);
- ssize_t r;
- while ((r = read(respfds[0], buf.base, buf.len)) == -1 && errno == EINTR)
- ;
- if (r <= 0)
- break;
- (*resp)->size += r;
- }
-
-Exit:
- if (mutex_locked)
- pthread_mutex_unlock(&cloexec_mutex);
- if (pid != -1) {
- /* wait for the child to complete */
- pid_t r;
- while ((r = waitpid(pid, child_status, 0)) == -1 && errno == EINTR)
- ;
- if (r == pid) {
- /* success */
- ret = 0;
- }
- }
- if (respfds[0] != -1)
- close(respfds[0]);
- if (respfds[1] != -1)
- close(respfds[1]);
- if (ret != 0)
- h2o_buffer_dispose(resp);
-
- return ret;
-}
-
-size_t h2o_numproc(void)
-{
-#if defined(_SC_NPROCESSORS_ONLN)
- return (size_t)sysconf(_SC_NPROCESSORS_ONLN);
-#elif defined(CTL_HW) && defined(HW_AVAILCPU)
- int name[] = {CTL_HW, HW_AVAILCPU};
- int ncpu;
- size_t ncpu_sz = sizeof(ncpu);
- if (sysctl(name, sizeof(name) / sizeof(name[0]), &ncpu, &ncpu_sz, NULL, 0) != 0 || sizeof(ncpu) != ncpu_sz) {
- fprintf(stderr, "[ERROR] failed to obtain number of CPU cores, assuming as one\n");
- ncpu = 1;
- }
- return ncpu;
-#else
- return 1;
-#endif
-}
diff --git a/web/server/h2o/libh2o/lib/common/socket.c b/web/server/h2o/libh2o/lib/common/socket.c
deleted file mode 100644
index 5b1c37e04..000000000
--- a/web/server/h2o/libh2o/lib/common/socket.c
+++ /dev/null
@@ -1,1433 +0,0 @@
-/*
- * Copyright (c) 2015 DeNA Co., Ltd., Kazuho Oku, Justin Zhu
- *
- * 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 <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <string.h>
-#include <sys/un.h>
-#include <unistd.h>
-#include <openssl/err.h>
-#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
-#include <sys/ioctl.h>
-#endif
-#if H2O_USE_PICOTLS
-#include "picotls.h"
-#endif
-#include "h2o/socket.h"
-#include "h2o/timeout.h"
-
-#if defined(__APPLE__) && defined(__clang__)
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
-#endif
-
-#ifndef IOV_MAX
-#define IOV_MAX UIO_MAXIOV
-#endif
-
-/* kernel-headers bundled with Ubuntu 14.04 does not have the constant defined in netinet/tcp.h */
-#if defined(__linux__) && !defined(TCP_NOTSENT_LOWAT)
-#define TCP_NOTSENT_LOWAT 25
-#endif
-
-#define OPENSSL_HOSTNAME_VALIDATION_LINKAGE static
-#include "../../deps/ssl-conservatory/openssl/openssl_hostname_validation.c"
-
-struct st_h2o_socket_ssl_t {
- SSL_CTX *ssl_ctx;
- SSL *ossl;
-#if H2O_USE_PICOTLS
- ptls_t *ptls;
-#endif
- int *did_write_in_read; /* used for detecting and closing the connection upon renegotiation (FIXME implement renegotiation) */
- size_t record_overhead;
- struct {
- h2o_socket_cb cb;
- union {
- struct {
- struct {
- enum {
- ASYNC_RESUMPTION_STATE_COMPLETE = 0, /* just pass thru */
- ASYNC_RESUMPTION_STATE_RECORD, /* record first input, restore SSL state if it changes to REQUEST_SENT
- */
- ASYNC_RESUMPTION_STATE_REQUEST_SENT /* async request has been sent, and is waiting for response */
- } state;
- SSL_SESSION *session_data;
- } async_resumption;
- } server;
- struct {
- char *server_name;
- h2o_cache_t *session_cache;
- h2o_iovec_t session_cache_key;
- h2o_cache_hashcode_t session_cache_key_hash;
- } client;
- };
- } handshake;
- struct {
- h2o_buffer_t *encrypted;
- } input;
- struct {
- H2O_VECTOR(h2o_iovec_t) bufs;
- h2o_mem_pool_t pool; /* placed at the last */
- } output;
-};
-
-struct st_h2o_ssl_context_t {
- SSL_CTX *ctx;
- const h2o_iovec_t *protocols;
- h2o_iovec_t _npn_list_of_protocols;
-};
-
-/* backend functions */
-static void do_dispose_socket(h2o_socket_t *sock);
-static void do_write(h2o_socket_t *sock, h2o_iovec_t *bufs, size_t bufcnt, h2o_socket_cb cb);
-static void do_read_start(h2o_socket_t *sock);
-static void do_read_stop(h2o_socket_t *sock);
-static int do_export(h2o_socket_t *_sock, h2o_socket_export_t *info);
-static h2o_socket_t *do_import(h2o_loop_t *loop, h2o_socket_export_t *info);
-static socklen_t get_peername_uncached(h2o_socket_t *sock, struct sockaddr *sa);
-
-/* internal functions called from the backend */
-static const char *decode_ssl_input(h2o_socket_t *sock);
-static void on_write_complete(h2o_socket_t *sock, const char *err);
-
-#if H2O_USE_LIBUV
-#include "socket/uv-binding.c.h"
-#else
-#include "socket/evloop.c.h"
-#endif
-
-h2o_buffer_mmap_settings_t h2o_socket_buffer_mmap_settings = {
- 32 * 1024 * 1024, /* 32MB, should better be greater than max frame size of HTTP2 for performance reasons */
- "/tmp/h2o.b.XXXXXX"};
-
-__thread h2o_buffer_prototype_t h2o_socket_buffer_prototype = {
- {16}, /* keep 16 recently used chunks */
- {H2O_SOCKET_INITIAL_INPUT_BUFFER_SIZE * 2}, /* minimum initial capacity */
- &h2o_socket_buffer_mmap_settings};
-
-const char *h2o_socket_error_out_of_memory = "out of memory";
-const char *h2o_socket_error_io = "I/O error";
-const char *h2o_socket_error_closed = "socket closed by peer";
-const char *h2o_socket_error_conn_fail = "connection failure";
-const char *h2o_socket_error_ssl_no_cert = "no certificate";
-const char *h2o_socket_error_ssl_cert_invalid = "invalid certificate";
-const char *h2o_socket_error_ssl_cert_name_mismatch = "certificate name mismatch";
-const char *h2o_socket_error_ssl_decode = "SSL decode error";
-
-static void (*resumption_get_async)(h2o_socket_t *sock, h2o_iovec_t session_id);
-static void (*resumption_new)(h2o_iovec_t session_id, h2o_iovec_t session_data);
-
-static int read_bio(BIO *b, char *out, int len)
-{
- h2o_socket_t *sock = BIO_get_data(b);
-
- if (len == 0)
- return 0;
-
- if (sock->ssl->input.encrypted->size == 0) {
- BIO_set_retry_read(b);
- return -1;
- }
-
- if (sock->ssl->input.encrypted->size < len) {
- len = (int)sock->ssl->input.encrypted->size;
- }
- memcpy(out, sock->ssl->input.encrypted->bytes, len);
- h2o_buffer_consume(&sock->ssl->input.encrypted, len);
-
- return len;
-}
-
-static void write_ssl_bytes(h2o_socket_t *sock, const void *in, size_t len)
-{
- if (len != 0) {
- void *bytes_alloced = h2o_mem_alloc_pool(&sock->ssl->output.pool, len);
- memcpy(bytes_alloced, in, len);
- h2o_vector_reserve(&sock->ssl->output.pool, &sock->ssl->output.bufs, sock->ssl->output.bufs.size + 1);
- sock->ssl->output.bufs.entries[sock->ssl->output.bufs.size++] = h2o_iovec_init(bytes_alloced, len);
- }
-}
-
-static int write_bio(BIO *b, const char *in, int len)
-{
- h2o_socket_t *sock = BIO_get_data(b);
-
- /* FIXME no support for SSL renegotiation (yet) */
- if (sock->ssl->did_write_in_read != NULL) {
- *sock->ssl->did_write_in_read = 1;
- return -1;
- }
-
- write_ssl_bytes(sock, in, len);
- return len;
-}
-
-static int puts_bio(BIO *b, const char *str)
-{
- return write_bio(b, str, (int)strlen(str));
-}
-
-static long ctrl_bio(BIO *b, int cmd, long num, void *ptr)
-{
- switch (cmd) {
- case BIO_CTRL_GET_CLOSE:
- return BIO_get_shutdown(b);
- case BIO_CTRL_SET_CLOSE:
- BIO_set_shutdown(b, (int)num);
- return 1;
- case BIO_CTRL_FLUSH:
- return 1;
- default:
- return 0;
- }
-}
-
-static void setup_bio(h2o_socket_t *sock)
-{
- static BIO_METHOD *bio_methods = NULL;
- if (bio_methods == NULL) {
- static pthread_mutex_t init_lock = PTHREAD_MUTEX_INITIALIZER;
- pthread_mutex_lock(&init_lock);
- if (bio_methods == NULL) {
- BIO_METHOD *biom = BIO_meth_new(BIO_TYPE_FD, "h2o_socket");
- BIO_meth_set_write(biom, write_bio);
- BIO_meth_set_read(biom, read_bio);
- BIO_meth_set_puts(biom, puts_bio);
- BIO_meth_set_ctrl(biom, ctrl_bio);
- __sync_synchronize();
- bio_methods = biom;
- }
- pthread_mutex_unlock(&init_lock);
- }
-
- BIO *bio = BIO_new(bio_methods);
- if (bio == NULL)
- h2o_fatal("no memory");
- BIO_set_data(bio, sock);
- BIO_set_init(bio, 1);
- SSL_set_bio(sock->ssl->ossl, bio, bio);
-}
-
-const char *decode_ssl_input(h2o_socket_t *sock)
-{
- assert(sock->ssl != NULL);
- assert(sock->ssl->handshake.cb == NULL);
-
-#if H2O_USE_PICOTLS
- if (sock->ssl->ptls != NULL) {
- if (sock->ssl->input.encrypted->size != 0) {
- const char *src = sock->ssl->input.encrypted->bytes, *src_end = src + sock->ssl->input.encrypted->size;
- h2o_iovec_t reserved;
- ptls_buffer_t rbuf;
- int ret;
- if ((reserved = h2o_buffer_reserve(&sock->input, sock->ssl->input.encrypted->size)).base == NULL)
- return h2o_socket_error_out_of_memory;
- ptls_buffer_init(&rbuf, reserved.base, reserved.len);
- do {
- size_t consumed = src_end - src;
- if ((ret = ptls_receive(sock->ssl->ptls, &rbuf, src, &consumed)) != 0)
- break;
- src += consumed;
- } while (src != src_end);
- h2o_buffer_consume(&sock->ssl->input.encrypted, sock->ssl->input.encrypted->size - (src_end - src));
- if (rbuf.is_allocated) {
- if ((reserved = h2o_buffer_reserve(&sock->input, rbuf.off)).base == NULL)
- return h2o_socket_error_out_of_memory;
- memcpy(reserved.base, rbuf.base, rbuf.off);
- sock->input->size += rbuf.off;
- ptls_buffer_dispose(&rbuf);
- } else {
- sock->input->size += rbuf.off;
- }
- if (!(ret == 0 || ret == PTLS_ERROR_IN_PROGRESS))
- return h2o_socket_error_ssl_decode;
- }
- return NULL;
- }
-#endif
-
- while (sock->ssl->input.encrypted->size != 0 || SSL_pending(sock->ssl->ossl)) {
- int rlen;
- h2o_iovec_t buf = h2o_buffer_reserve(&sock->input, 4096);
- if (buf.base == NULL)
- return h2o_socket_error_out_of_memory;
- { /* call SSL_read (while detecting SSL renegotiation and reporting it as error) */
- int did_write_in_read = 0;
- sock->ssl->did_write_in_read = &did_write_in_read;
- ERR_clear_error();
- rlen = SSL_read(sock->ssl->ossl, buf.base, (int)buf.len);
- sock->ssl->did_write_in_read = NULL;
- if (did_write_in_read)
- return "ssl renegotiation not supported";
- }
- if (rlen == -1) {
- if (SSL_get_error(sock->ssl->ossl, rlen) != SSL_ERROR_WANT_READ) {
- return h2o_socket_error_ssl_decode;
- }
- break;
- } else if (rlen == 0) {
- break;
- } else {
- sock->input->size += rlen;
- }
- }
-
- return 0;
-}
-
-static void flush_pending_ssl(h2o_socket_t *sock, h2o_socket_cb cb)
-{
- do_write(sock, sock->ssl->output.bufs.entries, sock->ssl->output.bufs.size, cb);
-}
-
-static void clear_output_buffer(struct st_h2o_socket_ssl_t *ssl)
-{
- memset(&ssl->output.bufs, 0, sizeof(ssl->output.bufs));
- h2o_mem_clear_pool(&ssl->output.pool);
-}
-
-static void destroy_ssl(struct st_h2o_socket_ssl_t *ssl)
-{
-#if H2O_USE_PICOTLS
- if (ssl->ptls != NULL) {
- ptls_free(ssl->ptls);
- ssl->ptls = NULL;
- }
-#endif
- if (ssl->ossl != NULL) {
- if (!SSL_is_server(ssl->ossl)) {
- free(ssl->handshake.client.server_name);
- free(ssl->handshake.client.session_cache_key.base);
- }
- SSL_free(ssl->ossl);
- ssl->ossl = NULL;
- }
- h2o_buffer_dispose(&ssl->input.encrypted);
- clear_output_buffer(ssl);
- free(ssl);
-}
-
-static void dispose_socket(h2o_socket_t *sock, const char *err)
-{
- void (*close_cb)(void *data);
- void *close_cb_data;
-
- if (sock->ssl != NULL) {
- destroy_ssl(sock->ssl);
- sock->ssl = NULL;
- }
- h2o_buffer_dispose(&sock->input);
- if (sock->_peername != NULL) {
- free(sock->_peername);
- sock->_peername = NULL;
- }
-
- close_cb = sock->on_close.cb;
- close_cb_data = sock->on_close.data;
-
- do_dispose_socket(sock);
-
- if (close_cb != NULL)
- close_cb(close_cb_data);
-}
-
-static void shutdown_ssl(h2o_socket_t *sock, const char *err)
-{
- int ret;
-
- if (err != NULL)
- goto Close;
-
- if (sock->_cb.write != NULL) {
- /* note: libuv calls the write callback after the socket is closed by uv_close (with status set to 0 if the write succeeded)
- */
- sock->_cb.write = NULL;
- goto Close;
- }
-
-#if H2O_USE_PICOTLS
- if (sock->ssl->ptls != NULL) {
- ptls_buffer_t wbuf;
- uint8_t wbuf_small[32];
- ptls_buffer_init(&wbuf, wbuf_small, sizeof(wbuf_small));
- if ((ret = ptls_send_alert(sock->ssl->ptls, &wbuf, PTLS_ALERT_LEVEL_WARNING, PTLS_ALERT_CLOSE_NOTIFY)) != 0)
- goto Close;
- write_ssl_bytes(sock, wbuf.base, wbuf.off);
- ptls_buffer_dispose(&wbuf);
- ret = 1; /* close the socket after sending close_notify */
- } else
-#endif
- if (sock->ssl->ossl != NULL) {
- ERR_clear_error();
- if ((ret = SSL_shutdown(sock->ssl->ossl)) == -1)
- goto Close;
- } else {
- goto Close;
- }
-
- if (sock->ssl->output.bufs.size != 0) {
- h2o_socket_read_stop(sock);
- flush_pending_ssl(sock, ret == 1 ? dispose_socket : shutdown_ssl);
- } else if (ret == 2 && SSL_get_error(sock->ssl->ossl, ret) == SSL_ERROR_WANT_READ) {
- h2o_socket_read_start(sock, shutdown_ssl);
- } else {
- goto Close;
- }
-
- return;
-Close:
- dispose_socket(sock, err);
-}
-
-void h2o_socket_dispose_export(h2o_socket_export_t *info)
-{
- assert(info->fd != -1);
- if (info->ssl != NULL) {
- destroy_ssl(info->ssl);
- info->ssl = NULL;
- }
- h2o_buffer_dispose(&info->input);
- close(info->fd);
- info->fd = -1;
-}
-
-int h2o_socket_export(h2o_socket_t *sock, h2o_socket_export_t *info)
-{
- static h2o_buffer_prototype_t nonpooling_prototype;
-
- assert(!h2o_socket_is_writing(sock));
-
- if (do_export(sock, info) == -1)
- return -1;
-
- if ((info->ssl = sock->ssl) != NULL) {
- sock->ssl = NULL;
- h2o_buffer_set_prototype(&info->ssl->input.encrypted, &nonpooling_prototype);
- }
- info->input = sock->input;
- h2o_buffer_set_prototype(&info->input, &nonpooling_prototype);
- h2o_buffer_init(&sock->input, &h2o_socket_buffer_prototype);
-
- h2o_socket_close(sock);
-
- return 0;
-}
-
-h2o_socket_t *h2o_socket_import(h2o_loop_t *loop, h2o_socket_export_t *info)
-{
- h2o_socket_t *sock;
-
- assert(info->fd != -1);
-
- sock = do_import(loop, info);
- info->fd = -1; /* just in case */
- if ((sock->ssl = info->ssl) != NULL) {
- setup_bio(sock);
- h2o_buffer_set_prototype(&sock->ssl->input.encrypted, &h2o_socket_buffer_prototype);
- }
- sock->input = info->input;
- h2o_buffer_set_prototype(&sock->input, &h2o_socket_buffer_prototype);
- return sock;
-}
-
-void h2o_socket_close(h2o_socket_t *sock)
-{
- if (sock->ssl == NULL) {
- dispose_socket(sock, 0);
- } else {
- shutdown_ssl(sock, 0);
- }
-}
-
-static uint16_t calc_suggested_tls_payload_size(h2o_socket_t *sock, uint16_t suggested_tls_record_size)
-{
- uint16_t ps = suggested_tls_record_size;
- if (sock->ssl != NULL && sock->ssl->record_overhead < ps)
- ps -= sock->ssl->record_overhead;
- return ps;
-}
-
-static void disable_latency_optimized_write(h2o_socket_t *sock, int (*adjust_notsent_lowat)(h2o_socket_t *, unsigned))
-{
- if (sock->_latency_optimization.notsent_is_minimized) {
- adjust_notsent_lowat(sock, 0);
- sock->_latency_optimization.notsent_is_minimized = 0;
- }
- sock->_latency_optimization.state = H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_DISABLED;
- sock->_latency_optimization.suggested_tls_payload_size = 16384;
- sock->_latency_optimization.suggested_write_size = SIZE_MAX;
-}
-
-static inline void prepare_for_latency_optimized_write(h2o_socket_t *sock,
- const h2o_socket_latency_optimization_conditions_t *conditions, uint32_t rtt,
- uint32_t mss, uint32_t cwnd_size, uint32_t cwnd_avail, uint64_t loop_time,
- int (*adjust_notsent_lowat)(h2o_socket_t *, unsigned))
-{
- /* check RTT */
- if (rtt < conditions->min_rtt * (uint64_t)1000)
- goto Disable;
- if (rtt * conditions->max_additional_delay < loop_time * 1000 * 100)
- goto Disable;
-
- /* latency-optimization is enabled */
- sock->_latency_optimization.state = H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_DETERMINED;
-
- /* no need to:
- * 1) adjust the write size if single_write_size << cwnd_size
- * 2) align TLS record boundary to TCP packet boundary if packet loss-rate is low and BW isn't small (implied by cwnd size)
- */
- if (mss * cwnd_size < conditions->max_cwnd) {
- if (!sock->_latency_optimization.notsent_is_minimized) {
- if (adjust_notsent_lowat(sock, 1 /* cannot be set to zero on Linux */) != 0)
- goto Disable;
- sock->_latency_optimization.notsent_is_minimized = 1;
- }
- sock->_latency_optimization.suggested_tls_payload_size = calc_suggested_tls_payload_size(sock, mss);
- sock->_latency_optimization.suggested_write_size =
- cwnd_avail * (size_t)sock->_latency_optimization.suggested_tls_payload_size;
- } else {
- if (sock->_latency_optimization.notsent_is_minimized) {
- if (adjust_notsent_lowat(sock, 0) != 0)
- goto Disable;
- sock->_latency_optimization.notsent_is_minimized = 0;
- }
- sock->_latency_optimization.suggested_tls_payload_size = 16384;
- sock->_latency_optimization.suggested_write_size = SIZE_MAX;
- }
- return;
-
-Disable:
- disable_latency_optimized_write(sock, adjust_notsent_lowat);
-}
-
-/**
- * Obtains RTT, MSS, size of CWND (in the number of packets).
- * Also writes to cwnd_avail minimum number of packets (of MSS size) sufficient to shut up poll-for-write under the precondition
- * that TCP_NOTSENT_LOWAT is set to 1.
- */
-static int obtain_tcp_info(int fd, uint32_t *rtt, uint32_t *mss, uint32_t *cwnd_size, uint32_t *cwnd_avail)
-{
-#define CALC_CWND_PAIR_FROM_BYTE_UNITS(cwnd_bytes, inflight_bytes) \
- do { \
- *cwnd_size = (cwnd_bytes + *mss / 2) / *mss; \
- *cwnd_avail = cwnd_bytes > inflight_bytes ? (cwnd_bytes - inflight_bytes) / *mss + 2 : 2; \
- } while (0)
-
-#if defined(__linux__) && defined(TCP_INFO)
-
- struct tcp_info tcpi;
- socklen_t tcpisz = sizeof(tcpi);
- if (getsockopt(fd, IPPROTO_TCP, TCP_INFO, &tcpi, &tcpisz) != 0)
- return -1;
- *rtt = tcpi.tcpi_rtt;
- *mss = tcpi.tcpi_snd_mss;
- *cwnd_size = tcpi.tcpi_snd_cwnd;
- *cwnd_avail = tcpi.tcpi_snd_cwnd > tcpi.tcpi_unacked ? tcpi.tcpi_snd_cwnd - tcpi.tcpi_unacked + 2 : 2;
- return 0;
-
-#elif defined(__FreeBSD__) && defined(TCP_INFO) && 0 /* disabled since we wouldn't use it anyways; OS lacks TCP_NOTSENT_LOWAT */
-
- struct tcp_info tcpi;
- socklen_t tcpisz = sizeof(tcpi);
- int bytes_inflight;
- if (getsockopt(fd, IPPROTO_TCP, TCP_INFO, &tcpi, &tcpisz) != 0 || ioctl(fd, FIONWRITE, &bytes_inflight) == -1)
- return -1;
- *rtt = tcpi.tcpi_rtt;
- *mss = tcpi.tcpi_snd_mss;
- CALC_CWND_PAIR_FROM_BYTE_UNITS(tcpi.tcpi_snd_cwnd, bytes_inflight);
- return 0;
-
-#elif defined(__APPLE__) && defined(TCP_CONNECTION_INFO)
-
- struct tcp_connection_info tcpi;
- socklen_t tcpisz = sizeof(tcpi);
- if (getsockopt(fd, IPPROTO_TCP, TCP_CONNECTION_INFO, &tcpi, &tcpisz) != 0 || tcpi.tcpi_maxseg == 0)
- return -1;
- *rtt = tcpi.tcpi_srtt * 1000;
- *mss = tcpi.tcpi_maxseg;
- CALC_CWND_PAIR_FROM_BYTE_UNITS(tcpi.tcpi_snd_cwnd, tcpi.tcpi_snd_sbbytes);
- return 0;
-
-#else
- /* TODO add support for NetBSD; note that the OS returns the number of packets for tcpi_snd_cwnd; see
- * http://twitter.com/n_soda/status/740719125878575105
- */
- return -1;
-#endif
-
-#undef CALC_CWND_PAIR_FROM_BYTE_UNITS
-}
-
-#ifdef TCP_NOTSENT_LOWAT
-static int adjust_notsent_lowat(h2o_socket_t *sock, unsigned notsent_lowat)
-{
- return setsockopt(h2o_socket_get_fd(sock), IPPROTO_TCP, TCP_NOTSENT_LOWAT, &notsent_lowat, sizeof(notsent_lowat));
-}
-#else
-#define adjust_notsent_lowat NULL
-#endif
-
-size_t h2o_socket_do_prepare_for_latency_optimized_write(h2o_socket_t *sock,
- const h2o_socket_latency_optimization_conditions_t *conditions)
-{
- uint32_t rtt = 0, mss = 0, cwnd_size = 0, cwnd_avail = 0;
- uint64_t loop_time = UINT64_MAX;
- int can_prepare = 1;
-
-#if !defined(TCP_NOTSENT_LOWAT)
- /* the feature cannot be setup unless TCP_NOTSENT_LOWAT is available */
- can_prepare = 0;
-#endif
-
-#if H2O_USE_LIBUV
- /* poll-then-write is impossible with libuv */
- can_prepare = 0;
-#else
- if (can_prepare)
- loop_time = h2o_evloop_get_execution_time(h2o_socket_get_loop(sock));
-#endif
-
- /* obtain TCP states */
- if (can_prepare && obtain_tcp_info(h2o_socket_get_fd(sock), &rtt, &mss, &cwnd_size, &cwnd_avail) != 0)
- can_prepare = 0;
-
- /* determine suggested_write_size, suggested_tls_record_size and adjust TCP_NOTSENT_LOWAT based on the obtained information */
- if (can_prepare) {
- prepare_for_latency_optimized_write(sock, conditions, rtt, mss, cwnd_size, cwnd_avail, loop_time, adjust_notsent_lowat);
- } else {
- disable_latency_optimized_write(sock, adjust_notsent_lowat);
- }
-
- return sock->_latency_optimization.suggested_write_size;
-
-#undef CALC_CWND_PAIR_FROM_BYTE_UNITS
-}
-
-void h2o_socket_write(h2o_socket_t *sock, h2o_iovec_t *bufs, size_t bufcnt, h2o_socket_cb cb)
-{
- size_t i, prev_bytes_written = sock->bytes_written;
-
- for (i = 0; i != bufcnt; ++i) {
- sock->bytes_written += bufs[i].len;
-#if H2O_SOCKET_DUMP_WRITE
- fprintf(stderr, "writing %zu bytes to fd:%d\n", bufs[i].len, h2o_socket_get_fd(sock));
- h2o_dump_memory(stderr, bufs[i].base, bufs[i].len);
-#endif
- }
-
- if (sock->ssl == NULL) {
- do_write(sock, bufs, bufcnt, cb);
- } else {
- assert(sock->ssl->output.bufs.size == 0);
- /* fill in the data */
- size_t ssl_record_size;
- switch (sock->_latency_optimization.state) {
- case H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_TBD:
- case H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_DISABLED:
- ssl_record_size = prev_bytes_written < 200 * 1024 ? calc_suggested_tls_payload_size(sock, 1400) : 16384;
- break;
- case H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_DETERMINED:
- sock->_latency_optimization.state = H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_NEEDS_UPDATE;
- /* fallthru */
- default:
- ssl_record_size = sock->_latency_optimization.suggested_tls_payload_size;
- break;
- }
- for (; bufcnt != 0; ++bufs, --bufcnt) {
- size_t off = 0;
- while (off != bufs[0].len) {
- int ret;
- size_t sz = bufs[0].len - off;
- if (sz > ssl_record_size)
- sz = ssl_record_size;
-#if H2O_USE_PICOTLS
- if (sock->ssl->ptls != NULL) {
- size_t dst_size = sz + ptls_get_record_overhead(sock->ssl->ptls);
- void *dst = h2o_mem_alloc_pool(&sock->ssl->output.pool, dst_size);
- ptls_buffer_t wbuf;
- ptls_buffer_init(&wbuf, dst, dst_size);
- ret = ptls_send(sock->ssl->ptls, &wbuf, bufs[0].base + off, sz);
- assert(ret == 0);
- assert(!wbuf.is_allocated);
- h2o_vector_reserve(&sock->ssl->output.pool, &sock->ssl->output.bufs, sock->ssl->output.bufs.size + 1);
- sock->ssl->output.bufs.entries[sock->ssl->output.bufs.size++] = h2o_iovec_init(dst, wbuf.off);
- } else
-#endif
- {
- ret = SSL_write(sock->ssl->ossl, bufs[0].base + off, (int)sz);
- if (ret != sz) {
- /* The error happens if SSL_write is called after SSL_read returns a fatal error (e.g. due to corrupt TCP
- * packet being received). We need to take care of this since some protocol implementations send data after
- * the read-side of the connection gets closed (note that protocol implementations are (yet) incapable of
- * distinguishing a normal shutdown and close due to an error using the `status` value of the read
- * callback).
- */
- clear_output_buffer(sock->ssl);
- flush_pending_ssl(sock, cb);
-#ifndef H2O_USE_LIBUV
- ((struct st_h2o_evloop_socket_t *)sock)->_flags |= H2O_SOCKET_FLAG_IS_WRITE_ERROR;
-#endif
- return;
- }
- }
- off += sz;
- }
- }
- flush_pending_ssl(sock, cb);
- }
-}
-
-void on_write_complete(h2o_socket_t *sock, const char *err)
-{
- h2o_socket_cb cb;
-
- if (sock->ssl != NULL)
- clear_output_buffer(sock->ssl);
-
- cb = sock->_cb.write;
- sock->_cb.write = NULL;
- cb(sock, err);
-}
-
-void h2o_socket_read_start(h2o_socket_t *sock, h2o_socket_cb cb)
-{
- sock->_cb.read = cb;
- do_read_start(sock);
-}
-
-void h2o_socket_read_stop(h2o_socket_t *sock)
-{
- sock->_cb.read = NULL;
- do_read_stop(sock);
-}
-
-void h2o_socket_setpeername(h2o_socket_t *sock, struct sockaddr *sa, socklen_t len)
-{
- if (sock->_peername != NULL)
- free(sock->_peername);
- sock->_peername = h2o_mem_alloc(offsetof(struct st_h2o_socket_peername_t, addr) + len);
- sock->_peername->len = len;
- memcpy(&sock->_peername->addr, sa, len);
-}
-
-socklen_t h2o_socket_getpeername(h2o_socket_t *sock, struct sockaddr *sa)
-{
- /* return cached, if exists */
- if (sock->_peername != NULL) {
- memcpy(sa, &sock->_peername->addr, sock->_peername->len);
- return sock->_peername->len;
- }
- /* call, copy to cache, and return */
- socklen_t len = get_peername_uncached(sock, sa);
- h2o_socket_setpeername(sock, sa, len);
- return len;
-}
-
-const char *h2o_socket_get_ssl_protocol_version(h2o_socket_t *sock)
-{
- if (sock->ssl != NULL) {
-#if H2O_USE_PICOTLS
- if (sock->ssl->ptls != NULL)
- return "TLSv1.3";
-#endif
- if (sock->ssl->ossl != NULL)
- return SSL_get_version(sock->ssl->ossl);
- }
- return NULL;
-}
-
-int h2o_socket_get_ssl_session_reused(h2o_socket_t *sock)
-{
- if (sock->ssl != NULL) {
-#if H2O_USE_PICOTLS
- if (sock->ssl->ptls != NULL)
- return ptls_is_psk_handshake(sock->ssl->ptls);
-#endif
- if (sock->ssl->ossl != NULL)
- return (int)SSL_session_reused(sock->ssl->ossl);
- }
- return -1;
-}
-
-const char *h2o_socket_get_ssl_cipher(h2o_socket_t *sock)
-{
- if (sock->ssl != NULL) {
-#if H2O_USE_PICOTLS
- if (sock->ssl->ptls != NULL) {
- ptls_cipher_suite_t *cipher = ptls_get_cipher(sock->ssl->ptls);
- if (cipher != NULL)
- return cipher->aead->name;
- } else
-#endif
- if (sock->ssl->ossl != NULL)
- return SSL_get_cipher_name(sock->ssl->ossl);
- }
- return NULL;
-}
-
-int h2o_socket_get_ssl_cipher_bits(h2o_socket_t *sock)
-{
- if (sock->ssl != NULL) {
-#if H2O_USE_PICOTLS
- if (sock->ssl->ptls != NULL) {
- ptls_cipher_suite_t *cipher = ptls_get_cipher(sock->ssl->ptls);
- if (cipher == NULL)
- return 0;
- return (int)cipher->aead->key_size;
- } else
-#endif
- if (sock->ssl->ossl != NULL)
- return SSL_get_cipher_bits(sock->ssl->ossl, NULL);
- }
- return 0;
-}
-
-h2o_iovec_t h2o_socket_get_ssl_session_id(h2o_socket_t *sock)
-{
- if (sock->ssl != NULL) {
-#if H2O_USE_PICOTLS
- if (sock->ssl->ptls != NULL) {
- /* FIXME */
- } else
-#endif
- if (sock->ssl->ossl != NULL) {
- SSL_SESSION *session;
- if (sock->ssl->handshake.server.async_resumption.state == ASYNC_RESUMPTION_STATE_COMPLETE &&
- (session = SSL_get_session(sock->ssl->ossl)) != NULL) {
- unsigned id_len;
- const unsigned char *id = SSL_SESSION_get_id(session, &id_len);
- return h2o_iovec_init(id, id_len);
- }
- }
- }
-
- return h2o_iovec_init(NULL, 0);
-}
-
-h2o_iovec_t h2o_socket_log_ssl_session_id(h2o_socket_t *sock, h2o_mem_pool_t *pool)
-{
- h2o_iovec_t base64id, rawid = h2o_socket_get_ssl_session_id(sock);
-
- if (rawid.base == NULL)
- return h2o_iovec_init(NULL, 0);
-
- base64id.base = pool != NULL ? h2o_mem_alloc_pool(pool, h2o_base64_encode_capacity(rawid.len))
- : h2o_mem_alloc(h2o_base64_encode_capacity(rawid.len));
- base64id.len = h2o_base64_encode(base64id.base, rawid.base, rawid.len, 1);
- return base64id;
-}
-
-h2o_iovec_t h2o_socket_log_ssl_cipher_bits(h2o_socket_t *sock, h2o_mem_pool_t *pool)
-{
- int bits = h2o_socket_get_ssl_cipher_bits(sock);
- if (bits != 0) {
- char *s = (char *)(pool != NULL ? h2o_mem_alloc_pool(pool, sizeof(H2O_INT16_LONGEST_STR))
- : h2o_mem_alloc(sizeof(H2O_INT16_LONGEST_STR)));
- size_t len = sprintf(s, "%" PRId16, (int16_t)bits);
- return h2o_iovec_init(s, len);
- } else {
- return h2o_iovec_init(NULL, 0);
- }
-}
-
-int h2o_socket_compare_address(struct sockaddr *x, struct sockaddr *y)
-{
-#define CMP(a, b) \
- if (a != b) \
- return a < b ? -1 : 1
-
- CMP(x->sa_family, y->sa_family);
-
- if (x->sa_family == AF_UNIX) {
- struct sockaddr_un *xun = (void *)x, *yun = (void *)y;
- int r = strcmp(xun->sun_path, yun->sun_path);
- if (r != 0)
- return r;
- } else if (x->sa_family == AF_INET) {
- struct sockaddr_in *xin = (void *)x, *yin = (void *)y;
- CMP(ntohl(xin->sin_addr.s_addr), ntohl(yin->sin_addr.s_addr));
- CMP(ntohs(xin->sin_port), ntohs(yin->sin_port));
- } else if (x->sa_family == AF_INET6) {
- struct sockaddr_in6 *xin6 = (void *)x, *yin6 = (void *)y;
- int r = memcmp(xin6->sin6_addr.s6_addr, yin6->sin6_addr.s6_addr, sizeof(xin6->sin6_addr.s6_addr));
- if (r != 0)
- return r;
- CMP(ntohs(xin6->sin6_port), ntohs(yin6->sin6_port));
- CMP(xin6->sin6_flowinfo, yin6->sin6_flowinfo);
- CMP(xin6->sin6_scope_id, yin6->sin6_scope_id);
- } else {
- assert(!"unknown sa_family");
- }
-
-#undef CMP
- return 0;
-}
-
-size_t h2o_socket_getnumerichost(struct sockaddr *sa, socklen_t salen, char *buf)
-{
- if (sa->sa_family == AF_INET) {
- /* fast path for IPv4 addresses */
- struct sockaddr_in *sin = (void *)sa;
- uint32_t addr;
- addr = htonl(sin->sin_addr.s_addr);
- return sprintf(buf, "%d.%d.%d.%d", addr >> 24, (addr >> 16) & 255, (addr >> 8) & 255, addr & 255);
- }
-
- if (getnameinfo(sa, salen, buf, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0)
- return SIZE_MAX;
- return strlen(buf);
-}
-
-int32_t h2o_socket_getport(struct sockaddr *sa)
-{
- switch (sa->sa_family) {
- case AF_INET:
- return htons(((struct sockaddr_in *)sa)->sin_port);
- case AF_INET6:
- return htons(((struct sockaddr_in6 *)sa)->sin6_port);
- default:
- return -1;
- }
-}
-
-static void create_ossl(h2o_socket_t *sock)
-{
- sock->ssl->ossl = SSL_new(sock->ssl->ssl_ctx);
- setup_bio(sock);
-}
-
-static SSL_SESSION *on_async_resumption_get(SSL *ssl,
-#if OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(LIBRESSL_VERSION_NUMBER)
- const
-#endif
- unsigned char *data,
- int len, int *copy)
-{
- h2o_socket_t *sock = BIO_get_data(SSL_get_rbio(ssl));
-
- switch (sock->ssl->handshake.server.async_resumption.state) {
- case ASYNC_RESUMPTION_STATE_RECORD:
- sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_REQUEST_SENT;
- resumption_get_async(sock, h2o_iovec_init(data, len));
- return NULL;
- case ASYNC_RESUMPTION_STATE_COMPLETE:
- *copy = 1;
- return sock->ssl->handshake.server.async_resumption.session_data;
- default:
- assert(!"FIXME");
- return NULL;
- }
-}
-
-static int on_async_resumption_new(SSL *ssl, SSL_SESSION *session)
-{
- h2o_iovec_t data;
- const unsigned char *id;
- unsigned id_len;
- unsigned char *p;
-
- /* build data */
- data.len = i2d_SSL_SESSION(session, NULL);
- data.base = alloca(data.len);
- p = (void *)data.base;
- i2d_SSL_SESSION(session, &p);
-
- id = SSL_SESSION_get_id(session, &id_len);
- resumption_new(h2o_iovec_init(id, id_len), data);
- return 0;
-}
-
-static void on_handshake_complete(h2o_socket_t *sock, const char *err)
-{
- if (err == NULL) {
-#if H2O_USE_PICOTLS
- if (sock->ssl->ptls != NULL) {
- sock->ssl->record_overhead = ptls_get_record_overhead(sock->ssl->ptls);
- } else
-#endif
- {
- const SSL_CIPHER *cipher = SSL_get_current_cipher(sock->ssl->ossl);
- switch (SSL_CIPHER_get_id(cipher)) {
- case TLS1_CK_RSA_WITH_AES_128_GCM_SHA256:
- case TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256:
- case TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
- case TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
- case TLS1_CK_RSA_WITH_AES_256_GCM_SHA384:
- case TLS1_CK_DHE_RSA_WITH_AES_256_GCM_SHA384:
- case TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
- case TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
- sock->ssl->record_overhead = 5 /* header */ + 8 /* record_iv_length (RFC 5288 3) */ + 16 /* tag (RFC 5116 5.1) */;
- break;
-#if defined(TLS1_CK_DHE_RSA_CHACHA20_POLY1305)
- case TLS1_CK_DHE_RSA_CHACHA20_POLY1305:
- case TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305:
- case TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305:
- sock->ssl->record_overhead = 5 /* header */ + 16 /* tag */;
- break;
-#endif
- default:
- sock->ssl->record_overhead = 32; /* sufficiently large number that can hold most payloads */
- break;
- }
- }
- }
-
- /* set ssl session into the cache */
- if (sock->ssl->ossl != NULL && !SSL_is_server(sock->ssl->ossl) && sock->ssl->handshake.client.session_cache != NULL) {
- if (err == NULL || err == h2o_socket_error_ssl_cert_name_mismatch) {
- SSL_SESSION *session = SSL_get1_session(sock->ssl->ossl);
- h2o_cache_set(sock->ssl->handshake.client.session_cache, h2o_now(h2o_socket_get_loop(sock)),
- sock->ssl->handshake.client.session_cache_key, sock->ssl->handshake.client.session_cache_key_hash,
- h2o_iovec_init(session, 1));
- }
- }
-
- h2o_socket_cb handshake_cb = sock->ssl->handshake.cb;
- sock->_cb.write = NULL;
- sock->ssl->handshake.cb = NULL;
- if (err == NULL)
- decode_ssl_input(sock);
- handshake_cb(sock, err);
-}
-
-static void proceed_handshake(h2o_socket_t *sock, const char *err)
-{
- h2o_iovec_t first_input = {NULL};
- int ret = 0;
-
- sock->_cb.write = NULL;
-
- if (err != NULL) {
- goto Complete;
- }
-
- if (sock->ssl->ossl == NULL) {
-#if H2O_USE_PICOTLS
- /* prepare I/O */
- size_t consumed = sock->ssl->input.encrypted->size;
- ptls_buffer_t wbuf;
- ptls_buffer_init(&wbuf, "", 0);
-
- if (sock->ssl->ptls != NULL) {
- /* picotls in action, proceed the handshake */
- ret = ptls_handshake(sock->ssl->ptls, &wbuf, sock->ssl->input.encrypted->bytes, &consumed, NULL);
- } else {
- /* start using picotls if the first packet contains TLS 1.3 CH */
- ptls_context_t *ptls_ctx = h2o_socket_ssl_get_picotls_context(sock->ssl->ssl_ctx);
- if (ptls_ctx != NULL) {
- ptls_t *ptls = ptls_new(ptls_ctx, 1);
- if (ptls == NULL)
- h2o_fatal("no memory");
- ret = ptls_handshake(ptls, &wbuf, sock->ssl->input.encrypted->bytes, &consumed, NULL);
- if ((ret == 0 || ret == PTLS_ERROR_IN_PROGRESS) && wbuf.off != 0) {
- sock->ssl->ptls = ptls;
- sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_COMPLETE;
- } else {
- ptls_free(ptls);
- }
- }
- }
-
- if (sock->ssl->ptls != NULL) {
- /* complete I/O done by picotls */
- h2o_buffer_consume(&sock->ssl->input.encrypted, consumed);
- switch (ret) {
- case 0:
- case PTLS_ERROR_IN_PROGRESS:
- if (wbuf.off != 0) {
- h2o_socket_read_stop(sock);
- write_ssl_bytes(sock, wbuf.base, wbuf.off);
- flush_pending_ssl(sock, ret == 0 ? on_handshake_complete : proceed_handshake);
- } else {
- h2o_socket_read_start(sock, proceed_handshake);
- }
- break;
- default:
- /* FIXME send alert in wbuf before calling the callback */
- on_handshake_complete(sock, "picotls handshake error");
- break;
- }
- ptls_buffer_dispose(&wbuf);
- return;
- }
- ptls_buffer_dispose(&wbuf);
-#endif
-
- /* fallback to openssl if the attempt failed */
- create_ossl(sock);
- }
-
- if (sock->ssl->ossl != NULL && SSL_is_server(sock->ssl->ossl) &&
- sock->ssl->handshake.server.async_resumption.state == ASYNC_RESUMPTION_STATE_RECORD) {
- if (sock->ssl->input.encrypted->size <= 1024) {
- /* retain a copy of input if performing async resumption */
- first_input = h2o_iovec_init(alloca(sock->ssl->input.encrypted->size), sock->ssl->input.encrypted->size);
- memcpy(first_input.base, sock->ssl->input.encrypted->bytes, first_input.len);
- } else {
- sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_COMPLETE;
- }
- }
-
-Redo:
- ERR_clear_error();
- if (SSL_is_server(sock->ssl->ossl)) {
- ret = SSL_accept(sock->ssl->ossl);
- switch (sock->ssl->handshake.server.async_resumption.state) {
- case ASYNC_RESUMPTION_STATE_COMPLETE:
- break;
- case ASYNC_RESUMPTION_STATE_RECORD:
- /* async resumption has not been triggered; proceed the state to complete */
- sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_COMPLETE;
- break;
- case ASYNC_RESUMPTION_STATE_REQUEST_SENT: {
- /* sent async request, reset the ssl state, and wait for async response */
- assert(ret < 0);
- SSL_free(sock->ssl->ossl);
- create_ossl(sock);
- clear_output_buffer(sock->ssl);
- h2o_buffer_consume(&sock->ssl->input.encrypted, sock->ssl->input.encrypted->size);
- h2o_buffer_reserve(&sock->ssl->input.encrypted, first_input.len);
- memcpy(sock->ssl->input.encrypted->bytes, first_input.base, first_input.len);
- sock->ssl->input.encrypted->size = first_input.len;
- h2o_socket_read_stop(sock);
- return;
- }
- default:
- h2o_fatal("unexpected async resumption state");
- break;
- }
- } else {
- ret = SSL_connect(sock->ssl->ossl);
- }
-
- if (ret == 0 || (ret < 0 && SSL_get_error(sock->ssl->ossl, ret) != SSL_ERROR_WANT_READ)) {
- /* failed */
- long verify_result = SSL_get_verify_result(sock->ssl->ossl);
- if (verify_result != X509_V_OK) {
- err = X509_verify_cert_error_string(verify_result);
- } else {
- err = "ssl handshake failure";
- }
- goto Complete;
- }
-
- if (sock->ssl->output.bufs.size != 0) {
- h2o_socket_read_stop(sock);
- flush_pending_ssl(sock, ret == 1 ? on_handshake_complete : proceed_handshake);
- } else {
- if (ret == 1) {
- if (!SSL_is_server(sock->ssl->ossl)) {
- X509 *cert = SSL_get_peer_certificate(sock->ssl->ossl);
- if (cert != NULL) {
- switch (validate_hostname(sock->ssl->handshake.client.server_name, cert)) {
- case MatchFound:
- /* ok */
- break;
- case MatchNotFound:
- err = h2o_socket_error_ssl_cert_name_mismatch;
- break;
- default:
- err = h2o_socket_error_ssl_cert_invalid;
- break;
- }
- X509_free(cert);
- } else {
- err = h2o_socket_error_ssl_no_cert;
- }
- }
- goto Complete;
- }
- if (sock->ssl->input.encrypted->size != 0)
- goto Redo;
- h2o_socket_read_start(sock, proceed_handshake);
- }
- return;
-
-Complete:
- h2o_socket_read_stop(sock);
- on_handshake_complete(sock, err);
-}
-
-void h2o_socket_ssl_handshake(h2o_socket_t *sock, SSL_CTX *ssl_ctx, const char *server_name, h2o_socket_cb handshake_cb)
-{
- sock->ssl = h2o_mem_alloc(sizeof(*sock->ssl));
- memset(sock->ssl, 0, offsetof(struct st_h2o_socket_ssl_t, output.pool));
-
- sock->ssl->ssl_ctx = ssl_ctx;
-
- /* setup the buffers; sock->input should be empty, sock->ssl->input.encrypted should contain the initial input, if any */
- h2o_buffer_init(&sock->ssl->input.encrypted, &h2o_socket_buffer_prototype);
- if (sock->input->size != 0) {
- h2o_buffer_t *tmp = sock->input;
- sock->input = sock->ssl->input.encrypted;
- sock->ssl->input.encrypted = tmp;
- }
-
- h2o_mem_init_pool(&sock->ssl->output.pool);
-
- sock->ssl->handshake.cb = handshake_cb;
- if (server_name == NULL) {
- /* is server */
- if (SSL_CTX_sess_get_get_cb(sock->ssl->ssl_ctx) != NULL)
- sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_RECORD;
- if (sock->ssl->input.encrypted->size != 0)
- proceed_handshake(sock, 0);
- else
- h2o_socket_read_start(sock, proceed_handshake);
- } else {
- create_ossl(sock);
- h2o_cache_t *session_cache = h2o_socket_ssl_get_session_cache(sock->ssl->ssl_ctx);
- if (session_cache != NULL) {
- struct sockaddr_storage sa;
- int32_t port;
- if (h2o_socket_getpeername(sock, (struct sockaddr *)&sa) != 0 &&
- (port = h2o_socket_getport((struct sockaddr *)&sa)) != -1) {
- /* session cache is available */
- h2o_iovec_t session_cache_key;
- session_cache_key.base = h2o_mem_alloc(strlen(server_name) + sizeof(":" H2O_UINT16_LONGEST_STR));
- session_cache_key.len = sprintf(session_cache_key.base, "%s:%" PRIu16, server_name, (uint16_t)port);
- sock->ssl->handshake.client.session_cache = session_cache;
- sock->ssl->handshake.client.session_cache_key = session_cache_key;
- sock->ssl->handshake.client.session_cache_key_hash =
- h2o_cache_calchash(session_cache_key.base, session_cache_key.len);
-
- /* fetch from session cache */
- h2o_cache_ref_t *cacheref = h2o_cache_fetch(session_cache, h2o_now(h2o_socket_get_loop(sock)),
- sock->ssl->handshake.client.session_cache_key,
- sock->ssl->handshake.client.session_cache_key_hash);
- if (cacheref != NULL) {
- SSL_set_session(sock->ssl->ossl, (SSL_SESSION *)cacheref->value.base);
- h2o_cache_release(session_cache, cacheref);
- }
- }
- }
- sock->ssl->handshake.client.server_name = h2o_strdup(NULL, server_name, SIZE_MAX).base;
- SSL_set_tlsext_host_name(sock->ssl->ossl, sock->ssl->handshake.client.server_name);
- proceed_handshake(sock, 0);
- }
-}
-
-void h2o_socket_ssl_resume_server_handshake(h2o_socket_t *sock, h2o_iovec_t session_data)
-{
- if (session_data.len != 0) {
- const unsigned char *p = (void *)session_data.base;
- sock->ssl->handshake.server.async_resumption.session_data = d2i_SSL_SESSION(NULL, &p, (long)session_data.len);
- /* FIXME warn on failure */
- }
-
- sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_COMPLETE;
- proceed_handshake(sock, 0);
-
- if (sock->ssl->handshake.server.async_resumption.session_data != NULL) {
- SSL_SESSION_free(sock->ssl->handshake.server.async_resumption.session_data);
- sock->ssl->handshake.server.async_resumption.session_data = NULL;
- }
-}
-
-void h2o_socket_ssl_async_resumption_init(h2o_socket_ssl_resumption_get_async_cb get_async_cb,
- h2o_socket_ssl_resumption_new_cb new_cb)
-{
- resumption_get_async = get_async_cb;
- resumption_new = new_cb;
-}
-
-void h2o_socket_ssl_async_resumption_setup_ctx(SSL_CTX *ctx)
-{
- SSL_CTX_sess_set_get_cb(ctx, on_async_resumption_get);
- SSL_CTX_sess_set_new_cb(ctx, on_async_resumption_new);
- /* if necessary, it is the responsibility of the caller to disable the internal cache */
-}
-
-#if H2O_USE_PICOTLS
-
-static int get_ptls_index(void)
-{
- static int index = -1;
-
- if (index == -1) {
- static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
- pthread_mutex_lock(&mutex);
- if (index == -1) {
- index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL);
- assert(index != -1);
- }
- pthread_mutex_unlock(&mutex);
- }
-
- return index;
-}
-
-ptls_context_t *h2o_socket_ssl_get_picotls_context(SSL_CTX *ossl)
-{
- return SSL_CTX_get_ex_data(ossl, get_ptls_index());
-}
-
-void h2o_socket_ssl_set_picotls_context(SSL_CTX *ossl, ptls_context_t *ptls)
-{
- SSL_CTX_set_ex_data(ossl, get_ptls_index(), ptls);
-}
-
-#endif
-
-static void on_dispose_ssl_ctx_session_cache(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, long argl, void *argp)
-{
- h2o_cache_t *ssl_session_cache = (h2o_cache_t *)ptr;
- if (ssl_session_cache != NULL)
- h2o_cache_destroy(ssl_session_cache);
-}
-
-static int get_ssl_session_cache_index(void)
-{
- static int index = -1;
- static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
- pthread_mutex_lock(&mutex);
- if (index == -1) {
- index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, on_dispose_ssl_ctx_session_cache);
- assert(index != -1);
- }
- pthread_mutex_unlock(&mutex);
- return index;
-}
-
-h2o_cache_t *h2o_socket_ssl_get_session_cache(SSL_CTX *ctx)
-{
- return (h2o_cache_t *)SSL_CTX_get_ex_data(ctx, get_ssl_session_cache_index());
-}
-
-void h2o_socket_ssl_set_session_cache(SSL_CTX *ctx, h2o_cache_t *cache)
-{
- SSL_CTX_set_ex_data(ctx, get_ssl_session_cache_index(), cache);
-}
-
-void h2o_socket_ssl_destroy_session_cache_entry(h2o_iovec_t value)
-{
- SSL_SESSION *session = (SSL_SESSION *)value.base;
- SSL_SESSION_free(session);
-}
-
-h2o_iovec_t h2o_socket_ssl_get_selected_protocol(h2o_socket_t *sock)
-{
- const unsigned char *data = NULL;
- unsigned len = 0;
-
- assert(sock->ssl != NULL);
-
-#if H2O_USE_PICOTLS
- if (sock->ssl->ptls != NULL) {
- const char *proto = ptls_get_negotiated_protocol(sock->ssl->ptls);
- return proto != NULL ? h2o_iovec_init(proto, strlen(proto)) : h2o_iovec_init(NULL, 0);
- }
-#endif
-
-#if H2O_USE_ALPN
- if (len == 0)
- SSL_get0_alpn_selected(sock->ssl->ossl, &data, &len);
-#endif
-#if H2O_USE_NPN
- if (len == 0)
- SSL_get0_next_proto_negotiated(sock->ssl->ossl, &data, &len);
-#endif
-
- return h2o_iovec_init(data, len);
-}
-
-static int on_alpn_select(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *_in, unsigned int inlen,
- void *_protocols)
-{
- const h2o_iovec_t *protocols = _protocols;
- size_t i;
-
- for (i = 0; protocols[i].len != 0; ++i) {
- const unsigned char *in = _in, *in_end = in + inlen;
- while (in != in_end) {
- size_t cand_len = *in++;
- if (in_end - in < cand_len) {
- /* broken request */
- return SSL_TLSEXT_ERR_NOACK;
- }
- if (cand_len == protocols[i].len && memcmp(in, protocols[i].base, cand_len) == 0) {
- goto Found;
- }
- in += cand_len;
- }
- }
- /* not found */
- return SSL_TLSEXT_ERR_NOACK;
-
-Found:
- *out = (const unsigned char *)protocols[i].base;
- *outlen = (unsigned char)protocols[i].len;
- return SSL_TLSEXT_ERR_OK;
-}
-
-#if H2O_USE_ALPN
-
-void h2o_ssl_register_alpn_protocols(SSL_CTX *ctx, const h2o_iovec_t *protocols)
-{
- SSL_CTX_set_alpn_select_cb(ctx, on_alpn_select, (void *)protocols);
-}
-
-#endif
-
-#if H2O_USE_NPN
-
-static int on_npn_advertise(SSL *ssl, const unsigned char **out, unsigned *outlen, void *protocols)
-{
- *out = protocols;
- *outlen = (unsigned)strlen(protocols);
- return SSL_TLSEXT_ERR_OK;
-}
-
-void h2o_ssl_register_npn_protocols(SSL_CTX *ctx, const char *protocols)
-{
- SSL_CTX_set_next_protos_advertised_cb(ctx, on_npn_advertise, (void *)protocols);
-}
-
-#endif
-
-void h2o_sliding_counter_stop(h2o_sliding_counter_t *counter, uint64_t now)
-{
- uint64_t elapsed;
-
- assert(counter->cur.start_at != 0);
-
- /* calculate the time used, and reset cur */
- if (now <= counter->cur.start_at)
- elapsed = 0;
- else
- elapsed = now - counter->cur.start_at;
- counter->cur.start_at = 0;
-
- /* adjust prev */
- counter->prev.sum += elapsed;
- counter->prev.sum -= counter->prev.slots[counter->prev.index];
- counter->prev.slots[counter->prev.index] = elapsed;
- if (++counter->prev.index >= sizeof(counter->prev.slots) / sizeof(counter->prev.slots[0]))
- counter->prev.index = 0;
-
- /* recalc average */
- counter->average = counter->prev.sum / (sizeof(counter->prev.slots) / sizeof(counter->prev.slots[0]));
-}
diff --git a/web/server/h2o/libh2o/lib/common/socket/evloop.c.h b/web/server/h2o/libh2o/lib/common/socket/evloop.c.h
deleted file mode 100644
index 754ed23b9..000000000
--- a/web/server/h2o/libh2o/lib/common/socket/evloop.c.h
+++ /dev/null
@@ -1,624 +0,0 @@
-/*
- * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku, Fastly, Inc.
- *
- * 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 <netinet/in.h>
-#include <netinet/tcp.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <sys/uio.h>
-#include <unistd.h>
-#include "cloexec.h"
-#include "h2o/linklist.h"
-
-#if !defined(H2O_USE_ACCEPT4)
-#ifdef __linux__
-#define H2O_USE_ACCEPT4 1
-#elif __FreeBSD__ >= 10
-#define H2O_USE_ACCEPT4 1
-#else
-#define H2O_USE_ACCEPT4 0
-#endif
-#endif
-
-struct st_h2o_evloop_socket_t {
- h2o_socket_t super;
- int fd;
- int _flags;
- h2o_evloop_t *loop;
- struct {
- size_t cnt;
- h2o_iovec_t *bufs;
- union {
- h2o_iovec_t *alloced_ptr;
- h2o_iovec_t smallbufs[4];
- };
- } _wreq;
- struct st_h2o_evloop_socket_t *_next_pending;
- struct st_h2o_evloop_socket_t *_next_statechanged;
-};
-
-static void link_to_pending(struct st_h2o_evloop_socket_t *sock);
-static void write_pending(struct st_h2o_evloop_socket_t *sock);
-static h2o_evloop_t *create_evloop(size_t sz);
-static void update_now(h2o_evloop_t *loop);
-static int32_t adjust_max_wait(h2o_evloop_t *loop, int32_t max_wait);
-
-/* functions to be defined in the backends */
-static int evloop_do_proceed(h2o_evloop_t *loop, int32_t max_wait);
-static void evloop_do_on_socket_create(struct st_h2o_evloop_socket_t *sock);
-static void evloop_do_on_socket_close(struct st_h2o_evloop_socket_t *sock);
-static void evloop_do_on_socket_export(struct st_h2o_evloop_socket_t *sock);
-
-#if H2O_USE_POLL || H2O_USE_EPOLL || H2O_USE_KQUEUE
-/* explicitly specified */
-#else
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
-#define H2O_USE_KQUEUE 1
-#elif defined(__linux)
-#define H2O_USE_EPOLL 1
-#else
-#define H2O_USE_POLL 1
-#endif
-#endif
-
-#if H2O_USE_POLL
-#include "evloop/poll.c.h"
-#elif H2O_USE_EPOLL
-#include "evloop/epoll.c.h"
-#elif H2O_USE_KQUEUE
-#include "evloop/kqueue.c.h"
-#else
-#error "poller not specified"
-#endif
-
-void link_to_pending(struct st_h2o_evloop_socket_t *sock)
-{
- if (sock->_next_pending == sock) {
- struct st_h2o_evloop_socket_t **slot = (sock->_flags & H2O_SOCKET_FLAG_IS_ACCEPTED_CONNECTION) != 0
- ? &sock->loop->_pending_as_server
- : &sock->loop->_pending_as_client;
- sock->_next_pending = *slot;
- *slot = sock;
- }
-}
-
-static void link_to_statechanged(struct st_h2o_evloop_socket_t *sock)
-{
- if (sock->_next_statechanged == sock) {
- sock->_next_statechanged = NULL;
- *sock->loop->_statechanged.tail_ref = sock;
- sock->loop->_statechanged.tail_ref = &sock->_next_statechanged;
- }
-}
-
-static const char *on_read_core(int fd, h2o_buffer_t **input)
-{
- int read_any = 0;
-
- while (1) {
- ssize_t rret;
- h2o_iovec_t buf = h2o_buffer_reserve(input, 4096);
- if (buf.base == NULL) {
- /* memory allocation failed */
- return h2o_socket_error_out_of_memory;
- }
- while ((rret = read(fd, buf.base, buf.len <= INT_MAX / 2 ? buf.len : INT_MAX / 2 + 1)) == -1 && errno == EINTR)
- ;
- if (rret == -1) {
- if (errno == EAGAIN)
- break;
- else
- return h2o_socket_error_io;
- } else if (rret == 0) {
- if (!read_any)
- return h2o_socket_error_closed; /* TODO notify close */
- break;
- }
- (*input)->size += rret;
- if (buf.len != rret)
- break;
- read_any = 1;
- }
- return NULL;
-}
-
-static void wreq_free_buffer_if_allocated(struct st_h2o_evloop_socket_t *sock)
-{
- if (sock->_wreq.smallbufs <= sock->_wreq.bufs &&
- sock->_wreq.bufs <= sock->_wreq.smallbufs + sizeof(sock->_wreq.smallbufs) / sizeof(sock->_wreq.smallbufs[0])) {
- /* no need to free */
- } else {
- free(sock->_wreq.alloced_ptr);
- sock->_wreq.bufs = sock->_wreq.smallbufs;
- }
-}
-
-static int write_core(int fd, h2o_iovec_t **bufs, size_t *bufcnt)
-{
- int iovcnt;
- ssize_t wret;
-
- if (*bufcnt != 0) {
- do {
- /* write */
- iovcnt = IOV_MAX;
- if (*bufcnt < iovcnt)
- iovcnt = (int)*bufcnt;
- while ((wret = writev(fd, (struct iovec *)*bufs, iovcnt)) == -1 && errno == EINTR)
- ;
- if (wret == -1) {
- if (errno != EAGAIN)
- return -1;
- break;
- }
- /* adjust the buffer */
- while ((*bufs)->len < wret) {
- wret -= (*bufs)->len;
- ++*bufs;
- --*bufcnt;
- assert(*bufcnt != 0);
- }
- if (((*bufs)->len -= wret) == 0) {
- ++*bufs;
- --*bufcnt;
- } else {
- (*bufs)->base += wret;
- }
- } while (*bufcnt != 0 && iovcnt == IOV_MAX);
- }
-
- return 0;
-}
-
-void write_pending(struct st_h2o_evloop_socket_t *sock)
-{
- assert(sock->super._cb.write != NULL);
-
- /* DONT_WRITE poll */
- if (sock->_wreq.cnt == 0)
- goto Complete;
-
- /* write */
- if (write_core(sock->fd, &sock->_wreq.bufs, &sock->_wreq.cnt) == 0 && sock->_wreq.cnt != 0) {
- /* partial write */
- return;
- }
-
- /* either completed or failed */
- wreq_free_buffer_if_allocated(sock);
-
-Complete:
- sock->_flags |= H2O_SOCKET_FLAG_IS_WRITE_NOTIFY;
- link_to_pending(sock);
- link_to_statechanged(sock); /* might need to disable the write polling */
-}
-
-static void read_on_ready(struct st_h2o_evloop_socket_t *sock)
-{
- const char *err = 0;
- size_t prev_bytes_read = sock->super.input->size;
-
- if ((sock->_flags & H2O_SOCKET_FLAG_DONT_READ) != 0)
- goto Notify;
-
- if ((err = on_read_core(sock->fd, sock->super.ssl == NULL ? &sock->super.input : &sock->super.ssl->input.encrypted)) != NULL)
- goto Notify;
-
- if (sock->super.ssl != NULL && sock->super.ssl->handshake.cb == NULL)
- err = decode_ssl_input(&sock->super);
-
-Notify:
- /* the application may get notified even if no new data is avaiable. The
- * behavior is intentional; it is designed as such so that the applications
- * can update their timeout counters when a partial SSL record arrives.
- */
- sock->super.bytes_read = sock->super.input->size - prev_bytes_read;
- sock->super._cb.read(&sock->super, err);
-}
-
-void do_dispose_socket(h2o_socket_t *_sock)
-{
- struct st_h2o_evloop_socket_t *sock = (struct st_h2o_evloop_socket_t *)_sock;
-
- evloop_do_on_socket_close(sock);
- wreq_free_buffer_if_allocated(sock);
- if (sock->fd != -1) {
- close(sock->fd);
- sock->fd = -1;
- }
- sock->_flags = H2O_SOCKET_FLAG_IS_DISPOSED;
- link_to_statechanged(sock);
-}
-
-void do_write(h2o_socket_t *_sock, h2o_iovec_t *_bufs, size_t bufcnt, h2o_socket_cb cb)
-{
- struct st_h2o_evloop_socket_t *sock = (struct st_h2o_evloop_socket_t *)_sock;
- h2o_iovec_t *bufs;
- h2o_iovec_t *tofree = NULL;
-
- assert(sock->super._cb.write == NULL);
- assert(sock->_wreq.cnt == 0);
- sock->super._cb.write = cb;
-
- /* cap the number of buffers, since we're using alloca */
- if (bufcnt > 10000)
- bufs = tofree = h2o_mem_alloc(sizeof(*bufs) * bufcnt);
- else
- bufs = alloca(sizeof(*bufs) * bufcnt);
-
- memcpy(bufs, _bufs, sizeof(*bufs) * bufcnt);
-
- /* try to write now */
- if (write_core(sock->fd, &bufs, &bufcnt) != 0) {
- /* fill in _wreq.bufs with fake data to indicate error */
- sock->_wreq.bufs = sock->_wreq.smallbufs;
- sock->_wreq.cnt = 1;
- *sock->_wreq.bufs = h2o_iovec_init(H2O_STRLIT("deadbeef"));
- sock->_flags |= H2O_SOCKET_FLAG_IS_WRITE_NOTIFY;
- link_to_pending(sock);
- goto Out;
- }
- if (bufcnt == 0) {
- /* write complete, schedule the callback */
- sock->_flags |= H2O_SOCKET_FLAG_IS_WRITE_NOTIFY;
- link_to_pending(sock);
- goto Out;
- }
-
-
- /* setup the buffer to send pending data */
- if (bufcnt <= sizeof(sock->_wreq.smallbufs) / sizeof(sock->_wreq.smallbufs[0])) {
- sock->_wreq.bufs = sock->_wreq.smallbufs;
- } else {
- sock->_wreq.bufs = h2o_mem_alloc(sizeof(h2o_iovec_t) * bufcnt);
- sock->_wreq.alloced_ptr = sock->_wreq.bufs;
- }
- memcpy(sock->_wreq.bufs, bufs, sizeof(h2o_iovec_t) * bufcnt);
- sock->_wreq.cnt = bufcnt;
-
- /* schedule the write */
- link_to_statechanged(sock);
-Out:
- free(tofree);
-}
-
-int h2o_socket_get_fd(h2o_socket_t *_sock)
-{
- struct st_h2o_evloop_socket_t *sock = (struct st_h2o_evloop_socket_t *)_sock;
- return sock->fd;
-}
-
-void do_read_start(h2o_socket_t *_sock)
-{
- struct st_h2o_evloop_socket_t *sock = (struct st_h2o_evloop_socket_t *)_sock;
-
- link_to_statechanged(sock);
-}
-
-void do_read_stop(h2o_socket_t *_sock)
-{
- struct st_h2o_evloop_socket_t *sock = (struct st_h2o_evloop_socket_t *)_sock;
-
- sock->_flags &= ~H2O_SOCKET_FLAG_IS_READ_READY;
- link_to_statechanged(sock);
-}
-
-void h2o_socket_dont_read(h2o_socket_t *_sock, int dont_read)
-{
- struct st_h2o_evloop_socket_t *sock = (struct st_h2o_evloop_socket_t *)_sock;
-
- if (dont_read) {
- sock->_flags |= H2O_SOCKET_FLAG_DONT_READ;
- } else {
- sock->_flags &= ~H2O_SOCKET_FLAG_DONT_READ;
- }
-}
-
-int do_export(h2o_socket_t *_sock, h2o_socket_export_t *info)
-{
- struct st_h2o_evloop_socket_t *sock = (void *)_sock;
-
- assert((sock->_flags & H2O_SOCKET_FLAG_IS_DISPOSED) == 0);
- evloop_do_on_socket_export(sock);
- sock->_flags = H2O_SOCKET_FLAG_IS_DISPOSED;
-
- info->fd = sock->fd;
- sock->fd = -1;
-
- return 0;
-}
-
-h2o_socket_t *do_import(h2o_loop_t *loop, h2o_socket_export_t *info)
-{
- return h2o_evloop_socket_create(loop, info->fd, 0);
-}
-
-h2o_loop_t *h2o_socket_get_loop(h2o_socket_t *_sock)
-{
- struct st_h2o_evloop_socket_t *sock = (void *)_sock;
- return sock->loop;
-}
-
-socklen_t h2o_socket_getsockname(h2o_socket_t *_sock, struct sockaddr *sa)
-{
- struct st_h2o_evloop_socket_t *sock = (void *)_sock;
- socklen_t len = sizeof(struct sockaddr_storage);
- if (getsockname(sock->fd, sa, &len) != 0)
- return 0;
- return len;
-}
-
-socklen_t get_peername_uncached(h2o_socket_t *_sock, struct sockaddr *sa)
-{
- struct st_h2o_evloop_socket_t *sock = (void *)_sock;
- socklen_t len = sizeof(struct sockaddr_storage);
- if (getpeername(sock->fd, sa, &len) != 0)
- return 0;
- return len;
-}
-
-static struct st_h2o_evloop_socket_t *create_socket(h2o_evloop_t *loop, int fd, int flags)
-{
- struct st_h2o_evloop_socket_t *sock;
-
- fcntl(fd, F_SETFL, O_NONBLOCK);
-
- sock = h2o_mem_alloc(sizeof(*sock));
- memset(sock, 0, sizeof(*sock));
- h2o_buffer_init(&sock->super.input, &h2o_socket_buffer_prototype);
- sock->loop = loop;
- sock->fd = fd;
- sock->_flags = flags;
- sock->_wreq.bufs = sock->_wreq.smallbufs;
- sock->_next_pending = sock;
- sock->_next_statechanged = sock;
-
- evloop_do_on_socket_create(sock);
-
- return sock;
-}
-
-static struct st_h2o_evloop_socket_t *create_socket_set_nodelay(h2o_evloop_t *loop, int fd, int flags)
-{
- int on = 1;
- setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
- return create_socket(loop, fd, flags);
-}
-
-h2o_socket_t *h2o_evloop_socket_create(h2o_evloop_t *loop, int fd, int flags)
-{
- fcntl(fd, F_SETFL, O_NONBLOCK);
- return &create_socket(loop, fd, flags)->super;
-}
-
-h2o_socket_t *h2o_evloop_socket_accept(h2o_socket_t *_listener)
-{
- struct st_h2o_evloop_socket_t *listener = (struct st_h2o_evloop_socket_t *)_listener;
- int fd;
-
-#if H2O_USE_ACCEPT4
- if ((fd = accept4(listener->fd, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC)) == -1)
- return NULL;
-#else
- if ((fd = cloexec_accept(listener->fd, NULL, NULL)) == -1)
- return NULL;
- fcntl(fd, F_SETFL, O_NONBLOCK);
-#endif
-
- return &create_socket_set_nodelay(listener->loop, fd, H2O_SOCKET_FLAG_IS_ACCEPTED_CONNECTION)->super;
-}
-
-h2o_socket_t *h2o_socket_connect(h2o_loop_t *loop, struct sockaddr *addr, socklen_t addrlen, h2o_socket_cb cb)
-{
- int fd;
- struct st_h2o_evloop_socket_t *sock;
-
- if ((fd = cloexec_socket(addr->sa_family, SOCK_STREAM, 0)) == -1)
- return NULL;
- fcntl(fd, F_SETFL, O_NONBLOCK);
- if (!(connect(fd, addr, addrlen) == 0 || errno == EINPROGRESS)) {
- close(fd);
- return NULL;
- }
-
- sock = create_socket_set_nodelay(loop, fd, H2O_SOCKET_FLAG_IS_CONNECTING);
- h2o_socket_notify_write(&sock->super, cb);
- return &sock->super;
-}
-
-h2o_evloop_t *create_evloop(size_t sz)
-{
- h2o_evloop_t *loop = h2o_mem_alloc(sz);
-
- memset(loop, 0, sz);
- loop->_statechanged.tail_ref = &loop->_statechanged.head;
- h2o_linklist_init_anchor(&loop->_timeouts);
-
- update_now(loop);
-
- return loop;
-}
-
-void update_now(h2o_evloop_t *loop)
-{
- struct timeval tv;
- gettimeofday(&tv, NULL);
- loop->_now = (uint64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000;
-}
-
-int32_t adjust_max_wait(h2o_evloop_t *loop, int32_t max_wait)
-{
- uint64_t wake_at = h2o_timeout_get_wake_at(&loop->_timeouts);
-
- update_now(loop);
-
- if (wake_at <= loop->_now) {
- max_wait = 0;
- } else {
- uint64_t delta = wake_at - loop->_now;
- if (delta < max_wait)
- max_wait = (int32_t)delta;
- }
-
- return max_wait;
-}
-
-void h2o_socket_notify_write(h2o_socket_t *_sock, h2o_socket_cb cb)
-{
- struct st_h2o_evloop_socket_t *sock = (struct st_h2o_evloop_socket_t *)_sock;
- assert(sock->super._cb.write == NULL);
- assert(sock->_wreq.cnt == 0);
-
- sock->super._cb.write = cb;
- link_to_statechanged(sock);
-}
-
-static void run_socket(struct st_h2o_evloop_socket_t *sock)
-{
- if ((sock->_flags & H2O_SOCKET_FLAG_IS_DISPOSED) != 0) {
- /* is freed in updatestates phase */
- return;
- }
-
- if ((sock->_flags & H2O_SOCKET_FLAG_IS_READ_READY) != 0) {
- sock->_flags &= ~H2O_SOCKET_FLAG_IS_READ_READY;
- read_on_ready(sock);
- }
-
- if ((sock->_flags & H2O_SOCKET_FLAG_IS_WRITE_NOTIFY) != 0) {
- const char *err = NULL;
- assert(sock->super._cb.write != NULL);
- sock->_flags &= ~H2O_SOCKET_FLAG_IS_WRITE_NOTIFY;
- if (sock->_wreq.cnt != 0) {
- /* error */
- err = h2o_socket_error_io;
- sock->_wreq.cnt = 0;
- } else if ((sock->_flags & H2O_SOCKET_FLAG_IS_CONNECTING) != 0) {
- sock->_flags &= ~H2O_SOCKET_FLAG_IS_CONNECTING;
- int so_err = 0;
- socklen_t l = sizeof(so_err);
- so_err = 0;
- if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, &so_err, &l) != 0 || so_err != 0) {
- /* FIXME lookup the error table */
- err = h2o_socket_error_conn_fail;
- }
- }
- on_write_complete(&sock->super, err);
- }
-}
-
-static void run_pending(h2o_evloop_t *loop)
-{
- struct st_h2o_evloop_socket_t *sock;
-
- while (loop->_pending_as_server != NULL || loop->_pending_as_client != NULL) {
- while ((sock = loop->_pending_as_client) != NULL) {
- loop->_pending_as_client = sock->_next_pending;
- sock->_next_pending = sock;
- run_socket(sock);
- }
- if ((sock = loop->_pending_as_server) != NULL) {
- loop->_pending_as_server = sock->_next_pending;
- sock->_next_pending = sock;
- run_socket(sock);
- }
- }
-}
-
-void h2o_evloop_destroy(h2o_evloop_t *loop)
-{
- struct st_h2o_evloop_socket_t *sock;
-
- /* timeouts are governed by the application and MUST be destroyed prior to destroying the loop */
- assert(h2o_linklist_is_empty(&loop->_timeouts));
-
- /* dispose all socket */
- while ((sock = loop->_pending_as_client) != NULL) {
- loop->_pending_as_client = sock->_next_pending;
- sock->_next_pending = sock;
- h2o_socket_close((h2o_socket_t *)sock);
- }
- while ((sock = loop->_pending_as_server) != NULL) {
- loop->_pending_as_server = sock->_next_pending;
- sock->_next_pending = sock;
- h2o_socket_close((h2o_socket_t *)sock);
- }
-
- /* now all socket are disposedand and placed in linked list statechanged
- * we can freeing memory in cycle by next_statechanged,
- */
- while ((sock = loop->_statechanged.head) != NULL) {
- loop->_statechanged.head = sock->_next_statechanged;
- free(sock);
- }
-
- /* lastly we need to free loop memory */
- free(loop);
-}
-
-int h2o_evloop_run(h2o_evloop_t *loop, int32_t max_wait)
-{
- h2o_linklist_t *node;
-
- /* update socket states, poll, set readable flags, perform pending writes */
- if (evloop_do_proceed(loop, max_wait) != 0)
- return -1;
-
- /* run the pending callbacks */
- run_pending(loop);
-
- /* run the timeouts */
- for (node = loop->_timeouts.next; node != &loop->_timeouts; node = node->next) {
- h2o_timeout_t *timeout = H2O_STRUCT_FROM_MEMBER(h2o_timeout_t, _link, node);
- h2o_timeout_run(loop, timeout, loop->_now);
- }
- /* assert h2o_timeout_run has called run_pending */
- assert(loop->_pending_as_client == NULL);
- assert(loop->_pending_as_server == NULL);
-
- if (h2o_sliding_counter_is_running(&loop->exec_time_counter)) {
- update_now(loop);
- h2o_sliding_counter_stop(&loop->exec_time_counter, loop->_now);
- }
-
- return 0;
-}
-
-void h2o_timeout__do_init(h2o_evloop_t *loop, h2o_timeout_t *timeout)
-{
- h2o_linklist_insert(&loop->_timeouts, &timeout->_link);
-}
-
-void h2o_timeout__do_dispose(h2o_evloop_t *loop, h2o_timeout_t *timeout)
-{
- h2o_linklist_unlink(&timeout->_link);
-}
-
-void h2o_timeout__do_link(h2o_evloop_t *loop, h2o_timeout_t *timeout, h2o_timeout_entry_t *entry)
-{
- /* nothing to do */
-}
-
-void h2o_timeout__do_post_callback(h2o_evloop_t *loop)
-{
- run_pending(loop);
-}
diff --git a/web/server/h2o/libh2o/lib/common/socket/evloop/epoll.c.h b/web/server/h2o/libh2o/lib/common/socket/evloop/epoll.c.h
deleted file mode 100644
index 247dac893..000000000
--- a/web/server/h2o/libh2o/lib/common/socket/evloop/epoll.c.h
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (c) 2014 DeNA Co., Ltd.
- *
- * 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 <assert.h>
-#include <limits.h>
-#include <stdio.h>
-#include <sys/epoll.h>
-
-#if 0
-#define DEBUG_LOG(...) fprintf(stderr, __VA_ARGS__)
-#else
-#define DEBUG_LOG(...)
-#endif
-
-struct st_h2o_evloop_epoll_t {
- h2o_evloop_t super;
- int ep;
-};
-
-static int update_status(struct st_h2o_evloop_epoll_t *loop)
-{
- while (loop->super._statechanged.head != NULL) {
- /* detach the top */
- struct st_h2o_evloop_socket_t *sock = loop->super._statechanged.head;
- loop->super._statechanged.head = sock->_next_statechanged;
- sock->_next_statechanged = sock;
- /* update the state */
- if ((sock->_flags & H2O_SOCKET_FLAG_IS_DISPOSED) != 0) {
- free(sock);
- } else {
- int changed = 0, op, ret;
- struct epoll_event ev;
- ev.events = 0;
- if (h2o_socket_is_reading(&sock->super)) {
- ev.events |= EPOLLIN;
- if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_READ) == 0) {
- sock->_flags |= H2O_SOCKET_FLAG_IS_POLLED_FOR_READ;
- changed = 1;
- }
- } else {
- if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_READ) != 0) {
- sock->_flags &= ~H2O_SOCKET_FLAG_IS_POLLED_FOR_READ;
- changed = 1;
- }
- }
- if (h2o_socket_is_writing(&sock->super)) {
- ev.events |= EPOLLOUT;
- if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE) == 0) {
- sock->_flags |= H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE;
- changed = 1;
- }
- } else {
- if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE) != 0) {
- sock->_flags &= ~H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE;
- changed = 1;
- }
- }
- if (changed) {
- if ((sock->_flags & H2O_SOCKET_FLAG__EPOLL_IS_REGISTERED) != 0) {
- if (ev.events != 0)
- op = EPOLL_CTL_MOD;
- else
- op = EPOLL_CTL_DEL;
- } else {
- assert(ev.events != 0);
- op = EPOLL_CTL_ADD;
- }
- ev.data.ptr = sock;
- while ((ret = epoll_ctl(loop->ep, op, sock->fd, &ev)) != 0 && errno == EINTR)
- ;
- if (ret != 0)
- return -1;
- if (op == EPOLL_CTL_DEL)
- sock->_flags &= ~H2O_SOCKET_FLAG__EPOLL_IS_REGISTERED;
- else
- sock->_flags |= H2O_SOCKET_FLAG__EPOLL_IS_REGISTERED;
- }
- }
- }
- loop->super._statechanged.tail_ref = &loop->super._statechanged.head;
-
- return 0;
-}
-
-int evloop_do_proceed(h2o_evloop_t *_loop, int32_t max_wait)
-{
- struct st_h2o_evloop_epoll_t *loop = (struct st_h2o_evloop_epoll_t *)_loop;
- struct epoll_event events[256];
- int nevents, i;
-
- /* collect (and update) status */
- if (update_status(loop) != 0)
- return -1;
-
- /* poll */
- max_wait = adjust_max_wait(&loop->super, max_wait);
- nevents = epoll_wait(loop->ep, events, sizeof(events) / sizeof(events[0]), max_wait);
- update_now(&loop->super);
- if (nevents == -1)
- return -1;
-
- if (nevents != 0)
- h2o_sliding_counter_start(&loop->super.exec_time_counter, loop->super._now);
-
- /* update readable flags, perform writes */
- for (i = 0; i != nevents; ++i) {
- struct st_h2o_evloop_socket_t *sock = events[i].data.ptr;
- int notified = 0;
- if ((events[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR)) != 0) {
- if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_READ) != 0) {
- sock->_flags |= H2O_SOCKET_FLAG_IS_READ_READY;
- link_to_pending(sock);
- notified = 1;
- }
- }
- if ((events[i].events & (EPOLLOUT | EPOLLHUP | EPOLLERR)) != 0) {
- if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE) != 0) {
- write_pending(sock);
- notified = 1;
- }
- }
- if (!notified) {
- static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
- static time_t last_reported = 0;
- time_t now = time(NULL);
- pthread_mutex_lock(&lock);
- if (last_reported + 60 < now) {
- last_reported = now;
- fprintf(stderr, "ignoring epoll event (fd:%d,event:%x)\n", sock->fd, (int)events[i].events);
- }
- pthread_mutex_unlock(&lock);
- }
- }
-
- return 0;
-}
-
-static void evloop_do_on_socket_create(struct st_h2o_evloop_socket_t *sock)
-{
-}
-
-static void evloop_do_on_socket_close(struct st_h2o_evloop_socket_t *sock)
-{
- struct st_h2o_evloop_epoll_t *loop = (void *)sock->loop;
- int ret;
-
- if (sock->fd == -1)
- return;
- if ((sock->_flags & H2O_SOCKET_FLAG__EPOLL_IS_REGISTERED) == 0)
- return;
- while ((ret = epoll_ctl(loop->ep, EPOLL_CTL_DEL, sock->fd, NULL)) != 0 && errno == EINTR)
- ;
- if (ret != 0)
- fprintf(stderr, "socket_close: epoll(DEL) returned error %d (fd=%d)\n", errno, sock->fd);
-}
-
-static void evloop_do_on_socket_export(struct st_h2o_evloop_socket_t *sock)
-{
- struct st_h2o_evloop_epoll_t *loop = (void *)sock->loop;
- int ret;
-
- if ((sock->_flags & H2O_SOCKET_FLAG__EPOLL_IS_REGISTERED) == 0)
- return;
- while ((ret = epoll_ctl(loop->ep, EPOLL_CTL_DEL, sock->fd, NULL)) != 0 && errno == EINTR)
- ;
- if (ret != 0)
- fprintf(stderr, "socket_export: epoll(DEL) returned error %d (fd=%d)\n", errno, sock->fd);
-}
-
-h2o_evloop_t *h2o_evloop_create(void)
-{
- struct st_h2o_evloop_epoll_t *loop = (struct st_h2o_evloop_epoll_t *)create_evloop(sizeof(*loop));
-
- pthread_mutex_lock(&cloexec_mutex);
- loop->ep = epoll_create(10);
- while (fcntl(loop->ep, F_SETFD, FD_CLOEXEC) == -1) {
- if (errno != EAGAIN) {
- fprintf(stderr, "h2o_evloop_create: failed to set FD_CLOEXEC to the epoll fd (errno=%d)\n", errno);
- abort();
- }
- }
- pthread_mutex_unlock(&cloexec_mutex);
-
- return &loop->super;
-}
diff --git a/web/server/h2o/libh2o/lib/common/socket/evloop/kqueue.c.h b/web/server/h2o/libh2o/lib/common/socket/evloop/kqueue.c.h
deleted file mode 100644
index 21288ed7c..000000000
--- a/web/server/h2o/libh2o/lib/common/socket/evloop/kqueue.c.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (c) 2014 DeNA Co., Ltd.
- *
- * 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 <assert.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/event.h>
-#include <sys/time.h>
-
-#if 0
-#define DEBUG_LOG(...) fprintf(stderr, __VA_ARGS__)
-#else
-#define DEBUG_LOG(...)
-#endif
-
-struct st_h2o_socket_loop_kqueue_t {
- h2o_evloop_t super;
- int kq;
-};
-
-static void ev_set(struct kevent *ev, int fd, int filter, int flags, struct st_h2o_evloop_socket_t *sock)
-{
-#ifdef __NetBSD__
- EV_SET(ev, fd, filter, flags, 0, 0, (intptr_t)sock);
-#else
- EV_SET(ev, fd, filter, flags, 0, 0, sock);
-#endif
-}
-
-static int collect_status(struct st_h2o_socket_loop_kqueue_t *loop, struct kevent *changelist, int changelist_capacity)
-{
- int change_index = 0;
-
-#define SET_AND_UPDATE(filter, flags) \
- do { \
- ev_set(changelist + change_index++, sock->fd, filter, flags, sock); \
- if (change_index == changelist_capacity) { \
- int ret; \
- while ((ret = kevent(loop->kq, changelist, change_index, NULL, 0, NULL)) != 0 && errno == EINTR) \
- ; \
- if (ret == -1) \
- return -1; \
- change_index = 0; \
- } \
- } while (0)
-
- while (loop->super._statechanged.head != NULL) {
- /* detach the top */
- struct st_h2o_evloop_socket_t *sock = loop->super._statechanged.head;
- loop->super._statechanged.head = sock->_next_statechanged;
- sock->_next_statechanged = sock;
- /* update the state */
- if ((sock->_flags & H2O_SOCKET_FLAG_IS_DISPOSED) != 0) {
- free(sock);
- } else {
- if (h2o_socket_is_reading(&sock->super)) {
- if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_READ) == 0) {
- sock->_flags |= H2O_SOCKET_FLAG_IS_POLLED_FOR_READ;
- SET_AND_UPDATE(EVFILT_READ, EV_ADD);
- }
- } else {
- if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_READ) != 0) {
- sock->_flags &= ~H2O_SOCKET_FLAG_IS_POLLED_FOR_READ;
- SET_AND_UPDATE(EVFILT_READ, EV_DELETE);
- }
- }
- if (h2o_socket_is_writing(&sock->super)) {
- if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE) == 0) {
- sock->_flags |= H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE;
- SET_AND_UPDATE(EVFILT_WRITE, EV_ADD);
- }
- } else {
- if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE) != 0) {
- sock->_flags &= ~H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE;
- SET_AND_UPDATE(EVFILT_WRITE, EV_DELETE);
- }
- }
- }
- }
- loop->super._statechanged.tail_ref = &loop->super._statechanged.head;
-
- return change_index;
-
-#undef SET_AND_UPDATE
-}
-
-int evloop_do_proceed(h2o_evloop_t *_loop, int32_t max_wait)
-{
- struct st_h2o_socket_loop_kqueue_t *loop = (struct st_h2o_socket_loop_kqueue_t *)_loop;
- struct kevent changelist[64], events[128];
- int nchanges, nevents, i;
- struct timespec ts;
-
- /* collect (and update) status */
- if ((nchanges = collect_status(loop, changelist, sizeof(changelist) / sizeof(changelist[0]))) == -1)
- return -1;
-
- /* poll */
- max_wait = adjust_max_wait(&loop->super, max_wait);
- ts.tv_sec = max_wait / 1000;
- ts.tv_nsec = max_wait % 1000 * 1000 * 1000;
- nevents = kevent(loop->kq, changelist, nchanges, events, sizeof(events) / sizeof(events[0]), &ts);
-
- update_now(&loop->super);
- if (nevents == -1)
- return -1;
-
- if (nevents != 0)
- h2o_sliding_counter_start(&loop->super.exec_time_counter, loop->super._now);
-
- /* update readable flags, perform writes */
- for (i = 0; i != nevents; ++i) {
- struct st_h2o_evloop_socket_t *sock = (void *)events[i].udata;
- assert(sock->fd == events[i].ident);
- switch (events[i].filter) {
- case EVFILT_READ:
- if (sock->_flags != H2O_SOCKET_FLAG_IS_DISPOSED) {
- sock->_flags |= H2O_SOCKET_FLAG_IS_READ_READY;
- link_to_pending(sock);
- }
- break;
- case EVFILT_WRITE:
- if (sock->_flags != H2O_SOCKET_FLAG_IS_DISPOSED) {
- write_pending(sock);
- }
- break;
- default:
- break; /* ??? */
- }
- }
-
- return 0;
-}
-
-static void evloop_do_on_socket_create(struct st_h2o_evloop_socket_t *sock)
-{
-}
-
-static void evloop_do_on_socket_close(struct st_h2o_evloop_socket_t *sock)
-{
-}
-
-static void evloop_do_on_socket_export(struct st_h2o_evloop_socket_t *sock)
-{
- struct st_h2o_socket_loop_kqueue_t *loop = (void *)sock->loop;
- struct kevent changelist[2];
- int change_index = 0, ret;
-
- if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_READ) != 0)
- ev_set(changelist + change_index++, sock->fd, EVFILT_READ, EV_DELETE, 0);
- if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE) != 0)
- ev_set(changelist + change_index++, sock->fd, EVFILT_WRITE, EV_DELETE, 0);
- if (change_index == 0)
- return;
- while ((ret = kevent(loop->kq, changelist, change_index, NULL, 0, NULL)) != 0 && errno == EINTR)
- ;
- if (ret == -1)
- fprintf(stderr, "kevent returned error %d (fd=%d)", errno, sock->fd);
-}
-
-h2o_evloop_t *h2o_evloop_create(void)
-{
- struct st_h2o_socket_loop_kqueue_t *loop = (struct st_h2o_socket_loop_kqueue_t *)create_evloop(sizeof(*loop));
-
- loop->kq = kqueue();
-
- return &loop->super;
-}
diff --git a/web/server/h2o/libh2o/lib/common/socket/evloop/poll.c.h b/web/server/h2o/libh2o/lib/common/socket/evloop/poll.c.h
deleted file mode 100644
index 8b3f3d149..000000000
--- a/web/server/h2o/libh2o/lib/common/socket/evloop/poll.c.h
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (c) 2014,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 <stdio.h>
-#include <poll.h>
-
-#if 0
-#define DEBUG_LOG(...) fprintf(stderr, __VA_ARGS__)
-#else
-#define DEBUG_LOG(...)
-#endif
-
-struct st_h2o_evloop_poll_t {
- h2o_evloop_t super;
- H2O_VECTOR(struct st_h2o_evloop_socket_t *) socks;
-};
-
-static void update_socks(struct st_h2o_evloop_poll_t *loop)
-{
- /* update loop->socks */
- while (loop->super._statechanged.head != NULL) {
- /* detach the top */
- struct st_h2o_evloop_socket_t *sock = loop->super._statechanged.head;
- loop->super._statechanged.head = sock->_next_statechanged;
- sock->_next_statechanged = sock;
- /* update the state */
- if ((sock->_flags & H2O_SOCKET_FLAG_IS_DISPOSED) != 0) {
- assert(sock->fd == -1);
- free(sock);
- } else {
- assert(sock->fd < loop->socks.size);
- if (loop->socks.entries[sock->fd] == NULL) {
- loop->socks.entries[sock->fd] = sock;
- } else {
- assert(loop->socks.entries[sock->fd] == sock);
- }
- if (h2o_socket_is_reading(&sock->super)) {
- DEBUG_LOG("setting READ for fd: %d\n", sock->fd);
- sock->_flags |= H2O_SOCKET_FLAG_IS_POLLED_FOR_READ;
- } else {
- DEBUG_LOG("clearing READ for fd: %d\n", sock->fd);
- sock->_flags &= ~H2O_SOCKET_FLAG_IS_POLLED_FOR_READ;
- }
- if (h2o_socket_is_writing(&sock->super)) {
- DEBUG_LOG("setting WRITE for fd: %d\n", sock->fd);
- sock->_flags |= H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE;
- } else {
- DEBUG_LOG("clearing WRITE for fd: %d\n", sock->fd);
- sock->_flags &= ~H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE;
- }
- }
- }
- loop->super._statechanged.tail_ref = &loop->super._statechanged.head;
-}
-
-int evloop_do_proceed(h2o_evloop_t *_loop, int32_t max_wait)
-{
- struct st_h2o_evloop_poll_t *loop = (struct st_h2o_evloop_poll_t *)_loop;
- H2O_VECTOR(struct pollfd) pollfds = {NULL};
- int fd, ret;
-
- /* update status */
- update_socks(loop);
-
- /* build list of fds to be polled */
- for (fd = 0; fd != loop->socks.size; ++fd) {
- struct st_h2o_evloop_socket_t *sock = loop->socks.entries[fd];
- if (sock == NULL)
- continue;
- assert(fd == sock->fd);
- if ((sock->_flags & (H2O_SOCKET_FLAG_IS_POLLED_FOR_READ | H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE)) != 0) {
- h2o_vector_reserve(NULL, &pollfds, pollfds.size + 1);
- struct pollfd *slot = pollfds.entries + pollfds.size++;
- slot->fd = fd;
- slot->events = 0;
- slot->revents = 0;
- if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_READ) != 0)
- slot->events |= POLLIN;
- if ((sock->_flags & H2O_SOCKET_FLAG_IS_POLLED_FOR_WRITE) != 0)
- slot->events |= POLLOUT;
- }
- }
-
- /* call */
- max_wait = adjust_max_wait(&loop->super, max_wait);
- ret = poll(pollfds.entries, (nfds_t)pollfds.size, max_wait);
- update_now(&loop->super);
- if (ret == -1)
- goto Exit;
- DEBUG_LOG("poll returned: %d\n", ret);
-
- /* update readable flags, perform writes */
- if (ret > 0) {
- size_t i;
- h2o_sliding_counter_start(&loop->super.exec_time_counter, loop->super._now);
- for (i = 0; i != pollfds.size; ++i) {
- /* set read_ready flag before calling the write cb, since app. code invoked by the latter may close the socket, clearing
- * the former flag */
- if ((pollfds.entries[i].revents & POLLIN) != 0) {
- struct st_h2o_evloop_socket_t *sock = loop->socks.entries[pollfds.entries[i].fd];
- assert(sock != NULL);
- assert(sock->fd == pollfds.entries[i].fd);
- if (sock->_flags != H2O_SOCKET_FLAG_IS_DISPOSED) {
- sock->_flags |= H2O_SOCKET_FLAG_IS_READ_READY;
- link_to_pending(sock);
- DEBUG_LOG("added fd %d as read_ready\n", sock->fd);
- }
- }
- if ((pollfds.entries[i].revents & POLLOUT) != 0) {
- struct st_h2o_evloop_socket_t *sock = loop->socks.entries[pollfds.entries[i].fd];
- assert(sock != NULL);
- assert(sock->fd == pollfds.entries[i].fd);
- if (sock->_flags != H2O_SOCKET_FLAG_IS_DISPOSED) {
- DEBUG_LOG("handling pending writes on fd %d\n", fd);
- write_pending(sock);
- }
- }
- }
- ret = 0;
- }
-
-Exit:
- free(pollfds.entries);
- return ret;
-}
-
-static void evloop_do_on_socket_create(struct st_h2o_evloop_socket_t *sock)
-{
- struct st_h2o_evloop_poll_t *loop = (struct st_h2o_evloop_poll_t *)sock->loop;
-
- if (sock->fd >= loop->socks.size) {
- h2o_vector_reserve(NULL, &loop->socks, sock->fd + 1);
- memset(loop->socks.entries + loop->socks.size, 0, (sock->fd + 1 - loop->socks.size) * sizeof(loop->socks.entries[0]));
- loop->socks.size = sock->fd + 1;
- }
-
- if (loop->socks.entries[sock->fd] != NULL)
- assert(loop->socks.entries[sock->fd]->_flags == H2O_SOCKET_FLAG_IS_DISPOSED);
-}
-
-static void evloop_do_on_socket_close(struct st_h2o_evloop_socket_t *sock)
-{
- struct st_h2o_evloop_poll_t *loop = (struct st_h2o_evloop_poll_t *)sock->loop;
-
- if (sock->fd != -1)
- loop->socks.entries[sock->fd] = NULL;
-}
-
-static void evloop_do_on_socket_export(struct st_h2o_evloop_socket_t *sock)
-{
- struct st_h2o_evloop_poll_t *loop = (struct st_h2o_evloop_poll_t *)sock->loop;
- evloop_do_on_socket_close(sock);
- loop->socks.entries[sock->fd] = NULL;
-}
-
-h2o_evloop_t *h2o_evloop_create(void)
-{
- struct st_h2o_evloop_poll_t *loop = (struct st_h2o_evloop_poll_t *)create_evloop(sizeof(*loop));
- return &loop->super;
-}
diff --git a/web/server/h2o/libh2o/lib/common/socket/uv-binding.c.h b/web/server/h2o/libh2o/lib/common/socket/uv-binding.c.h
deleted file mode 100644
index 44c71c166..000000000
--- a/web/server/h2o/libh2o/lib/common/socket/uv-binding.c.h
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku, Fastly, Inc.
- *
- * 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.
- */
-
-struct st_h2o_uv_socket_t {
- h2o_socket_t super;
- struct {
- uv_stream_t *stream;
- uv_close_cb close_cb;
- } uv;
- union {
- uv_connect_t _creq;
- uv_write_t _wreq;
- };
-};
-
-static void schedule_timer(h2o_timeout_t *timeout);
-
-static void alloc_inbuf_tcp(uv_handle_t *handle, size_t suggested_size, uv_buf_t *_buf)
-{
- struct st_h2o_uv_socket_t *sock = handle->data;
-
- h2o_iovec_t buf = h2o_buffer_reserve(&sock->super.input, 4096);
- memcpy(_buf, &buf, sizeof(buf));
-}
-
-static void alloc_inbuf_ssl(uv_handle_t *handle, size_t suggested_size, uv_buf_t *_buf)
-{
- struct st_h2o_uv_socket_t *sock = handle->data;
-
- h2o_iovec_t buf = h2o_buffer_reserve(&sock->super.ssl->input.encrypted, 4096);
- memcpy(_buf, &buf, sizeof(buf));
-}
-
-static void on_read_tcp(uv_stream_t *stream, ssize_t nread, const uv_buf_t *_unused)
-{
- struct st_h2o_uv_socket_t *sock = stream->data;
-
- if (nread < 0) {
- sock->super.bytes_read = 0;
- sock->super._cb.read(&sock->super, h2o_socket_error_closed);
- return;
- }
-
- sock->super.input->size += nread;
- sock->super.bytes_read = nread;
- sock->super._cb.read(&sock->super, NULL);
-}
-
-static void on_read_ssl(uv_stream_t *stream, ssize_t nread, const uv_buf_t *_unused)
-{
- struct st_h2o_uv_socket_t *sock = stream->data;
- size_t prev_bytes_read = sock->super.input->size;
- const char *err = h2o_socket_error_io;
-
- if (nread > 0) {
- sock->super.ssl->input.encrypted->size += nread;
- if (sock->super.ssl->handshake.cb == NULL)
- err = decode_ssl_input(&sock->super);
- else
- err = NULL;
- }
- sock->super.bytes_read = sock->super.input->size - prev_bytes_read;
- sock->super._cb.read(&sock->super, err);
-}
-
-static void on_do_write_complete(uv_write_t *wreq, int status)
-{
- struct st_h2o_uv_socket_t *sock = H2O_STRUCT_FROM_MEMBER(struct st_h2o_uv_socket_t, _wreq, wreq);
- if (sock->super._cb.write != NULL)
- on_write_complete(&sock->super, status == 0 ? NULL : h2o_socket_error_io);
-}
-
-static void free_sock(uv_handle_t *handle)
-{
- struct st_h2o_uv_socket_t *sock = handle->data;
- uv_close_cb cb = sock->uv.close_cb;
- free(sock);
- cb(handle);
-}
-
-void do_dispose_socket(h2o_socket_t *_sock)
-{
- struct st_h2o_uv_socket_t *sock = (struct st_h2o_uv_socket_t *)_sock;
- sock->super._cb.write = NULL; /* avoid the write callback getting called when closing the socket (#1249) */
- uv_close((uv_handle_t *)sock->uv.stream, free_sock);
-}
-
-int h2o_socket_get_fd(h2o_socket_t *_sock)
-{
- int fd, ret;
- struct st_h2o_uv_socket_t *sock = (struct st_h2o_uv_socket_t *)_sock;
-
- ret = uv_fileno((uv_handle_t *)sock->uv.stream, (uv_os_fd_t *)&fd);
- if (ret)
- return -1;
-
- return fd;
-}
-
-void do_read_start(h2o_socket_t *_sock)
-{
- struct st_h2o_uv_socket_t *sock = (struct st_h2o_uv_socket_t *)_sock;
-
- if (sock->super.ssl == NULL)
- uv_read_start(sock->uv.stream, alloc_inbuf_tcp, on_read_tcp);
- else
- uv_read_start(sock->uv.stream, alloc_inbuf_ssl, on_read_ssl);
-}
-
-void do_read_stop(h2o_socket_t *_sock)
-{
- struct st_h2o_uv_socket_t *sock = (struct st_h2o_uv_socket_t *)_sock;
- uv_read_stop(sock->uv.stream);
-}
-
-void do_write(h2o_socket_t *_sock, h2o_iovec_t *bufs, size_t bufcnt, h2o_socket_cb cb)
-{
- struct st_h2o_uv_socket_t *sock = (struct st_h2o_uv_socket_t *)_sock;
-
- assert(sock->super._cb.write == NULL);
- sock->super._cb.write = cb;
-
- uv_write(&sock->_wreq, sock->uv.stream, (uv_buf_t *)bufs, (int)bufcnt, on_do_write_complete);
-}
-
-static struct st_h2o_uv_socket_t *create_socket(h2o_loop_t *loop)
-{
- uv_tcp_t *tcp = h2o_mem_alloc(sizeof(*tcp));
-
- if (uv_tcp_init(loop, tcp) != 0) {
- free(tcp);
- return NULL;
- }
- return (void *)h2o_uv_socket_create((void *)tcp, (uv_close_cb)free);
-}
-
-int do_export(h2o_socket_t *_sock, h2o_socket_export_t *info)
-{
- struct st_h2o_uv_socket_t *sock = (void *)_sock;
- uv_os_fd_t fd;
-
- if (uv_fileno((uv_handle_t *)sock->uv.stream, &fd) != 0)
- return -1;
- /* FIXME: consider how to overcome the epoll(2) problem; man says,
- * "even after a file descriptor that is part of an epoll set has been closed,
- * events may be reported for that file descriptor if other file descriptors
- * referring to the same underlying file description remain open"
- */
- if ((info->fd = dup(fd)) == -1)
- return -1;
- return 0;
-}
-
-h2o_socket_t *do_import(h2o_loop_t *loop, h2o_socket_export_t *info)
-{
- struct st_h2o_uv_socket_t *sock = create_socket(loop);
-
- if (sock == NULL)
- return NULL;
- if (uv_tcp_open((uv_tcp_t *)sock->uv.stream, info->fd) != 0) {
- h2o_socket_close(&sock->super);
- return NULL;
- }
-
- return &sock->super;
-}
-
-h2o_socket_t *h2o_uv_socket_create(uv_stream_t *stream, uv_close_cb close_cb)
-{
- struct st_h2o_uv_socket_t *sock = h2o_mem_alloc(sizeof(*sock));
-
- memset(sock, 0, sizeof(*sock));
- h2o_buffer_init(&sock->super.input, &h2o_socket_buffer_prototype);
- sock->uv.stream = stream;
- sock->uv.close_cb = close_cb;
- stream->data = sock;
- return &sock->super;
-}
-
-static void on_connect(uv_connect_t *conn, int status)
-{
- if (status == UV_ECANCELED)
- return;
- struct st_h2o_uv_socket_t *sock = H2O_STRUCT_FROM_MEMBER(struct st_h2o_uv_socket_t, _creq, conn);
- h2o_socket_cb cb = sock->super._cb.write;
- sock->super._cb.write = NULL;
- cb(&sock->super, status == 0 ? NULL : h2o_socket_error_conn_fail);
-}
-
-h2o_loop_t *h2o_socket_get_loop(h2o_socket_t *_sock)
-{
- struct st_h2o_uv_socket_t *sock = (void *)_sock;
- return sock->uv.stream->loop;
-}
-
-h2o_socket_t *h2o_socket_connect(h2o_loop_t *loop, struct sockaddr *addr, socklen_t addrlen, h2o_socket_cb cb)
-{
- struct st_h2o_uv_socket_t *sock = create_socket(loop);
-
- if (sock == NULL)
- return NULL;
- if (uv_tcp_connect(&sock->_creq, (void *)sock->uv.stream, addr, on_connect) != 0) {
- h2o_socket_close(&sock->super);
- return NULL;
- }
- sock->super._cb.write = cb;
- return &sock->super;
-}
-
-socklen_t h2o_socket_getsockname(h2o_socket_t *_sock, struct sockaddr *sa)
-{
- struct st_h2o_uv_socket_t *sock = (void *)_sock;
- int len = sizeof(struct sockaddr_storage);
- if (uv_tcp_getsockname((void *)sock->uv.stream, sa, &len) != 0)
- return 0;
- return (socklen_t)len;
-}
-
-socklen_t get_peername_uncached(h2o_socket_t *_sock, struct sockaddr *sa)
-{
- struct st_h2o_uv_socket_t *sock = (void *)_sock;
- int len = sizeof(struct sockaddr_storage);
- if (uv_tcp_getpeername((void *)sock->uv.stream, sa, &len) != 0)
- return 0;
- return (socklen_t)len;
-}
-
-static void on_timeout(uv_timer_t *timer)
-{
- h2o_timeout_t *timeout = H2O_STRUCT_FROM_MEMBER(h2o_timeout_t, _backend.timer, timer);
-
- h2o_timeout_run(timer->loop, timeout, h2o_now(timer->loop));
- if (!h2o_linklist_is_empty(&timeout->_entries))
- schedule_timer(timeout);
-}
-
-void schedule_timer(h2o_timeout_t *timeout)
-{
- h2o_timeout_entry_t *entry = H2O_STRUCT_FROM_MEMBER(h2o_timeout_entry_t, _link, timeout->_entries.next);
- uv_timer_start(&timeout->_backend.timer, on_timeout,
- entry->registered_at + timeout->timeout - h2o_now(timeout->_backend.timer.loop), 0);
-}
-
-void h2o_timeout__do_init(h2o_loop_t *loop, h2o_timeout_t *timeout)
-{
- uv_timer_init(loop, &timeout->_backend.timer);
-}
-
-void h2o_timeout__do_dispose(h2o_loop_t *loop, h2o_timeout_t *timeout)
-{
- uv_close((uv_handle_t *)&timeout->_backend.timer, NULL);
-}
-
-void h2o_timeout__do_link(h2o_loop_t *loop, h2o_timeout_t *timeout, h2o_timeout_entry_t *entry)
-{
- /* register the timer if the entry just being added is the only entry */
- if (timeout->_entries.next == &entry->_link)
- schedule_timer(timeout);
-}
-
-void h2o_timeout__do_post_callback(h2o_loop_t *loop)
-{
- /* nothing to do */
-}
diff --git a/web/server/h2o/libh2o/lib/common/socketpool.c b/web/server/h2o/libh2o/lib/common/socketpool.c
deleted file mode 100644
index da69933f7..000000000
--- a/web/server/h2o/libh2o/lib/common/socketpool.c
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * Copyright (c) 2014-2016 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 <assert.h>
-#include <errno.h>
-#include <netdb.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <netinet/in.h>
-#include "h2o/hostinfo.h"
-#include "h2o/linklist.h"
-#include "h2o/socketpool.h"
-#include "h2o/string_.h"
-#include "h2o/timeout.h"
-
-struct pool_entry_t {
- h2o_socket_export_t sockinfo;
- h2o_linklist_t link;
- uint64_t added_at;
-};
-
-struct st_h2o_socketpool_connect_request_t {
- void *data;
- h2o_socketpool_connect_cb cb;
- h2o_socketpool_t *pool;
- h2o_loop_t *loop;
- h2o_hostinfo_getaddr_req_t *getaddr_req;
- h2o_socket_t *sock;
-};
-
-static void destroy_detached(struct pool_entry_t *entry)
-{
- h2o_socket_dispose_export(&entry->sockinfo);
- free(entry);
-}
-
-static void destroy_attached(struct pool_entry_t *entry)
-{
- h2o_linklist_unlink(&entry->link);
- destroy_detached(entry);
-}
-
-static void destroy_expired(h2o_socketpool_t *pool)
-{
- /* caller should lock the mutex */
- uint64_t expire_before = h2o_now(pool->_interval_cb.loop) - pool->timeout;
- while (!h2o_linklist_is_empty(&pool->_shared.sockets)) {
- struct pool_entry_t *entry = H2O_STRUCT_FROM_MEMBER(struct pool_entry_t, link, pool->_shared.sockets.next);
- if (entry->added_at > expire_before)
- break;
- destroy_attached(entry);
- __sync_sub_and_fetch(&pool->_shared.count, 1);
- }
-}
-
-static void on_timeout(h2o_timeout_entry_t *timeout_entry)
-{
- /* FIXME decrease the frequency of this function being called; the expiration
- * check can be (should be) performed in the `connect` fuction as well
- */
- h2o_socketpool_t *pool = H2O_STRUCT_FROM_MEMBER(h2o_socketpool_t, _interval_cb.entry, timeout_entry);
-
- if (pthread_mutex_trylock(&pool->_shared.mutex) == 0) {
- destroy_expired(pool);
- pthread_mutex_unlock(&pool->_shared.mutex);
- }
-
- h2o_timeout_link(pool->_interval_cb.loop, &pool->_interval_cb.timeout, &pool->_interval_cb.entry);
-}
-
-static void common_init(h2o_socketpool_t *pool, h2o_socketpool_type_t type, h2o_iovec_t host, int is_ssl, size_t capacity)
-{
- memset(pool, 0, sizeof(*pool));
-
- pool->type = type;
- pool->peer.host = h2o_strdup(NULL, host.base, host.len);
- pool->is_ssl = is_ssl;
- pool->capacity = capacity;
- pool->timeout = UINT64_MAX;
-
- pthread_mutex_init(&pool->_shared.mutex, NULL);
- h2o_linklist_init_anchor(&pool->_shared.sockets);
-}
-
-void h2o_socketpool_init_by_address(h2o_socketpool_t *pool, struct sockaddr *sa, socklen_t salen, int is_ssl, size_t capacity)
-{
- char host[NI_MAXHOST];
- size_t host_len;
-
- assert(salen <= sizeof(pool->peer.sockaddr.bytes));
-
- if ((host_len = h2o_socket_getnumerichost(sa, salen, host)) == SIZE_MAX) {
- if (sa->sa_family != AF_UNIX)
- h2o_fatal("failed to convert a non-unix socket address to a numerical representation");
- /* use the sockaddr_un::sun_path as the SNI indicator (is that the right thing to do?) */
- strcpy(host, ((struct sockaddr_un *)sa)->sun_path);
- host_len = strlen(host);
- }
-
- common_init(pool, H2O_SOCKETPOOL_TYPE_SOCKADDR, h2o_iovec_init(host, host_len), is_ssl, capacity);
- memcpy(&pool->peer.sockaddr.bytes, sa, salen);
- pool->peer.sockaddr.len = salen;
-}
-
-void h2o_socketpool_init_by_hostport(h2o_socketpool_t *pool, h2o_iovec_t host, uint16_t port, int is_ssl, size_t capacity)
-{
- struct sockaddr_in sin;
- memset(&sin, 0, sizeof(sin));
-
- if (h2o_hostinfo_aton(host, &sin.sin_addr) == 0) {
- sin.sin_family = AF_INET;
- sin.sin_port = htons(port);
- h2o_socketpool_init_by_address(pool, (void *)&sin, sizeof(sin), is_ssl, capacity);
- return;
- }
-
- common_init(pool, H2O_SOCKETPOOL_TYPE_NAMED, host, is_ssl, capacity);
- pool->peer.named_serv.base = h2o_mem_alloc(sizeof(H2O_UINT16_LONGEST_STR));
- pool->peer.named_serv.len = sprintf(pool->peer.named_serv.base, "%u", (unsigned)port);
-}
-
-void h2o_socketpool_dispose(h2o_socketpool_t *pool)
-{
- pthread_mutex_lock(&pool->_shared.mutex);
- while (!h2o_linklist_is_empty(&pool->_shared.sockets)) {
- struct pool_entry_t *entry = H2O_STRUCT_FROM_MEMBER(struct pool_entry_t, link, pool->_shared.sockets.next);
- destroy_attached(entry);
- __sync_sub_and_fetch(&pool->_shared.count, 1);
- }
- pthread_mutex_unlock(&pool->_shared.mutex);
- pthread_mutex_destroy(&pool->_shared.mutex);
-
- if (pool->_interval_cb.loop != NULL) {
- h2o_timeout_unlink(&pool->_interval_cb.entry);
- h2o_timeout_dispose(pool->_interval_cb.loop, &pool->_interval_cb.timeout);
- }
- free(pool->peer.host.base);
- switch (pool->type) {
- case H2O_SOCKETPOOL_TYPE_NAMED:
- free(pool->peer.named_serv.base);
- break;
- case H2O_SOCKETPOOL_TYPE_SOCKADDR:
- break;
- }
-}
-
-void h2o_socketpool_set_timeout(h2o_socketpool_t *pool, h2o_loop_t *loop, uint64_t msec)
-{
- pool->timeout = msec;
-
- pool->_interval_cb.loop = loop;
- h2o_timeout_init(loop, &pool->_interval_cb.timeout, 1000);
- pool->_interval_cb.entry.cb = on_timeout;
-
- h2o_timeout_link(loop, &pool->_interval_cb.timeout, &pool->_interval_cb.entry);
-}
-
-static void call_connect_cb(h2o_socketpool_connect_request_t *req, const char *errstr)
-{
- h2o_socketpool_connect_cb cb = req->cb;
- h2o_socket_t *sock = req->sock;
- void *data = req->data;
-
- free(req);
- cb(sock, errstr, data);
-}
-
-static void on_connect(h2o_socket_t *sock, const char *err)
-{
- h2o_socketpool_connect_request_t *req = sock->data;
- const char *errstr = NULL;
-
- assert(req->sock == sock);
-
- if (err != NULL) {
- h2o_socket_close(sock);
- req->sock = NULL;
- errstr = "connection failed";
- }
- call_connect_cb(req, errstr);
-}
-
-static void on_close(void *data)
-{
- h2o_socketpool_t *pool = data;
- __sync_sub_and_fetch(&pool->_shared.count, 1);
-}
-
-static void start_connect(h2o_socketpool_connect_request_t *req, struct sockaddr *addr, socklen_t addrlen)
-{
- req->sock = h2o_socket_connect(req->loop, addr, addrlen, on_connect);
- if (req->sock == NULL) {
- __sync_sub_and_fetch(&req->pool->_shared.count, 1);
- call_connect_cb(req, "failed to connect to host");
- return;
- }
- req->sock->data = req;
- req->sock->on_close.cb = on_close;
- req->sock->on_close.data = req->pool;
-}
-
-static void on_getaddr(h2o_hostinfo_getaddr_req_t *getaddr_req, const char *errstr, struct addrinfo *res, void *_req)
-{
- h2o_socketpool_connect_request_t *req = _req;
-
- assert(getaddr_req == req->getaddr_req);
- req->getaddr_req = NULL;
-
- if (errstr != NULL) {
- __sync_sub_and_fetch(&req->pool->_shared.count, 1);
- call_connect_cb(req, errstr);
- return;
- }
-
- struct addrinfo *selected = h2o_hostinfo_select_one(res);
- start_connect(req, selected->ai_addr, selected->ai_addrlen);
-}
-
-void h2o_socketpool_connect(h2o_socketpool_connect_request_t **_req, h2o_socketpool_t *pool, h2o_loop_t *loop,
- h2o_multithread_receiver_t *getaddr_receiver, h2o_socketpool_connect_cb cb, void *data)
-{
- struct pool_entry_t *entry = NULL;
-
- if (_req != NULL)
- *_req = NULL;
-
- /* fetch an entry and return it */
- pthread_mutex_lock(&pool->_shared.mutex);
- destroy_expired(pool);
- while (1) {
- if (h2o_linklist_is_empty(&pool->_shared.sockets))
- break;
- entry = H2O_STRUCT_FROM_MEMBER(struct pool_entry_t, link, pool->_shared.sockets.next);
- h2o_linklist_unlink(&entry->link);
- pthread_mutex_unlock(&pool->_shared.mutex);
-
- /* test if the connection is still alive */
- char buf[1];
- ssize_t rret = recv(entry->sockinfo.fd, buf, 1, MSG_PEEK);
- if (rret == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
- /* yes! return it */
- h2o_socket_t *sock = h2o_socket_import(loop, &entry->sockinfo);
- free(entry);
- sock->on_close.cb = on_close;
- sock->on_close.data = pool;
- cb(sock, NULL, data);
- return;
- }
-
- /* connection is dead, report, close, and retry */
- if (rret <= 0) {
- static long counter = 0;
- if (__sync_fetch_and_add(&counter, 1) == 0)
- fprintf(stderr, "[WARN] detected close by upstream before the expected timeout (see issue #679)\n");
- } else {
- static long counter = 0;
- if (__sync_fetch_and_add(&counter, 1) == 0)
- fprintf(stderr, "[WARN] unexpectedly received data to a pooled socket (see issue #679)\n");
- }
- destroy_detached(entry);
- pthread_mutex_lock(&pool->_shared.mutex);
- }
- pthread_mutex_unlock(&pool->_shared.mutex);
-
- /* FIXME repsect `capacity` */
- __sync_add_and_fetch(&pool->_shared.count, 1);
-
- /* prepare request object */
- h2o_socketpool_connect_request_t *req = h2o_mem_alloc(sizeof(*req));
- *req = (h2o_socketpool_connect_request_t){data, cb, pool, loop};
- if (_req != NULL)
- *_req = req;
-
- switch (pool->type) {
- case H2O_SOCKETPOOL_TYPE_NAMED:
- /* resolve the name, and connect */
- req->getaddr_req = h2o_hostinfo_getaddr(getaddr_receiver, pool->peer.host, pool->peer.named_serv, AF_UNSPEC, SOCK_STREAM,
- IPPROTO_TCP, AI_ADDRCONFIG | AI_NUMERICSERV, on_getaddr, req);
- break;
- case H2O_SOCKETPOOL_TYPE_SOCKADDR:
- /* connect (using sockaddr_in) */
- start_connect(req, (void *)&pool->peer.sockaddr.bytes, pool->peer.sockaddr.len);
- break;
- }
-}
-
-void h2o_socketpool_cancel_connect(h2o_socketpool_connect_request_t *req)
-{
- if (req->getaddr_req != NULL) {
- h2o_hostinfo_getaddr_cancel(req->getaddr_req);
- req->getaddr_req = NULL;
- }
- if (req->sock != NULL)
- h2o_socket_close(req->sock);
- free(req);
-}
-
-int h2o_socketpool_return(h2o_socketpool_t *pool, h2o_socket_t *sock)
-{
- struct pool_entry_t *entry;
-
- /* reset the on_close callback */
- assert(sock->on_close.data == pool);
- sock->on_close.cb = NULL;
- sock->on_close.data = NULL;
-
- entry = h2o_mem_alloc(sizeof(*entry));
- if (h2o_socket_export(sock, &entry->sockinfo) != 0) {
- free(entry);
- __sync_sub_and_fetch(&pool->_shared.count, 1);
- return -1;
- }
- memset(&entry->link, 0, sizeof(entry->link));
- entry->added_at = h2o_now(h2o_socket_get_loop(sock));
-
- pthread_mutex_lock(&pool->_shared.mutex);
- destroy_expired(pool);
- h2o_linklist_insert(&pool->_shared.sockets, &entry->link);
- pthread_mutex_unlock(&pool->_shared.mutex);
-
- return 0;
-}
diff --git a/web/server/h2o/libh2o/lib/common/string.c b/web/server/h2o/libh2o/lib/common/string.c
deleted file mode 100644
index 3c068f3ad..000000000
--- a/web/server/h2o/libh2o/lib/common/string.c
+++ /dev/null
@@ -1,594 +0,0 @@
-/*
- * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku, Justin Zhu, Fastly, Inc.
- *
- * 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 <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include "h2o/string_.h"
-
-h2o_iovec_t h2o_strdup(h2o_mem_pool_t *pool, const char *s, size_t slen)
-{
- h2o_iovec_t ret;
-
- if (slen == SIZE_MAX)
- slen = strlen(s);
-
- if (pool != NULL) {
- ret.base = h2o_mem_alloc_pool(pool, slen + 1);
- } else {
- ret.base = h2o_mem_alloc(slen + 1);
- }
- h2o_memcpy(ret.base, s, slen);
- ret.base[slen] = '\0';
- ret.len = slen;
- return ret;
-}
-
-h2o_iovec_t h2o_strdup_shared(h2o_mem_pool_t *pool, const char *s, size_t slen)
-{
- h2o_iovec_t ret;
-
- if (slen == SIZE_MAX)
- slen = strlen(s);
-
- ret.base = h2o_mem_alloc_shared(pool, slen + 1, NULL);
- memcpy(ret.base, s, slen);
- ret.base[slen] = '\0';
- ret.len = slen;
- return ret;
-}
-
-h2o_iovec_t h2o_strdup_slashed(h2o_mem_pool_t *pool, const char *src, size_t len)
-{
- h2o_iovec_t ret;
-
- ret.len = len != SIZE_MAX ? len : strlen(src);
- ret.base = pool != NULL ? h2o_mem_alloc_pool(pool, ret.len + 2) : h2o_mem_alloc(ret.len + 2);
- memcpy(ret.base, src, ret.len);
- if (ret.len != 0 && ret.base[ret.len - 1] != '/')
- ret.base[ret.len++] = '/';
- ret.base[ret.len] = '\0';
-
- return ret;
-}
-
-int h2o__lcstris_core(const char *target, const char *test, size_t test_len)
-{
- for (; test_len != 0; --test_len)
- if (h2o_tolower(*target++) != *test++)
- return 0;
- return 1;
-}
-
-size_t h2o_strtosize(const char *s, size_t len)
-{
- uint64_t v = 0, m = 1;
- const char *p = s + len;
-
- if (len == 0)
- goto Error;
-
- while (1) {
- int ch = *--p;
- if (!('0' <= ch && ch <= '9'))
- goto Error;
- v += (ch - '0') * m;
- if (p == s)
- break;
- m *= 10;
- /* do not even try to overflow */
- if (m == 10000000000000000000ULL)
- goto Error;
- }
-
- if (v >= SIZE_MAX)
- goto Error;
- return v;
-
-Error:
- return SIZE_MAX;
-}
-
-size_t h2o_strtosizefwd(char **s, size_t len)
-{
- uint64_t v, c;
- char *p = *s, *p_end = *s + len;
-
- if (len == 0)
- goto Error;
-
- int ch = *p++;
- if (!('0' <= ch && ch <= '9'))
- goto Error;
- v = ch - '0';
- c = 1;
-
- while (1) {
- ch = *p;
- if (!('0' <= ch && ch <= '9'))
- break;
- v *= 10;
- v += ch - '0';
- p++;
- c++;
- if (p == p_end)
- break;
- /* similar as above, do not even try to overflow */
- if (c == 20)
- goto Error;
- }
-
- if (v >= SIZE_MAX)
- goto Error;
- *s = p;
- return v;
-
-Error:
- return SIZE_MAX;
-}
-
-static uint32_t decode_base64url_quad(const char *src)
-{
- const char *src_end = src + 4;
- uint32_t decoded = 0;
-
- while (1) {
- if ('A' <= *src && *src <= 'Z') {
- decoded |= *src - 'A';
- } else if ('a' <= *src && *src <= 'z') {
- decoded |= *src - 'a' + 26;
- } else if ('0' <= *src && *src <= '9') {
- decoded |= *src - '0' + 52;
- } else if (*src == '-') {
- decoded |= 62;
- } else if (*src == '_') {
- decoded |= 63;
-#if 1 /* curl uses normal base64 */
- } else if (*src == '+') {
- decoded |= 62;
- } else if (*src == '/') {
- decoded |= 63;
-#endif
- } else {
- return UINT32_MAX;
- }
- if (++src == src_end)
- break;
- decoded <<= 6;
- }
-
- return decoded;
-}
-
-h2o_iovec_t h2o_decode_base64url(h2o_mem_pool_t *pool, const char *src, size_t len)
-{
- h2o_iovec_t decoded;
- uint32_t t;
- uint8_t *dst;
- char remaining_input[4];
-
- decoded.len = len * 3 / 4;
- decoded.base = pool != NULL ? h2o_mem_alloc_pool(pool, decoded.len + 1) : h2o_mem_alloc(decoded.len + 1);
- dst = (uint8_t *)decoded.base;
-
- while (len >= 4) {
- if ((t = decode_base64url_quad(src)) == UINT32_MAX)
- goto Error;
- *dst++ = t >> 16;
- *dst++ = t >> 8;
- *dst++ = t;
- src += 4;
- len -= 4;
- }
- switch (len) {
- case 0:
- break;
- case 1:
- goto Error;
- case 2:
- remaining_input[0] = *src++;
- remaining_input[1] = *src++;
- remaining_input[2] = 'A';
- remaining_input[3] = 'A';
- if ((t = decode_base64url_quad(remaining_input)) == UINT32_MAX)
- goto Error;
- *dst++ = t >> 16;
- break;
- case 3:
- remaining_input[0] = *src++;
- remaining_input[1] = *src++;
- remaining_input[2] = *src++;
- remaining_input[3] = 'A';
- if ((t = decode_base64url_quad(remaining_input)) == UINT32_MAX)
- goto Error;
- *dst++ = t >> 16;
- *dst++ = t >> 8;
- break;
- }
-
- assert((char *)dst - decoded.base == decoded.len);
- decoded.base[decoded.len] = '\0';
-
- return decoded;
-
-Error:
- if (pool == NULL)
- free(decoded.base);
- return h2o_iovec_init(NULL, 0);
-}
-
-size_t h2o_base64_encode(char *_dst, const void *_src, size_t len, int url_encoded)
-{
- static const char *MAP = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789+/";
- static const char *MAP_URL_ENCODED = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789-_";
-
- char *dst = _dst;
- const uint8_t *src = _src;
- const char *map = url_encoded ? MAP_URL_ENCODED : MAP;
- uint32_t quad;
-
- for (; len >= 3; src += 3, len -= 3) {
- quad = ((uint32_t)src[0] << 16) | ((uint32_t)src[1] << 8) | src[2];
- *dst++ = map[quad >> 18];
- *dst++ = map[(quad >> 12) & 63];
- *dst++ = map[(quad >> 6) & 63];
- *dst++ = map[quad & 63];
- }
- if (len != 0) {
- quad = (uint32_t)src[0] << 16;
- *dst++ = map[quad >> 18];
- if (len == 2) {
- quad |= (uint32_t)src[1] << 8;
- *dst++ = map[(quad >> 12) & 63];
- *dst++ = map[(quad >> 6) & 63];
- if (!url_encoded)
- *dst++ = '=';
- } else {
- *dst++ = map[(quad >> 12) & 63];
- if (!url_encoded) {
- *dst++ = '=';
- *dst++ = '=';
- }
- }
- }
-
- *dst = '\0';
- return dst - _dst;
-}
-
-static int decode_hex(int ch)
-{
- if ('0' <= ch && ch <= '9')
- return ch - '0';
- if ('A' <= ch && ch <= 'F')
- return ch - 'A' + 0xa;
- if ('a' <= ch && ch <= 'f')
- return ch - 'a' + 0xa;
- return -1;
-}
-
-int h2o_hex_decode(void *_dst, const char *src, size_t src_len)
-{
- unsigned char *dst = _dst;
-
- if (src_len % 2 != 0)
- return -1;
- for (; src_len != 0; src_len -= 2) {
- int hi, lo;
- if ((hi = decode_hex(*src++)) == -1 || (lo = decode_hex(*src++)) == -1)
- return -1;
- *dst++ = (hi << 4) | lo;
- }
- return 0;
-}
-
-void h2o_hex_encode(char *dst, const void *_src, size_t src_len)
-{
- const unsigned char *src = _src, *src_end = src + src_len;
- for (; src != src_end; ++src) {
- *dst++ = "0123456789abcdef"[*src >> 4];
- *dst++ = "0123456789abcdef"[*src & 0xf];
- }
- *dst = '\0';
-}
-
-h2o_iovec_t h2o_uri_escape(h2o_mem_pool_t *pool, const char *s, size_t l, const char *preserve_chars)
-{
- h2o_iovec_t encoded;
- size_t i, capacity = l * 3 + 1;
-
- encoded.base = pool != NULL ? h2o_mem_alloc_pool(pool, capacity) : h2o_mem_alloc(capacity);
- encoded.len = 0;
-
- /* RFC 3986:
- path-noscheme = segment-nz-nc *( "/" segment )
- segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
- unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
- sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
- / "*" / "+" / "," / ";" / "="
- */
- for (i = 0; i != l; ++i) {
- int ch = s[i];
- if (('A' <= ch && ch <= 'Z') || ('a' <= ch && ch <= 'z') || ('0' <= ch && ch <= '9') || ch == '-' || ch == '.' ||
- ch == '_' || ch == '~' || ch == '!' || ch == '$' || ch == '&' || ch == '\'' || ch == '(' || ch == ')' || ch == '*' ||
- ch == '+' || ch == ',' || ch == ';' || ch == '=' ||
- (ch != '\0' && preserve_chars != NULL && strchr(preserve_chars, ch) != NULL)) {
- encoded.base[encoded.len++] = ch;
- } else {
- encoded.base[encoded.len++] = '%';
- encoded.base[encoded.len++] = "0123456789ABCDEF"[(ch >> 4) & 0xf];
- encoded.base[encoded.len++] = "0123456789ABCDEF"[ch & 0xf];
- }
- }
- encoded.base[encoded.len] = '\0';
-
- return encoded;
-}
-
-h2o_iovec_t h2o_get_filext(const char *path, size_t len)
-{
- const char *end = path + len, *p = end;
-
- while (--p != path) {
- if (*p == '.') {
- return h2o_iovec_init(p + 1, end - (p + 1));
- } else if (*p == '/') {
- break;
- }
- }
- return h2o_iovec_init(NULL, 0);
-}
-
-static int is_ws(int ch)
-{
- return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n';
-}
-
-h2o_iovec_t h2o_str_stripws(const char *s, size_t len)
-{
- const char *end = s + len;
-
- while (s != end) {
- if (!is_ws(*s))
- break;
- ++s;
- }
- while (s != end) {
- if (!is_ws(end[-1]))
- break;
- --end;
- }
- return h2o_iovec_init(s, end - s);
-}
-
-size_t h2o_strstr(const char *haysack, size_t haysack_len, const char *needle, size_t needle_len)
-{
- /* TODO optimize */
- if (haysack_len >= needle_len) {
- size_t off, max = haysack_len - needle_len + 1;
- if (needle_len == 0)
- return 0;
- for (off = 0; off != max; ++off)
- if (haysack[off] == needle[0] && memcmp(haysack + off + 1, needle + 1, needle_len - 1) == 0)
- return off;
- }
- return SIZE_MAX;
-}
-
-/* note: returns a zero-width match as well */
-const char *h2o_next_token(h2o_iovec_t *iter, int separator, size_t *element_len, h2o_iovec_t *value)
-{
- const char *cur = iter->base, *end = iter->base + iter->len, *token_start, *token_end;
-
- /* find start */
- for (;; ++cur) {
- if (cur == end)
- return NULL;
- if (!(*cur == ' ' || *cur == '\t'))
- break;
- }
- token_start = cur;
- token_end = cur;
-
- /* find last */
- for (;; ++cur) {
- if (cur == end)
- break;
- if (*cur == separator) {
- ++cur;
- break;
- }
- if (*cur == ',') {
- if (token_start == cur) {
- ++cur;
- token_end = cur;
- }
- break;
- }
- if (value != NULL && *cur == '=') {
- ++cur;
- goto FindValue;
- }
- if (!(*cur == ' ' || *cur == '\t'))
- token_end = cur + 1;
- }
-
- /* found */
- *iter = h2o_iovec_init(cur, end - cur);
- *element_len = token_end - token_start;
- if (value != NULL)
- *value = (h2o_iovec_t){NULL};
- return token_start;
-
-FindValue:
- *iter = h2o_iovec_init(cur, end - cur);
- *element_len = token_end - token_start;
- if ((value->base = (char *)h2o_next_token(iter, separator, &value->len, NULL)) == NULL) {
- *value = (h2o_iovec_t){"", 0};
- } else if (h2o_memis(value->base, value->len, H2O_STRLIT(","))) {
- *value = (h2o_iovec_t){"", 0};
- iter->base -= 1;
- iter->len += 1;
- }
- return token_start;
-}
-
-int h2o_contains_token(const char *haysack, size_t haysack_len, const char *needle, size_t needle_len, int separator)
-{
- h2o_iovec_t iter = h2o_iovec_init(haysack, haysack_len);
- const char *token = NULL;
- size_t token_len = 0;
-
- while ((token = h2o_next_token(&iter, separator, &token_len, NULL)) != NULL) {
- if (h2o_lcstris(token, token_len, needle, needle_len)) {
- return 1;
- }
- }
- return 0;
-}
-
-h2o_iovec_t h2o_htmlescape(h2o_mem_pool_t *pool, const char *src, size_t len)
-{
- const char *s, *end = src + len;
- size_t add_size = 0;
-
-#define ENTITY_MAP() \
- ENTITY('"', "&quot;"); \
- ENTITY('&', "&amp;"); \
- ENTITY('\'', "&#39;"); \
- ENTITY('<', "&lt;"); \
- ENTITY('>', "&gt;");
-
- for (s = src; s != end; ++s) {
- if ((unsigned)(unsigned char)*s - '"' <= '>' - '"') {
- switch (*s) {
-#define ENTITY(code, quoted) \
- case code: \
- add_size += sizeof(quoted) - 2; \
- break
- ENTITY_MAP()
-#undef ENTITY
- }
- }
- }
-
- /* escape and return the result if necessary */
- if (add_size != 0) {
- /* allocate buffer and fill in the chars that are known not to require escaping */
- h2o_iovec_t escaped = {h2o_mem_alloc_pool(pool, len + add_size + 1), 0};
- /* fill-in the rest */
- for (s = src; s != end; ++s) {
- switch (*s) {
-#define ENTITY(code, quoted) \
- case code: \
- memcpy(escaped.base + escaped.len, quoted, sizeof(quoted) - 1); \
- escaped.len += sizeof(quoted) - 1; \
- break
- ENTITY_MAP()
-#undef ENTITY
- default:
- escaped.base[escaped.len++] = *s;
- break;
- }
- }
- assert(escaped.len == len + add_size);
- escaped.base[escaped.len] = '\0';
-
- return escaped;
- }
-
-#undef ENTITY_MAP
-
- /* no need not escape; return the original */
- return h2o_iovec_init(src, len);
-}
-
-h2o_iovec_t h2o_concat_list(h2o_mem_pool_t *pool, h2o_iovec_t *list, size_t count)
-{
- h2o_iovec_t ret = {NULL, 0};
- size_t i;
-
- /* calc the length */
- for (i = 0; i != count; ++i) {
- ret.len += list[i].len;
- }
-
- /* allocate memory */
- if (pool != NULL)
- ret.base = h2o_mem_alloc_pool(pool, ret.len + 1);
- else
- ret.base = h2o_mem_alloc(ret.len + 1);
-
- /* concatenate */
- ret.len = 0;
- for (i = 0; i != count; ++i) {
- h2o_memcpy(ret.base + ret.len, list[i].base, list[i].len);
- ret.len += list[i].len;
- }
- ret.base[ret.len] = '\0';
-
- return ret;
-}
-
-int h2o_str_at_position(char *buf, const char *src, size_t src_len, int lineno, int column)
-{
- const char *src_end = src + src_len;
- int i;
-
- /* find the line */
- if (lineno <= 0 || column <= 0)
- return -1;
- for (--lineno; lineno != 0; --lineno) {
- do {
- if (src == src_end)
- return -1;
- } while (*src++ != '\n');
- }
-
- /* adjust the starting column */
- while (column > 40) {
- if (src != src_end)
- ++src;
- --column;
- }
-
- /* emit */
- for (i = 1; i <= 76; ++i) {
- if (src == src_end || *src == '\n')
- break;
- *buf++ = *src++;
- }
- if (i < column)
- column = i;
- *buf++ = '\n';
- for (i = 1; i < column; ++i)
- *buf++ = ' ';
- *buf++ = '^';
- *buf++ = '\n';
- *buf = '\0';
- return 0;
-}
diff --git a/web/server/h2o/libh2o/lib/common/time.c b/web/server/h2o/libh2o/lib/common/time.c
deleted file mode 100644
index 368143e78..000000000
--- a/web/server/h2o/libh2o/lib/common/time.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (c) 2015 DeNA Co., Ltd.
- *
- * 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 <assert.h>
-#include <stdio.h>
-#include <string.h>
-#include "h2o/time_.h"
-
-static char *emit_wday(char *dst, int wday)
-{
- memcpy(dst, ("SunMonTueWedThuFriSat") + wday * 3, 3);
- return dst + 3;
-}
-
-static char *emit_mon(char *dst, int mon)
-{
- memcpy(dst, ("JanFebMarAprMayJunJulAugSepOctNovDec") + mon * 3, 3);
- return dst + 3;
-}
-
-static char *emit_digits(char *dst, int n, size_t cnt)
-{
- char *p = dst + cnt;
-
- /* emit digits from back */
- do {
- *--p = '0' + n % 10;
- n /= 10;
- } while (p != dst);
-
- return dst + cnt;
-}
-
-void h2o_time2str_rfc1123(char *buf, struct tm *gmt)
-{
- char *p = buf;
-
- /* format: Fri, 19 Sep 2014 05:24:04 GMT */
- p = emit_wday(p, gmt->tm_wday);
- *p++ = ',';
- *p++ = ' ';
- p = emit_digits(p, gmt->tm_mday, 2);
- *p++ = ' ';
- p = emit_mon(p, gmt->tm_mon);
- *p++ = ' ';
- p = emit_digits(p, gmt->tm_year + 1900, 4);
- *p++ = ' ';
- p = emit_digits(p, gmt->tm_hour, 2);
- *p++ = ':';
- p = emit_digits(p, gmt->tm_min, 2);
- *p++ = ':';
- p = emit_digits(p, gmt->tm_sec, 2);
- memcpy(p, " GMT", 4);
- p += 4;
- *p = '\0';
-
- assert(p - buf == H2O_TIMESTR_RFC1123_LEN);
-}
-
-static int fetch_digits(const char *s, size_t n)
-{
- int value = 0;
- for (; n != 0; ++s, --n) {
- if (!('0' <= *s && *s <= '9'))
- return -1;
- value = value * 10 + *s - '0';
- }
- return value;
-}
-
-int h2o_time_parse_rfc1123(const char *s, size_t len, struct tm *tm)
-{
- if (len != H2O_TIMESTR_RFC1123_LEN)
- return -1;
-
-/* 1 2
- * 01234567890123456789012345678
- * Fri, 19 Sep 2014 05:24:04 GMT
- */
-
-#define FETCH(dst, pos, n) \
- if ((dst = fetch_digits(s + pos, n)) == -1) \
- return -1;
- FETCH(tm->tm_year, 12, 4);
- tm->tm_year -= 1900;
- /* month is parsed afterwards */
- FETCH(tm->tm_mday, 5, 2);
- FETCH(tm->tm_hour, 17, 2);
- FETCH(tm->tm_min, 20, 2);
- FETCH(tm->tm_sec, 23, 2);
-#undef FETCH
-
-#define PACK3(a, b, c) (((a)&0xff) << 16 | ((b)&0xff) << 8 | ((c)&0xff))
-#define MAP(c1, c2, c3, value) \
- case PACK3(c1, c2, c3): \
- tm->tm_mon = value; \
- break
- switch (PACK3(s[8], s[9], s[10])) {
- MAP('J', 'a', 'n', 0);
- MAP('F', 'e', 'b', 1);
- MAP('M', 'a', 'r', 2);
- MAP('A', 'p', 'r', 3);
- MAP('M', 'a', 'y', 4);
- MAP('J', 'u', 'n', 5);
- MAP('J', 'u', 'l', 6);
- MAP('A', 'u', 'g', 7);
- MAP('S', 'e', 'p', 8);
- MAP('O', 'c', 't', 9);
- MAP('N', 'o', 'v', 10);
- MAP('D', 'e', 'c', 11);
- default:
- return -1;
- }
-#undef MAP
-#undef PACK3
-
- return 0;
-}
-
-static int calc_gmt_offset(time_t t, struct tm *local)
-{
- struct tm gmt;
- int delta;
-
- gmtime_r(&t, &gmt);
- delta = (local->tm_hour - gmt.tm_hour) * 60 + (local->tm_min - gmt.tm_min);
-
- if (local->tm_yday != gmt.tm_yday) {
- int day_offset;
- if (local->tm_year == gmt.tm_year)
- day_offset = local->tm_yday - gmt.tm_yday;
- else
- day_offset = local->tm_year - gmt.tm_year;
- delta += day_offset * 24 * 60;
- }
- return delta;
-}
-
-void h2o_time2str_log(char *buf, time_t time)
-{
- struct tm localt;
- localtime_r(&time, &localt);
- int gmt_off = calc_gmt_offset(time, &localt);
- int gmt_sign;
-
- if (gmt_off >= 0) {
- gmt_sign = '+';
- } else {
- gmt_off = -gmt_off;
- gmt_sign = '-';
- }
-
- int len = sprintf(buf, "%02d/%s/%d:%02d:%02d:%02d %c%02d%02d", localt.tm_mday,
- ("Jan\0Feb\0Mar\0Apr\0May\0Jun\0Jul\0Aug\0Sep\0Oct\0Nov\0Dec\0") + localt.tm_mon * 4, localt.tm_year + 1900,
- localt.tm_hour, localt.tm_min, localt.tm_sec, gmt_sign, gmt_off / 60, gmt_off % 60);
- assert(len == H2O_TIMESTR_LOG_LEN);
-}
diff --git a/web/server/h2o/libh2o/lib/common/timeout.c b/web/server/h2o/libh2o/lib/common/timeout.c
deleted file mode 100644
index c50be0a3f..000000000
--- a/web/server/h2o/libh2o/lib/common/timeout.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (c) 2014 DeNA Co., Ltd.
- *
- * 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/timeout.h"
-
-void h2o_timeout_run(h2o_loop_t *loop, h2o_timeout_t *timeout, uint64_t now)
-{
- uint64_t max_registered_at = now - timeout->timeout;
-
- while (!h2o_linklist_is_empty(&timeout->_entries)) {
- h2o_timeout_entry_t *entry = H2O_STRUCT_FROM_MEMBER(h2o_timeout_entry_t, _link, timeout->_entries.next);
- if (entry->registered_at > max_registered_at) {
- break;
- }
- h2o_linklist_unlink(&entry->_link);
- entry->registered_at = 0;
- entry->cb(entry);
- h2o_timeout__do_post_callback(loop);
- }
-}
-
-uint64_t h2o_timeout_get_wake_at(h2o_linklist_t *timeouts)
-{
- h2o_linklist_t *node;
- uint64_t wake_at = UINT64_MAX;
-
- /* change wake_at to the minimum value of the timeouts */
- for (node = timeouts->next; node != timeouts; node = node->next) {
- h2o_timeout_t *timeout = H2O_STRUCT_FROM_MEMBER(h2o_timeout_t, _link, node);
- if (!h2o_linklist_is_empty(&timeout->_entries)) {
- h2o_timeout_entry_t *entry = H2O_STRUCT_FROM_MEMBER(h2o_timeout_entry_t, _link, timeout->_entries.next);
- uint64_t entry_wake_at = entry->registered_at + timeout->timeout;
- if (entry_wake_at < wake_at)
- wake_at = entry_wake_at;
- }
- }
-
- return wake_at;
-}
-
-void h2o_timeout_init(h2o_loop_t *loop, h2o_timeout_t *timeout, uint64_t millis)
-{
- memset(timeout, 0, sizeof(*timeout));
- timeout->timeout = millis;
- h2o_linklist_init_anchor(&timeout->_entries);
-
- h2o_timeout__do_init(loop, timeout);
-}
-
-void h2o_timeout_dispose(h2o_loop_t *loop, h2o_timeout_t *timeout)
-{
- assert(h2o_linklist_is_empty(&timeout->_entries));
- h2o_timeout__do_dispose(loop, timeout);
-}
-
-void h2o_timeout_link(h2o_loop_t *loop, h2o_timeout_t *timeout, h2o_timeout_entry_t *entry)
-{
- /* insert at tail, so that the entries are sorted in ascending order */
- h2o_linklist_insert(&timeout->_entries, &entry->_link);
- /* set data */
- entry->registered_at = h2o_now(loop);
-
- h2o_timeout__do_link(loop, timeout, entry);
-}
-
-void h2o_timeout_unlink(h2o_timeout_entry_t *entry)
-{
- if (h2o_linklist_is_linked(&entry->_link)) {
- h2o_linklist_unlink(&entry->_link);
- entry->registered_at = 0;
- }
-}
diff --git a/web/server/h2o/libh2o/lib/common/url.c b/web/server/h2o/libh2o/lib/common/url.c
deleted file mode 100644
index d65d18fb5..000000000
--- a/web/server/h2o/libh2o/lib/common/url.c
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- * Copyright (c) 2014,2015 DeNA Co., Ltd.
- *
- * 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 <sys/socket.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include "h2o/memory.h"
-#include "h2o/string_.h"
-#include "h2o/url.h"
-
-const h2o_url_scheme_t H2O_URL_SCHEME_HTTP = {{H2O_STRLIT("http")}, 80};
-const h2o_url_scheme_t H2O_URL_SCHEME_HTTPS = {{H2O_STRLIT("https")}, 443};
-
-static int decode_hex(int ch)
-{
- if ('0' <= ch && ch <= '9')
- return ch - '0';
- if ('A' <= ch && ch <= 'F')
- return ch - 'A' + 0xa;
- if ('a' <= ch && ch <= 'f')
- return ch - 'a' + 0xa;
- return -1;
-}
-
-static size_t handle_special_paths(const char *path, size_t off, size_t last_slash)
-{
- size_t orig_off = off, part_size = off - last_slash;
-
- if (part_size == 2 && path[off - 1] == '.') {
- --off;
- } else if (part_size == 3 && path[off - 2] == '.' && path[off - 1] == '.') {
- off -= 2;
- if (off > 1) {
- for (--off; path[off - 1] != '/'; --off)
- ;
- }
- }
- return orig_off - off;
-}
-
-/* Perform path normalization and URL decoding in one pass.
- * See h2o_req_t for the purpose of @norm_indexes. */
-static h2o_iovec_t rebuild_path(h2o_mem_pool_t *pool, const char *src, size_t src_len, size_t *query_at, size_t **norm_indexes)
-{
- char *dst;
- size_t src_off = 0, dst_off = 0, last_slash, rewind;
-
- { /* locate '?', and set len to the end of input path */
- const char *q = memchr(src, '?', src_len);
- if (q != NULL) {
- src_len = *query_at = q - src;
- } else {
- *query_at = SIZE_MAX;
- }
- }
-
- /* dst can be 1 byte more than src if src is missing the prefixing '/' */
- dst = h2o_mem_alloc_pool(pool, src_len + 1);
- *norm_indexes = h2o_mem_alloc_pool(pool, (src_len + 1) * sizeof(*norm_indexes[0]));
-
- if (src[0] == '/')
- src_off++;
- last_slash = dst_off;
- dst[dst_off] = '/';
- (*norm_indexes)[dst_off] = src_off;
- dst_off++;
-
- /* decode %xx */
- while (src_off < src_len) {
- int hi, lo;
- char decoded;
-
- if (src[src_off] == '%' && (src_off + 2 < src_len) && (hi = decode_hex(src[src_off + 1])) != -1 &&
- (lo = decode_hex(src[src_off + 2])) != -1) {
- decoded = (hi << 4) | lo;
- src_off += 3;
- } else {
- decoded = src[src_off++];
- }
- if (decoded == '/') {
- rewind = handle_special_paths(dst, dst_off, last_slash);
- if (rewind > 0) {
- dst_off -= rewind;
- last_slash = dst_off - 1;
- continue;
- }
- last_slash = dst_off;
- }
- dst[dst_off] = decoded;
- (*norm_indexes)[dst_off] = src_off;
- dst_off++;
- }
- rewind = handle_special_paths(dst, dst_off, last_slash);
- dst_off -= rewind;
-
- return h2o_iovec_init(dst, dst_off);
-}
-
-h2o_iovec_t h2o_url_normalize_path(h2o_mem_pool_t *pool, const char *path, size_t len, size_t *query_at, size_t **norm_indexes)
-{
- const char *p = path, *end = path + len;
- h2o_iovec_t ret;
-
- *query_at = SIZE_MAX;
- *norm_indexes = NULL;
-
- if (len == 0) {
- ret = h2o_iovec_init("/", 1);
- return ret;
- }
-
- if (path[0] != '/')
- goto Rewrite;
-
- for (; p + 1 < end; ++p) {
- if ((p[0] == '/' && p[1] == '.') || p[0] == '%') {
- /* detect false positives as well */
- goto Rewrite;
- } else if (p[0] == '?') {
- *query_at = p - path;
- goto Return;
- }
- }
- for (; p < end; ++p) {
- if (p[0] == '?') {
- *query_at = p - path;
- goto Return;
- }
- }
-
-Return:
- ret.base = (char *)path;
- ret.len = p - path;
- return ret;
-
-Rewrite:
- ret = rebuild_path(pool, path, len, query_at, norm_indexes);
- if (ret.len == 0)
- goto RewriteError;
- if (ret.base[0] != '/')
- goto RewriteError;
- if (h2o_strstr(ret.base, ret.len, H2O_STRLIT("/../")) != SIZE_MAX)
- goto RewriteError;
- if (ret.len >= 3 && memcmp(ret.base + ret.len - 3, "/..", 3) == 0)
- goto RewriteError;
- return ret;
-RewriteError:
- fprintf(stderr, "failed to normalize path: `%.*s` => `%.*s`\n", (int)len, path, (int)ret.len, ret.base);
- ret = h2o_iovec_init("/", 1);
- return ret;
-}
-
-static const char *parse_scheme(const char *s, const char *end, const h2o_url_scheme_t **scheme)
-{
- if (end - s >= 5 && memcmp(s, "http:", 5) == 0) {
- *scheme = &H2O_URL_SCHEME_HTTP;
- return s + 5;
- } else if (end - s >= 6 && memcmp(s, "https:", 6) == 0) {
- *scheme = &H2O_URL_SCHEME_HTTPS;
- return s + 6;
- }
- return NULL;
-}
-
-const char *h2o_url_parse_hostport(const char *s, size_t len, h2o_iovec_t *host, uint16_t *port)
-{
- const char *token_start = s, *token_end, *end = s + len;
-
- *port = 65535;
-
- if (token_start == end)
- return NULL;
-
- if (*token_start == '[') {
- /* is IPv6 address */
- ++token_start;
- if ((token_end = memchr(token_start, ']', end - token_start)) == NULL)
- return NULL;
- *host = h2o_iovec_init(token_start, token_end - token_start);
- token_start = token_end + 1;
- } else {
- for (token_end = token_start; !(token_end == end || *token_end == '/' || *token_end == ':'); ++token_end)
- ;
- *host = h2o_iovec_init(token_start, token_end - token_start);
- token_start = token_end;
- }
-
- /* disallow zero-length host */
- if (host->len == 0)
- return NULL;
-
- /* parse port */
- if (token_start != end && *token_start == ':') {
- size_t p;
- ++token_start;
- if ((token_end = memchr(token_start, '/', end - token_start)) == NULL)
- token_end = end;
- if ((p = h2o_strtosize(token_start, token_end - token_start)) >= 65535)
- return NULL;
- *port = (uint16_t)p;
- token_start = token_end;
- }
-
- return token_start;
-}
-
-static int parse_authority_and_path(const char *src, const char *url_end, h2o_url_t *parsed)
-{
- const char *p = h2o_url_parse_hostport(src, url_end - src, &parsed->host, &parsed->_port);
- if (p == NULL)
- return -1;
- parsed->authority = h2o_iovec_init(src, p - src);
- if (p == url_end) {
- parsed->path = h2o_iovec_init(H2O_STRLIT("/"));
- } else {
- if (*p != '/')
- return -1;
- parsed->path = h2o_iovec_init(p, url_end - p);
- }
- return 0;
-}
-
-int h2o_url_parse(const char *url, size_t url_len, h2o_url_t *parsed)
-{
- const char *url_end, *p;
-
- if (url_len == SIZE_MAX)
- url_len = strlen(url);
- url_end = url + url_len;
-
- /* check and skip scheme */
- if ((p = parse_scheme(url, url_end, &parsed->scheme)) == NULL)
- return -1;
-
- /* skip "//" */
- if (!(url_end - p >= 2 && p[0] == '/' && p[1] == '/'))
- return -1;
- p += 2;
-
- return parse_authority_and_path(p, url_end, parsed);
-}
-
-int h2o_url_parse_relative(const char *url, size_t url_len, h2o_url_t *parsed)
-{
- const char *url_end, *p;
-
- if (url_len == SIZE_MAX)
- url_len = strlen(url);
- url_end = url + url_len;
-
- /* obtain scheme and port number */
- if ((p = parse_scheme(url, url_end, &parsed->scheme)) == NULL) {
- parsed->scheme = NULL;
- p = url;
- }
-
- /* handle "//" */
- if (url_end - p >= 2 && p[0] == '/' && p[1] == '/')
- return parse_authority_and_path(p + 2, url_end, parsed);
-
- /* reset authority, host, port, and set path */
- parsed->authority = (h2o_iovec_t){NULL};
- parsed->host = (h2o_iovec_t){NULL};
- parsed->_port = 65535;
- parsed->path = h2o_iovec_init(p, url_end - p);
-
- return 0;
-}
-
-h2o_iovec_t h2o_url_resolve(h2o_mem_pool_t *pool, const h2o_url_t *base, const h2o_url_t *relative, h2o_url_t *dest)
-{
- h2o_iovec_t base_path, relative_path, ret;
-
- assert(base->path.len != 0);
- assert(base->path.base[0] == '/');
-
- if (relative == NULL) {
- /* build URL using base copied to dest */
- *dest = *base;
- base_path = base->path;
- relative_path = h2o_iovec_init(NULL, 0);
- goto Build;
- }
-
- /* scheme */
- dest->scheme = relative->scheme != NULL ? relative->scheme : base->scheme;
-
- /* authority (and host:port) */
- if (relative->authority.base != NULL) {
- assert(relative->host.base != NULL);
- dest->authority = relative->authority;
- dest->host = relative->host;
- dest->_port = relative->_port;
- } else {
- assert(relative->host.base == NULL);
- assert(relative->_port == 65535);
- dest->authority = base->authority;
- dest->host = base->host;
- dest->_port = base->_port;
- }
-
- /* path */
- base_path = base->path;
- if (relative->path.base != NULL) {
- relative_path = relative->path;
- h2o_url_resolve_path(&base_path, &relative_path);
- } else {
- assert(relative->path.len == 0);
- relative_path = (h2o_iovec_t){NULL};
- }
-
-Build:
- /* build the output */
- ret = h2o_concat(pool, dest->scheme->name, h2o_iovec_init(H2O_STRLIT("://")), dest->authority, base_path, relative_path);
- /* adjust dest */
- dest->authority.base = ret.base + dest->scheme->name.len + 3;
- dest->host.base = dest->authority.base;
- if (dest->authority.len != 0 && dest->authority.base[0] == '[')
- ++dest->host.base;
- dest->path.base = dest->authority.base + dest->authority.len;
- dest->path.len = ret.base + ret.len - dest->path.base;
-
- return ret;
-}
-
-void h2o_url_resolve_path(h2o_iovec_t *base, h2o_iovec_t *relative)
-{
- size_t base_path_len = base->len, rel_path_offset = 0;
-
- if (relative->len != 0 && relative->base[0] == '/') {
- base_path_len = 0;
- } else {
- /* relative path */
- while (base->base[--base_path_len] != '/')
- ;
- while (rel_path_offset != relative->len) {
- if (relative->base[rel_path_offset] == '.') {
- if (relative->len - rel_path_offset >= 2 && relative->base[rel_path_offset + 1] == '.' &&
- (relative->len - rel_path_offset == 2 || relative->base[rel_path_offset + 2] == '/')) {
- if (base_path_len != 0) {
- while (base->base[--base_path_len] != '/')
- ;
- }
- rel_path_offset += relative->len - rel_path_offset == 2 ? 2 : 3;
- continue;
- }
- if (relative->len - rel_path_offset == 1) {
- rel_path_offset += 1;
- continue;
- } else if (relative->base[rel_path_offset + 1] == '/') {
- rel_path_offset += 2;
- continue;
- }
- }
- break;
- }
- base_path_len += 1;
- }
-
- base->len = base_path_len;
- *relative = h2o_iovec_init(relative->base + rel_path_offset, relative->len - rel_path_offset);
-}
-
-void h2o_url_copy(h2o_mem_pool_t *pool, h2o_url_t *dest, const h2o_url_t *src)
-{
- dest->scheme = src->scheme;
- dest->authority = h2o_strdup(pool, src->authority.base, src->authority.len);
- dest->host = h2o_strdup(pool, src->host.base, src->host.len);
- dest->path = h2o_strdup(pool, src->path.base, src->path.len);
- dest->_port = src->_port;
-}
-
-const char *h2o_url_host_to_sun(h2o_iovec_t host, struct sockaddr_un *sa)
-{
-#define PREFIX "unix:"
-
- if (host.len < sizeof(PREFIX) - 1 || memcmp(host.base, PREFIX, sizeof(PREFIX) - 1) != 0)
- return h2o_url_host_to_sun_err_is_not_unix_socket;
-
- if (host.len - sizeof(PREFIX) - 1 >= sizeof(sa->sun_path))
- return "unix-domain socket path is too long";
-
- memset(sa, 0, sizeof(*sa));
- sa->sun_family = AF_UNIX;
- memcpy(sa->sun_path, host.base + sizeof(PREFIX) - 1, host.len - (sizeof(PREFIX) - 1));
- return NULL;
-
-#undef PREFIX
-}
-
-const char *h2o_url_host_to_sun_err_is_not_unix_socket = "supplied name does not look like an unix-domain socket";