diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-07-24 09:54:23 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-07-24 09:54:44 +0000 |
commit | 836b47cb7e99a977c5a23b059ca1d0b5065d310e (patch) | |
tree | 1604da8f482d02effa033c94a84be42bc0c848c3 /fluent-bit/lib/monkey/mk_server | |
parent | Releasing debian version 1.44.3-2. (diff) | |
download | netdata-836b47cb7e99a977c5a23b059ca1d0b5065d310e.tar.xz netdata-836b47cb7e99a977c5a23b059ca1d0b5065d310e.zip |
Merging upstream version 1.46.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'fluent-bit/lib/monkey/mk_server')
23 files changed, 0 insertions, 11302 deletions
diff --git a/fluent-bit/lib/monkey/mk_server/CMakeLists.txt b/fluent-bit/lib/monkey/mk_server/CMakeLists.txt deleted file mode 100644 index 457525e6..00000000 --- a/fluent-bit/lib/monkey/mk_server/CMakeLists.txt +++ /dev/null @@ -1,57 +0,0 @@ -set(CMAKE_POSITION_INDEPENDENT_CODE ON) - -set(src - monkey.c - mk_lib.c - mk_fifo.c - mk_mimetype.c - mk_vhost.c - mk_header.c - mk_config.c - mk_user.c - mk_utils.c - mk_stream.c - mk_scheduler.c - mk_http.c - mk_http_parser.c - mk_http_thread.c - mk_socket.c - mk_net.c - mk_clock.c - mk_cache.c - mk_server.c - mk_kernel.c - mk_plugin.c - ) - -if(MK_HTTP2) - set(src - ${src} - "mk_http2.c" - ) -endif() - -# Always build a static library, thats our core :) -add_library(monkey-core-static STATIC ${src}) -set_target_properties(monkey-core-static PROPERTIES OUTPUT_NAME monkey) -target_link_libraries(monkey-core-static mk_core ${CMAKE_THREAD_LIBS_INIT} ${STATIC_PLUGINS_LIBS} ${CMAKE_DL_LIBS} rbtree co) - -message(STATUS "LINKING ${STATIC_PLUGINS_LIBS}") - -if(NOT DEFINED MK_HAVE_REGEX) - target_link_libraries(monkey-core-static regex) -endif() - -# Linux Kqueue emulation -if(MK_HAVE_LINUX_KQUEUE) - target_link_libraries(monkey-core-static kqueue) -endif() - -# FreeBSD backtrace -if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") - target_link_libraries(monkey-core-static execinfo) -endif() - -if (CMAKE_SYSTEM_NAME MATCHES "SunOS") - target_link_libraries(monkey-core-static socket nsl) -endif() diff --git a/fluent-bit/lib/monkey/mk_server/mk_cache.c b/fluent-bit/lib/monkey/mk_server/mk_cache.c deleted file mode 100644 index c678afa8..00000000 --- a/fluent-bit/lib/monkey/mk_server/mk_cache.c +++ /dev/null @@ -1,81 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* Monkey HTTP Server - * ================== - * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _GNU_SOURCE - -#include <monkey/mk_core.h> -#include <monkey/mk_cache.h> -#include <monkey/mk_cache_tls.h> -#include <monkey/mk_config.h> -#include <monkey/mk_utils.h> -#include <monkey/mk_vhost.h> -#include <monkey/mk_tls.h> - -/* This function is called when a thread is created */ -void mk_cache_worker_init() -{ - char *cache_error; - mk_ptr_t *p_tmp; - - /* Cache header request -> last modified */ - p_tmp = mk_mem_alloc_z(sizeof(mk_ptr_t)); - p_tmp->data = mk_mem_alloc_z(32); - p_tmp->len = -1; - MK_TLS_SET(mk_tls_cache_header_lm, p_tmp); - - /* Cache header request -> content length */ - p_tmp = mk_mem_alloc_z(sizeof(mk_ptr_t)); - p_tmp->data = mk_mem_alloc_z(MK_UTILS_INT2MKP_BUFFER_LEN); - p_tmp->len = -1; - MK_TLS_SET(mk_tls_cache_header_cl, p_tmp); - - /* Cache gmtime buffer */ - MK_TLS_SET(mk_tls_cache_gmtime, mk_mem_alloc(sizeof(struct tm))); - - /* Cache the most used text representations of utime2gmt */ - MK_TLS_SET(mk_tls_cache_gmtext, - mk_mem_alloc_z(sizeof(struct mk_gmt_cache) * MK_GMT_CACHES)); - - /* Cache buffer for strerror_r(2) */ - cache_error = mk_mem_alloc(MK_UTILS_ERROR_SIZE); - pthread_setspecific(mk_utils_error_key, (void *) cache_error); -} - -void mk_cache_worker_exit() -{ - char *cache_error; - - /* Cache header request -> last modified */ - mk_ptr_free(MK_TLS_GET(mk_tls_cache_header_lm)); - mk_mem_free(MK_TLS_GET(mk_tls_cache_header_lm)); - - /* Cache header request -> content length */ - mk_ptr_free(MK_TLS_GET(mk_tls_cache_header_cl)); - mk_mem_free(MK_TLS_GET(mk_tls_cache_header_cl)); - - /* Cache gmtime buffer */ - mk_mem_free(MK_TLS_GET(mk_tls_cache_gmtime)); - - /* Cache the most used text representations of utime2gmt */ - mk_mem_free(MK_TLS_GET(mk_tls_cache_gmtext)); - - /* Cache buffer for strerror_r(2) */ - cache_error = pthread_getspecific(mk_utils_error_key); - mk_mem_free(cache_error); -} diff --git a/fluent-bit/lib/monkey/mk_server/mk_clock.c b/fluent-bit/lib/monkey/mk_server/mk_clock.c deleted file mode 100644 index 3a45512f..00000000 --- a/fluent-bit/lib/monkey/mk_server/mk_clock.c +++ /dev/null @@ -1,171 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* Monkey HTTP Server - * ================== - * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <time.h> - -#include <mk_core/mk_pthread.h> -#include <mk_core/mk_unistd.h> - -#include <monkey/mk_core.h> -#include <monkey/mk_config.h> -#include <monkey/mk_clock.h> -#include <monkey/mk_utils.h> -#include <monkey/mk_tls.h> - -#ifdef _WIN32 -static struct tm* localtime_r(const time_t* timep, struct tm* result) -{ - localtime_s(result, timep); - - return result; -} - -static struct tm* gmtime_r(const time_t* timep, struct tm* result) -{ - gmtime_s(result, timep); - - return result; -} -#endif - - -/* - * The mk_ptr_ts have two buffers for avoid in half-way access from - * another thread while a buffer is being modified. The function below returns - * one of two buffers to work with. - */ -static inline char *_next_buffer(mk_ptr_t *pointer, char **buffers) -{ - if (pointer->data == buffers[0]) { - return buffers[1]; - } - else { - return buffers[0]; - } -} - -static void mk_clock_log_set_time(time_t utime, struct mk_server *server) -{ - char *time_string; - struct tm result; - - time_string = _next_buffer(&server->clock_context->log_current_time, server->clock_context->log_time_buffers); - server->clock_context->log_current_utime = utime; - - strftime(time_string, LOG_TIME_BUFFER_SIZE, "[%d/%b/%G %T %z]", - localtime_r(&utime, &result)); - - server->clock_context->log_current_time.data = time_string; -} - -static void mk_clock_headers_preset(time_t utime, struct mk_server *server) -{ - int len1; - int len2; - struct tm *gmt_tm; - struct tm result; - char *buffer; - - buffer = _next_buffer(&server->clock_context->headers_preset, - server->clock_context->header_time_buffers); - - gmt_tm = gmtime_r(&utime, &result); - - len1 = snprintf(buffer, - HEADER_TIME_BUFFER_SIZE, - "%s", - server->server_signature_header); - - len2 = strftime(buffer + len1, - HEADER_PRESET_SIZE - len1, - MK_CLOCK_GMT_DATEFORMAT, - gmt_tm); - - server->clock_context->headers_preset.data = buffer; - server->clock_context->headers_preset.len = len1 + len2; -} - -void *mk_clock_worker_init(void *data) -{ - time_t cur_time; - struct mk_server *server = data; - - mk_utils_worker_rename("monkey: clock"); - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); - pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); - - server->clock_context->mk_clock_tid = pthread_self(); - - while (1) { - cur_time = time(NULL); - - if(cur_time != ((time_t)-1)) { - mk_clock_log_set_time(cur_time, server); - mk_clock_headers_preset(cur_time, server); - } - sleep(1); - } - - return NULL; -} - -void mk_clock_exit(struct mk_server *server) -{ - pthread_cancel(server->clock_context->mk_clock_tid); - pthread_join(server->clock_context->mk_clock_tid, NULL); - - mk_mem_free(server->clock_context->header_time_buffers[0]); - mk_mem_free(server->clock_context->header_time_buffers[1]); - mk_mem_free(server->clock_context->log_time_buffers[0]); - mk_mem_free(server->clock_context->log_time_buffers[1]); - - mk_mem_free(server->clock_context); -} - -/* This function must be called before any threads are created */ -void mk_clock_sequential_init(struct mk_server *server) -{ - server->clock_context = mk_mem_alloc_z(sizeof(struct mk_clock_context)); - - if (server->clock_context == NULL) { - return; - } - - /* Time when monkey was started */ - server->clock_context->monkey_init_time = time(NULL); - - server->clock_context->log_current_time.len = LOG_TIME_BUFFER_SIZE - 2; - server->clock_context->headers_preset.len = HEADER_PRESET_SIZE - 1; - - server->clock_context->header_time_buffers[0] = mk_mem_alloc_z(HEADER_PRESET_SIZE); - server->clock_context->header_time_buffers[1] = mk_mem_alloc_z(HEADER_PRESET_SIZE); - - server->clock_context->log_time_buffers[0] = mk_mem_alloc_z(LOG_TIME_BUFFER_SIZE); - server->clock_context->log_time_buffers[1] = mk_mem_alloc_z(LOG_TIME_BUFFER_SIZE); - - /* Set the time once */ - time_t cur_time = time(NULL); - - if (cur_time != ((time_t)-1)) { - mk_clock_log_set_time(cur_time, server); - mk_clock_headers_preset(cur_time, server); - } -} diff --git a/fluent-bit/lib/monkey/mk_server/mk_config.c b/fluent-bit/lib/monkey/mk_server/mk_config.c deleted file mode 100644 index f8dc9c00..00000000 --- a/fluent-bit/lib/monkey/mk_server/mk_config.c +++ /dev/null @@ -1,636 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* Monkey HTTP Server - * ================== - * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <monkey/monkey.h> -#include <monkey/mk_kernel.h> -#include <monkey/mk_config.h> -#include <monkey/mk_utils.h> -#include <monkey/mk_mimetype.h> -#include <monkey/mk_info.h> -#include <monkey/mk_core.h> -#include <monkey/mk_server.h> -#include <monkey/mk_plugin.h> -#include <monkey/mk_vhost.h> -#include <monkey/mk_mimetype.h> -#include <monkey/mk_info.h> - -#include <ctype.h> -#include <limits.h> -#include <mk_core/mk_dirent.h> -#include <sys/stat.h> - -struct mk_server_config *mk_config; - -static int mk_config_key_have(struct mk_list *list, const char *value) -{ - struct mk_list *head; - struct mk_string_line *entry; - - mk_list_foreach(head, list) { - entry = mk_list_entry(head, struct mk_string_line, _head); - if (strcasecmp(entry->val, value) == 0) { - return MK_TRUE; - } - } - return MK_FALSE; -} - -void mk_config_listeners_free(struct mk_server *server) -{ - struct mk_list *tmp; - struct mk_list *head; - struct mk_config_listener *l; - - mk_list_foreach_safe(head, tmp, &server->listeners) { - l = mk_list_entry(head, struct mk_config_listener, _head); - mk_list_del(&l->_head); - mk_mem_free(l->address); - mk_mem_free(l->port); - mk_mem_free(l); - } -} - -void mk_config_free_all(struct mk_server *server) -{ - mk_vhost_free_all(server); - mk_mimetype_free_all(server); - - if (server->config) { - mk_rconf_free(server->config); - } - - if (server->path_conf_root) { - mk_mem_free(server->path_conf_root); - } - - if (server->path_conf_pidfile) { - mk_mem_free(server->path_conf_pidfile); - } - - if (server->conf_user_pub) { - mk_mem_free(server->conf_user_pub); - } - - /* free config->index_files */ - if (server->index_files) { - mk_string_split_free(server->index_files); - } - - if (server->user) { - mk_mem_free(server->user); - } - - if (server->transport_layer) { - mk_mem_free(server->transport_layer); - } - - mk_config_listeners_free(server); - - mk_ptr_free(&server->server_software); - mk_mem_free(server); -} - -/* Print a specific error */ -static void mk_config_print_error_msg(char *variable, char *path) -{ - mk_err("[config] %s at %s has an invalid value", - variable, path); - mk_mem_free(path); - exit(EXIT_FAILURE); -} - -/* - * Check if at least one of the Listen interfaces are being used by another - * process. - */ -int mk_config_listen_check_busy(struct mk_server *server) -{ - int fd; - struct mk_list *head; - struct mk_plugin *p; - struct mk_config_listener *listen; - - p = mk_plugin_cap(MK_CAP_SOCK_PLAIN, server); - if (!p) { - mk_warn("Listen check: consider build monkey with basic socket handling!"); - return MK_FALSE; - } - - mk_list_foreach(head, &server->listeners) { - listen = mk_list_entry(head, struct mk_config_listener, _head); - - fd = mk_socket_connect(listen->address, atol(listen->port), MK_FALSE); - if (fd != -1) { - close(fd); - return MK_TRUE; - } - } - - return MK_FALSE; -} - -int mk_config_listen_parse(char *value, struct mk_server *server) -{ - int ret = -1; - int flags = 0; - long port_num; - char *address = NULL; - char *port = NULL; - char *divider; - struct mk_list *list = NULL; - struct mk_string_line *listener; - - list = mk_string_split_line(value); - if (!list) { - goto error; - } - - if (mk_list_is_empty(list) == 0) { - goto error; - } - - /* Parse the listener interface */ - listener = mk_list_entry_first(list, struct mk_string_line, _head); - if (listener->val[0] == '[') { - /* IPv6 address */ - divider = strchr(listener->val, ']'); - if (divider == NULL) { - mk_err("[config] Expected closing ']' in IPv6 address."); - goto error; - } - if (divider[1] != ':' || divider[2] == '\0') { - mk_err("[config] Expected ':port' after IPv6 address."); - goto error; - } - - address = mk_string_copy_substr(listener->val + 1, 0, - divider - listener->val - 1); - port = mk_string_dup(divider + 2); - } - else if (strchr(listener->val, ':') != NULL) { - /* IPv4 address */ - divider = strrchr(listener->val, ':'); - if (divider == NULL || divider[1] == '\0') { - mk_err("[config] Expected ':port' after IPv4 address."); - goto error; - } - - address = mk_string_copy_substr(listener->val, 0, - divider - listener->val); - port = mk_string_dup(divider + 1); - } - else { - /* Port only */ - address = NULL; - port = mk_string_dup(listener->val); - } - - errno = 0; - port_num = strtol(port, NULL, 10); - if (errno != 0 || port_num == LONG_MAX || port_num == LONG_MIN) { - mk_warn("Using defaults, could not understand \"Listen %s\"", - listener->val); - port = NULL; - } - - /* Check extra properties of the listener */ - flags = MK_CAP_HTTP; - if (mk_config_key_have(list, "!http")) { - flags |= ~MK_CAP_HTTP; - } - -#ifdef MK_HAVE_HTTP2 - if (mk_config_key_have(list, "h2")) { - flags |= (MK_CAP_HTTP2 | MK_CAP_SOCK_TLS); - } - - if (mk_config_key_have(list, "h2c")) { - flags |= MK_CAP_HTTP2; - } -#endif - - if (mk_config_key_have(list, "tls")) { - flags |= MK_CAP_SOCK_TLS; - } - - /* register the new listener */ - mk_config_listener_add(address, port, flags, server); - mk_string_split_free(list); - list = NULL; - ret = 0; - -error: - if (address) { - mk_mem_free(address); - } - if (port) { - mk_mem_free(port); - } - if (list) { - mk_string_split_free(list); - } - - return ret; -} - -static int mk_config_listen_read(struct mk_rconf_section *section, - struct mk_server *server) -{ - int ret; - struct mk_list *cur; - struct mk_rconf_entry *entry; - - mk_list_foreach(cur, §ion->entries) { - entry = mk_list_entry(cur, struct mk_rconf_entry, _head); - if (strcasecmp(entry->key, "Listen")) { - continue; - } - - ret = mk_config_listen_parse(entry->val, server); - if (ret != 0) { - return -1; - } - } - - return 0; -} - -/* Read configuration files */ -static int mk_config_read_files(char *path_conf, char *file_conf, - struct mk_server *server) -{ - unsigned long len; - char *tmp = NULL; - struct stat checkdir; - struct mk_rconf *cnf; - struct mk_rconf_section *section; - - if (!path_conf) { - return -1; - } - - if (!file_conf) { - file_conf = "monkey.conf"; - } - - server->path_conf_root = mk_string_dup(path_conf); - - if (stat(server->path_conf_root, &checkdir) == -1) { - mk_err("ERROR: Cannot find/open '%s'", server->path_conf_root); - return -1; - } - - mk_string_build(&tmp, &len, "%s/%s", path_conf, file_conf); - cnf = mk_rconf_open(tmp); - if (!cnf) { - mk_mem_free(tmp); - mk_err("Cannot read '%s'", server->conf_main); - return -1; - } - section = mk_rconf_section_get(cnf, "SERVER"); - if (!section) { - mk_err("ERROR: No 'SERVER' section defined"); - return -1; - } - - /* Map source configuration */ - server->config = cnf; - - /* Listen */ - if (!server->port_override) { - /* Process each Listen entry */ - if (mk_config_listen_read(section, server)) { - mk_err("[config] Failed to read listen sections."); - } - if (mk_list_is_empty(&server->listeners) == 0) { - mk_warn("[config] No valid Listen entries found, set default"); - mk_config_listener_add(NULL, NULL, MK_CAP_HTTP, server); - } - } - else { - mk_config_listener_add(NULL, server->port_override, - MK_CAP_HTTP, server); - } - - /* Number of thread workers */ - if (server->workers == -1) { - server->workers = (size_t) mk_rconf_section_get_key(section, - "Workers", - MK_RCONF_NUM); - } - - if (server->workers < 1) { - server->workers = mk_utils_get_system_core_count(); - - if (server->workers < 1) { - mk_config_print_error_msg("Workers", tmp); - } - } - - /* Timeout */ - server->timeout = (size_t) mk_rconf_section_get_key(section, - "Timeout", MK_RCONF_NUM); - if (server->timeout < 1) { - mk_config_print_error_msg("Timeout", tmp); - } - - /* KeepAlive */ - server->keep_alive = (size_t) mk_rconf_section_get_key(section, - "KeepAlive", - MK_RCONF_BOOL); - if (server->keep_alive == MK_ERROR) { - mk_config_print_error_msg("KeepAlive", tmp); - } - - /* MaxKeepAliveRequest */ - server->max_keep_alive_request = (size_t) - mk_rconf_section_get_key(section, - "MaxKeepAliveRequest", - MK_RCONF_NUM); - - if (server->max_keep_alive_request == 0) { - mk_config_print_error_msg("MaxKeepAliveRequest", tmp); - } - - /* KeepAliveTimeout */ - server->keep_alive_timeout = (size_t) mk_rconf_section_get_key(section, - "KeepAliveTimeout", - MK_RCONF_NUM); - if (server->keep_alive_timeout == 0) { - mk_config_print_error_msg("KeepAliveTimeout", tmp); - } - - /* Pid File */ - if (!server->path_conf_pidfile) { - server->path_conf_pidfile = mk_rconf_section_get_key(section, - "PidFile", - MK_RCONF_STR); - } - - /* Home user's directory /~ */ - server->conf_user_pub = mk_rconf_section_get_key(section, - "UserDir", - MK_RCONF_STR); - - /* Index files */ - server->index_files = mk_rconf_section_get_key(section, - "Indexfile", MK_RCONF_LIST); - - /* HideVersion Variable */ - server->hideversion = (size_t) mk_rconf_section_get_key(section, - "HideVersion", - MK_RCONF_BOOL); - if (server->hideversion == MK_ERROR) { - mk_config_print_error_msg("HideVersion", tmp); - } - - /* User Variable */ - server->user = mk_rconf_section_get_key(section, "User", MK_RCONF_STR); - - /* Resume */ - server->resume = (size_t) mk_rconf_section_get_key(section, - "Resume", MK_RCONF_BOOL); - if (server->resume == MK_ERROR) { - mk_config_print_error_msg("Resume", tmp); - } - - /* Max Request Size */ - server->max_request_size = (size_t) mk_rconf_section_get_key(section, - "MaxRequestSize", - MK_RCONF_NUM); - if (server->max_request_size <= 0) { - mk_config_print_error_msg("MaxRequestSize", tmp); - } - else { - server->max_request_size *= 1024; - } - - /* Symbolic Links */ - server->symlink = (size_t) mk_rconf_section_get_key(section, - "SymLink", MK_RCONF_BOOL); - if (server->symlink == MK_ERROR) { - mk_config_print_error_msg("SymLink", tmp); - } - - /* Transport Layer plugin */ - if (!server->transport_layer) { - server->transport_layer = mk_rconf_section_get_key(section, - "TransportLayer", - MK_RCONF_STR); - } - - /* Default Mimetype */ - mk_mem_free(tmp); - tmp = mk_rconf_section_get_key(section, "DefaultMimeType", MK_RCONF_STR); - if (tmp) { - mk_string_build(&server->mimetype_default_str, &len, "%s\r\n", tmp); - } - - /* File Descriptor Table (FDT) */ - server->fdt = (size_t) mk_rconf_section_get_key(section, - "FDT", - MK_RCONF_BOOL); - - /* FIXME: Overcapacity not ready */ - server->fd_limit = (size_t) mk_rconf_section_get_key(section, - "FDLimit", - MK_RCONF_NUM); - /* Get each worker clients capacity based on FDs system limits */ - server->server_capacity = mk_server_capacity(server); - - - if (!server->one_shot) { - mk_vhost_init(path_conf, server); - } - else { - mk_vhost_set_single(server->one_shot, server); - } - - mk_mem_free(tmp); - return 0; -} - -void mk_config_signature(struct mk_server *server) -{ - unsigned long len; - - /* Server Signature */ - if (server->hideversion == MK_FALSE) { - snprintf(server->server_signature, - sizeof(server->server_signature) - 1, - "Monkey/%s", MK_VERSION_STR); - } - else { - snprintf(server->server_signature, - sizeof(server->server_signature) - 1, - "Monkey"); - } - len = snprintf(server->server_signature_header, - sizeof(server->server_signature_header) - 1, - "Server: %s\r\n", server->server_signature); - server->server_signature_header_len = len; -} - -/* read main configuration from monkey.conf */ -void mk_config_start_configure(struct mk_server *server) -{ - int ret; - unsigned long len; - - ret = mk_config_read_files(server->path_conf_root, - server->conf_main, server); - if (ret != 0) { - return; - } - - /* Load mimes */ - mk_mimetype_read_config(server); - - mk_ptr_reset(&server->server_software); - - /* Basic server information */ - if (server->hideversion == MK_FALSE) { - mk_string_build(&server->server_software.data, - &len, "Monkey/%s (%s)", MK_VERSION_STR, MK_BUILD_OS); - server->server_software.len = len; - } - else { - mk_string_build(&server->server_software.data, &len, "Monkey Server"); - server->server_software.len = len; - } -} - -/* Register a new listener into the main configuration */ -struct mk_config_listener *mk_config_listener_add(char *address, - char *port, int flags, - struct mk_server *server) -{ - struct mk_list *head; - struct mk_config_listener *check; - struct mk_config_listener *listen = NULL; - - listen = mk_mem_alloc(sizeof(struct mk_config_listener)); - if (!listen) { - mk_err("[listen_add] malloc() failed"); - return NULL; - } - - if (!address) { - listen->address = mk_string_dup(MK_DEFAULT_LISTEN_ADDR); - } - else { - listen->address = mk_string_dup(address); - } - - /* Set the port */ - if (!port) { - mk_err("[listen_add] TCP port not defined"); - exit(EXIT_FAILURE); - } - - listen->port = mk_string_dup(port); - listen->flags = flags; - - /* Before to add a new listener, lets make sure it's not a duplicated */ - mk_list_foreach(head, &server->listeners) { - check = mk_list_entry(head, struct mk_config_listener, _head); - if (strcmp(listen->address, check->address) == 0 && - strcmp(listen->port, check->port) == 0) { - mk_warn("Listener: duplicated %s:%s, skip.", - listen->address, listen->port); - - /* free resources */ - mk_mem_free(listen->address); - mk_mem_free(listen->port); - mk_mem_free(listen); - return NULL; - } - } - - mk_list_add(&listen->_head, &server->listeners); - return listen; -} - -void mk_config_set_init_values(struct mk_server *server) -{ - /* Init values */ - server->is_seteuid = MK_FALSE; - server->timeout = 15; - server->hideversion = MK_FALSE; - server->keep_alive = MK_TRUE; - server->keep_alive_timeout = 15; - server->max_keep_alive_request = 50; - server->resume = MK_TRUE; - server->standard_port = 80; - server->symlink = MK_FALSE; - server->nhosts = 0; - mk_list_init(&server->hosts); - server->user = NULL; - server->open_flags = O_RDONLY; /* The only place this is effectively used (other than the sanity check) - * is mk_http.c where it's used to test for file existence and the fd is apparently leaked */ - server->index_files = NULL; - server->conf_user_pub = NULL; - server->workers = 1; - - /* TCP REUSEPORT: available on Linux >= 3.9 */ - if (server->scheduler_mode == -1) { - if (server->kernel_features & MK_KERNEL_SO_REUSEPORT) { - server->scheduler_mode = MK_SCHEDULER_REUSEPORT; - } - else { - server->scheduler_mode = MK_SCHEDULER_FAIR_BALANCING; - } - } - - /* Max request buffer size allowed - * right now, every chunk size is 4KB (4096 bytes), - * so we are setting a maximum request size to 32 KB */ - server->max_request_size = MK_REQUEST_CHUNK * 8; - - /* Internals */ - server->safe_event_write = MK_FALSE; - - /* Init plugin list */ - mk_list_init(&server->plugins); - - /* Init listeners */ - mk_list_init(&server->listeners); -} - -void mk_config_sanity_check(struct mk_server *server) -{ - /* Check O_NOATIME for current user, flag will just be used - * if running user is allowed to. - */ - int fd; - int flags; - - if (!server->path_conf_root) { - return; - } - - flags = server->open_flags; - flags |= O_NOATIME; - fd = open(server->path_conf_root, flags); - - if (fd > -1) { - server->open_flags = flags; - close(fd); - } -} diff --git a/fluent-bit/lib/monkey/mk_server/mk_fifo.c b/fluent-bit/lib/monkey/mk_server/mk_fifo.c deleted file mode 100644 index fd148db7..00000000 --- a/fluent-bit/lib/monkey/mk_server/mk_fifo.c +++ /dev/null @@ -1,463 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* Monkey HTTP Server - * ================== - * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <monkey/mk_fifo.h> -#include <monkey/mk_scheduler.h> - -#ifdef _WIN32 -#include <event.h> -#endif - -static struct mk_fifo_worker *mk_fifo_worker_create(struct mk_fifo *ctx, - void *data) -{ - int id; - int ret; - struct mk_fifo_worker *fw; - - /* Get an ID */ - id = mk_list_size(&ctx->workers); - - fw = mk_mem_alloc_z(sizeof(struct mk_fifo_worker)); - if (!fw) { - perror("malloc"); - return NULL; - } - MK_EVENT_NEW(&fw->event); - - fw->worker_id = id; - fw->data = data; - fw->fifo = ctx; - - fw->buf_data = mk_mem_alloc(MK_FIFO_BUF_SIZE); - if (!fw->buf_data) { - perror("malloc"); - mk_mem_free(fw); - return NULL; - } - fw->buf_len = 0; - fw->buf_size = MK_FIFO_BUF_SIZE; - -#ifdef _WIN32 - ret = evutil_socketpair(AF_INET, SOCK_STREAM, 0, fw->channel); - if (ret == -1) { - perror("socketpair"); - mk_mem_free(fw); - return NULL; - } -#else - ret = pipe(fw->channel); - if (ret == -1) { - perror("pipe"); - mk_mem_free(fw); - return NULL; - } -#endif - - mk_list_add(&fw->_head, &ctx->workers); - return fw; -} - -/* - * Function used as a callback triggered by mk_worker_callback() or - * through a mk_sched_worker_cb_add(). It purpose is to prepare the - * channels on the final worker thread so it can consume pushed - * messages. - */ -void mk_fifo_worker_setup(void *data) -{ - struct mk_fifo_worker *mw = NULL; - struct mk_fifo *ctx = data; - - pthread_mutex_lock(&ctx->mutex_init); - - mw = mk_fifo_worker_create(ctx, data); - if (!mw) { - mk_err("[msg] error configuring msg-worker context "); - pthread_mutex_unlock(&ctx->mutex_init); - return; - } - - /* Make the current worker context available */ - pthread_setspecific(*ctx->key, mw); - pthread_mutex_unlock(&ctx->mutex_init); -} - -struct mk_fifo *mk_fifo_create(pthread_key_t *key, void *data) -{ - struct mk_fifo *ctx; - - ctx = mk_mem_alloc(sizeof(struct mk_fifo)); - if (!ctx) { - perror("malloc"); - return NULL; - } - ctx->data = data; - - /* Lists */ - mk_list_init(&ctx->queues); - mk_list_init(&ctx->workers); - - - /* Pthread specifics */ - - /* We need to isolate this because there is a key that's shared between monkey - * instances by design. - */ - if (key != NULL) { - ctx->key = key; - pthread_key_create(ctx->key, NULL); - } - - pthread_mutex_init(&ctx->mutex_init, NULL); - - return ctx; -} - -int mk_fifo_queue_create(struct mk_fifo *ctx, char *name, - void (*cb)(struct mk_fifo_queue *, void *, - size_t, void *), - void *data) - -{ - int id = -1; - int len; - struct mk_list *head; - struct mk_fifo_queue *q; - - /* Get ID for the new queue */ - if (mk_list_is_empty(&ctx->queues) == 0) { - id = 0; - } - else { - q = mk_list_entry_last(&ctx->queues, struct mk_fifo_queue, _head); - id = q->id + 1; - } - - /* queue name might need to be truncated if is too long */ - len = strlen(name); - if (len > (int) sizeof(q->name) - 1) { - len = sizeof(q->name) - 1; - } - - /* Validate that name is not a duplicated */ - mk_list_foreach(head, &ctx->queues) { - q = mk_list_entry(head, struct mk_fifo_queue, _head); - if (strlen(q->name) != (unsigned int) len) { - continue; - } - - if (strncmp(q->name, name, len) == 0) { - return -1; - } - } - - /* Allocate and register queue */ - q = mk_mem_alloc(sizeof(struct mk_fifo_queue)); - if (!q) { - perror("malloc"); - return -1; - } - q->id = id; - q->cb_message = cb; - q->data = data; - - strncpy(q->name, name, len); - q->name[len] = '\0'; - mk_list_add(&q->_head, &ctx->queues); - - return id; -} - -struct mk_fifo_queue *mk_fifo_queue_get(struct mk_fifo *ctx, int id) -{ - struct mk_list *head; - struct mk_fifo_queue *q = NULL; - - mk_list_foreach(head, &ctx->queues) { - q = mk_list_entry(head, struct mk_fifo_queue, _head); - if (q->id == id) { - return q; - } - } - - return NULL; -} - -int mk_fifo_queue_destroy(struct mk_fifo *ctx, struct mk_fifo_queue *q) -{ - (void) ctx; - - mk_list_del(&q->_head); - mk_mem_free(q); - return 0; -} - -int mk_fifo_queue_id_destroy(struct mk_fifo *ctx, int id) -{ - struct mk_fifo_queue *q; - - q = mk_fifo_queue_get(ctx, id); - if (!q) { - return -1; - } - - mk_fifo_queue_destroy(ctx, q); - return 0; -} - -static int mk_fifo_queue_destroy_all(struct mk_fifo *ctx) -{ - int c = 0; - struct mk_list *tmp; - struct mk_list *head; - struct mk_fifo_queue *q; - - mk_list_foreach_safe(head, tmp, &ctx->queues) { - q = mk_list_entry(head, struct mk_fifo_queue, _head); - mk_fifo_queue_destroy(ctx, q); - c++; - } - - return c; -} - -static int mk_fifo_worker_destroy_all(struct mk_fifo *ctx) -{ - int c = 0; - struct mk_list *tmp; - struct mk_list *head; - struct mk_fifo_worker *fw; - - mk_list_foreach_safe(head, tmp, &ctx->workers) { - fw = mk_list_entry(head, struct mk_fifo_worker, _head); - -#ifdef _WIN32 - evutil_closesocket(fw->channel[0]); - evutil_closesocket(fw->channel[1]); -#else - close(fw->channel[0]); - close(fw->channel[1]); -#endif - mk_list_del(&fw->_head); - mk_mem_free(fw->buf_data); - mk_mem_free(fw); - c++; - } - - return c; -} - -static int msg_write(int fd, void *buf, size_t count) -{ - ssize_t bytes; - size_t total = 0; - - do { -#ifdef _WIN32 - bytes = send(fd, (uint8_t *)buf + total, count - total, 0); -#else - bytes = write(fd, (uint8_t *)buf + total, count - total); -#endif - if (bytes == -1) { - if (errno == EAGAIN) { - /* - * This could happen, since this function goal is not to - * return until all data have been read, just sleep a little - * bit (0.05 seconds) - */ - -#ifdef _WIN32 - Sleep(5); -#else - usleep(50000); -#endif - continue; - } - } - else if (bytes == 0) { - /* Broken pipe ? */ - perror("write"); - return -1; - } - total += bytes; - - } while (total < count); - - return total; -} - -/* - * Push a message into a queue: this function runs from the parent thread - * so it needs to write the message to every thread pipe channel. - */ -int mk_fifo_send(struct mk_fifo *ctx, int id, void *data, size_t size) -{ - int ret; - struct mk_list *head; - struct mk_fifo_msg msg; - struct mk_fifo_queue *q; - struct mk_fifo_worker *fw; - - /* Validate queue ID */ - q = mk_fifo_queue_get(ctx, id); - if (!q) { - return -1; - } - - pthread_mutex_lock(&ctx->mutex_init); - - mk_list_foreach(head, &ctx->workers) { - fw = mk_list_entry(head, struct mk_fifo_worker, _head); - - msg.length = size; - msg.flags = 0; - msg.queue_id = (uint16_t) id; - - ret = msg_write(fw->channel[1], &msg, sizeof(struct mk_fifo_msg)); - if (ret == -1) { - pthread_mutex_unlock(&ctx->mutex_init); - perror("write"); - fprintf(stderr, "[msg] error writing message header\n"); - return -1; - } - - ret = msg_write(fw->channel[1], data, size); - if (ret == -1) { - pthread_mutex_unlock(&ctx->mutex_init); - perror("write"); - fprintf(stderr, "[msg] error writing message body\n"); - return -1; - } - } - - pthread_mutex_unlock(&ctx->mutex_init); - - return 0; -} - -static inline void consume_bytes(char *buf, int bytes, int length) -{ - memmove(buf, buf + bytes, length - bytes); -} - -static inline int fifo_drop_msg(struct mk_fifo_worker *fw) -{ - size_t drop_bytes; - struct mk_fifo_msg *msg; - - msg = (struct mk_fifo_msg *) fw->buf_data; - drop_bytes = (sizeof(struct mk_fifo_msg) + msg->length); - consume_bytes(fw->buf_data, drop_bytes, fw->buf_len); - fw->buf_len -= drop_bytes; - - return 0; -} - -static inline int fifo_is_msg_ready(struct mk_fifo_worker *fw) -{ - struct mk_fifo_msg *msg; - - msg = (struct mk_fifo_msg *) fw->buf_data; - if (fw->buf_len >= (msg->length + sizeof(struct mk_fifo_msg))) { - return MK_TRUE; - } - - return MK_FALSE; -} - -int mk_fifo_worker_read(void *event) -{ - int available; - char *tmp; - size_t size; - ssize_t bytes; - struct mk_fifo_msg *fm; - struct mk_fifo_worker *fw; - struct mk_fifo_queue *fq; - - fw = (struct mk_fifo_worker *) event; - - /* Check available space */ - available = fw->buf_size - fw->buf_len; - if (available <= 1) { - size = fw->buf_size + (MK_FIFO_BUF_SIZE / 2); - tmp = mk_mem_realloc(fw->buf_data, size); - if (!tmp) { - perror("realloc"); - return -1; - } - fw->buf_data = tmp; - fw->buf_size = size; - available = fw->buf_size - fw->buf_len; - } - - /* Read data from pipe */ -#ifdef _WIN32 - bytes = recv(fw->channel[0], fw->buf_data + fw->buf_len, available, 0); -#else - bytes = read(fw->channel[0], fw->buf_data + fw->buf_len, available); -#endif - - if (bytes == 0) { - return -1; - } - else if (bytes == -1){ - perror("read"); - return -1; - } - - fw->buf_len += bytes; - - /* Find messages and trigger callbacks */ - while (fw->buf_len > 0) { - if (fifo_is_msg_ready(fw) == MK_TRUE) { - /* we got a complete message */ - fm = (struct mk_fifo_msg *) fw->buf_data; - fq = mk_fifo_queue_get(fw->fifo, fm->queue_id); - if (!fq) { - /* Invalid queue */ - fprintf(stderr, "[fifo worker read] invalid queue id %i\n", - fm->queue_id); - fifo_drop_msg(fw); - continue; - } - - /* Trigger callback if any */ - if (fq->cb_message) { - fq->cb_message(fq, fm->data, fm->length, fq->data); - } - fifo_drop_msg(fw); - } - else { - /* msg not ready */ - break; - } - } - - return 0; -} - -int mk_fifo_destroy(struct mk_fifo *ctx) -{ - mk_fifo_queue_destroy_all(ctx); - mk_fifo_worker_destroy_all(ctx); - mk_mem_free(ctx); - return 0; -} diff --git a/fluent-bit/lib/monkey/mk_server/mk_header.c b/fluent-bit/lib/monkey/mk_server/mk_header.c deleted file mode 100644 index cd8f77bd..00000000 --- a/fluent-bit/lib/monkey/mk_server/mk_header.c +++ /dev/null @@ -1,451 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* Monkey HTTP Server - * ================== - * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <monkey/monkey.h> -#include <monkey/mk_server.h> -#include <monkey/mk_header.h> -#include <monkey/mk_core.h> -#include <monkey/mk_http_status.h> -#include <monkey/mk_config.h> -#include <monkey/mk_socket.h> -#include <monkey/mk_utils.h> -#include <monkey/mk_clock.h> -#include <monkey/mk_cache.h> -#include <monkey/mk_http.h> -#include <monkey/mk_vhost.h> -#include <monkey/mk_tls.h> - -#define MK_HEADER_SHORT_DATE "Date: " -#define MK_HEADER_SHORT_LOCATION "Location: " -#define MK_HEADER_SHORT_CT "Content-Type: " -#define MK_HEADER_ACCEPT_RANGES "Accept-Ranges: bytes" MK_CRLF -#define MK_HEADER_ALLOWED_METHODS "Allow: " -#define MK_HEADER_CONN_KA "Connection: Keep-Alive" MK_CRLF -#define MK_HEADER_CONN_CLOSE "Connection: Close" MK_CRLF -#define MK_HEADER_CONN_UPGRADE "Connection: Upgrade" MK_CRLF -#define MK_HEADER_CONTENT_LENGTH "Content-Length: " -#define MK_HEADER_CONTENT_ENCODING "Content-Encoding: " -#define MK_HEADER_TE_CHUNKED "Transfer-Encoding: chunked" MK_CRLF -#define MK_HEADER_LAST_MODIFIED "Last-Modified: " -#define MK_HEADER_UPGRADE_H2C "Upgrade: h2c" MK_CRLF - -const mk_ptr_t mk_header_short_date = mk_ptr_init(MK_HEADER_SHORT_DATE); -const mk_ptr_t mk_header_short_location = mk_ptr_init(MK_HEADER_SHORT_LOCATION); -const mk_ptr_t mk_header_short_ct = mk_ptr_init(MK_HEADER_SHORT_CT); -const mk_ptr_t mk_header_allow = mk_ptr_init(MK_HEADER_ALLOWED_METHODS); - -const mk_ptr_t mk_header_conn_ka = mk_ptr_init(MK_HEADER_CONN_KA); -const mk_ptr_t mk_header_conn_close = mk_ptr_init(MK_HEADER_CONN_CLOSE); -const mk_ptr_t mk_header_conn_upgrade = mk_ptr_init(MK_HEADER_CONN_UPGRADE); -const mk_ptr_t mk_header_content_length = mk_ptr_init(MK_HEADER_CONTENT_LENGTH); -const mk_ptr_t mk_header_content_encoding = mk_ptr_init(MK_HEADER_CONTENT_ENCODING); -const mk_ptr_t mk_header_accept_ranges = mk_ptr_init(MK_HEADER_ACCEPT_RANGES); -const mk_ptr_t mk_header_te_chunked = mk_ptr_init(MK_HEADER_TE_CHUNKED); -const mk_ptr_t mk_header_last_modified = mk_ptr_init(MK_HEADER_LAST_MODIFIED); -const mk_ptr_t mk_header_upgrade_h2c = mk_ptr_init(MK_HEADER_UPGRADE_H2C); - -#define status_entry(num, str) {num, sizeof(str) - 1, str} - -static const struct header_status_response status_response[] = { - - /* - * The most used first: - * - * - HTTP/1.1 200 OK - * - HTTP/1.1 404 Not Found - */ - status_entry(MK_HTTP_OK, MK_RH_HTTP_OK), - status_entry(MK_CLIENT_NOT_FOUND, MK_RH_CLIENT_NOT_FOUND), - - /* Informational */ - status_entry(MK_INFO_CONTINUE, MK_RH_INFO_CONTINUE), - status_entry(MK_INFO_SWITCH_PROTOCOL, MK_RH_INFO_SWITCH_PROTOCOL), - - /* Successful */ - status_entry(MK_HTTP_CREATED, MK_RH_HTTP_CREATED), - status_entry(MK_HTTP_ACCEPTED, MK_RH_HTTP_ACCEPTED), - status_entry(MK_HTTP_NON_AUTH_INFO, MK_RH_HTTP_NON_AUTH_INFO), - status_entry(MK_HTTP_NOCONTENT, MK_RH_HTTP_NOCONTENT), - status_entry(MK_HTTP_RESET, MK_RH_HTTP_RESET), - status_entry(MK_HTTP_PARTIAL, MK_RH_HTTP_PARTIAL), - - /* Redirections */ - status_entry(MK_REDIR_MULTIPLE, MK_RH_REDIR_MULTIPLE), - status_entry(MK_REDIR_MOVED, MK_RH_REDIR_MOVED), - status_entry(MK_REDIR_MOVED_T, MK_RH_REDIR_MOVED_T), - status_entry(MK_REDIR_SEE_OTHER, MK_RH_REDIR_SEE_OTHER), - status_entry(MK_NOT_MODIFIED, MK_RH_NOT_MODIFIED), - status_entry(MK_REDIR_USE_PROXY, MK_RH_REDIR_USE_PROXY), - - /* Client side errors */ - status_entry(MK_CLIENT_BAD_REQUEST, MK_RH_CLIENT_BAD_REQUEST), - status_entry(MK_CLIENT_UNAUTH, MK_RH_CLIENT_UNAUTH), - status_entry(MK_CLIENT_PAYMENT_REQ, MK_RH_CLIENT_PAYMENT_REQ), - status_entry(MK_CLIENT_FORBIDDEN, MK_RH_CLIENT_FORBIDDEN), - status_entry(MK_CLIENT_METHOD_NOT_ALLOWED, MK_RH_CLIENT_METHOD_NOT_ALLOWED), - status_entry(MK_CLIENT_NOT_ACCEPTABLE, MK_RH_CLIENT_NOT_ACCEPTABLE), - status_entry(MK_CLIENT_PROXY_AUTH, MK_RH_CLIENT_PROXY_AUTH), - status_entry(MK_CLIENT_REQUEST_TIMEOUT, MK_RH_CLIENT_REQUEST_TIMEOUT), - status_entry(MK_CLIENT_CONFLICT, MK_RH_CLIENT_CONFLICT), - status_entry(MK_CLIENT_GONE, MK_RH_CLIENT_GONE), - status_entry(MK_CLIENT_LENGTH_REQUIRED, MK_RH_CLIENT_LENGTH_REQUIRED), - status_entry(MK_CLIENT_PRECOND_FAILED, MK_RH_CLIENT_PRECOND_FAILED), - status_entry(MK_CLIENT_REQUEST_ENTITY_TOO_LARGE, - MK_RH_CLIENT_REQUEST_ENTITY_TOO_LARGE), - status_entry(MK_CLIENT_REQUEST_URI_TOO_LONG, - MK_RH_CLIENT_REQUEST_URI_TOO_LONG), - status_entry(MK_CLIENT_UNSUPPORTED_MEDIA, MK_RH_CLIENT_UNSUPPORTED_MEDIA), - status_entry(MK_CLIENT_REQUESTED_RANGE_NOT_SATISF, - MK_RH_CLIENT_REQUESTED_RANGE_NOT_SATISF), - - /* Server side errors */ - status_entry(MK_SERVER_INTERNAL_ERROR, MK_RH_SERVER_INTERNAL_ERROR), - status_entry(MK_SERVER_NOT_IMPLEMENTED, MK_RH_SERVER_NOT_IMPLEMENTED), - status_entry(MK_SERVER_BAD_GATEWAY, MK_RH_SERVER_BAD_GATEWAY), - status_entry(MK_SERVER_SERVICE_UNAV, MK_RH_SERVER_SERVICE_UNAV), - status_entry(MK_SERVER_GATEWAY_TIMEOUT, MK_RH_SERVER_GATEWAY_TIMEOUT), - status_entry(MK_SERVER_HTTP_VERSION_UNSUP, MK_RH_SERVER_HTTP_VERSION_UNSUP) -}; - -static const int status_response_len = - (sizeof(status_response)/(sizeof(status_response[0]))); - -static void mk_header_cb_finished(struct mk_stream_input *in) -{ - struct mk_iov *iov = in->buffer; - - mk_iov_free_marked(iov); - -#if defined(__APPLE__) - /* - * Disable TCP_CORK right away, according to: - * - * --- - * commit 81e8b869d70f9da93ddfbfb17ec7f12ce3c28fc6 - * Author: Sonny Karlsson <ksonny@lotrax.org> - * Date: Sat Oct 18 12:11:49 2014 +0200 - * - * http: Remove cork before first call to sendfile(). - * - * This removes a large delay on Mac OS X when headers and file content - * does not fill a single frame. - * Deactivating TCP_NOPUSH does not cause pending frames to be sent until - * the next write operation. - * --- - */ - - mk_server_cork_flag(in->stream->channel->fd, TCP_CORK_OFF); -#endif -} - -static void cb_stream_iov_extended_free(struct mk_stream_input *in) -{ - struct mk_iov *iov; - - iov = in->buffer; - mk_iov_free(iov); -} - -/* Send response headers */ -int mk_header_prepare(struct mk_http_session *cs, struct mk_http_request *sr, - struct mk_server *server) -{ - int i = 0; - unsigned long len = 0; - char *buffer = 0; - mk_ptr_t response; - struct response_headers *sh; - struct mk_iov *iov; - - sh = &sr->headers; - iov = &sh->headers_iov; - - /* HTTP Status Code */ - if (sh->status == MK_CUSTOM_STATUS) { - response.data = sh->custom_status.data; - response.len = sh->custom_status.len; - } - else { - for (i = 0; i < status_response_len; i++) { - if (status_response[i].status == sh->status) { - response.data = status_response[i].response; - response.len = status_response[i].length; - break; - } - } - } - - /* Invalid status set */ - mk_bug(i == status_response_len); - - mk_iov_add(iov, response.data, response.len, MK_FALSE); - - /* - * Preset headers (mk_clock.c): - * - * - Server - * - Date - */ - mk_iov_add(iov, - server->clock_context->headers_preset.data, - server->clock_context->headers_preset.len, - MK_FALSE); - - /* Last-Modified */ - if (sh->last_modified > 0) { - mk_ptr_t *lm = MK_TLS_GET(mk_tls_cache_header_lm); - lm->len = mk_utils_utime2gmt(&lm->data, sh->last_modified); - - mk_iov_add(iov, - mk_header_last_modified.data, - mk_header_last_modified.len, - MK_FALSE); - mk_iov_add(iov, - lm->data, - lm->len, - MK_FALSE); - } - - /* Connection */ - if (sh->connection == 0) { - if (cs->close_now == MK_FALSE) { - if (sr->connection.len > 0) { - if (sr->protocol != MK_HTTP_PROTOCOL_11) { - mk_iov_add(iov, - mk_header_conn_ka.data, - mk_header_conn_ka.len, - MK_FALSE); - } - } - } - else { - mk_iov_add(iov, - mk_header_conn_close.data, - mk_header_conn_close.len, - MK_FALSE); - } - } - else if (sh->connection == MK_HEADER_CONN_UPGRADED) { - mk_iov_add(iov, - mk_header_conn_upgrade.data, - mk_header_conn_upgrade.len, - MK_FALSE); - } - - /* Location */ - if (sh->location != NULL) { - mk_iov_add(iov, - mk_header_short_location.data, - mk_header_short_location.len, - MK_FALSE); - - mk_iov_add(iov, - sh->location, - strlen(sh->location), - MK_TRUE); - } - - /* allowed methods */ - if (sh->allow_methods.len > 0) { - mk_iov_add(iov, - mk_header_allow.data, - mk_header_allow.len, - MK_FALSE); - mk_iov_add(iov, - sh->allow_methods.data, - sh->allow_methods.len, - MK_FALSE); - } - - /* Content type */ - if (sh->content_type.len > 0) { - mk_iov_add(iov, - sh->content_type.data, - sh->content_type.len, - MK_FALSE); - } - - /* - * Transfer Encoding: the transfer encoding header is just sent when - * the response has some content defined by the HTTP status response - */ - switch (sh->transfer_encoding) { - case MK_HEADER_TE_TYPE_CHUNKED: - mk_iov_add(iov, - mk_header_te_chunked.data, - mk_header_te_chunked.len, - MK_FALSE); - break; - } - - /* E-Tag */ - if (sh->etag_len > 0) { - mk_iov_add(iov, sh->etag_buf, sh->etag_len, MK_FALSE); - } - - /* Content-Encoding */ - if (sh->content_encoding.len > 0) { - mk_iov_add(iov, mk_header_content_encoding.data, - mk_header_content_encoding.len, - MK_FALSE); - mk_iov_add(iov, sh->content_encoding.data, - sh->content_encoding.len, - MK_FALSE); - } - - /* Content-Length */ - if (sh->content_length >= 0 && sh->transfer_encoding != 0) { - /* Map content length to MK_POINTER */ - mk_ptr_t *cl = MK_TLS_GET(mk_tls_cache_header_cl); - mk_string_itop(sh->content_length, cl); - - /* Set headers */ - mk_iov_add(iov, - mk_header_content_length.data, - mk_header_content_length.len, - MK_FALSE); - mk_iov_add(iov, - cl->data, - cl->len, - MK_FALSE); - } - - if ((sh->content_length != 0 && (sh->ranges[0] >= 0 || sh->ranges[1] >= 0)) && - server->resume == MK_TRUE) { - buffer = 0; - - /* yyy- */ - if (sh->ranges[0] >= 0 && sh->ranges[1] == -1) { - mk_string_build(&buffer, - &len, - "%s bytes %d-%ld/%ld\r\n", - RH_CONTENT_RANGE, - sh->ranges[0], - (sh->real_length - 1), sh->real_length); - mk_iov_add(iov, buffer, len, MK_TRUE); - } - - /* yyy-xxx */ - if (sh->ranges[0] >= 0 && sh->ranges[1] >= 0) { - mk_string_build(&buffer, - &len, - "%s bytes %d-%d/%ld\r\n", - RH_CONTENT_RANGE, - sh->ranges[0], sh->ranges[1], sh->real_length); - - mk_iov_add(iov, buffer, len, MK_TRUE); - } - - /* -xxx */ - if (sh->ranges[0] == -1 && sh->ranges[1] > 0) { - mk_string_build(&buffer, - &len, - "%s bytes %ld-%ld/%ld\r\n", - RH_CONTENT_RANGE, - (sh->real_length - sh->ranges[1]), - (sh->real_length - 1), sh->real_length); - mk_iov_add(iov, buffer, len, MK_TRUE); - } - } - - if (sh->upgrade == MK_HEADER_UPGRADED_H2C) { - mk_iov_add(iov, mk_header_upgrade_h2c.data, mk_header_upgrade_h2c.len, - MK_FALSE); - } - - - if (sh->cgi == SH_NOCGI || sh->breakline == MK_HEADER_BREAKLINE) { - if (!sr->headers._extra_rows) { - mk_iov_add(iov, mk_iov_crlf.data, mk_iov_crlf.len, - MK_FALSE); - } - else { - mk_iov_add(sr->headers._extra_rows, mk_iov_crlf.data, - mk_iov_crlf.len, MK_FALSE); - } - } - - /* - * Configure the Stream to dispatch the headers - */ - - /* Set the IOV input stream */ - sr->in_headers.buffer = iov; - sr->in_headers.bytes_total = iov->total_len; - sr->in_headers.cb_finished = mk_header_cb_finished; - - if (sr->headers._extra_rows) { - /* Our main sr->stream contains the main headers (header_iov) - * and 'may' have already some linked data. If we have some - * extra headers rows we need to link this IOV right after - * the main header_iov. - */ - struct mk_stream_input *in = &sr->in_headers_extra; - in->type = MK_STREAM_IOV; - in->dynamic = MK_FALSE; - in->cb_consumed = NULL; - in->cb_finished = cb_stream_iov_extended_free; - in->stream = &sr->stream; - in->buffer = sr->headers._extra_rows; - in->bytes_total = sr->headers._extra_rows->total_len; - - mk_list_add_after(&sr->in_headers_extra._head, - &sr->in_headers._head, - &sr->stream.inputs); - } - - sh->sent = MK_TRUE; - - return 0; -} - -void mk_header_set_http_status(struct mk_http_request *sr, int status) -{ - mk_bug(!sr); - sr->headers.status = status; - - MK_TRACE("Set HTTP status = %i", status); -} - -void mk_header_response_reset(struct response_headers *header) -{ - struct mk_iov *iov; - - header->status = -1; - header->sent = MK_FALSE; - header->ranges[0] = -1; - header->ranges[1] = -1; - header->content_length = -1; - header->connection = 0; - header->transfer_encoding = -1; - header->last_modified = -1; - header->upgrade = -1; - header->cgi = SH_NOCGI; - mk_ptr_reset(&header->content_type); - mk_ptr_reset(&header->content_encoding); - header->location = NULL; - header->_extra_rows = NULL; - header->allow_methods.len = 0; - - /* Initialize headers IOV */ - iov = &header->headers_iov; - iov->io = (struct iovec *) &header->__iov_io; - iov->buf_to_free = (void *) &header->__iov_buf; - mk_iov_init(&header->headers_iov, MK_HEADER_IOV, 0); -} diff --git a/fluent-bit/lib/monkey/mk_server/mk_http.c b/fluent-bit/lib/monkey/mk_server/mk_http.c deleted file mode 100644 index 1e2d219d..00000000 --- a/fluent-bit/lib/monkey/mk_server/mk_http.c +++ /dev/null @@ -1,1638 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* Monkey HTTP Server - * ================== - * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _GNU_SOURCE - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> - -#include <sys/stat.h> -#include <fcntl.h> -//#include <regex.h> -#include <re.h> - -#include <monkey/monkey.h> -#include <monkey/mk_user.h> -#include <monkey/mk_core.h> -#include <monkey/mk_http.h> -#include <monkey/mk_http_status.h> -#include <monkey/mk_http_thread.h> -#include <monkey/mk_clock.h> -#include <monkey/mk_utils.h> -#include <monkey/mk_config.h> -#include <monkey/mk_socket.h> -#include <monkey/mk_mimetype.h> -#include <monkey/mk_header.h> -#include <monkey/mk_plugin.h> -#include <monkey/mk_vhost.h> -#include <monkey/mk_server.h> -#include <monkey/mk_plugin_stage.h> - -const mk_ptr_t mk_http_method_get_p = mk_ptr_init(MK_METHOD_GET_STR); -const mk_ptr_t mk_http_method_post_p = mk_ptr_init(MK_METHOD_POST_STR); -const mk_ptr_t mk_http_method_head_p = mk_ptr_init(MK_METHOD_HEAD_STR); -const mk_ptr_t mk_http_method_put_p = mk_ptr_init(MK_METHOD_PUT_STR); -const mk_ptr_t mk_http_method_delete_p = mk_ptr_init(MK_METHOD_DELETE_STR); -const mk_ptr_t mk_http_method_options_p = mk_ptr_init(MK_METHOD_OPTIONS_STR); -const mk_ptr_t mk_http_method_null_p = { NULL, 0 }; - -const mk_ptr_t mk_http_protocol_09_p = mk_ptr_init(MK_HTTP_PROTOCOL_09_STR); -const mk_ptr_t mk_http_protocol_10_p = mk_ptr_init(MK_HTTP_PROTOCOL_10_STR); -const mk_ptr_t mk_http_protocol_11_p = mk_ptr_init(MK_HTTP_PROTOCOL_11_STR); -const mk_ptr_t mk_http_protocol_null_p = { NULL, 0 }; - -/* Create a memory allocation in order to handle the request data */ -void mk_http_request_init(struct mk_http_session *session, - struct mk_http_request *request, - struct mk_server *server) -{ - struct mk_list *host_list = &server->hosts; - - request->port = 0; - request->status = MK_TRUE; - request->uri.data = NULL; - request->method = MK_METHOD_UNKNOWN; - request->protocol = MK_HTTP_PROTOCOL_UNKNOWN; - request->connection.len = -1; - request->file_fd = -1; - request->file_info.size = -1; - request->vhost_fdt_id = 0; - request->vhost_fdt_hash = 0; - request->vhost_fdt_enabled = MK_FALSE; - request->host.data = NULL; - request->stage30_blocked = MK_FALSE; - request->session = session; - request->host_conf = mk_list_entry_first(host_list, struct mk_vhost, _head); - request->uri_processed.data = NULL; - request->real_path.data = NULL; - request->handler_data = NULL; - - request->in_file.fd = -1; - - /* Response Headers */ - mk_header_response_reset(&request->headers); - - /* Reset callbacks for headers stream */ - mk_stream_set(&request->stream, - session->channel, - NULL, - NULL, NULL, NULL); -} - -static inline int mk_http_point_header(mk_ptr_t *h, - struct mk_http_parser *parser, int key) -{ - struct mk_http_header *header; - - header = &parser->headers[key]; - if (header->type == key) { - h->data = header->val.data; - h->len = header->val.len; - return 0; - } - else { - h->data = NULL; - h->len = -1; - } - - return -1; -} - -static int mk_http_request_prepare(struct mk_http_session *cs, - struct mk_http_request *sr, - struct mk_server *server) -{ - int ret; - int status = 0; - char *temp; - struct mk_list *hosts = &server->hosts; - struct mk_list *alias; - struct mk_http_header *header; - - /* - * Process URI, if it contains ASCII encoded strings like '%20', - * it will return a new memory buffer with the decoded string, otherwise - * it returns NULL - */ - temp = mk_utils_url_decode(sr->uri); - - if (temp) { - sr->uri_processed.data = temp; - sr->uri_processed.len = strlen(temp); - } - else { - sr->uri_processed.data = sr->uri.data; - sr->uri_processed.len = sr->uri.len; - } - - /* Always assign the default vhost' */ - sr->host_conf = mk_list_entry_first(hosts, struct mk_vhost, _head); - sr->user_home = MK_FALSE; - - /* Valid request URI? */ - if (sr->uri_processed.data[0] != '/') { - mk_http_error(MK_CLIENT_BAD_REQUEST, cs, sr, server); - return MK_EXIT_OK; - } - - /* Check if we have a Host header: Hostname ; port */ - mk_http_point_header(&sr->host, &cs->parser, MK_HEADER_HOST); - - /* Header: Connection */ - mk_http_point_header(&sr->connection, &cs->parser, MK_HEADER_CONNECTION); - - /* Header: Range */ - mk_http_point_header(&sr->range, &cs->parser, MK_HEADER_RANGE); - - /* Header: If-Modified-Since */ - mk_http_point_header(&sr->if_modified_since, - &cs->parser, - MK_HEADER_IF_MODIFIED_SINCE); - - /* HTTP/1.1 needs Host header */ - if (!sr->host.data && sr->protocol == MK_HTTP_PROTOCOL_11) { - mk_http_error(MK_CLIENT_BAD_REQUEST, cs, sr, server); - return MK_EXIT_OK; - } - - /* Should we close the session after this request ? */ - mk_http_keepalive_check(cs, sr, server); - - /* Content Length */ - header = &cs->parser.headers[MK_HEADER_CONTENT_LENGTH]; - if (header->type == MK_HEADER_CONTENT_LENGTH) { - sr->_content_length.data = header->val.data; - sr->_content_length.len = header->val.len; - } - else { - sr->_content_length.data = NULL; - } - - /* Assign the first node alias */ - alias = &sr->host_conf->server_names; - sr->host_alias = mk_list_entry_first(alias, - struct mk_vhost_alias, _head); - - if (sr->host.data) { - /* Set the given port */ - if (cs->parser.header_host_port > 0) { - sr->port = cs->parser.header_host_port; - } - - /* Match the virtual host */ - mk_vhost_get(sr->host, &sr->host_conf, &sr->host_alias, server); - - /* Check if this virtual host have some redirection */ - if (sr->host_conf->header_redirect.data) { - mk_header_set_http_status(sr, MK_REDIR_MOVED); - sr->headers.location = mk_string_dup(sr->host_conf->header_redirect.data); - sr->headers.content_length = 0; - sr->headers.location = NULL; - mk_header_prepare(cs, sr, server); - return 0; - } - } - - /* Is requesting an user home directory ? */ - if (server->conf_user_pub && - sr->uri_processed.len > 2 && - sr->uri_processed.data[1] == MK_USER_HOME) { - - if (mk_user_init(cs, sr, server) != 0) { - mk_http_error(MK_CLIENT_NOT_FOUND, cs, sr, server); - return MK_EXIT_ABORT; - } - } - - /* Plugins Stage 20 */ - ret = mk_plugin_stage_run_20(cs, sr, server); - if (ret == MK_PLUGIN_RET_CLOSE_CONX) { - MK_TRACE("STAGE 20 requested close conexion"); - return MK_EXIT_ABORT; - } - - /* Normal HTTP process */ - status = mk_http_init(cs, sr, server); - - MK_TRACE("[FD %i] HTTP Init returning %i", cs->socket, status); - return status; -} - -/* - * This function allow the core to invoke the closing connection process - * when some connection was not proceesed due to a premature close or similar - * exception, it also take care of invoke the STAGE_40 and STAGE_50 plugins events - */ -static void mk_request_premature_close(int http_status, struct mk_http_session *cs, - struct mk_server *server) -{ - struct mk_http_request *sr; - struct mk_list *sr_list = &cs->request_list; - struct mk_list *host_list = &server->hosts; - - /* - * If the connection is too premature, we need to allocate a temporal session_request - * to do not break the plugins stages - */ - if (mk_list_is_empty(sr_list) == 0) { - sr = &cs->sr_fixed; - memset(sr, 0, sizeof(struct mk_http_request)); - mk_http_request_init(cs, sr, server); - mk_list_add(&sr->_head, &cs->request_list); - } - else { - sr = mk_list_entry_first(sr_list, struct mk_http_request, _head); - } - - /* Raise error */ - if (http_status > 0) { - if (!sr->host_conf) { - sr->host_conf = mk_list_entry_first(host_list, - struct mk_vhost, _head); - } - mk_http_error(http_status, cs, sr, server); - - /* STAGE_40, request has ended */ - mk_plugin_stage_run_40(cs, sr, server); - } - - /* STAGE_50, connection closed and remove the http_session */ - mk_plugin_stage_run_50(cs->socket, server); - mk_http_session_remove(cs, server); -} - -int mk_http_handler_read(struct mk_sched_conn *conn, struct mk_http_session *cs, - struct mk_server *server) -{ - int bytes; - int max_read; - int available = 0; - int new_size; - int total_bytes = 0; - char *tmp = 0; - -#ifdef MK_HAVE_TRACE - int socket = conn->event.fd; -#endif - - MK_TRACE("MAX REQUEST SIZE: %i", server->max_request_size); - - try_pending: - - available = cs->body_size - cs->body_length; - if (available <= 0) { - /* Reallocate buffer size if pending data does not have space */ - new_size = cs->body_size + conn->net->buffer_size; - if (new_size > server->max_request_size) { - MK_TRACE("Requested size is > mk_config->max_request_size"); - mk_request_premature_close(MK_CLIENT_REQUEST_ENTITY_TOO_LARGE, cs, - server); - return -1; - } - - /* - * Check if the body field still points to the initial body_fixed, if so, - * allow the new space required in body, otherwise perform a realloc over - * body. - */ - if (cs->body == cs->body_fixed) { - cs->body = mk_mem_alloc(new_size + 1); - cs->body_size = new_size; - memcpy(cs->body, cs->body_fixed, cs->body_length); - MK_TRACE("[FD %i] New size: %i, length: %i", - socket, new_size, cs->body_length); - } - else { - MK_TRACE("[FD %i] Realloc from %i to %i", - socket, cs->body_size, new_size); - tmp = mk_mem_realloc(cs->body, new_size + 1); - if (tmp) { - cs->body = tmp; - cs->body_size = new_size; - } - else { - mk_request_premature_close(MK_SERVER_INTERNAL_ERROR, cs, - server); - return -1; - } - } - } - - /* Read content */ - max_read = (cs->body_size - cs->body_length); - bytes = mk_sched_conn_read(conn, cs->body + cs->body_length, max_read); - MK_TRACE("[FD %i] read %i", socket, bytes); - - if (bytes == 0) { - MK_TRACE("[FD %i] broken pipe?", socket); - errno = 0; - return -1; - } - else if (bytes == -1) { - return -1; - } - - if (bytes > max_read) { - MK_TRACE("[FD %i] Buffer still have data: %i", - socket, bytes - max_read); - cs->body_length += max_read; - cs->body[cs->body_length] = '\0'; - total_bytes += max_read; - - goto try_pending; - } - else { - cs->body_length += bytes; - cs->body[cs->body_length] = '\0'; - - total_bytes += bytes; - } - - MK_TRACE("[FD %i] Retry total bytes: %i", socket, total_bytes); - return total_bytes; -} - -/* Build error page */ -static int mk_http_error_page(char *title, mk_ptr_t *message, char *signature, - char **out_buf, unsigned long *out_size) -{ - char *temp; - - *out_buf = NULL; - - if (message) { - temp = mk_ptr_to_buf(*message); - } - else { - temp = mk_string_dup(""); - } - - mk_string_build(out_buf, out_size, - MK_REQUEST_DEFAULT_PAGE, title, temp, signature); - mk_mem_free(temp); - return 0; -} - -static int mk_http_range_set(struct mk_http_request *sr, size_t file_size, - struct mk_server *server) -{ - struct response_headers *sh = &sr->headers; - struct mk_stream_input *in; - - in = &sr->in_file; - in->bytes_total = file_size; - in->bytes_offset = 0; - - if (server->resume == MK_TRUE && sr->range.data) { - /* yyy- */ - if (sh->ranges[0] >= 0 && sh->ranges[1] == -1) { - in->bytes_offset = sh->ranges[0]; - in->bytes_total = file_size - in->bytes_offset; - } - - /* yyy-xxx */ - if (sh->ranges[0] >= 0 && sh->ranges[1] >= 0) { - in->bytes_offset = sh->ranges[0]; - in->bytes_total = labs(sh->ranges[1] - sh->ranges[0]) + 1; - } - - /* -xxx */ - if (sh->ranges[0] == -1 && sh->ranges[1] > 0) { - in->bytes_total = sh->ranges[1]; - in->bytes_offset = file_size - sh->ranges[1]; - } - - if ((size_t) in->bytes_offset >= file_size || - in->bytes_total > file_size) { - return -1; - } - - lseek(in->fd, in->bytes_offset, SEEK_SET); - } - return 0; -} - -static int mk_http_range_parse(struct mk_http_request *sr) -{ - int eq_pos, sep_pos, len; - char *buffer = 0; - struct response_headers *sh; - - if (!sr->range.data) - return -1; - - if ((eq_pos = mk_string_char_search(sr->range.data, '=', sr->range.len)) < 0) - return -1; - - if (strncasecmp(sr->range.data, "Bytes", eq_pos) != 0) - return -1; - - if ((sep_pos = mk_string_char_search(sr->range.data, '-', sr->range.len)) < 0) - return -1; - - len = sr->range.len; - sh = &sr->headers; - - /* =-xxx */ - if (eq_pos + 1 == sep_pos) { - sh->ranges[0] = -1; - sh->ranges[1] = (unsigned long) atol(sr->range.data + sep_pos + 1); - - if (sh->ranges[1] <= 0) { - return -1; - } - - sh->content_length = sh->ranges[1]; - return 0; - } - - /* =yyy-xxx */ - if ((eq_pos + 1 != sep_pos) && (len > sep_pos + 1)) { - buffer = mk_string_copy_substr(sr->range.data, eq_pos + 1, sep_pos); - sh->ranges[0] = (unsigned long) atol(buffer); - mk_mem_free(buffer); - - buffer = mk_string_copy_substr(sr->range.data, sep_pos + 1, len); - sh->ranges[1] = (unsigned long) atol(buffer); - mk_mem_free(buffer); - - if (sh->ranges[1] < 0 || (sh->ranges[0] > sh->ranges[1])) { - return -1; - } - - sh->content_length = abs(sh->ranges[1] - sh->ranges[0]) + 1; - return 0; - } - /* =yyy- */ - if ((eq_pos + 1 != sep_pos) && (len == sep_pos + 1)) { - buffer = mk_string_copy_substr(sr->range.data, eq_pos + 1, len); - sr->headers.ranges[0] = (unsigned long) atol(buffer); - mk_mem_free(buffer); - - sh->content_length = (sh->content_length - sh->ranges[0]); - return 0; - } - - return -1; -} - -static int mk_http_directory_redirect_check(struct mk_http_session *cs, - struct mk_http_request *sr, - struct mk_server *server) -{ - int port_redirect = 0; - char *host; - char *location = 0; - char *real_location = 0; - char *protocol = "http"; - unsigned long len; - - /* - * We have to check if there is a slash at the end of - * this string. If it doesn't exist, we send a redirection header. - */ - if (sr->uri_processed.data[sr->uri_processed.len - 1] == '/') { - return 0; - } - - host = mk_ptr_to_buf(sr->host); - - /* - * Add ending slash to the location string - */ - location = mk_mem_alloc(sr->uri_processed.len + 2); - memcpy(location, sr->uri_processed.data, sr->uri_processed.len); - location[sr->uri_processed.len] = '/'; - location[sr->uri_processed.len + 1] = '\0'; - - /* FIXME: should we done something similar for SSL = 443 */ - if (sr->host.data && sr->port > 0) { - if (sr->port != server->standard_port) { - port_redirect = sr->port; - } - } - - if (MK_SCHED_CONN_PROP(cs->conn) & MK_CAP_SOCK_TLS) { - protocol = "https"; - } - - if (port_redirect > 0) { - mk_string_build(&real_location, &len, "%s://%s:%i%s\r\n", - protocol, host, port_redirect, location); - } - else { - mk_string_build(&real_location, &len, "%s://%s%s\r\n", - protocol, host, location); - } - - MK_TRACE("Redirecting to '%s'", real_location); - mk_mem_free(host); - - mk_header_set_http_status(sr, MK_REDIR_MOVED); - sr->headers.content_length = 0; - - mk_ptr_reset(&sr->headers.content_type); - sr->headers.location = real_location; - sr->headers.cgi = SH_NOCGI; - sr->headers.pconnections_left = - (server->max_keep_alive_request - cs->counter_connections); - - mk_header_prepare(cs, sr, server); - - /* we do not free() real_location as it's freed by iov */ - mk_mem_free(location); - sr->headers.location = NULL; - return -1; -} - -/* Look for some index.xxx in pathfile */ -static inline char *mk_http_index_lookup(mk_ptr_t *path_base, - char *buf, size_t buf_size, - size_t *out, size_t *bytes, - struct mk_server *server) -{ - off_t off = 0; - size_t len; - struct mk_string_line *entry; - struct mk_list *head; - - if (!server->index_files) { - return NULL; - } - - off = path_base->len; - memcpy(buf, path_base->data, off); - - mk_list_foreach(head, server->index_files) { - entry = mk_list_entry(head, struct mk_string_line, _head); - - len = off + entry->len + 1; - if (len >= buf_size) { - continue; - } - - memcpy(buf + off, entry->val, entry->len); - buf[off + entry->len] = '\0'; - - if (access(buf, F_OK) == 0) { - MK_TRACE("Index lookup OK '%s'", buf); - *out = off + entry->len; - *bytes = path_base->len - 1; - return buf; - } - } - - return NULL; -} - -/* Turn CORK_OFF once headers are sent */ -#if defined (__linux__) -static inline void mk_http_cb_file_on_consume(struct mk_stream_input *in, - long bytes) -{ - int ret; - (void) bytes; - - /* - * This callback is invoked just once as we want to turn off - * the TCP Cork. We do this just overriding the callback for - * the file stream. - */ - ret = mk_server_cork_flag(in->stream->channel->fd, TCP_CORK_OFF); - if (ret == -1) { - mk_warn("Could not set TCP_CORK/TCP_NOPUSH off"); - } - MK_TRACE("[FD %i] Disable TCP_CORK/TCP_NOPUSH", - in->stream->channel->fd); - in->cb_consumed = NULL; -} -#endif - -int mk_http_init(struct mk_http_session *cs, struct mk_http_request *sr, - struct mk_server *server) -{ - int ret; - int ret_file; - struct mk_mimetype *mime; - struct mk_list *head; - struct mk_list *handlers; - struct mk_plugin *plugin; - struct mk_vhost_handler *h_handler; - struct mk_http_thread *mth = NULL; - size_t index_length; - size_t index_bytes; - char *index_path = NULL; - - MK_TRACE("[FD %i] HTTP Protocol Init, session %p", cs->socket, sr); - - /* Request to root path of the virtualhost in question */ - if (sr->uri_processed.len == 1 && sr->uri_processed.data[0] == '/') { - sr->real_path.data = sr->host_conf->documentroot.data; - sr->real_path.len = sr->host_conf->documentroot.len; - } - - /* Compose real path */ - if (sr->user_home == MK_FALSE) { - int len; - - len = sr->host_conf->documentroot.len + sr->uri_processed.len; - if (len < MK_PATH_BASE) { - memcpy(sr->real_path_static, - sr->host_conf->documentroot.data, - sr->host_conf->documentroot.len); - memcpy(sr->real_path_static + sr->host_conf->documentroot.len, - sr->uri_processed.data, - sr->uri_processed.len); - sr->real_path_static[len] = '\0'; - sr->real_path.data = sr->real_path_static; - sr->real_path.len = len; - } - else { - ret = mk_buffer_cat(&sr->real_path, - sr->host_conf->documentroot.data, - sr->host_conf->documentroot.len, - sr->uri_processed.data, - sr->uri_processed.len); - - if (ret < 0) { - MK_TRACE("Error composing real path"); - return MK_EXIT_ERROR; - } - } - } - - /* Check if this is related to a protocol upgrade */ -#ifdef MK_HAVE_HTTP2 - if (cs->parser.header_connection & MK_HTTP_PARSER_CONN_UPGRADE) { - /* HTTP/2.0 upgrade ? */ - if (cs->parser.header_connection & MK_HTTP_PARSER_CONN_HTTP2_SE) { - MK_TRACE("Connection Upgrade request: HTTP/2.0"); - /* - * This is a HTTP/2.0 upgrade, we need to validate that we - * have at least the 'Upgrade' and 'HTTP2-Settings' headers. - */ - struct mk_http_header *p; - p = &cs->parser.headers[MK_HEADER_HTTP2_SETTINGS]; - if (cs->parser.header_upgrade == MK_HTTP_PARSER_UPGRADE_H2C && - p->key.data) { - /* - * Switch protocols and invoke the callback upgrade to prepare - * the new protocol internals. - */ - mk_sched_switch_protocol(cs->conn, MK_CAP_HTTP2); - return cs->conn->protocol->cb_upgrade(cs, sr, server); - } - else { - MK_TRACE("Invalid client upgrade request, skip it"); - } - } - } -#endif - - /* Check backward directory request */ - if (memmem(sr->uri_processed.data, sr->uri_processed.len, - MK_HTTP_DIRECTORY_BACKWARD, - sizeof(MK_HTTP_DIRECTORY_BACKWARD) - 1)) { - return mk_http_error(MK_CLIENT_FORBIDDEN, cs, sr, server); - } - - if (sr->_content_length.data && - (sr->method != MK_METHOD_POST && - sr->method != MK_METHOD_PUT)) { - sr->_content_length.data = NULL; - sr->_content_length.len = 0; - } - - ret_file = mk_file_get_info(sr->real_path.data, &sr->file_info, MK_FILE_READ); - - /* Manually set the headers input streams */ - sr->in_headers.type = MK_STREAM_IOV; - sr->in_headers.dynamic = MK_FALSE; - sr->in_headers.cb_consumed = NULL; - sr->in_headers.cb_finished = NULL; - sr->in_headers.stream = &sr->stream; - mk_list_add(&sr->in_headers._head, &sr->stream.inputs); - - /* Plugin Stage 30: look for handlers for this request */ - if (sr->stage30_blocked == MK_FALSE) { - sr->uri_processed.data[sr->uri_processed.len] = '\0'; - handlers = &sr->host_conf->handlers; - mk_list_foreach(head, handlers) { - h_handler = mk_list_entry(head, struct mk_vhost_handler, _head); - - if (re_matchp(h_handler->match, - sr->uri_processed.data, NULL) == -1) { - continue; - } - - if (h_handler->cb) { - /* Create coroutine/thread context */ - sr->headers.content_length = 0; - mth = mk_http_thread_create(MK_HTTP_THREAD_LIB, - h_handler, - cs, sr, - 0, NULL); - if (!mth) { - return -1; - } - - mk_http_thread_start(mth); - return MK_EXIT_OK; - } - else { - if (!h_handler->handler) { - return mk_http_error(MK_SERVER_INTERNAL_ERROR, cs, sr, - server); - } - plugin = h_handler->handler; - sr->stage30_handler = h_handler->handler; - ret = plugin->stage->stage30(plugin, cs, sr, - h_handler->n_params, - &h_handler->params); - mk_header_prepare(cs, sr, server); - } - - MK_TRACE("[FD %i] STAGE_30 returned %i", cs->socket, ret); - switch (ret) { - case MK_PLUGIN_RET_CONTINUE: - /* FIXME: PLUGINS DISABLED - if ((plugin->flags & MK_PLUGIN_THREAD) && - plugin->stage->stage30_thread) { - mth = mk_http_thread_new(MK_HTTP_THREAD_PLUGIN, - plugin, cs, sr, - h_handler->n_params, - &h_handler->params); - printf("[http thread] %p\n", mth); - mk_http_thread_resume(mth->parent); - } - */ - return MK_PLUGIN_RET_CONTINUE; - case MK_PLUGIN_RET_CLOSE_CONX: - if (sr->headers.status > 0) { - return mk_http_error(sr->headers.status, cs, sr, server); - } - else { - return mk_http_error(MK_CLIENT_FORBIDDEN, cs, sr, server); - } - case MK_PLUGIN_RET_END: - return MK_EXIT_OK; - } - } - } - - /* If there is no handler and the resource don't exists, raise a 404 */ - if (ret_file == -1) { - return mk_http_error(MK_CLIENT_NOT_FOUND, cs, sr, server); - } - - /* is it a valid directory ? */ - if (sr->file_info.is_directory == MK_TRUE) { - /* Send redirect header if end slash is not found */ - if (mk_http_directory_redirect_check(cs, sr, server) == -1) { - MK_TRACE("Directory Redirect"); - - /* Redirect has been sent */ - return -1; - } - - /* looking for an index file */ - char tmppath[MK_MAX_PATH]; - index_path = mk_http_index_lookup(&sr->real_path, - tmppath, MK_MAX_PATH, - &index_length, &index_bytes, - server); - if (index_path) { - if (sr->real_path.data != sr->real_path_static) { - mk_ptr_free(&sr->real_path); - sr->real_path.data = mk_string_dup(index_path); - } - /* If it's static and it still fits */ - else if (index_length < MK_PATH_BASE) { - memcpy(sr->real_path_static, index_path, index_length); - sr->real_path_static[index_length] = '\0'; - } - /* It was static, but didn't fit */ - else { - sr->real_path.data = mk_string_dup(index_path); - } - sr->real_path.len = index_length; - - ret = mk_file_get_info(sr->real_path.data, - &sr->file_info, MK_FILE_READ); - if (ret != 0) { - return mk_http_error(MK_CLIENT_FORBIDDEN, cs, sr, server); - } - - } - } - -#ifndef _WIN32 - /* Check symbolic link file */ - if (sr->file_info.is_link == MK_TRUE) { - if (server->symlink == MK_FALSE) { - return mk_http_error(MK_CLIENT_FORBIDDEN, cs, sr, server); - } - else { - int n; - char linked_file[MK_MAX_PATH]; - n = readlink(sr->real_path.data, linked_file, MK_MAX_PATH); - if (n < 0) { - return mk_http_error(MK_CLIENT_FORBIDDEN, cs, sr, server); - } - } - } -#endif - - /* Plugin Stage 30: look for handlers for this request */ - if (sr->stage30_blocked == MK_FALSE) { - char *uri; - - if (!index_path) { - sr->uri_processed.data[sr->uri_processed.len] = '\0'; - uri = sr->uri_processed.data; - } - else { - uri = sr->real_path.data + index_bytes; - } - - handlers = &sr->host_conf->handlers; - mk_list_foreach(head, handlers) { - h_handler = mk_list_entry(head, struct mk_vhost_handler, _head); - if (re_matchp(h_handler->match, uri, NULL) == -1) { - continue; - } - - plugin = h_handler->handler; - sr->stage30_handler = h_handler->handler; - ret = plugin->stage->stage30(plugin, cs, sr, - h_handler->n_params, - &h_handler->params); - - MK_TRACE("[FD %i] STAGE_30 returned %i", cs->socket, ret); - switch (ret) { - case MK_PLUGIN_RET_CONTINUE: - return MK_PLUGIN_RET_CONTINUE; - case MK_PLUGIN_RET_CLOSE_CONX: - if (sr->headers.status > 0) { - return mk_http_error(sr->headers.status, cs, sr, server); - } - else { - return mk_http_error(MK_CLIENT_FORBIDDEN, cs, sr, server); - } - case MK_PLUGIN_RET_END: - return MK_EXIT_OK; - } - } - } - - /* - * Monkey listens for PUT and DELETE methods in addition to GET, POST and - * HEAD, but it does not care about them, so if any plugin did not worked - * on it, Monkey will return error 501 (501 Not Implemented). - */ - if (sr->method == MK_METHOD_PUT || sr->method == MK_METHOD_DELETE) { - return mk_http_error(MK_CLIENT_METHOD_NOT_ALLOWED, cs, sr, server); - } - else if (sr->method == MK_METHOD_UNKNOWN) { - return mk_http_error(MK_SERVER_NOT_IMPLEMENTED, cs, sr, server); - } - - /* counter connections */ - sr->headers.pconnections_left = (int) - (server->max_keep_alive_request - cs->counter_connections); - - /* Set default value */ - mk_header_set_http_status(sr, MK_HTTP_OK); - sr->headers.location = NULL; - sr->headers.content_length = 0; - - /* - * For OPTIONS method, we let the plugin handle it and - * return without any content. - */ - if (sr->method == MK_METHOD_OPTIONS) { - /* FIXME: OPTIONS NOT WORKING */ - //sr->headers.allow_methods.data = MK_METHOD_AVAILABLE; - //sr->headers.allow_methods.len = strlen(MK_METHOD_AVAILABLE); - - mk_ptr_reset(&sr->headers.content_type); - mk_header_prepare(cs, sr, server); - return MK_EXIT_OK; - } - else { - mk_ptr_reset(&sr->headers.allow_methods); - } - - /* read permissions and check file */ - if (sr->file_info.read_access == MK_FALSE) { - return mk_http_error(MK_CLIENT_FORBIDDEN, cs, sr, server); - } - - /* Matching MimeType */ - mime = mk_mimetype_find(server, &sr->real_path); - if (!mime) { - mime = server->mimetype_default; - } - - if (sr->file_info.is_directory == MK_TRUE) { - return mk_http_error(MK_CLIENT_FORBIDDEN, cs, sr, server); - } - - /* get file size */ - if (sr->file_info.size == 0) { - return mk_http_error(MK_CLIENT_NOT_FOUND, cs, sr, server); - } - - /* Configure some headers */ - sr->headers.last_modified = sr->file_info.last_modification; - sr->headers.etag_len = snprintf(sr->headers.etag_buf, - MK_HEADER_ETAG_SIZE, - "ETag: \"%x-%zx\"\r\n", - (unsigned int) sr->file_info.last_modification, - sr->file_info.size); - - if (sr->if_modified_since.data && sr->method == MK_METHOD_GET) { - time_t date_client; /* Date sent by client */ - time_t date_file_server; /* Date server file */ - - date_client = mk_utils_gmt2utime(sr->if_modified_since.data); - date_file_server = sr->file_info.last_modification; - - if (date_file_server <= date_client && - date_client > 0) { - mk_header_set_http_status(sr, MK_NOT_MODIFIED); - mk_header_prepare(cs, sr, server); - return MK_EXIT_OK; - } - } - - /* Object size for log and response headers */ - sr->headers.content_length = sr->file_info.size; - sr->headers.real_length = sr->file_info.size; - - /* Open file */ - if (mk_likely(sr->file_info.size > 0)) { - sr->file_fd = mk_vhost_open(sr, server); - if (sr->file_fd == -1) { - MK_TRACE("open() failed"); - return mk_http_error(MK_CLIENT_FORBIDDEN, cs, sr, server); - } - sr->in_file.fd = sr->file_fd; - sr->in_file.bytes_offset = 0; - sr->in_file.bytes_total = sr->file_info.size; - sr->in_file.stream = &sr->stream; - } - - /* Process methods */ - if (sr->method == MK_METHOD_GET || sr->method == MK_METHOD_HEAD) { - if (mime) { - sr->headers.content_type = mime->header_type; - } - - /* HTTP Ranges */ - if (sr->range.data != NULL && server->resume == MK_TRUE) { - if (mk_http_range_parse(sr) < 0) { - sr->headers.ranges[0] = -1; - sr->headers.ranges[1] = -1; - return mk_http_error(MK_CLIENT_BAD_REQUEST, cs, sr, server); - } - if (sr->headers.ranges[0] >= 0 || sr->headers.ranges[1] >= 0) { - mk_header_set_http_status(sr, MK_HTTP_PARTIAL); - } - - /* Calc bytes to send & offset */ - if (mk_http_range_set(sr, sr->file_info.size, server) != 0) { - sr->headers.content_length = -1; - sr->headers.ranges[0] = -1; - sr->headers.ranges[1] = -1; - return mk_http_error(MK_CLIENT_REQUESTED_RANGE_NOT_SATISF, - cs, sr, server); - } - } - } - else { - /* without content-type */ - mk_ptr_reset(&sr->headers.content_type); - } - - /* Send headers */ - mk_header_prepare(cs, sr, server); - if (mk_unlikely(sr->headers.content_length == 0)) { - return 0; - } - /* Send file content */ - if (sr->method == MK_METHOD_GET || sr->method == MK_METHOD_POST) { - /* Note: bytes and offsets are set after the Range check */ - sr->in_file.type = MK_STREAM_FILE; - mk_stream_append(&sr->in_file, &sr->stream); - } - - /* - * Enable TCP Cork for the remote socket. It will be disabled - * later by the file stream on the channel after send the first - * file bytes. - */ -#if defined(__linux__) - sr->in_file.cb_consumed = mk_http_cb_file_on_consume; -#endif - - /* - * Enable CORK/NO_PUSH - * ------------------- - * If it was compiled for Linux, it will turn the Cork off after - * send the first round of bytes from the target static file. - * - * For OSX, it sets TCP_NOPUSH off after send all HTTP headers. Refer - * to mk_header.c for more details. - */ - //mk_server_cork_flag(cs->socket, TCP_CORK_ON); - - /* Start sending data to the channel */ - return MK_EXIT_OK; -} - -/* - * Check if a connection can stay open using - * the keepalive headers vars and Monkey configuration as criteria - */ -int mk_http_keepalive_check(struct mk_http_session *cs, - struct mk_http_request *sr, - struct mk_server *server) -{ - if (server->keep_alive == MK_FALSE) { - return -1; - } - - /* Default Keepalive is off */ - if (sr->protocol == MK_HTTP_PROTOCOL_10) { - cs->close_now = MK_TRUE; - } - else if (sr->protocol == MK_HTTP_PROTOCOL_11) { - cs->close_now = MK_FALSE; - } - - if (sr->connection.data) { - if (cs->parser.header_connection == MK_HTTP_PARSER_CONN_KA && - sr->protocol == MK_HTTP_PROTOCOL_11) { - cs->close_now = MK_FALSE; - } - else if (cs->parser.header_connection == MK_HTTP_PARSER_CONN_CLOSE) { - cs->close_now = MK_TRUE; - } - } - - /* Client has reached keep-alive connections limit */ - if (cs->counter_connections >= server->max_keep_alive_request) { - cs->close_now = MK_TRUE; - return -1; - } - - return 0; -} - -static inline void mk_http_request_ka_next(struct mk_http_session *cs) -{ - cs->body_length = 0; - cs->counter_connections++; - - /* Update data for scheduler */ - cs->init_time = cs->server->clock_context->log_current_utime; - cs->status = MK_REQUEST_STATUS_INCOMPLETE; - - /* Initialize parser */ - mk_http_parser_init(&cs->parser); -} - -int mk_http_request_end(struct mk_http_session *cs, struct mk_server *server) -{ - int ret; - int status; - int len; - struct mk_http_request *sr = NULL; - - if (server->max_keep_alive_request <= cs->counter_connections) { - cs->close_now = MK_TRUE; - goto shutdown; - } - - /* Check if we have some enqueued pipeline requests */ - ret = mk_http_parser_more(&cs->parser, cs->body_length); - if (ret == MK_TRUE) { - /* Our pipeline request limit is the same that our keepalive limit */ - cs->counter_connections++; - len = (cs->body_length - cs->parser.i) -1; - memmove(cs->body, - cs->body + cs->parser.i + 1, - len); - cs->body_length = len; - - /* Prepare for next one */ - sr = mk_list_entry_first(&cs->request_list, struct mk_http_request, _head); - mk_http_request_free(sr, server); - mk_http_request_init(cs, sr, server); - mk_http_parser_init(&cs->parser); - status = mk_http_parser(sr, &cs->parser, cs->body, cs->body_length, - server); - if (status == MK_HTTP_PARSER_OK) { - ret = mk_http_request_prepare(cs, sr, server); - if (ret == MK_EXIT_ABORT) { - return -1; - } - - /* - * Return 1 means, we still have more data to send in a different - * scheduler round. - */ - return 1; - } - else if (status == MK_HTTP_PARSER_PENDING) { - return 0; - } - else if (status == MK_HTTP_PARSER_ERROR) { - cs->close_now = MK_TRUE; - } - } - - shutdown: - /* - * We need to ask to http_keepalive if this - * connection can continue working or we must - * close it. - */ - if (cs->close_now == MK_TRUE) { - MK_TRACE("[FD %i] No KeepAlive mode, remove", cs->conn->event.fd); - mk_http_session_remove(cs, server); - return -1; - } - else { - mk_http_request_free_list(cs, server); - mk_http_request_ka_next(cs); - mk_sched_conn_timeout_add(cs->conn, mk_sched_get_thread_conf()); - return 0; - } - - return -1; -} - -void cb_stream_page_finished(struct mk_stream_input *in) -{ - mk_ptr_t *page = in->buffer; - - mk_ptr_free(page); - mk_mem_free(page); -} - -/* Enqueue an error response. This function always returns MK_EXIT_OK */ -int mk_http_error(int http_status, struct mk_http_session *cs, - struct mk_http_request *sr, - struct mk_server *server) -{ - int ret, fd; - size_t count; - mk_ptr_t message; - mk_ptr_t page; - struct mk_vhost_error_page *entry; - struct mk_list *head; - struct file_info finfo; - struct mk_iov *iov; - - /* This function requires monkey to be properly initialized which is not the case - * when it's just used to parse http requests in fluent-bit so we want it to ignore - * that case and let fluent-bit handle it. - */ - if (server->workers == 0) { - return MK_EXIT_OK; - } - - mk_header_set_http_status(sr, http_status); - mk_ptr_reset(&page); - - /* - * We are nice sending error pages for clients who at least respect - * the especification - */ - if (http_status != MK_CLIENT_LENGTH_REQUIRED && - http_status != MK_CLIENT_BAD_REQUEST && - http_status != MK_CLIENT_REQUEST_ENTITY_TOO_LARGE) { - - /* Lookup a customized error page */ - mk_list_foreach(head, &sr->host_conf->error_pages) { - entry = mk_list_entry(head, struct mk_vhost_error_page, _head); - if (entry->status != http_status) { - continue; - } - - /* validate error file */ - ret = mk_file_get_info(entry->real_path, &finfo, MK_FILE_READ); - if (ret == -1) { - break; - } - - /* open file */ - fd = open(entry->real_path, server->open_flags); - if (fd == -1) { - break; - } - /* This fd seems to be leaked, we need to verify this logic */ - - /* Outgoing headers */ - sr->headers.content_length = finfo.size; - sr->headers.real_length = finfo.size; - mk_header_prepare(cs, sr, server); - - /* Stream setup */ - mk_stream_in_file(&sr->stream, &sr->in_file, sr->file_fd, - finfo.size, 0, NULL, NULL); - return MK_EXIT_OK; - } - } - - mk_ptr_reset(&message); - - switch (http_status) { - case MK_CLIENT_FORBIDDEN: - mk_http_error_page("Forbidden", - &sr->uri, - server->server_signature, - &page.data, &page.len); - break; - case MK_CLIENT_NOT_FOUND: - mk_string_build(&message.data, &message.len, - "The requested URL was not found on this server."); - mk_http_error_page("Not Found", - &message, - server->server_signature, - &page.data, &page.len); - mk_ptr_free(&message); - break; - case MK_CLIENT_REQUEST_ENTITY_TOO_LARGE: - mk_string_build(&message.data, &message.len, - "The request entity is too large."); - mk_http_error_page("Entity too large", - &message, - server->server_signature, - &page.data, &page.len); - mk_ptr_free(&message); - break; - case MK_CLIENT_METHOD_NOT_ALLOWED: - mk_http_error_page("Method Not Allowed", - &sr->uri, - server->server_signature, - &page.data, &page.len); - break; - case MK_SERVER_NOT_IMPLEMENTED: - mk_http_error_page("Method Not Implemented", - &sr->uri, - server->server_signature, - &page.data, &page.len); - break; - case MK_SERVER_INTERNAL_ERROR: - mk_http_error_page("Internal Server Error", - &sr->uri, - server->server_signature, - &page.data, &page.len); - break; - } - - if (page.len > 0 && sr->method != MK_METHOD_HEAD && sr->method != MK_METHOD_UNKNOWN) { - sr->headers.content_length = page.len; - } - else { - sr->headers.content_length = 0; - } - - sr->headers.location = NULL; - sr->headers.cgi = SH_NOCGI; - sr->headers.pconnections_left = 0; - sr->headers.last_modified = -1; - - if (!page.data) { - mk_ptr_reset(&sr->headers.content_type); - } - else { - mk_ptr_set(&sr->headers.content_type, "Content-Type: text/html\r\n"); - } - - mk_header_prepare(cs, sr, server); - if (page.data) { - if (sr->method != MK_METHOD_HEAD) { - if (sr->headers._extra_rows) { - iov = sr->headers._extra_rows; - sr->in_headers_extra.bytes_total += page.len; - } - else { - iov = &sr->headers.headers_iov; - sr->in_headers.bytes_total += page.len; - } - mk_iov_add(iov, page.data, page.len, MK_TRUE); - } - else { - mk_mem_free(page.data); - } - } - - mk_channel_write(cs->channel, &count); - mk_http_request_end(cs, server); - - return MK_EXIT_OK; -} - -/* - * From thread mk_sched_worker "list", remove the http_session - * struct information - */ -void mk_http_session_remove(struct mk_http_session *cs, - struct mk_server *server) -{ - struct mk_list *tmp; - struct mk_list *head; - struct mk_plugin *handler; - struct mk_http_request *sr; - - MK_TRACE("[FD %i] HTTP Session remove", cs->socket); - if (cs->_sched_init == MK_FALSE) { - return; - } - - /* On session remove, make sure to cleanup any handler */ - mk_list_foreach_safe(head, tmp, &cs->request_list) { - sr = mk_list_entry(head, struct mk_http_request, _head); - if (sr->stage30_handler) { - MK_TRACE("Hangup stage30 handler"); - handler = sr->stage30_handler; - if (mk_unlikely(!handler->stage->stage30_hangup)) { - mk_warn("Plugin %s, do not implement stage30_hangup", handler->name); - continue; - } - handler->stage->stage30_hangup(handler, cs, sr); - } - } - - if (cs->body != cs->body_fixed) { - mk_mem_free(cs->body); - } - mk_http_request_free_list(cs, server); - mk_list_del(&cs->request_list); - - cs->_sched_init = MK_FALSE; -} - -/* FIXME: nobody is using this */ -struct mk_http_session *mk_http_session_lookup(int socket) -{ - (void) socket; - return NULL; -} - - -/* Initialize a HTTP session (just created) */ -int mk_http_session_init(struct mk_http_session *cs, struct mk_sched_conn *conn, - struct mk_server *server) -{ - /* Alloc memory for node */ - cs->_sched_init = MK_TRUE; - cs->pipelined = MK_FALSE; - cs->counter_connections = 0; - cs->close_now = MK_FALSE; - cs->socket = conn->event.fd; - cs->status = MK_REQUEST_STATUS_INCOMPLETE; - cs->server = server; - - /* Map the channel, just for protocol-handler internal stuff */ - cs->channel = &conn->channel; - - /* Map the connection instance, required to handle exceptions */ - cs->conn = conn; - - /* creation time in unix time */ - cs->init_time = conn->arrive_time; - - /* alloc space for body content */ - if (conn->net->buffer_size > MK_REQUEST_CHUNK) { - cs->body = mk_mem_alloc(conn->net->buffer_size); - cs->body_size = conn->net->buffer_size; - } - else { - /* Buffer size based in Chunk bytes */ - cs->body = cs->body_fixed; - cs->body_size = MK_REQUEST_CHUNK; - } - - /* Current data length */ - cs->body_length = 0; - - /* Init session request list */ - mk_list_init(&cs->request_list); - - /* Initialize the parser */ - mk_http_parser_init(&cs->parser); - - return 0; -} - - -void mk_http_request_free(struct mk_http_request *sr, struct mk_server *server) -{ - /* Let the vhost interface to handle the session close */ - mk_vhost_close(sr, server); - - if (sr->headers.location) { - mk_mem_free(sr->headers.location); - } - - if (sr->uri_processed.data != sr->uri.data) { - mk_ptr_free(&sr->uri_processed); - } - - if (sr->real_path.data != sr->real_path_static) { - mk_ptr_free(&sr->real_path); - } - - if (sr->stream.channel) { - mk_stream_release(&sr->stream); - } -} - -void mk_http_request_free_list(struct mk_http_session *cs, - struct mk_server *server) -{ - struct mk_list *head, *tmp; - struct mk_http_request *request; - - /* sr = last node */ - MK_TRACE("[FD %i] Free struct client_session", cs->socket); - mk_list_foreach_safe(head, tmp, &cs->request_list) { - request = mk_list_entry(head, struct mk_http_request, _head); - mk_list_del(&request->_head); - - mk_http_request_free(request, server); - if (request != &cs->sr_fixed) { - mk_mem_free(request); - } - } -} - -/* - * Lookup a known header or a non-known header. For unknown headers - * set the 'key' value wth a lowercase string - */ -struct mk_http_header *mk_http_header_get(int name, struct mk_http_request *req, - const char *key, unsigned int len) -{ - int i; - struct mk_http_parser *parser = &req->session->parser; - struct mk_http_header *header; - - /* Known header */ - if (name >= 0 && name < MK_HEADER_SIZEOF) { - return &parser->headers[name]; - } - - /* Check if want to retrieve a custom header */ - if (name == MK_HEADER_OTHER) { - /* Iterate over the extra headers identified by the parser */ - for (i = 0; i < parser->headers_extra_count; i++) { - header = &parser->headers_extra[i]; - if (header->key.len != len) { - continue; - } - - if (strncmp(header->key.data, key, len) == 0) { - return header; - } - } - return NULL; - } - - return NULL; -} - -/* - * Main callbacks for the Scheduler - */ -int mk_http_sched_read(struct mk_sched_conn *conn, - struct mk_sched_worker *worker, - struct mk_server *server) -{ - int ret; - int status; - size_t count; - (void) worker; - struct mk_http_session *cs; - struct mk_http_request *sr; - -#ifdef MK_HAVE_TRACE - int socket = conn->event.fd; -#endif - - cs = mk_http_session_get(conn); - if (cs->_sched_init == MK_FALSE) { - /* Create session for the client */ - MK_TRACE("[FD %i] Create HTTP session", socket); - ret = mk_http_session_init(cs, conn, server); - if (ret == -1) { - return -1; - } - } - - /* Invoke the read handler, on this case we only support HTTP (for now :) */ - ret = mk_http_handler_read(conn, cs, server); - if (ret > 0) { - if (mk_list_is_empty(&cs->request_list) == 0) { - /* Add the first entry */ - sr = &cs->sr_fixed; - mk_list_add(&sr->_head, &cs->request_list); - mk_http_request_init(cs, sr, server); - } - else { - sr = mk_list_entry_first(&cs->request_list, struct mk_http_request, _head); - } - status = mk_http_parser(sr, &cs->parser, cs->body, - cs->body_length, server); - if (status == MK_HTTP_PARSER_OK) { - MK_TRACE("[FD %i] HTTP_PARSER_OK", socket); - if (mk_http_status_completed(cs, conn) == -1) { - mk_http_session_remove(cs, server); - return -1; - } - mk_sched_conn_timeout_del(conn); - ret = mk_http_request_prepare(cs, sr, server); - } - else if (status == MK_HTTP_PARSER_ERROR) { - /* The HTTP parser may enqueued some response error */ - if (mk_channel_is_empty(cs->channel) != 0) { - mk_channel_write(cs->channel, &count); - } - mk_http_session_remove(cs, server); - MK_TRACE("[FD %i] HTTP_PARSER_ERROR", socket); - return -1; - } - else { - MK_TRACE("[FD %i] HTTP_PARSER_PENDING", socket); - } - } - - return ret; -} - -/* The scheduler got a connection close event from the remote client */ -int mk_http_sched_close(struct mk_sched_conn *conn, - struct mk_sched_worker *sched, - int type, struct mk_server *server) -{ - struct mk_http_session *session; - (void) sched; - -#ifdef MK_HAVE_TRACE - MK_TRACE("[FD %i] HTTP sched close (type=%i)", conn->event.fd, type); -#else - (void) type; -#endif - - /* Release resources of the requests and session */ - session = mk_http_session_get(conn); - mk_http_session_remove(session, server); - return 0; -} - -int mk_http_sched_done(struct mk_sched_conn *conn, - struct mk_sched_worker *worker, - struct mk_server *server) -{ - (void) worker; - struct mk_http_session *session; - struct mk_http_request *sr; - - session = mk_http_session_get(conn); - sr = mk_list_entry_first(&session->request_list, - struct mk_http_request, _head); - mk_plugin_stage_run_40(session, sr, server); - - return mk_http_request_end(session, server); -} - -struct mk_sched_handler mk_http_handler = { - .name = "http", - .cb_read = mk_http_sched_read, - .cb_close = mk_http_sched_close, - .cb_done = mk_http_sched_done, - .sched_extra_size = sizeof(struct mk_http_session), - .capabilities = MK_CAP_HTTP -}; diff --git a/fluent-bit/lib/monkey/mk_server/mk_http2.c b/fluent-bit/lib/monkey/mk_server/mk_http2.c deleted file mode 100644 index 7a4f1e82..00000000 --- a/fluent-bit/lib/monkey/mk_server/mk_http2.c +++ /dev/null @@ -1,384 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* Monkey HTTP Server - * ================== - * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _GNU_SOURCE - -#include <inttypes.h> - -#include <monkey/mk_http2.h> -#include <monkey/mk_http2_settings.h> -#include <monkey/mk_header.h> -#include <monkey/mk_scheduler.h> - -/* HTTP/2 Connection Preface */ -#define MK_HTTP2_PREFACE "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" -static mk_ptr_t http2_preface = { - .data = MK_HTTP2_PREFACE, - .len = sizeof(MK_HTTP2_PREFACE) - 1 -}; - -static inline void buffer_consume(struct mk_http2_session *h2s, int bytes) -{ - memmove(h2s->buffer, - h2s->buffer + bytes, - h2s->buffer_length - bytes); - - MK_TRACE("[h2] consume buffer length from %i to %i", - h2s->buffer_length, h2s->buffer_length - bytes); - h2s->buffer_length -= bytes; -} - -static struct mk_http2_session *mk_http2_session_create() -{ - struct mk_http2_session *h2s; - - h2s = mk_mem_alloc(sizeof(struct mk_http2_session)); - if (!h2s) { - return NULL; - } - h2s->buffer = NULL; - h2s->buffer_length = 0; - h2s->buffer_size = sizeof(h2s->buffer_fixed); - h2s->buffer = h2s->buffer_fixed; - h2s->settings = MK_HTTP2_SETTINGS_DEFAULT; - - return h2s; -} - -/* FIXME -static int mk_http2_session_destroy(struct mk_http2_session *h2s) -{ - if (h2s->buffer != h2s->buffer_fixed) { - mk_mem_free(h2s->buffer); - } - mk_mem_free(h2s); - return 0; -} - -static int mk_http2_frame_header(char *buf, uint32_t length, uint8_t type, - uint32_t flags, void *data) -{ - struct mk_http2_frame *f = (struct mk_http2_frame *) buf; - - f->len_type = (length << 8 | type); - f->flags = flags; - f->payload = data; - - return sizeof(struct mk_http2_frame); -} - -*/ - -/* Handle an upgraded session */ -static int mk_http2_upgrade(void *cs, void *sr, struct mk_server *server) -{ - struct mk_http_session *s = cs; - struct mk_http_request *r = sr; - struct mk_http2_session *h2s; - - mk_header_set_http_status(r, MK_INFO_SWITCH_PROTOCOL); - r->headers.connection = MK_HEADER_CONN_UPGRADED; - r->headers.upgrade = MK_HEADER_UPGRADED_H2C; - mk_header_prepare(s, r, server); - - h2s = mk_http2_session_create(); - if (!h2s) { - return -1; - } - - h2s->status = MK_HTTP2_UPGRADED; - s->conn->data = h2s; - - return MK_HTTP_OK; -} - -/* FIXME Decode a frame header, no more... no less -static inline void mk_http2_frame_decode_header(uint8_t *buf, - struct mk_http2_frame *frame) -{ - struct mk_http2_session *h2s; - (void) h2s; - - frame->len_type = mk_http2_bitdec_32u(buf); - frame->flags = buf[4]; - frame->stream_id = mk_http2_bitdec_stream_id(buf + 5); - frame->payload = buf + 9; - -#ifdef MK_HAVE_TRACE - MK_TRACE("Frame Header"); - printf(" length=%i, type=%i, stream_id=%i\n", - mk_http2_frame_len(frame), - mk_http2_frame_type(frame), - frame->stream_id); -#endif -} -*/ - -static inline int mk_http2_handle_settings(struct mk_sched_conn *conn, - struct mk_http2_frame *frame) -{ - int i; - int frame_len; - int settings; - int setting_size = 6; /* 16 bits identifier + 32 bits value = 6 bytes */ - uint16_t setting_id; - uint32_t setting_value; - uint8_t *p; - struct mk_http2_session *h2s; - - h2s = conn->data; - frame_len = mk_http2_frame_len(frame); - if (frame->flags == MK_HTTP2_SETTINGS_ACK) { - /* - * Nothing to do, the peer just received our SETTINGS and it's - * sending an acknowledge. - * - * note: validate that frame length is zero. - */ - if (frame_len > 0) { - /* - * This must he handled as a connection error, we must reply - * with a FRAME_SIZE_ERROR. ref: - * - * https://httpwg.github.io/specs/rfc7540.html#SETTINGS - */ - - /* FIXME: send a GOAWAY error frame */ - MK_TRACE("FRAME SIZE ERR: %i\n", frame_len); - return -1; - - } - return 0; - } - - /* - * Iterate our SETTINGS payload, it may contain many entries in the - * following format: - * - * +-------------------------------+ - * | Identifier (16) | - * +-------------------------------+-------------------------------+ - * | Value (32) | - * +---------------------------------------------------------------+ - * - * 48 bits = 6 bytes - */ - settings = (frame_len / setting_size); - for (i = 0; i < settings; i++ ) { - /* Seek payload per SETTINGS entry */ - p = frame->payload + (setting_size * i); - - setting_id = p[0] << 8 | p[1]; - setting_value = p[2] << 24 | p[3] << 16 | p[4] << 8 | p[5]; - MK_H2_TRACE(conn, "[Setting] ID=%" PRIu16 " VAL=%" PRIu32, - setting_id, setting_value); - - switch (setting_id) { - case MK_HTTP2_SETTINGS_HEADER_TABLE_SIZE: - /* unhandled */ - break; - case MK_HTTP2_SETTINGS_ENABLE_PUSH: - if (setting_value != 0 && setting_value != 1) { - /* FIXME: PROTOCOL_ERROR */ - MK_H2_TRACE(conn, "Invalid SETTINGS_ENABLE_PUSH"); - return -1; - } - h2s->settings.enable_push = setting_value; - break; - case MK_HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS: - if (setting_value < 64) { - h2s->settings.max_concurrent_streams = setting_value; - } - else { - h2s->settings.max_concurrent_streams = 64; - } - MK_H2_TRACE(conn, "SETTINGS MAX_CONCURRENT_STREAMS=%i", - setting_value); - break; - case MK_HTTP2_SETTINGS_INITIAL_WINDOW_SIZE: - if (setting_value < 65535 || setting_value > 2147483647) { - /* FIXME: send FLOW_CONTROL_ERROR */ - MK_H2_TRACE(conn, "Invalid INITIAL_WINDOW_SIZE"); - return -1; - } - h2s->settings.initial_window_size = setting_value; - break; - case MK_HTTP2_SETTINGS_MAX_FRAME_SIZE: - if (setting_value < 16384 || setting_value > 2147483647) { - /* FIXME: send PROTOCOL_ERROR */ - return -1; - } - h2s->settings.max_frame_size = setting_value; - break; - case MK_HTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: - /* Unhandled */ - break; - default: - /* - * 5.5 Extending HTTP/2: ...Implementations MUST ignore unknown - * or unsupported values in all extensible protocol elements... - */ - break; - } - } - - /* FIXME // No errors, send the ACK - mk_http2_send_raw(conn, MK_HTTP2_SETTINGS_ACK_FRAME, - sizeof(MK_HTTP2_SETTINGS_ACK_FRAME) - 1); - */ - return 0; -} - - -static inline int mk_http2_frame_run(struct mk_sched_conn *conn, - struct mk_sched_worker *worker) -{ - int ret; - struct mk_http2_frame frame; - struct mk_http2_session *h2s; - (void) worker; - - h2s = conn->data; - - /* Decode the frame header */ - //FIXME mk_http2_frame_decode_header(h2s->buffer, &frame); - - /* Do some validations */ - if (h2s->buffer_length < (MK_HTTP2_HEADER_SIZE + (frame.len_type >> 8))) { - /* FIXME: need more data */ - return 0; - } - - /* Do some work based on the frame type */ - if (mk_http2_frame_type(&frame) == MK_HTTP2_SETTINGS) { - ret = mk_http2_handle_settings(conn, &frame); - /* FIXME: send our MK_HTTP2_SETTINGS_ACK_FRAME */ - return ret; - } - - return 0; -} - -static int mk_http2_sched_read(struct mk_sched_conn *conn, - struct mk_sched_worker *worker, - struct mk_server *server) -{ - int bytes; - int new_size; - int available; - char *tmp; - struct mk_http2_session *h2s; - (void) worker; - (void) server; - - h2s = conn->data; - available = h2s->buffer_size - h2s->buffer_length; - if (available == 0) { - new_size = h2s->buffer_size + MK_HTTP2_CHUNK; - if (h2s->buffer == h2s->buffer_fixed) { - h2s->buffer = mk_mem_alloc(new_size); - if (!h2s->buffer) { - /* FIXME: send internal server error ? */ - return -1; - } - memcpy(h2s->buffer, h2s->buffer_fixed, h2s->buffer_length); - MK_TRACE("[FD %i] Buffer new size: %i, length: %i", - conn->event.fd, new_size, h2s->buffer_length); - } - else { - MK_TRACE("[FD %i] Buffer realloc from %i to %i", - conn->event.fd, h2s->buffer_size, new_size); - tmp = mk_mem_realloc(h2s->buffer, new_size); - if (tmp) { - h2s->buffer = tmp; - h2s->buffer_size = new_size; - } - else { - /* FIXME: send internal server error ? */ - return -1; - } - - } - } - - /* Read the incoming data */ - bytes = mk_sched_conn_read(conn, - h2s->buffer, - h2s->buffer_size - h2s->buffer_length); - if (bytes == 0) { - errno = 0; - return -1; - } - else if (bytes == -1) { - return -1; - } - - h2s->buffer_length += bytes; - - /* Upgraded connections from HTTP/1.x requires the preface */ - if (h2s->status == MK_HTTP2_UPGRADED) { - if (h2s->buffer_length >= http2_preface.len) { - if (memcmp(h2s->buffer, - http2_preface.data, http2_preface.len) != 0) { - MK_H2_TRACE(conn, "Invalid HTTP/2 preface"); - return 0; - } - - MK_H2_TRACE(conn, "HTTP/2 preface OK"); - - buffer_consume(h2s, http2_preface.len); - h2s->status = MK_HTTP2_OK; - - /* Send out our default settings - mk_stream_set(&h2s->stream_settings, - MK_STREAM_RAW, - &conn->channel, - MK_HTTP2_SETTINGS_DEFAULT_FRAME, - sizeof(MK_HTTP2_SETTINGS_DEFAULT_FRAME) - 1, - NULL, - NULL, NULL, NULL); - */ - } - else { - /* We need more data */ - return 0; - } - } - - /* Check that we have a minimum header size */ - if (h2s->buffer_length < MK_HTTP2_HEADER_SIZE) { - MK_TRACE("HEADER FRAME incomplete %i/%i bytes", - h2s->buffer_length, MK_HTTP2_HEADER_SIZE); - return 0; - } - - /* We have at least one frame */ - return mk_http2_frame_run(conn, worker); -} - - -struct mk_sched_handler mk_http2_handler = { - .name = "http2", - .cb_read = mk_http2_sched_read, - .cb_close = NULL, - .cb_done = NULL, - .cb_upgrade = mk_http2_upgrade, - .sched_extra_size = sizeof(struct mk_http2_session), - .capabilities = MK_CAP_HTTP2 -}; diff --git a/fluent-bit/lib/monkey/mk_server/mk_http_parser.c b/fluent-bit/lib/monkey/mk_server/mk_http_parser.c deleted file mode 100644 index 4e7aa316..00000000 --- a/fluent-bit/lib/monkey/mk_server/mk_http_parser.c +++ /dev/null @@ -1,744 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* Monkey HTTP Server - * ================== - * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _GNU_SOURCE - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <stdint.h> -#include <limits.h> - -#include <monkey/mk_http.h> -#include <monkey/mk_http_parser.h> -#include <monkey/mk_http_status.h> - -#define mark_end() \ - p->end = p->i; \ - p->chars = -1; - -#define start_next() \ - p->start = p->i + 1; \ - continue - -#define field_len() (p->end - p->start) -#define header_scope_eq(p, x) p->header_min = p->header_max = x - -struct row_entry { - int len; - const char name[32]; -}; - -struct row_entry mk_methods_table[] = { - { 3, "GET" }, - { 4, "POST" }, - { 4, "HEAD" }, - { 3, "PUT" }, - { 6, "DELETE" }, - { 7, "OPTIONS" } -}; - -struct row_entry mk_headers_table[] = { - { 6, "accept" }, - { 14, "accept-charset" }, - { 15, "accept-encoding" }, - { 15, "accept-language" }, - { 13, "authorization" }, - { 13, "cache-control" }, - { 6, "cookie" }, - { 10, "connection" }, - { 14, "content-length" }, - { 13, "content-range" }, - { 12, "content-type" }, - { 4, "host" }, - { 14, "http2-settings" }, - { 17, "if-modified-since" }, - { 13, "last-modified" }, - { 19, "last-modified-since" }, - { 5, "range" }, - { 7, "referer" }, - { 7, "upgrade" }, - { 10, "user-agent" } -}; - -static inline void reverse_char_lookup(char *buf, char c, int len, struct mk_http_parser *p) -{ - int x = 0; - int y = 0; - - x = p->i; - do { - if (buf[x - y] == c) { - p->i = x - y; - return; - } - y++; - } while (y < len); -} - -static inline void char_lookup(char *buf, char c, int len, struct mk_http_parser *p) -{ - int x = 0; - - x = p->i; - do { - if (buf[x] == c) { - p->i = x; - return; - } - x++; - } while (x < len); -} - -static inline int str_searchr(char *buf, char c, int len) -{ - int i; - - for (i = len - 1; i >= 0; i--) { - if (buf[i] == c) { - return i; - } - } - - return -1; -} - -static inline int method_lookup(struct mk_http_request *req, - struct mk_http_parser *p, char *buffer) -{ - int i = 0; - int len; - - /* Method lenght */ - len = field_len(); - - /* Point the buffer */ - req->method = MK_METHOD_UNKNOWN; - req->method_p.data = buffer + p->start; - req->method_p.len = len; - - if (p->method >= 0) { - if (strncmp(buffer + p->start + 1, - mk_methods_table[p->method].name + 1, - len - 1) == 0) { - req->method = p->method; - return req->method; - } - } - - for (i = 0; i < MK_METHOD_SIZEOF; i++) { - if (len != mk_methods_table[i].len) { - continue; - } - - if (strncmp(buffer + p->start, mk_methods_table[i].name, len) == 0) { - req->method = i; - return i; - } - } - return MK_METHOD_UNKNOWN; -} - -static inline void request_set(mk_ptr_t *ptr, struct mk_http_parser *p, char *buffer) -{ - ptr->data = buffer + p->start; - ptr->len = field_len(); -} - -/* - * expected: a known & expected value in lowercase - * value : the expected string value in the header - * len : the value string length. - * - * If it matches it return zero. Otherwise -1. - */ -static inline int header_cmp(const char *expected, char *value, int len) -{ - int i = 0; - - if (len >= 8) { - if (expected[0] != tolower(value[0])) return -1; - if (expected[1] != tolower(value[1])) return -1; - if (expected[2] != tolower(value[2])) return -1; - if (expected[3] != tolower(value[3])) return -1; - if (expected[4] != tolower(value[4])) return -1; - if (expected[5] != tolower(value[5])) return -1; - if (expected[6] != tolower(value[6])) return -1; - if (expected[7] != tolower(value[7])) return -1; - i = 8; - } - - for (; i < len; i++) { - if (expected[i] != tolower(value[i])) { - return -1; - } - } - - return 0; -} - -static inline int header_lookup(struct mk_http_parser *p, char *buffer) -{ - int i; - int len; - int pos; - long val; - char *endptr; - char *tmp; - - struct mk_http_header *header; - struct mk_http_header *header_extra; - struct row_entry *h; - - len = (p->header_sep - p->header_key); - for (i = p->header_min; i <= p->header_max && i >= 0; i++) { - h = &mk_headers_table[i]; - /* Check string length first */ - if (h->len != len) { - continue; - } - - if (header_cmp(h->name + 1, buffer + p->header_key + 1, len - 1) == 0) { - /* We got a header match, register the header index */ - header = &p->headers[i]; - header->type = i; - header->key.data = buffer + p->header_key; - header->key.len = len; - header->val.data = buffer + p->header_val; - header->val.len = p->end - p->header_val; - p->header_count++; - mk_list_add(&header->_head, &p->header_list); - - if (i == MK_HEADER_HOST) { - /* Handle a possible port number in the Host header */ - int sep = str_searchr(header->val.data, ':', header->val.len); - if (sep > 0) { - int plen; - short int port_size = 6; - char port[6]; /* Can't use port_size to declare a stack allocated array in vc++ */ - - plen = header->val.len - sep - 1; - if (plen <= 0 || plen >= port_size) { - return -MK_CLIENT_BAD_REQUEST; - } - memcpy(&port, header->val.data + sep + 1, plen); - port[plen] = '\0'; - - errno = 0; - val = strtol(port, &endptr, 10); - if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) - || (errno != 0 && val == 0)) { - return -MK_CLIENT_BAD_REQUEST; - } - - if (endptr == port || *endptr != '\0') { - return -MK_CLIENT_BAD_REQUEST; - } - - p->header_host_port = val; - - /* Re-set the Host header value without port */ - header->val.len = sep; - } - } - else if (i == MK_HEADER_CONTENT_LENGTH) { - errno = 0; - val = strtol(header->val.data, &endptr, 10); - if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) - || (errno != 0 && val == 0)) { - return -MK_CLIENT_REQUEST_ENTITY_TOO_LARGE; - } - if (endptr == header->val.data) { - return -1; - } - if (val < 0) { - return -1; - } - - p->header_content_length = val; - } - else if (i == MK_HEADER_CONNECTION) { - /* Check Connection: Keep-Alive */ - if (header->val.len == sizeof(MK_CONN_KEEP_ALIVE) - 1) { - if (header_cmp(MK_CONN_KEEP_ALIVE, - header->val.data, - header->val.len ) == 0) { - p->header_connection = MK_HTTP_PARSER_CONN_KA; - } - } - /* Check Connection: Close */ - else if (header->val.len == sizeof(MK_CONN_CLOSE) -1) { - if (header_cmp(MK_CONN_CLOSE, - header->val.data, header->val.len) == 0) { - p->header_connection = MK_HTTP_PARSER_CONN_CLOSE; - } - } - else { - p->header_connection = MK_HTTP_PARSER_CONN_UNKNOWN; - - /* Try to find some known values */ - - /* Connection: upgrade */ - pos = mk_string_search_n(header->val.data, - "Upgrade", - MK_STR_INSENSITIVE, - header->val.len); - if (pos >= 0) { - p->header_connection = MK_HTTP_PARSER_CONN_UPGRADE; - } - - /* Connection: HTTP2-Settings */ - pos = mk_string_search_n(header->val.data, - "HTTP2-Settings", - MK_STR_INSENSITIVE, - header->val.len); - if (pos >= 0) { - p->header_connection |= MK_HTTP_PARSER_CONN_HTTP2_SE; - } - } - } - else if (i == MK_HEADER_UPGRADE) { - if (header_cmp(MK_UPGRADE_H2C, - header->val.data, header->val.len) == 0) { - p->header_upgrade = MK_HTTP_PARSER_UPGRADE_H2C; - } - } - - return 0; - } - } - - /* - * The header_lookup did not match any known header, so we register this - * entry into the headers_extra array. - */ - if (p->headers_extra_count < MK_HEADER_EXTRA_SIZE) { - header_extra = &p->headers_extra[p->headers_extra_count]; - header_extra->key.data = tmp = (buffer + p->header_key); - header_extra->key.len = len; - - /* Transform the header key string to lowercase */ - for (i = 0; i < len; i++) { - tmp[i] = tolower(tmp[i]); - } - - header_extra->val.data = buffer + p->header_val; - header_extra->val.len = p->end - p->header_val; - p->headers_extra_count++; - p->header_count++; - mk_list_add(&header_extra->_head, &p->header_list); - return 0; - } - - /* - * Header is unknown and we cannot store it on our extra headers - * list as it's already full. Request is too large. - */ - return -MK_CLIENT_REQUEST_ENTITY_TOO_LARGE; -} - -/* - * This function is invoked everytime the parser evaluate the request is - * OK. Here we perform some extra validations mostly based on some logic - * and protocol requirements according to the data received. - */ -static inline int mk_http_parser_ok(struct mk_http_request *req, - struct mk_http_parser *p, - struct mk_server *server) -{ - /* Validate HTTP Version */ - if (req->protocol == MK_HTTP_PROTOCOL_UNKNOWN) { - mk_http_error(MK_SERVER_HTTP_VERSION_UNSUP, req->session, req, server); - return MK_HTTP_PARSER_ERROR; - } - - /* POST checks */ - if (req->method == MK_METHOD_POST || req->method == MK_METHOD_PUT) { - /* validate Content-Length exists */ - if (p->headers[MK_HEADER_CONTENT_LENGTH].type == 0) { - mk_http_error(MK_CLIENT_LENGTH_REQUIRED, req->session, req, server); - return MK_HTTP_PARSER_ERROR; - } - } - - return MK_HTTP_PARSER_OK; -} - -/* - * Parse the protocol and point relevant fields, don't take logic decisions - * based on this, just parse to locate things. - */ -int mk_http_parser(struct mk_http_request *req, struct mk_http_parser *p, - char *buffer, int buf_len, struct mk_server *server) -{ - int s; - int tmp; - int ret; - int len; - - /* lazy test - printf("p->i=%i buf_len=%i\n", - p->i, buf_len); - - for (s = p->i; s < buf_len; s++) { - if (buffer[s] == '\r') { - printf("CR"); - } - else if (buffer[s] == '\n') { - printf("LF"); - } - else { - printf("%c", buffer[s]); - } - } - printf("\n"); - */ - - len = buf_len; - for (; p->i < len; p->i++, p->chars++) { - /* FIRST LINE LEVEL: Method, URI & Protocol */ - if (p->level == REQ_LEVEL_FIRST) { - switch (p->status) { - case MK_ST_REQ_METHOD: /* HTTP Method */ - if (p->chars == -1) { - switch (buffer[p->i]) { - case 'G': - p->method = MK_METHOD_GET; - break; - case 'P': - p->method = MK_METHOD_POST; - break; - case 'H': - p->method = MK_METHOD_HEAD; - break; - case 'D': - p->method = MK_METHOD_DELETE; - break; - case 'O': - p->method = MK_METHOD_OPTIONS; - break; - } - continue; - } - - if (buffer[p->i] == ' ') { - mark_end(); - p->status = MK_ST_REQ_URI; - if (p->end < 2) { - return MK_HTTP_PARSER_ERROR; - } - method_lookup(req, p, buffer); - start_next(); - } - else { - if ((p->i - p->start) > 10) { - return MK_HTTP_PARSER_ERROR; - } - } - break; - case MK_ST_REQ_URI: /* URI */ - if (buffer[p->i] == ' ') { - mark_end(); - p->status = MK_ST_REQ_PROT_VERSION; - if (field_len() < 1) { - return MK_HTTP_PARSER_ERROR; - } - request_set(&req->uri, p, buffer); - start_next(); - } - else if (buffer[p->i] == '?') { - mark_end(); - request_set(&req->uri, p, buffer); - p->status = MK_ST_REQ_QUERY_STRING; - start_next(); - } - else if (buffer[p->i] == '\r' || buffer[p->i] == '\n') { - mk_http_error(MK_CLIENT_BAD_REQUEST, req->session, - req, server); - return MK_HTTP_PARSER_ERROR; - } - break; - case MK_ST_REQ_QUERY_STRING: /* Query string */ - char_lookup(buffer, '\n', len, p); - - if (buffer[p->i] == '\n') { - reverse_char_lookup(buffer, ' ', p->i, p); - } - - if (buffer[p->i] == ' ') { - mark_end(); - request_set(&req->query_string, p, buffer); - p->status = MK_ST_REQ_PROT_VERSION; - start_next(); - } - else if (buffer[p->i] == '\r' || buffer[p->i] == '\n') { - mk_http_error(MK_CLIENT_BAD_REQUEST, req->session, - req, server); - return MK_HTTP_PARSER_ERROR; - } - break; - case MK_ST_REQ_PROT_VERSION: /* Protocol Version */ - /* - * Most of the time we already have the string version in our - * buffer, for that case try to match the version and avoid - * loop rounds. - */ - if (p->start + 6 >= p->i) { - continue; - } - - tmp = p->start; - if (buffer[tmp] == 'H' && - buffer[tmp + 1] == 'T' && - buffer[tmp + 2] == 'T' && - buffer[tmp + 3] == 'P' && - buffer[tmp + 4] == '/' && - buffer[tmp + 5] == '1' && - buffer[tmp + 6] == '.') { - - request_set(&req->protocol_p, p, buffer); - req->protocol_p.len = 8; - mk_http_set_minor_version(buffer[tmp + 7]); - } - else { - mk_http_error(MK_SERVER_HTTP_VERSION_UNSUP, - req->session, req, server); - return MK_HTTP_PARSER_ERROR; - } - p->status = MK_ST_FIRST_CONTINUE; - break; - case MK_ST_FIRST_CONTINUE: - if (buffer[p->i] == '\r') { - p->status = MK_ST_FIRST_FINALIZING; - } - else { - return MK_HTTP_PARSER_ERROR; - } - break; - case MK_ST_FIRST_FINALIZING: /* New Line */ - if (buffer[p->i] == '\n') { - p->level = REQ_LEVEL_CONTINUE; - start_next(); - } - else { - return MK_HTTP_PARSER_ERROR; - } - break; - case MK_ST_BLOCK_END: - if (buffer[p->i] == '\n') { - return mk_http_parser_ok(req, p, server); - } - else { - return MK_HTTP_PARSER_ERROR; - } - break; - }; - } - else if (p->level == REQ_LEVEL_CONTINUE) { - if (buffer[p->i] == '\r') { - p->level = REQ_LEVEL_FIRST; - p->status = MK_ST_BLOCK_END; - } - else { - p->level = REQ_LEVEL_HEADERS; - p->status = MK_ST_HEADER_KEY; - p->chars = 0; - } - } - /* HEADERS: all headers stuff */ - if (p->level == REQ_LEVEL_HEADERS) { - /* Expect a Header key */ - if (p->status == MK_ST_HEADER_KEY) { - if (buffer[p->i] == '\r') { - if (p->chars == 0) { - p->level = REQ_LEVEL_END; - start_next(); - } - else { - return MK_HTTP_PARSER_ERROR; - } - } - - if (p->chars == 0) { - /* - * We reach the start of a Header row, lets catch the most - * probable header. - * - * The goal of this 'first row character lookup', is to define a - * small range set of probable headers comparison once we catch - * a header end. - */ - s = tolower(buffer[p->i]); - switch (s) { - case 'a': - p->header_min = MK_HEADER_ACCEPT; - p->header_max = MK_HEADER_AUTHORIZATION; - break; - case 'c': - p->header_min = MK_HEADER_CACHE_CONTROL; - p->header_max = MK_HEADER_CONTENT_TYPE; - break; - case 'h': - p->header_min = MK_HEADER_HOST; - p->header_max = MK_HEADER_HTTP2_SETTINGS; - break; - case 'i': - header_scope_eq(p, MK_HEADER_IF_MODIFIED_SINCE); - break; - case 'l': - p->header_min = MK_HEADER_LAST_MODIFIED; - p->header_max = MK_HEADER_LAST_MODIFIED_SINCE; - break; - case 'r': - p->header_min = MK_HEADER_RANGE; - p->header_max = MK_HEADER_REFERER; - break; - case 'u': - p->header_min = MK_HEADER_UPGRADE; - p->header_max = MK_HEADER_USER_AGENT; - break; - default: - p->header_key = -1; - p->header_sep = -1; - p->header_min = -1; - p->header_max = -1; - }; - p->header_key = p->i; - continue; - } - - /* Found key/value separator */ - char_lookup(buffer, ':', len, p); - if (buffer[p->i] == ':') { - /* Set the key/value middle point */ - p->header_sep = p->i; - - /* validate length */ - mark_end(); - if (field_len() < 1) { - return MK_HTTP_PARSER_ERROR; - } - - /* Wait for a value */ - p->status = MK_ST_HEADER_VALUE; - start_next(); - } - } - /* Parsing the header value */ - else if (p->status == MK_ST_HEADER_VALUE) { - /* Trim left, set starts only when found something != ' ' */ - if (buffer[p->i] == '\r' || buffer[p->i] == '\n') { - return MK_HTTP_PARSER_ERROR; - } - else if (buffer[p->i] != ' ') { - p->status = MK_ST_HEADER_VAL_STARTS; - p->start = p->header_val = p->i; - } - continue; - } - /* New header row starts */ - else if (p->status == MK_ST_HEADER_VAL_STARTS) { - /* Maybe there is no more headers and we reach the end ? */ - if (buffer[p->i] == '\r') { - mark_end(); - if (field_len() <= 0) { - return MK_HTTP_PARSER_ERROR; - } - - /* - * A header row has ended, lets lookup the header and populate - * our headers table index. - */ - ret = header_lookup(p, buffer); - if (ret != 0) { - if (ret < -1) { - mk_http_error(-ret, req->session, req, server); - } - return MK_HTTP_PARSER_ERROR; - } - - /* Try to catch next LF */ - if (p->i + 1 < len) { - if (buffer[p->i + 1] == '\n') { - p->i++; - p->status = MK_ST_HEADER_KEY; - p->chars = -1; - start_next(); - } - } - - p->status = MK_ST_HEADER_END; - start_next(); - } - else if (buffer[p->i] == '\n' && buffer[p->i - 1] != '\r') { - return MK_HTTP_PARSER_ERROR; - } - } - else if (p->status == MK_ST_HEADER_END) { - if (buffer[p->i] == '\n') { - p->status = MK_ST_HEADER_KEY; - p->chars = -1; - start_next(); - } - else { - return MK_HTTP_PARSER_ERROR; - } - } - } - else if (p->level == REQ_LEVEL_END) { - if (buffer[p->i] == '\n') { - if (p->header_content_length > 0) { - p->level = REQ_LEVEL_BODY; - p->chars = -1; - start_next(); - } - else { - return mk_http_parser_ok(req, p, server); - } - } - else { - return MK_HTTP_PARSER_ERROR; - } - } - else if (p->level == REQ_LEVEL_BODY) { - /* - * Reaching this level can means two things: - * - * - A Pipeline Request - * - A Body content (POST/PUT methods) - */ - if (p->header_content_length > 0) { - - p->body_received = len - p->start; - if ((len - p->start) < p->header_content_length) { - return MK_HTTP_PARSER_PENDING; - } - - /* Cut off */ - p->i += p->body_received; - req->data.len = p->body_received; - req->data.data = (buffer + p->start); - } - return mk_http_parser_ok(req, p, server); - } - } - - return MK_HTTP_PARSER_PENDING; -} diff --git a/fluent-bit/lib/monkey/mk_server/mk_http_thread.c b/fluent-bit/lib/monkey/mk_server/mk_http_thread.c deleted file mode 100644 index d3c606f3..00000000 --- a/fluent-bit/lib/monkey/mk_server/mk_http_thread.c +++ /dev/null @@ -1,290 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* Monkey HTTP Server - * ================== - * Copyright 2001-2016 Monkey Software LLC <eduardo@monkey.io> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <monkey/mk_info.h> -#include <monkey/mk_plugin.h> -#include <monkey/mk_thread.h> -#include <monkey/mk_net.h> -#include <monkey/mk_vhost.h> -#include <monkey/mk_http_thread.h> - -#include <stdlib.h> - -/* - * libco do not support parameters in the entrypoint function due to the - * complexity of implementation in terms of architecture and compiler, but - * it provide a workaround using a global structure as a middle entry-point - * that achieve the same stuff. - */ -struct mk_http_libco_params { - int type; - struct mk_vhost_handler *handler; - struct mk_http_session *session; - struct mk_http_request *request; - int n_params; - struct mk_list *params; - struct mk_thread *th; -}; - -pthread_once_t mk_http_thread_initialize_tls_once_flag = PTHREAD_ONCE_INIT; - -MK_TLS_DEFINE(struct mk_http_libco_params, mk_http_thread_libco_params); -MK_TLS_DEFINE(struct mk_thread, mk_thread); - -/* This function could return NULL if the process runs out of memory, in that - * case failure is imminent. - */ -static inline struct mk_http_libco_params *thread_get_libco_params() -{ - struct mk_http_libco_params *libco_params; - - libco_params = MK_TLS_GET(mk_http_thread_libco_params); - - if (libco_params == NULL) { - libco_params = mk_mem_alloc_z(sizeof(struct mk_http_libco_params)); - - if (libco_params == NULL) { - mk_err("libco thread params could not be allocated."); - } - - MK_TLS_SET(mk_http_thread_libco_params, libco_params); - } - - return libco_params; -} - -static void mk_http_thread_initialize_tls_once() -{ - MK_TLS_INIT(mk_http_thread_libco_params); - MK_TLS_INIT(mk_thread); -} - -void mk_http_thread_initialize_tls() -{ - pthread_once(&mk_http_thread_initialize_tls_once_flag, - mk_http_thread_initialize_tls_once); -} - -static inline void thread_cb_init_vars() -{ - struct mk_http_libco_params *libco_params; - struct mk_vhost_handler *handler; - struct mk_http_session *session; - struct mk_http_request *request; - int close; - int type; - struct mk_http_thread *mth; - struct mk_thread *th; - - libco_params = thread_get_libco_params(); - - type = libco_params->type; - handler = libco_params->handler; - session = libco_params->session; - request = libco_params->request; - th = libco_params->th; - - /* - * Until this point the th->callee already set the variables, so we - * wait until the core wanted to resume so we really trigger the - * output callback. - */ - co_switch(th->caller); - - if (type == MK_HTTP_THREAD_LIB) { - /* Invoke the handler callback */ - handler->cb(request, handler->data); - - /* - * Once the callback finished, we need to sanitize the connection - * so other further requests can be processed. - */ - int ret; - struct mk_sched_worker *sched; - struct mk_channel *channel; - - channel = request->session->channel; - sched = mk_sched_get_thread_conf(); - - MK_EVENT_NEW(channel->event); - ret = mk_event_add(sched->loop, - channel->fd, - MK_EVENT_CONNECTION, - MK_EVENT_READ, channel->event); - if (ret == -1) { - //return -1; - } - - /* Save temporal session */ - mth = request->thread; - - /* - * Finalize request internally, if ret == -1 means we should - * ask to shutdown the connection. - */ - ret = mk_http_request_end(session, session->server); - if (ret == -1) { - close = MK_TRUE; - } - else { - close = MK_FALSE; - } - mk_http_thread_purge(mth, close); - - /* Return control to caller */ - mk_thread_yield(th); - } - else if (type == MK_HTTP_THREAD_PLUGIN) { - /* FIXME: call plugin handler callback with params */ - } -} - -static inline void thread_params_set(struct mk_thread *th, - int type, - struct mk_vhost_handler *handler, - struct mk_http_session *session, - struct mk_http_request *request, - int n_params, - struct mk_list *params) -{ - struct mk_http_libco_params *libco_params; - - libco_params = thread_get_libco_params(); - - /* Callback parameters in order */ - libco_params->type = type; - libco_params->handler = handler; - libco_params->session = session; - libco_params->request = request; - libco_params->n_params = n_params; - libco_params->params = params; - libco_params->th = th; - - co_switch(th->callee); -} - -struct mk_http_thread *mk_http_thread_create(int type, - struct mk_vhost_handler *handler, - struct mk_http_session *session, - struct mk_http_request *request, - int n_params, - struct mk_list *params) -{ - size_t stack_size; - struct mk_thread *th = NULL; - struct mk_http_thread *mth; - struct mk_sched_worker *sched; - - sched = mk_sched_get_thread_conf(); - if (!sched) { - return NULL; - } - - th = mk_thread_new(sizeof(struct mk_http_thread), NULL); - if (!th) { - return NULL; - } - - mth = (struct mk_http_thread *) MK_THREAD_DATA(th); - if (!mth) { - return NULL; - } - - mth->session = session; - mth->request = request; - mth->parent = th; - mth->close = MK_FALSE; - request->thread = mth; - mk_list_add(&mth->_head, &sched->threads); - - th->caller = co_active(); - th->callee = co_create(MK_THREAD_STACK_SIZE, - thread_cb_init_vars, &stack_size); - -#ifdef MK_HAVE_VALGRIND - th->valgrind_stack_id = VALGRIND_STACK_REGISTER(th->callee, - ((char *)th->callee) + stack_size); -#endif - - /* Workaround for makecontext() */ - thread_params_set(th, type, handler, session, request, n_params, params); - - return mth; -} - -/* - * Move a http thread context from sched->thread to sched->threads_purge list. - * On this way the scheduler will release or reasign the resource later. - */ -int mk_http_thread_purge(struct mk_http_thread *mth, int close) -{ - struct mk_sched_worker *sched; - - sched = mk_sched_get_thread_conf(); - if (!sched) { - return -1; - } - - mth->close = close; - mk_list_del(&mth->_head); - mk_list_add(&mth->_head, &sched->threads_purge); - - return 0; -} - -int mk_http_thread_destroy(struct mk_http_thread *mth) -{ - struct mk_thread *th; - - /* Unlink from scheduler thread list */ - mk_list_del(&mth->_head); - - /* release original memory context */ - th = mth->parent; - mth->session->channel->event->type = MK_EVENT_CONNECTION; - mk_thread_destroy(th); - - return 0; -} - -int mk_http_thread_event(struct mk_event *event) -{ - struct mk_sched_conn *conn = (struct mk_sched_conn *) event; - - /* - struct mk_thread *th; - struct mk_http_thread *mth; - - th = conn->channel.thread; - mth = (struct mk_http_thread *) MK_THREAD_DATA(th); - */ - - mk_thread_resume(conn->channel.thread); - return 0; -} - -/* - * Start the co-routine: invoke coroutine callback and start processing - * data flush requests. - */ -int mk_http_thread_start(struct mk_http_thread *mth) -{ - mk_http_thread_resume(mth); - return 0; -} diff --git a/fluent-bit/lib/monkey/mk_server/mk_kernel.c b/fluent-bit/lib/monkey/mk_server/mk_kernel.c deleted file mode 100644 index cc69e96c..00000000 --- a/fluent-bit/lib/monkey/mk_server/mk_kernel.c +++ /dev/null @@ -1,165 +0,0 @@ -/*-*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* Monkey HTTP Server - * ================== - * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <monkey/monkey.h> -#include <monkey/mk_core.h> -#include <monkey/mk_kernel.h> -#include <monkey/mk_utils.h> -#include <monkey/mk_server.h> -#include <monkey/mk_scheduler.h> - -#include <ctype.h> - -#ifndef _WIN32 -#include <sys/utsname.h> - -int mk_kernel_version() -{ - int a, b, c; - int len; - int pos; - char *p, *t; - char *tmp; - struct utsname uts; - - if (uname(&uts) == -1) { - mk_libc_error("uname"); - } - len = strlen(uts.release); - - /* Fixme: this don't support Linux Kernel 10.x.x :P */ - a = (*uts.release - '0'); - - /* Second number */ - p = (uts.release) + 2; - pos = mk_string_char_search(p, '.', len - 2); - if (pos <= 0) { - /* Some Debian systems uses a different notation, e.g: 3.14-2-amd64 */ - pos = mk_string_char_search(p, '-', len - 2); - if (pos <= 0) { - return -1; - } - } - - tmp = mk_string_copy_substr(p, 0, pos); - if (!tmp) { - return -1; - } - b = atoi(tmp); - mk_mem_free(tmp); - - /* Last number (it needs filtering) */ - t = p = p + pos + 1; - do { - t++; - } while (isdigit(*t)); - - tmp = mk_string_copy_substr(p, 0, t - p); - if (!tmp) { - return -1; - } - c = atoi(tmp); - mk_mem_free(tmp); - - MK_TRACE("Kernel detected: %i.%i.%i", a, b, c); - return MK_KERNEL_VERSION(a, b, c); -} - -/* Detect specific Linux Kernel features that we may use */ -int mk_kernel_features(int version) -{ - int flags = 0; - - /* - * TCP Auto Corking (disabled by #175) - * ----------------------------------- - * I found that running some benchmarks on Linux 3.16 with - * tcp_autocorking enabled, it lead to lower performance, looks like - * a manual cork fits better for our needs. - * - * I think there is something wrong that we need to clarify, by now - * I've logged the following issue: - * - * https://github.com/monkey/monkey/issues/175 - * - if (mk_kernel_runver >= MK_KERNEL_VERSION(3, 14, 0) && - mk_socket_tcp_autocorking() == MK_TRUE) { - flags |= MK_KERNEL_TCP_AUTOCORKING; - } - */ - - /* SO_REUSEPORT */ - if (version >= MK_KERNEL_VERSION(3, 9, 0)) { - flags |= MK_KERNEL_SO_REUSEPORT; - } - - /* TCP_FASTOPEN */ - if (version >= MK_KERNEL_VERSION(3, 7, 0)) { - flags |= MK_KERNEL_TCP_FASTOPEN; - } - - return flags; -} - -int mk_kernel_features_print(char *buffer, size_t size, - struct mk_server *server) -{ - int offset = 0; - int features = 0; - - if (server->kernel_features & MK_KERNEL_TCP_FASTOPEN) { - offset += snprintf(buffer, size - offset, "%s", "TCP_FASTOPEN "); - features++; - } - - if (server->kernel_features & MK_KERNEL_SO_REUSEPORT) { - if (server->scheduler_mode == MK_SCHEDULER_FAIR_BALANCING) { - offset += snprintf(buffer + offset, size - offset, - "%s!%s", ANSI_BOLD ANSI_RED, ANSI_RESET); - } - offset += snprintf(buffer + offset, size - offset, "%s", "SO_REUSEPORT "); - features++; - } - - if (server->kernel_features & MK_KERNEL_TCP_AUTOCORKING) { - snprintf(buffer + offset, size - offset, "%s", "TCP_AUTOCORKING "); - features++; - } - - return features; -} -#else -/* We still need to determine if this can be safely ignored or what do we need to do here */ - -int mk_kernel_version() -{ - return 1; -} - -int mk_kernel_features(int version) -{ - return 0; -} - -int mk_kernel_features_print(char* buffer, size_t size, - struct mk_server* server) -{ - return 0; -} -#endif diff --git a/fluent-bit/lib/monkey/mk_server/mk_lib.c b/fluent-bit/lib/monkey/mk_server/mk_lib.c deleted file mode 100644 index c2940086..00000000 --- a/fluent-bit/lib/monkey/mk_server/mk_lib.c +++ /dev/null @@ -1,796 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* Monkey HTTP Server - * ================== - * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _GNU_SOURCE -#include <stdarg.h> -#include <string.h> -#include <errno.h> -#include <signal.h> - -#include <mk_core/mk_pthread.h> - -#include <monkey/mk_lib.h> -#include <monkey/monkey.h> -#include <monkey/mk_stream.h> -#include <monkey/mk_thread.h> -#include <monkey/mk_scheduler.h> -#include <monkey/mk_fifo.h> -#include <monkey/mk_utils.h> -#include <monkey/mk_tls.h> - -#define config_eq(a, b) strcasecmp(a, b) - -static inline int bool_val(char *v) -{ - if (strcasecmp(v, "On") == 0 || strcasecmp(v, "Yes") == 0) { - return MK_TRUE; - } - else if (strcasecmp(v, "Off") == 0 || strcasecmp(v, "No") == 0) { - return MK_FALSE; - } - - return -1; -} - -mk_ctx_t *mk_create() -{ - mk_ctx_t *ctx; - - ctx = mk_mem_alloc_z(sizeof(mk_ctx_t)); - if (!ctx) { - return NULL; - } - - /* Create Monkey server instance */ - ctx->server = mk_server_create(); - - /* - * FIFO - * ==== - * Before to prepare the background service, we create a MK_FIFO interface - * for further communication between the caller (user) and HTTP end-point - * callbacks. - */ - ctx->fifo = mk_fifo_create(NULL, ctx->server); - ctx->fifo->key = &mk_server_fifo_key; - - /* - * FIFO: Set workers callback associated to the Monkey scheduler to prepare them - * before to enter the event loop - */ - mk_sched_worker_cb_add(ctx->server, mk_fifo_worker_setup, ctx->fifo); - return ctx; -} - -int mk_destroy(mk_ctx_t *ctx) -{ - mk_fifo_destroy(ctx->fifo); - mk_mem_free(ctx); - - return 0; -} - -static inline int mk_lib_yield(mk_request_t *req) -{ - int ret; - struct mk_thread *th; - struct mk_channel *channel; - struct mk_sched_worker *sched; - - sched = mk_sched_get_thread_conf(); - if (!sched) { - return -1; - } - - th = MK_TLS_GET(mk_thread); - channel = req->session->channel; - - channel->thread = th; - - ret = mk_event_add(sched->loop, - channel->fd, - MK_EVENT_THREAD, - MK_EVENT_WRITE, channel->event); - if (ret == -1) { - return -1; - } - - /* Just wait */ - mk_thread_yield(th); - - if (channel->event->status & MK_EVENT_REGISTERED) { - /* We got a notification, remove the event registered - ret = mk_event_add(sched->loop, - channel->fd, - MK_EVENT_CONNECTION, - MK_EVENT_READ, channel->event); - mk_thread_yield(th); - */ - - ret = mk_event_del(sched->loop, channel->event); - } - - return 0; -} - -static void mk_lib_worker(void *data) -{ - int fd; - int bytes; - uint64_t val; - struct mk_server *server; - struct mk_event *event; - - mk_ctx_t *ctx = data; - server = ctx->server; - - /* Start the service */ - mk_server_setup(server); - mk_server_loop(server); - - /* - * Give a second to the parent context to avoid consume an event - * we should not read at the moment (SIGNAL_START). - */ - sleep(1); - - /* Wait for events */ - mk_event_wait(server->lib_evl); - mk_event_foreach(event, server->lib_evl) { - fd = event->fd; - -#ifdef _WIN32 - bytes = recv(fd, &val, sizeof(uint64_t), MSG_WAITALL); -#else - bytes = read(fd, &val, sizeof(uint64_t)); -#endif - - if (bytes <= 0) { - return; - } - - if (val == MK_SERVER_SIGNAL_STOP) { - break; - } - } - - mk_event_loop_destroy(server->lib_evl); - mk_exit_all(server); - pthread_kill(pthread_self(), 0); - - return; -} - -int mk_start(mk_ctx_t *ctx) -{ - int fd; - int bytes; - int ret; - uint64_t val; - pthread_t tid; - struct mk_event *event; - struct mk_server *server; - - server = ctx->server; - - ret = mk_utils_worker_spawn(mk_lib_worker, ctx, &tid); - if (ret == -1) { - return -1; - } - ctx->worker_tid = tid; - - /* Wait for the started signal so we can return to the caller */ - mk_event_wait(server->lib_evl_start); - mk_event_foreach(event, server->lib_evl_start) { - fd = event->fd; - - /* When using libevent _mk_event_channel_create creates a unix socket - * instead of a pipe and windows doesn't us calling read / write on a - * socket instead of recv / send - */ -#ifdef _WIN32 - bytes = recv(fd, &val, sizeof(uint64_t), MSG_WAITALL); -#else - bytes = read(fd, &val, sizeof(uint64_t)); -#endif - - if (bytes <= 0) { - ret = -1; - break; - } - - if (val == MK_SERVER_SIGNAL_START) { - ret = 0; - break; - } - else { - ret = -1; - break; - } - } - - mk_event_loop_destroy(server->lib_evl_start); - if (ret == -1) { - mk_stop(ctx); - } - - return ret; -} - -int mk_stop(mk_ctx_t *ctx) -{ - int n; - uint64_t val; - int8_t scheduler_mode ; - struct mk_server *server = ctx->server; - - /* Keep track of the scheduler mode on stack, since the - * the worker may free the server before we need the info. - */ - scheduler_mode = server->scheduler_mode; - - val = MK_SERVER_SIGNAL_STOP; - - /* Send a stop signal to the main lib channel to abort. - * - * MK_SCHEDULER_FAIR_BALANCING: this signal will be - * consumed by mk_server_loop_balancer. - * - * MK_SCHEDULER_REUSEPORT: this signal will be consumed - * by mk_lib_worker. - */ -#ifdef _WIN32 - n = send(server->lib_ch_manager[1], &val, sizeof(val), 0); -#else - n = write(server->lib_ch_manager[1], &val, sizeof(val)); -#endif - if (n <= 0) { - perror("write"); - return -1; - } - - /* In MK_SCHEDULER_FAIR_BALANCING mode, we need one more - * stop signal to abort mk_lib_worker. - */ - if (scheduler_mode == MK_SCHEDULER_FAIR_BALANCING) { - /* Give mk_server_loop_balancer time to clean up. */ - sleep(1); - - /* Send a signal for mk_lib_worker to abort */ -#ifdef _WIN32 - n = send(server->lib_ch_manager[1], &val, sizeof(val), 0); -#else - n = write(server->lib_ch_manager[1], &val, sizeof(val)); -#endif - if (n <= 0) { - perror("write"); - return -1; - } - } - - /* Wait for the child thread to exit */ - pthread_join(ctx->worker_tid, NULL); - return 0; -} - -/* - * Instruct Monkey core to invoke a callback function inside each worker - * started by the scheduler. - */ -int mk_worker_callback(mk_ctx_t *ctx, - void (*cb_func) (void *), - void *data) -{ - return mk_sched_worker_cb_add(ctx->server, cb_func, data); -} - -int mk_config_set_property(struct mk_server *server, char *k, char *v) -{ - int b; - int ret; - int num; - unsigned long len; - - if (config_eq(k, "Listen") == 0) { - ret = mk_config_listen_parse(v, server); - if (ret != 0) { - return -1; - } - } - else if (config_eq(k, "Workers") == 0) { - num = atoi(v); - if (num <= 0) { - server->workers = mk_utils_get_system_core_count(); - } - else { - server->workers = num; - } - } - else if (config_eq(k, "Timeout") == 0) { - num = atoi(v); - if (num <= 0) { - return -1; - } - server->timeout = num; - } - else if (config_eq(k, "KeepAlive") == 0) { - b = bool_val(v); - if (b == -1) { - return -1; - } - server->keep_alive = b; - } - else if (config_eq(k, "MaxKeepAliveRequest") == 0) { - num = atoi(v); - if (num <= 0) { - return -1; - } - server->max_keep_alive_request = num; - } - else if (config_eq(k, "KeepAliveTimeout") == 0) { - num = atoi(v); - if (num <= 0) { - return -1; - } - server->keep_alive_timeout = num; - } - else if (config_eq(k, "UserDir") == 0) { - server->conf_user_pub = mk_string_dup(v); - } - else if (config_eq(k, "IndexFile") == 0) { - server->index_files = mk_string_split_line(v); - if (!server->index_files) { - return -1; - } - } - else if (config_eq(k, "HideVersion") == 0) { - b = bool_val(v); - if (b == -1) { - return -1; - } - server->hideversion = b; - } - else if (config_eq(k, "Resume") == 0) { - b = bool_val(v); - if (b == -1) { - return -1; - } - server->resume = b; - } - else if (config_eq(k, "MaxRequestSize") == 0) { - num = atoi(v); - if (num <= 0) { - return -1; - } - server->max_request_size = num; - } - else if (config_eq(k, "SymLink") == 0) { - b = bool_val(v); - if (b == -1) { - return -1; - } - server->symlink = b; - } - else if (config_eq(k, "DefaultMimeType") == 0) { - mk_string_build(&server->mimetype_default_str, &len, "%s\r\n", v); - } - else if (config_eq(k, "FDT") == 0) { - b = bool_val(v); - if (b == -1) { - return -1; - } - server->fdt = b; - } - - return 0; -} - -int mk_config_set(mk_ctx_t *ctx, ...) -{ - int ret; - char *key; - char *value; - va_list va; - - va_start(va, ctx); - - while ((key = va_arg(va, char *))) { - value = va_arg(va, char *); - if (!value) { - /* Wrong parameter */ - va_end(va); - return -1; - } - - ret = mk_config_set_property(ctx->server, key, value); - if (ret != 0) { - va_end(va); - return -1; - } - } - - va_end(va); - return 0; -} - -/* Given a vhost id, return the vhost context */ -struct mk_vhost *mk_vhost_lookup(mk_ctx_t *ctx, int id) -{ - struct mk_vhost *host; - struct mk_list *head; - - mk_list_foreach(head, &ctx->server->hosts) { - host = mk_list_entry(head, struct mk_vhost, _head); - if (host->id == id) { - return host; - } - } - - return NULL; -} - -int mk_vhost_create(mk_ctx_t *ctx, char *name) -{ - struct mk_vhost *h; - struct mk_vhost_alias *halias; - - /* Virtual host */ - h = mk_mem_alloc_z(sizeof(struct mk_vhost)); - if (!h) { - return -1; - } - - /* Assign a virtual host id, we just set based on list size */ - h->id = mk_list_size(&ctx->server->hosts); - mk_list_init(&h->error_pages); - mk_list_init(&h->server_names); - mk_list_init(&h->handlers); - - /* Host alias */ - halias = mk_mem_alloc_z(sizeof(struct mk_vhost_alias)); - if (!halias) { - mk_mem_free(h); - return -1; - } - - /* Host name */ - if (!name) { - halias->name = mk_string_dup("127.0.0.1"); - } - else { - halias->name = mk_string_dup(name); - } - mk_list_add(&halias->_head, &h->server_names); - mk_list_add(&h->_head, &ctx->server->hosts); - - /* Return the host id, that number is enough for further operations */ - return h->id; -} - -static int mk_vhost_set_property(struct mk_vhost *vh, char *k, char *v) -{ - struct mk_vhost_alias *ha; - - if (config_eq(k, "Name") == 0) { - ha = mk_mem_alloc(sizeof(struct mk_vhost_alias)); - if (!ha) { - return -1; - } - ha->name = mk_string_dup(v); - ha->len = strlen(v); - mk_list_add(&ha->_head, &vh->server_names); - } - else if (config_eq(k, "DocumentRoot") == 0) { - vh->documentroot.data = mk_string_dup(v); - vh->documentroot.len = strlen(v); - } - - return 0; -} - -int mk_vhost_set(mk_ctx_t *ctx, int vid, ...) -{ - int ret; - char *key; - char *value; - va_list va; - struct mk_vhost *vh; - - /* Lookup the virtual host */ - vh = mk_vhost_lookup(ctx, vid); - if (!vh) { - return -1; - } - - va_start(va, vid); - - while ((key = va_arg(va, char *))) { - value = va_arg(va, char *); - if (!value) { - /* Wrong parameter */ - return -1; - } - - ret = mk_vhost_set_property(vh, key, value); - if (ret != 0) { - va_end(va); - return -1; - } - } - - va_end(va); - return 0; -} - -int mk_vhost_handler(mk_ctx_t *ctx, int vid, char *regex, - void (*cb)(mk_request_t *, void *), void *data) -{ - struct mk_vhost *vh; - struct mk_vhost_handler *handler; - void (*_cb) (struct mk_http_request *, void *); - - /* Lookup the virtual host */ - vh = mk_vhost_lookup(ctx, vid); - if (!vh) { - return -1; - } - - _cb = cb; - handler = mk_vhost_handler_match(regex, _cb, data); - if (!handler) { - return -1; - } - mk_list_add(&handler->_head, &vh->handlers); - - return 0; -} - -/* Flush streams data associated to a request in question */ -int mk_http_flush(mk_request_t *req) -{ - int ret; - size_t out_bytes = 0; - - ret = mk_channel_stream_write(&req->stream, &out_bytes); - return ret; -} - -int mk_http_status(mk_request_t *req, int status) -{ - req->headers.status = status; - return 0; -} - -/* Append a response header */ -int mk_http_header(mk_request_t *req, - char *key, int key_len, - char *val, int val_len) -{ - int pos; - int len; - char *buf; - struct response_headers *h; - - h = &req->headers; - if (!h->_extra_rows) { - h->_extra_rows = mk_iov_create(MK_PLUGIN_HEADER_EXTRA_ROWS * 2, 0); - if (!h->_extra_rows) { - return -1; - } - } - - len = key_len + val_len + 4; - buf = mk_mem_alloc(len); - if (!buf) { - /* we don't free extra_rows as it's released later */ - return -1; - } - - /* Compose the buffer */ - memcpy(buf, key, key_len); - pos = key_len; - buf[pos++] = ':'; - buf[pos++] = ' '; - memcpy(buf + pos, val, val_len); - pos += val_len; - buf[pos++] = '\r'; - buf[pos++] = '\n'; - - /* Add the new buffer */ - mk_iov_add(h->_extra_rows, buf, pos, MK_TRUE); - - return 0; -} - -static inline int chunk_header(long num, char *out) -{ - int i = 1; - int j, c; - int remainder; - int quotient; - char tmp[32]; - char hex[] = "0123456789ABCDEF"; - - if (num == 0) { - out[0] = '0'; - out[1] = '\r'; - out[2] = '\n'; - out[3] = '\r'; - out[4] = '\n'; - out[5] = '\0'; - return 5; - } - - quotient = num; - while (quotient != 0) { - remainder = quotient % 16; - tmp[i++] = hex[remainder]; - quotient = quotient / 16; - } - - c = 0; - for (j = i -1 ; j > 0; j--, c++) { - out[c] = tmp[j]; - } - - out[c++] = '\r'; - out[c++] = '\n'; - out[c] = '\0'; - - return c; -} - -static void free_chunk_header(struct mk_stream_input *input) -{ - mk_mem_free(input->buffer); - input->buffer = NULL; -} - - -/* Check if response headers were processed, otherwise prepare them */ -static int headers_setup(mk_request_t *req) -{ - /* - * Let's keep it simple for now: if the headers have not been sent, do it - * now and then send the body content just queued. - */ - if (req->headers.sent == MK_FALSE) { - /* Force chunked-transfer encoding */ - if (req->protocol == MK_HTTP_PROTOCOL_11) { - req->headers.transfer_encoding = MK_HEADER_TE_TYPE_CHUNKED; - } - else { - req->headers.content_length = -1; - } - mk_header_prepare(req->session, req, req->session->server); - } - return 0; -} - -/* Enqueue some data for the body response */ -int mk_http_send(mk_request_t *req, char *buf, size_t len, - void (*cb_finish)(mk_request_t *)) -{ - int chunk_len; - int ret; - char *tmp; - char chunk_pre[32]; - (void) cb_finish; - - if (req->session->channel->status != MK_CHANNEL_OK) { - return -1; - } - - if (req->headers.status == -1) { - /* Cannot append data if the status have not been set */ - mk_err("HTTP: set the response status first"); - return -1; - } - - /* Chunk encoding prefix */ - if (req->protocol == MK_HTTP_PROTOCOL_11) { - chunk_len = chunk_header(len, chunk_pre); - tmp = mk_string_dup(chunk_pre); - if (!tmp) { - return -1; - } - ret = mk_stream_in_raw(&req->stream, NULL, - tmp, chunk_len, NULL, free_chunk_header); - if (ret != 0) { - return -1; - } - } - - /* Append raw data */ - if (len > 0) { - ret = mk_stream_in_raw(&req->stream, NULL, - buf, len, NULL, NULL); - if (ret == 0) { - /* Update count of bytes */ - req->stream_size += len; - } - } - - if (req->protocol == MK_HTTP_PROTOCOL_11 && len > 0) { - ret = mk_stream_in_raw(&req->stream, NULL, - "\r\n", 2, NULL, NULL); - } - - /* Validate if the response headers are ready */ - headers_setup(req); - - /* Flush channel data */ - ret = mk_http_flush(req); - - /* - * Flush have been done, before to return our original caller, we want to yield - * and give some execution time to the event loop to avoid possible blocking - * since the caller might be using this mk_http_send() in a loop. - */ - mk_lib_yield(req); - return ret; -} - -int mk_http_done(mk_request_t *req) -{ - if (req->session->channel->status != MK_CHANNEL_OK) { - return -1; - } - - /* Validate if the response headers are ready */ - headers_setup(req); - - if (req->headers.transfer_encoding == MK_HEADER_TE_TYPE_CHUNKED) { - /* Append end-of-chunk bytes */ - mk_http_send(req, NULL, 0, NULL); - } - else { - mk_http_send(req, NULL, 0, NULL); - } - - if (req->session->close_now == MK_TRUE) { - mk_lib_yield(req); - } - - return 0; -} - -/* Create a messaging queue end-point */ -int mk_mq_create(mk_ctx_t *ctx, char *name, void (*cb), void *data) -{ - int id; - - id = mk_fifo_queue_create(ctx->fifo, name, cb, data); - return id; -} - -/* Write a message to a specific queue ID */ -int mk_mq_send(mk_ctx_t *ctx, int qid, void *data, size_t size) -{ - return mk_fifo_send(ctx->fifo, qid, data, size); -} - -int mk_main() -{ - while (1) { - sleep(60); - } - - return 0; -} diff --git a/fluent-bit/lib/monkey/mk_server/mk_mimetype.c b/fluent-bit/lib/monkey/mk_server/mk_mimetype.c deleted file mode 100644 index b86b4ef1..00000000 --- a/fluent-bit/lib/monkey/mk_server/mk_mimetype.c +++ /dev/null @@ -1,227 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* Monkey HTTP Server - * ================== - * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _GNU_SOURCE - -#include <stdio.h> -#include <stdlib.h> -#include <sys/stat.h> -#include <string.h> -#include <ctype.h> - -#include <mk_core/mk_unistd.h> - -#include <monkey/monkey.h> -#include <monkey/mk_mimetype.h> -#include <monkey/mk_utils.h> -#include <monkey/mk_config.h> -#include <monkey/mk_core.h> -#include <monkey/mk_http.h> - -struct mk_mimetype *mimetype_default; - -static int rbtree_compare(const void *lhs, const void *rhs) -{ - return strcmp((const char *)lhs, (const char *)rhs); -} - -/* Match mime type for requested resource */ -struct mk_mimetype *mk_mimetype_lookup(struct mk_server *server, char *name) -{ - int cmp; - struct rb_tree_node *node = server->mimetype_rb_head.root; - - while (node) { - struct mk_mimetype *entry = container_of(node, struct mk_mimetype, _rb_head); - cmp = strcmp(name, entry->name); - if (cmp < 0) - node = node->left; - else if (cmp > 0) - node = node->right; - else { - return entry; - } - } - return NULL; -} - -int mk_mimetype_add(struct mk_server *server, char *name, const char *type) -{ - int len = strlen(type) + 3; - char *p; - struct mk_mimetype *new_mime; - - /* make sure we register the extension in lower case */ - p = name; - for ( ; *p; ++p) *p = tolower(*p); - - new_mime = mk_mem_alloc_z(sizeof(struct mk_mimetype)); - if (!new_mime) { - return -1; - } - new_mime->name = mk_string_dup(name); - if (!new_mime->name) { - mk_mem_free(new_mime); - return -1; - } - new_mime->type.data = mk_mem_alloc(len); - if (!new_mime->type.data) { - mk_mem_free(new_mime->name); - mk_mem_free(new_mime); - return -1; - } - new_mime->type.len = len - 1; - new_mime->header_type.data = mk_mem_alloc(len + 32); - if (!new_mime->header_type.data) { - mk_mem_free(new_mime->name); - mk_mem_free(new_mime->type.data); - mk_mem_free(new_mime); - return -1; - } - new_mime->header_type.len = snprintf(new_mime->header_type.data, - len + 32, - "Content-Type: %s\r\n", - type); - strcpy(new_mime->type.data, type); - strcat(new_mime->type.data, MK_CRLF); - new_mime->type.data[len-1] = '\0'; - - /* Insert the node into the RBT */ - rb_tree_insert(&server->mimetype_rb_head, - new_mime->name, &new_mime->_rb_head); - - /* Add to linked list head */ - mk_list_add(&new_mime->_head, &server->mimetype_list); - - return 0; -} - -int mk_mimetype_init(struct mk_server *server) -{ - char *name; - int ret; - - /* Initialize the heads */ - mk_list_init(&server->mimetype_list); - rb_tree_new(&server->mimetype_rb_head, rbtree_compare); - - name = mk_string_dup(MIMETYPE_DEFAULT_NAME); - if (server->mimetype_default_str) { - ret = mk_mimetype_add(server, name, server->mimetype_default_str); - } - else { - ret = mk_mimetype_add(server, name, MIMETYPE_DEFAULT_TYPE); - } - if (ret < 0) { - mk_mem_free(name); - return -1; - } - server->mimetype_default = mk_list_entry_first(&server->mimetype_list, - struct mk_mimetype, - _head); - mk_mem_free(name); - return 0; -} - -/* Load the two mime arrays into memory */ -int mk_mimetype_read_config(struct mk_server *server) -{ - char path[MK_MAX_PATH]; - struct mk_rconf *cnf; - struct mk_rconf_section *section; - struct mk_rconf_entry *entry; - struct mk_list *head; - struct file_info f_info; - int ret; - - if (!server->conf_mimetype) { - return -1; - } - - /* Read mime types configuration file */ - snprintf(path, MK_MAX_PATH, "%s/%s", - server->path_conf_root, - server->conf_mimetype); - - ret = mk_file_get_info(path, &f_info, MK_FILE_EXISTS); - if (ret == -1 || f_info.is_file == MK_FALSE) { - snprintf(path, MK_MAX_PATH, "%s", server->conf_mimetype); - } - cnf = mk_rconf_open(path); - if (!cnf) { - mk_warn("[mime] skipping mimetype configuration file"); - return -1; - } - - /* Get MimeTypes tag */ - section = mk_rconf_section_get(cnf, "MIMETYPES"); - if (!section) { - mk_err("[mime] Invalid mime type file"); - return -1; - } - - mk_list_foreach(head, §ion->entries) { - entry = mk_list_entry(head, struct mk_rconf_entry, _head); - if (!entry->key || !entry->val) { - continue; - } - - if (mk_mimetype_add(server, entry->key, entry->val) != 0) { - mk_err("[mime] Error loading Mime Types"); - return -1; - } - } - - mk_rconf_free(cnf); - - return 0; -} - -struct mk_mimetype *mk_mimetype_find(struct mk_server *server, mk_ptr_t *filename) -{ - int j, len; - - j = len = filename->len; - - /* looking for extension */ - while (j >= 0 && filename->data[j] != '.') { - j--; - } - - if (j <= 0) { - return NULL; - } - - return mk_mimetype_lookup(server, filename->data + j + 1); -} - -void mk_mimetype_free_all(struct mk_server *server) -{ - struct mk_list *head; - struct mk_list *tmp; - struct mk_mimetype *mime; - - mk_list_foreach_safe(head, tmp, &server->mimetype_list) { - mime = mk_list_entry(head, struct mk_mimetype, _head); - mk_ptr_free(&mime->type); - mk_mem_free(mime->name); - mk_mem_free(mime->header_type.data); - mk_mem_free(mime); - } -} diff --git a/fluent-bit/lib/monkey/mk_server/mk_net.c b/fluent-bit/lib/monkey/mk_server/mk_net.c deleted file mode 100644 index de183de4..00000000 --- a/fluent-bit/lib/monkey/mk_server/mk_net.c +++ /dev/null @@ -1,284 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* Monkey HTTP Server - * ================== - * Copyright 2001-2016 Monkey Software LLC <eduardo@monkey.io> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <monkey/mk_core.h> -#include <monkey/mk_net.h> -#include <monkey/mk_scheduler.h> -#include <monkey/mk_plugin.h> -#include <monkey/mk_thread.h> -#include <monkey/mk_tls.h> - -#ifdef _WIN32 -#include <winsock2.h> -#include <afunix.h> -#else -#include <sys/socket.h> -#include <netinet/tcp.h> -#endif - -/* Initialize the network stack*/ -int mk_net_init() -{ -#ifdef _WIN32 - int result; - WSADATA wsa_data; - static int initialized = 0; - - if(0 != initialized) { - return 0; - } - - result = WSAStartup(MAKEWORD(2, 2), &wsa_data); - - if(0 != result) { - if(WSAEINPROGRESS == result) - { - Sleep(100); /* Let the other thread finish initializing the stack */ - - return 0; - } - - return -1; - } - - initialized = 1; -#endif - - return 0; -} - -/* Connect to a TCP socket server */ -static int mk_net_fd_connect(int fd, char *host, unsigned long port) -{ - int ret; - struct addrinfo hints; - struct addrinfo *res; - char _port[6]; - - memset(&hints, 0, sizeof hints); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - - snprintf(_port, sizeof(_port), "%lu", port); - ret = getaddrinfo(host, _port, &hints, &res); - if (ret != 0) { - return -1; - } - - ret = connect(fd, res->ai_addr, res->ai_addrlen); - freeaddrinfo(res); - - return ret; -} - -struct mk_net_connection *mk_net_conn_create(char *addr, int port) -{ - int fd; - int ret; - int error = 0; - socklen_t len = sizeof(error); - struct mk_sched_worker *sched; - struct mk_net_connection *conn; - - /* Allocate connection context */ - conn = mk_mem_alloc(sizeof(struct mk_net_connection)); - if (!conn) { - return NULL; - } - - /* Create socket */ - fd = mk_socket_create(AF_INET, SOCK_STREAM, 0); - if (fd == -1) { - mk_mem_free(conn); - return NULL; - } - - /* Make socket async */ - mk_socket_set_nonblocking(fd); - conn->fd = fd; - - ret = mk_net_fd_connect(conn->fd, addr, port); - if (ret == -1) { - if (errno != EINPROGRESS) { - close(fd); - mk_mem_free(conn); - return NULL; - } - - MK_EVENT_NEW(&conn->event); - - sched = mk_sched_get_thread_conf(); - // FIXME: not including the thread - //conn->thread = mk_thread_get(); - ret = mk_event_add(sched->loop, conn->fd, MK_EVENT_THREAD, - MK_EVENT_WRITE, &conn->event); - if (ret == -1) { - close(fd); - mk_mem_free(conn); - return NULL; - } - - /* - * Return the control to the parent caller, we need to wait for - * the event loop to get back to us. - */ - mk_thread_yield(conn->thread); - - /* We got a notification, remove the event registered */ - ret = mk_event_del(sched->loop, &conn->event); - - /* Check the connection status */ - if (conn->event.mask & MK_EVENT_WRITE) { - ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len); - if (ret == -1) { - close(fd); - mk_mem_free(conn); - return NULL; - } - - if (error != 0) { - /* Connection is broken, not much to do here */ - fprintf(stderr, "Async connection failed %s:%i\n", - conn->host, conn->port); - close(fd); - mk_mem_free(conn); - return NULL; - } - MK_EVENT_NEW(&conn->event); - return conn; - } - else { - close(fd); - mk_mem_free(conn); - return NULL; - } - } - - return NULL; -} - -int mk_net_conn_write(struct mk_channel *channel, - void *data, size_t len) -{ - int ret = 0; - int error; - ssize_t bytes; - size_t total = 0; - size_t send; - socklen_t slen = sizeof(error); - struct mk_thread *th = MK_TLS_GET(mk_thread); - struct mk_sched_worker *sched; - - sched = mk_sched_get_thread_conf(); - if (!sched) { - return -1; - } - - retry: - error = 0; - - if (len - total > 524288) { - send = 524288; - } - else { - send = (len - total); - } - - send = len - total; - bytes = channel->io->write(channel->io->plugin, channel->fd, (uint8_t *)data + total, send); - if (bytes == -1) { - if (errno == EAGAIN) { - MK_EVENT_NEW(channel->event); - channel->thread = th; - ret = mk_event_add(sched->loop, - channel->fd, - MK_EVENT_THREAD, - MK_EVENT_WRITE, channel->event); - if (ret == -1) { - /* - * If we failed here there no much that we can do, just - * let the caller we failed - */ - return -1; - } - - /* - * Return the control to the parent caller, we need to wait for - * the event loop to get back to us. - */ - mk_thread_yield(th); - - /* We got a notification, remove the event registered */ - ret = mk_event_del(sched->loop, channel->event); - if (ret == -1) { - return -1; - } - - /* Check the connection status */ - if (channel->event->mask & MK_EVENT_WRITE) { - ret = getsockopt(channel->fd, SOL_SOCKET, SO_ERROR, &error, &slen); - if (ret == -1) { - fprintf(stderr, "[io] could not validate socket status"); - return -1; - } - - if (error != 0) { - return -1; - } - - MK_EVENT_NEW(channel->event); - goto retry; - } - else { - return -1; - } - - } - else { - return -1; - } - } - - /* Update counters */ - total += bytes; - if (total < len) { - channel->thread = th; - ret = mk_event_add(sched->loop, - channel->fd, - MK_EVENT_THREAD, - MK_EVENT_WRITE, channel->event); - if (ret == -1) { - /* - * If we failed here there no much that we can do, just - * let the caller we failed - */ - return -1; - } - - mk_thread_yield(th); - goto retry; - } - - if (channel->event->status & MK_EVENT_REGISTERED) { - /* We got a notification, remove the event registered */ - ret = mk_event_del(sched->loop, channel->event); - } - - return total; -} diff --git a/fluent-bit/lib/monkey/mk_server/mk_plugin.c b/fluent-bit/lib/monkey/mk_server/mk_plugin.c deleted file mode 100644 index 50e2886b..00000000 --- a/fluent-bit/lib/monkey/mk_server/mk_plugin.c +++ /dev/null @@ -1,804 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* Monkey HTTP Server - * ================== - * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <monkey/monkey.h> -#include <monkey/mk_utils.h> -#include <monkey/mk_http.h> -#include <monkey/mk_clock.h> -#include <monkey/mk_plugin.h> -#include <monkey/mk_mimetype.h> -#include <monkey/mk_vhost.h> -#include <monkey/mk_static_plugins.h> -#include <monkey/mk_plugin_stage.h> -#include <monkey/mk_core.h> -#include <monkey/mk_net.h> - -#ifndef _WIN32 -#include <dlfcn.h> -#include <err.h> -#endif - -enum { - bufsize = 256 -}; - -static struct plugin_stagemap *plg_stagemap; -struct plugin_network_io *plg_netiomap; - -struct mk_plugin *mk_plugin_lookup(char *shortname, struct mk_server *server) -{ - struct mk_list *head; - struct mk_plugin *p = NULL; - - mk_list_foreach(head, &server->plugins) { - p = mk_list_entry(head, struct mk_plugin, _head); - if (strcmp(p->shortname, shortname) == 0){ - return p; - } - } - - return NULL; -} - -void *mk_plugin_load_dynamic(const char *path) -{ - void *handle; - -#ifdef _WIN32 - handle = (void *) LoadLibraryA(path); -#else - handle = dlopen(path, RTLD_LAZY); - - if (!handle) { - mk_warn("dlopen() %s", dlerror()); - } -#endif - - return handle; -} - -void *mk_plugin_load_symbol(void *handler, const char *symbol) -{ - void *s; - -#ifdef _WIN32 - s = GetProcAddress((HMODULE)handler, symbol); -#else - dlerror(); - s = dlsym(handler, symbol); - if (dlerror() != NULL) { - return NULL; - } -#endif - - return s; -} - -/* Initialize a plugin, trigger the init_plugin callback */ -static int mk_plugin_init(struct plugin_api *api, - struct mk_plugin *plugin, - struct mk_server *server) -{ - int ret; - unsigned long len; - char path[1024]; - char *conf_dir = NULL; - struct file_info f_info; - - MK_TRACE("Load Plugin: '%s'", plugin->shortname); - - snprintf(path, 1024, "%s/%s", - server->path_conf_root, server->conf_plugins); - ret = mk_file_get_info(path, &f_info, MK_FILE_READ); - if (ret == -1 || f_info.is_directory == MK_FALSE) { - snprintf(path, 1024, "%s", server->conf_plugins); - } - - /* Build plugin configuration path */ - mk_string_build(&conf_dir, - &len, - "%s/%s/", - path, plugin->shortname); - - /* Init plugin */ - plugin->api = api; - plugin->server_ctx = server; - - if (plugin->network != NULL) { - plugin->network->plugin = plugin; - } - - ret = plugin->init_plugin(plugin, conf_dir); - mk_mem_free(conf_dir); - - return ret; -} - - -/* - * Load a plugin into Monkey core, 'type' defines if it's a MK_PLUGIN_STATIC or - * a MK_PLUGIN_DYNAMIC. 'shortname' is mandatory and 'path' is only used when - * MK_PLUGIN_DYNAMIC is set and represents the absolute path of the shared - * library. - */ -struct mk_plugin *mk_plugin_load(int type, const char *shortname, - void *data, struct mk_server *server) -{ - char *path; - char symbol[64]; - void *handler; - struct mk_list *head; - struct mk_plugin *tmp; - struct mk_plugin *plugin = NULL; - struct mk_plugin_stage *stage; - - /* Set main struct name to reference */ - if (type == MK_PLUGIN_DYNAMIC) { - path = (char *) data; - handler = mk_plugin_load_dynamic(path); - if (!handler) { - return NULL; - } - - snprintf(symbol, sizeof(symbol) - 1, "mk_plugin_%s", shortname); - plugin = mk_plugin_load_symbol(handler, symbol); - if (!plugin) { - mk_warn("Plugin '%s' is not registering properly", path); -#ifdef _WIN32 - FreeLibrary((HMODULE)handler); -#else - dlclose(handler); -#endif - return NULL; - } - - /* Make sure this is not loaded twice (ref #218) */ - mk_list_foreach(head, &server->plugins) { - tmp = mk_list_entry(head, struct mk_plugin, _head); - if (tmp->load_type == MK_PLUGIN_STATIC && - strcmp(tmp->name, plugin->name) == 0){ - mk_warn("Plugin '%s' have been built-in.", - tmp->shortname); -#ifdef _WIN32 - FreeLibrary((HMODULE)handler); -#else - dlclose(handler); -#endif - return NULL; - } - } - - plugin->load_type = MK_PLUGIN_DYNAMIC; - plugin->handler = handler; - plugin->path = mk_string_dup(path); - } - else if (type == MK_PLUGIN_STATIC) { - plugin = (struct mk_plugin *) data; - plugin->load_type = MK_PLUGIN_STATIC; - } - - if (!plugin) { - return NULL; - } - - /* Validate all callbacks are set */ - if (!plugin->shortname || !plugin->name || !plugin->version || - !plugin->init_plugin || !plugin->exit_plugin) { - mk_warn("Plugin '%s' is not registering all fields properly", - shortname); - return NULL; - } - - if (plugin->hooks & MK_PLUGIN_NETWORK_LAYER) { - mk_bug(!plugin->network); - } - - mk_list_init(&plugin->stage_list); - if (plugin->hooks & MK_PLUGIN_STAGE) { - struct mk_plugin_stage *st; - - stage = plugin->stage; - if (stage->stage10) { - st = mk_mem_alloc(sizeof(struct mk_plugin_stage)); - st->stage10 = stage->stage10; - st->plugin = plugin; - mk_list_add(&st->_head, &server->stage10_handler); - mk_list_add(&st->_parent_head, &plugin->stage_list); - } - if (stage->stage20) { - st = mk_mem_alloc(sizeof(struct mk_plugin_stage)); - st->stage20 = stage->stage20; - st->plugin = plugin; - mk_list_add(&st->_head, &server->stage20_handler); - mk_list_add(&st->_parent_head, &plugin->stage_list); - } - if (stage->stage30) { - st = mk_mem_alloc(sizeof(struct mk_plugin_stage)); - st->stage30 = stage->stage30; - st->plugin = plugin; - mk_list_add(&st->_head, &server->stage30_handler); - mk_list_add(&st->_parent_head, &plugin->stage_list); - } - if (stage->stage40) { - st = mk_mem_alloc(sizeof(struct mk_plugin_stage)); - st->stage40 = stage->stage40; - st->plugin = plugin; - mk_list_add(&st->_head, &server->stage40_handler); - mk_list_add(&st->_parent_head, &plugin->stage_list); - } - if (stage->stage50) { - st = mk_mem_alloc(sizeof(struct mk_plugin_stage)); - st->stage50 = stage->stage50; - st->plugin = plugin; - mk_list_add(&st->_head, &server->stage50_handler); - mk_list_add(&st->_parent_head, &plugin->stage_list); - } - } - - if (type == MK_PLUGIN_DYNAMIC) { - /* Add Plugin to the end of the list */ - mk_list_add(&plugin->_head, &server->plugins); - } - - return plugin; -} - -void mk_plugin_unregister(struct mk_plugin *p) -{ - mk_mem_free(p->path); - mk_list_del(&p->_head); - if (p->load_type == MK_PLUGIN_DYNAMIC) { -#ifdef _WIN32 - FreeLibrary((HMODULE)p->handler); -#else - dlclose(p->handler); -#endif - } - -} - -void mk_plugin_api_init(struct mk_server *server) -{ - struct plugin_api *api; - - /* Create an instance of the API */ - api = mk_mem_alloc_z(sizeof(struct plugin_api)); - -#ifndef _WIN32 - __builtin_prefetch(api); -#endif - - /* Setup and connections list */ - /* FIXME: api->config = server; */ - - /* API plugins funcions */ - - /* Error helper */ - api->_error = mk_print; - - /* HTTP callbacks */ - api->http_request_end = mk_plugin_http_request_end; - api->http_request_error = mk_plugin_http_error; - - /* Memory callbacks */ - api->pointer_set = mk_ptr_set; - api->pointer_print = mk_ptr_print; - api->pointer_to_buf = mk_ptr_to_buf; - api->plugin_load_symbol = mk_plugin_load_symbol; - api->mem_alloc = mk_mem_alloc; - api->mem_alloc_z = mk_mem_alloc_z; - api->mem_realloc = mk_mem_realloc; - api->mem_free = mk_mem_free; - - /* String Callbacks */ - api->str_build = mk_string_build; - api->str_dup = mk_string_dup; - api->str_search = mk_string_search; - api->str_search_n = mk_string_search_n; - api->str_char_search = mk_string_char_search; - api->str_copy_substr = mk_string_copy_substr; - api->str_itop = mk_string_itop; - api->str_split_line = mk_string_split_line; - api->str_split_free = mk_string_split_free; - - /* File Callbacks */ - api->file_to_buffer = mk_file_to_buffer; - api->file_get_info = mk_file_get_info; - - /* HTTP Callbacks */ - api->header_prepare = mk_plugin_header_prepare; - api->header_add = mk_plugin_header_add; - api->header_get = mk_http_header_get; - api->header_set_http_status = mk_header_set_http_status; - - /* Channels / Streams */ - api->channel_new = mk_channel_new; - api->channel_flush = mk_channel_flush; - api->channel_write = mk_channel_write; - api->channel_append_stream = mk_channel_append_stream; - - /* IOV callbacks */ - api->iov_create = mk_iov_create; - api->iov_realloc = mk_iov_realloc; - api->iov_free = mk_iov_free; - api->iov_free_marked = mk_iov_free_marked; - api->iov_add = mk_iov_add; - api->iov_set_entry = mk_iov_set_entry; - api->iov_send = mk_iov_send; - api->iov_print = mk_iov_print; - - /* events mechanism */ - api->ev_loop_create = mk_event_loop_create; - api->ev_add = mk_event_add; - api->ev_del = mk_event_del; - api->ev_timeout_create = mk_event_timeout_create; - api->ev_channel_create = mk_event_channel_create; - api->ev_wait = mk_event_wait; - api->ev_backend = mk_event_backend; - - /* Mimetype */ - api->mimetype_lookup = mk_mimetype_lookup; - - /* Socket callbacks */ - api->socket_cork_flag = mk_socket_set_cork_flag; - api->socket_connect = mk_socket_connect; - api->socket_open = mk_socket_open; - api->socket_reset = mk_socket_reset; - api->socket_set_tcp_fastopen = mk_socket_set_tcp_fastopen; - api->socket_set_tcp_reuseport = mk_socket_set_tcp_reuseport; - api->socket_set_tcp_nodelay = mk_socket_set_tcp_nodelay; - api->socket_set_nonblocking = mk_socket_set_nonblocking; - api->socket_create = mk_socket_create; - api->socket_ip_str = mk_socket_ip_str; - - /* Async network */ - api->net_conn_create = mk_net_conn_create; - - /* Config Callbacks */ - api->config_create = mk_rconf_create; - api->config_open = mk_rconf_open; - api->config_free = mk_rconf_free; - api->config_section_get = mk_rconf_section_get; - api->config_section_get_key = mk_rconf_section_get_key; - - /* Scheduler and Event callbacks */ - api->sched_loop = mk_sched_loop; - api->sched_get_connection = mk_sched_get_connection; - api->sched_event_free = mk_sched_event_free; - api->sched_remove_client = mk_plugin_sched_remove_client; - api->sched_worker_info = mk_plugin_sched_get_thread_conf; - - /* Worker functions */ - api->worker_spawn = mk_utils_worker_spawn; - api->worker_rename = mk_utils_worker_rename; - - /* Time functions */ - api->time_unix = mk_plugin_time_now_unix; - api->time_to_gmt = mk_utils_utime2gmt; - api->time_human = mk_plugin_time_now_human; - - api->stacktrace = (void *) mk_utils_stacktrace; - api->kernel_version = mk_kernel_version; - api->kernel_features_print = mk_kernel_features_print; - api->plugins = &server->plugins; - - /* handler */ - api->handler_param_get = mk_handler_param_get; - - server->api = api; -} - -void mk_plugin_load_static(struct mk_server *server) -{ - /* Load static plugins */ - mk_list_init(&server->plugins); - mk_static_plugins(&server->plugins); -} - -void mk_plugin_load_all(struct mk_server *server) -{ - int ret; - char *tmp; - char *path; - char shortname[64]; - struct mk_plugin *p; - struct mk_rconf *cnf; - struct mk_rconf_section *section; - struct mk_rconf_entry *entry; - struct mk_list *head; - struct mk_list *htmp; - struct file_info f_info; - - mk_plugin_load_static(server); - mk_list_foreach_safe(head, htmp, &server->plugins) { - p = mk_list_entry(head, struct mk_plugin, _head); - - /* Load the static plugin */ - p = mk_plugin_load(MK_PLUGIN_STATIC, - p->shortname, - (void *) p, - server); - if (!p) { - continue; - } - ret = mk_plugin_init(server->api, p, server); - if (ret == -1) { - /* Free plugin, do not register, error initializing */ - mk_warn("Plugin initialization failed: %s", p->shortname); - mk_plugin_unregister(p); - continue; - } - else if (ret == -2) { - /* Do not register, just skip it */ - mk_plugin_unregister(p); - continue; - } - } - - /* In case there are not dynamic plugins */ - if (!server->conf_plugin_load) { - return; - } - - /* Read configuration file */ - path = mk_mem_alloc_z(1024); - snprintf(path, 1024, "%s/%s", server->path_conf_root, - server->conf_plugin_load); - ret = mk_file_get_info(path, &f_info, MK_FILE_READ); - if (ret == -1 || f_info.is_file == MK_FALSE) { - snprintf(path, 1024, "%s", server->conf_plugin_load); - } - - cnf = mk_rconf_open(path); - if (!cnf) { - mk_warn("No dynamic plugins loaded."); - mk_mem_free(path); - return; - } - - /* Read section 'PLUGINS' */ - section = mk_rconf_section_get(cnf, "PLUGINS"); - if (!section) { - exit(EXIT_FAILURE); - } - - /* Read key entries */ - mk_list_foreach_safe(head, htmp, §ion->entries) { - entry = mk_list_entry(head, struct mk_rconf_entry, _head); - if (strcasecmp(entry->key, "Load") == 0) { - - /* Get plugin 'shortname' */ - tmp = memrchr(entry->val, '-', strlen(entry->val)); - ++tmp; - memset(shortname, '\0', sizeof(shortname) - 1); - strncpy(shortname, tmp, strlen(tmp) - 3); - - /* Load the dynamic plugin */ - p = mk_plugin_load(MK_PLUGIN_DYNAMIC, - shortname, - entry->val, - server); - if (!p) { - mk_warn("Invalid plugin '%s'", entry->val); - continue; - } - - ret = mk_plugin_init(server->api, p, server); - if (ret < 0) { - /* Free plugin, do not register */ - MK_TRACE("Unregister plugin '%s'", p->shortname); - mk_plugin_unregister(p); - continue; - } - } - } - - /* Look for plugins thread key data */ - mk_plugin_preworker_calls(server); - mk_vhost_map_handlers(server); - mk_mem_free(path); - mk_rconf_free(cnf); -} - -static void mk_plugin_exit_stages(struct mk_plugin *p) -{ - struct mk_list *tmp; - struct mk_list *head; - struct mk_plugin_stage *st; - - mk_list_foreach_safe(head, tmp, &p->stage_list) { - st = mk_list_entry(head, struct mk_plugin_stage, _parent_head); - - /* remove from direct config->stageN head list */ - mk_list_del(&st->_head); - - /* remove from plugin->stage_lists */ - mk_list_del(&st->_parent_head); - mk_mem_free(st); - } -} - -/* Invoke all plugins 'exit' hook and free resources by the plugin interface */ -void mk_plugin_exit_all(struct mk_server *server) -{ - struct mk_plugin *plugin; - struct mk_list *head, *tmp; - - /* Plugins */ - mk_list_foreach(head, &server->plugins) { - plugin = mk_list_entry(head, struct mk_plugin, _head); - plugin->exit_plugin(plugin); - } - - /* Plugin interface it self */ - mk_list_foreach_safe(head, tmp, &server->plugins) { - plugin = mk_list_entry(head, struct mk_plugin, _head); - mk_list_del(&plugin->_head); - mk_plugin_exit_stages(plugin); - - if (plugin->load_type == MK_PLUGIN_DYNAMIC) { - mk_mem_free(plugin->path); -#ifdef _WIN32 - FreeLibrary((HMODULE)plugin->handler); -#else - dlclose(plugin ->handler); -#endif - } - else if (plugin->load_type == MK_PLUGIN_STATIC) { - if (plugin->network != NULL) { - mk_mem_free(plugin->network); - } - - mk_mem_free(plugin); - } - } - - mk_mem_free(server->api); - mk_mem_free(plg_stagemap); -} - -/* - * When a worker is exiting, it invokes this function to release any plugin - * associated data. - */ -void mk_plugin_exit_worker() -{ -} - -/* This function is called by every created worker - * for plugins which need to set some data under a thread - * context - */ -void mk_plugin_core_process(struct mk_server *server) -{ - struct mk_plugin *node; - struct mk_list *head; - - mk_list_foreach(head, &server->plugins) { - node = mk_list_entry(head, struct mk_plugin, _head); - - /* Init plugin */ - if (node->master_init) { - node->master_init(server); - } - } -} - -/* This function is called by every created worker - * for plugins which need to set some data under a thread - * context - */ -void mk_plugin_core_thread(struct mk_server *server) -{ - - struct mk_plugin *node; - struct mk_list *head; - - mk_list_foreach(head, &server->plugins) { - node = mk_list_entry(head, struct mk_plugin, _head); - - /* Init plugin thread context */ - if (node->worker_init) { - node->worker_init(server); - } - } -} - -/* This function is called by Monkey *outside* of the - * thread context for plugins, so here's the right - * place to set pthread keys or similar - */ -void mk_plugin_preworker_calls(struct mk_server *server) -{ - int ret; - struct mk_plugin *node; - struct mk_list *head; - - mk_list_foreach(head, &server->plugins) { - node = mk_list_entry(head, struct mk_plugin, _head); - - /* Init pthread keys */ - if (node->thread_key) { - MK_TRACE("[%s] Set thread key", node->shortname); - - ret = pthread_key_create(node->thread_key, NULL); - if (ret != 0) { - mk_err("Plugin Error: could not create key for %s", - node->shortname); - } - } - } -} - -int mk_plugin_http_error(int http_status, struct mk_http_session *cs, - struct mk_http_request *sr, - struct mk_plugin *plugin) -{ - return mk_http_error(http_status, cs, sr, plugin->server_ctx); -} - - -int mk_plugin_http_request_end(struct mk_plugin *plugin, - struct mk_http_session *cs, int close) -{ - int ret; - int con; - struct mk_http_request *sr; - struct mk_server *server = plugin->server_ctx; - - MK_TRACE("[FD %i] PLUGIN HTTP REQUEST END", cs->socket); - - cs->status = MK_REQUEST_STATUS_INCOMPLETE; - if (mk_list_is_empty(&cs->request_list) == 0) { - MK_TRACE("[FD %i] Tried to end non-existing request.", cs->socket); - return -1; - } - - sr = mk_list_entry_last(&cs->request_list, struct mk_http_request, _head); - mk_plugin_stage_run_40(cs, sr, server); - - if (close == MK_TRUE) { - cs->close_now = MK_TRUE; - } - - /* Let's check if we should ask to finalize the connection or not */ - ret = mk_http_request_end(cs, server); - MK_TRACE("[FD %i] HTTP session end = %i", cs->socket, ret); - if (ret < 0) { - con = mk_sched_event_close(cs->conn, mk_sched_get_thread_conf(), - MK_EP_SOCKET_DONE, server); - if (con != 0) { - return con; - } - else { - return -1; - } - } - - return ret; -} - -/* Plugin epoll event handlers - * --------------------------- - * this functions are called by connection.c functions as mk_conn_read(), - * mk_conn_write(),mk_conn_error(), mk_conn_close() and mk_conn_timeout(). - * - * Return Values: - * ------------- - * MK_PLUGIN_RET_EVENT_NOT_ME: There's no plugin hook associated - */ - -void mk_plugin_event_bad_return(const char *hook, int ret) -{ - mk_err("[%s] Not allowed return value %i", hook, ret); -} - -int mk_plugin_time_now_unix(struct mk_server *server) -{ - return server->clock_context->log_current_utime; -} - -mk_ptr_t *mk_plugin_time_now_human(struct mk_server *server) -{ - return &server->clock_context->log_current_time; -} - -int mk_plugin_sched_remove_client(int socket, struct mk_server *server) -{ - struct mk_sched_conn *conn; - struct mk_sched_worker *sched; - - MK_TRACE("[FD %i] remove client", socket); - - sched = mk_sched_get_thread_conf(); - conn = mk_sched_get_connection(sched, socket); - if (!conn) { - return -1; - } - - return mk_sched_remove_client(conn, sched, server); -} - -int mk_plugin_header_prepare(struct mk_plugin *plugin, - struct mk_http_session *cs, - struct mk_http_request *sr) -{ - return mk_header_prepare(cs, sr, plugin->server_ctx); -} - - -int mk_plugin_header_add(struct mk_http_request *sr, char *row, int len) -{ - mk_bug(!sr); - - if (!sr->headers._extra_rows) { - /* - * We allocate space for a fixed number of IOV entries: - * - * MK_PLUGIN_HEADER_EXTRA_ROWS = X - * - * we use (MK_PLUGIN_HEADER_EXTRA_ROWS * 2) thinking in an ending CRLF - */ - sr->headers._extra_rows = mk_iov_create(MK_PLUGIN_HEADER_EXTRA_ROWS * 2, 0); - mk_bug(!sr->headers._extra_rows); - } - - mk_iov_add(sr->headers._extra_rows, row, len, - MK_FALSE); - mk_iov_add(sr->headers._extra_rows, - mk_iov_crlf.data, mk_iov_crlf.len, - MK_FALSE); - return 0; -} - -struct mk_sched_worker *mk_plugin_sched_get_thread_conf() -{ - return MK_TLS_GET(mk_tls_sched_worker_node); -} - -struct mk_plugin *mk_plugin_cap(char cap, struct mk_server *server) -{ - struct mk_list *head; - struct mk_plugin *plugin; - - mk_list_foreach(head, &server->plugins) { - plugin = mk_list_entry(head, struct mk_plugin, _head); - if (plugin->capabilities & cap) { - return plugin; - } - } - - return NULL; -} - -struct mk_vhost_handler_param *mk_handler_param_get(int id, - struct mk_list *params) -{ - int i = 0; - struct mk_list *head; - - mk_list_foreach(head, params) { - if (i == id) { - return mk_list_entry(head, struct mk_vhost_handler_param, _head); - } - i++; - } - - return NULL; -} diff --git a/fluent-bit/lib/monkey/mk_server/mk_scheduler.c b/fluent-bit/lib/monkey/mk_server/mk_scheduler.c deleted file mode 100644 index a680d3cd..00000000 --- a/fluent-bit/lib/monkey/mk_server/mk_scheduler.c +++ /dev/null @@ -1,866 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* Monkey HTTP Server - * ================== - * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <monkey/monkey.h> -#include <monkey/mk_info.h> -#include <monkey/mk_core.h> -#include <monkey/mk_vhost.h> -#include <monkey/mk_scheduler.h> -#include <monkey/mk_scheduler_tls.h> -#include <monkey/mk_server.h> -#include <monkey/mk_thread.h> -#include <monkey/mk_cache.h> -#include <monkey/mk_config.h> -#include <monkey/mk_clock.h> -#include <monkey/mk_plugin.h> -#include <monkey/mk_utils.h> -#include <monkey/mk_linuxtrace.h> -#include <monkey/mk_server.h> -#include <monkey/mk_plugin_stage.h> -#include <monkey/mk_http_thread.h> - -#include <signal.h> - -#ifndef _WIN32 -#include <sys/syscall.h> -#endif - -extern struct mk_sched_handler mk_http_handler; -extern struct mk_sched_handler mk_http2_handler; - -pthread_mutex_t mutex_worker_init = PTHREAD_MUTEX_INITIALIZER; -pthread_mutex_t mutex_worker_exit = PTHREAD_MUTEX_INITIALIZER; - -/* - * Returns the worker id which should take a new incomming connection, - * it returns the worker id with less active connections. Just used - * if config->scheduler_mode is MK_SCHEDULER_FAIR_BALANCING. - */ -static inline int _next_target(struct mk_server *server) -{ - int i; - int target = 0; - unsigned long long tmp = 0, cur = 0; - struct mk_sched_ctx *ctx = server->sched_ctx; - struct mk_sched_worker *worker; - - cur = (ctx->workers[0].accepted_connections - - ctx->workers[0].closed_connections); - if (cur == 0) { - return 0; - } - - /* Finds the lowest load worker */ - for (i = 1; i < server->workers; i++) { - worker = &ctx->workers[i]; - tmp = worker->accepted_connections - worker->closed_connections; - if (tmp < cur) { - target = i; - cur = tmp; - - if (cur == 0) - break; - } - } - - /* - * If sched_ctx->workers[target] worker is full then the whole server too, - * because it has the lowest load. - */ - if (mk_unlikely(server->server_capacity > 0 && - server->server_capacity <= cur)) { - MK_TRACE("Too many clients: %i", server->server_capacity); - - /* Instruct to close the connection anyways, we lie, it will die */ - return -1; - } - - return target; -} - -struct mk_sched_worker *mk_sched_next_target(struct mk_server *server) -{ - int t; - struct mk_sched_ctx *ctx = server->sched_ctx; - - t = _next_target(server); - if (mk_likely(t != -1)) { - return &ctx->workers[t]; - } - - return NULL; -} - -/* - * This function is invoked when the core triggers a MK_SCHED_SIGNAL_FREE_ALL - * event through the signal channels, it means the server will stop working - * so this is the last call to release all memory resources in use. Of course - * this takes place in a thread context. - */ -void mk_sched_worker_free(struct mk_server *server) -{ - int i; - pthread_t tid; - struct mk_sched_ctx *ctx = server->sched_ctx; - struct mk_sched_worker *worker = NULL; - - pthread_mutex_lock(&mutex_worker_exit); - - /* - * Fix Me: needs to implement API to make plugins release - * their resources first at WORKER LEVEL - */ - - /* External */ - mk_plugin_exit_worker(); - mk_vhost_fdt_worker_exit(server); - mk_cache_worker_exit(); - - /* Scheduler stuff */ - tid = pthread_self(); - for (i = 0; i < server->workers; i++) { - worker = &ctx->workers[i]; - if (worker->tid == tid) { - break; - } - worker = NULL; - } - - mk_bug(!worker); - - /* FIXME!: there is nothing done here with the worker context */ - - /* Free master array (av queue & busy queue) */ - mk_mem_free(MK_TLS_GET(mk_tls_sched_cs)); - mk_mem_free(MK_TLS_GET(mk_tls_sched_cs_incomplete)); - mk_mem_free(MK_TLS_GET(mk_tls_sched_worker_notif)); - pthread_mutex_unlock(&mutex_worker_exit); -} - -struct mk_sched_handler *mk_sched_handler_cap(char cap) -{ - if (cap == MK_CAP_HTTP) { - return &mk_http_handler; - } - -#ifdef MK_HAVE_HTTP2 - else if (cap == MK_CAP_HTTP2) { - return &mk_http2_handler; - } -#endif - - return NULL; -} - -/* - * Register a new client connection into the scheduler, this call takes place - * inside the worker/thread context. - */ -struct mk_sched_conn *mk_sched_add_connection(int remote_fd, - struct mk_server_listen *listener, - struct mk_sched_worker *sched, - struct mk_server *server) -{ - int ret; - int size; - struct mk_sched_handler *handler; - struct mk_sched_conn *conn; - struct mk_event *event; - - /* Before to continue, we need to run plugin stage 10 */ - ret = mk_plugin_stage_run_10(remote_fd, server); - - /* Close connection, otherwise continue */ - if (ret == MK_PLUGIN_RET_CLOSE_CONX) { - listener->network->network->close(listener->network, remote_fd); - MK_LT_SCHED(remote_fd, "PLUGIN_CLOSE"); - return NULL; - } - - handler = listener->protocol; - if (handler->sched_extra_size > 0) { - void *data; - size = (sizeof(struct mk_sched_conn) + handler->sched_extra_size); - data = mk_mem_alloc_z(size); - conn = (struct mk_sched_conn *) data; - } - else { - conn = mk_mem_alloc_z(sizeof(struct mk_sched_conn)); - } - - if (!conn) { - mk_err("[server] Could not register client"); - return NULL; - } - - event = &conn->event; - event->fd = remote_fd; - event->type = MK_EVENT_CONNECTION; - event->mask = MK_EVENT_EMPTY; - event->status = MK_EVENT_NONE; - conn->arrive_time = server->clock_context->log_current_utime; - conn->protocol = handler; - conn->net = listener->network->network; - conn->is_timeout_on = MK_FALSE; - conn->server_listen = listener; - - /* Stream channel */ - conn->channel.type = MK_CHANNEL_SOCKET; /* channel type */ - conn->channel.fd = remote_fd; /* socket conn */ - conn->channel.io = conn->net; /* network layer */ - conn->channel.event = event; /* parent event ref */ - mk_list_init(&conn->channel.streams); - - /* - * Register the connections into the timeout_queue: - * - * When a new connection arrives, we cannot assume it contains some data - * to read, meaning the event loop may not get notifications and the protocol - * handler will never be called. So in order to avoid DDoS we always register - * this session in the timeout_queue for further lookup. - * - * The protocol handler is in charge to remove the session from the - * timeout_queue. - */ - mk_sched_conn_timeout_add(conn, sched); - - /* Linux trace message */ - MK_LT_SCHED(remote_fd, "REGISTERED"); - - return conn; -} - -static void mk_sched_thread_lists_init() -{ - struct mk_list *sched_cs_incomplete; - - /* mk_tls_sched_cs_incomplete */ - sched_cs_incomplete = mk_mem_alloc(sizeof(struct mk_list)); - mk_list_init(sched_cs_incomplete); - MK_TLS_SET(mk_tls_sched_cs_incomplete, sched_cs_incomplete); -} - -/* Register thread information. The caller thread is the thread information's owner */ -static int mk_sched_register_thread(struct mk_server *server) -{ - struct mk_sched_ctx *ctx = server->sched_ctx; - struct mk_sched_worker *worker; - - /* - * If this thread slept inside this section, some other thread may touch - * server->worker_id. - * So protect it with a mutex, only one thread may handle server->worker_id. - * - * Note : Let's use the platform agnostic atomics we implemented in cmetrics here - * instead of a lock. - */ - worker = &ctx->workers[server->worker_id]; - worker->idx = server->worker_id++; - worker->tid = pthread_self(); - -#if defined(__linux__) - /* - * Under Linux does not exists the difference between process and - * threads, everything is a thread in the kernel task struct, and each - * one has it's own numerical identificator: PID . - * - * Here we want to know what's the PID associated to this running - * task (which is different from parent Monkey PID), it can be - * retrieved with gettid() but Glibc does not export to userspace - * the syscall, we need to call it directly through syscall(2). - */ - worker->pid = syscall(__NR_gettid); -#elif defined(__APPLE__) - uint64_t tid; - pthread_threadid_np(NULL, &tid); - worker->pid = tid; -#else - worker->pid = 0xdeadbeef; -#endif - - /* Initialize lists */ - mk_list_init(&worker->timeout_queue); - worker->request_handler = NULL; - - return worker->idx; -} - -static void mk_signal_thread_sigpipe_safe() -{ -#ifndef _WIN32 - sigset_t old; - sigset_t set; - - sigemptyset(&set); - sigaddset(&set, SIGPIPE); - pthread_sigmask(SIG_BLOCK, &set, &old); -#endif -} - -/* created thread, all these calls are in the thread context */ -void *mk_sched_launch_worker_loop(void *data) -{ - int ret; - int wid; - unsigned long len; - char *thread_name = 0; - struct mk_list *head; - struct mk_sched_worker_cb *wcb; - struct mk_sched_worker *sched = NULL; - struct mk_sched_notif *notif = NULL; - struct mk_sched_thread_conf *thinfo = data; - struct mk_sched_ctx *ctx; - struct mk_server *server; - - server = thinfo->server; - ctx = server->sched_ctx; - - /* Avoid SIGPIPE signals on this thread */ - mk_signal_thread_sigpipe_safe(); - - /* Init specific thread cache */ - mk_sched_thread_lists_init(); - mk_cache_worker_init(); - - /* Virtual hosts: initialize per thread-vhost data */ - mk_vhost_fdt_worker_init(server); - - /* Register working thread */ - wid = mk_sched_register_thread(server); - sched = &ctx->workers[wid]; - sched->loop = mk_event_loop_create(MK_EVENT_QUEUE_SIZE); - if (!sched->loop) { - mk_err("Error creating Scheduler loop"); - exit(EXIT_FAILURE); - } - - - sched->mem_pagesize = mk_utils_get_system_page_size(); - - /* - * Create the notification instance and link it to the worker - * thread-scope list. - */ - notif = mk_mem_alloc_z(sizeof(struct mk_sched_notif)); - MK_TLS_SET(mk_tls_sched_worker_notif, notif); - - /* Register the scheduler channel to signal active workers */ - ret = mk_event_channel_create(sched->loop, - &sched->signal_channel_r, - &sched->signal_channel_w, - notif); - if (ret < 0) { - exit(EXIT_FAILURE); - } - - mk_list_init(&sched->event_free_queue); - mk_list_init(&sched->threads); - mk_list_init(&sched->threads_purge); - - /* - * ULONG_MAX BUG test only - * ======================= - * to test the workaround we can use the following value: - * - * thinfo->closed_connections = 1000; - */ - - //thinfo->ctx = thconf->ctx; - - /* Rename worker */ - mk_string_build(&thread_name, &len, "monkey: wrk/%i", sched->idx); - mk_utils_worker_rename(thread_name); - mk_mem_free(thread_name); - - /* Export known scheduler node to context thread */ - MK_TLS_SET(mk_tls_sched_worker_node, sched); - mk_plugin_core_thread(server); - - if (server->scheduler_mode == MK_SCHEDULER_REUSEPORT) { - sched->listeners = mk_server_listen_init(server); - if (!sched->listeners) { - exit(EXIT_FAILURE); - } - } - - /* Unlock the conditional initializator */ - pthread_mutex_lock(&server->pth_mutex); - server->pth_init = MK_TRUE; - pthread_cond_signal(&server->pth_cond); - pthread_mutex_unlock(&server->pth_mutex); - - /* Invoke custom worker-callbacks defined by the scheduler (lib) */ - mk_list_foreach(head, &server->sched_worker_callbacks) { - wcb = mk_list_entry(head, struct mk_sched_worker_cb, _head); - wcb->cb_func(wcb->data); - } - - mk_mem_free(thinfo); - - /* init server thread loop */ - mk_server_worker_loop(server); - - return 0; -} - -/* Create thread which will be listening for incomings requests */ -int mk_sched_launch_thread(struct mk_server *server, pthread_t *tout) -{ - pthread_t tid; - pthread_attr_t attr; - struct mk_sched_thread_conf *thconf; - - server->pth_init = MK_FALSE; - - /* - * This lock is used for the 'pth_cond' conditional. Once the worker - * thread is ready it will signal the condition. - */ - pthread_mutex_lock(&server->pth_mutex); - - /* Thread data */ - thconf = mk_mem_alloc_z(sizeof(struct mk_sched_thread_conf)); - thconf->server = server; - - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); - if (pthread_create(&tid, &attr, mk_sched_launch_worker_loop, - (void *) thconf) != 0) { - mk_libc_error("pthread_create"); - pthread_mutex_unlock(&server->pth_mutex); - return -1; - } - - *tout = tid; - - /* Block until the child thread is ready */ - while (!server->pth_init) { - pthread_cond_wait(&server->pth_cond, &server->pth_mutex); - } - - pthread_mutex_unlock(&server->pth_mutex); - - return 0; -} - -/* - * The scheduler nodes are an array of struct mk_sched_worker type, - * each worker thread belongs to a scheduler node, on this function we - * allocate a scheduler node per number of workers defined. - */ -int mk_sched_init(struct mk_server *server) -{ - int size; - struct mk_sched_ctx *ctx; - - ctx = mk_mem_alloc_z(sizeof(struct mk_sched_ctx)); - if (!ctx) { - mk_libc_error("malloc"); - return -1; - } - - size = (sizeof(struct mk_sched_worker) * server->workers); - ctx->workers = mk_mem_alloc(size); - if (!ctx->workers) { - mk_libc_error("malloc"); - mk_mem_free(ctx); - return -1; - } - memset(ctx->workers, '\0', size); - - /* Initialize helpers */ - pthread_mutex_init(&server->pth_mutex, NULL); - pthread_cond_init(&server->pth_cond, NULL); - server->pth_init = MK_FALSE; - - /* Map context into server context */ - server->sched_ctx = ctx; - - /* The mk_thread_prepare call was replaced by mk_http_thread_initialize_tls - * which is called earlier. - */ - - return 0; -} - -int mk_sched_exit(struct mk_server *server) -{ - struct mk_sched_ctx *ctx; - - ctx = server->sched_ctx; - mk_sched_worker_cb_free(server); - mk_mem_free(ctx->workers); - mk_mem_free(ctx); - - return 0; -} - -void mk_sched_set_request_list(struct rb_root *list) -{ - MK_TLS_SET(mk_tls_sched_cs, list); -} - -int mk_sched_remove_client(struct mk_sched_conn *conn, - struct mk_sched_worker *sched, - struct mk_server *server) -{ - struct mk_event *event; - - /* - * Close socket and change status: we must invoke mk_epoll_del() - * because when the socket is closed is cleaned from the queue by - * the Kernel at its leisure, and we may get false events if we rely - * on that. - */ - event = &conn->event; - MK_TRACE("[FD %i] Scheduler remove", event->fd); - - mk_event_del(sched->loop, event); - - /* Invoke plugins in stage 50 */ - mk_plugin_stage_run_50(event->fd, server); - - sched->closed_connections++; - - /* Unlink from the red-black tree */ - //rb_erase(&conn->_rb_head, &sched->rb_queue); - mk_sched_conn_timeout_del(conn); - - /* Close at network layer level */ - conn->net->close(conn->net->plugin, event->fd); - - /* Release and return */ - mk_channel_clean(&conn->channel); - mk_sched_event_free(&conn->event); - conn->status = MK_SCHED_CONN_CLOSED; - - MK_LT_SCHED(remote_fd, "DELETE_CLIENT"); - return 0; -} - -/* FIXME: nobody is using this function, check back later */ -struct mk_sched_conn *mk_sched_get_connection(struct mk_sched_worker *sched, - int remote_fd) -{ - (void) sched; - (void) remote_fd; - return NULL; -} - -/* - * For a given connection number, remove all resources associated: it can be - * used on any context such as: timeout, I/O errors, request finished, - * exceptions, etc. - */ -int mk_sched_drop_connection(struct mk_sched_conn *conn, - struct mk_sched_worker *sched, - struct mk_server *server) -{ - mk_sched_threads_destroy_conn(sched, conn); - return mk_sched_remove_client(conn, sched, server); -} - -int mk_sched_check_timeouts(struct mk_sched_worker *sched, - struct mk_server *server) -{ - int client_timeout; - struct mk_sched_conn *conn; - struct mk_list *head; - struct mk_list *temp; - - /* PENDING CONN TIMEOUT */ - mk_list_foreach_safe(head, temp, &sched->timeout_queue) { - conn = mk_list_entry(head, struct mk_sched_conn, timeout_head); - if (conn->event.type & MK_EVENT_IDLE) { - continue; - } - - client_timeout = conn->arrive_time + server->timeout; - - /* Check timeout */ - if (client_timeout <= server->clock_context->log_current_utime) { - MK_TRACE("Scheduler, closing fd %i due TIMEOUT", - conn->event.fd); - MK_LT_SCHED(conn->event.fd, "TIMEOUT_CONN_PENDING"); - conn->protocol->cb_close(conn, sched, MK_SCHED_CONN_TIMEOUT, - server); - mk_sched_drop_connection(conn, sched, server); - } - } - - return 0; -} - -static int sched_thread_cleanup(struct mk_sched_worker *sched, - struct mk_list *list) -{ - int c = 0; - struct mk_list *tmp; - struct mk_list *head; - struct mk_http_thread *mth; - (void) sched; - - mk_list_foreach_safe(head, tmp, list) { - mth = mk_list_entry(head, struct mk_http_thread, _head); - mk_http_thread_destroy(mth); - c++; - } - - return c; - -} - -int mk_sched_threads_purge(struct mk_sched_worker *sched) -{ - int c = 0; - - c = sched_thread_cleanup(sched, &sched->threads_purge); - return c; -} - -int mk_sched_threads_destroy_all(struct mk_sched_worker *sched) -{ - int c = 0; - - c = sched_thread_cleanup(sched, &sched->threads_purge); - c += sched_thread_cleanup(sched, &sched->threads); - - return c; -} - -/* - * Destroy the thread contexts associated to the particular - * connection. - * - * Return the number of contexts destroyed. - */ -int mk_sched_threads_destroy_conn(struct mk_sched_worker *sched, - struct mk_sched_conn *conn) -{ - int c = 0; - struct mk_list *tmp; - struct mk_list *head; - struct mk_http_thread *mth; - (void) sched; - - mk_list_foreach_safe(head, tmp, &sched->threads) { - mth = mk_list_entry(head, struct mk_http_thread, _head); - if (mth->session->conn == conn) { - mk_http_thread_destroy(mth); - c++; - } - } - return c; -} - -/* - * Scheduler events handler: lookup for event handler and invoke - * proper callbacks. - */ -int mk_sched_event_read(struct mk_sched_conn *conn, - struct mk_sched_worker *sched, - struct mk_server *server) -{ - int ret = 0; - -#ifdef MK_HAVE_TRACE - MK_TRACE("[FD %i] Connection Handler / read", conn->event.fd); -#endif - - /* - * When the event loop notify that there is some readable information - * from the socket, we need to invoke the protocol handler associated - * to this connection and also pass as a reference the 'read()' function - * that handle 'read I/O' operations, e.g: - * - * - plain sockets through liana will use just read(2) - * - ssl though mbedtls should use mk_mbedtls_read(..) - */ - ret = conn->protocol->cb_read(conn, sched, server); - if (ret == -1) { - if (errno == EAGAIN) { - MK_TRACE("[FD %i] EAGAIN: need to read more data", conn->event.fd); - return 1; - } - return -1; - } - - return ret; -} - -int mk_sched_event_write(struct mk_sched_conn *conn, - struct mk_sched_worker *sched, - struct mk_server *server) -{ - int ret = -1; - size_t count; - struct mk_event *event; - - MK_TRACE("[FD %i] Connection Handler / write", conn->event.fd); - - ret = mk_channel_write(&conn->channel, &count); - if (ret == MK_CHANNEL_FLUSH || ret == MK_CHANNEL_BUSY) { - return 0; - } - else if (ret == MK_CHANNEL_DONE || ret == MK_CHANNEL_EMPTY) { - if (conn->protocol->cb_done) { - ret = conn->protocol->cb_done(conn, sched, server); - } - if (ret == -1) { - return -1; - } - else if (ret == 0) { - event = &conn->event; - mk_event_add(sched->loop, event->fd, - MK_EVENT_CONNECTION, - MK_EVENT_READ, - conn); - } - return 0; - } - else if (ret & MK_CHANNEL_ERROR) { - return -1; - } - - /* avoid to make gcc cry :_( */ - return -1; -} - -int mk_sched_event_close(struct mk_sched_conn *conn, - struct mk_sched_worker *sched, - int type, struct mk_server *server) -{ - MK_TRACE("[FD %i] Connection Handler, closed", conn->event.fd); - mk_event_del(sched->loop, &conn->event); - - if (type != MK_EP_SOCKET_DONE) { - conn->protocol->cb_close(conn, sched, type, server); - } - /* - * Remove the socket from the scheduler and make sure - * to disable all notifications. - */ - mk_sched_drop_connection(conn, sched, server); - return 0; -} - -void mk_sched_event_free(struct mk_event *event) -{ - struct mk_sched_worker *sched = mk_sched_get_thread_conf(); - - if ((event->type & MK_EVENT_IDLE) != 0) { - return; - } - - event->type |= MK_EVENT_IDLE; - mk_list_add(&event->_head, &sched->event_free_queue); -} - -/* Register a new callback function to invoke when a worker is created */ -int mk_sched_worker_cb_add(struct mk_server *server, - void (*cb_func) (void *), - void *data) -{ - struct mk_sched_worker_cb *wcb; - - wcb = mk_mem_alloc(sizeof(struct mk_sched_worker_cb)); - if (!wcb) { - return -1; - } - - wcb->cb_func = cb_func; - wcb->data = data; - mk_list_add(&wcb->_head, &server->sched_worker_callbacks); - return 0; -} - -void mk_sched_worker_cb_free(struct mk_server *server) -{ - struct mk_list *tmp; - struct mk_list *head; - struct mk_sched_worker_cb *wcb; - - mk_list_foreach_safe(head, tmp, &server->sched_worker_callbacks) { - wcb = mk_list_entry(head, struct mk_sched_worker_cb, _head); - mk_list_del(&wcb->_head); - mk_mem_free(wcb); - } -} - -int mk_sched_send_signal(struct mk_sched_worker *worker, uint64_t val) -{ - ssize_t n; - - /* When using libevent _mk_event_channel_create creates a unix socket - * instead of a pipe and windows doesn't us calling read / write on a - * socket instead of recv / send - */ - -#ifdef _WIN32 - n = send(worker->signal_channel_w, &val, sizeof(uint64_t), 0); -#else - n = write(worker->signal_channel_w, &val, sizeof(uint64_t)); -#endif - - if (n < 0) { - mk_libc_error("write"); - - return 0; - } - - return 1; -} - -int mk_sched_broadcast_signal(struct mk_server *server, uint64_t val) -{ - int i; - int count = 0; - struct mk_sched_ctx *ctx; - struct mk_sched_worker *worker; - - ctx = server->sched_ctx; - for (i = 0; i < server->workers; i++) { - worker = &ctx->workers[i]; - - count += mk_sched_send_signal(worker, val); - } - - return count; -} - -/* - * Wait for all workers to finish: this function assumes that previously a - * MK_SCHED_SIGNAL_FREE_ALL was sent to the worker channels. - */ -int mk_sched_workers_join(struct mk_server *server) -{ - int i; - int count = 0; - struct mk_sched_ctx *ctx; - struct mk_sched_worker *worker; - - ctx = server->sched_ctx; - for (i = 0; i < server->workers; i++) { - worker = &ctx->workers[i]; - pthread_join(worker->tid, NULL); - count++; - } - - return count; -} diff --git a/fluent-bit/lib/monkey/mk_server/mk_server.c b/fluent-bit/lib/monkey/mk_server/mk_server.c deleted file mode 100644 index a84ef448..00000000 --- a/fluent-bit/lib/monkey/mk_server/mk_server.c +++ /dev/null @@ -1,679 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* Monkey HTTP Server - * ================== - * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <monkey/mk_info.h> -#include <monkey/monkey.h> -#include <monkey/mk_config.h> -#include <monkey/mk_scheduler.h> -#include <monkey/mk_plugin.h> -#include <monkey/mk_utils.h> -#include <monkey/mk_server.h> -#include <monkey/mk_server_tls.h> -#include <monkey/mk_scheduler.h> -#include <monkey/mk_core.h> -#include <monkey/mk_fifo.h> -#include <monkey/mk_http_thread.h> - -#ifdef _WIN32 -#include <winsock2.h> -#else -#include <sys/socket.h> -#include <netinet/in.h> -#endif - -#ifndef _WIN32 -#include <sys/time.h> -#include <sys/resource.h> -#endif - -pthread_key_t mk_server_fifo_key; - -static int mk_server_lib_notify_event_loop_break(struct mk_sched_worker *sched); - -/* Return the number of clients that can be attended */ -unsigned int mk_server_capacity(struct mk_server *server) -{ - int ret; - int cur; - -#ifndef _WIN32 - struct rlimit lim; - - /* Limit by system */ - getrlimit(RLIMIT_NOFILE, &lim); - cur = lim.rlim_cur; - - if (server->fd_limit > cur) { - lim.rlim_cur = server->fd_limit; - lim.rlim_max = server->fd_limit; - - ret = setrlimit(RLIMIT_NOFILE, &lim); - if (ret == -1) { - mk_warn("Could not increase FDLimit to %i.", server->fd_limit); - } - else { - cur = server->fd_limit; - } - } - else if (server->fd_limit > 0) { - cur = server->fd_limit; - } - -#else - ret = 0; - cur = INT_MAX; - - /* This is not the right way to plug this, according to raymond chen the only limit - * to fd count is free memory in their winsock provider and there are no other limits - * that I know of but I should still look for a more elegant solution. (even if it - * was just ignoring the server_capacity limit in scheduler.c: _next_target) - */ -#endif - - return cur; -} - -static inline -struct mk_sched_conn *mk_server_listen_handler(struct mk_sched_worker *sched, - void *data, - struct mk_server *server) -{ - int ret; - int client_fd = -1; - struct mk_sched_conn *conn; - struct mk_server_listen *listener = data; - - client_fd = mk_socket_accept(listener->server_fd); - if (mk_unlikely(client_fd == -1)) { - MK_TRACE("[server] Accept connection failed: %s", strerror(errno)); - goto error; - } - - conn = mk_sched_add_connection(client_fd, listener, sched, server); - if (mk_unlikely(!conn)) { - goto error; - } - - ret = mk_event_add(sched->loop, client_fd, - MK_EVENT_CONNECTION, MK_EVENT_READ, conn); - if (mk_unlikely(ret != 0)) { - mk_err("[server] Error registering file descriptor: %s", - strerror(errno)); - goto error; - } - - sched->accepted_connections++; - MK_TRACE("[server] New connection arrived: FD %i", client_fd); - return conn; - -error: - if (client_fd != -1) { - listener->network->network->close(listener->network, client_fd); - } - - return NULL; -} - -void mk_server_listen_free() -{ - struct mk_list *list; - struct mk_list *tmp; - struct mk_list *head; - struct mk_server_listen *listener; - - list = MK_TLS_GET(mk_tls_server_listen); - mk_list_foreach_safe(head, tmp, list) { - listener = mk_list_entry(head, struct mk_server_listen, _head); - mk_list_del(&listener->_head); - mk_mem_free(listener); - } -} - -void mk_server_listen_exit(struct mk_list *list) -{ - struct mk_list *tmp; - struct mk_list *head; - struct mk_server_listen *listen; - - if (!list) { - return; - } - - mk_list_foreach_safe(head, tmp, list) { - listen = mk_list_entry(head, struct mk_server_listen, _head); - mk_event_closesocket(listen->server_fd); - mk_list_del(&listen->_head); - mk_mem_free(listen); - } - - mk_mem_free(list); -} - -struct mk_list *mk_server_listen_init(struct mk_server *server) -{ - int server_fd; - int reuse_port = MK_FALSE; - struct mk_list *head; - struct mk_list *listeners; - struct mk_event *event; - struct mk_server_listen *listener; - struct mk_sched_handler *protocol; - struct mk_plugin *plugin; - struct mk_config_listener *listen; - - if (!server) { - goto error; - } - - listeners = mk_mem_alloc(sizeof(struct mk_list)); - mk_list_init(listeners); - - if (server->scheduler_mode == MK_SCHEDULER_REUSEPORT) { - reuse_port = MK_TRUE; - } - - mk_list_foreach(head, &server->listeners) { - listen = mk_list_entry(head, struct mk_config_listener, _head); - - server_fd = mk_socket_server(listen->port, - listen->address, - reuse_port, - server); - if (server_fd >= 0) { - if (mk_socket_set_tcp_defer_accept(server_fd) != 0) { -#if defined (__linux__) - mk_warn("[server] Could not set TCP_DEFER_ACCEPT"); -#endif - } - - listener = mk_mem_alloc_z(sizeof(struct mk_server_listen)); - - /* configure the internal event_state */ - event = &listener->event; - event->fd = server_fd; - event->type = MK_EVENT_LISTENER; - event->mask = MK_EVENT_EMPTY; - event->status = MK_EVENT_NONE; - - /* continue with listener setup and linking */ - listener->server_fd = server_fd; - listener->listen = listen; - - if (listen->flags & MK_CAP_HTTP) { - protocol = mk_sched_handler_cap(MK_CAP_HTTP); - if (!protocol) { - mk_err("HTTP protocol not supported"); - exit(EXIT_FAILURE); - } - listener->protocol = protocol; - } - -#ifdef MK_HAVE_HTTP2 - if (listen->flags & MK_CAP_HTTP2) { - protocol = mk_sched_handler_cap(MK_CAP_HTTP2); - if (!protocol) { - mk_err("HTTP2 protocol not supported"); - exit(EXIT_FAILURE); - } - listener->protocol = protocol; - } -#endif - listener->network = mk_plugin_cap(MK_CAP_SOCK_PLAIN, server); - - if (listen->flags & MK_CAP_SOCK_TLS) { - plugin = mk_plugin_cap(MK_CAP_SOCK_TLS, server); - if (!plugin) { - mk_err("SSL/TLS not supported"); - exit(EXIT_FAILURE); - } - listener->network = plugin; - } - - mk_list_add(&listener->_head, listeners); - } - else { - mk_err("[server] Failed to bind server socket to %s:%s.", - listen->address, - listen->port); - return NULL; - } - } - - if (reuse_port == MK_TRUE) { - MK_TLS_SET(mk_tls_server_listen, listeners); - } - - return listeners; - -error: - return NULL; -} - -/* Here we launch the worker threads to attend clients */ -void mk_server_launch_workers(struct mk_server *server) -{ - int i; - pthread_t skip; - - /* Launch workers */ - for (i = 0; i < server->workers; i++) { - /* Spawn the thread */ - mk_sched_launch_thread(server, &skip); - } -} - -/* - * When using the FIFO interface, this function get's the FIFO worker - * context and register the pipe file descriptor into the main event - * loop. - * - * note: this function is invoked by each worker thread. - */ -static int mk_server_fifo_worker_setup(struct mk_event_loop *evl) -{ - int ret; - struct mk_fifo_worker *fw; - - fw = pthread_getspecific(mk_server_fifo_key); - if (!fw) { - return -1; - } - - ret = mk_event_add(evl, fw->channel[0], - MK_EVENT_FIFO, MK_EVENT_READ, - fw); - if (ret != 0) { - mk_err("[server] Error registering fifo worker channel: %s", - strerror(errno)); - return -1; - } - - return 0; -} - -/* - * The loop_balancer() runs in the main process context and is considered - * the old-fashion way to handle connections. It have an event queue waiting - * for connections, once one arrives, it decides which worker (thread) may - * handle it registering the accept(2)ed file descriptor on the worker - * event monitored queue. - */ -void mk_server_loop_balancer(struct mk_server *server) -{ - size_t bytes; - uint64_t val; - int operation_flag; - struct mk_list *head; - struct mk_list *listeners; - struct mk_server_listen *listener; - struct mk_event *event; - struct mk_event_loop *evl; - struct mk_sched_worker *sched; - struct mk_event management_event; - - /* Init the listeners */ - listeners = mk_server_listen_init(server); - if (!listeners) { - mk_err("Failed to initialize listen sockets."); - return; - } - - /* Create an event loop context */ - evl = mk_event_loop_create(MK_EVENT_QUEUE_SIZE); - if (!evl) { - mk_err("Could not initialize event loop"); - exit(EXIT_FAILURE); - } - - /* Register the listeners */ - mk_list_foreach(head, listeners) { - listener = mk_list_entry(head, struct mk_server_listen, _head); - mk_event_add(evl, listener->server_fd, - MK_EVENT_LISTENER, MK_EVENT_READ, - listener); - } - - memset(&management_event, 0, sizeof(struct mk_event)); - - mk_event_add(evl, - server->lib_ch_manager[0], - MK_EVENT_NOTIFICATION, - MK_EVENT_READ, - &management_event); - - operation_flag = MK_TRUE; - while (operation_flag) { - mk_event_wait(evl); - mk_event_foreach(event, evl) { - if (event->mask & MK_EVENT_READ) { - /* This signal is sent by mk_stop and both this and - * mk_lib_worker are expecting it. - */ - if (server->lib_ch_manager[0] == event->fd) { -#ifdef _WIN32 - bytes = recv(event->fd, &val, sizeof(uint64_t), MSG_WAITALL); -#else - bytes = read(event->fd, &val, sizeof(uint64_t)); -#endif - - if (bytes <= 0) { - return; - } - - if (val == MK_SERVER_SIGNAL_STOP) { - operation_flag = MK_FALSE; - - break; - } - - continue; - } - - /* - * Accept connection: determinate which thread may work on this - * new connection. - */ - sched = mk_sched_next_target(server); - if (sched != NULL) { - mk_server_listen_handler(sched, event, server); - - mk_server_lib_notify_event_loop_break(sched); - -#ifdef MK_HAVE_TRACE - int i; - struct mk_sched_ctx *ctx = server->sched_ctx; - - for (i = 0; i < server->workers; i++) { - MK_TRACE("Worker Status"); - MK_TRACE(" WID %i / conx = %llu", - ctx->workers[i].idx, - ctx->workers[i].accepted_connections - - ctx->workers[i].closed_connections); - } -#endif - } - else { - mk_warn("[server] Over capacity."); - } - } - else if (event->mask & MK_EVENT_CLOSE) { - mk_err("[server] Error on socket %d: %s", - event->fd, strerror(errno)); - } - } - } - mk_event_loop_destroy(evl); - mk_server_listen_exit(listeners); -} - -/* - * This function is called when the scheduler is running in the REUSEPORT - * mode. That means that each worker is listening on shared TCP ports. - * - * When using shared TCP ports the Kernel decides to which worker the - * connection will be assigned. - */ -void mk_server_worker_loop(struct mk_server *server) -{ - int ret = -1; - int timeout_fd; - uint64_t val; - struct mk_event *event; - struct mk_event_loop *evl; - struct mk_list *list; - struct mk_list *head; - struct mk_sched_conn *conn; - struct mk_sched_worker *sched; - struct mk_server_listen *listener; - struct mk_server_timeout *server_timeout; - - /* Get thread conf */ - sched = mk_sched_get_thread_conf(); - evl = sched->loop; - - /* - * The worker will NOT process any connection until the master - * process through mk_server_loop() send us the green light - * signal MK_SERVER_SIGNAL_START. - */ - mk_event_wait(evl); - mk_event_foreach(event, evl) { - if ((event->mask & MK_EVENT_READ) && - event->type == MK_EVENT_NOTIFICATION) { - if (event->fd == sched->signal_channel_r) { - /* When using libevent _mk_event_channel_create creates a unix socket - * instead of a pipe and windows doesn't us calling read / write on a - * socket instead of recv / send - */ -#ifdef _WIN32 - ret = recv(event->fd, &val, sizeof(val), MSG_WAITALL); -#else - ret = read(event->fd, &val, sizeof(val)); -#endif - if (ret < 0) { - mk_libc_error("read"); - continue; - } - if (val == MK_SERVER_SIGNAL_START) { - MK_TRACE("Worker %i started (SIGNAL_START)", sched->idx); - break; - } - } - } - } - - if (server->scheduler_mode == MK_SCHEDULER_REUSEPORT) { - /* Register listeners */ - list = MK_TLS_GET(mk_tls_server_listen); - mk_list_foreach(head, list) { - listener = mk_list_entry(head, struct mk_server_listen, _head); - mk_event_add(sched->loop, listener->server_fd, - MK_EVENT_LISTENER, MK_EVENT_READ, - listener); - } - } - - /* - * If running in library mode, register the FIFO pipe file descriptors - * into the main event loop. - */ - if (server->lib_mode == MK_TRUE) { - mk_server_fifo_worker_setup(evl); - } - - /* create a new timeout file descriptor */ - server_timeout = mk_mem_alloc_z(sizeof(struct mk_server_timeout)); - MK_TLS_SET(mk_tls_server_timeout, server_timeout); - timeout_fd = mk_event_timeout_create(evl, server->timeout, 0, server_timeout); - - while (1) { - mk_event_wait(evl); - mk_event_foreach(event, evl) { - ret = 0; - if (event->type & MK_EVENT_IDLE) { - continue; - } - - if (event->type == MK_EVENT_CONNECTION) { - conn = (struct mk_sched_conn *) event; - - if (event->mask & MK_EVENT_WRITE) { - MK_TRACE("[FD %i] Event WRITE", event->fd); - ret = mk_sched_event_write(conn, sched, server); - } - - if (event->mask & MK_EVENT_READ) { - MK_TRACE("[FD %i] Event READ", event->fd); - ret = mk_sched_event_read(conn, sched, server); - } - - - if (event->mask & MK_EVENT_CLOSE && ret != -1) { - MK_TRACE("[FD %i] Event CLOSE", event->fd); - ret = -1; - } - - if (ret < 0 && conn->status != MK_SCHED_CONN_CLOSED) { - MK_TRACE("[FD %i] Event FORCE CLOSE | ret = %i", - event->fd, ret); - mk_sched_event_close(conn, sched, MK_EP_SOCKET_CLOSED, - server); - } - } - else if (event->type == MK_EVENT_LISTENER) { - /* - * A new connection have been accepted..or failed, despite - * the result, we let the loop continue processing the other - * events triggered. - */ - conn = mk_server_listen_handler(sched, event, server); - if (conn) { - //conn->event.mask = MK_EVENT_READ - //goto speed; - } - continue; - } - else if (event->type == MK_EVENT_CUSTOM) { - /* - * We got an event associated to a custom interface, that - * means a plugin registered some file descriptor on this - * event loop and an event was triggered. We pass the control - * to the defined event handler. - */ - event->handler(event); - } - else if (event->type == MK_EVENT_NOTIFICATION) { -#ifdef _WIN32 - ret = recv(event->fd, &val, sizeof(val), MSG_WAITALL); -#else - ret = read(event->fd, &val, sizeof(val)); -#endif - if (ret < 0) { - mk_libc_error("read"); - continue; - } - - if (event->fd == sched->signal_channel_r) { - if (val == MK_SCHED_SIGNAL_DEADBEEF) { - //FIXME:mk_sched_sync_counters(); - continue; - } - else if (val == MK_SCHED_SIGNAL_FREE_ALL) { - if (timeout_fd > 0) { - mk_event_timeout_destroy(evl, server_timeout); - } - mk_mem_free(MK_TLS_GET(mk_tls_server_timeout)); - mk_server_listen_exit(sched->listeners); - mk_event_loop_destroy(evl); - mk_sched_worker_free(server); - return; - } - else if (val == MK_SCHED_SIGNAL_EVENT_LOOP_BREAK) { - /* NOTE: This is just a notification that's sent to break out - * of the libevent loop in windows after accepting a new - * client - */ - MK_TRACE("New client accepted, awesome!"); - } - } - else if (event->fd == timeout_fd) { - mk_sched_check_timeouts(sched, server); - } - continue; - } - else if (event->type == MK_EVENT_THREAD) { - mk_http_thread_event(event); - continue; - } - else if (event->type == MK_EVENT_FIFO) { - mk_fifo_worker_read(event); - continue; - } - } - mk_sched_threads_purge(sched); - mk_sched_event_free_all(sched); - } -} - -static int mk_server_lib_notify_event_loop_break(struct mk_sched_worker *sched) -{ - uint64_t val; - - /* Check the channel is valid (enabled by library mode) */ - if (sched->signal_channel_w <= 0) { - return -1; - } - - val = MK_SCHED_SIGNAL_EVENT_LOOP_BREAK; - -#ifdef _WIN32 - return send(sched->signal_channel_w, &val, sizeof(uint64_t), 0); -#else - return write(sched->signal_channel_w, &val, sizeof(uint64_t)); -#endif -} - -static int mk_server_lib_notify_started(struct mk_server *server) -{ - uint64_t val; - - /* Check the channel is valid (enabled by library mode) */ - if (server->lib_ch_start[1] <= 0) { - return -1; - } - - val = MK_SERVER_SIGNAL_START; - -#ifdef _WIN32 - return send(server->lib_ch_start[1], &val, sizeof(uint64_t), 0); -#else - return write(server->lib_ch_start[1], &val, sizeof(uint64_t)); -#endif -} - -void mk_server_loop(struct mk_server *server) -{ - uint64_t val; - - /* Rename worker */ - mk_utils_worker_rename("monkey: server"); - - if (server->lib_mode == MK_FALSE) { - mk_info("HTTP Server started"); - } - - /* Wake up workers */ - val = MK_SERVER_SIGNAL_START; - mk_sched_broadcast_signal(server, val); - - /* Signal lib caller (if any) */ - mk_server_lib_notify_started(server); - - /* - * When using REUSEPORT mode on the Scheduler, we need to signal - * them so they can start processing connections. - */ - if (server->scheduler_mode == MK_SCHEDULER_REUSEPORT) { - /* do thing :) */ - } - else { - /* FIXME!: this old mode needs some checks on library mode */ - mk_server_loop_balancer(server); - } -} diff --git a/fluent-bit/lib/monkey/mk_server/mk_socket.c b/fluent-bit/lib/monkey/mk_server/mk_socket.c deleted file mode 100644 index 0277ab1c..00000000 --- a/fluent-bit/lib/monkey/mk_server/mk_socket.c +++ /dev/null @@ -1,402 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* Monkey HTTP Server - * ================== - * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _GNU_SOURCE - -#ifndef SOL_TCP -#define SOL_TCP IPPROTO_TCP -#endif - -#include <monkey/monkey.h> -#include <monkey/mk_info.h> -#include <monkey/mk_socket.h> -#include <monkey/mk_kernel.h> -#include <monkey/mk_net.h> -#include <monkey/mk_core.h> -#include <monkey/mk_utils.h> -#include <monkey/mk_plugin.h> - -#include <time.h> - -/* - * Example from: - * http://www.baus.net/on-tcp_cork - */ -int mk_socket_set_cork_flag(int fd, int state) -{ - MK_TRACE("Socket, set Cork Flag FD %i to %s", fd, (state ? "ON" : "OFF")); - -#if defined (TCP_CORK) - return setsockopt(fd, SOL_TCP, TCP_CORK, &state, sizeof(state)); -#elif defined (TCP_NOPUSH) - return setsockopt(fd, SOL_SOCKET, TCP_NOPUSH, &state, sizeof(state)); -#endif - - return 0; -} - -int mk_socket_set_nonblocking(int sockfd) -{ - - MK_TRACE("Socket, set FD %i to non-blocking", sockfd); - -#ifdef _WIN32 - u_long flags; - - flags = 0; - if (SOCKET_ERROR == ioctlsocket(sockfd, FIONBIO, &flags)) { - mk_err("Can't set to non-blocking mode socket %i", sockfd); - return -1; - } -#else - if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) | O_NONBLOCK) == -1) { - mk_err("Can't set to non-blocking mode socket %i", sockfd); - return -1; - } - fcntl(sockfd, F_SETFD, FD_CLOEXEC); -#endif - - return 0; -} - -/* - * Enable the TCP_FASTOPEN feature for server side implemented in - * Linux Kernel >= 3.7, for more details read here: - * - * TCP Fast Open: expediting web services: http://lwn.net/Articles/508865/ - */ -int mk_socket_set_tcp_fastopen(int sockfd) -{ -#if defined (__linux__) - int qlen = 5; - return setsockopt(sockfd, SOL_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen)); -#endif - - (void) sockfd; - return -1; -} - -int mk_socket_set_tcp_nodelay(int sockfd) -{ - int on = 1; - - return setsockopt(sockfd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)); -} - -int mk_socket_set_tcp_defer_accept(int sockfd) -{ -#if defined (__linux__) - int timeout = 0; - - return setsockopt(sockfd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, sizeof(int)); -#else - (void) sockfd; - return -1; -#endif -} - -int mk_socket_set_tcp_reuseport(int sockfd) -{ - int on = 1; - return setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)); -} - -int mk_socket_create(int domain, int type, int protocol) -{ - int fd; - -#ifdef SOCK_CLOEXEC - fd = socket(domain, type | SOCK_CLOEXEC, protocol); -#else - fd = socket(domain, type, protocol); - -#ifndef _WIN32 - fcntl(fd, F_SETFD, FD_CLOEXEC); -#endif -#endif - - if (fd == -1) { - mk_libc_error("socket"); - return -1; - } - - return fd; -} - -int mk_socket_open(char *path, int async) -{ - int ret; - int socket_fd; - struct sockaddr_un address; - - socket_fd = mk_socket_create(PF_UNIX, SOCK_STREAM, 0); - if (socket_fd == -1) { - return -1; - } - - memset(&address, '\0', sizeof(struct sockaddr_un)); - address.sun_family = AF_UNIX; - snprintf(address.sun_path, sizeof(address.sun_path), "%s", path); - - if (async == MK_TRUE) { - mk_socket_set_nonblocking(socket_fd); - } - - ret = connect(socket_fd, (struct sockaddr *) &address, - sizeof(struct sockaddr_un)); - if (ret == -1) { - if (errno == EINPROGRESS) { - return socket_fd; - } - else { -#ifdef MK_HAVE_TRACE - mk_libc_error("connect"); -#endif - close(socket_fd); - return -1; - } - } - - return socket_fd; -} - - -int mk_socket_connect(char *host, int port, int async) -{ - int ret; - int socket_fd = -1; - char *port_str = 0; - unsigned long len; - struct addrinfo hints; - struct addrinfo *res, *rp; - - memset(&hints, 0, sizeof hints); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - - mk_string_build(&port_str, &len, "%d", port); - - ret = getaddrinfo(host, port_str, &hints, &res); - mk_mem_free(port_str); - if(ret != 0) { - mk_err("Can't get addr info: %s", gai_strerror(ret)); - return -1; - } - for (rp = res; rp != NULL; rp = rp->ai_next) { - socket_fd = mk_socket_create(rp->ai_family, - rp->ai_socktype, rp->ai_protocol); - - if (socket_fd == -1) { - mk_warn("Error creating client socket, retrying"); - continue; - } - - if (async == MK_TRUE) { - mk_socket_set_nonblocking(socket_fd); - } - - ret = connect(socket_fd, - (struct sockaddr *) rp->ai_addr, rp->ai_addrlen); - if (ret == -1) { - if (errno == EINPROGRESS) { - break; - } - else { - printf("%s", strerror(errno)); - perror("connect"); - exit(1); - close(socket_fd); - continue; - } - } - break; - } - freeaddrinfo(res); - - if (rp == NULL) - return -1; - - return socket_fd; -} - -int mk_socket_reset(int socket) -{ - int status = 1; - - if (setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &status, sizeof(int)) == -1) { - mk_libc_error("socket"); - exit(EXIT_FAILURE); - } - - return 0; -} - -int mk_socket_bind(int socket_fd, const struct sockaddr *addr, - socklen_t addrlen, int backlog, struct mk_server *server) -{ - int ret; - - ret = bind(socket_fd, addr, addrlen); - if( ret == -1 ) { - mk_warn("Error binding socket"); - return ret; - } - - /* - * Enable TCP_FASTOPEN by default: if for some reason this call fail, - * it will not affect the behavior of the server, in order to succeed, - * Monkey must be running in a Linux system with Kernel >= 3.7 and the - * tcp_fastopen flag enabled here: - * - * # cat /proc/sys/net/ipv4/tcp_fastopen - * - * To enable this feature just do: - * - * # echo 1 > /proc/sys/net/ipv4/tcp_fastopen - */ - if (server->kernel_features & MK_KERNEL_TCP_FASTOPEN) { - ret = mk_socket_set_tcp_fastopen(socket_fd); - if (ret == -1) { - mk_warn("Could not set TCP_FASTOPEN"); - } - } - - ret = listen(socket_fd, backlog); - if(ret == -1 ) { - return -1; - } - - return ret; -} - -/* Just IPv4 for now... */ -int mk_socket_server(char *port, char *listen_addr, - int reuse_port, struct mk_server *server) -{ - int ret; - int socket_fd = -1; - struct addrinfo hints; - struct addrinfo *res, *rp; - - memset(&hints, 0, sizeof hints); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_PASSIVE; - - mk_net_init(); - - ret = getaddrinfo(listen_addr, port, &hints, &res); - if(ret != 0) { - mk_err("Can't get addr info: %s", gai_strerror(ret)); - return -1; - } - - for (rp = res; rp != NULL; rp = rp->ai_next) { - socket_fd = mk_socket_create(rp->ai_family, - rp->ai_socktype, rp->ai_protocol); - if (socket_fd == -1) { - mk_warn("Error creating server socket, retrying"); - continue; - } - - ret = mk_socket_set_tcp_nodelay(socket_fd); - if (ret == -1) { - mk_warn("Could not set TCP_NODELAY"); - } - - mk_socket_reset(socket_fd); - - /* Check if reuse port can be enabled on this socket */ - if (reuse_port == MK_TRUE && - (server->kernel_features & MK_KERNEL_SO_REUSEPORT)) { - ret = mk_socket_set_tcp_reuseport(socket_fd); - if (ret == -1) { - mk_warn("Could not use SO_REUSEPORT, using fair balancing mode"); - server->scheduler_mode = MK_SCHEDULER_FAIR_BALANCING; - } - } - - ret = mk_socket_bind(socket_fd, rp->ai_addr, rp->ai_addrlen, - MK_SOMAXCONN, server); - if(ret == -1) { - mk_err("Cannot listen on %s:%s", listen_addr, port); - freeaddrinfo(res); - return -1; - } - break; - } - freeaddrinfo(res); - - if (rp == NULL) - return -1; - - return socket_fd; -} - -int mk_socket_ip_str(int socket_fd, char **buf, int size, unsigned long *len) -{ - int ret; - struct sockaddr_storage addr; - socklen_t s_len = sizeof(addr); - - ret = getpeername(socket_fd, (struct sockaddr *) &addr, &s_len); - - if (mk_unlikely(ret == -1)) { - MK_TRACE("[FD %i] Can't get addr for this socket", socket_fd); - return -1; - } - - errno = 0; - - if(addr.ss_family == AF_INET) { - if((inet_ntop(AF_INET, &((struct sockaddr_in *)&addr)->sin_addr, - *buf, size)) == NULL) { - mk_warn("mk_socket_ip_str: Can't get the IP text form (%i)", errno); - return -1; - } - } - else if(addr.ss_family == AF_INET6) { - if((inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&addr)->sin6_addr, - *buf, size)) == NULL) { - mk_warn("mk_socket_ip_str: Can't get the IP text form (%i)", errno); - return -1; - } - } - - *len = strlen(*buf); - return 0; -} - -int mk_socket_accept(int server_fd) -{ - int remote_fd; - - struct sockaddr sock_addr; - socklen_t socket_size = sizeof(struct sockaddr); - -#ifdef MK_HAVE_ACCEPT4 - remote_fd = accept4(server_fd, &sock_addr, &socket_size, - SOCK_NONBLOCK | SOCK_CLOEXEC); -#else - remote_fd = accept(server_fd, &sock_addr, &socket_size); - mk_socket_set_nonblocking(remote_fd); -#endif - - return remote_fd; -} diff --git a/fluent-bit/lib/monkey/mk_server/mk_stream.c b/fluent-bit/lib/monkey/mk_server/mk_stream.c deleted file mode 100644 index df0f1b0b..00000000 --- a/fluent-bit/lib/monkey/mk_server/mk_stream.c +++ /dev/null @@ -1,338 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* Monkey HTTP Server - * ================== - * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <monkey/monkey.h> -#include <monkey/mk_stream.h> -#include <assert.h> - -/* Create a new channel */ -struct mk_channel *mk_channel_new(int type, int fd) -{ - struct mk_channel *channel; - - channel = mk_mem_alloc(sizeof(struct mk_channel)); - if (!channel) { - return NULL; - } - channel->type = type; - channel->fd = fd; - channel->status = MK_CHANNEL_OK; - mk_list_init(&channel->streams); - - return channel; -} - -int mk_channel_release(struct mk_channel *channel) -{ - mk_mem_free(channel); - return 0; -} - -static inline size_t channel_write_in_file(struct mk_channel *channel, - struct mk_stream_input *in) -{ - ssize_t bytes = 0; - - MK_TRACE("[CH %i] STREAM_FILE [fd=%i], bytes=%lu", - channel->fd, in->fd, in->bytes_total); - - /* Direct write */ - bytes = mk_sched_conn_sendfile(channel, - in->fd, - &in->bytes_offset, - in->bytes_total - ); - MK_TRACE("[CH=%d] [FD=%i] WRITE STREAM FILE: %lu bytes", - channel->fd, in->fd, bytes); - - return bytes; -} - -size_t mk_stream_size(struct mk_stream *stream) -{ - return (stream->bytes_total - stream->bytes_offset); -} - -/* - * It 'intent' to write a few streams over the channel and alter the - * channel notification side if required: READ -> WRITE. - */ -int mk_channel_flush(struct mk_channel *channel) -{ - int ret = 0; - size_t count = 0; - size_t total = 0; - uint32_t stop = (MK_CHANNEL_DONE | MK_CHANNEL_ERROR | MK_CHANNEL_EMPTY); - - do { - ret = mk_channel_write(channel, &count); - total += count; - -#ifdef MK_HAVE_TRACE - MK_TRACE("Channel flush: %d bytes", count); - if (ret & MK_CHANNEL_DONE) { - MK_TRACE("Channel was empty"); - } - if (ret & MK_CHANNEL_ERROR) { - MK_TRACE("Channel error"); - } - if (ret & MK_CHANNEL_EMPTY) { - MK_TRACE("Channel empty"); - } -#endif - } while (total <= 4096 && ((ret & stop) == 0)); - - if (ret == MK_CHANNEL_DONE) { - MK_TRACE("Channel done"); - return ret; - } - else if (ret & (MK_CHANNEL_FLUSH | MK_CHANNEL_BUSY)) { - MK_TRACE("Channel FLUSH | BUSY"); - if ((channel->event->mask & MK_EVENT_WRITE) == 0) { - mk_event_add(mk_sched_loop(), - channel->fd, - MK_EVENT_CONNECTION, - MK_EVENT_WRITE, - channel->event); - } - } - - return ret; -} - -int mk_stream_in_release(struct mk_stream_input *in) -{ - if (in->cb_finished) { - in->cb_finished(in); - } - - mk_stream_input_unlink(in); - if (in->dynamic == MK_TRUE) { - mk_mem_free(in); - } - - return 0; -} - -int mk_channel_stream_write(struct mk_stream *stream, size_t *count) -{ - ssize_t bytes = 0; - struct mk_iov *iov; - struct mk_list *tmp; - struct mk_list *head; - struct mk_channel *channel; - struct mk_stream_input *input; - - channel = stream->channel; - - /* Validate channel status */ - if (channel->status != MK_CHANNEL_OK) { - return -MK_CHANNEL_ERROR; - } - - /* Iterate inputs and process stream */ - mk_list_foreach_safe(head, tmp, &stream->inputs) { - input = mk_list_entry(head, struct mk_stream_input, _head); - if (input->type == MK_STREAM_FILE) { - bytes = channel_write_in_file(channel, input); - } - else if (input->type == MK_STREAM_IOV) { - iov = input->buffer; - if (!iov) { - return MK_CHANNEL_EMPTY; - } - - bytes = mk_sched_conn_writev(channel, iov); - - MK_TRACE("[CH %i] STREAM_IOV, wrote %d bytes", - channel->fd, bytes); - if (bytes > 0) { - /* Perform the adjustment on mk_iov */ - mk_iov_consume(iov, bytes); - } - } - else if (input->type == MK_STREAM_RAW) { - bytes = mk_sched_conn_write(channel, - input->buffer, input->bytes_total); - MK_TRACE("[CH %i] STREAM_RAW, bytes=%lu/%lu\n", - channel->fd, bytes, input->bytes_total); - } - - if (bytes > 0) { - *count = bytes; - mk_stream_input_consume(input, bytes); - - /* notification callback, optional */ - if (stream->cb_bytes_consumed) { - stream->cb_bytes_consumed(stream, bytes); - } - - if (input->cb_consumed) { - input->cb_consumed(input, bytes); - } - - if (input->bytes_total == 0) { - MK_TRACE("Input done, unlinking (channel=%p)", channel); - mk_stream_in_release(input); - } - MK_TRACE("[CH %i] CHANNEL_FLUSH", channel->fd); - } - else if (bytes < 0) { - mk_stream_in_release(input); - return -MK_CHANNEL_ERROR; - } - else if (bytes == 0) { - mk_stream_in_release(input); - return -MK_CHANNEL_ERROR; - } - } - - return bytes; -} - -/* It perform a direct stream I/O write through the network layer */ -int mk_channel_write(struct mk_channel *channel, size_t *count) -{ - ssize_t bytes = -1; - struct mk_iov *iov; - struct mk_stream *stream = NULL; - struct mk_stream_input *input; - - errno = 0; - - if (mk_list_is_empty(&channel->streams) == 0) { - MK_TRACE("[CH %i] CHANNEL_EMPTY", channel->fd); - return MK_CHANNEL_EMPTY; - } - - /* Get the input source */ - stream = mk_list_entry_first(&channel->streams, struct mk_stream, _head); - if (mk_list_is_empty(&stream->inputs) == 0) { - return MK_CHANNEL_EMPTY; - } - input = mk_list_entry_first(&stream->inputs, struct mk_stream_input, _head); - - /* - * Based on the Stream Input type we consume on that way, not all inputs - * requires to read from buffer, e.g: Static File, Pipes. - */ - if (channel->type == MK_CHANNEL_SOCKET) { - if (input->type == MK_STREAM_FILE) { - bytes = channel_write_in_file(channel, input); - } - else if (input->type == MK_STREAM_IOV) { - iov = input->buffer; - if (!iov) { - return MK_CHANNEL_EMPTY; - } - - bytes = mk_sched_conn_writev(channel, iov); - - MK_TRACE("[CH %i] STREAM_IOV, wrote %d bytes", - channel->fd, bytes); - if (bytes > 0) { - /* Perform the adjustment on mk_iov */ - mk_iov_consume(iov, bytes); - } - } - else if (input->type == MK_STREAM_RAW) { - bytes = mk_sched_conn_write(channel, - input->buffer, input->bytes_total); - MK_TRACE("[CH %i] STREAM_RAW, bytes=%lu/%lu", - channel->fd, bytes, input->bytes_total); - if (bytes > 0) { - /* DEPRECATED: consume_raw(input, bytes); */ - } - } - - if (bytes > 0) { - *count = bytes; - mk_stream_input_consume(input, bytes); - - /* notification callback, optional */ - if (stream->cb_bytes_consumed) { - stream->cb_bytes_consumed(stream, bytes); - } - - if (input->cb_consumed) { - input->cb_consumed(input, bytes); - } - - if (input->bytes_total == 0) { - MK_TRACE("Input done, unlinking (channel=%p)", channel); - mk_stream_in_release(input); - } - - if (mk_list_is_empty(&stream->inputs) == 0) { - /* Everytime the stream is empty, we notify the trigger the cb */ - if (stream->cb_finished) { - stream->cb_finished(stream); - } - - if (mk_channel_is_empty(channel) == 0) { - MK_TRACE("[CH %i] CHANNEL_DONE", channel->fd); - return MK_CHANNEL_DONE; - } - else { - MK_TRACE("[CH %i] CHANNEL_FLUSH", channel->fd); - return MK_CHANNEL_FLUSH; - } - } - - MK_TRACE("[CH %i] CHANNEL_FLUSH", channel->fd); - return MK_CHANNEL_FLUSH; - } - else if (bytes < 0) { - if (errno == EAGAIN) { - return MK_CHANNEL_BUSY; - } - - mk_stream_in_release(input); - return MK_CHANNEL_ERROR; - } - else if (bytes == 0) { - mk_stream_in_release(input); - return MK_CHANNEL_ERROR; - } - } - - return MK_CHANNEL_ERROR; -} - -/* Remove any dynamic memory associated */ -int mk_channel_clean(struct mk_channel *channel) -{ - struct mk_list *tmp; - struct mk_list *tmp_in; - struct mk_list *head; - struct mk_list *head_in; - struct mk_stream *stream; - struct mk_stream_input *in; - - mk_list_foreach_safe(head, tmp, &channel->streams) { - stream = mk_list_entry(head, struct mk_stream, _head); - mk_list_foreach_safe(head_in, tmp_in, &stream->inputs) { - in = mk_list_entry(head_in, struct mk_stream_input, _head); - mk_stream_in_release(in); - } - mk_stream_release(stream); - } - - return 0; -} diff --git a/fluent-bit/lib/monkey/mk_server/mk_user.c b/fluent-bit/lib/monkey/mk_server/mk_user.c deleted file mode 100644 index 7200ff08..00000000 --- a/fluent-bit/lib/monkey/mk_server/mk_user.c +++ /dev/null @@ -1,175 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* Monkey HTTP Server - * ================== - * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <monkey/monkey.h> -#include <monkey/mk_user.h> -#include <monkey/mk_http.h> -#include <monkey/mk_http_status.h> -#include <monkey/mk_core.h> -#include <monkey/mk_utils.h> -#include <monkey/mk_config.h> - -#ifndef _WIN32 -#include <pwd.h> -#include <sys/resource.h> -#include <sys/types.h> -#include <grp.h> - -int mk_user_init(struct mk_http_session *cs, struct mk_http_request *sr, - struct mk_server *server) -{ - int limit; - const int offset = 2; /* The user is defined after the '/~' string, so offset = 2 */ - const int user_len = 255; - char user[/*user_len*/ 255]; /* VC++ Doesn't allow for this to be a const int*/ - char *user_uri; - struct passwd *s_user; - - if (sr->uri_processed.len <= 2) { - return -1; - } - - limit = mk_string_char_search(sr->uri_processed.data + offset, '/', - sr->uri_processed.len); - - if (limit == -1) { - limit = (sr->uri_processed.len) - offset; - } - - if (limit + offset >= (user_len)) { - return -1; - } - - memcpy(user, sr->uri_processed.data + offset, limit); - user[limit] = '\0'; - - MK_TRACE("user: '%s'", user); - - /* Check system user */ - if ((s_user = getpwnam(user)) == NULL) { - mk_http_error(MK_CLIENT_NOT_FOUND, cs, sr, server); - return -1; - } - - if (sr->uri_processed.len > (unsigned int) (offset+limit)) { - user_uri = mk_mem_alloc(sr->uri_processed.len); - if (!user_uri) { - return -1; - } - - memcpy(user_uri, - sr->uri_processed.data + (offset + limit), - sr->uri_processed.len - offset - limit); - user_uri[sr->uri_processed.len - offset - limit] = '\0'; - - mk_string_build(&sr->real_path.data, &sr->real_path.len, - "%s/%s%s", - s_user->pw_dir, server->conf_user_pub, user_uri); - mk_mem_free(user_uri); - } - else { - mk_string_build(&sr->real_path.data, &sr->real_path.len, - "%s/%s", s_user->pw_dir, server->conf_user_pub); - } - - sr->user_home = MK_TRUE; - return 0; -} - -/* Change process user */ -int mk_user_set_uidgid(struct mk_server *server) -{ - struct passwd *usr; - - /* Launched by root ? */ - if (geteuid() == 0 && server->user) { - struct rlimit rl; - - if (getrlimit(RLIMIT_NOFILE, &rl)) { - mk_warn("cannot get resource limits"); - } - - /* Check if user exists */ - if ((usr = getpwnam(server->user)) == NULL) { - mk_err("Invalid user '%s'", server->user); - goto out; - } - - if (initgroups(server->user, usr->pw_gid) != 0) { - mk_err("Initgroups() failed"); - } - - /* Change process UID and GID */ - if (setegid(usr->pw_gid) == -1) { - mk_err("I cannot change the GID to %u", usr->pw_gid); - } - - if (seteuid(usr->pw_uid) == -1) { - mk_err("I cannot change the UID to %u", usr->pw_uid); - } - - server->is_seteuid = MK_TRUE; - } - - out: - /* Variables set for run checks on file permission */ - //FIXME - //EUID = geteuid(); - //EGID = getegid(); - - return 0; -} - -/* Return process to the original user */ -int mk_user_undo_uidgid(struct mk_server *server) -{ - if (server->is_seteuid == MK_TRUE) { - if (setegid(0) < 0) { - mk_err("Can't restore effective GID"); - } - if (seteuid(0) < 0) { - mk_err("Can't restore effective UID"); - } - } - return 0; -} - -#else -/* - None of these functionalities are going to be available in windows at the moment -*/ - -int mk_user_init(struct mk_http_session* cs, struct mk_http_request* sr, - struct mk_server* server) -{ - return -1; -} - -int mk_user_set_uidgid(struct mk_server* server) -{ - mk_err("Cannot impersonate users in windows"); - - return 0; -} - -int mk_user_undo_uidgid(struct mk_server* server) -{ - return 0; -} -#endif diff --git a/fluent-bit/lib/monkey/mk_server/mk_utils.c b/fluent-bit/lib/monkey/mk_server/mk_utils.c deleted file mode 100644 index 443c0ec3..00000000 --- a/fluent-bit/lib/monkey/mk_server/mk_utils.c +++ /dev/null @@ -1,589 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* Monkey HTTP Server - * ================== - * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -/* local headers */ -#include <monkey/monkey.h> -#include <monkey/mk_core.h> -#include <monkey/mk_utils.h> -#include <monkey/mk_config.h> -#include <monkey/mk_socket.h> -#include <monkey/mk_clock.h> -#include <monkey/mk_user.h> -#include <monkey/mk_cache.h> -#include <monkey/mk_tls.h> - -#include <assert.h> -#include <ctype.h> -#include <stdarg.h> -#include <time.h> -#include <inttypes.h> - -#ifdef _WIN32 -#include <winsock2.h> -#else -#include <sys/socket.h> -#endif - -/* stacktrace */ -#ifndef _WIN32 -#include <dlfcn.h> -#endif - -#ifdef MK_HAVE_BACKTRACE -#include <execinfo.h> -#endif - -#define MK_UTILS_GMT_DATEFORMAT "%a, %d %b %Y %H:%M:%S GMT" - -#ifdef _WIN32 -static struct tm* localtime_r(const time_t* timep, struct tm* result) -{ - localtime_s(result, timep); - - return result; -} - -static struct tm* gmtime_r(const time_t* timep, struct tm* result) -{ - gmtime_s(result, timep); - - return result; -} - -static time_t timegm(struct tm* timeptr) -{ - return _mkgmtime(timeptr); -} -#endif - -#ifdef _WIN32 -int mk_utils_get_system_core_count() -{ - SYSTEM_LOGICAL_PROCESSOR_INFORMATION *proc_info_buffer; - unsigned int result_entry_count; - unsigned int entry_index; - DWORD result_length; - int result_code; - int core_count; - - core_count = 1; - result_length = 0; - proc_info_buffer = NULL; - - result_code = GetLogicalProcessorInformation(proc_info_buffer, &result_length); - /* We're passing a null buffer, result_code has to be false */ - - if (ERROR_INSUFFICIENT_BUFFER == GetLastError()) { - result_entry_count = result_length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); - proc_info_buffer = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION *) _alloca(result_length); - - if(NULL != proc_info_buffer) { - result_code = GetLogicalProcessorInformation(proc_info_buffer, &result_length); - - if (0 != result_code) { - core_count = 0; - - for(entry_index = 0 ; entry_index < result_entry_count ; entry_index++) { - if(RelationProcessorCore == proc_info_buffer[entry_index].Relationship) { - core_count++; - } - } - } - } - - /* Athread stack allocation error is a pretty serious - * error so in that case we let someone else handle it by returning a - * sane default (1 core) - */ - } - - return core_count; -} - -int mk_utils_get_system_page_size() -{ - SYSTEM_INFO si; - - GetSystemInfo(&si); - - return si.dwPageSize; -} - -#else -int mk_utils_get_system_core_count() -{ - return sysconf(_SC_NPROCESSORS_ONLN); -} - -int mk_utils_get_system_page_size() -{ - return sysconf(_SC_PAGESIZE); -} - -#endif - - -/* Date helpers */ -static const char mk_date_wd[][6] = {"Sun, ", "Mon, ", "Tue, ", "Wed, ", "Thu, ", "Fri, ", "Sat, "}; -static const char mk_date_ym[][5] = {"Jan ", "Feb ", "Mar ", "Apr ", "May ", "Jun ", "Jul ", - "Aug ", "Sep ", "Oct ", "Nov ", "Dec "}; - -static int mk_utils_gmt_cache_get(char **data, time_t date) -{ - unsigned int i; - struct mk_gmt_cache *gcache = MK_TLS_GET(mk_tls_cache_gmtext); - - if (mk_unlikely(!gcache)) { - return MK_FALSE; - } - - for (i = 0; i < MK_GMT_CACHES; i++) { - if (date == gcache[i].time) { - memcpy(*data, gcache[i].text, 32); - gcache[i].hits++; - return MK_TRUE; - } - } - - return MK_FALSE; -} - -static void mk_utils_gmt_cache_add(char *data, time_t time) -{ - unsigned int i, min = 0; - struct mk_gmt_cache *gcache = MK_TLS_GET(mk_tls_cache_gmtext); - - for (i = 1; i < MK_GMT_CACHES; i++) { - if (gcache[i].hits < gcache[min].hits) - min = i; - } - - gcache[min].hits = 1; - gcache[min].time = time; - memcpy(gcache[min].text, data, 32); -} - -/* - *This function given a unix time, set in a mk_ptr_t - * the date in the RFC1123 format like: - * - * Wed, 23 Jun 2010 22:32:01 GMT - * - * it also adds a 'CRLF' at the end - */ -int mk_utils_utime2gmt(char **data, time_t date) -{ - const int size = 31; - unsigned short year, mday, hour, min, sec; - char *buf=0; - struct tm *gtm; - - if (date == 0) { - if ((date = time(NULL)) == -1) { - return -1; - } - } - else { - /* Maybe it's converted already? */ - if (mk_utils_gmt_cache_get(data, date) == MK_TRUE) { - return size; - } - } - - /* Convert unix time to struct tm */ - gtm = MK_TLS_GET(mk_tls_cache_gmtime); - - /* If this function was invoked from a non-thread context it should exit */ - mk_bug(!gtm); - gtm = gmtime_r(&date, gtm); - if (!gtm) { - return -1; - } - - /* struct tm -> tm_year counts number of years after 1900 */ - year = gtm->tm_year + 1900; - - /* Signed division is slow, by using unsigned we gain 25% speed */ - mday = gtm->tm_mday; - hour = gtm->tm_hour; - min = gtm->tm_min; - sec = gtm->tm_sec; - - /* Compose template */ - buf = *data; - - /* Week day */ - memcpy(buf, mk_date_wd[gtm->tm_wday], 5); - buf += 5; - - /* Day of the month */ - *buf++ = ('0' + (mday / 10)); - *buf++ = ('0' + (mday % 10)); - *buf++ = ' '; - - /* Month */ - memcpy(buf, mk_date_ym[gtm->tm_mon], 4); - buf += 4; - - /* Year */ - *buf++ = ('0' + (year / 1000) % 10); - *buf++ = ('0' + (year / 100) % 10); - *buf++ = ('0' + (year / 10) % 10); - *buf++ = ('0' + (year % 10)); - *buf++ = ' '; - - /* Hour */ - *buf++ = ('0' + (hour / 10)); - *buf++ = ('0' + (hour % 10)); - *buf++ = ':'; - - /* Minutes */ - *buf++ = ('0' + (min / 10)); - *buf++ = ('0' + (min % 10)); - *buf++ = ':'; - - /* Seconds */ - *buf++ = ('0' + (sec / 10)); - *buf++ = ('0' + (sec % 10)); - - /* GMT Time zone + CRLF */ - memcpy(buf, " GMT\r\n\0", 7); - - /* Add new entry to the cache */ - mk_utils_gmt_cache_add(*data, date); - - /* Set mk_ptr_t data len */ - return size; -} - -time_t mk_utils_gmt2utime(char *date) -{ - time_t new_unix_time; - struct tm t_data; - memset(&t_data, 0, sizeof(struct tm)); - - -#ifdef _WIN32 -#pragma message("Since there is no strptime in windows we'll parse the date in a really crude way just to get it out of the way") - - if (0 != strcmp(MK_UTILS_GMT_DATEFORMAT, "%a, %d %b %Y %H:%M:%S GMT")) { - return -1; - } - - { - char *token; - - token = strtok(date, " "); /* "%a, " */ - - if (NULL == token) { - return -1; - } - - token = strtok(NULL, " "); /* "%d " */ - - if (NULL == token) { - return -1; - } - - t_data.tm_mday = strtol(token, NULL, 10); - - token = strtok(NULL, " "); /* "%b " */ - - if (NULL == token) { - return -1; - } - - if(0 == _strnicmp(token, "jan", 3)){ - t_data.tm_mon = 0; - } - else if(0 == _strnicmp(token, "feb", 3)){ - t_data.tm_mon = 1; - } - else if(0 == _strnicmp(token, "mar", 3)){ - t_data.tm_mon = 2; - } - else if(0 == _strnicmp(token, "apr", 3)){ - t_data.tm_mon = 3; - } - else if(0 == _strnicmp(token, "may", 3)){ - t_data.tm_mon = 4; - } - else if(0 == _strnicmp(token, "jun", 3)){ - t_data.tm_mon = 5; - } - else if(0 == _strnicmp(token, "jul", 3)){ - t_data.tm_mon = 6; - } - else if(0 == _strnicmp(token, "aug", 3)){ - t_data.tm_mon = 7; - } - else if(0 == _strnicmp(token, "sep", 3)){ - t_data.tm_mon = 8; - } - else if(0 == _strnicmp(token, "oct", 3)){ - t_data.tm_mon = 9; - } - else if(0 == _strnicmp(token, "nov", 3)){ - t_data.tm_mon = 10; - } - else if(0 == _strnicmp(token, "dec", 3)){ - t_data.tm_mon = 11; - } - else { - return -1; - } - - token = strtok(NULL, " "); /* "%Y " */ - - if (NULL == token) { - return -1; - } - - t_data.tm_year = strtol(token, NULL, 10); - - token = strtok(NULL, ":"); /* "%H:" */ - - if (NULL == token) { - return -1; - } - - t_data.tm_hour = strtol(token, NULL, 10); - - token = strtok(NULL, ":"); /* "%M:" */ - - if (NULL == token) { - return -1; - } - - t_data.tm_min = strtol(token, NULL, 10); - - token = strtok(NULL, " "); /* "%S " */ - - if (NULL == token) { - return -1; - } - - t_data.tm_sec = strtol(token, NULL, 10); - } - -#else - if (!strptime(date, MK_UTILS_GMT_DATEFORMAT, (struct tm*)&t_data)) { - return -1; - } -#endif - - new_unix_time = timegm((struct tm *) &t_data); - - return (new_unix_time); -} - -int mk_buffer_cat(mk_ptr_t *p, char *buf1, int len1, char *buf2, int len2) -{ - /* Validate lengths */ - if (mk_unlikely(len1 < 0 || len2 < 0)) { - return -1; - } - - /* alloc space */ - p->data = (char *) mk_mem_alloc(len1 + len2 + 1); - - /* copy data */ - memcpy(p->data, buf1, len1); - memcpy(p->data + len1, buf2, len2); - p->data[len1 + len2] = '\0'; - - /* assign len */ - p->len = len1 + len2; - - return 0; -} - -/* Convert hexadecimal to int */ -int mk_utils_hex2int(char *hex, int len) -{ - int i = 0; - int res = 0; - char c; - - while ((c = *hex++) && i < len) { - res *= 0x10; - - if (c >= 'a' && c <= 'f') { - res += (c - 0x57); - } - else if (c >= 'A' && c <= 'F') { - res += (c - 0x37); - } - else if (c >= '0' && c <= '9') { - res += (c - 0x30); - } - else { - return -1; - } - i++; - } - - if (res < 0) { - return -1; - } - - return res; -} - -/* If the URI contains hexa format characters it will return - * convert the Hexa values to ASCII character - */ -char *mk_utils_url_decode(mk_ptr_t uri) -{ - int tmp, hex_result; - unsigned int i; - int buf_idx = 0; - char *buf; - char hex[3]; - - if ((tmp = mk_string_char_search(uri.data, '%', uri.len)) < 0) { - return NULL; - } - - i = tmp; - - buf = mk_mem_alloc_z(uri.len + 1); - if (i > 0) { - memcpy(buf, uri.data, i); - buf_idx = i; - } - - while (i < uri.len) { - if (uri.data[i] == '%' && i + 2 < uri.len) { - memcpy(hex, uri.data + i + 1, 2); - hex[2] = '\0'; - - hex_result = mk_utils_hex2int(hex, 2); - - if (hex_result != -1) { - buf[buf_idx] = hex_result; - } - else { - mk_mem_free(buf); - return NULL; - } - i += 2; - } - else { - buf[buf_idx] = uri.data[i]; - } - i++; - buf_idx++; - } - buf[buf_idx] = '\0'; - - return buf; -} - -#ifndef MK_HAVE_BACKTRACE -void mk_utils_stacktrace(void) {} -#else -void mk_utils_stacktrace(void) -{ - unsigned int i; - int ret; - size_t size; - void *arr[10]; - Dl_info d; - - printf("[stack trace]\n"); - size = backtrace(arr, 10); - - for (i = 1; i < size && i < 10; i++) { - ret = dladdr(arr[i], &d); - if (ret == 0 || !d.dli_sname) { - printf(" #%i 0x%016" PRIxPTR " in \?\?\?\?\?\?\?()\n", - (i - 1), (uintptr_t) arr[i]); - continue; - } - - printf(" #%i 0x%016" PRIxPTR " in %s() from %s\n", - (i - 1), (uintptr_t) arr[i], d.dli_sname, d.dli_fname); - } -} -#endif - - - -/* - * This hash generation function is taken originally from Redis source code: - * - * https://github.com/antirez/redis/blob/unstable/src/dict.c#L109 - * - * ---- - * MurmurHash2, by Austin Appleby - * Note - This code makes a few assumptions about how your machine behaves - - * 1. We can read a 4-byte value from any address without crashing - * 2. sizeof(int) == 4 - * - * And it has a few limitations - - * - * 1. It will not work incrementally. - * 2. It will not produce the same results on little-endian and big-endian - * machines. - */ -unsigned int mk_utils_gen_hash(const void *key, int len) -{ - /* 'm' and 'r' are mixing constants generated offline. - They're not really 'magic', they just happen to work well. */ - uint32_t seed = 5381; - const uint32_t m = 0x5bd1e995; - const int r = 24; - - /* Initialize the hash to a 'random' value */ - uint32_t h = seed ^ len; - - /* Mix 4 bytes at a time into the hash */ - const unsigned char *data = (const unsigned char *)key; - - while(len >= 4) { - uint32_t k = *(uint32_t*) data; - - k *= m; - k ^= k >> r; - k *= m; - - h *= m; - h ^= k; - - data += 4; - len -= 4; - } - - /* Handle the last few bytes of the input array */ - switch(len) { - case 3: h ^= data[2] << 16; // fallthrough - case 2: h ^= data[1] << 8; // fallthrough - case 1: h ^= data[0]; h *= m; - }; - - /* Do a few final mixes of the hash to ensure the last few - * bytes are well-incorporated. */ - h ^= h >> 13; - h *= m; - h ^= h >> 15; - - return (unsigned int) h; -} diff --git a/fluent-bit/lib/monkey/mk_server/mk_vhost.c b/fluent-bit/lib/monkey/mk_server/mk_vhost.c deleted file mode 100644 index 2dc35fb1..00000000 --- a/fluent-bit/lib/monkey/mk_server/mk_vhost.c +++ /dev/null @@ -1,821 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* Monkey HTTP Server - * ================== - * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <monkey/mk_info.h> -#include <monkey/monkey.h> -#include <monkey/mk_core.h> -#include <monkey/mk_vhost.h> -#include <monkey/mk_vhost_tls.h> -#include <monkey/mk_utils.h> -#include <monkey/mk_http_status.h> -#include <monkey/mk_info.h> - -#include <mk_core/mk_dirent.h> - -#include <re.h> -#include <sys/stat.h> -#include <fcntl.h> - -static int str_to_regex(char *str, regex_t *reg) -{ - char *p = str; - regex_t *result; - - while (*p) { - if (*p == ' ') *p = '|'; - p++; - } - - result = re_compile(str); - - memcpy(reg, result, REGEXP_SIZE); - - return 0; -} - -/* - * This function is triggered upon thread creation (inside the thread - * context), here we configure per-thread data. - */ -int mk_vhost_fdt_worker_init(struct mk_server *server) -{ - int i; - int j; - struct mk_vhost *h; - struct mk_list *list; - struct mk_list *head; - struct vhost_fdt_host *fdt; - struct vhost_fdt_hash_table *ht; - struct vhost_fdt_hash_chain *hc; - - if (server->fdt == MK_FALSE) { - return -1; - } - - /* - * We are under a thread context and the main configuration is - * already in place. Now for every existent virtual host we are - * going to create the File Descriptor Table (FDT) which aims to - * hold references of 'open and shared' file descriptors under - * the Virtual Host context. - */ - - /* - * Under an initialization context we need to protect this critical - * section - */ - pthread_mutex_lock(&server->vhost_fdt_mutex); - - /* - * Initialize the thread FDT/Hosts list and create an entry per - * existent virtual host - */ - list = mk_mem_alloc_z(sizeof(struct mk_list)); - mk_list_init(list); - - mk_list_foreach(head, &server->hosts) { - h = mk_list_entry(head, struct mk_vhost, _head); - - fdt = mk_mem_alloc(sizeof(struct vhost_fdt_host)); - fdt->host = h; - - /* Initialize hash table */ - for (i = 0; i < VHOST_FDT_HASHTABLE_SIZE; i++) { - ht = &fdt->hash_table[i]; - ht->av_slots = VHOST_FDT_HASHTABLE_CHAINS; - - /* for each chain under the hash table, set the fd */ - for (j = 0; j < VHOST_FDT_HASHTABLE_CHAINS; j++) { - hc = &ht->chain[j]; - hc->fd = -1; - hc->hash = 0; - hc->readers = 0; - } - } - mk_list_add(&fdt->_head, list); - } - - MK_TLS_SET(mk_tls_vhost_fdt, list); - pthread_mutex_unlock(&server->vhost_fdt_mutex); - - return 0; -} - -int mk_vhost_fdt_worker_exit(struct mk_server *server) -{ - struct mk_list *list; - struct mk_list *head; - struct mk_list *tmp; - struct vhost_fdt_host *fdt; - - if (server->fdt == MK_FALSE) { - return -1; - } - - list = MK_TLS_GET(mk_tls_vhost_fdt); - mk_list_foreach_safe(head, tmp, list) { - fdt = mk_list_entry(head, struct vhost_fdt_host, _head); - mk_list_del(&fdt->_head); - mk_mem_free(fdt); - } - - mk_mem_free(list); - return 0; -} - - -static inline -struct vhost_fdt_hash_table *mk_vhost_fdt_table_lookup(int id, struct mk_vhost *host) -{ - struct mk_list *head; - struct mk_list *list; - struct vhost_fdt_host *fdt_host; - struct vhost_fdt_hash_table *ht = NULL; - - list = MK_TLS_GET(mk_tls_vhost_fdt); - mk_list_foreach(head, list) { - fdt_host = mk_list_entry(head, struct vhost_fdt_host, _head); - if (fdt_host->host == host) { - ht = &fdt_host->hash_table[id]; - return ht; - } - } - - return ht; -} - -static inline -struct vhost_fdt_hash_chain -*mk_vhost_fdt_chain_lookup(unsigned int hash, struct vhost_fdt_hash_table *ht) -{ - int i; - struct vhost_fdt_hash_chain *hc = NULL; - - for (i = 0; i < VHOST_FDT_HASHTABLE_CHAINS; i++) { - hc = &ht->chain[i]; - if (hc->hash == hash) { - return hc; - } - } - - return NULL; -} - - -static inline int mk_vhost_fdt_open(int id, unsigned int hash, - struct mk_http_request *sr, - struct mk_server *server) -{ - int i; - int fd = -1; - struct vhost_fdt_hash_table *ht = NULL; - struct vhost_fdt_hash_chain *hc; - - if (server->fdt == MK_FALSE) { - return open(sr->real_path.data, sr->file_info.flags_read_only); - } - - ht = mk_vhost_fdt_table_lookup(id, sr->host_conf); - if (mk_unlikely(!ht)) { - return open(sr->real_path.data, sr->file_info.flags_read_only); - } - - /* We got the hash table, now look around the chains array */ - hc = mk_vhost_fdt_chain_lookup(hash, ht); - if (hc) { - /* Increment the readers and return the shared FD */ - hc->readers++; - sr->vhost_fdt_id = id; - sr->vhost_fdt_hash = hash; - sr->vhost_fdt_enabled = MK_TRUE; - return hc->fd; - } - - /* - * Get here means that no entry exists in the hash table for the - * requested file descriptor and hash, we must try to open the file - * and register the entry in the table. - */ - fd = open(sr->real_path.data, sr->file_info.flags_read_only); - if (fd == -1) { - return -1; - } - - /* If chains are full, just return the new FD, bad luck... */ - if (ht->av_slots <= 0) { - return fd; - } - - /* Register the new entry in an available slot */ - for (i = 0; i < VHOST_FDT_HASHTABLE_CHAINS; i++) { - hc = &ht->chain[i]; - if (hc->fd == -1) { - hc->fd = fd; - hc->hash = hash; - hc->readers++; - ht->av_slots--; - - sr->vhost_fdt_id = id; - sr->vhost_fdt_hash = hash; - sr->vhost_fdt_enabled = MK_TRUE; - - return fd; - } - } - - return fd; -} - -static inline int mk_vhost_fdt_close(struct mk_http_request *sr, - struct mk_server *server) -{ - int id; - unsigned int hash; - struct vhost_fdt_hash_table *ht = NULL; - struct vhost_fdt_hash_chain *hc; - - if (server->fdt == MK_FALSE || sr->vhost_fdt_enabled == MK_FALSE) { - if (sr->in_file.fd > 0) { - return close(sr->in_file.fd); - } - return -1; - } - - id = sr->vhost_fdt_id; - hash = sr->vhost_fdt_hash; - - ht = mk_vhost_fdt_table_lookup(id, sr->host_conf); - if (mk_unlikely(!ht)) { - return close(sr->in_file.fd); - } - - /* We got the hash table, now look around the chains array */ - hc = mk_vhost_fdt_chain_lookup(hash, ht); - if (hc) { - /* Increment the readers and check if we should close */ - hc->readers--; - sr->vhost_fdt_enabled = MK_FALSE; - - if (hc->readers == 0) { - hc->fd = -1; - hc->hash = 0; - ht->av_slots++; - return close(sr->in_file.fd); - } - else { - return 0; - } - } - return close(sr->in_file.fd); -} - - -int mk_vhost_open(struct mk_http_request *sr, struct mk_server *server) -{ - int id; - int off; - unsigned int hash; - - off = sr->host_conf->documentroot.len; - hash = mk_utils_gen_hash(sr->real_path.data + off, - sr->real_path.len - off); - id = (hash % VHOST_FDT_HASHTABLE_SIZE); - - return mk_vhost_fdt_open(id, hash, sr, server); -} - -int mk_vhost_close(struct mk_http_request *sr, struct mk_server *server) -{ - return mk_vhost_fdt_close(sr, server); -} - -struct mk_vhost_handler *mk_vhost_handler_match(char *match, - void (*cb)(struct mk_http_request *, - void *), - void *data) -{ - int ret; - struct mk_vhost_handler *h; - - h = mk_mem_alloc(sizeof(struct mk_vhost_handler)); - if (!h) { - return NULL; - } - h->name = NULL; - h->cb = cb; - h->data = data; - h->match = mk_mem_alloc(REGEXP_SIZE); - if (!h->match) { - mk_mem_free(h); - return NULL; - } - mk_list_init(&h->params); - - ret = str_to_regex(match, h->match); - if (ret == -1) { - mk_mem_free(h); - return NULL; - } - - return h; -} - -/* - * Open a virtual host configuration file and return a structure with - * definitions. - */ -struct mk_vhost *mk_vhost_read(char *path) -{ - int ret; - char *tmp; - char *host_low; - struct stat checkdir; - struct mk_vhost *host; - struct mk_vhost_alias *new_alias; - struct mk_vhost_error_page *err_page; - struct mk_rconf *cnf; - struct mk_rconf_section *section_host; - struct mk_rconf_section *section_ep; - struct mk_rconf_section *section_handlers; - struct mk_rconf_entry *entry_ep; - struct mk_string_line *entry; - struct mk_list *head, *list, *line; - struct mk_vhost_handler *h_handler; - struct mk_vhost_handler_param *h_param; - - /* Read configuration file */ - cnf = mk_rconf_open(path); - if (!cnf) { - mk_err("Configuration error, aborting."); - exit(EXIT_FAILURE); - } - - /* Read 'HOST' section */ - section_host = mk_rconf_section_get(cnf, "HOST"); - if (!section_host) { - mk_err("Invalid config file %s", path); - return NULL; - } - - /* Alloc configuration node */ - host = mk_mem_alloc_z(sizeof(struct mk_vhost)); - host->config = cnf; - host->file = mk_string_dup(path); - - /* Init list for host name aliases */ - mk_list_init(&host->server_names); - - /* Init list for custom error pages */ - mk_list_init(&host->error_pages); - - /* Init list for content handlers */ - mk_list_init(&host->handlers); - - /* Lookup Servername */ - list = mk_rconf_section_get_key(section_host, "Servername", MK_RCONF_LIST); - if (!list) { - mk_err("Hostname does not contain a Servername"); - exit(EXIT_FAILURE); - } - - mk_list_foreach(head, list) { - entry = mk_list_entry(head, struct mk_string_line, _head); - if (entry->len > MK_HOSTNAME_LEN - 1) { - continue; - } - - /* Hostname to lowercase */ - host_low = mk_string_tolower(entry->val); - - /* Alloc node */ - new_alias = mk_mem_alloc_z(sizeof(struct mk_vhost_alias)); - new_alias->name = mk_mem_alloc_z(entry->len + 1); - strncpy(new_alias->name, host_low, entry->len); - mk_mem_free(host_low); - - new_alias->len = entry->len; - - mk_list_add(&new_alias->_head, &host->server_names); - } - mk_string_split_free(list); - - /* Lookup document root handled by a mk_ptr_t */ - host->documentroot.data = mk_rconf_section_get_key(section_host, - "DocumentRoot", - MK_RCONF_STR); - if (!host->documentroot.data) { - mk_err("Missing DocumentRoot entry on %s file", path); - mk_rconf_free(cnf); - mk_mem_free(host->file); - mk_mem_free(host); - return NULL; - } - - host->documentroot.len = strlen(host->documentroot.data); - - /* Validate document root configured */ - if (stat(host->documentroot.data, &checkdir) == -1) { - mk_err("Invalid path to DocumentRoot in %s", path); - } - else if (!(checkdir.st_mode & S_IFDIR)) { - mk_err("DocumentRoot variable in %s has an invalid directory path", path); - } - - if (mk_list_is_empty(&host->server_names) == 0) { - mk_rconf_free(cnf); - mk_mem_free(host->file); - mk_mem_free(host); - return NULL; - } - - /* Check Virtual Host redirection */ - host->header_redirect.data = NULL; - host->header_redirect.len = 0; - - tmp = mk_rconf_section_get_key(section_host, - "Redirect", - MK_RCONF_STR); - if (tmp) { - host->header_redirect.data = mk_string_dup(tmp); - host->header_redirect.len = strlen(tmp); - mk_mem_free(tmp); - } - - /* Error Pages */ - section_ep = mk_rconf_section_get(cnf, "ERROR_PAGES"); - if (section_ep) { - mk_list_foreach(head, §ion_ep->entries) { - entry_ep = mk_list_entry(head, struct mk_rconf_entry, _head); - - int ep_status = -1; - char *ep_file = NULL; - unsigned long len; - - ep_status = atoi(entry_ep->key); - ep_file = entry_ep->val; - - /* Validate input values */ - if (ep_status < MK_CLIENT_BAD_REQUEST || - ep_status > MK_SERVER_HTTP_VERSION_UNSUP || - ep_file == NULL) { - continue; - } - - /* Alloc error page node */ - err_page = mk_mem_alloc_z(sizeof(struct mk_vhost_error_page)); - err_page->status = ep_status; - err_page->file = mk_string_dup(ep_file); - err_page->real_path = NULL; - mk_string_build(&err_page->real_path, &len, "%s/%s", - host->documentroot.data, err_page->file); - - MK_TRACE("Map error page: status %i -> %s", err_page->status, err_page->file); - - /* Link page to the error page list */ - mk_list_add(&err_page->_head, &host->error_pages); - } - } - - /* Handlers */ - int i; - int params; - struct mk_list *head_line; - - section_handlers = mk_rconf_section_get(cnf, "HANDLERS"); - if (!section_handlers) { - return host; - } - mk_list_foreach(head, §ion_handlers->entries) { - entry_ep = mk_list_entry(head, struct mk_rconf_entry, _head); - if (strncasecmp(entry_ep->key, "Match", strlen(entry_ep->key)) == 0) { - line = mk_string_split_line(entry_ep->val); - if (!line) { - continue; - } - h_handler = mk_mem_alloc(sizeof(struct mk_vhost_handler)); - if (!h_handler) { - exit(EXIT_FAILURE); - } - h_handler->match = mk_mem_alloc(REGEXP_SIZE); - if (!h_handler->match) { - mk_mem_free(h_handler); - exit(EXIT_FAILURE); - } - h_handler->cb = NULL; - mk_list_init(&h_handler->params); - - i = 0; - params = 0; - mk_list_foreach(head_line, line) { - entry = mk_list_entry(head_line, struct mk_string_line, _head); - switch (i) { - case 0: - ret = str_to_regex(entry->val, h_handler->match); - if (ret == -1) { - return NULL; - } - break; - case 1: - h_handler->name = mk_string_dup(entry->val); - break; - default: - /* link parameters */ - h_param = mk_mem_alloc(sizeof(struct mk_vhost_handler_param)); - h_param->p.data = mk_string_dup(entry->val); - h_param->p.len = entry->len; - mk_list_add(&h_param->_head, &h_handler->params); - params++; - }; - i++; - } - h_handler->n_params = params; - mk_string_split_free(line); - - if (i < 2) { - mk_err("[Host Handlers] invalid Match value\n"); - exit(EXIT_FAILURE); - } - mk_list_add(&h_handler->_head, &host->handlers); - } - } - - - return host; -} - -int mk_vhost_map_handlers(struct mk_server *server) -{ - int n = 0; - struct mk_list *head; - struct mk_list *head_handler; - struct mk_vhost *host; - struct mk_vhost_handler *h_handler; - struct mk_plugin *p; - - mk_list_foreach(head, &server->hosts) { - host = mk_list_entry(head, struct mk_vhost, _head); - mk_list_foreach(head_handler, &host->handlers) { - h_handler = mk_list_entry(head_handler, - struct mk_vhost_handler, _head); - - /* Lookup plugin by name */ - p = mk_plugin_lookup(h_handler->name, server); - if (!p) { - mk_err("Plugin '%s' was not loaded", h_handler->name); - continue; - } - - if (p->hooks != MK_PLUGIN_STAGE) { - mk_err("Plugin '%s' is not a handler", h_handler->name); - continue; - } - - h_handler->handler = p; - n++; - } - } - - return n; -} - -void mk_vhost_set_single(char *path, struct mk_server *server) -{ - struct mk_vhost *host; - struct mk_vhost_alias *halias; - struct stat checkdir; - - /* Set the default host */ - host = mk_mem_alloc_z(sizeof(struct mk_vhost)); - mk_list_init(&host->error_pages); - mk_list_init(&host->server_names); - - /* Prepare the unique alias */ - halias = mk_mem_alloc_z(sizeof(struct mk_vhost_alias)); - halias->name = mk_string_dup("127.0.0.1"); - mk_list_add(&halias->_head, &host->server_names); - - host->documentroot.data = mk_string_dup(path); - host->documentroot.len = strlen(path); - host->header_redirect.data = NULL; - - /* Validate document root configured */ - if (stat(host->documentroot.data, &checkdir) == -1) { - mk_err("Invalid path to DocumentRoot in %s", path); - exit(EXIT_FAILURE); - } - else if (!(checkdir.st_mode & S_IFDIR)) { - mk_err("DocumentRoot variable in %s has an invalid directory path", path); - exit(EXIT_FAILURE); - } - mk_list_add(&host->_head, &server->hosts); - mk_list_init(&host->handlers); -} - -/* Given a configuration directory, start reading the virtual host entries */ -void mk_vhost_init(char *path, struct mk_server *server) -{ - DIR *dir; - unsigned long len; - char *buf = 0; - char *sites = 0; - char *file; - struct mk_vhost *p_host; /* debug */ - struct dirent *ent; - struct file_info f_info; - int ret; - - if (!server->conf_sites) { - mk_warn("[vhost] skipping default site"); - return; - } - - /* Read default virtual host file */ - mk_string_build(&sites, &len, "%s/%s/", - path, server->conf_sites); - ret = mk_file_get_info(sites, &f_info, MK_FILE_EXISTS); - if (ret == -1 || f_info.is_directory == MK_FALSE) { - mk_mem_free(sites); - sites = server->conf_sites; - } - - mk_string_build(&buf, &len, "%s/default", sites); - - p_host = mk_vhost_read(buf); - if (!p_host) { - mk_err("Error parsing main configuration file 'default'"); - } - mk_list_add(&p_host->_head, &server->hosts); - server->nhosts++; - mk_mem_free(buf); - buf = NULL; - - - /* Read all virtual hosts defined in sites/ */ - if (!(dir = opendir(sites))) { - mk_mem_free(sites); - mk_err("Could not open %s", sites); - exit(EXIT_FAILURE); - } - - /* Reading content */ - while ((ent = readdir(dir)) != NULL) { - if (ent->d_name[0] == '.') { - continue; - } - if (strcmp((char *) ent->d_name, "..") == 0) { - continue; - } - if (ent->d_name[strlen(ent->d_name) - 1] == '~') { - continue; - } - if (strcasecmp((char *) ent->d_name, "default") == 0) { - continue; - } - file = NULL; - mk_string_build(&file, &len, "%s/%s", sites, ent->d_name); - - p_host = mk_vhost_read(file); - mk_mem_free(file); - if (!p_host) { - continue; - } - else { - mk_list_add(&p_host->_head, &server->hosts); - server->nhosts++; - } - } - closedir(dir); - mk_mem_free(sites); -} - - -/* Lookup a registered virtual host based on the given 'host' input */ -int mk_vhost_get(mk_ptr_t host, struct mk_vhost **vhost, - struct mk_vhost_alias **alias, - struct mk_server *server) -{ - struct mk_vhost *entry_host; - struct mk_vhost_alias *entry_alias; - struct mk_list *head_vhost, *head_alias; - - mk_list_foreach(head_vhost, &server->hosts) { - entry_host = mk_list_entry(head_vhost, struct mk_vhost, _head); - mk_list_foreach(head_alias, &entry_host->server_names) { - entry_alias = mk_list_entry(head_alias, struct mk_vhost_alias, _head); - if (entry_alias->len == host.len && - strncmp(entry_alias->name, host.data, host.len) == 0) { - *vhost = entry_host; - *alias = entry_alias; - return 0; - } - } - } - - return -1; -} - -static void mk_vhost_handler_free(struct mk_vhost_handler *h) -{ - struct mk_list *tmp; - struct mk_list *head; - struct mk_vhost_handler_param *param; - - /* Release Params */ - mk_list_foreach_safe(head, tmp, &h->params) { - param = mk_list_entry(head, struct mk_vhost_handler_param, _head); - mk_list_del(¶m->_head); - mk_mem_free(param->p.data); - mk_mem_free(param); - } - - mk_mem_free(h->match); - mk_mem_free(h->name); - mk_mem_free(h); -} - -int mk_vhost_destroy(struct mk_vhost *vh) -{ - struct mk_vhost_alias *halias = NULL; - struct mk_vhost_handler *hhandler; - struct mk_vhost_error_page *ep; - struct mk_list *head; - struct mk_list *tmp; - - if (vh) { - /* Free aliases or servernames */ - mk_list_foreach_safe(head, tmp, &vh->server_names) { - halias = mk_list_entry(head, struct mk_vhost_alias, _head); - if (halias) { - mk_list_del(&halias->_head); - if (halias->name) { - mk_mem_free(halias->name); - } - mk_mem_free(halias); - } - } - - /* Handlers */ - mk_list_foreach_safe(head, tmp, &vh->handlers) { - hhandler = mk_list_entry(head, struct mk_vhost_handler, _head); - if (hhandler) { - mk_vhost_handler_free(hhandler); - } - } - - /* Free error pages */ - mk_list_foreach_safe(head, tmp, &vh->error_pages) { - ep = mk_list_entry(head, struct mk_vhost_error_page, _head); - if (ep) { - mk_list_del(&ep->_head); - if (ep->file) { - mk_mem_free(ep->file); - } - if (ep->real_path) { - mk_mem_free(ep->real_path); - } - mk_mem_free(ep); - } - } - mk_ptr_free(&vh->documentroot); - - /* Free source configuration */ - if (vh->config) { - mk_rconf_free(vh->config); - } - mk_list_del(&vh->_head); - if (vh->file) { - mk_mem_free(vh->file); - } - - mk_mem_free(vh); - } - return 0; -} - -void mk_vhost_free_all(struct mk_server *server) -{ - struct mk_vhost *host; - struct mk_list *head; - struct mk_list *tmp; - - mk_list_foreach_safe(head, tmp, &server->hosts) { - host = mk_list_entry(head, struct mk_vhost, _head); - mk_vhost_destroy(host); - } -} diff --git a/fluent-bit/lib/monkey/mk_server/monkey.c b/fluent-bit/lib/monkey/mk_server/monkey.c deleted file mode 100644 index 68513d21..00000000 --- a/fluent-bit/lib/monkey/mk_server/monkey.c +++ /dev/null @@ -1,241 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* Monkey HTTP Server - * ================== - * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _GNU_SOURCE - -#include <mk_core/mk_pthread.h> -#include <mk_core/mk_event.h> - -#include <monkey/mk_scheduler.h> -#include <monkey/mk_plugin.h> -#include <monkey/mk_clock.h> -#include <monkey/mk_thread.h> -#include <monkey/mk_mimetype.h> -#include <monkey/mk_http_thread.h> - -pthread_once_t mk_server_tls_setup_once = PTHREAD_ONCE_INIT; - -static void mk_set_up_tls_keys() -{ - MK_INIT_INITIALIZE_TLS_UNIVERSAL(); - MK_INIT_INITIALIZE_TLS(); - - mk_http_thread_initialize_tls(); -} - -void mk_server_info(struct mk_server *server) -{ - struct mk_list *head; - struct mk_plugin *p; - struct mk_config_listener *l; - -#ifdef _WIN32 - printf(MK_BANNER_ENTRY "Process ID is %ld\n", (long)GetCurrentProcessId()); -#else - printf(MK_BANNER_ENTRY "Process ID is %ld\n", (long) getpid()); -#endif - mk_list_foreach(head, &server->listeners) { - l = mk_list_entry(head, struct mk_config_listener, _head); - printf(MK_BANNER_ENTRY "Server listening on %s:%s\n", - l->address, l->port); - } - printf(MK_BANNER_ENTRY - "%i threads, may handle up to %i client connections\n", - server->workers, server->server_capacity); - - /* List loaded plugins */ - printf(MK_BANNER_ENTRY "Loaded Plugins: "); - mk_list_foreach(head, &server->plugins) { - p = mk_list_entry(head, struct mk_plugin, _head); - printf("%s ", p->shortname); - } - printf("\n"); - -#ifdef __linux__ - char tmp[64]; - - if (mk_kernel_features_print(tmp, sizeof(tmp), server) > 0) { - printf(MK_BANNER_ENTRY "Linux Features: %s\n", tmp); - } -#endif - - fflush(stdout); -} - -/* Initialize Monkey Server */ -struct mk_server *mk_server_create() -{ - int ret; - int kern_version; - int kern_features; - struct mk_server *server; - - server = mk_mem_alloc_z(sizeof(struct mk_server)); - if (!server) { - return NULL; - } - - /* I'll try to leave both initializations here because - * it should be possible to run in windows using the accept - * backend in which case it doesn't make sense to tie the net stack - * initialization to libevent. - */ - mk_net_init(); - mk_event_init(); - - /* Library mode: event loop */ - server->lib_mode = MK_TRUE; - server->lib_evl = mk_event_loop_create(8); - if (!server->lib_evl) { - mk_mem_free(server); - return NULL; - } - - /* Library mode: channel manager */ - - memset(&server->lib_ch_event, 0, sizeof(struct mk_event)); - - ret = mk_event_channel_create(server->lib_evl, - &server->lib_ch_manager[0], - &server->lib_ch_manager[1], - &server->lib_ch_event); - - if (ret != 0) { - mk_event_loop_destroy(server->lib_evl); - mk_mem_free(server); - return NULL; - } - - /* Library mode: start event loop */ - server->lib_evl_start = mk_event_loop_create(1); - if (!server->lib_evl_start) { - mk_event_loop_destroy(server->lib_evl); - mk_mem_free(server); - return NULL; - } - - memset(&server->lib_ch_start_event, 0, sizeof(struct mk_event)); - - ret = mk_event_channel_create(server->lib_evl_start, - &server->lib_ch_start[0], - &server->lib_ch_start[1], - &server->lib_ch_start_event); - - if (ret != 0) { - mk_event_loop_destroy(server->lib_evl); - mk_event_loop_destroy(server->lib_evl_start); - mk_mem_free(server); - return NULL; - } - - /* Initialize linked list heads */ - mk_list_init(&server->plugins); - mk_list_init(&server->sched_worker_callbacks); - mk_list_init(&server->stage10_handler); - mk_list_init(&server->stage20_handler); - mk_list_init(&server->stage30_handler); - mk_list_init(&server->stage40_handler); - mk_list_init(&server->stage50_handler); - server->scheduler_mode = -1; - - mk_core_init(); - - /* Init thread keys */ - pthread_once(&mk_server_tls_setup_once, mk_set_up_tls_keys); - - /* Init Kernel version data */ - kern_version = mk_kernel_version(); - kern_features = mk_kernel_features(kern_version); - - server->kernel_version = kern_version; - server->kernel_features = kern_features; - -#ifdef MK_HAVE_TRACE - MK_TRACE("Monkey TRACE is enabled"); - //pthread_mutex_init(&mutex_trace, (pthread_mutexattr_t *) NULL); -#endif - -#ifdef LINUX_TRACE - mk_info("Linux Trace enabled"); -#endif - - mk_config_set_init_values(server); - - mk_mimetype_init(server); - - pthread_mutex_init(&server->vhost_fdt_mutex, NULL); - - return server; -} - -int mk_server_setup(struct mk_server *server) -{ - int ret; - pthread_t tid; - - /* Core and Scheduler setup */ - mk_config_start_configure(server); - mk_config_signature(server); - - mk_sched_init(server); - - - /* Clock init that must happen before starting threads */ - mk_clock_sequential_init(server); - - /* Load plugins */ - mk_plugin_api_init(server); - mk_plugin_load_all(server); - - /* Workers: logger and clock */ - ret = mk_utils_worker_spawn((void *) mk_clock_worker_init, server, &tid); - if (ret != 0) { - return -1; - } - - /* Configuration sanity check */ - mk_config_sanity_check(server); - - /* Invoke Plugin PRCTX hooks */ - mk_plugin_core_process(server); - - /* Launch monkey http workers */ - mk_server_launch_workers(server); - - return 0; -} - -void mk_exit_all(struct mk_server *server) -{ - uint64_t val; - - /* Distribute worker signals to stop working */ - val = MK_SCHED_SIGNAL_FREE_ALL; - mk_sched_broadcast_signal(server, val); - - /* Wait for all workers to finish */ - mk_sched_workers_join(server); - - /* Continue exiting */ - mk_plugin_exit_all(server); - mk_clock_exit(server); - - mk_sched_exit(server); - mk_config_free_all(server); -} |