/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Monkey HTTP Server * ================== * Copyright 2001-2017 Eduardo Silva * * 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 #include #include #include #include #include #include #include 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); }