435 lines
14 KiB
C++

//----------------------------------------------------------------------------
//
// Copyright (C) 2009 Intel Corporation
//
// File: MPSSoapServer.cpp
//
// Contents: This class implements a SOAP server.
//
//----------------------------------------------------------------------------
#include "global.h"
#include "TunnelManager.h"
#include "MPSNotificationSoapBinding.nsmap"
#include "TypeValidationsExtraction.h"
#include "MPSSoapServer.h"
#include "soapStub.h"
#include "SoapBinding.h"
#include "OptionsUtils.h"
#include "ConnectedSystems.h"
#include "ListParser.h"
#include <string>
#include <sstream>
#include <fstream>
#include <iostream>
string chomp(const string &strToChomp);
//*****************************************************************************
// Name : MPSoapServer
// Description : Constructor - initializes soap structures
//*****************************************************************************
MPSSoapServer::MPSSoapServer()
{
// Initialize soap.
m_soap = soap_new1(SOAP_XML_STRICT);
}
//*****************************************************************************
// Name : MPSSoapServer
// Description : Destructor - kill soap.
//*****************************************************************************
MPSSoapServer::~MPSSoapServer(void)
{
if (m_soap != NULL)
{
soap_destroy(m_soap);
soap_end(m_soap);
soap_done(m_soap);
soap_del(m_soap);
}
}
//*****************************************************************************
// Name : MPSSoapServer::RunServer
// Description : Listen on socket for one time interval.
//*****************************************************************************
bool MPSSoapServer::RunServer (SOAP_SOCKET handle)
{
bool ret = true;
m_soap->socket = handle;
if (soap_serve(m_soap) != SOAP_OK)
{
ACE_DEBUG((MY_DEBUG ACE_TEXT("Failed to process request")));
ret = false;
}
soap_destroy(m_soap); // clean up class instances
soap_end(m_soap); // clean up everything and close socket
return ret;
}
//*****************************************************************************
// Service operations:
//*****************************************************************************
//*****************************************************************************
// This function generated together with server operation but this is the client function
//*****************************************************************************
SOAP_FMAC5 int SOAP_FMAC6 __mps__MPSAlert(struct soap* , _mps__EventNotificationRequest *, _mps__MPSAlertResponse *)
{
return 501; // not implemented
}
// return 0 in case of not number string
int string_to_integer(const string& str)
{
stringstream ss(str);
int i;
ss >> i;
if (ss.fail())
i = 0;
return i;
}
// Checks if string is in URI format
bool is_URI(string str)
{
ACE_TString astr = str.c_str();
URL_Wrapper mc_data;
if (validateAndGetElement(astr, mc_data) != STATUS_SUCCESS)
{
ACE_ERROR ((MY_ERROR ACE_TEXT ("Invalid URI: %s.\n"),
str.c_str()));
return false;
}
return true;
}
//*****************************************************************************
// Name : Authenticate
// Description : Authenicate the user using _soap_auth_func
//*****************************************************************************
bool Authenticate(struct soap* soap)
{
#ifdef ACE_WIN32
if (_soap_auth_func != NULL) // Need credentials for service connection
{
char error[MAX_DLL_ERR_LEN];
if (!soap->userid ||!soap->passwd ||
(_soap_auth_func (soap->userid,
soap->passwd,
getSOAPDllParameters()->c_str(),
error, MAX_DLL_ERR_LEN ) == 0) )
{
ACE_DEBUG((MY_INFO ACE_TEXT("Failed to authenticate soap client\n")));
return false;
}
}
#endif
return true;
}
//*****************************************************************************
// Name : __mpi__IsMachineConnected
// Description : Checks if machine appears in Tunnel_Manager map
//*****************************************************************************
SOAP_FMAC5 int SOAP_FMAC6 __mpi__IsMachineConnected(struct soap* soap, _mpi__IsMachineConnected *mpi__IsMachineConnected, _mpi__IsMachineConnectedResponse *mpi__IsMachineConnectedResponse)
{
ACE_TRACE(ACE_TEXT("__mpi__IsMachineConnected"));
if (!Authenticate(soap))
return soap_receiver_fault_subcode(soap, "101", "User not authorized", "Wrong user name or permission denied.");
string system = mpi__IsMachineConnected->Machine->SystemName;
if (Tunnel_Manager::instance().fqdn_exists(ACE_CString(system.c_str())))
mpi__IsMachineConnectedResponse->IsConnected = true;
else
mpi__IsMachineConnectedResponse->IsConnected = false;
return SOAP_OK;
}
//*****************************************************************************
// Name : __mpi__EnumerateConnectedMachines
// Description : Enumerates connected machines, save in Connected_Systems map
// and return the context
//*****************************************************************************
SOAP_FMAC5 int SOAP_FMAC6 __mpi__EnumerateConnectedMachines(struct soap* soap, _mpi__EnumerateConnectedMachines *mpi__EnumerateConnectedMachines, _mpi__EnumerateConnectedMachinesResponse *mpi__EnumerateConnectedMachinesResponse)
{
ACE_TRACE(ACE_TEXT("__mpi__EnumerateConnectedMachines"));
if (!Authenticate(soap))
return soap_receiver_fault_subcode(soap, "101", "User not authorized", "Wrong user name or permission denied.");
if (Connected_Systems::instance().max_concurrent_enums_exceeded())
{
ACE_DEBUG((MY_DEBUG
ACE_TEXT("Max concurrent enumeration exceeeded (%d)\n"), *getMaxConcurrentEnums()));
return soap_receiver_fault_subcode(soap, "100", "Unexpected exeption", "Internal error.");
}
try{
// create new enumeration using current connected list
ConnectedSystemsEnumerationDataPtr cs(new Connected_Systems_Enumeration_Data());
ACE_UINT32 context;
if (!Connected_Systems::instance().add_new_enumeration(context , cs))
return soap_receiver_fault_subcode(soap, "100", "Unexpected exeption", "Internal error.");
time_t expires = cs->get_expires();
stringstream ss;
ss << context;
string* str = soap_new_std__string(soap, -1);
*str = ss.str();
mpi__EnumerateConnectedMachinesResponse->EnumerationContext = soap_new_xsd__anyType(soap, -1);
mpi__EnumerateConnectedMachinesResponse->EnumerationContext->__item = (char *) str->c_str();
mpi__EnumerateConnectedMachinesResponse->Expires = soap_new_std__string(soap, -1);
mpi__EnumerateConnectedMachinesResponse->Expires->assign(ctime(&expires));
return SOAP_OK;
}
catch(...)
{
return soap_receiver_fault_subcode(soap, "100", "Unexpected exeption", "Internal error.");
}
}
//*****************************************************************************
// Name : __mpi__Pull
// Description : Retrieves a list of names of machines corresponding to the
// enumeration specified by the enumeration context.
//*****************************************************************************
SOAP_FMAC5 int SOAP_FMAC6 __mpi__Pull(struct soap* soap, _mpi__Pull *mpi__Pull, _mpi__PullResponse *mpi__PullResponse)
{
ACE_TRACE(ACE_TEXT("__mpi__Pull"));
if (!Authenticate(soap))
return soap_receiver_fault_subcode(soap, "101", "User not authorized", "Wrong user name or permission denied.");
ACE_UINT32 context = string_to_integer(mpi__Pull->EnumerationContext->__item);
unsigned int num_items_to_pull = 1;
if (mpi__Pull->MaxElements != NULL && mpi__Pull->MaxElements->length() > 0)
num_items_to_pull = string_to_integer(mpi__Pull->MaxElements->c_str());
if (num_items_to_pull == 0) // MaxElements does not include numbers
num_items_to_pull = 1;
// takes the minimum of MaxEnumElements config data and MaxElements parametere
num_items_to_pull = min (num_items_to_pull, *(getMaxEnumElements()) );
// get the enumeration for this context
ConnectedSystemsEnumerationDataPtr* cs = Connected_Systems::instance().get_connected_system_enumeration_data_ptr(context);
if (cs == NULL)
return soap_receiver_fault_subcode(soap, "102", "Invalid Enumeration context", "An invalid enumeration context has been passed as parameter");
unsigned int num=0;
for( ;
(*cs)->get_systems_set_iterator() != (*cs)->get_systems_set_end() && num < num_items_to_pull;
(*cs)->get_systems_set_iterator()++)
{
mpi__SystemType* system = soap_new_mpi__SystemType(soap, 1);
system->SystemName = (*cs)->get_systems_set_iterator()->c_str();
mpi__PullResponse->Items.push_back(system);
num++;
}
// in case this is the last element - create the EndOfSequence parameter, and release the context
if ((*cs)->get_systems_set_iterator() == (*cs)->get_systems_set_end())
{
mpi__PullResponse->EndOfSequence = soap_new_xsd__anyType(soap,1);
Connected_Systems::instance().release_context(context);
}
return SOAP_OK;
}
//*****************************************************************************
// Name : __mpi__Release
// Description : Release a enumeration context.
//*****************************************************************************
SOAP_FMAC5 int SOAP_FMAC6 __mpi__Release(struct soap* soap, _mpi__Release *mpi__Release, struct __mpi__ReleaseResponse &_param_1)
{
ACE_TRACE(ACE_TEXT("__mpi__Release"));
if (!Authenticate(soap))
return soap_receiver_fault_subcode(soap, "101", "User not authorized", "Wrong user name or permission denied.");
ACE_UINT32 context = string_to_integer(mpi__Release->EnumerationContext->__item);
if (!Connected_Systems::instance().context_exists(context))
return soap_receiver_fault_subcode(soap, "102", "Invalid Enumeration context", "An invalid enumeration context has been passed as parameter");
if (Connected_Systems::instance().release_context(context))
return SOAP_OK;
return soap_receiver_fault_subcode(soap, "100", "Unexpected exeption", "Internal error.");
}
//*****************************************************************************
// Name : __mpi__SubscribeForNotifications
// Description : Enables subscribing a system to receive MpsNotification events
// whenever a machine connects to or disconnects from the MPS.
//*****************************************************************************
SOAP_FMAC5 int SOAP_FMAC6 __mpi__SubscribeForNotifications(struct soap* soap, _mpi__SubscribeForNotifications *mpi__SubscribeForNotifications, _mpi__SubscribeForNotificationsResponse *mpi__SubscribeForNotificationsResponse)
{
ACE_TRACE(ACE_TEXT("__mpi__SubscribeForNotifications"));
if (!Authenticate(soap))
return soap_receiver_fault_subcode(soap, "101", "User not authorized", "Wrong user name or permission denied.");
string delivery = mpi__SubscribeForNotifications->Delivery;
if (!is_URI(delivery))
return soap_sender_fault(soap, "Validation constraint violation: data type mismatch in element Delivery", NULL);
List_Parser parser;
vector<ACE_TString> vec;
if (parser.parseItemList(NOTIFICATION_LIST_DEFAULT, vec) != PARSER_STATUS_SUCCESS)
{
ACE_DEBUG((MY_DEBUG
ACE_TEXT("Error parsing notificationList.config file \n")));
return soap_receiver_fault_subcode(soap, "100", "Unexpected exeption", "Internal error.");
}
if (vec.size() >= *getMaxSubsribers())
{
ACE_DEBUG((MY_DEBUG
ACE_TEXT("Subsribers number excedded MaxSubscribers (%d) \n"),
*getMaxSubsribers()));
return soap_receiver_fault_subcode(soap, "100", "Unexpected exeption", "Internal error.");
}
ofstream fileStream;
fileStream.open(NOTIFICATION_LIST_DEFAULT, ios::app);
if(!fileStream.fail())
{
fileStream << "\n" << delivery;
}
fileStream.close();
return SOAP_OK;
}
//*****************************************************************************
// Name : __mpi__Unsubscribe
// Description : function removes a system from the subscribers list for
// receiving MpsNotification events whenever a machine connects
// to or disconnects from the MPS.
//*****************************************************************************
SOAP_FMAC5 int SOAP_FMAC6 __mpi__Unsubscribe(struct soap* soap, _mpi__Unsubscribe *mpi__Unsubscribe, struct __mpi__UnsubscribeResponse &_param_2)
{
ACE_TRACE(ACE_TEXT("__mpi__Unsubscribe"));
if (!Authenticate(soap))
return soap_receiver_fault_subcode(soap, "101", "User not authorized", "Wrong user name or permission denied.");
string delivery = mpi__Unsubscribe->Delivery;
if (!is_URI(delivery))
return soap_sender_fault(soap, "Validation constraint violation: data type mismatch in element Delivery", NULL);
ifstream fileStream;
ofstream outfileStream;
string str;
bool found = false;
try{
fileStream.open(NOTIFICATION_LIST_DEFAULT, ios::in);
outfileStream.open(TEMP_NOTIFICATION_LIST_DEFAULT, ios::out|ios::trunc);
if(!fileStream.fail())
{
while (!fileStream.eof())
{
getline(fileStream, str);
if(!fileStream.fail())
{
// first chomp the line from '\n' or "\n\r" (in Linux)
str = chomp(str);
if (str.compare(delivery) == 0)
{
ACE_DEBUG((MY_DEBUG
ACE_TEXT("%s found in notification.config file and deleted\n"),
delivery.c_str()));
found = true;
}
else
outfileStream << str << "\n";
}
}
}
fileStream.clear(); // if getline failed the failbit internal flag is set
fileStream.close();
outfileStream.close();
if (!found)
{
remove(TEMP_NOTIFICATION_LIST_DEFAULT);
return soap_receiver_fault_subcode(soap, "103", "URI not found", "No such URI in notification.config file");
}
// copy TEMP_NOTIFICATION_LIST_DEFAULT to NOTIFICATION_LIST_DEFAULT
// make sure to not add newline at the end of the file
fileStream.open(TEMP_NOTIFICATION_LIST_DEFAULT, ios::in);
if(fileStream.fail())
{
return soap_receiver_fault_subcode(soap, "100", "Unexpected exeption", "Internal error.");
}
else
{
outfileStream.open(NOTIFICATION_LIST_DEFAULT, ios::out|ios::trunc);
if(outfileStream.fail())
return soap_receiver_fault_subcode(soap, "100", "Unexpected exeption", "Internal error.");
// read first line and don't add newline
getline(fileStream, str);
if(!fileStream.fail())
outfileStream << str ;
while (!fileStream.eof())
{
getline(fileStream, str);
outfileStream << "\n" << str;
}
}
outfileStream.close();
fileStream.close();
}
catch(...)
{
ACE_DEBUG((MY_DEBUG
ACE_TEXT("__mpi__Unsubscribe: got exception\n")));
}
remove(TEMP_NOTIFICATION_LIST_DEFAULT);
return SOAP_OK;
}