diff --git a/include/GVOHub.hpp b/include/GVOHub.hpp index b40c598..4d33037 100644 --- a/include/GVOHub.hpp +++ b/include/GVOHub.hpp @@ -94,6 +94,7 @@ protected: void request_shutdown(const socklen_t& sock); std::string get_client_key(const GXml& xml) const; int get_client_index(const GXml& xml) const; + int get_client_index(const std::string& reference) const; std::string get_response_value(const GXml& xml, const std::string& name) const; void get_name_value_pair(const GXmlNode* node, @@ -108,6 +109,7 @@ protected: // Low-level methods void create_samp_file(void) const; void post_samp_ok(const socklen_t& sock) const; + void post_samp_void(const socklen_t& sock) const; void post_string(const std::string& content, const socklen_t& sock) const; void notify(const std::string& url, const std::string& notification) const; std::string random_string(const size_t& length) const; diff --git a/src/vo/GVOClient.cpp b/src/vo/GVOClient.cpp index 66a9327..1827f6f 100644 --- a/src/vo/GVOClient.cpp +++ b/src/vo/GVOClient.cpp @@ -913,7 +913,7 @@ void GVOClient::post_string(const std::string& content) const // Send content to socket bool done = false; do { - int length = post.length() + 1; // +1 for terminating 0 + int length = post.length(); int sent_length = send(m_socket, post.c_str(), length, 0); if (sent_length < length) { post = post.substr(sent_length, std::string::npos); diff --git a/src/vo/GVOHub.cpp b/src/vo/GVOHub.cpp index 96e1e4b..740a531 100644 --- a/src/vo/GVOHub.cpp +++ b/src/vo/GVOHub.cpp @@ -42,24 +42,19 @@ #include // waitpid() function #include // inet_addr() function #include "GVOHub.hpp" -#include "GVOClient.hpp" #include "GException.hpp" #include "GTools.hpp" /* __ Method name definitions ____________________________________________ */ -#define G_INIT_MEMBERS "GVOHub::init_members()" #define G_START_HUB "GVOHub::start_hub()" -#define G_HANDLE_REQUEST "GVOHub::handle_request(socklen_t&)" -#define G_REGISTER_SERVICE "GVOHub::register_service(GXml&, socklen_t&)" /* __ Macros _____________________________________________________________ */ /* __ Coding definitions _________________________________________________ */ -#define G_KEY 12345 -//#define G_USE_FORK /* __ Debug definitions __________________________________________________ */ -#define G_CONSOLE_DUMP +//#define G_CONSOLE_DUMP +#define G_SHOW_MESSAGE /*========================================================================== @@ -249,8 +244,8 @@ void GVOHub::init_members(void) m_version = "1.3"; m_hub_id = "gammalib_hub"; m_socket = -1; // Signals no socket - m_clients.clear(); m_shutdown = false; + m_clients.clear(); // Return return; @@ -273,8 +268,8 @@ void GVOHub::copy_members(const GVOHub& hub) m_version = hub.m_version; m_hub_id = hub.m_hub_id; m_socket = hub.m_socket; - m_clients = hub.m_clients; m_shutdown = hub.m_shutdown; + m_clients = hub.m_clients; // Return return; @@ -372,47 +367,6 @@ void GVOHub::start_hub(void) throw GException::runtime_error(G_START_HUB, msg); } - #if defined(G_USE_FORK) - // Create child process to handle the request - int pid = fork(); - if (pid < 0) { - std::string msg = "No child process created."; - throw GException::runtime_error(G_START_HUB, msg); - } - - // If we have a PID of 0 we are in the child process. In this case - // we have to handle the incoming requests ... - if (pid == 0) { - - // Handle request - handle_request(socket); - - // Exit child process - exit(0); - } - - // ... otherwise we are in the parent process. - else { - - // Wait for the child process to terminate - int status = 0; - waitpid(pid, &status, 0); - - // Close socket - close(socket); - - // Send SIG_IGN to the child process so that the kernel can - // close it without sending it to zombie state - std::signal(pid, SIG_IGN); - - // If we have received a shutdown request then exit the event - // loop - if (o_clients->registered == -1) { - break; - } - - } - #else // Handle request handle_request(socket); @@ -424,7 +378,6 @@ void GVOHub::start_hub(void) if (m_shutdown) { break; } - #endif } // endwhile: main event loop @@ -452,8 +405,8 @@ void GVOHub::handle_request(const socklen_t& sock) // Initialize buffer char buffer[1001]; - // Initialise response - std::string response = ""; + // Initialise message + std::string message = ""; // Read from socket until nothing is received anymore. int timeout = 2000; // Initial timeout is 2 sec @@ -462,22 +415,24 @@ void GVOHub::handle_request(const socklen_t& sock) n = gammalib::recv(sock, buffer, 1000, 0, timeout); if (n > 0) { buffer[n] = '\0'; - response.append(std::string(buffer)); + message.append(std::string(buffer)); } timeout = 10; // The timeout now is 0.01 sec } while (n > 0); // Dump the buffer - #if defined(G_CONSOLE_DUMP) - std::cout << "Hub has received the following message:" << std::endl; - std::cout << response << std::endl; + #if defined(G_SHOW_MESSAGE) + std::cout << std::endl; + std::cout << "GVOHub has received the following message:" << std::endl; + std::cout << "==========================================" << std::endl; + std::cout << message << std::endl; #endif // Extract response into an XML object GXml xml; - size_t start = response.find("\n"); - response.append("\n"); - response.append(" \n"); - response.append(" \n"); - response.append(" \n"); - response.append(" \n"); - response.append(" \n"); - response.append("\n"); - - // Post response - post_string(response, sock); + // Post void message + post_samp_void(sock); // Return return; @@ -610,46 +552,41 @@ void GVOHub::request_register(const GXml& xml, const socklen_t& sock) // Attached client m_clients.push_back(voclient); - /* - for (int i = 0; i < m_clients.size(); ++i) { - std::cout << "Client i " << m_clients[i].reference << " key=" << m_clients[i].private_key << std::endl; - } - */ // Declare response - std::string msg = ""; + std::string response = ""; // Set response - msg.append("\n"); - msg.append("\n"); - msg.append("\n"); - msg.append(" \n"); - msg.append(" \n"); - msg.append(" samp.private-key\n"); - msg.append(" "+voclient.private_key+"\n"); - msg.append(" \n"); - msg.append(" \n"); - msg.append(" samp.hub-id\n"); - msg.append(" "+m_hub_id+"\n"); - msg.append(" \n"); - msg.append(" \n"); - msg.append(" samp.self-id\n"); - msg.append(" "+voclient.reference+"\n"); - msg.append(" \n"); - msg.append(" \n"); - msg.append(" samp.status\n"); - msg.append(" samp.ok\n"); - msg.append(" \n"); - msg.append(" \n"); - msg.append(" samp.url-translator\n"); - msg.append(" "+m_hub_url+"\n"); - msg.append(" \n"); - msg.append(" \n"); - msg.append("\n"); - msg.append("\n"); + response.append("\n"); + response.append("\n"); + response.append("\n"); + response.append(" \n"); + response.append(" \n"); + response.append(" samp.private-key\n"); + response.append(" "+voclient.private_key+"\n"); + response.append(" \n"); + response.append(" \n"); + response.append(" samp.hub-id\n"); + response.append(" "+m_hub_id+"\n"); + response.append(" \n"); + response.append(" \n"); + response.append(" samp.self-id\n"); + response.append(" "+voclient.reference+"\n"); + response.append(" \n"); + response.append(" \n"); + response.append(" samp.status\n"); + response.append(" samp.ok\n"); + response.append(" \n"); + response.append(" \n"); + response.append(" samp.url-translator\n"); + response.append(" "+m_hub_url+"\n"); + response.append(" \n"); + response.append(" \n"); + response.append("\n"); + response.append("\n"); // Post response - post_string(msg, sock); + post_string(response, sock); // Send notifications send_notifications("samp.hub.event.register", voclient.reference); @@ -680,19 +617,8 @@ void GVOHub::request_unregister(const GXml& xml, const socklen_t& sock) // Continue only if index is valid if (i != -1) { - // Declare message - std::string msg = ""; - - // Set response - msg.append("\n"); - msg.append("\n"); - msg.append("\n"); - msg.append(" \n"); - msg.append("\n"); - msg.append("\n"); - - // Post response - post_string(msg, sock); + // Post void message + post_samp_void(sock); // Send notifications send_notifications("samp.hub.event.unregister", @@ -746,18 +672,8 @@ void GVOHub::request_declare_metadata(const GXml& xml, const socklen_t& sock) m_clients[i].author_name = get_response_value(xml, "author.name"); m_clients[i].homepage = get_response_value(xml, "home.page"); - // Declare message - std::string msg = ""; - - // The hub response to Metadata declaration has no useful - // content and can be discarded by the client. - msg.append("\n"); - msg.append("\n"); - msg.append("\n"); - msg.append("\n"); - - // Post response - post_string(msg,sock); + // Post void message + post_samp_void(sock); // Send notifications send_notifications("samp.hub.event.metadata", m_clients[i].reference); @@ -882,47 +798,69 @@ void GVOHub::request_get_subscriptions(const GXml& xml, const socklen_t& sock) std::cout << "GVOHub::request_get_subscriptions" << std::endl; #endif - // Get client index - int i = get_client_index(xml); + // Initialise client name + std::string client_name = ""; - // Continue only if index is valid - if (i != -1) { - - // Declare message - std::string msg = ""; - - // Set response - msg.append("\n"); - msg.append("\n"); - msg.append("\n"); - msg.append(" \n"); - - // Append all subscriptions - for (int k = 0; k < m_clients[i].subscriptions.size(); ++k) { - msg.append(" \n"); - msg.append(" "); - msg.append(m_clients[i].subscriptions[k]); - msg.append("\n"); - msg.append(" \n)"); - msg.append(" \n"); + // Get the client name + const GXmlNode* node = xml.element("methodCall > params > param[1] > value"); + if (node != NULL) { + const GXmlText* text = static_cast((*node)[0]); + if (text != NULL) { + client_name = text->text(); } + } - // Finish response - msg.append(" \n"); - msg.append("\n"); - msg.append("\n"); - - // Post response - post_string(msg, sock); + // Declare response + std::string response = ""; - } // endif: client index was valid + // Set response + response.append("\n"); + response.append("\n"); + response.append("\n"); + response.append(" \n"); - // Signal if the client was unknown - #if defined(G_CONSOLE_DUMP) + // If key is "gammalib_hub" then return some special information + if (client_name == "gammalib_hub") { + // Do nothing + } + + // ... handle all other clients else { - std::cout << " *** ERROR: Unable to find client " << get_client_key(xml) << std::endl; + + // Get client index + int i = get_client_index(client_name); + + // Continue only if index is valid + if (i != -1) { + + // Append all subscriptions + for (int k = 0; k < m_clients[i].subscriptions.size(); ++k) { + response.append(" \n"); + response.append(" "); + response.append(m_clients[i].subscriptions[k]); + response.append("\n"); + response.append(" \n"); + response.append(" \n"); + } + + } + + // Signal if the client was unknown + #if defined(G_CONSOLE_DUMP) + else { + std::cout << " *** ERROR: Unable to find client " << get_client_key(xml) << std::endl; + } + #endif + } - #endif + + // Finish response + response.append(" \n"); + response.append("\n"); + response.append("\n"); + + // Post response + post_string(response, sock); // Return return; @@ -1016,19 +954,8 @@ void GVOHub::request_get_subscribed_clients(const GXml& xml, const socklen_t& so fclose(fptr); */ - // Declare message - std::string msg = ""; - - // Set response - msg.append("\n"); - msg.append("\n"); - msg.append("\n"); - msg.append(" \n"); - msg.append("\n"); - msg.append("\n"); - - // Post message - post_string(msg, sock); + // Post void message + post_samp_void(sock); // Return return; @@ -1043,87 +970,128 @@ void GVOHub::request_get_subscribed_clients(const GXml& xml, const socklen_t& so * * Handles all metadata requests. ***************************************************************************/ -void GVOHub::request_get_metadata(const GXml& xml,const socklen_t& sock) +void GVOHub::request_get_metadata(const GXml& xml, const socklen_t& sock) { // Header #if defined(G_CONSOLE_DUMP) std::cout << "GVOHub::request_get_metadata" << std::endl; #endif - // Get client key - std::string key = get_client_key(xml); + // Initialise client name + std::string client_name = ""; - // Declare message - std::string msg = ""; + // Get the client name + const GXmlNode* node = xml.element("methodCall > params > param[1] > value"); + if (node != NULL) { + const GXmlText* text = static_cast((*node)[0]); + if (text != NULL) { + client_name = text->text(); + } + } + + // Declare response + std::string response = ""; // Set response - msg.append("\n"); - msg.append("\n"); - msg.append("\n"); - msg.append(" \n"); - msg.append(" \n"); - msg.append(" samp.status\n"); - msg.append(" samp.ok\n"); - msg.append(" \n"); + response.append("\n"); + response.append("\n"); + response.append("\n"); + response.append(" \n"); + response.append(" \n"); + response.append(" samp.status\n"); + response.append(" samp.ok\n"); + response.append(" \n"); // If key is "gammalib_hub" then return some special information - if (key == "gammalib_hub") { - msg.append(" samp.namegammalib_hub\n"); - msg.append(" samp.description.textGammaLib VO Hub\n"); - msg.append(" samp.icon.url\n"); - msg.append(" samp.documentation.urlgammalib github documentation\n"); - msg.append(" author.affiliationIRAP, CNRS Toulouse\n"); - msg.append(" author.emaildontcontactme@please\n"); - msg.append(" author.nameJ. Knoedlseder, T. Louge\n"); - msg.append(" home.pageno dedicated page\n"); + if (client_name == "gammalib_hub") { + response.append(" \n"); + response.append(" samp.name\n"); + response.append(" gammalib_hub\n"); + response.append(" \n"); + response.append(" \n"); + response.append(" samp.description.text\n"); + response.append(" GammaLib VO Hub\n"); + response.append(" \n"); + response.append(" \n"); + response.append(" samp.icon.url\n"); + response.append(" http://a.fsdn.com/allura/p/gammalib/icon\n"); + response.append(" \n"); + response.append(" \n"); + response.append(" samp.documentation.url\n"); + response.append(" http://cta.irap.omp.eu/gammalib/user_manual/modules/vo.html\n"); + response.append(" \n"); + response.append(" \n"); + response.append(" author.affiliation\n"); + response.append(" IRAP, Toulouse, France\n"); + response.append(" \n"); + response.append(" \n"); + response.append(" author.email\n"); + response.append(" jurgen.knodlseder@irap.omp.eu\n"); + response.append(" \n"); + response.append(" \n"); + response.append(" author.name\n"); + response.append(" J. Knoedlseder, T. Louge\n"); + response.append(" \n"); + response.append(" \n"); + response.append(" home.page\n"); + response.append(" http://cta.irap.omp.eu/gammalib/\n"); + response.append(" \n"); } // ... otherwise get the index else { // Get client index - int i = get_client_index(xml); + int i = get_client_index(client_name); // Continue only if index is valid if (i != -1) { // Append response - msg.append(" samp.name"); - msg.append(m_clients[i].name); - msg.append("\n"); - msg.append(" samp.description.text"); - msg.append(m_clients[i].description); - msg.append("\n"); - msg.append(" samp.icon.url"); - msg.append(m_clients[i].icon); - msg.append("\n"); - msg.append(" samp.documentation.url"); - msg.append(m_clients[i].documentation); - msg.append("\n"); - msg.append(" author.affiliation"); - msg.append(m_clients[i].affiliation); - msg.append("\n"); - msg.append(" author.email"); - msg.append(m_clients[i].email); - msg.append("\n"); - msg.append(" author.name"); - msg.append(m_clients[i].author_name); - msg.append("\n"); - msg.append(" home.page"); - msg.append(m_clients[i].homepage); - msg.append("\n"); + response.append(" \n"); + response.append(" samp.name\n"); + response.append(" "+m_clients[i].name+"\n"); + response.append(" \n"); + response.append(" \n"); + response.append(" samp.description.text\n"); + response.append(" "+m_clients[i].description+"\n"); + response.append(" \n"); + response.append(" \n"); + response.append(" samp.icon.url\n"); + response.append(" "+m_clients[i].icon+"\n"); + response.append(" \n"); + response.append(" \n"); + response.append(" samp.documentation.url\n"); + response.append(" "+m_clients[i].documentation+"\n"); + response.append(" \n"); + response.append(" \n"); + response.append(" author.affiliation\n"); + response.append(" "+m_clients[i].affiliation+"\n"); + response.append(" \n"); + response.append(" \n"); + response.append(" author.email\n"); + response.append(" "+m_clients[i].email+"\n"); + response.append(" \n"); + response.append(" \n"); + response.append(" author.name\n"); + response.append(" "+m_clients[i].author_name+"\n"); + response.append(" \n"); + response.append(" \n"); + response.append(" home.page\n"); + response.append(" "+m_clients[i].homepage+"\n"); + response.append(" \n"); } // endif: index was valid } // endelse: client was not the hub // Finish response - msg.append(" \n"); - msg.append("\n"); - msg.append("\n"); + response.append(" \n"); + response.append("\n"); + response.append("\n"); // Post response - post_string(msg, sock); + post_string(response, sock); // Return return; @@ -1190,9 +1158,10 @@ std::string GVOHub::get_client_key(const GXml& xml) const * @brief Extract client index in shared memory from XML request * * @param[in] xml XML message sent by client. + * @return Client index (-1 if not found). * - * Extracts the client index in shared memory from the XML request. The - * method returns -1 if no client was found. + * Extracts the client index from the XML request. The method returns -1 if + * no client was found. ***************************************************************************/ int GVOHub::get_client_index(const GXml& xml) const { @@ -1226,6 +1195,38 @@ int GVOHub::get_client_index(const GXml& xml) const /***********************************************************************//** + * @brief Extract client index in shared memory from XML request + * + * @param[in] reference Client reference. + * @return Client index (-1 if not found). + * + * Extracts the client index from the client reference. The method returns -1 + * if no client was found. + ***************************************************************************/ +int GVOHub::get_client_index(const std::string& reference) const +{ + // Header + #if defined(G_CONSOLE_DUMP) + std::cout << "GVOHub::get_client_index" << std::endl; + #endif + + // Initialise index + int index = -1; + + // Search for index + for (int i = 0; i < m_clients.size(); ++i) { + if (m_clients[i].reference == reference) { + index = i; + break; + } + } + + // Return index + return index; +} + + +/***********************************************************************//** * @brief Returns value for a SAMP client query parameter * * @param[in] xml client query XML document. @@ -1243,7 +1244,7 @@ std::string GVOHub::get_response_value(const GXml& xml, std::string value = ""; // Get the client's private key - const GXmlNode* node = xml.element("methodCall > params > param > value > struct"); + const GXmlNode* node = xml.element("methodCall > params > param[1] > value > struct"); if (node != NULL) { int num = node->elements("member"); for (int i = 0; i < num; ++i) { @@ -1645,39 +1646,6 @@ void GVOHub::create_samp_file(void) const /***********************************************************************//** - * @brief Post SAMP ok massage to client - * - * @param[in] sock Socket. - * - * Posts a SAMP of massage to a client. - ***************************************************************************/ -void GVOHub::post_samp_ok(const socklen_t& sock) const -{ - // Declare response - std::string response = ""; - - // Compose response - response.append("\n"); - response.append("\n"); - response.append("\n"); - response.append(" \n"); - response.append(" \n"); - response.append(" samp.status\n"); - response.append(" samp.ok\n"); - response.append(" \n"); - response.append(" \n"); - response.append("\n"); - response.append("\n"); - - // Post string - post_string(response, sock); - - // Return - return; -} - - -/***********************************************************************//** * @brief Post string content to client * * @param[in] content String content to post. @@ -1693,27 +1661,28 @@ void GVOHub::post_string(const std::string& content, const socklen_t& sock) cons // Determine content length int length = content.length(); - // Set prefix - std::string prefix = "POST /"+m_hub_path+" HTTP/1.1\n" - "Content-Type: text/xml\n" - "User-Agent: GammaLib\n" - "Host: "+m_hub_host+":"+m_hub_port+"\n" + // Set prefix (note that the response has no POST!) + std::string prefix = "HTTP/1.1 200 OK\n" "Connection: close\n" + "Content-Type: text/xml\n" "Content-Length: "+gammalib::str(length)+"\n\n"; + // Build post string std::string post = prefix + content; // Dump message to post - #if defined(G_CONSOLE_DUMP) - std::cout << "\nGVOHub::post_string posts the following message" << std::endl; + #if defined(G_SHOW_MESSAGE) + std::cout << std::endl; + std::cout << "GVOHub response:" << std::endl; + std::cout << "================" << std::endl; std::cout << post << std::endl; #endif // Send content to socket bool done = false; do { - int length = post.length() + 1; // +1 for terminating 0 + int length = post.length(); int sent_length = send(sock, post.c_str(), length, 0); if (sent_length < length) { post = post.substr(sent_length, std::string::npos); @@ -1731,6 +1700,70 @@ void GVOHub::post_string(const std::string& content, const socklen_t& sock) cons /***********************************************************************//** + * @brief Post SAMP ok massage to client + * + * @param[in] sock Socket. + * + * Posts a SAMP OK message to a client. + ***************************************************************************/ +void GVOHub::post_samp_ok(const socklen_t& sock) const +{ + // Declare response + std::string response = ""; + + // Compose response + response.append("\n"); + response.append("\n"); + response.append("\n"); + response.append(" \n"); + response.append(" \n"); + response.append(" samp.status\n"); + response.append(" samp.ok\n"); + response.append(" \n"); + response.append(" \n"); + response.append("\n"); + response.append("\n"); + + // Post string + post_string(response, sock); + + // Return + return; +} + + +/***********************************************************************//** + * @brief Post SAMP void massage to client + * + * @param[in] sock Socket. + * + * Posts a void SAMP message to a client. Void messages can typically be + * discared by the client. + ***************************************************************************/ +void GVOHub::post_samp_void(const socklen_t& sock) const +{ + // Declare response + std::string response = ""; + + // Compose response + response.append("\n"); + response.append("\n"); + response.append(" \n"); + response.append(" \n"); + response.append(" \n"); + response.append(" \n"); + response.append(" \n"); + response.append("\n"); + + // Post string + post_string(response, sock); + + // Return + return; +} + + +/***********************************************************************//** * @brief Send notification to client * * @param[in] url URL. @@ -1831,8 +1864,10 @@ void GVOHub::notify(const std::string& url, std::string post = prefix + notification; // Dump message to post - #if defined(G_CONSOLE_DUMP) - std::cout << "\nGVOHub::notify posts the following message" << std::endl; + #if defined(G_SHOW_MESSAGE) + std::cout << std::endl; + std::cout << "GVOHub sends following notification:" << std::endl; + std::cout << "====================================" << std::endl; std::cout << post << std::endl; #endif