10 years agoNew info Hvy-Plastic hvy-plastic-3 hvy-plastic-3.0
Markus Armbruster [Sat, 5 May 2012 14:51:18 +0000 (16:51 +0200)]
New info Hvy-Plastic

10 years agoChange fairland island size probability distribution
Markus Armbruster [Mon, 9 Mar 2009 20:22:03 +0000 (21:22 +0100)]
Change fairland island size probability distribution

Island size is randomly chosen from the interval [1..2*is+1], with
expected value is.  Use two dice to roll the size instead of one.
This makes extreme sizes much less likely.
(cherry picked from commit 29d2f5ccfe4d629151c4843f994ac8e9fcc74f58)

10 years agoMake fairland record the island number in the deity territory
Markus Armbruster [Sat, 5 Apr 2008 14:09:24 +0000 (16:09 +0200)]
Make fairland record the island number in the deity territory

Can be useful for deities when further customizing their game setup.
(cherry picked from commit 880f3856d10ec3cc63213dcf7729055eb37dcc11)

10 years agoUpdate change log again for 4.3.30 v4.3.30
Markus Armbruster [Tue, 22 May 2012 18:35:52 +0000 (20:35 +0200)]
Update change log again for 4.3.30

10 years agoDisable damage to base when missile explodes on launch
Markus Armbruster [Tue, 22 May 2012 18:17:16 +0000 (20:17 +0200)]
Disable damage to base when missile explodes on launch

When a missile explodes on launch, it has a 33% chance to damage its

Unfortunately, damaging the base breaks callers that call msl_launch()
for each member of a list of missiles created by msl_sel() or
perform_mission().  Damage to the base can damage other missiles
there.  Any copies of them in the list become stale.  When
msl_launch() modifies and writes back such a stale copy, the damage
gets wiped out, triggering a seqno oops.

Affects missile interdiction and interception using missiles with
non-zero load.  Stock game's ABMs have zero load, so interception is
safe there.  Relatively harmless in practice.  Broken in Empire 2.

Instead of fixing the bug, simply disable damage to the base for now.

10 years agoFix march not to wipe out concurrent updates
Markus Armbruster [Fri, 18 May 2012 14:29:19 +0000 (16:29 +0200)]
Fix march not to wipe out concurrent updates

March code reads the land units into a land unit list, and writes them
back when it changes them, e.g. when a land unit stops.  If a land
unit changes in the land unit file while it is in such a land unit
list, the copy in the land unit list becomes stale, and must not be

To that end, do_unit_move() calls lnd_mar() after prompting for path
or destination.  lnd_mar() re-reads all the land units.
Unfortunately, it still writes back stale copies in certain
circumstances.  Known ways to trigger such writes:

* Deity loads land unit onto a ship or land unit

* Land unit's crew killed just right, e.g. by collateral damage from
  interdiction, followed by additional updates, such as shell fire

* Sector no longer owned or allied, e.g. allied sector captured by an
  enemy (own sector would kill or retreat the land unit)

Writing a stale copy wipes out the updates that made the copy stale,
and triggers a seqno mismatch oops.  For instance, damage that follows
killing of all crew by collateral damage from interdiction is wiped
out.  If no damage follows, we still get a generation oops.

10 years agoFix navigate not to wipe out concurrent updates
Markus Armbruster [Thu, 17 May 2012 18:33:34 +0000 (20:33 +0200)]
Fix navigate not to wipe out concurrent updates

Navigation code reads the ships into a ship list, and writes them back
when it changes them, e.g. when a ship stops.  If a ship changes in
the ship file while it is in such a ship list, the copy in the ship
list becomes stale, and must not be used.

To that end, do_unit_move() calls shp_nav() after prompting for path
or destination.  shp_nav() re-reads all the ships.  Unfortunately, it
still writes back stale copies in certain circumstances.  Known ways
to trigger such writes:

* Deity sets a sail path

* Ship's crew gone, e.g. killed by shell fire

* Sector no longer navigable, e.g. harbor shelled down, or bridge

Writing a stale copy wipes out the updates that made the copy stale,
and triggers a seqno mismatch oops.  For instance, ship damage that
kills all crew while the ship is being navigated gets wiped out.

10 years agoFix Windows build: gettimeofday() and SHUT_WR missing
Ron Koenderink [Fri, 11 May 2012 02:59:50 +0000 (20:59 -0600)]
Fix Windows build: gettimeofday() and SHUT_WR missing

Commit 904822e3 introduced use of SHUT_WR, which Windows calls
SD_SEND.  Add the obvious work-around.

Commit 49ae6a7b introduced use of gettimeofday(), which the Microsoft
CRT lacks.  Add a replacement based on _ftime_s().

10 years agoUpdate change log again for 4.3.30
Markus Armbruster [Sat, 5 May 2012 14:18:14 +0000 (16:18 +0200)]
Update change log again for 4.3.30

10 years agoFix buffer overruns in fairland for island size zero
Markus Armbruster [Sat, 5 May 2012 12:16:00 +0000 (14:16 +0200)]
Fix buffer overruns in fairland for island size zero

Fairland creates islands with size 1 + random() % (2 * is - 1), where
"is" is either chosen by the user (fourth command line argument) or
defaults to half the continent size (second command line argument).
Negative values are silently replaced by zero.

Not only does value zero make no sense, it also breaks the code: the
island size is always one then (because random() % -1 is zero), but
allocate_memory() provides only space for zero sectors in sectx[],
secty[] and sectc[].  This leads to buffer overruns in try_to_grow(),
find_coast(), elevate_land, set_coastal_flags().  Can smash the heap.

Fix by changing the lower bound from zero to one.  Diagnosed with
valgrind.  Has always been broken.

10 years agoFix an out-of-bounds subscript in fairland
Markus Armbruster [Sat, 5 May 2012 11:46:15 +0000 (13:46 +0200)]
Fix an out-of-bounds subscript in fairland

elevate_land() tests for capital sector in three places.  The third
one is broken: half of the test is done even for islands, subscripting
capx[] and possibly capy[] out of bounds.  This could screw up
elevation (unlikely) or crash (even less likely).  Diagnosed with

