Code:
/*
* @(#)main.c 1.100 12/22/00
*
* Configuration and initialization and main entry point for MCP.
*/
#define MPLOGMODULE "mcp_main"
#include <stdio.h>
#include <mprq.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <mpclpars.h>
#include <mplog.h>
#include <mpmalloc.h>
#include <mpstatus.h>
#include <server_auth.h>
#include <mp_except.h>
#include "user_cache.h"
#include "mcp_filth.h"
#include "peer.h"
#include "concentrator.h"
#include "user_list.h"
extern int debug_level;
extern int start_proxies;
extern int mcp_peer_suggest(MPTLADDR *);
extern u_int pool_min, pool_max, pool_target_hitrate, pool_target_latency;
extern u_int pool_metric_max, pool_stats_interval;
extern int db_queue_warn_interval, db_queue_warn_threshold;
extern int req_queue_warn_interval, req_queue_warn_threshold;
extern int webd_crypt_interval;
extern int mait_retry_tmo;
char *prog_name;
char *db_frontend_addrstr = NULL;
char *dirtywords = NULL;
char *welcome_url = NULL;
char *telegram_dir_prefix = "/opt/mpath/telegrams";
char *activity_directory = NULL;
char *score_directory = NULL;
char *ban_ipaddrs_file = NULL;
int score_rotate_interval = 900;
int use_portnum = 0;
int pri_portnum = 0;
int use_mait = 0;
int force_shutdown = 0;
int db_timeout = 0;
int tcp_port = 0;
int use_priority_session = 0;
int hb_timeout_count = 6;
int hb_interval = 20;
int pager_hb_interval = 120;
int pager_hb_timeout_count = 3;
int no_backoffs = 0;
int cleanup_delay = 300;
int login_reap_delay = 10*60;
int record_leave_scores = 0;
int audit_gics = 0;
int db_stats_interval = 15;
int telegram_quota_default = 50;
int user_list_debug_level = 0;
int alert_on_servorum_reconnect = 0;
int no_launches = 0;
int use_gicsconc_addresses = false;
int use_concentrator_broadcast = false;
int no_buddy_stuff = false;
char *billconfig = NULL;
usage(char *name)
{
char *var;
fprintf(stderr, "Usage: %s args\n", name);
fprintf(stderr, "Argument names must be preceded by a hyphen.\n");
fprintf(stderr, "\n--- GENERAL CONFIGURATION ---\n\n");
fprintf(stderr, "no-backoffs\n"
"\t\tDo not use servorum reconnect backoffs\n");
fprintf(stderr, "cleanup-delay <n>\n\t\tDelay in seconds before MCP "
"will clean up after its old\n\t\tincarnation "
"after restarting.\n");
fprintf(stderr, "debug <n>\n\t\tSet debug level (0-6)\n");
fprintf(stderr, "filth <path>\n\t\tSet dirty word list filename\n");
fprintf(stderr, "force\n\t\tForce shutdown of old server\n");
fprintf(stderr, "login-reap-delay <n>\n\t\tDelay in seconds before MCP "
"will stop waiting for users to\n\t\treconnect "
"after an MCP restart (added to "
"cleanup-delay)\n");
fprintf(stderr, "mcp <tladdr>\n\t\tPeer MCP to connect to (may be "
"specified more than once)\n");
fprintf(stderr, "telegram-dir <directory>\n\t\tDirectory to use for "
"storing telegram files (MCP will\n\t\tcreate "
"a subdirectory hierarchy underneath)\n");
fprintf(stderr, "telegram-quota <n>\n\t\tSet the default number of "
"telegrams allowed per user.\n\t\tDefault = "
"%d\n", telegram_quota_default);
fprintf(stderr, "welcome <string>\n\t\tSet gizmo welcome message, "
"usually a URL\n");
fprintf(stderr, "no-buddy-stuff\n\t\tTurns off buddy-list management."
"\n\t\tThis is used when we want to run a multiple"
"\n\t\tMCP system where several user MCPs split the"
"\n\t\tuser load and one MCP handles buddy users."
"\n");
fprintf(stderr, "\n--- DATABASE OPTIONS ---\n\n");
fprintf(stderr, "db-frontend <tladdr>\n\t\tDB Frontend server to run "
"transactions through (default=none)\n");
fprintf(stderr, "db-queue-interval <n>\n\t\tMaximum frequency of EMERG "
"messages about database\n\t\tqueue size, in "
"seconds (default=%d)\n",
db_queue_warn_interval);
fprintf(stderr, "db-queue-threshold <n>\n\t\tMinimum database queue "
"size considered worthy of\n\t\tan EMERG "
"message (default=%d)\n",
db_queue_warn_threshold);
fprintf(stderr, "db-stats-interval <n>\n\t\tHow often, in minutes, the "
"short-term database statistics\n\t\tare "
"output to the logs and reset (default=%d)\n",
db_stats_interval);
fprintf(stderr, "db-timeout <n>\n\t\tSet database operation timeout in "
"seconds, 0=none\n");
fprintf(stderr, "proxies <n>\n\t\tNumber of Infranet connections to "
"open (default 3)\n");
fprintf(stderr, "record-leave-scores\n\t\tRecord score reports "
"indicating normal/abnormal disconnects\n"
"\t\tfrom GICS (can eat lots of DB space)\n");
fprintf(stderr, "\n--- NETWORKING OPTIONS ---\n\n");
fprintf(stderr, "heartbeat-interval <n>\n\t\tInterval in seconds "
"between outgoing heartbeats\n\t\tfor normal "
"users. Default 20.\n");
fprintf(stderr, "heartbeat-timeout-count <n>\n\t\tNumber of MPReq "
"heartbeats that must be missed for a\n "
"\t\tnormal session to time out. Default "
"6.\n");
fprintf(stderr, "pager-heartbeat-interval <n>\n\t\tInterval in seconds "
"between outgoing heartbeats\n\t\tfor pager "
"users. Default 120.\n");
fprintf(stderr, "pager-heartbeat-timeout-count <n>\n\t\tNumber of "
"MPReq heartbeats that must be missed for a\n "
"\t\tpager session to time out. Default "
"3.\n");
fprintf(stderr, "port <n>\n\t\tSet port number for MPReq sessions. "
"Used for both TCP and UDP\n");
fprintf(stderr, "priority-port <n>\n\t\tSet priority port number. "
"Turns on priority port.\n");
fprintf(stderr, "tcp-port <n>\n\t\tAllow users to connect via TCP as "
"well as UDP.\n");
fprintf(stderr, "gics-concentrator-address <tladdr>\n\t\t"
"pass this tladdr to GICSes so they can connect\n"
"\t\tto a concentrator and spare us the heartbeats\n");
fprintf(stderr, "use-concentrator-broadcast\n\t\t"
"Enables using the concentrator to broadcast messages\n"
"\t\ton behalf of the MCP rather than sending direct\n"
"\t\tto all users.\n");
fprintf(stderr, "\n--- USAGE/BILLING-RELATED OPTIONS ---\n\n");
fprintf(stderr, "activity-directory <dir>\n\t\tIf set, activities will "
"be written to files in the specified\n"
"\t\tdirectory (one file per hour.) Default "
"is to not log\n\t\tactivities to files.\n");
fprintf(stderr, "score-directory <dir>\n\t\tIf set, scores will "
"be written to files in the specified\n"
"\t\tdirectory (one file per score-rotate-interval.)\n"
"This option must be specified, or scores won't be logged!\n");
fprintf(stderr, "score-rotate-interval <seconds>\n\t\t"
"How often we should switch to a new score log\n"
"(default 900).\n");
fprintf(stderr, "bill-config <file>\n\t\tSets billing config file.\n");
fprintf(stderr, "\n--- LOAD MANAGEMENT OPTIONS ---\n\n");
fprintf(stderr, "audit-gics\n\t\tTurn on GICS auditing. Will inspect "
"GICSes at recycle time\n\t\tto make sure no "
"extra child servers have been created.\n");
fprintf(stderr, "pool-max <n>\n\t\tMaximum GICSes to keep in idle "
"pool (times metric)\n");
fprintf(stderr, "pool-metric-max <n>\n\t\tMaximum value of GICS pool "
"metric (default %u)\n", pool_metric_max);
fprintf(stderr, "pool-min <n>\n\t\tMinimum GICSes to keep in idle "
"pool (times metric)\n");
fprintf(stderr, "pool-hitrate <n>\n\t\tMinimum GICS pool hit rate to "
"maintain\n");
fprintf(stderr, "pool-latency <n>\n\t\tMaximum GICS pool latency to "
"maintain (secs)\n");
fprintf(stderr, "req-queue-interval <n>\n\t\tMaximum frequency of "
"EMERG messages about request\n\t\tqueue size, "
"in seconds (default=%d)\n",
req_queue_warn_interval);
fprintf(stderr, "req-queue-threshold <n>\n\t\tMinimum request queue "
"size considered worthy of\n\t\tan EMERG "
"message (default=%d)\n",
req_queue_warn_threshold);
fprintf(stderr, "\n--- SECURITY-RELATED OPTIONS ---\n\n");
fprintf(stderr, "webd-crypt-interval <n>\n\t\tInterval between mpwebd "
"crypto key changes, in seconds.\n");
fprintf(stderr, "ban-ipaddrs <file>\n\t\tFile which contains banned "
"IP addresses.\n");
fprintf(stderr, "\n--- MAIT OPTIONS ---\n\n");
fprintf(stderr, "use-mait<n>\n\t\tSwitches on MAIT to use"
"provider database for user info\n");
fprintf(stderr, "mait-retry-tmo <n>\n\t\tInterval between "
"authentication tool restarts, in msecs.\n"
"\t\t(default=%d)\n",
mait_retry_tmo);
fprintf(stderr, "\n--- LOGGING OPTIONS ---\n\n");
fprintf(stderr, "alert-on-servorum-reconnect\n\t\tOutput an ALERT "
"log message every time a servorum\n\t\t"
"connects, even if it previously closed "
"cleanly.\n");
fprintf(stderr, "no-launches\n\t\tMCP isn't expected to launch any "
"games or matchmakers, so\n\t\tsuppress alerts "
"about failed launch attempts.\n");
fprintf(stderr, "pool-stats-interval <n>\n\t\tSet the minimum time "
"in seconds between dumps of the GICS\n\t\t"
"pool state when launches fail. Default is "
"%d.\n", pool_stats_interval);
fprintf(stderr, "user-list-debug-level <n>\n\t\tSet the amount of "
"debug output from the user list management\n"
"\t\tsubsystem (0=none, 4=maximum). Default "
"is 0.\n");
fprintf(stderr, MPLOG_OPTIONS_HELP);
exit(0);
}
int
help(void *operand, u_int argc, char **argv) {
usage("mcp");
return 0;
}
/*
* Add a peer MCP to the list of other MCPs we should contact.
*/
static int
add_peer_mcp(void *operand, u_int argc, char **argv)
{
MPTLADDR new_addr;
MPStringToTlAddr(*argv, &new_addr);
if (mcp_peer_suggest(&new_addr))
{
fprintf(stderr, "Can't add MCP %s\n", *argv);
exit(1);
}
return (1);
}
/*
* Use a specific priority port
*/
static int
priority_port(void *operand, u_int argc, char **argv)
{
int pri_port;
if (argc)
{
pri_port = atoi(*argv);
}
else
{
fprintf(stderr, "Need argument for priority-port!");
return (-1);
}
if (pri_port < 1 || pri_port > 65536)
{
fprintf(stderr, "Priority port is invalid, user requested %d",
pri_port);
return (-1);
}
use_priority_session = true;
pri_portnum = pri_port;
return (1);
}
/* Add a gics concentrator address */
static int
add_gics_concentrator_address(void* operand, u_int argc, char **argv) {
MPTLADDR tladdr;
if (MPStringToTlAddr(argv[0], &tladdr)) {
mp_log("006P1", MPLT_ERR, "Failed to translate \"%s\" to TLADDR",
argv[0]);
return -1;
}
if (gicsconc_add_address(&tladdr)) {
mp_log("006P2", MPLT_ERR, "Failed to add tladdr %s to list of gics concentrators",
argv[0]);
return -1;
}
use_gicsconc_addresses = true;
return 1;
}
cl_table_t cl_table[] = {
{ "activity-directory", 1, 1, cl_eval_string_flag, (void *) &activity_directory },
{ "alert-on-servorum-reconnect", 0, 0, cl_eval_bool_flag, (void *) &alert_on_servorum_reconnect },
{ "audit-gics", 0, 0, cl_eval_bool_flag, (void *) &audit_gics },
{ "ban-ipaddrs", 1, 1, cl_eval_string_flag, (void *) &ban_ipaddrs_file},
{ "bill-config", 1, 1, cl_eval_string_flag, (void *) &billconfig },
{ "cleanup-delay", 1, 1, cl_eval_uint_flag, (void *)&cleanup_delay },
{ "db-frontend", 1, 1, cl_eval_string_flag, (void *)&db_frontend_addrstr },
{ "db-queue-interval", 1, 1, cl_eval_int_flag, (void *)&db_queue_warn_interval },
{ "db-queue-threshold", 1, 1, cl_eval_int_flag, (void *)&db_queue_warn_threshold },
{ "db-stats-interval", 1, 1, cl_eval_uint_flag, (void *)&db_stats_interval },
{ "db-timeout", 1, 1, cl_eval_uint_flag, (void *) &db_timeout },
{ "debug", 1, 1, cl_eval_uint_flag, (void*) &debug_level },
{ "filth", 1, 1, cl_eval_string_flag, (void *) &dirtywords },
{ "force", 0, 0, cl_eval_bool_flag, (void*) &force_shutdown },
{ "gics-concentrator-address", 1, 1, add_gics_concentrator_address, NULL },
{ "heartbeat-interval", 1, 1, cl_eval_uint_flag, (void *)&hb_interval },
{ "heartbeat-timeout-count", 1, 1, cl_eval_uint_flag, (void *)&hb_timeout_count },
{ "login-reap-delay", 1, 1, cl_eval_uint_flag, (void *)&login_reap_delay },
{ "mait-retry-tmo", 1, 1, cl_eval_uint_flag, (void*)&mait_retry_tmo },
{ "mcp", 1, 1, add_peer_mcp, NULL },
{ "no-backoffs", 0, 0, cl_eval_bool_flag, (void*) &no_backoffs },
{ "no-buddy-stuff", 0, 0, cl_eval_bool_flag, (void*) &no_buddy_stuff },
{ "no-launches", 0, 0, cl_eval_bool_flag, (void*) &no_launches },
{ "pager-heartbeat-interval", 1, 1, cl_eval_uint_flag, (void *)&pager_hb_interval },
{ "pager-heartbeat-timeout-count", 1, 1, cl_eval_uint_flag, (void *)&pager_hb_timeout_count },
{ "pool-hitrate", 1, 1, cl_eval_uint_flag, (void *)&pool_target_hitrate },
{ "pool-latency", 1, 1, cl_eval_uint_flag, (void *)&pool_target_latency },
{ "pool-max", 1, 1, cl_eval_uint_flag, (void *)&pool_max },
{ "pool-metric-max", 1, 1, cl_eval_uint_flag, (void *)&pool_metric_max },
{ "pool-min", 1, 1, cl_eval_uint_flag, (void *)&pool_min },
{ "pool-stats-interval", 1, 1, cl_eval_uint_flag, (void *)&pool_stats_interval },
{ "port", 1, 1, cl_eval_uint_flag, (void*) &use_portnum },
{ "priority-port", 1, 1, priority_port, NULL },
{ "proxies", 1, 1, cl_eval_uint_flag, (void *)&start_proxies },
{ "record-leave-scores", 0, 0, cl_eval_bool_flag, (void *)&record_leave_scores },
{ "req-queue-interval", 1, 1, cl_eval_int_flag, (void *)&req_queue_warn_interval },
{ "req-queue-threshold", 1, 1, cl_eval_int_flag, (void *)&req_queue_warn_threshold },
{ "score-directory", 1, 1, cl_eval_string_flag, (void *) &score_directory },
{ "score-rotate-interval", 1, 1, cl_eval_int_flag, (void *)&score_rotate_interval },
{ "tcp-port", 1, 1, cl_eval_uint_flag, (void *) &tcp_port },
{ "telegram-dir", 1, 1, cl_eval_string_flag, (void *)&telegram_dir_prefix },
{ "telegram-quota", 1, 1, cl_eval_uint_flag, (void *)&telegram_quota_default },
{ "use-mait", 0, 0, cl_eval_bool_flag, (void*)&use_mait },
{ "use-concentrator-broadcast", 0, 0, cl_eval_bool_flag, (void*)&use_concentrator_broadcast },
{ "user-list-debug-level", 1, 1, cl_eval_uint_flag, (void *)&user_list_debug_level },
{ "webd-crypt-interval", 1, 1, cl_eval_uint_flag, (void *)&webd_crypt_interval },
{ "welcome", 1, 1, cl_eval_string_flag, (void *) &welcome_url },
MPLOG_OPTIONS,
{ "help", 0, 0, help, (void *)0},
};
int
handle_runtime_options( u_int argc, char **argv) {
int retval;
get_progname(prog_name, mcp);
next_arg(); /* skip program name */
/* Parse command line arguments */
if((retval = cl_parse(cl_table, sizeof(cl_table)/sizeof(cl_table_t),
true,
prog_name,
argc,
argv)) < 0) {
usage(prog_name);
}
argv+= retval;
argc-= retval;
return TRUE;
}
/*
* Set a single configuration parameter.
*/
int
set_runtime_option(char *name, char *value)
{
char *argv[3];
int argc = 1, retval;
argv[0] = name;
if (value)
{
argv[1] = debug_strdup(value);
argv[2] = NULL;
argc++;
}
else
argv[1] = NULL;
if((retval = cl_parse(cl_table, sizeof(cl_table)/sizeof(cl_table_t),
true, prog_name, argc, argv)) < 0)
{
debug_free(argv[1]);
return (MCP_NOT_FOUND);
}
return (MCP_OK);
}
main(int argc, char **argv)
{
int c;
int argval;
char *mpath_etc;
init_logging();
debug_alloc_init(1);
signal(SIGPIPE, SIG_IGN);
if (!crypt_init_random())
exit(1);
MPModuleInit();
if (MPSTInit("MCP", MPT_MCP, "1", NULL))
exit(1);
/*
* Need to init concentrator module before possibly handling
* -gics-concentrator-address option.
*/
if (concentrator_init())
exit(1);
handle_runtime_options(argc, argv);
mpath_etc = getenv("MPATH_ETC");
if (mpath_etc == NULL)
mpath_etc = "/opt/mpath";
if (billconfig == NULL)
{
billconfig = debug_malloc(strlen(mpath_etc) +
sizeof("/plans.conf"));
if (billconfig == NULL)
mp_log_abort("0043Y", MPLT_EMERG, "Out of memory");
sprintf(billconfig, "%s/plans.conf", mpath_etc);
mp_log("0001L", MPLT_WARN, "No billing plan configuration file "
"was specified. Using %s.", billconfig);
}
if (use_portnum != 0 || pri_portnum != 0) {
set_portnum(use_portnum, pri_portnum);
}
if (NVTreeInit())
exit(1);
MPHashInit();
if (! mp_exception_init())
exit(1);
if (mcp_peer_init())
exit(1);
if (conn_init())
exit(1);
if (mcpcode_init())
exit(1);
if (filth_init())
exit(1);
bll_config_init(); /* we don't always care about plans.conf */
if (closequeue_init())
exit(1);
if (dsp_queue_init())
exit(1);
if (db_stats_init())
exit(1);
if (proxy_init())
exit(1);
if (user_cache_init())
exit(1);
if (ccache_init())
exit(1);
if (rnr_init()) /* needs proxy_init() and user_cache_init() */
exit(1);
if (cleanup_init())
exit(1);
if (cache_init())
exit(1);
if (webd_init())
exit(1);
if (user_list_init())
exit(1);
if (pager_count_init())
exit(1);
if (activity_file_init())
exit(1);
if (userlog_file_init())
exit(1);
if (host_id_file_init())
exit(1);
if (score_file_init())
exit(1);
ipaddr_ban_init(ban_ipaddrs_file);
if (use_mait)
if (mait_init())
exit(1);
if (User_HeapInit())
exit(1);
if (UserList_HeapInit())
exit(1);
if (UserListMember_HeapInit())
exit(1);
if (UserListSubscr_HeapInit())
exit(1);
if (UserRelation_HeapInit())
exit(1);
BEGIN
dsp_main(NULL);
END
rnr_shutdown_all();
UserRelation_HeapCleanup();
UserListSubscr_HeapCleanup();
UserListMember_HeapCleanup();
UserList_HeapCleanup();
User_HeapCleanup();
ipaddr_ban_cleanup();
filth_shutdown();
MPModuleCleanup();
return (0);
}