its a number of applications servers to run mplayer.com gaming/video/audio chat client the server 24 applications in all the (MCP) The Master Control Program is responsible for user authentication, account management, and all system stored data.
The MCP is the only process which has an interface to the database (Via the Dbfront).
there are all pre compiled applications from a working environment just our servers don't seam to be setup correctly.
/*
* @(#)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);
}
/*
* @(#)rnr_mcp.c 1.40 04/03/99
*
* Functions for MCP requests.
*/
#define MPLOGMODULE "mcp_rnr_mcp"
#include <malloc.h>
#include <mprq.h>
#include <mcpreq.h>
#include <mpcrypt.h>
#include <mpxdr.h>
#include <gam_common.h>
#include <mpservorum.h>
#include <mpdeadlock.h>
#include <mpmalloc.h>
#include <db_types.h>
#include <server_auth.h>
#include "rnr_int.h"
#include "dsp_int.h"
#include "db_proxy.h"
#include "db_user.h"
#include "peer.h"
#include "config.h"
#include "mcp_util.h"
#include "mcp_servorum.h"
#include "user_cache.h"
#define MCP_PEER_LOOP_TIMEOUT (10*60) /* Poll for new MCPs every 10 min */
#define CACHE_TYPE_USER 0
struct mcp {
void *session; /* Session to remote MCP. */
int us; /* Flag: Is this actually us? */
MPTLADDR addr; /* Remote address. */
MPTLADDR priaddr; /* Priority address (if any) */
u_int use_pri; /* true if priority address is valid */
u_long id; /* MCP identifier. */
u_long death; /* Time of death, if known. */
struct mcp *next;
MCP_SOURCE source; /* where we got the data */
};
typedef struct mcp *mcpp;
static volatile mcpp mcplist = NULL;
static volatile int known_mcps = 0;
static int initial_mcp_count = 0;
static MPTLADDR *initial_mcps = NULL;
static Mutex mcpmutex;
static cond_t mcpcond;
void *mcp_admin_login(MPTLADDR *, void (*)());
static char *ident = "@(#)rnr_mcp.c 1.40 04/03/99";
/*
* Add an MCP to the list of peer MCPs we'll want to try to make contact
* with when we have the chance.
*
* The MCP mutex must already be held (or this must be called during startup,
* before anything else can contend for the list.)
*/
void *
mcp_peer_add(MPTLADDR *mcpaddr,
u_int use_pri, MPTLADDR *priaddr,
MCP_SOURCE source)
{
mcpp new, cur;
char addrstr[150], priaddrstr[150];
MPTLADDR *us;
/* If it's us, exit immediately. */
us = dsp_get_listen_addr();
if (MPTLADDREq(mcpaddr, us, 0))
{
DebugT("004PF", 6, "mcp_peer_add ignoring local listen address");
return (NULL);
}
us = dsp_get_pri_addr();
if (us && MPTLADDREq(mcpaddr, us, 0))
{
DebugT("004PG", 6, "mcp_peer_add ignoring local priority address");
return (NULL);
}
new = debug_malloc(sizeof(*new));
if (new == NULL)
{
DebugT("004PH", 0, "mcp_peer_add: Out of memory");
return (NULL);
}
memset(new, 0, sizeof(*new));
memcpy(&new->addr, mcpaddr, sizeof(new->addr));
memcpy(&new->priaddr, priaddr, sizeof(new->priaddr));
new->use_pri = use_pri;
new->source = source;
MPTLADDRtostr(mcpaddr, addrstr);
if (use_pri)
MPTLADDRtostr(priaddr, priaddrstr);
else
strcpy(priaddrstr, "no priority port");
/*
* Scan the list; if we already know about an MCP, don't bother
* adding it again.
*/
for (cur = mcplist; cur; cur = cur->next)
if (MPTLADDREq(mcpaddr, &cur->addr, 0) ||
(cur->use_pri && MPTLADDREq(mcpaddr, &cur->priaddr, 0)) ||
(use_pri && MPTLADDREq(priaddr, &cur->addr, 0)) ||
(cur->use_pri && use_pri &&
MPTLADDREq(priaddr, &cur->priaddr, 0)))
break;
if (cur == NULL)
{
DebugT("004PJ", 4, "Adding peer MCP %s (%s) to list based on %s",
addrstr,
use_pri ? priaddrstr : "no priority port",
source == MCP_SOURCE_UNINIT ? "uninitialized data" :
source == MCP_SOURCE_INIT ? "initial data" :
source == MCP_SOURCE_HEARSAY ? "hearsay" :
source == MCP_SOURCE_AUTHORITATIVE ?
"authoritative data" :
"occult knowledge");
new->next = mcplist;
mcplist = new;
cur = new;
}
else
{
/* We don't need the 'new' after all. */
debug_free(new);
/* Now if we got a note about an MCP, make sure it's got
different information */
if (MPTLADDREq(mcpaddr, &cur->addr, 0) &&
((use_pri && cur->use_pri &&
MPTLADDREq(priaddr, &cur->priaddr, 0)) ||
(!use_pri && !cur->use_pri)))
{
DebugT("004PK", 6, "Already know about MCP %s (%s) from %s",
addrstr,
use_pri ? priaddrstr : "no priority port",
cur->source == MCP_SOURCE_UNINIT ? "uninitialized data" :
cur->source == MCP_SOURCE_INIT ? "initial data" :
cur->source == MCP_SOURCE_HEARSAY ? "hearsay" :
cur->source == MCP_SOURCE_AUTHORITATIVE ?
"authoritative data" :
"occult knowledge");
if (source > cur->source)
cur->source = source;
}
else if (source < cur->source)
{
char knownaddrstr[150], knownpriaddrstr[150];
MPTLADDRtostr(&cur->addr, knownaddrstr);
if (cur->use_pri)
MPTLADDRtostr(&cur->priaddr, knownpriaddrstr);
else
strcpy(knownpriaddrstr, "no priority port");
DebugT("004PL", 6, "Ignoring %s for known MCP %s (%s), claimed %s (%s)",
source == MCP_SOURCE_UNINIT ? "uninitialized data" :
source == MCP_SOURCE_INIT ? "initial data" :
source == MCP_SOURCE_HEARSAY ? "hearsay" :
source == MCP_SOURCE_AUTHORITATIVE ?
"authoritative data" :
"occult knowledge",
knownaddrstr,
knownpriaddrstr,
addrstr,
priaddrstr);
}
else
{
char knownaddrstr[150], knownpriaddrstr[150];
MPTLADDRtostr(&cur->addr, knownaddrstr);
if (cur->use_pri)
MPTLADDRtostr(&cur->priaddr, knownpriaddrstr);
else
strcpy(knownpriaddrstr, "no priority port");
memcpy( (caddr_t)&cur->addr,
(caddr_t)mcpaddr,
sizeof(cur->addr));
if (use_pri)
memcpy( (caddr_t)&cur->priaddr,
(caddr_t)priaddr,
sizeof(cur->priaddr));
cur->use_pri = use_pri;
cur->source = source;
DebugT("004PM", 4, "Based on %s, changing MCP %s (%s) to %s (%s)",
source == MCP_SOURCE_UNINIT ? "uninitialized data" :
source == MCP_SOURCE_INIT ? "initial data" :
source == MCP_SOURCE_HEARSAY ? "hearsay" :
source == MCP_SOURCE_AUTHORITATIVE ?
"authoritative data" :
"occult knowledge",
knownaddrstr,
knownpriaddrstr,
addrstr,
priaddrstr);
}
}
epilogue:
cond_signal(&mcpcond);
return (cur);
}
/*
* Connect to a peer MCP and introduce ourselves.
*/
static void *
connectup(mcpp peer)
{
void *session;
XDR out;
char buf[100];
u_long our_id = mcp_number();
u_int code;
MPTLADDR *mcpaddr;
MPTLADDR priaddr, *ppriaddr;
u_long use_pri = false;
session = mcp_admin_login(&peer->addr, dsp_enqueue);
if (session == NULL)
return (NULL);
/*
* We're connected and logged in as an admin. Offer our information.
* Lose the mutex while we do so, or we might deadlock if the other
* guy is doing the same thing. Nobody can touch the peer structure
* we're looking at, since its session hasn't been filled in yet.
*/
lock_mutex_unlock(&mcpmutex);
xdrmem_create(&out, buf, sizeof(buf), XDR_ENCODE);
/*
* Send both our normal address and our priority address.
*/
if ((ppriaddr = dsp_get_pri_addr()) == (MPTLADDR*) 0)
{
MPTlAddrZero(&priaddr, MPPROTO_UDPIP);
use_pri = false;
}
else
{
memcpy((caddr_t)&priaddr, (caddr_t)ppriaddr, sizeof(priaddr));
use_pri = true;
}
if (! xdr_MPTLADDR(&out, dsp_get_listen_addr()) ||
! xdr_u_long(&out, &our_id) ||
! xdr_u_long(&out, &use_pri) ||
! xdr_MPTLADDR(&out, &priaddr))
{
DebugT("004PN", 2, "Can't encode our address to send to peer");
MPSessClose(session);
return (NULL);
}
if (code = MPCReqSync(session, MCP_S_MCP_INFO, buf, xdr_getpos(&out),
NULL, 0))
DebugT("004PP", 3, "Got status %d sending our address to peer", code);
xdr_destroy(&out);
if (code = MPCReqSync(session, MCP_G_MCP_ID, buf, 0, buf, sizeof(buf)))
DebugT("004PQ", 3, "Can't get peer MCP identifier, code %d", code);
else
{
xdrmem_create(&out, buf, sizeof(buf), XDR_DECODE);
xdr_u_long(&out, &peer->id);
xdr_destroy(&out);
DebugT("004PR", 4, "Successfully connected to MCP %lu", peer->id);
}
/*
* Set the timeout on this session obnoxiously low, since we need to
* know right away if a peer dies. Allow lots of requests to be in
* process in parallel.
*/
MPSessOptionsSet(session, MPSESS_OPT_HB_TXTMO, (caddr_t)1000);
MPSessOptionsSet(session, MPSESS_OPT_SREQ_ZOMBIE_SIZE, (caddr_t)1000);
/* Grab the lock again on our way out. */
lock_mutex_lock(&mcpmutex);
known_mcps++;
return (session);
}
/*
* MCP contact thread. This loops continuously, trying to connect to the
* peer MCPs we know about, and asking each of the connected ones for its
* list of MCPs, so we'll discover any servers that any of the other servers
* know about.
*/
static void *
mcp_peer_loop(void *dummy)
{
timestruc_t timeout;
mcpp cur;
u_int listsize, loop;
MPTLADDR mcpaddr, priaddr;
u_long use_pri;
caddr_t resp_params;
u_int resp_params_len;
XDR in;
u_int status;
lock_mutex_lock(&mcpmutex);
/*
* Give the main program some time to come up, so when we connect to
* a peer it'll have a chance to connect back to us. Otherwise the
* reverse connection could happen before we're bound to our UDP
* port.
*/
memset(&timeout, 0, sizeof(timeout));
timeout.tv_sec = time(NULL) + 10;
lock_cond_timedwait(&mcpcond, &mcpmutex, &timeout);
memset(&timeout, 0, sizeof(timeout));
while (1)
{
DebugT("004PT", 4, "MCP discovery loop looking for new peers.");
for (cur = mcplist; cur; cur = cur->next)
{
if (cur->session == NULL)
cur->session = connectup(cur);
if (cur->session == NULL)
continue;
tell_mm_about_mcp(cur->use_pri ?
&cur->priaddr :
&cur->addr, 1);
tell_servorum_about_mcp(cur->use_pri ?
&cur->priaddr :
&cur->addr, 1);
/*
* Ask the other guy for his MCP list. We can't hold
* the mutex while we're waiting, because he could be
* asking us for our list at exactly the same time.
* Luckily, MCP peer structures can never be freed,
* only modified; the worst that'll happen is the
* session closing while we wait, in which case the
* request will fail and we can continue.
*/
resp_params = NULL;
resp_params_len = 0;
lock_mutex_unlock(&mcpmutex);
status = MPCReqSyncAlloc(cur->session, MCP_L_PEER_MCPS, NULL,
0, &resp_params, &resp_params_len);
lock_mutex_lock(&mcpmutex);
if (status)
{
DebugT("004PV", 4, "Couldn't list MCPs on MCP %lu, response = %d",
cur->id,
status);
if (resp_params)
debug_free(resp_params);
continue;
}
xdrmem_create(&in, resp_params, resp_params_len,
XDR_DECODE);
/* Now decode all peer MCPs */
if (! xdr_u_int(&in, &listsize))
{
DebugT("004PW", 3, "Couldn't decode list size from %lu",
cur->id);
goto epilogue;
}
for (loop = 0; loop < listsize; loop++)
{
if (!xdr_MPTLADDR(&in, &mcpaddr) ||
!xdr_u_long(&in, &use_pri) ||
!xdr_MPTLADDR(&in, &priaddr)) {
DebugT("004PX", 3, "Couldn't decode MCP in list from %lu",
cur->id);
goto epilogue;
}
/* Classify as hearsay if the MCP isn't giving
us data on itself. The first MCP given
back is always the MCP itself */
mcp_peer_add(&mcpaddr, use_pri, &priaddr,
loop == 0 ?
MCP_SOURCE_AUTHORITATIVE :
MCP_SOURCE_HEARSAY);
}
DebugT("004PY", 6, "Got %u MCPs from %lu",
listsize,
cur->id);
epilogue:
xdr_destroy(&in);
debug_free(resp_params);
}
if (mcplist == NULL)
{
DebugT("004Q0", 5, "MCP discovery loop: no peers, sleeping.");
lock_cond_wait(&mcpcond, &mcpmutex);
}
else
{
timeout.tv_sec = time(NULL) + MCP_PEER_LOOP_TIMEOUT;
lock_cond_timedwait(&mcpcond, &mcpmutex, &timeout);
}
}
}
/*
* Return a complete listing of known MCPs.
*
* Valid for:
* Anyone
* Input:
* None
* Output:
* MPTLADDR array
*/
int
rnr_l_mcps(struct runner *rnr, XDR *xdrs, XDR *out)
{
long count;
MPTLADDR *mcpaddr;
mcpp cur;
int status = MCP_OK;
/*
* Only the matchmakers or servora are entitled to have our priority
* address...
*/
if (conn_type(rnr->args) == CONN_MATCHMAKER ||
conn_type(rnr->args) == CONN_SERVORUM)
{
MPTLADDR tladdr;
char tladdrstr[80];
MPSessGetRemoteTlAddr(rnr->session, &tladdr);
MPTLADDRtostr(&tladdr, tladdrstr);
DebugT("004Q1", 6, "[FNORD] MCP_L_MCPS issuing my priority address to %s",
tladdrstr);
mcpaddr = dsp_get_pri_addr();
if (!mcpaddr)
mcpaddr = dsp_get_listen_addr();
} else {
MPTLADDR tladdr;
char tladdrstr[80];
MPSessGetRemoteTlAddr(rnr->session, &tladdr);
MPTLADDRtostr(&tladdr, tladdrstr);
DebugT("004Q2", 6, "[FNORD] MCP_L_MCPS issuing just ordinary addresses to %s",
tladdrstr);
mcpaddr = dsp_get_listen_addr();
}
/*
* List ourselves as well as any MCPs we're actually in contact with.
*/
lock_mutex_lock(&mcpmutex);
count = 1 + known_mcps;
if ( ! xdr_long(out, &count) ||
! xdr_MPTLADDR(out, mcpaddr) )
{
DebugT("004Q3", 2, "xdr_MPTLADDR failed");
status = MCP_INTERNAL;
}
if (status == MCP_OK)
for (cur = mcplist; cur; cur = cur->next)
if (cur->session)
{
if (conn_type(rnr->args) == CONN_MATCHMAKER ||
conn_type(rnr->args) == CONN_SERVORUM)
{
mcpaddr = cur->use_pri ?
&cur->priaddr :
&cur->addr;
}
else
{
mcpaddr = &cur->addr;
}
if (! xdr_MPTLADDR(out, &cur->addr))
{
DebugT("004Q4", 2, "xdr_MPTLADDR failed");
status = MCP_INTERNAL;
break;
}
}
lock_mutex_unlock(&mcpmutex);
DebugT("004Q5", 5, "Returning %d mcp addresses.", count);
return (status);
}
/*
* Return a complete listing of known MCPs, both normal and priority addresses
* (special request for peering MCPs)
*
* Valid for:
* peer MCPs
* Input:
* None
* Output:
* MPTLADDR array
*/
int
rnr_l_peer_mcps(struct runner *rnr, XDR *xdrs, XDR *out)
{
long count;
MPTLADDR *mcpaddr;
MPTLADDR *ppriaddr, priaddr;
u_long use_pri = false;
mcpp cur;
int status = MCP_OK;
/*
* List ourselves as well as any MCPs we're actually in contact with.
*/
lock_mutex_lock(&mcpmutex);
count = 1 + known_mcps;
if ( ! xdr_long(out, &count))
{
DebugT("004Q6", 2, "Failed to xdr count of peer MCPs");
status = MCP_INTERNAL;
goto epilogue;
}
mcpaddr = dsp_get_listen_addr();
ppriaddr = dsp_get_pri_addr();
if (!ppriaddr)
{
MPTlAddrZero(&priaddr, MPPROTO_UDPIP);
use_pri = false;
}
else
{
memcpy((caddr_t)&priaddr, (caddr_t)ppriaddr, sizeof(priaddr));
use_pri = true;
}
if ( ! xdr_MPTLADDR(out, mcpaddr) ||
! xdr_u_long(out, &use_pri) ||
! xdr_MPTLADDR(out, &priaddr) )
{
DebugT("004Q7", 2, "Failed to xdr my own MCP data for peer MCP listing");
status = MCP_INTERNAL;
goto epilogue;
}
if (status == MCP_OK)
for (cur = mcplist; cur; cur = cur->next)
if (cur->session)
{
if (! xdr_MPTLADDR(out, &cur->addr) ||
! xdr_u_long(out, &use_pri) ||
! xdr_MPTLADDR(out, &cur->priaddr))
{
DebugT("004Q8", 2, "Failed to XDR a peer MCP");
status = MCP_INTERNAL;
break;
}
}
epilogue:
lock_mutex_unlock(&mcpmutex);
DebugT("004Q9", 5, "Returning %d mcp addresses.", count);
return (status);
}
/*
* Send request to all MCPs
*
* Valid for:
* MCP-to-MCP relaying of MCP_ADMIN_MESSAGE only
* Input:
* u_long Message code
* caddr_t Base of buffer to be sent
* u_long Length of buffer to be sent
* Output:
* none
*/
void
mcp_request_all(u_long code, caddr_t buffer, u_long length)
{
long count = 0;
mcpp cur;
int status = MCP_OK;
char tladdrstr[80];
lock_mutex_lock(&mcpmutex);
for (cur = mcplist; cur; cur = cur->next)
{
status = MPCReq(cur->session,
code,
buffer,
length,
NULL,
NULL);
if (status == MCP_OK)
{
count++;
}
else
{
MPTLADDRtostr(&cur->addr, tladdrstr);
DebugT("004QA", 6, "Failed mcp_request_all with code %d, msg length %d, to MCP at %s, returned error %d (0x%x)",
code,
length,
tladdrstr,
status,
MPErrorGet());
}
}
lock_mutex_unlock(&mcpmutex);
DebugT("004QB", 6, "FNORD: sent to %d MCPs.", count);
}
/*
* Get our local MCP identifier.
*
* Valid for:
* Anyone (it's useless information to anyone but another MCP, though.)
* Input:
* none
* Output:
* u_long MCP identifier.
*/
int
rnr_g_mcp_id(struct runner *rnr, XDR *xdrs, XDR *out)
{
u_long mcpno = mcp_number();
if (! xdr_u_long(out, &mcpno))
{
DebugT("004QC", 0, "Can't encode MCP ID");
return (MCP_INTERNAL);
}
return (MCP_OK);
}
/*
* Accept information from a peer MCP.
*
* Valid for:
* Admin
* Input:
* MPTLADDR Peer's listen address.
* u_long Peer's MCP number.
* Output:
* None
*/
int
rnr_s_mcp_info(struct runner *rnr, XDR *in, XDR *out)
{
MPTLADDR hisaddr;
u_long hisid;
u_long use_pri;
MPTLADDR hispriaddr;
mcpp new;
char addrstr[150];
int status = MCP_OK;
if (! xdr_MPTLADDR(in, &hisaddr) ||
! xdr_u_long(in, &hisid) ||
! xdr_u_long(in, &use_pri) ||
! xdr_MPTLADDR(in, &hispriaddr))
return (MCP_INVALID);
MPTLADDRtostr(&hisaddr, addrstr);
DebugT("004QE", 1, "Received registration from MCP %lu at %s", hisid, addrstr);
lock_mutex_lock(&mcpmutex);
new = mcp_peer_add(&hisaddr, use_pri, &hispriaddr,
MCP_SOURCE_AUTHORITATIVE);
if (new)
{
/*
* Don't set the session; we'll need to log in on the next
* pass and authenticate ourselves to him. Having a connection
* where two MCPs think they're mutually logged in will most
* likely screw up the encryption.
*/
new->id = hisid;
}
else
status = MCP_INTERNAL;
lock_mutex_unlock(&mcpmutex);
cond_signal(&mcpcond);
/*
* Clear the user cache since we don't know what he has cached, and
* there might be inconsistencies.
*/
user_cache_clear();
return (MCP_OK);
}
/*
* Invalidate a cache entry.
*
* Valid for:
* Admin
* Input:
* u_long Cache entry type to clear
* varies Which entry -- type depends on first param
* Output:
* None
*/
int
rnr_cache_inval(struct runner *rnr, XDR *in, XDR *out)
{
u_long type;
char *username = NULL;
if (! xdr_u_long(in, &type))
return (MCP_INVALID);
switch (type) {
case CACHE_TYPE_USER:
if (! xdr_string(in, &username, 100))
return (MCP_INVALID);
user_cache_delete(username);
debug_free(username);
return (MCP_OK);
}
return (MCP_INVALID);
}
/*
* Process a session close; it might be a peer.
*/
int
mcp_peer_kill(void *session)
{
mcpp cur;
int foundit = 0;
MPTLADDR hisaddr;
lock_mutex_lock(&mcpmutex);
for (cur = mcplist; cur; cur = cur->next)
{
if (cur->session == session)
{
DebugT("004QN", 4, "Lost session to MCP %lu", cur->id);
memcpy(&hisaddr,
cur->use_pri ?
&cur->priaddr :
&cur->addr,
sizeof(hisaddr));
cur->session = NULL;
cur->death = time(NULL);
known_mcps--;
foundit = 1;
}
}
lock_mutex_unlock(&mcpmutex);
if (foundit)
{
tell_mm_about_mcp(&hisaddr, 0);
tell_servorum_about_mcp(&hisaddr, 0);
return (0);
}
return (1);
}
/*
* Queue up an MCP address to be considered as a peer.
*/
int
mcp_peer_suggest(MPTLADDR *mcpaddr)
{
if (initial_mcps)
initial_mcps = debug_realloc(initial_mcps,
(initial_mcp_count + 1) * sizeof(MPTLADDR));
else
initial_mcps = debug_malloc(sizeof(MPTLADDR));
if (initial_mcps)
{
memcpy(&initial_mcps[initial_mcp_count++], mcpaddr,
sizeof(MPTLADDR));
return (0);
}
else
{
initial_mcp_count = 0;
return (1);
}
}
/*
* Get the session handle, if any, for a particular MCP.
*/
void *
mcp_peer_session(u_long mcp_id)
{
mcpp cur;
void *sess = NULL;
lock_mutex_lock(&mcpmutex);
for (cur = mcplist; cur; cur = cur->next)
{
if (cur->id == mcp_id)
{
sess = cur->session;
break;
}
}
lock_mutex_unlock(&mcpmutex);
return (sess);
}
/*
* Initialize the list of peer MCPs, and spawn off the thread that'll poll
* them periodically to discover neighbors.
*/
int
mcp_peer_init()
{
thread_t thread;
MPTLADDR priaddr;
lock_mutex_init(&mcpmutex, "rnr_mcp.c:mcpmutex", 100);
if (cond_init(&mcpcond, USYNC_THREAD, 0))
{
DebugT("004QP", 0, "Can't set up locking for peer MCP list");
return (1);
}
MPTlAddrZero(&priaddr, MPPROTO_UDPIP);
while (initial_mcp_count--)
mcp_peer_add(&initial_mcps[initial_mcp_count], false, &priaddr,
MCP_SOURCE_INIT);
if (thr_create(NULL, 0, mcp_peer_loop, NULL, THR_DETACHED, &thread))
{
DebugT("004QQ", 1, "Can't set up peer MCP scanning thread");
return (1);
}
return (0);
}
/*
* Kick the main loop into action.
*/
void
mcp_peer_kick()
{
cond_signal(&mcpcond);
}
there mcp code