summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorxplat <xplat>2007-05-14 23:09:23 (GMT)
committerxplat <xplat>2007-05-14 23:09:23 (GMT)
commit21fd5f0ee37922dc448d9e88f24ec5472d24f948 (patch)
treeb8f895e2ac54b6af3fad2bb234958b8b7b473f80
parent03bde803c4044bbf0efb4210558def2d098b6224 (diff)
parente6816f605d09158be5d5c904c71580688f0591ae (diff)
downloadmoo-cvs-CONSTANTS.zip
moo-cvs-CONSTANTS.tar.gz
moo-cvs-CONSTANTS.tar.bz2
moo-cvs-CONSTANTS.tar.xz
merged in changes from HEADCONSTANTS
-rw-r--r--ChangeLog.txt82
-rw-r--r--Makefile.in19
-rw-r--r--config.h.in10
-rwxr-xr-xconfigure48
-rw-r--r--configure.in16
-rw-r--r--db.h38
-rw-r--r--db_file.c201
-rw-r--r--db_objects.c16
-rw-r--r--decompile.c12
-rw-r--r--execute.c119
-rw-r--r--execute.h28
-rw-r--r--list.c28
-rw-r--r--log.c23
-rw-r--r--log.h15
-rw-r--r--my-in.h17
-rw-r--r--my-string.h10
-rw-r--r--net_bsd_tcp.c72
-rw-r--r--net_multi.c97
-rw-r--r--net_single.c44
-rw-r--r--net_sysv_tcp.c88
-rw-r--r--net_tcp.c92
-rw-r--r--network.c28
-rw-r--r--network.h8
-rw-r--r--options.h89
-rw-r--r--parser.y10
-rw-r--r--program.c12
-rw-r--r--server.c173
-rw-r--r--server.h90
-rw-r--r--storage.c34
-rw-r--r--storage.h29
-rw-r--r--str_intern.c2
-rw-r--r--streams.c13
-rw-r--r--streams.h7
-rw-r--r--tasks.c504
-rw-r--r--tasks.h15
-rw-r--r--utils.c12
-rw-r--r--version.c2
37 files changed, 1627 insertions, 476 deletions
diff --git a/ChangeLog.txt b/ChangeLog.txt
index 8ef2a2e..4c51c98 100644
--- a/ChangeLog.txt
+++ b/ChangeLog.txt
@@ -2313,7 +2313,7 @@ Version 1.8.0p6
-- Fixed bug where toint() accepted arguments that were not
syntactically correct (e.g., "-+5", "- 3"). Report from tijmen@dse.nl.
- Version 1.8.1
+Version 1.8.1, 10 January 2000
-- New maintainers: Ben Jackson (ben@ben.com) and Jay Carlson (nop@nop.com)
-- No significant user-visible changes to server behavior.
-- Many internal memory usage bugs fixed.
@@ -2372,3 +2372,83 @@ Version 1.8.0p6
away with reusing a type like M_VM, but this may break eventually.)
-- Server hackers should read README.rX for more information on
changes to server internals.
+
+Version 1.8.2
+Because of the long time with no release after 1.8.1, some distributors began
+to distribute 1.8.1 plus patches as 1.8.2. To avoid confusion, we have opted
+to make the next official release version 1.8.3.
+
+Version 1.8.3, in progress
+-- SF bug #887464: fixed a bug in the server's startup processing, in which it
+ scans for unknown built-in functions in active verbs (Thanks luke-jr and
+ Gavin Lambert for reports and patches.)
+-- Server will report progress every few seconds (rather than every 10k objects)
+ during potentially long-running operations (loading, validating, writing)
+-- New validation algorithms for cycle-detection and hierarchy checking vastly
+ decrease startup time on large databases.
+-- SF bug #1552816: fixed an issue that could cause tracebacks in emergency mode
+ to produce "Unknown Var type" errors
+-- SF bug #1500775: fixed two use-after-free bugs that could lead very rarely to
+ calling the wrong functions during player connection (Thanks Garance Drosehn
+ for the report and initial patch.)
+**** Changes relevant to programmers / wizards:
+-- SF bug #227620: add_verb() now returns (positive integer) verb index
+-- bf_crypt() now passes salts longer than 2 characters to the underlying C
+ function. This works fine for traditional DES crypts and supports modern
+ modular crypts like FreeBSD's. See the Programmers Manual for more details.
+-- bf_queued_tasks() entries include a 10th element (size of the task in bytes)
+-- bf_open_network_connection() accepts an optional third argument that
+ associates a specific listener object with the new connection. This
+ simplifies a lot of outbound connection management.
+-- network input is suspended on new connections until after the initial
+ #0:do_login_command call returns. Thus do_login_command may now reliably
+ set binary mode without losing data.
+-- connection_option()/connection_options()/set_connection_option() now
+ recognize the following new options:
+ (*) "intrinsic-commands"
+ which determines which (if any) of the commands
+ .program
+ PREFIX
+ SUFFIX
+ OUTPUTPREFIX
+ OUTPUTSUFFIX
+ will be recognized on that connection. Option value is a list
+ of strings, but set_connection_option() also accepts any numeric
+ value, in which case all 5 intrinsic commands are enabled/disabled
+ according to the value being true/false.
+ (*) "disable-oob"
+ which, if set true, disables all out-of-band command processing
+ on subsequent input lines, i.e., the server behaves for that
+ connection as if OUT_OF_BAND_PREFIX had never been #defined.
+ Out-of-band quoting (see below) is likewise disabled.
+-- If "disable-oob" is set false (as it is by default), then it is now the case
+ that all out-of-band lines will be processed as out-of-band commands (i.e.,
+ by #0:do_out_of_band_command) if no 'flush' command intervenes; setting of
+ "hold-input" and/or making intervening read() calls will not affect this.
+ (This fixes a bug whereby read() sometimes snarfed out-of-band lines.)
+-- Setting connection_option "binary" now disables all out-of-band processing
+ on that connection.
+**** Changes significant to people compiling and running the server:
+-- several fixes for warnings, wrong use of free() vs myfree(), etc.
+-- fixes to support modern toolchains (bison, autoconf, ...)
+-- Admins can trade faster startup for increased memory consumption by
+ disabling STRING_INTERNING in options.h
+-- Added a new compile option (MEMO_STRLEN in options.h) that optimizes away
+ most strlen computations.
+-- A new OUT_OF_BAND_QUOTE_PREFIX is added; any player input lines that begin
+ with this string will be stripped of this prefix and processed normally, even
+ if the resulting line begins with OUT_OF_BAND_PREFIX. This provides a means
+ for quoting lines that would otherwise trigger do_out_of_band_command.
+-- If the server is compiled with OUTBOUND_NETWORK, this may now be explicitly
+ enabled/disabled from the server command line using +O and -O respectively.
+-- If the server is compiled with NP_TCP, there is now a command line option
+ `-a SOURCE-ADDRESS' to bind and listen on a specific interface, instead of
+ all interfaces.
+-- Fixed some flushing issues with emergency wizard mode (-e).
+ The server now behaves a bit more sensibly when stdin comes from a pipe.
+ stdout and stderr are now closed if they are not being used.
+ (Outside of emergency wizard mode, stdout is only used on an an NP_SINGLE
+ server; stderr is only used if no logfile (-l) is specifed.)
+**** Changes relevant to server hackers:
+-- New call_verb2() accepts verb name that is a MOO string (ie, str_ref-able)
+-- str_hash() replaced with a faster (and better?) string hash function
diff --git a/Makefile.in b/Makefile.in
index 1df191a..d86da39 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -39,6 +39,7 @@ CSRCS = ast.c ast_c2v.c code_gen.c db_file.c db_io.c db_objects.c db_properties.
OPT_NET_SRCS = net_single.c net_multi.c \
net_mp_selct.c net_mp_poll.c net_mp_fake.c \
+ net_tcp.c \
net_bsd_tcp.c net_bsd_lcl.c net_sysv_tcp.c net_sysv_lcl.c
OPT_NET_OBJS = $(OPT_NET_SRCS:.c=.o)
@@ -48,6 +49,7 @@ OPT_CSRCS = gnu-malloc.c $(OPT_NET_SRCS)
YSRCS = parser.y
HDRS = ast.h bf_register.h code_gen.h db.h db_io.h db_private.h decompile.h \
+ db_tune.h \
disassemble.h eval_env.h eval_vm.h exceptions.h execute.h functions.h \
getpagesize.h keywords.h list.h log.h match.h md5.h name_lookup.h \
network.h net_mplex.h net_multi.h net_proto.h numbers.h opcode.h \
@@ -136,7 +138,7 @@ tags:
etags -t $(SRCS)
clean:
- rm -f $(OBJS) core y.tab.c y.tab.h y.output makedep eddep
+ rm -f $(OBJS) $(OPT_NET_OBJS) core parser.c y.tab.c y.tab.h y.output makedep eddep
distclean: clean
rm -f config.h Makefile config.status
@@ -153,10 +155,22 @@ depend: ${ALL_CSRCS}
###############################################################################
# $Log$
+# Revision 1.8.8.2 2007/05/14 23:09:23 xplat
+# merged in changes from HEAD
+#
# Revision 1.8.8.1 2002/11/03 03:37:58 xplat
# Initial support for keeping type constants in a global constants table
# rather than every stack frame.
#
+# Revision 1.10 2006/12/06 23:44:24 wrog
+# Add parser.c to clean target
+#
+# Revision 1.9 2004/05/22 01:25:43 wrog
+# merging in WROGUE changes (W_SRCIP, W_STARTUP, W_OOB)
+#
+# Revision 1.8.10.1 2003/06/01 12:33:07 wrog
+# added net_tcp.c; (put db_tune.h in HDRS); ran makedepend
+#
# Revision 1.8 2000/05/11 06:32:27 xythian
# fixed bloody "suspicious line 293" emacs warning when saving Makefile.in
# by tweaking quotes
@@ -493,6 +507,7 @@ net_mp_selct.o: net_mp_selct.c my-string.h config.h my-sys-time.h \
options.h my-types.h log.h my-stdio.h structures.h net_mplex.h
net_mp_poll.o: net_mp_poll.c my-poll.h config.h log.h my-stdio.h \
structures.h net_mplex.h storage.h ref_count.h
+net_tcp.o: net_tcp.c
net_bsd_tcp.o: net_bsd_tcp.c my-inet.h config.h my-in.h my-types.h \
my-socket.h my-stdlib.h my-string.h my-unistd.h list.h structures.h \
my-stdio.h log.h name_lookup.h net_proto.h options.h server.h \
@@ -506,7 +521,7 @@ net_sysv_tcp.o: net_sysv_tcp.c my-inet.h config.h my-fcntl.h my-in.h \
my-types.h my-ioctl.h my-socket.h my-stdlib.h my-string.h \
my-stropts.h my-tiuser.h my-unistd.h log.h my-stdio.h structures.h \
name_lookup.h net_proto.h options.h server.h network.h streams.h \
- timers.h my-time.h
+ timers.h my-time.h net_tcp.c exceptions.h
net_sysv_lcl.o: net_sysv_lcl.c my-fcntl.h config.h my-stat.h \
my-stdio.h my-stdlib.h my-unistd.h exceptions.h list.h structures.h \
log.h net_multi.h net_proto.h options.h storage.h ref_count.h \
diff --git a/config.h.in b/config.h.in
index ef89701..8e74619 100644
--- a/config.h.in
+++ b/config.h.in
@@ -60,6 +60,7 @@
#undef NDECL_TOLOWER /* <ctype.h> */
#undef NDECL_FCNTL /* <fcntl.h> */
#undef NDECL_HTONL /* <netinet/in.h> */
+#undef NDECL_IN_ADDR_T /* <netinet/in.h> */
#undef NDECL_IOCTL /* <sys/ioctl.h> */
#undef NDECL_POLL /* <poll.h> */
#undef NDECL_KILL /* <signal.h> */
@@ -272,6 +273,15 @@
/*
* $Log$
+ * Revision 1.2.8.1 2007/05/14 23:09:23 xplat
+ * merged in changes from HEAD
+ *
+ * Revision 1.3 2004/05/22 01:25:43 wrog
+ * merging in WROGUE changes (W_SRCIP, W_STARTUP, W_OOB)
+ *
+ * Revision 1.2.10.1 2003/06/01 12:39:27 wrog
+ * ensure definitions for in_addr_t, INADDR_NONE
+ *
* Revision 1.2 1998/12/29 05:26:51 nop
* Fixed one more Log keyword that slipped by.
*
diff --git a/configure b/configure
index 6878b69..2832b91 100755
--- a/configure
+++ b/configure
@@ -1614,6 +1614,41 @@ done
trfrom='[a-z]' trto='[A-Z]'
+for var in in_addr_t
+do
+echo "checking whether $var is declared in netinet/in.h"
+
+pattern="[^_a-zA-Z0-9]$var"
+cat > conftest.c <<EOF
+#include "confdefs.h"
+
+#include <netinet/in.h>
+
+
+EOF
+eval "$CPP conftest.c > conftest.out 2>&1"
+if egrep "$pattern" conftest.out >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ {
+test -n "$verbose" && \
+echo " defining NDECL_`echo $var | tr "$trfrom" "$trto"`"
+echo "#define" NDECL_`echo $var | tr "$trfrom" "$trto"` 1 >> confdefs.h
+DEFS="$DEFS -DNDECL_`echo $var | tr "$trfrom" "$trto"`=1"
+SEDDEFS="${SEDDEFS}\${SEDdA}NDECL_`echo $var | tr "$trfrom" "$trto"`\${SEDdB}NDECL_`echo $var | tr "$trfrom" "$trto"`\${SEDdC}1\${SEDdD}
+\${SEDuA}NDECL_`echo $var | tr "$trfrom" "$trto"`\${SEDuB}NDECL_`echo $var | tr "$trfrom" "$trto"`\${SEDuC}1\${SEDuD}
+\${SEDeA}NDECL_`echo $var | tr "$trfrom" "$trto"`\${SEDeB}NDECL_`echo $var | tr "$trfrom" "$trto"`\${SEDeC}1\${SEDeD}
+"
+}
+
+fi
+rm -f conftest*
+
+done
+
+
+trfrom='[a-z]' trto='[A-Z]'
for func in ioctl
do
echo "checking whether $func is declared in sys/ioctl.h"
@@ -2838,8 +2873,17 @@ ${CONFIG_SHELL-/bin/sh} config.status
# $Log$
-# Revision 1.1 1997/03/03 03:45:05 nop
-# Initial revision
+# Revision 1.1.1.1.10.1 2007/05/14 23:09:24 xplat
+# merged in changes from HEAD
+#
+# Revision 1.2 2004/05/22 01:25:43 wrog
+# merging in WROGUE changes (W_SRCIP, W_STARTUP, W_OOB)
+#
+# Revision 1.1.1.1.12.1 2003/06/01 12:39:27 wrog
+# ensure definitions for in_addr_t, INADDR_NONE
+#
+# Revision 1.1.1.1 1997/03/03 03:45:05 nop
+# LambdaMOO 1.8.0p5
#
# Revision 2.8 1996/03/19 07:16:46 pavel
# Added one more option for trying to enable ANSI C compilation.
diff --git a/configure.in b/configure.in
index d814f46..ca763b0 100644
--- a/configure.in
+++ b/configure.in
@@ -321,6 +321,9 @@ AC_HAVE_FUNCS(random lrand48 wait3 wait2 sigsetmask sigprocmask sigrelse)
MOO_NDECL_FUNCS(ctype.h, tolower)
MOO_NDECL_FUNCS(fcntl.h, fcntl)
MOO_NDECL_FUNCS(netinet/in.h, htonl)
+dnl *** this next should really be some variety of AC_CHECK_TYPE
+dnl *** but this is just a grep test anyway --wrog
+MOO_NDECL_VARS(netinet/in.h, in_addr_t)
MOO_NDECL_FUNCS(sys/ioctl.h, ioctl)
MOO_NDECL_FUNCS(poll.h, poll)
MOO_NDECL_FUNCS(signal.h, kill sigemptyset sigprocmask sigrelse)
@@ -518,8 +521,17 @@ echo "----------------------------------------------------------------------"
AC_OUTPUT(Makefile)
# $Log$
-# Revision 1.1 1997/03/03 03:45:05 nop
-# Initial revision
+# Revision 1.1.1.1.10.1 2007/05/14 23:09:24 xplat
+# merged in changes from HEAD
+#
+# Revision 1.2 2004/05/22 01:25:43 wrog
+# merging in WROGUE changes (W_SRCIP, W_STARTUP, W_OOB)
+#
+# Revision 1.1.1.1.12.1 2003/06/01 12:39:27 wrog
+# ensure definitions for in_addr_t, INADDR_NONE
+#
+# Revision 1.1.1.1 1997/03/03 03:45:05 nop
+# LambdaMOO 1.8.0p5
#
# Revision 2.8 1996/03/19 07:16:46 pavel
# Added one more option for trying to enable ANSI C compilation.
diff --git a/db.h b/db.h
index c239445..d1bb89c 100644
--- a/db.h
+++ b/db.h
@@ -161,13 +161,30 @@ extern int db_for_all_contents(Objid,
*/
extern void db_change_location(Objid oid, Objid location);
-/* NOTE: New flags must always be added to the end of this list, rather than
- * replacing one of the obsolete ones, since old databases might have
- * old objects around that still have that flag set.
- */
typedef enum {
- FLAG_USER, FLAG_PROGRAMMER, FLAG_WIZARD, FLAG_OBSOLETE_1,
- FLAG_READ, FLAG_WRITE, FLAG_OBSOLETE_2, FLAG_FERTILE
+ /* Permanent flags */
+ FLAG_USER,
+ FLAG_PROGRAMMER,
+ FLAG_WIZARD,
+ FLAG_OBSOLETE_1,
+ FLAG_READ,
+ FLAG_WRITE,
+ FLAG_OBSOLETE_2,
+ FLAG_FERTILE,
+ /* NOTE: New permanent flags must always be added here, rather
+ * than replacing one of the obsolete ones, since old
+ * databases might have old objects around that still have
+ * that flag set.
+ */
+
+ /* Temporary flags.
+ * (not saved; can be renumbered with impunity)
+ * make sure FLAG_FIRST_TEMP > last permanent flag
+ */
+ FLAG_FIRST_TEMP = 14,
+ /* allows space for the 2 needed by validate_hierarchies(),
+ * just in case int is only 16 bits
+ */
} db_object_flag;
extern int db_object_has_flag(Objid, db_object_flag);
@@ -518,6 +535,15 @@ extern void db_delete_verb(db_verb_handle);
/*
* $Log$
+ * Revision 1.4.8.1 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
+ * Revision 1.5 2004/05/22 01:25:43 wrog
+ * merging in WROGUE changes (W_SRCIP, W_STARTUP, W_OOB)
+ *
+ * Revision 1.4.10.1 2003/06/03 12:18:00 wrog
+ * allow temporary flags on objects
+ *
* Revision 1.4 2001/01/29 08:38:44 bjj
* Fix Sourceforge Bug #127620: add_verb() should return verbindex
* And now it does. Old servers always returned 0, new servers will always
diff --git a/db_file.c b/db_file.c
index af3c17f..a81979c 100644
--- a/db_file.c
+++ b/db_file.c
@@ -221,24 +221,22 @@ write_object(Objid oid)
static int
validate_hierarchies()
{
- Objid oid, log_oid;
+ Objid oid;
Objid size = db_last_used_objid() + 1;
int broken = 0;
int fixed_nexts = 0;
oklog("VALIDATING the object hierarchies ...\n");
-# define PROGRESS_INTERVAL 10000
# define MAYBE_LOG_PROGRESS \
{ \
- if (oid == log_oid) { \
- log_oid += PROGRESS_INTERVAL; \
+ if (log_report_progress()) { \
oklog("VALIDATE: Done through #%d ...\n", oid); \
} \
}
oklog("VALIDATE: Phase 1: Check for invalid objects ...\n");
- for (oid = 0, log_oid = PROGRESS_INTERVAL; oid < size; oid++) {
+ for (oid = 0; oid < size; oid++) {
Object *o = dbpriv_find_object(oid);
MAYBE_LOG_PROGRESS;
@@ -273,24 +271,28 @@ validate_hierarchies()
fixed_nexts);
oklog("VALIDATE: Phase 2: Check for cycles ...\n");
- for (oid = 0, log_oid = PROGRESS_INTERVAL; oid < size; oid++) {
+ for (oid = 0; oid < size; oid++) {
Object *o = dbpriv_find_object(oid);
MAYBE_LOG_PROGRESS;
if (o) {
-# define CHECK(start, field, name) \
- { \
- Objid oid2 = start; \
- int count = 0; \
- for (; oid2 != NOTHING \
- ; oid2 = dbpriv_find_object(oid2)->field) { \
- if (++count > size) { \
- errlog("VALIDATE: Cycle in `%s' chain of #%d\n",\
- name, oid); \
- broken = 1; \
- break; \
- } \
- } \
+# define CHECK(start, field, name) \
+ { \
+ Objid slower = start; \
+ Objid faster = slower; \
+ while (faster != NOTHING) { \
+ faster = dbpriv_find_object(faster)->field; \
+ if (faster == NOTHING) \
+ break; \
+ faster = dbpriv_find_object(faster)->field; \
+ slower = dbpriv_find_object(slower)->field; \
+ if (faster == slower) { \
+ errlog("VALIDATE: Cycle in `%s' chain of #%d\n", \
+ name, oid); \
+ broken = 1; \
+ break; \
+ } \
+ } \
}
CHECK(o->parent, parent, "parent");
@@ -299,62 +301,72 @@ validate_hierarchies()
CHECK(o->contents, next, "contents");
# undef CHECK
+
+ /* setup for phase 3: set two temp flags on every object */
+ o->flags |= (3<<FLAG_FIRST_TEMP);
}
}
if (broken) /* Can't continue if cycles found */
return 0;
- oklog("VALIDATE: Phase 3: Check for inconsistencies ...\n");
- for (oid = 0, log_oid = PROGRESS_INTERVAL; oid < size; oid++) {
+ oklog("VALIDATE: Phase 3a: Finding delusional parents ...\n");
+ for (oid = 0; oid < size; oid++) {
Object *o = dbpriv_find_object(oid);
MAYBE_LOG_PROGRESS;
if (o) {
-# define CHECK(up, up_name, down, down_name, across) \
- { \
- Objid up = o->up; \
- Objid oid2; \
- \
- /* Is oid in its up's down list? */ \
- if (up != NOTHING) { \
- for (oid2 = dbpriv_find_object(up)->down; \
- oid2 != NOTHING; \
- oid2 = dbpriv_find_object(oid2)->across) { \
- if (oid2 == oid) /* found it */ \
- break; \
- } \
- if (oid2 == NOTHING) { /* didn't find it */ \
- errlog("VALIDATE: #%d not in %s (#%d)'s %s list.\n", \
- oid, up_name, up, down_name); \
- broken = 1; \
- } \
- } \
+# define CHECK(up, down, down_name, across, FLAG) \
+ { \
+ Objid oidkid; \
+ Object *okid; \
+ \
+ for (oidkid = o->down; \
+ oidkid != NOTHING; \
+ oidkid = okid->across) { \
+ \
+ okid = dbpriv_find_object(oidkid); \
+ if (okid->up != oid) { \
+ errlog( \
+ "VALIDATE: #%d erroneously on #%d's %s list.\n", \
+ oidkid, oid, down_name); \
+ broken = 1; \
+ } \
+ else { \
+ /* mark okid as properly claimed */ \
+ okid->flags &= ~(1<<(FLAG)); \
+ } \
+ } \
}
- CHECK(parent, "parent", child, "child", sibling);
- CHECK(location, "location", contents, "contents", next);
+ CHECK(parent, child, "child", sibling, FLAG_FIRST_TEMP);
+ CHECK(location, contents, "contents", next, FLAG_FIRST_TEMP+1);
# undef CHECK
+ }
+ }
-# define CHECK(up, down, down_name, across) \
+ oklog("VALIDATE: Phase 3b: Finding delusional children ...\n");
+ for (oid = 0; oid < size; oid++) {
+ Object *o = dbpriv_find_object(oid);
+
+ MAYBE_LOG_PROGRESS;
+ if (o) {
+# define CHECK(up, up_name, down_name, FLAG) \
{ \
- Objid oid2; \
- \
- for (oid2 = o->down; \
- oid2 != NOTHING; \
- oid2 = dbpriv_find_object(oid2)->across) { \
- if (dbpriv_find_object(oid2)->up != oid) { \
- errlog( \
- "VALIDATE: #%d erroneously on #%d's %s list.\n", \
- oid2, oid, down_name); \
- broken = 1; \
- } \
+ /* If oid is unclaimed, up must be NOTHING */ \
+ if ((o->flags & (1<<(FLAG))) && o->up != NOTHING) { \
+ errlog("VALIDATE: #%d not in %s (#%d)'s %s list.\n", \
+ oid, up_name, o->up, down_name); \
+ broken = 1; \
} \
}
- CHECK(parent, child, "child", sibling);
- CHECK(location, contents, "contents", next);
+ CHECK(parent, "parent", "child", FLAG_FIRST_TEMP);
+ CHECK(location, "location", "contents", FLAG_FIRST_TEMP+1);
+
+ /* clear temp flags */
+ o->flags &= ~(3<<FLAG_FIRST_TEMP);
# undef CHECK
}
@@ -489,7 +501,7 @@ read_db_file(void)
errlog("READ_DB_FILE: Bad object #%d.\n", i - 1);
return 0;
}
- if (i % 10000 == 0 || i == nobjs)
+ if (i == nobjs || log_report_progress())
oklog("LOADING: Done reading %d objects ...\n", i);
}
@@ -519,7 +531,7 @@ read_db_file(void)
return 0;
}
db_set_verb_program(h, program);
- if (i % 5000 == 0 || i == nprogs)
+ if (i == nprogs || log_report_progress())
oklog("LOADING: Done reading %d verb programs...\n", i);
}
@@ -576,39 +588,40 @@ write_db_file(const char *reason)
user_list = db_all_users();
- TRY
+ TRY {
dbio_printf(header_format_string, current_version);
- write_tags();
- dbio_printf("%d\n%d\n%d\n%d\n",
- max_oid + 1, nprogs, 0, user_list.v.list[0].v.num);
- for (i = 1; i <= user_list.v.list[0].v.num; i++)
- dbio_write_objid(user_list.v.list[i].v.obj);
- oklog("%s: Writing %d objects...\n", reason, max_oid + 1);
- for (oid = 0; oid <= max_oid; oid++) {
- write_object(oid);
- if ((oid + 1) % 10000 == 0 || oid == max_oid)
- oklog("%s: Done writing %d objects...\n", reason, oid + 1);
- }
- oklog("%s: Writing %d MOO verb programs...\n", reason, nprogs);
- for (i = 0, oid = 0; oid <= max_oid; oid++)
- if (valid(oid)) {
- int vcount = 0;
-
- for (v = dbpriv_find_object(oid)->verbdefs; v; v = v->next) {
- if (v->program) {
- dbio_printf("#%d:%d\n", oid, vcount);
- dbio_write_program(v->program);
- if (++i % 5000 == 0 || i == nprogs)
- oklog("%s: Done writing %d verb programs...\n",
- reason, i);
+ write_tags();
+ dbio_printf("%d\n%d\n%d\n%d\n",
+ max_oid + 1, nprogs, 0, user_list.v.list[0].v.num);
+ for (i = 1; i <= user_list.v.list[0].v.num; i++)
+ dbio_write_objid(user_list.v.list[i].v.obj);
+ oklog("%s: Writing %d objects...\n", reason, max_oid + 1);
+ for (oid = 0; oid <= max_oid; oid++) {
+ write_object(oid);
+ if (oid == max_oid || log_report_progress())
+ oklog("%s: Done writing %d objects...\n", reason, oid + 1);
+ }
+ oklog("%s: Writing %d MOO verb programs...\n", reason, nprogs);
+ for (i = 0, oid = 0; oid <= max_oid; oid++)
+ if (valid(oid)) {
+ int vcount = 0;
+
+ for (v = dbpriv_find_object(oid)->verbdefs; v; v = v->next) {
+ if (v->program) {
+ dbio_printf("#%d:%d\n", oid, vcount);
+ dbio_write_program(v->program);
+ if (++i == nprogs || log_report_progress())
+ oklog("%s: Done writing %d verb programs...\n",
+ reason, i);
+ }
+ vcount++;
}
- vcount++;
}
- }
- oklog("%s: Writing forked and suspended tasks...\n", reason);
- write_task_queue();
- oklog("%s: Writing list of formerly active connections...\n", reason);
- write_active_connections();
+ oklog("%s: Writing forked and suspended tasks...\n", reason);
+ write_task_queue();
+ oklog("%s: Writing list of formerly active connections...\n", reason);
+ write_active_connections();
+ }
EXCEPT(dbpriv_dbio_failed)
success = 0;
ENDTRY;
@@ -810,6 +823,9 @@ char rcsid_db_file[] = "$Id$";
/*
* $Log$
+ * Revision 1.4.6.3.2.1 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
* Revision 1.4.6.3 2002/09/17 15:35:04 xplat
* GNU indent normalization.
*
@@ -819,6 +835,15 @@ char rcsid_db_file[] = "$Id$";
* Revision 1.4.6.1 2002/09/12 05:57:40 xplat
* Changes for inline PC saving and patch tags in the on-disk DB.
*
+ * Revision 1.5 2004/05/22 01:25:43 wrog
+ * merging in WROGUE changes (W_SRCIP, W_STARTUP, W_OOB)
+ *
+ * Revision 1.4.8.2 2003/06/03 12:21:17 wrog
+ * new validation algorithms for cycle-detection and hierarchy checking
+ *
+ * Revision 1.4.8.1 2003/06/01 12:27:35 wrog
+ * added braces and fixed indentation on TRY
+ *
* Revision 1.4 1998/12/14 13:17:33 nop
* Merge UNSAFE_OPTS (ref fixups); fix Log tag placement to fit CVS whims
*
diff --git a/db_objects.c b/db_objects.c
index 26f658c..075422a 100644
--- a/db_objects.c
+++ b/db_objects.c
@@ -289,18 +289,18 @@ db_object_bytes(Objid oid)
Verbdef *v;
count = sizeof(Object) + sizeof(Object *);
- count += strlen(o->name) + 1;
+ count += memo_strlen(o->name) + 1;
for (v = o->verbdefs; v; v = v->next) {
count += sizeof(Verbdef);
- count += strlen(v->name) + 1;
+ count += memo_strlen(v->name) + 1;
if (v->program)
count += program_bytes(v->program);
}
count += sizeof(Propdef) * o->propdefs.cur_length;
for (i = 0; i < o->propdefs.cur_length; i++)
- count += strlen(o->propdefs.l[i].name) + 1;
+ count += memo_strlen(o->propdefs.l[i].name) + 1;
len = dbpriv_count_properties(oid);
count += (sizeof(Pval) - sizeof(Var)) * len;
@@ -554,6 +554,16 @@ char rcsid_db_objects[] = "$Id$";
/*
* $Log$
+ * Revision 1.4.8.1 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
+ * Revision 1.5 2006/09/07 00:55:02 bjj
+ * Add new MEMO_STRLEN option which uses the refcounting mechanism to
+ * store strlen with strings. This is basically free, since most string
+ * allocations are rounded up by malloc anyway. This saves lots of cycles
+ * computing strlen. (The change is originally from jitmoo, where I wanted
+ * inline range checks for string ops).
+ *
* Revision 1.4 1998/12/14 13:17:36 nop
* Merge UNSAFE_OPTS (ref fixups); fix Log tag placement to fit CVS whims
*
diff --git a/decompile.c b/decompile.c
index 54dabef..ab54d97 100644
--- a/decompile.c
+++ b/decompile.c
@@ -67,6 +67,7 @@ do { \
arm_sink = &(temp->next); \
} while (0);
+#define SKIP_BYTES(n) ((void)(ptr += n))
#define READ_BYTES(n) \
(ptr += n, \
(n == 1 \
@@ -83,7 +84,7 @@ do { \
#define READ_LITERAL() program->literals[READ_BYTES(bc.numbytes_literal)]
#define READ_FORK() program->fork_vectors[READ_BYTES(bc.numbytes_fork)]
#define READ_ID() READ_BYTES(bc.numbytes_var_name)
-#define READ_STACK() READ_BYTES(bc.numbytes_stack)
+#define READ_STACK() SKIP_BYTES(bc.numbytes_stack)
#define READ_JUMP(is_hot) read_jump(bc.numbytes_label, &ptr, &is_hot)
@@ -1100,6 +1101,9 @@ char rcsid_decompile[] = "$Id$";
/*
* $Log$
+ * Revision 1.5.6.5.2.3 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
* Revision 1.5.6.5.2.2 2002/11/03 03:42:35 xplat
* GNU indent normalization.
*
@@ -1113,6 +1117,12 @@ char rcsid_decompile[] = "$Id$";
* Revision 1.5.6.4 2002/09/17 15:35:04 xplat
* GNU indent normalization.
*
+ * Revision 1.7 2006/12/06 23:51:31 wrog
+ * Fix compiler warnings about unused values
+ *
+ * Revision 1.6 2002/09/15 23:21:01 xplat
+ * GNU indent normalization.
+ *
* Revision 1.5.6.3 2002/09/17 15:03:56 xplat
* Updated to INLINEPC_updater_1 in trunk.
*
diff --git a/execute.c b/execute.c
index bc50562..64b6472 100644
--- a/execute.c
+++ b/execute.c
@@ -61,7 +61,6 @@ static int ticks_remaining;
int task_timed_out;
static int interpreter_is_running = 0;
static Timer_ID task_alarm_id;
-static task_kind current_task_kind;
static const char *handler_verb_name; /* For in-DB traceback handling */
static Var handler_verb_args;
@@ -734,7 +733,7 @@ run(char raise, enum error resumption_error, Var * result)
+ ((unsigned) bv[-2] << 8) \
+ bv[-1]))))
-#define SKIP_BYTES(bv, nb) (void)(bv += nb)
+#define SKIP_BYTES(bv, nb) ((void)(bv += nb))
#define LOAD_STATE_VARIABLES() \
do { \
@@ -812,8 +811,10 @@ do { \
Var cond;
cond = POP();
- if (!is_true(cond)) /* jump if false */
- JUMP(READ_BYTES(bv, bc.numbytes_label));
+ if (!is_true(cond)) { /* jump if false */
+ unsigned lab = READ_BYTES(bv, bc.numbytes_label);
+ JUMP(lab);
+ }
else {
SKIP_BYTES(bv, bc.numbytes_label);
}
@@ -822,7 +823,10 @@ do { \
break;
case OP_JUMP:
- JUMP(READ_BYTES(bv, bc.numbytes_label));
+ {
+ unsigned lab = READ_BYTES(bv, bc.numbytes_label);
+ JUMP(lab);
+ }
break;
case OP_FOR_LIST:
@@ -962,12 +966,13 @@ do { \
|| (list.type == TYPE_LIST
&& index.v.num > list.v.list[0].v.num /* size */ )
|| (list.type == TYPE_STR
- && index.v.num > (int) strlen(list.v.str))) {
+ && index.v.num > (int) memo_strlen(list.v.str))) {
free_var(value);
free_var(index);
free_var(list);
PUSH_ERROR(E_RANGE);
- } else if (list.type == TYPE_STR && strlen(value.v.str) != 1) {
+ } else if (list.type == TYPE_STR
+ && memo_strlen(value.v.str) != 1) {
free_var(value);
free_var(index);
free_var(list);
@@ -1180,10 +1185,11 @@ do { \
ans = do_add(lhs, rhs);
else if (lhs.type == TYPE_STR && rhs.type == TYPE_STR) {
char *str;
+ int llen = memo_strlen(lhs.v.str);
- str = mymalloc((strlen(rhs.v.str) + strlen(lhs.v.str) + 1)
- * sizeof(char), M_STRING);
- sprintf(str, "%s%s", lhs.v.str, rhs.v.str);
+ str = mymalloc(llen + memo_strlen(rhs.v.str) + 1, M_STRING);
+ strcpy(str, lhs.v.str);
+ strcpy(str + llen, rhs.v.str);
ans.type = TYPE_STR;
ans.v.str = str;
} else {
@@ -1273,7 +1279,7 @@ do { \
}
} else { /* list.type == TYPE_STR */
if (index.v.num <= 0
- || index.v.num > (int) strlen(list.v.str)) {
+ || index.v.num > (int) memo_strlen(list.v.str)) {
free_var(index);
free_var(list);
PUSH_ERROR(E_RANGE);
@@ -1317,7 +1323,7 @@ do { \
free_var(from);
PUSH_ERROR(E_TYPE);
} else {
- int len = (base.type == TYPE_STR ? strlen(base.v.str)
+ int len = (base.type == TYPE_STR ? memo_strlen(base.v.str)
: base.v.list[0].v.num);
if (from.v.num <= to.v.num
&& (from.v.num <= 0 || from.v.num > len
@@ -1683,7 +1689,7 @@ do { \
free_var(value);
PUSH_ERROR(E_TYPE);
} else if (rangeset_check(base.type == TYPE_STR
- ? strlen(base.v.str)
+ ? memo_strlen(base.v.str)
: base.v.list[0].v.num,
from.v.num, to.v.num)) {
free_var(base);
@@ -1706,7 +1712,7 @@ do { \
v.type = TYPE_INT;
item = RUN_ACTIV.base_rt_stack[i];
if (item.type == TYPE_STR) {
- v.v.num = strlen(item.v.str);
+ v.v.num = memo_strlen(item.v.str);
PUSH(v);
} else if (item.type == TYPE_LIST) {
v.v.num = item.v.list[0].v.num;
@@ -1825,6 +1831,7 @@ do { \
{
Var v, marker;
int i;
+ unsigned lab;
if (eop == EOP_END_CATCH)
v = POP();
@@ -1840,7 +1847,8 @@ do { \
if (eop == EOP_END_CATCH)
PUSH(v);
- JUMP(READ_BYTES(bv, bc.numbytes_label));
+ lab = READ_BYTES(bv, bc.numbytes_label);
+ JUMP(lab);
}
break;
@@ -1892,7 +1900,7 @@ do { \
goto do_test;
case EOP_EXIT_ID:
- READ_BYTES(bv, bc.numbytes_var_name); /* ignore id */
+ SKIP_BYTES(bv, bc.numbytes_var_name); /* ignore id */
/* fall thru */
case EOP_EXIT:
{
@@ -2130,17 +2138,19 @@ run_interpreter(char raise, enum error e,
if (ret == OUTCOME_ABORTED && handler_verb_name) {
db_verb_handle h;
+ enum outcome hret;
Var args, handled, traceback;
int i;
args = handler_verb_args;
h = db_find_callable_verb(SYSTEM_OBJECT, handler_verb_name);
if (do_db_tracebacks && h.ptr) {
- ret = do_server_verb_task(SYSTEM_OBJECT, handler_verb_name,
- var_ref(handler_verb_args), h,
- activ_stack[0].player, "", &handled, 0);
- if ((ret == OUTCOME_DONE && is_true(handled))
- || ret == OUTCOME_BLOCKED) {
+ hret = do_server_verb_task(SYSTEM_OBJECT, handler_verb_name,
+ var_ref(handler_verb_args), h,
+ activ_stack[0].player, "", &handled,
+ 0/*no-traceback*/);
+ if ((hret == OUTCOME_DONE && is_true(handled))
+ || hret == OUTCOME_BLOCKED) {
/* Assume the in-DB code handled it */
free_var(args);
return OUTCOME_ABORTED; /* original ret value */
@@ -2192,13 +2202,12 @@ current_max_stack_size(void)
/* procedure to create a new task */
static enum outcome
-do_task(Program * prog, int which_vector, Var * result, int do_db_tracebacks)
+do_task(Program * prog, int which_vector, Var * result, int is_fg, int do_db_tracebacks)
{ /* which vector determines the vector for the root_activ.
a forked task can also have which_vector == MAIN_VECTOR.
this happens iff it is recovered from a read from disk,
because in that case the forked statement is parsed as
the main vector */
- int forked = (current_task_kind == TASK_FORKED);
RUN_ACTIV.prog = program_ref(prog);
@@ -2212,17 +2221,16 @@ do_task(Program * prog, int which_vector, Var * result, int do_db_tracebacks)
RUN_ACTIV.bi_func_pc = 0;
RUN_ACTIV.temp.type = TYPE_NONE;
- return run_interpreter(0, E_NONE, result, !forked, do_db_tracebacks);
+ return run_interpreter(0, E_NONE, result, is_fg, do_db_tracebacks);
}
/* procedure to resume an old task */
enum outcome
-resume_from_previous_vm(vm the_vm, Var v, task_kind kind, Var * result)
+resume_from_previous_vm(vm the_vm, Var v)
{
int i;
- current_task_kind = kind;
check_activ_stack_size(the_vm->max_stack_size);
top_activ_stack = the_vm->top_activ_stack;
root_activ_vector = the_vm->root_activ_vector;
@@ -2232,12 +2240,12 @@ resume_from_previous_vm(vm the_vm, Var v, task_kind kind, Var * result)
free_vm(the_vm, 0);
if (v.type == TYPE_ERR)
- return run_interpreter(1, v.v.err, result, 0, 1);
+ return run_interpreter(1, v.v.err, 0, 0/*bg*/, 1/*traceback*/);
else {
/* PUSH_REF(v) */
*(RUN_ACTIV.top_rt_stack++) = var_ref(v);
- return run_interpreter(0, E_NONE, result, 0, 1);
+ return run_interpreter(0, E_NONE, 0, 0/*bg*/, 1/*traceback*/);
}
}
@@ -2264,7 +2272,6 @@ do_server_program_task(Objid this, const char *verb, Var args, Objid vloc,
{
Var *env;
- current_task_kind = TASK_INPUT;
check_activ_stack_size(current_max_stack_size());
top_activ_stack = 0;
@@ -2288,7 +2295,7 @@ do_server_program_task(Objid this, const char *verb, Var args, Objid vloc,
set_rt_env_str(env, SLOT_VERB, str_ref(RUN_ACTIV.verb));
set_rt_env_var(env, SLOT_ARGS, args);
- return do_task(program, MAIN_VECTOR, result, do_db_tracebacks);
+ return do_task(program, MAIN_VECTOR, result, 1/*fg*/, do_db_tracebacks);
}
enum outcome
@@ -2297,7 +2304,6 @@ do_input_task(Objid user, Parsed_Command * pc, Objid this, db_verb_handle vh)
Program *prog = db_verb_program(vh);
Var *env;
- current_task_kind = TASK_INPUT;
check_activ_stack_size(current_max_stack_size());
top_activ_stack = 0;
@@ -2321,21 +2327,19 @@ do_input_task(Objid user, Parsed_Command * pc, Objid this, db_verb_handle vh)
set_rt_env_str(env, SLOT_VERB, str_ref(pc->verb));
set_rt_env_var(env, SLOT_ARGS, var_ref(pc->args));
- return do_task(prog, MAIN_VECTOR, 0, 1);
+ return do_task(prog, MAIN_VECTOR, 0, 1/*fg*/, 1/*traceback*/);
}
enum outcome
-do_forked_task(Program * prog, Var * rt_env, activation a, int f_id,
- Var * result)
+do_forked_task(Program * prog, Var * rt_env, activation a, int f_id)
{
- current_task_kind = TASK_FORKED;
check_activ_stack_size(current_max_stack_size());
top_activ_stack = 0;
RUN_ACTIV = a;
RUN_ACTIV.rt_env = rt_env;
- return do_task(prog, f_id, result, 1);
+ return do_task(prog, f_id, 0, 0/*bg*/, 1/*traceback*/);
}
/* this is called from bf_eval to set up stack for an eval call */
@@ -3010,11 +3014,11 @@ read_activ(activation * a, int *which_vector, int is_root)
}
if (a->bi_func_pc != 0) {
func_name = dbio_read_string();
- a->bi_func_id = number_func_by_name(func_name);
- if (a->bi_func_id == FUNC_NOT_FOUND) {
+ if ((i = number_func_by_name(func_name)) == FUNC_NOT_FOUND) {
errlog("READ_ACTIV: Unknown built-in function `%s'\n", func_name);
return 0;
}
+ a->bi_func_id = i;
if (!read_bi_func_data(a->bi_func_id, &a->bi_func_data,
&a->bi_func_pc)) {
errlog("READ_ACTIV: Bad saved state for built-in function `%s'\n",
@@ -3106,7 +3110,44 @@ char rcsid_execute[] = "$Id$";
/*
* $Log$
- * Revision 1.13.6.7.2.2 2002/11/03 03:42:35 xplat
+ * Revision 1.13.6.7.2.3 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
+ * Revision 1.19 2006/12/06 23:54:53 wrog
+ * Fix compiler warnings about undefined behavior (bv assigned twice in JUMP(READ_BYTES(...))) and unused values
+ *
+ * Revision 1.18 2006/09/26 02:03:59 pschwan
+ * b=1552816
+ * r=ben
+ *
+ * execute.c:run_interpreter() sometimes clobbers the real return code with that
+ * of the traceback handler. If |result| is non-NULL, this can lead to it being
+ * used later on without ever having been initialized, causing "Unknown Var type"
+ * errors.
+ *
+ * In practice -- because |result| is almost always NULL or (in one case)
+ * initialized before calling run_interpreter() -- this situation wasn't
+ * encountered execept in Emergency Mode.
+ *
+ * Revision 1.17 2006/09/07 00:55:02 bjj
+ * Add new MEMO_STRLEN option which uses the refcounting mechanism to
+ * store strlen with strings. This is basically free, since most string
+ * allocations are rounded up by malloc anyway. This saves lots of cycles
+ * computing strlen. (The change is originally from jitmoo, where I wanted
+ * inline range checks for string ops).
+ *
+ * Revision 1.16 2004/05/22 01:25:43 wrog
+ * merging in WROGUE changes (W_SRCIP, W_STARTUP, W_OOB)
+ *
+ * Revision 1.15 2004/03/03 23:06:57 bjj
+ * Luke-Jr's patch for read_activ FUNC_NOT_FOUND
+ *
+ * Revision 1.14.2.1 2003/06/04 21:28:58 wrog
+ * removed useless arguments from resume_from_previous_vm(), do_forked_task();
+ * replaced current_task_kind with is_fg argument for do_task();
+ * made enum task_kind internal to tasks.c
+ *
+ * Revision 1.14 2002/09/15 23:21:01 xplat
* GNU indent normalization.
*
* Revision 1.13.6.7.2.1 2002/11/03 03:37:58 xplat
diff --git a/execute.h b/execute.h
index bc20fed..2e4e8b3 100644
--- a/execute.h
+++ b/execute.h
@@ -71,10 +71,6 @@ typedef struct {
typedef vmstruct *vm;
-typedef enum {
- TASK_INPUT, TASK_FORKED, TASK_SUSPENDED
-} task_kind;
-
#define alloc_data(size) mymalloc(size, M_BI_FUNC_DATA)
#define free_data(ptr) myfree((void *) ptr, M_BI_FUNC_DATA)
@@ -97,13 +93,13 @@ enum outcome {
};
extern enum outcome do_forked_task(Program * prog, Var * rt_env,
- activation a, int f_id, Var * result);
+ activation a, int f_id);
extern enum outcome do_input_task(Objid user, Parsed_Command * pc,
Objid this, db_verb_handle vh);
extern enum outcome do_server_verb_task(Objid this, const char *verb,
Var args, db_verb_handle h,
Objid player, const char *argstr,
- Var * result, int do_db_tracebacks);
+ Var * result, int do_db_tracebacks);
extern enum outcome do_server_program_task(Objid this, const char *verb,
Var args, Objid vloc,
const char *verbname,
@@ -112,8 +108,7 @@ extern enum outcome do_server_program_task(Objid this, const char *verb,
const char *argstr,
Var * result,
int do_db_tracebacks);
-extern enum outcome resume_from_previous_vm(vm the_vm, Var value,
- task_kind tk, Var * result);
+extern enum outcome resume_from_previous_vm(vm the_vm, Var value);
extern int task_timed_out;
extern void abort_running_task(void);
@@ -136,6 +131,9 @@ extern int read_activ(activation * a, int *which_vector, int is_root);
/*
* $Log$
+ * Revision 1.6.6.3.2.1 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
* Revision 1.6.6.3 2002/10/27 22:48:12 xplat
* Changes to support PCs located in vectors other than MAIN_VECTOR.
*
@@ -145,6 +143,20 @@ extern int read_activ(activation * a, int *which_vector, int is_root);
* Revision 1.6.6.1 2002/09/12 05:57:40 xplat
* Changes for inline PC saving and patch tags in the on-disk DB.
*
+ * Revision 1.8 2004/05/22 01:25:43 wrog
+ * merging in WROGUE changes (W_SRCIP, W_STARTUP, W_OOB)
+ *
+ * Revision 1.7.2.2 2003/06/07 13:14:24 wrog
+ * fix log entry
+ *
+ * Revision 1.7.2.1 2003/06/04 21:28:59 wrog
+ * removed useless arguments from resume_from_previous_vm(), do_forked_task();
+ * replaced current_task_kind with is_fg argument for do_task();
+ * made enum task_kind internal to tasks.c
+ *
+ * Revision 1.7 2002/09/15 23:21:01 xplat
+ * GNU indent normalization.
+ *
* Revision 1.6 2002/08/18 09:47:26 bjj
* Finally made free_activation() take a pointer after noticing how !$%^&
* much time it was taking in a particular profiling run.
diff --git a/list.c b/list.c
index 094c28b..f3fe9d7 100644
--- a/list.c
+++ b/list.c
@@ -343,8 +343,8 @@ strrangeset(Var base, int from, int to, Var value)
{
/* base and value are free'd */
int index, offset = 0;
- int val_len = strlen(value.v.str);
- int base_len = strlen(base.v.str);
+ int val_len = memo_strlen(value.v.str);
+ int base_len = memo_strlen(base.v.str);
int lenleft = (from > 1) ? from - 1 : 0;
int lenmiddle = val_len;
int lenright = (base_len > to) ? base_len - to : 0;
@@ -416,7 +416,7 @@ bf_length(Var arglist, Byte next, void *vdata, Objid progr)
break;
case TYPE_STR:
r.type = TYPE_INT;
- r.v.num = strlen(arglist.v.list[1].v.str);
+ r.v.num = memo_strlen(arglist.v.list[1].v.str);
break;
default:
free_var(arglist);
@@ -565,7 +565,7 @@ bf_crypt(Var arglist, Byte next, void *vdata, Objid progr)
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
extern const char *crypt(const char *, const char *);
- if (arglist.v.list[0].v.num == 1 || strlen(arglist.v.list[2].v.str) < 2) {
+ if (arglist.v.list[0].v.num == 1 || memo_strlen(arglist.v.list[2].v.str) < 2) {
/* provide a random 2-letter salt, works with old and new crypts */
salt[0] = saltstuff[RANDOM() % (int) strlen(saltstuff)];
salt[1] = saltstuff[RANDOM() % (int) strlen(saltstuff)];
@@ -825,7 +825,7 @@ check_subs_list(Var subs)
|| subs.v.list[4].type != TYPE_STR)
return 1;
subj = subs.v.list[4].v.str;
- subj_length = strlen(subj);
+ subj_length = memo_strlen(subj);
if (invalid_pair(subs.v.list[1].v.num, subs.v.list[2].v.num,
subj_length))
return 1;
@@ -855,7 +855,7 @@ bf_substitute(Var arglist, Byte next, void *vdata, Objid progr)
char c = '\0';
template = arglist.v.list[1].v.str;
- template_length = strlen(template);
+ template_length = memo_strlen(template);
subs = arglist.v.list[2];
if (check_subs_list(subs)) {
@@ -863,7 +863,7 @@ bf_substitute(Var arglist, Byte next, void *vdata, Objid progr)
return make_error_pack(E_INVARG);
}
subject = subs.v.list[4].v.str;
- subject_length = strlen(subject);
+ subject_length = memo_strlen(subject);
s = new_stream(template_length);
ans.type = TYPE_STR;
@@ -964,7 +964,7 @@ bf_string_hash(Var arglist, Byte next, void *vdata, Objid progr)
const char *str = arglist.v.list[1].v.str;
r.type = TYPE_STR;
- r.v.str = hash_bytes(str, strlen(str));
+ r.v.str = hash_bytes(str, memo_strlen(str));
free_var(arglist);
return make_var_pack(r);
}
@@ -976,7 +976,7 @@ bf_value_hash(Var arglist, Byte next, void *vdata, Objid progr)
const char *lit = value_to_literal(arglist.v.list[1]);
r.type = TYPE_STR;
- r.v.str = hash_bytes(lit, strlen(lit));
+ r.v.str = hash_bytes(lit, memo_strlen(lit));
free_var(arglist);
return make_var_pack(r);
}
@@ -1143,6 +1143,16 @@ char rcsid_list[] = "$Id$";
/*
* $Log$
+ * Revision 1.6.8.1 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
+ * Revision 1.7 2006/09/07 00:55:02 bjj
+ * Add new MEMO_STRLEN option which uses the refcounting mechanism to
+ * store strlen with strings. This is basically free, since most string
+ * allocations are rounded up by malloc anyway. This saves lots of cycles
+ * computing strlen. (The change is originally from jitmoo, where I wanted
+ * inline range checks for string ops).
+ *
* Revision 1.6 2001/03/12 00:16:29 bjj
* bf_crypt now passes the entire second argument as the salt to
* the C crypt() routine. This works fine for traditional DES crypts
diff --git a/log.c b/log.c
index baf7b1d..12c9401 100644
--- a/log.c
+++ b/log.c
@@ -38,14 +38,24 @@ set_log_file(FILE * f)
log_file = f;
}
+int log_pcount = 5000;
+static time_t log_prev = 0;
+int log_report_progress_cktime()
+{
+ time_t now = time(0);
+ log_pcount = 5000;
+ return ((now >= log_prev + 2) && (log_prev = now, 1));
+}
+
static void
do_log(const char *fmt, va_list args, const char *prefix)
{
FILE *f;
+ log_prev = time(0);
+ log_pcount = 5000;
if (log_file) {
- time_t now = time(0);
- char *nowstr = ctime(&now);
+ char *nowstr = ctime(&log_prev);
nowstr[19] = '\0'; /* kill the year and newline at the end */
f = log_file;
@@ -153,6 +163,15 @@ char rcsid_log[] = "$Id$";
/*
* $Log$
+ * Revision 1.3.8.1 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
+ * Revision 1.4 2004/05/22 01:25:43 wrog
+ * merging in WROGUE changes (W_SRCIP, W_STARTUP, W_OOB)
+ *
+ * Revision 1.3.10.1 2003/06/03 12:19:27 wrog
+ * added log_report_progress()
+ *
* Revision 1.3 1998/12/14 13:17:59 nop
* Merge UNSAFE_OPTS (ref fixups); fix Log tag placement to fit CVS whims
*
diff --git a/log.h b/log.h
index 2beb53e..b036c30 100644
--- a/log.h
+++ b/log.h
@@ -30,8 +30,23 @@ extern void reset_command_history(void);
extern void log_command_history(void);
extern void add_command_to_history(Objid player, const char *command);
+
+#define log_report_progress() ((--log_pcount <= 0) && log_report_progress_cktime())
+
+extern int log_pcount;
+extern int log_report_progress_cktime();
+
/*
* $Log$
+ * Revision 1.3.8.1 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
+ * Revision 1.4 2004/05/22 01:25:43 wrog
+ * merging in WROGUE changes (W_SRCIP, W_STARTUP, W_OOB)
+ *
+ * Revision 1.3.10.1 2003/06/03 12:19:27 wrog
+ * added log_report_progress()
+ *
* Revision 1.3 1998/12/14 13:18:00 nop
* Merge UNSAFE_OPTS (ref fixups); fix Log tag placement to fit CVS whims
*
diff --git a/my-in.h b/my-in.h
index 1c33c25..807079b 100644
--- a/my-in.h
+++ b/my-in.h
@@ -38,10 +38,27 @@ extern unsigned32 ntohl();
#endif
+# if NDECL_IN_ADDR_T
+typedef unsigned32 in_addr_t;
+# endif
+
+# ifndef INADDR_NONE
+# define INADDR_NONE ((in_addr_t)-1)
+# endif
+
#endif
/*
* $Log$
+ * Revision 1.3.8.1 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
+ * Revision 1.4 2004/05/22 01:25:43 wrog
+ * merging in WROGUE changes (W_SRCIP, W_STARTUP, W_OOB)
+ *
+ * Revision 1.3.10.1 2003/06/01 12:39:27 wrog
+ * ensure definitions for in_addr_t, INADDR_NONE
+ *
* Revision 1.3 1998/12/14 13:18:09 nop
* Merge UNSAFE_OPTS (ref fixups); fix Log tag placement to fit CVS whims
*
diff --git a/my-string.h b/my-string.h
index a95f6ca..ac09182 100644
--- a/my-string.h
+++ b/my-string.h
@@ -54,6 +54,7 @@ extern size_t strlen(const char *);
# if NDECL_MEMCPY
# include "my-types.h"
extern void *memcpy(void *, const void *, size_t);
+extern void *memmove(void *, const void *, size_t);
extern int memcmp(const void *, const void *, size_t);
# endif
# endif
@@ -87,6 +88,15 @@ extern void *memset(void *, int, size_t);
/*
* $Log$
+ * Revision 1.3.8.1 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
+ * Revision 1.4 2004/05/22 01:25:43 wrog
+ * merging in WROGUE changes (W_SRCIP, W_STARTUP, W_OOB)
+ *
+ * Revision 1.3.10.1 2003/06/11 10:36:14 wrog
+ * added memmove()
+ *
* Revision 1.3 1998/12/14 13:18:19 nop
* Merge UNSAFE_OPTS (ref fixups); fix Log tag placement to fit CVS whims
*
diff --git a/net_bsd_tcp.c b/net_bsd_tcp.c
index af36792..eeeb50b 100644
--- a/net_bsd_tcp.c
+++ b/net_bsd_tcp.c
@@ -41,37 +41,28 @@
#include "timers.h"
#include "utils.h"
+#include "net_tcp.c"
+
const char *
proto_name(void)
{
return "BSD/TCP";
}
-const char *
-proto_usage_string(void)
-{
- return "[port]";
-}
-
int
proto_initialize(struct proto *proto, Var * desc, int argc, char **argv)
{
int port = DEFAULT_PORT;
- char *p;
-
- initialize_name_lookup();
proto->pocket_size = 1;
proto->believe_eof = 1;
proto->eol_out_string = "\r\n";
- if (argc > 1)
+ if (!tcp_arguments(argc, argv, &port))
return 0;
- else if (argc == 1) {
- port = strtoul(argv[0], &p, 10);
- if (*p != '\0')
- return 0;
- }
+
+ initialize_name_lookup();
+
desc->type = TYPE_INT;
desc->v.num = port;
return 1;
@@ -103,7 +94,7 @@ proto_make_listener(Var desc, int *fd, Var * canon, const char **name)
return E_QUOTA;
}
address.sin_family = AF_INET;
- address.sin_addr.s_addr = htonl(INADDR_ANY);
+ address.sin_addr.s_addr = bind_local_ip;
address.sin_port = htons(port);
if (bind(s, (struct sockaddr *) &address, sizeof(address)) < 0) {
enum error e = E_QUOTA;
@@ -213,6 +204,9 @@ proto_open_connection(Var arglist, int *read_fd, int *write_fd,
static struct sockaddr_in addr;
static Stream *st1 = 0, *st2 = 0;
+ if (!outbound_network_enabled)
+ return E_PERM;
+
if (!st1) {
st1 = new_stream(20);
st2 = new_stream(50);
@@ -238,18 +232,39 @@ proto_open_connection(Var arglist, int *read_fd, int *write_fd,
log_perror("Making socket in proto_open_connection");
return E_QUOTA;
}
- TRY
+
+ if (bind_local_ip != INADDR_ANY) {
+ static struct sockaddr_in local_addr;
+
+ local_addr.sin_family = AF_INET;
+ local_addr.sin_addr.s_addr = bind_local_ip;
+ local_addr.sin_port = 0;
+ /* In theory, if the original listen() succeeded,
+ * then this should too, but who knows, really? */
+ if (bind(s, (struct sockaddr *) &local_addr, sizeof(local_addr)) < 0) {
+ enum error e = E_QUOTA;
+
+ log_perror("Binding local address in proto_open_connection");
+ if (errno == EACCES)
+ e = E_PERM;
+ close(s);
+ return e;
+ }
+ }
+ TRY {
id = set_timer(server_int_option("outbound_connect_timeout", 5),
timeout_proc, 0);
- result = connect(s, (struct sockaddr *) &addr, sizeof(addr));
- cancel_timer(id);
- EXCEPT(timeout_exception)
+ result = connect(s, (struct sockaddr *) &addr, sizeof(addr));
+ cancel_timer(id);
+ }
+ EXCEPT(timeout_exception) {
result = -1;
- errno = ETIMEDOUT;
- reenable_timers();
- ENDTRY
+ errno = ETIMEDOUT;
+ reenable_timers();
+ }
+ ENDTRY;
- if (result < 0) {
+ if (result < 0) {
close(s);
if (errno == EADDRNOTAVAIL ||
errno == ECONNREFUSED ||
@@ -281,6 +296,15 @@ char rcsid_net_bsd_tcp[] = "$Id$";
/*
* $Log$
+ * Revision 1.3.8.1 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
+ * Revision 1.4 2004/05/22 01:25:43 wrog
+ * merging in WROGUE changes (W_SRCIP, W_STARTUP, W_OOB)
+ *
+ * Revision 1.3.10.1 2003/06/01 12:42:30 wrog
+ * added cmdline options -a (source address) +O/-O (enable/disable outbound network)
+ *
* Revision 1.3 1998/12/14 13:18:27 nop
* Merge UNSAFE_OPTS (ref fixups); fix Log tag placement to fit CVS whims
*
diff --git a/net_multi.c b/net_multi.c
index 7f3d570..8765ec8 100644
--- a/net_multi.c
+++ b/net_multi.c
@@ -274,6 +274,10 @@ pull_input(nhandle * h)
if (isgraph(c) || c == ' ' || c == '\t')
stream_add_char(s, c);
+#ifdef INPUT_APPLY_BACKSPACE
+ else if (c == 0x08 || c == 0x7F)
+ stream_delete_char(s);
+#endif
else if (c == '\r' || (c == '\n' && !h->last_input_was_CR))
server_receive_line(h->shandle, reset_stream(s));
@@ -618,44 +622,19 @@ network_set_connection_binary(network_handle nh, int do_binary)
h->binary = do_binary;
}
-Var
-network_connection_options(network_handle nh, Var list)
-{
-#if NETWORK_PROTOCOL == NP_TCP
- nhandle *h = nh.ptr;
- Var pair;
-
- pair = new_list(2);
- pair.v.list[1].type = TYPE_STR;
- pair.v.list[1].v.str = str_dup("client-echo");
- pair.v.list[2].type = TYPE_INT;
- pair.v.list[2].v.num = h->client_echo;
- list = listappend(list, pair);
-#endif
-
- return list;
-}
-
-int
-network_connection_option(network_handle nh, const char *option, Var * value)
-{
-#if NETWORK_PROTOCOL == NP_TCP
- nhandle *h = nh.ptr;
-
- if (!mystrcasecmp(option, "client-echo")) {
- value->type = TYPE_INT;
- value->v.num = h->client_echo;
- return 1;
- }
-#endif
+#if NETWORK_PROTOCOL == NP_LOCAL
+# define NETWORK_CO_TABLE(DEFINE, nh, value, _)
+ /* No network-specific connection options */
- return 0;
-}
+#elif NETWORK_PROTOCOL == NP_TCP
+# define NETWORK_CO_TABLE(DEFINE, nh, value, _) \
+ DEFINE(client-echo, _, TYPE_INT, num, \
+ ((nhandle *)nh.ptr)->client_echo, \
+ network_set_client_echo(nh, is_true(value));) \
-int
-network_set_connection_option(network_handle nh, const char *option, Var value)
+void
+network_set_client_echo(network_handle nh, int is_on)
{
-#if NETWORK_PROTOCOL == NP_TCP
nhandle *h = nh.ptr;
/* These values taken from RFC 854 and RFC 857. */
@@ -664,29 +643,28 @@ network_set_connection_option(network_handle nh, const char *option, Var value)
#define TN_WONT 252
#define TN_ECHO 1
- {
- static char telnet_cmd[4] =
+ static char telnet_cmd[4] =
{TN_IAC, 0, TN_ECHO, 0};
- if (!mystrcasecmp(option, "client-echo")) {
- h->client_echo = is_true(value);
- if (h->client_echo)
- telnet_cmd[1] = TN_WONT;
- else
- telnet_cmd[1] = TN_WILL;
- enqueue_output(nh, telnet_cmd, 3, 0, 1);
- return 1;
- }
- }
-#endif
-
- return 0;
+ h->client_echo = is_on;
+ if (is_on)
+ telnet_cmd[1] = TN_WONT;
+ else
+ telnet_cmd[1] = TN_WILL;
+ enqueue_output(nh, telnet_cmd, 3, 0, 1);
}
+#else /* NETWORK_PROTOCOL == NP_SINGLE */
+
+# error "NP_SINGLE ???"
+
+#endif /* NETWORK_PROTOCOL */
+
+
#ifdef OUTBOUND_NETWORK
enum error
-network_open_connection(Var arglist)
+network_open_connection(Var arglist, server_listener sl)
{
int rfd, wfd;
const char *local_name, *remote_name;
@@ -694,7 +672,7 @@ network_open_connection(Var arglist)
e = proto_open_connection(arglist, &rfd, &wfd, &local_name, &remote_name);
if (e == E_NONE)
- make_new_connection(null_server_listener, rfd, wfd,
+ make_new_connection(sl, rfd, wfd,
local_name, remote_name, 1);
return e;
@@ -726,6 +704,21 @@ char rcsid_net_multi[] = "$Id$";
/*
* $Log$
+ * Revision 1.3.8.1 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
+ * Revision 1.6 2006/12/06 23:57:51 wrog
+ * New INPUT_APPLY_BACKSPACE option to process backspace/delete characters on nonbinary connections (patch 1571939)
+ *
+ * Revision 1.5 2005/09/29 18:46:17 bjj
+ * Add third argument to open_network_connection() that associates a specific listener object with the new connection. This simplifies a lot of outbound connection management.
+ *
+ * Revision 1.4 2004/05/22 01:25:43 wrog
+ * merging in WROGUE changes (W_SRCIP, W_STARTUP, W_OOB)
+ *
+ * Revision 1.3.10.1 2003/06/07 12:59:04 wrog
+ * introduced connection_option macros
+ *
* Revision 1.3 1998/12/14 13:18:31 nop
* Merge UNSAFE_OPTS (ref fixups); fix Log tag placement to fit CVS whims
*
diff --git a/net_single.c b/net_single.c
index 9e20593..499fac1 100644
--- a/net_single.c
+++ b/net_single.c
@@ -116,23 +116,9 @@ network_set_connection_binary(network_handle nh, int do_binary)
binary = do_binary;
}
-Var
-network_connection_options(network_handle nh, Var list)
-{
- return list;
-}
+#define NETWORK_CO_TABLE(DEFINE, nh, value, _)
+ /* No network-specific connection options */
-int
-network_connection_option(network_handle nh, const char *option, Var * value)
-{
- return 0;
-}
-
-int
-network_set_connection_option(network_handle nh, const char *option, Var value)
-{
- return 0;
-}
void
network_close(network_handle nh)
@@ -218,6 +204,10 @@ network_process_io(int timeout)
if (isgraph(c) || c == ' ' || c == '\t')
stream_add_char(s, c);
+#ifdef INPUT_APPLY_BACKSPACE
+ else if (c == 0x08 || c == 0x7F)
+ stream_delete_char(s);
+#endif
else if (c == '\n')
server_receive_line(sh, reset_stream(s));
}
@@ -237,10 +227,26 @@ network_process_io(int timeout)
char rcsid_net_single[] = "$Id$";
-/* $Log$
-/* Revision 1.2 1997/03/03 04:19:07 nop
-/* GNU Indent normalization
/*
+ * $Log$
+ * Revision 1.2.10.1 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
+ * Revision 1.4 2006/12/06 23:57:51 wrog
+ * New INPUT_APPLY_BACKSPACE option to process backspace/delete characters on nonbinary connections (patch 1571939)
+ *
+ * Revision 1.3 2004/05/22 01:25:44 wrog
+ * merging in WROGUE changes (W_SRCIP, W_STARTUP, W_OOB)
+ *
+ * Revision 1.2.12.2 2003/06/07 13:03:55 wrog
+ * deslashed log entries
+ *
+ * Revision 1.2.12.1 2003/06/07 12:59:04 wrog
+ * introduced connection_option macros
+ *
+ * Revision 1.2 1997/03/03 04:19:07 nop
+ * GNU Indent normalization
+ *
* Revision 1.1.1.1 1997/03/03 03:45:02 nop
* LambdaMOO 1.8.0p5
*
diff --git a/net_sysv_tcp.c b/net_sysv_tcp.c
index d6375d2..4881529 100644
--- a/net_sysv_tcp.c
+++ b/net_sysv_tcp.c
@@ -55,6 +55,8 @@
#include "structures.h"
#include "timers.h"
+#include "net_tcp.c"
+
static struct t_call *call = 0;
static void
@@ -72,31 +74,20 @@ proto_name(void)
return "SysV/TCP";
}
-const char *
-proto_usage_string(void)
-{
- return "[port]";
-}
-
int
proto_initialize(struct proto *proto, Var * desc, int argc, char **argv)
{
int port = DEFAULT_PORT;
- char *p;
-
- initialize_name_lookup();
proto->pocket_size = 1;
proto->believe_eof = 1;
proto->eol_out_string = "\r\n";
- if (argc > 1)
+ if (!tcp_arguments(argc, argv, &port))
return 0;
- else if (argc == 1) {
- port = strtoul(argv[0], &p, 10);
- if (*p != '\0')
- return 0;
- }
+
+ initialize_name_lookup();
+
desc->type = TYPE_INT;
desc->v.num = port;
return 1;
@@ -123,7 +114,7 @@ proto_make_listener(Var desc, int *fd, Var * canon, const char **name)
return E_QUOTA;
}
req_addr.sin_family = AF_INET;
- req_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ req_addr.sin_addr.s_addr = bind_local_ip;
req_addr.sin_port = htons(port);
requested.addr.maxlen = sizeof(req_addr);
@@ -143,7 +134,7 @@ proto_make_listener(Var desc, int *fd, Var * canon, const char **name)
if (t_errno == TACCES || (t_errno == TSYSERR && errno == EACCES))
e = E_PERM;
return e;
- } else if (port != 0 && rec_addr.sin_port != port) {
+ } else if (port != 0 && rec_addr.sin_port != htons(port)) {
errlog("Can't bind to requested port!\n");
t_close(s);
return E_QUOTA;
@@ -268,8 +259,8 @@ proto_open_connection(Var arglist, int *read_fd, int *write_fd,
* getting all those nasty little parameter-passing rules right. This
* function isn't recursive anyway, so it doesn't matter.
*/
- struct sockaddr_in rec_addr;
- struct t_bind received;
+ struct sockaddr_in rec_addr, req_addr;
+ struct t_bind received, requested, *p_requested;
static const char *host_name;
static int port;
static Timer_ID id;
@@ -278,6 +269,9 @@ proto_open_connection(Var arglist, int *read_fd, int *write_fd,
static struct sockaddr_in addr;
static Stream *st1 = 0, *st2 = 0;
+ if (!outbound_network_enabled)
+ return E_PERM;
+
if (!st1) {
st1 = new_stream(20);
st2 = new_stream(50);
@@ -304,11 +298,26 @@ proto_open_connection(Var arglist, int *read_fd, int *write_fd,
log_ti_error("Making endpoint in proto_open_connection");
return E_QUOTA;
}
+
+ if (bind_local_ip == INADDR_ANY) {
+ p_requested = 0;
+ }
+ else {
+ req_addr.sin_family = AF_INET;
+ req_addr.sin_addr.s_addr = bind_local_ip;
+ req_addr.sin_port = 0;
+
+ requested.addr.maxlen = sizeof(req_addr);
+ requested.addr.len = sizeof(req_addr);
+ requested.addr.buf = (void *) &req_addr;
+ p_requested = &requested;
+ }
+
received.addr.maxlen = sizeof(rec_addr);
received.addr.len = sizeof(rec_addr);
received.addr.buf = (void *) &rec_addr;
- if (t_bind(fd, 0, &received) < 0) {
+ if (t_bind(fd, p_requested, &received) < 0) {
log_ti_error("Binding outbound endpoint");
t_close(fd);
return E_QUOTA;
@@ -317,19 +326,21 @@ proto_open_connection(Var arglist, int *read_fd, int *write_fd,
call->addr.len = sizeof(addr);
call->addr.buf = (void *) &addr;
- TRY
+ TRY {
id = set_timer(server_int_option("outbound_connect_timeout", 5),
timeout_proc, 0);
- result = t_connect(fd, call, 0);
- cancel_timer(id);
- EXCEPT(timeout_exception)
+ result = t_connect(fd, call, 0);
+ cancel_timer(id);
+ }
+ EXCEPT(timeout_exception) {
result = -1;
- errno = ETIMEDOUT;
- t_errno = TSYSERR;
- reenable_timers();
- ENDTRY
+ errno = ETIMEDOUT;
+ t_errno = TSYSERR;
+ reenable_timers();
+ }
+ ENDTRY;
- if (result < 0) {
+ if (result < 0) {
t_close(fd);
log_ti_error("Connecting in proto_open_connection");
return E_QUOTA;
@@ -352,10 +363,23 @@ proto_open_connection(Var arglist, int *read_fd, int *write_fd,
char rcsid_net_sysv_tcp[] = "$Id$";
-/* $Log$
-/* Revision 1.2 1997/03/03 04:19:09 nop
-/* GNU Indent normalization
/*
+ * $Log$
+ * Revision 1.2.10.1 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
+ * Revision 1.3 2004/05/22 01:25:44 wrog
+ * merging in WROGUE changes (W_SRCIP, W_STARTUP, W_OOB)
+ *
+ * Revision 1.2.12.2 2003/06/01 13:15:18 wrog
+ * Fixed log / comment braindeath
+ *
+ * Revision 1.2.12.1 2003/06/01 12:42:30 wrog
+ * added cmdline options -a (source address) +O/-O (enable/disable outbound network)
+ *
+ * Revision 1.2 1997/03/03 04:19:09 nop
+ * GNU Indent normalization
+ *
* Revision 1.1.1.1 1997/03/03 03:45:02 nop
* LambdaMOO 1.8.0p5
*
diff --git a/net_tcp.c b/net_tcp.c
new file mode 100644
index 0000000..069391d
--- /dev/null
+++ b/net_tcp.c
@@ -0,0 +1,92 @@
+/************
+ * net_tcp.c
+ *
+ * common code for
+ * multi-user networking protocol implementations for TCP/IP
+ * (net_bsd_tcp.c and net_sysv_tcp.c)
+ *
+ */
+
+#ifdef OUTBOUND_NETWORK
+static char outbound_network_enabled = OUTBOUND_NETWORK;
+#endif
+
+static in_addr_t bind_local_ip = INADDR_ANY;
+
+const char *
+proto_usage_string(void)
+{
+ return "[+O|-O] [-a ip_address] [[-p] port]";
+}
+
+
+static int
+tcp_arguments(int argc, char **argv, int *pport)
+{
+ char *p = 0;
+
+ for ( ; argc > 0; argc--, argv++) {
+ if (argc > 0
+ && (argv[0][0] == '-' || argv[0][0] == '+')
+ && argv[0][1] == 'O'
+ && argv[0][2] == 0
+ ) {
+#ifdef OUTBOUND_NETWORK
+ outbound_network_enabled = (argv[0][0] == '+');
+#else
+ if (argv[0][0] == '+') {
+ fprintf(stderr, "Outbound network not supported.\n");
+ oklog("CMDLINE: *** Ignoring %s (outbound network not supported)\n", argv[0]);
+ }
+#endif
+ }
+ else if (0 == strcmp(argv[0],"-a")) {
+ if (argc <= 1)
+ return 0;
+ argc--;
+ argv++;
+ bind_local_ip = inet_addr(argv[0]);
+ if (bind_local_ip == INADDR_NONE)
+ return 0;
+ oklog("CMDLINE: Source address restricted to %s\n", argv[0]);
+ }
+ else {
+ if (p != 0) /* strtoul always sets p */
+ return 0;
+ if (0 == strcmp(argv[0],"-p")) {
+ if (argc <= 1)
+ return 0;
+ argc--;
+ argv++;
+ }
+ *pport = strtoul(argv[0], &p, 10);
+ if (*p != '\0')
+ return 0;
+ oklog("CMDLINE: Initial port = %d\n", *pport);
+ }
+ }
+#ifdef OUTBOUND_NETWORK
+ oklog("CMDLINE: Outbound network connections %s.\n",
+ outbound_network_enabled ? "enabled" : "disabled");
+#endif
+ return 1;
+}
+
+char rcsid_net_tcp[] = "$Id$";
+
+/*
+ * $Log$
+ * Revision 1.2.6.2 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
+ * Revision 1.2 2004/05/22 01:25:44 wrog
+ * merging in WROGUE changes (W_SRCIP, W_STARTUP, W_OOB)
+ *
+ * Revision 1.1.2.2 2003/06/10 00:14:52 wrog
+ * fixed printf warning
+ *
+ * Revision 1.1.2.1 2003/06/01 12:42:30 wrog
+ * added cmdline options -a (source address) +O/-O (enable/disable outbound network)
+ *
+ *
+ */
diff --git a/network.c b/network.c
index dab4abf..26c2348 100644
--- a/network.c
+++ b/network.c
@@ -23,8 +23,36 @@
# include "net_multi.c"
#endif
+Var
+network_connection_options(network_handle nh, Var list)
+{
+ CONNECTION_OPTION_LIST(NETWORK_CO_TABLE, nh, list);
+}
+
+int
+network_connection_option(network_handle nh, const char *option, Var * value)
+{
+ CONNECTION_OPTION_GET(NETWORK_CO_TABLE, nh, option, value);
+}
+
+int
+network_set_connection_option(network_handle nh, const char *option, Var value)
+{
+ CONNECTION_OPTION_SET(NETWORK_CO_TABLE, nh, option, value);
+}
+
+
/*
* $Log$
+ * Revision 1.2.8.1 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
+ * Revision 1.3 2004/05/22 01:25:44 wrog
+ * merging in WROGUE changes (W_SRCIP, W_STARTUP, W_OOB)
+ *
+ * Revision 1.2.10.1 2003/06/07 12:59:04 wrog
+ * introduced connection_option macros
+ *
* Revision 1.2 1998/12/14 13:18:35 nop
* Merge UNSAFE_OPTS (ref fixups); fix Log tag placement to fit CVS whims
*
diff --git a/network.h b/network.h
index 3a2660c..8ee83cb 100644
--- a/network.h
+++ b/network.h
@@ -191,7 +191,7 @@ extern int network_set_connection_option(network_handle nh,
#ifdef OUTBOUND_NETWORK
#include "structures.h"
-extern enum error network_open_connection(Var arglist);
+extern enum error network_open_connection(Var arglist, server_listener sl);
/* The given MOO arguments should be used as a
* specification of a remote network connection
* to be made. If the arguments are OK and the
@@ -246,6 +246,12 @@ extern void network_shutdown(void);
/*
* $Log$
+ * Revision 1.3.8.1 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
+ * Revision 1.4 2005/09/29 18:46:18 bjj
+ * Add third argument to open_network_connection() that associates a specific listener object with the new connection. This simplifies a lot of outbound connection management.
+ *
* Revision 1.3 1998/12/14 13:18:36 nop
* Merge UNSAFE_OPTS (ref fixups); fix Log tag placement to fit CVS whims
*
diff --git a/options.h b/options.h
index 9a74658..dd89865 100644
--- a/options.h
+++ b/options.h
@@ -53,6 +53,17 @@
#define OUT_OF_BAND_PREFIX "#$#"
/******************************************************************************
+ * If OUT_OF_BAND_QUOTE_PREFIX is defined as a non-empty string, then any
+ * lines of input from any player that begin with that prefix will be
+ * stripped of that prefix and processed normally (whether to be parsed a
+ * command or given to a pending read()ing task), even if the resulting line
+ * begins with OUT_OF_BAND_PREFIX. This provides a means of quoting lines
+ * that would otherwise spawn #0:do_out_of_band_command tasks
+ */
+
+#define OUT_OF_BAND_QUOTE_PREFIX "#$\""
+
+/******************************************************************************
* The following constants define the execution limits placed on all MOO tasks.
*
* DEFAULT_MAX_STACK_DEPTH is the default maximum depth allowed for the MOO
@@ -143,19 +154,31 @@
/* #define MPLEX_STYLE MP_POLL */
/******************************************************************************
- * Define OUTBOUND_NETWORK to enable the built-in MOO function
- * open_network_connection(), which allows (only) wizard-owned MOO code to make
- * outbound network connections from the server.
+ * The built-in MOO function open_network_connection(), when enabled,
+ * allows (only) wizard-owned MOO code to make outbound network connections
+ * from the server. When disabled, it raises E_PERM whenever called.
+ *
+ * The +O and -O command line options can explicitly enable and disable this
+ * function. If neither option is supplied, the definition given to
+ * OUTBOUND_NETWORK here determines the default behavior
+ * (use 0 to disable by default, 1 or blank to enable by default).
+ *
+ * If OUTBOUND_NETWORK is not defined at all,
+ * open_network_connection() is permanently disabled and +O is ignored.
+ *
* *** THINK VERY HARD BEFORE ENABLING THIS FUNCTION ***
- * In some contexts, this could represent a serious breach of security. By
- * default, the open_network_connection() function is disabled, always raising
- * E_PERM when called.
+ * In some contexts, this could represent a serious breach of security.
*
* Note: OUTBOUND_NETWORK may not be defined if NETWORK_PROTOCOL is either
* NP_SINGLE or NP_LOCAL.
*/
-/* #define OUTBOUND_NETWORK */
+/* disable by default, +O enables: */
+/* #define OUTBOUND_NETWORK 0 */
+
+/* enable by default, -O disables: */
+/* #define OUTBOUND_NETWORK 1 */
+
/******************************************************************************
* The following constants define certain aspects of the server's network
@@ -184,6 +207,15 @@
#define DEFAULT_CONNECT_TIMEOUT 300
/******************************************************************************
+ * On connections that have not been set to binary mode, the server normally
+ * discards incoming characters that are not printable ASCII, including
+ * backspace (8) and delete(127). If INPUT_APPLY_BACKSPACE is defined,
+ * backspace and delete cause the preceding character (if any) to be removed
+ * from the input stream. (Comment this out to restore pre-1.8.3 behavior)
+ */
+#define INPUT_APPLY_BACKSPACE
+
+/******************************************************************************
* The server maintains a cache of the most recently used patterns from calls
* to the match() and rmatch() built-in functions. PATTERN_CACHE_SIZE controls
* how many past patterns are remembered by the server. Do not set it to a
@@ -251,6 +283,13 @@
#define STRING_INTERNING /* */
/******************************************************************************
+ * Store the length of the string WITH the string rather than recomputing
+ * it each time it is needed.
+ ******************************************************************************
+ */
+/* #define MEMO_STRLEN */
+
+/******************************************************************************
* This package comes with a copy of the implementation of malloc() from GNU
* Emacs. This is a very nice and reasonably portable implementation, but some
* systems, notably the NeXT machine, won't allow programs to provide their own
@@ -277,6 +316,9 @@
#ifndef OUT_OF_BAND_PREFIX
#define OUT_OF_BAND_PREFIX ""
#endif
+#ifndef OUT_OF_BAND_QUOTE_PREFIX
+#define OUT_OF_BAND_QUOTE_PREFIX ""
+#endif
#if PATTERN_CACHE_SIZE < 1
# error Illegal match() pattern cache size!
@@ -331,6 +373,14 @@
# error You cannot define "OUTBOUND_NETWORK" with that "NETWORK_PROTOCOL"
#endif
+/* make sure OUTBOUND_NETWORK has a value;
+ for backward compatibility, use 1 if none given */
+#if defined(OUTBOUND_NETWORK) && (( 0 * OUTBOUND_NETWORK - 1 ) == 0)
+#undef OUTBOUND_NETWORK
+#define OUTBOUND_NETWORK 1
+#endif
+
+
#if NETWORK_PROTOCOL != NP_LOCAL && NETWORK_PROTOCOL != NP_SINGLE && NETWORK_PROTOCOL != NP_TCP
# error Illegal value for "NETWORK_PROTOCOL"
#endif
@@ -350,6 +400,31 @@
/*
* $Log$
+ * Revision 1.8.8.1 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
+ * Revision 1.11 2006/12/06 23:57:51 wrog
+ * New INPUT_APPLY_BACKSPACE option to process backspace/delete characters on nonbinary connections (patch 1571939)
+ *
+ * Revision 1.10 2006/09/07 00:55:02 bjj
+ * Add new MEMO_STRLEN option which uses the refcounting mechanism to
+ * store strlen with strings. This is basically free, since most string
+ * allocations are rounded up by malloc anyway. This saves lots of cycles
+ * computing strlen. (The change is originally from jitmoo, where I wanted
+ * inline range checks for string ops).
+ *
+ * Revision 1.9 2004/05/22 01:25:44 wrog
+ * merging in WROGUE changes (W_SRCIP, W_STARTUP, W_OOB)
+ *
+ * Revision 1.8.10.3 2004/05/21 00:02:59 wrog
+ * allow for OUT_OF_BAND_QUOTE_PREFIX being undefined
+ *
+ * Revision 1.8.10.2 2003/06/11 10:36:45 wrog
+ * added OUT_OF_BAND_QUOTE_PREFIX
+ *
+ * Revision 1.8.10.1 2003/06/01 12:42:30 wrog
+ * added cmdline options -a (source address) +O/-O (enable/disable outbound network)
+ *
* Revision 1.8 2001/01/29 09:08:40 bjj
* Made STRING_INTERNING optional via options.h.
*
diff --git a/parser.y b/parser.y
index 3bbd0cc..aa9a870 100644
--- a/parser.y
+++ b/parser.y
@@ -1366,6 +1366,9 @@ char rcsid_parser[] = "$Id$";
/*
* $Log$
+ * Revision 1.2.6.4.2.2 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
* Revision 1.2.6.4.2.1 2002/11/03 03:37:58 xplat
* Initial support for keeping type constants in a global constants table
* rather than every stack frame.
@@ -1382,6 +1385,13 @@ char rcsid_parser[] = "$Id$";
* Revision 1.2.6.1 2002/09/12 05:57:40 xplat
* Changes for inline PC saving and patch tags in the on-disk DB.
*
+ * Revision 1.4 2004/05/22 01:25:44 wrog
+ * merging in WROGUE changes (W_SRCIP, W_STARTUP, W_OOB)
+ *
+ * Revision 1.3 2004/04/09 19:52:52 bjj
+ * == Revision 1.2.8.1 2003/06/07 20:16:24 wrog
+ * fixed 6 rules that were missing final semicolons to make newer bison happy.
+ *
* Revision 1.2 1998/12/14 13:18:45 nop
* Merge UNSAFE_OPTS (ref fixups); fix Log tag placement to fit CVS whims
*
diff --git a/program.c b/program.c
index d3d752f..e168dc9 100644
--- a/program.c
+++ b/program.c
@@ -78,7 +78,7 @@ program_bytes(Program * p)
count += sizeof(const char *) * p->num_var_names;
for (i = 0; i < p->num_var_names; i++)
- count += strlen(p->var_names[i]) + 1;
+ count += memo_strlen(p->var_names[i]) + 1;
return count;
}
@@ -116,6 +116,16 @@ char rcsid_program[] = "$Id$";
/*
* $Log$
+ * Revision 1.5.8.1 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
+ * Revision 1.6 2006/09/07 00:55:02 bjj
+ * Add new MEMO_STRLEN option which uses the refcounting mechanism to
+ * store strlen with strings. This is basically free, since most string
+ * allocations are rounded up by malloc anyway. This saves lots of cycles
+ * computing strlen. (The change is originally from jitmoo, where I wanted
+ * inline range checks for string ops).
+ *
* Revision 1.5 1998/12/14 13:18:48 nop
* Merge UNSAFE_OPTS (ref fixups); fix Log tag placement to fit CVS whims
*
diff --git a/server.c b/server.c
index 1ad5ab2..083bd60 100644
--- a/server.c
+++ b/server.c
@@ -89,8 +89,7 @@ typedef struct slistener {
static slistener *all_slisteners = 0;
-server_listener null_server_listener =
-{0};
+server_listener null_server_listener = {0};
static void
free_shandle(shandle * h)
@@ -414,7 +413,7 @@ send_message(Objid listener, network_handle nh, const char *msg_name,...)
}
} else /* Use default message */
while ((line = va_arg(args, const char *)) != 0)
- network_send_line(nh, line, 1);
+ network_send_line(nh, line, 1);
va_end(args);
}
@@ -486,18 +485,18 @@ main_loop(void)
nexth = h->next;
if (!h->outbound && h->connection_time == 0
- && (get_server_option(h->listener, "connect_timeout", &v)
- ? (v.type == TYPE_INT && v.v.num > 0
- && now - h->last_activity_time > v.v.num)
- : (now - h->last_activity_time
- > DEFAULT_CONNECT_TIMEOUT))) {
+ && (get_server_option(h->listener, "connect_timeout", &v)
+ ? (v.type == TYPE_INT && v.v.num > 0
+ && now - h->last_activity_time > v.v.num)
+ : (now - h->last_activity_time
+ > DEFAULT_CONNECT_TIMEOUT))) {
call_notifier(h->player, h->listener, "user_disconnected");
oklog("TIMEOUT: #%d on %s\n",
h->player,
network_connection_name(h->nhandle));
if (h->print_messages)
send_message(h->listener, h->nhandle, "timeout_msg",
- "*** Timed-out waiting for login. ***",
+ "*** Timed-out waiting for login. ***",
0);
network_close(h->nhandle);
free_shandle(h);
@@ -507,7 +506,7 @@ main_loop(void)
network_connection_name(h->nhandle));
if (h->print_messages)
send_message(h->listener, h->nhandle,
- "recycle_msg", "*** Recycled ***", 0);
+ "recycle_msg", "*** Recycled ***", 0);
network_close(h->nhandle);
free_shandle(h);
} else if (h->disconnect_me) {
@@ -560,42 +559,34 @@ init_cmdline(int argc, char *argv[])
cmdline_buflen = p - argv[0];
}
+#define SERVER_CO_TABLE(DEFINE, H, VALUE, _) \
+ DEFINE(binary, _, TYPE_INT, num, \
+ H->binary, \
+ { \
+ H->binary = is_true(VALUE); \
+ network_set_connection_binary(H->nhandle, H->binary); \
+ }) \
+
static int
server_set_connection_option(shandle * h, const char *option, Var value)
{
- if (!mystrcasecmp(option, "binary")) {
- h->binary = is_true(value);
- network_set_connection_binary(h->nhandle, h->binary);
- return 1;
- }
- return 0;
+ CONNECTION_OPTION_SET(SERVER_CO_TABLE, h, option, value);
}
static int
server_connection_option(shandle * h, const char *option, Var * value)
{
- if (!mystrcasecmp(option, "binary")) {
- value->type = TYPE_INT;
- value->v.num = h->binary;
- return 1;
- }
- return 0;
+ CONNECTION_OPTION_GET(SERVER_CO_TABLE, h, option, value);
}
static Var
server_connection_options(shandle * h, Var list)
{
- Var pair;
-
- pair = new_list(2);
- pair.v.list[1].type = TYPE_STR;
- pair.v.list[1].v.str = str_dup("binary");
- pair.v.list[2].type = TYPE_INT;
- pair.v.list[2].v.num = h->binary;
-
- return listappend(list, pair);
+ CONNECTION_OPTION_LIST(SERVER_CO_TABLE, h, list);
}
+#undef SERVER_CO_TABLE
+
static char *
read_stdin_line()
{
@@ -603,6 +594,7 @@ read_stdin_line()
char *line, buffer[1000];
int buflen;
+ fflush(stdout);
if (!s)
s = new_stream(100);
@@ -820,6 +812,7 @@ emergency_mode()
else
printf("%s\n", message);
} else if (!mystrcasecmp(command, "abort") && nargs == 0) {
+ printf("Bye. (%s)\n\n", "NOT saving database");
exit(1);
} else if (!mystrcasecmp(command, "quit") && nargs == 0) {
start_ok = 0;
@@ -828,7 +821,7 @@ emergency_mode()
} else if (!mystrcasecmp(command, "debug") && nargs == 0) {
debug = !debug;
} else if (!mystrcasecmp(command, "wizard") && nargs == 1
- && sscanf(words.v.list[2].v.str, "#%d", &wizard) == 1) {
+ && sscanf(words.v.list[2].v.str, "#%d", &wizard) == 1) {
printf("** Switching to wizard #%d...\n", wizard);
} else {
if (mystrcasecmp(command, "help")
@@ -871,6 +864,11 @@ emergency_mode()
}
}
+ printf("Bye. (%s)\n\n", start_ok ? "continuing" : "saving database");
+#if NETWORK_PROTOCOL != NP_SINGLE
+ fclose(stdout);
+#endif
+
free_stream(s);
in_emergency_mode = 0;
oklog("EMERGENCY_MODE: Leaving mode; %s continue...\n",
@@ -958,15 +956,23 @@ server_new_connection(server_listener sl, network_handle nh, int outbound)
h->connection_time = 0;
h->last_activity_time = time(0);
h->player = next_unconnected_player--;
- h->listener = outbound ? SYSTEM_OBJECT : l->oid;
+ h->listener = l ? l->oid : SYSTEM_OBJECT;
h->tasks = new_task_queue(h->player, h->listener);
h->disconnect_me = 0;
h->outbound = outbound;
h->binary = 0;
- h->print_messages = (!outbound && l->print_messages);
-
- if (!outbound)
- new_input_task(h->tasks, "");
+ h->print_messages = l ? l->print_messages : !outbound;
+
+ if (l || !outbound) {
+ new_input_task(h->tasks, "", 0);
+ /*
+ * Suspend input at the network level until the above input task
+ * is processed. At the point when it is dequeued, tasks.c will
+ * notice that the queued input size is below the low water mark
+ * and resume input.
+ */
+ task_suspend_input(h->tasks);
+ }
oklog("%s: #%d on %s\n",
outbound ? "CONNECT" : "ACCEPT",
@@ -997,7 +1003,7 @@ server_receive_line(server_handle sh, const char *line)
shandle *h = (shandle *) sh.ptr;
h->last_activity_time = time(0);
- new_input_task(h->tasks, line);
+ new_input_task(h->tasks, line, h->binary);
}
void
@@ -1058,9 +1064,8 @@ player_connected(Objid old_id, Objid new_id, int is_newly_created)
"*** Redirecting connection to new port ***", 0);
if (new_h->print_messages)
send_message(new_h->listener, new_h->nhandle, "redirect_to_msg",
- "*** Redirecting old connection to this port ***", 0);
+ "*** Redirecting old connection to this port ***", 0);
network_close(existing_h->nhandle);
- free_shandle(existing_h);
if (existing_h->listener == new_h->listener)
call_notifier(new_id, new_h->listener, "user_reconnected");
else {
@@ -1068,6 +1073,7 @@ player_connected(Objid old_id, Objid new_id, int is_newly_created)
"user_client_disconnected");
call_notifier(new_id, new_h->listener, "user_connected");
}
+ free_shandle(existing_h);
} else {
oklog("%s: %s on %s\n",
is_newly_created ? "CREATED" : "CONNECTED",
@@ -1082,7 +1088,7 @@ player_connected(Objid old_id, Objid new_id, int is_newly_created)
"*** Connected ***", 0);
}
call_notifier(new_id, new_h->listener,
- is_newly_created ? "user_created" : "user_connected");
+ is_newly_created ? "user_created" : "user_connected");
}
}
@@ -1219,6 +1225,13 @@ main(int argc, char **argv)
this_program, db_usage_string(), network_usage_string());
exit(1);
}
+#if NETWORK_PROTOCOL != NP_SINGLE
+ if (!emergency)
+ fclose(stdout);
+#endif
+ if (log_file)
+ fclose(stderr);
+
oklog("STARTING: Version %s of the LambdaMOO server\n", server_version);
oklog(" (Using %s protocol)\n", network_protocol_name());
oklog(" (Task timeouts measured in %s seconds.)\n",
@@ -1359,6 +1372,20 @@ bf_db_disk_size(Var arglist, Byte next, void *vdata, Objid progr)
return make_var_pack(v);
}
+#ifdef OUTBOUND_NETWORK
+static slistener *
+find_slistener_by_oid(Objid obj)
+{
+ slistener *l;
+
+ for (l = all_slisteners; l; l = l->next)
+ if (l->oid == obj)
+ return l;
+
+ return 0;
+}
+#endif /* OUTBOUND_NETWORK */
+
static package
bf_open_network_connection(Var arglist, Byte next, void *vdata, Objid progr)
{
@@ -1366,12 +1393,37 @@ bf_open_network_connection(Var arglist, Byte next, void *vdata, Objid progr)
Var r;
enum error e;
+ server_listener sl;
+ slistener l;
if (!is_wizard(progr)) {
free_var(arglist);
return make_error_pack(E_PERM);
}
- e = network_open_connection(arglist);
+
+ if (arglist.v.list[0].v.num == 3) {
+ Objid oid;
+
+ if (arglist.v.list[3].type != TYPE_OBJ) {
+ return make_error_pack(E_TYPE);
+ }
+ oid = arglist.v.list[3].v.obj;
+ arglist = listdelete(arglist, 3);
+
+ sl.ptr = find_slistener_by_oid(oid);
+ if (!sl.ptr) {
+ /* Create a temporary */
+ l.print_messages = 0;
+ l.name = "open_network_connection";
+ l.desc = zero;
+ l.oid = oid;
+ sl.ptr = &l;
+ }
+ } else {
+ sl.ptr = NULL;
+ }
+
+ e = network_open_connection(arglist, sl);
free_var(arglist);
if (e == E_NONE) {
/* The connection was successfully opened, implying that
@@ -1554,7 +1606,7 @@ bf_set_connection_option(Var arglist, Byte next, void *vdata, Objid progr)
else if (!h || h->disconnect_me
|| (!server_set_connection_option(h, option, value)
&& !tasks_set_connection_option(h->tasks, option, value)
- && !network_set_connection_option(h->nhandle, option, value)))
+ && !network_set_connection_option(h->nhandle, option, value)))
e = E_INVARG;
free_var(arglist);
@@ -1690,7 +1742,7 @@ bf_buffered_output_length(Var arglist, Byte next, void *vdata, Objid progr)
if (nargs == 0)
r.v.num = MAX_QUEUED_OUTPUT;
else {
- shandle *h = find_shandle(arglist.v.list[1].v.obj);
+ shandle *h = find_shandle(conn);
if (!h)
return make_error_pack(E_INVARG);
@@ -1740,6 +1792,9 @@ char rcsid_server[] = "$Id$";
/*
* $Log$
+ * Revision 1.5.8.3 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
* Revision 1.5.8.2 2002/11/03 03:42:35 xplat
* GNU indent normalization.
*
@@ -1747,6 +1802,36 @@ char rcsid_server[] = "$Id$";
* Initial support for keeping type constants in a global constants table
* rather than every stack frame.
*
+ * Revision 1.10 2006/11/21 18:42:37 pschwan
+ * b=1500775
+ * fixes two use-after-free bugs that could lead very rarely to
+ * calling the wrong functions during player connection
+ *
+ * Revision 1.9 2005/09/29 18:46:18 bjj
+ * Add third argument to open_network_connection() that associates a specific listener object with the new connection. This simplifies a lot of outbound connection management.
+ *
+ * Revision 1.8 2004/05/25 07:28:55 wrog
+ * indentation fixes
+ *
+ * Revision 1.7 2004/05/22 01:25:44 wrog
+ * merging in WROGUE changes (W_SRCIP, W_STARTUP, W_OOB)
+ *
+ * Revision 1.5.10.4 2004/05/21 23:02:56 wrog
+ * NP_SINGLE needs to have stdout stay open
+ *
+ * Revision 1.5.10.3 2004/05/20 19:57:11 wrog
+ * fixed flushing issues w.r.t. emergency mode;
+ * close stdout and stderr when we are not using them
+ *
+ * Revision 1.6 2003/06/12 18:16:56 bjj
+ * Suspend input on connection until :do_login_command() can run.
+ *
+ * Revision 1.5.10.2 2003/06/11 10:40:16 wrog
+ * added binary argument to new_input_task()
+ *
+ * Revision 1.5.10.1 2003/06/07 12:59:04 wrog
+ * introduced connection_option macros
+ *
* Revision 1.5 1998/12/29 06:56:32 nop
* Fixed leak in onc().
*
diff --git a/server.h b/server.h
index e21811f..6cec9d5 100644
--- a/server.h
+++ b/server.h
@@ -158,10 +158,100 @@ extern void boot_player(Objid player);
extern void write_active_connections(void);
extern int read_active_connections(void);
+
+
+/* Body for *_connection_option() */
+#define CONNECTION_OPTION_GET(TABLE,HANDLE,OPTION,VALUE) \
+ _STATEMENT({ \
+ TABLE(_CONNECT_OPTION_GET_SINGLE, (HANDLE), @, \
+ _RMPAREN2((OPTION),(VALUE))) \
+ return 0; \
+ })
+
+/* Body for *_set_connection_option() */
+#define CONNECTION_OPTION_SET(TABLE,HANDLE,OPTION,VALUE) \
+ _STATEMENT({ \
+ TABLE(_CONNECT_OPTION_SET_SINGLE, (HANDLE), (VALUE), \
+ _RMPAREN2((OPTION),(VALUE))) \
+ return 0; \
+ })
+
+/* Body for *_connection_options() */
+#define CONNECTION_OPTION_LIST(TABLE,HANDLE,LIST) \
+ _STATEMENT({ \
+ TABLE(_CONNECT_OPTION_LIST_SINGLE, (HANDLE), @, \
+ (LIST)) \
+ return (LIST); \
+ })
+
+/* All of the above require a TABLE of connection options #defined
+ * as follows
+ *
+ * #define TABLE(DEFINE, HANDLE, VALUE, _)
+ * DEFINE(<name>, _, TYPE_<foo>, <member>,
+ * <get-value-expression>,
+ * <set-value-statement>)
+ * ...
+ *
+ * where
+ * <get-value-expression>
+ * should extract from HANDLE a value for option <name>
+ * of type suitable for assignment to Var.v.<member>
+ * <set-value-expression>
+ * should do whatever needs to be done to HANDLE
+ * to reflect the new VALUE
+ */
+
+/*
+ * Helper macros for CONNECTION_OPTION_(GET|SET|LIST)
+ * (nothing should need to invoke these directly):
+ */
+#define _RMPAREN2(ARG1,ARG2) ARG1,ARG2
+#define _STATEMENT(STMT) do STMT while (0)
+
+#define _CONNECT_OPTION_GET_SINGLE(NAME, OPTION, VALUE, \
+ TYPE_FOO, VFOO_MEMBER, \
+ GETVALUE, SETVALUE) \
+ if (!mystrcasecmp(OPTION, #NAME)) { \
+ VALUE->type = (TYPE_FOO); \
+ VALUE->v.VFOO_MEMBER = (GETVALUE); \
+ return 1; \
+ }
+
+#define _CONNECT_OPTION_SET_SINGLE(NAME, OPTION, VALUE, \
+ TYPE_FOO, VFOO_MEMBER, \
+ GETVALUE, SETVALUE) \
+ if (!mystrcasecmp(OPTION, #NAME)) { \
+ SETVALUE; \
+ return 1; \
+ }
+
+#define _CONNECT_OPTION_LIST_SINGLE(NAME, LIST, \
+ TYPE_FOO, VFOO_MEMBER, \
+ GETVALUE, SETVALUE) \
+ { \
+ Var pair = new_list(2); \
+ pair.v.list[1].type = TYPE_STR; \
+ pair.v.list[1].v.str = str_dup(#NAME); \
+ pair.v.list[2].type = (TYPE_FOO); \
+ pair.v.list[2].v.VFOO_MEMBER = (GETVALUE); \
+ LIST = listappend(LIST, pair); \
+ } \
+
+
#endif /* Server_H */
/*
* $Log$
+ * Revision 1.3.8.1 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
+ * Revision 1.4 2004/05/22 01:25:44 wrog
+ * merging in WROGUE changes (W_SRCIP, W_STARTUP, W_OOB)
+ *
+ * Revision 1.3.10.1 2003/06/07 12:59:04 wrog
+ * introduced connection_option macros
+ *
* Revision 1.3 1998/12/14 13:18:58 nop
* Merge UNSAFE_OPTS (ref fixups); fix Log tag placement to fit CVS whims
*
diff --git a/storage.c b/storage.c
index 0e051f4..f963a3e 100644
--- a/storage.c
+++ b/storage.c
@@ -43,7 +43,11 @@ refcount_overhead(Memory_Type type)
/* for systems with picky double alignment */
return MAX(sizeof(int), sizeof(double));
case M_STRING:
+#ifdef MEMO_STRLEN
+ return sizeof(int) + sizeof(int);
+#else
return sizeof(int);
+#endif /* MEMO_STRLEN */
case M_LIST:
/* for systems with picky pointer alignment */
return MAX(sizeof(int), sizeof(Var *));
@@ -82,6 +86,10 @@ mymalloc(unsigned size, Memory_Type type)
if (offs) {
memptr += offs;
((int *) memptr)[-1] = 1;
+#ifdef MEMO_STRLEN
+ if (type == M_STRING)
+ ((int *) memptr)[-2] = size - 1;
+#endif /* MEMO_STRLEN */
}
return memptr;
}
@@ -108,7 +116,7 @@ str_dup(const char *s)
addref(emptystring);
return emptystring;
} else {
- r = (char *) mymalloc(strlen(s) + 1, M_STRING);
+ r = (char *) mymalloc(strlen(s) + 1, M_STRING); /* NO MEMO HERE */
strcpy(r, s);
}
return r;
@@ -129,19 +137,18 @@ myrealloc(void *ptr, unsigned size, Memory_Type type)
alloc_real_size[type] -= malloc_real_size(ptr);
#endif
- ptr = realloc((char *) ptr - offs, size + offs);
- if (!ptr) {
- sprintf(msg, "memory re-allocation (size %u) failed!", size);
- panic(msg);
- }
-
+ ptr = realloc((char *) ptr - offs, size + offs);
+ if (!ptr) {
+ sprintf(msg, "memory re-allocation (size %u) failed!", size);
+ panic(msg);
+ }
#ifdef USE_GNU_MALLOC
alloc_size[type] += malloc_size(ptr);
alloc_real_size[type] += malloc_real_size(ptr);
}
#endif
- return (char *)ptr + offs;
+ return (char *) ptr + offs;
}
void
@@ -179,6 +186,7 @@ free_str(const char *s)
if (delref(s) == 0)
myfree((void *) s, M_STRING);
}
+
#endif
Var
@@ -225,6 +233,16 @@ char rcsid_storage[] = "$Id$";
/*
* $Log$
+ * Revision 1.5.8.1 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
+ * Revision 1.6 2006/09/07 00:55:02 bjj
+ * Add new MEMO_STRLEN option which uses the refcounting mechanism to
+ * store strlen with strings. This is basically free, since most string
+ * allocations are rounded up by malloc anyway. This saves lots of cycles
+ * computing strlen. (The change is originally from jitmoo, where I wanted
+ * inline range checks for string ops).
+ *
* Revision 1.5 1998/12/14 13:18:59 nop
* Merge UNSAFE_OPTS (ref fixups); fix Log tag placement to fit CVS whims
*
diff --git a/storage.h b/storage.h
index 11ca34a..496f293 100644
--- a/storage.h
+++ b/storage.h
@@ -18,7 +18,8 @@
#ifndef Storage_h
#define Storage_h 1
-#include "config.h"
+#include "my-string.h"
+
#include "structures.h"
#include "ref_count.h"
@@ -47,17 +48,41 @@ extern void myfree(void *where, Memory_Type type);
extern void *mymalloc(unsigned size, Memory_Type type);
extern void *myrealloc(void *where, unsigned size, Memory_Type type);
-static inline void /* XXX was extern, fix for non-gcc compilers */
+static inline void /* XXX was extern, fix for non-gcc compilers */
free_str(const char *s)
{
if (delref(s) == 0)
myfree((void *) s, M_STRING);
}
+#ifdef MEMO_STRLEN
+/*
+ * Using the same mechanism as ref_count.h uses to hide Value ref counts,
+ * keep a memozied strlen in the storage with the string.
+ */
+#define memo_strlen(X) ((void)0, (((int *)(X))[-2]))
+#else
+#define memo_strlen(X) strlen(X)
+
+#endif /* MEMO_STRLEN */
+
#endif /* Storage_h */
/*
* $Log$
+ * Revision 1.5.8.1 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
+ * Revision 1.7 2006/12/06 23:44:56 wrog
+ * Fix compiler warnings about redefining strlen/strcmp
+ *
+ * Revision 1.6 2006/09/07 00:55:02 bjj
+ * Add new MEMO_STRLEN option which uses the refcounting mechanism to
+ * store strlen with strings. This is basically free, since most string
+ * allocations are rounded up by malloc anyway. This saves lots of cycles
+ * computing strlen. (The change is originally from jitmoo, where I wanted
+ * inline range checks for string ops).
+ *
* Revision 1.5 1998/12/14 13:19:00 nop
* Merge UNSAFE_OPTS (ref fixups); fix Log tag placement to fit CVS whims
*
diff --git a/str_intern.c b/str_intern.c
index 421da70..78c6413 100644
--- a/str_intern.c
+++ b/str_intern.c
@@ -243,7 +243,7 @@ str_intern(const char *s)
if (e != NULL) {
intern_allocations_saved++;
- intern_bytes_saved += strlen(s);
+ intern_bytes_saved += memo_strlen(e->s);
return str_ref(e->s);
}
diff --git a/streams.c b/streams.c
index ca318e3..d55102b 100644
--- a/streams.c
+++ b/streams.c
@@ -59,6 +59,13 @@ stream_add_char(Stream * s, char c)
}
void
+stream_delete_char(Stream * s)
+{
+ if (s->current > 0)
+ s->current--;
+}
+
+void
stream_add_string(Stream * s, const char *string)
{
int len = strlen(string);
@@ -231,6 +238,12 @@ char rcsid_streams[] = "$Id$";
/*
* $Log$
+ * Revision 1.3.8.1 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
+ * Revision 1.4 2006/12/06 23:57:51 wrog
+ * New INPUT_APPLY_BACKSPACE option to process backspace/delete characters on nonbinary connections (patch 1571939)
+ *
* Revision 1.3 1998/12/14 13:19:01 nop
* Merge UNSAFE_OPTS (ref fixups); fix Log tag placement to fit CVS whims
*
diff --git a/streams.h b/streams.h
index c2d6a9b..e60a4f8 100644
--- a/streams.h
+++ b/streams.h
@@ -28,6 +28,7 @@ typedef struct {
extern Stream *new_stream(int size);
extern void stream_add_char(Stream *, char);
+extern void stream_delete_char(Stream *);
extern void stream_add_string(Stream *, const char *);
extern void stream_printf(Stream *, const char *,...);
extern void free_stream(Stream *);
@@ -39,6 +40,12 @@ extern int stream_length(Stream *);
/*
* $Log$
+ * Revision 1.3.8.1 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
+ * Revision 1.4 2006/12/06 23:57:51 wrog
+ * New INPUT_APPLY_BACKSPACE option to process backspace/delete characters on nonbinary connections (patch 1571939)
+ *
* Revision 1.3 1998/12/14 13:19:02 nop
* Merge UNSAFE_OPTS (ref fixups); fix Log tag placement to fit CVS whims
*
diff --git a/tasks.c b/tasks.c
index d4f0991..3c5e7ea 100644
--- a/tasks.c
+++ b/tasks.c
@@ -43,6 +43,17 @@
#include "verbs.h"
#include "version.h"
+typedef enum {
+ /* Input Tasks */
+ TASK_INBAND, /* vanilla in-band */
+ TASK_OOB, /* out-of-band unless disable_oob */
+ TASK_QUOTED, /* in-band; needs unquote unless disable-oob */
+ TASK_BINARY, /* in-band; binary mode string */
+ /* Background Tasks */
+ TASK_FORKED,
+ TASK_SUSPENDED,
+} task_kind;
+
typedef struct forked_task {
int id;
Program *program;
@@ -61,6 +72,7 @@ typedef struct suspended_task {
typedef struct {
char *string;
int length;
+ struct task *next_itail; /* see tqueue.first_itail */
} input_task;
typedef struct task {
@@ -73,6 +85,17 @@ typedef struct task {
} t;
} task;
+enum icmd_flag {
+ /* fix icmd_index() if you change any of the following numbers: */
+ ICMD_SUFFIX = 1,
+ ICMD_OUTPUTSUFFIX = 2,
+ ICMD_OUTPUTPREFIX = 3,
+ ICMD_PREFIX = 4,
+ ICMD_PROGRAM = 5, /* .program */
+ /* mask */
+ ICMD_ALL_CMDS = ((1<<(ICMD_PROGRAM+1))-2)
+};
+
typedef struct tqueue {
/*
* A task queue can be in one of four possible states, depending upon the
@@ -88,7 +111,8 @@ typedef struct tqueue {
* negative `player' slots) are treated specially: they are passed to a
* particular verb on the system object. If that verb returns a valid
* player object number, then that is used as the new player number for the
- * connection.
+ * connection. (Note that none of this applies to tasks that are being
+ * read() or that are being handled as out-of-band commands.)
*
* The `connected' field is true iff this queue has an associated open
* network connection. Queues without such connections may nonetheless
@@ -102,20 +126,36 @@ typedef struct tqueue {
Objid handler;
int connected;
task *first_input, **last_input;
+ task *first_itail, **last_itail;
+ /* The input queue alternates between contiguous sequences of TASK_OOBs
+ * and sequences of non-TASK_OOBs; the "itail queue" is the queue of all
+ * sequence-ending tasks threaded along the next_itail pointers.
+ * first_itail is null iff first_input is null
+ * When the queue is nonempty,
+ * last_itail points to the penultimate .next_itail pointer slot
+ * unlike last_input which always points to the final (null)
+ * .next pointer slot
+ * For tasks not at the end of a sequence,
+ * the next_itail field is ignored and may be garbage.
+ */
int total_input_length;
int last_input_task_id;
int input_suspended;
+
task *first_bg, **last_bg;
int usage; /* a kind of inverted priority */
int num_bg_tasks; /* in either here or waiting_tasks */
- int hold_input; /* make input tasks wait for read() */
char *output_prefix, *output_suffix;
const char *flush_cmd;
Stream *program_stream;
Objid program_object;
const char *program_verb;
- char reading; /* boolean */
+ /* booleans */
+ char hold_input; /* input tasks must wait for read() */
+ char disable_oob; /* treat all input lines as inband */
+ char reading; /* some task is blocked on read() */
+ char icmds; /* which of .program/PREFIX/... are enabled */
vm reading_vm;
} tqueue;
@@ -140,6 +180,92 @@ static ext_queue *external_queues = 0;
: ttt->t.suspended.start_time)
+/*
+ * ICMD_FOR_EACH(DEFINE,verb)
+ * expands to a table of intrinsic commands,
+ * each entry of the form
+ *
+ * DEFINE(ICMD_NAME,<name>,<matcher>) where
+ * ICMD_NAME == enumeration constant name to use
+ * <name> == full verbname
+ * <matcher>(verb) -> true iff verb matches <name>
+ */
+#define __IDLM(DEFINE,DELIMITER,verb) \
+ DEFINE(ICMD_##DELIMITER, DELIMITER, \
+ (strcmp(verb, #DELIMITER) == 0)) \
+
+#define ICMD_FOR_EACH(DEFINE,verb) \
+ DEFINE(ICMD_PROGRAM, .program, \
+ (verbcasecmp(".pr*ogram", (verb)))) \
+ __IDLM(DEFINE,PREFIX, (verb)) \
+ __IDLM(DEFINE,SUFFIX, (verb)) \
+ __IDLM(DEFINE,OUTPUTPREFIX,(verb)) \
+ __IDLM(DEFINE,OUTPUTSUFFIX,(verb)) \
+
+static int
+icmd_index(const char * verb) {
+ /* evil, poor-man's minimal perfect hash */
+ int len = strlen(verb);
+ char c2 = len > 2 ? verb[2] : 0;
+ char c8 = len > 8 ? verb[8] : 0;
+ switch (((c2&7)^6)+!(c8&2)) {
+ default:
+ break;
+#define _ICMD_IX(ICMD_PREFIX,_,MATCH) \
+ case ICMD_PREFIX: \
+ if (MATCH) return ICMD_PREFIX; \
+ break; \
+
+ ICMD_FOR_EACH(_ICMD_IX,verb);
+ }
+ return 0;
+}
+#undef _ICMD_IX
+
+static Var
+icmd_list(int icmd_flags)
+{
+ Var s;
+ Var list = new_list(0);
+ s.type = TYPE_STR;
+#define _ICMD_MKSTR(ICMD_PREFIX,PREFIX,_) \
+ if (icmd_flags & (1<<ICMD_PREFIX)) { \
+ s.v.str = str_dup(#PREFIX); \
+ list = listappend(list, s); \
+ } \
+
+ ICMD_FOR_EACH(_ICMD_MKSTR,@);
+ return list;
+}
+#undef _ICMD_MKSTR
+
+static int
+icmd_set_flags(tqueue * tq, Var list)
+{
+ int i;
+ int newflags;
+ if (list.type == TYPE_INT) {
+ newflags = is_true(list) ? ICMD_ALL_CMDS : 0;
+ }
+ else if(list.type != TYPE_LIST)
+ return 0;
+ else {
+ newflags = 0;
+ for (i = 1; i <= list.v.list[0].v.num; ++i) {
+ int icmd;
+ if (list.v.list[i].type != TYPE_STR)
+ return 0;
+ icmd = icmd_index(list.v.list[i].v.str);
+ if (!icmd)
+ return 0;
+ newflags |= (1<<icmd);
+ }
+ }
+ tq->icmds = newflags;
+ return 1;
+}
+
+
static void
deactivate_tqueue(tqueue * tq)
{
@@ -213,8 +339,9 @@ find_tqueue(Objid player, int create_if_not_found)
tq->handler = 0;
tq->connected = 0;
- tq->first_input = tq->first_bg = 0;
+ tq->first_input = tq->first_itail = tq->first_bg = 0;
tq->last_input = &(tq->first_input);
+ tq->last_itail = &(tq->first_itail);
tq->last_bg = &(tq->first_bg);
tq->total_input_length = tq->input_suspended = 0;
@@ -224,6 +351,8 @@ find_tqueue(Objid player, int create_if_not_found)
tq->reading = 0;
tq->hold_input = 0;
+ tq->disable_oob = 0;
+ tq->icmds = ICMD_ALL_CMDS;
tq->num_bg_tasks = 0;
tq->last_input_task_id = 0;
@@ -277,17 +406,52 @@ dequeue_bg_task(tqueue * tq)
return t;
}
+static char oob_quote_prefix[] = OUT_OF_BAND_QUOTE_PREFIX;
+#define oob_quote_prefix_length (sizeof(oob_quote_prefix) - 1)
+
+enum dequeue_how { DQ_FIRST = -1, DQ_OOB = 0, DQ_INBAND = 1 };
+
static task *
-dequeue_input_task(tqueue * tq)
+dequeue_input_task(tqueue * tq, enum dequeue_how how)
{
- task *t = tq->first_input;
+ task *t;
+ task **pt, **pitail;
+
+ if (tq->disable_oob) {
+ if (how == DQ_OOB)
+ return 0;
+ how = DQ_FIRST;
+ }
+
+ if (!tq->first_input)
+ return 0;
+ else if (how == (tq->first_input->kind == TASK_OOB)) {
+ pt = &(tq->first_itail->next);
+ pitail = &(tq->first_itail->t.input.next_itail);
+ }
+ else {
+ pt = &(tq->first_input);
+ pitail = &(tq->first_itail);
+ }
+ t = *pt;
if (t) {
- tq->first_input = t->next;
+ *pt = t->next;
if (t->next == 0)
- tq->last_input = &(tq->first_input);
+ tq->last_input = pt;
else
t->next = 0;
+
+ if (t == *pitail) {
+ *pitail = 0;
+ if (t->t.input.next_itail) {
+ tq->first_itail = t->t.input.next_itail;
+ t->t.input.next_itail = 0;
+ }
+ if (*(tq->last_itail) == 0)
+ tq->last_itail = &(tq->first_itail);
+ }
+
tq->total_input_length -= t->t.input.length;
if (tq->input_suspended
&& tq->connected
@@ -295,27 +459,34 @@ dequeue_input_task(tqueue * tq)
server_resume_input(tq->player);
tq->input_suspended = 0;
}
+
+ if (t->kind == TASK_OOB) {
+ if (tq->disable_oob)
+ t->kind = TASK_INBAND;
+ }
+ else if (t->kind == TASK_QUOTED) {
+ if (!tq->disable_oob)
+ memmove(t->t.input.string,
+ t->t.input.string + oob_quote_prefix_length,
+ 1 + strlen(t->t.input.string + oob_quote_prefix_length));
+ t->kind = TASK_INBAND;
+ }
}
return t;
}
-static task *
-dequeue_any_task(tqueue * tq)
-{
- task *t = dequeue_input_task(tq);
-
- if (t)
- return t;
- else
- return dequeue_bg_task(tq);
-}
-
static void
free_task(task * t, int strong)
{ /* for FORKED tasks, strong == 1 means free the rt_env also.
for SUSPENDED tasks, strong == 1 means free the vm also. */
switch (t->kind) {
- case TASK_INPUT:
+ default:
+ panic("Unknown task kind in free_task()");
+ break;
+ case TASK_BINARY:
+ case TASK_INBAND:
+ case TASK_QUOTED:
+ case TASK_OOB:
free_str(t->t.input.string);
break;
case TASK_FORKED:
@@ -467,6 +638,37 @@ find_verb_on(Objid oid, Parsed_Command * pc, db_verb_handle * vh)
static int
+do_intrinsic_command(tqueue * tq, Parsed_Command * pc)
+{
+ int icmd = icmd_index(pc->verb);
+ if (!(icmd && (tq->icmds & (1<<icmd))))
+ return 0;
+ switch (icmd) {
+ default:
+ panic("Bad return value from icmd_index()");
+ break;
+ case ICMD_PROGRAM:
+ if (!is_programmer(tq->player))
+ return 0;
+ if (pc->args.v.list[0].v.num != 1)
+ notify(tq->player, "Usage: .program object:verb");
+ else
+ start_programming(tq, (char *) pc->args.v.list[1].v.str);
+ break;
+ case ICMD_PREFIX:
+ case ICMD_OUTPUTPREFIX:
+ set_delimiter(&(tq->output_prefix), pc->argstr);
+ break;
+ case ICMD_SUFFIX:
+ case ICMD_OUTPUTSUFFIX:
+ set_delimiter(&(tq->output_suffix), pc->argstr);
+ break;
+ }
+ return 1;
+}
+
+
+static int
do_command_task(tqueue * tq, char *command)
{
if (tq->program_stream) { /* We're programming */
@@ -480,18 +682,7 @@ do_command_task(tqueue * tq, char *command)
if (!pc)
return 0;
- if (is_programmer(tq->player) && verbcasecmp(".pr*ogram", pc->verb)) {
- if (pc->args.v.list[0].v.num != 1)
- notify(tq->player, "Usage: .program object:verb");
- else
- start_programming(tq, (char *) pc->args.v.list[1].v.str);
- } else if (strcmp(pc->verb, "PREFIX") == 0
- || strcmp(pc->verb, "OUTPUTPREFIX") == 0)
- set_delimiter(&(tq->output_prefix), pc->argstr);
- else if (strcmp(pc->verb, "SUFFIX") == 0
- || strcmp(pc->verb, "OUTPUTSUFFIX") == 0)
- set_delimiter(&(tq->output_suffix), pc->argstr);
- else {
+ if (!do_intrinsic_command(tq, pc)) {
Objid location = (valid(tq->player)
? db_object_location(tq->player)
: NOTHING);
@@ -570,11 +761,11 @@ do_login_task(tqueue * tq, char *command)
}
if (dead_tq) { /* Copy over tasks from old queue for player */
tq->num_bg_tasks = dead_tq->num_bg_tasks;
- while ((t = dequeue_any_task(dead_tq)) != 0) {
- if (t->kind == TASK_INPUT)
- free_task(t, 0);
- else /* FORKED or SUSPENDED */
- enqueue_bg_task(tq, t);
+ while ((t = dequeue_input_task(dead_tq, DQ_FIRST)) != 0) {
+ free_task(t, 0);
+ }
+ while ((t = dequeue_bg_task(dead_tq)) != 0) {
+ enqueue_bg_task(tq, t);
}
dead_tq->player = NOTHING; /* it'll be freed by run_ready_tasks */
dead_tq->num_bg_tasks = 0;
@@ -629,92 +820,111 @@ free_task_queue(task_queue q)
ensure_usage(tq);
}
+#define TASK_CO_TABLE(DEFINE, tq, value, _) \
+ DEFINE(flush-command, _, TYPE_STR, str, \
+ tq->flush_cmd ? str_ref(tq->flush_cmd) : str_dup(""), \
+ { \
+ if (tq->flush_cmd) \
+ free_str(tq->flush_cmd); \
+ if (value.type == TYPE_STR && value.v.str[0] != '\0') \
+ tq->flush_cmd = str_ref(value.v.str); \
+ else \
+ tq->flush_cmd = 0; \
+ }) \
+ \
+ DEFINE(hold-input, _, TYPE_INT, num, \
+ tq->hold_input, \
+ { \
+ tq->hold_input = is_true(value); \
+ /* Anything to be done? */ \
+ if (!tq->hold_input && tq->first_input) \
+ ensure_usage(tq); \
+ }) \
+ \
+ DEFINE(disable-oob, _, TYPE_INT, num, \
+ tq->disable_oob, \
+ { \
+ tq->disable_oob = is_true(value); \
+ /* Anything to be done? */ \
+ if (!tq->disable_oob && tq->first_input \
+ && (tq->first_itail->next \
+ || tq->first_input->kind == TASK_OOB)) \
+ ensure_usage(tq); \
+ }) \
+ \
+ DEFINE(intrinsic-commands, _, TYPE_LIST, list, \
+ icmd_list(tq->icmds).v.list, \
+ { \
+ if (!icmd_set_flags(tq, value)) \
+ return 0; \
+ }) \
+
int
tasks_set_connection_option(task_queue q, const char *option, Var value)
{
- tqueue *tq = q.ptr;
-
- if (!mystrcasecmp(option, "flush-command")) {
- if (tq->flush_cmd)
- free_str(tq->flush_cmd);
- if (value.type == TYPE_STR && value.v.str[0] != '\0')
- tq->flush_cmd = str_ref(value.v.str);
- else
- tq->flush_cmd = 0;
-
- return 1;
- }
- if (!mystrcasecmp(option, "hold-input")) {
- tq->hold_input = is_true(value);
- if (!tq->hold_input && tq->first_input) /* Anything to be done? */
- ensure_usage(tq);
- return 1;
- }
- return 0;
+ CONNECTION_OPTION_SET(TASK_CO_TABLE, (tqueue *)q.ptr, option, value);
}
int
tasks_connection_option(task_queue q, const char *option, Var * value)
{
- tqueue *tq = q.ptr;
-
- if (!mystrcasecmp(option, "flush-command")) {
- value->type = TYPE_STR;
- value->v.str = (tq->flush_cmd ? str_ref(tq->flush_cmd) : str_dup(""));
- return 1;
- }
- if (!mystrcasecmp(option, "hold-input")) {
- value->type = TYPE_INT;
- value->v.num = tq->hold_input;
- return 1;
- }
- return 0;
+ CONNECTION_OPTION_GET(TASK_CO_TABLE, (tqueue *)q.ptr, option, value);
}
Var
tasks_connection_options(task_queue q, Var list)
{
- tqueue *tq = q.ptr;
- Var pair;
-
- pair = new_list(2);
- pair.v.list[1].type = TYPE_STR;
- pair.v.list[1].v.str = str_dup("flush-command");
- pair.v.list[2].type = TYPE_STR;
- pair.v.list[2].v.str = (tq->flush_cmd ? str_ref(tq->flush_cmd)
- : str_dup(""));
- list = listappend(list, pair);
-
- pair = new_list(2);
- pair.v.list[1].type = TYPE_STR;
- pair.v.list[1].v.str = str_dup("hold-input");
- pair.v.list[2].type = TYPE_INT;
- pair.v.list[2].v.num = tq->hold_input;
- list = listappend(list, pair);
-
- return list;
+ CONNECTION_OPTION_LIST(TASK_CO_TABLE, (tqueue *)q.ptr, list);
}
+#undef TASK_CO_TABLE
+
static void
-enqueue_input_task(tqueue * tq, const char *input, int at_front)
+enqueue_input_task(tqueue * tq, const char *input, int at_front, int binary)
{
+ static char oob_prefix[] = OUT_OF_BAND_PREFIX;
task *t;
t = (task *) mymalloc(sizeof(task), M_TASK);
- t->kind = TASK_INPUT;
+ if (binary)
+ t->kind = TASK_BINARY;
+ else if (oob_quote_prefix_length > 0
+ && strncmp(oob_quote_prefix, input, oob_quote_prefix_length) == 0)
+ t->kind = TASK_QUOTED;
+ else if (sizeof(oob_prefix) > 1
+ && strncmp(oob_prefix, input, sizeof(oob_prefix) - 1) == 0)
+ t->kind = TASK_OOB;
+ else
+ t->kind = TASK_INBAND;
+
t->t.input.string = str_dup(input);
tq->total_input_length += (t->t.input.length = strlen(input));
+ t->t.input.next_itail = 0;
if (at_front && tq->first_input) { /* if nothing there, front == back */
+ if ((tq->first_input->kind == TASK_OOB) != (t->kind == TASK_OOB)) {
+ t->t.input.next_itail = tq->first_itail;
+ tq->first_itail = t;
+ if (tq->last_itail == &(tq->first_itail))
+ tq->last_itail = &(t->t.input.next_itail);
+ }
t->next = tq->first_input;
tq->first_input = t;
- } else {
+ }
+ else {
+ if (tq->first_input && (((*(tq->last_itail))->kind == TASK_OOB)
+ != (t->kind == TASK_OOB)))
+ tq->last_itail = &((*(tq->last_itail))->t.input.next_itail);
+ *(tq->last_itail) = t;
+
*(tq->last_input) = t;
tq->last_input = &(t->next);
t->next = 0;
}
- if (!tq->hold_input || tq->reading) /* Anything to do with this line? */
+ /* Anything to do with this line? */
+ if (!tq->hold_input || tq->reading
+ || (!tq->disable_oob && t->kind == TASK_OOB))
ensure_usage(tq);
if (!tq->input_suspended
@@ -725,6 +935,17 @@ enqueue_input_task(tqueue * tq, const char *input, int at_front)
}
}
+void
+task_suspend_input(task_queue q)
+{
+ tqueue *tq = q.ptr;
+
+ if (!tq->input_suspended && tq->connected) {
+ server_suspend_input(tq->player);
+ tq->input_suspended = 1;
+ }
+}
+
static void
flush_input(tqueue * tq, int show_messages)
{
@@ -734,7 +955,8 @@ flush_input(tqueue * tq, int show_messages)
if (show_messages)
notify(tq->player, ">> Flushing the following pending input:");
- while ((t = dequeue_input_task(tq)) != 0) {
+ while ((t = dequeue_input_task(tq, DQ_FIRST)) != 0) {
+ /* TODO*** flush only non-TASK_OOB tasks ??? */
if (show_messages) {
stream_printf(s, ">> %s", t->t.input.string);
notify(tq->player, reset_stream(s));
@@ -748,7 +970,7 @@ flush_input(tqueue * tq, int show_messages)
}
void
-new_input_task(task_queue q, const char *input)
+new_input_task(task_queue q, const char *input, int binary)
{
tqueue *tq = q.ptr;
@@ -756,7 +978,7 @@ new_input_task(task_queue q, const char *input)
flush_input(tq, 1);
return;
}
- enqueue_input_task(tq, input, 0);
+ enqueue_input_task(tq, input, 0/*at-rear*/, binary);
}
static void
@@ -910,7 +1132,7 @@ read_input_now(Objid connection)
if (!tq || is_out_of_input(tq)) {
r.type = TYPE_ERR;
r.v.err = E_INVARG;
- } else if (!(t = dequeue_input_task(tq))) {
+ } else if (!(t = dequeue_input_task(tq, DQ_INBAND))) {
r.type = TYPE_INT;
r.v.num = 0;
} else {
@@ -987,7 +1209,6 @@ run_ready_tasks(void)
{
int did_one = 0;
time_t start = time(0);
- static char oob_prefix[] = OUT_OF_BAND_PREFIX;
while (active_tqueues && !did_one) {
/* Loop over tqueues, looking for a task */
@@ -1000,33 +1221,36 @@ run_ready_tasks(void)
current_task_id = tq->reading_vm->task_id;
v.type = TYPE_ERR;
v.v.err = E_INVARG;
- resume_from_previous_vm(tq->reading_vm, v, TASK_INPUT, 0);
+ resume_from_previous_vm(tq->reading_vm, v);
did_one = 1;
}
while (!did_one) { /* Loop over tasks, looking for runnable one */
- if (tq->hold_input && !tq->reading)
+ t = dequeue_input_task(tq, ((tq->hold_input && !tq->reading)
+ ? DQ_OOB
+ : DQ_FIRST));
+ if (!t)
t = dequeue_bg_task(tq);
- else
- t = dequeue_any_task(tq);
if (!t)
break;
switch (t->kind) {
- case TASK_INPUT:
- if (sizeof(oob_prefix) > 1
- && !strncmp(oob_prefix, t->t.input.string,
- sizeof(oob_prefix) - 1)) {
- do_out_of_band_command(tq, t->t.input.string);
- did_one = 1;
- } else if (tq->reading) {
+ default:
+ panic("Unexpected task kind in run_ready_tasks()");
+ break;
+ case TASK_OOB:
+ do_out_of_band_command(tq, t->t.input.string);
+ did_one = 1;
+ break;
+ case TASK_BINARY:
+ case TASK_INBAND:
+ if (tq->reading) {
Var v;
tq->reading = 0;
current_task_id = tq->reading_vm->task_id;
v.type = TYPE_STR;
v.v.str = t->t.input.string;
- resume_from_previous_vm(tq->reading_vm, v, TASK_INPUT,
- 0);
+ resume_from_previous_vm(tq->reading_vm, v);
did_one = 1;
} else {
/* Used to insist on tq->connected here, but Pavel
@@ -1046,15 +1270,14 @@ run_ready_tasks(void)
ft = t->t.forked;
current_task_id = ft.id;
do_forked_task(ft.program, ft.rt_env, ft.a,
- ft.f_index, 0);
+ ft.f_index);
did_one = 1;
}
break;
case TASK_SUSPENDED:
current_task_id = t->t.suspended.the_vm->task_id;
resume_from_previous_vm(t->t.suspended.the_vm,
- t->t.suspended.value,
- TASK_SUSPENDED, 0);
+ t->t.suspended.value);
did_one = 1;
break;
}
@@ -1106,7 +1329,7 @@ run_server_task_setting_id(Objid player, Objid what, const char *verb,
h = db_find_callable_verb(what, verb);
if (h.ptr)
return do_server_verb_task(what, verb, args, h, player, argstr,
- result, 1);
+ result, 1/*traceback*/);
else {
/* simulate an empty verb */
if (result) {
@@ -1126,7 +1349,8 @@ run_server_program_task(Objid this, const char *verb, Var args, Objid vloc,
{
current_task_id = new_task_id();
return do_server_program_task(this, verb, args, vloc, verbname, program,
- progr, debug, player, argstr, result, 1);
+ progr, debug, player, argstr, result,
+ 1/*traceback*/);
}
void
@@ -1443,8 +1667,8 @@ activation_bytes(activation * ap)
}
/* XXX ignore bi_func_data, it's an opaque type. */
total += value_bytes(ap->temp) - sizeof(Var);
- total += strlen(ap->verb) + 1;
- total += strlen(ap->verbname) + 1;
+ total += memo_strlen(ap->verb) + 1;
+ total += memo_strlen(ap->verbname) + 1;
return total;
}
@@ -1972,7 +2196,7 @@ bf_force_input(Var arglist, Byte next, void *vdata, Objid progr)
return make_error_pack(E_PERM);
}
tq = find_tqueue(conn, 1);
- enqueue_input_task(tq, line, at_front);
+ enqueue_input_task(tq, line, at_front, 0/*non-binary*/);
free_var(arglist);
return no_var_pack();
}
@@ -2014,13 +2238,55 @@ char rcsid_tasks[] = "$Id$";
/*
* $Log$
+ * Revision 1.9.6.5.2.1 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
* Revision 1.9.6.5 2002/10/29 01:00:28 xplat
* Changed PMODE_* to PARSE_* for clarity.
*
* Revision 1.9.6.4 2002/10/27 22:48:12 xplat
* Changes to support PCs located in vectors other than MAIN_VECTOR.
*
- * Revision 1.9.6.3 2002/09/17 15:35:06 xplat
+ * Revision 1.14 2006/09/07 00:55:02 bjj
+ * Add new MEMO_STRLEN option which uses the refcounting mechanism to
+ * store strlen with strings. This is basically free, since most string
+ * allocations are rounded up by malloc anyway. This saves lots of cycles
+ * computing strlen. (The change is originally from jitmoo, where I wanted
+ * inline range checks for string ops).
+ *
+ * Revision 1.13 2004/05/28 07:53:32 wrog
+ * added "intrinsic-commands" connection option
+ *
+ * Revision 1.12 2004/05/22 01:25:44 wrog
+ * merging in WROGUE changes (W_SRCIP, W_STARTUP, W_OOB)
+ *
+ * Revision 1.10.2.5 2004/05/20 19:40:32 wrog
+ * fixed force_input(,,1) bug
+ *
+ * Revision 1.11 2003/06/12 18:16:56 bjj
+ * Suspend input on connection until :do_login_command() can run.
+ *
+ * Revision 1.10.2.4 2003/06/11 10:57:27 wrog
+ * fixed non-blocking read() to only grab inband lines
+ * fixed "hold-input" to not hold up out-of-band lines
+ * fixed out-of-band line handling to not mess with binary input lines
+ * implemented quoting with OUT_OF_BAND_QUOTE_PREFIX
+ * TASK_INPUT differentiates into TASK_INBAND/OOB/QUOTED/BINARY
+ * input queue is now doubly threaded so that one can dequeue first available (non-)TASK_OOB even if it's not at the front
+ * new connection option "disable-oob"
+ *
+ * Revision 1.10.2.3 2003/06/07 14:34:14 wrog
+ * removed dequeue_any_task()
+ *
+ * Revision 1.10.2.2 2003/06/07 12:59:04 wrog
+ * introduced connection_option macros
+ *
+ * Revision 1.10.2.1 2003/06/04 21:28:59 wrog
+ * removed useless arguments from resume_from_previous_vm(), do_forked_task();
+ * replaced current_task_kind with is_fg argument for do_task();
+ * made enum task_kind internal to tasks.c
+ *
+ * Revision 1.10 2002/09/15 23:21:01 xplat
* GNU indent normalization.
*
* Revision 1.9.6.2 2002/09/17 15:04:07 xplat
diff --git a/tasks.h b/tasks.h
index 81ba473..e359f55 100644
--- a/tasks.h
+++ b/tasks.h
@@ -35,7 +35,8 @@ extern Var tasks_connection_options(task_queue, Var);
extern int tasks_set_connection_option(task_queue, const char *,
Var);
-extern void new_input_task(task_queue, const char *);
+extern void new_input_task(task_queue, const char *, int);
+extern void task_suspend_input(task_queue);
extern enum error enqueue_forked_task2(activation a, int f_index,
unsigned after_seconds, int vid);
extern enum error enqueue_suspended_task(vm the_vm, void *data);
@@ -110,6 +111,18 @@ extern db_verb_handle find_verb_for_programming(Objid player,
/*
* $Log$
+ * Revision 1.3.8.1 2007/05/14 23:09:24 xplat
+ * merged in changes from HEAD
+ *
+ * Revision 1.5 2004/05/22 01:25:44 wrog
+ * merging in WROGUE changes (W_SRCIP, W_STARTUP, W_OOB)
+ *
+ * Revision 1.4 2003/06/12 18:16:57 bjj
+ * Suspend input on connection until :do_login_command() can run.
+ *
+ * Revision 1.3.10.1 2003/06/11 10:40:17 wrog
+ * added binary argument to new_input_task()
+ *
* Revision 1.3 1998/12/14 13:19:08 nop
* Merge UNSAFE_OPTS (ref fixups); fix Log tag placement to fit CVS whims
*
diff --git a/utils.c b/utils.c
index 98b90a8..32518b1 100644
--- a/utils.c
+++ b/utils.c
@@ -364,7 +364,7 @@ value_bytes(Var v)
switch (v.type) {
case TYPE_STR:
- size += strlen(v.v.str) + 1;
+ size += memo_strlen(v.v.str) + 1;
break;
case TYPE_FLOAT:
size += sizeof(double);
@@ -443,6 +443,16 @@ char rcsid_utils[] = "$Id$";
/*
* $Log$
+ * Revision 1.7.8.1 2007/05/14 23:09:25 xplat
+ * merged in changes from HEAD
+ *
+ * Revision 1.8 2006/09/07 00:55:02 bjj
+ * Add new MEMO_STRLEN option which uses the refcounting mechanism to
+ * store strlen with strings. This is basically free, since most string
+ * allocations are rounded up by malloc anyway. This saves lots of cycles
+ * computing strlen. (The change is originally from jitmoo, where I wanted
+ * inline range checks for string ops).
+ *
* Revision 1.7 2002/08/18 09:47:26 bjj
* Finally made free_activation() take a pointer after noticing how !$%^&
* much time it was taking in a particular profiling run.
diff --git a/version.c b/version.c
index 85157b2..0cd0f16 100644
--- a/version.c
+++ b/version.c
@@ -40,7 +40,7 @@
#include "config.h"
#include "version.h"
-const char *server_version = "1.8.1";
+const char *server_version = "1.8.3";
int
check_version(DB_Version version)