Previously ISteamNetworkingSockets was plumbed through much more invasively.
But with the changes to callbacks, symmetric ocnnect mode, and P2P
connections automatically using internal loopback when sending to self,
now it is possible to implement ISteamNetworkingMessages much more as a
seperate layer on top.
ISteamnetworkingMessages is a P2P interface that is more like UDP. You don't
listen or connect, and you don't deal with connection handles. Instead, you
specify the remote address with each send call. The purpose of the API is to
make it easier to port UDP code to P2P. It's not currently part of the
opensource code, and has not yet been released in the Steamworks SDK. But I
probably will soon, once we have some good P2P example code. The previous
incarnations of the interface were kind of crap. I finally have something
worth releasing.
Now you can register standard function pointers, instead of deriving
from a special class. This means that Steam and the opensource code
can now work the same, so this fixed issue #124
This is a P2P feature for a common use case:
- The two peers are "equal" to each other. (Neither is clearly the "client"
or "server".)
- Either peer may initiate the connection, and indeed they may do this
at the same time
- The peers only desire a single connection to each other, and if both
peers initiate connections simultaneously, a protocol is needed for them
to resolve the conflict, so that we end up with a single connection.
Also added remote virtual port to ConnectP2PCustomSignaling
Also, copy over the declarations for functions that require SDR.
They are behind STEAMNETWORKINSOCKETS_ENABLE_SDR, so there is
no real reason to remove the code. It just creates merge conflicts.
On Steam these are only used internally, since we always have SDR
fallback. But without SDR fallback these will end up being the
mail failure code, if the connection fails.
This change includes many changes to improve P2P connections. I didn't
bother replaying them one at a time from perforce.
Changed the plumbing of how data packets are sent, using context structures
more. The main goal of these changes is to remove the assumption that data
packets are always sent/received on the currently selected transport. Also,
I removed two specialized end-to-end messages for ICE transport and SDR P2P
transport. Now all end-to-end packets are ordinary data packets (just without
any data). This is good because, for UDP, they are encrypted. (For SDR
connections we don't encrytpt them, because we want the relays to be able to
observe them and perhaps mutate them.) And is reduces the number of different
packet types and codepaths that need to be supported. This does have one
unfortunate downside: the receiver does not know which transport is used to
send dropped packets. So, any out-of-band checks on alternate transports,
which do not contain data, and are much more likely to drop (since the
transport is not selectged) will be observed as a gap in the end-to-end
sequence number. Oddly, the sender actually will have the more complete
picture (albeit after some delay), since he knows the outcome of every
single packet, and he knows what transport was used to send it.
Added a flag that can be used to indicate to the peer, "I am not using this
transport as my primary transport." My protocol does not have an explicit
nomination framework. Instead, any data packet that doesn't have this flag
is considered a nomination.
SNP now needs to remember what transport was used for each outgoing packet.
Added some plumbing so that I can collect data about how often ICE is
successful, how the routes compare to SDR, and if it fails, what progress
it made.
The ICE session interface offers more control over what kind of candidtes to
gather, and returns more detailed info about the candidates and route. The
goal here is to allow a semi-private mode. If you don't want to share your
public address with random Internet peers (to avoid getting DDoSed), but you
do want to get a LAN connection to any peers in your office / dorm (where LAN
broadcasts may not discover that you are on the same LAN), you can choose to
share only local addresses. This seems oddd to only share the "private"
address while keeping your "public" address a secret -- but in this case
the "private" address is actually more sensitive, and the public address is
the one that script kiddies would need to boot you. We are dealing with a
differet kind of thread here. The option to go totally private and disable
ICE completely, or only share relayed candidates, or only share public
addressses, are all still available, if the threat model is different.
When linking with Steam, these call ISteamNetworkingUtils functions, and
GCC complains if it hasn't seen that class. Even if you don't ever call
any of these functions, GCC doesn't like the fact it could not generate the
code if you were to do so. Not sure what the spec says, but it feels like
Visual Studio's approach makes more sense here.
These are really useful, and since everything inline, and calling functions
that we are already obligated to support, there is no extra maintenance
burden.
Derive TransportPopulateConnectionInfo on all the transports to
populate this field.
The ICE transport (the one we actually care about the most) is
unfortunately not fully plumbed up so that we know how we are relayed.
Will plumb that through soon.
The standalone library was defining some of the same symbols as the flat
interface in steam_api.dll, and this was leading to complications. Renamed
those functions, and they are not part of the "flat interface", they are just
global internal functions functions.
Added wrappers in the flat interface with the same name to pass thorugh. So
if the library is compiled with the flat interface (which we do in the
opensource version), no functions are removed and the flat interface stays the
same.
Steamworks SDK has found itself in a really bad place having to support ABIs
that differ on different platforms. That didn't matter in the days when
everybody compiled all of their binaries per platform, but it breaks the
"write once, run anywhere" ideal. We don't have to support old ABIs so let's
just pick a packing and use it everywhere. (But note that we do have stucts
with pointers in them, so our structs will vary between 32-bit and 64-bit.)
https://github.com/nxrighthere/ValveSockets-CSharp/issues/8
- Got WebRTC transport class started.
- Added steamwebrtc interface header. This is some work that SamL did for
Steamlink, to isolate all the webrtc build requirements from our code. I'm
not sure what the final version will look loike, but this is a good place to
start, since this library already exists and I can get a proof of concept
working. After we're working, I'll probably peel back the layers a bit and
refactor this, and then eventually figure out how to opensource that work.
- Added config values to set the STUN server list
- Bring in interfaces for custom signaling from Steamworks SDK.
- Promote some stuff related to ISteamNetworkingMessages to base class.
It is hidden behind STEAMNETWORKINGSOCKETS_HAS_DEFAULT_P2P_SIGNALING.
- Add STEAMNETWORKINGSOCKETS_ENABLE_SDR in a bunch of places.
- Add CSteamNetworkConnectionBase::AsSteamNetworkConnectionP2P so we
can compile without RTTI.
This is used to poll many connections in a single function call. Previously,
this was only possible if all of the connections were those accepted on the
same listen socket. (ReceiveMessagesOnListenSocket). But this left out at
least two important use cases with known users:
- If you create more than one listen socket (because there is more way to
contact your service, e.g. once for P2P and another for direct IP, and
another for relayed connections), then you could not poll all of the
connections efficiently.
- In P2P use cases, we may initiate many connections to peers, and we want
to poll all of them at once.
This change is relevant to: Issue #49, Issue #50, and issue #52. (But I don't
this it really "fixes" any of them.)
This is to try to limit what is exposed in a naive generic interface to allow
users to adjust config values, in a way that doesn't allow the user to break
the security in a trivial way.
Working towards being able to use this object in a new API to send messages
efficiently. (Issue #51.)
- Message objects are actually ref counted now.
- m_sender renamed to m_identityPeer
- Added a flags field. Now you can know if the received message was sent
reliable or not.
- Added inline protected destructor to enforce proper usage.
- Tweaked tons of comments
- When receiving a fragmented unreliable message, I found a place where we
were doing more memory allocations and memcpying than necessary and
optimized that.
Delete a #ifdef __cplusplus block. This whole file is using tons of C++
features. It was weird to have that one block have that #ifdef
Also: In ConnectionState_ProblemDetectedLocally and ConnectionState_FinWait,
don't try to take any action immediately. Just trigger an immediate wake up
call, and we will take that action back out in the main loop, where we know
what's higher up on the call stack and what is safe to do.
The only other currently supported cipher is the NULL cipher, which we want
for remote streaming because we don't want to pay cost to encrypt/decrypt
on mobile. But eventually we might want to add other ciphers, and this is
the mechanism to do it.
This required shuffling around the crypto handshake quite a bit, because we
want the app to be able to set configuration options on incoming cnonections
before accepting them.
The connection will be responsible for end to end stuff including encryption,
message fragmentation and reliability, etc. Transports deliver datagrams. A
transport is always associated with a single connection, but a connection may
have more than one transport, and may switch between transports over the course
of the connection lifetime.
The goal here is to have conenction types that can switch transport.
Specifically, we need to support a connection that can detect when peers
are on the same LAN and use ordinary UDP in that case, attempt NAT piercing
using STUN, and if that fails, then relay (either using TURN or SDR).
There is more work to be done here. For example, each transport almost
certainly has its own ping time and quality characeristics, so we probably ought
to track some stats there. (But our stats situation is already getting pretty
crazy, so maybe just track ping seperately).
This change also includes some changes relevant for Steam Remote Play
streaming, which is going to use this protocol for relayed connections.
(And eventualy, hopefully, for all connections.) For example, steam remote
play needs really high bandwidth and packet rate, and the tolerance for
sending the timing data for jitter tracking was too tight. I also need to
pass a "certificate" to a subprocess in a single blob, which actually includes
the private key.
This is a bit more wasteful, but it facilitates forward and backward
compatibility. If one peer is using an identity type that an old
peer doesnt' parse, they can still often communicate. The old peer
often doesn't need to really "understand" what the identity is.
Also fixed some parsing bugs in SteamAPI_SteamNetworkingIdentity_ParseString.
At least in the public header. This maximizes compatibility wth some old
toolchains. We may not support those toolchains for building the code,
but it's nice for them to at least be able to link with us and use our
public header.
Also:
- STEAMNETWORKINGSOCKETS_STEAM now mens "running on steam", not "running using
the steam client". STEAMNETWORKINGSOCKETS_STEAMCLIENT is for that.
- Refactored stats stuff, moved it into the namespace. At one point I thought
I might expose some stuff in a public interface. For now, keeping it internal.
- Removed concept of Steam "universe" from this branch of the code.
- Don't use OVERRIDE, override works.