Broken since the test was added in Chainsaw 3.12.  Parenthesis were
added blindly 4.0.11 to shut up the compiler.  Reindentation (commit
9b7adfbe and ef383c06, v4.2.13) made the bug stand out more, but it
still managed to hide in the general ugliness of fairland's code.

10 years agoFix typo in change log
Markus Armbruster [Sat, 5 May 2012 07:17:00 +0000 (09:17 +0200)]
Fix typo in change log

10 years agoUpdate change log again for 4.3.30
Markus Armbruster [Sun, 29 Apr 2012 18:29:04 +0000 (20:29 +0200)]
Update change log again for 4.3.30

10 years agoStart the makefile's dependency section with a comment
Markus Armbruster [Sun, 29 Apr 2012 16:50:26 +0000 (18:50 +0200)]
Start the makefile's dependency section with a comment

Just to separate it visually from the preceding section

10 years agoJournal login before changing the player thread's name
Markus Armbruster [Sun, 29 Apr 2012 10:36:54 +0000 (12:36 +0200)]
Journal login before changing the player thread's name

The journal logs a thread name for each event.  The player thread name
changes on entry to the playing phase.  Connecting old and new name
isn't as easy as it should be:

    Sun Apr 29 12:13:39 2012     Conn29 input coun POGO
    Sun Apr 29 12:13:39 2012     Conn29 input pass peter
    Sun Apr 29 12:13:39 2012     Conn29 input play
    Sun Apr 29 12:13:39 2012     Play#0 login 0 armbru
    Sun Apr 29 12:15:39 2012     Play#0 logout 0

To connect Conn29 with Play#0, you have to know that country#0 is
named POGO.

Fix that by logging login before the thread name change:

    Sun Apr 29 12:17:41 2012     Conn29 input coun POGO
    Sun Apr 29 12:17:41 2012     Conn29 input pass peter
    Sun Apr 29 12:17:41 2012     Conn29 input play
    Sun Apr 29 12:17:41 2012     Conn29 login 0 armbru
    Sun Apr 29 12:19:41 2012     Play#0 logout 0

Now "Conn29 login 0" makes the connection obvious.

This involves moving journal_login() from player_main() before
empth_set_name() in its caller play_cmd().  Move journal_logout() as
well, for symmetry.

If player_main() fails, we now log login/logout instead of nothing in
the journal.  That's okay.  Note that before commit c9f21c0e (v4.3.8),
we logged just login then.

10 years agoFix arm to require nuke and plane to be in the same sector
Markus Armbruster [Sun, 29 Apr 2012 07:58:51 +0000 (09:58 +0200)]
Fix arm to require nuke and plane to be in the same sector

It happily arms a plane with a remote nuke.  The nuke gets teleported
to the plane when the plane moves (a two-way sortie doesn't count as
move).  Broken in 4.3.3.  Reported by Harald Katzer.

10 years agoUpdate change log for 4.3.30
Markus Armbruster [Thu, 26 Apr 2012 18:15:48 +0000 (20:15 +0200)]
Update change log for 4.3.30

10 years agoDocument login_grace_time and the shutdown phase properly
Markus Armbruster [Wed, 28 Mar 2012 16:29:04 +0000 (18:29 +0200)]
Document login_grace_time and the shutdown phase properly

10 years agoDon't send "idle connection terminated" in login phase
Markus Armbruster [Wed, 28 Mar 2012 16:24:46 +0000 (18:24 +0200)]
Don't send "idle connection terminated" in login phase

Message was introduced in commit 08b94556, v4.3.20.  Revert this
change, because it's undocumented, and probably not useful for

10 years agoRename play_lock back to update_lock
Markus Armbruster [Tue, 27 Mar 2012 18:06:35 +0000 (20:06 +0200)]
Rename play_lock back to update_lock

It was renamed to play_lock because it synchronized not just updates
but also shutdown.  Since the previous commit, it again only
synchronizes updates.  Rename it back.

Also move its initialization next to shutdown_lock's.

10 years agoFix synchronization between shutdown and player threads
Markus Armbruster [Tue, 27 Mar 2012 17:58:31 +0000 (19:58 +0200)]
Fix synchronization between shutdown and player threads

shutdwn() sets the EOF indicator, aborts the running command, if any,
forbids sleeping on I/O and wakes up the player thread, for all player
threads in state PS_PLAYING.  It takes play_lock to prevent new
commands from running.  It then waits up to 3s for player threads to
terminate, by polling player_next(), to let output buffers drain.


1. Polling is lame.

2. New player threads can still enter state PS_PLAYING.  They'll block
   as soon as they try to run a command.  Somehwat unclean.

3. We can exit before all player threads left state PS_PLAYING, losing
   a treasury update, play time update, and log entries.  Could happen
   when player threads blocked on output until commit 90b3abc5 fixed
   that; its commit message describes the bug's impact in more detail.
   Since then, the bug shouldn't bite in practice, because player
   threads should leave state PS_PLAYING quickly.

Fix by introducing shutdown_lock: player threads in state PS_PLAYING
hold it shared, shutdwn() takes it exclusive, instead of play_lock.
Takes care of the issues as follows:

3. shutdwn() waits until all player threads left state PS_PLAYING, no
   matter how long it takes them.

2. New player threads block before entering state PS_PLAYING.

1. shutdwn() still polls up to 3s for player threads to terminate.
   Still lame.  Left for another day.

10 years agoStart player thread shutdown grace time at shutdwn() entry
Markus Armbruster [Tue, 27 Mar 2012 17:21:38 +0000 (19:21 +0200)]
Start player thread shutdown grace time at shutdwn() entry

Before, it was started after all commands aborted.  Shouldn't make a
difference in practice, as command abortion is supposed to be quick.

10 years agoClean up superfluous includes
Markus Armbruster [Sun, 18 Mar 2012 19:23:18 +0000 (20:23 +0100)]
Clean up superfluous includes

10 years agoBelatedly update convert's c_form
Markus Armbruster [Sun, 18 Mar 2012 18:20:21 +0000 (19:20 +0100)]
Belatedly update convert's c_form

Commit 82c91665 (v4.3.16) removed its optional third argument without
updating c_form.

10 years agoDocument the header for empmod.c and trdsub.c in prototypes.h
Markus Armbruster [Sun, 18 Mar 2012 18:09:29 +0000 (19:09 +0100)]
Document the header for empmod.c and trdsub.c in prototypes.h

