280 lines
8.8 KiB
C++
280 lines
8.8 KiB
C++
/*
|
|
* Original work: Copyright (c) 2014, Oculus VR, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* RakNet License.txt file in the licenses directory of this source tree. An additional grant
|
|
* of patent rights can be found in the RakNet Patents.txt file in the same directory.
|
|
*
|
|
*
|
|
* Modified work: Copyright (c) 2016-2020, SLikeSoft UG (haftungsbeschränkt)
|
|
*
|
|
* This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
|
|
* license found in the license.txt file in the root directory of this source tree.
|
|
*/
|
|
|
|
#include "Rackspace2.h"
|
|
#include "slikenet/TCPInterface.h"
|
|
#include "slikenet/HTTPConnection2.h"
|
|
#include "slikenet/linux_adapter.h"
|
|
#include "slikenet/osx_adapter.h"
|
|
|
|
using namespace SLNet;
|
|
|
|
Rackspace2::Rackspace2()
|
|
{
|
|
X_Auth_Token[0]=0;
|
|
eventCallback=0;
|
|
tcp=0;
|
|
cloudAccountNumber=0;
|
|
reexecuteLastRequestOnAuth=false;
|
|
}
|
|
Rackspace2::~Rackspace2()
|
|
{
|
|
|
|
}
|
|
void Rackspace2::Update(void)
|
|
{
|
|
RakString stringTransmitted;
|
|
RakString hostTransmitted;
|
|
RakString responseReceived;
|
|
Packet *packet;
|
|
SystemAddress sa;
|
|
// This is kind of crappy, but for TCP plugins, always do HasCompletedConnectionAttempt, then Receive(), then HasFailedConnectionAttempt(),HasLostConnection()
|
|
sa = tcp->HasCompletedConnectionAttempt();
|
|
if (sa!=UNASSIGNED_SYSTEM_ADDRESS)
|
|
{
|
|
//printf("Rackspace2 TCP: Connected to %s\n", sa.ToString());
|
|
// serverAddress = sa;
|
|
}
|
|
for (packet = tcp->Receive(); packet; tcp->DeallocatePacket(packet), packet = tcp->Receive())
|
|
;
|
|
sa = tcp->HasFailedConnectionAttempt();
|
|
//if (sa!=UNASSIGNED_SYSTEM_ADDRESS)
|
|
// printf("Rackspace2 TCP: Failed connection attempt to %s\n", sa.ToString());
|
|
sa = tcp->HasLostConnection();
|
|
if (sa!=UNASSIGNED_SYSTEM_ADDRESS)
|
|
{
|
|
//printf("Rackspace2 TCP: Lost connection to %s\n", sa.ToString());
|
|
// serverAddress=UNASSIGNED_SYSTEM_ADDRESS;
|
|
}
|
|
|
|
SystemAddress hostReceived;
|
|
ptrdiff_t contentOffset;
|
|
if (httpConnection2->GetResponse(stringTransmitted, hostTransmitted, responseReceived, hostReceived, contentOffset))
|
|
{
|
|
if (responseReceived.IsEmpty()==false)
|
|
{
|
|
static FILE *fp = nullptr;
|
|
if (fp == nullptr)
|
|
fopen_s(&fp, "responses.txt", "wt");
|
|
// #low - add nullptr-check (incl. error logging) for fp
|
|
fprintf(fp, responseReceived.C_String());
|
|
fprintf(fp, "\n");
|
|
if (contentOffset==-1)
|
|
{
|
|
if (eventCallback)
|
|
eventCallback->OnResponse(R2RC_NO_CONTENT, responseReceived, contentOffset);
|
|
}
|
|
else
|
|
{
|
|
json_error_t error;
|
|
|
|
json_t *root = json_loads(strstr(responseReceived.C_String() + contentOffset, "{"), JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK, &error);
|
|
if (!root)
|
|
{
|
|
if (eventCallback)
|
|
eventCallback->OnResponse(R2RC_BAD_JSON, responseReceived, contentOffset);
|
|
}
|
|
else
|
|
{
|
|
void *iter = json_object_iter(root);
|
|
const char *firstKey = json_object_iter_key(iter);
|
|
if (_stricmp(firstKey, "unauthorized")==0)
|
|
{
|
|
if (eventCallback)
|
|
eventCallback->OnResponse(R2RC_UNAUTHORIZED, responseReceived, contentOffset);
|
|
}
|
|
else if (_stricmp(firstKey, "itemNotFound")==0)
|
|
{
|
|
if (eventCallback)
|
|
eventCallback->OnResponse(R2RC_404_NOT_FOUND, responseReceived, contentOffset);
|
|
}
|
|
else if (_stricmp(firstKey, "access")==0)
|
|
{
|
|
json_t *valAuthToken = json_object_get(json_object_get(json_object_get(root, "access"), "token"), "id");
|
|
strcpy_s(X_Auth_Token, json_string_value(valAuthToken));
|
|
|
|
json_t *valAccountNumber = json_object_get(json_object_get(json_object_get(json_object_get(root, "access"), "token"), "tenant"), "id");
|
|
cloudAccountNumber = atoi(json_string_value(valAccountNumber));
|
|
|
|
if (reexecuteLastRequestOnAuth)
|
|
{
|
|
reexecuteLastRequestOnAuth=false;
|
|
|
|
json_t *root2 = json_loads(__addOpLast_dataAsStr.C_String(), 0, &error);
|
|
AddOperation(__addOpLast_URL, __addOpLast_isPost, root2, true);
|
|
}
|
|
else
|
|
{
|
|
if (eventCallback)
|
|
eventCallback->OnResponse(R2RC_AUTHENTICATED, responseReceived, contentOffset);
|
|
}
|
|
|
|
}
|
|
else if (_stricmp(firstKey, "domains")==0)
|
|
{
|
|
if (eventCallback)
|
|
eventCallback->OnResponse(R2RC_GOT_DOMAINS, responseReceived, contentOffset);
|
|
}
|
|
else if (_stricmp(firstKey, "records")==0)
|
|
{
|
|
if (eventCallback)
|
|
eventCallback->OnResponse(R2RC_GOT_RECORDS, responseReceived, contentOffset);
|
|
}
|
|
else if (_stricmp(firstKey, "servers")==0)
|
|
{
|
|
if (eventCallback)
|
|
eventCallback->OnResponse(R2RC_GOT_SERVERS, responseReceived, contentOffset);
|
|
}
|
|
else if (_stricmp(firstKey, "images")==0)
|
|
{
|
|
if (eventCallback)
|
|
eventCallback->OnResponse(R2RC_GOT_IMAGES, responseReceived, contentOffset);
|
|
}
|
|
else if (_stricmp(firstKey, "message")==0)
|
|
{
|
|
const char *message = json_string_value(json_object_iter_value(iter));
|
|
|
|
if (strcmp(message, "Invalid authentication token. Please renew.")==0)
|
|
{
|
|
// Sets reexecuteLastRequestOnAuth to true
|
|
// After authenticate completes, will rerun the last run command
|
|
Reauthenticate();
|
|
}
|
|
else
|
|
{
|
|
if (eventCallback)
|
|
eventCallback->OnMessage(message, responseReceived, stringTransmitted, contentOffset);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (eventCallback)
|
|
eventCallback->OnResponse(R2RC_UNKNOWN, responseReceived, contentOffset);
|
|
}
|
|
}
|
|
|
|
json_decref(root);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (eventCallback)
|
|
eventCallback->OnEmptyResponse(stringTransmitted);
|
|
}
|
|
}
|
|
}
|
|
void Rackspace2::SetEventCallback(Rackspace2EventCallback *callback)
|
|
{
|
|
eventCallback=callback;
|
|
}
|
|
int Rackspace2::GetCloudAccountNumber(void) const
|
|
{
|
|
return cloudAccountNumber;
|
|
}
|
|
const char *Rackspace2::GetAuthToken(void) const
|
|
{
|
|
return (const char*) &X_Auth_Token;
|
|
}
|
|
void Rackspace2::Reauthenticate(void)
|
|
{
|
|
reexecuteLastRequestOnAuth=true;
|
|
AuthenticateInt(lastAuthenticationURL.C_String(), lastRackspaceCloudUsername.C_String(), lastApiAccessKey.C_String());
|
|
}
|
|
void Rackspace2::AuthenticateInt(const char *authenticationURL, const char *rackspaceCloudUsername, const char *apiAccessKey)
|
|
{
|
|
json_t *json_credentials = json_object();
|
|
json_object_set(json_credentials, "username", json_string(rackspaceCloudUsername));
|
|
json_object_set(json_credentials, "apiKey", json_string(apiAccessKey));
|
|
json_t *json_auth = json_object();
|
|
json_object_set(json_auth, "RAX-KSKEY:apiKeyCredentials", json_credentials);
|
|
json_t *json_root = json_object();
|
|
json_object_set(json_root, "auth", json_auth);
|
|
|
|
RakString URL = authenticationURL;
|
|
RakString command = "/tokens";
|
|
URL += command;
|
|
|
|
AddOperation(URL, OT_POST, json_root, false);
|
|
}
|
|
void Rackspace2::Authenticate(const char *authenticationURL, const char *rackspaceCloudUsername, const char *apiAccessKey)
|
|
{
|
|
lastAuthenticationURL=authenticationURL;
|
|
lastRackspaceCloudUsername=rackspaceCloudUsername;
|
|
lastApiAccessKey=apiAccessKey;
|
|
AuthenticateInt(authenticationURL, rackspaceCloudUsername,apiAccessKey);
|
|
}
|
|
void Rackspace2::AddOperation(SLNet::RakString URL, OpType opType, json_t *data, bool setAuthToken)
|
|
{
|
|
if (tcp==0)
|
|
{
|
|
tcp = SLNet::OP_NEW<TCPInterface>(_FILE_AND_LINE_);
|
|
|
|
if (tcp->Start(0, 0, 8)==false)
|
|
{
|
|
if (eventCallback)
|
|
eventCallback->OnTCPFailure();
|
|
}
|
|
|
|
httpConnection2 = SLNet::OP_NEW<HTTPConnection2>(_FILE_AND_LINE_);
|
|
|
|
tcp->AttachPlugin(httpConnection2);
|
|
}
|
|
|
|
RakString authURLHeader, authURLDomain, authURLPath;
|
|
URL.SplitURI(authURLHeader,authURLDomain,authURLPath);
|
|
char *jsonStr = "";
|
|
if (data)
|
|
jsonStr = json_dumps(data, 0);
|
|
RakString requestStr;
|
|
RakString extraBody;
|
|
if (setAuthToken)
|
|
{
|
|
RakAssert(X_Auth_Token[0]);
|
|
// Test expired token
|
|
//strcpy_s(X_Auth_Token, "fd6ad67c-fbd3-4b35-94e2-059b6090998e");
|
|
extraBody.Set("Accept: application/json\r\nX-Auth-Token: %s", X_Auth_Token);
|
|
|
|
__addOpLast_URL = URL;
|
|
__addOpLast_isPost = opType;
|
|
__addOpLast_dataAsStr = jsonStr;
|
|
}
|
|
else
|
|
{
|
|
extraBody = "Accept: application/json";
|
|
}
|
|
|
|
if (opType==OT_POST)
|
|
requestStr = RakString::FormatForPOST(URL, "application/json", jsonStr, extraBody);
|
|
else if (opType==OT_GET)
|
|
requestStr = RakString::FormatForGET(URL, extraBody);
|
|
else if (opType==OT_DELETE)
|
|
requestStr = RakString::FormatForDELETE(URL, extraBody);
|
|
else
|
|
requestStr = RakString::FormatForPUT(URL, "application/json", jsonStr, extraBody);
|
|
|
|
bool b = httpConnection2->TransmitRequest(requestStr,authURLDomain, 443, true);
|
|
if (!b)
|
|
{
|
|
if (eventCallback)
|
|
eventCallback->OnTransmissionFailed(httpConnection2, requestStr, authURLDomain);
|
|
}
|
|
if (data)
|
|
{
|
|
free(jsonStr);
|
|
json_decref(data);
|
|
}
|
|
}
|
|
|