#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/file.h>
#if defined(_SEQUENT_)
#include <sys/procstats.h>
#endif
#include <fcntl.h>
#if !defined(FNDELAY) && defined(O_NDELAY)
#define FNDELAY O_NDELAY
#endif
#if !defined(FASYNC)
#if defined(O_ASYNC)
#define FASYNC O_ASYNC
#else
#define FASYNC 0
#endif
#endif
#define TELOPTS
#include <arpa/telnet.h>
#include <netdb.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>
#include <memory.h>
#include <fcntl.h>
#include <setjmp.h>
#ifdef _AIX
#include <sys/select.h>
#endif
#include "config.h"
#include "lint.h"
#include "interpret.h"
#include "comm.h"
#include "object.h"
#include "sent.h"
#include "patchlevel.h"
#ifndef EPROTO
#define EPROTO EPROTOTYPE
#endif
int socket (int, int, int);
#if !defined(sgi) && !defined(LINUX) && !defined(__NetBSD__) && !defined(__bsdi__) && !defined(_SEQUENT_)
#ifdef NeXT
int setsockopt (int, int, int, void *, int);
#else
int setsockopt (int, int, int, const char *, int);
#endif
int bind (int, struct sockaddr *, int);
int listen (int, int);
int accept (int, struct sockaddr *, int *);
#endif /* sgi */
int select (int, fd_set *, fd_set *, fd_set *, struct timeval *);
#if !defined(LINUX) && !defined(__NetBSD__) && !defined(__bsdi__)
void bzero (char *, int);
#endif
void telnet_neg (char *, char *);
void set_prompt (char *);
char *query_ip_number (struct object *);
static void add_ip_entry (unsigned long, char *);
extern char *xalloc(), *string_copy(), *unshared_str_copy();
extern int d_flag;
extern int current_time;
extern int eval_cost;
extern struct svalue *sp;
char * first_cmd_in_buf (struct interactive *);
void next_cmd_in_buf (struct interactive *);
char * skip_eols (struct interactive *, char *);
void remove_flush_entry (struct interactive *ip);
void remove_interactive(), add_ref();
extern void debug_message(), fatal(), free_sentence();
struct interactive *all_players[MAX_PLAYERS];
extern int errno;
void new_player();
void flush_all_player_mess();
static struct in_addr ntohl_addr();
fd_set readfds;
int nfds = 0;
int num_player;
FILE *f_ip_demon = NULL, *f_ip_demon_wr;
static struct object *first_player_for_flush=(struct object *)NULL;
/*
* Interprocess communication interface to the backend.
*/
static int s, udp_send = -1;
extern int port_number;
#ifdef CATCH_UDP_PORT
extern int udp_port;
static int udp_s;
#endif
#ifdef COMM_STAT
int add_message_calls=0;
int inet_packets=0;
int inet_volume=0;
#endif
#ifdef SERVICE_PORT
extern int service_port;
static int service_s = -1, all_services[MAX_PLAYERS];
static void
new_service(int sock)
{
int i;
for (i=0 ; i<MAX_PLAYERS ; i++)
if (all_services[i] < 0)
break;
if (i < MAX_PLAYERS)
all_services[i] = sock;
else {
write(sock, "ERROR Too many services in use.\n", 32);
close(sock);
}
}
#endif /* SERVICE_PORT */
#if (FASYNC || defined(FIOASYNC)) && defined(SIGIO)
void
catch_io(int sig)
{
extern int volatile interupted;
#if defined(SYSV) || defined(LINUX)
signal(SIGIO, catch_io);
#endif
interupted = 1;
}
#endif
void
prepare_ipc()
{
struct sockaddr_in sin;
struct hostent *hp;
int tmp;
char host_name[100];
if (gethostname(host_name, sizeof host_name) == -1)
{
perror("gethostname");
fatal("Error in gethostname()\n");
}
hp = gethostbyname(host_name);
if (hp == 0)
{
(void)fprintf(stderr, "gethostbyname: unknown host.\n");
exit(1);
}
memset((char *)&sin, '\0', sizeof sin);
memcpy((char *)&sin.sin_addr, hp->h_addr, hp->h_length);
sin.sin_port = htons((u_short)port_number);
sin.sin_family = hp->h_addrtype;
sin.sin_addr.s_addr = INADDR_ANY;
s = socket(hp->h_addrtype, SOCK_STREAM, 0);
if (s == -1)
{
perror("socket");
abort();
}
tmp = 1;
if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR,
(char *) &tmp, sizeof (tmp)) < 0)
{
perror ("setsockopt");
exit (1);
}
if (bind(s, (struct sockaddr *)&sin, sizeof sin) == -1)
{
if (errno == EADDRINUSE)
{
fprintf(stderr, "Socket already bound!\n");
debug_message("Socket already bound!\n");
exit(errno);
}
else
{
perror("bind");
abort();
}
}
if (listen(s, 5) == -1)
{
perror("listen");
abort();
}
tmp = 1;
#if defined(M_UNIX) || defined(NeXT) || defined(_AIX)
if (ioctl(s, FIONBIO, &tmp) == -1)
{
perror("ioctl socket FIONBIO");
abort();
}
#if defined(FIOASYNC) && defined(SIGIO)
if (ioctl(s, FIOASYNC, &tmp) == -1)
{
perror("ioctl socket FIOASYNC");
abort();
}
#endif
#else /* M_UNIX */
fcntl(s, F_SETOWN, getpid());
if (fcntl(s, F_SETFL, FNDELAY | FASYNC) == -1)
{
perror("fcntl socket FNDELAY | FASYNC");
abort();
}
#endif /* M_UNIX */
#ifdef SERVICE_PORT
if (service_port > 0) {
sin.sin_port = htons((u_short)service_port);
sin.sin_family = hp->h_addrtype;
sin.sin_addr.s_addr = INADDR_ANY;
service_s = socket(hp->h_addrtype, SOCK_STREAM, 0);
if (service_s >= 0)
{
tmp = 1;
if (setsockopt (service_s, SOL_SOCKET, SO_REUSEADDR,
(char *) &tmp, sizeof (tmp)) < 0)
{
close(service_s);
service_s = -1;
}
}
if (service_s >= 0 && bind(service_s, (struct sockaddr *)&sin, sizeof sin) == -1)
{
close(service_s);
service_s = -1;
}
if (service_s >= 0 && listen(service_s, 5) == -1)
{
close(service_s);
service_s = -1;
}
#if defined(M_UNIX) || defined(NeXT) || defined(_AIX)
tmp = 1;
if (service_s >= 0 && ioctl(service_s, FIONBIO, &tmp) == -1)
{
close(service_s);
service_s = -1;
}
#if defined(FIOASYNC) && defined(SIGIO)
if (service_s >= 0 && ioctl(service_s, FIOASYNC, &tmp) == -1)
{
close(service_s);
service_s = -1;
}
#endif
#else /* M_UNIX */
if (service_s >= 0 && fcntl(service_s, F_SETOWN, getpid()) == -1)
{
close(service_s);
service_s = -1;
}
if (service_s >= 0 && fcntl(service_s, F_SETFL, FNDELAY | FASYNC) == -1)
{
close(service_s);
service_s = -1;
}
#endif /* M_UNIX */
}
for (tmp = 0 ; tmp < MAX_PLAYERS ; tmp++)
all_services[tmp] = -1;
#endif /* SERVICE_PORT */
signal(SIGPIPE, SIG_IGN);
#ifdef CATCH_UDP_PORT
if (udp_port != -1)
{
sin.sin_port = htons((u_short)udp_port);
#ifdef DEBUG
if (d_flag & DEBUG_COMMAND)
debug_message("UDP recv-socket on port: %d\n", udp_port);
#endif
udp_s = socket(hp->h_addrtype, SOCK_DGRAM, 0);
if (udp_s == -1)
{
perror("udp_socket");
abort();
}
tmp = 1;
if (setsockopt (udp_s, SOL_SOCKET, SO_REUSEADDR,
(char *) &tmp, sizeof (tmp)) < 0)
{
perror ("setsockopt");
exit (1);
}
if (bind(udp_s, (struct sockaddr *)&sin, sizeof sin) == -1)
{
if (errno == EADDRINUSE)
{
fprintf(stderr, "UDP Socket already bound!\n");
debug_message("UDP Socket already bound!\n");
close(udp_s);
udp_port = -1;
}
else
{
perror("udp-bind");
abort();
}
}
}
if (udp_port != -1)
{
tmp = 1;
#if defined(M_UNIX) || defined(NeXT) || defined(_AIX)
if (ioctl(udp_s, FIONBIO, &tmp) == -1)
{
perror("udp - ioctl socket FIONBIO");
abort();
}
#if defined(FIOASYNC) && defined(SIGIO)
if (ioctl(udp_s, FIOASYNC, &tmp) == -1)
{
perror("udp - ioctl socket FIOASYNC");
abort();
}
#endif
#else /* M_UNIX */
if (udp_s >= 0 && fcntl(udp_s, F_SETOWN, getpid()) == -1)
{
perror("udp - fcntl socket F_SETOWN");
abort();
}
if (fcntl(udp_s, F_SETFL, FNDELAY | FASYNC) == -1)
{
perror("udp - fcntl socket FNDELAY | FASYNC");
abort();
}
#endif /* M_UNIX */
}
#endif /* CATCH_UDP_PORT */
}
/*
* This one is called when shutting down the MUD.
*/
void
ipc_remove()
{
(void)printf("Shutting down ipc...\n");
if (udp_send >= 0)
close(udp_send);
close(s);
}
void write_socket();
/*
* Send a message to a player. If that player is shadowed, special
* care has to be taken.
*/
/*VARARGS1*/
void add_message2(ob,fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9)
char *fmt;
long a1, a2, a3, a4, a5, a6, a7, a8, a9;
struct object *ob;
{
char buff[10000];
sprintf(buff,fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9);
if (ob && !(ob->flags & O_DESTRUCTED))
{
push_string(buff,STRING_MALLOC);
apply("catch_tell", ob, 1, 1);
}
else
write_socket(buff, (struct object *)0);
}
void
add_message(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9)
char *fmt;
long a1, a2, a3, a4, a5, a6, a7, a8, a9;
{
add_message2(command_giver,fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9);
}
void
write_socket(char *fmt, struct object *command_giver)
{
char buff[10000]; /* Kludgy! Hope this is enough ! */
char buff2[MAX_SOCKET_PACKET_SIZE+1];
char *c_from, *c_to;
struct interactive *ip;
int n, chunk, length;
int from, to;
int min_length;
int old_message_length;
if (command_giver == 0 || (command_giver->flags & O_DESTRUCTED) ||
command_giver->interactive == 0 ||
command_giver->interactive->do_close) {
if ( fmt != MESSAGE_FLUSH )
fputs(fmt, stderr);
fflush(stderr);
return;
}
ip = command_giver->interactive;
old_message_length = ip->message_length;
if ( fmt == MESSAGE_FLUSH ) {
min_length = 1;
strncpy ( buff, ip->message_buf, length=old_message_length );
buff[length] = '\0';
}
else
{
#ifdef COMM_STAT
add_message_calls++; /* We want to know how many packets the old
version would have sent */
#endif
min_length = DESIRED_SOCKET_PACKET_SIZE;
if (old_message_length + strlen(fmt) > sizeof buff)
error("Too long message!\n");
(void) strcpy(buff + old_message_length, fmt);
length = old_message_length + strlen(buff + old_message_length);
/*
* Always check that your arrays are big enough !
*/
if (shadow_catch_message(command_giver, buff + old_message_length))
return;
/* Insert super-snooper here */
#ifdef SUPER_SNOOP
{ /* This is *crude* code -Azid */
extern char super_snooped[256][16], super_snoopfile[256][32];
extern int num_super_snooped;
extern struct svalue *sapply();
if (num_super_snooped)
{
int i, f;
for (i = 0; i < num_super_snooped; i++)
{
if (ip->ob->living_name != NULL)
{
if (strcmp(ip->ob->living_name, super_snooped[i]) == 0)
{
f = open(super_snoopfile[i], O_WRONLY | O_APPEND | O_CREAT, 0600);
if (f != NULL)
{
write(f, buff + old_message_length,
strlen(buff + old_message_length));
close(f);
}
break;
}
}
}
}
}
/* End of super-snooper */
#endif
if (ip->snoop_by)
add_message2(ip->snoop_by->ob,"%%%s", buff + old_message_length);
if ( length >= min_length )
strncpy ( buff, ip->message_buf, old_message_length );
else
strcpy(ip->message_buf + old_message_length,
buff + old_message_length );
}
if (d_flag & DEBUG_OUTPUT)
debug_message("[%s(%d)]: %s", command_giver->name, length, buff);
/*
* Insert CR after all NL.
*/
to = 0;
if (ip->current_column > ip->screen_width)
ip->current_column = ip->screen_width;
for (from = 0 ; length - from >= min_length ; to = 0 )
{
#ifdef WORD_WRAP
if (ip->screen_width > 3)
{
int i;
int fold_size;
fold_size = ip->screen_width / 5;
while(to < sizeof(buff2) - 4 && buff[from] != '\0')
{
if (buff[from] == '\n')
{
buff2[to++] = '\r';
buff2[to++] = '\n';
from++;
ip->current_column = 0;
continue;
}
if (buff[from] == '\t')
{
ip->current_column &= ~7;
ip->current_column += 8;
if (ip->current_column >= ip->screen_width)
{
buff2[to++] = '\r';
buff2[to++] = '\n';
ip->current_column = 0;
/* Skip whitespace at the beginning of the line */
while (buff[from] == ' ' || buff[from] == '\t')
from++;
if (buff[from] == '\n')
from++;
}
else
buff2[to++] = '\t';
from++;
continue;
}
for (i = 1; buff[from + i] >= '!'; i++);
if (i + ip->current_column >= ip->screen_width)
if ( ip->current_column > ip->screen_width - fold_size)
{
buff2[to++] = '\r';
buff2[to++] = '\n';
ip->current_column = 0;
/* Skip whitespace at the beginning of the line */
while (buff[from] == ' ' || buff[from] == '\t')
from++;
if (buff[from] == '\n')
from++;
}
else
{
if (to + ip->screen_width - ip->current_column + 2 >=
sizeof(buff2) - 4)
break;
memcpy(&buff2[to], &buff[from],
ip->screen_width - ip->current_column - 1);
from += ip->screen_width - ip->current_column - 1;
to += ip->screen_width - ip->current_column - 1;
buff2[to++] = '-';
buff2[to++] = '\r';
buff2[to++] = '\n';
ip->current_column = 0;
}
else
{
if (to + i >= sizeof(buff2) - 4)
break;
memcpy(&buff2[to], &buff[from], i);
from += i;
to += i;
ip->current_column += i;
}
}
}
else
#endif /* WORD_WRAP */
{
for ( ; to < (sizeof buff2)-1 && buff[from] != '\0';)
{
if (buff[from] == '\n')
buff2[to++] = '\r';
buff2[to++] = buff[from++];
}
}
chunk = to;
/*
* We split up the message into something smaller than the max size.
*/
if ((n = write(ip->socket, buff2, chunk)) == -1)
{
if (errno == EMSGSIZE)
return;
if (errno == EINVAL)
{
if (old_message_length) remove_flush_entry(ip);
ip->do_close = 1;
return;
}
if (errno == ENETUNREACH)
{
if (old_message_length) remove_flush_entry(ip);
ip->do_close = 1;
return;
}
if (errno == EHOSTUNREACH)
{
if (old_message_length) remove_flush_entry(ip);
ip->do_close = 1;
return;
}
if (errno == EPIPE) {
if (old_message_length) remove_flush_entry(ip);
ip->do_close = 1;
return;
}
if (errno == EWOULDBLOCK) {
if (old_message_length)
remove_flush_entry(ip);
/* ip->do_close = 1; -- LA */
return;
}
fprintf(stderr, "write: unknown errno %d\n", errno);
perror("write");
if (old_message_length) remove_flush_entry(ip);
ip->do_close = 1;
return;
}
#ifdef COMM_STAT
inet_packets++;
inet_volume += n;
#endif
if (n != chunk)
fprintf(stderr, "write socket: wrote %d, should be %d.\n",
n, chunk);
continue;
}
length -= from;
ip->message_length = length;
if (from)
strncpy( ip->message_buf, buff + from, length );
if ( length && !old_message_length )
{ /* buffer became 'dirty' */
if ( ip->next_player_for_flush = first_player_for_flush )
{
first_player_for_flush->interactive->previous_player_for_flush =
command_giver;
}
ip->previous_player_for_flush = 0;
first_player_for_flush = command_giver;
}
if ( !length && old_message_length ) /* buffer has become empty */
remove_flush_entry(ip);
}
void
remove_flush_entry(struct interactive *ip)
{
ip->message_length = 0;
if ( ip->previous_player_for_flush )
{
ip->previous_player_for_flush->interactive->next_player_for_flush
= ip->next_player_for_flush;
}
else
{
first_player_for_flush = ip->next_player_for_flush;
}
if ( ip->next_player_for_flush )
{
ip->next_player_for_flush->interactive->previous_player_for_flush
= ip->previous_player_for_flush;
}
}
void
flush_all_player_mess()
{
struct object *p,*np;
for ( p = first_player_for_flush; p; p = np)
{
np = p->interactive->next_player_for_flush;
/* beware of side-effects when calling add_message the first time! */
write_socket(MESSAGE_FLUSH,p);
}
}
/*
* Copy a string, replacing newlines with '\0'. Also add an extra
* space and back space for every newline. This trick will allow
* otherwise empty lines, as multiple newlines would be replaced by
* multiple zeroes only.
*/
static INLINE int
copy_chars(char *from, char *to, int n)
{
int i;
char *start = to;
for (i = 0; i < n; i++)
{
if (from[i] == '\r')
continue;
if (from[i] == '\n')
{
*to++ = ' ';
*to++ = '\b';
*to++ = '\0';
continue;
}
*to++ = from[i];
}
return to - start;
}
/*
* Get a message from any player. For all players without a completed
* cmd in their input buffer, read their socket. Then, return the first
* cmd of the next player in sequence that has a complete cmd in their buffer.
* CmdsGiven is used to allow people in ED to send more cmds (if they have
* them queued up) than normal players. If we get a heartbeat, still read
* all sockets; if the next cmd giver is -1, we have already cycled and
* can go back to do the heart beat.
*/
#define StartCmdGiver (MAX_PLAYERS-1) /* the one after heartbeat */
#define IncCmdGiver NextCmdGiver = (NextCmdGiver < 0? StartCmdGiver: \
NextCmdGiver - 1)
int NextCmdGiver = StartCmdGiver;
int CmdsGiven = 0; /* -1 is used to poll heart beat. */
int twait = 0; /* wait time for select() */
extern comm_time_to_call_heart_beat;
#define MSR_SIZE 20
int msecs_response[MSR_SIZE];
int msr_point = -1;
long last_sec, last_usec;
int
get_msecs_response(int ix)
{
return (ix >= 0 && ix < MSR_SIZE) ? msecs_response[ix] : -1;
}
int
get_message(char *buff, int size)
{
int i, res;
struct interactive *ip = 0;
char *p;
/*
* Stay in this loop until we have a message from a player.
*/
while(1)
{
int new_socket, cnt;
struct sockaddr_in addr;
int length;
struct timeval timeout;
#ifdef CATCH_UDP_PORT
char udp_buf[1024], *st;
#endif
#ifdef SERVICE_PORT
char service_buf[1024];
int service;
#endif /* SERVICE_PORT */
/* First, try to get a new player... */
length = sizeof addr;
new_socket = accept(s, (struct sockaddr *)&addr, &length);
if (new_socket != -1)
{
#if defined(M_UNIX) || defined(NeXT) || defined(_AIX)
i = 1;
ioctl(new_socket, FIONBIO, &i);
#else
fcntl(new_socket, F_SETOWN, getpid());
fcntl(new_socket, F_SETFL, FNDELAY | FASYNC);
#endif
new_player(new_socket, &addr, length);
}
else if (new_socket == -1 && errno != EWOULDBLOCK && errno != EINTR &&
errno != EPROTO)
{
perror("accept");
abort();
}
#ifdef SERVICE_PORT
/* Next, try to get a new service... */
if (service_s > -1)
{
length = sizeof addr;
new_socket = accept(service_s, (struct sockaddr *)&addr, &length);
if (new_socket != -1)
{
#if defined(M_UNIX) || defined(NeXT) || defined(_AIX)
i = 1;
ioctl(new_socket, FIONBIO, &i);
#else
fcntl(new_socket, F_SETOWN, getpid());
fcntl(new_socket, F_SETFL, FNDELAY | FASYNC);
#endif
new_service(new_socket);
}
else if (new_socket == -1 && errno != EWOULDBLOCK &&
errno != EINTR && errno != EPROTO)
{
perror("accept");
abort();
}
}
#endif /* SERVICE_PORT */
#ifdef CATCH_UDP_PORT
/* Then see if we got any udp messages */
if (udp_port != -1)
{
cnt = recvfrom(udp_s, udp_buf, sizeof(udp_buf), 0,
(struct sockaddr *)&addr, &length);
if (cnt != -1)
{
udp_buf[sizeof(udp_buf) - 1] = 0;
udp_buf[cnt] = 0;
st = inet_ntoa(addr.sin_addr);
push_string(st, STRING_MALLOC);
push_string(udp_buf, STRING_MALLOC);
apply_master_ob(M_INCOMING_UDP, 2);
}
}
#endif
nfds = 0;
FD_ZERO(&readfds);
for (i = 0; i < MAX_PLAYERS; i++)
{
ip = all_players[i];
if (!ip)
continue;
if (ip->do_close)
{
ip->do_close = 0;
remove_interactive(ip->ob, 1);
continue;
}
if (!first_cmd_in_buf(ip))
{
FD_SET(ip->socket, &readfds);
if (ip->socket >= nfds)
nfds = ip->socket+1;
}
}
#ifdef SERVICE_PORT
for (i = 0 ; i < MAX_PLAYERS ; i++)
{
if ((service = all_services[i]) < 0)
continue;
FD_SET(service, &readfds);
if (service >= nfds)
nfds = service + 1;
}
#endif /* SERVICE_PORT */
if (f_ip_demon != NULL)
{
FD_SET(fileno(f_ip_demon), &readfds);
}
/*
Measure average response time
*/
#if defined(_SEQUENT_)
get_process_stats(&timeout, PS_SELF, NULL, NULL);
#else
gettimeofday(&timeout, 0);
#endif
if (msr_point < 0)
{
for (i = 0; i < MSR_SIZE; i++)
msecs_response[i] = -1;
msr_point = 0;
}
else
{
msecs_response[msr_point++] = (timeout.tv_sec - last_sec) * 1000 +
((timeout.tv_usec > last_usec)
? (timeout.tv_usec - last_usec) / 1000
: (1000000 - (last_usec - timeout.tv_usec)) / 1000);
/* Do not store the zero values */
if (msecs_response[msr_point - 1] < 5)
msr_point--;
msr_point %= MSR_SIZE;
}
timeout.tv_sec = 0; /* avoid busy waiting when no buffered cmds */
timeout.tv_usec = 0;
res = select(nfds, &readfds, 0, 0, &timeout);
#if defined(_SEQUENT_)
get_process_stats(&timeout, PS_SELF, NULL, NULL);
#else
gettimeofday(&timeout, 0);
#endif
last_sec = timeout.tv_sec;
last_usec = timeout.tv_usec;
if (res == -1)
{
twait = 0;
if (errno == EINTR) /* if we got an alarm, finish the round */
goto return_next_command;
perror("select");
return 0;
}
if (res)
{ /* waiting packets */
if (f_ip_demon != NULL && FD_ISSET(fileno(f_ip_demon), &readfds))
{
char buf[200], *pp, *q;
unsigned long laddr;
if (fgets(buf, sizeof buf, f_ip_demon))
{
/*printf("hname says: %s\n", buf);*/
laddr = inet_addr(buf);
if (laddr != -1)
{
pp = strchr(buf, ' ');
if (pp)
{
pp++;
q = strchr(buf, ',');
if (q)
{
char *p1, *p2, *name;
*q = 0;
p1 = q + 1;
if (p2 = strchr(p1, ','));
{
*p2 = 0;
p2++;
if(name = strchr(p2, ':'))
{
*name = 0;
name++;
if(q = strchr(name, '\n'))
{
int i;
struct interactive *ir;
int lport, rport;
*q = 0;
lport = atoi(p1);
rport = atoi(p2);
for (i = 0; i < MAX_PLAYERS; i++)
{
if (!(ir = all_players[i]))
continue;
if (ir->addr.sin_addr.s_addr
== laddr &&
ir->lport == lport &&
ir->rport == rport)
{
ir->rname =
xalloc(strlen(name) +
1);
strcpy(ir->rname, name);
break;
}
}
}
}
}
}
else
q = strchr(buf, '\n');
if (q)
{
*q = 0;
add_ip_entry(laddr, pp);
}
}
}
}
}
#ifdef SERVICE_PORT
for (i = 0; i < MAX_PLAYERS; i++)
{
int l;
struct svalue *ret;
service = all_services[i];
if (service < 0)
continue;
if (FD_ISSET(service, &readfds)) {
if ((l = read(service, service_buf, sizeof(service_buf)-1)) == -1) {
close(service);
all_services[i] = -1;
continue;
}
service_buf[l] = '\0';
push_string(service_buf, STRING_MALLOC);
ret = apply_master_ob(M_INCOMING_SERVICE, 1);
if (ret == 0 || ret->type != T_STRING) {
write(service, "ERROR Service calls not supported\n", 34);
close(service);
all_services[i] = -1;
continue;
}
if (write(service, ret->u.string, strlen(ret->u.string)) < 0) {
close(service);
all_services[i] = -1;
continue;
}
}
}
#endif /* SERVICE_PORT */
for (i = 0; i < MAX_PLAYERS; i++)
{ /* read all pending sockets */
ip = all_players[i];
if (ip == 0)
continue;
if (FD_ISSET(ip->socket, &readfds))
{ /* read this player */
int l;
/*
* Dont overfill their buffer.
* Use a very conservative estimate on how much we can
* read.
*/
l = (MAX_TEXT - ip->text_end - 1) / 3;
if (l < size)
size = l;
if ((l = read(ip->socket, buff, size)) == -1)
{
if (errno == ENETUNREACH)
{
debug_message("Net unreachable detected.\n");
remove_interactive(ip->ob, 1);
continue;
}
if (errno == EHOSTUNREACH)
{
debug_message("Host unreachable detected.\n");
remove_interactive(ip->ob, 1);
continue;
}
if (errno == ETIMEDOUT)
{
debug_message("Connection timed out detected.\n");
remove_interactive(ip->ob, 1);
continue;
}
if (errno == ECONNRESET)
{
debug_message("Connection reset by peer detected.\n");
remove_interactive(ip->ob, 1);
continue;
}
if (errno == EWOULDBLOCK)
{
debug_message("read would block socket %d!\n",
ip->socket);
remove_interactive(ip->ob, 1);
continue;
}
if (errno == EMSGSIZE)
{
debug_message("read EMSGSIZE !\n");
continue;
}
perror("read");
debug_message("Unknown errno %d\n", errno);
remove_interactive(ip->ob, 1);
continue;
}
if (l == 0)
{
if (ip->closing)
fatal("Tried to read from closing socket.\n");
remove_interactive(ip->ob, 1);
return 0;
}
buff[l] = '\0';
/* replace newlines by nulls and catenate to buffer */
ip->text_end +=
copy_chars(buff, ip->text + ip->text_end, l);
/* now, text->end is just after the last char read. If last */
/* char was a nl, char *before* text_end will be null. */
ip->text[ip->text_end] = '\0';
}
}
}
/*
* we have read the sockets, now find and return a command
*/
return_next_command:
twait = 0;
ip = 0;
for (i = 0; i < MAX_PLAYERS + 1; i++)
{
if (NextCmdGiver == -1)
{ /* we have cycled around all players */
CmdsGiven = 0; /* check heart beat */
IncCmdGiver;
return 0;
}
ip = all_players[NextCmdGiver];
if (ip && (p = first_cmd_in_buf(ip))) /* wont respond to partials*/
break;
CmdsGiven = 0; /* new player, no cmds issued */
IncCmdGiver;
}
if (!ip || !p)
{ /* no cmds found; loop and select (on timeout) again */
NextCmdGiver = StartCmdGiver;/* do a complete poll next time */
CmdsGiven = 0;
return(0);
}
/*
* we have a player cmd - return it. If he is in ed, count his
* cmds, else only allow 1 cmd. If he has only one partially
* completed cmd left after * this, move it to the start of his
* buffer; new stuff will be appended.
*/
command_giver = ip->ob;
telnet_neg(buff, p);
next_cmd_in_buf(ip); /* move on buffer pointers */
ip->current_column = 0;
/* if he is not in ed, dont let him issue another till the poll comes again */
if (ip->ed_buffer && CmdsGiven < ALLOWED_ED_CMDS)
CmdsGiven++;
else {
IncCmdGiver;
CmdsGiven = 0;
}
/* manage snooping - should the snooper see type ahead?
Well, he doesnt here
*/
if (!ip->noecho)
{ /* This is *crude* code -Azid */
extern char super_snooped[256][16], super_snoopfile[256][32];
extern int num_super_snooped;
extern struct svalue *sapply();
#ifdef SUPER_SNOOP
if (num_super_snooped)
{
int i, f;
for (i = 0; i < num_super_snooped; i++)
{
if (ip->ob->living_name != NULL)
{
if (strcmp(ip->ob->living_name, super_snooped[i]) == 0) {
f = open(super_snoopfile[i], O_WRONLY | O_APPEND | O_CREAT, 0600);
if (f != NULL)
{
write(f, buff, strlen(buff));
write(f,"\n",1);
close(f);
}
break;
}
}
}
}
#endif
}
if (ip->snoop_by && !ip->noecho)
add_message2(ip->snoop_by->ob,"%% %s\n", buff);
command_giver = ip->ob;
if (ip->noecho)
{
/* Must not enable echo before the user input is received. */
add_message("%c%c%c", IAC, WONT, TELOPT_ECHO);
}
ip->noecho = 0;
ip->last_time = current_time;
return 1;
}
}
/*
* find the first character of the next complete cmd in a buffer, 0 if no
* completed cmd. There is a completed cmd if there is a null between
* text_start and text_end. Zero length commands are discarded (as occur
* between <cr> and <lf>). Update text_start if we have to skip leading
* nulls.
*/
char *
first_cmd_in_buf(struct interactive *ip)
{
char * p, *q;
p = ip->text_start + ip->text;
while ((p < (ip->text_end + ip->text)) && !*p) /* skip null input */
p++;
ip->text_start = p - ip->text;
if (ip->text_start >= ip->text_end)
{
ip->text_start = ip->text_end = 0;
ip->text[0] = '\0';
return(0);
}
while ((p < (ip->text_end + ip->text)) && *p) /* find end of cmd */
p++;
if (p < ip->text + ip->text_end) /* null terminated, was command */
return(ip->text + ip->text_start);
/* have a partial command at end of buffer; move it to start, return null */
/* if it cant move down, truncate it and return it as cmd. */
p = ip->text + ip->text_start;
q = ip->text;
while (p < (ip->text + ip->text_end))
*(q++) = *(p++);
ip->text_end -= ip->text_start;
ip->text_start = 0;
if (ip->text_end > MAX_TEXT - 2)
{
ip->text[ip->text_end-2] = '\0'; /* nulls to truncate */
ip->text[ip->text_end-1] = '\0'; /* nulls to truncate */
ip->text_end--;
return(ip->text);
}
/* buffer not full and no newline - no cmd. */
return(0);
}
/*
* move pointers to next cmd, or clear buf.
*/
void
next_cmd_in_buf(struct interactive *ip)
{
char * p = ip->text + ip->text_start;
while (*p && p < ip->text + ip->text_end)
p++;
/* skip past any nulls at the end */
while (!*p && p < ip->text + ip->text_end)
p++;
if (p < ip->text + ip->text_end)
ip->text_start = p - ip->text;
else
{
ip->text_start = ip->text_end = 0;
ip->text[0] = '\0';
}
}
/*
* Remove an interactive player immediately.
*/
void
remove_interactive(struct object *ob, int link_dead)
{
struct object *save = command_giver;
int i;
if (!ob || !(ob->interactive))
return;
for (i = 0; i < MAX_PLAYERS; i++)
{
if (all_players[i] != ob->interactive)
continue;
if (ob->interactive->closing)
fatal("Double call to remove_interactive()\n");
command_giver = ob;
if (ob->interactive->ed_buffer)
{
extern void save_ed_buffer();
/* This will call 'get_ed_buffer_save_file_name' in master_ob
* If that fails(error in LPC) the closing IP will hang and
* on the next read a 'fatal read on closing socket will occur'
* unless we do this here before ip->closing = 1
*/
add_message("Saving editor buffer.\n");
save_ed_buffer();
}
if (!(ob->interactive))
return;
ob->interactive->closing = 1;
if (ob->interactive->snoop_by)
{
ob->interactive->snoop_by->snoop_on = 0;
ob->interactive->snoop_by = 0;
}
if (ob->interactive->snoop_on)
{
ob->interactive->snoop_on->snoop_by = 0;
ob->interactive->snoop_on = 0;
}
write_socket("Closing down.\n", command_giver);
write_socket(MESSAGE_FLUSH, command_giver);
(void)shutdown(ob->interactive->socket, 2);
close(ob->interactive->socket);
num_player--;
if (ob->interactive->input_to)
{
free_vector(ob->interactive->carryover);
free_sentence(ob->interactive->input_to);
ob->interactive->input_to = 0;
}
if(ob->interactive->rname)
free(ob->interactive->rname);
free((char *)ob->interactive);
ob->interactive = 0;
all_players[i] = 0;
free_object(ob, "remove_interactive");
push_object(ob);
push_number(link_dead);
apply_master_ob(M_REMOVE_INTERACTIVE,2);
command_giver = save;
return;
}
(void) fprintf(stderr, "Could not find and remove player %s\n", ob->name);
abort();
}
/*
* get the I'th player object from the interactive list, i starts at 0
* and can go to num_player - 1. For users(), etc.
*/
struct object *
get_interactive_object(i)
int i;
{
int n;
if (i >= num_player) /* love them ASSERTS() :-) */
fatal("Get interactive (%d) with only %d players!", i, num_player);
for (n = 0; n < MAX_PLAYERS; n++)
if (all_players[n])
if (!(i--))
return(all_players[n]->ob);
fatal("Get interactive: player %d not found! (num_players = %d)",
i, num_player);
return 0; /* Just to satisfy some compiler warnings */
}
void
new_player(int new_socket, struct sockaddr_in *addr, int len)
{
int i;
char *p;
if (d_flag & DEBUG_CONNECT)
debug_message("New player at socket %d.\n", new_socket);
for (i = 0; i < MAX_PLAYERS; i++)
{
struct object *ob;
struct svalue *ret;
extern struct object *master_ob;
if (all_players[i] != 0)
continue;
command_giver = master_ob;
master_ob->interactive =
(struct interactive *)xalloc(sizeof (struct interactive));
master_ob->interactive->default_err_message = 0;
master_ob->flags |= O_ONCE_INTERACTIVE;
/* This initialization is not pretty. */
master_ob->interactive->rname = 0;
master_ob->interactive->ob = master_ob;
master_ob->interactive->text[0] = '\0';
master_ob->interactive->input_to = 0;
master_ob->interactive->closing = 0;
master_ob->interactive->snoop_on = 0;
master_ob->interactive->snoop_by = 0;
master_ob->interactive->text_end = 0;
master_ob->interactive->text_start = 0;
master_ob->interactive->do_close = 0;
master_ob->interactive->noecho = 0;
master_ob->interactive->trace_level = 0;
master_ob->interactive->trace_prefix = 0;
master_ob->interactive->last_time = current_time;
master_ob->interactive->ed_buffer = 0;
master_ob->interactive->message_length=0;
master_ob->interactive->carryover = allocate_array(0);
#ifdef WORD_WRAP
master_ob->interactive->current_column = 0;
master_ob->interactive->screen_width = 0;
#endif
all_players[i] = master_ob->interactive;
all_players[i]->socket = new_socket;
set_prompt(NULL);
#if 1
memcpy((char *)&all_players[i]->addr, (char *)addr, len);
#else
getpeername(new_socket, (struct sockaddr *)&all_players[i]->addr,
&len);
#endif
all_players[i]->rport = ntohs(addr->sin_port);
all_players[i]->lport = port_number;
num_player++;
/*
* The player object has one extra reference.
* It is asserted that the master_ob is loaded.
*/
add_ref(master_ob, "new_player");
ret = apply_master_ob(M_CONNECT, 0);
if (ret == 0 || ret->type != T_OBJECT)
{
remove_interactive(master_ob, 0);
return;
}
/*
* There was an object returned from connect(). Use this as the
* player object.
*/
ob = ret->u.ob;
ob->interactive = master_ob->interactive;
ob->interactive->ob = ob;
ob->flags |= O_ONCE_INTERACTIVE;
master_ob->flags &= ~O_ONCE_INTERACTIVE;
write_socket(MESSAGE_FLUSH, command_giver);
master_ob->interactive = 0;
free_object(master_ob, "reconnect");
add_ref(ob, "new_player");
command_giver = ob;
if (f_ip_demon_wr != NULL) {
/*printf("sent hname %s\n:", query_ip_number(ob));*/
fprintf(f_ip_demon_wr, "%s;%d,%d\n", query_ip_number(ob),
all_players[i]->lport, all_players[i]->rport);
fflush(f_ip_demon_wr);
}
logon(ob);
flush_all_player_mess();
return;
}
p = "Lpmud is full. Come back later.\r\n";
write(new_socket, p, strlen(p));
close(new_socket);
}
int
call_function_interactive(struct interactive *i, char *str)
{
char *function;
struct object *ob;
int j;
if (!i->input_to)
return 0;
/*
* Special feature: input_to() has been called to setup
* a call to a function.
*/
if (i->input_to->ob->flags & O_DESTRUCTED)
{
/* Sorry, the object has selfdestructed ! */
free_sentence(i->input_to);
i->input_to = 0;
free_vector(i->carryover);
i->carryover = allocate_array(0);
return 0;
}
function = string_copy(command_giver->interactive->input_to->function);
ob = i->input_to->ob;
free_sentence(i->input_to);
/*
* We must clear this reference before the call to apply(), because
* someone might want to set up a new input_to().
*/
i->input_to = 0;
/*
* Now we set current_object to this object, so that input_to will
* work for static functions.
*/
push_string(str, STRING_MALLOC);
current_object = ob;
for (j = 0; j < i->carryover->size; j++)
push_svalue(&(i->carryover->item[j]));
free_vector(i->carryover);
i->carryover = allocate_array(0);
(void)apply(function, ob, 1 + j, 0);
free(function);
flush_all_player_mess();
return 1;
}
int
set_call(struct object *ob, struct sentence *sent, int noecho)
{
struct object *save = command_giver;
if (ob == 0 || sent == 0)
return 0;
if (ob->interactive == 0 || ob->interactive->input_to)
return 0;
ob->interactive->input_to = sent;
ob->interactive->noecho = noecho;
command_giver = ob;
if (noecho)
add_message("%c%c%c", IAC, WILL, TELOPT_ECHO);
command_giver = save;
return 1;
}
static struct in_addr
ntohl_addr(struct in_addr addr)
{
struct in_addr ret;
ret.s_addr=ntohl(addr.s_addr);
return(ret);
}
void
remove_all_players()
{
int i;
struct svalue *ret;
extern jmp_buf error_recovery_context;
extern int error_recovery_context_exists;
ret = apply_master_ob(M_START_SHUTDOWN, 0);
if (ret && ret->type == T_POINTER)
{
int i;
struct vector *unload_vec = ret->u.vec;
unload_vec->ref++;
for (i = 0; i < unload_vec->size; i++)
if (setjmp(error_recovery_context))
{
clear_state();
add_message("Anomaly in the fabric of world space.\n");
}
else
{
error_recovery_context_exists = 1;
push_svalue(&(unload_vec->item[i]));
eval_cost = 0;
apply_master_ob(M_CLEANUP_SHUTDOWN, 1);
}
free_vector(unload_vec);
}
error_recovery_context_exists = 0;
apply_master_ob(M_FINAL_SHUTDOWN, 0);
}
void
set_prompt(char *str)
{
if (str)
command_giver->interactive->prompt = str;
else
command_giver->interactive->prompt = "> ";
}
/*
* Print the prompt, but only if input_to not is disabled.
*/
void
print_prompt()
{
if (command_giver == 0)
fatal("command_giver == 0.\n");
if (command_giver->interactive->input_to == 0)
{
if (!(command_giver->flags & O_DESTRUCTED) &&
command_giver->interactive->prompt)
add_message(command_giver->interactive->prompt);
if (1)
{ /* add test for heart_beat later */
flush_all_player_mess();
}
}
}
/*
* Let object 'me' snoop object 'you'. If 'you' is 0, then turn off
* snooping.
*
* This routine is almost identical to the old set_snoop. The main
* difference is that the routine writes nothing to player directly,
* all such communication is taken care of by the mudlib. It communicates
* with master.c in order to find out if the operation is permissble or
* not. The old routine let everyone snoop anyone. This routine also returns
* 0 or 1 depending on success.
*/
int
set_snoop(struct object *me, struct object *you)
{
struct interactive *on = 0, *by = 0, *tmp;
int i;
struct svalue *ret;
extern struct object *master_ob;
/* Stop if people managed to quit before we got this far */
if (me->flags & O_DESTRUCTED)
return 0;
if (you && (you->flags & O_DESTRUCTED))
return 0;
/* Find the snooper & snopee */
for(i = 0 ; i < MAX_PLAYERS && (on == 0 || by == 0); i++)
{
if (all_players[i] == 0)
continue;
if (all_players[i]->ob == me)
by = all_players[i];
else if (all_players[i]->ob == you)
on = all_players[i];
}
/* Check for permissions with valid_snoop in master */
if (current_object != master_ob)
{
push_object(current_object);
push_object(me);
if (you == 0)
push_number(0);
else
push_object(you);
ret = apply_master_ob(M_VALID_SNOOP, 3);
if (!ret || ret->type != T_NUMBER || ret->u.number == 0)
return 0;
}
/* Stop snoop */
if (you == 0)
{
if (by == 0)
error("Could not find snooper to stop snoop on.\n");
if (by->snoop_on == 0)
return 1;
by->snoop_on->snoop_by = 0;
by->snoop_on = 0;
return 1;
}
/* Strange event, but possible, so test for it */
if (on == 0 || by == 0)
return 0;
/* Protect against snooping loops */
for (tmp = on; tmp; tmp = tmp->snoop_on)
{
if (tmp == by)
return 0;
}
/* Terminate previous snoop, if any */
if (by->snoop_on)
{
by->snoop_on->snoop_by = 0;
by->snoop_on = 0;
}
if (on->snoop_by)
{
on->snoop_by->snoop_on = 0;
on->snoop_by = 0;
}
on->snoop_by = by;
by->snoop_on = on;
return 1;
}
#define TS_DATA 0
#define TS_IAC 1
#define TS_WILL 2
#define TS_WONT 3
#define TS_DO 4
#define TS_DONT 5
void
telnet_neg(char *to, char *from)
{
int state = TS_DATA;
int ch;
char *first = to;
while(1)
{
ch = (*from++ & 0xff);
switch(state) {
case TS_DATA:
switch(ch)
{
case IAC:
state = TS_IAC;
continue;
case '\b': /* Backspace */
case 0x7f: /* Delete */
if (to <= first)
continue;
to -= 1;
continue;
default:
if (ch & 0x80)
{
if (d_flag & DEBUG_TELNET) debug_message("Tel_neg: 0x%x\n", ch);
continue;
}
*to++ = ch;
if (ch == 0)
return;
continue;
}
case TS_IAC:
switch(ch)
{
case WILL:
state = TS_WILL;
continue;
case WONT:
state = TS_WONT;
continue;
case DO:
state = TS_DO;
continue;
case DONT:
state = TS_DONT;
continue;
case DM:
break;
case NOP:
case GA:
default:
break;
}
state = TS_DATA;
continue;
case TS_WILL:
if (d_flag & DEBUG_TELNET) debug_message("Will %s\n", telopts[ch]);
state = TS_DATA;
continue;
case TS_WONT:
if (d_flag & DEBUG_TELNET) debug_message("Wont %s\n", telopts[ch]);
state = TS_DATA;
continue;
case TS_DO:
if (d_flag & DEBUG_TELNET) debug_message("Do %s\n", telopts[ch]);
state = TS_DATA;
continue;
case TS_DONT:
if (d_flag & DEBUG_TELNET) debug_message("Dont %s\n", telopts[ch]);
state = TS_DATA;
continue;
default:
if (d_flag & DEBUG_TELNET) debug_message("Bad state: 0x%x\n", state);
state = TS_DATA;
continue;
}
}
}
#define IPSIZE 200
static struct ipentry
{
unsigned long addr;
char *name;
} iptable[IPSIZE];
static int ipcur;
char *
query_ip_name(struct object *ob)
{
int i;
if (ob == 0)
ob = command_giver;
if (!ob || ob->interactive == 0)
return 0;
for(i = 0; i < IPSIZE; i++)
{
if (iptable[i].addr ==
(ob->interactive->addr.sin_addr.s_addr & 0xffffffff) &&
iptable[i].name)
return iptable[i].name;
}
return inet_ntoa(ob->interactive->addr.sin_addr);
}
static void
add_ip_entry(unsigned long addr, char *name)
{
int i;
for(i = 0; i < IPSIZE; i++)
{
if (iptable[i].addr == addr)
return;
}
iptable[ipcur].addr = addr;
if (iptable[ipcur].name)
free_string(iptable[ipcur].name);
iptable[ipcur].name = make_shared_string(name);
ipcur = (ipcur+1) % IPSIZE;
}
char *
query_ip_number(struct object *ob)
{
if (ob == 0)
ob = command_giver;
if (!ob || ob->interactive == 0)
return 0;
return inet_ntoa(ob->interactive->addr.sin_addr);
}
#ifndef INET_NTOA_OK
/*
Note: if the address string is "a.b.c.d" the address number is
a * 256^3 + b * 256^2 + c * 256 + d
*/
char *
inet_ntoa(struct in_addr ad)
{
u_long s_ad;
int a, b, c, d;
static char addr[20]; /* 16 + 1 should be enough */
s_ad = ad.s_addr;
d = s_ad % 256;
s_ad /= 256;
c = s_ad % 256;
s_ad /= 256;
b = s_ad % 256;
a = s_ad / 256;
sprintf(addr, "%d.%d.%d.%d", a, b, c, d);
return addr;
}
#endif /* INET_NTOA_OK */
char *
query_host_name()
{
static char name[20];
gethostname(name, sizeof name);
name[sizeof name - 1] = '\0'; /* Just to make sure */
return name;
}
struct object *
query_snoop(struct object *ob)
{
if (ob->interactive->snoop_by == 0)
return 0;
return ob->interactive->snoop_by->ob;
}
int
query_idle(struct object *ob)
{
if (!ob->interactive)
error("query_idle() of non-interactive object.\n");
return current_time - ob->interactive->last_time;
}
void
notify_no_command()
{
char *p,*m;
extern struct object *vbfc_object;
if (!command_giver->interactive)
return;
p = command_giver->interactive->default_err_message;
if (p)
{
/* We want 'value by function call'
*/
m = process_string(p, vbfc_object != 0);
if (!shadow_catch_message(command_giver, m))
add_message(m);
if (m != p)
free(m);
free_string(p);
command_giver->interactive->default_err_message = 0;
}
else
{
add_message("What ?\n");
}
}
void
clear_notify()
{
if (!command_giver || !command_giver->interactive)
return;
if (command_giver->interactive->default_err_message)
{
free_string(command_giver->interactive->default_err_message);
command_giver->interactive->default_err_message = 0;
}
}
void
set_notify_fail_message(char *str)
{
if (!command_giver || !command_giver->interactive)
return;
clear_notify();
if (command_giver->interactive->default_err_message)
free_string(command_giver->interactive->default_err_message);
command_giver->interactive->default_err_message = make_shared_string(str);
}
int
replace_interactive(struct object *ob, struct object *obfrom,
/*IGN*/char *name)
{
struct svalue *v;
/*
* Check with master that exec allowed
*/
push_string(name, STRING_MALLOC);
if (ob)
push_object(ob);
else
push_number(0);
push_object(obfrom);
v = apply_master_ob(M_VALID_EXEC, 3);
if (!v || v->type != T_NUMBER || v->u.number == 0)
return 0;
/* fprintf(stderr,"DEBUG: %s,%s\n",ob->name,obfrom->name); */
if (ob && ob->interactive)
error("Bad argument1 to exec()\n");
if (!obfrom->interactive)
error("Bad argument2 to exec()\n");
if (obfrom->interactive->message_length) {
write_socket(MESSAGE_FLUSH, obfrom);
}
if (ob)
{
ob->interactive = obfrom->interactive;
ob->interactive->ob = ob;
ob->flags |= O_ONCE_INTERACTIVE;
add_ref(ob, "exec");
free_object(obfrom, "exec");
obfrom->interactive = 0;
obfrom->flags &= ~O_ONCE_INTERACTIVE;
}
else
remove_interactive(obfrom, 0);
if (obfrom == command_giver) command_giver = ob;
return 1;
}
#ifdef DEBUG
/*
* This is used for debugging reference counts.
*/
void
update_ref_counts_for_players()
{
int i;
for (i = 0; i<MAX_PLAYERS; i++)
{
if (all_players[i] == 0)
continue;
all_players[i]->ob->extra_ref++;
if (all_players[i]->input_to)
all_players[i]->input_to->ob->extra_ref++;
}
}
#endif /* DEBUG */
/*
* Send messages to other muds.
*
* The message is sent with udp. If it gets there it gets there...
*/
int
send_udp(char *to_host, int to_port, char *msg)
{
int ip1, ip2, ip3, ip4;
struct sockaddr_in name;
struct hostent *hp, *gethostbyname();
if (udp_send < 0)
{
/* Create socket on which to send. */
udp_send = socket(AF_INET, SOCK_DGRAM, 0);
}
if (udp_send < 0)
return 0;
if (sscanf(to_host, "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4) == 4)
{
name.sin_addr.s_addr = inet_addr(to_host);
name.sin_family = AF_INET;
}
else
{
hp = gethostbyname(to_host);
if (hp == 0)
return 0;
memcpy(&name.sin_addr, hp->h_addr, hp->h_length);
name.sin_family = AF_INET;
}
name.sin_port = htons(to_port);
/* Send message. */
if (sendto(udp_send, msg, strlen(msg), 0,
(struct sockaddr *)&name, sizeof(name)) != strlen(msg))
return 0;
return 1;
}