/* * Copyright (C) 2016+ AzerothCore , released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version. * Copyright (C) 2008-2016 TrinityCore * Copyright (C) 2005-2009 MaNGOS */ #include "ACSoap.h" #include "Log.h" #include "soapH.h" #include "soapStub.h" #include "World.h" void ACSoapRunnable::run() { struct soap soap; soap_init(&soap); soap_set_imode(&soap, SOAP_C_UTFSTRING); soap_set_omode(&soap, SOAP_C_UTFSTRING); // check every 3 seconds if world ended soap.accept_timeout = 3; soap.recv_timeout = 5; soap.send_timeout = 5; if (!soap_valid_socket(soap_bind(&soap, _host.c_str(), _port, 100))) { sLog->outError("ACSoap: couldn't bind to %s:%d", _host.c_str(), _port); exit(-1); } sLog->outString("ACSoap: bound to http://%s:%d", _host.c_str(), _port); while (!World::IsStopped()) { if (!soap_valid_socket(soap_accept(&soap))) continue; // ran into an accept timeout #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) sLog->outDebug(LOG_FILTER_NETWORKIO, "ACSoap: accepted connection from IP=%d.%d.%d.%d", (int)(soap.ip >> 24) & 0xFF, (int)(soap.ip >> 16) & 0xFF, (int)(soap.ip >> 8) & 0xFF, (int)soap.ip & 0xFF); #endif struct soap* thread_soap = soap_copy(&soap);// make a safe copy ACE_Message_Block* mb = new ACE_Message_Block(sizeof(struct soap*)); ACE_OS::memcpy(mb->wr_ptr(), &thread_soap, sizeof(struct soap*)); process_message(mb); } soap_done(&soap); } void ACSoapRunnable::process_message(ACE_Message_Block* mb) { ACE_TRACE (ACE_TEXT ("SOAPWorkingThread::process_message")); struct soap* soap; ACE_OS::memcpy(&soap, mb->rd_ptr (), sizeof(struct soap*)); mb->release(); soap_serve(soap); soap_destroy(soap); // dealloc C++ data soap_end(soap); // dealloc data and clean up soap_done(soap); // detach soap struct free(soap); } /* Code used for generating stubs: int ns1__executeCommand(char* command, char** result); */ int ns1__executeCommand(soap* soap, char* command, char** result) { // security check if (!soap->userid || !soap->passwd) { #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) sLog->outDebug(LOG_FILTER_NETWORKIO, "ACSoap: Client didn't provide login information"); #endif return 401; } uint32 accountId = AccountMgr::GetId(soap->userid); if (!accountId) { #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) sLog->outDebug(LOG_FILTER_NETWORKIO, "ACSoap: Client used invalid username '%s'", soap->userid); #endif return 401; } if (!AccountMgr::CheckPassword(accountId, soap->passwd)) { #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) sLog->outDebug(LOG_FILTER_NETWORKIO, "ACSoap: invalid password for account '%s'", soap->userid); #endif return 401; } if (AccountMgr::GetSecurity(accountId) < SEC_ADMINISTRATOR) { #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) sLog->outDebug(LOG_FILTER_NETWORKIO, "ACSoap: %s's gmlevel is too low", soap->userid); #endif return 403; } if (!command || !*command) return soap_sender_fault(soap, "Command can not be empty", "The supplied command was an empty string"); #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) sLog->outDebug(LOG_FILTER_NETWORKIO, "ACSoap: got command '%s'", command); #endif SOAPCommand connection; // commands are executed in the world thread. We have to wait for them to be completed { // CliCommandHolder will be deleted from world, accessing after queueing is NOT save CliCommandHolder* cmd = new CliCommandHolder(&connection, command, &SOAPCommand::print, &SOAPCommand::commandFinished); sWorld->QueueCliCommand(cmd); } // wait for callback to complete command int acc = connection.pendingCommands.acquire(); if (acc) { sLog->outError("ACSoap: Error while acquiring lock, acc = %i, errno = %u", acc, errno); } // alright, command finished char* printBuffer = soap_strdup(soap, connection.m_printBuffer.c_str()); if (connection.hasCommandSucceeded()) { *result = printBuffer; return SOAP_OK; } else return soap_sender_fault(soap, printBuffer, printBuffer); } void SOAPCommand::commandFinished(void* soapconnection, bool success) { SOAPCommand* con = (SOAPCommand*)soapconnection; con->setCommandSuccess(success); con->pendingCommands.release(); } //////////////////////////////////////////////////////////////////////////////// // // Namespace Definition Table // //////////////////////////////////////////////////////////////////////////////// struct Namespace namespaces[] = { { "SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/", nullptr, nullptr }, // must be first { "SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/", nullptr, nullptr }, // must be second { "xsi", "http://www.w3.org/1999/XMLSchema-instance", "http://www.w3.org/*/XMLSchema-instance", nullptr }, { "xsd", "http://www.w3.org/1999/XMLSchema", "http://www.w3.org/*/XMLSchema", nullptr }, { "ns1", "urn:AC", nullptr, nullptr }, // "ns1" namespace prefix { nullptr, nullptr, nullptr, nullptr } };