Kawe Mazidjatari b3a68ed095 Add EABase, EAThread and DirtySDK to R5sdk
DirtySDK (EA's Dirty Sockets library) will be used for the LiveAPI implementation, and depends on: EABase, EAThread.
2024-04-05 18:29:03 +02:00

298 lines
22 KiB
C

/*H********************************************************************************/
/*!
\File qoscommon.h
\Description
This code declares shared items between client and server of the QOS system.
\Copyright
Copyright (c) 2017 Electronic Arts Inc.
*/
/********************************************************************************H*/
#ifndef _qoscommon_h
#define _qoscommon_h
/*** Include files ****************************************************************/
#include "DirtySDK/platform.h"
#include "DirtySDK/dirtysock/dirtyaddr.h"
#include "DirtySDK/dirtysock/dirtynet.h"
/*** Defines **********************************************************************/
#define QOS_COMMON_HMAC_TYPE (CRYPTHASH_SHA256) //!< a secure strong hashing algorithm
#define QOS_COMMON_HMAC_SIZE (32) //!< CRYPTSHA256_HASHSIZE
#define QOS_COMMON_SECURE_KEY_LENGTH (16) //!< length of random data as key, in generation of hmac
#define QOS_COMMON_SIZEOF_PROBE_DATA (45) //!< total byte count of probe, excluding hmac
#define QOS_COMMON_PROBE_PROTOCOL_ID ('qos2') //!< probe packets will all start with this to identify them as being the QOS 2 protocol
#define QOS_COMMON_PROBE_VERSION_MAJOR (2) //!< identifies changes to QosCommonProbePacketT, 2 bytes, first byte indicates api breaking
#define QOS_COMMON_PROBE_VERSION_MINOR (0) //!< second byte compatible bug fixes.
#define QOS_COMMON_PROBE_VERSION ((QOS_COMMON_PROBE_VERSION_MAJOR << 8) | QOS_COMMON_PROBE_VERSION_MINOR) //!< the combined major, minor version bytes.
#define QOS_COMMON_MIN_PACKET_SIZE (QOS_COMMON_SIZEOF_PROBE_DATA + QOS_COMMON_HMAC_SIZE) //!< size of on wire representation of the probe packet
#define QOS_COMMON_MAX_PACKET_SIZE (SOCKET_MAXUDPRECV) //!< maximum probe/packet length
#define QOS_COMMON_MAX_PROBE_COUNT (32) //!< maximum probes per request
#define QOS_COMMON_MAX_SITES (32) //!< maximum sites we can test against at one time
#define QOS_COMMON_MAX_CONTROL_CONFIGS (6) //!< maximum number of QosClientControl selectors we can include in the request
#define QOS_COMMON_MAX_TESTS (4) //!< latency, bandwidthUP, bandwidthDown; and extra room for something we haven't considered
#define QOS_COMMON_MAX_RESULTS (QOS_COMMON_MAX_SITES * QOS_COMMON_MAX_TESTS) //!< highest number of possible results we can generate
#define QOS_COMMON_MAX_URL_LENGTH (256) //!< size used for URL strings
#define QOS_COMMON_MAX_RPC_STRING (128) //!< size used for typical strings
#define QOS_COMMON_MAX_RPC_STRING_SHORT (16) //!< size used for strings we expect to be very short
#define QOS_COMMON_MAX_RPC_BODY_SIZE (1024 * 200) //!< rpc messages should never exceed this size, raw results are our biggest message
#define QOS_COMMON_DEFAULT_RPC_BODY_SIZE (QOS_COMMON_MAX_RPC_BODY_SIZE / 10) //!< An amount of space that will usually be enough to receive an rpc message into
#define QOS_COMMON_CONTENT_TYPE ("application/grpc") //!< http content type, everything is protobuff
#define QOS_COMMON_SERVER_URL ("/eadp.qoscoordinator.QOSCoordinatorRegistration/registerServer") //!< used by server to register to the QOS server, and heartbeat to refresh its availability
#define QOS_COMMON_CLIENT_URL ("/eadp.qoscoordinator.QOSCoordinator/ClientCall") //!< used by client to request config and push back final results
// flags contained in probe packets
#define QOS_COMMON_PACKET_FLAG_LAST_PROBE (1) //!< set if the client expects this is the last packet in this test
/*** Macros ***********************************************************************/
/*** Type Definitions *************************************************************/
//! just enough space to hold a address family, port, and an v4 or v6 address. Used for storage or communicating address on the wire, never used to actually send/recv.
typedef struct QosCommonAddrT
{
union
{
union
{
uint8_t aBytes[16];
uint16_t aWords[8];
uint32_t aDwords[4];
}v6;
uint32_t v4;
}addr;
uint16_t uFamily;
uint16_t uPort;
} QosCommonAddrT;
//! describes the configuration for a particular QOS test
typedef struct QosCommonTestT
{
char strTestName[QOS_COMMON_MAX_RPC_STRING_SHORT]; //!< name of the test
char strSiteName[QOS_COMMON_MAX_RPC_STRING_SHORT]; //!< alias of target QOS server
uint16_t uProbeSizeUp; //!< minimum size of the probe, the probe will be padded with extra data to reach this size
uint16_t uProbeSizeDown; //!< minimum size of the probe, the probe will be padded with extra data to reach this size
uint16_t uTimeout; //!< maximum amount of time before giving up on completing the test
uint16_t uMinTimeBetwenProbes; //!< minimum amount of time between each probe sent from the client
uint16_t uTimeTillResend; //!< if we haven't got the expected number of responses back in this much time, we will send more probes
uint16_t uInitSyncTimeout; //!< the amount of time we might wait to synchronize all requests together
uint8_t uProbeCountUp; //!< number of probes to send to the server
uint8_t uProbeCountDown; //!< number of probes there server should respond with for each probe received
uint8_t uResendExtraProbeCount; //!< in the case of finding packet loss, we request the lost packets again with a few extras, to reduce the chance that those are lost too
uint8_t uAcceptableLostProbeCount; //!< typically we would receive (uProbeCountUp * uProbeCountDown) probes, this indicates how many less probes we can receive without triggering a re-send
} QosCommonTestT;
//! describes QosClientControl overrides that should be executed before doing any QosTests
typedef struct QosCommonControlConfigT
{
char strValue[QOS_COMMON_MAX_RPC_STRING]; //!< string value, such as QosClientControl(mQosClient, 'sprt', 0, strValue);
char strControl[5]; //!< dirty sdks four character code identifier, usually in the form of 'wxzy'
int32_t iValue; //!< integer value, such as QosClientControl(mQosClient, 'lprt', iValue, NULL);
} QosCommonControlConfigT;
//! describes a site, QOS Tests are performed against a QOS/ping Site
typedef struct QosCommonSiteT
{
char strSiteName[QOS_COMMON_MAX_RPC_STRING_SHORT]; //!< identifies where a site is, such as bio-sjc
char strProbeAddr[QOS_COMMON_MAX_RPC_STRING]; //!< url to communicate with the server
uint8_t aSecureKey[QOS_COMMON_SECURE_KEY_LENGTH]; //!< key used in generating hmac
uint16_t uProbePort; //!< port to use when communicating
uint16_t uProbeVersion; //!< the version the site is operating with
} QosCommonSiteT;
//! a collection of sites, control configs and tests to describe what actions the client should be taking
typedef struct QosCommonClientConfigT
{
QosCommonSiteT aSites[QOS_COMMON_MAX_SITES]; //!< list of sites that are potential targets
QosCommonControlConfigT aControlConfigs[QOS_COMMON_MAX_CONTROL_CONFIGS]; //!< list of control settings to be run before doing tests
QosCommonTestT aQosTests[QOS_COMMON_MAX_TESTS]; //!< list tests to be done
QosCommonAddrT clientAddressFromCoordinator; //!< the client must report its external address to the QOS server, the coordinator will initialize this to what it sees the clients address as
uint8_t uNumSites; //!< number of QosCommonSiteT contained in aSites
uint8_t uNumControlConfigs; //!< number of QosCommonControlConfigT contained in aControlConfigs
uint8_t uNumQosTests; //!< number of QosCommonTestT contained aQosTests
} QosCommonClientConfigT;
//!< a firewall or NAT (network address translation) indicates how difficult it is to make a connection with this location
typedef enum QosCommonFirewallTypeE
{
QOS_COMMON_FIREWALL_UNKNOWN,
QOS_COMMON_FIREWALL_OPEN,
QOS_COMMON_FIREWALL_MODERATE,
QOS_COMMON_FIREWALL_STRICT,
QOS_COMMON_FIREWALL_NUMNATTYPES //!< max number of NAT types, must be at the end
} QosCommonFirewallTypeE;
//! contains latency and bandwidth results for a given site
typedef struct QosCommonTestResultT
{
char strSiteName[QOS_COMMON_MAX_RPC_STRING_SHORT];
uint32_t uMinRTT;
uint32_t uUpbps;
uint32_t uDownbps;
uint32_t hResult;
} QosCommonTestResultT;
//! the coordinator will examine a QosCommonRawResultsT and produce usable QosCommonProcessedResultsT
typedef struct QosCommonProcessedResultsT
{
QosCommonTestResultT aTestResults[QOS_COMMON_MAX_SITES]; //!< an ordered list (by "best" site, coordinator's decision) of all test results
QosCommonAddrT clientExternalAddress; //!< this is the address the coordinator recommends using for communication to this client
QosCommonFirewallTypeE eFirewallType; //!< this is what the coordinator classifies the firewall type to be
uint32_t uNumResults; //!< number of results found in aTestResults
uint32_t uTimeTillRetry; //!< if this is != 0, the QOS server wants us to check back in this many ms for a new test
uint32_t hResult; //!< holds the error/status code of the request
} QosCommonProcessedResultsT;
//! the coordinator responds with configuration or results
typedef struct QosCommonCoordinatorToClientResponseT
{
QosCommonClientConfigT configuration; //!< what does the coordinator want the client to do
QosCommonProcessedResultsT results; //!< contains the processed data from the coordinator, this will be provided if there coordinator doesn't have more tests for the client to do
uint32_t uServiceRequestID; //!< number uniquely identifies this transaction taking place between client and coordinator
} QosCommonCoordinatorToClientResponseT;
//! sent to and from the QOS server as a udp probe, note QosCommonSerializeProbePacket and QosCommonDeserializeProbePacket determines on wire packing and order
typedef struct QosCommonProbePacketT
{
QosCommonAddrT clientAddressFromService; //!< initially the client address from coordinator, however address from server prospective takes precedence, used to authenticate the packet is coming from the address that generated it
uint32_t uProtocol; //!< QOS 2.0 packets will always contain 'qos2' for easy identification.
uint32_t uServiceRequestId; //!< provided by the QosCoordinator, unique to the client doing multiple QOS actions, used to identify which server resources this client is using
uint32_t uServerReceiveTime; //!< time the server received this probe from the client
uint16_t uServerSendDelta; //!< duration the server held onto the packet before sending the response probe, this is latency added by the server process
uint16_t uVersion; //!< uniquely identifies protocol
uint16_t uProbeSizeUp; //!< indicates how big this probe is, including any padding for bandwidth
uint16_t uProbeSizeDown; //!< indicates how big this probe is, including any padding for bandwidth
uint16_t uClientRequestId; //!< provided by the client, unique to a particular QOS action, used to pair request and responses together
uint8_t uProbeCountUp; //!< count index of this probe
uint8_t uProbeCountDown; //!< from client (number of probes there server should respond with for each probe received) from server (count index of this probe)
uint8_t uExpectedProbeCountUp; //!< number of probes the client expects to send to the sever in this test (assuming no packet loss)
} QosCommonProbePacketT;
//! a single QOS probe result information
typedef struct QosCommonProbeResultT
{
uint32_t uClientSendTime; //!< time the client initially sent this QOS probe
uint32_t uServerReceiveTime; //!< time the server received this probe from the client (note that server and client time are not in sync)
uint16_t uServerSendDelta; //!< duration the server held onto the packet before sending the response probe, this is latency added by the server process
uint16_t uClientReceiveDelta; //!< duration since sending before the client received response from the QOS server for this probe
} QosCommonProbeResultT;
//!< after the client performs the tests, raw results are provided to the coordinator for analysis
//! Its expected each QosCommonRawResultsT can be used to generate latency values, bandwidth values, with two QosCommonRawResultsT firewall values can be calculated
typedef struct QosCommonRawResultsT
{
QosCommonProbeResultT aProbeResult[QOS_COMMON_MAX_PROBE_COUNT]; //!< a list of individual probe timings
QosCommonAddrT clientAddressFromServer; //!< clients address from prospective of the QOS server
char strSiteName[QOS_COMMON_MAX_RPC_STRING_SHORT]; //!< identifies where a site is, such as bio-sjc
char strTestName[QOS_COMMON_MAX_RPC_STRING_SHORT]; //!< identifies which test, such as latency, bandwidthUp, bandwidthDown
uint32_t hResult; //!< holds the error/status code of the request
uint8_t uProbeCountUp; //!< number of probes the request sent when all retrying and everything is done (usually same as uProbeCountRequestedUp if no probes were lost, otherwise we send more)
uint8_t uProbeCountDown; //!< number of valid probes from this request that came back from the server (usually same as uProbeCountRequestedDown at the end unless an error or probes lost)
uint8_t uProbeCountHighWater; //!< the highest count of probe we receive back
//note, uProbeCountHighWater, uProbeCountDown, and uProbeCountUp aren't shared with the coordinator
} QosCommonRawResultsT ;
//! data the client will tell the coordinator about itself (aside from test results) to help it make its decisions
typedef struct QosCommonClientModifiersT
{
QosCommonAddrT clientAddressInternal; //!< address the client believes it is using
char strPlatform[QOS_COMMON_MAX_RPC_STRING_SHORT]; //!< a string describing which platform the client is
QosCommonFirewallTypeE eOSFirewallType; //!< the firewall type that the client OS suggests it might be
uint32_t uPacketQueueRemaining; //!< number of spots left in the packet queue after the client has done its tests, a 0 value indicates a problem
uint32_t uStallCountCoordinator; //!< number of stall events encountered when attempting to communicate with the coordinator
uint32_t uStallDurationCoordinator; //!< total duration of time spent stalled while communicating with the coordinator
uint32_t uStallCountProbe; //!< number of stall events encountered when attempting to send probes to the qos server
uint32_t uStallDurationProbe; //!< total duration of time spent stalled while communicating with the qos server
uint32_t hResult; //!< current error status of the QosClient module, can be used to report errors to the coordinator
} QosCommonClientModifiersT;
//! the client informs the coordinator of who it is and any results it has gathered in order to get configuration or processed "final" results
typedef struct QosCommonClientToCoordinatorRequestT
{
QosCommonRawResultsT aResults[QOS_COMMON_MAX_RESULTS]; //!< a set of raw results for each site, for each test performed
char strQosProfile[QOS_COMMON_MAX_RPC_STRING]; //!< a string describing which setting the coordinator should use for this title. (likely service name, like fifa-pc-2017)
uint32_t uServiceRequestID; //!< number uniquely identifies this transaction taking place between client and coordinator
uint32_t uNumResults; //!< number results in aResults, if the client has results to report
uint16_t uProbeVersion; //!< uniquely identifies protocol
QosCommonClientModifiersT clientModifiers; //!< a set of fields the client wants to share with the coordinator such as health information to use in decision process
} QosCommonClientToCoordinatorRequestT;
//! the QOS server will request to be registered with the coordinator
typedef struct QosCommonServerToCoordinatorRequestT
{
char strAddr[QOS_COMMON_MAX_RPC_STRING]; //!< url to communicate with the server
char strSiteName[QOS_COMMON_MAX_RPC_STRING_SHORT]; //!< location where this server resides ie bio-sjc
char strPool[QOS_COMMON_MAX_RPC_STRING]; //!< segregate servers at a given location, such as only fifa is using this server or only for special qa tests
uint8_t aSecureKey[QOS_COMMON_SECURE_KEY_LENGTH]; //!< key used to generate hmac
uint16_t uPort; //!< port to use when communicating
uint16_t uCapacityPerSec; //!< maximum number of clients the coordinator should send to the server per second
uint16_t uLastLoadPerSec; //!< number of qos tests started last second
uint16_t uProbeVersion; //!< the probe packet version this server will operate with
uint16_t uUpdateInterval; //!< amount of time in ms that the coordinator should wait before expecting the next heartbeat
uint8_t bShuttingDown; //!< indicates if this server has begun to shutdown, if so no more clients should be sent to this server
} QosCommonServerToCoordinatorRequestT;
//! registration message is for debug purpose only
typedef struct QosCommonCoordinatorToServerResponseT
{
char strRegistrationMessage[QOS_COMMON_MAX_RPC_STRING]; //!< message provided by the coordinator for this server, likely explaining any error status
uint32_t uMinServiceRequestID; //!< don't accept service request id's older than this
} QosCommonCoordinatorToServerResponseT;
/*** Variables ********************************************************************/
/*** Functions ********************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
// QosCommonClientToCoordinatorRequestT helpers
DIRTYCODE_API uint8_t* QosCommonClientToCoordinatorRequestEncode(const QosCommonClientToCoordinatorRequestT *pClientToCoordinatorRequest, uint8_t *pBuffer, uint32_t uBuffSize, uint32_t *pOutSize);
DIRTYCODE_API int32_t QosCommonClientToCoordinatorEstimateEncodedSize(const QosCommonClientToCoordinatorRequestT *pClientToCoordinatorRequest);
DIRTYCODE_API void QosCommonClientToCoordinatorPrint(const QosCommonClientToCoordinatorRequestT *pClientToCoordinatorRequest, uint32_t uLogLevel);
// QosCommonCoordinatorToClientResponseT helpers
DIRTYCODE_API int32_t QosCommonCoordinatorToClientResponseDecode(QosCommonCoordinatorToClientResponseT *pResponse, const uint8_t *pBuffer, uint32_t uBuffSize);
DIRTYCODE_API void QosCommonCoordinatorToClientPrint(const QosCommonCoordinatorToClientResponseT *pResponse, uint32_t uLogLevel);
// QosCommonServerToCoordinatorRequestT helpers
DIRTYCODE_API uint8_t* QosCommonServerToCoordinatorRequestEncode(const QosCommonServerToCoordinatorRequestT *pServerRegistrationRequest, uint8_t *pBuffer, uint32_t uBuffSize, uint32_t *pOutSize);
// QosCommonCoordinatorToServerResponseT helpers
DIRTYCODE_API int32_t QosCommonCoordinatorToServerResponseDecode(QosCommonCoordinatorToServerResponseT *pServerRegistrationResponse, const uint8_t *pBuffer, uint32_t uBuffSize);
// helpers for address
DIRTYCODE_API char* QosCommonAddrToString(const QosCommonAddrT *pAddr, char *pBuffer, int32_t iBufSize);
DIRTYCODE_API int32_t QosCommonStringToAddr(char *pStrIn, QosCommonAddrT *pOutAddr);
DIRTYCODE_API uint8_t QosCommonIsAddrEqual(QosCommonAddrT *pAddr1, QosCommonAddrT *pAddr2);
DIRTYCODE_API uint8_t QosCommonIsRemappedAddrEqual(QosCommonAddrT *pAddr1, struct sockaddr *pAddr2);
DIRTYCODE_API void QosCommonConvertAddr(QosCommonAddrT *pTargetAddr, struct sockaddr *pSourceAddr);
// helpers for serializing and deserializing packets
DIRTYCODE_API uint8_t QosCommonSerializeProbePacket(uint8_t *pOutBuff, uint32_t uBuffSize, const QosCommonProbePacketT *pInPacket, uint8_t *pSecureKey);
DIRTYCODE_API uint8_t QosCommonDeserializeProbePacket(QosCommonProbePacketT *pOutPacket, uint8_t *pInBuff, uint8_t *pSecureKey1, uint8_t *pSecureKey2);
DIRTYCODE_API void QosCommonDeserializeProbePacketInsecure(QosCommonProbePacketT *pOutPacket, uint8_t *pInBuff);
DIRTYCODE_API uint16_t QosCommonDeserializeClientRequestId(uint8_t *pInBuff);
DIRTYCODE_API uint32_t QosCommonDeserializeServiceRequestId(uint8_t *pInBuff);
// helpers for version numbering
DIRTYCODE_API uint16_t QosCommonMakeVersion(uint8_t uMajor, uint8_t uMinor);
DIRTYCODE_API void QosCommonGetVersion(uint16_t uVersion, uint8_t *uMajor, uint8_t *uMinor);
DIRTYCODE_API uint8_t QosCommonIsCompatibleVersion(uint16_t uVersion1, uint16_t uVersion2);
DIRTYCODE_API uint8_t QosCommonIsCompatibleProbeVersion(uint16_t uVersion);
#ifdef __cplusplus
}
#endif
//@}
#endif // _qoscommon_h