The C++ standard doesn't require us to stuff multiple statements
onto the same line, so we should avoid this for readability reasons.
This is especially true if one of the statements is controlled and
others aren't.
- Each packet has a version field.
- Clients connecting to the netpuncher always send a request packet.
This allows the netpuncher to react differently depending on the
client's version.
- Encode packets as binary instead of ASCII. This allows adding fields
while maintaining compatibility.
With my fix from 9eb2478b2 ("C4NetIOUDP: Fix timeout during non-MC
connection"), C4NetIOUDP would send data packets to the master server
before the ConnOK packet. The server would then discard these data
packets, resulting in a one-second delay until retransmission.
The "normal" connection process is a three-way handshake (Conn->,
<-Conn, ConnOK->). When establishing a multicast connection, this
handshake is repeated via the MC address. However, the code always
expected that second handshake to happen and thus ran into a timeout on
the client in the non-MC case, repeating the handshake a second time. In
the end, it usually still worked as the server supports reconnecting,
but packets may be lost in the process.
A follow-up on a previous PR GH-41. The discussion in the forum can be
viewed at http://forum.openclonk.org/topic_show.pl?pid=33086.
Run clang-tidy (without auto, pass-by-value and using checks) to fix the
header files not modified in the previous PR.
Summary of the changes:
- C++11 member initialization.
- nullptr instead of 0 for pointers.
- override for functions declared virtual in base class.
- default trivial special member functions
Consolidate the include statements scattered across the code in accordance
with the comment in C4Include.h. The advantages are listed in the same
comment.
Furthermore, it follows llvm-include-order which is the logical
extrapolation of the project's style guideline wherever possible
(C4Include.h being the most-frequent exception).
Previously, the SReq packet would only be sent after receiving an
ID from the netpuncher. Instead, we can send the request as soon as the
C4NetIOUDP connection setup finishes.
With the IPv6 support, hosts now often list around 20 addresses.
However, most of these are local only and thus rarely result in a
successful connection. With the introduction of address sorting in
7d5596220 ("Sort addresses used for initial host connection",
2017-02-26), the connection succeeds with the first few addresses most
of the time.
This commit changes the initial connection process to start with only
the first four addresses. After 100 ms, it proceeds with the next four
addresses and so on. This should reduce the packet volume significantly
as the connection should be established after only one or two steps.
We may want to tweak the parameters if this turns out to make joining
slower in practise. In a "normal" setup, the first four addresses should
be the IPv6 privacy and stable addresses, and the next four addresses
should include the IPv4 addresses from masterserver and netpuncher.
100 ms are long enough to get an answer from the host and short enough
to not bother the player too much.
Instead of "Compiler" and "Decompiler", which make me look up what's
even going on each time I see them, use the standard terms "serializer"
and "deserializer".
With the addition of IPv6, some computers with lots of addresses are
reaching the old address limit of 20 addresses. We'll have to see how
this works out in practise. Maybe we'll have to do the connection in
stages to prevent sending out too many packets at once (like only
connecting to the first five addresses initially, then after a timeout
the next five, and so on).
Computers with multiple (possibly virtual) network adapters can have
tons of link-local fe80::/64 IPv6 addresses. Connections to those hosts
would run into a timeout before getting to public addresses behind the
link-local ones.
By sorting the address list, we can prioritize public IPv6 addresses if
supported by the client, then try IPv4 before working through the swamp
of link-local addresses.
After GameOver(), the global function CollectStatistics() is called
which in turn calls CollectStats() on all definitions and the Scenario.
The results are collected into a proplist and sent to the masterserver
as JSON.
The intended purpose is to collect statistics like weapon kill counts
and evaluate them across all online games to improve balancing.
We don't benefit at all from privacy addresses as we're publishing all
local addresses in any case. By preferring stable addresses, we can
avoid reconnection issues after the preferred address changes.
This API is defined in RFC5014, but apparently only implemented in
Linux.
In contrast to getifaddrs(), /proc/net/if_inet6 allows filtering
deprecated privacy addresses. As these addresses generally won't be
useful for new connections, there's no reason to include them and they
only cause unnecessary connection attempts.
On Windows, we cannot resolve addresses using getaddrinfo() before
initializing Winsock. By storing the address as string, the address
parsed later on.
Forcing a static address does not work for IPv6 where everyone has
multiple addresses that change over time. For example, adding a new
connection would fail if the preferred privacy address changes during
a game.
On Linux, all IPv6 sockets are dual-stack per default; on Windows, they
are not. It's still a good idea to set the option on Linux as well as
the default value can be changed.
When connecting via TCP, C4NetIO still creates IPv4 sockets, so no dual
stack option is required there.
It's not actually used anywhere, but it's not broken now!
This also moves the low-level and OS-specific GetLocalAddresses code to
C4NetIO where it's fitting better than in C4Network2Client.
We use ff02::1 as discovery multicast address.
This "all nodes" multicast address is good enough for discovery in the
local network as packets there are likely broadcasted over ethernet
anyways.