10 years agoDocument execute()'s subtle use of player->aborted
Markus Armbruster [Sun, 18 Mar 2012 18:07:47 +0000 (19:07 +0100)]
Document execute()'s subtle use of player->aborted

10 years agoio_shutdown() is now unused, remove
Markus Armbruster [Sun, 18 Mar 2012 18:04:21 +0000 (19:04 +0100)]
io_shutdown() is now unused, remove

10 years agoChange login command kill to kill less ruthlessly
Markus Armbruster [Sun, 18 Mar 2012 17:30:39 +0000 (18:30 +0100)]
Change login command kill to kill less ruthlessly

The victim's connection closes without any explanation.  Output may be
lost.  This is because kill_cmd() kills by calling io_shutdown(),
which shuts down the socket and drains the I/O queues.

How this makes the victim's thread terminate is a bit subtle: shutting
down the socket makes it ready.  If the victim's thread is waiting for
I/O, it wakes up.  Since all further reads return EOF, and all further
writes fail, the command terminates quickly (short of inifinite loop
bugs), then the command loop, and finally the thread.

To make kill behave more nicely, change kill_cmd() to work exactly
like server shutdown: send a flash message to the victim, set his EOF
indicator, abort the command, forbid sleeping on I/O, wake up the
victim's thread.  Just as reliable, but doesn't lose output.

If the victim's client fails to close his connection, the victim's
thread may still linger in state PS_SHUTDOWN for up to
login_grace_time (default 120s).  An attacker could try to use that to
make the server run out of file descriptors or memory, but simply
connecting achieves the same effect more cheaply.

10 years agoSeparate max_idle_visitor from max_idle
Markus Armbruster [Sun, 18 Mar 2012 17:24:51 +0000 (18:24 +0100)]
Separate max_idle_visitor from max_idle

Cut it to 5 minutes, from max_idle's 15.

Since max_idle now applies only to authenticated players, increasing
it is perfectly safe.

10 years agoSeparate login_grace_time from max_idle
Markus Armbruster [Sun, 18 Mar 2012 17:11:35 +0000 (18:11 +0100)]
Separate login_grace_time from max_idle

max_idle applies in state PS_PLAYING, login_grace_time before (login,
state PS_INIT) and after (logout, state PS_SHUTDOWN).

Cut login_grace_time to two minutes, from max_idle's 15.  Two minutes
is plenty to complete login and logout.  Makes swamping the server
with connections slightly harder, as they get dropped faster.  While
that makes sense all by itself, the real aim is making increasing
max_idle safe.  The next commit will complete that job.

10 years agoFix unwanted player thread blocking on output during shutdown
Markus Armbruster [Wed, 14 Mar 2012 19:22:17 +0000 (20:22 +0100)]
Fix unwanted player thread blocking on output during shutdown

shutdwn() disables blocking on I/O for all player threads in state
PS_PLAYING, by setting struct player member may_sleep to
PLAYER_SLEEP_NEVER.  This ensures the player threads complete logout
quickly and reliably.  A thread may still block on I/O in io_close()
called from player_delete(), since commit 904822e3, but that's okay,
because it happens after all game state updates.

Bug: if shutdwn() aborts a command, the player thread returns through
dispatch(), which resets may_sleep back to PLAYER_SLEEP_FREELY.  Input
can't block regardless, because the EOF indicator is set, but output
can.  When it happens, the player thread may not complete logout
before shutdwn() terminates the process.

This can make us lose a treasury update (similar to the bug fixed by
commit bdc1c40f; the relevant bug description is in commit note
6f8ca87f), play time update, and log entries.

How?  There are two paths from dispatch() to player_delete().  Here's
the first one:

  1. command()
     Doesn't print since dispatch() returns 0 when it resets may_sleep
  2. player_main()
     Loop and call status()
  3. status()
     If the command set dolcost to a non-trivial amount, print it
     Charge dolcost
     If player went broke or became solvent, notify him
     Charge time used
     Return 0, because shutdwn() set the EOF indicator
  4. player_main()
     Break the loop
     Charge time used
     print Bye-bye
     journal.log the logout
  5. play_cmd()
     server.log the logout
  6. player_login()
     Try to flush output
     get EOF, break loop
     print so long
     call player_delete()

Ways the bug can bite:

A. When we block in 4. print Bye-bye, we can fail to log.

B. When we block in 3. print broke/solvent notification, we can
   additionally fail to charge time used.

C. When we block in 3. print dolcost, we can additionally fail to
   charge dolcost.

Note: B. and C. couldn't happen before commit bdc1c40f.  Instead,
something just like C happened always, whether player thread blocked
or not.

The second path:

  1. execute()
     Loop and call status()
  2. status()
     As above
  3. execute()
     break the loop
  4. dispatch()
     Continue with the first path

No additional ways to bite.

Fix by avoiding the may_sleep reset when the player thread is on its
way to terminate: may not sleep and has its EOF indicator set.

Broken in commit 0a4d77e9, v4.3.23.

10 years agoFix pr_player() and upr_player() to obey max_idle
Markus Armbruster [Sun, 11 Mar 2012 14:07:48 +0000 (15:07 +0100)]
Fix pr_player() and upr_player() to obey max_idle

The output queue flush can block indefinitely.  Permits a client to
hog the thread indefinitely by not reading output.

Broken in commit 08b94556 (v4.3.20) "Reimplement max_idle without a
separate thread".  Until then, the idle thread aborted a stuck attempt
to flush output.

Denial of service seems possible.

10 years agoFactor player_output_some() out of pr_player(), upr_player()
Markus Armbruster [Sun, 11 Mar 2012 13:56:41 +0000 (14:56 +0100)]
Factor player_output_some() out of pr_player(), upr_player()

10 years agoFix recvclient() to obey max_idle for output, too
Markus Armbruster [Sun, 11 Mar 2012 11:35:18 +0000 (12:35 +0100)]
Fix recvclient() to obey max_idle for output, too

recvclient() flushes the output queue before receiving input.  The
receive obeys max_idle, the flush doesn't.

Broken in commit 08b94556 (v4.3.20) "Reimplement max_idle without a
separate thread".  Until then, the idle thread aborted a stuck attempt
to flush output.

