As long as symbol_by_value(), show_capab() and togg() support only
int, flags need to fit into int.
Not a problem in practice, because no machine capable of running
Empire has int narrower than 32 bits, and 32 bits suffice.
Some flags members are long instead of int: struct lchrstr member
l_flags, struct natstr member nat_flags, struct mchrstr member m_flags
are long. Waste of space on machines with long wider than int.
Change them to int.
Rearrange struct lchrstr and struct natstr to avoid holes.
We seed it with value of time(). It's the traditional way, but it
provides only a few bits of effective entropy when an attacker has a
rough idea when the program started.
Instead, seed with a kernel random number. If we can't get one, fall
back to a hash of gettimeofday() and getpid(). This should happen
only on old systems or Windows. Far worse than a kernel random
number, but far better than using time().
Note that fairland used to seed with time() + getpid() until commit
331aac2a (v4.2.20) dropped the getpid(), claiming it didn't improve
the randomness. Perhaps it didn't under Windows then, but it
certainly did elsewhere, so it was a regression.
Commit ee01ac19 (v4.3.23) enlarged player member hostaddr from 32 to
46 characters, but missed natstr member nat_hostaddr. player_main()
copies hostaddr to nat_hostaddr. Can overrun the destination, but
fortunately just into nat_hostname.
Impact:
* Can makes praddr() print only a suffix of the address. Used by play
command, for player messages during login and logout, and for
logging.
* Can make player_main()'s test for "same address as last time" fail,
causing extra "Last connection" messages.
* Matching against econfig key privip is not affected.
* Journal event login is not affected.
Deities can customize which commodities can be sold in table item.
Default is to allow anything but civilians and military. However,
this applies only to the commodity market, not to the unit market:
cargo of ships and land units is not restricted.
Make the two markets consistent: permit selling military by default,
forbid selling units carrying unsalable commodities. This outlaws
selling units carrying civilians by default.
Planes flying one-way with crew or cargo spread plague from their old
base to their new base. Planes dropping cargo spread plague from
their base to the drop's target sector.
New function reads and returns target sector/ship. Avoids reading the
target sector unnecessarily. Callers receive the target ship, not
just its number. Next commit will put it to use.
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.
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.
Issues:
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.
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.
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.
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.
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.
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).
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.
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
eof.
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()
doesn't.
Record typed_wu()'s decision in new telstr member tel_cont. Use it in
rea().