Mark obsolete pages with '+' in subject pages. Drop the separate
"Obsolete" subject page: move "info Innards" to subject "Server", and
"info update" to "Updates" (where it came from in commit a5764534,
v4.3.10).
For instance, use "127.0.0.1" for IPv4 loopback instead of
"::ffff:127.0.0.1".
Simplifies use of econfig key privip: plain dotted decimal now just
works regardless of IPv6 use, no need to add the IPv4-mapped form.
Also affects how addresses are logged and shown to players, and nation
selector ip. Nicer that way.
Systems using GNU libc such as Linux are frequently configured in a
way getaddrinfo(NULL, ...) put the IPv4 wildcard "0.0.0.0" *before*
the IPv6 wildcard "::" in the result. Because of that, listen_addr ""
listens only on all IPv4 addresses. Workaround: listen_addr "::".
Document it in listen_addr's doc string.
OpenBSD refuses to implement IPV6_V6ONLY, in violation of RFC 3493.
RFC 4038 frowningly recognizes this practice. The only way to bind
both IPv4 and IPv4 there is two separate sockets. Requires more
surgery than I can do now.
Since we can't have both IPv6 and IPv6 on OpenBSD with our single
socket, prefer IPv4, but if that doesn't work, do IPv6.
To prefer IPv6 instead, put 'listen_addr "::"' into econfig. Document
that in listen_addr's doc string.
We rely on AF_INET6 wildcard bind() binding the AF_INET port, too,
i.e. IPV6_V6ONLY off. This should be the default according to RFC
3493 section 5.3, but isn't on Windows and BSD. RFC 4038 recognizes
this fact in section 4.2.
When IPV6_V6ONLY is on, an AF_INET6 wildcard bind only accepts
connections from IPv6 addresses. Thus, IPv4 doesn't work when
getaddrinfo() returns an AF_INET6 address first (which it should do
when the system has an IPv6 address configured).
Switch off IPV6_V6ONLY explicitly instead of relying on the default.
This makes IPv6 work on systems where IPV6_V6ONLY is on by default,
such as Windows and BSD.
Except for OpenBSD, which does not support switching it off. To be
addressed in the next commit.
Shouldn't fail. If it fails, but bind() works, the failure doesn't
matter. If bind() fails, we can just as well report that failure
instead of setsockopt()'s.
How qsort() sorts members that compare equal is unspecified. Can
upset the smoke test. Observed under FreeBSD 8.3.
Break ties in power by comparing country numbers. Countries equal in
power are now sorted by increasing country number.
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.
The smoke test waits for the server completing startup by trying to
connect until it works. Hangs if the server doesn't complete startup
for some reason. Make it give up after 5s.
Likewise, The smoke test waits for the server to terminate by trying
kill -0 until it fails. Hangs if the server doesn't terminate. Make
it give up after 5s.
Lots stay on the market until there's a bid and bidding time expires.
When the highest bidder changes, and less than five minutes of bidding
time are left, it gets extended by five minutes (since 4.0.7, actually
works since 4.0.9).
Normally, this ensures that the competition has at least five minutes
to react. Except when this is the first bid, bidding time may have
expired already. If it expired less than five minutes ago, the
competition still gets time to react, just less than it should. If it
expired earlier, the sale is executed immediately for units. For
commodities, the bidding time is set to expire in five minutes (since
4.2.0).
Instead of extending bidding time by five minutes, set it to expire in
five minutes, both for commodities and for units.
check_trade() converts the price to float, which can lose precision,
although only for ridiculously high prices. Has been broken since
4.0.0 introduced the market.
Avoid the conversion. Bulletins now show pre-tax price as $N instead
of $N.00.
Code dealing with money mixes int and long pretty haphazardly.
Harmless, because practical amounts of money fit into int on any
machine capable of running the server. Clean up anyway.
meltitems() computes #items * etus per update * fallout in type long.
Theoretical maximum is ITEM_MAX * etus * FALLOUT_MAX = 99980001 *
etus. Can overflow 32 bits for etus > 21. Has been broken since the
introduction of fallout in KSU.
Compute the product in double instead.
Code dealing with reserves mixes int and long pretty haphazardly.
Harmless, because practical reserves fit easily on any machine capable
of running the server. Clean up anyway.
Code dealing with counting people mixes int and long pretty
haphazardly. Harmless, because practical populations fit into int
easily on any machine capable of running the server. Clean up anyway.
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.
ef_ensure_space() oopses on negative ID, but succeeds anyway. edit()
proceeds to ef_write(), which neglects to check for negative ID.
Since the ID isn't in the cache, it then passes a NULL old element to
callback prewrite(), which crashes.
Fix ef_ensure_space() to fail on negative ID. Commit 5173f8cd
(v4.3.0) made it oops, but neglected to make it fail.
Fix ef_write() to oops and fail on negative ID.
ef_write() still passes NULL old element to prewrite() when the ID
isn't in the cache. Doesn't actually happen, because we use
prewrite() callbacks only with fully cached tables. Fragile. Make
ef_open() fail when that assumption is violated.
Newly built ships and land units are given to the player, planes and
nukes to the sector owner. Matters only for deities, because only
deities can build in foreign sectors. Stupid all the same.
This has always been inconsistent. Empire 1 gave ships and nukes to
the player, and planes to the sector owner. Chainsaw 3 added land
units, and gave them to the player. Empire 2 changed build to give
nukes to the sector owner.
Building doesn't work when the unit built is given to POGO, because
giving a unit to POGO destroys it. When build gives to the sector
owner, deities can't build in unowned sectors. When build gives to
the player, POGO can't build at all. That's more limiting, so change
build to always give to the sector owner.
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.
random() may yield different pseudo-random number sequences for the
same seed on another system. For instance, at least some versions of
MinGW provide a random() in -liberty that differs from traditional BSD
(see commit c8231b12). Rather inconvenient for regression testing.
MT19937 Mersenne Twister is a proven, high-quality PRNG. Actual code
is reference code provided by the inventors[*]. Quick tests show
performance comparable to random().
Like random(), MT is not cryptographically secure: observing enough of
its output permits guessing its state, and thus its future output. I
don't think players can do that.
Drop the copy of BSD random() we added for Windows.
Like the previous commit, this changes the server's die rolls, and
makes fairland create a different random map for the same seed. Update
expected smoke test results accordingly.
[*] mt19937ar.sep.tgz downloaded from
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html
"random() % n" is sound only when n is a power of two. The error is
hardly relevant in Empire, because random() yields 31 bits, and our n
are always much smaller than 2^31. Fix it anyway.
Use smallest the 2^m >= n instead of n, and discard numbers exceeding
n.
Bonus: faster for me even in the worst case n = 2^m+1.
Like the recent change to damage(), this changes some of the server's
die rolls, only this time the effect is pretty pervasive. Worse,
fairland now creates a completely different random map for the same
seed. Update expected smoke test results accordingly.
Turns damage() into a one-liner.
damage() now uses random() % 32768 in chance() instead of random() %
100 inline, therefore can round differently for the same pseudo-random
number. Update expected smoke test results accordingly.
Aside: "random() % n" distributes evenly only when n is a power of
two. 100 isn't. However, because random() yields at least 31 bits,
and 100 is so much smaller than 2^31, the error is vanishingly small.