10 years agoClean up how recvclient() deals with command abortion
Markus Armbruster [Sun, 11 Mar 2012 11:32:17 +0000 (12:32 +0100)]
Clean up how recvclient() deals with command abortion

We must not block in io_input() after command abortion unblocked
io_output().  Instead of checking player->aborted, compute the
deadline according to player->may_sleep, like we do for io_output().

10 years agoFix player_login() to obey max_idle for output, too
Markus Armbruster [Sun, 11 Mar 2012 10:49:46 +0000 (11:49 +0100)]
Fix player_login() to obey max_idle for output, too

player_login() flushes the output queue before receiving input.  The
receive obeys max_idle, the flush doesn't.  Which means a client could
hog the thread indefinitely.

Broken in commit 08b94556 (v4.3.20) "Reimplement max_idle without a
separate thread".  Until then, the idle thread aborted a stuck attempt
to flush output.

Denial of service seems possible.

10 years agoFlush all output before reading a login command, not just some
Markus Armbruster [Sun, 11 Mar 2012 10:43:38 +0000 (11:43 +0100)]
Flush all output before reading a login command, not just some

Before, a client could theoretically make the output queue grow
without bounds.

10 years agoFix io_close() to obey deadline for output, too
Markus Armbruster [Sun, 11 Mar 2012 09:06:04 +0000 (10:06 +0100)]
Fix io_close() to obey deadline for output, too

A client can delay thread exit indefinitely by not reading output.
Broken in commit 08b94556 (v4.3.20) "Reimplement max_idle without a
separate thread".  Until then, the idle thread aborted a stuck attempt
to flush output.

Denial of service seems possible.

Note that commit 904822e3 moved flushing the output queue from
player_login() to io_close().  It also made io_close() wait for the
client to close the connection.  That wait obeys the deadline.

10 years agoAdd deadline support to io_output(), io_output_if_queue_long()
Markus Armbruster [Sun, 11 Mar 2012 08:04:44 +0000 (09:04 +0100)]
Add deadline support to io_output(), io_output_if_queue_long()

Replace parameter wait by deadline.  Non-zero wait argument becomes
(time_t)-1 argument, zero wait argument becomes zero deadline
argument.  No functional change, yet.

10 years agoSwitch io_close(), io_input() from timeouts to deadlines
Markus Armbruster [Sun, 11 Mar 2012 06:14:24 +0000 (07:14 +0100)]
Switch io_close(), io_input() from timeouts to deadlines

All users want deadlines.  Move the conversion from deadline to
timeout from callers to io.c, where it becoems an implementation

10 years agoUnbreak nightly build
Markus Armbruster [Sat, 31 Mar 2012 16:59:27 +0000 (18:59 +0200)]
Unbreak nightly build

The nightly build uses a gross hack to keep timestamps stable: it
replaces the system's time() by emp_time().  It doesn't replace other
time-related functions such as gettimeofday().  Works as long as we
don't mix hacked time with unhacked time.

The previous commit compares time gotten from gettimeofday() with time
gotten from time().  The nightly build's I/O timeouts become zero,
which makes login impossible.

Replace gettimeofday(), too.

10 years agoBase idle timeout on player->curup again, not current time
Markus Armbruster [Sat, 10 Mar 2012 12:51:39 +0000 (13:51 +0100)]
Base idle timeout on player->curup again, not current time

Idle timeout used to expire max_idle minutes after the last
player->curup update.  When we got rid of the idle thread in commit
08b94556 (v4.3.20), this got changed to "wait no more than max_idle
minutes for input".  Time spent computing and time spent blocked on
output no longer counts.  In particular, a connection can block
indefinitely on output since then.  Let's fix that.

Start with basing the input timeout on player->curup again.  The
missing output timeout will be added shortly.

Aside: since status() updates player->curup, the idle timer gets reset
when the update aborts a command.  Left for another day.

10 years agoReplace the per-iop input_timeout by per-function timeouts
Markus Armbruster [Sat, 10 Mar 2012 12:27:34 +0000 (13:27 +0100)]
Replace the per-iop input_timeout by per-function timeouts

Commit 08b94556 (v4.3.20) added io_open() parameter input_timeout.  It
applies to io_input() and, since commit 904822e3, to io_close().  Add
timeout parameters to these functions instead.

10 years agoClean up io_input() for the "no input available" case
Markus Armbruster [Sat, 10 Mar 2012 10:13:08 +0000 (11:13 +0100)]
Clean up io_input() for the "no input available" case

Return zero when no input is available, regardless of parameter
waitforinput.  Before, it returned -1 with errno set to EAGAIN or
EWOULDBLOCK when not waiting for input.  Current callers all wait.

Drop errno from the function's contract, for consistency with

10 years agoFix buffer overflow in build
Markus Armbruster [Tue, 20 Mar 2012 19:28:46 +0000 (20:28 +0100)]
Fix buffer overflow in build

Remote hole, can smash the stack.  Broken when Empire 2 added the
confirmation prompt.

10 years agoFix buffer overflow in scrap and scuttle
Markus Armbruster [Tue, 20 Mar 2012 06:02:58 +0000 (07:02 +0100)]
Fix buffer overflow in scrap and scuttle

Remote hole, can smash the stack.  Additionally, the confirmation
prompt is misleading when the player supplies conditionals.  Redesign
the flawed prompt.

Broken when Chainsaw added the confirmation prompt.  Reported by Scott
C. Zielinski.

10 years agoFix execute's printing of the executed commands
Markus Armbruster [Thu, 15 Mar 2012 20:38:29 +0000 (21:38 +0100)]
Fix execute's printing of the executed commands

If execute's argument was read interactively, it prints the argument
instead of the command.  Else, it prints uninitialized garbage.  The
latter can theoretically crash the server, or leak information.

Broken in commit 3de1e8be, v4.3.28

10 years agoFix uninitialized variable use in defending land unit retreat
Markus Armbruster [Mon, 5 Mar 2012 11:57:33 +0000 (12:57 +0100)]
Fix uninitialized variable use in defending land unit retreat

lnd_take_casualty() uses uninitialized rsect to compute the mobility
cost of retreating a defending land unit.  This can charge incorrect
mobility, prevent retreat, or, if the stars align just right, crash
the server when sector_mcost() subscripts dchr[] with it.

