//---------------------------------------------------------------------------- // // 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 #include #include #include 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 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; }