openmohaa/code/gamespy/sake/sakeRequest.c
2023-02-04 21:00:01 +01:00

287 lines
9.3 KiB
C

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#include "sakeRequest.h"
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
const char * GSI_SAKE_SERVICE_NAMESPACES[GSI_SAKE_SERVICE_NAMESPACE_COUNT] =
{
"ns1=\"http://gamespy.net/sake\""
};
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#define SAKEI_SOAP_URL_FORMAT "http://%s.sake." GSI_DOMAIN_NAME "/SakeStorageServer/StorageServer.asmx"
char sakeiSoapUrl[SAKE_MAX_URL_LENGTH] = "";
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
SAKERequest SAKE_CALL sakeiInitRequest(SAKE sake, SAKEIRequestType type, void *input, SAKERequestCallback callback, void *userData)
{
SAKERequest request;
GS_ASSERT(sake);
// init the request init result to success
sake->mStartRequestResult = SAKEStartRequestResult_SUCCESS;
// check for input
if(!input)
{
sake->mStartRequestResult = SAKEStartRequestResult_BAD_INPUT;
return NULL;
}
// check for authentication
if(gsi_is_false(sake->mIsGameAuthenticated) || gsi_is_false(sake->mIsProfileAuthenticated))
{
sake->mStartRequestResult = SAKEStartRequestResult_NOT_AUTHENTICATED;
return NULL;
}
// allocate memory for the request object
request = (SAKERequest)gsimalloc(sizeof(SAKERequestInternal));
if(!request)
{
sake->mStartRequestResult = SAKEStartRequestResult_OUT_OF_MEMORY;
return NULL;
}
// init the request object
memset(request, 0, sizeof(SAKERequestInternal));
request->mSake = sake;
request->mType = type;
request->mInput = input;
request->mCallback = callback;
request->mUserData = userData;
return request;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void SAKE_CALL sakeiFreeRequest(SAKERequest request)
{
GS_ASSERT(request);
// this should already be freed by the time we get here
GS_ASSERT(request->mOutput == NULL);
// free the request
gsifree(request);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static SAKERequestResult SAKE_CALL sakeiCheckHttpResult(GHTTPResult httpResult)
{
switch(httpResult)
{
case GHTTPSuccess:
return SAKERequestResult_SUCCESS;
case GHTTPOutOfMemory:
return SAKERequestResult_OUT_OF_MEMORY;
default:
return SAKERequestResult_CONNECTION_ERROR;
}
}
static SAKERequestResult SAKE_CALL sakeiCheckSakeResult(const char * sakeResult)
{
if(strcmp(sakeResult, "Success") == 0)
return SAKERequestResult_SUCCESS;
else if(strcmp(sakeResult, "SecretKeyInvalid") == 0)
return SAKERequestResult_SECRET_KEY_INVALID;
else if(strcmp(sakeResult, "ServiceDisabled") == 0)
return SAKERequestResult_SERVICE_DISABLED;
else if(strcmp(sakeResult, "DatabaseUnavailable") == 0)
return SAKERequestResult_DATABASE_UNAVAILABLE;
else if(strcmp(sakeResult, "LoginTicketInvalid") == 0)
return SAKERequestResult_LOGIN_TICKET_INVALID;
else if(strcmp(sakeResult, "LoginTicketExpired") == 0)
return SAKERequestResult_LOGIN_TICKET_EXPIRED;
else if(strcmp(sakeResult, "TableNotFound") == 0)
return SAKERequestResult_TABLE_NOT_FOUND;
else if(strcmp(sakeResult, "RecordNotFound") == 0)
return SAKERequestResult_RECORD_NOT_FOUND;
else if(strcmp(sakeResult, "FieldNotFound") == 0)
return SAKERequestResult_FIELD_NOT_FOUND;
else if(strcmp(sakeResult, "FieldTypeInvalid") == 0)
return SAKERequestResult_FIELD_TYPE_INVALID;
else if(strcmp(sakeResult, "NoPermission") == 0)
return SAKERequestResult_NO_PERMISSION;
else if(strcmp(sakeResult, "RecordLimitReached") == 0)
return SAKERequestResult_RECORD_LIMIT_REACHED;
else if(strcmp(sakeResult, "AlreadyRated") == 0)
return SAKERequestResult_ALREADY_RATED;
else if(strcmp(sakeResult, "NotRateable") == 0)
return SAKERequestResult_NOT_RATEABLE;
else if(strcmp(sakeResult, "NotOwned") == 0)
return SAKERequestResult_NOT_OWNED;
else if(strcmp(sakeResult, "FilterInvalid") == 0)
return SAKERequestResult_FILTER_INVALID;
else if(strcmp(sakeResult, "SortInvalid") == 0)
return SAKERequestResult_SORT_INVALID;
else if(strcmp(sakeResult, "TargetFilterInvalid") == 0)
return SAKERequestResult_TARGET_FILTER_INVALID;
else
return SAKERequestResult_UNKNOWN_ERROR;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static void SAKE_CALL sakeiSoapCallback(GHTTPResult httpResult, GSXmlStreamWriter requestData, GSXmlStreamReader responseData, void *userData)
{
SAKERequest request = (SAKERequest)userData;
void *output = NULL;
SAKERequestResult result;
char resultString[32];
// sanity check
GS_ASSERT(request);
GS_ASSERT(request->mSake);
GS_ASSERT(request->mInfo);
if(!request || !request->mSake || !request->mInfo)
return;
result = sakeiCheckHttpResult(httpResult);
if(result == SAKERequestResult_SUCCESS)
{
if(gsi_is_false(gsXmlMoveToStart(responseData)) ||
gsi_is_false(gsXmlMoveToNext(responseData, request->mInfo->mResponseTag)) ||
gsi_is_false(gsXmlReadChildAsStringNT(responseData, request->mInfo->mResultTag, resultString, sizeof(resultString))))
{
result = SAKERequestResult_MALFORMED_RESPONSE;
}
else
{
result = sakeiCheckSakeResult(resultString);
// fill in the output
if(result == SAKERequestResult_SUCCESS)
{
if(request->mInfo->mSakeOutputSize != 0)
{
request->mOutput = gsimalloc(request->mInfo->mSakeOutputSize);
if(request->mOutput)
{
request->mSoapResponse = responseData;
result = request->mInfo->mProcessSoapResponseFunc(request);
if(result == SAKERequestResult_SUCCESS)
output = request->mOutput;
}
else
{
result = SAKERequestResult_OUT_OF_MEMORY;
}
}
}
}
}
// call the callback
if(request->mCallback)
request->mCallback(request->mSake, request, result, request->mInput, output, request->mUserData);
// free data
if(request->mInfo->mFreeDataFunc)
request->mInfo->mFreeDataFunc(request);
// free the output data
gsifree(request->mOutput);
request->mOutput = NULL;
// free the sake request
sakeiFreeRequest(request);
GSI_UNUSED(requestData);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static SAKEStartRequestResult SAKE_CALL sakeiSetupRequest(SAKERequest request)
{
SAKEStartRequestResult result;
SAKEIRequestInfo * info;
GS_ASSERT(request);
GS_ASSERT(request->mSake);
GS_ASSERT(request->mInfo);
// store a utility pointer to the info
info = request->mInfo;
// check the input
result = info->mValidateInputFunc(request);
if(result != SAKEStartRequestResult_SUCCESS)
return result;
// create the xml request stream
request->mSoapRequest = gsXmlCreateStreamWriter(GSI_SAKE_SERVICE_NAMESPACES, GSI_SAKE_SERVICE_NAMESPACE_COUNT);
if(request->mSoapRequest == NULL)
return SAKEStartRequestResult_OUT_OF_MEMORY;
// open the stream
gsXmlWriteOpenTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, request->mInfo->mFuncName);
// this info is included with every request
gsXmlWriteIntElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "gameid", (gsi_u32)request->mSake->mGameId);
gsXmlWriteStringElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "secretKey", request->mSake->mSecretKey);
gsXmlWriteStringElement(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, "loginTicket", request->mSake->mLoginTicket);
// fill in the request data
result = info->mFillSoapRequestFunc(request);
if(result != SAKEStartRequestResult_SUCCESS)
{
gsXmlFreeWriter(request->mSoapRequest);
request->mSoapRequest = NULL;
if(info->mFreeDataFunc)
info->mFreeDataFunc(request);
return result;
}
// close the stream and writer
gsXmlWriteCloseTag(request->mSoapRequest, GSI_SAKE_SERVICE_NAMESPACE, request->mInfo->mFuncName);
gsXmlCloseWriter(request->mSoapRequest);
return SAKEStartRequestResult_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static void SAKE_CALL sakeiExecuteRequest(SAKERequest request)
{
if(sakeiSoapUrl[0] == '\0')
{
int rcode;
rcode = snprintf(sakeiSoapUrl, SAKE_MAX_URL_LENGTH, SAKEI_SOAP_URL_FORMAT, request->mSake->mGameName);
GS_ASSERT(rcode >= 0);
GSI_UNUSED(rcode);
}
gsiExecuteSoap(sakeiSoapUrl, request->mInfo->mSoapAction, request->mSoapRequest, sakeiSoapCallback, request);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
SAKEStartRequestResult SAKE_CALL sakeiStartRequest(SAKERequest request, SAKEIRequestInfo * info)
{
SAKEStartRequestResult result;
request->mInfo = info;
result = sakeiSetupRequest(request);
if(result != SAKEStartRequestResult_SUCCESS)
return result;
sakeiExecuteRequest(request);
return SAKEStartRequestResult_SUCCESS;
}