Broken in commit 4e7c993a, v4.3.6.  Reported by Scott C. Zielinski.

10 years agoFix how play_cmd() ensures connection close
Markus Armbruster [Wed, 22 Feb 2012 13:30:58 +0000 (14:30 +0100)]
Fix how play_cmd() ensures connection close

play_cmd() needs to return in a state that makes player_login() break
the login command loop.

play_cmd() assumes player_main() always returns in such a state:
connection's EOF indicator set.  Unfortunately, the assumption is
wrong.  Fortunately, play_cmd() checks it, oopses and recovers.

player_main() can return with neiter error nor EOF indicator set,
e.g. when the game is down.

player_main() can return with just the error indicator set.  For
instance, when the client dies, io_input() detects ECONNRESET, sets
the error indicator and fails.

Broken in commit 8549efbc.  Fix by setting the EOF indicator silently
(without oopsing) when necessary.

10 years agoRestore amusing comment on naming of empmod.c
Markus Armbruster [Sat, 18 Feb 2012 19:57:42 +0000 (20:57 +0100)]
Restore amusing comment on naming of empmod.c

Got lost in 4.2.0.

10 years agoDrop C_MOD flag from commands that "obviously" don't need it
Markus Armbruster [Sat, 18 Feb 2012 17:09:34 +0000 (18:09 +0100)]
Drop C_MOD flag from commands that "obviously" don't need it

C_MOD prevents print functions from blocking.  The common reason for
wanting non-blocking prints are "read, print, write back" patterns.
There might be other reasons lurking in the code, and that's why
messing with C_MOD is scary.

Nevertheless, drop it from cutoff, headlines, land, lstat, motd,
neweff, payoff, qorder, sorder, and wall.  These commands have had
C_MOD "forever", even though they clearly don't modify game state.
They're all pretty simple.  Similar commands such as census, news,
ship, plane, nuke, sstat, pstat, flash never had C_MOD.

10 years agoNormalize command capability order in player_coms[] initializer
Markus Armbruster [Sat, 18 Feb 2012 16:14:37 +0000 (17:14 +0100)]
Normalize command capability order in player_coms[] initializer

No functional change.

10 years agoRevise money and capital command permissions
Markus Armbruster [Sat, 18 Feb 2012 15:49:53 +0000 (16:49 +0100)]
Revise money and capital command permissions

arm and disarm no longer require money, for consistency with the other
commands to move stuff around.

satellite no longer requires money, for consistency with lookout,
radar, sonar and skywatch.

qorder, sorder, survey and test no longer require a capital, for
consistency with the other commands that report on stuff the player

start and stop no longer require a capital, for consistency with the
other commands to control production.

fortify now requires a capital, for consistency with mission, morale
and range.

10 years agoRevise nation status command permissions
Markus Armbruster [Sat, 18 Feb 2012 15:19:59 +0000 (16:19 +0100)]
Revise nation status command permissions

Create new command capability NONVIS.  Give it to players in any state
except visitors (and STAT_UNUSED, but those must not exist).  This
makes it possible to have commands available to anyone but visitors.

Command change fails when the player is a visitor.  Simply make it
unavailable instead, by requiring NONVIS.

Make read unavailable to visitors, because it's useless: visitors
can't receive telegrams (typed_wu() fails).

Make census, commodity and sinfra unavailable to visitors.  Visitors
don't normally have sectors.

Make map and nmap unavailable to visitors.  Visitors don't have sectors,
so their maps are always empty.

Make them unavailable to new players (between add and newcap) and
players in sanctuary, too.  This is consistent with all the other
commands to examine the environment.  It also prevents people from
trying multiple unbroken countries in a blitz to find the one with the
nicest vicinity.

Make resource available to new players, for consistency with census
and commodity.

Make country, echo and financial available to anyone.

10 years agoClean up c_permit values of deity commands
Markus Armbruster [Sat, 18 Feb 2012 14:00:57 +0000 (15:00 +0100)]
Clean up c_permit values of deity commands

A player may execute a command when his player->nstat has all the bits
in the command's c_permit.

Normal player commands require bit(2).  Command break requires bit(1),
and execute requires bit(5).  Deity commands require both bit(2) and
bit(3).  Works, because deities always have both bits set in nstat, as
they may execute normal player commands, too.  But it's a bit
confusing.  Change them to only require their own bit(3).

10 years agoDrop useless nstat value VIS
Markus Armbruster [Sat, 18 Feb 2012 12:55:58 +0000 (13:55 +0100)]
Drop useless nstat value VIS

A player may execute a command when his player->nstat has all the bits
in the command's c_permit.

All commands require bit(0).  All players always have it.  Silly; get
rid of it.

10 years agoClean up info sect on highlighting
Markus Armbruster [Sat, 18 Feb 2012 11:52:49 +0000 (12:52 +0100)]
Clean up info sect on highlighting

Don't say selected sectors "show up in reverse video", that depends on
the client.  Just say "will be highlighted", like we do for the other
commands that highlight, e.g. info survey.

10 years agoread can print telegram without header after deletion prompt
Markus Armbruster [Sat, 18 Feb 2012 09:04:06 +0000 (10:04 +0100)]
read can print telegram without header after deletion prompt

rea() loops if more telegrams arrive while we wait for the player to
confirm deletion.  If the first new one is a continuation of the last
old one, its header is suppressed.  Don't do that.

Broken in commit 17223e8f, v4.3.29.

10 years agoFix 'm' in path argument of explore, move, transport
Markus Armbruster [Sat, 11 Feb 2012 08:51:46 +0000 (09:51 +0100)]
Fix 'm' in path argument of explore, move, transport

Two related bugs:

* It moans about deprecated argument syntax ('m' without a space
  before its argument) even when there's no argument.

* It uses the third instead of second argument for map flags (second
  argument is ignored): "m# s" doesn't show ships, and "m# s p" shows
  planes instead of ships.

Broken in commit 28d48474, v4.3.27.

10 years agoClarify buytax econfig doc string
Markus Armbruster [Sat, 11 Feb 2012 08:01:30 +0000 (09:01 +0100)]
Clarify buytax econfig doc string

Reported by Scott C. Zielinski.

