/* Copyright (c) 1993 Stephen F. White */ #include <stdio.h> #ifdef SYSV #include <string.h> #else #include <strings.h> #endif #include <ctype.h> #include <signal.h> #include <sys/types.h> #include <sys/time.h> #include <sys/resource.h> #include <sys/wait.h> #include "config.h" #include "cool.h" #include "proto.h" #include "sys_proto.h" #include "netio.h" #include "execute.h" #ifdef PROTO time_t time(time_t *t); #endif int promiscuous = 0; int corefile = 0; int compiler = 0; int registration = 0; int verify_servers = 0; Objid sys_obj; /* shortcut, d00d */ static int read_welcome(const char *fname); Playerid find_player(const char *name); void panic(const char *s) { writelog(); fprintf(stderr, "PANIC: %s\n", s); shutdown_server(); } /* * init() * * Initializes the database and dumpfile, loads and connects to * remote servers (if possible). Also calls SYSOBJ.boot_server() in * the newly-loaded database. */ int init(const char *dbfilename, int send_boot, int db_must_exist) { char buf[MAX_PATH_LEN]; /* sys_obj is a global to save shoving SYS_OBJ in a local var each time */ sys_obj.server = 0; sys_obj.id = SYS_OBJ; /* read config file */ sprintf(buf, "%s.cfg", dbfilename); writelog(); fprintf(stderr, "Reading config file from %s\n", buf); if (read_config(buf)) { writelog(); fprintf(stderr, "Couldn't read config file\n"); return -2; } /* if */ sprintf(buf, "%s.welcome", dbfilename); if (read_welcome(buf)) { return -3; } /* if */ /* initialize db and cache */ writelog(); fprintf(stderr, "Initializing db\n"); dddb_setfile(dbfilename); if (dddb_init(db_must_exist)) { return -4; } writelog(); fprintf(stderr, "Initializing cache\n"); if (cache_init()) { return -5; } /* initialize system symbol table */ sym_init_sys(); /* initialize random number generator */ srandom((int) time((time_t *) 0)); /* initialize opcode table */ opcode_init(); /* call SYS_OBJ.boot_server() */ if (send_boot) { send_message(-1, 0, 0, sys_obj, sys_obj, sys_obj, sym_sys(BOOT_SERVER), list_dup(empty_list), 0, sys_obj); } return 0; } static int read_welcome(const char *fname) { FILE *f; String *str; int c; if (!(f = fopen(fname, "r"))) { writelog(); perror(fname); return -1; } str = string_new(0); while ((c = getc(f)) != EOF) { str = string_catc(str, c); } fclose(f); welcome = str->str; return 0; } void shutdown_server(void) { writelog(); fprintf(stderr, "Syncing cache\n"); cache_sync(); writelog(); fprintf(stderr, "Closing database\n"); dddb_close(); } Error sys_get_global(const char *var, Var *r) { Object *sys; if (!(sys = retrieve(sys_obj))) { writelog(); fprintf(stderr, "SYS_OBJ: #%d not found\n", SYS_OBJ); return E_OBJNF; } else if (var_get_global(sys, var, r) == E_VARNF) { writelog(); fprintf(stderr, "SYS_OBJ: #%d.%s missing\n", SYS_OBJ, var); return E_VARNF; } else { return E_NONE; } } Error sys_assign_global(const char *var, Var value) { Object *sys; if (!(sys = retrieve(sys_obj))) { writelog(); fprintf(stderr, "SYS_OBJ: #%d not found\n", SYS_OBJ); return E_OBJNF; } else if (var_assign_global(sys, string_cpy(var), value) == E_TYPE) { writelog(); fprintf(stderr, "SYS_OBJ: #%d.%s assignment: type mismatch\n", SYS_OBJ, var); return E_TYPE; } else { return E_NONE; } } Playerid find_player(const char *name) { Object *p; Var players, pname; int i; Playerid player = NOTHING; if (sys_get_global("players", &players) != E_NONE) { return NOTHING; } else if (players.type != LIST) { writelog(); fprintf(stderr, "SYS_OBJ: #%d.players is not a list\n", SYS_OBJ); return NOTHING; } else { players = var_dup(players); /* in case sysobj gets swapped out (!) */ for (i = 0; i < players.v.list->len; i++) { if (players.v.list->el[i].type == OBJ && (p = retrieve(players.v.list->el[i].v.obj)) && var_get_global(p, "name", &pname) == E_NONE && pname.type == STR && !cool_strcasecmp(pname.v.str->str, name)) { player = p->id.id; break; } cache_reset(); } var_free(players); } return player; } static void do_connect(Objid player) { List *args = list_new(1); args->el[0].type = OBJ; args->el[0].v.obj = player; send_message(-1, 0, 0, player, sys_obj, sys_obj, sym_sys(CONNECT_PLAYER), args, 0, sys_obj); } Playerid connect_player(const char *name, const char *password) { Objid player; Var ppassword; Object *p; char salt[3]; player.server = 0; if (!name || !*name || !password) { return NOTHING; } else if ((player.id = find_player(name)) == NOTHING) { return NOTHING; } else if (!(p = retrieve(player))) { return NOTHING; } else if (var_get_global(p, "password", &ppassword) == E_VARNF || ppassword.type != STR || !ppassword.v.str->str[0]) { do_connect(player); cache_reset(); return player.id; } salt[0] = ppassword.v.str->str[0]; salt[1] = ppassword.v.str->str[1]; salt[2] = '\0'; if (!strcmp(crypt(password, salt), ppassword.v.str->str)) { do_connect(player); cache_reset(); return player.id; } else { return NOTHING; } } Playerid create_player(const char *name, const char *password) { Var strv, pclass; Object *p; char salt[3]; static char saltstuff[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"; List *args; struct timeval cur_time; salt[0] = saltstuff[random() % strlen(saltstuff)]; salt[1] = saltstuff[random() % strlen(saltstuff)]; salt[2] = '\0'; if (!name || !*name || !password || !*password) { return NOTHING; } else if (sys_get_global("player_class", &pclass) != E_NONE) { return NOTHING; } else if (pclass.type != OBJ) { writelog(); fprintf(stderr, "SYS_OBJ: #%d.player_class is not an obj\n", SYS_OBJ); return NOTHING; } if (find_player(name) != NOTHING) { return NOTHING; } p = clone(pclass.v.obj); if (!p) { writelog(); fprintf(stderr, "SYS_OBJ: couldn't clone #%d\n", pclass.v.obj.id); return NOTHING; } (void) send_message(-1, 0, 0, sys_obj, sys_obj, p->id, sym_sys(INIT), list_dup(empty_list), 0, p->id); gettimeofday(&cur_time, 0); process_queues(cur_time, &cur_time); /* do player init */ strv.type = STR; strv.v.str = string_cpy(name); (void) var_assign_global(p, sym_sys(NAME), strv); strv.v.str = string_cpy(crypt(password, salt)); (void) var_assign_global(p, sym_sys(PASSWORD), strv); args = list_new(1); args->el[0].type = OBJ; args->el[0].v.obj = p->id; send_message(-1, 0, 0, p->id, sys_obj, sys_obj, sym_sys(CREATE_PLAYER), args, 0, sys_obj); return p->id.id; } void disconnect_player(Playerid who) { List *args; Objid player; player.id = who; player.server = 0; args = list_new(1); args->el[0].type = OBJ; args->el[0].v.obj = player; send_message(-1, 0, 0, player, sys_obj, sys_obj, sym_sys(DISCONNECT_PLAYER), args, 0, sys_obj); } void connect_server(Serverid server) { List *args; args = list_new(1); args->el[0].type = OBJ; args->el[0].v.obj.id = 0; args->el[0].v.obj.server = server; (void) send_message(-1, 0, 0, sys_obj, sys_obj, sys_obj, sym_sys(CONNECT_SERVER), args, 0, sys_obj); } void disconnect_server(Serverid server) { List *args; args = list_new(1); args->el[0].type = OBJ; args->el[0].v.obj.id = 0; args->el[0].v.obj.server = server; (void) send_message(-1, 0, 0, sys_obj, sys_obj, sys_obj, sym_sys(DISCONNECT_SERVER), args, 0, sys_obj); } static Playerid progr; /* programmer */ int prog_getc(void); void prog_ungetc(int c); void prog_error(const char *s); /* error function */ FILE *progfile; int prog_getc(void) { return getc(progfile); } void prog_ungetc(int c) { ungetc(c, progfile); } void prog_error(const char *s) { tell(progr, s); } void do_compile(Playerid player, FILE *pf, GENPTR progwhat) { int *data = (int *) progwhat; Objid obj; String *method; int nerrors; Object *new; obj.server = 0; obj.id = data[0]; method = (String *) data[1]; progr = player; progfile = pf; if (obj.id < 0) { /* multiple objects */ nerrors = compile(player, prog_getc, prog_ungetc, prog_error, 0, 0, 0, 0, 0); } else { /* single method */ if (!(new = retrieve(obj))) { tell(player, "Object no longer exists!"); } else { nerrors = compile(player, prog_getc, prog_ungetc, prog_error, 1, new, method, 0, 0); } string_free(method); } cache_reset(); FREE(progwhat); }