diff --git a/Makefile b/Makefile index eba3e9c..0f64874 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ MANDIR = $(PREFIX)/share/man CFLAGS = -O2 -g -std=c99 -fno-strict-aliasing -Wall -W -D_GNU_SOURCE -I/usr/local/include LDFLAGS = -lssl -lcrypto -lev -L/usr/local/lib -OBJS = stud.o ringbuffer.o configuration.o +OBJS = stud.o ringbuffer.o configuration.o log.o all: realall diff --git a/configuration.c b/configuration.c index ff3409f..05d7369 100644 --- a/configuration.c +++ b/configuration.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -19,8 +20,10 @@ #include #include +#include "stud.h" #include "configuration.h" #include "version.h" +#include "log.h" #define ADDR_LEN 150 #define PORT_LEN 6 @@ -42,10 +45,15 @@ #define CFG_SYSLOG "syslog" #define CFG_SYSLOG_FACILITY "syslog-facility" #define CFG_PARAM_SYSLOG_FACILITY 11015 +#define CFG_LOG_LEVEL "log-level" +#define CFG_PARAM_LOG_LEVEL 11016 +#define CFG_PARAM_INSTANCE_NAME 11017 #define CFG_DAEMON "daemon" #define CFG_WRITE_IP "write-ip" #define CFG_WRITE_PROXY "write-proxy" #define CFG_PEM_FILE "pem-file" +#define CFG_INSTANCE_NAME "instance-name" +#define CFG_PID_FILE "pid-file" #ifdef USE_SHARED_CACHE #define CFG_SHARED_CACHE "shared-cache" @@ -69,6 +77,9 @@ #endif // END: configuration parameters +#define PID_DIR "/var/run/stud" +#define PID_DIR_NONPRIVILEGED "/tmp" + static char var_buf[CONFIG_BUF_SIZE]; static char val_buf[CONFIG_BUF_SIZE]; static char error_buf[CONFIG_BUF_SIZE]; @@ -90,14 +101,28 @@ char * config_error_get (void) { return error_buf; } -void config_die (char *fmt, ...) { - va_list args; - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); - fprintf(stderr, "\n"); +char * pid_dir_get () { + if (getuid() == 0) { + return PID_DIR; + } else { + char *td = getenv("TMPDIR"); + return (td == NULL || strlen(td) < 1) ? + PID_DIR_NONPRIVILEGED : + td; + } +} - exit(1); +int config_param_val_pid_file (char *str, char *dst) { + int len = (str == NULL) ? 0 : strlen(str); + memset(dst, '\0', PATH_MAX); + if (len < 1) { + char *name = stud_instance_name(NULL); + if (name == NULL || strlen(name) < 1) name = "stud"; + snprintf(dst, PATH_MAX, "%s/%s.pid", pid_dir_get(), name); + } else { + strncat(dst, str, PATH_MAX); + } + return 1; } stud_config * config_new (void) { @@ -138,13 +163,15 @@ stud_config * config_new (void) { r->SHCUPD_MCASTTTL = NULL; #endif - r->QUIET = 0; r->SYSLOG = 0; r->SYSLOG_FACILITY = LOG_DAEMON; + r->LOG_LEVEL = log_str2level(NULL); r->TCP_KEEPALIVE_TIME = 3600; r->DAEMONIZE = 0; r->PREFER_SERVER_CIPHERS = 0; + config_param_val_pid_file(NULL, r->PID_FILE); + return r; } @@ -528,10 +555,10 @@ void config_param_validate (char *k, char *v, stud_config *cfg, char *file, int struct stat st; if (strcmp(k, "tls") == 0) { - //cfg->ENC_TLS = 1; + cfg->ETYPE = ENC_TLS; } else if (strcmp(k, "ssl") == 0) { - //cfg->ENC_TLS = 0; + cfg->ETYPE = ENC_SSL; } else if (strcmp(k, CFG_CIPHERS) == 0) { if (v != NULL && strlen(v) > 0) { @@ -619,7 +646,7 @@ void config_param_validate (char *k, char *v, stud_config *cfg, char *file, int } } else if (strcmp(k, CFG_QUIET) == 0) { - r = config_param_val_bool(v, &cfg->QUIET); + cfg->LOG_LEVEL = LOG_ERR; } else if (strcmp(k, CFG_SYSLOG) == 0) { r = config_param_val_bool(v, &cfg->SYSLOG); @@ -665,6 +692,9 @@ void config_param_validate (char *k, char *v, stud_config *cfg, char *file, int r = 0; } } + else if (strcmp(k, CFG_LOG_LEVEL) == 0) { + cfg->LOG_LEVEL = log_str2level(v); + } else if (strcmp(k, CFG_DAEMON) == 0) { r = config_param_val_bool(v, &cfg->DAEMONIZE); } @@ -687,6 +717,12 @@ void config_param_validate (char *k, char *v, stud_config *cfg, char *file, int config_assign_str(&cfg->CERT_FILE, v); } } + else if (strcmp(k, CFG_INSTANCE_NAME) == 0) { + stud_instance_name(v); + } + else if (strcmp(k, CFG_PID_FILE) == 0) { + r = config_param_val_pid_file(v, cfg->PID_FILE); + } else { fprintf( stderr, @@ -696,17 +732,19 @@ void config_param_validate (char *k, char *v, stud_config *cfg, char *file, int } if (! r) { - if (file != NULL) - config_die("Error in configuration file '%s', line %d: %s\n", file, line, config_error_get()); - else - config_die("Invalid parameter '%s': %s", k, config_error_get()); + if (file != NULL) { + die("Error in configuration file '%s', line %d: %s\n", file, line, config_error_get()); + } else { + die("Invalid parameter '%s': %s", k, config_error_get()); + } } } #ifndef NO_CONFIG_FILE int config_file_parse (char *file, stud_config *cfg) { - if (cfg == NULL) - config_die("Undefined stud options; THIS IS A BUG!\n"); + if (cfg == NULL) { + die("Undefined stud options; THIS IS A BUG!\n"); + } char line[CONFIG_BUF_SIZE]; FILE *fd = NULL; @@ -717,8 +755,26 @@ int config_file_parse (char *file, stud_config *cfg) { } else { fd = fopen(file, "r"); } - if (fd == NULL) - config_die("Unable to open configuration file '%s': %s\n", file, strerror(errno)); + if (fd == NULL) { + die("Unable to open configuration file '%s': %s\n", file, strerror(errno)); + } + + // assign stud instance name + char *bn = strdup(basename(file)); + if (bn != NULL) { + char *ptr = bn + strlen(bn); + while (ptr > bn) { + if (*ptr == '.') { + *ptr = '\0'; + break; + } + ptr--; + } + str_trim(bn); + stud_instance_name(bn); + config_param_val_pid_file(NULL, cfg->PID_FILE); + free(bn); + } // read config int i = 0; @@ -737,8 +793,6 @@ int config_file_parse (char *file, stud_config *cfg) { if (val == NULL) continue; str_trim(val); - // printf("File '%s', line %d, key: '%s', value: '%s'\n", file, i, key, val); - // validate configuration key => value config_param_validate(key, val, cfg, file, i); } @@ -894,9 +948,13 @@ void config_print_usage_fd (char *prog, stud_config *cfg, FILE *out) { fprintf(out, " -q --quiet Be quiet; emit only error messages\n"); fprintf(out, " -s --syslog Send log message to syslog in addition to stderr/stdout\n"); fprintf(out, " --syslog-facility=FACILITY Syslog facility to use (Default: \"%s\")\n", config_disp_log_facility(cfg->SYSLOG_FACILITY)); + fprintf(out, " --log-level=NAME Log level (Default: \"%s\")\n", config_disp_str(log_level2str(cfg->LOG_LEVEL))); + fprintf(out, " --instance-name Instance name (Default: \"%s\")\n", config_disp_str(stud_instance_name(NULL))); fprintf(out, "\n"); fprintf(out, "OTHER OPTIONS:\n"); fprintf(out, " --daemon Fork into background and become a daemon (Default: %s)\n", config_disp_bool(cfg->DAEMONIZE)); + fprintf(out, " -p --pid-file=FILE Save daemon's pid to specified file (Default: \"%s\")\n", config_disp_str(cfg->PID_FILE)); + fprintf(out, "\n"); fprintf(out, " --write-ip Write 1 octet with the IP family followed by the IP\n"); fprintf(out, " address in 4 (IPv4) or 16 (IPv6) octets little-endian\n"); fprintf(out, " to backend before the actual data\n"); @@ -1044,12 +1102,6 @@ void config_print_default (FILE *fd, stud_config *cfg) { fprintf(fd, FMT_QSTR, CFG_GROUP, config_disp_gid(cfg->GID)); fprintf(fd, "\n"); - fprintf(fd, "# Quiet execution, report only error messages\n"); - fprintf(fd, "#\n"); - fprintf(fd, "# type: boolean\n"); - fprintf(fd, FMT_STR, CFG_QUIET, config_disp_bool(cfg->QUIET)); - fprintf(fd, "\n"); - fprintf(fd, "# Use syslog for logging\n"); fprintf(fd, "#\n"); fprintf(fd, "# type: boolean\n"); @@ -1062,12 +1114,30 @@ void config_print_default (FILE *fd, stud_config *cfg) { fprintf(fd, FMT_QSTR, CFG_SYSLOG_FACILITY, config_disp_log_facility(cfg->SYSLOG_FACILITY)); fprintf(fd, "\n"); + fprintf(fd, "# Log level\n"); + fprintf(fd, "# Available levels: fatal, error, warning, notice, info, debug\n"); + fprintf(fd, "# type: string\n"); + fprintf(fd, FMT_QSTR, CFG_LOG_LEVEL, config_disp_str(log_level2str(cfg->LOG_LEVEL))); + fprintf(fd, "\n"); + + fprintf(fd, "# Instance name (used for syslog ident)\n"); + fprintf(fd, "# type: string\n"); + fprintf(fd, FMT_QSTR, CFG_INSTANCE_NAME, config_disp_str(stud_instance_name(NULL))); + fprintf(fd, "\n"); + fprintf(fd, "# Run as daemon\n"); fprintf(fd, "#\n"); fprintf(fd, "# type: boolean\n"); fprintf(fd, FMT_STR, CFG_DAEMON, config_disp_bool(cfg->DAEMONIZE)); fprintf(fd, "\n"); + fprintf(fd, "# Pid file\n"); + fprintf(fd, "# NOTE: Pid file is automatically computed from instance name.\n"); + fprintf(fd, "#\n"); + fprintf(fd, "# type: string\n"); + fprintf(fd, "# %s = \"%s\"\n", CFG_PID_FILE, config_disp_str(cfg->PID_FILE)); + fprintf(fd, "\n"); + fprintf(fd, "# Report client address by writing IP before sending data\n"); fprintf(fd, "#\n"); fprintf(fd, "# NOTE: This option is mutually exclusive with option %s.\n", CFG_WRITE_PROXY); @@ -1127,9 +1197,12 @@ void config_parse_cli(int argc, char **argv, stud_config *cfg) { { CFG_QUIET, 0, NULL, 'q' }, { CFG_SYSLOG, 0, NULL, 's' }, { CFG_SYSLOG_FACILITY, 1, NULL, CFG_PARAM_SYSLOG_FACILITY }, + { CFG_LOG_LEVEL, 1, NULL, CFG_PARAM_LOG_LEVEL }, + { CFG_INSTANCE_NAME, 1, NULL, CFG_PARAM_INSTANCE_NAME }, { CFG_DAEMON, 0, &cfg->DAEMONIZE, 1 }, { CFG_WRITE_IP, 0, &cfg->WRITE_IP_OCTET, 1 }, { CFG_WRITE_PROXY, 0, &cfg->WRITE_PROXY_LINE, 1 }, + { CFG_PID_FILE, 1, NULL, 'p' }, { "test", 0, NULL, 't' }, { "version", 0, NULL, 'V' }, @@ -1141,7 +1214,7 @@ void config_parse_cli(int argc, char **argv, stud_config *cfg) { int option_index = 0; c = getopt_long( argc, argv, - "c:e:Ob:f:n:B:C:U:P:M:k:r:u:g:qstVh", + "c:e:Ob:f:n:B:C:U:P:M:k:r:u:g:qsp:tVh", long_options, &option_index ); @@ -1153,8 +1226,9 @@ void config_parse_cli(int argc, char **argv, stud_config *cfg) { break; #ifndef NO_CONFIG_FILE case CFG_PARAM_CFGFILE: - if (!config_file_parse(optarg, cfg)) - config_die("%s", config_error_get()); + if (!config_file_parse(optarg, cfg)) { + die("%s", config_error_get()); + } break; case CFG_PARAM_DEFCFG: config_print_default(stdout, cfg); @@ -1164,6 +1238,9 @@ void config_parse_cli(int argc, char **argv, stud_config *cfg) { case CFG_PARAM_SYSLOG_FACILITY: config_param_validate(CFG_SYSLOG_FACILITY, optarg, cfg, NULL, 0); break; + case CFG_PARAM_LOG_LEVEL: + config_param_validate(CFG_LOG_LEVEL, optarg, cfg, NULL, 0); + break; case 'c': config_param_validate(CFG_CIPHERS, optarg, cfg, NULL, 0); break; @@ -1212,11 +1289,17 @@ void config_parse_cli(int argc, char **argv, stud_config *cfg) { config_param_validate(CFG_GROUP, optarg, cfg, NULL, 0); break; case 'q': - config_param_validate(CFG_QUIET, CFG_BOOL_ON, cfg, NULL, 0); + config_param_validate(CFG_LOG_LEVEL, LSTR_ERR, cfg, NULL, 0); + break; + case CFG_PARAM_INSTANCE_NAME: + config_param_validate(CFG_INSTANCE_NAME, optarg, cfg, NULL, 0); break; case 's': config_param_validate(CFG_SYSLOG, CFG_BOOL_ON, cfg, NULL, 0); break; + case 'p': + config_param_validate(CFG_PID_FILE, optarg, cfg, NULL, 0); + break; case 't': test_only = 1; break; @@ -1230,14 +1313,15 @@ void config_parse_cli(int argc, char **argv, stud_config *cfg) { break; default: - config_die("Invalid command line parameters. Run %s --help for instructions.", basename(argv[0])); + die("Invalid command line parameters. Run %s --help for instructions.", basename(argv[0])); } } prog = argv[0]; - if (tls && ssl) - config_die("Options --tls and --ssl are mutually exclusive."); + if (tls && ssl) { + die("Options --tls and --ssl are mutually exclusive."); + } else { if (ssl) cfg->ETYPE = ENC_SSL; @@ -1245,17 +1329,18 @@ void config_parse_cli(int argc, char **argv, stud_config *cfg) { cfg->ETYPE = ENC_TLS; } - if (cfg->WRITE_IP_OCTET && cfg->WRITE_PROXY_LINE) - config_die("Options --write-ip and --write-proxy are mutually exclusive."); + if (cfg->WRITE_IP_OCTET && cfg->WRITE_PROXY_LINE) { + die("Options --write-ip and --write-proxy are mutually exclusive."); + } if (cfg->DAEMONIZE) { cfg->SYSLOG = 1; - cfg->QUIET = 1; } #ifdef USE_SHARED_CACHE - if (cfg->SHCUPD_IP != NULL && ! cfg->SHARED_CACHE) - config_die("Shared cache update listener is defined, but shared cache is disabled."); + if (cfg->SHCUPD_IP != NULL && ! cfg->SHARED_CACHE) { + die("Shared cache update listener is defined, but shared cache is disabled."); + } #endif // argv leftovers, do we have pem file as an argument? @@ -1263,14 +1348,15 @@ void config_parse_cli(int argc, char **argv, stud_config *cfg) { argv += optind; if (argv != NULL && argv[0] != NULL) config_param_validate(CFG_PEM_FILE, argv[0], cfg, NULL, 0); - else if (cfg->CERT_FILE == NULL || strlen(cfg->CERT_FILE) < 1) - config_die("No x509 certificate PEM file specified!"); + else if (cfg->CERT_FILE == NULL || strlen(cfg->CERT_FILE) < 1) { + fail("No x509 certificate PEM file specified!"); + } // was this only a test? if (test_only) { fprintf(stderr, "Trying to initialize SSL context with certificate '%s'\n", cfg->CERT_FILE); if (! init_openssl()) - config_die("Error initializing OpenSSL."); + die("Error initializing OpenSSL."); printf("%s configuration looks ok.\n", basename(prog)); exit(0); } diff --git a/configuration.h b/configuration.h index 44be7f6..e60f08b 100644 --- a/configuration.h +++ b/configuration.h @@ -6,6 +6,7 @@ */ #include +#include #ifdef USE_SHARED_CACHE #include "shctx.h" @@ -51,12 +52,13 @@ struct __stud_config { char *SHCUPD_MCASTIF; char *SHCUPD_MCASTTTL; #endif - int QUIET; int SYSLOG; int SYSLOG_FACILITY; + int LOG_LEVEL; int TCP_KEEPALIVE_TIME; int DAEMONIZE; int PREFER_SERVER_CIPHERS; + char PID_FILE[PATH_MAX]; }; typedef struct __stud_config stud_config; diff --git a/debian/changelog b/debian/changelog index c4d45a5..2c25113 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,25 @@ +stud (0.3~0.2012061401) unstable; urgency=low + + * fixes --write-proxy + + -- Lars van de Kerkhof Thu, 14 Jun 2012 9:39:41 +0100 + +stud (0.3~0.2012052301) unstable; urgency=low + + * changed default pid file location + + -- Charlie Root Wed, 23 May 2012 14:15:41 +0100 + +stud (0.3~0.2012051501) unstable; urgency=low + + * Merged native configuration file support + * Added init script :) + + -- Charlie Root Tue, 15 May 2012 23:03:41 +0200 + stud (0.3~0.20111212) unstable; urgency=low * Initial release. - -- Charlie Root Mon, 12 Dec 2011 13:24:18 +0100 + -- Charlie Root Mon, 12 Dec 2011 13:24:18 +0100 diff --git a/debian/rules b/debian/rules index aa6b51e..29cc8cb 100755 --- a/debian/rules +++ b/debian/rules @@ -27,6 +27,11 @@ override_dh_auto_install: chmod 700 $(CURDIR)/debian/stud/etc/stud echo "Run /etc/init.d/stud --sample-config > /etc/stud/something.conf for default instance configuration" >> "$(CURDIR)/debian/stud/etc/stud/README.TXT" + # add init script + mkdir -p $(CURDIR)/debian/stud/etc/init.d + cp -a $(CURDIR)/init.stud $(CURDIR)/debian/stud/etc/init.d/stud + chmod 755 $(CURDIR)/debian/stud/etc/init.d/stud + %: dh $@ diff --git a/init.stud b/init.stud index 0dba4c5..4c0d2eb 100755 --- a/init.stud +++ b/init.stud @@ -21,139 +21,17 @@ CONFIG_DIR="/etc/stud" # Runtime directory data RUNTIME_DIR="/var/run/stud" -####################################################### +# filedescriptor limit +ULIMIT_N=100000 ####################################################### -stud_single_instance_config_reset() { -####################################################### -# stud instance configuration # -####################################################### - -# stud listening address -FRONTEND_ADDRESS="*,8443" - -# upstream service address -BACKEND_ADDRESS="127.0.0.1,80" - -# x509 certificate file -CERT_FILE="" - -# TLS only service? Don't set this to 1 if you're -# offloading HTTPS. -TLS_ONLY="0" - -# cipher suite (run openssl ciphers for full list) -CIPHER_SUITE="HIGH" - -# OpenSSL engine -ENGINE="" - -# Number of worker processes -WORKERS="1" - -# Listen backlog -BACKLOG="" - -# Chroot directory -CHROOT_DIR="" - -# drop privileges and run as specified -# user if set -SETUID_USER="" - -# use shared cache with specified number of sessions -# WARNING: stud must be compiled with USE_SHARED_CACHE=1 -SHARED_CACHE_SESSIONS="0" - -# Accept cache updates on specified address -# -# syntax: HOST,PORT -# -# WARNING: stud must be compiled with USE_SHARED_CACHE=1 -# SHARED_CACHE_SESSIONS must be >= 1 -CACHE_UPDATE_ACCEPT="" - -# Send cache updates to specified list space separated peers -# -# syntax: HOST1,PORT HOST2,PORT -# -# WARNING: stud must be compiled with USE_SHARED_CACHE=1 -# and CACHE_UPDATE_ACCEPT must be defined -CACHE_UPDATE_SEND="" - -# Force network interface and ttl to receive and send multicast -# cache updates -# -# syntax: IFACE[,TTL] -# -# WARNING: stud must be compiled with USE_SHARED_CACHE=1 -# and CACHE_UPDATE_ACCEPT must be defined -CACHE_UPDATE_IFACE="" - -# default tcp keepalive on client socket in seconds -CLIENT_TCP_KEEPALIVE_SEC="" - -# log to syslog? -SYSLOG="1" - -# Enable write-ip? -WRITE_IP="0" - -# Enable SENDPROXY protocol; see -# http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt -# for additional info -WRITE_PROXY="0" - -# Alternative OpenSSL library dir -# Use this if you'd like to run stud with different -# version of OpenSSL library -OPENSSL_LIB_DIR="" - -# Semicolon separated list of process affinities; requires -# taskset(8) utility. -# -# SYNTAX: -# ":;:;..." -# -# : stud worker process number, starting with 1 -# : process affinity, see taskset(8) for details -# -# EXAMPLES: -# -# "1:0" => bind first process to CPU0 -# -# "1:0;2:3-4;3:5;4:7" => bind first worker process to CPU0, -# second worker process to CPU3 and CPU4, -# third worker process to CPU5 and fourth -# worker process to CPU7 -PROCESS_AFFINITY="" - -# Process priority (integer between -19 to 19) -# lower value means higher priority -# -PROCESS_PRIORITY="" - -# ulimit -n value before starting single stud instance -# -# Comment out or set to 0 to disable ulimit -n -# setup. -# -ULIMIT_N="" - -# Additional stud command line options -# -# NOTE: set this only if you really know what your're -# doing -# -# ADDITIONAL_STUD_OPT="" - -# EOF -} - PATH="${PATH}:." INSTANCE_NAME="" STUD=`which stud 2>/dev/null` +uid=`id -u` + +test "${uid}" != "0" && RUNTIME_DIR="/tmp" die() { msg_log "FATAL: $@" @@ -173,90 +51,22 @@ msg_err() { _real_single_instance_start() { + cfg="${1}" + instance_name="" + if [ ! -f "${cfg}" ] || [ ! -r "${cfg}" ]; then + instance_name="${cfg}" + cfg="${CONFIG_DIR}/${cfg}.conf" + if [ ! -f "${cfg}" ] || [ ! -r "${cfg}" ]; then + die "Invalid configuration file '${cfg}'." + fi + fi # check stud binary if [ -z "${STUD}" ] || [ ! -f "${STUD}" ] || [ ! -x "${STUD}" ]; then die "Invalid stud binary: '${STUD}'" fi - # generate stud command line options - opts="-f ${FRONTEND_ADDRESS}" - opts="${opts} -b ${BACKEND_ADDRESS}" - - if [ "${TLS_ONLY}" = "1" ]; then - opts="${opts} --tls" - else - opts="${opts} --ssl" - fi - - test ! -z "${CIPHER_SUITE}" && opts="${opts} -c ${CIPHER_SUITE}" - test ! -z "${ENGINE}" && opts="${opts} -e ${ENGINE}" - - if [ ! -z "${WORKERS}" ] && [ ${WORKERS} -gt 0 ]; then - opts="${opts} -n ${WORKERS}" - fi - - if [ ! -z "${BACKLOG}" ] && [ ${BACKLOG} -gt 0 ]; then - opts="${opts} -B ${BACKLOG}" - fi - - if [ ! -z "${CLIENT_TCP_KEEPALIVE_SEC}" ] && [ ${CLIENT_TCP_KEEPALIVE_SEC} -gt 0 ]; then - opts="${opts} -k ${CLIENT_TCP_KEEPALIVE_SEC}" - fi - - # shared cache sessions... - if [ ! -z "${SHARED_CACHE_SESSIONS}" ] && [ ${SHARED_CACHE_SESSIONS} -gt 0 ]; then - opts="${opts} -C ${SHARED_CACHE_SESSIONS}" - - # shared cache stuff - if [ ! -z "${CACHE_UPDATE_ACCEPT}" ]; then - opts="${opts} -U ${CACHE_UPDATE_ACCEPT}" - - c_u=0 - for h in ${CACHE_UPDATE_SEND}; do - test ! -z "${h}" || continue - opts="${opts} -P ${h}" - c_u=$((c_u + 1)) - done - if [ ${c_u} -lt 1 ]; then - die "Cache updates are enabled but CACHE_UPDATE_SEND option seems to be empty." - fi - - if [ ! -z "${CACHE_UPDATE_IFACE}" ]; then - opts="${opts} -M ${CACHE_UPDATE_IFACE}" - fi - fi - - fi - - # chroot? - test ! -z "${CHROOT_DIR}" && opts="${opts} -r ${CHROOT_DIR}" - test ! -z "${SETUID_USER}" && opts="${opts} -u ${SETUID_USER}" - - opts="${opts} -q" - test "${SYSLOG}" = "1" && opts="${opts} -s" - - test "${WRITE_IP}" = "1" && opts="${opts} --write-ip" - test "${WRITE_PROXY}" = "1" && opts="${opts} --write-proxy" - - if [ ! -z "${CERT_FILE}" ] && [ -f "${CERT_FILE}" ] && [ -r "${CERT_FILE}" ]; then - opts="${opts} ${CERT_FILE}" - else - die "Invalid or unreadable certificate file '${CERT_FILE}'." - fi - - # additional command line options?! - if [ ! -z "${ADDITIONAL_STUD_OPT}" ]; then - opts="${opts} ${ADDITIONAL_STUD_OPT}" - fi - - # priority?! - prefix="" - if [ ! -z "${PROCESS_PRIORITY}" ]; then - prefix="nice -n ${PROCESS_PRIORITY}" - fi - # we want to start stud in a daemon mode... - opts="${opts} --daemon" + opts="--config ${cfg} --daemon" # set ulimits! ulimit_set || die "Unable to set stud runtime limits." @@ -265,13 +75,13 @@ _real_single_instance_start() { unset LD_LIBRARY_PATH # set new lib path if requested - if [ ! -z "${OPENSSL_LIB_DIR}" -a -d "${OPENSSL_LIB_DIR}" ]; then + if [ ! -z "${OPENSSL_LIB_DIR}" ] && [ -d "${OPENSSL_LIB_DIR}" ]; then LD_LIBRARY_PATH="${OPENSSL_LIB_DIR}" export LD_LIBRARY_PATH fi # start stud! - msg_log "Starting instance '${INSTANCE_NAME}': ${STUD} ${opts}" + msg_log "Starting instance '${instance_name}': ${STUD} ${opts}" out=`${prefix} ${STUD} ${opts} 2>&1` # remove lib path @@ -283,17 +93,12 @@ _real_single_instance_start() { die "Empty stud pid. This is extremely weird." fi - # wait a little bit, check if pid is still alive - sleep 0.2 >/dev/null 2>&1 - if ! kill -0 "${stud_pid}" >/dev/null 2>&1; then - die "Stud started successfully as pid ${stud_pid} but died shortly after startup."; - fi - - # write pid file! - pid_file_write "${INSTANCE_NAME}" "${stud_pid}" || msg_warn "${Error}" + file="${RUNTIME_DIR}/${1}.pid" + echo "${stud_pid}" > "${file}" + return 0 # set affinity! - stud_affinity_set "${stud_pid}" || die "${Error}" + # stud_affinity_set "${stud_pid}" || die "${Error}" } stud_single_instance_start() { @@ -311,7 +116,7 @@ stud_single_instance_start() { # do the real stuff... Error="" - out=`_real_single_instance_start 2>&1` + out=`_real_single_instance_start "${name}" 2>&1` rv=$? if [ "${rv}" != "0" ]; then Error="${out}" @@ -354,7 +159,7 @@ stud_single_instance_stop() { sleep 0.1 >/dev/null 2>&1 done - # not ok?! try to with headshot... + # not ok?! shoot it in the head if [ "${ok}" != "1" ]; then msg_log "Gentle stop of instance ${name} failed, trying to stop it with SIGKILL." if ! kill -9 "${pid}"; then @@ -412,21 +217,6 @@ pid_file_read() { head -n 1 "${file}" } -# writes pid file for specific instance -pid_file_write() { - test -z "${1}" && return 1 - test -z "${2}" && return 1 - - # check runtime directory - if [ ! -e "${RUNTIME_DIR}" ] || [ ! -d "${RUNTIME_DIR}" ] || [ ! -w "${RUNTIME_DIR}" ]; then - # try to create directory - mkdir -p "${RUNTIME_DIR}" || die "Unable to create missing runtime directory '${RUNTIME_DIR}'" - fi - - file="${RUNTIME_DIR}/${1}.pid" - echo "${2}" > "${file}" -} - # lists running instances running_instance_list() { list="" @@ -468,17 +258,18 @@ stud_instances_start() { die "No stud instances configured in directory '${CONFIG_DIR}'." fi + # create runtime directory if necessary + if [ ! -d "${RUNTIME_DIR}" ]; then + mkdir -p "${RUNTIME_DIR}" || die "Unable to create runtime/pid directory ${RUNTIME_DIR}" + fi + echo "Starting stud instances:" num_ok=0 num_failed=0 for instance in ${list}; do echo -n " ${instance}: " - # load configuration - if ! stud_single_instance_config_load "${instance}"; then - echo "failed: ${Error}" - return 1 # start instance - elif stud_single_instance_start "${instance}"; then + if stud_single_instance_start "${instance}"; then echo "done." msg_log "Instance ${name} successfully started." num_ok=$((num_ok + 1)) @@ -540,12 +331,8 @@ stud_instances_restart() { for instance in ${list}; do echo -n " ${instance}: "; - # load configuration - if ! stud_single_instance_config_load "${instance}"; then - echo "failed: ${Error}" - return 1 # restart instance - elif stud_single_instance_restart "${instance}"; then + if stud_single_instance_restart "${instance}"; then echo "done." num_ok=$((num_ok + 1)) msg_log "Instance ${instance} successfully restarted." @@ -578,7 +365,7 @@ stud_instances_status() { fi for instance in ${list_all}; do - echo -n " ${instance}: " + printf " %-55s" "${instance}" if stud_single_instance_status "${instance}"; then echo "running as pid $Error" i=$((i + 1)) @@ -599,7 +386,7 @@ stud_config_instances_list() { for file in ${CONFIG_DIR}/*.conf; do test -f "${file}" -a -r "${file}" || continue fileb=`basename "${file}"` - name=`echo "${fileb}" | cut -d. -f1` + name=`echo "${fileb}" | sed -e 's/\.conf$//g'` test ! -z "${name}" || continue list="${list} ${name}" done @@ -608,28 +395,7 @@ stud_config_instances_list() { } stud_single_instance_config_print() { - head -n 151 "$0" | tail -n 123 -} - -stud_single_instance_config_load() { - file="${CONFIG_DIR}/${1}.conf" - INSTANCE_NAME="" - - # reset configuration - stud_single_instance_config_reset - Error='' - - if [ -f "${file}" -a -r "${file}" ]; then - . "${file}" >/dev/null || Error="Unable to load instance configuration file '${file}'." - else - Error="Invalid or unreadable instance configuration file '${file}'." - return 1 - fi - - # set instance name... - INSTANCE_NAME="${1}" - - return 0 + ${STUD} --default-config } stud_instance_worker_pids() { @@ -705,6 +471,9 @@ stud_affinity_set() { } ulimit_n_set() { + if [ "$uid" != "0" ]; then + return 0 + fi if [ -z "$ULIMIT_N" ] || [ "$ULIMIT_N" = "0" ]; then return 0 fi @@ -765,8 +534,19 @@ OPTIONS: EOF } +############################################################ +# MAIN # +############################################################ + +# try to load script configuration file +for dir in /etc/default /etc/sysconfig /usr/local/etc/default /usr/local/etc/sysconfig; do + f="${dir}/stud" + test -f "${f}" -a -r "${f}" || continue + . "${f}" >/dev/null 2>&1 && break +done + # parse command line... -TEMP=`getopt -o C:R:Vh --long config-dir:,runtime-dir:,sample-config,version,help -n "$MYNAME" -- "$@"` +TEMP=`getopt -o C:R:Vh --long config-dir:,runtime-dir:,sample-config,default-config,version,help -n "$MYNAME" -- "$@"` test "$?" != "0" && die "Invalid command line arguments. Run $MYNAME --help for instructions." eval set -- "$TEMP" while true; do @@ -779,7 +559,7 @@ while true; do RUNTIME_DIR="${2}" shift 2 ;; - --sample-config) + --sample-config|--default-config) stud_single_instance_config_print exit 0 ;; diff --git a/log.c b/log.c new file mode 100644 index 0000000..e90bb8c --- /dev/null +++ b/log.c @@ -0,0 +1,285 @@ +/** + * log.c + * + * Author: Brane F. Gracnar + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +#include "ringbuffer.h" +#include "stud.h" +#include "configuration.h" +#include "log.h" + + +#define TIMESTR_BUF_LEN 40 +#define TIMESTR_FMT "%Y/%m/%d %H:%M:%S.%%d" +#define SOCKSTR_BUF_LEN 48 +#define PSSTR_BUF_LEN 100 +#define LOG_BUF_LEN 1024 + +#define DOLOG(l) (l <= CONFIG->LOG_LEVEL) ? 1 : 0 + + +char buf_timestr[TIMESTR_BUF_LEN]; +char sockstr_buf[SOCKSTR_BUF_LEN]; +char psstr_buf[PSSTR_BUF_LEN]; + +static int logging_initialized = 0; + +extern stud_config *CONFIG; +extern int child_num; + +char * ts_as_str (char *dst) { + if (dst == NULL) dst = buf_timestr; + + char fmtbuf[TIMESTR_BUF_LEN]; + memset(fmtbuf, '\0', sizeof(fmtbuf)); + memset(dst, '\0', TIMESTR_BUF_LEN); + + // get cached loop time... + ev_tstamp t_ev = ev_now(EV_DEFAULT); + + time_t t = (time_t) t_ev; + struct tm *lt = localtime(&t); + strftime(fmtbuf, sizeof(fmtbuf), TIMESTR_FMT, lt); + + // add microtime + int frac = (t_ev - (long) t_ev) * 1000000; + snprintf(dst, TIMESTR_BUF_LEN, fmtbuf, frac); + + return dst; +} + +char * sock_as_str (int sock, char *dst) { + if (dst == NULL) dst = sockstr_buf; + memset(dst, '\0', SOCKSTR_BUF_LEN); + + struct sockaddr_storage addr; + char ipstr[INET6_ADDRSTRLEN]; + int port = 0; + + socklen_t len = sizeof(addr); + getpeername(sock, (struct sockaddr*)&addr, &len); + + // IPv4 socket? + if (addr.ss_family == AF_INET) { + struct sockaddr_in *s = (struct sockaddr_in *)&addr; + port = ntohs(s->sin_port); + inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof(ipstr)); + } + // IPv6 socket? + else if (addr.ss_family == AF_INET6) { + struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr; + port = ntohs(s->sin6_port); + inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof(ipstr)); + } + // UNIX domain socket? + else if (addr.ss_family == AF_UNIX) { + + } + + snprintf(dst, SOCKSTR_BUF_LEN, "[%s]:%d", ipstr, port); + return dst; +} + +char * ps_as_str (proxystate *ps, char *dst) { + char up_buf[SOCKSTR_BUF_LEN]; + char down_buf[SOCKSTR_BUF_LEN]; + + if (dst == NULL) dst = psstr_buf; + memset(dst, '\0', PSSTR_BUF_LEN); + + sock_as_str(ps->fd_up, up_buf); + sock_as_str(ps->fd_down, down_buf); + + snprintf(dst, PSSTR_BUF_LEN, "%s => %s", up_buf, down_buf); + + return dst; +} + +char buf_pcsig[10]; +char * proc_signature (char *dst) { + if (child_num < 0 || child_num >= CONFIG->NCORES) + return "master"; + else { + if (dst == NULL) dst = buf_pcsig; + + // already cached stuff? + if (dst == buf_pcsig && buf_pcsig[0] != '\0') return dst; + + memset(dst, '\0', sizeof(buf_pcsig)); + snprintf(dst, sizeof(buf_pcsig), "worker #%d", child_num); + } + + return dst; +} + +char * log_level2str (int level) { + switch (level) { + case LOG_EMERG: + return LSTR_FATAL; + break; + case LOG_ERR: + return LSTR_ERR; + break; + case LOG_WARNING: + return LSTR_WARN; + break; + case LOG_NOTICE: + return LSTR_NOTICE; + break; + case LOG_INFO: + return LSTR_INFO; + break; + case LOG_DEBUG: + return LSTR_DEBUG; + break; + default: + return LSTR_UNKNOWN; + } +} + +int log_str2level (char *str) { + int r = LOG_NOTICE; + if (str == NULL || strlen(str) < 1) return r; + + if (strcasecmp(str, LSTR_FATAL) == 0) + r = LOG_EMERG; + else if (strcasecmp(str, LSTR_ERR) == 0) + r = LOG_ERR; + else if (strcasecmp(str, LSTR_WARN) == 0 || strcasecmp(str, "warn") == 0) + r = LOG_WARNING; + else if (strcasecmp(str, LSTR_NOTICE) == 0) + r = LOG_NOTICE; + else if (strcasecmp(str, LSTR_INFO) == 0) + r = LOG_INFO; + else if (strcasecmp(str, LSTR_DEBUG) == 0) + r = LOG_DEBUG; + + return r; +} + +char buf_syslog_ident[128]; +char * log_syslog_ident (void) { + char *n = stud_instance_name(NULL); + if (n == NULL || strlen(n) < 1) + return "stud"; + + snprintf(buf_syslog_ident, sizeof(buf_syslog_ident), "stud/%s", n); + return buf_syslog_ident; +} + +void log_init (void) { + if (logging_initialized) return; + if (CONFIG->SYSLOG) { + openlog(log_syslog_ident(), LOG_CONS | LOG_PID | LOG_NDELAY, CONFIG->SYSLOG_FACILITY); + } +} + +void log_msg (int level, char *fmt, ...) { + va_list args; + char buf[LOG_BUF_LEN]; + + //printf("LCFG LLEVEL: %d, LLEVEL: %d\n", CONFIG->LOG_LEVEL, level); + if (! DOLOG(level)) return; + //printf("DAEMONIZE: %d\n", CONFIG->DAEMONIZE); + //printf("SYSLOG: %d\n", CONFIG->SYSLOG); + if (CONFIG->DAEMONIZE && ! CONFIG->SYSLOG) return; + + // format log message + memset(buf, '\0', LOG_BUF_LEN); + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + if (! CONFIG->DAEMONIZE) { + fprintf(stderr, "[%s] %-10s %-7s %s\n", ts_as_str(NULL), proc_signature(NULL), log_level2str(level), buf); + } + + if (CONFIG->SYSLOG) { + syslog(level, "%s %s", proc_signature(NULL), buf); + } +} + + +void log_msg_ps (int level, proxystate *ps, char *fmt, ...) { + va_list args; + char buf[LOG_BUF_LEN]; + + if (! DOLOG(level)) return; + + // format log message + memset(buf, '\0', LOG_BUF_LEN); + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + log_msg(level, "%s %s", ps_as_str(ps, NULL), buf); +} + +void log_msg_sock (int level, int sock, char *fmt, ...) { + va_list args; + char buf[LOG_BUF_LEN]; + + if (! DOLOG(level)) return; + + // format log message + memset(buf, '\0', LOG_BUF_LEN); + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + log_msg(level, "%s %s", sock_as_str(sock, NULL), buf); +} + +void log_msg_lps (int level, int listener, proxystate *ps, char *fmt, ...) { + va_list args; + char buf[LOG_BUF_LEN]; + + if (! DOLOG(level)) return; + + // format log message + memset(buf, '\0', LOG_BUF_LEN); + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + log_msg( + level, "[%s %s] %s", sock_as_str(listener, NULL), + ps_as_str(ps, NULL), buf + ); +} + +void fail (char *fmt, ...) { + va_list args; + char buf[LOG_BUF_LEN]; + + // format log message + memset(buf, '\0', LOG_BUF_LEN); + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + die("%s %s", buf, strerror(errno)); +} diff --git a/log.h b/log.h new file mode 100644 index 0000000..ffcff59 --- /dev/null +++ b/log.h @@ -0,0 +1,107 @@ +/** + * log.h + * + * Author: Brane F. Gracnar + * + */ + +// "Initializes" logging subsystem +void log_init (void); + +// Writes timestamp (including microseconds) to dst. +// If dst == NULL uses it's own buffer. +char * ts_as_str (char *dst); + +// Writes string representation of proxystate structure to dst. +// If dst == NULL uses it's own buffer. +char * ps_as_str (proxystate *ps, char *dst); + +// Writes string representation of a socket to dst. +// If dst == NULL uses it's own buffer. +char * sock_as_str (int sock, char *dst); + +char * log_level2str (int level); +int log_str2level (char *str); + +/** + * Log level names + */ + +#define LSTR_FATAL "FATAL" +#define LSTR_ERR "ERROR" +#define LSTR_WARN "WARNING" +#define LSTR_NOTICE "NOTICE" +#define LSTR_INFO "INFO" +#define LSTR_DEBUG "DEBUG" +#define LSTR_UNKNOWN "UNKNOWN" + +/** + * General purpose logging functions + */ + +void log_msg (int level, char *fmt, ...); + +#define log_fatal(...) log_msg(LOG_EMERG, __VA_ARGS__) +#define log_err(...) log_msg(LOG_ERR, __VA_ARGS__) +#define log_warn(...) log_msg(LOG_WARNING, __VA_ARGS__) +#define log_notice(...) log_msg(LOG_NOTICE, __VA_ARGS__) +#define log_info(...) log_msg(LOG_INFO, __VA_ARGS__) +#define log_debug(...) log_msg(LOG_DEBUG, __VA_ARGS__) + +/** + * Proxy state logging "functions" + */ + +void log_msg_ps (int level, proxystate *ps, char *fmt, ...); + +#define log_fatal_ps(...) log_msg_ps(LOG_EMERG, __VA_ARGS__) +#define log_err_ps(...) log_msg_ps(LOG_ERR, __VA_ARGS__) +#define log_warn_ps(...) log_msg_ps(LOG_WARNING, __VA_ARGS__) +#define log_notice_ps(...) log_msg_ps(LOG_NOTICE, __VA_ARGS__) +#define log_info_ps(...) log_msg_ps(LOG_INFO, __VA_ARGS__) +#define log_debug_ps(...) log_msg_ps(LOG_DEBUG, __VA_ARGS__) + +/** + * Socket logging "functions" + */ + +void log_msg_sock (int level, int sock, char *fmt, ...); + +#define log_fatal_sock(...) log_msg_sock(LOG_EMERG, __VA_ARGS__) +#define log_err_sock(...) log_msg_sock(LOG_ERR, __VA_ARGS__) +#define log_warn_sock(...) log_msg_sock(LOG_WARNING, __VA_ARGS__) +#define log_notice_sock(...) log_msg_sock(LOG_NOTICE, __VA_ARGS__) +#define log_info_sock(...) log_msg_sock(LOG_INFO, __VA_ARGS__) +#define log_debug_sock(...) log_msg_sock(LOG_DEBUG, __VA_ARGS__) + +/** + * Socket and proxy state logging functions + */ + +void log_msg_lps (int level, int listener, proxystate *ps, char *fmt, ...); + +#define log_fatal_lps(...) log_msg_lps(LOG_EMERG, __VA_ARGS__) +#define log_err_lps(...) log_msg_lps(LOG_ERR, __VA_ARGS__) +#define log_warn_lps(...) log_msg_lps(LOG_WARNING, __VA_ARGS__) +#define log_notice_lps(...) log_msg_lps(LOG_NOTICE, __VA_ARGS__) +#define log_info_lps(...) log_msg_lps(LOG_INFO, __VA_ARGS__) +#define log_debug_lps(...) log_msg_lps(LOG_DEBUG, __VA_ARGS__) + + +/** + * Fatal logging "functions" + */ + +void fail (char *fmt, ...); + +#define die(...) \ + log_msg(LOG_CRIT, __VA_ARGS__); \ + exit(1) + +#define die_ps(...) \ + log_msg_ps(LOG_CRIT, __VA_ARGS__); \ + exit(1) + +#define die_sock(...) \ + log_msg_sock(LOG_CRIT, __VA_ARGS__); \ + exit(1) diff --git a/stud.c b/stud.c index 0ed6581..cdb97b2 100644 --- a/stud.c +++ b/stud.c @@ -59,9 +59,11 @@ #include #include +#include "stud.h" #include "ringbuffer.h" #include "shctx.h" #include "configuration.h" +#include "log.h" #ifndef MSG_NOSIGNAL # define MSG_NOSIGNAL 0 @@ -86,7 +88,7 @@ static struct addrinfo *backaddr; static pid_t master_pid; static ev_io listener; static int listener_socket; -static int child_num; +int child_num = -1; static pid_t *child_pids; static SSL_CTX *ssl_ctx; @@ -109,58 +111,6 @@ stud_config *CONFIG; static char tcp_proxy_line[128] = ""; -/* What agent/state requests the shutdown--for proper half-closed - * handling */ -typedef enum _SHUTDOWN_REQUESTOR { - SHUTDOWN_HARD, - SHUTDOWN_DOWN, - SHUTDOWN_UP -} SHUTDOWN_REQUESTOR; - -/* - * Proxied State - * - * All state associated with one proxied connection - */ -typedef struct proxystate { - ringbuffer ring_down; /* pushing bytes from client to backend */ - ringbuffer ring_up; /* pushing bytes from backend to client */ - - ev_io ev_r_up; /* Upstream write event */ - ev_io ev_w_up; /* Upstream read event */ - - ev_io ev_r_handshake; /* Downstream write event */ - ev_io ev_w_handshake; /* Downstream read event */ - - ev_io ev_r_down; /* Downstream write event */ - ev_io ev_w_down; /* Downstream read event */ - - int fd_up; /* Upstream (client) socket */ - int fd_down; /* Downstream (backend) socket */ - - int want_shutdown:1; /* Connection is half-shutdown */ - int handshaked:1; /* Initial handshake happened */ - int renegotiation:1; /* Renegotation is occuring */ - - SSL *ssl; /* OpenSSL SSL state */ - - struct sockaddr_storage remote_ip; /* Remote ip returned from `accept` */ -} proxystate; - -#define LOG(...) \ - do { \ - if (!CONFIG->QUIET) fprintf(stdout, __VA_ARGS__); \ - if (CONFIG->SYSLOG) syslog(LOG_INFO, __VA_ARGS__); \ - } while(0) - -#define ERR(...) \ - do { \ - fprintf(stderr, __VA_ARGS__); \ - if (CONFIG->SYSLOG) syslog(LOG_ERR, __VA_ARGS__); \ - } while(0) - -#define NULL_DEV "/dev/null" - /* set a file descriptor (socket) to non-blocking mode */ static void setnonblocking(int fd) { int flag = 1; @@ -174,32 +124,18 @@ static void settcpkeepalive(int fd) { socklen_t optlen = sizeof(optval); if(setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0) { - ERR("Error activating SO_KEEPALIVE on client socket: %s", strerror(errno)); + log_err("Error activating SO_KEEPALIVE on client socket: %s", strerror(errno)); } optval = CONFIG->TCP_KEEPALIVE_TIME; optlen = sizeof(optval); #ifdef TCP_KEEPIDLE if(setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &optval, optlen) < 0) { - ERR("Error setting TCP_KEEPIDLE on client socket: %s", strerror(errno)); + log_err("Error setting TCP_KEEPIDLE on client socket: %s", strerror(errno)); } #endif } -static void fail(const char* s) { - perror(s); - exit(1); -} - -void die (char *fmt, ...) { - va_list args; - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); - - exit(1); -} - #ifndef OPENSSL_NO_DH static int init_dh(SSL_CTX *ctx, const char *cert) { DH *dh; @@ -216,13 +152,13 @@ static int init_dh(SSL_CTX *ctx, const char *cert) { dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); BIO_free(bio); if (!dh) { - ERR("{core} Note: no DH parameters found in %s\n", cert); + log_err("{core} Note: no DH parameters found in %s", cert); return -1; } - LOG("{core} Using DH parameters from %s\n", cert); + log_notice("{core} Using DH parameters from %s", cert); SSL_CTX_set_tmp_dh(ctx, dh); - LOG("{core} DH initialized with %d bit key\n", 8*DH_size(dh)); + log_notice("{core} DH initialized with %d bit key", 8*DH_size(dh)); DH_free(dh); #ifndef OPENSSL_NO_EC @@ -231,7 +167,7 @@ static int init_dh(SSL_CTX *ctx, const char *cert) { ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); SSL_CTX_set_tmp_ecdh(ctx,ecdh); EC_KEY_free(ecdh); - LOG("{core} ECDH Initialized with NIST P-256\n"); + log_notice("{core} ECDH Initialized with NIST P-256"); #endif /* NID_X9_62_prime256v1 */ #endif /* OPENSSL_NO_EC */ @@ -249,7 +185,7 @@ static void info_callback(const SSL *ssl, int where, int ret) { proxystate *ps = (proxystate *)SSL_get_app_data(ssl); if (ps->handshaked) { ps->renegotiation = 1; - LOG("{core} SSL renegotiation asked by client\n"); + log_info_ps(ps, "SSL renegotiation asked by client."); } } } @@ -352,23 +288,32 @@ static int create_shcupd_socket() { const int gai_err = getaddrinfo(CONFIG->SHCUPD_IP, CONFIG->SHCUPD_PORT, &hints, &ai); if (gai_err != 0) { - ERR("{getaddrinfo}: [%s]\n", gai_strerror(gai_err)); - exit(1); + die( + "Error creating shared cache update listening socket [%s]:%s: getaddrinfo: %s", + CONFIG->SHCUPD_IP, CONFIG->SHCUPD_PORT, + gai_strerror(gai_err) + ); } /* check if peers inet family addresses match */ while (*pai) { if ((*pai)->ai_family != ai->ai_family) { - ERR("Share host and peers inet family differs\n"); - exit(1); + die( + "Error creating shared cache update listening socket [%s]:%s: share host and peers inet family differs.", + CONFIG->SHCUPD_IP, CONFIG->SHCUPD_PORT + ); } pai++; } int s = socket(ai->ai_family, SOCK_DGRAM, IPPROTO_UDP); - if (s == -1) - fail("{socket: shared cache updates}"); + if (s == -1) { + fail( + "Error creating shared cache update listening socket [%s]:%s:", + CONFIG->SHCUPD_IP, CONFIG->SHCUPD_PORT + ); + } int t = 1; setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &t, sizeof(int)); @@ -390,8 +335,7 @@ static int create_shcupd_socket() { memset(&ifr, 0, sizeof(ifr)); if (strlen(CONFIG->SHCUPD_MCASTIF) > IFNAMSIZ) { - ERR("Error iface name is too long [%s]\n",CONFIG->SHCUPD_MCASTIF); - exit(1); + die("Error iface name is too long [%s].", CONFIG->SHCUPD_MCASTIF); } memcpy(ifr.ifr_name, CONFIG->SHCUPD_MCASTIF, strlen(CONFIG->SHCUPD_MCASTIF)); @@ -453,8 +397,7 @@ static int create_shcupd_socket() { memset(&ifr, 0, sizeof(ifr)); if (strlen(CONFIG->SHCUPD_MCASTIF) > IFNAMSIZ) { - ERR("Error iface name is too long [%s]\n",CONFIG->SHCUPD_MCASTIF); - exit(1); + die("Error iface name is too long [%s].", CONFIG->SHCUPD_MCASTIF); } memcpy(ifr.ifr_name, CONFIG->SHCUPD_MCASTIF, strlen(CONFIG->SHCUPD_MCASTIF)); @@ -501,7 +444,7 @@ static int create_shcupd_socket() { #endif /* IPV6_ADD_MEMBERSHIP */ if (bind(s, ai->ai_addr, ai->ai_addrlen)) { - fail("{bind-socket}"); + fail("{bind-socket}:"); } freeaddrinfo(ai); @@ -561,8 +504,7 @@ SSL_CTX * init_openssl() { rsa = load_rsa_privatekey(ctx, CONFIG->CERT_FILE); if(!rsa) { - ERR("Error loading rsa private key\n"); - exit(1); + fail("Error loading RSA private key:"); } if (SSL_CTX_use_RSAPrivateKey(ctx,rsa) <= 0) { @@ -586,7 +528,7 @@ SSL_CTX * init_openssl() { ERR_print_errors_fp(stderr); exit(1); } - LOG("{core} will use OpenSSL engine %s.\n", ENGINE_get_id(e)); + log_notice("{core} will use OpenSSL engine %s.", ENGINE_get_id(e)); ENGINE_finish(e); ENGINE_free(e); } @@ -602,13 +544,11 @@ SSL_CTX * init_openssl() { #ifdef USE_SHARED_CACHE if (CONFIG->SHARED_CACHE) { if (shared_context_init(ctx, CONFIG->SHARED_CACHE) < 0) { - ERR("Unable to alloc memory for shared cache.\n"); - exit(1); + fail("Unable to alloc memory for shared cache:"); } if (CONFIG->SHCUPD_PORT) { if (compute_secret(rsa, shared_secret) < 0) { - ERR("Unable to compute shared secret.\n"); - exit(1); + die("Unable to compute shared secret."); } /* Force tls tickets cause keys differs */ @@ -649,8 +589,7 @@ static void prepare_proxy_line(struct sockaddr* ai_addr) { assert(res < sizeof(tcp_proxy_line)); } else { - ERR("The --write-proxy mode is not implemented for this address family.\n"); - exit(1); + die("The --write-proxy mode is not implemented for this address family."); } } @@ -664,14 +603,21 @@ static int create_main_socket() { const int gai_err = getaddrinfo(CONFIG->FRONT_IP, CONFIG->FRONT_PORT, &hints, &ai); if (gai_err != 0) { - ERR("{getaddrinfo}: [%s]\n", gai_strerror(gai_err)); - exit(1); + die( + "Error creating listening socket [%s]:%s {getaddrinfo}: %s", + CONFIG->FRONT_IP, CONFIG->FRONT_PORT, + gai_strerror(gai_err) + ); } int s = socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP); - if (s == -1) - fail("{socket: main}"); + if (s == -1) { + fail( + "Error creating listening socket [%s]:%s", + CONFIG->FRONT_IP, CONFIG->FRONT_PORT + ); + } int t = 1; setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &t, sizeof(int)); @@ -681,7 +627,10 @@ static int create_main_socket() { setnonblocking(s); if (bind(s, ai->ai_addr, ai->ai_addrlen)) { - fail("{bind-socket}"); + fail( + "Error binding listening socket [%s]:%s", + CONFIG->FRONT_IP, CONFIG->FRONT_PORT + ); } #ifndef NO_DEFER_ACCEPT @@ -710,7 +659,7 @@ static int create_back_socket() { int flag = 1; int ret = setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag)); if (ret == -1) { - perror("Couldn't setsockopt to backend (TCP_NODELAY)\n"); + log_err_sock(s, "Couldn't setsockopt to backend (TCP_NODELAY): %s", strerror(errno)); } int t = 1; @@ -719,7 +668,7 @@ static int create_back_socket() { if (t == 0 || errno == EINPROGRESS || errno == EINTR) return s; - perror("{backend-connect}"); + log_err_sock(s, "Unable to connect to backend: %s", strerror(errno)); return -1; } @@ -765,11 +714,11 @@ static void handle_socket_errno(proxystate *ps) { return; if (errno == ECONNRESET) - ERR("{backend} Connection reset by peer\n"); + log_err("{backend} Connection reset by peer"); else if (errno == ETIMEDOUT) - ERR("{backend} Connection to backend timed out\n"); + log_err("{backend} Connection to backend timed out"); else if (errno == EPIPE) - ERR("{backend} Broken pipe to backend (EPIPE)\n"); + log_err("{backend} Broken pipe to backend (EPIPE)"); else perror("{backend} [errno]"); shutdown_proxy(ps, SHUTDOWN_DOWN); @@ -798,7 +747,7 @@ static void back_read(struct ev_loop *loop, ev_io *w, int revents) { safe_enable_io(ps, &ps->ev_w_up); } else if (t == 0) { - LOG("{backend} Connection closed\n"); + log_info_ps(ps, "{backend} Connection closed"); shutdown_proxy(ps, SHUTDOWN_DOWN); } else { @@ -806,6 +755,7 @@ static void back_read(struct ev_loop *loop, ev_io *w, int revents) { handle_socket_errno(ps); } } + /* Write some data, previously received on the secure upstream socket, * out of the downstream buffer and onto the backend socket */ static void back_write(struct ev_loop *loop, ev_io *w, int revents) { @@ -908,7 +858,7 @@ static void handle_connect(struct ev_loop *loop, ev_io *w, int revents) { /* do nothing, we'll get phoned home again... */ } else { - perror("{backend-connect}"); + log_err_ps(ps, "Error connecting to backend: %s", strerror(errno)); shutdown_proxy(ps, SHUTDOWN_HARD); } } @@ -972,11 +922,11 @@ static void client_handshake(struct ev_loop *loop, ev_io *w, int revents) { ev_io_start(loop, &ps->ev_w_handshake); } else if (err == SSL_ERROR_ZERO_RETURN) { - LOG("{client} Connection closed (in handshake)\n"); + log_info_ps(ps, "Client closed connection in TLS handshake."); shutdown_proxy(ps, SHUTDOWN_UP); } else { - LOG("{client} Unexpected SSL error (in handshake): %d\n", err); + log_err_ps(ps, "Unexpected SSL error in handshake: %d", err); shutdown_proxy(ps, SHUTDOWN_UP); } } @@ -985,14 +935,14 @@ static void client_handshake(struct ev_loop *loop, ev_io *w, int revents) { /* Handle a socket error condition passed to us from OpenSSL */ static void handle_fatal_ssl_error(proxystate *ps, int err) { if (err == SSL_ERROR_ZERO_RETURN) - ERR("{client} Connection closed (in data)\n"); + log_err_ps(ps, "Client closed connection closed in data."); else if (err == SSL_ERROR_SYSCALL) if (errno == 0) - ERR("{client} Connection closed (in data)\n"); + log_debug_ps(ps, "Client closed connection in data."); else - perror("{client} [errno] "); + log_err_ps(ps, "Client error: %s", strerror(errno)); else - ERR("{client} Unexpected SSL_read error: %d\n", err); + log_err_ps(ps, "Unexpected SSL_read error: %d", err); shutdown_proxy(ps, SHUTDOWN_UP); } @@ -1078,32 +1028,25 @@ static void handle_accept(struct ev_loop *loop, ev_io *w, int revents) { socklen_t sl = sizeof(addr); int client = accept(w->fd, (struct sockaddr *) &addr, &sl); if (client == -1) { - switch (errno) { - case EMFILE: - ERR("{client} accept() failed; too many open files for this process\n"); - break; - - case ENFILE: - ERR("{client} accept() failed; too many open files for this system\n"); - break; - - default: - assert(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN); - break; - } + if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) + return; + + log_err("Error accepting connection on %s: %s", sock_as_str(w->fd, NULL), strerror(errno)); return; } int flag = 1; int ret = setsockopt(client, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag) ); if (ret == -1) { - perror("Couldn't setsockopt on client (TCP_NODELAY)\n"); + int e = errno; + log_err("[%s] Couldn't setsockopt TCP_NODELAY: %s", sock_as_str(client, NULL), strerror(e)); } #ifdef TCP_CWND int cwnd = 10; ret = setsockopt(client, IPPROTO_TCP, TCP_CWND, &cwnd, sizeof(cwnd)); if (ret == -1) { - perror("Couldn't setsockopt on client (TCP_CWND)\n"); + int e = errno; + log_err("[%s] Couldn't setsockopt TCP_CWND: %s", sock_as_str(client, NULL), strerror(e)); } #endif @@ -1113,8 +1056,9 @@ static void handle_accept(struct ev_loop *loop, ev_io *w, int revents) { int back = create_back_socket(); if (back == -1) { + int e = errno; + log_err("[client %s] Unable to create backend socket: %s", sock_as_str(client, NULL), strerror(e)); close(client); - perror("{backend-connect}"); return; } @@ -1129,6 +1073,9 @@ static void handle_accept(struct ev_loop *loop, ev_io *w, int revents) { SSL_set_fd(ssl, client); proxystate *ps = (proxystate *)malloc(sizeof(proxystate)); + if (ps == NULL) { + fail("Unable to allocate memory for new proxy state:"); + } ps->fd_up = client; ps->fd_down = back; @@ -1168,7 +1115,7 @@ static void check_ppid(struct ev_loop *loop, ev_timer *w, int revents) { (void) revents; pid_t ppid = getppid(); if (ppid != master_pid) { - ERR("{core} Process %d detected parent death, closing listener socket.\n", child_num); + log_err("Process %d detected parent death, closing listener socket.", child_num); ev_timer_stop(loop, w); ev_io_stop(loop, &listener); close(listener_socket); @@ -1180,7 +1127,7 @@ static void check_ppid(struct ev_loop *loop, ev_timer *w, int revents) { /* Set up the child (worker) process including libev event loop, read event * on the bound socket, etc */ static void handle_connections() { - LOG("{core} Process %d online\n", child_num); + log_notice("Process %d online", child_num); /* child cannot create new children... */ create_workers = 0; @@ -1193,9 +1140,9 @@ static void handle_connections() { int res = sched_setaffinity(0, sizeof(cpus), &cpus); if (!res) - LOG("{core} Successfully attached to CPU #%d\n", child_num); + log_notice("Successfully attached to CPU #%d", child_num); else - ERR("{core-warning} Unable to attach to CPU #%d; do you have that many cores?\n", child_num); + log_warn("Unable to attach to CPU #%d: %s (Do you have that many cores?)", child_num, strerror(errno)); #endif loop = ev_default_loop(EVFLAG_AUTO); @@ -1209,22 +1156,35 @@ static void handle_connections() { ev_io_start(loop, &listener); ev_loop(loop, 0); - ERR("{core} Child %d exiting.\n", child_num); + log_err("Child %d exiting.", child_num); exit(1); } void change_root() { - if (chroot(CONFIG->CHROOT) == -1) - fail("chroot"); - if (chdir("/")) - fail("chdir"); + if (chroot(CONFIG->CHROOT) == -1) { + fail("Unable to chroot to %s", CONFIG->CHROOT); + } + if (chdir("/")) { + fail("Unable to chdir to / inside chroot %s", CONFIG->CHROOT); + } } void drop_privileges() { - if (setgid(CONFIG->GID)) - fail("setgid failed"); - if (setuid(CONFIG->UID)) - fail("setuid failed"); + if (setgid(CONFIG->GID)) { + fail("Unable to drop privileges: setgid to %d failed:", CONFIG->GID); + } + if (setuid(CONFIG->UID)) { + fail("Unable to drop privileges: setuid to %d failed:", CONFIG->UID); + } +} + +char instance_name[128]; +char * stud_instance_name (char *name) { + if (name != NULL) { + memset(instance_name, '\0', sizeof(instance_name)); + strncpy(instance_name, name, (sizeof(instance_name) - 1)); + } + return instance_name; } @@ -1238,8 +1198,12 @@ void init_globals() { const int gai_err = getaddrinfo(CONFIG->BACK_IP, CONFIG->BACK_PORT, &hints, &backaddr); if (gai_err != 0) { - ERR("{getaddrinfo}: [%s]", gai_strerror(gai_err)); - exit(1); + die( + "Error creating backend address [%s]:%d: {getaddrinfo}: %s", + CONFIG->BACK_IP, + CONFIG->BACK_PORT, + gai_strerror(gai_err) + ); } #ifdef USE_SHARED_CACHE @@ -1256,8 +1220,11 @@ void init_globals() { const int gai_err = getaddrinfo(spo->ip, spo->port ? spo->port : CONFIG->SHCUPD_PORT, &hints, pai); if (gai_err != 0) { - ERR("{getaddrinfo}: [%s]", gai_strerror(gai_err)); - exit(1); + die( + "Error creating shared cache update peer socket [%s]:%s getaddrinfo: %s", + spo->ip, CONFIG->SHCUPD_PORT, + gai_strerror(gai_err) + ); } spo++; pai++; @@ -1265,11 +1232,11 @@ void init_globals() { } #endif /* child_pids */ - if ((child_pids = calloc(CONFIG->NCORES, sizeof(pid_t))) == NULL) - fail("calloc"); + if ((child_pids = calloc(CONFIG->NCORES, sizeof(pid_t))) == NULL) { + fail("Unable to allocate memory for child pids:"); + } - if (CONFIG->SYSLOG) - openlog("stud", LOG_CONS | LOG_PID | LOG_NDELAY, CONFIG->SYSLOG_FACILITY); + log_init(); } /* Forks COUNT children starting with START_INDEX. @@ -1282,8 +1249,7 @@ void start_children(int start_index, int count) { for (child_num = start_index; child_num < start_index + count; child_num++) { int pid = fork(); if (pid == -1) { - ERR("{core} fork() failed: %s; Goodbye cruel world!\n", strerror(errno)); - exit(1); + die("Unable to start children, fork() failed: %s; Goodbye cruel world!", strerror(errno)); } else if (pid == 0) { /* child */ handle_connections(); @@ -1307,7 +1273,7 @@ void replace_child_with_pid(pid_t pid) { } } - ERR("Cannot find index for child pid %d", pid); + log_err("Cannot find index for child pid %d", pid); } /* Manage status changes in child processes */ @@ -1318,23 +1284,23 @@ static void do_wait(int __attribute__ ((unused)) signo) { if (pid == -1) { if (errno == ECHILD) { - ERR("{core} All children have exited! Restarting...\n"); + log_err("All children have exited! Restarting."); start_children(0, CONFIG->NCORES); } else if (errno == EINTR) { - ERR("{core} Interrupted wait\n"); + log_warn("Interrupted wait"); } else { - fail("wait"); + fail("Error wait(2) for children:"); } } else { if (WIFEXITED(status)) { - ERR("{core} Child %d exited with status %d. Replacing...\n", pid, WEXITSTATUS(status)); + log_err("Child %d exited with status %d, replacing.", pid, WEXITSTATUS(status)); replace_child_with_pid(pid); } else if (WIFSIGNALED(status)) { - ERR("{core} Child %d was terminated by signal %d. Replacing...\n", pid, WTERMSIG(status)); + log_err("Child %d was terminated by signal %d, replacing.", pid, WTERMSIG(status)); replace_child_with_pid(pid); } } @@ -1346,17 +1312,22 @@ static void sigh_terminate (int __attribute__ ((unused)) signo) { /* are we the master? */ if (getpid() == master_pid) { - LOG("{core} Received signal %d, shutting down.\n", signo); + log_notice("Received signal %d, shutting down.", signo); /* kill all children */ int i; for (i = 0; i < CONFIG->NCORES; i++) { - /* LOG("Stopping worker pid %d.\n", child_pids[i]); */ + /* log_notice("Stopping worker pid %d.", child_pids[i]); */ if (child_pids[i] > 1 && kill(child_pids[i], SIGTERM) != 0) { - ERR("{core} Unable to send SIGTERM to worker pid %d: %s\n", child_pids[i], strerror(errno)); + log_err("Unable to send SIGTERM to worker pid %d: %s", child_pids[i], strerror(errno)); } } - /* LOG("Shutdown complete.\n"); */ + /* log_notice("Shutdown complete."); */ + + // remove pid file + if (CONFIG->DAEMONIZE && strlen(CONFIG->PID_FILE) > 0) { + unlink(CONFIG->PID_FILE); + } } /* this is it, we're done... */ @@ -1371,8 +1342,9 @@ void init_signals() { act.sa_handler = SIG_IGN; /* Avoid getting PIPE signal when writing to a closed file descriptor */ - if (sigaction(SIGPIPE, &act, NULL) < 0) - fail("sigaction - sigpipe"); + if (sigaction(SIGPIPE, &act, NULL) < 0) { + fail("Unable to install SIGPIPE signal handler:"); + } /* We don't care if someone stops and starts a child process with kill (1) */ act.sa_flags = SA_NOCLDSTOP; @@ -1380,38 +1352,50 @@ void init_signals() { act.sa_handler = do_wait; /* We do care when child processes change status */ - if (sigaction(SIGCHLD, &act, NULL) < 0) - fail("sigaction - sigchld"); + if (sigaction(SIGCHLD, &act, NULL) < 0) { + fail("Unable to install SIGCHLD signal handler:"); + } /* catch INT and TERM signals */ act.sa_flags = 0; act.sa_handler = sigh_terminate; if (sigaction(SIGINT, &act, NULL) < 0) { - ERR("Unable to register SIGINT signal handler: %s\n", strerror(errno)); - exit(1); + fail("Unable to register SIGINT signal handler:"); } if (sigaction(SIGTERM, &act, NULL) < 0) { - ERR("Unable to register SIGTERM signal handler: %s\n", strerror(errno)); - exit(1); + fail("Unable to register SIGTERM signal handler:"); } } +int pid_file_write (char *path, pid_t pid) { + FILE *fd = fopen(path, "w"); + if (fd == NULL) return 0; + if (fprintf(fd, "%d\n", pid) < 1) return 0; + if (fclose(fd) != 0) return 0; + return 1; +} + void daemonize () { /* go to root directory */ if (chdir("/") != 0) { - ERR("Unable change directory to /: %s\n", strerror(errno)); - exit(1); + die("Unable change directory to /: %s", strerror(errno)); } /* let's make some children, baby :) */ pid_t pid = fork(); if (pid < 0) { - ERR("Unable to daemonize: fork failed: %s\n", strerror(errno)); - exit(1); + die("Unable to daemonize: fork failed: %s", strerror(errno)); } /* am i the parent? */ if (pid != 0) { + // write pid file + if (! pid_file_write(CONFIG->PID_FILE, pid)) { + int e = errno; + kill(pid, SIGKILL); // kill the child + fprintf(stderr, "Unable to write pid file %s: %s\n", CONFIG->PID_FILE, strerror(e)); + exit(1); + } printf("{core} Daemonized as pid %d.\n", pid); exit(0); } @@ -1424,28 +1408,24 @@ void daemonize () { /* reopen standard streams to null device */ stdin = fopen(NULL_DEV, "r"); if (stdin == NULL) { - ERR("Unable to reopen stdin to %s: %s\n", NULL_DEV, strerror(errno)); - exit(1); + die("Unable to reopen stdin to %s: %s", NULL_DEV, strerror(errno)); } stdout = fopen(NULL_DEV, "w"); if (stdout == NULL) { - ERR("Unable to reopen stdout to %s: %s\n", NULL_DEV, strerror(errno)); - exit(1); + die("Unable to reopen stdout to %s: %s", NULL_DEV, strerror(errno)); } stderr = fopen(NULL_DEV, "w"); if (stderr == NULL) { - ERR("Unable to reopen stderr to %s: %s\n", NULL_DEV, strerror(errno)); - exit(1); + die("Unable to reopen stderr to %s: %s", NULL_DEV, strerror(errno)); } /* this is child, the new master */ pid_t s = setsid(); if (s < 0) { - ERR("Unable to create new session, setsid(2) failed: %s :: %d\n", strerror(errno), s); - exit(1); + die("Unable to create new session, setsid(2) failed: %s :: %d", strerror(errno), s); } - LOG("Successfully daemonized as pid %d.\n", getpid()); + log_notice("Successfully daemonized as pid %d.", getpid()); } void openssl_check_version() { @@ -1455,8 +1435,8 @@ void openssl_check_version() { /* check if we're running the same openssl that we were */ /* compiled with */ if ((openssl_version ^ OPENSSL_VERSION_NUMBER) & ~0xff0L) { - ERR( - "WARNING: {core} OpenSSL version mismatch; stud was compiled with %lx, now using %lx.\n", + log_warn( + "OpenSSL version mismatch; stud was compiled with %lx, now using %lx.", (unsigned long int) OPENSSL_VERSION_NUMBER, (unsigned long int) openssl_version ); @@ -1464,7 +1444,7 @@ void openssl_check_version() { /* exit(1); */ } - LOG("{core} Using OpenSSL version %lx.\n", (unsigned long int) openssl_version); + log_debug("Using OpenSSL version %lx.", (unsigned long int) openssl_version); } /* Process command line args, create the bound socket, @@ -1472,7 +1452,7 @@ void openssl_check_version() { int main(int argc, char **argv) { // initialize configuration CONFIG = config_new(); - + // parse command line config_parse_cli(argc, argv, CONFIG); @@ -1505,8 +1485,7 @@ int main(int argc, char **argv) { /* should we daemonize ?*/ if (CONFIG->DAEMONIZE) { - /* disable logging to stderr */ - CONFIG->QUIET = 1; + // enable syslog logging CONFIG->SYSLOG = 1; /* become a daemon */ diff --git a/stud.h b/stud.h new file mode 100644 index 0000000..7405d7a --- /dev/null +++ b/stud.h @@ -0,0 +1,76 @@ +/** + * Copyright 2011 Bump Technologies, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BUMP TECHNOLOGIES, INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BUMP TECHNOLOGIES, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of Bump Technologies, Inc. + * + **/ + +#include +#include +#include + +#include "ringbuffer.h" + +/* What agent/state requests the shutdown--for proper half-closed + * handling */ +typedef enum _SHUTDOWN_REQUESTOR { + SHUTDOWN_HARD, + SHUTDOWN_DOWN, + SHUTDOWN_UP +} SHUTDOWN_REQUESTOR; + +/* + * Proxied State + * + * All state associated with one proxied connection + */ +typedef struct proxystate { + ringbuffer ring_down; /* pushing bytes from client to backend */ + ringbuffer ring_up; /* pushing bytes from backend to client */ + + ev_io ev_r_up; /* Upstream write event */ + ev_io ev_w_up; /* Upstream read event */ + + ev_io ev_r_handshake; /* Downstream write event */ + ev_io ev_w_handshake; /* Downstream read event */ + + ev_io ev_r_down; /* Downstream write event */ + ev_io ev_w_down; /* Downstream read event */ + + int fd_up; /* Upstream (client) socket */ + int fd_down; /* Downstream (backend) socket */ + + int want_shutdown:1; /* Connection is half-shutdown */ + int handshaked:1; /* Initial handshake happened */ + int renegotiation:1; /* Renegotation is occuring */ + + SSL *ssl; /* OpenSSL SSL state */ + + struct sockaddr_storage remote_ip; /* Remote ip returned from `accept` */ +} proxystate; + +#define NULL_DEV "/dev/null" + +char * stud_instance_name (char *name);