10 years agoPolish the bulletin the seller gets after a unit sale
Markus Armbruster [Thu, 9 Feb 2012 18:40:26 +0000 (19:40 +0100)]
Polish the bulletin the seller gets after a unit sale

10 years agoMake market command unavailable to visitors, and set C_MOD flag
Markus Armbruster [Wed, 8 Feb 2012 18:11:12 +0000 (19:11 +0100)]
Make market command unavailable to visitors, and set C_MOD flag

The market command executes all trades that have become ready, by
calling check_market() and check_trade().  This modifies game state,
but market lacks C_MOD.  That's wrong.  But can it do harm?

Turns out yes.  check_trade() looks safe, but check_market() telexes
seller and buyer while holding a copy of the commodity struct.  If
this telexes the player who sent the market command, and he has
NF_INFORM on, the telegram notification may yield the processor.  It
then writes back its copy, triggering a generation oops.  Any updates
made by other threads meanwhile are wiped out, triggering a seqno
mismatch oops.

This can cause commodity trades to be executed multiple times,
multiplying the sold commodities.  Abuse seems tricky, but possible:
conspiring trade partners trade commodities back and forth to multiply
them.  One of them needs to get the output backlog just right to make
the telegram notification yield, and the timing right so that the
MarketUpdate thread or another player's buy, market, reset, sell, set
or trade command runs check_market() before his thread resumes.

Closely related bug: visitors can trigger execution of trades by means
of command market.  That's clearly inappropriate.

Broken in Empire 3.  Reported by Scott C. Zielinski.

10 years agoClarify what happens when the player aborts commands
Markus Armbruster [Tue, 7 Feb 2012 06:26:57 +0000 (07:26 +0100)]
Clarify what happens when the player aborts commands

10 years agoFix market not to expropriate sellers of units
Markus Armbruster [Sun, 5 Feb 2012 18:31:35 +0000 (19:31 +0100)]
Fix market not to expropriate sellers of units

When a ship, plane, land unit or nuke is sold, the seller is replaced
by POGO: POGO gets the money, the telegrams and makes the news.
Likewise when a sale fails because the buyer can't pay.

Broken in commit 94a3108b, v4.3.17.  Reported by Scott C. Zielinski.

10 years agoFix server shutdown to let player output drain properly
Markus Armbruster [Sun, 29 Jan 2012 11:06:30 +0000 (12:06 +0100)]
Fix server shutdown to let player output drain properly

Commit 1e1dfc86 (v4.3.23) attempted to do this, but it's flawed.

Server shutdown makes the player command loops terminate.  Each player
thread then flushes buffered output and closes the server's end of the
connection.  The client eventually gets EOF, and closes its end of the
connection.  All is well.

However, if the client sends more input after the server closed its
end of the connection, but before it completed receiving server
output, it gets ECONNRESET, and the remaining output is lost.

Instead of closing the server's end of the connection, we need to shut
down its transmission direction, then wait for the client to close its
end, by receiving client input until EOF.  Do that in io_close().

The output flushing in player_login() is now superfluous.  Remove it.

Make shutdwn() wait for the io_close() to complete instead of output
queues to drain.  Without that, we could still close the server's end
of the connection prematurely, through program termination.  Change
player_delete() to keep the player in Players until after io_close()
completes, so that shutdwn() can detect completion.

10 years agoClean up how quit and server shutdown trigger connection close
Markus Armbruster [Sun, 29 Jan 2012 09:44:28 +0000 (10:44 +0100)]
Clean up how quit and server shutdown trigger connection close

Simply set the player connection's EOF indicator.  Cleaner than
setting player->state to PS_SHUTDOWN from random places.

Move the assignment of PS_PLAYING from player_main() to its caller
play_cmd(), so that player->state is exclusively controlled in

10 years agoFix login command quit to really quit
Markus Armbruster [Sun, 29 Jan 2012 09:34:47 +0000 (10:34 +0100)]
Fix login command quit to really quit

quit_cmd() calls io_shutdown() to make player_login()'s next command
read detect EOF.  io_shutdown() drains the input queue and shuts down
the socket with shutdown().  player_login()'s next io_gets() fails all
right, but then io_input() *can* read more from the socket on my Linux
box, at least when I send plenty of input fast.  Thus, we ignore
whatever input after quit was already queued, then resume reading
commands, not necessarily at the beginning of a line.

Fix by setting the EOF indicator instead.

10 years agoFix idle timeout during execute
Markus Armbruster [Sun, 29 Jan 2012 07:52:30 +0000 (08:52 +0100)]
Fix idle timeout during execute

Timeout during execute gets handled just like an EOF cookie: end the
batch file, resume reading normal commands.  That's wrong, we need to
close the connection.

A real EOF is recorded in the player's connection's EOF indicator.
Let's use that for all "connection needs to be closed" conditions, so
they all work the same.  Create io_set_eof() to provide access.

Make recvclient() set the player connection's EOF indicator on
timeout.  This makes the timeout "stick".  Record receipt of an EOF
cookie in new struct player member got_ctld.  Also abort the command,
as before.  This leaves further interpretation of the EOF cookie to
the command loops.

Make player_main() set the player connection's EOF indicator on
got_ctld.  Player connection gets closed on on EOF cookie, as before.

Change execute() to break the batch command loop when got_ctld is set,
then reset it.  Ends the batch file on EOF cookie, as before.

Change status() back to checking EOF and error indicators (partial
revert of commit 9c5854c8, v4.3.16), and drop struct player member

10 years agoMake execute yield the processor after every command
Markus Armbruster [Sun, 29 Jan 2012 07:41:54 +0000 (08:41 +0100)]
Make execute yield the processor after every command

A player sending execute script contents quickly could theoretically
get an unfair share of the server.  Missed in commit db6fd8da
(v4.2.22), which made only the normal command loop yield.

10 years agoSimplify recvclient() to return -1 for all failures
Markus Armbruster [Sat, 28 Jan 2012 16:49:20 +0000 (17:49 +0100)]
Simplify recvclient() to return -1 for all failures

Callers don't care.  Also fix some comments.

10 years agoDon't lose output when client shuts down input transmission
Markus Armbruster [Sat, 28 Jan 2012 15:48:08 +0000 (16:48 +0100)]
Don't lose output when client shuts down input transmission

