home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Overload
/
ShartewareOverload.cdr
/
games
/
tinymud2.zip
/
INTERFAC.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-09-02
|
34KB
|
1,505 lines
/* Concentrator upgraded June 1990 Robert Hood */
/* modifed Concentrator to match Fuzzy & Randoms 1.5.4 changes = 6/90 Fuzzy */
/* modified interface.c to support LOTS of people, using a concentrator */
/* May 1990, Robert Hood */
/* #define CHECKC /* consistency checking */
#include <stdio.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/time.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/errno.h>
#include <ctype.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include "config.h"
#include "db.h"
#include "interface.h"
#define BUFSIZE 0xFFFF
struct text_block
{
int nchars;
struct text_block *nxt;
char *start;
char *buf;
};
struct text_queue
{
struct text_block *head;
struct text_block **tail;
};
struct descriptor_data
{
int descriptor;
int num;
int connected;
dbref player;
char *output_prefix;
char *output_suffix;
int output_size;
struct text_queue output;
struct text_queue input;
char *raw_input;
char *raw_input_at;
long connected_at;
long last_time;
int quota;
struct sockaddr_in address; /* added 3/6/90 SCG */
char *hostname; /* 5/18/90 - Fuzzy */
struct descriptor_data *next;
};
#define MALLOC(result, type, number) do { \
if (!((result) = (type *) malloc ((number) * sizeof (type)))) \
panic("Out of memory"); \
} while (0)
#define FREE(x) (free((void *) x))
struct message
{
char *data;
short len;
struct message *next;
};
struct conc_list
{
struct conc_list *next;
int sock, current, status;
struct descriptor_data *firstd;
struct message *first, *last;
char *incoming, *outgoing;
int ilen, olen;
} *firstc = 0;
void queue_message(struct conc_list * c, char *data, int len);
void start_log();
struct timeval timeval_sub(struct timeval now, struct timeval then);
struct timeval msec_add(struct timeval t, int x);
struct timeval update_quotas(struct timeval last, struct timeval current);
void main_loop();
int notify(dbref player, const char *msg);
void process_output(struct conc_list * c);
int process_input(struct descriptor_data * d, char *buf, int got);
void process_commands();
void dump_users(struct descriptor_data * e, char *user);
void free_text_block(struct text_block * t);
void main(int argc, char **argv);
void set_signals();
int msec_diff(struct timeval now, struct timeval then);
void clearstrings(struct descriptor_data * d);
void shutdownsock(struct descriptor_data * d);
struct descriptor_data *initializesock(struct sockaddr_in * a);
struct text_block *make_text_block(const char *s, int n);
void add_to_queue(struct text_queue * q, const char *b, int n);
int flush_queue(struct text_queue * q, int n);
int queue_write(struct descriptor_data * d, const char *b, int n);
int queue_string(struct descriptor_data * d, const char *s);
void freeqs(struct descriptor_data * d);
void welcome_user(struct descriptor_data * d);
void do_motd(dbref);
char *strsave(const char *s);
void save_command(struct descriptor_data * d, const char *command);
void set_userstring(char **userstring, const char *command);
int do_command(struct descriptor_data * d, char *command);
void check_connect(struct descriptor_data * d, const char *msg);
void parse_connect(const char *msg, char *command, char *user, char *pass);
void close_sockets();
void emergency_shutdown(void);
void boot_off(dbref player);
int bailout(int sig, int code, struct sigcontext * scp);
char *time_format_1(long dt);
char *time_format_2(long dt);
#ifdef CONNECT_MESSAGES
void announce_connect(dbref);
void announce_disconnect(dbref);
#endif /* CONNECT_MESSAGES */
int sigshutdown(int, int, struct sigcontext *);
int logsynch();
char *logfile = LOG_FILE;
int debug;
void chg_userid();
void file_date(struct descriptor_data * d, const char *file);
static const char *connect_fail = "Either that player does not exist, or has a different password.\n";
#ifndef REGISTRATION
static const char *create_fail = "Either there is already a player with that name, or that name is illegal.\n";
#endif /* REGISTRATION */
static const char *flushed_message = "<Output Flushed>\n";
static const char *shutdown_message = "Going down - Bye\n";
int sock;
int shutdown_flag = 0;
int port = TINYPORT;
int intport = INTERNAL_PORT;
start_port()
{
int temp;
struct sockaddr_in sin;
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 1)
{
perror("socket");
exit(-1);
}
temp = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&temp, sizeof(temp));
sin.sin_family = AF_INET;
sin.sin_port = htons(intport);
sin.sin_addr.s_addr = htonl(INADDR_ANY);
temp = bind(sock, (struct sockaddr *) & sin, sizeof(sin));
if (temp < 0)
{
perror("bind");
exit(-1);
}
temp = listen(sock, 5);
if (temp < 0)
{
perror("listen");
exit(-1);
}
}
struct timeval
timeval_sub(struct timeval now, struct timeval then)
{
now.tv_sec -= then.tv_sec;
now.tv_usec -= then.tv_usec;
if (now.tv_usec < 0)
{
now.tv_usec += 1000000;
now.tv_sec--;
}
return now;
}
struct timeval
msec_add(struct timeval t, int x)
{
t.tv_sec += x / 1000;
t.tv_usec += (x % 1000) * 1000;
if (t.tv_usec >= 1000000)
{
t.tv_sec += t.tv_usec / 1000000;
t.tv_usec = t.tv_usec % 1000000;
}
return t;
}
struct timeval
update_quotas(struct timeval last, struct timeval current)
{
int nslices;
struct descriptor_data *d;
struct conc_list *c;
nslices = msec_diff(current, last) / COMMAND_TIME_MSEC;
if (nslices > 0)
{
for (c = firstc; c; c = c->next)
for (d = c->firstd; d; d = d->next)
{
d->quota += COMMANDS_PER_TIME * nslices;
if (d->quota > COMMAND_BURST_SIZE)
d->quota = COMMAND_BURST_SIZE;
}
}
return msec_add(last, nslices * COMMAND_TIME_MSEC);
}
int
notify(dbref player2, const char *msg)
{
struct descriptor_data *d;
struct conc_list *c;
int retval = 0;
#ifdef COMPRESS
extern const char *uncompress(const char *);
msg = uncompress(msg);
#endif /* COMPRESS */
for (c = firstc; c; c = c->next)
for (d = c->firstd; d; d = d->next)
{
if (d->connected && d->player == player2)
{
queue_string(d, msg);
queue_write(d, "\n", 1);
retval++;
}
}
return (retval);
}
int
process_input(d, buf, got)
struct descriptor_data *d;
char *buf;
int got;
{
char *p, *pend, *q, *qend;
d->last_time = time(0);
if (!d->raw_input)
{
MALLOC(d->raw_input, char, MAX_COMMAND_LEN);
d->raw_input_at = d->raw_input;
}
p = d->raw_input_at;
pend = d->raw_input + MAX_COMMAND_LEN - 1;
for (q = buf, qend = buf + got; q < qend; q++)
{
if (*q == '\n')
{
*p = '\0';
if (p > d->raw_input)
save_command(d, d->raw_input);
p = d->raw_input;
} else
if (p < pend && isascii(*q) && isprint(*q))
{
*p++ = *q;
}
}
if (p > d->raw_input)
{
d->raw_input_at = p;
} else
{
FREE(d->raw_input);
d->raw_input = 0;
d->raw_input_at = 0;
}
return 1;
}
void process_commands()
{
int nprocessed;
struct descriptor_data *d, *dnext, *dlast;
struct conc_list *c;
struct text_block *t;
char header[4];
do
{
nprocessed = 0;
for (c = firstc; c; c = c->next)
{
dlast = 0;
for (d = c->firstd; d; d = dnext)
{
dnext = d->next;
if (d->quota > 0 && (t = d->input.head))
{
d->quota--;
nprocessed++;
if (!do_command(d, t->start))
{
header[0] = 0;
header[1] = 2;
header[2] = d->num;
queue_message(c, header, 3);
if (dlast)
dlast->next = dnext;
else
c->firstd = dnext;
shutdownsock(d);
FREE(d);
break;
} else
{
d->input.head = t->nxt;
if (!d->input.head)
d->input.tail = &d->input.head;
free_text_block(t);
}
}
dlast = d;
}
}
} while (nprocessed > 0);
}
void dump_users(struct descriptor_data * e, char *user)
{
static struct conc_list *rwclist[NOFILE];
static struct descriptor_data *rwdlist[NOFILE];
int ccount, dcount, dloop, cloop;
struct descriptor_data *d;
struct conc_list *c;
long now;
int counter = 0;
static int maxcounter = 0;
int wizard, reversed, tabular;
char buf[1024];
# ifdef DO_WHOCHECK
writelog("WHO CHECK %d\n", sizeof(rwclist));
writelog("WHO CHECK %d\n", sizeof(rwdlist));
# endif
while (*user && isspace(*user))
user++;
if (!*user)
user = NULL;
reversed = e->connected && Flag(e->player, REVERSED_WHO);
tabular = e->connected && Flag(e->player, TABULAR_WHO);
time(&now);
queue_string(e, tabular ? "Player Name On For Idle\n" :
"Current Players:\n");
#ifdef GOD_MODE
wizard = e->connected && God(e->player);
#else GOD_MODE
wizard = e->connected && Wizard(e->player);
#endif GOD_MODE
if (reversed)
{
ccount = 0;
for (c = firstc; c; c = c->next)
rwclist[ccount++] = c;
for (cloop = ccount - 1; cloop >= 0; --cloop)
{
dcount = 0;
for (d = rwclist[cloop]->firstd; d; d = d->next)
rwdlist[dcount++] = d;
for (dloop = dcount - 1; dloop >= 0; --dloop)
{
d = rwdlist[dloop];
if (d->connected &&
++counter && /* Count everyone connected */
(!user || string_prefix(db[d->player].name, user)))
{
if (tabular)
{
sprintf(buf, "%-16s %10s %4s",
db[d->player].name,
time_format_1(now - d->connected_at),
time_format_2(now - d->last_time));
if (wizard)
sprintf(buf, "%s %s", buf, d->hostname);
} else
{
sprintf(buf, "%s idle %d seconds",
db[d->player].name, now - d->last_time);
if (wizard)
sprintf(buf, "%s from host %s", buf, d->hostname);
}
strcat(buf, "\n");
queue_string(e, buf);
}
}
}
} else
{
for (c = firstc; c; c = c->next)
{
for (d = c->firstd; d; d = d->next)
{
if (d->connected &&
++counter && /* Count everyone connected */
(!user || string_prefix(db[d->player].name, user)))
{
if (tabular)
{
sprintf(buf, "%-16s %10s %4s",
db[d->player].name,
time_format_1(now - d->connected_at),
time_format_2(now - d->last_time));
if (wizard)
sprintf(buf, "%s %s", buf, d->hostname);
} else
{
sprintf(buf, "%s idle %d seconds",
db[d->player].name, now - d->last_time);
if (wizard)
sprintf(buf, "%s from host %s", buf, d->hostname);
}
strcat(buf, "\n");
queue_string(e, buf);
}
}
}
}
if (counter > maxcounter)
{ maxcounter = counter;
if (counter > 30)
{ writelog ("%d users logged in\n", counter); }
}
sprintf(buf, "%d user%s connected\n", counter,
counter == 1 ? " is" : "s are");
queue_string(e, buf);
}
void free_text_block(struct text_block * t)
{
FREE(t->buf);
FREE((char *)t);
}
#ifndef BOOLEXP_DEBUGGING
void main(int argc, char **argv)
{
int pid;
if (argc < 3)
{
fprintf(stderr, "Usage: %s infile dumpfile [port iport logfile]\n", *argv);
exit(1);
}
if (argc > 3)
port = atoi(argv[3]);
if (argc > 4)
intport = atoi(argv[4]);
if (argc > 5)
logfile = argv[5];
start_log();
if (init_game(argv[1], argv[2]) < 0)
{
writelog("INIT: Couldn't load %s\n", argv[1]);
exit(2);
}
pid = vfork();
if (pid < 0)
{
perror("fork");
exit(-1);
}
if (pid == 0)
{
char pstr[32], istr[32], clvl[32];
/* Add port argument to concentrator */
sprintf(pstr, "%d", port);
sprintf(istr, "%d", intport);
sprintf(clvl, "%d", 1);
execl("concentrate", "conc", pstr, istr, clvl, 0);
}
set_signals();
start_port(port);
main_loop();
close_sockets();
dump_database();
exit(0);
}
#endif
void start_log()
{
#ifdef DETACH
if (!debug)
{
int i;
if (fork() != 0)
exit(0);
i = open("/dev/tty", O_RDWR, 0);
if (i != -1)
{
ioctl(i, TIOCNOTTY, 0);
close(i);
}
}
freopen(logfile, "a", stderr);
setbuf(stderr, NULL);
#endif /* DETACH */
}
void set_signals(void)
{
int dump_status(void);
signal(SIGPIPE, SIG_IGN);
signal(SIGINT, (void *)sigshutdown);
signal(SIGTERM, (void *)sigshutdown);
#ifdef DETACH
signal(SIGUSR2, (void *)logsynch);
#else /* DETACH */
signal(SIGUSR2, (void *)bailout);
#endif /* DETACH */
if (debug)
return;
# ifdef NOCOREDUMP
signal(SIGQUIT, (void *)bailout);
signal(SIGILL, (void *)bailout);
signal(SIGTRAP, (void *)bailout);
signal(SIGIOT, (void *)bailout);
signal(SIGEMT, (void *)bailout);
signal(SIGFPE, (void *)bailout);
signal(SIGBUS, (void *)bailout);
signal(SIGSEGV, (void *)bailout);
signal(SIGSYS, (void *)bailout);
signal(SIGTERM, (void *)bailout);
signal(SIGXCPU, (void *)bailout);
signal(SIGXFSZ, (void *)bailout);
signal(SIGVTALRM, (void *)bailout);
# endif
}
int
msec_diff(struct timeval now, struct timeval then)
{
return ((now.tv_sec - then.tv_sec) * 1000
+ (now.tv_usec - then.tv_usec) / 1000);
}
void
clearstrings(struct descriptor_data * d)
{
if (d->output_prefix)
{
FREE(d->output_prefix);
d->output_prefix = 0;
}
if (d->output_suffix)
{
FREE(d->output_suffix);
d->output_suffix = 0;
}
}
void
shutdownsock(struct descriptor_data * d)
{
if (d->connected)
{
writelog("DISCONNECT descriptor %d,%d player %s(%d)\n", d->descriptor, d->num, db[d->player].name, d->player);
#ifdef CONNECT_MESSAGES
announce_disconnect(d->player);
#endif /* CONNECT_MESSAGES */
} else
{
writelog("DISCONNECT descriptor %d,%d never connected\n", d->descriptor, d->num);
}
clearstrings(d);
freeqs(d);
}
struct descriptor_data *
initializesock(struct sockaddr_in * a)
{
struct descriptor_data *d;
MALLOC(d, struct descriptor_data, 1);
d->connected = 0;
d->output_prefix = 0;
d->output_suffix = 0;
d->output_size = 0;
d->output.head = 0;
d->output.tail = &d->output.head;
d->input.head = 0;
d->input.tail = &d->input.head;
d->raw_input = 0;
d->raw_input_at = 0;
d->quota = COMMAND_BURST_SIZE;
d->last_time = 0;
d->address = *a; /* This will be the address of the
* concentrator */
d->hostname = ""; /* This will be set during connect */
welcome_user(d);
return d;
}
struct text_block *
make_text_block(const char *s, int n)
{
struct text_block *p;
MALLOC(p, struct text_block, 1);
MALLOC(p->buf, char, n);
bcopy(s, p->buf, n);
p->nchars = n;
p->start = p->buf;
p->nxt = 0;
return p;
}
void
add_to_queue(struct text_queue * q, const char *b, int n)
{
struct text_block *p;
if (n == 0)
return;
p = make_text_block(b, n);
p->nxt = 0;
*q->tail = p;
q->tail = &p->nxt;
}
int
flush_queue(struct text_queue * q, int n)
{
struct text_block *p;
int really_flushed = 0;
n += strlen(flushed_message);
while (n > 0 && (p = q->head))
{
n -= p->nchars;
really_flushed += p->nchars;
q->head = p->nxt;
free_text_block(p);
}
p = make_text_block(flushed_message, strlen(flushed_message));
p->nxt = q->head;
q->head = p;
if (!p->nxt)
q->tail = &p->nxt;
really_flushed -= p->nchars;
return really_flushed;
}
int
queue_write(struct descriptor_data * d, const char *b, int n)
{
int space;
space = MAX_OUTPUT - d->output_size - n;
if (space < 0)
d->output_size -= flush_queue(&d->output, -space);
add_to_queue(&d->output, b, n);
d->output_size += n;
return n;
}
int
queue_string(struct descriptor_data * d, const char *s)
{
return queue_write(d, s, strlen(s));
}
void
freeqs(struct descriptor_data * d)
{
struct text_block *cur, *next;
cur = d->output.head;
while (cur)
{
next = cur->nxt;
free_text_block(cur);
cur = next;
}
d->output.head = 0;
d->output.tail = &d->output.head;
cur = d->input.head;
while (cur)
{
next = cur->nxt;
free_text_block(cur);
cur = next;
}
d->input.head = 0;
d->input.tail = &d->input.head;
if (d->raw_input)
FREE(d->raw_input);
d->raw_input = 0;
d->raw_input_at = 0;
}
void
welcome_user(struct descriptor_data * d)
{
queue_string(d, WELCOME_MESSAGE);
file_date(d, NEWS_FILE);
# ifdef CONNECT_FILE
do_connect_msg(d, CONNECT_FILE);
# endif
}
void
goodbye_user(struct descriptor_data * d)
{
queue_string(d, LEAVE_MESSAGE);
}
char *
strsave(const char *s)
{
char *p;
MALLOC(p, char, strlen(s) + 1);
if (p)
strcpy(p, s);
return p;
}
void
save_command(struct descriptor_data * d, const char *command)
{
add_to_queue(&d->input, command, strlen(command) + 1);
}
void
set_userstring(char **userstring, const char *command)
{
if (*userstring)
{
FREE(*userstring);
*userstring = 0;
}
while (*command && isascii(*command) && isspace(*command))
command++;
if (*command)
*userstring = strsave(command);
}
int
do_command(struct descriptor_data * d, char *command)
{
if (!strcmp(command, QUIT_COMMAND))
{
goodbye_user(d);
return 0;
} else
if (!strncmp(command, WHO_COMMAND, strlen(WHO_COMMAND)))
{
if (d->output_prefix)
{
queue_string(d, d->output_prefix);
queue_write(d, "\n", 1);
}
dump_users(d, command + strlen(WHO_COMMAND));
if (d->output_suffix)
{
queue_string(d, d->output_suffix);
queue_write(d, "\n", 1);
}
} else
if (d->connected &&
!strncmp(command, PREFIX_COMMAND, strlen(PREFIX_COMMAND)))
{
#ifdef ROBOT_MODE
if (!Robot(d->player))
{
#ifndef TINKER
notify(d->player,
"Only robots can use OUTPUTPREFIX; contact a Wizard.");
#else TINKER
notify(d->player,
"Only robots can use OUTPUTPREFIX; contact a Tinker.");
#endif TINKER
return 1;
}
if (!d->connected)
return 1;
#endif ROBOT_MODE
set_userstring(&d->output_prefix, command + strlen(PREFIX_COMMAND));
} else
if (d->connected &&
!strncmp(command, SUFFIX_COMMAND, strlen(SUFFIX_COMMAND)))
{
#ifdef ROBOT_MODE
if (!Robot(d->player))
{
#ifndef TINKER
notify(d->player,
"Only robots can use OUTPUTSUFFIX; contact a Wizard.");
#else TINKER
notify(d->player,
"Only robots can use OUTPUTSUFFIX; contact a Tinker.");
#endif TINKER
return 1;
}
#endif ROBOT_MODE
set_userstring(&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);
}
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(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);
writelog("FAILED CONNECT %s on descriptor %d,%d\n", user, d->descriptor, d->num);
} else
{
writelog("CONNECTED %s(%d) on descriptor %d,%d %s\n",
db[player].name, player, d->descriptor, d->num, d->hostname);
d->connected = 1;
d->connected_at = time(NULL);
d->player = player;
do_motd(player);
do_look_around(player);
#ifdef CONNECT_MESSAGES
announce_connect(player);
#endif /* CONNECT_MESSAGES */
}
} else
if (!strncmp(command, "cr", 2))
{
#ifndef REGISTRATION
player = create_player(user, password);
if (player == NOTHING)
{
queue_string(d, create_fail);
writelog("FAILED CREATE %s on descriptor %d,%d %s\n",
user, d->descriptor, d->num, d->hostname);
} else
{
writelog("CREATED %s(%d) on descriptor %d,%d %s\n",
db[player].name, player, d->descriptor, d->num, d->hostname);
d->connected = 1;
d->connected_at = time(0);
d->player = player;
do_motd(player);
do_look_around(player);
#ifdef CONNECT_MESSAGES
announce_connect(player);
#endif /* CONNECT_MESSAGES */
}
#else
queue_string(d, REGISTER_MESSAGE);
#endif /* REGISTRATION */
} else
{
welcome_user(d);
}
}
void
parse_connect(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(void)
{
struct descriptor_data *d, *dnext;
struct conc_list *c;
char header[4];
for (c = firstc; c; c = c->next)
{
/* conc.c now handles printing the Going Down - Bye message */
shutdown(c->sock, 0);
close(c->sock);
}
close(sock);
}
void
emergency_shutdown(void)
{
close_sockets();
}
int
bailout(int sig, int code, struct sigcontext * scp)
{
long *ptr;
int i;
writelog("BAILOUT: caught signal %d code %d", sig, code);
ptr = (long *)scp;
for (i = 0; i < sizeof(struct sigcontext); i++)
writelog(" %08lx\n", *ptr);
panic("PANIC on spurious signal");
_exit(7);
return 0;
}
char *
time_format_1(long dt)
{
register struct tm *delta;
static char buf[64];
delta = gmtime(&dt);
if (delta->tm_yday > 0)
{
sprintf(buf, "%dd %02d:%02d",
delta->tm_yday, delta->tm_hour, delta->tm_min);
} else
{
sprintf(buf, "%02d:%02d",
delta->tm_hour, delta->tm_min);
}
return buf;
}
char *
time_format_2(long dt)
{
register struct tm *delta;
static char buf[64];
delta = gmtime(&dt);
if (delta->tm_yday > 0)
{
sprintf(buf, "%dd", delta->tm_yday);
} else
if (delta->tm_hour > 0)
{
sprintf(buf, "%dh", delta->tm_hour);
} else
if (delta->tm_min > 0)
{
sprintf(buf, "%dm", delta->tm_min);
} else
{
sprintf(buf, "%ds", delta->tm_sec);
}
return buf;
}
#ifdef CONNECT_MESSAGES
void
announce_connect(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);
}
void
announce_disconnect(dbref player)
{
dbref loc;
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);
}
#endif /* CONNECT_MESSAGES */
int
sigshutdown(int sig, int code, struct sigcontext * scp)
{
writelog("SHUTDOWN: on signal %d code %d\n", sig, code);
shutdown_flag = 1;
return 0;
}
#ifdef DETACH
int
logsynch()
{
freopen(logfile, "a", stderr);
setbuf(stderr, NULL);
writelog("log file reopened\n");
return 0;
}
#endif /* DETACH */
#include <sys/stat.h>
void
file_date(struct descriptor_data * d, char *file)
{
static char buf[80];
extern char *ctime(long *clock);
struct stat statb;
char *tstring;
char *cp;
if (stat(file, &statb) == -1)
return;
tstring = ctime(&statb.st_mtime);
if ((cp = (char *)index(tstring, '\n')) != NULL)
*cp = '\0';
strcpy(buf, "News last updated ");
strcat(buf, tstring);
strcat(buf, "\n\n");
queue_string(d, (char *)buf);
}
void main_loop()
{
struct message *ptr;
int found, newsock, lastsock, len, loop;
int accepting;
struct timeval tv;
struct sockaddr_in sin;
fd_set in, out;
char data[1025], *p1, *p2, buffer[1025], header[4];
struct conc_list *c, *tempc, *nextc, *lastc;
struct descriptor_data *d, *tempd, *nextd;
struct timeval last_slice, current_time;
struct timeval next_slice;
struct timeval slice_timeout;
short templen;
accepting = 1;
lastsock = sock + 1;
while (!shutdown_flag)
{
gettimeofday(¤t_time, (struct timezone *) 0);
last_slice = update_quotas(last_slice, current_time);
process_commands();
if (shutdown_flag)
break;
next_slice = msec_add(last_slice, COMMAND_TIME_MSEC);
slice_timeout = timeval_sub(next_slice, current_time);
FD_ZERO(&in);
FD_ZERO(&out);
FD_SET(sock, &in);
for (c = firstc; c; c = c->next)
process_output(c);
for (c = firstc; c; c = c->next)
if (c->sock)
{
if (c->ilen < BUFSIZE)
FD_SET(c->sock, &in);
len = c->first ? c->first->len : 0;
while (c->first && ((c->olen + len + 2) < BUFSIZE))
{
templen = c->first->len;
bcopy(&templen, c->outgoing + c->olen, 2);
bcopy(c->first->data, c->outgoing + c->olen + 2, len);
c->olen += len + 2;
ptr = c->first;
c->first = ptr->next;
FREE(ptr->data);
FREE(ptr);
if (c->last == ptr)
c->last = 0;
len = c->first ? c->first->len : 0;
}
if (c->olen)
FD_SET(c->sock, &out);
}
tv.tv_sec = 1000;
tv.tv_usec = 0;
found = select(lastsock, &in, &out, (fd_set *) 0, &tv);
if (found < 0)
continue;
if (accepting && FD_ISSET(sock, &in))
{
len = sizeof(sin);
newsock = accept(sock, (struct sockaddr *) & sin, &len);
if (newsock >= 0)
{
if (newsock >= lastsock)
lastsock = newsock + 1;
if (fcntl(newsock, F_SETFL, FNDELAY) == -1)
{
perror("make_nonblocking: fcntl");
}
MALLOC(tempc, struct conc_list, 1);
tempc->next = firstc;
tempc->firstd = 0;
tempc->first = 0;
tempc->last = 0;
tempc->status = 0;
/* Imcomming and outgoing I/O buffers */
MALLOC(tempc->incoming, char, BUFSIZE);
tempc->ilen = 0;
MALLOC(tempc->outgoing, char, BUFSIZE);
tempc->olen = 0;
firstc = tempc;
firstc->sock = newsock;
writelog("CONCENTRATOR CONNECT: sock %d, addr %x\n", newsock, sin.sin_addr.s_addr);
}
}
for (c = firstc; c; c = nextc)
{
nextc = c->next;
#ifdef CHECKC
if (!(c->sock))
writelog("CONSISTENCY CHECK: Concentrator found with null socket #\n");
#endif
if ((FD_ISSET(c->sock, &in)) && (c->ilen < BUFSIZE))
{
int i;
len = recv(c->sock, c->incoming + c->ilen,
BUFSIZE - c->ilen, 0);
if (len == 0)
{
struct message *mptr, *tempm;
writelog("CONCENTRATOR DISCONNECT: %d\n", c->sock);
close(c->sock);
d = c->firstd;
while (d)
{
shutdownsock(d);
tempd = d;
d = d->next;
FREE(tempd);
}
if (firstc == c)
firstc = firstc->next;
else
lastc->next = c->next;
FREE(c->incoming);
FREE(c->outgoing);
mptr = c->first;
while (mptr)
{
tempm = mptr;
mptr = mptr->next;
FREE(mptr->data);
FREE(mptr);
}
FREE(c);
break;
} else
if (len < 0)
{
writelog("recv: %s\n", strerror(errno));
} else
{
int num;
c->ilen += len;
while (c->ilen > 2)
{
bcopy(c->incoming, &templen, 2);
#ifdef CHECKC
if (templen < 1)
writelog("CONSISTENCY CHECK: Message recived with lenght < 1\n");
#endif
if (c->ilen >= (templen + 2))
{
num = *(c->incoming + 2);
/* Is it coming from the command user #? */
if (num == 0)
{
/* Proccess commands */
switch (*(c->incoming + 3))
{
case 1: /* connect */
d = initializesock(&sin);
d->descriptor = c->sock;
d->next = c->firstd;
c->firstd = d;
d->num = *(c->incoming + 4);
MALLOC(d->hostname, char,
templen - 5);
bcopy(c->incoming + 9, d->hostname,
templen - 6);
*(d->hostname + templen - 7) = 0;
#ifdef DEBUG
writelog("USER CONNECT %d,%d from host %s\n", c->sock, d->num, d->hostname);
#endif
break;
case 2: /* disconnect */
tempd = 0;
d = c->firstd;
num = *(c->incoming + 4);
while (d)
{
if (d->num == num)
{
writelog("USER ABORTED CONNECTION %d,%d\n", c->sock, d->num);
shutdownsock(d);
if (c->firstd == d)
c->firstd = d->next;
else
tempd->next = d->next;
FREE(d);
break;
}
tempd = d;
d = d->next;
}
#ifdef CHECKC
if (!d)
writelog("CONSISTENCY CHECK: Disconnect Received for unknown user %d,%d\n", c->sock, num);
#endif
break;
/*
* This take a message from a concentrator, and logs it in
* the log file
*/
case 4:
{
char buffer[2048];
bcopy(c->incoming + 4, buffer,
templen - 2);
*(buffer + templen - 1) = 0;
writelog(buffer);
break;
}
#ifdef CHECKC
default:
writelog("CONSISTENCY CHECK: Received unknown command from concentrator\n");
#endif
}
} else
{
d = c->firstd;
while (d)
{
if (d->num == num)
{
process_input(d, c->incoming + 3,
templen - 1);
break;
}
d = d->next;
}
#ifdef CHECKC
if (!d)
writelog("CONSISTENCY CHECK: Message received for unknown user %d,%d\n", c->sock, num);
#endif
}
bcopy(c->incoming + templen + 2, c->incoming,
(c->ilen - templen - 2));
c->ilen = c->ilen - templen - 2;
} else
break;
}
}
}
lastc = c;
}
/* Send data loop */
for (c = firstc; c; c = c->next)
{
if (FD_ISSET(c->sock, &out))
{
if (c->olen)
{
len = send(c->sock, c->outgoing, c->olen, 0);
if (len > 0)
{
c->olen -= len;
bcopy(c->outgoing + len, c->outgoing, c->olen);
}
}
}
}
}
}
void process_output(struct conc_list * c)
{
struct descriptor_data *d;
struct text_block **qp, *cur;
short templen;
for (d = c->firstd; d; d = d->next)
{
qp = &d->output.head;
cur = *qp;
if (cur)
{
if (cur->nchars < 512)
{
if ((c->olen + cur->nchars + 3) < BUFSIZE)
{
templen = cur->nchars + 1;
bcopy(&templen, c->outgoing + c->olen, 2);
*(c->outgoing + c->olen + 2) = d->num;
strncpy(c->outgoing + c->olen + 3, cur->start, cur->nchars);
d->output_size -= cur->nchars;
c->olen += cur->nchars + 3;
if (!cur->nxt)
d->output.tail = qp;
*qp = cur->nxt;
free_text_block(cur);
}
} else
{
if ((c->olen + 512 + 3) < BUFSIZE)
{
templen = 512 + 1;
bcopy(&templen, c->outgoing + c->olen, 2);
*(c->outgoing + c->olen + 2) = d->num;
strncpy(c->outgoing + c->olen + 3, cur->start, 512);
d->output_size -= 512;
c->olen += 512 + 3;
cur->nchars -= 512;
cur->start += 512;
}
}
}
}
}
void boot_off(dbref player)
{
struct conc_list *c;
struct descriptor_data *d, *lastd;
char header[4];
for (c = firstc; c; c = c->next)
{
lastd = 0;
for (d = c->firstd; d; d = d->next)
{
if (d->connected && d->player == player)
{
header[0] = 0;
header[1] = 2;
header[2] = d->num;
queue_message(c, header, 3);
process_output(c);
if (lastd)
lastd->next = d->next;
else
c->firstd = d->next;
shutdownsock(d);
FREE(d);
return;
}
lastd = d;
}
}
}
void queue_message(struct conc_list * c, char *data, int len)
{
struct message *ptr;
MALLOC(ptr, struct message, 1);
MALLOC(ptr->data, char, len);
ptr->len = len;
bcopy(data, ptr->data, len);
ptr->next = 0;
if (c->last == 0)
c->first = ptr;
else
c->last->next = ptr;
c->last = ptr;
}
int do_connect_msg(struct descriptor_data * d, const char *filename)
{
FILE *f;
char buf[BUFFER_LEN];
char *p;
if ((f = fopen(filename, "r")) == NULL)
{
return (0);
} else
{
while (fgets(buf, sizeof buf, f))
{
queue_string(d, (char *)buf);
}
fclose(f);
return (1);
}
}