mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
DirtySDK (EA's Dirty Sockets library) will be used for the LiveAPI implementation, and depends on: EABase, EAThread.
1336 lines
66 KiB
C
1336 lines
66 KiB
C
/*H********************************************************************************/
|
|
/*!
|
|
\File qoscommon.c
|
|
|
|
\Description
|
|
This code implements shared items between client and server of the QOS system.
|
|
|
|
\Copyright
|
|
Copyright (c) 2016 Electronic Arts Inc.
|
|
|
|
*/
|
|
/********************************************************************************H*/
|
|
|
|
/*** Include files ****************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "DirtySDK/dirtysock.h"
|
|
#include "DirtySDK/dirtysock/dirtymem.h"
|
|
#include "DirtySDK/dirtysock/dirtyerr.h"
|
|
#include "DirtySDK/dirtysock/dirtynet.h"
|
|
#include "DirtySDK/misc/qoscommon.h"
|
|
#include "DirtySDK/util/binary7.h"
|
|
#include "DirtySDK/crypt/crypthash.h"
|
|
#include "DirtySDK/crypt/crypthmac.h"
|
|
|
|
#include "DirtySDK/util/protobufcommon.h"
|
|
#include "DirtySDK/util/protobufwrite.h"
|
|
#include "DirtySDK/util/protobufread.h"
|
|
|
|
/*** Defines **********************************************************************/
|
|
|
|
//!< Limits put on values when decoding rpcs
|
|
|
|
#define QOS_COMMON_MAX_INIT_SYNC_TIME (5000) //!< max time to wait for all the tests to start at the same time, after this time the tests will continue without synchronizing
|
|
#define QOS_COMMON_MAX_TIME_BETWEEN_PROBES (1000) //!< time between each probe send for a given test
|
|
#define QOS_COMMON_MIN_PROBE_COUNT (1) //!< the min amount of probes used for a given test, note QOS_COMMON_MAX_PROBE_COUNT is defined in qoscommon.h
|
|
#define QOS_COMMON_MAX_RESEND_EXTRA_PROBES (QOS_COMMON_MAX_PROBE_COUNT) //!< if we think we lost probes, should we send some extras to reduce the chances of losing some of those too
|
|
#define QOS_COMMON_MIN_TIMEOUT (7000) //!< min qosclient request timeout period, the test is considered failed if this much time passed
|
|
#define QOS_COMMON_MAX_TIMEOUT (20000) //!< max qosclient request timeout period, the test is considered failed if this much time passed
|
|
#define QOS_COMMON_MIN_RESEND_TIME (200) //!< qosclient time till we decide probes have been lost, so send more probes then initially planned
|
|
#define QOS_COMMON_MAX_RESEND_TIME (QOS_COMMON_MAX_TIMEOUT) //!< qosclient time till we decide probes have been lost, so send more probes then initially planned
|
|
#define QOS_COMMON_MAX_ACCEPTABLE_LOST_PROBES (QOS_COMMON_MAX_PROBE_COUNT) //!< don't bother resend new probes if we've only lost x number of probes
|
|
#define QOS_COMMON_RPC_HEADER_SIZE (1) //! one byte is needed to make a grpc header on top of what is done in protobuff
|
|
#define QOS_COMMON_ENABLE_HMAC (1) //! be sure that hmac is enabled except for special debug cases
|
|
|
|
/*** Macros ***********************************************************************/
|
|
|
|
/*** Type Definitions *************************************************************/
|
|
// Note that all of the below enums must be kept in sync with the proto files
|
|
// that belong to the coordinator.
|
|
|
|
//message ClientRequest
|
|
enum
|
|
{
|
|
CLIENT_TO_COORDINATOR_REQUEST_ARESULTS = 1,
|
|
CLIENT_TO_COORDINATOR_REQUEST_PROFILE,
|
|
CLIENT_TO_COORDINATOR_REQUEST_SERVICE_ID,
|
|
CLIENT_TO_COORDINATOR_REQUEST_PROBE_VERSION,
|
|
CLIENT_TO_COORDINATOR_REQUEST_MODIFIERS
|
|
}eClientToCoordinatorRequestFields;
|
|
|
|
//message ClientModifierFields
|
|
enum
|
|
{
|
|
CLIENT_MODIFIER_INTERNAL_ADDRESS = 1,
|
|
CLIENT_MODIFIER_PLATFORM,
|
|
CLIENT_MODIFIER_OS_FIREWALL,
|
|
CLIENT_MODIFIER_PACKET_QUEUE_REMAINING,
|
|
CLIENT_MODIFIER_STALL_COUNT_COMM,
|
|
CLIENT_MODIFIER_STALL_DURATION_COMM,
|
|
CLIENT_MODIFIER_STALL_COUNT_PROBE,
|
|
CLIENT_MODIFIER_STALL_DURATION_PROBE,
|
|
CLIENT_MODIFIER_HRESULT
|
|
}eQosCommonClientModifiersFields;
|
|
|
|
//message ClientRawResult
|
|
enum
|
|
{
|
|
RAW_RESULTS_ARESULT = 1,
|
|
RAW_RESULTS_CLIENT_ADDRESS_FROM_SERVER,
|
|
RAW_RESULTS_SITE_NAME,
|
|
RAW_RESULTS_TEST_NAME,
|
|
RAW_RESULTS_HRESULT
|
|
}eQosCommonRawResultsFields;
|
|
|
|
//message ProbeResult
|
|
enum
|
|
{
|
|
PROBE_RESULT_CLIENT_SEND_TIME = 1,
|
|
PROBE_RESULT_SERVER_RECV_TIME,
|
|
PROBE_RESULT_SERVER_SEND_DELTA,
|
|
PROBE_RESULT_CLIENT_RECV_DELTA
|
|
}eQosCommonProbeResultFields;
|
|
|
|
//message ClientResponse
|
|
enum
|
|
{
|
|
COORDINATOR_TO_CLIENT_RESPONSE_STATUS = 1,
|
|
COORDINATOR_TO_CLIENT_RESPONSE_SERVICE_ID,
|
|
COORDINATOR_TO_CLIENT_RESPONSE_CLIENT_ADDR_FROM_COORDINATOR,
|
|
COORDINATOR_TO_CLIENT_RESPONSE_FIREWALL_TYPE,
|
|
COORDINATOR_TO_CLIENT_RESPONSE_TIME_TILL_RETRY,
|
|
COORDINATOR_TO_CLIENT_RESPONSE_CLIENT_EXTERNAL_ADDRESS,
|
|
COORDINATOR_TO_CLIENT_RESPONSE_APINGSITES,
|
|
COORDINATOR_TO_CLIENT_RESPONSE_ACONTROL_CONFIGS,
|
|
COORDINATOR_TO_CLIENT_RESPONSE_ATESTS,
|
|
COORDINATOR_TO_CLIENT_RESPONSE_ASITE_RESULTS
|
|
}eCoordinatorToClientResponseFields;
|
|
|
|
//message PingSite
|
|
enum
|
|
{
|
|
SITE_NAME = 1,
|
|
SITE_ADDR,
|
|
SITE_PORT,
|
|
SITE_KEY,
|
|
SITE_PROBE_VERSION
|
|
}eQosCommonSiteFields;
|
|
|
|
//message ControlConfig
|
|
enum
|
|
{
|
|
CONTROL_CONFIG_NAME = 1,
|
|
CONTROL_CONFIG_I_VALUE,
|
|
CONTROL_CONFIG_STR_VALUE
|
|
}eQosCommonControlConfigFields;
|
|
|
|
//message QosTest
|
|
enum
|
|
{
|
|
TEST_NAME = 1,
|
|
TEST_SITE,
|
|
TEST_PROBE_COUNT_UP,
|
|
TEST_PROBE_COUNT_DOWN,
|
|
TEST_PROBE_SIZE_UP,
|
|
TEST_PROBE_SIZE_DOWN,
|
|
TEST_TIMEOUT,
|
|
TEST_MINTIME_BETWEEN_PROBES,
|
|
TEST_TIME_TILL_RESEND,
|
|
TEST_RESEND_EXTRA_PROBE_COUNT,
|
|
TEST_ACCEPTABLE_PROBE_LOSS,
|
|
TEST_INIT_SYNC_TIME
|
|
}eQosCommonTestFields;
|
|
|
|
//message TestResult
|
|
enum
|
|
{
|
|
TEST_RESULT_SITE = 1,
|
|
TEST_RESULT_RTT,
|
|
TEST_RESULT_UP_BPS,
|
|
TEST_RESULT_DOWN_BPS,
|
|
TEST_RESULT_HRESULT
|
|
}eQosCommonTestResultFields;
|
|
|
|
//message ServerRegistrationRequest
|
|
enum
|
|
{
|
|
SERVER_TO_COORDINATOR_REQUEST_SITE = 1,
|
|
SERVER_TO_COORDINATOR_REQUEST_ADDR,
|
|
SERVER_TO_COORDINATOR_REQUEST_POOL,
|
|
SERVER_TO_COORDINATOR_REQUEST_KEY,
|
|
SERVER_TO_COORDINATOR_REQUEST_PORT,
|
|
SERVER_TO_COORDINATOR_REQUEST_CAPCAITY_SEC,
|
|
SERVER_TO_COORDINATOR_REQUEST_LAST_LOAD_SEC,
|
|
SERVER_TO_COORDINATOR_REQUEST_PROBE_VERSION,
|
|
SERVER_TO_COORDINATOR_REQUEST_UPDATE_INTERVAL,
|
|
SERVER_TO_COORDINATOR_REQUEST_SHUTTING_DOWN
|
|
}eServerToCoordinatorRequestFields;
|
|
|
|
enum
|
|
{
|
|
COORDINATOR_TO_SERVER_RESPONSE_STATUS = 1,
|
|
COORDINATOR_TO_SERVER_RESPONSE_REGISTRATION_MESSAGE,
|
|
COORDINATOR_TO_SERVER_RESPONSE_MIN_SERVICE_ID
|
|
}eCoordinatorToServerResponseFields;
|
|
|
|
/*** Function Prototypes **********************************************************/
|
|
|
|
/*** Variables ********************************************************************/
|
|
|
|
/*** Private Functions ************************************************************/
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _QosCommonScrubProbeResults
|
|
|
|
\Description
|
|
Time values are kind of meaningless outside of the box they are generated on
|
|
here we try to make them more readable and take less space by trimming them to
|
|
lower values.
|
|
|
|
\Input *pIn - input values
|
|
\Input *pOut - [out] output values
|
|
\Input uHightWater - max array index used
|
|
|
|
\Version 08/02/2017 (cvienneau)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _QosCommonScrubProbeResults(const QosCommonProbeResultT* pIn, QosCommonProbeResultT* pOut, uint32_t uHightWater)
|
|
{
|
|
//scan data for lowest client side time and lowest server side time
|
|
uint32_t uMinClientTime = (uint32_t)-1;
|
|
uint32_t uMinServerTime = (uint32_t)-1;
|
|
uint32_t uProbeIndex;
|
|
for (uProbeIndex = 0; uProbeIndex <= uHightWater; uProbeIndex++)
|
|
{
|
|
if ((pIn[uProbeIndex].uClientSendTime != 0) && (pIn[uProbeIndex].uClientSendTime < uMinClientTime))
|
|
{
|
|
uMinClientTime = pIn[uProbeIndex].uClientSendTime;
|
|
}
|
|
|
|
if ((pIn[uProbeIndex].uServerReceiveTime != 0) && (pIn[uProbeIndex].uServerReceiveTime < uMinServerTime))
|
|
{
|
|
uMinServerTime = pIn[uProbeIndex].uServerReceiveTime;
|
|
}
|
|
}
|
|
|
|
//zeros are used when probes are missing, so we want to use 1 instead.
|
|
uMinClientTime--;
|
|
uMinServerTime--;
|
|
|
|
//pass over data again to reduce values
|
|
for (uProbeIndex = 0; uProbeIndex <= uHightWater; uProbeIndex++)
|
|
{
|
|
if (pIn[uProbeIndex].uClientSendTime != 0)
|
|
{
|
|
pOut[uProbeIndex].uClientSendTime = pIn[uProbeIndex].uClientSendTime - uMinClientTime;
|
|
}
|
|
else
|
|
{
|
|
pOut[uProbeIndex].uClientSendTime = UINT32_MAX;
|
|
}
|
|
|
|
if (pIn[uProbeIndex].uServerReceiveTime != 0)
|
|
{
|
|
pOut[uProbeIndex].uServerReceiveTime = pIn[uProbeIndex].uServerReceiveTime - uMinServerTime;
|
|
//copy the delta values out of the original array deltas don't need re-basing
|
|
pOut[uProbeIndex].uClientReceiveDelta = pIn[uProbeIndex].uClientReceiveDelta;
|
|
pOut[uProbeIndex].uServerSendDelta = pIn[uProbeIndex].uServerSendDelta;
|
|
}
|
|
else
|
|
{
|
|
//if the server didn't receive the probe put error sentinel values in for everything
|
|
pOut[uProbeIndex].uServerReceiveTime = UINT32_MAX;
|
|
pOut[uProbeIndex].uClientReceiveDelta = UINT16_MAX;
|
|
pOut[uProbeIndex].uServerSendDelta = UINT16_MAX;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/*** Public functions *************************************************************/
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function QosCommonClientToCoordinatorEstimateEncodedSize
|
|
|
|
\Description
|
|
Estimate how much space will be needed to encode the QosCommonClientToCoordinatorRequestT.
|
|
|
|
\Input *pClientToCoordinatorRequest - structure to read values from
|
|
|
|
\Output
|
|
int32_t - negative on error or, size on success
|
|
|
|
\Version 12/09/2016 (cvienneau)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t QosCommonClientToCoordinatorEstimateEncodedSize(const QosCommonClientToCoordinatorRequestT *pClientToCoordinatorRequest)
|
|
{
|
|
// the basic introduction message with no results fits under 200 bytes, lets say 1k as a min anyways
|
|
int32_t iEstimatedSize = 1024;
|
|
// my own local test shows ~600 bytes for 3 results, approximately 200 bytes per result, but if the tests used more probes (i used 10)
|
|
// i could see this easily be 600b, lets just say 1k per result for plenty of wiggle room
|
|
iEstimatedSize = iEstimatedSize + (1024 * pClientToCoordinatorRequest->uNumResults);
|
|
|
|
return(iEstimatedSize);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function QosCommonClientToCoordinatorRequestEncode
|
|
|
|
\Description
|
|
Encode the QosCommonClientToCoordinatorRequestT into a buffer, which
|
|
gives the coordinator information on who the client is and what test
|
|
results it might already have.
|
|
|
|
\Input *pClientToCoordinatorRequest - structure to read values from
|
|
\Input *pBuffer - [out] buffer we are writing to
|
|
\Input uBuffSize - max size of buffer
|
|
\Input *pOutSize - [out] output size of encoded data
|
|
|
|
\Output
|
|
uint8_t* - NULL on error or, pointer to filled buffer on success
|
|
|
|
\Version 12/09/2016 (cvienneau)
|
|
*/
|
|
/********************************************************************************F*/
|
|
uint8_t* QosCommonClientToCoordinatorRequestEncode(const QosCommonClientToCoordinatorRequestT *pClientToCoordinatorRequest, uint8_t *pBuffer, uint32_t uBuffSize, uint32_t *pOutSize)
|
|
{
|
|
char strTemp[QOS_COMMON_MAX_RPC_STRING];
|
|
uint32_t uIndex, uIndexProbe;
|
|
int32_t iError = 0;
|
|
|
|
ds_memclr(pBuffer, QOS_COMMON_RPC_HEADER_SIZE);
|
|
ProtobufWriteRefT *pEncoder = ProtobufWriteCreate(pBuffer + QOS_COMMON_RPC_HEADER_SIZE, uBuffSize - QOS_COMMON_RPC_HEADER_SIZE, TRUE);
|
|
|
|
if (pEncoder)
|
|
{
|
|
iError |= ProtobufWriteString(pEncoder, pClientToCoordinatorRequest->strQosProfile, (int32_t)strlen(pClientToCoordinatorRequest->strQosProfile), CLIENT_TO_COORDINATOR_REQUEST_PROFILE);
|
|
iError |= ProtobufWriteVarint(pEncoder, pClientToCoordinatorRequest->uServiceRequestID, CLIENT_TO_COORDINATOR_REQUEST_SERVICE_ID);
|
|
iError |= ProtobufWriteVarint(pEncoder, pClientToCoordinatorRequest->uProbeVersion, CLIENT_TO_COORDINATOR_REQUEST_PROBE_VERSION);
|
|
|
|
iError |= ProtobufWriteMessageBegin(pEncoder, CLIENT_TO_COORDINATOR_REQUEST_MODIFIERS);
|
|
QosCommonAddrToString(&pClientToCoordinatorRequest->clientModifiers.clientAddressInternal, strTemp, sizeof(strTemp));
|
|
iError |= ProtobufWriteString(pEncoder, strTemp, (int32_t)strlen(strTemp), CLIENT_MODIFIER_INTERNAL_ADDRESS);
|
|
iError |= ProtobufWriteString(pEncoder, pClientToCoordinatorRequest->clientModifiers.strPlatform, (int32_t)strlen(pClientToCoordinatorRequest->clientModifiers.strPlatform), CLIENT_MODIFIER_PLATFORM);
|
|
iError |= ProtobufWriteVarint(pEncoder, pClientToCoordinatorRequest->clientModifiers.eOSFirewallType, CLIENT_MODIFIER_OS_FIREWALL);
|
|
iError |= ProtobufWriteVarint(pEncoder, pClientToCoordinatorRequest->clientModifiers.uPacketQueueRemaining, CLIENT_MODIFIER_PACKET_QUEUE_REMAINING);
|
|
iError |= ProtobufWriteVarint(pEncoder, pClientToCoordinatorRequest->clientModifiers.uStallCountCoordinator, CLIENT_MODIFIER_STALL_COUNT_COMM);
|
|
iError |= ProtobufWriteVarint(pEncoder, pClientToCoordinatorRequest->clientModifiers.uStallCountProbe, CLIENT_MODIFIER_STALL_COUNT_PROBE);
|
|
iError |= ProtobufWriteVarint(pEncoder, pClientToCoordinatorRequest->clientModifiers.uStallDurationCoordinator, CLIENT_MODIFIER_STALL_DURATION_COMM);
|
|
iError |= ProtobufWriteVarint(pEncoder, pClientToCoordinatorRequest->clientModifiers.uStallDurationProbe, CLIENT_MODIFIER_STALL_DURATION_PROBE);
|
|
iError |= ProtobufWriteVarint(pEncoder, pClientToCoordinatorRequest->clientModifiers.hResult, CLIENT_MODIFIER_HRESULT);
|
|
iError |= ProtobufWriteMessageEnd(pEncoder); //end of CLIENT_TO_COORDINATOR_REQUEST_MODIFIERS
|
|
|
|
// add all current results
|
|
if ((iError == 0) && (pClientToCoordinatorRequest->uNumResults > 0))
|
|
{
|
|
for (uIndex = 0; uIndex < pClientToCoordinatorRequest->uNumResults; uIndex++)
|
|
{
|
|
iError |= ProtobufWriteMessageBegin(pEncoder, CLIENT_TO_COORDINATOR_REQUEST_ARESULTS);
|
|
iError |= ProtobufWriteVarint(pEncoder, pClientToCoordinatorRequest->aResults[uIndex].hResult, RAW_RESULTS_HRESULT);
|
|
iError |= ProtobufWriteString(pEncoder, pClientToCoordinatorRequest->aResults[uIndex].strSiteName, (int32_t)strlen(pClientToCoordinatorRequest->aResults[uIndex].strSiteName), RAW_RESULTS_SITE_NAME);
|
|
iError |= ProtobufWriteString(pEncoder, pClientToCoordinatorRequest->aResults[uIndex].strTestName, (int32_t)strlen(pClientToCoordinatorRequest->aResults[uIndex].strTestName), RAW_RESULTS_TEST_NAME);
|
|
QosCommonAddrToString(&pClientToCoordinatorRequest->aResults[uIndex].clientAddressFromServer, strTemp, sizeof(strTemp));
|
|
iError |= ProtobufWriteString(pEncoder, strTemp, (int32_t)strlen(strTemp), RAW_RESULTS_CLIENT_ADDRESS_FROM_SERVER);
|
|
|
|
if ((iError == 0) && (pClientToCoordinatorRequest->aResults[uIndex].uProbeCountDown > 0))
|
|
{
|
|
//make an array the same size as the one contained in the struct
|
|
QosCommonProbeResultT aScrubedProbeResults[(sizeof(pClientToCoordinatorRequest->aResults[uIndex].aProbeResult) / sizeof(pClientToCoordinatorRequest->aResults[uIndex].aProbeResult[0]))];
|
|
|
|
//lower the values used to something more human readable
|
|
_QosCommonScrubProbeResults(pClientToCoordinatorRequest->aResults[uIndex].aProbeResult, aScrubedProbeResults, pClientToCoordinatorRequest->aResults[uIndex].uProbeCountHighWater);
|
|
// info on individual probes
|
|
for (uIndexProbe = 0; uIndexProbe <= pClientToCoordinatorRequest->aResults[uIndex].uProbeCountHighWater; uIndexProbe++) //this list may have spaces if some probes were not received
|
|
{
|
|
iError |= ProtobufWriteMessageBegin(pEncoder, RAW_RESULTS_ARESULT);
|
|
iError |= ProtobufWriteVarint(pEncoder, aScrubedProbeResults[uIndexProbe].uClientSendTime, PROBE_RESULT_CLIENT_SEND_TIME);
|
|
iError |= ProtobufWriteVarint(pEncoder, aScrubedProbeResults[uIndexProbe].uServerReceiveTime, PROBE_RESULT_SERVER_RECV_TIME);
|
|
iError |= ProtobufWriteVarint(pEncoder, aScrubedProbeResults[uIndexProbe].uServerSendDelta, PROBE_RESULT_SERVER_SEND_DELTA);
|
|
iError |= ProtobufWriteVarint(pEncoder, aScrubedProbeResults[uIndexProbe].uClientReceiveDelta, PROBE_RESULT_CLIENT_RECV_DELTA);
|
|
iError |= ProtobufWriteMessageEnd(pEncoder); //end of probe result
|
|
}
|
|
}
|
|
iError |= ProtobufWriteMessageEnd(pEncoder); //end of result
|
|
}
|
|
}
|
|
*pOutSize = ProtobufWriteDestroy(pEncoder) + QOS_COMMON_RPC_HEADER_SIZE;
|
|
}
|
|
else
|
|
{
|
|
iError |= -1;
|
|
*pOutSize = 0;
|
|
}
|
|
return((iError == 0) ? pBuffer : NULL);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function QosCommonClientToCoordinatorPrint
|
|
|
|
\Description
|
|
Print the QosCommonClientToCoordinatorRequestT to tty.
|
|
|
|
\Input *pClientToCoordinatorRequest - structure to print
|
|
\Input uLogLevel - log level to control spam
|
|
|
|
\Version 03/03/2018 (cvienneau)
|
|
*/
|
|
/********************************************************************************F*/
|
|
void QosCommonClientToCoordinatorPrint(const QosCommonClientToCoordinatorRequestT *pClientToCoordinatorRequest, uint32_t uLogLevel)
|
|
{
|
|
#if DIRTYCODE_LOGGING
|
|
char strTemp[QOS_COMMON_MAX_RPC_STRING];
|
|
uint32_t uIndex, uIndexProbe;
|
|
|
|
NetPrintfVerbose((uLogLevel, 0, "qoscommon: cl2co.strQosProfile: %s\n", pClientToCoordinatorRequest->strQosProfile));
|
|
NetPrintfVerbose((uLogLevel, 0, "qoscommon: cl2co.uServiceRequestID: %u\n", pClientToCoordinatorRequest->uServiceRequestID));
|
|
NetPrintfVerbose((uLogLevel, 1, "qoscommon: cl2co.uProbeVersion: %u\n", pClientToCoordinatorRequest->uProbeVersion));
|
|
|
|
QosCommonAddrToString(&pClientToCoordinatorRequest->clientModifiers.clientAddressInternal, strTemp, sizeof(strTemp));
|
|
NetPrintfVerbose((uLogLevel, 0, "qoscommon: cl2co.cm.clientAddressInternal: %s\n", strTemp));
|
|
NetPrintfVerbose((uLogLevel, 1, "qoscommon: cl2co.cm.strPlatform: %s\n", pClientToCoordinatorRequest->clientModifiers.strPlatform));
|
|
NetPrintfVerbose((uLogLevel, 0, "qoscommon: cl2co.cm.eOSFirewallType: %u\n", pClientToCoordinatorRequest->clientModifiers.eOSFirewallType));
|
|
NetPrintfVerbose((uLogLevel, 0, "qoscommon: cl2co.cm.uPacketQueueRemaining: %u\n", pClientToCoordinatorRequest->clientModifiers.uPacketQueueRemaining));
|
|
NetPrintfVerbose((uLogLevel, 1, "qoscommon: cl2co.cm.uStallCountCoordinator: %u\n", pClientToCoordinatorRequest->clientModifiers.uStallCountCoordinator));
|
|
NetPrintfVerbose((uLogLevel, 1, "qoscommon: cl2co.cm.uStallCountProbe: %u\n", pClientToCoordinatorRequest->clientModifiers.uStallCountProbe));
|
|
NetPrintfVerbose((uLogLevel, 0, "qoscommon: cl2co.cm.uStallDurationCoordinator: %u\n", pClientToCoordinatorRequest->clientModifiers.uStallDurationCoordinator));
|
|
NetPrintfVerbose((uLogLevel, 0, "qoscommon: cl2co.cm.uStallDurationProbe: %u\n", pClientToCoordinatorRequest->clientModifiers.uStallDurationProbe));
|
|
NetPrintfVerbose((uLogLevel, 0, "qoscommon: cl2co.cm.hResult: 0x%08x\n", pClientToCoordinatorRequest->clientModifiers.hResult));
|
|
|
|
// add all current results
|
|
for (uIndex = 0; uIndex < pClientToCoordinatorRequest->uNumResults; uIndex++)
|
|
{
|
|
NetPrintfVerbose((uLogLevel, 0, "qoscommon: cl2co.aResults[%u] site: %s, test: %s, hresult: 0x%08x, up: %u, down: %u, high: %u, addr: %s\n",
|
|
uIndex,
|
|
pClientToCoordinatorRequest->aResults[uIndex].strSiteName,
|
|
pClientToCoordinatorRequest->aResults[uIndex].strTestName,
|
|
pClientToCoordinatorRequest->aResults[uIndex].hResult,
|
|
pClientToCoordinatorRequest->aResults[uIndex].uProbeCountUp,
|
|
pClientToCoordinatorRequest->aResults[uIndex].uProbeCountDown,
|
|
pClientToCoordinatorRequest->aResults[uIndex].uProbeCountHighWater,
|
|
QosCommonAddrToString(&pClientToCoordinatorRequest->aResults[uIndex].clientAddressFromServer, strTemp, sizeof(strTemp))
|
|
));
|
|
|
|
if (pClientToCoordinatorRequest->aResults[uIndex].uProbeCountDown > 0)
|
|
{
|
|
//make an array the same size as the one contained in the struct
|
|
QosCommonProbeResultT aScrubedProbeResults[(sizeof(pClientToCoordinatorRequest->aResults[uIndex].aProbeResult) / sizeof(pClientToCoordinatorRequest->aResults[uIndex].aProbeResult[0]))];
|
|
|
|
//lower the values used to something more human readable
|
|
_QosCommonScrubProbeResults(pClientToCoordinatorRequest->aResults[uIndex].aProbeResult, aScrubedProbeResults, pClientToCoordinatorRequest->aResults[uIndex].uProbeCountHighWater);
|
|
// info on individual probes
|
|
for (uIndexProbe = 0; uIndexProbe <= pClientToCoordinatorRequest->aResults[uIndex].uProbeCountHighWater; uIndexProbe++) //this list may have spaces if some probes were not received
|
|
{
|
|
// only print the first probe, unless we have higher logging level set.
|
|
int32_t uLocalLogLevel = 0;
|
|
if (uIndexProbe > 0)
|
|
{
|
|
uLocalLogLevel = 1;
|
|
}
|
|
NetPrintfVerbose((uLogLevel, uLocalLogLevel, "qoscommon: cl2co.aResults[%d].aProbeResult[%d] csend: %u, srcv: %u, sdelta: %u, cdelta: %u\n", uIndex, uIndexProbe,
|
|
aScrubedProbeResults[uIndexProbe].uClientSendTime,
|
|
aScrubedProbeResults[uIndexProbe].uServerReceiveTime,
|
|
aScrubedProbeResults[uIndexProbe].uServerSendDelta,
|
|
aScrubedProbeResults[uIndexProbe].uClientReceiveDelta));
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function QosCommonCoordinatorToClientResponseDecode
|
|
|
|
\Description
|
|
Decodes the buffer, into a QosCommonCoordinatorToClientResponseT, which
|
|
gives the client instructions on what it should be doing next.
|
|
|
|
\Input *pResponse - [out] structure to write values to
|
|
\Input *pBuffer - buffer we are reading from
|
|
\Input uBuffSize - max size of pBuffer
|
|
|
|
\Output
|
|
int32_t - -1 on error 0 otherwise
|
|
|
|
\Version 12/09/2016 (cvienneau)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t QosCommonCoordinatorToClientResponseDecode(QosCommonCoordinatorToClientResponseT *pResponse, const uint8_t *pBuffer, uint32_t uBuffSize)
|
|
{
|
|
int32_t iMsgSize;
|
|
uint8_t bError = FALSE;
|
|
|
|
ds_memclr(pResponse, sizeof(QosCommonCoordinatorToClientResponseT));
|
|
pBuffer = ProtobufCommonReadSize(pBuffer + QOS_COMMON_RPC_HEADER_SIZE, uBuffSize - QOS_COMMON_RPC_HEADER_SIZE, &iMsgSize);
|
|
|
|
if (pBuffer)
|
|
{
|
|
ProtobufReadT Reader, ReaderValue;
|
|
const uint8_t *pCurrentRepeat;
|
|
char strTempAddr[QOS_COMMON_MAX_RPC_STRING];
|
|
ProtobufReadInit(&Reader, pBuffer, iMsgSize);
|
|
|
|
pResponse->uServiceRequestID = (uint32_t)ProtobufReadVarint(&Reader, ProtobufReadFind(&Reader, COORDINATOR_TO_CLIENT_RESPONSE_SERVICE_ID));
|
|
ProtobufReadString(&Reader, ProtobufReadFind(&Reader, COORDINATOR_TO_CLIENT_RESPONSE_CLIENT_ADDR_FROM_COORDINATOR), strTempAddr, sizeof(strTempAddr));
|
|
QosCommonStringToAddr(strTempAddr, &pResponse->configuration.clientAddressFromCoordinator);
|
|
|
|
//most will only be valid if results have been calculated, but we don't know what magic the coordinator might use
|
|
pResponse->results.eFirewallType = (QosCommonFirewallTypeE)ProtobufReadVarint(&Reader, ProtobufReadFind(&Reader, COORDINATOR_TO_CLIENT_RESPONSE_FIREWALL_TYPE));
|
|
pResponse->results.uTimeTillRetry = (uint32_t)ProtobufReadVarint(&Reader, ProtobufReadFind(&Reader, COORDINATOR_TO_CLIENT_RESPONSE_TIME_TILL_RETRY));
|
|
ProtobufReadString(&Reader, ProtobufReadFind(&Reader, COORDINATOR_TO_CLIENT_RESPONSE_CLIENT_EXTERNAL_ADDRESS), strTempAddr, sizeof(strTempAddr));
|
|
QosCommonStringToAddr(strTempAddr, &pResponse->results.clientExternalAddress);
|
|
|
|
pResponse->configuration.uNumSites = 0;
|
|
pCurrentRepeat = NULL;
|
|
while ((pCurrentRepeat = ProtobufReadFind2(&Reader, COORDINATOR_TO_CLIENT_RESPONSE_APINGSITES, pCurrentRepeat)) != NULL)
|
|
{
|
|
if (pResponse->configuration.uNumSites >= QOS_COMMON_MAX_SITES)
|
|
{
|
|
bError = TRUE;
|
|
break;
|
|
}
|
|
pCurrentRepeat = ProtobufReadMessage(&Reader, pCurrentRepeat, &ReaderValue);
|
|
ProtobufReadString(&ReaderValue, ProtobufReadFind(&ReaderValue, SITE_NAME), pResponse->configuration.aSites[pResponse->configuration.uNumSites].strSiteName, sizeof(pResponse->configuration.aSites[pResponse->configuration.uNumSites].strSiteName));
|
|
ProtobufReadString(&ReaderValue, ProtobufReadFind(&ReaderValue, SITE_ADDR), pResponse->configuration.aSites[pResponse->configuration.uNumSites].strProbeAddr, sizeof(pResponse->configuration.aSites[pResponse->configuration.uNumSites].strProbeAddr));
|
|
ProtobufReadBytes(&ReaderValue, ProtobufReadFind(&ReaderValue, SITE_KEY), pResponse->configuration.aSites[pResponse->configuration.uNumSites].aSecureKey, sizeof(pResponse->configuration.aSites[pResponse->configuration.uNumSites].aSecureKey));
|
|
pResponse->configuration.aSites[pResponse->configuration.uNumSites].uProbePort = ProtobufReadVarint(&ReaderValue, ProtobufReadFind(&ReaderValue, SITE_PORT));
|
|
pResponse->configuration.aSites[pResponse->configuration.uNumSites].uProbeVersion = ProtobufReadVarint(&ReaderValue, ProtobufReadFind(&ReaderValue, SITE_PROBE_VERSION));
|
|
pResponse->configuration.uNumSites++;
|
|
}
|
|
|
|
pResponse->configuration.uNumControlConfigs = 0;
|
|
pCurrentRepeat = NULL;
|
|
while ((pCurrentRepeat = ProtobufReadFind2(&Reader, COORDINATOR_TO_CLIENT_RESPONSE_ACONTROL_CONFIGS, pCurrentRepeat)) != NULL)
|
|
{
|
|
if (pResponse->configuration.uNumControlConfigs >= QOS_COMMON_MAX_CONTROL_CONFIGS)
|
|
{
|
|
bError = TRUE;
|
|
break;
|
|
}
|
|
pCurrentRepeat = ProtobufReadMessage(&Reader, pCurrentRepeat, &ReaderValue);
|
|
ProtobufReadString(&ReaderValue, ProtobufReadFind(&ReaderValue, CONTROL_CONFIG_NAME), pResponse->configuration.aControlConfigs[pResponse->configuration.uNumControlConfigs].strControl, sizeof(pResponse->configuration.aControlConfigs[pResponse->configuration.uNumControlConfigs].strControl));
|
|
pResponse->configuration.aControlConfigs[pResponse->configuration.uNumControlConfigs].iValue = (int32_t)ProtobufReadVarint(&ReaderValue, ProtobufReadFind(&ReaderValue, CONTROL_CONFIG_I_VALUE));
|
|
ProtobufReadString(&ReaderValue, ProtobufReadFind(&ReaderValue, CONTROL_CONFIG_STR_VALUE), pResponse->configuration.aControlConfigs[pResponse->configuration.uNumControlConfigs].strValue, sizeof(pResponse->configuration.aControlConfigs[pResponse->configuration.uNumControlConfigs].strValue));
|
|
pResponse->configuration.uNumControlConfigs++;
|
|
}
|
|
|
|
pResponse->configuration.uNumQosTests = 0;
|
|
pCurrentRepeat = NULL;
|
|
while ((pCurrentRepeat = ProtobufReadFind2(&Reader, COORDINATOR_TO_CLIENT_RESPONSE_ATESTS, pCurrentRepeat)) != NULL)
|
|
{
|
|
if (pResponse->configuration.uNumQosTests >= QOS_COMMON_MAX_TESTS)
|
|
{
|
|
bError = TRUE;
|
|
break;
|
|
}
|
|
pCurrentRepeat = ProtobufReadMessage(&Reader, pCurrentRepeat, &ReaderValue);
|
|
ProtobufReadString(&ReaderValue, ProtobufReadFind(&ReaderValue, TEST_NAME), pResponse->configuration.aQosTests[pResponse->configuration.uNumQosTests].strTestName, sizeof(pResponse->configuration.aQosTests[pResponse->configuration.uNumQosTests].strTestName));
|
|
ProtobufReadString(&ReaderValue, ProtobufReadFind(&ReaderValue, TEST_SITE), pResponse->configuration.aQosTests[pResponse->configuration.uNumQosTests].strSiteName, sizeof(pResponse->configuration.aQosTests[pResponse->configuration.uNumQosTests].strSiteName));
|
|
pResponse->configuration.aQosTests[pResponse->configuration.uNumQosTests].uProbeCountUp = DS_CLAMP(ProtobufReadVarint(&ReaderValue, ProtobufReadFind(&ReaderValue, TEST_PROBE_COUNT_UP)), QOS_COMMON_MIN_PROBE_COUNT, QOS_COMMON_MAX_PROBE_COUNT);
|
|
pResponse->configuration.aQosTests[pResponse->configuration.uNumQosTests].uProbeCountDown = DS_CLAMP(ProtobufReadVarint(&ReaderValue, ProtobufReadFind(&ReaderValue, TEST_PROBE_COUNT_DOWN)), QOS_COMMON_MIN_PROBE_COUNT, QOS_COMMON_MAX_PROBE_COUNT);
|
|
pResponse->configuration.aQosTests[pResponse->configuration.uNumQosTests].uProbeSizeUp = DS_CLAMP(ProtobufReadVarint(&ReaderValue, ProtobufReadFind(&ReaderValue, TEST_PROBE_SIZE_UP)), QOS_COMMON_MIN_PACKET_SIZE, QOS_COMMON_MAX_PACKET_SIZE);
|
|
pResponse->configuration.aQosTests[pResponse->configuration.uNumQosTests].uProbeSizeDown = DS_CLAMP(ProtobufReadVarint(&ReaderValue, ProtobufReadFind(&ReaderValue, TEST_PROBE_SIZE_DOWN)), QOS_COMMON_MIN_PACKET_SIZE, QOS_COMMON_MAX_PACKET_SIZE);
|
|
pResponse->configuration.aQosTests[pResponse->configuration.uNumQosTests].uTimeout = DS_CLAMP(ProtobufReadVarint(&ReaderValue, ProtobufReadFind(&ReaderValue, TEST_TIMEOUT)), QOS_COMMON_MIN_TIMEOUT, QOS_COMMON_MAX_TIMEOUT);
|
|
pResponse->configuration.aQosTests[pResponse->configuration.uNumQosTests].uMinTimeBetwenProbes = DS_MIN(ProtobufReadVarint(&ReaderValue, ProtobufReadFind(&ReaderValue, TEST_MINTIME_BETWEEN_PROBES)), QOS_COMMON_MAX_TIME_BETWEEN_PROBES);
|
|
pResponse->configuration.aQosTests[pResponse->configuration.uNumQosTests].uTimeTillResend = DS_CLAMP(ProtobufReadVarint(&ReaderValue, ProtobufReadFind(&ReaderValue, TEST_TIME_TILL_RESEND)), QOS_COMMON_MIN_RESEND_TIME, QOS_COMMON_MAX_RESEND_TIME);
|
|
pResponse->configuration.aQosTests[pResponse->configuration.uNumQosTests].uResendExtraProbeCount = DS_MIN(ProtobufReadVarint(&ReaderValue, ProtobufReadFind(&ReaderValue, TEST_RESEND_EXTRA_PROBE_COUNT)), QOS_COMMON_MAX_RESEND_EXTRA_PROBES);
|
|
pResponse->configuration.aQosTests[pResponse->configuration.uNumQosTests].uAcceptableLostProbeCount = DS_MIN(ProtobufReadVarint(&ReaderValue, ProtobufReadFind(&ReaderValue, TEST_ACCEPTABLE_PROBE_LOSS)), QOS_COMMON_MAX_ACCEPTABLE_LOST_PROBES);
|
|
pResponse->configuration.aQosTests[pResponse->configuration.uNumQosTests].uInitSyncTimeout = DS_MIN(ProtobufReadVarint(&ReaderValue, ProtobufReadFind(&ReaderValue, TEST_INIT_SYNC_TIME)), QOS_COMMON_MAX_INIT_SYNC_TIME);
|
|
pResponse->configuration.uNumQosTests++;
|
|
}
|
|
|
|
pResponse->results.uNumResults = 0;
|
|
pCurrentRepeat = NULL;
|
|
while ((pCurrentRepeat = ProtobufReadFind2(&Reader, COORDINATOR_TO_CLIENT_RESPONSE_ASITE_RESULTS, pCurrentRepeat)) != NULL)
|
|
{
|
|
if (pResponse->results.uNumResults >= QOS_COMMON_MAX_SITES)
|
|
{
|
|
bError = TRUE;
|
|
break;
|
|
}
|
|
pCurrentRepeat = ProtobufReadMessage(&Reader, pCurrentRepeat, &ReaderValue);
|
|
ProtobufReadString(&ReaderValue, ProtobufReadFind(&ReaderValue, TEST_RESULT_SITE), pResponse->results.aTestResults[pResponse->results.uNumResults].strSiteName, sizeof(pResponse->results.aTestResults[pResponse->results.uNumResults].strSiteName));
|
|
pResponse->results.aTestResults[pResponse->results.uNumResults].uMinRTT = (uint32_t)ProtobufReadVarint(&ReaderValue, ProtobufReadFind(&ReaderValue, TEST_RESULT_RTT));
|
|
pResponse->results.aTestResults[pResponse->results.uNumResults].uUpbps = (uint32_t)ProtobufReadVarint(&ReaderValue, ProtobufReadFind(&ReaderValue, TEST_RESULT_UP_BPS));
|
|
pResponse->results.aTestResults[pResponse->results.uNumResults].uDownbps = (uint32_t)ProtobufReadVarint(&ReaderValue, ProtobufReadFind(&ReaderValue, TEST_RESULT_DOWN_BPS));
|
|
pResponse->results.aTestResults[pResponse->results.uNumResults].hResult = (uint32_t)ProtobufReadVarint(&ReaderValue, ProtobufReadFind(&ReaderValue, TEST_RESULT_HRESULT));
|
|
pResponse->results.uNumResults++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bError = TRUE;
|
|
}
|
|
|
|
return(bError ? -1 : 0);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function QosCommonCoordinatorToClientPrint
|
|
|
|
\Description
|
|
Print the QosCommonCoordinatorToClientResponseT to tty.
|
|
|
|
\Input *pResponse - structure to print
|
|
\Input uLogLevel - log level to control spam
|
|
|
|
\Version 03/03/2018 (cvienneau)
|
|
*/
|
|
/********************************************************************************F*/
|
|
void QosCommonCoordinatorToClientPrint(const QosCommonCoordinatorToClientResponseT *pResponse, uint32_t uLogLevel)
|
|
{
|
|
#if DIRTYCODE_LOGGING
|
|
char strTemp[QOS_COMMON_MAX_RPC_STRING];
|
|
uint32_t uIndex;
|
|
|
|
//todo set proper log levels of these prints
|
|
|
|
NetPrintfVerbose((uLogLevel, 0, "qoscommon: co2cl.uServiceRequestID: %u\n", pResponse->uServiceRequestID));
|
|
NetPrintfVerbose((uLogLevel, 0, "qoscommon: co2cl.configuration.clientAddressFromCoordinator: %s\n", QosCommonAddrToString(&pResponse->configuration.clientAddressFromCoordinator, strTemp, sizeof(strTemp))));
|
|
NetPrintfVerbose((uLogLevel, 1, "qoscommon: co2cl.results.eFirewallType: %u\n", pResponse->results.eFirewallType));
|
|
NetPrintfVerbose((uLogLevel, 0, "qoscommon: co2cl.results.uTimeTillRetry: %u\n", pResponse->results.uTimeTillRetry));
|
|
NetPrintfVerbose((uLogLevel, 1, "qoscommon: co2cl.results.clientExternalAddress: %s\n", QosCommonAddrToString(&pResponse->results.clientExternalAddress, strTemp, sizeof(strTemp))));
|
|
|
|
for (uIndex = 0; uIndex < pResponse->configuration.uNumSites; uIndex++)
|
|
{
|
|
NetPrintfVerbose((uLogLevel, 0, "qoscommon: co2cl.configuration.aSites[%d] %s, %s:%u, %u\n",
|
|
uIndex,
|
|
pResponse->configuration.aSites[uIndex].strSiteName,
|
|
pResponse->configuration.aSites[uIndex].strProbeAddr,
|
|
pResponse->configuration.aSites[uIndex].uProbePort,
|
|
pResponse->configuration.aSites[uIndex].uProbeVersion));
|
|
//NetPrintfVerbose((uLogLevel, 0, "qoscommon: co2cl.configuration.aSites[%d].aSecureKey: X\n", pResponse->configuration.aSites[uIndex].aSecureKey));
|
|
}
|
|
|
|
for (uIndex = 0; uIndex < pResponse->configuration.uNumControlConfigs; uIndex++)
|
|
{
|
|
NetPrintfVerbose((uLogLevel, 0, "qoscommon: co2cl.configuration.aControlConfigs[%u]: '%s', %d, %s\n",
|
|
uIndex,
|
|
pResponse->configuration.aControlConfigs[uIndex].strControl,
|
|
pResponse->configuration.aControlConfigs[uIndex].iValue,
|
|
pResponse->configuration.aControlConfigs[uIndex].strValue));
|
|
}
|
|
|
|
for (uIndex = 0; uIndex < pResponse->configuration.uNumQosTests; uIndex++)
|
|
{
|
|
NetPrintfVerbose((uLogLevel, 0, "qoscommon: co2cl.configuration.aQosTests[%u]: %s, %s, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u\n",
|
|
uIndex,
|
|
pResponse->configuration.aQosTests[uIndex].strTestName,
|
|
pResponse->configuration.aQosTests[uIndex].strSiteName,
|
|
pResponse->configuration.aQosTests[uIndex].uProbeCountUp,
|
|
pResponse->configuration.aQosTests[uIndex].uProbeCountDown,
|
|
pResponse->configuration.aQosTests[uIndex].uProbeSizeUp,
|
|
pResponse->configuration.aQosTests[uIndex].uProbeSizeDown,
|
|
pResponse->configuration.aQosTests[uIndex].uTimeout,
|
|
pResponse->configuration.aQosTests[uIndex].uMinTimeBetwenProbes,
|
|
pResponse->configuration.aQosTests[uIndex].uTimeTillResend,
|
|
pResponse->configuration.aQosTests[uIndex].uResendExtraProbeCount,
|
|
pResponse->configuration.aQosTests[uIndex].uAcceptableLostProbeCount,
|
|
pResponse->configuration.aQosTests[uIndex].uInitSyncTimeout));
|
|
}
|
|
|
|
for (uIndex = 0; uIndex < pResponse->results.uNumResults; uIndex++)
|
|
{
|
|
NetPrintfVerbose((uLogLevel, 1, "qoscommon: co2cl.results.aTestResults[%d]: %s, %u, %u, %u, 0x%08x\n",
|
|
uIndex,
|
|
pResponse->results.aTestResults[uIndex].strSiteName,
|
|
pResponse->results.aTestResults[uIndex].uMinRTT,
|
|
pResponse->results.aTestResults[uIndex].uUpbps,
|
|
pResponse->results.aTestResults[uIndex].uDownbps,
|
|
pResponse->results.aTestResults[uIndex].hResult));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function QosCommonServerToCoordinatorRequestEncode
|
|
|
|
\Description
|
|
Encode QosCommonServerToCoordinatorRequestT into a buffer, which either
|
|
tells the coordinator we are a new server to be added to the available pool
|
|
or as a heartbeat and update of the secure key.
|
|
|
|
\Input *pServerRegistrationRequest - structure to read values from
|
|
\Input *pBuffer - [out] buffer we are writing to
|
|
\Input uBuffSize - size of buffer
|
|
\Input *pOutSize - [out] output size of encoded data
|
|
|
|
\Output
|
|
uint8_t* - NULL on error, pointer to filled buffer on success
|
|
|
|
\Version 12/09/2016 (cvienneau)
|
|
*/
|
|
/********************************************************************************F*/
|
|
uint8_t* QosCommonServerToCoordinatorRequestEncode(const QosCommonServerToCoordinatorRequestT *pServerRegistrationRequest, uint8_t *pBuffer, uint32_t uBuffSize, uint32_t *pOutSize)
|
|
{
|
|
int32_t iError = 0;
|
|
|
|
//first byte is grpc header
|
|
ds_memclr(pBuffer, QOS_COMMON_RPC_HEADER_SIZE);
|
|
ProtobufWriteRefT *pEncoder = ProtobufWriteCreate(pBuffer + QOS_COMMON_RPC_HEADER_SIZE, uBuffSize - QOS_COMMON_RPC_HEADER_SIZE, TRUE);
|
|
|
|
if (pEncoder)
|
|
{
|
|
iError |= ProtobufWriteString(pEncoder, pServerRegistrationRequest->strSiteName, (int32_t)strlen(pServerRegistrationRequest->strSiteName), SERVER_TO_COORDINATOR_REQUEST_SITE);
|
|
iError |= ProtobufWriteString(pEncoder, pServerRegistrationRequest->strPool, (int32_t)strlen(pServerRegistrationRequest->strPool), SERVER_TO_COORDINATOR_REQUEST_POOL);
|
|
iError |= ProtobufWriteString(pEncoder, pServerRegistrationRequest->strAddr, (int32_t)strlen(pServerRegistrationRequest->strAddr), SERVER_TO_COORDINATOR_REQUEST_ADDR);
|
|
iError |= ProtobufWriteBytes(pEncoder, pServerRegistrationRequest->aSecureKey, sizeof(pServerRegistrationRequest->aSecureKey), SERVER_TO_COORDINATOR_REQUEST_KEY);
|
|
iError |= ProtobufWriteVarint(pEncoder, pServerRegistrationRequest->uPort, SERVER_TO_COORDINATOR_REQUEST_PORT);
|
|
iError |= ProtobufWriteVarint(pEncoder, pServerRegistrationRequest->uCapacityPerSec, SERVER_TO_COORDINATOR_REQUEST_CAPCAITY_SEC);
|
|
iError |= ProtobufWriteVarint(pEncoder, pServerRegistrationRequest->uLastLoadPerSec, SERVER_TO_COORDINATOR_REQUEST_LAST_LOAD_SEC);
|
|
iError |= ProtobufWriteVarint(pEncoder, pServerRegistrationRequest->uProbeVersion, SERVER_TO_COORDINATOR_REQUEST_PROBE_VERSION);
|
|
iError |= ProtobufWriteVarint(pEncoder, pServerRegistrationRequest->uUpdateInterval, SERVER_TO_COORDINATOR_REQUEST_UPDATE_INTERVAL);
|
|
iError |= ProtobufWriteVarint(pEncoder, pServerRegistrationRequest->bShuttingDown, SERVER_TO_COORDINATOR_REQUEST_SHUTTING_DOWN);
|
|
*pOutSize = ProtobufWriteDestroy(pEncoder) + QOS_COMMON_RPC_HEADER_SIZE;
|
|
}
|
|
else
|
|
{
|
|
iError |= -1;
|
|
*pOutSize = 0;
|
|
}
|
|
return((iError == 0) ? pBuffer : NULL);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function QosCommonCoordinatorToServerResponseDecode
|
|
|
|
\Description
|
|
Decode buffer into a QosCommonCoordinatorToServerResponseT, which
|
|
tells the server any registration status.
|
|
|
|
\Input *pServerRegistrationResponse - [out] structure to write values to
|
|
\Input *pBuffer - buffer we are reading from
|
|
\Input uBuffSize - size of buffer
|
|
|
|
\Output
|
|
int32_t - -1 on err, 0 on success
|
|
|
|
\Version 12/09/2016 (cvienneau)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t QosCommonCoordinatorToServerResponseDecode(QosCommonCoordinatorToServerResponseT *pServerRegistrationResponse, const uint8_t *pBuffer, uint32_t uBuffSize)
|
|
{
|
|
int32_t iMsgSize;
|
|
uint8_t bError = FALSE;
|
|
|
|
ds_memclr(pServerRegistrationResponse, sizeof(QosCommonCoordinatorToServerResponseT));
|
|
pBuffer = ProtobufCommonReadSize(pBuffer + QOS_COMMON_RPC_HEADER_SIZE, uBuffSize - QOS_COMMON_RPC_HEADER_SIZE, &iMsgSize);
|
|
|
|
if (pBuffer)
|
|
{
|
|
ProtobufReadT Reader;
|
|
ProtobufReadInit(&Reader, pBuffer, iMsgSize);
|
|
//note we don't do anything with COORDINATOR_TO_SERVER_RESPONSE_STATUS
|
|
ProtobufReadString(&Reader, ProtobufReadFind(&Reader, COORDINATOR_TO_SERVER_RESPONSE_REGISTRATION_MESSAGE), pServerRegistrationResponse->strRegistrationMessage, sizeof(pServerRegistrationResponse->strRegistrationMessage));
|
|
pServerRegistrationResponse->uMinServiceRequestID = (uint32_t)ProtobufReadVarint(&Reader, ProtobufReadFind(&Reader, COORDINATOR_TO_SERVER_RESPONSE_MIN_SERVICE_ID));
|
|
}
|
|
else
|
|
{
|
|
bError = TRUE;
|
|
}
|
|
|
|
return(bError ? -1 : 0);
|
|
}
|
|
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function QosCommonAddrToString
|
|
|
|
\Description
|
|
Convert a address into a human readable easily pars-able string.
|
|
|
|
\Input *pAddr - address to convert
|
|
\Input *pBuffer - [out] buffer to write to
|
|
\Input iBufSize - size of buffer
|
|
|
|
\Output
|
|
char* - the pBuffer pointer that was written to
|
|
|
|
\Version 12/09/2016 (cvienneau)
|
|
*/
|
|
/********************************************************************************F*/
|
|
char* QosCommonAddrToString(const QosCommonAddrT *pAddr, char *pBuffer, int32_t iBufSize)
|
|
{
|
|
//we build a sockaddr, just so we can use our library print function, which saves us some headache
|
|
// if we wanted more details take a look at _ds_sockaddrtostr()
|
|
if (pAddr->uFamily == AF_INET)
|
|
{
|
|
struct sockaddr sockAddr;
|
|
SockaddrInit(&sockAddr, AF_INET);
|
|
SockaddrInSetAddr(&sockAddr, pAddr->addr.v4);
|
|
SockaddrInSetPort(&sockAddr, pAddr->uPort);
|
|
ds_snzprintf(pBuffer, iBufSize, "v4%A", &sockAddr);
|
|
}
|
|
#ifndef DIRTYCODE_NX
|
|
else if (pAddr->uFamily == AF_INET6)
|
|
{
|
|
struct sockaddr_in6 sockAddr6;
|
|
SockaddrInit6(&sockAddr6, AF_INET6);
|
|
ds_memcpy(&sockAddr6.sin6_addr, &(pAddr->addr.v6), sizeof(sockAddr6.sin6_addr));
|
|
sockAddr6.sin6_port = pAddr->uPort;
|
|
ds_snzprintf(pBuffer, iBufSize, "v6%A", &sockAddr6);
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
ds_snzprintf(pBuffer, iBufSize, "na[0]:0");
|
|
}
|
|
return(pBuffer);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function QosCommonStringToAddr
|
|
|
|
\Description
|
|
Convert a string generated by QosCommonAddrToString into a QosCommonAddrT
|
|
|
|
\Input *pStrIn - text to convert
|
|
\Input *pOutAddr - [out] address to write to
|
|
|
|
\Output
|
|
int32_t - -1 on err, 0 on success
|
|
|
|
\Version 12/09/2016 (cvienneau)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t QosCommonStringToAddr(char *pStrIn, QosCommonAddrT *pOutAddr)
|
|
{
|
|
int32_t iRet = -1;
|
|
int32_t iCurrentToken = 0;
|
|
char *pSave = NULL;
|
|
char *pTokenTemp = NULL;
|
|
char *pToken0 = NULL;
|
|
char *pToken1 = NULL;
|
|
char *pToken2 = NULL;
|
|
|
|
ds_memclr(pOutAddr, sizeof(QosCommonAddrT));
|
|
pTokenTemp = ds_strtok_r(pStrIn, "[]", &pSave);
|
|
while (pTokenTemp != NULL)
|
|
{
|
|
//process the token into a variable based off the token count
|
|
if (iCurrentToken == 0)
|
|
{
|
|
pToken0 = pTokenTemp;
|
|
}
|
|
else if (iCurrentToken == 1)
|
|
{
|
|
pToken1 = pTokenTemp;
|
|
}
|
|
else if (iCurrentToken == 2)
|
|
{
|
|
pToken2 = pTokenTemp;
|
|
}
|
|
pTokenTemp = ds_strtok_r(NULL, "[]", &pSave);
|
|
iCurrentToken++;
|
|
}
|
|
|
|
if ((pToken0 != NULL) && (ds_strnicmp(pToken0, "v4", 2) == 0))
|
|
{
|
|
pOutAddr->uFamily = AF_INET;
|
|
if (pToken1 != NULL)
|
|
{
|
|
struct sockaddr tempAddr; //doing this so i can make use of SockaddrInSetAddrText
|
|
SockaddrInit(&tempAddr, AF_INET);
|
|
SockaddrInSetAddrText(&tempAddr, pToken1);
|
|
pOutAddr->addr.v4 = SockaddrInGetAddr(&tempAddr);
|
|
iRet = 0;
|
|
}
|
|
if (pToken2 != NULL)
|
|
{
|
|
pOutAddr->uPort = atoi(pToken2 + 1); // +1 to move past the ':' character
|
|
}
|
|
}
|
|
#ifndef DIRTYCODE_NX
|
|
else if ((pToken0 != NULL) && (ds_strnicmp(pToken0, "v6", 2) == 0))
|
|
{
|
|
pOutAddr->uFamily = AF_INET6;
|
|
if (pToken1 != NULL)
|
|
{
|
|
struct sockaddr_in6 tempAddr; //doing this so i can make use of SockaddrInSetAddrText
|
|
SockaddrInit6(&tempAddr, AF_INET6);
|
|
SockaddrInSetAddrText((struct sockaddr *)&tempAddr, pToken1); //this will translate the string into the bytes it needs to be
|
|
ds_memcpy(&(pOutAddr->addr.v6), &tempAddr.sin6_addr, sizeof(pOutAddr->addr.v6)); //write the bytes into our structure
|
|
iRet = 0;
|
|
}
|
|
if (pToken2 != NULL)
|
|
{
|
|
pOutAddr->uPort = atoi(pToken2 + 1); // +1 to move past the ':' character
|
|
}
|
|
}
|
|
#endif
|
|
return(iRet);
|
|
}
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function QosCommonConvertAddr
|
|
|
|
\Description
|
|
Determine if pSourceAddr is remapped, if so fetch the real info and
|
|
copy the common fields from pSourceAddr to pTargetAddr.
|
|
|
|
\Input *pTargetAddr - [out] structure to store the fields we are interested in
|
|
\Input *pSourceAddr - address to copy from
|
|
|
|
\Version 06/27/2017 (cvienneau)
|
|
*/
|
|
/********************************************************************************F*/
|
|
void QosCommonConvertAddr(QosCommonAddrT *pTargetAddr, struct sockaddr *pSourceAddr)
|
|
{
|
|
#ifndef DIRTYCODE_NX
|
|
struct sockaddr_in6 SockAddr6;
|
|
|
|
//check to see if the ipv4 address coming in is a remapped ipv6 addr, if it is get the real ipv6 info
|
|
if (pSourceAddr->sa_family == AF_INET)
|
|
{
|
|
uint32_t uAddr = SockaddrInGetAddr(pSourceAddr);
|
|
if (SocketInfo(NULL, '?ip6', uAddr, &SockAddr6, sizeof(SockAddr6)) == 1)
|
|
{
|
|
pSourceAddr = (struct sockaddr *)&SockAddr6; //it is an ipv6 remapped addr, use the ipv6 info below.
|
|
}
|
|
}
|
|
#endif
|
|
|
|
pTargetAddr->uFamily = pSourceAddr->sa_family;
|
|
|
|
if (pTargetAddr->uFamily == AF_INET)
|
|
{
|
|
pTargetAddr->addr.v4 = SockaddrInGetAddr(pSourceAddr);
|
|
pTargetAddr->uPort = SockaddrInGetPort(pSourceAddr);
|
|
}
|
|
|
|
#ifndef DIRTYCODE_NX
|
|
else if (pTargetAddr->uFamily == AF_INET6)
|
|
{
|
|
struct sockaddr_in6 * pAddr6 = (struct sockaddr_in6 *)pSourceAddr;
|
|
ds_memcpy(&(pTargetAddr->addr.v6), &pAddr6->sin6_addr, sizeof(pTargetAddr->addr.v6));
|
|
pTargetAddr->uPort = pAddr6->sin6_port;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function QosCommonIsAddrEqual
|
|
|
|
\Description
|
|
Compare if two addresses belong to the same machine (ignore port).
|
|
|
|
\Input *pAddr1 - first address to compare
|
|
\Input *pAddr2 - second address to compare
|
|
|
|
\Output
|
|
uint8_t - TRUE if addresses are equal
|
|
|
|
\Version 12/09/2016 (cvienneau)
|
|
*/
|
|
/********************************************************************************F*/
|
|
uint8_t QosCommonIsAddrEqual(QosCommonAddrT *pAddr1, QosCommonAddrT *pAddr2)
|
|
{
|
|
if (pAddr1->uFamily == pAddr2->uFamily)
|
|
{
|
|
if (pAddr1->uFamily == AF_INET)
|
|
{
|
|
if (pAddr1->addr.v4 == pAddr2->addr.v4)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
}
|
|
#ifndef DIRTYCODE_NX
|
|
else if (pAddr1->uFamily == AF_INET6)
|
|
{
|
|
//just compare the address portion of the struct
|
|
if (memcmp(&pAddr1->addr.v6,
|
|
&pAddr2->addr.v6,
|
|
sizeof(pAddr1->addr.v6)) == 0)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function QosCommonIsRemappedAddrEqual
|
|
|
|
\Description
|
|
Retrieve the address remap for pAddr1 if it exists (would be the case for ipv6)
|
|
and compare it to the v4 or already remapped pAddr2 to see if they belong to the same
|
|
machine.
|
|
|
|
\Input *pAddr1 - first address to compare
|
|
\Input *pAddr2 - second address to compare
|
|
|
|
\Output
|
|
uint8_t - TRUE if addresses are equal
|
|
|
|
\Version 12/09/2016 (cvienneau)
|
|
*/
|
|
/********************************************************************************F*/
|
|
uint8_t QosCommonIsRemappedAddrEqual(QosCommonAddrT *pAddr1, struct sockaddr *pAddr2)
|
|
{
|
|
uint32_t uAddr1v4;
|
|
uint32_t uAddr2v4;
|
|
|
|
if (pAddr2->sa_family != AF_INET)
|
|
{
|
|
return(FALSE); //we expect this address to be ipv4 or a remapped ipv6, so we shouldn't see anything other than AF_INET
|
|
}
|
|
uAddr2v4 = SockaddrInGetAddr(pAddr2);
|
|
|
|
if (pAddr1->uFamily == AF_INET)
|
|
{
|
|
uAddr1v4 = pAddr1->addr.v4;
|
|
}
|
|
#ifndef DIRTYCODE_NX
|
|
else if (pAddr1->uFamily == AF_INET6)
|
|
{
|
|
struct sockaddr_in6 addr6;
|
|
SockaddrInit6(&addr6, AF_INET6);
|
|
ds_memcpy(&addr6.sin6_addr, &(pAddr1->addr.v6), sizeof(addr6.sin6_addr));
|
|
addr6.sin6_port = pAddr1->uPort;
|
|
uAddr1v4 = SocketControl(NULL, '+ip6', sizeof(addr6), &addr6, NULL);
|
|
//todo when will things be removed from the address map?
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
return(FALSE); // we don't know the type, they're not equal
|
|
}
|
|
|
|
if (uAddr1v4 == uAddr2v4)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function QosCommonSerializeProbePacket
|
|
|
|
\Description
|
|
Write the contents of a QosCommonProbePacketT struct to a buffer, sign it for authenticity
|
|
in preparation for sending it on the wire.
|
|
|
|
\Input *pOutBuff - [out] buffer the packet will be written to
|
|
\Input uBuffSize - size of the buffer the packet is being written to, must be at least QOS_COMMON_MIN_PACKET_SIZE
|
|
\Input *pInPacket - the structure containing the probe packet information
|
|
\Input *pSecureKey- the secure key used to sign the probe as being authentic
|
|
|
|
\Output
|
|
uint8_t - number of bytes written to the buffer
|
|
|
|
\Version 07/06/2017 (cvienneau)
|
|
*/
|
|
/********************************************************************************F*/
|
|
uint8_t QosCommonSerializeProbePacket(uint8_t *pOutBuff, uint32_t uBuffSize, const QosCommonProbePacketT *pInPacket, uint8_t *pSecureKey)
|
|
{
|
|
/*
|
|
This is the order we are going to serialize in
|
|
uint32_t uProtocol; //!< QOS 2.0 packets will always contain 'qos2' for easy identification.
|
|
uint16_t uVersion; //!< uniquely identifies protocol
|
|
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
|
|
uint16_t uClientRequestId; //!< provided by the client, unique to a particular QOS action, used to pair request and responses together
|
|
uint32_t uServerReceiveTime; //!< time the server received this probe from the client
|
|
uint16_t uServerSendDelta; //!< delta before the server sent this probe response
|
|
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
|
|
uint8_t uProbeCountUp; //!< count index of this probe
|
|
uint8_t uProbeCountDown; //!< count index of this probe
|
|
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
|
|
uint8_t aHmac[QOS_COMMON_HMAC_SIZE];//!< when combined with the secure key identifies this packet as coming from a real QOS client
|
|
*/
|
|
if (uBuffSize >= QOS_COMMON_MIN_PACKET_SIZE)
|
|
{
|
|
uint32_t uTemp32;
|
|
uint16_t uTemp16;
|
|
uint8_t *pWrite = pOutBuff;
|
|
|
|
uTemp32 = SocketHtonl(pInPacket->uProtocol); ds_memcpy(pWrite, &uTemp32, sizeof(uint32_t)); pWrite += sizeof(uint32_t); //4
|
|
uTemp16 = SocketHtons(pInPacket->uVersion); ds_memcpy(pWrite, &uTemp16, sizeof(uint16_t)); pWrite += sizeof(uint16_t); //2
|
|
uTemp32 = SocketHtonl(pInPacket->uServiceRequestId); ds_memcpy(pWrite, &uTemp32, sizeof(uint32_t)); pWrite += sizeof(uint32_t); //4
|
|
uTemp16 = SocketHtons(pInPacket->uClientRequestId); ds_memcpy(pWrite, &uTemp16, sizeof(uint16_t)); pWrite += sizeof(uint16_t); //2
|
|
uTemp32 = SocketHtonl(pInPacket->uServerReceiveTime); ds_memcpy(pWrite, &uTemp32, sizeof(uint32_t)); pWrite += sizeof(uint32_t); //4
|
|
uTemp16 = SocketHtons(pInPacket->uServerSendDelta); ds_memcpy(pWrite, &uTemp16, sizeof(uint16_t)); pWrite += sizeof(uint16_t); //2
|
|
uTemp16 = SocketHtons(pInPacket->uProbeSizeUp); ds_memcpy(pWrite, &uTemp16, sizeof(uint16_t)); pWrite += sizeof(uint16_t); //2
|
|
uTemp16 = SocketHtons(pInPacket->uProbeSizeDown); ds_memcpy(pWrite, &uTemp16, sizeof(uint16_t)); pWrite += sizeof(uint16_t); //2
|
|
/*pInPacket->uProbeCountUp;*/ ds_memcpy(pWrite, &pInPacket->uProbeCountUp, sizeof(uint8_t)); pWrite += sizeof(uint8_t); //1
|
|
/*pInPacket->uProbeCountDown;*/ ds_memcpy(pWrite, &pInPacket->uProbeCountDown, sizeof(uint8_t)); pWrite += sizeof(uint8_t); //1
|
|
/*pInPacket->uExpectedProbeCountUp;*/ ds_memcpy(pWrite, &pInPacket->uExpectedProbeCountUp, sizeof(uint8_t)); pWrite += sizeof(uint8_t); //1
|
|
uTemp16 = SocketHtons(pInPacket->clientAddressFromService.uFamily); ds_memcpy(pWrite, &uTemp16, sizeof(uint16_t)); pWrite += sizeof(uint16_t); //2
|
|
uTemp16 = SocketHtons(pInPacket->clientAddressFromService.uPort); ds_memcpy(pWrite, &uTemp16, sizeof(uint16_t)); pWrite += sizeof(uint16_t); //2
|
|
uTemp32 = SocketHtonl(pInPacket->clientAddressFromService.addr.v6.aDwords[0]); ds_memcpy(pWrite, &uTemp32, sizeof(uint32_t)); pWrite += sizeof(uint32_t); //4
|
|
uTemp32 = SocketHtonl(pInPacket->clientAddressFromService.addr.v6.aDwords[1]); ds_memcpy(pWrite, &uTemp32, sizeof(uint32_t)); pWrite += sizeof(uint32_t); //4
|
|
uTemp32 = SocketHtonl(pInPacket->clientAddressFromService.addr.v6.aDwords[2]); ds_memcpy(pWrite, &uTemp32, sizeof(uint32_t)); pWrite += sizeof(uint32_t); //4
|
|
uTemp32 = SocketHtonl(pInPacket->clientAddressFromService.addr.v6.aDwords[3]); ds_memcpy(pWrite, &uTemp32, sizeof(uint32_t)); pWrite += sizeof(uint32_t); //4
|
|
//total 45 bytes == QOS_COMMON_SIZEOF_PROBE_DATA
|
|
//generate hmac, it is just bytes, we don't need to hton them
|
|
//hash the probe values with the secure key to sign the probe as being authentic
|
|
CryptHmacCalc(pWrite, QOS_COMMON_HMAC_SIZE, pOutBuff, QOS_COMMON_SIZEOF_PROBE_DATA, pSecureKey, QOS_COMMON_SECURE_KEY_LENGTH, QOS_COMMON_HMAC_TYPE);
|
|
pWrite += QOS_COMMON_HMAC_SIZE;
|
|
return(pWrite - pOutBuff);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function QosCommonDeserializeClientRequestId
|
|
|
|
\Description
|
|
Read the uClientRequestId from the packet without doing any validation.
|
|
|
|
\Input *pInBuff - buffer the packet will be read from
|
|
|
|
\Output
|
|
uint16_t - the uClientRequestId field from a serialized QosCommonProbePacketT
|
|
|
|
\Version 07/06/2017 (cvienneau)
|
|
*/
|
|
/********************************************************************************F*/
|
|
uint16_t QosCommonDeserializeClientRequestId(uint8_t *pInBuff)
|
|
{
|
|
//uClientRequestId is the 10'th byte in the serialized packet
|
|
return(SocketNtohs(*(uint16_t*)(pInBuff+10)));
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function QosCommonDeserializeServiceRequestId
|
|
|
|
\Description
|
|
Read the uServiceRequestId from the packet without doing any validation.
|
|
|
|
\Input *pInBuff - buffer the packet will be read from to
|
|
|
|
\Output
|
|
uint32_t - the uServiceRequestId field from a serialized QosCommonProbePacketT
|
|
|
|
\Version 07/06/2017 (cvienneau)
|
|
*/
|
|
/********************************************************************************F*/
|
|
uint32_t QosCommonDeserializeServiceRequestId(uint8_t *pInBuff)
|
|
{
|
|
//uServiceRequestId is the 6'th byte in the serialized packet
|
|
return(SocketNtohl(*(uint32_t*)(pInBuff + 6)));
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function QosCommonDeserializeProbePacket
|
|
|
|
\Description
|
|
Authenticate and read a QosCommonProbePacketT from the provided buffer.
|
|
|
|
\Input *pOutPacket - [out] struct to contain the deserailzed probe
|
|
\Input *pInBuff - buffer the probe is read from
|
|
\Input *pSecureKey1 - secure key used to authenticate the probe data
|
|
\Input *pSecureKey2 - optional alternative, secure key used to authenticate the probe data
|
|
|
|
\Output
|
|
uint32_t - 0=first secure key succeeded, 1=second secure key succeeded, else failure
|
|
|
|
\Version 07/06/2017 (cvienneau)
|
|
*/
|
|
/********************************************************************************F*/
|
|
uint8_t QosCommonDeserializeProbePacket(QosCommonProbePacketT *pOutPacket, uint8_t *pInBuff, uint8_t *pSecureKey1, uint8_t *pSecureKey2)
|
|
{
|
|
uint8_t uRet = 0;
|
|
|
|
#if QOS_COMMON_ENABLE_HMAC
|
|
uint8_t aHmac[QOS_COMMON_HMAC_SIZE];
|
|
|
|
//validate the hmac, which is at the end of the packet
|
|
//generate what we think the hmac should be
|
|
CryptHmacCalc(aHmac, QOS_COMMON_HMAC_SIZE, pInBuff, QOS_COMMON_SIZEOF_PROBE_DATA, pSecureKey1, QOS_COMMON_SECURE_KEY_LENGTH, QOS_COMMON_HMAC_TYPE);
|
|
if (memcmp(aHmac, pInBuff + QOS_COMMON_SIZEOF_PROBE_DATA, QOS_COMMON_HMAC_SIZE) != 0)
|
|
{
|
|
//first secure key failed, try with the backup secure key if one was provided
|
|
if (pSecureKey2 != NULL)
|
|
{
|
|
CryptHmacCalc(aHmac, QOS_COMMON_HMAC_SIZE, pInBuff, QOS_COMMON_SIZEOF_PROBE_DATA, pSecureKey2, QOS_COMMON_SECURE_KEY_LENGTH, QOS_COMMON_HMAC_TYPE);
|
|
if (memcmp(aHmac, pInBuff + QOS_COMMON_SIZEOF_PROBE_DATA, QOS_COMMON_HMAC_SIZE) != 0)
|
|
{
|
|
return(2); //failed authentication
|
|
}
|
|
else
|
|
{
|
|
uRet = 1; //first hmac didn't succeed but second one did
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return(2); //failed authentication
|
|
}
|
|
}
|
|
#endif
|
|
|
|
QosCommonDeserializeProbePacketInsecure(pOutPacket, pInBuff);
|
|
return(uRet);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function QosCommonDeserializeProbePacketInsecure
|
|
|
|
\Description
|
|
Read a QosCommonProbePacketT from the provided buffer.
|
|
|
|
\Input *pOutPacket - [out] struct to contain the deserailzed probe
|
|
\Input *pInBuff - buffer the probe is read from
|
|
|
|
\Version 07/06/2017 (cvienneau)
|
|
*/
|
|
/********************************************************************************F*/
|
|
void QosCommonDeserializeProbePacketInsecure(QosCommonProbePacketT *pOutPacket, uint8_t *pInBuff)
|
|
{
|
|
/*
|
|
This is the order we are going to deserialize from
|
|
uint32_t uProtocol; //!< QOS 2.0 packets will always contain 'qos2' for easy identification.
|
|
uint16_t uVersion; //!< uniquely identifies protocol
|
|
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
|
|
uint16_t uClientRequestId; //!< provided by the client, unique to a particular QOS action, used to pair request and responses together
|
|
uint32_t uServerReceiveTime; //!< time the server received this probe from the client
|
|
uint32_t uServerSendDelta; //!< delta before the server sent this probe response
|
|
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
|
|
uint8_t uProbeCountUp; //!< count index of this probe
|
|
uint8_t uProbeCountDown; //!< count index of this probe
|
|
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
|
|
uint8_t aHmac[QOS_COMMON_HMAC_SIZE];//!< when combined with the secure key identifies this packet as coming from a real QOS client
|
|
*/
|
|
pOutPacket->uProtocol = SocketNtohl(*(uint32_t*)pInBuff); pInBuff += sizeof(uint32_t); //4
|
|
pOutPacket->uVersion = SocketNtohs(*(uint16_t*)pInBuff); pInBuff += sizeof(uint16_t); //2
|
|
pOutPacket->uServiceRequestId = SocketNtohl(*(uint32_t*)pInBuff); pInBuff += sizeof(uint32_t); //4
|
|
pOutPacket->uClientRequestId = SocketNtohs(*(uint16_t*)pInBuff); pInBuff += sizeof(uint16_t); //2
|
|
pOutPacket->uServerReceiveTime = SocketNtohl(*(uint32_t*)pInBuff); pInBuff += sizeof(uint32_t); //4
|
|
pOutPacket->uServerSendDelta = SocketNtohl(*(uint16_t*)pInBuff); pInBuff += sizeof(uint16_t); //2
|
|
pOutPacket->uProbeSizeUp = SocketNtohs(*(uint16_t*)pInBuff); pInBuff += sizeof(uint16_t); //2
|
|
pOutPacket->uProbeSizeDown = SocketNtohs(*(uint16_t*)pInBuff); pInBuff += sizeof(uint16_t); //2
|
|
pOutPacket->uProbeCountUp = *pInBuff; pInBuff += sizeof(uint8_t); //1
|
|
pOutPacket->uProbeCountDown = *pInBuff; pInBuff += sizeof(uint8_t); //1
|
|
pOutPacket->uExpectedProbeCountUp = *pInBuff; pInBuff += sizeof(uint8_t); //1
|
|
pOutPacket->clientAddressFromService.uFamily = SocketNtohs(*(uint16_t*)pInBuff); pInBuff += sizeof(uint16_t); //2
|
|
pOutPacket->clientAddressFromService.uPort = SocketNtohs(*(uint16_t*)pInBuff); pInBuff += sizeof(uint16_t); //2
|
|
pOutPacket->clientAddressFromService.addr.v6.aDwords[0] = SocketNtohl(*(uint32_t*)pInBuff); pInBuff += sizeof(uint32_t); //4
|
|
pOutPacket->clientAddressFromService.addr.v6.aDwords[1] = SocketNtohl(*(uint32_t*)pInBuff); pInBuff += sizeof(uint32_t); //4
|
|
pOutPacket->clientAddressFromService.addr.v6.aDwords[2] = SocketNtohl(*(uint32_t*)pInBuff); pInBuff += sizeof(uint32_t); //4
|
|
pOutPacket->clientAddressFromService.addr.v6.aDwords[3] = SocketNtohl(*(uint32_t*)pInBuff); pInBuff += sizeof(uint32_t); //4
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function QosCommonMakeVersion
|
|
|
|
\Description
|
|
Make a version number out of a major and minor version parts
|
|
|
|
\Input uMajor - major byte, indicates non-backwards compatible changes
|
|
\Input uMinor - minor byte, indicates bug fixes
|
|
|
|
\Output
|
|
uint16_t - 2 bytes representing a version.
|
|
|
|
\Version 12/09/2016 (cvienneau)
|
|
*/
|
|
/********************************************************************************F*/
|
|
uint16_t QosCommonMakeVersion(uint8_t uMajor, uint8_t uMinor)
|
|
{
|
|
uint16_t uVersion = (uMajor << 8) + uMinor;
|
|
return(uVersion);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function QosCommonGetVersion
|
|
|
|
\Description
|
|
Split a version number into major and minor version parts
|
|
|
|
\Input uVersion - full version, to be split into major and minor components
|
|
\Input *uMajor - [out] major byte, indicates non-backwards compatible changes
|
|
\Input *uMinor - [out] minor byte, indicates bug fixes
|
|
|
|
\Version 12/09/2016 (cvienneau)
|
|
*/
|
|
/********************************************************************************F*/
|
|
void QosCommonGetVersion(uint16_t uVersion, uint8_t *uMajor, uint8_t *uMinor)
|
|
{
|
|
*uMajor = (uVersion >> 8);
|
|
*uMinor = (uVersion & 0x00FF);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function QosCommonIsCompatibleVersion
|
|
|
|
\Description
|
|
Compare the major portion of two version number to see if they are compatible.
|
|
|
|
\Input uVersion1 - first version
|
|
\Input uVersion2 - second version
|
|
|
|
\Output
|
|
uint8_t - TRUE if they are compatible
|
|
|
|
\Version 12/09/2016 (cvienneau)
|
|
*/
|
|
/********************************************************************************F*/
|
|
uint8_t QosCommonIsCompatibleVersion(uint16_t uVersion1, uint16_t uVersion2)
|
|
{
|
|
uint8_t uMajor1 = (uVersion1 >> 8);
|
|
uint8_t uMajor2 = (uVersion2 >> 8);
|
|
if (uMajor1 == uMajor2)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function QosCommonIsCompatibleProbeVersion
|
|
|
|
\Description
|
|
Compare if probes of the passed in version are compatible with our version of code.
|
|
|
|
\Input uVersion - version of probe
|
|
|
|
\Output
|
|
uint8_t - TRUE if they are compatible
|
|
|
|
\Version 12/09/2016 (cvienneau)
|
|
*/
|
|
/********************************************************************************F*/
|
|
uint8_t QosCommonIsCompatibleProbeVersion(uint16_t uVersion)
|
|
{
|
|
uint8_t uMajor = (uVersion >> 8);
|
|
if (uMajor == QOS_COMMON_PROBE_VERSION_MAJOR)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
return(FALSE);
|
|
}
|