player_login() skips sending C_EXIT and flushing server output when
io_eof() is true.  That's the case after a read from the socket
returned zero, which means the client has shut down transmission on
his socket, or closed it.  If it's the former, then dropping output
like that is bad.  Our client never does that, but others might.

Condition was introduced in Empire 2, don't know why.

10 years agoShow treasury status on EOF, quit, shutdown
Markus Armbruster [Sat, 28 Jan 2012 14:34:25 +0000 (15:34 +0100)]
Show treasury status on EOF, quit, shutdown

status() informs the player of non-trivial command costs and earnings,
and when he goes broke or becomes solvent.  However, this is skipped
when the command gets aborted by the player signalling EOF, or by
server shutdown, and after a quit command.

Fix by moving the check for EOF or shutdown down to the may_play_now()

This looks a bit like it would also fix charging of play time.  But
that's not broken, because player_main() charges, too.

10 years agoFix client's command abort at beginning of first input line
Markus Armbruster [Thu, 26 Jan 2012 19:46:42 +0000 (20:46 +0100)]
Fix client's command abort at beginning of first input line

Commit 3cceb59b (v4.3.26) fixed the client to abort commands reliably
on ^C, even when it arrives at the beginning of an input line.  Except
it didn't work at the beginning of the first input line, because
input_eol was initialized to zero.

Easily fixed, but "end of line" isn't quite right there.  Revert sense
and rename to partial_line_sent.

10 years agoSimplify journal_entry_pr(), rename to journal_entry_write()
Markus Armbruster [Sat, 21 Jan 2012 15:48:53 +0000 (16:48 +0100)]
Simplify journal_entry_pr(), rename to journal_entry_write()

journal_entry_pr(S, N) writes up to N characters from zero-terminated
string S.  journal_input() passes -1 for N to write all characters.
Unclean.  SIZE_MAX would do, but it's C99, and MSC doesn't provide it.

Simplify journal_entry_pr() to write exactly N characters.  This makes
it more similar to write() than to pr(), therefore rename.

10 years agoPut home page URL into configure --help
Markus Armbruster [Sat, 21 Jan 2012 09:44:57 +0000 (10:44 +0100)]
Put home page URL into configure --help

10 years agoBump version to 4.3.30
Markus Armbruster [Sat, 21 Jan 2012 09:12:42 +0000 (10:12 +0100)]
Bump version to 4.3.30

10 years agoFinal change log polish for 4.3.29 v4.3.29
Markus Armbruster [Fri, 20 Jan 2012 19:21:37 +0000 (20:21 +0100)]
Final change log polish for 4.3.29

10 years agoUpdate change log for 4.3.29
Markus Armbruster [Sun, 15 Jan 2012 18:47:04 +0000 (19:47 +0100)]
Update change log for 4.3.29

10 years agodrop and fly from carrier can fail to load last civ or mil
Markus Armbruster [Sat, 26 Nov 2011 21:48:28 +0000 (22:48 +0100)]
drop and fly from carrier can fail to load last civ or mil

pln_equip() refuses to abandon its base sector.  Unfortunately, it
checks even when flying off carriers, and refuses to load the last
civilian or military depending on what happens to be in uninitialized
variable sect.

Broken in commit 91139692, v4.3.0.

10 years agoClean up journal_open() to open the journal write-only
Markus Armbruster [Sat, 26 Nov 2011 19:25:04 +0000 (20:25 +0100)]
Clean up journal_open() to open the journal write-only

We don't actually need update mode.

10 years agoClean up read to open telegram file read-only
Markus Armbruster [Sat, 26 Nov 2011 15:45:01 +0000 (16:45 +0100)]
Clean up read to open telegram file read-only

Update mode hasn't been necessary since 4.0.11 dropped use of

10 years agoCheck for mailbox creation failure
Markus Armbruster [Sat, 26 Nov 2011 15:06:01 +0000 (16:06 +0100)]
Check for mailbox creation failure

Deity command add logs the failure, utility program files reports it
and exits unsuccessfully.  Before, this failure was silently ignored.

10 years agoFactor mailbox_create() out of nat_reset() and files.c
Markus Armbruster [Sat, 26 Nov 2011 15:01:51 +0000 (16:01 +0100)]
Factor mailbox_create() out of nat_reset() and files.c

10 years agoChange read and wire to never delete a corrupt mailbox
Markus Armbruster [Wed, 23 Nov 2011 19:24:51 +0000 (20:24 +0100)]
Change read and wire to never delete a corrupt mailbox

Before, rea() deleted the mailbox regardless of errors.  Acceptable
only when the user gets a chance to avoid that after the problem is
reported.  Not the case for "read y".

Not an issue for announcements, but treat them the same for

10 years agoClean up how read deals with new telegram arrivals
Markus Armbruster [Wed, 23 Nov 2011 18:56:24 +0000 (19:56 +0100)]
Clean up how read deals with new telegram arrivals

Fooling around with the file size is silly.  It works only because
read has flag C_MOD set, so they can only arrive while we're sitting
at the delete confirmation prompt, not during reading.

Simply try to read more telegrams instead.

10 years agoChange wire not to read more after confirming deletion
Markus Armbruster [Wed, 23 Nov 2011 06:34:19 +0000 (07:34 +0100)]
Change wire not to read more after confirming deletion

Telegram deletion deletes the mailbox.  If more telegrams arrive while
we wait for the player to confirm deletion, the mailbox again contains
unread telegrams, so we can't just delete it.  Instead, rea() loops to
read the new telegrams.

Announcements worked the same until Empire 3 put them in a single file
shared by all.  Since then, deleting announcements merely updates
nat_annotim, and there's no need to read new announcements after
getting the player's confirmation.  So don't.

10 years agoLimit telegram squashing to 5s total
Markus Armbruster [Mon, 21 Nov 2011 19:38:02 +0000 (20:38 +0100)]
Limit telegram squashing to 5s total

Before, only the time between adjacent telegrams was limited, not the
total time.

10 years agoDon't lie "You have a new telegram" after read with inform off
Markus Armbruster [Mon, 21 Nov 2011 19:07:48 +0000 (20:07 +0100)]
Don't lie "You have a new telegram" after read with inform off

