openmohaa/code/gamespy/sc/sciWebServices.c

601 lines
21 KiB
C
Raw Normal View History

2023-02-04 21:00:01 +01:00
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#include "../common/gsCore.h"
#include "sci.h"
#include "sciInterface.h"
#include "sciWebServices.h"
#include "sciReport.h"
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#define SC_CREATEMATCHLESSSESSION_SOAPACTION "SOAPAction: \"http://gamespy.net/competition/CreateMatchlessSession\""
#define SC_CREATESESSION_SOAPACTION "SOAPAction: \"http://gamespy.net/competition/CreateSession\""
#define SC_SUBMITREPORT_SOAPACTION "SOAPAction: \"http://gamespy.net/competition/SubmitReport\""
#define SC_SETINTENTION_SOAPACTION "SOAPAction: \"http://gamespy.net/competition/SetReportIntention\""
#define SC_SERVICE_NAMESPACE_COUNT 1
const char * SC_SERVICE_NAMESPACES[SC_SERVICE_NAMESPACE_COUNT] =
{
"gsc=\"http://gamespy.net/competition/\""
};
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
SCResult sciWsInit(SCWebServices* theWebServices,
SCInterfacePtr theInterface)
{
GS_ASSERT(theWebServices != NULL);
GS_ASSERT(theInterface != NULL);
GS_ASSERT(!theWebServices->mInit);
// Check gsCore
if (gsCoreIsShutdown())
{
return SCResult_CORE_NOT_INITIALIZED;
}
// Initialize SCWebServices struct
theWebServices->mInterface = theInterface;
theWebServices->mCreateSessionCallback = NULL;
theWebServices->mSetReportIntentionCallback = NULL;
theWebServices->mSubmitReportDataCallback = NULL;
theWebServices->mCreateSessionUserData = NULL;
theWebServices->mSetReportIntentionUserData = NULL;
theWebServices->mSubmitReportUserData = NULL;
theWebServices->mCreateSessionPending = gsi_false;
theWebServices->mSetReportIntentionPending = gsi_false;
theWebServices->mSubmitReportPending = gsi_false;
// Now initialized
theWebServices->mInit = gsi_true;
return SCResult_NO_ERROR;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void sciWsDestroy(SCWebServices* theWebServices)
{
GS_ASSERT(theWebServices != NULL);
GS_ASSERT(theWebServices->mInit);
// No longer initialized
theWebServices->mInit = gsi_false;
// Destroy SCWebServices struct
theWebServices->mCreateSessionCallback = NULL;
theWebServices->mSetReportIntentionCallback = NULL;
theWebServices->mSubmitReportDataCallback = NULL;
theWebServices->mCreateSessionUserData = NULL;
theWebServices->mSetReportIntentionUserData = NULL;
theWebServices->mSubmitReportUserData = NULL;
theWebServices->mCreateSessionPending = gsi_false;
theWebServices->mSetReportIntentionPending = gsi_false;
theWebServices->mSubmitReportPending = gsi_false;
theWebServices->mInterface = NULL;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void sciWsThink(SCWebServices* theWebServices)
{
GS_ASSERT(theWebServices != NULL);
GS_ASSERT(theWebServices->mInit);
gsCoreThink(0);
GSI_UNUSED(theWebServices);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
SCResult sciWsCreateSession (SCWebServices * theWebServices,
gsi_u32 theGameId,
const GSLoginCertificate * theCertificate,
const GSLoginPrivateData * thePrivateData,
SCCreateSessionCallback theCallback,
gsi_time theTimeoutMs,
void * theUserData)
{
GSXmlStreamWriter aRequest = NULL;
// Check parameters
GS_ASSERT(theWebServices != NULL);
GS_ASSERT(theWebServices->mInit);
// Check for pending request
if (theWebServices->mCreateSessionPending)
return SCResult_CALLBACK_PENDING;
// Create the XML message writer
aRequest = gsXmlCreateStreamWriter(SC_SERVICE_NAMESPACES, SC_SERVICE_NAMESPACE_COUNT);
if (aRequest == NULL)
return SCResult_OUT_OF_MEMORY;
// Fill in the request data
if (gsi_is_false(gsXmlWriteOpenTag(aRequest, "gsc", "CreateSession")) ||
gsi_is_false(gsXmlWriteOpenTag(aRequest, "gsc", "certificate")) ||
gsi_is_false(wsLoginCertWriteXML(theCertificate, "gsc", aRequest)) ||
gsi_is_false(gsXmlWriteCloseTag(aRequest, "gsc", "certificate")) ||
gsi_is_false(gsXmlWriteHexBinaryElement(aRequest, "gsc", "proof", (const gsi_u8*)thePrivateData->mKeyHash, GS_CRYPT_MD5_HASHSIZE)) ||
gsi_is_false(gsXmlWriteIntElement(aRequest, "gsc", "gameid", (gsi_u32)theGameId)) ||
gsi_is_false(gsXmlWriteCloseTag(aRequest, "gsc", "CreateSession")) ||
gsi_is_false(gsXmlCloseWriter(aRequest))
)
{
gsXmlFreeWriter(aRequest);
return SCResult_HTTP_ERROR;
}
// Set callback
theWebServices->mCreateSessionCallback = theCallback;
theWebServices->mCreateSessionUserData = theUserData;
theWebServices->mCreateSessionPending = gsi_true;
// Execute soap call
gsiExecuteSoap(scServiceURL, SC_CREATESESSION_SOAPACTION,
aRequest, sciWsCreateSessionCallback, theWebServices);
GSI_UNUSED(theTimeoutMs);
return SCResult_NO_ERROR;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
SCResult sciWsCreateMatchlessSession (SCWebServices * theWebServices,
gsi_u32 theGameId,
const GSLoginCertificate * theCertificate,
const GSLoginPrivateData * thePrivateData,
SCCreateSessionCallback theCallback,
gsi_time theTimeoutMs,
void * theUserData)
{
GSXmlStreamWriter aRequest = NULL;
// Check parameters
GS_ASSERT(theWebServices != NULL);
GS_ASSERT(theWebServices->mInit);
// Check for pending request
if (theWebServices->mCreateSessionPending)
return SCResult_CALLBACK_PENDING;
// Create the XML message writer
aRequest = gsXmlCreateStreamWriter(SC_SERVICE_NAMESPACES, SC_SERVICE_NAMESPACE_COUNT);
if (aRequest == NULL)
return SCResult_OUT_OF_MEMORY;
// Fill in the request data
if (gsi_is_false(gsXmlWriteOpenTag(aRequest, "gsc", "CreateMatchlessSession")) ||
gsi_is_false(gsXmlWriteOpenTag(aRequest, "gsc", "certificate")) ||
gsi_is_false(wsLoginCertWriteXML(theCertificate, "gsc", aRequest)) ||
gsi_is_false(gsXmlWriteCloseTag(aRequest, "gsc", "certificate")) ||
gsi_is_false(gsXmlWriteHexBinaryElement(aRequest, "gsc", "proof", (const gsi_u8*)thePrivateData->mKeyHash, GS_CRYPT_MD5_HASHSIZE)) ||
gsi_is_false(gsXmlWriteIntElement(aRequest, "gsc", "gameid", (gsi_u32)theGameId)) ||
gsi_is_false(gsXmlWriteCloseTag(aRequest, "gsc", "CreateMatchlessSession")) ||
gsi_is_false(gsXmlCloseWriter(aRequest))
)
{
gsXmlFreeWriter(aRequest);
return SCResult_HTTP_ERROR;
}
// Set callback
theWebServices->mCreateSessionCallback = theCallback;
theWebServices->mCreateSessionUserData = theUserData;
theWebServices->mCreateSessionPending = gsi_true;
// Execute soap call
gsiExecuteSoap(scServiceURL, SC_CREATEMATCHLESSSESSION_SOAPACTION,
aRequest, sciWsCreateSessionCallback, theWebServices);
GSI_UNUSED(theTimeoutMs);
return SCResult_NO_ERROR;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void sciWsCreateSessionCallback(GHTTPResult theHttpResult,
GSXmlStreamWriter theRequestData,
GSXmlStreamReader theResponseData,
void* theUserData)
{
SCResult aTranslatedResult = SCResult_HTTP_ERROR;
SCWebServices* aWebServices = (SCWebServices*)theUserData;
char csid[255];
char ccid[255];
int csidLen = 255;
int ccidLen = 255;
GS_ASSERT(aWebServices != NULL);
GS_ASSERT(aWebServices->mCreateSessionPending);
// Check for shutdown
if (!aWebServices->mInit)
return;
if (theHttpResult == GHTTPSuccess)
{
int createResult = 0;
// Parse through in a way that will work for either type of CreateSession response.
if (gsi_is_false(gsXmlMoveToStart(theResponseData)))
{
aTranslatedResult = SCResult_RESPONSE_INVALID;
}
else if(gsi_is_false(gsXmlMoveToNext(theResponseData, "CreateSessionResponse")))
{
if(gsi_is_false(gsXmlMoveToNext(theResponseData, "CreateMatchlessSessionResponse")))
{
aTranslatedResult = SCResult_RESPONSE_INVALID;
}
}
if(gsi_is_false(gsXmlMoveToNext(theResponseData, "CreateSessionResult")))
{
if(gsi_is_false(gsXmlMoveToNext(theResponseData, "CreateMatchlessSessionResult")))
{
aTranslatedResult = SCResult_RESPONSE_INVALID;
}
}
if(gsi_is_false(gsXmlReadChildAsInt(theResponseData, "result", &createResult)))
{
aTranslatedResult = SCResult_RESPONSE_INVALID;
}
else if(aTranslatedResult != SCResult_RESPONSE_INVALID)
{
// Parse server reported result
if (createResult == SCWsResult_NO_ERROR)
{
// Read session and connection ID
if(gsi_is_false(gsXmlReadChildAsStringNT(theResponseData, "csid", csid, csidLen)) ||
gsi_is_false(gsXmlReadChildAsStringNT(theResponseData, "ccid", ccid, ccidLen))
)
{
aTranslatedResult = SCResult_RESPONSE_INVALID;
}
else
{
sciInterfaceSetSessionId((SCInterface*)aWebServices->mInterface, csid);
sciInterfaceSetConnectionId((SCInterface*)aWebServices->mInterface, ccid);
aTranslatedResult = SCResult_NO_ERROR;
}
}
else
{
// Server reported an error, handle it?
// TODO:
// translate result into developer useable form
// report result string as gsDebugFormat message for easier debugging
aTranslatedResult = SCResult_RESPONSE_INVALID;
}
}
}
else
{
aTranslatedResult = SCResult_HTTP_ERROR;
}
// Client callback
aWebServices->mCreateSessionPending = gsi_false;
if (aWebServices->mCreateSessionCallback != NULL)
{
aWebServices->mCreateSessionCallback(aWebServices->mInterface, theHttpResult, aTranslatedResult, aWebServices->mCreateSessionUserData);
aWebServices->mCreateSessionUserData = NULL;
aWebServices->mCreateSessionCallback = NULL;
}
GSI_UNUSED(theRequestData);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
SCResult sciWsSetReportIntention(SCWebServices* theWebServices,
gsi_u32 theGameId,
const char * theSessionId,
const char * theConnectionId,
gsi_bool isAuthoritative,
const GSLoginCertificate * theCertificate,
const GSLoginPrivateData * thePrivateData,
SCSetReportIntentionCallback theCallback,
gsi_time theTimeoutMs,
void * theUserData)
{
GSXmlStreamWriter aRequest = NULL;
// Check parameters
GS_ASSERT(theWebServices != NULL);
GS_ASSERT(theWebServices->mInit);
// Check for pending request
if (theWebServices->mSetReportIntentionPending)
return SCResult_CALLBACK_PENDING;
// Create the XML message writer
aRequest = gsXmlCreateStreamWriter(SC_SERVICE_NAMESPACES, SC_SERVICE_NAMESPACE_COUNT);
if (aRequest == NULL)
return SCResult_OUT_OF_MEMORY;
// Fill in the request data
if (gsi_is_false(gsXmlWriteOpenTag(aRequest, "gsc", "SetReportIntention")) ||
gsi_is_false(gsXmlWriteOpenTag(aRequest, "gsc", "certificate")) ||
gsi_is_false(wsLoginCertWriteXML(theCertificate, "gsc", aRequest)) ||
gsi_is_false(gsXmlWriteCloseTag(aRequest, "gsc", "certificate")) ||
gsi_is_false(gsXmlWriteHexBinaryElement(aRequest, "gsc", "proof", (const gsi_u8*)thePrivateData->mKeyHash, GS_CRYPT_MD5_HASHSIZE)) ||
gsi_is_false(gsXmlWriteStringElement(aRequest, "gsc", "csid", theSessionId)) ||
gsi_is_false(gsXmlWriteStringElement(aRequest, "gsc", "ccid", theConnectionId)) ||
gsi_is_false(gsXmlWriteIntElement(aRequest, "gsc", "gameid", (gsi_u32)theGameId)) ||
gsi_is_false(gsXmlWriteIntElement(aRequest, "gsc", "authoritative", (gsi_u32)(gsi_is_true(isAuthoritative) ? 1:0))) ||
gsi_is_false(gsXmlWriteCloseTag(aRequest, "gsc", "SetReportIntention")) ||
gsi_is_false(gsXmlCloseWriter(aRequest))
)
{
gsXmlFreeWriter(aRequest);
return SCResult_HTTP_ERROR;
}
// Set callback
theWebServices->mSetReportIntentionCallback = theCallback;
theWebServices->mSetReportIntentionUserData = theUserData;
theWebServices->mSetReportIntentionPending = gsi_true;
// Execute soap call
gsiExecuteSoap(scServiceURL, SC_SETINTENTION_SOAPACTION,
aRequest, sciWsSetReportIntentionCallback, theWebServices);
GSI_UNUSED(theTimeoutMs);
return SCResult_NO_ERROR;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void sciWsSetReportIntentionCallback(GHTTPResult theHttpResult,
GSXmlStreamWriter theRequestData,
GSXmlStreamReader theResponseData,
void* theUserData)
{
SCResult aTranslatedResult = SCResult_HTTP_ERROR;
SCWebServices* aWebServices = (SCWebServices*)theUserData;
char ccid[255];
int ccidLen = 255;
GS_ASSERT(aWebServices != NULL);
GS_ASSERT(aWebServices->mSetReportIntentionPending);
// Check for shutdown
if (!aWebServices->mInit)
return;
if (theHttpResult == GHTTPSuccess)
{
int intentionResult = 0;
if (gsi_is_false(gsXmlMoveToStart(theResponseData)) ||
gsi_is_false(gsXmlMoveToNext(theResponseData, "SetReportIntentionResponse")) ||
gsi_is_false(gsXmlMoveToNext(theResponseData, "SetReportIntentionResult")) ||
gsi_is_false(gsXmlReadChildAsInt(theResponseData, "result", &intentionResult)) ||
gsi_is_false(gsXmlReadChildAsStringNT(theResponseData, "ccid", ccid, ccidLen))
)
{
aTranslatedResult = SCResult_RESPONSE_INVALID;
}
else
{
if (intentionResult == SCWsResult_NO_ERROR)
{
aTranslatedResult = SCResult_NO_ERROR;
sciInterfaceSetConnectionId((SCInterface*)aWebServices->mInterface, ccid);
}
else
aTranslatedResult = SCResult_UNKNOWN_RESPONSE;
}
}
else
{
aTranslatedResult = SCResult_HTTP_ERROR;
}
// Client callback
aWebServices->mSetReportIntentionPending = gsi_false;
if (aWebServices->mSetReportIntentionCallback != NULL)
{
aWebServices->mSetReportIntentionCallback(aWebServices->mInterface,
theHttpResult,
aTranslatedResult,
aWebServices->mSetReportIntentionUserData);
aWebServices->mSetReportIntentionUserData = NULL;
aWebServices->mSetReportIntentionCallback = NULL;
}
GSI_UNUSED(theRequestData);
}
///////////////////////////////////////////////////////////////////////////////
// declared here to allow function to get around Unicode calls
extern GHTTPBool ghiPostAddFileFromMemory(GHTTPPost post,const char * name,const char * buffer,
int bufferLen,const char * reportFilename,const char * contentType);
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Private GSSoapCustomFunc used by sciWsSubmitReport
static void sciWsSubmitReportCustom(GHTTPPost thePost, void* theUserData)
{
SCWebServices* aWebServices = (SCWebServices*)theUserData;
//Use internal method to get around unicode calls
ghiPostAddFileFromMemory(thePost, "report", (char *)aWebServices->mSubmitReportData,
(gsi_i32)aWebServices->mSubmitReportLength, "report", "application/bin");
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
SCResult sciWsSubmitReport(SCWebServices* theWebServices,
gsi_u32 theGameId,
const char * theSessionId,
const char * theConnectionId,
const SCIReport * theReport,
gsi_bool isAuthoritative,
const GSLoginCertificate * theCertificate,
const GSLoginPrivateData * thePrivateData,
SCSubmitReportCallback theCallback,
gsi_time theTimeoutMs,
void * theUserData)
{
GSXmlStreamWriter aRequest = NULL;
//SCIReportHeader * aReportHeader = NULL;
//gsi_u32 aTotalSize = 0;
//SCReportStatus* aStatus = NULL;
// Check parameters
GS_ASSERT(theWebServices != NULL);
//GS_ASSERT(theReportData != NULL);
// Check for pending request
if (theWebServices->mSubmitReportPending)
{
return SCResult_CALLBACK_PENDING;
}
// Get a pointer to the header
//aReportHeader = (SCIReportHeader*)theReport->mBuffer.mData;
// Check for complete report
if (theReport->mBuffer.mPos < sizeof(SCIReportHeader))
return SCResult_REPORT_INVALID;
// Check size (early check for easier debugging)
//aTotalSize = sizeof(SCIReportHeader);
//aTotalSize += htonl(aReportHeader->mPlayerDataLength);
//aTotalSize += htonl(aReportHeader->mTeamDataLength);
//aTotalSize += htonl(aReportHeader->mSessionDataLength);
// aTotalSize += auth info...
//if (theReport->mBuffer.mPos != aTotalSize)
// return SCResult_REPORT_INVALID;
// Create the XML message writer
aRequest = gsXmlCreateStreamWriter(SC_SERVICE_NAMESPACES, SC_SERVICE_NAMESPACE_COUNT);
if (aRequest == NULL)
return SCResult_OUT_OF_MEMORY;
// Fill in the request data
if (gsi_is_false(gsXmlWriteOpenTag(aRequest, "gsc", "SubmitReport")) ||
gsi_is_false(gsXmlWriteOpenTag(aRequest, "gsc", "certificate")) ||
gsi_is_false(wsLoginCertWriteXML(theCertificate, "gsc", aRequest)) ||
gsi_is_false(gsXmlWriteCloseTag(aRequest, "gsc", "certificate")) ||
gsi_is_false(gsXmlWriteHexBinaryElement(aRequest, "gsc", "proof", (const gsi_u8*)thePrivateData->mKeyHash, GS_CRYPT_MD5_HASHSIZE)) ||
gsi_is_false(gsXmlWriteStringElement(aRequest, "gsc", "csid", theSessionId)) ||
gsi_is_false(gsXmlWriteStringElement(aRequest, "gsc", "ccid", theConnectionId)) ||
gsi_is_false(gsXmlWriteIntElement(aRequest, "gsc", "gameid", (gsi_u32)theGameId)) ||
gsi_is_false(gsXmlWriteIntElement(aRequest, "gsc", "authoritative", (gsi_u32)(gsi_is_true(isAuthoritative) ? 1:0))) ||
gsi_is_false(gsXmlWriteCloseTag(aRequest, "gsc", "SubmitReport")) ||
gsi_is_false(gsXmlCloseWriter(aRequest))
)
{
gsXmlFreeWriter(aRequest);
return SCResult_OUT_OF_MEMORY;
}
// Get submission size
theWebServices->mSubmitReportData = (gsi_u8*)theReport->mBuffer.mData;
theWebServices->mSubmitReportLength = theReport->mBuffer.mPos;
// Set callback
theWebServices->mSubmitReportDataCallback = theCallback;
theWebServices->mSubmitReportUserData = theUserData;
theWebServices->mSubmitReportPending = gsi_true;
// Execute soap call
gsiExecuteSoapCustom(scServiceURL, SC_SUBMITREPORT_SOAPACTION,
aRequest, sciWsSubmitReportCallback,sciWsSubmitReportCustom, theWebServices);
GSI_UNUSED(theTimeoutMs);
return SCResult_NO_ERROR;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void sciWsSubmitReportCallback(GHTTPResult theHttpResult,
GSXmlStreamWriter theRequestData,
GSXmlStreamReader theResponseData,
void* theUserData)
{
SCResult aTranslatedResult = SCResult_HTTP_ERROR;
SCWebServices* aWebServices = (SCWebServices*)theUserData;
GS_ASSERT(aWebServices != NULL);
// Check for shutdown
if (!aWebServices->mInit)
return;
GS_ASSERT(aWebServices->mSubmitReportPending);
if (theHttpResult == GHTTPSuccess)
{
int submitResult = 0;
if (gsi_is_false(gsXmlMoveToStart(theResponseData)) ||
gsi_is_false(gsXmlMoveToNext(theResponseData, "SubmitReportResponse")) ||
gsi_is_false(gsXmlMoveToNext(theResponseData, "SubmitReportResult")) ||
gsi_is_false(gsXmlReadChildAsInt(theResponseData, "result", &submitResult))
)
{
aTranslatedResult = SCResult_RESPONSE_INVALID;
}
else
{
switch (submitResult)
{
case SCWsResult_NO_ERROR:
aTranslatedResult = SCResult_NO_ERROR;
break;
case SCWsResult_REPORT_INVALID:
aTranslatedResult = SCResult_REPORT_INVALID;
break;
case SCWsResult_SINGLE_ATTACHMENT_EXPECTED:
aTranslatedResult = SCResult_SUBMISSION_FAILED;
break;
default:
aTranslatedResult = SCResult_UNKNOWN_RESPONSE;
break;
};
}
}
else
{
aTranslatedResult = SCResult_HTTP_ERROR;
}
// Client callback
aWebServices->mSubmitReportPending = gsi_false;
if (aWebServices->mSubmitReportDataCallback != NULL)
{
aWebServices->mSubmitReportDataCallback(aWebServices->mInterface,
theHttpResult,
aTranslatedResult,
aWebServices->mSubmitReportUserData);
aWebServices->mSubmitReportUserData = NULL;
aWebServices->mSubmitReportDataCallback = NULL;
}
GSI_UNUSED(theRequestData);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////