#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include "lnode.h" /* Only for sake of -g flag to cc (SYSV) ! */
#include "interpret.h" /* Only for sake of -g flag to cc (SYSV) ! */
#include "comm.h"
#include "object.h"
#include "config.h"
/* Kludge because of cc -g ! */
struct sentence {
int dummy;
};
extern char *malloc();
extern int d_flag;
#define MAX_PLAYERS 30
struct interactive *all_players[MAX_PLAYERS];
extern int errno;
/*
* Interprocess communication interface to the backend.
*/
static msgqid;
/*
* Use a lock file as the unique id for this message queue.
* If the lock file is not present, then we was not started by
* a frontend program, so we create the lock file ourselfs.
*/
prepare_ipc() {
key_t key;
int fd;
key = ftok(IPC_IDENT_FILE, 0);
if (key == (key_t)-1) {
fd = creat(IPC_IDENT_FILE, 0666);
if (fd == -1) {
perror(IPC_IDENT_FILE);
exit(1);
}
close(fd);
key = ftok(IPC_IDENT_FILE, 0);
if (key == (key_t)-1) {
perror(IPC_IDENT_FILE);
exit(1);
}
/* We have to create the message queue. */
msgqid = msgget(key, IPC_CREAT|0666);
if (msgqid == -1) {
perror("msgget");
exit(1);
}
return;
}
/* Find the already existing message queue. */
msgqid = msgget(key, 0);
if (msgqid == -1) {
perror("msgget");
exit(1);
}
}
/*
* This one is called when shutting down the MUD.
*/
ipc_remove() {
int res;
printf("Shutting down ipc...\n");
res = msgctl(msgqid, IPC_RMID);
if (res == -1)
perror("msgctl IPC_RMID");
if (unlink(IPC_IDENT_FILE) == -1) {
perror(IPC_IDENT_FILE);
fprintf(stderr, "Warning could not unlink %s\n", IPC_IDENT_FILE);
}
}
add_message(fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
{
char buff[1000], length;
struct interactive *ip;
ip = command_giver->interactive;
if (ip == 0)
error("Add_message to a non-interactive object: %s!\n",
command_giver->name);
sprintf(buff, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9);
if (d_flag)
debug_message("[%s]: %s", command_giver->name, buff);
length = strlen(buff);
if (length + ip->mess_size > MAX_TEXT)
flush_message();
strcpy(ip->message + ip->mess_size, buff);
ip->mess_size += length;
}
flush_message()
{
struct interactive *ip = command_giver->interactive;
int res;
if (ip == 0)
error("Add_message to a non-interactive object: %s!\n",
command_giver->name);
if (ip->mess_size == 0)
return;
if (ip->mess_size == -1)
ip->mess_size = 0; /* Indicates a null message. */
ip->mtype = ip->pid;
while(1) {
res = msgsnd(msgqid, (struct msgbuf *)ip,
ip->mess_size, 0);
if (res == -1) {
if (errno == EINTR)
continue;
perror("msgsnd");
abort();
exit(1);
}
ip->mess_size = 0;
ip->message[0] = '\0';
return;
}
}
struct rec_buffer rec_buffer;
/*
* Get a message from any player.
* If we get a message, set command_giver to the players object and
* return true.
* If we are interrupted, return false (no message yet).
*/
get_message(buff, size)
char *buff;
{
int i, res;
/*
* Stay in this loop until we have a message to a logged on player.
*/
while(1) {
char *p;
/* First flush all send messages. */
for (i=0; i<MAX_PLAYERS; i++) {
if (all_players[i] != 0 && all_players[i]->mess_size > 0) {
command_giver = all_players[i]->ob;
flush_message();
}
}
res = msgrcv(msgqid, &rec_buffer, sizeof rec_buffer.text, 1, 0);
if (res == -1 && errno == EINTR)
return 0;
if (p = strchr(rec_buffer.text, '\n'))
*p = '\0';
if (res == -1) {
perror("msgrcv");
exit(1);
}
/*
* Now we have a message. Find which object it is associated with
* this message by looking at the pid.
*/
for (i=0; i<MAX_PLAYERS; i++) {
if (all_players[i] == 0)
continue;
if (all_players[i]->pid != rec_buffer.pid)
continue;
command_giver = all_players[i]->ob;
strcpy(buff, rec_buffer.text);
return 1;
}
/*
* We come here when no object was associated with this pid.
* Then we add a new player !
*/
for (i=0; i<MAX_PLAYERS; i++) {
struct object *ob;
if (all_players[i] != 0)
continue;
current_object = 0;
ob = (clone_object("obj/player"))->u.ob;
if (ob == 0)
error("Could not load 'obj/player'\n");
ob->enable_commands = 1;
ob->interactive =
(struct interactive *)malloc(sizeof (struct interactive));
ob->interactive->logon_state = 0;
ob->interactive->pid = rec_buffer.pid;
ob->interactive->mess_size = 0;
all_players[i] = ob->interactive;
command_giver = ob;
ob->interactive->ob = ob;
(void)logon(ob, rec_buffer.text);
break;
}
/* Did we not find any free player data structure ? */
if (i == MAX_PLAYERS)
send_null_message(rec_buffer.pid);
}
}
remove_interactive(ob)
struct object *ob;
{
struct object *save = command_giver;
int i;
for (i=0; i<MAX_PLAYERS; i++) {
if (all_players[i] != ob->interactive)
continue;
command_giver = ob;
flush_message();
/* Send a null message to his frontend, to indicate
* that he is logged of.
*/
send_null_message(ob->interactive->pid);
free(ob->interactive);
all_players[i] = 0;
ob->interactive = 0;
command_giver = save;
return 0;
}
fprintf(stderr, "Could not find and remove player %s\n", ob->name);
exit(1);
}
static send_null_message(pid) {
long mtype;
int res;
mtype = pid;
res = msgsnd(msgqid, (struct msgbuf *)&mtype, 0, 0);
if (res == -1) {
perror("msgsnd null message");
abort();
exit(1);
}
}