/*
* mod_mono.c
*
* Authors:
* Daniel Lopez Ridruejo
* Gonzalo Paniagua Javier
* Marek Habersack
*
* Copyright (c) 2002 Daniel Lopez Ridruejo
* (c) 2002-2009 Novell, Inc.
*
* 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.
*/
#ifdef HAVE_CONFIG_H
#include "mod_mono_config.h"
#endif
/* uncomment this to get tons of messages in the log */
/* or use --enable-debug with configure */
/* #define DEBUG */
#ifndef DEBUG_LEVEL
#define DEBUG_LEVEL 0
#endif
#ifdef DEBUG
#define STDOUT_NULL_DEFAULT 0
#else
#define STDOUT_NULL_DEFAULT 1
#endif
#include <stdlib.h>
#include "mod_mono.h"
#include "mono-io-portability.h"
DEFINE_MODULE (mono_module);
/* Configuration pool. Cleared on restart. */
static apr_pool_t *pconf;
typedef struct per_dir_config {
char *location;
char *alias;
} per_dir_config;
enum {
FORK_NONE,
FORK_INPROCESS,
FORK_ATTEMPTED,
FORK_FAILED,
FORK_SUCCEEDED
};
typedef enum {
AUTORESTART_MODE_INVALID,
AUTORESTART_MODE_NONE,
AUTORESTART_MODE_TIME,
AUTORESTART_MODE_REQUESTS,
} auto_restart_mode;
#define URI_LIST_ITEM_SIZE 256
#define ACTIVE_URI_LIST_ITEM_COUNT 100
#define WAITING_URI_LIST_ITEM_COUNT 100
typedef struct {
int32_t id;
time_t start_time;
char uri[URI_LIST_ITEM_SIZE];
} uri_item;
typedef struct {
uint32_t requests_counter;
uint32_t handled_requests;
time_t start_time;
char restart_issued;
char starting;
int active_requests;
int waiting_requests;
int accepting_requests;
uri_item active_uri_list[ACTIVE_URI_LIST_ITEM_COUNT];
uri_item waiting_uri_list[WAITING_URI_LIST_ITEM_COUNT];
} dashboard_data;
#define INITIAL_DATA_MAX_ALLOCA_SIZE 8192
typedef struct {
size_t method_len;
size_t server_hostname_len;
size_t uri_len;
size_t args_len;
size_t protocol_len;
size_t local_ip_len;
size_t remote_ip_len;
const char *remote_name;
size_t remote_name_len;
size_t filename_len;
} initial_data_info;
typedef struct xsp_data {
char is_default;
char *alias;
char *filename; /* Unix socket path */
char *umask_value;
char *run_xsp;
char *executable_path;
char *path;
char *server_path;
char *target_framework;
char *applications;
char *wapidir;
char *document_root;
char *appconfig_file;
char *appconfig_dir;
char *listen_port;
char *listen_address;
char *listen_backlog;
char *minthreads;
char *max_cpu_time;
char *max_memory;
char *debug;
char *env_vars;
char *iomap;
char *hidden;
char status; /* One of the FORK_* in the enum above.
* Don't care if run_xsp is "false" */
char is_virtual; /* is the server virtual? */
char *start_attempts;
char *start_wait_time;
char *max_active_requests;
char *max_waiting_requests;
/* auto-restart stuff */
auto_restart_mode restart_mode;
uint32_t restart_requests;
uint32_t restart_time;
/* other settings */
unsigned char no_flush;
int portability_level;
/* The dashboard */
apr_shm_t *dashboard_shm;
dashboard_data *dashboard;
apr_global_mutex_t *dashboard_mutex;
char dashboard_mutex_initialized_in_child;
char *dashboard_file;
char *dashboard_lock_file;
} xsp_data;
typedef struct {
int nservers;
xsp_data *servers;
char auto_app;
char auto_app_set;
} module_cfg;
typedef struct {
uint32_t client_block_buffer_size;
char *client_block_buffer;
} request_data;
typedef struct {
char *name;
apr_lockmech_e sym;
char available;
} lock_mechanism;
#define LOCK_MECH(name) {#name, APR_LOCK_ ## name, APR_HAS_ ## name ## _SERIALIZE}
static lock_mechanism lockMechanisms [] = {
LOCK_MECH (FCNTL),
LOCK_MECH (FLOCK),
LOCK_MECH (SYSVSEM),
LOCK_MECH (PROC_PTHREAD),
LOCK_MECH (POSIXSEM),
{"DEFAULT", APR_LOCK_DEFAULT, 1},
{NULL, 0, 0}
};
static int send_table (apr_pool_t *pool, apr_table_t *table, apr_socket_t *sock);
static void start_xsp (module_cfg *config, int is_restart, char *alias);
static apr_status_t terminate_xsp2 (void *data, char *alias, int for_restart, int lock_held);
#define IS_MASTER(__conf__) (!strcmp (GLOBAL_SERVER_NAME, (__conf__)->alias))
static long
string_to_long (char *str, char *what, long def)
{
long retval;
char *endptr;
if (!str || !*str)
return def;
retval = strtol (str, &endptr, 0);
if ((retval == LONG_MAX && errno == ERANGE) || (str == endptr) || *endptr) {
ap_log_error (APLOG_MARK, APLOG_WARNING, STATUS_AND_SERVER,
"%s: conversion to integer failed - returning the default value %lu.",
what ? what : "Configuration", def);
return def;
}
return retval;
}
static apr_lockmech_e
get_apr_locking_mechanism ()
{
char *name = getenv ("MOD_MONO_LOCKING_MECHANISM");
int i = 0;
DEBUG_PRINT (2, "Requested locking mechanism name: %s", name);
if (!name)
return APR_LOCK_DEFAULT;
while (lockMechanisms [i].name) {
if (!strncasecmp (name, lockMechanisms [i].name, strlen (lockMechanisms [i].name))) {
if (lockMechanisms [i].available) {
DEBUG_PRINT (1, "Using configured lock mechanism: %s", lockMechanisms [i].name);
return lockMechanisms [i].sym;
} else {
ap_log_error (APLOG_MARK, APLOG_ALERT, STATUS_AND_SERVER,
"Locking mechanism '%s' is unavailable for this platform. Using the default one.",
lockMechanisms [i].name);
return APR_LOCK_DEFAULT;
}
}
i++;
}
ap_log_error (APLOG_MARK, APLOG_ALERT, STATUS_AND_SERVER,
"No locking mechanism matching '%s' has been found for this platform. Using the default one.",
name);
return APR_LOCK_DEFAULT;
}
/* */
static int
search_for_alias (const char *alias, module_cfg *config)
{
/* 'alias' may be NULL to search for the default XSP */
int i;
xsp_data *xsp;
DEBUG_PRINT (0, "Searching for alias %s", alias);
DEBUG_PRINT (0, "%u servers available", config->nservers);
for (i = 0; i < config->nservers; i++) {
xsp = &config->servers [i];
DEBUG_PRINT (0, "Server at index %u is '%s'", i, xsp->alias);
if ((alias == NULL || !strcmp (alias, "default")) && xsp->is_default)
return i;
if (alias != NULL && !strcmp (alias, xsp->alias))
return i;
}
return -1;
}
static const char *
set_alias (cmd_parms *cmd, void *mconfig, const char *alias)
{
per_dir_config *config = mconfig;
module_cfg *sconfig;
sconfig = ap_get_module_config (cmd->server->module_config, &mono_module);
config->alias = (char *) alias;
if (search_for_alias (alias, sconfig) == -1) {
char *err = apr_pstrcat (cmd->pool, "Server alias '", alias, ", not found.", NULL);
return err;
}
return NULL;
}
static const char *
set_auto_application (cmd_parms *cmd, void *mconfig, const char *value)
{
module_cfg *sconfig;
sconfig = ap_get_module_config (cmd->server->module_config, &mono_module);
if (!strcasecmp (value, "disabled")) {
if (sconfig->auto_app_set && sconfig->auto_app != FALSE)
return apr_pstrdup (cmd->pool, "Conflicting values for MonoAutoApplication.");
sconfig->auto_app = FALSE;
/* TODO: Copiar de 'XXGLOBAL' a 'default' */
} else if (!strcasecmp (value, "enabled")) {
if (sconfig->auto_app_set && sconfig->auto_app != TRUE)
return apr_pstrdup (cmd->pool, "Conflicting values for MonoAutoApplication.");
sconfig->auto_app = TRUE;
} else {
return apr_pstrdup (cmd->pool, "Invalid value. Must be 'enabled' or 'disabled'");
}
sconfig->auto_app_set = TRUE;
return NULL;
}
static unsigned long
parse_restart_time (const char *t)
{
uint32_t time_spec [4] = {0, 0, 0, 0};
int parsed;
parsed = sscanf (t, "%u:%u:%u:%u",
&time_spec [0],
&time_spec [1],
&time_spec [2],
&time_spec [3]);
switch (pars