/* xenix.c */ #include "copyright.h" /* Hacked by Lawrence Foard to make a Xenix interface for TinyMUD */ /*#include <stdio.h>*/ #include <prototypes.h> #include <sys/signal.h> #include <stdio.h> #include <sys_2.3/types.h> #include <sys/file.h> #include <sys/timeb.h> #include <sys/times.h> /*#include <signal.h>*/ #include <sys/ioctl.h> #include <fcntl.h> #include <sys/errno.h> #include <ctype.h> #include "config.h" #include "db.h" #include "interface.h" #include "fifo.h" char ccom[1204]; dbref cplr; extern int errno; int shutdown_flag = 0; static const char *connect_fail = "Either that player does not exist, or has a different password.\n"; static const char *create_fail = "Either there is already a player with that name, or that name is illegal.\n"; static const char *flushed_message = "<Output Flushed>\n"; static const char *shutdown_message = "Going down - Bye\n"; /* size of user input and output buffers */ #define IBUF 1024 #define OBUF 4096 /* how many I/O descripters? */ #define MAXDES 32 /* max prefix+suffix length */ #define MAXSUF 100 void set_signals (); int bailout (); void shovechars (); void make_nonblocking (); void welcome_user (); void check_connect (); void parse_connect (); void close_sockets (); void dump_users (); void announce_connect (); void announce_disconnect (); void process_commands (); struct descriptor_data { int descriptor; int connected; dbref player; char output_prefix[MAXSUF]; char output_suffix[MAXSUF]; long connected_at; long last_time; FIFO in; FIFO out; }; struct descriptor_data des[MAXDES]; int topdes = 0; #ifndef BOOLEXP_DEBUGGING void main (argc, argv) int argc; char **argv; { char buff[100]; FILE *fi; int a; if (argc < 3) { fprintf (stderr, "Usage: %s infile dumpfile [port]\n", *argv); exit (1); } if (init_game (argv[1], argv[2]) < 0) { fprintf (stderr, "Couldn't load %s!\n", argv[1]); exit (2); } set_signals (); /* go do it */ if (!(fi = fopen ("ports.dat", "r"))) { fprintf (stderr, "ports.dat was not found\n"); exit (1); } while (fgets (buff, 99, fi)) { int fd; /* get rid of \n */ if (*buff) buff[strlen (buff) - 1] = 0; if ((fd = open (buff, O_RDWR)) == -1) fprintf (stderr, "Warning-Couldn't open I/O device %s\n", buff); else { initializesock (&des[topdes++], fd); fprintf (stderr, "Inited: %s\n", buff); } } fclose (fi); shovechars (); close_sockets (); dump_database (); exit (0); } #endif /*BOOLEXP_DEBUGGING*/ void set_signals () { int dump_status (void); /* we don't care about SIGPIPE, we notice it in select() and write() */ /* signal (SIGPIPE, SIG_IGN);*/ /* standard termination signals */ signal (SIGINT, bailout); signal (SIGTERM, bailout); /* catch these because we might as well */ signal (SIGQUIT, bailout); signal (SIGILL, bailout); signal (SIGTRAP, bailout); signal (SIGIOT, bailout); signal (SIGEMT, bailout); signal (SIGFPE, bailout); signal (SIGBUS, bailout); signal (SIGSEGV, bailout); signal (SIGSYS, bailout); signal (SIGTERM, bailout); /* signal (SIGXCPU, bailout);*/ /* signal (SIGXFSZ, bailout);*/ /* signal (SIGVTALRM, bailout);*/ signal (SIGUSR2, bailout); /* status dumper (predates "WHO" command) */ signal (SIGUSR1, dump_status); } /* queue write */ void queue_write (d, buf, size) struct descriptor_data *d; char *buf; int size; { fi_write (&d->out, buf, size); } void queue_string (d, str) struct descriptor_data *d; char *str; { fi_write (&d->out, str, strlen (str)); } void raw_notify (player, msg) dbref player; const char *msg; { struct descriptor_data *d; int a; for (a = 0; a < topdes; a++) { d = &des[a]; if (d->connected && d->player == player) { queue_string (d, msg); queue_write (d, "\n", 1); } } } /* Everything happens here.... */ void shovechars () { struct descriptor_data *d, *dnext; int a = 0, b; while (!shutdown_flag) { /* The manual says Xenix has Select and the compiler claims it doesn't so I gave up and kludged it instead. If you can find the missing select call it would probably work alots better than this.*/ /* wait 1 tenth of a second then poll the streams */ if (!test_top ()) nap (100); else do_top () && do_top && do_top (); if (shutdown_flag) break; for (b = 0; b < topdes; b++) { d = &des[b]; /* only check non connected streams every tenth poll */ if (!d->connected && a != 10) continue; if (!process_input (d)) { fprintf (stderr, "pipe input error %d err %d\n", d->descriptor, errno); /* shutdownsock(d); continue;*/ } if (!process_output (d)) { fprintf (stderr, "pipe output error %d\n", errno); /* shutdownsock(d); continue;*/ } } if (a++ == 10) a = 0; process_commands (); dispatch (); } } void shutdownsock (d) struct descriptor_data *d; { int dd; if (d->connected) { fprintf (stderr, "DISCONNECT descriptor %d player %s(%d)\n", d->descriptor, db[d->player].name, d->player); announce_disconnect (d->player); } else { fprintf (stderr, "DISCONNECT descriptor %d never connected\n", d->descriptor); } fi_close (&d->in); fi_close (&d->out); initializesock (d, d->descriptor); /* restart stream */ } initializesock (d, s) struct descriptor_data *d; int s; { d->descriptor = s; d->connected = 0; make_nonblocking (s); *d->output_prefix = 0; *d->output_suffix = 0; d->last_time = 0; fi_open (&d->in, MAX_INPUT); fi_open (&d->out, MAX_OUTPUT); welcome_user (d); } int process_output (d) struct descriptor_data *d; { int cnt, hope; char *buff; if (!fi_readok (&d->out)) return (1); /* write as much as possible */ if (!(hope = fi_rread (&d->out, &buff))) return (1); cnt = write (d->descriptor, buff, hope); if (cnt < 0) { /* flush fifo */ fi_flush (&d->out); return (0); } fi_munch (&d->out, cnt); /* if everything was written try to write some more */ return ((cnt == hope) ? process_output (d) : 1); } void make_nonblocking (s) int s; { if (fcntl (s, F_SETFL, FNDELAY) == -1) { perror ("make_nonblocking: fcntl"); panic ("FNDELAY fcntl failed"); } } void welcome_user (d) struct descriptor_data *d; { queue_string (d, WELCOME_MESSAGE); } int process_input (d) struct descriptor_data *d; { char buf[1024]; int got; /* make sure we can accept more input first */ if (!fi_writeok (&d->in)) return (1); got = read (d->descriptor, buf, sizeof buf); if (got <= 0) { /* if interrupted system call ignore error */ if ((errno == 5) || (errno == EINTR)) return 1; else return 0; } fi_write (&d->in, buf, got); } void process_commands () { int nprocessed; struct descriptor_data *d, *dnext; struct text_block *t; char buff[1024]; int a; for (a = 0; a < topdes; a++) { d = &des[a]; if (fi_readok (&d->in) &&fi_gets (&d->in, buff, 1024) &&!do_command (d, buff)) shutdownsock (d); } } int do_command (d, command) struct descriptor_data *d; char *command; { if (!*command) return (1); if (!strcmp (command, QUIT_COMMAND)) { return 0; } else if (!strcmp (command, WHO_COMMAND)) { if (d->output_prefix) { queue_string (d, d->output_prefix); queue_write (d, "\n", 1); } dump_users (d); if (d->output_suffix) { queue_string (d, d->output_suffix); queue_write (d, "\n", 1); } } else if (!strncmp (command, PREFIX_COMMAND, strlen (PREFIX_COMMAND))) { strcpy (d->output_prefix, command + strlen (PREFIX_COMMAND)); } else if (!strncmp (command, SUFFIX_COMMAND, strlen (SUFFIX_COMMAND))) { strcpy (d->output_suffix, command + strlen (SUFFIX_COMMAND)); } else { if (d->connected) { if (*d->output_prefix) { queue_string (d, d->output_prefix); queue_write (d, "\n", 1); } strcpy (ccom, command); cplr = d->player; process_command (d->player, command); if (*d->output_suffix) { queue_string (d, d->output_suffix); queue_write (d, "\n", 1); } } else { check_connect (d, command); } } return 1; } void check_connect (d, msg) struct descriptor_data *d; const char *msg; { char command[MAX_COMMAND_LEN]; char user[MAX_COMMAND_LEN]; char password[MAX_COMMAND_LEN]; dbref player; parse_connect (msg, command, user, password); if (!strncmp (command, "co", 2)) { player = connect_player (user, password); if (player == NOTHING) { queue_string (d, connect_fail); fprintf (stderr, "FAILED CONNECT %s on descriptor %d\n", user, d->descriptor); } else { fprintf (stderr, "CONNECTED %s(%d) on descriptor %d\n", db[player].name, player, d->descriptor); d->connected = 1; d->connected_at = time (0); d->player = player; do_look_around (player); announce_connect (player); } } else if (!strncmp (command, "cr", 2)) { player = create_player (user, password); if (player == NOTHING) { queue_string (d, create_fail); fprintf (stderr, "FAILED CREATE %s on descriptor %d\n", user, d->descriptor); } else { fprintf (stderr, "CREATED %s(%d) on descriptor %d\n", db[player].name, player, d->descriptor); d->connected = 1; d->connected_at = time (0); d->player = player; do_look_around (player); announce_connect (player); } } else { welcome_user (d); } } void parse_connect (msg, command, user, pass) const char *msg; char *command; char *user; char *pass; { char *p; while (*msg && isascii (*msg) && isspace (*msg)) msg++; p = command; while (*msg && isascii (*msg) && !isspace (*msg)) *p++ = *msg++; *p = '\0'; while (*msg && isascii (*msg) && isspace (*msg)) msg++; p = user; while (*msg && isascii (*msg) && !isspace (*msg)) *p++ = *msg++; *p = '\0'; while (*msg && isascii (*msg) && isspace (*msg)) msg++; p = pass; while (*msg && isascii (*msg) && !isspace (*msg)) *p++ = *msg++; *p = '\0'; } void close_sockets () { struct descriptor_data *d, *dnext; int a; for (a = 0; a < topdes; a++) { d = &des[a]; write (d->descriptor, shutdown_message, strlen (shutdown_message)); close (d->descriptor); } } void emergency_shutdown () { close_sockets (); } void boot_off (player) dbref player; { struct descriptor_data *d; int a; for (a = 0; a < topdes; a++) { d = &des[a]; if (d->connected && d->player == player) shutdownsock (d); } } int bailout (sig, code, scp) int sig; int code; struct sigcontext *scp; { char message[1024]; sprintf (message, "BAILOUT: caught signal %d code %d", sig, code); panic (message); _exit (7); return 0; } int dump_status () { /* struct descriptor_data *d; long now; (void) time (&now); fprintf (stderr, "STATUS REPORT:\n"); for (d = descriptor_list; d; d = d->next) { if (d->connected) { fprintf (stderr, "PLAYING descriptor %d player %s(%d)", d->descriptor, db[d->player].name, d->player); if (d->last_time) fprintf (stderr, " idle %d seconds\n", now - d->last_time); else fprintf (stderr, " never used\n"); } else { fprintf (stderr, "CONNECTING descriptor %d", d->descriptor); if (d->last_time) fprintf (stderr, " idle %d seconds\n", now - d->last_time); else fprintf (stderr, " never used\n"); } } return 0;*/ } void dump_users (e) struct descriptor_data *e; { struct descriptor_data *d; long now; int a; char buf[1024]; time (&now); queue_string (e, "Player Name On For Idle\n"); for (a = 0; a < topdes; a++) { d = &des[a]; if (d->connected) { /* sprintf (buf, "%-16s %10s %4s", db[d->player].name, time_format_1(now - d->connected_at), time_format_2(now - d->last_time));*/ sprintf (buf, "%s", db[d->player].name); queue_string (e, buf); queue_write (e, "\n", 1); } } } void announce_connect (player) dbref player; { dbref loc; char buf[BUFFER_LEN]; if ((loc = getloc (player)) == NOTHING) return; if (Dark (player) || Dark (loc)) return; sprintf (buf, "%s has connected.", db[player].name); notify_except (db[loc].contents, player, buf); db[player].flags |= PLAYER_CONNECT; } void announce_disconnect (player) dbref player; { dbref loc; int num, a; char buf[BUFFER_LEN]; if ((loc = getloc (player)) == NOTHING) return; if (Dark (player) || Dark (loc)) return; sprintf (buf, "%s has disconnected.", db[player].name); notify_except (db[loc].contents, player, buf); for (num = a = 0; a < MAXDES; a++) if (des[a].connected && (des[a].player == player)) num++; if (num < 2) db[player].flags &= ~PLAYER_CONNECT; }