Here's how telegram notification works with NF_INFORM off: typed_wu()
increments the telegram recipient's nat_tgms.  status(), running right
before command prompts, notifies the player when nat_tgms > 0, and
resets it.  Thus, we tell the player how many telegrams arrived since
the previous command prompt.

However, what we really want is something else, namely the number of
"new telegrams waiting".  That's what the notification message says,
after all.  Telegrams already printed by read shouldn't count, even
when they arrived since the previous command prompt.

Make them not count by clearing pending telegrams on read regardless
of toggle inform.

Same for announcements.

10 years agoFix telegram notifications during read (toggle inform on)
Markus Armbruster [Mon, 21 Nov 2011 19:05:45 +0000 (20:05 +0100)]
Fix telegram notifications during read (toggle inform on)

Reset number of pending telegrams before delete prompt instead of

Before, the client claimed pending telegrams at that prompt, because
it wasn't C_INFORMed of the read, yet.  Worse, if more telegrams
arrived while sitting at the prompt, the reset clobbered their number
and sent a bogus clear C_INFORM message, effectively hiding the new
arrivals from the player.

10 years agoFix wire not to clear pending telegrams with toggle inform on
Markus Armbruster [Mon, 21 Nov 2011 06:26:02 +0000 (07:26 +0100)]
Fix wire not to clear pending telegrams with toggle inform on

Broken since Empire 2 introduced toggle inform.

10 years agoFix pending anno count for annos squashed together
Markus Armbruster [Mon, 21 Nov 2011 06:20:01 +0000 (07:20 +0100)]
Fix pending anno count for annos squashed together

Adjacent announcements are squashed together when the sender is the
same and the timestamp is "close enough".  Except typed_wu()
increments natstr member nat_ann regardless.  Fix that to work exactly
like nat_tgms.

10 years agoFix read not to split production report when update is slow
Markus Armbruster [Mon, 21 Nov 2011 06:26:02 +0000 (07:26 +0100)]
Fix read not to split production report when update is slow

Adjacent telegrams are squashed together if type and sender are the
same, and the timestamp is "close enough".  This is done in two
places: rea() and typed_wu().  They're inconsistent: typed_wu()
ignores the timestamp for production reports since Empire 2, but rea()

Record typed_wu()'s decision in new telstr member tel_cont.  Use it in

10 years agoSimplify how typed_wu() counts telegrams
Markus Armbruster [Sun, 20 Nov 2011 19:14:00 +0000 (20:14 +0100)]
Simplify how typed_wu() counts telegrams

typed_wu() counts telegrams to update nat_tgms and, since Empire 2,
send C_INFORM messages.  Adjacent telegrams are squashed together if
type and sender are the same, and the timestamp is within TEL_SECONDS.

typed_wu() increments nat_tgms when it sends a telegram that read
doesn't squash into the previous one.

Since Empire 2, it also sends a C_INFORM message then.  Inexplicably,
it fails to use the same condition: it tests just new_tele, not
new_tele || np->nat_tgms == 0.  C_INFORM messages got missed, until
4.0.18 made rea() call clear_telegram_is_new().  Convoluted.

Send C_INFORM exactly when incrementing nat_tgms, and back out
4.0.18's fix.

10 years agoFix clear_telegram_is_new() for TEL_NORM from POGO at the epoch
Markus Armbruster [Sun, 20 Nov 2011 18:26:20 +0000 (19:26 +0100)]
Fix clear_telegram_is_new() for TEL_NORM from POGO at the epoch

Purely theoretical, of course.

10 years agoClean up how telegram_is_new() detects production report
Markus Armbruster [Sun, 20 Nov 2011 18:11:04 +0000 (19:11 +0100)]
Clean up how telegram_is_new() detects production report

Test for TEL_UPDATE, not update_running.

10 years agoMove clear_telegram_is_new() call to beginning of update
Markus Armbruster [Sun, 20 Nov 2011 17:30:39 +0000 (18:30 +0100)]
Move clear_telegram_is_new() call to beginning of update

The call was added in 4.2.5 "so that the next telegram is flagged as
new and not part of the update".  Since the update sends only
TEL_UPDATE telegrams (the previous commit restored that property), and
nothing else does, the next telegram is flagged as new automatically,
except when it's from the next update.  Document that, and move the
call to a more natural place.

10 years agoEnsure the update's production report isn't split by bulletins
Markus Armbruster [Sun, 20 Nov 2011 17:26:43 +0000 (18:26 +0100)]
Ensure the update's production report isn't split by bulletins

During the update, wu() sends TEL_UPDATE telegrams ("Production
Report") instead of TEL_BULLETIN telegrams, but typed_wu() has no such
logic.  It's used by tele(), which doesn't run during the update, and
mpr(), which may, e.g. called from ship or mission code used by
autonav or sail.  This inserts bulletins in the middle of the
production report, splitting it apart.

Happens since mpr() was added in Empire 2.  Before, only tele() used
typed_wu() directly, and everything else wu().

Change mpr() to use wu().

10 years agoSaner error handling in typed_wu()
Markus Armbruster [Sun, 20 Nov 2011 14:14:36 +0000 (15:14 +0100)]
Saner error handling in typed_wu()

Leave nat_ann, nat_tgm alone and return -1 on all errors.  Before,
only failed open was handled that way.  Failed write and close were
logged and ignored.  While there, improve the log messages a bit.

Note: the return value fix has little effect.  It makes tele() log the
failure, which is redundant.  Everything else goes through wu() and
ignores the value.

10 years agoDrop superfluous fseek() from rea()
Markus Armbruster [Sun, 13 Nov 2011 18:04:07 +0000 (19:04 +0100)]
Drop superfluous fseek() from rea()

10 years agoMake add require confirmation for unadvisable actions
Markus Armbruster [Sun, 6 Nov 2011 18:40:21 +0000 (19:40 +0100)]
Make add require confirmation for unadvisable actions

Deleting a country in state STAT_SANCT, STAT_ACTIVE or STAT_GOD is
risky, because any references to this country become dangling, which
makes ef_verify() unhappy.  For a reason: we may well have code that
isn't prepared for dangling references, and breaks.

Replacing a country that is being used is risky, because it can get us
into weird states.  For instance, replacing a player by a visitor can
result in a visitor that owns stuff.