Secure Sockets: Frequently Asked Questions

Frequently asked questions about secure sockets.

1. Which of the following patterns for SecureDeviceAssociation creation is preferable on Xbox One, and why? a. Both peers initiate creation concurrently (bi-directional establishment) b. One peer initiates creation, and the second peer listens for creation completion (uni-directional establishment)
Uni-directional establishment of associations is strongly recommended. A side-effect of bi-directional creation (or really any case where multiple SecureDeviceAssociations between a pair of devices are established) is that any given CreateAssociationAsync operation may discover there are different potential network paths between the consoles that are more responsive at any particular moment. As a result, both sides racing with each other to establish their own initiated SecureDeviceAssociations can end up with two associations (even when CreateSecureDeviceAssociationBehavior::Reevaluate is not used,) and those associations may have selected different socket address pairs.

2. Can the socket address resolved by SecureDeviceAssociation::GetRemoteSocketAddressBytes() change for an established secure device association?
For any given secure device association, the API guarantees the reported socket address byte pairs used in that communication will remain the same for the life of secure device association.

Any changes in an association’s state are signaled through the StateChanged callback. The title can keep track of this state to know whether the system implicitly thinks that address pair is still valid for it to use. Note that the system is conservative in its “liveness” checks, and apps (or user experiences) will often use their own, shorter timeouts for considering a peer non-responsive.

3. What is the best way of comparing two SecureDeviceAssociation objects?
The best way to determine whether they represent associations to the same remote device is by retrieving their RemoteSecureDeviceAddress objects and calling SecureDeviceAddress::Compare on them. This will always return zero if the two represented devices are equal, or non-zero if not. This is not affected by any particular network path used.

4. What is the best way to map the SOCKADDR_STORAGE structure retrieved from a recvfrom call to a container of secure device association objects tracked by the title?
As mentioned above, the socket address retrieved by GetRemoteSocketAddressBytes for an established secure device association will not change. So the best practice would be to cache mappings between the SOCKADDR_STORAGE objects and title objects which track the Secure Device Association objects. The SOCKADDR_STORAGE retrieved by recvfrom can then be compared with the cached SOCKADDR_STORAGE mappings (as opposed to invoking SecureDeviceAssociation::GetAssociationBySocketAddressBytes and then finding the title object by SecureDeviceAssociation on every receive).

Note, that you should not do a memcmp over the entire structure. You should confirm that the address family is AF_INET6 and then use the SOCKADDR_IN6.sin6_addr and sin6_port values for comparison. Currently on Xbox One, the sin6_flowinfo and sin6_scope_id fields are not considered important to uniqueness.

5. What ports should I be using for TCP communication?
We don’t typically recommend using TCP because it is optimized for reliability and bulk transfers rather than low latency peer-to-peer gaming. A “reliable UDP” protocol is typically better suited. However, for apps that wish to use TCP, best practice and the standard TCP pattern is to use port “0” for your TCP client port. This means that you should have two socket descriptors for TCP communication. The “server” descriptor will have “Accept” usage type and can bind to a fixed (non-reserved) port of your choosing. The “client” descriptor will have the “Initiate” usage type with the BoundPort specified as “0”. You do not actually need to call bind on the client socket before you can use it— the implicit bind performed by connect() will do this if it hasn’t been already.

If you do need to use a fixed port or range of ports for your TCP client, then you will need to call bind on the socket before you can use it to connect. You may also run into problems when disconnecting and reconnecting to the same server address because per protocol design, the previous socket will stay in the “TIME_WAIT” state for a default interval of 2 minutes even after it is disconnected and closed. If this affects you, consider setting the socket linger timer to a smaller interval (such as 0) by calling setsockopt with the SO_LINGER option and the linger structure with the parameters of l_onoff to 1 and l_linger to the desired interval.

6. Can I perform QoS probes while calling CreateAssociationAsync?
It not safe to call CreateAssociationAsync against an address that is also being QoS probed through MeasureQualityOfServiceAsync at the same time. These operations should only be performed sequentially against the same address.

7. What is the best practice for destroying a SecureDeviceAssociation?
Best practice is for titles to align their management of SecureDeviceAssociation lifetimes to their actual secure communication intent. If there is no longer traffic to be flowing on the SecureDeviceAssociation then destroying it is recommended. SecureDeviceAssociations are not terminated while a title is running unless DestroyAsync is explicitly called. There is a small CPU, memory, and network usage cost for active SecureDeviceAssociations but the OS has performance optimizations for scenarios with multiple unused associations.